Serveur DHCP natif utilisant bash

J'adore automatiser le processus et écrire mes propres vélos pour étudier tel ou tel matériel. Mon nouvel objectif était un serveur DHCP, qui émettra une adresse dans les petits réseaux afin que la configuration initiale de l'équipement puisse être faite.

Dans cet article, je vais parler un peu du protocole DHCP et de quelques subtilités de bash.



Résultat final


Commençons par la fin, pour que ce soit pourquoi nous nous battons.

Démonstration de travail:



Référentiel avec script: firemoon777 / bash-dhcp-server

Problème initial


La configuration dont j'ai besoin se fait de cette façon: nous nous connectons directement via une paire torsadée à l'équipement, émettons une adresse temporaire via DHCP et la configurons avec un script déjà créé. Et donc dix à vingt fois de suite.

Pour beaucoup, le serveur isc-dhcp bien connu fait parfaitement son travail, mais, hélas, il n'informe pas mon script que l'adresse est émise, vous devez donc en quelque sorte bloquer l'exécution jusqu'à ce que l'adresse soit émise.

La solution, semble-t-il, est en surface: cingler jusqu'à ce que le visage soit bleu, jusqu'à ce que l'équipement réponde:

while ! ping -c1 -W1 "$DHCP" | grep -q "time=" do echo "Waiting for $DHCP..." done 

Mais cette décision manque définitivement d'aventurisme.

Partie théorique


Obtention d'une adresse avec un seul serveur DHCP



Le protocole DHCP fonctionne sur UDP sur les ports 67 et 68. Le serveur ne fonctionne toujours qu'à 67, et le client uniquement à 68. Comme le client n'a pas d'adresse (a l'adresse 0.0.0.0), les paquets DHCP sont diffusés. C'est-à-dire le client envoie toujours des paquets à l'adresse 255.255.255.255:67 à partir de l'adresse 0.0.0.0:68 et le serveur envoie de son adresse: 67 à l'adresse 255.255.255.255:68.

Le client reçoit l' adresse en quatre paquets ( DORA ):

  1. Le client découvre où se trouve le serveur DHCP ( D iscover)
  2. Le serveur répond et propose son adresse (offre)
  3. Le client demande l'adresse proposée à un serveur spécifique ( R equest)
  4. Le serveur accepte et délivre l'adresse ( A ck)

Visuellement, le schéma peut être représenté comme suit:



Obtention d'une adresse avec plusieurs serveurs DHCP



Lorsque le client envoie Discover, tous les serveurs qui peuvent entendre envoient leur offre au client. Mais le client doit en choisir un. La sélection du client est annoncée dans le message de demande avec l'option 54 (serveur DHCP), qui contient l'adresse IP du serveur DHCP préféré. Bien que la demande soit également envoyée à tous les utilisateurs du réseau, seul le serveur DHCP dont l'adresse IP est spécifiée dans l'option 54 répondra.



Contenu du paquet DHCP


Un paquet DHCP se compose de deux parties: une constante de 236 octets et une variable qui contient des options (option DHCP).

Tableau avec tous les champs du paquet DHCP de Wikipedia
Le terrainLa descriptionLongueur (en octets)
op
Type de message. Par exemple, il peut prendre des valeurs: BOOTREQUEST (0x01, demande du client au serveur) et BOOTREPLY (0x02, réponse du serveur au client).
1
htype
Type d'adresse matérielle. Les valeurs valides pour ce champ sont définies dans RFC 1700 Assigned Numbers. Par exemple, pour une adresse MAC Ethernet, ce champ est défini sur 0x01.
1
hlen
La longueur de l'adresse matérielle en octets. L'adresse MAC Ethernet est 0x06.
1
le houblon
Nombre de routeurs intermédiaires (appelés agents relais DHCP ) par lesquels le message est passé. Le client définit ce champ sur 0x00.
1
xid
Un identifiant de transaction unique de 4 octets généré par le client au début du processus d'obtention de l'adresse.
4
secondes
Temps en secondes depuis le début du processus d'obtention de l'adresse. Ne peut pas être utilisé (dans ce cas, il est défini sur 0x0000).
2
drapeaux
Le champ pour les indicateurs est des paramètres spéciaux du protocole DHCP.
2
ciaddr
Adresse IP du client. Il est renseigné uniquement si le client a déjà sa propre adresse IP et est capable de répondre aux requêtes ARP (cela est possible si le client effectue la procédure de mise à jour de l'adresse après l'expiration du bail).
4
yiaddr
La nouvelle adresse IP du client proposée par le serveur.
4
siaddr
Adresse IP du serveur. Renvoyé dans la clause DHCP (voir ci-dessous).
4
giaddr
L'adresse IP de l'agent de relais, si elle était impliquée dans le processus de remise du message DHCP au serveur.
4
chaddr
L'adresse matérielle (généralement l'adresse MAC) du client.
16
ronfler
Nom de serveur facultatif sous forme de chaîne terminée par null.
64
fichier
Nom de fichier serveur facultatif utilisé par les postes de travail sans disque lors du téléchargement à distance. Comme sname , il est représenté comme une chaîne terminée par un caractère nul.
128
les options
Champ d' options DHCP . Diverses options de configuration supplémentaires sont indiquées ici. Au début de ce champ, quatre octets spéciaux de valeurs 99, 130, 83, 99 («nombres magiques») sont indiqués, permettant au serveur de déterminer la présence de ce champ. Le champ a une longueur variable, mais le client DHCP doit être prêt à recevoir un message DHCP de 576 octets (dans ce message, le champ d' options fait 340 octets).
variable


Liste de toutes les options DHCP dans RFC 2132

Les options DHCP sont codées comme suit:
NuméroLa longueurLes données

Par exemple, le paramètre 3 (passerelle proposée) avec une valeur de 10.0.0.1:
3410001

Si vous devez transmettre plusieurs paramètres, la longueur du paramètre augmente.
Par exemple, dans le paramètre 6 (serveur DNS), nous transmettrons deux adresses (1.1.1.1 et 8.8.4.4):
6811118844

Un signe de la fin du champ d'option est un paramètre avec le nombre 255 (0xFF) et une longueur de 0.

Le plus souvent, le client met le paramètre 55 (une liste de paramètres qu'il souhaite recevoir en réponse) dans DHCP Discover, cependant, nous avons le droit de ne pas lui donner tout ce qu'il a demandé.

Partie pratique


Il était initialement prévu d'écrire le serveur dans un langage plus approprié (C) pour cela, cependant, ce serait banal et simple. Il s'agit soit d'écrire un script qui reprendra les fonctions du serveur DHCP.

Simplification


Le serveur en cours de développement étant censé être utilisé dans des réseaux de deux nœuds reliés par un patch, les simplifications suivantes ont été adoptées:

  • garanti qu'un client sur le réseau;
  • il est garanti qu'il n'y a plus de serveurs DHCP sur le réseau
  • l'initiateur décide de l'adresse à émettre
  • La version DHCP et le déclin DHCP sont ignorés

Auditeur


Tout d'abord, vous devez apprendre à recevoir des paquets. Cela nécessite un auditeur sympathique certifié , par exemple, nc. Mais tous les nc ne conviennent pas à ces fins. OpenBSD netcat 1.130 de Debian convient, mais 1.105 avec Ubuntu a disparu. Exécutez nc pour écouter tous les paquets UDP arrivant sur le port 67.

 nc -l 0.0.0.0 -up 67 -w0 

OpenBSD netcat est également nécessaire en raison du commutateur -w avec une valeur de 0. Après avoir reçu un paquet (diffusion UDP), le nc traditionnel ne reçoit plus de paquets, mais il ne se termine pas.

Gestion des octets bruts


Dans le shell, il est très difficile de travailler avec des caractères non imprimables, comme un caractère nul: il l'ignore simplement. Un paquet DHCP contient plusieurs octets 0x00 (par exemple, le champ de fichier). La solution au problème se présente sous la forme d'un vidage hexadécimal:

  nc -l 0.0.0.0 -up 67 -w0 | stdbuf -o0 od -v -w1 -t x1 -An 

Un octet par ligne, sans sortir l'adresse, sans ignorer les octets en double. Vous pouvez également pimenter stdbuf -o0 afin que la sortie ne soit pas mise en mémoire tampon.

Réception, stockage et traitement des colis


À partir de la commande od stdout, les octets sont pris par la commande read et ajoutés à un tableau.

 msg=() for i in {0..235}; do read -r tmp msg[$i]=$tmp done 

Bien que toutes les valeurs soient transmises en notation hexadécimale, le numéro d'option DHCP et la longueur de l'option sont mieux affichés à l'écran / dans les journaux sous la forme décimale habituelle. Pour ce faire, vous pouvez utiliser une entrée bash'a courte:

 $ op=AC $ echo $((16#$op)) 172 

Le paquet reçu est édité selon le type de demande (Discover ou Request) et renvoyé.

Réponse


Cependant, l'envoi d'un colis n'est pas une tâche aussi simple. Vous devez d'abord convertir les octets du vidage en octets bruts et envoyer tout en une fois avec un seul paquet.

La conversion peut être effectuée avec l'utilitaire printf à l'aide de séquences d'échappement. Et pour que rien ne soit perdu, écrivez immédiatement des octets dans un fichier.

 #   >/tmp/dhcp.payload #     for i in ${msg[*]}; do printf "\x$i" >> /tmp/dhcp.payload done 

OpenBSD netcat est également utilisé pour l'envoi. Cependant, si la version 1.105 avec Ubuntu convient comme écouteur, elle ne convient pas pour diffuser des messages UDP: nous obtenons l'erreur de protocole non disponible.

 cat /tmp/dhcp.payload | nc -ub 255.255.255.255 68 -s $SERVER -p 67 -w0 

Le commutateur -b permet d'envoyer des messages de diffusion, et c'est la deuxième raison pour laquelle le serveur doit être exécuté sous le superutilisateur.

Quelles sont les limitations?


Ce serveur DHCP a été conçu avec des simplifications comme un seul client sur le réseau. Cependant, cela fonctionnera avec plusieurs clients. Obtenez simplement l'adresse la plus rapide.



Conclusion


Bien que les scripts bash puissent difficilement être appelés un langage de programmation à part entière, néanmoins, avec le désir, vous pouvez même résoudre des problèmes tels que l'émission d'une adresse IP sur le réseau sans utiliser de logiciel spécialement conçu pour cela. Et résoudre des problèmes spécifiques apporte non seulement de la joie, mais aussi de nouvelles connaissances qui se sont ouvertes au moment de la solution.

Les sources


  1. DHCP - Wikipedia
  2. Paramètres DHCP et BOOTP - IANA

Source: https://habr.com/ru/post/fr435148/


All Articles