| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function isBlockedIpv4(a: number, b: number, c: number): boolean { |
| if (a === 0) return true; |
| if (a === 10) return true; |
| if (a === 100 && b >= 64 && b <= 127) return true; |
| if (a === 127) return true; |
| if (a === 169 && b === 254) return true; |
| if (a === 172 && b >= 16 && b <= 31) return true; |
| if (a === 192 && b === 0 && c === 0) return true; |
| if (a === 192 && b === 0 && c === 2) return true; |
| if (a === 192 && b === 88 && c === 99) return true; |
| if (a === 192 && b === 168) return true; |
| if (a === 198 && (b === 18 || b === 19)) return true; |
| if (a === 198 && b === 51 && c === 100) return true; |
| if (a === 203 && b === 0 && c === 113) return true; |
| if (a >= 224) return true; |
| return false; |
| } |
|
|
| function isBlockedDottedIpv4(addr: string): boolean { |
| const parts = addr.split('.').map(Number); |
| if (parts.length !== 4 || parts.some(part => !Number.isInteger(part) || part < 0 || part > 255)) { |
| return false; |
| } |
| const [a, b, c] = parts as [number, number, number, number]; |
| return isBlockedIpv4(a, b, c); |
| } |
|
|
| |
| |
| function isBlockedEmbeddedIpv4(hi: number, lo: number): boolean { |
| return isBlockedIpv4((hi >> 8) & 0xff, hi & 0xff, (lo >> 8) & 0xff); |
| } |
|
|
| |
| |
| |
| function expandIpv6(input: string): number[] | null { |
| let s = input; |
| const pct = s.indexOf('%'); |
| if (pct !== -1) s = s.slice(0, pct); |
| if (!s.includes(':')) return null; |
|
|
| |
| const dotMatch = s.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/); |
| if (dotMatch) { |
| const dotted = dotMatch[1]; |
| if (dotted === undefined) return null; |
| const octets = dotted.split('.').map(Number); |
| if (octets.length !== 4 || octets.some(o => !Number.isInteger(o) || o < 0 || o > 255)) return null; |
| const [o0, o1, o2, o3] = octets as [number, number, number, number]; |
| const hextets = [ |
| (((o0 << 8) | o1) >>> 0).toString(16), |
| (((o2 << 8) | o3) >>> 0).toString(16), |
| ].join(':'); |
| s = s.slice(0, s.length - dotted.length) + hextets; |
| } |
|
|
| const halves = s.split('::'); |
| if (halves.length > 2) return null; |
|
|
| const parseGroups = (part: string): number[] | null => { |
| if (part === '') return []; |
| const out: number[] = []; |
| for (const g of part.split(':')) { |
| if (!/^[0-9a-f]{1,4}$/.test(g)) return null; |
| out.push(parseInt(g, 16)); |
| } |
| return out; |
| }; |
|
|
| if (halves.length === 2) { |
| const head = parseGroups(halves[0] ?? ''); |
| const tail = parseGroups(halves[1] ?? ''); |
| if (head === null || tail === null) return null; |
| const missing = 8 - head.length - tail.length; |
| if (missing < 1) return null; |
| return [...head, ...new Array(missing).fill(0), ...tail]; |
| } |
|
|
| const groups = parseGroups(s); |
| if (groups === null || groups.length !== 8) return null; |
| return groups; |
| } |
|
|
| export function isBlockedResolvedAddress(address: string): boolean { |
| const normalized = address.trim().toLowerCase().replace(/^\[|\]$/g, ''); |
|
|
| |
| if (/^\d+\.\d+\.\d+\.\d+$/.test(normalized)) { |
| return isBlockedDottedIpv4(normalized); |
| } |
|
|
| const groups = expandIpv6(normalized); |
| if (!groups) return false; |
| const [g0, g1, g2, , , g5, g6, g7] = groups as |
| [number, number, number, number, number, number, number, number]; |
|
|
| |
| const highSevenZero = groups.slice(0, 7).every(part => part === 0); |
| if (highSevenZero && (g7 === 0 || g7 === 1)) return true; |
|
|
| |
| if ((g0 & 0xfe00) === 0xfc00) return true; |
| if ((g0 & 0xffc0) === 0xfe80) return true; |
| if ((g0 & 0xffc0) === 0xfec0) return true; |
| if ((g0 & 0xff00) === 0xff00) return true; |
| if (g0 === 0x2001 && g1 === 0x0db8) return true; |
|
|
| |
| if (groups.slice(0, 5).every(part => part === 0) && g5 === 0xffff) { |
| return isBlockedEmbeddedIpv4(g6, g7); |
| } |
| if (g0 === 0x64 && g1 === 0xff9b && groups.slice(2, 6).every(part => part === 0)) { |
| return isBlockedEmbeddedIpv4(g6, g7); |
| } |
| if (groups.slice(0, 6).every(part => part === 0)) { |
| return isBlockedEmbeddedIpv4(g6, g7); |
| } |
| if (g0 === 0x2002) { |
| return isBlockedEmbeddedIpv4(g1, g2); |
| } |
|
|
| return false; |
| } |
|
|