Una interfaz, en un momento dado, pertenece a un espacio de nombres de red y solo a uno. El espacio de nombres de red init (inicial), a excepción de las interfaces físicas heredadas de espacios de nombres de red destruidos, no tiene ninguna habilidad especial sobre otros espacios de nombres de red:no puede ver directamente sus interfaces. Siempre que esté en los espacios de nombres pid y mount de init, aún puede encontrar los espacios de nombres de red utilizando diferentes informaciones disponibles en /proc
y finalmente mostrar sus interfaces ingresando esos espacios de nombres de red.
Proporcionaré ejemplos en shell.
-
enumerar los espacios de nombres de red
Para esto, debe saber cómo existen esos espacios de nombres:siempre que un recurso los mantenga. Un recurso aquí puede ser un proceso (en realidad, un hilo de proceso), un punto de montaje o un descriptor de archivo abierto (fd). Todos esos recursos están referenciados en
/proc/
y apunte a un pseudo-archivo abstracto en elnsfs
pseudo-sistema de archivos que enumera todos los espacios de nombres. La única información significativa de este archivo es su inodo, que representa el espacio de nombres de la red, pero el inodo no se puede manipular solo, tiene que ser el archivo. Es por eso que más adelante no podemos mantener solo el valor del inodo (dado porstat -c %i /proc/some/file
):mantendremos el inodo para poder eliminar los duplicados y un nombre de archivo para tener una referencia utilizable paransenter
más tarde.-
proceso (en realidad hilo)
El caso más común:para contenedores habituales. El espacio de nombres de red de cada subproceso se puede conocer a través de la referencia
/proc/pid/ns/net
:solostat
y enumerar todos los espacios de nombres únicos. El2>/dev/null
es ocultar cuandostat
ya no puedo encontrar procesos efímeros.find /proc/ -mindepth 1 -maxdepth 1 -name '[1-9]*' | while read -r procpid; do stat -L -c '%20i %n' $procpid/ns/net done 2>/dev/null
Esto se puede hacer más rápido con el
lsns
especializado comando que trata con espacios de nombres, pero parece manejar solo procesos (no puntos de montaje ni fd abierto como se verá más adelante):lsns -n -u -t net -o NS,PATH
(que tendría que reformatearse para más tarde como
lsns -n -u -t net -o NS,PATH | while read inode path; do printf '%20u %s\n' $inode "$path"; done
) -
punto de montaje
Esos son utilizados principalmente por el
ip netns add
comando que crea espacios de nombres de red permanentes montándolos, evitando así que desaparezcan cuando no hay ningún proceso ni recurso fd que los mantenga, y luego también permite, por ejemplo, ejecutar un enrutador, un cortafuegos o un puente en un espacio de nombres de red sin ningún proceso vinculado.Los espacios de nombres montados (el manejo de los espacios de nombres de montaje y quizás pid es probablemente más complejo, pero de todos modos solo nos interesan los espacios de nombres de red) aparecen como cualquier otro punto de montaje en
/proc/mounts
, con el tipo de sistema de archivosnsfs
. No hay una manera fácil en shell de distinguir un espacio de nombres de red de otro tipo de espacio de nombres, pero como dos pseudoarchivos del mismo sistema de archivos (aquínsfs
) no compartirá el mismo inodo, solo selecciónelos todos e ignore los errores más adelante en el paso de la interfaz cuando intente usar una referencia de espacio de nombres que no sea de red como espacio de nombres de red. Lo siento, a continuación no manejaré correctamente los puntos de montaje con caracteres especiales, incluidos los espacios, porque ya están escapados en/proc/mounts
(sería más fácil en cualquier otro idioma), así que tampoco me molestaré en usar líneas terminadas en nulo.awk '$3 == "nsfs" { print $2 }' /proc/mounts | while read -r mount; do stat -c '%20i %n' "$mount" done
-
abrir descriptor de archivo
Estos son probablemente incluso más raros que los puntos de montaje, excepto temporalmente en la creación del espacio de nombres, pero pueden ser retenidos y utilizados por alguna aplicación especializada que maneje múltiples espacios de nombres, incluida posiblemente alguna tecnología de contenedorización.
No pude idear un método mejor que buscar todos los fd disponibles en cada
/proc/pid/fd/
, usando stat para verificar que apunta a unnsfs
espacio de nombres y, de nuevo, no me importa ahora si es realmente un espacio de nombres de red. Estoy seguro de que hay un ciclo más optimizado, pero este al menos no deambulará por todas partes ni asumirá ningún límite máximo de proceso.find /proc/ -mindepth 1 -maxdepth 1 -name '[1-9]*' | while read -r procpid; do find $procpid/fd -mindepth 1 | while read -r procfd; do if [ "$(stat -f -c %T $procfd)" = nsfs ]; then stat -L -c '%20i %n' $procfd fi done done 2>/dev/null
Ahora elimine todas las referencias de espacios de nombres de red duplicados de los resultados anteriores. Por ejemplo, usando este filtro en la salida combinada de los 3 resultados anteriores (especialmente de la parte del descriptor de archivo abierto):
sort -k 1n | uniq -w 20
-
-
en cada espacio de nombres enumere las interfaces
Ahora que tenemos las referencias a todos los espacios de nombres de red existentes (y también algunos espacios de nombres que no son de red que simplemente ignoraremos), simplemente ingrese cada uno de ellos usando la referencia y muestre las interfaces.
Tome la salida de los comandos anteriores como entrada a este ciclo para enumerar las interfaces (y según la pregunta de OP, elija mostrar sus direcciones), mientras ignora los errores causados por espacios de nombres que no son de red como se explicó anteriormente:
while read -r inode reference; do if nsenter --net="$reference" ip -br address show 2>/dev/null; then printf 'end of network %d\n\n' $inode fi done
El inodo de la red de inicio se puede imprimir con pid 1 como referencia:
echo -n 'INIT NETWORK: ' ; stat -L -c %i /proc/1/ns/net
Salida de ejemplo (real pero redactada) con un contenedor LXC en ejecución, un espacio de nombres de red "montado" vacío creado con ip netns add ...
tener una interfaz de puente no conectada, un espacio de nombres de red con otro dummy0
interfaz, mantenida viva por un proceso no en este espacio de nombres de red pero manteniendo un fd abierto en él, creado con:
unshare --net sh -c 'ip link add dummy0 type dummy; ip address add dev dummy0 10.11.12.13/24; sleep 3' & sleep 1; sleep 999 < /proc/$!/ns/net &
y un Firefox en ejecución que aísla cada uno de sus subprocesos de "Contenido web" en un espacio de nombres de red no conectado (todos los que están abajo lo
interfaces):
lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.0.2.2/24 2001:db8:0:1:bc5c:95c7:4ea6:f94f/64 fe80::b4f0:7aff:fe76:76a8/64 wlan0 DOWN dummy0 UNKNOWN 198.51.100.2/24 fe80::108a:83ff:fe05:e0da/64 lxcbr0 UP 10.0.3.1/24 2001:db8:0:4::1/64 fe80::216:3eff:fe00:0/64 virbr0 DOWN 192.168.122.1/24 virbr0-nic DOWN [email protected] UP fe80::fc8e:ff:fe85:476f/64 end of network 4026531992 lo DOWN end of network 4026532418 lo DOWN end of network 4026532518 lo DOWN end of network 4026532618 lo DOWN end of network 4026532718 lo UNKNOWN 127.0.0.1/8 ::1/128 [email protected] UP 10.0.3.66/24 fe80::216:3eff:fe6a:c1e9/64 end of network 4026532822 lo DOWN bridge0 UNKNOWN fe80::b884:44ff:feaf:dca3/64 end of network 4026532923 lo DOWN dummy0 DOWN 10.11.12.13/24 end of network 4026533021 INIT NETWORK: 4026531992