博客 / 詳情

返回

Linux 路由三大件

對於 Linux 網絡,好奇心強的同學一定思考過兩個問題:

  • 當我們發出一個包的時候,Linux 是如何決策該從哪個網卡(假設有多個網卡)、哪個下一跳發出這個包,用什麼 IP 作為 source......
  • 當 Linux 收到一個包時,又是如何決定往哪裏送的,是發送給本地程序、其他虛擬接口,還是轉發到其他機器......

今天,我們就來分析這兩個問題的核心所在:路由。

我們學習計算機網絡的時候,一般都會了解到基於目的地址(cidr)的路由(ip route),但是在 Linux 2.0 之後,RPDB (Routing Policy DataBase)誕生了,引入了更豐富的路由策略(ip rule)。除此以外,我們還可以通過 iptables 來操縱數據包,作為路由策略實施的依據,間接地影響路由過程。

至此,我們就認識了 Linux 路由的三大件。那麼,三大件分別是什麼原理,又是是如何交互的呢?且看下文分析。

注:雖然 Linux 提出了 nftables 來替換 iptables,但 iptables 仍然是事實上的標準

RPDB

首先我們來看看 RPDB,RPDB 由兩部分組成,一個是 rule 列表,一個是 routing table 列表。

rule

ip rule 命令可以展示所有的 rule,每個 rule 由 selector(依據什麼特徵選擇包) 和對應 action(對包做什麼) 組成。

selector 主要有幾種類型:

  • 出/入接口的 index,如 eth0、eth1
  • fwmark: 包攜帶的標記
  • Tunnel id
  • src/dst addr/port
  • type of service
  • priority
  • ......

action 主要由幾種類型:

  • 傳遞給特定的 route
  • 跳轉到其它的 rule
  • Drop/reject 這個包
  • ......

routing table

routing table 最開始只有一個,RPDB 後引入了多個(可以通過 cat /etc/iproute2/rt_tables 查看),默認有三個:

  • local,dst 為本地或者廣播地址的路由
  • main,默認的路由
  • default,一般為空,為後處理預留空間

ip route 命令默認展示的是 main table,ip route show table local 形式可以展示其它 table。

routing table 裏面每個 route 代表了 dst 為某個/些/類地址 的數據包應該 通過哪個渠道 轉發。route 由幾部分組成:

  • types

    • unicast,單播,最常見
    • unreachable,丟包並返回 ICMP 消息
    • blackhole, 默默丟包
    • ......
  • socpe,目標地址的範圍: cat /etc/iproute2/rt_scopes,默認有三個

    • link,只在本設備有效,通常是直連
    • host,只在本機有效
    • global,全局有效,可傳播,是默認值
    • ......
  • proto,路由由誰創建和維護: /etc/iproute2/rt_protos,默認有三個

    • kernel,內核創建,長期有效
    • boot,臨時的
    • static,手動創建,override 動態路由(由路由協議維護entry)
    • ......
  • preference,優先級,一般都是數字越小,優先級越高
  • dev,通過的設備名字,如 eth0
  • nexthop,下一跳
  • src,設置發出包的 src ip
  • ......

RPDB 運行邏輯

參考 fib_lookup 函數:如果你沒有動過 RPDB,那麼直接用 mian table 進行路由查找(fib_table_lookup)了;如果動過,則通過 __fib_lookup/fib_rules_lookup 進行 rule 匹配,匹配邏輯為:

  • 無論是出還是入方向的每個包,都會遍歷所有 rule,按照 priority,由 0 開始
  • 第一個匹配的 rule 會執行 action
  • 如果 action 是 lookup route table,則用對應 table 進行路由查找(fib_table_lookup),如果查找失敗,則繼續執行下一個 rule
  • 如果沒有任何 rule 匹配,則報錯

路由查找邏輯為:

  • 最長前綴匹配(也是被認為最精準的)的 route 被選中
  • 如果有多個匹配,則 preference、tos/dscp、自然順序都會被進行考慮,最後僅剩一個匹配
  • 如果沒有匹配,則返回 rule 匹配,繼續檢查下一個 rule

iptables

iptables 主要用於包過濾、修改和 NAT。再次拿出下面這張神圖,來闡釋它五大表和五大鏈,及其生效順序和範圍:

原圖:https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter...

三大件的交互過程

瞭解了各自原理之後,我們當然想知道它們是怎麼交互的。上面那張圖實際上已經闡釋了他們之間的交互,不過下面這張圖能看得更清晰:

image.png
原圖:http://www.adminsehow.com/2011/09/iptables-packet-traverse-map/

實踐

這是一個完全沒動過的環境:

我們現在來設計一個需求:源端口為 30300 的包,默默丟棄;源端口為 30301 的包,丟棄並報錯;源端口為 30302 的包,用新的 route table 轉發。
先看看實施前的結果,用 taobao.com 來測試

nc -zv taobao.com 443 -p 30300
Connection to taobao.com (59.82.122.115) 443 port [tcp/https] succeeded!
nc -zv taobao.com 443 -p 30301
Connection to taobao.com (106.11.226.158) 443 port [tcp/https] succeeded!
nc -zv taobao.com 443 -p 30302
Connection to taobao.com (106.11.226.158) 443 port [tcp/https] succeeded!

雖然實現這個需求有很多方式,但是我這裏為了演示三大件的交互而選擇了下面的這種方式:

首先需要標記這三種類型的包,由於是本地發包,我們採用 mangle output

iptables -A OUTPUT -t mangle -o enp0s1 -p tcp --sport 30300 -j MARK --set-mark 1
iptables -A OUTPUT -t mangle -o enp0s1 -p tcp --sport 30301 -j MARK --set-mark 2
iptables -A OUTPUT -t mangle -o enp0s1 -p tcp --sport 30302 -j MARK --set-mark 3

iptables -t mangle -L 展示,iptables -t mangle -F 清理。

然後增加相應的 route table

echo 2 custom >> /etc/iproute2/rt_tables
ip route add default via 192.168.64.1 dev enp0s1 src 192.168.64.4 table custom

以及 rule

ip rule add from all fwmark 1 blackhole
ip rule add from all fwmark 2 prohibited
ip rule add from all fwmark 3 table custom

結果發現 30302 依然能通,但是 30300 和 30301 都超時了,沒看出來返回的錯誤。
採用 traceroute 的 tcp 模式作為測試工具則能夠看出一些差別。

ip rule add from all fwmark 2 unreachable 對應結果也確實符合期望

traceroute -T --sport=30301 --port=443 tabao.com
traceroute to tabao.com (128.14.151.194), 30 hops max, 60 byte packets
send: Network is unreachable

參考

  • ip-rule(8) - Linux manual page: https://www.man7.org/linux/man-pages/man8/ip-rule.8.html
  • ip-route(8) - Linux manual page: https://www.man7.org/linux/man-pages/man8/ip-route.8.html
  • iptables(8) - Linux manual page: https://www.man7.org/linux/man-pages/man8/iptables.8.html
  • fib_rule_match: https://elixir.bootlin.com/linux/v6.1.11/source/net/core/fib_...
  • fib4_rule_match: https://elixir.bootlin.com/linux/v6.1.11/source/net/ipv4/fib_...
  • https://elixir.bootlin.com/linux/v6.1.11/source/include/uapi/...
  • fib_table: https://elixir.bootlin.com/linux/v6.1.11/source/include/net/i...
  • fib_info: https://elixir.bootlin.com/linux/v6.1.11/source/include/net/i...
  • https://serverfault.com/questions/63014/ip-address-scope-para...
  • https://linux.die.net/man/8/ebtables
  • fib_table_lookup:https://elixir.bootlin.com/linux/v6.1.11/source/net/ipv4/fib_...
  • https://blogs.manageengine.com/network/netflowanalyzer/2012/0...
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.