众所周知,当一个tcp/ip服务使用nat映射出公网的时候,在同一内网的设备无法通过公网ip访问这个服务
whq12520于某天安装mcsm面板,使用nginx反代ssl的时候遇到这个问题,就打算浅浅研究一下
举个例子,存在一个192.168.1.0/24的内网(192.168.1.xxx),NAT网关为192.168.1.1,网关对外公网ip为100.128.1.1的网络。
其中,192.168.1.2(server1)使用80端口对外开放了一个http服务,网关同时设定了端口映射规则10.128.1.1:80->192.168.1.2:80。这个规则意味着所有目标地址为10.128.1.1:80的数据包在经过网关时,目标地址会被网关替换成192.168.1.2:80,源地址不变。
一个正常的tcp握手请求如图所示
这时,tcp握手数据包正常到达server1,然后server回应请求也会经过网关NAT地址转换,如图所示
这时,tcp握手正常进行
如果一个在内网的pc1访问10.128.1.1:80的http服务,就会遇到nat回环的问题,tcp会因为地址不对而导致握手异常。
现在,在同一内网的pc对10.128.1.1:80发起一个tcp握手请求
我们看到,握手数据包正常到达server1。但请注意,server1收到的这个tcp握手请求数据包的源地址ip和server1自身在同一个内网。
接下来server1应该响应tcp握手请求,如图所示
这次tcp握手回应似乎有点不一样,因为数据包的目标ip与发送者server1在同一个内网,所以server1本身的路由规则不会把数据包发给网关,意味着直接通过内网交换到达pc1。
一开始pc1向10.128.1.1:80发送的tcp握手请求,预期应收到源地址为10.128.1.1的回应,但实际收到的是来自192.168.1.2:80的回应,与预期源ip不符合,结果导致tcp握手失败。
要解决NAT回环也很简单,目前有两个办法
方法1:DNS劫持(需要域名访问)
假如abc.net域名解析到10.128.1.1,内网设备PC1无法通过域名访问server1,遇到nat回环问题
解决方法则是在DNS层面配置域名劫持,把pc1的abc.net域名直接劫持到192.168.1.2而不是10.128.1.1,这样tcp握手请求就不会经过NAT网关的地址转换,直接与server1通信。
方法2:配置网关的NAT回环
在网关配置一个NAT回环,原理是当内网的pc1的tcp握手请求经过网关时,不仅仅转换目标地址,连同源地址也一并转换。原理如图所示