使用iptables结合ipset封锁国外的异常IP访问
最近遇到了网站不断被一些国外的IP扫描的问题,想了想,决定将所有非国内的客户端全部封锁,只允许国内的用户进行访问。
首先需要找到所有国内的IP段,这个比较简单,ipip.net
的github提供了一个china_ip_list项目,记录了目前所有国内的IP地址段,每月更新。
这个列表可以通过wget https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt
直接进行下载。
有了IP列表,接下来的事情相对简单不少,虽然理论上可以通过iptables针对文件里的每一个IP段添加规则,但是这样会添加几千条规则,不是最优解,所以就借助ipset和iptables进行封锁。
首先,使用ipset
创建一个集合,名字就叫whitelist-china
ipset create whitelist-china hash:net hashsize 10000 maxelem 1000000
然后,将文件中的所有IP段都加到这个集合里:
for i in $(cat china_ip_list.txt);do
ipset add whitelist-china $i;
done
最后,在通过iptables封锁所有不在这个集合中的IP,因为不想影响我访问国内的地址,所以在这里,只需要将TCP协议的SYN包,以及ICMP包丢弃掉就可以:
iptables -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m set ! --match-set whitelist-china src -j DROP
iptables -A INPUT -p icmp -m set ! --match-set whitelist-china src -j DROP
这么设置之后,出现了一些问题,我在本地无法通过127.0.0.1访问本机的MySQL服务了,为什么呢?因为连接本机,那么客户端的IP就是127.0.0.1,很显然这个IP也不在国内的地址段里,直接导致iptables错误的把本地的请求也丢弃了。于是还需要放行本地发起的请求:
iptables -A INPUT -s 127.0.0.1/8 -j ACCEPT
好了,经过这样的设置,世界清净了不少,如果想看看到底有多少的数据被iptables丢弃,只需要执行iptables -vnL
查看命中数量:
# iptables -vnL
Chain INPUT (policy ACCEPT 70K packets, 3507K bytes)
pkts bytes target prot opt in out source destination
70660 3505K DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x17/0x02 ! match-set whitelist-china src
40 1738 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0 ! match-set whitelist-china src