iptables

介绍

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 了。