Linux 的包过滤功能,即 Linux 防火墙,它由 netfilter 和 iptables 两个组件组成。
其中,iptables分为四表五链,其中四个表包括:
其中,五链指的是:
INPUT 链:处理来自外部的数据。
OUTPUT 链:处理向外发送的数据。
FORWARD 链:数据转发。通过路由表后发现目的地址非本机,则匹配该链中的规则。
PREROUTING 链:处理刚到达本机并在路由转发前的数据包。
整个数据链在数据包到达LINUX内核时,整体的fiter链路如下所示:
可以简单化的理解:
当数据包刚到达系统时,就由PPREOUTING链负责
当数据包的目标是本机的话,就由INPUT链负责
当数据包从本地出去的话,就由OUTPUT链负责
当数据包的目标不是本地,而是要经过本地的路由,则由FORWARD负责
注意:如果我们只是操作filter表,其实就需要关心INPUT、OUTPUT和FORWARD链即可。
所以,我们简答的理解,iptable存在不同的表,表里有着不同的链,而在链中我们可以指定不同的规则。
这里,先说明iptables的命令格式:
iptables [-t 表名] 命令选项 [链名] [条件匹配] [-j 处理动作或者跳转]
如果没有设置表名,则默认为filter表,即默认添加-t filter
其中,命令选项
匹配条件
动作
接下来,我们通过几个常用指定来熟悉iptables的使用。
首先,我们如果想查看某一个表的所有链和规则,可以使用:
iptables --table filter --list
此时我们一般在没有其他配置的情况下,只会看到三个链的规则,分别是INPUT,FORWARD和OUTPUT:
此时,如果不写--table filter
,则默认也是查询filter表,并且--table
可以简化为-t
,--list
可以简化为-L
故我们最后想要查看filter表的命令可以简化为:
iptables -L
如果我们希望能够允许一个ip地址对当前LINUX主机的访问,可以使用下列命令:
iptables \
--table filter \
--append INPUT \
--source 192.168.3.20 \
--jump ACCEPT
这里,我们可以简化规则为:
iptables -A INPUT -s 192.168.3.20 -j ACCEPT
但是这种添加白名单的场景,一般是在我们拒绝所有ip访问的前提下添加的(因为一般默认都是能够访问的,添不添加没有任何意思,只是多了一个规则罢了)
注意:
上面的添加命令选项为--append
,表示在当前链的末端进行添加,如果我们想在首部添加,第一个生效,则可以使用-I
选项进行添加:
iptables -I INPUT -s 192.168.3.20 -j ACCEPT
此时,存在一个场景,我们希望能够拒绝一个ip对当前LINUX主机的访问规则,我们可以使用如下命令:
iptables \
--table filter \
--append INPUT \
--source 192.168.3.20 \
--jump REJECT
同样,我们可以简写为:
iptables -A INPUT -s 192.168.3.20 -j REJECT
它的意思就是希望拒绝ip地址为192.168.0.1
对我们当前主机的数据包访问,此时我们再次查看当前filter表的规则,会发现在INPUT链中多出一个规则:
此时,当我们在拒绝访问的主机上去ping当前主机,就发现无法访问了,同时我们也无法ping通192这个节点,这是因为数据包过去以后,我们还需要接受,同样要走INPUT的规则。
这里需要注意的事,我们在iptables的链中配置的规则,执行顺序是自上而下,故如果我们想要实现除了某个/某几个IP对主机的访问,其他ip地址都拒绝访问,应该要将允许访问的规则放在前面,最后添加一个DROP/REJECT规则进行丢弃或者拒绝,来达到我们的目的。
那如果我们希望删除配置好的规则,则可以使用--line-numbers
来查看每个规则的具体行号:
iptables -L --line-numbers
此时,我们想要删除某个具体的规则,则可以使用:
iptables --delete [链名称] [具体行号]
这里,需要注意的是:
--delete
可以简化为-D当然,还有其他的命令,可以对照规则介绍中的参数自定义实现。
一般来说,我们在iptables中执行的命令会立即生效,不需要任何规则的保存操作,但是如果你的主机存在时而重启的情况,则需要进行保存操作,因为机器重启后,iptables之前配置的规则就会自动丢失。
iptables-save > /etc/iptabels01.rule
等待重启后,我们可以应用之前保存的规则进行恢复:
iptables-restore < /etc/iptabels01.rule
iptables经常会使用到各种白名单访问的场景当中,下面简单介绍两种应用场景中iptables的使用。
那么,现在我们如果希望ip地址为192.168.0.1
和19.168.0.2
能够访问当前系统,其他全部丢弃,应该如何配置呢??
首先第一步,我们需要查看当前filter的链规则,没有其他与配置相关的规则处理后,依次添加两条允许访问规则和一条丢弃所有规则
iptables -A INPUT -s 192.168.0.1 -j ACCEPT
iptables -A INPUT -s 192.168.0.2 -j ACCEPT
iptables -A INPUT -s 0.0.0.0/0 -j DROP
iptables-save
此时即可完成我们的需求,但是如果你将上述的规则执行顺序进行了变化,例如你先执行DROP规则,再执行ACCEPT规则,就会导致最后在查看INPUT规则是下面的顺序:
INPUT all -- 0.0.0.0/0 0.0.0.0/0 DROP
INPUT all -- 192.168.0.1/0 0.0.0.0/0 ACCEPT
INPUT all -- 192.168.0.2/0 0.0.0.0/0 ACCEPT
这样,由于iptables规则是自上而下顺序执行的,就会导致先执行了DROP,已丢弃了所有,那么后面的ACCEPT已没有任何的意思,故我们需要将ACCEPT置于DROP的上方,或者通过-I
选项将规则添加到链的首部来实现我们的需求。
现在存在场景,主机中存在DOCKER启动的ZOOKEEPER服务,该服务未实现认证模式,存在安全漏洞,故我们需要对该服务的访问设置白名单:只指定ip地址为192.168.0.1
和192.168.0.2
对当前主机的2181端口的访问。
首先,我们查看iptables对于当前2181的规则:
iptables -nL |grep 2181
此时会默认出现两条规则:
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181 ctstate NEW,UNTRACKED
该规则允许所有流量对于主机的2181的访问,这其实是DOCKER网络为服务开启的iptables规则,而非我们自动配置的,我们可以通查看DOCKER链的规则找到答案:
> iptables -nL --line-numbers
Chain DOCKER (6 references)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181 ctstate NEW,UNTRACKED
4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:9091
5 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
6 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
...
故我们只是增加两条访问的规则,和一条丢弃所有的规则,并不能实现最后只允许指定ip地址访问的目的,因为在规则链的底部仍然存在这两条ACCEPT的规则(允许所有流量)的规则。
所以,我们的执行策略应该是:
这里有一个坑点:我们在上面看到了规则的行号分别为3和4,正常逻辑就是:
iptabels -D DOCKER 3
iptabels -D DOCKER 4
这时候,你再执行iptables -nL --line-numbers
你会惊奇地发现: ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181 ctstate NEW,UNTRACKED
这条规则依旧存在,这是由于当我们删除规则的时候,下面的规则会自动上移,故其实当我们执行iptabels -D DOCKER 4
的时候,其实删除的是下面的ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:9091
,然后你会发现,该服务可能都会受影响没法访问了(就问你坑不坑吧!!!)
故正确的执行命令应该是:
iptabels -D DOCKER 3
iptabels -D DOCKER 3
-I
一直添加到规则的首部:iptables -I DOCKER -s 0.0.0.0/0 -p tcp --dport 2181 -j DROP
iptables -I DOCKER -s 192.168.0.1 -p tcp --dport 2181 -j ACCEPT
iptables -I DOCKER -s 192.168.0.2 -p tcp --dport 2181 -j ACCEPT
其中:
最后,我们再查看2181的iptables规则,就如下所示:
ACCEPT tcp -- 192.168.0.1 0.0.0.0/0 tcp dpt:2181
ACCEPT tcp -- 192.168.0.2 0.0.0.0/0 tcp dpt:2181
DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2181
此时我们就实现了指定ip访问DOKCER服务的2181端口的白名单限制了。