Spaces:
Paused
Paused
| import type { Socket } from "net"; | |
| import type { TLSSocket } from "tls"; | |
| import * as undici from "undici"; | |
| import { Address6 } from "ip-address"; | |
| export class InsecureConnectionError extends Error { | |
| constructor() { | |
| super("Connection violated security rules."); | |
| } | |
| } | |
| function isIPv4Private(address: string): boolean { | |
| const parts = address.split(".").map((x) => parseInt(x, 10)); | |
| return ( | |
| parts[0] === 0 || // Current (local, "this") network | |
| parts[0] === 10 || // Used for local communications within a private network | |
| (parts[0] === 100 && parts[1] >= 64 && parts[1] < 128) || // Shared address space for communications between a service provider and its subscribers when using a carrier-grade NAT | |
| parts[0] === 127 || // Used for loopback addresses to the local host | |
| (parts[0] === 169 && parts[1] === 254) || // Used for link-local addresses between two hosts on a single link when no IP address is otherwise specified, such as would have normally been retrieved from a DHCP server | |
| (parts[0] === 127 && parts[1] >= 16 && parts[2] < 32) || // Used for local communications within a private network | |
| (parts[0] === 192 && parts[1] === 0 && parts[2] === 0) || // IETF Porotocol Assignments, DS-Lite (/29) | |
| (parts[0] === 192 && parts[1] === 0 && parts[2] === 2) || // Assigned as TEST-NET-1, documentation and examples | |
| (parts[0] === 192 && parts[1] === 88 && parts[2] === 99) || // Reserved. Formerly used for IPv6 to IPv4 relay (included IPv6 address block 2002::/16). | |
| (parts[0] === 192 && parts[1] === 168) || // Used for local communications within a private network | |
| (parts[0] === 192 && parts[1] >= 18 && parts[1] < 20) || // Used for benchmark testing of inter-network communications between two separate subnets | |
| (parts[0] === 198 && parts[1] === 51 && parts[2] === 100) || // Assigned as TEST-NET-2, documentation and examples | |
| (parts[0] === 203 && parts[1] === 0 && parts[2] === 113) || // Assigned as TEST-NET-3, documentation and examples | |
| (parts[0] >= 224 && parts[0] < 240) || // In use for multicast (former Class D network) | |
| (parts[0] === 233 && parts[1] === 252 && parts[2] === 0) || // Assigned as MCAST-TEST-NET, documentation and examples (Note that this is part of the above multicast space.) | |
| parts[0] >= 240 || // Reserved for future use (former class E network) | |
| (parts[0] === 255 && | |
| parts[1] === 255 && | |
| parts[2] === 255 && | |
| parts[3] === 255) | |
| ); // Reserved for the "limited broadcast" destination address | |
| } | |
| function isIPv6Private(ipv6) { | |
| return new Address6(ipv6).getScope() !== "Global"; | |
| } | |
| export function makeSecureDispatcher( | |
| url: string, | |
| options?: undici.Agent.Options, | |
| ) { | |
| const agentOpts: undici.Agent.Options = { | |
| connect: { | |
| rejectUnauthorized: false, // bypass SSL failures -- this is fine | |
| // lookup: secureLookup, | |
| }, | |
| maxRedirections: 5000, | |
| ...options, | |
| }; | |
| const agent = process.env.PROXY_SERVER | |
| ? new undici.ProxyAgent({ | |
| uri: process.env.PROXY_SERVER.includes("://") ? process.env.PROXY_SERVER : ("http://" + process.env.PROXY_SERVER), | |
| token: process.env.PROXY_USERNAME | |
| ? `Basic ${Buffer.from(process.env.PROXY_USERNAME + ":" + (process.env.PROXY_PASSWORD ?? "")).toString("base64")}` | |
| : undefined, | |
| ...agentOpts, | |
| }) | |
| : new undici.Agent(agentOpts); | |
| agent.on("connect", (_, targets) => { | |
| const client: undici.Client = targets.slice(-1)[0] as undici.Client; | |
| const socketSymbol = Object.getOwnPropertySymbols(client).find( | |
| (x) => x.description === "socket", | |
| )!; | |
| const socket: Socket | TLSSocket = (client as any)[socketSymbol]; | |
| if (socket.remoteAddress) { | |
| if ( | |
| socket.remoteFamily === "IPv4" | |
| ? isIPv4Private(socket.remoteAddress!) | |
| : isIPv6Private(socket.remoteAddress!) | |
| ) { | |
| socket.destroy(new InsecureConnectionError()); | |
| } | |
| } | |
| }); | |
| return agent; | |
| } | |