diff --git a/pcapkit/protocols/application/ftp.py b/pcapkit/protocols/application/ftp.py index 5ee94f81de..62e605550d 100644 --- a/pcapkit/protocols/application/ftp.py +++ b/pcapkit/protocols/application/ftp.py @@ -42,7 +42,7 @@ class Type(EnumLookup, StrEnum): """FTP packet type. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. diff --git a/pcapkit/protocols/application/http.py b/pcapkit/protocols/application/http.py index a7d337838a..231bdc0ac4 100644 --- a/pcapkit/protocols/application/http.py +++ b/pcapkit/protocols/application/http.py @@ -37,7 +37,7 @@ #: message can begin with it and a prefix compare cannot false-positive on one. #: That is what makes it a positive identification rather than a heuristic, and #: it is why :meth:`HTTP._guess_version` tests it before attempting any parse -#: (#800). +#: (:issue:`800`). _HTTP2_PREFACE = b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n' @@ -60,7 +60,7 @@ class HTTP(Application[_PT, _ST], Generic[_PT, _ST]): #: :attr:`length`; without that, ``ProtocolBase.__init__``'s #: ``self._info.__update__(packet=self.packet.payload)`` slices the payload #: from octet 9 of a buffer whose frame starts at octet 24 and reports the - #: tail of the preface as packet payload. See #800. + #: tail of the preface as packet payload. See :issue:`800`. _preface_length = 0 #: This class is a version dispatcher rather than a protocol with a header of @@ -71,7 +71,7 @@ class HTTP(Application[_PT, _ST], Generic[_PT, _ST]): #: according to that value -- so the set of names that is correct here depends #: on an argument. :obj:`None` therefore opts out of the construction keyword #: check that :meth:`ProtocolBase.__init__ - #: ` performs (#617); the + #: ` performs (:issue:`617`); the #: two versioned classes are checked normally when constructed directly. __keywords__ = None @@ -219,14 +219,14 @@ def _guess_version(self, length: 'int', **kwargs: 'Any') -> 'HTTP': """Identify the HTTP version of the payload, and parse it with that version. The payload is *identified* first and trial-parsed only as a last resort. - Until #800 there was no identification step at all: both versions were + Until :issue:`800` there was no identification step at all: both versions were tried in turn and whichever parser did not object was taken as the answer, which answers "did a parser accept this?" where the question is "what is this?" -- and got both directions wrong. The HTTP/2 connection preface came back ``version='2'`` only because ``httpv2.HTTP`` read its leading ``b'PRI'`` as a 24-bit declared frame length of 5,265,993, and ``b'foo bar baz\\r\\nX: y\\r\\n\\r\\n'`` -- not HTTP at all -- came back - ``version='2'`` the same way. #799 closed the second of those by + ``version='2'`` the same way. :issue:`799` closed the second of those by requiring a frame's declared length to be backed by its buffer, but that left the preface *unidentifiable*: a real HTTP/2 connection opening is refused by both arms and reported as not-HTTP. diff --git a/pcapkit/protocols/application/httpv1.py b/pcapkit/protocols/application/httpv1.py index 5bda637997..00486fc50d 100644 --- a/pcapkit/protocols/application/httpv1.py +++ b/pcapkit/protocols/application/httpv1.py @@ -78,7 +78,7 @@ def _test_start_line(data: 'bytes') -> 'bool': This is a *classification* predicate and parses nothing: it answers "is this HTTP/1?" for :meth:`HTTP._guess_version - `, which until #800 + `, which until :issue:`800` answered that question by trial-parsing every version in the family and keeping whichever one did not object -- so a payload that is not HTTP at all was classified by which parser happened to fail less loudly. @@ -142,7 +142,7 @@ class Type(EnumLookup, StrEnum): """HTTP packet type. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. diff --git a/pcapkit/protocols/application/httpv2.py b/pcapkit/protocols/application/httpv2.py index 8175680ff0..4206a3ae39 100644 --- a/pcapkit/protocols/application/httpv2.py +++ b/pcapkit/protocols/application/httpv2.py @@ -223,7 +223,7 @@ def unpack(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_HTTP' fixed ``stream`` and ``error`` fields alone consume eight); that residual is why :meth:`HTTP._guess_version ` still - suppresses :exc:`struct.error` on its last arm. See #799. + suppresses :exc:`struct.error` on its last arm. See :issue:`799`. ``length`` is resolved against :func:`len` only for *this* method's own check, and the *original* argument -- ``None`` diff --git a/pcapkit/protocols/application/ngap.py b/pcapkit/protocols/application/ngap.py index 7b7d704eac..876db65c05 100644 --- a/pcapkit/protocols/application/ngap.py +++ b/pcapkit/protocols/application/ngap.py @@ -201,7 +201,7 @@ class PDUKind(EnumLookup, StrEnum): |pycrate|_ resolves by value. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. @@ -223,11 +223,11 @@ class Criticality(EnumLookup, IntEnum): by |pycrate|_ through the standard member map. The values are the ``ENUMERATED`` indices, which is what goes on the wire. - Carries no ``get`` of its own. GitHub issue #877 re-parented this class onto + Carries no ``get`` of its own. GitHub issue :issue:`877` re-parented this class onto :class:`~pcapkit.corekit.enum.EnumLookup` and kept a delegating override for one reason only: it converted the base's name-miss :exc:`KeyError` into a :exc:`ValueError`, so that an unknown *name* and an unknown *value* reported - identically. GitHub issue #923's ruling retired that conversion -- a name + identically. GitHub issue :issue:`923`'s ruling retired that conversion -- a name miss is :exc:`KeyError`-shaped, exactly as ``E['nosuch']`` is on a stdlib :class:`~enum.Enum` -- which left the override a pure pass-through, so it went with it. diff --git a/pcapkit/protocols/data/internet/hip.py b/pcapkit/protocols/data/internet/hip.py index 96ae6a5fe3..abfa08fd42 100644 --- a/pcapkit/protocols/data/internet/hip.py +++ b/pcapkit/protocols/data/internet/hip.py @@ -209,7 +209,7 @@ class PuzzleParameter(Parameter): #: exact width of ``Random #I``. Declared rather than recomputed from #: :meth:`int.bit_length`, which cannot see a leading zero octet: without it #: a parameter read with ``Length = 12`` re-serialised as ``Length = 5``. - #: See #653. + #: See :issue:`653`. rhash_len: 'int' if TYPE_CHECKING: @@ -227,7 +227,7 @@ class SolutionParameter(Parameter): #: Carried verbatim rather than interpreted, so that re-serialising a parsed #: parameter reproduces the octet it arrived with. It used to be read as a #: ``PUZZLE`` ``Lifetime``, which only :rfc:`7401#section-5.2.4` defines, and - #: the conformant ``0x00`` then could not be re-serialised at all. See #654. + #: the conformant ``0x00`` then could not be re-serialised at all. See :issue:`654`. reserved: 'int' #: Solution data. opaque: 'bytes' @@ -241,7 +241,7 @@ class SolutionParameter(Parameter): #: width of both fields. Declared rather than recomputed from #: :meth:`int.bit_length`, which cannot see a leading zero octet: without it a #: parameter read with ``Length = 20`` re-serialised as ``Length = 6``. - #: See #653. + #: See :issue:`653`. rhash_len: 'int' if TYPE_CHECKING: diff --git a/pcapkit/protocols/link/arp.py b/pcapkit/protocols/link/arp.py index 50f5da67d9..21994824cf 100644 --- a/pcapkit/protocols/link/arp.py +++ b/pcapkit/protocols/link/arp.py @@ -406,7 +406,7 @@ def _make_proto_resolve(self, addr: 'IPv4Address | IPv6Address | str | bytes', p directly, because :obj:`bool` is an :class:`int` subclass that either constructor accepts without complaint. Before this, ``addr=True`` packed as ``00000001`` (IPv4) or ``::1`` (IPv6) with - no exception and no warning at all (c.f. #508, #540). + no exception and no warning at all (c.f. :issue:`508`, :issue:`540`). The description below uses :attr:`self.__class__.__name__ ` rather than :attr:`self.alias diff --git a/pcapkit/protocols/link/l2tp.py b/pcapkit/protocols/link/l2tp.py index 388f36310a..84ff18ed11 100644 --- a/pcapkit/protocols/link/l2tp.py +++ b/pcapkit/protocols/link/l2tp.py @@ -42,7 +42,7 @@ different framing decision. It also means v3 is the first member of this family to have a real :meth:`~pcapkit.protocols.protocol.Protocol.__index__`. -GitHub issue #548 proposed closing that gap by binding +GitHub issue :issue:`548` proposed closing that gap by binding :class:`~pcapkit.protocols.link.l2tpv2.L2TPv2` at 115 instead, which does not work and is worth recording so it is not proposed again. Over IP the v3 session header is, in :rfc:`3931` ยง4.1.1's own words, *"free of any restrictions imposed diff --git a/pcapkit/protocols/link/l2tpv2.py b/pcapkit/protocols/link/l2tpv2.py index ff05dea418..e4dd608ce3 100644 --- a/pcapkit/protocols/link/l2tpv2.py +++ b/pcapkit/protocols/link/l2tpv2.py @@ -98,7 +98,7 @@ class L2TPv2(L2TP[Data_L2TP, Schema_L2TP], references :rfc:`3931`, i.e. **L2TPv3**, whose session and control message headers are a different shape -- so the binding waits on an ``L2TPv3`` class rather than on this one. Binding *this* class there was - proposed in GitHub issue #548 and does not work: over IP the v3 session + proposed in GitHub issue :issue:`548` and does not work: over IP the v3 session header carries no version nibble at all, so this class cannot recognise that the datagram is not its own. See :class:`~pcapkit.protocols.link.l2tp.L2TP` for the measurement. diff --git a/pcapkit/protocols/link/ospf.py b/pcapkit/protocols/link/ospf.py index 695957a31f..18f5531bb6 100644 --- a/pcapkit/protocols/link/ospf.py +++ b/pcapkit/protocols/link/ospf.py @@ -336,8 +336,8 @@ def _make_id_numbers(self, id: 'IPv4Address | str | bytes | bytearray') -> 'byte straight from its own arguments), so the only caller is a unit test. It is routed through :func:`parse_ip_address` anyway, so that it does not resurface the defect the moment a caller - reaches it -- the same kind of omission is how #469's single-site - fix survived to become #491 and then #508 (c.f. #540). + reaches it -- the same kind of omission is how :issue:`469`'s single-site + fix survived to become :issue:`491` and then :issue:`508` (c.f. :issue:`540`). The description below uses :attr:`self.__class__.__name__ ` rather than :attr:`self.alias diff --git a/pcapkit/protocols/misc/pcapng.py b/pcapkit/protocols/misc/pcapng.py index 1f4033c540..cb34659eea 100644 --- a/pcapkit/protocols/misc/pcapng.py +++ b/pcapkit/protocols/misc/pcapng.py @@ -250,7 +250,7 @@ class PacketDirection(EnumLookup, enum.IntEnum): """Packet direction for ``epb_flags`` options. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. @@ -268,7 +268,7 @@ class PacketReception(EnumLookup, enum.IntEnum): """Reception type for ``epb_flags`` options. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. @@ -314,7 +314,7 @@ class WireGuardKeyLabel(EnumLookup, StrEnum): """WireGuard key log label. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub - issue #877's ruling that every non-registry enumeration shares that + issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract -- pure re-parenting, since this class defines neither ``get`` nor ``_missing_`` of its own to reconcile with the base. @@ -721,7 +721,7 @@ def length(self) -> 'int': :attr:`ProtocolBase.length ` does not distinguish them, but a PCAP-NG block carries a trailer. :attr:`self.packet ` is overridden accordingly; see there and - #646. + :issue:`646`. """ return self._info.length @@ -759,7 +759,7 @@ def packet(self) -> 'Data_Packet': packet block reported ``packet == b''`` while ``captured_len`` declared hundreds of octets, and dumping such a block through :class:`~pcapkit.dumpkit.pcap.PCAPIO` wrote a record header promising - octets it then did not write. See #646. + octets it then did not write. See :issue:`646`. The payload is therefore the block schema's :attr:`~pcapkit.protocols.schema.schema.Schema.__payload__` field, which @@ -1308,11 +1308,9 @@ def _check_block_floor(self, length: 'Optional[int]') -> 'None': of nothing ``__length__`` is negative -- which :func:`~pcapkit.protocols.schema.misc.pcapng.pcapng_block_selector` hands to :class:`~pcapkit.corekit.fields.misc.SchemaField`, where - :meth:`io.RawIOBase.read` raises the bare ``ValueError`` of `#678 - `__. + :meth:`io.RawIOBase.read` raises the bare ``ValueError`` of :issue:`678`. - Reporting the end of the stream instead is what keeps the `#431 - `__ accommodation: + Reporting the end of the stream instead is what keeps the :issue:`431` accommodation: :exc:`~pcapkit.utilities.exceptions.StreamEOFError` is an :exc:`EOFError`, which :meth:`Extractor.record_frames ` already catches @@ -1387,7 +1385,7 @@ def _get_local_timezone() -> 'timezone': Not used when reconstructing a block timestamp, and must not be: a PCAP-NG timestamp is an offset from the UNIX epoch, so mixing the *reading* host's zone into it makes one file parse to different - instants on different machines (see #361). + instants on different machines (see :issue:`361`). :meth:`self._get_timezone <_get_timezone>` returns :attr:`datetime.timezone.utc` instead when the capture names no ``if_tzone``. @@ -1607,7 +1605,7 @@ def _make_timestamp(self, timestamp: 'Optional[float | Decimal | dt_type | int]' used to promise a "timezone conversion" that the code never performed, which made it look as though the read side's timezone shift had a counterpart here (it did not, so a read followed by a - write drifted by the host's UTC offset -- see #361). + write drifted by the host's UTC offset -- see :issue:`361`). """ with localcontext(prec=64): diff --git a/pcapkit/protocols/schema/application/httpv2.py b/pcapkit/protocols/schema/application/httpv2.py index a24ee6f8b4..f0358c3043 100644 --- a/pcapkit/protocols/schema/application/httpv2.py +++ b/pcapkit/protocols/schema/application/httpv2.py @@ -128,12 +128,12 @@ class Flags(EnumLookup, enum.IntFlag): """Flags enumeration for HTTP/2 frames. Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per - GitHub issue #877's ruling that every non-registry enumeration + GitHub issue :issue:`877`'s ruling that every non-registry enumeration shares that lookup contract. The six concrete per-frame subclasses below each declare ``class Flags(FrameType.Flags):`` with no base list of their own, so they inherit :class:`EnumLookup` transitively through this one re-parent rather than needing it repeated -- - verified at runtime for GitHub issue #877 (see the session report), + verified at runtime for GitHub issue :issue:`877` (see the session report), not merely assumed from the MRO rules. """ diff --git a/pcapkit/protocols/schema/internet/hip.py b/pcapkit/protocols/schema/internet/hip.py index 406a0f72d8..5e52a2fe1e 100644 --- a/pcapkit/protocols/schema/internet/hip.py +++ b/pcapkit/protocols/schema/internet/hip.py @@ -332,7 +332,7 @@ def encrypted_data_len(pkt: 'dict[str, Any]') -> 'int': ciphertext by four. That was recorded as the second half of ``hip-parameter/ENCRYPTED`` in the round-trip suite's expected-failure table, and left alone -- because while the padding rule was also four - octets out (#651), the two errors cancelled at some residues of ``Length`` + octets out (:issue:`651`), the two errors cancelled at some residues of ``Length`` and not others. Measured by packing through the public maker at every residue, the old record total agreed with :rfc:`7401` Section 5.2.1 at ``Length % 8`` in ``{0, 5, 6, 7}`` and was eight octets over at @@ -388,7 +388,7 @@ def parameter_total_len(length: 'int') -> 'int': Padding", and it is the **total** -- contents plus the four octets of ``Type`` and ``Length`` plus padding -- that must land on a multiple of eight. Aligning the contents alone instead, as every padding site in this - module and in :mod:`pcapkit.protocols.internet.hip` did before #651, puts + module and in :mod:`pcapkit.protocols.internet.hip` did before :issue:`651`, puts every parameter at ``4 (mod 8)`` for every possible ``Length``: never a multiple of eight and never the length the RFC gives. It is not even a consistent offset, because the two formulas disagree in both directions -- @@ -464,7 +464,7 @@ def parameter_padding_len(pkt: 'dict[str, Any]') -> 'int': #: its own. So by the time ``padding`` is evaluated -- after the list, since #: fields are packed in declaration order -- ``pkt['len']`` is the *last #: locator's* ``len``, not the parameter's. That is 4 for any IPv6 locator -#: whatever the locator count, which is how the pre-#679 padding expression came +#: whatever the locator count, which is how the pre-:issue:`679` padding expression came #: to append exactly four octets to every ``LOCATOR_SET`` regardless of size. #: #: The shadowing is specific to the packing path. :meth:`Schema.unpack @@ -572,7 +572,7 @@ class R1CounterParameter(Parameter, code=[Enum_Parameter.R1_Counter, layout to code 128 (``R1_Counter``) and code 129 (``R1_COUNTER``) -- one parameter under two numbers, the difference being HIP's own C-bit rather than an unrelated code -- and the field list below is that layout - exactly, since #672 widened :attr:`counter` to eight octets. + exactly, since :issue:`672` widened :attr:`counter` to eight octets. :attr:`~pcapkit.protocols.internet.hip.HIP.__parameter__` already carries two hand-written entries -- not a name-normalisation rule; ``R1_Counter`` and ``R1_COUNTER`` differ only in case, and each needed its own line -- @@ -582,7 +582,7 @@ class R1CounterParameter(Parameter, code=[Enum_Parameter.R1_Counter, parse path by :class:`~pcapkit.corekit.fields.collections.OptionField` -- that fell back to :class:`UnassignedParameter` for 128, since a single-code ``code=`` registered 129 alone and left 128 unclaimed. - See #690. + See :issue:`690`. """ @@ -598,7 +598,7 @@ class R1CounterParameter(Parameter, code=[Enum_Parameter.R1_Counter, #: version under which four octets is right, and both codes that reach this #: class -- ``R1_Counter`` (128, HIPv1) and ``R1_COUNTER`` (129) -- are #: affected. It was a :class:`~pcapkit.corekit.fields.numbers.UInt32Field` - #: until #672: the parameter declared the correct ``len=12`` and packed 12 + #: until :issue:`672`: the parameter declared the correct ``len=12`` and packed 12 #: octets in total where :rfc:`7401` Section 5.2.1's arithmetic makes the #: record 16, leaving it four short at ``4 (mod 8)``. Measured before the #: fix, at ``counter=1``: ``00 80 00 0c 00 00 00 00 00 00 00 01`` for code @@ -649,7 +649,7 @@ class LocatorSetParameter(Parameter, code=Enum_Parameter.LOCATOR_SET): #: correct on the unpacking path for the reason :data:`LOCATOR_SET_LEN` #: gives -- nothing has shadowed ``len`` yet when this field is resolved, #: since ``type`` and ``len`` are the only fields ahead of it. What was - #: wrong until #679 is the *quantity* it was being handed: + #: wrong until :issue:`679` is the *quantity* it was being handed: #: :meth:`~pcapkit.protocols.internet.hip.HIP._make_param_locator_set` wrote #: ``Length`` as ``sum(Locator.len)``, in the 4-octet units #: :rfc:`8046#section-4` gives ``Locator Length``, where :rfc:`7401` @@ -681,7 +681,7 @@ class LocatorSetParameter(Parameter, code=Enum_Parameter.LOCATOR_SET): #: parameter's packet context while they pack, and their own ``len`` #: overwrites it before ``padding`` is reached. #: - #: This is the site #651 deliberately left alone, and its fix + #: This is the site :issue:`651` deliberately left alone, and its fix #: documented as an exclusion, because two defects in this parameter #: cancelled at the shape its tests sampled and correcting either alone #: made the wire output worse. @@ -751,7 +751,7 @@ class SolutionParameter(Parameter, code=Enum_Parameter.SOLUTION): #: (:rfc:`7401#section-5.2.5`, and :rfc:`5201#section-5.2.5` identically). #: This octet is *not* a lifetime: only ``PUZZLE`` carries one, at the same #: offset, and only :rfc:`7401#section-5.2.4` defines the ``2^(value - 32)`` - #: seconds encoding that goes in it. See #654. + #: seconds encoding that goes in it. See :issue:`654`. reserved: 'int' = UInt8Field() #: Opaque data. opaque: 'bytes' = BytesField(length=2) @@ -925,7 +925,7 @@ def pre_unpack(cls, packet: 'dict[str, Any]') -> 'None': ``packet.update(self.__dict__)`` carries it in here -- that value is trusted over the ``HIP_CIPHER`` sibling lookup below, which a parameter packed on its own has no ``options`` list for. See - #556. + :issue:`556`. """ if 'cipher' in packet: @@ -984,7 +984,7 @@ def post_process(self, packet: 'dict[str, Any]') -> 'Schema': #: :meth:`HIP._make_param_encrypted #: ` before #: packing -- so it is documented here rather than accepted by - #: ``__init__``. See #556. + #: ``__init__``. See :issue:`556`. cipher: 'Enum_Cipher' def __init__(self, type: 'Enum_Parameter', len: 'int', diff --git a/pcapkit/protocols/schema/internet/hopopt.py b/pcapkit/protocols/schema/internet/hopopt.py index d13cfe783e..7d5753fc30 100644 --- a/pcapkit/protocols/schema/internet/hopopt.py +++ b/pcapkit/protocols/schema/internet/hopopt.py @@ -184,7 +184,7 @@ def smf_dpd_data_selector(pkt: 'dict[str, Any]') -> 'Field': themselves. Sizing the field at ``Opt Data Len`` handed them an area two octets short of the option they read, which :class:`~pcapkit.corekit.fields.collections.OptionField` then mis-counted - against the option area -- c.f. #431. + against the option area -- c.f. :issue:`431`. """ mode = Enum_SMFDPDMode.get(pkt['test']['mode']) diff --git a/pcapkit/protocols/schema/internet/ipv4.py b/pcapkit/protocols/schema/internet/ipv4.py index 393db80bb7..59af1f6500 100644 --- a/pcapkit/protocols/schema/internet/ipv4.py +++ b/pcapkit/protocols/schema/internet/ipv4.py @@ -125,7 +125,7 @@ def quick_start_option_length(schema: 'Type[QSOption]') -> 'int': :class:`QSOption` is an :class:`~pcapkit.protocols.schema.schema.EnumSchema`, so a caller may register a further function code with a schema of its own width -- and a number written here has to be kept in step by hand with every - field the suboptions declare, which is precisely how #552 arose: the length + field the suboptions declare, which is precisely how :issue:`552` arose: the length was ``5``, the width of a Quick-Start Request's ``ttl`` and ``nonce`` alone, with the ``type``, ``length`` and ``flags`` octets in front of them unaccounted for. @@ -210,7 +210,7 @@ def quick_start_data_selector(pkt: 'dict[str, Any]') -> 'Field': octets to be read as a further, fabricated option -- which made the enclosing datagram fail with ``ProtocolError: IPv4: invalid format``. That is silent corruption on the way to a misleading failure, and it was logged - in review twice before #552 filed it. + in review twice before :issue:`552` filed it. """ func = Enum_QSFunction.get(pkt['flags']['func']) @@ -368,9 +368,9 @@ def post_process(self, packet: 'dict[str, Any]') -> 'Schema': of, so nothing downstream can question it. Measured before this fix: ``ts_data=[True, 5]`` packed as ``0000000100000005`` and reported ``IPv4Address('0.0.0.1')`` with no exception and no - warning. This was the fifth site of that defect -- #469, #491, - #508 and #540 are the first four -- and the reason it is the fifth - is that each of those fixed the sites it could see. See #552. + warning. This was the fifth site of that defect -- :issue:`469`, :issue:`491`, + :issue:`508` and :issue:`540` are the first four -- and the reason it is the fifth + is that each of those fixed the sites it could see. See :issue:`552`. """ ts_flag = Enum_TSFlag.get(self.flags['flag']) @@ -516,7 +516,7 @@ class SIDOption(Option, code=Enum_OptionNumber.SID): #: ``packet length < 0: -2`` the library warned about -- and re-emitted it two #: octets too wide on the way out, against the ``length=4`` that #: :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_sid` had always - #: written. See #534. + #: written. See :issue:`534`. sid: 'int' = UInt16Field() if TYPE_CHECKING: @@ -678,7 +678,7 @@ class QuickStartReportOption(QSOption, code=Enum_QSFunction.Report_of_Approved_R #: ``packet length < 0: -1`` and then died with a bare ``struct.error: bad #: char in struct format``, the unconsumed octet having been read as another #: option. Declared as padding rather than as data because :rfc:`4782` gives - #: it no meaning and no caller should be setting it. See #552. + #: it no meaning and no caller should be setting it. See :issue:`552`. reserved: 'bytes' = PaddingField(length=1) #: QS nonce. nonce: 'QSNonce' = BitField(length=4, namespace={ diff --git a/pcapkit/protocols/schema/internet/ipv6_opts.py b/pcapkit/protocols/schema/internet/ipv6_opts.py index 73e3939164..bdf086f708 100644 --- a/pcapkit/protocols/schema/internet/ipv6_opts.py +++ b/pcapkit/protocols/schema/internet/ipv6_opts.py @@ -184,7 +184,7 @@ def smf_dpd_data_selector(pkt: 'dict[str, Any]') -> 'Field': themselves. Sizing the field at ``Opt Data Len`` handed them an area two octets short of the option they read, which :class:`~pcapkit.corekit.fields.collections.OptionField` then mis-counted - against the option area -- c.f. #431. + against the option area -- c.f. :issue:`431`. """ mode = Enum_SMFDPDMode.get(pkt['test']['mode']) diff --git a/pcapkit/protocols/schema/internet/ipv6_route.py b/pcapkit/protocols/schema/internet/ipv6_route.py index 83ac62b7fa..770392e7f9 100644 --- a/pcapkit/protocols/schema/internet/ipv6_route.py +++ b/pcapkit/protocols/schema/internet/ipv6_route.py @@ -57,7 +57,7 @@ def ipv6_route_data_length(hdr_ext_len: 'int') -> 'int': that arithmetic is done on the read side; see :meth:`~pcapkit.protocols.internet.ipv6_route.IPv6_Route._make_hdr_ext_len` for its inverse on the write side. Do NOT drop the ``4 +``: that turns - the field back into raw octets and is the exact defect #487 fixed. + the field back into raw octets and is the exact defect :issue:`487` fixed. Args: hdr_ext_len: raw ``Hdr Ext Len`` field value, as read off the wire. @@ -81,10 +81,10 @@ def ipv6_route_header_length(hdr_ext_len: 'int') -> 'int': :mod:`pcapkit.protocols.internet.ipv6_route` reports back as the parsed route data's own ``.length``, which :meth:`~pcapkit.protocols.internet. ipv6_route.IPv6_Route.read` then subtracts from the outer packet length - to find the next layer's length. #487 unified the write side + to find the next layer's length. :issue:`487` unified the write side (:meth:`~pcapkit.protocols.internet.ipv6_route.IPv6_Route._make_hdr_ext_len`) into one helper; this is the matching read-side helper for the total - header length, finishing that half of #487. + header length, finishing that half of :issue:`487`. Args: hdr_ext_len: raw ``Hdr Ext Len`` field value, as read off the wire. @@ -192,7 +192,7 @@ class RPL(RoutingType, code=Enum_Routing.RPL_Source_Route_Header): #: NOTE: :rfc:`6554#section-3` gives ``CmprI`` and ``CmprE`` as *"4-bit #: unsigned integer"*, i.e. the high and low nibble of a single octet, so #: they cannot be two :class:`~pcapkit.corekit.fields.numbers.UInt8Field` - #: as they were before #564. Together with :attr:`pad` below -- ``Pad`` + #: as they were before :issue:`564`. Together with :attr:`pad` below -- ``Pad`` #: (4 bits) plus ``Reserved`` (20 bits) -- this is the one 32-bit word the #: diagram in :rfc:`6554#section-3` draws, and the same word #: :meth:`IPv6_Route._read_data_type_rpl diff --git a/pcapkit/protocols/schema/misc/pcap/frame.py b/pcapkit/protocols/schema/misc/pcap/frame.py index ffd0a83810..688935cc8c 100644 --- a/pcapkit/protocols/schema/misc/pcap/frame.py +++ b/pcapkit/protocols/schema/misc/pcap/frame.py @@ -33,7 +33,7 @@ def byteorder_callback(field: 'Field', packet: 'dict[str, Any]') -> 'None': :data:`sys.byteorder` is for a schema packed or unpacked on its own, with no global header to ask -- which also means a *misspelled* key looks exactly like an absent one and reports nothing. That is what hid GitHub - issue #605: ``unpack`` wrote ``bytesorder``, so every field here was read + issue :issue:`605`: ``unpack`` wrote ``bytesorder``, so every field here was read in the host's order rather than the file's, which is right by coincidence on a little-endian capture and byte-swapped on a big-endian one. See :file:`tests/protocols/misc/pcap/test_frame_endian_runtime.py` for the diff --git a/pcapkit/protocols/schema/misc/pcapng.py b/pcapkit/protocols/schema/misc/pcapng.py index a40d1d1937..8bce310fff 100644 --- a/pcapkit/protocols/schema/misc/pcapng.py +++ b/pcapkit/protocols/schema/misc/pcapng.py @@ -231,8 +231,7 @@ def nonnegative(length: 'Callable[[dict[str, Any]], int]') -> 'Callable[[dict[st Neither is one of :mod:`pcapkit.utilities.exceptions`, so a caller cannot tell either from a bug in its own code, and neither is an :exc:`EOFError`, so neither is caught by the frame loop -- one malformed block therefore cost the - whole extraction. See `#678 - `__. + whole extraction. See :issue:`678`. Two shapes reach here. A Block Total Length below the block's own fixed-field floor -- 28 octets for a Section Header Block, 20 for an Interface @@ -249,8 +248,7 @@ def nonnegative(length: 'Callable[[dict[str, Any]], int]') -> 'Callable[[dict[st :func:`bounded_area` already made, for the reason their docstrings give: a block read has no catch point above :meth:`FieldBase.unpack `, so one refusal aborts the - whole extraction rather than one block, which is what the `#431 - `__ accommodation exists + whole extraction rather than one block, which is what the :issue:`431` accommodation exists to prevent. The end of the file is the one case that is *not* a clamp, since there no block is being read at all -- see :meth:`PCAPNG._check_block_floor `, which reports it @@ -315,13 +313,12 @@ def bounded_option(length: 'Callable[[dict[str, Any]], int]') -> 'Callable[[dict padding without limit: 2,000 Enhanced Packet Blocks in 80,048 octets, each with one option declaring 65,535 against none present, produced 131,070,000 octets of zero padding, an amplification of 1,637x linear in the block - count. See `#594 `__, - and `#573 `__ for the + count. See :issue:`594`, and :issue:`573` for the 32-bit band the field layer's own budget already covers. The bound has to come from this layer because the field layer cannot see it. What distinguishes the crafted case from the legitimate one is not the - shortfall's size -- both are inside a 16-bit length, which is why #554's + shortfall's size -- both are inside a 16-bit length, which is why :issue:`554`'s ``len(buffer) < length`` rejection was declined -- but whether the option is inconsistent with the framing the block itself declares. Block Total Length is authoritative and cross-checked against its own trailing copy, so @@ -331,8 +328,7 @@ def bounded_option(length: 'Callable[[dict[str, Any]], int]') -> 'Callable[[dict capture says so through ``captured_len`` instead, and leaves its options whole, so it never trips this. - Clamping rather than refusing is what keeps the `#431 - `__ accommodation: a + Clamping rather than refusing is what keeps the :issue:`431` accommodation: a block read has no catch point above :meth:`FieldBase.unpack `, so one refusal aborts the whole extraction rather than one block, and a truncated capture would stop @@ -412,8 +408,7 @@ def bounded_area(length: 'Callable[[dict[str, Any]], int]') -> 'Callable[[dict[s Secrets -- are deliberately left unclamped *against the block* here, since each computes its span with a different offset and the equality above has to be re-established per block rather than assumed. They do go - through :func:`nonnegative`, which is the part of `#678 - `__ that stops a + through :func:`nonnegative`, which is the part of :issue:`678` that stops a declared length reaching a read at all; the per-block equality is still open. @@ -469,8 +464,7 @@ def pcapng_block_selector(packet: 'dict[str, Any]') -> 'Field': :meth:`FieldBase.unpack ` zero-pads a short read rather than refusing it. A tail of one, two or three octets therefore arrived here negative and - :meth:`io.RawIOBase.read` raised a bare ``ValueError``, which is `#678 - `__. The floor is a + :meth:`io.RawIOBase.read` raised a bare ``ValueError``, which is :issue:`678`. The floor is a backstop: :meth:`PCAPNG._check_block_floor ` reports that tail as end-of-stream before it gets here, and on the packing path @@ -570,13 +564,13 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Enum_ option code in this namespace (or in the shared ``opt`` namespace), or an unregistered member of the same registry, carrying the code itself, when neither declares one. See GitHub - issue #575. + issue :issue:`575`. Notes: - Until GitHub issue #860, + Until GitHub issue :issue:`860`, :meth:`~pcapkit.const.pcapng.option_type.OptionType.get` minted a fresh member -- via :func:`aenum.extend_enum` -- for any code - neither namespace's row covers, unconditionally on a miss. #860 + neither namespace's row covers, unconditionally on a miss. :issue:`860` converted that miss path to :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` instead, so calling it now would no longer grow the registry @@ -744,7 +738,7 @@ def __init_subclass__(cls, /, code: 'Optional[Enum_OptionType | Iterable[Enum_Op own fourth parameter ``namespace``, and before Python 3.11 that parameter is positional-or-keyword rather than positional-only -- so a class keyword literally called ``namespace`` bound it twice. - See GitHub issue #439. + See GitHub issue :issue:`439`. *args: Arbitrary positional arguments. **kwargs: Arbitrary keyword arguments. @@ -804,7 +798,7 @@ def register(code: 'Enum_OptionType', cls: 'Type[Option]', ns: 'Optional[str]' = every other registry in the package does -- the lookup that follows cannot tell a deliberate replacement from an accidental one, so an unreported overwrite is a parser silently swapped out for another. See - `#675 `__ for the + :issue:`675` for the guard ``register_protocol`` added first, which this one now matches. The guard is identity-based: it fires only when the incumbent differs @@ -814,7 +808,7 @@ def register(code: 'Enum_OptionType', cls: 'Type[Option]', ns: 'Optional[str]' = :meth:`__init_subclass__` honest: it loops over a ``code`` list with no deduplication, so a repeated or aliased entry reaches this method twice with the same class, and the second call now finds itself already the - incumbent. GitHub issue #718 corrected the previous presence-only + incumbent. GitHub issue :issue:`718` corrected the previous presence-only guard, which read every such repeat as a caller mistake whether or not the value had actually changed -- the same fix the sibling :meth:`register` methods on @@ -1813,8 +1807,7 @@ def post_process(self, packet: 'dict[str, Any]') -> 'Self': raised, for the reason :func:`nonnegative` gives: a bare :exc:`struct.error` is neither one of :mod:`pcapkit.utilities.exceptions` nor an :exc:`EOFError`, so it - aborted the whole extraction rather than this one entry. See `#678 - `__. + aborted the whole extraction rather than this one entry. See :issue:`678`. A line of nothing but NUL octets is the block's own 32-bit padding and ends the entry. ``bytes.strip()`` takes only ASCII whitespace, @@ -1858,15 +1851,13 @@ def post_process(self, packet: 'dict[str, Any]') -> 'Self': is worse, since ``struct.pack('`__. The entry is + field was read. See :issue:`723`. The entry is now walked once, end to end: a length-prefixed field's bytes are never inspected for structure, only counted out by the prefix that names them, and a blank line -- found by *reading*, not by splitting -- is what starts the next entry. The one-octet terminator that must follow a binary field's value, and the warning - when it is missing, are unchanged from `#704 - `__; walking the + when it is missing, are unchanged from :issue:`704`; walking the buffer whole rather than pre-slicing it also retires that fix's newline restoration, which existed only to undo what the slicing itself had taken away. @@ -1891,8 +1882,7 @@ def post_process(self, packet: 'dict[str, Any]') -> 'Self': :meth:`bytes.strip` still will not take the NUL octets off since they are not ASCII whitespace. The padding then went out as part of the field's value with nothing to flag it, silently, however - small -- see `#794 - `__. + small -- see :issue:`794`. :meth:`~io.BytesIO.readline` returns a line without its own trailing newline only at end of stream, so a terminator-less line is necessarily the buffer's last one; a binary field's diff --git a/pcapkit/protocols/schema/schema.py b/pcapkit/protocols/schema/schema.py index e2e79640bb..481b81a73b 100644 --- a/pcapkit/protocols/schema/schema.py +++ b/pcapkit/protocols/schema/schema.py @@ -273,7 +273,7 @@ def __prepare__(cls, name: 'str', bases: 'tuple[type, ...]', /, **kwds: 'Any') - #: positional-only, ``def __new__(mcls, name, bases, namespace, /, #: **kwargs)``), so a class keyword spelled the same as any of them binds #: that parameter twice: ``TypeError: ABCMeta.__new__() got multiple - #: values for argument '...'``. That is GitHub issue #439's root cause -- + #: values for argument '...'``. That is GitHub issue :issue:`439`'s root cause -- #: ``namespace`` collided this way, which is why #: :mod:`pcapkit.protocols.schema.misc.pcapng`'s ``Option`` subclasses #: spell it ``ns=`` instead. @@ -401,7 +401,7 @@ def __init_subclass__(cls, /, *args: 'Any', **kwargs: 'Any') -> 'None': :func:`schema_final` finalises carries a generated ``__init__`` built from the :attr:`__fields__` that were declared at that moment, so a subclass adding a field afterwards inherits a constructor that cannot - set it -- which is #422's failure shape, reached by a different route. + set it -- which is :issue:`422`'s failure shape, reached by a different route. This turns that promise into a rule the interpreter keeps. Args: @@ -1064,8 +1064,8 @@ class _EnumRegistry(collections.defaultdict): This is the schema-layer instance of the defect :meth:`ProtocolBase.\ _lookup_registry ` - fixed for the protocol-layer ``__proto__`` family in GitHub issues #421 and - #425; see GitHub issue #555. The fallback itself is deliberate -- it + fixed for the protocol-layer ``__proto__`` family in GitHub issues :issue:`421` and + :issue:`425`; see GitHub issue :issue:`555`. The fallback itself is deliberate -- it is how an unknown option, chunk or block falls back to its ``Unknown*``/``Unassigned*`` schema -- so this subclass keeps returning it, it just stops recording it. @@ -1293,7 +1293,7 @@ def register(cls, code: '_ET', schema: 'Type[Self]') -> 'None': ` applies, even though ``code`` here -- unlike ``register_protocol``'s key -- is supplied by the caller and independent of ``schema``. GitHub - issue #718 corrected the previous presence-only guard: a repeat + issue :issue:`718` corrected the previous presence-only guard: a repeat call that names the exact same schema object is a caller replaying a registration, not a mistake, so it is now a silent no-op. @@ -1304,8 +1304,8 @@ def register(cls, code: '_ET', schema: 'Type[Self]') -> 'None': looked up, so parsing a single packet carrying an unknown code would have made the next legitimate registration for that code warn about an entry no caller ever asked for -- the defect fixed for this layer - in #555, and for the parser-layer ``__proto__`` family in #421 and - #425. That fix is what makes this guard safe to add. + in :issue:`555`, and for the parser-layer ``__proto__`` family in :issue:`421` and + :issue:`425`. That fix is what makes this guard safe to add. :class:`pcapkit.protocols.schema.misc.pcapng.Option` overrides this method with a namespaced registry of its own and does not delegate diff --git a/pcapkit/protocols/schema/transport/sctp.py b/pcapkit/protocols/schema/transport/sctp.py index 31736e4292..5e8a4ef864 100644 --- a/pcapkit/protocols/schema/transport/sctp.py +++ b/pcapkit/protocols/schema/transport/sctp.py @@ -220,7 +220,7 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Enum_ Processed field value -- the registry member declared for the port, or an unregistered member of the same registry, carrying the port itself, when the registry declares none. See GitHub - issue #575. + issue :issue:`575`. Notes: See :meth:`pcapkit.protocols.schema.transport.tcp.PortEnumField.post_process`, diff --git a/pcapkit/protocols/schema/transport/tcp.py b/pcapkit/protocols/schema/transport/tcp.py index b3272436d9..3f50d9b953 100644 --- a/pcapkit/protocols/schema/transport/tcp.py +++ b/pcapkit/protocols/schema/transport/tcp.py @@ -256,11 +256,11 @@ def mptcp_dss_ack_selector(pkt: 'dict[str, Any]') -> 'Field': This is a :class:`~pcapkit.corekit.fields.misc.SwitchField` selector rather than a :class:`~pcapkit.corekit.fields.misc.ConditionalField` wrapping ``NumberField(length=lambda pkt: ...)``, which is what it was - until #576. + until :issue:`576`. The width lambda read ``8 if pkt['flags']['a'] else 0`` -- **0**, not 4 -- so an unextended Data ACK packed no octets at all while the ``length`` - octet still counted 4 for it. That is the defect #576 records: the option + octet still counted 4 for it. That is the defect :issue:`576` records: the option went onto the wire 4 (or 8, with ``dsn`` too) octets shorter than it declared, and the ``ack`` value the caller supplied was simply not present. @@ -276,7 +276,7 @@ def mptcp_dss_ack_selector(pkt: 'dict[str, Any]') -> 'Field': integer``. Measured on the 8-octet form, which the old lambda did reach: ``_make_mptcp_dss(DSS, ack=1 << 40)`` raised exactly that. - That half is now history: **#591 fixed it**, in + That half is now history: :issue:`591` **fixed it**, in :mod:`pcapkit.corekit.fields.numbers` where this note used to say the fix belonged, by recomputing ``_need_process`` from the width actually in force instead of once from the placeholder. A callable-length @@ -302,7 +302,7 @@ def mptcp_dss_ack_selector(pkt: 'dict[str, Any]') -> 'Field': special case: its selector always hands back an already-concrete field, :class:`~pcapkit.corekit.fields.misc.NoValueField` included, so its ``length`` is safe wherever it is read. Swapping the two would be a - behaviour change, not a tidy-up, and #603 does not make it. + behaviour change, not a tidy-up, and :issue:`603` does not make it. """ if not pkt['flags']['A']: @@ -334,8 +334,8 @@ def mptcp_dss_dsn_selector(pkt: 'dict[str, Any]') -> 'Field': identical defect: ``NumberField(length=lambda pkt: 8 if pkt['flags']['m'] else 0, ...)``. See that function's note for why the ``0`` was wrong, why a corrected lambda would not have packed either *at the time*, and why the - ``SwitchField`` form is kept now that #591 has made a callable length work. - C.f. #576, #591. + ``SwitchField`` form is kept now that :issue:`591` has made a callable length work. + C.f. :issue:`576`, :issue:`591`. """ if not pkt['flags']['M']: @@ -390,7 +390,7 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Enum_ Processed field value -- the registry member declared for the port, or an unregistered member of the same registry, carrying the port itself, when the registry declares none. See GitHub - issue #575. + issue :issue:`575`. Notes: :meth:`~pcapkit.const.reg.apptype.AppType.get` mints a fresh @@ -409,12 +409,12 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Enum_ A port outside this field's own width is rejected *before* any of that, rather than being let through to :meth:`_missing_` and caught alongside a genuine miss. Both are a bare :exc:`ValueError` - with nothing to tell them apart by type, and GitHub issue #758 + with nothing to tell them apart by type, and GitHub issue :issue:`758` gave the out-of-range case a deliberate, ``breaking``-tagged rejection specifically so it would stop being minted over -- a catch keyed on exception type alone cannot see the difference between that and :mod:`aenum`'s own "no member has this value", - so it would absorb both and quietly revert #758 for these four + so it would absorb both and quietly revert :issue:`758` for these four fields. Checking the width first needs no exception-based distinction at all: it asks the same question :meth:`_missing_` would eventually ask, and asks it in a way that never manufactures @@ -766,7 +766,7 @@ class _MPTCP(Schema): #: itself. :rfc:`8684` section 3 therefore puts ``kind`` in bits 0-7, #: ``length`` in bits 8-15, and the subtype in bits 16-19 of this 3-octet #: window -- which is why ``subtype`` reads from bit 16 and ``length`` has - #: to read from bit 8. It read from bit 1 until #553, straddling the low + #: to read from bit 8. It read from bit 1 until :issue:`553`, straddling the low #: seven bits of ``kind`` and the high bit of ``length``, so a 12-octet #: MP_CAPABLE (``1e 0c 01``) decoded its length as 60. test: 'MPTCPSubtypeTest' = ForwardMatchField(BitField(length=3, namespace={ @@ -889,7 +889,7 @@ class MPTCPCapable(MPTCP, code=Enum_MPTCPOption.MP_CAPABLE): #: #: :rfc:`8684` section 3.1 gives MP_CAPABLE as 12 octets without this key #: and 20 octets with it, so the field is present only for the latter -- - #: not, as it read until #567, for every length *except* 32, which is not + #: not, as it read until :issue:`567`, for every length *except* 32, which is not #: an MP_CAPABLE length either RFC form uses. rkey: 'int' = ConditionalField( UInt64Field(), @@ -982,7 +982,7 @@ class MPTCPDSS(MPTCP, code=Enum_MPTCPOption.DSS): #: 4 octets when ``A`` is set, 8 when ``a`` is set as well, absent otherwise -- #: :rfc:`8684` section 3.3 figure 9. Both the presence test and the width live #: in :func:`mptcp_dss_ack_selector`, whose note records what this field - #: declared until #576 and why the switch form is kept. + #: declared until :issue:`576` and why the switch form is kept. ack: 'int' = SwitchField( selector=mptcp_dss_ack_selector, ) @@ -1103,7 +1103,7 @@ class MPTCPFastclose(MPTCP, code=Enum_MPTCPOption.MP_FASTCLOSE): #: :rfc:`8684` section 3.5 figure 14 spends a whole 32-bit row on #: ``Kind``/``Length``/``Subtype``/``(reserved)``, i.e. the subtype's 4 bits #: are followed by **12** reserved bits, not 4 -- so the subtype-and-reserved - #: part is 2 octets and the option is 12 octets in total. Until #576 this + #: part is 2 octets and the option is 12 octets in total. Until :issue:`576` this #: field did not exist and ``test`` was the only octet between ``length`` and #: ``key``, so the schema packed **11** octets against a ``length`` of 12. #: Declared the same way :class:`MPTCPJoinACK` declares its own reserved diff --git a/pcapkit/protocols/schema/transport/udp.py b/pcapkit/protocols/schema/transport/udp.py index 21d84cb550..fac262b219 100644 --- a/pcapkit/protocols/schema/transport/udp.py +++ b/pcapkit/protocols/schema/transport/udp.py @@ -67,7 +67,7 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Enum_ Processed field value -- the registry member declared for the port, or an unregistered member of the same registry, carrying the port itself, when the registry declares none. See GitHub - issue #575. + issue :issue:`575`. Notes: See :meth:`pcapkit.protocols.schema.transport.tcp.PortEnumField.post_process`, diff --git a/pcapkit/protocols/transport/tcp.py b/pcapkit/protocols/transport/tcp.py index 42f95f55d8..d448067ac5 100644 --- a/pcapkit/protocols/transport/tcp.py +++ b/pcapkit/protocols/transport/tcp.py @@ -1667,7 +1667,7 @@ def _read_join_synack(self, schema: 'Schema_MPTCPJoinSYNACK', options: 'Option') subtype/flags (1) + ``Address ID`` (1) + the truncated HMAC (8) + the random number (4). - This guard required ``20`` until #576 -- a value that appears in + This guard required ``20`` until :issue:`576` -- a value that appears in neither the figure nor the schema, and that contradicted this method's own docstring. Together with ``_make_join_synack``'s ``length=12`` it made the SYN/ACK form unusable in both directions at once: the maker @@ -1850,13 +1850,13 @@ def _read_mptcp_remove(self, schema: 'Schema_MPTCPRemoveAddress', *, options: 'O IDs is one further octet. :attr:`~pcapkit.protocols.schema.transport.tcp.MPTCPRemoveAddress.addr_id` sizes its list as ``pkt['length'] - 3`` from exactly this, which is why - ``_make_mptcp_remove``'s constant ``length=4`` (fixed in #576) also + ``_make_mptcp_remove``'s constant ``length=4`` (fixed in :issue:`576`) also mis-sized the parse rather than only the pack. The guard permits ``3``, i.e. ``n = 0``, which the figure does not describe -- it shows one Address ID plus "n-1 Address IDs, if required". Left as it stands: tightening it to reject an empty list is - a behaviour change beyond #576's scope, and a zero-ID REMOVE_ADDR now + a behaviour change beyond :issue:`576`'s scope, and a zero-ID REMOVE_ADDR now at least round-trips honestly instead of declaring an octet it never packed. @@ -1907,7 +1907,7 @@ def _read_mptcp_prio(self, schema: 'Schema_MPTCPPriority', *, options: 'Option') 4-octet :rfc:`6824` form is therefore legacy, and the guard stays permissive so that traffic carrying it still parses. - ``_make_mptcp_prio`` declared a constant ``length=4`` until #576, + ``_make_mptcp_prio`` declared a constant ``length=4`` until :issue:`576`, which meant the construction side could only ever emit the legacy form -- and emitted it with an all-zero phantom Address ID when the caller supplied none, because @@ -1999,10 +1999,10 @@ def _read_mptcp_fastclose(self, schema: 'Schema_MPTCPFastclose', options: 'Optio it draws is **12** octets: ``Kind`` (1) + ``Length`` (1) + subtype-and-reserved (2, being 4 subtype bits and 12 reserved) + the option receiver's key (64 bits, 8). Note that section 3.5 is Fast - Close; section 3.7 is Fallback (MP_FAIL), which #576's own text cited + Close; section 3.7 is Fallback (MP_FAIL), which :issue:`576`'s own text cited here by mistake. - Three sites disagreed on this number before #576, all three now + Three sites disagreed on this number before :issue:`576`, all three now reading 12: this guard required ``16``, an octet count nothing in the RFC produces for MP_FASTCLOSE; ``_make_mptcp_fastclose`` declared the correct 12 but the schema packed only **11**, missing the reserved diff --git a/pcapkit/protocols/transport/udp.py b/pcapkit/protocols/transport/udp.py index 8c13a96f14..01d667424c 100644 --- a/pcapkit/protocols/transport/udp.py +++ b/pcapkit/protocols/transport/udp.py @@ -70,7 +70,7 @@ class UDP(Transport[Data_UDP, Schema_UDP], version from the payload and delegates. :attr:`TCP.__proto__ ` bound :class:`pcapkit.protocols.application.httpv1.HTTP` directly for the - same ports until #682, which repointed it here and so removed an + same ports until :issue:`682`, which repointed it here and so removed an asymmetry that had predated the 8080 entries -- port 80 was already split that way. Both tables now agree.