Pull to refresh

BIND: храним зоны в mysql (Dynamically Loadable Zones — BIND DLZ)

Reading time 4 min
Views 15K
Возможность Berkeley Internet Name Daemon (BIND) хранить зоны DNS в базе mysql не шибко известна и крайне плохо документирована. Документация заморожена на моменте включения отдельного патча DLZ в основную ветку BIND, а это BIND 9.4.* и 2005-2006 годы. Я постараюсь хотя бы частично восполнить этот пробел, выложив под хабракатом рабочие на данный момент инструкции с примерами. Мое описание совершенно не претендует на полноту, но простейшую зону прописать позволит.
Отдельно хочу заметить, что DLZ поддерживает не только mysql, список поддерживаемых хранилищ также под хабракатом.


Начну со списка хранилищ, которые поддерживает DLZ:
  1. Файловая система — все данные хранятся в именах файлов и каталогов, определенном образом структурированных
  2. Berkeley DB
  3. PostgreSQL
  4. MySQL
  5. ODBC (Firebird, Oracle, DB2, Sybase, SAPDB, MS SQL Server, и т.п.)
  6. LDAP


Для работы с DLZ bind должен быть собран с поддержкой DLZ и соответствующими драйверами хранилища. Как этого добиться — смотрите руководство к Вашей ОС.

Конкретно mysql драйвер не работает с BIND, скомпилированным с поддержкой потоков (threads), на некоторых ОС, в том числе на linux. Список ОС, в которых mysql драйвер может использоваться в многотопоточном BIND, есть в описании mysql драйвера на официальном сайте DLZ.

В gentoo включаем следующие USE для BIND со следующими USE=dlz mysql -threads (остальное на Ваш выбор).

Создаем БД, например, «dns», в ней таблицу, например, «records» и пользователя, который имеет право на SELECT из этой БД. Вообще dlz поддерживает любой вариант структуры, так как в конфиге BIND мы будет указывать конкретные sql-запросы на получение данных. Здесь я привожу то, что взято из официальной документации и доработано до текущих реалий (BIND 9.7.4_p1).

Мой вариант структуры таблицы records:

CREATE TABLE IF NOT EXISTS `records` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `zone` varchar(255) NOT NULL,
  `ttl` int(11) NOT NULL DEFAULT '86400',
  `type` varchar(255) NOT NULL,
  `host` varchar(255) NOT NULL DEFAULT '@',
  `mx_priority` int(11) DEFAULT NULL,
  `data` text,
  `resp_person` varchar(255) DEFAULT NULL,
  `serial` bigint(20) DEFAULT NULL,
  `refresh` int(11) DEFAULT NULL,
  `retry` int(11) DEFAULT NULL,
  `expire` int(11) DEFAULT NULL,
  `minimum` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `type` (`type`),
  KEY `host` (`host`),
  KEY `zone` (`zone`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;


Пример данных о зоне:

INSERT INTO `records` (`id`, `zone`, `ttl`, `type`, `host`, `mx_priority`, `data`, `resp_person`, `serial`, `refresh`, `retry`, `expire`, `minimum`) VALUES
(1, 'example.com', 86400, 'SOA', '@', NULL, 'ns1.example.com.', 'admin.example.com.', 2011013101, 10800, 7200, 604800, 86400),
(2, 'example.com', 86400, 'NS', '@', NULL, 'ns1.example.com.', NULL, NULL, NULL, NULL, NULL, NULL),
(3, 'example.com', 86400, 'NS', '@', NULL, 'ns2.example.com.', NULL, NULL, NULL, NULL, NULL, NULL),
(4, 'example.com', 86400, 'A', '@', NULL, '192.168.0.35', NULL, NULL, NULL, NULL, NULL, NULL),
(5, 'example.com', 86400, 'A', 'ns1', NULL, '192.168.0.36', NULL, NULL, NULL, NULL, NULL, NULL),
(6, 'example.com', 86400, 'A', 'ns2', NULL, '192.168.0.37', NULL, NULL, NULL, NULL, NULL, NULL);

В named.conf прописываем:

dlz "Mysql zone" {
   database "mysql
   {dbname=dns user=username pass=password socket=/var/run/mysqld/mysqld.sock}
   {select zone from records where zone = '$zone$'}
   {select ttl, type, mx_priority, case when lower(type)='txt' then concat('\"', data, '\"')
        else data end from records where zone = '$zone$' and host = '$record$'
        and not (type = 'SOA' or type = 'NS')}
   {select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
        from records where (type = 'SOA' or type='NS') and zone = '$zone$'}";
};


«Mysql zone» — просто название куска конфига, к имени самой зоны отношения не имеет.

$zone$ и $record$ прописываем именно так, это переменные на место которых DLZ сам будет подставлять имя зоны и записи при запросе.

В третье строчке можно прописывать следующие параметры:
dbname=
port=
host=
user=
pass=
socket=
compress=
ssl=
space=

Названия говорят вроде бы сами за себя. Ну, может быть, кроме «space=», но что это — я не знаю. В документации кроме того, что это булевый параметр, ничего про него не сказано.

Запросы опишу вкратце. В документации они описаны подробнее.
  • select zone from records where zone = '$zone$' — запрос, с помощью которого BIND понимает поддерживает ли он вообще эту зону.
  • select ttl, type, mx_priority, case when lower(type)='txt' then concat('\"', data, '\"')
    else data end from records where zone = '$zone$' and host = '$record$'
    and not (type = 'SOA' or type = 'NS')}
    — запрос получения записи о конкретном хосте в зоне.
  • select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
    from records where (type = 'SOA' or type='NS') and zone = '$zone$'
    как видно из запроса — тут мы получаем все авторитарные (authority) записи о зоне.


Самая неприятная и непонятная проблема, с которой я столкнулся, ориентируясь на имеющиеся в интернете документы, это постоянное появление в логах записей типа:
Jun 22 19:51:10.142 dns_rdata_fromtext: buffer-0xbfffe390:1: near eof:
unexpected end of input
Jun 22 19:51:10.143 dns_sdlz_putrr returned error. Error code was:
unexpected end of input
Jun 22 19:51:10.146 dns_rdata_fromtext: buffer-0xbfffe0d0:1: near eof:
unexpected end of input
Jun 22 19:51:10.147 dns_sdlz_putrr returned error. Error code was:
unexpected end of input
и неработающей зоной.

Обозначают эти строчки то, что DLZ получает данные не в том формате или порядке, как ожидает. A и NS записи должны иметь ttl, type и data, именно в таком порядке и только их (остальные поля — NULL). MX — все вышеперечисленное + mx_priority, SOA — ttl, type, data, responsible_person, refresh, retry, expire, minimum. (Информация в этом абзаце выкопана из почтового архива).

Есть еще два варианта запроса, связанных с переносом (xfer) зон, я их не использовал, так что отсылаю к официальной документации.

Очень помогает для отладки, как ни странно, отладочный режим BIND (-d 9). В gentoo прописываем OPTIONS="-d 9" в /etc/conf.d/named.

Я буду очень рад, если в комментариях, пользователи хабра поделятся своим опытом и конфигами для работы с BIND DLZ. Я пока только на начальном этапе настройки, мне предстоит очень многое. Например, обратные зоны.
Tags:
Hubs:
+21
Comments 49
Comments Comments 49

Articles