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
8 changes: 7 additions & 1 deletion pcapkit/protocols/internet/hip.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ class HIP(IPv6_Ext[Data_HIP, Schema_HIP], Internet[Data_HIP, Schema_HIP],
``HIP_CIPHER`` parameters before it, so an AES cipher's IV is read
as the IV, rather than warning of a missing ``HIP_CIPHER`` and
reading the IV as encrypted data (:issue:`2708`).
* A parameter given to :meth:`make` as empty raw octets, which hold no
type, raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`,
rather than being dropped from the header (:issue:`2723`).

.. versionremoved:: 1.6.0

Expand Down Expand Up @@ -965,14 +968,17 @@ def _make_hip_param(self, parameters: 'list[Schema_Parameter | tuple[Enum_Parame
Raises:
ProtocolError: If the code of a ``(code, value)`` pair, or the key
of a parameter given as parsed data, is a name, a :obj:`bool` or
a code its field cannot carry.
a code its field cannot carry, or if a parameter given as raw
octets is empty (:issue:`2723`).

"""
total_length = 0
if isinstance(parameters, list):
parameters_list = [] # type: list[Schema_Parameter | bytes]
for schema in parameters:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'HIPv{version}: invalid parameter: {schema!r} holds no type field')
# :rfc:`7401#section-5.2.1` pads every parameter to a
# multiple of 8 octets, and Header Length counts in those
# units; a raw parameter is taken to omit its padding.
Expand Down
11 changes: 11 additions & 0 deletions pcapkit/protocols/internet/hopopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ class HOPOPT(IPv6_Ext[Data_HOPOPT, Schema_HOPOPT],
Quick-Start report, given the wrong number of octets, raise
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than being
padded or cut to their field (:issue:`2676`).
* An option given to :meth:`make` as empty raw octets, which hold no
type octet, raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`
rather than an :exc:`IndexError` (:issue:`2723`).

.. versionremoved:: 1.6.0

Expand Down Expand Up @@ -645,6 +648,12 @@ def _make_hopopt_options(self, options: 'list[Schema_Option | tuple[Enum_Option
Returns:
Tuple of options and total length of options.

Raises:
ProtocolError: If the type of an option, given in a ``(type,
kwargs)`` pair or as the key of a container, is a name, a
:obj:`bool` or a code its field cannot carry, or if an option
given as raw octets is empty (:issue:`2723`).

Note:
Options given as a :obj:`list` are fresh input: padding options in
it are dropped, and padding is inserted after each option to align
Expand All @@ -666,6 +675,8 @@ def _make_hopopt_options(self, options: 'list[Schema_Option | tuple[Enum_Option
options_list = [] # type: list[Schema_Option | bytes]
for schema in options:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'{self.alias}: invalid option: {schema!r} holds no type octet')
code = Enum_Option.get(schema[0])
if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
continue
Expand Down
8 changes: 7 additions & 1 deletion pcapkit/protocols/internet/ipv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ class IPv4(IP[Data_IPv4, Schema_IPv4],
the option has no room for, rather than cutting it to nine or four,
and :meth:`make` for a checksum that is not two octets, rather than
padding or cutting it (:issue:`2676`).
* An option given to :meth:`make` as empty raw octets, which hold no
type octet, raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`
rather than an :exc:`IndexError` (:issue:`2723`).

.. versionremoved:: 1.6.0

Expand Down Expand Up @@ -882,7 +885,8 @@ def _make_ipv4_options(self, options: 'list[Schema_Option | tuple[Enum_OptionNum
Raises:
ProtocolError: If the type of an option, given in a ``(type,
kwargs)`` pair or as the key of a container, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if an option
given as raw octets is empty (:issue:`2723`).

"""
total_length = 0
Expand All @@ -891,6 +895,8 @@ def _make_ipv4_options(self, options: 'list[Schema_Option | tuple[Enum_OptionNum
if isinstance(options, list):
for schema in options:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'{self.alias}: invalid option: {schema!r} holds no type octet')
code = Enum_OptionNumber.get(schema[0])
if code in (Enum_OptionNumber.NOP, Enum_OptionNumber.EOOL): # ignore padding options by default
continue
Expand Down
11 changes: 11 additions & 0 deletions pcapkit/protocols/internet/ipv6_opts.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ class IPv6_Opts(IPv6_Ext[Data_IPv6_Opts, Schema_IPv6_Opts],
Quick-Start report, given the wrong number of octets, raise
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than being
padded or cut to their field (:issue:`2676`).
* An option given to :meth:`make` as empty raw octets, which hold no
type octet, raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`
rather than an :exc:`IndexError` (:issue:`2723`).

.. versionremoved:: 1.6.0

Expand Down Expand Up @@ -633,6 +636,12 @@ def _make_ipv6_opts(self, options: 'list[Schema_Option | tuple[Enum_Option | int
Returns:
Tuple of options and total length of options.

Raises:
ProtocolError: If the type of an option, given in a ``(type,
kwargs)`` pair or as the key of a container, is a name, a
:obj:`bool` or a code its field cannot carry, or if an option
given as raw octets is empty (:issue:`2723`).

Note:
Options given as a :obj:`list` are fresh input: padding options in
it are dropped, and padding is inserted after each option to align
Expand All @@ -654,6 +663,8 @@ def _make_ipv6_opts(self, options: 'list[Schema_Option | tuple[Enum_Option | int
options_list = [] # type: list[Schema_Option | bytes]
for schema in options:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'{self.alias}: invalid option: {schema!r} holds no type octet')
code = Enum_Option.get(schema[0])
if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
continue
Expand Down
35 changes: 29 additions & 6 deletions pcapkit/protocols/internet/mh.py
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,11 @@ class MH(IPv6_Ext[Data_MH, Schema_MH],
degree that does not fit 24 bits as two's complement, where it masked
it. The option makers check their registry codes and their one-octet
``Option Length`` too (:issue:`2614`).
* An option, sub-option, QoS attribute or CGA extension given to a
maker as empty raw octets, which hold no type, raises
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than being
dropped beside another item or, for most, raising an
:exc:`AttributeError` alone (:issue:`2723`).
* Each enumeration field of :meth:`make` and of the message, option and
sub-option makers, and the type of each option, sub-option, QoS
attribute and CGA extension given to them, takes a member or an
Expand Down Expand Up @@ -8011,13 +8016,16 @@ def _make_mh_options(self, options: 'Option | list[Schema_Option | tuple[Enum_Op
Raises:
ProtocolError: If the type of an option, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if an option
given as raw octets is empty (:issue:`2723`).

"""
if isinstance(options, list):
options_list = [] # type: list[Schema_Option | bytes]
for schema in options:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'{self.alias}: invalid option: {schema!r} holds no type octet')
code = Enum_Option.get(int.from_bytes(schema[0:1], 'big', signed=False))

data = schema # type: Schema_Option | bytes
Expand Down Expand Up @@ -10020,12 +10028,15 @@ def _make_fid_suboptions(
Raises:
ProtocolError: If the type of a sub-option, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if a
sub-option given as raw octets is empty (:issue:`2723`).

"""
if isinstance(suboptions, list):
entries = [] # type: list[Schema_FlowIdentificationSuboption | bytes]
for item in suboptions:
if isinstance(item, bytes) and not item:
raise ProtocolError(f'{self.alias}: invalid sub-option: {item!r} holds no type octet')
if isinstance(item, (bytes, Schema)):
entries.append(cast('Schema_FlowIdentificationSuboption | bytes', item))
else:
Expand Down Expand Up @@ -10441,12 +10452,15 @@ def _make_ani_suboptions(
Raises:
ProtocolError: If the type of a sub-option, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if a
sub-option given as raw octets is empty (:issue:`2723`).

"""
if isinstance(suboptions, list):
entries = [] # type: list[Schema_ANISuboption | bytes]
for item in suboptions:
if isinstance(item, bytes) and not item:
raise ProtocolError(f'{self.alias}: invalid sub-option: {item!r} holds no type octet')
if isinstance(item, (bytes, Schema)):
entries.append(cast('Schema_ANISuboption | bytes', item))
else:
Expand Down Expand Up @@ -10846,12 +10860,15 @@ def _make_qos_attributes(
Raises:
ProtocolError: If the type of an attribute, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if an
attribute given as raw octets is empty (:issue:`2723`).

"""
if isinstance(attributes, list):
entries = [] # type: list[Schema_QoSAttribute | bytes]
for item in attributes:
if isinstance(item, bytes) and not item:
raise ProtocolError(f'{self.alias}: invalid attribute: {item!r} holds no type octet')
if isinstance(item, (bytes, Schema)):
entries.append(cast('Schema_QoSAttribute | bytes', item))
else:
Expand Down Expand Up @@ -11200,12 +11217,15 @@ def _make_lcmp_suboptions(
Raises:
ProtocolError: If the type of a sub-option, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if a
sub-option given as raw octets is empty (:issue:`2723`).

"""
if isinstance(suboptions, list):
entries = [] # type: list[Schema_LMAControlledMAGSuboption | bytes]
for item in suboptions:
if isinstance(item, bytes) and not item:
raise ProtocolError(f'{self.alias}: invalid sub-option: {item!r} holds no type octet')
if isinstance(item, (bytes, Schema)):
entries.append(cast('Schema_LMAControlledMAGSuboption | bytes', item))
else:
Expand Down Expand Up @@ -11658,14 +11678,17 @@ def _make_cga_extensions(self, extensions: 'Extension | list[Schema_CGAExtension
Raises:
ProtocolError: If the type of an extension, given in a ``(type,
kwargs)`` pair or as the key of parsed data, is a name, a
:obj:`bool` or a code its field cannot carry.
:obj:`bool` or a code its field cannot carry, or if an
extension given as raw octets is empty (:issue:`2723`).

"""
total_length = 0
if isinstance(extensions, list):
extensions_list = [] # type: list[Schema_CGAExtension | bytes]
for schema in extensions:
if isinstance(schema, bytes):
if not schema:
raise ProtocolError(f'{self.alias}: invalid CGA extension: {schema!r} holds no type field')
code = Enum_CGAExtension.get(int.from_bytes(schema[0:2], 'big', signed=False))

data = schema # type: Schema_CGAExtension | bytes
Expand Down
39 changes: 27 additions & 12 deletions pcapkit/protocols/misc/pcapng.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,16 +723,21 @@ class PCAPNG(ProtocolBase[Data_PCAPNG, Schema_PCAPNG],

.. versionchanged:: 1.6.0

Each enumeration field of :meth:`make` and of the block and option
makers, and the code of each option and the type of each name
resolution record given to a block maker, takes a member or an
:class:`int` code, resolved with the enumeration's ``get``, an option
code in the block's namespace; a name, a :obj:`bool` for a field wider
than one bit, or a code the field cannot carry raises
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than
resolving against an enumeration inferred from the caller's frame,
writing a different value or raising another exception
(:issue:`2594`).
* Each enumeration field of :meth:`make` and of the block and option
makers, and the code of each option and the type of each name
resolution record given to a block maker, takes a member or an
:class:`int` code, resolved with the enumeration's ``get``, an option
code in the block's namespace; a name, a :obj:`bool` for a field
wider than one bit, or a code the field cannot carry raises
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than
resolving against an enumeration inferred from the caller's frame,
writing a different value or raising another exception
(:issue:`2594`).
* An option or a name resolution record given to a block maker as raw
octets too short to hold its 16-bit code raises
:exc:`~pcapkit.utilities.exceptions.ProtocolError`, rather than
reading empty octets as code 0 and writing an end-of-options or
end-of-records marker for them (:issue:`2723`).

.. versionremoved:: 1.6.0

Expand Down Expand Up @@ -5150,7 +5155,8 @@ def _make_pcapng_options(self, options: 'Option | list[Schema_Option | tuple[Enu
Raises:
ProtocolError: If an option's code is a name, a :obj:`bool`, or a
code the 16-bit option code field cannot carry
(:issue:`2594`).
(:issue:`2594`), or if an option given as raw octets is
shorter than that field (:issue:`2723`).

"""
# an option area kept as captured is written back verbatim
Expand All @@ -5163,6 +5169,10 @@ def _make_pcapng_options(self, options: 'Option | list[Schema_Option | tuple[Enu
options_list = [] # type: list[Schema_Option | bytes]
for schema in options:
if isinstance(schema, bytes):
# NOTE: Octets short of the code field would read as code 0
# and be taken for an opt_endofopt (#2723).
if len(schema) < 2:
raise ProtocolError(f'PCAP-NG: invalid option: {schema!r} holds no whole option code')
code = Enum_OptionType.get(int.from_bytes(schema[0:2], self._byte, signed=False),
namespace=namespace)
if code == Enum_OptionType.opt_endofopt: # moved to the end, written once
Expand Down Expand Up @@ -6630,7 +6640,8 @@ def _make_nrb_records(self, records: 'Record | list[Schema_NameResolutionRecord
Raises:
ProtocolError: If a record's type is a name, a :obj:`bool`, or a
code the 16-bit record type field cannot carry
(:issue:`2594`).
(:issue:`2594`), or if a record given as raw octets is shorter
than that field (:issue:`2723`).

"""
# a record area kept as captured is written back verbatim
Expand All @@ -6643,6 +6654,10 @@ def _make_nrb_records(self, records: 'Record | list[Schema_NameResolutionRecord
records_list = [] # type: list[Schema_NameResolutionRecord | bytes]
for schema in records:
if isinstance(schema, bytes):
# NOTE: Octets short of the type field would read as type 0
# and be taken for an nrb_record_end (#2723).
if len(schema) < 2:
raise ProtocolError(f'PCAP-NG: invalid record: {schema!r} holds no whole record type')
code = Enum_RecordType.get(int.from_bytes(schema[0:2], self._byte, signed=False))
if code == Enum_RecordType.nrb_record_end: # moved to the end, written once
has_record_end = True
Expand Down
8 changes: 8 additions & 0 deletions pcapkit/protocols/transport/dccp.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,12 @@ def _make_dccp_options(self, options: 'list[Schema_Option | tuple[Enum_Option |
Returns:
Tuple of options and total length of options.

Raises:
ProtocolError: If the type of an option, given in a ``(type,
kwargs)`` pair or as the key of a container, is a name, a
:obj:`bool` or a code its field cannot carry, or if an option
given as raw octets is empty (:issue:`2723`).

Note:
The options are emitted in the given order, Padding included, so
that a parsed option list re-emits the same octets. Padding
Expand All @@ -595,6 +601,8 @@ def _make_dccp_options(self, options: 'list[Schema_Option | tuple[Enum_Option |
options_list = [] # type: list[Schema_Option | bytes]
if isinstance(options, list):
for item in options:
if isinstance(item, bytes) and not item:
raise ProtocolError(f'{self.alias}: invalid option: {item!r} holds no type octet')
if isinstance(item, (bytes, Schema)):
options_list.append(item)
else:
Expand Down
Loading
Loading