使用iptables做NAT转发

648次阅读
没有评论
使用 iptables 做 NAT 转发

前言

很有必要记录下来,因为一直对 iptables 了解不够透彻,导致对 nat 一直是敬而远之。

直到昨天晚上看到了数据进入服务器,iptables 的转发图后。

一切都变得豁然开朗。

虽然话是这么说,但是开朗和彻底理解还是有些距离的。

也导致我一整个晚上都彻夜难眠。

使用 iptables 做 NAT 转发
当时时看了这张图开始对 iptables 豁然开朗

环境介绍

主机名 内网 ip 外网 ip 程序名称
主机 A 192.168.0.238/24 140.210.202.195
主机 B 192.168.0.178/24 140.210.197.113 nginx(port:80)

本次打算访问主机 A 外网 ip(140.210.202.195:80),通过转发,转发到主机 B 的 nginx 上

第一次尝试

主机 A 上执行下面代码

# 临时开启内核的转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward

#设置通过和返回两个方向的 nat
iptables -t nat -I PREROUTING -p tcp --dst 192.168.0.238 --dport 80 -j DNAT --to-destination 192.168.0.178:80

iptables -t nat -I POSTROUTING -p tcp -s 192.168.0.178 --dport 80 -j SNAT --to-source 192.168.0.238

这时候,以我的理解,网络就应该已经通了

因为正反向的转发都已经配置好了

但是我在浏览器中访问:主机 A 的公网 ip 时 (140.210.202.195),没有任何相应

在主机 A 上访问主机 A 的内网 ip:curl 192.168.0.238,没有任何响应

我一度十分沮丧,直到我想起,iptables 的模型中,数据包会因为 ip 是否为当前 ip 而分成两个路线

我开始在主机 B 上访问主机 A 的内网 ip:curl 192.168.0.238,一下子就通了,显得那么流畅

第二次尝试

首先解决在主机 A 上访问本机内网 ip 无相应的问题

按照 iptables 模型图来看,当服务器意识到 ip 指向自己时,nat 表下的 output 就开始起作用了

于是我敲下命令

# 在 nat 表下的 OUTPUT 链上设置 DNAT
iptables -t nat -I OUTPUT  -p tcp --dst 192.168.0.238 --dport 80 -j DNAT --to-destination 192.168.0.178:80

当我再次在主机 A 上访问自身内网 ip 时:curl 192.168.0.238,通了!!!

按捺住激动的感觉,开始了第三次尝试

第三次尝试

接下来就是解决公网 ip 访问,无法访问到主机 B 的 nginx

没有头绪的时候,我开始抓包了

首先是抓主机 A 内网访问主机 B,这个没问题,是通的

[root@master ~]# tcpdump -i eth0 tcp port 80 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:25:19.388160 IP 192.168.0.178.40416 > 192.168.0.238.http: Flags [S], seq 4138848512, win 29200, options [mss 1460,sackOK,TS val 140020 ecr 0,nop,wscale 7], length 0
10:25:19.388185 IP 192.168.0.238.40416 > 192.168.0.178.http: Flags [S], seq 4138848512, win 29200, options [mss 1460,sackOK,TS val 140020 ecr 0,nop,wscale 7], length 0
10:25:19.388360 IP 192.168.0.178.http > 192.168.0.238.40416: Flags [S.], seq 2892093041, ack 4138848513, win 28960, options [mss 1460,sackOK,TS val 140020 ecr 140020,nop,wscale 7], length 0
10:25:19.388375 IP 192.168.0.238.http > 192.168.0.178.40416: Flags [S.], seq 2892093041, ack 4138848513, win 28960, options [mss 1460,sackOK,TS val 140020 ecr 

接着就是浏览器访问主机 A 的公网 ip 了:

[root@master ~]# tcpdump -i eth0 tcp port 80 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:24:20.610393 IP 140.210.197.113.mbus > 192.168.0.238.http: Flags [S], seq 1934685210, win 29200, options [mss 1460,sackOK,TS val 81242 ecr 0,nop,wscale 7], length 0
10:24:20.610407 IP 140.210.197.113.mbus > 192.168.0.178.http: Flags [S], seq 1934685210, win 29200, options [mss 1460,sackOK,TS val 81242 ecr 0,nop,wscale 7], length 0
10:24:21.611655 IP 140.210.197.113.mbus > 192.168.0.238.http: Flags [S], seq 1934685210, win 29200, options [mss 1460,sackOK,TS val 82244 ecr 0,nop,wscale 7], length 0
10:24:21.611664 IP 140.210.197.113.mbus > 192.168.0.178.http: Flags [S], seq 1934685210, win 29200, options [mss 1460,sackOK,TS val 82244 ecr 0,nop,wscale 7], length 0

结果是,怎么看都是一个公网 ip 去试图访问一个内网 ip

没在一个网段肯定是不通的

没有条件,就创造条件,我开始给公网 ip 映射一个内网 ip:

# 公网 ip 访问内网时,映射一个内网 ip 给公网
iptables -t nat -I POSTROUTING -p tcp --dst 192.168.0.178 -j SNAT --to-source 192.168.0.238

试了下,通了,哈哈哈

又简单改进了一下最后的命令

iptables -t nat -I POSTROUTING -p tcp --dst 192.168.0.0/24 -o eth0  -j MASQUERADE 

已经可以完美使用了

最后

使用 iptables 做 NAT 转发
看完这张图整个逻辑完全清晰

贴几个有助于 iptables 学习的文章

正文完
 
评论(没有评论)