Base Protocol

pcapkit.protocols.transport.transport contains Transport, which is a base class for transport layer protocols, eg. TCP, UDP and SCTP.

class pcapkit.protocols.transport.transport.Transport(file=None, length=None, **kwargs)[source]

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

Abstract base class for transport layer protocol family.

property layer: Literal['Transport']

Protocol layer.

classmethod register(code, protocol)[source]

Register a new protocol class.

Notes

The full qualified class name of the new protocol class should be as {protocol.module}.{protocol.name}.

Parameters:

Important

This method must be called from a non-abstract class, as the protocol map should be associated directly with specific transport layer protocol type.

Raises:
Warns:

pcapkit.utilities.warnings.RegistryWarning – If this port 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 ProtocolBase.register for the guard this shares with register_protocol.

Note

cls.__proto__ belongs to the concrete protocol, not to Transport, so register_apptype reaching this method twice for one call – once as TCP, once as UDP – inspects two different registries and cannot warn spuriously.

classmethod analyze(ports, payload, **kwargs)[source]

Analyse packet payload.

Parameters:
  • ports (tuple[int, int]) – Source & destination port numbers.

  • payload (bytes) – Packet payload.

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

Return type:

ProtocolBase

Returns:

Parsed payload as a Protocol instance.

static _make_port(port, proto)[source]

Resolve a port number to its application type.

Parameters:
  • port (AppType | int) – port number, or the application type itself

  • proto (TransportProtocol) – transport protocol the port belongs to, which is what distinguishes e.g. TCP/80 from UDP/80

Return type:

AppType

Returns:

The AppType for port.

Important

self.make accepts a bare int for a port, and the schema field only converts one on the way out (in PortEnumField.pre_process), leaving the schema attribute holding whatever it was handed. A constructed packet therefore reached self.read with an int where a parsed one carries an AppType, and reading .port off it raised AttributeError. Normalising here keeps the two paths agreeing on the type the schema declares.

_decode_next_layer(dict_, ports, length=None, *, packet=None)[source]

Decode next layer protocol.

The method will check if the next layer protocol is supported based on the source and destination port numbers. We will use the lower port number from both ports as the primary key to lookup the next layer.

Parameters:
Return type:

TypeVar(_PT, bound= Data)

Returns:

Current protocol with next layer extracted.

Important

The port is forwarded whether or not it is registered, since ProtocolBase._import_next_layer passes it on as alias and Raw records it as Data_Raw.protocol. Dropping it – as this used to, by falling back to None – anonymised the very case the field is most useful for: a payload on a port we do not decode is then indistinguishable from one on port 22. The lower port is the one carried, for the same reason it is the primary lookup key. SCTP._decode_next_layer and Internet._import_next_layer already behave this way for an unregistered PPID and transport type.

__layer__: Literal['Transport']

Layer of protocol.

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

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

Important

The attribute must be defined and maintained in subclass.