1. 程式人生 > >關於 iptables 和 tc 的限速理解

關於 iptables 和 tc 的限速理解

關於 iptables

iptables 是包過濾軟體,包過濾的順序如下:

每一個包都會匹配 rule 策略,而每一個 rule 策略會有一個 action,觸發了其中一個 rule 就不會觸發另外一個 rule,但如果要觸發的 rule 放在最後面,那麼可以想象,包過濾的效率就會大大降低,所以設計策略的時候要儘量將常用的策略放在最前面,策略的順序可以通過不斷的調整 -A 和 -I 策略,甚至還有 return 的動作,設計 iptables 的人真的很厲害。

這是 iptables 內部的 table 表和 chain 鏈,可以理解為 iptables 是一個大網,table 就是小網,裡面的 chain 就是他的網線,當資料包經過這個小網的時候必然會觸碰這些網線,這樣“看不順眼”的資料包就會被攔住。鳥哥的圖畫的真好。這裡需要理解的是資料包的流行會分 2 個地方,就是進入本機或者不進入本機,進入本機的包就會走 input 的 chain 鏈,不進入本機的包就會去 FORWARD,什麼是進入或者不進入呢?

舉個例子就是這是一臺路由器伺服器,伺服器上面假設了 web 伺服器,然後這個路由器負責的內部網路還有一臺資料庫伺服器,不過這臺伺服器是獨立於路由器的另外一臺機器,不過上網也是要經過路由器,那麼一個外網使用者訪問這個 web 伺服器和訪問資料庫伺服器的行為就是進入本機和不進入本機的行為,因為 web 伺服器是跟路由器在同一臺機器上的,所以要進入本機,因為資料庫伺服器是另外一臺機器上的,所以不進入本機。解釋得好渣,還是看鳥哥吧。鳥哥乃神人。迴歸主題,看下圖的結構,可以看出如果我們要在 iptables 上操刀的話可以在任何表上操刀,例如可以在 PREROUTING,FORWARD,POSTROUTING

 表上做限速是完全沒有問題的,前提是要注意不能衝突,每個表都有各自的作用。所以一般來說,要寫 iptables 策略的時候都要跟著這個圖來筆畫一下,這樣才能知道有沒有寫錯。

filter (過濾器):主要跟進入 Linux 本機的封包有關,這個是預設的 table 喔!
INPUT:主要與想要進入我們 Linux 本機的封包有關;
OUTPUT:主要與我們 Linux 本機所要送出的封包有關;
FORWARD:這個咚咚與 Linux 本機比較沒有關係, 他可以『轉遞封包』到後端的電腦中,與下列 nat table 相關性較高。

nat (位址轉換):是 Network Address Translation 的縮寫, 這個表格主要在進行來源與目的之 IP 或 port 的轉換,與 Linux 本機較無關,主要與 Linux 主機後的區域網路內電腦較有相關。
PREROUTING:在進行路由判斷之前所要進行的規則(DNAT/REDIRECT)
POSTROUTING:在進行路由判斷之後所要進行的規則(SNAT/MASQUERADE)
OUTPUT:與發送出去的封包有關

mangle (破壞者):這個表格主要是與特殊的封包的路由旗標有關, 早期僅有 PREROUTING 及 OUTPUT 鏈,不過從 kernel 2
.4.18 之後加入了 INPUT 及 FORWARD 鏈。 由於這個表格與特殊旗標相關性較高,所以像咱們這種單純的環境當中,較少使用 mangle 這個表格。
Table (表名) Explanation (註釋)
nat nat 表的主要用處是網路地址轉換,即 Network Address Translation,縮寫為 NAT。做過 NAT 操作的資料包的地址就被改變了,當然這種改變是根據我們的規則進行的。屬於一個流的包只會經過這個表一次。如果第一個包被允許做 NAT 或 Masqueraded,那麼餘下的包都會自 動地被做相同的操作。也就是說,餘下的包不會再通過這個表,一個一個的被 NAT,而是自動地完成。這就 是我們為什麼不應該在這個表中做任何過濾的主要原因,對這一點,後面會有更加詳細的討論。PREROUTING 鏈的作用是在包剛剛到達防火牆時改變它的目的地址,如果需要的話。 OUTPUT 鏈改變本地產生的包的目的地址。POSTROUTING 鏈在包就要離開防火牆之前改變其源地址。
mangle 這個表主要用來 mangle 資料包。我們可以改變不同的包及包 頭的內容,比如 TTL,TOS 或 MARK。 注意 MARK 並沒有真正地改動資料包,它只是在核心空間為包設了一個標記。防火牆 內的其他的規則或程式(如 tc)可以使用這種標記對包進行過濾或高階路由。這個表有五個內建的鏈: PREROUTING,POSTROUTING, OUTPUT,INPUT 和 FORWARD。PREROUTING 在包進入防火牆之後、路由判斷之前改變 包, POSTROUTING 是在所有路由判斷之後。 OUTPUT 在確定包的目的之前更改資料包。INPUT 在包被路由到本地 之後,但在使用者空間的程式看到它之前改變包。FORWARD 在最初的路由判 斷之後、最後一次更改包的目的之前mangle包。注意,mangle 表不能做任何 NAT,它只是改變資料包的 TTL,TOS 或 MARK,而不是其源目地址。NAT 是在nat 表中操作的。
filter filter 表是專門過濾包 的,內建三個鏈,可以毫無問題地對包進行 DROP、LOG、ACCEPT 和 REJECT 等操作。FORWARD 鏈過濾所有不是本地產生的並且目的地不是本地(所謂本地就是防火牆了)的包,而 INPUT 恰恰針對那些目的地是本地的包。OUTPUT 是用來過濾所有本地生成的包的

  • iptables 是主要工作在第三,四層的,即主要處理 ip、tcp,偶爾能夠在第七層工作是因為打了 patch。
  • 什麼是資料包:其實就是隻 ip 資料包和 tcp 資料包

    包(Packet)是 TCP/IP 協議通訊傳輸中的資料單位,一般也稱“資料包”。有人說,區域網中傳輸的不是“幀”(Frame)嗎?沒錯,但是 TCP/IP 協議是工作在 OSI 模型第三層(網路層)、第四層(傳輸層)上的,而幀是工作在第二層(資料鏈路層)。上一層的內容由下一層的內容來傳輸,所以在區域網中,“包”是包含在“幀”裡的。

舉例來說 tcp 包的包頭含有以下這些資訊(等等):

資訊 解釋 iptables 關鍵字
源 IP 地址 傳送包的 IP 地址。 src
目的 IP 地址 接收包的 IP 地址。 dst
源埠 源系統上的連線的埠。 sport
目的埠 目的系統上的連線的埠。 dport

關於 tc

TC--Traffic Control

TC 是 linux 中的流量控制模組,利用佇列規定建立起資料包佇列,並定義了佇列中資料包的傳送方式,從而實現對流量的控制。關鍵字:佇列系統,包接收和傳輸。

Traffic control is the name given to the sets of queuing systems and mechanisms by which packets are received and transmitted on a router. This includes deciding which (and whether) packets to accept at what rate on the input of an interface and determining which packets to transmit in what order at what rate on the output of an interface.

tc工作位置圖:

在我使用的過程中,對於他的理解是有一些加深了:

  1. tc 就是看門的,like as a dog,所以這就可以解釋了為什麼要 iptables + tc 了,tc 能夠和 iptables 合作,因為可以從圖上看到各自工作的位置是不一樣的,各施其職。
  2. tc 對於包一視同仁,專門負責包的排隊分發,官方里面提到一個很經典的說法就是他是一個接收和傳輸的佇列系統,tc 翻譯為交通管制是很巧妙的,有鑑於此,我認為他的限速效果最好,無論你是 p2p 包還是什麼加密包,只要是包就要受到約束,這樣就可以避免了那些日新月異的封裝加密之類的包被逃掉了。
  3. tc 主要是以 mark 的形式來匹配,所以使用的時候 mark 標記需要注意不要衝突,mark 標記是 iptables 裡面提到的一個東西:

    6.5.5. MARK target

    用來設定 mark 值,這個值只能在本地的 mangle 表裡使用,不能用在其他任何地方,就更不用說路由器或 另一臺機子了。因為 mark 比較特殊,它不是包本身的一部分,而是在包穿越計算機的過程中由核心分配的和它相關聯的一個欄位。它可以和本地的高階路由功能聯用,以使不同的包能使用不同的佇列要求,等等。如 果你想在傳輸過程中也有這種功能,還是用 TOS target 吧。有關高階路由的更多資訊,可以檢視 Linux Advanced Routing and Traffic Control HOW-TO。

    mark 只能存在於核心之中,不受三界法則影響,所以 mark 值我覺得是配置 tc 的特別需要注意的地方,尤其是如果你使用了 wifidog 之類的要玩 mark 的時候。

  4. tc 的類是樹架構,有主幹和葉這樣很分明的區分的,這種層次是很容易理解的,不過文件的解釋是相當的難理解,難理解的是怎麼做,命令寫法簡直坑爹。

  5. 涉及很多相當高深的佇列演算法,流控制模式其實略懂就行了,諸葛先生不也就略懂麼。所以不是那種極端情況其實無須特別考慮這個。
  6. 對於 tc 來說,上傳和下載行為是這樣區分的,上傳,就是使用者端傳送資料包給伺服器,假設路由器是雙網絡卡,所以負責傳送資料包給伺服器的是外網網絡卡,所以限制上傳速度在外網網絡卡處, 下載,就是伺服器傳送資料包給使用者,因為路由器是雙網絡卡的關係,所以負責傳送資料包給使用者的是內網網絡卡,所以限制下載速度是在內網網絡卡,因為 tc 是一個能夠負責接收資料包的工具,所以限制上傳速度其實就是限制外網網絡卡接收使用者傳送的資料包的速度,而限制下載速度其實就是限制內網網絡卡接收到要傳送給使用者的資料包的速度。

測試流程介紹

  1. 首先需要建立 tc 策略
  2. 然後由 iptables 來進行呼叫,主要通過 set mark,根據不同的 mark 標記來進行不同的 tc 策略呼叫

備註

  1. 測試環境是 eth0 負責外網,p3p1 是負責內網
  2. 考慮到特殊需求,tc 限制的是所有的包,所以需要 iptables 將發到內網伺服器的包分開處理,以便實現訪問外網能夠限制網速,訪問內網沒有限制

上傳

清除 eth0 所有佇列規則

tc qdisc del dev eth0 root 2>/dev/null

定義最頂層(根)佇列規則,並指定 default 類別編號,為網路介面 eth1 繫結一個佇列,型別為 htb,並指定了一個 handle 控制代碼 1:0 用於標識它下面的子類,沒有標識的會被分配到預設子類 123(預設值只是設定而已,可以不用)

tc qdisc add dev eth0 root handle 1:0 htb default 123

用於為佇列建一個主幹類,頻寬為 100 Mbit,最大速率為 100 Mbit,(這裡是 bit,所以實際速度需要除以 8)優先順序為 0,htb 的主幹類不能互相借用頻寬,但是一個父類的所有子類之間可以借用頻寬,這裡 parent 1:0 是剛才建立的 handle1:0 ,classid 是他的子類,分類號為 1:1,冒號前面是父類號,後面是子類號

tc class add dev eth0 parent 1:0 classid 1:1 htb rate 100Mbit ceil 100Mbit prio 0

為主幹類建立第一個葉分類,頻寬為 10Mbit,最大速為 10 Mbit,優先順序為1,所有葉分類的全部子類優先順序低於主幹類,以防止重要資料堵塞,主要還是避免邏輯混亂,10 Mbit 必須要有 96 kbit 的 burst 速度

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10Mbit ceil 10Mbit prio 1 burst 96kbit

設定排程,sfq 隨機公平演算法,這裡的 parent 是指隸屬於之前的子分類,你需要對哪一個子分類的條目做佇列分配控制就需要在這裡寫對應的子分類 id 在每個類下面再附加上另一個佇列規定,隨機公平佇列(SFQ),不被某個連線不停佔用頻寬,以保證頻寬的平均公平使用:

    #SFQ(Stochastic Fairness Queueing,隨機公平佇列),SFQ的關鍵詞是“會話”(或稱作“流”) ,
    #主要針對一個TCP會話或者UDP流。流量被分成相當多數量的FIFO佇列中,每個佇列對應一個會話。
    #資料按照簡單輪轉的方式傳送, 每個會話都按順序得到傳送機會。這種方式非常公平,保證了每一
    #個會話都不會沒其它會話所淹沒。SFQ之所以被稱為“隨機”,是因為它並不是真的為每一個會話建立
    #一個佇列,而是使用一個雜湊演算法,把所有的會話對映到有限的幾個佇列中去。
    #引數perturb是多少秒後重新配置一次雜湊演算法。預設為10
tc qdisc add dev eth0 parent 1:11 handle 111:0 sfq perturb 10

設定過濾器 filter,對應之前配置的哪一個父類和子類,然後設定控制編號 handle,這裡是跟 iptables 的 mark 相對應的,並且多個不同的filter注意 prio 不要相同。

tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 1001 fw classid 1:11

設定 iptables規則,在 mangle 表的 postroutingchain 上配置,源地址是 172.16.1.138 並且目標地址不是 192.168.0.10,從網絡卡eth0發出的包進行 mark,mark 號是 1001

iptables -t mangle -A POSTROUTING -s 172.16.1.138/32 ! -d 192.168.0.10 -o eth0 -j MARK --set-xmark 1001

設定 return 是為了加快包檢查,return 的順序是:子鏈——>父鏈——>預設的策略,檢查到源地址是 172.16.1.138 並且目標地址不是 192.168.0.10 的包就會跳到 postrouting 層,然後會繼續檢查其他這層的 chain,這樣不用每個包都要檢查一次這條 chain 的內容了,加快了一倍的速度

iptables -t mangle -A POSTROUTING -o eth0 -s 172.16.1.138 ! -d 192.168.0.10 -j RETURN

下載

tc qdisc del dev p3p1 root 2>/dev/null

tc qdisc add dev p3p1 root handle 1:0 htb default 123

tc class add dev p3p1 parent 1:0 classid 1:1 htb rate 100Mbit ceil 100Mbit prio 0

tc class add dev p3p1 parent 1:1 classid 1:11 htb rate 10Mbit ceil 10Mbit prio 1

tc qdisc add dev p3p1 parent 1:11 handle 111:0 sfq perturb 10

tc filter add dev p3p1 parent 1:0 protocol ip prio 1 handle 1000 fw classid 1:11

這裡用 I 的是 insert 一條配置,這樣排序會放在前面,因為 iptables 是按順序匹配的,並且為了跟 wifidog 的策略避免衝突

iptables -t mangle -I POSTROUTING -o p3p1 -d 172.16.1.138 ! -s 192.168.0.10 -j MARK --set-mark 1000
iptables -t mangle -I POSTROUTING -o p3p1 -d 172.16.1.138 ! -s 192.168.0.10 -j RETURN

EOF完

引用: