這裡講述 PF “負載均衡”的功能與實現
簡介
地址池是提供2個以上的地址供一組用戶共享的。
地址池可以是:
rdr規則中的重定向地址
nat規則中的轉換地址
route-to,reply-to,dup-tofilter選項中的目的地址。
有4種使用地址池的方法:
*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
使用源地址hash來確定使用地址池中的哪個地址。這個方法保證給定的源地址總是被映射到同一個地址池。Hash算法的種子可以在source-hash關鍵字後通過16進制字元或者字元串來指定。默認情況下,pfctl 在規則集裝入時會隨機產生種子。
*round-robin
在地址池中按順序循環,這是默認方法,也是表中定義的地址池唯一的方法。
除了 round-robin 方法,地址池的地址必須表達成 CIDR(ClasslessInter-DomainRouting)的網路地址族。round-robin 方法可以接受多個使用列表和表的單獨地址。
sticky-address 選項可以在 random 和 round-robin 池類型中使用,保證特定的源地址始終映射到同樣的重定向地址。
NAT地址池
地址池在 NAT 規則中可以被用做轉換地址。連線的源地址會被轉換成使用指定的方法從地址池中選擇的地址。這對於 PF 負載一個非常大的網路的 NAT 會非常有用。由於經過 NAT 的連線對每個地址是有限的,增加附加的轉換地址允許 NAT 網關增大服務的用戶數量。
在下面的例子中,2個地址被用來做輸出數據包的轉換地址。對於每一個輸出的連線,PF按照順序循環使用地址。
nat on $ext_if inet from any to any -> { 192.0.2.5,192.0.2.10 }
這個方法的一個缺點是成功建立連線的同一個內部地址不會總是轉換為同一個外部地址。這會導致衝突,例如:瀏覽根據用戶的ip地址跟蹤登錄的用戶的web站點。一個可選擇的替代方法是使用 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
成功的連線將按照順序重定向到web伺服器,從同一個源到來的連線傳送到同一個伺服器。這個 sticky connection 會和指向這個連線的狀態一起存在。如果狀態過期,sticky connection 也過期。那個主機的更多連線被重定向到按順序的下一個web伺服器。
輸出流量負載均衡
地址池可以和 route-to 過濾選項聯合使用,在多路徑路由協定(例如BGP4)不可用是負載均衡2個或者多個網際網路連線。通過對 round-robin 地址池使用 route-to,輸出連線可以平均分配到多個輸出路徑。
需要收集的附加的信息是鄰近的網際網路路由器IP位址。這要加入到 route-to 選項後來控制輸入數據包的目的地址。
下面的例子通過2條到網際網路的連線平衡輸出流量:
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選項用來在收到流量的內部接口上指定平衡的流量經過各自的網關到輸出的網路接口。注意route-to選項必須在每個需要均衡的過濾規則上出現。返回的數據包會路由到它們出去時的外部接口(這是由ISP做的),然後正常路由回內部網路。
要保證帶有屬於$ext_if1源地址的數據包總是路由到$ext_gw1($ext_if2和$ext_gw2也是同樣的),下面2行必須包括在規則集中:
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 on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
block in from any to any
block out from any to any
pass out on $int_if from any to $lan_net
pass in quick on $int_if from $lan_net to $int_if
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 modulatestate
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
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
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