![Nftables DNAT 似乎不起作用](https://rvso.com/image/1615273/Nftables%20DNAT%20%E4%BC%BC%E4%B9%8E%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8.png)
我正在嘗試使用 nftables 在我的新 centos 8 上設定 DNAT。這個實用程式(和 centos 8)對我來說是新的,我已經使用 iptables(centos 到 6)很多年了。
我的假設是我沒有正確設定 DNAT 啟動的東西,但我可能只是沒有正確使用這些工具。或兩者。
無論如何,以防萬一,這是我之前關於同一盒子上的一些路由問題的問題:多個網際網路連接,傳入封包位於錯誤的 NIC 連接埠(入站路由問題?)(問題是 ARP 流量,已解決)。
下面是我目前設定的草圖,藍線標記了我想要發生的事情(預期的「路徑」)
基本上,資料包來自互聯網,透過介面 2 (ens2),透過本地介面(ens5,本地 IP 192.168.1.10)DNAT 到 192.168.1.2。 (一旦工作正常,將對 ens 3 和 4 進行相同的設置,轉到同一 LAN 上的幾個不同的虛擬機器)
我已經驗證資料包進入正確的介面(預期的 nft 日誌觸發器),但是 conntrack -E
沒有顯示任何內容。
另外,centos 6 盒子(實際目標,192.168.1.2)上的 iptables 日誌記錄沒有顯示任何內容(很久以前放置的相同日誌記錄在我上次檢查時(幾個月前)顯示了預期輸出,因此該盒子理論上應該沒問題)
這是我現在的 nftables 腳本,IP/IF 已翻譯以匹配草圖。
table ip nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
iif "ens2" goto PREROUTING_RDS2
iif "ens3" goto PREROUTING_RDS3
}
chain PREROUTING_RDS2 {
tcp dport { http, https } log prefix "RDS2_dnat-3 "
tcp dport { http, https } dnat to IP_6
}
chain PREROUTING_RDS3 {
tcp dport { http, https } log prefix "RDS3_dnat-3 "
tcp dport { http, https } dnat to IP_6
}
}
table inet filter {
chain INPUT {
type filter hook input priority 0; policy drop;
#
iif "lo" accept
#
# allow ping
ip protocol icmp icmp type echo-request limit rate 1/second log prefix "PING "
ip protocol icmp icmp type echo-request limit rate 1/second accept
# following is required and must be BEFORE the ct state established otherwise the ping flooding will not be stopped
ip protocol icmp drop
#
ct state established,related accept
ct status dnat accept
#
iifname "ens5" goto INPUT_LOCAL
#
# now we drop the rest
ct state invalid log prefix "INPUT_STATE_INVALID_DROP: "
ct state invalid drop
log prefix "INPUT_FINAL_REJECT: "
reject with icmpx type admin-prohibited
}
chain FILTER {
type filter hook forward priority 50; policy drop;
iif "ens2" goto FILTER_RDS2
iif "ens3" goto FILTER_RDS3
}
chain INPUT_LOCAL {
tcp dport ssh goto INPUT_LOCAL_ssh
}
chain INPUT_LOCAL_ssh {
ip saddr IP_MY_PC accept
}
chain FILTER_RDS2 {
oifname "ens5" ip daddr IP_6 tcp dport { http, https } accept
}
chain FILTER_RDS3 {
oifname "ens5" ip daddr IP_6 tcp dport { http, https } accept
}
}
先感謝您。
答案1
其實,這個問題如果不仔細研究一下,是很難回答的。之前的問答解決初始設定Centos8。解決方案變得非常複雜。考慮到為此必須採取的配置類型,可能不值得每個接口擁有一個 IP,在同一 LAN 上有多個接口,而不是同一接口上的所有 IP,特別是考慮到它處於虛擬環境中:不會有任何加速。對配置的任何更改都必須反映在以下命令中,因此正確管理這一點將很困難。
Centos8路由器
由於為了解決同一 LAN 中的多個介面問題,需要額外的路由表,因此在此 Q/A 中Centos8作為路由器,必須將更多路由條目從主表複製到附加路由表:
# ip route add 192.168.1.0/24 dev ens5 table 1001 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1002 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1003 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1004 src 192.168.1.10
否則收到的任何資料包恩斯1,恩斯2,恩斯3或者恩斯4和脫氧核糖核酸編輯透過恩斯5將失敗反向路徑過濾器因為沒有路線可以通過恩斯5在那些桌子上。
當然這還不夠:回覆資料包中沒有任何資訊(例如:從分離6)關於使用了什麼介面以及應該以相反的方式重複使用。因此必須使用 netfilter 的 conntrack 來記住每個流的資訊。在 nftables 規則中,刪除整個ip nat
表:
# nft delete table ip nat
並將其替換為這個新表ip markandnat
:
# nft -f - << 'EOF'
table ip markandnat {
map iif2mark {
type iface_index : mark;
elements = {
ens1 : 101,
ens2 : 102,
ens3 : 103,
ens4 : 104
}
}
map mark2daddr {
type mark : ipv4_addr;
elements = {
102 : 192.168.1.2,
103 : 192.168.1.2, # same IP, as per OP's config
104 : 192.168.1.4 # some other VM
}
}
chain premark {
type filter hook prerouting priority -150; policy accept;
meta mark set ct mark meta mark != 0 return
meta mark set iif map @iif2mark meta mark != 0 ct mark set meta mark
}
chain prenat {
type nat hook prerouting priority -100; policy accept;
tcp dport { http, https } dnat to meta mark map @mark2daddr
}
}
EOF
這將映射介面 => 標記 => dnat 目的地,同時將標記儲存為 conntrack 的標記(請參閱末尾的鏈接康馬克用法)。現在,透過新增以下規則,路由堆疊將可用並使用此標記,以指向相同的附加路由表:
# ip rule add pref 11001 fwmark 101 table 1001
# ip rule add pref 11002 fwmark 102 table 1002
# ip rule add pref 11003 fwmark 103 table 1003
# ip rule add pref 11004 fwmark 104 table 1004
但仍有一個缺失的部分:再次關於反向路徑過濾器。當使用標記時,反向路徑過濾器不會使用標記變更的新路由進行重新檢查,並且通常會失敗檢查。其實有一個未記錄的功能,2009/2010 年核心 2.6.33/2.6.32.8 中添加,這恰好解決了這個問題,而不需要使用寬鬆的反向路徑模式:src_valid_mark
。
# sysctl -w net.ipv4.conf.ens1.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens2.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens3.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens4.src_valid_mark=1
分離6伺服器
如果您想暫時使用備用網關,即使這再次增加了複雜性並且可能會產生不可預見的微妙副作用,也可以透過使用標記來實現。由於是 CentOS 6,nftables不可用,所以iptables將會被使用。
我會考慮分離6VM 在(唯一)介面上具有 IP 192.168.1.2/24乙太網路0,預設網關 192.168.1.1。讓我們為備用網關 192.168.1.10 新增的路由表和規則:
# ip route add table 10 default via 192.168.1.10
# ip rule add fwmark 10 lookup 10
放在iptables規則(這裡僅碾壓需要表格):
# iptables-restore << 'EOF'
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -j CONNMARK --restore-mark
-A PREROUTING -m mark ! --mark 0 -j RETURN
-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j MARK --set-mark 10
-A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j MARK --set-mark 10
-A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark
-A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark
COMMIT
EOF
現在,在連接埠 80 或 443 上接收到的任何流都會標記傳入資料包及其回應。路由堆疊將使用此標記將傳入和回應的網關變更為 192.168.1.10 (粉碎/輸出觸發重新路由檢查,請參閱下面的第二個連結)。
看來這種情況下不需要使用src_valid_mark
,但是設定一下即可,rp_filter=2
如果不起作用就設定一下。此設定不允許同時接收脫氧核糖核酸透過 192.168.1.1 編輯流量。
一些連結:
答案2
從評論來看,最直接和最重要的遺漏是關閉 ip 轉發。只是:
echo 1 > /proc/sys/net/ipv4/ip_forward
並檢查 DNATted 封包現在是否到達 IP6。
第二個問題是不對稱路由。 DNATted 資料包透過 192.168.1.10 (IP5) 到達 IP6,並在此處進行修改(目標位址已更改)。傳回封包將通過 LAN 上的預設閘道 (182.168.1.1),並且它們在到達連接來源的路由上不會被修改。它們可能會保留其 RFC1918 位址,或會被 SNAT 到 192.168.1.1 上的其他位址,並且永遠不會符合其目的地上的任何連接,並且可能會被丟棄。
編輯:
因此,為了解決 FORWARD 鏈,我將其重寫為以下內容(恕我直言,更簡單):
table inet filter {
:
chain FORWARD {
type filter hook forward priority 0; policy drop;
ct state established,related accept
ct status dnat accept
}
:
}