DHCP+Mysql-server pÄ Python

DHCP+Mysql-server pÄ Python

Syftet med detta projekt var:

  • Studie av DHCP-protokollet nĂ€r det anvĂ€nds i IPv4-nĂ€tverk
  • Studie av Python (nĂ„got mer Ă€n frĂ„n grunden 😉 )
  • byte av server DB2DHCP (min fork), originalet hĂ€r, som det blir svĂ„rare och svĂ„rare att kompilera för det nya operativsystemet. Och jag gillar inte att det finns en binĂ€rfil som man inte kan "byta ut just nu"
  • skapa en fungerande DHCP-server med möjlighet att hĂ€mta IP-adressen för en klient baserat pĂ„ klientens mac-adress eller kombinationen av switchens mac-adress + port (Option 82)
  • skriva Ă€nnu ett exemplar (Åh! det Ă€r min favoritaktivitet)
  • fĂ„ kritik för min klumpighet pĂ„ Habrhabr (eller helst en inbjudan) 😉

Resultat: fungerar 😉 Testat pĂ„ FreeBSD och Ubuntu. Teoretiskt kan koden anpassas för att fungera pĂ„ vilket operativsystem som helst, eftersom det inte verkar finnas nĂ„gra specifika bindningar i koden.
Varning! Mycket mer följer.

LÀnk till repository för dem som vill "ta pÄ det i verkligheten".

Processen för installation, konfiguration och anvĂ€ndning av resultatet av "studien av materien" beskrivs lĂ€ngre ner, följt av lite teori om DHCP-protokollet. För mig. Och för historien 😉

Lite teori

Vad Àr DHCP

Det Àr ett nÀtverksprotokoll som tillÄter en enhet att ta reda pÄ sin IP-adress (och andra parametrar som gateway, DNS och sÄ vidare) frÄn en DHCP-server. Paketbyte sker via UDP-protokollet. Den allmÀnna principen för hur enheten fungerar vid begÀran av nÀtverksparametrar Àr följande:

  1. Enheten (klienten) skickar en broadcast UDP-begÀran (DHCPDISCOVER) över hela nÀtverket med begÀran "nÄgon, ge mig en IP-adress". Vanligtvis (men inte alltid) sker begÀran frÄn port 68 (kÀlla) till port 67 (destination). Vissa enheter skickar paket Àven frÄn port 67. Inuti DHCPDISCOVER-paketet finns klientens MAC-adress.
  2. Alla DHCP-servrar i nÀtverket (och de kan vara flera) formar ett erbjudande, DHCPOFFER, med nÀtverksinstÀllningar för enheten som skickade DHCPDISCOVER, och skickar det ocksÄ som broadcast över nÀtverket. Identifieringen av till vem detta paket Àr avsett sker med hjÀlp av klientens MAC-adress som gavs tidigare i DHCPDISCOVER-begÀran.
  3. Kunden tar emot paket med nÀtverksinstÀllningar, vÀljer det som Àr mest attraktivt (kriterier kan variera, till exempel tid för paketleverans eller antal mellanliggande vÀgar), och gör en "officiell begÀran" DHCPREQUEST med nÀtverksinstÀllningarna till den servern som han gillar. I detta fall gÄr paketet direkt till en specifik DHCP-server.
  4. Servern som mottagit DHCPREQUEST skickar ett paket av formatet DHCPACK, dÀr den Àn en gÄng listar nÀtverksinstÀllningarna som Àr avsedda för denna klient.

DHCP+Mysql-server pÄ Python

Dessutom finns det DHCPINFORM-paket som skickas frÄn klienten med syftet att informera DHCP-servern om att "klienten Àr aktiv" och anvÀnder de tilldelade nÀtverksinstÀllningarna. I denna serversimplementation ignoreras dessa paket.

Paketformat

Generellt ser Ethernet-paketets ram ungefÀr ut sÄ hÀr:

DHCP+Mysql-server pÄ Python

I vÄrt fall kommer vi endast att titta pÄ datan i UDP-paketet, utan headers för OSI-protokollen, det vill sÀga strukturen av DHCP:

DHCPDISCOVER

SÄ, processen för att erhÄlla en IP-adress för en enhet börjar med att DHCP-klienten skickar en broadcast-förfrÄgan frÄn port 68 till 255.255.255.255:67. I detta paket inkluderar klienten sin MAC-adress samt vad den vill fÄ frÄn DHCP-servern. Paketstrukturen beskrivs i tabellen nedan.

Tabell över strukturen av paketet DHCPDISCOVER

Position i paketet
Namn pÄ vÀrdet
Exempel
Representation
Byte
Förklaring

1
Boot Request
1
Hex
1
Typ av meddelande. 1 — begĂ€ran frĂ„n klient till server, 2 — svar frĂ„n server till klient.

2
HÄrdvarutyp
1
Hex
1
Typ av hĂ„rdvaruadress, i detta protokoll 1 — MAC.

3
LÀngd av hÄrdvaruadressen
6
Hex
1
LÀngd pÄ enhetens MAC-adress.

4
Hops
1
Hex
1
Antal mellanliggande vÀgar.

5
Transaktions-ID
23:cf:de:1d
Hex
4
Unik identifierare för transaktionen. Genereras av klienten i början av begÀrningsoperationen.

7
Sekunder förflutna
0
Hex
4
Tiden i sekunder sedan början pÄ processen för att erhÄlla en adress.

9
Bootp-flaggor
0
Hex
2
Vissa flaggor som kan sÀttas som indikator av protokollparametrar.

11
Klientens IP-adress
0.0.0.0
StrÀng
4
IP-adress för klienten (om det finns).

15
Din klient-IP-adress
0.0.0.0
StrÀng
4
IP-adress som föreslagits av servern (om det finns).

19
NĂ€sta servers IP-adress
0.0.0.0
StrÀng
4
IP-adress för servern (om den Àr kÀnd).

23
Relay-agentens IP-adress
172.16.114.41
StrÀng
4
IP-adress för relay-agenten (t.ex. switch).

27
Klientens MAC-adress
14:d6:4d:a7:c9:55
Hex
6
MAC-adressen för avsÀndaren av paketet (klienten).

31
Padding av klientens hÄrdvaruadress
 
Hex
10
Reserverat utrymme. Vanligtvis fyllt med nollor.

41
Serverns vÀrdnamn
 
StrÀng
64
Namn pÄ DHCP-servern. Vanligtvis inte överförs.

105
Boot-filnamn
 
StrÀng
128
Filnamn pÄ servern som anvÀnds av diskfria stationer vid start

235
Magic cookie
63:82:53:63
Hex
4
Ett »magiskt« nummer som kan anvÀndas för att avgöra att detta paket tillhör DHCP-protokollet

DHCP-alternativ. Kan komma i valfri ordning

236
Alternativnummer
53
Dec
1
Alternativ 53 som definierar typen av DHCP-paket

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

 
Alternativets lÀngd
1
Dec
1

 
Alternativets vÀrde
1
Dec
1

 
Alternativnummer
50
Dec
1
Vilken IP-adress vill klienten fÄ

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
172.16.134.61
StrÀng
4

 
Alternativnummer
55
 
1
De nÀtverksparametrar som begÀrs av klienten. InnehÄllet kan variera

01 — NĂ€tmask
03 — Gateway
06 — DNS
oc — VĂ€rdnamn
0f — nĂ€tverks domĂ€nnamn
1c — adress för sĂ€ndning av brĂ„dskande meddelanden (broadcast)
42 — namn pĂ„ TFTP-servern
79 — Classless Static Route

 
Alternativets lÀngd
8
 
1

 
Alternativets vÀrde
01:03:06:0c:0f:1c:42:79
 
8

 
Alternativnummer
82
Dec
 
Alternativ 82, dĂ€r MAC-adressen för enheter — retransmittorn och vissa ytterligare vĂ€rden överförs.

Oftast — porten pĂ„ switchen dĂ€r den slutgiltiga DHCP-klienten arbetar. I detta alternativ Ă€r det »inbĂ€ddade« ytterligare parametrar. Den första byte — subalternativets nummer, den andra dess lĂ€ngd, dĂ€refter dess vĂ€rde.

I detta fall bÀr alternativ 82 subalternativ:
Agent Circuit ID = 00:04:00:01:00:04, dÀr de sista tvÄ bytes Àr porten för DHCP-klienten som skickade begÀran

Agent Remote ID = 00:06:c8:be:19:93:11:48 — MAC-adressen för retransmittoren DHCP

 
Alternativets lÀngd
18
Dec
 

 
Alternativets vÀrde
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
Paketets slut
255
Dec
1
255 symboliserar slutet av paketet

DHCPOFFER

SĂ„ snart servern mottar paketet DHCPDISCOVER och om den ser att den kan erbjuda nĂ„got till klienten frĂ„n vad som begĂ€rdes, sĂ„ formar den ett svar — DHCPDISCOVER. Svaret skickas tillbaka till porten »frĂ„n vilken den kom«, som en broadcast, eftersom klienten för tillfĂ€llet Ă€nnu inte har nĂ„gon IP-adress, sĂ„ paketet kan endast tas emot om det skickas ut som en brĂ„dskande sĂ€ndning. Klienten kĂ€nner igen att detta paket Ă€r för den genom sin MAC-adress inuti paketet, sĂ„vĂ€l som transaktionsnumret som den genererar vid skapandet av det första paketet.

Strukturen för DHCPOFFER-paketet

Position i paketet
Namn pÄ vÀrdet (vanligtvis)
Exempel
Representation
Byte
Förklaring

1
Boot Request
1
Hex
1
Typ av meddelande. 1 — begĂ€ran frĂ„n klient till server, 2 — svar frĂ„n server till klient.

2
HÄrdvarutyp
1
Hex
1
Typ av hĂ„rdvaruadress, i detta protokoll 1 — MAC.

3
LÀngd av hÄrdvaruadressen
6
Hex
1
LÀngd pÄ enhetens MAC-adress.

4
Hops
1
Hex
1
Antal mellanliggande vÀgar.

5
Transaktions-ID
23:cf:de:1d
Hex
4
Unik identifierare för transaktionen. Genereras av klienten i början av begÀrningsoperationen.

7
Sekunder förflutna
0
Hex
4
Tiden i sekunder sedan början pÄ processen för att erhÄlla en adress.

9
Bootp-flaggor
0
Hex
2
Vissa flaggor som kan stĂ€llas in som en indikation pĂ„ protokollparametrar. I detta fall, 0 — betyder typ av begĂ€ran Unicast

11
Klientens IP-adress
0.0.0.0
StrÀng
4
IP-adress för klienten (om det finns).

15
Din klient-IP-adress
172.16.134.61
StrÀng
4
IP-adress som föreslagits av servern (om det finns).

19
NĂ€sta servers IP-adress
0.0.0.0
StrÀng
4
IP-adress för servern (om den Àr kÀnd).

23
Relay-agentens IP-adress
172.16.114.41
StrÀng
4
IP-adress för relay-agenten (t.ex. switch).

27
Klientens MAC-adress
14:d6:4d:a7:c9:55
Hex
6
MAC-adressen för avsÀndaren av paketet (klienten).

31
Padding av klientens hÄrdvaruadress
 
Hex
10
Reserverat utrymme. Vanligtvis fyllt med nollor.

41
Serverns vÀrdnamn
 
StrÀng
64
Namn pÄ DHCP-servern. Vanligtvis inte överförs.

105
Boot-filnamn
 
StrÀng
128
Filnamn pÄ servern som anvÀnds av diskfria stationer vid start

235
Magic cookie
63:82:53:63
Hex
4
Ett »magiskt« nummer som kan anvÀndas för att avgöra att detta paket tillhör DHCP-protokollet

DHCP-alternativ. Kan komma i valfri ordning

236
Alternativnummer
53
Dec
1
Alternativ 53, som definierar typen av DHCP-paket 2 — DHCPOFFER

 
Alternativets lÀngd
1
Dec
1

 
Alternativets vÀrde
2
Dec
1

 
Alternativnummer
1
Dec
1
Alternativ som erbjuder DHCP-klienten nÀtmask

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
255.255.224.0
StrÀng
4

 
Alternativnummer
3
Dec
1
Alternativ som erbjuder DHCP-klienten standard gateway

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
172.16.12.1
StrÀng
4

 
Alternativnummer
6
Dec
1
Alternativ som erbjuder DHCP-klienten DNS

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
8.8.8.8
StrÀng
4

 
Alternativnummer
51
Dec
1
LivslÀngden för de utfÀrdade nÀtverksparametrarna i sekunder, efter vilken DHCP-klienten mÄste begÀra dem igen

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
86400
Dec
4

 
Alternativnummer
82
Dec
1
Alternativ 82, upprepar vad som kom i DHCPDISCOVER

 
Alternativets lÀngd
18
Dec
1

 
Alternativets vÀrde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Paketets slut
255
Dec
1
255 symboliserar slutet av paketet

DHCPREQUEST

Efter att klienten har fÄtt DHCPOFFER, skapar den ett paket med begÀran om nÀtverksparametrar, inte till alla DHCP-servrar i nÀtverket, utan endast till en specifik, vars DHCPOFFER-erbjudande den tyckte mest om. Kriterierna för "tyckte om" kan variera och beror pÄ implementeringen av DHCP-klienten. Mottagaren av begÀran anges med MAC-adressen för DHCP-servern. Dessutom kan paketet DHCPREQUEST skickas av klienten utan att ha bildat tidigare DHCPDISCOVER, om IP-adressen frÄn servern redan tidigare har erhÄllits.

Tabell över strukturen för DHCPREQUEST-paketet

Position i paketet
Namn pÄ vÀrdet (vanligtvis)
Exempel
Representation
Byte
Förklaring

1
Boot Request
1
Hex
1
Typ av meddelande. 1 — begĂ€ran frĂ„n klient till server, 2 — svar frĂ„n server till klient.

2
HÄrdvarutyp
1
Hex
1
Typ av hĂ„rdvaruadress, i detta protokoll 1 — MAC.

3
LÀngd av hÄrdvaruadressen
6
Hex
1
LÀngd pÄ enhetens MAC-adress.

4
Hops
1
Hex
1
Antal mellanliggande vÀgar.

5
Transaktions-ID
23:cf:de:1d
Hex
4
Unik identifierare för transaktionen. Genereras av klienten i början av begÀrningsoperationen.

7
Sekunder förflutna
0
Hex
4
Tiden i sekunder sedan början pÄ processen för att erhÄlla en adress.

9
Bootp-flaggor
8000
Hex
2
NÄgra flaggor kan sÀttas för att indikera protokollparametrar. I detta fall Àr "broadcast" instÀllt.

11
Klientens IP-adress
0.0.0.0
StrÀng
4
IP-adress för klienten (om det finns).

15
Din klient-IP-adress
172.16.134.61
StrÀng
4
IP-adress som föreslagits av servern (om det finns).

19
NĂ€sta servers IP-adress
0.0.0.0
StrÀng
4
IP-adress för servern (om den Àr kÀnd).

23
Relay-agentens IP-adress
172.16.114.41
StrÀng
4
IP-adress för relay-agenten (t.ex. switch).

27
Klientens MAC-adress
14:d6:4d:a7:c9:55
Hex
6
MAC-adressen för avsÀndaren av paketet (klienten).

31
Padding av klientens hÄrdvaruadress
 
Hex
10
Reserverat utrymme. Vanligtvis fyllt med nollor.

41
Serverns vÀrdnamn
 
StrÀng
64
Namn pÄ DHCP-servern. Vanligtvis inte överförs.

105
Boot-filnamn
 
StrÀng
128
Filnamn pÄ servern som anvÀnds av diskfria stationer vid start

235
Magic cookie
63:82:53:63
Hex
4
Ett »magiskt« nummer som kan anvÀndas för att avgöra att detta paket tillhör DHCP-protokollet

DHCP-alternativ. Kan komma i valfri ordning

236
Alternativnummer
53
Dec
3
Alternativ 53, som definierar typen av DHCP-paket 3 - DHCPREQUEST

 
Alternativets lÀngd
1
Dec
1

 
Alternativets vÀrde
3
Dec
1

 
Alternativnummer
61
Dec
1
Klientidentifierare: 01 (för Ethernet) + klientens MAC-adress

 
Alternativets lÀngd
7
Dec
1

 
Alternativets vÀrde
01:2c:ab:25:ff:72:a6
Hex
7

 
Alternativnummer
60
Dec
 
"Vendor class identifier". I mitt fall rapporterar den versionen av DHCP-klienten. Andra enheter kan returnera nÄgot annat. Windows till exempel meddelar MSFT 5.0

 
Alternativets lÀngd
11
Dec
 

 
Alternativets vÀrde
udhcp 0.9.8
StrÀng
 

 
Alternativnummer
55
 
1
De nÀtverksparametrar som begÀrs av klienten. InnehÄllet kan variera

01 — NĂ€tmask
03 — Gateway
06 — DNS
oc — VĂ€rdnamn
0f — nĂ€tverks domĂ€nnamn
1c — adress för sĂ€ndning av brĂ„dskande meddelanden (broadcast)
42 — namn pĂ„ TFTP-servern
79 — Classless Static Route

 
Alternativets lÀngd
8
 
1

 
Alternativets vÀrde
01:03:06:0c:0f:1c:42:79
 
8

 
Alternativnummer
82
Dec
1
Alternativ 82, upprepar vad som kom i DHCPDISCOVER

 
Alternativets lÀngd
18
Dec
1

 
Alternativets vÀrde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Paketets slut
255
Dec
1
255 symboliserar slutet av paketet

DHCPACK

Som bekrÀftelse pÄ att "ja, precis, det Àr din IP-adress och jag kommer inte att ge den till nÄgon annan" frÄn DHCP-servern, fungerar paketet i formatet DHCPACK frÄn servern till klienten. Det skickas precis som de andra paketen i broadcast. Dock, i nedan presenterad kod för en DHCP-server implementerad i Python, duplicerar jag varje broadcast-begÀran genom att skicka paketet till en specifik IP-adress för klienten, om den redan Àr kÀnd. DHCP-servern bryr sig inte om paketet DHCPACK nÄdde klienten. Om klienten inte fÄr DHCPACK, upprepar den helt enkelt DHCPREQUEST efter en tid.

Tabell över strukturen för DHCPACK-paketet

Position i paketet
Namn pÄ vÀrdet (vanligtvis)
Exempel
Representation
Byte
Förklaring

1
Boot Request
2
Hex
1
Typ av meddelande. 1 — begĂ€ran frĂ„n klient till server, 2 — svar frĂ„n server till klient.

2
HÄrdvarutyp
1
Hex
1
Typ av hĂ„rdvaruadress, i detta protokoll 1 — MAC.

3
LÀngd av hÄrdvaruadressen
6
Hex
1
LÀngd pÄ enhetens MAC-adress.

4
Hops
1
Hex
1
Antal mellanliggande vÀgar.

5
Transaktions-ID
23:cf:de:1d
Hex
4
Unik identifierare för transaktionen. Genereras av klienten i början av begÀrningsoperationen.

7
Sekunder förflutna
0
Hex
4
Tiden i sekunder sedan början pÄ processen för att erhÄlla en adress.

9
Bootp-flaggor
8000
Hex
2
NÄgra flaggor kan sÀttas för att indikera protokollparametrar. I detta fall Àr "broadcast" instÀllt.

11
Klientens IP-adress
0.0.0.0
StrÀng
4
IP-adress för klienten (om det finns).

15
Din klient-IP-adress
172.16.134.61
StrÀng
4
IP-adress som föreslagits av servern (om det finns).

19
NĂ€sta servers IP-adress
0.0.0.0
StrÀng
4
IP-adress för servern (om den Àr kÀnd).

23
Relay-agentens IP-adress
172.16.114.41
StrÀng
4
IP-adress för relay-agenten (t.ex. switch).

27
Klientens MAC-adress
14:d6:4d:a7:c9:55
Hex
6
MAC-adressen för avsÀndaren av paketet (klienten).

31
Padding av klientens hÄrdvaruadress
 
Hex
10
Reserverat utrymme. Vanligtvis fyllt med nollor.

41
Serverns vÀrdnamn
 
StrÀng
64
Namn pÄ DHCP-servern. Vanligtvis inte överförs.

105
Boot-filnamn
 
StrÀng
128
Filnamn pÄ servern som anvÀnds av diskfria stationer vid start

235
Magic cookie
63:82:53:63
Hex
4
Ett »magiskt« nummer som kan anvÀndas för att avgöra att detta paket tillhör DHCP-protokollet

DHCP-alternativ. Kan komma i valfri ordning

236
Alternativnummer
53
Dec
3
Alternativ 53, som definierar typen av DHCP-paket 5 - DHCPACK

 
Alternativets lÀngd
1
Dec
1

 
Alternativets vÀrde
5
Dec
1

 
Alternativnummer
1
Dec
1
Alternativ som erbjuder DHCP-klienten nÀtmask

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
255.255.224.0
StrÀng
4

 
Alternativnummer
3
Dec
1
Alternativ som erbjuder DHCP-klienten standard gateway

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
172.16.12.1
StrÀng
4

 
Alternativnummer
6
Dec
1
Alternativ som erbjuder DHCP-klienten DNS

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
8.8.8.8
StrÀng
4

 
Alternativnummer
51
Dec
1
LivslÀngden för de utfÀrdade nÀtverksparametrarna i sekunder, efter vilken DHCP-klienten mÄste begÀra dem igen

 
Alternativets lÀngd
4
Dec
1

 
Alternativets vÀrde
86400
Dec
4

 
Alternativnummer
82
Dec
1
Alternativ 82, upprepar vad som kom i DHCPDISCOVER

 
Alternativets lÀngd
18
Dec
1

 
Alternativets vÀrde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
Paketets slut
255
Dec
1
255 symboliserar slutet av paketet

Installation

Installationen innebÀr faktiskt att installera de pythonmoduler som behövs för att fungera. Antas att MySQL redan Àr installerat och konfigurerat.

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

Skapa MySQL-databasen, ladda upp dumpen pydhcp.sql, konfigurera konfigurationsfilen.

Konfiguration

Alla serverinstÀllningar ligger i en fil i xml-format. Referensfil:

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

Nu ska vi titta nÀrmare pÄ taggarna:

Sektionen dhcpserver beskriver de grundlÀggande instÀllningarna för att starta servern, nÀmligen:

  • host — vilken IP-adress servern lyssnar pĂ„ pĂ„ port 67
  • broadcast — vilken IP som Ă€r broadcast för DHCPOFFER och DHCPACK
  • DHCPServer — vilken IP som anvĂ€nds av DHCP-servern
  • LeaseTime Ă€r tiden för uthyrning av den tilldelade IP-adressen
  • ThreadLimit — hur mĂ„nga trĂ„dar som körs samtidigt för att bearbeta mottagna UDP-paket pĂ„ port 67. Antas hjĂ€lpa vid högtrafikprojekt 😉
  • defaultMask, defaultRouter, defaultDNS — det som erbjuds abonnenten som standard om IP finns i databasen men inga ytterligare parametrar anges för den

Sektion mysql:

host, username, password, basename — allt talar för sig sjĂ€lv. En ungefĂ€rlig struktur av databasen finns publicerad pĂ„ GitHub

Sektionen query: hÀr beskrivs förfrÄgningarna för att fÄ OFFER/ACK:

  • offer_count — antalet rader med förfrĂ„gningar som returnerar resultat av typen ip, mask, router, dns
  • offer_n — förfrĂ„gningsstrĂ€ng. Om resultatet Ă€r tomt, utförs nĂ€sta förfrĂ„gan offer
  • history_sql — en förfrĂ„gan som skriver till exempel i "autentiseringshistorik" för abonnenten

I förfrÄgningarna kan alla variabler frÄn sektionen options eller alternativ frÄn DHCP-protokollet ingÄ.

Sektion options. HÀr blir det mer intressant. HÀr kan vi skapa variabler som vi kan anvÀnda senare i sektionen query.

Till exempel:

option_82_hex:sw_port1:20:22

, denna rad kommando tar hela strÀngen som kommer i DHCP-förfrÄgan i alternativ 82, i hex-format, i intervallet 20 till 22 byte inklusive och lÀgger den i en ny variabel sw_port1 (porten av switchen som begÀran kom ifrÄn)

option_82_hex:sw_mac:26:40

, vi definierar variabeln sw_mac genom att ta hex frÄn intervallet 26:40

För att se alla tillgÀngliga alternativ som kan anvÀndas i förfrÄgningar kan vi starta servern med nyckeln -d. Vi ser ungefÀr sÄ hÀr ut i loggen:

--en DHCPINFORM-paket har kommit till port 67, frÄn 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'}

DÀrför kan vi kapsla in vilken som helst variabel i {} och den kommer att anvÀndas i SQL-förfrÄgan.

LÄt oss dokumentera att IP-adressen som klienten fick:

DHCP+Mysql-server pÄ Python

DHCP+Mysql-server pÄ Python

Starta servern

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

— d lĂ€ge för att skriva ut i konsolen DEBUG
— c <filnamn> konfigurationsfil

Flygplansanalys

Nu mer i detalj om implementeringen av servern i Python. Detta Àr smÀrtsamt. Python lÀrdes "pÄ sprÄng". MÄnga aspekter gjordes pÄ ett sÀtt som: "wow, jag gjorde nÄgot som fungerar". Helt ooptimerat och kvarlÀmnat i detta tillstÄnd frÀmst pÄ grund av liten erfarenhet av utveckling i Python. Jag kommer att fokusera pÄ de mest intressanta aspekterna av serverimplementationen i "koden".

Parser för XML-konfigurationsfil

AnvÀnder den standardmodul för Python xml.dom. Det verkar enkelt, men vid implementeringen saknades verkligen bra dokumentation och exempel pÄ nÀtet som anvÀnder denna 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)

MultitrÄdning

Konstigt nog Àr trÄdning i Python implementerat pÄ ett vÀldigt tydligt och enkelt sÀtt.

def PacketWork(data, addr): 
...
# implementation of parsing the incoming packet and responding to it
...


while True:
    data, addr = udp_socket.recvfrom(1024) # wait for UDP packet
    thread = threading.Thread(target=PacketWork, args=(data, addr,)).start()	# as soon as it arrives, we launch the previously defined function PacketWork in the background with parameters
    while threading.active_count() > gconfig["dhcp_ThreadLimit"]:
       time.sleep(1) # if the number of already launched threads exceeds the settings, wait until it decreases

Mottagning/avsÀndning av DHCP-paket

För att fÄnga UDP-paket som gÄr genom nÀtverkskortet mÄste du "lyfta" en socket:

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

, dÀr flaggorna:

  • AF_INET — betyder att adressformatet kommer vara IP: port. Det kan ocksĂ„ finnas AF_UNIX — dĂ€r adressen anges med filnamnet.
  • SOCK_DGRAM — betyder att vi tar emot inte ett "rĂ„tt paket", utan ett som redan har passerat genom brandvĂ€ggen, och med en del av paketet bortskuret. Det innebĂ€r att vi fĂ„r bara UDP-paketet utan den "fysiska" komponenten av UDP-paketets omslag. Om du anvĂ€nder flaggan SOCK_RAW, mĂ„ste Ă€ven den "omslutningen" parsas.

Skickandet av paketet kan göras som broadcast:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # vÀxlar socket till broadcast-lÀge
                    rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, sÄvÀl som till adressen "dÀr paketet kom ifrÄn":

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # vÀxlar socket till "flera lyssnare"
                        rz=udp_socket.sendto(packetack, addr)

, dÀr SOL_SOCKET betyder "protokollnivÄ" för att stÀlla in alternativ,

, SO_BROADCAST Àr alternativet som gör att paketet skickas som "broadcast"

  , SO_REUSEADDR Àr alternativet som vÀxlar socket till lÀget "flera lyssnare". I teorin behövs det inte i detta fall, men pÄ en av serverarna i FreeBSD dÀr jag testade, fungerade inte koden utan detta alternativ.

Analys av DHCP-paketet

HĂ€r gillar jag verkligen Python. Det visar sig att det "ur lĂ„dan" gör att man ganska fritt kan hantera byte-kod. Det gör det vĂ€ldigt enkelt att konvertera till decimala vĂ€rden, strĂ€ngar och hex – det vill sĂ€ga det som vi faktiskt behöver för att förstĂ„ paketets struktur. Till exempel kan man fĂ„ en byte-intervall i HEX och i rena bytes:

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

, packa bytes i struktur:

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

FÄ IP frÄn strukturen:

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

Och vice versa:

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

Detta Ă€r allt 😉

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster