«Child Process» и «DNS сервер BIND с локальными зонами»: разница между страницами

Материал из support.qbpro.ru
(Различия между страницами)
imported>Supportadmin
 
imported>Vix
Нет описания правки
 
Строка 1: Строка 1:
'''''Stability: 3 - Stable'''''
Исходные данные


Node обеспечивает трёх-направленный POPEN (3) для модуля child_process.
Для корректной работы DNS нем необходимо иметь настроенную сеть. DNS в текущей статье будет настроен на дистрибутиве Debian, особенности других дистрибутивов тоже будут отмечены. Конфиг сети стенда следующий:


Поток данных можно направлять через стандартные stdin, stdout и stderr дочернего процесса в полностью неблокирующем стиле. (Заметим, что некоторые программы используют внутреннюю линейную буферизации строк ввода/вывода. Это не влияет node.js, но это означает что информация, передаваемая дочернему процессу "потребляется" им не сразу.)
dns:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
  address 10.0.0.152
  netmask 255.255.255.0
  gateway 10.0.0.254
auto eth1
iface eth1 inet static
  address 192.168.1.1
  netmask 255.255.255.0
где 10.0.0.152/24 - внешний интерфейс (подсеть, выделенная провайдером), 192.168.1.1/24 - внутренний (Локальная сеть). Настраиваемая зона будет иметь имя example.com. В примере со slave сервером, вторичный сервер будет расположен на IP 10.0.0.191.


Для создания дочернего процесса используйте require('child_process').spawn() или require('child_process').fork(). Семантика каждого немного отличается, и описана ниже.
Установка BIND9


==Class: ChildProcess==
Для работы DNS сервера необходимо установить пакет bind9 (в некоторых дистрибутивах - bind). Как отмечено на схеме - основным конфигурационным файлом BIND является файл named.conf (данный файл может быть размещен в каталоге /etc, иногда в /etc/bind ).
ChildProcess is an EventEmitter.


Child processes always have three streams associated with them. child.stdin, child.stdout, and child.stderr. These may be shared with the stdio streams of the parent process, or they may be separate stream objects which can be piped to and from.
Параметры (синтаксис) named.conf


The ChildProcess class is not intended to be used directly. Use the spawn() or fork() methods to create a Child Process instance.
Синтаксис файла named.conf придерживается следующих правил:


===Event: 'error'===
IP-адреса - список IP должен быть разделен символом ";" , возможно указывать подсеть в формате 192.168.1.1/24 или 192.168.1.1/255.255.255.0, (для исключения IP перед ним нужно поставить знак !), возможно указывать имена "any", "none", "localhost" в двойных кавычках.
err Error Object the error.
Emitted when:


The process could not be spawned, or
Комментарии - строки начинающиеся на #, // и заключенные в /* и */ считаются комментариями.
The process could not be killed, or
Sending a message to the child process failed for whatever reason.
See also ChildProcess#kill() and ChildProcess#send().


===Event: 'exit'===
В файлах описания зон - символ @ является "переменной" хранящей имя зоны, указанной в конфигурационном файле named.conf или в директиве @ $ORIGIN текущего описания зоны.
code Number the exit code, if it exited normally.
signal String the signal passed to kill the child process, if it was killed by the parent.
This event is emitted after the child process ends. If the process terminated normally, code is the final exit code of the process, otherwise null. If the process terminated due to receipt of a signal, signal is the string name of the signal, otherwise null.


Note that the child process stdio streams might still be open.
Каждая завершенная строка параметров должна завершаться символом ; .


See waitpid(2).
Раздел Acl
Acl (access control list) - позволяет задать именованный список сетей. Формат раздела: acl "имя_сети" {ip; ip; ip; };


===Event: 'close'===
Раздел Options
code Number the exit code, if it exited normally.
Раздел Options задает глобальные параметры конфигурационного файла, управляющие всеми зонами. Данный раздел имеет формат: options {операторы_раздела_Options};. Options может быть "вложен" в раздел Zone, при этом он переопределяет глобальные параметры. Часто используемые операторы options:
signal String the signal passed to kill the child process, if it was killed by the parent.
This event is emitted when the stdio streams of a child process have all terminated. This is distinct from 'exit', since multiple processes might share the same stdio streams.


===Event: 'disconnect'===
allow-query {список_ip} - Разрешает ответы на запросы только из список_ip. При отсутствии - сервер отвечает на все запросы.
This event is emitted after using the .disconnect() method in the parent or in the child. After disconnecting it is no longer possible to send messages. An alternative way to check if you can send messages is to see if the child.connected property is true.
allow-recursion {список_ip} - На запросы из список_ip будут выполняться рекурсивные запросы. Для остальных - итеративные. Если  не задан параметр, то сервер выполняет рекурсивные запросы для всех сетей.
allow-transfer {список_ip} - Указывает список серверов, которым разрешено брать зону с сервера (в основном тут указывают slave сервера)
directory /path/to/work/dir - указывает абсолютный путь к рабочему каталогу сервера. Этот оператор допустим только в разделе  options.
forwarders {ip порт, ip порт...} - указывает адреса хостов и если нужно порты, куда переадресовывать запросы (обычно тут указываются DNS провайдеров ISP).
forward ONLY или forward FIRST - параметр first указывает, DNS-серверу пытаться разрешать имена с помощью DNS-серверов, указанных в параметре forwarders, и лишь в случае, если разрешить имя с помощью данных серверов не удалось, то будет осуществлять попытки разрешения имени самостоятельно.
notify YES|NO - YES - уведомлять slave сервера об изменениях в зоне, NO - не уведомлять.
recursion YES|NO - YES - выполнять рекурсивные запросы, если просит клиент, NO - не выполнять (только итеративные запросы). Если ответ найден в кэше, то возвращается из кэша. (может использоваться только в разделе Options)
Раздел Zone
Определяет описание зон(ы). Формат раздела: zone {операторы_раздела_zone}; Операторы, которые наиболее часто используются:


===Event: 'message'===
allow-update {список_ip} - указывает системы, которым разрешено динамически обновлять данную зону.
message Object a parsed JSON object or primitive value
file "имя_файла" - указывает путь файла параметров зоны (должен быть расположен в каталоге, определенном в разделе options оператором directory)
sendHandle Handle object a Socket or Server object
masters {список_ip} -указывает список мастер-серверов. (допустим только в подчиненных зонах)
Messages send by .send(message, [sendHandle]) are obtained using the message event.
type "тип_зоны" - указывает тип зоны, описываемой в текущем разделе,тип_зоны может принимать следующие значения:
forward - указывает зону переадресации, которая переадресовывает запросы, пришедшие в эту зону.
hint - указывает вспомогательную зону (данный тип содержит информацию о корневых серверах, к которым сервер будет обращаться в случае невозможности найти ответ в кэше)
master - указывает работать в качестве мастер сервера для текущей зоны.
slave - указывает работать в качестве подчиненного сервера для текущей зоны.
Дополнительные параметры конфигурации
Значения времени в файлах зон по умолчанию указывается в секундах, если за ними не стоит одна из следующих букв: S - секунды, M - минуты, H- часы, D - дни, W - недели. Соответственно, запись 2h20m5s будет иметь значение 2 часа 20 минут 5 секунд и соответствовать 8405 секунд.


====child.stdin====
Любое имя хоста/записи, не оканчивающиеся точкой считается неFQDN именем и будет дополнено именем текущей зоны. Например, запись domen в файле зоны examle.com будет развернуто в FQDN-имя domen.examle.com. .
Stream object
A Writable Stream that represents the child process's stdin. Closing this stream via end() often causes the child process to terminate.


If the child stdio streams are shared with the parent, then this will not be set.
В конфигурационных файлах BIND могут применяться следующие директивы:


====child.stdout====
$TTL - определяет TTL по-умолчанию для всех записей в текущей зоне.
Stream object
$ORIGIN - изменяет имя зоны с указанного в файле named.conf. При этом, область действия данной директивы не распространяется  "выше" (то есть если файл включен директивой $INCLUDE, то область действия$ORIGN не распространяется на родительский)
A Readable Stream that represents the child process's stdout.
$INCLUDE - включает указанный файл как часть файла зоны.
Для того чтобы локальный резолвер сервера тоже использовал локальный DNS, необходимо привести файл resolv.conf к следующему виду:


If the child stdio streams are shared with the parent, then this will not be set.
dns:~# cat /etc/resolv.conf
nameserver 127.0.0.1
Если в имени ресурсной записи встречается символ "*", то это он означает что вместо него можно подразумевать любую разрешенную последовательность символов. Такую запись называют "wildcard запись". Однако, символ "*" не может быть использован где угодно. Это может быть только первый символ в поле Name текущего домена, отделенный от остальных символом "."


====child.stderr====
Настройка кэширующего DNS сервера
Stream object
A Readable Stream that represents the child process's stderr.


If the child stdio streams are shared with the parent, then this will not be set.
После установки bind, он полностью готов работать как кэширующий DNS сервер без дополнительной настройки. Единственный недостаток - он обрабатывает запросы на всех интерфейсах, что нам абсолютно не нужно, поэтому мы немного подредактируем настройки сервера.


====child.pid====
Для того, чтобы BIND работал в качестве кэширующего сервера, необходимо иметь конфигурационные файлы заполненные необходимой информацией:
'''Integer'''


The PID of the child process.
named.conf;
описание серверов корневой зоны (зона типа hint);
описание зоны 127.in-addr.arpa.
dns:~# cat /etc/bind/named.conf
acl "lan" {
            192.168.1.1/24;
            127.0.0.1;
};
options {
            directory "/var/cache/bind";
          // If there is a firewall between you and nameservers you want
          // to talk to, you may need to fix the firewall to allow multiple
          // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
          /*
          * Тут сказано, что если используется фаерволл, то необходимо
          *  нашему серверу создать соответствующие правила
          *  то есть открыть доступ по 53 TCP и UDP порту
          */
          forward first;              // задаем пересылку только первого запроса
          forwarders {                // указываем DNS сервера для пересылки
                      83.239.0.202;    // предоставленные провайдером
                      213.132.67.110;  // ибо до них ближе чем до корневых
          };
          listen-on { lan; };        // пусть слушает только нужные интерфейсы
          allow-query { lan; };      // разрешить запросы только из локальной сети
          allow-recursion { lan; };  // рекурсивные запросы тоже только из локальной
          allow-transfer { none; };  // трансфер зон нам не нужен
          version "unknown";        // не отображать версию DNS сервера при ответах
          auth-nxdomain no;    # для совместимости RFC1035
          listen-on-v6 { none; };    //IPv6 нам не нужен
          };
// описание настроек корневых серверов
zone "." {
          type hint;
          file "db.root";
};
// нижеописанные зоны определяют сервер авторитетным для петлевых
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)
zone "localhost" {
          type master;
          file "localhost";
};
zone "127.in-addr.arpa" {
          type master;
          file "127.in-addr.arpa";
};
zone "0.in-addr.arpa" {
          type master;
          file "0.in-addr.arpa";
};
zone "255.in-addr.arpa" {
          type master;
          file "255.in-addr.arpa";
};


Example:
В данном примере приведен кэширующий DNS сервер, обрабатывающий запросы из списка сетей lan, в которую входит только одна локальная сеть 192.168.1.1/24 и петлевой интерфейс. При необходимости можно включить туда и другие сети. После определения списка сетей в директиве acl, в любом месте конфига можно будет ссылаться на этот список по имени (в нашем примере имя - lan), что, собственно и сделано в разделе options. Большинство параметров я прокомментировал, но отдельного внимания требует раздел, описывающий зону корневых серверов. В параметре file задан относительный путь к файлу описания корневых серверов (путь, относительно рабочего каталога сервера). За обновлениями данного файла необходимо следить, хотя он обновляется довольно редко (откуда брать обновленный файл я писал в теории DNS). Как вы заметили, имеется так же две записи для зоны localhost и две записи обратных зон для бродкаст доменов. Назначение этих зон состоит в том, чтобы избежать трансляции случайных запросов имен соответствующих IP-адресов на серверы, обслуживающие корневую зону.


  <nowiki>var spawn = require('child_process').spawn,
Чтобы не вносить неразбериху в куче конфигурационных файлов, в статье я привожу примеры на основе единого конфигурационного файла. На самом деле, в последних версиях Debian (и других дистрибутивах Linux), файл named.conf выглядит следующим образом:
    grep  = spawn('grep', ['ssh']);


console.log('Spawned child pid: ' + grep.pid);
root@master:~# cat /etc/bind/named.conf
grep.stdin.end();</nowiki>
// This is the primary configuration file for the BIND DNS server named.
====child.kill([signal])====
//
'''signal String'''
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local


Send a signal to the child process. If no argument is given, the process will be sent 'SIGTERM'. See signal(7) for a list of available signals.
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
То есть основной файл не содержит конфигураций, а включает в себя более узко специализированные файлы, которые отвечают за свои задачи, например named.conf.options - содержит глобальные параметры конфигурации, named.conf.default-zones - содержит описание localhost и broadcast зон, а named.conf.local содержит описания зон, за которые отвечает данный сервер.


  <nowiki>var spawn = require('child_process').spawn,
   
    grep  = spawn('grep', ['ssh']);


grep.on('close', function (code, signal) {
Далее, хочу обратить внимание на наличие файлов зон в каталоге, указанном в разделе options в параметре directory с именами, соответствующими параметрам file в разделах, описывающих зоны:
  console.log('child process terminated due to receipt of signal '+signal);
});


// send SIGHUP to process
dns:~# ls -l /var/cache/bind/
grep.kill('SIGHUP');</nowiki>
итого 24
-rw-r--r-- 1 root root  237 Май 28 01:28 0.in-addr.arpa
-rw-r--r-- 1 root root  271 Май 28 01:28 127.in-addr.arpa
-rw-r--r-- 1 root root  237 Май 28 01:28 255.in-addr.arpa
-rw-r--r-- 1 root root 2994 Май 28 01:28 db.root
-rw-r--r-- 1 root root  270 Май 28 01:28 localhost
dns:~# cat /var/cache/bind/127.in-addr.arpa
;
; BIND reverse data file for local loopback interface
;
$TTL    604800
@      IN      SOA    localhost. root.localhost. (
                              1        ; Serial
                              604800    ; Refresh
                              86400    ; Retry
                              2419200  ; Expire
                              604800 ) ; Negative Cache TTL
;
@      IN      NS      localhost.
1.0.0  IN      PTR    localhost.
Рассматривать файлы "петлевых" и бродкастовых зон не вижу смысла, т.к. после установки пакета bind настройки заданные по умолчанию в данных файлах вполне приемлемы. Далее, при организации мастер сервера мы рассмотрим пример описания файла зоны. Хочу обратить внимание, что мы настраиваем кэширующий сервер, а определяем мы его и как master для некоторых из зон. В нашем случае "кэширующий" говорит о том, что наш сервер не поддерживает ни одну из реально существующих зон, т.е. ему не делегировано прав на такое обслуживание.


May emit an 'error' event when the signal cannot be delivered. Sending a signal to a child process that has already exited is not an error but may have unforeseen consequences: if the PID (the process ID) has been reassigned to another process, the signal will be delivered to that process instead. What happens next is anyone's guess.
Да, чуть не забыл, демон named должен быть разрешен для запуска на необходимых уровнях выполнения ОС (команда в RedHat - /sbin/chkconfig bind9 on, в Debian - /usr/sbin/update-rc.d bind9 defaults). После изменения конфигурационных файлов можно добавить сервис в автозагрузку и запустить демон:


Note that while the function is called kill, the signal delivered to the child process may not actually kill it. kill really just sends a signal to a process.
dns:~# update-rc.d bind9 defaults
Adding system startup for /etc/init.d/bind9 ...
/etc/rc0.d/K20bind9 -> ../init.d/bind9
/etc/rc1.d/K20bind9 -> ../init.d/bind9
/etc/rc6.d/K20bind9 -> ../init.d/bind9
/etc/rc2.d/S20bind9 -> ../init.d/bind9
/etc/rc3.d/S20bind9 -> ../init.d/bind9
/etc/rc4.d/S20bind9 -> ../init.d/bind9
/etc/rc5.d/S20bind9 -> ../init.d/bind9
dns:~# /etc/init.d/bind9 start
Starting domain name service...: bind9.
На этом настройка кэширующего DNS завершена. Все запросы, которые попадают в кэш DNS сервера он хранит в оперативной памяти компьютера и при перезапуске демона эти данные обнуляются. Для проверки работы кэша можно выполнить команду nslookup mail.ru example.com., если в ответе содержится строка Non-authoritative answer, то адрес пришел из кэша, а так же если выполнить dig www.ru. (или другой домен, которого еще нет в кэше) и через некоторое время повторить команду, то время ответа должно быть гораздо меньше.


See kill(2)
Давайте рассмотрим другие варианты сервера.


====child.send(message, [sendHandle])====
Главный (master) сервер зоны
'''message Object'''


'''sendHandle Handle object'''
Основной конфиг содержит следующие настройки:


When using child_process.fork() you can write to the child using child.send(message, [sendHandle]) and messages are received by a 'message' event on the child.
dns:~# cat /etc/bind/named.conf
acl "lan" {
          192.168.1.1/24;
          127.0.0.1;
};


For example:
options {
          directory "/var/cache/bind";
          allow-query { any; };      // отвечать на зпросы со всех интерфейсов
          recursion no;              // запретить рекурсивные запросы
          auth-nxdomain no;          // для совместимости RFC1035
          listen-on-v6 { none; };    // IPv6 нам не нужен
          version "unknown";          // не отображать версию DNS сервера при ответах


  <nowiki>var cp = require('child_process');
          /*
          *  Раскомментируйте строки ниже, если
          *  хотите разрешить рекрусивные запросы
          *  из локальной сети.
          * (так же, необходимо закомментировать
          *  recursion no; )
          */
          # forwarders {                // указываем DNS сервера для пересылки
          #        83.239.0.202;        // предоставленные провайдером
          #        213.132.67.110;      // ибо до них ближе чем до корневых
          # };


var n = cp.fork(__dirname + '/sub.js');
          # allow-recursion { lan; };    // рекурсивные запросы тоже только из локальной


n.on('message', function(m) {
};
  console.log('PARENT got message:', m);
});


n.send({ hello: 'world' });</nowiki>
// описание настроек корневых серверов
And then the child script, 'sub.js' might look like this:
zone "." {
          type hint;
          file "db.root";
};


<nowiki>process.on('message', function(m) {
// нижеописанные зоны определяют сервер авторитетным для петлевых
  console.log('CHILD got message:', m);
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)
});


process.send({ foo: 'bar' });</nowiki>
zone "localhost" {
In the child the process object will have a send() method, and process will emit objects each time it receives a message on its channel.
          type master;
          file "localhost";
};


There is a special case when sending a {cmd: 'NODE_foo'} message. All messages containing a NODE_ prefix in its cmd property will not be emitted in the message event, since they are internal messages used by node core. Messages containing the prefix are emitted in the internalMessage event, you should by all means avoid using this feature, it is subject to change without notice.
zone "127.in-addr.arpa" {
          type master;
          file "127.in-addr.arpa";
};


The sendHandle option to child.send() is for sending a TCP server or socket object to another process. The child will receive the object as its second argument to the message event.
zone "0.in-addr.arpa" {
          type master;
          file "0.in-addr.arpa";
};


Emits an 'error' event if the message cannot be sent, for example because the child process has already exited.
zone "255.in-addr.arpa" {
          type master;
          file "255.in-addr.arpa";
};


====Example: sending server object====
// описание основной зоны
zone "example.com" {
          type master;
          file "example.com";
          allow-transfer { 10.0.0.191; };
};


Here is an example of sending a server:
//описание обратных зон
zone "0.0.10.in-addr.arpa" {
          type master;
          file "0.0.10.in-addr.arpa";
          allow-transfer { 10.0.0.191; };
};


<nowiki>var child = require('child_process').fork('child.js');
zone "1.168.192.in-addr.arpa" {
          type master;
          file "1.168.192.in-addr.arpa";
#        allow-transfer { 10.0.0.191; };  // зона описывает локальную сеть поэтому ее не передаем
};


// Open up the server object and send the handle.
// настройки логирования
var server = require('net').createServer();
logging {
server.on('connection', function (socket) {
          channel "misc" {
  socket.end('handled by parent');
                    file "/var/log/bind/misc.log" versions 4 size 4m;
});
                    print-time yes;
server.listen(1337, function() {
                    print-severity yes;
  child.send('server', server);
                    print-category yes;
});</nowiki>
          };
And the child would the receive the server object as:


<nowiki>process.on('message', function(m, server) {
          channel "query" {
  if (m === 'server') {
                    file "/var/log/bind/query.log" versions 4 size 4m;
    server.on('connection', function (socket) {
                    print-time yes;
      socket.end('handled by child');
                    print-severity no;
    });
                    print-category no;
  }
          };
});</nowiki>


Note that the server is now shared between the parent and child, this means that some connections will be handled by the parent and some by the child.
          category default {
                    "misc";
          };


For dgram servers the workflow is exactly the same. Here you listen on a message event instead of connection and use server.bind instead of server.listen. (Currently only supported on UNIX platforms.)
          category queries {
                    "query";
          };
};
Давайте кратко разберем конфигурационный файл и настройки master сервера: мы настраиваем мастер сервер для зоны example.com. . Согласно конфига, наш BIND имеет рабочий каталог /var/cache/bind, сервер отвечает на запросы со всех интерфейсов (allow-query {any ;};), рекурсивные запросы обрабатывает как итеративные (recursion no), является мастер-сервером для зоны example.com и локальных служебных зон (type master). При этом, если необходимо разрешить кэширование (то есть рекурсивные запросы) для локальной сети, то необходимо раскомментировать параметры forwarders и allow-recursion и закомментировать recursion no;.


====Example: sending socket object====
Так же, для примера, я привел возможности BIND логировать все происходящее при работе сервера (можно для этой цели использовать syslog). В разделе logging задаются 2 параметра channel (можно и больше двух - на ваше усмотрение), эти параметры дословно можно назвать "канал" записи. Каждый канал определяет имя канала и настройки параметров записи (что записывать, а что - нет и куда писать). Директива category задает какую категорию сообщений в какой канал отправлять. Исходя из этого, мы имеем: запись стандартной информации в канал misc, а приходящие запросы посылаются в канал query. При этом, если файлы журнала достигают 4Мб (size 4m), он переименовывается добавлением к имени .1 и начинается запись в новый журнал, числа в конце других журналов увеличиваются. Журналы с номером, более указанного в version (в нашем случае 4) удаляются (Управлять ротацией логов можно так же с помощью logrotate). Параметры print* определяют заносить ли в журнал время появления, важность и категорию информации. Более подробно про настройки раздела logging можно почитать в man (5) named.conf.


Here is an example of sending a socket. It will spawn two children and handle connections with the remote address 74.125.127.100 as VIP by sending the socket to a "special" child process. Other sockets will go to a "normal" process.
Отдельно хочется описать параметр  allow-transfer { 10.0.0.191; };. Данный параметр описывает серверы, которым разрешено скачивать копию зоны - т.н. slave серверА. В следующем примере мы разберем настройку slave DNS.


<nowiki>var normal = require('child_process').fork('child.js', ['normal']);
Для корректной работы логирования необходимо создать соответствующий каталог и присвоить необходимые права:
var special = require('child_process').fork('child.js', ['special']);


// Open up the server and send sockets to child
dns:~# mkdir /var/log/bind/
var server = require('net').createServer();
dns:~# chmod 744 /var/log/bind/
server.on('connection', function (socket) {
dns:~# ps aux | grep named
bind      4298  0.0  3.4  46792 13272 ?        Ssl  Jul05  0:00 /usr/sbin/named -u bind
root      4815  0.0  0.1  3304  772 pts/4    S+  18:19  0:00 grep named
dns:~# chown bind /var/log/bind/
dns:~# ls -ld /var/log/bind/
drwxr--r-- 2 bind root 4096 Июл  6 18:18 /var/log/bind/
Давайте далее рассмотрим наш файл описания зоны example.com.:


  // if this is a VIP
dns:~# cat /var/cache/bind/example.com
  if (socket.remoteAddress === '74.125.127.100') {
$TTL 3D
    special.send('socket', socket);
@      IN      SOA    ns.example.com. root.example.com. (
    return;
                                        2011070601      ; serial
  }
                                        8H              ; refresh
  // just the usual dudes
                                        2H              ; retry
  normal.send('socket', socket);
                                        2W              ; expire
});
                                        1D)             ; minimum
server.listen(1337);</nowiki>
The child.js could look like this:


<nowiki>process.on('message', function(m, socket) {
@      IN      NS      ns.example.com.
  if (m === 'socket') {
@      IN      NS      ns2.example.com.
    socket.end('You were handled as a ' + process.argv[2] + ' person');
@      IN      A      10.0.0.152
  }
@      IN      MX      5 mx.example.com.
});</nowiki>
ns      IN      A      10.0.0.152
Note that once a single socket has been sent to a child the parent can no longer keep track of when the socket is destroyed. To indicate this condition the .connections property becomes null. It is also recommended not to use .maxConnections in this condition.
ns2    IN      A      10.0.0.191
mx      IN      A      10.0.0.152
www    IN      CNAME  @
а так же в домене in-addr.arpa.


===child.disconnect()===
dns:~# cat /var/cache/bind/0.0.10.in-addr.arpa
To close the IPC connection between parent and child use the child.disconnect() method. This allows the child to exit gracefully since there is no IPC channel keeping it alive. When calling this method the disconnect event will be emitted in both parent and child, and the connected flag will be set to false. Please note that you can also call process.disconnect() in the child process.
$TTL 3600
@      IN      SOA    ns.examle.com.  root.example.com. (
            2007042001 ; Serial
            3600      ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
        IN      NS      ns.examle.com.
        IN      NS      ns2.example.com.
152    IN      PTR    examle.com.
191    IN      PTR    ns.example.com.
*      IN      PTR    examle.com.


===child_process.spawn(command, [args], [options])===
dns:~# cat /var/cache/bind/1.168.192.in-addr.arpa
command String The command to run
$TTL 3600
@      IN      SOA    ns.examle.com.  root.example.com. (
            2007042001 ; Serial
            3600      ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )    ; Minimum
        IN      NS      ns.examle.com.
        IN      NS      ns2.example.com.
*      IN      PTR    examle.com.
Наша сеть небольшая, предполагается, что в сети совсем мало машин. Все сервисы сети размещены на одном хосте example.com., поэтому и master DNS (ns.example.com.) и почтовый сервер (mx.example.com.) указывает на одну машину (10.0.0.152).


args Array List of string arguments
Вторичный (secondary, slave) авторитетный сервер зоны


options Object
Основная функция slave сервера - автоматическая синхронизация описания зоны с master сервером. Данная задача регламентируется документом RFC 1034 в разделе 4.3.5. Согласно данному документу обмен данными между серверами рекомендовано производить по протоколу TCP, посредством запроса AXFR. По этому запросу за одно TCP соединение должна передаваться вся зона целиком (RFC 1035).


cwd String Current working directory of the child process
Так же, slave DNS-сервер делит нагрузку с master сервером или принимает на себя всю нагрузку в случае аварии па первом сервере.
stdio Array|String Child's stdio configuration. (See below)
customFds Array Deprecated File descriptors for the child to use for stdio. (See below)
env Object Environment key-value pairs
detached Boolean The child will be a process group leader. (See below)
uid Number Sets the user identity of the process. (See setuid(2).)
gid Number Sets the group identity of the process. (See setgid(2).)
return: ChildProcess object
Launches a new process with the given command, with command line arguments in args. If omitted, args defaults to an empty Array.


The third argument is used to specify additional options, which defaults to:
Прежде чем приступить к настройке slave DNS сервера, необходимо проверить возможность получения зоны вручную со вторичного сервера с помощью следующей команды:


{ cwd: undefined,
root@debian:~# dig @10.0.0.152 example.com. axfr
  env: process.env
}
cwd allows you to specify the working directory from which the process is spawned. Use env to specify environment variables that will be visible to the new process.


Example of running ls -lh /usr, capturing stdout, stderr, and the exit code:
; <<>> DiG 9.7.3 <<>> @10.0.0.152 example.com. axfr
; (1 server found)
;; global options: +cmd
example.com.            259200  IN      SOA    ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400
example.com.            259200  IN      NS      ns.example.com.
example.com.            259200  IN      NS      ns2.example.com.
example.com.            259200  IN      A      10.0.0.152
example.com.            259200  IN      MX      5 mx.example.com.
mx.example.com.        259200  IN      A      10.0.0.152
ns.example.com.        259200  IN      A      10.0.0.152
ns2.example.com.        259200  IN      A      10.0.0.191
www.example.com.        259200  IN      CNAME  example.com.
example.com.            259200  IN      SOA    ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400
;; Query time: 14 msec
;; SERVER: 10.0.0.152#53(10.0.0.152)
;; WHEN: Fri Jul  8 15:33:54 2011
;; XFR size: 11 records (messages 1, bytes 258)
Получение зоны прошло успешно. Далее, для настройки подчиненного сервера, алгоритм следующий:


var spawn = require('child_process').spawn,
Скопировать конфигурационный файл named.conf с master сервера;
    ls    = spawn('ls', ['-lh', '/usr']);
Заменить параметр type master на type slave в тех зонах, для которых он будет вторичным;
Параметр  allow-transfer { 10.0.0.191; }; заменить на masters { 10.0.0.152;}; в тех зонах, для которых он будет вторичным;
Удалить зоны, которые не будет обслуживать текущий сервер, в том числе и корневую, если slave не будет отвечать на рекурсивные запросы;
Создать каталоги для логов, как в предыдущем примере.
Итого, мы получаем конфиг slave сервера:


ls.stdout.on('data', function (data) {
root@debian:~# cat /etc/bind/named.conf
  console.log('stdout: ' + data);
options {
});
          directory "/var/cache/bind";
          allow-query { any; };      // отвечать на запросы со всех интерфейсов
          recursion no;              // запретить рекурсивные запросы
          auth-nxdomain no;          // для совместимости RFC1035
          listen-on-v6 { none; };    // IPv6 нам не нужен
          version "unknown";         // не отображать версию DNS сервера при ответах
};


ls.stderr.on('data', function (data) {
// нижеописанные зоны определяют сервер авторитетным для петлевых
  console.log('stderr: ' + data);
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)
});


ls.on('close', function (code) {
zone "localhost" {
  console.log('child process exited with code ' + code);
          type master;
});
          file "localhost";
Example: A very elaborate way to run 'ps ax | grep ssh'
};


var spawn = require('child_process').spawn,
zone "127.in-addr.arpa" {
    ps    = spawn('ps', ['ax']),
          type master;
    grep  = spawn('grep', ['ssh']);
          file "127.in-addr.arpa";
};


ps.stdout.on('data', function (data) {
zone "0.in-addr.arpa" {
  grep.stdin.write(data);
          type master;
});
          file "0.in-addr.arpa";
};


ps.stderr.on('data', function (data) {
zone "255.in-addr.arpa" {
  console.log('ps stderr: ' + data);
          type master;
});
          file "255.in-addr.arpa";
};


ps.on('close', function (code) {
// описание основной зоны
  if (code !== 0) {
zone "example.com" {
    console.log('ps process exited with code ' + code);
          type slave;
  }
          file "example.com";
  grep.stdin.end();
          masters { 10.0.0.152; };
});
};


grep.stdout.on('data', function (data) {
//описание обратной зоны
  console.log('' + data);
zone "0.0.10.in-addr.arpa" {
});
          type slave;
          file "0.0.10.in-addr.arpa";
          masters { 10.0.0.152; };
};


grep.stderr.on('data', function (data) {
// настройки логирования
  console.log('grep stderr: ' + data);
logging {
});
          channel "misc" {
                    file "/var/log/bind/misc.log" versions 4 size 4m;
                    print-time YES;
                    print-severity YES;
                    print-category YES;
          };


grep.on('close', function (code) {
          channel "query" {
  if (code !== 0) {
                    file "/var/log/bind/query.log" versions 4 size 4m;
    console.log('grep process exited with code ' + code);
                    print-time YES;
  }
                    print-severity NO;
});
                    print-category NO;
Example of checking for failed exec:
          };


var spawn = require('child_process').spawn,
          category default {
    child = spawn('bad_command');
                    "misc";
          };


child.stderr.setEncoding('utf8');
          category queries {
child.stderr.on('data', function (data) {
                    "query";
  if (/^execvp\(\)/.test(data)) {
          };
    console.log('Failed to start child process.');
};
  }
после перезапуска наш slave сервер благополучно скопирует необходимую ему информацию с главного сервера, о чем будет говорить наличие файлов в  каталоге:
});
Note that if spawn receives an empty options object, it will result in spawning the process with an empty environment rather than using process.env. This due to backwards compatibility issues with a deprecated API.


The 'stdio' option to child_process.spawn() is an array where each index corresponds to a fd in the child. The value is one of the following:
root@debian:~# ls -la /var/cache/bind/
итого 28
drwxrwxr-x  2 root bind 4096 Июл  8 18:47 .
drwxr-xr-x 10 root root 4096 Июл  8 15:17 ..
-rw-r--r--  1 bind bind  416 Июл  8 18:32 0.0.10.in-addr.arpa
......
-rw-r--r--  1 bind bind  455 Июл  8 18:32 example.com
........
В принципе,/stroallow-transfer {pngp slave сервер может не хранить копию зоны у себя в файловой системе. Эта копия нужна только в момент старта DNS. Наличие копии зоны в файловой системе может избавить от сбоя при недоступности master сервера во время запуска slave DNS. Если не указать опцию file в разделе zone, то копия не создается.


'pipe' - Create a pipe between the child process and the parent process. The parent end of the pipe is exposed to the parent as a property on the child_process object as ChildProcess.stdio[fd]. Pipes created for fds 0 - 2 are also available as ChildProcess.stdin, ChildProcess.stdout and ChildProcess.stderr, respectively.
Настройка netfilter (iptables) для DNS BIND
'ipc' - Create an IPC channel for passing messages/file descriptors between parent and child. A ChildProcess may have at most one IPC stdio file descriptor. Setting this option enables the ChildProcess.send() method. If the child writes JSON messages to this file descriptor, then this will trigger ChildProcess.on('message'). If the child is a Node.js program, then the presence of an IPC channel will enable process.send() and process.on('message').
'ignore' - Do not set this file descriptor in the child. Note that Node will always open fd 0 - 2 for the processes it spawns. When any of these is ignored node will open /dev/null and attach it to the child's fd.
Stream object - Share a readable or writable stream that refers to a tty, file, socket, or a pipe with the child process. The stream's underlying file descriptor is duplicated in the child process to the fd that corresponds to the index in the stdio array.
Positive integer - The integer value is interpreted as a file descriptor that is is currently open in the parent process. It is shared with the child process, similar to how Stream objects can be shared.
null, undefined - Use default value. For stdio fds 0, 1 and 2 (in other words, stdin, stdout, and stderr) a pipe is created. For fd 3 and up, the default is 'ignore'.
As a shorthand, the stdio argument may also be one of the following strings, rather than an array:


ignore - ['ignore', 'ignore', 'ignore']
Собственно, настроив работу сервера, неплохо было бы его защитить. Мы знаем, что сервер работает на 53/udp порту. Почитав статью о том, что такое netfilter и правила iptables и ознакомившись с практическими примерами iptables, можно создать правила фильтрации сетевого трафика:
pipe - ['pipe', 'pipe', 'pipe']
inherit - [process.stdin, process.stdout, process.stderr] or [0,1,2]
Example:


var spawn = require('child_process').spawn;
dns ~ # iptables-save
# типовые правила iptables для DNS
*filter
:INPUT DROP [7511:662704]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
# разрешить доступ локальной сети к DNS серверу:
-A INPUT -s 192.168.1.1/24 -d 192.168.1.1/32 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
-A OUTPUT -p udp -m udp --sport 32768:61000 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 32768:61000 -j ACCEPT
-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# разрешить доступ DNS серверу совершать исходящие запросы
-A OUTPUT -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
COMMIT
Это типовой пример! Для задания правил iptables под Ваши задачи и конфигурацию сети, необходимо понимать принцип работы netfilter в Linux, почитав вышеуказанные статьи.


// Child will use parent's stdios
Устранение неполадок
spawn('prg', [], { stdio: 'inherit' });


// Spawn child sharing only stderr
Основным источником для выявления проблем с DNS является системный лог. Вот пример ошибок при запуске, когда я ошибся с путем к файлу зоны коревых серверов:
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });


// Open an extra fd=4, to interact with programs present a
Jul  5 18:12:43 dns-server named[4224]: starting BIND 9.7.3 -u bind
// startd-style interface.
Jul  5 18:12:43 dns-server named[4224]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS='
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });
Jul  5 18:12:43 dns-server named[4224]: adjusted limit on open files from 1024 to 1048576
If the detached option is set, the child process will be made the leader of a new process group. This makes it possible for the child to continue running after the parent exits.
Jul  5 18:12:43 dns-server named[4224]: found 1 CPU, using 1 worker thread
Jul  5 18:12:43 dns-server named[4224]: using up to 4096 sockets
Jul  5 18:12:43 dns-server named[4224]: loading configuration from '/etc/bind/named.conf'
Jul  5 18:12:43 dns-server named[4224]: reading built-in trusted keys from file '/etc/bind/bind.keys'
Jul  5 18:12:43 dns-server named[4224]: using default UDP/IPv4 port range: [1024, 65535]
Jul  5 18:12:43 dns-server named[4224]: using default UDP/IPv6 port range: [1024, 65535]
Jul  5 18:12:43 dns-server named[4224]: listening on IPv4 interface lo, 127.0.0.1#53
Jul  5 18:12:43 dns-server named[4224]: listening on IPv4 interface eth1, 192.168.1.1#53
Jul  5 18:12:43 dns-server named[4224]: generating session key for dynamic DNS
Jul  5 18:12:43 dns-server named[4224]: could not configure root hints from '/etc/bind/db.root': file not found
Jul  5 18:12:43 dns-server named[4224]: loading configuration: file not found            # файл не найден
Jul  5 18:12:43 dns-server named[4224]: exiting (due to fatal error)
Jul  5 18:15:05 dns-server named[4298]: starting BIND 9.7.3 -u bind
Jul  5 18:15:05 dns-server named[4298]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS='
Jul  5 18:15:05 dns-server named[4298]: adjusted limit on open files from 1024 to 1048576
Jul  5 18:15:05 dns-server named[4298]: found 1 CPU, using 1 worker thread
Jul  5 18:15:05 dns-server named[4298]: using up to 4096 sockets
Jul  5 18:15:05 dns-server named[4298]: loading configuration from '/etc/bind/named.conf'
Jul  5 18:15:05 dns-server named[4298]: using default UDP/IPv4 port range: [1024, 65535]
Jul  5 18:15:05 dns-server named[4298]: using default UDP/IPv6 port range: [1024, 65535]
Jul  5 18:15:05 dns-server named[4298]: listening on IPv4 interface lo, 127.0.0.1#53
Jul  5 18:15:05 dns-server named[4298]: listening on IPv4 interface eth1, 192.168.1.1#53
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 254.169.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 2.0.192.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 100.51.198.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 113.0.203.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: D.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 8.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 9.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: A.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: B.E.F.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: automatic empty zone: 8.B.D.0.1.0.0.2.IP6.ARPA
Jul  5 18:15:05 dns-server named[4298]: zone 0.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone 127.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone 255.in-addr.arpa/IN: loaded serial 1
Jul  5 18:15:05 dns-server named[4298]: zone localhost/IN: loaded serial 2
Jul  5 18:15:05 dns-server named[4298]: running                                 # запуск прошел удачно
Отличным инструментом для диагностики являются команды диагностики DNS.


By default, the parent will wait for the detached child to exit. To prevent the parent from waiting for a given child, use the child.unref() method, and the parent's event loop will not include the child in its reference count.
* [http://www.k-max.name/linux/howto-dns-server-bind/ HOWTO DNS сервер BIND (практика)]
 
Example of detaching a long-running process and redirecting its output to a file:
 
var fs = require('fs'),
    spawn = require('child_process').spawn,
    out = fs.openSync('./out.log', 'a'),
    err = fs.openSync('./out.log', 'a');
 
var child = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ]
});
 
child.unref();
When using the detached option to start a long-running process, the process will not stay running in the background unless it is provided with a stdio configuration that is not connected to the parent. If the parent's stdio is inherited, the child will remain attached to the controlling terminal.
 
There is a deprecated option called customFds which allows one to specify specific file descriptors for the stdio of the child process. This API was not portable to all platforms and therefore removed. With customFds it was possible to hook up the new process' [stdin, stdout, stderr] to existing streams; -1 meant that a new stream should be created. Use at your own risk.
 
See also: child_process.exec() and child_process.fork()
 
child_process.exec(command, [options], callback)#
command String The command to run, with space-separated arguments
options Object
cwd String Current working directory of the child process
env Object Environment key-value pairs
encoding String (Default: 'utf8')
timeout Number (Default: 0)
maxBuffer Number (Default: 200*1024)
killSignal String (Default: 'SIGTERM')
callback Function called with the output when process terminates
error Error
stdout Buffer
stderr Buffer
Return: ChildProcess object
Runs a command in a shell and buffers the output.
 
var exec = require('child_process').exec,
    child;
 
child = exec('cat *.js bad_file | wc -l',
  function (error, stdout, stderr) {
    console.log('stdout: ' + stdout);
    console.log('stderr: ' + stderr);
    if (error !== null) {
      console.log('exec error: ' + error);
    }
});
The callback gets the arguments (error, stdout, stderr). On success, error will be null. On error, error will be an instance of Error and err.code will be the exit code of the child process, and err.signal will be set to the signal that terminated the process.
 
There is a second optional argument to specify several options. The default options are
 
{ encoding: 'utf8',
  timeout: 0,
  maxBuffer: 200*1024,
  killSignal: 'SIGTERM',
  cwd: null,
  env: null }
If timeout is greater than 0, then it will kill the child process if it runs longer than timeout milliseconds. The child process is killed with killSignal (default: 'SIGTERM'). maxBuffer specifies the largest amount of data allowed on stdout or stderr - if this value is exceeded then the child process is killed.
 
child_process.execFile(file, args, options, callback)#
file String The filename of the program to run
args Array List of string arguments
options Object
cwd String Current working directory of the child process
env Object Environment key-value pairs
encoding String (Default: 'utf8')
timeout Number (Default: 0)
maxBuffer Number (Default: 200*1024)
killSignal String (Default: 'SIGTERM')
callback Function called with the output when process terminates
error Error
stdout Buffer
stderr Buffer
Return: ChildProcess object
This is similar to child_process.exec() except it does not execute a subshell but rather the specified file directly. This makes it slightly leaner than child_process.exec. It has the same options.
 
child_process.fork(modulePath, [args], [options])#
modulePath String The module to run in the child
args Array List of string arguments
options Object
cwd String Current working directory of the child process
env Object Environment key-value pairs
encoding String (Default: 'utf8')
execPath String Executable used to create the child process
Return: ChildProcess object
This is a special case of the spawn() functionality for spawning Node processes. In addition to having all the methods in a normal ChildProcess instance, the returned object has a communication channel built-in. See child.send(message, [sendHandle]) for details.
 
By default the spawned Node process will have the stdout, stderr associated with the parent's. To change this behavior set the silent property in the options object to true.
 
The child process does not automatically exit once it's done, you need to call process.exit() explicitly. This limitation may be lifted in the future.
 
These child Nodes are still whole new instances of V8. Assume at least 30ms startup and 10mb memory for each new Node. That is, you cannot create many thousands of them.
 
The execPath property in the options object allows for a process to be created for the child rather than the current node executable. This should be done with care and by default will talk over the fd represented an environmental variable NODE_CHANNEL_FD on the child process. The input and output on this fd is expected to be line delimited JSON objects.

Версия от 16:26, 16 октября 2016

Исходные данные

Для корректной работы DNS нем необходимо иметь настроенную сеть. DNS в текущей статье будет настроен на дистрибутиве Debian, особенности других дистрибутивов тоже будут отмечены. Конфиг сети стенда следующий:

dns:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
 address 10.0.0.152
 netmask 255.255.255.0
 gateway 10.0.0.254

auto eth1
iface eth1 inet static
 address 192.168.1.1
 netmask 255.255.255.0

где 10.0.0.152/24 - внешний интерфейс (подсеть, выделенная провайдером), 192.168.1.1/24 - внутренний (Локальная сеть). Настраиваемая зона будет иметь имя example.com. В примере со slave сервером, вторичный сервер будет расположен на IP 10.0.0.191.

Установка BIND9

Для работы DNS сервера необходимо установить пакет bind9 (в некоторых дистрибутивах - bind). Как отмечено на схеме - основным конфигурационным файлом BIND является файл named.conf (данный файл может быть размещен в каталоге /etc, иногда в /etc/bind ).

Параметры (синтаксис) named.conf

Синтаксис файла named.conf придерживается следующих правил:

IP-адреса - список IP должен быть разделен символом ";" , возможно указывать подсеть в формате 192.168.1.1/24 или 192.168.1.1/255.255.255.0, (для исключения IP перед ним нужно поставить знак !), возможно указывать имена "any", "none", "localhost" в двойных кавычках.

Комментарии - строки начинающиеся на #, // и заключенные в /* и */ считаются комментариями.

В файлах описания зон - символ @ является "переменной" хранящей имя зоны, указанной в конфигурационном файле named.conf или в директиве @ $ORIGIN текущего описания зоны.

Каждая завершенная строка параметров должна завершаться символом ; .

Раздел Acl Acl (access control list) - позволяет задать именованный список сетей. Формат раздела: acl "имя_сети" {ip; ip; ip; };

Раздел Options Раздел Options задает глобальные параметры конфигурационного файла, управляющие всеми зонами. Данный раздел имеет формат: options {операторы_раздела_Options};. Options может быть "вложен" в раздел Zone, при этом он переопределяет глобальные параметры. Часто используемые операторы options:

allow-query {список_ip} - Разрешает ответы на запросы только из список_ip. При отсутствии - сервер отвечает на все запросы.
allow-recursion {список_ip} - На запросы из список_ip будут выполняться рекурсивные запросы. Для остальных - итеративные. Если  не задан параметр, то сервер выполняет рекурсивные запросы для всех сетей.
allow-transfer {список_ip} - Указывает список серверов, которым разрешено брать зону с сервера (в основном тут указывают slave сервера)
directory /path/to/work/dir - указывает абсолютный путь к рабочему каталогу сервера. Этот оператор допустим только в разделе  options.
forwarders {ip порт, ip порт...} - указывает адреса хостов и если нужно порты, куда переадресовывать запросы (обычно тут указываются DNS провайдеров ISP).
forward ONLY или forward FIRST - параметр first указывает, DNS-серверу пытаться разрешать имена с помощью DNS-серверов, указанных в параметре forwarders, и лишь в случае, если разрешить имя с помощью данных серверов не удалось, то будет осуществлять попытки разрешения имени самостоятельно.
notify YES|NO - YES - уведомлять slave сервера об изменениях в зоне, NO - не уведомлять.
recursion YES|NO - YES - выполнять рекурсивные запросы, если просит клиент, NO - не выполнять (только итеративные запросы). Если ответ найден в кэше, то возвращается из кэша. (может использоваться только в разделе Options)

Раздел Zone Определяет описание зон(ы). Формат раздела: zone {операторы_раздела_zone}; Операторы, которые наиболее часто используются:

allow-update {список_ip} - указывает системы, которым разрешено динамически обновлять данную зону.
file "имя_файла" - указывает путь файла параметров зоны (должен быть расположен в каталоге, определенном в разделе options оператором directory)
masters {список_ip} -указывает список мастер-серверов. (допустим только в подчиненных зонах)
type "тип_зоны" - указывает тип зоны, описываемой в текущем разделе,тип_зоны может принимать следующие значения:
forward - указывает зону переадресации, которая переадресовывает запросы, пришедшие в эту зону.
hint - указывает вспомогательную зону (данный тип содержит информацию о корневых серверах, к которым сервер будет обращаться в случае невозможности найти ответ в кэше)
master - указывает работать в качестве мастер сервера для текущей зоны.
slave - указывает работать в качестве подчиненного сервера для текущей зоны.

Дополнительные параметры конфигурации Значения времени в файлах зон по умолчанию указывается в секундах, если за ними не стоит одна из следующих букв: S - секунды, M - минуты, H- часы, D - дни, W - недели. Соответственно, запись 2h20m5s будет иметь значение 2 часа 20 минут 5 секунд и соответствовать 8405 секунд.

Любое имя хоста/записи, не оканчивающиеся точкой считается неFQDN именем и будет дополнено именем текущей зоны. Например, запись domen в файле зоны examle.com будет развернуто в FQDN-имя domen.examle.com. .

В конфигурационных файлах BIND могут применяться следующие директивы:

$TTL - определяет TTL по-умолчанию для всех записей в текущей зоне.
$ORIGIN - изменяет имя зоны с указанного в файле named.conf. При этом, область действия данной директивы не распространяется  "выше" (то есть если файл включен директивой $INCLUDE, то область действия$ORIGN не распространяется на родительский)
$INCLUDE - включает указанный файл как часть файла зоны.

Для того чтобы локальный резолвер сервера тоже использовал локальный DNS, необходимо привести файл resolv.conf к следующему виду:

dns:~# cat /etc/resolv.conf
nameserver 127.0.0.1

Если в имени ресурсной записи встречается символ "*", то это он означает что вместо него можно подразумевать любую разрешенную последовательность символов. Такую запись называют "wildcard запись". Однако, символ "*" не может быть использован где угодно. Это может быть только первый символ в поле Name текущего домена, отделенный от остальных символом "."

Настройка кэширующего DNS сервера

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

Для того, чтобы BIND работал в качестве кэширующего сервера, необходимо иметь конфигурационные файлы заполненные необходимой информацией:

named.conf;
описание серверов корневой зоны (зона типа hint);
описание зоны 127.in-addr.arpa.
dns:~# cat /etc/bind/named.conf
acl "lan" {
           192.168.1.1/24;
           127.0.0.1;
};

options {
           directory "/var/cache/bind";

          // If there is a firewall between you and nameservers you want
          // to talk to, you may need to fix the firewall to allow multiple
          // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
          /*
          * Тут сказано, что если используется фаерволл, то необходимо
          *  нашему серверу создать соответствующие правила
          *  то есть открыть доступ по 53 TCP и UDP порту
          */

          forward first;              // задаем пересылку только первого запроса

          forwarders {                // указываем DNS сервера для пересылки
                     83.239.0.202;    // предоставленные провайдером
                     213.132.67.110;  // ибо до них ближе чем до корневых
          };

         listen-on { lan; };        // пусть слушает только нужные интерфейсы
         allow-query { lan; };      // разрешить запросы только из локальной сети
         allow-recursion { lan; };  // рекурсивные запросы тоже только из локальной
         allow-transfer { none; };  // трансфер зон нам не нужен

         version "unknown";         // не отображать версию DNS сервера при ответах

         auth-nxdomain no;    # для совместимости RFC1035
         listen-on-v6 { none; };    //IPv6 нам не нужен
         };

// описание настроек корневых серверов
zone "." {
         type hint;
         file "db.root";
};

// нижеописанные зоны определяют сервер авторитетным для петлевых
// интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {
         type master;
         file "localhost";
};

zone "127.in-addr.arpa" {
         type master;
          file "127.in-addr.arpa";
};

zone "0.in-addr.arpa" {
         type master;
         file "0.in-addr.arpa";
};

zone "255.in-addr.arpa" {
         type master;
         file "255.in-addr.arpa";
};

В данном примере приведен кэширующий DNS сервер, обрабатывающий запросы из списка сетей lan, в которую входит только одна локальная сеть 192.168.1.1/24 и петлевой интерфейс. При необходимости можно включить туда и другие сети. После определения списка сетей в директиве acl, в любом месте конфига можно будет ссылаться на этот список по имени (в нашем примере имя - lan), что, собственно и сделано в разделе options. Большинство параметров я прокомментировал, но отдельного внимания требует раздел, описывающий зону корневых серверов. В параметре file задан относительный путь к файлу описания корневых серверов (путь, относительно рабочего каталога сервера). За обновлениями данного файла необходимо следить, хотя он обновляется довольно редко (откуда брать обновленный файл я писал в теории DNS). Как вы заметили, имеется так же две записи для зоны localhost и две записи обратных зон для бродкаст доменов. Назначение этих зон состоит в том, чтобы избежать трансляции случайных запросов имен соответствующих IP-адресов на серверы, обслуживающие корневую зону.

Чтобы не вносить неразбериху в куче конфигурационных файлов, в статье я привожу примеры на основе единого конфигурационного файла. На самом деле, в последних версиях Debian (и других дистрибутивах Linux), файл named.conf выглядит следующим образом:

root@master:~# cat /etc/bind/named.conf // This is the primary configuration file for the BIND DNS server named. // // Please read /usr/share/doc/bind9/README.Debian.gz for information on the // structure of BIND configuration files in Debian, *BEFORE* you customize // this configuration file. // // If you are just adding zones, please do that in /etc/bind/named.conf.local

include "/etc/bind/named.conf.options"; include "/etc/bind/named.conf.local"; include "/etc/bind/named.conf.default-zones"; То есть основной файл не содержит конфигураций, а включает в себя более узко специализированные файлы, которые отвечают за свои задачи, например named.conf.options - содержит глобальные параметры конфигурации, named.conf.default-zones - содержит описание localhost и broadcast зон, а named.conf.local содержит описания зон, за которые отвечает данный сервер.


Далее, хочу обратить внимание на наличие файлов зон в каталоге, указанном в разделе options в параметре directory с именами, соответствующими параметрам file в разделах, описывающих зоны:

dns:~# ls -l /var/cache/bind/ итого 24 -rw-r--r-- 1 root root 237 Май 28 01:28 0.in-addr.arpa -rw-r--r-- 1 root root 271 Май 28 01:28 127.in-addr.arpa -rw-r--r-- 1 root root 237 Май 28 01:28 255.in-addr.arpa -rw-r--r-- 1 root root 2994 Май 28 01:28 db.root -rw-r--r-- 1 root root 270 Май 28 01:28 localhost dns:~# cat /var/cache/bind/127.in-addr.arpa

BIND reverse data file for local loopback interface

$TTL 604800 @ IN SOA localhost. root.localhost. (

                             1         ; Serial
                             604800    ; Refresh
                             86400     ; Retry
                             2419200   ; Expire
                             604800 )  ; Negative Cache TTL

@ IN NS localhost. 1.0.0 IN PTR localhost. Рассматривать файлы "петлевых" и бродкастовых зон не вижу смысла, т.к. после установки пакета bind настройки заданные по умолчанию в данных файлах вполне приемлемы. Далее, при организации мастер сервера мы рассмотрим пример описания файла зоны. Хочу обратить внимание, что мы настраиваем кэширующий сервер, а определяем мы его и как master для некоторых из зон. В нашем случае "кэширующий" говорит о том, что наш сервер не поддерживает ни одну из реально существующих зон, т.е. ему не делегировано прав на такое обслуживание.

Да, чуть не забыл, демон named должен быть разрешен для запуска на необходимых уровнях выполнения ОС (команда в RedHat - /sbin/chkconfig bind9 on, в Debian - /usr/sbin/update-rc.d bind9 defaults). После изменения конфигурационных файлов можно добавить сервис в автозагрузку и запустить демон:

dns:~# update-rc.d bind9 defaults Adding system startup for /etc/init.d/bind9 ... /etc/rc0.d/K20bind9 -> ../init.d/bind9 /etc/rc1.d/K20bind9 -> ../init.d/bind9 /etc/rc6.d/K20bind9 -> ../init.d/bind9 /etc/rc2.d/S20bind9 -> ../init.d/bind9 /etc/rc3.d/S20bind9 -> ../init.d/bind9 /etc/rc4.d/S20bind9 -> ../init.d/bind9 /etc/rc5.d/S20bind9 -> ../init.d/bind9 dns:~# /etc/init.d/bind9 start Starting domain name service...: bind9. На этом настройка кэширующего DNS завершена. Все запросы, которые попадают в кэш DNS сервера он хранит в оперативной памяти компьютера и при перезапуске демона эти данные обнуляются. Для проверки работы кэша можно выполнить команду nslookup mail.ru example.com., если в ответе содержится строка Non-authoritative answer, то адрес пришел из кэша, а так же если выполнить dig www.ru. (или другой домен, которого еще нет в кэше) и через некоторое время повторить команду, то время ответа должно быть гораздо меньше.

Давайте рассмотрим другие варианты сервера.

Главный (master) сервер зоны

Основной конфиг содержит следующие настройки:

dns:~# cat /etc/bind/named.conf acl "lan" {

         192.168.1.1/24;
         127.0.0.1;

};

options {

         directory "/var/cache/bind";
         allow-query { any; };       // отвечать на зпросы со всех интерфейсов
         recursion no;               // запретить рекурсивные запросы
         auth-nxdomain no;           // для совместимости RFC1035
         listen-on-v6 { none; };     // IPv6 нам не нужен
         version "unknown";          // не отображать версию DNS сервера при ответах
         /*
         *  Раскомментируйте строки ниже, если
         *  хотите разрешить рекрусивные запросы
         *  из локальной сети.
         *  (так же, необходимо закомментировать
         *  recursion no; )
         */
         # forwarders {                 // указываем DNS сервера для пересылки
         #         83.239.0.202;        // предоставленные провайдером
         #         213.132.67.110;      // ибо до них ближе чем до корневых
         # };
         # allow-recursion { lan; };    // рекурсивные запросы тоже только из локальной

};

// описание настроек корневых серверов zone "." {

         type hint;
         file "db.root";

};

// нижеописанные зоны определяют сервер авторитетным для петлевых // интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {

         type master;
         file "localhost";

};

zone "127.in-addr.arpa" {

         type master;
         file "127.in-addr.arpa";

};

zone "0.in-addr.arpa" {

         type master;
         file "0.in-addr.arpa";

};

zone "255.in-addr.arpa" {

         type master;
         file "255.in-addr.arpa";

};

// описание основной зоны zone "example.com" {

         type master;
         file "example.com";
         allow-transfer { 10.0.0.191; };

};

//описание обратных зон zone "0.0.10.in-addr.arpa" {

         type master;
         file "0.0.10.in-addr.arpa";
         allow-transfer { 10.0.0.191; };

};

zone "1.168.192.in-addr.arpa" {

         type master;
         file "1.168.192.in-addr.arpa";
  1. allow-transfer { 10.0.0.191; }; // зона описывает локальную сеть поэтому ее не передаем

};

// настройки логирования logging {

         channel "misc" {
                   file "/var/log/bind/misc.log" versions 4 size 4m;
                   print-time yes;
                   print-severity yes;
                   print-category yes;
         };
         channel "query" {
                   file "/var/log/bind/query.log" versions 4 size 4m;
                   print-time yes;
                   print-severity no;
                   print-category no;
         };
         category default {
                   "misc";
         };
         category queries {
                   "query";
         };

}; Давайте кратко разберем конфигурационный файл и настройки master сервера: мы настраиваем мастер сервер для зоны example.com. . Согласно конфига, наш BIND имеет рабочий каталог /var/cache/bind, сервер отвечает на запросы со всех интерфейсов (allow-query {any ;};), рекурсивные запросы обрабатывает как итеративные (recursion no), является мастер-сервером для зоны example.com и локальных служебных зон (type master). При этом, если необходимо разрешить кэширование (то есть рекурсивные запросы) для локальной сети, то необходимо раскомментировать параметры forwarders и allow-recursion и закомментировать recursion no;.

Так же, для примера, я привел возможности BIND логировать все происходящее при работе сервера (можно для этой цели использовать syslog). В разделе logging задаются 2 параметра channel (можно и больше двух - на ваше усмотрение), эти параметры дословно можно назвать "канал" записи. Каждый канал определяет имя канала и настройки параметров записи (что записывать, а что - нет и куда писать). Директива category задает какую категорию сообщений в какой канал отправлять. Исходя из этого, мы имеем: запись стандартной информации в канал misc, а приходящие запросы посылаются в канал query. При этом, если файлы журнала достигают 4Мб (size 4m), он переименовывается добавлением к имени .1 и начинается запись в новый журнал, числа в конце других журналов увеличиваются. Журналы с номером, более указанного в version (в нашем случае 4) удаляются (Управлять ротацией логов можно так же с помощью logrotate). Параметры print* определяют заносить ли в журнал время появления, важность и категорию информации. Более подробно про настройки раздела logging можно почитать в man (5) named.conf.

Отдельно хочется описать параметр allow-transfer { 10.0.0.191; };. Данный параметр описывает серверы, которым разрешено скачивать копию зоны - т.н. slave серверА. В следующем примере мы разберем настройку slave DNS.

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

dns:~# mkdir /var/log/bind/ dns:~# chmod 744 /var/log/bind/ dns:~# ps aux | grep named bind 4298 0.0 3.4 46792 13272 ? Ssl Jul05 0:00 /usr/sbin/named -u bind root 4815 0.0 0.1 3304 772 pts/4 S+ 18:19 0:00 grep named dns:~# chown bind /var/log/bind/ dns:~# ls -ld /var/log/bind/ drwxr--r-- 2 bind root 4096 Июл 6 18:18 /var/log/bind/ Давайте далее рассмотрим наш файл описания зоны example.com.:

dns:~# cat /var/cache/bind/example.com $TTL 3D @ IN SOA ns.example.com. root.example.com. (

                                       2011070601      ; serial
                                       8H              ; refresh
                                       2H              ; retry
                                       2W              ; expire
                                       1D)             ; minimum

@ IN NS ns.example.com. @ IN NS ns2.example.com. @ IN A 10.0.0.152 @ IN MX 5 mx.example.com. ns IN A 10.0.0.152 ns2 IN A 10.0.0.191 mx IN A 10.0.0.152 www IN CNAME @ а так же в домене in-addr.arpa.

dns:~# cat /var/cache/bind/0.0.10.in-addr.arpa $TTL 3600 @ IN SOA ns.examle.com. root.example.com. (

            2007042001 ; Serial
            3600       ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
       IN      NS      ns.examle.com.
       IN      NS      ns2.example.com.

152 IN PTR examle.com. 191 IN PTR ns.example.com.

  • IN PTR examle.com.

dns:~# cat /var/cache/bind/1.168.192.in-addr.arpa $TTL 3600 @ IN SOA ns.examle.com. root.example.com. (

            2007042001 ; Serial
            3600       ; Refresh
            900        ; Retry
            3600000    ; Expire
            3600 )     ; Minimum
       IN      NS      ns.examle.com.
       IN      NS      ns2.example.com.
  • IN PTR examle.com.

Наша сеть небольшая, предполагается, что в сети совсем мало машин. Все сервисы сети размещены на одном хосте example.com., поэтому и master DNS (ns.example.com.) и почтовый сервер (mx.example.com.) указывает на одну машину (10.0.0.152).

Вторичный (secondary, slave) авторитетный сервер зоны

Основная функция slave сервера - автоматическая синхронизация описания зоны с master сервером. Данная задача регламентируется документом RFC 1034 в разделе 4.3.5. Согласно данному документу обмен данными между серверами рекомендовано производить по протоколу TCP, посредством запроса AXFR. По этому запросу за одно TCP соединение должна передаваться вся зона целиком (RFC 1035).

Так же, slave DNS-сервер делит нагрузку с master сервером или принимает на себя всю нагрузку в случае аварии па первом сервере.

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

root@debian:~# dig @10.0.0.152 example.com. axfr

<<>> DiG 9.7.3 <<>> @10.0.0.152 example.com. axfr
(1 server found)
global options
+cmd

example.com. 259200 IN SOA ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400 example.com. 259200 IN NS ns.example.com. example.com. 259200 IN NS ns2.example.com. example.com. 259200 IN A 10.0.0.152 example.com. 259200 IN MX 5 mx.example.com. mx.example.com. 259200 IN A 10.0.0.152 ns.example.com. 259200 IN A 10.0.0.152 ns2.example.com. 259200 IN A 10.0.0.191 www.example.com. 259200 IN CNAME example.com. example.com. 259200 IN SOA ns.example.com. root.example.com. 2011070801 28800 7200 1209600 86400

Query time
14 msec
SERVER
10.0.0.152#53(10.0.0.152)
WHEN
Fri Jul 8 15:33:54 2011
XFR size
11 records (messages 1, bytes 258)

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

Скопировать конфигурационный файл named.conf с master сервера; Заменить параметр type master на type slave в тех зонах, для которых он будет вторичным; Параметр allow-transfer { 10.0.0.191; }; заменить на masters { 10.0.0.152;}; в тех зонах, для которых он будет вторичным; Удалить зоны, которые не будет обслуживать текущий сервер, в том числе и корневую, если slave не будет отвечать на рекурсивные запросы; Создать каталоги для логов, как в предыдущем примере. Итого, мы получаем конфиг slave сервера:

root@debian:~# cat /etc/bind/named.conf options {

         directory "/var/cache/bind";
         allow-query { any; };      // отвечать на запросы со всех интерфейсов
         recursion no;              // запретить рекурсивные запросы
         auth-nxdomain no;          // для совместимости RFC1035
         listen-on-v6 { none; };    // IPv6 нам не нужен
         version "unknown";         // не отображать версию DNS сервера при ответах

};

// нижеописанные зоны определяют сервер авторитетным для петлевых // интерфейсов, а так же для броадкаст-зон (согласно RFC 1912)

zone "localhost" {

         type master;
         file "localhost";

};

zone "127.in-addr.arpa" {

         type master;
         file "127.in-addr.arpa";

};

zone "0.in-addr.arpa" {

         type master;
         file "0.in-addr.arpa";

};

zone "255.in-addr.arpa" {

         type master;
         file "255.in-addr.arpa";

};

// описание основной зоны zone "example.com" {

         type slave;
         file "example.com";
         masters { 10.0.0.152; };

};

//описание обратной зоны zone "0.0.10.in-addr.arpa" {

         type slave;
         file "0.0.10.in-addr.arpa";
         masters { 10.0.0.152; };

};

// настройки логирования logging {

         channel "misc" {
                   file "/var/log/bind/misc.log" versions 4 size 4m;
                   print-time YES;
                   print-severity YES;
                   print-category YES;
         };
         channel "query" {
                   file "/var/log/bind/query.log" versions 4 size 4m;
                   print-time YES;
                   print-severity NO;
                   print-category NO;
         };
         category default {
                   "misc";
         };
         category queries {
                   "query";
         };

}; после перезапуска наш slave сервер благополучно скопирует необходимую ему информацию с главного сервера, о чем будет говорить наличие файлов в каталоге:

root@debian:~# ls -la /var/cache/bind/ итого 28 drwxrwxr-x 2 root bind 4096 Июл 8 18:47 . drwxr-xr-x 10 root root 4096 Июл 8 15:17 .. -rw-r--r-- 1 bind bind 416 Июл 8 18:32 0.0.10.in-addr.arpa ...... -rw-r--r-- 1 bind bind 455 Июл 8 18:32 example.com ........ В принципе,/stroallow-transfer {pngp slave сервер может не хранить копию зоны у себя в файловой системе. Эта копия нужна только в момент старта DNS. Наличие копии зоны в файловой системе может избавить от сбоя при недоступности master сервера во время запуска slave DNS. Если не указать опцию file в разделе zone, то копия не создается.

Настройка netfilter (iptables) для DNS BIND

Собственно, настроив работу сервера, неплохо было бы его защитить. Мы знаем, что сервер работает на 53/udp порту. Почитав статью о том, что такое netfilter и правила iptables и ознакомившись с практическими примерами iptables, можно создать правила фильтрации сетевого трафика:

dns ~ # iptables-save

  1. типовые правила iptables для DNS
  • filter
INPUT DROP [7511:662704]
FORWARD DROP [0:0]
OUTPUT DROP [0:0]

-A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP

  1. разрешить доступ локальной сети к DNS серверу:

-A INPUT -s 192.168.1.1/24 -d 192.168.1.1/32 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT -A OUTPUT -o lo -j ACCEPT -A OUTPUT -p icmp -j ACCEPT -A OUTPUT -p udp -m udp --sport 32768:61000 -j ACCEPT -A OUTPUT -p tcp -m tcp --sport 32768:61000 -j ACCEPT -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

  1. разрешить доступ DNS серверу совершать исходящие запросы

-A OUTPUT -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT COMMIT Это типовой пример! Для задания правил iptables под Ваши задачи и конфигурацию сети, необходимо понимать принцип работы netfilter в Linux, почитав вышеуказанные статьи.

Устранение неполадок

Основным источником для выявления проблем с DNS является системный лог. Вот пример ошибок при запуске, когда я ошибся с путем к файлу зоны коревых серверов:

Jul 5 18:12:43 dns-server named[4224]: starting BIND 9.7.3 -u bind Jul 5 18:12:43 dns-server named[4224]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS=' Jul 5 18:12:43 dns-server named[4224]: adjusted limit on open files from 1024 to 1048576 Jul 5 18:12:43 dns-server named[4224]: found 1 CPU, using 1 worker thread Jul 5 18:12:43 dns-server named[4224]: using up to 4096 sockets Jul 5 18:12:43 dns-server named[4224]: loading configuration from '/etc/bind/named.conf' Jul 5 18:12:43 dns-server named[4224]: reading built-in trusted keys from file '/etc/bind/bind.keys' Jul 5 18:12:43 dns-server named[4224]: using default UDP/IPv4 port range: [1024, 65535] Jul 5 18:12:43 dns-server named[4224]: using default UDP/IPv6 port range: [1024, 65535] Jul 5 18:12:43 dns-server named[4224]: listening on IPv4 interface lo, 127.0.0.1#53 Jul 5 18:12:43 dns-server named[4224]: listening on IPv4 interface eth1, 192.168.1.1#53 Jul 5 18:12:43 dns-server named[4224]: generating session key for dynamic DNS Jul 5 18:12:43 dns-server named[4224]: could not configure root hints from '/etc/bind/db.root': file not found Jul 5 18:12:43 dns-server named[4224]: loading configuration: file not found # файл не найден Jul 5 18:12:43 dns-server named[4224]: exiting (due to fatal error) Jul 5 18:15:05 dns-server named[4298]: starting BIND 9.7.3 -u bind Jul 5 18:15:05 dns-server named[4298]: built with '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--localstatedir=/var' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-dlz-postgres=no' '--with-dlz-mysql=no' '--with-dlz-bdb=yes' '--with-dlz-filesystem=yes' '--with-dlz-ldap=yes' '--with-dlz-stub=yes' '--with-geoip=/usr' '--enable-ipv6' 'CFLAGS=-fno-strict-aliasing -DDIG_SIGCHASE -O2' 'LDFLAGS=' 'CPPFLAGS=' Jul 5 18:15:05 dns-server named[4298]: adjusted limit on open files from 1024 to 1048576 Jul 5 18:15:05 dns-server named[4298]: found 1 CPU, using 1 worker thread Jul 5 18:15:05 dns-server named[4298]: using up to 4096 sockets Jul 5 18:15:05 dns-server named[4298]: loading configuration from '/etc/bind/named.conf' Jul 5 18:15:05 dns-server named[4298]: using default UDP/IPv4 port range: [1024, 65535] Jul 5 18:15:05 dns-server named[4298]: using default UDP/IPv6 port range: [1024, 65535] Jul 5 18:15:05 dns-server named[4298]: listening on IPv4 interface lo, 127.0.0.1#53 Jul 5 18:15:05 dns-server named[4298]: listening on IPv4 interface eth1, 192.168.1.1#53 Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 254.169.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 2.0.192.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 100.51.198.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 113.0.203.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 255.255.255.255.IN-ADDR.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: D.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 8.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 9.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: A.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: B.E.F.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: automatic empty zone: 8.B.D.0.1.0.0.2.IP6.ARPA Jul 5 18:15:05 dns-server named[4298]: zone 0.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone 127.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone 255.in-addr.arpa/IN: loaded serial 1 Jul 5 18:15:05 dns-server named[4298]: zone localhost/IN: loaded serial 2 Jul 5 18:15:05 dns-server named[4298]: running # запуск прошел удачно Отличным инструментом для диагностики являются команды диагностики DNS.