在默认情况下,操作系统使用路由表决定某个 IP 数据包的下一跳。而使用路由表只能基于数据包的目的地址来决定路由。 一些防火墙实现支持将匹配到的数据包置于指定的路由,而不遵循系统的路由表。由于防火墙软件支持十分详尽的规则来匹配数据包,这样相比使用路由表更加灵活。这种路由方式称为基于策略的路由(Policy-based routing)。
考虑以下场景
某个路由器有一个内网(LAN)接口 rl0,IP 地址为 192.168.120.1/24,以及两个用作外网(WAN)用途的网络接口 bge0 和 bge1,其IP地址分别为 10.1.101.12/24 和 172.18.10.220/20。访问私有和公开网络资源都通过接口 bge0 使用路由器 10.1.101.1 作为默认路由。
因为某些奇怪的原因,需要将来自 LAN 访问 172.24.0.0/16 的 TCP 22 端口的数据包的下一跳路由改为 172.18.8.1。
使用以下规则来实现:
pass in quick route-to bge1:172.18.8.1 on rl0 proto tcp from 192.168.120.1/24 to 172.24.0.0/16 port = 22
现需要将这个路由器的两个 WAN 接口上传入的 TCP 80 请求转发到 LAN 中的一个 HTTP 服务(主机 192.168.120.6,端口 TCP 80)。设置 DNAT 规则以实现该转发:
rdr rge0 from any to 10.1.101.12 port = 80 -> 192.168.120.6 port 80 tcp rdr rge1 from any to 172.18.10.220 port = 80 -> 192.168.120.6 port 80 tcp
因为该路由器的默认路由是 10.1.101.1,接口 rge0;可以期待从此接口传入的请求将能够正常建立 TCP 连接。然而从 rge1 传入的请求通常将不能工作。因为当有来自外部的客户端,例如 116.62.123.0,发出了 TCP 请求(例如 TCP SYN),192.168.120.6 上的服务将正常对这个来源地址进行回复(例如 TCP ACK),而这个回复将被路由器 192.168.120.1 路由到 rge0 上的 10.1.101.1。由于此回复数据包的来源地址与当初发送请求的目的地址不同,客户端操作系统将会丢弃这个回复。
使用一个 SNAT 规则将从 rge1 传入 192.168.120.6:80 的数据包的来源地址更改为路由器自己在 LAN 接口的地址 192.168.120.1,就可以使相应的 TCP 通信正常工作。但是这样做将会使原始的来源地址丢失—— 192.168.120.6 上的 HTTP 守护进程将会看到相应请求来自 192.168.120.1,而不是真实的来源 IP 地址。
根据此需求,当路由器遇到来自 rge1 往 192.168.120.6:80 的 TCP SYN 请求时,需要将这个连接的所有回复数据包都路由到 rge1,而不走路由表。
pass in quick reply-to rge1:172.18.8.1 on rge1 proto tcp from any to 192.168.120.6 port = 80 flags S/FSRPAU keep state
为了过滤出某个 TCP 连接所有的回复数据包,防火墙软件需要在连接建立时记住这个 TCP 连接;使用选项 flags S/FSRPAU 来匹配 TCP SYN 包(TCP 连接的开始),再使用选项 keep state 要求保持对这个 TCP 会话的追踪,否则使用 reply-to 没有意义。