好長時間沒寫blog了,這段時間暫時沒有寫代碼,一直在倒騰軟路由的事情。 不過多虧了軟路由,我對網絡知識的儲備又增加了一些。

這篇文章是想好好講一下關於Linux上的網絡數據包的路由處理.

據我現在所瞭解到的知識,Linux上決定數據包路由流向的關鍵模塊有兩個, 第一個是RPDB(Routing Policy DataBase 路由策略數據庫),第二個是netfilter/iptables,很多人會把netfilter/iptables直接稱之為iptables,也沒有問題,但是嚴格上來說還是分開為好,netfilter是內核中的一部分,提供了一組數據包的hook. iptables則是實現了這些hook,並且提供了在用戶空間操作這些hook的辦法.

RPDB

先來講講RPDB吧,RPDB有分為路由規則以及路由表,處理流程如下:

1進入 -> 規則過濾 -> 規則匹配[最高優先級] -> 查路由表[最長匹配前綴] -> 出去

首先查找路由規則,然後根據優先級來匹配規則,匹配到之後進入對應規則的路由表,在路由表中按照最長匹配前綴的方法匹配, 如果路由表中沒有找到,則會繼續匹配規則.

下面是默認的ubuntu系統的路由規則:

1root@ubuntu:~# ip rule
20:	from all lookup local
332766:	from all lookup main
432767:	from all lookup default

這三條規則的意思都差不多,from all大概是指任意源地址的數據包,lookup local是指路由到local表中, 如果local表中沒有匹配到,則按照規則優先級,匹配到下一條規則,也就是from all lookup main

下面是local路由表以及main路由表的內容:

 1root@ubuntu:~# ip route show table local
 2local 10.2.199.237 dev ens34 proto kernel scope host src 10.2.199.237
 3broadcast 10.2.199.255 dev ens34 proto kernel scope link src 10.2.199.237
 4local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
 5local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
 6broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
 7
 8root@ubuntu:~# ip route show table main
 9default via 10.2.199.1 dev ens34 proto static
1010.2.199.0/24 dev ens34 proto kernel scope link src 10.2.199.237

通俗易懂的講一下路由表中每一條路由的含義, 就現已local的第一條為例:

  • local 這個是一個本地地址的關鍵詞, 代表這個數據包的目標地址是本機.
  • 10.2.199.237 目標地址
  • dev ens34 該數據包的出口網卡
  • proto kernel 這一條規則是由內核創建的
  • scope host 作用域,這條的意思就是這個目標IP只能在本機用
  • src 10.2.199.237 源地址

關於scope再講一下,作用域的意義其實就是字面意思,scope可能的值有三個分別是host,link,global

  • host 當一條路由表示目的地址為本地主機時, 例如127.0.0.1這種只能在本地使用的
  • link 當一條路由表示的目的地址為本地網絡時, 例如192.168.1.1或者範圍192.168.1.0/24這種局域網地址
  • global 當一條路由表示的目的地址超過下一跳時,廣域網就屬於這種

以上基本就是關於路由規則以及路由表的所有內容,不過在執行路由決策之前會首先經過netfilter的各種hook,也就是iptables的規則。

netfilter/iptables

iptables 提供了raw,mangle,nat,filter 四種內置的規則鏈類型,每個規則鏈類型都有自帶的內置規則鏈。

先講講四個規則鏈類型的職能:

  • (raw) 主要是對收到的數據包進行ct (connection track), 最高優先級的鏈
  • (mangle) 可以實現對數據包頭部字段的修改,比較經典的就是打mark標記,配合RPDB的策略路由使用
  • (nat) 可以修改數據包的地址等信息,實現重定向之類的功能
  • (filter) 主要就是進行數據包過濾的作用,那些接受哪些丟棄

nftables上的實現會有所不同,但是基本大同小異。

然後是內置規則鏈,總共是5個類型:

  • (PREROUTING) 數據包抵達時,在路由判斷之前
  • (INPUT) 數據包進入主機之前
  • (FORWARD) 負責被轉發的數據包
  • (OUTPUT) 數據包被主機處理之後
  • (POSTROUTING) 數據包發出時,在路由判斷之後

大體的執行順序是:

 1# 目標為本機的數據包
 2raw (PREROUTING) -> mangle (PREROUTING) -> nat (PREROUTING)
 3-> 執行路由 ->
 4mangle (INPUT) -> nat (INPUT) -> filter (INPUT)
 5-> 本地進程 -> 執行路由 ->
 6raw (OUTPUT) -> mangle (OUTPUT) -> nat (OUTPUT) -> filter (OUTPUT)
 7-> 路由檢查 ->
 8mangle (POSTROUTING) -> nat (POSTROUTING)
 9
10# 目標非本機的數據包
11raw (PREROUTING) -> mangle (PREROUTING) -> nat (PREROUTING)
12-> 執行路由 ->
13mangle (FORWARD) -> filter (FORWARD)
14-> 路由檢查 ->
15mangle (POSTROUTING) -> nat (POSTROUTING)

可以發現,基本上的順序就是raw->mangle->nat->filter, 這個不會改變,以及轉發的數據包是不會經過INPUT和OUTPUT鏈.