Le risque de fuite de données lors de l'interrogation périodique des routes

Sur les routeurs multi-WAN à haute disponibilité et les passerelles VPN professionnelles, la stabilité du réseau dépend directement de la rapidité de détection des changements d'état physique. Lorsqu'une liaison montante par fibre optique subit une rupture, qu'un modem cellulaire perd sa porteuse ou qu'un bail DHCP expire, la table de transfert du noyau Linux (Forwarding Information Base, ou FIB) entre dans une phase transitoire critique.

Historiquement, de nombreux scripts d'orchestration utilisaient une scrutation périodique (polling) : invoquer la commande ip route show toutes les 2 à 5 secondes via des sous-processus, analyser le texte produit ou émettre des requêtes ICMP répétées. Cette méthode introduit des failles majeures dans les environnements VPN sécurisés :

  1. La fenêtre d'exposition en clair : Durant les secondes de battement entre la coupure physique et la vérification suivante, les applications continuent d'émettre des paquets. Si la route par défaut du VPN disparaît ou bascule sur une interface secondaire non protégée, des données non chiffrées s'échappent directement sur le réseau public.
  2. Surcharge de changement de contexte : Créer continuellement des processus shell pour analyser des flux textuels mobilise d'importantes ressources processeur, provoquant des variations de latence en période de forte charge.
  3. Conditions de concurrence en cas de micro-coupures : Si une interface subit des oscillations rapides (flapping), le mécanisme d'interrogation applique des modifications avec un temps de retard, générant des boucles de routage et l'interruption des tunnels.

Pour obtenir une réaction instantanée sans la moindre fuite de données, les passerelles VPN modernes communiquent directement avec le bus d'événements asynchrone du noyau Linux : RTNetlink (NETLINK_ROUTE).

Netlink est un mécanisme de communication inter-processus (IPC) spécifique à Linux, conçu pour échanger l'état du réseau entre l'espace noyau et l'espace utilisateur via les primitives standards des sockets BSD (AF_NETLINK). Contrairement aux appels ioctl ou aux systèmes de fichiers virtuels, Netlink gère la diffusion multidiffusion (multicast) d'événements en temps réel.

Le protocole dédié au routage, RTNetlink, gère les tables de routage, les états de liaison des cartes physiques, les adresses IP, les tables de voisinage (ARP/NDP) et les règles de mise en file d'attente (qdisc).

+-------------------------------------------------------------------+
|                     Démon VPN en espace utilisateur               |
|    - Boucle d'événements (epoll / kqueue)                         |
|    - Analyseur RTNetlink et machine à états                       |
+-------------------------------------------------------------------+
                  ^                                    |
     Flux d'événements| Groupes multicast     Commandes| Modifications
     asynchrones      | (RTMGRP_LINK,         synchrones| atomiques
     (RTM_NEWLINK,    |  RTMGRP_IPV4_ROUTE)             | (NLM_F_REPLACE,
      RTM_NEWROUTE)   |                                 |  RTM_NEWROUTE)
                      |                                 v
+-------------------------------------------------------------------+
|                     Cœur Netlink du noyau Linux                   |
|                    (AF_NETLINK / NETLINK_ROUTE)                   |
+-------------------------------------------------------------------+
        ^                                            |
        | Notifications d'état                       | Mises à jour FIB
        |                                            v
+---------------------------+        +------------------------------+
| Événements physiques NIC  |        | Table de transfert du noyau  |
| (carrier on/off, netif_*) |        | (FIB IPv4 / IPv6, ip rules)  |
+---------------------------+        +------------------------------+

Groupes multicast essentiels pour la surveillance réseau

Afin de recevoir les alertes instantanément sans boucle de scrutation, le démon VPN ouvre un socket Netlink brut et souscrit aux groupes appropriés :

struct sockaddr_nl sa;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;

int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
bind(fd, (struct sockaddr *)&sa, sizeof(sa));

Les messages surveillés en priorité sont :

  • RTM_NEWLINK / RTM_DELLINK : Émis dès qu'une interface change d'état administratif (IFF_UP), perd ou retrouve sa porteuse physique (IFF_RUNNING / IFLA_CARRIER), ou modifie son MTU.
  • RTM_NEWADDR / RTM_DELADDR : Déclenchés lors de l'attribution ou de la révocation d'une adresse IP par DHCP, SLAAC ou configuration manuelle.
  • RTM_NEWROUTE / RTM_DELROUTE : Diffusés à chaque fois qu'une entrée de la table FIB est créée, modifiée ou supprimée.

Lorsque le noyau notifie un changement, les informations parviennent sous forme de structures nlmsghdr séquentielles dans le tampon de réception du socket. Chaque message comprend un en-tête suivi d'attributs de routage (RtAttr) :

+-------------------------+-------------------------+------------------------+
|  nlmsghdr (16 octets)   |   rtmsg (12 octets)     |  Attributs rtattr...   |
|  - nlmsg_len            |   - rtm_family          |  - RTA_DST             |
|  - nlmsg_type           |   - rtm_table           |  - RTA_GATEWAY         |
|  - nlmsg_flags          |   - rtm_protocol        |  - RTA_OIF (Interface) |
|  - nlmsg_seq / pid      |   - rtm_scope           |  - RTA_PRIORITY        |
+-------------------------+-------------------------+------------------------+

Lecture sécurisée via les macros POSIX

Les macros standards du noyau (NLMSG_OK, NLMSG_NEXT, RTA_OK, RTA_NEXT) parcourent le flux de données en prévenant tout dépassement de tampon :

char buffer[8192];
ssize_t len = recv(fd, buffer, sizeof(buffer), 0);

for (struct nlmsghdr *nh = (struct nlmsghdr *)buffer; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
    if (nh->nlmsg_type == NLMSG_DONE) break;
    if (nh->nlmsg_type == NLMSG_ERROR) { /* Traitement d'erreur */ continue; }

    if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE) {
        struct rtmsg *rt = (struct rtmsg *)NLMSG_DATA(nh);
        struct rtattr *rta = (struct rtattr *)RTM_RTA(rt);
        int rta_len = RTM_PAYLOAD(nh);

        for (; RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) {
            if (rta->rta_type == RTA_GATEWAY) {
                // Adresse IP de la passerelle
            } else if (rta->rta_type == RTA_OIF) {
                int ifindex = *(int *)RTA_DATA(rta);
                // Indice numérique de l'interface de sortie
            }
        }
    }
}

Prévention des débordements de tampon (ENOBUFS)

Lors de perturbations importantes du réseau (par exemple lors de retraits massifs de routes BGP), le noyau peut émettre des milliers de messages en quelques millisecondes. Si le processus applicatif est momentanément suspendu par l'ordonnanceur, le tampon du socket se sature, entraînant la perte de messages et le retour de l'erreur -ENOBUFS.

Un démon robuste met en œuvre une double protection :

  1. Agrandissement du tampon de socket : Activer SO_RCVBUFFORCE (avec le privilège CAP_NET_ADMIN) pour porter le tampon de réception à 16 ou 32 Mo :
    int rcvbuf = 16 * 1024 * 1024;
    setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof(rcvbuf));
    
  2. Resynchronisation complète avec NLM_F_DUMP : En cas d'erreur ENOBUFS, la cohérence incrémentale est rompue. Le démon émet aussitôt une requête de vidage global (NLM_F_REQUEST | NLM_F_DUMP) avec RTM_GETROUTE afin de reconstruire l'état complet de la FIB en mémoire vive sans interrompre les tunnels existants.

Conception d'un basculement Multi-WAN hermétique sans fuite

Pour s'assurer qu'aucun flux ne puisse circuler en clair lors des transitions de lien, la permutation des routes doit être atomique et adossée à des tables de routage politiques (ip rule).

[ Trafic applicatif sortant ]
               |
               v
+-------------------------------------------------------------+
| Règles de routage par politique (ip rule) :                 |
| - Paquets chiffrés du tunnel (fwmark 0x51820) -> Table 'main'|
| - Tout autre flux standard                     -> Table 'vpn'|
+-------------------------------------------------------------+
                               |
               +---------------+---------------+
               |                               |
               v                               v
+-------------------------------+   +-------------------------+
| Table dédiée 'vpn' :          |   | Table système 'main' :  |
| - default dev wg0 métrique 50 |   | - default via WAN 1     |
| - default blackhole métr. 999 |   |   (eth0, 192.168.1.1)   |
+-------------------------------+   | - default via WAN 2     |
                                    |   (eth1, 10.0.0.1)      |
                                    +-------------------------+

1. La route sentinelle blackhole

Avant même l'établissement de la session, le démon installe une route de type blackhole avec une métrique basse dans la table dédiée au VPN :

# Ajouter une route de sécurité blackhole dans la table vpn
ip route add blackhole default table vpn metric 999

Si l'interface VPN principale (wg0 ou riceguard0) s'arrête brutalement, le noyau achemine immédiatement les paquets suivants vers cette route d'absorption, les détruisant instantanément sans coût CPU, écartant ainsi tout risque d'exposition sur l'interface physique externe.

2. Remplacement atomique via NLM_F_REPLACE

Plutôt que d'exécuter une suppression suivie d'un ajout (créant un vide dangereux de quelques millisecondes), RTNetlink permet une substitution atomique en un appel système unique. En transmettant le message RTM_NEWROUTE avec les drapeaux NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, le noyau modifie le pointeur de passerelle au cœur de la FIB. Aucun paquet en transit ne subit d'interruption.

3. Gestion dynamique multi-voies dans RiceGuard

Dans les déploiements d'entreprise équipés de RiceGuard exploitant deux connexions physiques simultanées, le démon surveille les signaux de porteuse RTNetlink pour assurer un basculement transparent.

Lorsque RTM_NEWLINK signale la perte de liaison sur la fibre (IFLA_CARRIER passant à 0), le démon RiceGuard réassocie les sockets UDP de transport vers la liaison cellulaire de secours via SO_BINDTOIFINDEX en moins de 4 millisecondes. Étant donné que les sessions clientes sont gérées au niveau de la couche virtuelle, les communications TCP et les appels vocaux se poursuivent sans coupure.

Les administrateurs peuvent observer directement les événements du noyau en temps réel :

# Surveiller en direct l'ensemble des liaisons, adresses et routes
ip monitor all

# Surveiller spécifiquement les évolutions de routes avec horodatage
ip -ts monitor route

# Vérifier l'état des files d'attente Netlink et les paquets écartés
ss -u -a --netlink
cat /proc/net/netlink

Dans la sortie de /proc/net/netlink, observez la colonne Drops relative au protocole NETLINK_ROUTE (protocole 0). Un nombre supérieur à zéro signale que l'application ne traite pas les messages assez rapidement, nécessitant l'ajustement du tampon de réception.

Bonnes pratiques pour le déploiement

  • Séparer les sockets de commande et d'événements : Utiliser un socket dédié exclusivement à la réception des notifications multicast et un autre pour les requêtes d'administration afin d'éviter tout blocage de flux.
  • Utiliser les identifiants numériques d'interface : Toujours suivre les interfaces réseau par leur numéro d'index immuable (ifindex) plutôt que par leur nom textuel (eth0), écartant tout risque de conflit lors d'un renommage matériel.
  • Maintenir des tables de routage politiques isolées : Ne jamais insérer la route VPN par défaut directement dans la table main partagée avec les interfaces physiques.

L'adoption de l'architecture événementielle de RTNetlink permet aux passerelles VPN sous Linux d'offrir une réactivité instantanée face aux aléas réseau tout en garantissant une imperméabilité totale des données transmises.