计算机网络实验:IP包流量分析 (抓取IP包并解析,运行结果GUI输出)
系统:Mac Mojave10.14.6
环境:python3.7, pycharm CE
(计算机网络课程实验,老师要求抓包分析,也即实现一小部分Wireshark软件功能。网上查了很多资料,大多数使用了winpcap以及c++。很遗憾,我没学过c++,所以改用python,使用pypcap抓包,dkpt解析包。)
1.准备工作
pypcap是基于libpcap封装的为python语言提供的抓包库。
dpkt是用来解析数据包的库。
安装:在终端通过pip安装
$pip install pypcap
$pip install dpkt
安装成功页面:
成功安装pypcap-1.2.3以及dpkt-1.9.2,开始进行抓包分析。
2.抓包分析
import pcap
import dpkt
import time
'''
计网实验一:IP包流量分析
利用pcap抓包
利用dpkt解析包
输出IP数据包信息:time,src,dst,protocol,length,ttl,df,mf,offset,checksum
'''
# 所有网络接口
devs = pcap.findalldevs()
print('All NIC:',devs, sep='\n')
# 抓包
sniffer = pcap.pcap(name='en4', promisc=True, immediate=True)
# 解析: timestamp(时间戳),raw_buf(包中原始数据)
for timestamp, raw_buf in sniffer:
# 解析以太网帧
eth = dpkt.ethernet.Ethernet(raw_buf)
# 判断是否为IP数据报
if not isinstance(eth.data, dpkt.ip.IP):
print("Non IP packet type not supported ", eth.data.__class__.__name__)
continue
# 抓IP数据包
packet = eth.data
# 取出分片信息
df = bool(packet.off & dpkt.ip.IP_DF)
mf = bool(packet.off & dpkt.ip.IP_MF)
offset = packet.off & dpkt.ip.IP_OFFMASK
# 输出数据包信息:time,src,dst,protocol,length,ttl,df,mf,offset,checksum
output1 = {'time':time.strftime('%Y-%m-%d %H:%M:%S',(time.localtime(timestamp)))}
output2 = {'src':'%d.%d.%d.%d'%tuple(packet.src) , 'dst':'%d.%d.%d.%d'%tuple(packet.dst)}
output3 = {'protocol':packet.p, 'len':packet.len, 'ttl':packet.ttl}
output4 = {'df':df, 'mf':mf, 'offset':offset, 'checksum':packet.sum}
print()
print(output1)
print(output2)
print(output3)
print(output4)
3.程序解读
通过pcap.findalldevs()找出所有网络接口:
# 所有网络接口
devs = pcap.findalldevs()
print('All NIC:',devs, sep='\n')
运行结果如下:
All NIC:
['bridge0', 'utun0', 'en1', 'utun1', 'en2', 'en4', 'lo0', 'en0', 'gif0', 'stf0', 'XHC0', 'p2p0', 'awdl0', 'XHC20']
使用pcap.pcap()抓包:
# 抓包
sniffer = pcap.pcap(name='en4', promisc=True, immediate=True)
pcap.pcap()函数参数列表中name=‘en4’的意思是抓取网口en4的数据包,在上一条运行结果中也可以找到网口en4。那能不能抓取其他网口的数据包呢?我这里的尝试结果是不可以,因为我在连接校园网时使用的网口就是en4。所以在运行前检查一下本机使用的网口,实在不确定是哪一个,就在所有网口列表里一个个试吧。
接下来就是解析包:
# 解析: timestamp(时间戳),raw_buf(包中原始数据)
for timestamp, raw_buf in sniffer:
使用for循环解析sniffer中的各种包。
# 解析以太网帧
eth = dpkt.ethernet.Ethernet(raw_buf)
# 判断是否为IP数据报
if not isinstance(eth.data, dpkt.ip.IP):
print("Non IP packet type not supported ", eth.data.__class__.__name__)
continue
循环内部:先解析以太网帧,并判断是否为IP数据包,不是则输出提示语句跳出本轮循环,是则进行后续解析:
# 抓IP数据包
packet = eth.data
# 取出分片信息
df = bool(packet.off & dpkt.ip.IP_DF)
mf = bool(packet.off & dpkt.ip.IP_MF)
offset = packet.off & dpkt.ip.IP_OFFMASK
将IP数据包放入packet,取出其中包含的分片信息。接下来就是最后的输出部分:
# 输出数据包信息:time,src,dst,protocol,length,ttl,df,mf,offset,checksum
output1 = {'time':time.strftime('%Y-%m-%d %H:%M:%S',(time.localtime(timestamp)))}
output2 = {'src':'%d.%d.%d.%d'%tuple(packet.src) , 'dst':'%d.%d.%d.%d'%tuple(packet.dst)}
output3 = {'protocol':packet.p, 'len':packet.len, 'ttl':packet.ttl}
output4 = {'df':df, 'mf':mf, 'offset':offset, 'checksum':packet.sum}
print()
print(output1)
print(output2)
print(output3)
print(output4)
4.运行结果
首次运行可能会遇到类似错误:(cannot open BPF device) /dev/bpf0: Permission denied
解决方法是要在终端开启网口:sudo chmod o+r /dev/bpf*
之后就能顺利运行程序了,运行结果如下:
All NIC:
['bridge0', 'utun0', 'en1', 'utun1', 'en2', 'en4', 'lo0', 'en0', 'gif0', 'stf0', 'XHC0', 'p2p0', 'awdl0', 'XHC20']
Non IP packet type not supported bytes
Non IP packet type not supported ARP
Non IP packet type not supported LLC
Non IP packet type not supported bytes
Non IP packet type not supported bytes
{'time': '2019-10-23 15:44:16'}
{'src': '10.11.107.157', 'dst': '108.177.125.188'}
{'protocol': 6, 'len': 40, 'ttl': 64}
{'df': False, 'mf': False, 'offset': 0, 'checksum': 4249}
{'time': '2019-10-23 15:44:16'}
{'src': '108.177.125.188', 'dst': '10.11.107.157'}
{'protocol': 6, 'len': 52, 'ttl': 104}
{'df': False, 'mf': False, 'offset': 0, 'checksum': 62437}
Non IP packet type not supported bytes
{'time': '2019-10-23 15:44:28'}
{'src': '10.11.107.157', 'dst': '108.177.125.188'}
{'protocol': 6, 'len': 78, 'ttl': 64}
{'df': True, 'mf': False, 'offset': 0, 'checksum': 55956}
{'time': '2019-10-23 15:44:28'}
{'src': '108.177.125.188', 'dst': '10.11.107.157'}
{'protocol': 6, 'len': 78, 'ttl': 104}
{'df': False, 'mf': False, 'offset': 0, 'checksum': 54208}
{'time': '2019-10-23 15:44:28'}
{'src': '10.11.107.157', 'dst': '108.177.125.188'}
{'protocol': 6, 'len': 52, 'ttl': 64}
{'df': True, 'mf': False, 'offset': 0, 'checksum': 55982}
Non IP packet type not supported LLC
Non IP packet type not supported bytes
Non IP packet type not supported bytes
Non IP packet type not supported bytes
Non IP packet type not supported LLC
Non IP packet type not supported ARP
Non IP packet type not supported bytes
{'time': '2019-10-23 15:44:39'}
{'src': '10.11.107.140', 'dst': '10.11.107.255'}
{'protocol': 17, 'len': 229, 'ttl': 128}
{'df': False, 'mf': False, 'offset': 0, 'checksum': 58804}
Non IP packet type not supported LLC
Non IP packet type not supported bytes
在不人为干预的情况下,程序会一直进行抓包分析,不断输出解析结果。
到这里抓包解析就完成了。
(这里的运行结果在console输出。如果需要输出到GUI,欢迎阅读下一篇博客。)