web-dev-qa-db-ja.com

NftablesDNATが機能していないようです

Nftablesを使用して新しいcentos8にDNATをセットアップしようとしています。このユーティリティ(およびcentos 8)は私にとって新しいものであり、私は長年にわたってiptables(centosから6)を使用してきました。

私の想定では、DNATを開始するために何かを適切にセットアップしていませんが、ツールを適切に使用していない可能性があります。または両方。

とにかく、それが重要な場合は、同じボックスのいくつかのルーティングの問題に関する私の前の質問があります: 複数のインターネット接続、間違ったNICポートの着信パケット(インバウンドルーティングの問題? ) (問題はARPフラックスでした、解決しました)。

以下は私の現在の設定のスケッチであり、青い線は私が何をしたいのかを示しています(予想される「パス」)

enter image description here

基本的に、パケットはインターネットから着信し、インターフェイス2(ens2)を経由して、ローカルインターフェイス(ens5、ローカルIP 192.168.1.10)を介して192.168.1.2にDNATされます。 (これが機能すると、同じLAN上のいくつかの異なるVMに移動して、ens 3と4にも同じことがセットアップされます)

パケットが正しいインターフェイス(予想される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
ciuly

実際、この質問には、 前のQ/Acentos8の初期設定を解決することをよく見ないと答えることは困難です。解決策は非常に複雑になります。このために配置する必要のある構成の種類を考慮すると、特に仮想環境にあることを考えると、同じインターフェイス上のすべてのIPではなく、同じLAN上に複数のインターフェイスを持つインターフェイスごとに1つの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 

それ以外の場合、ens1ens2ensまたはens4およびdnat edで受信されたパケットthrough ens5は失敗します reverse path filter これらのテーブルにはens5を通るルートがないためです。

もちろん、それだけでは十分ではありません。応答パケットには、使用されたインターフェイスに関する情報がなく(たとえば、centos6から戻ってくる)、逆に再利用する必要があります。したがって、この情報は、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のマークとして保存されます(connmark使用法については最後のリンクを参照してください)。これで、同じ追加のルーティングテーブルを指すように、以下のルールを追加することで、このマークがルーティングスタックで使用可能になります。

# 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

centos6サーバー

代替ゲートウェイを一時的に使用したい場合は、それが再び複雑さを増し、おそらく予期しない微妙な副作用が発生したとしても、マークを使用することで可能です。 CentOS 6であるため、nftablesは使用できないため、iptablesが使用されます。

centos6 VMは(一意の)インターフェイスethにIP192.168.1.2/24を持ち、デフォルトはgw192.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ルールを配置します(ここではmangleテーブルのみが必要です):

# 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に変更するために使用されます(mangle/OUTPUTは、再ルーティングチェックをトリガーします。以下の2番目のリンクを参照してください)。

この場合、src_valid_markを使用する必要はないようですが、設定するか、機能しない場合はrp_filter=2を設定してください。この設定では、192.168.1.1を介したdnat edトラフィックの受信も許可されません。


いくつかのリンク:

1
A.B

コメントから判断すると、最も直接的で重要な省略はip転送がオフになっています。ただ:

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

dNATtedパケットがIP6に到着するかどうかを確認します。

2番目の問題は非対称ルーティングです。 DNATtedパケットは192.168.1.10(IP5)を介してIP6に到達し、そこで変更されます(宛先アドレスが変更されます)。戻りパケットはLAN上のデフォルトゲートウェイ(182.168.1.1)を通過し、接続オリジンへのルートで変更されません。 RFC1918アドレスを保持するか、192.168.1.1で別のアドレスにSNATされ、宛先の接続と一致することはなく、ドロップされる可能性があります。

編集:

したがって、FORWARDチェーンに対処するために、次のように書き直します(はるかに単純なIMHO)。

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