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
65 changes: 48 additions & 17 deletions pcapkit/protocols/internet/hopopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,37 @@ def _read_opt_type(self, kind: 'int') -> 'tuple[int, bool]':
bin_ = bin(kind)[2:].zfill(8)
return int(bin_[:2], base=2), bool(int(bin_[2], base=2))

@staticmethod
def _hopopt_option_length(schema_len: 'int') -> 'int':
"""Compute a HOPOPT option's whole-option length from its on-the-wire ``Opt Data Len``.

Per :rfc:`8200#section-4.3`, an option's ``Opt Data Len`` field
(what each ``Schema_*Option.len`` here holds) counts *"the length of
the Option Data field of this option, in octets"* -- i.e. it
excludes the Option Type and Opt Data Len fields themselves, so the
whole option, which is what every ``_read_opt_*`` below reports back
as the parsed option's own ``.length``, is two octets more. This is
the exact ``+2``/``-2`` mismatch #398 fixed independently in six
places (see ``Data_PadOption.length`` vs. ``Schema_PadOption.length``
below, at the surviving explanation of that fix); collecting the
read-side half of it into one helper is so a future fix to this
arithmetic only has to happen once. Do NOT drop the ``+ 2``: that is
precisely the mismatch #398 fixed.

Note that only the *stored-length* read-side call sites are
collected here -- most ``_make_opt_*`` methods recompute the wire
``Opt Data Len`` from ``len(value)`` rather than reading a parsed
``.length`` back, so they have nothing to unify against this helper.

Args:
schema_len: raw ``Opt Data Len`` field value, as read off the wire.

Returns:
Whole-option length, in octets, including the Type and Opt Data Len fields.

"""
return schema_len + 2

def _read_hopopt_options(self, length: 'int') -> 'Option':
"""Read HOPOPT options.

Expand Down Expand Up @@ -509,7 +540,7 @@ def _read_opt_none(self, schema: 'Schema_UnassignedOption', *, options: 'Option'
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
data=schema.data,
)
return opt
Expand Down Expand Up @@ -569,7 +600,7 @@ def _read_opt_pad(self, schema: 'Schema_PadOption', *, options: 'Option') -> 'Da
if code == Enum_Option.Pad1:
_size = 1
else:
_size = schema.len + 2
_size = self._hopopt_option_length(schema.len)

opt = Data_PadOption(
type=schema.type,
Expand Down Expand Up @@ -610,7 +641,7 @@ def _read_opt_tun(self, schema: 'Schema_TunnelEncapsulationLimitOption', *, opti
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
limit=schema.limit,
)
return opt
Expand Down Expand Up @@ -644,7 +675,7 @@ def _read_opt_ra(self, schema: 'Schema_RouterAlertOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
value=schema.alert,
)
return opt
Expand Down Expand Up @@ -686,7 +717,7 @@ def _read_opt_calipso(self, schema: 'Schema_CALIPSOOption', *, options: 'Option'
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
domain=schema.domain,
cmpt_len=schema.cmpt_len * 4,
level=schema.level,
Expand Down Expand Up @@ -753,7 +784,7 @@ def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
dpd_type=mode,
tid_type=tid_type,
tid_len=tid_len,
Expand All @@ -768,7 +799,7 @@ def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
dpd_type=mode,
hav=schema.hav,
)
Expand Down Expand Up @@ -811,7 +842,7 @@ def _read_opt_pdm(self, schema: 'Schema_PDMOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
scaledtlr=schema.scaledtlr,
scaledtls=schema.scaledtls,
psntp=schema.psntp,
Expand Down Expand Up @@ -875,7 +906,7 @@ def _read_opt_qs(self, schema: 'Schema_QuickStartOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema_req.len + 2,
length=self._hopopt_option_length(schema_req.len),
func=func,
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
ttl=datetime.timedelta(seconds=schema_req.ttl),
Expand All @@ -889,7 +920,7 @@ def _read_opt_qs(self, schema: 'Schema_QuickStartOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema_rep.len + 2,
length=self._hopopt_option_length(schema_rep.len),
func=func,
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
nonce=schema_rep.nonce['nonce'],
Expand Down Expand Up @@ -933,7 +964,7 @@ def _read_opt_rpl(self, schema: 'Schema_RPLOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
flags=Data_RPLFlags(
down=bool(schema.flags['down']),
rank_err=bool(schema.flags['rank_err']),
Expand Down Expand Up @@ -994,7 +1025,7 @@ def _read_opt_mpl(self, schema: 'Schema_MPLOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
seed_type=kind,
flags=Data_MPLFlags(
max=bool(schema.flags['max']),
Expand Down Expand Up @@ -1032,7 +1063,7 @@ def _read_opt_ilnp(self, schema: 'Schema_ILNPOption', *, options: 'Option') -> '
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
nonce=schema.nonce,
)
return opt
Expand Down Expand Up @@ -1064,7 +1095,7 @@ def _read_opt_lio(self, schema: 'Schema_LineIdentificationOption', *, options: '
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
line_id_len=schema.id_len,
line_id=schema.id,
)
Expand Down Expand Up @@ -1101,7 +1132,7 @@ def _read_opt_jumbo(self, schema: 'Schema_JumboPayloadOption', *, options: 'Opti
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
jumbo_len=schema.jumbo_len,
)
return opt
Expand Down Expand Up @@ -1145,7 +1176,7 @@ def _read_opt_home(self, schema: 'Schema_HomeAddressOption', *, options: 'Option
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
address=schema.addr,
)
return opt
Expand Down Expand Up @@ -1183,7 +1214,7 @@ def _read_opt_ip_dff(self, schema: 'Schema_IPDFFOption', *, options: 'Option') -
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._hopopt_option_length(schema.len),
version=schema.flags['ver'],
flags=Data_DFFFlags(
dup=bool(schema.flags['dup']),
Expand Down
65 changes: 48 additions & 17 deletions pcapkit/protocols/internet/ipv6_opts.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,37 @@ def _read_opt_type(self, kind: 'int') -> 'tuple[int, bool]':
bin_ = bin(kind)[2:].zfill(8)
return int(bin_[:2], base=2), bool(int(bin_[2], base=2))

@staticmethod
def _ipv6_opts_option_length(schema_len: 'int') -> 'int':
"""Compute an IPv6-Opts option's whole-option length from its on-the-wire ``Opt Data Len``.

Per :rfc:`8200#section-4.3`, an option's ``Opt Data Len`` field
(what each ``Schema_*Option.len`` here holds) counts *"the length of
the Option Data field of this option, in octets"* -- i.e. it
excludes the Option Type and Opt Data Len fields themselves, so the
whole option, which is what every ``_read_opt_*`` below reports back
as the parsed option's own ``.length``, is two octets more. This is
the exact ``+2``/``-2`` mismatch #398 fixed independently in six
places (see ``Data_PadOption.length`` vs. ``Schema_PadOption.length``
below, at the surviving explanation of that fix); collecting the
read-side half of it into one helper is so a future fix to this
arithmetic only has to happen once. Do NOT drop the ``+ 2``: that is
precisely the mismatch #398 fixed.

Note that only the *stored-length* read-side call sites are
collected here -- most ``_make_opt_*`` methods recompute the wire
``Opt Data Len`` from ``len(value)`` rather than reading a parsed
``.length`` back, so they have nothing to unify against this helper.

Args:
schema_len: raw ``Opt Data Len`` field value, as read off the wire.

Returns:
Whole-option length, in octets, including the Type and Opt Data Len fields.

"""
return schema_len + 2

def _read_ipv6_opts(self, length: 'int') -> 'Option':
"""Read IPv6-Opts options.

Expand Down Expand Up @@ -520,7 +551,7 @@ def _read_opt_none(self, schema: 'Schema_UnassignedOption', *, options: 'Option'
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
data=schema.data,
)
return opt
Expand Down Expand Up @@ -581,7 +612,7 @@ def _read_opt_pad(self, schema: 'Schema_PadOption', *, options: 'Option') -> 'Da
if code == Enum_Option.Pad1:
_size = 1
else:
_size = schema.len + 2
_size = self._ipv6_opts_option_length(schema.len)

opt = Data_PadOption(
type=schema.type,
Expand Down Expand Up @@ -622,7 +653,7 @@ def _read_opt_tun(self, schema: 'Schema_TunnelEncapsulationLimitOption', *, opti
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
limit=schema.limit,
)
return opt
Expand Down Expand Up @@ -656,7 +687,7 @@ def _read_opt_ra(self, schema: 'Schema_RouterAlertOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
value=schema.alert,
)
return opt
Expand Down Expand Up @@ -698,7 +729,7 @@ def _read_opt_calipso(self, schema: 'Schema_CALIPSOOption', *, options: 'Option'
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
domain=schema.domain,
cmpt_len=schema.cmpt_len * 4,
level=schema.level,
Expand Down Expand Up @@ -765,7 +796,7 @@ def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
dpd_type=mode,
tid_type=tid_type,
tid_len=tid_len,
Expand All @@ -780,7 +811,7 @@ def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
dpd_type=mode,
hav=schema.hav,
)
Expand Down Expand Up @@ -823,7 +854,7 @@ def _read_opt_pdm(self, schema: 'Schema_PDMOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
scaledtlr=schema.scaledtlr,
scaledtls=schema.scaledtls,
psntp=schema.psntp,
Expand Down Expand Up @@ -887,7 +918,7 @@ def _read_opt_qs(self, schema: 'Schema_QuickStartOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema_req.len + 2,
length=self._ipv6_opts_option_length(schema_req.len),
func=func,
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
ttl=datetime.timedelta(seconds=schema_req.ttl),
Expand All @@ -901,7 +932,7 @@ def _read_opt_qs(self, schema: 'Schema_QuickStartOption', *, options: 'Option')
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema_rep.len + 2,
length=self._ipv6_opts_option_length(schema_rep.len),
func=func,
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
nonce=schema_rep.nonce['nonce'],
Expand Down Expand Up @@ -945,7 +976,7 @@ def _read_opt_rpl(self, schema: 'Schema_RPLOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
flags=Data_RPLFlags(
down=bool(schema.flags['down']),
rank_err=bool(schema.flags['rank_err']),
Expand Down Expand Up @@ -1006,7 +1037,7 @@ def _read_opt_mpl(self, schema: 'Schema_MPLOption', *, options: 'Option') -> 'Da
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
seed_type=kind,
flags=Data_MPLFlags(
max=bool(schema.flags['max']),
Expand Down Expand Up @@ -1044,7 +1075,7 @@ def _read_opt_ilnp(self, schema: 'Schema_ILNPOption', *, options: 'Option') -> '
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
nonce=schema.nonce,
)
return opt
Expand Down Expand Up @@ -1076,7 +1107,7 @@ def _read_opt_lio(self, schema: 'Schema_LineIdentificationOption', *, options: '
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
line_id_len=schema.id_len,
line_id=schema.id,
)
Expand Down Expand Up @@ -1113,7 +1144,7 @@ def _read_opt_jumbo(self, schema: 'Schema_JumboPayloadOption', *, options: 'Opti
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
jumbo_len=schema.jumbo_len,
)
return opt
Expand Down Expand Up @@ -1157,7 +1188,7 @@ def _read_opt_home(self, schema: 'Schema_HomeAddressOption', *, options: 'Option
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
address=schema.addr,
)
return opt
Expand Down Expand Up @@ -1195,7 +1226,7 @@ def _read_opt_ip_dff(self, schema: 'Schema_IPDFFOption', *, options: 'Option') -
type=schema.type,
action=Enum_OptionAction.get(schema.type >> 6),
change=bool(schema.type & 0b00100000),
length=schema.len + 2,
length=self._ipv6_opts_option_length(schema.len),
version=schema.flags['ver'],
flags=Data_DFFFlags(
dup=bool(schema.flags['dup']),
Expand Down
Loading
Loading