замена серверу DB2DHCP (мой форк), оригинал здесь, который собирать под новую ОС всё труднее и труднее. Да и не нравится, что бинарник, который нет возможности «поменять прям щас»
получение работоспособного сервера DHCP с возможностью выборки IP адреса абонента по mac абонента или связке mac свича+порт (Option 82)
написание очередного велосипеда (О! это моё любимое занятие)
получение люлей про свою косорукость на Хабрахабр (а лучше инвайта) 😉
Результат: работает 😉 Опробовано на ОС FreeBSD и Ubuntu. Теоретически код можно попросить работать под любой ОС, т.к. специфических привязок в коде как будто нет.
Осторожно! Дальше много.
Ссылка на репозиторий для любителей «потрогать живьем».
Процесс установки, настройки и использования результата «изучения матчасти» много ниже, а далее немножко теории по протоколу DHCP. Для себя. И для истории 😉
Немножко теории
Что такое DHCP
Это сетевой протокол который позволяет устройству узнать свой IP адрес (ну и другие параметры вроде шлюза, DNS и прочего), у сервера DHCP. Обмен пакетами идет по протоколу UDP. Общий принцип работы устройства при запросе параметров сети следующий:
Устройство (клиент) рассылает широковещательный UDP запрос (DHCPDISCOVER) по всей сети с запросом «ну кто-нибудь, дайте мне IP адрес». Причем обычно (но не всегда) запрос происходит с 68 порта (источник), а назначение — 67 порт (назначение). Некоторые устройства отправляют пакеты и с 67 порта. Внутри пакета DHCPDISCOVER включен MAC адрес устройства клиента.
Все сервера DHCP, находящиеся в сети (а их может быть несколько), формируют для устройства отправившего DHCPDISCOVER, предложение DHCPOFFER с сетевыми настройками, и так-же широковещательно его отсылает его по сети. Идентификация кому предназначен этот пакет идет по MAC адресу клиента, предоставленного ранее в запросе DHCPDISCOVER.
Клиент принимает пакеты с предложениями сетевых настроек, выбирает наиболее привлекательный (критерии могут быть различными, например в т.ч. и по времени доставки пакета, количестве промежуточных маршрутов), и делает у понравившегося сервера DHCP «официальный запрос» DHCPREQUEST с сетевыми настройками. В этом случае пакет идет уже к конкретному серверу DHCP.
Сервер, получивший DHCPREQUEST, отправляет пакет формата DHCPACK, в котором в очередной раз перечисляет сетевые настройки предназначенные для данного клиента
Кроме того, есть пакеты DHCPINFORM, которые ходят от клиента, и цель которых проинформировать DHCP сервер о том, что «клиент жив» и пользуется выданными сетевыми настройками. В реализации данного сервера эти пакеты игнорируются.
Формат пакетов
В целом фрейм пакета Ethernet выглядит примерно так:
В нашем случаем мы рассмотрим только данные непосредственно содержимого пакета UDP, без заголовков протоколов уровней OSI, а именно структуру DHCP:
DHCPDISCOVER
Итак, процесс получения IP адреса для устройства начинается с того, что клиент DHCP рассылает широковещательный запрос с порта 68 на 255.255.255.255:67. В этом пакете клиент включает свой MAC адрес, а так-же что именно он хочет получить от DHCP сервера. Структура пакета описана в виде таблицы ниже.
Таблица структуры пакета DHCPDISCOVER
Позиция в пакете
Название значения
Пример
Представление
Байт
Пояснение
1
Boot Request
1
Hex
1
Тип сообщения. 1 — запрос от клиента к серверу, 2 — ответ от сервера клиенту
2
Hardware type
1
Hex
1
Тип аппаратного адреса, в данном протоколе 1 — MAC
3
Hardware adrees length
6
Hex
1
Длина MAC адреса устройства
4
Hops
1
Hex
1
Количество промежуточных маршрутов
5
Transaction ID
23:cf:de:1d
Hex
4
Уникальный идентификатор транзакции. Генерирует клиент в начале операции запроса
7
Second elapsed
0
Hex
4
Время в секундах с начала процесса получения адреса
9
Bootp flags
0
Hex
2
Некие флаги, которые могут устанавливаться, в качестве указания параметров протокола
11
Client IP address
0.0.0.0
Строка
4
IP адрес клиента (если есть)
15
Your client IP address
0.0.0.0
Строка
4
IP адрес предложенный сервером (если есть)
19
Next server IP address
0.0.0.0
Строка
4
IP адрес сервера (если известен)
23
Relay agent IP address
172.16.114.41
Строка
4
IP адрес агента ретрансляции (например свича)
27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC адрес отправителя пакета (клиента)
31
Client hardware address padding
Hex
10
Зарезервированное место. Обычно забито нулями
41
Server host name
Строка
64
Имя сервера DHCP. Обычно не передается
105
Boot file name
Строка
128
Имя файла на сервере, используемое бездисковыми станциями при загрузке
235
Magic cookie
63:82:53:63
Hex
4
«Магическое» число, по которому в т.ч. можно определить, что этот пакет — принадлежит протоколу DHCP
Опции DHCP. Могут идти в любом порядке
236
Номер опции
53
Dec
1
Опция 53, определяющая тип пакета DHCP
Номер опции
50
Dec
1
Какой IP адрес хочет получить клиент
Длина опции
4
Dec
1
Значение опции
172.16.134.61
Строка
4
Номер опции
55
1
Запрашиваемые клиентом сетевые параметры. Состав может быть различным
01 — Маска сети
03 — Шлюз
06 — DNS
oc — Имя хоста
0f — имя домена сети
1c — адрес широковещательного запроса (бродкаста)
42 — имя сервера TFTP
79 — Classless Static Route
Длина опции
8
1
Значение опции
01:03:06:0c:0f:1c:42:79
8
Номер опции
82
Dec
Опция 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
Dec
Значение опции
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
Окончание пакета
255
Dec
1
255 символизирует окончание пакета
DHCPOFFER
Как только сервер получает пакет DHCPDISCOVER и если он видит, что может клиенту что-то предложить из запрошенного, то он формирует для него ответ — DHCPDISCOVER. Ответ высылается на порт «откуда пришел», бродкастом, т.к. в этот момент, у клиента еще нет IP адреса, следовательно пакет он может принять, только если он отослан широковещательно. Клиент распознает что это пакет для него по MAC своему адресу внутри пакета, а так-же номеру транзакции, который он генерирует в момент создания первого пакета.
Таблица структуры пакета DHCPOFFER
Позиция в пакете
Название значения (общепринятое)
Пример
Представление
Байт
Пояснение
1
Boot Request
1
Hex
1
Тип сообщения. 1 — запрос от клиента к серверу, 2 — ответ от сервера клиенту
2
Hardware type
1
Hex
1
Тип аппаратного адреса, в данном протоколе 1 — MAC
3
Hardware adrees length
6
Hex
1
Длина MAC адреса устройства
4
Hops
1
Hex
1
Количество промежуточных маршрутов
5
Transaction ID
23:cf:de:1d
Hex
4
Уникальный идентификатор транзакции. Генерирует клиент в начале операции запроса
7
Second elapsed
0
Hex
4
Время в секундах с начала процесса получения адреса
9
Bootp flags
0
Hex
2
Некие флаги, которые могут устанавливаться, в качестве указания параметров протокола. В данном случае, 0 — означает тип запроса Unicast
11
Client IP address
0.0.0.0
Строка
4
IP адрес клиента (если есть)
15
Your client IP address
172.16.134.61
Строка
4
IP адрес предложенный сервером (если есть)
19
Next server IP address
0.0.0.0
Строка
4
IP адрес сервера (если известен)
23
Relay agent IP address
172.16.114.41
Строка
4
IP адрес агента ретрансляции (например свича)
27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC адрес отправителя пакета (клиента)
31
Client hardware address padding
Hex
10
Зарезервированное место. Обычно забито нулями
41
Server host name
Строка
64
Имя сервера DHCP. Обычно не передается
105
Boot file name
Строка
128
Имя файла на сервере, используемое бездисковыми станциями при загрузке
235
Magic cookie
63:82:53:63
Hex
4
«Магическое» число, по которому в т.ч. можно определить, что этот пакет — принадлежит протоколу DHCP
Опции DHCP. Могут идти в любом порядке
236
Номер опции
53
Dec
1
Опция 53, определяющая тип пакета DHCP 2 — DHCPOFFER
Длина опции
1
Dec
1
Значение опции
2
Dec
1
Номер опции
1
Dec
1
Опция предлагающая DHCP клиенту маску сети
Длина опции
4
Dec
1
Значение опции
255.255.224.0
Строка
4
Номер опции
3
Dec
1
Опция предлагающая DHCP клиенту шлюз по умолчанию
Длина опции
4
Dec
1
Значение опции
172.16.12.1
Строка
4
Номер опции
6
Dec
1
Опция предлагающая DHCP клиенту DNS
Длина опции
4
Dec
1
Значение опции
8.8.8.8
Строка
4
Номер опции
51
Dec
1
Время жизни выданных сетевых параметров в секундах, через которое DHCP клиент должен запросить их снова
Длина опции
4
Dec
1
Значение опции
86400
Dec
4
Номер опции
82
Dec
1
Опция 82, повторяет то что пришло в DHCPDISCOVER
Длина опции
18
Dec
1
Значение опции
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
Окончание пакета
255
Dec
1
255 символизирует окончание пакета
DHCPREQUEST
После того, как клиент получит DHCPOFFER, он формирует пакет с запросом сетевых параметров уже не ко всем серверам DHCP в сети, а только к одному конкретному, предложение DHCPOFFER которого, ему наиболее «понравилось». Критерии «понравилось» могут быть различные и зависят от реализации DHCP клиента. Получатель запроса указывается при помощи MAC адреса сервера DHCP. Так-же пакет DHCPREQUEST может быть выслан клиентом и без формирования ранее DHCPDISCOVER, если IP адрес у сервера уже ранее когда-то был получен.
Таблица структуры пакета DHCPREQUEST
Позиция в пакете
Название значения (общепринятое)
Пример
Представление
Байт
Пояснение
1
Boot Request
1
Hex
1
Тип сообщения. 1 — запрос от клиента к серверу, 2 — ответ от сервера клиенту
2
Hardware type
1
Hex
1
Тип аппаратного адреса, в данном протоколе 1 — MAC
3
Hardware adrees length
6
Hex
1
Длина MAC адреса устройства
4
Hops
1
Hex
1
Количество промежуточных маршрутов
5
Transaction ID
23:cf:de:1d
Hex
4
Уникальный идентификатор транзакции. Генерирует клиент в начале операции запроса
7
Second elapsed
0
Hex
4
Время в секундах с начала процесса получения адреса
9
Bootp flags
8000
Hex
2
Некие флаги, которые могут устанавливаться, в качестве указания параметров протокол. В данном случае выставлено «бродкаст»
11
Client IP address
0.0.0.0
Строка
4
IP адрес клиента (если есть)
15
Your client IP address
172.16.134.61
Строка
4
IP адрес предложенный сервером (если есть)
19
Next server IP address
0.0.0.0
Строка
4
IP адрес сервера (если известен)
23
Relay agent IP address
172.16.114.41
Строка
4
IP адрес агента ретрансляции (например свича)
27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC адрес отправителя пакета (клиента)
31
Client hardware address padding
Hex
10
Зарезервированное место. Обычно забито нулями
41
Server host name
Строка
64
Имя сервера DHCP. Обычно не передается
105
Boot file name
Строка
128
Имя файла на сервере, используемое бездисковыми станциями при загрузке
235
Magic cookie
63:82:53:63
Hex
4
«Магическое» число, по которому в т.ч. можно определить, что этот пакет — принадлежит протоколу DHCP
Опции DHCP. Могут идти в любом порядке
236
Номер опции
53
Dec
3
Опция 53, определяющая тип пакета DHCP 3 — DHCPREQUEST
Длина опции
1
Dec
1
Значение опции
3
Dec
1
Номер опции
61
Dec
1
Идентификатор клиента: 01 (для Ehernet) + MAC адрес клиента
Длина опции
7
Dec
1
Значение опции
01:2c:ab:25:ff:72:a6
Hex
7
Номер опции
60
Dec
«Vendor class identifier». В моем случае сообает версию DHCP клиента. Возможно другие устройства, возвращают что-то другое. Windows например сообщает MSFT 5.0
Длина опции
11
Dec
Значение опции
udhcp 0.9.8
Строка
Номер опции
55
1
Запрашиваемые клиентом сетевые параметры. Состав может быть различным
01 — Маска сети
03 — Шлюз
06 — DNS
oc — Имя хоста
0f — имя домена сети
1c — адрес широковещательного запроса (бродкаста)
42 — имя сервера TFTP
79 — Classless Static Route
Длина опции
8
1
Значение опции
01:03:06:0c:0f:1c:42:79
8
Номер опции
82
Dec
1
Опция 82, повторяет то что пришло в DHCPDISCOVER
Длина опции
18
Dec
1
Значение опции
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
Окончание пакета
255
Dec
1
255 символизирует окончание пакета
DHCPACK
В качестве подтверждения того, что «да точно, это твой IP адрес, и больше я его никому не выдам» от DHCP сервера, служит пакет в формате DHCPACK от сервера клиенту. Он так-же как и остальные пакеты высылается широковещательно. Хотя, в ниже приведенном коде DHCP сервера реализованного на Python, я на всякий случай дублирую любой широковещательный запрос, отправкой пакета на конкретный IP клиента, если он уже известен. Причем DHCP сервер совершенно не волнует, дошел ли до клиента пакет DHCPACK. Если клиент не получает DHCPACK, то через некоторое время он просто повторяет DHCPREQUEST
Таблица структуры пакета DHCPACK
Позиция в пакете
Название значения (общепринятое)
Пример
Представление
Байт
Пояснение
1
Boot Request
2
Hex
1
Тип сообщения. 1 — запрос от клиента к серверу, 2 — ответ от сервера клиенту
2
Hardware type
1
Hex
1
Тип аппаратного адреса, в данном протоколе 1 — MAC
3
Hardware adrees length
6
Hex
1
Длина MAC адреса устройства
4
Hops
1
Hex
1
Количество промежуточных маршрутов
5
Transaction ID
23:cf:de:1d
Hex
4
Уникальный идентификатор транзакции. Генерирует клиент в начале операции запроса
7
Second elapsed
0
Hex
4
Время в секундах с начала процесса получения адреса
9
Bootp flags
8000
Hex
2
Некие флаги, которые могут устанавливаться, в качестве указания параметров протокол. В данном случае выставлено «бродкаст»
11
Client IP address
0.0.0.0
Строка
4
IP адрес клиента (если есть)
15
Your client IP address
172.16.134.61
Строка
4
IP адрес предложенный сервером (если есть)
19
Next server IP address
0.0.0.0
Строка
4
IP адрес сервера (если известен)
23
Relay agent IP address
172.16.114.41
Строка
4
IP адрес агента ретрансляции (например свича)
27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC адрес отправителя пакета (клиента)
31
Client hardware address padding
Hex
10
Зарезервированное место. Обычно забито нулями
41
Server host name
Строка
64
Имя сервера DHCP. Обычно не передается
105
Boot file name
Строка
128
Имя файла на сервере, используемое бездисковыми станциями при загрузке
235
Magic cookie
63:82:53:63
Hex
4
«Магическое» число, по которому в т.ч. можно определить, что этот пакет — принадлежит протоколу DHCP
Опции DHCP. Могут идти в любом порядке
236
Номер опции
53
Dec
3
Опция 53, определяющая тип пакета DHCP 5 — DHCPACK
Длина опции
1
Dec
1
Значение опции
5
Dec
1
Номер опции
1
Dec
1
Опция предлагающая DHCP клиенту маску сети
Длина опции
4
Dec
1
Значение опции
255.255.224.0
Строка
4
Номер опции
3
Dec
1
Опция предлагающая DHCP клиенту шлюз по умолчанию
Длина опции
4
Dec
1
Значение опции
172.16.12.1
Строка
4
Номер опции
6
Dec
1
Опция предлагающая DHCP клиенту DNS
Длина опции
4
Dec
1
Значение опции
8.8.8.8
Строка
4
Номер опции
51
Dec
1
Время жизни выданных сетевых параметров в секундах, через которое DHCP клиент должен запросить их снова
Длина опции
4
Dec
1
Значение опции
86400
Dec
4
Номер опции
82
Dec
1
Опция 82, повторяет то что пришло в DHCPDISCOVER
Длина опции
18
Dec
1
Значение опции
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18
Окончание пакета
255
Dec
1
255 символизирует окончание пакета
Установка
Установка фактически заключается в установке модулей python необходимых для работы. Предполагается что MySQL уже установлена и настроена.
Создаем БД MySQL, заливаем в неё дамп pydhcp.sql, настраиваем файл конфигурации.
Конфигурация
Все настройки сервера лежат в файле формата xml. Эталонный файл:
<?xml version="1.0" ?>
<config>
<dhcpserver>
<host>0.0.0.0</host>
<broadcast>255.255.255.255</broadcast>
<DHCPServer>192.168.0.71</DHCPServer>
<LeaseTime>8600</LeaseTime>
<ThreadLimit>1</ThreadLimit>
<defaultMask>255.255.255.0</defaultMask>
<defaultRouter>192.168.0.1</defaultRouter>
<defaultDNS>8.8.8.8</defaultDNS>
</dhcpserver>
<mysql>
<host>localhost</host>
<username>test</username>
<password>test</password>
<basename>pydhcp</basename>
</mysql>
<options>
<option>option_82_hex:sw_port1:20:22</option>
<option>option_82_hex:sw_port2:16:18</option>
<option>option_82_hex:sw_mac:26:40</option>
</options>
<query>
<offer_count>3</offer_count>
<offer_1>select ip,mask,router,dns from users where upper(mac)=upper('{option_82_AgentRemoteId_hex}') and upper(port)=upper('{option_82_AgentCircuitId_port_hex}')</offer_1>
<offer_2>select ip,mask,router,dns from users where upper(mac)=upper('{sw_mac}') and upper(port)=upper('{sw_port2}')</offer_2>
<offer_3>select ip,mask,router,dns from users where upper(mac)=upper('{ClientMacAddress}')</offer_3>
<history_sql>insert into history (id,dt,mac,ip,comment) values (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')</history_sql>
</query>
</config>
Теперь поподробнее по тегам:
Секция dhcpserver описывает основные настройки для запуска сервера, а именно:
host — какой ip адрес слушает сервер на порту 67
broadcast — какой ip является бродкастом для DHCPOFFER и DHCPACK
DHCPServer — какой ip у DHCP сервера
LeaseTime время аренды выданного ip адреса
ThreadLimit — сколько одновременно потоков запущено по обработке поступивших пакетов UDP на порту 67. Предполагается что поможет на высоконагруженных проектах 😉
defaultMask,defaultRouter,defaultDNS — то что предлагается абоненту по умолчанию, если IP в базе найден, но дополнительные параметры для него не указаны
Секция mysql:
host,username,password,basename — всё говорит само за себя. Примерная структура базы данных выложена на GitHub
Секция query: здесь описываются запросы для получения OFFER/ACK:
offer_count — количество строк с запросами которые возвращают результат вида ip,mask,router,dns
offer_n — строка запроса. Если возврат — пусто, то выполняет следующий запрос offer
history_sql — запрос пишуший например в «историю авторизации» по абоненту
В запросах могут участвовать любые переменные из секции options или опции из протокола DHCP.
Секция options. Вот тут уже интереснее. Тут мы можем создавать переменные которые можем использовать в дальнейшем в секции query.
Например:
option_82_hex:sw_port1:20:22
, эта строчка-команда взять всю строку пришедшую в DHCP запросе опции 82, в формате hex, в диапазоне с 20 по 22 байт фключительно и положить её в новую переменную sw_port1 (порт свича откуда пришел запрос)
option_82_hex:sw_mac:26:40
, опеределяем переменную sw_mac, взяв hex из диапазона 26:40
Увидеть все возможные опции которые можно использовать в запросах, можно при помощи запуска сервера с ключем -d. Увидим примерно такой лог:
Соответственно мы можем любую переменную обернуть в {} и она будет использована в SQL запросе.
Запечатлим для истории, что IP адрес клиент получил:
Запуск сервера
./pydhcpdb.py -d -c config.xml
— d режим вывода в консоль DEBUG
— c <имя_файла> конфигурационный файл
Разбор полетов
А теперь подробнее по реализации сервера на Python. Это боль. Python изучался «на лету». Многие моменты сделаны в стиле: «ухты, как-то сделал что работает». Совсем не оптимизированны, и оставлены в таком виде в основном из-за малого опыта разработки на python. Остановлюсь на наиболее интересных моментах реализации сервера в «коде».
Парсер файла конфигурации XML
Используется стандартный модуль Python xml.dom. Вроде бы и просто, но при реализации ощутимо не хватало толковой документации и примеров в сети с использованием данного модуля.
tree = minidom.parse(gconfig["config_file"])
mconfig=tree.getElementsByTagName("mysql")
for elem in mconfig:
gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data
gconfig["mysql_username"]=elem.getElementsByTagName("username")[0].firstChild.data
gconfig["mysql_password"]=elem.getElementsByTagName("password")[0].firstChild.data
gconfig["mysql_basename"]=elem.getElementsByTagName("basename")[0].firstChild.data
dconfig=tree.getElementsByTagName("dhcpserver")
for elem in dconfig:
gconfig["broadcast"]=elem.getElementsByTagName("broadcast")[0].firstChild.data
gconfig["dhcp_host"]=elem.getElementsByTagName("host")[0].firstChild.data
gconfig["dhcp_LeaseTime"]=elem.getElementsByTagName("LeaseTime")[0].firstChild.data
gconfig["dhcp_ThreadLimit"]=int(elem.getElementsByTagName("ThreadLimit")[0].firstChild.data)
gconfig["dhcp_Server"]=elem.getElementsByTagName("DHCPServer")[0].firstChild.data
gconfig["dhcp_defaultMask"]=elem.getElementsByTagName("defaultMask")[0].firstChild.data
gconfig["dhcp_defaultRouter"]=elem.getElementsByTagName("defaultRouter")[0].firstChild.data
gconfig["dhcp_defaultDNS"]=elem.getElementsByTagName("defaultDNS")[0].firstChild.data
qconfig=tree.getElementsByTagName("query")
for elem in qconfig:
gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data
for num in range(int(gconfig["offer_count"])):
gconfig["offer_"+str(num+1)]=elem.getElementsByTagName("offer_"+str(num+1))[0].firstChild.data
gconfig["history_sql"]=elem.getElementsByTagName("history_sql")[0].firstChild.data
options=tree.getElementsByTagName("options")
for elem in options:
node=elem.getElementsByTagName("option")
for options in node:
optionsMod.append(options.firstChild.data)
Многопоточность
Как ни странно, многопоточность в Python реализована очень понятно и просто.
def PacketWork(data,addr):
...
# реализация разбора пришедшего пакета, и ответа на него
...
while True:
data, addr = udp_socket.recvfrom(1024) # ждем пакет UDP
thread = threading.Thread(target=PacketWork, args=(data,addr,)).start() # как пришел - запускаем в фоне определенную ранее функцию PacketWork с параметрами
while threading.active_count() >gconfig["dhcp_ThreadLimit"]:
time.sleep(1) # если число уже запущеных потоков больше чем в настройках, ждем пока их станет меньше
Прием/отправка пакета DHCP
Для того чтобы перехватить пакеты UDP идущие через сетевую карту, нужно «поднять» сокет:
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 — т.е. то что нам собственно и нужно, чтобы понять структуру пакета. Так например можно получить диапазон байт в HEX и просто байтах: