Linux

將介面的公共 IP “給予”給具有本地 IP 的另一台主機

  • October 2, 2021

我有一台機器(執行 openSUSE Leap 15.3),它有多個公共 IP 地址,用作一些額外主機的網關。我需要讓網關上的一個公共 IP 就像它屬於連接到它的一台機器一樣(流量被透明地轉發)。

iptables-save目前的輸出如下(包括一些不相關的 Docker 規則,但敏感部分已編輯):

# Generated by iptables-save v1.8.7
*filter
:INPUT ACCEPT [9747976:4527721149]
:FORWARD ACCEPT [12638879:4423560060]
:OUTPUT ACCEPT [8913992:2531503118]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed
# Generated by iptables-save v1.8.7
*nat
:PREROUTING ACCEPT [480085:188100350]
:INPUT ACCEPT [62951:4107383]
:OUTPUT ACCEPT [150:9857]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -i eth0 -j DNAT --to-destination 10.125.0.2
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed

據我所知,唯一相關的部分是:

-A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -i eth0 -j DNAT --to-destination 10.125.0.2
-A POSTROUTING -j MASQUERADE

這仍然存在許多問題:

  • 當內部機器啟動出站連接時,它的 IP 被 NAT 為網關的主地址,而不是我試圖給它的地址。
  • 接收連接時,它們似乎來自網關的本地 IP,而不是原始 IP(應該有解決方法,因為這是預設網關)。
  • 如果服務0.0.0.0在網關上偵聽,則該埠上的連接不會被重定向,它們會轉到該服務。

我試圖將其他一些問題的答案拼接在一起,例如:

但是由於我缺乏重要的 iptables 經驗,我無法解決我的問題,或者解決了一些只是為了讓其他人彈出。

任何人都可以提出一些規則來達到這種效果嗎?或者也許有一種方法可以在沒有 iptables 的情況下做到這一點?

當內部機器啟動出站連接時,它的 IP 被 NAT 為網關的主地址,而不是我試圖給它的地址。

這應該通過以下方式解決:

iptables -t nat -I POSTROUTING 1 -s 10.125.0.2 -o eth0 -j SNAT --to-source <FORWARD_IP>

它被添加到前面,因此它會首先觸發,檢測數據包來自該系統並將其轉換為指定的 IP,而不是從介面中選擇地址。

接收連接時,它們似乎來自網關的本地 IP,而不是原始 IP(應該有解決方法,因為這是預設網關)。

此問題與以下 SNAT 規則有關:

iptables -t nat -A POSTROUTING -j MASQUERADE

它太寬了*。您正在對每個方向的**所有內容*進行 SNAT ,這既不高效也不安全。它匹配所有內容,包括您的 DNATed 數據包。它們首先被目標轉換為私有地址,然後它們的源被此規則轉換為從分配了 10.xxx 地址的私有介面中挑選的地址。

我懷疑您正試圖用一條規則覆蓋所有公共介面和所有專用網路。雖然 Linux(IP 集)中有地址列表,但沒有介面列表,因此僅使用一條規則無法正確執行此操作。

至少使用源地址過濾它(例如要源翻譯哪些地址):

iptables -t nat -A POSTROUTING -s 10.125.0.0/24 -j MASQUERADE

如果您有多個專用網路,請添加更多此類規則。

我認為最好為每個公共介面創建一個單獨的規則,這樣通過私有介面發出的數據包永遠不會得到原始碼轉換,無論它們擁有什麼源地址,例如iptables -t nat -A POSTROUTING -s 10.125.0.0/24 -o eth0 -j MASQUERADE等等。這樣從 10.xxx 到 172.xxx 的數據包也不會被轉換,並且您在兩個網路中的服務將直接看到彼此的 IP,仍然可以在 FORWARD 過濾器鏈中選擇性地過濾它們。

如果服務正在網關上的 0.0.0.0 上偵聽,則該埠上的連接不會被重定向,它們會轉到該服務。

最後,我不完全理解這一點。我在評論裡問,你沒有回答。哪些連接,來自哪裡,源 IP 是什麼?

DNAT 處理髮生在路由決策之前,這就是為什麼鏈被稱為“PREROUTING”的原因。它從不檢查是否有某個本地程序在該埠上偵聽。本地服務有機會回答的唯一方法是讓數據包通過 INPUT 鏈。為此,路由程式碼必須決定它是發往本地機器的,因此它必須是乙太不翻譯或翻譯成該系統分配的某個地址。

根據目前規則,從私有網路發送到公共 IP 的數據包不應轉換,因為它們不是通過eth0. 因此,他們將由當地服務機構提供服務。但這並不取決於本地服務是否正在執行;如果不是,您將收到“連接被拒絕”。

如果您需要從 LAN 到 <FORWARD_IP> 的數據包按照相同的 DNAT 規則進行轉換,請丟棄該-i eth0匹配項:

iptables -A PREROUTING -d &lt;REDACTED_FORWARDING_IP&gt;/32 -j DNAT --to-destination 10.125.0.2

但是,我反對如此廣泛的規則。在我看來,DNAT 規則最好盡可能嚴格,因此您最好通過 protos (tcp/udp) 和您在 10.125.0.2 上執行的服務的埠進行過濾。如果那是一個 web 伺服器,只轉發 tcp/80 和 tcp/443,像這樣:iptables -A PREROUTING -d &lt;REDACTED_FORWARDING_IP&gt;/32 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 10.125.0.2.

有什麼問題?說,您正在使用 ping 檢查某些內容。此 ping 結果將取決於此內部系統狀態,它是您實際 ping 的系統。這令人困惑。這不是大多數係統管理員在 ping 路由器時期望看到的行為。所以最好讓 ping 由主機回答。

引用自:https://serverfault.com/questions/1079372