原理就是调用socket模块里提供的各种API捕获数据包,然后根据RFC791协议对捕获的数据包按格式进行解析,把数据分类然后存储在一个字典里。
捕获部分代码:
def catchIPData():
# 获取本机IP作为公共网络接口
HOST = socket.gethostbyname(socket.gethostname())
# 创建一个原始套接字
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
# 将该套接字与公共网络接口绑定
s.bind((HOST, 0))
# 设定该套接字包含IP数据报首部
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# 设定该套接字接收所有数据包
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
# 接收一个数据包并返回
packet = s.recvfrom(4096)
return packet
解析部分代码:
def decodeIpHeader(packet):
# 创建一个空字典
IPDatagram = {}
# 根据RFC791协议对数据包进行解析
IPDatagram['version'] = packet[0] >> 4
IPDatagram['headLength'] = packet[0] & 0x0f
IPDatagram['serviceType'] = packet[1]
IPDatagram['totalLength'] = (packet[2] << 8) + packet[3]
IPDatagram['identification'] = (packet[4] << 8) + packet[5]
IPDatagram['flag'] = packet[6] >> 5
IPDatagram['moreFragment'] = IPDatagram['flag'] & 1
IPDatagram['dontFragment'] = (IPDatagram['flag'] >> 1) & 1
IPDatagram['fragmentOffset'] = ((packet[6] & 0x1f) << 8) + packet[7]
IPDatagram['TTL'] = packet[8]
IPDatagram['protocol'] = packet[9]
IPDatagram['headerCheckSum'] = (packet[10] << 8) + packet[11]
# 源IP地址和目的IP地址都按照IP地址的格式用字符串存储
IPDatagram['sourceAddress'] = "%d.%d.%d.%d" % (packet[12], packet[13], packet[14], packet[15])
IPDatagram['destinationAddress'] = "%d.%d.%d.%d" % (packet[16], packet[17], packet[18], packet[19])
# 根据数据包中头部长度确定是否有选项,如果有则添加至option列表中
IPDatagram['options'] = []
if IPDatagram['headLength'] > 5:
step = 5
while step < IPDatagram['headLength']:
IPDatagram['options'].append(packet[step * 4])
IPDatagram['options'].append(packet[step * 4 + 1])
IPDatagram['options'].append(packet[step * 4 + 2])
IPDatagram['options'].append(packet[step * 4 + 3])
step += 1
# 根据数据包中的总长度将数据部分添加至data列表中
IPDatagram['data'] = []
step = IPDatagram['headLength'] * 4
while step < IPDatagram['totalLength']:
IPDatagram['data'].append(packet[step])
step += 1
# 返回储存有数据包数据的字典
return IPDatagram