Служба DNS (Bind)

Если локальная сеть не подключена к сети Интернет, вполне возможно, что внутренний DNS-сервер в ней не нужен. За преобразование доменного имени в IP-адрес и обратно в Linux отвечает несколько разных механизмов, лишь один из которых базируется на службе доменных имён. В самом простом случае имена всех компьютеров вместе с их адресами можно записать в файл /etc/hosts. Порядок просмотра различных пространств имён указывается в файле /etc/nsswitch.conf. Строка hosts: files nisplus nis dns этого файла предписывает приложениям, пользующимся стандартной функцией gethostbyname() сначала заглянуть в /etc/hosts, затем попытаться получить таблицы hosts службы nisplus или nis, а только затем обращаться к DNS-серверу. Это вполне разумное правило: учитывая время выполнения запроса в каждом случае.

Если задачу преобразования имён в адреса взял на себя провайдер, собственный DNS-сервер можно тоже не заводить. В этом случае на всех компьютерах в качестве сервера имён указывается сервер провайдера (поле nameserver в файле /etc/resolv.conf), к которому и идут все запросы. Даже если внутренняя сеть организована согласно RFC1918 (т. н. интранет) и адреса компьютеров в ней не могут «светиться» в сети Интернет, DNS-запросы во внешний мир работать будут. Между собой компьютерам предлагается общаться с помощью /etc/hosts или IP-адресов. Кстати, некоторые службы и системные утилиты, работающие с доменными именами, запускаются в ALT Linux с использованием chroot (в каталоге /var/resolv), так что после изменения упомянутых файлов рекомендуется выполнить команду update_chrooted conf.

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

Первая задача — уменьшение времени ответа на DNS-запрос абонентов внутренней сети. Если канал подключения к Интернет обладает большим временем задержки (скажем, четверть секунды), то работа с данными, включающими в себя много доменных имён (например, с www-страницами) может стать весьма медленной, хотя общий объём трафика будет невелик. Система доменных имён — распределённая база данных, замечательно поддерживающая механизм кеширования запросов. Первое обращение к кеширующему DNS-серверу приводит к выполнению рекурсивного запроса: опрашивается сервер более высокого уровня, который, если не знает ответа, передаст запрос дальше. Результат запроса оседает в кеше, так что все последующие обращения именно к этой записи дальше кеширующего сервера не уйдут. Время жизни (Time To Live, TTL) записи в кеше определяется хозяином запрошенного доменного имени. По истечении TTL запись из кеша удаляется.

Такой кеш можно организовать в своей сети с помощью демона pdnsd. pdnsd — только кеширующий демон, он не работает с собственными таблицами (кеш, однако, сохраняется на диске для последующего использования) и не поддерживает передачу зон. Зато он прост в настройке и эксплуатации, а кроме того специально модифицирован для работы с PPP-соединением (например, по модему, когда кеширование любого трафика полезно). Сервер хорошо работает в условиях нескольких вариантов подключения, когда адрес вышестоящего DNS-сервера не остаётся постоянным (например, при использовании нескольких провайдеров поочерёдно). Перед запуском service pdnsd start стоит отредактировать файл /etc/pdnsd.conf, изменив в нём адреса вышестоящих серверов на провайдерские. В /etc/reader.conf первым сервером имён должен быть localhost:

# cat /etc/resolv.conf
domain internal.domain.net
nameserver 127.0.0.1

Вторая задача — именование компьютеров в интранет-сети. Это бывает важно, если среди компьютеров внутренней сети есть свои серверы (например, корпоративный WWW-сервер), к которым другие компьютеры обращаются по доменному имени. Поскольку адреса такой сети не пойдут дальше межсетевого экрана, вы можете использовать имя какого угодно, в том числе — несуществующего — домена и составить табличку в /etc/hosts. Однако раздавать эту табличку лучше всё-таки средствами DNS: например, тот же pdnsd при старте считывает /etc/hosts с помощью команды source в файле настроек.

Обе эти задачи можно было решить и воспользовавшись Bind — мощным полнофункциональным DNS-сервером (обратите внимание, пакет и сервис называются bind, а сам демон — named). Bind — программа весьма сложная (общий объём документации в пакете bind-doc — более полутора мегабайтов, одних RFC поддерживается около сорока), с замысловатой моделью безопасности и долгой историей эксплуатации. Как во всякой сложной программе, в Bind изредка обнаруживаются уязвимости, поэтому в ALT Linux 2.4 Master этот сервер (Bind версии 9) запускается с использованием chroot. В /etc от Bind осталась только символьная ссылка на главный файл настроек, named.conf. Всю свою жизнь named проводит, запертый в /var/lib/bind в качестве корневого каталога. Там у него есть собственный /etc, содержащий (в варианте ALT Linux) целый набор включаемых друг в друга настроечных файлов, /var и даже /dev. Обратите внимание, что все пути к файлам и каталогам в настройках Bind начинаются именно из этого каталога, и /zone соответствует /var/lib/bind/zone.

Для того, чтобы запустить named в кеширующем режиме, достаточно раскомментировать и заполнить раздел настройки forwarders (вышестоящие серверы) в файле /var/lib/bind/etc/options.conf. Обратите внимание на возможные ограничения на право обращаться к серверу с обычными и рекурсивными запросами (настройки allow-query и allow-recursion). Можно раскомментировать находящиеся в этом файле разумные установки по умолчанию. Эти настройки открывают доступ только абонентам локальных сетей, т. е. сетей, к которым компьютер подключён непосредственно.

# grep allow- /var/lib/bind/etc/options.conf
         //      allow-query { localnets; };
         //      allow-recursion { localnets; };

Использование Bind для полноценного именования компьютеров в локальной сети требует создания двух зон (т. н. прямой и обратной), содержащих в виде записей определённого формата информацию о доменных именах компьютеров и об их роли в этих доменах. Каждая зона должна включать запись типа SOA (State Of Authority, сведения об ответственности). В этой записи определяются основные временные и административные параметры домена, в том числе электронный адрес лица, ответственного за домен (администратора) и серийный номер зоны. Серийный номер — число в диапазоне от 0 до 4294967295 (2**32); каждое изменение, вносимое в зону, должно сопровождаться увеличением этого номера. Обнаружив увеличение серийного номера, кеширующие и вторичные серверы признают все закешированные записи из этой зоны устаревшими. Структура номера может быть любой, лишь бы он постоянно увеличивался. Удобно использовать формат годмесяцчисловерсия, где все числа, кроме года, двузначные, а версия может обнуляться раз в день, соответствовать времени (например, по формуле 100*(часы*60+минуты)/(60*24) или иметь сквозную нумерацию (в этом случае появляется сложность с переходом от версии 99 к версии 100, то есть 0). Даже если серийный номер генерируется автоматически, рекомендуется пользоваться этим форматом, наглядно отражающим время создания зоны. Пример зоны, не содержащей ничего, кроме записи SOA, находится в файле /var/lib/bind/zone/empty.

Кроме записи типа SOA, в каждой зоне должна быть хотя бы одна запись типа NS (Name Server), указывающая адрес DNS-сервера, авторитетного в этом домене (как минимум — адрес сервера, на котором запущен named). Несколько зон включаются в настройку Bind автоматически (файл /var/lib/bind/etc/rfc1912.conf). Они нужны для обслуживания сети, привязанной к сетевой заглушке (127.0.0.1/8). Стоит обратить внимание на то, что имя домена, который обслуживается зоной, задаётся в файле настроек, а в самом файле зоны можно использовать _относительную_ адресацию (без . в конце имени), так что операция переименования домена делается редактированием одной строки. В ALT Linux рекомендуется добавлять описания зон в настроечный файл /var/lib/bind/etc/local.conf.

Прямая зона нужна для преобразования доменного имени в IP-адрес — операции, необходимой многим программам постоянно. Большинство записей в прямой зоне — типа A (Address) — предназначены именно для этого. Другие часто встречающиеся типы записей — это CNAME (Canonical Name, настоящее имя), позволяющий привязать несколько дополнительных имён к одному, и MX (Mail eXchange, обмен почтой), указывающий, куда пересылать почтовые сообщения, в поле адресат которых встречается определённое доменное имя. Вот пример прямой зоны для воображаемого домена internal.domain.net (незначащие поля соответствующих файлов заменены на . . .):

# cat /var/lib/bind/etc/local.conf 
 . . .
zone "internal.domain.net" {
        type master;
        file "internal.domain.net";
};
 . . .
# cat /var/lib/bind/zone/internal.domain.net 
$TTL    1D
@       IN      SOA     server root.server (
                                2004082202      ; serial
                                12H             ; refresh
                                1H              ; retry
                                1W              ; expire
                                1H              ; ncache
                        )
        IN      NS      server
                MX 10   server
server          A       10.10.10.1
www             CNAME   server
mail            CNAME   server
jack            A       10.10.10.100
jill            A       10.10.10.101

В этом примере совпадение имени файла и имени зоны случайно, но осмысленно — так проще разбираться с содержимым каталога /var/lib/bind/zone. Используются правила умолчания: если в записи некоторое поле опущено, оно наследуется от предыдущей. Так, вместо A можно было бы всюду написать IN A, а вместо MX — @ IN MX (@ означает имя домена, указанное в файле настройки). Как видно из пример, всю работу в сети делает компьютер с адресом 10.10.10.1, он же server.internal.domain.net, он же www.internal.domain.net и mail.internal.domain.net. Несмотря на наличие среди CNAME этого сервера имени mail, MX-запись указывает всё же не на него, а на действительный адрес — так рекомендовано RFC. Распространённая практика заводить запись типа A непосредственно на имя зоны (т. е. присваивать адрес имени internal.domain.net) приводит, помимо незначительных выгод, к мелким, неочевидным и весьма трудно преодолимым трудностям, которые мы здесь описывать не будем, ограничившись советом не использовать этот — пусть и законный — трюк.

Для того, чтобы превращать IP-адреса в доменные имена у каждой сети должна быть обратная зона. Если такой зоны нет, и в файле /etc/hosts тоже ничего не написано, операция не выполнится. Такое преобразование нужно гораздо реже и в основном по соображениям административным: для того, чтобы выяснить принадлежность компьютера (с которого, допустим, пытаются атаковать сервер) по его IP-адресу. Некоторые почтовые серверы проверяют, содержится ли IP-адрес машины, передающей сообщение, в обратной зоне и похоже ли полученное доменное имя на то, что указано в сообщении, и при несовпадении отказываются принимать письмо. К сожалению, поскольку неудобства, связанные с отсутствием обратной зоны, понятны лишь грамотному администратору, а таковых на просторах Интернета не слишком много, обратные зоны во множестве сетей либо отсутствуют, либо дают неверную информацию. В случае внутренней сети обратная зона необязательна, но желательна — для простоты администрирования и удовлетворения потребностей разных программных продуктов, которые ею пользуются.

Обратная зона состоит почти целиком из записей типа PTR (Pointer, указатель). Чтобы не класть сущностей, решено было не вводить новый способ работы сервера имён и представить обратное преобразование IP-адреса как прямое преобразование доменного имени специального вида. Например, чтобы выяснить доменное имя компьютера с адресом 1.2.3.4, необходимо запросить информацию о доменном имени 4.3.2.1.in-addr.arpa. Таким образом, каждой подсети класса C (или выше) соответствует определённый домен, в котором можно найти ответ. Вот как выглядит обратная зона для нашего воображаемого домена:

# cat /var/lib/bind/etc/local.conf          
 . . .
zone "12.11.10.in-addr.arpa" {
        type master;
        file "12.11.10.in-addr.arpa";
};
 . . .
# cat /var/lib/bind/zone/12.11.10.in-addr.arpa
$TTL    1D
@       IN      SOA     server.internal.domain.net. root.server.internal.domain.net (
                                2004082201      ; serial
                                12H             ; refresh
                                1H              ; retry
                                1W              ; expire
                                1H              ; ncache
                        )
        IN      NS      server.internal.domain.net.
0               PTR     internal.domain.net.
1               PTR     server.internal.domain.net.
100             PTR     jack.internal.domain.net.
101             PTR     jill.internal.domain.net.

Обратите внимание, что относительные адреса, использованные в левой части записей PTR, раскрываются в полные вида адрес.12.11.10.in-addr.arpa, а в правой части используются полные (которые вполне могут указывать на имена в разных доменах).

Проверить синтаксическую правильность надстроечного файла и файла зоны можно с помощью утилит named-checkconf и named-checkzone, входящих в пакет bind. Они же используются при запуске службы командой service bind start. Однако при интенсивной эксплуатации сервера, когда остановка службы нежелательна, можно попросить демон перечитать файлы настроек или определённые зоны с помощью утилиты rndc — вот тогда не стоит забывать о проверке синтаксиса.

Стоит иметь в виду, что, в отличие от прямых зон, обратные описывают административную принадлежность компьютеров, но сами принадлежат хозяину сети (как правило, провайдеру). Возникает особого рода затруднение, связанное с работой DNS-сервера уже не во внутренней сети, а в сети Интернет. Дело в том, что подсети класса C (т. н. сети /24, в которых сетевая маска занимает 24 бита, а адрес компьютера — 8) выдаются только организациям, способным такую подсеть освоить (в сети класса C 254 абонентских IP-адреса, один адрес сети и один широковещательный адрес). Чаще всего выдаются совсем маленькие подсети — от /30 (на два абонентских адреса) до /27 (на 30 адресов) — или другие диапазоны, сетевая маска которых не выровнена по границе байта. Таких подсетей в обратной зоне получится несколько, а возможности просто разделить её, отдав часть адресов в администрирование хозяевам, нет. Грамотный провайдер в таких случаях пользуется RFC2317 (есть в пакете bind-docs), предписывающем в обратной зоне заводить не записи вида PTR, а ссылки CNAME на адреса в «классифицированных» обратных зонах специального вида. Обратное преобразование становится двухступенчатым, зато администрирование каждой классифицированной зоны можно отдать хозяину.

DNS-сервер, отвечающий на запросы из сети Интернет должен быть зарегистрирован в родительском домене. В самом деле, единственный способ узнать, кто обслуживает домен internal.domain.net — спросить об этом у DNS-сервера домена domain.net. Так что о выделении поддомена необходимо договариваться с провайдером. Регистрацией в доменах первого уровня занимаются выделенные организации. Например, домен в зоне .ru необходимо регистрировать в компании АНО «Региональный Сетевой Информационный Центр»" (RU-CENTER).

Правила требуют, чтобы при регистрации домена было указано не менее двух DNS-серверов, которые будут его обслуживать. Из всех зарегистрированных серверов (записей типа NS в родительской зоне) только одна соответствует т. н. первичному (master) серверу, а остальные — т. н. вторичным (slave). Для внешнего пользователя вторичный сервер не отличается от первичного: он столь же авторитетен в ответе на запрос об именах его домена. Отличия только в способе администрирования. Все изменения вносятся в зоны первичного сервера, а вторичный только кеширует эти зоны, целиком получая их по специальному межсерверному протоколу. Полученная зона складывается в файл, редактировать который бессмысленно: первичный сервер при изменении зоны рассылает всем своим вторичным указание скачать её заново. Право на скачивание зоны можно ограничить настройкой allow-transfer (как правило в ней перечисляются адреса вторичных серверов). Вот слегка отредактированная цитата из руководства по Bind, описывающая задание вторичного сервера в файле настроек (в ALT Linux 2.4 Master рекомендуется редактировать local.conf, предварительно установив пакет bind-slave):

// We are a slave server for eng.example.com
zone "eng.example.com" {
     type slave;
     file "slave/eng.example.com";
     // IP address of eng.example.com master server
     masters { 192.168.4.12; };
};

Вторичный сервер хорошо размещать где-нибудь подальше от первичного, во всяком случае, в другой сети — так повышается надёжность обработки запроса (если один сервер недоступен, возможно, ответит второй) и возрастает скорость распространения записей по кешам промежуточных серверов.

Проверку работоспособности, доступности и вообще самочувствия DNS-сервера лучше всего делать утилитой dig из пакета bind-utils. Это очень мощная утилита, выдающая максимум информации о том, что происходило с запросом (запрашивая обратное преобразование, не забудьте добавить ключ -x). Более лаконична, но не менее мощна утилита host из того же пакета. Поминаемую старыми руководствами по UNIX утилиту nslookup использовать не рекомендуется, о чём она сама честно предупреждает.

# dig jack.internal.domain.net  

; <<>> DiG 9.2.4rc5 <<>> jack.internal.domain.net
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32751
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; QUESTION SECTION:
;jack.internal.domain.net.      IN      A

;; ANSWER SECTION:
jack.internal.domain.net. 86400 IN      A       10.11.12.100

;; AUTHORITY SECTION:
internal.domain.net.    86400   IN      NS      server.internal.domain.net.

;; ADDITIONAL SECTION:
server.internal.domain.net. 86400 IN    A       10.11.12.1

;; Query time: 37 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Aug 22 16:07:17 2004
;; MSG SIZE  rcvd: 95

Наконец, для выяснения административной принадлежности тех или иных доменов и сетей можно воспользоваться утилитой whois, которая обращается к специальной сетевой базе данных (не имеющей отношения к DNS).