(hostname: string)
| 84 | // first non-empty group instead lets loopback and metadata addresses past a |
| 85 | // guard whose whole purpose is blocking them. |
| 86 | const parseIpv6 = (hostname: string): ReadonlyArray<number> | null => { |
| 87 | if (!hostname.includes(":")) return null; |
| 88 | // node:dns returns link-local addresses with their interface scope |
| 89 | // ("fe80::1%eth0"); the zone is not part of the address being classified. |
| 90 | const [head, tail, ...extra] = hostname.replace(/%.*$/, "").split("::"); |
| 91 | if (extra.length > 0) return null; |
| 92 | |
| 93 | // The head half ends the address only when there is no "::" after it. |
| 94 | const high = parseIpv6Groups(head, tail === undefined); |
| 95 | if (high === null) return null; |
| 96 | if (tail === undefined) return high.length === 8 ? high : null; |
| 97 | |
| 98 | const low = parseIpv6Groups(tail, true); |
| 99 | if (low === null) return null; |
| 100 | const elided = 8 - high.length - low.length; |
| 101 | if (elided < 1) return null; |
| 102 | return [...high, ...Array<number>(elided).fill(0), ...low]; |
| 103 | }; |
| 104 | |
| 105 | const isBlockedIpv4 = ([a, b]: readonly [number, number, number, number]): boolean => |
| 106 | a === 0 || |
no test coverage detected