Puenteando dos interfaces de tap

Puenteando dos interfaces de tap

Soy un novato total, este es mi primer experimento con redes de kernel. Estoy intentando crear un puente entre dos tapinterfaces e intentar enviar tráfico a través de él. Es más un experimento que un propósito en particular.

$ 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          

Tengo el puente br0creado, con ambos tap1y tap2agregado. Tengo un programa que inyecta paquetes ARP en el tap1uso libpcap. Wireshark muestra correctamente los paquetes que ingresan tap1. Sin embargo, no aparece ningún paquete en tap2. Intenté agregar la siguiente regla en ebtables:

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

No aparece ningún paquete en los registros. Agradeceré cualquier aporte.

EDITAR: Agregar más información. Inyectar paquetes falsos es de hecho la aplicación. Mi intención aquí es simular, completamente en software y sin máquinas virtuales, cómo se reenvían los paquetes a través de la pila del kernel de Linux. No estoy creando ningún espacio de nombres de red nuevo. ¿Quizás ese sea el problema?

Solo tengo dos procesos. El proceso de "lectura" tiene un descriptor de archivo abierto tap2e intenta leerlo constantemente. El proceso de escritura tiene un descriptor de archivo abierto tap1y espera que el usuario le solicite enviar la consulta ARP. La consulta ARP tiene una dirección IP de origen aleatoria. La dirección MAC de origen se establece como la dirección MAC de tap1. Aquí está el resultado de 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

Lo he configurado tap1y tap2para no tener direcciones IP. ¿Podría ser el problema?

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

Según la respuesta, verifiqué cómo adjuntar varias aplicaciones a tap2. Noto esto: cuando ninguna aplicación usa tap1o tap2, ambas interfaces no tienen el indicador LOWER_UP configurado.

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

Cuando inicio las aplicaciones, el indicador LOWER_UP se establece:

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

Lamento que esto esté resultando largo, solo espero que haya suficiente información para entender el problema.

Respuesta1

Por si acaso, porque dijiste que eres un novato total: una interfaz tun (capa 3) o tap (capa 2) es el punto final de la interfaz de red de una aplicación, y la aplicación puede leer y escribir paquetes desde esta interfaz de red. Lo que creas ip tuntap add ...o lo obsoleto tunctlsonnombres persistentespara dichos puntos finales, normalmente seguirá ejecutando la aplicación y no hará nada a menos que la ejecute.

Como la aplicación interactúa con la interfaz de red como una cuestión de diseño, no hay necesidad de "inyectar" paquetes con una aplicación de terceros, a menos que se refiera a "inyectar" esta interacción normal que describí.

Además, si quieres jugar con las redes, te recomiendo usarespacios de nombres de redyquintos pares. Básicamente, puedes configurar muchas computadoras virtuales en tu computadora que pueden imitar la comunicación entre computadoras reales en una red.

Entonces, si desea hacer eso y no quiere jugar con su propia aplicación creando y recibiendo paquetes, no necesita una interfaz tun/tap.

Dicho esto, acabo de probar tu configuración, con una ligera variación porque no dijiste qué usas para "inyectar" paquetes: usé dos socats para crear el punto final de tap tap0ay tap1aluego los uní y usé otros dos socats en dos espacios de nombres diferentes para crear los paquetes correctos para mí. Deben estar en un espacio de nombres diferente, ya que los paquetes locales siempre se entregarán mediante loopback lo.

Y como era de esperar, los dispositivos de derivación en puente funcionan bien.

Entonces supongo que el problema está en el paquete que está inyectando: dirección Ethernet incorrecta o no hay transmisión. Edite su pregunta con el tcpdump -xx ...resultado cuando inyecte el paquete ARP.

¿O posiblemente le gustaría crear espacios de nombres de red y unir dos puntos finales de dos pares veth? Eso es mucho más sencillo.

Editar

El paquete ARP se ve bien. Parece que no hay ninguna aplicación conectada tap2. Si lo hace ip link, no debería ver una LOWER_UPbandera para tap2. Adivina: El puente detecta que el dispositivo está parcialmente activo y no envía paquetes a este puerto.

Intenta reemplazarlo con uno tapquetieneuna aplicación conectada a él, algo así como

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

(la 10.0.2.2/24dirección no hace nada, pero socatno funcionará si no especifica una dirección), y en otra terminal

sudo ip link set tapx master br0

(que reemplaza brctl addif), luego inyecte su paquete varias veces y vea si obtiene un volcado hexadecimal en la primera ventana. Consulte también LOWER_UPcon ip link show dev tapx.

Por cierto, ifconfigy brctlestán desactualizados. Utilice ipy bridgeen su lugar.

No asignar direcciones IP a los puertos del puente no importa, porque los puertos del puenteno tengo direcciones IP(Si se les asignó algo antes de ser esclavizados por un puente, se ignoran). Ver por ejemploaquí.

Respuesta2

Luché mucho con esto y creo que llegué a una solución. O, al menos, una mejor comprensión de lo que está pasando.

Es importante tener en cuenta que la única forma de entregar un paquete a una interfaz tap en el lado de recepción ("RX") es escribiendo ese paquete en el descriptor del socket.creado por el proceso que abrió el grifo(vía open("/dev/net/tun",...)y ioctl). Sólo un proceso puede tener este descriptor de archivo a la vez. Si un dispositivo de grifo está abierto y otro proceso intenta volver a abrir otro dispositivo de grifo con el mismo nombre, esa llamada al sistema fallará.

Entonces, cuando tienes cualquier otro proceso, como Wireshark, abrir un socket sin formato y luego vincularloesoa tap0, sólo es capaz de escribir tráficoafueradel sistema (desde la perspectiva del núcleo). Es decir, Wireshark debería superar el TXcontador de tap0y solo RXlos paquetes se reenviarán a la interfaz puenteada.

Puedes consultar los contadores de cada me gusta:

#!/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

que genera algo como:

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

Entonces, en tu caso específico, sospecho que el problema está aquí:

Tengo un programa que inyecta ARPpaquetes tap1usando libpcap. Wireshark muestra correctamente los paquetes que ingresan tap1. Sin embargo, no aparece ningún paquete en tap2.

¿Cómo se inyectan paquetes ARP en tap1? Supongo que Wireshark no está llamando fd = open("/dev/net/tun", ...)y ioctl(fd, TUNSETIFF, ...), por lo que los paquetes enviados serán TX y, por lo tanto, no estarán puenteados.

Necesitará el programa que se abre tap0para escribir paquetes en tap0el descriptor de archivo de para que esos paquetes se reenvíen br0y aparezcan en tap1.

información relacionada