Internet Layer Base Protocol

pcapkit.protocols.internet.internet contains Internet, which is a base class for internet layer protocols, e.g. AH, IPsec, IPv4, IPv6 and IPX.

class pcapkit.protocols.internet.internet.Internet[_PT: Data, _ST: Schema](file=None, length=None, **kwargs)[source]

Bases: ProtocolBase[_PT, _ST], Generic[_PT, _ST]

Abstract base class for internet layer protocol family.

This class parses the following protocols, which are registered in the self.__proto__ attribute:

Changed in version 1.5.0: A layer parsed as an IPv6 extension header keeps only its own octets in data, so that from_data(info).data rebuilds it exactly (#1446).

property layer: Literal['Internet']

Protocol layer.

classmethod register(code, protocol)[source]

Register a new protocol class.

Notes

The fully qualified class name should be {protocol.module}.{protocol.name}.

Parameters:
Raises:

pcapkit.utilities.exceptions.RegistryError – If protocol is not a class, or not a ProtocolBase subclass.

Warns:

pcapkit.utilities.warnings.RegistryWarning – If this protocol number is already registered, naming the displaced entry and its replacement so a caller can tell what was lost. Fires only when the incumbent differs from the replacement; see Protocol.register for the guard this shares with register_protocol, and for the shipped descriptor a restore puts back (#1504).

Changed in version 1.3.0: Takes the class, or a ModuleDescriptor naming it, as protocol, in place of the module and class_ name strings.

classmethod from_data(data, **kwargs)[source]

Create protocol instance from data.

Parameters:
Return type:

Self

Returns:

Protocol instance, cut back to what was captured when the header it was parsed from was cut short (#1458).

_decode_next_layer(dict_, proto=None, length=None, *, packet=None, version=4, ipv6_exthdr=None, payload=None)[source]

Decode next layer extractor.

Parameters:
Return type:

_PT

Returns:

Current protocol with next layer extracted.

Notes

dict_ gains the keys __next_type__ (next layer protocol type) and __next_name__ (next layer protocol name), which Info.to_dict carries and the dumpers leave out.

_import_next_layer(proto, length=None, *, packet=None, version=4, extension=False, payload=None)[source]

Import next layer extractor.

Parameters:
Return type:

ProtocolBase

Returns:

Instance of next layer.

Notes

An IPv6 extension header past EXTENSION_HEADER_LIMIT in a row is not dissected: it and the rest of the packet are kept as Raw, with one ProtocolWarning (#1604). Each header dissects the next one from here, so the chain’s depth is handed to the next layer, see _next_layer_class().

_next_layer_class(proto, file_, length, extension=False)[source]

Pick the class the next layer is parsed with.

Parameters:
  • proto (int | None) – next layer protocol index

  • file_ (bytes) – payload of the current layer

  • length (int) – valid (non-padding) length

  • extension (bool) – if is extension header, see _next_exthdr_depth()

Return type:

tuple[Type[ProtocolBase], dict[str, Any]]

Returns:

NoPayload if there is nothing to parse; Raw if the parse stops at this layer, or the next layer is an IPv6 extension header past EXTENSION_HEADER_LIMIT in a row; otherwise the class registered for proto. Paired with it, the keywords that only that next layer is constructed with: the warning given, as error, or the next layer’s place in its chain, as _exthdr_depth.

Warns:

ProtocolWarning – If the next layer is past EXTENSION_HEADER_LIMIT (#1604), unless this layer is inside a payload being rebuilt (#1619).

_next_exthdr_depth(proto, extension=False)[source]

Place the next layer in its chain of IPv6 extension headers.

Parameters:
  • proto (int | None) – next layer protocol index

  • extension (bool) – if the next layer is parsed as an extension header by IPv6’s walk, which counts the chain itself, see IPv6._decode_next_layer

Return type:

int

Returns:

One more than _exthdr_depth if proto names an IPv6 extension header, or 0 if it names none, so that another layer between two headers starts a new chain. Past EXTENSION_HEADER_LIMIT, the next layer is left raw.

classmethod _make_payload(data)[source]

Create payload from data for protocol construction.

As Protocol._make_payload, but the payload is built at its place in its chain of IPv6 extension headers, one past this layer’s, since it parses its own octets again. So rebuilding a frame stops at EXTENSION_HEADER_LIMIT where parsing it did, rather than that many headers past each header of the chain, and warns of the limit once, as _next_layer_class() describes (#1619).

Parameters:

data (Data) – protocol data

Return type:

ProtocolBase

Returns:

Payload for protocol construction.

classmethod _rebuilt_exthdr_depth()[source]

Place a layer from_data() rebuilds in its chain of IPv6 extension headers.

Return type:

int

Returns:

Where _make_payload() of the layer it is the payload of puts it, if it is an IPv6 extension header, or 0 if it is not, as _next_exthdr_depth() places a layer being parsed. A layer rebuilt on its own is at 0, as one parsed from its own octets is.

Note

The parse tells an extension header by the protocol number naming it, which a rebuild does not have, so this tells one by its class: IPv6_Ext is the base of every Internet layer __proto__ registers under such a number.

__layer__: Literal['Internet']

Layer of protocol.

__proto__: DefaultDict[int, ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]]

Protocol index mapping for decoding next layer, see self._decode_next_layer & self._import_next_layer.

__proto_key__: ClassVar[tuple[Type[EnumRegistry], bool]]

the enum a key must be a member of, and whether a bare int is a valid key there too. Declared by the class owning the registry, and read from it by register_protocol_code() so a code= key is checked exactly as register_transtype() checks its own – a subclass sharing this registry is therefore checked as Internet is, while IPX, which keeps one of its own, declares its own pairing or none at all (#2268).

Type:

What __proto__ is keyed by

_exthdr_depth = 0

How many IPv6 extension headers in a row the next layer follows: this layer’s place in such a chain, or how many headers IPv6 walked, else 0, see EXTENSION_HEADER_LIMIT and _next_exthdr_depth().

Type:

int

pcapkit.protocols.internet.internet._exthdr_rebuilt

Where the payload Internet._make_payload() rebuilds sits in a chain of IPv6 extension headers, should it be one: one past the layer it is the payload of, as Internet._next_exthdr_depth() places it while parsing, see EXTENSION_HEADER_LIMIT.

Type:

contextvars.ContextVar[int]

Extension Header Chains

A chain of IPv6 extension headers is dissected to at most EXTENSION_HEADER_LIMIT headers in a row, whether it follows IPv6 or another layer such as IPv4. What follows is kept as Raw, with one ProtocolWarning (#1604). The pyshark engine leaves the walk to its own parser, which does not stop there, so it may still find the upper layer past it (#1609). So may the dpkt toolkit, which reads the chain as dpkt decodes it. So does the scapy engine behind IPv6, where Scapy dissects each extension header itself; behind IPv4, its toolkit steps over them in the octets to find TCP, up to EXTENSION_HEADER_LIMIT of them in a row. The pypcapfile toolkit walks no extension header chain, so it finds no upper layer behind one.