构建无盘 2.6 防火墙
想要为您的家庭网络构建自定义路由器/防火墙吗?您几乎可以从旧货出售或在线拍卖中免费获得必要的硬件。您甚至可能有一些旧硬件闲置着。奔腾级别的系统就足够了,并且可以很好地处理压力。通常,我们不需要太多内存,但我建议至少 16MB 的 RAM。我们可以使用 Compact Flash 或 CF 卡代替硬盘。CF 具有一些巧妙的功能,例如板载错误检测和纠正,以最大限度地减少闪存磨损。由于具有全功能的 IDE 接口,它也可以用作普通的 IDE 设备。不过,您确实需要一个适配器来连接卡。我们将只使用两到三个兆字节,因此卡的大小并不重要。
现在,我们将构建一台具有以下功能的机器:iptables 防火墙、SSH 守护进程、DHCP 服务器和 DNS 服务器。因为我们将从头开始构建一个 Linux 系统,所以我们需要相当多的软件。常用的 Linux 工具不是为嵌入式系统构建的,它们加载了我们不需要的功能。这就是 BusyBox(嵌入式 Linux 的瑞士军刀)发挥作用的地方。我们可以用 BusyBox 替换我们大多数需要的工具,例如 shell、ifconfig、ip 工具等等。然后我们需要一个引导加载程序、一个 C 库、iptables、一个 SSH 服务器和一个 DNS 服务器。我们将使用新的 2.6.1 内核版本,它引入了一些我们稍后会处理的问题。
我使用 GRUB 作为引导加载程序,但任何最新的加载程序都应该可以。iptables 1.2.9 版本是我们防火墙软件的选择,Dropbear 用作我们的 SSH 守护进程。最后,我们使用方便的 dnsmasq 程序,它基本上是一个精简但功能齐全的 DNS 服务器,用于将我们的请求转发到您的 ISP 的 DNS 服务器。
我面临的最大问题是 C 库 libc。我选择了轻量级库 uClibc。它是一个用于嵌入式系统的 C 库,带有一整套工具链。可以通过从 uclibc.org/cgi-bin/cvsweb/toolchain/gcc-3.3.x.tar.gz?view=tar 获取安装程序 tar 文件来轻松安装开发环境。解压缩它并编辑 toolchain 目录中的 Makefile,然后键入make。这会下载、编译并安装适用于您平台的工具链。安装需要一些时间,主要取决于您的互联网连接。完成后,您将看到一个名为 toolchain_ARCHITECTURE(例如,toolchain_i386)的目录,其中包含所有库、头文件和稍后需要的交叉编译器。
最大的问题之一是“我应该使用什么文件系统?” Compact Flash 卡出厂时已格式化为 VFAT,这可能不是 Linux 的最佳选择。显而易见的选择是 ext3,但您应该关注闪存磨损,这迟早会影响所有基于闪存的设备。所有基于闪存的介质在一定数量的写入周期后都会失效;compact Flash 通常在一百万次左右失效。这听起来可能很多,但文件系统的日志功能最终会杀死闪存。为了简单起见,我们使用 ext2 文件系统,我们以只读方式挂载它。要配置路由器,您必须以可写方式重新挂载磁盘。
将卡连接到 USB 读卡器或使用 IDE 适配器,并使用您最喜欢的 fdisk 程序创建一个新分区。一个与您的闪存大小相同的分区就足够了。然后发出命令/sbin/mkfs.ext2 -m0 /dev/[flash]以创建一个新的 ext2 文件系统。
发出命令tune2fs -c0 -i0 /dev/[flash]以关闭自动文件系统检查以及文件系统应检查错误的警告。因为我们以只读方式使用它,所以我们不必太担心错误。挂载磁盘并继续。
新内核进行了一些重大改进,第一个也是最明显的改进是新的图形配置菜单。它可以通过以下任一方式调用make gconfig或make xconfig分别用于基于 GTK+ 或 Qt 的应用程序(图 1)。使用这些新的 GUI,配置内核变得轻而易举,比以往任何时候都容易。
为路由器编译内核时,您可能需要考虑的一件事是,BusyBox 的模块支持在新 2.6 模块中似乎有点不稳定。我们可以通过编译一个非模块化内核来轻松避免这个问题,这样做的好处是我们不必考虑与模块相关的实用程序。
在功能方面,我建议您检查所有与 iptables 相关的选项以及您的网卡驱动程序。除非您需要它们,否则我们可以取消选中大多数其他选项。请记住,我们选择添加的内容越少,内核需要的空间就越少。但请务必静态编译所有选项,因为我们不使用模块。
完成后,输入make并观看新的、整理后的编译过程。在您的 Compact Flash 上创建一个名为 boot 的目录,并将cp内核从 arch/i386/boot/ 复制到 /mnt/cf/boot/。
编译应用程序非常容易;我们从 BusyBox 开始。解压缩它,切换到新目录并键入make menuconfig。您将看到一个简单而清晰的基于 ncurses 的配置菜单(图 2)。按 B 选择 Build Options,然后输入 uClibc 工具链 GCC 程序的 prefix。我将我的 toolchain_i386 目录复制到了 /usr,所以我必须输入的完整路径是 /usr/toolchain_i386/bin/i386-linux-。接下来,转到 Installation Options 并将您的安装目录更改为您的闪存卡的挂载点。激活 ifconfig、inetd、ip 和 udhcpd 选项以及所有子选项。您应该在 BusyBox 的 examples 目录中找到一个注释良好的 udhcpd 配置文件。最后,转到 Init Utilities 部分并确认所有选项都已选中。您可能还想添加 vi 以及其他工具以增加功能。
BusyBox 可以为您提供用于登录和用户管理的工具。然而,我不知何故无法让它们正常工作。因此,我不得不使用来自 tinylogin.busybox.net 的 TinyLogin 包。配置和安装非常简单;只需编辑 Makefile 以使用交叉编译器并以用户 root 身份安装,以便 TinyLogin 可以设置 SUID 位。
此配置不支持 IPv6。当然,这是一个未来要添加的功能,但 IPv6 对于典型的 SOHO 环境来说相当罕见。缺乏 IPv6 支持使我们需要在我们的应用程序中禁用它。
虽然在 iptables 上禁用此功能非常容易(make DO_IPV6=0 KERNEL_DIR=[您的 Linux 内核路径] CC=[您的交叉编译器路径]),但 dnsmasq 不会被说服放弃此功能。经过几个小时的认真挠头后,我尝试了小 DNS 守护进程的最新不稳定版本,即 2.0rc1。命令make CC=[交叉编译器路径]立即工作并生成了一个完美工作的 dnsmasq 二进制文件。2.0 版本还具有嵌入式 DHCP 守护进程,有些人可能更喜欢它而不是 BusyBox 附带的那个。
您应该对所有二进制文件使用 strip 命令以去除调试信息并使其更小。
dropbear SSH 守护进程工作良好,并且无需修改即可使用 uClibc 进行编译。如果您遇到问题,请查阅 INSTALL 文件,其中还解释了如何配置它。将生成的二进制文件(dropbear、dropbearkey)复制到 /sbin。
除此之外,您还需要添加以下行
none /dev/pts devpts gid=5,mode=620 0 0
到文件 /etc/fstab,以便 dropbear 的 openpty() 函数工作,并且您实际上可以登录。除此之外,您还需要目录 /dev/pts 和设备文件 /dev/ptmx。/dev/urandom 是通过 dropbearkey 程序生成 RSA 和 DSS 密钥所必需的。
切换到 /mnt/cf。在安装 BusyBox 和 TinyLogin 之后,我们已经迎来了一个有些熟悉的环境。您现在必须添加以下目录:/dev、/etc、/lib 和 /proc。
转到目录 /lib 并从您的 toolchain_i386/lib 目录复制以下库和符号链接。它应该看起来像清单 1。
清单 1. 要复制的库和符号链接
$ ls -lh total 295K -rwxr-xr-x 1 root root 16K Jan 18 17:40 ld-uClibc-0.9.26.so lrwxr-xr-x 1 root root 19 Jan 19 13:33 ld-uClibc.so.0 -> ld-uClibc-0.9.26.so -rw-r--r-- 1 root root 8.9K Jan 18 17:40 libcrypt-0.9.26.so lrwxr-xr-x 1 root root 13 Jan 19 13:33 libcrypt.so -> libcrypt.so.0 lrwxr-xr-x 1 root root 18 Jan 19 13:33 libcrypt.so.0 -> libcrypt-0.9.26.so lrwxr-xr-x 1 root root 19 Jan 19 13:33 libc.so.0 -> libuClibc-0.9.26.so -rw-r--r-- 1 root root 5.6K Jan 18 17:40 libdl-0.9.26.so lrwxr-xr-x 1 root root 10 Jan 19 13:33 libdl.so -> libdl.so.0 lrwxr-xr-x 1 root root 15 Jan 19 13:33 libdl.so.0 -> libdl-0.9.26.so -rw-r--r-- 1 root root 1.5K Jan 18 17:40 libnsl-0.9.26.so lrwxr-xr-x 1 root root 11 Jan 19 13:33 libnsl.so -> libnsl.so.0 lrwxr-xr-x 1 root root 16 Jan 19 13:33 libnsl.so.0 -> libnsl-0.9.26.so -rw-r--r-- 1 root root 255K Jan 18 18:16 libuClibc-0.9.26.so -rw-r--r-- 1 root root 4.2K Jan 18 17:40 libutil-0.9.26.so lrwxr-xr-x 1 root root 12 Jan 27 16:02 libutil.so -> libutil.so.0 lrwxr-xr-x 1 root root 17 Jan 27 16:02 libutil.so.0 -> libutil-0.9.26.so
将 iptables 和 dnsmasq 二进制文件复制到 /sbin,并切换到 /dev 目录。从您的 /dev 目录复制清单 2 中显示的设备。使用命令cp -dpr复制设备文件,否则它们可能无法工作。当然,您也可以使用 mknod 命令从头开始创建设备。
清单 2. 要复制的设备
crw------- 1 root root 5, 1 Jan 17 15:34 console crw------- 1 root root 1, 6 Sep 15 15:40 core brw-rw---- 1 root disk 3, 64 Sep 15 15:40 hdb brw-rw---- 1 root disk 3, 65 Sep 15 15:40 hdb1 crw-rw-rw- 1 root root 1, 3 Sep 15 15:40 null crw-rw-rw- 1 root root 5, 2 Jan 27 17:32 ptmx drwxr-xr-x 2 root root 1024 Jan 20 15:15 pts crw-r--r-- 1 root root 1, 8 Sep 15 15:40 random lrwxrwxrwx 1 root root 17 Jan 18 15:25 stderr -> ../proc/self/fd/2 lrwxrwxrwx 1 root root 17 Jan 18 15:25 stdin -> ../proc/self/fd/0 lrwxrwxrwx 1 root root 17 Jan 18 15:25 stdout -> ../proc/self/fd/1 crw-rw-rw- 1 root root 5, 0 Sep 15 15:40 tty crw--w---- 1 root root 4, 0 Sep 15 15:40 tty0 crw------- 1 root root 4, 1 Jan 17 15:35 tty1 crw------- 1 root root 4, 2 Jan 17 15:35 tty2 crw------- 1 root root 4, 3 Jan 17 15:35 tty3 crw------- 1 root root 4, 4 Jan 17 15:35 tty4 crw------- 1 root root 4, 5 Jan 17 15:35 tty5 crw-r--r-- 1 root root 1, 9 Jan 27 15:57 urandom crw-rw-rw- 1 root root 1, 5 Sep 15 15:40 zero
现在,我们将添加用户 root。发出命令/usr/sbin/chroot ./ /bin/ash,您将看到 BusyBox 的 ash shell。转到目录 /etc 并创建空文件 passwd、shadow 和 group。
使用命令adduser -h /root root您可以添加用户 root。您必须编辑文件 /etc/passwd 并更改行root:x:500:500:Linux User,,,:/root:/bin/sh为root:x:0:0:Linux User,,,:/root:/bin/sh为了使用户 root 成为超级用户。现在键入su root并使用命令创建密码passwd.
之后,我们需要添加常用的配置和系统文件:hosts、securetty、fstab、inittab 和 resolv.conf。我没有使用功能齐全的 init 脚本,我的 inittab 仅包含两行
tty1::respawn:/sbin/getty 38400 tty1 ::sysinit:/etc/rc
所有应用程序都使用 rc 脚本启动(清单 3)。网络接口也直接使用此脚本配置。
清单 3. rc 脚本
#!/bin/sh /bin/mount -a echo "Setting up network" /sbin/ifconfig lo 127.0.0.1 /sbin/ifconfig eth0 192.168.0.1 /sbin/ifconfig eth1 10.0.0.2 /sbin/route add default gw 10.0.0.1 echo "Starting daemons" /sbin/inetd /sbin/dropbear /sbin/udhcpd /sbin/dnsmasq Starting Firewall /etc/firewall.sh
我使用 Fwbuilder 创建了 firewall.sh 脚本,这是启动和运行防火墙的最简单和最舒适的解决方案。有关 Fwbuilder 的更多信息,请阅读 Mick Bauer 在 2003 年 5 月和 6 月的 Linux Journal 杂志上发表的文章。如果您必须更改脚本,则需要使用 SSH 登录并使用命令mount -o rw,remount /dev/hda1 /使闪存卡可写。然后,将脚本从您的机器传输到防火墙并将其移动到 /etc/firewall.sh。最后,使脚本可执行并使用命令mount -o ro,remount /dev/hda1 /再次使文件系统只读。您可能希望通过编写一个小 shell 脚本来自动化此过程。
系统日志记录的一个好解决方案是将日志消息通过网络发送到另一台机器。此选项效果很好,但需要另一台计算机;尽管如此,这是我的选择。另一种方法需要另一个分区,以读写方式挂载以进行日志记录,这会大大增加闪存的负担。
2.6 系列内核需要适当的引导加载程序。直接将内核直接写入磁盘已被弃用,而且毕竟非常混乱。在 /mnt/cf/boot 中创建一个名为 grub 的目录,并从您的 /boot/grub 目录复制 stage1、stage2 和 e2fs_stage_1_5。除此之外,您还需要一个名为 menu.lst 的 GRUB 配置文件。附带说明一下,我必须创建一个名为 grub.conf 的符号链接,否则 GRUB 将无法启动——这似乎是 Red Hat 特有的故障。menu.lst 需要放在 /boot/grub 中。
接下来,您需要使用命令创建引导软盘cat stage1 stage2 > /dev/fd0。从软盘启动,您将被放入 GRUB shell。键入root (hd0,0)和setup (hd0)。GRUB 会吐出一些调试消息,这些消息应该表明该过程是否成功。弹出软盘并键入reboot。防火墙现在应该启动了,几秒钟后您应该看到登录提示符。
我们现在有一个非常基本的 Linux 系统,专为防火墙和路由而设计。您可以轻松添加 PPP 守护进程以实现拨号式宽带互联网访问。您还可以添加打印守护进程并将打印作业假脱机到内存中。2.6 内核还具有本机 ipsec 实现,将其编译到内核中并添加用户空间工具以实现完整的 VPN 功能。如您所见,可能性几乎是无限的。
Linux Journal FTP 站点提供了本文示例文件系统的 tarball(请参阅资源),如果您遇到问题,这可能会有所帮助。
资源
BusyBox: www.busybox.net
Dropbear: matt.ucc.asn.au/dropbear/dropbear.html
示例文件系统: ftp.linuxjournal.com/pub/lj/listings/Web/7383.tar
TinyLogin: tinylogin.busybox.net
uClibc: www.uclibc.org
“使用 Firewall Builder,第一部分”: www.linuxjournal.com/article/6625
“使用 Firewall Builder,第二部分”: www.linuxjournal.com/article/6715
Christian Herzog 是一位专注于开源技术的奥地利 Web 开发人员。他最近与一位朋友一起开设了一家新公司。您可以通过 christian@dc-it.at 与他联系。