Scapy python 脚本在嗅探时消耗太多 CPU

Kar*_*tin 5 python wireless scapy

我已经使用 python + scapy 编写了一个无线探针嗅探器。我想在 openwrt 路由器中使用这个脚本。

每次它从附近的设备捕获探测请求时,都会将信息发送到 Web 服务。(mac、电源和探头)。

我的问题是CPU的高消耗。该脚本在我的笔记本电脑上运行得很好(它需要 50-70% 的 cpu),但是当我在 openwrt 路由器(400mhz cpu,16 ram)中运行它时,它需要 99%。这是 scapy 中的一个众所周知的错误,即高负载丢失数据包(我同时测试了笔记本电脑和路由器中的脚本,路由器没有捕获空中所有可用的数据包)

我已经对代码做了一些优化,但我认为还有更多的改进空间。

这是脚本。

#!/usr/bin/python
from scapy.all import *
import time
import thread
import requests
from datetime import datetime

PROBE_REQUEST_TYPE=0
PROBE_REQUEST_SUBTYPE=4
buf={'arrival':0,'source':0,'dest':0,'pwr':0,'probe':0}
uuid='1A2B3'

def PacketHandler(pkt):
    global buf
    if pkt.haslayer(Dot11):
        if pkt.type==PROBE_REQUEST_TYPE and pkt.subtype == PROBE_REQUEST_SUBTYPE:
            arrival= int(time.mktime(time.localtime()))
            try:
                extra = pkt.notdecoded
            except:
                extra=None

            if extra!=None:
                signal_strength = -(256-ord(extra[-4:-3]))
            else:
                signal_strength = -100

            source = pkt.addr2
            dest= pkt.addr3
            pwr=signal_strength
            probe=pkt.getlayer(Dot11).info

            if buf['source']!=source and buf['probe']!=probe:
                print 'launch %r %r %r' % (source,dest,probe)
                buf={'arrival':arrival,'source':source,'dest':dest,'pwr':pwr,'probe':probe}

                try:
                    thread.start_new_thread(exporter,(arrival,source,dest,pwr,probe))
                except:
                    print 'Error launching the thread %r' % source

def exporter (arrival,source,dest,pwr,probe):
    global uuid
    urlg='http://webservice.com/?arrival='+str(arrival)+'&source='+str(source)+'&dest='+str(dest)+'&pwr='+str(pwr)+'&probe='+str(probe)+'&uuid='+uuid
    try:
        r=requests.get(urlg)
        print r.status_code
        print r.content
    except:
        print 'ERROR in Thread:::::: %r' % source







def main():
    print "[%s] Starting scan"%datetime.now()
    sniff(iface=sys.argv[1],prn=PacketHandler,store=0)

if __name__=="__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

[更新]

经过大量阅读和深入搜索(似乎没有多少人找到相同问题或类似问题的完整解决方案)。我发现您可以直接从嗅探函数进行过滤,因此我添加了一个过滤器来捕获探测请求。

def main():
    print "[%s] Starting scan"%datetime.now()
    sniff(iface=sys.argv[1],prn=PacketHandler, filter='link[26] = 0x40',store=0)
Run Code Online (Sandbox Code Playgroud)

在我的笔记本电脑上运行非常流畅,使用了 1%-3% 的 CPU 并捕获了大部分可用的数据包。

但是当我在路由器上运行它时,脚本会引发错误并崩溃。

Traceback (most recent call last):
  File "snrV2.py", line 66, in <module>
    main()
  File "snrV2.py", line 63, in main
    sniff(iface=sys.argv[1],prn=PacketHandler, filter='link[26] = 0x40',store=0)
  File "/usr/lib/python2.7/site-packages/scapy/sendrecv.py", line 550, in sniff
    s = L2socket(type=ETH_P_ALL, *arg, **karg)
  File "/usr/lib/python2.7/site-packages/scapy/arch/linux.py", line 460, in __init__
    attach_filter(self.ins, filter)
  File "/usr/lib/python2.7/site-packages/scapy/arch/linux.py", line 132, in attach_filter
    s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 99] Protocol not available
Run Code Online (Sandbox Code Playgroud)

我曾尝试使用 bpf 过滤器语法(与 tcpdump http://biot.com/capstats/bpf.html 中使用的相同),并且假设您也可以在 scapy 中使用它,但我收到了过滤器语法错误。

嗅探功能:

def main():                                                                                                                                           
    print "[%s] Starting scan"%datetime.now()                                                                                                         
    sniff(iface=sys.argv[1],prn=PacketHandler, filter='type mgt subtype probe-req', store=0) 
Run Code Online (Sandbox Code Playgroud)

错误:

Traceback (most recent call last):
  File "snrV2.py", line 66, in <module>
    main()
  File "snrV2.py", line 63, in main
    sniff(iface=sys.argv[1],prn=PacketHandler, filter='type mgt subtype probe-req', store=0)
  File "/usr/lib/python2.7/site-packages/scapy/sendrecv.py", line 550, in sniff
    s = L2socket(type=ETH_P_ALL, *arg, **karg)
  File "/usr/lib/python2.7/site-packages/scapy/arch/linux.py", line 460, in __init__
    attach_filter(self.ins, filter)
  File "/usr/lib/python2.7/site-packages/scapy/arch/linux.py", line 120, in attach_filter
    raise Scapy_Exception("Filter parse error")
NameError: global name 'Scapy_Exception' is not defined
Run Code Online (Sandbox Code Playgroud)

在路由器中,我安装了最新版本的 scapy 和 tcpdump。现在我真的不知道该怎么办了。

小智 1

当我尝试使用时,我遇到了类似的错误(socket.error:[Errno 99]协议不可用)sniff()在 NETGEAR WNDR4300 上使用过滤器时,我遇到了类似的错误(socket.error:[Errno 99] 协议不可用)。

经过Google大量搜索后,我发现原因是我的路由器的Linux内核没有启用CONFIG_PACKET。Scapy安装指南中提到,如下:

  • 确保您的内核已选择数据包套接字 (CONFIG_PACKET)
  • 如果您的内核< 2.6,请确保选择套接字过滤(CONFIG_FILTER)

CONFIG_PACKET=y如果你在编译内核时设置,那么它将为底层套接字启用BPF。