version 0.04
date 2004-09-27

一、前言

由於 ADSL 及 Cable Modem 的普及,越來越多企業或個人所擁有的對外連線早已超過一條了,
不管是固接還是撥接,相信不少人都在思考如何用最有效的方式將多條連線作整合,
將所有連線的使用發揮至最大極限及最佳的使用率。
除了起到負載的分攤之外,還能達到斷線備援目的,以提供更靈活的連線整合方案。

本文將以實作的方式試圖在 Linux 上做到上述要求。

二、環境

我先說明一下我的測試環境:

2.1 系統方面:
我目前測試的系統是 RedHat 9.0 Linux ,採用"伺服器"類型安裝,並沒提供 X 界面。
透過 APT 更新至最新修補,並沒安裝 distro 之外的套件。
事實上,只要實作所需的套件滿足的話,並不需要安裝任何伺服器套件。
甚至,核心版本也不需作任何修改,只是某些連線特徵會有些差異(後文[7.1]再詳述)。

2.2 網路方面:
原本的 seednet adsl 是五個 IP 撥接的, 除了之前透過 ip share 來使用外,我再起了另外一個 ppp0 界面。
此外另外再牽了一條 hinet 固一 adsl 。
如此環境,基本上能夠分別測試到如下這幾種連線方式:
* 固接(固定 IP)
* 撥接(非固定 IP)
* ip share(非固定 IP)
見圖:

/\__/\__/
              ,--| internet |--.
             /    /--/--/   
            |                   |
            |                   |
+--[seednet ADSL]           [hinet ADSL]
|      (非固定)                  (固一)
|           |               220.130.96.254
|    [ ip share ]               |
|   192.168.100.1               |
|           |                   |
|    192.168.100.2           220.130.96.21
|   +----------------------------------+
+---|    (eth1)               (eth0)   |
ppp0|         kernel 2.4.23            |
    +----------------------------------+
            (my linux box RH9.0)

2.3 測試方式
雖然,撥接adsl 都是同一設備,或許還不十分理想,目前也只能如此了...
我採用的是拔線的方式來測斷線的,暫還沒想到其他方式,或許大家可以幫忙想想的...
我的測試基本上是用 ping 來做:
* 若是 ppp 或不指定測試目標,我會用 next hop 來測。
* 否則,我會用 traceroute 找出 ISP 端機房的 router ip ,
  而不用 next hop ,是因為怕不準,比方說斷線是外部線路之類的。

若大家有更好提議,也歡迎提供....

三、設計目標

實作方案基本上要做到如下這些要求:

3.1 出向負載分流
所有連線在正常情況下,將共同分攤由內對外產生的連線流量。
對於固定連線,可指定權重(weight),否則使用相同權重( weight 1)。

3.2 斷線偵測
若有連線斷掉,需自動從路由中移除。
當連線恢復時,則自動增加路由。

3.3 進向負載分流(額外需求)
外部連線進來,儘可能的將流量分攤在每一條連線上。

四、設計構思

4.1 出向負載分流
利用 Linux iproute 程式,將每一條連線的 gateway 及其權重增加至路由表的 default route 中。
其中的固接 adsl 及 ip share 連線,需靜態指定其 gateway 位址及權重。
其餘撥接或非固接連線,則用 iproute 程式抓出當時的 gateway ,權重分配為 1 。

4.2 斷線偵測
不管是固接還是非固接連線,用手工方式(如 traceroute)抓出 ISP 端的機房 router 位址,
並確定用 ping  可以獲得回應。
然後用靜態路由指定通向 router 的 nexthop gateway ,定期使用 ping 來偵察連線。
每次偵測後都重跑 iproute 程式,並重新設定路由表。
若 ping 不成功,則抓出連線界面,且在重設路由表時忽略該界面連線。

4.3 進向負載分流(額外需求)
使用動態 dns(ddns) 將為每一界面位址分配一個 A 記錄,以達到輪詢回應結果,
從而讓不同的外部連線請求輪流使用每一條連線進入。

本實作方案中,ddns server 建議部署於外部的穩定連線的主機上。
關於動態 dns 的 server 設定,不含在本次實作方案之內。可請參考:
http://www.study-area.org/tips/ddns.htm

設計難點在於 ipshare :
其中 ipshare 部份需另行設定 nat 轉線。
否則需從清單中移除。

若 nat 設定正確,接下來的難點是獲得 ipshare 的 IP (因為也是非固接的),
這需要在外部的 web server 另行開發 php 程式來獲取(可置於 ddns server)。
關於這部份設計,請參考:
http://phorum.study-area.org/viewtopic.php?p=108638
或使用如下代碼:
----------------------- cut here ----------------------
<?php

//Get the real client IP ("bullet-proof"???)

function GetProxyIP()
{
       if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
           $ip = getenv("REMOTE_ADDR");
       else
           $ip = "unknown";
   return($ip);
}/*-------GetIP()-------*/

function GetClientIP()
{
   if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
           $ip = getenv("HTTP_CLIENT_IP");
       else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
           $ip = getenv("HTTP_X_FORWARDED_FOR");
       else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
           $ip = getenv("REMOTE_ADDR");
       else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
           $ip = $_SERVER['REMOTE_ADDR'];
       else
           $ip = "unknown";
   return($ip);
}

printf("proxy IP: ");
print_r(GetProxyIP());
printf("<br> ");
printf("client IP: ");
print_r(GetClientIP());

?>
----------------------- cut here ----------------------

五、實作指令

5.1 獲取當前各界面之 ip :
# ip address show
1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:02:44:84:26:4f brd ff:ff:ff:ff:ff:ff
    inet 220.130.96.21/24 brd 220.130.96.255 scope global eth0
3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:20:ed:36:f9:74 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.2/24 brd 192.168.100.255 scope global eth1
4: eth2: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:02:b3:4b:69:49 brd ff:ff:ff:ff:ff:ff
    inet 10.1.2.3/24 brd 10.1.2.255 scope global eth2
15: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 3
    link/ppp
    inet 210.64.33.27 peer 210.64.33.1/32 scope global ppp0

5.2 設定 ip rule :
# ip rule add pref 10 from 220.130.96.21 table 10
# ip rule add pref 20 from 192.168.100.2 table 20
# ip rule add pref 30 from 210.64.33.27 table 30

5.3 設定 ip route 各 table :
# ip route replace default via 220.130.96.254 dev eth0 table 10
# ip route replace default via 192.168.100.1 dev eth1 table 20
# ip route replace default via 210.64.33.1 dev ppp0 table 30

5.4 設定 ip route main table:
# ip route replace default
> nexthop via 220.130.96.254 dev eth0 weight 4
> nexthop via 192.168.100.1 dev eth1 weight 1
> nexthop via 210.64.33.1 dev ppp0 weight 1

5.5 檢視 main table 規則:
# ip route show
210.64.33.1 dev ppp0  proto kernel  scope link  src 210.64.33.27
192.168.100.0/24 dev eth1  scope link
220.130.96.0/24 dev eth0  scope link
10.1.2.0/24 dev eth2  scope link
169.254.0.0/16 dev eth2  scope link
127.0.0.0/8 dev lo  scope link
default
        nexthop via 220.130.96.254  dev eth0 weight 4
        nexthop via 192.168.100.1  dev eth1 weight 1
        nexthop via 210.64.33.1  dev ppp0 weight 1

5.6 刷新 route cache:
# ip route flush cache

5.7 測試及確認連線生效:
基本上,若在輸入上述命令中沒遇到 error ,那設定就已完成。
接下來可起用多個對外連線(或用 ping),
然後使用 tcpdump -i any 來查看封包是否能分攤在每一條連線上。

六、撰寫 script :
若前述設定經測試成功後,接下來就是撰寫 script 以讓工作自動進行。

6.1 configs

* 說明:
提供給其它 scripts 所需的共同變數值。

* 代碼:
----------------------- cut here ----------------------
BASH=/bin/bash
MAIL=root
SH=/bin/bash
LS=/bin/ls
GREP=/bin/grep
AWK=/bin/awk
SED=/bin/sed
HEAD=/usr/bin/head
TAIL=/usr/bin/tail
CUT=/bin/cut
CAT=/bin/cat
WC=/usr/bin/wc
TR=/usr/bin/tr
SEQ=/usr/bin/seq
SORT=/bin/sort
LSMOD=/sbin/lsmod
IP=/sbin/ip
PING=/bin/ping
IPTABLES=/sbin/iptables
ROUTE=/sbin/route
DATE=/bin/date
DHCP_DIR=/var/lib/dhcp

STATIC=./statics

INTERVAL=60 # check time interval in seconds
RUN_SCRIPT=./run_ip.sh # script to run ip route
DDNS_SCRIPT=./ddns/ddns.sh # script to run ddns update
DDNS=yes # enable/disable ddns update

#-- define public destination for ping --#
fixed_dest="http://www.54bk.com/168.95.1.1"

#-- define fixed interface & gateway --#
#-- format: "if:gw:weight [if:gw:weight]..." --#
fixed_gw="eth0:220.130.96.254:4 eth1:192.168.100.1:1"
fixed_if="$(echo -e "${fixed_gw// / }" | cut -d: -f1)"

#-- define internal interface, or comment out for none --#
int_if="eth0"

#-- statict routing dest & order --#
#-- format: "static_xxx=value; static_xxxx_order=value"
static_seed_net="139.175.0.0/16"
static_seed_net_order="eth1 eth0"
static_studyarea=140.113.27.184
static_studyarea_order="eth0 eth1"

----------------------- cut here ----------------------

* 變數設定說明:
fixed_dest=
用來作 ping 測試的外部 IP。
fixed_gw=
固定界面之閘道及權重,格式為 "界面名稱:閘道位址:權重"。
int_if=
內部界面名稱,可設定多個。該界面將不會用來設定 default route 。
INTERVAL=
偵測動作之時間間隔,以秒數作單位。
RUN_SCRIPT=
執行路由設定 script 之路逕。執行時可使用 -d 選項排除不必要之界面。
DDNS_SCRIPT=
執行動態 DNS 更新 script 之路逕。執行時可使用 -e 選項排除不必要之界面。
DDNS=
啟用或關閉 ddns 更新(yes|no)。
static_xxxxxx=
靜態路由之目的地,可為單一 IP 或 net_ID/mask 。xxxxxx 為任意名稱。
static_xxxxxx_order=
靜態路由選取的界面次序。左邊為最優,若該界面失效,則選下一個。

6.2 run_ip.sh

* 說明:
此 script 用來抓出系統全部界面及 nexthop gateway ,
並完成路由規則及路由表設定。

* 代碼:
----------------------- cut here ----------------------
#!/bin/bash
#
# script name:  run_ip.sh
# purpose:      changing route table.
# author:       netman(netman@study-area.org)
# license:      GPL(http://www.gnu.org/licenses/gpl.html)
#
# date:         2004-09-23
# version:      v0.05
#
# caveate:
#       1) tested on redhat 9.0 linux only
#       2) iproute program is required
#
#------------------------------------------------------------
# change log:
#       1) 2004-03-23 v0.01
#               * first beta release
#       2) 2004-03-24 v0.02
#               * BUGFIXED:
#                 - Add IPIF and GWIP checking before change route.
#       3) 2004-04-15 v0.03
#               * Add function:
#                 - Restart network if dead device detected.
#       4) 2004-07-07 v0.04
#               * IMPROVEMENT
#                 - Create central config file
#               * Add function:
#                 - Enable static routing
#       5) 2004-09-23 v0.05
#               * IMPROVEMENT
#                 - More accurate on deleting old rules
#                 - More accurate on deleting dead interface
#   - Add gw determining for dhcp interface
#   - Add deletion for dead route
# * BugFix
#   - Use central conf file
#   - Filter out IPv6 address
#
#------------------------------------------------------------

WD=${0%/*}
CONFIG=$WD/configs
[ -f $CONFIG ] && . $CONFIG || {
        echo "${0#*/}: ERROR: can not load $CONFIG."
        exit 1
}

#-- route command prefix --#
DEFGW='/sbin/ip route replace default'

#-- define dead interface --#
while getopts "d:" opt; do
        case $opt in
                d) dead_dev=$OPTARG ;;
        esac
done

#-- determine active interfaces --#
interfaces=$($IP address | $GREP -E 'ppp|eth' |
$AWK -F': ' '/^[0-9][0-9]*:/{print $2}' | $SORT -u
| grep -Ev "${int_if// /|}")

#-- remove old rule table --#
for i in $interfaces; do
$IP address | $GREP -A2 $i | $AWK '/inet[^6]/{print $2}' | $CUT -d'/' -f1
done | xargs -n1 echo from | while read line; do
$IP rule | grep "$line"
done | $SED -e "s/^/ip rule del pref /;s/://;s/lookup/table/" | $BASH
unset i

#-- remove dead interfaces --#
if [ -n "$dead_dev" ]; then
        interfaces=$(echo "$interfaces" | grep -Ev "${dead_dev// /|}")
for dev in $dead_dev; do
DEF_ROUTE=$($IP route list | grep '^default' | grep "dev $dev")
echo "$DEF_ROUTE" | while read line; do
$IP route del $line
done
done
fi

#-- exit while all dead --#
[ "$interfaces" ] || {
$IP route del default
exit 2
}

#-- define table_id --#
init_num=10
offset=`echo -e "${interfaces// / }" | $WC -l`
last_num=$(($init_num + $((offset * 10)) ))
tb_num=`$SEQ -s ' ' $init_num 10 $last_num`

#-- FUNCTION: determine DHCP assigning gw --#
dhgw() {
    get_lastest () {
OIFS="$IFS"
IFS='
'
for line in $RnT1 $RNT2; do
l="$(echo $line | grep -o 'lease-time[^;]*' | cut -d' ' -f2)"
r="$(echo $line | grep -o 'routers[^;]*' | cut -d' ' -f2)"
e="$(echo $line | grep -o 'expire[^;]*' | cut -d' ' -f3-)"
EX_TIME=$($DATE -d "$e" +%s)
if [ "$((EX_TIME - l))" -gt "${P_TIME-0}" ]; then
P_TIME=$((EX_TIME-l))
D_TIME=$EX_TIME
ROUTER=$r
fi
done
IFS="$OIFS"
echo $D_TIME $ROUTER
    }

DH_IF=$1
shift 1
RnT1=$($CAT $1 2>/dev/null | xargs echo | tr '}{' ' ' | $GREP $DH_IF | $TAIL -n 2)
RnT2=$($CAT $1 2>/dev/null | xargs echo | tr '}{' ' ' | $GREP $DH_IF | $TAIL -n 2)
[ "$RnT1" -o "$RnT2" ] || return
GnT=$(get_lastest)
C_TIME=$($DATE +%s)
[ "${GnT% *}" -gt $C_TIME ] && GWIP=${GnT#* }
}

#-- FUNCTION: determine gw --#
dgw() {
unset GWIP
        #-- for fixed if --#
        if echo $fixed_if | $GREP -wq $1 ; then
                GWIP=`echo -e "${fixed_gw// / }" | $GREP "^$1:" |
                        $CUT -d: -f2`
                WEIGHT=`echo -e "${fixed_gw// / }" | $GREP "^$1:" |
                        $CUT -d: -f3`
        #-- for ppp if --#
        elif echo $1 | $GREP -q ppp ; then
                GWIP="`$IP address show dev $1 | $AWK '/inet[^6]/{print $4}' |
                        $CUT -d'/' -f1 | $HEAD -n 1`"
else
#-- try current gw --#
GWIP=$($ROUTE -n | $GREP $1'$' | $AWK '/^0.0.0.0/{print $2}' | $HEAD -n 1)
fi
#-- for dhcp if --#
[ "$GWIP" ] || dhgw $1 $DHCP_DIR/dhclient.leases $DHCP_DIR/dhclient-$i.leases
}

#-- config rule & routing --#
for i in $interfaces ; do
        unset IFIP GWIP WEIGHT
        IFIP="`$IP address show dev $i | $AWK '/inet[^6]/{print $2}' |
                $CUT -d'/' -f1`"
        dgw $i
        [ "$tb_num" ] && tb_id=${tb_num%% *}
        [ "$IFIP" -a "$GWIP" ] || continue
# check gw
        $IP route replace $fixed_dest via $GWIP dev $i &>/dev/null &&
        sleep 2; $PING -c1 -w2 $fixed_dest &>/dev/null && GWOK=true
        $IP route del $fixed_dest via $GWIP dev $i &>/dev/null
if [ "$GWOK" = true ]; then
unset GWOK
else
continue
fi
        # set rule
        $IP rule add pref $tb_id from $IFIP table $tb_id
        # set route to gw
        $IP route replace default via $GWIP dev $i table $tb_id
        DEFGW=$DEFGW" nexthop via $GWIP dev $i weight ${WEIGHT:=1}"
SETGW=true
        tb_num=${tb_num#* }
done

#-- apply routing --#
[ "$SETGW" = true ] && {
#-- remove old default route --#
DEF_NU=$($IP route | $GREP -c '^default')
for ((i=1;i<=$DEF_NU;i++)); do
$IP route del default
done
#-- set new default route --#
$DEFGW
}

#-- apply static routes  --#
[ -f $STATIC ] && . $STATIC

#-- flush cache --#
$IP route flush cache

#-- show routing
$IP route list

#-- FINISH --#
exit 0

----------------------- cut here ----------------------

* 參數說明:
-d "<interface...>"
指定失效界面,可設定多個。

6.3 statics

* 說明:
此 script 用來設定靜態路由,封包將只會從單一連線送出,而不會分攤至其他連線。

* 代碼:
----------------------- cut here ----------------------
#!/bin/bash
#
# script name:  statics
# purpose:      set static routes.
# author:       netman(netman@study-area.org)
# license:      GPL(http://www.gnu.org/licenses/gpl.html)
#
# date:         2004-09-23
# version:      v0.02
#
# caveate:
#       1) tested on redhat 9.0 linux only
#       2) iproute program is required
#
#------------------------------------------------------------
# change log:
#       2004-07-08 v0.01
#               * first beta release2
#       2004-09-23 v0.02
#               * Improvment:
# - using flexible static_xxxx variable

WD=${0%/*}
CONFIG=$WD/configs
[ -f $CONFIG ] && . $CONFIG || {
        echo "${0#*/}: ERROR: can not load $CONFIG."
        exit 1
}

set_static () {
while [ "$2" ]; do
eval s_dest=$$1
eval s_order=$$2
all_gw="$($IP route show | $SED -n '/^default/,$p')"
for if in $s_order; do
if echo "$all_gw" | $GREP -q "$if" ; then
sn_gw=$(echo "$all_gw" | $GREP $if | awk '{print $3}')
sn_gw=${sn_gw%/*}
break
fi
done
[ "$sn_gw" ] && {
$IP route replace "$s_dest" via $sn_gw
}
shift 2
done
}
set_static ${!static_*}

----------------------- cut here ----------------------

* 注意要點:
此 script 可由 run_ip.sh 來呼叫,也可以獨立使用。

6.4 chk_line.sh

* 說明:
此 script 用來偵測連線是否正常,並定期執行 run_ip.sh 及 ddns.sh(選用)。
若抓出失效界面,再用 -d 參數傳給 run_ip.sh ,該界面將被忽略。

* 代碼:
----------------------- cut here ----------------------
#!/bin/bash
#
# script name:  chk_ip.sh
# purpose:      checking outbound link and change route and dns.
# author:       netman(netman@study-area.org)
# license:      GPL(http://www.gnu.org/licenses/gpl.html)
#
# date:         2004-09-23
# version:      v0.04
#
# caveate:
#       1) tested on redhat 9.0 linux only
#       2) using PING for link detection
#       3) iproute program is required
#       4) scripts run_ip.sh & ddns.sh are required too
#
#------------------------------------------------------------
# change log:
#       1) 2004-03-23 v0.01
#               * first beta release
#       2) 2004-03-24 v0.02
#               * add script path detection
#       4) 2004-07-07 v0.03
#               * IMPROVEMENT
#                 - Create central config file
#               * Add function:
#                 - Add email notification
#       5) 2004-09-23 v0.04
#               * IMPROVEMENT
#                 - Rewrite the method of getting dead interface
#
#------------------------------------------------------------

WD=${0%/*}
CONFIG=$WD/configs
[ -f $CONFIG ] && . $CONFIG || {
        echo "${0#*/}: ERROR: can not load $CONFIG."
        exit 1
}

# change working directory
cd $WD

#-- determine gateways --#
get_gw () {
        defaults=$($IP route show | $SED -n '/default/,$p' | $GREP via)
        if_n_gw=$(echo -en "$defaults" | $AWK '{print $5":"$3":'$fixed_dest'"}')
        if [ -n "$fixed_gw" ]; then
fixed_pair=$(echo -e "${fixed_gw// / }" | awk -F: '{print $1":"$2":'$fixed_dest'"}')
dyn_pair=$(echo "$if_n_gw" | $GREP -Ev "$(echo $fixed_if | $TR ' ' '|')")
        all_pair=$(echo $fixed_pair $dyn_pair)
else
        all_pair=$(echo "$if_n_gw")
fi
}

#-- configure static route --#
get_dev () {
        for i in "$@"; do
                if=${i%%:*}
                gw=$(echo $i | $CUT -d: -f2)
                dest=${i##*:}
                $IP route replace $dest via $gw dev $if &&
sleep 1; $PING -c1 -w2 $dest &>/dev/null || echo $if
                $IP route del $dest via $gw dev $if
        done
        unset i
}

#-- run loop --#
while : ; do
        get_gw                  # have gw
        d_dev=$(echo $(get_dev $all_pair)) # have dead link

[ "$d_dev" ] && { # send mail if dead link found
                echo "dead link found: $d_dev" |
                mail -s "$(hostname): dead link" $MAIL
        }

$SH $RUN_SCRIPT -d "$d_dev" # to run ip script

[ -f "$DDNS_SCRIPT"  -a "$DDNS" = yes ] && $SH $DDNS_SCRIPT

unset all_pair
        sleep $INTERVAL
done

----------------------- cut here ----------------------

6.5 ddns/ddns.sh (選用項目)

* 說明:
此 script 用來動態偵測連線位址,並動態更新 dns 位址記錄。

* 代碼:
----------------------- cut here ----------------------
#!/bin/bash
#
# script name: ddns.sh
# purpose: updating dns record
# author: netman(netman@study-area.org)
# license: GPL(http://www.gnu.org/licenses/gpl.html)
#
# date: 2004-09-25
# version: v0.04
#
# caveate:
# 1) tested on redhat 9.0 linux only.
# 2) iproute program is required.
# 3) a php webpage to show ip, and the lynx program are required.
# 4) ddns server and ddns key are required.
#
#------------------------------------------------------------
# change log:
# 1) 2004-03-23 v0.01
# * first beta release
# 2) 2004-03-23 v0.02
# * add EXCL_IF list for exception
# 3) 2004-03-23 v0.03
# * add -e option for appending EXCL_IF
# 4) 2004-09-25 v0.04
# * BugFix: detect gw interface list
#
#------------------------------------------------------------

# set commands
HOST=/usr/bin/host
GREP=/bin/grep
CAT=/bin/cat
IP=/sbin/ip
SED=/bin/sed
AWK=/bin/awk
LYNX=/usr/bin/lynx
TOUCH=/bin/touch
DIFF=/usr/bin/diff
NSUPDATE=/usr/bin/nsupdate
MV=/bin/mv

# set variables
if echo $0 | $GREP '^/' ; then
    w_dir=${0%/*}
else
    w_dir=$PWD/${0%/*}
fi
KEY_FILE=$w_dir/Ktestddns.+157+14615.key
UPDATE_DATA=$w_dir/nsupdate.data
UPDATE_OLD=$UPDATE_DATA.old
HOST_NAME=testddns.study-area.org
NS_SERVER=dns.study-area.org # don't use IP address
IP_SERVER=dns.study-area.org # server running ip.php program
IP_SERVER_IP=$(echo $($HOST $IP_SERVER) | tail -n 1 | $AWK '{print $NF}')
IP_URL="http://$IP_SERVER/ip.php"
CLIENT_TYPE="client" # no proxy or using ISP's proxy
#CLIENT_TYPE="proxy" # use local proxy
MASQ_IF="eth1" # which masqueraded behine NAT
#EXCL_IF="eth1" # note: also use -e options to append list

# have exception
while getopts "e:" opt; do
    case $opt in
e) EXCL_IF=$(echo $EXCL_IF $OPTARG) ;;
    esac
done

# ensure key files
for file in $KEY_FILE ${KEY_FILE%key}private
do
    if [ ! -r $file ]; then
echo "$(basename $0): ERROR: $file is not readable."
exit 1
    fi
done

# ensure the server is connectable
$HOST $NS_SERVER $NS_SERVER | $GREP -q "^$NS_SERVER has address" || {
    echo "$(basename $0): ERROR: could not contact nameserver $NS_SERVER."
    exit 2
}

# prepare initial script
$CAT >| $UPDATE_DATA < > $UPDATE_DATA
echo "send" >> $UPDATE_DATA

# do a test then update
$TOUCH $UPDATE_OLD
if ! $DIFF $UPDATE_OLD $UPDATE_DATA; then
$NSUPDATE -k $KEY_FILE -v $UPDATE_DATA && {
$MV $UPDATE_DATA $UPDATE_OLD
}
fi

#-- end of script --#

----------------------- cut here ----------------------

* 變數設定說明:
KEY_FILE=
用以更新 dns 記錄的 key 。
UPDATE_DATA=
儲存 nsupdate 所需的命令稿。
UPDATE_OLD=
上一次 nsupdate 所需的命令稿。
script 會比對前一份命令稿內容,若相同,則不做 update ,否則才做。
HOST_NAME=
主機名稱。需與 ddns 所設定的記錄一致。
NS_SERVER=
ddns server 之主機名稱,不能使用 IP 位址。
IP_SERVER=
偵測 IP 用的主機名稱。
IP_SERVER_IP=
偵測 IP 用的主機位址。
IP_URL=
偵測 IP 用的網頁 URL 。
CLIENT_TYPE=
主機連線類型。其值為 "client" 或 "proxy" 二者之一。
若主機沒有使用 proxy 或使用 ISP 提供的 proxy,請設為 "client"。
若主機使用 local LAN 的 proxy ,則請設為 "proxy"。
MASQ_IF=
連線將會經過 NAT 的界面,但其偽裝位址需作 ddns 更新。
(注意:NAT 必須要有相應的 port mapping 設定。)
EXCL_IF=
排除在 ddns 更新之外的界面。
通常是連線將會經過 NAT 的界面,但其偽裝位址不作 ddns 更新。

* 參數說明:
-e "<interface...>"
排除在 ddns 更新之外的界面,可設定多個。
若為多個界面,其值必須至於雙引號(" ")或單引號(' ')之中,如:
-e "eth0 eth1"
參數值將會擴充至 $ESCL_IF 變數裡面。

* 注意要點:
1) 關於動態 ddns 的 server 及 client 端設定,請另行參考:
http://www.study-area.org/tips/ddns.htm
2) 請定期檢測及確認 ddns server 能夠連線及正常咦鳌

<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>

阅读(543) | 评论(0) | 转发(0) |

0

上一篇:定义linux console下面的热键(转coolend)

下一篇:流量控制系列手册页:tc

相关热门文章
  • 高速免费上网轻松搞定 8500WN...
  • ipad 开发让生活中可以任意使...
  • SDH点对点接入与MPLS-VPN的区...
  • 买了二手车 先做5件事...
  • 电热水壶在生活中占据重要位置...
  • linux 常见服务端口
  • 什么是shell
  • linux socket的bug??
  • linux的线程是否受到了保护?...
  • 一个适用于windows和linux的抓...
  • 制作jffs2文件系统
  • make命令详解
  • nagios 进程突然增多一个...
  • 第七章 进程调度
  • ubuntu安装tftp服务器
给主人留下些什么吧!~~
评论热议

linux下等值多重路由(转netman)相关推荐

  1. Linux下备份cisco路由配置

    TFTP (普通文件传输协议或一般文件传输协议) 大家一定记得在2003年8月12日全球爆发冲击波(Worm.Blaster)病毒,这种病毒会监听端口69,模拟出一个TFTP服务器,并启动一个***传 ...

  2. ubuntu系统写路由指令_ubuntu/linux下设置永久路由

    很多时候,为了安全,我们会划分内网外网,看来网上很多资料,几乎都是1.2.3,我以为是三步走呢,原来只要执行一个就好了~ 方法一:修改rc.local,写在exit 0 前面啊~ 实测,成功~ sud ...

  3. linux下设置永久路由

    1.在/etc/rc.local里添加 方法: route add -net 192.168.3.0/24 dev eth0 route add -net 192.168.2.0/24 gw 192. ...

  4. linux下添加路由的方法

    Linux中增加软路由的两种方法 第一种: route add -net 172.16.6.0 netmask 255.255.255.0 gw 172.16.2.254 dev eth0 /* 增加 ...

  5. linux 下添加,修改,删除路由

    在日常生活中,或者在服务器中,有多个网卡配置多个地址,访问不同的网络段,这种情况是非常常见的现象,这个时候我们就需要添加多个路由来实现多网络段的通行. 一.设置当前终端路由(再开机就没效了) 1.显示 ...

  6. 在linux下添加路由

    linux下添加路由的方法: 一:使用 route 命令添加 使用route 命令添加的路由,机器重启或者网卡重启后路由就失效了,方法: //添加到主机的路由 # route add –host 19 ...

  7. linux gateway添加,linux下添加路由的方法:

    linux下添加路由的方法: 一:使用 route 命令添加 使用route 命令添加的路由,机器重启或者网卡重启后路由就失效了,方法: //添加到主机的路由 # route add –host 19 ...

  8. linux下static状态,关于linux的添加永久静态路由的static-routes方法

    一:使用 route 命令添加 使用route 命令添加的路由,机器重启或者网卡重启后路由就失效了,方法: //添加到主机的路由 # route add –host 192.168.1.11 dev ...

  9. Linux中增加软路由的两种方法,Linux中增加软路由的三种方法

    # route add –net IP netmask MASK eth0 # route add –net IP netmask MASK gw IP # route add –net IP/24 ...

最新文章

  1. windows安装oracle11g
  2. 学习打卡-2018/08/09
  3. 3分钟看完Build2016 Day 1 Keynote
  4. 程序员九重镜界,很老的今天刚刚翻出来
  5. JVM学习笔记-04-java历史-沙箱安全机制
  6. arduino COM口被占用问题解决
  7. Open Graphics Library初步_搭建环境_GLUT
  8. 深度神经进化大有可为?Uber详解如何用它优化强化学习 | 5篇论文
  9. ValueError: No JSON object could be decoded?此种异常的解决方案之一
  10. GJB150.5A-2009军用装备实验室温度冲击环境试验
  11. 通过图片url 获取图片file对象
  12. 新的Steam控制器,ScummVM上的Sherlock Holmes以及更多开放游戏新闻
  13. 什么是5G技术-认识5G
  14. Unity RPG 黑暗之光 问题记录 上 (1-63 地形场景 角色选择 行走 相机跟随、旋转、缩放 任务系统 面板栏 背包系统 状态系统)
  15. 现在大多数论文存在的弊病——可重复性
  16. Mac系统如何显示隐藏文件
  17. 享受科研,心怀远方:青年学者刘元玮的成长之路
  18. pygame 窗口标题和图标设置
  19. Binutils 相关工具记录
  20. 电子面单接口申请对接(返回电子面单模板)

热门文章

  1. 庆贺:D900系统终于稳定功能满足需要
  2. 网易云音乐怎么剪辑音乐并保存,酷狗音乐怎么截取一段音乐并保存
  3. 判断链表是否有环,并且找出链表环的接点
  4. mysql中三目运算_mysql三目运算使用示例
  5. 夏日街头新风尚 | 变色镜片
  6. java jhat_java命令--jhat命令使用
  7. Jquery cookies 设置1小时后失效
  8. MySQL 慢查询日志如何查看及配置
  9. 一款简单好用的Unity任务系统
  10. 国家医保补助的慢性病有哪些?如何申请慢性疾病的医保补助?