启动器「发给朋友」不再把代理 TUN 当公网 IP;删掉永不生效的 ^tun\d
198.18.0.0/15 是 RFC 2544 的基准测试段,Clash / Mihomo 这类代理软件拿它当本地 TUN 的 fake-ip 池 —— 那是本机自己的地址,冒充「公网 IP」发给朋友只会让人连不上。同时按网卡名 补上 Radmin VPN / Hamachi:它们是点对点地址,正是同组好友互连要用的,仍留在 vpn 一类。 另外删掉 VIRTUAL_IF 里的 `^tun\d`:分类顺序是 VPN_IF → VIRTUAL_IF,而 VPN_IF 里的 `tun\d` 是子串匹配,凡能被 `^tun\d` 命中的名字都已经被它命中,这条永远轮不到。同一个 判断写在两处、其中一处是死代码,只会让后来者以为顺序无所谓(review 里就是这么指出的)。 测试从 test/windows-bundle.test.js 移到独立的 test/doctor.test.js —— 这本来就是 tools/doctor.mjs 的纯函数,不该挂在打包测试里。另补两条钉住分类顺序的用例:一条防止 `^tun\d` 被抄回 VIRTUAL_IF,一条记录 macOS 的 utunN 因 `tun\d` 子串匹配而归 vpn 的现状 (那是仓库原有行为,本次未改;把它写下来,免得有人误以为 VIRTUAL_IF 里的 `utun` 在起作用)。
This commit is contained in:
1 parent
7adba466fc
commit
9f9207a66e
2 files changed
+82
-4
No files matched your search
+12
-4
@@ -24,16 +24,21 @@ import {
|
||||
// LAN addresses (also used by scripts/launch.mjs)
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
const VIRTUAL_IF = /(vethernet|virtualbox|vmware|vmnet|docker|^br-|^veth|wsl|hyper-v|vboxnet|bridge\d|utun|awdl|llw|parallels|loopback)/i;
|
||||
const VPN_IF = /(tailscale|zerotier|^zt|wireguard|^wg\d|tun\d|tap)/i;
|
||||
// 名字里带这些的网卡不对局域网开放:虚拟机 / 容器 / WSL / 代理软件的 TUN 适配器(Mihomo、Clash)。
|
||||
// 这里不再列 `^tun\d`:下面 VPN_IF 的 `tun\d` 先判定,任何能被 `^tun\d` 命中的名字也一定被它命中,
|
||||
// 于是 tun0/tap0 一律归为 vpn(那正是同组好友互连用的地址)。写在两处只会让人以为顺序无关。
|
||||
const VIRTUAL_IF = /(vethernet|virtualbox|vmware|vmnet|docker|^br-|^veth|wsl|hyper-v|vboxnet|bridge\d|utun|awdl|llw|parallels|loopback|mihomo|clash|sing-?box)/i;
|
||||
// 点对点 VPN:这些地址就是同组好友互相访问用的(Tailscale / ZeroTier / WireGuard / Radmin VPN / Hamachi)。
|
||||
const VPN_IF = /(tailscale|zerotier|^zt|wireguard|^wg\d|tun\d|tap|radmin|hamachi)/i;
|
||||
|
||||
function ipv4ToInt(ip) { return ip.split('.').reduce((n, x) => (n << 8) + Number(x), 0) >>> 0; }
|
||||
function inCidr(ip, base, bits) { const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0; return (ipv4ToInt(ip) & mask) === (ipv4ToInt(base) & mask); }
|
||||
|
||||
/**
|
||||
* Classify every non-internal IPv4 address: 'lan' (RFC 1918, what friends at home use), 'vpn' (Tailscale / ZeroTier /
|
||||
* CGNAT 100.64/10), 'virtual' (Hyper-V, WSL, Docker, VirtualBox … — usually not reachable from other machines),
|
||||
* 'public' (a public address directly on this machine), 'linklocal' (169.254 — no DHCP, useless).
|
||||
* Radmin / Hamachi / CGNAT 100.64/10), 'virtual' (Hyper-V, WSL, Docker, VirtualBox, a Clash/Mihomo TUN adapter … —
|
||||
* not reachable from other machines, sharing them only confuses people), 'public' (a public address directly on this
|
||||
* machine), 'linklocal' (169.254 — no DHCP, useless).
|
||||
* @returns {{ name: string, address: string, kind: string }[]} best first
|
||||
*/
|
||||
export function classifyAddresses(ifaces = os.networkInterfaces()) {
|
||||
@@ -44,6 +49,9 @@ export function classifyAddresses(ifaces = os.networkInterfaces()) {
|
||||
const ip = a.address;
|
||||
let kind;
|
||||
if (inCidr(ip, '169.254.0.0', 16)) kind = 'linklocal';
|
||||
// 198.18.0.0/15 是 RFC 2544 的基准测试段:代理软件(Clash / Mihomo 的 fake-ip 池)拿它做本地 TUN 地址,
|
||||
// 绝对不是能发给朋友的「公网 IP」。
|
||||
else if (inCidr(ip, '198.18.0.0', 15)) kind = 'virtual';
|
||||
else if (VPN_IF.test(name) || inCidr(ip, '100.64.0.0', 10)) kind = 'vpn';
|
||||
else if (VIRTUAL_IF.test(name)) kind = 'virtual';
|
||||
else if (inCidr(ip, '10.0.0.0', 8) || inCidr(ip, '172.16.0.0', 12) || inCidr(ip, '192.168.0.0', 16)) kind = 'lan';
|
||||
|
||||
Reference in new issue
Block a user