Root Protocol

pcapkit.protocols.protocol contains Protocol, the abstract base for a new protocol stack. A protocol in an existing layer subclasses that layer’s base instead – Link, Internet, Transport or Application (Customisation & Extensions). The built-in families, those bases included, derive from ProtocolBase, whose metaclass is ProtocolMeta, both under Internal Definitions.

Changed in version 1.5.0: Constructing a protocol with a keyword that none of its signatures declares raises UnsupportedCall, where it was discarded (#617). A next layer captured shorter than its header is kept as Raw, where it was parsed with zero-filled fields (#1170).

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

Bases: ProtocolBase, Generic[_PT, _ST]

User-facing abstract base class for third-party protocols.

Inherit it directly only to create a new protocol stack; a new protocol in an existing layer subclasses that layer’s base class instead; see Customisation & Extensions. The built-in protocol families do not derive from this class but from ProtocolBase, whose metaclass is ProtocolMeta.

Changed in version 1.3.0: The built-in protocol families derive from ProtocolBase, so a built-in protocol is not an instance of this class, where every one was; and a subclass is registered in pcapkit.protocols.__proto__ when it is defined.

abstract property name: str

Name of current protocol.

property alias: str

Acronym of current protocol.

property info_name: str

Key the enclosing layer’s data model holds info under.

property info: _PT

Parsed data model of current instance.

property data: bytes

Binary packet data of current instance.

abstract property length: int

Header length of current protocol.

property payload: ProtocolBase

Payload of current instance.

property protocol: str | None

Name of next layer protocol (if any).

property protochain: ProtoChain

Protocol chain of current instance.

Note

NoPayload has no chain and narrows this to None; _decode_next_layer() passes it on as basis, which ProtoChain accepts.

property packet: Packet

Packet data of the protocol.

Note

The split takes self.length as the length of the octets preceding the payload, and the payload as running to the end of the buffer: a header followed by its payload.

A protocol laid out otherwise overrides this, or its header eats the payload and the payload is b''. PCAPNG does: its length is the wire’s Block Total Length, and the captured octets sit ahead of the option list and the trailing length field. The payload matters because Protocol.__init__() injects it into every parsed _info, which the dumpers write out.

property schema: _ST

Header schema instance of the protocol.

property context: ContextRegistry

Caller supplied parsing context.

See also

pcapkit.corekit.context for what this channel is for, and self._get_context for how a protocol implementation reaches its own entry.

classmethod id()

Index ID of the protocol.

Return type:

tuple[str, ...]

Returns:

By default, it returns the name of the protocol. In certain cases, the method may return multiple values.

classmethod register(code, protocol)

Register a new protocol class.

Notes

The fully qualified class name of the new protocol class 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 code holds a different entry, naming the displaced one and its replacement. An unresolved ModuleDescriptor incumbent counts as different from the class it names.

Note

As for register_protocol, handing back the entry stored under code – the same class object, or an equal ModuleDescriptor – is a silent no-op that keeps the stored entry (#1364). The comparison resolves nothing, so a stored descriptor stays deferred.

A descriptor equal to the one code shipped with restores that shipped object, unresolved, so undoing an override leaves the entry as shipped (#1504); see _next_layer_entry(), which every layer’s register shares.

classmethod analyze(proto, payload, **kwargs)

Analyse packet payload.

Parameters:
  • proto (int) – Protocol registry number.

  • payload (bytes) – Packet payload.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

ProtocolBase

Returns:

Parsed payload as a ProtocolBase instance.

classmethod from_schema(schema)

Create protocol instance from schema.

Parameters:

schema (_ST | dict[str, Any]) – Protocol schema.

Return type:

Self

Returns:

Protocol instance.

classmethod from_data(data, **kwargs)

Create protocol instance from data.

data may be the dict that Info.to_dict returns, which carries the metadata the rebuild reads: __next_name__ and __next_type__, which the payload is dispatched on, __short_read__ and __short_width__, and, for IPv6, the extension header chain under __exthdr__. A hand-written dict without them rebuilds no payload (nor IPv6 extension header) and cuts no short read back; nothing is guessed from its other keys (see _make_payload(), #2003).

A header the capture cut short, as __short_read__ records, is cut back and read at the width __short_width__ records, so the rebuild parses the octets captured as the capture did (#2703): it holds the values its parse read, not those make() fills in past the cut (#2761), and the Raw next layer that parse left (#2717). Inside a payload _make_payload() rebuilds, which gives only its octets, the header made is read instead.

Parameters:
  • data (_PT | dict[str, Any]) – Protocol data.

  • **kwargs (Any) – Construction keywords that data does not carry, such as the num and header of Frame, or the num, sct and ctx of PCAPNG. They take precedence over the keywords _make_data() returns.

Return type:

Self

Returns:

Protocol instance.

Raises:

UnsupportedCall – If any of kwargs matches no parameter of the protocol, as for a direct construction.

abstractmethod read(length=None, **kwargs)

Read (parse) packet data.

Parameters:
  • length (int | None) – Length of packet data.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

_PT

Returns:

Parsed packet data.

abstractmethod make(**kwargs)

Make (construct) packet data.

Parameters:

**kwargs (Any) – Arbitrary keyword arguments.

Return type:

_ST

Returns:

Curated protocol schema data.

Note

The **kwargs absorbs the keywords Protocol.__post_init__ hands to the parse as well as the construction, so an implementation need not declare every keyword it is called with. A caller’s keyword that no signature declares still raises UnsupportedCall from Protocol.__init__ (#617).

Warning

Calling this method directly is not checked, and discards an undeclared keyword silently. The check lives in Protocol.__init__, the one place the keywords converge, so it covers SomeProtocol(...) and its pack(), but not object.__new__(cls).make(**kwargs), as HTTP.make calls its versioned implementation. Construct through the constructor to get the check.

unpack(length=None, **kwargs)

Unpack (parse) packet data.

Parameters:
  • length (int | None) – Length of packet data.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

_PT

Returns:

Parsed packet data.

Notes

The special keyword argument __packet__ passes the global packet data to underlying methods, for when the current instance does not have it.

A self.__header__ already set, by from_schema() or by the pack() call of __post_init__(), is kept, unless it holds raw bytes where parsing its packed octets yields a schema – e.g. a raw option given to make(), directly or inside a data model – which read() cannot consume; it is then replaced by the parsed one (#1312).

A header from_data() rebuilds from a short read is parsed from the octets captured, its warnings discarded, and given its data model’s __short_read__ before read() runs, as the record of a cut those octets may not show (#2761).

Raises:

ProtocolError – If the made header holds raw items and its packed octets do not parse, either as a schema or by read(). The message carries the original error’s, which is also chained as __cause__.

Changed in version 1.6.0: A raw item that make() takes from inside a data model, such as the one from_data() passes on, is replaced too, rather than reaching read() (#2725).

pack(**kwargs)

Pack (construct) packet data.

Parameters:

**kwargs (Any) – Arbitrary keyword arguments.

Return type:

bytes

Returns:

Constructed packet data.

Notes

The special keyword argument __packet__ passes the global packet data to underlying methods, for when the current instance does not have it.

The octets are built from kwargs alone, through make(); the instance’s state is not read, so a bare SomeProtocol(...).pack() returns a default header, not the instance’s octets, which data holds.

Nor is that state written. Once the instance is parsed or constructed, the header is made on a shallow copy (see _packing_target()), so schema, info and anything make() sets, such as TCP.connection, still describe that packet. Only the call __post_init__() makes to construct the instance keeps the header, for unpack() to read back.

When from_data() rebuilds a header the capture cut short, that call cuts it back to the octets captured, through __short_read__ and Schema._cut_short_read (#2703). __post_init__() then drops that header, so unpack() parses the octets back and the rebuild holds the values its parse read, not those make() filled in past the cut (#2761).

Changed in version 1.5.0: Calling it no longer replaces the instance’s __header__, which left schema disagreeing with info (#1769).

static decode(byte, *, encoding=None, errors='strict')

Decode bytes into str.

Should decoding fail using encoding, the method will try again decoding the bytes as 'unicode_escape' with 'replace' for error handling.

See also

The method is a wrapping function for bytes.decode().

Parameters:
  • byte (bytes) – Source bytestring.

  • encoding (str | None) – The encoding with which to decode the bytes. If not provided, pcapkit will first try detecting its encoding using chardet. The fallback encoding is UTF-8.

  • errors (Literal['strict', 'ignore', 'replace']) – The error handling scheme to use for the handling of decoding errors. The default is 'strict' meaning that decoding errors raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name registered with codecs.register_error() that can handle UnicodeDecodeError.

Return type:

str

static unquote(url, *, encoding='utf-8', errors='replace')

Unquote URLs into readable format.

Should decoding fail, the method will try again replacing '%' with '\x' then decoding the url as 'unicode_escape' with 'replace' for error handling.

See also

This method is a wrapper function for urllib.parse.unquote().

Parameters:
  • url (str) – URL string.

  • encoding (str) – The encoding with which to decode the bytes.

  • errors (Literal['strict', 'ignore', 'replace']) – The error handling scheme to use for the handling of decoding errors. The default is 'replace', which substitutes a replacement marker for each undecodable sequence. Other possible values are 'strict', under which decoding errors raise a UnicodeDecodeError, and 'ignore', as well as any other name registered with codecs.register_error() that can handle UnicodeDecodeError.

Return type:

str

static resolve_index(name, default=None, *, namespace, reversed=False)

Resolve a name for an enumeration field of make().

A field of make() that holds an enumeration takes a member or an int code, and refuses a name (#2594). This resolves a name against a namespace given explicitly, so that its result can be passed on:

>>> from pcapkit.const.reg.ethertype import EtherType
>>> from pcapkit.protocols.link.ethernet.protocol import Ethernet
>>> code = Ethernet.resolve_index('Address_Resolution_Protocol',
...                               namespace=EtherType)
>>> Ethernet(type=code).info.type
<EtherType.Address_Resolution_Protocol: 2054>
Parameters:
  • name (str | int | IntEnum | aenum.IntEnum) – a member name; a member or an int is returned as it is, for make() to resolve

  • default (int | None) – the code to return when name is not in namespace

  • namespace (dict[str, int] | dict[int, str] | Type[IntEnum] | Type[aenum.IntEnum]) – the enumeration name names a member of, or a dict of codes and names

  • reversed (bool) – if namespace is a dict of names to codes, rather than of codes to names

Return type:

int | IntEnum | aenum.IntEnum

Returns:

The member name names, for an enumeration namespace; the code it names, for a dict; else default.

Raises:

ProtocolNotImplemented – If name is a str that is not in namespace and default is None.

Added in version 1.6.0: Takes over the <field>_default, <field>_namespace and <field>_reversed arguments of make() (#2594).

static expand_comp(value)

Expand protocol class to protocol name.

The method is used to expand protocol class to protocol name, in the following manner:

  1. If value is a protocol instance, the method will return the protocol class, and the protocol names in upper case obtained from Protocol.id.

  2. If value is a protocol class, the method will return the protocol class itself, and the protocol names in upper case obtained from Protocol.id.

  3. If value is str, the method will attempt to search for the existing registered protocol class with ProtocolBase.get_protocol() and follow step 2; otherwise, return the value in upper case alone.

Parameters:

value (str | ProtocolBase | Type[ProtocolBase]) – Protocol class or name.

Return type:

tuple

__layer__: Literal['Link', 'Internet', 'Transport', 'Application'] | None

Layer of protocol, can be one of Link, Internet, Transport and Application. For example, the layer of Ethernet is Link. However, certain protocols are not in any layer, such as Raw, and thus its layer is None.

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

Protocol index mapping for decoding the next layer; see self._decode_next_layer and self._import_next_layer. Each value is a ModuleDescriptor naming the module and class, or a ProtocolBase subclass.

__keywords__: frozenset[str] | None

Construction keywords this protocol takes out of **kwargs by name rather than declaring as a parameter, as IPv6_Ext.read does with alias. _declared_keywords() reads signatures, which miss such a name, so the construction check of __init__() accepts only those listed here, unioned over the MRO. Prefer a declared parameter, which also documents the keyword (#617).

None skips the check, for a dispatcher whose real signature is chosen at call time: HTTP.make declares only version and forwards the rest to HTTPv1.make or HTTPv2.make. A protocol that skips the check discards an unknown keyword silently. Unlike a set, None is not inherited, so HTTPv1 and HTTPv2, which declare their keywords in full, stay checked.

__own_make_keywords__: bool

Whether the parameters of this class’s own make() are accepted only while that make is the one in use. By default _declared_keywords() takes every make in the MRO. A base whose subclasses override make without forwarding sets this, so its keywords are refused for them rather than accepted and dropped, as IPv6_Ext does for len and data (#2286). Not inherited, and __keywords__ and the other construction methods are unaffected.

__schema__: Type[_ST]

Protocol header schema definition.

__header__: _ST

Protocol header schema instance.

_read_packet(length=None, *, header=None, payload=None, discard=False)

Read raw packet data.

Overloads:
Parameters:
  • length (int | None) – length of the packet

  • header (int | None) – length of the packet header

  • payload (int | None) – length of the packet payload

  • discard (bool) – flag if discard header data

  • If header is omitted, returns the whole packet data in bytes.

  • If discard is set as True, returns the packet body (in bytes) only.

  • Otherwise, returns the header and payload data as Packet object.

_get_payload()

Get payload from self.__header__.

Return type:

bytes

Returns:

Payload of self.__header__ as bytes.

See also

This is a wrapper function for pcapkit.protocols.schema.Schema.get_payload().

classmethod _make_data(data)

Create key-value pairs from data for protocol construction.

Parameters:

data (Data) – protocol data

Return type:

dict[str, Any]

Returns:

Key-value pairs for protocol construction.

_make_index(value, namespace, *, bits, name, alias=None)

Resolve the code given for an enumeration field of make().

The field takes a member of namespace or an int code, and either resolves with namespace’s get(). A name is refused rather than looked up, so a caller holding one resolves it first, with resolve_index() (#2594). The code is checked as _make_uint() checks an integer, so a bool passes only for a one-bit field (#2617): the field’s width decides what is refused, not the enumeration’s range.

Parameters:
  • value (Any) – the value given for the field

  • namespace (Type[_ET]) – the enumeration the field holds

  • bits (int) – width of the field, in bits

  • name (str) – name of the field, for the error message

  • alias (str | None) – prefix of the error message, for a caller whose alias raises before read() sets it; alias by default

Return type:

_ET

Returns:

What namespace’s get() resolves value to. For most registries that includes an unassigned code, as the Unassigned or Reserved member their _missing_ builds. Where get raises ValueError for a code the field carries, as a closed enumeration does, the code itself comes back as an int, so that the field is rebuilt as captured.

Raises:

ProtocolError – If value is not an int (a name among them), is a bool for a field wider than one bit, is negative, or does not fit in bits bits. The message names alias.

Changed in version 1.6.0: Takes the enumeration and the width of the field, in place of the default, namespace, reversed and pack arguments, refuses a code the field cannot carry, and refuses a name rather than resolving it against an enumeration inferred from the calling method’s frame (#2594).

classmethod _make_payload(data)

Create payload from data for protocol construction.

The payload’s type and name are __next_type__ and __next_name__. If either is missing or None, or data holds nothing under __next_name__, the payload is a NoPayload, as for a protocol with no next layer; otherwise Protocol.from_data builds it.

Info.to_dict carries both keys, so data rebuilt from such a dict dispatches as the info did. A hand-written dict must carry them too, as it must __short_read__ and, for IPv6, __exthdr__: the payload is never guessed from the other keys of data (#2003).

The payload is built one layer further into the frame, as _parse_next_layer() counts it, so a rebuild stops at FRAME_LAYER_LIMIT where the parse did (#1610). The payload’s parse reports nothing, the limit included: this protocol’s own parse goes over the same octets, so the rebuilt frame reports each warning, and each error a next-layer fallback absorbs, once, as the parsed one did (#2711).

Parameters:

data (Data) – protocol data

Return type:

ProtocolBase

Returns:

Payload for protocol construction.

_packing_target()

Return the instance that pack() makes its header on.

Return type:

Self

Returns:

The instance itself while it is being constructed, i.e. before __post_init__() has set its info, since its unpack() reads the made header back; a shallow copy of it otherwise, so that neither that header nor an attribute that make() sets is left on the instance (#1769).

Note

A pack() override that does not call this one has to build on this target too, as Frame.pack and PCAPNG.pack do. The copy is shallow, so a make() that mutates a container in place still reaches the instance’s.

_read_unpack(size=1, *, signed=False, lilendian=False, quiet=False)

Read bytes and unpack for integers.

Parameters:
  • size (int) – buffer size

  • signed (bool) – signed flag

  • lilendian (bool) – little-endian flag

  • quiet (bool) – quiet (no exception) flag

Return type:

int

Returns:

Unpacked data upon success

Raises:

StructError – If the buffer is empty, whatever quiet says, or if fewer than size octets were read, without quiet.

_read_octets(data, pos=0, *, size, what)

Read exactly size octets out of data at pos.

A plain slice comes back short past the end of data, which would let a truncated field parse rather than fail.

Parameters:
  • data (bytes) – buffer being read

  • pos (int) – offset of the octets in data

  • size (int) – octets to read

  • what (str) – name of the field, for the error message

Return type:

bytes

Returns:

The size octets at pos.

Raises:

ProtocolError – If fewer than size octets remain from pos. The message names alias.

Added in version 1.6.0.

_read_uint(data, pos=0, *, size, what, lilendian=False)

Read a size-octet unsigned integer out of data at pos.

_read_unpack() reads the file; this reads a buffer already in hand. The inverse is _make_pack(), not _make_uint(), which checks a value and packs nothing.

Parameters:
  • data (bytes) – buffer being read

  • pos (int) – offset of the integer in data

  • size (int) – octets in the integer

  • what (str) – name of the field, for the error message

  • lilendian (bool) – little-endian flag

Return type:

int

Returns:

The integer.

Raises:

ProtocolError – If fewer than size octets remain from pos, as _read_octets() raises it.

Added in version 1.6.0.

static _read_sint(value, bits)

Read value, an unsigned bits-bit field, as a two’s-complement one.

It takes the unsigned integer a field has already read, such as a BitField sub-field, rather than a buffer.

Parameters:
  • value (int) – the unsigned value read from the field

  • bits (int) – width of the field, in bits

Return type:

int

Returns:

The signed value the same bits denote.

Added in version 1.6.0.

_read_vector(data, pos=0, *, size=1, what)

Read a length-prefixed vector out of data.

The vector is a size-octet unsigned big-endian length, then that many octets, as the variable-length vectors of TLS’s presentation language are (RFC 9846 Section 3.4).

Parameters:
  • data (bytes) – buffer being read

  • pos (int) – offset of the length prefix in data

  • size (int) – octets in the length prefix

  • what (str) – name of the vector, for the error message

Return type:

tuple[bytes, int]

Returns:

The vector’s octets, and the offset just past them.

Raises:

ProtocolError – If the length prefix, or the octets it counts, run past the end of data. The message names alias.

Added in version 1.6.0.

_read_whole_vector(data, *, size=1, what)

Read the one length-prefixed vector that data holds.

The vector is read as _read_vector() reads it from offset zero, and has to end where data does.

Parameters:
  • data (bytes) – buffer holding the vector and nothing else

  • size (int) – octets in the length prefix

  • what (str) – name of the vector, for the error message

Return type:

bytes

Returns:

The vector’s octets.

Raises:

ProtocolError – If the vector runs past the end of data, or octets follow it. The message names alias.

Added in version 1.6.0.

_read_uints(data, *, size=1, what)

Read data as a run of size-octet unsigned big-endian integers.

Parameters:
  • data (bytes) – buffer holding the integers and nothing else

  • size (int) – octets in each integer

  • what (str) – name of the list, for the error message

Return type:

tuple[int, ...]

Returns:

The integers, in order.

Raises:

ProtocolError – If the length of data is not a multiple of size, whose trailing octets would otherwise be padded out when the list is made again. The message names alias.

Added in version 1.6.0.

classmethod _make_pack(integer, *, size=1, signed=False, lilendian=False)

Pack integers to bytes.

Parameters:
  • integer (int) – integer to be packed

  • size (int) – buffer size

  • signed (bool) – signed flag

  • lilendian (bool) – little-endian flag

Return type:

bytes

Returns:

Packed data upon success.

Raises:

StructError – If failed to pack the integer.

_make_octets(value, *, size, name, alias=None)

Check that value is exactly size octets.

The octets _read_octets() reads are written as they are, so their size is all there is to check.

Parameters:
  • value (Any) – the value given for the field

  • size (int) – octets in the field

  • name (str) – name of the field, for the error message

  • alias (str | None) – prefix of the error message, for a caller whose alias raises before read() sets it; alias by default

Return type:

bytes

Returns:

value as bytes.

Raises:

ProtocolError – If value is not bytes or bytearray, or is not size octets long. The message names alias.

Added in version 1.6.0.

classmethod _fill_short_read(value, *, size, model, field, offset=0)

Zero-fill the octets of value that a capture cut short.

A model parsed from a capture cut short records, in its __short_read__, the field of __schema__ the capture ended inside and the octets of it present. A padding field keeps only those octets, where the other fields read the rest as zeros, so a value read at or past the cut comes back short. Zero-filled, it rebuilds as the rest of the header does, and the rebuild is cut back to what was captured. A value of any other width is handed back for _make_octets() to refuse.

Parameters:
  • value (Any) – the value taken from model

  • size (int) – octets in the value’s field

  • model (Any) – the data model value was taken from

  • field (str) – the field of __schema__ that holds value

  • offset (int) – where value starts in field

Return type:

Any

Returns:

value zero-filled to size where it is exactly the octets the cut kept of it; otherwise value itself.

Added in version 1.6.0.

_make_uint(value, *, bits, name, alias=None)

Check that value is an unsigned integer that fits in bits bits.

A bool passes only for a one-bit field, so that a flag given for a wider field is refused rather than read as 0 or 1.

Parameters:
  • value (Any) – the value given for the field

  • bits (int) – width of the field, in bits

  • name (str) – name of the field, for the error message

  • alias (str | None) – prefix of the error message, for a caller whose alias raises before read() sets it; alias by default

Return type:

int

Returns:

value as a plain int.

Raises:

ProtocolError – If value is not an int, is a bool for a field wider than one bit, is negative, or does not fit in bits bits. The message names alias.

Added in version 1.6.0.

_make_sint(value, *, bits, name, alias=None, allow_unsigned=False)

Check that value is a signed integer that fits in bits bits.

The inverse of _read_sint(). A bool is refused whatever bits is, since no signed field holds a flag.

Parameters:
  • value (Any) – the value given for the field

  • bits (int) – width of the field, in bits

  • name (str) – name of the field, for the error message

  • alias (str | None) – prefix of the error message, for a caller whose alias raises before read() sets it or is not the prefix its messages carry; alias by default

  • allow_unsigned (bool) – also accept the unsigned spelling of the field’s bits bits, i.e. up to 2 ** bits - 1, for a field whose specification spells one value both ways, as a sentinel written -1 and 0xFF...F; both denote the same bits

Return type:

int

Returns:

The unsigned integer whose bits bits denote value in two’s complement.

Raises:

ProtocolError – If value is not an int, is a bool, or does not fit in bits bits as two’s complement (or, with allow_unsigned, as an unsigned integer either). The message names alias.

Added in version 1.6.0.

static _uint_size(value, *, minimum=0)

Count the octets a non-negative integer needs.

value.bit_length() is rounded up to whole octets: // 8 alone floors, and counts one octet too few for a width that is not a multiple of eight.

Parameters:
  • value (int) – the integer, not negative

  • minimum (int) – the fewest octets to count, for a field that cannot be empty although 0 needs none

Return type:

int

Returns:

The octets value needs, and at least minimum.

Added in version 1.6.0.

classmethod _make_vector(octets, *, size=1)

Write octets as a length-prefixed vector.

The inverse of _read_vector(): a size-octet unsigned big-endian length, packed by _make_pack(), then octets.

Parameters:
  • octets (bytes) – the vector’s octets

  • size (int) – octets in the length prefix

Return type:

bytes

Returns:

The length prefix followed by octets.

Raises:

StructError – If the length of octets does not fit in size octets.

Added in version 1.6.0.

classmethod _make_uints(values, *, size=1)

Write values as a run of size-octet unsigned big-endian integers.

The inverse of _read_uints(), each value packed by _make_pack().

Parameters:
  • values (Iterable[int]) – the integers, or anything int converts to one, such as an enumeration member

  • size (int) – octets in each integer

Return type:

bytes

Returns:

The packed integers, concatenated in order.

Raises:

StructError – If a value is negative, or does not fit in size octets.

Added in version 1.6.0.

_read_mac_addr(addr)

Read a MAC address, an EUI-64 one included.

Parameters:

addr (bytes) – the address octets

Return type:

str

Returns:

Colon (:) separated hex encoded address.

Added in version 1.6.0.

_make_mac_addr(addr, *, size=6, name='MAC address', alias=None)

Make a MAC address, or an EUI-64 one with size=8.

The inverse of _read_mac_addr().

Parameters:
  • addr (str | bytes | bytearray) – :- or --separated hex encoded address

  • size (int | None) – octets in the address, or None for any number of them, none included

  • name (str) – name of the address, for the error message

  • alias (str | None) – prefix of the error message, for a caller whose alias raises before read() sets it or is not the prefix its messages carry; alias by default

Return type:

bytes

Returns:

The address octets.

Raises:

ProtocolError – If addr is not a str, bytes or bytearray (a bool included), or is not a :- or --separated hex encoded address of size octets. The message names alias.

Added in version 1.6.0.

static _lookup_registry(registry, code)

Look up a dispatch registry entry without recording a miss.

Parameters:
  • registry (DefaultDict[Any, _VT]) – dispatch registry to read, i.e. self.__proto__ or one of the per-protocol __option__ / __chunk__ / __block__ family. Passed in rather than read from the class, so that a caller reaching the registry through an instance keeps doing so.

  • code (Any) – registry key to look up, i.e. the wire code being dispatched on

Return type:

_VT

Returns:

The entry registered for code, or the fallback registry declares when code is not registered.

Important

Each of these registries is a collections.defaultdict on a class attribute, shared process-wide, so registry[code] would insert every code it misses: one packet with an unrecognised code would grow the registry permanently. The entry buys nothing, costs a spurious “already registered” warning on the next genuine register of that code, and makes “is this code registered?” depend on what has been parsed, so the fallback is read from the default factory directly.

static _lookup_next_layer(registry, proto)

Look up the protocol class registered for a next layer code.

Parameters:
Return type:

Type[ProtocolBase]

Returns:

The class registered for proto, or the fallback registry declares – normally Raw – when proto is not registered.

Important

The lookup is self._lookup_registry, so a miss does not grow the shared registry. The entry found, registered or the fallback, may be a ModuleDescriptor, resolved to the class it names.

Nothing is written back. A hit memoised under proto would keep a class importlib.reload() makes stale, and make parsing mutate a registry the whole process shares (#1559); so would a memo in the default factory or in a cache beside the registry (#421, #425, #555). Each lookup resolves its descriptor again, kept cheap by ModuleDescriptor.klass reading sys.modules rather than re-entering importlib.import_module() (#574).

_decode_next_layer(dict_, proto, length=None, *, packet=None)

Decode next layer protocol.

Parameters:
  • dict_ (_PT) – info buffer

  • proto (int) – next layer protocol index

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

  • packet (dict[str, Any] | None) – packet info (passed from self.unpack)

Return type:

_PT

Returns:

Current protocol with next layer extracted.

Notes

The method adds a __next_type__ key to dict_ to store the next layer protocol type, and a __next_name__ key to store the next layer protocol name. Info.to_dict carries both, so that _make_payload() dispatches a dict rebuild on them, while the dumpers and repr leave them out (#2003).

_import_next_layer(proto, length=None, *, packet=None)

Import next layer extractor.

Parameters:
Return type:

ProtocolBase

Returns:

Instance of next layer.

_empty_next_layer(file_, length)

The class a next layer with nothing to parse is kept as.

Parameters:
  • file_ (bytes) – payload of the current layer

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

Return type:

Type[ProtocolBase] | None

Returns:

None if octets were captured past the header and it leaves its next layer a length, which is then parsed. Otherwise Raw if no octets were captured past a header leaving its next layer a negative length, and NoPayload if the header leaves none, or no octets past it.

Note

A header leaves a negative length when it declares more than it was given: one the capture cut short, read at the octets captured, or an IPv6 extension header overrunning the payload (#2477). Such a next layer is kept raw, not dispatched on a code the cut may have read as zeros (#1170). from_data() reads the rebuild of a cut header at the width its parse read it at, which leaves it the same length, so the rebuild keeps Raw where its data model did (#2717, #2761).

Added in version 1.6.0.

static _parse_next_layer(klass, file_, length, **kwargs)

Parse the next layer, or keep it as raw octets if its header was not captured.

Parameters:
  • klass (Type[ProtocolBase]) – next layer protocol class

  • file_ (bytes) – payload of the current layer

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

  • **kwargs (Any) – keyword arguments for the next layer’s constructor

Return type:

ProtocolBase

Returns:

Instance of klass, or of Raw when fewer octets were captured than its header needs, or when it is past FRAME_LAYER_LIMIT.

Note

Schema.unpack zero-fills a field the stream ends inside, so a header parsed from too few octets is filled with values that were never on the wire, and from_data rebuilds them (#1170). Such a payload is kept as Raw instead, as an unparseable one is.

The captured octets are the first length of file_, or all of it when it holds fewer, as a truncated capture does. They are short of the header when there are fewer than the next layer’s __length_hint__, unless the header it parsed, length octets long, fits in them anyway: for a variable-length header such as L2TPv2 the hint is the longest form rather than the shortest. A next layer that reports no hint is kept as parsed.

The warnings of a parse that may be replaced are held until that is known, then:

  • replaced as short – dropped, since they describe a header the result does not have: packet length < 0 twice for an Ethernet frame of 10 octets (#1580);

  • kept – reported as the parse ends, inside the guard that catches them under an error filter; a layer kept with its header cut short still warns;

  • raised – dropped when beholder(), which wraps _import_next_layer(), replaces the layer, whose error reports the failure (#2308); otherwise reported as the error leaves.

Under beholder a layer is held however much was captured, since one that raises is replaced at any length (#2516), so a kept layer’s warnings follow those of the layers it carries. Outside it, a layer captured at least as long as its hint cannot be replaced, and is parsed holding nothing, even inside one that holds.

A layer past FRAME_LAYER_LIMIT in its frame is not parsed: it and the rest of the frame are kept as Raw, marked _past_layer_limit, with one ProtocolWarning (#1610).

Warns:

ProtocolWarning – If the next layer is past FRAME_LAYER_LIMIT.

_get_context(cls=None)

Get the caller supplied context for this protocol, if any.

The lookup is keyed on self.id, so a protocol finds its own context without knowing how the caller spelled the registry.

Parameters:

cls (Type[_CTX] | None) – Expected context class; when given, a context registered under this protocol’s name but of another type is ignored rather than returned for the implementation to trip over.

Return type:

_CTX | None

Returns:

The matching context, or None when the caller supplied none.

_data: bytes

Raw packet data.

_file: IO[bytes]

Source packet stream.

_info: _PT

Parsed packet data.

_next: ProtocolBase

Next layer protocol instance.

_protos: ProtoChain

Protocol chain instance.

_seekset: int

File pointer.

Type:

int

_sigterm

Whether to stop parsing the next layer of protocol.

Type:

bool

__reconstructing__: bool = False

Whether from_data() is rebuilding this instance from a parsed data model, rather than from keywords somebody wrote. It decides only whether the construction keyword check of __init__() raises or warns, and is set for that call alone; every other code path sees False.

__short_read__: tuple[str, int] | None = None

The __short_read__ record of the data model from_data() rebuilds this instance from. pack() cuts the header it makes back to the octets captured, and __post_init__() has unpack() parse them at the width __short_width__ records, so the rebuild is parsed as its capture was (#2703, #2761). Set for that call alone, like __reconstructing__; otherwise None.

_past_layer_limit: bool = False

Whether _parse_next_layer() kept this layer as Raw unparsed, being past FRAME_LAYER_LIMIT. Such a layer carries an error as a failed parse does; this tells the two apart, for what follows the limit is not to be read on (#1610).

__data__: Type[_PT] = <class 'pcapkit.protocols.misc.raw.data.Raw'>

Protocol packet data definition.

__init__(file=None, length=None, **kwargs)

Initialisation.

Overloads:
Parameters:
Raises:

UnsupportedCall – When constructing (file is None), if a keyword names no parameter of this protocol’s make(), read(), pack(), unpack(), __post_init__() or __init__(), anywhere in the MRO – except a make whose class sets __own_make_keywords__, which counts only while it is the make of the protocol being constructed – and is not listed in __keywords__. Parsing (file is given) is unaffected.

Note

The _layer, _protocol and __context__ keywords are out-of-band: they configure the parse rather than describe the packet, and are consumed here, the one point every producer passes through, so a spelling normalised here is normalised for the engines, every _import_next_layer and any third-party protocol alike.

packet is read but not consumed: it stays in the keywords forwarded to __post_init__(), and while parsing a copy is republished beside it as __packet__.

__post_init__(file=None, length=None, **kwargs)

Post initialisation hook.

Overloads:
Parameters:
  • file (IO[bytes] | bytes | None) – Source packet stream.

  • length (int | None) – Length of packet data.

  • **kwargs (Any) – Arbitrary keyword arguments.

See also

For construction arguments, please refer to self.make.

Note

Inside a payload _make_payload() rebuilds, the parse’s warnings are dropped, since the enclosing layer parses the same octets again and reports them (#2711). A parse that raises reports its warnings, unless beholder() replaces the layer.

classmethod __init_subclass__(schema=None, data=None, code=None, *args, **kwargs)[source]

Initialisation for subclasses.

Parameters:
  • schema (Type[_ST] | None) – Schema class.

  • data (Type[_PT] | None) – Data class.

  • code (Any) – Next-layer dispatch registration key(s). None (the default) skips registration entirely. See ProtocolBase.__init_subclass__() for the accepted shapes and the enum-type inference rule.

  • *args (Any) – Arbitrary positional arguments.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

None

Sets self.__schema__ and self.__data__ on the subclass through ProtocolBase.__init_subclass__(), which also finds an omitted one.

Once that has accepted code, a concrete subclass is also named in the by-name registry, ProtocolBase.__registry__, under its upper-cased class name; unlike code’s dispatch registration, this is not opt-in. An abstract subclass, as isabstract() reports it, is not named, nor is a class deriving ProtocolBase alone, as every built-in protocol does. A name holding another entry keeps it, with a RegistryWarning; only ProtocolBase.register_protocol replaces one. The ModuleDescriptor naming the class’s own module and name is no clash, and stays.

See also

For more information on the registry, please refer to ProtocolBase.register_protocol.

Changed in version 1.6.0: An abstract subclass is not registered, and a name already holding an entry keeps it, where every subclass was registered over it (#2763).

__repr__()

Returns representation of parsed protocol data.

Example

>>> protocol
<Frame frame=<Frame ..., ethernet=Ethernet(...), protocols='Ethernet:IPv6:Raw', packet=b'...'>>
Return type:

str

__str__()

Returns formatted hex representation of source data stream.

Example

>>> protocol
<Frame frame=<Frame ..., ethernet=Ethernet(...), protocols='Ethernet:IPv6:Raw', packet=b'...'>>
>>> print(protocol)
00 00 00 00 00 00 00 a6 87 f9 27 93 16 ee fe 80 00 00 00     ..........'........
00 00 00 1c cd 7c 77 ba c7 46 b7 87 00 0e aa 00 00 00 00     .....|w..F.........
fe 80 00 00 00 00 00 00 1c cd 7c 77 ba c7 46 b7 01 01 a4     ..........|w..F....
5e 60 d9 6b 97                                               ^`.k.
Return type:

str

__getitem__(key)

Subscription (getitem) support.

  • If key is a Protocol object, the method will fetch its indexes (self.id).

  • Later, search the packet’s chain of protocols with the calculated key.

  • If no matches, then raises ProtocolNotFound.

Parameters:

key (str | Protocol | Type[Protocol]) – Indexing key.

Return type:

ProtocolBase

Returns:

The sub-packet from the current packet of indexed protocol.

Raises:

ProtocolNotFound – If key is not in the current packet.

See also

The method calls self.expand_comp to handle the key and expand it for robust searching.

__contains__(name)

Returns if certain protocol is in the instance.

Parameters:

name (str | Protocol | Type[Protocol]) – Name to search

Return type:

bool

See also

The method calls self.expand_comp to handle the name and expand it for robust searching.

abstractmethod classmethod __index__()

Numeral registry index of the protocol.

Return type:

IntEnum | aenum.IntEnum

__length_hint__()

Return an estimated length for the object.

Return type:

int | None

_exlayer: str | None

Parse packet until such layer.

_exproto: str | ProtocolBase | Type[ProtocolBase] | None

Parse packet until such protocol.

_exctx: ContextRegistry | None = None

Caller supplied parsing context; see pcapkit.corekit.context. self.__init__ sets a ContextRegistry; an instance built without __init__ reads the class-level None.

Parsing and Construction

Parsing, construction, from_schema() and from_data() share one path:

        flowchart TD
    FS["from\_schema(schema)"] -->|"\_\_header\_\_ = schema,<br/>then its octets"| P
    FD["from\_data(data)"] -->|"\_make\_data(data) gives the fields,<br/>\_\_reconstructing\_\_ set"| C
    P["Proto(file, length, ...)<br/>parse"] --> INIT
    C["Proto(field=value, ...)<br/>construct"] --> INIT
    INIT["\_\_init\_\_<br/>consumes \_layer, \_protocol and \_\_context\_\_"]
    INIT -->|construct| CHK["\_check\_construction\_keywords<br/>an undeclared keyword: UnsupportedCall,<br/>or a warning when reconstructing"]
    CHK --> PACK["\_\_post\_init\_\_: pack(...)<br/>make() gives the schema, kept as \_\_header\_\_,<br/>and its octets"]
    INIT -->|parse| OCT["\_\_post\_init\_\_: the octets given,<br/>or file.read(length)"]
    PACK --> DATA["\_data, and \_file over it"]
    OCT --> DATA
    DATA --> UNP{"unpack: \_\_header\_\_ set?"}
    UNP -->|no| SCH["\_\_schema\_\_.unpack(\_file, length, packet)"]
    UNP -->|yes| KEPT["kept, or replaced by the parse of its octets<br/>where it holds raw items"]
    SCH --> READ
    KEPT --> READ
    READ["read(): the data model,<br/>calling \_decode\_next\_layer"] --> INFO["\_\_init\_\_: \_info updated with packet"]

    click FS "protocol.html#pcapkit.protocols.protocol.Protocol.from_schema"
    click FD "protocol.html#pcapkit.protocols.protocol.Protocol.from_data"
    click INIT "protocol.html#pcapkit.protocols.protocol.Protocol.__init__"
    click PACK "protocol.html#pcapkit.protocols.protocol.Protocol.pack"
    click UNP "protocol.html#pcapkit.protocols.protocol.Protocol.unpack"
    click READ "protocol.html#protocol-next-layer-dispatch"
    

A rebuild of a header the capture cut short drops the header pack() made, so unpack() parses its octets back (#2761), and inside a payload being rebuilt the parse’s warnings are held and dropped (#2711).

Next-Layer Dispatch

How a layer picks and builds the layer it carries, and where it keeps Raw or NoPayload instead:

        flowchart TD
    DEC["\_decode\_next\_layer(dict\_, proto, length)<br/>called from read()"] --> IMP["\_import\_next\_layer, wrapped by beholder"]
    IMP --> EMP{"\_empty\_next\_layer"}
    EMP -->|"octets and a non-zero length"| TERM{"layer= or protocol= reached?"}
    EMP -->|"no octets, length &lt; 0"| KRAW["Raw"]
    EMP -->|"otherwise: no octets,<br/>or a length of 0"| KNOP["NoPayload"]
    TERM -->|yes| KRAW
    TERM -->|no| LOOK["\_lookup\_next\_layer(\_\_proto\_\_, proto)<br/>the registered class, or the registry's fallback,<br/>normally Raw"]
    KRAW --> LIM
    KNOP --> LIM
    LOOK --> LIM
    LIM{"\_parse\_next\_layer:<br/>past FRAME\_LAYER\_LIMIT,<br/>and not already Raw or NoPayload?"}
    LIM -->|yes| RAWL["Raw, marked \_past\_layer\_limit<br/>one ProtocolWarning"]
    LIM -->|no| NEW["klass(file\_, length, ...)"]
    NEW -->|raises| BEH["beholder: NoPayload for an end-of-file StructError,<br/>else Raw carrying the error"]
    NEW -->|parsed| SHORT{"captured fewer octets than both<br/>\_\_length\_hint\_\_() and its length?"}
    SHORT -->|yes| RAWS["Raw, its held warnings dropped"]
    SHORT -->|no| KEEP["the parsed layer"]
    RAWL --> WRITE
    BEH --> WRITE
    RAWS --> WRITE
    KEEP --> WRITE
    WRITE["dict\_ gets its info, \_\_next\_type\_\_ and \_\_next\_name\_\_<br/>self.\_next and self.\_protos set"]

    click DEC "protocol.html#pcapkit.protocols.protocol.Protocol._decode_next_layer"
    click IMP "protocol.html#pcapkit.protocols.protocol.Protocol._import_next_layer"
    click EMP "protocol.html#pcapkit.protocols.protocol.Protocol._empty_next_layer"
    click LOOK "protocol.html#pcapkit.protocols.protocol.Protocol._lookup_next_layer"
    click LIM "protocol.html#pcapkit.protocols.protocol.Protocol._parse_next_layer"
    click BEH "../corekit/decorators.html#pcapkit.corekit.decorators.beholder"
    

Some layers add steps of their own: Internet the EXTENSION_HEADER_LIMIT bound and IGMP’s dispatch, Transport a family base’s dispatch, and IPv6 the walk drawn under The Extension Header Walk.

Layers per Frame

A frame is dissected to at most FRAME_LAYER_LIMIT layers, counted from the first layer its frame record carries, through tunnels, VLAN tags and IPv6 extension headers alike; a protocol constructed from its own octets is not counted, so its count starts at the first layer it dissects. The rest is kept as Raw, with one ProtocolWarning (#1610), and marked _past_layer_limit, so the default engine’s TCP reassembly and flow tracing do not read a TCP segment back out of it, as they do one the TCP parser rejected (#1518). One chain of extension headers is bounded separately, by EXTENSION_HEADER_LIMIT.

The pyshark, scapy and pypcapfile engines dissect with their own parsers, which do not apply the frame’s bound (#1609); the dpkt toolkit reads what dpkt decodes, which applies neither bound.

Value Helpers

A protocol reads and makes field values through the helpers on Protocol, not copies of its own (#2614). A maker checks a caller’s values through them before packing, and raises ProtocolError for a value its field cannot carry rather than masking it (#2617):

Helper

Does

_make_uint()

checks an unsigned integer; a bool passes for a one-bit field only

_make_sint()

checks a two’s-complement integer, the inverse of _read_sint()

_make_octets()

checks a fixed-size field’s octets, refusing any other width rather than padding or cutting it (#2676)

_fill_short_read()

zero-fills the octets a cut capture left out of a value taken from its model, before _make_octets(), for the rebuild to cut back

_uint_size()

counts the octets a variable-width integer needs

pad_length()

counts the padding that takes a length to an alignment boundary

Data Models

class pcapkit.protocols.data.Protocol(*args, **kwargs)[source]

Bases: Data

Root protocol.

packet: bytes

Packet payload.

class pcapkit.protocols.data.Packet(header, payload)[source]

Bases: Data

Header and payload data.

header: bytes

packet header

payload: bytes

packet payload

Internal Definitions

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

Bases: Generic[_PT, _ST]

Abstract base class for all protocol families.

The built-in protocol families – the layer base classes Link, Internet, Transport and Application, and the miscellaneous protocols in pcapkit.protocols.misc, PCAP and PCAP-NG included – derive from this class directly. Its metaclass is ProtocolMeta.

Note

This class is for internal use only. For customisation, subclass Protocol to create a new protocol stack, or the matching layer base class above for a new protocol in an existing layer.

__registry__: dict[str, ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]]

Protocol registry by name, holding each protocol class under its upper-cased class name, 'IPV4' for IPv4. Each built-in protocol is a ModuleDescriptor here, so the map names every one before any is imported, and get_protocol() imports a class only when it resolves its entry (#2763). Protocol.__init_subclass__() adds each concrete Protocol subclass as it is defined, register_protocol() replaces an entry, and ProtocolMeta.registry is a read-only view.

Added in version 1.6.0.

classmethod register_protocol(protocol)[source]

Register a protocol class in __registry__, replacing what its name holds.

The key is protocol.__name__.upper(). Defining a concrete Protocol subclass registers it already, but keeps an entry its name holds, so this is how to replace one, or to register a class that derives ProtocolBase alone.

Parameters:

protocol (Type[ProtocolBase]) – ProtocolBase subclass

Raises:

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

Warns:

pcapkit.utilities.warnings.RegistryWarning – If the name holds a different class, naming it and its replacement, and their ids where the two read the same. A ModuleDescriptor entry is resolved to compare, so registering the class it names is silent and leaves the descriptor in place.

Note

A built-in protocol is stored as the descriptor it shipped as, per _shipped_registry, rather than as its class, so undoing an override leaves the entry as shipped, to be imported on lookup.

Added in version 1.6.0.

classmethod get_protocol(name, default=None)[source]

Look a protocol class up in __registry__ by name.

Overloads:
Parameters:
  • name (str) – protocol name, in any case: 'ipv4' finds IPv4

  • default (Any) – what to return where no entry has the name

Returns:

The class registered under name.upper(), imported where its entry is a ModuleDescriptor, or default. The entry is left as it is, so a descriptor is resolved again on each lookup and follows a reloaded module.

Raises:

pcapkit.utilities.exceptions.ProtocolError – If a descriptor names a class its module does not define.

Added in version 1.6.0.

classmethod __init_subclass__(schema=None, data=None, code=None, *args, **kwargs)[source]

Initialisation for subclasses.

Parameters:
  • schema (Type[_ST] | None) – Schema class.

  • data (Type[_PT] | None) – Data class.

  • code (Any) – Next-layer dispatch registration key(s). None (the default) skips registration entirely – see below.

  • *args (Any) – Arbitrary positional arguments.

  • **kwargs (Any) – Arbitrary keyword arguments.

Raises:

UnsupportedCall – If any unrecognised class keyword is given.

Return type:

None

Sets self.__schema__ and self.__data__ on the subclass and, if code is given, registers it into the next-layer dispatch registry (or registries) code names, e.g. Link.__proto__.

Notes

An omitted schema or data is the class of the subclass’s own name in the schema or data module beside the protocol module defining it, as L2TP finds L2TP (#2534), else Raw or Raw.

Dispatch registration is opt-in, like the engine=/protocol=/ fmt= keywords of Engine, Reassembly, TraceFlow and Dumper. Every built-in protocol omits code: the built-in dispatch tables (e.g. Link.__proto__) are literal assignments in each layer module. A class defined without code can be registered later through the owning class’s register() or the matching register_* helper in pcapkit.foundation.registry.protocols.

code accepts:

  • a single enum member, whose type determines the destination registry (or registries) – e.g. any EtherType member always means Link, and any LinkType member means both Frame and PCAPNG;

  • a dict mapping a destination class to a key, for a key that cannot name its own destination – a raw int port, for instance, is ambiguous between TCP and UDP, and must use this form;

  • an iterable mixing either of the above, to register the same class into several registries from a single declaration – e.g. a L2TP subclass reachable both by its IP protocol number and by a UDP port.

The mapping form is accepted even where the key’s type could be inferred. An enum member whose type names no known destination raises RegistryError rather than guessing.

See also

pcapkit.foundation.registry.protocols.protocol.register_protocol_code() implements the resolution described above.

Protocol inherits the other members of this class, and they are documented under it above; each group below links to its entries.

property name
property alias
property info_name
property info
property data
property length
property payload
property protocol
property protochain
property packet[source]
property schema[source]
property context

name, alias, info_name, info, data, length, payload, protocol, protochain, packet, schema, context

id()[source]
register()[source]
analyze()[source]
from_schema()[source]
from_data()[source]
read()[source]
make()[source]
unpack()[source]
pack()[source]
decode()[source]
unquote()[source]
resolve_index()[source]
expand_comp()[source]
_read_packet()[source]
_get_payload()[source]
_make_data()[source]
_make_index()[source]
_make_payload()[source]
_packing_target()[source]
_read_unpack()[source]
_read_octets()[source]
_read_uint()[source]
_read_sint()[source]
_read_vector()[source]
_read_whole_vector()[source]
_read_uints()[source]
_make_pack()[source]
_make_octets()[source]
_fill_short_read()[source]
_make_uint()[source]
_make_sint()[source]
_uint_size()[source]
_make_vector()[source]
_make_uints()[source]
_read_mac_addr()[source]
_make_mac_addr()[source]
_lookup_registry()[source]
_lookup_next_layer()[source]
_decode_next_layer()[source]
_import_next_layer()[source]
_parse_next_layer()[source]
_get_context()[source]
__init__()[source]
__post_init__()[source]
__repr__()[source]
__str__()[source]
__getitem__()[source]
__contains__()[source]
__index__()[source]
__length_hint__()[source]

id(), register(), analyze(), from_schema(), from_data(), read(), make(), unpack(), pack(), decode(), unquote(), resolve_index(), expand_comp(), _read_packet(), _get_payload(), _make_data(), _make_index(), _make_payload(), _packing_target(), _read_unpack(), _read_octets(), _read_uint(), _read_sint(), _read_vector(), _read_whole_vector(), _read_uints(), _make_pack(), _make_octets(), _fill_short_read(), _make_uint(), _make_sint(), _uint_size(), _make_vector(), _make_uints(), _read_mac_addr(), _make_mac_addr(), _lookup_registry(), _lookup_next_layer(), _decode_next_layer(), _import_next_layer(), _parse_next_layer(), _get_context(), __init__(), __post_init__(), __repr__(), __str__(), __getitem__(), __contains__(), __index__(), __length_hint__()

__layer__
__proto__
__keywords__
__own_make_keywords__
__schema__
__header__
_data
_file
_info
_next
_protos
_seekset
_sigterm
_past_layer_limit
__data__
_exlayer
_exproto
_exctx

__layer__, __proto__, __keywords__, __own_make_keywords__, __schema__, __header__, _data, _file, _info, _next, _protos, _seekset, _sigterm, _past_layer_limit, __data__, _exlayer, _exproto, _exctx

class pcapkit.protocols.protocol.ProtocolMeta(name, bases, namespace, /, **kwargs)[source]

Bases: ABCMeta

Metaclass of ProtocolBase, and so of every protocol class.

Over abc.ABCMeta, it adds the class property registry.

property registry: MappingProxyType[str, ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]]

Read-only view of the by-name protocol registry.

It is ProtocolBase.__registry__, with each entry as stored: a built-in protocol is the ModuleDescriptor naming it, so reading the view imports nothing. Look a class up with ProtocolBase.get_protocol(), which resolves a descriptor.

Note

Every protocol class reads the same map, later registrations included. Defined on the metaclass, it is a class attribute, not an instance one.

Added in version 1.6.0.

pcapkit.protocols.protocol.OUT_OF_BAND_KEYWORDS

Construction keywords that name no field. Protocol.__init__ or the schema layer consumes them, not make. No signature declares them, so _declared_keywords() takes them from here.

packet is injected by the library: Protocol.__init__ puts packet=self.packet.payload into every parsed _info, which the default Protocol._make_data (data.to_dict()) carries into the keywords Protocol.from_data rebuilds from. Refusing it would break from_data for every protocol whose make lacks it, starting with NoPayload. Where it is a real field, as the packet type of HIP.make, listing it here only stops it being refused.

pcapkit.protocols.protocol._KEYWORD_CONSUMERS

Methods a construction keyword may be for. Protocol.__post_init__ passes the same **kwargs to pack (and so make) and unpack (and so read).

pcapkit.protocols.protocol._declared_keywords(cls)[source]

Collect every keyword the protocol cls declares a parameter for.

Parameters:

cls (type) – Protocol class to inspect.

Return type:

frozenset[str] | None

Returns:

Names of every keyword-acceptable parameter declared by any of _KEYWORD_CONSUMERS anywhere in the MRO of cls, plus every entry of Protocol.__keywords__ found there, plus OUT_OF_BAND_KEYWORDS. None if cls itself sets __keywords__ to None, meaning its keywords cannot be enumerated and are not to be checked – inherited None does not count, as Protocol.__keywords__ explains.

The union is wider than the signature of cls.make: Protocol.__post_init__ hands one **kwargs to both the construction and the parse, so a keyword read declares travels through make too, as extension of HIP.read does.

The walk covers the whole MRO, not the most derived override of each method, so a subclass forwarding to its parent keeps the parent’s keywords. The exception is a class that sets Protocol.__own_make_keywords__: its make counts only while no subclass overrides it (#2286).

Type Variables

pcapkit.protocols.protocol._PT: pcapkit.protocols.data.Data
pcapkit.protocols.protocol._ST: pcapkit.protocols.schema.Schema