OpenStack网络基础知识: 玩转Linux防火墙命令iptables

linux新手难以逾越的墙

Posted by fishcried on February 19, 2016

linux的使用者中有很多人还无法纯熟的玩转iptables.网络不通,常会怀疑防火墙,但不能精确的诊断.给出依据.本文总结下iptables,整理下自己的思路.

讲个经历: 一次网络延迟问题诊断时,进行了很久也无法找到根源,一位其他组同事告诉我说把iptables服务关闭了,因为在之前的公司曾经遇到过类似问题。当时就凌乱了,iptables规则排查过,没有规则,默认ACCEPT。而且把iptables服务关闭是什么意思(我用的是ubuntu)?,我就说iptables不是服务,没法关闭啊,除非把内核模块卸载了,但是卸载了怕出现其他问题(线上环境),然后我又把iptables只是个命令,netfilter框架是什么给讲了一遍。同事说,这个具体的不懂,但是centos上是可以关闭的,问题解决后,我装了一台centos机器,还真有service iptables stop命令,实际上就是卸载相关的模块.

原来只是大家的理解角度不同而已.

看下常用的一张图,来说明下iptables的构成.

netfilter与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点

netfilter包处理

Netifilter框架其实非常简单,在数据包处理的不同阶段提供了5大HOOK点,可以在这5个地方注册自己的功能函数,从而对数据包进行控制。

数据包从左边进入IP协议栈,进行IP校验以后,数据包被第一个钩子函数PRE_ROUTING处理,然后就进入路由模块,由其决定该数据包是转发出去还是送给本机。若该数据包是送给本机的,则要经过钩子函数LOCAL_IN处理后传递给本机的上层协议;若该数据包应该被转发,则它将被钩子函数FORWARD处理,然后还要经钩子函数POST_ROUTING处理后才能传输到网络。本机进程产生的数据包要先经过钩子函数LOCAL_OUT处理后,再进行路由选择处理,然后经过钩子函数POST_ROUTING处理后再发送到网络。

iptables原理

已经知道iptables背后的实现是基于netfilter框架,通过在不同的hook点按照优先级插入功能函数来控制数据包.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表

用来进行连接跟踪设置.可以用于加速规则匹配.

防火墙相关命令的使用

iptables

如果非必要,真没有人愿意去详细的学习iptables语法,写起来太麻烦.但熟悉熟悉,理解了原理,掌握起来也很容易.任何命令的参数其实都有其自己的体系,遵循着背后的原理.

iptables使用的语法: iptables [-t table] 操作 chain RULE ,下面是一个简化图.

iptables的使用

  1. 如果想查看特别的表时使用-t指定,如果查看单独的链需要在操作后面指定.
  2. 如果是查看规则定义,使用-S. -S-L查看规则时更加清晰.
  3. 如果查看匹配状况使用-nvL.配合watch使用.
  4. --line-number用于查看规则号.

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的流量匹配?

iptables [-t 表] -L [链] -nv
iptables-save -c

如果想快速的查看规则匹配情况,可以使用上面两条命令.第一条命令较为灵活,可以控制表和链,而且统计信息比较人性化.第二条命令简单. 配合watch能够动态观察.

iptables自定义连

如果想自行定义规则链,可以通过-N参数,然后通过-j/--jump跳转过来就可以了.

iptables -N 链名
iptables ... -j 链名

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