夜雨聆风学习资料网

ARTICLE · 1216379

我把遥控器 App 的局域网限制解了——还浑然不知

我把遥控器 App 的局域网限制解了——还浑然不知

自己写的 App、自己配的 Tailscale、自己忘记的子网路由。三件事碰在一起,结果就是:人在外面,遥控了家里的电视。


起因:一个"不对劲"的瞬间

那天在外面吃饭,掏出手机想调一下家里的米家设备。

打开 App,操作灯、开关,一切正常——毕竟 HomeAssistant 跑在 NAS 上,Tailscale 连着,没啥好奇怪的。

然后我无意中点开了自己写的遥控器 App。

居然连上了。 甚至还能操控。

我愣了一下。

这个 App 叫 AIRC(AI 遥控),是我用 Kotlin Multiplatform 写的 Android 遥控器。它的工作原理是:手机通过 ADB 往目标设备(一台插在康佳电视上的 Android 盒子)上部署一个 airc-runtime,之后全部通信走局域网 WebSocket + mDNS 发现。

关键词:局域网。

而我现在人在外面,走的是 4G。

"这 App 绝对没写云中转功能啊……"


排查:娜斯的"诊断报告"

我把情况丢给了 NAS 上常驻的 Hermes Agent(我叫它"娜斯"),让它帮我查网络拓扑。

几分钟后回来了:

Tailscale 设备列表:  100.110.175.89  ds220plus     suqishuo@  linux    -  100.85.74.46    ace-3         suqishuo@  android  active; direct  100.123.9.55    aliyun-derp   suqishuo@  linux    -NAS 的 Tailscale 配置:  AdvertiseRoutes: ["192.168.1.0/24"]  IP Forwarding:   已开启

真相大白。


原理:Tailscale 子网路由当了一回"隐身网桥"

这事的本质很简单,但效果很离谱。

我的 App 原本的通信路径

AIRC 的设计是纯局域网的:

一加 Ace 3(控制端)    │    │ WebSocket(局域网直连)    │    ▼Android 盒子(192.168.1.x)    │ HDMI    ▼康佳电视

手机通过 mDNS 发现盒子,然后建 WebSocket 长连接。没有云中转、没有公网穿透、没有任何外网访问逻辑。 就是一段干净的局域网代码。

Tailscale 偷偷干了什么

NAS(ds220plus)上很早之前配过一条命令:

tailscale up --advertise-routes=192.168.1.0/24

这意味着 NAS 向整个 Tailscale 网络宣告:"发往 192.168.1.x 的所有流量,由我来转发。"

于是实际的通信路径变成了:

一加 Ace 3(外面,4G)    │    │ Tailscale WireGuard 加密隧道    │ (direct UDP / IPv6 直连,不打洞不过中继)    │    ▼NAS ds220plus(子网路由器,100.110.175.89)    │    │ 本地转发到 192.168.1.0/24    │    ▼Android 盒子(192.168.1.x)    │ HDMI    ▼康佳电视

手机 App 以为自己还在局域网里。

mDNS 发现?Tailscale 虽然不是原生支持 mDNS,但子网路由把整个 IP 层的 192.168.1.x 都打通了——App 直接用 IP 建 WebSocket 连接,NAS 透明转发,App 毫无感知。

这就好比你给家里的每一面墙都装了一扇隐形门,而你忘记了这件事。


为什么是"直连"而不是"中继"?

娜斯的诊断里还有一个关键字段:

ace-3  active; direct [IPv6]:41647, tx 30MB rx 16MB

direct —— 手机和 NAS 之间是 UDP 打洞成功的直连,没有经过 Tailscale 的 DERP 中继。

这意味着:

  • • 延迟低(不绕路、不排队)
  • • 带宽上限取决于两端网络,不被中继限制
  • • 流量不过 Tailscale 的第三方服务器

Tailscale 的 NAT 穿透技术在 IPv6 环境下尤其高效。30MB 上传 / 16MB 下载的流量,大概是传了几张截图和操作指令——和我实际使用场景对得上。


这就是"基础设施对了"的感觉

这件事最有意思的不是技术本身,而是一个开发者对自己系统的"失控感"。

我写了 AIRC,我知道它的通信边界是局域网。

我配了 Tailscale 子网路由,但那是很早之前的事了,配完就忘了。

这两件事在我脑子里是两条平行线,从来没觉得它们会相交。

但基础设施不这么想。它不管你记得不记得。它就在那里,默默工作,把两条平行线焊在了一起。

结果就是:我自己写的 App 跨过了我自己认为不可能跨越的边界,而我自己还不知道。


对 AIRC 的启发

这次"意外 QA"也让我重新审视 AIRC 的架构:

  1. 1. 不需要加云中转。Tailscale 子网路由已经证明了——只要目标设备的 IP 层可达,AIRC 现有的 WebSocket 方案就能工作。加云中转反而引入延迟、成本和安全隐患。
  2. 2. mDNS 发现可以加 fallback。在子网路由场景下 mDNS 不可达(mDNS 是链路层多播,不会被路由),但用户手动输入 IP 或从历史记录重连就能直接用 WebSocket。加一个"上次连接的 IP"快捷入口就够了。
  3. 3. Tailscale + AIRC 是一个很好的组合。对于 NAS 用户和 Homelab 玩家来说,这种"局域网 App 自动变成全球可达"的体验,比任何云方案都干净。

配置只需 3 步

如果你也有类似场景——自己写的局域网 App、家里的打印机、没公网 IP 的摄像头——Tailscale 子网路由可以一键打通:

1. 安装 Tailscale

Synology 套件中心搜 Tailscale(SPK 包)。其他 NAS 品牌也有对应版本。

2. 宣告子网路由

SSH 进 NAS:

sudo tailscale up --advertise-routes=192.168.1.0/24

(换成你家里的实际网段)

3. 批准路由

登录 Tailscale Admin Console,找到你的 NAS,点击路由旁边的 Approve。

手机端不需要任何配置。Tailscale Android/iOS 客户端默认接受子网路由。


总结

这次经历最好的部分不是技术,而是一种类似"发现隐藏关卡"的感觉:

你自己写的软件,在你不知道的时候,运行得比你预期的更好。

这大概也算一种 Vibe Coding 的 bonus track。


AIRC 项目:github.com/Ernest-su/ai-remote-controller

排查由 NAS 上的 Hermes Agent 完成。

公众号:编码生活禅意录 | 博客:suqishuo.cn

相关学习资料