import "../setup.ts"; import { stubNetwork } from "../helpers.ts"; import { assert, assertEquals, assertFalse, assertRejects } from "@std/assert"; import { isPrivateAddress, isPrivateHostname, resolvePublicAddress, } from "../../remote/public-address.ts"; Deno.test("isPrivateAddress: private and reserved IPv4 ranges", () => { for ( const ip of [ "0.0.0.0", "10.1.2.3", "127.0.0.1", "100.64.0.1", "100.127.255.255", "169.254.169.254", "172.16.0.1", "172.31.255.255", "192.0.0.8", "192.168.1.1", "198.18.0.1", "224.0.0.1", "255.255.255.255", ] ) { assert(isPrivateAddress(ip), ip); } }); Deno.test("isPrivateAddress: public IPv4 addresses", () => { for ( const ip of [ "8.8.8.8", "93.184.216.34", "100.63.255.255", "100.128.0.0", "172.15.255.255", "172.32.0.0", "192.169.0.1", "223.255.255.255", ] ) { assertFalse(isPrivateAddress(ip), ip); } }); Deno.test("isPrivateAddress: IPv6, including IPv4 carried inside it", () => { for ( const ip of [ "::", "::1", "fc00::1", "fd12:3456::1", "fe80::1%eth0", "fec0::1", "ff02::1", "::ffff:127.0.0.1", "::ffff:7f00:1", "::ffff:10.0.0.1", "64:ff9b::a00:1", // NAT64 of 10.0.0.1 "2002:a00:1::", // 6to4 of 10.0.0.1 "::10.0.0.1", ] ) { assert(isPrivateAddress(ip), ip); } for ( const ip of [ "2606:4700:4700::1111", "::ffff:8.8.8.8", "64:ff9b::808:808", "2002:808:808::", ] ) { assertFalse(isPrivateAddress(ip), ip); } }); Deno.test("isPrivateAddress: anything that isn't an IP is not an address", () => { for ( const s of ["example.com", "1.2.3", "1.2.3.4.5", "256.1.1.1", "1::2::3", ""] ) { assertFalse(isPrivateAddress(s), s); } }); Deno.test("isPrivateHostname: localhost names and bracketed literals", () => { assert(isPrivateHostname(new URL("http://localhost:8000/"))); assert(isPrivateHostname(new URL("http://app.localhost/"))); assert(isPrivateHostname(new URL("http://[::1]/"))); assert(isPrivateHostname(new URL("http://127.0.0.1/"))); // WHATWG URL parsing normalises these to 127.0.0.1 before we see them. assert(isPrivateHostname(new URL("http://0x7f000001/"))); assert(isPrivateHostname(new URL("http://2130706433/"))); assertFalse(isPrivateHostname(new URL("https://example.com/"))); }); Deno.test("resolvePublicAddress: IP literals skip DNS", async () => { using net = stubNetwork(() => new Response()); assertEquals( await resolvePublicAddress(new URL("https://8.8.8.8/")), "8.8.8.8", ); assertEquals( await resolvePublicAddress(new URL("https://[2606:4700::1]/")), "2606:4700::1", ); assertEquals(net.calls.length, 0); }); Deno.test("resolvePublicAddress: refuses private literals without resolving", async () => { await assertRejects( () => resolvePublicAddress(new URL("http://169.254.169.254/latest")), Error, "private", ); }); Deno.test("resolvePublicAddress: a name resolving anywhere private is refused", async () => { using _ = stubNetwork(() => new Response(), { "internal.example": ["10.0.0.5"], "mixed.example": ["93.184.216.34", "127.0.0.1"], "nowhere.example": [], }); await assertRejects( () => resolvePublicAddress(new URL("http://internal.example/")), Error, "resolves to 10.0.0.5", ); await assertRejects( () => resolvePublicAddress(new URL("http://mixed.example/")), Error, "resolves to 127.0.0.1", ); await assertRejects( () => resolvePublicAddress(new URL("http://nowhere.example/")), Error, "Could not resolve", ); assertEquals( await resolvePublicAddress(new URL("http://public.example/")), "93.184.216.34", ); });