Une interface, à un instant donné, appartient à un espace de noms réseau et à un seul. L'espace de noms réseau init (initial), sauf pour hériter des interfaces physiques des espaces de noms réseau détruits, n'a aucune capacité spéciale sur les autres espaces de noms réseau :il ne peut pas voir directement leurs interfaces. Tant que vous êtes toujours dans les espaces de noms pid et mount d'init, vous pouvez toujours trouver les espaces de noms réseau en utilisant différentes informations disponibles à partir de /proc
et enfin afficher leurs interfaces en saisissant ces espaces de noms réseau.
Je vais fournir des exemples en shell.
-
énumérer les espaces de noms réseau
Pour cela, vous devez savoir comment ces espaces de noms existent :tant qu'une ressource les maintient. Une ressource ici peut être un processus (en fait un thread de processus), un point de montage ou un descripteur de fichier ouvert (fd). Ces ressources sont toutes référencées dans
/proc/
et pointe vers un pseudo-fichier abstrait dans lensfs
pseudo-système de fichiers énumérant tous les espaces de noms. La seule information significative de ce fichier est son inode, représentant l'espace de noms du réseau, mais l'inode ne peut pas être manipulé seul, il doit s'agir du fichier. C'est pourquoi plus tard nous ne pouvons pas garder uniquement la valeur de l'inode (donnée parstat -c %i /proc/some/file
) :nous conserverons l'inode pour pouvoir supprimer les doublons et un nom de fichier pour avoir encore une référence utilisable pournsenter
plus tard.-
processus (en fait thread)
Le cas le plus courant :pour les contenants usuels. L'espace de noms réseau de chaque thread peut être connu via la référence
/proc/pid/ns/net
:justestat
eux et énumérer tous les espaces de noms uniques. Le2>/dev/null
est de se cacher quandstat
ne trouve plus les processus éphémères.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
Cela peut être fait plus rapidement avec le
lsns
spécialisé commande qui traite des espaces de noms, mais semble ne gérer que les processus (pas les points de montage ni les fd ouverts comme on le verra plus tard) :lsns -n -u -t net -o NS,PATH
(qui devra être reformaté pour plus tard en
lsns -n -u -t net -o NS,PATH | while read inode path; do printf '%20u %s\n' $inode "$path"; done
) -
point de montage
Ceux-ci sont principalement utilisés par le
ip netns add
commande qui crée des espaces de noms réseau permanents en les montant, évitant ainsi qu'ils ne disparaissent lorsqu'aucun processus ni ressource fd ne les maintient, puis permettant également par exemple d'exécuter un routeur, un pare-feu ou un pont dans un espace de noms réseau sans aucun processus lié.Les espaces de noms montés (la gestion des espaces de noms mount et peut-être pid est probablement plus complexe, mais nous ne nous intéressons de toute façon qu'aux espaces de noms réseau) apparaissent comme n'importe quel autre point de montage dans
/proc/mounts
, avec le type de système de fichiersnsfs
. Il n'y a pas de moyen facile en shell de distinguer un espace de noms réseau d'un autre type d'espace de noms, mais puisque deux pseudo-fichiers du même système de fichiers (icinsfs
) ne partageront pas le même inode, élisez-les tous et ignorez les erreurs plus tard dans l'étape d'interface lorsque vous essayez d'utiliser une référence d'espace de noms non réseau comme espace de noms réseau. Désolé, ci-dessous, je ne gérerai pas correctement les points de montage contenant des caractères spéciaux, y compris des espaces, car ils sont déjà échappés dans/proc/mounts
(ce serait plus facile dans n'importe quel autre langage), donc je ne m'embêterai pas non plus à utiliser des lignes terminées par null.awk '$3 == "nsfs" { print $2 }' /proc/mounts | while read -r mount; do stat -c '%20i %n' "$mount" done
-
ouvrir le descripteur de fichier
Ceux-ci sont probablement encore plus rares que les points de montage, sauf temporairement lors de la création de l'espace de noms, mais peuvent être détenus et utilisés par une application spécialisée gérant plusieurs espaces de noms, y compris éventuellement une technologie de conteneurisation.
Je ne pouvais pas concevoir une meilleure méthode que de rechercher tous les fd disponibles dans chaque
/proc/pid/fd/
, en utilisant stat pour vérifier qu'il pointe vers unnsfs
espace de noms et encore une fois ne pas se soucier pour l'instant s'il s'agit vraiment d'un espace de noms réseau. Je suis sûr qu'il existe une boucle plus optimisée, mais celle-ci au moins ne se promènera pas partout et n'assumera aucune limite de processus maximale.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
Supprimez maintenant toutes les références d'espace de noms réseau en double des résultats précédents. Par exemple en utilisant ce filtre sur la sortie combinée des 3 résultats précédents (notamment de la partie descripteur de fichier ouvert) :
sort -k 1n | uniq -w 20
-
-
dans chaque espace de noms, énumérez les interfaces
Nous avons maintenant les références à tous les espaces de noms réseau existants (ainsi qu'à certains espaces de noms non réseau que nous allons simplement ignorer), entrez simplement chacun d'eux en utilisant la référence et affichez les interfaces.
Prenez la sortie des commandes précédentes comme entrée dans cette boucle pour énumérer les interfaces (et selon la question de l'OP, choisissez d'afficher leurs adresses), tout en ignorant les erreurs causées par les espaces de noms non réseau comme expliqué précédemment :
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 du réseau init peut être imprimé avec le pid 1 comme référence :
echo -n 'INIT NETWORK: ' ; stat -L -c %i /proc/1/ns/net
Exemple de sortie (réel mais expurgé) avec un conteneur LXC en cours d'exécution, un espace de nom de réseau "monté" vide créé avec ip netns add ...
ayant une interface de pont non connectée, un espace de noms réseau avec un autre dummy0
interface, maintenue en vie par un processus pas dans cet espace de noms réseau mais en gardant un fd ouvert dessus, créé avec :
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 &
et un Firefox en cours d'exécution qui isole chacun de ses threads "Contenu Web" dans un espace de noms réseau non connecté (tous ceux en panne 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