前言的前言
文中对于数据包的分析,是本文的核心中的核心, 望读者细读!
前言
这是我前几天遇到的一个实际问题:
我在实验室的服务器(物理机)上启动了一个虚拟机, 虚拟机通过网桥连接了服务器的一个网卡从加入到服务器所在的内部互连网段.
这个时候我希望通过访问服务器的指定端口, 来连接虚拟机, 注意我们访问服务器使用的是另一个网卡, 与虚拟机并不在同一个网段!
显然这需要配置DNAT, 但是配置后连接被拒绝, 百思不得解之后在知乎提问:
iptables 配置DNAT连接ssh ,为什么仍然提示端口拒绝
非常感谢
@Virtual @gongjunhe @染红了的枫叶林 三位同志的指点, 现将所学奉上.
拓扑
H-1
我的个人主机, IP为:
H-2
物理机服务器, IP为:
H-3
虚拟机, IP为:
可以看到H1和H2的em2在同一网段, H3和H2的em1在同一网段
即:
注意:
在下面的截图中,
- H1 对应了 kingdo@kingdo-server
- H2 对应了 kingdo@crane22
- H3 对应了 vagrant@zhangqi
配置
初始状态
filter表的默认Target都是Accept;
nat表没有建立任何规则;
Linux的路由转发确保是打开状态.
配置DNAT
我们的目标是, 通过H2的11122端口访问H3的22端口,即:
211.69.198.211:11122 ---> 192.168.111.101:22
配置如下规则:
sudo iptables -t nat -A PREROUTING -d 211.69.198.211 -p tcp --dport 11122 -j DNAT --to-destination 192.168.111.101:22
此时我们在H2上进行测试:
此时在H1上进行测试:
一个是拒绝连接, 一个是超时,这是为什么呢?
我们看下面这个图, 如果数据从H2上发送, 那么将会经过OUTPUT和POSTROUTING两个链,但是我们的DNAT规则其实是配置在PREOUTING中的,因此我们从H2上访问,实际上并没有进行地址转换,因此连接被拒绝!
因此我们在OUTPUT中再配置一个看看:
sudo iptables -t nat -A OUTPUT -d 211.69.198.211 -p tcp --dport 11122 -j DNAT --to-destination 192.168.111.101:22
再尝试ssh连接:
我们发现和H1一样, 超时了,很好! WHY?
我们分别打印,H2和H1连接H3的时候, H3上的抓包情况:
H2链接时:
H1连接时:
说明H3的的确收到了来自H1和H2的连接请求.
原因分析
这是因为什么呢?
因为H1和H2的数据包发送到H3, H3想返回数据,但是发现数据发不出去,因为源地址不可达!
以H1为例:
- H1发出的,最原始数据包是:
211.69.198.232:50648 => 211.69.198.211:111222
- 在H2中进行DNAT后:
211.69.198.232:50648 => 192.168.111.101:22
- 这也就意味着, 我们必须要在H2中接收到H3发来的:
192.168.111.101:22 => 211.69.198.232:50648
- 然后根据DNAT回复原来的socket:
211.69.198.211:111222 => 211.69.198.232:50648
经过上述过程, 就完成了一次通讯!
但是问题出在了第三步,那就是H3没办法将数据包发送到H2中, 因为目的地址其实是
211.69.198.232
也即,这是H1的地址,因此即使是H3可以路由到H1(在我的机器上的确是这样的),那么也无法完成上述的环路!
怎么办呢?
配置SNAT
我们需要将包的源地址,进行SNAT转化,将其修改为H2的地址从而帮助完成环路:
sudo iptables -t nat -A POSTROUTING -d 192.168.111.101/32 -j MASQUERADE
看看,此时是否成功:
H1:
[图片上传失败...(image-eb2b58-1636597174011)]
H2:
解决问题!
那么此时完整的环路是怎样的呢?
还是以H1为例:
- H1发出的,最原始数据包是
211.69.198.232:port1 => 211.69.198.211:111222
- 在H2中进行DNAT后
211.69.198.232:port1 => 192.168.111.101:22
- 在H2中进行SNAT后
192.168.250.22:port2 => 192.168.111.101:22
- H3返回数据包
192.168.111.101:22 => 192.168.250.22:port2
- 根据SNAT恢复
192.168.111.101:22 => 211.69.198.232:port1
- 根据DNAT恢复
211.69.198.211:111222 => 211.69.198.232:port1
上述过程, 用梁耀湘的话说,那就是:畅通无阻
后记
我们来分析一下, 为什么H2不做SNAT, 也无法成功呢?
前面提到, 想要完成回路,H2必须要接收到来自H3的包, 虽然我上面的拓扑没有画, 但是其实H3是可以访问到H2.
但是依然不行, 这个是因为H3回到H2的包源地址和目标地址必须是确定的,这样才能根据DNAT的记录去恢复原来的地址.
但是H3访问H2其实也是通过SNAT转发, 这样回到H2的时候, 源地址其实已经改变了,因此依然无法完成回路.
那么如果H3可以直接把数据给到H2,是不是就不用SNAT了呢?是的!
但是我们要用H2另一个网段, 即
192.168.250.22:11122 => 192.168.111.101:22
我们分析下环路:
- H2发出的,最原始数据包是
192.168.250.22:port1 => 192.168.250.22:111222
- 进行DNAT后
192.168.250.22:port1 => 192.168.111.101:22
- 此时H2需要收到H3的数据包
192.168.111.101:22 => 192.168.250.22:port1
这个关键的过程由于两者在同一网段,是可以轻松实现的.
那么这种情况下是不需要进行SNAT的.当然了,这种配置是没有价值的!
网友评论