
Ziel dieses Projekts war:
- Untersuchung des DHCP-Protokolls bei der Arbeit mit IPv4-Netzwerken
- Lernen von Python (ein bisschen mehr als bei null đ )
- Serveraustausch (mein Fork), das Original , das unter einem neuen Betriebssystem immer schwieriger zu kompilieren ist. Und es ist auch nicht angenehm, dass der Binary nicht «sofort geÀndert werden kann»
- Erstellung eines funktionierenden DHCP-Servers mit der Möglichkeit, die IP-Adresse des Clients anhand der MAC-Adresse des Clients oder der Verbindung von MAC-Adresse und Switch-Port (Option 82) auszuwÀhlen
- Schreiben eines weiteren Fahrrads (Oh! Das ist meine LieblingsbeschÀftigung)
- Kritik fĂŒr meine Unbeholfenheit auf Habrhabr erhalten (oder besser noch eine Einladung) đ
Ergebnis: funktioniert đ Ausprobiert auf FreeBSD und Ubuntu. Theoretisch kann der Code auch unter jedem Betriebssystem zum Laufen gebracht werden, da es im Code scheinbar keine spezifischen Bindungen gibt.
Vorsicht! Es folgt viel.
Link zum Repository fĂŒr die Liebhaber .
Der Prozess der Installation, Konfiguration und Nutzung des Ergebnisses des «Studiums der Materie» ist weiter unten zu finden, gefolgt von ein wenig Theorie ĂŒber das DHCP-Protokoll. FĂŒr mich. Und fĂŒr die Nachwelt đ
Ein wenig Theorie
Was ist DHCP
Dies ist ein Netzwerkprotokoll, das es einem GerĂ€t ermöglicht, seine IP-Adresse (und andere Parameter wie Gateway, DNS usw.) vom DHCP-Server zu erfahren. Der Paketwechsel erfolgt ĂŒber das UDP-Protokoll. Das allgemeine Arbeitsprinzip des GerĂ€ts beim Anfordern von Netzwerkeinstellungen ist wie folgt:
- Das GerÀt (Client) sendet eine Broadcast-UDP-Anfrage (DHCPDISCOVER) an das gesamte Netzwerk mit der Bitte: "Kann mir jemand eine IP-Adresse geben?" In der Regel (aber nicht immer) erfolgt die Anfrage vom Port 68 (Quelle) und das Ziel ist Port 67 (Ziel). Einige GerÀte senden Pakete auch von Port 67. Im Inneren des DHCPDISCOVER-Pakets ist die MAC-Adresse des Client-GerÀts enthalten.
- Alle DHCP-Server im Netzwerk (von denen es mehrere geben kann) erstellen fĂŒr das GerĂ€t, das DHCPDISCOVER gesendet hat, ein DHCPOFFER-Angebot mit Netzwerkeinstellungen und senden dieses ebenfalls broadcastmĂ€Ăig im Netzwerk. Die Identifizierung, fĂŒr wen dieses Paket bestimmt ist, erfolgt ĂŒber die zuvor im DHCPDISCOVER-Antrag bereitgestellte MAC-Adresse des Clients.
- Der Kunde empfÀngt Pakete mit Netzwerkkonfigurationen, wÀhlt das attraktivste aus (die Kriterien können unterschiedlich sein, zum Beispiel die Lieferzeit des Pakets oder die Anzahl der Zwischenrouten), und sendet an den bevorzugten DHCP-Server eine "offizielle Anfrage" DHCPREQUEST mit den Netzwerkeinstellungen. In diesem Fall wird das Paket bereits an einen bestimmten DHCP-Server gesendet.
- Der Server, der die DHCPREQUEST erhalten hat, sendet ein Paket im Format DHCPACK, in dem erneut die Netzwerkeinstellungen aufgelistet sind, die fĂŒr diesen Kunden bestimmt sind.

DarĂŒber hinaus gibt es DHCPINFORM-Pakete, die vom Client ausgehen und die darauf abzielen, den DHCP-Server darĂŒber zu informieren, dass der "Client aktiv ist" und die bereitgestellten Netzwerkeinstellungen nutzt. Diese Pakete werden in dieser Serverimplementierung ignoriert.
Paketformat
Im Allgemeinen sieht der Ethernet-Paketrahmen ungefÀhr so aus:
![]()
In unserem Fall betrachten wir nur die Daten des UDP-Paket-Inhalts, ohne die Header der OSI-Protokollschichten, nÀmlich die Struktur von DHCP:
DHCPDISCOVER
Der Prozess zur Beschaffung einer IP-Adresse fĂŒr ein GerĂ€t beginnt damit, dass der DHCP-Client eine Broadcast-Anfrage von Port 68 an 255.255.255.255:67 sendet. In diesem Paket enthĂ€lt der Client seine MAC-Adresse sowie die Informationen, die er vom DHCP-Server erhalten möchte. Die Struktur des Pakets ist in der nachstehenden Tabelle beschrieben.
Tabelle der Struktur des DHCPDISCOVER-Pakets
Position im Paket
Wertbezeichnung
Beispiel
Darstellung
Byte
ErklÀrung
1
Boot-Anfrage
1
Hex
1
Nachrichtentyp. 1 â Anfrage vom Client an den Server, 2 â Antwort vom Server an den Client
2
Hardwaretyp
1
Hex
1
Typ der Hardwareadresse, in diesem Protokoll 1 â MAC
3
LĂ€nge der Hardwareadresse
6
Hex
1
LÀnge der MAC-Adresse des GerÀts
4
Hops
1
Hex
1
Anzahl der Zwischengestoppten
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Identifikationsnummer der Transaktion. Wird vom Client zu Beginn des Anfragevorgangs generiert.
7
Sekunden seit Beginn
0
Hex
4
Zeit in Sekunden seit dem Beginn des Anschaffungsprozesses der Adresse
9
Bootp-Flags
0
Hex
2
Verschiedene Flags, die gesetzt werden können, um die Protokollparameter anzugeben
11
Client-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse, die vom Server vorgeschlagen wird (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenfolge
4
IP-Adresse des Relais-Agenten (z.B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Absenders des Pakets (Client)
31
Hardware-Adresse des Clients (Padding)
Â
Hex
10
Reservierter Platz. In der Regel mit Nullen gefĂŒllt.
41
Server-Host-Name
Â
Zeichenfolge
64
Name des DHCP-Servers. In der Regel wird er nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenfolge
128
Name der Datei auf dem Server, die von diskless Workstations beim Booten verwendet wird.
235
Magische Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer u.a. festgestellt werden kann, dass dieses Paket dem DHCP-Protokoll angehört.
DHCP-Optionen. Können in beliebiger Reihenfolge folgen.
236
Optionsnummer
53
Dezimal
1
Option 53, die den Typ des DHCP-Pakets definiert.
1 â DHCPDISCOVER
3 â DHCPREQUEST
2 â DHCPOFFER
5 â DHCPACK
8 â DHCPINFORM
Â
LĂ€nge der Option
1
Dezimal
1
Â
Wert der Option
1
Dezimal
1
Â
Optionsnummer
50
Dezimal
1
Welche IP-Adresse möchte der Client erhalten?
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
172.16.134.61
Zeichenfolge
4
Â
Optionsnummer
55
Â
1
Vom Client angeforderte Netzwerkparameter. Die Zusammensetzung kann unterschiedlich sein.
01 â Subnetzmaske
03 â Gateway
06 â DNS
0c â Hostname
0f â Name der Domain
1c â Adresse der Broadcast-Anfrage
42 â TFTP-Servername
79 â Classless Static Route
Â
LĂ€nge der Option
8
Â
1
Â
Wert der Option
01:03:06:0c:0f:1c:42:79
Â
8
Â
Optionsnummer
82
Dezimal
Â
Option 82, in der die MAC-Adresse des GerĂ€ts (Repeater) und einige zusĂ€tzliche Werte ĂŒbertragen werden.
In der Regel der Port des Switches, an dem der endgĂŒltige DHCP-Client arbeitet. In dieser Option sind zusĂ€tzliche Parameter "eingebettet". Das erste Byte ist die Nummer der "Suboption", das zweite ihre LĂ€nge, gefolgt von ihrem Wert.
In diesem Fall sind in Option 82 die Unteroptionen eingebettet:
Agent Circuit ID = 00:04:00:01:00:04, wobei die letzten zwei Bytes den DHCP-Clientport reprÀsentieren, von dem die Anfrage kam
Agent Remote ID = 00:06:c8:be:19:93:11:48 â MAC-Adresse des DHCP-Relay-GerĂ€ts
Â
LĂ€nge der Option
18
Dezimal
Â
Â
Wert der Option
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
Â
Â
Ende des Pakets
255
Dezimal
1
255 symbolisiert das Ende des Pakets
DHCPOFFER
Sobald der Server das Paket DHCPDISCOVER empfĂ€ngt und sieht, dass er dem Client etwas aus der Anfrage anbieten kann, erstellt er eine Antwort â DHCPOFFER. Die Antwort wird an den "Ursprungsport" gesendet, als Broadcast, da der Client zu diesem Zeitpunkt noch keine IP-Adresse hat; daher kann er das Paket nur empfangen, wenn es breitbandig gesendet wird. Der Client erkennt, dass dies ein Paket fĂŒr ihn ist, anhand seiner MAC-Adresse im Paket sowie der Transaktionsnummer, die er beim Erstellen des ersten Pakets generiert.
Tabelle der DHCPOFFER-Paketstruktur
Position im Paket
Name des Wertes (allgemein anerkannt)
Beispiel
Darstellung
Byte
ErklÀrung
1
Boot-Anfrage
1
Hex
1
Nachrichtentyp. 1 â Anfrage vom Client an den Server, 2 â Antwort vom Server an den Client
2
Hardwaretyp
1
Hex
1
Typ der Hardwareadresse, in diesem Protokoll 1 â MAC
3
LĂ€nge der Hardwareadresse
6
Hex
1
LÀnge der MAC-Adresse des GerÀts
4
Hops
1
Hex
1
Anzahl der Zwischengestoppten
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Identifikationsnummer der Transaktion. Wird vom Client zu Beginn des Anfragevorgangs generiert.
7
Sekunden seit Beginn
0
Hex
4
Zeit in Sekunden seit dem Beginn des Anschaffungsprozesses der Adresse
9
Bootp-Flags
0
Hex
2
Einige Flags, die als Indikationen der Protokollparameter gesetzt werden können. In diesem Fall bedeutet 0 â den Anforderungstyp Unicast
11
Client-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenfolge
4
IP-Adresse, die vom Server vorgeschlagen wird (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenfolge
4
IP-Adresse des Relais-Agenten (z.B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Absenders des Pakets (Client)
31
Hardware-Adresse des Clients (Padding)
Â
Hex
10
Reservierter Platz. In der Regel mit Nullen gefĂŒllt.
41
Server-Host-Name
Â
Zeichenfolge
64
Name des DHCP-Servers. In der Regel wird er nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenfolge
128
Name der Datei auf dem Server, die von diskless Workstations beim Booten verwendet wird.
235
Magische Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer u.a. festgestellt werden kann, dass dieses Paket dem DHCP-Protokoll angehört.
DHCP-Optionen. Können in beliebiger Reihenfolge folgen.
236
Optionsnummer
53
Dezimal
1
Option 53, die den Typ des DHCP-Pakets definiert: 2 â DHCPOFFER
Â
LĂ€nge der Option
1
Dezimal
1
Â
Wert der Option
2
Dezimal
1
Â
Optionsnummer
1
Dezimal
1
Option, die dem DHCP-Client die Subnetzmaske anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
255.255.224.0
Zeichenfolge
4
Â
Optionsnummer
3
Dezimal
1
Option, die dem DHCP-Client das Standard-Gateway anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
172.16.12.1
Zeichenfolge
4
Â
Optionsnummer
6
Dezimal
1
Option, die dem DHCP-Client DNS anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
8.8.8.8
Zeichenfolge
4
Â
Optionsnummer
51
Dezimal
1
Die Lebensdauer der bereitgestellten Netzparameter in Sekunden, nach der der DHCP-Client sie erneut anfordern sollte
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
86400
Dezimal
4
Â
Optionsnummer
82
Dezimal
1
Option 82, wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dezimal
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dezimal
18
Â
Ende des Pakets
255
Dezimal
1
255 symbolisiert das Ende des Pakets
DHCPREQUEST
Nachdem der Client das DHCPOFFER erhalten hat, erstellt er ein Paket mit der Anfrage nach Netzparametern nicht an alle DHCP-Server im Netzwerk, sondern nur an einen spezifischen, dessen DHCPOFFER ihm am meisten 'gefiel'. Die Kriterien, was 'gefiel', können unterschiedlich sein und hĂ€ngen von der Implementierung des DHCP-Clients ab. Der EmpfĂ€nger der Anfrage wird durch die MAC-Adresse des DHCP-Servers angegeben. AuĂerdem kann das DHCPREQUEST-Paket auch ohne vorheriges DHCPDISCOVER vom Client gesendet werden, wenn die IP-Adresse des Servers bereits zuvor erhalten wurde.
Tabelle der Struktur des DHCPREQUEST-Pakets
Position im Paket
Name des Wertes (allgemein anerkannt)
Beispiel
Darstellung
Byte
ErklÀrung
1
Boot-Anfrage
1
Hex
1
Nachrichtentyp. 1 â Anfrage vom Client an den Server, 2 â Antwort vom Server an den Client
2
Hardwaretyp
1
Hex
1
Typ der Hardwareadresse, in diesem Protokoll 1 â MAC
3
LĂ€nge der Hardwareadresse
6
Hex
1
LÀnge der MAC-Adresse des GerÀts
4
Hops
1
Hex
1
Anzahl der Zwischengestoppten
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Identifikationsnummer der Transaktion. Wird vom Client zu Beginn des Anfragevorgangs generiert.
7
Sekunden seit Beginn
0
Hex
4
Zeit in Sekunden seit dem Beginn des Anschaffungsprozesses der Adresse
9
Bootp-Flags
8000
Hex
2
Einige Flags, die gesetzt werden können, um die Parameter des Protokolls anzugeben. In diesem Fall ist 'Broadcast' gesetzt
11
Client-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenfolge
4
IP-Adresse, die vom Server vorgeschlagen wird (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenfolge
4
IP-Adresse des Relais-Agenten (z.B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Absenders des Pakets (Client)
31
Hardware-Adresse des Clients (Padding)
Â
Hex
10
Reservierter Platz. In der Regel mit Nullen gefĂŒllt.
41
Server-Host-Name
Â
Zeichenfolge
64
Name des DHCP-Servers. In der Regel wird er nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenfolge
128
Name der Datei auf dem Server, die von diskless Workstations beim Booten verwendet wird.
235
Magische Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer u.a. festgestellt werden kann, dass dieses Paket dem DHCP-Protokoll angehört.
DHCP-Optionen. Können in beliebiger Reihenfolge folgen.
236
Optionsnummer
53
Dezimal
3
Option 53, die den Typ des DHCP-Pakets definiert 3 â DHCPREQUEST
Â
LĂ€nge der Option
1
Dezimal
1
Â
Wert der Option
3
Dezimal
1
Â
Optionsnummer
61
Dezimal
1
Client-Identifier: 01 (fĂŒr Ethernet) + MAC-Adresse des Clients
Â
LĂ€nge der Option
7
Dezimal
1
Â
Wert der Option
01:2c:ab:25:ff:72:a6
Hex
7
Â
Optionsnummer
60
Dezimal
Â
'Vendor Class Identifier'. In meinem Fall gibt sie die Version des DHCP-Clients an. Möglicherweise geben andere GerĂ€te etwas anderes zurĂŒck. Windows zum Beispiel berichtet MSFT 5.0
Â
LĂ€nge der Option
11
Dezimal
Â
Â
Wert der Option
udhcp 0.9.8
Zeichenfolge
Â
Â
Optionsnummer
55
Â
1
Vom Client angeforderte Netzwerkparameter. Die Zusammensetzung kann unterschiedlich sein.
01 â Subnetzmaske
03 â Gateway
06 â DNS
0c â Hostname
0f â Name der Domain
1c â Adresse der Broadcast-Anfrage
42 â TFTP-Servername
79 â Classless Static Route
Â
LĂ€nge der Option
8
Â
1
Â
Wert der Option
01:03:06:0c:0f:1c:42:79
Â
8
Â
Optionsnummer
82
Dezimal
1
Option 82, wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dezimal
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dezimal
18
Â
Ende des Pakets
255
Dezimal
1
255 symbolisiert das Ende des Pakets
DHCPACK
Als BestĂ€tigung dafĂŒr, dass "ja, dies ist dein IP-Adresse und ich werde sie niemandem sonst geben" vom DHCP-Server dient das Paket im Format DHCPACK an den Client. Es wird, wie alle anderen Pakete, ebenfalls broadcasted. Im folgenden Code des DHCP-Servers, implementiert in Python, dupliziere ich zur Sicherheit jede Broadcast-Anfrage, indem ich das Paket an eine spezifische IP des Clients sende, falls diese bereits bekannt ist. Dabei kĂŒmmert sich der DHCP-Server ĂŒberhaupt nicht darum, ob das DHCPACK-Paket den Client erreicht hat. Wenn der Client kein DHCPACK erhĂ€lt, sendet er nach einer gewissen Zeit einfach erneut eine DHCPREQUEST.
Tabelle der Struktur des DHCPACK-Pakets
Position im Paket
Name des Wertes (allgemein anerkannt)
Beispiel
Darstellung
Byte
ErklÀrung
1
Boot-Anfrage
2
Hex
1
Nachrichtentyp. 1 â Anfrage vom Client an den Server, 2 â Antwort vom Server an den Client
2
Hardwaretyp
1
Hex
1
Typ der Hardwareadresse, in diesem Protokoll 1 â MAC
3
LĂ€nge der Hardwareadresse
6
Hex
1
LÀnge der MAC-Adresse des GerÀts
4
Hops
1
Hex
1
Anzahl der Zwischengestoppten
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Identifikationsnummer der Transaktion. Wird vom Client zu Beginn des Anfragevorgangs generiert.
7
Sekunden seit Beginn
0
Hex
4
Zeit in Sekunden seit dem Beginn des Anschaffungsprozesses der Adresse
9
Bootp-Flags
8000
Hex
2
Einige Flags, die gesetzt werden können, um die Parameter des Protokolls anzugeben. In diesem Fall ist 'Broadcast' gesetzt
11
Client-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenfolge
4
IP-Adresse, die vom Server vorgeschlagen wird (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenfolge
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenfolge
4
IP-Adresse des Relais-Agenten (z.B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Absenders des Pakets (Client)
31
Hardware-Adresse des Clients (Padding)
Â
Hex
10
Reservierter Platz. In der Regel mit Nullen gefĂŒllt.
41
Server-Host-Name
Â
Zeichenfolge
64
Name des DHCP-Servers. In der Regel wird er nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenfolge
128
Name der Datei auf dem Server, die von diskless Workstations beim Booten verwendet wird.
235
Magische Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer u.a. festgestellt werden kann, dass dieses Paket dem DHCP-Protokoll angehört.
DHCP-Optionen. Können in beliebiger Reihenfolge folgen.
236
Optionsnummer
53
Dezimal
3
Option 53, die den Pakettyp DHCP definiert, 5 â DHCPACK
Â
LĂ€nge der Option
1
Dezimal
1
Â
Wert der Option
5
Dezimal
1
Â
Optionsnummer
1
Dezimal
1
Option, die dem DHCP-Client die Subnetzmaske anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
255.255.224.0
Zeichenfolge
4
Â
Optionsnummer
3
Dezimal
1
Option, die dem DHCP-Client das Standard-Gateway anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
172.16.12.1
Zeichenfolge
4
Â
Optionsnummer
6
Dezimal
1
Option, die dem DHCP-Client DNS anbietet
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
8.8.8.8
Zeichenfolge
4
Â
Optionsnummer
51
Dezimal
1
Die Lebensdauer der bereitgestellten Netzparameter in Sekunden, nach der der DHCP-Client sie erneut anfordern sollte
Â
LĂ€nge der Option
4
Dezimal
1
Â
Wert der Option
86400
Dezimal
4
Â
Optionsnummer
82
Dezimal
1
Option 82, wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dezimal
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dezimal
18
Â
Ende des Pakets
255
Dezimal
1
255 symbolisiert das Ende des Pakets
Installation von
Die Installation besteht tatsÀchlich darin, die erforderlichen Python-Module zu installieren. Es wird vorausgesetzt, dass MySQL bereits installiert und konfiguriert ist.
FreeBSD
pkg install python3 python3 -m ensurepip pip3 install mysql-connector
Ubuntu
sudo apt-get install python3 sudo apt-get install pip3 sudo pip3 install mysql-connector
Wir erstellen eine MySQL-Datenbank, laden den Dump pydhcp.sql hoch und konfigurieren die Konfigurationsdatei.
Konfiguration
Alle Servereinstellungen befinden sich in einer XML-Datei. Referenzdatei:
0.0.0.0
255.255.255.255
192.168.0.71
8600
1
255.255.255.0
192.168.0.1
8.8.8.8
localhost
test
test
pydhcp
option_82_hex:sw_port1:20:22
option_82_hex:sw_port2:16:18
option_82_hex:sw_mac:26:40
3
select ip,mask,router,dns from users where upper(mac)=upper('{option_82_AgentRemoteId_hex}') and upper(port)=upper('{option_82_AgentCircuitId_port_hex}')
select ip,mask,router,dns from users where upper(mac)=upper('{sw_mac}') and upper(port)=upper('{sw_port2}')
select ip,mask,router,dns from users where upper(mac)=upper('{ClientMacAddress}')
insert into history (id,dt,mac,ip,comment) values (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')Lassen Sie uns die Tags im Detail betrachten:
Der Abschnitt dhcpserver beschreibt die grundlegenden Einstellungen fĂŒr den Betrieb des Servers, nĂ€mlich:
- host â welche IP-Adresse der Server am Port 67 abhört
- Broadcast â welche IP ist die Broadcast-Adresse fĂŒr DHCPOFFER und DHCPACK?
- DHCPServer â welche IP hat der DHCP-Server?
- LeaseTime â die Dauer der Miete fĂŒr die zugewiesene IP-Adresse.
- ThreadLimit â wie viele Threads gleichzeitig zur Verarbeitung der eingehenden UDP-Pakete auf Port 67 laufen. Dies soll bei hochbelasteten Projekten helfen đ.
- defaultMask, defaultRouter, defaultDNS â die Standardwerte, die dem Abonnenten angeboten werden, wenn die IP in der Datenbank gefunden wird, aber keine zusĂ€tzlichen Parameter angegeben sind.
MySQL-Sektion:
host, username, password, basename â hier spricht alles fĂŒr sich. Eine beispielhafte Datenbankstruktur ist auf
Query-Sektion: hier werden die Anfragen zum Erhalt von OFFER/ACK beschrieben:
- offer_count â die Anzahl der Zeilen mit Anfragen, die Ergebnisse wie ip, mask, router, dns zurĂŒckgeben.
- offer_n â die Anfragezeile. Wenn die RĂŒckgabe leer ist, wird die nĂ€chste Anfrage offer ausgefĂŒhrt.
- history_sql â eine Anfrage, die beispielsweise in die âAutorisierungshistorieâ des Abonnenten schreibt.
In den Anfragen können beliebige Variablen aus der Sektion options oder Optionen aus dem DHCP-Protokoll verwendet werden.
Optionssektion. Hier wird es interessanter. Hier können wir Variablen erstellen, die wir spÀter in der Query-Sektion verwenden können.
Zum Beispiel:
option_82_hex:sw_port1:20:22, dieser Befehlszeile nimmt die gesamte Zeile des in der DHCP-Anfrage ĂŒbermittelten Options 82 im Hex-Format im Bereich von 20 bis 22 Byte einschlieĂlich und speichert sie in einer neuen Variablen sw_port1 (der Port des Switches, von dem die Anfrage kommt)
option_82_hex:sw_mac:26:40, definieren wir die Variable sw_mac, indem wir den Hex-Wert aus dem Bereich 26:40 entnehmen
Um alle möglichen Optionen zu sehen, die in Anfragen verwendet werden können, kann der Server mit dem SchlĂŒssel -d gestartet werden. Wir sehen ungefĂ€hr so ein Log:
-- DHCPINFORM-Paket an Port 67 von 0025224ad764, b'x91xa5xe0xa3xa5xa9-x8fx8a' empfangen, ('172.30.114.25', 68)
{'ClientMacAddress': '0025224ad764',
'ClientMacAddressByte': b'x00%"Jxd7d',
'HType': 'Ethernet',
'HostName': b'x91xa5xe0xa3xa5xa9-x8fx8a',
'ReqListDNS': True,
'ReqListDomainName': True,
'ReqListPerfowmRouterDiscover': True,
'ReqListRouter': True,
'ReqListStaticRoute': True,
'ReqListSubnetMask': True,
'ReqListVendorSpecInfo': 43,
'RequestedIpAddress': '0.0.0.0',
'Vendor': b'MSFT 5.0',
'chaddr': '0025224ad764',
'ciaddr': '172.30.128.13',
'flags': b'x00x00',
'giaddr': '172.30.114.25',
'gpoz': 308,
'hlen': 6,
'hops': 1,
'htype': 'MAC',
'magic_cookie': b'cx82Sc',
'op': 'DHCPINFORM',
'option12': 12,
'option53': 53,
'option55': 55,
'option60': 60,
'option61': 61,
'option82': 82,
'option_82_byte': b'x12x01x06x00x04x00x01x00x06x02x08x00'
b'x06x00x1eXx9exb2xad',
'option_82_hex': '12010600040001000602080006001e589eb2ad',
'option_82_len': 18,
'option_82_str': "b'x12x01x06x00x04x00x01x00x06x02x08x00x06x00x1eXx9exb2xad'",
'result': False,
'secs': 768,
'siaddr': '0.0.0.0',
'sw_mac': '001e589eb2ad',
'sw_port1': '06',
'xidbyte': b'<x89}x8c',
'xidhex': '3c897d8c',
'yiaddr': '0.0.0.0'}Dementsprechend können wir jede Variable in {} einfĂŒgen, und sie wird im SQL-Befehl verwendet.
Lassen Sie uns fĂŒr die Nachwelt festhalten, dass die IP-Adresse des Clients lautet:


Serverstart
./pydhcpdb.py -d -c config.xml
â d fĂŒr den DEBUG-Ausgabemodus in der Konsole
â c <Dateiname> fĂŒr die Konfigurationsdatei
Fluguntersuchung
Jetzt gehen wir nÀher auf die Implementierung des Servers in Python ein. Das ist eine echte Herausforderung. Python wurde "on-the-fly" erlernt. Viele Aspekte wurden im Stil von "Wow, ich habe irgendwie etwas zum Laufen gebracht" umgesetzt. Es ist alles andere als optimiert und blieb aus mangelnder Erfahrung in der Python-Entwicklung in diesem Zustand. Ich werde auf die interessantesten Punkte bei der Implementierung des Servers im "Code" eingehen.
Parser fĂŒr die XML-Konfigurationsdatei
Es wird das Standardmodul xml.dom von Python verwendet. Es scheint einfach zu sein, aber bei der Umsetzung fehlte es stark an brauchbarer Dokumentation und Beispielen im Internet zur Verwendung dieses Moduls.
tree = minidom.parse(gconfig["config_file"])
mconfig=tree.getElementsByTagName("mysql")
for elem in mconfig:
gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data
gconfig["mysql_username"]=elem.getElementsByTagName("username")[0].firstChild.data
gconfig["mysql_password"]=elem.getElementsByTagName("password")[0].firstChild.data
gconfig["mysql_basename"]=elem.getElementsByTagName("basename")[0].firstChild.data
dconfig=tree.getElementsByTagName("dhcpserver")
for elem in dconfig:
gconfig["broadcast"]=elem.getElementsByTagName("broadcast")[0].firstChild.data
gconfig["dhcp_host"]=elem.getElementsByTagName("host")[0].firstChild.data
gconfig["dhcp_LeaseTime"]=elem.getElementsByTagName("LeaseTime")[0].firstChild.data
gconfig["dhcp_ThreadLimit"]=int(elem.getElementsByTagName("ThreadLimit")[0].firstChild.data)
gconfig["dhcp_Server"]=elem.getElementsByTagName("DHCPServer")[0].firstChild.data
gconfig["dhcp_defaultMask"]=elem.getElementsByTagName("defaultMask")[0].firstChild.data
gconfig["dhcp_defaultRouter"]=elem.getElementsByTagName("defaultRouter")[0].firstChild.data
gconfig["dhcp_defaultDNS"]=elem.getElementsByTagName("defaultDNS")[0].firstChild.data
qconfig=tree.getElementsByTagName("query")
for elem in qconfig:
gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data
for num in range(int(gconfig["offer_count"])):
gconfig["offer_"+str(num+1)]=elem.getElementsByTagName("offer_"+str(num+1))[0].firstChild.data
gconfig["history_sql"]=elem.getElementsByTagName("history_sql")[0].firstChild.data
options=tree.getElementsByTagName("options")
for elem in options:
node=elem.getElementsByTagName("option")
for options in node:
optionsMod.append(options.firstChild.data)Multithreading
Seltsamerweise ist die Multithread-Programmierung in Python sehr klar und einfach umgesetzt.
def PacketWork(data, addr):
...
# Implementierung der Analyse des eingehenden Pakets und der Antwort darauf
...
while True:
data, addr = udp_socket.recvfrom(1024) # Warten auf UDP-Paket
thread = threading.Thread(target=PacketWork, args=(data, addr,)).start() # Wenn es angekommen ist - starten wir die zuvor definierte Funktion PacketWork im Hintergrund mit den Parametern
while threading.active_count() > gconfig["dhcp_ThreadLimit"]:
time.sleep(1) # Wenn die Anzahl der bereits gestarteten Threads gröĂer ist als in den Einstellungen, warten wir, bis sie weniger werdenEmpfang/Versand von DHCP-Paketen
Um UDP-Pakete abzufangen, die ĂŒber die Netzwerkkarte gesendet werden, muss ein Socket "eröffnet" werden:
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) udp_socket.bind((gconfig["dhcp_host"], 67))
, wobei die Flags:
- AF_INET bedeutet, dass das Format der Adresse IP: Port sein wird. Es kann auch AF_UNIX geben - wo die Adresse durch den Dateinamen angegeben wird.
- SOCK_DGRAM bedeutet, dass wir kein "rohes Paket" empfangen, sondern bereits ein Paket, das durch die Firewall gegangen ist, und dass teilweise das Paket abgeschnitten wurde. D.h. wir erhalten nur das UDP-Paket ohne die "physische" Verpackung des UDP-Pakets. Wenn das Flag SOCK_RAW verwendet wird, muss auch diese "Verpackung" geparst werden.
Der Versand eines Pakets kann auch als Broadcast erfolgen:
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # Aktivierung des Sockets fĂŒr das Senden von Broadcasts
rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68)), sowie an die Adresse, von der das Paket kam:
udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # Aktivierung des Sockets fĂŒr den Modus "viele Zuhörer"
rz=udp_socket.sendto(packetack, addr), wobei SOL_SOCKET das "Protokollniveau" zur Festlegung von Optionen bedeutet,
, SO_BROADCAST ist die Option, die angibt, dass das Paket als "Broadcast" gesendet wird.
 , SO_REUSEADDR ist die Option, die den Socket in den Modus "viele Zuhörer" wechselt. Theoretisch ist sie in diesem Fall nicht notwendig, aber auf einem der FreeBSD-Server, den ich getestet habe, funktionierte der Code ohne diese Option nicht.
Analyse des DHCP-Pakets
Hier hat mir Python wirklich gefallen. Es stellt sich heraus, dass es "out of the box" ziemlich frei mit Bytecode umgehen kann. Es ermöglicht eine sehr einfache Ăbersetzung in Dezimalwerte, Strings und Hexadezimal â also genau das, was wir brauchen, um die Struktur des Pakets zu verstehen. So kann man beispielsweise einen Bytebereich in HEX und einfachen Bytes erhalten:
res["xidhex"]=data[4:8].hex()
res["xidbyte"]=data[4:8], Bytes in eine Struktur packen:
res["flags"]=pack('BB',data[10],data[11])IP aus der Struktur erhalten:
res["ciaddr"]=socket.inet_ntoa(pack('BBBB',data[12],data[13],data[14],data[15]));Und umgekehrt:
res=res+socket.inet_pton(socket.AF_INET, gconfig["dhcp_Server"])
Damit sind wir fertig đ
Quelle: habr.com
