diff options
author | Timo Teräs <timo.teras@iki.fi> | 2013-07-12 08:50:26 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2013-07-12 09:28:01 +0300 |
commit | 3c24eab6e249a1b8f20770fa4f73557eb4eabde2 (patch) | |
tree | ad00a25ec2e75ba793bb45c3cae9e1ef1cfcceac /testing/gdnsd | |
parent | bbc06ec1abefc220a621547bc31befeb5d6046b5 (diff) | |
download | aports-3c24eab6e249a1b8f20770fa4f73557eb4eabde2.tar.bz2 aports-3c24eab6e249a1b8f20770fa4f73557eb4eabde2.tar.xz |
testing/gdnsd: experimental version 1.9.0
* update to upstream 1.9.0
* updated to use userspace-rcu
* cherry-pick cname reply fix
* refreshed djbdns support patch (from upstream dev branch)
* updated init.d script
Diffstat (limited to 'testing/gdnsd')
-rw-r--r-- | testing/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch | 265 | ||||
-rw-r--r-- | testing/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch | 42 | ||||
-rw-r--r-- | testing/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch | 823 | ||||
-rw-r--r-- | testing/gdnsd/APKBUILD | 68 | ||||
-rwxr-xr-x | testing/gdnsd/gdnsd.initd | 53 | ||||
-rw-r--r-- | testing/gdnsd/gdnsd.pre-install | 5 |
6 files changed, 1256 insertions, 0 deletions
diff --git a/testing/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch b/testing/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch new file mode 100644 index 0000000000..fb703b352d --- /dev/null +++ b/testing/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch @@ -0,0 +1,265 @@ +From 22b0dcf8a19aaeb1e6f32ad9f0aad95ab26b8a61 Mon Sep 17 00:00:00 2001 +From: Brandon Black <blblack@gmail.com> +Date: Thu, 11 Jul 2013 14:37:57 -0500 +Subject: [PATCH] Fix auth section of ANY-query on CNAME + +Queries with QTYPE=ANY for a name which has a CNAME RR + should be treated as if QTYPE=CNAME. Prior to this + fix, they were being treated more like QTYPE=A. Given + it's QTYPE=ANY and the effects seem to be limited to + the auth section, I doubt this is a production concern + for anyone, but it's good to be correct. + +Fixes Issue #51 (thanks Timo!) +--- + gdnsd/dnspacket.c | 11 ++- + t/012cname/001cname.t | 157 +++++++++++++++++++++++++++++++++++++++++++ + t/012cname/gdnsd.conf | 11 +++ + t/012cname/zones/example.com | 24 +++++++ + 4 files changed, 201 insertions(+), 2 deletions(-) + create mode 100644 t/012cname/001cname.t + create mode 100644 t/012cname/gdnsd.conf + create mode 100644 t/012cname/zones/example.com + +diff --git a/gdnsd/dnspacket.c b/gdnsd/dnspacket.c +index 3c26d83..db7e26a 100644 +--- a/gdnsd/dnspacket.c ++++ b/gdnsd/dnspacket.c +@@ -1190,6 +1190,9 @@ static unsigned int encode_rrs_any(dnspacket_context_t* c, unsigned int offset, + case DNS_TYPE_SOA: + offset = encode_rr_soa(c, offset, (const void*)rrset, true); + break; ++ case DNS_TYPE_CNAME: ++ offset = encode_rr_cname(c, offset, (const void*)rrset, true); ++ break; + case DNS_TYPE_NS: + offset = encode_rrs_ns(c, offset, (const void*)rrset, true); + break; +@@ -1659,8 +1662,12 @@ static unsigned int answer_from_db(dnspacket_context_t* c, const uint8_t* qname, + // for the normal response handling code below. The explicit check of the first + // rrsets entry works because if CNAME exists at all, by definition it is the only + // type of rrset at this node. +- while(resdom && resdom->rrsets +- && resdom->rrsets->gen.type == DNS_TYPE_CNAME && c->qtype != DNS_TYPE_CNAME) { ++ while(resdom ++ && resdom->rrsets ++ && resdom->rrsets->gen.type == DNS_TYPE_CNAME ++ && c->qtype != DNS_TYPE_CNAME ++ && c->qtype != DNS_TYPE_ANY) { ++ + dmn_assert(status == DNAME_AUTH); + + res_hdr->flags1 |= 4; // AA bit +diff --git a/t/012cname/001cname.t b/t/012cname/001cname.t +new file mode 100644 +index 0000000..6e96335 +--- /dev/null ++++ b/t/012cname/001cname.t +@@ -0,0 +1,157 @@ ++ ++# CNAME test, with include_optional_ns to get the auth section right... ++# this is basically going through A, CNAME, and ANY queries against ++# five different classes of CNAME targets (local nonexistent, ++# local existent, delegation, delegation glue record, and external). ++# CNAME and ANY responses should be identical (this was the bug that ++# triggered writing these testcases - ANY was being treated more like A). ++ ++use _GDT (); ++use FindBin (); ++use File::Spec (); ++use Test::More tests => 17; ++ ++my $standard_soa = 'example.com 21600 SOA ns1.example.com hmaster.example.net 1 7200 1800 259200 900'; ++ ++my $pid = _GDT->test_spawn_daemon(File::Spec->catfile($FindBin::Bin, 'gdnsd.conf')); ++ ++_GDT->test_dns( ++ qname => 'cn-nx.example.com', qtype => 'A', ++ header => { rcode => 'NXDOMAIN' }, ++ answer => 'cn-nx.example.com 21600 CNAME nx.example.com', ++ auth => $standard_soa, ++ stats => [qw/udp_reqs nxdomain/], ++); ++ ++foreach my $qt (qw/CNAME ANY/) { ++ _GDT->test_dns( ++ qname => 'cn-nx.example.com', qtype => $qt, ++ answer => 'cn-nx.example.com 21600 CNAME nx.example.com', ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns1.example.com 21600 A 192.0.2.1', ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++ ); ++} ++ ++_GDT->test_dns( ++ qname => 'cn-local.example.com', qtype => 'A', ++ answer => [ ++ 'cn-local.example.com 21600 CNAME ns1.example.com', ++ 'ns1.example.com 21600 A 192.0.2.1', ++ ], ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++); ++ ++foreach my $qt (qw/CNAME ANY/) { ++ _GDT->test_dns( ++ qname => 'cn-local.example.com', qtype => $qt, ++ answer => [ ++ 'cn-local.example.com 21600 CNAME ns1.example.com' ++ ], ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns1.example.com 21600 A 192.0.2.1', ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++ ); ++} ++ ++_GDT->test_dns( ++ qname => 'cn-deleg.example.com', qtype => 'A', ++ answer => [ ++ 'cn-deleg.example.com 21600 CNAME foo.subz.example.com', ++ ], ++ auth => [ ++ 'subz.example.com 21600 NS ns1.subz.example.com', ++ 'subz.example.com 21600 NS ns2.subz.example.com', ++ ], ++ addtl => [ ++ 'ns1.subz.example.com 21600 A 192.0.2.10', ++ 'ns2.subz.example.com 21600 A 192.0.2.20', ++ ], ++); ++ ++foreach my $qt (qw/CNAME ANY/) { ++ _GDT->test_dns( ++ qname => 'cn-deleg.example.com', qtype => $qt, ++ answer => [ ++ 'cn-deleg.example.com 21600 CNAME foo.subz.example.com', ++ ], ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns1.example.com 21600 A 192.0.2.1', ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++ ); ++} ++ ++_GDT->test_dns( ++ qname => 'cn-deleg-glue.example.com', qtype => 'A', ++ answer => [ ++ 'cn-deleg-glue.example.com 21600 CNAME ns1.subz.example.com', ++ ], ++ auth => [ ++ 'subz.example.com 21600 NS ns1.subz.example.com', ++ 'subz.example.com 21600 NS ns2.subz.example.com', ++ ], ++ addtl => [ ++ 'ns1.subz.example.com 21600 A 192.0.2.10', ++ 'ns2.subz.example.com 21600 A 192.0.2.20', ++ ], ++); ++ ++foreach my $qt (qw/CNAME ANY/) { ++ _GDT->test_dns( ++ qname => 'cn-deleg-glue.example.com', qtype => $qt, ++ answer => [ ++ 'cn-deleg-glue.example.com 21600 CNAME ns1.subz.example.com', ++ ], ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns1.example.com 21600 A 192.0.2.1', ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++ ); ++} ++ ++_GDT->test_dns( ++ qname => 'cn-ext.example.com', qtype => 'A', ++ answer => 'cn-ext.example.com 21600 CNAME www.example.net', ++); ++ ++foreach my $qt (qw/CNAME ANY/) { ++ _GDT->test_dns( ++ qname => 'cn-ext.example.com', qtype => $qt, ++ answer => 'cn-ext.example.com 21600 CNAME www.example.net', ++ auth => [ ++ 'example.com 21600 NS ns1.example.com', ++ 'example.com 21600 NS ns2.example.com', ++ ], ++ addtl => [ ++ 'ns1.example.com 21600 A 192.0.2.1', ++ 'ns2.example.com 21600 A 192.0.2.2', ++ ], ++ ); ++} ++ ++_GDT->test_kill_daemon($pid); +diff --git a/t/012cname/gdnsd.conf b/t/012cname/gdnsd.conf +new file mode 100644 +index 0000000..2bc6c92 +--- /dev/null ++++ b/t/012cname/gdnsd.conf +@@ -0,0 +1,11 @@ ++options => { ++ listen => @dns_lspec@ ++ http_listen => @http_lspec@ ++ dns_port => @dns_port@ ++ http_port => @http_port@ ++ zones_default_ttl = 21600 ++ realtime_stats = true ++ max_response = 62464 ++ chaos_response = "some random string" ++ include_optional_ns = true ++} +diff --git a/t/012cname/zones/example.com b/t/012cname/zones/example.com +new file mode 100644 +index 0000000..94a452f +--- /dev/null ++++ b/t/012cname/zones/example.com +@@ -0,0 +1,24 @@ ++ ++@ SOA ns1 hmaster.example.net. ( ++ 1 ; serial ++ 7200 ; refresh ++ 1800 ; retry ++ 259200 ; expire ++ 900 ; ncache ++) ++ ++@ NS ns1 ++@ NS ns2 ++ns1 A 192.0.2.1 ++ns2 A 192.0.2.2 ++ ++subz NS ns1.subz ++subz NS ns2.subz ++ns1.subz A 192.0.2.10 ++ns2.subz A 192.0.2.20 ++ ++cn-nx CNAME nx ++cn-local CNAME ns1 ++cn-deleg CNAME foo.subz ++cn-deleg-glue CNAME ns1.subz ++cn-ext CNAME www.example.net. +-- +1.8.3.2 + diff --git a/testing/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch b/testing/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch new file mode 100644 index 0000000000..f607d08c52 --- /dev/null +++ b/testing/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch @@ -0,0 +1,42 @@ +From e4d663a531205cdb281318bc912d76f2be22b328 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> +Date: Thu, 11 Jul 2013 18:47:22 +0300 +Subject: [PATCH 1/2] Fix ztree_txn_* API to work + +ztree_clone() sets ztclone->zones to valid pointer even where +it was NULL in the original ztree. This happens since malloc(0) +returns always valid pointer. This confuses _ztree_update() and +various other places as in several cases ->zones is tested +instead of ->zones_len. + +Fix ztree_clone() to keep ->zones as NULL if the original had +it as NULL. +--- + gdnsd/ztree.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/gdnsd/ztree.c b/gdnsd/ztree.c +index 57ff6d6..3924504 100644 +--- a/gdnsd/ztree.c ++++ b/gdnsd/ztree.c +@@ -526,9 +526,14 @@ static ztree_t* ztree_clone(const ztree_t* original) { + + ztree_t* ztclone = malloc(sizeof(ztree_t)); + ztclone->label = original->label; +- ztclone->zones = malloc(original->zones_len * sizeof(zone_t*)); +- memcpy(ztclone->zones, original->zones, original->zones_len * sizeof(zone_t*)); +- ztclone->zones_len = original->zones_len; ++ if (original->zones) { ++ ztclone->zones = malloc(original->zones_len * sizeof(zone_t*)); ++ memcpy(ztclone->zones, original->zones, original->zones_len * sizeof(zone_t*)); ++ ztclone->zones_len = original->zones_len; ++ } else { ++ ztclone->zones = NULL; ++ ztclone->zones_len = 0; ++ } + ztchildren_t* old_ztc = original->children; + if(old_ztc) { + ztchildren_t* new_ztc = ztclone->children = calloc(1, sizeof(ztchildren_t)); +-- +1.8.3.2 + diff --git a/testing/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch b/testing/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch new file mode 100644 index 0000000000..b7b14221ed --- /dev/null +++ b/testing/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch @@ -0,0 +1,823 @@ +From 53c6e973765c7cd096f982a304bc87fc1ca114ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> +Date: Thu, 11 Jul 2013 18:51:43 +0300 +Subject: [PATCH 2/2] Impelement loading of DJBDNS zone files + +--- + docs/TODO | 12 +- + gdnsd/Makefile.am | 2 +- + gdnsd/main.c | 1 + + gdnsd/zscan_djb.c | 577 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + gdnsd/zscan_djb.h | 38 ++++ + gdnsd/zsrc_djb.c | 91 ++++++--- + gdnsd/zsrc_djb.h | 2 + + 7 files changed, 694 insertions(+), 29 deletions(-) + create mode 100644 gdnsd/zscan_djb.c + create mode 100644 gdnsd/zscan_djb.h + +diff --git a/docs/TODO b/docs/TODO +index 1e67141..831231b 100644 +--- a/docs/TODO ++++ b/docs/TODO +@@ -161,12 +161,12 @@ Other zonefile formats: + ------------------------- + Load other zonefile (or zone data in general) formats? The BIND syntax + sucks, but I'm keeping it as the default, it's too widespread not to. +-However, the zonefile scanner is mostly cleanly separated from the rest +-of the code, and it wouldn't be that hard to add support for more +-formats (djbdns? a SQL connection?). Update: the core code is +-basically ready for this. I even created a mostly-empty zsrc_djb.c +-file since that's likely the first/easiest target. Just needs +-implementation. ++ ++Additionally, the djbdns style zone files are also supported. ++ ++As the zonefile scanner is mostly cleanly separated from the rest of ++the code, additional zonefile formats (e.g. SQL backend) should not ++be too hard to implement. + + Stuff from conversations w/ Paul Dekkers: -------- + +diff --git a/gdnsd/Makefile.am b/gdnsd/Makefile.am +index a57a3d4..a42309d 100644 +--- a/gdnsd/Makefile.am ++++ b/gdnsd/Makefile.am +@@ -4,7 +4,7 @@ AM_CPPFLAGS = -I$(srcdir)/libgdnsd -I$(builddir)/libgdnsd + + # How to build gdnsd + sbin_PROGRAMS = gdnsd +-gdnsd_SOURCES = main.c conf.c zsrc_djb.c zsrc_djb.h zsrc_rfc1035.c zsrc_rfc1035.h ztree.c ztree.h zscan_rfc1035.c ltarena.c ltree.c dnspacket.c dnsio_udp.c dnsio_tcp.c statio.c monio.c conf.h dnsio_tcp.h dnsio_udp.h dnspacket.h dnswire.h ltarena.h ltree.h statio.h monio.h zscan_rfc1035.h ++gdnsd_SOURCES = main.c conf.c zsrc_djb.c zsrc_djb.h zscan_djb.c zsrc_rfc1035.c zsrc_rfc1035.h ztree.c ztree.h zscan_rfc1035.c ltarena.c ltree.c dnspacket.c dnsio_udp.c dnsio_tcp.c statio.c monio.c conf.h dnsio_tcp.h dnsio_udp.h dnspacket.h dnswire.h ltarena.h ltree.h statio.h monio.h zscan_rfc1035.h + gdnsd_LDADD = libgdnsd/libgdnsd.la $(LIBGDNSD_LIBS) $(CAPLIBS) + + zscan_rfc1035.c: zscan_rfc1035.rl +diff --git a/gdnsd/main.c b/gdnsd/main.c +index b2b5d22..759ce1e 100644 +--- a/gdnsd/main.c ++++ b/gdnsd/main.c +@@ -89,6 +89,7 @@ static void hup_signal(struct ev_loop* loop V_UNUSED, struct ev_signal *w V_UNUS + + log_debug("Received SIGHUP"); + // these functions should log_info() that they're taking SIGHUP actions, as appropriate ++ zsrc_djb_sighup(); + zsrc_rfc1035_sighup(); + } + +diff --git a/gdnsd/zscan_djb.c b/gdnsd/zscan_djb.c +new file mode 100644 +index 0000000..34c41e8 +--- /dev/null ++++ b/gdnsd/zscan_djb.c +@@ -0,0 +1,577 @@ ++/* Copyright © 2012-2013 Timo Teräs <timo.teras@iki.fi> ++ * ++ * This file is part of gdnsd. ++ * ++ * gdnsd is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * gdnsd is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with gdnsd. If not, see <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#define _GNU_SOURCE ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <dirent.h> ++#include <setjmp.h> ++ ++#include "conf.h" ++#include "ztree.h" ++#include "zscan_djb.h" ++#include "gdnsd/log.h" ++#include "gdnsd/misc.h" ++ ++#define TTL_NS 259200 ++#define TTL_POSITIVE 86400 ++#define TTL_NEGATIVE 2560 ++ ++#define parse_abort() \ ++ siglongjmp(z->jbuf, 1) ++ ++#define parse_warn(_fmt, ...) \ ++ log_warn("djb: %s: parse error at line %u: " _fmt,z->fn,z->lcount,__VA_ARGS__);\ ++ ++#define parse_error_noargs(_fmt) \ ++ do {\ ++ log_err("djb: %s: parse error at line %u: " _fmt,z->fn,z->lcount);\ ++ parse_abort();\ ++ } while(0) ++ ++#define parse_error(_fmt, ...) \ ++ do {\ ++ log_err("djb: %s: parse error at line %u: " _fmt,z->fn,z->lcount,__VA_ARGS__);\ ++ parse_abort();\ ++ } while(0) ++ ++typedef struct { ++ char* ptr; ++ unsigned len; ++} field_t; ++ ++typedef struct { ++ uint8_t ns[256]; ++ uint8_t email[256]; ++ unsigned ttl; ++ unsigned serial; ++ unsigned refresh; ++ unsigned retry; ++ unsigned expire; ++ unsigned cache; ++ ++ unsigned mtime; ++} soa_info_t; ++ ++typedef struct { ++ /* variables preserved across files */ ++ uint64_t mtime; ++ zscan_djb_zonedata_t* zonedata; ++ const char* path; ++ uint8_t** texts; ++ char* line; ++ size_t allocated; ++ int num_texts; ++ int skipped; ++ ++ /* file specific data */ ++ int lcount; ++ char* full_fn; ++ const char* fn; ++ FILE* file; ++ ++ sigjmp_buf jbuf; ++} zscan_t; ++ ++static const uint8_t dname_root[] = {1,0}; ++static const uint8_t dname_ns[] = {4,2,'n','s',255}; ++static const uint8_t dname_mx[] = {4,2,'m','x',255}; ++static const uint8_t dname_srv[] = {5,3,'s','r','v',255}; ++ ++void zscan_djbzone_add(zscan_djb_zonedata_t** zd, zone_t *zone) { ++ zscan_djb_zonedata_t* nzd = malloc(sizeof(zscan_djb_zonedata_t)); ++ nzd->zone = zone; ++ nzd->marked = 0; ++ nzd->next = *zd; ++ *zd = nzd; ++} ++ ++zscan_djb_zonedata_t* zscan_djbzone_get(zscan_djb_zonedata_t* zd, const uint8_t* dname, int exact) { ++ zscan_djb_zonedata_t* best = NULL; ++ ++ for (; zd; zd = zd->next) { ++ if (exact) { ++ if (dname_cmp(zd->zone->dname, dname) == 0) ++ return zd; ++ } else { ++ if (!dname_isinzone(zd->zone->dname, dname)) ++ continue; ++ if (best == NULL || zd->zone->dname[0] > best->zone->dname[0]) { ++ best = zd; ++ if (best->zone->dname[0] == dname[0]) ++ return best; ++ } ++ } ++ } ++ return best; ++} ++ ++void zscan_djbzone_free(zscan_djb_zonedata_t** zd) { ++ zscan_djb_zonedata_t* cur = *zd; ++ zscan_djb_zonedata_t* next; ++ ++ while (cur) { ++ next = cur->next; ++ free(cur); ++ cur = next; ++ } ++ *zd = NULL; ++} ++ ++ ++F_NONNULL ++static uint8_t *parse_dname(zscan_t *z, uint8_t *dname, field_t *f) { ++ dname_status_t status = dname_from_string(dname, (const uint8_t*) f->ptr, f->len); ++ ++ switch(status) { ++ case DNAME_INVALID: ++ parse_error("'%.*s' is not a domain name", f->len, f->ptr); ++ break; ++ case DNAME_VALID: ++ break; ++ case DNAME_PARTIAL: ++ if(dname_cat(dname, dname_root) == DNAME_INVALID) ++ parse_error("'%.*s' is not a valid name", f->len, f->ptr); ++ break; ++ } ++ return dname; ++} ++ ++F_NONNULL ++static uint8_t *make_dname_relative(uint8_t* dname, const uint8_t* parent_dname) { ++ *dname -= *parent_dname - 1; ++ dname[*dname] = 0; ++ dmn_assert(dname_status(dname) == DNAME_VALID); ++ return dname; ++} ++ ++F_NONNULL ++static uint8_t *expand_dname(zscan_t *z, uint8_t *dname, field_t *f, const uint8_t *subzone, const uint8_t *zone) { ++ /* fully qualified name in the primary field? */ ++ if (strchr(f->ptr, '.') != NULL) ++ return parse_dname(z, dname, f); ++ ++ /* construct dname of form <fieldname>.<subzone>.<zone> ++ * e.g. ns1.ns.example.com */ ++ dname_from_string(dname, (const uint8_t*) f->ptr, f->len); ++ dname_cat(dname, subzone); ++ switch (dname_cat(dname, zone)) { ++ case DNAME_VALID: ++ break; ++ case DNAME_PARTIAL: ++ if(dname_cat(dname, dname_root) != DNAME_INVALID) ++ break; ++ /* fallthrough */ ++ case DNAME_INVALID: ++ parse_error("unable to expand '%.*s' as to valid domain name", f->len, f->ptr); ++ break; ++ } ++ ++ return dname; ++} ++ ++F_NONNULL ++static uint32_t parse_ipv4(zscan_t *z, field_t *f) { ++ struct in_addr addr; ++ ++ if(inet_pton(AF_INET, f->ptr, &addr) <= 0) ++ parse_error("IPv4 address '%s' invalid", f->ptr); ++ ++ return addr.s_addr; ++} ++ ++F_NONNULL ++static unsigned parse_ttl(zscan_t *z, field_t *f, unsigned defttl) { ++ char *end; ++ if (f->len == 0) ++ return defttl; ++ unsigned ttl = strtol(f->ptr, &end, 10); ++ if (end != f->ptr + f->len) ++ parse_error("Invalid TTL '%.*s'", f->len, f->ptr); ++ return ttl; ++} ++ ++F_NONNULL ++static unsigned parse_int(zscan_t *z, field_t *f) { ++ char *end; ++ unsigned ttl = strtol(f->ptr, &end, 10); ++ if (end != f->ptr + f->len) ++ parse_error("Invalid integer value '%.*s'", f->len, f->ptr); ++ return ttl; ++} ++ ++F_NONNULL ++static void parse_txt(field_t *f) { ++ char ch; ++ unsigned int i; ++ unsigned int j; ++ ++ j = 0; ++ i = 0; ++ while (i < f->len) { ++ ch = f->ptr[i++]; ++ if (ch == '\\') { ++ if (i >= f->len) break; ++ ch = f->ptr[i++]; ++ if ((ch >= '0') && (ch <= '7')) { ++ ch -= '0'; ++ if ((i < f->len) && (f->ptr[i] >= '0') && (f->ptr[i] <= '7')) { ++ ch <<= 3; ++ ch += f->ptr[i++] - '0'; ++ if ((i < f->len) && (f->ptr[i] >= '0') && (f->ptr[i] <= '7')) { ++ ch <<= 3; ++ ch += f->ptr[i++] - '0'; ++ } ++ } ++ } ++ } ++ f->ptr[j++] = ch; ++ } ++ f->len = j; ++ f->ptr[j] = 0; ++} ++ ++static void create_zones(zscan_t *z, char record_type, field_t *field) { ++ uint8_t dname[256]; ++ ++ if (record_type != 'Z') ++ return; ++ ++ parse_dname(z, dname, &field[0]); ++ if (zscan_djbzone_get(z->zonedata, dname, 1)) ++ return; ++ ++ char* src = gdnsd_str_combine("djb:", z->fn, NULL); ++ zscan_djbzone_add(&z->zonedata, zone_new(logf_dname(dname), src)); ++ dmn_fmtbuf_reset(); ++ free(src); ++} ++ ++#define TTDCHECK(fno) if (field[fno].len) { z->skipped++; return; } ++#define LOCCHECK(fno) if (field[fno].len) { z->skipped++; return; } ++ ++static void load_zones(zscan_t *z, char record_type, field_t *field) { ++ uint8_t dname[256], dname2[256], email[256]; ++ unsigned i, ttl; ++ ++ parse_dname(z, dname, &field[0]); ++ zscan_djb_zonedata_t* zd = zscan_djbzone_get(z->zonedata, dname, 0); ++ if (!zd) ++ return; ++ ++ //log_info("djb: processing '%s'", logf_dname(dname)); ++ ++ zone_t* zone = zd->zone; ++ make_dname_relative(dname, zone->dname); ++ ++ //log_info("djb: record %c name '%s' in zone '%s'", record_type, logf_dname(dname), logf_dname(zone->dname)); ++ ++ switch (record_type) { ++ case 'Z': /* SOA */ ++ TTDCHECK(9); ++ LOCCHECK(10); ++ zone->serial = parse_int(z, &field[3]); ++ zone->mtime = z->mtime; ++ if (ltree_add_rec_soa(zone, dname, ++ parse_dname(z, dname2, &field[1]), ++ parse_dname(z, email, &field[2]), ++ parse_ttl(z, &field[8], TTL_NEGATIVE), ++ zone->serial ?: z->mtime, /* serial */ ++ parse_int(z, &field[4]) ?: 16384, /* refresh */ ++ parse_int(z, &field[5]) ?: 2048, /* retry */ ++ parse_int(z, &field[6]) ?: 1048576, /* expire */ ++ parse_int(z, &field[7]) ?: 2560 /* cache */)) ++ parse_abort(); ++ break; ++ case '.': /* NS + SOA (+ A) */ ++ case '&': /* NS (+ A) */ ++ TTDCHECK(4); ++ LOCCHECK(5); ++ expand_dname(z, dname2, &field[2], dname_ns, dname); ++ ttl = parse_ttl(z, &field[3], TTL_NS); ++ if (ltree_add_rec_ns(zone, dname, dname2, ttl)) ++ parse_abort(); ++ if (field[1].len) { ++ zd = zscan_djbzone_get(z->zonedata, dname2, 0); ++ if (zd) { ++ make_dname_relative(dname2, zd->zone->dname); ++ log_info("djb: NS+A name '%s' in zone '%s'", logf_dname(dname2), logf_dname(zd->zone->dname)); ++ if (ltree_add_rec_a(zone, dname2, parse_ipv4(z, &field[1]), ttl, 0, NULL)) ++ parse_abort(); ++ } ++ } ++ break; ++ case '@': /* MX (+ A) */ ++ TTDCHECK(5); ++ LOCCHECK(6); ++ expand_dname(z, dname2, &field[2], dname_mx, dname); ++ ttl = parse_ttl(z, &field[4], TTL_POSITIVE); ++ if (ltree_add_rec_mx(zone, dname, dname2, ttl, parse_int(z, &field[3]))) ++ parse_abort(); ++ if (field[1].len) { ++ zd = zscan_djbzone_get(z->zonedata, dname2, 0); ++ if (zd) { ++ make_dname_relative(dname2, zd->zone->dname); ++ log_info("djb: MX+A name '%s' in zone '%s'", logf_dname(dname2), logf_dname(zd->zone->dname)); ++ if (ltree_add_rec_a(zone, dname2, parse_ipv4(z, &field[1]), ttl, 0, NULL)) ++ parse_abort(); ++ } ++ } ++ break; ++ case '+': /* A */ ++ case '=': /* A + PTR */ ++ TTDCHECK(3); ++ ttl = parse_ttl(z, &field[2], TTL_POSITIVE); ++ if (field[4].len == 2 && memcmp(field[4].ptr, "~~", 2) == 0) { ++ /* FIXME: check ooz is right */ ++ if (ltree_add_rec_dynaddr(zone, dname, (const uint8_t *) field[1].ptr, ttl, 0, 0, 0)) ++ parse_abort(); ++ } else { ++ LOCCHECK(4); ++ if (ltree_add_rec_a(zone, dname, parse_ipv4(z, &field[1]), ttl, 0, NULL)) ++ parse_abort(); ++#if 0 ++ /* FIXME: autogen PTR record */ ++ if (line[0] == '=') { ++ ltree_add_rec_ptr(); ++ } ++#endif ++ } ++ break; ++ case 'C': /* CNAME */ ++ TTDCHECK(3); ++ ttl = parse_ttl(z, &field[2], TTL_POSITIVE); ++ if (field[4].len == 2 && memcmp(field[4].ptr, "~~", 2) == 0) { ++ if (ltree_add_rec_dyncname(zone, dname, (const uint8_t *) field[1].ptr, dname_root, ttl)) ++ parse_abort(); ++ } else { ++ LOCCHECK(4); ++ if (ltree_add_rec_cname(zone, dname, parse_dname(z, dname2, &field[1]), ttl)) ++ parse_abort(); ++ } ++ break; ++ case '\'': /* TXT */ ++ TTDCHECK(3); ++ LOCCHECK(4); ++ ++ parse_txt(&field[1]); ++ ++ unsigned bytes = field[1].len; ++ const char* src = field[1].ptr; ++ unsigned chunks = (bytes + 254) / 255; ++ ++ if(bytes > 255 && gconfig.disable_text_autosplit) ++ parse_error_noargs("Text chunk too long (>255 unescaped)"); ++ if(bytes > 65500) ++ parse_error_noargs("Text chunk too long (>65500 unescaped)"); ++ ++ z->texts = realloc(z->texts, sizeof(uint8_t *) * (chunks + 1)); ++ for (i = 0; i < chunks; i++) { ++ int s = (bytes > 255 ? 255 : bytes); ++ z->texts[i] = malloc(s + 1); ++ z->texts[i][0] = s; ++ memcpy(&z->texts[i][1], src, s); ++ bytes -= s; ++ src += s; ++ } ++ z->texts[i] = NULL; ++ if (ltree_add_rec_txt(zone, dname, chunks, z->texts, parse_ttl(z,&field[2], TTL_POSITIVE))) { ++ for (i = 0; i < chunks; i++) ++ free(z->texts[i]); ++ parse_abort(); ++ } ++ break; ++ case 'S': /* SRV (+ A) */ ++ TTDCHECK(7); ++ LOCCHECK(8); ++ expand_dname(z, dname2, &field[2], dname_srv, dname); ++ ttl = parse_ttl(z, &field[6], TTL_POSITIVE); ++ if (ltree_add_rec_srv(zone, dname, dname2, ttl, parse_int(z, &field[4]), parse_int(z, &field[5]), parse_int(z, &field[3]))) ++ parse_abort(); ++ if (field[1].len) { ++ zd = zscan_djbzone_get(z->zonedata, dname2, 0); ++ if (zd) { ++ make_dname_relative(dname2, zd->zone->dname); ++ log_info("djb: SRV+A name '%s' in zone '%s'", logf_dname(dname2), logf_dname(zd->zone->dname)); ++ if (ltree_add_rec_a(zone, dname2, parse_ipv4(z, &field[1]), ttl, 0, NULL)) ++ parse_abort(); ++ } ++ } ++ break; ++ case 'N': /* NAPTR */ ++ TTDCHECK(8); ++ LOCCHECK(9); ++ parse_txt(&field[3]); ++ parse_txt(&field[4]); ++ parse_txt(&field[5]); ++ if (field[3].len > 255 || field[4].len > 255 || field[5].len > 255) ++ parse_error_noargs("NAPTR label cannot exceed 255 chars"); ++ ++ z->texts = realloc(z->texts, 4 * sizeof(uint8_t *)); ++ for (i = 0; i < 3; i++) { ++ z->texts[i] = malloc(field[3+i].len + 1); ++ z->texts[i][0] = field[3+i].len; ++ memcpy(&z->texts[i][1], field[3+i].ptr, field[3+i].len); ++ } ++ z->texts[i] = NULL; ++ if (ltree_add_rec_naptr(zone, dname, parse_dname(z, dname2, &field[6]), parse_ttl(z, &field[7], TTL_POSITIVE), parse_int(z, &field[1]), parse_int(z, &field[2]), 3, z->texts)) { ++ for (i = 0; i < 3; i++) ++ free(z->texts[i]); ++ parse_abort(); ++ } ++ break; ++#if 0 ++ case '3': /* AAAA */ ++ case '6': /* AAAA + PTR */ ++ case '^': /* PTR */ ++ case ':': /* raw */ ++#endif ++ default: ++ parse_warn("Unsupported djb record type '%c'", record_type); ++ } ++} ++ ++typedef void (*djb_recordcb_t)(zscan_t *z, char record_type, field_t *fields); ++ ++static void zscan_foreach_file_record(zscan_t *z, djb_recordcb_t cb) { ++ field_t field[15]; ++ ssize_t len; ++ size_t i; ++ char *c; ++ ++ z->lcount = 0; ++ log_debug("Scanning djbzone file '%s'", z->fn); ++ ++ z->file = fopen(z->full_fn, "rt"); ++ if(z->file == NULL) ++ parse_error("Cannot open zone file '%s' for reading: %s", z->full_fn, logf_errno()); ++ ++ while ((len = getline(&z->line, &z->allocated, z->file)) != -1) { ++ z->lcount++; ++ ++ /* Skip empty lines and comments */ ++ if (len == 0 || z->line[0] == '#' || z->line[0] == '-') ++ continue; ++ if (z->line[len-1] == '\n') { ++ z->line[len-1] = 0; ++ len--; ++ } ++ /* Skip empty lines and location records */ ++ if (len == 0 || z->line[0] == '%') ++ continue; ++ ++ for (i = 0, c = z->line + 1; i < sizeof(field)/sizeof(field[0]); i++) { ++ field[i].ptr = c ?: (char*) ""; ++ field[i].len = 0; ++ if (c) { ++ char *n = strchr(c, ':'); ++ if (n) { ++ field[i].len = n - c; ++ *n = 0; ++ c = n + 1; ++ } else { ++ field[i].len = strlen(c); ++ c = NULL; ++ } ++ } ++ } ++ ++ cb(z, z->line[0], field); ++ } ++} ++ ++static bool zscan_foreach_record(zscan_t *z, djb_recordcb_t cb) { ++ DIR *dir; ++ struct dirent *e; ++ bool failed = false; ++ ++ dir = opendir(z->path); ++ if (dir == NULL) { ++ log_err("djb: cannot open directory '%s': %s", z->path, logf_errno()); ++ return true; ++ } ++ ++ while ((e = readdir(dir)) != NULL) { ++ if (e->d_name[0] == '.') ++ continue; ++ ++ struct stat st; ++ z->full_fn = gdnsd_str_combine(z->path, e->d_name, &z->fn); ++ if (stat(z->full_fn, &st)) { ++ log_err("djb: cannot stat file '%s': %s", z->fn, logf_errno()); ++ parse_abort(); ++ } ++ if((st.st_mode & S_IFMT) != S_IFREG) { ++ free(z->full_fn); ++ z->fn = z->full_fn = NULL; ++ continue; ++ } ++ uint64_t emtime = get_extended_mtime(&st); ++ if (emtime > z->mtime) ++ z->mtime = emtime; ++ failed = true; ++ if(!sigsetjmp(z->jbuf, 0)) { ++ zscan_foreach_file_record(z, cb); ++ failed = false; ++ } ++ if (z->file) { ++ fclose(z->file); ++ z->file = NULL; ++ } ++ free(z->full_fn); ++ z->fn = z->full_fn = NULL; ++ ++ if (failed) ++ break; ++ } ++ closedir(dir); ++ ++ return failed; ++} ++ ++F_WUNUSED F_NONNULL ++bool zscan_djb(const char* djb_path, zscan_djb_zonedata_t** zonedata) ++{ ++ dmn_assert(djb_path); ++ ++ zscan_t _z, *z = &_z; ++ memset(z, 0, sizeof(*z)); ++ z->path = djb_path; ++ ++ if (zscan_foreach_record(z, create_zones) || zscan_foreach_record(z, load_zones)) ++ goto error; ++ ++ for (zscan_djb_zonedata_t *zd = z->zonedata; zd; zd = zd->next) ++ if (zone_finalize(zd->zone)) ++ goto error; ++ ++ if (z->skipped) ++ log_warn("djb: skipped %d records with TTD or location", z->skipped); ++ ++ *zonedata = z->zonedata; ++ return false; ++ ++error: ++ zscan_djbzone_free(&z->zonedata); ++ return true; ++} +diff --git a/gdnsd/zscan_djb.h b/gdnsd/zscan_djb.h +new file mode 100644 +index 0000000..5c47deb +--- /dev/null ++++ b/gdnsd/zscan_djb.h +@@ -0,0 +1,38 @@ ++/* Copyright © 2013 Timo Teräs <timo.teras@iki.fi> ++ * ++ * This file is part of gdnsd. ++ * ++ * gdnsd is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * gdnsd is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with gdnsd. If not, see <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#ifndef GDNSD_ZSCAN_DJB_H ++#define GDNSD_ZSCAN_DJB_H ++ ++#include "config.h" ++ ++typedef struct _zscan_djb_zonedata { ++ zone_t* zone; ++ int marked; ++ struct _zscan_djb_zonedata* next; ++} zscan_djb_zonedata_t; ++ ++void zscan_djbzone_add(zscan_djb_zonedata_t**, zone_t *zone); ++zscan_djb_zonedata_t* zscan_djbzone_get(zscan_djb_zonedata_t*, const uint8_t*, int); ++void zscan_djbzone_free(zscan_djb_zonedata_t**); ++ ++F_WUNUSED F_NONNULL ++bool zscan_djb(const char* djb_path, zscan_djb_zonedata_t** zonedata); ++ ++#endif // GDNSD_ZSCAN_DJB_H +diff --git a/gdnsd/zsrc_djb.c b/gdnsd/zsrc_djb.c +index 688d467..9d77a0a 100644 +--- a/gdnsd/zsrc_djb.c ++++ b/gdnsd/zsrc_djb.c +@@ -18,6 +18,7 @@ + */ + + #include "zsrc_djb.h" ++#include "zscan_djb.h" + + #include <string.h> + #include <stdlib.h> +@@ -27,36 +28,82 @@ + + #include "conf.h" + #include "ltree.h" +-#include "ltarena.h" +-#include "ztree.h" +-#include "gdnsd/misc.h" + #include "gdnsd/log.h" ++#include "gdnsd/paths.h" ++ ++static struct ev_loop* zones_loop = NULL; ++static ev_async* sighup_waker = NULL; ++static char* djb_dir = NULL; ++static zscan_djb_zonedata_t* active_zonedata = NULL; + + static void unload_zones(void) { +- // for every zone_t created and sent to ztree earlier +- // during zsrc_djb_load_zones: +- // zlist_update(z, NULL); // removes from runtime lookup +- // zone_delete(z); // destroys actual data inside +- // free other associated local data, if any ++ ztree_txn_start(); ++ for (zscan_djb_zonedata_t* cur = active_zonedata; cur; cur = cur->next) ++ ztree_txn_update(cur->zone, NULL); ++ ztree_txn_end(); ++ ++ zscan_djbzone_free(&active_zonedata); ++} ++ ++static void zsrc_djb_sync_zones(void) { ++ zscan_djb_zonedata_t* zonedata; ++ int num_zones = 0; ++ ++ if (zscan_djb(djb_dir, &zonedata)) ++ return; ++ ++ ztree_txn_start(); ++ for (zscan_djb_zonedata_t* cur = zonedata; cur; cur = cur->next) { ++ zscan_djb_zonedata_t* old = zscan_djbzone_get(active_zonedata, cur->zone->dname, 1); ++ if (old) { ++ old->marked = 1; ++ ztree_txn_update(old->zone, cur->zone); ++ //ztree_update(old->zone, cur->zone); ++ } else { ++ ztree_txn_update(NULL, cur->zone); ++ //ztree_update(NULL, cur->zone); ++ } ++ num_zones++; ++ } ++ for (zscan_djb_zonedata_t* cur = active_zonedata; cur; cur = cur->next) { ++ if (!cur->marked) ++ ztree_txn_update(cur->zone, NULL); ++ //ztree_update(cur->zone, NULL); ++ } ++ ztree_txn_end(); ++ ++ log_info("zsrc_djb: loaded %d zones...", num_zones); ++ ++ zscan_djbzone_free(&active_zonedata); ++ active_zonedata = zonedata; + } + + void zsrc_djb_load_zones(void) { +- // scan input file(s): +- // create zone_t object for each local zone using +- // ztree.h:zone_new("example.com", "djb:datafile") +- // set zone_t->mtime from filesystem mtime. +- // add records to the zone_t via ltree_add_rec_*. +- // call zone_finalize(z) to do post-processing +- // call zlist_update(NULL, z); for each zone created, +- // which makes it available for runtime lookup +- // keep track of the zone_t's you created, you're +- // responsible for destroying them later. ++ djb_dir = gdnsd_resolve_path_cfg("djbdns/", NULL); ++ zsrc_djb_sync_zones(); + if(atexit(unload_zones)) + log_fatal("zsrc_djb: atexit(unload_zones) failed: %s", logf_errno()); + } + +-void zsrc_djb_runtime_init(struct ev_loop* loop V_UNUSED) { +- // for runtime reloading based on FS updates, +- // can just no-op for now and load on startup only, above. +- return; ++// called within our thread/loop to take sighup action ++F_NONNULL ++static void sighup_cb(struct ev_loop* loop, ev_async* w V_UNUSED, int revents V_UNUSED) { ++ dmn_assert(loop); dmn_assert(w); ++ log_info("zsrc_djb: received SIGHUP notification, scanning for changes..."); ++ zsrc_djb_sync_zones(); ++} ++ ++// called from main thread to feed ev_async ++void zsrc_djb_sighup(void) { ++ dmn_assert(zones_loop); dmn_assert(sighup_waker); ++ ev_async_send(zones_loop, sighup_waker); ++} ++ ++void zsrc_djb_runtime_init(struct ev_loop* loop) { ++ dmn_assert(loop); ++ ++ zones_loop = loop; ++ sighup_waker = malloc(sizeof(ev_async)); ++ ev_async_init(sighup_waker, sighup_cb); ++ ev_async_start(loop, sighup_waker); + } +diff --git a/gdnsd/zsrc_djb.h b/gdnsd/zsrc_djb.h +index dc60ae1..dc4c96d 100644 +--- a/gdnsd/zsrc_djb.h ++++ b/gdnsd/zsrc_djb.h +@@ -28,4 +28,6 @@ void zsrc_djb_load_zones(void); + F_NONNULL + void zsrc_djb_runtime_init(struct ev_loop* loop); + ++void zsrc_djb_sighup(void); ++ + #endif // GDNSD_ZSRC_DJB_H +-- +1.8.3.2 + diff --git a/testing/gdnsd/APKBUILD b/testing/gdnsd/APKBUILD new file mode 100644 index 0000000000..f63bb99bbe --- /dev/null +++ b/testing/gdnsd/APKBUILD @@ -0,0 +1,68 @@ +# Contributor: Natanael Copa <ncopa@alpinelinux.org> +# Maintainer: Timo Teräs <timo.teras@iki.fi> +pkgname=gdnsd +pkgver=1.9.0 +pkgrel=0 +pkgdesc="Geographic Authoritative DNS server" +url="https://github.com/blblack/gdnsd/" +arch="all" +license="GPL-3" +depends="" +depends_dev="" +makedepends="userspace-rcu-dev libev-dev libcap-dev autoconf automake libtool" +install="$pkgname.pre-install" +subpackages="$pkgname-dev $pkgname-doc" +source="https://github.com/blblack/gdnsd/archive/v$pkgver.tar.gz + 0001-Fix-auth-section-of-ANY-query-on-CNAME.patch + 0001-Fix-ztree_txn_-API-to-work.patch + 0002-Impelement-loading-of-DJBDNS-zone-files.patch + gdnsd.initd" + +_builddir="$srcdir"/gdnsd-$pkgver +prepare() { + local i + cd "$_builddir" + for i in $source; do + case $i in + *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;; + esac + done + ./autogen.sh || return 1 +} + +build() { + cd "$_builddir" + ./configure --prefix=/usr \ + --sysconfdir=/etc \ + --localstatedir=/var \ + --enable-fast-install \ + || return 1 + make || return 1 + install -Dm755 "$srcdir"/gdnsd.initd \ + "$pkgdir"/etc/init.d/gdnsd || return 1 +} + +package() { + cd "$_builddir" + make DESTDIR="$pkgdir" install || return 1 + rm -f "$pkgdir"/usr/lib/*.la \ + "$pkgdir"/usr/lib/gdnsd/*.la + install -Dm755 "$srcdir"/gdnsd.initd \ + "$pkgdir"/etc/init.d/gdnsd || return 1 +} + +md5sums="17b5450d6b78f73bb3f47f7b2d1e5f0f v1.9.0.tar.gz +c6229e37f4d3f9c2bec7f8e56ef93b0c 0001-Fix-auth-section-of-ANY-query-on-CNAME.patch +64b0232acbd664db83ff2ac800cb5459 0001-Fix-ztree_txn_-API-to-work.patch +bc54485f31d09b0c83eb78dee4cd7446 0002-Impelement-loading-of-DJBDNS-zone-files.patch +85f07d47b324a8913cb87a45067d4f44 gdnsd.initd" +sha256sums="955970ddd07c9926450a07877f106124a57dd56913f40e8fe2262287a2377db0 v1.9.0.tar.gz +459b8fab55c701ffa196e6838056322c60129ab3646eefac4dd4900df8300e2a 0001-Fix-auth-section-of-ANY-query-on-CNAME.patch +f42d30f3aa88d5fedcf1642de33132beafade609c041ed9f5943ba3da9d7c2fb 0001-Fix-ztree_txn_-API-to-work.patch +f78f0071812ef675e7b57cfa8d0edfcd00be84f6e320afedcf9352bc3a08a197 0002-Impelement-loading-of-DJBDNS-zone-files.patch +dd1ee7fa4063455f127c444b467625fd12cc51349858757614607cf367804a74 gdnsd.initd" +sha512sums="666cb34241fa3dd345d6dbde6d9166c691e8418eaf913dd2b1a7d1c3aa6b1a6f8d7d74b6f6e7804a989951b45d10e69f34bce647737b8460c5b0fc18e25150aa v1.9.0.tar.gz +703ef89071a21db03f14efa1fc0d269fbd1d50cc6861cd9912cad1076d0cfe91e7cfc4760a6355cca91df1d58387431c3f53ffa8b19342bde54bc850ff80b278 0001-Fix-auth-section-of-ANY-query-on-CNAME.patch +c8a1a23a623dcacf3cd799929a974edbe29e0ab36ef85ada4047dd04726c96ff040eff733509f523b9982aa8956408b9a654f8c6c6c26e454773b3b81d4f49cb 0001-Fix-ztree_txn_-API-to-work.patch +c32e7bfd09006344cc53b32fe8597c5d9744d2d66723e0eea6ba4a5ec4db39c5700c844d880bacd41862126a21cdaaca276b8510a512e7f1b5ccdcfdb5ab1f1b 0002-Impelement-loading-of-DJBDNS-zone-files.patch +0e8263182bbfa52aa8176443373d5de8b05dfb3f6d4f3268e0deecaca24832125bb3fa59309a4880bd7ae76ffb612ecb61f6cf00732f0237a4de21fadae219b5 gdnsd.initd" diff --git a/testing/gdnsd/gdnsd.initd b/testing/gdnsd/gdnsd.initd new file mode 100755 index 0000000000..9820052bee --- /dev/null +++ b/testing/gdnsd/gdnsd.initd @@ -0,0 +1,53 @@ +#!/sbin/runscript + +name="gdnsd daemon" +extra_commands="configtest" +extra_started_commands="reload fastrestart" +description="Geographic Authoritative DNS server" +description_configtest="Run syntax tests for configuration files only." +description_reload="Signal running gdnsd to reload configuration files" +description_fastrestart="Optimized restart sequence (minimizes down time)" + +if [ -z "${GDNSD_CONFFILE}" ]; then + if [ "${SVCNAME}" = "gdnsd" ]; then + GDNSD_ROOT=system + else + GDNSD_ROOT=/var/gdnsd/${SVCNAME} + fi +fi + +depend() { + need net + use logger + after firewall + provide auth-dns +} + +act() { + ebegin "$1 ${SVCNAME}" + /usr/sbin/gdnsd -d ${GDNSD_ROOT} $2 + eend $? +} + +configtest() { + act "Checking configuration" checkconf +} + +start() { + act "Starting" start +} + +stop () { + if [ "${RC_CMD}" = "restart" ]; then + configtest || return 1 + fi + act "Stopping" stop +} + +fastrestart() { + act "Restarting" restart +} + +reload() { + act "Reloading" reload +} diff --git a/testing/gdnsd/gdnsd.pre-install b/testing/gdnsd/gdnsd.pre-install new file mode 100644 index 0000000000..66de81a2e1 --- /dev/null +++ b/testing/gdnsd/gdnsd.pre-install @@ -0,0 +1,5 @@ +#!/bin/sh + +addgroup gdnsd 2>/dev/null +adduser -S -H -h /dev/null -s /bin/false -D -G gdnsd gdnsd 2>/dev/null +exit 0 |