Linux服务器禁止国外IP访问
使用iptables+ipset实现
IPSET介绍
ipset 是一个用于在 Linux 系统中管理 IP 地址集合的工具,可以用于高效地创建、管理和检查 IP 集合。
基本命令结构
ipset [options] command [arguments]
Commands:
options | arguments | 描述 |
---|---|---|
create | SETNAME TYPENAME [type-specific-options] | Create a new set |
add | SETNAME ENTRY | Add entry to the named set |
del | SETNAME ENTRY | Delete entry from the named set |
test | SETNAME ENTRY | Test entry in the named set |
destroy | [SETNAME] | Destroy a named set or all sets |
list | [SETNAME] | List the entries of a named set or all sets |
save | [SETNAME] | Save the named set or all sets to stdout |
restore | Restore a saved state | |
flush | [SETNAME] | Flush a named set or all sets |
rename | FROM-SETNAME TO-SETNAME | Rename two sets |
swap | FROM-SETNAME TO-SETNAME | Swap the contect of two existing sets |
help | [TYPENAME] | Print help, and settype specific help |
version | Print version information | |
quit | Quit interactive mode | |
常用命令和参数
创建集合
ipset create setname typename options
- setname: 集合的名称。
- typename: 集合的类型,例如 hash:ip、hash:net、hash:ip,port 等。
- [options]: 其他可选参数,例如 family、hashsize、maxelem。
- 示例: 创建一个名为 myset 的集合;类型为 hash:net;地址族为 inet (IPv4);初始哈希表大小为 1024;最大元素数量为 65536。
ipset create myset hash:net family inet hashsize 1024 maxelem 65536
添加元素
ipset add setname element
- setname: 集合的名称。
- element: 要添加的元素,例如 IP 地址或子网。
- 示例:
ipset add myset 192.168.1.0/24
删除元素
ipset del setname element
- setname: 集合的名称。
- element: 要添加的元素,例如 IP 地址或子网。
- 示例:
ipset del myset 192.168.1.0/24
销毁集合
ipset destroy setname
setname: 集合的名称。
示例: 销毁名为 myset 的集合。
ipset destroy myset
保存集合
ipset save [setname]
setname: 可选,集合的名称。如果不指定,将保存所有集合。
示例:
ipset save > /etc/ipset.rules
恢复集合
- 示例: 从保存的文件恢复集合
ipset restore < /etc/ipset.rules
列出集合
ipset list [setname]
setname: 可选,集合的名称。如果不指定,将列出所有集合所有元素。
示例: 列出名为 myset 的集合中的所有元素
ipset list myset
常用参数:
参数名 | 描述 |
---|---|
family | 指定地址族,inet 表示 IPv4,inet6 表示 IPv6。 |
hashsize | 指定哈希表的初始大小。 |
maxelem | 指定集合中允许的最大元素数量。 |
timeout | 为集合中的元素指定超时时间(以秒为单位)。 |
counters | 启用计数器,用于统计匹配次数。 |
comment | 启用注释功能,为元素添加注释。 |
skbinfo | 保存匹配的报文的元数据信息(例如接口索引、队列号)。 |
持久化ipset数据
systemd 方式实现规则数据持久化,避免重启后ipset数据丢失
- 新增持久化保存集合脚本:/usr/local/bin/ipset-save.sh
#!/bin/bash
ipset save > /etc/ipset.rules
- 新增恢复集合脚本:/usr/local/bin/ipset-restore.sh
#!/bin/bash
ipset restore < /etc/ipset.rules
- 新增systemd 服务单元文件: /etc/systemd/system/ipset.service
[Unit]
Description=Restore ipset rules
Before=network-pre.target
Wants=network-pre.target
Requires=local-fs.target
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ipset-restore.sh
ExecReload=/usr/local/bin/ipset-restore.sh
ExecStop=/usr/local/bin/ipset-save.sh
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
保存并退出编辑器。然后,重新加载 systemd 配置并启动服务(修改systemd文件需重新执行下面命令):
sudo systemctl daemon-reload
sudo systemctl enable ipset.service
sudo systemctl start ipset.service
验证服务状态
sudo systemctl status ipset.service
重启(reboot)并验证:
sudo ipset list
iptables介绍:
iptables 是一个用于配置 Linux 内核中内置的 IP 包过滤规则的工具。
它是 Linux 系统中强大的防火墙工具,用于控制网络流量的传输。
iptables 提供了用户空间命令行接口,用于与内核空间中的 netfilter 子系统交互。
基本概念
表(Tables): iptables 规则被组织到不同的表中,每个表用于不同类型的操作。常见的表有:
filter 表:这是默认表,包含用于过滤数据包的规则。它包含 INPUT、FORWARD 和 OUTPUT 链。
nat 表:用于网络地址转换(Network Address Translation),包含 PREROUTING、POSTROUTING 和 OUTPUT 链。
mangle 表:用于修改数据包的头部,包含 PREROUTING、POSTROUTING、INPUT、FORWARD 和 OUTPUT 链。
raw 表:用于配置不进行连接跟踪的规则,包含 PREROUTING 和 OUTPUT 链。
------------------------------------------------------------------------------------------------------
链(Chains): 每个表包含若干链,链是有序的规则列表。常见的链有:
INPUT:处理进入本地系统的数据包。
FORWARD:处理转发的数据包。
OUTPUT:处理从本地系统发出的数据包。
PREROUTING:在数据包路由决策之前处理数据包。
POSTROUTING:在数据包路由决策之后处理数据包。
------------------------------------------------------------------------------------------------------
规则(Rules): 每个链包含若干规则,规则定义了匹配条件和相应的动作(目标)。当数据包匹配规则时,执行相应的动作。
------------------------------------------------------------------------------------------------------
目标(Targets): 目标定义了当规则匹配时应采取的动作。常见的目标有:
ACCEPT:接受数据包。
DROP:丢弃数据包。
REJECT:拒绝数据包并发送错误响应。
LOG:记录数据包信息到系统日志。
# 查询当前的 iptables 规则
iptables -L -n -v
# 允许 TCP 流量到端口 80(HTTP)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 拒绝所有 ICMP 数据包(例如 ping 请求)
iptables -A INPUT -p icmp -j DROP
# 允许从特定 IP 地址的 SSH 连接(例如允许来自 192.168.1.100 的 SSH 连接)
iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -s 134.160.154.41 -p tcp --dport 6001 -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 6001 -j ACCEPT
# 默认拒绝所有其他输入流量(通常放在规则列表的最后):
iptables -P INPUT DROP
#----------------------------------------------------------------------------------------------------------
# 使用-A(追加)和-I(插入):
# -A(追加)命令将规则添加到链的末尾。
# -I(插入)命令允许你将规则插入到链的指定位置,但位置是基于规则编号的,而不是基于你定义的某种顺序。默认情况下,如果你不提供编号,-I会将规则插入到链的开头。
# 例如,要将规则插入到INPUT链的第二条位置,你可以这样做:
iptables -I INPUT 2 -s 192.168.1.100 -p tcp --dport 22 -j ACCEPT
iptables -I INPUT 13 -s 134.160.154.41 -p tcp --dport 6001 -m state --state NEW -j ACCEPT
# 按行号删除规则:
# 如果你知道要删除的规则的行号(使用 iptables -L -n --line-numbers 可以查看带行号的规则列表),你可以使用 -D 选项和行号来删除它。例如,要删除行号为 3 的规则,你可以执行:
iptables -D INPUT 3
# 按匹配条件删除规则:
# 例如,要删除所有允许来自 IP 地址 192.168.1.100 的流量的 INPUT 链规则,你可以执行:
iptables -D INPUT -s 192.168.1.100 -j ACCEPT
持久化iptables规则数据
systemd 方式实现规则数据持久化,避免重启后iptables规则数据丢失
- 新增持久化保存规则脚本:/usr/local/bin/iptables-save-rules.sh
#!/bin/bash
iptables-save > /etc/iptables/rules.v4
- 新增恢复规则脚本:/usr/local/bin/iptables-restore-rules.sh
#!/bin/bash
iptables-restore < /etc/iptables/rules.v4
- 新增systemd服务单元规则持久化文件: /etc/systemd/system/iptables-save.service
[Unit]
Description=Save iptables rules
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/iptables-save-rules.sh
RemainAfterExit=true
[Install]
WantedBy=halt.target reboot.target shutdown.target
保存并退出编辑器。然后,重新加载 systemd 配置并启动服务(修改systemd文件需重新执行下面命令):
sudo systemctl daemon-reload
sudo systemctl enable iptables-save.service
sudo systemctl start iptables-save.service
- 新增systemd服务单元规则恢复文件: /etc/systemd/system/iptables-restore.service
[Unit]
Description=Restore iptables rules
Before=network-pre.target
Wants=network-pre.target
Requires=local-fs.target
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/iptables-restore-rules.sh
ExecReload=/usr/local/bin/iptables-restore-rules.sh
#ExecStop=/usr/local/bin/iptables-save-rules.sh
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
保存并退出编辑器。然后,重新加载 systemd 配置并启动服务(修改systemd文件需重新执行下面命令):
sudo systemctl daemon-reload
sudo systemctl enable iptables-restore.service
sudo systemctl start iptables-restore.service
验证服务状态
sudo systemctl status iptables-save.service
sudo systemctl status iptables-restore.service
重启(reboot)并验证:
sudo iptables -L
iptables使用ipset:
特别须知: 使用集合控制时注意规则是否会阻止回环地址(127),ssh等管理,避免被拦截后无法正常远程管理
- 添加匹配在ipset集合中的允许规则:
sudo iptables -I INPUT 3 -m set --match-set cnip src -j ACCEPT
- 添加匹配不在ipset集合中的阻止规则:
sudo iptables -I INPUT 3 -m set ! --match-set cnip src -j DROP
获取中国IP子网分配
# 下载 APNIC 最新 IP 地址分配数据
curl https://ftp.apnic.net/stats/apnic/delegated-apnic-latest -O delegated-apnic-latest
# 提取所有中国的 IPv4 地址块并添加到 ipset 集合
grep '|CN|ipv4|' delegated-apnic-latest | while IFS='|' read -r registry cc type start_ip count date status
do
ip_prefix="$start_ip/$(awk -v n=$count 'BEGIN {print 32-log(n)/log(2)}')"
sudo echo $ip_prefix >> ./cnip_list
done
APNIC数据说明:
例: apnic|CN|ipv4|222.240.0.0|524288|20040326|allocated
注册机构(apnic):
表示该记录来自哪个互联网号码分配机构。apnic 代表亚太网络信息中心(Asia-Pacific Network Information Centre)。
国家代码(CN):
表示该 IP 地址块的分配国家。CN 代表中国。
地址类型(ipv4):
表示地址类型,这里是 ipv4。对于 IPv6 地址,值为 ipv6。
起始地址(222.240.0.0):
表示 IP 地址块的起始地址。
地址数(524288):
表示该记录中包含的地址数量。例如,524288 表示这个块包含 524,288 个连续的 IP 地址。
分配日期(20040326):
表示该地址块的分配日期,格式为 YYYYMMDD。这里是 2004 年 3 月 26 日。
状态(allocated):
表示该地址块的当前状态。allocated 表示地址块已经分配出去。其他可能的状态包括 assigned(分配给最终用户)和 available(可用的)。
解析地址块
对于起始 IP 地址 222.240.0.0 和地址数量 524288,我们需要计算子网掩码和地址块范围。524288 个地址相当于 2^19,所以掩码将是 /13(因为 32 - 19 = 13)。
地址块范围
起始地址:222.240.0.0
结束地址:222.247.255.255
- 创建ipset集合cnip:
create cnip hash:net family inet hashsize 16384 maxelem 1000000
- 创建添加数据到cnip集合脚本(赋予执行权限并执行):
#!/bin/bash
ipset create cnip hash:net family inet hashsize 16384 maxelem 1000000
for i in `cat cnip_list`
do ipset add cnip $i
done
建议把局域网IP端默认都加到cnip集合中,避免无法远程控制
ipset add cnip 10.0.0.0/8
ipset add cnip 192.0.0.0/8
ipset add cnip 172.0.0.0/8
- 查看cnip集合数据:
ipset list cnip
- 添加iptables规则(前置特定规则避免集合规则导致无法远程管理):
# 防火墙: 运行回环地址规则
sudo iptables -I INPUT 1 -s 127.0.0.1/32 -j ACCEPT
# 防火墙: 允许本地局域网访问规则
sudo iptables -I INPUT 2 -s 10.0.1.0/24 -j ACCEPT
# 防火墙: 允许特定ip访问规则
sudo iptables -I INPUT 3 -s 222.246.123.123 -j ACCEPT
# 防火墙: cnip 集合规则(阻止源IP不在cnip集合规则中的访问)
sudo iptables -I INPUT 4 -m set ! --match-set cnip src -j DROP