下の図のように、Linuxカーネルを介してトラフィックをルーティングすることは可能ですか?同じIP範囲を使用して、「内部」ネットワーク外のデバイスの正確なコピーをエミュレートしながら、相手が同じIPを持っていることを知らずに、内部および外部デバイスが互いに通信できるようにしたいと思います。
例:デバイス次に、レスポンスはブローカーに再送信され、IP 192.168.2.5のデバイスXに送信されます。
私はこれがネットワークネームスペースを通して可能で効率的な偽装を可能にすることを知っています。しかし、私は名前空間の使用を避け、代わりにさまざまなトラフィック方向に他のルーティングテーブルと同じものを使用したいと思います。可能ですか?
正しく理解した場合、IP 範囲が重複して NAT を使用できません。そうですか?
答え1
トポロジー
まず、ネットワークインタフェースを設定しますmiddleman
。私はあなたがシステムコンソールにログインしたか、inner
ネットワークに関連していないインターフェースを介してアクセスしたと仮定しますouter
。この回答の目的のために、私たちはインターフェースがmiddleman-eth0
「middleman
内部」ネットワークに接続され、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
:
- ルーティングエントリのため、パケットは
192.168.3.0/24 via 192.168.2.1
ブローカーにルーティングされます。 - パケット到着
middleman-eth0
- パケットは
MANGLE
テーブルチェーンに到着PREROUTING
し、fwmarkを次に設定します。100
- パケットは
NAT
テーブルチェーンに到達し、宛先にPREROUTING
マッピングされます。192.168.2.10
fwmark 100 lookup 200
パケットはルールに準拠したルーティングサブシステムに入ります。- ルーティングテーブル200でヒットし、
192.168.2.0/24 dev middleman-eth1
カーネルがそれをデバイスに送信する。middleman-eth1
- パケットが
NAT
テーブルチェーンに到着しPOSTROUTING
、そのソースがにマッピングされます192.168.3.10
。 - パケットはアドレスが「外部」ノードに到着します
192.168.2.10
。 - ...深呼吸をしてください...
- 外部ノードが応答を送信します。
192.168.3.10
- 返信到着
middleman-eth1
- 応答は
MANGLE
テーブルチェーンに到着PREROUTING
し、fwmarkを次に設定します。200
- 応答は
NAT
テーブルチェーンに到着しPREROUTING
、ターゲットにマッピングされます。192.168.2.10
fwmark 200 lookup 100
応答は、ルールに準拠したルーティングサブシステムに移動します。- ルーティングテーブル100は
192.168.2.0/24 dev middleman-eth0
ルールと一致するので、カーネルはそれをデバイスに送信する。middleman-eth0
- 応答は
NAT
テーブルチェーンに到着しPOSTROUTING
、そのソースはテーブルチェーンにマップされます。192.168.3.10
- 応答は、
192.168.2.10
元の要求に対する応答を確認する「内部」ノードに到達します。
確認する
「内部」ノード0(192.168.2.10
)でアドレスを使用して「外部」ノード0にpingしようとすると、内部ノード0で実行すると次のようになります192.168.3.10
。tcpdump -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
これを行うことができます。PREROUTING
RAW
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