Scapy python script consuming too much cpu while sniffing
Asked Answered
B

1

6

I have coded a wireless probe sniffer using python + scapy. I'm want to use this script in openwrt routers.

Everytime it captures a probe request from nearby devices, the information is send to a webservice. (mac, power and probe).

My problem is the high consumption of CPU. The script runs quite good in my laptop (it takes between 50-70% of cpu), but when I run it in an openwrt router (400mhz cpu,16 ram) it takes 99%. It's a well known bug in scapy the lost of packets with high loads (I have tested at the same time the script in my laptop and in the router and the router do not catched all the available packets in the air)

I already made some optimizations to the code, but I think there's more room for improvement.

This is the script.

#!/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()

[UPDATE]

After a lot of reading and deep searching (it seems not many people have found full solution to the same issue or something similar). I have found you can filter directly from the sniff function, so I've added a filter to just catch probe requests.

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

In my laptop runs really smooth, using between 1%-3% of cpu and catching most of the available packets in the air.

but when I run this on the router, the script throws an error and crash.

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

I have tried using bpf filter syntax (the same used in tcpdump http://biot.com/capstats/bpf.html) and it is supposed you can also use it in scapy but I get a filter syntax error.

Sniff fucntion:

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

error:

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

In the router I have installed the last version of scapy and tcpdump. Now I really don't know what to do.

Boothe answered 15/7, 2015 at 8:12 Comment(15)
1: Capturing packets is a demanding thing to do 2: 400mhz isn't as powerful as you think, it will for sure utilize all of that power with ease to capture traffic under Python. If your PC uses 70% CPU that should be a good indication of the amount of power needed to capture all the packets since I assume you've got more than 2Ghz in your PC, which tells me you use roughly 1400Mhz to capture them all, now compare that to your 400Mhz. (it's not a accurate calculate, but gives you an idea of what you're doing)Paule
@Paule Why is it off-topic here?Verney
@Verney because he's not having an actual issue with his code, this is a request to enhance a already working example. Meaning it's due for a review not help (this is a "we help you fix your issue" site and the link i gave is a "we optimize for you" site)Paule
@Paule Using too much CPU sounds like an actual issue to me (or rather, a specific problem as it is said on the SO help center). Although this question could possibly be a good CR question, I believe this question is not off-topic for SO. Note that CR has a policy of pointing out any feedback with code, if this would be posted on CR the OP might get feedback on naming issues etc, which I believe is not what the OP wants, the OP wants to solve his issue with CPU usage.Fairweather
@SimonAndréForsberg Yea but then again, this code works. Probably as intended as well. It's not even certain we can help him here. He's not using any loops or weird vairable names. This is perfect for CR and would be to broad to solve here IMO. We're not here to polish code, we're here to solve issues (and no this isn't a issue, this is a design problem either by hardware specs or extreme optimization needed which is part of evolving code from reviews, not trouble shooting)Paule
@Paule I think you misunderstood the intention of SO a little. While what you describe makes up a big part of SO questions, that's not all of them. The code doesn't have to "not work" for a question to be on-topic at SO. I agree with Simon here :DMessaline
@Torxed: stop trying to shoehorn questions into CR. If this question is off-topic here, then vote to close it for proper, listed reasons. You can advise that a question might be a good CR fit, but the first rule of voting to close a post is that it has to actually be off-topic here.Comfrey
@Torxed: for example, this question might be too broad. At which point you vote to close it as such, advise the OP that it might be a better fit for CR (check their on-topic help info first) and flag the post to ask a moderator to migrate it. But don't abuse the custom close vote messages for this.Comfrey
@Torxed: note that the code works is also not a reason to flag somehing as off-topic. We have loads of questions where the code posted "works" already, just not good enough for specific metrics.Comfrey
@MartijnPieters I've tried to find the "Migrate to CR" for ages, even the "move to "unix.stackexchange.com" is no where to be found. Tell me how or a FAQ showing where those options are and i'll gladly do so.Paule
@Torxed: what part of it has to actually be off-topic and flag the post to ask a moderator did you miss? The migrate to options are deliberately limited.Comfrey
@MartijnPieters That wasn't my question nor was it my statement that I would use it on this topic. You told me to stop abusing the "Other" closure which I'm happy to do if I get a pointer where to find the "flag for migration" option, unless you meant the manual "Flag for operator" which in case I do not need you assistance and we can carry on ignoring the fact that I think this should not be here.Paule
Wow, I've never thought my question will ignite a discussion if something is on/off topic. If you see, I am really having a problem, I am missing packets, once I run the script on the router it's not able to catch all the available packets in the air. I've found out a temporary solution that runs on my pc but not in the router (the code crashed), I have updated the original question.Boothe
Can you get tcpdump to filter traffic using the same filter?Monacid
Yes, the filter is "tcpdump -s 256 -e -U -n -i mon0 type mgt subtype probe-req" and works great, it catches all the available packets and just uses 6% cpu running in the device. @EriksDobelisBoothe
F
1

I encountered a similar error (socket.error: [Errno 99] Protocol not available) when I tried to use sniff() with a filter on my NETGEAR WNDR4300.

After a lot of searching on Google, I found that the reason is that the Linux kernel of my router does not enable CONFIG_PACKET. It is mentioned in the Scapy installation guide, as follows:

  • Make sure your kernel has Packet sockets selected (CONFIG_PACKET)
  • If your kernel is < 2.6, make sure that Socket filtering is selected CONFIG_FILTER)

If you set CONFIG_PACKET=y when you compile the kernel, then it will enable the BPF for underlying socket.

Fireboard answered 10/12, 2015 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.