How to store scapy packet data? - python

I have a DNS packet sniffer built with Scapy that I'd like to store packet data from.
I understand that packet data is stored as a dictionary, which should make it ideal to store in another dictionary or array. I can see using pkt[0].summary that the data is correct and I am getting packets but I cannot figure out how to correctly store it.
As I am new to Python / Scapy, my question is how to store / append this packet data to a dictionary or array as the packets come through.
This is what the code looks like:
#!/usr/bin/env python
from scapy.all import *
from datetime import datetime
import time
import datetime
import sys
# Select interface and ports of interest
interface = 'ens33'
bpf = 'udp and port 53'
# SELECT/FILTER MSGS
def select_DNS(pkt):
pkt_time = pkt.sprintf('%sent.time%')
# SELECT/FILTER DNS MSGS
try:
dict = []
# queries
if DNSQR in pkt and pkt.dport == 53:
domain = pkt.getlayer(DNS).qd.qname.decode() # .decode() gets rid of the b''
print('Q - Time: ' + pkt_time + ' , source IP: ' + pkt[IP].src + ' , domain: ' + domain)
# responses
elif DNSRR in pkt and pkt.sport == 53:
domain = pkt.getlayer(DNS).qd.qname.decode()
print('R - Time: ' + pkt_time + ' , source IP: ' + pkt[IP].src + ' , domain: ' + domain)
except:
pass
# START SNIFFER
sniff(iface=interface, filter=bpf, store=0, prn=select_DNS)

I'm fairly sure the packet structure is not a dictionary, even though it provides some dictionary like features (overriding the slicing notation).
If you want to store the packets in a list (array), just append them as you go.
cache = []
def select_DNS(pkt):
cache.append(pkt)
If you want to store packets to disk, I would suggest writing them out using the wrpacp function to save them in "pcap" format.
wrpcap("temp.cap",pkts)

Related

Split string to dictionary based on multiple delimiters

Problem:
I get a cluster definition as a string. The definition contains the IP, Port and Trunk details of two interconnected applications for one or more data centers. The structure of the string is the following:
Application1 IPs and Port details: 'N' number of IPs (minimum 2) and exactly 1 port. IPs are separated with commas, while the port is separated with colon.
Application1 config is closed with a semicolon, which is followed by Application2 IPs and trunks.
On Application 2 an IP and Trunk forms a single unit. These units are separated by colons while IP and Trunk information within the units are separated by '|'
This is a sample input which contains the cluster definitions for 2 Data Centers.
cluster_params = "1.1.1.1,2.2.2.2:5002;10.10.0.1|17,10.10.0.2|18,10.10.0.3|19,10.10.0.4|20\n3.3.3.3,4.4.4.4:5003;10.10.1.1|21,10.10.1.2|22,10.10.1.3|23,10.10.1.4|24"
What I need:
I would like to split the cluster_params into a nested dictionary, something like the below sample:
clusters = { 'Cluster1_App1_port_salt': ['App1_IP1', 'App1_IP2', 'App1_IPn'],
'App2_IPs_and_ports': ['App2_Ip1', 'App2_Port1','App2_Ip2', 'App2_Port2', 'App2_Ipn', 'App2_Portn'],
'Cluster2_App1_port_salt': ['App1_IP1', 'App1_IP2', 'App1_IPn'],
'App2_IPs_and_ports': ['App2_Ip1', 'App2_Port1','App2_Ip2', 'App2_Port2', 'App2_Ipn', 'App2_Portn'],}
I can split and get the required variables from the string with the below code, but can't figure out how to put it into a nested dictionary. (App1 is ICM and App2 is MPP in the below code)
import string
import random
cluster_params = "1.1.1.1,2.2.2.2:5002;10.10.0.1|17,10.10.0.2|18,10.10.0.3|19,10.10.0.4|20\n3.3.3.3,4.4.4.4:5003;10.10.1.1|21,10.10.1.2|22,10.10.1.3|23,10.10.1.4|24"
clusters =cluster_params.split('\n')
for i in clusters:
separate_cluster=i.split(';')
icm_config=separate_cluster[0]
mpp_config=separate_cluster[1]
icm_separator=icm_config.split(':')
icm_ips=icm_separator[0]
icm_port=icm_separator[1]
salt=random.choice(string.ascii_lowercase)+random.choice(string.ascii_lowercase)+random.choice(string.ascii_lowercase)+random.choice(string.ascii_lowercase)
PIM_Name='PIM_Connector_' + icm_port + '_' + salt
mpp_separator=mpp_config.split(',')
mpp_ip=[]
mpp_trunk=[]
for i in mpp_separator:
mpp_ip.append(i.split('|')[0])
mpp_trunk.append(i.split('|')[1])
print('ICM_Config: ' + icm_config)
print('Pim_Name: ' + PIM_Name)
print('ICM_IPs: ' + icm_ips)
print('ICM_Port: ' + icm_port)
print('ICM_IPs ' + icm_ips)
print('MPP_Config: ' + mpp_config)
print( mpp_ip)
print( mpp_trunk)
Thanks!
Check this out:
def salt():
return "".join([random.choice(string.ascii_lowercase) for _ in range(4)])
apps_names = ["icm","mpp"]
clusters_dict = {}
for i,cluster in enumerate(cluster_params.split("\n")):
salt_ = salt()
icm,mpp = cluster.split(";")
icm_ips,icm_port= icm.split(":")
icm_ips=icm_ips.split(",")
mpp_ips , mpp_trunks = [], []
for entry in mpp.split(","):
mpp_ip,mpp_trunk = entry.split("|")
mpp_ips.append(mpp_ip)
mpp_trunks.append(mpp_trunk)
args_dict ={}
args_dict["icm_"+str(icm_port)+"_"+salt_]=icm_ips
args_dict["mpp_ips_and_ports"]=[mpp_ips[i]+"_"+mpp_trunks[i] for i in range(len(mpp_ips))]
clusters_dict["cluster"+str(i+1)]=args_dict
print(clusters_dict)
output example :
{'cluster1': {'icm_5002_phua': ['1.1.1.1', '2.2.2.2'], 'mpp_ips_and_ports': ['10.10.0.1_17', '10.10.0.2_18', '10.10.0.3_19', '10.10.0.4_20']}, 'cluster2': {'icm_5003_ppkg': ['3.3.3.3', '4.4.4.4'], 'mpp_ips_and_ports': ['10.10.1.1_21', '10.10.1.2_22', '10.10.1.3_23', '10.10.1.4_24']}}

Reading serial interface with Python returns distorted data

I am trying to read binary serial port using Python. Each source message consists of 3 floating point values, 12 bytes in total. Using the Python code shown below, I was expecting to get a 12-byte bytearray message. However, running the code I found out it is not always 12 bytes and sometimes it is gibberish. What am I doing wrong here or why is it so?
Pyhon code:
#!/usr/bin/env python
import serial
import time
serialPort = 'COM3'
serialBaud = 921600
dataNumBytes = 4
numData = 3
rawData = bytearray(numData * dataNumBytes)
# Connect to serial port
print('Trying to connect to ' + str(serialPort) +
' at ' + str(serialBaud) + ' BAUD.')
try:
s = serial.Serial(serialPort, serialBaud, timeout=4)
print('Connected!')
except:
print("Failed to connect with " + str(serialPort) +
' at ' + str(serialBaud) + ' BAUD.')
s.reset_input_buffer() # flush input buffer
while (True):
time.sleep(0.1)
s.readinto(rawData)
print(rawData)
Terminal output:
bytearray(b'r u?\xb78\x0c\xbe\x1dN\x82>')
bytearray(b'#cu?\xb78\x0c\xbe0\xa7\x82>')
bytearray(b'\xca\x8fu?\x03\x9d\r\xbeno\x81>')
bytearray(b'#cu?\xb78\x0c\xbeno\x81>')
bytearray(b'\x0e\xa6u?\xb78\x0c\xbe\n\xf5\x81>')
bytearray(b'\x0e\xa6u?\xca\x91\x0c\xbe\n\xf5\x81>')
bytearray(b'\x98\xd2u?\xf0C\r\xbe\x81\xc8\x81>')
bytearray(b'\xca\x8fu?\x03\x9d\r\xbe0\xa7\x82>')
bytearray(b'\xca\x8fu?\xb78\x0c\xbe\xb9\xd3\x82>')
bytearray(b'#cu?\xb78\x0c\xbe\x1dN\x82>')
bytearray(b'#cu?\xb78\x0c\xbe\x1dN\x82>')
bytearray(b'\xfcLu?\xdd\xea\x0c\xbe\x94!\x82>')
All right. Apparently, the data output is correct and everything works fine. My understanding of 12-byte data is wrong. Here is an example to read the first line of the example shown above:
>>> from struct import *
>>> data = bytearray(b'r u?\xb78\x0c\xbe\x1dN\x82>') # define 12-byte data
>>> unpack('f', data[0:4]) # unpack 1st floating value
(0.9575263261795044,)
>>> unpack('f', data[4:8]) # unpack 2nd floating value
(-0.13693509995937347,)
>>> unpack('f', data[8:12]) # unpack 3rd floating value
(0.25450220704078674,)

Python - PING a list of IP Address from database

Python - PING a list of IP Address from database
I have a list of ip addresses consisting of 200 locations, which in that location there are 4 ip addresses that I need to do ping testing. I intend to make a command which when I write the name or code of a particular location then it will directly ping to 4 ip address at that location. I have learned a bit to create a list that contains the ip address I entered through the command input () like this :
import os
import socket
ip = []
y = ['IP 1 : ','IP 2 : ', 'IP 3 : ', 'IP 4 : ']
while True:
for x in y:
server_ip = input(x)
ip.append(server_ip)
break
for x in ip:
print("\n")
rep = os.system('ping ' + x + " -c 3")
please give me a little advice about the command I want to make so that I no longer need to enter the ip address one by one. which still makes me confused, especially on how to make the existing items in the database into a variable x which we will insert into this command;
rep = os.system ('ping' + x + "-c 3")
EDIT: It now iterates over a CSV file rather than a hard-coded Python dictionary.
I believe you will be better off using python dictionaries rather than python lists. Assuming you are using Python 3.X, this is what you want to run:
import os
import csv
# Save the IPs you want to ping inside YOURFILE.csv
# Then iterate over the CSV rows using a For Loop
# Ensure your ip addresses are under a column titled ip_address
with open('YOURFILE.csv', newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
rep = os.system("ping " + row['ip_address'] + " -c 3")

Zlib won't decompress python 2.7

I am trying to move data from a server to a client via socket.
I try to compress data from the server and send it to the socket,
but when I try to decompress in the client I get this error:
zlib.error: Error -5 while decompressing data: incomplete or truncated stream
I think I know why, but I don't get why it happens.
Maybe it's because I try to decompress "Uncompressed" data,
because if the client got data it doesn't know if the data is compressed or not and trying to compress it now causes the error.
Maybe I'm completely wrong, but I don't know how to fix it, I need your help.
Client: gets the data (which is a string representing an image)
def room_client(port,ip):
roomC = socket.socket()
roomC.connect((ip, port))
while True:
print 'in while of client server'
#recv pict
#display
#send ack
img = ""
size = roomC.recv(1024)
roomC.sendall(size)
while len(img) < int(size):
data = roomC.recv(1024)
img += data
roomC.send("ACK")
to_pic = img.split('#')[0]
print to_pic
scrn = open("monitor_serv.png", "wb")
scrn.write(zlib.decompress(to_pic))
scrn.close()
Server: sending the image(screenshot)
def room_server(port):
#sends pictures
print 'in room_server '
roomS = socket.socket()
roomS.bind(('0.0.0.0',port))
roomS.listen(1)
client, addr = roomS.accept()
while True:
print 'in while of room server'
# take picture
# send picture
# recv ack
flag = True
img1 = ImageGrab.grab()
send = zlib.compress(img1.tobytes())
size = img1.size
send = send + "#" + str(size[0]) + "#"+ str(size[1]) + "#0#0"
client.sendall(str(len(send)))
print "0"
f = client.recv(1024)
print "A ", f
client.sendall(send)
g = client.recv(1024)
print "C ", g
while True:
if flag:
flag = False
img2 = ImageGrab.grab()
coordinates = equal(img1, img2)
cropped_image = img2.crop(coordinates)
else:
flag = True
img1 = ImageGrab.grab()
coordinates = equal(img1, img2)
cropped_image = img1.crop(coordinates)
if coordinates is not None:
size = cropped_image.size
send = zlib.compress(cropped_image.tobytes())
try:
send = send + "#" + str(size[0]) + "#" + \
str(size[1]) + "#" + str(coordinates[0]) + "#" + str(coordinates[1])
client.sendall(str(len(send)))
client.recv(1024)
client.sendall(send)
client.recv(1024)
except:
break
On the server, you're sending this:
send = zlib.compress(img1.tobytes())
size = img1.size
send = send + "#" + str(size[0]) + "#"+ str(size[1]) + "#0#0"
On the client, you're parsing it like this:
to_pic = img.split('#')[0]
print to_pic
scrn = open("monitor_serv.png", "wb")
scrn.write(zlib.decompress(to_pic))
There's going to be a # byte in almost all arbitrary compressed files. So your to_pic is going to be truncated at the first one. Which means zlib will almost always give you an error saying you've given it a truncated stream.
You need to come up with some other way to frame the data. Some options:
Instead of sending data#width#height#0#0 prefixed by the byte length of that string, you could send just data prefixed by its byte length, width, and height.
If you want to use # as a delimiter, you could escape any # bytes inside the actual image data, and then unescape on the other side. For example, you could replace('#', '##'), and then re.split on the first single # sign, and then replace('##', '#').
If you rsplit to pull off the last four #s instead of split to pull off the first oneā€¦ it's a bit hacky, but it would work here, because none of the other fields could ever have an # in them, just the compressed image data field.
There are other issues with the protocol framing that you need to rethink, but they're all things that, when you're sending smallish files over localhost sockets, will only occasionally come up; this is the only one that's almost bound to come up almost every time. Unfortunately, that doesn't mean you don't need to fix the other ones; it just means they'll be harder to debug.
Meanwhile, there's another flaw in your design:
What you get back from ImageGrab.grab() (even before cropping) isn't a PNG image, it's raw PIL/Pillow Image data. You compress that on the server, uncompress it on the client, and save those bytes as a PNG file. You can't do that.
One option is to use Pillow on the client as well: create an Image object from the decompressed bytes, then tell it to save itself to a PNG file.
Another option is to have the server export to bytes in PNG format instead of giving you the raw bytes. There are two big advantages to this version: No need for PIL installed on the client side, and PNG data is already compressed so you can scrap all your zlib stuff and write much simpler code.

How can I convert a CIDR list to a IP range list in Python? [duplicate]

Let's say I have a text file contains a bunch of cidr ip ranges like this:
x.x.x.x/24
x.x.x.x/24
x.x.x.x/23
x.x.x.x/23
x.x.x.x/22
x.x.x.x/22
x.x.x.x/21
and goes on...
How can I convert these cidr notations to all possible ip list in a new text file in Python?
You can use netaddr for this. The code below will create a file on your disk and fill it with every ip address in the requested block:
from netaddr import *
f = open("everyip.txt", "w")
ip = IPNetwork('10.0.0.0/8')
for addr in ip:
f.write(str(addr) + '\n')
f.close()
If you don't need the satisfaction of writing your script from scratch, you could use the python cidrize package.
based off How can I generate all possible IPs from a list of ip ranges in Python?
import struct, socket
def ips(start, end):
start = struct.unpack('>I', socket.inet_aton(start))[0]
end = struct.unpack('>I', socket.inet_aton(end))[0]
return [socket.inet_ntoa(struct.pack('>I', i)) for i in range(start, end)]
# ip/CIDR
ip = '012.123.234.34'
CIDR = 10
i = struct.unpack('>I', socket.inet_aton(ip))[0] # number
# 175893026
start = (i >> CIDR) << CIDR # shift right end left to make 0 bits
end = i | ((1 << CIDR) - 1) # or with 11111 to make highest number
start = socket.inet_ntoa(struct.pack('>I', start)) # real ip address
end = socket.inet_ntoa(struct.pack('>I', end))
ips(start, end)

Categories

Resources