El problema, en realidad una característica: filtro de red
De la descripción, creo que la única explicación lógica es que el puente de netfilter código está habilitado: destinado, entre otros usos, para firewalls de puentes con estado o para aprovechar iptables'coincidencias y objetivos de la ruta del puente sin tener que (o poder) duplicarlos todos en ebtables. Sin tener en cuenta las capas de red, el código de puente Ethernet, en la capa de red 2, ahora realiza llamadas ascendentes a iptables trabajando a nivel IP, es decir, capa de red 3. Solo se puede habilitar globalmente: para host y todos los contenedores, o para ninguno. Una vez que se entiende lo que está pasando y se sabe qué buscar, se pueden tomar decisiones adaptadas.
El proyecto netfilter describe los diversos ebtables
/iptables
interacción cuando filtro de red está habilitado. Especialmente de interés es el sección 7 explicar por qué a veces se necesitan algunas reglas sin efecto aparente para evitar efectos no deseados de la ruta del puente, como usar:
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPTiptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
para evitar que dos sistemas en la misma LAN sean nados... el puente (ver ejemplo a continuación).
Tiene algunas opciones para evitar su problema, pero la elección que tomó es probablemente la mejor si no desea conocer todos los detalles ni verificar si algunas reglas de iptables (a veces ocultas en otros espacios de nombres) se verían interrumpidas:
-
prevenir permanentemente el filtro de red módulo a cargar. Generalmente blacklist
no es suficiente, install
debe ser utilizado. Esta es una opción propensa a problemas para aplicaciones que dependen de filtro de red: obviamente Docker, Kubernetes, ...
echo install br_netfilter /bin/true > /etc/modprobe.d/disable-br-netfilter.conf
-
Tener el módulo cargado, pero deshabilitar sus efectos. Para iptables"efectos que es:
sysctl -w net.bridge.bridge-nf-call-iptables=0
Si se pone esto al inicio, el módulo debe cargarse primero o este interruptor aún no existirá.
Estas dos opciones anteriores seguramente interrumpirán iptables coincidir -m physdev
: El xt_physdev módulo cuando se carga, carga automáticamente el filtro de red módulo (esto sucedería incluso si una regla agregada desde un contenedor activara la carga). Ahora filtro de red no se cargará, -m physdev
probablemente nunca coinciden.
-
Evite el efecto de br_netfilter cuando sea necesario, como OP: agregue esas reglas aparentes de no operación en varias cadenas (PRERROUTING, FORWARD, POSTROUTING) como se describe en sección 7. Por ejemplo:
iptables -t nat -A POSTROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j ACCEPTiptables -A FORWARD -i br0 -o br0 -j ACCEPT
Esas reglas nunca deben coincidir porque el tráfico en la misma LAN IP no se enruta, a excepción de algunas configuraciones raras de DNAT. Pero gracias a filtro de red coinciden, porque son los primeros en ser llamados cambiar tramas ("actualizadas" a paquetes IP) que atraviesan el puente. Luego se les llama de nuevo para enrutado paquetes que atraviesan el router a una interfaz no relacionada (pero no coincidirá entonces).
No coloque una IP en el puente: coloque esa IP en un extremo de un veth
interfaz con su otro extremo en el puente: esto debería garantizar que el puente no interactúe con el enrutamiento, pero eso no es lo que hacen la mayoría de los productos comunes de contenedores/máquinas virtuales.
Incluso puede ocultar el puente en su propio espacio de nombres de red aislado (eso solo sería útil si desea aislarse de otros ebtables reglas esta vez).
Cambia todo a nftables cuáles de los objetivos establecidos evitarán estos problemas de interacción de puentes. Por ahora, el cortafuegos del puente no tiene soporte con estado disponible, todavía está WIP pero se promete que será más limpio cuando esté disponible, porque no habrá ninguna "llamada ascendente".
Debe buscar qué desencadena la carga de filtro de red (p. ej: -m physdev
) y ver si se puede evitar o no, para elegir cómo proceder.
Ejemplo con espacios de nombres de red
Vamos a reproducir algunos efectos utilizando un espacio de nombres de red. Tenga en cuenta que en ninguna parte ebtables se utilizará la regla. También tenga en cuenta que este ejemplo se basa en el legado habitual iptables
, ni iptables sobre nftables como se habilita por defecto en Debian buster.
Reproduzcamos un caso simple similar con muchos usos de contenedores: un enrutador 192.168.0.1/192.0.2.100 que hace NAT con dos hosts detrás: 192.168.0.101 y 192.168.0.102, vinculado con un puente en el enrutador. Los dos hosts pueden comunicarse directamente en la misma LAN, a través del puente.
#!/bin/shfor ns in host1 host2 router; do ip netns del $ns 2>/dev/null || : ip netns add $ns ip -n $ns link set lo updoneip netns exec router sysctl -q -w net.ipv4.conf.default.forwarding=1ip -n router link add bridge0 type bridgeip -n router link set bridge0 upip -n router address add 192.168.0.1/24 dev bridge0for i in 1 2; do ip -n host$i link add eth0 type veth peer netns router port$i ip -n host$i link set eth0 up ip -n host$i address add 192.168.0.10$i/24 dev eth0 ip -n host$i route add default via 192.168.0.1 ip -n router link set port$i up master bridge0done#to mimic a standard NAT router, iptables rule voluntarily made as it is to show the last "effect"ip -n router link add name eth0 type dummyip -n router link set eth0 upip -n router address add 192.0.2.100/24 dev eth0ip -n router route add default via 192.0.2.1ip netns exec router iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE
Carguemos el módulo kernel filtro de red (para estar seguro de que no será más tarde) y deshabilite sus efectos con la palanca (no por espacio de nombres puente-nf-llamada-iptables, disponible solo en el espacio de nombres inicial:
modprobe br_netfiltersysctl -w net.bridge.bridge-nf-call-iptables=0
Advertencia: de nuevo, esto puede interrumpir iptables reglas como -m physdev
en cualquier lugar del host o en contenedores que dependan de filtro de red cargado y habilitado.
Agreguemos algunos contadores de tráfico de ping icmp.
ip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-requestip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-reply
Hagamos ping:
# ip netns exec host1 ping -n -c2 192.168.0.102PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.047 ms64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.058 ms--- 192.168.0.102 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1017msrtt min/avg/max/mdev = 0.047/0.052/0.058/0.009 ms
Los contadores no coinciden:
# ip netns exec router iptables -v -S FORWARD-P FORWARD ACCEPT -c 0 0-A FORWARD -p icmp -m icmp --icmp-type 8 -c 0 0-A FORWARD -p icmp -m icmp --icmp-type 0 -c 0 0
Habilitemos puente-nf-llamada-iptables y ping de nuevo:
# sysctl -w net.bridge.bridge-nf-call-iptables=1net.bridge.bridge-nf-call-iptables = 1# ip netns exec host1 ping -n -c2 192.168.0.102PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.094 ms64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.163 ms--- 192.168.0.102 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1006msrtt min/avg/max/mdev = 0.094/0.128/0.163/0.036 ms
Esta vez, los paquetes conmutados obtuvieron una coincidencia en la cadena de filtro/REENVÍO de iptables:
# ip netns exec router iptables -v -S FORWARD-P FORWARD ACCEPT -c 4 336-A FORWARD -p icmp -m icmp --icmp-type 8 -c 2 168-A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
Pongamos una política de ELIMINACIÓN (que ponga a cero los contadores predeterminados) y volvamos a intentarlo:
# ip netns exec host1 ping -n -c2 192.168.0.102PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.--- 192.168.0.102 ping statistics ---2 packets transmitted, 0 received, 100% packet loss, time 1008ms# ip netns exec router iptables -v -S FORWARD-P FORWARD DROP -c 2 168-A FORWARD -p icmp -m icmp --icmp-type 8 -c 4 336-A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
El código de puente filtraba las tramas/paquetes conmutados a través de iptables. Agreguemos la regla de omisión (que pondrá a cero nuevamente los contadores predeterminados) como en OP e intentemos nuevamente:
# ip netns exec router iptables -A FORWARD -i bridge0 -o bridge0 -j ACCEPT# ip netns exec host1 ping -n -c2 192.168.0.102PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.132 ms64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.123 ms--- 192.168.0.102 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1024msrtt min/avg/max/mdev = 0.123/0.127/0.132/0.012 ms# ip netns exec router iptables -v -S FORWARD-P FORWARD DROP -c 0 0-A FORWARD -p icmp -m icmp --icmp-type 8 -c 6 504-A FORWARD -p icmp -m icmp --icmp-type 0 -c 4 336-A FORWARD -i bridge0 -o bridge0 -c 4 336 -j ACCEPT
Veamos lo que ahora se recibe realmente en el host2 durante un ping desde el host1:
# ip netns exec host2 tcpdump -l -n -s0 -i eth0 -p icmptcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes02:16:11.068795 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 1, length 6402:16:11.068817 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 1, length 6402:16:12.088002 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 2, length 6402:16:12.088063 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 2, length 64
... en lugar de la fuente 192.168.0.101. La regla de la mascarada también se llamaba desde el camino del puente. Para evitar esto, agregue (como se explica en sección 7's ejemplo) una regla de excepción antes, o indique una interfaz saliente que no sea de puente, si es posible (ahora está disponible, incluso puede usar -m physdev
si tiene que ser un puente...).
Relacionados aleatoriamente:
LKML/netfilter-dev: br_netfilter: habilitar en redes no iniciales: sería útil habilitar esta función por espacio de nombres en lugar de globalmente, lo que limitaría las interacciones entre hosts y contenedores.
netfilter-dev: netfilter: physdev: relaja la dependencia de br_netfilter: simplemente intentar eliminar un no existente physdev la regla podría crear problemas.
netfilter-dev: soporte de seguimiento de conexiones para bridge: WIP código de filtro de red de puente para preparar firewalls de puente con estado utilizando nftables, esta vez de forma más elegante. Creo que uno de los últimos pasos para deshacerse de iptables (API del lado del kernel).