Dynamic DNS Server своими руками
kayo — Вс, 19/12/2010 - 02:57
Понадобилось мне как-то на своём сервере DNS обеспечить функциональность подобную dyndns.com, однако почти сразу выяснилось, что сервера как такового в свободном доступе не сыскать. Побродив по сети, нашёл кое-какие решения вроде этого, однако некоторая брутальность подхода и сложность реализации мне сразу не понравилась.
На сервере работает bind9, и для него, разумеется, существует решение, позволяющие динамически обновлять доменные записи с удалённых клиентов. Однако сводится оно к использованию продвинутого метода nsupdate, который не поддерживается средненьким сетевым оборудованием не промышленного уровня, а в частности моим домашним маршрутизатором. Поэтому лучшим решением, на мой взгляд, было иметь сервер, протокольно совместимый с ddclient, который есть почти во всех ныне существующих сетевых устройствах.
Кое-какие вводные слова
Итак, бегло глянув спеки, Кайо подумал, что реализация подобной приблуды - весьма простая задача. Вот некоторые размышления, которые привели к описываемому в статье решению:
Идея первая. Менять записи напрямую было бы относительно сложно и небезопасно, гораздо лучше использовать для этого nsupdate, который по сути принимает на вход файл изменений и последовательно применяет имеющиеся в нём команды. При этом нет необходимости передёргивать сам bind, чтобы изменения вступили в силу.
Идея вторая. Мне не очень хотелось реализовывать авторизацию пользователей, было решено воспользоваться помощью WEB-сервера. Пользователи хранятся в файле htpasswd, используемом обычно для базовой авторизации по HTTP.
Идея третья. Для обеспечения безопасности сервис должен работать под своим пользователем в роли FastCGI backend-а, на который будет ссылаться WEB-сервер при появлении ожидаемого запроса. Сервису будут доступны ключи авторизации пользователей для запуска nsupdate, которые не будут доступны другим.
Идея четвёртая. Для администрирования пользователей в этой реализации решено было написать небольшой скрипт, который автоматически генерирует ключи, а также обновляет базу пользователей и список ключей bind.
Динамически обновляемые зоны в bind9
Перед тем, как перейти к описанию установки и настройки сервиса, хотелось бы рассказать, как работает nsupdate и bind.
Создаём ключи
Итак, первое, что нам потребуется сделать, настроить зоны, которые мы бы хотели обновлять динамически. Утилита nsupdate взаимодействует с bind используя ключи, поэтому сейчас мы должны генерировать ключ примерно таким образом:
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST ddserver
Здесь мы указали тип ключа (hmac-md5), длину (512, можно в принципе использовать любую для этого типа ключа от 1 до 512) и пользователя (ddserver).
По завершении у нас будет пара ключей: публичный и приватный, у меня получились такие:
Kddserver.+157+47946.key Kddserver.+157+47946.private
Далее нам потребуется хеш (всё, что находится после числа 157 в файле .key) из публичного ключа для добавления его в конфигурацию сервера.
Создадим файл /etc/bind/ddserver.conf со следующим содержимым:
key ddserver { algorithm hmac-md5; secret "<ваш ключ>"; };
Далее включим его в /etc/bind/named.conf.local (Кайо добавил строку перед описанием доменных зон):
include "/etc/bind/ddserver.conf";
Теперь передёргиваем bind9:
sudo invoke-rc.d bind9 reload
Настраиваем доступ
Почти всё, однако мы ещё не дали разрешения на динамическое обновление конкретных зон, поэтому делаем следующее: находим описание нужной зоны, и добавляем в неё разрешение на обновление соответствующему ключу:
zone "illumium.org" { type master; file "illumium.org"; allow-update { key ddserver; }; };
Этого в общем-то будет достаточно, но так мы дали слишком много возможностей клиенту с ключом ddserver. Можно определиться более конкретно, какие обновления позволено делать, например добавив следующую директиву вместо блока allow-update:
update-policy { grant ddserver name kayo-home.illumium.org. A; };
Тем самым мы позволили обновлять лишь A запись только для поддомена kayo-home.illumium.org.
Чтобы излишне не загромождать статью, Кайо не рассматривает здесь обновление обратных зон, однако суть практически та же.
Тестируем обновление зоны
Итак, воспользуемся nsupdate для обновления нашего поддомена. Чтобы обновить некоторую A-запись, нужно сперва удалить её, затем добавить снова уже с нужным IP-адресом. Создадим файл update.ns с таким содержимым:
zone illumium.org update delete kayo-home.illumium.org. A update add kayo-home.illumium.org. 60 IN A 1.2.3.4 send
Добавляем запись A-типа kayo-home.illumium.org с IP 1.2.3.4 и TTL 60 секунд. Время жизни TTL указывать необходимо, чем оно больше, тем дольше запись будет оставаться в кешах DNS серверов. К примеру, если указать 600 (10 минут), запись в течении 10 минут не будет запрашиваться снова, и если в течении этого времени IP обновится, об этом станет известно только спустя указанный интервал.
Теперь собственно пробуем обновить (делать это можно с любого хоста, где есть nsupdate и доступен созданный нами ранее приватный ключ):
nsupdate -k Kddserver.+157+47946.private -v update.ns
Смотрим syslog на сервере в момент запуска команды, должны появиться записи вида:
updating zone 'illumium.org/IN': deleting rrset at 'kayo-home.illumium.org' A updating zone 'illumium.org/IN': adding an RR at 'kayo-home.illumium.org' A
При этом по завершении nsupdate не должен ничего выдать на stdout и stderr. Если вы не верно определили привилегии, утилита скажет, что обновление не удалось. Так что теперь чтобы убедиться, что мы не может таким образом обновлять другие записи, пробуем изменить имя в update.ns и заново вызвать nsupdate, если всё настроено, как описано у меня, получаем следующее:
update failed: REFUSED
А в syslog на сервере bind скажет вот что:
updating zone 'illumium.org/IN': update failed: rejected by secure update (REFUSED)
DynDNS Server совместимый с протоколом dyndns2
Кайо разработал ddserver как FastCGI backend. Софт написан на C и запускается как демон под непривилегированным пользователем, которому позволено находить ключи пользователей и запускать nsupdate. Проект разместил на SF.Net. Там же лежат готовые пакеты для Debian. В общем, хотелось проще, получилось как всегда ^_~
Краткое описание протокола
Обновление доменных записей dyndns2 происходит посредством HTTP GET запроса. Сперва клиент определяет свой текущий IP адрес. Это он может делать разными способами: например запросить у ADSL модема или через WEB (http://checkip.dyndns.com и подобные). В случае, если текущий IP клиента изменился, он должен сделать запрос на обновление записей, который в простейшем случае выглядит следующим образом:
http://<пользователь>:<пароль>@dyndns-server.dom/nic/update?hostname=<домен>&myip=<IP>
Доменные имена должны быть представлены в полном формате, но без завершающей точки. В случае, если доменных имён несколько, они должны быть перечислены через запятую.
Управление пользователями
Для администрирования пользователей был написан скрипт ddserver-admin, делает он следующее:
- ddserver-admin user-list - выводит список существующих пользователей
- ddserver-admin user-add <username> - добавляет нового пользователя или обновляет существующего
- ddserver-admin user-del <username> - удаляет существующего пользователя
При добавлении и обновлении пользователя потребуется ввести пароль для доступа через WEB. Скрипт автоматически генерирует нужные ключи и обновляет htpasswd файл соответствующей утилитой из apache. Имя пользователя будет названием ключа для bind.
В директории /etc/ddserver у нас будут два файла:
- named.conf - содержит ключи, потребуется включить в конфиг bind-а директивой include с указанием полного пути
- htpasswd - потребуется указать WEB-серверу для обеспечения авторизации пользователей
Разграничение доступа
Чтобы не дублировать документацию и много не писать здесь, приведу лишь некоторые примеры настройки автоматически обновляемых зон:
zone "site1.dom" { type master; file "site1.dom"; allow-update { key user1; // user1 может обновлять любые записи в зоне site1.dom }; }; zone "site2.dom" { type master; file "site2.dom"; update-policy { grant user2 name user2.site2.dom. A; // user2 может обновлять только A запись поддомен user2.site2.dom в зоне site2.dom grant user3 subdomain site2.dom. A; // user3 может обновлять любые A записи поддомены site2.dom grant user4 wildcard *u4.site2.dom.; // user4 может обновлять записи, соответствующие шаблону *u4.site2.dom }; };
Важно иметь ввиду также значения TTL в файлах описания зон, чтобы снизить время нахождения динамических записей в кешах серверов имён.
Настройка обновления через WEB в Nginx
Поскольку Кайо использует Nginx, здесь будет рассказано, как настроить работу сервиса в качестве FastCGI backend-а к нему. Перейдём сразу к примеру конфигурации, который довольно прост и практически не требует пояснений:
# DDServer server config.. server { listen 80; server_name ddns.yourdomain.dom; // Указываем по какому адресу будет доступен сервис location /nic/update { auth_basic "badauth"; // Требуем базовую авторизацию auth_basic_user_file /etc/ddserver/htpasswd; // Указываем файл пользователей access_log off; // Запрещаем логи fastcgi_pass 127.0.0.1:7111; // Определяем способ связи с backend-ом fastcgi_param REMOTE_USER $remote_user; // Заботимся об отправке имени пользователя в качестве переменной среды REMOTE_USER include fastcgi_params; // Включаем другие параметры } }
Статус проекта
Пока проект находится в стадии активного тестирования, так что могут возникнуть проблемы.
В данный момент поддерживается:
- обновление A-записей
- обновление нескольких имён за раз (с одинаковым IP)
Не поддерживается:
- обновление MX записей
- автообновление обратных зон

ddserever 0.0.2a имеет
Гость (не проверено) — Пт, 28/01/2011 - 09:53ddserever 0.0.2a имеет зависимость от libfcgi0ldbl и папки /etc/ddserver/keys, поэтому перед установкой:
Спасибо за верное замечание
kayo — Сб, 05/02/2011 - 15:22еще в
Гость (не проверено) — Пт, 28/01/2011 - 10:06С доступом туда со стороны
kayo — Сб, 05/02/2011 - 15:29Пожалуй единственный
Гость (не проверено) — Вс, 06/01/2013 - 00:45Пожалуй единственный вменяемый проект такого типа! Спасибо большое! Планируете развивать далее, добавить функционал?
Написал ebuild для gentoo - http://portage.org.ua/portage/net-dns/ddserver/
Конечно, если появятся
kayo — Пнд, 01/04/2013 - 14:45На Апаче разве нельзя
Artem (не проверено) — Чт, 23/07/2015 - 01:55Можно, то можно. Только
kayo — Ср, 12/08/2015 - 22:15А не подскажите, на чем лучше
Round (не проверено) — Вс, 22/04/2018 - 21:19А не подскажите, на чем лучше сделать свой сервер днс чтобы для всех доменных зон? Кэширующий и высокопроизводительный. 20000-50000 запросов в секунду, причем разных доменов. Но кэш все равно необходимо собирать и складировать - в идеале - в бд (понимаю что там будут миллионы строк). Ну... и при таком объеме полагаю понадобится база днсок, и софт, соответственно должен использовать их случайно.
Под ubuntu ту же...
Благодарю!
Ну вообще на Rust есть
kayo — Вс, 22/04/2018 - 21:32Ну вообще на Rust есть полностью асинхронный высокопроизводительный сервер из проекта trust-dns: trust-dns-server.
Возможно потребуется немного подрехтовать под конкретные задачи, но думаю лучше решения не найти.
Отправить комментарий