Skip to content

Gestion réseau Linux

Le document Util-Linux présente la gestion des flux utilisé par des processus et la découverte des machines sur le réseau.

Configuration de base

Sans Network Manager

Vérifier le nom et l'état de l'interface :

ip a

Activer l'interface (la passer en "UP") :

sudo ip link set en1ps0 up

Obtenir une adresse IP : Le simple fait d'activer l'interface ne vous connecte pas ; il faut une configuration IP. * Via DHCP (automatique, le plus courant) :

sudo dhclient en1ps0
(Note : Si dhclient n'est pas installé, essayez dhcpcd en1ps0).

*   **Configuration statique (si pas de DHCP) :**
    ```bash
    sudo ip addr add 192.168.1.XX/24 dev en1ps0
    sudo ip route add default via 192.168.1.1
    ```

Avec Network Manager

Voire le status des connexion

nmcli device status

Activer une connexion :

nmcli connection up id "NomConnexion"

Ajouter une connexion DHCP :

nmcli connection add type ethernet con-name "MaConnexion" ifname en1ps0

Configuration statique :

nmcli connection modify "MaConnexion" ipv4.addresses 192.168.1.XX/24 ipv4.gateway 192.168.1.1 ipv4.dns "8.8.8.8" ipv4.method manual
nmcli connection up "MaConnexion"

On peut aussi faire persister une connexion vpn lors de la connexion de l'utilisateur via cette commande par exemple :

nmcli connection modify peer_laptop connection.autoconnect yes

Voici d'autre documentation plus exaustive : Archlinux Wiki ,RHEL Wiki

Bridges réseau (ponts logiciel)

Un bridge (pont) est un commutateur logiciel (switch) de niveau 2. Il relie plusieurs interfaces réseau dans un même domaine de broadcast, comme si elles étaient branchées sur le même switch physique. Les interfaces attachées au bridge (les ports) perdent leur IP — c'est le bridge lui-même qui porte l'adresse IP.

       ┌─────────── br0 (IP: 192.168.1.50) ───────────┐
       │                (switch logiciel)               │
       ├──────────┬──────────────┬──────────────────────┤
       │          │              │                      │
   enx98...   vnet0 (VM)    tap0 (VPN)              ...
   (port)     (port)       (port)

Cas d'usage 1 : VM sur le même LAN que l'hôte

Par défaut, KVM/libvirt crée un réseau NAT (virbr0, 192.168.122.x). Les VMs sortent derrière le NAT et ne sont pas directement joignables depuis le LAN. En bridgant l'interface physique, les VMs obtiennent une IP directement sur le LAN (ex: 192.168.1.x) via le DHCP de la box, comme si elles étaient branchées physiquement.

Avant (NAT) :                           Après (Bridge) :

  VM → virbr0 (192.168.122.x)             VM → br0 → box → 192.168.1.x
         ↓ NAT                                  ↓ (pas de NAT)
  hôte → 192.168.1.75                     br0 → 192.168.1.50
                                         enx... (port, sans IP)

Configuration avec NetworkManager

1. Créer le bridge :

nmcli connection add type bridge con-name br0 ifname br0 ipv4.method auto

2. Supprimer la connexion existante de l'interface physique :

L'interface qui sera attachée au bridge ne doit plus avoir sa propre connexion IP.

nmcli connection delete "Connexion filaire 1"

3. Créer le port (slave) reliant l'interface physique au bridge :

(dans cette exemple enx98e743339299 est notre liens ou l'on souhaite faire sortir les VM)

nmcli connection add type ethernet slave-type bridge con-name br0-eth ifname enx98e743339299 master br0

4. Activer le port puis le bridge :

nmcli connection up br0-eth
nmcli connection up br0

5. Vérifier :

ip addr show br0              # doit avoir une IP en 192.168.1.x
nmcli device status           # enx... connecté en tant que bridge slave
bridge link                   # liste des ports du bridge

6. Attacher une VM KVM au bridge :

Dans la définition XML de la VM :

<interface type='bridge'>
  <source bridge='br0'/>
  <model type='virtio'/>
</interface>

Ou en CLI :

virsh attach-interface <nom-vm> --type bridge --source br0 --model virtio --persistent

Attacher manuellement une interface TAP de VM au bridge

Quand une VM KVM/libvirt démarre, libvirt crée une interface TAP (ex: vnet0, vnet1) et est censé l'attacher automatiquement au bridge configuré dans le XML. Mais si le bridge a été recréé manuellement ou si libvirt ne le gère pas, le TAP reste en l'air et la VM n'a pas de réseau.

Symptôme : la VM est configurée avec <source bridge='br0'/> mais n'obtient pas d'IP. L'interface vnetX existe mais n'apparaît pas dans les ports du bridge.

Vérifier :

# Lister les ports du bridge (vnetX doit apparaître)
ls /sys/class/net/br0/brif/

# Vérifier si vnetX est attaché
ip link show vnet1 | grep master
# Si vide → vnetX n'est PAS dans le bridge

Attacher manuellement :

sudo ip link set vnet1 master br0

Vérifier après :

ls /sys/class/net/br0/brif/   # doit lister vnet1
ip link show vnet1 | grep master   # doit afficher "master br0"

Note : Cette commande est temporaire (perdue au shutdown de la VM). Pour que l'attachement soit automatique, le bridge doit être géré par NetworkManager ou libvirt avant le démarrage de la VM. Si le bridge est recréé manuellement après le boot, il faut refaire cette commande à chaque fois.

Cas d'usage 2 : Sniffing réseau avec Wireshark (inline tap)

Un bridge permet d'insérer une machine Linux entre deux segments réseau pour capturer tout le trafic qui transite. La machine agit comme un câble transparent : le trafic passe d'une interface à l'autre via le bridge, et Wireshark capture sur l'interface du bridge.

  [Routeur/Box] ── eth0 ──┐
                          ├── br0 ── (Wireshark capture ici)
  [Machine cible] ── eth1 ┘

Mise en place avec NetworkManager

# Créer le bridge (STP off, sans IP pour être transparent)
nmcli connection add type bridge con-name br0 ifname br0 ipv4.method disabled ipv6.method disabled bridge.stp no

# Supprimer les connexions existantes des deux interfaces
nmcli connection delete "Connexion filaire 1" 2>/dev/null

# Attacher les deux interfaces au bridge
nmcli connection add type ethernet slave-type bridge con-name br0-eth0 ifname eth0 master br0
nmcli connection add type ethernet slave-type bridge con-name br0-eth1 ifname eth1 master br0

# Activer (ports d'abord, bridge ensuite)
nmcli connection up br0-eth0 && nmcli connection up br0-eth1 && nmcli connection up br0

# (Optionnel) Donner une IP au bridge pour administrer la machine
nmcli connection modify br0 ipv4.method auto
nmcli connection up br0

Capturer avec Wireshark

# Lancer Wireshark sur le bridge pour voir tout le trafic qui transite
sudo wireshark -i br0

Toutes les communications entre le routeur et la machine cible passent par br0 et sont visibles dans Wireshark. Le bridge ne modifie pas les paquets (niveau 2 transparent).

Diagnostic

# État du bridge et ses ports
bridge link show
ip link show type bridge

# Lister les ports attachés au bridge
ls /sys/class/net/br0/brif/

# Tables MAC apprises par le bridge (quelles MAC sont sur quels ports)
bridge fdb show br br0

# Tables ARP (IP → MAC)
ip neigh show dev br0

# Statistiques du trafic par port
bridge -s link show

Supprimer un bridge

# Retirer les ports
sudo ip link set enx98e743339299 nomaster
# Désactiver et supprimer
sudo ip link set br0 down
sudo ip link delete br0 type bridge

Avec NetworkManager :

nmcli connection delete br0-eth    # supprimer le port
nmcli connection delete br0        # supprimer le bridge
# Recréer la connexion normale de l'interface
nmcli connection add type ethernet con-name "Connexion filaire 1" ifname enx98e743339299
nmcli connection up "Connexion filaire 1"

Piège : STP activé par défaut

NetworkManager active STP (Spanning Tree Protocol) par défaut sur les bridges, avec un forward-delay de 15 secondes. Pendant ce délai, le bridge bloque le trafic et reste en NO-CARRIER → le DHCP échoue et le bridge n'obtient jamais d'IP.

Symptôme : br0 reste bloqué en connexion (obtention de la configuration IP) indéfiniment, ou NO-CARRIER même avec un port attaché et carrier actif.

Solution : Toujours créer le bridge avec STP désactivé :

nmcli connection add type bridge con-name br0 ifname br0 ipv4.method auto bridge.stp no

STP n'est utile que si vous connectez plusieurs switches/bridges entre eux et risquez de créer des boucles. Pour un bridge simple (1 interface physique + VMs), il n'a aucune utilité.

Méthode simple en 3 commandes (NetworkManager)

# 1. Créer le bridge (STP off = pas de délai de 15s)
nmcli connection add type bridge con-name br0 ifname br0 ipv4.method auto bridge.stp no

# 2. Attacher l'interface physique (remplace sa connexion existante)
nmcli connection add type ethernet slave-type bridge con-name br0-eth ifname enx98e743339299 master br0

# 3. Activer (port d'abord, bridge ensuite)
nmcli connection up br0-eth && nmcli connection up br0

Important : l'interface physique ne doit pas avoir d'autre connexion active. Si "Connexion filaire 1" existe encore sur cette interface, la supprimer d'abord : nmcli connection delete "Connexion filaire 1"

Alternative simple : macvtap (sans bridge)

Si le seul but est de mettre une VM KVM sur le même LAN (pas de sniffing, pas de plusieurs VMs qui doivent se parler entre elles), macvtap est beaucoup plus simple : aucun bridge à créer, aucun port à configurer. La VM est directement attachée à l'interface physique.

macvtap :                              Bridge :

  VM → enx98... (192.168.1.x)            VM → br0 → enx... (192.168.1.x)
  (direct, pas de bridge)                     (bridge intermédiaire)

Configuration KVM (XML) :

<interface type='direct'>
  <source dev='enx98e743339299' mode='bridge'/>
  <model type='virtio'/>
</interface>

Ou en CLI :

virsh attach-interface <nom-vm> --type direct --source enx98e743339299 --mode bridge --model virtio --persistent

Avantages de macvtap

  • Zéro configuration réseau sur l'hôte — pas de bridge, pas de port, pas de NM
  • La VM obtient une IP directement sur le LAN via le DHCP de la box
  • Performances identiques voire meilleures (pas de overhead de bridge)

Limites de macvtap

macvtap Bridge
VM ↔ autres machines du LAN Oui Oui
VM ↔ hôte Non (isolé L2) Oui
VM ↔ autres VMs sur le même hôte Non (si même interface) Oui
Sniffing Wireshark Non Oui
Plusieurs interfaces physiques redondantes Non Oui (LACP/bonding)
IPv6 SLAAC sur la VM Oui Oui

Quand utiliser macvtap ? Si vous voulez juste qu'une VM ait une IP sur le LAN et que vous n'avez pas besoin qu'elle parle à l'hôte ou à d'autres VMs locales. C'est le plus rapide à mettre en place.

Quand utiliser un bridge ? Si la VM doit communiquer avec l'hôte, si vous voulez sniffer le trafic, ou si vous avez plusieurs VMs qui doivent se parler entre elles.

Exemple ensuite de reset

nmcli connection delete br0-eth
nmcli connection delete br0
sudo ip link delete br0
Il faut ensuite recré les liens exemple en CLI :

nmcli connection add type ethernet con-name "Connexion filaire 1" ifname enx98e743339299

Résolution de nom

resolvconf

sudo apt install resolvconf
sudo nano /etc/resolvconf/resolv.conf.d/head

Les fichiers dans /etc/resolvconf/resolv.conf.d/ sont assemblés pour générer le fichier /etc/resolv.conf final : 1. head : Le contenu est placé tout en haut (priorité maximale). 2. (Données dynamiques) : Les DNS fournis par votre routeur/DHCP arrivent ensuite. 3. tail : Le contenu est ajouté à la fin (serveurs de secours).

En ajoutant votre ligne nameserver X.X.X.X à la suite du texte existant dans head, ce serveur sera toujours le premier interrogé, quel que soit le réseau auquel vous vous connectez.

On peut en rajouter plusieurs dans le head.

sudo cat /etc/resolvconf/resolv.conf.d/head
nameserver 1.1.1.1
nameserver 1.0.0.1

Pour voir la configuration actuelle :

sudo resolvconf -u

systemd-resolved

systemd-resolved est un service système qui fournit la résolution de noms de réseau aux applications locales.

Vérifier l'état et la configuration actuelle :

resolvectl status

Tester la résolution d'un nom :

resolvectl query google.com

Lien symbolique recommandé pour /etc/resolv.conf : Pour que les applications utilisent le stub local de systemd-resolved :

sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

Vider le cache DNS :

sudo resolvectl flush-caches

Configurer des DNS statiques : Éditer le fichier /etc/systemd/resolved.conf :

[Resolve]
DNS=1.1.1.1 8.8.8.8
FallbackDNS=1.0.0.1 8.8.4.4
Puis redémarrer le service :
sudo systemctl restart systemd-resolved

Tailscale

Installation Debian

sudo apt install curl
curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update
sudo apt install tailscale
sudo tailscale up --accept-routes --accept-dns=false --stateful-filtering=false

Vous êtes connecté

tailscale ip -4

Configuration avancé

Si le périphérique qu'on à ajouté est un serveur ou un périphérique accessible à distance, on doit de désactiver l’expiration de la clé pour éviter d’avoir à vous authentifier périodiquement.

Ajouter une route :

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
sudo tailscale up --advertise-routes=10.3.1.0/24 --snat-subnet-routes=true --stateful-filtering=false --accept-routes --accept-dns=false

Pour que le client Linux accepte la route :

sudo tailscale up --accept-routes

Pour le refuser :

sudo tailscale up --accept-routes=false --stateful-filtering=false

Pour utiliser tailscale dans un conteneur lxc :

sudo nano /etc/pve/lxc/xxx.conf
lxc.mount.entry: /dev/net dev/net none bind,create=dir

accepter le noeud en "exit node" :

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
sudo tailscale up --advertise-exit-node --accept-routes --stateful-filtering=false

zerotier

Installation Debian

sudo apt install curl gnupg1 -y
curl -s https://install.zerotier.com | sudo bash
sudo zerotier-cli join 28e7a7697309d93a

Configuration avancé

Si installation dans un conteneur aller dans le ficher de config du conteneur (/etc/pve/lxc/num.conf) :

lxc.mount.entry: /dev/net dev/net none bind,create=dir

Pour désinstaller ZeroTier :

sudo apt remove zerotier-one -y && \
sudo rm -rf /etc/apt/sources.list.d/zerotier.list && \
sudo rm -rf /var/lib/zerotier-one

Executer dans un conteneur Zerotier :

sudo docker run -d --name zerotierclient --restart unless-stopped --cap-add NET_ADMIN --device /dev/net/tun zerotier/zerotier:latest xxx

IPv6

Diagnostiquer la connectivité IPv6

# Vérifier l'adresse IPv6 publique assignée
ip -6 addr show dev eno1

# Vérifier la table de routage IPv6 (chercher "default")
ip -6 route show
ip -6 route show default

# Identifier la gateway IPv6 (routeur annoncé par RA)
ip -6 neigh show dev eno1

# Tester la sortie IPv6 vers Internet
curl -6 --max-time 5 https://ipv6.icanhazip.com

# Vérifier qu'un service écoute bien en IPv6
ss -tlnp | grep 443
# Doit montrer [::]:443, pas uniquement 0.0.0.0:443

Problème fréquent : route par défaut IPv6 manquante

Le routeur peut annoncer un préfixe IPv6 via SLAAC (Router Advertisement) sans pour autant inclure une route par défaut. L'adresse est alors bien assignée à l'interface, mais les paquets de réponse ne savent pas par où sortir → les clients semblent ne jamais obtenir de réponse.

Symptômes :

  • ip -6 route show default → vide
  • curl -6 https://ipv6.icanhazip.com → Could not connect
  • Les clients externes (4G/5G) ne parviennent pas à se connecter

Trouver la gateway (adresse link-local du routeur) :

ip -6 neigh show dev eno1
# Chercher l'entrée avec le flag "router"
# Exemple : fe80::e65d:51ff:fe35:980 lladdr e4:5d:51:35:09:80 router STALE

Ajouter la route manuellement (temporaire) :

sudo ip -6 route add default via fe80::e65d:51ff:fe35:980 dev eno1

Configuration IPv6 persistante avec ifupdown

Sur Debian/Ubuntu sans NetworkManager ni netplan, la configuration réseau passe par /etc/network/interfaces.

La commande inet6 auto active SLAAC (adresse dérivée du MAC via EUI-64, donc stable). Le post-up ajoute la route par défaut manquante à chaque activation de l'interface :

# /etc/network/interfaces
allow-hotplug eno1
auto eno1
iface eno1 inet static
    address 192.168.1.250/24
    gateway 192.168.1.1

# IPv6 via SLAAC + route par défaut forcée
iface eno1 inet6 auto
    post-up ip -6 route replace default via fe80::e65d:51ff:fe35:980 dev $IFACE || true

Note : replace au lieu de add évite l'erreur si la route existe déjà (ex : après un ifup sans ifdown). Le || true empêche l'échec du script au boot.

Appliquer sans redémarrer :

sudo ifdown eno1 && sudo ifup eno1
# Ou simplement ajouter la route manuellement pour tester
sudo ip -6 route replace default via fe80::GATEWAY_LL dev eno1

Forcer la découverte IPv6 (SLAAC) et gérer le forwarding (Docker)

Lorsqu'un routeur (comme une box internet) envoie ses annonces réseau (Router Advertisements) peu fréquemment, une machine Linux configurée en auto (SLAAC) peut mettre plusieurs minutes après un redémarrage avant d'obtenir son adresse IPv6. De plus, l'activation de l'IP forwarding (souvent par Docker) désactive par défaut l'acceptation de ces annonces par le noyau.

1. Forcer l'acceptation des annonces avec le forwarding activé : Il faut configurer sysctl pour forcer l'acceptation des RA (valeur 2) même si la machine agit comme un routeur :

# /etc/sysctl.d/99-ipv6-accept-ra.conf
net.ipv6.conf.all.accept_ra=2
net.ipv6.conf.default.accept_ra=2
net.ipv6.conf.eno1.accept_ra=2
Appliquer avec : sudo sysctl -p /etc/sysctl.d/99-ipv6-accept-ra.conf

2. Solliciter activement le routeur avec ndisc6 : Pour ne pas attendre l'annonce passive du routeur (notamment au boot), installez l'outil ndisc6 :

sudo apt install ndisc6
Vous pouvez forcer la découverte manuellement sur une interface avec la commande :
sudo rdisc6 eno1
(Note : Sous Debian/Ubuntu, le gestionnaire de réseau utilisera automatiquement cet utilitaire, s'il est installé, pour solliciter une adresse IPv6 dès l'activation de l'interface).

Docker et IPv6

Par défaut, les réseaux bridge Docker n'ont pas l'IPv6 activé. Les containers n'obtiennent pas d'adresse IPv6 et Traefik ne peut pas router le trafic IPv6 vers eux, même si l'OS hôte a une IP IPv6.

Activer IPv6 sur un réseau dans docker-compose.yaml :

networks:
    frontend:
        name: frontend        # Évite le préfixe du projet (ex: "infrastructure_frontend")
        driver: bridge
        enable_ipv6: true
        ipam:
            config:
                - subnet: 172.19.0.0/16   # Subnet IPv4 existant
                - subnet: fd01::/80        # Subnet IPv6 ULA (plage privée fd00::/8)