PCAP Dumper

pcapkit.dumpkit.pcap is the dumper for the PCAP format, like those in dictdumper.

class pcapkit.dumpkit.pcap.PCAPIO(fname, *, protocol, byteorder=sys.byteorder, nanosecond=False, **kwargs)[source]

Bases: DumperBase

PCAP file dumper.

Parameters:
  • fname (str) – output file name

  • protocol (LinkType | IntEnum | aenum.IntEnum | str | int) – data link type

  • byteorder (Literal['big', 'little']) – header byte order

  • nanosecond (bool) – nanosecond-resolution file flag

  • **kwargs (Any) – further global header fields, i.e. version, thiszone, sigfigs and snaplen, and arbitrary keyword arguments

Changed in version 1.5.0: The global header takes version, thiszone, sigfigs and snaplen from **kwargs, so format='pcap' output keeps the input’s values; 1.4.x wrote the defaults (#1165, #1255).

property kind: Literal['pcap']

File format of current dumper.

__init__(fname, *, protocol, byteorder=sys.byteorder, nanosecond=False, **kwargs)[source]

Initialise dumper.

Parameters:
  • fname (str) – output file name

  • protocol (LinkType | IntEnum | aenum.IntEnum | str | int) – data link type

  • byteorder (Literal['big', 'little']) – header byte order

  • nanosecond (bool) – nanosecond-resolution file flag

  • **kwargs (Any) – further global header fields, i.e. version, thiszone, sigfigs and snaplen, and arbitrary keyword arguments

_append_value(value, file, name)[source]

Call this function to write contents.

Parameters:
  • value (Frame) – content to be dumped

  • file (IO[bytes]) – output file

  • name (str) – name of current content block

Notes

A PCAP record is a 16-octet header followed by the packet octets, and both are already in hand: the header fields are value.frame_info, with the fraction in this file’s resolution (see self._make_timestamp), and the octets are exactly value.packet. So this writes them directly, rather than handing them to Frame, whose constructor packs the record and then dissects it again through the whole protocol stack to arrive at bytes it was given. That round trip measured about 82% of the cost of a flow-traced extraction – http.pcap, 1117 frames, best of 7: 2319 ms with the rebuild against 1263 ms without, over a 1030 ms untraced baseline.

Skipping it is not only cheaper. The re-dissection would re-emit every parse warning the frame had already produced once, and warn about payloads it has no business parsing at all – writing a 3-octet payload would raise SchemaWarning: packet length < 0: -3 from a dumper that only has to copy it.

incl_len is written as len(value.packet), the octets that follow it, not as value.frame_info.incl_len. The two are equal for every record a file holds whole. A record whose captured length runs past the end of its file, or a PCAP-NG block whose captured length runs past the block (#1405), is kept as captured by its reader: the declared length stays in frame_info, so the source rebuilds byte-exactly, and packet is the octets present. Copying that declared length would claim octets the trace does not hold, and a reader would run off the end of the file (#1541).

_make_timestamp(frame_info, time_epoch)[source]

Record header seconds and fraction, in this file’s resolution.

Parameters:
  • frame_info (FrameInfo) – the frame’s record header fields

  • time_epoch (Decimal | float | int) – the frame’s UNIX timestamp

Return type:

tuple[int, int]

Returns:

The ts_sec and ts_usec fields to write.

Notes

frame_info does not say which resolution its ts_usec is in. A PCAP frame carries its file’s, and one converted from PCAP-NG carries its interface’s (cf. block2frame()), either of which may differ from this file’s (#1500). time_epoch settles it: the fraction is in whichever resolution truncates the frame’s offset into its second to exactly that value.

The fraction is written as is when that is this file’s resolution, so a record traced at its own resolution keeps its octets, and also when neither resolution fits, as for a frame built by hand. When it is the other resolution, the fraction is recomputed from time_epoch at this file’s – microseconds times 1000, or nanoseconds divided by 1000 and truncated rather than rounded. That is how block2frame() and Frame.make reduce a timestamp to a fraction, and how libpcap scales a nanosecond file down (sf-pcap.c). It also keeps the second: 999,999,999 ns truncates to 999,999 us, where rounding would reach a whole second. A recomputed fraction of a second or more is carried into ts_sec, so that multiplying by 1000 cannot overflow the field.