概述
!!!!!学习累,没人带好难
有个需求,就是在本地通过一台代理(1.1.1.1)访问它后面的服务(2.2.2.2),需要直接配置本地应用的访问地址为服务的地址,但是本地网络到服务又是无法直接通信的。于是想到用iptables规则,对发出的数据包做dnat处理,即本地应用直接访问2.2.2.2,然后将请求的目的地址通过dnat替换成1.1.1.1。先说一下成功的做法,后面再探讨一下操作的误区和一些思考。(以下操作全都在本地应用节点上进行)
百度搜索 “iptables 将主机发出的目的地址改掉” 这几个字找到答案:
iptables -t nat -A OUTPUT -d 2.2.2.2
-j DNAT --to 1.1.1.1
(完事了,就是这么简单)
下面说一下错误的做法:
iptables -t nat -A PREROUTING -d 2.2.2.2 -j DNAT --to 1.1.1.1
iptables -t nat -A POSTROUTING -s 1.1.1.1 -j SNAT --to 2.2.2.2
对这是错误的,想法是对的,操作是错的。先说一下为什么这么做,第一条规则是想把发送发往2.2.2.2的包的目的地址改成1.1.1.1,这样请求就可以通过1.1.1.1被代理到后面的服务2.2.2.2上面。然后第二条规则,是想将2.2.2.2返回的响应包的源的地址做snat,改成2.2.2.2,这样做的目的也是为了保证客户端请求和响应地址的一致性,以确保tcp会话的完整性,如果请求和响应的地址不通够不成一个完整的会话。
目前来看想法是没问题的,然而并没有达到预期的效果,在本地ping 2.2.2.2 ,同时另开一个shell进行tcpdump截包,发现数据包根本出不来。
对于修改请求包的目的地址,对比正确的操作,我们可以看到,规则加错了链,应该加到OUTPUT链,而不是PREROUTING链。于是我找到了下面这张图(来自简书-任总的精美技术文档 https://www.jianshu.com/p/e6360c2ac19d)。
从而复习了以下各条链作用的位置
prerouting:流入的数据包进入路由表之前。
input :通过路由表判断后目的地址是本机,然后进入本机内部资源。
output :由本机产生的数据向外转发
forward :通过路由表判断目的地址是本机,然后通过路由转发到其他地方。
postrouting:传出的数据包到达网卡出口前。
[img=https://img-bbs.csdn.net/upload/202009/08/1599532531_195664.png][/img]
结合大佬的解释和我遭遇的挫折,我理解或者我猜想,postroutging链只处理网卡接收的数据且,只能添加SNAT规则,不能添加DNAT规则,prerouting链与此正好相反,只处理应用发出的数据包,只能添加DNAT规则,不能添加SNAT规则我尝试过确实如此。
用户空间的请求包为出方向的数据包是这样走的:用户空间---->output----->(经过路由)------>postrouting
服务器应的数据包是入方向的数据包是这样走的:prerouting----->(经过路由)----->input----->用户空间
我要做的是出方向的DNAT,上面说了postrouting不能添加DNAT规则,那么只能在output链添加DNAT规则链了,猜想与最开始百度的结果不谋而合了。基本上就是这么回事了,解决了请求包的DNAT的需求。
看上去我还漏了一个多余的需求,就是响应包的SNAT,说它多余是因为真的多余,这个是不需要做的。难道不需要保持请求响应地址的一致性来确保tcp会话的完整性吗??就这个问题我思考了 a long time,看上面的图片,数据在output链经过DNAT处理后,被送到路由处理,然后才到postrouting从网卡发送出去,路由工作在哪,ip层好吧。这个地方我就想了,OUTPUT链工作在哪一层,tcp层还是ip层,tcp包不带ip,那至少不在tcp层,那就认为在ip层了。既然ip包的封装是在OUTPUT链所在的ip层做的,那这个地方我就可以认为与服务端建立会话的地址就是DNAT之后的地址,也就是1.1.1.1。
事实上我做了DNAT以后,通过ping,通过curl命令访问对端服务,都能正常访问了,既然如此,我只能这么猜了,有猜的不对的地方请大佬带带我
最后
以上就是欣喜小蜜蜂为你收集整理的iptables 出数据包做DNAT的全部内容,希望文章能够帮你解决iptables 出数据包做DNAT所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复