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:
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.
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.
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.
Serwer, który otrzymał DHCPREQUEST, wysyła pakiet w formacie DHCPACK, w którym ponownie zawiera listę ustawień sieciowych przeznaczonych dla tego klienta
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:
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
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
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
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
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:
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:
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:
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: