IPv6 CIDR notation parsing and utilities.

This module provides CIDR parsing, network calculations, and IP range checking for IPv6 networks. Works with bigint representations to enable efficient IP assignment workflows.

A Cidrv6 stores whichever dialect it was written in, a prefix length (fe80::/10) or a network mask (fe80::/ffc0::), and every operation here accepts both.

Examples

Both dialects parse, a zone rides along, and each writes back as it came

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

const prefixed = parseCidrv6("fe80::%ether1/64");
const masked = parseCidrv6("fe80::/ffff:ffff:ffff:ffff::");

assertEquals(cidrv6Size(prefixed), cidrv6Size(masked));
assertEquals(stringifyCidrv6(prefixed), "fe80::%ether1/64");
assertEquals(stringifyCidrv6(masked), "fe80::/ffff:ffff:ffff:ffff::");

CIDR operations

import { assert, assertEquals } from "@std/assert";
import {
  cidrv6Contains,
  cidrv6FirstAddress,
  cidrv6LastAddress,
  parseCidrv6,
} from "@hertzg/ip/cidrv6";
import { parseAddressv6, stringifyAddressv6 } from "@hertzg/ip/addressv6";

const cidr = parseCidrv6("2001:db8:ffff:ffff:ffff:ffff::/120");
let currentIp = cidrv6FirstAddress(cidr) + 1n;

while (cidrv6Contains(cidr, currentIp)) {
  const assigned = stringifyAddressv6(currentIp);
  currentIp = currentIp + 1n;
  if (currentIp > cidrv6LastAddress(cidr)) break;
}

assert(cidrv6Contains(cidr, parseAddressv6("2001:db8:ffff:ffff:ffff:ffff::1").address));
assertEquals(cidrv6Contains(cidr, parseAddressv6("2001:db9::1").address), false);

Functions

f
cidrv6Contains(
cidr: Cidrv6,
address: bigint
): boolean

Checks if an IPv6 address is contained within a CIDR block.

f
cidrv6ContainsCidr(
outer: Cidrv6,
inner: Cidrv6
): boolean

Checks if one IPv6 CIDR block fully contains another.

f
cidrv6FirstAddress(cidr: Cidrv6): bigint

Returns the first address of a CIDR block.

f
cidrv6Intersect(
a: Cidrv6,
b: Cidrv6
): Cidrv6 | null

Returns the intersection of two IPv6 CIDR blocks.

f
cidrv6LastAddress(cidr: Cidrv6): bigint

Returns the last address of a CIDR block.

f
cidrv6Mask(cidrOrPrefixLength: Cidrv6 | PrefixLengthv6): Maskv6
3 overloads

Creates a network mask from an IPv6 prefix length.

f
cidrv6Merge(cidrs: readonly Cidrv6[]): Cidrv6[]

Merges IPv6 CIDR blocks into the minimal covering set.

f
cidrv6Overlaps(
a: Cidrv6,
b: Cidrv6
): boolean

Checks if two IPv6 CIDR blocks overlap (share at least one address).

f
cidrv6PrefixLength(cidrOrMask: Cidrv6 | Maskv6 | string): PrefixLengthv6
4 overloads

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

f
cidrv6Size(cidrOrPrefixLength: Cidrv6 | PrefixLengthv6): bigint
3 overloads

Returns the total number of IP addresses in a CIDR block.

f
cidrv6Subtract(
a: Cidrv6,
b: Cidrv6
): Cidrv6[]

Subtracts one IPv6 CIDR block from another.

f
compareCidrv6(
a: Cidrv6,
b: Cidrv6
): -1 | 0 | 1

Compares two IPv6 CIDR blocks for sorting.

f
mapFromCidrv4(cidr: Cidrv4): Cidrv6
3 overloads

Converts an IPv4 CIDR block with a prefix length to its IPv4-mapped IPv6 CIDR representation.

f
parseCidrv6(cidr: string): ParsedCidrv6

Parses IPv6 CIDR notation, in either dialect and with an optional zone ID, to a ParsedCidrv6.

f
stringifyCidrv6(cidr: Addressv6 | ParsedAddressv6 | ParsedCidrv6): string

Stringifies an IPv6 CIDR block, or an address, to CIDR notation with the address compressed.

f
stringifyCidrv6Expanded(cidr: Addressv6 | ParsedAddressv6 | ParsedCidrv6): string

Stringifies an IPv6 CIDR block, or an address, to CIDR notation with the address written in full uncompressed colon-hexadecimal.

f
unmapToCidrv4(cidr: Cidrv6): Cidrv4
3 overloads

Converts an IPv4-mapped IPv6 CIDR block with a prefix length to its IPv4 CIDR representation.

Type Aliases

T
Addressv4 = number

An IPv4 address as a 32-bit unsigned integer, 0 to 4294967295. The primitive type is what carries the version: a number is IPv4, a bigint is IPv6 (ADR 0001).

T
Addressv6 = bigint

An IPv6 address as a 128-bit unsigned bigint, 0n to 2n ** 128n - 1n. The primitive type is what carries the version: a bigint is IPv6, a number is IPv4 (ADR 0001).

T
Cidrv4 = PrefixedCidrv4 | MaskedCidrv4

Represents an IPv4 CIDR block.

T
Cidrv6 = PrefixedCidrv6 | MaskedCidrv6

Represents an IPv6 CIDR block.

T
MaskedCidrv4 = { readonly address: Addressv4; readonly mask: Maskv4; readonly prefixLength?: never; }

An IPv4 CIDR block written with a network mask, as in 10.0.0.0/255.0.0.0.

T
MaskedCidrv6 = { readonly address: Addressv6; readonly mask: Maskv6; readonly prefixLength?: never; }

An IPv6 CIDR block written with a network mask, as in 2001:db8::/ffff:ffff::.

T
Maskv4 = number

An IPv4 network mask as a 32-bit unsigned integer, e.g. 0xFFFFFF00 for /24.

T
Maskv6 = bigint

An IPv6 network mask as a 128-bit unsigned bigint, e.g. 0xFFFFFFFFFFFFFFFF0000000000000000n for /64.

T
ParsedAddressv6 = { readonly address: Addressv6; readonly zoneId?: ZoneId; }

What parseAddressv6 returns and what stringifyAddressv6 accepts: the address, plus the zone ID if the notation had one. Read .address for the bare Addressv6; the zone never touches the value, and no operation in this package reads it.

T
ParsedCidrv6 = Cidrv6 & { readonly zoneId?: ZoneId; }

What parseCidrv6 returns and what stringifyCidrv6 accepts: a Cidrv6 in the dialect it was written in, plus the zone ID if the notation had one (fe80::%ether1/64, the form RouterOS and netstat -rn emit for link-local routes). Assignable to Cidrv6, so a parse result goes straight into every cidrv6* operation; none of them reads the zone.

T
PrefixedCidrv4 = { readonly address: Addressv4; readonly prefixLength: PrefixLengthv4; readonly mask?: never; }

An IPv4 CIDR block written with a prefix length, as in 10.0.0.0/8.

T
PrefixedCidrv6 = { readonly address: Addressv6; readonly prefixLength: PrefixLengthv6; readonly mask?: never; }

An IPv6 CIDR block written with a prefix length, as in 2001:db8::/32.

T
PrefixLengthv4 = number

An IPv4 prefix length, the 24 in /24. The range is 0 to 32; it is documented rather than encoded in the type, so prefixLength + 1 stays a PrefixLengthv4 (ADR 0002).

T
PrefixLengthv6 = number

An IPv6 prefix length, the 64 in /64. The range is 0 to 128; it is documented rather than encoded in the type, so prefixLength + 1 stays a PrefixLengthv6 (ADR 0002).

T
ZoneId = string

The zone ID of an address, the interface tail after % in fe80::1%eth0 (RFC 4007 section 11). Carried verbatim by the Parsed* types; never percent-decoded, so %25eth0 is the zone 25eth0.