内核配置,第 1 部分
安装之后,应该有一个 "iptables" 命令可供使用,还有一个方便的 iptables 帮助页面("man iptables")。好;现在只需要确保已在内核中构建了必需的功能。本教程假设您编译自己的内核。进入 /usr/src/linux,输入 "make menuconfig" 或 "make xconfig";我们将启用一些内核网络功能。
内核配置,第 2 部分
在 "Networking options" 部分中,确保至少启用了以下选项:
<*> Packet socket
[*] Network packet filtering (replaces ipchains)
<*> Unix domain sockets
[*] TCP/IP networking
[*] IP: advanced router
[*] IP: policy routing
[*] IP: use netfilter MARK value as routing key
[*] IP: fast network address translation
[*] IP: use TOS value as routing key
然后,在 "IP: Netfilter Configuration --->" 菜单中,启用每个选项,这样我们就拥有了完整的 netfilter 功能。虽然我们不会使用所有 netfilter 功能,但最好启用它们,这样您可以在以后进行一些实验。
内核配置,第 3 部分
"Networking options" 类别下有一个网络选项不应该启用:明确拥塞通知。让这个选项保留禁用状态:
[ ] IP: TCP Explicit Congestion Notification support
如果启用了这个选项,那么 Linux 机器将不能继续与 8% 的因特网进行网络通信。启用 ECN 时,Linux 机器发送出的一些包将会设置 ECN 位;不过,这个位会使许多网际路由器感到困惑,因此一定要禁用 ECN。
好,现在已根据我们的需要正确配置了内核,编译一个新的内核,安装它,然后重新引导。现在开始使用 netfilter
防火墙设计基础
在创建防火墙时,"iptables" 命令是我们的朋友。我们使用它与内核中的网络包过滤规则进行交互。我们将使用 "iptables" 命令来新建规则、列出现有规则、刷新规则和设置缺省包处理策略。这就意味着要创建防火墙,需要输入一系列 iptables 命令,这就是我们首先要讨论的内容(此时请别输入此命令!)……
防火墙设计基础,续
# iptables -P INPUT DROP
您现在看到的是一个几乎“完美”的防火墙。如果输入此命令,您将会得到难以置信的完美保护,它可以防止任何形式的进入恶意攻击。那是因为此命令告诉内核删除所有进入网络包。虽然这个防火墙非常安全,但它有点傻。但在继续讨论之前,让我们研究一下此命令是如何执行操作的。
设置链策略
"iptables -P" 命令用于为包过滤规则链设置缺省策略。在本示例中,iptables -P 用于为 INPUT 链设置缺省策略,INPUT 是一个内置链,包括了应用于每个进入包的规则。通过将缺省策略设置成 DROP,告诉内核应该删除(即,废弃)到达 INPUT 规则链末端的任意包。而且,由于我们还没有对 INPUT 链添加任何规则,因此所有包都会到达此链的末端,而且所有包都会被删除
设置链策略,续
再次声明,这个命令本身根本没有用。但是,它演示了一个很好的防火墙设计策略。我们从缺省情况下删除所有包开始,然后逐步开放防火墙,这样它将会满足我们的需要。这种做法可以确保防火墙会尽可能安全。
(小)改进
在本示例中,假设我们正在为有两个网络接口 eh0 和 eth1 的机器设计防火墙。eth0 网卡连接到 LAN,而 eth1 网卡连接到 DSL 路由器,这是与因特网的连接。对于这种情况,通过添加以下几行命令就可以改进我们的“终极防火墙”:
iptables -P INPUT DROP
iptables -A INPUT -i ! eth1 -j ACCEPT
这行附加的 "iptables -A" 将一个新的包过滤规则添加到 INPUT 链的末端。添加此规则之后,INPUT 链就包含了一个规则和缺省删除策略。现在,让我们看一下这个半成品防火墙有什么功能。
有关 INPUT 链
当包进入任何一个接口(lo、th0 或 eth1)时,netfilter 代码会将它定向到 INPUT 链,并检查该包是否与第一个规则匹配。如果匹配,则接受包,并且不再执行处理。如果不匹配,则实施 INPUT 链的缺省策略,废弃(删除)该包。
那是概念性的概述。具体情况中,第一个规则会匹配来自 eth0 和 lo 的所有包,并立即允许它们进入。而所有来自 eth1 的包都将被删除。因此,如果我们在机器上启用这个防火墙,它可以与 LAN 交互,但却会彻底断开因特网连接。让我们看一些启用因特网通信流的方法。
传统防火墙,第 1 部分
显然,如果要使防火墙变得实用,需要有选择性地允许某些进入包经由因特网到达机器。有两种方法可以使防火墙开放到实用的程度 -- 一种是使用静态规则,另一种是使用动态规则,即有状态规则。
传统防火墙,第 2 部分
让我们使用下载网页作为示例。如果想要机器能够从因特网下载网页,可以添加一个静态规则,此规则永远允许每个进入 http 包,不管它来自何处:
iptables -A INPUT --sport 80 -j ACCEPT
由于所有标准 Web 通信流都来自源端口 80,实际上此规则允许机器下载网页。虽然可以勉强接受这种传统方法,但是它却有许多问题。
传统防火墙的缺点,第 1 部分
这里有个问题:虽然大多数 Web 通信流来自端口 80,但有些不是这样。因此,虽然此规则在大部分时间中有效,但仍有少量情况并不适用此规则。例如,您可能看到过类似于 "http://www.foo.com:81" 的 URL。这个 URL 示例通过端口 81 连接到网站,而不是缺省端口 80,因此在防火墙后面就看不到这个网站。考虑所有这些特殊情况可以将相当安全的防火墙迅速变成瑞士干酪, 并迅速将许多规则添加到 INPUT 链以处理偶尔遇到的奇特网站。
传统防火墙的缺点,第 2 部分
但是,这个规则的主要问题与安全性相关。的确,只有使用源端口 80 的通信流才能通过我们的防火墙。但是包的源端口并不是我们所能控制的,闯入者可以轻易地改变它。例如,如果闯入者知道我们的防火墙是如何设计的,他只要确保其所有进入连接都来自其机器的 80 端口就可以绕过我们的防火墙。由于这个静态防火墙规则很容易被利用,因此需要一个更安全的动态方法。幸好,iptables 和内核 2.4 提供了启用动态、有状态过滤所需要的一切条件。
与其在基于静态协议特征的防火墙上开一个洞,还不如使用 Linux 新的连接跟踪功能来使防火墙根据包的动态连接状态做出判定。conntrack 通过将每个包与一个独立的双向通信信道或连接相关联来进行判定。
例如,设想一下,当使用 Telnet 或 ssh 连接远程机器时会发生什么情况。如果查看包级的网络通信流,您所看到的许多包从一台机器传递到另一台机器。但是,从更高级别的角度看,这种包交换是您的本地机器与远程机器之间的双向通信信道。传统(过时)的防火墙只看到独立的包,并没有看出它们实际上是一个更大的整体(连接)的一部分。
conntrack 内幕
那正是产生连接跟踪技术的原因。Linux 的 conntrack 功能可以“看到”正在发生的更高级别的连接,从而将 ssh 会话看作是单一的逻辑实体。conntrack 甚至可以将 UDP 和 ICMP 包交换看作是逻辑“连接”,即使 UDP 和 ICMP 实际上是非连接方式;这是非常有用的,因为它可以让我们使用 conntrack 来处理 ICMP 和 UDP 包交换。
如果已经重新启动,并且正在使用支持 netfilter 的新内核,那么通过输入 "cat /proc/net/ip_conntrack" 可以查看您的机器参与的活动网络连接。即使没有配置防火墙,Linux 的 conntrack 功能也可以在幕后工作,跟踪您的机器参与的连接。
NEW 连接状态,第 1 部分
conntrack 不仅能识别连接,它还可以将它看到的包分成四种连接状态。我们将要讨论的第一种状态叫作 NEW。输入 "ssh remote.host.com" 时,初始包或源自于您的机器并要发送到 remote.host.com 的包都处于 NEW 状态。但是,即使只从 remote.host.com 接收到一个应答包,那么就立即不再将其它作为此连接的一部分、发送至 remote.host.com 的包看作是 NEW 包。因此,只有在建立新连接、并且还没有从远程主机接收到通信流时使用的包才被看作是 NEW(当然,这个包是此特定连接的一部分)。
NEW 连接状态,第 2 部分
我们已经描述了外出 NEW 包,但还有可能会有进入 NEW 包(很常见)。进入 NEW 包通常来自远程机器,在启动与您的连接时使用。您的 Web 服务器接收到的初始包(作为 HTTP 请求的一部分)将被看作是进入 NEW 包;但是,只要您应答了一个进入 NEW 包,所接收到的与此特定连接相关的其它包都不再被看作是处于 NEW 状态。
ESTABLISHED 状态
一旦连接看到两个方向上都有通信流,与此附加相关的其它包都被看作处于 ESTABLISHED 状态。NEW 和 ESTABLISHED 之间的区别很重要,我们稍后将做讨论。
RELATED 状态
第三种连接状态类别叫作 RELATED。RELATED 包是那些启动新连接,但有与当前现有连接相关的包。RELATED 状态可以用于调整组成多重连接协议(如 ftp)的连接,以及与现有连接相关的错误包(如与现有连接相关的 ICMP 错误包)。
INVALID 状态
最后是 INVALID 包 -- 那些包不能归入以上三种类别。应当注意某个包是否被看作是 INVALID,因为这种包不会被自动废弃;因此您需要插入适当的规则,并设置链策略,以便可以正确处理这些包。
添加有状态规则
好,我们已经掌握了连接跟踪,现在来看一下能够使这个没有功能的防火墙变得非常有用的一个附加规则:
iptables -P INPUT DROP
iptables -A INPUT -i ! eth1 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
规则如何工作
当输入到现有 INPUT 链的末端时,这个单一规则可以让我们建立与远程机器的连接。其工作方式如下。假设我们要 ssh 到 remote.host.com。输入 "ssh remote.host.com" 之后,我们的机器发送出一个包来启动连接。这个特定包处于 NEW 状态,防火墙允许它外出,因为我们只阻拦进入防火墙的包,而不是外出的。
当收到来自 remote.host.com 的应答包时,这个包沿着我们的 INPUT 链流动。它不匹配第一个规则(因为它来自 eth1),因此它继续移动到下一个,也是最后的规则。如果它匹配此规则,则接受它,如果不匹配,则它会落到 INPUT 链的末端,并对它应用缺省策略 (DROP)。那么,这个进入应答包会被接受,还是会落到底呢?
规则如何工作,续
答:被接受。当内核检查这个进入包时,它首先认出这个包是现有连接的一部分。然后,内核需要判定这是 NEW 还是 ESTABLISHED 包。由于这是个进入包,它查看这个连接是否有外出通信流,结果发现有外出通信流(我们发送的初始 NEW 包)。因此,这个进入包被归入 ESTABLISHED 类,就象其它接收到或发送的与此连接关联的包。
进入 NEW 包
现在,考虑一下如果远程机器上的某个人尝试 ssh 到我们的机器,会发生什么情况。我们接收到的初始包属于 NEW 类,它不匹配规则 1,因此它前进到规则 2。由于这个包处于 ESTABLISHED 或 RELATED 状态,它将跌落到 INPUT 链的末端,于是将对它应用缺省策略 DROP。进入 ssh 连接请求将被删除,而且没有我们的应答(或 TCP 复位)。
几乎完美的防火墙
那么,目前我们的防火墙怎么样?如果您不要因特网上的任何人与您连接,但又需要连接到因特网上的站点,那么此防火墙非常适用于膝上型计算机或工作站。您可以使用 Netscape、konqueror、ftp、ping,执行 DNS 查找及更多操作。您启动的任何连接都将返回到防火墙。但是,任何来自因特网的未经请求的连接都将被删除,除非它与您启动的现有连接相关。只要不需要对外提供任何网络服务系统,那么它就是个几乎完美的防火墙。
基本防火墙脚本
以下是一个简单脚本,它可以用于建立/拆毁第一个基本工作站防火墙:
#!/bin/bash # A basic stateful firewall for a workstation or laptop that isn't running any # network services like a web server, SMTP server, ftp server, etc. if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! eth1 -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT fi
使用脚本
如果使用这个脚本,可以通过输入 "./firewall stop" 来停止防火墙,通过输入 "./firewall start" 再启动它。如果要停止防火墙,使用 "iptables -F INPUT" 将规则清除处 INPUT 链,然后使用 "iptables -P INPUT ACCEPT" 命令使缺省 INPUT 策略切换回 ACCEPT。现在来看一下可以对现有工作站防火墙进行的一些改进。在我说明了所有改进之后,我将向您显示最后的工作站防火墙脚本。然后,就开始为服务器定制防火墙。
明确关闭 ECN
我以前提到过应当关闭 ECN(明确拥塞通知),以便因特网通信可以正确工作。虽然您可能会按我的建议禁用了 ECN,但在将来您也许会忘了这样做。或者,您可能将防火墙脚本传送给某个人,而那个人启用了 ECN。由于这些原因,最好使用 /proc 接口来明确禁用 ECN,如下所示:
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
转发
如果使用 Linux 机器作为路由器,那么应该启用 IP 转发,它给予内核许可权,以允许包在 eth0 和 eth1 之间传递,反之亦然。在我们的配置示例中,eth0 连接到 LAN,eth1 连接到因特网,在允许 LAN 经由 Linux 机器连接因特网时,启用 IP 转发是必要步骤。要启用 IP 转发,请使用以下这行命令:
echo 1 > /proc/sys/net/ipv4/ip_forward
处理拒绝,第 1 部分
目前,我们已经删除了所有来自因特网的未经请求的通信流。虽然这是一种阻止讨厌的网络活动的有效方法,但是它有一些缺点。这种方法最大的问题是闯入者很容易就可以检测到我们正在使用防火墙,因为我们的机器没有应答标准 TCP 复位和 ICMP 端口不可到达响应 -- 一般机器发送会的响应,用于表示对不存在服务的连接失败。
处理拒绝,第 2 部分
与其让潜在的闯入者知道我们在运行防火墙(对于在提示他们,我们正在运行一些他们不能得到的有价值服务),还不如假装我们根本没有运行服务。通过将以下两个规则添加到 INPUT 链的末端,可以成功地完成此项任务:
iptables -A INPUT -p tcp -i eth1 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i eth1 -j REJECT --reject-with icmp-port-unreachable
第一个规则负责正确传递 TCP 连接,而第二个规则处理 UDP。只要这两个规则就位,闯入者就很难检测到我们运行了防火墙;但愿,这会使闯入者离开我们的机器,转而搜索其它更潜在的目标以供他滥用。
处理拒绝,第 3 部分
除了使防火墙变得更“隐蔽”,这些规则还消除了由于连接到某些 ftp 和 irc 服务器带来的延迟。这个延迟是由于服务器对您的机器执行身份查找(连接到端口 113)而引起的,并最终(大约 15 秒之后)导致超时。现在,防火墙将返回 TCP 复位,身份查找将立即失败,而不是重试 15 秒(而您正在耐心地等待服务器的响应)。
防止欺骗
在许多发行版中,当建成网络接口时,还会将旧的 ipchains 规则添加到系统。这些特殊规则是由发行版的创建程序添加的,用于处理电子欺骗问题,即包的源地址已经过调整,这样它们就包含了无效值(某些脚本骗子做的事)。虽然我们可以创建类似的 iptables 规则来阻拦受到欺骗的包,但还有一种更简单的方法。目前,内核的内置功能可以删除受到欺骗的包;我们要做的只是通过简单的 /proc 接口来启用它。方法如下。
防止欺骗,续
for x in lo eth0 eth1
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
此 shell 脚本将告诉内核删除接口 lo、eth0 和 eth1 上所有受到欺骗的包。可以将这些行添加到防火墙脚本中,也可以将它们添加到创建 lo、eth0 和 eth1 接口的脚本中。
伪装
NAT(网络地址转换)和 IP 伪装虽然与防火墙没有直接关系,但通常与防火墙一起使用。我们将讨论您可能需要使用的两种常用 NAT/伪装配置。第一个规则负责处理那种用拨号链接到使用动态 IP 的因特网 (ppp0) 的情况:
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
如果您属于这种情况,那么还应该转换防火墙脚本,将对 "eth1"(我们的示例 DSL 路由器)更改成 "ppp0"。如果 ppp0 还不存在,最好添加引用 "ppp0" 的防火墙规则。只要创建了 ppp0,一切立即就会正常工作。 请确保还启用了 IP 转发。
SNAT
如果使用 DSL 来连接因特网,那么您或许有两种可能配置中的一种。一种可能性是 DSL 路由器或调制解调器有其自己的 IP 号码,并为您执行网络地址转换。如果是这种情况,那么就不需要 Linux 来执行 NAT,因为 DSL 路由器已经这样处理了。
但是,如果想要更多地控制 NAT 功能,也许应该与 ISP 讨论关于 DSL 连接的配置,以便使您的 DSL 连接处于“桥接方式”。在桥接方式中,防火墙将成为 ISP 的网络中的正式部分,DSL 路由器将会在 ISP 和您的 Linux 机器之间透明的来回转发 IP 通信流,而不会让任何人知道它的存在。它不再拥有 IP 号码;事实上,eth1(在我们的示例中)隐藏了 IP。如果有人从因特网上 ping 您的 IP,他们将从您的 Linux 机器上得到应答,而不是路由器。
SNAT,续
使用了这种设置,就应该使用 NAT(源 NAT),而不是伪装。以下就是您应该添加到防火墙的一行代码:
iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 1.2.3.4
在这个示例中,应该将 eth1 更改成直接连接到 DSL 路由器的以太网接口,1.2.3.4 应该更改成静态 IP(以太网接口的 IP)。再次声明,请记住要启用 IP 转发。
NAT 问题
幸好,NAT 和伪装与防火墙能够和睦相处。在编写防火墙过滤规则时,应忽略正在使用 NAT 的事实。您的规则应该根据包的“真正”源地址和目的地址接受、删除或拒绝它们。防火墙过滤代码能够看到包的原始源地址,以及最终目的地址。这对我们很有用处,因为它可以让防火墙继续正常工作,即使我们暂时禁用了 NAT 或伪装。
了解表
在以上的 NAT/伪装示例中,我们将规则附加到链,但还做了一些略有不同的事。请注意 "-t" 选项。"-t" 选项可以让我们指定链所属的表。当省略这个选项时,缺省表将缺省为 "filter"。因此,以前所有与非 NAT 相关的命令修改 "filter" 表中的 INPUT 链。"filter" 表包含了所有与接收或拒绝包相关的规则,而 "nat" 表(如您假设的)包含了与网络地址转换相关的规则。还有其它内置 iptables 链,在 iptables 帮助页面以及 Rusty 的 HOWTO(请参阅本教程结尾处的“参考资料”部分,以获取链接)中详细描述了这些链。
增强的脚本
现在已经讨论过一些可能的增强,让我们看一下第二种更灵活的防火墙启动/停止脚本:
#!/bin/bash # An enhanced stateful firewall for a workstation, laptop or router that isn't # running any network services like a web server, SMTP server, ftp server, etc. #change this to the name of the interface that provides your "uplink" #(connection to the Internet) UPLINK="eth1" #if you're a router (and thus should forward IP packets between interfaces), #you want ROUTER="yes"; otherwise, ROUTER="no" ROUTER="yes" #change this next line to the static IP of your uplink interface for static SNAT, or #"dynamic" if you have a dynamic IP. If you don't need any NAT, set NAT to "" to #disable it. NAT="1.2.3.4" #change this next line so it lists all your network interfaces, including lo INTERFACES="lo eth0 eth1" if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable #explicitly disable ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi #disable spoofing on all interfaces for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then #we're a router of some kind, enable IP forwarding echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then #dynamic IP address, use masquerading echo "Enabling masquerading (dynamic ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then #static IP, use SNAT echo "Enabling SNAT (static ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT #turn off NAT/masquerading, if any iptables -t nat -F POSTROUTING fi
查看规则
在开始定制防火墙以便可以在服务器上使用它之前,我需要演示如何列出当前活动的防火墙规则。要查看过滤器表的 INPUT 链中的规则,输入:
# iptables -v -L INPUT
-v 选项给出一个冗长的输出,这样我们可以查看每个规则传送的总包数和总的字节数。还可以使用以下命令查看 nat POSTROUTING 表:
# iptables -t nat -v -L POSTROUTING
Chain POSTROUTING (policy ACCEPT 399 packets, 48418 bytes)
pkts bytes target prot opt in out source destination
2728 170K SNAT all -- any eth1 anywhere anywhere to:215.218.215.2
准备提供服务
现在,防火墙不允许陌生人连接我们机器上的服务,因为它只接受进入 ESTABLISHED 或 RELATED 包。由于它删除了所有进入 NEW 包,因此所有连接尝试都将被无条件拒绝。但是,只要有选择地允许一些进入通信流通过防火墙,我们就可以让陌生人连接到我们指定的服务。
有状态 HTTP
虽然我们要接受一些进入连接,但我们可能并不想接受所有进入连接。最好从“缺省拒绝”策略开始(就象我们现在使用的策略),逐渐开放对那些希望人们可以连接的服务的访问。例如,如果正在运行 Web 服务器,我们允许 NEW 包进入我们的机器,只要它们去往端口 80 (HTTP)。那就是我们需要做的。一旦允许 NEW 包进入,那我们就允许建立连接。一旦建立了连接,就匹配了允许进入 ESTABLISHED 和 RELATED 包的现有规则,从而 HTTP 连接将变得畅通无阻。
有状态 HTTP 示例
让我们看一下防火墙的“核心”,以及允许进入 HTTP 连接的新规则:
iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #our new rule follows iptables -A INPUT -p tcp --dport http -m state --state NEW -j ACCEPT iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable
这个新规则允许去往我们机器的端口 80 (http) 的 NEW TCP 包进入。请注意这个规则的位置。它出现在 REJECT 规则有重要意义。由于 iptables 将应用第一个匹配的规则,因此将它放到 REJECT 行的后面会使这个规则无法生效。
最后的防火墙脚本
现在来看一下最后的防火墙脚本,它可以用于膝上型计算机、工作站、路由器或服务器(或者其中的某些组合!)。
#!/bin/bash #Our complete stateful firewall script. This firewall can be customized for #a laptop, workstation, router or even a server. #change this to the name of the interface that provides your "uplink" #(connection to the Internet) UPLINK="eth1" #if you're a router (and thus should forward IP packets between interfaces), #you want ROUTER="yes"; otherwise, ROUTER="no" ROUTER="yes" #change this next line to the static IP of your uplink interface for static SNAT, or #"dynamic" if you have a dynamic IP. If you don't need any NAT, set NAT to "" to #disable it. NAT="1.2.3.4" #change this next line so it lists all your network interfaces, including lo INTERFACES="lo eth0 eth1" #change this line so that it lists the assigned numbers or symbolic names (from #/etc/services) of all the services that you'd like to provide to the general #public. If you don't want any services enabled, set it to "" SERVICES="http ftp smtp ssh rsync" if [ "$1" = "start" ] then echo "Starting firewall..." iptables -P INPUT DROP iptables -A INPUT -i ! ${UPLINK} -j ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #enable public access to certain services for x in ${SERVICES} do iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT done iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable #explicitly disable ECN if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi #disable spoofing on all interfaces for x in ${INTERFACES} do echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter done if [ "$ROUTER" = "yes" ] then #we're a router of some kind, enable IP forwarding echo 1 > /proc/sys/net/ipv4/ip_forward if [ "$NAT" = "dynamic" ] then #dynamic IP address, use masquerading echo "Enabling masquerading (dynamic ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE elif [ "$NAT" != "" ] then #static IP, use SNAT echo "Enabling SNAT (static ip)..." iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP} fi fi elif [ "$1" = "stop" ] then echo "Stopping firewall..." iptables -F INPUT iptables -P INPUT ACCEPT #turn off NAT/masquerading, if any iptables -t nat -F POSTROUTING fi
服务器改进
通常可以使防火墙变得“更好”一点。当然,是不是“更好”要根据各人的特殊需要而定。现有脚本可能会完全符合您的要求,但也可能需要进行附加调整。本章节旨在充当各种想法的食谱,演示增强现有有状态防火墙的各种方法。
记录技术
目前,我们还没有讨论如何记录。有一种特殊目标 LOG 可以用于记录事物。在使用 LOG 时,有一个特殊选项 "--log-prefix" 可以让您指定在包转储到系统日志时出现的一些文本。以下是一个日志规则示例:
iptables -A INPUT -j LOG --log-prefix "bad input:"
不应将它作为第一个规则添加到 INPUT 链中,因为这将会为您接收的每个包都记录一个记录项。事实上,应该将日志规则放到 INPUT 链的底层,以便记录陌生的包和其它异常。
记录技术,续
以下是关于 LOG 目标的重要注意事项。通常,当一条规则匹配时,会接受、拒绝或删除某个包,不会再处理其它规则。但是,当日志规则匹配时,则会记录这个包。但是却不会接受、拒绝或删除它。事实上,包会继续移动到下一个规则,如果日志规则是链中的最后一个规则,那么将应用缺省链策略。
LOG 目标还可以与 "limit" 模块组合(在 iptables 帮助页面中描述),以使重复记录项最小化。以下是一个示例:
iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute -j LOG --log-prefix "INVALID STATE:"
创建自己的链
iptables 可以让您创建自己的用户定义链,可以将这个链指定成规则中的目标。如果想要了解如何完成此项任务,请花一些时间阅读 Rusty 的著作 http://netfilter.samba.org/unreliable-guides/packet-filtering-HOWTO/index.html。
实施网络使用策略
对于那些想要对公司或高校 LAN 实施网络使用策略的人来说,火墙提供了许多强大的功能。通过将添加添加到 FORWARD 链或设置 FORWARD 的策略,可以控制您的机器将转发什么包。通过将规则添加到 OUTPUT 链,还可以对由 Linux 机器自身的用户在本地生成的包采取什么操作。iptables 还有难以置信的能力,它可以根据所有者(uid 或 gid)来过滤本地创建的包。如需有关此项功能的详细信息,请在 iptables 帮助页面中搜索 "owner"。
其它安全性角落
在示例防火墙中,我们已经假设所有内部 LAN 通信流都是值得信任的,只有进入因特网通信流必须受到严格监控。您的特定网络可能属于这种情况,也可以不属于此类情况。当然没有什么事能阻止您配置防火墙,以防止进入 LAN 通信流。需要考虑您想要保护的网络的其它“角落”。还应适当配置两个 LAN 安全性“专区”,每个“专区”都有其自己的安全性策略。
tcpdump
在本章节中,我将介绍许多参考资料,您会发现这些参考资料有助于创建自己的有状态防火墙。让我们从一个重要工具开始……
tcpdump 是研究低级包交换和验证防火墙是否正常工作的必备工具。如果您还没有,想方法弄到它。如果已经有了,则应该使用它。
netfilter.kernelnotes.org
http://netfilter.samba.org 是 netfilter 小组的主页。这个页面上有许多优秀的参考资料,包括 iptables 源码,以及 Rusty 的著作 "unreliable guides"。这些参考资料包括适用于开发人员的基本网络概念 HOWTO、netfilter (iptables) HOWTO、NAT HOWTO 和 netfilter 破坏 HOWTO。 此外还有 netfilter FAQ 和其它内容