2つのタップインターフェースをブリッジする

2つのタップインターフェースをブリッジする

私は完全な初心者で、これがカーネル ネットワークに関する初めての実験です。2 つのインターフェイス間にブリッジを作成しtap、トラフィックを送信しようとしています。これは、特定の目的のためというよりは、実験的なものです。

$ brctl showstp br0
br0
bridge id      8000.46846e0c0ff9
designated root    8000.46846e0c0ff9
root port         0            path cost          0
max age          20.00         bridge max age        20.00
hello time        2.00         bridge hello time      2.00
forward delay        15.00         bridge forward delay      15.00
ageing time         300.00
hello timer           1.98         tcn timer          0.00
topology change timer     0.00         gc timer         115.04
flags          


tap1 (1)
port id        8001            state            forwarding
designated root    8000.46846e0c0ff9   path cost        100
designated bridge  8000.46846e0c0ff9   message age timer      0.00
designated port    8001            forward delay timer   10.34
designated cost       0            hold timer         0.98
flags          

tap2 (2)
port id        8002            state            forwarding
designated root    8000.46846e0c0ff9   path cost        100
designated bridge  8000.46846e0c0ff9   message age timer      0.00
designated port    8002            forward delay timer    0.00
designated cost       0            hold timer         0.98
flags          

ブリッジ br0を作成し、 とtap1を追加しました。を使用してtap2ARP パケットを に注入するプログラムがあります。 Wireshark は に入るパケットを正しく表示します。 しかし、 にはパケットが表示されません。 ebtables に次のルールを追加してみました:tap1libpcaptap1tap2

sudo ebtables -I INPUT --log --log-level debug

ログにパケットが表示されません。ご意見をお聞かせいただければ幸いです。

編集: 情報を追加します。偽のパケットを挿入するのはまさにアプリケーションです。ここでの私の意図は、パケットが Linux カーネル スタックを介してどのように転送されるかを、完全にソフトウェアで、VM なしでシミュレートすることです。新しいネットワーク名前空間は作成していません。おそらくそれが問題でしょうか?

プロセスは 2 つだけです。「読み取り」プロセスは にファイル記述子を開いておりtap2、そこから常に読み取りを試行します。書き込みプロセスは にファイル記述子を開いておりtap1、ARP クエリを送信するユーザー プロンプトを待ちます。ARP クエリにはランダムなソース IP アドレスがあります。ソース MAC アドレスは の MAC アドレスとして設定されますtap1。以下は tcpdump の出力です。

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tap1, link-type EN10MB (Ethernet), capture size 262144 bytes
^[[A07:19:57.752990 ARP, Request who-has google-public-dns-a.google.com tell 0.0.248.17, length 28
    0x0000:  ffff ffff ffff ba9c 0589 16ad 0806 0001
    0x0010:  0800 0604 0001 ba9c 0589 16ad 0000 f811
    0x0020:  0000 0000 0000 0808 0808

tap1IP アドレスを持たないように設定しましたtap2。これが問題でしょうか?

brctl addbr br0
ip tuntap add name tap1 mode tap
ip tuntap add name tap2 mode tap
brctl addif br0 tap1
brctl addif br0 tap2
ifconfig tap1 0.0.0.0 up
ifconfig tap2 0.0.0.0 up
ifconfig br0 10.0.1.1 netmask 255.255.255.0 broadcast 10.0.1.255
ip link set br0 up
ip link set tap1 up
ip link set tap2 up

回答に基づいて、さまざまなアプリケーションを に接続して確認しました。またはtap2を使用しているアプリケーションがない場合、両方のインターフェイスに LOWER_UP フラグが設定されていないことに気付きました。tap1tap2

4: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 46:84:6e:0c:0f:f9 brd ff:ff:ff:ff:ff:ff
25: tap1: <NO-CARRIER,BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast master br0 state DOWN mode DEFAULT group default qlen 500
    link/ether ba:9c:05:89:16:ad brd ff:ff:ff:ff:ff:ff
26: tap2: <NO-CARRIER,BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast master br0 state DOWN mode DEFAULT group default qlen 500

アプリケーションを起動すると、LOWER_UP フラグが設定されます。

4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 46:84:6e:0c:0f:f9 brd ff:ff:ff:ff:ff:ff
25: tap1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UP mode DEFAULT group default qlen 500
    link/ether ba:9c:05:89:16:ad brd ff:ff:ff:ff:ff:ff
26: tap2: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UP mode DEFAULT group default qlen 500
    link/ether 46:84:6e:0c:0f:f9 brd ff:ff:ff:ff:ff:ff

長くなってしまい申し訳ありませんが、問題を理解するのに十分な情報が得られることを願っています。

答え1

念のため、あなたは完全な初心者だと言ったので、tun(レイヤー3)またはtap(レイヤー2)インターフェースはアプリケーションのネットワークインターフェースエンドポイントであり、アプリケーションはこのネットワークインターフェースからパケットを読み書きできます。あなたが作成するもの、ip tuntap add ...または時代遅れのものtunctlは次のとおりです。永続的な名前このようなエンドポイントの場合、通常はアプリケーションを実行しますが、アプリケーションを実行しない限り何も実行されません。

アプリケーションは設計上、ネットワーク インターフェイスと対話するため、私が説明したこの通常の対話を「挿入」することを意味していない限り、サード パーティ アプリケーションでパケットを「挿入」する必要はありません。

また、ネットワークをいじってみたい場合は、ネットワーク名前空間そしてベスペア基本的に、ネットワーク上の実際のコンピュータ間の通信を模倣できる仮想コンピュータをコンピュータ上に多数設定できます。

したがって、そうしたい場合、そしてパケットの作成と受信を行う独自のアプリケーションを操作したくない場合は、tun/tap インターフェイスは必要ありません。

とはいえ、パケットを「注入」するために何を使用するかが書かれていないので、少し変更を加えて設定をテストしました。2 つsocatの を使ってエンドポイントと をタップしtap0atap1aそれらをブリッジして、2socatつの異なる名前空間で別の 2 つの を使って正しいパケットを作成しました。ローカル パケットは常にループバック 経由で配信されるため、それらは異なる名前空間にある必要がありますlo

そして予想通り、ブリッジ タップ デバイスは正常に動作します。

したがって、問題は、挿入しているパケットにあると考えられます。イーサネット アドレスが間違っているか、ブロードキャストがありません。ARPtcpdump -xx ...パケットを挿入したときの出力を質問に含めて編集してください。

あるいは、ネットワーク名前空間を作成し、代わりに 2 つの veth ペアの 2 つのエンドポイントをブリッジしたいとお考えですか? その方がずっと簡単です。

編集

ARP パケットは正常です。 に接続されているアプリケーションがないようですtap2。 に接続されている場合は、のフラグip linkは表示されないはずです。推測: ブリッジはデバイスが部分的にしか起動していないことを検出し、このポートにパケットを送信しません。LOWER_UPtap2

それをtap次のように置き換えてみてくださいもっているそれに接続されたアプリケーション、例えば

sudo socat TUN:10.0.2.2/24,tun-name=tapx,tun-type=tap,iff-up - | hexdump -C

10.0.2.2/24アドレスは何もしませんが、socatアドレスを指定しないと機能しません)、別のターミナルで

sudo ip link set tapx master br0

( を置き換えますbrctl addif)、パケットを数回挿入して、最初のウィンドウで 16 進ダンプが表示されるかどうかを確認します。 で も確認しLOWER_UPますip link show dev tapx

ちなみに、ifconfigと はbrctl古くなっています。代わりにipと を使用してくださいbridge

ブリッジのポートにIPアドレスを割り当てなくても問題はありません。ブリッジポートはIPアドレスを持っていない(橋によって奴隷化される前に割り当てられたものがあった場合は無視されます)。例:ここ

答え2

私はこれにかなり苦労しましたが、解決策にたどり着いたと思います。少なくとも、何が起こっているのかをよりよく理解できました。

受信側(「RX」)のタップインターフェースにパケットを配信する唯一の方法は、そのパケットをソケット記述子に書き込むことであるということを覚えておくことが重要です。蛇口を開けるプロセスによって作成された(およびopen("/dev/net/tun",...)経由ioctl)。一度にこのファイル記述子を持つことができるのは 1 つのプロセスだけです。タップ デバイスが開かれているときに、別のプロセスが同じ名前の別のタップ デバイスを再度開こうとすると、そのシステム コールは失敗します。

Wiresharkのような他のプロセスでは、生のソケットを開いてバインドしますそれtap0、トラフィックを書き込むことしかできないシステムの(カーネルの観点から)つまり、Wireshark はTXのカウンターを増加させtap0RXパケットのみがブリッジ インターフェイスに転送されることになります。

それぞれのカウンターは次のように確認できます:

#!/bin/bash
for if in tap{0,1}; do
    stats=/sys/class/net/$if/statistics/
    rx=$(cat $stats/rx_packets)
    tx=$(cat $stats/tx_packets)
    echo "$if: rx=$rx, tx=$tx"
done

出力は次のようになります:

tap0: rx=0, tx=6
tap1: rx=0, tx=5

したがって、あなたの特定のケースでは、問題はここにあると思われます:

ARPlibpcap を使用して にパケットを注入するプログラムがありますtap1。 Wireshark は に入るパケットを正しく表示しますtap1。 しかし、 にはパケットが表示されませんtap2

fd = open("/dev/net/tun", ...)どのようにして ARP パケットを tap1 に注入していますか? Wireshark は および を呼び出していないと想定しているioctl(fd, TUNSETIFF, ...)ため、送信されるパケットは TX となり、ブリッジされません。

それらのパケットを に転送してに表示するには、 のファイル記述子tap0にパケットを書き込むために開くプログラムが必要になります。tap0br0tap1

関連情報