====== iptables脚本 ====== 本文讲述个人使用的iptables脚本,iptables是Linux下的netfilter防火墙配置工具。 配置iptables需要有TCP/IP协议的背景知识,以及对netfilter架构的了解,在此推荐[[http://www.frozentux.net/documents/iptables-tutorial|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()函数,后续会讲到。 ===== 脚本类型 ===== 不同角色的机器需要不同的防火墙设置,这里按照客户机、网关、服务器三种最常用的角色,分别提供三种脚本模板: * 客户机模板:[[ftp://gwduan.com/pub/wiki/scripts/rc.iptables-client.ref|rc.iptables-client.ref]] * 网关模板:[[ftp://gwduan.com/pub/wiki/scripts/rc.iptables-gate.ref|rc.iptables-gate.ref]] * 服务器模板:[[ftp://gwduan.com/pub/wiki/scripts/rc.iptables-server.ref|rc.iptables-server.ref]] 此外,还有一个增加了OpenVPN支持的网关模板:[[ftp://gwduan.com/pub/wiki/scripts/rc.iptables-gate-openvpn.ref|rc.iptables-gate-openvpn.ref]],详细说明可参见[[.:openvpn|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配置方案,一般情况下,还是建议使用发行版自己的实现,毕竟这是整体解决方案,而且发行版其他涉及防火墙设置的很多应用都会与此耦合,不小心就会“牵一发动全身”。 下面只讲述脚本在[[http://www.slackware.com|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 {{tag>iptables 防火墙}}