How to process packet captures with Python's dpkt module - python

I am trying to write a python program to parse packet capture using dpkt module. I have used it on packet captures that had Ethernet and tcpdump captures and it worked fine. However, my current packet capture is raw packet capture that directly has IP header and subsequent protocols and it seems like dpkt is not able to understand these captures. Picture of capture file is attached. enter image description here
The code I had was
f = open(ipfile, 'rb')
pcap = dpkt.pcap.Reader(f)
for ts,buf in pcap:
eth = dpkt.ethernet.Ethernet(buf) //Also tried with eth = dpkt.sll.SLL(buf), but no luck.
ip = eth.data
tcp = ip.data
Any ideas on how to parse such captures?
Thanks !!

I had the same issue with CAIDA pcap. Try
ip = dpkt.ethernet.Ethernet(buf)

Related

Why does sender IP address increment in Scapy?

I am trying to make a TCP packet that is sent to my other computer 500 times. I have created this code:
from scapy.all import *
from scapy.utils import rdpcap
#Create your own packets
data = 'This is a test'
myPacket = Ether(src="00:E0:4C:00:02:42",dst="00:E0:4C:01:08:99")/IP(src="169.254.162.71/16",dst="169.254.208.208/16")/TCP()/Raw(load=data)
print(myPacket.show())
for i in range (0,500):
sendp(myPacket, iface="Ethernet 4") # sending packet at layer 2
The issue is that when I run this code, the computer receives packets with an incrementing Source IP and the Destination IP is wrong, for some reason:
Any help fixing this would be appreciated.
The /16 in your addresses is called a netmask in CIDR notation. It means that your adresses are subnets that include all possible addresses between 169.254.0.0 and 169.254.255.255. (Same for the source IP)
See https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing and https://en.wikipedia.org/wiki/Private_network
Scapy is going to send 256x256x256x256 (accounting for both sr and dst) packets with all possible addresses, starting as you saw with the 0.0 ones. You just need to remove the /16.

Python sniffer using pypcap and dpkt on OS X

I'm actually trying to sniff packets with python (using pypcap and dpkt).
I tried the following :
import dpkt, pcap
pc = pcap.pcap() # construct pcap object
pc.setfilter('src host X.X.X.X or dst host X.X.X.X')
for timestamp, packet in pc:
print dpkt.ethernet.Ethernet(packet)
But nothing happens when I launch the script... Did I miss something ?
Using Python 2.7
On OS X Yosemite (10.10)
The question is old but for new people who might hit this. The github 'chains' project uses both pypcap and dpkt for exactly this kind of thing (Disclaimer: I'm involved with all three projects :) https://github.com/SuperCowPowers/chains
chains/sources/packet_streamer.py (code showing use of pypcap for 'sniffing')
chains/links/packet_meta.py (code showing use of dpkt for packet parsing)
For those that just want to use pypcap/dpkt here's a working code snippet:
import pcap
import dpkt
sniffer = pcap.pcap(name=None, promisc=True, immediate=True)
for timestamp, raw_buf in sniffer:
output = {}
# Unpack the Ethernet frame (mac src/dst, ethertype)
eth = dpkt.ethernet.Ethernet(raw_buf)
output['eth'] = {'src': eth.src, 'dst': eth.dst, 'type':eth.type}
# It this an IP packet?
if not isinstance(eth.data, dpkt.ip.IP):
print 'Non IP Packet type not supported %s\n' % eth.data.__class__.__name__
continue
# Grab ip packet
packet = eth.data
# Pull out fragment information
df = bool(packet.off & dpkt.ip.IP_DF)
mf = bool(packet.off & dpkt.ip.IP_MF)
offset = packet.off & dpkt.ip.IP_OFFMASK
# Pulling out src, dst, length, fragment info, TTL, checksum and Protocol
output['ip'] = {'src':packet.src, 'dst':packet.dst, 'p': packet.p,
'len':packet.len, 'ttl':packet.ttl,
'df':df, 'mf': mf, 'offset': offset,
'checksum': packet.sum}
print output
You should check out Scapy. Its a powerful networking tool, that can be used interactivly as well. Its written in python, hence you can use it in your scripts as well.
In scapy its as easy as (but you can easily add filters as well):
sniff(iface='eth0')
If you didn't place the path to a file in pcap.pcap(), there's no pcap for it to parse.
I ran your script with a glob of from a pcap directory I have and replaced the IP with one in my network, seemed like it worked.
You sure you installed pypcap and dpkt?
Here's exactly what I did with your script.
import dpkt, pcap, glob
for i in glob.glob("/pcap/*.pcap"):
pc = pcap.pcap(i)
pc.setfilter('src host 192.168.1.140 or dst host 192.168.1.140')
for timestamp, packet in pc:
print dpkt.ethernet.Ethernet(packet)
It printed a lot of stuff.
Nothing jumps out at the code, so I'm wondering if it is just the network.
Can you double check the IP addresses and also maybe run tcpdump as a sanity check to make sure you can see traffic?
For tcpdump something like this
$ sudo tcpdump -i en1 "src host 10.0.0.2 or dst host 10.0.0.2"

Whole packet length Scapy

I am capturing WiFi traffic with tcpdump using the parameter -s 100 (which means I am only capturing the headers of the packets).
When I load the .pcap file and process it with Scapy I do:
pkts = rdpcap(pcapfile)
totalbytes = 0
for pkt in pkts:
totalbytes += len(pkt)
However, as I am truncating the capture, doing len(pkt) will not give me the whole packet length (frame length), it will give me the captured packet length. How can I get the real packet length?
Extra: as I have done in some occasions before, I open the pcap file in wireshark and search for the hex values of interest. But in this case (frame.len) will show the value I am looking for, but I can't find the way wireshark obtains this real packet length without having the whole packet captured.
The rdpcap function uses the PcapReader class for reading packets. Unfortunately this class discards the information you are looking for in the read_packet method, even though it is to be found in the pcap file. So you have to use the RawPcapReader directly.
totalbytes = 0
for pkt, (sec, usec, wirelen) in RawPcapReader(pcapfile):
totalbytes += wirelen
With modern Scapy versions, the proper answer would be to use pkt.wirelen. This only exists in packets read from a pcap
If for some reason you don't want to use RawPcapReader, you can use the len attribute for IPv4 packets.
real_length = pkt[IP].len
truncated_length = len(pkt)
Strangely, the IPv6 layer in Scapy doesn't have the same attribute, but it does have an attribute called plen which is the length of the payload:
payload_length = pkt[IPv6].plen
real_length = payload_length + 40
truncated_length = len(pkt)

Reading MAC frame and feeding it to Wireshark

We have a device receiving 802.11p MAC frames from the air and feeding them to the serial port completely unchanged (no network layer headers) and we'd like to see them arranged in Wireshark, so we can have a sort of self made sniffer for this 802.11p protocol.
My approach (in linux with python) was, open the serial port, read the frames and write them to a named pipe which wireshark would be listening to. After a lot of searching I've found out that the format i have to write into that pipe has to be like the pcap files format. I've looked to some python modules that do pcap formatting (scapy, pcapy, dpkt), but i can't find any that gets a pure MAC frame and simply writes it to a file in the pcap format in a way that wireshark can read and without me having to do all the parsing. What is your suggestion?
How about just creating a tap device and writing the frames to that? Then you can sniff the tap device with wireshark just like any other device. There's an example using a tap device in Python here, and a longer tutorial (actually about tun devices) in C here.
NB: I haven't tested this, but the idea seems reasonable...
UPDATE: This seems to work. It's based on the above gist, but
simply reads frame data from a file and writes it to the device:
import sys
import fcntl
import os
import struct
import subprocess
TUNSETIFF = 0x400454ca
TUNSETOWNER = TUNSETIFF + 2
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
# Open TUN device file.
tun = open('/dev/net/tun', 'r+b')
# Tell it we want a TUN device named lars0.
ifr = struct.pack('16sH', 'lars0', IFF_TAP | IFF_NO_PI)
fcntl.ioctl(tun, TUNSETIFF, ifr)
# Optionally, we want it be accessed by the normal user.
fcntl.ioctl(tun, TUNSETOWNER, 1000)
# Bring it up and assign addresses.
subprocess.check_call(['ifconfig', 'lars0', 'up'])
print 'waiting'
sys.stdin.readline()
# Read an IP packet been sent to this TUN device.
packet = list(open('/tmp/packet.raw').read())
# Write the reply packet into TUN device.
os.write(tun.fileno(), ''.join(packet))
print 'waiting'
sys.stdin.readline()

header filtering using python

i want to filter some headers in a wireshark capture (converted to text format) so i can analyse these set of headers.i need a python script to do this. any help would be appreciated
You might want to look at dpkt. It's a Python library to simplify reading (or generating) network data. Just save your Wireshark data as a Pcap stream and it can easily be opened from within Python.
I don't know exactly which headers you want or how you need them filtered and formatted, but here's an example of what you could write: (taken from a contributor's blog post)
import dpkt
pcap = dpkt.pcap.Reader(open('test.pcap'))
for timestamp, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
tcp = ip.data
print 'Got data from port ' + str(tcp.port)

Categories

Resources