Le « File exists » d’OpenVPN sur une route n’est pas un problème de fichier
Le message vient de la table de routage du noyau, pas du système de fichiers. Lisez l’entrée qui possède déjà le préfixe avant de modifier la politique du LAN.
Commencez là où le message apparaît. Un client se connecte, le tunnel monte, puis le journal indique que la commande d’ajout de route de Linux a échoué avec File exists. Rien dans cette phrase ne renvoie à un certificat, une clé ou un fichier de configuration, même si les mots le suggèrent. Le noyau décrit sa table de routage, et le préfixe que vous avez demandé d’installer possède déjà une entrée.
Suivez la séquence du client lui-même : ce qu’il a demandé, ce que la table contenait déjà, qui a placé cette entrée là, et seulement ensuite ce qu’il faut changer. Chaque étape élimine un propriétaire possible.
Ce que le client demandait réellement
Avant l’échec, le client journalise la route qu’il compte ajouter, généralement comme destination, masque de réseau, passerelle et parfois comme métrique ou table. Cette ligne est la demande. L’erreur qui suit est la réponse du noyau, et les deux se lisent côte à côte.
journalctl -u openvpn-client@office -b --no-pager | grep -nE 'route|File exists'
openvpn --config /etc/openvpn/client/office.ovpn --verb 4 --log /tmp/ovpn.log
Un code de sortie non nul de l’assistant de routes est moins informatif que le texte en dessous, car différentes réponses du noyau produisent un code non nul. Conservez le message exact ; la distinction entre une entrée existante et une passerelle injoignable décide laquelle des sections suivantes s’applique.
Lisez la route existante, pas seulement l’adresse
Chercher dans la table le même quadruple pointé ne suffit pas. Un objet route est identifié par sa famille d’adresses, sa table, son préfixe de destination, sa métrique, son protocole et son périphérique de sortie, et des entrées qui partagent un préfixe peuvent légitimement coexister lorsque ces attributs diffèrent. Ce qui entre en collision, c’est l’objet entier, pas le texte.
ip -4 route show table all | grep -F '10.40.'
ip -4 route show match 10.40.0.0/16
ip -4 route get 10.40.0.5
La dernière commande répond à une question différente des deux premières : non pas ce qui existe, mais quelle entrée le noyau choisirait pour cette destination en ce moment. Les deux vues sont utiles, et elles divergent assez souvent pour mériter une comparaison avant de conclure quoi que ce soit. Le désaccord entre elles est le cas intéressant, pas une erreur d’arrondi.
Notez le préfixe, la table, la métrique et le périphérique à côté de la demande échouée. Si l’entrée existante a les mêmes attributs et le même saut suivant, vous avez une instruction en double et non un problème de routage.
Quatre propriétaires qu’un préfixe peut avoir
Les routes connectées proviennent d’une adresse attribuée et sont recréées par le système chaque fois que cette adresse existe. Un client DHCP ou un gestionnaire de connexions installe des routes dans le cadre de son propre cycle de vie. Un autre client VPN porte peut-être déjà le même préfixe. Et un hook ou un script local peut en ajouter une que rien d’autre ne connaît.
Chaque propriétaire demande une correction différente. Une route connectée n’est pas à vous de supprimer ; la retirer peut casser l’accès local avant que le tunnel ne soit utilisable, et le noyau la remettra. Une route détenue par un gestionnaire doit être modifiée via ce gestionnaire, pas avec un ip route del manuel que la prochaine reconnexion annule.
Une interface conservée rend la même confusion plus facile. Quand le périphérique tunnel survit à une reconnexion, des routes installées par du code de configuration personnalisé peuvent encore être présentes au second passage, si bien qu’un script qui suppose un état propre échoue la seconde fois et fonctionne la première. Soit vous effacez délibérément l’entrée obsolète, soit vous rendez le code de configuration idempotent.
block-local répond à une autre question
Quand un profil envoie tout le trafic par le tunnel, le client doit décider de ce qui arrive au réseau local. L’indicateur block-local change cette décision en routant le LAN local par le tunnel tout en conservant l’exception documentée pour la passerelle du LAN ; c’est un choix de politique de trafic aux conséquences visibles sur l’accessibilité.
Il n’explique pas pourquoi l’ajout d’une route a renvoyé une erreur d’entrée existante, et l’adopter comme réparation universelle cache le conflit réel derrière un changement de politique. Si vos ressources locales deviennent inaccessibles après une modification de profil, cet indicateur est l’une des premières choses à inspecter ; si l’ajout d’une route échoue, ce n’est pas la réponse.
Traitez-le comme une décision sur les destinations qui restent locales, prise délibérément et consignée. Ce n’est pas un interrupteur à essayer quand le journal semble alarmant.
Bouclez la boucle : supprimez le doublon à sa source
Une fois que vous savez quel propriétaire détient l’entrée, supprimez l’instruction en double là où elle est définie. Cela peut être une ligne route dans le profil, un push du serveur ou un hook qui n’a plus besoin de s’exécuter.
ip -4 route show match 10.40.0.0/16
ip -4 route get 10.40.0.5
journalctl -u openvpn-client@office -b --no-pager | tail -n 15
Reconnectez-vous ensuite et confirmez trois choses : le tunnel monte, la destination voulue se résout vers le chemin souhaité, et l’échec a disparu sans qu’un nouveau n’apparaisse à sa place. Un journal propre avec un chemin mal choisi n’est pas une correction.
Si le préfixe désigne le LAN local d’un côté et un réseau distant de l’autre, le problème est un chevauchement d’adresses et non un doublon, et aucune suppression ne rendra les deux significations vraies en même temps. Ce cas demande un autre plan pour l’un des deux réseaux. Décidez quel côté sera renuméroté avant de toucher à l’un ou l’autre.