Parsing Context

Parsing Context

pcapkit.corekit.context provides a protocol keyed channel for caller supplied information that a protocol needs in order to parse a packet, but that is not carried on the wire.

Most protocols are self describing – every length, offset and type that pcapkit needs to walk a packet is present in the packet itself. A few are not. ESP is the motivating example: RFC 4303 deliberately leaves the payload length, the position of the Pad Length / Next Header trailer and the length of the Integrity Check Value to be derived from the Security Association (SA), which is negotiated out of band and is therefore knowable only to the caller.

Rather than adding protocol specific keyword arguments to Extractor, such information is passed as a ContextRegistry – a mapping of protocol index ID (c.f. Protocol.id) to a ProtocolContext instance. The registry is handed to Extractor once, and is then propagated down the protocol stack by Protocol._import_next_layer, so that a protocol nested arbitrarily deep can reach it through Protocol._get_context.

Example

Decoding an ESP tunnel end to end:

>>> import pcapkit
>>> from pcapkit.protocols.internet.esp import (Cipher, ESPContext,
...                                            Integrity, SecurityAssociation)
>>> sa = SecurityAssociation(
...     spi=0x4321,
...     encryption=Cipher.AES_CBC,
...     encryption_key=bytes.fromhex('90d382b410eeba7ad938c46cec1a82bf'),
... )
>>> extraction = pcapkit.extract('esp.pcap', context=ESPContext(sa))

Important

A context object frequently holds secrets – ESP encryption and integrity keys, for instance. Contexts are therefore held as plain instance attributes on the protocol object and are never written into the protocol’s data model, which is the only thing that reaches Info.to_dict and, from there, the output dumpers. Implementations of ProtocolContext are expected to keep secrets out of their __repr__() as well.

class pcapkit.corekit.context.ProtocolContext[source]

Bases: object

Abstract base class for caller supplied protocol parsing context.

A subclass carries whatever out-of-band information the corresponding protocol needs, and declares which protocol it applies to through protocol().

Warning

Should the context hold secrets, the subclass must override __repr__() so that they are not printed. The default implementation below prints the class name and the protocol names only, and is safe in that respect.

abstractmethod classmethod protocol()[source]

Index ID of the protocol(s) this context applies to.

The returned names are matched against Protocol.id, and are case insensitive.

Return type:

tuple[str, ...]

__repr__()[source]

Representation of the context, free of any secrets.

Return type:

str

class pcapkit.corekit.context.ContextRegistry(*contexts, **named)[source]

Bases: Mapping[str, ProtocolContext]

Protocol keyed collection of ProtocolContext instances.

Parameters:
register(context, *, name=None)[source]

Register context under one or more protocol index IDs.

Parameters:
Raises:

RegistryError – If context is not a ProtocolContext, or if a context is already registered for the same protocol.

Return type:

None

classmethod make(value)[source]

Coerce value into a ContextRegistry.

This is the normalisation used by the public interfaces, so that a caller may pass whichever shape is most convenient:

Parameters:

value (ContextRegistry | ProtocolContext | Mapping[str, ProtocolContext] | Iterable[ProtocolContext] | None) – Value to coerce.

Return type:

Self

Returns:

A new ContextRegistry.

Raises:

RegistryError – If value is of an unsupported type.

match(names, cls=None)[source]

Find the context registered for any of names.

Parameters:
  • names (Iterable[str]) – Protocol index IDs to look up, in order of preference.

  • cls (Type[TypeVar(_CT, bound= ProtocolContext)] | None) – If given, the context is only returned when it is an instance of cls.

Return type:

TypeVar(_CT, bound= ProtocolContext) | None

Returns:

The first matching context, or None if there is none.

__getitem__(key)[source]

Get the context registered for key.

Return type:

ProtocolContext

__iter__()[source]

Iterate over the registered protocol index IDs.

Return type:

Iterator[str]

__len__()[source]

Number of registered contexts.

Return type:

int

__contains__(key)[source]

Test whether a context is registered for key.

Return type:

bool

__bool__()[source]

Test whether any context is registered.

Return type:

bool

__repr__()[source]

Representation of the registry, free of any secrets.

Return type:

str