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

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()

Related

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()

How to read packets with VLAN layer

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

How can I read the response to a Modbus read request?

For a project that uses the Raspberry Pi 4, with a special shield as Modbus master I've succesfully written to a register, but I'm having trouble reading from a register. I'm using the Simply Modbus Slave program to test and can see that the request seems to go over well, but I haven't been able to print any data on my Raspberry Pi.
Currently I'm suspecting that the command I use from modbus-tk (cst.READ_INPUT_REGISTERS) send the Read Input Registers command, but doesn't actually receive the response.
I'm therefore seeking help to capture these values, or alternatively save everything received from the slave and find the values among this data.
Also, it could be nice to perhaps print everything sent and received so I can see what's happening in the communication.
This is the current code that I'm using:
## To install dependencies:
## sudo pip3 install modbus-tk
##################################################################################################
import serial
import fcntl
import os
import struct
import termios
import array
import time
#import modbus lib
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus as modbus
#import modbus_tk.modbus_rtu as modbus_rtu
from modbus_tk import modbus_rtu
# RS485 ioctls define
TIOCGRS485 = 0x542E
TIOCSRS485 = 0x542F
SER_RS485_ENABLED = 0b00000001
SER_RS485_RTS_ON_SEND = 0b00000010
SER_RS485_RTS_AFTER_SEND = 0b00000100
SER_RS485_RX_DURING_TX = 0b00010000
# rs 485 port
ser1 = serial.Serial("/dev/ttySC0",19200)
#ser1 = serial.Serial("/dev/ttySC0",9600)
ser2 = serial.Serial("/dev/ttySC1",9600)
def rs485_enable():
buf = array.array('i', [0] * 8) # flags, delaytx, delayrx, padding
#enable 485 chanel 1
fcntl.ioctl(ser1, TIOCGRS485, buf)
buf[0] |= SER_RS485_ENABLED|SER_RS485_RTS_AFTER_SEND
buf[1] = 0
buf[2] = 0
fcntl.ioctl(ser1, TIOCSRS485, buf)
#enable 485 chanel 2
fcntl.ioctl(ser2, TIOCGRS485, buf)
buf[0] |= SER_RS485_ENABLED|SER_RS485_RTS_AFTER_SEND
buf[1] = 0
buf[2] = 0
fcntl.ioctl(ser2, TIOCSRS485, buf)
#end of rs485_enable():
if __name__ == '__main__':
logger = modbus_tk.utils.create_logger("console")
rs485_enable()
#set modbus master
master = modbus_rtu.RtuMaster(
serial.Serial(port= '/dev/ttySC0',
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
xonxoff=0)
)
master.set_timeout(5.0)
master.set_verbose(True)
logger.info("connected")
read = logger.info(master.execute(1, cst.READ_INPUT_REGISTERS, 4, 1))
print(read)
My code is an edited version of my shield's demo code (rtumaster.py) found here (Software/Test Codes/MODBUS).
Thank you in advance

Sniff network traffic with scapy and regular expressions?

I had my first glance on python's scapy package and wanted to test my first little script. In order to test the code below I sent myself an E-Mail containing this string "10000000000000". My expectation was that below minimal example (with my network card in monitoring mode and execution as su) would give an command line output for that E-Mail specifically but it doesn't. I am sure that this is caused by an misunderstanding of network traffic and tcp by myself -- could anyone elucidate?
The virtual environment I set-up is Python 3.6.8
(I have tested that I can sniff network traffic in general using the commented out line, only when I try to filter their content via regular expressions the result is not as I expected.)
import optparse
import scapy.all as sca
import re
from scapy import packet
from scapy.layers.dns import DNS
from scapy.layers.dot11 import Dot11Beacon, Dot11ProbeReq
from scapy.layers.inet import TCP
class SniffDataTraffic:
#staticmethod
def find_expr(pack: packet) -> str:
regex_dict = {'foo': r"1[0-9]{13}",'bar': r"2[1-5]{14}"}
raw_pack = pack.sprintf('%Raw.load%')
found = {iter: re.findall(regex_dict[iter], raw_pack) for iter in regex_dict.keys()}
for name, value in found.items():
if value:
return "[+] found {}: {}".format(name, value[0])
def main():
try:
print("[*] Starting sniffer")
#sca.sniff(iface="xxxxxmon", prn=lambda x: x.summary(), store=False)
sca.sniff(prn=SniffDataTraffic.find_expr, filter='tcp', iface="xxxxxmon", store=False)
except KeyboardInterrupt:
exit(0)
if __name__ == '__main__':
main()

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()

Categories