Article · 3 septembre 2026 · 6 min de lecture

Debug Detective : la règle fantôme

Le décor était planté : Apache aurait dû écouter sur le port 3002, mais depuis mon serveur de rebond l'application était bel et bien morte. Chaque curl revenait vide. La machine répondait, le service restait introuvable.

Didi, une grenouille en trench et chapeau mou, examine a la loupe une porte parmi une rangee de portes identiques dans un couloir sombre, Sudo la mouche a son epaule.
systemctl status httpd montrant le service en échec, avec AH00072 address already in use sur le port 3002.
En échec, et la ligne de log qui ouvre l'enquête. Quelque chose a pris le 3002 avant Apache.

La scène

Je me suis connecté en ssh sur la machine suspecte. Premier réflexe, vérifier le service : failed. Apache ne tournait pas du tout.

Les logs m'ont donné le premier indice : address already in use: AH00072. Quelqu'un d'autre avait déjà pris le contrôle du port 3002. J'ai donc demandé qui.

netstat -tulpen lancé avec sudo, montrant 127.0.0.1:3002 occupé par le PID 452, sendmail.
Le voilà. sendmail, PID 452, installé sur 127.0.0.1:3002.

Le suspect

sendmail. Un service auquel je ne pensais pas, sur un port dont j'avais besoin, lié uniquement à la boucle locale, ce qui explique exactement pourquoi Apache n'a pas pu prendre 0.0.0.0:3002 et a renoncé.

Au passage j'ai appris quelque chose qui vaut plus que la réponse. Lancez la même commande sans mon acolyte Sudo et la colonne PID reste vide :

La même commande netstat sans sudo. La colonne PID est vide et un avertissement indique qu'il faut être root.
Mêmes ports, mêmes inodes, aucun nom. Sans Sudo, le voleur se cache à la vue de tous. Heureusement que je ne l'ai pas mangée.

J'ai mis fin à la carrière de l'imposteur d'une seule balle en plein cœur :

kill 452
#!Bang!

Un peu de massage cardiaque et mon ami Apache est revenu, enfin capable de reprendre la place qui lui revenait sur le port 3002.

systemctl status httpd montrant le service actif et en cours d'exécution, à l'écoute sur le port 3002.
Actif, en marche, à l'écoute sur le 3002. Affaire classée, forcément.

Un curl depuis localhost atteignait le port 3002 sans problème. L'affaire était-elle si simple ?

No route to host

Je suis retourné au bureau et j'ai relancé un curl depuis le serveur de rebond pour vérifier que le travail était fait, mais... No route to host. Étrange. Faisons un ping.

curl qui échoue avec No route to host, suivi d'un ping réussi avec cinq paquets et aucune perte.
Le curl refusé, le ping passe sans broncher. Cinq paquets, zéro perte.

Curieux. Le serveur répondait aux pings. Le chemin était ouvert. Le blocage venait donc d'ailleurs. Ce ne pouvait être qu'au niveau du pare-feu.

La fausse piste

Je suis retourné sur les lieux examiner iptables, et tout semblait normal.

Sortie de iptables -L. La règle 3 accepte tout le trafic de partout vers partout, au-dessus d'une règle REJECT.
La règle 3 accepte tout, de partout vers partout, et elle passe avant le REJECT. À la lecture, mon curl aurait dû passer tranquillement.

La troisième règle laissait passer tout le trafic, et elle se trouvait plus haut que le reject en bas de chaîne, donc le curl aurait dû fonctionner. La seule chose bizarre de tout l'écran était un petit avertissement tout en bas, à propos de tables legacy présentes.

Alors je l'ai suivi. J'ai cherché, cherché pendant des heures, à retrouver ces fameuses tables legacy, et elles n'étaient nulle part. Après une longue réflexion, j'ai décidé qu'il valait mieux prendre du recul et réanalyser la situation objectivement, sans m'engager davantage sur cette voie.

C'est la partie de cette affaire qu'il faut garder. L'indice était réel, il était imprimé à l'écran par l'outil lui-même, et il n'avait rien à voir avec mon problème. Un indice que l'on voit n'est pas un indice qui compte.

La révélation

C'est là que ça m'est revenu. Je me suis souvenu qu'il y a longtemps un collègue avait résolu une affaire similaire avec un petit assistant. Ajouter -v.

Sortie de iptables -L -v. La colonne in apparaît et la règle 3 ne s'applique qu'à l'interface lo.
La colonne in apparaît. La règle 3 n'acceptait pas tout venant de partout. Elle acceptait tout ce qui arrivait sur lo.

Le voilà. -L seul n'affiche pas les colonnes d'interface. -L -v si. La règle 3 ne laissait pas tout passer : elle laissait tout passer sur l'interface de boucle locale.

Mes paquets frappaient à la mauvaise porte, et iptables haussait les épaules.

C'est aussi pour cela qu'un curl depuis localhost fonctionnait et qu'un curl depuis le bureau échouait. Les compteurs de paquets le disent à voix haute : la règle 3 avait vu passer un seul paquet, et le reject en bas de chaîne en avait vu trois. Ces trois-là étaient les miens.

Une règle, et la porte s'est ouverte :

sudo iptables -I INPUT -p tcp -s didi_office -d 172.16.238.10 --dport 3002 -j ACCEPT
Le fantôme n'est pas ce qui manque. C'est ce que vous n'avez pas affiché.

Note du détective

Deux suspects, une seule affaire. Un processus auquel je ne pensais pas, et une règle qui disait une chose dans le résumé et une autre dans le détail. Aucun des deux ne se cachait. Je ne leur posais simplement pas la bonne question.

Une plateforme qui refuse de s'expliquer ?

La plupart des pannes cessent d'être mystérieuses dès que la bonne colonne est affichée. Si vous voulez un deuxième regard sur l'une d'elles, écrivez-moi.

Contactez-nous