refactor(net-policy): use ipaddr helpers

This commit is contained in:
Peter Steinberger
2026-07-13 21:57:28 +01:00
parent f1331bcea2
commit 350d455d4b

View File

@@ -147,34 +147,6 @@ function isNumericIpv4LiteralPart(value: string): boolean {
return /^[0-9]+$/.test(value) || /^0x[0-9a-f]+$/i.test(value);
}
function parseIpv6WithEmbeddedIpv4(raw: string): ipaddr.IPv6 | undefined {
if (!raw.includes(":") || !raw.includes(".")) {
return undefined;
}
const match = /^(.*:)([^:%]+(?:\.[^:%]+){3})(%[0-9A-Za-z]+)?$/i.exec(raw);
if (!match) {
return undefined;
}
const [, prefix, embeddedIpv4, zoneSuffix = ""] = match;
if (prefix === undefined || embeddedIpv4 === undefined) {
return undefined;
}
if (!ipaddr.IPv4.isValidFourPartDecimal(embeddedIpv4)) {
return undefined;
}
const [a, b, c, d] = embeddedIpv4.split(".").map((part) => Number.parseInt(part, 10));
if (a === undefined || b === undefined || c === undefined || d === undefined) {
return undefined;
}
const high = ((a << 8) | b).toString(16);
const low = ((c << 8) | d).toString(16);
const normalizedIpv6 = `${prefix}${high}:${low}${zoneSuffix}`;
if (!ipaddr.IPv6.isValid(normalizedIpv6)) {
return undefined;
}
return ipaddr.IPv6.parse(normalizedIpv6);
}
/** Type guard for parsed IPv4 addresses. */
export function isIpv4Address(address: ParsedIpAddress): address is ipaddr.IPv4 {
return address.kind() === "ipv4";
@@ -209,16 +181,9 @@ export function parseCanonicalIpAddress(raw: string | undefined): ParsedIpAddres
if (!normalized) {
return undefined;
}
if (ipaddr.IPv4.isValid(normalized)) {
if (!ipaddr.IPv4.isValidFourPartDecimal(normalized)) {
return undefined;
}
return ipaddr.IPv4.parse(normalized);
}
if (ipaddr.IPv6.isValid(normalized)) {
return ipaddr.IPv6.parse(normalized);
}
return parseIpv6WithEmbeddedIpv4(normalized);
const isCanonical =
ipaddr.IPv4.isValidFourPartDecimal(normalized) || ipaddr.IPv6.isValid(normalized);
return isCanonical ? ipaddr.parse(normalized) : undefined;
}
/** Parses canonical IP literals plus legacy IPv4 forms needed for SSRF checks. */
@@ -227,10 +192,7 @@ export function parseLooseIpAddress(raw: string | undefined): ParsedIpAddress |
if (!normalized) {
return undefined;
}
if (ipaddr.isValid(normalized)) {
return ipaddr.parse(normalized);
}
return parseIpv6WithEmbeddedIpv4(normalized);
return ipaddr.isValid(normalized) ? ipaddr.parse(normalized) : undefined;
}
/** Normalizes canonical IP literals and maps IPv4-mapped IPv6 addresses to IPv4 text. */
@@ -245,15 +207,8 @@ export function normalizeIpAddress(raw: string | undefined): string | undefined
/** True only for canonical four-part dotted-decimal IPv4 literals. */
export function isCanonicalDottedDecimalIPv4(raw: string | undefined): boolean {
const trimmed = normalizeOptionalString(raw);
if (!trimmed) {
return false;
}
const normalized = stripIpv6Brackets(trimmed);
if (!normalized) {
return false;
}
return ipaddr.IPv4.isValidFourPartDecimal(normalized);
const normalized = normalizeIpParseInput(raw);
return normalized !== undefined && ipaddr.IPv4.isValidFourPartDecimal(normalized);
}
/** Detects legacy numeric IPv4 forms that canonical parsing deliberately rejects. */
@@ -362,20 +317,12 @@ export function isBlockedSpecialUseIpv6Address(
/** True for canonical IPv4 literals in RFC 1918 private ranges. */
export function isRfc1918Ipv4Address(raw: string | undefined): boolean {
const parsed = parseCanonicalIpAddress(raw);
if (!parsed || !isIpv4Address(parsed)) {
return false;
}
return parsed.range() === "private";
return parseCanonicalIpAddress(raw)?.range() === "private";
}
/** True for canonical IPv4 literals in the carrier-grade NAT range. */
export function isCarrierGradeNatIpv4Address(raw: string | undefined): boolean {
const parsed = parseCanonicalIpAddress(raw);
if (!parsed || !isIpv4Address(parsed)) {
return false;
}
return parsed.range() === "carrierGradeNat";
return parseCanonicalIpAddress(raw)?.range() === "carrierGradeNat";
}
/** Applies the SSRF block policy for parsed IPv4 special-use ranges. */
@@ -445,26 +392,13 @@ export function isIpInCidr(ip: string, cidr: string): boolean {
);
}
let parsedCidr: [ParsedIpAddress, number];
try {
parsedCidr = ipaddr.parseCIDR(candidate);
} catch {
return false;
}
const [baseAddress, prefixLength] = parsedCidr;
const comparableBase = normalizeIpv4MappedAddress(baseAddress);
if (comparableIp.kind() !== comparableBase.kind()) {
return false;
}
try {
if (isIpv4Address(comparableIp) && isIpv4Address(comparableBase)) {
return comparableIp.match([comparableBase, prefixLength]);
}
if (isIpv6Address(comparableIp) && isIpv6Address(comparableBase)) {
return comparableIp.match([comparableBase, prefixLength]);
}
return false;
const [baseAddress, prefixLength] = ipaddr.parseCIDR(candidate);
const comparableBase = normalizeIpv4MappedAddress(baseAddress);
return (
comparableIp.kind() === comparableBase.kind() &&
comparableIp.match([comparableBase, prefixLength])
);
} catch {
return false;
}