From 41d1a2c4feabd7fc0c9b671db0294b629e3d979a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Lars=20V=C3=B6lker?= <49641816+LarsV33@users.noreply.github.com> Date: Sun, 26 Oct 2025 22:17:45 +0100 Subject: [PATCH 1/2] PCAPNG: Adding SHB Options This patch allows to set Hardware, OS, and User Application, when creating a PcapNgWriter. These values will be written into the SHB. --- scapy/utils.py | 25 +++++++++++++++++++++++++ test/regression.uts | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/scapy/utils.py b/scapy/utils.py index 9b7ad90537d..3fecc39f3c8 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -2403,6 +2403,9 @@ class RawPcapNgWriter(GenericRawPcapWriter): def __init__(self, filename, # type: str + shb_hardware=None, # type: Optional[str] + shb_os=None, # type: Optional[str] + shb_userapp=None, # type: Optional[str] ): # type: (...) -> None @@ -2416,6 +2419,10 @@ def __init__(self, self.endian = "<" self.endian_magic = b"\x4d\x3c\x2b\x1a" + self.shb_hardware = shb_hardware + self.shb_os = shb_os + self.shb_userapp = shb_userapp + self.filename = filename self.f = open(filename, "wb", 4096) @@ -2483,6 +2490,24 @@ def _write_block_shb(self): # Section Length block_shb += struct.pack(self.endian + "q", -1) + # Add Hardware Name Option (2), if exists + if self.shb_hardware is not None: + block_shb += struct.pack(self.endian + "HH", 0x0002, len(self.shb_hardware)) + block_shb += self.shb_hardware.encode() + block_shb = self._add_padding(block_shb) + + # Add OS Name Option (3), if exists + if self.shb_os is not None: + block_shb += struct.pack(self.endian + "HH", 0x0003, len(self.shb_os)) + block_shb += self.shb_os.encode() + block_shb = self._add_padding(block_shb) + + # Add User Application Name Option (4), if exists + if self.shb_userapp is not None: + block_shb += struct.pack(self.endian + "HH", 0x0004, len(self.shb_userapp)) + block_shb += self.shb_userapp.encode() + #block_shb = self._add_padding(block_shb) + self.f.write(self.build_block(block_type, block_shb)) def _write_block_idb(self, diff --git a/test/regression.uts b/test/regression.uts index 86b8c7f064b..4d90b36a30c 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -2158,6 +2158,16 @@ l = rdpcap(tmpfile) assert b"Scapy" in l[0][Raw].load assert l[0].time == ts += Write a pcapng with SHB options + +tmpfile = get_temp_file(autoext=".pcapng") +r = RawPcapNgWriter(tmpfile, shb_hardware="hardware", shb_os="os", shb_userapp="userapp") +r._write_block_shb() +r.f.close() + +# without a reader not much we can check +assert os.stat(tmpfile).st_size == 60 + = Check wrpcapng() tmpfile = get_temp_file(autoext=".pcapng") From af50eb26453fd5ae3e83f28fb7b5a69250149eee Mon Sep 17 00:00:00 2001 From: Guillaume Valadon Date: Wed, 18 Feb 2026 21:33:37 +0100 Subject: [PATCH 2/2] PCAPNG: store SHB options in reader, fix padding, improve test --- scapy/utils.py | 4 ++-- test/regression.uts | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scapy/utils.py b/scapy/utils.py index 3fecc39f3c8..080173be65d 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -1749,7 +1749,7 @@ def _read_block_shb(self): raise Scapy_Exception("PcapNg: Invalid Section Header Block " " options (too short)") self._read_block_tail(blocklen) - self._read_options(options) + self.shb_options = self._read_options(options) def _read_packet(self, size=MTU): # type: ignore # type: (int) -> Tuple[bytes, RawPcapNgReader.PacketMetadata] @@ -2506,7 +2506,7 @@ def _write_block_shb(self): if self.shb_userapp is not None: block_shb += struct.pack(self.endian + "HH", 0x0004, len(self.shb_userapp)) block_shb += self.shb_userapp.encode() - #block_shb = self._add_padding(block_shb) + block_shb = self._add_padding(block_shb) self.f.write(self.build_block(block_type, block_shb)) diff --git a/test/regression.uts b/test/regression.uts index 4d90b36a30c..344dd8f9dfa 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -2158,15 +2158,18 @@ l = rdpcap(tmpfile) assert b"Scapy" in l[0][Raw].load assert l[0].time == ts -= Write a pcapng with SHB options += Write and read back a pcapng with SHB options tmpfile = get_temp_file(autoext=".pcapng") r = RawPcapNgWriter(tmpfile, shb_hardware="hardware", shb_os="os", shb_userapp="userapp") r._write_block_shb() r.f.close() -# without a reader not much we can check -assert os.stat(tmpfile).st_size == 60 +reader = RawPcapNgReader(tmpfile) +assert reader.shb_options.get(2) == b"hardware" +assert reader.shb_options.get(3) == b"os" +assert reader.shb_options.get(4) == b"userapp" +reader.close() = Check wrpcapng()