Server DHCP+Mysql în Python

Server DHCP+Mysql în Python

Scopul acestui proiect a fost:

  • Aflați despre DHCP într-o rețea IPv4
  • Învățarea Python (puțin mai mult decât de la zero 😉)
  • înlocuirea serverului DB2DHCP (furculița mea), original aici, care devine din ce în ce mai greu de asamblat pentru noul sistem de operare. Și nu-mi place că este un binar care nu există nicio modalitate de a „schimba chiar acum”
  • obținerea unui server DHCP funcțional, cu capacitatea de a selecta adresa IP a abonatului folosind combinația mac a abonatului sau comutator mac+port (Opțiunea 82)
  • scriind o altă bicicletă (Oh! aceasta este activitatea mea preferată)
  • primirea de comentarii despre statutul tău de club pe Habrahabr (sau mai bine zis, o invitație) 😉

Rezultat: funcționează 😉 Testat pe FreeBSD și Ubuntu OS. Teoretic, codul poate fi solicitat să funcționeze sub orice sistem de operare, deoarece Se pare că nu există legături specifice în cod.
Cu grija! Mai sunt multe de urmat.

Link către depozitul pentru amatori "atinge viu".

Procesul de instalare, configurare și utilizare a rezultatului „studiului hardware-ului” este mult mai scăzut, iar apoi puțină teorie despre protocolul DHCP. Pentru mine. Și pentru istorie 😉

Puțină teorie

Ce este DHCP

Acesta este un protocol de rețea care permite unui dispozitiv să-și afle adresa IP (și alți parametri precum gateway, DNS etc.) de la un server DHCP. Pachetele sunt schimbate folosind protocolul UDP. Principiul general de funcționare a dispozitivului la solicitarea parametrilor de rețea este următorul:

  1. Dispozitivul (clientul) trimite o cerere de difuzare UDP (DHCPDISCOVER) în întreaga rețea cu solicitarea „ei bine, cineva să-mi dea o adresă IP”. Mai mult, de obicei (dar nu întotdeauna) cererea apare de la portul 68 (sursă), iar destinația este portul 67 (destinația). Unele dispozitive trimit și pachete de la portul 67. Adresa MAC a dispozitivului client este inclusă în pachetul DHCPDISCOVER.
  2. Toate serverele DHCP situate în rețea (și pot fi mai multe dintre ele) formează o ofertă DHCPOFFER cu setări de rețea pentru dispozitivul care a trimis DHCPDISCOVER și, de asemenea, o difuzează în rețea. Identificarea cui este destinat acest pachet se bazează pe adresa MAC a clientului furnizată mai devreme în cererea DHCPDISCOVER.
  3. Clientul acceptă pachete cu propuneri de setări de rețea, îl selectează pe cel mai atractiv (criteriile pot fi diferite, de exemplu, ora livrării pachetelor, numărul de rute intermediare) și face o „cerere oficială” DHCPREQUEST cu setările de rețea de pe serverul DHCP care îi place. În acest caz, pachetul ajunge la un anumit server DHCP.
  4. Serverul care a primit DHCPREQUEST trimite un pachet în format DHCPACK, în care listează din nou setările de rețea destinate acestui client

Server DHCP+Mysql în Python

În plus, există pachete DHCPINFORM care provin de la client și al căror scop este de a informa serverul DHCP că „clientul este în viață” și utilizează setările de rețea emise. În implementarea acestui server, aceste pachete sunt ignorate.

Format pachet

În general, un cadru de pachet Ethernet arată cam așa:

Server DHCP+Mysql în Python

În cazul nostru, vom lua în considerare doar datele direct din conținutul pachetului UDP, fără antete de protocol layer OSI, și anume structura DHCP:

DHCPDISCOVER

Deci, procesul de obținere a unei adrese IP pentru un dispozitiv începe cu clientul DHCP care trimite o solicitare de difuzare de la portul 68 la 255.255.255.255:67. În acest pachet, clientul include adresa sa MAC, precum și ce anume dorește să primească de la serverul DHCP. Structura pachetului este descrisă în tabelul de mai jos.

Tabelul structurii pachetelor DHCPDISCOVER

Poziție în pachet
Nume valoare
Exemplu
idee
Octet
clarificare

1
Solicitare de pornire
1
Hex
1
Tipul mesajului. 1 - cerere de la client la server, 2 - răspuns de la server la client

2
Tip hardware
1
Hex
1
Tipul adresei hardware, în acest protocol 1 - MAC

3
Lungimea adreselor hardware
6
Hex
1
Lungimea adresei MAC a dispozitivului

4
Hamei
1
Hex
1
Numărul de rute intermediare

5
ID tranzacție
23:cf:de:1d
Hex
4
Identificator unic de tranzacție. Generat de client la începutul unei operațiuni de solicitare

7
A trecut al doilea
0
Hex
4
Timp în secunde de la începutul procesului de obținere a unei adrese

9
Steaguri de boot
0
Hex
2
Anumite steaguri care pot fi setate pentru a indica parametrii protocolului

11
Adresa IP a clientului
0.0.0.0
rând
4
Adresa IP a clientului (dacă există)

15
Adresa IP a clientului dvs
0.0.0.0
rând
4
Adresa IP oferită de server (dacă este disponibilă)

19
Următoarea adresă IP a serverului
0.0.0.0
rând
4
Adresa IP a serverului (dacă este cunoscută)

23
Adresa IP a agentului de retransmisie
172.16.114.41
rând
4
Adresa IP a agentului de releu (de exemplu, un comutator)

27
Adresa MAC a clientului
14:d6:4d:a7:c9:55
Hex
6
Adresa MAC a expeditorului pachetului (client)

31
Complet cu adrese hardware client
 
Hex
10
Loc rezervat. De obicei umplute cu zerouri

41
Nume gazdă server
 
rând
64
Nume server DHCP. De obicei nu se transmite

105
Numele fișierului de pornire
 
rând
128
Numele fișierului pe server folosit de stațiile fără disc la pornire

235
Prajituri magice
63: 82: 53: 63
Hex
4
Număr „magic”, conform căruia, incl. puteți determina că acest pachet aparține protocolului DHCP

Opțiuni DHCP. Poate merge în orice ordine

236
Numărul opțiunii
53
decembrie
1
Opțiunea 53, care specifică tipul de pachet DHCP

1 - DHCPDISCOVER
3 - DHCPREQUEST
2 - OFERTA DHCP
5 - DHCPACK
8 - DHCPINFORM

 
Lungimea opțiunii
1
decembrie
1

 
Valoarea opțiunii
1
decembrie
1

 
Numărul opțiunii
50
decembrie
1
Ce adresă IP dorește să primească clientul?

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
172.16.134.61
rând
4

 
Numărul opțiunii
55
 
1
Parametrii rețelei solicitați de client. Compoziția poate varia

01 — Mască de rețea
03 - Gateway
06 - DNS
oc — Nume gazdă
0f - nume de domeniu al rețelei
1c - adresa cererii de difuzare (difuzare)
42 - Nume server TFTP
79 - Rută statică fără clasă

 
Lungimea opțiunii
8
 
1

 
Valoarea opțiunii
01:03:06:0c:0f:1c:42:79
 
8

 
Numărul opțiunii
82
decembrie
 
Opțiunea 82, care transmite adresa MAC a dispozitivului repetitor și câteva valori suplimentare.

Cel mai adesea, acesta este portul switch-ului pe care rulează clientul DHCP final.Această opțiune conține parametri suplimentari.Primul octet este numărul „subopțiunii”, al doilea este lungimea acestuia, apoi valoarea sa.

În acest caz, în opțiunea 82, subopțiunile sunt imbricate:
ID circuit agent = 00:04:00:01:00:04, unde ultimii doi octeți sunt portul client DHCP de la care a venit cererea

Agent Remote ID = 00:06:c8:be:19:93:11:48 - adresa MAC a dispozitivului repetitor DHCP

 
Lungimea opțiunii
18
decembrie
 

 
Valoarea opțiunii
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
Sfârșitul pachetului
255
decembrie
1
255 simbolizează sfârșitul pachetului

DHCPOFFER

Imediat ce serverul primește pachetul DHCPDISCOVER și dacă vede că poate oferi clientului ceva din cel solicitat, atunci generează un răspuns pentru acesta - DHCPDISCOVER. Răspunsul este trimis în portul „de unde a venit”, prin difuzare, pentru că în acest moment, clientul nu are încă o adresă IP, prin urmare poate accepta pachetul doar dacă este trimis prin difuzare. Clientul recunoaște că acesta este un pachet pentru el după adresa sa MAC din interiorul pachetului, precum și prin numărul tranzacției pe care îl generează în momentul creării primului pachet.

Tabelul structurii pachetelor DHCPOFFER

Poziție în pachet
Numele valorii (comun)
Exemplu
idee
Octet
clarificare

1
Solicitare de pornire
1
Hex
1
Tipul mesajului. 1 - cerere de la client la server, 2 - răspuns de la server la client

2
Tip hardware
1
Hex
1
Tipul adresei hardware, în acest protocol 1 - MAC

3
Lungimea adreselor hardware
6
Hex
1
Lungimea adresei MAC a dispozitivului

4
Hamei
1
Hex
1
Numărul de rute intermediare

5
ID tranzacție
23:cf:de:1d
Hex
4
Identificator unic de tranzacție. Generat de client la începutul unei operațiuni de solicitare

7
A trecut al doilea
0
Hex
4
Timp în secunde de la începutul procesului de obținere a unei adrese

9
Steaguri de boot
0
Hex
2
Anumite steaguri care pot fi setate pentru a indica parametrii protocolului. În acest caz, 0 înseamnă tipul de solicitare Unicast

11
Adresa IP a clientului
0.0.0.0
rând
4
Adresa IP a clientului (dacă există)

15
Adresa IP a clientului dvs
172.16.134.61
rând
4
Adresa IP oferită de server (dacă este disponibilă)

19
Următoarea adresă IP a serverului
0.0.0.0
rând
4
Adresa IP a serverului (dacă este cunoscută)

23
Adresa IP a agentului de retransmisie
172.16.114.41
rând
4
Adresa IP a agentului de releu (de exemplu, un comutator)

27
Adresa MAC a clientului
14:d6:4d:a7:c9:55
Hex
6
Adresa MAC a expeditorului pachetului (client)

31
Complet cu adrese hardware client
 
Hex
10
Loc rezervat. De obicei umplute cu zerouri

41
Nume gazdă server
 
rând
64
Nume server DHCP. De obicei nu se transmite

105
Numele fișierului de pornire
 
rând
128
Numele fișierului pe server folosit de stațiile fără disc la pornire

235
Prajituri magice
63: 82: 53: 63
Hex
4
Număr „magic”, conform căruia, incl. puteți determina că acest pachet aparține protocolului DHCP

Opțiuni DHCP. Poate merge în orice ordine

236
Numărul opțiunii
53
decembrie
1
Opțiunea 53, care definește tipul de pachet DHCP 2 - DHCPOFFER

 
Lungimea opțiunii
1
decembrie
1

 
Valoarea opțiunii
2
decembrie
1

 
Numărul opțiunii
1
decembrie
1
Opțiunea de a oferi clientului DHCP o mască de rețea

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
255.255.224.0
rând
4

 
Numărul opțiunii
3
decembrie
1
Opțiune de a oferi clientului DHCP un gateway implicit

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
172.16.12.1
rând
4

 
Numărul opțiunii
6
decembrie
1
Opțiunea de a oferi DHCP clientului DNS

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
8.8.8.8
rând
4

 
Numărul opțiunii
51
decembrie
1
Durata de viață a parametrilor de rețea emiși în secunde, după care clientul DHCP trebuie să îi solicite din nou

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
86400
decembrie
4

 
Numărul opțiunii
82
decembrie
1
Opțiunea 82, repetă ceea ce a venit în DHCPDISCOVER

 
Lungimea opțiunii
18
decembrie
1

 
Valoarea opțiunii
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
decembrie
18

 
Sfârșitul pachetului
255
decembrie
1
255 simbolizează sfârșitul pachetului

DHCPREQUEST

După ce clientul primește DHCPOFFER, el formează un pachet care solicită parametri de rețea nu tuturor serverelor DHCP din rețea, ci doar unuia anume, a cărui ofertă DHCPOFFER i-a „placut” cel mai mult. Criteriile „like” pot fi diferite și depind de implementarea DHCP a clientului. Destinatarul cererii este specificat folosind adresa MAC a serverului DHCP. De asemenea, un pachet DHCPREQUEST poate fi trimis de client fără a genera mai întâi DHCPDISCOVER, dacă adresa IP a serverului a fost deja obținută anterior.

Tabelul structurii pachetelor DHCPREQUEST

Poziție în pachet
Numele valorii (comun)
Exemplu
idee
Octet
clarificare

1
Solicitare de pornire
1
Hex
1
Tipul mesajului. 1 - cerere de la client la server, 2 - răspuns de la server la client

2
Tip hardware
1
Hex
1
Tipul adresei hardware, în acest protocol 1 - MAC

3
Lungimea adreselor hardware
6
Hex
1
Lungimea adresei MAC a dispozitivului

4
Hamei
1
Hex
1
Numărul de rute intermediare

5
ID tranzacție
23:cf:de:1d
Hex
4
Identificator unic de tranzacție. Generat de client la începutul unei operațiuni de solicitare

7
A trecut al doilea
0
Hex
4
Timp în secunde de la începutul procesului de obținere a unei adrese

9
Steaguri de boot
8000
Hex
2
Anumite steaguri care pot fi setate pentru a indica parametrii protocolului. În acest caz, „difuzare” este setat

11
Adresa IP a clientului
0.0.0.0
rând
4
Adresa IP a clientului (dacă există)

15
Adresa IP a clientului dvs
172.16.134.61
rând
4
Adresa IP oferită de server (dacă este disponibilă)

19
Următoarea adresă IP a serverului
0.0.0.0
rând
4
Adresa IP a serverului (dacă este cunoscută)

23
Adresa IP a agentului de retransmisie
172.16.114.41
rând
4
Adresa IP a agentului de releu (de exemplu, un comutator)

27
Adresa MAC a clientului
14:d6:4d:a7:c9:55
Hex
6
Adresa MAC a expeditorului pachetului (client)

31
Complet cu adrese hardware client
 
Hex
10
Loc rezervat. De obicei umplute cu zerouri

41
Nume gazdă server
 
rând
64
Nume server DHCP. De obicei nu se transmite

105
Numele fișierului de pornire
 
rând
128
Numele fișierului pe server folosit de stațiile fără disc la pornire

235
Prajituri magice
63: 82: 53: 63
Hex
4
Număr „magic”, conform căruia, incl. puteți determina că acest pachet aparține protocolului DHCP

Opțiuni DHCP. Poate merge în orice ordine

236
Numărul opțiunii
53
decembrie
3
Opțiunea 53, care definește tipul de pachet DHCP 3 - DHCPREQUEST

 
Lungimea opțiunii
1
decembrie
1

 
Valoarea opțiunii
3
decembrie
1

 
Numărul opțiunii
61
decembrie
1
ID client: 01 (pentru Ehernet) + adresa MAC a clientului

 
Lungimea opțiunii
7
decembrie
1

 
Valoarea opțiunii
01:2c:ab:25:ff:72:a6
Hex
7

 
Numărul opțiunii
60
decembrie
 
„Identificatorul clasei furnizorului”. În cazul meu, raportează versiunea client DHCP. Poate că alte dispozitive returnează ceva diferit. Windows, de exemplu, raportează MSFT 5.0

 
Lungimea opțiunii
11
decembrie
 

 
Valoarea opțiunii
udhcp 0.9.8
rând
 

 
Numărul opțiunii
55
 
1
Parametrii rețelei solicitați de client. Compoziția poate varia

01 — Mască de rețea
03 - Gateway
06 - DNS
oc — Nume gazdă
0f - nume de domeniu al rețelei
1c - adresa cererii de difuzare (difuzare)
42 - Nume server TFTP
79 - Rută statică fără clasă

 
Lungimea opțiunii
8
 
1

 
Valoarea opțiunii
01:03:06:0c:0f:1c:42:79
 
8

 
Numărul opțiunii
82
decembrie
1
Opțiunea 82, repetă ceea ce a venit în DHCPDISCOVER

 
Lungimea opțiunii
18
decembrie
1

 
Valoarea opțiunii
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
decembrie
18

 
Sfârșitul pachetului
255
decembrie
1
255 simbolizează sfârșitul pachetului

DHCPACK

Ca confirmare că „da, așa e, aceasta este adresa ta IP și nu o voi da nimănui” de pe serverul DHCP, un pachet în format DHCPACK de la server la client servește. Este transmis difuzat la fel ca alte pachete. Deși, în codul de mai jos pentru un server DHCP implementat în Python, pentru orice eventualitate, dublez orice solicitare de difuzare trimițând un pachet către un anumit IP client, dacă este deja cunoscut. Mai mult decât atât, serverului DHCP nu îi pasă deloc dacă pachetul DHCPACK a ajuns la client. Dacă clientul nu primește DHCPACK, atunci după un timp el repetă pur și simplu DHCPREQUEST

Tabelul structurii pachetelor DHCPACK

Poziție în pachet
Numele valorii (comun)
Exemplu
idee
Octet
clarificare

1
Solicitare de pornire
2
Hex
1
Tipul mesajului. 1 - cerere de la client la server, 2 - răspuns de la server la client

2
Tip hardware
1
Hex
1
Tipul adresei hardware, în acest protocol 1 - MAC

3
Lungimea adreselor hardware
6
Hex
1
Lungimea adresei MAC a dispozitivului

4
Hamei
1
Hex
1
Numărul de rute intermediare

5
ID tranzacție
23:cf:de:1d
Hex
4
Identificator unic de tranzacție. Generat de client la începutul unei operațiuni de solicitare

7
A trecut al doilea
0
Hex
4
Timp în secunde de la începutul procesului de obținere a unei adrese

9
Steaguri de boot
8000
Hex
2
Anumite steaguri care pot fi setate pentru a indica parametrii protocolului. În acest caz, „difuzare” este setat

11
Adresa IP a clientului
0.0.0.0
rând
4
Adresa IP a clientului (dacă există)

15
Adresa IP a clientului dvs
172.16.134.61
rând
4
Adresa IP oferită de server (dacă este disponibilă)

19
Următoarea adresă IP a serverului
0.0.0.0
rând
4
Adresa IP a serverului (dacă este cunoscută)

23
Adresa IP a agentului de retransmisie
172.16.114.41
rând
4
Adresa IP a agentului de releu (de exemplu, un comutator)

27
Adresa MAC a clientului
14:d6:4d:a7:c9:55
Hex
6
Adresa MAC a expeditorului pachetului (client)

31
Complet cu adrese hardware client
 
Hex
10
Loc rezervat. De obicei umplute cu zerouri

41
Nume gazdă server
 
rând
64
Nume server DHCP. De obicei nu se transmite

105
Numele fișierului de pornire
 
rând
128
Numele fișierului pe server folosit de stațiile fără disc la pornire

235
Prajituri magice
63: 82: 53: 63
Hex
4
Număr „magic”, conform căruia, incl. puteți determina că acest pachet aparține protocolului DHCP

Opțiuni DHCP. Poate merge în orice ordine

236
Numărul opțiunii
53
decembrie
3
Opțiunea 53, care definește tipul de pachet DHCP 5 - DHCPACK

 
Lungimea opțiunii
1
decembrie
1

 
Valoarea opțiunii
5
decembrie
1

 
Numărul opțiunii
1
decembrie
1
Opțiunea de a oferi clientului DHCP o mască de rețea

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
255.255.224.0
rând
4

 
Numărul opțiunii
3
decembrie
1
Opțiune de a oferi clientului DHCP un gateway implicit

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
172.16.12.1
rând
4

 
Numărul opțiunii
6
decembrie
1
Opțiunea de a oferi DHCP clientului DNS

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
8.8.8.8
rând
4

 
Numărul opțiunii
51
decembrie
1
Durata de viață a parametrilor de rețea emiși în secunde, după care clientul DHCP trebuie să îi solicite din nou

 
Lungimea opțiunii
4
decembrie
1

 
Valoarea opțiunii
86400
decembrie
4

 
Numărul opțiunii
82
decembrie
1
Opțiunea 82, repetă ceea ce a venit în DHCPDISCOVER

 
Lungimea opțiunii
18
decembrie
1

 
Valoarea opțiunii
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
decembrie
18

 
Sfârșitul pachetului
255
decembrie
1
255 simbolizează sfârșitul pachetului

Instalare

Instalarea constă de fapt în instalarea modulelor python necesare pentru lucru. Se presupune că MySQL este deja instalat și configurat.

FreeBSD

pkg instalează python3 python3 -m assurepip pip3 instalează conectorul mysql

Ubuntu

sudo apt-get install python3 sudo apt-get install pip3 sudo pip3 install mysql-connector

Creăm o bază de date MySQL, încărcăm dump-ul pydhcp.sql în ea și configurăm fișierul de configurare.

configurație

Toate setările serverului sunt într-un fișier xml. Fișier de referință:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 gazdă locală Test Test pydhcp option_8.8.8.8_hex:sw_port82:1:20 option_22_hex:sw_port82:2:16 option_18_hex:sw_mac:82:26 40 selectați ip, masca, router, dns de la utilizatori unde upper(mac)=upper('{option_3_AgentRemoteId_hex}') și upper(port)=upper('{option_1_AgentCircuitId_port_hex}') selectați ip, mască, router, dns de la utilizatori unde upper(mac)=upper('{sw_mac}') și upper(port)=upper('{sw_port82}') selectați ip, mască, router, dns de la utilizatori unde upper(mac)=upper('{ClientMacAddress}') inserați în istoric (id, dt, mac, ip, comentariu) valori (null, now(), '{ClientMacAddress}','{RequestedIpAddress}', 'DHCPACK/INFORM')

Acum, mai detaliat despre etichete:

Secțiunea dhcpserver descrie setările de bază pentru pornirea serverului, și anume:

  • gazdă - ce adresă IP ascultă serverul pe portul 67
  • broadcast - care ip este difuzarea pentru DHCPOFFER și DHCPACK
  • DHCPServer - care este ip-ul serverului DHCP
  • Durata de închiriere LeaseTime a adresei IP emise
  • ThreadLimit - câte fire rulează simultan pentru a procesa pachetele UDP primite pe portul 67. Se presupune că va ajuta la proiectele cu încărcare mare 😉
  • defaultMask,defaultRouter,defaultDNS - ce este oferit abonatului în mod implicit dacă se găsește un IP în baza de date, dar nu sunt specificați parametri suplimentari pentru acesta

secțiunea mysql:

gazdă, nume de utilizator, parolă, nume de bază - totul vorbește de la sine. O structură aproximativă a bazei de date este postată pe GitHub

Secțiunea de interogări: solicitările pentru primirea OFERTE/ACK sunt descrise aici:

  • offer_count — numărul de linii cu solicitări care returnează un rezultat precum ip,mask,router,dns
  • offer_n — șir de interogare. Dacă returnarea este goală, atunci execută următoarea cerere de ofertă
  • history_sql - o interogare care scrie, de exemplu, în „istoricul autorizațiilor” pentru un abonat

Cererile pot include orice variabile din secțiunea de opțiuni sau opțiuni din protocolul DHCP.

Secțiunea de opțiuni. Aici devine mai interesant. Aici putem crea variabile pe care le putem folosi mai târziu în secțiunea de interogare.

De exemplu:

option_82_hex:sw_port1:20:22

, această linie de comandă preia întreaga linie care a venit în opțiunea de solicitare DHCP 82, în format hex, în intervalul de la 20 la 22 de octeți inclusiv și o pune în noua variabilă sw_port1 (portul de comutare de unde a venit cererea)

option_82_hex:sw_mac:26:40

, definiți variabila sw_mac, luând hex din intervalul 26:40

Puteți vedea toate opțiunile posibile care pot fi utilizate în interogări pornind serverul cu comutatorul -d. Vom vedea ceva ca acest jurnal:

--a sosit un pachet DHCPINFORM pe portul 67, de la 0025224ad764 , b'x91xa5xe0xa3xa5xa9-x8fx8a' , ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764': '00MacAddress': '7Mac'91': 'ClientMacAddress': '5c'0' Jxd3d', ' HType': 'Ethernet', 'HostName': b'x5xa9xe8xa8xa43xa0.0.0.0-x5.0fx0025224a', 'ReqListDNS': True, 'ReqListDomainName': True, 'ReqListPerfowmRouterDiscover': True, 'ReqList: TrueRouter': 'ReqList: TrueRouter': ReqListSubnetMask ': True, 'ReqListVendorSpecInfo': 764, 'RequestedIpAddress': '172.30.128.13', 'Vendor': b'MSFT 00', 'chaddr': '00ad172.30.114.25', 'ciaddr.', '308,':6'. steaguri „: b'x1x82”, „giaddr”: „12”, „gpoz”: 12, „hlen”: 53, „hops”: 53, „htype”: „MAC”, „magic_cookie”: b” cx55Sc ', 'op': 'DHCPINFORM', 'option55': 60, 'option60': 61, 'option61': 82, 'option82': 82, 'option12': 01, 'option06': 00, 'option_04_byte' : b'x00x01x00x06x02x08x00x06x00x1x9x2' b'x82x12010600040001000602080006001x589eXx2exb82xad', 'option_18_hex': '82 option_12_str': "b'x01x06x00x04x00x01x00x06x02x08x00x06x00x1x9eXx2exb768xad'", 'rezultat': Fals, 'secs': 0.0.0.0, 'siaddr' : '001', 'sw_mac': '589e2eb1ad', 'sw_port06': '89', 'xidbyte': b'

În consecință, putem include orice variabilă în {} și va fi folosită în interogarea SQL.

Să înregistrăm pentru istoric că clientul a primit adresa IP:

Server DHCP+Mysql în Python

Server DHCP+Mysql în Python

Pornirea serverului

./pydhcpdb.py -d -c config.xml

— d modul de ieșire consolei DEBUG
- c <nume fișier> fișier de configurare

Rezumat

Și acum mai multe detalii despre implementarea serverului în Python. Este o durere. Python a fost învățat din mers. Multe momente sunt făcute în stilul „wow, cumva l-am făcut să funcționeze”. Nu este deloc optimizat și lăsat în această formă în principal din cauza experienței reduse în dezvoltarea Python. Mă voi opri asupra celor mai interesante aspecte ale implementării serverului în „cod”.

Analizor de fișiere de configurare XML

Este utilizat modulul standard Python xml.dom. Pare simplu, dar în timpul implementării a existat o lipsă vizibilă a documentației clare și a exemplelor în rețea folosind acest modul.

    arbore = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") pentru elem în mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("gazdă")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("username")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("parola")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basename")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") pentru elem în dconfig: gconfig["broadcast"]=elem.getElementsByTagName("broadcast")[0]. firstChild.data gconfig["dhcp_host"]=elem.getElementsByTagName("gazdă")[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"Maskp_default] =elem.getElementsByTagName("defaultMask")[0].firstChild.data gconfig["dhcp_defaultRouter"]=elem.getElementsByTagName("defaultRouter")[0].firstChild.data gconfig["dhcp_defaultRouter"]=elem.getElementsByTagName("defaultRouter")[0].firstChild.data gconfig["dhcp_defaultRouter"](Nameelem.DNSget"] defaultDNS")[0].firstChild.data qconfig=tree.getElementsByTagName("interogare") pentru elem în qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[1].firstChild.data pentru num în interval(int(gconfig["ofer_count"])): gconfig["offer_"+str(num+1)]=elem.getElementsByTagName("offer_"+str(num+0))[0].firstChild.data gconfig ["history_sql"]=elem.getElementsByTagName("history_sql")[XNUMX].firstChild.data options=tree.getElementsByTagName("opțiuni") pentru elem în opțiuni: node=elem.getElementsByTagName("opțiune") pentru opțiuni în nod : optionsMod.append(options.firstChild.data)

Multithreading

În mod ciudat, multithreadingul în Python este implementat foarte clar și simplu.

def PacketWork(data,addr): ... # implementarea analizării pachetului de intrare și a răspunsului la acesta ... în timp ce True: data, addr = udp_socket.recvfrom(1024) # așteptând firul de pachete UDP = threading.Thread( target=PacketWork , args=(data,addr,)).start() # așa cum a venit - lansăm funcția PacketWork definită anterior în fundal cu parametrii în timp ce threading.active_count() >gconfig["dhcp_ThreadLimit"]: time. sleep(1) # dacă numărul Există mai multe fire care rulează deja decât în ​​setări, așteptăm până când sunt mai puține dintre ele

Primiți/trimiteți pachet DHCP

Pentru a intercepta pachetele UDP care vin prin placa de rețea, trebuie să „ridicați” soclul:

udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP) udp_socket.bind((gconfig["dhcp_host"],67))

, unde steagurile sunt:

  • AF_INET - înseamnă că formatul adresei va fi IP: port. Poate exista și AF_UNIX - unde adresa este dată de numele fișierului.
  • SOCK_DGRAM - înseamnă că nu acceptăm un „pachet brut”, ci unul care a trecut deja prin firewall și cu un pachet parțial tăiat. Acestea. primim doar un pachet UDP fără componenta „fizică” a pachetului de pachete UDP. Dacă utilizați flag-ul SOCK_RAW, atunci va trebui să analizați și acest „wrapper”.

Trimiterea unui pachet poate fi ca o difuzare:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #switch the socket to broadcast mode rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, și la adresa „de unde a venit coletul”:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # comută socket-ul în modul multi-ascultător rz=udp_socket.sendto(packetack, addr)

, unde SOL_SOCKET înseamnă „nivelul de protocol” pentru setarea opțiunilor,

, opțiunea SO_BROADCAST că pachetul de cască este „difuzat”

  Opțiunea ,SO_REUSEADDR comută soclul în modul „mulți ascultători”. În teorie, nu este necesar în acest caz, dar pe unul dintre serverele FreeBSD pe care am testat, codul nu a funcționat fără această opțiune.

Analizarea unui pachet DHCP

Aici mi-a plăcut foarte mult Python. Se pare că din cutie vă permite să fiți destul de flexibili cu bytecode. Permițându-i să fie foarte ușor tradus în valori zecimale, șiruri și hex - adică aceasta este ceea ce avem de fapt nevoie pentru a înțelege structura pachetului. Deci, de exemplu, puteți obține o serie de octeți în HEX și doar octeți:

    res["xidhex"]=date[4:8].hex() res["xidbyte"]=date[4:8]

, împachetați octeții într-o structură:

res["flags"]=pack('BB',data[10],data[11])

Obțineți IP din structură:

res["ciaddr"]=socket.inet_ntoa(pack('BBBB',data[12],data[13],data[14],data[15]));

Si invers:

res=res+socket.inet_pton(socket.AF_INET, gconfig["dhcp_Server"])

Asta e tot deocamdată 😉

Sursa: www.habr.com

Adauga un comentariu