DHCP+Mysql server na Pythonu

DHCP+Mysql server na Pythonu

Cilj ovog projekta je bio:

  • Istraživanje DHCP protokola u radu s IPv4 mrežom
  • Istraživanje Pythona (malo više od nule 😉 )
  • zamjena serveru DB2DHCP (moj fork), original ovdje, koji se sve teže i teže sastavlja za novi operativni sustav. Također mi se ne sviđa što binarni program ne može 'promijeniti odmah'
  • dobivanje funkcionalnog DHCP servera s mogućnošću odabira IP adrese klijenta prema MAC adresi klijenta ili kombinaciji MAC adrese switcha+port (Option 82)
  • pisanje još jednog kotača (O! to je moja omiljena aktivnost)
  • dobivanje kritika zbog svoje nespretnosti na Habrhabr (ili, još bolje, pozivnice) 😉

Rezultat: radi 😉 Isprobano na FreeBSD i Ubuntu OS-u. Teoretski, kod se može zamoliti da radi na bilo kojem operativnom sustavu, pošto nema specifičnih vezanosti u kodu.
Pažnja! Dalje slijedi puno.

Link na repozitorij za entuzijaste da 'dotaknu uživo'.

Proces instalacije, konfiguracije i korištenja rezultata 'istraživanja materije' slijedi niže, a zatim malo teorije o DHCP protokolu. Za sebe. I za povijest 😉

Malo teorije

Što je DHCP

To je mrežni protokol koji omogućava uređaju da sazna svoju IP adresu (i druge parametre kao što su gateway, DNS i slično) od DHCP servera. Razmjena paketa odvija se putem UDP protokola. Opći princip rada uređaja prilikom zahtjeva za mrežnim parametrima je sljedeći:

  1. Uređaj (klijent) šalje širokouništeni UDP zahtjev (DHCPDISCOVER) kroz cijelu mrežu s upitom 'neka netko da mi IP adresu'. Obično (ali ne uvijek) zahtjev dolazi s porta 68 (izvor), a odredišni port je 67. Neka uređaja također šalju pakete s porta 67. Unutar DHCPDISCOVER paketa uključen je MAC adresa uređaja klijenta.
  2. Svi DHCP serveri koji se nalaze u mreži (a može ih biti više) formiraju ponudu DHCPOFFER za uređaj koji je poslao DHCPDISCOVER, s mrežnim postavkama, i također ga širokouništeno šalju kroz mrežu. Identifikacija kome je ovaj paket namijenjen odvija se putem MAC adrese klijenta, pružene ranije u zahtjevu DHCPDISCOVER.
  3. Klijent prima pakete s ponudama mrežnih postavki, odabire najprivlačniji (kriteriji mogu biti različiti, na primjer, i prema vremenu isporuke paketa, broju međurute), i šalje 'službeni zahtjev' DHCPREQUEST na omiljenom DHCP poslužitelju sa mrežnim postavkama. U tom slučaju, paket ide već konkretnom DHCP poslužitelju.
  4. Poslužitelj koji je primio DHCPREQUEST šalje paket formata DHCPACK, u kojem ponovno navodi mrežne postavke namijenjene ovom klijentu.

DHCP+Mysql server na Pythonu

Osim toga, postoje paketi DHCPINFORM koji dolaze od klijenta, a cilj im je obavijestiti DHCP poslužitelj da je 'klijent živ' i koristi dodijeljene mrežne postavke. U implementaciji ovog poslužitelja, ovi paketi se ignoriraju.

Format paketa

Općenito, okvir Ethernet paketa izgleda otprilike ovako:

DHCP+Mysql server na Pythonu

U našem slučaju razmatramo samo podatke izravno sadržane u UDP paketu, bez zaglavlja protokola razina OSI, a to je struktura DHCP-a:

DHCPDISCOVER

Dakle, proces dobivanja IP adrese za uređaj započinje slanjem širokofrekventnog zahtjeva od strane DHCP klijenta s porta 68 na 255.255.255.255:67. U ovom paketu klijent uključuje svoju MAC adresu, kao i što točno želi dobiti od DHCP poslužitelja. Struktura paketa opisana je u tablici ispod.

Tablica strukture paketa DHCPDISCOVER

Pozicija u paketu
Naziv vrijednosti
Primjer
Prikaz
Bajt
Objašnjenje

1
Boot Request
1
Hex
1
Tip poruke. 1 — zahtjev od klijenta prema poslužitelju, 2 — odgovor od poslužitelja klijentu

2
Vrsta hardvera
1
Hex
1
Tip hardverske adrese, u ovom protokolu 1 — MAC

3
Duljina hardverske adrese
6
Hex
1
Duljina MAC adrese uređaja

4
Hops
1
Hex
1
Broj međurute

5
Transakcijski ID
23:cf:de:1d
Hex
4
Jedinstveni identifikator transakcije. Klijent ga generira na početku operacije zahtjeva

7
Drugo proteklo vrijeme
0
Hex
4
Vrijeme u sekundama od početka procesa dobivanja adrese

9
Bootp zastavice
0
Hex
2
Neke zastavice koje se mogu postaviti kao oznaka za parametre protokola

11
IP adresa klijenta
0.0.0.0
Retak
4
IP adresa klijenta (ako postoji)

15
Vaša IP adresa klijenta
0.0.0.0
Retak
4
IP adresa ponuđena od strane poslužitelja (ako postoji)

19
IP adresa sljedećeg poslužitelja
0.0.0.0
Retak
4
IP adresa poslužitelja (ako je poznata)

23
IP adresa agenta preusmjeravanja
172.16.114.41
Retak
4
IP adresa agenta preusmjeravanja (na primjer, switch)

27
MAC adresa klijenta
14:d6:4d:a7:c9:55
Hex
6
MAC adresa pošiljatelja paketa (klijenta)

31
Puni sastav MAC adrese klijenta
 
Hex
10
Rezervirani prostor. Obično popunjen nulama

41
Ime poslužitelja
 
Retak
64
Ime DHCP poslužitelja. Obično se ne prenosi

105
Naziv boot datoteke
 
Retak
128
Naziv datoteke na poslužitelju koji se koristi od strane bezdiskovnih stanica prilikom podizanja.

235
Magic cookie
63:82:53:63
Hex
4
«Magični» broj, prema kojem se može odrediti pripada li ovaj paket DHCP protokolu.

DHCP opcije. Mogu se pojaviti u bilo kojem redoslijedu.

236
Broj opcije
53
Dec
1
Opcija 53, koja određuje tip DHCP paketa.

1 — DHCPDISCOVER
3 — DHCPREQUEST
2 — DHCPOFFER
5 — DHCPACK
8 — DHCPINFORM

 
Duljina opcije
1
Dec
1

 
Vrijednost opcije
1
Dec
1

 
Broj opcije
50
Dec
1
Koju IP adresu želi dobiti klijent

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
172.16.134.61
Retak
4

 
Broj opcije
55
 
1
Zahtijevani mrežni parametri od strane klijenta. Sadržaj može biti različit.

01 — Maska podmreže
03 — Prolaz
06 — DNS
oc — Ime hosta
0f — ime domene mreže
1c — adresa multicast (broadcast) zahtjeva
42 — ime TFTP poslužitelja
79 — Classless Static Route

 
Duljina opcije
8
 
1

 
Vrijednost opcije
01:03:06:0c:0f:1c:42:79
 
8

 
Broj opcije
82
Dec
 
Opcija 82, u kojoj se prenosi MAC adresa uređaja — retransmitera i neka dodatna vrijednost.

Najčešće — port switch-a na kojem radi krajnji DHCP klijent. U ovoj opciji su "utemeljeni" dodatni parametri. Prvi bajt — broj "podopcije", drugi njen broj bajtova, zatim njezina vrijednost.

U ovom slučaju, u opciji 82 su uteljenjene podopcje:
Agent Circuit ID = 00:04:00:01:00:04, gdje zadnja dva bajta označavaju port DHCP klijenta s kojeg je došao zahtjev.

Agent Remote ID = 00:06:c8:be:19:93:11:48 — MAC adresa uređaja retransmitera DHCP.

 
Duljina opcije
18
Dec
 

 
Vrijednost opcije
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
Kraj paketa
255
Dec
1
255 označava kraj paketa.

DHCPOFFER

Čim poslužitelj primi paket DHCPDISCOVER i ako vidi da može ponuditi nešto klijentu iz traženog, formira odgovor — DHCPDISCOVER. Odgovor se šalje na port "odakle je došao", putem broadcasta, jer u tom trenutku klijent još nema IP adresu, a stoga paket može prihvatiti samo ako je poslan široko. Klijent prepoznaje da je to paket za njega prema svom MAC adresi unutar paketa, kao i prema broju transakcije koji generira pri stvaranju prvog paketa.

Tablica strukture paketa DHCPOFFER

Pozicija u paketu
Naziv vrijednosti (opće prihvaćeno)
Primjer
Prikaz
Bajt
Objašnjenje

1
Boot Request
1
Hex
1
Tip poruke. 1 — zahtjev od klijenta prema poslužitelju, 2 — odgovor od poslužitelja klijentu

2
Vrsta hardvera
1
Hex
1
Tip hardverske adrese, u ovom protokolu 1 — MAC

3
Duljina hardverske adrese
6
Hex
1
Duljina MAC adrese uređaja

4
Hops
1
Hex
1
Broj međurute

5
Transakcijski ID
23:cf:de:1d
Hex
4
Jedinstveni identifikator transakcije. Klijent ga generira na početku operacije zahtjeva

7
Drugo proteklo vrijeme
0
Hex
4
Vrijeme u sekundama od početka procesa dobivanja adrese

9
Bootp zastavice
0
Hex
2
Neki zastavice koje se mogu postaviti kao naznaka protokolskih parametara. U ovom slučaju, 0 — označava tip zahtjeva Unicast.

11
IP adresa klijenta
0.0.0.0
Retak
4
IP adresa klijenta (ako postoji)

15
Vaša IP adresa klijenta
172.16.134.61
Retak
4
IP adresa ponuđena od strane poslužitelja (ako postoji)

19
IP adresa sljedećeg poslužitelja
0.0.0.0
Retak
4
IP adresa poslužitelja (ako je poznata)

23
IP adresa agenta preusmjeravanja
172.16.114.41
Retak
4
IP adresa agenta preusmjeravanja (na primjer, switch)

27
MAC adresa klijenta
14:d6:4d:a7:c9:55
Hex
6
MAC adresa pošiljatelja paketa (klijenta)

31
Puni sastav MAC adrese klijenta
 
Hex
10
Rezervirani prostor. Obično popunjen nulama

41
Ime poslužitelja
 
Retak
64
Ime DHCP poslužitelja. Obično se ne prenosi

105
Naziv boot datoteke
 
Retak
128
Naziv datoteke na poslužitelju koji se koristi od strane bezdiskovnih stanica prilikom podizanja.

235
Magic cookie
63:82:53:63
Hex
4
«Magični» broj, prema kojem se može odrediti pripada li ovaj paket DHCP protokolu.

DHCP opcije. Mogu se pojaviti u bilo kojem redoslijedu.

236
Broj opcije
53
Dec
1
Opcija 53, koja određuje tip DHCP paketa 2 — DHCPOFFER.

 
Duljina opcije
1
Dec
1

 
Vrijednost opcije
2
Dec
1

 
Broj opcije
1
Dec
1
Opcija koja nudi DHCP klijentu masku podmreže.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
255.255.224.0
Retak
4

 
Broj opcije
3
Dec
1
Opcija koja nudi DHCP klijentu zadani prolaz.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
172.16.12.1
Retak
4

 
Broj opcije
6
Dec
1
Opcija koja nudi DHCP klijentu DNS.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
8.8.8.8
Retak
4

 
Broj opcije
51
Dec
1
Vrijeme trajanja izdanih mrežnih parametara u sekundama, nakon kojeg DHCP klijent treba ponovno zatražiti.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
86400
Dec
4

 
Broj opcije
82
Dec
1
Opcija 82, ponavlja ono što je došlo u DHCPDISCOVER.

 
Duljina opcije
18
Dec
1

 
Vrijednost opcije
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Kraj paketa
255
Dec
1
255 označava kraj paketa.

DHCPREQUEST

Nakon što klijent primi DHCPOFFER, oblikuje paket s zahtjevom za mrežnim parametrima ne prema svim DHCP poslužiteljima u mreži, već samo jednom konkretnom, čija mu je ponuda DHCPOFFER bila najprivlačnija. Kriteriji 'privlačnosti' mogu biti različiti i ovise o implementaciji DHCP klijenta. Pr menerima zahtjeva se navodi pomoću MAC adrese DHCP poslužitelja. Također, paket DHCPREQUEST može biti poslan od strane klijenta i bez prethodnog formiranja DHCPDISCOVER, ako je IP adresa već ranije dobivena od poslužitelja.

Tablica strukture paketa DHCPREQUEST

Pozicija u paketu
Naziv vrijednosti (opće prihvaćeno)
Primjer
Prikaz
Bajt
Objašnjenje

1
Boot Request
1
Hex
1
Tip poruke. 1 — zahtjev od klijenta prema poslužitelju, 2 — odgovor od poslužitelja klijentu

2
Vrsta hardvera
1
Hex
1
Tip hardverske adrese, u ovom protokolu 1 — MAC

3
Duljina hardverske adrese
6
Hex
1
Duljina MAC adrese uređaja

4
Hops
1
Hex
1
Broj međurute

5
Transakcijski ID
23:cf:de:1d
Hex
4
Jedinstveni identifikator transakcije. Klijent ga generira na početku operacije zahtjeva

7
Drugo proteklo vrijeme
0
Hex
4
Vrijeme u sekundama od početka procesa dobivanja adrese

9
Bootp zastavice
8000
Hex
2
Neki flagovi koji se mogu postaviti kao oznaka parametara protokola. U ovom slučaju je postavljen 'broadcast'

11
IP adresa klijenta
0.0.0.0
Retak
4
IP adresa klijenta (ako postoji)

15
Vaša IP adresa klijenta
172.16.134.61
Retak
4
IP adresa ponuđena od strane poslužitelja (ako postoji)

19
IP adresa sljedećeg poslužitelja
0.0.0.0
Retak
4
IP adresa poslužitelja (ako je poznata)

23
IP adresa agenta preusmjeravanja
172.16.114.41
Retak
4
IP adresa agenta preusmjeravanja (na primjer, switch)

27
MAC adresa klijenta
14:d6:4d:a7:c9:55
Hex
6
MAC adresa pošiljatelja paketa (klijenta)

31
Puni sastav MAC adrese klijenta
 
Hex
10
Rezervirani prostor. Obično popunjen nulama

41
Ime poslužitelja
 
Retak
64
Ime DHCP poslužitelja. Obično se ne prenosi

105
Naziv boot datoteke
 
Retak
128
Naziv datoteke na poslužitelju koji se koristi od strane bezdiskovnih stanica prilikom podizanja.

235
Magic cookie
63:82:53:63
Hex
4
«Magični» broj, prema kojem se može odrediti pripada li ovaj paket DHCP protokolu.

DHCP opcije. Mogu se pojaviti u bilo kojem redoslijedu.

236
Broj opcije
53
Dec
3
Opcija 53, koja definira tip paketa DHCP 3 — DHCPREQUEST

 
Duljina opcije
1
Dec
1

 
Vrijednost opcije
3
Dec
1

 
Broj opcije
61
Dec
1
Identifikator klijenta: 01 (za Ethernet) + MAC adresa klijenta

 
Duljina opcije
7
Dec
1

 
Vrijednost opcije
01:2c:ab:25:ff:72:a6
Hex
7

 
Broj opcije
60
Dec
 
«Vendor class identifier». U mom slučaju javlja verziju DHCP klijenta. Moguće je da druga uređaji vraćaju nešto drugo. Windows, na primjer, izvještava MSFT 5.0

 
Duljina opcije
11
Dec
 

 
Vrijednost opcije
udhcp 0.9.8
Retak
 

 
Broj opcije
55
 
1
Zahtijevani mrežni parametri od strane klijenta. Sadržaj može biti različit.

01 — Maska podmreže
03 — Prolaz
06 — DNS
oc — Ime hosta
0f — ime domene mreže
1c — adresa multicast (broadcast) zahtjeva
42 — ime TFTP poslužitelja
79 — Classless Static Route

 
Duljina opcije
8
 
1

 
Vrijednost opcije
01:03:06:0c:0f:1c:42:79
 
8

 
Broj opcije
82
Dec
1
Opcija 82, ponavlja ono što je došlo u DHCPDISCOVER.

 
Duljina opcije
18
Dec
1

 
Vrijednost opcije
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Kraj paketa
255
Dec
1
255 označava kraj paketa.

DHCPACK

Kao potvrda da 'da, to je tvoja IP adresa i više je neću dodijeliti nikome drugome' od DHCP poslužitelja služi paket u formatu DHCPACK koji poslužitelj šalje klijentu. Također, kao i ostali paketi, šalje se širokoupno. Iako, u niže prikazanom kodu DHCP poslužitelja implementiranog na Pythonu, za svaki slučaj dupliciram bilo koji širokoupni zahtjev slanjem paketa na određeni IP klijenta, ako je već poznat. Osim toga, DHCP poslužitelju nije važno je li paket DHCPACK stigao do klijenta. Ako klijent ne primi DHCPACK, nakon nekog vremena jednostavno ponavlja DHCPREQUEST.

Tablica strukture paketa DHCPACK

Pozicija u paketu
Naziv vrijednosti (opće prihvaćeno)
Primjer
Prikaz
Bajt
Objašnjenje

1
Boot Request
2
Hex
1
Tip poruke. 1 — zahtjev od klijenta prema poslužitelju, 2 — odgovor od poslužitelja klijentu

2
Vrsta hardvera
1
Hex
1
Tip hardverske adrese, u ovom protokolu 1 — MAC

3
Duljina hardverske adrese
6
Hex
1
Duljina MAC adrese uređaja

4
Hops
1
Hex
1
Broj međurute

5
Transakcijski ID
23:cf:de:1d
Hex
4
Jedinstveni identifikator transakcije. Klijent ga generira na početku operacije zahtjeva

7
Drugo proteklo vrijeme
0
Hex
4
Vrijeme u sekundama od početka procesa dobivanja adrese

9
Bootp zastavice
8000
Hex
2
Neki flagovi koji se mogu postaviti kao oznaka parametara protokola. U ovom slučaju je postavljen 'broadcast'

11
IP adresa klijenta
0.0.0.0
Retak
4
IP adresa klijenta (ako postoji)

15
Vaša IP adresa klijenta
172.16.134.61
Retak
4
IP adresa ponuđena od strane poslužitelja (ako postoji)

19
IP adresa sljedećeg poslužitelja
0.0.0.0
Retak
4
IP adresa poslužitelja (ako je poznata)

23
IP adresa agenta preusmjeravanja
172.16.114.41
Retak
4
IP adresa agenta preusmjeravanja (na primjer, switch)

27
MAC adresa klijenta
14:d6:4d:a7:c9:55
Hex
6
MAC adresa pošiljatelja paketa (klijenta)

31
Puni sastav MAC adrese klijenta
 
Hex
10
Rezervirani prostor. Obično popunjen nulama

41
Ime poslužitelja
 
Retak
64
Ime DHCP poslužitelja. Obično se ne prenosi

105
Naziv boot datoteke
 
Retak
128
Naziv datoteke na poslužitelju koji se koristi od strane bezdiskovnih stanica prilikom podizanja.

235
Magic cookie
63:82:53:63
Hex
4
«Magični» broj, prema kojem se može odrediti pripada li ovaj paket DHCP protokolu.

DHCP opcije. Mogu se pojaviti u bilo kojem redoslijedu.

236
Broj opcije
53
Dec
3
Opcija 53, koja definira tip paketa DHCP 5 — DHCPACK

 
Duljina opcije
1
Dec
1

 
Vrijednost opcije
5
Dec
1

 
Broj opcije
1
Dec
1
Opcija koja nudi DHCP klijentu masku podmreže.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
255.255.224.0
Retak
4

 
Broj opcije
3
Dec
1
Opcija koja nudi DHCP klijentu zadani prolaz.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
172.16.12.1
Retak
4

 
Broj opcije
6
Dec
1
Opcija koja nudi DHCP klijentu DNS.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
8.8.8.8
Retak
4

 
Broj opcije
51
Dec
1
Vrijeme trajanja izdanih mrežnih parametara u sekundama, nakon kojeg DHCP klijent treba ponovno zatražiti.

 
Duljina opcije
4
Dec
1

 
Vrijednost opcije
86400
Dec
4

 
Broj opcije
82
Dec
1
Opcija 82, ponavlja ono što je došlo u DHCPDISCOVER.

 
Duljina opcije
18
Dec
1

 
Vrijednost opcije
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Kraj paketa
255
Dec
1
255 označava kraj paketa.

Instalacija

Instalacija se zapravo sastoji u postavljanju potrebnih python modula za rad. Pretpostavlja se da je MySQL već instaliran i konfiguriran.

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

Stvaramo MySQL bazu podataka, učitavamo u nju dump pydhcp.sql, postavljamo datoteku s konfiguracijom.

Konfiguracija

Sve postavke poslužitelja nalaze se u datoteci formata xml. Referentna datoteka:

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')

Sada malo detaljnije o tagovima:

Sekcija dhcpserver opisuje osnovne postavke za pokretanje servera, odnosno:

  • host — koji IP adresa sluša server na portu 67
  • broadcast — koji IP je broadcast za DHCPOFFER i DHCPACK
  • DHCPServer — koji IP ima DHCP server
  • LeaseTime vremenski period zakupa izdanog IP adresa
  • ThreadLimit — koliko istodobno niti je pokrenuto za obradu pristiglih UDP paketa na portu 67. Smatra se da će pomoći na visoko opterećenim projektima 😉
  • defaultMask,defaultRouter,defaultDNS — što se nudi pretplatniku prema zadanim postavkama, ako je IP pronađen u bazi, ali dodatne postavke za njega nisu navedene

Sekcija mysql:

host,username,password,basename — sve govori samo za sebe. Približna struktura baze podataka je objavljena na GitHub

Sekcija query: ovdje se opisuju upitnici za dobivanje OFFER/ACK:

  • offer_count — broj redaka s upitima koji vraćaju rezultat u obliku ip,mask,router,dns
  • offer_n — redak upita. Ako je povratak — prazan, izvršava sljedeći upit offer
  • history_sql — upit koji zapisuje, na primjer, u "povijest autorizacije" za pretplatnika

U upitima mogu sudjelovati bilo koje varijable iz sekcije options ili opcije iz DHCP protokola.

Sekcija options. Ovdje postaje zanimljivije. Ovdje možemo kreirati varijable koje možemo koristiti dalje u sekciji query.

Na primjer:

option_82_hex:sw_port1:20:22

, ova naredba uzima cijeli string iz DHCP zahtjeva opcije 82, u hex formatu, u rasponu od 20. do 22. bajta uključivo i stavlja ga u novu varijablu sw_port1 (port switcha odakle je došao zahtjev)

option_82_hex:sw_mac:26:40

, definira varijablu sw_mac, uzimajući hex iz raspona 26:40

Sve moguće opcije koje se mogu koristiti u zahtjevima mogu se vidjeti pokretanjem servera s ključem -d. Vidjet ćemo okvirno takav log:

--prispjeli paket DHCPINFORM na portu 67, od 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'}

Stoga, možemo bilo koju varijablu staviti u {} i bit će korištena u SQL zahtjevu.

Zabilježimo za povijest koji je IP adresa klijent dobio:

DHCP+Mysql server na Pythonu

DHCP+Mysql server na Pythonu

Pokretanje servera

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

— d način ispravnog ispisivanja u konzolu DEBUG
— c <ime_datoteke> konfiguracijska datoteka

Analiza

A sada ćemo detaljnije proći kroz implementaciju servera na Pythonu. To je boli. Python se učio "u hodu". Mnogi momenti su napravljeni u stilu: "wow, nekako sam to napravio i radi". Nije uopće optimizirano i ostavljeno je u tom stanju uglavnom zbog malo iskustva u razvoju na Pythonu. Zastat ću na najzanimljivijim momentima implementacije servera u "kodovima".

Parser XML konfiguracijske datoteke

Koristi se standardni Python modul xml.dom. Izgleda jednostavno, ali pri implementaciji nedostajalo je kvalitetne dokumentacije i primjera na mreži koji koriste ovaj modul.

    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)

Višestruko izvršavanje

Zanimljivo je da je višestruko izvršavanje u Pythonu realizirano vrlo jasno i jednostavno.

def PacketWork(data,addr): 
...
# implementacija analize primljenog paketa i odgovora na njega
...


while True:
    data, addr = udp_socket.recvfrom(1024) # čekamo UDP paket
    thread = threading.Thread(target=PacketWork, args=(data,addr,)).start()	# čim stigne - pokrećemo u pozadini prethodno definiranu funkciju PacketWork s parametrima
    while threading.active_count() > gconfig["dhcp_ThreadLimit"]:
       time.sleep(1) # ako je broj već pokrenutih niti veći od postavki, čekamo dok ih ne bude manje

Prijem/otprema DHCP paketa

Da biste presreli UDP pakete koji prolaze kroz mrežnu kartu, potrebno je "podignuti" soket:

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

, gdje su znakovi:

  • AF_INET — označava da će format adrese biti IP: port. Može biti i AF_UNIX — gdje se adresa zadava imenom datoteke.
  • SOCK_DGRAM — označava da primamo ne 'sirovi paket', već paket koji je prošao kroz vatrozid i sa djelomično rezanim paketom. Odnosno, dobivamo samo UDP paket bez 'fizičke' omotnice UDP paketa. Ako koristimo oznaku SOCK_RAW, morat ćemo dodatno obraditi i tu 'omotnicu'.

Slanje paketa može biti kao broadcast:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # prebacujemo socket u način slanja broadcasta
                    rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, kao i na adresu 'odakle je paket stigao':

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # prebacujemo socket u način 'više slušatelja'
                        rz=udp_socket.sendto(packetack, addr)

, gdje SOL_SOCKET označava 'razinu protokola' za postavljanje opcija,

, SO_BROADCAST je opcija koja označava da paket šaljemo 'broadcastom'

  , SO_REUSEADDR je opcija koja prebacuje socket u način 'više slušatelja'. Ideja je da nije potrebna u ovom slučaju, ali na jednom od FreeBSD servera na kojem sam testirao, bez ove opcije kod nije radio.

Razrada DHCP paketa

Ovdje mi se stvarno svidio Python. Naime, iz 'kutije' omogućava prilično slobodno postupanje s bajt kodom. Omogućava vrlo jednostavno pretvaranje u decimalne vrijednosti, nizove i hex — tj. ono što nam je zapravo potrebno da razumijemo strukturu paketa. Tako možemo dobiti raspon bajtova u HEX i običnim bajtovima:

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

, pakirati bajtove u strukturu:

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

Dobiti IP iz strukture:

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

I obrnuto:

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

Na tome je sve 😉

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster