IP Address Conversion

pcapkit.corekit.schema.ipaddress converts a caller-supplied IP address to an ipaddress object, refusing a bool before ipaddress reads it as an int (#491), for the IP address fields (pcapkit.corekit.fields.ipaddress) and the protocols’ makers alike. It is one of the pcapkit.corekit.schema helpers shared across the schema layer, not part of the header schema framework in pcapkit.protocols.schema; see Choosing Between utilities and corekit.

Added in version 1.6.0: Moved here from pcapkit.corekit.fields.ipaddress, with the guards the IP address fields share (#2674).

Construction Helpers

pcapkit.corekit.schema.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 (cf. _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 #491 guard 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: MH._make_opt_mn_id carries exactly such a check (#469), and #491 is the same defect at every site that lacks one. 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 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_*. Those protocol-level guards answer for the option, alongside siblings that are not about addresses at all – _make_opt_mn_id refuses a bool for every MN-ID subtype, address-typed or not – so none of them 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 no call of this function or of a _make_* in the library sits inside an except for either one specifically.

Added in version 1.5.0.

Internal Definitions

pcapkit.corekit.schema.ipaddress._reject_bool(value, description)[source]

Reject a bool value before it reaches ipaddress.

Parameters:
  • value (object) – Value to check.

  • description (str) – Human-readable description of what value is, used to build the FieldValueError message.

Raises:

FieldValueError – If value is a bool.

Notes

bool is an int subclass, and every conversion here and in pcapkit.corekit.fields.ipaddress ultimately calls ipaddress.ip_address() or ipaddress.ip_interface(), both of which treat any int below 2**32 as IPv4 – so without this guard, True/False are silently accepted as 0.0.0.1/0.0.0.0 (or the equivalent interface) on an IPv4-typed field, with no exception and no warning. On an IPv6-typed field the same conversion happens to raise instead, because the resulting IPv4Address’s version mismatches – and that asymmetry is exactly what let this slip past #469’s otherwise equivalent guard for MH._make_opt_mn_id (cf. #491).

Every caller checks this before dispatching on the value’s type, for the same placement reason #469 gives: a correct check in the wrong position does not fire.

Guarding the field classes is necessary but not sufficient, because a _make_* that must know the address family before it can build the schema converts the argument itself and so never hands the fields a bool at all. parse_ip_address() is where those callers reach this guard (cf. #508).