名前空間なしでネットワーク仮想コピーにトラフィックをルーティング

名前空間なしでネットワーク仮想コピーにトラフィックをルーティング

下の図のように、Linuxカーネルを介してトラフィックをルーティングすることは可能ですか?同じIP範囲を使用して、「内部」ネットワーク外のデバイスの正確なコピーをエミュレートしながら、相手が同じIPを持っていることを知らずに、内部および外部デバイスが互いに通信できるようにしたいと思います。

マシンのネットワークインタフェースの低レベルの説明

例:デバイス次に、レスポンスはブローカーに再送信され、IP 192.168.2.5のデバイスXに送信されます。

私はこれがネットワークネームスペースを通して可能で効率的な偽装を可能にすることを知っています。しかし、私は名前空間の使用を避け、代わりにさまざまなトラフィック方向に他のルーティングテーブルと同じものを使用したいと思います。可能ですか?

正しく理解した場合、IP 範囲が重複して NAT を使用できません。そうですか?

ベストアンサー1

トポロジー

まず、ネットワークインタフェースを設定しますmiddleman。私はあなたがシステムコンソールにログインしたか、innerネットワークに関連していないインターフェースを介してアクセスしたと仮定しますouter。この回答の目的のために、私たちはインターフェースがmiddleman-eth0middleman内部」ネットワークに接続され、middleman-eth1「外部」ネットワークに接続されていると仮定します。これにより、次のネットワークトポロジが提供されます。

ネットワークトポロジ図

転送を有効にする

パケット転送が有効になっていることを確認する必要がありますmiddleman

sysctl -w net.ipv4.ip_forward=1

空の netfilter 構成で開始する必要があります。実行するとiptables-save出力は生成されません。

インターフェイスの設定

この目的のために、両方middleman-eth0ともmiddleman-eth1同じネットワーク構成を持っています。

ip addr add 192.168.2.1/24 dev middleman-eth0
ip addr add 192.168.2.1/24 dev middleman-eth1

これが変だと思ったら、そうなんですね!現在のルーティングテーブルはmiddleman次のとおりです。

192.168.2.0/24 dev middleman-eth1 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth0 proto kernel scope link src 192.168.2.1

これは特に役に立ちません。

VRF構成

私たちはLinuxを使って」仮想ルーティングと転送eth0"("VRF")。これにより、着信トラフィックが着信トラフィックとは異なるルーティングテーブルを表示できるように、システムに複数の隔離されたルーティングドメインを作成できますeth1

まず、VRF インターフェイスを作成します。

ip link add vrf-inner type vrf table 100
ip link set vrf-inner up
ip link add vrf-outer type vrf table 200
ip link set vrf-outer up

このコマンドは 2 つの VRF デバイスを設定し、各デバイスを特定のルーティングテーブルに関連付けます。

次に、各物理インターフェイスをVRFデバイスに接続します。

ip link set dev middleman-eth0 master vrf-inner
ip link set dev middleman-eth1 master vrf-outer

これらの変更の後、デフォルトのルーティングテーブルが空になります。

middleman# ip route show
<no output>

middleman-eth0表100は、(「内部」ネットワーク)に関連する規則を示しています。

middleman# ip route show table 100
broadcast 192.168.2.0 dev middleman-eth0 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth0 proto kernel scope link src 192.168.2.1
local 192.168.2.1 dev middleman-eth0 proto kernel scope host src 192.168.2.1
broadcast 192.168.2.255 dev middleman-eth0 proto kernel scope link src 192.168.2.1

middleman-eth1表200は、(「外部」ネットワーク)の規則を示しています。

middleman# ip route show table 200
broadcast 192.168.2.0 dev middleman-eth1 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth1 proto kernel scope link src 192.168.2.1
local 192.168.2.1 dev middleman-eth1 proto kernel scope host src 192.168.2.1
broadcast 192.168.2.255 dev middleman-eth1 proto kernel scope link src 192.168.2.1

この時点で、実際には2つの接続が切断されたネットワークがあります。

隔離されたルーティングドメインのネットワークトポロジの表示

「内部」ネットワークのホストは192.168.2.1に接続でき、接続されますmiddleman-eth0。 「外部」ネットワークのホストは次のことができます。返品192.168.2.1に連絡すると通話中になりますmiddleman-eth1

二人が会った場所

今、私たちがしなければならないことは、どちらか一方が192.168.3.0/24他方のアドレスを使用してノードに接続できるようにマッピングを設定することです。

192.168.3.0/24まず、すべてのノードに以下を介してネットワークにルーティングされることを知らせる必要がありますmiddleman。つまり、「内部」ネットワークと「外部」ネットワークの両方のすべてのノードで、次のものが必要です。

ip route add 192.168.3.0/24 via 192.168.2.1

上記では、middleman(a)192.168.3.0/24範囲内のアドレスを192.168.2.0/24範囲にマッピングし、(b)接続をルーティングするときに正しいルーティングテーブルが使用されていることを確認する必要があります。 (a)を達成するためにいくつかのルールを作成できますNETMAP

iptables -t nat -A PREROUTING -d 192.168.3.0/24 -j NETMAP --to 192.168.2.0/24
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j NETMAP --to 192.168.3.0/24

(b)を実装するために、まず受信インターフェイスに従ってパケットを表示します。

iptables -t mangle -A PREROUTING -i middleman-eth0 -d 192.168.3.0/24 -j MARK --set-mark 100
iptables -t mangle -A PREROUTING -i middleman-eth1 -d 192.168.3.0/24 -j MARK --set-mark 200

その後、これらのタグはルーティングテーブルを選択するために使用されます。

ip rule add prio 100 fwmark 100 lookup 200
ip rule add prio 200 fwmark 200 lookup 100

表100には「内部」ネットワークの規則があり、表200には「外部」ネットワークの規則があるため、これらの規則は「インターフェースに到着するパケットの場合はmiddleman-eth0決定に関連するルーティング表を使用してくださいmiddleman-eth1」と言い、その逆の場合同様です。 。

飛び散るボールをたどる

これらすべての操作が完了した後、192.168.2.10「内部」ネットワークのノードがpingを試みた場合192.168.3.10

  1. ルーティングエントリのため、パケットは192.168.3.0/24 via 192.168.2.1ブローカーにルーティングされます。
  2. パケット到着middleman-eth0
  3. パケットはMANGLEテーブルチェーンに到着PREROUTINGし、fwmarkを次に設定します。100
  4. パケットはNATテーブルチェーンに到達し、宛先にPREROUTINGマッピングされます。192.168.2.10
  5. fwmark 100 lookup 200パケットはルールに準拠したルーティングサブシステムに入ります。
  6. ルーティングテーブル200でヒットし、192.168.2.0/24 dev middleman-eth1カーネルがそれをデバイスに送信する。middleman-eth1
  7. パケットがNATテーブルチェーンに到着しPOSTROUTING、そのソースがにマッピングされます192.168.3.10
  8. パケットはアドレスが「外部」ノードに到着します192.168.2.10
  9. ...深呼吸をしてください...
  10. 外部ノードが応答を送信します。192.168.3.10
  11. 返信到着middleman-eth1
  12. 応答はMANGLEテーブルチェーンに到着PREROUTINGし、fwmarkを次に設定します。200
  13. 応答はNATテーブルチェーンに到着しPREROUTING、ターゲットにマッピングされます。192.168.2.10
  14. fwmark 200 lookup 100応答は、ルールに準拠したルーティングサブシステムに移動します。
  15. ルーティングテーブル100は192.168.2.0/24 dev middleman-eth0ルールと一致するので、カーネルはそれをデバイスに送信する。middleman-eth0
  16. 応答はNATテーブルチェーンに到着しPOSTROUTING、そのソースはテーブルチェーンにマップされます。192.168.3.10
  17. 応答は、192.168.2.10元の要求に対する応答を確認する「内部」ノードに到達します。

確認する

「内部」ノード0(192.168.2.10)でアドレスを使用して「外部」ノード0にpingしようとすると、内部ノード0で実行すると次のようになります192.168.3.10tcpdump -nn -i any icmp

07:01:58.125370 innernode0-eth0 Out IP 192.168.2.10 > 192.168.3.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125533 innernode0-eth0 In  IP 192.168.3.10 > 192.168.2.10: ICMP echo reply, id 12999, seq 1, length 64

私達はmiddleman見た:

07:01:58.125440 middleman-eth0 In  IP 192.168.2.10 > 192.168.3.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125459 middleman-eth1 Out IP 192.168.3.10 > 192.168.2.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125514 middleman-eth1 In  IP 192.168.2.10 > 192.168.3.10: ICMP echo reply, id 12999, seq 1, length 64
07:01:58.125518 middleman-eth0 Out IP 192.168.3.10 > 192.168.2.10: ICMP echo reply, id 12999, seq 1, length 64

「外部」ノード0には、次のものが表示されます。

07:01:58.125489 outernode0-eth0 In  IP 192.168.3.10 > 192.168.2.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125497 outernode0-eth0 Out IP 192.168.2.10 > 192.168.3.10: ICMP echo reply, id 12999, seq 1, length 64

だから私たちはあなたの目標を達成したと思います!


使ったミニネットこの構成をテストしてみてください。私のテスト環境の完全なソースコードを見つけることができます。ここ。この設定の練習ビデオがあります。ここ

修正する

ABがコメントで指摘したように、この設定には何か問題があります!デフォルトでは、カーネルの接続追跡ロジックでは、送信元/宛先アドレスと送信元/宛先ポートのみが表示されます。innernode0ポート4000からポート80への接続はouternode0次のとおりです。同じ接続は反対方向の接続です...つまり、すべてのノードのポート80で実行されているWebサーバーがあると仮定すると、次の2つのコマンドは次のようになります。

innernode0# curl --local-port 4000 192.168.3.10

そして:

outernode0# curl --local-port 4000 192.168.3.10

次の場所に単一の接続追跡エントリが作成されますmiddleman

middleman# conntrack  -L
tcp      6 118 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 src=192.168.2.10 dstroot@mininet-vm:/proc/net=192.168.3.10 sport=80 dport=4000 [ASSURED] mark=0 use=1

conntrackサブシステムにこれらの接続を区別する方法を教えてください。テーブルのチェーンに一対のルールを追加することでCTこれを行うことができます。PREROUTINGRAW

iptables -t raw -A PREROUTING -s 192.168.2.0/24 -i middleman-eth0 -j CT --zone-orig 100
iptables -t raw -A PREROUTING -s 192.168.2.0/24 -i middleman-eth1 -j CT --zone-orig 200

これらのルールが適用されると、conntrack テーブルに 2 つの個別の接続を表示できるようになります。

middleman# conntrack -L
tcp      6 113 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 zone-orig=200 src=192.168.2.10 dst=192.168.3.10 sport=80 dport=40568 [ASSURED] mark=0 use=1
tcp      6 112 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 zone-orig=100 src=192.168.2.10 dst=192.168.3.10 sport=80 dport=4000 [ASSURED] mark=0 use=1

おすすめ記事