python3捕获本机网卡IP数据包并解析

python3捕获本机网卡IP数据包并解析

相关知识

1.IP数据包

1.1IP数据包的格式

IP数据包的标头格式如图1所示。

img

图1 IP数据包格式

1.2 IP数据包的格式说明

IP数据报标头部分固定为20个字节,其中包含了12个参数域,各参数域的具体含义如下:

  1. 版本号(Version):长度4位,标识目前采用的 IP 协议的版本号。一般的值为 0100(IPv4),0110(IPv6)
    
  2. IP 报头长度(Header Length):长度4位,定义了一个以4B为一个单位的IP包的报头长度
    
  3. 服务类型(Type of Service):长度8位,用于指示路由器如何处理该数据包。该字段长度由4位服务类型(TOS)子域和3位优先级(precedence)子域组成,1位为保留位。
    
  4. 数据报总长度(Total Length):总长度为2B(即6位)。以字节为单位计算的 IP 包的长度(包括头部和数据),所以 IP 包最大长度 65 535 字节。
    
  5. 标识符(Identifier):长度16位,用于识别IP数据报的编号,让目的主机判断新来的数据属于哪个分组。
    
  6. 标志(Flags):共3位,最高位为0;DF禁止分片标识。DF=0,可以分片;DF=1,不能分片。MF:分片标识。MF=0,表示接的是最后一个分片;MF=1,不是最后一个分片。
    
  7. 片偏移(Fragment Offset):共13位,说明分片在整个数据报中的相对位置。
    
  8. 生存时间(TTL):8位,用来设置数据数据报在整个网络传输过程中的寿命。常以一个数据报可以经过的最多的路由器跳步数来控制。
    
  9. 协议(Protocol):共8位,表示该IP数据报的高层协议类型。
    
  10. 头部校验(Header Checksum):共16位,用于存放检查报头错误的校验码。校验的范围是整个IP包的报头。
    
  11. 起源和目标地址(Source and Destination Addresses):包括源、宿主机地址,共32位。分别表示发送和接受数据报的源主机和宿主机的IP地址。
    

12) 可选项(Options):长度范围是0~40B,主要用于控制和测试。在使用选项字段的过程中,有可能出现报头部分的长度不是32位的整数倍的情况。如果出现这种情况,就需要通过填充位来凑齐。

2.套接字

2.1 套接字的概念

a) socket(套接字)接口是应用程序与TCP/IP协议栈的接口,它定义了一组函数或例程来支持TCP/IP网络应用程序开发。

b) socket(简称套接字) 是进程间通信的一种方式。

c) 它能实现不同主机间的进程间通信。

2.2 网卡设置

为了获取网络中的IP数据包,必须对网卡进行编程。但是,在通常情况下,网络通信的套接字程序只能响应与自己硬件地址相匹配的数据包或是以广播形式发出的数据包。对于其他形式的数据包,如已到达网络接口,但却不是发送到此地址的数据包,网络接口在投递地址并非自身地址之后将不引起响应,我们要想获取网络设备的所有数据包,需要将网卡设置为混杂模式。

python socket中在windows操作系统下开启混杂模式使用s.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)

2.3 使用原始套接字

1、使用socket.socket(family=AF_INET,type=SOCK_STREAM,

proto=0,fileno=None) 创建套接字

a) family :用于指定socket的地址类型,前缀AF即Address Family的缩写。最常见的有AF_INET和AF_INET6两种,分别表示使用IPv4和IPv6协议。

b) type :用于指定socket的类型,使用SOCK前缀。常见的有以下几种类型:

  • SOCK_STREAM(流式套接字):使用TCP或STCP协议,面向连接的socket;

  • SOCK_DGRAM(数据报套接字):使用UDP协议,无连接的socket;

  • SOCK_RAW:这类socket,数据包将绕过运输层,因此可以在应用层得到数据包的头部;

2、socket相关函数

  • socket.bind(adress) :该函数将socket绑定到一个地址上;

  • socket.listen([backlog]) :启动监听,即允许服务器接受连接;

  • s.recvfrom(bufsize[.flag]):接受UDP套接字的数据;

3.scapy模块

3.1 scapy介绍

scapy是python写的一个功能强大的交互式数据包处理程序,可用来发送、嗅探、解析和伪造网络数据包,常常被用到网络攻击和测试中。

3.2 使用scapy抓包

1、安装scapy:pip3 install scapy

2、使用scapy抓包

def sniff(count=0,store=1,offline=None,prn=None, lfilter=None,L2socket=None,timeout=None,opened_socket=None,stop_filter=None, iface=None, *arg, **karg)

使用sniff()函数可以轻松捕获某些数据包,甚至克隆tcpdump或tshark。可以提供一个接口或要监听的接口列表。

3.3winpcap

进行Windows平台上的抓包前需要安装winpacap。winpcap(windows packet capture)是windows平台下一个免费,公共的网络访问系统。开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它用于windows系统下的直接的网络编程。

程序实现

开发环境

windows、python3.6

方法1:使用socket编程实现抓包解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#coding=utf-8
import socket
import os
from time import *
import sys

def catchIPData():
HOST = socket.gethostbyname(socket.gethostname())
# 如果操作系统是windows系统
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
s.bind((HOST, 0))#将socket绑定到一个地址上
if os.name == "nt":#windows下需要开启混杂模式
s.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
begin_time = time()
end_time = 912568857479
try:
while (end_time-begin_time>1):
packet = s.recvfrom(65565)[0]#从网卡上捕获包
ip_header = decodeIpHeader(packet[0:20])# 将缓冲区的前20个字节按IP头进行解析
#print(ip_header)
end_time = time()
print(end_time)
except KeyboardInterrupt:
if os.name == "nt":
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)#关闭混杂模式
return ip_header

def decodeIpHeader(packet):#对IP数据头进行解析
IPDatagram = {}
IPDatagram['version'] = packet[0] >> 4 # 版本字段与IP数据报头部共享一个字节,通过右移操作取得单独的版本字段
IPDatagram['headLength'] = packet[0] & 0x0f # 首部长度字段的1代表4个字节
IPDatagram['serviceType'] = packet[1] # 区分服务
IPDatagram['totalLength'] = (packet[2] << 8) + packet[3] # IP首部+数据的总长度,即len(packet)
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] # 首部校验和
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]) # 目的地址
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
IPDatagram['data'] = []
return IPDatagram

if __name__ == '__main__':
packet=catchIPData()
HOST = socket.gethostbyname(socket.gethostname())
print("HOST:", HOST)
print("正在抓包中,已将数据包保存至capture1.txt")
# 输出重定向:在控制台的输出重定向到 txt文本文件中
output = sys.stdout
outputfile = open('./capture1.txt', 'w')
sys.stdout = outputfile
while True:
# 逐个数据包打印信息,重定向至txt
for i in range(len(packet)):
print("----------No.%d-----------"%i)
for key in packet:
if (key == 'protocol'):
protocol_list = {'1':'ICMP','2':'IGMP','6':'TCP','17':'UDP','88':'IGRP','89':'OSPF'}
print(key + ":" + protocol_list[str(packet[key])])
else:
print(key + ":" + str(packet[key]))

图1为程序运行结果。如图2所示,解析数据包后保存每个IP数据包的IP头的所有域内容在txt文本中,包括:版本号(Version)、IP 报头长度(Header Length)、服务类型(Type of Service)、数据报总长度(Total Length)、标识符(Identifier)、标志(Flags)、片偏移(Fragment Offset)、生存时间(TTL)、协议(Protocol)、头部检验(Header Checksum)、起始和目标地址(Source and Destination Address)、可选项(Options)。

图1 程序运行结果
图2 保存IP数据包信息的txt文件

方法2:使用scapy实现抓包解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#python 3.6
#scapy版本2.4.3
from scapy.all import *
import sys

def save_info(dpkt):
print("--------------------------总结-----------------------------")
print("总计捕获包数:", len(dpkt))
wrpcap('./demo.pcap', dpkt)
print("成功将捕获信息保存至demo.pcap!")
print("将捕获信息保存至capture.txt方便查看!")
# 输出重定向:在控制台的输出重定向到 txt文本文件中
output = sys.stdout
outputfile = open('./capture.txt', 'w')
sys.stdout = outputfile
# 逐个数据包打印信息,重定向至txt
for i in range(len(dpkt)):
print(dpkt[i])
print(dpkt[i].show())
return True

if __name__ == "__main__":
mode = int(input("请选择嗅探模式1或2 1:按时间嗅探;2:按捕获包数嗅探;"))
if(mode == 1):
capture_time = int(input("请输入嗅探时间(以秒为单位)"))
dpkt = sniff(filter='ip',prn=lambda x: x.summary(),timeout= capture_time)#嗅探抓取ip数据包
if(save_info(dpkt)):
print("此轮结束")
elif(mode == 2):
capture_counts = int(input("请输入捕获包数:"))
dpkt = sniff(filter='ip', prn=lambda x: x.summary(), count=capture_counts)
if(save_info(dpkt)):
print("此轮结束")
else:
print("输入有误")

将抓捕数据包保存为demo.pcap,并且将数据包解析结果保存为capture.txt。解析IP头的所有域内容,包括:version,head Length,service of type,identifier,flags,fragment offset,TTL,protocol,header checksum,source address,destination address,options。

img

图3 程序运行结果图

img

图4 捕获信息解析txt文件
作者

terese

发布于

2019-10-10

更新于

2022-10-05

许可协议