From 3932865e1f36b7ba3a5aa10055724f847417e240 Mon Sep 17 00:00:00 2001 From: Jarry Shaw Date: Sun, 25 Oct 2026 00:41:00 -0400 Subject: [PATCH] docs(protocols): fifth whole-repo pass over link and transport protocols (#1103) - TCP/SCTP option, chunk, parameter and cause registries: document that a non-string value is a (parser, constructor) pair and name the fallback methods, in the registry comments and the register_* meth arguments. - TCP __proto__ comment: HTTP dispatch trial-parses as a last resort; UDP binds the same class, not a proxy. - ARP._make_proto_resolve: FieldValueError also covers an invalid or wrong-version IP address. - L2TP: drop the inaccurate HTTP/3-QUIC analogy for L2F/L2TPv1. - Link._read_protos returns an EtherType, not an internet-layer enum. - TODO grammar in the link and transport package inits. --- docs/source/pcapkit/protocols/link/l2tp.rst | 4 +-- pcapkit/protocols/link/__init__.py | 2 +- pcapkit/protocols/link/arp.py | 4 ++- pcapkit/protocols/link/l2tp.py | 3 +- pcapkit/protocols/link/link.py | 2 +- pcapkit/protocols/transport/__init__.py | 2 +- pcapkit/protocols/transport/sctp.py | 39 +++++++++++++-------- pcapkit/protocols/transport/tcp.py | 33 ++++++++++------- 8 files changed, 53 insertions(+), 36 deletions(-) diff --git a/docs/source/pcapkit/protocols/link/l2tp.rst b/docs/source/pcapkit/protocols/link/l2tp.rst index d90b758eef..35fc86c44b 100644 --- a/docs/source/pcapkit/protocols/link/l2tp.rst +++ b/docs/source/pcapkit/protocols/link/l2tp.rst @@ -53,8 +53,8 @@ an earlier version of L2TP: :rfc:`2661` §3.1 requires ``Ver`` to be 2 and reser the value 1 "to permit detection of L2F packets should they arrive intermixed with L2TP packets". L2F is a separate protocol with its own header, so it is to be implemented as ``L2F``, the canonical name, with ``L2TPv1`` only as an alias in its -:meth:`~pcapkit.protocols.protocol.Protocol.id` -- the relationship HTTP/3 has to -QUIC. See :meth:`HTTPv1.id ` for +:meth:`~pcapkit.protocols.protocol.Protocol.id`. See +:meth:`HTTPv1.id ` for how a version-flavoured alias is spelled: canonical name first, alias second, since callers take element zero as canonical. diff --git a/pcapkit/protocols/link/__init__.py b/pcapkit/protocols/link/__init__.py index 6f579788b1..ecb7a0f604 100644 --- a/pcapkit/protocols/link/__init__.py +++ b/pcapkit/protocols/link/__init__.py @@ -9,7 +9,7 @@ the link layer, with detailed implementation and methods. """ -# TODO: Implements DSL, EAPOL, FDDI, ISDN, NDP, PPP. +# TODO: Implement DSL, EAPOL, FDDI, ISDN, NDP, PPP. # Base Class for Link Layer from pcapkit.protocols.link.link import Link diff --git a/pcapkit/protocols/link/arp.py b/pcapkit/protocols/link/arp.py index e1b54291e5..0a28c32398 100644 --- a/pcapkit/protocols/link/arp.py +++ b/pcapkit/protocols/link/arp.py @@ -442,7 +442,9 @@ def _make_proto_resolve(self, addr: 'IPv4Address | IPv6Address | str | bytes', p packed, and anything else is returned as given. Raises: - FieldValueError: If ``addr`` is a :obj:`bool` (see + FieldValueError: If ``addr`` is packed as an IPv4 or IPv6 address + and is a :obj:`bool`, not a valid address, or not of that + version (see :func:`~pcapkit.corekit.fields.ipaddress.parse_ip_address`). ProtocolError: If ``ptype`` is neither IPv4 nor IPv6 and ``addr`` is a :class:`str` that is not *hex* encoded. diff --git a/pcapkit/protocols/link/l2tp.py b/pcapkit/protocols/link/l2tp.py index c5ced29afc..e18f82b193 100644 --- a/pcapkit/protocols/link/l2tp.py +++ b/pcapkit/protocols/link/l2tp.py @@ -59,8 +59,7 @@ the value 1 "to permit detection of L2F packets should they arrive intermixed with L2TP packets". L2F is a separate protocol with its own header. It is therefore to be implemented as ``L2F``, the canonical name, carrying ``L2TPv1`` -only as an alias in its :meth:`~pcapkit.protocols.protocol.Protocol.id` -- -the same relationship HTTP/3 has to QUIC. See +only as an alias in its :meth:`~pcapkit.protocols.protocol.Protocol.id`. See :meth:`HTTPv1.id ` for how a version-flavoured alias is spelled: canonical name first, alias second, since callers take element zero as canonical. diff --git a/pcapkit/protocols/link/link.py b/pcapkit/protocols/link/link.py index 0a3fd1bb67..4e48983e9f 100644 --- a/pcapkit/protocols/link/link.py +++ b/pcapkit/protocols/link/link.py @@ -206,7 +206,7 @@ def _read_protos(self, size: int) -> 'Enum_EtherType': size: buffer size Returns: - Internet layer protocol enumeration. + EtherType enumeration of the next layer protocol. """ _byte = self._read_unpack(size) diff --git a/pcapkit/protocols/transport/__init__.py b/pcapkit/protocols/transport/__init__.py index 85c9989fa4..bbe6320833 100644 --- a/pcapkit/protocols/transport/__init__.py +++ b/pcapkit/protocols/transport/__init__.py @@ -9,7 +9,7 @@ the transport layer, with detailed implementation and methods. """ -# TODO: Implements DCCP, RSVP. +# TODO: Implement DCCP, RSVP. # Base Class for Transport Layer from pcapkit.protocols.transport.transport import Transport diff --git a/pcapkit/protocols/transport/sctp.py b/pcapkit/protocols/transport/sctp.py index 16e0952c58..f7dcc21963 100644 --- a/pcapkit/protocols/transport/sctp.py +++ b/pcapkit/protocols/transport/sctp.py @@ -471,10 +471,11 @@ class SCTP(Transport[Data_SCTP, Schema_SCTP], ) # type: DefaultDict[int, ModuleDescriptor[ProtocolBase] | Type[ProtocolBase]] #: Chunk type to method mapping, see :meth:`_read_sctp_chunks` and - #: :meth:`_make_sctp_chunks`. Method names are expected to be referred to - #: the class by ``_read_chunk_${name}`` and ``_make_chunk_${name}``, and if - #: such name not found, the value should then be a method that can parse the - #: chunk by itself. + #: :meth:`_make_sctp_chunks`. A :class:`str` value names the methods + #: ``_read_chunk_${name}`` and ``_make_chunk_${name}``, falling back to + #: :meth:`_read_chunk_donone` and :meth:`_make_chunk_donone` when the class + #: has no such method; any other value is a ``(parser, constructor)`` pair + #: of callables. __chunk__ = collections.defaultdict( lambda: 'donone', { @@ -495,10 +496,11 @@ class SCTP(Transport[Data_SCTP, Schema_SCTP], ) # type: DefaultDict[int, str | tuple[ChunkParser, ChunkConstructor]] #: Chunk parameter type to method mapping, see - #: :meth:`_read_sctp_parameters` and :meth:`_make_sctp_parameters`. Method - #: names are expected to be referred to the class by ``_read_param_${name}`` - #: and ``_make_param_${name}``, and if such name not found, the value should - #: then be a method that can parse the parameter by itself. + #: :meth:`_read_sctp_parameters` and :meth:`_make_sctp_parameters`. A + #: :class:`str` value names the methods ``_read_param_${name}`` and + #: ``_make_param_${name}``, falling back to :meth:`_read_param_donone` and + #: :meth:`_make_param_donone` when the class has no such method; any other + #: value is a ``(parser, constructor)`` pair of callables. __parameter__ = collections.defaultdict( lambda: 'donone', { @@ -514,10 +516,11 @@ class SCTP(Transport[Data_SCTP, Schema_SCTP], ) # type: DefaultDict[int, str | tuple[ParameterParser, ParameterConstructor]] #: Error cause code to method mapping, see :meth:`_read_sctp_causes` and - #: :meth:`_make_sctp_causes`. Method names are expected to be referred to - #: the class by ``_read_cause_${name}`` and ``_make_cause_${name}``, and if - #: such name not found, the value should then be a method that can parse the - #: error cause by itself. + #: :meth:`_make_sctp_causes`. A :class:`str` value names the methods + #: ``_read_cause_${name}`` and ``_make_cause_${name}``, falling back to + #: :meth:`_read_cause_donone` and :meth:`_make_cause_donone` when the class + #: has no such method; any other value is a ``(parser, constructor)`` pair + #: of callables. __cause__ = collections.defaultdict( lambda: 'donone', { @@ -756,7 +759,9 @@ def register_chunk(cls, code: 'Enum_Chunk', meth: 'str | tuple[ChunkParser, Chun Args: code: SCTP chunk type. - meth: Method name or callable to parse and/or construct the chunk. + meth: Method name, or a ``(parser, constructor)`` pair of + callables, to parse and construct the chunk; see + :attr:`__chunk__`. Warns: RegistryWarning: If a different entry is already registered for @@ -779,7 +784,9 @@ def register_parameter(cls, code: 'Enum_Parameter', meth: 'str | tuple[Parameter Args: code: SCTP chunk parameter type. - meth: Method name or callable to parse and/or construct the parameter. + meth: Method name, or a ``(parser, constructor)`` pair of + callables, to parse and construct the parameter; see + :attr:`__parameter__`. Warns: RegistryWarning: If a different entry is already registered for @@ -802,7 +809,9 @@ def register_cause(cls, code: 'Enum_CauseCode', meth: 'str | tuple[CauseParser, Args: code: SCTP error cause code. - meth: Method name or callable to parse and/or construct the cause. + meth: Method name, or a ``(parser, constructor)`` pair of + callables, to parse and construct the cause; see + :attr:`__cause__`. Warns: RegistryWarning: If a different entry is already registered for diff --git a/pcapkit/protocols/transport/tcp.py b/pcapkit/protocols/transport/tcp.py index 92b1f82f57..e650d68930 100644 --- a/pcapkit/protocols/transport/tcp.py +++ b/pcapkit/protocols/transport/tcp.py @@ -358,9 +358,10 @@ class TCP(Transport[Data_TCP, Schema_TCP], # ``httpv1.HTTP``, because HTTP/1 and HTTP/2 share these ports on the # wire -- RFC 9113 calls the cleartext form ``http`` and keeps it on # 80 -- so the port cannot decide the version and the payload has to. - # That dispatch is a positive identification (the RFC 9113 §3.4 - # connection preface, then an HTTP/1 start line) rather than a trial - # parse. UDP's table binds the proxy for the same ports. + # That dispatch identifies the payload positively (the RFC 9113 §3.4 + # connection preface, then an HTTP/1 start line) and trial-parses + # only as a last resort. UDP's table binds the same class for the + # same ports. 20: ModuleDescriptor('pcapkit.protocols.application.ftp', 'FTP_DATA'), 21: ModuleDescriptor('pcapkit.protocols.application.ftp', 'FTP'), 80: ModuleDescriptor('pcapkit.protocols.application.http', 'HTTP'), @@ -369,10 +370,11 @@ class TCP(Transport[Data_TCP, Schema_TCP], ) #: Option code to method mapping, see :meth:`_read_tcp_options` and - #: :meth:`_make_tcp_options`. Method names are expected to be referred to - #: the class by ``_read_mode_${name}`` and ``_make_mode_${name}``, and if - #: such name not found, the value should then be a method that can parse the - #: option by itself. + #: :meth:`_make_tcp_options`. A :class:`str` value names the methods + #: ``_read_mode_${name}`` and ``_make_mode_${name}``, falling back to + #: :meth:`_read_mode_donone` and :meth:`_make_mode_donone` when the class + #: has no such method; any other value is a ``(parser, constructor)`` pair + #: of callables. __option__ = collections.defaultdict( lambda: 'donone', { @@ -402,10 +404,11 @@ class TCP(Transport[Data_TCP, Schema_TCP], ) # type: DefaultDict[int, str | tuple[OptionParser, OptionConstructor]] #: Option code to method mapping, see :meth:`_read_mode_mp` and - #: :meth:`_make_mode_mp`. Method names are expected to be referred to the - #: class by ``_read_mptcp_${name}`` and ``_make_mptcp_${name}``, and if such - #: name not found, the value should then be a method that can parse the - #: option by itself. + #: :meth:`_make_mode_mp`. A :class:`str` value names the methods + #: ``_read_mptcp_${name}`` and ``_make_mptcp_${name}``, falling back to + #: :meth:`_read_mptcp_unknown` and :meth:`_make_mptcp_unknown` when the + #: class has no such method; any other value is a ``(parser, constructor)`` + #: pair of callables. __mp_option__ = collections.defaultdict( lambda: 'unknown', { @@ -686,7 +689,9 @@ def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, O Args: code: TCP option code. - meth: Method name or callable to parse and/or construct the option. + meth: Method name, or a ``(parser, constructor)`` pair of + callables, to parse and construct the option; see + :attr:`__option__`. Warns: RegistryWarning: If a different entry is already registered for @@ -709,7 +714,9 @@ def register_mp_option(cls, code: 'Enum_MPTCPOption', meth: 'str | tuple[MPOptio Args: code: MPTCP option code. - meth: Method name or callable to parse and/or construct the option. + meth: Method name, or a ``(parser, constructor)`` pair of + callables, to parse and construct the option; see + :attr:`__mp_option__`. Warns: RegistryWarning: If a different entry is already registered for