防火墙: 玩转linux iptables
linux的使用者中有很多人还无法纯熟的玩转iptables。网络不通,常会怀疑防火墙,但不能精确的诊断并给出依据。本文总结下iptables,整理下自己的思路。
讲个经历: 一次网络延迟问题诊断时,进行了很久也无法找到根源,临组同事说把iptables服务关闭了(在之前的公司曾经遇到过类似问题)。当时就凌乱了,iptables规则排查过,为设置任何规则,默认ACCEPT。重要的是iptables服务关闭是什么意思(我用的是ubuntu)?,我就说iptables不是服务,没法关闭啊,除非把内核模块卸载了,但是卸载了怕出现其他问题(线上环境),然后又把iptables只是个命令,netfilter框架是什么给讲了一遍,同事说, 这个具体的不懂,但是centos上是可以关闭的,问题解决后,我装了一台centos机器,还真有
service iptables stop
命令,实际上就是卸载相关的模块。原来只是大家的理解角度不同而已。同时防火墙,iptables,netfilter,firewalled几个特别容易混。
看下常用的一张图,来说明下iptables的构成。
- iptables其实是个client,供用户去管理防火墙。相关的请求最后会发送相关内核模块,如ip_tables。
- ip_tables内核模块主要用于组织iptables使用的表,链,规则。
- netfilter是一套技术框架,ip_tables依托于netfilter来注册各种hooks实现对数据包的具体控制。一些厂商的防火墙,入侵检测,入侵防御系统什么的基本依托于Netfilter来实现(从事过相关开发)。
看了上面的图,也就明白了为什么有人叫Linux的防火墙为"iptables",有的叫"netfilter/iptebles",有的干脆叫"netfilter"了。角度不同而已。
Linux防火墙的核心原理
想玩转很复杂的命令,用得多了自然就记住了,但只能说是能玩,还不能说是玩转。能玩转,必然是对后面的原理理解得非常透彻。 比如说:
1。 ps,top,lsof
这些命令,如果不理解进程的构成(资源),不理解进程调度,想深刻的理解命令输出的含义,灵活的运用命令是很难的。使用strace
可能就更费力了。
2。 同样tcpdump,ip,ethtool,ss
命令,在对TCP/IP相关协议不清楚的情况下,不清楚各个协议字段的情况下想玩转也很困难,只能常常叹参数复杂。
那么,一起来学习下防火墙背后的原理吧。
核心: Netfilter转发框架
Netfilter的Hook点
Netifilter框架其实非常简单,在数据包处理的不同阶段提供了5大HOOK点,可以在这5个地方注册自己的功能函数,从而对数据包进行控制。
数据包从左边进入IP协议栈,进行IP校验以后,数据包被第一个钩子函数PRE_ROUTING处理,然后就进入路由模块,由其决定该数据包是转发出去还是送给本机。若该数据包是送给本机的,则要经过钩子函数LOCAL_IN处理后传递给本机的上层协议;若该数据包应该被转发,则它将被钩子函数FORWARD处理,然后还要经钩子函数POST_ROUTING处理后才能传输到网络。本机进程产生的数据包要先经过钩子函数LOCAL_OUT处理后,再进行路由选择处理,然后经过钩子函数POST_ROUTING处理后再发送到网络。
Netfilter 接口: iptables
框架有了,我们总的在各个hook点添加功能吧,怎么操作那?iptables就是提供用用户进行灵活操作的接口工具。比如我们通过iptables进行一些规则的控制等操作。而规则是以表->链->规则的逻辑来对流量的逻辑控制。
iptables根据功能定义了4个表,raw,mangle,filter,nat。这个四个表中有各自包含不同的链,如PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING,这些链与Netfilter的HOOK点相对应,链中包含具体的规则从而控制数据包了。 重复一下,之所以区分出来4个不同的表,就是为了进行功能划分,不同的表对用不同的功能。
图中上部分为表与链的对应。下部分则是iptables与netfilter的结合,仔细看图可以梳理出数据包的整个匹配过程。
Filter表
filter表用于实现对转发包的控制。表中的三个链INPUT,FORWARD,OUTPUT分别处理对应类型的数据包。通过在对应的链上设置规则最终对数据包进行控制。通俗的讲,INPUT用户保护本机,OUTPUT用户限制本机应用程序的网络访问,FORWARD链一般用于保护后端的服务器。
- INPUT 进入本机进程的数据包
- FORWARD 主机扮演的是路由的角色,经由本机的数据包
- OUTPUT 本机进程生成数据包
NAT表
NAT(Network Address Traslation),网络地址转换。包含了PREROUTING,OUTPUT,POSTROUTING链。
- PREROUTING 在路由之前先修改目的ip,实现DNAT
- OUTPUT 用于解决本机发送的数据包实现DNAT功能。因为本机发送的数据包会经由OUTPUT,POSTROUTING, POSTROUTING只能做SNAT,所以设计了OUTPUT来处理本机发送数据的DNAT,因为如果本机发出的数据包无法经过PREROUTING,没法做DNAT)。
- POSTROUTING 数据包离开时经由POSTROUTING,用户修改源地址,实现SNAT。
Mangle表
用来修改数据包。没怎么用过。一般用于QOS。
Raw表
用来进行连接跟踪设置。可以用于加速规则匹配。
表 | 链 | 场景 |
---|---|---|
filter | INPUT, FORWARD, OUTPUT | 防火墙规则最常用的表,控制转发 |
nat | PREROUTING, OUTPUT, POSTROUTING | SNAT,DNAT |
raw | PREROUTING,OUTPUT | 提高性能,跳过ip_contrack |
mangle | ALL | 用于修改数据包的一些标识位置,实现qos,策略路由等 |
防火墙相关命令的使用
iptables
如果非必要,真没有人愿意去详细的学习iptables语法,写起来太麻烦。但熟悉熟悉,理解了原理,掌握起来也很容易。任何命令的参数其实都有其自己的体系,遵循着背后的原理。
iptables使用的语法: iptables [-t table] 操作 chain RULE
,下面是一个简化图。
- 如果想查看特别的表时使用
-t
指定,如果查看单独的链需要在操作后面指定。 - 如果是查看规则定义,使用
-S
。-S
比-L
查看规则时更加清晰。 - 如果查看匹配状况使用
-nvL
。配合watch使用。 --line-number
用于查看规则号。
-nvL配置grep和watch查看特定规则的配置非常有用!
iptables-save
这个命令主要是把内存态的规则保存到文件,然后下次启动的时候用iptables-restore
来载入规则。 但是这个命令常常用来查看防火墙规则。比iptables
用得都多, 主要是输出结果的格式比较紧凑直观。而且能方便的能看到所有表的规则。
┌─[ubuntu@fishcried] - [~] - [2015-07-17 05:47:22]
└─[0] sudo iptables-save
# Generated by iptables-save v1.4.21 on Fri Jul 17 17:46:45 2015
*mangle
:PREROUTING ACCEPT [170491:25205613]
:INPUT ACCEPT [170491:25205613]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [186436:72064133]
:POSTROUTING ACCEPT [186436:72064133]
COMMIT
# Completed on Fri Jul 17 17:46:45 2015
# Generated by iptables-save v1.4.21 on Fri Jul 17 17:46:45 2015
*nat
:PREROUTING ACCEPT [726722:43601168]
:INPUT ACCEPT [726722:43601168]
:OUTPUT ACCEPT [17016:1033385]
:POSTROUTING ACCEPT [17016:1033385]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE
COMMIT
# Completed on Fri Jul 17 17:46:45 2015
# Generated by iptables-save v1.4.21 on Fri Jul 17 17:46:45 2015
*filter
:INPUT ACCEPT [5130295:773100722]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5052679:681817970]
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
COMMIT
# Completed on Fri Jul 17 17:46:45 2015
- 输出是分段的,每个段落一个表,*开头后面跟着表名
- :开头的行是对链匹配次数的总结,后面跟着统计信息,[数据包:字节数]。
- 后面跟着的是具体规则
- 最后跟着
COMMIT
表示一个表的结束
iptables-save
有两个选项:
- -t 后面可以指定表明
- -c 输出会在每条规则前加上匹配信息
技巧: 如何快速查看iptables的流量匹配?
1. iptables [-t 表] -L [链] -nv
2. iptables-save -c
3. 开启日志 -A INPUT -j LOG --log-prefix "curious_log " --log-level 6 //输出日志在/var/log/messages
TODO: 遇到真实案例时,记录下过程并提供素材,添加一个案例。
如果想快速的查看规则匹配情况,可以使用上面两条命令。第一条命令较为灵活,可以控制表和链,而且统计信息比较人性化。第二条命令简单。 配合watch能够动态观察。
iptables自定义连
如果想自行定义规则链,可以通过-N
参数,然后通过-j/--jump
跳转过来就可以了。
iptables -N 链名
iptables 。。。 -j 链名
很多系统都是通过添加自己的链来实现功能,比如openstack的安全组还有kubernetes/openshift。
iptables规则调优策略
优化的核心原则就是减少规则匹配。
- 简化规则
- 用
multiport
,iprange
模块,简化规则数量,也减少了匹配次数。
- 用
- 调整匹配顺序
- 书写规则顺序的原则,通用匹配放在前面。 配合
iptable -t tname -Lnv
的观察数据 - 提前规则的在表的位置。例如将filter表中针对dnat后匹配的规则放到raw中匹配,需要使用没有做dnat的ip。这样减少了很多次匹配。
- 分层优化,减少匹配顺序。通过自定义的链,来跳转规则。这样就能减少匹配次数了
- 书写规则顺序的原则,通用匹配放在前面。 配合
NEW,ESTABLISHED,RELATED,INVALID状态
- NEW: conntrack模块看到的某个连接第一个包,它即将被匹配了。比如,我们看到一个SYN包,是我们所留意的连接的第一个包,就要匹配它。第一个包也可能不是SYN包,但它仍会被认为是NEW状态。
- ESTABLISHED: 已经注意到两个方向上的数据传输,而且会继续匹配这个连接的包。处于ESTABLISHED状态的连接是非常容易理解的。只要发送并接到应答,连接就是ESTABLISHED的了。一个连接要从NEW变为ESTABLISHED,只需要接到应答包即可,不管这个包是发往防火墙的,还是要由防火墙转发的。ICMP的错误和重定向等信息包也被看作是ESTABLISHED,只要它们是我们所发出的信息的应答。
- RELATED 当一个连接和某个已处于ESTABLISHED状态的连接有关系时,就被认为是RELATED的了。换句话说,一个连接要想是RELATED的,首先要有一个ESTABLISHED的连接。这个ESTABLISHED连接再产生一个主连接之外的连接,这个新的连接就是RELATED的了,比如ftp的父子链接。
- 非以上状态的包。
常用的规则场景
tcp通用规则
# 这条规则能够过滤掉很多类型的端口扫描
iptables -t filter -A INPUT -p tcp -m state --state INVALID -j DROP
# 避免配置很多内部端口通行规则
iptables -t filter -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
端口扫描
state与recent模块配合使用。30分钟内发起22,21,80以外端口超过10次,认为是portscan。
iptables -A INPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p all -m state --state NEW -m recent --name port_scan --update --seconds 1800 --hitcount 10 -j DROP
iptables -A INPUT -p tcp --syn -m state --state NEW -m multiport --dports 22,21,80 -j ACCEPT
iptables -A INPUT -p all -m recent --name port_scan --set
暴力猜解
暴力猜解会发起很多次尝试,主要是在这里下手。
#pop3猜解
iptables -A OUTPUT -p tcp --sport 110 -m string --algo bm --string "-ERR Authentication failed。" \
-m recent --name pop3 \
--update --seconds 600 --hicount 6 -j REJECT
iptables -A OUTPUT -p tcp --sport 110 -m string --algo bm --string "-ERR Authentication failed。" \
-m recent --name pop3 --set
#ssh猜解
iptables -A INPUT -p tcp --syn --dport 22 -m recent --name ssh --update --seconds 600 --hitcount 4 -j DROP
iptables -A INPUT -p tcp --syn --dport 22 -m recent --name ssh --set
Syn flood
modprobe ipt_recent ip_list_tot=16384
iptables -N SYN_FLOOD
iptables -A FORWARD -p tcp --syn --dport 80 -m limit --limit 1/m --limit-burst 300 -j ACCEPT
iptables -A FORWARD -p tcp --syn --dport 80 -j SYN_FLOOD
iptables -A SYN_FLOOD -p tcp --syn --dport 80 -m recent --name syn_flood --update --second 123 --hitcount 1 -j ACCEPT
iptables -A SYN_FLOOD -p tcp --syn --dport 80 -m recent --name syn_flood --set
iptables -A SYN_FLOOD -p tcp --syn --dport 80 -j DROP
也可以通过调整网络子系统的参数来抵御flood攻击:
- net。ipv4。tcp_synack_retries
- net。ipv4。tcp_max_syn_backlog
- net。ipv4。tcp_syncookies
ip欺骗经典配置
- 任何进入网络的数据包不能把网络内部的地址作为源地址。
- 任何进入网络的数据包必须把网络内部的地址作为目的地址。
- 任何离开网络的数据包必须把网络内部的地址作为源地址。
- 任何离开网络的数据包不能把网络内部的地址作为目的地址。
- 任何进入或离开网络的数据包不能把一个私有地址(Private Address)或在RFC1918中列出的属于保留空间(包括10.x.x.x/8、172.16.x.x/12 或192.168.x.x/16 和网络回送地址127.0.0.0/8.)的地址作为源或目的地址.
- 阻塞任意源路由包或任何设置了IP选项的包。
变更记录
Why | Who | When |
---|---|---|
create | fishcired | 2014-08-28 |
完善思维导图,添加实例 | fishcired | 2014-08-29 |
调整内容,完善思维导图 | fishcired | 2015-07-17 |
重新对图形进行了调整,修改标题 | fishcired | 2016-02-19 |