--------------------------------------------------------------------------------
目录
介绍
NAT地址池
进站连接的负载均衡
出站通讯的负载均衡
规则集实例
--------------------------------------------------------------------------------
介绍
地址池是系统提供给一组用户共享的两个或多个地址。一个地址池可以作为 rdr 规则的重定向地址、也可以作为 nat 规则的转换地址、及route-to, reply-to, and dup-to 过滤 选项的目标地址。
有四种使用地址池的方法:
bitmask - 将地址池的高位地址嫁接到被修改地址(NAT规则的源地址, rdr规则的目标地址)上。例如: 如果地址池是192.0.2.1/24 而被修改的地址是10.0.0.50, 那么得到的地址就是 192.0.2.50;如果地址池是192.0.2.1/25而被修改的地址是10.0.0.130, 那么得到的地址就是192.0.2.2。
random - 从地址池中随机选择一个地址。
source-hash - 使用一个源地址的哈希来确定使用地址池中的哪个地址。这种方法确保了一个给定的源地址总是映射到相同的池地址上。提供给哈希算法的key可以在 source-hash 关键字后以16进制格式或一个字串随意指定。默认情况下, 当每次规则集被载入时 pfctl(8) 会产生一个随机的key。
round-robin - 依次循环使用地址池内的地址。这是默认的方法, 当使用表格指定地址池时只能使用此方法。
除了round-robin方法, 地址池必须用一个 CIDR 网段表示。round-robin方法接受用一个列表或表格表示的多个地址。
sticky-address 选项可以与 random 和 round-robin 类型的地址池一同使用, 这样可以确保一个特定的源地址总是被映射到同一个转发地址上。
NAT 地址池
一个地址池可以作为 nat
规则中的转发地址。多个连接的源地址将基于选择的上述方法被转换成地址池中的一个地址。这在PF为一个非常大型的网络做NAT时很有用。因为每个转换地址容纳的被NAT的连接数是有限的, 增加额外的转换地址可以让NAT网关按比例为更多用户提供服务。(译者注:注意, 此处的"按比例"对应上句的"有限"。)
这个例子中用一个包含两个地址的地址池转换出站数据包。PF用round-robin方法依次循环地为每个出站连接转换地址。
代码: 全选
nat on $ext_if inet from any to any -> { 192.0.2.5, 192.0.2.10 }
这种方法的一个缺点是来自同一个内部地址的延续性连接并非总是被转换到同一个的转换地址上。这种情况可能导致冲突, 例如, 当web站点跟踪登录用户的IP地址时, 解决的方法是使用 source-hash方法, 这样每个内部地址总是被转换为同一个转换地址。为了完成这个目的, 地址池必须是一个CIDR网段。
代码: 全选
nat on $ext_if inet from any to any -> 192.0.2.4/31 source-hash
nat规则使用地址池 192.0.2.4/31 (192.0.2.4 - 192.0.2.5) 作为出站数据包的转换地址。 因为使用了source-hash关键字, 每个内部地址将总是被转换成同一个转换地址。
进站连接的负载均衡
地址池也可以用来完成进站连接的负载均衡。例如, 进站的web服务器连接可以被分配到一组服务器:
代码: 全选
web_servers = "{ 10.0.0.10, 10.0.0.11, 10.0.0.13 }"
rdr on $ext_if proto tcp from any to any port 80 -> $web_servers \
round-robin sticky-address
延续性的连接将被以round-robin方式重定向到这组服务器, 同时来自同一地址的连接总被分配到固定的同一台服务器。只要连接还保持着状态, 这种 "粘性连接"将一直存在。一旦状态结束, 粘性连接也不存在了, 这时来自那台主机的更多的连接将按依次循环(round robin)的方式被重新定向到下一台服务器上。
出站通讯的负载均衡
当一个固有的多路径路由协议(像 BGP4) 不可用时, 地址池和 route-to 过滤选项结合使用可以平衡两个以上的Internet链接的负载。通过使用 route-to 和一个 round-robin 型地址池, 出站连接可以被均匀地分配到多个出站路径中。
完成这个工作还需要的一条额外信息是每个Internet连接相邻路由器的IP地址。这是用来提供给 route-to 选项以控制出站数据包的目的地。
下面的例子均衡两个Internet连接的出站通讯:
代码: 全选
lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
from $lan_net to any keep state
route-to选项被用来将(从web服务器$lan_net)进入内部接口($int_if)的通讯路由到均衡(round-robin)的网关(ext_gw1和ext_gw2)上并指定了出站网络接口(ext_if1和ext_if2)。注意:route-to选项必须使用在每条用来均衡通讯的过滤规则中。回程数据包将被路由回出站使用的同一个外部接口(这由ISP完成) 并被正常地路由回内部网络。
为了确保源地址属于 $ext_if1 的数据包总是被路由到 $ext_gw1 (对 $ext_if2 和 $ext_gw2 也一样) , 下面的两行应该包含在规则集中:
代码: 全选
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 \
to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 \
to any
最终, NAT 也能被用在每个出站接口上:
代码: 全选
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
一个完整的出站通讯负载均衡的实例可能像这样:
代码: 全选
lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
# nat outgoing connections on each internet interface
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
# default deny
block in from any to any
block out from any to any
# pass all outgoing packets on internal interface
pass out on $int_if from any to $lan_net
# pass in quick any packets destined for the gateway itself
pass in quick on $int_if from $lan_net to $int_if
# load balance outgoing tcp traffic from internal network.
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto tcp from $lan_net to any flags S/SA modulate state
# load balance outgoing udp and icmp traffic from internal network
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto { udp, icmp } from $lan_net to any keep state
# general "pass out" rules for external interfaces
pass out on $ext_if1 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if1 proto { udp, icmp } from any to any keep state
pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if2 proto { udp, icmp } from any to any keep state
# route packets from any IPs on $ext_if1 to $ext_gw1 and the same for
# $ext_if2 and $ext_gw2
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any
block in on fxp0 from <spammers> to any