Iptables 转发规则
iptables 是 linux 中的防火墙模块,用于网络包的过滤与转发,一共可以分为五链四表。

iptbles 的匹配规则
一台主机中,可能会具有多个网卡,这些网卡会有不同的网络地址,但是所有网卡会共用同一个 iptables 匹配规则,也会共用宿主机的路由转发规则。
在路由选择中,只有最终判断为本地地址,如 127.0.0.1,本机的网卡地址的网络包才会被转发到 INPUT,而 docker 虚拟网卡上挂载的地址,则会被转发到虚拟网卡上,而不是直接进入INPUT 链中。注意,虚拟网卡上的转发是不经过 iptables 的,一个网络包到达 docker0 网卡后只会经过网卡的转发规则,直接被转发到对应的进程中。在进入 docker 进程后,使用的 iptables 规则和宿主机 iptables 规则是不相同的。
外部的流量在PREROUTING 链进行 DNAT 后,会根据目的网络地址来判断是否能够匹配本地路由地址,否则将会被转发到 FORWARD 链中。
内部的流量流出时,会直接根据目的地址判断是否为本地流量,如果是本地流量则不经过 OUTPUT 链,直接被转发到 INPUT 链中。这意味着 localhost 与 127.0.0.1 这两个地址是不会经过任何的DNAT 的。如果目的地址不是本机地址,那么会经过 OUTPUT 和 POSTROUTING链进行 DNAT 和 SNAT,这时候会再次通过路由表判断流量的地址转发到具体的网卡上。
不容易理解的地方
如果一个主机挂载了一个 docker0 网卡,那么 iptables 的转发规则就会稍微有些难以理解。
- 172.0.0.x 网段不是本机的 ip 地址,因此在路由选择中不会转发给 INPUT,而是会转发给 FORWARD,然后经过 POSTROUTING,然后转发给 docker0 网卡,docker0 网卡会根据目的 ip 地址将网络包转发给虚拟机,注意此时的虚拟机收到网络包后已经不与宿主机使用同一个 iptables。
- localhost 和 127.0.0.1 会经过路由选择后直接转发给 INPUT,不能够经过任何的 DNAT 修改,因此针对 localhost 的转发都是无效的。
- DNAT 和 SNAT 是具有记忆性的。如果一次 tcp 中,宿主机给出流量做了 DNAT,那么收到这个 tcp 的回包时,将会自动进行反操作,因此 docker 中的虚拟容器只需要一次 DNAT 就可以访问外界流量了。
如何做 NAT 转换
1、首先需要开启端口转发
2、 sudo iptables -t nat -A PREROUTING -d x.x.x.x -p tcp -dport x -j DNAT --to-destinaton x.x.x.x:x
3、 sudo iptables -t nat -A POSTROUTING -d x.x.x.x -p tcp -dport x -j SNAT --to-source x.x.x.x
4、需要在 FORWARD 链中放行流量,例如
sudo iptables -A FORWARD -i eth0 -o eth0 -j ACCEPT
5、如果只需要在本主机进行端口转换,则应该使用重定向来代替
sudo iptables -t nat -A PREROUTING -d 127.0.0.1 -dport x -j REDIRECT to-ports x
利用 string模块完成应用层过滤
iptables 的 string 模块可以将网络包中的关键词进行匹配,从而实现禁止访问某些 url,禁止访问某些内容,或者禁止回复某些内容的效果。具体代码如下:
sudo iptables -t filter INPUT -m string --algo bm --string 'sf' -j DROP
但是,iptables 不能够确定字符串出现的位置,因此可能会出现误伤的情况。