你可能会问,iptables 的默认链就已经能够满足我们了,为什么还需要自定义链呢?
当默认链中的规则非常多时,不方便我们管理。
想象一下,如果 INPUT 链中存放了 200 条规则,这 200 条规则有针对 httpd 服务的,有针对 sshd 服务的,有针对私网 IP 的,有针对公网 IP 的,假如,我们突然想要修改针对 httpd 服务的相关规则,难道我们还要从头看一遍这 200 条规则,找出哪些规则是针对 httpd 的吗?这显然不合理。
所以,iptables 中,可以通过自定义链即可解决上述问题。
假设,我们自定义一条链,链名叫 IN_WEB
,我们可以将所有针对 80
端口的入站规则都写入到这条自定义链中,当以后想要修改针对 Web 服务的入站规则时,就直接修改 IN_WEB
链中的规则就好了,即使默认链中有再多的规则,我们也不会害怕了,因为我们知道,所有针对 80
端口的入站规则都存放在 IN_WEB
链中,同理,我们可以将针对 sshd
的出站规则放入到 OUT_SSH
自定义链中,将针对 Nginx
的入站规则放入到 IN_NGINX
自定义链中,这样,我们就能想改哪里改哪里,再也不同担心找不到规则在哪里了。
但是需要注意的是,自定义链并不能直接使用,而是需要被默认链引用才能够使用,空口白话说不明白,等到示例时我们自然会明白。
说了这么多,我们来动手创建一条自定义链,使用 -N
选项可以创建自定义链,示例如下:
$ iptables -N IN_WEB
$ iptables -nvL
Chain INPUT (policy ACCEPT 51 packets, 5036 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 28 packets, 4128 bytes)
pkts bytes target prot opt in out source destination
Chain IN_WEB (0 references)
pkts bytes target prot opt in out source destination
自定义链创建完成后,查看 filter 表中的链,如上图所示,自定义链已经被创建,而且可以看到,这条自定义链的引用计数为0(0 references
),也就是说,这条自定义链还没有被任何默认链所引用,所以,即使 IN_WEB
中配置了规则,也不会生效,我们现在不用在意它,继续聊我们的自定义链。
好了,自定义链已经创建完毕,现在我们就可以直接在自定义链中配置规则了,如下所示,我们配置一些规则用于举例。
$ iptables -t filter -I IN_WEB -s 10.0.1.201 -j REJECT
$ iptables --line-numbers -nvL IN_WEB
Chain IN_WEB (0 references)
num pkts bytes target prot opt in out source destination
1 0 0 REJECT all -- * * 10.0.1.201 0.0.0.0/0 reject-with icmp-port-unreachable
如上所示,对自定义链的操作与对默认链的操作并没有什么不同,一切按照操作默认链的方法操作自定义链即可。
现在,自定义链中已经有了一些规则,但是目前,这些规则无法匹配到任何报文,因为我们并没有在任何默认链中引用它。
既然 IN_WEB
链是为了针对 Web 服务的入站规则而创建的,那么这些规则应该去匹配入站的报文,所以,我们应该用 INPUT
链去引用它。
当然,自定义链在哪里创建,应该被哪条默认链引用,取决于实际的工作场景,因为此处示例的规则是匹配入站报文,所以在 INPUT
链中引用自定义链。
$ iptables -I INPUT -p tcp --dport 80 -j IN_WEB
$ iptables -nvL
Chain INPUT (policy ACCEPT 30 packets, 2904 bytes)
pkts bytes target prot opt in out source destination
0 0 IN_WEB tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 16 packets, 2496 bytes)
pkts bytes target prot opt in out source destination
Chain IN_WEB (1 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 10.0.1.201 0.0.0.0/0 reject-with icmp-port-unreachable
如上,我们在 INPUT
链中添加了一条规则,访问本机 80
端口的 tcp 报文将会被这条规则匹配到。
而上述规则中的 -j IN_WEB
表示:访问 80
端口的 tcp 报文将由自定义链 IN_WEB
中的规则进行处理。
没错,在之前的示例中,我们使用 -j
选项指定动作,而此处,我们将“动作”替换为了“自定义链”,当 -j
对应的值为一个自定义链时,就表示被当前规则匹配到的报文将交由对应的自定义链处理,具体怎样处理,取决于自定义链中的规则,当 IN_WEB
自定义链被 INPUT
链引用以后,可以发现,IN_WEB
链的引用计数已经变为 1
,表示这条自定义链已经被引用了 1 次。
那么此刻,我们在 10.0.1.201
上尝试访问本机(10.0.1.200
)的 80
端口,已经被拒绝访问,证明刚才自定义链中的规则已经生效了。
$ curl 10.0.1.200
curl: (7) couldn't connect to host
自定义链还可以引用其他的自定义链,感兴趣的话,动手试试吧。
评论区