15 min read

ipset使用笔记

ipset使用笔记

简介

ipset是iptables的扩展,允许创建一次匹配整个“地址”集的防火墙规则。 与通过线性存储和遍历的普通iptables链不同,IP集存储在索引数据结构中,即使在处理大型集时,查找也非常高效。

ipset只是iptables的扩展,所以本篇文章不仅是ipset的使用笔记,同时也是iptables的使用笔记。

安装

// Debian
apt-get install ipset

//RHEL
yum -y install ipset

快速入门

需求,禁1.1.1.12.2.2.2IP访问服务器,使用以下iptables 命令可实现:

iptables -A INPUT -s 1.1.1.1 -j DROP
iptables -A INPUT -s 2.2.2.2 -j DROP

同时,我们如果使用ipset也可以实现

ip -N myset iphash
ipset -A myset 1.1.1.1
ipset -A myset 2.2.2.2
iptables -A INPUT -m set --set myset src -j DROP

上面的ipset命令创建了一个带有两个地址(1.1.1.1和2.2.2.2)的新集合( ipset类型为iphash )。

然后iptables命令引用带有匹配规范的-m set --set myset src ,这意味着“匹配源头与之匹配(即包含在内)名为myset的集合的数据包”

标志src表示匹配“源”。 标志dst将匹配“destination”,并且标志src,dst将在源和目标上匹配。

在上面的第二个版本中,只需要一个iptables命令,无论该组中包含多少额外的IP地址。 尽管此示例仅使用两个地址,但您可以轻松定义1,000个地址,而基于ipset的配置仍然只需要一个iptables规则,而前一种方法,如果没有ipset的优势,则需要1,000个iptables规则。

应用场景

ipset优点

除了性能提升之外,ipset还允许在许多场景中进行更直接的配置。

如果要定义一个防火墙条件,该条件与1.1.1.1或2.2.2.2中的所有数据包相匹配,并在mychain中继续处理,请注意以下内容不起作用:

iptables -A INPUT -s ! 1.1.1.1 -g mychain
iptables -A INPUT -s ! 2.2.2.2 -g mychain

如果一个数据包来自1.1.1.1,它将与第一个规则不匹配(因为源地址 1.1.1.1),但它将匹配第二个规则(因为源地址不是 2.2.2.2)。 如果数据包来自2.2.2.2,它将匹配第一个规则(因为源地址不是 1.1.1.1)。 规则相互抵消,所有数据包都匹配,包括1.1.1.1和2.2.2.2。

虽然还有其他方法可以正确构建规则并在没有ipset的情况下实现所需的结果,但没有一种方法可以直观或直接:

ipset -N myset iphash
ipset -A myset 1.1.1.1
ipset -A myset 2.2.2.2
iptables -A INPUT -m set ! --set myset src -g mychain

在上面,如果一个数据包来自1.1.1.1,它将与规则不匹配(因为源地址1.1.1.1与设置的myset匹配)。 如果数据包来自2.2.2.2,则它与规则不匹配(因为源地址2.2.2.2与设置的myset匹配)。

虽然这是一个简单的例子,但它说明了在单个规则中拟合完整条件的基本好处。 在许多方面,单独的iptables规则彼此是相互独立的,并且将单独的规则合并为单个逻辑条件并不总是直截了当,直观或最优,特别是当涉及混合正常和反向测试时。 ipset只是让这些情况下的生活更轻松。

ipset的另一个好处是可以独立于活动的iptables规则来操作集合。 添加/更改/删除条目是一件小事,因为信息简单且顺序无关紧要。 编辑平面列表不需要经过深思熟虑。 另一方面,在iptables中,除了每个规则是一个明显更复杂的对象这一事实之外,规则的顺序至关重要,因此就地规则修改更加繁重且可能容易出错。

配合NAT使用

出站NAT(SNAT或IP伪装)允许专用LAN内的主机访问Internet。 适当的iptables NAT规则匹配源自专用LAN的Internet绑定数据包,并将源地址替换为网关本身的地址(使网关看起来是源主机并隐藏其后面的私有“真实”主机)。

NAT会自动跟踪活动连接,以便将返回的数据包转发回正确的内部主机(通过将目标地址从网关地址更改回原始内部主机的地址)。

以下是执行此操作的简单出站NAT规则的示例,其中10.0.0.0/24是内部LAN:

iptables -t nat -A POSTROUTING \ -o eth0 -j MASQUERADE 

事实证明,这是ipset的另一个伟大的应用程序。 假设除了充当本地专用LAN(10.0.0.0/24)的Internet网关之外,您的盒子还可以直接路由到其他四个专用网络(10.30.30.0/24,10.40.40.0/24,192.168.4.0/23和172.22.0.0/22)。 运行以下命令:

ipset -N routed_nets nethash
ipset -A routed_nets 10.30.30.0/24
ipset -A routed_nets 10.40.40.0/24
ipset -A routed_nets 192.168.4.0/23
ipset -A routed_nets 172.22.0.0/22
iptables -t nat -A POSTROUTING \
         -s 10.0.0.0/24 \
         -m set ! --set routed_nets dst \
         -j MASQUERADE

正如您所看到的,ipset可以很容易地确定您想要匹配的内容和不需要的内容。 此规则将伪装从内部LAN(10.0.0.0/24)通过该框的所有流量,除了绑定到routed_nets集中任何网络的数据包,保留对这些网络的正常直接IP路由。 由于此配置完全基于网络地址,因此您不必担心适当的连接类型(VPN的类型,跳数等),也不必担心物理接口和拓扑。

这应该是这样的。 因为这是纯粹的第3层(网络层)实现,所以实现它所需的基础分类也应该是纯层3。

限制某些PC只能访问某些公共主机

让我们说老板担心某些员工在互联网上玩而不是工作,并要求你限制他们的PC访问他们需要能够工作的特定网站,但他不希望这样。影响所有PC(例如他)。

要限制三台PC(10.0.0.5,10.0.0.6和10.0.0.7)只能访问worksite1.com,worksite2.com和worksite3.com,请运行以下命令:

ipset -N limited_hosts iphash
ipset -A limited_hosts 10.0.0.5
ipset -A limited_hosts 10.0.0.6
ipset -A limited_hosts 10.0.0.7
ipset -N allowed_sites iphash
ipset -A allowed_sites worksite1.com
ipset -A allowed_sites worksite2.com
ipset -A allowed_sites worksite3.com
iptables -I FORWARD \
         -m set --set limited_hosts src \
         -m set ! --set allowed_sites dst \
         -j DROP

此示例与单个规则中的两个集匹配。 如果源匹配limited_hosts且目标与allowed_sites不匹配,则丢弃该数据包(因为limited_hosts仅允许与allowed_sites通信)。

请注意,因为此规则位于FORWARD链中,所以它不会影响与防火墙本身之间的通信,也不会影响内部流量(因为该流量甚至不会涉及防火墙)。

阻止除某些PC之外的所有主机的访问(反向场景)

假设老板想阻止访问局域网内所有主机上的一组站点,除了他的PC和他的助手的PC。 对于多样性,在这个例子中,让我们通过MAC地址而不是IP匹配boss和助手PC。 让我们说MAC是11:11:11:11:11:11和22:22:22:22:22:22,其他人阻止的网站是badsite1.com,badsite2.com和badsite3.com 。

代替使用第二个ipset来匹配MAC,让我们利用带有MARK目标的多个iptables命令来标记数据包,以便在同一链中的后续规则中进行处理:

ipset -N blocked_sites iphash
ipset -A blocked_sites badsite1.com
ipset -A blocked_sites badsite2.com
ipset -A blocked_sites badsite3.com
iptables -I FORWARD -m mark --mark 0x187 -j DROP
iptables -I FORWARD \
         -m mark --mark 0x187 \
         -m mac --mac-source 11:11:11:11:11:11 \
         -j MARK --set-mark 0x0
iptables -I FORWARD \
         -m mark --mark 0x187 \
         -m mac --mac-source 22:22:22:22:22:22 \
         -j MARK --set-mark 0x0
iptables -I FORWARD \
         -m set --set blocked_sites dst \
         -j MARK --set-mark 0x187

正如您所看到的,因为您没有使用ipset来执行上一个示例中的所有匹配工作,所以这些命令更复杂。 因为有多个iptables命令,所以必须认识到它们的顺序非常重要。

请注意,这些规则是使用-I选项(插入)而不是-A(追加)添加的。 插入规则后,它将添加到链的顶部,将所有现有规则向下推。 因为正在插入这些规则中的每一个,所以有效顺序是相反的,因为随着每个规则的添加,它将被插入到前一个规则之上。

上面的最后一个iptables命令实际上成为FORWARD链中的第一个规则。 此规则匹配目标与blocked_sites ipset匹配的所有数据包,然后使用0x187(任意选择的十六进制数)标记这些数据包。 接下来的两条规则仅匹配要排除的主机的数据包以及已标记为0x187的数据包。 然后这两个规则将这些数据包上的标记设置为0x0,“清除”0x187标记。

最后,最后一个iptables规则(由上面的第一个iptables命令表示)丢弃所有具有0x187标记的数据包。 这应该匹配在blocked_sites集中具有目的地的所有数据包,除了来自任一排除的MAC的数据包,因为这些数据包上的标记在达到DROP规则之前被清除。

这只是解决问题的一种方法。 除了使用第二个ipset之外,另一种方法是利用用户定义的链。

如果你想使用第二个ipset而不是mark技术,你将无法达到上述的确切结果,因为ipset没有machash集类型。 但是,有一个macipmap集类型,但这需要在IP和MAC上匹配,而不是像上面那样单独使用MAC。

注意事项:在大多数实际情况中,此解决方案实际上不适用于网站,因为许多可能成为blocked_sites集合的主机(如Facebook,MySpace等)可能有多个IP地址,这些IP可能经常变化。 iptables / ipset的一般限制是只有在解析为单个IP时才应指定主机名。

此外,主机名查找仅在命令运行时发生,因此如果IP地址更改,防火墙规则将不会知道更改,仍将引用旧IP。 因此,实现这些类型的Web访问策略的更好方法是使用HTTP代理解决方案,例如Squid。 该主题显然超出了本文的范围。

自动禁止尝试访问无效服务的主机

ipset还为iptables提供了“目标扩展”,它提供了一种基于任何iptables规则动态添加和删除集合条目的机制。 您无需使用ipset命令手动添加条目,而是可以让iptables随时为您添加条目。

例如,如果远程主机尝试连接到端口25,但您没有运行SMTP服务器,则可能没有任何好处。 要拒绝主持人有机会主动尝试其他任何操作,请使用以下规则:

ipset -N banned_hosts iphash
iptables -A INPUT \
         -p tcp --dport 25 \
         -j SET --add-set banned_hosts src
iptables -A INPUT \
         -m set --set banned_hosts src \
         -j DROP

如果数据包到达端口25,比如源地址为1.1.1.1,则会立即将其添加到banned_hosts,就像运行此命令一样:

ipset -A banned_hosts 1.1.1.1

由于DROP规则,从1.1.1.1开始的所有流量都被阻止。

请注意,这也将禁止尝试运行端口扫描的主机,除非他们知道要避免端口25。

清除运行配置

如果要清除ipset和iptables配置(设置,规则,条目)并重置为新的打开防火墙状态(在防火墙脚本的顶部有用),请运行以下命令:

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -t filter -F
iptables -t raw -F
iptables -t nat -F
iptables -t mangle -F
ipset -F
ipset -X

无法销毁“正在使用”的集合,这意味着由一个或多个iptables规则引用(使用ipset -X )。 因此,为了确保从任何状态完全“重置”,必须首先刷新iptables链(如上所示)。

生产实例

结合生产的SSH,配置如下:

ipset create whitelist-ssh hash:net hashsize 4096
ipset add whitelist-ssh 192.168.10.0/23

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m set --match-set whitelist-ssh src -p tcp --dport 22 -m comment --comment "Allow Access SSH" -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m comment --comment "Deny Access SSH" -j DROP

ipset list
iptables -t filter -vxnL

ipset save > /etc/ipset.up.rules
iptables-save > /etc/iptables/rules.v4

//往/etc/rc.local加入以下:
ipset restore < /etc/ipset.up.rules
iptables-restore < /etc/iptables/rules.v4

模拟fail2ban 功能

60秒内访问3次SSH,将源IP禁止60秒

ipset create badguys hash:net timeout 900
ipset add badguys 192.168.0.0/16 nomatch
ipset add badguys 172.16.0.0/16 nomatch

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m set --match-set badguys -j DROP


iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 3 --rttl --name SSH -j set --add-set badguys src

或者

ipset create badguys hash:net timeout 900

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m set --match-set badguys src -j DROP
iptables -A INPUT -p tcp --dport 22 -m hashlimit --hashlimit-above 5/min --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name SSH-bruteforce -j SET --add-set badguys src

模拟Port Knocking 功能

ipset create knock hash:ip timeout 10
ipset create knock2 hash:ip timeout 10
ipset create whosthere hash:ip timeout 300

iptables -A INPUT -m set --match-set whosthere src -j ACCEPT
iptables -A INPUT -p tcp --dport 1989 -j SET --add-set knock src
iptables -A INPUT -p tcp -m set --match-set knock src --dport 2016 -j SET --add-set knock2 src
iptables -A INPUT -p udp -m set --match-set knock2 src --dport 1864 -j SET --add-set whosthere src

依次按以下敲门

  • 1989/TCP
  • 2016/TCP
  • 1864/UDP

批量禁端口

ipset -N BAD-PORTS bitmap:port range 135-1512
ipset -A BAD-PORTS 135
ipset -A BAD-PORTS 137-139
ipset -A BAD-PORTS 144
ipset -A BAD-PORTS 445
ipset -A BAD-PORTS 1512

iptables -A FORWARD -p tcp -m set --match-set BAD-PORTS dst -j DROP
iptables -A FORWARD -p udp -m set --match-set BAD-PORTS dst -j DROP

或者 对TCP与UDP分别对应

ipset create bl-tcp-ports bitmap:port range 0-65535
ipset create bl-udp-ports bitmap:port range 0-65535
ipset add bl-tcp-ports 23
ipset add bl-tcp-ports 1433
ipset add bl-tcp-ports 2323
ipset add bl-tcp-ports 3306
ipset add bl-tcp-ports 3389
ipset add bl-tcp-ports 5060

定义开放服务端口

  • 简单版本
ipset create services bitmap:port range 0-65535
ipset add services 443

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A INPUT -p tcp -i ens192 -d 172.16.4.109 -m conntrack --ctstate NEW -m set --match-set services dst -j ACCEPT
  • IP + 端口结合
    iptables 实现如下:
-A INPUT -s 192.0.2.42 -d 0/0 -p tcp --dport 22 -j ACCEPT 
-A INPUT -s 192.0.2.42 -d 0/0 -p tcp --dport 25 -j ACCEPT
-A INPUT -s 198.51.100.54 -d 0/0 -p tcp --dport 22 -j ACCEPT
-A INPUT -s 198.51.100.54 -d 0/0 -p tcp --dport 25 -j ACCEPT

使用ipset 简化

-A INPUT -p tcp -m set --match-set ADMIN_ADDR src -m set --match-set RESTRICTED_PORTS dst -j ACCEPT

ipset create ADMIN_ADDR hash:ip
ipset create RESTRICTED_PORTS bitmap:port
ipset add ADMIN_ADDR 192.0.2.42,198.51.100.54
ipset add RESTRICTED_PORTS 22,25

ipset add ADMIN_ADDR $friend_ip
ipset del ADMIN_ADDR $friend_ip 

实现管理员IP白名单功能

ipset create trustedAdminsIP hash:ip
ipset add trustedAdminsIP 192.0.2.1
ipset add trustedAdminsIP 192.0.2.2
ipset list trustedAdminsIP

iptables -A INPUT -i lo -j ACCEPT

iptables -A INPUT -m state ---state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m set --match-set trustedAdminsIP src -p tcp -m tcp --dport 22 -j ACCEPT

ipset del trustedAdminsIP 192.0.2.2
ipset flush trustedAdminsIP
ipset destroy trustedAdminsIP 

或优雅的写法

ipset create whitelist -exist hash:net family inet
ipset add whitelist 119.147.144.176/29
ipset add whitelist 39.108.115.157

iptables -I  INPUT 2 -p tcp --dport 22 -m set --match-set whitelist src -j LOG --log-prefix "IP Whitelisted INPUT "
iptables -t filter -I INPUT 3 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m set --match-set whitelist src -m comment --comment "Allow Access SSH" -j ACCEPT

IP黑名单功能

ipset create blacklist hash:net
ipset add blacklist 185.93.185.237 -exist
ipset add blacklist 204.2.134.0/24 -exist
ipset add blacklist 208.100.26.228 -exist
iptables -I INPUT 1 -m set --match-set blacklist src -j LOG --log-prefix "IP Blacklisted INPUT"
iptables -I INPUT 2 -m set --match-set blacklist src -j DROP

使用systemd 管理

Unit]
Description=ipset persistent rule service
Before=firewalld.service
ConditionFileNotEmpty=/etc/sysconfig/ipset
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/ipset -exist -file /etc/sysconfig/ipset restore
ExecStop=/usr/sbin/ipset -file /etc/sysconfig/ipset save
[Install]
WantedBy=multi-user.target

引用