Iptables

使用不同的網關埠轉發不起作用

  • August 18, 2021

讓我試著解釋一下我的家庭網路設置:

         ┌────────────────────┐
         │      Internet      │
         │ Public IP: 1.2.3.4 │
         └──────────┬─────────┘
                    │
 ┌──────────────────┴─────────────────┐
 │             ISP Modem              │
 │  Forward everything to AP Router   │
 │            192.168.1.1             │
 └──────────────────┬─────────────────┘
                    │
  ┌─────────────────┴───────────────┐
  │             AP Router           │
  │         DHCP happens here       │
  │ Forward 1122 to 192.168.10.2:22 ├─────────────┐
  │           192.168.10.1          │             │
  └─────────────────┬───────────────┘             │
                    │                             │
                    │                             │
                    │                     ┌───────┴───────┐
                    │                     │ NUC (Ubuntu)  │
                    │                     │ PiHole + VPN  │
                    │                     │ 192.168.10.50 │
                    │                     └───────────────┘
                    │                             ▲
                    │                             │
┌────────────────────┴──────────────────┐          │
│            Desktop (Ubuntu)           │          │ Default routing
│              192.168.10.2             │          │
│    Default gateway: 192.168.10.50     ├──────────┘
│          DNS: 192.168.10.50           │
└───────────────────────────────────────┘

如果桌面192.168.10.1用作預設網關,例如 SSH 到1.2.3.4:1122工作,我可以 SSH 到桌面。但我希望桌面192.168.10.50用作預設網關。在這種情況下,任何埠轉發都不起作用。

在做了一些研究之後,這可以通過基於 IP 表/策略的路由來完成,但我對此一無所知。最簡單的方法是什麼?

TL;DR(僅限第一種方法)

在桌面上:

ip route add 192.168.10.0/24 dev eth0 table 1000
ip route add default via 192.168.10.1 dev eth0 table 1000
ip rule add iif lo ipproto tcp sport 22 lookup 1000

問題

這裡的問題發生在桌面上。

如果採用不同的佈局,NUC 可以可靠地攔截所有流,則可以使用更簡單的方法。這將要求 NUC 有兩個網路設備,因為在同一個乙太網 LAN 上路由兩個 IP LAN 並不能防止例如 DHCP 的問題。將 NUC 作為有狀態網橋是另一種解決方案,也需要兩個 NIC。

在目前佈局下,NUC 無法攔截 AP 和桌面之間的所有流量……

…解決方案必須在桌面上完成。

Linux 可以使用策略路由,其中​​選擇器用於為數據包提供不同的結果(通過使用不同的路由表)。對於明顯相同的目的地使用多條路由的所有問題都需要使用策略路由,主要使用能夠根據源進行分離的選擇器(因為路由表已經在這里分離目的地)。

人們必須以某種方式將直接來自 AP 的數據包與來自 NUC 的數據包區分開來,因此當涉及到桌面的 SSH 連接時,它們可以有不同的結果(即:不同的路由)。

似乎不可用ip rule的是選擇器,當這些路由僅與使用的網關不同時,可以區分通過兩條路由到達的兩個數據包。Linux 的策略規則似乎沒有捕捉到這種情況:只要它來自相同的界面,它就是相同的。

我會假設:

  • Desktop 的網路介面稱為eth0
  • 桌面沒有路由(例如:libvirt、LXC、Docker)。路由需要更多配置並選擇應該做什麼(VM 應該接收來自 NUC 還是來自 AP 的 SSH?)。下面的答案需要一些小的調整才能為路由案例正確創建例外,或者容器/VM 將僅遵循預設路由(即:通過 NUC)。

這裡有兩種方法。

策略路由匹配第 4 層協議(TCP 埠 22)

Linux 4.17開始,可以使用選擇器在 TCP 埠 22 上與策略路由匹配。然後很容易為它使用不同的路線。不要以不同的方式處理數據包的來源,而是以不同的方式處理此特定埠:

ip route add 192.168.10.0/24 dev eth0 table 1000
ip route add default via 192.168.10.1 dev eth0 table 1000
ip rule add iif lo ipproto tcp sport 22 lookup 1000

這裡iif lo不是關於lo介面,而是來自 local system的特定語法含義。LAN 路由也必須複製,或者例如來自 NUC 本身的 SSH 連接將通過 AP 進行回复,AP 會發出 ICMP 重定向以告知錯誤配置。在這種特定情況下,不需要為接收的數據包指定備用路由,因為它是同一個介面。如果它是其他介面並且啟用了SRPF ( rp_filter=1),則還需要在規則和預設路由中替換為實際的其他介面ip rule add iif eth0 ipproto tcp dport 22 lookup 1000eth0

這是一個非常簡單的方法,只需 3 個命令即可實現目標。

如果 VPN 允許傳入流量,可以調整這以從某些特定 LAN 接收 SSH 或來自 NUC 的地址塊,但這在任何情況下都不允許從使用這兩者的同一個公共 IP 源接收 SSH 連接目的地/路線同時。

使用 AP 的 MAC 地址和標記進行策略路由

與以前的方法不同,有一種間接方法可以將傳入的數據包辨識為來自 AP 網關而不是來自 NUC:它的乙太網源 MAC 地址。

這不能由策略路由直接使用,但可以使用防火牆標記標記此類傳入數據包。策略路由可以使用標記,並且有一些方法可以在回複數據包上設置此標記。

我將傳入部分和回复部分分開。由於這不依賴於特定類型的傳入流量,因此無需更改即可處理稍後從 AP 轉發到桌面的其他埠。

我將在下面假設:

  • AP 的 MAC 地址(ip neigh show 192.168.10.1在 ping 之後在桌面上看到)的值為 02:00:00:ac:ce:55。替換下面的這個值。

傳入和常用設置

應該看看 Netfilter、iptables和路由如何在這個示意圖上互動:

Netfilter 和通用網路中的數據包流

raw/PREROUTING 中的*iptables規則將標記數據包。*然後通過策略路由以與之前類似的方式完成此操作。

iptables -t raw -A PREROUTING -i eth0 -m mac --mac-source 02:00:00:ac:ce:55 -j MARK --set-mark 1

ip route add default via 192.168.10.1 table 1000 
ip rule add fwmark 1 lookup 1000

回复

有兩種處理回复的方法:

  • 簡單和自動,僅 TCP

只能與 TCP 一起使用,不能與其他協議一起使用,包括不包括 UDP。

由於目標是 TCP 埠 22,這對於 OP 的情況來說已經足夠了。只需完成傳入部分:

sysctl -w net.ipv4.tcp_fwmark_accept=1
sysctl -w net.ipv4.fwmark_reflect=1

說明:

接受新連接時創建的每個 TCP套接字都將繼承第一個數據包的標記,就好像SO_MARK套接字選項僅用於此連接一樣。具體來說,所有回复流量將通過傳入流量到達的同一網關路由回,使用路由表 1000 設置標記時。

以類似的方式,由核心直接處理的回複數據包(如 ICMP 回顯回复或 TCP RST 以及 TCP FIN 的某些情況)繼承傳入數據包的標記。例如,如果沒有 TCP 套接字偵聽(即:SSH 伺服器在桌面上停止),就會出現這種情況。如果沒有此標記,則通過 AP 的 SSH 連接嘗試將超時,而不是連接被拒絕,因為 TCP RST 將通過 NUC 路由(並被遠端客戶端忽略)。或者…

  • 通過在數據包和conntrack條目之間傳輸標記並返回回複數據包的通用處理

標記可以在 conntrack 條目中被記憶為connmark ,**以使其影響流的所有進一步數據包,包括回複數據包,方法是將其複制回 mangle/OUTPUT 從conntrackmark。完成傳入部分:

iptables -t mangle -A PREROUTING -m mark --mark 1 -j CONNMARK --set-mark 1
iptables -t mangle -I OUTPUT -m connmark --mark 1 -j MARK --set-mark 1

這將處理所有情況(包括 TCP RST 和 UDP)。因此,AP 可以配置為將任意傳入的 TCP 或 UDP 流量轉發到桌面。此部落格中的其他文件


各種各樣的

注意事項

  • 當一個地址被刪除(然後可能又被添加回來)或一個介面被關閉(然後又被啟動)時,所有手動添加的關聯路由都將被刪除並且不會重新出現。因此,手動ip route命令至少應該與配置桌面網路的工具集成,以便在每次建立網路連接時添加它們。
  • 每個工具都有不同的方式來進行高級網路配置,這可能是不完整的。例如,Ubuntu 的Netplan不會在其routing-policy設置中記錄是否可以使用iif loipproto tcp sport 22. 應該首選允許使用自定義腳本來替換不可用功能的工具(例如ifupdownNetworkManager可以這樣做)。
  • 挑剔:對於使用最後一種方法的極其複雜的情況,在 VPN 允許傳入流量的情況下,單個遠端(公共)IP 地址將使用兩條路由(視為兩個不同的公共 IP 地址)兩次連接到同一個桌面服務,並且為兩個目的地使用相同的源埠,桌面只會看到兩次相同的流並且會混淆(兩個 UDP 將被合併,第二個 TCP 將失敗)。這通常可以在路由時處理(使用conntrack 區域和/或自動conntrack更改源埠),對於這裡的主機情況可能無法處理。

獎金

如果 Desktop 實際上是一個路由器,那麼最後一個使用標記和 CONNTRACK 的方法應該如何更改。到容器的路由必須複製到表 1000。這應該可行,但尚未使用 Docker 進行測試(這可能會帶來額外的挑戰)。

假設這裡:

  • 桌面通過名為br0的介面(Docker 將使用docker0作為預設網路)在 LAN 172.17.0.0/16 中路由 NAT-ed 容器,本地 IP 地址為 172.17.0.1/16
  • 桌面 DNAT 將一些埠指向這些容器

變化:

  • 規則和路線

到容器的路由必須從主路由表複製到表 1000。如果容器/虛擬化工具動態添加新介面和路由,新路由必須手動(或使用工具中的某些 API 觸發的某些腳本機制)也可以添加到表 1000 中。

ip route add 172.17.0.0/16 dev br0 table 1000

如果沒有這個,通過 AP 並標記(在下一個項目符號中)的傳入連接將被路由AP。

  • 在原始表中保留之前關於 MAC 地址的規則。
  • 刪除mangle表中之前的規則
iptables -t mangle -F
  • 把這些規則改為:
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -m connmark ! --mark 0 -j CONNMARK --restore-mark
iptables -t mangle -A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark

(對於這種單標記情況,可以以更多行為代價進行一些優化)

第一個 PREROUTING 規則確保不會用值為 0 的數據包標記覆蓋 conntrack 標記。第二個 PREROUTING 規則為最初通過 AP 建立的流的一部分來自容器(單個數據包最初未標記)的路由流量設置標記。

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