Serwer DHCP+Mysql w Pythonie

Serwer DHCP+Mysql w Pythonie

Celem tego projektu było:

  • Poznanie protokołu DHCP w sieci IPv4
  • Nauka Pythona (trochę więcej niż od zera 😉)
  • wymiana serwera DB2DHCP (mój widelec), oryginał tutaj, który staje się coraz trudniejszy w montażu dla nowego systemu operacyjnego. I nie podoba mi się, że to binarność, której nie da się „w tej chwili zmienić”
  • uzyskanie działającego serwera DHCP z możliwością wyboru adresu IP abonenta za pomocą kombinacji mac abonenta lub przełącznik mac+port (Opcja 82)
  • pisanie kolejnego roweru (Och! to moje ulubione zajęcie)
  • otrzymywanie komentarzy na temat Twojej maczugi na Habrahabr (lub jeszcze lepiej zaproszenie) 😉

Wynik: działa 😉 Przetestowano na FreeBSD i Ubuntu OS. Teoretycznie kod można poprosić o działanie pod dowolnym systemem operacyjnym, ponieważ Wydaje się, że w kodzie nie ma konkretnych powiązań.
Ostrożnie! Jeszcze wiele przed nami.

Link do repozytorium dla amatorów „dotknąć żywego”.

Proces instalacji, konfiguracji i wykorzystania wyniku „badania sprzętu” jest znacznie niższy, a potem trochę teorii na temat protokołu DHCP. Dla siebie. I dla historii 😉

Trochę teorii

Co to jest DHCP

Jest to protokół sieciowy, który umożliwia urządzeniu znalezienie adresu IP (i innych parametrów, takich jak brama, DNS itp.) z serwera DHCP. Wymiana pakietów odbywa się przy użyciu protokołu UDP. Ogólna zasada działania urządzenia przy żądaniu parametrów sieciowych jest następująca:

  1. Urządzenie (klient) wysyła w całej sieci żądanie rozgłoszeniowe UDP (DHCPDISCOVER) z żądaniem „no cóż, ktoś podał mi adres IP”. Co więcej, zazwyczaj (choć nie zawsze) żądanie następuje z portu 68 (źródłowego), a miejscem docelowym jest port 67 (docelowy). Niektóre urządzenia wysyłają również pakiety z portu 67. Adres MAC urządzenia klienckiego znajduje się w pakiecie DHCPDISCOVER.
  2. Wszystkie serwery DHCP znajdujące się w sieci (a może być ich kilka) tworzą ofertę DHCPOFFER z ustawieniami sieciowymi dla urządzenia, które wysłało DHCPDISCOVER, a także rozgłaszają je w sieci. Identyfikacja dla kogo przeznaczony jest ten pakiet odbywa się na podstawie adresu MAC klienta podanego wcześniej w żądaniu DHCPDISCOVER.
  3. Klient przyjmuje pakiety z propozycjami ustawień sieciowych, wybiera najatrakcyjniejszy (kryteria mogą być różne, np. czas dostarczenia pakietu, liczba tras pośrednich) i składa „oficjalne żądanie” DHCPREQUEST z ustawieniami sieciowymi z serwera DHCP, który lubi. W takim przypadku pakiet trafia do określonego serwera DHCP.
  4. Serwer, który otrzymał DHCPREQUEST, wysyła pakiet w formacie DHCPACK, w którym ponownie zawiera listę ustawień sieciowych przeznaczonych dla tego klienta

Serwer DHCP+Mysql w Pythonie

Dodatkowo od klienta przychodzą pakiety DHCPINFORM, których celem jest poinformowanie serwera DHCP, że „klient żyje” i korzysta z wydanych ustawień sieciowych. W implementacji tego serwera pakiety te są ignorowane.

Format pakietu

Ogólnie ramka pakietu Ethernet wygląda mniej więcej tak:

Serwer DHCP+Mysql w Pythonie

W naszym przypadku pod uwagę weźmiemy tylko dane bezpośrednio z zawartości pakietu UDP, bez nagłówków protokołu warstwy OSI, czyli strukturę DHCP:

ODKRYJ DHCP

Zatem proces uzyskiwania adresu IP dla urządzenia rozpoczyna się od wysłania przez klienta DHCP żądania rozgłoszeniowego z portu 68 na adres 255.255.255.255:67. W tym pakiecie klient zawiera swój adres MAC, a także to, co dokładnie chce otrzymać z serwera DHCP. Strukturę pakietu opisano w poniższej tabeli.

Tabela struktury pakietów DHCPDISCOVER

Pozycja w pakiecie
Nazwa wartości
Przykład
Wprowadzenie
Bajt
Wyjaśnienie

1
Żądanie rozruchu
1
Hex
1
Typ wiadomości. 1 - żądanie od klienta do serwera, 2 - odpowiedź od serwera do klienta

2
Typ sprzętu
1
Hex
1
Typ adresu sprzętowego, w tym protokole 1 - MAC

3
Długość adresów sprzętowych
6
Hex
1
Długość adresu MAC urządzenia

4
Chmiel
1
Hex
1
Liczba tras pośrednich

5
ID transakcji
23:por.:de:1d
Hex
4
Unikalny identyfikator transakcji. Generowane przez klienta na początku operacji żądania

7
Drugi upłynął
0
Hex
4
Czas w sekundach od rozpoczęcia procesu uzyskiwania adresu

9
Flagi rozruchowe
0
Hex
2
Pewne flagi, które można ustawić w celu wskazania parametrów protokołu

11
Adres IP klienta
0.0.0.0
Linia
4
Adres IP klienta (jeśli istnieje)

15
Adres IP Twojego klienta
0.0.0.0
Linia
4
Adres IP oferowany przez serwer (jeśli jest dostępny)

19
Adres IP następnego serwera
0.0.0.0
Linia
4
Adres IP serwera (jeśli jest znany)

23
Adres IP agenta przekazującego
172.16.114.41
Linia
4
Adres IP agenta przekazującego (na przykład przełącznika)

27
Adres MAC klienta
14:d6:4d:a7:c9:55
Hex
6
Adres MAC nadawcy pakietu (klienta)

31
Dopełnienie adresu sprzętowego klienta
 
Hex
10
Zarezerwowane miejsce. Zwykle wypełnione zerami

41
Nazwa hosta serwera
 
Linia
64
Nazwa serwera DHCP. Zwykle nie jest transmitowany

105
Nazwa pliku rozruchowego
 
Linia
128
Nazwa pliku na serwerze używana przez stacje bezdyskowe podczas uruchamiania

235
Magiczne ciastko
63: 82: 53: 63
Hex
4
Numer „Magiczny”, według którego m.in. możesz ustalić, że ten pakiet należy do protokołu DHCP

Opcje DHCP. Można iść w dowolnej kolejności

236
Numer opcji
53
grudzień
1
Opcja 53, która określa typ pakietu DHCP

1 - DHCPODKRYJ
3 - ŻĄDANIE DHCP
2 - OFERTA DHCP
5 - DHCPACK
8 - INFORMACJA DHCP

 
Długość opcji
1
grudzień
1

 
Wartość opcji
1
grudzień
1

 
Numer opcji
50
grudzień
1
Jaki adres IP chce otrzymać klient?

 
Długość opcji
4
grudzień
1

 
Wartość opcji
172.16.134.61
Linia
4

 
Numer opcji
55
 
1
Parametry sieci wymagane przez klienta. Skład może się różnić

01 — Maska sieci
03 - Brama
06 - DNS
oc — nazwa hosta
0f - nazwa domeny sieciowej
1c - adres żądania transmisji (transmisji)
42 - nazwa serwera TFTP
79 - Bezklasowa trasa statyczna

 
Długość opcji
8
 
1

 
Wartość opcji
01:03:06:0c:0f:1c:42:79
 
8

 
Numer opcji
82
grudzień
 
Opcja 82, która przesyła adres MAC urządzenia wzmacniającego i kilka dodatkowych wartości.

Najczęściej jest to port przełącznika, na którym działa końcowy klient DHCP. Opcja ta zawiera dodatkowe parametry. Pierwszy bajt to numer „podopcji”, drugi to jej długość, następnie jej wartość.

W tym przypadku w opcji 82 podopcje są zagnieżdżone:
Identyfikator obwodu agenta = 00:04:00:01:00:04, gdzie dwa ostatnie bajty to port klienta DHCP, z którego nadeszło żądanie

Agent Remote ID = 00:06:c8:be:19:93:11:48 - adres MAC urządzenia wzmacniającego DHCP

 
Długość opcji
18
grudzień
 

 
Wartość opcji
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
Koniec pakietu
255
grudzień
1
Liczba 255 symbolizuje koniec pakietu

OFERTA DHCP

Gdy tylko serwer odbierze pakiet DHCPDISCOVER i zobaczy, że może zaoferować klientowi coś z żądanego, generuje dla niego odpowiedź - DHCPDISCOVER. Odpowiedź jest wysyłana do portu „skąd przyszła”, poprzez transmisję, ponieważ w tym momencie klient nie posiada jeszcze adresu IP, dlatego może przyjąć pakiet tylko wtedy, gdy zostanie wysłany w drodze rozgłoszenia. Klient rozpoznaje, że jest to paczka dla niego, po swoim adresie MAC znajdującym się wewnątrz paczki, a także numerze transakcji, który generuje w momencie tworzenia pierwszej paczki.

Tabela struktury pakietów DHCPOFFER

Pozycja w pakiecie
Nazwa wartości (wspólna)
Przykład
Wprowadzenie
Bajt
Wyjaśnienie

1
Żądanie rozruchu
1
Hex
1
Typ wiadomości. 1 - żądanie od klienta do serwera, 2 - odpowiedź od serwera do klienta

2
Typ sprzętu
1
Hex
1
Typ adresu sprzętowego, w tym protokole 1 - MAC

3
Długość adresów sprzętowych
6
Hex
1
Długość adresu MAC urządzenia

4
Chmiel
1
Hex
1
Liczba tras pośrednich

5
ID transakcji
23:por.:de:1d
Hex
4
Unikalny identyfikator transakcji. Generowane przez klienta na początku operacji żądania

7
Drugi upłynął
0
Hex
4
Czas w sekundach od rozpoczęcia procesu uzyskiwania adresu

9
Flagi rozruchowe
0
Hex
2
Pewne flagi, które można ustawić w celu wskazania parametrów protokołu. W tym przypadku 0 oznacza typ żądania Unicast

11
Adres IP klienta
0.0.0.0
Linia
4
Adres IP klienta (jeśli istnieje)

15
Adres IP Twojego klienta
172.16.134.61
Linia
4
Adres IP oferowany przez serwer (jeśli jest dostępny)

19
Adres IP następnego serwera
0.0.0.0
Linia
4
Adres IP serwera (jeśli jest znany)

23
Adres IP agenta przekazującego
172.16.114.41
Linia
4
Adres IP agenta przekazującego (na przykład przełącznika)

27
Adres MAC klienta
14:d6:4d:a7:c9:55
Hex
6
Adres MAC nadawcy pakietu (klienta)

31
Dopełnienie adresu sprzętowego klienta
 
Hex
10
Zarezerwowane miejsce. Zwykle wypełnione zerami

41
Nazwa hosta serwera
 
Linia
64
Nazwa serwera DHCP. Zwykle nie jest transmitowany

105
Nazwa pliku rozruchowego
 
Linia
128
Nazwa pliku na serwerze używana przez stacje bezdyskowe podczas uruchamiania

235
Magiczne ciastko
63: 82: 53: 63
Hex
4
Numer „Magiczny”, według którego m.in. możesz ustalić, że ten pakiet należy do protokołu DHCP

Opcje DHCP. Można iść w dowolnej kolejności

236
Numer opcji
53
grudzień
1
Opcja 53, która określa typ pakietu DHCP 2 - DHCPOFFER

 
Długość opcji
1
grudzień
1

 
Wartość opcji
2
grudzień
1

 
Numer opcji
1
grudzień
1
Opcja zaoferowania klientowi DHCP maski sieci

 
Długość opcji
4
grudzień
1

 
Wartość opcji
255.255.224.0
Linia
4

 
Numer opcji
3
grudzień
1
Opcja zaoferowania klientowi DHCP bramy domyślnej

 
Długość opcji
4
grudzień
1

 
Wartość opcji
172.16.12.1
Linia
4

 
Numer opcji
6
grudzień
1
Opcja oferowania DHCP klientowi DNS

 
Długość opcji
4
grudzień
1

 
Wartość opcji
8.8.8.8
Linia
4

 
Numer opcji
51
grudzień
1
Czas życia wydanych parametrów sieciowych w sekundach, po którym klient DHCP musi zażądać ich ponownie

 
Długość opcji
4
grudzień
1

 
Wartość opcji
86400
grudzień
4

 
Numer opcji
82
grudzień
1
Opcja 82 powtarza to, co pojawiło się w DHCPDISCOVER

 
Długość opcji
18
grudzień
1

 
Wartość opcji
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ek
grudzień
18

 
Koniec pakietu
255
grudzień
1
Liczba 255 symbolizuje koniec pakietu

ŻĄDANIE DHCP

Po otrzymaniu DHCPOFFER klient tworzy pakiet z żądaniem parametrów sieciowych nie do wszystkich serwerów DHCP w sieci, a tylko do jednego, konkretnego, którego oferta DHCPOFFER „podobała mu się najbardziej”. Kryteria „polubienia” mogą być różne i zależeć od implementacji DHCP klienta. Odbiorca żądania jest określany przy użyciu adresu MAC serwera DHCP. Klient może także wysłać pakiet DHCPREQUEST bez uprzedniego generowania protokołu DHCPDISCOVER, jeśli adres IP serwera został już uzyskany wcześniej.

Tabela struktury pakietów DHCPREQUEST

Pozycja w pakiecie
Nazwa wartości (wspólna)
Przykład
Wprowadzenie
Bajt
Wyjaśnienie

1
Żądanie rozruchu
1
Hex
1
Typ wiadomości. 1 - żądanie od klienta do serwera, 2 - odpowiedź od serwera do klienta

2
Typ sprzętu
1
Hex
1
Typ adresu sprzętowego, w tym protokole 1 - MAC

3
Długość adresów sprzętowych
6
Hex
1
Długość adresu MAC urządzenia

4
Chmiel
1
Hex
1
Liczba tras pośrednich

5
ID transakcji
23:por.:de:1d
Hex
4
Unikalny identyfikator transakcji. Generowane przez klienta na początku operacji żądania

7
Drugi upłynął
0
Hex
4
Czas w sekundach od rozpoczęcia procesu uzyskiwania adresu

9
Flagi rozruchowe
8000
Hex
2
Pewne flagi, które można ustawić w celu wskazania parametrów protokołu. W tym przypadku ustawiona jest opcja „transmisja”.

11
Adres IP klienta
0.0.0.0
Linia
4
Adres IP klienta (jeśli istnieje)

15
Adres IP Twojego klienta
172.16.134.61
Linia
4
Adres IP oferowany przez serwer (jeśli jest dostępny)

19
Adres IP następnego serwera
0.0.0.0
Linia
4
Adres IP serwera (jeśli jest znany)

23
Adres IP agenta przekazującego
172.16.114.41
Linia
4
Adres IP agenta przekazującego (na przykład przełącznika)

27
Adres MAC klienta
14:d6:4d:a7:c9:55
Hex
6
Adres MAC nadawcy pakietu (klienta)

31
Dopełnienie adresu sprzętowego klienta
 
Hex
10
Zarezerwowane miejsce. Zwykle wypełnione zerami

41
Nazwa hosta serwera
 
Linia
64
Nazwa serwera DHCP. Zwykle nie jest transmitowany

105
Nazwa pliku rozruchowego
 
Linia
128
Nazwa pliku na serwerze używana przez stacje bezdyskowe podczas uruchamiania

235
Magiczne ciastko
63: 82: 53: 63
Hex
4
Numer „Magiczny”, według którego m.in. możesz ustalić, że ten pakiet należy do protokołu DHCP

Opcje DHCP. Można iść w dowolnej kolejności

236
Numer opcji
53
grudzień
3
Opcja 53, która definiuje typ pakietu DHCP 3 - DHCPREQUEST

 
Długość opcji
1
grudzień
1

 
Wartość opcji
3
grudzień
1

 
Numer opcji
61
grudzień
1
Identyfikator klienta: 01 (dla Ehernet) + adres MAC klienta

 
Długość opcji
7
grudzień
1

 
Wartość opcji
01:2c:ab:25:ff:72:a6
Hex
7

 
Numer opcji
60
grudzień
 
„Identyfikator klasy dostawcy”. W moim przypadku zgłasza wersję klienta DHCP. Być może inne urządzenia zwracają coś innego. Na przykład system Windows zgłasza MSFT 5.0

 
Długość opcji
11
grudzień
 

 
Wartość opcji
udhcp 0.9.8
Linia
 

 
Numer opcji
55
 
1
Parametry sieci wymagane przez klienta. Skład może się różnić

01 — Maska sieci
03 - Brama
06 - DNS
oc — nazwa hosta
0f - nazwa domeny sieciowej
1c - adres żądania transmisji (transmisji)
42 - nazwa serwera TFTP
79 - Bezklasowa trasa statyczna

 
Długość opcji
8
 
1

 
Wartość opcji
01:03:06:0c:0f:1c:42:79
 
8

 
Numer opcji
82
grudzień
1
Opcja 82 powtarza to, co pojawiło się w DHCPDISCOVER

 
Długość opcji
18
grudzień
1

 
Wartość opcji
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ek
grudzień
18

 
Koniec pakietu
255
grudzień
1
Liczba 255 symbolizuje koniec pakietu

DHCPACK

Jako potwierdzenie, że „tak, zgadza się, to jest Twój adres IP i nikomu innemu go nie oddam” z serwera DHCP, służy pakiet w formacie DHCPACK z serwera do klienta. Jest wysyłany rozgłoszeniowo, tak jak inne pakiety. Chociaż w poniższym kodzie dla serwera DHCP zaimplementowanego w Pythonie, na wszelki wypadek, duplikuję każde żądanie rozgłoszeniowe, wysyłając pakiet na konkretny adres IP klienta, jeśli jest on już znany. Co więcej, serwer DHCP w ogóle nie przejmuje się tym, czy pakiet DHCPACK dotarł do klienta. Jeśli klient nie otrzyma DHCPACK, to po chwili po prostu powtarza DHCPREQUEST

Tabela struktury pakietów DHCPACK

Pozycja w pakiecie
Nazwa wartości (wspólna)
Przykład
Wprowadzenie
Bajt
Wyjaśnienie

1
Żądanie rozruchu
2
Hex
1
Typ wiadomości. 1 - żądanie od klienta do serwera, 2 - odpowiedź od serwera do klienta

2
Typ sprzętu
1
Hex
1
Typ adresu sprzętowego, w tym protokole 1 - MAC

3
Długość adresów sprzętowych
6
Hex
1
Długość adresu MAC urządzenia

4
Chmiel
1
Hex
1
Liczba tras pośrednich

5
ID transakcji
23:por.:de:1d
Hex
4
Unikalny identyfikator transakcji. Generowane przez klienta na początku operacji żądania

7
Drugi upłynął
0
Hex
4
Czas w sekundach od rozpoczęcia procesu uzyskiwania adresu

9
Flagi rozruchowe
8000
Hex
2
Pewne flagi, które można ustawić w celu wskazania parametrów protokołu. W tym przypadku ustawiona jest opcja „transmisja”.

11
Adres IP klienta
0.0.0.0
Linia
4
Adres IP klienta (jeśli istnieje)

15
Adres IP Twojego klienta
172.16.134.61
Linia
4
Adres IP oferowany przez serwer (jeśli jest dostępny)

19
Adres IP następnego serwera
0.0.0.0
Linia
4
Adres IP serwera (jeśli jest znany)

23
Adres IP agenta przekazującego
172.16.114.41
Linia
4
Adres IP agenta przekazującego (na przykład przełącznika)

27
Adres MAC klienta
14:d6:4d:a7:c9:55
Hex
6
Adres MAC nadawcy pakietu (klienta)

31
Dopełnienie adresu sprzętowego klienta
 
Hex
10
Zarezerwowane miejsce. Zwykle wypełnione zerami

41
Nazwa hosta serwera
 
Linia
64
Nazwa serwera DHCP. Zwykle nie jest transmitowany

105
Nazwa pliku rozruchowego
 
Linia
128
Nazwa pliku na serwerze używana przez stacje bezdyskowe podczas uruchamiania

235
Magiczne ciastko
63: 82: 53: 63
Hex
4
Numer „Magiczny”, według którego m.in. możesz ustalić, że ten pakiet należy do protokołu DHCP

Opcje DHCP. Można iść w dowolnej kolejności

236
Numer opcji
53
grudzień
3
Opcja 53, która definiuje typ pakietu DHCP 5 - DHCPACK

 
Długość opcji
1
grudzień
1

 
Wartość opcji
5
grudzień
1

 
Numer opcji
1
grudzień
1
Opcja zaoferowania klientowi DHCP maski sieci

 
Długość opcji
4
grudzień
1

 
Wartość opcji
255.255.224.0
Linia
4

 
Numer opcji
3
grudzień
1
Opcja zaoferowania klientowi DHCP bramy domyślnej

 
Długość opcji
4
grudzień
1

 
Wartość opcji
172.16.12.1
Linia
4

 
Numer opcji
6
grudzień
1
Opcja oferowania DHCP klientowi DNS

 
Długość opcji
4
grudzień
1

 
Wartość opcji
8.8.8.8
Linia
4

 
Numer opcji
51
grudzień
1
Czas życia wydanych parametrów sieciowych w sekundach, po którym klient DHCP musi zażądać ich ponownie

 
Długość opcji
4
grudzień
1

 
Wartość opcji
86400
grudzień
4

 
Numer opcji
82
grudzień
1
Opcja 82 powtarza to, co pojawiło się w DHCPDISCOVER

 
Długość opcji
18
grudzień
1

 
Wartość opcji
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ek
grudzień
18

 
Koniec pakietu
255
grudzień
1
Liczba 255 symbolizuje koniec pakietu

Instalacja

Instalacja w rzeczywistości polega na zainstalowaniu niezbędnych do pracy modułów Pythona. Zakłada się, że MySQL jest już zainstalowany i skonfigurowany.

FreeBSD

pkg zainstaluj python3 python3 -m zapewnijpip pip3 zainstaluj złącze mysql

Ubuntu

sudo apt-get zainstaluj python3 sudo apt-get zainstaluj pip3 sudo pip3 zainstaluj złącze mysql

Tworzymy bazę danych MySQL, przesyłamy do niej zrzut pydhcp.sql i konfigurujemy plik konfiguracyjny.

Konfiguracja

Wszystkie ustawienia serwera znajdują się w pliku xml. Plik referencyjny:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 Lokalny Gospodarz test test pydhcp opcja_8.8.8.8_hex:sw_port82:1:20 opcja_22_hex:sw_port82:2:16 opcja_18_hex:sw_mac:82:26 40 wybierz ip,mask,router,dns od użytkowników, gdzie Upper(mac)=upper('{option_3_AgentRemoteId_hex}') i Upper(port)=upper('{option_1_AgentCircuitId_port_hex}') wybierz ip, maskę, router, dns od użytkowników, gdzie Upper(mac)=upper('{sw_mac}') i Upper(port)=upper('{sw_port82}') wybierz ip, maskę, router, dns od użytkowników, gdzie Upper(mac)=upper('{ClientMacAddress}') wstaw do historii (id,dt,mac,ip,komentarz) wartości (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Teraz bardziej szczegółowo na temat tagów:

Sekcja dhcpserver opisuje podstawowe ustawienia uruchamiania serwera, a mianowicie:

  • host - jakiego adresu IP nasłuchuje serwer na porcie 67
  • broadway - który adres IP jest rozgłoszeniem dla DHCPOFFER i DHCPACK
  • DHCPServer - jakie jest IP serwera DHCP
  • LeaseTime Czas dzierżawy wydanego adresu IP
  • ThreadLimit - ile wątków jest uruchomionych jednocześnie, aby przetworzyć przychodzące pakiety UDP na porcie 67. Ma to pomóc w projektach o dużym obciążeniu 😉
  • defaultMask,defaultRouter,defaultDNS - co jest domyślnie oferowane abonentowi, jeśli adres IP zostanie znaleziony w bazie danych, ale nie zostaną dla niego określone dodatkowe parametry

sekcja mysql:

host, nazwa użytkownika, hasło, nazwa bazowa - wszystko mówi samo za siebie. Przybliżona struktura bazy danych jest opublikowana na stronie GitHub

Sekcja zapytań: prośby o otrzymanie OFERTY/POTWIERDZENIA opisano tutaj:

  • Offer_count — liczba linii z żądaniami, które zwracają wynik taki jak ip, maska, router, dns
  • oferta_n — ciąg zapytania. Jeśli return jest pusty, wykonuje następujące żądanie oferty
  • history_sql - zapytanie wpisujące np. do „historii autoryzacji” dla abonenta

Żądania mogą zawierać dowolne zmienne z sekcji opcji lub opcje protokołu DHCP.

Sekcja opcji. Tutaj robi się ciekawiej. Tutaj możemy utworzyć zmienne, których będziemy mogli użyć później w sekcji zapytań.

Na przykład:

option_82_hex:sw_port1:20:22

, ta linia poleceń pobiera całą linię przyszłą w opcji żądania DHCP 82, w formacie szesnastkowym, w zakresie od 20 do 22 bajtów włącznie i umieszcza ją w nowej zmiennej sw_port1 (przełącz port, z którego przyszło żądanie)

option_82_hex:sw_mac:26:40

, zdefiniuj zmienną sw_mac, przyjmując wartość szesnastkową z zakresu 26:40

Wszystkie możliwe opcje, których można użyć w zapytaniach, można zobaczyć, uruchamiając serwer za pomocą przełącznika -d. Zobaczymy coś takiego jak ten dziennik:

--a Pakiet DHCPINFORM przybył na port 67, z 0025224ad764 , b'x91xa5xe0xa3xa5xa9-x8fx8a' , ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764', 'ClientMacAddressByte': b'x00 7% „Jxd91d” , ' 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” , 'flagi ': b'x00x172.30.114.25', 'giaddr': '308', 'gpoz': 6, 'hlen': 1, 'hops': 82, 'htype': 'MAC', 'magic_cookie': b'cx12Sc ', 'op': 'DHCPINFORM', 'opcja 12': 53, 'opcja 53': 55, 'opcja 55': 60, 'opcja 60': 61, 'opcja 61': 82, 'opcja 82': 82, ' opcja_12_byte': b'x01x06x00x04x00x01x00x06x02x08x00x06' b'x00x1x9eXx2exb82xad', 'opcja_12010600040001000602080006001_hex': '589e2eb82ad', 'opcja _18_len': 82 12, 'option_01_str': "b'x06x00x04x00x01x00x06x02x08x00x06x00x1x9x2eXx768exb0.0.0.0xad'", 'wynik': Fałsz, 'sek': 001, „siaddr”: „589”, „sw_mac”: „2e1eb06ad”, „sw_port89”: „8”, „xidbyte”: b”

W związku z tym możemy zawinąć dowolną zmienną w {} i zostanie ona użyta w zapytaniu SQL.

Zapiszmy dla historii, że klient otrzymał adres IP:

Serwer DHCP+Mysql w Pythonie

Serwer DHCP+Mysql w Pythonie

Uruchomienie serwera

./pydhcpdb.py -d -c plik konfiguracyjny.xml

— d tryb wyjścia konsoli DEBUG
- c <nazwa pliku> plik konfiguracyjny

Odprawa

A teraz więcej szczegółów na temat implementacji serwera w Pythonie. To jest ból. Pythona uczyłem się na bieżąco. Wiele momentów jest zrobionych w stylu „wow, jakoś mi się udało”. W ogóle nie zoptymalizowany i pozostawiony w tej formie głównie ze względu na małe doświadczenie w tworzeniu Pythona. Zatrzymam się nad najciekawszymi aspektami implementacji serwera w „kodzie”.

Parser pliku konfiguracyjnego XML

Używany jest standardowy moduł Pythona xml.dom. Wydaje się to proste, jednak podczas wdrażania zauważalny był brak jasnej dokumentacji i przykładów w sieci wykorzystujących ten moduł.

    drzewo = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") dla elem w mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("nazwa użytkownika")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("hasło")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basename")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") dla elem w 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") dla elem w qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data dla num w zakres(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") dla elem w opcjach: node=elem.getElementsByTagName("opcja") dla opcji w węźle : opcjeMod.append(opcje.firstChild.data)

Wielowątkowość

Co dziwne, wielowątkowość w Pythonie jest zaimplementowana bardzo przejrzyście i prosto.

def PacketWork(data,addr): ... # implementacja analizowania przychodzącego pakietu i odpowiadania na niego ... while True: dane, adres = udp_socket.recvfrom(1024) # oczekiwanie na pakiet UDP wątek = threading.Thread( target=PacketWork , args=(data,addr,)).start() # jak wyszło - uruchamiamy w tle zdefiniowaną wcześniej funkcję PacketWork z parametrami podczas threading.active_count() >gconfig["dhcp_ThreadLimit"]: czas. Sleep(1) # jeśli liczba Działa już więcej wątków niż w ustawieniach, czekamy aż będzie ich mniej

Odbierz/wyślij pakiet DHCP

Aby przechwycić pakiety UDP przechodzące przez kartę sieciową, należy „podnieść” gniazdo:

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

, gdzie flagi to:

  • AF_INET - oznacza, że ​​format adresu będzie miał postać IP:port. Może być też AF_UNIX – gdzie adres jest podany przez nazwę pliku.
  • SOCK_DGRAM - oznacza, że ​​nie przyjmujemy „surowego pakietu”, ale taki, który przeszedł już przez firewall i to z częściowo przyciętym pakietem. Te. otrzymujemy tylko pakiet UDP bez „fizycznego” komponentu opakowania pakietu UDP. Jeśli użyjesz flagi SOCK_RAW, będziesz musiał także przeanalizować to „opakowanie”.

Wysłanie pakietu może przypominać transmisję:

                    udp_socket.setsockopt(socket.SOL_SOCKET, gniazdo.SO_BROADCAST, 1) #przełącz gniazdo w tryb rozgłaszania rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, oraz na adres „skąd nadeszła przesyłka”:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # przełącz gniazdo w tryb wielu słuchaczy rz=udp_socket.sendto(packetack, adres)

, gdzie SOL_SOCKET oznacza „poziom protokołu” służący do ustawiania opcji,

, SO_BROADCAST opcja, że ​​pakiet kasku jest „rozgłaszany”

  Opcja SO_REUSEADDR przełącza gniazdo w tryb „wielu słuchaczy”. Teoretycznie jest to w tym przypadku niepotrzebne, jednak na jednym z serwerów FreeBSD, na którym testowałem, kod nie działał bez tej opcji.

Analizowanie pakietu DHCP

Tutaj naprawdę spodobał mi się Python. Okazuje się, że po wyjęciu z pudełka pozwala to na dość elastyczną pracę z kodem bajtowym. Umożliwiając bardzo łatwe przetłumaczenie go na wartości dziesiętne, ciągi znaków i szesnastkowe - tj. tego właśnie potrzebujemy, aby zrozumieć strukturę pakietu. Na przykład możesz uzyskać zakres bajtów w formacie HEX i tylko bajty:

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

, spakuj bajty do struktury:

res["flagi"]=pack('BB',dane[10],dane[11])

Uzyskaj adres IP ze struktury:

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

I wzajemnie:

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

To wszystko na teraz 😉

Źródło: www.habr.com

Dodaj komentarz