iptables详解

前言

防火墙,就是用于实现访问控制的功能的,它分为硬件的和软件的防火墙两种。无论是在哪个网络中,防火墙工作的地方一定是在网络的边缘。而我们的任务就是需要去定义到底防火墙如何工作,这就是防火墙的策略-规则,以达到让它对出入网络的IP、数据进行检测。

目前市面上比较常见的有3、4层的防火墙,叫网络层的防火墙,还有7层的防火墙,其实是代理层的网关。

对于TCP/IP的七层模型来讲,我们知道第三层是网络层,三层的防火墙会在这层对源地址和目标地址进行检测。但是对于七层的防火墙,不管你源端口或者目标端口,源地址或者目标地址是什么,都将对你所有的内容进行检查。所以,对于设计原理来讲,七层防火墙更加安全,但是这却带来了效率更低。所以市面上通常的防火墙方案,都是两者结合的。而又由于我们都需要从防火墙所控制的这个口来访问,所以防火墙的工作效率就成了用户能够访问数据多少的一个最重要的控制,配置的不好甚至有可能成为流量的瓶颈。

netfilteriptables

  • Netfilter是由Rusty Russell提出的Linux 2.4内核防火墙框架,该框架既简洁又灵活,可实现安全策略应用中的许多功能,如数据包过滤、数据包处理、地址伪装、透明代理、动态网络地址转换,以及基于用户及媒体MAC地址的过滤和基于状态的过滤、包速率限制等。
  • iptables是为用户提供的Netfilter管理工具,用于实现对内核中网络防火墙的管理

防火墙策略

防火墙策略一般分为两种,一种叫策略,一种叫策略。通策略,默认门是关着的,必须要定义谁能进;堵策略则是,大门是洞开的,但是你必须有身份认证,否则不能进。所以我们要定义,让进来的进来,让出去的出去,所以通,是要全通,而堵,则是要选择。当我们定义的策略的时候,要分别定义多条功能。其中:定义数据包中允许或者不允许的策略,filter过滤的功能,而定义地址转换的功能的则是nat选项。为了让这些功能交替工作,我们制定出了这个定义,来定义、区分各种不同的工作功能和处理方式。

表(Table)

描述了iptables功能的大类,如包过滤或网络地址转换(NAT)。共定义了5个表。

  • raw 用于配置数据包,raw中的数据包不会被系统跟踪
  • filter(过滤)用于过滤本机流入、流出的数据包。是iptables默认使用的表。
  • nat(网络地址转换)用于五元组的转换
  • mangle(变更)主要用于修改数据包中的路由标记。如TTL TOS MARK等。
  • security用于强制访问控制网络规则(例如: SELinux – 详细信息参考 该文章)

大部分情况仅需要使用filternat

iptables是工作在用户空间的,它可以让规则进行生效的,本身不是一种服务,而且规则是立即生效的。而我们iptables现在被做成了一个服务,可以进行启动,停止的。启动,则将规则直接生效,停止,则将规则撤销。iptables还支持自己定义链。但是自己定义的链,必须是跟某种特定的链关联起来的。

注意:规则的次序非常关键,检查规则的时候,是按照从上往下的方式进行检查,如果匹配到对应规则,则执行动作,不再往下匹配。

链(Chain)

每个表都有自己的一组内置链,用户还可以自定义链,这样用户就可以建立一组规则,它们都关联都一个共同的标签如MYCHAIN。默认定义了五个链

  • PREROUTING路由前,数据包进入本机,进入路由表之前
  • INPUT数据包通过路由表后,目的地为本机
  • FORWARD数据包通过路由表后,目的地不为本机
  • OUTPUT由本机发出的数据包
  • POSTROUTING数据包通过路由表后,发送至网卡前

表跟链的关系图

表和链的对应关系图

详细的数据包流经图

tables_traverse_detail

只关注filternat表的数据包流经图

tables_traverse

语法格式

iptables [-t 表]
         <命令> -<A I R P D L Z F N E X>
         [链]
         [规则号码]
         [匹配条件]
         [-j 匹配后的动作]

拒绝来自192.168.2.0/24icmp

1
iptables -t filter -A INPUT -s 192.168.2.0/24 -p icmp -j DROP

详解命令

查看管理命令-L

附加子命令

  • -t 接表名,如果不加-t,默认是-t filter
  • -n 以数字的方式显示ip port
  • -v 显示详细信息
  • -x 在计数器上显示精确值,不做单位换算
  • –line-numbers 显示规则的行号

查看 filter 表所有规则

1
iptables -vnL # 等价于iptables -t filter -vnL

查看nat表所有规则

1
iptables -t nat -vnL

查看filter表的INPUT链规则

1
iptables -vnL INPUT

查看 filter 表所有规则并显示行号

1
iptables -vnL --line-numbers

链管理命令(这都是立即生效的)

-P 设置默认策略

当数据包不在我们设置的规则之内时,则该数据包的通过与否,是以策略的设置为准。

默认策略一般只有两种:

1
iptables -P INPUT <DROP|ACCEPT>

这就把默认规则给拒绝了。并且没有定义哪个动作,所以远程连接ssh都被拒绝了。

-F 清空规则链的(注意每个链的管理权限)

1
2
iptables -F        # 清空 filter 表的所有链
iptables -F OUTPUT # 清空 filter 表的 OUTPUT 链

-N 新建自定义链

1
iptables -N MYCHAIN

-E 给用户自定义的链重命名

1
iptables -E MYCHAIN MYNEWCHAIN

-X 用于删除自定义的空链,但是在删除之前必须要将里面的链给清空

1
iptables -X MYNEWCHAIN

-Z 清空链,及链中默认规则的计数器的(有两个计数器,被匹配到的数据包数、字节数,使用iptales -vnL查看)

1
2
iptables -Z # 默认只清空 filter 链
iptables -t nat -Z

规则管理命令

-A chain 追加,在当前链的最后新增一个规则

1
2
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP

-I chain [num]: 插入,把当前规则插入为第几条,默认第一条

1
iptables -I INPUT -p tcp --dport 80 -j DROP

-R chain num:Replays替换/修改第几条规则

1
iptables -R INPUT 1 -p tcp --dport 81 -j DROP

-D chain num:删除,指定删除第几条规则

1
iptables -t filter -D INPUT 1

匹配

每个iptables规则都包含一组匹配以及一个目标,后者告诉iptables对于符合规则的数据包应该采取什么动作。iptables匹配指的是数据包必须匹配的条件,只有当数据包满足所有的匹配条件时,iptables才能根据由该规则的目标所指定的动作来处理该数据包。

每个匹配都在iptables命令行中指定。常用的iptables匹配如下:

通用匹配(地址/协议/匹配等)

  • -s(–source) 匹配源地址或网络,这里不能指定主机名称,必须是 IP|IP/MASK|0.0.0.0/0.0.0.0,地址可以取反,加一个!
  • -d(–destination) 匹配目标地址或网络
  • -p(–protocol) 匹配上层协议(TCP/UDP/ICMP/ALL)
  • -i(–in-interface) 匹配流入接口,一般用在INPUTPREROUTING
  • -o(–out-interface) 流出接口,一般在OUTPUTPOSTROUTING
  • -f(–fragment) 匹配 分片的包的第二片或及以后的部分

扩展匹配

隐含扩展:对协议的扩展

  • tcp
  • udp
  • icmp
  • all

TCP协议的扩展(-p tcp)

–sport(–source-port)、–dport(–destination-port)

指定端口,不能指定多个非连续端口,只能指定单个端口或多个连续的端口。不指定此项,则默认所有端口。

8090目的端口全部DROP

iptables -A INPUT -p tcp --dport 80:90 -j DROP

080的所有目的端口端口全部DROP

iptables -A INPUT -p tcp --dport :80 -j DROP

8065535的所有目的端口全部DROP

iptables -A INPUT -p tcp --dport 80: -j DROP
–tcp-flags

TCP的标志位(SYN ACK FIN PSH RST URG)

匹配SYN标记被设置而FINACK标记没有设置的包

iptables -p tcp --tcp-flags SYN,FIN,ACK SYN -j ACCEPT

匹配所有标记都未置的包

iptables -p tcp --tcp-flags ALL NONE -j DROP
–syn

匹配SYN标记被设置而ACKRST标记没有设置的包,等同于下命令

iptables -p tcp --tcp-flags SYN,RST,ACK SYN
–tcp-option

根据选项匹配包

UDP协议的扩展(-p udp)

–dport –sport

tcp一样

icmp数据报文的扩展(-p icmp)

–icmp-type

根据ICMP类型匹配包

echo-request(请求数据包)一般用8来表示

echo-reply(响应数据包)一般用0来表示

显式扩展(-m)

state 按包状态匹配

  • NEW: 第一次握手,我们就叫 NEW 连接,有别于 tcp 的 syn
  • ESTABLISHED: 第二次握手完成的 ack 都为1,这是正常的数据传输,和 tcp 的第二次第三次握手,为已建立的连接
  • INVALID: 不能被识别属于哪个连接或没有任何状态,例如:SYN=1 ACK=1 RST=1,对于这种数据包是无法识别的,都称之为INVALID无法识别的
  • RELATED: 正在建立一个新的连接,这个连接是和一个已建立的连接相关的,例如:FTP这种古老的拥有的特征,每个端口都是独立的,21号和20号端口都是一去一回,他们之间是有关系的,这种关系我们称之为RELATED

格式

1
-m state --state 状态

示例

1
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

比如进来的只允许状态为NEWESTABLISHED的进来,出去只允许ESTABLISHED状态的出去,这就可以将比较常见的反弹式木马有很好的控制。

mac 按源mac匹配

1
iptables -A INPUT -m mac --mac-source 00:0c:29:a7:bb:99 -j DROP

limit 按包速率匹配

格式

单位时间连接控制,使用/second /minute /hour /day等单位为后缀,默认是3/hour

--limit RATE

间的连接的并发连接控制,默认为5

--limit-burst N

示例

限制目的ip为192.168.2.201每秒3个包

1
2
iptables -A INPUT -d 192.168.2.201 -m limit --limit 3/s -j ACCEPT
iptables -A INPUT -d 192.168.2.201 -j DROP

limit英语上看是限制的意思,但实际上只是按一定速率去匹配而已,要想限制的话后面要再跟一条DROP

iprange IP地址范围匹配

格式

-m iprange [!] <--src-range|--dst-range> IPADDR-IPADDR

来自从 192.168.2.202 到 192.168.2.220 的 tcp 包全部DROP

iptables -A INPUT -p tcp -m iprange --src-range 192.168.2.202-192.168.2.220 -j DROP

multiport 多端口匹配

用来匹配多个不连续的端口,最多能够匹配 15 个不连续的源端口。必须与-p参数一起使用。

格式

1
-m multiport [!] <--sports|--dports|--ports> port1[,port2,..,portn]

拒绝 tcp 目的端口为8090

1
iptables -A INPUT -p tcp -m multiport --dports 80,90 -j DROP

TTL 匹配

根据 IP 头里的 TTL (Time To Live,即生存期)字段来匹配包

  • –ttl-eq
  • –ttl-gt
  • –ttl-lt

拒绝ttl 为 64的流量

1
iptables -A INPUT -p icmp -m ttl --ttl-eq 64 -j DROP

time 基于时间的控制

匹配起始时间与结束时间

1
-m time --datestart YYYY[-MM[[-DD[Thh[:mm[:ss]]]]] --datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]

根据时间和星期几来匹配

  • --timestart hh:mm[:ss] --timestop hh:mm[:ss] [!] --monthdays day[,day...]
  • --timestart hh:mm[:ss] --timestop hh:mm[:ss] [!] --weekdays day[,day...]

每周的周六日拒绝ping

1
iptables -A INPUT -p icmp -m time --timestart 00:00:01 --timestop 23:59:59  --weekdays Sat,Sun -j DROP

-j 动作和跳转

iptables支持一组目标和跳转,它们告诉一条规则当报文完全匹配该条规则的时候,应该怎么处理此报文。

常用的目标如下:

ACCEPT

允许数据包通过

DROP

丢弃数据包,不对该数据包做进一步处理,对接受栈而言,就好像该数据包从来没有被接收一样

LOG

将数据包信息记录到rsyslog

  • –log-level
    • debug
    • info
    • notice
    • warning
    • warn
    • err
    • error
    • crit
    • alert
    • emerg
    • panic
  • –log-prefix 在记录的信息之前加上指定的前缀,前缀最多能有29个英文字符
  • –log-tcp-sequence
  • –log-tcp-options
  • –log-ip-options

需要在/etc/rsyslog.conf添加一条配置kern.=info /var/log/firewall.log,然后重启rsyslog服务

1
iptables -A INPUT -p icmp -j LOG --log-prefix ICMP_ --log-level info

REJECT

丢弃数据包,同时发生适当的响应报文(如:针对TCP连接的RST包或针对UDPICMP端口不可达消息)

--reject-with指定返回什么样的信息

  • icmp-net-unreachable
  • icmp-host-unreachable
  • icmp-port-unreachable
  • icmp-proto-unreachable
  • mp-net-prohibited
  • mp-host-prohibited
  • port-unreachable (默认选项)

示例

1
2
3
4
5
iptables -A INPUT -p tcp --dport 80 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --dport 81 -j REJECT --reject-with net-unreach
iptables -A INPUT -p tcp --dport 82 -j REJECT --reject-with host-unreach
iptables -A INPUT -p tcp --dport 83 -j REJECT --reject-with icmp-net-unreachable
iptables -A INPUT -p tcp --dport 85 -j DROP

DNAT

对于目标地址转换,数据流向是从外向内的,外面的是客户端,里面的是服务器端通过目标地址转换,我们可以让外面的IP通过我们对外的外网IP来访问我们服务器不同的服务器,而我们的服务却放在内网服务器的不同的服务器上。

–to-destination

1
iptables -t nat -A PREROUTING -d 192.168.2.201 -p tcp --dport 80 -j DNAT --to-destination 192.168.2.202

注意:目标地址转换要做在到达网卡之前进行转换,所以要做在 PREROUTING 这个位置上

SNAT

基于原地址的转换一般用在我们的许多内网用户通过一个外网的口上网的时候,这时我们将内网地址转换为一个外网的IP,我们就可以实现连接公网的功能。

--to-source指定源地址和端口,可以是单独的 ip 也可以是 ip 段

将 192.168.2.0/24 段的 ip 在经过的时候全都转换成 172.16.100.1 这个外网地址

1
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j SNAT --to-source 172.16.100.1

MASQUERADE

动态源地址伪装。如果上网 ip 不固定,可以使用该参数。系统会自动将私有源 ip 转换成可以上网的公网 ip。适用于那些 ip 不固定的场景,比如拨号上网或通过 dhcp 分配 ip 的情况。

--to-ports设置外出包能使用的端口

1
2
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j MASQUERADE --to-ports 80-90

REDIRECT

转发包或流到另一个端口

–to-ports

将外网访问 80 端口的数据转发到本机的 8080 端口

1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 81

将访问 80 端口的数据转发到本机的 81-89 端口

1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 81-89

MARK

对报文打防火墙标记。将封包标上某个代号,以便提供作为后续过滤的条件判断依据。

1
2
3
4
iptables -t mangle -A PREROUTING -p tcp --dport 1111 -j MARK --set-mark 1111
iptables -t mangle -A PREROUTING -p tcp --dport 1112 -j MARK --set-mark 1112
iptables -t filter -A INPUT -m mark --mark 1111 -j REJECT --reject-with icmp-net-unreachable
iptables -t filter -A INPUT -m mark --mark 1112 -j DROP

RETURN

如果作用在主链则停止匹配;如果应用于自定义链上,则将返回父链继续匹配

控制规则的存放以及开启

注意:定义的所有内容,当重启的时候都会失效

在开机的时候,会自动加载/etc/sysconfig/iptabels

1
2
iptables-save > iptabels.txt
iptables-restore < /etc/sysconfig/iptables.txt

调试

通过 raw 表和 TRACE 扩展

  • 我们知道从系统进出的网络包,不管其最终目的地为何,都要经过 raw 表的 PREROUTING 和 OUTPUT 链。
  • man iptables-extensions可知,TRACE 扩展目标能够记录 iptables 处理一个网络包时经过的表、链和规则。
1
2
3
4
5
6
7
8
for mod in ipt_LOG nf_log_ipv4;do\
find /lib/modules/$(uname -r) -name "${mod}.ko" -type f | grep -q ${mod}.ko
&& mod=${mod} && break;\
done

modprobe ${mod}
modprobe nf_conntrack_ipv4
sysctl net.netfilter.nf_log.2=${mod}
1
2
iptables -t raw -A PREROUTING -p icmp -j TRACE
iptables -t raw -A OUTPUT -p icmp -j TRACE

调试 network namespace iptables

kernel >= 4.11

在通过 raw 表和 TRACE 扩展调试的基础上执行如下命令

1
echo 1 >/proc/sys/net/netfilter/nf_log_all_netns

kernel < 4.11

使用 ulog

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir -p /tmp/ulogd-rpms
cd /tmp/ulogd-rpms
curl -O https://www.rpmfind.net/linux/epel/7/x86_64/Packages/l/libnetfilter_log-1.0.1-7.el7.x86_64.rpm
curl -O http://repo.iotti.biz/CentOS/7/x86_64/libnetfilter_acct-1.0.2-3.el7.lux.1.x86_64.rpm
curl -O http://repo.iotti.biz/CentOS/7/x86_64/ulogd-2.0.5-2.el7.lux.x86_64.rpm
rpm -ivh *.rpm
cd && rm -rf /tmp/ulogd-rpms

sed -i '/^# loglevel=1/s/^# //' /etc/ulogd.conf
sed -i '/^#stack=log1:NFLOG,base1/s/^#//' /etc/ulogd.conf

ip net exec NAMESPAC-NAME bash
/etc/init.d/ulogd start
1
iptables -A OUTPUT -p icmp -j NFLOG --nflog-prefix="IPT_FILTER_OUTPUT"`

总结

iptables是一个非常重要的工具,它是每一个防火墙上几乎必备的设置,也是我们在做大型网络的时候,为了很多原因而必须要设置的。学好iptables,可以让我们对整个网络的结构有一个比较深刻的了解,同时,我们还能够将内核空间中数据的走向以及Linux的安全给掌握的非常透彻。我们在学习的时候,尽量能结合着各种各样的项目,实验来完成,这样对你加深iptables的配置,以及各种技巧有非常大的帮助。

参考

0%