基于iptables实现内网穿透

其实这个问题我在17年10、11月份的时候就遇到了,当时没有解决。当时我在AWS上折腾docker,我有一个php的docker想要访问宿主机的mysql,两个机器网络不一样(docker的傻逼网络?还是我tmd从aws处又拿了一个内网ip?),宿主机是172.31.x.x,docker是172.32.x.x,需求就是如何在docker里访问宿主机的mysql。(讲道理可以直接访问啊,但最后还是没搞定,具体情况记不清了,后来那台ubuntu好像sshd挂了,又开了一台amz linux ami,就没复现这个问题)

现在这个问题在我配置mysql innodb cluster时遇到的。我原本配置的mysql router(windows)有莫名奇妙的问题。在并发创建mysql连接时返回socket错误。

2018-01-24 17:27:39 DEBUG   [48d4] Write error: SystemError: 无法立即完成一个非阻止性套接字操作。
2018-01-24 17:27:39 DEBUG   [48d4] [routing:TestCluster_default_rw] Routing stopped (up:16477b;down:290b) Copy server-client failed: SystemError: 无法立即完成一个非阻止性套接字操作。

于是只能在virtualbox的ubuntu中重新配置一个mysql router。而又因为原来宿主机上的mysql集群同步ip配置的是172的外网网卡ip,不想去修改那个配置,导致mysql router读取集群配置时获取的链接因网段不同无法登陆。

当然出于我对于linux以及对计算机网络的了解,我觉得这件事情只需要修改docker中发出数据包的目的地址ip就可以达成目的。

原理是比较简单,但iptables是linux下成名已久的复杂工具。虽然有很多教程,但是很多都语焉不详。

iptables有四表五链,表以功能划分,链则表现数据包的生命周期。

Filter表——过滤数据包
Nat表——Network Address Translation。分为SNAT、DNAT、MASQUERADE、REDIRECT,修改ip和端口
Mangle表——修改TOS、TTL,MARK、SECMARK、CONNSECMARK标记数据包可实现路由
Raw表——过滤数据是否经过iptables

INPUT链
OUTPUT链
FORWARD链
PREROUTING链
POSTROUTING链

然而并不是所有数据包能走过所有数据链。一般是三种

1、PREROUTING→FORWARD→POSTROUTING

2、PREROUTING→INPUT

3、OUTPUT→POSTROUTING

看图

于是对于这个需求,我原来天然的以为只要

iptables -t nat -A INPUT -p tcp -d 172.31.35.109 --dport 3316 -j DNAT --to-destination 192.168.56.102
#或者
iptables -t nat -A PREROUTING -p tcp -d 172.31.35.109 --dport 3316 -j DNAT --to-destination 192.168.56.102

当然这根本不起效果,因为数据包根本没有通过PREROUTING、INPUT链。

所以正解是

iptables -t nat -A OUTPUT -p tcp -d 172.31.35.109 --dport 3316 -j DNAT --to-destination 192.168.56.102

iptables设置固化还需要另外2个工具,分别是iptables-save和iptables-restore。于是固化可以这样实现。

#>重定向符的权限问题,通过提升bash权限把语句当脚本执行
sudo sh -c "iptables-save > /etc/iptables.rules"
sudo iptables-restore < /etc/iptables.rules

#固化
#/etc/network/interface
#文件后添加
pre-up iptables-restore < /etc/iptables.rules
post-down iptables-save > /etc/iptables.rules

万一把iptables玩崩了,还可以这么重置iptables。

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t raw -F
iptables -t raw -X
iptables -t security -F
iptables -t security -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

net.ipv4.ip_forward=1这个设置好像只影响FORWARD链,这里的例子不需要设置这个值。

然而只设置iptables并不能起作用,原因见最后一张图,数据包先经过路由再到OUTPUT链上。而目的ip 172.31.35.109这个内网地址就被吸到路由黑洞里了,所以还需要配上路由。(据说有用路由黑洞挡ddos的操作)

route add -host 172.31.35.109 dev enp0s3

#静态路由
#/etc/network/interface
#文件后添加
up route add -host 172.31.35.109 dev enp0s3

 

参考:

https://www.netfilter.org/projects/iptables/index.html

https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html

https://en.wikipedia.org/wiki/Iptables

https://wiki.archlinux.org/index.php/iptables

https://help.ubuntu.com/community/IptablesHowTo

https://www.cnblogs.com/clouders/p/6544584.html

iptables学习笔记(2)

 

 

 

 

 

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注