Ricky Robinson
Ricky Robinson

Reputation: 22893

buggy behaviour in Scapy

I use Scapy's function send to send data packets that will generate ICMP packets at routers and dump those ICMP packets with tcpdump, launched as a child process.

Then, I will read those ICMP packets back into my program with scapy's built-in rdpcap function.

Well, it turns out that rdpcap sometimes messes up something and as soon as I want to peek into my captured packets, it returns the following:

(InteractiveConsole)
>>> icmpPackets
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/scapy/plist.py", line 57, in __repr__
    if self._elt2pkt(r).haslayer(p):
AttributeError: 'NoneType' object has no attribute 'haslayer'

Then, I will just need to call rdpcap again on the same argument and everything will go back to normal:

>>> icmpPackets = rdpcap(tcpdumpFileName)
>>> icmpPackets
<icmpPackets.cap: TCP:0 UDP:0 ICMP:1428 Other:1>

This is some bug, right?

EDIT: Ok, the one thing I do before I get that error is the following, which might not be too orthodox, but I don't need the ethernet layer when I'm forging packets. If I remove these two lines, I won't get any such errors:

for i in range(len(icmpPackets)):
        icmpPackets[i] = icmpPackets[i].getlayer(IP)

I did this before elsewhere and never got a problem. What's happening here?

Upvotes: 2

Views: 1138

Answers (1)

Pierre
Pierre

Reputation: 6237

Hi,

I don't really understand why you sniff traffic with tcpdump rather than scapy, but anyway... Your problem is not a bug in Scapy but rather in your code. You're replacing each packet with its .getlayer(IP) which returns None if the packet has no IP layer (e.g., ARP packets). Hence the exception you get latter.

I think you should replace

icmpPackets = rdpcap(tcpdumpFileName)
for i in range(len(icmpPackets)):
    icmpPackets[i] = icmpPackets[i].getlayer(IP)

with

icmpPackets = PacketList([p[IP] for p in PcapReader(tcpdumpFileName) if IP in p])

First of all I think it's more "Pythonic", plus it fixes the problem by removing the packets without IP layer. Or you could also use, if you want to have all the packets without the Ether layer:

icmpPackets = PacketList([p.payload for p in PcapReader(tcpdumpFileName)])

Plus you could filter with a BPF filter in tcpdump (icmp if you just want ICMP packets).

Upvotes: 1

Related Questions