
Ziel dieses Projekts war:
- Studium des DHCP-Protokolls im IPv4-Netzwerk
- Studium von Python (ein wenig mehr als von Grund auf đ )
- Ersatz fĂŒr den Server (mein Fork), Original , das unter einem neuen Betriebssystem immer schwieriger zu kompilieren ist. AuĂerdem gefĂ€llt mir nicht, dass ich das Binary nicht 'sofort' austauschen kann.
- Erstellung eines betriebsbereiten DHCP-Servers mit der Möglichkeit, die IP-Adresse des Clients anhand der MAC-Adresse des Clients oder der Kombination aus MAC des Switches + Port (Option 82) auszuwÀhlen.
- Schreiben eines weiteren Fahrrads (Oh! Das ist mein LieblingsbeschÀftigung)
- Erhalt von Kritik zu meiner Ungeschicklichkeit auf Habrhabr (oder besser noch eine Einladung) đ
Ergebnis: funktioniert đ Erprobt auf FreeBSD und Ubuntu. Theoretisch könnte der Code auch unter jedem anderen Betriebssystem verwendet werden, da es anscheinend keine spezifischen Bindungen im Code gibt.
Achtung! Jetzt wird es viel.
Link zum Repository fĂŒr Liebhaber .
Der Prozess der Installation, Konfiguration und Verwendung des Ergebnisses des âStudiums der Materieâ befindet sich viel tiefer, und dann etwas Theorie zum DHCP-Protokoll. FĂŒr mich. Und fĂŒr die Geschichte đ
Ein wenig Theorie
Was ist DHCP
Das ist ein Netzwerkprotokoll, das einem GerĂ€t ermöglicht, seine IP-Adresse (und andere Parameter wie Gateway, DNS und mehr) vom DHCP-Server zu erfahren. Der Austausch von Paketen erfolgt ĂŒber das UDP-Protokoll. Das allgemeine Arbeitsprinzip eines GerĂ€ts bei der Anforderung von Netzparameter ist wie folgt:
- Das GerĂ€t (Client) sendet eine Broadcast-UDP-Anfrage (DHCPDISCOVER) im gesamten Netzwerk mit der Anfrage: âNa, jemand, gebt mir eine IP-Adresseâ. Ăblicherweise (aber nicht immer) erfolgt die Anfrage von Port 68 (Quelle), wĂ€hrend die Zieladresse Port 67 ist (Ziel). Einige GerĂ€te senden Pakete auch von Port 67. Innerhalb des DHCPDISCOVER-Pakets ist die MAC-Adresse des Client-GerĂ€ts enthalten.
- Alle DHCP-Server im Netzwerk (und es können mehrere sein) formulieren ein Angebot (DHCPOFFER) mit Netzwerkeinstellungen fĂŒr das GerĂ€t, das DHCPDISCOVER gesendet hat, und senden es ebenfalls als Broadcast im Netzwerk. Die Identifizierung, an wen dieses Paket gerichtet ist, erfolgt ĂŒber die MAC-Adresse des Clients, die zuvor in der DHCPDISCOVER-Anfrage bereitgestellt wurde.
- Der Client empfĂ€ngt Pakete mit Angeboten fĂŒr Netzwerkkonfigurationen, wĂ€hlt die attraktivste aus (die Kriterien können unterschiedlich sein, beispielsweise auch die Lieferzeit des Pakets oder die Anzahl der Zwischennetzwerke), und sendet an den bevorzugten DHCP-Server eine offizielle DHCP-Anfrage DHCPREQUEST mit den Netzwerkkonfigurationen. In diesem Fall geht das Paket bereits an einen bestimmten DHCP-Server.
- Der Server, der die DHCPREQUEST erhalten hat, sendet ein DHCPACK-Paket, in dem erneut die fĂŒr diesen Client vorgesehenen Netzwerkkonfigurationen aufgefĂŒhrt sind.

DarĂŒber hinaus gibt es DHCPINFORM-Pakete, die vom Client gesendet werden und deren Ziel es ist, den DHCP-Server darĂŒber zu informieren, dass der "Client aktiv" ist und die ausgegebenen Netzwerkkonfigurationen nutzt. In dieser Serverimplementierung werden diese Pakete ignoriert.
Paketformat
Im Allgemeinen sieht das Ethernet-Paket folgendermaĂen aus:
![]()
In unserem Fall betrachten wir nur die Daten des UDP-Paketinhalts, ohne die Header der OSI-Protokolle, nÀmlich die Struktur von DHCP:
DHCPDISCOVER
Der Prozess zum Erhalt 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 gibt der Client seine MAC-Adresse an und auch, was genau er vom DHCP-Server erhalten möchte. Die Paketstruktur wird in der nachstehenden Tabelle beschrieben.
Tabelle der Paketstruktur DHCPDISCOVER
Position im Paket
Name des Wertes
Beispiel
Darstellung
Byte
ErlÀuterung
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 Zwischennetzwerke
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Transaktions-ID. Wird vom Client zu Beginn der Anforderungsoperation generiert.
7
Verstrichene Zeit in Sekunden
0
Hex
4
Zeit in Sekunden seit Beginn des Prozesses zur Erlangung der Adresse
9
Bootp-Flags
0
Hex
2
Einige Flags, die gesetzt werden können, um die Protokollparameter anzugeben
11
Client-IP-Adresse
0.0.0.0
Zeichenkette
4
Die IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
0.0.0.0
Zeichenkette
4
Die vom Server vorgeschlagene IP-Adresse (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenkette
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenkette
4
IP-Adresse des Relay-Agenten (z. B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Paketabsenders (Client)
31
Client-HardwareadressenausfĂŒllung
Â
Hex
10
Reservierter Platz. Normalerweise mit Nullen gefĂŒllt.
41
Server-Hostname
Â
Zeichenkette
64
Name des DHCP-Servers. Normalerweise wird dies nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenkette
128
Dateiname auf dem Server, der von diskless Stations bei der Anmeldung verwendet wird
235
Magic-Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer unter anderem bestimmt werden kann, dass dieses Paket dem DHCP-Protokoll gehört
DHCP-Optionen. Können in beliebiger Reihenfolge auftreten
236
Optionsnummer
53
Dez
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
Dez
1
Â
Wert der Option
1
Dez
1
Â
Optionsnummer
50
Dez
1
Welche IP-Adresse möchte der Client erhalten
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
172.16.134.61
Zeichenkette
4
Â
Optionsnummer
55
Â
1
Von dem Client angeforderte Netzwerkkonfigurationen. Die Zusammensetzung kann unterschiedlich sein
01 â Subnetzmaske
03 â Gateway
06 â DNS
oc â Hostname
0f â NetzwerkdomĂ€nenname
1c â Broadcast-Adresse (Brodcast)
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
Dez
Â
Option 82, die die MAC-Adresse des GerĂ€tes â des Relais und einige zusĂ€tzliche Werte ĂŒbertrĂ€gt.
In der Regel â Port des Switches, an dem der Endclient fĂŒr DHCP arbeitet. In dieser Option sind zusĂ€tzliche Parameter "eingebettet". Das erste Byte ist die "Suboptionsnummer", das zweite ihre LĂ€nge, danach der Wert.
In diesem Fall sind in Option 82 Suboptionen eingebettet:
Agent Circuit ID = 00:04:00:01:00:04, wobei die letzten zwei Bytes der Port des DHCP-Clients sind, von dem die Anfrage kam
Agent Remote ID = 00:06:c8:be:19:93:11:48 â MAC-Adresse des RelaisgerĂ€tes fĂŒr DHCP
Â
LĂ€nge der Option
18
Dez
Â
Â
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
Dez
1
255 symbolisiert das Ende des Pakets
DHCPOFFER
Sobald der Server das Paket DHCPDISCOVER erhĂ€lt und sieht, dass er dem Client etwas aus der Anfrage anbieten kann, erstellt er eine Antwort â DHCPDISCOVER. Die Antwort wird an den Port gesendet, von dem sie kam, broadcast-mĂ€Ăig, da der Client zu diesem Zeitpunkt noch keine IP-Adresse hat und das Paket daher nur akzeptieren kann, wenn es broadcast gesendet wird. Der Client erkennt, dass dies sein Paket ist, anhand seiner MAC-Adresse im Paket sowie der Transaktionsnummer, die er beim Erstellen des ersten Pakets generiert.
Tabelle der Paketstruktur DHCPOFFER
Position im Paket
Bezeichnung des Wertes (ĂŒblich)
Beispiel
Darstellung
Byte
ErlÀuterung
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 Zwischennetzwerke
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Transaktions-ID. Wird vom Client zu Beginn der Anforderungsoperation generiert.
7
Verstrichene Zeit in Sekunden
0
Hex
4
Zeit in Sekunden seit Beginn des Prozesses zur Erlangung der Adresse
9
Bootp-Flags
0
Hex
2
Einige Flags, die gesetzt werden können, um Parameter des Protokolls anzuzeigen. In diesem Fall bedeutet 0 â Anfrage Typ Unicast
11
Client-IP-Adresse
0.0.0.0
Zeichenkette
4
Die IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenkette
4
Die vom Server vorgeschlagene IP-Adresse (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenkette
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenkette
4
IP-Adresse des Relay-Agenten (z. B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Paketabsenders (Client)
31
Client-HardwareadressenausfĂŒllung
Â
Hex
10
Reservierter Platz. Normalerweise mit Nullen gefĂŒllt.
41
Server-Hostname
Â
Zeichenkette
64
Name des DHCP-Servers. Normalerweise wird dies nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenkette
128
Dateiname auf dem Server, der von diskless Stations bei der Anmeldung verwendet wird
235
Magic-Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer unter anderem bestimmt werden kann, dass dieses Paket dem DHCP-Protokoll gehört
DHCP-Optionen. Können in beliebiger Reihenfolge auftreten
236
Optionsnummer
53
Dez
1
Option 53, die den Typ des DHCP-Pakets definiert 2 â DHCPOFFER
Â
LĂ€nge der Option
1
Dez
1
Â
Wert der Option
2
Dez
1
Â
Optionsnummer
1
Dez
1
Option, die dem DHCP-Client eine Subnetzmaske anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
255.255.224.0
Zeichenkette
4
Â
Optionsnummer
3
Dez
1
Option, die dem DHCP-Client ein Standardgateway anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
172.16.12.1
Zeichenkette
4
Â
Optionsnummer
6
Dez
1
Option, die dem DHCP-Client einen DNS anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
8.8.8.8
Zeichenkette
4
Â
Optionsnummer
51
Dez
1
Die Lebensdauer der vergebenen Netzwerkkonfigurationen in Sekunden, nach denen der DHCP-Client diese erneut anfordern muss
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
86400
Dez
4
Â
Optionsnummer
82
Dez
1
Option 82, die wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dez
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18
Â
Ende des Pakets
255
Dez
1
255 symbolisiert das Ende des Pakets
DHCPREQUEST
Nachdem der Client das DHCPOFFER erhalten hat, erstellt er ein Paket mit der Anfrage der Netzwerkeinstellungen nicht fĂŒr alle DHCP-Server im Netzwerk, sondern nur fĂŒr einen bestimmten, dessen DHCPOFFER ihm am meisten "gefiel". Die Kriterien, die das "Gefallen" bestimmen, können unterschiedlich sein und hĂ€ngen von der Implementierung des DHCP-Clients ab. Der EmpfĂ€nger der Anfrage wird ĂŒber die MAC-Adresse des DHCP-Servers angegeben. Das DHCPREQUEST-Paket kann auch vom Client ohne vorherige Dhcpdiscover-Anfrage gesendet werden, wenn die IP-Adresse vom Server zuvor bereits erhalten wurde.
Tabelle der Struktur des DHCPREQUEST-Pakets
Position im Paket
Bezeichnung des Wertes (ĂŒblich)
Beispiel
Darstellung
Byte
ErlÀuterung
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 Zwischennetzwerke
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Transaktions-ID. Wird vom Client zu Beginn der Anforderungsoperation generiert.
7
Verstrichene Zeit in Sekunden
0
Hex
4
Zeit in Sekunden seit Beginn des Prozesses zur Erlangung 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 es auf "Broadcast" gesetzt.
11
Client-IP-Adresse
0.0.0.0
Zeichenkette
4
Die IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenkette
4
Die vom Server vorgeschlagene IP-Adresse (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenkette
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenkette
4
IP-Adresse des Relay-Agenten (z. B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Paketabsenders (Client)
31
Client-HardwareadressenausfĂŒllung
Â
Hex
10
Reservierter Platz. Normalerweise mit Nullen gefĂŒllt.
41
Server-Hostname
Â
Zeichenkette
64
Name des DHCP-Servers. Normalerweise wird dies nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenkette
128
Dateiname auf dem Server, der von diskless Stations bei der Anmeldung verwendet wird
235
Magic-Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer unter anderem bestimmt werden kann, dass dieses Paket dem DHCP-Protokoll gehört
DHCP-Optionen. Können in beliebiger Reihenfolge auftreten
236
Optionsnummer
53
Dez
3
Option 53, die den Typ des DHCP-Pakets 3 â DHCPREQUEST definiert
Â
LĂ€nge der Option
1
Dez
1
Â
Wert der Option
3
Dez
1
Â
Optionsnummer
61
Dez
1
Kundenkennung: 01 (fĂŒr Ethernet) + MAC-Adresse des Clients
Â
LĂ€nge der Option
7
Dez
1
Â
Wert der Option
01:2c:ab:25:ff:72:a6
Hex
7
Â
Optionsnummer
60
Dez
Â
"Vendor class identifier". In meinem Fall gibt es die Version des DHCP-Clients an. Möglicherweise geben andere GerĂ€te etwas anderes zurĂŒck. Windows beispielsweise meldet MSFT 5.0.
Â
LĂ€nge der Option
11
Dez
Â
Â
Wert der Option
udhcp 0.9.8
Zeichenkette
Â
Â
Optionsnummer
55
Â
1
Von dem Client angeforderte Netzwerkkonfigurationen. Die Zusammensetzung kann unterschiedlich sein
01 â Subnetzmaske
03 â Gateway
06 â DNS
oc â Hostname
0f â NetzwerkdomĂ€nenname
1c â Broadcast-Adresse (Brodcast)
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
Dez
1
Option 82, die wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dez
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18
Â
Ende des Pakets
255
Dez
1
255 symbolisiert das Ende des Pakets
DHCPACK
Als BestĂ€tigung, dass "ja, das ist deine IP-Adresse, und ich werde sie niemand anderem geben", dient das Paket im Format DHCPACK vom DHCP-Server an den Client. Es wird, wie die anderen Pakete, ebenfalls broadcasted. Allerdings dupliziere ich im folgenden Code des in Python implementierten DHCP-Servers vorsichtshalber jede Broadcast-Anfrage, indem ich ein Paket an eine bestimmte IP-Adresse des Clients sende, wenn diese bereits bekannt ist. Der DHCP-Server interessiert sich jedoch ĂŒberhaupt nicht dafĂŒr, ob das DHCPACK-Paket den Client erreicht hat. ErhĂ€lt der Client kein DHCPACK, wiederholt er einfach nach einer gewissen Zeit das DHCPREQUEST.
Tabelle der Struktur des DHCPACK-Pakets
Position im Paket
Bezeichnung des Wertes (ĂŒblich)
Beispiel
Darstellung
Byte
ErlÀuterung
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 Zwischennetzwerke
5
Transaktions-ID
23:cf:de:1d
Hex
4
Eindeutige Transaktions-ID. Wird vom Client zu Beginn der Anforderungsoperation generiert.
7
Verstrichene Zeit in Sekunden
0
Hex
4
Zeit in Sekunden seit Beginn des Prozesses zur Erlangung 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 es auf "Broadcast" gesetzt.
11
Client-IP-Adresse
0.0.0.0
Zeichenkette
4
Die IP-Adresse des Clients (falls vorhanden)
15
Ihre Client-IP-Adresse
172.16.134.61
Zeichenkette
4
Die vom Server vorgeschlagene IP-Adresse (falls vorhanden)
19
NĂ€chste Server-IP-Adresse
0.0.0.0
Zeichenkette
4
IP-Adresse des Servers (falls bekannt)
23
Relay-Agent-IP-Adresse
172.16.114.41
Zeichenkette
4
IP-Adresse des Relay-Agenten (z. B. Switch)
27
Client-MAC-Adresse
14:d6:4d:a7:c9:55
Hex
6
MAC-Adresse des Paketabsenders (Client)
31
Client-HardwareadressenausfĂŒllung
Â
Hex
10
Reservierter Platz. Normalerweise mit Nullen gefĂŒllt.
41
Server-Hostname
Â
Zeichenkette
64
Name des DHCP-Servers. Normalerweise wird dies nicht ĂŒbertragen.
105
Boot-Dateiname
Â
Zeichenkette
128
Dateiname auf dem Server, der von diskless Stations bei der Anmeldung verwendet wird
235
Magic-Cookie
63:82:53:63
Hex
4
Die "magische" Zahl, anhand derer unter anderem bestimmt werden kann, dass dieses Paket dem DHCP-Protokoll gehört
DHCP-Optionen. Können in beliebiger Reihenfolge auftreten
236
Optionsnummer
53
Dez
3
Option 53, die den Typ des DHCP-Pakets 5 â DHCPACK definiert
Â
LĂ€nge der Option
1
Dez
1
Â
Wert der Option
5
Dez
1
Â
Optionsnummer
1
Dez
1
Option, die dem DHCP-Client eine Subnetzmaske anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
255.255.224.0
Zeichenkette
4
Â
Optionsnummer
3
Dez
1
Option, die dem DHCP-Client ein Standardgateway anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
172.16.12.1
Zeichenkette
4
Â
Optionsnummer
6
Dez
1
Option, die dem DHCP-Client einen DNS anbietet
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
8.8.8.8
Zeichenkette
4
Â
Optionsnummer
51
Dez
1
Die Lebensdauer der vergebenen Netzwerkkonfigurationen in Sekunden, nach denen der DHCP-Client diese erneut anfordern muss
Â
LĂ€nge der Option
4
Dez
1
Â
Wert der Option
86400
Dez
4
Â
Optionsnummer
82
Dez
1
Option 82, die wiederholt, was im DHCPDISCOVER empfangen wurde
Â
LĂ€nge der Option
18
Dez
1
Â
Wert der Option
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18
Â
Ende des Pakets
255
Dez
1
255 symbolisiert das Ende des Pakets
Installation
Die Einrichtung besteht tatsÀchlich darin, die benötigten 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 das 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')Jetzt detaillierter zu den Tags:
Der Abschnitt dhcpserver beschreibt die grundlegenden Einstellungen zum Starten des Servers, nÀmlich:
- host â welche IP-Adresse der Server am Port 67 abfĂ€ngt.
- broadcast â welche IP-Adresse fĂŒr DHCPOFFER und DHCPACK verwendet wird.
- DHCPServer â welche IP-Adresse der DHCP-Server hat.
- LeaseTime â die Zeit, fĂŒr die die zugewiesene IP-Adresse gĂŒltig ist.
- ThreadLimit â wie viele Threads gleichzeitig zur Verarbeitung der eingehenden UDP-Pakete am Port 67 aktiv sind. Es wird angenommen, dass dies bei stark ausgelasteten Projekten hilft đ.
- 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.
Abschnitt mysql:
host, username, password, basename â alles erklĂ€rt sich von selbst. Eine Beispielform der Datenbankstruktur wird bereitgestellt auf
Abschnitt query: Hier sind die Abfragen zur Beschaffung von OFFER/ACK beschrieben:
- offer_count â die Anzahl der Zeilen mit Anfragen, die ein Ergebnis in der Form ip, mask, router, dns zurĂŒckgeben.
- offer_n â Anfragenzeile. Wenn die RĂŒckgabe leer ist, wird die nĂ€chste Anfrage offer ausgefĂŒhrt.
- history_sql â eine Abfrage, die beispielsweise in die 'Authentifizierungshistorie' fĂŒr den Abonnenten schreibt.
In den Abfragen können beliebige Variablen aus dem Abschnitt options oder Optionen aus dem DHCP-Protokoll verwendet werden.
Abschnitt options. Hier wird es interessanter. Hier können wir Variablen erstellen, die wir spÀter im Abschnitt query verwenden können.
Zum Beispiel:
option_82_hex:sw_port1:20:22, dieser Befehl nimmt die gesamte Zeile aus der DHCP-Anfrage Option 82 im Hex-Format im Bereich von Byte 20 bis 22 (einschlieĂlich) und legt sie in einer neuen Variablen sw_port1 ab (Switch-Port, von dem die Anfrage kam)
option_82_hex:sw_mac:26:40, wir definieren die Variable sw_mac, indem wir den Hex-Wert aus dem Bereich 26:40 nehmen
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 etwa folgendes Protokoll:
--es kam ein Paket DHCPINFORM an Port 67 von 0025224ad764, b'x91xa5xe0xa3xa5xa9-x8fx8a', ('172.30.114.25', 68)
{'ClientMacAddress': '0025224ad764',
'ClientMacAddressByte': b'x00%"Jxd7d',
'HType': 'Ethernet',
'HostName': b'x91xa5xe0xa3xa5xa9-x8fx8a',
'ReqListDNS': True,
'ReqListDomainName': True,
'ReqListRouterDiscover': 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'}Daher können wir jede Variable in {} einschlieĂen, und sie wird im SQL-Abfrage verwendet.
Lassen Sie uns zur Dokumentation festhalten, welche IP-Adresse der Client erhalten hat:


Server starten
.\/pydhcpdb.py -d -c config.xml
â d Modus fĂŒr DEBUG-Ausgabe in der Konsole
â c Konfigurationsdatei
ĂberprĂŒfung der Funktionsweise
Nun also ausfĂŒhrlicher zur Umsetzung des Servers in Python. Das ist schmerzhaft. Python wurde "on the fly" gelernt. Viele Aspekte wurden nach dem Motto umgesetzt: "Wow, das habe ich irgendwie gemacht, es funktioniert." Völlig unoptimiert und in dieser Form belassen, hauptsĂ€chlich wegen geringer Erfahrung in der Python-Entwicklung. Ich werde mich auf die interessantesten Aspekte der Server-Implementierung im "Code" konzentrieren.
Parser fĂŒr die XML-Konfigurationsdatei
Es wird das Standardmodul Python xml.dom verwendet. Es scheint einfach zu sein, aber bei der Implementierung hat es merklich an brauchbarer Dokumentation und Beispielen im Netz gefehlt, die dieses Modul verwenden.
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
Es ist ĂŒberraschend, dass Multithreading in Python sehr klar und einfach umgesetzt ist.
def PacketWork(data, addr):
...
# Implementierung der Analyse des eingehenden Pakets und der Antwort darauf
...
while True:
data, addr = udp_socket.recvfrom(1024) # Warten auf ein UDP-Paket
thread = threading.Thread(target=PacketWork, args=(data, addr,)).start() # Sobald es ankommt, starten wir die vorher 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 höher ist als in den Einstellungen, warten wir, bis es weniger werdenEmpfang/Versand von DHCP-Paketen
Um UDP-Pakete, die ĂŒber die Netzwerkkarte gehen, abzufangen, muss der Socket "hochgefahren" 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 Adressformat IP:Port sein wird. Es kann auch AF_UNIX geben â wobei die Adresse durch einen Dateinamen angegeben wird.
- SOCK_DGRAM bedeutet, dass wir kein ârohes Paketâ empfangen, sondern bereits ein Paket, das durch die Firewall gefiltert und teilweise abgeschnitten wurde. Das heiĂt, 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 sowohl per Broadcast erfolgen:
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #legen den Socket in den Broadcast-Modus
rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68)), als auch an die Adresse, âvon der das Paket kamâ:
udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #legen den Socket in den Modus "mehrere Zuhörer"
rz=udp_socket.sendto(packetack, addr), wobei SOL_SOCKET âProtokollebeneâ zum Setzen der Optionen bedeutet,
, SO_BROADCAST die Option ist, dass das Paket âper 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 erforderlich, aber auf einem der FreeBSD-Server, auf dem 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 aus der âBoxâ recht flexibel mit Bytecode umgehen kann. Es ermöglicht, diesen sehr einfach in dezimale Werte, Strings und Hex zu ĂŒbersetzen â also genau das, was wir brauchen, um die Struktur des Pakets zu verstehen. So kann man beispielsweise einen Bereich von Bytes in HEX und einfach in Bytes erhalten:
res["xidhex"]=data[4:8].hex()
res["xidbyte"]=data[4:8], die Bytes in eine Struktur packen:
res["flags"]=pack('BB',data[10],data[11])Die 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"])
Das ist alles đ
Quelle: habr.com
