|
| 1 | +import os |
| 2 | +import struct |
| 3 | +import math |
| 4 | + |
| 5 | +from urh.util.Logger import logger |
| 6 | + |
| 7 | + |
| 8 | +# Refer to PCAPNG spec |
| 9 | +# https://www.ietf.org/staging/draft-tuexen-opsawg-pcapng-02.html |
| 10 | + |
| 11 | +def _build_pcapng_shb(shb_userappl: str = "", shb_hardware: str = "") -> bytes: |
| 12 | + BLOCKTYPE = 0x0A0D0D0A |
| 13 | + HEADERS_BLOCK_LENGTH = 28 |
| 14 | + MAGIC_NUMBER = 0x1A2B3C4D |
| 15 | + VERSION_MAJOR, VERSION_MINOR = 1, 0 |
| 16 | + SECTIONLENGTH = 0xFFFFFFFFFFFFFFFF # -1 => Not specified |
| 17 | + |
| 18 | + shb_userappl_padded_len = math.ceil(len(shb_userappl) / 4) * 4 |
| 19 | + shb_hardware_padded_len = math.ceil(len(shb_hardware) / 4) * 4 |
| 20 | + |
| 21 | + total_block_len = HEADERS_BLOCK_LENGTH |
| 22 | + if shb_userappl_padded_len > 0: |
| 23 | + total_block_len += shb_userappl_padded_len + 4 |
| 24 | + |
| 25 | + if shb_hardware_padded_len > 0: |
| 26 | + total_block_len += shb_hardware_padded_len + 4 |
| 27 | + |
| 28 | + shb = struct.pack(">IIIHHQ", |
| 29 | + BLOCKTYPE, |
| 30 | + total_block_len, |
| 31 | + MAGIC_NUMBER, |
| 32 | + VERSION_MAJOR, VERSION_MINOR, |
| 33 | + SECTIONLENGTH) |
| 34 | + |
| 35 | + if shb_userappl != "": |
| 36 | + SHB_USERAPPL = 4 |
| 37 | + strpad = shb_userappl.ljust(shb_userappl_padded_len, "\0") |
| 38 | + shb += struct.pack(">HH", SHB_USERAPPL, shb_userappl_padded_len) |
| 39 | + shb += bytes(strpad, 'ascii') |
| 40 | + |
| 41 | + if shb_hardware != "": |
| 42 | + SHB_HARDWARE = 2 |
| 43 | + strpad = shb_hardware.ljust(shb_hardware_padded_len, "\0") |
| 44 | + shb += struct.pack(">HH", SHB_HARDWARE, shb_hardware_padded_len) |
| 45 | + shb += bytes(strpad, 'ascii') |
| 46 | + |
| 47 | + shb += struct.pack(">I", total_block_len) |
| 48 | + return shb |
| 49 | + |
| 50 | +def _build_pcapng_idb(link_type) -> bytes: |
| 51 | + BLOCKTYPE = 0x00000001 |
| 52 | + BLOCKLENGTH = 20 |
| 53 | + SNAP_LEN = 0 |
| 54 | + |
| 55 | + return struct.pack(">IIHHII", |
| 56 | + BLOCKTYPE, |
| 57 | + BLOCKLENGTH, |
| 58 | + link_type, 0, |
| 59 | + SNAP_LEN, |
| 60 | + BLOCKLENGTH) |
| 61 | + |
| 62 | +def _build_pcapng_epb(packet: bytes, timestamp: float) -> bytes: |
| 63 | + BLOCKTYPE = 0x00000006 |
| 64 | + BLOCKHEADERLEN = 32 |
| 65 | + INTERFACE_ID = 0 |
| 66 | + |
| 67 | + captured_packet_len = len(packet) |
| 68 | + original_packet_len = captured_packet_len |
| 69 | + padded_packet_len = math.ceil(captured_packet_len / 4) * 4 |
| 70 | + padding_len = padded_packet_len - original_packet_len |
| 71 | + padded_packet = packet + bytearray(padding_len) |
| 72 | + block_total_length = BLOCKHEADERLEN + padded_packet_len |
| 73 | + timestamp_int = int(timestamp * 1e6) # Set the proper resolution |
| 74 | + timestamp_high = timestamp_int >> 32 |
| 75 | + timestamp_low = timestamp_int & 0x00000000FFFFFFFF |
| 76 | + |
| 77 | + epb = struct.pack(">IIIIIII", |
| 78 | + BLOCKTYPE, |
| 79 | + block_total_length, |
| 80 | + INTERFACE_ID, |
| 81 | + timestamp_high, |
| 82 | + timestamp_low, |
| 83 | + captured_packet_len, |
| 84 | + original_packet_len) |
| 85 | + epb += padded_packet |
| 86 | + epb += struct.pack(">I", block_total_length) |
| 87 | + return epb |
| 88 | + |
| 89 | +def create_pcapng_file(filename: str, shb_userappl: str = "", shb_hardware: str = "", |
| 90 | + link_type: int = 147) -> bytes: |
| 91 | + if filename == "": |
| 92 | + return |
| 93 | + |
| 94 | + shb_bytes = _build_pcapng_shb(shb_userappl, shb_hardware) |
| 95 | + idb_bytes = _build_pcapng_idb(link_type) |
| 96 | + |
| 97 | + if os.path.isfile(filename): |
| 98 | + logger.warning("{0} already exists. Overwriting it".format(filename)) |
| 99 | + |
| 100 | + with open(filename, "wb") as f: |
| 101 | + f.write(shb_bytes) |
| 102 | + f.write(idb_bytes) |
| 103 | + |
| 104 | +def append_packets_to_pcapng(filename: str, packets: list, timestamps: list): |
| 105 | + with open(filename, "ab") as f: |
| 106 | + for packet, timestamp in zip(packets, timestamps): |
| 107 | + f.write(_build_pcapng_epb(packet, timestamp)) |
0 commit comments