使用 Linux 构建透明防火墙,第三部分

作者:Mick Bauer

在本系列文章中,我将展示如何使用运行在廉价 Linksys WRT54GL 无线路由器上的 OpenWrt (Linux) 构建透明防火墙。在第一部分中,我解释了为什么防火墙仍然重要,以及传统 IP 防火墙和透明防火墙之间的区别。

在第二部分中,我勾勒出了在家庭网络环境中部署透明防火墙的简单设计(可能是任何基于 OpenWrt 的防火墙的最佳应用)。我还展示了逐步过程,通过该过程,我用 OpenWrt Kamikaze(v. 8.09.2,运行 Linux 2.4 内核)替换了我的 WRT54GL 上的原生 Linksys 固件,然后将其升级到 OpenWrt Backfire(v. 10.03,运行 Linux 2.6 内核)。

本月,我将重新编译和配置 OpenWrt Backfire,希望这是本系列中涵盖的最后一个主要的 OpenWrt 特定任务。下次,我将开始编写自定义 iptables 防火墙脚本,该脚本将适用于您想要用作透明防火墙的任何 Linux 系统。

在深入探讨之前,关于 OpenWrt 性能的简要说明:OpenWrt 是一个业余爱好者的发行版,它运行在廉价硬件上,RAM 和处理器比任何现代 Linux 桌面系统都少且速度慢。我写它是因为它很有趣,而且因为我一直想在本专栏中进行一些硬件破解。但是,如果您需要非常快速或非常稳定的防火墙,OpenWrt 不是一个好的选择。

重新编译 OpenWrt 内核

在配置 OpenWrt 之前,您需要重新编译它。也就是说,您需要重新编译 Backfire 中的 Linux 2.6 内核,以便 iptables 可以在桥接模式下运行,将内核重新捆绑到新的固件映像中,然后将其重新刷写到您的网关。这比听起来可能要少做很多工作。

OpenWrt 构建过程有一些先决条件。首先,您需要所有这些 Ubuntu 软件包(或您的发行版的等效软件包):gawk、gcc、binutils、patch、bzip2、flex、bison、make、gettext、pkg-config、unzip、libz-dev、libcheaders 和 subversion。

如果您之前编译过 Linux 内核,您的系统可能已经安装了其中大部分;在我的系统上,我只需要安装 gawk、flex、bison、subversion 和 gettext。

接下来,您需要在非 Windows 格式化的卷上(msdos、fat32 和 ntfs 不支持 Linux 用户/组所有权和权限)拥有 3.5GB 的可用磁盘空间。我不知道为什么编译仅具有 4MB RAM 的设备的固件映像需要如此多的空间,但是如果您在编译期间耗尽磁盘空间,您将收到奇怪的、神秘的错误消息。

编译过程耗时但很简单。作为非 root 用户,将您的工作目录更改为您的 3.5GB 可用卷,并执行以下命令序列

backfireimage-$ svn co svn://svn.openwrt.org/openwrt/branches/backfire

这会将当前版本的 OpenWrt 的源代码树提取到您的工作目录中。现在,进入该源代码树

backfireimage-$ cd ./backfire

通过将此行添加到您的内核配置中,您可以使 iptables 能够在桥接模式下运行——也就是说,控制遍历本地桥接设备的数据包

backfireimage/backfire-$ echo "CONFIG_BRIDGE_NETFILTER=y" >> 
 ↪./target/linux/brcm47xx

现在,重新构建整个 OpenWrt 固件映像——Linux 2.6 内核、所有系统命令以及它们所在的压缩 RAM 文件系统

backfireimage/backfire-$ make

这个make命令需要相当长的时间,具体取决于您的 CPU 和硬盘的速度。如果由于错误而过早结束,最可能的原因是您缺少必需的软件包或您没有足够的可用磁盘空间。

如果您的构建由于其他原因而失败,或者如果您根本无法判断,请使用以下命令重试

backfireimage/backfire-$ make V=99

以这种方式将 make 的详细程度设置为 99 会导致它输出大量的日志消息。如果您最终在 OpenWrt 论坛(https://forum.openwrt.org)上寻求帮助,包括其中一些日志消息将提高您收到有用答案的几率。

一旦构建成功完成,您可以将您的工作目录更改为新二进制固件映像所在的目录。由于我正在使用 Linksys WRT54GL,它使用 Broadcom 芯片组,并且由于我正在安装 Linux 2.6 内核,因此我想要的二进制文件位于 bin/brcm47xx 中

backfireimage/backfire-$ cd bin/brcm47xx

现在是时候重新启动 WRT54GL 并重新刷写其固件了。在关闭路由器电源然后再打开电源后立即,或发出命令reboot从 telnet 会话中,输入此命令以从您的构建系统推送新映像

backfireimage/backfire-$ tftp -m binary 192.168.1.1 -c 
 ↪put openwrt-wrt54g-squashfs.bin

您可能还记得上次,OpenWrt 的默认 IP 地址是 192.168.1.1。在我连接到宽带路由器的笔记本电脑上,我已经将以太网接口配置为与同一网络上的 IP 地址(192.168.1.30,子网掩码 255.255.255.0)。

您的宽带路由器可能需要几次重启/TFTP 尝试才能“看到”TFTP 推送,但是一旦它看到,并且在它解压缩并加载新固件之后,您的路由器将能够充当透明防火墙!但是,首先您必须进行一些系统级配置。

启用 SSH

我上个月展示的连接到 OpenWrt 的两个示例都涉及 telnet。虽然这是登录 OpenWrt 的默认方式(至少对于初始设置而言),但它非常不安全。

幸运的是,在 OpenWrt Backfire 上,Dropbear Secure Shell (SSH) 守护程序包已安装并在启动时默认运行。您要做的就是禁用 telnet 登录并启用 SSH 登录,首先 telnet 进入 OpenWrt,然后通过以下方式设置 root 密码passwd命令,像这样

root@OpenWrt:~# passwd
Changing password for root
New password: *********
Retype password: *********
Password for root changed by root

您无需重启路由器;只需注销 telnet 会话,然后ssh返回。这次,系统将提示您输入用户名(使用“root”)和密码(您刚刚输入的密码)。

现在您已经有了安全的管理会话,您可以开始使用统一配置接口 (uci) 系统重新配置 OpenWrt。

使用 uci

在早期版本的 OpenWrt 中,例如 White Russian,您必须管理两个不同的配置系统:NVRAM 设置,通过nvram命令和用于普通 Linux 操作系统和应用程序设置的标准 /etc 系统。但是,使用 Kamikaze 和 Backfire 版本的 OpenWrt,nvram 设置保存在 /etc/config 中的文件中,这使得 OpenWrt 比以前更像 UNIX。

实际上,大多数 OpenWrt 行为,而不仅仅是 NVRAM 特定设置,都可以通过 /etc/config/ 中的文件进行管理。关键是与普通配置文件不同,您应该使用命令uci而不是文本编辑器来操作 /etc/config 中的任何内容。

uci 自动决定给定 /etc/config 文件中的更改是否需要触发 NVRAM 更改,是否需要其他命令,例如iptables被调用等等。严格来说,您可能并不总是必须使用 uci——例如,我能够通过编辑 /etc/config/system 并重新启动来更改我的 WRT54GL 的时区。但是,当您坚持使用 uci 时,OpenWrt 上的工作效果会更好。

清单 1 显示了一个 uci 命令块,您可以使用它来更改 OpenWrt 盒子的时区和主机名。

清单 1. 更改时区和主机名

root@OpenWrt# uci set 
 ↪system.@system[0].timezone=CST6CDT,M3.2.0,M11.1.0
root@OpenWrt# uci set system.@system[0].hostname=sugartongs
root@OpenWrt# uci commit system

uci 命令的一般语法是uci [操作] [配置文件名].[配置文件节].[选项名]=[值]。因此,清单 1 中的第一行转换为“更改 /etc/config/system 中系统节中的名为 timezone 的设置,使其值为 CST6CDT,M3.2.0,M11.1.0”。

为什么时区值在实际时区名称之后有这么多乱码?为什么不直接说“CST6CDT”?这是因为不同国家/地区的夏令时开始和结束日期不同。请参阅资源,获取您可以使用的不同时区字符串的图表链接。

设置正确的时区非常重要。它允许您的 OpenWrt Backfire 系统使用rdate命令(或者您可以安装 ntpclient 以使其改用 ntp)自动通过 Internet 同步其时间。如果您未设置正确的时区,rdate 将无法正常工作,这意味着许多其他事情也会失败,例如 IPsec 以及任何其他使用数字证书的东西。

继续,清单 1 中的第二行涉及将选项“hostname”的设置从其默认值“OpenWrt”更改为“sugartongs”。显然,您可以指定任何您喜欢的主机名。

第三行告诉 uci 提交自上次运行以来对 /etc/config/ 的所有更改——也就是说,根据需要更改 NVRAM、执行 iptables 命令等等。但是,我发现对于时区和主机名设置,您还需要重新启动路由器才能使更改生效(使用命令reboot,自然)。

安装可选软件包

我稍后会回到 uci。首先,这里简要介绍一下可选软件包。

与任何 Linux 发行版一样,OpenWrt 也有可选软件包,您可以在基本系统映像就位后安装。OpenWrt 的大多数软件包都是面向网络的,它们包括 apache、bind、freeradius、各种 Linux 内核模块、snort、squid、stunnel、vpnc 和 vsftpd。

但这些超出了本系列文章的范围。构建使用 OpenWrt Backfire 的透明防火墙所需的一切都包含在基本映像中(至少对于我的 Linksys WRT54GL 来说是这样)。此外,大多数宽带路由器都有 16 到 72 兆字节总共组合的闪存和 RAM;即使使用压缩文件系统,这对于应用程序本身或其数据来说也没有多少存储空间。

但是,如果您想安装可选软件包,它们可以从 openwrt.org 的架构下载站点的 packages 目录中获得。例如,对于我的系统,运行 Broadcom 47xx 版本的 OpenWrt Backfire,可选软件包位于 backfire.openwrt.org/10.03/brcm47xx/packages。有关查找和管理 OpenWrt 软件包的更多信息,请参阅 OpenWrt Wiki 页面 Packages。

OpenWrt 文档

在我看来,完整的文档不是 OpenWrt 的优势之一。这是一个由网络工程师为网络工程师设计的 Linux 发行版,其维护者假设 OpenWrt 用户具有高于平均水平的能力和意愿来自行解决问题。

对于我们其他人,一些有用的 OpenWrt 文档不是在 OpenWrt 主页的文档区域中找到,而是在 OpenWrt Wiki wiki.openwrt.org 中找到。迟早您可能还需要使用论坛 (https://forum.openwrt.org) 甚至 Google 来找到您的 OpenWrt 相关问题的答案。

更改 OpenWrt 上的网络配置

本月要介绍的最后一项任务,也是(我希望是)最后一个 OpenWrt 特定的任务,是在 OpenWrt 上配置网络。这是一个我无法深入探讨的庞大主题(尽管我认为我的示例非常清楚)。OpenWrt Wiki 上提供了有关如何在 OpenWrt 上配置网络的许多不同方法的更完整说明 (wiki.openwrt.org/doc/uci/network)。

说到这里,您会注意到关于配置网络的 wiki 文章没有列出任何实际的 uci 命令;它仅显示了“最终产品” /etc/config/network。这是因为一旦您了解语法,OpenWrt 的 /etc/config 文件中的语句很容易转换为 uci 命令。

我建议您首先在纸上草拟您希望 /etc/config/network 看起来的样子,将其与当前 /etc/config/network 的外观进行比较,记下哪些行需要更改,然后将这些更改转换为命令列表。与简单地编辑配置文件相比,输入长命令序列时确实更容易出错。但是,使用向上箭头键调出您刚刚输入的命令,然后在序列中下一个命令的不同部分上按退格键,可以减少您需要执行的键入量,从而减少您搞砸的可能性。

清单 2 显示了 Linksys WRT54GL 的 Backfire 默认 /etc/config/network 文件。

清单 2. 默认 /etc/config/network 文件

config switch eth0
        option enable   1

config switch_vlan eth0_0
        option device   "eth0"
        option vlan     0
        option ports    "0 1 2 3 5"

config switch_vlan eth0_1
        option device   "eth0"
        option vlan     1
        option ports    "4 5"

config interface loopback
        option ifname   "lo"
        option proto    static
        option ipaddr   127.0.0.1
        option netmask  255.0.0.0

config interface lan
        option type     bridge
        option ifname   "eth0.0"
        option proto    static
        option ipaddr   192.168.1.1
        option netmask  255.255.255.0

#### WAN configuration
config interface        wan
        option ifname   "eth0.1"
        option proto    dhcp

让我们从顶部开始逐步了解此文件。首先,config switch eth0option enable 1构成第一个配置部分。每个部分都由一个 config 行组成,该行命名一些网络接口、交换机、vlan 或其他元素,后跟影响该元素的一个或多个 option 行。清单 2 中的第一部分启用了交换机设备 eth0。

与宽带路由器的典型情况一样,Linksys WRT54G 上的所有以太网端口都由单个交换机芯片组(在本例中为 Broadcom 芯片组)控制。单个端口在 OpenWrt 中通过其虚拟 LAN (VLAN) 分配来引用,例如,eth0.0 (VLAN #0)、eth0.1 (VLAN #1) 等等。清单 2 中的后续配置部分定义和配置了这些 VLAN。

清单 2 中的第二部分显示了 VLAN 0 的设置,称为eth0_0在配置文件中,但在随后内核中称为eth0.0. option device,指定 VLAN 与哪个交换机关联(eth0 是唯一存在的交换机);option vlan指定您要定义的 VLAN 编号;以及option ports指定哪些端口属于此 VLAN。

端口号在 OpenWrt 中的分配方式与您期望的不同。端口 #5 是与内核本身关联的“虚拟”端口。每个 VLAN 都必须与端口 #5 关联。WRT54GL 上的端口 #4 标记为“WAN 端口”,您通常连接到 DSL 路由器或电缆调制解调器的端口(尽管在 OpenWrt 中您可以将其分配给您喜欢的任何 VLAN——实际上没有什么特别之处)。

端口 0–3 对应于 WRT54GL 上的端口 4、3、2 和 1;它们相对于盒子上的丝网印刷向后编号。因此,在清单 2 中,option ports "0 1 2 3 5"表示“端口 4、3、2 和 1”,并且option ports "4 5"将转换为“WAN 端口”。

因此,接下来的部分将 WAN 端口定义为属于 VLAN #1 (eth0.1)。

不要担心loopback部分。如果您了解环回接口,则此部分的含义显而易见。如果您不了解,则无关紧要,因为无论如何您都不应更改此部分。只需说,与任何其他 Linux 系统一样,发送到 IP 地址 127.0.0.1 或接口 lo 的数据包将直接转到本地内核,并标记为源自本地。

最后两个部分定义了网络接口。第一个接口部分任意命名为 lan,其实际接口名称 (ifname) 为 eth0.0(您会记得它实际上是交换机 eth0 上的 VLAN 0)。由于它与交换机端口有关,因此属于 switch 类型。此接口的静态 IP 地址为 192.168.1.1,子网掩码为 255.255.255.0。

您会从清单 2 的第二部分中回忆起,eth0.0 与路由器上的端口 1–4 关联。此 VLAN 现在被定义为独立的以太网交换机,其 IP 地址为 192.168.1.1/24(意味着连接到端口 1–4 的任何设备都需要具有同一逻辑 LAN 中的 IP 地址)。

在第二个接口部分中,VLAN 1 (eth0.1) 仅与路由器的 WAN 端口(OpenWrt 端口 4)关联,被配置为具有动态、dhcp 分配 IP 地址的标准(非桥接)接口。

那么,我想做什么更改呢?基本上,我想将整个以太网接口块配置为单个交换机,包括 WAN 接口。我还想将交换机的 IP 地址(以及其网络地址)更改为 10.0.0.253,这是我计划将防火墙插入的网络上未使用的 IP 地址。

由于所有桥接端口都将在同一 VLAN 上,因此我可以删除整个 VLAN eth0_1 部分和整个接口 wan 部分。我还必须更改 VLAN eth0_0 下的 ports 选项和接口 lan 下的 ipaddr 选项。所有这些总共只需要七个命令(包括重新启动系统)!

清单 3 显示了您希望 /etc/config/network 看起来的样子。

清单 3. 新的 /etc/config/network 文件

config 'switch' 'eth0'
	option 'enable' '1'

config 'switch_vlan' 'eth0_0'
	option 'device' 'eth0'
	option 'vlan' '0'
	option 'ports' '0 1 2 3 4 5'

config 'interface' 'loopback'
	option 'ifname' 'lo'
	option 'proto' 'static'
	option 'ipaddr' '127.0.0.1'
	option 'netmask' '255.0.0.0'

config 'interface' 'lan'
	option 'type' 'bridge'
	option 'ifname' 'eth0.0'
	option 'proto' 'static'
	option 'ipaddr' '10.0.0.253'
	option 'netmask' '255.255.255.0'

清单 4 显示了将清单 2 中显示的 /etc/config/network 转换为清单 3 中显示的 /etc/config/network 所需的七个命令。但是,在执行这些命令之前,阅读以下说明文字,这将帮助您避免使您的宽带路由器变砖(使其无法使用)的风险。

清单 4. 用于更改 /etc/config/network 的 uci 命令

root@OpenWrt:~# uci set network.eth0_0.ports="0 1 2 3 4 5"

root@OpenWrt:~# uci delete network.eth0_1

root@OpenWrt:~# uci set network.lan.ipaddr="10.0.0.253"

root@OpenWrt:~# uci delete network.wan

root@OpenWrt:~# uci show network

root@OpenWrt:~# uci commit

root@OpenWrt:~# reboot

本月我的空间已用完,所以我无法剖析清单 4,希望清单 4 与之前的 uci 示例足够相似,可以理解。但是,我将给您留下两个重要的注意事项。

首先,请注意uci show network。这允许您在提交更改之前检查您的工作。如果任何行错误,您可以重新输入相关的 uci 命令。要重新开始,请输入命令uci revert network以撤消所有更改。如果您将事情搞砸得太糟糕以至于无法ssh返回,您可以重新刷写固件映像,这将重置路由器的 IP 地址回 192.168.1.1 等。但是,在提交之前检查和重新检查您的工作比重新刷写更省事,也更容易让您放松!

其次,在更改设备的 IP 地址并重新启动后,您将无法重新连接到您的 OpenWrt 盒子,除非您已将您的客户端系统重新配置为与 OpenWrt 盒子的新地址兼容的 IP 地址。例如,在我将我的 Linux 笔记本电脑的以太网接口重新配置为 IP 地址 10.0.0.30 和子网掩码 255.255.255.0 后,我能够ssh返回到我的 OpenWrt 路由器,命令为ssh root@10.0.0.253.

结论

本月我介绍了很多内容:重新编译 OpenWrt 以获得 iptables 桥接支持、启用 SSH、使用 uci 和重新配置网络。下次,我将向您展示如何禁用默认的 OpenWrt 防火墙并创建一个自定义 iptables 脚本,该脚本应在任何支持桥接的 Linux 2.6 系统上工作。在那之前,请注意安全!

资源

OpenWrt 项目主页: www.openwrt.org

OpenWrt 的统一配置接口文档: wiki.openwrt.org/doc/uci

时区字符串图表: nuwiki.openwrt.org/oldwiki/openwrtdocs/whiterussian/configuration#timezone

OpenWrt 软件包信息: wiki.openwrt.org/oldwiki/openwrtdocs/packages

Mick Bauer (darth.elmo@wiremonkeys.org) 是美国最大的银行之一的网络安全架构师。他是 O'Reilly 图书 Linux 服务器安全第二版(以前称为 使用 Linux 构建安全服务器)的作者,信息安全会议的特邀演讲者,以及“网络工程波尔卡”的作曲家。

加载 Disqus 评论