Configuration réseau#

Hide code cell source

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.gridspec as gridspec
import numpy as np
import pandas as pd
import seaborn as sns
import ipaddress
import socket

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

Modèle réseau Linux — stack TCP/IP, netfilter, namespaces#

La pile réseau du noyau#

Linux implémente la pile TCP/IP directement dans le noyau. Chaque paquet entrant ou sortant traverse une série de couches avant d’atteindre l’application ou le réseau physique.

Application (socket)
       │
  ┌────▼────┐
  │ Socket  │  ← couche 5-7 : API POSIX, domaines AF_INET, AF_INET6, AF_UNIX
  ├─────────┤
  │  TCP/UDP│  ← couche 4 : ports, sessions, contrôle de flux
  ├─────────┤
  │   IP    │  ← couche 3 : adressage, routage, fragmentation
  ├─────────┤
  │Netfilter│  ← hooks noyau pour le filtrage et le NAT
  ├─────────┤
  │ Driver  │  ← couche 2 : Ethernet, Wi-Fi, tun/tap…
  └─────────┘

Le sous-système Netfilter s’insère directement dans la pile IP. Il expose cinq hooks (NF_INET_PRE_ROUTING, NF_INET_LOCAL_IN, NF_INET_FORWARD, NF_INET_LOCAL_OUT, NF_INET_POST_ROUTING) que des modules noyau peuvent intercepter pour analyser ou modifier les paquets. iptables et nftables s’appuient tous deux sur ces hooks.

Namespaces réseau#

Linux supporte les network namespaces (netns), qui isolent complètement une pile réseau : interfaces, tables de routage, règles iptables, sockets. Chaque conteneur Docker possède son propre namespace réseau.

# Créer un namespace réseau isolé
ip netns add test_ns

# Exécuter une commande dans ce namespace
ip netns exec test_ns ip addr

# Relier deux namespaces via une paire veth
ip link add veth0 type veth peer name veth1
ip link set veth1 netns test_ns

# Lister les namespaces
ip netns list

# Supprimer
ip netns del test_ns

Les namespaces sont la brique fondamentale de la conteneurisation réseau. Un processus hérite du namespace de son parent ; seule une appel unshare(CLONE_NEWNET) ou ip netns exec permet d’en changer.

Interfaces réseau#

Types d’interfaces#

Interface

Rôle

eth0, ens3

Ethernet physique (nommage prévisible systemd)

lo

Loopback (127.0.0.1, ::1)

wlan0, wlp2s0

Wi-Fi

bond0

Agrégation de liens (bonding)

br0

Bridge (pont logiciel)

eth0.10

VLAN 802.1Q

veth0

Virtual Ethernet pair (conteneurs)

tun0, tap0

Interfaces virtuelles (VPN)

dummy0

Interface de test sans matériel

Exploration via /sys/class/net#

# Vitesse de l'interface (Mb/s)
cat /sys/class/net/ens3/speed

# État opérationnel
cat /sys/class/net/ens3/operstate    # up, down, unknown

# Statistiques (octets reçus/émis, erreurs)
cat /sys/class/net/ens3/statistics/rx_bytes
cat /sys/class/net/ens3/statistics/tx_packets
cat /sys/class/net/ens3/statistics/rx_errors

# Driver utilisé
readlink /sys/class/net/ens3/device/driver

Configuration IP#

Adresses avec ip addr#

# Lister les adresses
ip addr show
ip addr show ens3

# Ajouter une adresse IPv4 avec masque CIDR
ip addr add 192.168.1.10/24 dev ens3

# Ajouter une adresse IPv6
ip addr add 2001:db8::1/64 dev ens3

# Supprimer une adresse
ip addr del 192.168.1.10/24 dev ens3

# Vider toutes les adresses d'une interface
ip addr flush dev ens3

Routes avec ip route#

# Table de routage principale
ip route show
ip route show table main

# Ajouter une route statique
ip route add 10.10.0.0/16 via 192.168.1.1 dev ens3

# Ajouter la route par défaut
ip route add default via 192.168.1.254

# Supprimer une route
ip route del 10.10.0.0/16

# Tester quel chemin sera utilisé pour une destination
ip route get 8.8.8.8

Sortie de ip route get 8.8.8.8 :

8.8.8.8 via 192.168.1.254 dev ens3 src 192.168.1.10 uid 1000
    cache

Policy routing avec ip rule#

Le policy routing (routage par politique) permet d’utiliser plusieurs tables de routage selon des critères : adresse source, marque de paquet, ToS.

# Lister les règles
ip rule list

# Créer une table de routage personnalisée
echo "200 custom_table" >> /etc/iproute2/rt_tables

# Ajouter une règle : paquets venant de 10.0.0.0/8 → table custom_table
ip rule add from 10.0.0.0/8 table custom_table

# Ajouter une route dans cette table
ip route add default via 10.0.0.1 table custom_table

# Supprimer la règle
ip rule del from 10.0.0.0/8

Les tables de routage prédéfinies sont local (255), main (254) et default (253). Le noyau les consulte dans l’ordre croissant de priorité défini par ip rule.

NetworkManager#

NetworkManager est le gestionnaire de connexions réseau standard sur les distributions modernes (RHEL, Fedora, Ubuntu Desktop, Debian…). Il gère les profils de connexion et supporte Ethernet, Wi-Fi, VPN, bonds, bridges, VLANs.

nmcli — interface en ligne de commande#

# État général
nmcli general status

# Lister les connexions
nmcli connection show

# Lister les périphériques
nmcli device status

# Activer / désactiver une connexion
nmcli connection up "Wired connection 1"
nmcli connection down "Wired connection 1"

# Créer une connexion Ethernet statique
nmcli connection add type ethernet \
    con-name "serveur-eth0" \
    ifname ens3 \
    ipv4.addresses 192.168.1.10/24 \
    ipv4.gateway 192.168.1.254 \
    ipv4.dns "1.1.1.1,8.8.8.8" \
    ipv4.method manual

# Modifier une connexion existante
nmcli connection modify "serveur-eth0" ipv4.dns "9.9.9.9"

# Supprimer une connexion
nmcli connection delete "serveur-eth0"

# Recharger une connexion après modification
nmcli connection reload

Les profils de connexion sont stockés dans /etc/NetworkManager/system-connections/ au format INI (.nmconnection).

# Contenu type d'un profil
cat /etc/NetworkManager/system-connections/serveur-eth0.nmconnection
[connection]
id=serveur-eth0
type=ethernet
interface-name=ens3

[ethernet]

[ipv4]
address1=192.168.1.10/24,192.168.1.254
dns=1.1.1.1;8.8.8.8;
method=manual

[ipv6]
method=auto

Netplan (Ubuntu)#

Netplan est la couche d’abstraction de configuration réseau d’Ubuntu (depuis 17.10). Les fichiers YAML dans /etc/netplan/ sont traduits en configuration pour le backend choisi (NetworkManager ou systemd-networkd).

Structure d’un fichier Netplan#

# /etc/netplan/00-installer-config.yaml
network:
  version: 2
  renderer: networkd          # ou NetworkManager

  ethernets:
    ens3:
      dhcp4: false
      addresses:
        - 192.168.1.10/24
        - 2001:db8::10/64
      routes:
        - to: default
          via: 192.168.1.254
      nameservers:
        addresses: [1.1.1.1, 8.8.8.8]
        search: [example.com, local.example.com]
      mtu: 1500

  bonds:
    bond0:
      interfaces: [ens3, ens4]
      parameters:
        mode: active-backup
        primary: ens3
        mii-monitor-interval: 100

  vlans:
    vlan10:
      id: 10
      link: ens3
      addresses: [10.10.10.1/24]

Commandes Netplan#

# Tester la configuration sans l'appliquer
netplan try              # revient automatiquement si non confirmé

# Appliquer la configuration
netplan apply

# Générer les fichiers backend sans appliquer
netplan generate

# Déboguer
netplan --debug apply

Backends Netplan

networkd (systemd-networkd) est adapté aux serveurs sans interface graphique. NetworkManager convient aux postes de travail où des connexions Wi-Fi et VPN sont gérées dynamiquement. Le choix du backend n’affecte pas la syntaxe YAML Netplan.

DNS#

/etc/resolv.conf et /etc/hosts#

/etc/resolv.conf définit les serveurs DNS utilisés par la libc (et donc la plupart des programmes) :

nameserver 1.1.1.1
nameserver 8.8.8.8
search example.com local.example.com
options ndots:5 timeout:2 attempts:3

/etc/hosts permet de résoudre des noms localement sans passer par DNS :

127.0.0.1   localhost
::1         localhost ip6-localhost
192.168.1.5  srv-db.example.com  srv-db

L’ordre de résolution est défini par /etc/nsswitch.conf :

hosts: files dns myhostname

systemd-resolved#

systemd-resolved est le résolveur DNS intégré à systemd. Il offre un cache local, la validation DNSSEC, le DNS-over-TLS et la résolution par interface.

# État du résolveur
resolvectl status

# Résoudre un nom
resolvectl query github.com

# Statistiques du cache
resolvectl statistics

# Vider le cache
resolvectl flush-caches

# DNS actif par interface
resolvectl dns ens3

# Configurer un serveur DNS pour une interface
resolvectl dns ens3 9.9.9.9

Quand systemd-resolved est actif, /etc/resolv.conf est souvent un lien symbolique vers /run/systemd/resolve/stub-resolv.conf (qui pointe vers 127.0.0.53, le stub resolver).

Outils de diagnostic DNS#

# dig — outil de référence
dig github.com                         # enregistrement A
dig github.com AAAA                    # enregistrement AAAA
dig github.com MX                      # enregistrements MX
dig @8.8.8.8 github.com               # requête vers un serveur spécifique
dig +trace github.com                  # résolution itérative complète
dig -x 140.82.121.4                    # résolution inverse (PTR)
dig +short github.com                  # sortie compacte

# nslookup — outil interactif
nslookup github.com
nslookup -type=MX github.com 8.8.8.8

# host — commande simple
host github.com
host -t NS github.com

Diagnostic réseau#

ss — état des sockets#

ss (socket statistics) remplace netstat et est beaucoup plus rapide car il interroge directement le noyau via Netlink.

# Toutes les connexions TCP établies
ss -t state established

# Ports en écoute (TCP et UDP)
ss -tlunp

# Connexions avec processus propriétaire
ss -tlnp

# Filtrer par port
ss -t sport = :443

# Statistiques globales
ss -s

Sortie de ss -tlnp :

State  Recv-Q Send-Q  Local Address:Port   Peer Address:Port  Process
LISTEN 0      128           0.0.0.0:22          0.0.0.0:*     users:(("sshd",pid=1234,fd=3))
LISTEN 0      511           0.0.0.0:80          0.0.0.0:*     users:(("nginx",pid=5678,fd=6))
LISTEN 0      511           0.0.0.0:443         0.0.0.0:*     users:(("nginx",pid=5678,fd=7))

Connectivité et routage#

# Ping basique
ping -c 4 8.8.8.8
ping6 -c 4 2001:4860:4860::8888

# Traceroute UDP (par défaut)
traceroute 8.8.8.8

# Traceroute ICMP (plus compatible)
traceroute -I 8.8.8.8

# mtr — combinaison ping + traceroute en temps réel
mtr 8.8.8.8
mtr --report --report-cycles 10 8.8.8.8

# Tester la connectivité TCP sans telnet
nc -zv 192.168.1.5 22
nc -zv -w 3 github.com 443

tcpdump — capture de paquets#

# Capturer sur l'interface ens3
tcpdump -i ens3

# Filtrer par host
tcpdump -i ens3 host 192.168.1.5

# Filtrer par port
tcpdump -i ens3 port 80 or port 443

# Capturer et sauvegarder (pour Wireshark)
tcpdump -i ens3 -w capture.pcap

# Lire un fichier de capture
tcpdump -r capture.pcap

# Afficher le contenu ASCII des paquets HTTP
tcpdump -i ens3 -A port 80

# N'afficher que les en-têtes (pas de résolution DNS pour plus de vitesse)
tcpdump -i ens3 -n -q port 22

Performances de tcpdump

Sur un lien chargé, utilisez -c N pour limiter le nombre de paquets capturés et -s snaplen pour capturer uniquement les N premiers octets de chaque paquet (par défaut 262144 octets). Une capture avec -w est nettement plus performante que la sortie texte en temps réel.

Bonding et teaming#

Le bonding agrège plusieurs interfaces physiques en une interface logique unique, offrant redondance et/ou augmentation de bande passante.

Modes de bonding#

Mode

Nom

Description

0

balance-rr

Round-robin, répartition des paquets

1

active-backup

Une seule interface active, bascule en cas de panne

2

balance-xor

Répartition par hachage src/dst MAC

3

broadcast

Envoi sur toutes les interfaces

4

802.3ad (LACP)

Agrégation dynamique IEEE, switch doit supporter LACP

5

balance-tlb

Répartition adaptative en émission

6

balance-alb

Répartition adaptative en émission + réception

Le mode 1 (active-backup) est le plus simple et ne nécessite aucune configuration du switch. Le mode 4 (LACP) offre les meilleures performances mais exige un switch manageable.

Configuration d’un bond avec ip#

# Créer l'interface bond
ip link add bond0 type bond

# Définir le mode
echo active-backup > /sys/class/net/bond0/bonding/mode
echo 100 > /sys/class/net/bond0/bonding/miimon

# Attacher les esclaves
ip link set ens3 down
ip link set ens3 master bond0
ip link set ens4 down
ip link set ens4 master bond0

# Activer le bond
ip link set bond0 up
ip addr add 192.168.1.10/24 dev bond0

# Vérifier l'état
cat /proc/net/bonding/bond0

Avec Netplan (mode LACP) :

bonds:
  bond0:
    interfaces: [ens3, ens4]
    addresses: [192.168.1.10/24]
    parameters:
      mode: 802.3ad
      lacp-rate: fast
      mii-monitor-interval: 100
      transmit-hash-policy: layer3+4

VLANs — 802.1Q#

Un VLAN (Virtual LAN) segmente logiquement un réseau physique. En 802.1Q, une étiquette de 4 octets est insérée dans l’en-tête Ethernet ; les 12 bits de VLAN ID permettent 4094 VLANs (1-4094).


Démonstrations Python#

Module ipaddress — calcul de sous-réseaux#

import ipaddress

# Réseau de base
net = ipaddress.IPv4Network("192.168.0.0/22")

print(f"Réseau       : {net}")
print(f"Masque       : {net.netmask}")
print(f"Masque joker : {net.hostmask}")
print(f"Adresse réseau: {net.network_address}")
print(f"Broadcast    : {net.broadcast_address}")
print(f"Nb d'hôtes   : {net.num_addresses - 2}")
print(f"Préfixe      : /{net.prefixlen}")
print()

# Décomposer en sous-réseaux /24
print("Sous-réseaux /24 :")
for subnet in net.subnets(new_prefix=24):
    hosts = list(subnet.hosts())
    print(f"  {subnet}  →  premier hôte: {hosts[0]}  dernier: {hosts[-1]}")

print()

# Supernet
supernet = net.supernet()
print(f"Supernet (/21) : {supernet}")

# Vérifier l'appartenance
ip = ipaddress.IPv4Address("192.168.1.42")
print(f"\n{ip} dans {net} : {ip in net}")
print(f"{ip} est privée : {ip.is_private}")
print(f"{ip} est globale: {ip.is_global}")

# IPv6
net6 = ipaddress.IPv6Network("2001:db8::/32")
print(f"\nRéseau IPv6    : {net6}")
print(f"Nb d'adresses  : {net6.num_addresses:.2e}")
subnet6 = list(net6.subnets(new_prefix=48))[0]
print(f"Premier /48    : {subnet6}")
Réseau       : 192.168.0.0/22
Masque       : 255.255.252.0
Masque joker : 0.0.3.255
Adresse réseau: 192.168.0.0
Broadcast    : 192.168.3.255
Nb d'hôtes   : 1022
Préfixe      : /22

Sous-réseaux /24 :
  192.168.0.0/24  →  premier hôte: 192.168.0.1  dernier: 192.168.0.254
  192.168.1.0/24  →  premier hôte: 192.168.1.1  dernier: 192.168.1.254
  192.168.2.0/24  →  premier hôte: 192.168.2.1  dernier: 192.168.2.254
  192.168.3.0/24  →  premier hôte: 192.168.3.1  dernier: 192.168.3.254

Supernet (/21) : 192.168.0.0/21

192.168.1.42 dans 192.168.0.0/22 : True
192.168.1.42 est privée : True
192.168.1.42 est globale: False

Réseau IPv6    : 2001:db8::/32
Nb d'adresses  : 7.92e+28
Premier /48    : 2001:db8::/48

Plan d’adressage — visualisation#

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

# Plan d'adressage d'une infrastructure typique
plan = [
    {"VLAN": 1,  "Nom": "Management",   "Réseau": "10.0.1.0/24",  "Hôtes": 10,  "Couleur": "#4e79a7"},
    {"VLAN": 10, "Nom": "Production",   "Réseau": "10.0.10.0/24", "Hôtes": 80,  "Couleur": "#f28e2b"},
    {"VLAN": 20, "Nom": "Staging",      "Réseau": "10.0.20.0/24", "Hôtes": 30,  "Couleur": "#59a14f"},
    {"VLAN": 30, "Nom": "DMZ",          "Réseau": "10.0.30.0/24", "Hôtes": 15,  "Couleur": "#e15759"},
    {"VLAN": 40, "Nom": "Sauvegarde",   "Réseau": "10.0.40.0/24", "Hôtes": 8,   "Couleur": "#76b7b2"},
    {"VLAN": 50, "Nom": "Supervision",  "Réseau": "10.0.50.0/24", "Hôtes": 5,   "Couleur": "#edc948"},
]

df = pd.DataFrame(plan)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Tableau
ax = axes[0]
ax.axis("off")
table_data = [[row["VLAN"], row["Nom"], row["Réseau"],
               str(row["Hôtes"]), f"{254 - row['Hôtes']} libres"]
              for _, row in df.iterrows()]
col_labels = ["VLAN", "Segment", "Réseau", "Utilisés", "Disponibles"]
tbl = ax.table(cellText=table_data, colLabels=col_labels,
               loc="center", cellLoc="center")
tbl.auto_set_font_size(False)
tbl.set_fontsize(10)
tbl.scale(1.2, 1.8)
for i, row in enumerate(plan):
    for j in range(5):
        tbl[(i + 1, j)].set_facecolor(row["Couleur"] + "55")
for j in range(5):
    tbl[(0, j)].set_facecolor("#333333")
    tbl[(0, j)].set_text_props(color="white", fontweight="bold")
ax.set_title("Plan d'adressage VLAN", fontweight="bold", pad=12)

# Utilisation des hôtes
ax2 = axes[1]
noms = df["Nom"]
utilises = df["Hôtes"]
libres = 254 - df["Hôtes"]
x = np.arange(len(noms))
width = 0.55
bars1 = ax2.bar(x, utilises, width, label="Utilisés", color=[r["Couleur"] for r in plan])
bars2 = ax2.bar(x, libres, width, bottom=utilises, label="Disponibles",
                color=[r["Couleur"] + "33" for r in plan], edgecolor=[r["Couleur"] for r in plan],
                linewidth=0.8)
ax2.set_xticks(x)
ax2.set_xticklabels(noms, rotation=20, ha="right")
ax2.set_ylabel("Adresses hôtes (/24)")
ax2.set_title("Utilisation par segment", fontweight="bold")
ax2.set_ylim(0, 265)
ax2.legend(loc="upper right")
for bar, val in zip(bars1, utilises):
    ax2.text(bar.get_x() + bar.get_width() / 2, val + 4,
             str(val), ha="center", va="bottom", fontsize=9)

plt.suptitle("Infrastructure réseau multi-VLAN", fontsize=13, fontweight="bold", y=1.02)
plt.show()
_images/7abc2d585a2ab5f39252bf3b17e9261ffc2599130d603ecc50a28a68911936fb.png

Table de routage — simulation#

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

routes = pd.DataFrame([
    {"Destination": "0.0.0.0/0",       "Via": "192.168.1.254", "Interface": "ens3",   "Métrique": 100, "Proto": "static",  "Type": "default"},
    {"Destination": "10.0.10.0/24",    "Via": "0.0.0.0",       "Interface": "ens3",   "Métrique": 0,   "Proto": "kernel",  "Type": "local"},
    {"Destination": "10.0.20.0/24",    "Via": "10.0.1.2",      "Interface": "ens3",   "Métrique": 200, "Proto": "static",  "Type": "network"},
    {"Destination": "10.0.30.0/24",    "Via": "10.0.1.3",      "Interface": "ens3",   "Métrique": 200, "Proto": "static",  "Type": "network"},
    {"Destination": "172.16.0.0/12",   "Via": "10.0.1.1",      "Interface": "bond0",  "Métrique": 150, "Proto": "ospf",    "Type": "network"},
    {"Destination": "192.168.1.0/24",  "Via": "0.0.0.0",       "Interface": "ens3",   "Métrique": 0,   "Proto": "kernel",  "Type": "local"},
    {"Destination": "10.8.0.0/24",     "Via": "0.0.0.0",       "Interface": "tun0",   "Métrique": 0,   "Proto": "kernel",  "Type": "vpn"},
])

color_map = {
    "default": "#e15759",
    "local":   "#4e79a7",
    "network": "#59a14f",
    "vpn":     "#f28e2b",
}

fig, axes = plt.subplots(1, 2, figsize=(15, 5))

# Tableau des routes
ax = axes[0]
ax.axis("off")
tbl = ax.table(
    cellText=routes[["Destination", "Via", "Interface", "Métrique", "Proto"]].values,
    colLabels=["Destination", "Passerelle", "Interface", "Métrique", "Proto"],
    loc="center", cellLoc="center"
)
tbl.auto_set_font_size(False)
tbl.set_fontsize(9)
tbl.scale(1.1, 1.7)
for i, (_, row) in enumerate(routes.iterrows()):
    c = color_map[row["Type"]] + "44"
    for j in range(5):
        tbl[(i + 1, j)].set_facecolor(c)
for j in range(5):
    tbl[(0, j)].set_facecolor("#444444")
    tbl[(0, j)].set_text_props(color="white", fontweight="bold")
ax.set_title("Table de routage principale", fontweight="bold", pad=12)

# Distribution par protocole
ax2 = axes[1]
proto_counts = routes["Proto"].value_counts()
colors = ["#4e79a7", "#59a14f", "#f28e2b", "#e15759"]
wedges, texts, autotexts = ax2.pie(
    proto_counts.values,
    labels=proto_counts.index,
    autopct="%1.0f%%",
    colors=colors[:len(proto_counts)],
    startangle=90,
    pctdistance=0.75
)
for at in autotexts:
    at.set_fontsize(10)
    at.set_fontweight("bold")
ax2.set_title("Routes par protocole", fontweight="bold")

legend_patches = [mpatches.Patch(color=color_map[t], label=t.capitalize()) for t in color_map]
axes[0].legend(handles=legend_patches, loc="lower center",
               bbox_to_anchor=(0.5, -0.08), ncol=4, fontsize=8)
plt.suptitle("Analyse de la table de routage", fontsize=13, fontweight="bold")
plt.show()
_images/41dbdb3c9344aad77fce79b075daf220018fc557be49acc4862b4092e729e8be.png

Diagramme d’architecture réseau#

sns.set_theme(style="white", palette="muted", font_scale=1.0)

fig, ax = plt.subplots(figsize=(13, 9))
ax.set_xlim(0, 13)
ax.set_ylim(0, 9)
ax.axis("off")

def boite(ax, x, y, w, h, label, sublabel="", color="#4e79a7", fontsize=9):
    rect = plt.Rectangle((x - w/2, y - h/2), w, h,
                          facecolor=color + "33", edgecolor=color, linewidth=2, zorder=3)
    ax.add_patch(rect)
    ax.text(x, y + (0.15 if sublabel else 0), label, ha="center", va="center",
            fontsize=fontsize, fontweight="bold", zorder=4)
    if sublabel:
        ax.text(x, y - 0.25, sublabel, ha="center", va="center",
                fontsize=7.5, color="#555555", zorder=4)

def fleche(ax, x1, y1, x2, y2, label="", color="#888888"):
    ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
                arrowprops=dict(arrowstyle="<->", color=color, lw=1.5), zorder=2)
    if label:
        mx, my = (x1 + x2) / 2, (y1 + y2) / 2
        ax.text(mx + 0.15, my, label, fontsize=7.5, color=color, va="center")

# Internet
boite(ax, 6.5, 8.3, 2.2, 0.8, "Internet", "", "#888888", fontsize=10)

# Firewall
boite(ax, 6.5, 6.8, 2.4, 0.9, "Pare-feu", "iptables / nftables", "#e15759")
fleche(ax, 6.5, 7.75, 6.5, 7.25, color="#e15759")

# Switch/routeur cœur
boite(ax, 6.5, 5.3, 2.4, 0.9, "Routeur cœur", "bond0 LACP", "#f28e2b")
fleche(ax, 6.5, 6.35, 6.5, 5.75, color="#f28e2b")

# DMZ
boite(ax, 2.5, 3.7, 2.4, 0.9, "DMZ (VLAN 30)", "10.0.30.0/24", "#e15759")
fleche(ax, 5.3, 5.1, 3.7, 4.0, color="#aaaaaa")

# Production
boite(ax, 6.5, 3.7, 2.4, 0.9, "Production (VLAN 10)", "10.0.10.0/24", "#59a14f")
fleche(ax, 6.5, 4.85, 6.5, 4.15, color="#aaaaaa")

# Management
boite(ax, 10.5, 3.7, 2.4, 0.9, "Management (VLAN 1)", "10.0.1.0/24", "#4e79a7")
fleche(ax, 7.7, 5.1, 9.3, 4.0, color="#aaaaaa")

# Serveurs dans les zones
boite(ax, 2.5, 2.2, 1.8, 0.7, "srv-web", "nginx / TLS", "#76b7b2", fontsize=8)
boite(ax, 5.5, 2.2, 1.8, 0.7, "srv-app", "Python / Java", "#59a14f", fontsize=8)
boite(ax, 7.5, 2.2, 1.8, 0.7, "srv-db", "PostgreSQL", "#4e79a7", fontsize=8)
boite(ax, 10.5, 2.2, 1.8, 0.7, "srv-mgmt", "Ansible / Zabbix", "#edc948", fontsize=8)

fleche(ax, 2.5, 3.25, 2.5, 2.55, color="#aaaaaa")
fleche(ax, 6.5, 3.25, 5.5, 2.55, color="#aaaaaa")
fleche(ax, 6.5, 3.25, 7.5, 2.55, color="#aaaaaa")
fleche(ax, 10.5, 3.25, 10.5, 2.55, color="#aaaaaa")

# Légende VLANs
for i, (label, color) in enumerate([
    ("DMZ", "#e15759"), ("Production", "#59a14f"), ("Management", "#4e79a7")
]):
    ax.add_patch(plt.Rectangle((0.3 + i * 3.5, 0.3), 0.35, 0.35,
                                facecolor=color + "55", edgecolor=color, linewidth=1.5))
    ax.text(0.8 + i * 3.5, 0.48, label, fontsize=8.5, va="center")

ax.set_title("Architecture réseau Linux multi-VLAN — vue logique",
             fontsize=13, fontweight="bold", pad=14)
plt.show()
_images/afc90f96a5d7399a7f50c5768cf870682b38de6f64b5c9c2f55ca2048d5ade7d.png

Résumé#

La configuration réseau sous Linux repose sur deux niveaux : les outils noyau exposés via la suite iproute2 (ip link, ip addr, ip route, ip rule) et les gestionnaires de haut niveau (NetworkManager, Netplan) qui persistent la configuration au redémarrage.

Points essentiels à retenir :

  • iproute2 est l’ensemble d’outils canonique : ip remplace ifconfig, route, arp. Les modifications sont immédiates mais non persistantes.

  • NetworkManager est adapté aux environnements dynamiques ; nmcli permet une gestion complète en ligne de commande.

  • Netplan (Ubuntu) abstrait le backend et simplifie la configuration déclarative en YAML.

  • systemd-resolved centralise la résolution DNS avec cache, DNSSEC et routage par interface.

  • Le module Python ipaddress permet de manipuler des réseaux IP avec précision, sans dépendance externe.

  • Le bonding et les VLANs sont des fonctionnalités noyau accessibles directement via ip link, indépendamment du gestionnaire de haut niveau.

  • Pour le diagnostic, ss (sockets), tcpdump (capture), mtr (routage) et resolvectl (DNS) couvrent l’essentiel des situations.

La maîtrise de la pile réseau Linux est un prérequis pour les chapitres suivants sur le filtrage (pare-feu), les services réseau (Nginx, DNS, NFS) et la sécurisation des accès (SSH, VPN).