原理
写代码的人都知道,在写一个系统的时候,为了保持这个系统的灵活性和可扩展性,我们经常会在系统的某些地方留个坑,换句话说就是留一些钩子,让别人在这钩子里干一些事情,扩展整个系统的功能。iptables 实际上是对 Linux 网络栈钩子里实现的逻辑。
iptables原理图
官网的Iptables架构图:
更加详细的图:
最完整的一张原理图
一个数据包进来,首先会经过 PREROUTING 链,PREROUTING 链最重要的一个功能就是可以修改数据包目的地址和端口。过了 PREROUTING 之后,内核会根据数据包的目的地址来决定该数据包是进入 INPUT 链还是 FORWARD 链。发送给本机的数据包经过 INPUT 链之后就直接交给本地的进程处理了;至于非本机的数据包就会根据 FORWARD 的规则来判断是否需要转发该数据包。所有从本机出去的数据包最后都需要经过 POSTROUTING 链,POSTROUTING 链的最重要的一个作用是修改数据包的源地址。
层级调用关系
These chains have no policy; if a packet reaches the end of the chain it is returned to the chain which called it
换句话说,iptables 有类似于函数调用的层级关系!
NAT
SNAT
SNAT 发生在 postrouting 阶段,将本机产生的所有的数据的源地址进行相应的修改。如果要启用 SNAT,只需在 iptables 规则链中添加-j SNAT
和--to-source
指定数据包的 IP 地址即可,下面是几个例子:
# 将数据包的源地址修改为1.2.3.4。
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
# 将数据包的源地址修改为1.2.3.4至1.2.3.6中的任意一个。
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
Masquerading
有的时候 IP 地址可能会动态的发生变化,因此,如果像上面的例子那样指定死了 IP 地址的话,当 IP 地址一发生变化,就需要重新修改规则了。为了省去这样的麻烦,你可以使用-j MASQUERADE
,-j MASQUERADE
告诉 iptables 总是将数据包的源地址修改为网络接口的 IP 地址(如果从 eth0 出去,就使用 eth0 的地址,如果从 eth1 出去,就使用 eth1 的地址)。下面是一个例子:
# 将所有从ppp0出去的数据包的源地址修改为ppp0的IP地址
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
DNAT
DNAT 是在 PREROUTING 链中修改数据包的目的地址,你可以在规则中使用-j DNAT
和--to-destination
来使用 DNAT,--to-destination
是指定数据包的目的地址是什么。下面是 iptables 的一些例子:
# 将来自eth0的数据包的目的地址修改为5.6.7.8
iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8
# 指定随意选用一段IP地址
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10
## Change destination addresses of web traffic to 5.6.7.8, port 8080.
iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080
一些心得
PREROUTING 和 POSTROUTING 两条链是游离在 Linux 系统之外的,所有一些修改数据包的逻辑可以放在这里面做。