2
votes

Here is a simple exmaple:

from scapy.all import *
pkts = rdpcap('/tmp/sample.pcap')
wireshark(pkts)

Then wireshark gives this error:

The capture file appears to be damaged or corrupt.
(libpcap: IrDA capture has a packet with an invalid sll_protocol field)

I am using wireshark 1.8, python 2.7.3 and scapy 2.2.0.

NOTE: I can open the smaple.pcap file using wireshark directly.

What can I do to make scapy-generated pcap files to open in wireshark?

EDIT: I tried other pcap files (from wireshark capture samples) and it worked. It seems the problem is in my packets. Here is the first packet (which don't work also):

###[ cooked linux ]###
  pkttype   = unicast
  lladdrtype= 0x1
  lladdrlen = 6
  src       = '\x00\x04\xed\xcb\x9b0'
  proto     = 0x800
###[ IP ]###
     version   = 4L
     ihl       = 5L
     tos       = 0xb8
     len       = 165
     id        = 47433
     flags     = 
     frag      = 0L
     ttl       = 49
     proto     = udp
     chksum    = 0x50c9
     src       = 22.31.32.55
     dst       = 192.168.1.102
     \options   \
###[ UDP ]###
        sport     = 4566
        dport     = 4566
        len       = 145
        chksum    = 0x0
###[ Raw ]###
           load      = 'H\x84\x80\x80\x80\x80\x80\x8c\x80\x80\x86\x81\x8b\x82\x80\x82\x81\x98\xb1\xb9\xb2\xae\xb1\xb6\xb8\xae\xb1\xae\xb2\xb5\xad\xb0\xb1\xb2\xb2\xb6\xb6\xb5\xb7\xb4\xb9\xb4\xad\x81\xca\x82\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\xa6\x81\x80\xa7\x81\x80\xa8\x82\x80\x80\x84\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\x8a\x82\xe5\xee\x86\x88\xe3\xe3\xec\xe9\xe5\xee\xf4\xb2\x89\x84\x80\x80\x81\x80\xb8\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x88\x84\x80\x80\x81\x80\xb7\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x8c\x82\x80\x82\x9f\x84\x9e\xa7 \xe2\xb6\x80'

Note: changed IP addresses so checksum might not be correct.

2
Does wireshark([pkts[0]]) work? If it does, try finding the problematic packet. If it doesn't, edit your question with the value of pkts[0].Yoel

2 Answers

4
votes

I have no idea what seems to be the problem, but it can be resolved in the following manner:

wireshark(pkt for pkt in pkts) # don't supply a list but rather a generator

This also outputs the following message:

WARNING: PcapWriter: unknown LL type for generator. Using type 1 (Ethernet)

Apparently, the wireshark function doesn't handle a Linux cooked-mode capture that well. This odd situation might have something to do with the following excerpt from scapy's wiki:

Please remember that Wireshark works with Layer 2 packets (usually called "frames"). So we had to add an Ether() header to our ICMP packets. Passing just IP packets (layer 3) to Wireshark will give strange results.

We can also circumvent this issue by creating a dummy Ethernet layer, if we don't really care about the layer 2 frame:

pkts = [Ether(src=pkt[0].src)/pkt[1:] for pkt in pkts]

EDIT - upon further research, and analyzing scapy's source code, I figured out why passing a generator object seems to solve this issue.

The wireshark function creates a temporary file containing the packets and launches Wireshark with that file. The link type to be specified in the header of that file is extracted in the following manner:

if self.linktype == None:
    if type(pkt) is list or type(pkt) is tuple or isinstance(pkt,BasePacketList):
        pkt = pkt[0]
    try:
        self.linktype = conf.l2types[pkt.__class__]
    except KeyError:
        warning("PcapWriter: unknown LL type for %s. Using type 1 (Ethernet)" % pkt.__class__.__name__)
        self.linktype = 1

When passing a generator object, the first if statement evaluates to False (which is obviously a bug) and an exception is raised when attempting to access conf.l2types[pkt.__class__] since pkt.__class__ is <type 'generator'>. Therefore, the except clause of the try-except code block is executed and the link type is specified as 1.

However, when passing a real list, the first if statement evaluates to True and the first packet of the list is extracted and used to access conf.l2types, which is:

In [2]: conf.l2types
Out[2]: 
   0x1 <-  Dot3                 (802.3)
   0x1 <-> Ether                (Ethernet)
   0xc  -> IP                   (IP)
  0x17  -> Ether                (Ethernet)
  0x1f <-> IPv6                 (IPv6)
  0x65 <-> IP                   (IP)
  0x69 <-> Dot11                (802.11)
  0x71  -> CookedLinux          (cooked linux)
  0x77 <-> PrismHeader          (Prism header)
  0x7f <-> RadioTap             (RadioTap dummy)
  0x90 <-> CookedLinux          (cooked linux)
  0xc0 <-> PPI                  (Per-Packet Information header (partial))
 0x304  -> Ether                (Ethernet)
 0x321  -> Dot11                (802.11)
 0x322  -> PrismHeader          (Prism header)
 0x323  -> RadioTap             (RadioTap dummy)

Since pkts[0].__class__ is scapy.layers.l2.CookedLinux, the link type is set to 0x90 rather than to 0x71 (seems like yet another bug), which results in Wireshark failing to parse the file.


Therefore, I think that the best approach would be to copycat scapy's wireshark function, with the subtle change of allowing the user to explicitly specify the link type:

def wireshark(*args, **kwargs):
    """Run wireshark on a list of packets"""
    f = scapy.all.get_temp_file()
    scapy.all.wrpcap(f, *args, **kwargs)
    subprocess.Popen([scapy.all.conf.prog.wireshark, "-r", f])

wireshark(pkts, linktype=0x71)

EDIT - I've now noticed that the link type mapping issue was already reported and fixed by secdev. However, it hasn't reached python-scapy just yet. I've also created a new issue on the invalid handling of a generator object in PcapWriter.

0
votes

(libpcap: IrDA capture has a packet with an invalid sll_protocol field)

Linux IrDA uses something like the Linux cooked-mode header, but it's not the same:

I don't know what caused your program to choose 144 rather than 113; was your input file an Linux IrDA file rather than a Linux cooked capture file?