前言#
在翻译过程中,需要特别注意保持所有 Markdown 语法和标签的完整性,不改变 HTML 标签的功能,以确保翻译后的内容不会影响任何语法或标签的渲染。请按照以下规则进行翻译:
-
识别和翻译文本内容:只识别和翻译 Markdown 中的纯文本内容,包括标题、段落和列表项中的文本。
-
保留标签和属性:遇到 HTML 标签(如、
-
特殊语法处理:对于 Markdown 特定的语法(如链接、图像标签),只翻译描述性文本部分(如 alt text),不改变链接或语法结构。
-
保持格式不变:确保所有 Markdown 格式(如粗体、斜体、代码块)在翻译过程中保持不变。
-
你的任务是确保翻译内容准确无误,并且不破坏原始 Markdown 结构和 HTML 标签的功能。请在翻译过程中仔细检查,以确保语法和标签的正确渲染。
-
你只能返回翻译后的文本,不能返回其他内容。
重要提示:只返回翻译后的文本,不要返回其他内容。
将以下文本翻译为繁体中文:
前言#
當我想要寫這篇文章時,突然覺得哪裡不對。為什麼我在 xlog 寫的文章,都是日網絡的?
其實我並不擅長計算機網絡基礎,這是我知識領域裡很薄弱的一塊。日站也好,網絡業務也好,雖然我會做,但是那是很頂層的應用,自頂到下,其實我是並不擅長的。
但是這個,既是原因,也是結果。正因為我不擅長,所以就會遇到「很罕見」的問題,然後這個問題其實對大家來說並不是問題。
這也是一種非舒適區悖論。
nat loopback#
nat loopback,也叫 hairpinning。它解決的問題很簡單,就是。。。就是。。。。就是 nat 的 loopback!
你的公網 ipv4 假設是 1.2.3.4,你配置了一個端口轉發,從 1.2.3.4:1000,轉發到 192.168.1.2:1000,你的(其中一台)路由器是 192.168.1.1。如果你身處內網,以 / 24 為例,你的那網 ip 是 192.168.1.200。這個時候,你訪問 1.2.3.4:1000,是會遇到問題的。
通常上,路由器的端口轉發,背後對應的 iptable,是從外部(wan 側)作為開始,向內(lan)側轉發。換句話,wan 側監聽,任意的(外部)ip 請求端口 1000,都會被轉發到 192.168.1.2:1000。
對應規則
-A zone_wan_prerouting -p tcp -m tcp --dport 1000 -j DNAT --to-destination 192.168.1.2:1000
那麼問題來了,如果你並不在外網,而在內網,去訪問 1.2.3.4:1000 會怎麼樣呢?如果不做額外的設置(但是其實這個額外設置在很多情況下是默認存在的),那麼單憑這一條 dnat 規則是無法連通的。因為限制了入口鏈在 wan 側。
nat loopback?#
那麼,上邊說這個問題,是個什麼問題呢?nat loopback?
如果你不知道這個問題,那麼你就無法提出這個問題。
幸好科技帶給了我們新東西。在今天,我們可以通過直接問 chatgpt,來得到我們的問題是什麼。
問問問題。而不是問問題。Ask what the question is, instead of how to solve it.
這是我對於 chatgpt 的典型用法。在浩瀚的技術門類中,傳統的查詢和技術學習路線,去空中樓閣地做一件事情,太需要運氣了。你掌握了 ABCEFG 六門技術,但是你無法將他們聯結起來,曾經很多時候只能漫無目的地再嘗試 / 積累 HIGK,但是你真正缺少的是 D。大模型的生產力其實很有限,很多未知的東西她現在還很難做到,但是這個場景很典型。
nat loopback!#
其實在現代的路由器系統裡,nat loopback 早就給你考慮好了。
openwrt 裡,其背後的設計為 reflection。
你會得到這樣一個規則。
-A zone_lan_prerouting -s 192.168.1.0/24 -d 192.168.0.3/32 -p tcp -m tcp --dport 1000 -m comment --comment "!fw3: 1000 (reflection)" -j DNAT --to-destination 192.168.1.2:1000
注意標題裡的話,因為是非橋接環境,所以此處 openwrt 的 wan 環境 ip 是 192.168.0.3
links#
- https://openwrt.org/docs/guide-user/firewall/firewall_configuration#:~:text=to%20ipv4.-,reflection,-boolean
問題!#
橋接環境,openwrt 直接 pppoe 撥號,並不會導致 nat loopback 失效。但是在非橋接環境下,也就是光猫路由模式下,會的。
這裡的問題在於,openwrt 的 nat loopback,實際上是斷斷續續出過問題的,加上版本的碎片化,你在嘈雜的互聯網裡,很難找到你的錯誤究竟是哪個。
這直接導致了,問題很多,答案也很多,但是大家的插口並不兼容。
你會搜索到各種的,比如說這個某某版本的 openwrt 的 bug 呀,你要配置什麼內核 flag 呀,種種「對」的方法。對,但是解答不了你的問題。
這個問題,大模型目前也幫不了你。非但幫不了,她可太擅長在這個問題上擦邊捣亂了。
她最擅長的事情是,搭建草台班子。
問題的根本原因是,這條規則,僅設置了 192.168.0.3 為入口,而實際上的入口,應該也包括 public wan。
-A zone_lan_prerouting -s 192.168.1.0/24 -d 192.168.0.3/32 -p tcp -m tcp --dport 1000 -m comment --comment "!fw3: 1000 (reflection)" -j DNAT --to-destination 192.168.1.2:1000
也就是額外需要
-A zone_lan_prerouting -s 192.168.1.0/24 -d 1.2.3.4/32 -p tcp -m tcp --dport 1000 -j DNAT --to-destination 192.168.1.2:1000
從 lan 側,訪問 pub ip,那麼直接轉發到目的主機。
但是這樣不夠優雅,對吧
完成#
IP=$(curl -s 4.ipw.cn | grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' | head -n 1)
iptables -t nat -A PREROUTING -s 192.168.1.0/24 -d $IP/32 -p tcp -m tcp --dport 1000 -j zone_wan_prerouting
所以我們就可以直接添加一個自定義的防火墻規則,如果使用 nft,那麼大模型可以幫你。其實這個兩行,也是 chatgpt 寫的。
獲取到 public ip 之後,其實把請求扔回到zone_wan_prerouting
即可,不需要再重複寫一次目的主機。
其實可以更簡化 / 更通用為,不過這樣就和 openwrt 的 uci 綁定了,畢竟還有 padavan 呢。
LAN=$(uci show network.lan.ipaddr | cut -d"'" -f2)
IP=$(curl -s 4.ipw.cn | grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' | head -n 1)
iptables -t nat -A PREROUTING -s $LAN/24 -d $IP/32 -p tcp -m tcp --dport 1000 -j zone_wan_prerouting
padavan 下,其實處理的更優雅,並沒有 flection,而是
-A PREROUTING -d 1.2.3.4/32 -j vserver
-A PREROUTING -d 192.168.0.1/32 -j vserver
定義了vserver
作為外部輸入鏈。