# -*- coding: utf-8 -*-
# mypy: disable-error-code=assignment
"""header schema for Host Identity Protocol"""
from typing import TYPE_CHECKING, cast
from pcapkit.const.hip.certificate import Certificate as Enum_Certificate
from pcapkit.const.hip.cipher import Cipher as Enum_Cipher
from pcapkit.const.hip.di import DITypes as Enum_DITypes
from pcapkit.const.hip.ecdsa_curve import ECDSACurve as Enum_ECDSACurve
from pcapkit.const.hip.ecdsa_low_curve import ECDSALowCurve as Enum_ECDSALowCurve
from pcapkit.const.hip.eddsa_curve import EdDSACurve as Enum_EdDSACurve
from pcapkit.const.hip.esp_transform_suite import ESPTransformSuite as Enum_ESPTransformSuite
from pcapkit.const.hip.group import Group as Enum_Group
from pcapkit.const.hip.hi_algorithm import HIAlgorithm as Enum_HIAlgorithm
from pcapkit.const.hip.hit_suite import HITSuite as Enum_HITSuite
from pcapkit.const.hip.nat_traversal import NATTraversal as Enum_NATTraversal
from pcapkit.const.hip.notify_message import NotifyMessage as Enum_NotifyMessage
from pcapkit.const.hip.parameter import Parameter as Enum_Parameter
from pcapkit.const.hip.registration import Registration as Enum_Registration
from pcapkit.const.hip.registration_failure import RegistrationFailure as Enum_RegistrationFailure
from pcapkit.const.hip.suite import Suite as Enum_Suite
from pcapkit.const.hip.transport import Transport as Enum_Transport
from pcapkit.const.reg.transtype import TransType as Enum_TransType
from pcapkit.corekit.fields.collections import ListField, OptionField
from pcapkit.corekit.fields.ipaddress import IPv6AddressField
from pcapkit.corekit.fields.misc import ConditionalField, PayloadField, SchemaField, SwitchField
from pcapkit.corekit.fields.numbers import (EnumField, NumberField, UInt8Field, UInt16Field,
UInt32Field, UInt64Field)
from pcapkit.corekit.fields.strings import BitField, BytesField, PaddingField
from pcapkit.protocols.schema.schema import EnumSchema, Schema, schema_final
from pcapkit.utilities.exceptions import FieldValueError
from pcapkit.utilities.logging import SPHINX_TYPE_CHECKING
from pcapkit.utilities.warnings import ProtocolWarning, warn
__all__ = [
'HIP',
'LocatorData', 'Locator', 'HostIdentity',
'ECDSACurveHostIdentity', 'ECDSALowCurveHostIdentity', 'EdDSACurveHostIdentity',
'UnassignedParameter', 'ESPInfoParameter', 'R1CounterParameter',
'LocatorSetParameter', 'PuzzleParameter', 'SolutionParameter',
'SEQParameter', 'ACKParameter', 'DHGroupListParameter',
'DiffieHellmanParameter', 'HIPTransformParameter', 'HIPCipherParameter',
'NATTraversalModeParameter', 'TransactionPacingParameter', 'EncryptedParameter',
'HostIDParameter', 'HITSuiteListParameter', 'CertParameter',
'NotificationParameter', 'EchoRequestSignedParameter', 'RegInfoParameter',
'RegRequestParameter', 'RegResponseParameter', 'RegFailedParameter',
'RegFromParameter', 'EchoResponseSignedParameter', 'TransportFormatListParameter',
'ESPTransformParameter', 'SeqDataParameter', 'AckDataParameter',
'PayloadMICParameter', 'TransactionIDParameter', 'OverlayIDParameter',
'RouteDstParameter', 'HIPTransportModeParameter', 'HIPMACParameter',
'HIPMAC2Parameter', 'HIPSignature2Parameter', 'HIPSignatureParameter',
'EchoRequestUnsignedParameter', 'EchoResponseUnsignedParameter', 'RelayFromParameter',
'RelayToParameter', 'RouteViaParameter', 'FromParameter',
'RVSHMACParameter', 'RelayHMACParameter',
]
if TYPE_CHECKING:
from ipaddress import IPv6Address
from typing import Any, Optional
from pcapkit.corekit.fields.field import FieldBase as Field
from pcapkit.protocols.data.internet.hip import EncryptedParameter as Data_EncryptedParameter
from pcapkit.protocols.data.internet.hip import HIPCipherParameter as Data_HIPCipherParameter
from pcapkit.protocols.protocol import ProtocolBase
if SPHINX_TYPE_CHECKING: # pragma: no cover
from typing_extensions import TypedDict
[docs]
class PacketType(TypedDict):
"""Packet type."""
#: Fixed bit, ``0`` when sent and ignored on receipt.
bit_0: int
#: Packet type.
type: int
[docs]
class VersionType(TypedDict):
"""Version type."""
#: Version.
version: int
#: Reserved bits.
reserved: int
#: Fixed bit, ``1`` when sent and ignored on receipt.
bit_1: int
[docs]
class ControlsType(TypedDict):
"""Controls type."""
#: Anonymous.
anonymous: bool
#: Reserved bits.
reserved: int
[docs]
class LocatorFlags(TypedDict):
"""Locator flags."""
#: Reserved bits.
reserved: int
#: Preferred flag.
preferred: bool
[docs]
class DIData(TypedDict):
"""DI type data."""
#: DI type.
type: Enum_DITypes
#: DI length.
len: int
[docs]
class RouteFlags(TypedDict):
"""Route destination flags."""
#: Symmetric flag.
symmetric: int
#: Must-follow flag.
must_follow: int
#: Reserved bits.
reserved: int
[docs]
def locator_value_selector(pkt: 'dict[str, Any]') -> 'Field':
"""Selector function for :attr:`Locator.value` field.
Args:
pkt: Packet data.
Returns:
The field for the locator, chosen by its type and length.
* If ``type`` is ``0`` and ``len`` is ``4``, i.e. a 16-octet locator,
returns an :class:`~pcapkit.corekit.fields.ipaddress.IPv6AddressField` instance.
* If ``type`` is ``1`` and ``len`` is ``5``, i.e. a 20-octet locator,
returns a :class:`~pcapkit.corekit.fields.misc.SchemaField` wrapped
:class:`~pcapkit.protocols.schema.internet.hip.LocatorData` instance.
Raises:
FieldValueError: For any other locator type and length.
"""
if pkt['type'] == 0 and pkt['len'] == 4:
return IPv6AddressField()
if pkt['type'] == 1 and pkt['len'] == 5:
return SchemaField(
length=20,
schema=LocatorData,
)
raise FieldValueError('invalid locator type or length')
[docs]
def host_id_hi_selector(pkt: 'dict[str, Any]') -> 'Field':
"""Selector function for :attr:`HostIDParameter.hi` field.
Args:
pkt: Packet data.
Returns:
The field for the host identity, chosen by its algorithm.
* If ``algorithm`` is ``7`` (ECDSA), returns a
:class:`~pcapkit.corekit.fields.misc.SchemaField` wrapped
:class:`~pcapkit.protocols.schema.internet.hip.ECDSACurveHostIdentity` instance.
* If ``algorithm`` is ``9`` (ECDSA_LOW), returns a
:class:`~pcapkit.corekit.fields.misc.SchemaField` wrapped
:class:`~pcapkit.protocols.schema.internet.hip.ECDSALowCurveHostIdentity` instance.
* If ``algorithm`` is ``13`` (EdDSA), returns a
:class:`~pcapkit.corekit.fields.misc.SchemaField` wrapped
:class:`~pcapkit.protocols.schema.internet.hip.EdDSACurveHostIdentity` instance.
* Otherwise, returns a :class:`~pcapkit.corekit.fields.strings.BytesField`
instance of ``hi_len`` octets.
"""
algo = pkt['algorithm']
schema = HostIdentity.registry[algo]
if schema is None:
return BytesField(length=pkt['hi_len'])
return SchemaField(length=pkt['hi_len'], schema=schema)
[docs]
def registration_type_list_len(pkt: 'dict[str, Any]') -> 'int':
"""Return registration type list length.
Used by the ``reg_request``, ``reg_response`` and ``reg_failed`` fields of
:class:`RegRequestParameter`, :class:`RegResponseParameter` and
:class:`RegFailedParameter` respectively, each of which follows a single
``lifetime`` octet with a list of registration type octets sized by the
remainder of the parameter.
Args:
pkt: Parameter unpacked schema.
Returns:
Registration type list length.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is too
short to hold the ``lifetime`` octet already read, which would
otherwise underflow the list length below zero.
"""
length = pkt['len'] - 1
if length < 0:
raise FieldValueError(f'HIP: invalid parameter length: {pkt["len"]}')
return length
[docs]
def reg_info_list_len(pkt: 'dict[str, Any]') -> 'int':
"""Return ``REG_INFO`` registration type list length.
Used by the ``reg_info`` field of :class:`RegInfoParameter`, which follows
a pair of ``min_lifetime`` and ``max_lifetime`` octets with a list of
registration type octets sized by the remainder of the parameter.
Args:
pkt: Parameter unpacked schema.
Returns:
Registration type list length.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is too
short to hold the ``min_lifetime`` and ``max_lifetime`` octets
already read, which would otherwise underflow the list length
below zero.
"""
length = pkt['len'] - 2
if length < 0:
raise FieldValueError(f'HIP: invalid parameter length: {pkt["len"]}')
return length
[docs]
def two_octet_prefix_list_len(pkt: 'dict[str, Any]') -> 'int':
"""Return list length for a parameter with a two-octet prefix.
Used by the ``modes``, ``suites`` and ``mode`` fields of
:class:`NATTraversalModeParameter`, :class:`ESPTransformParameter` and
:class:`HIPTransportModeParameter` respectively, each of which follows a
two-octet ``reserved`` or ``port`` field with a list of items sized by
the remainder of the parameter.
:class:`TransportFormatListParameter` looks like another call site --
same ``pkt['len'] - 2`` expression -- but is not: see
:func:`transport_format_list_len` for why it has no such prefix to
subtract.
Args:
pkt: Parameter unpacked schema.
Returns:
List length.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is too
short to hold the two octets already read, which would otherwise
underflow the list length below zero.
"""
length = pkt['len'] - 2
if length < 0:
raise FieldValueError(f'HIP: invalid parameter length: {pkt["len"]}')
return length
[docs]
def encrypted_data_len(pkt: 'dict[str, Any]') -> 'int':
"""Return ``ENCRYPTED`` encrypted-data length.
Used by the ``data`` field of :class:`EncryptedParameter`, which follows a
four-octet ``reserved`` field and a conditional sixteen-octet ``iv`` with
the ciphertext, sized by the remainder of the parameter. :rfc:`7401`
Section 5.2.18 puts all three inside ``Length`` --
::
| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IV |
/ /
/ Encrypted data /
-- so both have to come off ``Length`` to leave the data, and
:meth:`~pcapkit.protocols.internet.hip.HIP._make_param_encrypted` writes
``len=4 + len(iv) + len(data)`` to match.
Args:
pkt: Parameter unpacked schema.
Returns:
Encrypted data length.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is too short
to hold the ``reserved`` octets, and the ``iv`` octets where a
cipher that carries one was resolved -- which would otherwise
underflow the data length below zero.
"""
length = pkt['len'] - 4 - (16 if pkt.get('iv') else 0)
if length < 0:
raise FieldValueError(f'HIP: invalid parameter length: {pkt["len"]}')
return length
[docs]
def parameter_total_len(length: 'int') -> 'int':
"""Return the total on-wire length of a HIP parameter.
:rfc:`7401` Section 5.2.1 states the arithmetic outright, so there is
nothing here to infer from the diagram --
::
All of the encoded TLV parameters have a length (that includes the
Type and Length fields), which is a multiple of 8 bytes. When
needed, padding MUST be added to the end of the parameter so that the
total length is a multiple of 8 bytes.
Total Length = 11 + Length - (Length + 3) % 8;
-- and this function is that formula, spelled the way the RFC spells it.
The distinction that matters is *which* quantity gets aligned. ``Length``
is "Length of the Contents, in bytes, excluding Type, Length, and
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 would put 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 -- at ``Length = 4``
(a whole ``SEQ``) the contents are already 8-aligned with the header, so
the RFC requires no padding at all and aligning the contents would append
four octets that must not be there; at ``Length = 8`` the contents are
8-aligned on their own, so aligning them would append nothing and leave
the record four octets short.
Args:
length: The parameter's ``Length`` field, i.e. its contents length in
octets, excluding ``Type``, ``Length`` and ``Padding``.
Returns:
Total length of the parameter in octets, including ``Type``,
``Length``, ``Contents`` and ``Padding``. Always a multiple of eight.
Raises:
FieldValueError: If ``length`` is negative. This cannot happen from
real wire bytes -- ``len`` is an unsigned 16-bit field -- but a
caller constructing a schema directly could still pass one, and
the RFC formula is meaningless there: it would answer 8 for
``Length = -1``, a "total" smaller than the four-octet header
alone. Raising keeps this to the same floor-and-raise discipline
as :func:`two_octet_prefix_list_len`.
"""
if length < 0:
raise FieldValueError(f'HIP: invalid parameter length: {length}')
return 11 + length - (length + 3) % 8
[docs]
def parameter_padding_len(pkt: 'dict[str, Any]') -> 'int':
"""Return the number of padding octets a HIP parameter needs.
Used by the ``padding`` field of every parameter schema in this module.
The count is whatever :func:`parameter_total_len` leaves over once the
four-octet ``Type`` and ``Length`` header and the ``Length`` octets of
contents are accounted for, which :rfc:`7401` Section 5.2.1 bounds at
"0-7 bytes".
This is one function shared by every parameter rather than a lambda
repeated per class, so the RFC's arithmetic is stated in one place.
Args:
pkt: Parameter unpacked schema.
Returns:
Padding length in octets, between 0 and 7 inclusive.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is
negative; see :func:`parameter_total_len`.
"""
length = pkt['len']
return parameter_total_len(length) - 4 - length
#: Packet-context key under which :class:`LocatorSetParameter` keeps its own
#: ``Length`` for the benefit of :func:`locator_set_padding_len`.
#:
#: It exists because the contents of ``LOCATOR_SET`` are a
#: :class:`~pcapkit.corekit.fields.collections.ListField` of nested schemas,
#: and a nested schema packed through one **shares the
#: enclosing packet context**: :meth:`Schema.pack
#: <pcapkit.protocols.schema.schema.Schema.pack>` opens with
#: ``packet.update(self.__dict__)``, and :class:`Locator` declares a ``len`` of
#: 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 -- 4 for any IPv6 locator,
#: whatever the locator count.
#:
#: The shadowing is specific to the packing path. :meth:`Schema.unpack
#: <pcapkit.protocols.schema.schema.Schema.unpack>` hands each field
#: ``packet.copy()``, so nested writes do not propagate back and ``pkt['len']``
#: stays the parameter's there. Snapshotting under a key no nested schema
#: declares is what makes one callback correct on both paths rather than
#: accidentally correct on one.
LOCATOR_SET_LEN = '__locator_set_len__'
[docs]
def locator_set_len_callback(field: 'ListField', # pylint: disable=unused-argument
pkt: 'dict[str, Any]') -> 'None':
"""Snapshot ``LOCATOR_SET``'s own ``Length`` before its locators shadow it.
Installed as the ``callback`` of :attr:`LocatorSetParameter.locators`, which
:meth:`ListField.__call__
<pcapkit.corekit.fields.collections.ListField.__call__>` runs when the field
is resolved against the packet -- i.e. before any nested :class:`Locator` has
been packed into it. See :data:`LOCATOR_SET_LEN` for why the snapshot is
needed at all.
Args:
field: The field being resolved. Unused; the signature is
:class:`~pcapkit.corekit.fields.collections.ListField`'s.
pkt: Parameter unpacked schema, modified in place.
"""
pkt[LOCATOR_SET_LEN] = pkt['len']
[docs]
def locator_set_padding_len(pkt: 'dict[str, Any]') -> 'int':
"""Return the number of padding octets a ``LOCATOR_SET`` parameter needs.
The same arithmetic as :func:`parameter_padding_len` -- it defers to it
rather than repeating it -- but read off the snapshot
:func:`locator_set_len_callback` took, for the reason :data:`LOCATOR_SET_LEN`
gives.
Args:
pkt: Parameter unpacked schema.
Returns:
Padding length in octets, between 0 and 7 inclusive.
Raises:
FieldValueError: If the parameter's ``Length`` on the wire is
negative; see :func:`parameter_total_len`.
"""
return parameter_padding_len({'len': pkt[LOCATOR_SET_LEN]})
[docs]
class Parameter(EnumSchema[Enum_Parameter]):
"""Base schema for HIP parameters."""
__default__ = lambda: UnassignedParameter
#: Parameter type.
type: 'Enum_Parameter' = EnumField(length=2, namespace=Enum_Parameter)
#: Parameter length.
len: 'int' = UInt16Field()
[docs]
@schema_final
class UnassignedParameter(Parameter):
"""Header schema for HIP unassigned parameters."""
#: Parameter value.
value: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', value: 'bytes') -> 'None': ...
[docs]
@schema_final
class ESPInfoParameter(Parameter, code=Enum_Parameter.ESP_INFO):
"""Header schema for HIP ``ESP_INFO`` parameters.
.. versionchanged:: 1.5.0
``reserved`` is read as an :obj:`int` rather than as zero padding
:obj:`bytes`, and written back as given (:issue:`1328`).
"""
#: Reserved, "zero when sent, ignored when received" (:rfc:`7402#section-5.1.1`).
#: Read as a value rather than as padding, so that re-serialising a parsed
#: parameter reproduces the octets it arrived with.
reserved: 'int' = UInt16Field()
#: Key management index.
index: 'int' = UInt16Field()
#: Old SPI.
old_spi: 'int' = UInt32Field()
#: New SPI.
new_spi: 'int' = UInt32Field()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'int', index: 'int',
old_spi: 'int', new_spi: 'int') -> 'None': ...
[docs]
@schema_final
class R1CounterParameter(Parameter, code=[Enum_Parameter.R1_Counter,
Enum_Parameter.R1_COUNTER]):
"""Header schema for HIP ``R1_COUNTER`` parameters.
Registered under both codes, not 129 alone. :rfc:`5201#section-5.2.3`
(HIPv1) and :rfc:`7401#section-5.2.3` (HIPv2) give the identical 4 + 8
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. :attr:`~pcapkit.protocols.internet.hip.HIP.__parameter__` carries
two hand-written entries -- not a name-normalisation rule; ``R1_Counter``
and ``R1_COUNTER`` differ only in case, and each needs its own line --
mapping both codes to the same ``_read_param_r1_counter``, and
``_make_param_r1_counter`` builds this class for either code. The schema lookup
this class's own ``code=`` feeds -- consulted on the parse path by
:class:`~pcapkit.corekit.fields.collections.OptionField` -- would fall
back to :class:`UnassignedParameter` for 128 if a single-code ``code=``
registered 129 alone and left 128 unclaimed.
"""
#: Reserved.
reserved: 'bytes' = PaddingField(length=4)
#: R1 counter.
#:
#: Eight octets, not four. :rfc:`7401#section-5.2.3` labels the field "R1
#: generation counter, 8 bytes" in its diagram and then says outright that
#: the parameter "contains a 64-bit unsigned integer in network byte
#: order", so the width is stated twice and inferred from neither.
#: :rfc:`5201#section-5.2.3` gives the same 4 + 8 layout, so there is no
#: version under which four octets is right, and both codes that reach this
#: class -- ``R1_Counter`` (128, HIPv1) and ``R1_COUNTER`` (129) -- are
#: affected. With the four ``reserved`` octets the contents are 12 octets,
#: which :rfc:`7401` Section 5.2.1's arithmetic pads to a 16-octet record.
counter: 'int' = UInt64Field()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', counter: 'int') -> 'None': ...
[docs]
@schema_final
class Locator(Schema):
"""Header schema for HIP locators."""
#: Traffic type.
traffic: 'int' = UInt8Field()
#: Locator type.
type: 'int' = UInt8Field()
#: Locator length.
len: 'int' = UInt8Field()
#: Reserved and flags.
flags: 'LocatorFlags' = BitField(
length=1,
namespace={
'reserved': (0, 7),
'preferred': (7, 1),
},
)
lifetime: 'int' = UInt32Field()
#: Locator value.
value: 'IPv6Address | LocatorData' = SwitchField(
selector=locator_value_selector,
)
if TYPE_CHECKING:
def __init__(self, traffic: 'int', type: 'int', len: 'int', flags: 'LocatorFlags',
lifetime: 'int', value: 'bytes | LocatorData') -> 'None': ...
[docs]
@schema_final
class LocatorSetParameter(Parameter, code=Enum_Parameter.LOCATOR_SET):
"""Header schema for HIP ``LOCATOR_SET`` parameters."""
#: List of locators.
#:
#: The ``length`` callback is the parameter's own ``Length``, and that is
#: 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 matters
#: is the *quantity* it is handed: :rfc:`7401` Section 5.2.1's ``Length`` is
#: a byte count, not the 4-octet units :rfc:`8046#section-4` gives
#: ``Locator Length``, and
#: :meth:`~pcapkit.protocols.internet.hip.HIP._make_param_locator_set`
#: writes it as one. :meth:`Schema.unpack
#: <pcapkit.protocols.schema.schema.Schema.unpack>` reads exactly
#: ``field.length`` octets off the stream and hands only those to
#: :meth:`ListField.unpack
#: <pcapkit.corekit.fields.collections.ListField.unpack>`, so a ``Length``
#: in locator units would offer a set of *n* plain IPv6 locators ``4n``
#: octets of a ``24n``-octet contents, parse one truncated locator and leave
#: the rest of the record unconsumed. With ``Length`` a byte count the
#: budget is the contents, and each locator bills the 8 + ``Locator
#: Length`` * 4 octets it actually consumed.
locators: 'list[Locator]' = ListField(
length=lambda pkt: pkt['len'],
item_type=SchemaField(schema=Locator),
callback=locator_set_len_callback,
)
#: Padding.
#:
#: Not :func:`parameter_padding_len`, which every other parameter in this
#: module uses, but :func:`locator_set_padding_len` -- the same arithmetic
#: read off a snapshot of this parameter's ``Length`` rather than off
#: ``pkt['len']`` directly. :data:`LOCATOR_SET_LEN` documents why the direct
#: read does not work here: the nested :class:`Locator` schemas share this
#: parameter's packet context while they pack, and their own ``len``
#: overwrites it before ``padding`` is reached.
#:
#: The shadowed ``len`` is 4 for any IPv6 locator, so a padding read off
#: ``pkt['len']`` directly would append exactly four octets whatever the
#: locator count.
padding: 'bytes' = PaddingField(length=locator_set_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', locators: 'list[Locator]') -> 'None': ...
[docs]
@schema_final
class LocatorData(Schema):
"""Header schema for HIP locator data."""
#: SPI.
spi: 'int' = UInt32Field()
#: Locator.
ip: 'IPv6Address' = IPv6AddressField()
if TYPE_CHECKING:
def __init__(self, spi: 'int', ip: 'IPv6Address | int | bytes | str') -> 'None': ...
[docs]
@schema_final
class PuzzleParameter(Parameter, code=Enum_Parameter.PUZZLE):
"""Header schema for HIP ``PUZZLE`` parameters."""
#: Numeric index.
index: 'int' = UInt8Field()
#: Lifetime.
lifetime: 'int' = UInt8Field()
#: Opaque data.
opaque: 'bytes' = BytesField(length=2)
#: Random data.
random: 'int' = NumberField(length=lambda pkt: pkt['len'] - 4, signed=False)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', index: 'int', lifetime: 'int',
opaque: 'bytes', random: 'int') -> 'None': ...
[docs]
@schema_final
class SolutionParameter(Parameter, code=Enum_Parameter.SOLUTION):
"""Header schema for HIP ``SOLUTION`` parameters.
.. versionremoved:: 1.5.0
``lifetime``, now :attr:`reserved`: only ``PUZZLE`` carries a lifetime
(:issue:`654`).
"""
#: Numeric index.
index: 'int' = UInt8Field()
#: Reserved octet -- "zero when sent, ignored when received"
#: (: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.
reserved: 'int' = UInt8Field()
#: Opaque data.
opaque: 'bytes' = BytesField(length=2)
#: Random data.
random: 'int' = NumberField(length=lambda pkt: (pkt['len'] - 4) // 2, signed=False)
#: Solution.
solution: 'int' = NumberField(length=lambda pkt: (pkt['len'] - 4) // 2, signed=False)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', index: 'int', reserved: 'int',
opaque: 'bytes', random: 'int', solution: 'int') -> 'None': ...
[docs]
@schema_final
class SEQParameter(Parameter, code=Enum_Parameter.SEQ):
"""Header schema for HIP ``SEQ`` parameters."""
#: Update ID.
update_id: 'int' = UInt32Field()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', update_id: 'int') -> 'None': ...
[docs]
@schema_final
class ACKParameter(Parameter, code=Enum_Parameter.ACK):
"""Header schema for HIP ``ACK`` parameters."""
#: Update ID.
update_id: 'list[int]' = ListField(
length=lambda pkt: pkt['len'],
item_type=UInt32Field(),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', update_id: 'bytes | list[int]') -> 'None': ...
[docs]
@schema_final
class DHGroupListParameter(Parameter, code=Enum_Parameter.DH_GROUP_LIST):
"""Header schema for HIP ``DH_GROUP_LIST`` parameters."""
#: List of DH groups.
groups: 'list[Enum_Group]' = ListField(
length=lambda pkt: pkt['len'],
item_type=EnumField(length=1, namespace=Enum_Group),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', groups: 'list[Enum_Group]') -> 'None': ...
[docs]
@schema_final
class DiffieHellmanParameter(Parameter, code=Enum_Parameter.DIFFIE_HELLMAN):
"""Header schema for HIP ``DIFFIE_HELLMAN`` parameters."""
#: Diffie-Hellman group.
group: 'Enum_Group' = EnumField(length=1, namespace=Enum_Group)
#: Public value length.
pub_len: 'int' = UInt16Field()
#: Diffie-Hellman value.
pub_val: 'int' = NumberField(length=lambda pkt: pkt['pub_len'], signed=False)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', group: 'Enum_Group', pub_len: 'int',
pub_val: 'int') -> 'None': ...
[docs]
@schema_final
class HIPCipherParameter(Parameter, code=Enum_Parameter.HIP_CIPHER):
"""Header schema for HIP ``HIP_CIPHER`` parameters."""
#: Cipher IDs.
ciphers: 'list[Enum_Cipher]' = ListField(
length=lambda pkt: pkt['len'],
item_type=EnumField(length=2, namespace=Enum_Cipher),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', ciphers: 'list[Enum_Cipher]') -> 'None': ...
[docs]
@schema_final
class NATTraversalModeParameter(Parameter, code=Enum_Parameter.NAT_TRAVERSAL_MODE):
"""Header schema for HIP ``NAT_TRAVERSAL_MODE`` parameters."""
#: Reserved.
reserved: 'bytes' = PaddingField(length=2)
#: NAT traversal modes.
modes: 'list[Enum_NATTraversal]' = ListField(
length=two_octet_prefix_list_len,
item_type=EnumField(length=2, namespace=Enum_NATTraversal),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', modes: 'list[Enum_NATTraversal]') -> 'None': ...
[docs]
@schema_final
class TransactionPacingParameter(Parameter, code=Enum_Parameter.TRANSACTION_PACING):
"""Header schema for HIP ``TRANSACTION_PACING`` parameters."""
#: Transaction pacing.
min_ta: 'int' = UInt32Field()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', min_ta: 'int') -> 'None': ...
[docs]
@schema_final
class EncryptedParameter(Parameter, code=Enum_Parameter.ENCRYPTED):
"""Header schema for HIP ``ENCRYPTED`` parameters."""
#: Reserved.
reserved: 'bytes' = PaddingField(length=4)
#: Initialization vector.
iv: 'bytes' = ConditionalField(
BytesField(length=16),
lambda pkt: pkt['__cipher__'] in (Enum_Cipher.AES_128_CBC, Enum_Cipher.AES_256_CBC),
)
#: Data.
data: 'bytes' = BytesField(length=encrypted_data_len)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
[docs]
@classmethod
def pre_unpack(cls, packet: 'dict[str, Any]') -> 'None':
"""Prepare ``packet`` data for unpacking process.
Args:
packet: packet data
Notes:
When ``packet`` already carries a resolved ``cipher`` -- as it
does when this schema was built via
:meth:`HIP._make_param_encrypted
<pcapkit.protocols.internet.hip.HIP._make_param_encrypted>`, which
sets it as a plain attribute so ``pack()``'s own
``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.
"""
if 'cipher' in packet:
packet['__cipher__'] = packet.pop('cipher')
return
if 'options' in packet:
cipher_list = cast('list[Data_HIPCipherParameter]',
packet['options'].getlist(Enum_Parameter.HIP_CIPHER))
if not cipher_list:
warn(f'HIP: [ParamNo {Enum_Parameter.ENCRYPTED}] '
'missing HIP_CIPHER parameter', ProtocolWarning)
# raise ProtocolError(f'HIPv{version}: [ParamNo {schema.type}] invalid format')
cipher_id = Enum_Cipher(0xffff)
else:
cipher_ids = [] # type: list[Enum_Cipher]
for cipher in cipher_list:
cipher_ids.extend(cipher.cipher_id)
encrypted_list = cast('list[Data_EncryptedParameter]',
packet['options'].getlist(Enum_Parameter.ENCRYPTED))
encrypted_index = len(encrypted_list)
if encrypted_index >= len(cipher_ids):
warn(f'HIP: [ParamNo {Enum_Parameter.ENCRYPTED}] '
'too many ENCRYPTED parameters', ProtocolWarning)
# raise ProtocolError(f'HIPv{version}: [ParamNo {schema.type}] invalid format')
cipher_id = Enum_Cipher(0xfffe)
else:
cipher_id = cipher_ids[encrypted_index]
else:
warn(f'HIP: [ParamNo {Enum_Parameter.ENCRYPTED}] '
'missing HIP_CIPHER parameter', ProtocolWarning)
cipher_id = Enum_Cipher(0xffff)
packet['__cipher__'] = cipher_id
[docs]
def post_process(self, packet: 'dict[str, Any]') -> 'Schema':
"""Revise ``schema`` data after unpacking process.
Args:
packet: Unpacked data.
Returns:
Revised schema.
"""
self.cipher = packet['__cipher__']
return self
if TYPE_CHECKING:
#: Cipher ID. Not a schema field -- set as a plain attribute, either
#: by :meth:`post_process` after unpacking, or by
#: :meth:`HIP._make_param_encrypted
#: <pcapkit.protocols.internet.hip.HIP._make_param_encrypted>` before
#: packing -- so it is documented here rather than accepted by
#: ``__init__``.
cipher: 'Enum_Cipher'
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes',
iv: 'Optional[bytes]', data: 'bytes') -> 'None': ...
[docs]
@schema_final
class HostIDParameter(Parameter, code=Enum_Parameter.HOST_ID):
"""Header schema for HIP ``HOST_ID`` parameters."""
#: Host ID length.
hi_len: 'int' = UInt16Field()
#: Domain ID type and length.
di_data: 'DIData' = BitField(
length=2,
namespace={
'type': (0, 4),
'len': (4, 12),
},
)
#: Algorithm type.
algorithm: 'Enum_HIAlgorithm' = EnumField(length=2, namespace=Enum_HIAlgorithm)
#: Host ID.
hi: 'bytes | HostIdentity' = SwitchField(selector=host_id_hi_selector)
#: Domain ID.
di: 'bytes' = BytesField(length=lambda pkt: pkt['di_data']['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', hi_len: 'int', di_data: 'DIData',
algorithm: 'Enum_HIAlgorithm', hi: 'bytes | HostIdentity',
di: 'bytes') -> 'None': ...
[docs]
class HostIdentity(EnumSchema[Enum_HIAlgorithm]):
"""Host identity schema."""
[docs]
@schema_final
class ECDSACurveHostIdentity(HostIdentity, code=Enum_HIAlgorithm.ECDSA):
"""Host identity schema with ECDSA curve."""
#: Algorithm curve type.
curve: 'Enum_ECDSACurve' = EnumField(length=2, namespace=Enum_ECDSACurve)
#: Public key.
pub_key: 'bytes' = BytesField(length=lambda pkt: pkt['__length__'])
if TYPE_CHECKING:
def __init__(self, curve: 'Enum_ECDSACurve', pub_key: 'bytes') -> 'None': ...
[docs]
@schema_final
class ECDSALowCurveHostIdentity(HostIdentity, code=Enum_HIAlgorithm.ECDSA_LOW):
"""Host identity schema with ECDSA_LOW curve."""
#: Algorithm curve type.
curve: 'Enum_ECDSALowCurve' = EnumField(length=2, namespace=Enum_ECDSALowCurve)
#: Public key.
pub_key: 'bytes' = BytesField(length=lambda pkt: pkt['__length__'])
if TYPE_CHECKING:
def __init__(self, curve: 'Enum_ECDSALowCurve', pub_key: 'bytes') -> 'None': ...
[docs]
@schema_final
class EdDSACurveHostIdentity(HostIdentity, code=Enum_HIAlgorithm.EdDSA):
"""Host identity schema with EdDSA curve."""
#: Algorithm curve type.
curve: 'Enum_EdDSACurve' = EnumField(length=2, namespace=Enum_EdDSACurve)
#: Public key.
pub_key: 'bytes' = BytesField(length=lambda pkt: pkt['__length__'])
if TYPE_CHECKING:
def __init__(self, curve: 'Enum_EdDSACurve', pub_key: 'bytes') -> 'None': ...
[docs]
@schema_final
class HITSuiteListParameter(Parameter, code=Enum_Parameter.HIT_SUITE_LIST):
"""Header schema for HIP ``HIT_SUITE_LIST`` parameters."""
#: HIT suite IDs.
suites: 'list[Enum_HITSuite]' = ListField(
length=lambda pkt: pkt['len'],
item_type=EnumField(length=1, namespace=Enum_HITSuite),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', suites: 'list[Enum_HITSuite]') -> 'None': ...
[docs]
@schema_final
class CertParameter(Parameter, code=Enum_Parameter.CERT):
"""Header schema for HIP ``CERT`` parameters."""
#: Certificate group.
cert_group: 'Enum_Group' = EnumField(length=1, namespace=Enum_Group)
#: Certificate count.
cert_count: 'int' = UInt8Field()
#: Certificate ID.
cert_id: 'int' = UInt8Field()
#: Certificate type.
cert_type: 'Enum_Certificate' = EnumField(length=1, namespace=Enum_Certificate)
#: Certificate data.
cert: 'bytes' = BytesField(length=lambda pkt: pkt['len'] - 4)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', cert_group: 'Enum_Group', cert_count: 'int',
cert_id: 'int', cert_type: 'Enum_Certificate', cert: 'bytes') -> 'None': ...
[docs]
@schema_final
class NotificationParameter(Parameter, code=Enum_Parameter.NOTIFICATION):
"""Header schema for HIP ``NOTIFICATION`` parameters."""
#: Reserved.
reserved: 'bytes' = PaddingField(length=2)
#: Notify message type.
msg_type: 'Enum_NotifyMessage' = EnumField(length=2, namespace=Enum_NotifyMessage)
#: Notification data.
msg: 'bytes' = BytesField(length=lambda pkt: pkt['len'] - 4)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', msg_type: 'Enum_NotifyMessage', msg: 'bytes') -> 'None': ...
[docs]
@schema_final
class EchoRequestSignedParameter(Parameter, code=Enum_Parameter.ECHO_REQUEST_SIGNED):
"""Header schema for HIP ``ECHO_REQUEST_SIGNED`` parameters."""
#: Opaque data.
opaque: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', opaque: 'bytes') -> 'None': ...
[docs]
@schema_final
class RegInfoParameter(Parameter, code=Enum_Parameter.REG_INFO):
"""Header schema for HIP ``REG_INFO`` parameters."""
#: Minimum lifetime.
min_lifetime: 'int' = UInt8Field()
#: Maximum lifetime.
max_lifetime: 'int' = UInt8Field()
#: Registration types.
reg_info: 'list[Enum_Registration]' = ListField(
length=reg_info_list_len,
item_type=EnumField(length=1, namespace=Enum_Registration),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', min_lifetime: 'int', max_lifetime: 'int',
reg_info: 'list[Enum_Registration]') -> 'None': ...
[docs]
@schema_final
class RegRequestParameter(Parameter, code=Enum_Parameter.REG_REQUEST):
"""Header schema for HIP ``REG_REQUEST`` parameters."""
#: Lifetime.
lifetime: 'int' = UInt8Field()
#: Registration types.
reg_request: 'list[Enum_Registration]' = ListField(
length=registration_type_list_len,
item_type=EnumField(length=1, namespace=Enum_Registration),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', lifetime: 'int', reg_request: 'list[Enum_Registration]') -> 'None': ...
[docs]
@schema_final
class RegResponseParameter(Parameter, code=Enum_Parameter.REG_RESPONSE):
"""Header schema for HIP ``REG_RESPONSE`` parameters."""
#: Lifetime.
lifetime: 'int' = UInt8Field()
#: Registration types.
reg_response: 'list[Enum_Registration]' = ListField(
length=registration_type_list_len,
item_type=EnumField(length=1, namespace=Enum_Registration),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', lifetime: 'int', reg_response: 'list[Enum_Registration]') -> 'None': ...
[docs]
@schema_final
class RegFailedParameter(Parameter, code=Enum_Parameter.REG_FAILED):
"""Header schema for HIP ``REG_FAILED`` parameters."""
#: Lifetime.
lifetime: 'int' = UInt8Field()
#: Registration types.
reg_failed: 'list[Enum_RegistrationFailure]' = ListField(
length=registration_type_list_len,
item_type=EnumField(length=1, namespace=Enum_RegistrationFailure),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', lifetime: 'int', reg_failed: 'list[Enum_RegistrationFailure]') -> 'None': ...
[docs]
@schema_final
class RegFromParameter(Parameter, code=Enum_Parameter.REG_FROM):
"""Header schema for HIP ``REG_FROM`` parameters."""
#: Port.
port: 'int' = UInt16Field()
#: Protocol.
protocol: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
#: Reserved.
reserved: 'bytes' = PaddingField(length=1)
#: Address.
address: 'IPv6Address' = IPv6AddressField()
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', port: 'int', protocol: 'Enum_TransType', address: 'IPv6Address | bytes | int | str') -> 'None': ...
[docs]
@schema_final
class EchoResponseSignedParameter(Parameter, code=Enum_Parameter.ECHO_RESPONSE_SIGNED):
"""Header schema for HIP ``ECHO_RESPONSE_SIGNED`` parameters."""
#: Opaque data.
opaque: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', opaque: 'bytes') -> 'None': ...
[docs]
@schema_final
class SeqDataParameter(Parameter, code=Enum_Parameter.SEQ_DATA):
"""Header schema for HIP ``SEQ_DATA`` parameters."""
#: Sequence number.
seq: 'int' = UInt32Field()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', seq: 'int') -> 'None': ...
[docs]
@schema_final
class AckDataParameter(Parameter, code=Enum_Parameter.ACK_DATA):
"""Header schema for HIP ``ACK_DATA`` parameters."""
#: Acked sequence number.
ack: 'list[int]' = ListField(
length=lambda pkt: pkt['len'],
item_type=UInt32Field(),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', ack: 'list[int]') -> 'None': ...
[docs]
@schema_final
class PayloadMICParameter(Parameter, code=Enum_Parameter.PAYLOAD_MIC):
"""Header schema for HIP ``PAYLOAD_MIC`` parameters."""
#: Next header.
next: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
#: Reserved.
reserved: 'bytes' = PaddingField(length=3)
#: Payload data.
payload: 'bytes' = BytesField(length=4)
#: MIC value.
mic: 'bytes' = BytesField(length=lambda pkt: pkt['len'] - 8)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', next: 'Enum_TransType', payload: 'bytes', mic: 'bytes') -> 'None': ...
[docs]
@schema_final
class TransactionIDParameter(Parameter, code=Enum_Parameter.TRANSACTION_ID):
"""Header schema for HIP ``TRANSACTION_ID`` parameters."""
#: Transaction ID.
id: 'int' = NumberField(length=lambda pkt: pkt['len'], signed=False)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', id: 'int') -> 'None': ...
[docs]
@schema_final
class OverlayIDParameter(Parameter, code=Enum_Parameter.OVERLAY_ID):
"""Header schema for HIP ``OVERLAY_ID`` parameters."""
#: Overlay ID.
id: 'int' = NumberField(length=lambda pkt: pkt['len'], signed=False)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', id: 'int') -> 'None': ...
[docs]
@schema_final
class RouteDstParameter(Parameter, code=Enum_Parameter.ROUTE_DST):
"""Header schema for HIP ``ROUTE_DST`` parameters."""
#: Flags.
flags: 'RouteFlags' = BitField(length=2, namespace={
'symmetric': (0, 1),
'must_follow': (1, 1),
'reserved': (2, 14),
})
#: Reserved.
reserved: 'bytes' = PaddingField(length=2)
#: HIT addresses.
hit: 'list[IPv6Address]' = ListField(
length=lambda pkt: pkt['len'] - 4,
item_type=IPv6AddressField(),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', flags: 'RouteFlags', hit: 'list[str | int | bytes | IPv6Address]') -> 'None': ...
[docs]
@schema_final
class HIPTransportModeParameter(Parameter, code=Enum_Parameter.HIP_TRANSPORT_MODE):
"""Header schema for HIP ``HIP_TRANSPORT_MODE`` parameters."""
#: Port.
port: 'int' = UInt16Field()
#: Mode IDs.
mode: 'list[Enum_Transport]' = ListField(
length=two_octet_prefix_list_len,
item_type=EnumField(length=2, namespace=Enum_Transport),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', port: 'int', mode: 'list[Enum_Transport]') -> 'None': ...
[docs]
@schema_final
class HIPMACParameter(Parameter, code=Enum_Parameter.HIP_MAC):
"""Header schema for HIP ``HIP_MAC`` parameters."""
#: HMAC value.
hmac: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', hmac: 'bytes') -> 'None': ...
[docs]
@schema_final
class HIPMAC2Parameter(Parameter, code=Enum_Parameter.HIP_MAC_2):
"""Header schema for HIP ``HIP_MAC_2`` parameters."""
#: HMAC value.
hmac: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', hmac: 'bytes') -> 'None': ...
[docs]
@schema_final
class HIPSignature2Parameter(Parameter, code=Enum_Parameter.HIP_SIGNATURE_2):
"""Header schema for HIP ``HIP_SIGNATURE_2`` parameters."""
#: Signature algorithm.
algorithm: 'Enum_HIAlgorithm' = EnumField(length=2, namespace=Enum_HIAlgorithm)
#: Signature value.
signature: 'bytes' = BytesField(length=lambda pkt: pkt['len'] - 2)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', algorithm: 'Enum_HIAlgorithm', signature: 'bytes') -> 'None': ...
[docs]
@schema_final
class HIPSignatureParameter(Parameter, code=Enum_Parameter.HIP_SIGNATURE):
"""Header schema for HIP ``HIP_SIGNATURE`` parameters."""
#: Signature algorithm.
algorithm: 'Enum_HIAlgorithm' = EnumField(length=2, namespace=Enum_HIAlgorithm)
#: Signature value.
signature: 'bytes' = BytesField(length=lambda pkt: pkt['len'] - 2)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', algorithm: 'Enum_HIAlgorithm', signature: 'bytes') -> 'None': ...
[docs]
@schema_final
class EchoRequestUnsignedParameter(Parameter, code=Enum_Parameter.ECHO_REQUEST_UNSIGNED):
"""Header schema for HIP ``ECHO_REQUEST_UNSIGNED`` parameters."""
#: Opaque data.
opaque: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', opaque: 'bytes') -> 'None': ...
[docs]
@schema_final
class EchoResponseUnsignedParameter(Parameter, code=Enum_Parameter.ECHO_RESPONSE_UNSIGNED):
"""Header schema for HIP ``ECHO_RESPONSE_UNSIGNED`` parameters."""
#: Opaque data.
opaque: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', opaque: 'bytes') -> 'None': ...
[docs]
@schema_final
class RelayFromParameter(Parameter, code=Enum_Parameter.RELAY_FROM):
"""Header schema for HIP ``RELAY_FROM`` parameters."""
#: Port.
port: 'int' = UInt16Field()
#: Protocol.
protocol: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
#: Reserved.
reserved: 'bytes' = PaddingField(length=1)
#: Address.
address: 'IPv6Address' = IPv6AddressField()
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', port: 'int', protocol: 'Enum_TransType', address: 'str | bytes | int | IPv6Address') -> 'None': ...
[docs]
@schema_final
class RelayToParameter(Parameter, code=Enum_Parameter.RELAY_TO):
"""Header schema for HIP ``RELAY_TO`` parameters."""
#: Port.
port: 'int' = UInt16Field()
#: Protocol.
protocol: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
#: Reserved.
reserved: 'bytes' = PaddingField(length=1)
#: Address.
address: 'IPv6Address' = IPv6AddressField()
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', port: 'int', protocol: 'Enum_TransType', address: 'str | bytes | int | IPv6Address') -> 'None': ...
[docs]
@schema_final
class OverlayTTLParameter(Parameter, code=Enum_Parameter.OVERLAY_TTL):
"""Header schema for HIP ``OVERLAY_TTL`` parameters."""
#: TTL value.
ttl: 'int' = UInt16Field()
#: Reserved.
reserved: 'bytes' = PaddingField(length=2)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', ttl: 'int') -> 'None': ...
[docs]
@schema_final
class RouteViaParameter(Parameter, code=Enum_Parameter.ROUTE_VIA):
"""Header schema for HIP ``ROUTE_VIA`` parameters."""
#: Flags.
flags: 'RouteFlags' = BitField(length=2, namespace={
'symmetric': (0, 1),
'must_follow': (1, 1),
'reserved': (2, 14),
})
#: Reserved.
reserved: 'bytes' = PaddingField(length=2)
#: HIT addresses.
hit: 'list[IPv6Address]' = ListField(
length=lambda pkt: pkt['len'] - 4,
item_type=IPv6AddressField(),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', reserved: 'bytes', flags: 'RouteFlags', hit: 'list[str | bytes | int | IPv6Address]') -> 'None': ...
[docs]
@schema_final
class FromParameter(Parameter, code=Enum_Parameter.FROM):
"""Header schema for HIP ``FROM`` parameters."""
#: Address.
address: 'IPv6Address' = IPv6AddressField()
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', address: 'str | bytes | int | IPv6Address') -> 'None': ...
[docs]
@schema_final
class RVSHMACParameter(Parameter, code=Enum_Parameter.RVS_HMAC):
"""Header schema for HIP ``RVS_HMAC`` parameters."""
#: HMAC value.
hmac: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', hmac: 'bytes') -> 'None': ...
[docs]
@schema_final
class ViaRVSParameter(Parameter, code=Enum_Parameter.VIA_RVS):
"""Header schema for HIP ``VIA_RVS`` parameters."""
#: Address.
address: 'list[IPv6Address]' = ListField(
length=lambda pkt: pkt['len'],
item_type=IPv6AddressField(),
)
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', address: 'list[str | bytes | int | IPv6Address]') -> 'None': ...
[docs]
@schema_final
class RelayHMACParameter(Parameter, code=Enum_Parameter.RELAY_HMAC):
"""Header schema for HIP ``RELAY_HMAC`` parameters."""
#: HMAC value.
hmac: 'bytes' = BytesField(length=lambda pkt: pkt['len'])
#: Padding.
padding: 'bytes' = PaddingField(length=parameter_padding_len)
if TYPE_CHECKING:
def __init__(self, type: 'Enum_Parameter', len: 'int', hmac: 'bytes') -> 'None': ...
[docs]
@schema_final
class HIP(Schema):
"""Header schema for HIP packet."""
#: Next header.
next: 'Enum_TransType' = EnumField(length=1, namespace=Enum_TransType)
#: Header length.
len: 'int' = UInt8Field()
#: Packet type.
pkt: 'PacketType' = BitField(
length=1,
namespace={
'bit_0': (0, 1),
'type': (1, 7),
},
)
#: HIP version.
ver: 'VersionType' = BitField(
length=1,
namespace={
'version': (0, 4),
'reserved': (4, 3),
'bit_1': (7, 1),
},
)
#: Checksum.
checksum: 'bytes' = BytesField(length=2)
#: HIP controls.
control: 'ControlsType' = BitField(
length=2,
namespace={
'reserved': (0, 15),
'anonymous': (15, 1),
},
)
#: Sender's host identity tag.
shit: 'int' = NumberField(length=16, signed=False)
#: Receiver's host identity tag.
rhit: 'int' = NumberField(length=16, signed=False)
#: HIP parameters.
param: 'list[Parameter]' = OptionField(
length=lambda pkt: (pkt['len'] - 4) * 8,
base_schema=Parameter,
type_name='type',
registry=Parameter.registry,
)
#: Payload.
payload: 'bytes' = PayloadField()
if TYPE_CHECKING:
def __init__(self, next: 'Enum_TransType', len: 'int', pkt: 'PacketType',
ver: 'VersionType', checksum: 'bytes', control: 'ControlsType',
shit: 'int', rhit: 'int', param: 'bytes | list[bytes | Parameter]',
payload: 'bytes | ProtocolBase | Schema') -> 'None': ...