Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> программы —> DNS сервер Unbound

Установка и настройка DNS сервера Unbound

Автор: terminus.


Версия статьи 2.2.1

В предыдущей заметке мною был описан процесс установки авторитарного DNS сервера NSD. В этой статье хочу описать установку и настройку кеширующего DNS сервера Unbound. Установка проводилась на FreeBSD 7.0. Мотив написания обоих заметок — это попытка отказаться от необходимости использования гламурного BIND, и поиск новых решений на смену устаревающих.

В случае с обслуживанием рекурсивных клиентских запросов в качестве альтернативы BIND'у можно рассматривать тот же самый djbdns (dnscache) со всеми его традиционными плюсами и минусами. Но, как ни крути — это и есть то самое устаревающее решение. Поэтому захотел расширить свои знания освоив Unbound.

Unbound это кеширующий DNS сервер который обслуживает исключительно рекурсивные запросы. Во время работы сервера кеш целиком распологается в памяти, а его размер ограничен указанным объемом. Unbound поддерживает расширения DNSSEC и может работать как "validator" (в конце статьи будет пример настройки Unbound в роли "validator iterator" для тех кто захочит задействовать функциональность проверки DNSSEC сигнатур). В качестве плюсов Unbound по сравнению с BIND надо отметить все те же скромные размеры и скорость. На официальном сайте проекта приведена следующая сравнительная информация по скорости работы популярных DNS серверов:
Server      Queries/sec (10 clients)
Unbound             8 276
MaraDNS             3 068
BIND                3 003
dnscache            2 928
PowerDNS Recursor   2 074

Результаты были получены для версии Unbound 1.0. Как видно, имеет место почти трехкратное превосходство над BIND - за те же деньги и на том же железе можно прокачать через себя в три раза больше клиентских запросов!

Детальный список фич и возможностей unbound после установки можно будет прочитать в файле /usr/local/share/doc/unbound/FEATURES.


Установка

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

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

При первой установке, порт предлагал выбрать такие опции конфигурации:
     Options for unbound-1.2.0
[ ] LIBEVENT  is useful when using many (10000) outgoing ports
[X] THREADS   build with threads support

Необходимо детально описать о чем идет речь.

При проведении разрешения имен которых еще нет в кеше сервера, а значит при необходимости обращаться к внешним авторитарным DNS серверам, Unbound отсылает исходящие запросы используя множество UDP портов из разрешенного диапазона. Это сделано для обеспечения дополнительной безопасности чтобы было труднее угадать с какого порта был отправлен запрос и затруднить возможность атак с целью отравления записей в кеше. Позже, в примере файла конфигурации это будет отражено - опция outgoing-range: 512 указывает, сколько UDP портов для этой цели разрешено использовать одному потоку (thread) сервера.

Каждый открытый сервером UDP или TCP порт, потребляет один файловый дескриптор. Серверу Unbound необходимо иметь возможность работать со всеми открытыми дескрипторами. Сам Unbound содержит в себе некий builtinmini-event обработчик, который и используется для этого. Встроенный обработчик способен обслуживать максимум 1024 открытых файловый дескрипторов на один процесс сервера.

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

Если же отказаться от опции THREADS, то сервер будет собран без потоков (фактически с одним потоком на процесс) и будет происходить форканье процессов, что есть практически параллельный запуск нового сервера со своим собственным кешем. Минус такого подхода - это увеличение требований к памяти. Плюс этого метода работы - увеличение скорости на 10-20 %.

Таким образом, если наш сервер будет собран с поддержкой потоков THREADS, и мы захотим использовать восемь потоков (опция конфигурации num-threads: 8), то при установленных outgoing-range: 512, в сумме это даст 512*8=4096 одновременно открытых файловых дескрипторов, что превышает возможности встроенного обработчика. Unbound не захочет стартовать и выведет сообщение об ошибке. Проблема. (Кривое решение проблемы - это снизить значение outgoing-range, но делать этого не стоит так как это уменьшает секюрность). Для правильного решения этой проблемы, разработчики Unbound предлагают использовать специальные сторонние обработчики, такие как например libevent или libev. Выбор опции LIBEVENT приведет к установке дополнительного порта libevent 1.4.8 и линковке с ним Unbound.

Если же мы откажемся от использования потоков и соберем Unbound без THREADS, и без ненужного теперь LIBEVENT, то при использовании той же опции конфигурации num-threads: 8, мы получим восемь процессов Unbound каждый из которых будет иметь свой кеш и использовать только 512 файловых дескрипторов управляемых встроенным обработчиком.

До выхода unbound 1.2.0 в нем сушествовала неприятная ошибка - при одновременном использовании модели на основе потоков и обработчика libevent между потоками сервера могло возникнуть состояние гонки (race condition). Это приводило к нестабильной работе и даже падениям сервера. К счатью эту ошибку нашли и исправили, и теперь ничто не мешает использовать все преимущества связки unbound+libevent.

Таким образом, возврашаясь к выбору опций предлагаемых портом - оптимальным является вариант использования потоков в связке с libevent. Это позволит без проблем масштабировать производительность сервера и экономить выделенные ресурсы оперативной памяти.

Выбираем опции:
     Options for unbound-1.2.0
[X] LIBEVENT  is useful when using many (10000) outgoing ports
[X] THREADS   build with threads support

На машине Pentium4 2,53GHz сборка порта заняла три-четыре минуты.

Файлы установленные портом:
/usr/local/man/man1/unbound-host.1.gz
/usr/local/man/man3/libunbound.3.gz
/usr/local/man/man5/unbound.conf.5.gz
/usr/local/man/man8/unbound.8.gz
/usr/local/man/man8/unbound-control.8.gz
/usr/local/man/man8/unbound-checkconf.8.gz
/usr/local/etc/unbound/unbound.conf.sample
/usr/local/include/unbound.h
/usr/local/lib/libunbound.so.0
/usr/local/lib/libunbound.so
/usr/local/lib/libunbound.la
/usr/local/lib/libunbound.a
/usr/local/sbin/unbound
/usr/local/sbin/unbound-checkconf
/usr/local/sbin/unbound-control
/usr/local/sbin/unbound-control-setup
/usr/local/sbin/unbound-host
/usr/local/share/doc/unbound/CREDITS
/usr/local/share/doc/unbound/Changelog
/usr/local/share/doc/unbound/FEATURES
/usr/local/share/doc/unbound/LICENSE
/usr/local/share/doc/unbound/README
/usr/local/share/doc/unbound/README.svn
/usr/local/share/doc/unbound/README.tests
/usr/local/share/doc/unbound/TODO
/usr/local/share/doc/unbound/control_proto_spec.txt
/usr/local/share/doc/unbound/ietf67-design-02.odp
/usr/local/share/doc/unbound/ietf67-design-02.pdf
/usr/local/share/doc/unbound/requirements.txt
/usr/local/etc/rc.d/unbound

Кроме того в систему была добавлена библиотека libevent-1.4.8

Управление запуском, перезапуском и остановкой будет вестись через стандартный rc.d скрипт установленный вместе с портом. Для проверки правильности синтаксиса unbound.conf удобно применять unbound-checkconf. Кроме того, начиная с версии 1.1.0 в состав unbound вошел дополнительный инструмент unbound-control для удаленного управления сервером и снятия статистики.

В процессе установки порта, в систему автоматически добавляется новый пользователь из-под которого будет запускаться демон unbound:
unbound:*:59:1:unbound dns resolver:/nonexistent:/usr/sbin/nologin

Настройка

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

Unbound позволяет запускать себя в chroot окружении. Я решил использовать эту возможность чтобы не замарачиваться с настройкой jail.

Для обеспечения полноценной работы в chroot, придется сделать один дополнительный маневр. Дело в том, что unbound необходим доступ к  /dev/random. Я посчитал, что правильным решением будет ограниченное монтирование devfs в подкаталог ./dev в каталоге unbound.

В директории /usr/local/etc/unbound создаем новую поддиректорию ./dev:
drwxr-xr-x	3	unbound	wheel	512	5 июл 17:54 .
drwxr-xr-x	37	root	wheel	1536	3 июл 20:53 ..
dr-xr-xr-x	4	root	wheel	512	5 июл 20:00 dev

В файле /etc/devfs.rules прописываем новый devfs releset:
[unbound_ruleset=20]
add hide
add path null unhide
add path zero unhide
add path crypto unhide
add path random unhide
add path urandom unhide

В файле /etc/fstab прописываем монтирование devfs:
devfs	/usr/local/etc/unbound/dev	devfs	rw	0	0

В файле /etc/rc.conf прописываем применение созданного devfs releset к точке монтирования:
devfs_set_rulesets="/usr/local/etc/unbound/dev=unbound_ruleset"

В результате всех этих танцев с бубном, после каждой перезагрузки в подкаталоге ./dev будет:
[root@dns /usr/local/etc/unbound/dev]# ls -la
total 0
crw-rw-rw-	1 root	wheel	0,  13	5 июл 20:22 null
crw-rw-rw-	1 root	wheel	0,  19	5 июл 20:00 random
lrwxr-xr-x	1 root	wheel	6	5 июл 17:00 urandom -> random
crw-rw-rw-	1 root	wheel	0,  14	5 июл 17:00 zero

Если не проблема перезапустить сервер то перезагружаем FreeBSD и проверяем, что devfs красиво подмонтировалась в /usr/local/etc/unbound/dev со всеми ограничениями как положено.

Если же не хочеться перезапускать машину, то монтирование можно выполнить и на ходу:
# mount /usr/local/etc/unbound/dev
# /etc/rc.d/devfs restart

Далее продолжаем настройку unbound:

Переходим в /usr/local/etc/unbound и скачиваем туда свежий hint-файл named.cache с информацией об адресах корневых серверов:
# cd /usr/local/etc/unbound
# fetch ftp://FTP.INTERNIC.NET/domain/named.cache

Генерируем связку ключей необходимых для работы unbound-control:
# unbound-control-setup
setup in directory /usr/local/etc/unbound
generating unbound_server.key
Generating RSA private key, 1024 bit long modulus
..++++++
...............................................++++++
e is 65537 (0x10001)
generating unbound_control.key
Generating RSA private key, 1024 bit long modulus
...................++++++
..................++++++
e is 65537 (0x10001)
create unbound_server.pem (self signed certificate)
create unbound_control.pem (signed client certificate)
Signature ok
subject=/CN=unbound-control
Getting CA Private Key
Setup success. Certificates created. Enable in unbound.conf file to use

Корректируем права доступа для созданных ключей (это важно!):
# chown unbound:wheel ./unbound_*
# chmod 440 ./unbound_*

Дело в том, что сразу же после генерации ключей права доступа для них по умолчанию выставляются так, что любой локальный пользователь может их прочитать. Это плохо так как локальный контроль доступа у утилиты unbound-control происходит только на основе разрешений файловой системы для этих ключей. Разработчики unbound предлагают при генерации использовать sudo или su и генерировать ключи работая из-под пользователя unbound, но мне такой метод кажется все равно геморойным. Таким образом после выполнения данных шагов локальный доступ к unbound-control будет только у root и пользователей из группы wheel.

Если хотите производить мониторинг работы сервера с помошью cacti, то сразу сейчас надо будет создать еще одну директорию в которой будет хранится статистика. В конце статьи есть ссылочка на архив со скриптом и шаблонами для cacti.
# mkdir ./statistics

На работающем сервере каталог /usr/local/etc/unbound будет выглядеть так:
[root@dns /usr/local/etc/unbound]# ls -la
total 21
drwxr-xr-x   3 unbound  wheel    512 24 янв 15:24 .
drwxr-xr-x  34 root     wheel   1536 21 янв 18:55 ..
dr-xr-xr-x   4 root     wheel    512 24 янв 14:30 dev
-rw-r--r--   1 root     wheel   2879  4 фев  2008 named.cache
drwxr-xr-x   2 root     wheel    512 29 янв 21:15 statistics
-rw-r--r--   1 root     wheel   1848 14 янв 20:39 unbound.conf
-rw-r--r--   1 unbound  daemon     5 24 янв 12:30 unbound.pid
-r--r-----   1 unbound  wheel    887 24 янв 15:17 unbound_control.key
-r--r-----   1 unbound  wheel    627 24 янв 15:17 unbound_control.pem
-r--r-----   1 unbound  wheel    887 24 янв 15:17 unbound_server.key
-r--r-----   1 unbound  wheel    619 24 янв 15:17 unbound_server.pem

При работающем скрипте unbound_cacti каталог /usr/local/etc/unbound/statistics будет выглядеть так:
[root@dns /usr/local/etc/unbound/statistics]# ls -la
total 12
drwxr-xr-x  2 root     wheel  512 29 янв 21:15 .
drwxr-xr-x  4 unbound  wheel  512  1 фев 13:21 ..
-rw-r--r--  1 root     wheel  107  8 фев 00:40 answers_to_queries
-rw-r--r--  1 root     wheel  257  8 фев 00:40 cache_hits
-rw-r--r--  1 root     wheel   88  8 фев 00:40 histogram
-rw-r--r--  1 root     wheel  106  8 фев 00:40 memory_usage
-rw-r--r--  1 root     wheel  130  8 фев 00:40 queues_by_flags
-rw-r--r--  1 root     wheel  141  8 фев 00:40 queues_by_type

Конфиг unbound.conf:
server:
        verbosity: 0
        #statistics-interval: 300
        num-threads: 4
        interface: 0.0.0.0
        port: 53

        outgoing-range: 512
        num-queries-per-thread: 1024

        msg-cache-size: 16m
        rrset-cache-size: 32m
        #key-cache-size: 10m

        msg-cache-slabs: 4
        rrset-cache-slabs: 4
        infra-cache-slabs: 4
        #key-cache-slabs: 4

        cache-max-ttl: 86400
        infra-host-ttl: 60
        infra-lame-ttl: 120

        infra-cache-numhosts: 10000
        infra-cache-lame-size: 10k

        do-ip4: yes
        do-ip6: no
        do-udp: yes
        do-tcp: yes
        do-daemonize: yes

        access-control: 0.0.0.0/0 refuse
        access-control: 192.168.1.0/24 allow
        access-control: 127.0.0.0/8 allow
        access-control: ::0/0 refuse
        access-control: ::1 allow
        access-control: ::ffff:127.0.0.1 allow

        chroot: "/usr/local/etc/unbound"
        username: "unbound"
        directory: "/usr/local/etc/unbound"
        #logfile: "/usr/local/etc/unbound/unbound.log"
        logfile: ""
        use-syslog: no
        pidfile: "/usr/local/etc/unbound/unbound.pid"
        root-hints: "/usr/local/etc/unbound/named.cache"

        identity: "DNS"
        version: "1.0"
        hide-identity: yes
        hide-version: yes
        harden-glue: yes
        do-not-query-address: 127.0.0.1/8
        do-not-query-address: ::1
        do-not-query-localhost: yes
        module-config: "iterator"

        #extended-statistics: yes

#local-zone: "mail.ru." transparent
#       local-data: "www.mail.ru. 300 IN A 10.10.10.10"
#       local-data: "ftp.mail.ru. 300 IN A 172.16.1.2"

#stub-zone:
#       name: "times.lv."
#       stub-addr: 193.108.185.34

#forward-zone:
#       name: "."
#       forward-addr: 195.122.12.242

remote-control:
        control-enable: yes
        control-interface: 127.0.0.1
        control-port: 953
        server-key-file: "/usr/local/etc/unbound/unbound_server.key"
        server-cert-file: "/usr/local/etc/unbound/unbound_server.pem"
        control-key-file: "/usr/local/etc/unbound/unbound_control.key"
        control-cert-file: "/usr/local/etc/unbound/unbound_control.pem"

Замечание 1
В процессе обсуждения статьи, выявилось несколько важных моментов конфигурации, на которые необходимо обратить внимание. Для пользователей FreeBSD 7 это может быть не актуально, но если у вас FreeBSD 6 или другая система то стоит проверить все ли ОК.

Первое, что надо учитывать в конфигурациях расчитанных на большие нагрузки - максимальное количество файловых дескрипторов которые разрешено открыть процессу (ulimit -n) и общее количество сокетов. Во FreeBSD эти значения можно узнать через
# sysctl -a | grep kern.maxfiles
# sysctl -a | grep kern.ipc.maxsockets


Регулируется они через установки sysctl. На моей машине с FreeBSD 7 по умолчанию эти значения были такие:
kern.maxfiles: 12328
kern.maxfilesperproc: 11095
kern.ipc.maxsockets: 12328

Указаная выше конфигурация unbound.conf приведет к появлению четырех потоков у процесса unbound. Каждый из четырех потоков сможет открыть 512 дескрипторов для UDP (по числу outgoing-range: ), кроме того каждый поток открывает 10 дискрипторов для обслуживания входящих и 10 дискрипторов для обслуживания исходящих TCP соединений (эти значения регулируются через опции outgoing-num-tcp: и incoming-num-tcp: которые по умолчанию выставлены в 10).

В сумме получается 512*4 + 20*4 = 2128 а значит на FreeBSD 7 проблем это вызвать не должно... Если же окажеться, что необходимо увеличить лимиты, то сделать это можно так:

Выставляем на ходу
# sysctl kern.maxfiles=20328
# sysctl kern.maxfilesperproc=20095
# sysctl kern.ipc.maxsockets=20328

и не забываем занести их в /etc/sysctl.conf
kern.maxfiles=20328
kern.maxfilesperproc=20095
kern.ipc.maxsockets=20328

Замечание 2
Второе на что необходимо обратить внимание - это общий обьем памяти доступной для аллокации одному процессу - "data seg size" (ulimit -d). По умолчанию, на FreeBSD 7.0 этот объем равен 512M:
ulimit -d
data seg size           (kbytes, -d) 524288

Указаная выше конфигурация unbound.conf потребляет 16+32 = примерно 50M, а значит об этом моменте можно не беспокоится. Но, если размеры кешей будут значительны, то будет необходимо увеличить лимиты. Значение ulimit -d выставляется в файле /boot/loader.conf Размер указывается в байтах
kern.maxdsiz=""

Спасибо камраду seacat23, участвовавшему в обсуждении статьи, за наводку на проблему нехватки файловых дескрипторов и лимита памяти доступной процессу Unbound!


Замечание 3
В последних версиях Unbound появились новые настройки отвечающие за резервирование русурсов сервера для более плавной обработки пиков запросов. Это настройки указывают на то, какой объем буфера резервировать для приема и передачи UDP пакетов:

so-rcvbuf: 4m
so-sndbuf: 4m

подробней можно прочитать в мане unbound.conf - в качестве стартового значения рекомендовано начинать с 4m. Кроме выставления этих параметров имеет смысл так же увеличить максимальный размер буфера сокетов через sysctl.conf - увеличиваем значение с 262144 по-умолчанию, до 16m.
kern.ipc.maxsockbuf=16777216



Прописываем в /etc/rc.conf:
unbound_enable="YES"

В общем-то на этом все. Запускаем unbound-checkconf и, если нет сообщений об ошибках, то можно запускать сервер:
# /usr/local/etc/rc.d/unbound start

После этого проверяем, что все успешно запустилось:
# ps auxw | grep unbound
unbound  26674  0,0  0,7 20608 6964 ?? Is 15:42 0:00,06 /usr/local/sbin/unbound

# netstat -an | grep 53
tcp4	0      0  *.53                   *.*              LISTEN
udp4	0      0  *.53                   *.*

# netstat -an | grep 953
tcp4    0      0  *.953                  *.*              LISTEN

А так же с помошью nslookup проверим наш новый ресольвер и убедиться, что он отвечает:
# nslookup
> server 127.0.0.1
Default server: 127.0.0.1
Address: 127.0.0.1#53
> www.lissyara.su.
Server:         127.0.0.1
Address:        127.0.0.1#53

Non-authoritative answer:
www.lissyara.su canonical name = hosting.lissyara.su.
Name:   hosting.lissyara.su
Address: 77.221.149.162
>                                               

Если в будущем понадобиться менять какие-либо параметры в unbound.conf то, для того чтобы сервер перечитал свой конфиг, достаточно выполнения традиционного:
/usr/local/etc/rc.d/unbound reload 

unbound-control

Что касается инструмента unbound-control:
# unbound-control
[Usage:  unbound-control [options] command
        Remote control utility for unbound server.
Options:
  -c file       config file, default is /usr/local/etc/unbound/unbound.conf
  -s ip[@port]  server address, if omitted config is used.
  -h            show this usage help.
Commands:
  start                         start server; runs unbound(8)
  stop                          stops the server
  reload                        reloads the server
                                (this flushes data, stats, requestlist)
  stats                         print statistics
  stats_noreset                 peek at statistics
  status                        display status of server
  verbosity <number>            change logging detail
  log_reopen                    close and open the logfile
  local_zone <name> <type>      add new local zone
  local_zone_remove <name>      remove local zone and its contents
  local_data <RR data...>       add local data, for example
                                local_data www.example.com A 192.0.2.1
  local_data_remove <name>      remove local RR data from name
  dump_cache                    print cache to stdout
  load_cache                    load cache from stdin
  lookup <name>                 print nameservers for name
  flush <name>                  flushes common types for name from cache
                                types:  A, AAAA, MX, PTR, NS,
                                        SOA, CNAME, DNAME, SRV, NAPTR
  flush_type <name> <type>      flush name, type from cache
  flush_zone <name>             flush everything at or under name
                                from rr and dnssec caches
  flush_stats                   flush statistics, make zero
  flush_requestlist             drop queries that are worked on
  dump_requestlist              show what is worked on
  set_option opt: val           set option to value, no reload
  get_option opt                get option value
  list_stubs                    list stub-zones and root hints in use
  list_forwards                 list forward-zones in use
  list_local_zones              list local-zones in use
  list_local_data               list local-data RRs in use
  forward [off | addr ...]      without arg show forward setup
                                or off to turn off root forwarding
                                or give list of ip addresses
Version 1.4.6
BSD licensed, see LICENSE in source package for details.
Report bugs to unbound-bugs@nlnetlabs.nl

Как видете все опции интуитивно понятны. Много интересных возможностей.

Для того чтобы управлять каким-либо удаленным сервером unbound через локальную версию unbound-control необходимо чтобы на машину с которой производится управление были скопированы сгенерированный на сервере публичные *.pem ключи, а так же чтобы они были прописаны в конфиг файле. Вызов unbound-control -с ./config.conf -s 1.2.3.4


Мониторинг работы
В коплект поставки unbound входят плагины для системы мониторинга под названием munin. Я ради интереса их посмотрел, но что-то мне этот munin не понравился... Решил вот для cacti что-нибудь придумать. Предлагаемый скрипт unbound_cacti надо использовать в тандеме с cron и net-snmp. Если в настройке крона ни у кого проблем возникнуть не должно, то вот с настройкой net-snmp я сильно помочь не могу - я его осилил "на скорую руку" и дошел только до волшебной команды snmpconf которая помогает генерировать snmpd.conf, чего и могу порекомендовать всем кто его раньше не использовал. У меня был установлен net-snmp-5.4.2.1_1 из портов.

unbound_cacti.tar.gz содержит скрипт для извлечения статистики из unbound-control и шаблоны для cacti
файл скачан размер размещён примечание
unbound-cacti.tar.gz
2140 70.5kb 2009-02-01 Скрипт для снятия статистики и шаблоны для cacti ver. 0.7.1 (обновлен/last change: 09.01.2010)

Внутри архива скрипт для снятия статистики, кое-какие пошаговые руководства как все это правильно установить, и готовые шаблоны для импорта в Cacti.

P.S
Примеры для наглядности. Графики сняты с реальной машины обслуживающей сеть из 4K+ абонентов (спасибо Руслану за эти красивые графики):








Почти на всех графиках выводятся значения вида запрос/секунда. Это значит, что если сервер обрабатывает 600 запросов за 5 мин то на графике будет 2. График-гистограмма для времени ответов не отображает "общего" значения - столбики расположенны по принципу стека (один над другим) для того чтобы было удобнее оценивать масштабы.



За одно и стандартные cacti графики по нагруженности сервера и по трафику. Графики были сняты с того же самого сервера:





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

При использовании DNSSEC на стророне авторитарного DNS сервера (отправителя) происходит хеширование групп записей зоны и "подписивание" хешей с помошью закрытого ключа. Эти дополнительные данные сохраняются в файле зоны в виде записей типа RRSIG. Публичные ключи используемые при подписывании данных так же сохраняются в зоне в виде записей типа  DNSKEY. Сторона-получатель имея в своем распоряжении правильный/надежный публичный ключ отправителя может самостоятельно выполнить проверку полученныйх данных. Авторитарные сервера используют два типа ключей для подписи данных в зонах - это ZSK (Zone Signing Keys) ключи, и KSK (Key Signing Keys) ключи. Подобная схема применяется с целью ускорения процесса проверки подписей валидаторами DNS, так как, следуя рекомендациям, ZSK ключи выберают меньшего размера чем KSK ключи. Для обеспечения безопасности системы администраторы авторитарных серверов производят ротацию ZSK ключей примерно раз в месяц, в то время как KSK ключи (из-за их большей длины, а значит и устойчивости к подбору) меняют реже - примерно раз в год. KSK ключами подписывают ZSK ключи. Для того чтобы кеш сервер/валидатор с поддержкой DNSSEC мог бы произвести проверку полученных данных, ему необходимо сначала убедиться в достоверности KSK ключа, а затем, запросив данные о ZSK ключах непосредственно из записей зоны, провести их валидацию, и уже потом провести валидацию данных зоны подписанных этими ZSK ключами.

В идеале инфраструктура DNSSEC должна быть внедрена начиная с корневых серверов. В таком случае (как и при использование SSL сертификатов), клиенту для поведения проверки правильности данных необходимо иметь в своем распоряжении лишь ограниченное число "корневых" сертификатов которым он верит.

До недавнего времени DNSSEC можно было использовать ограничено. Для того чтобы иметь возможность проверять подписи какой-либо зоны, надо было устанавливать у себя ее публичные ключи - то есть для каждой зоны свой отдельный ключ. Это неприменимо для масштабов интернета. Летом 2010 года на корневых серверах была внедрена поддержка DNSSEC. В данный момент корневая зона подписана, а это значит, что для построения цепи доверия достаточно иметь в распоряжениии только публичный ключ IANA!

Unbound поддерживает использование DNSSEC (а так же инфраструктуры DLV). Для задействования этой возможности надо проделать следующие шаги:

Включение DNSSEC


Надо скачать с сайта IANA( https://data.iana.org/root-anchors/root-anchors.xml ) публичный ключ которым подписана корневая зона. Из файла root-anchors.xml надо извлеч секции

<KeyTag>
19036
</KeyTag>
<Algorithm>
8
</Algorithm>
<DigestType>
2
</DigestType>
<Digest>
49..[тут остальные символы]..B5
</Digest>

и преобразовать их к виду:

. IN DS 19036 8 2 49..[тут остальные символы]..B5

эти данные надо сохранить в файле /usr/local/etc/unbound/root.key

Файл root.key надо сделать доступным для записи процессу unbound:

# chown unbound:wheel /usr/local/etc/unbound/root.key



Надо изменит unbound.conf:
module-config: "validator iterator"
auto-trust-anchor-file: "/usr/local/etc/unbound/root.key"



И перезапустить Unbound:
# /usr/local/etc/rc.d/unbound restart



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

Переодически происходит ротация ключа которым подписана корневая зона. Администратор Unbound сервера должен об этом помнить. В состав сервера unbound интегрирована отдельная компонента под названием autotrust. В ее задачи входит автоматизация ротации ключей. Использованная нами ранее директива "auto-trust-anchor-file" как раз активирует autotrust. Если сервер работает беспрерывно то autotrust самостоятельно отследит ротацию ключа и перезапишет файл root.key новыми данными. Если же сервер не работал продолжительное время, то может понадобиться вручную обновить root.key.

Вид root.key на роботающем сервере. Видна работа autotrust - были добавлены дополнительные служебные записи:


cat ./root.key
; autotrust trust anchor file
;;id: . 1
;;last_queried: 1283605654 ;;Sat Sep  4 13:07:34 2010
;;last_success: 1283605654 ;;Sat Sep  4 13:07:34 2010
;;next_probe_time: 1283646085 ;;Sun Sep  5 00:21:25 2010
;;query_failed: 0
;;query_interval: 43200
;;retry_time: 8640
.       86400   IN      DNSKEY  257 3 8 AwEAAagA
IKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF
FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2
MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/Q
Zxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9
dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6
DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25A
sRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+
Uk1ihz0= ;{id = 19036 (ksk), size = 2048b} 
;;state=2 [  VALID  ] ;;count=0 
;;lastchange=1283605654 ;;Sat Sep  4 13:07:34 2010



IP/UDP пакеты протокола DNS с данными DNSSEC могут достигать больших размеров, в следствии чего, при прохождении через интернет они будут фрагментироваться. Если где-нибудь используется фаервол который неадекватно обрабатывает большие фрагментированные пакеты, то могут начаться проблемы. Например при использовании keep-state правил в ipfw из FreeBSD 7.2  и ниже. Такая конфигурация ipfw не работает:
add check-state
add allow icmp from me to any out keep-state
add allow tcp from me to any out keep-state
add allow udp from me to any out keep-state
add deny ip from any to any

Для решения этой проблемы можно либо разрешить прохождение через фаервол фрагментов IP пакетов перед keep-state правилами:
allow ip from any to me frag
add check-state
add allow icmp from me to any out keep-state
add allow tcp from me to any out keep-state
add allow udp from me to any out keep-state
add deny ip from any to any

либо наложить на FreeBSD 7.2 и ниже патч бекпортированный из FreeBSD 8.0-CURRENT который реализует функциональность дефрагментации IP на отдельном reass правиле. Патч здесь ( http://people.freebsd.org/~piso/ipfw-reass-7x.diff ). Пример правил с его применением:

add reass ip from any to any in
add check-state
add allow icmp from me to any out keep-state
add allow tcp from me to any out keep-state
add allow udp from me to any out keep-state
add deny ip from any to any



Комментарии

Опции unbound.conf:

num-threads: 4

- Рекомендуется выставлять количество потоков по количеству процессоров (ядер процессора).

msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4

При использовании модели на основе потоков, значения этих параметров рекомендуется выставлять как значение степени двойки которое наиболее близко к значению num-threads. Параметры влияют на эффективность совместного использования потоками общего кеша. Если используется модель на основе форков процессов, то можно выставить эти значения в 1.

outgoing-range: 512 
#outgoing-port-avoid: 0-32767
#outgoing-port-avoid: 65001-65535

- Эти опции указывают на то, сколько различных случайных портов может использовать при проведении запросов, и на то из какого диапазона можно брать эти порты (закомментировано). По умолчанию, для исходящих запросов используется диапазон 1024 - 65535 из которого автоматически исключаются номера известных сервисов назначенных IANA. Если вдруг это понадобиться, то чтобы ограничить этот диапазон, скажем до 32768 - 65000 надо добавить в конфиг оба outgoing-port-avoid. Каждый новый запрос к авторитарным DNS серверам отправляется со своего порта — это сделано для секюрности.

msg-cache-size: 16m
rrset-cache-size: 32m
key-cache-size: 10m
cache-max-ttl: 86400

- Эти опции указывают на то, каким будет размер кеша полученных DNS ответов (msg-cache) и, собственно, кеша DNS записей (rrset-cache). Рекомендуется устанавливать размер rrset-cache в два раза больше чем размер msg-cache. Опция cache-max-ttl указывает на максимальный срок жизни записей в кеше даже не смотря на их оригинальный TTL (86400 = 24 часа). Параметр key-cache-size указывает на размер памяти выделенной для хранения DNSSEC ключей (если unbound работает в режиме "validator iterator")

num-queries-per-thread: 1024

- Указывает сколько одновременных клиентских запросов сможет обработать один поток.

infra-host-ttl: 60
infra-lame-ttl: 120

- Установка этих значений указывает срок жизни записей из внутреннего кеша "неработающих" и "неправильных" DNS серверов. По умолчанию эти значения выставлены в 900 секунд (15 мин). Имеет смысл все же снизить их значения. Так, например, если применяется схема форвардинга запросов через установку forward-zone: то в случае кратковременного прерывания связи с сервером на который происходит форвардинг, такой сервер может попасть в кеш неработающих серверов и доступ к нему будет возобновлен только через 15 минут, что не есть хорошее решение :) После установки этих значений, следующая попытка обращения к серверу из черного списка будет предпринята уже через 60 сек. Эта настройка связана с безопасностью (в большей мере параноидальной безопасностью :)

access-control: 192.168.1.0/24 allow

- Кому разрешено посылать рекурсивные запросы (пользоваться кешем)

statistics-interval: 300
logfile: ""
use-syslog: no

- Полное отключение любого логирования. Мне не нужно. Если надо — можно включить и установить уровень verbosity от 1 до 4. В отличии от NSD, Unbound пишет в свои логи очень много разной статистики. При вербозности 4, вывод в лог по насыщенности практически напоминает tcpdump. statistics-interval - вывод в лог переодических отчетов о работе серврера.

module-config: "iterator"

- Устанавливает режим работы как исключительно DNS кеша. Еще один вариант этой настройки "validator iterator". В таком случае появляется возможность использовать DNSSEC расширения.

local-zone:

- Возможность "засорить" кеш своими данными приоритет которых будет выше чем у данных оригинальной зоны. Параметр устанавливаемый после имени local-zone указывает на режим как надо отвечать на данные которые предварительно не были указаны. Варианты:
deny - serves local data (if any), else, drops queries.
refuse - serves local data (if any), else, replies with error.
static - serves local data, else, nxdomain or nodata answer.
transparent - serves local data, else, resolves normally .
direct - serves the zone data for any subdomain in the zone.
nodefault - can be used to normally resolve AS112 zones.

stub-zone:

- Перенаправление всех запросов к этой зоне на указанный авторитарный сервер. Запросы отсылаются как итерационные.

forward-zone:

- Перенаправление всех запросов к этой зоне на указанный кеширующий сервер. Запросы отсылаются как рекурсивные. Это способ форвардинга запросов. Если указать здесь:
forward-zone: 
name: "."
forward-addr 192.168.2.1

То все запросы направляемые на наш сервер, будут перенаправляться на 192.168.2.1 который уже будет проводить всю рекурсию и возвращать ответ.

#extended-statistics: yes
remote-control:
        control-enable: yes
        control-interface: 127.0.0.1
        control-port: 953

- Данная секция включает возможность удаленного управления сервером через unbound-control. Указывается само разрешение удаленного управления, на каком IP и на каком TCP порту сервер будет ожидать подключений. Включение опции extended-statistics значительно расширяет диапазон выводимой статистики (например, начинает выводиться статистика по количеству отдельных типов DNS запросов), но это так же снижает скорость работы сервера.

Конфигурация для больших нагрузок

В mail-листах unbound было несколько обсуждений в которых поднимался вопрос об оптимальных настройках для серверов рассчитаных на большие нагрузки. Перепишу здесь основные мысли.

Главные опции влияющие на производительность сервера - это num-queries-per-thread, outgoing-range, а так же размеры кешей msg-cache-size и rrset-cache-size.

num-queries-per-thread - устанавливает размер "очереди" запросов ждущих разрешения. Это максимальное количество одновременных рекурсий которое разрешено принять от клиетов и обработать одному процессу. Если очередь переполняется, то вновь пришедшие клиентские запросы все еще могут быть обслужанны, но только на основании тех данных, что уже находятся в кеше сервера. Если нужной информации в кеше нет то запрос может быть дропнут.

outgoing-range - устанавлиевает максимальное число одновременно инициированнных рекурсий к внешним серверам. Как много может быть паралельных разрешений имен которых еще нет в кеше.

Значения этих двух параметров надо держать близко друг к другу. Если размер num-queries-per-thread слишком большой, и при этом outgoing-range маленький, то это приведет к потерям в очереди запросов - запросы не будут обслужаны из-за задержек. В статистике такая ситуация будет видна так:
[1223529704] unbound[24517:0] info: server stats for thread 0: 42804
queries, 21012 answers from cache, 21792 recursions
[1223529704] unbound[24517:0] info: server stats for thread 0:
requestlist max 1031 avg 811.488 exceeded 10926

exceeded 10926 - столько раз очередь num-queries-per-thread "переполнялась" - следовательно столько запросов небыло разрешено. Клиентами это будет ощущаться как то, что DNS сервер не ответил на запрос.

Для того чтобы иметь возможность устанавливать большие значения outgoing-range необходимо использовать libevent.



размещено: 2008-07-09,
последнее обновление: 2011-04-23,
автор: terminus


Rimlyanin, 2008-07-09 в 14:04:13

Спасибо, сейчас буду пробовать настроить, тут как раз понадобилось в одной из сетей NS поднять, думал как всегда BIND :)

dmitry, 2008-07-09 в 19:04:57

как ни крути, BIND намного лучше и быстрей. во всяком случае у меня с ним проблем никогда не было.

GR, 2008-07-09 в 19:11:49

>... гламурного BIND

Прикольно :)
У меня он ассоциируется скорее с огромным чёрным паровозом который бегает по современным электродорогам ,) Оно электричество конечно не пользует, дымит и пыхтит ... но таскает вагончики все эти скоро 30 лет :)

PS: Интересно - Unbound подвержен http://www.us-cert.gov/cas/techalerts/TA08-190B.html или нет? Если нет - то просто статья "в руку" :)

GR.

max, 2008-07-09 в 21:15:47

to GR
проблема дизайна протокола - что непонятно тебе?

shutdown now, 2008-07-09 в 23:20:33

я вот powerdns-recursor около года использую, kevent умеет использовать и chrootиться тоже, но DNS валидатора как в unbound нет
а вот bind с большим кешем тупит, использую его чисто как авторитетный

terminus, 2008-07-10 в 14:50:50

>как ни крути, BIND намного лучше и быстрей.

Ну, это дело вкуса... Да, бинд как и sendmail - софт с традицией и все такое, но факты говорят о том, что в нем часто находят дыры (как вот недавно TA08-190B) и, что он не такой уж быстрый и масштабируемый (BIND vs NSD http://people.freebsd.org/~kris/scaling/bind-nsd.png).
Я для себя напротив понятия BIND сделал ментальную пометку "это плохо" и, пока не жалею ;)
К стати на счет TA08-190B - пока не ясно на сколько эта проблема серьезна (детали баги пока не известны - может проблема протокола, а может только реализации), но счастивые обладатели PowerDNS или Unbound или djbdns сейчас лениво пьют пиво, ибо эти продукты используют техники затрудняющие атаку...

opt1k, 2008-08-17 в 20:32:08

Статья супер, большое спасибо.

Обратите внимание на:
forward-zone:
name: "."
stub-addr: 192.168.2.1
надо так:
forward-zone:
name: "."
forward-addr: 192.168.2.1

terminus, 2008-08-18 в 12:14:41

Немного погодя (когда время появится) мне предется исправить статью. Дело в том, что начиная с версии Unbound 1.0.2 он стал проверять наличие libevent и, если его нет, и количество потоков выствлено в 4 или больше (общее количество файловых дискрипторов >= 1024 на процесс), то Unbound не заводится и выкидывае сообщение об ошибке.

Я спрашивал в unbound-users что делать если libevent 1.3e работает не стабильно, но надо использовать много потоков? Там посоветовали не использовать потоки, а использовать форки процессов... Лажа. Написал маинтаинеру libevent с просьбой обновить порт, но ответа пока не получил.

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

Kolesya, 2008-10-13 в 12:20:18

>В результате всех этих танцев с бубном, после
>каждой перезагрузки компа будим иметь в ./dev:

Перегружать не обязательно, хватит
/etc/rc.d/devfs restart

Kolesya, 2008-10-13 в 12:21:53

в догонку:
1. правим /etc/fstab
2. правим /etc/devfs.rules
3. mount -a
4. /etc/rc.d/devfs restart

terminus, 2008-10-13 в 12:27:44

Спасибо за комментарий - внесу его в статью как вариант для тех кому нельзя перезапускаться.

Сделал с перезагрузками просто как меру предосторожности - параноег йа ;)

Алексей, 2008-10-14 в 1:46:07

Что делать?
Имею:
devfs ruleset: ioctl DEVFSIO_SUSE: Inappropriate ioctl for device
./devfs: WARNING: devfs_set_ruleset: unable to set ruleset 20 to /usr/local/etc/unbound/dev
devfs rule: ioctl DEVFSIO_SAPPLY: Inappropriate ioctl for device
./devfs: WARNING: devfs_apply_ruleset: unable to apply ruleset 20 to /usr/local/etc/unbound/dev

freebsd 6.3

Алексей, 2008-10-14 в 2:04:37

Нет мне прощенья!!!
Перепутал fstab c fbtab...
... - это судьба...

Kolesya, 2008-10-14 в 20:43:50

6.3-STABLE
7.0-STABLE
ulimit не находит, юзайте limits

scan, 2009-01-20 в 17:25:31

Кстати, как уверяют в багфиксах для версии 1.2.0:

The long standing bug with libevent use is fixed. It turns out to be a race condition in the calls to libevent. The builtin mini-event did not have a problem being called like this, but libevent and libev usage is now fixed. Libevent 1.1 is reported to still give problems, but 1.4.5 and 1.4.8 seem fine.

terminus, 2009-01-20 в 19:45:16

Да-да, спасибо что упомянули. Я в курсе о изменениях в новой версии unbound - сейчас я как раз перешел на 1.2.0 с использованием потоков вместе с libevent, и проблем больше не отмечаю. Чуть позже я перепишу статью по-новой. Есть план рассмотреть так же DNSSEC и DLV.

Ce$$, 2009-05-26 в 16:22:21

Искал замену dnscache, 1,5 месяца работает unbound, нареканий нет. Спасибо за статью.

Митра, 2009-10-30 в 22:09:32

Поставил, работает.
Спасибо.

kirgudu, 2009-12-03 в 13:21:13

Кстати, очень не рекомендуется stateful firewall для DNS. При большой нагрузке - клеит ласты, т.к. стейтов становится очень и очень много.

Den, 2012-03-18 в 13:33:24

здрасте.. я по вопросу

Генерируем связку ключей необходимых для работы unbound-control:

# unbound-control-setup

что-то не совсем понял как сгенерировать ключи..

terminus, 2012-03-18 в 14:55:24

Находясь в директории /usr/local/etc/unbound запускаете команду unbound-control-setup. Она сгенерирует несколько файлов (публичный и закрытый ключи). Далее действуете по оставшимся в руководстве шагам.

Raven_kg, 2012-06-21 в 8:58:09

А что случилось с аттачем? Не могу скачать, говорит у мну нет прав.

terminus, 2012-06-21 в 18:22:00

У меня все нормально скачивается.

Вот закинул копию на другой хостинг:
http://www.sendspace.com/file/mbh3t8

Саша, 2012-08-30 в 17:32:28

А расскажите, пожалуйста, как в unbound логировать хосты, с которых приходят запросы? Мне кажется, что это очень важно и нужно для ДНС-сервера, а бегло не смог найти как. :(

terminus, 2012-09-02 в 14:04:44

Логировать IP адреса клиентов можно только выставив 5й уровень вербозности лог файла.

Александр, 2013-03-22 в 12:32:14

Если вдруг это понадобиться, то чтобы ограничить этот диапазон, скажем до 32768 - 65000 надо добавить в конфиг оба outgoing-port-avoid.

А разве не достаточно будет указать один раз outgoing-port-avoid: 32768-65000 ?

GK, 2013-11-13 в 16:01:50

подключение от провайдера по DHCP!!!!  
указываю ip адрес полученный по DHCP в outgoing-interface: стартую unbound
/usr/local/etc/rc.d/unbound start

unbound-checkconf: no errors in /usr/local/etc/unbound/unbound.conf
Obtaining a trust anchor:/usr/local/etc/rc.d/unbound: WARNING: failed precmd routine for unbound

пробовал прописывать статические ip и dns  unbound работает до 1 перезагрузки
а потом то же самое
unbound-checkconf: no errors in /usr/local/etc/unbound/unbound.conf
Obtaining a trust anchor:/usr/local/etc/rc.d/unbound: WARNING: failed precmd routine for unbound

unbound.log
debug: failed address 178.*.*.* port 55574
[1386736099] unbound[10707:0] error: can't bind socket: Can't assign requested address
HELLP!!!

Юрий, 2014-05-29 в 9:12:30

Наткнулся на статью в свете отказа в 10-ке от Бинда в пользу Unbound. Статья очень толковая и довольно полная. Большое спасибо!

Александр, 2016-02-23 в 1:38:51

Статья огонь! Перерыл, наверное, 3 десятка разных мануалов. В т.ч. зачитал до дыр мануалы и советы от разрабов на оф.сайте, но такой целостной и последовательной статьи не видел.

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

Vano, 2016-05-05 в 15:36:38

кеш целиком распологается в памяти

Андрей, 2017-07-05 в 22:23:05

Команда unbound-control-setup в директории /etc/unbound (FreeBSD 11.0) отвечает Command not found

Андрей, 2018-04-25 в 20:56:33

Сам себе и отвечу. В феврале 2016 года local_unbound изменили и unbound_control_setup убрали. И теперь надо все ставить из портов или пакет собирать, чтобы нормально настроить.



 

  Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
  Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0721 секунд
Из них PHP: 56%; SQL: 44%; Число SQL-запросов: 87 шт.
Исходный размер: 155411; Сжатая: 30826