使用 ipset 管理大批量 IP 地址
如果需要开放或者阻止一大批 IP 地址,直接想到的办法就是往 iptables 配置文件里面写入一条记录。但是这样带来的问题是维护起来比较繁琐,而且如果有时需要加入 IP 地址的数目比较多的话,还会iptables查找的效率。为了解决这个问题,我们可以使用 ipset。使用 ipset 的好处是方便管理,而且 IP 地址的查找效率从 O(n) 降低到 O(1)。ipset 的处理原理是映射到 iptables 的一条规则上,本质上还是 iptables 负责处理进出的流量。
ipset 属于Linux内核模块,为了方便管理,大多数 Linux 发行版都提供了管理工具,下面以 CentOS 为例,分享一下我平时的使用 ipset 的经验。
一般情况下,操作系统默认是没有安装 ipset 的管理工具的,所以我们需要自己安装:
yum install ipset
因为 ipset 以集合的方式来存储 IP 地址,所以存储起来非常高效。但是,除了 IP 地址之外,ipset 还可以存储其它的数据类型,比如还可以存储一个网络段,端口号(支持 TCP 和 UDP,默认为 TCP),mac 地址,网络接口的名称,也可以存储以上类型的组合。
ipset 的基本用法
处理 IP 地址
我们可以创建一条规则,仅仅存储 IP 地址:
ipset create light_ip hash:ip
这样,我们就创建了一个名称为 light_ip,只是用来存储 IP 地址的集合。
接下里,我们可以往这个集合俩面添加 IP 地址:
ipset add light_ip 12.34.56.78
接下来,我们可以查看已经添加过的 IP 地址:
[root@test ~]# ipset list light_ip
Name: light_ip
Type: hash:ip
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16520
References: 0
Members:
12.34.56.78
从上面的输出结果中,我们可以看到,只添加了一个 IP 地址,还可以看到集合的默认大小是 1024,最大可以是 65536。(注:如果 IP 地址的数量超过了 1024,集合的大小会成倍增长,直到 IP 地址的数目增长到 65535)
到目前为止,我们已经创建了一个集合,并且往集合里面添加了 1 个 IP 地址。但是,操作系统并没有对这个集合里面的 IP 地址做任何处理,因为我们还没在 iptables 里面添加规则,前面讲过,ipset 里面的 IP 地址最终会映射到 iptables 的规则上。
接下来,我们往 iptables 里面天机一条规则:
iptables -I INPUT -m set --match-set light_ip src -j DROP
service iptables save
这样,我们就为新创建的集合添加了一条 iptables 规则。我们还可以继续往新创建的集合里面添加 IP 地址,可以及时生效,不需要重启 iptables。
ipset 的扩展用法
处理某一个 IP 地址段:
ipset create ip_segment hash:net
ipset add ip_segment 10.12.2.0/24
我们可以在原有的集合的基础上排除一部分 IP 地址,这样 ip_segment 这个集合所定义的规则就不会对这一部分 IP 地址生效。
ipset add ip_segment 10.12.2.0/30 nomatch
(注:这条规则有的版本上不支持,我试验的版本当时不支持)
同样,我们也可以添加单个 IP 地址:
ipset add ip_segment 6.7.8.9
这样,我么又有了一个 IP 地址的集合,我们只需把这个集合映射到 iptables 上的某一条规则上即可生效。
处理基于端口的 IP 地址的集合:
有时候我们需要开放某一个端口给某一批 IP 地址,但是又不想开放给所有的 IP 地址,这时候 ipset 的这种用法,就非常灵活。
首先,创建一个基于端口的 IP 地址的集合:
ipset create light_port hash:ip,port
接下里我们可以允许某一 IP 地址访问服务器的某一个端口:
ipset add light_port 1.2.3.4,5432
然后在 iptables 添加规则,允许这一组 IP 地址:
iptables -I INPUT -m set --match-set light_port src -j DROP
service iptables save
ipset 一些常用的命令列举如下:
ipset del light_port x.x.x.x # 从 light_port 集合中删除内容
ipset list light_port # 查看 light_port 集合内容
ipset list # 查看所有集合的内容
ipset flush light_port # 清空 light_port 集合
ipset flush # 清空所有集合
ipset destroy light_port # 删除 light_port 集合(前提是这个集合没有被使用)
ipset destroy # 销毁所有集合
ipset save light_port # 输出 light_port 集合内容到标准输出
ipset save # 输出所有集合内容到标准输出
ipset restore # 根据输入内容恢复集合内容
ipset 还有其他的用法,比如可以设置某一个 IP 地址的过期时间,这样我们可以只是禁用这个 IP 地址一段时间。我们不仅可以根据 hash 的方式来创建 IP 地址,还可以根据 bitmap、link 的方式来创建集合。这两种方法创建集合大小是固定的。