Nftables DNATが動作していないようです

Nftables DNATが動作していないようです

私は、nftables を使用して新しい CentOS 8 に DNAT を設定しようとしています。このユーティリティ (および CentOS 8) は私にとって新しいものですが、私は長年 iptables (CentOS から 6 まで) を使用してきました。

私の推測では、DNAT が起動するように何かを適切に設定しなかったのですが、ツールを適切に使用していないだけかもしれません。あるいはその両方かもしれません。

とにかく、もし関係があるなら、同じボックスでのルーティングの問題に関する私の以前の質問を以下に示します。複数のインターネット接続、間違った NIC ポートへの受信パケット (受信ルーティングの問題?)(問題は ARP フラックスでしたが、解決しました)。

以下は私の現在の設定のスケッチです。青い線は私が実現したいこと(予想される「パス」)を示しています。

ここに画像の説明を入力してください

基本的に、パケットはインターネットから入ってきて、インターフェース 2 (ens2) を通過し、ローカル インターフェース (ens5、ローカル IP 192.168.1.10) を経由して 192.168.1.2 に DNAT されます。(これが機能すると、ens 3 と 4 にも同じ設定が行われ、同じ LAN 上のいくつかの異なる VM に送信されます)

パケットが正しいインターフェース (予想される nft ログ トリガー) で着信することを確認しましたが、 conntrack -E何も表示されません。

また、Centos 6 ボックス (実際のターゲット、192.168.1.2) の iptables ログには何も表示されません (何年も前に設定された同じログは、数か月前に最後に確認したときには期待どおりの出力を示していたため、そのボックスは理論的には問題ないはずです)

以下は、スケッチに合わせて IP/IF を変換した、現在の私の nftables スクリプトです。

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

実際、この質問は、前回のQ/A初期設定の解決セントロス8. ソリューションは非常に複雑になります。このために実施する必要がある構成の種類を考慮すると、すべての IP を同じインターフェイス上に配置するのではなく、同じ LAN 上の複数のインターフェイスでインターフェイスごとに 1 つの IP を設定することはおそらく価値がありません。特に仮想環境の場合、速度は上がりません。構成の変更はすべて、以下のコマンド全体に反映される必要があるため、これを正しく管理することは困難です。


セントロス8ルーター

同じLAN内の複数のインターフェースの問題を解決するために追加のルーティングテーブルがあるので、このQ/Aではセントロス8ルータとして動作している場合は、メイン テーブルから追加のルーティング テーブルにさらに多くのルート エントリを複製する必要があります。

# 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またはens4そしてdnated を通じてエンス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 を持っていますeth0、デフォルトのゲートウェイは 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に変更するために使用されます(マングル/出力再ルート チェックがトリガーされます (以下の 2 番目のリンクを参照)。

この場合は使用する必要はないようですsrc_valid_markが、設定するか、rp_filter=2動作しない場合は設定してください。この設定では受信も許可されません。dnat192.168.1.1 を経由するトラフィック。


いくつかのリンク:

答え2

コメントから判断すると、最も直接的かつ重要な省略は、IP 転送をオフにすることです。次のとおりです。

echo 1 > /proc/sys/net/ipv4/ip_forward

そして、DNAT されたパケットが IP6 に到着するかどうかを確認します。

2 番目の問題は、非対称ルーティングです。DNAT されたパケットは、192.168.1.10 (IP5) を経由して IP6 に到達し、そこで変更されます (宛先アドレスが変更されます)。返信パケットは、LAN のデフォルト ゲートウェイ (182.168.1.1) を通過し、接続元へのルートで変更されることはありません。返信パケットは、RFC1918 アドレスを保持するか、192.168.1.1 で別のアドレスに SNAT され、宛先のどの接続とも一致せず、破棄される可能性があります。

編集:

したがって、FORWARD チェーンに対処するには、次のように書き直します (私見では、はるかに簡単です)。

table inet filter {
:
    chain FORWARD {
            type filter hook forward priority 0; policy drop;
            ct state established,related accept
            ct status dnat accept
    }
:
}

関連情報