Установка и настройка DNS сервера NSD под FreeBSD


Автор: terminus.

Раньше, по долгу службы, приходилось администрировать DNS сервера. И вот недавно вновь появилась такая необходимость — надо было настроить два авторитарных DNS (master + slave) для обслуживания зоны. Сервера должны были смотреть в интернет. Задача — запустить зону и обеспечить автоматическую, секюрную репликацию от master (192.168.0.1) к slave (192.168.0.2).

В качестве ОС однозначно решил использовать FreeBSD 7.0 RELEASE, а вот с выбором DNS сервера для такого ответственного задания, все было не так просто... Дело в том, что BIND я не считаю за DNS сервер которому можно было бы доверить держать зону выставленную в интернет. Это мое субъективное мнение. Просто я стараюсь держаться подальше от софта в котором с периодичностью раз в пол года находят дыры позволяющие удаленно заражать кеш, не говоря уже о проблемах с его производительностью. Был вариант использовать любимый и проверенный временем пакет djbdns (tinydns), но опять же что-то меня остановило. Все хорошо в софте от djb, но развития больше нет — не пишет djb обновлений ни для djbdns ни для qmail, да и как то не хотелось снова замарачиваться с настройкой daemontools.

Выбор пал на авторитарный DNS сервер NSD. Честно сказать я давно присматривался с этому серверу. Недавно снова обратил свое внимание, когда вышел его брат, DNS ресольвер Unbound. Почитав мануалы на оба этих продукта, пришел в выводу, что не все так грустно в мире DNS, и что у djbdns появилась достойная замена.

С архитектурной точки зрения NSD — это исключительно авторитарный DNS сервер. Он не обслуживает рекурсивные клиентские запросы и ни чего не кеширует. Так же из плюсов стоит отметить его маленькие размеры, скромное потребление ресурсов и большую скорость работы. На счет показателей скорости, сошлюсь на результаты тестов которые не так давно проводил Kris Kennaway http://people.freebsd.org/~kris/scaling/bind-nsd.png Подсчитать же количество потребляемых ресурсов, исходя из размеров зоны, можно здесь: http://www.nlnetlabs.nl/projects/nsd/nsd-memsize.html

Что же касается минусов, то стоит отметить ограниченную функциональность. Нет никаких view'ов — хочешь чтобы кто-то видел зону так, а кто-то другой по-другому - запускай второй NSD с его данными и разруливай доступ на фаерволе. Нет динамических обновлений. Нет точной статистики по загруженности — только аналог BIND'овских NSTATS и XSTATS которые выводятся в лог файл (зато в последнюю версию BIND аж, таки свой веб сервер встроили чтобы статистику показывать). Если нужна детальная статистика того кто, что и сколько — разработчики предлагают использовать для этого сторонние утилиты для прямого анализа трафика сервера.

В общем быстрого взгляда на опции конфигурации достаточно чтобы понять, что можно сделать с помощью NSD, а что не выйдет. Опций мало, все очень просто.

Так или иначе, мне BIND'овских извращений не надо. Мне надо чтобы работало.

Решено — ставим NSD!


Установка

На момент написания этой статьи, в портах была доступна версия 3.0.7. На всякий случай упомяну процедуру обновления портов. Для версий FreeBSD начиная с 6.2, это удобно делать через portsnap:# portsnap fetch
# portsnap extract


После обновления портов, ставим NSD традиционным методом: # cd /usr/ports/dns/nsd
# make install clean


При первой установке, порт предлагает выбрать несколько опций конфигурации. По-умолчанию выбран вполне разумный набор, с которым можно согласиться. Опции же такие: Options for nsd 3.0.7
[ ] ROOT_SERVER Configure NSD as a root server
[X] LARGEFILE Enable support for large files
[X] IPV6 Enable IPv6 support
[X] DNSSEC Enable DNSSEC
[ ] BIND8_STATS Enable BIND8 like NSTATS & XSTATS
[ ] CHECKING Enable internal runtime checks
[X] TSIG Enable TSIG support
[ ] NSEC3 Enable NSEC3 support
[ ] NSID Enable NSID support
[X] DOCFILES Enable PORTDOCS


ROOT_SERVER — по-умолчанию NSD не разрешает запускать на себе корневую зону. Опция включает такую функциональность.

LARGEFILE - не берусь прокомментировать. В README эта опция описана как "Disable large file support (64 bit file lengths). Makes off_t a 32bit length during compilation" По-умолчанию включена.

DNSSEC - включает функциональность позволяющую подписывать DNS сообщения между серверами на основе шифрования с открытым ключом и использовать другие возможности DNSSEC.

CHECKING - полезно для debug, дополнительные внутренние проверки во время работы. Снижает производительность.

TSIG - включает функциональность позволяющую подписывать DNS сообщения между серверами на основе шифрования с общим симметричным ключом.

NSEC3 - экспериментальное расширение DNSSEC (непонялчтотакое =) не надо в общем)

NSID - экспериментальное расширение позволяющее вставлять в каждый ответ DNS сервера метку однозначно идентифицирующую DNS сервер. Используется для debug.

DOCFILES - в /usr/loca/share/doc/nsd будет установлен набор полезных руководств.

Компиляция происходит очень быстро — сервер маленький. Через пару минут порт будет собран и установлен.

Файлы устанавливаемые портом:/usr/local/sbin
/usr/local/etc/nsd
/usr/local/man
/usr/local/man/man8
/usr/local/man/man5
/usr/local/sbin/nsd
/usr/local/sbin/zonec
/usr/local/sbin/nsdc
/usr/local/sbin/nsd-notify
/usr/local/sbin/nsd-checkconf
/usr/local/sbin/nsd-patch
/usr/local/sbin/nsd-xfer
/usr/local/man/man8
/usr/local/man/man8
/usr/local/man/man8
/usr/local/man/man8/nsd-notify.8
/usr/local/man/man8/nsd-checkconf.8
/usr/local/man/man8/nsd-patch.8
/usr/local/man/man8/nsd-xfer.8
/usr/local/man/man5/nsd.conf.5
/usr/local/etc/nsd/nsd.conf.sample
/usr/local/etc/rc.d/nsd.sh
/usr/local/share/doc/nsd/CREDITS
/usr/local/share/doc/nsd/ChangeLog
/usr/local/share/doc/nsd/LICENSE
/usr/local/share/doc/nsd/NSD-DATABASE
/usr/local/share/doc/nsd/NSD-DIFFFILE
/usr/local/share/doc/nsd/NSD-FOR-BIND-USERS
/usr/local/share/doc/nsd/README
/usr/local/share/doc/nsd/README.icc
/usr/local/share/doc/nsd/RELNOTES
/usr/local/share/doc/nsd/REQUIREMENTS
/usr/local/share/doc/nsd/TESTPLAN
/usr/local/share/doc/nsd/TODO
/usr/local/share/doc/nsd/UPGRADING
/usr/local/share/doc/nsd/coding-style
/usr/local/share/doc/nsd/differences.tex


Установленные инструменты:nsd - the daemon itself
nsdc - a shell script to control the daemon
zonec - zone compiler
nsd-notify - a simple C program to send outbound notifies
nsd-xfer - a program to receive zones from a master server using AXFR
from the command line.
nsd-checkconf - simple C program to check nsd.conf before use.
nsd-patch - simple program that cleans IXFR changes back to zone files.


Главные инструменты с чем придется работать:nsdc - главный интерфейс для локального управления демоном
(аналог BIND'овской ndc)
nsd-checkconf - проверяет корректность конфигурации nsd.conf

# nsdc
Usage: nsdc [-c configfile] {start|stop|reload|rebuild|restart|
running|update|notify|patch}
options:
-c configfile Use specified configfile (default: /usr/local/etc/nsd/nsd.conf)
commands:
start Start nsd server.
stop Stop nsd server.
reload Nsd server reloads database file.
rebuild Compile database file from zone files.
restart Stop the nsd server and start it again.
running Prints message and exit nonzero if server not running.
update Try to update all slave zones hosted on this server.
notify Send notify messages to all secondary servers.
patch Merge zone transfer changes back to zone files.


В процессе установки не создается никаких новых пользователей. NSD сразу же компилится так, чтобы запускаться от имени пользователя bind который уже присутствует в системе

Это все, что касается установки из порта. Далее, идет настройка.


Настройка

Как и каждый правильный демон, NSD требует к себе уважения. Это означает, что его хозяину надо прочитать man nsd.conf, составить этот nsd.conf и составить файлы данных зон. Синтаксис nsd.conf (файла конфигурации NSD) отличается от того, что принято в BIND. Синтаксис файлов зон такой же как и в BIND. NSD может работать в chroot окружении. Я поленился делать jail для запуска NSD и для большей секюрности решил использовать этот chroot. По умолчанию chroot не задействован.


Далее пошаговое описание настроек сделаных на master сервере

Стартовый скрипт запуска /usr/local/etc/rc.d/nsd.sh подправляем, для того чтобы указать на новое расположение nsd.pid:##pidfile=/var/run/${name}.pid
pidfile=/usr/local/etc/nsd/run/${name}.pid


В /usr/local/etc/nsd создаем поддиректории со следующими правами доступа:[root@master /usr/local/etc/nsd]# ls -la
drwxr-xr-x 5 root wheel 512 Jun 24 18:22 .
drwxr-xr-x 5 root wheel 512 Jun 24 11:35 ..
drwxrwx--- 2 root bind 512 Jun 24 13:38 data
-r--r----- 1 root wheel 935 Jun 24 13:28 nsd.conf
drwxrwx--- 2 root bind 512 Jun 24 16:07 run
drwxr-x--- 4 root bind 512 Jun 24 11:50 zones


Права доступа для ./data такие, потому, что пользователь bind будет писать в нее.
На работающем master сервере там автоматически создаются файлы:-rw-r--r-- 1 root bind 677 Jun 24 13:38 nsd.database
-rw-r--r-- 1 bind bind 1524 Jun 24 14:24 xfrd.state


В директорию ./run на работающем сервере, будет писаться pid-rw-r--r-- 1 bind bind 5 Jun 24 16:07 nsd.pid


Директория zones содержит:drwxr-x--- 2 root bind 512 Jun 24 13:39 master
drwxr-x--- 2 root bind 512 Jun 24 12:37 slave


Директория slave тут пустая, а в директории master создан файл с именем зоны:-rw-r--r-- 1 root bind 1163 Jun 24 13:38 domain.su


Создаем случайный общий ключ который будет использоваться в TSIG подписях при передаче зон между master и slave. Делаем это так:# dd if=/dev/urandom bs=16 count=1 2>/dev/null | openssl base64
KSVb40kv/CuHgTTvhKZ7Y5==


Конфигурационный файл nsd.conf на master такой:server:
chroot: "/usr/local/etc/nsd"
ip-address: 0.0.0.0
ip4-only: yes
database: "/usr/local/etc/nsd/data/nsd.database"
logfile: "/var/log/nsd.log"
server-count: 5
pidfile: "/usr/local/etc/nsd/run/nsd.pid"
zonesdir: "/usr/local/etc/nsd/zones"
difffile: "/usr/local/etc/nsd/data/ixfr.db"
xfrdfile: "/usr/local/etc/nsd/data/xfrd.state"

key:
name: "master-slave.domain.su"
algorithm: hmac-md5
secret: "KSVb40kv/CuHgTTvhKZ7Y5=="

zone:
name: "domain.su"
zonefile: "./master/domain.su"
notify: 192.168.0.2 master-slave.domain.su
provide-xfr: 192.168.0.2 master-slave.domain.su


Файл зоны domain.su на master такой (примерно):$TTL 1800 ;minimum ttl
domain.su. IN SOA ns1.domain.su. hostmaster.domain.su. (
2008062414 ;serial
3600 ;refresh
9600 ;retry
180000 ;expire
600 ;negative ttl
)

NS ns1.domain.su.
NS ns2.domain.su.
MX 10 mail
A 127.0.0.24

ns1 A 192.168.0.1
ns2 A 192.168.0.2
www A 127.0.0.24
ftp A 127.0.0.26
mail A 127.0.0.27


После создания nsd.conf и файла зоны, необходимо выполнить:# nsd-checkconf /usr/local/etc/nsd/nsd.conf


Если нет сообщений об ошибках то создаем базу nsd.database в которой собственно и будут храниться данные о записях зоны:# nsdc rebuild
zonec: reading zone "domain.su".
zonec: processed 8 RRs in "domain.su".
zonec: done with 0 errors.


После этого база /usr/local/etc/nsd/data/nsd.database будет создана.

Вносим в /etc/rc.conf строку nsd_enable="YES" и запускаем сервер: # /usr/local/etc/rc.d/nsd.sh start


После этого создадутся файлы:/usr/local/etc/nsd/run/nsd.pid
/usr/local/etc/nsd/data/xfrd.state
/var/log/nsd.log


Все в порядке — master работает. Стоит проверить ps auxw, /var/log/nsd.log, а так же через nslookup поспрашивать новый сервер и убедиться, что все ок.


Далее пошаговое описание настроек сделаных на slave сервере

Стартовый скрипт запуска /usr/local/etc/rc.d/nsd.sh подправляем для того, чтобы указать на новое расположение nsd.pid:##pidfile=/var/run/${name}.pid
pidfile=/usr/local/etc/nsd/run/${name}.pid


В /usr/local/etc/nsd создаем поддиректории со следующими правами доступа:[root@slave /usr/local/etc/nsd]# ls -la
drwxr-xr-x 5 root wheel 512 Jun 24 18:22 .
drwxr-xr-x 5 root wheel 512 Jun 24 11:35 ..
drwxrwx--- 2 root bind 512 Jun 24 13:38 data
-r--r----- 1 root wheel 935 Jun 24 13:28 nsd.conf
drwxrwx--- 2 root bind 512 Jun 24 16:07 run
drwxr-x--- 4 root bind 512 Jun 24 11:50 zones


Права доступа для ./data такие потому, что пользователь bind будет писать в нее. На работающем slave сервере там автоматически создаются файлы:-rw-r--r-- 1 bind bind 604 Jun 24 19:09 ixfr.db
-rw-r--r-- 1 root bind 677 Jun 24 13:38 nsd.database
-rw-r--r-- 1 bind bind 1524 Jun 24 14:24 xfrd.state


В директорию ./run на работающем сервере, будет писаться pid-rw-r--r-- 1 bind bind 5 Jun 24 16:07 nsd.pid


Директория zones содержит:drwxr-x--- 2 root bind 512 Jun 24 13:39 master
drwxr-x--- 2 root bind 512 Jun 24 12:37 slave


Обе директории master и slave пока пустые:


Конфигурационный файл nsd.conf на slave такой:server:
chroot: "/usr/local/etc/nsd"
ip-address: 0.0.0.0
ip4-only: yes
database: "/usr/local/etc/nsd/data/nsd.database"
logfile: "/var/log/nsd.log"
server-count: 5
pidfile: "/usr/local/etc/nsd/run/nsd.pid"
zonesdir: "/usr/local/etc/nsd/zones"
difffile: "/usr/local/etc/nsd/data/ixfr.db"
xfrdfile: "/usr/local/etc/nsd/data/xfrd.state"

key:
name: "master-slave.domain.su"
algorithm: hmac-md5
secret: "KSVb40kv/CuHgTTvhKZ7Y5=="

zone:
name: "domain.su"
zonefile: "./slave/domain.su"
allow-notify: 192.168.0.1 master-slave.domain.su
request-xfr: AXFR 192.168.0.1 master-slave.domain.su


После создания nsd.conf и файла зоны, необходимо выполнить:# nsd-checkconf /usr/local/etc/nsd/nsd.conf


Если нет сообщений об ошибках то создаем базу nsd.database в которой собственно и будут храниться данные о записях зоны:# nsdc rebuild
zonec: reading zone "domain.su".
warning: slave zone domain.su with no zonefile './slave/domain.su'
(No such file or directory) will force zone transfer.
zonec: processed 0 RRs in "domain.su".
zonec: done with 0 errors.


После этого база /usr/local/etc/nsd/data/nsd.database будет создана

Вносим в /etc/rc.conf строку nsd_enable="YES" и запускаем сервер:# /usr/local/etc/rc.d/nsd.sh start


После этого создадутся файлы:/usr/local/etc/nsd/run/nsd.pid
/usr/local/etc/nsd/data/xfrd.state
/var/log/nsd.log


Все в порядке — slave работает. Стоит проверить ps auxw и /var/log/nsd.log.


Последний шаг чтобы убедиться, что репликация между master и slave происходит как надо - заходим на master, открываем текстовый файл зоны /usr/local/etc/nsd/zones/master/domain.su и меняем там строку с серийным номером. Сохраняем файл зоны и выполняем:# nsdc rebuild
# nsdc reload


Эта процедура пересоздает базу nsd.database на master (вносит туда изменения из отредактированного файла зоны) и отправляет сообщение NOTIFY на slave. Получив такое сообщение, slave запросит произвести AXFR передачу с master (192.168.0.1) и сохранит полученные данные в ixfr.db. Это важный момент! На slave база ixfr.db является своего рода логом транзакций полученных с master. Сразу после этого slave может обслуживать запросы. Текстовые данные пока еще НЕ созданы в файле ./zones/slave/domain.su

Последний штрих который необходимо сделать на slave сервере — внести в crontab root'a выполнение такой команды:5 5 * * * root /usr/local/sbin/nsdc patch


Команда nsdc patch выполняет две операции:
1 Переносит данные из лога ixfr.db в базу nsd.database, после чего удаляет лог.
2 Создает текстовые файлы с данными зоны в ./zones/slave/domain.su


Можно было бы не писать, но все же упомяну - все дальнейшие изменения в записях зоны вносятся в текстовый файл ./zones/master/domain.su на master сервере, после чего для перестройки базы и ее репликации на slave, выполняется тот же самый цикл команд:# nsdc rebuild
# nsdc reload


Замечания

Почитав файлы README и NSD-FOR-BIND-USERS из комплекта поставки NSD удалось просветлиться по поводу таких моментов:

То, является ли зона типа master или типа slave определяется директивой request-xfr - у master ее нет, у slave она должна быть.

NSD master не поддерживает инкрементные передачи IXFR, поддерживаются только полные AXFR передачи. Если мастер (как в данном примере) работает под NSD, то в конфиге slave появляется request-xfr: AXFR 192.168.0.1 master-slave.domain.su

Директива provide-xfr на master эквивалентна директивам allow-transfer и server для BIND

В BIND ассоциация TSIG ключей происходит с IP сервера с которым производится коммуникация. В NSD TSIG ключи ассоциируются с ALC записями и соответствующие ключи используются при проведении различных запросов/ответов. Таким образом при работе с одним сервером можно применять одни ключи для оповещении о изменении зоны, и другие ключи при передаче данных зоны (своя пара для notify; allow-notify и своя для provide-xfr; request-xfr)!

На TSIG запросы отсылаются TSIG ответы.

В отличии от BIND, где адреса slave серверов определяются непосредственно из данных зоны (какие NS там указаны, такие значит у зоны slave), в NSD это определяется только из настроек в nsd.conf (кто указан в параметрах notify - тот и slave).

xfrd.state - файл-состояния используемый на slave для отслеживания истечения срока годности записей slave зоны.

Обновлено: 12.03.2015