桥接过滤器
最后更新于
最后更新于
原文:
通常,将一个物理网络(如以太网)划分为两个独立的网络段而不需要创建子网,并使用路由器将它们连接起来是很有用的。以这种方式连接两个网络的设备称为桥接器。具有两个网络接口的 FreeBSD 系统就足够充当桥接器。
桥接器通过扫描连接到其每个网络接口的设备的 MAC 层地址(以太网地址)来工作,然后只有当源地址和目标地址位于不同的网络段时,才会转发流量。从许多角度来看,桥接器类似于只有两个端口的以太网交换机。
由于宽带互联网连接(xDSL)成本的降低以及 IPv4 地址的减少,越来越多的公司实现了 24 小时全天候连接到互联网,并且只有少量(有时甚至不是 2 的幂)IP 地址。在这些情况下,通常希望有一个防火墙来过滤进出互联网的流量,但基于路由器的包过滤解决方案可能不适用,可能是因为子网问题、路由器是由连接提供商(ISP)拥有,或者路由器不支持此类功能。在这些场景中,强烈建议使用过滤桥接器。
基于桥接器的防火墙可以配置并插入到 xDSL 路由器和以太网集线器/交换机之间,而无需任何 IP 编号问题。
为 FreeBSD 系统添加桥接功能并不困难。从 4.5 版本开始,可以将这些功能作为模块加载,而无需重新编译内核,从而大大简化了操作。接下来的小节中,我将介绍两种安装方式。
重要
不要同时遵循这两种指令:一个过程 排除 另一个过程。根据你的需求和能力选择最佳选项。
在继续之前,请确保至少拥有两块支持混杂模式(既支持接收又支持传输)的以太网卡,因为它们必须能够发送任何地址的以太网数据包,而不仅仅是它们自己的地址。此外,为了获得良好的吞吐量,卡片应该是 PCI 总线主控卡。最好的选择仍然是 Intel EtherExpress™ Pro,其次是 3Com® 3c9xx 系列。为了简化防火墙配置,使用不同厂商的两张卡(使用不同的驱动程序)可能是有用的,这样可以清楚地区分连接到路由器的接口和连接到内网的接口。
所以你决定使用较旧但经过良好测试的安装方法。首先,你需要将以下几行添加到内核配置文件中:
第一行用于编译桥接支持,第二行是防火墙,第三行是防火墙的日志记录功能。
如果你选择使用新且更简单的安装方法,现在要做的就是在 /boot/loader.conf 中添加以下行:
通过这种方式,在系统启动时,bridge.ko 模块将与内核一起加载。无需为 ipfw.ko 模块添加类似的行,因为它将在执行以下步骤后自动加载。
在重新启动以加载新内核或所需的模块(根据先前选择的安装方法)之前,你必须对 /etc/rc.conf 配置文件进行一些更改。防火墙的默认规则是拒绝所有 IP 包。最初,我们将设置一个“开放”防火墙,以验证其操作,而不会遇到与包过滤相关的任何问题(如果你打算远程执行此过程,这种配置将避免你被隔离在网络之外)。将以下行添加到 /etc/rc.conf 文件中:
第一行将启用防火墙(并在内核中没有编译时加载 ipfw.ko 模块),第二行将其设置为 open
模式(如 /etc/rc.firewall 中所解释),第三行用于不显示规则加载信息,第四行启用日志记录支持。
关于网络接口的配置,最常用的方法是仅为其中一张网卡分配 IP 地址,但即使两张网卡或没有网卡配置 IP,桥接器仍然可以正常工作。在没有 IP 的情况下,桥接主机将更加隐蔽,因为它无法从网络访问:要配置它,你需要通过控制台或通过一个与桥接器分开的第三个网络接口登录。有时,在系统启动期间,某些程序需要网络访问,例如用于域名解析:在这种情况下,必须为外部接口(连接到 Internet 的接口,DNS 服务器所在的接口)分配一个 IP 地址,因为桥接器将在启动程序的最后激活。这意味着必须在 /etc/rc.conf 文件的 ifconfig 部分中提到 fxp0 接口(在我们的示例中),而 xl0 接口则不需要提到。为两张网卡分配 IP 地址并没有太大意义,除非在启动过程中,某些应用程序需要访问两个以太网段上的服务。
还有一点需要了解。在以太网上运行 IP 时,实际上有两个以太网协议在使用:一个是 IP,另一个是 ARP。ARP 用于将主机的 IP 地址转换为其以太网地址(MAC 层)。为了使通过桥接器隔开的两台主机之间能够通信,必须确保桥接器能够转发 ARP 数据包。该协议不包含在 IP 层中,因为它仅在以太网上运行的 IP 协议中存在。FreeBSD 防火墙仅在 IP 层上进行过滤,因此所有非 IP 包(包括 ARP)将被转发,而不会被过滤,即使防火墙配置为不允许任何内容。
现在是时候重新启动系统并像之前一样使用它了:会有一些关于桥接器和防火墙的新消息,但桥接器将不会被激活,防火墙处于 open
模式时,不会阻止任何操作。
如果有任何问题,你应该在继续之前解决它们。
此时,为了启用桥接器,你需要执行以下命令(务必替换 fxp0 和 xl0 这两个网络接口名称为你自己使用的接口):
第一行指定了应该由桥接器启用的接口,第二行将在桥接器上启用防火墙,最后一行将启用桥接器。
此时,你应该能够将这台计算机插入到两个主机组之间,而不会妥协它们之间的任何通信能力。如果成功,下一步是将这些行的 net.link.ether.bridge.[blah]=[blah]
部分添加到 /etc/sysctl.conf 文件中,以便在启动时自动执行。
现在是时候创建你自己的文件,并编写自定义的防火墙规则来保护内部网络了。由于并非所有防火墙功能都可以应用于桥接的数据包,因此配置可能会有些复杂。此外,正在转发的数据包与被本地计算机接收的数据包在处理方式上有所不同。通常,传入的数据包只会经过一次防火墙处理,而不是像平常那样经过两次;实际上,它们仅在接收到时被过滤,因此使用 out
或 xmit
的规则将永远无法匹配。个人而言,我使用的是 in via
语法,尽管这是较旧的语法,但理解起来是有意义的。另一个限制是,你只能使用 pass
或 drop
命令来过滤桥接的数据包。像 divert
、forward
或 reject
这样的复杂命令无法使用。虽然这些选项仍然可以使用,但仅限于桥接器本机(如果它有 IP 地址)上下行的流量。
FreeBSD 4.0 中引入了状态过滤的概念,这是对 UDP 流量的一大改进。UDP 流量通常是一个请求,随后立即会返回一个响应,具有相同的 IP 地址和端口号(当然,源和目的地是反向的)。对于没有状态跟踪的防火墙,几乎无法处理这种类型的流量作为一个单独的会话。但对于可以“记住”出去的 UDP 数据包,并在接下来的几分钟内允许响应的防火墙来说,处理 UDP 服务就变得非常简单。下面的示例展示了如何操作。对 TCP 数据包也可以做同样的事情。这使你能够避免一些拒绝服务攻击和其他恶意操作,但通常会导致你的状态表迅速增长。
让我们看一个示例配置。首先注意,在 /etc/rc.firewall 的顶部,已经有针对环回接口 lo0 的标准规则,因此我们不需要再关心它们。自定义规则应放在单独的文件中(例如 /etc/rc.firewall.local),并通过修改 /etc/rc.conf 文件中定义 open
防火墙的行,在系统启动时加载:
重要
必须指定 完整 路径,否则它将无法加载,可能导致你无法连接到网络。
假设我们的例子中,fxp0 接口连接到外部(Internet),xl0 接口连接到内部(LAN)。桥接器的 IP 地址是 1.2.3.4
(虽然你的 ISP 不太可能给你这样一个地址,但在本示例中它是有效的)。
之前有设置过防火墙的朋友可能会注意到有些内容缺失。特别是,没有反欺骗规则,事实上我们并没有添加:
也就是说,丢弃来自外部、声称来自我们网络的数据包。这是你常见的一种做法,用以确保有人不会通过生成看起来像是来自内部的恶意数据包,试图绕过数据包过滤器。这样做的问题在于,外部接口上至少有一台主机你不希望忽略:路由器。但通常情况下,ISP 在他们的路由器上已经做了反欺骗处理,所以我们不需要过多担心。
最后一条规则看起来是默认规则的精确副本,也就是不允许任何不被明确允许的流量通过。但有所不同的是,所有可疑流量都会被记录日志。
习惯于设置防火墙的人可能也习惯在 ident 数据包(TCP 端口 113)上使用 reset
或 forward
规则。不幸的是,桥接的情况下,这个选项不适用,因此最好的做法是简单地将这些数据包传递到它们的目的地。只要目标机器没有运行 ident 守护进程,这基本是无害的。另一种选择是丢弃端口 113 的连接,这会给像 IRC 这样的服务带来一些问题(ident 探测必须超时)。
你可能注意到的唯一有些奇怪的事情是,允许桥接机器发送流量的规则,以及允许内部主机的规则。记住,这是因为这两种流量会通过内核的不同路径并进入数据包过滤器。内部网络会通过桥接,而本地机器会使用常规的 IP 栈进行通信。因此,需要两条规则来处理这两种情况。in via fxp0
规则适用于两种路径。一般来说,如果在整个过滤器中使用 in via
规则,你需要为本地生成的数据包做一个例外,因为这些数据包并没有通过我们的任何接口进入。
本文的许多部分来自一篇旧文,内容关于桥接,由 Nick Sayer 编辑、更新和改编。灵感来源于 Steve Peterson 对桥接的介绍。
特别感谢 Luigi Rizzo,感谢他在 FreeBSD 中实现了桥接代码,并且花时间回答我关于这方面的所有问题。
同时感谢 Tom Rhodes,他审查了我将这篇文章从意大利语(原文语言)翻译成英语的工作。
现在,需要构建并安装新内核。你可以在 FreeBSD 手册的 部分找到详细说明。
有两条规则允许 SMTP 和 DNS 流量指向邮件服务器和名称服务器(如果你有这些服务器的话)。显然,整个规则集应该根据个人口味进行调整,这只是一个特定的示例(规则格式在 手册页中有准确描述)。注意,对于“relay”和“ns”规则来说,名称服务查找必须在桥接启用之前完成。这是一个确保你在正确的网络卡上设置 IP 的示例。或者,也可以指定 IP 地址而不是主机名(如果机器没有 IP 地址,则需要这样做)。