For the complete documentation index, see llms.txt. This page is also available as Markdown.

PF 转发

简介

办公室里运行 NAT 后,所有机器都可访问整个互联网。但如果 NAT 网关后有一台机器需要被外部访问呢?这就需要重定向。重定向允许将入站流量发送到 NAT 网关后的机器。

来看一个例子:

pass in on egress proto tcp from any to any port 80 rdr-to 192.168.1.20

这行将 TCP 端口 80(Web 服务器)的流量重定向到网络内部 192.168.1.20 的机器。如此一来,即便 192.168.1.20 位于网关之后、身处你的网络内部,外部世界也能访问它。

上面 rdr 行中的 from any to any 部分相当有用。若你知道哪些地址或子网应被允许访问端口 80 上的 Web 服务器,可在此处加以限制:

pass in on egress proto tcp from 203.0.113.0/24 to any port 80 rdr-to 192.168.1.20

这只会重定向指定子网。注意,这意味着你可以将不同的入站主机重定向到网关后不同的机器。这同样很有用。例如,只要你知道远程用户从哪个 IP 地址连接,就可让远程站点的用户使用网关上相同的端口与 IP 地址访问他们自己的桌面计算机。

pass in on egress proto tcp from 203.0.113.14 to any port 80 rdr-to 192.168.1.20
pass in on egress proto tcp from 198.51.100.89 to any port 80 rdr-to 192.168.1.22
pass in on egress proto tcp from 198.51.100.178 to any port 80 rdr-to 192.168.1.23

同一规则内也可重定向一段端口范围:

pass in on egress proto tcp from any to any port 5000:5500 \
   rdr-to 192.168.1.20
pass in on egress proto tcp from any to any port 5000:5500 \
   rdr-to 192.168.1.20 port 6000
pass in on egress proto tcp from any to any port 5000:5500 \
   rdr-to 192.168.1.20 port 7000:*

这些示例将 5000 到 5500(含)的端口重定向到 192.168.1.20

  • 规则 1 中,端口 5000 重定向到 5000,5001 重定向到 5001,依此类推。

  • 规则 2 中,整个端口范围都重定向到端口 6000。

  • 规则 3 中,端口 5000 重定向到 7000,5001 重定向到 7001,依此类推。

安全影响

重定向确有安全影响。在防火墙上开洞让流量进入受保护的内部网络,可能让内部机器遭受入侵。若流量被转发到内部 Web 服务器,而 Web 服务器守护进程又被发现存在漏洞,互联网上的入侵者便可借此攻陷该机器。入侵者由此获得通向内部网络的入口,且此入口被允许径直穿过防火墙。

通过将外部可访问的系统严格隔离在单独网络上,可将这些风险降至最低。此网络通常称为非军事区(DMZ)或专有服务网络(PSN)。这样,即便 Web 服务器被攻陷,也可通过对进出 DMZ/PSN 的流量仔细过滤,将影响限制在 DMZ/PSN 网络内。

重定向与反射

重定向规则常用于将互联网入站连接转发到内部网络或 LAN 中具有专有地址的本地服务器,例如:

但当从 LAN 上的客户端测试此重定向规则时,它并不工作。原因在于重定向规则仅对穿越指定接口(示例中为 egress,即外部接口)的数据包生效。然而,从 LAN 上的主机连接到防火墙的外部地址,并不意味着数据包真的会穿越防火墙的外部接口。防火墙上的 TCP/IP 协议栈会将入站数据包的目的地址与自身地址及别名比较,一旦数据包通过内部接口便立即识别出指向自身的连接。此类数据包物理上并未穿越外部接口,协议栈也不会以任何方式模拟这种穿越。因此,PF 在外部接口上根本看不到这些数据包,指定外部接口的重定向规则也不适用。

为内部接口添加第二条重定向规则也达不到预期效果。本地客户端连接防火墙的外部地址时,TCP 握手的首个数据包通过内部接口到达防火墙。重定向规则确实适用,目的地址被替换为内部服务器的地址。数据包经内部接口转发回内部服务器。但源地址未被转换,仍为本地客户端的地址,因此服务器将回复直接发给客户端。防火墙看不到回复,也就无法正确地反向转换。客户端从意料之外的源收到回复并将其丢弃。TCP 握手随之失败,连接无法建立。

尽管如此,让 LAN 上的客户端像外部客户端那样连接到同一台内部服务器,且对客户端透明,常常仍是所期望的。此问题有几种解决方案:

视域分离 DNS

可配置 DNS 服务器,使其对本地主机的查询响应不同于对外部查询的响应,从而让本地客户端在名称解析时获得内部服务器的地址。它们随后直接连接到本地服务器,防火墙完全不介入。由于数据包不必经过防火墙,这还能减少本地流量。

将服务器移入独立的本地网络

为防火墙增加一块额外的网络接口,并将本地服务器从客户端所在的网络移入专用网络(DMZ),即可像重定向外部连接那样重定向本地客户端的连接。使用独立网络有若干优点,包括通过将服务器与其余本地主机隔离来提升安全性。若服务器(在本例中可从互联网访问)一旦被攻陷,它也无法直接访问其他本地主机,因为所有连接都必须经过防火墙。

TCP 代理

可在防火墙上设置通用 TCP 代理,要么监听待转发端口,要么让内部接口上的连接重定向到它监听的端口。本地客户端连接防火墙时,代理接受连接,再向内部服务器建立第二条连接,并在两条连接之间转发数据。

RDR-TO 与 NAT-TO 组合

在内部接口上添加一条额外的 NAT 规则,即可实现上述缺失的源地址转换。

这会让客户端的首个数据包经内部接口转发回时再次被转换,将客户端的源地址替换为防火墙的内部地址。内部服务器会将回复发回防火墙,防火墙在转发给本地客户端时可反向执行 NAT 与 RDR 转换。这种结构相当复杂,因为每条反射连接会创建两条独立状态。须小心防止 NAT 规则应用到其他流量,例如来自外部主机(通过其他重定向)或防火墙自身的连接。注意,上面的 rdr-to 规则会让 TCP/IP 协议栈看到在内部接口上到达、目的地址位于内部网络内的数据包。

最后更新于