NAT 的自然演进
编者按:由于印刷错误,David Bandel 关于 iptables 构建的文章在杂志中不完整。我们在此完整呈现。
在 Netfilter 框架中,我们可用的最佳工具之一是 NAT(网络地址转换)。NAT 允许我们混淆(但不是隐藏)我们的真实网络,迫使潜在的黑客更加努力(并可能去寻找更容易的目标)。它还允许我们最大限度地利用有限的 IP 地址。上个月[参见 LJ 2002 年 5 月刊中的 “Netfilter 2:尽在掌握”],我们研究了扩展 iptables 以包含实验性或 beta 匹配和目标。本月,我们将研究如何正确地进行 NAT,更仔细地研究一两个其他匹配,然后看看构建 iptables 规则时一些更常见的错误是什么以及如何避免它们。
鉴于当今可用的 IPv4 地址短缺,您的 ISP 很可能没有为您提供足够的 IP 地址来运行所有系统。如果您幸运的话,您可能会得到超过六个可以实际使用的 IP 地址。但是如果您不使用它们,您将会失去它们。而且您不希望那样,否则明天就没有扩展空间了。因此,您将使您的防火墙看起来像您拥有尽可能多的 IP 地址可供使用的系统。如何做到这一点?最简单的方法是将所有 IP 地址分配给一个网卡(连接到您的 ISP 的那个),并对连接进行 SNAT(源网络地址转换),使它们看起来像是来自每个 IP 地址轮流(此示例假设您的内部网络是 192.168.0.0/24,它绑定到 eth1,而您的可用 IP 地址是 209.127.112.26-209.127.112.30,它们绑定到 eth0)
iptables -t nat -A POSTROUTING
-o eth0 -s
--to-source 209.127.112.26-209.127.112.30
现在 iptables 将第一个连接 NAT 到 .26,第二个连接到 .27,第三个连接到 .28,依此类推,在连接到 .30 之后绕回到 .26。
一个警告:在部署之前测试一下。我遇到过一个路由器,它不喜欢看到来自同一 MAC 地址的多个 IP 地址。它会通过第一个连接,但随后的连接会超时。路由器的内置防火墙(客户端无法关闭)很可能认为其他数据包是欺骗性的,并默默地丢弃了它们。
让我们确保我们接受所有传出连接,但只接受与这些传出连接相关的传入连接
iptables -t filter -A FORWARD -i ! eth0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t filter -A FORWARD -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -t filter -A FORWARD -i eth0 -m state --state NEW,INVALID -j DROP
现在我们已经管理了传出流量,让我们假设我们已将所有服务移到此防火墙内部。我们进一步假设它们都在 192.168.0.0/24 网络的 eth1 内部。每个服务都有两个与之关联的 IP 地址:世界看到的一个外部 IP 地址,以及我们看到的一个内部 IP 地址。具体来说,我们将分配以下地址
Apache Web 服务器(同时服务不安全和安全连接):209.127.112.26 和 192.168.0.4
FTP 服务器:209.127.112.27 和 192.168.0.5
主 DNS 服务器:209.127.112.26 和 192.168.0.6
辅助 DNS 服务器:209.127.112.28 和 192.168.0.7
主邮件服务器:209.127.112.28 和 192.168.0.8
辅助邮件服务器:209.127.112.29 和 192.168.0.9
由于我们上面的 iptables 状态表规则,每个服务(或更具体地说,与该服务对应的每个端口)不仅需要通过防火墙转发到正确的内部 IP 地址,而且我们需要一个规则来接受新的 NEW 流量。从 Apache 开始,在我们的例子中,它同时使用端口 80 和 443(用于 SSL),我们有
iptables -t filter -I FORWARD -i eth0 -d iptables -t nat -A PREROUTING -d -p tcp --dport 80 -j DNAT --to-destination iptables -t filter -I FORWARD -i eth0 -d 209.127.112.26 -p tcp --dport 443 -j ACCEPT iptables -t nat -A PREROUTING -d --dport 443 -j DNAT --to-destination 192.168.0.4
请注意,我们必须在 FORWARD 链中插入一个规则。这是因为我们已经有一个更通用的规则会丢弃 NEW 连接。我们可以在链中的任何位置插入规则,但是如果我们不指定位置,默认情况下会将其作为第一个规则插入。通常,这不会成为问题,并将使我们的特定规则位于我们的通用规则之前。
请注意,我们还指定了此连接应显示的 IP 地址。这不是必需的,因为在其他 IP 地址上显示的连接将由状态表处理并丢弃,除非我们做了一些非常可疑的事情并在我们的防火墙上启动了 Web 服务器。如果我们的防火墙上没有打开任何端口,我们就没问题。为了以防万一,我们可以通过确保我们对 INPUT 链也具有状态规则来保护它们
iptables -t filter -A INPUT -i ! eth0 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT iptables -t filter -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -t filter -A INPUT -i eth0 -m state --state NEW,INVALID -j DROP
上面的第一个规则允许来自 lo(本地主机接口)以及任何内部设备的 NEW、ESTABLISHED 和 RELATED 连接,仅省略了我们的外部设备,这在接下来的两个规则中处理。
接下来,我们看看 FTP 连接。这很简单,与上面的规则完全相同,但端口为 21
iptables -t filter -I FORWARD -i eth0 -p tcp
--dport 21 -j ACCEPT
iptables -t nat -A PREROUTING -i eth0
-d
--to-destination 192.168.0.5
我们不必担心 FTP 数据通道(端口 20),因为我们的 FTP 服务器会打开它传出,并且我们的状态规则将传递此新连接。
现在它变得有点困难了。DNS 在 UDP 上用于正常查询,在 TCP 上用于区域传输。如果我们不想允许向外进行区域传输,我们只打开 UDP。如果我们想允许区域传输,那么我们必须同时允许两者。假设我们想同时允许两者,我们知道我们可以将 UDP、TCP 或 ICMP 指定为协议。您必须指定 -p(协议)才能指定端口。如果您想要 UDP 和 TCP,您应该能够说 “not ICMP”,并且自动假定另外两个。不幸的是,它不是那样工作的。
当您指定协议时,即使您说 -p ! ICMP,加载的也是 ICMP 匹配模块,而不是 TCP 和 UDP 匹配模块。因此,当您指定端口时,您将收到错误消息。这是使用负面匹配的危险;加载的匹配模块是指定的模块,而不是您可能假设加载的模块。您必须肯定地指定您想要的每个匹配,以便加载相应的匹配模块。
现在,让我们假设您只对打开 UDP 端口感兴趣
iptables -t filter -I FORWARD -i eth0
-d
iptables -t nat -A POSTROUTING -i eth0
-d
--to-destination
iptables -t filter -I FORWARD -i eth0
-d
iptables -t nat -A POSTROUTING -i eth0
-d
--to-destination 192.168.0.8
最后,我们需要处理我们的邮件主机
iptables -t filter -I FORWARD -i eth0 -d 209.127.112.28 -i eth0 -p TCP --dport 25 -J ACCEPT iptables -t nat -A POSTROUTING -i eth0 -d --to-destination iptables -t filter -I FORWARD -i eth0 -d 209.127.112.29 -i eth0 -p UDP --dport 25 -J ACCEPT iptables -t nat -A POSTROUTING -i eth0 -d --to-destination 192.168.0.9我们现在可以接受传入邮件了。有人看到这里有问题吗?
如果我们使用 mail -v user@another.dom 测试我们的传出邮件,我们的防火墙将抓取 209.127.112.25-209.127.112.30 中的一个。如果我们的 DNS 记录说我们的 MX 主机是 209.127.112.28,那么我们只有 20% 的机会抓取到该 IP 地址,并且有 80% 的机会上游邮件主机将退回我们的邮件,因为邮件不是来自具有 DNS MX RR 的主机——这不好。
那么我们如何解决这个问题呢?如果我们有幸添加所有我们的 IP 地址作为 MX 主机,那将解决部分问题,但是上游主机可能会花费时间连接到我们不通过 DNAT 将邮件传递的 IP 地址。而且我们真的不希望所有这些 IP 地址都显示为 MX IP 地址。
正确的响应是在通用 SNAT 规则之前添加更具体的 SNAT 规则,该规则将处理端口 25 上的传出流量。这里的危险在于,如果我们不能信任我们的内部用户,我们还必须确保内部用户不能滥用端口 25。因此,我们将为传出流量添加三个规则,一个规则仅将来自我们的主邮件服务器 (192.168.0.8) 的端口 25 流量 SNAT 到 209.127.112.28,另外两个规则阻止来自除我们的真实邮件主机之外的所有其他内部地址的端口 25 流量
iptables -t filter -I FORWARD -i eth1 -s iptables -t filter -I FORWARD -i eth1 -p tcp --dport 25 -s -I POSTROUTING -o eth0 -p tcp --dport 25 -s 192.168.0.8 -j SNAT --to-source 209.127.112.28
你们中的一些人可能会想:哈!抓到他了。上面的前两个规则是颠倒的。嗯,是的,它们是颠倒的。但那是因为我们一次插入一个规则作为第一个规则,因此上面的规则二在运行它们之后实际上将是 FORWARD 链中的规则一。SNAT 规则在另一个链中,因此它可以放在任何位置。此外,我建议您确保上面的第一个规则对于您的系统是正确的。如果不受信任的网络是 192.168.0.0/24,而受信任的网络是 192.168.1.0/24,您可能需要将源 (-s) 设置为 192.168.0.0/23 以覆盖两者。或者,也许只是删除 -s 选项并在入站接口 (-i) 上匹配。
我建议构建防火墙的最佳方法是遍历每个链,查看特定数据包将在何处以及如何(甚至是否)处理。不要像我们在这里所做的那样,看似随意地插入规则。在纸上构建您的链,所有规则都按正确的顺序排列。那么您就不会犯错误。您始终可以在之后检查以确保规则是否与您认为想要的规则相同:iptables -t <table> -L -nv。上面包含 -v 的规则将向您显示此规则影响了多少数据包和多少字节。如果一周过去后,您仍然有受其影响的字节数为 0 的规则,您可能需要重新审视该规则在链中的位置。但是,仅仅因为规则影响了数据包,并不意味着它处于正确的位置。它可能只影响了真正应该受到影响的一半数据包。
我正在等待有人编写 Netfilter 的 “杀手级应用”,那将是一个运行测试、分析规则并允许您移动它们并再次测试的实用程序。但在那一天到来之前,您将不得不手动完成。
你们中的一些人可能已经注意到,我大量使用 -i eth0 或 -i ! eth0,但通常会匹配一个接口。通常,您可能会看到这没有必要,因为我已经限制了源 IP 地址或数据包标头的某些其他部分,这些部分几乎可以确保匹配我们想要的内容。但我这样做是有特定原因的。我关闭了 rp_filters(反向路径过滤器)。这些过滤器倾向于干扰合法的 VPN 数据包。此外,Linux 的 rp_filter 远不如 iptables 细粒度。
很难确保内部人员不会通过您的防火墙传递不应传出的数据。也许有些人有正当理由通过防火墙传递公司数据。但现在让我们假设情况并非如此。您想阻止某些数据离开(或至少尝试这样做)。
我们可以尝试通过标记数据来阻止某些数据离开,然后使用字符串匹配来查找该标记。在这里,我建议采用一种策略,即将诸如 “Copyright, foo.corp, not for publication” 之类的字符串放在您不想通过防火墙发送的文件的顶部。然后,在内部防火墙上,或者作为外部防火墙上 eth2(其中 eth0 是 Internet,eth1 是不受信任的 LAN,eth2 是受信任的 LAN)上的规则,您可能需要类似这样的内容
iptables -t filter -I FORWARD -i eth2 -m string --string="Copyright, foo.corp, not for publication" -j DROP
关于这个特定解决方案的几句话。首先,确保您已加载 ipconntrack 模块。这将对数据包进行碎片整理,并大大提高看到字符串的可能性。其次,不要期望它能捕获所有内容。特别是,如果文件已被压缩,则短语将无法识别。因此,这确实有局限性。
但是,如果您正在运行 IIS 服务器并想删除包含字符串 root.exe 的数据包,它将非常好用。规则可能如下所示
iptables -t filter -I FORWARD -m string --string=root.exe -j DROP
虽然使用 MIRROR 目标并将攻击反击攻击者可能很有趣,但这在道德上是值得怀疑的。
如果您仍然受到此类活动的困扰,您还可以使用 PSD(端口扫描检测)匹配。我不再看到那么多端口扫描,因为我看到的是拥有特定工具的脚本小子;他们将工具对准我的系统并开火。通常,这是一个旨在破坏运行 FrontPage 扩展的 IIS 服务器的 FTP 攻击。我看到一个 FTP 进入,然后是大量尝试创建 _vti_private 文件之类的活动。我们可以用以下方法阻止这种情况
iptables -t filter -I FORWARD -i eth0 -p tcp --dport 21 -m string --string="_vti_private" -j REJECT
显然,如果您正在运行 FrontPage 服务器,并且人们没有 “发布” 到它(使用端口 80),而是通过 FTP 移动他们的站点,则上述方法将不起作用。
本文没有涉及大量的扩展和目标。一些具有非常特定路由要求的读者可能希望查看 MARK 目标,无论是否使用 realm 匹配,以进行一些非常时髦的路由技巧。这将需要结合使用 iproute2 和 iptables。对于 ISP 或其他具有非常特定路由和带宽限制要求的用户来说,这是一个非常强大的组合。
你们中的其他人可能想看到一些 ULOG 目标示例或 iplimit 或 mport 示例。但是这些与其他匹配或目标非常相似,并且以相同的方式处理。通常,内核配置中的帮助将向您展示足够的 iptables 规则片段,以便您使用这些扩展。
请记住,只有 ACCEPT、DROP 或 REJECT 是数据包的最终目标,并停止 iptables 对数据包的处理。RETURN 目标仅终止链,但不终止 iptables 处理。
我也还没有涉及 MANGLE 表。但是此表的工作方式与 ipchains 中的 mangle 目标相同。如果您有兴趣,请尝试一下。您可能会发现您将无法使用数字(十六进制)目标,而必须使用描述性值。如果您不记得它们是什么,请尝试
iptables -j TOS -h
如果您需要 ICMP 类型列表,因为您想使用 iptables 处理特定的 ICMP 类型(例如允许 ping,这将通过具有 -m state --state ESTABLISHED,RELATED 的防火墙丢弃),此技巧也适用
iptables -p icmp -h有了正确的 ICMP 名称 echo-request,您可以允许 ping
iptables -t filter -I INPUT -i eth0 -p icmp --icmp-type echo-request -j ACCEPT如果您担心这一点,您还可以使用 iplimit 或 limit 对其进行速率限制。但请注意,限制 ping 并不会限制您的链路上的流量,而只会限制您响应此流量的速率。无论如何,标准 ping 数据包非常小,并且通常任何给定主机每秒仅发送一次,因此它们几乎不会被视为流量。
我见过的 iptables 脚本的一些常见错误包括为数据包选择不适当的接口。这包括未选择可能受到影响的所有接口。通常,在用作防火墙和主机(通常是在家庭中使用的系统)的系统上,lo(本地主机接口)会被遗忘。我还看到传出数据包使用 MANGLE 表、OUTPUT 链或 SNAT 目标,这些数据包具有 -i <interface> 而不是 -o <interface>。
有时规则变得非常具体,以至于没有任何东西可以匹配它们。尝试您能做到的最通用的规则,仅在需要时添加匹配扩展。只需注意这些规则相对于其他规则的位置,这样它们就不会拾取您不想要的数据包。
确保您使用了正确的案例:ipchains 对其内置链使用小写,但 iptables 使用大写。目标也是大写。几乎所有其他内容都是小写。如果您使用短选项(就像我在本文中所做的那样),链操作(Insert、Append、Delete 等)使用大写。
Netfilter 和 iptables 构成了一个极其强大的防火墙。但是要利用它,您需要掌握我的第一篇文章(“驯服野生的 Netfilter”,发表在 LJ 2001 年 9 月刊)中解释的基本语法,了解可供您使用的模块和匹配项,并了解特定系统可以了解数据包的哪些信息。掌握这三件事,您可以为可能遇到的任何问题构建高度复杂、量身定制的防火墙解决方案。
了解如何利用新的和实验性的匹配和目标(并始终对其进行测试)。您在上个月的文章中通过 pending-patches、most-of-pom 和 patch-o-matic 的 iptables 构建目标了解了这一点。通过创建和发送特定数据包到防火墙接口进行测试超出了本文的范围,但是存在许多实用程序可以帮助您完成此操作(sendip 或 ipmagic 浮现在脑海中)。
为内核构建缺少的模块(确保已选择它们)。
构建您的规则链,更具体的规则在前,更通用的规则在后。如果它有助于您组织事物,请继续构建可以从另一个链调用的自定义用户链。虽然本文未具体介绍这一点,但在 2001 年 9 月的文章中已对此进行了介绍。充分利用您可以使用的所有工具,包括 LOG 目标,以帮助您查看是否应用了特定规则以及应用于哪些数据包。
只需一些基本知识,iptables 就不难使用。阅读互联网上的一些 iptables 脚本。我不建议按原样使用它们;它们几乎肯定无法在您身上工作而无需大量调整,但它们会向您展示语法、规则(您可以从中获取片段)、思维过程等。
