C'est un problème aussi vieux qu'Internet. Vous souhaitez accéder à votre ordinateur à distance, mais il se trouve derrière un routeur qui obtient au hasard différentes adresses IP. Ou peut-être que c'est votre ordinateur portable et qu'il se retrouve à différents endroits avec, encore une fois, des adresses IP différentes. Il existe de nombreuses façons de résoudre ce problème et certaines d'entre elles sont meilleures que d'autres.

De nombreux routeurs peuvent signaler leur adresse IP à un serveur DNS dynamique. C'était génial, mais maintenant, il semble que beaucoup d'entre eux vous demandent de mettre à niveau ou de renouveler constamment afin que vous puissiez voir leurs publicités. Certains d'entre eux disparaissent également. Si votre fournisseur de routeur en fournit un, cela pourrait être un bon choix, jusqu'à ce que vous changiez de routeur, bien sûr. OpenWRT prend en charge de nombreux services de ce type et il existe de nombreuses listes de services communs.

Cependant, si vous disposez d'un seul ordinateur accessible au public, par exemple un serveur Web ou même une instance cloud, et que vous exécutez votre propre serveur DNS, vous n'avez vraiment pas besoin de l'un de ces services. Je vais vous montrer comment je le fais avec un serveur Linux accessible fonctionnant Bind. Il s'agit d'une configuration courante, mais si vous avez un système différent, vous devrez peut-être vous adapter un peu.

Il existe de nombreuses façons de configurer un DNS dynamique si vous êtes prêt à avoir une grande structure des deux côtés. La plupart d'entre eux dépendent de la configuration d'une clé secrète pour permettre les mises à jour DNS et d'une sorte de script qui appelle nsupdate ou demander au serveur DHCP de le faire. Le problème est que j'ai beaucoup d'ordinateurs clients et beaucoup sont configurés différemment. Je voulais un système où la seule chose nécessaire du côté client était ssh. Toute l'infrastructure reste sur le serveur DNS.

Contexte

Je vais supposer que vous avez déjà Bind configuration et vous avez une connaissance pratique de ce que fait DNS. En général, cependant, vous aurez un seul fichier pour chaque domaine – zone dans DNS Speak – que vous contrôlez. Voici un fichier de zone typique (la RFC 1035 contrôle le format):

; zone file for wd5gnr.com
$TTL 3600 ; default TTL for zone
$ORIGIN wd5gnr.com.
@ 3600 IN SOA ns1.wd5gnr.com. alw.al-williams.com. (
12040320 ; serial number
3m ; refresh
180 ; retry
1209600 ; expire
3m ; negative
)
@ IN A 158.69.212.64
@ IN NS ns1
@ IN NS ns2
ns1 IN A 158.69.212.64
ns2 IN A 158.69.212.64
@ IN MX 10 mail
www IN A 158.69.212.64

Les parties d'intérêt ici sont les $TTL ou le temps de vivre. La valeur est en secondes, c'est donc une heure. Cela peut être un peu long à attendre si votre adresse IP change beaucoup. Les serveurs utilisent également un numéro de série pour indiquer que l’enregistrement a changé. Il n’existe pas de format réel pour le nombre tant que chaque modification entraîne un nombre plus important. Vous pouvez utiliser un compteur de séquence ou permuter la date. Cela n’a pas vraiment d’importance. Enfin, il existe des enregistrements IN qui nous indiquent différentes adresses IP. Pour ce fichier, @ est un raccourci pour wd5gnr.com et tout ce qui n'a pas de période à la fin aura wd5gnr.com y est annexé. Ainsi, la dernière ligne définit un hôte «www.wd5gnr.com» et aurait pu être écrite avec «www.wd5gnr.com». au lieu de «www» – cette dernière période fait toute la différence.

D'une manière ou d'une autre, nous avons besoin d'un moyen de créer plus d'enregistrements dans ce fichier de zone qui pointeront vers d'autres hôtes – peut-être dyn.wd5gnr.com – à une adresse IP différente. J'ai commencé avec un script très simple sur le serveur DNS qui trouverait l'adresse IP de l'appelant et modifierait un modèle pour créer un fichier de zone DNS, puis rechargerait la zone. Cela a fonctionné jusqu'à ce que je veuille gérer plus d'un hôte dynamique à la fois. Je vais vous montrer comment j'ai géré cela, mais d'abord, parlons de ce dont vous avez besoin pour le faire vous-même.

Ce dont vous aurez besoin

En plus du serveur DNS pour un domaine que vous contrôlez, vous aurez également besoin d'un accès ssh à votre serveur configuré pour utiliser un certificat et non un mot de passe. Vous avez probablement également besoin d'un accès root, même si je vais vous montrer comment vous n'en aurez pas besoin après la configuration, si cela ne vous dérange pas de permettre à quiconque connecté à votre compte de mettre à jour votre adresse IP.

Mise en place ssh ne pas exiger de mot de passe est facile et fortement recommandé. Si vous avez besoin d'une introduction à la configuration Bind, vous pouvez lire cet article, tant que vous vous souvenez d'utiliser votre gestionnaire de paquets à la place de yum – sauf si votre gestionnaire de paquets est yum! Ou vous pourriez préférer celui-ci.

Le plan

Une fois que vous avez configuré votre serveur DNS et ssh session, il n'y a que quelques éléments à configurer.

  1. Un script à exécuter à distance en utilisant ssh.
  2. Un modèle qui définit votre fichier de zone DNS (mais n'est pas votre fichier de zone DNS).
  3. Un moyen de déclencher le script depuis votre machine locale.
  4. Un moyen de recharger le serveur DNS.

Le script, bien sûr, est un script Bash mais il fait bon usage d'Awk. Mon format de fichier de modèle d'origine était simple. J'ai fait une copie du fichier de zone, remplacez le numéro de série par $SERIAL et l'adresse IP dynamique avec $IP. Le script brancherait de nouvelles valeurs et rechargerait le serveur DNS à l'aide d'un programme de contrôle appelé rndc, plus dans une minute.

Quelques Gotchas

Le plus gros problème avec ce schéma est qu'il n'y a qu'une seule adresse IP dynamique autorisée. Mais avant de résoudre ce problème, examinons certains des problèmes. Tout d'abord, nous devons connaître l'adresse distante de l'ordinateur appelant le script. Voici un code:

echo "$SSH_CLIENT" | cut -d ' ' -f 1

Ceci, bien sûr, suppose que nous sommes connectés via ssh. J'ai pris quelques raccourcis car je ne m'attendais pas à appeler ce script manuellement sauf pendant les tests. Les arguments étaient simples, même si je devrais plus tard en ajouter un peu plus. Le premier script a pris une adresse IP ou un tiret pour indiquer mon ssh Adresse IP, un nom de zone et c'était tout.

Le script chercherait ${ZONENAME}.dns.template dans le répertoire courant et utilisez un simple awk script pour gsub toute occurrence de $SERIAL et $IP dans le modèle. Awk écrirait dans un fichier temporaire et une fois réussi, je déplacerais le fichier vers le fichier DNS (encore une fois, dans le même répertoire) et effectuerais la mise à jour du serveur.

Ce dernier élément est également un peu délicat. Bind a un outil, rndc, qui peut recharger une zone (entre autres). Mais normalement, vous devez être root pour l'exécuter. Vous pouvez utiliser sudo, bien sûr, mais pour un script automatisé, ce n’est pas pratique car il voudra votre mot de passe.

Modifier les SUDOERS

Il s'avère que sudo a de nombreuses fonctionnalités que vous n'utilisez pas souvent. L'un d'eux permettra aux utilisateurs ou groupes d'utilisateurs d'exécuter des choses sans mot de passe, même si cela nécessiterait normalement root. De toute évidence, vous devez être très prudent avec cette capacité. J'ai créé un fichier appelé /etc/sudoers.d/91-dynamicdns sur le serveur DNS qui contient une seule ligne:

myuserid    ALL=(root) NOPASSWD:   /usr/sbin/rndc reload wd5gnr.com

Cela me permet de recharger ce fichier de zone en tant qu'utilisateur normal sans entrer de mot de passe en utilisant sudo. Si vous essayez de faire autre chose, vous obtiendrez toujours le sudo invite de mot de passe.

XKCD par (Randall Munroe) CC By_NC 2.5

Appel du script

Il ne reste plus qu'à appeler le script sur la machine locale en utilisant ssh. Vous avez plusieurs options. Bien sûr, l'exécuter manuellement est assez facile, mais j'ai utilisé cron ou anacron pour planifier l'exécution du script périodiquement et à peu près en synchronisation avec la valeur TTL. Vous pourriez utiliser systemd, si tu préfères. Sur un ordinateur portable utilisant NetworkManager, il serait possible d'écrire un script qui s'exécute lorsque la connexion réseau se connecte, ce qui conviendrait probablement.

La manière exacte dont vous le faites dépendra de votre configuration. Gardez à l'esprit que même une fois le WiFi connecté, le routeur peut obtenir une nouvelle adresse IP WAN à tout moment.Une sorte de mise à jour périodique est donc probablement une bonne idée, même si vous souhaitez forcer une mise à jour sur la connexion réseau ou la connexion.

Plusieurs hôtes

Tout cela a bien fonctionné pendant un certain temps, mais j'ai finalement voulu autoriser plusieurs lignes. Le problème est que chaque mise à jour est déconnectée du reste. D'une manière ou d'une autre, vous souhaitez que le modèle n'affecte que les lignes spécifiques à modifier. Je voulais aussi vérifier l'adresse IP et ne recharger que dans le cas où la nouvelle adresse IP était différente.

Il existe bien sûr de nombreuses solutions à ce problème. Il serait même possible de stocker les adresses IP dans une base de données ou un fichier et d'effectuer toutes les mises à jour à chaque fois. Mais cela m'a paru pénible, alors j'ai opté pour quelque chose de plus facile. Le fichier de modèle copiera désormais toute ligne sans préfixe à droite de la sortie inchangée. Mais certaines lignes auront un préfixe qui est du texte suivi de deux points. Lorsque le script trouve une telle ligne, il cherche à voir si le préfixe est celui avec lequel nous travaillons. Si tel est le cas, il remplace $SERIAL et $IP comme avant. Il supprime le préfixe et cache temporairement la ligne. Il y a un préfixe spécial, !, qui correspond à n'importe quel préfixe. C’est principalement pour permettre $SERIAL à utiliser dans une ligne qui change à chaque mise à jour.

Avec ce nouveau schéma, aucune sortie ne se produit lorsque le script traite le modèle. Cependant, le script prend désormais deux arguments: le modèle et le fichier de zone existant. Le traitement du deuxième fichier est différent. Il copie simplement chaque ligne du fichier de zone dans un nouveau fichier, sauf s'il y avait une ligne de remplacement à partir du premier passage. Si tel est le cas, cette ligne remplace l'ancienne. Vous pouvez déterminer quelle passe awk est en regardant ARGIND qui vous indique le fichier que vous traitez actuellement.

Le seul gros problème, alors, est si vous avez essayé d'exécuter le script deux fois en même temps. La réponse à ce problème est d'utiliser flock, une technique couverte dans un précédent Linux-Fu.

Vous pouvez trouver l'intégralité du script final sur GitHub avec un exemple de fichier de modèle. Notez que tout fonctionne sur le serveur. Vous exécutez simplement le script via ssh – et cela peut être fait automatiquement de plusieurs manières – et le code côté serveur s'occupe du reste. Puisque vous avez probablement besoin ssh mis en place de toute façon, cela signifie qu'il n'y a aucune clé supplémentaire à maintenir et aucune mise à jour de chaque client chaque fois que vous souhaitez modifier quoi que ce soit.

Autres méthodes

Comme d'habitude, il existe de nombreuses façons de résoudre ce problème. Cela peut ou non répondre à vos besoins. J'ai envisagé d'écrire simplement le modèle en utilisant $INCLUDE pour inclure un fichier de sous-zone pour chaque hôte dynamique et demander au script de les écrire. Cela fonctionnera probablement, mais si vous aviez beaucoup d'hôtes, cela se retrouverait avec beaucoup de fichiers errants. Il y a aussi une certaine ambiguïté dans la RFC 1035 quant au comportement correct de $INCLUDE bien que la documentation de Bind le clarifie, au moins en ce qui concerne Bind.

Il montre encore quelques trucs intéressants avec awk et flock, bien que. Il existe d'autres moyens de trouver vos serveurs distants, tels que PageKite. Enfin, vous pouvez lancer du matériel sur le problème.

LAISSER UN COMMENTAIRE

Rédigez votre commentaire !
Entrez votre nom ici