Понадобилось реализовать управление выдачей IP в сети одного провайдера, увязав его с системой учёта и прочими «фишками». В качестве DHCP сервера стоял ISC DHCP 4.x на 9-м Ubuntu Server'е.
Для DHCPd нужно было реализовать:
Хочу поделиться информацией, собранной в процессе реализации, на какие подводные камни наткнулся, как обходил, что так и не обошёл. Возможно кому-то сэкономит несколько часов времени.
Сразу оговорюсь: данный пост ни в коем случае не является истиной в последней инстанции, указанием на единственно верное решение, да и вообще какой-либо инструкцией. Это всего лишь некий набор рабочей информации. Использовать её или нет, верить ей или нет, а так же как решать ту или иную задачу — пусть каждый решает сам в контексте его ситуации. Мои варианты решений оказались удобны мне в моём случае, но не более того. Итак:
Далее, как я решил некоторые подзадачи в моём случае:
Для DHCPd нужно было реализовать:
- добавление новой статичной резервации (по маку либо порту свитча — опция 82),
- «привязка» юзера с IP выданным динамически (то есть из пула свободных IP) в статичную резервацию
- удаление статичной резервации
- удаление динамической лизы до истечения срока резервации
- Различные отчёты по подсетям, мак-адресам, свободным и занятым аресам
Хочу поделиться информацией, собранной в процессе реализации, на какие подводные камни наткнулся, как обходил, что так и не обошёл. Возможно кому-то сэкономит несколько часов времени.
Сразу оговорюсь: данный пост ни в коем случае не является истиной в последней инстанции, указанием на единственно верное решение, да и вообще какой-либо инструкцией. Это всего лишь некий набор рабочей информации. Использовать её или нет, верить ей или нет, а так же как решать ту или иную задачу — пусть каждый решает сам в контексте его ситуации. Мои варианты решений оказались удобны мне в моём случае, но не более того. Итак:
- ISC DHCPd не поддерживает и в обозримом будущем не будет поддерживать обновление конфига по SIGHUP или какому-то ещё сигналу. По их заверениям это «требует слишком серьёзной работы, на которую у них нет и не предвидится времени»
- Вся статичная конфинурация хранится в dhcpd.conf, вся динамическая dhcpd.leases. При чём сначала пишется lease, делается flush на диск, и только после этого посылается ответ клиенту. Вместе эти два файла содержат всю необходимую информацию, чтобы при рестарте сервер вернулся точно в то же состояние, в каком он был до этого.
- Если dhcpd делает что-то, что прописано в конфиге и не предполагает никаких вариаций, конфликтов (например статические резервации IP по MAC'у) — в dhcpd.leases ничего не пишется.
- Как следствие — единственный способ проследить когда последний раз выдавался некий IP статично привязанный к MAC'у — анализ логов: dhcpd.leases этой информации не содержит, в конфиг сервер тоже ничего не пишет.
- dhcpd имеет свой API через который теоретически можно управлять сервером в real-time. А так же command-line утилитку omshell, использующую этот API. Через неё теоретически можно управлять сервером без даун-тайма. К тому же она поддерживает возможность подать последовательность команд на STDIN, что делает её довольно удобным инструментом для многих задач. Все данные пишутся в dhcp.leases, конфиг не трогают.
- В omshell нет возможности получить списки чего-либо. Вся работа идёт с 1 уникальным объектом. Для получения списков придётся парсить файлы конфига/leases.
- omshell не поддерживает удаление имеющейся lease, говорит «not implemented». Кроме того во время одного из тестов поломался файл dhcp.leases (появился какой-то странный мусор внутри) и dhcpd из-за этого не перезапускался. Воспроизвести ситуацию не удалось, но решил не рисковать и оставил omshell в покое.
- В 4-й версии нет возможности контроллировать порядок динамической выдачи адресов из нескольких подсетей shared-network'а. Вариант типа выдавать публичные адреса для всех клиентов из основной сети и приватные с NAT-ом из другой только, если в основной сети в данный момент свободных не осталось больше не работает. Будет выдаваться из обеих в порядке, удобном dhcpd.
- Привязка ip-mac значит только, что этому маку будет выдан этот IP, если он попросит и IP будет свободен. Но при этом этот IP может быть выдан ещё кому-то, если на данный момент свободен, находится в pool'e где разрешено выдавать IP не прописанным статически клиентам и свободных адресов недостаточно.
- Мне не удалось найти ни одного готового внятно работающего инструмента, способного управлять isc dhcd 4.x из под web'a и мало-мальски расширяемого. Всё что есть более менее работоспособного — сделано под 3-ю версию.
- Я не нашёл ни одного реализованного в полной мере проекта подключения SQL как бекенда для хранения dhcpd.conf и dhcpd.leases. Все виденные мною проекты пересоздают конфиг, читают и пишут dhcpd.leases и перезапускают dhcpd
Далее, как я решил некоторые подзадачи в моём случае:
- Удаление уже выданной lease решил посредством дописывания в конец dhcpd.leases копии требуемой лизы, заменив в ней «binding state active» на «bindng state free» и рестартом dhcpd. Сервер читает dhcpd.leases по порядку и записи встречающиеся позже оверрайдят предыдущие.
- Данные хранил в MySQL, при изменениях перегенерил конфиг и перезапускал dhcpd.
- Занятые на данный момент адреса получал прочитав dhcpd.leases (как упоминалось выше, его содержимое всегда актуально, файл легко разбирается регекспами) + из базы: всё чего нет ни в файле в статусе 'active', ни в базе — считается свободным.
- Привязку IP к порту свича комбинацией класса и pool'a как в этом примере:
... класс задается по IP cвича и номеру порта ...
class "172.16.16.227:4" {
match if concat(
binary-to-ascii(10,8,".",packet(24,4)),":",binary-to-ascii(10,8,"",suffix(option agent.circuit-id,1))) = "172.16.16.227:4";
}
...
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1;
... другие опции...
pool { range 192.168.1.3; allow members of "172.16.16.227:4"; } # bind ip to port
pool { #static bindings
range 192.168.1.2; range 192.168.1.4; range 192.168.1.5;
.... тут продолжается список занятых под разные нужды IP в этой сети, КРОМЕ тех что на портах свичей ...
deny unknown-clients;
}
pool { #free IPs
range 192.168.1.6; range 192.168.1.8; range 192.168.1.15;
.... тут продолжается список cвободных IP в этой сети ...
allow unknown-clients;
}
}