底部的整个脚本。
因此,我正按照标题所说的尝试在python中创建LowLevel数据包嗅探器。创建原始套接字并捕获数据包的过程似乎正常。
我的问题是:当我尝试使用以下代码将源IP和目标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地址(类似字节的对象,长度为4个字节)转换为其标准的点分四进制字符串表示形式(例如,“ 123.45.67.89”)。
机智将src和dst IP转换为人类可读的格式,我得到了一堆无用的数字(显然这些数字代表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()