IPv4 CIDR Range Matcher

Convert IPv4 addresses to integers and test membership in CIDR blocks for allowlists, proxies and rate limits.

TypescriptSecurity Boundaries

Code

snippet
export interface ParsedCidr {
  network: number;
  mask: number;
  prefix: number;
}

export function ipv4ToInt(address: string): number {
  const parts = address.split(".");
  if (parts.length !== 4) throw new TypeError("invalid IPv4 address: " + address);
  let value = 0;
  for (const part of parts) {
    if (!/^\d{1,3}$/.test(part)) throw new TypeError("invalid IPv4 octet: " + part);
    if (part.length > 1 && part.startsWith("0")) throw new RangeError("leading zeros are not allowed");
    const octet = Number(part);
    if (octet > 255) throw new RangeError("IPv4 octet out of range: " + part);
    value = value * 256 + octet;
  }
  return value >>> 0;
}

export function parseCidr(cidr: string): ParsedCidr {
  const parts = cidr.split("/");
  if (parts.length !== 2) throw new SyntaxError("CIDR must contain one slash");
  const address = parts[0]!;
  const prefix = Number(parts[1]!);
  if (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) {
    throw new RangeError("CIDR prefix must be an integer between 0 and 32");
  }
  const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
  return { network: (ipv4ToInt(address) & mask) >>> 0, mask, prefix };
}

export function isIpInCidr(address: string, cidr: string): boolean {
  const { network, mask } = parseCidr(cidr);
  return ((ipv4ToInt(address) & mask) >>> 0) === network;
}