Nftables DNAT 似乎不起作用

Nftables DNAT 似乎不起作用

我正在嘗試使用 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
    }
:
}

相關內容