Next Previous Contents

14. 劍譜 (Cookbook)

本章所包含的 '劍譜' 單元﹐應可讓您依招式克敵制勝。然而﹐離開了原理的基本功夫﹐光練招而不練氣﹐縱有劍譜也枉然。所以﹐請先溫故而知新。

14.1 以不同的 SLA 來跑多個站點 (Running multiple sites with different SLAs)

您可以用好多方法來做啦。Apache 就可以透過模組來達到某些支援﹐不過我們這裡要教您用 Linux 怎樣做﹐並且舉一反三﹐將其它服務也一併搞定。這些命令都偷師自下面提到的 Jamal Hadi 的演講 。

假設我們有兩個客戶﹐要提供 http、ftp、還有 streaming audio 服務﹐我們只打算賣給他們一定數量的頻寬而已。那我們可以在伺服器上面做手腳。

客戶 A 最多只有 2 megabits﹐而客戶 B 已經支付 5 megabits 的錢了。那我們在伺服器上建立虛擬 IP 位址﹐來將客戶分開來。

# ip address add 188.177.166.1 dev eth0
# ip address add 188.177.166.2 dev eth0

以哪些適合的位址來分配給不同的伺服器﹐則悉從尊便了。所有常用 daemon 都支援這玩意。

接著﹐我們首先將 CBQ adisc 指派給 eth0﹕

# tc qdisc add dev eth0 root handle 1: cbq bandwidth 10Mbit cell 8 avpkt 1000 \
  mpu 64

然後﹐為我們的客戶建立類別(classes)﹕

# tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate \
  2MBit avpkt 1000 prio 5 bounded isolated allot 1514 weight 1 maxburst 21
# tc class add dev eth0 parent 1:0 classid 1:2 cbq bandwidth 10Mbit rate \
  5Mbit avpkt 1000 prio 5 bounded isolated allot 1514 weight 1 maxburst 21

再來﹐我們為這兩個類別增加過濾器﹕

##FIXME: Why this line, what does it do?, what is a divisor?:
##FIXME: A divisor has something to do with a hash table, and the number of
##       buckets - ahu
# tc filter add dev eth0 parent 1:0 protocol ip prio 5 handle 1: u32 divisor 1
# tc filter add dev eth0 parent 1:0 prio 5 u32 match ip src 188.177.166.1
  flowid 1:1
# tc filter add dev eth0 parent 1:0 prio 5 u32 match ip src 188.177.166.2
  flowid 1:2

這樣﹐就大功告成了啦。

FIXME: 為何不用 token bucket 過濾器﹖還是預設的 pfifo_fast 撤出了﹖

14.2 幫貴主機抵禦 SYN floods (Protecting your host from SYN floods)

根據 Alexey 的 iproute 文件﹐已可以和 netfiler 搭配了﹐且有好些看來不錯的途經。如果您要使用這個﹐請小心調整那些數字﹐針對您的系統給予合理的數值。

假如您想要保護整個網路﹐可以跳過這裡﹐這裡是針對單一主機而已的。

#! /bin/sh -x
#
# sample script on using the ingress capabilities
# this script shows how one can rate limit incoming SYNs
# Useful for TCP-SYN attack protection. You can use
# IPchains to have more powerful additions to the SYN (eg 
# in addition the subnet)
#
#path to various utilities;
#change to reflect yours.
#
TC=/sbin/tc
IP=/sbin/ip
IPTABLES=/sbin/iptables
INDEV=eth2
#
# tag all incoming SYN packets through $INDEV as mark value 1
############################################################ 
$iptables -A PREROUTING -i $INDEV -t mangle -p tcp --syn \
  -j MARK --set-mark 1
############################################################ 
#
# install the ingress qdisc on the ingress interface
############################################################ 
$TC qdisc add dev $INDEV handle ffff: ingress
############################################################ 

#
# 
# SYN packets are 40 bytes (320 bits) so three SYNs equals
# 960 bits (approximately 1kbit); so we rate limit below
# the incoming SYNs to 3/sec (not very useful really; but
#serves to show the point - JHS
############################################################ 
$TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 1 fw \
police rate 1kbit burst 40 mtu 9k drop flowid :1
############################################################ 


#
echo "---- qdisc parameters Ingress  ----------"
$TC qdisc ls dev $INDEV
echo "---- Class parameters Ingress  ----------"
$TC class ls dev $INDEV
echo "---- filter parameters Ingress ----------"
$TC filter ls dev $INDEV parent ffff:

#deleting the ingress qdisc
#$TC qdisc del $INDEV ingress

14.3 以 ICMP 速率限制抵擋 dDoS (Ratelimit ICMP to prevent dDoS)

目前來說﹐分散式服務癱瘓(distributed denial of service)攻擊已經成為 Internet 上頭號騷擾行為。對貴網路使用適當的過濾和速率限制﹐可讓您既避免成為砲灰﹐也避免成為砲手﹐一箭雙雕。

如果您要對網路做過濾﹐那您或許會不讓非本地 IP 來源位址的封包離開貴網路。這可以制止別人以匿名身份對 internet 發送垃圾。

如前面介紹的﹐速率限制考慮得更是週長。再看看下面的 ASCII 圖例﹐幫您重溫一下﹕

[The Internet] ---<E3, T3, whatever>--- [Linux router] --- [Office+ISP]
                                      eth1          eth0

讓我們先將前提部份設定起來吧﹕

# tc qdisc add dev eth0 root handle 10: cbq bandwidth 10Mbit avpkt 1000
# tc class add dev eth0 parent 10:0 classid 10:1 cbq bandwidth 10Mbit rate \
  10Mbit allot 1514 prio 5 maxburst 20 avpkt 1000

假如您有 100Mbit﹐或是更快的界面﹐請調整這些數字。現在您需要判定要允許多大的 ICMP 流量。您可以用 tcpdump 進行測量﹐將結果寫進一個檔案﹐然後過一會看看有多少 ICMP 封包通過網路。請不要忘記將測量時間拉長一點。

如果測量結果看起來不切實際﹐那您可以以可用頻寬的 5% 來計算。那就讓我們把類別設好吧﹕

# tc class add dev eth0 parent 10:1 classid 10:100 cbq bandwidth 10Mbit rate \
  100Kbit allot 1514 weight 800Kbit prio 5 maxburst 20 avpkt 250 \
  bounded

目前的限制為 100Kbit。接下來我們需要一個過濾器﹐將 ICMP 流量撥給這個類別﹕

# tc filter add dev eth0 parent 10:0 protocol ip prio 100 u32 match ip
  protocol 1 0xFF flowid 10:100

14.4 為互動流量排優先次序 (Prioritizing interactive traffic)

如果有大量的數據傳入您的線路﹐或是反向傳出﹐而您需要用 telnet 或 ssh 進行某些維護工作﹐這或許不十分理想﹐因為其它封包或會打斷您的鍵盤操作。假如有辦法讓這些互動封包從這些大塊的流量底下暗渡陳倉﹐就最好不過了。Linux 可以幫您做到哦﹗

如前﹐我們需要操縱雙向的流量。顯然﹐如果線路兩端都有 Linux 機器就最理想了﹐當然其它 UNIX's 也可以做得到啦。這點﹐就請教您身邊的 Solaris/BSD 高手囉。

標準的 pfifo_fast 排程方法帶有 3 個不同的 'bands'。當 band1 和 band2 都流量獲得之後﹐在 band0 的流量會先傳送。至為關鍵的是﹐我們的互動流量一定要在 band0 裡面﹗

我們乾脆明目張膽的改編(即將淘汰的) ipchains HOWTO 好了﹕

在 IP 標頭中﹐有 4 個位元並不常用的﹐稱為 Type of Service (TOS) 位元。它們會影響封包被處理的程序﹔這 4 個位元分別是﹕"Minimum Delay"、"Maximum Throughput"、"Maximum Reliability"、和 "Minimum"。它們四者﹐只能設定其一。Ipchains 之 TOS-mangling 作者﹐Rob van Nieuwkerk﹐曾作如下述﹕

對我而言﹐"Minimum Delay" 猶為重要。我為了那些“互動”封包 在我的上傳(Linux) router 上將之打開。我只用一條 33k6 的 modem 線路而已。Linux 將封包的優先順序排進 3 個佇列中。這樣﹐ 在我進行大量下載的時候﹐還可以獲得一個可接受的互動效能。

最常見的做法是將 telnet 和 ftp control 連線設為 "Minimum Delay" ﹐而 FTP data 設為 "Maximum Throughput"。在您的上傳 router 上﹐可以如下那樣動作﹕

# iptables -A PREROUTING -t mangle -p tcp --sport telnet \
  -j TOS --set-tos Minimize-Delay
# iptables -A PREROUTING -t mangle -p tcp --sport ftp \
  -j TOS --set-tos Minimize-Delay
# iptables -A PREROUTING -t mangle -p tcp --sport ftp-data \
  -j TOS --set-tos Maximize-Throughput

好了﹐這只對那些 telnet 及從外面送來本地主機的數據有效而已。其它您也要一一設好﹐例如 telnet、ssh、朋友的﹐所有外送封包的 TOS 欄位全自動設好。

如果客戶端並非設定如此﹐那您可以用 netfilter 來做。於您的本機上﹕

# iptables -A OUTPUT -t mangle -p tcp --dport telnet \
  -j TOS --set-tos Minimize-Delay
# iptables -A OUTPUT -t mangle -p tcp --dport ftp \
  -j TOS --set-tos Minimize-Delay
# iptables -A OUTPUT -t mangle -p tcp --dport ftp-data \
  -j TOS --set-tos Maximize-Throughput

14.5 用 netfilter、iproute2、ipchains、及 squid 做通透性 web-caching (Transparent web-caching using netfilter, iproute2, ipchains and squid)

本章節由 Internet for Education (泰國) 的讀者 Ram Narula 提供。

以 Linux 來做的話﹐常規技巧上或會採用 ipchains﹐﹐將 "外送" 的 port 80(web) 流量送往伺服器所跑的 squid 服務程式。

有 3 種常見辦法可確定 "外送" 的 port 80(web) 流量會送往伺服器所跑的 squid 服務程式﹐而第 4 種將是這裡的重頭戲。

用網關 router 來做

告訴網關 router 將外送目的端埠口為 80 的封包﹐送到 squid 伺服器的 IP 位址上。

但是

這會額外增加 router 的負載﹐而且有些商業 routers 未必支援這種做法。

用 Layer 4 switch 來做

Layer 4 switch 絕對能勝任此項工作。

但是

此類設備的成本非常高。一般而言﹐Layer 4 switch 的成本甚至比 router 加一台好的 Linux 伺服器還要高。

用 cache 伺服器來做網關

您可以強迫所有流量都經過 cache 伺服器。

但是

這有點冒險﹐因為 Squid 會耗掉相當道 cpu 資源﹐或會造成整體的網路效能降低﹐或是伺服器當掉而誰也連不上 internet。

Linux+NetFilter router

NetFilter 可以提供另一可行手段﹐就是用 NetFilter 來將那些目的端埠口為 89 的封包 "標識" 起來﹐同時用 iproute2 將已 "標識" 的封包送到 Squid 伺服器那裡。

|----------------|
| Implementation |
|----------------|

 Addresses used
 10.0.0.1 naret (NetFilter server)
 10.0.0.2 silom (Squid server)
 10.0.0.3 donmuang (Router connected to the internet)
 10.0.0.4 kaosarn (other server on network)
 10.0.0.5 RAS
 10.0.0.0/24 main network
 10.0.0.0/19 total network

|---------------|
|Network diagram|
|---------------|

Internet
|
donmuang
|
------------hub/switch----------
|        |             |       |
naret   silom        kaosarn  RAS etc.
首先﹐確定 naret 為預設網關(除 silom 外)﹐讓所有流量均通過它。而 silom 的預設網關必須是 donmuang(10.0.0.3)﹐要不然會產生流量迴圈(loop)。

(網路中的所有伺服器都以 10.0.0.1 為預設網關﹐也就是 donmuang router 的舊 IP 位址﹐所以我將 donmuang 的 IP 設為 10.0.0.3﹐而將 10.0.0.1 給 naret 用。)

Silom
-----
-setup squid and ipchains 

在 silom 上面設定 Squid 伺服器﹐要確定它能支援通透性 caching/proxying﹐其預設埠口通常為 3128﹐然後﹐所有給 port 80 的流量都會被轉送到本機埠口 3128。用 ipchains 的話﹐可以這樣做﹕

silom# ipchains -N allow1
silom# ipchains -A allow1 -p TCP -s 10.0.0.0/19 -d 0/0 80 -j REDIRECT 3128
silom# ipchains -I input -j allow1

或是﹐netfilter 來做﹕

silom# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128

(注意﹕您或許還有其它項目的設定)

關於 Squid 伺服器的更多設定資料﹐請參考 Squid 的 faq ﹕ http://squid.nlanr.net)。

請確定在這台伺服器上面將 ip forwarding 功能打開﹐還有﹐這個伺服器的預設網關是 donmuang (而不是 naret)。

Naret
-----
-setup iptables and iproute2
-disable icmp REDIRECT messages (if needed)

  1. 將目的埠口為 80 的封包 "標識" 為數值 2
     
    naret# iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 80 \
     -j MARK --set-mark 2
    
  2. 設定好 iproute2﹐將 "標識" 為 2 的封包送到 silom 那邊
    naret# echo 202 www.out >> /etc/iproute2/rt_tables
    naret# ip rule add fwmark 2 table www.out
    naret# ip route add default via 10.0.0.2 dev eth0 table www.out
    naret# ip route flush cache
    

    如果 donmuang 和 naret 都在同一 subnet 上的話﹐那 naret 就不要送出 REDIRECT 的 icmp 訊息了。這時候﹐按如下方法將 icmp REDIRECT 關閉﹕

    naret# echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
    naret# echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
    naret# echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects
    

如此﹐所有設定都完成了﹐請回去檢查一下﹕

On naret:

naret# iptables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
MARK       tcp  --  anywhere             anywhere           tcp dpt:www MARK set 0x2 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

naret# ip rule ls
0:      from all lookup local 
32765:  from all fwmark        2 lookup www.out 
32766:  from all lookup main 
32767:  from all lookup default 

naret# ip route list table www.out
default via 203.114.224.8 dev eth0 

naret# ip route   
10.0.0.1 dev eth0  scope link 
10.0.0.0/24 dev eth0  proto kernel  scope link  src 10.0.0.1
127.0.0.0/8 dev lo  scope link 
default via 10.0.0.3 dev eth0 

(make sure silom belongs to one of the above lines, in this case
it's the line with 10.0.0.0/24)

|------|
|-DONE-|
|------|

執行之後的流量流程圖 (Traffic flow diagram after implementation)


|-----------------------------------------|
|Traffic flow diagram after implementation|
|-----------------------------------------|

INTERNET
/\
||
\/
-----------------donmuang router---------------------
/\                                      /\         ||
||                                      ||         ||
||                                      \/         ||
naret                                  silom       ||
*destination port 80 traffic=========>(cache)      ||
/\                                      ||         ||
||                                      \/         \/
\\===================================kaosarn, RAS, etc.


注意﹕   因為在正常外送路徑上﹐多了一個額外的跳站(hop)﹐
        所以此網路為非對稱的。

這樣﹐在 kaosarn 和 internet 之間的封包﹐到這裡都會受到管制。

對於 web/http 流量﹕
kaosarn http request->naret->silom->donmuang->internet
http replies from internet->donmuang->silom->kaosarn

對於 非 web/http 請求(如﹐telnet)﹕
kaosarn outgoing data->naret->donmuang->internet
incoming data from internet->donmuang->kaosarn


Next Previous Contents