
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-serverAnfä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 ):
- Der Client findet heraus, wo sich der DHCP-Server befindet ( D iscover)
- Der Server antwortet und bietet seine Adresse an ( O ffer)
- Der Client fordert die vorgeschlagene Adresse von einem bestimmten Server an ( R equest).
- 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 WikipediaDas Feld | Beschreibung | Lä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 2132DHCP-Optionen werden wie folgt codiert:
Beispiel: Parameter 3 (vorgeschlagenes Gateway) mit einem Wert von 10.0.0.1:
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):
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
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.
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
- DHCP - Wikipedia
- DHCP- und BOOTP-Parameter - IANA