Leadaxe 记录 singbox-launcher 的 Tailscale 出口节点流量不被 sniff,域名规则对该类客户端不生效
Leadaxe 于 2026-09-29 08:06:22Z 在自己的仓库 singbox-launcher 提交 issue #139(目前仍 open):远程机器(Linux,内核 1.14.2-lx.7)以 tailscale endpoint 且 advertise_exit_node: true 作为出口节点、手机(LxBox)以其为 exit_node 时,手机流量会绕过该机器上全部基于域名的路由规则——模板把 sniff 与 resolve 限定在启动器自身的入站(tun-in、proxy-in),经 tailscale endpoint 进入的连接不会被 sniff,只带目标 IP,域名规则与域名规则集都不匹配,全部落到 route.final。他给出同一时刻的实测对照:经 tun-in 的局域网客户端被识别为 api.anthropic.com 并命中 AI 规则集、走专用选择器;经 Tailscale 出口节点的手机只见裸 IP、未命中任何规则而走 proxy-out,导致该服务以「不支持地区」拒绝手机。成因在 bin/wizard_template.json 的 route.rules:sniff 与 hijack-dns 之后的 resolve,其 inbound 只由 @tun(tun-in)与 @enable_proxy_in(proxy-in)构建,tailscale 等可接收入站连接的 endpoint 不在其中。他期望 tailscale endpoint 接收的连接同样经过 sniff/resolve,并列出两种改法:去掉这两条规则的 inbound 限制(对所有入站生效),或在 endpoint 宣告出口节点时把其标签加入两条规则的 inbound 列表。该缺陷尚未修复,也未随任何版本发出(最新发布为 09-28 的 v2.3.3)。
作者原文@LeadaxeSummary
Traffic from Tailscale exit-node clients bypasses all domain-based routing rules on the exit node. The template restricts
sniffandresolveto the launcher's own inbounds (tun-in,proxy-in), so connections arriving through atailscaleendpoint are never sniffed. They carry only a destination IP, domain rules and domain rule-sets never match, and everything falls through toroute.final.Setup
- Remote machine (Linux, core
1.14.2-lx.7) with atailscaleendpoint,advertise_exit_node: true.- A phone (LxBox) uses that machine as
exit_node.- On the exit node, a rule sends a domain rule-set (AI services) to a dedicated selector;
route.finalisproxy-out.Observed
Generated
route.ruleson the exit node:{"action":"sniff","inbound":["tun-in"],"timeout":"1s"} {"action":"hijack-dns","protocol":"dns"} {"action":"resolve","inbound":["tun-in"],"strategy":"prefer_ipv4"}Live connections on the same machine at the same time:
| Client | host seen by core | matched rule | chain |
|---|---|---|---|
| LAN client viatun-in|api.anthropic.com|rule_set=[user:AI-SRS …]|Ai→ selected node |
| Phone via Tailscale exit node | bare IP | none |proxy-out→ final |The service behind the domain rule rejects the phone ("unsupported region") because the phone's traffic leaves through
route.finalinstead of the dedicated selector.Cause
bin/wizard_template.json,route.rules: thesniffrule (and theresolverule afterhijack-dns) buildinboundonly from@tun→tun-inand@enable_proxy_in→proxy-in. Tailscale endpoints (and any other endpoint that accepts inbound connections) are not in the list.Expected
Connections accepted by a
tailscaleendpoint go through the samesniff/resolvesteps astun-in, so the exit node applies its routing rules to exit-node clients exactly as to LAN clients.Possible fixes
- Drop the
inboundrestriction fromsniffandresolve(apply to all inbounds).- Add the tags of
tailscaleendpoints to theinboundlist of both rules when an endpoint advertises an exit node.