dpkt和scapy对处理大pcap包分析对比

对于scapy对pcap包的处理在我之前的一篇博客中有写:

https://blog.csdn.net/qq_38231051/article/details/81460427

这里对用scapy包对大pcap文件处理做出了简单的解决方法,但scapy包处理这种大文件有一个没法忍的缺点就是:

太慢了!!!

没错,特别慢,基本一个1G的文件要15分钟+,每跑一次数据我就得去看一集数码宝贝....

然后果然被要求优化。

emmmm

我试了试,用scapy直接遍历不做任何操作得12分钟+,没办法,就只能另寻出路了。


其实在我用spcay包之前我就用过dpkt,但......

dpkt的资料是真的少啊啊啊,

还是靠着万能的google捞到了自己想要的东西。跑1G数据(含数据处理)2分钟。优化后基本80s吧,不是很记得了。。。

不说废话了。。。。


这里分两部分,读pcap和写pcap文件(用dpkt写pcap文件的资料也是特少,我是看源码发现他有这个函数的。。。。)

dpkt读pcap文件

f = open('new1.pcap','rb')
pcap = dpkt.pcap.Reader(f)
for ts,buf in pcap:
    pass

ts是timestemp时间戳,buf(二进制数据)是主体的数据包信息。

如果我们想获取每个数据包的ip地址应该怎么做呢?

#由buf这个二进制数据转化为Ethernet类的对象
eth = dpkt.ethernet.Ethernet(buf)

ip_src = eth.data.src #这里是获取这个数据包的源ip
#要注意的是,这里的源ip是以二进制的方式返回的,如果我们要获取点分十进制的ip地址

#可以这样做
def inet_to_str(inet):
    try:
        return socket.inet_ntop(socket.AF_INET,inet)
    except:
        return False#这里因为具体需要我把IPv6给丢弃了
        #如果希望IPv6也能获取可以这样
        #return socket.inet_ntop(socket.AF_INET6,inet)
ip_src = inet_to_str(eth.data.src)
ip_dst = inet_to_str(eth.data.dst)#目的ip

如果要获取数据包的其他信息的话可以在官文文档中查看

https://dpkt.readthedocs.io/en/latest/print_packets.html

这里简单的贴一部分我的代码:

#coding=utf-8
import dpkt
import socket
import time

def inet_to_str(inet):
    try:
        return socket.inet_ntop(socket.AF_INET,inet)
    except:
        return False

def getip():
    f = open('new1.pcap','rb')#要以rb方式打开,用r方式打开会报错
    pcap = dpkt.pcap.Reader(f)
    for ts,buf in pcap:
        print(ts)打印时间戳
        eth=dpkt.ethernet.Ethernet(buf)

        #这里也是对没有IP段的包过滤掉
        if eth.type != dpkt.ethernet.ETH_TYPE_IP:
            continue

        ip = eth.data
        ip_src = inet_to_str(ip.src)
        ip_dst = inet_to_str(ip.dst)
        print(ip_src+'-->'+ip_dst)

if __name__=='__main__':
    getip()

这段代码在python3.6 centos7系统下运行没有问题


dpkt写文件

百度google了几次的我还以为dpkt不能写pcap文件呢,最后在dpkt官方文档看到了Writer方法,然后用dpkt.pcap.Writer在google找到了许多例子。

这是一个简单的例子:

f = open("new.pcap","wb")
writer = dpkt.pcap.Writer(test)
writer.writerpkt(eth,ts=ts)#参数意义可以对应上面的读文件中的两个参数
test.flush()
test.close()

这里只是一个整体的写法,我们来看一下细节方面,比如,我们怎么把一个数据包中的源地址和目的地址改为我们需要的:

test = open("new.pcap","wb")
writer = dpkt.pcap.Writer(test)
f=open("old.pcap",'rb')
packets = dpkt.pcap.Reader(f)
for ts,buf in packets:
    eth = dpkt.ethernet.Ethernet(buf)
    eth.data.src = socket.inet_pton(socket.AF_INET,"127.0.0.1")#这里是将点分十进制转化成二进制
    eth.data.dst = socket.inet.pton(socket.AF_INET,"127.0.0.2")
    writer.writepkt(eth,ts=ts)#如果不加ts参数的话,这个数据包的时间戳默认是当前时间!
    test.flush()
test.close()

源码不方便贴,上面的代码我没测试过。。。。如果报错,可能是该数据包没有ip的src,dst地址,就需要像之前读pcap那个一样进行协议过滤。也可能是其他小问题。可以多去google看官方文档学习。也可以留言一起交流。


总结

dpkt性能毫无疑问是比scapy更加有优势的,但dpkt这个包用起来远没有scapy包方便,如果只是小包处理的话,建议scapy,可以节省踩坑的时间。scapy中文资料也更加的多。如果要求性能的话我还是推荐dpkt。

 

你可能感兴趣的:(网络流量)