Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ This resolves [#548](https://github.com/JarryShaw/PyPCAPKit/issues/548), which r
- `TCP.__proto__` bound `httpv1.HTTP` directly for ports 80 and 8080, so a segment on either port was HTTP/1 by assertion of the port alone; both versions share those ports, so the payload has to decide. Repointed to the generic `pcapkit.protocols.application.http.HTTP` proxy, whose identification became positive only once [#800](https://github.com/JarryShaw/PyPCAPKit/issues/800) and [#814](https://github.com/JarryShaw/PyPCAPKit/pull/814) landed, which is why this waited. `udp.py` already bound the proxy for both ports; this removes the asymmetry its docstring and `docs/source/pep.rst` documented as an open request (prose-only on that side). Protochain over all 23 captures (1,604 frames) is *not* byte-identical, and that is the fix: all 231 HTTP/1.1 frames keep their chain, and nine frames in `options-transport.pcap` change `Ethernet:IPv4:TCP:Raw` to `Ethernet:IPv4:TCP:HTTP/2` -- genuine HTTP/2 frames this library's own `httpv2.HTTP.make` built, previously refused by the HTTP/1 parser. `_guess_version`'s entry count over the corpus goes 0 to 252 (231 HTTP/1.1, 9 HTTP/2, 12 fall-throughs that stay `Raw`). Not labelled breaking, but not free: TCP:80/8080 traffic that is neither valid HTTP/1 nor preface-carrying is now exposed to the fall-through arm, where the direct `httpv1` binding left it `Raw` regardless; a caller depending on that is the one who would notice ([#682](https://github.com/JarryShaw/PyPCAPKit/issues/682)).
- **a breaking change to** 8 more bespoke registries: step 2 of [#860](https://github.com/JarryShaw/PyPCAPKit/issues/860), PR 1 of 2 (`AppType` is PR 2, [#874](https://github.com/JarryShaw/PyPCAPKit/pull/874) below), bringing `StatusCode`, `ReturnCode`, `ResponseKind`, `GroupingInformation`, `OptionType`, `FEATCode`, `Command` and `Method` onto `EnumRegistry` and applying [#775](https://github.com/JarryShaw/PyPCAPKit/issues/775)'s mint/unmint ruling to their `get()` as well as `_missing_`. The first five convert 12 unambiguous placeholder branches (`Unassigned`, `Unknown`, `opt_unknown`) to `_unregistered_member`; the three with a custom `__new__` (`StatusCode`, `ReturnCode`, `OptionType`) get an override reconstructing the attributes the base's generic helper would leave unset, and `StatusCode`/`ReturnCode`'s hand-written `get()`, still on the retired `default == -1` convention, is replaced by the base's (no caller relied on the old form). `OptionType` keeps its own `get()` for its multi-namespace dispatch, but a round-2 review found it still minted on both its int/namespace and `str` paths, and the live pcapng parse path (`PCAPNG._make_pcapng_options`) calls it with wire bytes, so parsing an undeclared option code still registered a permanent member; both paths now build an unregistered member. `FEATCode`, `Command` and `Method` mint the literal wire value as its own name rather than any placeholder; per the owner's ruling (*"get will not have sufficient information to create new ones"*: `Command` needs `feat`/`desc`/`type`/`conf` and `Method` needs `safe`/`idempotent`, which a bare wire string lacks), both `_missing_` and each class's own `get()` (a second, independent mint site) now build an unregistered member. `FEATCode`'s crawler now declares all 15 real FEAT-code values from the live IANA table instead of minting 10 of them as a side effect of evaluating `Command`'s rows at import time, the import-time-mutation shape [#861](https://github.com/JarryShaw/PyPCAPKit/pull/861) removed from `FilterType`; pinned count-agnostically so a future IANA update cannot fail a correct regeneration. Untouched, per rulings: `CommandType` stays `IntFlag` (real `A|P` composites in the generated data), and `TransportProtocol`'s `auto()` renumbering and `AppType` are PR 2's. `pcapkit/protocols/schema/misc/pcapng.py`'s `OptionEnumField.post_process` docstring is corrected: it still bypasses `OptionType.get()` directly, now for `pickle` round-trip safety ([#860](https://github.com/JarryShaw/PyPCAPKit/issues/860) already stops the minting that used to be the reason), since neither of `OptionType`'s two paths gets both pickling and correct rendering right at once ([#869](https://github.com/JarryShaw/PyPCAPKit/pull/869)).
- `register` on `ProtocolBase`, `Frame`, `PCAPNG`, `SCTP`, `Link`, `Internet` and the concrete `Transport` subclasses (`TCP`, `UDP`) now raises `RegistryError` for a non-class argument, where it raised a bare `TypeError` ("issubclass() arg 1 must be a class") from inside `abc`. Each guard gains an explicit `isinstance(protocol, type)` test ahead of its `issubclass`, after the `ModuleDescriptor` is unwrapped, so a descriptor naming a non-class attribute is rejected too. All seven `Raises:` clauses already promised `RegistryError` if `protocol` "is not a ... subclass", which a non-class satisfied in spirit but not in fact; they now read "is not a class, or not a ... subclass". No guard's target class changes, and a wrong class still raises `RegistryError` as before. `Transport.register` on `Transport` itself still raises `UnsupportedCall` first; only its subclasses reach the guard. Not breaking for exception handling: `RegistryError` subclasses `TypeError` through `BaseError`, so `except TypeError` still catches it, and the type and message text are the only things a handler can key on that change. Two observable side effects do come with it, because `BaseError` is loud by default: the non-class path now emits pcapkit's one `CRITICAL` log record, and outside devmode it installs `sys.excepthook` and `threading.excepthook`, neither of which the bare `TypeError` from `abc` did. That is the wrong-class path's existing behaviour, so the fix makes the two consistent rather than introducing something new. Follows the same fix for the foundation registrars ([#1021](https://github.com/JarryShaw/PyPCAPKit/issues/1021)) ([#1026](https://github.com/JarryShaw/PyPCAPKit/issues/1026)).
- `PCAPNG`'s `ns_dnsname`, `ns_dnsIP4addr` and `ns_dnsIP6addr` scope guards, on both the read and the make side, now say the option "must be in Name Resolution Block", which is the block they check; they used to name the systemd(1) Journal Export Block, with a literal `:manpage:` role in the text. `register_record`'s `RegistryWarning` likewise now says "name resolution record already registered". The make-side `ns_dnsIP4addr`/`ns_dnsIP6addr` messages also drop the lowercase `ns_dnsip4addr`/`ns_dnsip6addr` spelling for the `OptionType` member name. Two more guards named the wrong option: `_make_option_if_rxspeed`'s scope and duplicate guards now say `[if_rxspeed]` rather than `[if_txspeed]`, and `_read_option_epb_queue`'s length guard says `[epb_queue]` rather than `[epb_packetid]`. Only message text changes; the exception and warning types are unchanged ([#1038](https://github.com/JarryShaw/PyPCAPKit/issues/1038)).

### pcapkit.toolkit

Expand Down
12 changes: 12 additions & 0 deletions docs/source/changelog/1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,18 @@ Fixed
so the fix makes the two consistent rather than introducing something new.
Follows the same fix for the foundation registrars (:issue:`1021`)
(:issue:`1026`).
* ``PCAPNG``'s ``ns_dnsname``, ``ns_dnsIP4addr`` and ``ns_dnsIP6addr`` scope guards,
on both the read and the make side, now say the option "must be in Name Resolution
Block", which is the block they check; they used to name the systemd(1) Journal
Export Block, with a literal ``:manpage:`` role in the text. ``register_record``'s
``RegistryWarning`` likewise now says "name resolution record already registered".
The make-side ``ns_dnsIP4addr``/``ns_dnsIP6addr`` messages also drop the lowercase
``ns_dnsip4addr``/``ns_dnsip6addr`` spelling for the ``OptionType`` member name.
Two more guards named the wrong option: ``_make_option_if_rxspeed``'s scope and
duplicate guards now say ``[if_rxspeed]`` rather than ``[if_txspeed]``, and
``_read_option_epb_queue``'s length guard says ``[epb_queue]`` rather than
``[epb_packetid]``. Only message text changes; the exception and warning types are unchanged
(:issue:`1038`).

pcapkit.toolkit
---------------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/contributing/conventions/process.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ commands down instead of a figure that will be stale by the next merge:
The grouping scheme was settled on :issue:`918`: **a section per top-level module, with**
``Added``/``Changed``/``Fixed`` **nested inside each** -- module granularity, not
per-file and not per-subpackage. The file carries **9** module-level sections holding
163 entries, and no entry carries an inline kind label::
164 entries, and no entry carries an inline kind label::

$ grep -cE '^\* \*\*(Added|Changed|Fixed)\*\*' docs/source/changelog/1.5.0.rst
0
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/protocols/data/misc/pcapng.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def __init__(self, type: 'Enum_OptionType', length: 'int', name: 'str') -> 'None

@info_final
class NS_DNSIP4AddrOption(Option):
"""Data model for PCAP-NG ``ns_dnsip4addr`` option."""
"""Data model for PCAP-NG ``ns_dnsIP4addr`` option."""

#: IPv4 address.
ip: 'IPv4Address'
Expand All @@ -588,7 +588,7 @@ def __init__(self, type: 'Enum_OptionType', length: 'int', ip: 'IPv4Address') ->

@info_final
class NS_DNSIP6AddrOption(Option):
"""Data model for PCAP-NG ``ns_dnsip6addr`` option."""
"""Data model for PCAP-NG ``ns_dnsIP6addr`` option."""

#: IPv6 address.
ip: 'IPv6Address'
Expand Down
28 changes: 14 additions & 14 deletions pcapkit/protocols/misc/pcapng.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ def register_record(cls, code: 'Enum_RecordType', meth: 'str | tuple[RecordParse

"""
if code in cls.__record__:
warn(f'PCAP-NG: [Type {code}] :manpage:`systemd(1)` journal export record already registered', RegistryWarning)
warn(f'PCAP-NG: [Type {code}] name resolution record already registered', RegistryWarning)
cls.__record__[code] = meth

@classmethod
Expand Down Expand Up @@ -2962,7 +2962,7 @@ def _read_option_epb_queue(self, schema: 'Schema_EPB_QueueOption', *,
raise ProtocolError(f'PCAP-NG: [epb_queue] option must be only one, '
f'but {self._opt[schema.type] + 1} found.')
if schema.length != 4:
raise ProtocolError(f'PCAP-NG: [epb_packetid] invalid length (expected 4, got {schema.length})')
raise ProtocolError(f'PCAP-NG: [epb_queue] invalid length (expected 4, got {schema.length})')

option = Data_EPB_QueueOption(
type=schema.type,
Expand Down Expand Up @@ -3010,7 +3010,7 @@ def _read_option_ns_dnsname(self, schema: 'Schema_NS_DNSNameOption', *,

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[schema.type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be only one, '
Expand All @@ -3036,7 +3036,7 @@ def _read_option_ns_dnsipv4(self, schema: 'Schema_NS_DNSIP4AddrOption', *,

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsIP4addr] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP4addr] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[schema.type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsIP4addr] option must be only one, '
Expand Down Expand Up @@ -3064,7 +3064,7 @@ def _read_option_ns_dnsipv6(self, schema: 'Schema_NS_DNSIP6AddrOption', *,

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsIP6addr] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP6addr] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[schema.type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsIP6addr] option must be only one, '
Expand Down Expand Up @@ -4820,10 +4820,10 @@ def _make_option_if_rxspeed(self, type: 'Enum_OptionType', option: 'Optional[Dat

"""
if self._type != Enum_BlockType.Interface_Description_Block:
raise ProtocolError(f'PCAP-NG: [if_txspeed] option must be in Interface Description Block, '
raise ProtocolError(f'PCAP-NG: [if_rxspeed] option must be in Interface Description Block, '
f'but found in {self._type} block.')
if self._opt[type] > 0:
raise ProtocolError(f'PCAP-NG: [if_txspeed] option must be only one, '
raise ProtocolError(f'PCAP-NG: [if_rxspeed] option must be only one, '
f'but {self._opt[type] + 1} found.')

if option is not None:
Expand Down Expand Up @@ -5119,7 +5119,7 @@ def _make_option_ns_dnsname(self, type: 'Enum_OptionType', option: 'Optional[Dat

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsname] option must be only one, '
Expand All @@ -5137,7 +5137,7 @@ def _make_option_ns_dnsname(self, type: 'Enum_OptionType', option: 'Optional[Dat
def _make_option_ns_dnsipv4(self, type: 'Enum_OptionType', option: 'Optional[Data_NS_DNSIP4AddrOption]' = None, *,
ip: 'str | bytes | IPv4Address | int' = '8.8.8.8',
**kwargs: 'Any') -> 'Schema_NS_DNSIP4AddrOption':
"""Make PCAP-NG ``ns_dnsip4addr`` option.
"""Make PCAP-NG ``ns_dnsIP4addr`` option.

Args:
type: Option type.
Expand All @@ -5150,10 +5150,10 @@ def _make_option_ns_dnsipv4(self, type: 'Enum_OptionType', option: 'Optional[Dat

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsip4addr] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP4addr] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsip4addr] option must be only one, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP4addr] option must be only one, '
f'but {self._opt[type] + 1} found.')

if option is not None:
Expand All @@ -5168,7 +5168,7 @@ def _make_option_ns_dnsipv4(self, type: 'Enum_OptionType', option: 'Optional[Dat
def _make_option_ns_dnsipv6(self, type: 'Enum_OptionType', option: 'Optional[Data_NS_DNSIP6AddrOption]' = None, *,
ip: 'str | bytes | IPv6Address | int' = '8.8.8.8',
**kwargs: 'Any') -> 'Schema_NS_DNSIP6AddrOption':
"""Make PCAP-NG ``ns_dnsip6addr`` option.
"""Make PCAP-NG ``ns_dnsIP6addr`` option.

Args:
type: Option type.
Expand All @@ -5181,10 +5181,10 @@ def _make_option_ns_dnsipv6(self, type: 'Enum_OptionType', option: 'Optional[Dat

"""
if self._type != Enum_BlockType.Name_Resolution_Block:
raise ProtocolError(f'PCAP-NG: [ns_dnsip6addr] option must be in :manpage:`systemd(1)` Journal Export Block, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP6addr] option must be in Name Resolution Block, '
f'but found in {self._type} block.')
if self._opt[type] > 0:
raise ProtocolError(f'PCAP-NG: [ns_dnsip6addr] option must be only one, '
raise ProtocolError(f'PCAP-NG: [ns_dnsIP6addr] option must be only one, '
f'but {self._opt[type] + 1} found.')

if option is not None:
Expand Down
Loading
Loading