На главную

Life With djbdns

Henning Brauer <lists-lwd@bsws.de>
11 August 2005

Жизнь с djbdns.

М. Альхименко (перевод), lithium.opennet.ru
1 июня 2006


Оригинал документа находится по адресу http://www.lifewithdjbdns.org/. Поскольку переводчик не занимается этой работой профессионально, возможны неточности и ошибки — исправления приветствуются. В некоторых местах в скобках указанные исходные термины, т.к. общепринятого перевода некоторых слов найти не удалось ("resolver") или более привычен оригинальный вариант ("name server", "split horizon"). Вы всегда можете изменить текст в своем любмом редакторе как вам нравится и/или прислать автору перевода свои соображения. Примечания переводчика выделены в тексте курсивом. По вопросам перевода обращайтесь на articles <at> lithium.opennet.ru, по вопросам содержания — к автору. Оригинал (и самая последняя версия) этого документа находится на http://lithium.opennet.ru. Автор перевода выражает признательность knops и радистке Кэт за помощь в работе над текстом.

Содержание


1. Введение

Этот документ, возможно, никогда не будет таким всесторонне полезным, как его вдохновитель, Life With Qmail Dave'а Sill'а, но в то же время djbdns не настолько сложен, как qmail (он делает намного более простую работу), поэтому может что-то и получится.

djbdns — набор простых программ для обслуживания и разрешения (resolving) данных DNS. Он предназначен для замены BIND во многих ситуациях, несмотря на то, что он пока еще не включает в себя всех функций BIND, и, возможно, никогда и не будет; djbdns содержит возможности, которые действительно необходимы, также есть некоторые функции, существующие в BIND, которые не были реализованы. Также как и qmail, особенно в его младшем возрасте, djbdns нуждается в некоторой доработке для развертывания.

Этот документ попробует представить развернутую картину (Big Picture), которой вам будет достаточно, чтобы начать действовать; охарактеризует компоненты djbdns и как они соотносятся друг с другом; снабдит описаниями типичных вариантов установок; и, будем надеяться, ответит на некоторые часто задаваемые вопросы; но он не позиционируется как замена всех существующих FAQ; это вводный документ для последовательного чтения, а не справочник.

"Life with djbdns" был начат Bennett'ом Todd'ом <bet@rahul.net> который написал значительные части этого документа. Без его колоссального объема работы и его опыта этот документ не был бы тем, чем является в настоящий момент.


2. Переводы

Испанский

Русский


3. Другие ресурсы

Официальная страница djbdns Dan'а Bernstein'а

www.djbdns.org

Существует также список рассылки dns@list.cr.yp.to. Подписаться на него можно, отослав пустое сообщение на dns-subscribe@list.cr.yp.to, отписка работает так же: отошлите пустое сообщение на dns-unsubscribe@list.cr.yp.to.


4. The Big Picture

Служба доменных имен (DNS) — распределенная база данных, поддерживающая делегирование полномочий для сегментов ключевого пространства. DNS в основном используется для преобразования имен узлов в IPv4-адреса; также DNS предлагает преобразование адресов в имена, информацию об узлах, специальную информацию для поддержки маршрутизации почты и бесчисленное множество более экзотических применений, зависящих от приложений. DNS использует некоторые внутренние типы записей, чтобы определить свою собственную иерархическую структуру, для делегирования поддоменов; также, существуют функции поддержки IPv6.

Как и в любой другой сложной системе, которая хорошо делает сложную работу, в DNS существует специальный жаргон и определенный набор понятий, с помощью которых описываются принципы этой системы. С некоторыми важными понятиями я попробую вас познакомить.

DNS состоит из группы серверов, передающих записи ресурсов (Resource Records, RRs) (далее в тексте просто "записи"). Существует много типов записей и несколько разных протоколов для их запроса. Для DNS транспортом служат как TCP, так и UDP, оба через 53 порт. Большинство обычных запросов выполняется по UDP. TCP используется когда общий размер всех записей в ответе превышает 512 байт, или при осуществлении зонных пересылок ("zone transfers").

4.1. Распознаватели (resolvers) и сервера имен: определения

Авторы стандартов DNS (RFCs 1034, 1035 и их многочисленных преемников) создавали их на основе модели, которая следовала за Berkeley Internet Name Daemon (BIND); эта модель включает точку зрения, что все сервера на самом деле основываются на том же коде и содержат условные обозначения зонных файлов, которые использует BIND. К сожалению, дизайн BIND, представленный в документах RFC, содержал изрядное количество нежелательных сложностей и также внушал опасения по поводу безопасности; дизайн djbdns основан на более простой модели, которую я опишу. Это также породило небольшое количество проблем с терминологией: существуют отдельные роли, которые может брать на себя DNS-сервер и которые нельзя разделить в традиционном жаргоне DNS, потому что BIND исполняет их все; поскольку они (роли) отделены в djbdns, важно дать им четкие имена. Я буду назвать термином "библиотека распознавателя" ("resolver library") библиотечную процедуру, которую клиентские программы используют для разрешения имен; термином "рекурсивный распознаватель" ("recursive resolver") — вспомогательный демон, который посылает DNS-запросы, и термином "полномочные сервера имен" ("authoritative nameservers") — конечные авторитетные источники (authorities), которые являются завершающими источниками информации. Эти определения очень многословны, но, пожалуйста, будьте терпеливы; при всей их скучной многословности они позволяют сделать две вещи: во-первых, они точно описывают выполняемые функции, и во-вторых, они разумно совместимы с традиционно используемыми терминами.

4.2. Типы запросов DNS

Существуют две различных разновидности DNS-запросов, которые могут быть отправлены, различающиеся битом с названием Recursion Desired (ожидание рекурсии) или RD-битом. Рекурсивные запросы, в которых этот бит установлен, обычно отсылаются прикладными программами, используя процедуры в системных библиотеках вроде gethostbyname(3). Их обычно посылают серверу, адрес которого был найден просмотром файла /etc/resolv.conf для поиска используемых в системе серверов имен (nameservers). Рекурсивный запрос просит сервер сделать все возможное, чтобы ответить на этот запрос, включая рекурсивный опрос всех необходимых сторонних серверов имен, чтобы разыскать ответ, т.е. имя. Ответ на рекурсивный запрос должен быть или окончательным ответом на вопрос, или окончательным заключением, что ответ не может быть найден.

Другой типа запроса — нерекурсивный (non-recursive) запрос, также называемый итеративным запросом; он обычно посылается программой, которая выступает в роли рекурсивного распознавателя (recursive resolver); например, программой, слушающей 53 порт на адресе, который клиенты находят в /etc/resolv.conf. Таким образом, клиент, который хочет найти IP-адрес для имени хоста или имя хоста для IP-адреса или собирается задать какой-то другой вопрос DNS-системе, смотрит адрес соответствующего рекурсивного распознавателя (recursive resolver) в /etc/resolv.conf и посылает ему рекурсивный запрос с установленным RD-битом; эта функциональность расположена в gethostbyname(3) и gethostbyaddr(3). Тогда рекурсивный распознаватель (recursive resolver) начинает процесс поиска актуальной запрошенной информации от имени пользователя довольно умным (т.е. комплексным) способом, используя группу итеративных запросов (с пустым (cleared) RD-битом). Эти итеративные запросы не просят сервер (в данном случае полномочный сервер имен (authoritative nameserver)) розыскать (отследить до конца) ответы для этих и будущих вопросов, они просто просят сервер ответить на вопрос или сказать, кто может быть ближе к знанию ответа (closer to knowing the answer).

Таким образом, в том случае, когда рекурсивный запрос для www.example.com может получить в ответ IP-адрес или окончательное заключение, что такого имени не существует, итеративный запрос может получить в ответ список серверов имен, которые можно попробовать использовать для дальнейшего поиска ответа.

4.3. Структура доменных имен

Доменные имена — это обозначения для узлов в древовидной структуре. Корень (root) дерева доменных имен — это ".", несмотря на то, что корень обычно не пишется в доменных именах. Доменное имя может быть вполне нормально записано как "www.example.com", но абсолютная версия доменного имени — "www.example.com.".

Обычно пользователям не нужно писать имена в такой форме, и вы также не нуждаетесь в завершающей точке когда конфигурируете djbdns, но это может быть полезно знать во время тестирования DNS; путем явного использования завершающей "." вы можете предотвратить попытки библиотек распознавателя (resolver libraries) добавить локальное доменное имя (суффикс), как это сконфигурировано директивой "search" в /etc/resolv.conf. Таким образом, если ваше доменное имя "foo.bar" и вы спрашиваете об имени "www.example.com", ваш браузер может (это зависит от особенностей вашей локальной библиотеки) попробовать искать "www.example.com.foo.bar" перед тем, как сделать попытку найти "www.example.com"; если взамен вы сделаете запрос "www.example.com.", дополнительная проверка определенно не будет производиться.

Древовидная структура пространства имен DNS отражена в древовидной структуре полномочных серверов имен (authoritative nameservers). Корневые сервера имен (root nameservers), адреса которых сконфигурированы в каждом рекурсивном распознавателе (recursive resolver), чтобы "залить насос" (под "prime the pump" здесь имеется в виду процедура заливки воды в насос перед работой, чтобы его запустить), оказываются в корне дерева полномочий; связи внутри дерева следуют за делегированием полномочий.

Эти корневые сервера могут авторитетно (authoritatively) сказать, какие сервера имен содержат данные для различных доменов непосредственно под "." (дерево доменных имен обычно изображается перевернутым, т.е. корневая зона расположена вверху, от неё идет ссылки вниз к нижележащим доменам), например, "com", "net", "edu", "org" и многим другим доменам второго уровня для различных стран.

4.3.1. Основные типы записей ресурсов (Resource Record Types)

DNS поддерживает множество типов записей ресурсов (resource record types). Полдюжина, или около того, будет использоваться почти каждым. Они будут более подробно описаны ниже. Но без трех типов записей мы не можем рассмотреть самую простую иллюстрацию, так что давайте сделаем это здесь:

    A   Запись для хоста (Address), сообщает IP-адрес по имени узла (hostname)

    NS  запись делегирования, определяет доменное имя сервера имен (NameServer),
        предназначенного для осуществления поиска дополнительной  информации в домене

    PTR запись указателя (PoinTeR), устанавливает соответствие одного доменного 
        имени другому, обычно используется для обратного поиска (reverse-lookup),
        чтобы транслировать IP-адрес обратно в имя хоста (hostname)

4.3.2. Пример: поиск IP-адреса www.example.com

Когда клиент хочет разрешить адрес www.example.com., он посылает рекурсивный запрос для A-записи (с установленным RD-битом) рекурсивному распознавателю (to recursive resolver), чей адрес он нашел, просматривая /etc/resolv.conf. Если все проходит нормально, он [в конечном итоге] получит назад ответ.

Распознаватель (resolver), получив от клиента запрос, начинает долгоиграющий процесс поиска ответа. На деле это обычно происходит довольно быстро, т.к. распознаватели (resolvers) разумно кэшируют ответы на предыдущие запросы, и поэтому зачастую могут отвечать на них без необходимости проходить через весь процесс поиска, через который мы сейчас пройдем.

Рекурсивный распознаватель (recursive resolver) сконфигурирован на адреса корневых полномочных серверов (root authoritative nameservers). Он начинает поиск отправкой итеративного запроса (RD-бит не установлен) для A-записи www.example.com одному из корневых полномочных серверов. Он может выбрать одного из них случайно; он может обладать собранными данными о том, как быстро они отвечали, и попробовать послать запрос тому, который, как ему кажется, ответил быстрее всех; он может использовать их попеременно; за этим — к автору распознавателя.

Итак, www.example.com, вероятно, не в сфере полномочий корневых серверов; они не знают никакого www.example.com. Но они _знают_ список серверов, полномочных для com.; фактически, они знают любой сервер, который полномочен для доменов верхнего уровня (top level domain, TLD) — это точное определение корневого сервера имен.

Таким образом, полномочный корневой сервер имен отсылает назад ответ, который говорит: "Сожалею, я не знаю www.example.com, но вот они — полномочные сервера для "com", и да, кстати, вот их IP-адреса". Так как распознаватель, так или иначе, немедленно спросил бы об IP-адресах [NS-серверов], А-записи, сопоставляющие IP-адреса с именами хостов NS-серверов верхнего уровня зоны ".com" были включены в ответ вместе со всеми NS-записями, задающими делегирование зоны ".com" этим серверам. Эти дополнительные A-записи названы "связывающими записями"("glue records"), запомните их, они важны для понимания, как лучше создавать data-файлы для djbdns. (Здесь и далее под термином "data-файл" подразумевается файл с именем "data", в котором tinydns хранит содержимое зон.)

Итак, теперь рекурсивный распознаватель знает, кто ответит на вопросы, которые заканчиваются на com., и он знает их адреса. Теперь он выбирает одного из них (как описано выше) и посылает точно такой же запрос, какой посылал ранее: итеративный (RD-бит не установлен) запрос A-записи для www.example.com. Также, TLD NS-сервера зоны .com, вероятно, не знают о содержимом зоны example.com, они могут предоставить информацию о зоне example.com в целом (they have their hands full just telling people about example.com as a whole) (и о любом другом домене, заканчивающемся на .com). Более важно, детали о содержимом домена example.com администрируется владельцами example.com, а не глобальными администраторами TLD серверов имен. Таким образом, опять распознаватель не получил ответа на свой вопрос, он получил NS-записи, дающие ему полномочные сервера для example.com, вместе с _их_ связывающими записями (glue records).

Немного отвлечемся от основной темы: если связывающие записи (glue records) отсутствуют, DNS все еще будет работать, но этот путь медленнее, т.к. рекурсивные распознаватели (recursive resolvers) должны вернуться и пойти узнавать A-записи для серверов имен — и очень, очень легко попасть в ловушку, где "вы не можете попасть туда отсюда", т.к. сервера имен для (например) example.com (вернее, A-записи для серверов имен) будут обычно _внутри_ example.com, так что вы не сможете найти их адреса обычным путем. Поэтому связывающие записи (glue records) важны.

Итак, теперь рекурсивный распознаватель (recursive resolver) знает, что полномочными серверами имен для example.com являются, например, "a.ns.example.com" и "b.ns.example.com" (также, это одно из типичных соглашений об именовании NS-серверов). Другие общепринятые названия — "ns1.example.com" и "ns2.example.com". Рекурсивный распознаватель (recursive resolver) выберет одного из них и отправит свой A-запрос еще один раз, и в этот раз он будет спрашивать полномочные сервера имен зоны example.com о A-записи для www.example.com, и он должен получить ответ обратно. Теперь он вернет его клиенту. Конечно, когда web browser сразу же вернется назад и спросит об адресе pics.example.com, чтобы начать загрузку картинок, сервер имен не пойдет назад к корневым серверам, так же, как и не будет надоедать TLD-серверам зоны com, он помнит, кто отвечает на вопросы о зоне example.com, и посылает свой запрос им напрямую.


5. Компоненты djbdns и как они сочетаются друг с другом

5.1. dnscache

Djbdns родился из двух наблюдений. Первое состоит в том, что много проблем безопасности BIND происходят из способа принятия решения, каким ответам доверять и какие ответы отбрасывать; связывающие записи ("glue records") работают потому, что любой ответ может содержать дополнительную информацию в себе и что большая часть любого ответа может быть подделана. Самый легкий путь решения этих проблем состоит в создании нового рекурсивного преобразователя (recursive resolver), который применяет строгие правила безопасности к вопросам, как и кого он спрашивает, и какие части ответа он будет использовать. Так родился dnscache. Это _только_ рекурсивный преобразователь (recursive resolver); в отличие от BIND, он никогда не возвращает полномочных данных (authoritative data), никогда не возвращает данные, которые не получил напрямую от полномочных серверов имен (authoritative nameserver), чьи полномочия он проверил трассировкой цепочки NS-делегирований (NS delegations) начиная с root-серверов, на которые он сконфигурирован. Для обеспечения простой гибкости он также может быть сконфигурирован с отдельными полномочными серверами имен для конкретных (определенных) доменов, эта настройка перекрывает обычный поиск через корневые сервера; это делает легкой настройку "расщепления горизонта DNS" ("split-horizon" DNS) (обсуждается далее). Dnscache имеет конфигурационные параметры для контроля размера кэша и для указания интерфейса, на котором будет слушаться порт для приема запросов.

5.2. tinydns и tinydns-data

tinydns, вполне возможно, самый простой полнофункциональный полномочный сервер имен. Он обслуживает только полномочные данные; любой запрос, на который невозможно ответить на основе данных из его дисковой базы данных (disk database), просто отбрасывается. Дисковая база данных (далее, БД) позволяет tinydns говорить, что он обладает всеобъемлющими знаниями об определенном домене; только в том случае, если это установлено (на это указывает присутствие записи "." в файле data), tinydns возвращает NXDOMAIN — официальное утверждение, что запрошенный домен не существует (Вернее, не существует запрошенная запись в домене, для которого полномочен tinydns. Другими словами, tinydns отвечает NXDOMAIN для записи только в том случае, если в файле data указано, что он полномочем для этого домена.).

tinydns читает очень маленькую и эффективную БД в cdb формате. Эта БД обладает такими характеристиками производительности, что когда она довольно активно используется (и поэтому блок заголовков в начале БД постоянно остается в кэше), любой запрос может быть обслужен двумя обращениями к диску. Для самых высокопроизводительных (highest-performance) серверов имен этого недостаточно; тем не менее, cdb-формат не слишком громоздкий для того, чтобы не позволить серверам держать рабочую БД в памяти, или с помощью использования RAM-диска, или с помощью простого обеспечения сервера достаточным количеством буферной памяти, чтобы вся БД была помещена в кэш.

БД tinydns устроена таком образом, что запрос к ней представляет собой ключ, и отклик является ответом; все реальные сведения о структурах DNS содержатся в tinydns-data — offline-программе, которая строит БД: она переводит текстовый файл "data" в двоичную БД (binary database) "data.cdb". Эта программа читает ясный (clean), простой (lean) формат, который делает очень несложной процедуру кодирования наиболее распространенных записей; со временем стало поддерживаться все большее их число. Для всех записей, специально не предусмотренных в настоящее время (not currently special-cased), существует "настраиваемый" или "общий" ("generic") формат записи, и препроцессор может быть использован для генерации любой записи, записанной в этом формате. Сведения о формате этого файла можно посмотреть в документации tinydns-data.

5.3. axfrdns

tinydns предоставляет данные через 53 порт UDP. Также, существует два случая, когда DNS нуждается в предоставлении данных через 53 порт TCP. Первый имеет место, когда ответ на запрос превышает 512 байт. В этом случае ответ усекается, устанавливается бит, указывающий на усечение, и если клиент хочет получить полный ответ, он делает запрос через TCP. Естественно, это происходит не сильно быстро, и, по большому счету, этого стоит избегать. Пока вы уверены, что не кодируете ваш файл data излишне сложным, вы не должны столкнуться с этой проблемой, если Вы не делаете что-то довольно экзотическое, например, статические round-robin DNS-записи для огромной фермы серверов или чего-то подобного. Не забывайте об известных случаях, когда сайты, имеющие обыкновение так поступать, больше не существуют; гигантские ответы DNS просто не делают это хорошо.

Другая область, где TCP используется в DNS, — зонные пересылки (zone transfers, AXFR). Зонные пересылки (zone transfers) не сильно безопасный механизм для копирования данных DNS; вместо этого лучше всего использовать что-то вроде rsync поверх ssh. Это действительно лучший подход к созданию надежной, устойчивой, эффективной и безопасной репликации между tinydns-серверами. Тем не менее, когда tinydns и другой сервер имен (например, BIND) должны обменяться полными зонами, единственное возможное решение — AXFR. Djbdns включает и функциональность и сервера (в axfrdns), и клиента AXFR (axfr-get, см. ниже). Они могут использоваться, чтобы устроить перенос зоны для репликации ("вторичные" сервера имен), а также для преобразования между форматом данных зон ВIND'а и форматом tinydns-data и обратно.

axfrdns разработан, чтобы работать рядом с tinydns, на 53-м порту TCP, предоставляя те же самые данные из того же самого файла двоичной БД (data.cdb). Он (axfrdns) работает из-под программы tcpserver, из пакета ucspi-tcp (см. ниже).

Есть два средства управления, доступные для того, чтобы ограничить то, что разрешено axfrdns. Во-первых, tcpserver предлагает ограничения, основанные на IP-адресе отправителя, которые определяются с помощью tcprules. Когда IP-адрес совпал с правилом, можно или отвергнуть соединение, или разрешить его; и если это разрешено, можно установить переменные окружения. Это позволяет использовать второй тип контроля — переменные окружения AXFR, список доменов, разделенных символом косой черты, для которых зонные пересылки будут разрешены.

Предположим, что Вы хотели позволить любому соединяться с axfrdns для того, чтобы повторно сделать запрос с большим (больше чем 512 байт) ответом, но Вы хотите позволить зонные пересылки только из example.dom (т.е. для хостов с обратными записями вида *.example.com).

        =example.dom:allow
        :allow,AXFR=""

Помните, что, так как axfrdns экспортирует данные tinydns в формат зонных пересылок, это - (между прочим) инструмент конвертирования в формат зон BIND'а

5.4. axfr-get

axfr-get — клиент переноса зоны, входящий в состав djbdns. Он запускается из-под tcpclient и записывает data-файл в формате tinydns-data.

Он может быть использован для настройки сервера tinydns как вторичного по отношению к серверу BIND. Также, он может быть использован (вместе с axfrdns) для отношений первичный-вторичный (master-slave) между серверами tinydns, но такое применение не рекомендуется; rsync поверх ssh — предпочтительней во всех отношениях, простой, производительный, безопасный метод, он выигрывает везде. Формат вывода, записанного axfr-get, имеет в качестве первой и основной цели гарантию, что любой возможный формат записи безошибочно сохранен; он возвращается к generic-формату записи всякий раз, когда это необходимо. Создание удобочитаемых и легко обслуживаемых вручную данных &mdash вторая цель этой программы. Существует несколько скриптов, доступных на домашней странице djbdns, которые могут помочь почистить данные, чтобы сделать их более приятными для сопровождения.

5.5. Программы — клиенты DNS

Djbdns включает несколько утилит для выполнения некоторых из тех задач, для которых используют программы вроде host(1), dig(1), и nslookup(8).

Далее по тексту, "FQDN" означает, что должно быть указанно полностью определенное доменное имя (fully qualified domain name), в отличие от "hostname" (т.е. указанное имя не будет содержать локальное имя домена, присоединенное к нему). Форма записи:

    команда аргументы
        -> сгенерированный вывод
        другие возможные комментарии

Это утилиты для скриптов; полезные для тестирования, но настроены для использования как строительные блоки для других программ; их вывод лишен того сорта болтовни, которая сопровождает отладку, он сокращен насколько это возможно, чтобы использовать его как ввод других программ.

    dnsip FQDN
        -> ipaddr
    dnsipq hostname
        -> FQDN ipaddr
    dnsname ipaddr
        -> FQDN
    dnsmx FQDN
        -> предпочтительный FQDN
        Если MX-записи не существует, dnsmx подделывает её с 
        предпочтением (дистанцией) равной нулю — даже
        если не существует записи любого типа (т.е. даже если 
        такого домена вообще нет). 
        dnsmx no-such-host выдает "0 no-such-host".
    dnstxt FQDN
        -> текстовая (TXT) запись, если она существует для FQDN
        пустая строка, если ничего не найдено

Далее, существуют более строгие диагностические инструменты; их вывод менее предназначен для использования в программах и более для анализа человеком, при отладке. В этих командах "type" — тип DNS-запроса, такой как "ptr", "a", "txt", "mx", "ns", "soa", или "any".

    dnsq type FQDN server
        -> отладочный вывод
        Отсылает итеративный запрос указанному серверу;
        это предпочтительное средство для тестирования tinydns.
    dnsqr type FQDN
        -> отладочный вывод
        Эта команда отсылает рекурсивный запрос, подходит для
        тестирования dnscache. Если вам необходимо переназначить
        адреса DNS-кэшей, указанных в /etc/resolv.conf, вы должны
        установить переменную окружения DNSCACHEIP:
        DNSCACHEIP=x.y.z.t dnsqr type FQDN
    dnstrace type FQDN server
        -> отладочная трассировка полного поиска
        Указанный сервер должен быть _корневым_ сервером имен;
        dnstrace начнет поиск FQDN начиная с этого сервера,
        и покажет все возможные пути поиска ответа;
        обычно это позволяет найти хост — источник проблем.

5.6. dnsfilter

Эта программа разработана для массового преобразования таких вещей, как лог-файлы; она также делает ужасающий стресс-тест для рекурсивного преобразователя (recursive resolver). Она читает строки из stdin и пишет в stdout. Если первая область строки, отделенная пробелами, похожа на IP-адрес, dnsfilter пробует сделать обратный запрос для него — для IP-адреса x.y.z.t она будет пробовать сделать PTR-запрос для t.z.y.x.in-addr.arpa. Если это пройдет успешно, полученный адрес будет добавлен к IP-адресу в строке на выходе. Эти запросы будут выполнены параллельно, опции командной строки позволят вам контролировать детали. См. документацию, чтобы узнать больше подробностей.

5.7. Специализированные сервера

В принципе, работа, которую выполняют эти сервера, могла быть сделана tinydns, но они довольно специализированны, и точно спроектированный код позволяет им делать работу лучше.

    pickdns
        Начиная с версии 1.04 pickdns больше не нужен. Теперь его функции
        выполняет tinydns.
        Полномочный сервер с балансировкой нагрузки (load-balancing 
        authoritative server), разработанный для использования DNS
        для распределения нагрузки, создаваемой клиентами, между
        несколькими серверами; включает приспособления для направления
        определенных классов клиентов на определенные подмножества
        (subsets) распределенных серверных ферм (distributed server farm)
        (т.е. попытка направить пользователей к ближайшим серверам)
    walldns
        обслуживает только общие полномочные данные DNS,
        скрывая все о зоне: для всех IP-адресов x.y.z.t действует 
        подобно (в формате tinydns-data):
                =t.z.y.x.in-addr.arpa:x.y.z.t
    rbldns
        Для обслуживания данных RBL-типа; отвечает на A, TXT, или *-запросы
        для t.z.y.x.$BASE если x.y.z.t перечислен в его data-файле,
        в котором можно определить отдельные адреса и подсети, также как
        и ответы, которые будут отосланы.

5.8. daemontools

Daemontools — сопутствующий пакет, необходимый для работы djbdns. Он предоставляет некоторые вспомогательные программы, которые помогают в запуске и управлении демонами.

    svscan делает работу, примерно подобную работе демона init
        в System V: он контролирует задания и следит за тем, 
        чтобы они оставались запущенными. Он обычно стартует  
        в каталоге /service и каждый подкаталог в этом 
        каталоге определяется как сервис; эти подкаталоги обычно
        представляют собой символические ссылки на каталоги в /etc
        (имеется в виду установка djbdns, в общем случае их размещение
        произвольно), которые, в свою очередь,
        создаются различными -conf программами (dnscache-conf, 
        tinydns-conf, и т.д).
    svc обеспечивает интерактивный интерфейс пользователя для 
        управления svscan; он принимает параметры вроде "-u" 
        для запуска, "-d" для останова или "-t" для
        остановки и последующего запуска, завершающиеся именем сервиса 
        в форме пути к контролируемому каталогу.
        В наиболее общем случае выглядит как:
                svc -t /service/dnscache
        для перезапуска dnscache, это простейший способ заставить его повторно
        собрать все данные, когда вам что-то не нравится в его кэше.
    supervise запускается svscan, чтобы следить за определенным демоном, и
        перезапустить его, если он "упадет"
    multilog читает журнальные данные (log data) из stdin, опционально 
        фильтрует их, и складывает результат в один или несколько 
        log-файлов, осуществляя их автоматическую ротацию.

5.9. ucspi-tcp

UCSPI — это Клиент-Серверный Программный Интерфейс UNIX (UNIX Client-Server Program Interface). Он определяет структуру командной строки и переменных окружения для вспомогательных программ межпроцессного взаимодействия (inter-process communications helper programs) и упрощает процесс написания клиентов и серверов.

UCSPI-TCP — это специальное подмножество UCSPI для TCP-приложений; он описывает больше подробностей о специфических переменных окружения и подобных деталях.

ucspi-tcp — это пакет UCSPI-TCP программ, написанный djb.

    tcpserver подобен inetd, только для одного сервиса. После запуска
        tcpserver будет ждать соединений на определенном порту, для 
        каждого из них он запустит клиентскую программу с аргументами, 
        указанными в командной строке tcpserver, и с переменными окружения,
        как  определно в UCSPI-TCP. Также, tcpserver реализует правила 
        контроля доступа.
    tcprules
        компилирует правила контроля доступа для tcpserver в базу данных cdb
    tcpclient
        программа, реализующая функционал клиента; позволяет сетевым 
        клиентам работать с TCP, в соответствии со спецификациями UCSPI-TCP.

6. Примеры конфигурации

Теперь приведем несколько пояснительных примеров. Они взяты из индивидуального рабочего опыта и предназначены больше для того, чтобы отразить обстоятельства, которые различные люди нашли наиболее распространенными и типовыми, чем для того, чтобы чисто и точно проиллюстрировать специфические технологии и принципы.

6.1. Простая установка

Итак, довольно теории, давайте начнем. Мы не будем здесь объяснять загрузку, компилирование, установку и добавление пользователей, вы можете найти эту информацию в Приложениях, в разделе ОС-специфичных методов. Существуют также несколько альтернативных методов инсталляции. Во-первых, вы должны решить, какие пакеты вам нужны. Обычно вам нужен dnscache, чтобы быть вашим распознавателем (resolver), и tinydns, чтобы быть вашим полномочным сервером имен. Если вам необходимо поддерживать вторичные сервера имен с BIND, вам также понадобится axfrdns (это не на 100% правда: если вы делаете некоторые паршивые хитрости (lousy tricks) и один ответ будет больше 512 байт, вам также будет необходим axfrdns (и в отсутствии BIND), но это не общепринято). После установки вам необходимо сконфигурировать и запустить ваши сервисы. Это описано ниже и зависит от использования daemontools (и ucspi-tcp, если вы используете axfrdns) в стандартном местоположении.

6.1.1. Настройка dnscache

Вам необходимо создать двух пользователей, называемых dnscache и dnslog. Из соображений безопасности убедитесь, что они не могут войти в систему.

Запустите dnscache-conf:

    dnscache-conf dnscache dnslog /etc/dnscache 1.2.3.4

где 1.2.3.4 — IP-адрес, на котром будет работать dnscache. По умолчанию log-файлы находятся в /etc/dnscache/log/main. Я не люблю иметь что-то кроме конфигурационных файлов в /etc, если вы хотите держать ваши log-файлы в /var/log/dnscache, создайте этот каталог с владельцем dnslog и замените ./main в /etc/dnscache/log/run на /var/log/dnscache.

Запустите dnscache, сообщив svscan о нем:

    ln -s /etc/dnscache /service

теперь dnscache должен запуститься в течении 5 секунд.

Если dnscache должен быть только локальным распознавателем (resolver), на этом можно закончить (в этом случае можно было не указывать ip-адрес 1.2.3.4, тогда dnscache слушал бы порт на 127.0.0.1). По умолчанию, dnscache не принимает запросы с других хостов. Если вы хотите принимать запросы с 1.2.3.*, просто сделайте

    touch /etc/dnscache/root/ip/1.2.3

Вы можете добавлять или удалять сети, не сообщая работающему dnscache об этом.

6.1.2. Настройка tinydns

Вам опять необходимо два пользователя, tinydns и dnslog. Если вы предварительно настраивали dnscache, как описано выше, пользователь dnslog уже существует.

Запустите tinydns-conf:

    tinydns-conf tinydns dnslog /etc/tinydns 1.2.3.5

где 1.2.3.5 — IP-адрес, на котором будет работать tinydns. Помните, что вы не можете использовать тот же IP-адрес для dnscache! По умолчанию, log-файлы находятся в /etc/tinydns/log/main. В этом случае можно также изменить путь расположения лог-файлов, как у dnscache, заменив ./main в /etc/tinydns/log/run на /var/log/tinydns.

Запускается tinydns аналогично dnscache:

    ln -s /etc/tinydns /service

теперь tinydns должен запуститься в течении 5 секунд.

Вы должны сообщить tinydns о хостах, которые он должен разрешать (resolve). Откройте /etc/tinydns/root/data в вашем любимом редакторе и наберите:

    #define the authoritative nameserver (определяем полномочный сервер имен)
    .example.com::ns1.example.com
    #mail exchanger (почтовый обменник)
    @example.com::mail.example.com
    #IP for machine1,2,3,4,5 (IP-адрес для машины1,2,3,4,5)
    =machine1.example.com:1.2.3.1
    =machine2.example.com:1.2.3.2
    =machine3.example.com:1.2.3.3
    =machine4.example.com:1.2.3.4
    =machine5.example.com:1.2.3.5
    #machine5 is also known as ns1 (машина5 также известна как ns1)
    +ns1.example.com:1.2.3.5
    #machine1 is our mailserver (машина1 — наш почтовый сервер)
    +mail.example.com:1.2.3.1
    #and our webserver (и наш web-сервер)
    +www.example.com:1.2.3.1

После редактирования перейдите в /etc/tinydns/root и выполните "make". Это скомпилирует data.cdb, который читает tinydns. (Не забывайте делать make после каждого изменения в файле data, иначе изменения не будут вступать в силу)

Существует также несколько скриптов в /etc/tinydns/root, которые оберегают вас от от редактирования файла data. Мы не находим их сильно полезными, потому что вы можете только добавлять записи, но не удалять их или редактировать. Смотрите в Примечаниях примеры их использования.

6.1.3. Настройка axfrdns

Также, как и всегда, создадим пользователя axfrdns и выполним:

    axfrdns-conf axfrdns dnslog /etc/axfrdns /etc/tinydns 1.2.3.5

где 1.2.3.5 — IP-адрес, который будет слушать axfrdns. Обычно, это должен быть то же IP-адрес, на котором запущен tinydns. Вы должны определить, какие сервера (IP-адреса) могут запрашивать у вас перенос зоны. Если вы хотите разрешить перенос зон example.com и example2.com с 9.8.7.6, добавьте эту строку в /etc/axfrdns/tcp:

    9.8.7.6:allow,AXFR="example.com/example2.com"

6.2. split horizon

Об этом можно почитать в djbdns FAQ (русский перевод.).

6.3. Вторичные DNS-сервера

6.3.1. tinydns to tinydns

6.3.1.1. копирование data.cdb

Вы можете просто скопировать сгенерированный data.cdb на вторую машину (например, используя rsync поверх ssh). data.cdb становится несколько большим, чем data-файл, таким образом, этот вариант применим только в локальной сети. Обратите внимание: data.cdb — архитектурно независимый файл, т.е. нет никаких проблем, если вы используете разные ОС. Мне больше нравится другой метод. Хранение файла data (не data.cdb) на нескольких машинах дает дополнительную меру безопасности в случае, если первичный NS-сервер откажет. Ваш путь может отличаться...

Если вы копируете data.cdb, вам больше ничего не нужно делать на вторичном NS-сервере, чтобы "оживить" новые данные, т.к. tinydns работает непосредственно с файлом на диске и немедленно заметит обновление. Тем не менее, вы должны убедиться, что файл не заменил оригинальный файл до тех пор, пока он не будет полностью скопирован, т.о. или передавайте его через rsync, который сделает это правильно автоматически, или используйте что-то вроде:

        scp data.cdb secondary:/etc/tinydns/root/data.cdb-new && \
        ssh secondary mv /etc/tinydns/root/data.cdb-new /etc/tinydns/root/data.cdb

6.3.1.2. использование rsync поверх ssh

Это метод, который я предпочитаю. Он удобен, даже если ваши tinydns-сервера соединены медленными линиями, например, в различных месторасположениях, потому что передаются только изменения, также доступна компрессия.

    rsync -e ssh -az /etc/tinydns/root/data $host:/etc/tinydns/root/data
    ssh $host "cd /etc/tinydns/root; make"

где $host — ваш вторичный tinydns-сервер. NB: и rsync и ssh имеют общую проблему, которая заключается в том, что другие программы хотят выполнить их в различных окружениях — т.е. rsync хочет выполнить ssh, и rsync хочет вызвать саму себя через ssh на удаленной системе. Кроме того, оба пакета по умолчанию устанавливаются в /usr/local, когда собираются из исходников с настройками по умолчанию, и /usr/local/bin не находится в пути по умолчанию (default path) во многих оболочках. Результат этого заключается в том, что, возможно, вам придется взять вышеупомянутую команду и переписать её примерно так:

        /usr/local/bin/rsync -e /usr/local/bin/ssh \
                --rsync-path=/usr/local/bin/rsync ...
    взамен более простого
        rsync -e ssh ...

Исходя из этих соображений, я обычно пробую и убеждаюсь, что пути /usr/bin/rsync и /usr/bin/ssh будут работать, даже если они не являются путями установки по умолчанию, и создаю символические ссылки в моих системах, чтобы они сработали, если понадобится.

6.3.2. Передача зоны от BIND к tinydns

(было бы неплохо иметь реакцию tinydns на входящие уведомления (notifies) в стиле BIND с запуском внешнего скрипта, который бы делал проверку аутентификации и вызывал axfr-get — никто не хочет написать патч?)

(UPDATE: У меня есть патч, но нет времени для проверки и тестирования.)

6.3.3. Передача зоны от tinydns к BIND

Если на вторичном сервере имен запущен не tinydns и он под вашим контролем, вы можете попробовать установить там tinydns. Если он не под вашим контролем, подумайте об использовании другого вторичного сервера имен ;-)). Хорошо, хватит шуток: если вам действительно необходимо поддерживать вторичные сервера имен с другой версией DNS-сервера, вы можете реализовать уведомления (Notifies) в стиле BIND. Эти уведомления (Notifies) говорят BIND'у: "Эй, домен xyz изменился, перезагрузи (reload) его!". Затем BIND проверяет серийный номер зоны у tinydns, если он больше, чем номер его зоны (т.е. версии, которая хранится у BIND), BIND производит AXFR-запрос для этого домена (это средство доставки данных и их перезагрузки). Пакет с уведомлением (Notify) ДОЛЖЕН иметь IP-адрес tinydns в качестве обратного, что делает задачу немного сложной, если IP-адрес tinydns не эквивалентен первичному IP-адресу вашей машины. Помните, что вы должны настроить axfrdns чтобы это работало.

Сам по себе Notify-скрипт (разработка Jos Backus) не слишком сложен:

#!/usr/bin/perl -w

# usage: dnsnotify zone slave [...]
# example: dnsnotify example.org 1.2.3.4 1.2.3.5
# requires Net::DNS >= 0.20

use Net::DNS;
use Data::Dumper;
use strict;

my $MY_IP = "a.b.c.d";  # your own IP here

my $zone   = shift;

die "usage: dnsnotify zone slave [...]\n"
  unless defined $zone and @ARGV;

my $res = new Net::DNS::Resolver;
$res->srcaddr($MY_IP);

for my $slave ( @ARGV ) {
  my $packet = new Net::DNS::Packet($zone, "SOA", "IN")
    or die "new Net::DNS::Packet failed\n";

  $packet->header->opcode("NS_NOTIFY_OP");
  $packet->header->aa(1);
  $packet->header->rd(0);

  #$packet->print;

  $res->nameservers($slave);
  print STDERR Dumper($packet);
  my $reply = $res->send($packet);
  if ( defined $reply ) {
    $reply->print;
  } else {
    warn "\n;; TIMED OUT\n";
  }
}

exit 0;

Существует одно изменение по сравнению с версией, опубликованной Jos: строка с $res->srcaddr. Она устанавливает исходящий IP-адрес для запроса, для того чтобы BIND на другой стороне принял уведомление (Notify). With Net::DNS >= 0.20 there is no need to patch any more.

6.4. Большие сайты, нуждающиеся в разделении файлов для каждой зоны

Некоторую информацию на эту тему можно найти на tinydns.org.

6.5. Использование djbdns в ISP-окружении

6.5.1. Экспорт tinydns-data из реляционных баз данных (Relational Database (RDBMS))

Существует одно главное отличие между djbdns в небольшом окружении (small environments) и у ISP (Internet Service Provider) — автоматизация. В качестве ISP, вы, скорее всего, будете создавать ваши DNS-данные (dnsdata) из базы данных (БД). Вы будете иметь интерфейс между tinydns и БД, работающий напрямую с файлом data вместо того, чтобы использовать add-ns, add-mx и т.д.

Формат этого файла задокументирован в http://cr.yp.to/djbdns/tinydns-data.html. На первый взгляд он выглядит немного странным, поскольку больше оптимизирован не для удобства чтения людьми, а для разбора [с помощью программных средств]. Это делает по-настоящему простой нашу задачу экспорта из БД.

Представим небольшие простые таблицы, одну для данных домена и одну, собственно, для данных DNS (dns data). Пусть они будут называться "Domains" и "NSEntry".

Domains будет выглядеть примерно так:

Domain          varchar         Domainname              example.com
nserver1        varchar         1st Nameserver          ns1.isp.com
nserver2        varchar         2nd Nameserver          ns2.isp.com
nserver3        varchar         3rd Nameserver          ns3.isp.com
nserver4        varchar         1st Nameserver          ns4.isp.com
nserver5        varchar         2nd Nameserver          ns5.isp.com
nserver6        varchar         3rd Nameserver          ns6.isp.com
mx1             varchar         1st Mailserver          mx1.isp.com
mx2             varchar         2nd Mailserver          mx2.isp.com
mx3             varchar         3rd Mailserver          mx3.isp.com
qmtp1           varchar         1st qmtp-Mailserver     qmtp1.isp.com
qmtp2           varchar         2nd qmtp-Mailserver     qmtp2.isp.com
serial          varchar         Serial No.              972244824       (устанавливается в time() при каждом изменении)
SOAmail         varchar         Mail-addr. SOA          hostmaster.isp.com (замена "@" на "." !!!)
NS              bit             1=we do dns, 0=no       1
changed         bit             1=changes were made     1               (сбрасывается в 0 после построения файла data)

таблица NSEntry также очень простая:

Domain          varchar         Domainname              example.com
Host            varchar         Hostname                www
Type            varchar         Entry-Type              A
Value           varchar         Entry-Value             1.2.3.4

теперь посмотрим, как извлечь данные из БД в tinydns (используя perl):

#!/usr/bin/perl

# Takes DNS-Info out of the database and creates tinydns' data-file.
# written Henning Brauer, Hostmaster BSWS, in July 2000
# License: BSD
# update Feb 8, 2001

use DBI;

#connect to your database
$dbh=DBI->connect("DBI:mysql:mydb:myhost", "login", "password") || die "Cannot connect to db server DBI::errstr,\n";;

#look for changes
$sth=$dbh->prepare("SELECT serial FROM Domains WHERE changed=1");
$rv=$sth->execute;
$sth->finish;

if ( $rv > 0 ) {
  print "Rewriting Nameserverdata\n";

  #These values are accepted by DENIC and CORE
  $refresh=10000;
  $retry=3600;
  $expire=604800;
  $min=86400;

  $i=0; $j=0;

  #Backup old File and use the template for the new one
  system("mv /etc/tinydns/root/data /etc/tinydns/root/data.old");
  system("cp /etc/tinydns/root/data.tl /etc/tinydns/root/data");
  open OF, ">> /etc/tinydns/root/data";

  #fetch domain-data
  $sth=$dbh->prepare("SELECT Domain, nserver1, nserver2, nserver3, nserver4, nserver5, nserver6, mx1, mx2, mx3, serial, SOAmail, NS, changed, qmtp1, qmtp2, mail FROM Domains WHERE NS=1 ORDER BY Domain");
  $sth->execute;
  while ( ( $zone, $ns[1], $ns[2], $ns[3], $ns[4], $ns[5], $ns[6], $mx1, $mx2, $mx3, $serial, $mail, $ns, $changed, $qmtp1, $qmtp2, $mtype ) = $sth->fetchrow_array ) {
    #support for glue-entries (like ns.bsws.de 213.128.133.188)
    foreach $dns (@ns) {
      $dns=~s/^([^ ]+) .*/$1/;
    }

    #SOA
    print OF "Z$zone\:$ns[1]\:$mail\:$serial\:$refresh\:$retry\:$expire\:$min\:\:\n";
    #Nameserver
    foreach $dns (@ns) {
      if ( $dns ne "" ) { print OF "."; print OF "$zone\:\:$dns\:\:\n"; }
    }

    #MX - supporting MXPS (http://cr.yp.to/proto/mxps.txt) now
    if ( $mx1 ne "" ) { print OF "\@$zone\:\:$mx1\:12816\:\:\n"; }
    if ( $mx2 ne "" ) { print OF "\@$zone\:\:$mx2\:12832\:\:\n"; }
    if ( $mx3 ne "" ) { print OF "\@$zone\:\:$mx3\:12848\:\:\n"; }
    if ( $qmtp1 ne "" ) { print OF "\@$zone\:\:$qmtp1\:12801\:\:\n"; }
    if ( $qmtp2 ne "" ) { print OF "\@$zone\:\:$qmtp2\:12817\:\:\n"; }

    #fetch the entries itself
    $st2=$dbh->prepare("SELECT Host, Type, Value FROM NSentry WHERE Domain=\"$zone\" ORDER BY host");
    $st2->execute;
    while ( ( $host, $typ, $value ) = $st2->fetchrow_array ) {
      #A-Record - Name to IP
      if ( $typ eq "A" ) {
        print OF "+$host\.$zone\:$value\:\:\n";
      }
      #A-Record + PTR for reverse lookup
      if ( $typ eq "AR" ) {
        print OF "=$host\.$zone\:$value\:\:\n";
      }
      #CNAME - bad thing...
      if ( $typ eq "CNAME" ) {
        print OF "\C$host\.$zone\:$value\:\:\n";
      }
    }
    $st2->finish;

    #remember changes and nameservers to send notifies to
    if ( $changed eq 1 ) {
      foreach $dns (@ns) {
        #replace bsws.de you your nameserverdomain
        if ( $dns !~ /.*bsws.de$/ && $dns ne "" ) {
          $chng[$j]=$zone;
          $ntfy[$j++]=$dns;
        }
      }
    }
  }
  $sth->finish;
  close OF;
  chdir("/etc/tinydns/root");
  system("make");

  #note 1

  $dbh->do("UPDATE Domains SET changed=0 WHERE NOT(changed=0)");
}

$dbh->disconnect();

So here we are! Если вы настроили tinydns и axfrdns как описано ранее, то теперь у вас есть сервер имен, управляемый лучшим ПО от DJB и получающий свои данные из БД. Теперь легко добавить в cron регулярное выполнение вышеописанной процедуры. Также, легко построить некоторый интерфейс, чтобы позволить вашим клиентам самим редактировать данные DNS.

6.5.2. Запуск добавочных tinydns-серверов

Для большинства TLD вы будете иметь запущенными (работающими) как минимум два DNS-сервера. Запуск второго tinydns — не проблема, тогда вы будете иметь два первичных DNS-сервера, работающих не по классический схеме первичный-вторичный (primary-secondary scheme). Это хорошо в том случае, если ваш первичный сервер откажет. Я предложил бы использовать rsync для передачи файла data на второй сервер tinydns, так что просто добавьте следующие строки к вышеприведенному скрипту в секции '#note 1':

    system("/usr/local/bin/rsync -e /usr/bin/ssh -az /etc/tinydns/root/data $host:/etc/tinydns/root/data");
    system("ssh $host \"cd /etc/tinydns/root; make\"");

где $host — ваш второй сервер tinydns. Конечно, вы можете также просто запустить полный скрипт на втором tinydns-сервере.

Если вам необходимо поддерживать вторичный сервер с BIND, используйте dnsnotify-скрипт, представленный выше, и вызывайте его при изменениях в файле data. Для этого просто добавьте строку

    for ( $i=0; $i<$j; $i++ ) { print "Notify: $chng[$i] -> $ntfy[$i]\n"; system("/path/to/dns_notify.pl $chng[$i] $ntfy[$i]"); }

к нашему скрипту db2tinydns в секции '#note 1'.

6.5.3. Выводы

Вы имеете как минимум один tinydns-сервер, забирающий свои данные из БД MySQL, уведомляете вторичные сервера под управлением BIND и/или синхронизируете его data-файл с дополнительными tinydns-серверами, и это все делается автоматически. Так что теперь вы будете иметь время для разработки красивого Web-интерфейса к вашей БД ;-))

Полный (complete) скрипт всегда доступен на lwd.bsws.de.

6.6. Собственные корневые сервера имен

Если вы имеете изолированную сеть (что подразумевает сеть без соединения с Internet) и имеете запущенные сервисы, которые требуют работающего DNS, вы должны фальсифицировать структуру, на которой основан Интернет. Главный момент здесь — то, что вы должны обеспечить "корневые сервера", которые являются начальным пунктом для каждого процесса разрешения DNS-имени (DNS resolving process). Как минимум, вы должны обеспечить один сервер, который будет являться полномочным для корня пространства имен DNS (root of the DNS namespace). К счастью, это легко в случае с tinydns. Просто определите сервер имен для "." в вашем файле data.

  ./add-ns . 1.2.3.1

Вы можете определить дополнительные сервера, если запускаете несколько внутренних корневых серверов:

  ./add-ns . 1.2.3.1
  ./add-ns . 1.2.3.2
  ./add-ns . 1.2.3.3

Нет необходимости указывать сервера имен для всех подзон, которые вы определили, если они обслуживаются той же группой серверов имен. Вы также можете делегировать подзоны другим серверам имен, если вы создаете большую сеть, которая отражает распределенную природу DNS. Например, вы можете использовать домен "local" внутри организации, и отдел продаж может запустить свой собственный сервер имен с адресом 1.3.1.1. Дополнительно, вы определите почтовый концентратор (mailhub) и интранет-сервер. Тогда вышеупомянутая конфигурация меняется на:

  ./add-ns . 1.2.3.1
  ./add-ns . 1.2.3.2
  ./add-ns . 1.2.3.3
  ./add-childns sales.local 1.3.1.1
  ./add-mx local 1.2.3.5
  ./add-host intra.local 1.2.3.4

Чтобы запустить разрешение имен через частные корневые сервера, вы должны сказать dnscache о них. Это делается путем замены содержимого root/servers/@ в каталоге вашего dnscache и /etc/dnsroots.global на IP-адреса ваших частных корневых серверов — строку за строкой.

6.7. Альтернативные корневые сервера имен

В конце концов, вы захотите использовать альтернативные TLD (alternate toplevel domain), которые не одобрены ICANN. Это не проблема. Все, что вам нужно, — это основать новый список корневых серверов. Вы можете посмотреть на технические рекомендации на сайте The Open Root Server Confederation

6.8. Отдача одного data-файла на нескольких интерфейсах

Существует патч, который позволяет tinydns работать на нескольких интерфейсах. Также, существуют рекомендации установить переменную окружения tinydns "IP" равной 0.0.0.0. Несмотря на то, что эти способы могут у вас работать, они не рекомендуются.

Рекомендованный метод состоит в запуске нескольких экземпляров tinydns, по одному на каждый обслуживаемый интерфейс. Переменную окружения "ROOT" для всех экземпляров следует установить в одно и то же значение

Это звучит расточительно? Подумайте еще раз. Файл data.cdb отображается tinydns в память в режиме только для чтения, что дает операционной системе возможность сделать все связанные буферы (associated buffers) общими для всех процессов tinydns. Также, операционная система может сделать (и сделает) общей память, занимаемую самой программой. Таким образом, накладные расходы сводятся к немного большему числу процессов (supervise/tinydns) и выделенной им памяти (associated memory), которая не принимается в расчет в современном окружении.

Преимущество заключается в том, что tinydns работает не на всех интерфейсах, а только на тех, которые вы указали. Также, вы получаете возможность контролировать ваши DNS-сервера отдельно на каждом интерфейсе.

Это примерная конфигурация для трех интерфейсов:

 tinydns-conf tinydns dnslog /etc/tinydns1 1.2.1.1
 tinydns-conf tinydns dnslog /etc/tinydns2 1.2.2.1
 tinydns-conf tinydns dnslog /etc/tinydns3 1.2.3.1
 echo "/etc/tinydns1/root" > /etc/tinydns2/env/ROOT
 echo "/etc/tinydns1/root" > /etc/tinydns3/env/ROOT
 ln -s /etc/tinydns[1-3] /service

7. Сопровождение

7.1. tinydns

Сопровождение tinydns сводится к более или менее частому обновлению вашего файла data. Со временем, вы можете оптимизировать ваши настройки, например, используя функцию местоположения (location feature).

Для изменения записей tinydns предоставляет приятную функцию, которая дает возможность гладкого перехода без ручного вмешательства: временные метки (timestamps). Смотрите документацию tinydns-data, чтобы узнать, как для этого может быть использована комбинация ttl/timestamp. Существует одна проблема с форматом временных меток: никто не может ввести их без расчета. Здесь приведена утилита конвертации, которая преобразует временные метки в формате ISO 8601 в требуемый формат "external TAI64". Она должна компоноваться с библиотекой libtai Dan'а:

*
// ---------------------------------------------------
// isotai64.c
// Frank Tegtmeyer <fte@pobox.com>, 2000-02-25
// see http://www.lightwerk.com/djbdns/isotai64.html
//
// input format:  YYYY-MM-DD HH:MM:SS zzzzz
// zzzzz is the timezone (+0200, +0000, -0400, ...)
//
// ---------------------------------------------------
*/

#include <stdio.h>
#include <time.h>
#include "tai.h"
#include "leapsecs.h"
#include "caltime.h"

char line[100];

char x[TAI_PACK];

main()
  {
  struct tai t;
  struct caltime ct;
  int i;

  if (leapsecs_init() == -1)
    printf("unable to init leapsecs\n");

  while (fgets(line,sizeof line,stdin))
    {
    if (!caltime_scan(line,&ct))
      printf("unable to parse\n");
    else
      {
      caltime_tai(&ct,&t);
      tai_pack(x,&t);
      for (i = 0;i < TAI_PACK;++i)
        printf("%2.2x",(unsigned long) (unsigned char) x[i]);
      }
    printf("\n");
    }
  exit(0);
}

7.2. dnscache

Чтобы иметь максимальную выгоду от вашего dnscache, вы должны регулярно проверять, соответствует ли его размер вашей организации. Если ваш кэш слишком большой, то это, скорее всего, не составляет большой проблемы, если вы способны пожертвовать используемой для этой задачи памятью. Тем не менее, если ваш кэш слишком маленький, дела обстоят хуже, чем это необходимо. Машина с работающим dnscache станет более загруженной, потому что dnscache запрашивает записи более часто. То же самое справедливо для серверов с зонами, которые dnsache будет опрашивать. Слишком маленький кэш также увеличивает использование полосы пропускания вашего Интернет-соединения. Все это также означает, что ваши пользователи будут дольше ожидать результатов этих запросов.

Как отрегулировать размер кэша описано в FAQ. Смотрите также секцию "использование памяти dnscache" в этом документе.


8. Сравнение с BIND, проблемы миграции

8.1. Миграция

Коротко:

  -установливаем djbdns
  -забираем зоны у BIND с помощью axfr-get
  -останавливаем bind
  -запускаем tinydns
  -идем пить пиво

8.1.1. Преобразование ваших зонных файлов

8.1.2. Если ваш сервер первичный для BIND-сервера

8.1.2.1. Корректировка серийных номеров (serials)

Если вы хотите использовать Z-записи в вашей конфигурации tinydns, потому что они более легкие в использовании, чем те, что используются по умолчанию tinydns-data, перед переходом на tinydns вам необходимо обратить внимание на серийные номера (serials). Вторичные сервера под управлением BIND (и, возможно, другие тоже) используют AXFR-механизм, чтобы держать свои данные синхронизированными с вашим первичным сервером. Решение об обновлении данных принимается на основании так называемого "серийного номера" ("serial number") в SOA-записи. Зонные пересылки (zone transfers) происходят только тогда, когда серийный номер у первичного сервера выше, чем у одного из вторичных. Ввиду того, что серийные номера выражаются целым положительным 32-х битным числом, диапазон их значений находится в пределах от 0 до 2^32-1 (4294967295). Чтобы избежать проблем при достижении верхнего порога сравнение серийных номеров осуществляется с использованием "sequence space arithmetic", которая описана в RFC1982, (русский перевод) и более ясно в How the AXFR protocol works.

Tinydns использует время модификации data-файла и устанавливает серийный номер равный десятичному числу секунд с начала Unix-эпохи (1 января 1970, 00:00:00 GMT). В настоящее время это приводит к значениям с девятью разрядами.

Один из распространенных форматов для серийных номеров в BIND-системах — использование четырех разрядов для года, двух для месяца, двух для дня и двух для увеличивающегося номера последнего обновления зоны. Для пятого изменения 2001-02-14 вы должны установить серийный номер в "200102144" или "2001021404". Девятиразрядный формат не вызывает проблем, потому что серийный номер, который создает tinydns-data, выше, чем номер, сформированный в формате BIND. Поэтому зонные пересылки будут продолжаться после перехода на tinydns.

Проблематичным является десятиразрядный формат. Серийные номера в этом формате выше тех, которые использует tinydns. Чтобы позволить зонным пересылкам продолжаться после перехода на tinydns, вы должны перед этим настроить серийные номера.

Для осуществления перехода, вам необходимо явно заставить все вторичные сервера перейти на новые номера. Вы можете сделать это принудительно, установив серийный номер в значение, которое больше YYYYMMDD##-даты BIND'а и меньше, чем time_t у tinydns-data, в соответствии с арифметикой серийных номеров SOA-записей. Существует диапазон таких значений. Середина этого диапазона может быть вычислена очень просто:

(YYYYMMDD## + time_t) / 2 + 2**31

Это будет работать, пока среднее между YYYYMMDD## и time_t не превышает 2**31 (потому что необходимо взять результат формулы по модулю 2**32). But that doesn't happen until after time_t exceeds 2**31, in 2038, and time_t will pass YYYYMMDD## and make this problem disappear before then, in 2034. (смысл этой фразы так и не поддался расшифровке, но в общих чертах там говорится о том, что до 2034 года можно использовать эту формулу спокойно) Итак, вкратце, вы можете расчитать серийный номер с помощью команды:

echo `date +%Y%m%d00\ %s` + 2 / 2 31 '^' + p | dc

В итоге, мы получаем следующие стадии:

   1. Отредактировать data-файл на использование Z-записи, с явным
      указанием серийного номера, расчитанного выше; опубликовать результаты.
   2. Подождать окончания синхронизации зон на вторичных серверах (зависит от 
      времени обновления (refresh time) в SOA, которая в tinydns-data 
      равна по умолчанию 4.5 ч.)
   3. Проверить (все) вторичные сервера одной из следующих команд:
      dnsq soa <domain> <ip of the secondary>
      dig @<ip of the secondary> <domain> soa
      nslookup -type=soa <domain> <ip of the secondary>
   4. Удалить явное указание серийного номера в Z-строке или перейти на
      использование более простых "."-строк; не обязательно 
      специально публиковать эти изменения (в данном случае, выполнять make),
      это подождет до следующего реального изменения в содержимом данных зоны.

Вы можете получить дополнительную информацию о серийных номерах.

8.1.2.2. Количество возвращаемых ip-адресов на один hostname

В djbdns-1.04 и выше, tinydns никогда не возвращает больше, чем 8 адресных записей для запрошенного имени хоста. Если вам нужна совместимость с традиционным поведением (подходом), тогда вам нужно запустить djbdns-1.03 или патчить tdlookup.c. (Оба этих метода ведут к потере гарантии.)


9. Тестирование конфигурации DNS, диагностирование проблем

(note: comment on why dnsq and dnsqr are preferable to nslookup)


10. Производительность

10.1. Использование памяти dnscache

dnscache распределяет (allocates) память, необходимую ему для кэша при запуске, поэтому объем памяти, занимаемый процессом dnscache, не растет. Вы можете установить параметр CACHESIZE в любое значение, которое пожелаете — официальный FAQ объясняет, как определить наиболее эффективное значение. Для всего, что выходит за пределы "нормального" использования dnscache одной рабочей станцией, возможно, будет хорошей идеей подумать об увеличении CACHESIZE.

Переменная окружения DATALIMIT, используемая в стандартном стартовом скрипте, является механизмом безопасности. Она используется, чтобы удерживать процесс от разрастания в тех маловероятных случаях, которые могут быть следствием логических или технических ошибок, которые могут позволить dnscache начать расти. В FAQ приводится пример как увеличить размер CACHESIZE до 100MB. Если вы хотите установить другое значение (2MB могут быть достаточны для небольшой компании, работающей с web и почтой через линию 64k), вы должны решить, как изменить значение DATALIMIT.

Хотя никто не придумал формулу для расчета правильного значения, вот несколько подсказок из mailinglist:

"Наименьшее значение, которое работает. dnscache распределяет пространство для своего кэша при запуске. Если значение DATALIMIT слишком мало, распределение будет неудачным. Вы не хотите, чтобы после первоначального распределения объем памяти, занимаемый dnscache, каким-то образом продолжал расти; DATALIMIT препятствует этому. Такой рост может случиться только как результат ошибки, так что это маловероятно; DATALIMIT дополнительная защитная мера, "на всякий случай". (Paul Jarc в этом сообщении)

Dan сказал: "Если вы хотите экспериментировать с большим кэшем, убедитесь что установили значение -d на пару мегабайт выше, чем размер кэша."

Uwe Ohse: "параметр "-d" — это "что-то" большее, чем CACHESIZE просто потому, что dnscache нуждается в "некотором" количестве памяти помимо кэша."

Чтобы скорректировать размер кэша вы должны контролировать "stats"-строки, которые dnscache записыват в лог-файлы. Markus Stumpf создает отдельный файл для этого, используя следущий прием с multilog:

exec setuidgid dnslog multilog t s250000 n20 ./main '-*' +'* stats * * *' =./dnsstatus

A. Установка программ

В общем случае, установка djbdns из исходников вместо использования пакетов — хорошая идея. Проделайте это один раз и полностью поймете, что использование пакетов djbdns может сделать вашу жизнь легче.

A.1. Ручная установка из исходного кода

A.1.1. daemontools

Возьмите daemontools по адресу http://cr.yp.to/daemontools/install.html. Установка действительно проста (необходимы привилегии root):

    mkdir -p /package
    chmod 1755 /package
    cd /package
    gunzip /path/to/daemontools-0.76.tar.gz
    tar -xf /path/to/daemontools-0.76.tar
    rm /path/to/daemontools-0.76.tar
    cd admin/daemontools-0.76
    package/install

A.1.1.1. Linux

A.1.1.2. *BSD


Внимание: Это не необходимо для daemontools >= 0.75

В *BSD вы должны добавить эти строки в ваш /etc/rc.local:

  echo -n "daemontools "
  PATH=$PATH:/usr/local/bin
  svscan /service &

A.1.1.3. Solaris

A.1.2. ucspi-tcp

Если вы планируете запускать axfrdns или axfr-get, вам необходимо получить ucspi-tcp по адресу http://cr.yp.to/ucspi-tcp/install.html. Установка также проста:

    gunzip ucspi-tcp-0.88.tar.gz
    tar -xf ucspi-tcp-0.88.tar
    cd ucspi-0.88
    make

Станьте root'ом для установки:

    make setup check

Это все. Конфигурирование не требуется.

A.1.3. Установка djbdns

Возьмите djbdns по адресу http://cr.yp.to/djbdns/install.html. Процесс установки, опять же, очень прост:

    gunzip djbdns-1.05.tar.gz
    tar -xf djbdns-1.05.tar
    cd djbdns-1.05
    make

Станьте root'ом для установки:

    make setup check

A.2. Использование RPM

Эта часть написана Bennett Todd; Я работаю с Red Hat Linux большую часть времени, и иногда с Solaris, так что я продемонстрирую процедуру установки с использованием инструментов, которые я одобряю; они включают init-скрипты и rpm пакеты, которые находятся в rpm-packaging.tar.gz. Содержащиеся spec-файлы построят rpm-пакеты из исходников (URL'ы для скачивания исходников включены в spec-файлы). Они также включают документацию, которую я создал путем копирования сайта DJB с помощью ftpcopy, упаковывая ее с помощью команд вроде этих:

        for pkg in djbdns daemontools ucspi-tcp;do
                tar cf - --exclude=\*.gz $pkg* | bzip2 \
                    > /usr/src/redhat/SOURCES/${pkg}-docs.tar.bz2
        done
(В RedHat-based дистрибутивах пути могут быть другими, например в ASPLinux вместо /usr/src/redhat/SOURCES/ слудет использовать /usr/src/asplinux/SOURCES/)

Также, для большинства машин, я запускаю dnscache работать как локальный resolver; это просто:

        rpm -i daemontools-0.76.i386.rpm
        rpm -i djbdns-1.05.i386.rpm
        useradd -d /no/home -s /no/shell dnscache
        useradd -d /no/home -s /no/shell dnslog
        dnscache-conf dnscache dnslog /etc/dnscache
        ln -s /etc/dnscache /service
        $EDITOR /etc/resolv.conf # set nameserver to 127.0.0.1
(В RadHat-based дистрибутивах, возможно, неплохой идеей будет использовать useradd с параметром "-r".) На tinydns.org доступны ссылки на альтернативные rpm.

A.3. Использование портов в OpenBSD

Все программы Dan Bernstein были удалены из портов OpenBSD из-за конфликтов с его лицензией (т.е. никакой лицензии нет). Но вы все еще можете вполне легко установить djbdns, руководствуясь оригинальной документацией. Вам только будет необходимо удостовериться, что вы изменили softlimit в /etc/tinydns/run с

        /usr/libexec/ld.so: tinydns: libc.so.29.0: Cannot allocate memory

A.4. Использование портов в FreeBSD

Процедура во FreeBSD в основном та же самая, что и в OpenBSD, если у вас есть установленное перед этим дерево портов. (В предыдущей версии документа в приложении А.3 автор описывал установку djbdns из портов в OpenBSD)

  su
  cd /usr/ports/sysutils/ucspi-tcp
  make install
  cd /usr/ports/sysutils/daemontools
  make install
  cd /usr/ports/net/djbdns
  make install

Эти команды скачают, соберут и установят djbdns, daemontools и ucspi-tcp для вас. Существующий пакет, созданный в /usr/ports/packages/, вы можете использовать для установки djbdns на другие машины, используя pkg_add.

A.5. Использование ? в Solaris

A.6. Стартовые скрипты SysV-типа


Внимание: При использовании daemontools >= 0.75 вам необходимо будет скорректировать пути

В SysV-системах, вы, возможно, захотите использовать init-скрипты в SysV-стиле. Вот один из возможных вариантов:

  #!/bin/sh
  #
  # svscan        Start and stop the svscan daemon.
  #
  # description: svscan is a general-purpose service manager, handling \
  #              execution of daemons, and ensuring their operation.
  # processname: svscan

  # Source function library.
  . /etc/rc.d/init.d/functions

  SERVICESDIR='/usr/local/service'
  BINDIR='/usr/local/bin'
  LOCKDIR='/var/lock/subsys'
  PATH=$PATH:$BINDIR

  [ -f $BINDIR/svscan ] || exit 0
  [ -d $SERVICESDIR ] || exit 0

  RETVAL=0

  # See how we were called.
  case "$1" in
    start)
          # Start svscan.
          action 'Starting svscan:' "/bin/sh -c '( cd $SERVICESDIR && exec $BINDIR/svscan ) &'"
          RETVAL=$?
          [ $RETVAL -eq 0 ] && touch $LOCKDIR/svscan
          ;;
    stop)
          # Stop svscan.
          echo -n "Shutting down svscan:"
          killproc svscan
          RETVAL=$?
          echo
          [ $RETVAL -eq 0 ] && rm -f $LOCKDIR/svscan

          # Stop supervised services. Do this last, so that
          # svscan doesn't restart them.
          x="$allow_null_glob_expansion"
          allow_null_glob_expansion=1
          for service in $SERVICESDIR/*
          do
                $BINDIR/svok $service || continue
                action "Ending supervision of service `basename $service`:" "$BINDIR/svc -x $service"
                [ -k $service ] && action "Ending supervision of service log `basename $service`:" "$BINDIR/svc -x $service/log"
                action "Stopping service `basename $service`:" "$BINDIR/svc -d $service"
                [ -k $service ] && action "Stopping service log `basename $service`:" "$BINDIR/svc -d $service/log"
          done
          allow_null_glob_expansion="$x"
          ;;
    status)
          status svscan
          RETVAL=$?
          x="$allow_null_glob_expansion"
          allow_null_glob_expansion=1
          for service in $SERVICESDIR/*
          do
                  $BINDIR/svstat $service
          done
          allow_null_glob_expansion="$x"
          ;;
    restart|reload)
          $0 stop
          $0 start
          RETVAL=$?
          ;;
    *)
          echo "Usage: svscan {start|stop|restart|reload|status}"
          exit 1
  esac

  exit $RETVAL

B. Использование add-* скриптов для создания data-файла tinydns

    cd /etc/tinydns/root
    ./add-host machine1.example.com 1.2.3.1
    ./add-host machine2.example.com 1.2.3.2
    ./add-host machine3.example.com 1.2.3.3

Теперь, если example.com делегирован вашему tinydns-серверу корректно, dnsip machine1.example.com должен показать 1.2.3.1. Обратите внимание, что example.com должен быть делегирован a.ns.example.com с вашим IP-адресом, чтобы это работало. Если вы хотите, чтобы machine1 была также доступна как www.example.com, просто сделайте

    cd /etc/tinydns/root
    ./add-alias www.example.com 1.2.3.1

Таким же образом, давайте определим machine2 в качестве нашего почтового сервера (mailserver) для example.com:

    cd /etc/tinydns/root
    ./add-mx example.com 1.2.3.1

Tinydns назовет почтовый сервер a.mx.example.com. Вы можете также добавить дополнительные сервера имен (nameservers):

    cd /etc/tinydns/root
    ./add-ns example.com 1.2.3.3
    ./add-ns 3.2.1.in-addr.arpa 1.2.3.3

Tinydns назовет второй (second) сервер b.ns.example.com.


C. Полезные ссылки


D. Acknowledgements

Bennett Todd <bet@rahul.net> for starting this great document, his amount of work for it and his great view for straight-through structuring. Thank you, Bennett. It was real fun to work with you.

Dave Sill for support and encouragement, and for letting me call this Life With djbdns in frank homage to his Life With qmail.

Joost van Baal <joostvb@xs4all.nl> for improving the description of an NS record.

Henning Brauer <hostmaster@bsws.de> for the section on ISP Design (exporting from RDBMS to tinydns-data, and doing Notify for BIND secondaries), the installation instructions and parts of appendix a.

Florent Guillaume <Florent.Guillaume@mail.com> for two changes on the dnsnotify script to let the notify be RFC 1996 conform.

Jos Backus <josb@cncdsl.com> for an always up-to-date dnsnotify.pl script.

Clemens <rabat@web.de> for the FreeBSD installation notes.

Richard Lucassen <spam1@lucasson.org> for the SysV-style init script.

David Pick <D.M.Pick@qmw.ac.uk> for additions to the FreeBSD installation notes.

Frank Tegtmeyer <fte@fte.to> for the section about private root servers, upgrading from bind and various other stuff I can't count anymore ;-))

Bob <rd@thrush.com> for correcting various spelling errors.

Scott Schwartz <schwartz@bio.cse.psu.edu> for the IPs per hostname hint.

Bernhard Graf <fisch@augensalat.de> for an updated Net::DNS::Resolver patch and an updated dnsnotify script.

Fridtjof Busse <fridtjof@fbunet.de> for updated OpenBSD instructions

$Id: lwd.sdf,v 1.6 2001/09/26 07:42:47 brahe Exp $


Рейтинг@Mail.ru