How to read packets with VLAN layer - python

I'm writing a program in Python to read and decode GOOSE packets from a .pcap file. So far, I've been able to read the packets with the Pypcapfile library:
from pcapfile import savefile
file = input("Enter the name of the pcap file: ")
try:
pcap = open(file, 'rb')
except IOError:
print("No file with name \"{}\" was found.\n".format(file))
return
capfile = savefile.load_savefile(pcap, verbose=True)
print(capfile)
Terminal:
Enter the name of the pcap file: goose2.pcap
[+] attempting to load goose2.pcap
[+] found valid header
[+] loaded 8023 packets
[+] finished loading savefile.
b'little'-endian capture file version 2.4
microsecond time resolution
snapshot length: 262144
linklayer type: LINKTYPE_ETHERNET
number of packets: 8023
The problem is that when I test my code with packets that contain a VLAN header (a mere two bytes), it says that the pcap file has 0 packets:
Enter the name of the pcap file: vlan.pcap
[+] attempting to load vlan.pcap
[+] found valid header
[+] loaded 0 packets
[+] finished loading savefile.
b'big'-endian capture file version 2.4
nanosecond time resolution
snapshot length: 65535
linklayer type: LINKTYPE_ETHERNET
number of packets: 0
I wrote my whole code around the Pypcapfile library so I want to avoid starting from the beginning with another library such as Scapy. I already tried adding the "layers=" argument to load_savefile but that didn't work. Is there any way around this?

Here's how I've tested things on my end. I grabbed the sample vlan capture from the wireshark wiki and decompressed it:
$ curl -o vlan.cap.gz 'https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=vlan.cap.gz'
$ gunzip vlan.cap.gz
We can use e.g. tshark to verify that this capture includes VLAN tagged packets:
$ tshark -r vlan.cap -V
Frame 1: 1518 bytes on wire (12144 bits), 1518 bytes captured (12144 bits)
[...]
Ethernet II, Src: AniCommu_40:ef:24 (00:40:05:40:ef:24), Dst: 3com_9f:b1:f3 (00:60:08:9f:b1:f3)
[...]
Type: 802.1Q Virtual LAN (0x8100)
802.1Q Virtual LAN, PRI: 0, DEI: 0, ID: 32
000. .... .... .... = Priority: Best Effort (default) (0)
...0 .... .... .... = DEI: Ineligible
.... 0000 0010 0000 = ID: 32
Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 131.151.32.129, Dst: 131.151.32.21
I can open this use the pcapfile module:
$ pip install --user Pypcapfile
$ python
>>> import pcapfile.savefile
>>> with open('vlan.cap', 'rb') as fd:
... capfile = pcapfile.savefile.load_savefile(fd, layers=2)
...
>>> capfile
b'little'-endian capture file version 2.4
microsecond time resolution
snapshot length: 65535
linklayer type: LINKTYPE_ETHERNET
number of packets: 395
>>> capfile.packets[0]
ethernet from b'00:40:05:40:ef:24' to b'00:60:08:9f:b1:f3' type unknown
But it looks like pcapfile doesn't have a particular decoder for VLAN frames.
The dpkt module works great:
>>> import dpkt
>>> fd = open('vlan.cap', 'rb')
>>> capfile = dpkt.pcap.Reader(fd)
>>> ts, buf = next(capfile)
>>> pkt = dpkt.ethernet.Ethernet(buf)
>>> pkt.vlan_tags
[VLANtag8021Q(pri=0, cfi=0, id=32)]
As does scapy:
>>> import scapy.all
>>> capfile = scapy.all.rdpcap('vlan.cap')
>>> capfile[0].vlan
32

Related

Save UDP packets from x amount of seconds in a pcap file

I am trying to save UDP data packets which I receive from a sensor to my PC through ethernet connection. I want to save the UDP data in the form of a pcap file.
So far I have written the following code to save 1 packet of data. I ran my code then opened up the saved pcap file using wireshark and compared it to the output from the raw wireshark data. Lines 0000 - 0010 from packet 1 are the same but line 0020 is different. test.pcap only has 42 bytes captured whereas from wireshark packet 1 has 1236 bytes captured.
Correct me if I am wrong but I think this is due to my code not giving enough time to collect all the data from the packet. I was hoping to get help in modifying my code below so that it saves the pcap file in time intervals. For example a pcap file will be saved every 5 seconds.
from scapy.all import wrpcap, Ether, IP, UDP
pkts = [Ether(src=" ", dst=" ") / IP(src=" ", dst=" ") / UDP(src=" ", dst=" ")]
wrpcap('test.pcap', [pkts])
Try this code, let me know if you are still getting less packets:
#!/usr/bin/env python3
import sys
import struct
import os
import argparse
from scapy.all import sniff, sendp, hexdump, linehexdump, get_if_list, get_if_hwaddr
from scapy.all import Packet, IPOption
from scapy.all import ShortField, IntField, LongField, BitField, FieldListField, FieldLenField
from scapy.all import IP, TCP, UDP, Raw
from scapy.layers.inet import _IPOption_HDR
from scapy.all import raw
from scapy.all import bytes_hex
import hashlib
import pcapng.blocks as blocks
from pcapng import FileWriter
counter = 1
def get_if():
ifs=get_if_list()
iface=None
for i in get_if_list():
if "enp1s0f1" in i:
iface=i
break;
if not iface:
print("Cannot find eth0 interface")
exit(1)
return iface
def main():
global counter
ifaces = [i for i in os.listdir('/sys/class/net/') ]
iface = get_if()
print(("sniffing on %s" % iface))
sys.stdout.flush()
writer = FileWriter(args.outfile, shb)
orig_packets = sniff(filter='tcp and port 5201',iface = iface)
for packet in orig_packets:
spb = shb.new_member(blocks.SimplePacket)
spb.packet_data = bytes(packet)
writer.write_block(spb)
print("C=",counter)
counter=counter+1
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("outfile", type=argparse.FileType("wb"))
args = parser.parse_args()
shb = blocks.SectionHeader(
options={
"shb_hardware": "artificial",
"shb_os": "python",
"shb_userappl": "python-pcapng",
})
idb = shb.new_member(
blocks.InterfaceDescription,
link_type=1,
options={
"if_description": "Hand-rolled",
"if_os": "Python",
"if_filter": [(0, b"tcp port 5201 and host 192.168.1.3")],
},)
main()

close pcap file with scapy

I print all ipv6 of file.pcap
from scapy.all import *
scapy_cap = rdpcap('file.pcap')
for packet in scapy_cap:
print packet[IPv6].src
How can I close this file handler after I finish to use it? rdpcap read all the packet to RAM and I didn't find out how can I release that resource .
The Following piece should work
from scapy.all import *
scapy_cap = PcapReader('file.pcap').read_all()
for packet in scapy_cap:
print packet[IPv6].src
scapy_cap.close()

Getting certificate size with python script

For a project I need to find the size of the certificate packet that is sent by server to client when setting up the ssl connection.
This happens over TCP and thus the packet can be split up over multiple segments. I have to do this on the top 100 Alexa sites. I am able to get the list of 100 sites and then running this code:
import ssl
import urllib
import os
import subprocess
from subprocess import call
import re
f = open("urls.txt", "r")
array = []
for line in f:
line = line[:-1]
array.append(line)
for a in array:
str = ":443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/Desktop/thesis/certificates/" + a + ".cert"
subprocess.getoutput('echo -n | openssl s_client -connect '+ a + str)
However this second for loop hangs after six iterations, so in my certificates folder there are only six certs.. Could someone tell me why this hangs and/or how to fix it? Thanks

PN-RT packet malformed

I tried with that codes to comunicate with Ethernet/Profinet protocol.I found that type of codes. But when I run to the program with that line-1
And i did not get any error. My program running but when i watching the wireshark side my connection information said-2
1
sudo python3 discovery.py
2
Wireshark malformed packet PN-RT
Yes it know that is Profinet protocol, but why is the malformed ? How can i fix ?
That is my python code:
#!/usr/bin/env python
import binascii
from socket import *
from fcntl import ioctl
import struct
import fcntl, struct
value='!6s6sH'
s=socket(AF_PACKET, SOCK_RAW)
s.bind(('enp2s0',1))
class EtherPacket:
def __init__(self, dst='25:36:73:32:74:48', src='c3:82:c5:b8:c2:81', protocol=0x8892):
self.dst = dst # Destination MAC
self.src = src # Source MAC
self.protocol = protocol # Protocol Types
self.raw ="" # Raw Data
self.assemble_eth_feilds()
def assemble_eth_feilds(self):
# Assemble All Feilds Of Ether Packet
self.raw = struct.pack( \
value.encode('ascii'),\
binascii.unhexlify(self.dst.replace(":","")),\
binascii.unhexlify(self.src.replace(":","")),\
self.protocol,\
)
return self.raw
def main():
pkt = EtherPacket()
s.sendto(pkt.raw, ('enp2s0' , 0 ))
if __name__=='__main__':
main()

Finding Bluetooth low energy with python

Is it possible for this code to be modified to include Bluetooth Low Energy devices as well? https://code.google.com/p/pybluez/source/browse/trunk/examples/advanced/inquiry-with-rssi.py?r=1
I can find devices like my phone and other bluetooth 4.0 devices, but not any BLE. If this cannot be modified, is it possible to run the hcitool lescan and pull the data from hci dump within python? I can use the tools to see the devices I am looking for and it gives an RSSI in hcidump, which is what my end goal is. To get a MAC address and RSSI from the BLE device.
Thanks!
As I said in the comment, that library won't work with BLE.
Here's some example code to do a simple BLE scan:
import sys
import os
import struct
from ctypes import (CDLL, get_errno)
from ctypes.util import find_library
from socket import (
socket,
AF_BLUETOOTH,
SOCK_RAW,
BTPROTO_HCI,
SOL_HCI,
HCI_FILTER,
)
if not os.geteuid() == 0:
sys.exit("script only works as root")
btlib = find_library("bluetooth")
if not btlib:
raise Exception(
"Can't find required bluetooth libraries"
" (need to install bluez)"
)
bluez = CDLL(btlib, use_errno=True)
dev_id = bluez.hci_get_route(None)
sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
sock.bind((dev_id,))
err = bluez.hci_le_set_scan_parameters(sock.fileno(), 0, 0x10, 0x10, 0, 0, 1000);
if err < 0:
raise Exception("Set scan parameters failed")
# occurs when scanning is still enabled from previous call
# allows LE advertising events
hci_filter = struct.pack(
"<IQH",
0x00000010,
0x4000000000000000,
0
)
sock.setsockopt(SOL_HCI, HCI_FILTER, hci_filter)
err = bluez.hci_le_set_scan_enable(
sock.fileno(),
1, # 1 - turn on; 0 - turn off
0, # 0-filtering disabled, 1-filter out duplicates
1000 # timeout
)
if err < 0:
errnum = get_errno()
raise Exception("{} {}".format(
errno.errorcode[errnum],
os.strerror(errnum)
))
while True:
data = sock.recv(1024)
# print bluetooth address from LE Advert. packet
print(':'.join("{0:02x}".format(x) for x in data[12:6:-1]))
I had to piece all of that together by looking at the hcitool and gatttool source code that comes with Bluez. The code is completely dependent on libbluetooth-dev so you'll have to make sure you have that installed first.
A better way would be to use dbus to make calls to bluetoothd, but I haven't had a chance to research that yet. Also, the dbus interface is limited in what you can do with a BLE connection after you make one.
EDIT:
Martin Tramšak pointed out that in Python 2 you need to change the last line to print(':'.join("{0:02x}".format(ord(x)) for x in data[12:6:-1]))
You could also try pygattlib. It can be used to discover devices, and (currently) there is a basic support for reading/writing characteristics. No RSSI for now.
You could discover using the following snippet:
from gattlib import DiscoveryService
service = DiscoveryService("hci0")
devices = service.discover(2)
DiscoveryService accepts the name of the device, and the method discover accepts a timeout (in seconds) for waiting responses. devices is a dictionary, with BL address as keys, and names as values.
pygattlib is packaged for Debian (or Ubuntu), and also available as a pip package.

Categories