没有做环境复现和抓包,下列是我的猜测,仅供参考:
假设有下列环境:
- 外网主机 ext: 203.0.113.101
- 光猫 gateway:WAN IP: 198.51.100.101 ,LAN IP: 192.168.1.1
- 你的内网手机 phone:LAN IP: 192.168.1.101
- 你的内网 srv: Web Server: LAN IP: 192.168.1.102
光猫配置的 DNAT: 198.51.100.101:28080 -> 192.168.1.102:80
从外网主机 ext 连接内网 srv:
1. ext 发出封包给有公网 IP 的光猫 gateway:
IP[SRC=203.0.113.101(ext), DST=198.51.100.101(gateway)] TCP[SPORT=53103(random), DPORT=28080]
2. gateway 收到封包,做 DNAT 修改目的 IP 地址和目的端口,然后发给 srv:
IP[SRC=203.0.113.101(ext), DST=192.168.1.102(srv)] TCP[SPORT=53103, DPORT=80]
3. srv 收到封包,然后回复:
IP[SRC=192.168.1.102(srv), DST=203.0.113.101(ext)] TCP[SPORT=80, DPORT=53103]
4. srv 发出的 reply packet 首先到达 gateway ,gateway 默认对 LAN-to-WAN 流量做 SNAT ,因为这个封包的地址匹配一条之前配置的端口转发规则,所以 SPORT 也会改回去:
IP[SRC=198.51.100.101(gateway), DST=203.0.113.101(ext)] TCP[SPORT=28080, DPORT=53103]
5. 外网主机 ext 收到 reply packet, 在它看来这就好像是 gateway 的 28080 端口直接发给它的,根本感觉不到内网 srv 的存在。
从内网主机 phone 通过公网 IP 198.51.100.101 和映射端口 28080 连接内网 srv:
1. phone 发出封包给 gateway:
IP[SRC=192.168.1.101(phone), DST=198.51.100.101(gateway)] TCP[SPORT=48131(random), DPORT=28080]
2. gateway 收到封包,修改目的地址,然后发给 srv:
IP[SRC=192.168.1.101(phone), DST=192.168.1.102(srv)] TCP[SPORT=48131, DPORT=80]
3. srv 收到封包,然后回复:
IP[SRC=192.168.1.102(srv), DST=192.168.1.101(phone)] TCP[SPORT=80, DPORT=48131]
4. 根据 srv 的路由规则,这个封包不需交给 gateway 转发,可以直接通过以太网发给 phone, srv 对 phone 的 IP 地址做 ARP 解析,然后构造以太帧交给网卡.
5. phone 收到这个封包,TCP session 由一个四元组 ( SRC_IP, DST_IP, SRC_PORT, DST_PORT )确定,由于 sender 和最初的 DST 198.51.100.101 (gateway) 不一致,所以 phone 的 os 不认为这是之前那个 TCP session 的 reply ,所以丢弃封包。
解决方法其一,配置光猫(网关设备)的 hairpin NAT ,什么是 hairpin NAT:
https://help.mikrotik.com/docs/display/ROS/NAT#NAT-HairpinNAThairpin NAT 正确配置之后,在以上的第二步 (gateway to srv) 的过程中,封包的 SRC IP 也会被修改,那么 srv 的 reply 封包的 DST IP 就会变成 gateway 的,而不是最初的 real sender, 再由 gateway 发给 real sender.