要进行流量的限制,当然是钥对服务器进行操作
以一台基础的centos7系统以例,切分成三份,分别是硬件,内核空间,用户空间
那麽如果有流量进来,就是先从网卡,让后进入linux内核,最后抵达网络应用
如果要进行流量过滤就是先让流量从网卡进来,然后在linux内核里进行过滤处理,没问题了在进入到网络应用,这样网络应用前面就有了一道防火墙
问题1:如果操作linux内核?
在linux内核中有一个叫netfilter的框架,一旦有流量从网卡进来到内核中就会触发netfilter机制从而进行流量过滤,但是直接操作netfilter是非常有难度的,但是在用户空间有一个iptables工具可以使用
iptables相当于netfilter的接口,iptables在前端,netfilter在后端,只需要在用户空间使用简单的iptables命令就可以执行netfilter的复杂流量过滤逻辑
iptables (四表五链)
filter | 过滤 |
---|---|
nat | 网络地址转换(可以进行负载均衡) |
mangle | |
raw | |
security |
常见的是前四个表:filter,nat,mangle,raw
常见中的常见是前面两个表:filter,nat
但是对于绝大多是使用iptables的命令的人其中最常使用的表是:filter
问题2:数据包是如何抵达网络应用程序的?
数据包从网络经过内核空间到用户空间,最简单的就是一进一出,但是要注意的一点linux系统是可以作为路由器存在的,也就是说有些数据包会经过这台linux主机,并且被转发到其他主机,这样就会多一条转发链路,在加上简单的一进一出的链路,就会发生很多事情,不过还好处于内核的netfilter已经在链路的各个部分做了“埋伏”
当我们的数据包一旦从外部抵达到系统时,就会由PREROUTING链负责
数据包的目标是本地主机的话,就由INPUT链负责
数据包如果从主机出去的话,就由OUTPUT链负责
数据包如果不是要到本机,只是经过本机路由,就由FORWARD链负责
数据包如果要离开本机,或者路由后,还有个POSTROUTING链负责
问题3:为什么要用链来表示每个部分?
我们可以把上面的图看成是一个整体链接在一起
问题3.1:这样的话我们过滤一个数据包需要全部链都过一遍吗?
不用,如果使用filter表,就只需要管理INPUT,OUTPUT和FORWARD链,而其他表管理的链也有所不同
对于filter表来说就是:
- 数据包的目标是本机(INPUT),可以进行过滤
- 数据包的转发(FORWARD),同样可以进行过滤
- 数据包的目标是其他地址(OUTPUT),也可以进行过滤
具体不同的链里面如果过滤,就需要往对于的链里面加入相应的规则就可以了
iptables———> 表———>链———>规则
#在iptables里面包含着不同的表,表里面包含着不同的链,链里面可以制定不同的规则=iptables命令的写法
实践
#注意:在工作中在修改防火墙规则之前,强烈建议您备份服务器的配置,并在测试过程中谨慎操作,以确保您的服务器仍然可以正常工作
通过iptables查看filter表内部的构造 #一般只需要管理三个链
iptables --table filter --list #注意:如果不使用--table +对应的表 就会默认filter
[root@nginx ~]# iptables --table filter --lis
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#初始状态下这三条链里面没有任何规则
[root@nginx ~]# hostname -I #查看主机ip
192.168.197.88
例子:我们使用其他的主机进行ping要实验的主机
发现可以ping通,那麽如何通过iptables进行过滤使其无法ping通?
根据上面的 iptables———> 表———>链———>规则来进行命令书写,实现过滤
###########在其他主机上或者想要拒绝源地址服务器发过来的数据包的节点上执行!!
iptables \
>--table filter \ #指定表
>--append INPUT \#指定链 根据我们数据包的传输规则来决定使用那条链路 INPUT,FORWARD,OUTPUT三条链中间应该选择INPUT 因为我们使用的是本地进行ping命令,要把数据包的目标地址为本地的给过滤掉
>--source 192.168.197.88 \ (源目标地址)#制定规则
>--jump REJECT #制定对接收到的数据包进行处理 :匹配到数据包后跳到它身上并且进行一个拒绝处理
iptables --table filter --append INPUT --source 192.168.197.88 --jump REJECT
查看:
[root@docker ~]# iptables --table filter --list
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT all -- nginx anywhere reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
此时就能看到规则被添加到了INPUT链里面了
注意: prot 表示protocol协议,因为没有设置具体是哪个协议,所以这个地址过来的数据包不管走那个协议都会给拒绝
这个时候就无法ping通了
源目标地址ping另一个已经将源目标地址屏蔽了的主机地址也已经ping不通了
无法ping通过是因为:ping发出去的数据包,还是需要返还回来的,需要有一个网络上来一个来回,从源到目的,从目的到源,返回的时候就会被刚才的规则给拒绝了
注意:这里有一个小插曲如果你的机器之前配置的由其他服务那麽的使用iptables就会有很多规则,就会发现执行完屏蔽命令后不起作用,执行下面的命令
iptables --list --line-numbers #查看防火墙规则 --line-numbers 可以显示行号
iptables --delete INPUT <rule_number>#指的是想删除或插入的规则的行号
iptables --insert INPUT <rule_number> --source 192.168.197.88 --jump REJECT
确保REJECT规则位于允许源地址的规则之前。如果需要重新排序规则,您可以使用以下命令删除规则并重新添加,使其生效!!!
注意:在有些时候会不希望自己的机器被别人使用ping命令进行发包,就可以直接禁用ICMP进行应答的操作
iptables --append INPUT --protocol icmp --icmp-type echo-request --jump DROP #使用此命令将阻止服务器对ping请求作出回应
根据上面iptables的屏蔽命令 设置的规则以外,同样还可以使用DROP来进行丢弃
将上面设置的规则进行删除,并重新配置
首先查看规则的序号:
iptables --list --line-numbers #也可以使用iptables --table filter --list
#--line-numbers 可以显示行号
进行删除:
[root@docker ~]# iptables --delete INPUT 1
让后重新创建规则:
[root@docker ~]# iptables --table filter --append INPUT --source 192.168.197.88 --jump DROP #DROP和REJECT所显示的是不一样的
需要注意的是这个时候同样是会出现上面相同的顺序问题,只需要将刚刚创建的规则进行删除,并再次创建即可
这是因为当有多个规则的时候iptables会从上往下进行执行,顺序为先1,后2,需要先删除前面的规则或者是删除刚刚本条规则,重新创建,自动的进行排序就可以了
删除iptables的时候需要注意:如果是根据序号来进行规则的连续删除的,需要注意!!!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YawmJ3rb-1692723685706)(image/
[root@docker ~]# iptables --delete INPUT 8 #iptables --table filter --delete INPUT
[root@docker ~]# iptables --insert INPUT --source 192.168.197.88 --jump DROP #就可以了
知道了过滤ip地址的核心操作,如何找到某个国家的ip地址集合?
https://www.ipdeny.com
推荐使用wget,也可以使用curl -O 参数来进行下载文件
curl -O https://www.ipdeny.com/ipblocks/data/aggregated/in-aggregated.zone
完成后,面临的第一个问题,如果将文件中这莫多的ip段进行过滤,即使我们写shell脚本的方式来进行逐个添加,也会消耗大量的cpu
根据以上引出 ipset
ipset能够更加优雅的进行处理,将多个ip段进行单独的汇聚在一个集合中,并生成一个唯一的哈希值,当我们为iptables添加ip地址的时候,只需要使用这个哈希值来代表背后的ip地址集合即可,以这样的方式可以减少消耗大量的cpu
实践
首先在需要过滤的主机上面使用ipset命令创建一个集合
[root@nginx opt]# ipset create zmx hash:net #集合名为zmx 因为我们要进行处理过滤的是网络号,不是主机号,所以hash后面需要用net来进行指明
查看ipset创建的集合
[root@nginx opt]# ipset list zmx
Name: zmx
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 376
References: 0
Number of entries: 0
Members:
目前虽然我们成功创建了ipset集合但是并未向集合中添加任何ip地址段,如果有加入的话就会在上面查看的时候在Members进行显示
在执行脚本之前先ping一个印度的域名进行测试
ping -c3 auth-dns-01.skyberbroadband.co.in
cat iptables-ipset.sh
#!/bin/bash
read -p "请输入需要创建的ipset集合:" -t 30 jihe
#首先使用ipset创建一个集合 这里因为集合可能已经被创建了所以我们为其加上--exist判断
ipset create $jihe hash:net --exist #如果集合确实存在,ipset就会忽略请求,就不会出现报错了
ipset flush $jihe #让后把这个集合本来就存在的ip地址进行清除,因为地址可能会出现更新,需要先进行清除,在加入
#让后使用wget下载需要的ip地址段文件
[ -f "jp-aggregated.zone" ] && rm in-aggregated.zone
curl -O https://www.ipdeny.com/ipblocks/data/aggregated/in-aggregated.zone #--no-check-certificate #问题1:如果重复执行此脚本的话就会重复下载同名文件所以需要进行判断
#问题2:因为网络原因可能会导致文件下载不成功需要进行判断
if [ $? -eq 0 ];then
echo "ok" #如果成功下载之后就可以直接通过for循环直接将文件中的ip段进行一个添加操作
#for address in `cat jp-aggregated.zone`;do
# ipset add $jihe $address
#done
else
echo "no"
for address in `cat in-aggregated.zone`;do #因为网络缘故下载容易出现错误导致判断会经常性的失误所以进行了修改
ipset add ${jihe} ${address}
done
fi
#目前已经创建ipset集合并加入了地址段
iptables --table filter --append INPUT --match set --match-set $jihe src --jump DROP
#--table 指定表
#--append INPUT 为input链添加规则
#--match 指定扩展模块 才可以调用到ipset集合中 --match set --metch-set zmx src 当源地址属于zmx集合中的地址时就匹配成功
#--jump 进行丢弃
如果不成功就查看iptable规则是否影响规则的执行
至此ok
但是如果我们重启机器之后我们设置的iptables和ipset就会被清空
解决方法:使用ipset save提前把ip集合先保存在一个文件里面
ipset save > /opt/ipset-guize #注意>方向 往右是保存 往左是导入
iptables-save > /opt/iptables-guize
关机开机之后再进行导入即可 #注意顺序要先导入ipset的配置再导入iptables的配置
[root@nginx ~]# ipset restore < /opt/ipset-guize
[root@nginx ~]# iptables-restore < /opt/iptables-guize
#如果不想再iptables导入配置的时候将原来的配置进行覆盖的话,就将iptables-restore后面加上--noflush或者-n就可以了
#注意顺序要先导入ipset的配置再导入iptables的配置
[root@nginx ~]# ipset restore < /opt/ipset-guize
[root@nginx ~]# iptables-restore < /opt/iptables-guize
#如果不想再iptables导入配置的时候将原来的配置进行覆盖的话,就将iptables-restore后面加上--noflush或者-n就可以了
完成