python arp header unpacking with struct module - python

I'm going to make my own python sniffer but i have problem with unpacking arp protocol header.
here is my code:
def Sniffer():
try:
# AF_PACKET, That's basically packet level.
# 0X0003, That's every packet. (We can find it here: /usr/include/linux/if_ether.h)
SK = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
except socket.error as MSG:
print "Socket creation error:\n", MSG
try:
while True:
Receive = SK.recvfrom(65565)
Packet = Receive[0]
Ethernet(Packet)
except socket.error as MSG:
print "Receive error:\n", MSG
# Ethernet Decapsulation (We need EtherType field value)
def Ethernet(Packet):
ETHERNET_LENGTH = 14
ETHERNET_HEADER = Packet[:ETHERNET_LENGTH]
ETHERNET_HEADER_UNPACK = struct.unpack("!6s6sH", ETHERNET_HEADER)
EtherType = ETHERNET_HEADER_UNPACK[2]
print EtherType
if EtherType == 2054:
ARP(ETHERNET_LENGTH, Packet)
if EtherType == 2048:
IPV4(Packet)
# ARP Decapsulation (We need OPCODE field value)
def ARP(ETHERNET_LENGTH, Packet):
ARP_LENGTH = 42
ARP_HEADER = Packet[ETHERNET_LENGTH:ARP_LENGTH]
ARP_HEADER_UNPACK = struct.unpack("!2s2s1s1s2s6s4s6s4s", ARP_HEADER)
OPCODE = ARP_HEADER_UNPACK[4]
if OPCODE == 1:
print "ARP Request (Some one scann your network)"
That's my error:
Traceback (most recent call last):
File "HoneySniffer.py", line 130, in <module>
Sniffer()
File "HoneySniffer.py", line 22, in Sniffer
Ethernet(Packet)
File "HoneySniffer.py", line 38, in Ethernet
ARP(ETHERNET_LENGTH, Packet)
File "HoneySniffer.py", line 48, in ARP
ARP_HEADER_UNPACK = struct.unpack("!2s2s1s1s2s6s4s6s4s", ARP_HEADER)
struct.error: unpack requires a string argument of length 28
why this is happening?
How can i to fix it?
I find it here: Python arp sniffing raw socket no reply packets

I have the exact same problem and i solved it using your reference link Python arp sniffing raw socket no reply packets and little research of my own.
conn=socket.socket(socket.AF_PACKET,socket.SOCK_RAW,socket.ntohs(0x0003))
def arp_header(packet):
(a ,b ,c ,d ,e ,f ,g ,h ,i ) = struct.unpack('2s2s1s1s2s6s4s6s4s',packet[14:42])
hw_type=(binascii.hexlify(a)).decode('utf-8')
proto_type=(binascii.hexlify(b)).decode('utf-8')
hw_size=(binascii.hexlify(c)).decode('utf-8')
proto_size=(binascii.hexlify(d)).decode('utf-8')
opcode=(binascii.hexlify(e)).decode('utf-8')
return (hw_type,proto_type,hw_size,proto_size,opcode,socket.inet_ntoa(g),socket.inet_ntoa(i))
use struct.unpack('2s2s1s1s2s6s4s6s4s',packet[14:42])
not struct.unpack('!2s2s1s1s2s6s4s6s4s',packet[14:42])
this solved my struct.error: unpack requires a string argument of length 28 error
i have also used individual variables,due to my project requirements,
Now ,for debugging i used print(packet[14:42]) -which gave me byte hex literals(like b'\x00\x01\x08\x00\x06\x04\x00\x01\xe4\x11[I&\xbe\n\x00..... etc)
so i have to decode in utf-8 after using hexlify,since hexlify is again returning byte objects to me.
Python version i used:3.6.5
Date:03/April/2019
Result:- Arp Packet:
- H/W Type: 0001, Protocol Type: 0800, H/W Size: 06 ,Protocol Size: 04
- Opcode: 0001, Source IP: 10.0.15.141, Destination IP: 10.0.10.2
Verdict:This method worked for me,i hope it will work for you also :)

Related

Python sending three-way handshake raw socket

I'm trying to code a python script through which I want to send packets from one host (desktop ubuntu) to a server (Ubuntu server) using multiple source addresses. I decided that would be best to use raw sockets and define my own TCP and IP header. I succeed to send the SYN packet and also get a response with the SYN-ACK packet but then my host doesn't respond with the ACK packet but with the RST packet. This is the first problem with I met in my solution. After the beginning of a three-way handshake I would like to send an HTTP GET keep-alive request. Does anyone know how to do it? Or does anyone know a better solution or library to use?
def send_raw_socket():
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
version_ihl_type_of_service = b'\x45\x00'
total_length = b'\x00\x3c'
Indentification = b'\xab\xcd'
flags_fragment_offset = b'\x00\x00'
TTL_protocol = b'\x40\x06'
Dest_add = b'\x0a\x0a'
Dest_add2 = b'\x1e\x03'
Src_add = b'\x0a\x0a'
src_add2 =b'\x0a\x0a'
Header_Checksum = my_ip_header_checksum(version_ihl_type_of_service, total_length, Indentification, flags_fragment_offset, TTL_protocol, Src_add,src_add2, Dest_add, Dest_add2)
IP_protocol = b'\x00\x06'
TCP_header_lenght = b'\x00\x14'
src_port = (int(src_port.hex(), 16)+49607).to_bytes(2, byteorder='big')
dest_port = b'\x1f\x95' # Source Port | Destination Port
seq_n1 = b'\x00\x00'
seq_n2 = b'\x00\x00' # Sequence Number
ack_n1 = b'\x00\x00'
ack_n2 = b'\x00\x00' # Acknowledgement Number
do_res = b'\x50\x02'
flags_win_s = b'\x71\x10' # Data Offset, Reserved, Flags | Window Size
checksum= tcp_header_checksum(IP_protocol, Src_add, src_add2, Dest_add, Dest_add2, TCP_header_lenght, src_port, dest_port, seq_n1, seq_n2, ack_n1, ack_n2, do_res, flags_win_s)
u_pinter= b'\x00\x00' # Checksum | Urgent Pointer
packet = version_ihl_type_of_service+total_length+Indentification+flags_fragment_offset+TTL_protocol+Header_Checksum+Src_add+src_add2+Dest_add+Dest_add2+src_port+dest_port+seq_n1+seq_n2+ack_n1+ack_n2+do_res+flags_win_s+checksum+u_pinter
s.sendto(packet, ('10.10.30.3',8085))
Wireshark three-way handshake

What does the integer return value mean, when I send a serial port message to my modem in Python?

How do I interpret the returned 4 in the following code, which is trying to send a basic AT message to my SIMCom 7600A modem via the serial AT port /dev/ttyUSB3?
from serial import Serial
# If a "port" is given, then the port will be opened immediately.
ser = Serial(port="/dev/ttyUSB3", timeout=2, write_timeout=2)
# The following prints as "True"
print(ser.is_open)
# Turn GPS on
ser.write(b"AT\r\n")
>>> 4
Here's another example when I request to "see GPS info", which returns 13:
ser.write(b"AT+CGPSINFO\r\n")
>>> 13
And one final example when I request to activate the GPS, which also returns 13:
ser.write(b"AT+CGPS=1,1\r\n")
>>> 13
Thanks!
-Sean
It is returning the length of the data that is written. Here is the source for the write function:
def write(self, data):
"""Output the given string over the serial port."""
if not self.is_open:
raise PortNotOpenError()
#~ if not isinstance(data, (bytes, bytearray)):
#~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
try:
# must call overloaded method with byte array argument
# as this is the only one not applying encodings
self._port_handle.Write(as_byte_array(data), 0, len(data))
except System.TimeoutException:
raise SerialTimeoutException('Write timeout')
return len(data)

how I do decode buffer message with struct

I write python socket client, but server return remaining time how to decode this structure in python.
header = Buffer.from( [03, 00, 00, 00]);
time = new Uint16Array(1);
time[0] = remaining_time_in_sec;
packet = Buffer.concat( [header, Buffer.from(time.buffer)]);
this.socket.write(packet);
this function return like
b'\x03\x00\x00\x00\t\x01'
i think solve this problem
this return binary code
b'\x03\x00\x00\x00\x0e\x01'
this here packet type
b'\x03\x00\x00\x00'
unpack('h',b'\x0e\x01')
return <======================
270

open a UDP socket on python 3.5

I'm trying to open a udp socket on python 3.5. I write a python code on python 2.7 and it works. when I moved on to python 3.5 it gives me an error , this is the python code :
from socket import *
import time
UDP_IP="192.168.1.26"
UDP_PORT = 6009
UDP_PORT2 = 5016
address= ('192.168.1.207' , 5454)
client_socket = socket(AF_INET , SOCK_DGRAM)
client_socket.settimeout(1)
sock = socket (AF_INET , SOCK_DGRAM)
sock.bind((UDP_IP , UDP_PORT))
sock2 = socket(AF_INET , SOCK_DGRAM)
sock2.bind((UDP_IP , UDP_PORT2))
while (1) :
data = "Temperature"
client_socket.sendto(data , address)
rec_data,addr = sock.recvfrom(2048)
temperature = float(rec_data)
print (temperature)
outputON_1 = 'ON_1'
outputOFF_1 = 'OFF_1'
seuil_T = 25.00
if (temperature < seuil_T) :
client_socket.sendto(outputOFF_1, address)
else :
client_socket.sendto(outputON_1 , address)
## sock.close()
data = "humidity"
client_socket.sendto(data , address)
rec_data , addr =sock2.recvfrom(2048)
humidity = float (rec_data)
print (humidity)
outputON_2 = "ON_2"
outputOFF_2 = "OFF_2"
seuil_H = 300
if humidity < seuil_H :
client_socket.sendto(outputOFF_2 , address)
else:
client_socket.sendto(outputON_2 , address)
This is the error that I got :
client_socket.sendto(data , address)
TypeError: a bytes-like object is required, not 'str'
In Python 3, the sendto, send and sendall methods on socket now take bytes objects and not strs. In order to fix this for your code you need to call .encode() your strings, e.g:
client_socket.sendto(outputOFF_2.encode() , address)
Or use byte string literals when defining them:
outputOFF_2 = b"OFF_2"
s.encode(), by default, will encode the string (s) using utf8. Alternate encodings can be provided as an argument, e.g: s.encode('ascii').
Also bear in mind that recv and recvfrom will now also return bytes so you may need to .decode() them (same rules apply to .decode as .encode).
you need to encode your string using
client_socket.sendto(bytes(data, 'utf-8') , address)

Receive UDP packet from specific source

I am trying to measure the responses back from DNS servers. Making a sniffer for a typical DNS response that is less than 512 bytes is no big deal. My issue is receiving large 3000+ byte responses - in some cases 5000+ bytes. I haven't been able to get a socket working that can receive that data reliably. Is there a way with Python sockets to receive from a specific source address?
Here is what I have so far:
import socket
import struct
def craft_dns(Qdns):
iden = struct.pack('!H', randint(0, 65535))
QR_thru_RD = chr(int('00000001', 2)) # '\x01'
RA_thru_RCode = chr(int('00100000', 2)) # '\x00'
Qcount = '\x00\x01' # question count is 1
ANcount = '\x00\x00'
NScount = '\x00\x00'
ARcount = '\x00\x01' # additional resource count is 1
pad = '\x00' #
Rtype_ANY = '\x00\xff' # Request ANY record
PROtype = '\x00\x01' # Protocol IN || '\x00\xff' # Protocol ANY
DNSsec_do = chr(int('10000000', 2)) # flips DNSsec bit to enable
edns0 = '\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00' # DNSsec disabled
domain = Qdns.split('.')
quest = ''
for x in domain:
quest += struct.pack('!B', len(x)) + x
packet = (iden+QR_thru_RD+RA_thru_RCode+Qcount+ANcount+NScount+ARcount+
quest+pad+Rtype_ANY+PROtype+edns0) # remove pad if asking <root>
return packet
def craft_ip(target, resolv):
ip_ver_len = int('01000101', 2) # IPvers: 4, 0100 | IP_hdr len: 5, 0101 = 69
ipvers = 4
ip_tos = 0
ip_len = 0 # socket will put in the right length
iden = randint(0, 65535)
ip_frag = 0 # off
ttl = 255
ip_proto = socket.IPPROTO_UDP # dns, brah
chksm = 0 # socket will do the checksum
s_addr = socket.inet_aton(target)
d_addr = socket.inet_aton(resolv)
ip_hdr = struct.pack('!BBHHHBBH4s4s', ip_ver_len, ip_tos, ip_len, iden,
ip_frag, ttl, ip_proto, chksm, s_addr, d_addr)
return ip_hdr
def craft_udp(sport, dest_port, packet):
#sport = randint(0, 65535) # not recommended to do a random port generation
udp_len = 8 + len(packet) # calculate length of UDP frame in bytes.
chksm = 0 # socket fills in
udp_hdr = struct.pack('!HHHH', sport, dest_port, udp_len, chksm)
return udp_hdr
def get_len(resolv, domain):
target = "10.0.0.3"
d_port = 53
s_port = 5353
ip_hdr = craft_ip(target, resolv)
dns_payload = craft_dns(domain) # '\x00' for root
udp_hdr = craft_udp(s_port, d_port, dns_payload)
packet = ip_hdr + udp_hdr + dns_payload
buf = bytearray("-" * 60000)
recvSock = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
recvSock.settimeout(1)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
sendSock.settimeout(1)
sendSock.connect((resolv, d_port))
sendSock.send(packet)
msglen = 0
while True:
try:
pkt = recvSock.recvfrom(65535)
msglen += len(pkt[0])
print repr(pkt[0])
except socket.timeout as e:
break
sendSock.close()
recvSock.close()
return msglen
result = get_len('75.75.75.75', 'isc.org')
print result
For some reason doing
pkt = sendSock.recvfrom(65535)
Recieves nothing at all. Since I'm using SOCK_RAW the above code is less than ideal, but it works - sort of. If the socket is extremely noisy (like on a WLAN), I could end up receiving well beyond the DNS packets, because I have no way to know when to stop receiving packets when receiving a multipacket DNS answer. For a quiet network, like a lab VM, it works.
Is there a better way to use a receiving socket in this case?
Obviously from the code, I'm not that strong with Python sockets.
I have to send with SOCK_RAW because I am constructing the packet in a raw format. If I use SOCK_DGRAM the custom packet will be malformed when sending to a DNS resolver.
The only way I could see is to use the raw sockets receiver (recvSock.recv or recvfrom) and unpack each packet, look if the source and dest address match within what is supplied in get_len(), then look to see if the fragment bit is flipped. Then record the byte length of each packet with len(). I'd rather not do that. It just seems there is a better way.
Ok I was stupid and didn't look at the protocol for the receiving socket. Socket gets kind of flaky when you try to receive packets on a IPPROTO_RAW protocol, so we do need two sockets. By changing to IPPROTO_UDP and then binding it, the socket was able to follow the complete DNS response over multiple requests. I got rid of the try/catch and the while loop, as it was no longer necessary and I'm able to pull the response length with this block:
recvSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
recvSock.settimeout(.3)
recvSock.bind((target, s_port))
sendSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
#sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sendSock.settimeout(.3)
sendSock.bind((target, s_port))
sendSock.connect((resolv, d_port))
sendSock.send(packet)
pkt = recvSock.recvfrom(65535)
msglen = len(pkt[0])
Now the method will return the exact bytes received from a DNS query. I'll leave this up in case anyone else needs to do something similar :)

Categories