# same-LAN TUN smoke 测试 简体中文 | [English](README.md) 这份指南覆盖同一家庭或办公室 LAN 内的 TUN 默认网关 smoke。它不同于 `tests/real-device/` 的隔离下游 LAN:Mac 和 Android 测试设备都连接同一个主 LAN,OpenSurge 不接管主 LAN DHCP。 ## 拓扑 ```text Home router / main Wi-Fi: 192.168.1.1 | +-- Mac en0: 192.168.1.20 | OpenSurge same_lan + mihomo TUN + DNS-only dnsmasq | +-- Android phone: 192.168.1.x default gateway: 192.168.1.20 DNS: 192.168.1.20 ``` 第一轮验收只面向一台测试手机。不要在主 LAN 上启动 OpenSurge DHCP,也不要把主 路由器的 DHCP 全局下发改成 Mac,除非你已经准备好影响所有设备。 如果要在专门测试 Wi-Fi 上关闭主路由 DHCP,让 OpenSurge 接管同一 Wi-Fi 的 DHCP/DNS,请先阅读 [same-WiFi DHCP 恢复参考](WIFI-DHCP-RECOVERY.zh-CN.md)。 恢复方案本身也是验收的一部分。 已具备恢复通道并要实际验证 DHCP 租约、DNS、TUN、provider、策略切换与受控 egress 时,使用独立的 [same-WiFi DHCP imported egress 全功能 runner](WIFI-DHCP-RUNNER.zh-CN.md)。 它使用 `same_wifi_dhcp`,不会放宽本页 `same_lan` 的 DHCP disabled 边界。 验证两台客户端精确 reservation、独立 selector、规则槽位和 UDP fail-closed 时,使用 [same-WiFi 双设备策略真机 gate](SAME-WIFI-DEVICE-POLICY.zh-CN.md)。它增加竞争 DHCP 主动探测和独立恢复门槛;真机运行通过前保持 Experimental / cooperative IPv4。 ## 启动 默认 runner 会从 macOS 默认路由推断接口,并从该接口读取 Mac IPv4 地址: ```sh make same-lan-start-tun ``` 也可以显式指定: ```sh OMG_SAME_LAN_IFACE=en0 \ OMG_SAME_LAN_MAC_IP=192.168.1.20 \ make same-lan-start-tun ``` runner 会生成 `runtime/same-lan/config-tun.yaml`,其中: - `gateway.mode: "same_lan"`; - `gateway.interface` 和 `gateway.upstream_interface` 相同; - `dhcp.enabled: false`; - `dns.listen` 绑定 Mac 的主 LAN IP; - `dns.upstream: "127.0.0.1#1053"`,让客户端 DNS 进入 mihomo fake-ip; - `transparent.mode: "tun"`。 ## Android ADB 验证 先让测试 Android 手机的 Wi-Fi 默认网关和 DNS 指向 Mac 的 LAN IP。当前 runner 不尝试永久修改手机 Wi-Fi 配置;它通过 ADB 自动采集验证结果,避免依赖人工口头 回报。 ```sh make same-lan-adb-check ``` 多台设备连接时指定序列号: ```sh OMG_SAME_LAN_ADB_SERIAL=57081FDCQ008KZ make same-lan-adb-check ``` ADB 检查会验证: - 设备处于 authorized `device` 状态; - Android 默认路由包含 `via `; - Android 镜像带有 `nslookup` 或 `dig` 时,能查询 `@ example.com`; - Android 全局显式代理没有被设置为测试成功的前提; - Android 通过 `curl`、`wget` 或 `nc` 发起到 `https://example.com/` 或 `example.com:443` 的无显式代理探针; - Mac 侧 `dnsmasq.log` 和 `mihomo.log` 能看到对应 DNS/fake-ip 与 TUN 连接。 如果 Android 镜像没有 `nslookup` 和 `dig`,ADB gate 会继续执行 TCP 探针,并 通过 Mac 侧 `dnsmasq.log` 中 Android 源 IP 的查询记录推断 DNS 路径。如果镜像也 没有 `curl`、`wget` 和 `nc`,这个 gate 才会停在缺少客户端探针工具的位置。后续 可以只补一个极薄 probe APK,不要把网关事实判断搬进 APK。 ## 代理出口 smoke 第一轮代理出口验证不需要导入完整订阅,先用生成的最小 mihomo 规则更稳。把 `upstream_proxy` 指向一个已知可用的 LAN 代理,并只匹配一个诊断域名: ```sh OMG_SAME_LAN_TEST_HOST=api.ipify.org \ OMG_SAME_LAN_UPSTREAM_PROXY_NAME=same-lan-http-egress \ OMG_SAME_LAN_UPSTREAM_PROXY_TYPE=http \ OMG_SAME_LAN_UPSTREAM_PROXY_SERVER=192.168.1.101 \ OMG_SAME_LAN_UPSTREAM_PROXY_PORT=8080 \ OMG_SAME_LAN_UPSTREAM_PROXY_MATCH_DOMAIN=api.ipify.org \ make same-lan-start-tun-proxy OMG_SAME_LAN_TEST_HOST=api.ipify.org make same-lan-adb-check ``` 如果要测 LAN SOCKS5 代理,把 `OMG_SAME_LAN_UPSTREAM_PROXY_TYPE` 改成 `socks5`,并指定对应 server/port。生成的 mihomo 配置会包含一个 `open-surge-egress` select group 和一条规则: ```yaml rules: - DOMAIN,api.ipify.org,open-surge-egress - MATCH,DIRECT ``` 只有以下证据同时成立,才宣称真实代理出口被验证: - Android 默认网关和 DNS 仍指向 Mac LAN IP; - Android 全局显式代理仍未设置; - `dnsmasq.log` 看到 Android 源 IP 查询 `api.ipify.org`; - `mihomo.log` 看到 `Domain(api.ipify.org) using open-surge-egress[...]`; - Android 浏览器打开 `https://api.ipify.org/` 时显示预期的上游代理出口 IP。 2026-07-09 的 same-LAN run 已经用 Pixel 测试手机、`api.ipify.org` 和一个 LAN HTTP 代理验证了这条路径。Android 页面和 Mac 侧直连该代理检查得到同一个出口 IP, 同时 `mihomo.log` 显示命中 `open-surge-egress[same-lan-http-egress]`。 策略组切换属于下一层 smoke。当前自动生成的 group 只有一个代理成员,所以可以证明 “命中代理”,但不能证明有意义的切换。要验证切换,至少让 `open-surge-egress` 同时包含 LAN 代理和 `DIRECT` 两个候选,然后用 `omg policy-select --config --group open-surge-egress --policy ` 切换当前选中项,再重复 `api.ipify.org` 探针。 ## imported 策略出口 smoke 如果要更接近导入订阅后的真实路径,同时仍保持代理端点本地可控,可以启动 same-LAN imported egress fixture: ```sh make same-lan-start-tun-imported-egress ``` 这个入口会生成 `runtime/same-lan/config-tun.yaml`,其中 `mihomo.profile_mode: "imported"`,并基于 lab fixture 渲染 `runtime/same-lan/mihomo-profile.imported-tun-egress.yaml`。渲染后的 profile 包含: 由于 imported profile 路径是相对于 config 文件所在目录解析的,生成的 config 会把该 profile 写为 `./mihomo-profile.imported-tun-egress.yaml`。 - 名为 `tun-egress-provider` 的 HTTP `proxy-provider`; - 包含 `DIRECT` 和 provider-backed `egress-proxy` 的 `TunEgress` select group; - 针对 `OMG_SAME_LAN_TEST_HOST` 的域名规则,默认是 `example.com`; - 其他流量使用 `MATCH,DIRECT`。 runner 还会启动一个用户态本地 helper:一边提供 HTTP provider,一边在 `127.0.0.1` 上作为受控 HTTP CONNECT proxy 监听。只有 provider 和 proxy 两个 端口都可连接时它才报告 ready;两轮客户端探针期间两者都必须保持存活。 当 Android 测试手机的网关和 DNS 指向 Mac LAN IP 后,运行: ```sh make same-lan-adb-check-imported-egress ``` 这个 ADB 检查会先验证 Android 路由、DNS 和无显式代理状态,再确认 `TunEgress` 包含 `egress-proxy`。随后它会在 `TunEgress[DIRECT]` 下发起一次无显式代理 HTTPS 探针,通过 `omg policy-select --group TunEgress --policy egress-proxy` 切换策略, 再重复探针。验收信号是 `mihomo.log` 同时出现 `TunEgress[DIRECT]` 和 `TunEgress[egress-proxy]`,并且受控 proxy 日志只在切换后出现 `CONNECT :443`。 这个 smoke 证明 same-LAN 透明 TUN 路径下的 imported provider-backed 策略切换可以 命中受控本地代理;它不证明真实订阅节点或远端出口 IP。 ### 不使用 ADB 的手动手机检查 当 Android 必须由人工操作时,不要运行 ADB target,而是: 1. 在测试手机上给同一 Wi-Fi 网段设置一个未占用的静态 IPv4 地址,把网关和 DNS 都指向 Mac LAN IP,并保持显式代理关闭。 2. 启动 fixture,选择 `DIRECT`,清空受控 proxy 日志后,用新的无痕浏览器标签访问 `https://example.com/`。 3. 确认 `mihomo.log` 出现 `example.com:443 ... using TunEgress[DIRECT]`,且受控 proxy 日志为空。 4. 通过 `omg policy-select` 选择 `egress-proxy`,再用新的无痕标签重复访问。确认 `mihomo.log` 出现 `TunEgress[egress-proxy]`,并且受控 proxy 日志出现 `CONNECT example.com:443`。 2026-07-10 的人工 Android run 未使用 ADB,两个浏览器探针均成功,并已完成 `make same-lan-stop` 清理。它仍只证明受控本地代理,不证明真实订阅节点或远端出口。 ## 停止 ```sh make same-lan-stop ``` 预期停止后: - OpenSurge runtime state 被移除; - same-LAN PF anchor 被卸载; - IPv4 forwarding 恢复到启动前状态; - DNS listener 不再占用 Mac LAN IP 的 53 端口; - Mac 和主 LAN 恢复到启动前的普通网络状态。 如果测试期间关闭过主路由 DHCP,请按 [same-WiFi DHCP 恢复参考](WIFI-DHCP-RECOVERY.zh-CN.md) 恢复路由器 DHCP、Mac Wi-Fi DHCP 和测试客户端自动获取地址。 ## 当前边界 这个 smoke 只证明一台测试 Android 在同一 LAN 内把默认网关/DNS 指向 Mac 后, 无显式代理流量可以进入 OpenSurge TUN 路径。配合 `same-lan-start-tun-proxy` 时, 它也可以证明单个域名的真实上游代理出口。配合 `same-lan-start-tun-imported-egress` 和 `same-lan-adb-check-imported-egress` 时, 它可以证明 imported provider-backed 策略切换会命中受控本地代理。它不证明主路由 DHCP 全局下发、所有设备兼容、IPv6、DoH/Private Relay、UDP/QUIC、完整订阅兼容性 或真实远端出口 IP。 关闭路由器 DHCP 后的 DHCP 接管不是本页这些窄范围 target 的隐含能力;它必须使用 `same-wifi-dhcp-*` 全功能 runner,并按 [WIFI-DHCP-RUNNER.zh-CN.md](WIFI-DHCP-RUNNER.zh-CN.md) 的恢复契约执行。