Ctrl K
ComunidadGuías…

electron/egress-addresses.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Which kind of address a browser connection would reach: the one list My Cloud's egress gate and a lent computer's
// own check both use.
//
// The address ranges, the NAT64 and 6to4 unwrapping and this machine's own addresses are adapted from
// pingdotgg/t3code@00cdceb1 apps/server/src/htmlRender/publicProxy.ts, MIT License, Copyright (c) 2026
// T3 Tools Inc. (full text in third_party/t3-code/LICENSE); modified: an address gets a class instead of
// local-or-public, cloud metadata addresses are a class of their own, and a machine's own networks are a list too.
import { BlockList, isIP } from "node:net";
import { networkInterfaces } from "node:os";

const family = (address) => (isIP(address) === 6 ? "ipv6" : "ipv4");

function subnets(entries) {
  const list = new BlockList();
  for (const [network, prefix] of entries) list.addSubnet(network, prefix, family(network));
  return list;
}

const LOOPBACK = subnets([["127.0.0.0", 8], ["::1", 128]]);
// ::/96 (IPv4-compatible, which also holds the unspecified address), local-use NAT64 and Teredo carry an
// IPv4 address a translator may route to without checking it.
const RESERVED = subnets([
  ["0.0.0.0", 8], ["198.18.0.0", 15], ["224.0.0.0", 3],
  ["::", 96], ["64:ff9b:1::", 48], ["2001::", 32], ["ff00::", 8],
]);
const LINK_LOCAL = subnets([["169.254.0.0", 16], ["fe80::", 10]]);
// fc00::/7 holds Fly's private 6PN network (fdaa::/16), which links a Cloud home to other customers' machines.
const PRIVATE = subnets([["10.0.0.0", 8], ["100.64.0.0", 10], ["172.16.0.0", 12], ["192.168.0.0", 16], ["fc00::", 7]]);
// AWS (IPv4 and IPv6), Azure, GCP and Oracle answer on 169.254.169.254; Alibaba on 100.100.100.200.
const METADATA = new BlockList();
for (const address of ["169.254.169.254", "fd00:ec2::254", "100.100.100.200"]) METADATA.addAddress(address, family(address));

const NAT64 = subnets([["64:ff9b::", 96]]);
const SIX_TO_FOUR = subnets([["2002::", 16]]);

/** The sixteen-bit groups of an IPv6 address, which may end in dotted IPv4. */
function ipv6Groups(address) {
  const dotted = /(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(address);
  const text = dotted
    ? `${address.slice(0, dotted.index)}${((+dotted[1] << 8) | +dotted[2]).toString(16)}:${((+dotted[3] << 8) | +dotted[4]).toString(16)}`
    : address;
  const [head = "", tail] = text.split("::");
  const left = head ? head.split(":") : [];
  const right = tail ? tail.split(":") : [];
  const fill = tail === undefined ? 0 : 8 - left.length - right.length;
  return [...left, ...Array(fill).fill("0"), ...right].map((group) => Number.parseInt(group, 16));
}

/** The IPv4 address a NAT64 or 6to4 address stands for, which a translator will route to. */
function embeddedIPv4(address) {
  const at = NAT64.check(address, "ipv6") ? 6 : SIX_TO_FOUR.check(address, "ipv6") ? 1 : -1;
  if (at === -1) return undefined;
  const groups = ipv6Groups(address);
  const high = groups[at] ?? 0;
  const low = groups[at + 1] ?? 0;
  return [high >> 8, high & 0xff, low >> 8, low & 0xff].join(".");
}

/** The addresses this machine's interfaces hold right now; IPv4-mapped IPv6 matches their IPv4 entries. */
export function ownAddresses(interfaces = networkInterfaces()) {
  const own = new BlockList();
  for (const entry of Object.values(interfaces).flat()) {
    if (entry) own.addAddress(entry.address.split("%", 1)[0], entry.family === "IPv6" ? "ipv6" : "ipv4");
  }
  return own;
}

/** Shorter prefixes are a VPN's catch-all route, not a network of devices beside this one. */
const NARROWEST_LOCAL = { ipv4: 8, ipv6: 16 };

/** The networks this machine's interfaces sit on: a public IPv6 prefix at home reaches the other devices there. */
export function ownSubnets(interfaces = networkInterfaces()) {
  const list = new BlockList();
  for (const entry of Object.values(interfaces).flat()) {
    const [network, bits] = String(entry?.cidr ?? "").split("/");
    const type = entry?.family === "IPv6" ? "ipv6" : "ipv4";
    const prefix = Number(bits);
    if (!network || !isIP(network.split("%", 1)[0]) || !Number.isInteger(prefix) || prefix < NARROWEST_LOCAL[type]) continue;
    list.addSubnet(network.split("%", 1)[0], prefix, type);
  }
  return list;
}

export function addressClass(raw, own = ownAddresses()) {
  const address = raw.split("%", 1)[0];
  if (!isIP(address)) return "reserved";
  const type = family(address);
  const embedded = type === "ipv6" ? embeddedIPv4(address) : undefined;
  if (embedded !== undefined) return addressClass(embedded, own);
  if (METADATA.check(address, type)) return "metadata";
  if (LOOPBACK.check(address, type)) return "loopback";
  if (RESERVED.check(address, type)) return "reserved";
  if (LINK_LOCAL.check(address, type)) return "link-local";
  if (own.check(address, type)) return "this-machine";
  if (PRIVATE.check(address, type)) return "private";
  return "public";
}

/** Whether `address` is in `list`, an address of either family; IPv4-mapped IPv6 matches IPv4 entries. */
export function listed(list, raw) {
  const address = raw.split("%", 1)[0];
  return isIP(address) !== 0 && list.check(address, family(address));
}