IPSET of Linux

Wolf

使用 iptables 来拦截 IP,是一种比较简单且常见的应对网络攻击的方式。有时候可能会封禁成千上万个 IP,如果添加成千上万条规则,会十分影响服务器的性能。ipset 就是为解决此问题而生。

背景

IPSets 是 Linux 内核的一个框架,可以使用ipset来管理。IPSets 依据 IP 类型以 Hashtable 的方式大量储存 IP地址/网段/端口/MAC地址/网络接口名称,查询十分便捷且迅速。

  • 你可以仅用一条iptables来匹配大量的IP地址或端口号。而不用写一堆iptables规则,从而将匹配时间从 O(n) 缩减到了 O(1)。
  • 可以在不改动iptables规则的情况下进行对需要匹配的IP地址进行动态增减,对系统性能基本无任何影响。
  • 可以用一条iptables规则来快速匹配IP类型的组合,如IP地址与端口的组合,IP地址与MAC的组合,IP地址与网段的组等等。

安装

在Debian下仅用一条命令即可,如下:

1
:~$ sudo apt-get install ipset

创建 IPSet 规则

  • 创建 IPs 规则
    1
    2
    3
    4
    5
    6
    :~$ ipset create test hash:ip
    :~$ ipset add test 114.114.114.114
    :~$ ipset add test 8.8.8.8
    :~$ ipset add test 1.1.1.1
    :~$ ipset add test 2.2.2.2
    :~$ ipset add test 3.3.3.3
  • 创建网段规则
    1
    2
    3
    :~$ ipset create test hash:net
    :~$ ipset add test 224.0.0.0/4
    :~$ ipset add test 192.168.1.0/24

在 iptables 里引用 IPSet

1
:~$ iptables -I INPUT --match set --match-set test src --jump DROP

上面的命令为将数据包的源地属于名为 test 的 IPSets 全部丢掉。

iptables里用set模块来启用IPSet
src代表对数据包的源地址进行匹配,这里也可以用dst来匹配目标地址。

添加注释

1
2
3
4
5
6
7
8
9
10
11
12
13
:~$ ipset create test hash:ip comment
:~$ ipset add test 1.1.1.1 comment "Black IP"
:~$ ipset list test
Name: test
Type: hash:ip
Revision: 0
Header: hashsize 1024 maxelem 65536 comment
Size in memory: 2619
References: 3
Number of entries: 14
Members:
1.1.1.1 comment "Black IP"
...

添加匹配计数

1
2
3
4
5
6
7
8
9
10
11
12
13
:~$ ipset create test hash:ip comment counters
:~$ ipset add test 1.1.1.1 comment "Black IP"
:~$ ipset list test
Name: test
Type: hash:ip
Revision: 0
Header: hashsize 1024 maxelem 65536 counters comment
Size in memory: 2619
References: 3
Number of entries: 14
Members:
1.1.1.1 packets 0 bytes 0 comment "Black IP"
...

保存和导入 IPSet 规则

1
2
:~$ ipset save -f blacklist
:~$ ipset restore -f blacklist

例子

假设有一万条IP地址需要我们拦截,而使用iptables时只能这样做

1
2
3
4
5
6
iptables -I INPUT --source 1.1.1.1 --jump DROP
iptables -I INPUT --source 2.2.2.2 --jump DROP
iptables -I INPUT --source 3.3.3.3 --jump DROP
iptables -I INPUT --source 4.4.4.4 --jump DROP
...
...

因为iptables的规则是按照顺序进行匹配的,所以每条数据包都需要对这一万条拦截规则进行匹配,而每次的匹配都需要去反复读取数据包的源IP地址,这时时间复杂度为 O(1000),会严重拖累iptables的性能。

而我们现在改为使用ipset来进行匹配,就变成了

1
2
3
4
5
6
7
8
ipset create test hash:ip
ipset add test 1.1.1.1
ipset add test 2.2.2.2
ipset add test 3.3.3.3
ipset add test 4.4.4.4
...
...
iptables -I INPUT --match set --match-set test src --jump DROP

可以看到,现在我们只使用了一条iptables 规则,所以此时只需要读取取一次数据包的源IP,然后在IP Sets的哈希表里进行匹配即可,时间复杂度被简化成了 O(1),这对iptables的性能提升十分巨大。


References: