Linux

如何將所有流量從特定介面路由到特定網關而不是預設路由?

  • September 10, 2022

在我的機器上,我有兩個介面:(wlan0預設路由)和tun0. 該tun0介面只是一個本地網路,它的ip範圍是172.16.150.0/24,我機器(機器A)的IP地址是172.16.150.1,另一台機器(機器B)的IP地址是172.16.150.128。我設置了一個 wifi 熱點,它為我創建了另一個界面ap0。我想ap0通過機器 B 路由來自介面的所有流量(因此網關應該是172.16.150.128)。

$ ip route
default via 192.168.0.1 dev wlan0 proto dhcp src 192.168.0.179 metric 1024
172.16.150.0/24 dev tun0 proto kernel scope link src 172.16.150.1 metric 1024
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.179 metric 1024 
192.168.0.1 dev wlan0 proto dhcp scope link src 192.168.0.179 metric 1024 
192.168.12.0/24 dev ap0 proto kernel scope link src 192.168.12.1

此時,由於預設路由是192.168.0.1,它將所有流量路由wlan0到我家路由器的介面。

我不是經驗豐富的 linux 使用者,所以我不確定如何讓 linux 核心路由來自網關的所有流量ap0172.16.150.128但這是我嘗試過的:

$ ip route add default 192.168.12.0/24 via 172.16.150.128
Error: either "to" is duplicate, or "192.168.12.0/24" is a garbage.

在這裡,我試圖讓核心通過網關路由來自192.168.12.0/24子網的所有流量。172.16.150.128

$ ip route add 192.168.12.0/24 via 172.16.150.128
RTNETLINK answers: File exists

與上一個命令相同,但沒有default單詞。我在某個地方讀到了ip addr flush dev ap0可能有幫助的地方,但它會重置介面及其 IP 地址,因此我需要通過手動恢復 IP 地址ip addr add或重新啟動 wifi 熱點。

我認為這不是正確的方法,因為我不想刷新介面,而是想將路由更改default為特定網關。

我怎樣才能做到這一點?

簡單的路由在這裡是不夠的。簡單路由關心目的地。但這裡的目標是也根據來源改變路線。這樣做稱為策略路由。在 Linux 上,這是通過使用額外的選擇器(不僅僅是目標)來實現的,例如源 IP 地址或源數據包的傳入介面來選擇備用路由表。這些備用路由表可以有其他路由,包括其他預設路由,最終為數據包選擇與路由表中的通常路由不同的路由。

這通常與 some + some結合使用,並根據要解決的問題進行選擇。通常會有基於源的選擇器以區別對待,而將有(並且只能有)用於這種情況的備用目的地。ip rule add ... lookup TABLE``ip route add ... table TABLEip rule ...``ip route ...

因此,對於這種情況,可以像下面那樣做。

  • 準備一個備用路由表(使用任意表 1000)

此表應包含所需的所有內容,因此將手動複製主路由表的部分內容

ip route add 192.168.12.0/24 dev ap0 table 1000
ip route add 172.16.150.0/24 dev tun0 table 1000

當然,為了實現目標,也有備用的預設路由:

ip route add default via 172.16.150.128 dev tun0 table 1000
  • 為兩個涉及的介面選擇備用路由表
ip rule add iif ap0 lookup 1000
ip rule add iif tun0 lookup 1000

路由規則應如下所示:

# ip rule
0:    from all lookup local
32764:    from all iif tun0 lookup 1000
32765:    from all iif ap0 lookup 1000
32766:    from all lookup main
32767:    from all lookup default

這解決了機器上的路由問題(但請參閱下一部分關於遠端系統的路由或使用 NAT):

  • 來自的任何數據包ap0都將使用備用路由表並將發送到tun0

這包括發送到 Internet 的流量,該流量將通過 172.16.150.128。有關詳細資訊:專門發送到這台機器的流量實際上將首先使用本地路由表,因此仍將照常工作。

  • 來自的任何數據包tun0都將使用備用路由表

    • (如果發送到本系統,實際上本地路由表會先路由到本系統)
    • 如果發送到 192.168.12.0/24 它將使用ap0
    • 有關詳細資訊:在其他情況下,路由查找會將流量發送回 172.16.150.128

    但這種情況在實踐中絕不應該發生。

如果ap0tun0曾經下降然後上升,則表 1000 中的相關路線將失去並且必須重新添加。


還有一個問題:如果 172.16.150.0/24 LAN 上的系統對 192.168.12.0/24 一無所知,它們將永遠不會向該系統 (172.16.150.1) 發送回复流量。他們可能會使用自己的預設網關,可能是 172.16.150.128。同樣,172.16.150.128 可能會將 192.168.12.0/24 的任何流量發送到它自己的上游網關,遠離這台機器,而不是通過這台機器。

要解決這個問題:

  • 讓 172.16.150.0/24 中的其他系統知道這個 LAN(首選)

只需在 172.16.150.128 上添加路由就足夠了:172.16.150.0/24 中的其他系統會嘗試通過 172.16.150.128 發送數據包,除了通過 172.16.150.1 路由它之外,還會發送 ICMP 重定向以告訴這些其他系統發送他們直接在那裡。如果那個 172.16.150.128 系統也在執行 Linux,這應該很簡單:

ip route add 192.168.12.0/24 via 172.16.150.1

所有系統也可以直接添加相同的路由。如果通過 DHCP 進行配置,則應使用 DHCP 選項 121(或者對於較舊的 Windows 客戶端可能是選項 249)將此設置添加到 DHCP 配置中,但這超出了此答案的範圍。

  • 否則,如果無法完成之前的更改(例如:無法控制 172.16.150.128),請使用 NAT

如果無法在 172.16.150.0/24 中的系統上設置正確的路由,尤其是在 172.16.150.128 上,那麼仍然可以使用 NAT 將所有 192.168.12.0/24 折疊到可訪問的 172.16.150.1 中。在機器上添加:

iptables -t nat -A POSTROUTING -s 192.168.12.0/24 -o tun0 -j MASQUERADE

此方法允許從 192.168.12.0/24 到 172.16.150.0/24 以及通過 172.16.150.128 到 Internet 的流量沿著回複數據包,但它不允許 192.168.12.0/24 上的任何服務從除此之外的任何其他服務訪問機器。需要針對特定埠/服務的其他 NAT 設置來創建例外。

引用自:https://unix.stackexchange.com/questions/716802