响水凹

欢迎来到 Guang-Wen Duan (Dennis Duan) 的个人 Wiki

用户工具

站点工具


computer:sec:iptables

iptables脚本

本文讲述个人使用的iptables脚本,iptables是Linux下的netfilter防火墙配置工具。

配置iptables需要有TCP/IP协议的背景知识,以及对netfilter架构的了解,在此推荐Iptables-tutorial,这是一个非常不错的网站,个人的新版本脚本也大量借鉴了其中的做法,感谢作者的贡献。

脚本框架

iptables脚本遵循基本的脚本规范,提供start、stop、restart功能。基本框架如下:

#
# Global configuration.
#
IPTABLES="/usr/sbin/iptables"
MODPROBE="/sbin/modprobe"
 
start() {
...
}
 
resume_all() {
...
}
 
stop() {
...
}
 
case "$1" in
'start')
	start
	;;
'stop')
	stop
	resume_all
	;;
'restart')
	stop
	start
	;;
*)
	echo "usage $0 start|stop|restart"
esac
这里有个resume_all()函数,后续会讲到。

脚本类型

不同角色的机器需要不同的防火墙设置,这里按照客户机、网关、服务器三种最常用的角色,分别提供三种脚本模板:

此外,还有一个增加了OpenVPN支持的网关模板:rc.iptables-gate-openvpn.ref,详细说明可参见OpenVPN的简单配置的相关部分。

使用时,先根据具体环境选择模板,再按实际情况进行更改调整。

不同角色脚本的主要区别在start()函数,下面就各个函数做简要说明(脚本里也有注释)。

脚本函数

客户机start()函数

配置接口参数

参数包括ip地址,接口名称等。对于客户机这些参数一般不用设置,因为客户机通常作为终端使用,不需要那么精确控制:

# 1.1 Local Area Network configuration.
#
LAN_IP="10.10.10.10"
LAN_IFACE="eth0"
LAN_BROADCAST="10.10.10.255"
 
#
# 1.2 Loopback configuration.
#
LO_IP="127.0.0.1"
LO_IFACE="lo"

装载内核模块

这里缺省只装载ip_conntrack_ftp,以处理FTP应用:

# 2.1 Required modules.
#
$MODPROBE ip_conntrack_ftp
 
#
# 2.2 Non-Required modules.
#
#$MODPROBE ip_conntrack_tftp
#$MODPROBE ip_conntrack_irc


接下来是Filter表的设置,客户机不涉及NAT表和Mangle表设置。

缺省策略

缺省策略设置为禁止一切数据:

# 3.1 Set default policies.
#
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP

分片包

虽然分片包有存在的理由,但在当今的网络现状下,已经很少了。分片出现更多的是源于攻击,所以禁止分片包(缺省直接丢弃,也可打开注释同时记录到日志里):

# 3.2 Drop all fragment packets.
#
#$IPTABLES -A INPUT -f -j LOG --log-prefix "iptables[fragment]:"
$IPTABLES -A INPUT -f -j DROP

Loopback接口

对于本地loopback接口不做限制:

# 3.3 Loopback rules.
#
$IPTABLES -A INPUT -i $LO_IFACE -j ACCEPT

Input链设置

客户机一般是不提供对外服务的,所以只允许相应的应答包进入本机(包括ESTABLISHED和RELATED状态):

# 3.4.1 Allow all established and related packets.
#
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

提供的对外服务需要明确指定(这里缺省提供ssh和ping服务),别的服务可参照添加:

# 3.4.2 Allow ssh.
#
$IPTABLES -A INPUT -p tcp --dport ssh --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.3 Allow ping.
#
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

在Windows网络环境下,会有大量的广播数据包,对Linux是没用的,如果需要,可以丢弃这些包:

# 3.4.4 In Microsoft Networks you will be swamped by broadcast. These lines
# will prevent them from showing up in the logs.
#
#$IPTABLES -A INPUT -d $LAN_BROADCAST -p udp --dport 135:139 -j DROP
 
#
# 3.4.5 If we get dhcp request from the outside of our network, our logs
# will be swamped as well. This rule will block them from getting logged.
#
#$IPTABLES -A INPUT -d 255.255.255.255 -p udp --dport 67:68 -j DROP
 
#
# 3.4.6 If you have a Microsoft Network on the outside of your firewall,
# you may also get flooded by Multicast. We drop them so we do not get
# flooded by logs.
#
#$IPTABLES -A INPUT -d 224.0.0.0/8 -j DROP

如果需要,可以将其他数据包记录到日志里,供后续处理:

# 3.4.7 Log rules.
#
#$IPTABLES -A INPUT -j LOG --log-prefix "iptables[input]:"

Output链设置

客户机可以访问任何地方,不做限制:

# 3.5.1 Allow full access.
#
$IPTABLES -A OUTPUT -j ACCEPT

Forward链设置

客户机是单点终端,不涉及Forward方面的配置。

网关start()函数

虽然角色不同,但start()函数的基本框架是一致的,所以相同的设置将不再重复讲述,完整的说明可参见脚本内容。

配置接口参数

网关作为网络的枢纽,一般都是有多个接口的,比如内网、外网、dmz接口,有的还配有专门的管理接口mng。

这里按四个接口的规格进行设计:

# 1.1 Local Area Network configuration.
#
LAN_IP="10.10.10.1"
LAN_IP_RANGE="10.10.10.0/24"
LAN_IFACE="eth0"
LAN_BROADCAST="10.10.10.255"
 
#
# 1.2 Internet configuration.
#
WAN_IP="172.16.0.10"
WAN_IFACE="eth1"
#WAN_IFACE="ppp+"
WAN_BROADCAST="172.16.0.255"
 
#
# 1.3 DMZ configuration.
#
DMZ_IP="10.10.20.1"
DMZ_IFACE="eth2"
DMZ_BROADCAST="10.10.20.255"
DMZ_HTTP_IP="10.10.20.10"
DMZ_FTP_IP="10.10.20.20"
DMZ_DNS_IP="10.10.20.30"
 
#
# 1.4 Management configuration.
#
MNG_IP="10.10.30.1"
MNG_IFACE="eth3"
MNG_BROADCAST="10.10.30.255"

装载内核模块

网关通常要做NAT,所以FTP应用多加载了ip_nat_ftp模块:

# 2.1 Required modules.
#
$MODPROBE ip_conntrack_ftp
$MODPROBE ip_nat_ftp
 
#
# 2.2 Non-Required modules.
#
#$MODPROBE ip_conntrack_tftp
#$MODPROBE ip_conntrack_irc
#$MODPROBE ip_nat_tftp
#$MODPROBE ip_nat_irc


接下来是Filter表的设置。

分片包

除了禁止到达本机的分片包外,也不转发分片包:

# 3.2 Drop all fragment packets.
#
#$IPTABLES -A INPUT -f -j LOG --log-prefix "iptables[fragment]:"
$IPTABLES -A INPUT -f -j DROP
#$IPTABLES -A FORWARD -f -j LOG --log-prefix "iptables[fragment]:"
$IPTABLES -A FORWARD -f -j DROP

Loopback接口

对于本地loopback接口同样不做限制(相比客户机,这里多了一条OUTPUT设置,因为后续要对Output链进行具体配置):

# 3.3 Loopback rules(allow all lookback packets).
#
$IPTABLES -A INPUT -i $LO_IFACE -j ACCEPT
$IPTABLES -A OUTPUT -o $LO_IFACE -j ACCEPT

Input链设置

允许相应的应答包进入本机(包括ESTABLISHED和RELATED状态):

# 3.4.1 Allow all established and related packets.
#
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

网关提供服务要慎之又慎。这里缺省允许在内网接口和管理接口接入ssh,允许在内网接口、管理接口和DMZ接口接受ping请求:

# 3.4.2 Allow ssh for management in LAN and MNG network.
#
$IPTABLES -A INPUT -i $LAN_IFACE -p tcp --dport ssh --syn -m state \
	--state NEW -j ACCEPT
$IPTABLES -A INPUT -i $MNG_IFACE -p tcp --dport ssh --syn -m state \
	--state NEW -j ACCEPT
 
#
# 3.4.3 Allow ping in LAN, DMZ and MNG network.
#
$IPTABLES -A INPUT -i $LAN_IFACE -p icmp --icmp-type echo-request -j ACCEPT
$IPTABLES -A INPUT -i $DMZ_IFACE -p icmp --icmp-type echo-request -j ACCEPT
$IPTABLES -A INPUT -i $MNG_IFACE -p icmp --icmp-type echo-request -j ACCEPT

如果为内网提供DHCP服务,则打开如下规则:

# 3.4.4 Allow dhcp requests from LAN.
#
#$IPTABLES -A INPUT -i $LAN_IFACE -p udp --sport bootpc \
#	--dport bootps -j ACCEPT

如果为内网提供DNS域名查询服务,则打开如下规则:

# 3.4.5 Allow dns requests from LAN.
#
#$IPTABLES -A INPUT -i $LAN_IFACE -p udp --dport domain -m state \
#	--state NEW -j ACCEPT

Output链设置

首先允许相应的应答包离开本机(即ESTABLISHED和RELATED状态):

# 3.5.1 Allow all established and related packets.
#
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

允许网关访问的服务,如下依次定义:

# 3.5.2 Allow ftp(21).
#
$IPTABLES -A OUTPUT -p tcp --dport ftp --syn -m state --state NEW -j ACCEPT
 
#
# 3.5.3 Allow ssh(22).
#
$IPTABLES -A OUTPUT -p tcp --dport ssh --syn -m state --state NEW -j ACCEPT
 
#
# 3.5.4 Allow smtp(25).
#
$IPTABLES -A OUTPUT -p tcp --dport smtp --syn -m state --state NEW -j ACCEPT
 
#
# 3.5.5 Allow dns request(53).
#
$IPTABLES -A OUTPUT -p udp --dport domain -m state --state NEW -j ACCEPT
 
#
# 3.5.6 Allow dhcp request(67).
#
$IPTABLES -A OUTPUT -p udp --dport bootps -m state --state NEW -j ACCEPT
 
#
# 3.5.7 Allow http(80).
#
$IPTABLES -A OUTPUT -p tcp --dport http --syn -m state --state NEW -j ACCEPT
 
#
# 3.5.8 Allow https(443).
#
$IPTABLES -A OUTPUT -p tcp --dport https --syn -m state --state NEW -j ACCEPT
 
#
# 3.5.9 Allow ping.
#
$IPTABLES -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT

对于非正常的访问,可记录进日志:

# 3.5.10 Log rules.
#
#$IPTABLES -A OUTPUT -j LOG --log-prefix "iptables[output]:"
鉴于网关的特殊地位,也有一种做法是不限制网关的对外访问,即Output都是ACCEPT(如客户机),这在测试阶段尤为方便,具体实施时可以商榷。

Forward链设置

首先允许转发所有的应答数据(即ESTABLISHED和RELATED状态):

# 3.6.1 Allow all established and related packets.
#
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

具体定义内网对外网的访问(缺省都是关闭的,可按需打开):

# 3.6.2 LAN --> WAN rules. 
#
# 3.6.2.1 Allow ftp(21).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p tcp --dport ftp \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.2.2 Allow ssh(22).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p tcp --dport ssh \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.2.3 Allow smtp(25).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p tcp --dport smtp \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.2.4 Allow dns request(53).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p udp --dport domain \
#	-m state --state NEW -j ACCEPT
 
#
# 3.6.2.5 Allow http(80).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p tcp --dport http \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.2.6 Allow https(443).
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p tcp --dport https \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.2.7 Allow ping.
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $WAN_IFACE -p icmp \
#	--icmp-type echo-request -j ACCEPT
通常不应该限制内网对外网的访问(即内网到外网的Forward都是ACCEPT),这里只是提供一个保守的做法。

允许内网对DMZ网络的完全访问(缺省关闭):

# 3.6.3 LAN --> DMZ rules.
#
# 3.6.3.1 Allow full access.
#
#$IPTABLES -A FORWARD -i $LAN_IFACE -o $DMZ_IFACE -m state \
#	--state NEW -j ACCEPT

具体定义外网对DMZ服务的访问(缺省关闭):

# 3.6.4 DMZ <-- WAN rules.
#
# 3.6.4.1 Allow ftp(21).
#
#$IPTABLES -A FORWARD -i $WAN_IFACE -o $DMZ_IFACE -p tcp --dport ftp \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.4.2 Allow dns request(53).
#
#$IPTABLES -A FORWARD -i $WAN_IFACE -o $DMZ_IFACE -p tcp --dport domain \
#	--syn -m state --state NEW -j ACCEPT
#$IPTABLES -A FORWARD -i $WAN_IFACE -o $DMZ_IFACE -p udp --dport domain \
#	-m state --state NEW -j ACCEPT
 
#
# 3.6.4.3 Allow http(80).
#
#$IPTABLES -A FORWARD -i $WAN_IFACE -o $DMZ_IFACE -p tcp --dport http \
#	--syn -m state --state NEW -j ACCEPT
 
#
# 3.6.4.4 Allow https(443).
#
#$IPTABLES -A FORWARD -i $WAN_IFACE -o $DMZ_IFACE -p tcp --dport https \
#	--syn -m state --state NEW -j ACCEPT
如果需要,可以把函数开头的接口设置中设定的DMZ主机地址,如DMZ_HTTP_IP、DMZ_FTP_IP等,添加到上面的相应规则中(-d参数:目标地址匹配),以实现更精确的控制。

对于非正常的流量,可记录进日志:

# 3.6.5 Log rules.
#
#$IPTABLES -A FORWARD -j LOG --log-prefix "iptables[forward]:"


接下来是NAT表的设置。

Postrouting链设置

在Postrouting链的最通常设置就是SNAT了,IP伪装(MASQUERADE)是SNAT的一种特例:

# 4.2 POSTROUTING chain.
#
#$IPTABLES -t nat -A POSTROUTING -o $WAN_IFACE -j SNAT --to $WAN_IP
#$IPTABLES -t nat -A POSTROUTING -o $WAN_IFACE -j MASQUERADE

Prerouting链设置

在开启SNAT的情况下,外网只能看到网关,不知道后面DMZ网络的结构,需要在网关做DNAT(重定向):

# 4.1 PREROUTING chain.
#
# 4.1.1 Allow ftp(21).
#
#$IPTABLES -t nat -A PREROUTING -i $WAN_IFACE -p tcp --dport ftp \
#	-j DNAT --to $DMZ_FTP_IP
 
#
# 4.1.2 Allow dns request(53).
#
#$IPTABLES -t nat -A PREROUTING -i $WAN_IFACE -p tcp --dport domain \
#	-j DNAT --to $DMZ_DNS_IP
#$IPTABLES -t nat -A PREROUTING -i $WAN_IFACE -p udp --dport domain \
#	-j DNAT --to $DMZ_DNS_IP
 
#
# 4.1.3 Allow http(80).
#
#$IPTABLES -t nat -A PREROUTING -i $WAN_IFACE -p tcp --dport http \
#	-j DNAT --to $DMZ_HTTP_IP
 
#
# 4.1.4 Allow https(80).
#
#$IPTABLES -t nat -A PREROUTING -i $WAN_IFACE -p tcp --dport https \
#	-j DNAT --to $DMZ_HTTP_IP


Mangle表暂未涉及。

服务器start()函数

服务器除了对外提供相应的服务外,通常并不允许自己随意访问外部网络,因而在Output链控制更为严格。

Input链设置

允许相应的应答包进入本机(ESTABLISHED和RELATED状态):

# 3.4.1 Allow all established and related packets.
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

具体定义提供的服务(下面是一些常用服务的模板,可按需打开):

# 3.4.2 Allow ftp(21).
#
#$IPTABLES -A INPUT -p tcp --dport ftp --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.3 Allow ssh(22).
#
#$IPTABLES -A INPUT -p tcp --dport ssh --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.4 Allow smtp(25).
#
#$IPTABLES -A INPUT -p tcp --dport smtp --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.5 Allow dns request(53).
#
#$IPTABLES -A INPUT -p udp --dport domain -m state --state NEW -j ACCEPT
 
#
# 3.4.6 Allow dhcp request(67).
#
#$IPTABLES -A INPUT -p udp --dport bootps -m state --state NEW -j ACCEPT
 
#
# 3.4.7 Allow http(80).
#
#$IPTABLES -A INPUT -p tcp --dport http --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.8 Allow https(443).
#
#$IPTABLES -A INPUT -p tcp --dport https --syn -m state --state NEW -j ACCEPT
 
#
# 3.4.9 Allow ping.
#
#$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

Output链设置

缺省只允许应答包离开(ESTABLISHED和RELATED状态):

# 3.5 Output rules.
#
# 3.5.1 Allow all established and related packets.
#
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Forward链设置

服务器不涉及Forward链。

stop()函数

功能很明确,清除所有规则:

stop() {
 
#
# Flush all the rules in the filter table.
#
$IPTABLES -F
 
#
# Erase all chains that's not default in filter table.
#
$IPTABLES -X
 
#
# Flush all the rules in the nat table.
#
 
$IPTABLES -t nat -F
 
#
# Erase all chains that's not default in nat table.
#
 
$IPTABLES -t nat -X
 
#
# Flush all the rules in the mangle table.
#
 
$IPTABLES -t mangle -F
 
#
# Erase all chains that's not default in mangle table.
#
 
$IPTABLES -t mangle -X
 
}

resume_all()函数

在stop()函数中,我们并没有恢复缺省策略为ACCEPT,这是因为restart功能的实现是先调用stop(),然后调用start()。如果stop()取消了所有限制,那么在start()启动之前,就会有一个时间空间,使机器处在无防火墙监管之下。

为此,额外提供一个resume_all()函数,在真正执行stop功能时,恢复所有缺省策略:

resume_all() {
 
#
# Reset the default policies in the filter table.
#
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
 
#
# Reset the default policies in the nat table.
#
$IPTABLES -t nat -P PREROUTING ACCEPT
$IPTABLES -t nat -P POSTROUTING ACCEPT
$IPTABLES -t nat -P OUTPUT ACCEPT
 
#
# Reset the default policies in the mangle table.
#
$IPTABLES -t mangle -P PREROUTING ACCEPT
$IPTABLES -t mangle -P POSTROUTING ACCEPT
$IPTABLES -t mangle -P INPUT ACCEPT
$IPTABLES -t mangle -P OUTPUT ACCEPT
$IPTABLES -t mangle -P FORWARD ACCEPT
 
}

应用

本文的iptables脚本是一个通用脚本,与具体使用哪个Linux发行版没有关系。但现在很多发行版都或多或少的提供了自己的iptables配置方案,一般情况下,还是建议使用发行版自己的实现,毕竟这是整体解决方案,而且发行版其他涉及防火墙设置的很多应用都会与此耦合,不小心就会“牵一发动全身”。

下面只讲述脚本在slackware下的使用方法。

slackware

slackware的脚本都存放在/etc/rc.d/目录下,故首先把相应模板脚本放到/etc/rc.d/目录下,改名为rc.iptables:

cp rc.iptables-XXXX.ref /etc/rc.d/rc.iptables

给新脚本增加执行权限:

chmod +x /etc/rc.d/rc.iptables

编辑/etc/rc.d/rc.S文件,在末尾添加调用rc.iptables的语句:

# If there is my iptables script, run it before network up.
if [ -x /etc/rc.d/rc.iptables ]; then
  . /etc/rc.d/rc.iptables start
fi
防火墙要在网络接口启动之前运行,否则就会留下时间空间,这就是脚本为什么放在rc.S中的原因(在rc.M中会启动网络接口)。

另外,对于网关脚本,需要打开内核的IP转发功能,才能实现Forward功能。具体方法是:

echo 1 > /proc/sys/net/ipv4/ip_forward

不过,slackwaer本身已提供了一个脚本rc.ip_forward来做这事,只需给它增加执行权限即可:

chmod +x /etc/rc.d/rc.ip_forward
computer/sec/iptables.txt · 最后更改: 2014/11/01 02:02 由 127.0.0.1