3rd-Party Support¶
The adapters below are best effort (#1687): they need not match the Built-in Support adapters one to one, since protocol rules belong in the default engine only, so the same capture can reassemble or trace differently from one engine to the next. Engine Support tabulates the gaps.
Scapy Tools¶
pcapkit.toolkit.scapy contains the adapters for the Scapy engine.
The reassembly and flow tracing adapters return the data their
pcapkit.foundation counterpart consumes, or None if the frame
cannot be used for it.
Warning
This module requires Scapy to be installed.
- pcapkit.toolkit.scapy.ipv4_reassembly(packet, *, count=-1)[source]¶
Make data for IPv4 reassembly.
A packet can be reassembled if it contains an IPv4 layer (
scapy.layers.inet.IP) whose header – as many octets as its IHL counts, and at least 20 – lies inside the frame and every IP datagram carrying it (see_within_datagrams()), and the DF (scapy.layers.inet.IP.flags.DF) flag isFalse. A zero-length frame has none, though Scapy hands it back as an IPv4 layer of defaults at theRAWandIPV4link types (see_frame()).- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for IPv4 reassembly (reasm.ipv4.packet) if the
packetcan be reassembled; otherwiseNone.
- pcapkit.toolkit.scapy.ipv6_reassembly(packet, *, count=-1)[source]¶
Make data for IPv6 reassembly.
A packet can be reassembled if it contains an IPv6 layer (
scapy.layers.inet6.IPv6), in no later IPv4 fragment, and an IPv6 Fragment header (RFC 2460 Section 4.5, i.e.,scapy.layers.inet6.IPv6ExtHdrFragment) among the extension headers Scapy dissects in that layer’s own chain.- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for IPv6 reassembly (reasm.ipv6.packet) if the
packetcan be reassembled; otherwiseNone.- Raises:
ModuleNotFound – If Scapy is not installed.
Note
A later IPv4 fragment’s data is a slice of the datagram’s payload, with no upper-layer header in it (RFC 791 Section 3.2), but Scapy dissects IPv6 there whatever the fragment offset. And the header and addresses handed on are those of the IPv6 layer the Fragment header follows, so one inside a packet that layer carries, such as the inner packet of 6in6, is not taken.
- pcapkit.toolkit.scapy.tcp_reassembly(packet, *, count=-1)[source]¶
Make data for TCP reassembly.
A packet can be reassembled if it contains a TCP layer (
scapy.layers.inet.TCP) whose fixed header lies inside its datagram, and whose Data Offset counts at least that header, in no later IPv4 fragment; or a TCP segment behind an AH or IPv6 extension header in IPv4, read off the octets. It is keyed by the IP layer that carries it – in an IP-in-IP tunnel, the innermost (see_tcp_carrier()).- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for TCP reassembly (reasm.tcp.packet) if the
packetcan be reassembled; otherwiseNone.
- pcapkit.toolkit.scapy.tcp_traceflow(packet, *, count=-1)[source]¶
Trace packet flow for TCP.
A packet can be traced if it contains a TCP layer (
scapy.layers.inet.TCP), on the termstcp_reassembly()sets.- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for TCP flow tracing (trace.tcp.packet) if the
packetcan be traced; otherwiseNone.
See also
Auxiliary Functions¶
- pcapkit.toolkit.scapy.packet2chain(packet)[source]¶
Fetch Scapy packet protocol chain.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.- Return type:
- Returns:
Colon (
:) separated list of protocol chain.- Raises:
ModuleNotFound – If Scapy is not installed.
- pcapkit.toolkit.scapy.packet2dict(packet)[source]¶
Convert Scapy packet into
dict.- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.- Return type:
- Returns:
A
dictmapping of packet data. Itspacketis the octets of the frame (see_frame()), none for a zero-length one. Each layer carries only the fields set on it (for a dissected packet, those read from the wire, with no defaults filled in). Field values that are themselves Scapy packets (e.g. IP options, DNS records), including those inside lists, are converted recursively. Thepacketitself is not modified.- Raises:
ModuleNotFound – If Scapy is not installed.
- pcapkit.toolkit.scapy.packet2frame(packet)[source]¶
Report a Scapy packet to the flow tracer, with its PCAP frame record.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.- Return type:
- Returns:
The
packet2dict()mapping of the packet, which every trace format but PCAP writes unchanged, carrying the octets Scapy dissected the packet from, the PCAP record header the PCAP trace dumper writes, and the exact timestamp it reads the header’s resolution from.- Raises:
ModuleNotFound – If Scapy is not installed.
Note
The octets are
packet.original, which Scapy’s readers keep as read, rather thanbytes(packet), which rebuilds them; for a packet not read from a capture, such as one built by hand, they are the octets it builds into (see_frame()).orig_lenispacket.wirelen, the record’s original length.The fraction in
frame_info.ts_usecis in the capture’s own resolution. That resolution is the oneScapyattaches withattach_resolution(), never one guessed from the value: a nanosecond count that is a whole number of microseconds has the same digits as the microsecond count. A packet that carries none, e.g. one built by hand, is taken to count microseconds.
- pcapkit.toolkit.scapy.attach_resolution(packet, resolution)[source]¶
Stash the timestamp resolution of a packet’s capture on the packet.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.resolution (
int) – Timestamp resolution, in units per second: the PCAP global header’s, or the PCAP-NG interface’s the packet was captured on.
- pcapkit.toolkit.scapy.attach_linktype(packet, linktype)[source]¶
Stash the data link type of a packet’s capture on the packet.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.linktype (
int) –LINKTYPE_*number: the PCAP global header’s, or the PCAP-NG interface’s the packet was captured on.
- pcapkit.toolkit.scapy._frame(packet)[source]¶
Return the octets of the frame a Scapy packet stands for.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.- Return type:
- Returns:
For a packet read from a capture, which every Scapy reader gives a
wirelen, the record’s original length,packet.original: the octets of the record, which the readers keep as read. For any other, such as one built by hand,bytes(packet): the octets it builds into.
- pcapkit.toolkit.scapy._within_datagrams(layer)[source]¶
Return the octets from
layeron that lie inside every IP datagram carrying it.- Parameters:
layer (
scapy.packet.Packet) – A layer of a dissected Scapy packet.- Return type:
- Returns:
The octets of
layerand everything after it, up to the nearest end that the Total Length or Payload Length of an IP layer above it declares.
Note
When Scapy dissects an IP layer, it files whatever follows the datagram’s declared length as a
Paddinglayer – an Ethernet frame’s padding up to its 60-octet minimum, or a trailer such as an FCS – andbytes()of any layer above that one ends with it. Those octets are no part of the datagram (#1584), so they are cut off here. An IPv4 Total Length of zero, as TCP segmentation offload leaves, declares nothing, so the datagram runs to the end of the frame (#1547); an IPv6 Payload Length of zero gives way to a Jumbo Payload option (#1434), whose length is read here rather than left to Scapy, which reads it in host byte order and adds the Hop-by-Hop Options header to it a second time.Every IP layer above
layerbounds it, not only the nearest: a datagram tunnelled in IP may declare more than the one carrying it holds, or nothing at all. An IPv4 layer built by hand has noihluntil it is built, so one given a Total Length alone has its IHL read off the octets it builds into (#1676).
- pcapkit.toolkit.scapy._tcp_carrier(packet)[source]¶
Fetch the TCP segment of a Scapy packet, and the IP layer that carries it.
- Parameters:
packet (
scapy.packet.Packet) – Scapy packet.- Return type:
tuple[scapy.layers.inet.IP|scapy.layers.inet6.IPv6,scapy.layers.inet.TCP,bytes,bytes] |None- Returns:
The nearest
IPorIPv6layer above the packet’s TCP layer, that layer, and the segment’s header and payload (see_tcp_segment()); orNoneif there is no such IP layer, or an IPv4 layer above it is a later fragment, whose data is a slice of the datagram’s payload with no upper-layer header in it (RFC 791 Section 3.2, #1617).An IPv4 layer whose protocol names an AH or IPv6 extension header (
IPV4_EXTENSION_HEADERS) has those headers stepped over in its octets, up toEXTENSION_HEADER_LIMITof them in a row (see_walk_extension_headers()), and what follows them is dissected from the octets: a tunnel, walked on as above, or a TCP segment (see_tcp_behind_extension_headers(), #1606). In the datagram an ICMP error quotes, they are left as Scapy dissects them.
Note
The nearest is the innermost IP layer of an IP-in-IP tunnel (RFC 2003, RFC 2473, RFC 4213), whose addresses are the TCP endpoints’ (#1581).
packet['IP']finds the outermost IPv4 layer instead, which is the tunnel’s, or with IPv4 carried in IPv6 the inner one. The extension header layers Scapy dissects between an IPv6 layer and its payload are not IP layers, so are stepped over.Inside IPv4, Scapy dissects an AH alone of those headers, and behind one only IPv6 and, for a Next Header of
0, IPv4, so the octets are read instead. It also dissects IPv6 and AH inside a later fragment, binding neither to a zero fragment offset as it binds TCP.
- pcapkit.toolkit.scapy._tcp_segment(tcp)[source]¶
Split the TCP segment
tcpheads into its header and its payload.- Parameters:
tcp (
scapy.layers.inet.TCP) – TCP layer of a dissected Scapy packet.- Return type:
- Returns:
The header, as many octets as the Data Offset counts, and the payload after it, up to the end of the datagrams that carry the segment, cf.
_within_datagrams(); orNoneif the datagrams hold fewer than the 20 octets of the fixed header, or the Data Offset counts fewer (RFC 9293 Section 3.1), as there is then no header to split off.
- pcapkit.toolkit.scapy._tcp_behind_extension_headers(segment)[source]¶
Split a TCP segment carried behind an AH or IPv6 extension header in IPv4.
- Parameters:
segment (
bytes) – Raw octets from the TCP header on, as far as the IPv4 layer carrying it goes (see_tcp_carrier()).- Return type:
- Returns:
The header, as many octets as the Data Offset counts, and the payload after it; or
Noneif there are fewer thanTCP_MIN_HEADER_LENoctets, the Data Offset counts fewer or more than were captured, or pcapkit’s own TCP parser rejects the options (see_default_accepts()).
Note
Scapy dissects no TCP layer there (see
_tcp_carrier()), so the segment is read off the octets, and its options are left to pcapkit’s parser to check.
DPKT Tools¶
pcapkit.toolkit.dpkt contains the adapters for the DPKT engine.
The reassembly and flow tracing adapters return the data their
pcapkit.foundation counterpart consumes, or None if the frame
cannot be used for it.
- pcapkit.toolkit.dpkt.ipv4_reassembly(packet, timestamp, *, count=-1)[source]¶
Make data for IPv4 reassembly.
A packet can be reassembled if its network layer is IPv4 (
dpkt.ip.IP) – one carried in IPv6 is not read – whose header was captured whole, and the DF (dpkt.ip.IP.df) flag isFalse.- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Capture timestamp of the packet, which drives the reassembly timeout. DPKT’s reader yields it beside the record’s octets rather than on the packet, so it is passed in – astcp_traceflow()does. A caller holding only a frame can read it back withpacket2timestamp(), which is whereDPKTleaves it. Handed on as afloat, though DPKT reads a nanosecond PCAP’s as aDecimal(#1501), and as the one nearest the exact value it carries, if any, where DPKT’s own may be an ulp off (#1668; see_capture_time()).count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for IPv4 reassembly (reasm.ipv4.packet) if the
packetcan be reassembled; otherwiseNone.
Note
The header and payload are sliced out of the record octets
DPKTattached to the frame, so they are the captured ones. A packet built by hand carries no such buffer, and its octets are thendpkt’s re-serialisation of it, in which a zeroed checksum or length comes back recomputed –attach_buffer()is what makes them the wire’s again. They are that re-serialisation too wheredpkt’s own lengths misplace the layer in the record, as behind some stacks of VLAN tags (#1646). The packet itself is left untouched either way.The header is the IHL’s octets, and the payload ends at the Total Length, or at the end of the frame for a zero one. A Total Length shorter than the IHL leaves the header whole and the payload empty (#1616).
Changed in version 1.5.0:
timestampis a new second positional parameter, so a 1.4.x call withpacketalone fails.
- pcapkit.toolkit.dpkt.ipv6_reassembly(packet, timestamp, *, count=-1)[source]¶
Make data for IPv6 reassembly.
A packet can be reassembled if its network layer is IPv6 (
dpkt.ip6.IP6) – one carried in IPv4 is not read – and has an IPv6 Fragment header (RFC 2460 Section 4.5, i.e.,dpkt.ip6.IP6FragmentHeader).- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Capture timestamp of the packet, which drives the reassembly timeout;packet2timestamp()reads it back off a stored frame. Handed on as afloat, as foripv4_reassembly().count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for IPv6 reassembly (reasm.ipv6.packet) if the
packetcan be reassembled; otherwiseNone.
Note
The header and payload are sliced out of the record octets
DPKTattached to the frame, so they are the captured ones. A packet built by hand carries no such buffer, and its octets are thendpkt’s re-serialisation of it, in which a zeroed checksum or length comes back recomputed –attach_buffer()is what makes them the wire’s again. They are that re-serialisation too wheredpkt’s own lengths misplace the layer in the record, as behind some stacks of VLAN tags (#1646). The packet itself is left untouched either way.Changed in version 1.5.0:
timestampis a new second positional parameter, so a 1.4.x call withpacketalone fails.
- pcapkit.toolkit.dpkt.tcp_reassembly(packet, timestamp, *, count=-1)[source]¶
Make data for TCP reassembly.
A packet can be reassembled if its network layer carries a TCP layer (
dpkt.tcp.TCP), behind any IPv6 extension headersdpktdecodes. TCP in an IP-in-IP tunnel, or behind an AH or IPv6 extension header carried in IPv4, is not read.- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Capture timestamp of the packet, which drives the reassembly timeout;packet2timestamp()reads it back off a stored frame. Handed on as afloat, as foripv4_reassembly().count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for TCP reassembly (reasm.tcp.packet) if the
packetcan be reassembled; otherwiseNone.
Note
The header and payload are sliced out of the record octets
DPKTattached to the frame, so they are the captured ones. A packet built by hand carries no such buffer, and its octets are thendpkt’s re-serialisation of it, in which a zeroed checksum or length comes back recomputed –attach_buffer()is what makes them the wire’s again. They are that re-serialisation too wheredpkt’s own lengths misplace the layer in the record, as behind some stacks of VLAN tags (#1646). The packet itself is left untouched either way.Changed in version 1.5.0:
timestampis a new second positional parameter, so a 1.4.x call withpacketalone fails.
- pcapkit.toolkit.dpkt.tcp_traceflow(packet, timestamp, *, data_link, count=-1)[source]¶
Trace packet flow for TCP.
A packet can be traced if its network layer carries a TCP layer (
dpkt.tcp.TCP), behind any IPv6 extension headersdpktdecodes. TCP in an IP-in-IP tunnel, or behind an AH or IPv6 extension header carried in IPv4, is not read.- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Timestamp of the packet, handed on as afloat, as foripv4_reassembly(). The PCAP frame record is built from the exact timestamp attached byattach_timestamp(), if any; seepacket2frame().data_link (
LinkType) – Data link layer protocol (from global header).count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for TCP flow tracing (trace.tcp.packet) if the
packetcan be traced; otherwiseNone.
Note
The header and payload are sliced out of the record octets
DPKTattached to the frame, so they are the captured ones. A packet built by hand carries no such buffer, and its octets are thendpkt’s re-serialisation of it, in which a zeroed checksum or length comes back recomputed –attach_buffer()is what makes them the wire’s again. They are that re-serialisation too wheredpkt’s own lengths misplace the layer in the record, as behind some stacks of VLAN tags (#1646). The packet itself is left untouched either way.See also
Auxiliary Functions¶
- pcapkit.toolkit.dpkt.attach_timestamp(packet, timestamp)[source]¶
Stash a frame’s capture timestamp on the frame.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Capture timestamp of the packet, as DPKT’s reader yielded it beside the record’s octets.
- pcapkit.toolkit.dpkt.packet2timestamp(packet)[source]¶
Read back the capture timestamp of a DPKT packet.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet, as stored byDPKT.- Return type:
- Returns:
Capture timestamp of the packet, in seconds since the epoch. As
DPKTattaches it, that is aTimestamp, or for a nanosecond PCAP file aDecimalTimestamp, which is aDecimalsubclass rather than afloat.- Raises:
UnsupportedCall – If the packet carries no timestamp, i.e. it did not come through
DPKT. Raised rather than defaulted, because a plausible-looking zero would silently misdate whatever was going to use it.
- pcapkit.toolkit.dpkt.attach_buffer(packet, buffer)[source]¶
Stash a frame’s record octets on the frame.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.buffer (
bytes) – Octets of the record the packet was parsed from, as DPKT’s reader yielded them.
- pcapkit.toolkit.dpkt.packet2bytes(packet)[source]¶
Fetch the octets of a DPKT packet without modifying it.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.- Return type:
- Returns:
The record octets attached by
attach_buffer(), i.e. the frame as it was captured. A packet that carries none – one built by hand rather than read byDPKT– is serialised from a copy instead, so that DPKT’s checksum and length recomputation never reaches the packet itself.
- pcapkit.toolkit.dpkt.packet2frame(packet, timestamp, *, data_link)[source]¶
Report a DPKT packet to the flow tracer, with its PCAP frame record.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float|Decimal) – Capture timestamp of the packet. The one attached byattach_timestamp(), if any, is preferred, since it is the value DPKT’s reader yielded.data_link (
LinkType) – Data link type.
- Return type:
- Returns:
The
packet2dict()mapping of the packet, which every trace format but PCAP writes unchanged, carrying the captured octets, frompacket2bytes(), the PCAP record header the PCAP trace dumper writes, and the exact timestamp it reads the header’s resolution from.
Note
The fraction in
frame_info.ts_usecis in the capture’s own resolution, and both it andorig_lencome from the reader:DPKTreads PCAP and PCAP-NG alike into aRecordTimestamp. A timestamp that is not one – a packet built by hand, or read by adpktwhose reader the engine could not extend – is read as DPKT yields it: aDecimalcounts nanoseconds and afloatmicroseconds, and the octets are taken to be whole.
- pcapkit.toolkit.dpkt.ipv6_hdr_len(ipv6)[source]¶
Calculate length of headers before IPv6 Fragment header.
- Parameters:
ipv6 (
IP6) – DPKT IPv6 packet.- Return type:
- Returns:
Length of headers before IPv6 Fragment header
dpkt.ip6.IP6FragmentHeader(RFC 2460 Section 4.5).
As specified in RFC 2460 Section 4.1, such a header may be a Hop-by-Hop Options header
dpkt.ip6.IP6HopOptsHeader(RFC 2460 Section 4.3), a Destination Options headerdpkt.ip6.IP6DstOptsHeader(RFC 2460 Section 4.6) or a Routing headerdpkt.ip6.IP6RoutingHeader(RFC 2460 Section 4.4). An Authentication header (RFC 4302) reaches here as well, though, so the headers are walked in the order they were parsed rather than looked up by a fixed list of types. Walking them is also what counts a repeated header type once per occurrence, and what leaves out one that sits after the Fragment header rather than before it.
- pcapkit.toolkit.dpkt.packet2chain(packet)[source]¶
Fetch DPKT packet protocol chain.
- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.- Return type:
- Returns:
Colon (
:) separated list of protocol chain. It ends at the first payload that is no layer, as inpacket2dict(), e.g. VRRP’s''.
- pcapkit.toolkit.dpkt.packet2dict(packet, timestamp, *, data_link)[source]¶
Convert DPKT packet into
dict.- Parameters:
packet (
dpkt.dpkt.Packet) – DPKT packet.timestamp (
float) – Timestamp of packet.data_link (
LinkType) – Data link type.
- Return type:
- Returns:
A
dictmapping of packet data. A layer’s payload is mapped as a layer of its own only where it is one, i.e. has the header fields adpkt.dpkt.Packethas; any other is leaf data. DPKT leaves some undecoded payloads as astrrather than asbytes, e.g.''for VRRP’s. A frame the engine keeps as raw data, as it keeps one DPKT cannot decode, has no header fields, so maps to an emptydict.
- pcapkit.toolkit.dpkt._capture_time(timestamp)[source]¶
The capture timestamp reassembly and flow tracing are handed.
- Parameters:
timestamp (
float|Decimal) – Capture timestamp of the packet.- Return type:
- Returns:
The
floatnearest the exact timestamp. DPKT reads a microsecond PCAP’s astv_sec + tv_usec / 1e6, which rounds twice, so can be an ulp off at a smalltv_sec:1.0036909999999999for1.003691(#1668). ARecordTimestampis therefore read by its exact value. Any other timestamp – one passed by hand, or yielded by adpktwhose reader the engine could not extend – carries none, and is handed on as it is.
Auxiliary Data¶
- class pcapkit.toolkit.dpkt.RecordTimestamp[source]¶
Bases:
objectA record’s capture timestamp, with what a PCAP frame record needs of it.
The readers
DPKTuses yield(timestamp, octets)and nothing else, so a record’s exact timestamp, its resolution and its original length would be lost between the reader andpacket2frame(). The engine’s readers yield aTimestampor aDecimalTimestampinstead, which is the value DPKT yields – so a stored frame’s timestamp is exactly what it was before – and also carries what would otherwise be lost. Reassembly and flow tracing are handed a plainfloatof it (#1501): of its exact value, since DPKT’s own for a microsecond PCAP rounds twice (#1668; see_capture_time()).A copy, a deep copy and a pickle at any protocol all rebuild a timestamp from what its
__reduce__()returns, so each keeps the exact timestamp, the resolution and the original length. This class answers each of those protocols itself, ahead of the numeric base class: the pure-PythonDecimalcopies a subclass astype(self)(str(self)), with the constructor’s defaults for the rest (#1647).
- class pcapkit.toolkit.dpkt.Timestamp(value=0.0, exact=None, resolution=RESOLUTION[False], orig_len=None)[source]¶
Bases:
RecordTimestamp,floatA
floatcapture timestamp; seeRecordTimestamp.
- class pcapkit.toolkit.dpkt.DecimalTimestamp(value='0', resolution=RESOLUTION[True], orig_len=None)[source]¶
Bases:
RecordTimestamp,DecimalA
Decimalcapture timestamp; seeRecordTimestamp.
PyShark Tools¶
pcapkit.toolkit.pyshark contains the adapters for the PyShark engine.
The reassembly and flow tracing adapters return the data their
pcapkit.foundation counterpart consumes, or None if the frame
cannot be used for it.
Note
Some pcapkit functions may not be available with the PyShark engine,
for lack of the corresponding PyShark functionality.
- pcapkit.toolkit.pyshark.tcp_traceflow(packet, *, count=-1)[source]¶
Trace packet flow for TCP.
A packet can be traced if it contains a TCP layer with a whole fixed header (see
_has_fixed_header()), keyed by the IP layer that carries it – in an IP-in-IP tunnel, the innermost (see_carrier()) – if tshark reports both its addresses (see_has_addresses()).- Parameters:
- Return type:
- Returns:
Data for TCP flow tracing (trace.tcp.packet) if the
packetcan be traced; otherwiseNone.- Raises:
MissingKeyError – If the frame’s link type cannot be resolved.
ProtocolError – If the packet has no
framelayer, a TCP flag field is not a boolean tshark spelling, orframe.time_epochis not decimal text.
See also
Changed in version 1.5.0: The link type is resolved from
frame.encap_typethroughENCAP_TYPE_TO_LINKTYPE, or, for a frame without that field, from the root layer’s name throughFILTER_NAME_TO_LINKTYPE. One that cannot be resolved either way raisesMissingKeyError; 1.4.x looked up the root layer’s name only, which gave the wrong DLT forppp,null,lapdandraw(#843).
- pcapkit.toolkit.pyshark.ENCAP_TYPE_TO_LINKTYPE: dict[int, LinkType]¶
frame.encap_type– Wireshark’s internalWTAP_ENCAP_*number, whichpysharkexposes aspacket.frame_info.encap_type– to the matchingLinkTypemember. This istcp_traceflow()’s primary link-type source;FILTER_NAME_TO_LINKTYPEbelow is only its fallback.A
WTAP_ENCAP_*number is not a DLT: it is 25 where the DLT is 113, 15 where it is 0, and 2 where it is 6, so it needs this table rather than a cast. What it does do is distinguish encapsulations that the PDML root layer’s filter name cannot, which is the whole reason this table exists:sllis bothLINUX_SLL(113) andLINUX_SLL2(276),nullis bothNULL(0) andLOOP(108),rawisRAW(101),IPV4(228) andIPV6(229),pppisPPP(9) andPPP_WITH_DIR(204),lapdisLAPD(203) andLINUX_LAPD(177).frame.encap_typeseparates every one of those pairs.Every entry was measured, not transcribed, with
editcap/tshark4.6.9:editcap -F pcap -T <encap> examples/captures/in.pcap out.pcap # value := the network field at offset 20 of out.pcap's pcap file header # key := the frame.encap_type that `tshark -r out.pcap -c 1 -T pdml` then reports
so each pair is one round trip through Wireshark’s own
wiretap/pcap-common.c, in the read directionpysharkactually exercises. In the source, the trailing comment on each line names theeditcap -Tencapsulation that produced it.What the sweep does not cover, since that bounds this table: of the 226 encapsulations
editcap -Taccepts, 157 could be written as pcap from the Ethernet source above and the other 69 refused the rewrite, so they are untested. Those 157 yielded 153 distinctframe.encap_typekeys, with no key mapping to two DLTs and no DLT reading back as two keys. Each is below exceptframe.encap_type32 (editcap -T hhdlc, DLT 121), left out becauseLinkTypehas no member for 121. An encapsulation absent from this table raises rather than resolving to a near-miss DLT.
- pcapkit.toolkit.pyshark.FILTER_NAME_TO_LINKTYPE: dict[str, LinkType]¶
Wireshark display-filter name ->
LinkTypemember, used bytcp_traceflow()only when the frame layer carries noframe.encap_typefield forENCAP_TYPE_TO_LINKTYPEabove to key on – every capture measured for that table did carry one, so this is a defensive path rather than the usual one. PyShark takes the name verbatim from the PDML<proto name=...>attribute, which is Wireshark’s own dissector filter name – the third argument toproto_register_protocol()in the relevantepan/dissectors/packet-*.c– and that vocabulary is notLinkType’s: Ethernet’s filter name iseth, neverETHERNET.Every entry comes from the same sweep as
ENCAP_TYPE_TO_LINKTYPEabove: the root<proto name=...>oftshark -r out.pcap -c 1 -T pdmlagainst the DLT inout.pcap’s own file header. In the source, the trailing comment on each line names theeditcap -Tencapsulation that produced it, so an entry can be re-checked, or corrected when upstream moves, by rerunning that one rewrite. Names are listed even where they already spell theirLinkTypemember (docsis,fddi,pflog, …): there is deliberately no fallback onto a like-named member, because upper-casing the name is exactly what would answer 101 for arawip6capture and 0 for aDLT_LOOPone – valid DLTs, wrong ones, and silent (#843).These classes of name are absent, each measured rather than assumed:
Ambiguous – one name, several DLTs, and the PDML node does not say which arrived. These cannot be mapped at any size:
user_dlt(16 DLTs),bluetooth(6),usb(5),usbll(4),raw(3), andarcnet,gfp,i2c,lapd,mtp2,netanalyzer,null,ppp,sll,wlan,wpan(2 each).Pseudo-protocols –
fake-field-wrapper, whichpysharkreports asdataand which was the root for 29 of the swept encapsulations (no dissector), and_ws.malformed, the root for the one capturetsharkcould not parse. Neither names a link type.Unswept – the 69 encapsulations
editcap -Twould not write as pcap from an Ethernet source. No evidence either way was gathered for them.
Caveats on what “unambiguous” means here. It means unambiguous within the 157 swept encapsulations: one of the 69 unswept could still root at the same name (
ether-nettlandtr-nettlare the obvious candidates, forethandtr). And some entries –llc,sctp,pppoes,fppandirlap– name a payload dissector that happened to be the outermost PDML node for exactly one encapsulation, rather than a link-layer dissector registered against aWTAP_ENCAP_*. These caveats are why this table is the fallback andframe.encap_typeis the primary key;ethandtradditionally check out against Wireshark’s own registrations (packet-eth.conWTAP_ENCAP_ETHERNET,packet-tr.conWTAP_ENCAP_TOKEN_RING).
Auxiliary Functions¶
- pcapkit.toolkit.pyshark.packet2dict(packet)[source]¶
Convert PyShark packet into
dict.- Parameters:
packet (
pyshark.packet.packet.Packet) – PyShark packet.- Return type:
- Returns:
A
dictmapping of packet data, with theframelayer’s fields at the top level and each later layer nested in the one before it. A packet comment, which PyShark reports asframe_infoin place of the frame layer, is kept under its ownPKT_COMMENTkey. A record with noframelayer keeps PyShark’sframe_infoat the top level.
- pcapkit.toolkit.pyshark._carrier(packet)[source]¶
Fetch the TCP layer of a PyShark packet and the IP layer that carries it.
- pcapkit.toolkit.pyshark._has_fixed_header(tcp)[source]¶
Whether tshark dissected the whole fixed TCP header of a PyShark TCP layer.
- Parameters:
tcp (
Any) – PyShark TCP layer.- Return type:
- Returns:
Whether the layer carries
tcp.urgent_pointer.
Note
A segment is traced only if its 20-octet fixed header (RFC 9293 Section 3.1) was captured and its Data Offset is at least 5. tshark omits fields in both other cases, measured with tshark 4.6.9 (#1611):
a Data Offset below 5 stops the dissection at
tcp.hdr_len, sotcp.ackand thetcp.flagsfields are absent;a header cut at octet k keeps the fields that fit: no TCP layer below 4, the ports only below 14, and no
tcp.urgent_pointerbelow 20.
tcp.urgent_pointercovers octets 18 and 19, the last of the fixed header.dissect_tcpinepan/dissectors/packet-tcp.cadds it unconditionally once the Data Offset check passes, in 2.6.0, 3.0.0 and 4.6.0, after every fieldtcp_traceflow()reads.
- pcapkit.toolkit.pyshark._has_addresses(ip)[source]¶
Whether tshark reported both addresses of a PyShark IP layer.
- Parameters:
ip (
Any) – PySharkiporipv6layer.- Return type:
- Returns:
Whether the layer carries its
srcanddstfields.
Note
tshark reports no
ip.dstbehind an LSRR or SSRR option whose route data is no whole number of addresses (“Suboption would go past end of option”), measured with tshark 4.6.9. Reading it raised a bareAttributeErrorout oftcp_traceflow(), which ended the extraction (#1671).
PyPCAP Tools¶
pcapkit.toolkit.pypcap contains the adapters for the PyPCAP engine.
Note
PyPCAP performs no protocol dissection, so the reassembly and flow tracing
adapters below cannot be implemented. They are defined anyway, so that
calling one fails with an explanatory
UnsupportedCall rather than an
ImportError.
- pcapkit.toolkit.pypcap.ipv4_reassembly(packet, *, count=-1)[source]¶
Make data for IPv4 reassembly.
- Parameters:
- Raises:
UnsupportedCall – Always, as PyPCAP provides no IPv4 layer to read.
- Return type:
- pcapkit.toolkit.pypcap.ipv6_reassembly(packet, *, count=-1)[source]¶
Make data for IPv6 reassembly.
- Parameters:
- Raises:
UnsupportedCall – Always, as PyPCAP provides no IPv6 layer to read.
- Return type:
- pcapkit.toolkit.pypcap.tcp_traceflow(packet, timestamp, *, data_link, count=-1)[source]¶
Trace packet flow for TCP.
- Parameters:
- Raises:
UnsupportedCall – Always, as PyPCAP provides no TCP layer to read.
- Return type:
Auxiliary Functions¶
- pcapkit.toolkit.pypcap.packet2chain(packet, *, data_link)[source]¶
Fetch PyPCAP packet protocol chain.
- Parameters:
- Return type:
- Returns:
Colon (
:) separated list of protocol chain.
Note
As PyPCAP does not dissect the packet, the chain is only ever the link layer type followed by
Raw, e.g.ETHERNET:Raw.
- pcapkit.toolkit.pypcap.packet2dict(packet, timestamp, *, data_link)[source]¶
Convert PyPCAP packet into
dict.- Parameters:
- Return type:
- Returns:
A
dictmapping of packet data.
Note
The mapping carries the captured bytes verbatim rather than a decoded protocol tree, since PyPCAP does not decode anything.
pcap-ct Tools¶
pcapkit.toolkit.pcap_ct contains the adapters for the pcap-ct engine.
Note
pcap-ct is an independent reimplementation of the PyPCAP interface, so
this module is deliberately a sibling of pcapkit.toolkit.pypcap rather
than an alias of it: each engine names its own adapter, so a change made for
one cannot quietly alter the other.
Like PyPCAP it performs no protocol dissection, so the reassembly and flow
tracing adapters below cannot be implemented. They are defined anyway, so
that calling one fails with an explanatory
UnsupportedCall rather than an
ImportError.
- pcapkit.toolkit.pcap_ct.ipv4_reassembly(packet, *, count=-1)[source]¶
Make data for IPv4 reassembly.
- Parameters:
- Raises:
UnsupportedCall – Always, as pcap-ct provides no IPv4 layer to read.
- Return type:
- pcapkit.toolkit.pcap_ct.ipv6_reassembly(packet, *, count=-1)[source]¶
Make data for IPv6 reassembly.
- Parameters:
- Raises:
UnsupportedCall – Always, as pcap-ct provides no IPv6 layer to read.
- Return type:
- pcapkit.toolkit.pcap_ct.tcp_traceflow(packet, timestamp, *, data_link, count=-1)[source]¶
Trace packet flow for TCP.
- Parameters:
- Raises:
UnsupportedCall – Always, as pcap-ct provides no TCP layer to read.
- Return type:
Auxiliary Functions¶
- pcapkit.toolkit.pcap_ct.packet2chain(packet, *, data_link)[source]¶
Fetch pcap-ct packet protocol chain.
- Parameters:
- Return type:
- Returns:
Colon (
:) separated list of protocol chain.
Note
As pcap-ct does not dissect the packet, the chain is only ever the link layer type followed by
Raw, e.g.ETHERNET:Raw.
- pcapkit.toolkit.pcap_ct.packet2dict(packet, timestamp, *, data_link)[source]¶
Convert pcap-ct packet into
dict.- Parameters:
- Return type:
- Returns:
A
dictmapping of packet data.
Note
The mapping carries the captured bytes verbatim rather than a decoded protocol tree, since pcap-ct does not decode anything.
PyPCAPFile Tools¶
pcapkit.toolkit.pypcapfile contains the adapters for the PyPCAPFile engine.
The reassembly and flow tracing adapters return the data their
pcapkit.foundation counterpart consumes, or None if the frame
cannot be used for it.
Note
PyPCAPFile has no IPv6 decoder, so ipv6_reassembly()
raises UnsupportedCall rather than returning
None – which would be indistinguishable from “this frame carries no
IPv6 fragment”.
TCP over IPv6 is therefore left out of
tcp_reassembly() and
tcp_traceflow(), with an
AttributeWarning once per capture when
the IPv6 packet is straight over Ethernet. PyPCAPFile decodes no link
layer but Ethernet, and no VLAN tag or tunnel, so a frame of any other link
type is left undecoded, with the engine’s own warning, and TCP behind a VLAN
tag, in a tunnel or behind an extension header (an IPv6 one, or AH in IPv4)
is left out without one.
- pcapkit.toolkit.pypcapfile.ipv4_reassembly(packet, *, count=-1)[source]¶
Make data for IPv4 reassembly.
A packet can be reassembled if it contains an IPv4 layer (
pcapfile.protocols.network.ip.IP) whose header was captured whole (see_network()), and the DF flag isFalse.- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for IPv4 reassembly (reasm.ipv4.packet) if the
packetcan be reassembled; otherwiseNone.- Raises:
ProtocolError – If
ipv4.srcoripv4.dstcannot be parsed as an IPv4 address.
- pcapkit.toolkit.pypcapfile.ipv6_reassembly(packet, *, count=-1)[source]¶
Make data for IPv6 reassembly.
- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.count (
int) – Packet index. If not provided, defaults to-1.
- Raises:
UnsupportedCall – Always, as PyPCAPFile has no IPv6 decoder.
- Return type:
- pcapkit.toolkit.pypcapfile.tcp_reassembly(packet, *, count=-1)[source]¶
Make data for TCP reassembly.
A packet can be reassembled if it contains an IPv4 layer carrying a TCP segment (see
_transport()); TCP over IPv6 cannot be, as PyPCAPFile has no IPv6 decoder.- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.count (
int) – Packet index. If not provided, defaults to-1.
- Return type:
- Returns:
Data for TCP reassembly (reasm.tcp.packet) if the
packetcan be reassembled; otherwiseNone.- Raises:
ProtocolError – If
ipv4.srcoripv4.dstcannot be parsed as an IPv4 address.- Warns:
AttributeWarning – If
packetis an IPv6 packet straight over Ethernet whose Next Header is TCP (see_ipv6_carries_tcp()), which is left out, and is the first such frame of its capture to reach eithertcp_reassembly()ortcp_traceflow(). The rest of that capture’s such frames are left out without another warning.
- pcapkit.toolkit.pypcapfile.tcp_traceflow(packet, *, data_link, count=-1)[source]¶
Trace packet flow for TCP.
A packet can be traced if it contains an IPv4 layer carrying a TCP segment (see
_transport()); TCP over IPv6 cannot be, as PyPCAPFile has no IPv6 decoder.- Parameters:
- Return type:
- Returns:
Data for TCP flow tracing (trace.tcp.packet) if the
packetcan be traced; otherwiseNone.- Raises:
ProtocolError – If
ipv4.srcoripv4.dstcannot be parsed as an IPv4 address.- Warns:
AttributeWarning – If
packetis an IPv6 packet straight over Ethernet whose Next Header is TCP (see_ipv6_carries_tcp()), which is left out, and is the first such frame of its capture to reach eithertcp_reassembly()ortcp_traceflow(). The rest of that capture’s such frames are left out without another warning.
See also
Auxiliary Functions¶
- pcapkit.toolkit.pypcapfile.packet2timestamp(packet)[source]¶
Calculate the timestamp of a PyPCAPFile packet.
- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.- Return type:
- Returns:
Timestamp of the packet, in seconds since the epoch, as the
floatnearest the exact value.
Note
PyPCAPFile keeps the two halves of the per-packet timestamp apart, and the sub-second half is nanoseconds rather than microseconds when the savefile carries the nanosecond magic number – which is recorded on the savefile header as
ns_resolution.The two are joined in one integer division, which rounds once.
timestamp + timestamp_us / divisorrounds twice, so can be an ulp off at a smalltimestamp:1.0036909999999999for1.003691(#1668).
- pcapkit.toolkit.pypcapfile.ipv4_header(ipv4)[source]¶
Rebuild the raw header bytes of a PyPCAPFile IPv4 packet.
- Parameters:
ipv4 (
IP) – PyPCAPFile IPv4 packet.- Return type:
- Returns:
Raw IPv4 header bytes, options included.
Note
PyPCAPFile discards the header bytes once decoded, but it retains every IPv4 header field plus the options blob, so this reconstruction is byte-exact rather than approximate.
- Raises:
ProtocolError – If
ipv4.srcoripv4.dstcannot be parsed as an IPv4 address.
- pcapkit.toolkit.pypcapfile.packet2chain(packet, *, data_link)[source]¶
Fetch PyPCAPFile packet protocol chain.
- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.data_link (
LinkType) – Data link type, from the savefile header.
- Return type:
- Returns:
Colon (
:) separated list of protocol chain.
Note
The chain reports what PyPCAPFile actually decoded and no more, so it ends in
Raw– the transport segment is left undecoded on purpose, see the module notes.
- pcapkit.toolkit.pypcapfile.packet2dict(packet, *, data_link)[source]¶
Convert PyPCAPFile packet into
dict.- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.data_link (
LinkType) – Data link type, from the savefile header.
- Return type:
- Returns:
A
dictmapping of packet data.- Raises:
ProtocolError – If a decoded IPv4 layer’s
src/dstcannot be parsed as an IPv4 address, or a decoded Ethernet layer’ssrc/dstcannot be parsed as a MAC address.
Note
A frame PyPCAPFile left undecoded is hex-encoded, as the engine reads it (see
PyPCAPFile._read_records), so it is un-hexed (see_maybe_unhex()) and reported as its octets, not as twice as many characters of hex text (#1667).
Internal Definitions¶
- pcapkit.toolkit.pypcapfile.IPV4_FLAG_DF = 2¶
IPv4 DF (don’t fragment) bit, within the three-bit flags field.
- pcapkit.toolkit.pypcapfile.IPV4_FLAG_MF = 1¶
IPv4 MF (more fragments) bit, within the three-bit flags field.
- pcapkit.toolkit.pypcapfile.IPV4_EXTENSION_HEADERS¶
IP protocol numbers of the headers
_walk_extension_headers()steps over inside IPv4: AH and the IPv6 Hop-by-Hop Options, Routing, Fragment, Destination Options, Mobility and HIP headers.
- pcapkit.toolkit.pypcapfile._walk_extension_headers(protocol, data)[source]¶
Step over the headers in
IPV4_EXTENSION_HEADERSat the head of an IPv4 payload.- Parameters:
- Return type:
- Returns:
The protocol number after the last of them, the octets from its header on, and how many headers were stepped over –
protocol,dataand0ifprotocolis none of them – orNoneif one of them is cut short or rejected, or more thanEXTENSION_HEADER_LIMITfollow in a row. An AH is(Payload Length + 2) * 4octets long (RFC 4302 Section 2.2), and no shorter thanAH_HEADER_LEN; any other is read by_default_extension_header().
- pcapkit.toolkit.pypcapfile._default_extension_header(protocol, data)[source]¶
Read an extension header inside IPv4 with pcapkit’s own parser.
- Parameters:
protocol (
int) – The header’s protocol number, one ofIPV4_EXTENSION_HEADERSother than AH.data (
bytes) – Raw octets from the header on, as far as the IPv4 packet goes.
- Return type:
- Returns:
The header’s Next Header field and its length, or
Noneif its parser raises anything at all, or fewer octets were captured than the header needs.
- pcapkit.toolkit.pypcapfile._default_accepts(name, header)[source]¶
Test if pcapkit’s own IPv4 or TCP parser accepts a header.
- Parameters:
- Return type:
- Returns:
Note
The parser stops at its own layer, so nothing past the header is dissected. The answer depends on the octets alone, so the most recent answers are remembered, as many as the cache’s
maxsize.
- pcapkit.toolkit.pypcapfile._network(packet)[source]¶
Fetch the decoded IPv4 layer of a PyPCAPFile packet, if any.
- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.- Return type:
IP|None- Returns:
The decoded
pcapfile.protocols.network.ip.IPlayer, orNonewhen the frame was not decoded that far – which is the case for every non-IPv4 frame, PyPCAPFile having no other network layer decoder – or its header length (IHL) runs past the captured octets (#1591).
Note
PyPCAPFile slices the header at its IHL however few octets there are, so a header cut short has fewer options than its IHL declares.
- pcapkit.toolkit.pypcapfile._transport(ipv4)[source]¶
Fetch the verbatim TCP segment carried by a PyPCAPFile IPv4 packet.
- Parameters:
ipv4 (
IP) – PyPCAPFile IPv4 packet.- Return type:
- Returns:
The raw TCP segment, up to the packet’s Total Length, or
Noneif the packet does not carry a TCP header. A later fragment carries none: from its offset on, its data is a slice of the datagram’s payload (RFC 791 Section 3.2, #1576). Nor does a segment too short for a header, or whose Data Offset is below 5 words (#1590).
Note
PyPCAPFile keeps every octet after the header as the payload, so a frame padded to the Ethernet minimum carries its padding there. The segment is cut at the Total Length to leave it out (#1577). A Total Length of
0, which TCP segmentation offload leaves in a capture taken on the sending host, keeps the rest of the frame (#1547).
- pcapkit.toolkit.pypcapfile._ipv6_carries_tcp(packet)[source]¶
Test if a PyPCAPFile frame is an IPv6 packet carrying TCP.
- Parameters:
packet (
pcap_packet) – PyPCAPFile packet.- Return type:
- Returns:
Trueif the frame is IPv6 straight over Ethernet and its Next Header is TCP; otherwiseFalse.
Note
PyPCAPFile leaves an IPv6 frame’s payload undecoded and hex-encoded (see
_maybe_unhex()), so this reads the Next Header field of the raw IPv6 header and decodes nothing.
- pcapkit.toolkit.pypcapfile._is_raw(layer)[source]¶
Test if a decoded layer is in fact undecoded raw bytes.
- pcapkit.toolkit.pypcapfile._maybe_unhex(value)[source]¶
Undo
binascii.hexlify(), ifvaluelooks hex-encoded.- Parameters:
value (
bytes) – Raw bytes, possibly hex-encoded.- Return type:
- Returns:
valuehex-decoded, if it is a valid even-length hex string; otherwisevalueitself, unchanged.
Note
The released PyPCAPFile (0.12.0) stores an IPv4 packet’s options (
IP.opt) and payload (IP.payload) asbinascii.hexlify()’d ASCII text once decoding stops short of the transport layer – which is exactly howPyPCAPFilecalls it – rather than as the raw bytes this module otherwise assumes. Both forms arebytes, hex-encoded or not, which is why_is_raw()cannot tell them apart, and falling back to the original value when it does not decode as hex is what keeps this a no-op for the raw, non-hex stand-ins used in unit tests.This is not a guarantee against every false positive, only a cheap and, in practice, reliable heuristic: a genuinely raw payload whose every byte happens to fall in the ASCII hex-digit range (e.g. a 24-byte TCP header built entirely from digits and
A-F) is indistinguishable from real hex text and gets silently halved. There is no way to tell the two forms apart from the bytes alone; this is acceptable here because that byte range is a small fraction of the possible values a real header or payload can take.