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
2 changes: 1 addition & 1 deletion docs/source/pcapkit/protocols/internet/esp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ Known Limitations
stateless parser cannot recover them; they are required both for the ICV
computation and for the AEAD associated data. An ESN protected packet
therefore fails the integrity check *cleanly* rather than being decoded.
* **Traffic Flow Confidentiality (TFC) padding (§2.4) is not detected.**
* **Traffic Flow Confidentiality (TFC) padding (§2.7) is not detected.**
TFC padding is indistinguishable from real payload without inspecting the
inner protocol's own length field, so it is handed to the next layer as
part of the plaintext.
Expand Down
37 changes: 21 additions & 16 deletions docs/source/pcapkit/protocols/internet/ipv6_ext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ IPv6-Ext - IPv6 Extension Header
only, which plays a double role. It is the shared **base class** of every
IPv6 extension header this package implements, supplying the
``extension``-mode contract: the guards that make
:attr:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.payload`,
:attr:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.protocol` and
:attr:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.payload` and
:attr:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.protochain`
unavailable on a header parsed as part of an IPv6 chain. It also implements a
unavailable on a header parsed as part of an IPv6 chain. Each subclass guards
its own ``protocol`` the same way; this class's
:attr:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.protocol` deliberately
does not. It also implements a
**generic** extractor for IPv6 extension headers [*]_, standing in whenever a
header's own dedicated parser is unavailable or has failed. :rfc:`6564#section-4`
requires, with an RFC 2119 **MUST**, that any IPv6 extension header defined since
Expand Down Expand Up @@ -157,20 +159,23 @@ left, then read only what is left. See
:func:`pcapkit.protocols.schema.misc.pcapng.bounded_area` and
:meth:`pcapkit.protocols.misc.pcapng.PCAPNG.read`.

This class follows that convention's *warning*
(:class:`~pcapkit.utilities.warnings.SchemaWarning`) and deliberately diverges
on the *action*. Clipping is right when the declared length only governs how
much of the current object to read, since there is always a well-defined
"what is left" to fall back to. Here the declared length also decides *where
the next header starts*; a clipped skip distance points at whatever bytes
end the buffer, which are not a header. Continuing from there would
fabricate a layer and record a false entry in
This class follows that convention's *warning* -- a
:class:`~pcapkit.utilities.warnings.SchemaWarning`, as
:func:`~pcapkit.protocols.schema.misc.pcapng.bounded_area` emits -- and
deliberately diverges on the *action*. Clipping is right when the declared
length only governs how much of the current object to read, since there is
always a well-defined "what is left" to fall back to. Here the declared length
also decides *where the next header starts*; a clipped skip distance points at
whatever bytes end the buffer, which are not a header. Continuing from there
would fabricate a layer and record a false entry in
:class:`~pcapkit.corekit.protochain.ProtoChain`, which reads as a parsed fact
rather than a guess. So :meth:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.read` warns in the same
wording as the sites above, then **stops the walk**: this instance absorbs
every remaining octet and reports :data:`None` for ``next``, which the
caller's loop already reads as "no more extension headers". The chain ends
honestly at the bad header instead of inventing what follows it.
rather than a guess. So :meth:`~pcapkit.protocols.internet.ipv6_ext.IPv6_Ext.read`
warns in the same form as
:func:`~pcapkit.protocols.schema.misc.pcapng.bounded_area`, then **stops the
walk**: this instance absorbs every remaining octet and reports :data:`None`
for ``next``, which the caller's loop already reads as "no more extension
headers". The chain ends honestly at the bad header instead of inventing what
follows it.

Header Schemas
--------------
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/protocols/data/internet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
# IPv6 Fragment Header
from pcapkit.protocols.data.internet.ipv6_frag import IPv6_Frag

# IPv6 Extension Header (base + generic fallback)
# IPv6 Extension Header (generic fallback)
from pcapkit.protocols.data.internet.ipv6_ext import IPv6_Ext

# IPv6 Destination Options
Expand Down Expand Up @@ -424,7 +424,7 @@
# IPv6 Fragment Header
'IPv6_Frag',

# IPv6 Extension Header (base + generic fallback)
# IPv6 Extension Header (generic fallback)
'IPv6_Ext',

# IPv6 Destination Options Header
Expand Down
8 changes: 5 additions & 3 deletions pcapkit/protocols/data/internet/esp.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ class ESP(Protocol):
#: byte of the packet that ESP owns.
length: 'int'
#: Payload data exactly as transmitted -- ciphertext, prefixed by any
#: cryptographic synchronisation data (IV) -- excluding the ICV.
#: cryptographic synchronisation data (IV) -- excluding the ICV whenever
#: :attr:`icv` holds it.
payload_data: 'bytes'
#: Integrity check value as transmitted; empty when absent, or when no
#: Security Association was available to say how long it is.
#: Integrity check value as transmitted; empty when absent, when no
#: Security Association was available to say how long it is, or when the
#: packet is shorter than the ICV its Security Association declares.
icv: 'bytes'
#: Outcome of the decryption and integrity check.
status: 'ESPStatus'
Expand Down
9 changes: 5 additions & 4 deletions pcapkit/protocols/data/internet/hip.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ class Parameter(Data):
type: 'Enum_Parameter'
#: Critical flag.
critical: 'bool'
#: Content length.
#: Parameter length, in octets -- the whole record, including ``Type``,
#: ``Length`` and ``Padding`` (:rfc:`7401#section-5.2.1`).
length: 'int'

if TYPE_CHECKING:
Expand Down Expand Up @@ -130,7 +131,7 @@ class HIP(Protocol):
version_fixed: 'int'
#: Checksum.
chksum: 'bytes'
#: Control
#: Control.
control: 'Control'
#: Sender's host identity tag.
shit: 'int'
Expand Down Expand Up @@ -416,7 +417,7 @@ class NATTraversalModeParameter(Parameter):

#: The two reserved octets, as captured.
reserved: 'bytes'
#: Mode IDs
#: Mode IDs.
mode_id: 'tuple[NATTraversal, ...]'

if TYPE_CHECKING:
Expand Down Expand Up @@ -718,7 +719,7 @@ class PayloadMICParameter(Parameter):

#: The three reserved octets, as captured.
reserved: 'bytes'
#: Next header
#: Next header.
next: 'TransType'
#: Payload data.
payload: 'bytes'
Expand Down
6 changes: 4 additions & 2 deletions pcapkit/protocols/data/internet/hopopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ class CALIPSOOption(Option):

#: CALIPSO domain of interpretation.
domain: 'int'
#: Compartment length.
#: Compartment bitmap length, in octets: four times the ``Cmpt Length``
#: field, which counts 32-bit words.
cmpt_len: 'int'
#: Sensitivity level.
level: 'int'
Expand Down Expand Up @@ -166,7 +167,8 @@ class SMFIdentificationBasedDPDOption(SMFDPDOption):

#: TaggerID type.
tid_type: 'TaggerID'
#: TaggerID length.
#: ``TidLen`` field as on the wire: the TaggerID length in octets minus
#: one, or ``0`` when there is no TaggerID [:rfc:`6621#section-6.1.1`].
tid_len: 'int'
#: TaggerID.
tid: 'Optional[bytes | IPv4Address | IPv6Address]'
Expand Down
6 changes: 3 additions & 3 deletions pcapkit/protocols/data/internet/ipv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class IPv4(Protocol):

#: Version.
version: 'Literal[4]'
#: Internet header length.
#: Internet header length, in octets.
hdr_len: 'int'
#: Type of service.
tos: 'ToSField'
Expand All @@ -122,7 +122,7 @@ class IPv4(Protocol):
id: 'int'
#: Flags.
flags: 'Flags'
#: Fragment offset.
#: Fragment offset, in octets.
offset: 'int'
#: Time to live.
ttl: 'timedelta'
Expand Down Expand Up @@ -150,7 +150,7 @@ def __init__(self, version: 'Literal[4]', hdr_len: 'int', tos: 'ToSField', len:
class OptionType(Data):
"""Data model for IPv4 option type data."""

#: Change flag.
#: Copied flag, i.e. whether the option is copied into every fragment.
change: 'bool'
#: Option class.
#class: 'int'
Expand Down
6 changes: 4 additions & 2 deletions pcapkit/protocols/data/internet/ipv6_opts.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ class CALIPSOOption(Option):

#: CALIPSO domain of interpretation.
domain: 'int'
#: Compartment length.
#: Compartment bitmap length, in octets: four times the ``Cmpt Length``
#: field, which counts 32-bit words.
cmpt_len: 'int'
#: Sensitivity level.
level: 'int'
Expand Down Expand Up @@ -172,7 +173,8 @@ class SMFIdentificationBasedDPDOption(SMFDPDOption):

#: TaggerID type.
tid_type: 'TaggerID'
#: TaggerID length.
#: ``TidLen`` field as on the wire: the TaggerID length in octets minus
#: one, or ``0`` when there is no TaggerID [:rfc:`6621#section-6.1.1`].
tid_len: 'int'
#: TaggerID.
tid: 'Optional[bytes | IPv4Address | IPv6Address]'
Expand Down
9 changes: 6 additions & 3 deletions pcapkit/protocols/internet/esp.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
stateless parser cannot recover them; they are required both for the ICV
computation and for the AEAD associated data. An ESN protected packet
therefore fails the integrity check *cleanly* rather than being decoded.
* **Traffic Flow Confidentiality (TFC) padding (§2.4) is not detected.**
* **Traffic Flow Confidentiality (TFC) padding (§2.7) is not detected.**
TFC padding is indistinguishable from real payload without inspecting the
inner protocol's own length field, so it is handed to the next layer as
part of the plaintext.
Expand Down Expand Up @@ -1251,8 +1251,11 @@ def make(self,

Raises:
ProtocolError: If ``encrypt`` is :data:`True` and no Security
Association is available for ``spi``, or if ``pad_len`` does
not satisfy the algorithm's alignment requirement.
Association is available for ``spi``, if ``pad_len`` is
outside ``0`` to ``255`` or does not satisfy the algorithm's
alignment requirement, or if
:meth:`SecurityAssociation.encrypt` rejects ``iv`` or cannot
run without |cryptography|_.

"""
if not encrypt:
Expand Down
26 changes: 18 additions & 8 deletions pcapkit/protocols/internet/hip.py
Original file line number Diff line number Diff line change
Expand Up @@ -1758,7 +1758,7 @@ def _read_param_cert(self, schema: 'Schema_CertParameter', *, version: 'int', #
options: 'Parameter') -> 'Data_CertParameter': # pylint: disable=unused-argument
"""Read HIP ``CERT`` parameter.

Structure of HIP ``CERT`` parameter [:rfc:`7401`]:
Structure of HIP ``CERT`` parameter [:rfc:`8002`]:

.. code-block:: text

Expand Down Expand Up @@ -3028,7 +3028,7 @@ def _read_param_relay_hmac(self, schema: 'Schema_RelayHMACParameter', version: '

Structure of HIP ``RELAY_HMAC`` parameter [:rfc:`5770`]:

.. code-block::
.. code-block:: text

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
Expand Down Expand Up @@ -3162,7 +3162,7 @@ def _make_param_esp_info(self, code: 'Enum_Parameter', param: 'Optional[Data_ESP
code: parameter code
param: parameter data
version: HIP protocol version
reserved: reserved octets, zero when sent (:rfc:`7402#section-5.1.1`)
reserved: reserved octets (:rfc:`7402#section-5.1.1`)
index: KEYMAT index
old_spi: old SPI
new_spi: new SPI
Expand Down Expand Up @@ -3355,8 +3355,9 @@ def _make_puzzle_lifetime(code: 'Enum_Parameter', version: 'int',
"""Encode a ``PUZZLE`` ``Lifetime`` octet.

:rfc:`7401#section-5.2.4` gives the puzzle lifetime as ``2^(value - 32)``
seconds -- and it is the *only* place either RFC defines that encoding, so
it applies to ``PUZZLE`` alone. ``SOLUTION``'s octet at the same offset is
seconds -- and the ``PUZZLE`` section is the only place either RFC defines
that encoding (:rfc:`5201#section-5.2.4` identically), so it applies to
``PUZZLE`` alone. ``SOLUTION``'s octet at the same offset is
``Reserved`` (:rfc:`7401#section-5.2.5`) and does not come through here.

Args:
Expand Down Expand Up @@ -4022,6 +4023,12 @@ def _make_param_host_id(self, code: 'Enum_Parameter', param: 'Optional[Data_Host
Returns:
HIP parameter schema.

Raises:
ProtocolError: If neither ``hi`` nor ``param`` is given and
``hi_curve`` is not an ECDSA, ECDSA_LOW or EdDSA curve, or if
``hi`` is a :class:`~pcapkit.protocols.data.internet.hip.HostIdentity`
whose ``curve`` is none of those.

"""
if param is not None:
hi = param.hi
Expand Down Expand Up @@ -5082,7 +5089,8 @@ def _make_param_relay_from(self, code: 'Enum_Parameter', param: 'Optional[Data_R
protocol_default: default transport protocol
protocol_namespace: transport protocol namespace
protocol_reversed: reverse transport protocol namespace
address: relay address
address: the address the relay server received the relayed
packet from (:rfc:`5770`)
reserved: the reserved octet, truncated or
zero-filled to 1 octet
**kwargs: arbitrary keyword arguments
Expand Down Expand Up @@ -5130,7 +5138,8 @@ def _make_param_relay_to(self, code: 'Enum_Parameter', param: 'Optional[Data_Rel
protocol_default: default transport protocol
protocol_namespace: transport protocol namespace
protocol_reversed: reverse transport protocol namespace
address: relay address
address: the address the relay server forwards the packet to
(:rfc:`5770`)
reserved: the reserved octet, truncated or
zero-filled to 1 octet
**kwargs: arbitrary keyword arguments
Expand Down Expand Up @@ -5247,7 +5256,8 @@ def _make_param_from(self, code: 'Enum_Parameter', param: 'Optional[Data_FromPar
code: parameter code
param: parameter data
version: HIP protocol version
address: relay address
address: the original source address of the relayed packet
(:rfc:`8004`)
**kwargs: arbitrary keyword arguments

Returns:
Expand Down
12 changes: 12 additions & 0 deletions pcapkit/protocols/internet/hopopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,10 @@ def _make_opt_pad(self, code: 'Enum_Option', opt: 'Optional[Data_PadOption]' = N
Returns:
Constructed option schema.

Warns:
ProtocolWarning: If ``code`` is ``Pad1`` but ``length`` is not
``0``; a ``PadN`` option is made instead.

Note:
:attr:`Data_PadOption.length
<pcapkit.protocols.data.internet.hopopt.Option.length>` counts the
Expand Down Expand Up @@ -1817,6 +1821,10 @@ def _make_opt_pdm(self, code: 'Enum_Option', opt: 'Optional[Data_PDMOption]' = N
Returns:
Constructed option schema.

Warns:
ProtocolWarning: If a scale exceeds ``255``, too large for its
one-octet field.

"""
if opt is not None:
psntp = opt.psntp
Expand Down Expand Up @@ -1890,6 +1898,10 @@ def _make_opt_qs(self, code: 'Enum_Option', opt: 'Optional[Data_QuickStartOption
Constructed option schema; an unassigned option schema if ``opt``
is a Quick-Start option parsed as unassigned, see :meth:`_read_opt_qs`.

Raises:
ProtocolError: If the QS function is neither a Quick-Start Request
nor a Report of Approved Rate.

"""
if isinstance(opt, Data_UnassignedOption):
return self._make_opt_none(code, opt)
Expand Down
10 changes: 7 additions & 3 deletions pcapkit/protocols/internet/ipv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ def read(self, length: 'Optional[int]' = None, *, # pylint: disable=unused-argu
Parsed packet data.

Raises:
ProtocolError: If the version is not 4, or if ``ihl`` declares
more header than the data holds.
ProtocolError: If the version is not 4, if ``ihl`` declares
more header than the data holds, or if an option is malformed.

"""
if length is None:
Expand Down Expand Up @@ -477,7 +477,8 @@ def make(self,
reserved: Reserved flag bit, i.e. the high-order bit of the flags.
df: Don't fragment flag.
mf: More fragments flag.
offset: Fragment offset.
offset: Fragment offset, in the 8-octet units of the wire field;
the parsed ``offset`` is in octets, see :meth:`_make_data`.
ttl: Time to live of the packet.
protocol: Payload protocol of the packet.
protocol_default: Default value of ``protocol``.
Expand Down Expand Up @@ -1708,6 +1709,9 @@ def _make_opt_ts(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_TSOptio
Constructed option schema.

Raises:
ProtocolError: If ``option`` is not given and ``timestamp`` is
neither a :obj:`list` nor a :obj:`dict`, which includes the
default :data:`None`.
FieldValueError: If an address is a :obj:`bool` or is not a valid
IPv4 address.

Expand Down
Loading
Loading