Parsing Context

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

Most protocols are self-describing: every length, offset and type needed to walk a packet is in the packet. A few are not, and 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 the Security Association (SA), which is negotiated out of band and known 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. It is handed to Extractor once and propagated down the protocol stack by Protocol._import_next_layer, so that a protocol nested arbitrarily deep can reach it through Protocol._get_context.

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 often holds secrets, such as ESP encryption and integrity keys. Contexts are therefore plain instance attributes on the protocol object and are never written into its data model, which is the only thing that reaches Info.to_dict and, from there, the output dumpers. ProtocolContext implementations 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.

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

Type Variables

pcapkit.corekit.context._CT: pcapkit.corekit.context.ProtocolContext