function cidrv6PrefixLength
cidrv6PrefixLength(mask: Maskv6): PrefixLengthv6

Recovers the prefix length from an IPv6 network mask given as a bigint.

Examples

Recovering prefix lengths from bigints

import { assertEquals } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

assertEquals(cidrv6PrefixLength(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFn), 128);
assertEquals(cidrv6PrefixLength(0xFFFFFFFFFFFFFFFF0000000000000000n), 64);
assertEquals(cidrv6PrefixLength(0xFFFFFFFFFFFF00000000000000000000n), 48);
assertEquals(cidrv6PrefixLength(0xFFFFFFFF000000000000000000000000n), 32);
assertEquals(cidrv6PrefixLength(0n), 0);

Parameters

mask: Maskv6

The network mask as a bigint

Return Type

The prefix length (0-128)

Throws

TypeError

If the mask's one bits are not contiguous from the top

RangeError

If the mask is not in 0n to 2^128 - 1

cidrv6PrefixLength(cidr: Cidrv6): PrefixLengthv6

Returns the prefix length of an IPv6 CIDR block.

A PrefixedCidrv6 gives back the prefix length it stores; a MaskedCidrv6 has its mask converted, which is where this can throw: a mask such as ffff:0:ffff:: describes no prefix length, so a block storing one has no answer here (ADR 0006).

Examples

Both dialects yield the same prefix length

import { assertEquals } from "@std/assert";
import { cidrv6PrefixLength, parseCidrv6 } from "@hertzg/ip/cidrv6";

assertEquals(cidrv6PrefixLength(parseCidrv6("2001:db8::/32")), 32);
assertEquals(
  cidrv6PrefixLength({ address: 0x20010db8n << 96n, mask: 0xFFFFFFFF000000000000000000000000n }),
  32,
);

A non-contiguous mask has no prefix length

import { assertThrows } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

assertThrows(
  () => cidrv6PrefixLength({ address: 0n, mask: 0xFFFF0000FFFF00000000000000000000n }),
  TypeError,
);

Parameters

cidr: Cidrv6

The CIDR block

Return Type

The prefix length (0-128)

Throws

TypeError

If a masked block's mask is not contiguous

RangeError

If a masked block's mask is not a 128-bit unsigned integer

cidrv6PrefixLength(mask: string): PrefixLengthv6

Recovers the prefix length from an IPv6 network mask given in colon-hexadecimal notation.

The string is parsed with the same rules as parseAddressv6 and then interpreted as a mask rather than an address.

Note that IPv6 has no standard netmask notation. RFC 4291 section 2.3 defines exactly one way to write a prefix -- address/prefix-length -- and nothing equivalent to IPv4's dotted netmask. A string like "ffff:ffff:ffff:ffff::" is a well-formed IPv6 address literal whose 128 bits are being read as a mask. It is accepted here because system APIs do report masks that way: POSIX getifaddrs() fills ifa_netmask with a sockaddr_in6, which is what Deno.networkInterfaces() surfaces as netmask: "ffff:ffff:ffff:ffff::". Prefer the prefix length when a source offers one -- those same APIs usually also report cidr.

Examples

Recovering prefix lengths from colon-hexadecimal

import { assertEquals } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

assertEquals(cidrv6PrefixLength("ffff:ffff:ffff:ffff::"), 64);
assertEquals(cidrv6PrefixLength("ffff:ffff::"), 32);
assertEquals(cidrv6PrefixLength("::"), 0);

Parameters

mask: string

The network mask in colon-hexadecimal notation (e.g. "ffff:ffff::")

Return Type

The prefix length (0-128)

Throws

TypeError

If the notation is malformed (bad group, wrong group count), or the mask's one bits are not contiguous from the top

RangeError

If an embedded IPv4 octet is out of range, as in "::1.2.3.256" -- a malformed hex group is a TypeError, not this

cidrv6PrefixLength(cidrOrMask: Cidrv6 | Maskv6 | string): PrefixLengthv6

Recovers the prefix length from an IPv6 CIDR block or network mask.

The inverse of cidrv6Mask. Accepts a Cidrv6 in either dialect, a bigint, or colon-hexadecimal notation.

A CIDR mask is a run of one bits from the most significant end followed by zeros; masks that do not have that shape describe no prefix length at all and are rejected rather than answered with a plausible-looking count of set bits. This is the one place a stored mask is checked, because it is the one call that has no answer for it (ADR 0006).

Examples

Both forms agree

import { assertEquals } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

assertEquals(cidrv6PrefixLength("ffff:ffff:ffff:ffff::"), 64);
assertEquals(cidrv6PrefixLength(0xFFFFFFFFFFFFFFFF0000000000000000n), 64);

Non-contiguous masks throw, in either form

import { assertThrows } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

assertThrows(() => cidrv6PrefixLength(0xFFFF0000FFFF00000000000000000000n), TypeError);
assertThrows(() => cidrv6PrefixLength("ffff:0:ffff::"), TypeError);
assertThrows(() => cidrv6PrefixLength("::ffff:ffff"), TypeError);

Round-trips with cidrv6Mask

import { assertEquals } from "@std/assert";
import { cidrv6Mask, cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

for (let prefixLength = 0; prefixLength <= 128; prefixLength++) {
  assertEquals(cidrv6PrefixLength(cidrv6Mask(prefixLength)), prefixLength);
}

Error handling

import { assertThrows } from "@std/assert";
import { cidrv6PrefixLength } from "@hertzg/ip/cidrv6";

// Wrong shape -- in range, but not a mask
assertThrows(() => cidrv6PrefixLength(0xFFFF0000FFFF00000000000000000000n), TypeError);
assertThrows(() => cidrv6PrefixLength("ffff:0:ffff::"), TypeError);

// Malformed notation
assertThrows(() => cidrv6PrefixLength("gggg::"), TypeError);

// Wrong range -- not a 128-bit unsigned integer at all
assertThrows(() => cidrv6PrefixLength(-1n), RangeError);
assertThrows(() => cidrv6PrefixLength(1n << 128n), RangeError);

Parameters

cidrOrMask: Cidrv6 | Maskv6 | string

A Cidrv6 block, or the network mask as a bigint or colon-hexadecimal notation

Return Type

The prefix length (0-128)

Throws

TypeError

If the mask is not contiguous, or the notation is malformed

RangeError

If the mask is out of range