Mettre à jour le fichier hosts selon le réseau
Faute d’écrire sur les lectures récentes, je vais partager mes divagations geek du moment. Aujourd’hui, c’est une histoire de flemme. Et comme souvent, c’est par ce biais que j’apprends des choses.
Le problème
Pour commencer, un peu de contexte. Pas d’inquiétude, on va rester simple.
J’héberge quelques services web à domicile. Ils sont accessibles via une adresse IP locale. Si je créer un signet dans mon navigateur préféré (Firerox, what else ?), ce signet ne fonctionne que chez moi. Par exemple : http://192.168.0.1
ouvre mon blog.
Mais imaginons que je passe le weekend ailleurs que chez moi : le signet essayera d’ouvrir une IP locale qui n’existe probablement pas sur le réseau où je suis connecté.
J’ai également un nom de domaine : grishka.fr
. Il me permet de créer des sous-domaines, comme blog.grishka.fr
. Un signet vers https://blog.grishka.fr
ouvrira mon blog, mais uniquement ailleurs que chez moi.
Donc sur mon ordinateur portable, j’ai 2 signets :
- Le premier vers l’adresse IP : il sert à ouvrir le blog depuis mon réseau local, donc quand je suis connecté chez moi.
- Le second vers le domaine : il sert à ouvrir le blog depuis internet, donc quand je suis connecté n’importe où ailleurs.
Et… je trouve idiot d’avoir 2 signets différents pour arriver au même endroit. J’ai donc exploré 2 contournements, on va voir le premier dans cet article.
interlude
Petite pause ici. Cela ne fonctionne pas chez moi car nativement un domaine ne redirige pas vers une adresse locale. Il existe des moyens de faire cela avec un serveur DNS par exemple, mais j’ignore volontairement cette solution ici. J’ai la flemme, certes, mais je me complique parfois la vie malgré tout. Et parce qu’il faut que je comprenne comment ça marche.
Le fichier hosts
Le fichier hosts
existe dans tous les systèmes d’exploitation. Son rôle est d’associer un nom d’hôte (ou nom de domaine) avec une adresse IP. Plus de détails ici pour les curieux. Selon le système, le fichier est placé dans un dossier différent. Sur mon portable, il est ici : /etc/hosts
.
Dans le fichier, je peux ajouter cette ligne par exemple :
192.168.1.2 blog.grishka.fr
Cela indique au système que si j’essaye d’accéder au domaine blog.grishka.fr
, alors il faut ouvrir l’adresse IP 192.168.1.2
. Quand je suis chez moi, cela me permet d’utiliser le nom de domaine comme si j’étais connecté ailleurs. Mais dès que je me connecte à un autre réseau, on retrouve le problème du signet : l’adresse IP visée n’existe pas.
J’ai donc bricolé une solution pour modifier le fichier hosts
automatiquement.
Changer de fichier hosts selon le réseau
L’idée est simple : selon le réseau où je me trouve, je veux mettre à jour le contenu du fichier hosts
pour qu’un nom de domaine pointe soit vers une IP locale, soit vers sa cible habituelle. On va faire ça étape par étape.
I — Préparer les fichiers hosts
Pour commencer, on va créer plusieurs fichiers hosts
qui seront utilisés selon la situation.
Je commence par copier le fichier hosts
existant dans un second fichier nommé hosts.lan
. Dans ce fichier, j’ajoute plusieurs lignes ainsi :
192.168.0.1 blog.grishka.fr
192.168.0.2 exemple.grishka.fr
192.168.0.3 service.grishka.fr
Notez que je peux ajouter autant de ligne que nécessaire. Dans l’exemple, l’IP change car ces services sont hébergés sur différentes machines.
Ensuite, je copie le fichier hosts.lan
dans un troisième fichier nommé hosts.wan
. Dans ce fichier, je vais commenter les lignes que j’ai ajoutées. C’est-à-dire que j’ajoute un #
au début de chaque ligne pour qu’elles soient ignorées. Je pourrais aussi les supprimer, ce serait pareil. Mais je préfère les garder et les désactiver. Dans ce fichier, j’ai donc ceci :
# 192.168.0.1 blog.grishka.fr
# 192.168.0.2 exemple.grishka.fr
# 192.168.0.3 service.grishka.fr
II — Le script
J’ai ensuite écrit un script très simple :
#!/bin/bash
if ping -I tun0 -c2 192.168.0.3 > /dev/null || ping -I wlp2s0 -c2 192.168.0.3 > /dev/null;
then
cp /etc/hosts.lan /etc/hosts
else
cp /etc/hosts.wan /etc/hosts
fi
Il prend la forme d’un test if
:
- Je fais un ping vers l’IP d’un service local (dans l’exemple, c’est celle qui sert
service.grishka.fr
.- Sur mon portable, je peux être connecté par 2 interfaces réseau :
tun0
qui est un VPN etwlp2s0
qui est le Wi-Fi. Je teste donc la connectivité sur les 2. - J’ignore le résultat du ping en dirigeant la sortie vers
/dev/null
et je m’intéresse au fait que la commande soit un succès ou non.
- Sur mon portable, je peux être connecté par 2 interfaces réseau :
- Si la commande est un succès, c’est la condition
then
qui s’applique. Le succès indique que j’arrive à joindre l’IP via l’une ou l’autre des interfaces réseau, donc que je suis d’une façon ou d’une autre connecté à mon réseau local.- Ici je copie le fichier
/etc/hosts.lan
vers le fichier/etc/hosts
: concrètement je remplace le second par le contenu du premier. - Le fichier
hosts
indique maintenant les IPs locales pour chaque sous-domaine.
- Ici je copie le fichier
- Si la commande est un échec, c’est la condition
else
qui s’applique. L’échec confirme que l’IP locale n’est pas joignable, je suis donc connecté ailleurs que chez moi.- Dans ce cas je copie le fichier
/etc/hosts.wan
vers le fichier/etc/hosts
, j’écrase à nouveau son contenu par une autre version. - Dans cette version, les lignes sont commentées avec le
#
, elles sont ignorées.
- Dans ce cas je copie le fichier
Je sauvegarde le code dans un fichier ~/script.sh
.
III — Automatiser la vérification
Le script fonctionne, mais je dois toujours le lancer manuellement pour qu’il fasse effet, ce qui n’est pas très pratique.
Pour rendre ceci automatique, on va réaliser plusieurs étapes.
- Tout d’abord, je transfère la propriété du fichier
script.sh
vers l’utilisateurroot
avec la commandechown root script.sh
. Pourquoi ? Parce que pour pouvoir écraser le fichierhosts
, qui est un fichier protégé du système, il faut des droits spéciaux ; - Ensuite, je rends le script exécutable :
chmod 700 script.sh
; - J’édite alors le fichier cron de l’utilisateur root. Concrètement, ce fichier permet de programmer des actions selon une périodicité ou selon des déclencheurs particuliers. Pour éditer le fichier :
sudo crontab -e
. - La programmation dans un fichier cron répond à une syntaxe particulière que vous pouvez retrouver ici. Je vais donc ajouter une ligne à mon fichier pour que le script soit lancé toutes les 5 minutes, et je sauvegarde.
*/5 * * * * /home/utilisateur/script.sh
Bilan
Lorsque j’allume mon ordinateur portable et que je me connecte à internet, le script est lancé au maximum 5 min plus tard. Il vérifie si l’IP locale d’un service que j’héberge est joignable : selon la réponse, il remplace le fichier hosts
par une version adaptée à la situation.
Je n’ai plus qu’un signet à utiliser, celui avec le nom de domaine blog.grishka.fr
: il ouvrira toujours le site, que ce soit au travers d’internet, ou de mon réseau local.
Bon, c’est assez amusant à mettre en place et en soi c’est une solution simple. Mais il y a quelques limites.
- Tout d’abord, si je me connecte sur un réseau où une machine est accessible sur la même IP que mon service, alors le script va croire à tort que je suis chez moi.
- À l’allumage du PC portable, je peux attendre jusqu’à 5 min pour que le script fonctionne. D’un autre côté, je n’ai pas envie de le lancer toutes les minutes…
- Si j’ai besoin d’autres modifications dans le fichier
hosts
, il faut que je les reproduise dans les 2 versions existantes (LAN et WAN).
Il y a donc une marge d’amélioration que je vais explorer. Et en parallèle je reviens rapidement vous parler d’une autre option, via un simple et unique… signet.