|
Description :
上星期做了在 兩條 ADSL 上自動切換路由 的測試後,有個朋友就跟我說光兩條線路做 Redundant 是不是有點浪費?我想想也對,於是我想到了FreeBSD 中的 PF 有個 round-robin 的功能,它可做 Triffic Outgoing 的 Load Balancing 流量平均的分配,因此再把這功能的應用加上,這下子不但不會斷線還可以於平常就同時使用兩條 ADSL,真的太棒了 ^^
這次的 shell script 有些許的改變,我還是使用 ping 的方式來判斷是否斷線,但是所 ping 的標地物 IP 改變了,不再是 ping 固網的 DNS,而是改 ping 固網內部的 ADSL 之 ATM 設備的虛擬 IP 為判斷標準,這樣的用意是讓我們在切換路由到另一家固網時才能精準判斷是否 100% loss。
以下我只把使用過的設定檔 pf.conf、pf2.conf 及 loadsharing.sh 這個 shell script 檔貼出來,至於 Firewall + NAT 的安裝過程就不贅述,請參考之前的文章:兩條 ADSL 上自動切換路由 。
Environment :
硬體:i386 PC Intel P3 500 記憶體網卡:512M RAM 作業系統:FreeBSD 6.0 Release 網路卡三片:xl0 vr0 兩片對外 de0 一片對內
Drawing :

Hinet ADSL ATM 內部的虛擬 IP:10.88.88.56 ext_gw1:210.xx.xx.254 xl0:210.xx.xx.8 de0:10.77.77.254 TFN ADSL ATM 內部的虛擬 IP:10.36.128.10 ext_gw2:61.xx.xx.254 vr0:61.xx.xx.6
Setp 1.
#vi /usr/local/sbin/loadsharing.sh # 開始編寫 5 秒鐘於背景跑一次的 shell script
#!/bin/sh
H_ATM_IP="10.88.88.50" H_GW1_IP="210.xx.xx.254" H_EXT_IP="210.xx.xx.8" T_ATM_IP="10.36.128.10" T_GW2_IP="61.xx.xx.254" T_EXT_IP="61.xx.xx.6"
active="P"
while [ 1 ]; do STATUS1=`ping -c 1 $H_ATM_IP |grep loss |awk '{ print $7; }'` STATUS2=`ping -c 1 $T_ATM_IP |grep loss |awk '{ print $7; }'`
if [ "$STATUS1" = "100%" ]; then if [ "$STATUS2" = "100%" ]; then # ALL line down if [ "$active" = "P" ]; then echo -e "\n\ ALL ADSL DOWN!\n\ Date: $(date)\n\ Host: $(hostname)\n\ " | /usr/bin/mail -s "$(date) ALL ADSL DOWN!" root active="S" else echo -e "ALL ADSL DOWN!" fi else # Hinet down, TFN up if [ "$active" = "P" ]; then echo -e "\n\ ADSL $H_ATM_IP DOWN!\n\ Date: $(date)\n\ Host: $(hostname)\n\ " | /usr/bin/mail -s "$(date) ADSL Hinet DOWN!" root route delete -net 0.0.0.0 route add -net 0.0.0.0 -gateway $T_GW2_IP pfctl -f /etc/pf2.conf active="S" else echo -e "Hinet ADSL DOWN!" fi fi else if [ "$STATUS2" = "100%" ]; then # Hinet up, TFN down if [ "$active" = "P" ]; then echo -e "\n\ ADSL $T_ATM_IP DOWN!\n\ Date: $(date)\n\ Host: $(hostname)\n\ " | /usr/bin/mail -s "$(date) ADSL TFN DOWN!" root route delete -net 0.0.0.0 route add -net 0.0.0.0 -gateway $H_GW1_IP pfctl -f /etc/pf2.conf active="S" else echo -e "TFN ADSL DOWN!" fi else # All line up if [ "$active" = "S" ]; then echo -e "\n\ ALL ADSL UP!\n\ Date: $(date)\n\ Host: $(hostname)\n\ " | /usr/bin/mail -s "$(date) ALL ADSL UP!" root pfctl -f /etc/pf.conf active="P" else echo -e "ALL ADSL UP!" fi fi fi sleep 5 done
#chmod 755 /usr/local/sbin/loadsharing.sh # 改變權限更改為可執行
Setp 2.
#vi /etc/pf.conf # PF 設定檔,讓兩片對外的網卡流量負載平衡
lan_net="10.77.77.0/24" ext_if1="xl0" ext_if2="vr0" int_if="de0" ext_gw1="210.xx.xx.254" ext_gw2="61.xx.xx.254" tcp_services= "{ 22, 113 }" # # 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 # pass in on $ext_if1 inet proto tcp from any to ($ext_if1) \ port $tcp_services flags S/SA keep state pass in on $ext_if2 inet proto tcp from any to ($ext_if2) \ port $tcp_services flags S/SA keep state
#vi /etc/pf2.conf # PF 的一般設定,這邊是做為有斷線時所切換採用的 rule
ext_if1="xl0" ext_if2="vr0" int_if="de0" # nat on $ext_if1 from $int_if:network to any -> ($ext_if1) nat on $ext_if2 from $int_if:network to any -> ($ext_if2) rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021 # pass in all pass out all
Setp 3.
#sh -x /usr/local/sbin/loadsharing.sh # 可測試 debug 程式 #sh /usr/local/sbin/loadsharing.sh & # 讓程式在背景跑
#vi /usr/local/etc/rc.d/boot_loadsharing.sh # 簡易的開機自動啟動讓程式跑在背景
sh /usr/local/sbin/loadsharing.sh &
|