Native DHCP-Server mit Bash

Ich liebe es, den Prozess zu automatisieren und meine eigenen Motorräder zu schreiben, um dieses oder jenes Material zu studieren. Mein neues Ziel war ein DHCP-Server, der in kleinen Netzwerken eine Adresse ausgibt, damit die Erstkonfiguration der Geräte durchgeführt werden kann.

In diesem Artikel werde ich ein wenig über das DHCP-Protokoll und einige Feinheiten von bash sprechen.



Endergebnis


Beginnen wir am Ende, damit klar ist, wofür wir kämpfen.

Demonstration der Arbeit:



Repository mit Skript: firemoon777 / bash-dhcp-server

Anfängliches Problem


Die Konfiguration, die ich benötige, erfolgt folgendermaßen: Wir stellen eine direkte Verbindung über Twisted Pair zum Gerät her, geben eine temporäre Adresse über DHCP aus und konfigurieren sie mit einem bereits erstellten Skript. Und so zehn bis zwanzig Mal hintereinander.

Für viele macht der bekannte isc-dhcp-Server seine Arbeit perfekt, aber leider benachrichtigt er mein Skript nicht über die Ausgabe der Adresse, sodass Sie die Ausführung irgendwie blockieren müssen, bis die Adresse ausgegeben wird.

Die Lösung scheint auf der Oberfläche zu liegen: Pingen Sie, bis das Gesicht blau ist, bis das Gerät reagiert:

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

Aber dieser Entscheidung fehlt definitiv der Abenteuerlust.

Theoretischer Teil


Abrufen einer Adresse mit einem einzelnen DHCP-Server



Das DHCP-Protokoll funktioniert über UDP an den Ports 67 und 68. Der Server arbeitet immer nur bei 67 und der Client nur bei 68. Da der Client keine Adresse hat (die Adresse 0.0.0.0 hat), werden DHCP-Pakete gesendet. Das heißt, Der Client sendet immer Pakete von der Adresse 0.0.0.0:68 an die Adresse 255.255.255.255:67, und der Server sendet von seiner Adresse: 67 an die Adresse 255.255.255.255:68.

Der Client empfängt die Adresse in vier Paketen ( DORA ):

  1. Der Client findet heraus, wo sich der DHCP-Server befindet ( D iscover)
  2. Der Server antwortet und bietet seine Adresse an ( O ffer)
  3. Der Client fordert die vorgeschlagene Adresse von einem bestimmten Server an ( R equest).
  4. Der Server stimmt zu und gibt die Adresse aus ( A ck)

Visuell kann das Schema wie folgt dargestellt werden:



Abrufen einer Adresse mit mehreren DHCP-Servern



Wenn der Client Discover sendet, senden alle Server, die dies hören können, ihr Angebot an den Client. Aber der Kunde muss einen auswählen. Die Clientauswahl wird in der Anforderungsnachricht mit Option 54 (DHCP-Server) angekündigt, die die IP-Adresse des bevorzugten DHCP-Servers enthält. Obwohl die Anforderung auch an alle im Netzwerk gesendet wird, antwortet nur der DHCP-Server, dessen IP in Option 54 angegeben ist.



DHCP-Paketinhalt


Ein DHCP-Paket besteht aus zwei Teilen: einer Konstanten mit einer Größe von 236 Byte und einer Variablen, die Optionen enthält (DHCP-Option).

Tabelle mit allen Feldern des DHCP-Pakets aus Wikipedia
Das FeldBeschreibungLänge (in Bytes)
op
Art der Nachricht. Beispielsweise können Werte angenommen werden: BOOTREQUEST (0x01, Anforderung von Client zu Server) und BOOTREPLY (0x02, Antwort von Server zu Client).
1
htype
Art der Hardwareadresse. Gültige Werte für dieses Feld sind in RFC 1700 Assigned Numbers definiert. Für eine Ethernet-MAC-Adresse wird dieses Feld beispielsweise auf 0x01 gesetzt.
1
hlen
Die Länge der Hardwareadresse in Bytes. Die Ethernet-MAC-Adresse lautet 0x06.
1
Hopfen
Die Anzahl der Zwischenrouter (die sogenannten DHCP-Relay-Agenten ), über die die Nachricht gesendet wurde. Der Client setzt dieses Feld auf 0x00.
1
xid
Eine eindeutige Transaktionskennung von 4 Bytes, die vom Client zu Beginn des Prozesses zum Abrufen der Adresse generiert wird.
4
sek
Die Zeit in Sekunden seit dem Beginn des Prozesses zum Abrufen der Adresse. Darf nicht verwendet werden (in diesem Fall ist es auf 0x0000 eingestellt).
2
Flaggen
Das Feld für Flags enthält spezielle Parameter des DHCP-Protokolls.
2
ciaddr
Client-IP-Adresse. Es wird nur ausgefüllt, wenn der Client bereits eine eigene IP-Adresse hat und auf ARP-Anforderungen antworten kann (dies ist möglich, wenn der Client das Verfahren zum Aktualisieren der Adresse nach Ablauf des Lease ausführt).
4
yiaddr
Die vom Server vorgeschlagene neue Client-IP-Adresse.
4
siaddr
Server-IP-Adresse. Wird in der DHCP-Klausel zurückgegeben (siehe unten).
4
giaddr
Die IP-Adresse des Relay-Agenten, falls einer an der Übermittlung der DHCP-Nachricht an den Server beteiligt war.
4
chaddr
Die Hardwareadresse (normalerweise die MAC-Adresse) des Clients.
16
sname
Optionaler Servername als nullterminierte Zeichenfolge.
64
Datei
Ein optionaler Serverdateiname, der von plattenlosen Workstations beim Remote-Download verwendet wird. Wie sname wird es als nullterminierte Zeichenfolge dargestellt.
128
Optionen
DHCP-Optionsfeld . Hier werden verschiedene zusätzliche Konfigurationsoptionen angezeigt. Am Anfang dieses Feldes werden vier spezielle Bytes mit den Werten 99, 130, 83, 99 („magische Zahlen“) angezeigt, damit der Server das Vorhandensein dieses Felds feststellen kann. Das Feld hat eine variable Länge, aber der DHCP-Client sollte bereit sein, eine 576-Byte-DHCP-Nachricht zu empfangen (in dieser Nachricht ist das Optionsfeld 340 Byte lang).
variabel


Liste aller DHCP-Optionen in RFC 2132

DHCP-Optionen werden wie folgt codiert:
NummerLängeDaten

Beispiel: Parameter 3 (vorgeschlagenes Gateway) mit einem Wert von 10.0.0.1:
3410001

Wenn Sie mehrere Parameter übergeben müssen, erhöht sich die Länge des Parameters.
In Parameter 6 (DNS-Server) übertragen wir beispielsweise zwei Adressen (1.1.1.1 und 8.8.4.4):
6811118844

Ein Vorzeichen am Ende des Optionsfelds ist ein Parameter mit der Nummer 255 (0xFF) und einer Länge von 0.

In den meisten Fällen fügt der Client Parameter 55 (eine Liste von Parametern, die er als Antwort erhalten möchte) in DHCP Discover ein. Wir haben jedoch das Recht, ihm nicht alles zu geben, was er angefordert hat.

Praktischer Teil


Es war ursprünglich geplant, den Server in einer geeigneteren Sprache (C) dafür zu schreiben, aber es wäre banal und einfach. Es geht entweder darum, ein Skript zu schreiben, das die Funktionen des DHCP-Servers übernimmt.

Vereinfachung


Da der zu entwickelnde Server in Netzwerken von zwei durch einen Patch verbundenen Knoten verwendet werden sollte, wurden die folgenden Vereinfachungen übernommen:

  • garantiert, dass ein Client im Netzwerk;
  • Es ist garantiert, dass sich keine DHCP-Server mehr im Netzwerk befinden
  • Der Initiator entscheidet, welche Adresse ausgegeben werden soll
  • DHCP-Freigabe und DHCP-Ablehnung werden ignoriert

Zuhörer


Zunächst müssen Sie lernen, wie Sie Pakete empfangen. Dies erfordert einen zertifizierten sympathischen Zuhörer, zum Beispiel nc. Aber nicht jeder nc ist für diese Zwecke geeignet. OpenBSD netcat 1.130 von Debian ist geeignet, aber 1.105 mit Ubuntu ist weg. Führen Sie nc aus, um alle UDP-Pakete abzuhören, die an Port 67 ankommen.

 nc -l 0.0.0.0 -up 67 -w0 

OpenBSD netcat wird auch wegen des -w-Switches mit dem Wert 0 benötigt. Nach dem Empfang eines Pakets (UDP Broadcast) empfängt der herkömmliche nc keine weiteren Pakete, endet jedoch nicht.

Raw-Byte-Behandlung


In der Shell ist es sehr schwierig, mit nicht druckbaren Zeichen wie einem Nullzeichen zu arbeiten: Es wird einfach ignoriert. Ein DHCP-Paket enthält viele Bytes 0x00 (z. B. das Dateifeld). Die Lösung des Problems erfolgt in Form eines Hex-Dumps:

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

Ein Byte pro Zeile, ohne die Adresse auszugeben, ohne doppelte Bytes zu überspringen. Sie können stdbuf -o0 auch aufpeppen, damit die Ausgabe nicht gepuffert wird.

Pakete empfangen, speichern und verarbeiten


Aus dem od-Befehl stdout werden die Bytes vom Befehl read übernommen und einem Array hinzugefügt.

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

Obwohl alle Werte in hexadezimaler Schreibweise übertragen werden, werden die DHCP-Optionsnummer und die Optionslänge am besten auf dem Bildschirm / in den Protokollen in der üblichen Dezimalform angezeigt. Dazu können Sie eine kurze Eingabe bash'a verwenden:

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

Das empfangene Paket wird entsprechend der Art der Anforderung (Erkennen oder Anfordern) bearbeitet und zurückgesendet.

Antwort


Das Senden eines Pakets ist jedoch keine so einfache Aufgabe. Zuerst müssen Sie Bytes aus dem Dump in Rohbytes konvertieren und alles auf einmal mit einem Paket senden.

Die Konvertierung kann mit dem Dienstprogramm printf mithilfe von Escape-Sequenzen erfolgen. Und damit nichts verloren geht, schreiben Sie Bytes sofort in eine Datei.

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

OpenBSD netcat wird auch zum Senden verwendet. Wenn jedoch Version 1.105 mit Ubuntu als Listener geeignet ist, ist sie nicht zum Senden von UDP-Nachrichten geeignet: Wir erhalten den Fehler Protokoll nicht verfügbar.

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

Mit dem Schalter -b können Broadcast-Nachrichten gesendet werden. Dies ist der zweite Grund, warum der Server unter dem Superuser ausgeführt werden muss.

Was sind die Einschränkungen?


Dieser DHCP-Server wurde mit Vereinfachungen wie ein einzelner Client im Netzwerk entwickelt. Es funktioniert jedoch mit mehreren Clients. Holen Sie sich einfach die schnellste Adresse.



Fazit


Obwohl Bash-Skripte kaum als vollwertige Programmiersprache bezeichnet werden können, können Sie bei Bedarf sogar Probleme wie die Angabe einer IP-Adresse im Netzwerk lösen, ohne dafür eine speziell entwickelte Software zu verwenden. Das Lösen spezifischer Probleme bringt nicht nur Freude, sondern auch neues Wissen, das zum Zeitpunkt der Lösung eröffnet wurde.

Quellen


  1. DHCP - Wikipedia
  2. DHCP- und BOOTP-Parameter - IANA

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


All Articles