1
votes

I have configured a Cisco router to dump a pcap file for traffic on a specific interface that I am trying to parse with dpkt and Python (2.7). The basic code is:

f = open('pktrace1.pcap','rb')
pcap = dpkt.pcap.Reader(f)

for ts,buf in pcap:
    eth = dpkt.ethernet.Ethernet(buf)
    ip = eth.data
    tcp = ip.data

f.close()

Now unfortunately for whatever reason the pcap dumps from the router leave the layer 2 information blank and the frame is encapsulated in a raw IP format. The above code fails at line 7 with the following AttributeError: 'str' object has no attribute 'data'

I guess that makes sense because it expects to parse layer 2 Ethernet information that doesn't exist.

I am relatively new to Python and the dpkt documentation has not been much help to me. Does anybody know how I can have dpkt handle these packets that lack the Ethernet information? Or perhaps how to have the router (Cisco 2911, IOS 15.0) export them with Ethernet information in tact?

I feel like there has got to be a simple way to make dpkt handle these dumps, as Wireshark can read them perfectly. Any help is much appreciated! :)

2

2 Answers

4
votes

To parse a raw IP pcap, I found that (quite logically) one has to skip the dpkt ethernet decode and jump straight to an IP decode as follows:

f = open('tun0.pcap')
pcap = dpkt.pcap.Reader(f)

for ts,buf in pcap:
    ip = dpkt.ip.IP(buf)
    tcp = ip.data

f.close()

I came across your question when I had the same problem, caused by running tcpdump on a tun0 virtual tunnel interface

The unix 'file' command showed the capture file type as:

tun0.pcap: tcpdump capture file (little-endian) - version 2.4 (raw IP, capture length 8192)

Whereas a dump from a real interface gave:

eth0.pcap: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)

I am sure you have already found the answer by now, but I am posting this in case others have the same question. It's my first time "giving something back" so I hope it's actually correct and useful!

2
votes

My reputation is too low to post a comment, but I thought I might have some relevant data to share, so herewith in the answer box instead

BTW, can you please provide some details about what tool you use to generate the pcap file and also your example "pktrace1.pcap" data? And also: if you capture with an AirPCAP adapter, you may be able to configure how it captures the data by its own settings. And if you need access to the data, you need to ensure that the network key has been enabled properly for the AirPCAP dongle (or your Cisco router must have network security disabled), otherwise there will also be no access to the data.

Then the main reason for this post: I had previously used the impacket lib previously, and thought this may help you as well. Here below is an example:

'''
Packet sniffer in python using the pcapy python library
python filter compile from http://carnivore.it/2010/06/12/python3_-_ctypes
pcapy compile from http://www.salstar.sk/pub/salpack/usr/sbin/httop.py and http://bytes.com/topic/python/answers/681254-python-packet-filter-pcapy
actual filtering answer on https://github.com/LeonB/dabbler/blob/master/pcapy-test.py ??
'''

import socket
from struct import *
import datetime
import sys
import radiotap
import pcapy
from impacket import ImpactDecoder, ImpactPacket

AIRPCAP_ADAPTER = '\\\\.\\airpcap00'
filter_string = '' # do not use with airpcap00 as this requires adapter to be on network so it seems (decryption key etc)

def main(argv):
    cap = pcapy.open_live(AIRPCAP_ADAPTER, 65536, 1, 0)
    #bpf = pcapy.compile (cap, 1500, filter_string, 0, 1)
    cap.setfilter(filter_string)
    print "Listening on %s: net=%s, mask=%s, linktype=%d" % (AIRPCAP_ADAPTER, cap.getnet(), cap.getmask(), cap.datalink())

    # Read packets -- header contains information about the data from pcap,
    # payload is the actual packet as a string
    # callback for received packets
    def recv_pkts(hdr, data):
        decoder = ImpactDecoder.EthDecoder()
        ether = decoder.decode(data)
        print ether
        # Parse the IP packet inside the Ethernet packet

    packet_limit = -1 # infinite
    cap.loop(packet_limit, recv_pkts) # capture packets


if __name__ == "__main__":
    main(sys.argv)