文章目录
防火墙的相关概念
四表五链
五链
四表
链表关系
规则
SUBCOMMAND
对链操作
对规则操作(后面必须加链的名称)
查看规则
匹配条件
通用匹配
扩展匹配
处理动作
保存规则
NAT实验
A主机配置
B主机配置
测试
防火墙的相关概念
- 按逻辑分类:
- 主机防火墙:针对单个主机进行防护,在主机上进行配置
- 网络防火墙:往往处于网络入口或边缘,针对网络入口进行防护,服务于防火墙背后的本地局域网
- 网络防火墙和主机防火墙并不冲突,可以理解为,网络防火墙主外(集体), 主机防火墙主内(个人)
- 按物理分类:
- 硬件防火墙:在硬件级别实现部分防火墙功能,性能高、成本高
- 软件防火墙:应用软件处理逻辑运行于通用硬件平台上的防火墙,性能低、成本低
iptables 不是真正的防火墙,可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的“安全框架“,这个”安全框架“才是真正的防火墙,叫做 netfilter
netfilter(包过滤)是Linux内核中的一个数据包处理模块,具有如下功能:
- 网络地址转换(NAT)
- 数据包内容修改
- 数据包过滤的防火墙功能
虽然我们使用 service iptables start
或 systemctl start iptablse
来启动iptables,但是iptables并没有守护进程,所以并不能算是一个真正意义上的服务,而应该算是内核提供的功能
四表五链
五链
我们知道Linux中为了安全分成了用户空间和内核空间两个部分,报文需要进入用户空间前会先经过内核空间,而要想达到”防火“的功能,就需要在内核空间中设置”关卡“,所有进出的报文都需要通过这些关卡,匹配规则后,符合放行条件的才能放行,符合阻拦条件的则需要被阻拦,于是就出现了 input
和 output
关卡,而这些关卡在iptables中被称为”链CHAIN”
事实上上述描述的场景并不完善,因为收到的报文访问的目标地址可能并不是主机,而是其他服务器,当本机的内核支持核心转发 IP_FORWARD
时(明明是台电脑却只能卑微的当个路由器),我们可以将报文转发给其他服务器,这时候就会出现其他的”关卡“,他们就是”路由决策前“、”转发“、”路由决策后“
所以根据上图,我们能想象出某些场景中报文的流向:
- 到本机某进程的报文:PREROUTING –> INPUT
- 由本机转发的报文:PREROUTING –> FORWARD –> POSTROUTING
- 由本机的某进程发出的报文:OUTPUT –> POSTROUTING
为什么这些”关卡“被称作”链“呢?iptables通过定义规则来实现不同的功能,而这些规则就写到了关卡中,防火墙的作用就在于对经过某个关卡的报文进行匹配”规则“,然后执行相应的”动作“;而每个关卡上可能不止有一条规则,而是有很多条规则,当我们将这些规则按一定的顺序串起来时,就形成了”链“,如下图所示。所以把”关卡“称为”链”会更加合适
四表
iptables通过定义规则来实现不同的功能,iptables中有四张表将这些功能分类,而要实现功能就要将规则(rules)写进这些表中,如放行(accept)、拒绝(reject)、丢弃(drop)等,而这四张表分别是:
- filter表:负责过滤功能(也就是防火);对应的内核模块为:iptables_filter
- nat表:提供地址转换功能;内核模块:iptables_nat
- mangle表:拆解修改报文并重新封装;内核模块:iptables_mangle
- raw表:关闭nat表上启用的连接追踪机制,提高性能;iptables_raw
链表关系
事实上,某些“链”中注定不会包含某类“规则”,就像某些“关卡”天生就不具备某些功能一样。比如A关卡是防空的,只能打击空中的敌人;B关卡是陆军,没有防空能力;C关卡比较牛逼,既可以防空又可以防陆;D关卡最屌,海陆空全防
从表的角度来看:
- filter表:用于写过滤规则,只要在INPUT、OUTPUT、FORWARD链写就能很好发覆盖,就没必要在路由决策前和路由决策后写了
- nat表:用于地址转换,源地址转换需要在路由决策后POSTROUTING修改,即SNAT;目的地址转换需要在路由决策前PREROUTING修改,即DNAT;某些进程可能自己也会做SNAT,需要在报文发出时OUTPUT修改;(CentOS 7在INPUT链上也可以设置nat表了,不过主要用的还是前两种)
- raw表和mangle表没用过
需要注意的是,当报文经过一条链时,会将当前链上所有的规则匹配一遍,但是匹配的时候总归要有顺序,应该一条条匹配,所以还有一个表优先级的问题(由高到低):
raw --> mangle --> nat --> filter
结合上述所有描述,我们可以将报文通过防火墙的流程总结为下图:
规则
规则:根据指定的匹配条件来尝试匹配每一个流经的报文,一旦匹配成功则由规则后面执行的处理动作进行处理
语法:iptables [-t TABLE] SUBCOMMAND CHAIN [!] CRITERIA -j TARGET
SUBCOMMAND
对链操作
-F [CHAIN]
:flush,清空某条链的所有规则-P [CHAIN]
:policy,定义链的默认动作-N CNAME
:new,添加自定义链-X CNAME
:删除自定义链,需要满足:自定义链没有被任何规则引用,即自定义链的引用计数为0;自定义链中没有任何规则,即自定义链为空-E CNAME NEWCNAME
:edit,修改自定义链的名字-Z [CHAIN]
:zero,清空链上的统计信息- 默认为对所有链做动作
对规则操作(后面必须加链的名称)
-A
:append,将规则追加到链最后-I
:insert,将规则插入到指定位置,需要给定序号-D
:delete,将链上的规则删除,需要给定序号-R
:replace,对链上的规则修改,需要给定序号
查看规则
-L [CHAIN]
:默认列出所有链上的规则
-n
:不做域名解析-v
:显示详细信息-vv
:更详细-vvv
:再详细–line-numbers
:显示规则序号
匹配条件
通用匹配
即不需要指明具体模块名就能使用的匹配条件
-s
:source,源IP-d
:destination,目的IP-p
:protocol,协议,有ip、tcp、udp、icmp等-i
:input interface,报文的流入接口-o
:output interface,报文的流出接口
扩展匹配
需要指明具体的模块名,条件作为模块的选项
隐式匹配:如果在通用匹配上使用了 -p
选项指明协议,则 -m
可有可无
- tcp:
–dport
:目的端口–sport
:源端口–tcp-flags LIST1 LIST2
- LIST1:要检查的标志位
- LIST2:LIST2必须在LIST1中出现,且必须为1的标志位,其余必须为0
–tcp-flags sys,ack,fin,rst syn
:相当于–syn
,也就是三次握手的第一次握手
–syn
:用来匹配tcp会话第一次握手iptables -A INPUT -p tcp -s 172.16.100.0/24 --dport 22 -j ACCEPT
:放行172.16.100.0/24网段的所有主机对22端口的访问(ssh)
- udp:
–sport
–dport
- icmp:
–icmp-type
:指定匹配icmp报文类型0
:echo reply8
:echo request
显示匹配:显示指定使用iptables的具体模块进行匹配
用法:-m 模块名 [模块选项]
multiport
:多端口扩展–sports PORT1[,PORT2…]
–dports PORT1[,PORT2…]
–ports PORT1[,PORT2,…]
iptables -A INPUT -d 10.1.1.1 -p tcp -m multiport --dports 22,80,443 -j ACCEPT
:放行10.1.1.1对22、80、443端口的访问
iprange
:多ip扩展–src-range IP[-IP2]
–dst-range IP[-IP2]
iptables -A INPUT -d 10.1.1.1 -p tcp --dport 22 -m iprange --src-range 192.168.1.1-192.168.1.100 -j ACCEPT
time
:指定匹配时段–datestart YYYY\[-MM]\[-DD][-hh[-:mm[:ss]]]
–datestop
–timestart
–timestop
–weekdays DAY1[,DAY2…]
–mouthdays
- 每天9点到19点不能访问:
iptables -A INPUT -p tcp --dport 80 -m time --timestart 9:00 --timestop 19:00 -j DROP
- 指定周一周二不能访问:
iptables -A INPUT -p tcp --dport 80 -m time --weekdays Mon,Tue -j DROP
connlimit
:限制同时并发连接数–connlimit-above N
–connlimit-mask N
:不可单独使用,与上一个选项配合使用,用于针对”某个IP段内的一定数量的IP“进行连接数量限制(IP段内所有IP共享限制)- 限制每个IP能打开5个连接:
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 6 -j REJECT
- 限制某网段内的主机只能打开10个连接:
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 10 --connlimit-mask 27 -j REJECT
limit
:限制发包速率–limit n/[minute|second|hour|day]
–limit-burst
:”令牌桶“算法,指定令牌桶中令牌的最大数量,相当于进程池
state
:基于连接追踪模板(nf_conntrack),用于记录各连接以及相关状态,基于ip实现,与tcp协议无关NEW
:新建立的连接,连接追踪模板无相应记录,客户端第一次发出的请求ESTABLISHED
:NEW之后进入模板中直到状态被删除之前的过程RELATED
:相关联的连接,如ftp的被动模式(20,21)INVALIED
:无法识别的状态
string
:匹配字符串–algo
:指定对应的匹配算法,可用的算法为bm、kmp等,此选项为必选选项–string
:指定需要匹配的字符串
处理动作
- ACCPET:允许数据包通过
- DROP:直接丢弃数据包,不给任何回应,这时候客户端超时才能察觉
- REJECT:拒绝数据包通过,并响应发送一个拒绝信息给发送方
- SNAT:源地址转换,解决内网用户用同一个公网地址上网问题
iptables -t nat -A POSTROUTING -s 内网网段 -j SNAT --to-source 需转换成的源地址
- MASQUERADE:SNAT的特殊形式,相当于动态SNAT
iptables -t nat -A POSTROUTING -s 内网网段 -o 出接口 -j MASQUERADE
- DNAT:目的地址转换,用于外网地址访问内网主机
iptables -t nat -A PREROUTING -d 100.1.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.1
- 自定义链:跳转到自定义链上,此时自定义链就”挂“在了某条链上,自定义链上的引用计数会+1
保存规则
iptables save
NAT实验
要求
- 在 A 上 ping 192.168.159.1通
- 在 C 上 ssh root@192.168.159.144
A主机配置
# 修改ip地址
ip addr add 172.16.10.1/24 dev ens33
# 修改默认路由
ip route add default via 172.16.10.2 dev ens33
# 重启网络
systemctl restart network
B主机配置
# 添加一个子接口
ifconfig eth0:0 172.16.10.2 netmask 255.255.255.0
# 关闭selinux
setenforce 0
# 清空filter表默认配置
iptables -F
# 为主机A配置SNAT
iptables -A POSTROUTING -t nat -s 172.16.10.0/24 -o eth0 -j MASQUERADE
# 为主机A配置DNAT
iptables -A PREROUTING -t nat -d 192.168.159.144 -p tcp --dport 2222 -j DNAT --to-destination 172.16.10.1:22
# 开启核心转发
echo 1 > /proc/sys/net/ipv4/ip_forward
测试
在 A 中 ping 192.168.159.1
[root@inside ~]# ping 192.168.159.1 PING 192.168.159.1 (192.168.159.1) 56(84) bytes of data. 64 bytes from 192.168.159.1: icmp_seq=1 ttl=127 time=0.714 ms 64 bytes from 192.168.159.1: icmp_seq=2 ttl=127 time=0.648 ms 64 bytes from 192.168.159.1: icmp_seq=3 ttl=127 time=0.525 ms 64 bytes from 192.168.159.1: icmp_seq=4 ttl=127 time=0.563 ms ^C --- 192.168.159.1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3002ms rtt min/avg/max/mdev = 0.525/0.612/0.714/0.077 ms
在 C 上 ssh root@192.168.159.144
C:\Users\Ti>ssh root@192.168.159.144 -p 2222 The authenticity of host '[192.168.159.144]:2222 ([192.168.159.144]:2222)' can't be established. ECDSA key fingerprint is SHA256:9T6E0aufwGnBm7L16GFC9+FFWimqK7uOeRwX4d0nCh4. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[192.168.159.144]:2222' (ECDSA) to the list of known hosts. root@192.168.159.144's password: Last login: Mon May 11 22:20:23 2020 from 172.16.10.2 [root@inside ~]# ip ad sh 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:73:3a:9e brd ff:ff:ff:ff:ff:ff inet 172.16.10.1/24 brd 172.16.10.255 scope global ens33 valid_lft forever preferred_lft forever inet6 fe80::8646:ee5f:9334:9c2f/64 scope link valid_lft forever preferred_lft forever [root@inside ~]#
参考文章,讲的非常具体并且有具体实验:iptables