Настройка tinydns и axfrdns из djbdns в NetBSD

Содержание

Введение

tinydns и axfrdns - это авторитетные серверы DNS из пакета djbdns авторства небезызвестного Дэниела Бернштайна.

tinydns - это UDP-сервер, а axfrdns - это TCP-сервер. Для их запуска будем использовать пакет daemontools, а для ведения журналов - утилиту multilog из этого пакета. Подробнее об установке и использовании пакета и утилиты можно прочитать в статье ?Использование daemontools в NetBSD.

Сборка и установка djbdns

Пропишем в файл /etc/mk.conf опции сборки:

PKG_OPTIONS.djbdns=             -djbdns-cachestats -djbdns-ignoreip2 -djbdns-listenmultiple -djbdns-mergequeries -djbdns-tinydns64

Установим пакет:

# cd /usr/pkgsrc/net/djbdns
# make install

Создание пользователя и группы для tinydns

Создадим группу и пользователя, от имени которых будет работать tinydns:

# groupadd djbdns
# useradd -g djbdns tinydns

Настройка tinydns

Создадим каталог /usr/pkg/etc/tinydns, в котором будут храниться файлы конфигурации tinydns:

# mkdir /usr/pkg/etc/tinydns
# chmod +st /usr/pkg/etc/tinydns

Создадим пустой файл базы данных DNS, скрипты для добавления новых записей в этот файл и Makefile для преобразования базы данных в двоичный вид:

# touch /usr/pkg/etc/tinydns/data
# printf "#!/bin/sh\n\nexec /usr/pkg/bin/tinydns-edit data data.new add alias \${1+\"\$@\"}\n" > /usr/pkg/etc/tinydns/add-alias
# printf "#!/bin/sh\n\nexec /usr/pkg/bin/tinydns-edit data data.new add childns \${1+\"\$@\"}\n" > /usr/pkg/etc/tinydns/add-childns
# printf "#!/bin/sh\n\nexec /usr/pkg/bin/tinydns-edit data data.new add host \${1+\"\$@\"}\n" > /usr/pkg/etc/tinydns/add-host
# printf "#!/bin/sh\n\nexec /usr/pkg/bin/tinydns-edit data data.new add mx \${1+\"\$@\"}\n" > /usr/pkg/etc/tinydns/add-mx
# printf "#!/bin/sh\n\nexec /usr/pkg/bin/tinydns-edit data data.new add ns \${1+\"\$@\"}\n" > /usr/pkg/etc/tinydns/add-ns
# printf "data.cdb: data\n\t/usr/pkg/bin/tinydns-data\n" > /usr/pkg/etc/tinydns/Makefile
# chmod +x /usr/pkg/etc/tinydns/add-*

Настроим запуск tinydns через daemontools:

# mkdir /service/.tinydns
# cat > /service/.tinydns/run <<END
#!/bin/sh

exec 2>&1

exec \
envdir ./env \
envuidgid tinydns \
softlimit -d 3000000 \
/usr/pkg/bin/tinydns
END
# chmod +x /service/.tinydns/run

Зададим переменные окружения для tinydns:

# mkdir /service/.tinydns/env
# echo -n "0.0.0.0" > /service/.tinydns/env/IP
# echo -n "/usr/pkg/etc/tinydns" > /service/.tinydns/env/ROOT

Назначение переменных окружения:

  • IP - IP-адрес, на котором tinydns будет ожидать поступления входящих запросов,
  • ROOT - каталог, который tinydns будет использовать в качестве корневого.

Настроим ведение журналов tinydns с помощью утилиты multilog из пакета daemontools:

# mkdir /service/.tinydns/log
# cat > /service/.tinydns/log/run <<END
#!/bin/sh

exec \
setuidgid multilog \
multilog t /var/log/tinydns/
END
# chmod +x /service/.tinydns/log/run

Создадим каталог /var/log/tinydns/ для журналов tinydns:

# mkdir /var/log/tinydns/
# chown multilog:multilog /var/log/tinydns/

Настройка доменных записей

Прежде всего стоит заметить, что в отличие от других DNS-серверов, данных разных зон в tinydns хранятся в одном файле.

Комментарии

Комментарии можно помещать в строки, начинающиеся с символа #.

Классификация клиентов

Клиентов, обращающихся с запросами к серверу, можно отнести к какому-либо классу. Для этого нужно создать в файле запись следующего вида:

 %lo:ipprefix

Где:

  • lo - обозначение класса,
  • ipprefix - IP-префикс клиентов, соответствующих этому классу.

Например, чтобы отличать локальных клиентов с IP-адресами из сети 192.168.0.0/16 от остальных клиентов, можно добавить в файл две записи:

 %in:192.168
 %ex

Тогда класс in будет соответствовать локальным клиентам, а класс ex будет соответствовать всем остальным, внешним клиентам.

Т.к. каждой записи в базе данных может быть сопоставлен определённый класс, можно создавать записи, которые будут видны только клиентам определённого класса или отдавать клиентам разных классов разные записи. С помощью

Настройка записи SOA

Общий вид записи SOA следующий:

Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:timestamp:lo

Где:

  • Z - тип записи SOA,
  • fqdn - имя доменной зоны,
  • mname - доменное имя первичного сервера имён,
  • rname - почтовый ящик администратора доменной зоны, где первая точка соответствует символу @,
  • ser - серийный номер доменной зоны,
  • ref - время обновления в секундах (по умолчанию 16384 секунд или 4 часа 33 минуты 6 секунд),
  • ret - время повтора в секундах (по умолчанию 2048 секунд или 34 минуты 8 секунд),
  • exp - время истечения срока действия в секундах (по умолчанию 1048576 секунд или 12 дней 3 часа 16 минут 16 секунд),
  • min - минимальное время в секундах (по умолчанию 2560 секунд или 42 минуты 40 секунд),
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300, а значение меньше 2 для записей типа NS может привести к проблемам поиска по имени),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Поля ref, ret, exp, min могут быть не указаны. В таком случае будут использоваться значения по умолчанию.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

При получении копии зоны от другого сервера SOA-запись будет иметь следующий вид:

Zstupin.su:ns1.stupin.su.:vladimir.stupin.su.:2022010601:10800:3600:604800:3600:10800

Можно попытаться сопоставить её с оригинальным определением:

$TTL 3h
stupin.su. IN SOA ns1.stupin.su. vladimir.stupin.su. 2022010601 3h 1h 1w 1h

Стоит заметить, что этот тип записей предназначен только для зон, скопированных с другого сервера имён. Для определения SOA-записей более естественным для tinydns способом стоит воспользоваться следующим разделом, где описана настройка NS-записей.

Настройка записей NS

Общий вид определения NS-записи вместе с SOA-записью:

.fqdn:ip:x:ttl:timestamp:lo

Определение NS-записи без SOA-записи:

&fqdn:ip:x:ttl:timestamp:lo

Где:

  • . - тип записи NS вместе с SOA-записью. Применяется для доменных зон, делегированных серверу,
  • & - тип записи NS. Применяется для делегирования доменных зон другим серверам,
  • fqdn - имя доменной зоны,
  • ip - IP-адрес сервера имён. Если указан, то будет создана A-запись, созданная из этого IP-адреса и имени сервера, указанного в поле x,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300, а значение меньше 2 для записей типа NS может привести к проблемам поиска по имени),
  • x - имя сервера имён. Если в имени есть точка, то это полное имя сервера. Если точки нет, то имя сервера имён будет иметь вид x.ns.fqdn,
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей A

Для настройки A-записи вместе с PTR-записью используется следующий формат:

=fqdn:ip:ttl:timestamp:lo

Для настройки дополнительных A-записи или A-записей без PTR-записи используется следующий формат:

+fqdn:ip:ttl:timestamp:lo

Для временно отключенных записей используется следующий формат:

-fqdn:ip:ttl:timestamp:lo

Где:

  • = - тип записи A вместе с PTR-записью,
  • + - тип записи A,
  • - - временно отключенная A-запись,
  • fqdn - доменное имя,
  • ip - IP-адрес,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей MX

Для настройки MX-записей используется следующий формат:

@fqdn:ip:x:dist:ttl:timestamp:lo

Где:

  • @ - тип записи MX,
  • fqdn - доменное имя почтового сервера,
  • ip - IP-адрес почтового сервера. Если указан, то будет создана A-запись, созданная из этого IP-адреса и имени сервера, указанного в поле x,
  • x - имя почтового сервера. Если в имени есть точка, то это полное имя сервера. Если точки нет, то имя сервера имён будет иметь вид x.mx.fqdn,
  • dist - дистанция до почтового сервера. Если не указана, то используется значение 0,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей PTR

Формат файла таков, что PTR-записи можно определять вместе с A-записями с префиксом =. Но при необходимости можно определить PTR-запись отдельно, следующим образом:

^fqdn:ip:ttl:timestamp:lo

Где:

  • ^ - тип записи PTR,
  • fqdn - доменное имя, на которое будет указывать PTR-запись,
  • ip - IP-адрес PTR-записи,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей CNAME

Вместо определения CNAME-записей лучше определить дополнительные A-записи с помощью префикса +. Но если вам всё-таки по каким-то неизвестным причинам понадобится создать CNAME-записи, то определить их можно следующим образом:

Cfqdn:p:ttl:timestamp:lo

Где:

  • ^ - тип записи CNAME,
  • fqdn - ссылающееся доменное имя,
  • p - целевое доменное имя,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей TXT

Для добавления записей типа TXT предусмотрен следующий формат:

'fqdn:s:ttl:timestamp:lo

Где:

  • ' - тип записи TXT,
  • fqdn - доменное имя,
  • s - текст, соответствующий доменному имени. В тексте поддерживается возможность указать символ при помощи его восмеричного кода в виде \nnn, например, \072 для двоеточия,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей SRV

По ссылке djbdns tools by Rob Mayoff можно найти Perl-скрипт для создания SRV-записей в формате djbdns и справку по использованию этого скрипта.

По ссылке 030-srv-records-and-axfrget.patch можно найти патч, добавляющий в djbdns поддержку записей типа SRV.

По ссылке Integrated the SRV+NAPTR ancient patch можно найти патч, добавляющий в djbdns поддержку записей типа SRV и NAPTR. По ссылке Added documentation of the patch можно найти документацию к этому патчу.

Формат SRV-записи, добавляемый патчем:

Sfqdn:ip:x:port:weight:priority:ttl:timestamp

Где:

  • S - тип записи SRV,
  • fqdn - доменное имя сервера,
  • ip - IP-адрес сервера. Если указан, то будет создана A-запись, созданная из этого IP-адреса и имени сервера, указанного в поле x,
  • x - имя сервера. Если в имени есть точка, то это полное имя сервера. Если точки нет, то имя сервера имён будет иметь вид x.srv.fqdn,
  • ttl - время жизни записи в секундах (учтите, что некоторые кэширующие серверы воспринимают значение меньше 300 как 300),
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Если в поле ttl указан 0, то в поле timestamp указано время окончания действия записи. Если значение в поле ttl не нулевое или отсутствует, то в поле timestamp указано время начала действия записи.

Настройка записей NAPTR

Формат записи, добавляемой патчем:

Nfqdn:order:pref:flags:service:regexp:replacement:ttl:timestamp

Где:

  • S - тип записи SRV,
  • fqdn - доменное имя сервера,
  • order -
  • pref -
  • flags -
  • service -
  • regexp -
  • replacement -
  • timestamp - отметка времени в формате TAI64,
  • lo - класс клиента, для которого действительна эта запись.

Запуск и проверка tinydns

Запустим сервис:

# mv /service/.tinydns /service/tinydns

Проверить, что он действительно запустился, можно с помощью команды следующего вида:

# netstat -anf inet | fgrep .53
udp        0      0  *.53                   *.*     

Проверить, что axfrdns отвечает на TCP-запросы, можно, например, с помощью утилиты dig:

$ dig stupin.su @192.168.252.5 -t A

Получение копии зоны с помощью axfr-get

Для получения копии зоны с удалённого DNS-сервера по протоколу AXFR можно воспользоваться командой такого вида:

$ tcpclient -l localhost -RH 192.168.252.1 53 axfr-get stupin.su data1 data1.tmp

Где:

  • 192.168.252.1 - IP-адрес удалённого DNS-сервера,
  • 53 - TCP-порт удалённого DNS-сервера,
  • stupin.su - доменная зона, копию которой нужно получить,
  • data1 - имя файла, в который нужно поместить копию зоны,
  • data1.tmp - имя временного файла, который будет использоваться в процессе приёма копии зоны до тех пор, пока она не будет принята полность.

В команде также фигурируют неочевидные опции -l localhost -RH. У меня ушло некоторое время, чтобы понять, почему получение копии не работало. Подключение устанавливалось с большой задержкой, а затем закрывалось по таймауту ожидания данных. Оказалось, что tcpclient пытается узнать доменные имена участвующих в обмене сторон по их IP-адресам, чтобы присвоить эту информацию переменным окружения TCPLOCALHOST, TCPREMOTEHOST и TCPREMOTEINFO и передать их axfr-get. Этой информации не было в DNS, кэширующий сервер dnscache отвечал с большой задержкой и сообщением об ошибке, а tcpclient пытался повторить запросы. В результате установка связи затягивалась, а удалённый DNS-сервер, так и не дождавшись запроса, просто закрывал подключение.

Создание пользователя для axfrdns

На этапе настройки tinydns нами уже была создана группа djbdns, воспользуемся ей. Остаётся только создать пользователя, от имени которого будет работать axfrdns:

# useradd -g djbdns axfrdns

Настройка axfrdns

Создадим файл /usr/pkg/etc/axfrdns/tcp, содержащий правила ограничения доступа к axfrdns по IP-адресу клиента, и файл /usr/pkg/etc/tinydns/Makefile для компиляции этих правил в двоичный вид в файл /usr/pkg/etc/axfrdns/tcp.cdb:

# mkdir /usr/pkg/etc/axfrdns
# printf "# sample line:  1.2.3.4:allow,AXFR=\"heaven.af.mil/3.2.1.in-addr.arpa\"\n:deny\n" > /usr/pkg/etc/axfrdns/tcp
# printf "tcp.cdb: tcp\n\ttcprules tcp.cdb tcp.tmp < tcp" > /usr/pkg/etc/axfrdns/Makefile

Настроим запуск axfrdns через daemontools:

# mkdir /service/.axfrdns
# cat > /service/.axfrdns/run <<END
#!/bin/sh

exec 2>&1

exec \
envdir ./env \
envuidgid axfrdns \
softlimit -d 300000 \
tcpserver -vDRHl0 -x /usr/pkg/etc/axfrdns/tcp.cdb -- 0.0.0.0 53 \
/usr/pkg/bin/axfrdns
END
# chmod +x /service/.axrfdns/run

Обратите внимание, что IP-адрес, на котором axfrdns будет ожидать входящих подключений, указывается в скрипте /service/.axfrdns/run. В примере выше это адрес 0.0.0.0, то есть входящие подключения будут ожидаться на всех локальных IP-адресах.

Зададим переменную окружения ROOT, в которой поместим путь к каталогу, который axfrdns будет использовать в качестве корневого:

# mkdir /service/.axfrdns/env
# echo -n "/usr/pkg/etc/tinydns" > /service/.axfrdns/env/ROOT

Настроим ведение журналов axfrdns с помощью утилиты multilog из пакета daemontools:

# mkdir /service/.axfrdns/log
# cat > /service/.axfrdns/log/run <<END
#!/bin/sh

exec \
setuidgid multilog \
multilog t /var/log/axfrdns/
END
# chmod +x /service/.axfrdns/log/run

Создадим каталог /var/log/axfrdns/ для журналов axfrdns:

# mkdir /var/log/axfrdns/
# chown multilog:multilog /var/log/axfrdns/

Настройка разрешений на передачу зон

Для того, чтобы с любого IP-адреса можно было выполнять запросы единичных записей по протоколу TCP, нужно поместить в файл /usr/pkg/etc/axfrdns/tcp такую строчку:

:allow,AXFR=""

Для того, чтобы позволить IP-адресу 192.168.252.1 полное копирование зоны stupin.su, нужно добавить в файл /usr/pkg/etc/axfrdns/tcp такую строчку:

192.168.252.1:allow,AXFR="stupin.su"

Для разрешения передачи нескольких зон их можно перечислить через косую черту, вот так:

192.168.252.1:allow,AXFR="stupin.su/kuramshin.me/252.168.192.in-addr.arpa/253.168.192.in-addr.arpa/254.168.192.in-addr-arpa"

Для того, чтобы разрешить передавать указанному IP-адресу любую имеющуюся зону, нужно опустить атрибут AXFR полностью:

192.168.252.1:allow

После редактирования файла не забудьте выполнить в каталоге /usr/pkg/etc/axfrdns команду make:

# make

Изменения вступаю в силу немедленно, перезапуск сервиса axfrdns при этом не требуется.

Запуск и проверка axfrdns

Запустим сервис:

# mv /service/.axfrdns /service/axfrdns

Проверить, что он действительно запустился, можно с помощью команды следующего вида:

# netstat -anf inet | fgrep .53
tcp        0      0  *.53                   *.*                    LISTEN
udp        0      0  *.53                   *.*                   

Как видно, теперь кроме UDP-сокета прослушивается ещё и TCP-сокет.

Проверить, что axfrdns отвечает на TCP-запросы, можно, например, с помощью утилиты dig:

$ dig stupin.su @192.168.252.5 +tcp -t MX

Проверить передачу зоны можно следующим образом:

$ dig stupin.su @192.168.252.5 +tcp -t AXFR

Дополнительные материалы