移动光猫放开 IPv6 入站:5G 手机直连家里 NAS,不用端口映射
背景
(光猫怎么开启Telnet并获取管理员密码?不在这一篇,百度一下型号有很多现成的了: )
家里有一台 NAS(其实就是台常年开机的 Mac,上面跑了个文件服务)。痛点很具体:人在外面,手机切 5G 想打开它,就是连不上。
有一天顺手查了下网络,发现宽带其实有公网 IPv6。地址是公网的,外面就是进不来。我一度以为是 DNS 没配,后来才明白:移动住宅线的整个入站方向,在网关处就被丢包了。
我的拓扑:
互联网 → 移动光猫(192.168.1.1) → 华为 Ax6 → Mac(NAS)
手机 → 5G(也是移动网络,同样有公网 v6)
先说一个关键认知,能省很多事:IPv6 不需要端口映射。地址本身就是公网地址,你连不上,一定是路上有设备在丢包。我的链路里有两层在丢,一层在光猫,一层在路由。
第一步:先定位丢包在哪
别猜,测:
- 手机上 ping 光猫 WAN 侧的 IPv6 地址 → 通,延迟 30ms 左右
- 手机上 ping Mac 的 IPv6 → 不通,100% 丢包
第一层在光猫。但我没停在这,又做了个对照:从光猫侧 ping Mac,还是不通------说明第二层在后面的 Ax6 上。
两层都在挡,就得把两层都打开。
第二步:光猫(重点)
光猫要改两处,一处 web 后台,一处命令行。
web 侧 :用超级管理员账号 CMCCAdmin 登录 192.168.1.1(登录不进去可以让移动打光猫上的电话恢复),找到 安全 → 防火墙 里的 "IPv6Session 防火墙开关",关掉。这个开关开着的时候,所有发往 LAN 侧设备的新入站连接一律被丢。
命令行侧:telnet(或者 nc)进光猫,先看规则:
sh
ip6tables -S no_source
里面有这么一条:
-A no_source -s 2409:8a34:xxxx::/60 -m devwl --dev-type 0 -j REJECT --reject-with icmp6-policy-fail
这条规则把所有"从 WAN 侧进来、源地址不在家庭前缀内"的包全部拒绝。5G 手机上的源地址当然不在你家前缀里,所以全被拒了。删掉它:
sh
ip6tables -D no_source -s 2409:8a34:xxxx::/60 -m devwl --dev-type 0 -j REJECT --reject-with icmp6-policy-fail
坑在这里:这个改动只在内存里。光猫重启、或者移动通过 TR069 下配置,它都会回来。所以要么重启后手动删一次,要么用定时任务自动重放(下面自动化那节有)。
第三步:华为 Ax6
路由的后台里把防火墙关掉就行。
我顺手试了"DMZ 主机"选项:把 Mac 设成 DMZ,防火墙保持开,看能不能单独放行。实测还是 100% 丢包------DMZ 只对 v4 生效,v6 没用。这个弯路你们可以绕开了。
端口选择:一个隐形坑
都打通之后,我先用手机试 80、443、8080,全超时。当时还怀疑自己哪步没配好,回去一步步重查,没问题。后来随手试了个高位端口 11111,直接通。
结论:移动住宅线把常用端口的入站封了(80/443/8080 这类)。想用公网 IP 提供服务,用高位端口。
验证过程(在光猫侧执行):
sh
$ curl -s -o /dev/null -w '%{http_code}' 'http://[Mac的v6地址]:11111/'
200
光猫侧 200,手机浏览器打开也是通的。
自动化(可选,但建议做)
打通之后有两个会"变脸"的问题:
- 光猫重新拨号后 v6 前缀会变,Mac 的完整地址跟着变
- 光猫那条 REJECT 规则重启/被推配置后会回来
我写了三个脚本加一个 launchd 定时任务(每 5 分钟跑一次):
getipv6:取 Mac 当前的公网 v6(优先取稳定地址,排除临时/隐私地址)fixont:登光猫检查 REJECT 规则,在就删,光猫不可达(比如我不在家)直接跳过dns6update:把一个域名的 AAAA 记录更新到当前地址;不在家直接跳过
getipv6 的核心就这么点:
sh
#!/bin/sh
ifname=$(route -n get -inet6 default | awk '/^ *interface:/{print $2}')
[ -n "$ifname" ] || ifname=en0
ifconfig "$ifname" | awk '
$1=="inet6" {
a=$2; sub(/\/.*/,"",a)
if (a ~ /^fe80/ || $0 ~ /deprecated/) next
if ($0 ~ /secured/) { print a; exit }
if ($0 ~ /dynamic/) { if (dyn=="") dyn=a } else if (temp=="") temp=a
}
END { if (dyn!="") print dyn; else if (temp!="") print temp }'
效果:光猫重拨、重启,5 分钟内地址和规则都自愈;我不在家的时候脚本自己全部跳过,DNS 记录保持在上次的值,不会把外面的临时地址写进去。
安全:放开之后怎么办
放开入站不能一放了之------那两层放开之后,局域网里所有设备的 v6 入站都是裸奔的。洗碗机、扫地机、音箱、打印机,全都能从互联网直接连,而 IoT 设备普遍弱口令、固件更新随缘。
收紧就放在光猫上做(所有入站流量必经光猫,它是最后一道闸)。在 no_source 链尾部加三条,顺序有讲究:
sh
-A no_source -m state --state ESTABLISHED,RELATED -j ACCEPT # 出站连接的返回包,没它家里所有 v6 出站都是单向的
-A no_source -d <Mac当前v6地址> -j ACCEPT # 只放行你的 Mac(地址变了由定时任务自动换)
-A no_source -j DROP # 其余入站全丢
这三条同样可以让 fixont 那个脚本每 5 分钟重放一遍,光猫重启也扛得住。加上之后,互联网能碰到的只有 Mac,IoT 全部被挡在网关。
几个零碎坑
- 光猫的 telnet 只允许一个会话,上次连接没断干净的话,下次登录会卡在 "User name can't be empty",先杀掉本地残留的 telnet/nc 进程再登
- 配完之后手机 ping Mac 可能还是不通(入站 ICMP 被拦了),不影响 HTTP,别慌
- 公网端口上跑的文件服务,目录只放你愿意暴露的东西,我专门用了一个独立目录
- 前缀变了之后,旧地址理论上可能被运营商重新分配,白名单规则里的地址要跟着自动更新,别写死
收尾
整套下来不算复杂:定位丢包在哪(光猫 + Ax6 两层),分别打开,换高位端口,再用白名单收紧。IPv6 最大的好处就是不用端口映射,最大的麻烦就是这些运营商侧的默认过滤,不摸一遍根本不知道。
唯一要长期接受的:光猫的命令行改动不持久,得靠定时任务自愈。
完事。
如果你也有这样的需求,把本文地址发给 ai agents 让他帮你处理一下你的网络是最方便的.