私は完全な初心者で、これがカーネル ネットワークに関する初めての実験です。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
を追加しました。を使用してtap2
ARP パケットを に注入するプログラムがあります。 Wireshark は に入るパケットを正しく表示します。 しかし、 にはパケットが表示されません。 ebtables に次のルールを追加してみました:tap1
libpcap
tap1
tap2
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
tap1
IP アドレスを持たないように設定しました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 フラグが設定されていないことに気付きました。tap1
tap2
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
の を使ってエンドポイントと をタップしtap0a
、tap1a
それらをブリッジして、2socat
つの異なる名前空間で別の 2 つの を使って正しいパケットを作成しました。ローカル パケットは常にループバック 経由で配信されるため、それらは異なる名前空間にある必要がありますlo
。
そして予想通り、ブリッジ タップ デバイスは正常に動作します。
したがって、問題は、挿入しているパケットにあると考えられます。イーサネット アドレスが間違っているか、ブロードキャストがありません。ARPtcpdump -xx ...
パケットを挿入したときの出力を質問に含めて編集してください。
あるいは、ネットワーク名前空間を作成し、代わりに 2 つの veth ペアの 2 つのエンドポイントをブリッジしたいとお考えですか? その方がずっと簡単です。
編集
ARP パケットは正常です。 に接続されているアプリケーションがないようですtap2
。 に接続されている場合は、のフラグip link
は表示されないはずです。推測: ブリッジはデバイスが部分的にしか起動していないことを検出し、このポートにパケットを送信しません。LOWER_UP
tap2
それを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
のカウンターを増加させtap0
、RX
パケットのみがブリッジ インターフェイスに転送されることになります。
それぞれのカウンターは次のように確認できます:
#!/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
したがって、あなたの特定のケースでは、問題はここにあると思われます:
ARP
libpcap を使用して にパケットを注入するプログラムがありますtap1
。 Wireshark は に入るパケットを正しく表示しますtap1
。 しかし、 にはパケットが表示されませんtap2
。
fd = open("/dev/net/tun", ...)
どのようにして ARP パケットを tap1 に注入していますか? Wireshark は および を呼び出していないと想定しているioctl(fd, TUNSETIFF, ...)
ため、送信されるパケットは TX となり、ブリッジされません。
それらのパケットを に転送してに表示するには、 のファイル記述子tap0
にパケットを書き込むために開くプログラムが必要になります。tap0
br0
tap1