DHCP+Mysql-server in Python

DHCP+Mysql-server in Python

Het doel van dit project was:

  • Leren over DHCP op een IPv4-netwerk
  • Python leren (iets meer dan helemaal opnieuw 😉)
  • vervanging van servers DB2DHCP (mijn vork), origineel hier, dat steeds moeilijker te monteren wordt voor het nieuwe besturingssysteem. En ik vind het niet leuk dat het binair is en dat er geen manier is om ‘nu te veranderen’
  • het verkrijgen van een werkende DHCP-server met de mogelijkheid om het IP-adres van de abonnee te selecteren met behulp van de mac van de abonnee of de combinatie van mac+poort (optie 82)
  • nog een fiets schrijven (Oh! dit is mijn favoriete bezigheid)
  • opmerkingen ontvangen over je clubhandigheid op Habrahabr (of beter nog, een uitnodiging) 😉

Resultaat: het werkt 😉 Getest op FreeBSD en Ubuntu OS. Theoretisch gezien kan de code onder elk besturingssysteem werken, omdat Er lijken geen specifieke bindingen in de code te zitten.
Voorzichtig! Er komt nog veel meer.

Link naar repository voor amateurs "levend aanraken".

Het proces van installeren, configureren en gebruiken is het resultaat van "het bestuderen van de hardware" veel lager, en dan een beetje theorie over het DHCP-protocol. Voor mezelf. En voor de geschiedenis 😉

Een beetje theorie

Wat is DHCP

Dit is een netwerkprotocol waarmee een apparaat zijn IP-adres (en andere parameters zoals gateway, DNS, enz.) kan achterhalen van een DHCP-server. Pakketten worden uitgewisseld via het UDP-protocol. Het algemene werkingsprincipe van het apparaat bij het opvragen van netwerkparameters is als volgt:

  1. Het apparaat (client) verzendt een UDP-broadcastverzoek (DHCPDISCOVER) door het netwerk met het verzoek "nou, iemand geef mij een IP-adres." Bovendien vindt het verzoek meestal (maar niet altijd) plaats vanaf poort 68 (bron) en is de bestemming poort 67 (bestemming). Sommige apparaten verzenden ook pakketten vanaf poort 67. Het MAC-adres van het clientapparaat is opgenomen in het DHCPDISCOVER-pakket.
  2. Alle DHCP-servers die zich op het netwerk bevinden (en er kunnen er meerdere zijn) vormen een DHCPOFFER-aanbod met netwerkinstellingen voor het apparaat dat DHCPDISCOVER heeft verzonden, en zenden dit ook uit over het netwerk. Identificatie van voor wie dit pakket bedoeld is, is gebaseerd op het MAC-adres van de client dat eerder in het DHCPDISCOVER-verzoek is opgegeven.
  3. De client accepteert pakketten met voorstellen voor netwerkinstellingen, selecteert de meest aantrekkelijke (de criteria kunnen verschillen, bijvoorbeeld het tijdstip van pakketbezorging, het aantal tussenliggende routes) en doet een "officieel verzoek" DHCPREQUEST met de netwerkinstellingen van de DHCP-server die hij leuk vindt. In dit geval gaat het pakket naar een specifieke DHCP-server.
  4. De server die de DHCPREQUEST heeft ontvangen, verzendt een pakket in DHCPACK-formaat, waarin opnieuw de netwerkinstellingen worden vermeld die bedoeld zijn voor deze client

DHCP+Mysql-server in Python

Daarnaast zijn er DHCPINFORM-pakketten die afkomstig zijn van de client en die tot doel hebben de DHCP-server te informeren dat de “client leeft” en de uitgegeven netwerkinstellingen gebruikt. In de implementatie van deze server worden deze pakketten genegeerd.

Pakketformaat

Over het algemeen ziet een Ethernet-pakketframe er ongeveer zo uit:

DHCP+Mysql-server in Python

In ons geval beschouwen we alleen de gegevens rechtstreeks uit de inhoud van het UDP-pakket, zonder OSI-laagprotocolheaders, namelijk de DHCP-structuur:

DHCPONTDEK

Het proces voor het verkrijgen van een IP-adres voor een apparaat begint dus met het verzenden van een broadcastverzoek van poort 68 naar 255.255.255.255:67 door de DHCP-client. In dit pakket bevat de client zijn MAC-adres en wat hij precies wil ontvangen van de DHCP-server. De pakketstructuur wordt beschreven in de onderstaande tabel.

DHCPDISCOVER-pakketstructuurtabel

Positie in het pakket
Waardenaam
Voorbeeld
idee
byte
Verduidelijking

1
Opstartverzoek
1
Hex
1
Berichttype. 1 - verzoek van client naar server, 2 - reactie van server naar client

2
Hardwaretype:
1
Hex
1
Type hardwareadres, in dit protocol 1 - MAC

3
Lengte van hardwareadressen
6
Hex
1
Lengte van het MAC-adres van het apparaat

4
Hop
1
Hex
1
Aantal tussenroutes

5
Transactie ID
23:cf:de:1d
Hex
4
Unieke transactie-ID. Gegenereerd door de client aan het begin van een aanvraagbewerking

7
De tweede is verstreken
0
Hex
4
Tijd in seconden vanaf het begin van het verkrijgen van een adres

9
Bootvlaggen
0
Hex
2
Bepaalde vlaggen die kunnen worden ingesteld om protocolparameters aan te geven

11
IP-adres van de klant
0.0.0.0
rij
4
IP-adres van client (indien aanwezig)

15
Het IP-adres van uw klant
0.0.0.0
rij
4
IP-adres aangeboden door de server (indien beschikbaar)

19
IP-adres van de volgende server
0.0.0.0
rij
4
Server IP-adres (indien bekend)

23
IP-adres van de relay-agent
172.16.114.41
rij
4
IP-adres van de relay-agent (bijvoorbeeld een switch)

27
MAC-adres van client
14:d6:4d:a7:c9:55
Hex
6
MAC-adres van de pakketafzender (client)

31
Hardwareadresopvulling van client
 
Hex
10
Gereserveerde stoel. Meestal gevuld met nullen

41
Hostnaam van de server
 
rij
64
DHCP-servernaam. Meestal niet verzonden

105
Naam van opstartbestand
 
rij
128
Bestandsnaam op de server die door schijfloze stations wordt gebruikt tijdens het opstarten

235
Magisch koekje
63: 82: 53: 63
Hex
4
“Magisch” nummer, volgens welke, incl. u kunt vaststellen dat dit pakket tot het DHCP-protocol behoort

DHCP-opties. Kan in elke volgorde gaan

236
Optienummer
53
december
1
Optie 53, die het DHCP-pakkettype specificeert

1 - DHCPONTDEK
3 - DHCPVERZOEK
2 - DHCPAANBIEDING
5 - DHCPACK
8 - DHCPINFORM

 
Optie lengte
1
december
1

 
Optie waarde
1
december
1

 
Optienummer
50
december
1
Welk IP-adres wil de klant ontvangen?

 
Optie lengte
4
december
1

 
Optie waarde
172.16.134.61
rij
4

 
Optienummer
55
 
1
Netwerkparameters opgevraagd door de klant. Samenstelling kan variëren

01 — Netwerkmasker
03 - Toegangspoort
06 - DNS
oc — Hostnaam
0f - netwerkdomeinnaam
1c - adres van uitzendverzoek (uitzending)
42 - TFTP-servernaam
79 - Klasseloze statische route

 
Optie lengte
8
 
1

 
Optie waarde
01:03:06:0c:0f:1c:42:79
 
8

 
Optienummer
82
december
 
Optie 82, die het MAC-adres van het repeaterapparaat en enkele aanvullende waarden verzendt.

Meestal is dit de poort van de switch waarop de eind-DHCP-client draait. Deze optie bevat aanvullende parameters. De eerste byte is het nummer van de "suboptie", de tweede is de lengte en vervolgens de waarde ervan.

In dit geval zijn in optie 82 de subopties genest:
Agentcircuit-ID = 00:04:00:01:00:04, waarbij de laatste twee bytes de DHCP-clientpoort zijn waar het verzoek vandaan kwam

Agent Remote ID = 00:06:c8:be:19:93:11:48 - MAC-adres van het DHCP-repeaterapparaat

 
Optie lengte
18
december
 

 
Optie waarde
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
Einde pakket
255
december
1
255 symboliseert het einde van het pakket

DHCPAANBIEDING

Zodra de server het DHCPDISCOVER-pakket ontvangt en ziet dat hij de cliënt iets van het gevraagde pakket kan aanbieden, genereert hij er een antwoord voor: DHCPDISCOVER. Het antwoord wordt per uitzending naar de poort gestuurd “waar het vandaan kwam”, omdat op dit moment heeft de client nog geen IP-adres en kan het pakket daarom alleen accepteren als het via broadcast wordt verzonden. De klant herkent dat dit een pakket voor hem is aan zijn MAC-adres in het pakket, evenals aan het transactienummer dat hij genereert op het moment dat het eerste pakket wordt aangemaakt.

DHCPOFFER-pakketstructuurtabel

Positie in het pakket
Naam van waarde (algemeen)
Voorbeeld
idee
byte
Verduidelijking

1
Opstartverzoek
1
Hex
1
Berichttype. 1 - verzoek van client naar server, 2 - reactie van server naar client

2
Hardwaretype:
1
Hex
1
Type hardwareadres, in dit protocol 1 - MAC

3
Lengte van hardwareadressen
6
Hex
1
Lengte van het MAC-adres van het apparaat

4
Hop
1
Hex
1
Aantal tussenroutes

5
Transactie ID
23:cf:de:1d
Hex
4
Unieke transactie-ID. Gegenereerd door de client aan het begin van een aanvraagbewerking

7
De tweede is verstreken
0
Hex
4
Tijd in seconden vanaf het begin van het verkrijgen van een adres

9
Bootvlaggen
0
Hex
2
Bepaalde vlaggen die kunnen worden ingesteld om protocolparameters aan te geven. In dit geval betekent 0 het Unicast-verzoektype

11
IP-adres van de klant
0.0.0.0
rij
4
IP-adres van client (indien aanwezig)

15
Het IP-adres van uw klant
172.16.134.61
rij
4
IP-adres aangeboden door de server (indien beschikbaar)

19
IP-adres van de volgende server
0.0.0.0
rij
4
Server IP-adres (indien bekend)

23
IP-adres van de relay-agent
172.16.114.41
rij
4
IP-adres van de relay-agent (bijvoorbeeld een switch)

27
MAC-adres van client
14:d6:4d:a7:c9:55
Hex
6
MAC-adres van de pakketafzender (client)

31
Hardwareadresopvulling van client
 
Hex
10
Gereserveerde stoel. Meestal gevuld met nullen

41
Hostnaam van de server
 
rij
64
DHCP-servernaam. Meestal niet verzonden

105
Naam van opstartbestand
 
rij
128
Bestandsnaam op de server die door schijfloze stations wordt gebruikt tijdens het opstarten

235
Magisch koekje
63: 82: 53: 63
Hex
4
“Magisch” nummer, volgens welke, incl. u kunt vaststellen dat dit pakket tot het DHCP-protocol behoort

DHCP-opties. Kan in elke volgorde gaan

236
Optienummer
53
december
1
Optie 53, die het DHCP 2-pakkettype definieert: DHCPOFFER

 
Optie lengte
1
december
1

 
Optie waarde
2
december
1

 
Optienummer
1
december
1
Optie om de DHCP-client een netwerkmasker aan te bieden

 
Optie lengte
4
december
1

 
Optie waarde
255.255.224.0
rij
4

 
Optienummer
3
december
1
Optie om de DHCP-client een standaardgateway aan te bieden

 
Optie lengte
4
december
1

 
Optie waarde
172.16.12.1
rij
4

 
Optienummer
6
december
1
Optie om DHCP aan te bieden aan DNS-client

 
Optie lengte
4
december
1

 
Optie waarde
8.8.8.8
rij
4

 
Optienummer
51
december
1
De levensduur van de uitgegeven netwerkparameters in seconden, waarna de DHCP-client deze opnieuw moet opvragen

 
Optie lengte
4
december
1

 
Optie waarde
86400
december
4

 
Optienummer
82
december
1
Optie 82 herhaalt wat er in DHCPDISCOVER stond

 
Optie lengte
18
december
1

 
Optie waarde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
december
18

 
Einde pakket
255
december
1
255 symboliseert het einde van het pakket

DHCPVERZOEK

Nadat de cliënt DHCPOFFER heeft ontvangen, vormt hij een pakket waarin hij netwerkparameters opvraagt, niet aan alle DHCP-servers op het netwerk, maar alleen aan één specifieke server, wiens DHCPOFFER-aanbod hij het meest “leuk” vond. De "like"-criteria kunnen verschillen en zijn afhankelijk van de DHCP-implementatie van de client. De ontvanger van het verzoek wordt opgegeven met behulp van het MAC-adres van de DHCP-server. Ook kan een DHCPREQUEST-pakket door de client worden verzonden zonder eerst DHCPDISCOVER te genereren, als het IP-adres van de server al eerder is verkregen.

DHCPREQUEST-pakketstructuurtabel

Positie in het pakket
Naam van waarde (algemeen)
Voorbeeld
idee
byte
Verduidelijking

1
Opstartverzoek
1
Hex
1
Berichttype. 1 - verzoek van client naar server, 2 - reactie van server naar client

2
Hardwaretype:
1
Hex
1
Type hardwareadres, in dit protocol 1 - MAC

3
Lengte van hardwareadressen
6
Hex
1
Lengte van het MAC-adres van het apparaat

4
Hop
1
Hex
1
Aantal tussenroutes

5
Transactie ID
23:cf:de:1d
Hex
4
Unieke transactie-ID. Gegenereerd door de client aan het begin van een aanvraagbewerking

7
De tweede is verstreken
0
Hex
4
Tijd in seconden vanaf het begin van het verkrijgen van een adres

9
Bootvlaggen
8000
Hex
2
Bepaalde vlaggen die kunnen worden ingesteld om protocolparameters aan te geven. In dit geval is “broadcast” ingesteld

11
IP-adres van de klant
0.0.0.0
rij
4
IP-adres van client (indien aanwezig)

15
Het IP-adres van uw klant
172.16.134.61
rij
4
IP-adres aangeboden door de server (indien beschikbaar)

19
IP-adres van de volgende server
0.0.0.0
rij
4
Server IP-adres (indien bekend)

23
IP-adres van de relay-agent
172.16.114.41
rij
4
IP-adres van de relay-agent (bijvoorbeeld een switch)

27
MAC-adres van client
14:d6:4d:a7:c9:55
Hex
6
MAC-adres van de pakketafzender (client)

31
Hardwareadresopvulling van client
 
Hex
10
Gereserveerde stoel. Meestal gevuld met nullen

41
Hostnaam van de server
 
rij
64
DHCP-servernaam. Meestal niet verzonden

105
Naam van opstartbestand
 
rij
128
Bestandsnaam op de server die door schijfloze stations wordt gebruikt tijdens het opstarten

235
Magisch koekje
63: 82: 53: 63
Hex
4
“Magisch” nummer, volgens welke, incl. u kunt vaststellen dat dit pakket tot het DHCP-protocol behoort

DHCP-opties. Kan in elke volgorde gaan

236
Optienummer
53
december
3
Optie 53, die het DHCP-pakkettype 3 definieert: DHCPREQUEST

 
Optie lengte
1
december
1

 
Optie waarde
3
december
1

 
Optienummer
61
december
1
Client-ID: 01 (voor Ehernet) + MAC-adres van de client

 
Optie lengte
7
december
1

 
Optie waarde
01:2c:ab:25:ff:72:a6
Hex
7

 
Optienummer
60
december
 
"Identificatiecode leverancierklasse". In mijn geval rapporteert het de DHCP-clientversie. Misschien retourneren andere apparaten iets anders. Windows rapporteert bijvoorbeeld MSFT 5.0

 
Optie lengte
11
december
 

 
Optie waarde
udhcp 0.9.8
rij
 

 
Optienummer
55
 
1
Netwerkparameters opgevraagd door de klant. Samenstelling kan variëren

01 — Netwerkmasker
03 - Toegangspoort
06 - DNS
oc — Hostnaam
0f - netwerkdomeinnaam
1c - adres van uitzendverzoek (uitzending)
42 - TFTP-servernaam
79 - Klasseloze statische route

 
Optie lengte
8
 
1

 
Optie waarde
01:03:06:0c:0f:1c:42:79
 
8

 
Optienummer
82
december
1
Optie 82 herhaalt wat er in DHCPDISCOVER stond

 
Optie lengte
18
december
1

 
Optie waarde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
december
18

 
Einde pakket
255
december
1
255 symboliseert het einde van het pakket

DHCPACK

Als bevestiging dat “ja, dat klopt, dit is uw IP-adres, en ik zal het aan niemand anders geven” van de DHCP-server, wordt een pakket in DHCPACK-formaat van de server naar de client verzonden. Het wordt net als andere pakketten uitgezonden. Hoewel ik in de onderstaande code voor een DHCP-server geïmplementeerd in Python, voor het geval dat, elk uitzendingsverzoek dupliceer door een pakket naar een specifiek client-IP te sturen, als dit al bekend is. Bovendien maakt het de DHCP-server helemaal niet uit of het DHCPACK-pakket de client heeft bereikt. Als de client geen DHCPACK ontvangt, herhaalt hij na een tijdje eenvoudigweg DHCPREQUEST

DHCPACK-pakketstructuurtabel

Positie in het pakket
Naam van waarde (algemeen)
Voorbeeld
idee
byte
Verduidelijking

1
Opstartverzoek
2
Hex
1
Berichttype. 1 - verzoek van client naar server, 2 - reactie van server naar client

2
Hardwaretype:
1
Hex
1
Type hardwareadres, in dit protocol 1 - MAC

3
Lengte van hardwareadressen
6
Hex
1
Lengte van het MAC-adres van het apparaat

4
Hop
1
Hex
1
Aantal tussenroutes

5
Transactie ID
23:cf:de:1d
Hex
4
Unieke transactie-ID. Gegenereerd door de client aan het begin van een aanvraagbewerking

7
De tweede is verstreken
0
Hex
4
Tijd in seconden vanaf het begin van het verkrijgen van een adres

9
Bootvlaggen
8000
Hex
2
Bepaalde vlaggen die kunnen worden ingesteld om protocolparameters aan te geven. In dit geval is “broadcast” ingesteld

11
IP-adres van de klant
0.0.0.0
rij
4
IP-adres van client (indien aanwezig)

15
Het IP-adres van uw klant
172.16.134.61
rij
4
IP-adres aangeboden door de server (indien beschikbaar)

19
IP-adres van de volgende server
0.0.0.0
rij
4
Server IP-adres (indien bekend)

23
IP-adres van de relay-agent
172.16.114.41
rij
4
IP-adres van de relay-agent (bijvoorbeeld een switch)

27
MAC-adres van client
14:d6:4d:a7:c9:55
Hex
6
MAC-adres van de pakketafzender (client)

31
Hardwareadresopvulling van client
 
Hex
10
Gereserveerde stoel. Meestal gevuld met nullen

41
Hostnaam van de server
 
rij
64
DHCP-servernaam. Meestal niet verzonden

105
Naam van opstartbestand
 
rij
128
Bestandsnaam op de server die door schijfloze stations wordt gebruikt tijdens het opstarten

235
Magisch koekje
63: 82: 53: 63
Hex
4
“Magisch” nummer, volgens welke, incl. u kunt vaststellen dat dit pakket tot het DHCP-protocol behoort

DHCP-opties. Kan in elke volgorde gaan

236
Optienummer
53
december
3
Optie 53, die het DHCP-pakkettype 5 definieert: DHCPACK

 
Optie lengte
1
december
1

 
Optie waarde
5
december
1

 
Optienummer
1
december
1
Optie om de DHCP-client een netwerkmasker aan te bieden

 
Optie lengte
4
december
1

 
Optie waarde
255.255.224.0
rij
4

 
Optienummer
3
december
1
Optie om de DHCP-client een standaardgateway aan te bieden

 
Optie lengte
4
december
1

 
Optie waarde
172.16.12.1
rij
4

 
Optienummer
6
december
1
Optie om DHCP aan te bieden aan DNS-client

 
Optie lengte
4
december
1

 
Optie waarde
8.8.8.8
rij
4

 
Optienummer
51
december
1
De levensduur van de uitgegeven netwerkparameters in seconden, waarna de DHCP-client deze opnieuw moet opvragen

 
Optie lengte
4
december
1

 
Optie waarde
86400
december
4

 
Optienummer
82
december
1
Optie 82 herhaalt wat er in DHCPDISCOVER stond

 
Optie lengte
18
december
1

 
Optie waarde
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
december
18

 
Einde pakket
255
december
1
255 symboliseert het einde van het pakket

installatie

De installatie bestaat feitelijk uit het installeren van de pythonmodules die nodig zijn voor het werk. Er wordt aangenomen dat MySQL al is geïnstalleerd en geconfigureerd.

FreeBSD

pkg installeer python3 python3 -m surepip pip3 installeer mysql-connector

Ubuntu

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

We maken een MySQL-database, uploaden de pydhcp.sql-dump erin en configureren het configuratiebestand.

Configuratie

Alle serverinstellingen staan ​​in een xml-bestand. Referentiebestand:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 lokalehost test test pydhcp optie_8.8.8.8_hex:sw_port82:1:20 optie_22_hex:sw_port82:2:16 optie_18_hex:sw_mac:82:26 40 selecteer ip,mask,router,dns van gebruikers waarbij upper(mac)=upper('{option_3_AgentRemoteId_hex}') en upper(port)=upper('{option_1_AgentCircuitId_port_hex}') selecteer ip,mask,router,dns van gebruikers waarbij upper(mac)=upper('{sw_mac}') en upper(port)=upper('{sw_port82}') selecteer ip,mask,router,dns van gebruikers waarbij upper(mac)=upper('{ClientMacAddress}') waarden invoegen in de geschiedenis (id,dt,mac,ip,comment) (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Nu meer in detail over de tags:

In het gedeelte DHCPserver worden de basisinstellingen voor het opstarten van de server beschreven, namelijk:

  • host - naar welk IP-adres de server luistert op poort 67
  • broadcast - welk ip-adres is de uitzending voor DHCPOFFER en DHCPACK
  • DHCPServer - wat is het IP-adres van de DHCP-server
  • LeaseTime-leasetijd van het uitgegeven IP-adres
  • ThreadLimit - hoeveel threads er tegelijkertijd actief zijn om inkomende UDP-pakketten op poort 67 te verwerken. Het zou moeten helpen bij projecten met een hoge belasting 😉
  • defaultMask,defaultRouter,defaultDNS - wat standaard aan de abonnee wordt aangeboden als er een IP-adres in de database wordt gevonden, maar er geen aanvullende parameters voor zijn opgegeven

mysql-sectie:

host, gebruikersnaam, wachtwoord, basisnaam - alles spreekt voor zich. Er wordt een geschatte databasestructuur gepost GitHub

Querysectie: verzoeken voor het ontvangen van OFFER/ACK worden hier beschreven:

  • offer_count — het aantal regels met verzoeken die een resultaat retourneren zoals ip,mask,router,dns
  • offer_n — querytekenreeks. Als retour leeg is, wordt het volgende offerteverzoek uitgevoerd
  • history_sql - een query die bijvoorbeeld naar de "autorisatiegeschiedenis" voor een abonnee schrijft

Verzoeken kunnen alle variabelen uit het optiegedeelte of opties uit het DHCP-protocol bevatten.

Opties sectie. Dit is waar het interessanter wordt. Hier kunnen we variabelen maken die we later in de querysectie kunnen gebruiken.

Bijvoorbeeld:

option_82_hex:sw_port1:20:22

, neemt deze opdrachtregel de volledige regel uit het DHCP-verzoek voor optie 82, in hex-formaat, in het bereik van bytes 20 tot en met 22, en plaatst deze in de nieuwe variabele sw_port1 (schakel de poort waar het verzoek vandaan kwam)

option_82_hex:sw_mac:26:40

, definieer de variabele sw_mac en neem de hex uit het bereik 26:40

U kunt alle mogelijke opties zien die in queries kunnen worden gebruikt door de server te starten met de schakeloptie -d. We zullen zoiets als dit logboek zien:

--een DHCPINFORM-pakket is aangekomen op poort 67, van 0025224ad764 , b'x91xa5xe0xa3xa5xa9-x8fx8a' , ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764', 'ClientMacAddressByte': b'x00 7%"Jx d91d' , ' HType': 'Ethernet', 'HostName': b'x5xa0xe3xa5xa9xa8-x8fx43a', 'ReqListDNS': True, 'ReqListDomainName': True, 'ReqListPerfowmRouterDiscover': True, 'ReqListRouter': True, 'ReqListStaticRoute': True, 'ReqListSubnetM ask': True, 'ReqListVendorSpecInfo': 0.0.0.0, 'RequestedIpAddress': '5.0', 'Vendor': b'MSFT 0025224', 'chaddr': '764ad172.30.128.13', 'ciaddr': '00' , 'flags': b'x00x172.30.114.25', 'giaddr': '308', 'gpoz': 6, 'hlen': 1, 'hops': 82, 'htype': 'MAC', 'magic_cookie': b'cx12Sc ', 'op': 'DHCPINFORM', 'option12': 53, 'option53': 55, 'option55': 60, 'option60': 61, 'option61': 82, 'option82': 82, ' optie_12_byte': b'x01x06x00x04x00x01x00x06x02x08x00x06' b'x00x1x9eXx2exb82xad', 'option_12010600040001000602080006001_hex': '589e2eb82ad', 'optie_ 18_len': 82 12, 'option_01_str': "b'x06x00x04x00x01x00x06x02x08x00x06x00x1x9x2eXx768exb0.0.0.0xad'", 'resultaat': False, 'secs': 001, 'siaddr': '589', 'sw_mac': '2e1eb06ad', 'sw_port89': '8', 'xidbyte': b'

Dienovereenkomstig kunnen we elke variabele in {} plaatsen en deze zal in de SQL-query worden gebruikt.

Laten we voor de geschiedenis vastleggen dat de client het IP-adres heeft ontvangen:

DHCP+Mysql-server in Python

DHCP+Mysql-server in Python

Serverstart

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

— d console-uitvoermodus DEBUG
- c <bestandsnaam> configuratiebestand

Nabespreking

En nu meer details over het implementeren van de server in Python. Het is pijn. Python werd in een mum van tijd geleerd. Veel momenten worden gemaakt in de stijl van ‘wauw, op de een of andere manier heb ik het voor elkaar gekregen.’ Helemaal niet geoptimaliseerd, en in deze vorm gelaten, voornamelijk vanwege weinig ervaring met Python-ontwikkeling. Ik zal in “code” stilstaan ​​bij de meest interessante aspecten van de serverimplementatie.

Parser voor XML-configuratiebestanden

Er wordt gebruik gemaakt van de standaard Python-module xml.dom. Het lijkt eenvoudig, maar tijdens de implementatie was er een merkbaar gebrek aan duidelijke documentatie en voorbeelden op het netwerk dat deze module gebruikte.

    tree = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") voor elem in mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("gebruikersnaam")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("wachtwoord")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basisnaam")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") voor 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") voor elem in qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data voor 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") voor elem in opties: node=elem.getElementsByTagName("option") voor opties in knooppunt : optiesMod.append(opties.firstChild.data)

Multithreading

Vreemd genoeg is multithreading in Python heel duidelijk en eenvoudig geïmplementeerd.

def PacketWork(data,addr): ... # implementatie van het parseren van het binnenkomende pakket en het reageren erop ... while True: data, addr = udp_socket.recvfrom(1024) # wachten op het UDP-pakket thread = threading.Thread( target=PacketWork , args=(data,addr,)).start() # zoals het kwam - we starten de eerder gedefinieerde PacketWork-functie op de achtergrond met parameters terwijl threading.active_count() >gconfig["dhcp_ThreadLimit"]: tijd. sleep(1) # if the number Er zijn al meer threads actief dan in de instellingen, we wachten tot er minder zijn

DHCP-pakket ontvangen/verzenden

Om UDP-pakketten die via de netwerkkaart binnenkomen te onderscheppen, moet u de socket “verhogen”:

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

, waar de vlaggen zijn:

  • AF_INET - betekent dat het adresformaat IP: poort is. Er kan ook AF_UNIX zijn - waarbij het adres wordt gegeven door de bestandsnaam.
  • SOCK_DGRAM - betekent dat we geen "onbewerkt pakket" accepteren, maar een pakket dat al door de firewall is gegaan, en met een gedeeltelijk bijgesneden pakket. Die. we ontvangen alleen een UDP-pakket zonder de “fysieke” component van de UDP-pakketverpakking. Als u de vlag SOCK_RAW gebruikt, moet u ook deze “wrapper” parseren.

Het verzenden van een pakket kan op een uitzending lijken:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #schakel de socket naar de uitzendmodus rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, en naar het adres “waar het pakket vandaan kwam”:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # schakel de socket naar de multi-listener-modus rz=udp_socket.sendto(packetack, addr)

, waarbij SOL_SOCKET het “protocolniveau” betekent voor het instellen van opties,

, SO_BROADCAST optie dat het helmpakket wordt "uitgezonden"

  De optie SO_REUSEADDR schakelt de socket naar de modus "veel luisteraars". In theorie is het in dit geval niet nodig, maar op een van de FreeBSD-servers waarop ik heb getest, werkte de code niet zonder deze optie.

Een DHCP-pakket parseren

Dit is waar ik Python erg leuk vond. Het blijkt dat je hiermee out-of-the-box behoorlijk flexibel kunt zijn met de bytecode. Hierdoor kan het heel gemakkelijk worden vertaald in decimale waarden, strings en hex - d.w.z. dit is wat we eigenlijk nodig hebben om de structuur van het pakket te begrijpen. U kunt dus bijvoorbeeld een reeks bytes in HEX krijgen en alleen maar bytes:

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

, pak de bytes in een structuur:

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

Haal IP uit de structuur:

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

En vice versa:

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

Dat is alles voor nu 😉

Bron: www.habr.com

Voeg een reactie