DHCP+Mysql сървър в Python

DHCP+Mysql сървър в Python

Целта на този проект беше:

  • Научаване за DHCP в IPv4 мрежа
  • Изучаване на Python (малко повече от нулата 😉)
  • подмяна на сървъра DB2DHCP (моята вилица), оригинал тук, който става все по-труден за сглобяване за новата ОС. И не ми харесва, че това е двоичен файл, който няма начин да „промените точно сега“
  • получаване на работещ DHCP сървър с възможност за избор на IP адреса на абоната, използвайки mac на абоната или комбинация от превключвател mac+port (Опция 82)
  • писане на друг велосипед (О! това е любимото ми занимание)
  • получаване на коментари за вашите умения с клуб в Habrahabr (или още по-добре, покана) 😉

Резултат: работи 😉 Тествано на FreeBSD и Ubuntu OS. Теоретично кодът може да бъде помолен да работи под всяка операционна система, защото Изглежда, че няма конкретни обвързвания в кода.
Внимателно! Предстои още много.

Връзка към хранилище за аматьори "докосване жив".

Процесът на инсталиране, конфигуриране и използване на резултата от „изучаване на хардуера“ е много по-нисък, а след това малко теория за DHCP протокола. За мен. И за историята 😉

Малко теория

Какво е DHCP

Това е мрежов протокол, който позволява на устройството да открие своя IP адрес (и други параметри като шлюз, DNS и т.н.) от DHCP сървър. Пакетите се обменят с помощта на UDP протокол. Общият принцип на работа на устройството при заявка на мрежови параметри е следният:

  1. Устройството (клиентът) изпраща UDP заявка за излъчване (DHCPDISCOVER) в цялата мрежа с искането „добре, някой да ми даде IP адрес“. Освен това обикновено (но не винаги) заявката идва от порт 68 (източник), а дестинацията е порт 67 (дестинация). Някои устройства също изпращат пакети от порт 67. MAC адресът на клиентското устройство е включен в пакета DHCPDISCOVER.
  2. Всички DHCP сървъри, разположени в мрежата (и може да има няколко от тях), формират оферта DHCPOFFER с мрежови настройки за устройството, изпратило DHCPDISCOVER, и също така го излъчват по мрежата. Идентифицирането на това за кого е предназначен този пакет се основава на MAC адреса на клиента, предоставен по-рано в заявката DHCPDISCOVER.
  3. Клиентът приема пакети с предложения за мрежови настройки, избира най-атрактивния (критериите могат да бъдат различни, например времето за доставка на пакета, броят на междинните маршрути) и прави „официална заявка“ DHCPREQUEST с мрежовите настройки от DHCP сървъра, който харесва. В този случай пакетът отива към определен DHCP сървър.
  4. Сървърът, получил DHCPREQUEST, изпраща пакет във формат DHCPACK, в който отново изброява мрежовите настройки, предназначени за този клиент

DHCP+Mysql сървър в Python

Освен това има DHCPINFORM пакети, които идват от клиента и чиято цел е да информират DHCP сървъра, че „клиентът е жив“ и използва издадените мрежови настройки. При изпълнението на този сървър тези пакети се игнорират.

Формат на опаковката

Като цяло рамката на Ethernet пакет изглежда по следния начин:

DHCP+Mysql сървър в Python

В нашия случай ще разгледаме само данните директно от съдържанието на UDP пакета, без заглавките на протокола на слоя OSI, а именно DHCP структурата:

DHCPDICOVER

И така, процесът на получаване на IP адрес за устройство започва с DHCP клиента, който изпраща заявка за излъчване от порт 68 до 255.255.255.255:67. В този пакет клиентът включва своя MAC адрес, както и какво точно иска да получи от DHCP сървъра. Структурата на пакета е описана в таблицата по-долу.

DHCPDISCOVER Структурна таблица на пакети

Позиция в опаковката
Име на стойността
Пример
идея
байт
Изясняване

1
Заявка за зареждане
1
магия
1
Тип съобщение. 1 - заявка от клиент към сървър, 2 - отговор от сървър към клиент

2
Тип хардуер
1
магия
1
Тип хардуерен адрес, в този протокол 1 - MAC

3
Дължина на хардуерните адреси
6
магия
1
Дължина на MAC адреса на устройството

4
Хмел
1
магия
1
Брой междинни маршрути

5
Идентификационен номер на транзакцията
23:cf:de:1d
магия
4
Уникален идентификатор на транзакция. Генерира се от клиента в началото на операция по заявка

7
Изтекла втора
0
магия
4
Време в секунди от началото на процеса на получаване на адрес

9
Флагове за зареждане
0
магия
2
Определени флагове, които могат да бъдат зададени за указване на параметри на протокола

11
IP адрес на клиента
0.0.0.0
ред
4
IP адрес на клиента (ако има такъв)

15
Вашият клиентски IP адрес
0.0.0.0
ред
4
IP адрес, предлаган от сървъра (ако е наличен)

19
IP адрес на следващия сървър
0.0.0.0
ред
4
IP адрес на сървъра (ако е известен)

23
IP адрес на релейния агент
172.16.114.41
ред
4
IP адрес на релейния агент (например комутатор)

27
MAC адрес на клиента
14:d6:4d:a7:c9:55
магия
6
MAC адрес на подателя на пакета (клиента)

31
Подпълване на хардуерния адрес на клиента
 
магия
10
Запазено място. Обикновено се пълни с нули

41
Име на хост на сървъра
 
ред
64
име на DHCP сървър. Обикновено не се предава

105
Име на файла за зареждане
 
ред
128
Име на файл на сървъра, използван от бездискови станции при зареждане

235
Вълшебни бисквитки
63: 82: 53: 63
магия
4
“Магическо” число, според което в т.ч. можете да определите, че този пакет принадлежи на DHCP протокола

DHCP опции. Може да върви в произволен ред

236
Номер на опцията
53
Декември
1
Опция 53, която определя типа DHCP пакет

1 - DHCPDISCOVER
3 - DHCPREQUEST
2 - DHCP ОФЕРТА
5 - DHCPACK
8 - DHCPINFORM

 
Дължина на опцията
1
Декември
1

 
Стойност на опцията
1
Декември
1

 
Номер на опцията
50
Декември
1
Какъв IP адрес иска да получи клиентът?

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
172.16.134.61
ред
4

 
Номер на опцията
55
 
1
Мрежови параметри, заявени от клиента. Съставът може да варира

01 — Мрежова маска
03 - Портал
06 - DNS
oc — Име на хост
0f - име на мрежов домейн
1c - адрес на заявка за излъчване (излъчване)
42 - Име на TFTP сървър
79 - Безкласов статичен маршрут

 
Дължина на опцията
8
 
1

 
Стойност на опцията
01:03:06:0c:0f:1c:42:79
 
8

 
Номер на опцията
82
Декември
 
Опция 82, която предава MAC адреса на ретранслаторното устройство и някои допълнителни стойности.

Най-често това е портът на комутатора, на който работи крайният DHCP клиент.Тази опция съдържа допълнителни параметри.Първият байт е номерът на „подопцията“, вторият е нейната дължина, след това нейната стойност.

В този случай в опция 82 подопциите са вложени:
Agent Circuit ID = 00:04:00:01:00:04, където последните два байта са DHCP клиентския порт, от който идва заявката

Agent Remote ID = 00:06:c8:be:19:93:11:48 - MAC адрес на DHCP ретранслаторното устройство

 
Дължина на опцията
18
Декември
 

 
Стойност на опцията
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
магия
 

 
Край на опаковката
255
Декември
1
255 символизира края на пакета

DHCP ОФЕРТА

Веднага след като сървърът получи DHCPDISCOVER пакета и ако види, че може да предложи на клиента нещо от заявеното, той генерира отговор за него - DHCPDISCOVER. Отговорът се изпраща до порта „откъдето е дошъл“, чрез излъчване, защото в този момент клиентът все още няма IP адрес, следователно може да приеме пакета само ако е изпратен чрез излъчване. Клиентът разпознава, че това е пакет за него по своя MAC адрес в пакета, както и по номера на транзакцията, който генерира при създаването на първия пакет.

DHCPOFFER Структурна таблица на пакети

Позиция в опаковката
Име на стойността (често срещано)
Пример
идея
байт
Изясняване

1
Заявка за зареждане
1
магия
1
Тип съобщение. 1 - заявка от клиент към сървър, 2 - отговор от сървър към клиент

2
Тип хардуер
1
магия
1
Тип хардуерен адрес, в този протокол 1 - MAC

3
Дължина на хардуерните адреси
6
магия
1
Дължина на MAC адреса на устройството

4
Хмел
1
магия
1
Брой междинни маршрути

5
Идентификационен номер на транзакцията
23:cf:de:1d
магия
4
Уникален идентификатор на транзакция. Генерира се от клиента в началото на операция по заявка

7
Изтекла втора
0
магия
4
Време в секунди от началото на процеса на получаване на адрес

9
Флагове за зареждане
0
магия
2
Определени флагове, които могат да бъдат зададени за указване на параметри на протокола. В този случай 0 означава типа Unicast заявка

11
IP адрес на клиента
0.0.0.0
ред
4
IP адрес на клиента (ако има такъв)

15
Вашият клиентски IP адрес
172.16.134.61
ред
4
IP адрес, предлаган от сървъра (ако е наличен)

19
IP адрес на следващия сървър
0.0.0.0
ред
4
IP адрес на сървъра (ако е известен)

23
IP адрес на релейния агент
172.16.114.41
ред
4
IP адрес на релейния агент (например комутатор)

27
MAC адрес на клиента
14:d6:4d:a7:c9:55
магия
6
MAC адрес на подателя на пакета (клиента)

31
Подпълване на хардуерния адрес на клиента
 
магия
10
Запазено място. Обикновено се пълни с нули

41
Име на хост на сървъра
 
ред
64
име на DHCP сървър. Обикновено не се предава

105
Име на файла за зареждане
 
ред
128
Име на файл на сървъра, използван от бездискови станции при зареждане

235
Вълшебни бисквитки
63: 82: 53: 63
магия
4
“Магическо” число, според което в т.ч. можете да определите, че този пакет принадлежи на DHCP протокола

DHCP опции. Може да върви в произволен ред

236
Номер на опцията
53
Декември
1
Опция 53, която дефинира типа DHCP 2 пакет - DHCPOFFER

 
Дължина на опцията
1
Декември
1

 
Стойност на опцията
2
Декември
1

 
Номер на опцията
1
Декември
1
Възможност за предлагане на мрежова маска на DHCP клиента

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
255.255.224.0
ред
4

 
Номер на опцията
3
Декември
1
Опция за предлагане на DHCP клиента на шлюз по подразбиране

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
172.16.12.1
ред
4

 
Номер на опцията
6
Декември
1
Възможност за предлагане на DHCP към DNS клиент

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
8.8.8.8
ред
4

 
Номер на опцията
51
Декември
1
Животът на издадените мрежови параметри в секунди, след което DHCP клиентът трябва да ги поиска отново

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
86400
Декември
4

 
Номер на опцията
82
Декември
1
Опция 82, повтаря това, което дойде в DHCPDISCOVER

 
Дължина на опцията
18
Декември
1

 
Стойност на опцията
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4г:ек
Декември
18

 
Край на опаковката
255
Декември
1
255 символизира края на пакета

DHCPREQUEST

След като клиентът получи DHCPOFFER, той формира пакет, изискващ мрежови параметри не към всички DHCP сървъри в мрежата, а само към един конкретен, чието DHCPOFFER предложение му е „харесало“ най-много. Критериите за „харесване“ могат да бъдат различни и зависят от изпълнението на DHCP на клиента. Получателят на заявката се посочва с помощта на MAC адреса на DHCP сървъра. Освен това DHCPREQUEST пакет може да бъде изпратен от клиента без първо да генерира DHCPDISCOVER, ако IP адресът на сървъра вече е получен преди това.

DHCPREQUEST Структурна таблица на пакети

Позиция в опаковката
Име на стойността (често срещано)
Пример
идея
байт
Изясняване

1
Заявка за зареждане
1
магия
1
Тип съобщение. 1 - заявка от клиент към сървър, 2 - отговор от сървър към клиент

2
Тип хардуер
1
магия
1
Тип хардуерен адрес, в този протокол 1 - MAC

3
Дължина на хардуерните адреси
6
магия
1
Дължина на MAC адреса на устройството

4
Хмел
1
магия
1
Брой междинни маршрути

5
Идентификационен номер на транзакцията
23:cf:de:1d
магия
4
Уникален идентификатор на транзакция. Генерира се от клиента в началото на операция по заявка

7
Изтекла втора
0
магия
4
Време в секунди от началото на процеса на получаване на адрес

9
Флагове за зареждане
8000
магия
2
Определени флагове, които могат да бъдат зададени за указване на параметри на протокола. В този случай е зададено „излъчване“.

11
IP адрес на клиента
0.0.0.0
ред
4
IP адрес на клиента (ако има такъв)

15
Вашият клиентски IP адрес
172.16.134.61
ред
4
IP адрес, предлаган от сървъра (ако е наличен)

19
IP адрес на следващия сървър
0.0.0.0
ред
4
IP адрес на сървъра (ако е известен)

23
IP адрес на релейния агент
172.16.114.41
ред
4
IP адрес на релейния агент (например комутатор)

27
MAC адрес на клиента
14:d6:4d:a7:c9:55
магия
6
MAC адрес на подателя на пакета (клиента)

31
Подпълване на хардуерния адрес на клиента
 
магия
10
Запазено място. Обикновено се пълни с нули

41
Име на хост на сървъра
 
ред
64
име на DHCP сървър. Обикновено не се предава

105
Име на файла за зареждане
 
ред
128
Име на файл на сървъра, използван от бездискови станции при зареждане

235
Вълшебни бисквитки
63: 82: 53: 63
магия
4
“Магическо” число, според което в т.ч. можете да определите, че този пакет принадлежи на DHCP протокола

DHCP опции. Може да върви в произволен ред

236
Номер на опцията
53
Декември
3
Опция 53, която дефинира DHCP пакет тип 3 - DHCPREQUEST

 
Дължина на опцията
1
Декември
1

 
Стойност на опцията
3
Декември
1

 
Номер на опцията
61
Декември
1
ID на клиента: 01 (за Ehernet) + MAC адрес на клиента

 
Дължина на опцията
7
Декември
1

 
Стойност на опцията
01:2c:ab:25:ff:72:a6
магия
7

 
Номер на опцията
60
Декември
 
„Идентификатор на класа на доставчика“. В моя случай той отчита версията на DHCP клиента. Може би други устройства връщат нещо различно. Windows например отчита MSFT 5.0

 
Дължина на опцията
11
Декември
 

 
Стойност на опцията
udhcp 0.9.8
ред
 

 
Номер на опцията
55
 
1
Мрежови параметри, заявени от клиента. Съставът може да варира

01 — Мрежова маска
03 - Портал
06 - DNS
oc — Име на хост
0f - име на мрежов домейн
1c - адрес на заявка за излъчване (излъчване)
42 - Име на TFTP сървър
79 - Безкласов статичен маршрут

 
Дължина на опцията
8
 
1

 
Стойност на опцията
01:03:06:0c:0f:1c:42:79
 
8

 
Номер на опцията
82
Декември
1
Опция 82, повтаря това, което дойде в DHCPDISCOVER

 
Дължина на опцията
18
Декември
1

 
Стойност на опцията
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4г:ек
Декември
18

 
Край на опаковката
255
Декември
1
255 символизира края на пакета

DHCPACK

Като потвърждение, че „да, точно така, това е вашият IP адрес и няма да го дам на никой друг“ от DHCP сървъра, служи пакет във формат DHCPACK от сървъра към клиента. Изпраща се излъчване точно като другите пакети. Въпреки че в кода по-долу за DHCP сървър, внедрен в Python, за всеки случай дублирам всяка заявка за излъчване, като изпращам пакет до конкретен клиентски IP адрес, ако вече е известен. Освен това DHCP сървърът изобщо не се интересува дали DHCPACK пакетът е достигнал до клиента. Ако клиентът не получи DHCPACK, след известно време той просто повтаря DHCPREQUEST

DHCPACK Структурна таблица на пакети

Позиция в опаковката
Име на стойността (често срещано)
Пример
идея
байт
Изясняване

1
Заявка за зареждане
2
магия
1
Тип съобщение. 1 - заявка от клиент към сървър, 2 - отговор от сървър към клиент

2
Тип хардуер
1
магия
1
Тип хардуерен адрес, в този протокол 1 - MAC

3
Дължина на хардуерните адреси
6
магия
1
Дължина на MAC адреса на устройството

4
Хмел
1
магия
1
Брой междинни маршрути

5
Идентификационен номер на транзакцията
23:cf:de:1d
магия
4
Уникален идентификатор на транзакция. Генерира се от клиента в началото на операция по заявка

7
Изтекла втора
0
магия
4
Време в секунди от началото на процеса на получаване на адрес

9
Флагове за зареждане
8000
магия
2
Определени флагове, които могат да бъдат зададени за указване на параметри на протокола. В този случай е зададено „излъчване“.

11
IP адрес на клиента
0.0.0.0
ред
4
IP адрес на клиента (ако има такъв)

15
Вашият клиентски IP адрес
172.16.134.61
ред
4
IP адрес, предлаган от сървъра (ако е наличен)

19
IP адрес на следващия сървър
0.0.0.0
ред
4
IP адрес на сървъра (ако е известен)

23
IP адрес на релейния агент
172.16.114.41
ред
4
IP адрес на релейния агент (например комутатор)

27
MAC адрес на клиента
14:d6:4d:a7:c9:55
магия
6
MAC адрес на подателя на пакета (клиента)

31
Подпълване на хардуерния адрес на клиента
 
магия
10
Запазено място. Обикновено се пълни с нули

41
Име на хост на сървъра
 
ред
64
име на DHCP сървър. Обикновено не се предава

105
Име на файла за зареждане
 
ред
128
Име на файл на сървъра, използван от бездискови станции при зареждане

235
Вълшебни бисквитки
63: 82: 53: 63
магия
4
“Магическо” число, според което в т.ч. можете да определите, че този пакет принадлежи на DHCP протокола

DHCP опции. Може да върви в произволен ред

236
Номер на опцията
53
Декември
3
Опция 53, която дефинира DHCP пакет тип 5 - DHCPACK

 
Дължина на опцията
1
Декември
1

 
Стойност на опцията
5
Декември
1

 
Номер на опцията
1
Декември
1
Възможност за предлагане на мрежова маска на DHCP клиента

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
255.255.224.0
ред
4

 
Номер на опцията
3
Декември
1
Опция за предлагане на DHCP клиента на шлюз по подразбиране

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
172.16.12.1
ред
4

 
Номер на опцията
6
Декември
1
Възможност за предлагане на DHCP към DNS клиент

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
8.8.8.8
ред
4

 
Номер на опцията
51
Декември
1
Животът на издадените мрежови параметри в секунди, след което DHCP клиентът трябва да ги поиска отново

 
Дължина на опцията
4
Декември
1

 
Стойност на опцията
86400
Декември
4

 
Номер на опцията
82
Декември
1
Опция 82, повтаря това, което дойде в DHCPDISCOVER

 
Дължина на опцията
18
Декември
1

 
Стойност на опцията
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4г:ек
Декември
18

 
Край на опаковката
255
Декември
1
255 символизира края на пакета

Инсталация

Инсталацията всъщност се състои в инсталиране на необходимите за работа Python модули. Предполага се, че MySQL вече е инсталиран и конфигуриран.

FreeBSD

pkg инсталирайте python3 python3 -m securepip pip3 инсталирайте mysql-конектор

Ubuntu

sudo apt-get инсталирате python3 sudo apt-get инсталирате pip3 sudo pip3 инсталирате mysql-конектор

Създаваме MySQL база данни, качваме дъмпа на pydhcp.sql в нея и конфигурираме конфигурационния файл.

Конфигурация

Всички настройки на сървъра са в xml файл. Референтен файл:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 локален хост тест тест pydhcp option_8.8.8.8_hex:sw_port82:1:20 option_22_hex:sw_port82:2:16 option_18_hex:sw_mac:82:26 40 изберете ip,mask,router,dns от потребители, където upper(mac)=upper('{option_3_AgentRemoteId_hex}') и upper(port)=upper('{option_1_AgentCircuitId_port_hex}') изберете ip,mask,router,dns от потребители, където upper(mac)=upper('{sw_mac}') и upper(port)=upper('{sw_port82}') изберете ip,mask,router,dns от потребители, където upper(mac)=upper('{ClientMacAddress}') вмъкнете в историята (id,dt,mac,ip,comment) стойности (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Сега по-подробно за етикетите:

Разделът dhcpserver описва основните настройки за стартиране на сървъра, а именно:

  • хост - какъв IP адрес сървърът слуша на порт 67
  • излъчване - кое ip е излъчването за DHCPOFFER и DHCPACK
  • DHCPServer - какво е ip-то на DHCP сървъра
  • LeaseTime време за наем на издадения IP адрес
  • ThreadLimit - колко нишки се изпълняват едновременно за обработка на входящи UDP пакети на порт 67. Предполага се, че помага при проекти с голямо натоварване 😉
  • defaultMask,defaultRouter,defaultDNS - какво се предлага на абоната по подразбиране, ако IP е намерен в базата данни, но не са посочени допълнителни параметри за него

mysql раздел:

хост, потребителско име, парола, базово име - всичко говори само за себе си. Приблизителна структура на базата данни е публикувана на GitHub

Секция за заявки: заявките за получаване на ОФЕРТА/ACK са описани тук:

  • offer_count — броят редове със заявки, които връщат резултат като ip,mask,router,dns
  • offer_n — низ за заявка. Ако връщането е празно, тогава се изпълнява следната заявка за оферта
  • history_sql - заявка, която записва, например, в „хронологията на оторизацията“ за абонат

Заявките могат да включват всякакви променливи от секцията с опции или опции от DHCP протокола.

Раздел Опции. Тук става по-интересно. Тук можем да създадем променливи, които да използваме по-късно в секцията за заявки.

Например:

option_82_hex:sw_port1:20:22

, този команден ред взема целия ред, който дойде в опцията за DHCP заявка 82, в шестнадесетичен формат, в диапазона от 20 до 22 байта включително, и го поставя в новата променлива sw_port1 (порт за превключване, откъдето е дошла заявката)

option_82_hex:sw_mac:26:40

, дефинирайте променливата sw_mac, като вземете шестнадесетичния код от диапазона 26:40

Можете да видите всички възможни опции, които могат да се използват в заявки, като стартирате сървъра с ключа -d. Ще видим нещо като този дневник:

--пакет DHCPINFORM пристигна на порт 67 от 0025224ad764, b'x91xa5xe0xa3xa5xa9-x8fx8a', ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764', 'ClientMacAddressBy te': b'x00 7%"Jxd91d' , 'HType': 'Ethernet', 'HostName': b'x5xa0xe3xa5xa9xa8-x8fx43a', 'ReqListDNS': True, 'ReqListDomainName': True, 'ReqListPerfowmRouterDiscover': True, 'ReqListRouter': True, 'ReqListStaticRoute ': Вярно, 'ReqListSubnetM ask': Вярно, '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, ' option_12_byte': b'x01x06x00x04x00x01x00x06x02x08x00x06' b'x00x1x9eXx2exb82xad', 'option_12010600040001000602080006001_hex': '589e2eb82ad', 'op tion_18_len': 82 12, 'option_01_str': "b'x06x00x04x00x01x00x06x02x08x00x06x00x1x9x2eXx768exb0.0.0.0xad'", "резултат": False, "секунди": 001, 'siaddr': '589', 'sw_mac': '2e1eb06ad', 'sw_port89': '8', 'xidbyte': b'

Съответно можем да обвием всяка променлива в {} и тя ще бъде използвана в SQL заявката.

Нека запишем за историята, че клиентът е получил IP адреса:

DHCP+Mysql сървър в Python

DHCP+Mysql сървър в Python

Старт на сървъра

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

— d конзолен изходен режим DEBUG
- c <име на файл> конфигурационен файл

инструктиране на отговорно лице

А сега повече подробности за внедряването на сървъра в Python. Това е болка. Python беше научен в движение. Много моменти са направени в стил „уау, някак си успях“. Изобщо не е оптимизиран и е оставен в тази форма главно поради малък опит в разработката на Python. Ще се спра на най-интересните аспекти на внедряването на сървъра в „код“.

Анализатор на XML конфигурационен файл

Използва се стандартният Python модул xml.dom. Изглежда просто, но по време на изпълнението имаше забележима липса на ясна документация и примери в мрежата, използваща този модул.

    дърво = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") за елемент в 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") за елемент в 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") за elem в qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data за num в диапазон (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") за елемент в опциите: node=elem.getElementsByTagName("опция") за опции в възел : optionsMod.append(options.firstChild.data)

Многопоточност

Колкото и да е странно, многопоточността в Python е реализирана много ясно и просто.

def PacketWork(data,addr): ... # реализация на анализиране на входящия пакет и отговор на него ... while True: data, addr = udp_socket.recvfrom(1024) # изчакване на UDP пакет thread = threading.Thread( target=PacketWork , args=(data,addr,)).start() # както дойде - стартираме предварително дефинираната PacketWork функция във фонов режим с параметри, докато threading.active_count() >gconfig["dhcp_ThreadLimit"]: време. sleep(1) # ако числото Вече работят повече нишки, отколкото в настройките, изчакваме, докато останат по-малко от тях

Получаване/изпращане на DHCP пакет

За да прихванете UDP пакети, идващи през мрежовата карта, трябва да „повдигнете“ сокета:

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

, където флаговете са:

  • AF_INET - означава, че форматът на адреса ще бъде IP: порт. Може да има и AF_UNIX - където адресът е даден от името на файла.
  • SOCK_DGRAM - означава, че не приемаме „суров пакет“, а такъв, който вече е преминал през защитната стена и с частично изрязан пакет. Тези. получаваме само UDP пакет без „физическия“ компонент на обвивката на UDP пакета. Ако използвате флага SOCK_RAW, тогава ще трябва също да анализирате тази „обвивка“.

Изпращането на пакет може да бъде като излъчване:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #превключване на сокета към режим на изпращане на излъчване rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, и на адреса „откъде идва пакетът“:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # превключване на сокета в режим на много слушатели rz=udp_socket.sendto(packetack, addr)

, където SOL_SOCKET означава „протоколно ниво“ за опции за настройка,

, опция SO_BROADCAST, че пакетът на каската е „излъчен“

  Опцията SO_REUSEADDR превключва сокета в режим „много слушатели“. На теория в този случай не е необходимо, но на един от FreeBSD сървърите, на които тествах, кодът не работи без тази опция.

Разбор на DHCP пакет

Това е мястото, където наистина харесах Python. Оказва се, че извън кутията ви позволява да бъдете доста гъвкави с байт кода. Позволявайки много лесно да бъде преведен в десетични стойности, низове и шестнадесетичен - т.е. това всъщност е необходимо, за да разберем структурата на пакета. Така, например, можете да получите набор от байтове в HEX и само байтове:

    res["xidhex"]=данни[4:8].hex() res["xidbyte"]=данни[4:8]

, пакетирайте байтовете в структура:

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

Вземете IP от структура:

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

И обратно:

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

Това е всичко за сега 😉

Източник: www.habr.com

Добавяне на нов коментар