介绍
linux 环境下,使用 iptables 可以执行 netfilter 的复杂流量过滤逻辑。 包含 filter, nat, managle, raw, security 五个表,分别对应不同的网络层,传输层,应用层,网络层,安全层。一般使用 filter, nat 两个表最多。
理解流量路径中的链
网卡 -> netfilter -> 应用
网卡 -> prerouting链 -> -> -> input链 -> 应用
数据包抵达系统时 | 数据包目标是本机时
|forward链
|数据包目标不是本机只是经过本机时
网卡 <- postrouting链 <-v <- <- output链 应用
数据包离开系统时 数据包从本机出去时
filter 表管理 input,forward,output 三个链 至此,只要在对应的链里添加规则,即可管理有关本机的所有流量。
理解链中添加规则
iptables --table filter --list # 列出 filter 表中所有链
iptables --list # 列出 filter 表(默认filter表)中所有链
iptables --table filter --list-rules # 列出 filter 表中所有链的规则
iptables --table filter --append INPUT --source 192.168.3.20 --jump REJECT # 添加规则,从192.168.3.20来的数据包,跳转到 REJECT 链,即拒绝
# 两次执行会添加两条规则,比如将 REJECT 改为 DROP,将会多一条 DROP 规则,最终会从上往下执行
# 所以,如果想要删除第一条规则,避免后面添加的规则不受影响,可以先查看规则的行数
iptables --table filter --list --line-numbers
# 然后执行删除命令,删除第一条规则
iptables --table filter --delete INPUT 1
查看规则
iptables --table filter --list --line-numbers
target prot opt source destination
ACCEPT tcp -- anywhere 172.17.0.3 tcp dpt:cslistener
# prot 表示协议,常见值有: tcp, udp, icmp, all
# target 表示动作,常见值有: ACCEPT, DROP, REJECT, LOG, MARK, SNAT, DNAT, RETURN, JUMP
# opt 表示选项,常见值有: dpt, sport, dport, sport, saddr, daddr,
IP段的获取和处理
查看 ipdeny.com 的 ip 段,通过 Country IP blocks 获取要屏蔽的国家地址段。 以印度为例,ipdeny.com 的 ip 段如下: 使用 aggregated 可以用更少的 IP 段,更高效的屏蔽工作。 下载了 aggregated 文件后,会发现,即使是使用 shell 来全部添加到 iptables 规则里,也会消耗不少CPU。 ipset 可以让我们更优雅的处理这个问题。
ipset
可以把众多IP地址段汇集到一个集合中,然后通过集合,集合可以生成唯一的哈希值,来添加到 iptables 规则里。 当为 iptables 添加 IP 地址时,只需要用这个哈希值来代表背后的IP地址段集合。会自动将 IP 地址添加到集合中。
创建集合
ipset create indiaip hash:net # 因为我们要处理的是网络地址而不是主机名,所以使用 hash:net
ipset list indiaip # 查看集合,加入好的IP会在 Members 字段显示出来
编写脚本
#!/bin/bash
# cat block-india.sh
ipset create indiaip hash:net -exist # 如果存在就忽略,避免报错
ipset flush indiaip # 清空集合,避免重复添加
[ -f "in-aggregated.zone" ] && rm -f in-aggregated.zone # 删除旧的文件,保证下载的是最新文件
wget https://www.ipdeny.com/ipblocks/data/aggregated/in-aggregated.zone
if [ $? -eq 0 ]; then
then
echo "Download success"
for ip in `cat in-aggregated.zone`; do
ipset add indiaip $ip -exist
done
else
echo "Download failed"
fi
# 添加规则
# 当访问来自印度的IP时,丢弃请求数据包
iptables \
--table filter \
--append INPUT \
--match set --match-set indiaip src \
--jump DROP
chmod +x block-india.sh
ping -c3auth-dns-01.skyberbrroadband.co.in. # ping 一个印度域名测试
./block-india.sh # 运行脚本
ipset list indiaip | less # 查看集合,加入好的IP会在 Members 字段显示出来
ipset list indiaip | grep 103.130.110 # 检查 ping 测试的 IP 是否在集合里
iptables --table filter --list --line-numbers # 检查规则,如果有多于的规则,应及时删除
ping -c3auth-dns-01.skyberbrroadband.co.in. # 再次 ping 一个印度域名测试,ping 会 loss 100%
持久化
重启服务后,像刚刚的设置方式 添加的 iptables 规则都会丢失,所以需要持久化。
ipset save > /etc/rules.ipset # 将集合保存到文件
iptables-save > /etc/rules.iptables # 将 iptables 规则保存到文件
iptables -L # 查看 iptables 规则
ipset list # 查看集合
ipset restore < /etc/rules.ipset # 恢复集合
iptables-restore < /etc/rules.iptables # 恢复 iptables 规则
# 如果不想把原来的内容覆盖掉,可以在 iptables-restore 前加上 --noflush 或者 -n 参数
# 同理 ipset restore 也可以加上 -exist 参数
net服务
# 域名
dns 解析的默认端口号是 53,所以可以做一条 iptables 规则去拦截 53 端口的请求
做一下 dns 的解析,然后能拿到一个 ip list,之后只要将 list 中所有的 ip 都传给 iptables 就 ok 了。