
A projekt célja a következő volt:
- A DHCP protokoll tanulmányozása az IPv4 hálózaton
- Python tanulmányozása (kicsit több mint nulláról 😉 )
- szervercsere (az én fork-om), az eredeti , amelyet egyre nehezebb összeállítani az új operációs rendszerhez. Ráadásul nem tetszik, hogy a bináris fájlt, amit "nem lehet most azonnal kicserélni"
- működő DHCP szerver létrehozása, amely lehetővé teszi az IP cím kiválasztását a kliens MAC címe vagy a MAC/Webswitch + port kombinációja (82. opció) alapján
- a következő kerék feltalálása (Ó! Ez a kedvenc időtöltésem)
- a ügyetlenségem miatt szerzett kritikák a HabrHabr-on (vagy inkább az invitálás 😉 miatt)
Eredmény: működik 😉 Kipróbáltam FreeBSD és Ubuntu rendszereken. Elméletileg a kód bármilyen operációs rendszer alatt futtatható, mivel a kódban nincs specifikus kötődés.
Vigyázat! Sok jön még.
Link a repóhoz az érdeklődőknek .
Az installálás, beállítás és az "anyag ismeretének" eredményének használata lentebb található, ezután egy kis elmélet a DHCP protokollról. Magam számára. És a történelem kedvéért 😉
Kis elmélet
Mi az a DHCP
Ez egy hálózati protokoll, amely lehetővé teszi, hogy az eszköz megtudja az IP címét (és más paramétereket, mint a gateway, DNS és hasonlók) a DHCP szervertől. A csomagok cseréje UDP protokollon történik. Az eszköz működésének általános elve a hálózati beállítások kérésénél a következő:
- Az eszköz (klient) egy széleskörű UDP kérést (DHCPDISCOVER) küld szét a hálózaton "valaki, adjatok nekem IP címet" kérdéssel. Általában (de nem mindig) a kérés a 68-as porton (forrás), míg a cél a 67-es port (cél). Néhány eszköz a 67-es portról is küld csomagokat. A DHCPDISCOVER csomagban benne van a kliens MAC címe.
- Minden DHCP szerver a hálózaton (amelyből több is lehet) javaslatot formál az eszköz számára, amely elküldte a DHCPDISCOVER-t, egy DHCPOFFER-t a hálózati beállításokkal, és azt széleskörűen elküldi a hálózaton. A csomag címzettjének azonosítása a kliens által a DHCPDISCOVER kérésben megadott MAC címen keresztül történik.
- A kliens fogadja a hálózati beállításokkal kapcsolatos ajánlattételeket, kiválasztja a legvonzóbbakat (a kritériumok változatosak lehetnek, például a csomag kézbesítési ideje vagy az átjárók száma), és a kedvelt DHCP szervertől "hivatalos kérdést" küld a DHCPREQUEST üzenettel a hálózati beállításokkal. Ekkor a csomag már egy konkrét DHCP szerverhez kerül.
- A DHCPREQUEST üzenetet kapó szerver DHCPACK formátumú csomagot küld vissza, amelyben újra felsorolja az adott kliens számára szánt hálózati beállításokat.

Ezen kívül léteznek DHCPINFORM csomagok is, amelyek a klienstől érkeznek, és céljuk, hogy tájékoztassák a DHCP szervert arról, hogy "a kliens él" és használja a rendelkezésre bocsátott hálózati beállításokat. Ezen szerver megvalósítása során ezek a csomagok figyelmen kívül maradnak.
Csomagformátum
Általánosságban az Ethernet csomag kerete körülbelül így néz ki:
![]()
Ebben az esetben csak a UDP csomag tartalmával foglalkozunk, a rétegek protokollfejlécétől eltekintve, nevezetesen a DHCP struktúrájával:
DHCPDISCOVER
Tehát az IP cím megszerzésének folyamata azzal kezdődik, hogy a DHCP kliens széles körű kérdést küld a 68-as portból a 255.255.255.255:67 címre. Ebben a csomagban a kliens belefoglalta a MAC címét, valamint azt, hogy mit szeretne a DHCP szervertől kapni. A csomag szerkezete az alábbi táblázatban van leírva.
A DHCPDISCOVER csomag szerkezetének táblázata
Pozíció a csomagban
Érték neve
támadásra
Képviselet
Bájt
Magyarázat
1
Boot Request
1
Hex
1
Üzenettípus. 1 — kérés a klienstől a szerverhez, 2 — válasz a szervertől a kliensnek.
2
Hardver típusa
1
Hex
1
A hardver cím típusa, ebben a protokollban 1 — MAC
3
Hardver cím hossza
6
Hex
1
A készülék MAC címének hossza
4
Hops
1
Hex
1
Átjárók száma
5
Tranzakciós azonosító
23:cf:de:1d
Hex
4
Egyedi tranzakciós azonosító. A kliens generálja a kérés művelet kezdetén.
7
Eltelt másodpercek
0
Hex
4
Idő másodpercben a cím megszerzésének folyamatának kezdetétől.
9
Bootp zászlók
0
Hex
2
Néhány zászló, amely beállítható a protokoll paramétereinek megadására.
11
Kliens IP cím
0.0.0.0
A sor
4
A kliens IP címe (ha van)
15
Az Ön kliens IP címe
0.0.0.0
A sor
4
A szerver által javasolt IP cím (ha van)
19
Következő szerver IP címe
0.0.0.0
A sor
4
A szerver IP címe (ha ismert)
23
Közvetítő ügynök IP címe
172.16.114.41
A sor
4
A közvetítő ügynök IP címe (például kapcsoló)
27
Kliens MAC cím
14:d6:4d:a7:c9:55
Hex
6
A csomag küldőjének (kliense) MAC címe.
31
Kliens hardver címének kitöltése
Hex
10
Fenntartott hely. Általában nullákkal van feltöltve.
41
Szerver hoszt neve
A sor
64
A DHCP szerver neve. Általában nem kerül átadásra.
105
Boot fájl neve
A sor
128
A fájl neve a szerveren, amelyet a lemezkép nélküli állomások használnak a betöltés során
235
Mágikus süti
63:82:53:63
Hex
4
A "mágikus" szám, amellyel például meg lehet határozni, hogy ez a csomag a DHCP protokollhoz tartozik
DHCP opciók. Bármilyen sorrendben érkezhetnek
236
Opció száma
53
Dec
1
53-as opció, amely meghatározza a DHCP csomag típusát
1 — DHCPDISCOVER
3 — DHCPREQUEST
2 — DHCPOFFER
5 — DHCPACK
8 — DHCPINFORM
Az opció hossza
1
Dec
1
Az opció értéke
1
Dec
1
Opció száma
50
Dec
1
Milyen IP címet szeretne kapni az ügyfél
Az opció hossza
4
Dec
1
Az opció értéke
172.16.134.61
A sor
4
Opció száma
55
1
A kliens által kért hálózati paraméterek. Az összetevők eltérhetnek
01 — Hálózati maszk
03 — Átjáró
06 — DNS
oc — Gazdagép neve
0f — A hálózat domain neve
1c — Széleskörű kérés (broadcast) címe
42 — TFTP szerver neve
79 — Osztály nélküli statikus útvonal
Az opció hossza
8
1
Az opció értéke
01:03:06:0c:0f:1c:42:79
8
Opció száma
82
Dec
82-es opció, amely tartalmazza az eszköz MAC címét — a visszavarót és néhány további értéket.
Leggyakrabban — a kapcsoló portja, ahol a végső DHCP kliens működik. Ebben az opcióban "beágyazott" további paraméterek találhatók. Az első bájt — a "megalapozó" száma, a második a hossza, aztán következik az értéke.
Ebben az esetben a 82-es opcióban beágyazott megalapozások találhatók:
Agent Circuit ID = 00:04:00:01:00:04, ahol az utolsó két bájt — a DHCP kliens portja, ahonnan a kérés érkezett
Agent Remote ID = 00:06:c8:be:19:93:11:48 — a DHCP visszavaro MAC címe
Az opció hossza
18
Dec
Az opció értéke
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
A csomag vége
255
Dec
1
255 jelzi a csomag végét
DHCPOFFER
Amint a szerver megkapja a DHCPDISCOVER csomagot, és látja, hogy tud ajánlani valamit a kért paraméterek közül, vissza kell formáznia a választ — DHCPDISCOVER. A válasz az "onnan jött" portra kerül elküldésre, széleskörűen, mivel ebben a pillanatban a kliensnek még nincs IP címe, tehát a csomagot csak akkor tudja elfogadni, ha azt széleskörűen küldték. A kliens a MAC cím szerint, valamint a tranzakciós szám alapján ismeri fel, amelyet az első csomag létrehozásakor generál.
A DHCPOFFER csomag struktúrájának táblázata
Pozíció a csomagban
A népszerű érték neve
támadásra
Képviselet
Bájt
Magyarázat
1
Boot Request
1
Hex
1
Üzenettípus. 1 — kérés a klienstől a szerverhez, 2 — válasz a szervertől a kliensnek.
2
Hardver típusa
1
Hex
1
A hardver cím típusa, ebben a protokollban 1 — MAC
3
Hardver cím hossza
6
Hex
1
A készülék MAC címének hossza
4
Hops
1
Hex
1
Átjárók száma
5
Tranzakciós azonosító
23:cf:de:1d
Hex
4
Egyedi tranzakciós azonosító. A kliens generálja a kérés művelet kezdetén.
7
Eltelt másodpercek
0
Hex
4
Idő másodpercben a cím megszerzésének folyamatának kezdetétől.
9
Bootp zászlók
0
Hex
2
Bizonyos zászlók, amelyek beállíthatók a protokoll paramétereinek meghatározására. Ebben az esetben 0 — unicast kérés típust jelent
11
Kliens IP cím
0.0.0.0
A sor
4
A kliens IP címe (ha van)
15
Az Ön kliens IP címe
172.16.134.61
A sor
4
A szerver által javasolt IP cím (ha van)
19
Következő szerver IP címe
0.0.0.0
A sor
4
A szerver IP címe (ha ismert)
23
Közvetítő ügynök IP címe
172.16.114.41
A sor
4
A közvetítő ügynök IP címe (például kapcsoló)
27
Kliens MAC cím
14:d6:4d:a7:c9:55
Hex
6
A csomag küldőjének (kliense) MAC címe.
31
Kliens hardver címének kitöltése
Hex
10
Fenntartott hely. Általában nullákkal van feltöltve.
41
Szerver hoszt neve
A sor
64
A DHCP szerver neve. Általában nem kerül átadásra.
105
Boot fájl neve
A sor
128
A fájl neve a szerveren, amelyet a lemezkép nélküli állomások használnak a betöltés során
235
Mágikus süti
63:82:53:63
Hex
4
A "mágikus" szám, amellyel például meg lehet határozni, hogy ez a csomag a DHCP protokollhoz tartozik
DHCP opciók. Bármilyen sorrendben érkezhetnek
236
Opció száma
53
Dec
1
53-as opció, amely meghatározza a DHCP csomag típusát 2 — DHCPOFFER
Az opció hossza
1
Dec
1
Az opció értéke
2
Dec
1
Opció száma
1
Dec
1
Opció, amely az ügyfél számára hálózati maszkot ajánl
Az opció hossza
4
Dec
1
Az opció értéke
255.255.224.0
A sor
4
Opció száma
3
Dec
1
Opció, amely az ügyfél számára alapértelmezett átjárót ajánl
Az opció hossza
4
Dec
1
Az opció értéke
172.16.12.1
A sor
4
Opció száma
6
Dec
1
Opció, amely az ügyfél számára DNS-t ajánl
Az opció hossza
4
Dec
1
Az opció értéke
8.8.8.8
A sor
4
Opció száma
51
Dec
1
A kiadott hálózati paraméterek élettartama másodpercben, amellyel a DHCP kliensnek újra kell kérnie őket
Az opció hossza
4
Dec
1
Az opció értéke
86400
Dec
4
Opció száma
82
Dec
1
82-es opció, amely megismétli a DHCPDISCOVER-ben érkezett információkat
Az opció hossza
18
Dec
1
Az opció értéke
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
A csomag vége
255
Dec
1
255 jelzi a csomag végét
DHCPREQUEST
Miután az ügyfél megkapja a DHCPOFFER-t, egy csomagot hoz létre, amelyben már nem minden DHCP szerverhez kéri a hálózati paramétereket a hálózaton, hanem csak egy konkrét szerverhez, akinek a DHCPOFFER ajánlata a legjobban "tetszett". A "tetszés" kritériumai különbözőek lehetnek, és a DHCP kliens megvalósításától függenek. A kérés címzettjét a DHCP szerver MAC címével határozzák meg. A DHCPREQUEST csomagot az ügyfél a DHCPDISCOVER előállítása nélkül is elküldheti, ha az IP-cím már korábban megvolt a szervertől.
A DHCPREQUEST csomag struktúrájának táblázata
Pozíció a csomagban
A népszerű érték neve
támadásra
Képviselet
Bájt
Magyarázat
1
Boot Request
1
Hex
1
Üzenettípus. 1 — kérés a klienstől a szerverhez, 2 — válasz a szervertől a kliensnek.
2
Hardver típusa
1
Hex
1
A hardver cím típusa, ebben a protokollban 1 — MAC
3
Hardver cím hossza
6
Hex
1
A készülék MAC címének hossza
4
Hops
1
Hex
1
Átjárók száma
5
Tranzakciós azonosító
23:cf:de:1d
Hex
4
Egyedi tranzakciós azonosító. A kliens generálja a kérés művelet kezdetén.
7
Eltelt másodpercek
0
Hex
4
Idő másodpercben a cím megszerzésének folyamatának kezdetétől.
9
Bootp zászlók
8000
Hex
2
Bizonyos zászlók, amelyek beállíthatók, mint a protokoll paramétereinek jelzése. Esetünkben a "broadcast" van beállítva.
11
Kliens IP cím
0.0.0.0
A sor
4
A kliens IP címe (ha van)
15
Az Ön kliens IP címe
172.16.134.61
A sor
4
A szerver által javasolt IP cím (ha van)
19
Következő szerver IP címe
0.0.0.0
A sor
4
A szerver IP címe (ha ismert)
23
Közvetítő ügynök IP címe
172.16.114.41
A sor
4
A közvetítő ügynök IP címe (például kapcsoló)
27
Kliens MAC cím
14:d6:4d:a7:c9:55
Hex
6
A csomag küldőjének (kliense) MAC címe.
31
Kliens hardver címének kitöltése
Hex
10
Fenntartott hely. Általában nullákkal van feltöltve.
41
Szerver hoszt neve
A sor
64
A DHCP szerver neve. Általában nem kerül átadásra.
105
Boot fájl neve
A sor
128
A fájl neve a szerveren, amelyet a lemezkép nélküli állomások használnak a betöltés során
235
Mágikus süti
63:82:53:63
Hex
4
A "mágikus" szám, amellyel például meg lehet határozni, hogy ez a csomag a DHCP protokollhoz tartozik
DHCP opciók. Bármilyen sorrendben érkezhetnek
236
Opció száma
53
Dec
3
53-as opció, amely meghatározza a DHCP csomag típusát 3 - DHCPREQUEST
Az opció hossza
1
Dec
1
Az opció értéke
3
Dec
1
Opció száma
61
Dec
1
Ügyfél azonosító: 01 (Ethernet számára) + ügyfél MAC címe
Az opció hossza
7
Dec
1
Az opció értéke
01:2c:ab:25:ff:72:a6
Hex
7
Opció száma
60
Dec
"Vendor class identifier". Az én esetemben a DHCP kliens verzióját közli. Lehetséges, hogy más eszközök más dolgot adnak vissza. A Windows például MSFT 5.0-t jelez.
Az opció hossza
11
Dec
Az opció értéke
udhcp 0.9.8
A sor
Opció száma
55
1
A kliens által kért hálózati paraméterek. Az összetevők eltérhetnek
01 — Hálózati maszk
03 — Átjáró
06 — DNS
oc — Gazdagép neve
0f — A hálózat domain neve
1c — Széleskörű kérés (broadcast) címe
42 — TFTP szerver neve
79 — Osztály nélküli statikus útvonal
Az opció hossza
8
1
Az opció értéke
01:03:06:0c:0f:1c:42:79
8
Opció száma
82
Dec
1
82-es opció, amely megismétli a DHCPDISCOVER-ben érkezett információkat
Az opció hossza
18
Dec
1
Az opció értéke
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
A csomag vége
255
Dec
1
255 jelzi a csomag végét
DHCPACK
A DHCP szerver által az ügyfélhez küldött DHCPACK csomag, mint a megerősítés arra, hogy "igen, ez a te IP-címed, és senkinek másnak nem adom ki", szolgál. Ugyanúgy, mint a többi csomag, széles körben kerül kiküldésre. Bár az alább bemutatott Python nyelven megvalósított DHCP szerverben minden széles körben küldött kérést megismétlek egy adott ügyfél IP-címére, ha az már ismert. A DHCP szerver számára nem számít, hogy a DHCPACK csomag eljutott-e az ügyfélhez. Ha az ügyfél nem kap DHCPACK-ot, idővel egyszerűen megismétli a DHCPREQUEST-t.
A DHCPACK csomag struktúrájának táblázata
Pozíció a csomagban
A népszerű érték neve
támadásra
Képviselet
Bájt
Magyarázat
1
Boot Request
2
Hex
1
Üzenettípus. 1 — kérés a klienstől a szerverhez, 2 — válasz a szervertől a kliensnek.
2
Hardver típusa
1
Hex
1
A hardver cím típusa, ebben a protokollban 1 — MAC
3
Hardver cím hossza
6
Hex
1
A készülék MAC címének hossza
4
Hops
1
Hex
1
Átjárók száma
5
Tranzakciós azonosító
23:cf:de:1d
Hex
4
Egyedi tranzakciós azonosító. A kliens generálja a kérés művelet kezdetén.
7
Eltelt másodpercek
0
Hex
4
Idő másodpercben a cím megszerzésének folyamatának kezdetétől.
9
Bootp zászlók
8000
Hex
2
Bizonyos zászlók, amelyek beállíthatók, mint a protokoll paramétereinek jelzése. Esetünkben a "broadcast" van beállítva.
11
Kliens IP cím
0.0.0.0
A sor
4
A kliens IP címe (ha van)
15
Az Ön kliens IP címe
172.16.134.61
A sor
4
A szerver által javasolt IP cím (ha van)
19
Következő szerver IP címe
0.0.0.0
A sor
4
A szerver IP címe (ha ismert)
23
Közvetítő ügynök IP címe
172.16.114.41
A sor
4
A közvetítő ügynök IP címe (például kapcsoló)
27
Kliens MAC cím
14:d6:4d:a7:c9:55
Hex
6
A csomag küldőjének (kliense) MAC címe.
31
Kliens hardver címének kitöltése
Hex
10
Fenntartott hely. Általában nullákkal van feltöltve.
41
Szerver hoszt neve
A sor
64
A DHCP szerver neve. Általában nem kerül átadásra.
105
Boot fájl neve
A sor
128
A fájl neve a szerveren, amelyet a lemezkép nélküli állomások használnak a betöltés során
235
Mágikus süti
63:82:53:63
Hex
4
A "mágikus" szám, amellyel például meg lehet határozni, hogy ez a csomag a DHCP protokollhoz tartozik
DHCP opciók. Bármilyen sorrendben érkezhetnek
236
Opció száma
53
Dec
3
53-as opció, amely meghatározza a DHCP csomag típusát 5 - DHCPACK
Az opció hossza
1
Dec
1
Az opció értéke
5
Dec
1
Opció száma
1
Dec
1
Opció, amely az ügyfél számára hálózati maszkot ajánl
Az opció hossza
4
Dec
1
Az opció értéke
255.255.224.0
A sor
4
Opció száma
3
Dec
1
Opció, amely az ügyfél számára alapértelmezett átjárót ajánl
Az opció hossza
4
Dec
1
Az opció értéke
172.16.12.1
A sor
4
Opció száma
6
Dec
1
Opció, amely az ügyfél számára DNS-t ajánl
Az opció hossza
4
Dec
1
Az opció értéke
8.8.8.8
A sor
4
Opció száma
51
Dec
1
A kiadott hálózati paraméterek élettartama másodpercben, amellyel a DHCP kliensnek újra kell kérnie őket
Az opció hossza
4
Dec
1
Az opció értéke
86400
Dec
4
Opció száma
82
Dec
1
82-es opció, amely megismétli a DHCPDISCOVER-ben érkezett információkat
Az opció hossza
18
Dec
1
Az opció értéke
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
A csomag vége
255
Dec
1
255 jelzi a csomag végét
Telepítés
A telepítés tulajdonképpen a szükséges python modulok telepítését jelenti a működéshez. Feltételezzük, hogy a MySQL már telepítve és konfigurálva van.
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
Hozzunk létre egy MySQL adatbázist, töltsük fel a pydhcp.sql dumpot, és állítsuk be a konfigurációs fájlt.
Konfiguráció
Minden szerverbeállítás egy xml formátumú fájlban található. Az etalon fájl:
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')Mostrando más sobre las etiquetas:
La sección dhcpserver describe la configuración básica para el funcionamiento del servidor, específicamente:
- host — qué dirección IP está escuchando el servidor en el puerto 67
- broadcast — qué IP es el broadcast para DHCPOFFER y DHCPACK
- DHCPServer — qué IP tiene el servidor DHCP
- LeaseTime es el tiempo de arrendamiento de la dirección IP otorgada
- ThreadLimit — cuántos hilos se ejecutan simultáneamente para procesar los paquetes UDP recibidos en el puerto 67. Se supone que esto ayudará en proyectos de alta carga 😉
- defaultMask, defaultRouter, defaultDNS — lo que se ofrece al suscriptor por defecto, si la IP se encuentra en la base, pero no se indican parámetros adicionales
Sección mysql:
host, username, password, basename — todo se explica por sí mismo. La estructura aproximada de la base de datos se puede encontrar en
Sección query: aquí se describen las consultas para obtener OFFER/ACK:
- offer_count — el número de filas con consultas que devuelven resultados del tipo ip, mask, router, dns
- offer_n — string de la consulta. Si la devolución es vacía, se ejecuta la siguiente consulta offer
- history_sql — consulta que escribe, por ejemplo, en 'historia de autorización' del suscriptor
En las consultas pueden participar cualquier variable de la sección options o las opciones del protocolo DHCP.
Sección options. Aquí es donde se vuelve más interesante. Aquí podemos crear variables que podemos usar más adelante en la sección query.
Például:
option_82_hex:sw_port1:20:22, ez a parancssor veszi az összes DHCP kérésben érkező 82-es opciót, hex formátumban, a 20-22 bájt között, beleértve, és egy új változóba, sw_port1-be (a kapcsoló port, ahonnan a kérés érkezett) helyezi.
option_82_hex:sw_mac:26:40, határozzuk meg a sw_mac változót, kivéve a hex értéket a 26:40 tartományból.
A rendelkezésre álló összes lehetőség megtekintéséhez, amelyeket a kérésekben használhatunk, a szerver -d kapcsolóval való indításával lehetséges. Körülbelül ilyen naplókat fogunk látni:
--érkezett a DHCPINFORM csomag a 67-es porton, a következőtől: 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,
'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'}Így bármilyen változót {}-be burkolhatunk, és az felhasználható SQL lekérdezésekben.
Rögzítsük a történelem számára, hogy az IP címet, amelyet az ügyfél kapott:


A szerver indítása
.\/pydhcpdb.py -d -c config.xml
— d a kimeneti mód DEBUG a konzolon
— c <fájl_név> konfigurációs fájl
Repülési jelentés
Most részletesebben a Python szerver megvalósításáról. Ez nehéz. A Python-t 'a levegőben' tanulmányozták. Sok oldal készült olyan stílusban: 'hű, valahogy megcsináltam, működik'. Teljesen nem optimalizált, és többnyire a kicsi fejlesztési tapasztalat miatt hagytuk ilyen állapotban. A szerver megvalósításának legérdekesebb aspektusaira fogok összpontosítani a 'kódban'.
XML konfigurációs fájl elemző
A Python xml.dom modulját használja. Úgy tűnik, elég egyszerű, de a megvalósítás során érezhetően hiányzott a hasznos dokumentáció és a példák az interneten a modul használatával kapcsolatban.
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)Többszálúság
Meglepetés, de a több szálú programozás Pythonban nagyon érthetően és egyszerűen van megvalósítva.
def PacketWork(data,addr):
...
# a beérkező csomag elemzésének és válaszának megvalósítása
...
while True:
data, addr = udp_socket.recvfrom(1024) # várakozás UDP csomagra
thread = threading.Thread(target=PacketWork, args=(data,addr,)).start() # amint megérkezik - a korábban definiált PacketWork funkciót háttérben indítjuk a paraméterekkel
while threading.active_count() > gconfig["dhcp_ThreadLimit"]:
time.sleep(1) # ha már a futó szálak száma meghaladja a beállított értéket, várunk, amíg csökkenDHCP csomag fogadása/küldése
Ahhoz, hogy elfogjuk az UDP csomagokat, amelyek az hálózati kártyán keresztül érkeznek, emelni kell a socketet:
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP) udp_socket.bind((gconfig["dhcp_host"],67))
, ahol a zászlók:
- AF_INET — azt jelenti, hogy az cím formátuma IP: port. Lehet még AF_UNIX — ahol az cím fájlnévként van megadva.
- SOCK_DGRAM — azt jelenti, hogy nem „nyers csomagot” fogadunk, hanem már a tűzfalon áthaladottat, és részben levágott csomagot. Tehát csak UDP csomagot kapunk „fizikai” csomagkörnyezet nélkül. Ha a SOCK_RAW zászlót használjuk, akkor még ezt az „csomagkörnyezetet” is elemezni kell.
A csomagküldés lehet broadcast formájában:
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # átkapcsoljuk a socketet broadcast küldési módra
rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68)), valamint címre, "ahonnan a csomag érkezett":
udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # átkapcsoljuk a socketet a "több hallgató" módra
rz=udp_socket.sendto(packetack, addr), ahol a SOL_SOCKET a "protokoll szint" option beállításához szükséges,
, a SO_BROADCAST opció azt jelzi, hogy a csomagot "broadcast" formában küldjük
, a SO_REUSEADDR opció átkapcsolja a socketet a "több hallgató" módra. Elvileg erre az esetre nincs szükség, de egy FreeBSD szerveren, amelyen teszteltem, enélkül a kód nem működött.
A DHCP csomag elemzése
Itt tényleg tetszett a Python. Kiderült, hogy a "dobozból" viszonylag szabadon bánik a bájtokkal. Lehetővé teszi számunkra, hogy nagyon egyszerűen átkonvertáljuk őket tizedes értékekbe, karakterláncokba és hexadecimális értékekbe – ez az, amire valóban szükségünk van a csomag struktúrájának megértéséhez. Például így kaphatunk bájtok tartományát HEX-ben és sima bájtokban:
res["xidhex"]=data[4:8].hex()
res["xidbyte"]=data[4:8], a bájtok csomagba rendezése:
res["flags"]=pack('BB',data[10],data[11])IP kinyerése a struktúrából:
res["ciaddr"]=socket.inet_ntoa(pack('BBBB',data[12],data[13],data[14],data[15]));És fordítva:
res=res+socket.inet_pton(socket.AF_INET, gconfig["dhcp_Server"])
Ennyi 😉
Forrás: habr.com
