PowerDNS MongoDB
PowerDNS + MongoDB
Требуется - настроить ДНС сервер который будет брать данные из Монго. Почему Монго - так хочет заказчик. Заполнять базу будет отдельное приложение, днс будет частью системы.
Сборка плагина
Ни одна из бинарных сборок которые я попробовал не включала плагина для работы с монго. В gentoo не было ключа для включение плагина при компиляции.
Путь один - собирать сервер руками. (чуть позже - собрать пакет для своей системы, rpm )
Для сборки требуются исходники mongo. Я не нашел как передать путь к хедерам монго - насколько я могу судить путь захардкожен. Потому (знаю что не правильно) просто скопировал все хедеры в папку с плагином (/usr/src/pdns-3.0.1/modules/mongodbbackend/)
Далее традиционно
./configure make
Обратить внимание на описание проблем со сборкой ниже - мне пришлось "патчить" модуль до рабочего состояния. Возможно вам не прийдется, или это особенность моего дистрибутива или сборки.
make install не делаю а беру модуль и подкладываю его там где ищет pdns_server
Ошибка в плагине
Мне пришлось закоментировать использование хинтов - с ними я получал ошибку:
Jun 08 14:15:19 [MONGODBBackend: (1)] (getSOA) Query: { name: "smtp-servers.example.com" }
Jun 08 14:15:19 [MONGODBBackend: (1)] (getSOA) Query: { name: "example.com" }
Jun 08 14:15:19 We have authority, zone='example.com', id=10
Jun 08 14:15:19 UeberBackend received question for ANY of smtp-servers.example.com
Jun 08 14:15:19 [MONGODBBackend: (1)] (lookup) Query: { query: { name: "smtp-servers.example.com" }, $hint: { name: 1 } }
Jun 08 14:15:19 Ueber get() was called for a ANY record
Jun 08 14:15:19 [MONGODBBackend: (1)] (get) Error: The record '{ $err: "bad hint", code: 10113 }' is missing required element(s) for the query '{ query: { name: "smtp-servers.example.com" }, $hint: { name: 1 } }'
Jun 08 14:15:19 UeberBackend reached end of backends
Jun 08 14:15:19 After first ANY query for 'smtp-servers.example.com', id=10: weDone=0, weHaveUnauth=0, weRedirected=0
Jun 08 14:15:19 Found nothing in the ANY, but let's try wildcards..
Jun 08 14:15:19 UeberBackend received question for ANY of *.example.com
Jun 08 14:15:19 [MONGODBBackend: (1)] (lookup) Query: { query: { name: "*.example.com" }, $hint: { name: 1 } }
Jun 08 14:15:19 Ueber get() was called for a ANY record
Jun 08 14:15:19 [MONGODBBackend: (1)] (get) Error: The record '{ $err: "bad hint", code: 10113 }' is missing required element(s) for the query '{ query: { name: "*.example.com" }, $hint: { name: 1 } }'
Jun 08 14:15:19 UeberBackend reached end of backends
Jun 08 14:15:19 Found nothing in the ANY and wildcards, let's try NS referral
Jun 08 14:15:19 UeberBackend received question for NS of smtp-servers.example.com
Jun 08 14:15:19 [MONGODBBackend: (1)] (lookup) Query: { query: { name: "smtp-servers.example.com", type: "NS" }, $hint: { name: 1, type: 1 } }
Jun 08 14:15:19 Ueber get() was called for a NS record
Jun 08 14:15:19 [MONGODBBackend: (1)] (get) Error: The record '{ $err: "bad hint", code: 10113 }' is missing required element(s) for the query '{ query: { name: "smtp-servers.example.com", type: "NS" }, $hint: { name: 1, type: 1 } }'
Насколько я могу понять - нужно писать hint { ... } а не $hint. Предположительно это баг.
В файле minimal.cc удалил строку:
mongo_query.hint(q_type == "ANY" ? BSON("name" << 1) : BSON("name" << 1 << "type" << 1));
MongoDB - минимальные записи записи
Для того что бы ДНС заработал нужно внести некоторое минимально число записей и описание зоны. в Монго при попытке вставить данные в несуществующий объект он будет создан что несколько упрощает жизнь.
Имена используемых коллекций я не менял: (определяется в конфиге PowerDNS вероятно).
collection-domains = domains collection-records = records collection-domainmetadata = domainmetadata collection-cryptokeys = cryptokeys collection-tsigkeys = tsigkeys
Работа с монго из консоли - заполнить зону
mongo - утилита для работы из консоли.
Тут короткое описание как вставлять записи. Пример со вставкой полдразумевает что зона уже создана и сервер стартован.
Использовать правильную базу:
use dns
Проверяю что записи нет:
sirmax@sirmax ~ $ host start4.example.com 192.168.15.1 Using domain server: Name: 192.168.15.1 Address: 192.168.15.1#53 Aliases:
Определяю переменную, а потом вствляю ее:
#mongo
> test = {"domain_id" : 10, "name" : "start4.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.2.2"} ] }
{
"domain_id" : 10,
"name" : "start4.example.com",
"type" : "A",
"ttl" : 120,
"content" : [
{
"data" : "192.168.2.2"
}
]
}
>db.records.insert(test)
>db.records.find();
<skipped>
{ "_id" : ObjectId("4fd1fb484a6ee59df5031fea"), "domain_id" : 10, "name" : "start4.example.com", "type" : "A", "ttl" : 120, "content" : [ { "data" : "192.168.2.2" } ] }
sirmax@sirmax ~ $ host start4.example.com 192.168.15.1 Using domain server: Name: 192.168.15.1 Address: 192.168.15.1#53 Aliases: start4.example.com has address 192.168.2.2
Я сделал следующие записи:
domains
{"domain_id" : 10, "name" : "example.com", "type" : "NATIVE", "ttl" : 120, "SOA" : {"hostmaster" : "ahu.example.com", "nameserver" : "ns1.example.com", "serial" : 2000081501, "refresh" : 28800, "retry" : 7200, "expire" : 604800, "default_ttl" : 86400 } }
{"domain_id" : 10, "name" : "example.com", "type" : "NS", "ttl" : 120, "content" : [ {"data" : "ns1.example.com"}, {"data" : "ns2.example.com"} ] }
{"domain_id" : 10, "name" : "example.com", "type" : "MX", "ttl" : 120, "content" : [ {"prio" : 10, "data" : "smtp-servers.example.com"}, {"prio" : 15, "data" : "smtp-servers.test.com"} ] }
{"domain_id" : 10, "name" : "ns1.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.1.1"} ] }
{"domain_id" : 10, "name" : "ns2.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.1.2"} ] }
{"domain_id" : 10, "name" : "smtp-servers.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.0.2"}, {"data" : "192.168.0.3"}, {"data" : "192.168.0.4"} ] }
records
{"domain_id" : 10, "name" : "example.com", "type" : "NS", "ttl" : 120, "content" : [ {"data" : "ns1.example.com"}, {"data" : "ns2.example.com"} ] }
{"domain_id" : 10, "name" : "example.com", "type" : "MX", "ttl" : 120, "content" : [ {"prio" : 10, "data" : "smtp-servers.example.com"}, {"prio" : 15, "data" : "smtp-servers.test.com"} ] }
{"domain_id" : 10, "name" : "ns1.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.1.1"} ] }
{"domain_id" : 10, "name" : "ns2.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.1.2"} ] }
{"domain_id" : 10, "name" : "smtp-servers.example.com", "type" : "A", "ttl" : 120, "content" : [ {"data" : "192.168.0.2"}, {"data" : "192.168.0.3"}, {"data" : "192.168.0.4"} ] }
db.records.find();
{ "_id" : ObjectId("4fd1dae01ac5e9baad14dc49"), "domain_id" : 10, "name" : "smtp-servers.example.com", "type" : "A", "ttl" : 120, "content" : [ { "data" : "192.168.0.2" }, { "data" : "192.168.0.3", "ttl" : 60 }, { "data" : "192.168.0.4" } ] }
{ "_id" : ObjectId("4fd1dccd1ac5e9baad14dc4a"), "domain_id" : 10, "name" : "ns1.example.com", "type" : "A", "ttl" : 120, "content" : [ { "data" : "192.168.1.1" } ] }
{ "_id" : ObjectId("4fd1dce71ac5e9baad14dc4b"), "domain_id" : 10, "name" : "example.com", "type" : "NS", "ttl" : 120, "content" : [ { "data" : "ns1.example.com" }, { "data" : "ns2.example.com" } ] }
{ "_id" : ObjectId("4fd1dd7a1ac5e9baad14dc4c"), "domain_id" : 10, "name" : "ns2.example.com", "type" : "A", "ttl" : 120, "content" : [ { "data" : "192.168.1.2" } ] }
{ "_id" : ObjectId("4fd1de521ac5e9baad14dc4d"), "domain_id" : 10, "name" : "example.com", "type" : "NS", "ttl" : 120, "content" : [ { "data" : "ns1.example.com" }, { "data" : "ns2.example.com" } ] }
Думаю, вцелом все более-менее ясно. Примеры записей есть тут: http://wiki.powerdns.com/trac/browser/trunk/pdns/modules/mongodbbackend/test Так же есть примеры с работой с json и заливкой данных.
rpm для CentOS
Со сборкой RPM пришлось повозиться. отмечу что для сборки нужен g++ Кроме того - несколько патчей.
pdns.spec
привожу полный spec, сами исходники - брал с оффсайта.
Summary: A modern, advanced and high performance authoritative-only nameserver
Name: pdns
Version: 3.1
Release: 10%{?dist}
Group: System Environment/Daemons
License: GPLv2
URL: http://powerdns.com
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Source0: http://downloads.powerdns.com/releases/%{name}-%{version}.tar.gz
#Patch0: %{name}-fixinit.patch
#Patch1: %{name}-gcc44.patch
#Patch2: pdns-fix-postgres-detection.patch
#Patch3: pdns-fix-crash-on-sigstop.patch
Patch0: pdns-fix-mongo-backend.patch
Patch1: pdns-fix-md5sum-bug.patch
Patch2: pdns-fix-hint.patch
#Patch1: pdns-fix-lua-detection.patch
Requires(post): %{_sbindir}/useradd, /sbin/chkconfig
Requires(preun): /sbin/service, /sbin/chkconfig
BuildRequires: boost-devel, chrpath
Provides: powerdns = %{version}-%{release}
%description
The PowerDNS Nameserver is a modern, advanced and high performance
authoritative-only nameserver. It is written from scratch and conforms
to all relevant DNS standards documents.
Furthermore, PowerDNS interfaces with almost any database.
%package backend-mysql
Summary: MySQL backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
BuildRequires: mysql-devel
%package backend-postgresql
Summary: PostgreSQL backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
BuildRequires: postgresql-devel
%package backend-pipe
Summary: Pipe backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
%package backend-geo
Summary: Geo backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
%package backend-ldap
Summary: LDAP backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
BuildRequires: openldap-devel
%package backend-sqlite
Summary: SQLite backend for %{name}
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
BuildRequires: sqlite-devel
%package backend-mongodb
Summary: MongoDB backend for %{name}
Group: System Environment/Daemons
Requires: %{name}%{?_isa} = %{version}-%{release}
BuildRequires: mongodb-devel
%description backend-mysql
This package contains the gmysql backend for %{name}
%description backend-postgresql
This package contains the gpgsql backend for %{name}
%description backend-pipe
This package contains the pipe backend for %{name}
%description backend-geo
This package contains the geo backend for %{name}
It allows different answers to DNS queries coming from different
IP address ranges or based on the geographic location
%description backend-ldap
This package contains the ldap backend for %{name}
%description backend-sqlite
This package contains the SQLite backend for %{name}
%description backend-mongodb
This package contains the MongoDB backend for %{name}
%prep
%setup -q
%patch0 -p1 -b .fixmongo
%patch1 -p1 -b .fixmd5
%patch2 -p1 -b .fixhint
#%patch1 -p1 -b .fixlua
#%patch0 -p1 -b .fixinit
#%patch1 -p1 -b .gcc44
#%patch2 -p1 -b .postgres
#%patch3 -p1 -b .sigstop
%build
export CPPFLAGS="-DLDAP_DEPRECATED %{optflags}"
%configure \
--sysconfdir=%{_sysconfdir}/%{name} \
--libdir=%{_libdir}/%{name} \
--disable-static \
--with-modules='' \
--with-dynmodules='pipe gmysql gpgsql geo ldap gsqlite3 mongodb' \
--with-mysql-lib=%{_libdir}/mysql \
--with-sqlite3-lib=%{_libdir}
#sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
#sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
make %{?_smp_mflags}
%install
%{__rm} -rf %{buildroot}
make install DESTDIR=%{buildroot}
%{__rm} -f %{buildroot}%{_libdir}/%{name}/*.la
%{__install} -p -D -m 0755 pdns/pdns %{buildroot}%{_initrddir}/pdns
%{__mv} %{buildroot}%{_sysconfdir}/%{name}/pdns.conf{-dist,}
# add the pdns user to the config file
sed -i '1i\setuid=pdns' %{buildroot}%{_sysconfdir}/%{name}/pdns.conf
sed -i '2i\setgid=pdns' %{buildroot}%{_sysconfdir}/%{name}/pdns.conf
# strip the static rpath from the binaries
chrpath --delete %{buildroot}%{_bindir}/pdns_control
chrpath --delete %{buildroot}%{_bindir}/zone2ldap
chrpath --delete %{buildroot}%{_bindir}/zone2sql
chrpath --delete %{buildroot}%{_sbindir}/pdns_server
chrpath --delete %{buildroot}%{_libdir}/%{name}/*.so
%post
if [ $1 -eq 1 ]; then
/sbin/chkconfig --add pdns
userid=`id -u pdns 2>/dev/null`
if [ x"$userid" = x ]; then
%{_sbindir}/useradd -c "PowerDNS user" -s /sbin/nologin -r -d / pdns > /dev/null || :
fi
fi
%preun
if [ $1 -eq 0 ]; then
/sbin/service pdns stop >/dev/null 2>&1 || :
/sbin/chkconfig --del pdns
fi
%clean
%{__rm} -rf %{buildroot}
%files
%defattr(-,root,root,-)
#%doc ChangeLog TODO pdns/COPYING
%{_bindir}/pdns_control
%{_bindir}/zone2ldap
%{_bindir}/zone2sql
%{_bindir}/dnsreplay
%{_bindir}/pdnssec
%{_sbindir}/pdns_server
%{_mandir}/man8/pdns_control.8.gz
%{_mandir}/man8/pdns_server.8.gz
%{_mandir}/man8/zone2sql.8.gz
%{_initrddir}/pdns
%dir %{_libdir}/%{name}/
%dir %{_sysconfdir}/%{name}/
%config(noreplace) %{_sysconfdir}/%{name}/pdns.conf
%files backend-mysql
%defattr(-,root,root,-)
#%doc pdns/COPYING
%{_libdir}/%{name}/libgmysqlbackend.so
%files backend-postgresql
%defattr(-,root,root,-)
#%doc pdns/COPYING
%{_libdir}/%{name}/libgpgsqlbackend.so
%files backend-pipe
%defattr(-,root,root,-)
#%doc pdns/COPYING
%{_libdir}/%{name}/libpipebackend.so
%files backend-geo
%defattr(-,root,root,-)
#%doc pdns/COPYING modules/geobackend/README
%{_libdir}/%{name}/libgeobackend.so
%files backend-ldap
%defattr(-,root,root,-)
#%doc pdns/COPYING
%{_libdir}/%{name}/libldapbackend.so
%files backend-sqlite
%defattr(-,root,root,-)
#%doc pdns/COPYING
%{_libdir}/%{name}/libgsqlite3backend.so
%files backend-mongodb
%defattr(-,root,root,-)
%{_libdir}/%{name}/libmongodbbackend.so
%changelog
Patch0
Patch0: pdns-fix-mongo-backend.patch Patch1: pdns-fix-md5sum-bug.patch Patch2: pdns-fix-hint.patch