桥接两个 Tap 接口

桥接两个 Tap 接口

我是个彻头彻尾的菜鸟,这是我第一次尝试内核网络。我试图在两个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,并添加了 和tap1tap2我有一个程序使用 注入 ARP 数据包tap1。Wiresharklibpcap正确显示进入 的数据包tap1。但是, 处没有显示任何数据包tap2。我尝试在 ebtables 中添加以下规则:

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

日志中没有显示任何数据包。如果您有任何意见,我将不胜感激。

编辑:添加更多信息。注入假数据包确实是应用程序。我的目的是完全在软件中模拟数据包如何通过 Linux 内核堆栈转发,而无需虚拟机。我没有创建任何新的网络命名空间。也许这就是问题所在?

我只有两个进程。“读取”进程有一个打开的文件描述符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,但tap2没有 IP 地址。这可能是问题所在吗?

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。我注意到:当没有应用程序使用tap1或 时tap2,两个接口都没有设置 LOWER_UP 标志。

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持久名称对于这样的端点,您通常仍会运行该应用程序,并且除非您运行该应用程序,否则它不会执行任何操作。

由于应用程序在设计上与网络接口进行交互,因此无需使用第三方应用程序“注入”数据包,除非您所说的“注入”就是我所描述的这种正常交互。

另外,如果你想尝试一下网络,我建议使用网络命名空间veth 对. 基本上,您可以在您的计算机上设置许多虚拟计算机,它们可以模拟网络上真实计算机之间的通信。

因此,如果您想这样做,并且不想使用自己的应用程序创建和接收数据包,则您不需要 tun/tap 接口。

话虽如此,我刚刚测试了您的设置,但略有不同,因为您没有说明使用什么来“注入”数据包:我使用两个socats 创建到 tap 端点tap0atap1a,然后桥接它们,并socat在两个不同的命名空间中使用另外两个 s 为我创建正确的数据包。它们需要位于不同的命名空间中,因为本地数据包将始终通过 loopback 传递lo

正如预期的那样,桥接分接设备工作正常。

因此,我猜想问题出在你注入的数据包中:错误的以太网地址,或者没有广播。请tcpdump -xx ...在注入 ARP 数据包时使用输出编辑你的问题。

或者你可能想创建网络命名空间并桥接两个 veth 对的两个端点?这简单得多。

编辑

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),然后多次注入数据包,看看是否在第一个窗口中获得十六进制转储。同时LOWER_UP检查ip link show dev tapx

顺便说一句,ifconfigbrctl已经过时了。请使用ipbridge代替。

不给网桥的端口分配 IP 地址没有关系,因为网桥端口没有 IP 地址(如果他们在被桥梁奴役之前就被分配了一些,那么他们将被忽略)。参见例如这里

答案2

我为此苦苦挣扎了很久,我想我已经找到了解决方案。或者,至少,对正在发生的事情有了更好的理解。

重要的是要记住,将数据包传送到接收端(“RX”)的分接接口的唯一方法是将该数据包写入套接字描述符打开水龙头的过程产生的(通过open("/dev/net/tun",...)ioctl)。一次只能有一个进程拥有此文件描述符。如果一个 tap 设备已打开,而另一个进程尝试重新打开另一个同名的 tap 设备,则该系统调用将失败。

因此,当您有任何其他进程(例如 wireshark)时,打开原始套接字然后绑定tap0,它只能写入流量出去系统(从内核角度来看)。也就是说,wireshark 应该将计数器设置TXtap0,并且只有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

您如何将 ARP 数据包注入 tap1?我假设 wireshark 没有调用fd = open("/dev/net/tun", ...)ioctl(fd, TUNSETIFF, ...),因此发送的数据包将是 TX,因此不会被桥接。

您将会需要打开一个程序tap0来将数据包写入到tap0的文件描述符中,以便这些数据包能够被转发br0并显示在 上tap1

相关内容