Linux 的大多数方面都在不断发展,以满足用户日益增长的需求;IP 防火墙也不例外。传统的 IP 防火墙实现对于大多数应用来说已经足够好,但在配置复杂环境时可能会显得笨拙且效率低下。为了解决这个问题,开发了一种配置 IP 防火墙和相关功能的新方法。这种新方法被称为“IP 防火墙链”,并在 2.2.0 Linux 内核中首次发布供通用使用。
IP 防火墙链支持由 Paul Russell 和 Michael Neuling 开发。[1] Paul 在 IPCHAINS-HOWTO 中记录了 IP 防火墙链软件。
IP 防火墙链允许您开发防火墙规则类,然后您可以向其中添加和删除主机或网络。防火墙规则链接的一个优点是,它可以提高具有大量规则的配置中的防火墙性能。
IP 防火墙链受 2.2 系列内核支持,也可作为针对 2.0.* 内核的补丁提供。HOWTO 描述了在哪里获取补丁,并提供了许多关于如何有效使用 ipchains 配置实用程序的有用提示。
您可以通过两种方式使用 ipchains 实用程序。第一种方式是使用 ipfwadm-wrapper shell 脚本,它主要是 ipfwadm 的直接替代品,在后台驱动 ipchains 程序。如果您想这样做,请不要再往下读。相反,请重新阅读前面描述 ipfwadm 的章节,并将 ipfwadm-wrapper 替换为它的位置。这会起作用,但不能保证该脚本会被维护,并且您将无法利用 IP 防火墙链提供的任何高级功能。
使用 ipchains 的第二种方式是学习它的新语法,并修改您现有的任何配置,以使用新语法而不是旧语法。通过一些仔细的考虑,您可能会发现在转换时可以优化您的配置。ipchains 语法比 ipfwadm 更容易学习,所以这是一个不错的选择。
ipfwadm 操作三个规则集以用于配置防火墙。使用 IP 防火墙链,您可以创建任意数量的规则集,每个规则集彼此链接,但始终存在三个与防火墙相关的规则集。标准规则集与 ipfwadm 使用的规则集直接等效,只是它们有名称input, forward和output.
让我们首先看一下 ipchains 命令的通用语法,然后我们将看看如何在不担心任何高级链接功能的情况下使用 ipchains 代替 ipfwadm。我们将通过回顾我们之前的示例来做到这一点。
ipchains 命令语法非常简单。我们现在来看看其中最重要的那些。大多数 ipchains 命令的通用语法是
ipchains command rule-specification options |
我们可以使用 ipchains 命令以多种方式操作规则和规则集。与 IP 防火墙相关的有
将一个或多个规则附加到指定链的末尾。如果将主机名作为源或目标提供,并且它解析为多个 IP 地址,则将为每个地址添加一个规则。
将一个或多个规则插入到指定链的开头。同样,如果在规则规范中提供了主机名,则将为它解析的每个地址添加一个规则。
从指定的链中删除一个或多个与规则规范匹配的规则。
删除位于位置rulenum在指定链中的规则。规则位置从链中第一个规则的 1 开始。
将位于位置rulenum在特定链中的规则替换为提供的规则规范。
根据特定链检查规则规范描述的数据报。此命令将返回一条消息,描述数据报如何被链处理。这对于测试您的防火墙配置非常有用,我们稍后会详细介绍它。
列出指定链的规则,如果未指定链,则列出所有链的规则。
清除指定链的规则,如果未指定链,则清除所有链的规则。
将指定链的所有规则的数据报和字节计数器归零,如果未指定链,则将所有链的计数器归零。
使用指定的名称创建新链。同名的链不得已存在。这是创建用户定义链的方式。
删除指定的用户定义链,如果未指定链,则删除所有用户定义链。要使此命令成功,必须没有从任何其他规则链对指定链的引用。
将指定链的默认策略设置为指定的策略。有效的防火墙策略是ACCEPT, DENY, REJECT, REDIR,或RETURN. ACCEPT, DENY,和REJECT与传统 IP 防火墙实现的含义相同。REDIR指定应将数据报透明地重定向到防火墙主机上的端口。RETURNRETURN 目标导致 IP 防火墙代码返回到调用包含此规则的防火墙链,并从调用规则之后的规则开始继续。
许多 ipchains 参数通过确定哪些类型的数据包匹配来创建规则规范。如果从规则规范中省略了任何这些参数,则假定为其默认值
指定将与此规则匹配的数据报的协议。有效的协议名称是tcp, udp, icmp,或all。您还可以在此处指定协议号以匹配其他协议。例如,您可以使用4来匹配ipip封装协议。如果提供了!!,则规则被否定,数据报将匹配除指定协议之外的任何协议。如果未提供此参数,则默认为all.
指定将与此规则匹配的数据报的源地址和端口。地址可以作为主机名、网络名或 IP 地址提供。可选的mask是要使用的网络掩码,可以以传统形式(例如,/255.255.255.0)或现代形式(例如,/24)提供。可选的port指定将匹配的 TCP 或 UDP 端口,或 ICMP 数据报类型。只有在您提供了带有其中一个-p参数的情况下,您才可以提供端口规范。tcp, udp,或icmp协议。端口可以指定为范围,方法是用冒号作为分隔符指定范围的上限和下限。例如,20:25描述了从 20 到 25(包括 25)的所有端口。同样,!! 字符可以用于否定值。
指定将与此规则匹配的数据报的目标地址和端口。此参数的编码与-s参数相同。
指定当此规则匹配时要采取的动作。您可以将此参数理解为“跳转到”。有效的目标是ACCEPT, DENY, REJECT, REDIR,和RETURN。ACCEPT,DENY,REJECT,REDIR,RETURN 或用户定义的链的名称。我们之前描述了每个目标的含义。但是,您也可以指定用户定义链的名称,处理将在其中继续。如果省略此参数,则对匹配规则的数据报不采取任何操作,除了更新数据报和字节计数器。
指定数据报在其上接收或将要传输的接口。同样,!! 反转匹配的结果。如果接口名称以++ 结尾,则任何以提供的字符串开头的接口都将匹配。例如,-i ppp+将匹配任何 PPP 网络设备,并且-i ! eth+将匹配除以太网设备之外的所有接口。
指定此规则适用于除分片数据报的第一个分片之外的所有内容。
以下 ipchains 选项在性质上更通用。其中一些控制 IP 链软件的相当深奥的功能
使命令生成两个规则。一个规则匹配提供的参数,另一个添加的规则匹配相反方向的对应参数。
使 ipchains 在其输出中变得冗长。它将提供更多信息。
使 ipchains 将 IP 地址和端口显示为数字,而不尝试将它们解析为其对应的名称。
启用内核记录匹配数据报。任何匹配该规则的数据报都将由内核使用其printk()函数记录,该函数通常由 sysklogd 程序处理并写入日志文件。这对于使不寻常的数据报可见很有用。
使 IP 链软件将任何匹配规则的数据报复制到用户空间“netlink”设备。 maxsize 参数限制了从每个数据报传递到 netlink 设备的字节数。此选项对软件开发人员最有用,但将来可能会被软件包利用。
使匹配的数据报被标记一个值。标记值是 32 位无符号数字。在现有实现中,这没有任何作用,但在将来的某个时候,它可能会决定数据报如何被其他软件(如路由代码)处理。如果 markvalue 以++ 或-- 开头,则该值将添加到或从现有 markvalue 中减去。
使您能够操作与此规则匹配的任何数据报的 IP 标头中的“服务类型”位。服务类型位被智能路由器用于在转发数据报之前对其进行优先级排序。 Linux 路由软件能够进行这种优先级排序。andmask 和andmask和xormask分别表示将与数据报的服务类型位进行逻辑 AND 和 OR 运算的位掩码。这是一个高级功能,在 IPCHAINS-HOWTO 中有更详细的讨论。
使 ipchains 输出中的任何数字都扩展到其确切值,而没有舍入。
使规则匹配任何设置了 SYN 位且清除了 ACK 和 FIN 位的 TCP 数据报。这用于过滤 TCP 连接请求。
让我们再次假设我们在我们的组织中有一个网络,并且我们正在使用基于 Linux 的防火墙机器来允许我们的用户访问 Internet 上的 WWW 服务器,但不允许传递任何其他流量。
如果我们的网络具有 24 位网络掩码(C 类)并且地址为 172.16.1.0,我们将使用以下 ipchains 规则
# ipchains -F forward # ipchains -P forward DENY # ipchains -A forward -s 0/0 80 -d 172.16.1.0/24 -p tcp -y -j DENY # ipchains -A forward -s 172.16.1.0/24 -d 0/0 80 -p tcp -b -j ACCEPT |
这些命令中的第一个命令清除input、output 和 forward 规则集中的所有规则,第二组命令将 input、output 和 forward 规则集的默认策略设置为 DENY。最后,第三和第四个命令执行我们想要的特定过滤。第四个命令允许进出我们网络外部的 Web 服务器的数据报通过,第三个命令阻止源端口为 80 的传入 TCP 连接。forward规则集和第二组命令设置forward规则集为DENYDENY。最后,第三和第四个命令执行我们想要的特定过滤。第四个命令允许进出我们网络外部的 Web 服务器的数据报通过,第三个命令阻止源端口为 80 的传入 TCP 连接。
如果我们现在想要添加允许仅被动模式访问外部网络中 FTP 服务器的规则,我们将添加这些规则
# ipchains -A forward -s 0/0 20 -d 172.16.1.0/24 -p tcp -y -j DENY # ipchains -A forward -s 172.16.1.0/24 -d 0/0 20 -p tcp -b -j ACCEPT # ipchains -A forward -s 0/0 21 -d 172.16.1.0/24 -p tcp -y -j DENY # ipchains -A forward -s 172.16.1.0/24 -d 0/0 21 -p tcp -b -j ACCEPT |
要使用 ipchains 列出我们的规则,我们使用它的-L参数。就像 ipfwadm 一样,有一些参数可以控制输出中的详细程度。在其最简单的形式中,ipchains 生成的输出看起来像
# ipchains -L -n Chain input (policy ACCEPT): Chain forward (policy DENY): target prot opt source destination ports DENY tcp -y---- 0.0.0.0/0 172.16.1.0/24 80 -> * ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 80 ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 80 -> * ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 20 ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 20 -> * ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 21 ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 21 -> * Chain output (policy ACCEPT): |
如果您不提供要列出的链的名称,ipchains 将列出所有链中的所有规则。我们示例中的 -n 参数告诉 ipchains 不要尝试将任何地址或端口转换为名称。呈现的信息应该是自我解释的。-n参数告诉 ipchains 不要尝试将任何地址或端口转换为名称。呈现的信息应该是自我解释的。
通过 -v-u选项调用的详细形式提供了更多细节。它的输出添加了数据报和字节计数器、服务类型 AND 和 XOR 标志、接口名称、标记和输出大小字段。
使用 ipchains 创建的所有规则都具有与之关联的数据报和字节计数器。这就是 IP 记帐的实现方式,将在第 10 章中详细讨论。默认情况下,这些计数器以四舍五入的形式呈现,使用后缀K和M分别表示一千和一百万的单位。如果提供了 -x-x参数,则计数器将扩展到其完整的未舍入形式。
您现在知道 ipchains 命令是 ipfwadm 的替代品,它具有更简单的命令行语法和一些有趣的增强功能,但您无疑想知道在哪里可以使用用户定义的链以及为什么。您可能还想知道如何使用 ipchains 命令在其软件包中附带的支持脚本。我们现在将探讨这些主题并解答这些问题。
传统 IP 防火墙代码的三个规则集为构建防火墙配置提供了一种机制,对于具有简单防火墙要求的小型网络来说,这种配置相当容易理解和管理。当配置要求不简单时,许多问题变得显而易见。首先,大型网络通常需要的防火墙规则比我们迄今为止看到的要多得多;不可避免地会出现需要添加防火墙规则以涵盖特殊情况的场景。随着规则数量的增长,防火墙的性能会随着对每个数据报进行越来越多的测试而降低,并且可管理性成为一个问题。其次,无法原子地启用和禁用规则集;相反,您在重建规则集的过程中被迫暴露于攻击之下。
IP 防火墙链的设计通过允许网络管理员创建任意规则集来帮助缓解这些问题,我们可以将这些规则集链接到三个内置规则集。我们可以使用 ipchains 的 -N-N选项来创建一个新的链,名称可以是任何不超过八个字符的名称。(将名称限制为仅小写字母可能是一个好主意。) -j-j选项配置当数据报与规则规范匹配时要采取的动作。 -j-j选项指定,如果数据报与规则匹配,则应针对用户定义的链执行进一步的测试。我们将用图表来说明这一点。
考虑以下 ipchains 命令
ipchains -P input DENY ipchains -N tcpin ipchains -A tcpin -s ! 172.16.0.0/16 ipchains -A tcpin -p tcp -d 172.16.0.0/16 ssh -j ACCEPT ipchains -A tcpin -p tcp -d 172.16.0.0/16 www -j ACCEPT ipchains -A input -p tcp -j tcpin ipchains -A input -p all |
我们将默认输入链策略设置为 denydeny。第二个命令创建一个名为“tcpin”的用户定义链。第三个命令向 tcpintcpin链添加一个规则,该规则匹配任何来自本地网络外部的数据报;该规则不采取任何操作。此规则是一个记帐规则,将在第 10 章中更详细地讨论。接下来的两个规则匹配任何目标为本地网络且为 ssh 或 wwwssh+ 或www端口的数据报;匹配这些规则的数据报被接受。下一个规则是真正的 ipchains 魔力开始的地方。它使防火墙软件针对 tcpin 用户定义的链检查任何协议为 TCP 的数据报。最后,我们向我们的 inputinput链添加一个规则,该规则匹配任何数据报;这是另一个记帐规则。它们将产生如图 9-4 所示的防火墙链。
我们的 input 和 tcpininput和tcpin链填充了我们的规则。数据报处理始终从内置链之一开始。我们将通过跟踪不同类型数据报的处理路径来了解我们的用户定义链是如何被调用的。
首先,让我们看看当接收到发往我们主机之一的 UDP 数据报时会发生什么。图 9-5 说明了规则的流程。
数据报由 inputinput链接收,并穿过前两个规则,因为它们分别匹配 ICMP 和 TCP 协议。它匹配 inputinput链中的第三个规则,但它没有指定目标,因此它的数据报和字节计数器被更新,但没有发生其他操作。数据报到达 inputinput链的末尾,遇到默认的 inputinput链策略,并被拒绝。
为了查看我们的用户定义链的运行情况,现在让我们考虑当我们接收到目标为我们主机之一的 sshssh端口的 TCP 数据报时会发生什么。图 9-6 显示了该顺序。
这一次,inputinput链中的第二个规则确实匹配,并且它指定了 tcpintcpin目标,我们的用户定义链。将用户定义的链指定为目标会导致针对该链中的规则测试数据报,因此下一个测试的规则是 tcpintcpin链中的第一个规则。第一个规则匹配任何源地址在我们本地网络之外的数据报,并且没有指定目标,因此它也是一个记帐规则,测试会落入下一个规则。我们 tcpintcpin链中的第二个规则确实匹配,并指定了 ACCEPTACCEPT目标。我们已经到达目标,因此不再进行防火墙处理。数据报被接受。
最后,让我们看看当我们到达用户定义链的末尾时会发生什么。为了看到这一点,我们将映射目标端口不是我们专门处理的两个端口之一的 TCP 数据报的流程,如图 图 9-7 所示。
用户定义的链没有默认策略。当用户定义链中的所有规则都已测试,并且没有一个匹配时,防火墙代码的行为就好像存在 RETURNRETURN规则一样,因此如果这不是您想要的,您应该确保在用户定义链的末尾提供一个规则,该规则采取您希望的任何操作。在我们的示例中,我们的测试返回到 inputinput规则集中紧随其后将我们移动到用户定义链的规则。最终我们到达 inputinput链的末尾,它确实有一个默认策略,我们的数据报被拒绝。
这个例子非常简单,但说明了我们的观点。更实际的 IP 链使用会复杂得多。以下命令列表提供了一个稍微更复杂的示例
# # Set default forwarding policy to REJECT ipchains -P forward REJECT # # create our user-defined chains ipchains -N sshin ipchains -N sshout ipchains -N wwwin ipchains -N wwwout # # Ensure we reject connections coming the wrong way ipchains -A wwwin -p tcp -s 172.16.0.0/16 -y -j REJECT ipchains -A wwwout -p tcp -d 172.16.0.0/16 -y -j REJECT ipchains -A sshin -p tcp -s 172.16.0.0/16 -y -j REJECT ipchains -A sshout -p tcp -d 172.16.0.0/16 -y -j REJECT # # Ensure that anything reaching the end of a user-defined chain is rejected. ipchains -A sshin -j REJECT ipchains -A sshout -j REJECT ipchains -A wwwin -j REJECT ipchains -A wwwout -j REJECT # # divert www and ssh services to the relevant user-defined chain ipchains -A forward -p tcp -d 172.16.0.0/16 ssh -b -j sshin ipchains -A forward -p tcp -s 172.16.0.0/16 -d 0/0 ssh -b -j sshout ipchains -A forward -p tcp -d 172.16.0.0/16 www -b -j wwwin ipchains -A forward -p tcp -s 172.16.0.0/16 -d 0/0 www -b -j wwwout # # Insert our rules to match hosts at position two in our user-defined chains. ipchains -I wwwin 2 -d 172.16.1.2 -b -j ACCEPT ipchains -I wwwout 2 -s 172.16.1.0/24 -b -j ACCEPT ipchains -I sshin 2 -d 172.16.1.4 -b -j ACCEPT ipchains -I sshout 2 -s 172.16.1.4 -b -j ACCEPT ipchains -I sshout 2 -s 172.16.1.6 -b -j ACCEPT # |
在此示例中,我们使用了用户定义的链的选择,以简化防火墙配置的管理并提高防火墙的效率,与仅涉及内置链的解决方案相比。
我们的示例为每个 www 和 sshssh和www服务在每个连接方向上创建用户定义的链。名为 wwwoutwwwout的链是我们放置允许进行出站万维网连接的主机的规则的地方,而 sshinsshin是我们定义我们想要允许入站 ssh 连接的主机的规则的地方。我们假设我们需要允许和拒绝我们网络上的单个主机进行或接收 www 和 sshssh和www连接。简化是因为用户定义的链允许我们整齐地将主机入站和出站权限的规则分组,而不是将它们全部混在一起。效率的提高是因为对于任何特定的数据报,我们减少了在找到目标之前所需的平均测试次数。效率增益随着我们添加更多主机而增加。如果我们没有使用用户定义的链,我们可能需要搜索整个规则列表以确定对接收到的每个数据报采取什么操作。即使我们假设我们列表中的每个规则都匹配总处理数据报的相等比例,我们平均仍然要搜索列表的一半。用户定义的链允许我们避免测试大量规则,如果被测试的数据报与跳转到它们的内置链中的简单规则不匹配。
ipchains 软件包随附三个支持脚本。第一个我们已经简要讨论过,而其余两个脚本提供了一种简单方便的方式来保存和恢复您的防火墙配置。
ipfwadm-wrapper 脚本模拟 ipfwadm 命令的命令行语法,但驱动 ipchains 命令来构建防火墙规则。这是将您现有的防火墙配置迁移到内核或学习 ipchains 语法的替代方案。ipfwadm-wrapper 脚本的行为与 ipfwadm 命令在两个方面有所不同:首先,由于 ipchains 命令不支持按地址指定接口,ipfwadm-wrapper 脚本接受 -V-V的参数,但尝试通过搜索配置了所提供地址的接口名称将其转换为 ipchains 等效的 -W-W。ipfwadm-wrapper 脚本在您使用 -V-V选项时始终会提供警告,以提醒您这一点。其次,分片记帐规则未正确转换。
ipchains-save 和 ipchains-restore 脚本使构建和修改防火墙配置更加简单。ipchains-save 命令读取当前的防火墙配置,并将简化形式写入标准输出。ipchains-restore 命令读取 ipchains-save 命令的输出格式的数据,并使用这些规则配置 IP 防火墙。使用这些脚本而不是直接修改防火墙配置文件并测试配置的优点是能够动态构建一次配置,然后保存它。然后您可以恢复该配置、修改它并随意重新保存它。
要使用这些脚本,您需要输入类似
ipchains-save >/var/state/ipchains/firewall.state |
ipchains-restore </var/state/ipchains/firewall.state |
ipchains-restore 脚本检查其输入中列出的任何用户定义的链是否已存在。如果您提供了 -f-f参数,它将在配置输入中的链之前自动清除用户定义链中的规则。默认行为是询问您是否跳过此链或清除它。
[1] | 可以通过 Paul.Russell@rustcorp.com.au 联系 Paul。 |