IP Address Fields

Changed in version 1.5.0: Every field here rejects a bool with FieldValueError, where an IPv4 field packed True and False as 0.0.0.1 and 0.0.0.0 (#491).

IP Addresses

class pcapkit.corekit.fields.ipaddress.IPv4AddressField(default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function IPv4AddressField.<lambda>>)[source]

Bases: _IPAddressField[IPv4Address]

IPv4 address value for protocol fields.

Parameters:
property version: Literal[4]

IP version number.

class pcapkit.corekit.fields.ipaddress.IPv6AddressField(default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function IPv6AddressField.<lambda>>)[source]

Bases: _IPAddressField[IPv6Address]

IPv6 address value for protocol fields.

Parameters:
property version: Literal[6]

IP version number.

IP Interface

class pcapkit.corekit.fields.ipaddress.IPv4InterfaceField(default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function IPv4InterfaceField.<lambda>>)[source]

Bases: _IPInterfaceField[IPv4Interface]

IPv4 interface value for protocol fields.

Parameters:

Changed in version 1.5.0: A mask that is not a contiguous netmask unpacks to an IPv4Interface subclass that keeps its four octets, where a hostmask-shaped one was read as a prefix length and any other raised (#1294).

property version: Literal[4]

IP version number.

pre_process(value, packet)[source]

Process field value before packing.

Parameters:
Return type:

bytes

Returns:

Processed field value.

Raises:

FieldValueError – If value is a bool (c.f. _reject_bool()), is not a valid IP interface, or is the wrong IP version for this field.

Notes

A string means what ipaddress.ip_interface() says it means, so '10.0.0.1/0.0.0.255' is the hostmask spelling of /24. Only a string the stdlib rejects is read with its mask taken literally: a dotted mask that is neither a netmask nor a hostmask, such as '10.0.0.1/255.0.255.0', or eight hex digits, such as '10.0.0.1/0x000000ff'. Those are the forms str() gives a _RawMaskIPv4Interface.

post_process(value, packet)[source]

Process field value after parsing (unpacking).

Parameters:
Return type:

IPv4Interface

Returns:

Processed field value.

Raises:

FieldValueError – If the resulting interface is the wrong IP version for this field. The eight octets cannot actually fail to convert here – they are always exactly 8 octets, fixed by this field’s length, any four octets are a valid address, and a mask that is not a netmask is kept as given – but the conversion is still wrapped for consistency with the rest of this module.

Notes

The trailing four octets are a dotted netmask, as written by pre_process() – not a prefix length as in IPv6InterfaceField.post_process(). When they are not a contiguous netmask, the value is a _RawMaskIPv4Interface that keeps them as given, rather than an interface the stdlib would reinterpret (0.0.0.255 as the hostmask of /24).

class pcapkit.corekit.fields.ipaddress.IPv6InterfaceField(default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function IPv6InterfaceField.<lambda>>)[source]

Bases: _IPInterfaceField[IPv6Interface]

IPv6 interface value for protocol fields.

Parameters:
property version: Literal[6]

IP version number.

pre_process(value, packet)[source]

Process field value before packing.

Parameters:
Return type:

bytes

Returns:

Processed field value.

Raises:

FieldValueError – If value is a bool (c.f. _reject_bool()), is not a valid IP interface, or is the wrong IP version for this field.

post_process(value, packet)[source]

Process field value after parsing (unpacking).

Parameters:
Return type:

IPv6Interface

Returns:

Processed field value.

Raises:

FieldValueError – If the trailing octet is not a valid IPv6 prefix length, i.e. greater than 128, or if the resulting interface is the wrong IP version for this field. Neither the leading sixteen octets nor the final ipaddress.ip_interface() call can actually fail here – the former is always exactly 16 octets, fixed by this field’s length, and any such octet string is a valid address; the latter is only ever reached once the prefix length has already been checked above, and any prefix length in 0..128 is valid. Both conversions are still wrapped for consistency with the rest of this module.

Notes

The trailing octet is the prefix length as a binary integer, as written by pre_process() – not a dotted netmask as in IPv4InterfaceField.post_process().

Construction Helpers

pcapkit.corekit.fields.ipaddress.parse_ip_address(value, description, version=None)[source]

Convert a caller-supplied address on the construction path.

Parameters:
  • value (IPv4Address | IPv6Address | bytes | int | str) – Address as the caller gave it – an ipaddress object, which is returned unchanged, or anything ipaddress accepts.

  • description (str) – Human-readable description of what value is, used to build the FieldValueError message. Callers in a protocol should carry their usual context into it, e.g. f'{self.alias}: [OptNo {type}] care-of address'.

  • version (int | None) – IP version to demand, 4 or 6, or None to take whichever family value describes. Pass it where the wire format fixes the family, so that an int is widened to the right one – 258 is ::102 for version=6 but 0.0.1.2 for ipaddress.ip_address().

Return type:

IPv4Address | IPv6Address

Returns:

The converted address.

Raises:

FieldValueError – If value is a bool (c.f. _reject_bool()), is not a valid IP address, or is not of version.

Notes

This is the sanctioned way for a _make_* method to turn a caller-supplied address into an ipaddress object, and it exists because doing it with ipaddress.ip_address() directly is the defect #508 found: a _make_* that has to know the address family before it can build the schema – to size an option whose length is the only thing on the wire that carries the family – must convert the argument itself, and that conversion happens before the schema, so it launders a bool into an IPv4Address that the guard added for #491 in _IPAddressField.pre_process() can then only see as a legitimate address: True / False become 0.0.0.1 / 0.0.0.0 – or ::1 / :: where the wire format fixes the family as IPv6 – without complaint.

Routing every one of them through here rather than giving each its own isinstance() check is the whole point: #469 added exactly such a check to MH._make_opt_mn_id, and #491 was the same defect surviving at every site that had not been thought of. A guard that has to be remembered per call site is a guard that will be forgotten at the next one.

The bool rejection is the first statement here, ahead of any dispatch on the value’s type, for the placement reason #469 gives and _reject_bool() repeats.

This raises FieldValueError and not ProtocolError, which is deliberate even though two sibling guards for the same mistake – MH._make_opt_mn_id from #469 and ESP's SecurityAssociation from #491 – raise the latter. The layer decides: this is a field-level conversion, so it answers with what _IPAddressField.pre_process() answers with for the identical value, and a caller sees one exception whether the bool reached the field through the schema or through a _make_*. The two protocol-level guards answer for the option, alongside siblings that are not about addresses at all – _make_opt_mn_id refuses a bool for all eight MN-ID subtypes, only one of which is address-typed – so neither can route through here without losing the subtype-aware message that is the point of it. Both exception classes derive from BaseError and ValueError, so the difference is invisible to except BaseError and except ValueError, and nothing in the library catches either one specifically.

Added in version 1.5.0.

Internal Definitions

class pcapkit.corekit.fields.ipaddress._IPField(length, default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function Field.<lambda>>)[source]

Bases: Field[_T], Generic[_T]

Internal IP related value for protocol fields.

Parameters:
abstract property version: int

IP version number.

class pcapkit.corekit.fields.ipaddress._IPAddressField(length, default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function Field.<lambda>>)[source]

Bases: _IPField[_AT]

Internal IP address value for protocol fields.

Parameters:
pre_process(value, packet)[source]

Process field value before packing.

Parameters:
Return type:

bytes

Returns:

Processed field value.

Raises:

FieldValueError – If value is a bool (c.f. _reject_bool()), is not a valid IP address, or is the wrong IP version for this field.

post_process(value, packet)[source]

Process field value after parsing (unpacking).

Parameters:
Return type:

TypeVar(_AT, IPv4Address, IPv6Address)

Returns:

Processed field value.

Raises:

FieldValueError – If value is the wrong IP version for this field. value cannot actually fail the underlying ipaddress.ip_address() conversion here – it is always exactly 4 or 16 octets, fixed by this field’s length, and any such octet string is a valid address – but the conversion is still wrapped for consistency with the rest of this module.

class pcapkit.corekit.fields.ipaddress._IPInterfaceField(length, default=<pcapkit.corekit.sentinels.NoValueType object>, callback=<function Field.<lambda>>)[source]

Bases: _IPField[_IT]

Internal IP interface value for protocol fields.

Parameters:

Type Variables

pcapkit.corekit.fields.ipaddress._T: ipaddress.IPv4Address | ipaddress.IPv6Address | ipaddress.IPv4Interface | ipaddress.IPv6Interface
pcapkit.corekit.fields.ipaddress._AT: ipaddress.IPv4Address | ipaddress.IPv6Address
pcapkit.corekit.fields.ipaddress._IT: ipaddress.IPv4Interface | ipaddress.IPv6Interface