好長時間沒寫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鏈.