1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | ----- 你做得非常好,在區域網路內進行測試是極其明智的步驟!而且你詳細記錄了測試結果和服務日誌,這對於診斷問題至關重要。 你的觀察是正確的:**連接埠轉發 (DNAT) 目前沒有如預期般運作。** 這是因為你的 `nftables` 規則設定了一個非常重要的**盲點**,導致它無法在目前的測試場景中發揮作用。 ----- ### 我們漏掉了什麼? 你目前的 `nftables` DNAT 規則是這樣寫的: `tcp dport 80 dnat to 127.0.0.1:1104` 這條規則的意思是:「當有封包的目的地埠是 **80** 時,將其轉發到 **127.0.0.1:1104**」。 **問題點就在於:** 1. **你沒有在樹莓派上運行任何監聽埠號 80 的服務。** 你的 `python3 -m http.server` 服務運行在 **1104 埠**。 2. **你期待透過埠號 80 訪問,但你的測試訪問的是樹莓派的 IP 地址**,而不是外部路由器的 IP。 **DNAT 規則的作用範圍:** DNAT 規則通常適用於**轉發進入路由器 (樹莓派) 的「外部」流量**。也就是說,它會改變那些**原本不以路由器為最終目的地**,而是要被轉發到內網其他設備的封包。 在你的測試情境中: * `http://raspberrypi.local` 或 `http://192.168.50.17` (埠號 80) * 當你在區域網路內的迷你電腦嘗試連接 `http://192.168.50.17` 時,這個請求封包的目的地 IP 是 `192.168.50.17` (樹莓派自身的 IP)。 * **流量的最終目的地就是樹莓派本身**。這類封包會走 `input` 鏈,而不是 `prerouting` 鏈。 * **DNAT 規則定義在 `prerouting` 鏈中,它不會處理發往本機的流量。** `prerouting` 鏈處理的是那些**即將被轉發**的流量。 ### 為什麼你的測試結果是這樣? * **`http://raspberrypi.local` (x)**:沒有運行埠號 80 的服務,且沒有 DNAT 規則將發往本機 80 埠的流量轉發出去。 * **`http://raspberrypi.local:1104` (o)**:直接連接到你樹莓派上運行的 `http.server` 服務的實際埠號,當然成功。 * **`http://192.168.50.17` (x)**:同上,沒有運行埠號 80 的服務,DNAT 規則不適用於發往本機的流量。 * **`http://192.168.50.17:1104` (o)**:同上,直接連接到服務的實際埠號,成功。 * **`http://127.0.0.1` (x)**:本地回環地址,沒有運行埠號 80 的服務。 * **`http://127.0.0.1:1104` (o)**:本地回環地址,直接連接到服務的實際埠號,成功。 簡單來說,你的 DNAT 規則現在就像在**高速公路的入口匝道**設置了一個轉向標誌,但是你所有的測試車輛都直接駛向了**高速公路上的服務區 (樹莓派本身)**,根本沒有經過入口匝道。 ----- ### 如何讓 DNAT 運作起來? 有兩種主要的方法來測試你的 DNAT 規則: #### 方法一:從「外部」網路測試 (真正的 DNAT 應用場景) 這是 DNAT 規則設計的真正目的。你需要一個**不同的網路**來模擬「外部」請求。 1. **確保你的樹莓派是一個「路由器」角色:** * 你的樹莓派需要有**兩個網路介面**: * 一個連接到你的**主路由器**(獲取外部 IP,假設是 `eth0` 或 `wlan0`)。 * 另一個介面連接到一個**獨立的子網路**(作為內部網路,例如通過另一個 `wlan` 介面作為 AP,或者 `eth0` 連接主路由,`usb_ethernet` 連接另一個單獨的網段)。 * **你的樹莓派目前可能只有一個介面連接到區域網路。** 如果只有一個介面,那麼所有的流量都將是發往本機的流量,DNAT 就不會生效。 #### 方法二:針對發往本機的流量也應用 DNAT (較常見的測試/單臂路由場景) 如果你只有一個網路介面,但仍然想測試 DNAT,或者你的樹莓派本身就是一個「單臂路由器」,那麼你需要添加一條規則到 `input` 鏈或使用 `OUTPUT` 鏈上的 `NAT` 規則來處理發往本機的流量。 最常見的解決方案是使用 **`OUTPUT` 鏈上的 DNAT 規則**來處理**從本機發出但目的地為本機外部 IP 的流量(通常稱為「髮夾 NAT」或 "hairpin NAT")**。 這條規則會捕捉那些: 1. 從樹莓派**自己**發出。 2. 目的地是**樹莓派自己的外部 IP 地址**。 3. 目的埠號是 **80**。 它會將這些流量重新定向到 **127.0.0.1:1104**。 **操作步驟 (在樹莓派 400 上):** 1. **添加 `OUTPUT` DNAT 規則:** ```bash # 注意:這裡的 chain 名稱可以自己定義,例如叫做 "my_output_dnat" sudo nft add chain ip nat output { type nat hook output priority 100 \; } sudo nft add rule ip nat output ip daddr 192.168.50.17 tcp dport 80 dnat to 127.0.0.1:1104 # 將 192.168.50.17 替換為你樹莓派當前在區域網路中的 IP 地址 ``` * **解釋:** * `ip daddr 192.168.50.17`: 目的地 IP 是樹莓派自己的 IP。 * `tcp dport 80`: 目的地埠號是 80。 * `dnat to 127.0.0.1:1104`: 將這些流量重定向到本機的 1104 埠。 * `priority 100` 或 `priority dnat`:`output` 鏈的 `nat` type 鉤子通常使用較高的數字優先級。 2. **再次測試:** * 從迷你電腦瀏覽器,嘗試連接:`http://192.168.50.17` * 從樹莓派 400 自身瀏覽器,嘗試連接:`http://127.0.0.1` (這條可能還是不行,因為 `OUTPUT` 規則通常是針對非回環介面的 IP) ### 建議的下一步 為了你當前的學習目標,**我建議你嘗試方案二,添加 `OUTPUT` 鏈的 DNAT 規則。** 這可以讓你繼續在單一網段內測試 DNAT 的效果,而不需要設置複雜的雙網卡路由環境。 請嘗試添加 `output` 鏈的 DNAT 規則,並確保將 `ip daddr` 替換為你樹莓派實際的區域網路 IP 地址。然後再次進行連線測試,並觀察服務日誌。 這是一個非常好的學習點,它讓你理解了不同 `nftables` 鉤子 (`prerouting`, `output`, `input`) 在封包流程中的具體作用。 |
Direct link: https://paste.plurk.com/show/bQpGg0PGThXw18cFNCfj