Un'interfaccia, in un dato momento, appartiene a uno spazio dei nomi di rete e solo a uno. Lo spazio dei nomi di rete init (iniziale), ad eccezione dell'ereditarietà delle interfacce fisiche degli spazi dei nomi di rete distrutti, non ha capacità speciali rispetto ad altri spazi dei nomi di rete:non può vedere direttamente le loro interfacce. Finché sei ancora nei namespace pid e mount di init, puoi ancora trovare i namespace di rete utilizzando diverse informazioni disponibili da /proc
e infine visualizzare le loro interfacce inserendo quegli spazi dei nomi di rete.
Fornirò esempi in shell.
-
enumerare gli spazi dei nomi di rete
Per questo devi sapere come esistono quegli spazi dei nomi:fintanto che una risorsa li mantiene attivi. Una risorsa qui può essere un processo (in realtà un thread di processo), un punto di montaggio o un descrittore di file aperto (fd). Queste risorse sono tutte referenziate in
/proc/
e puntano a uno pseudo-file astratto nelnsfs
pseudo-filesystem che enumera tutti gli spazi dei nomi. L'unica informazione significativa di questo file è il suo inode, che rappresenta lo spazio dei nomi di rete, ma l'inode non può essere manipolato da solo, deve essere il file. Ecco perché in seguito non possiamo mantenere solo il valore dell'inode (dato dastat -c %i /proc/some/file
):manterremo l'inode per poter rimuovere i duplicati e un nome file per avere ancora un riferimento utilizzabile pernsenter
più tardi.-
processo (in realtà thread)
Il caso più comune:per i soliti contenitori. Lo spazio dei nomi di rete di ogni thread può essere conosciuto tramite il riferimento
/proc/pid/ns/net
:solostat
loro ed enumerare tutti gli spazi dei nomi univoci. Il2>/dev/null
è nascondere quandostat
non riesce più a trovare processi effimeri.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
Questo può essere fatto più velocemente con il
lsns
specializzato comando che si occupa degli spazi dei nomi, ma sembra gestire solo i processi (non i punti di montaggio né l'apertura di fd come visto in seguito):lsns -n -u -t net -o NS,PATH
(che dovrebbe essere riformattato per dopo come
lsns -n -u -t net -o NS,PATH | while read inode path; do printf '%20u %s\n' $inode "$path"; done
) -
punto di montaggio
Quelli sono principalmente usati dal
ip netns add
comando che crea spazi dei nomi di rete permanenti montandoli, evitando così che scompaiano quando non ci sono processi o risorse fd che li mantengono attivi, permettendo quindi anche ad esempio di eseguire un router, un firewall o un bridge in uno spazio dei nomi di rete senza alcun processo collegato.Gli spazi dei nomi montati (la gestione degli spazi dei nomi mount e forse pid è probabilmente più complessa, ma in ogni caso siamo interessati solo agli spazi dei nomi di rete) appaiono come qualsiasi altro punto di montaggio in
/proc/mounts
, con il tipo di filesystemnsfs
. Non esiste un modo semplice nella shell per distinguere uno spazio dei nomi di rete da un altro tipo di spazio dei nomi, ma poiché due pseudo-file dallo stesso filesystem (quinsfs
) non condividerà lo stesso inode, basta eleggerli tutti e ignorare gli errori successivi nel passaggio dell'interfaccia quando si tenta di utilizzare un riferimento a uno spazio dei nomi non di rete come spazio dei nomi di rete. Spiacenti, di seguito non gestirò correttamente i punti di montaggio contenenti caratteri speciali, inclusi gli spazi, perché sono già sottoposti a escape in/proc/mounts
(sarebbe più facile in qualsiasi altra lingua), quindi non mi preoccuperò nemmeno di usare righe con terminazione nulla.awk '$3 == "nsfs" { print $2 }' /proc/mounts | while read -r mount; do stat -c '%20i %n' "$mount" done
-
apri il descrittore di file
Questi sono probabilmente anche più rari dei punti di montaggio, tranne temporaneamente alla creazione dello spazio dei nomi, ma potrebbero essere conservati e utilizzati da alcune applicazioni specializzate che gestiscono più spazi dei nomi, inclusa forse una tecnologia di containerizzazione.
Non potrei escogitare un metodo migliore che cercare tutti gli fd disponibili in ogni
/proc/pid/fd/
, utilizzando stat per verificare che punti a unnsfs
namespace e ancora una volta non mi interessa se è davvero uno spazio dei nomi di rete. Sono sicuro che c'è un ciclo più ottimizzato, ma questo almeno non vagherà ovunque né assumerà alcun limite massimo di processo.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
Ora rimuovi tutti i riferimenti allo spazio dei nomi di rete duplicati dai risultati precedenti. Ad esempio, utilizzando questo filtro sull'output combinato dei 3 risultati precedenti (specialmente dalla parte del descrittore di file aperto):
sort -k 1n | uniq -w 20
-
-
in ogni spazio dei nomi enumera le interfacce
Ora abbiamo i riferimenti a tutti gli spazi dei nomi di rete esistenti (e anche alcuni spazi dei nomi non di rete che semplicemente ignoreremo), inserisci semplicemente ciascuno di essi utilizzando il riferimento e visualizza le interfacce.
Prendi l'output dei comandi precedenti come input per questo ciclo per enumerare le interfacce (e secondo la domanda dell'OP, scegli di visualizzare i loro indirizzi), ignorando gli errori causati da spazi dei nomi non di rete come spiegato in precedenza:
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
L'inode della rete init può essere stampato con pid 1 come riferimento:
echo -n 'INIT NETWORK: ' ; stat -L -c %i /proc/1/ns/net
Output di esempio (reale ma redatto) con un contenitore LXC in esecuzione, uno spazio dei nomi di rete "montato" vuoto creato con ip netns add ...
avere un'interfaccia bridge non connessa, uno spazio dei nomi di rete con un altro dummy0
interfaccia, mantenuta in vita da un processo not in questo spazio dei nomi di rete ma mantenendo un fd aperto su di esso, creato 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 &
e un Firefox in esecuzione che isola ciascuno dei suoi thread "Contenuto Web" in uno spazio dei nomi di rete non connesso (tutti quelli in basso lo
interfacce):
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