An Introduction To iptables

2015/11/28

概述

Iptables是Linux内核防火墙(netfilter)提供的通用的表结构,和netfilter是早期Linux版本中ipchains和ipfwadm的继任者。iptables用于网络地址转换(NAT)、封包过滤(packet filtering),并在Linux 2.4版本后提供封包修改(packet mangling)。

这里放上IP封包头部的结构,以便于下文对各个规则的理解。

IPv4Packet

图1-1 IP包结构

相关字段说明:

Version:IP协议的版本(如IPv4)
IHL:IP Header的长度
DSCP:服务代码(即Type of Service)
ECN:显式拥塞指示标记
Total Length:整个IP包的长度
Identification:身份标识。如果一个IP包在传输过程中分段了,同一个包的不同片段拥有相同的唯一标识
Flags:标识是否能分段传输
Fragment Offset:分段偏移量。标识本分段在原始IP包中的详细位置
Time to Live:为避免网络回路(loop),每个Packet发送时都带有一个TTL值,表示这个Packet可以经过多少次路由(即“多少跳”)。每经过一跳,该值减1,达到0该Packet被丢弃。
Protocol:告诉目标host的网络层,自己属于哪个协议。(ICMP-1,TCP-6,UDP-17)
Header Checksum:头部校验,用于检查Packet是否有错误
Source Address:数据包的32位发送地址
Destination Address:数据包的32位接收地址
Options:可选字段,仅在IHL大于5时使用。可以包含Security、Record Route、Timestamp等信息。

规则表(Tables)

Iptables内建规则表有三个:filter、nat、mangle。

Mangle表

Mangle是英文“破坏、损坏”的意思,Mangle表的功能是修改数据包头部,如修改TOS之类的值。(建议不要在这个表中做任何filter或nat相关的工作)

Mangle表的几个target是:TOS、TTL、MARK、SECMARK、CONNSECMARK。其中TOS、TTL分别用于修改packet头部中的TOS、TTL字段;MARK、SECMARK、CONNSECMARK都用于向packet中设置可选的特殊字段。

Nat表

用于不同数据包的NAT(Network Address Translation),即用于修改数据包的source和destination两个值。一段流中只有第一个数据包会被Nat表中的规则修改,剩余数据包自动与第一个包采取相同行为。包含的target是DNAT、SNAT、MASQUERADE、REDIRECT。

DNAT用于修改数据包的destination地址然后转发至新的host,例如将数据包从公网IP发送至内网IP。

SNAT用于修改数据包的source地址,例如从内网向公网发起连接时,防火墙可将内网地址替换为自身公网地址。

MASQUERADE与SNAT的用法基本相同,但是通过它处理的数据包的source地址是动态计算出来的,而非单个配置好的IP,所以MASQUERADE可看做SNAT的一种特殊形式。很多网络服务商提供的是动态IP(拨号上网),使用MASQUERADE可以达到SNAT无法达到的效果。

REDIRECT是DNAT的一种特殊形式,不管数据包头部的destination是哪里,都转发到本地host上。

Filter表

Filter表是默认表,用于过滤Packet,可以依据Packet 内容选择DROP/ACCEPT等。

Security表

Security表用于MAC(Mandatory Access Control,如SELinux等)网络规则控制。

规则链(Chains)

链是多个有序的Rule序列的列表(即包含多个Rule列表的列表)。

表是由多个链组成的,默认表filter的内置链有INPUT、OUTPUT、FORWARD,这些链在Packet过滤过程的不同位置激活并生效(如图3-1所示)。

图3-1 iptables packet flow

Nat表内置链是PREROUTING、OUTPUT、POSTROUTING

Mangle表内置链是PREROUTING、OUTPUT,2.4.18后加入了INPUT 、FORWARD、POSTROUTING

Raw表内置链是PREROUTING、OUTPUT

绝大多数情况下不会用到raw、mangle和security表,所以图3-1可以简化成图3-2。

图3-2 简化的iptables packet flow

规则(Rules)

一条规则包含多个匹配条件和一个target(动作、处理行为)。

通常的匹配条件有接收数据包的网络接口(如eth0, eth1),数据包类型(如ICMP、TCP、UDP),数据包目的端口等。

Target可以是用户自定义链、内置链或扩展target。内置target有ACCEPT、DROP、QUEUE、RETURN;扩展target有REJECT、LOG。如果是内置target,Packet会被立即处理,不再Table中停留(即使还有后续链)。如果target是用户自定义链,Packet依然要走完原链的所有规则,才能跳到target(即这个自定义链)。

常用规则

删除现有规则

iptables –F 或 iptables –flush

设置默认链策略

(将INPUT/FORWARD/OUTPUT的默认链策略设为DROP,这样做会屏蔽所有输入、输出网卡的数据包,除非你明确指定哪些数据包可以通过网卡。)

iptables -P INPUT DROP

iptables -P FORWARD DROP

iptables -P OUTPUT DROP

设置黑名单

1)屏蔽所指定的IP地址访问本地主机

iptables -A INPUT -i eth0 -s 192.168.43.0/24 -j DROP

2)仅屏蔽来自该IP的TCP数据包

iptables -A INPUT -i eth0 -p tcp -s 192.168.43.0/24 -j DROP

允许来自外部的ping并回应

iptables -A INPUT -p icmp –icmp-type echo-request -j ACCEPT

iptables -A OUTPUT -p icmp –icmp-type echo-reply -j ACCEPT

允许从本机ping外部主机

iptables -A OUTPUT -p icmp –icmp-type echo-request -j ACCEPT

iptables -A INPUT -p icmp –icmp-type echo-reply -j ACCEPT

允许回环(loopback)访问

iptables -A INPUT -i lo -j ACCEPT

iptables -A OUTPUT -o lo -j ACCEPT

允许进入eth0的ssh连接

iptables -A INPUT -i eth0 -p tcp –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 22 -m state –state ESTABLISHED -j ACCEPT

允许从本地发起经过eth0的ssh连接

iptables -A OUTPUT -o eth0 -p tcp –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp –sport 22 -m state –state ESTABLISHED -j ACCEPT

允许来自192.168.100.0/24网络的ssh连接(CIDR网络地址)

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 22 -m state –state ESTABLISHED -j ACCEPT

仅允许从本地主机连接到192.168.100.0/24网络的ssh请求

iptables -A OUTPUT -o eth0 -p tcp -d 192.168.100.0/24 –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp –sport 22 -m state –state ESTABLISHED -j ACCEPT

允许HTTP/HTTPS连接请求

1)允许HTTP连接:80端口

iptables -A INPUT -i eth0 -p tcp –dport 80 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 80 -m state –state ESTABLISHED -j ACCEPT

2)允许HTTPS连接:443端口

iptables -A INPUT -i eth0 -p tcp –dport 443 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 443 -m state –state ESTABLISHED -j ACCEPT

允许从本地发起HTTPS连接

本规则可以允许用户从本地主机发起HTTPS连接,从而访问Internet。

iptables -A OUTPUT -o eth0 -p tcp –dport 443 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp –sport 443 -m state –state ESTABLISHED -j ACCEPT

使用-m multiport指定多个端口

通过指定-m multiport选项,可以在一条规则中同时允许SSH、HTTP、HTTPS连接:

iptables -A INPUT -i eth0 -p tcp -m multiport –dports 22,80,443 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp -m multiport –sports 22,80,443 -m state –state ESTABLISHED -j ACCEPT

允许出站DNS连接

iptables -A OUTPUT -p udp -o eth0 –dport 53 -j ACCEPT

iptables -A INPUT -p udp -i eth0 –sport 53 -j ACCEPT

允许来自指定网络的rsync连接请求

只希望能够从内部网络(192.168.101.0/24)访问即可:

iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 –dport 873 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 873 -m state –state ESTABLISHED -j ACCEPT

允许来自指定网络的MySQL连接请求

你可能启用了MySQL服务,但只希望DBA与相关开发人员能够从内部网络(192.168.100.0/24)直接登录数据库:

iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 –dport 3306 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 3306 -m state –state ESTABLISHED -j ACCEPT

允许Sendmail, Postfix邮件服务(端口25)

iptables -A INPUT -i eth0 -p tcp –dport 25 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 25 -m state –state ESTABLISHED -j ACCEPT

允许IMAP与IMAPS

IMAP:143 iptables -A INPUT -i eth0 -p tcp –dport 143 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 143 -m state –state ESTABLISHED -j ACCEPT

IMAPS:993 iptables -A INPUT -i eth0 -p tcp –dport 993 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 993 -m state –state ESTABLISHED -j ACCEPT

允许POP3与POP3S

POP3:110 iptables -A INPUT -i eth0 -p tcp –dport 110 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 110 -m state –state ESTABLISHED -j ACCEPT

POP3S:995 iptables -A INPUT -i eth0 -p tcp –dport 995 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 995 -m state –state ESTABLISHED -j ACCEPT

防DoS攻击

iptables -A INPUT -p tcp –dport 80 -m limit –limit 25/minute –limit-burst 100 -j ACCEPT

-m limit: 启用limit扩展

–limit 25/minute: 允许最多每分钟25个连接

–limit-burst 100: 当达到100个连接后,才启用上述25/minute限制

允许网卡间路由

如果本地主机有两块网卡,一块连接内网(eth0),一块连接外网(eth1),那么可以使用下面的规则将eth0的数据路由到eht1:

iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

DNAT与端口转发

以下规则将会把来自422端口的流量转发到22端口。这意味着来自422端口的SSH连接请求与来自22端口的请求等效。

1.启用DNAT转发 iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 –dport 422 -j DNAT –to-destination 192.168.102.37:22

2.允许连接到422端口的请求 iptables -A INPUT -i eth0 -p tcp –dport 422 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp –sport 422 -m state –state ESTABLISHED -j ACCEPT

将HTTP请求转发到内部服务器xxx.xxx.xxx.xxx

iptables -t nat -A PREROUTING -p tcp -i eth0 -d xxx.xxx.xxx.xxx –dport 8888 -j DNAT –to 192.168.0.2:80

iptables -A FORWARD -p tcp -i eth0 -d 192.168.0.2 –dport 80 -j ACCEPT

当该数据包到达xxx.xxx.xxx.xxx后,需要将该数据包转发给192.168.0.2的80端口,事实上NAT所做的是修改该数据包的目的地址和目的端口号。然后再将该数据包路由给对应的主机。

但是iptables会接受这样的需要路由的包么?这就由FORWARD链决定。我们通过第二条命令告诉iptables可以转发目的地址为192.168.0.2:80的数据包。再看一下上例中422端口转22端口,这是同一IP,因此不需要设置FORWARD链。

SNAT与MASQUERADE

如下命令表示把所有10.8.0.0网段的数据包SNAT成192.168.5.3的ip然后发出去:

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j snat –to-source 192.168.5.3

对于snat,不管是几个地址,必须明确的指定要snat的IP。假如我们的计算机使用ADSL拨号方式上网,那么外网IP是动态的,这时候我们可以考虑使用MASQUERADE

iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j MASQUERADE

负载均衡

可以利用iptables的-m nth扩展,及其参数(–counter 0 –every 3 –packet x),进行DNAT路由设置(-A PREROUTING -j DNAT –to-destination),从而将负载平均分配给3台服务器:

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state –state NEW -m nth –counter 0 –every 3 –packet 0 -j DNAT –to-destination 192.168.1.101:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state –state NEW -m nth –counter 0 –every 3 –packet 1 -j DNAT –to-destination 192.168.1.102:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state –state NEW -m nth –counter 0 –every 3 –packet 2 -j DNAT –to-destination 192.168.1.103:443

自定义链,记录丢弃的数据包

1.新建名为LOGGING的链 iptables -N LOGGING

2.将所有来自INPUT链中的数据包跳转到LOGGING链中 iptables -A INPUT -j LOGGING

3.指定自定义的日志前缀"IPTables Packet Dropped: " iptables -A LOGGING -m limit –limit 2/min -j LOG –log-prefix “IPTables Packet Dropped: " –log-level 7

4.丢弃这些数据包 iptables -A LOGGING -j DROP