Весь скрипт внизу.
Итак, я пытаюсь, как сказано в заголовке, создать анализатор пакетов LowLevel в python.Процесс создания необработанного сокета и захвата пакета, кажется, работает нормально.
Моя проблема: когда я пытаюсь перевести исходный и целевой IP-адреса в удобочитаемую форму, используя следующий код:
self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
self.dst_address = socket.inet_ntoa(struct.pack('<L', self.dst))
Я получаю следующую ошибку:
Traceback (most recent call last):
File "ip_header.py", line 68, in <module>
sniffer()
File "ip_header.py", line 62, in sniffer
header = IP(raw_buffer)
File "ip_header.py", line 31, in __init__
self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
struct.error: 'L' format requires 0 <= number <= 4294967295
Я знаю, что ошибка вызвана struct.pack('<L', self.src)
Поэтому я изменил формат с Long (L) на Long Long (Q).Затем я получаю еще одну ошибку, вызванную функцией socket.inet_ntoa()
.
OSError: packed IP wrong length for inet_ntoa
По сути, эта функция преобразует 32-разрядный упакованный адрес IPv4 (байтовоподобный объект длиной четыре байта).) к стандартному строковому представлению с точками в квадрате (например, «123.45.67.89»).
Без перевода IP-адресов src и dst в удобочитаемый формат, я получаю кучу бесполезных чисел (очевидно, эти цифры представляют IP-адрес)
procotol : ICMP, src : 2623909733031061696 -> dst : 6651666592092407870
ЗДЕСЬ ВЕСЬ СЦЕНАРИЙ
#!/usr/bin/env python3
import struct
import socket
from ctypes import *
class IP(Structure):
'''
This class parse IP header
'''
# list of ip protocols
# structre of ip header
_fields_ = [
("ihl", c_ubyte, 4), # Internet Header Length represent the number of 32bits words.
("version", c_ubyte, 4), # ip version number ( 4 for ipv4 ) , size = 4 bits
("tos", c_ubyte),
("len", c_ushort), # Total Size of ip packet not only the header (20 bytes < len < 65535), size = 2 bytes
("id", c_ushort),
('offset', c_ushort),
('ttl', c_ubyte), # Time To Live in seconds , size = 1 byte
('protocol_num', c_ubyte), # Protocol Number , (1 : icmp, 6:tcp, 17:udp ...) , size = 1 byte
('sum', c_ushort), # Header CheckSum, size = 2 bytes
("src", c_ulong), # Source Address , size = 4 bytes
("dst", c_ulong) # Destination Address , size = 4 bytes
]
def __new__(self, socket_buffer=None):
# create ctypes buffer from socket buffer
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
# human readable ip
self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
self.dst_address = socket.inet_ntoa(struct.pack('<L', self.dst))
# get type of protocol
if self.protocol_num == 1:
self.protocol = 'ICMP'
elif self.protocol_num == 6:
self.protocol = 'TCP'
elif self.protocol_num == 17:
self.protocol = 'UDP'
else :
self.protocol = self.protocol_num
def sniffer():
'''
create raw socket , sniff packets , close socket
'''
# create socket
socket_protocol = socket.IPPROTO_ICMP
sniff = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
# include ip header in the capture
sniff.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# capture packet
try :
while True:
raw_buffer, addr = sniff.recvfrom(4096)
# parse packet header
header = IP(raw_buffer)
print("procotol : {}, src : {} -> dst : {}".format(header.protocol, header.src_address, header.dst_address))
except KeyboardInterrupt:
sniff.close()
if __name__ == '__main__':
sniffer()