Web伺服器無法通過nftables埠轉發上的公共IP地址訪問自己
我有一個 WireGuard 伺服器作為邊緣路由器。將所有 http 流量轉發到我的網路伺服器。一切正常,但有一個問題。Web 伺服器無法通過 WireGuard 公共 IP 地址訪問自身。在網路伺服器電腦上,我無法使用網路瀏覽器訪問我的網站。
我發現
daddr
基於 nat 可以解決這個問題,但我想知道是否有更好的方法,因為 IP 地址可能會有所不同但iif
已修復。我的 Netgear WiFi 路由器可以進行埠轉發,而不會出現這種問題。但我無法檢查它的內部規則,我也不認為它使用daddr
基於 nat。這是WireGuard 伺服器的配置。
wg0
interface: wg0 Address = 10.0.0.1/24 public key: (hidden) private key: (hidden) listening port: 51820 peer: (hidden) endpoint: (hidden):51820 allowed ips: 10.0.0.2/32 latest handshake: 56 seconds ago transfer: 20.69 MiB received, 115.85 MiB sent
表格
table ip firewall { chain input { type filter hook input priority filter; policy drop; ct state established,related accept udp dport {51820} accept tcp dport {22} accept ip saddr 10.0.0.0/24 accept } chain prerouting { type nat hook prerouting priority dstnat; iif eth0 tcp dport {80,443} dnat to 10.0.0.2 } chain postrouting { type nat hook postrouting priority srcnat; ip saddr 10.0.0.0/24 masquerade } chain forward { type filter hook forward priority filter; policy drop; ct state established,related accept ct status dnat accept ip saddr 10.0.0.0/24 accept } }
這是Web伺服器的配置。
wg0
interface: wg0 Address = 10.0.0.2/24 public key: (hidden) private key: (hidden) listening port: 51820 fwmark: 0xca6c peer: (hidden) endpoint: (hidden):51820 allowed ips: 0.0.0.0/0 latest handshake: 25 seconds ago transfer: 114.69 MiB received, 3.56 MiB sent persistent keepalive: every 25 seconds
這是NAT 環回處理的一個案例。
目前,WireGuard 伺服器(“WGS”)僅從eth0重定向,因此從**wg0接收的流量不會發生任何事情。
On 應將 WGS 傳入流量重定向到用於其自己的公共 IP 地址的埠 80,443。但是有一個問題:如何在路由前步驟猜測數據包將被分類為本地而不知道規則中的本地目標 IP 地址,而這種分類發生在尚未發生的路由決策步驟?(有關數據包生命週期中這些不同步驟的摘要,請參見此示意圖)。
可以通過使用nftables的
fib
表達式(需要kernel >= 4.10 )動態地在數據包路徑中詢問核心如何路由數據包:FIB 表達式
fib {saddr | daddr | mark | iif | oif} [. ...] {oif | oifname | type}
fib表達式查詢fib(轉發資訊庫)以獲取資訊,例如特定地址將使用的輸出介面索引。輸入是元素的元組,用作fib查找函式的輸入。
這可以在路由步驟之前執行,並且僅當數據包被暫時歸類為本地目的地時才用於進行重定向:到屬於 WGS 的地址。由於這是在prerouting中完成的,一旦發生實際的路由決策,它將不再被歸類為本地數據包,而是被歸類為路由數據包(返回給發送者)。
將從wg0 (因此來自 Web 伺服器(“WS”))接收的流量重定向到屬於 WGS 的任何地址:
nft add rule ip firewall prerouting iif wg0 tcp dport '{ 80, 443 }' fib daddr type local dnat to 10.0.0.2
如果需要(例如:仍然能夠訪問僅偵聽 WGS 的 wg0 地址的私有管理介面),它可以被進一步過濾,因此只有 WGS 本地但不是wg0的 10.0.0.1 的目標將通過使用它來匹配:
nft add rule ip firewall prerouting iif wg0 daddr != 10.0.0.1 tcp dport '{ 80, 443 }' fib daddr type local dnat to 10.0.0.2
由於 nat/postrouting 鏈已經偽裝了 10.0.0.0/24 源範圍內的任何內容,因此不需要額外的步驟:WS 的源地址將替換為 wg0 上的 WGS 的地址。NAT 環回需要更改源(WS 不能接受來自其自身 IP 地址的數據包)。
可選地,可以在此偽裝規則之前插入一個專用規則,以選擇另一個 IP 地址來代替。任何地址都可以(而不是生成的源 10.0.0.1),無論是 WGS 本地地址還是非本地地址,只要在 WS 上此地址通過 WGS 路由即可。由於沒有提供 WS 和 WGS 的路由表,下面的範例可能是錯誤的。選擇不存在的 10.0.1.2 地址替換 WS 自己的 10.0.0.2,仍然允許 WS 自己的日誌輕鬆辨識來自自己的請求:
nft insert ip firewall postrouting ip saddr 10.0.0.2 ip daddr 10.0.0.2 snat to 10.0.1.2
或過於保守:
nft insert ip firewall postrouting ip saddr 10.0.0.2 ip daddr 10.0.0.2 tcp dport '{ 80, 443 }' ct status dnat oif wg0 snat to 10.0.1.2