Skip to content

Commit 798a878

Browse files
committed
fix(protocols): compose IPv6_Ext.id() from its direct concrete members (#2462)
- IPv6_Ext.id() returns the names of its direct concrete subclasses, as IP.id() and IPsec.id() do, so the 'IPv6_Ext' selector matches every member. - HOPOPT, IPv6_Route, IPv6_Frag, IPv6_Opts, MH and HIP gain an id() narrowed to their own class name; AH and ESP already narrow theirs. - The "must define" Warning and REQUIRED_OVERRIDES list id(). - A fallback IPv6_Ext layer no longer equals 'IPv6_Ext' with ==, as IPv4 does not equal 'IP'; the id() docstring says so and a test pins it. - Tests cover each member and 'IPsec' on parsed packets, and a malformed HOPOPT parsed by IPv6_Ext, which matches every member name. Closes #2462
1 parent 895b591 commit 798a878

15 files changed

Lines changed: 206 additions & 10 deletions

File tree

‎docs/source/pcapkit/protocols/internet/hip.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Octets Bits Name Description
3737
.. autoproperty:: protocol
3838
.. autoproperty:: protochain
3939

40+
.. automethod:: id
41+
4042
.. automethod:: register_parameter
4143

4244
.. automethod:: read

‎docs/source/pcapkit/protocols/internet/hopopt.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Octets Bits Name Description
2828
.. autoproperty:: protocol
2929
.. autoproperty:: protochain
3030

31+
.. automethod:: id
32+
3133
.. automethod:: register_option
3234

3335
.. automethod:: read

‎docs/source/pcapkit/protocols/internet/ipv6_ext.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ instead of clipping it.
4545
.. autoproperty:: payload
4646
.. autoproperty:: protochain
4747

48+
.. automethod:: id
49+
4850
.. automethod:: read
4951
.. automethod:: make
5052

‎docs/source/pcapkit/protocols/internet/ipv6_frag.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Octets Bits Name Description
3131
.. autoproperty:: protocol
3232
.. autoproperty:: protochain
3333

34+
.. automethod:: id
35+
3436
.. automethod:: read
3537
.. automethod:: make
3638

‎docs/source/pcapkit/protocols/internet/ipv6_opts.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Octets Bits Name Description
2828
.. autoproperty:: protocol
2929
.. autoproperty:: protochain
3030

31+
.. automethod:: id
32+
3133
.. automethod:: register_option
3234

3335
.. automethod:: read

‎docs/source/pcapkit/protocols/internet/ipv6_route.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Octets Bits Name Description
2929
.. autoproperty:: protocol
3030
.. autoproperty:: protochain
3131

32+
.. automethod:: id
33+
3234
.. automethod:: register_routing
3335

3436
.. automethod:: read

‎docs/source/pcapkit/protocols/internet/mh.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Octets Bits Name Description
3636
.. autoproperty:: protocol
3737
.. autoproperty:: protochain
3838

39+
.. automethod:: id
40+
3941
.. automethod:: register_message
4042
.. automethod:: register_option
4143
.. automethod:: register_extension

‎pcapkit/protocols/internet/hip.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,16 @@ def register_parameter(cls, code: 'Enum_Parameter', meth: 'str | tuple[Parameter
747747
warn(f'parameter {code} already registered, overwriting', RegistryWarning)
748748
cls.__parameter__[code] = meth
749749

750+
@classmethod
751+
def id(cls) -> 'tuple[Literal["HIP"]]': # type: ignore[override]
752+
"""Index ID of the protocol.
753+
754+
Returns:
755+
Index ID of the protocol.
756+
757+
"""
758+
return ('HIP',)
759+
750760
##########################################################################
751761
# Data models.
752762
##########################################################################

‎pcapkit/protocols/internet/hopopt.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,16 @@ def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, O
417417
warn(f'option {code} already registered, overwriting', RegistryWarning)
418418
cls.__option__[code] = meth
419419

420+
@classmethod
421+
def id(cls) -> 'tuple[Literal["HOPOPT"]]': # type: ignore[override]
422+
"""Index ID of the protocol.
423+
424+
Returns:
425+
Index ID of the protocol.
426+
427+
"""
428+
return ('HOPOPT',)
429+
420430
##########################################################################
421431
# Data models.
422432
##########################################################################

‎pcapkit/protocols/internet/ipv6_ext.py‎

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,15 @@ class keywords implement it.
223223
224224
Warning:
225225
A subclass **must** define :attr:`name`, :attr:`alias`,
226-
:attr:`protocol`, :attr:`length` and :meth:`__index__` itself. Each
227-
carries this class's *fallback-role* answer, which is wrong for a
228-
header with an identity of its own: it would report itself as
229-
``IPv6 Extension Header`` / ``IPv6-Ext``, read its length off a data
230-
model that is not its own, and :meth:`__index__` would raise rather
231-
than return its IANA number. The language cannot enforce the override,
232-
so ``tests/protocols/internet/test_ipv6_ext_unit.py`` does, over every
233-
subclass discovered at runtime.
226+
:attr:`protocol`, :attr:`length`, :meth:`__index__` and :meth:`id`
227+
itself. Each carries this class's *fallback-role* answer, which is
228+
wrong for a header with an identity of its own: it would report itself
229+
as ``IPv6 Extension Header`` / ``IPv6-Ext``, read its length off a data
230+
model that is not its own, :meth:`__index__` would raise rather than
231+
return its IANA number, and :meth:`id` would match every member's name
232+
rather than narrow to its own class name. The language cannot enforce
233+
the override, so ``tests/protocols/internet/test_ipv6_ext_unit.py``
234+
does, over every subclass discovered at runtime.
234235
235236
.. versionadded:: 1.5.0
236237
@@ -379,6 +380,22 @@ def protochain(self) -> 'ProtoChain | NoReturn':
379380
# Methods.
380381
##########################################################################
381382

383+
@classmethod
384+
def id(cls) -> 'tuple[Literal["HOPOPT"], Literal["IPv6_Route"], Literal["IPv6_Frag"], Literal["ESP"], Literal["AH"], Literal["IPv6_Opts"], Literal["MH"], Literal["HIP"]]': # pylint: disable=line-too-long
385+
"""Index ID of the protocol.
386+
387+
Returns:
388+
Index ID of every direct concrete subclass, each of which narrows
389+
its own :meth:`id` to itself. A header parsed by this class as the
390+
generic fallback therefore matches every one of these names.
391+
392+
Note:
393+
``== 'IPv6_Ext'`` is :data:`False`, as ``== 'IP'`` is on
394+
:class:`~pcapkit.protocols.internet.ipv4.IPv4`; ``== IPv6_Ext`` is :data:`True`.
395+
396+
"""
397+
return ('HOPOPT', 'IPv6_Route', 'IPv6_Frag', 'ESP', 'AH', 'IPv6_Opts', 'MH', 'HIP')
398+
382399
def read(self, length: 'Optional[int]' = None, *, # pylint: disable=arguments-differ
383400
extension: 'bool' = False, **kwargs: 'Any') -> '_PT':
384401
"""Read a generically-parsed IPv6 extension header.

0 commit comments

Comments
 (0)