收起左侧

光猫 NAT 回流思路分享

6
回复
447
查看
[ 复制链接 ]

0

主题

2

回帖

0

牛值

江湖小虾

背景

家里弱电箱放着一台 F7005TV3,感觉性能还是不错的,但是有 NAT 回流的问题,在家访问 NAS 非常麻烦,经常切账号。

最简单就是搭个 DNS 内网服务器,将域名指向内网设备,但是会存在 dns 的切换延迟,内网可以设置 ttl 为 1s,出到外网可以立即更新成公网 IP,但是从外网回到内网就要看域名解析的 TTL 时间了,国内普遍最低是 10 分钟(花钱可以修改),也就是意味着从外网进到内网最长会有 10 分钟时间无法使用域名访问,如果可以接受的话,就不用看这个文章了,去搭建 DNS 服务吧。

也舍不得花三五百买个硬路由,软路由不想 all in one,所以搞了光猫的 telnet 权限,研究 NAT 回流问题。

这个过程中学习到了很多知识,也成功解决了 NAT 回流问题,所以分享一下我的折腾经过,给大家提供一个思路。

硬件

  • 中兴 F7005TV3 电信版

需要

  • 光猫开启 telnet

NAT 原理

授人以鱼不如授人以渔,简单讲一下原理吧,省略了很多,只简单说下涉及到的。

当客户端发起请求时,数据包会先进入光猫,再从光猫出去。在这两个过程中,防火墙会根据相应规则进行匹配和处理。

  • 进:PREROUTING 表
  • 出:POSTROUTING 表

还有一些其他的,我就忽略了不讲了,下面举几个例子,了解为什么会出现 NAT 回流问题。

初始情况下,这两个表中没有自定义规则,仅包含防火墙的默认配置。

内网 IP 访问内网 IP

192.168.1.20 发起请求:

  • 请求包:192.168.1.20:1111 > 192.168.1.10:2222
  • 从 lan 口进,经过 PREROUTING,未匹配规则,包不修改
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.10 收到请求包:192.168.1.20:1111 > 192.168.1.10:2222

192.168.1.10 发出响应:

  • 响应包:192.168.1.10:2222 > 192.168.1.20:1111
  • 从 lan 口进,经过 PREROUTING,未匹配规则,包不修改
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.20 收到响应包:192.168.1.10:2222 > 192.168.1.20:1111

两者正常通讯。

外网访问内网

在这个情况下,肯定是做了端口映射的,假设光猫公网 IP 为 1.1.1.1,在光猫自带的界面添加端口映射 1000 > 192.168.1.10:1688

那么 PREROUTING 会新增一条规则:

  1. 从 wan 口来的
  2. 源地址为任意地址,任意端口
  3. 目标地址为 1.1.1.1,端口为 1000
    当匹配到数据包后,将数据包目标地址修改为 192.168.1.10,端口为 1688,同时会记录下这个修改信息

举例子好理解,假设外网 IP 为 8.8.8.8,所以流程为:

8.8.8.8 发起请求:

  • 请求包:8.8.8.8:1234 > 1.1.1.1:1000
  • 从 wan 口进,经过 PREROUTING,匹配规则,此时请求包修改为:8.8.8.8:1234 > 192.168.1.10:1688
  • 记录修改规则:1.1.1.1:1000-192.168.1.10:1688 (当然代码里不是这样的,我只是简单写一下方便理解)
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.10 收到请求包:8.8.8.8:1234 > 192.168.1.10:1688

192.168.1.10 发出响应:

  • 响应包:192.168.1.10:1688 > 8.8.8.8:1234
  • 从 lan 口进,经过 PREROUTING,未匹配规则,包不修改
  • POSTROUTING 时命中 PREROUTING 阶段的修改规则,此时响应包修改为:1.1.1.1:1000 > 8.8.8.8:1234
  • 8.8.8.8 收到响应包:1.1.1.1:1000 > 8.8.8.8:1234

内外网设备正常通讯。(这里省略了很多,方便理解)

内网通过域名访问内网:NAT 回流故障

现在来看下,为什么会出现 NAT 回流:

192.168.1.20 以域名发起请求:

  • 请求包:192.168.1.20:1111 > 1.1.1.1:1000
  • 从 lan 口进,经过 PREROUTING,未匹配规则,包不修改
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.10 收不到数据包

这是第一个问题,光猫添加的域名解析是匹配从 wan 口进的数据包,所以 NAT 回流的第一步,就是把这个规则改为数据包从 wan 和 lan 的都匹配。

假设完成了这个修改,那我们重新看看步骤:

192.168.1.20 以域名发起请求:

  • 请求包:192.168.1.20:1111 > 1.1.1.1:1000
  • 从 lan 口进,经过 PREROUTING,匹配规则,此时请求包修改为:192.168.1.20:1111 > 192.168.1.10:1688
  • 记录修改规则:1.1.1.1:1000-192.168.1.10:1688
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.10 收到数据包:192.168.1.20:1111 > 192.168.1.10:1688

192.168.1.10 发出响应:

  • 响应包:192.168.1.10:1688 > 192.168.1.20:1111
  • 从 lan 口进,经过 PREROUTING,未匹配规则,包不修改
  • 经过 POSTROUTING,未匹配规则,包不修改,从 lan 口出
  • 192.168.1.20 收到响应包:192.168.1.10:1688 > 192.168.1.20:1111
    此时,192.168.1.20 认为自己在和 1.1.1.1:1000 交互,怎么来了个 192.168.1.10:1688 的包?那么直接抛弃。

所以这是 NAT 回流的第二个问题,接受和响应不一致,而修改这个问题,就需要从整个流程来解决了。

内网通过域名访问内网:NAT 流程修改

其实也简单,我们知道 192.168.1.10 收到的数据包是 192.168.1.20:1111 > 192.168.1.10:1688,这显然是不行的。

所以我们需要光猫做一个中间人,让 10 认为自己在和光猫沟通,发的包是给光猫的,然后光猫再转成公网 1.1.1.1:1000 给 20 接收,这样就皆大欢喜了。

所以需要 2 个规则:

PREROUTING:

  1. 从任意口来的(wan 匹配外网的设备,lan 匹配内网的,所以光猫创建的没用)
  2. 源地址为任意地址,任意端口
  3. 目标地址为 1.1.1.1,端口为 1000
    当匹配到数据包后,将数据包目标地址修改为 192.168.1.10,端口为 1688,同时会记录下这个修改信息

POSTROUTING:

  1. 从 lan 口出去的
  2. 源地址是 192.168.1.0/24 的内外设备
  3. 目标地址为 192.168.1.10,端口 1688
  4. 修改源地址为 192.168.1.1,端口任意
    匹配到后,将内网走向 192.168.1.10:1688 的数据包的源地址改为 192.168.1.1,端口任意

这样的话,整个流程就为:

192.168.1.20 以域名发起请求:

  • 请求包:192.168.1.20:1111 > 1.1.1.1:1000
  • 从 lan 口进,经过 PREROUTING,匹配规则,此时请求包修改为:192.168.1.20:1111 > 192.168.1.10:1688
  • 记录修改规则:1.1.1.1:1000-192.168.1.10:1688
  • 经过 POSTROUTING,匹配规则,此时请求包修改为:192.168.1.1:1234 > 192.168.1.10:1688
  • 记录修改规则:192.168.1.20:1111-192.168.1.1:1234
  • 192.168.1.10 收到数据包:192.168.1.1:1234 > 192.168.1.10:1688

192.168.1.10 发出响应:

  • 响应包:192.168.1.10:1688 > 192.168.1.1:1234
  • 从 lan 口进,PREROUTING 时命中 POSTROUTING 阶段的修改规则,修改包为:192.168.1.10:1688 > 192.168.1.20:1111
  • POSTROUTING 时命中 PREROUTING 阶段的修改规则,修改包为:1.1.1.1:1000 > 192.168.1.20:1111
  • 192.168.1.20 收到响应包:1.1.1.1:1000 > 192.168.1.20:1111

此时设备就正常沟通了(修改规则的命中,是 POSTROUTING 互相 PREROUTING 命中的,也就是 2 层 NAT 的转换)。

方案分享

知道原理后,找对应的方案就比较简单了,就是 2 个规则,有 telnet 后连接上去创建就行,每个人可能都不一样,分享下我的方案吧。

我图省事,就直接全部端口走 192.168.1.2 了,等同于 DMZ,因为每一个端口解析就要创建一条匹配规则,操作起来太麻烦了。

而 192.168.1.2 是我的 iStoreOS 旁路由,在这里做端口映射方便些。

代码

这是直接使用的代码,你可以测试一下是否正常,正常的话,再考虑做自动任务

iptables -t nat -A PREROUTING -d <替换你的公网IP> -j DNAT --to-destination 192.168.1.2

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.2 -j SNAT --to-source 192.168.1.1

如果是端口映射而且还需要指定协议的话,就这两条命令:

iptables -t nat -A PREROUTING -d <替换你的公网IP> -p tcp --dport 1111 -j DNAT --to-destination 192.168.1.10:2222

iptables -t nat -I POSTROUTING 1 -s 192.168.1.0/24 -d 192.168.1.10 -p tcp --dport 2222 -j SNAT --to-source 192.168.1.1

而使用这两个命令还不行的话,还需要修改一下路由策略,因为我不停踩坑调试后发现,内网以域名访问的数据包,竟然从 wan 口出去了,所以如果你还不行的话,需要这个代码:

# 查看所有策略
ip rule list

# 将内网策略放在公网之上,最后数值越小优先级越高,检查一下公网 IP 的优先级时多少,然后把这个数值填小一点。
ip rule add from 192.168.1.0/24 to 192.168.1.0/24 lookup main priority 500

到了这一步,你应该是可以在内网以域名访问服务器了。
(如果还不行,那我确实不知道了,我是这样的完成的,原理也就那些,可以借助 AI 去询问一下)

自动任务

当然上面的命令,在光猫重启后就 g 了,然后因为公网 ip 是动态的,所以需要用自动任务去做自动更新。

在光猫上运行自动脚本太麻烦了,很多地方是只读的,我就没有在光猫上跑脚本,而是在光猫的用户目录里写了脚本(用户目录重启不会丢失),然后用 Lucky 去定时跑。

在光猫里运行:

启动脚本(在这里,我把公网的匹配放在了 ipset 规则里,然后直接更新 ipset 的规则,可以看到下面的更新 IP 脚本)

cat > /userconfig/NAT_INIT << 'EOF'
#!/bin/sh

INIT=$(ip rule list | grep -c "from 192.168.1.0/24 to 192.168.1.0/24 lookup main")

if [ "$INIT" -gt 0 ]; then
    echo "IS INIT"
else
    ip rule add from 192.168.1.0/24 to 192.168.1.0/24 lookup main priority 500
    ipset create wan_ip hash:ip
    iptables -t nat -A PREROUTING -m set --match-set wan_ip dst -j DNAT --to-destination 192.168.1.2
    iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.2 -j SNAT --to-source 192.168.1.1
    echo "INIT OK"
fi
EOF

chmod +x /userconfig/NAT_INIT

更新 IP

cat > /userconfig/NAT_AUTO_WAN << 'EOF'
#!/bin/sh

CURRENT_IP=$(curl -s ipv4.ddnspod.com | tail -n 1)
IPSET_IP=$(ipset list wan_ip | tail -n 1)

if [ "$CURRENT_IP" = "$IPSET_IP" ]; then
    echo "IP === ${CURRENT_IP}"
else
    ipset flush wan_ip
    ipset add wan_ip $CURRENT_IP
    echo "IP Update ${CURRENT_IP}"
fi
EOF

chmod +x /userconfig/NAT_AUTO_WAN

然后上面 2 个文件在光猫里创建好后,可以去 Lucky 创建定时任务:

#!/bin/sh
HOST="192.168.1.1"
PORT="23"
USER="root"
PASS="Zte521"

{
  sleep 1
  echo "$USER"
  sleep 1
  echo "$PASS"
  sleep 2
  echo "/userconfig/NAT_INIT"
  sleep 2
  echo "/userconfig/NAT_AUTO_WAN"
  sleep 1
  echo
  sleep 3
  echo "exit"
} | nc -v -w 10 "$HOST" "$PORT"

最后

如果有错别字可以提醒下,希望你能像我一样顺利,转载请注明出处哈。

感觉用 AI 学习新知识确实很方便,haha,终于不用纠结要不要买硬路由或者用软路由了。

收藏
送赞
分享

8

主题

88

回帖

0

牛值

初出茅庐

内外网两套班子的确很烦人,也困扰了我很多年。幸亏安装了飞牛,按照本坛大神徐大大的指导,用飞牛虚拟机装了openwrt做旁路由,在dnsmasq里面加了一个本地域名解析的address,现在内网 域名访问一点问题都没有了。

4

主题

312

回帖

0

牛值

小有名气

算了,内网还是设置一下host吧

嗯,最简单就是建个内网的 dns 服务了,但是有切换延迟,有点强迫症。  详情 回复
4 天前
苟利国家生死以,岂因祸福避趋之

0

主题

2

回帖

0

牛值

江湖小虾

4 天前 楼主 显示全部楼层
linlin9 发表于 2025-12-3 08:35
算了,内网还是设置一下host吧

嗯,最简单就是建个内网的 dns 服务了,但是有切换延迟,有点强迫症。

9

主题

20

回帖

0

牛值

江湖小虾

原来内网用域名无法访问是光猫的问题,难怪我说怎么从路由拨号改光猫拨号后,内网就不能用域名访问了,不过这个是不是改dns规则更方便一些?直接内网解析域名到内网ip

0

主题

6

回帖

0

牛值

江湖小虾

需要这么麻烦吗,主路由上hosts 文件加一条,域名到内网地址,然后,路由dhcp dns填主路由内网地址即可。双向地址转换这玩意,企业网可以搞搞。家用完全没必要。

mosDNS也可以,而且他还能泛解析呦,不用一条条添加,直接自定义域名  详情 回复
4 天前

7

主题

170

回帖

0

牛值

初出茅庐

fnOS1.0上线纪念勋章社区上线纪念勋章

Jeff_COlmn 发表于 2025-12-3 13:36
需要这么麻烦吗,主路由上hosts 文件加一条,域名到内网地址,然后,路由dhcp dns填主路由内网地址即可。双 ...

mosDNS也可以,而且他还能泛解析呦,不用一条条添加,直接自定义域名
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则