DHCP+Mysql szerver Pythonban

DHCP+Mysql szerver Pythonban

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 DB2DHCP (az én fork-om), az eredeti itt, 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 "élőben megnézni".

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ő:

  1. 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.
  2. 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.
  3. 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.
  4. 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.

DHCP+Mysql szerver Pythonban

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:

DHCP+Mysql szerver Pythonban

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 GitHub

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:

DHCP+Mysql szerver Pythonban

DHCP+Mysql szerver Pythonban

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ökken

DHCP 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

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster