summaryrefslogtreecommitdiffstats
path: root/main/gdnsd
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2013-08-02 13:25:45 +0300
committerTimo Teräs <timo.teras@iki.fi>2013-08-02 13:27:42 +0300
commit766ffa0f26fa85486ce272c8260924bfffcabf65 (patch)
tree016b24ba0eec185a29c83d4f30d0a0cf3cfd7652 /main/gdnsd
parentef2efd572dc4a06a1951f8d952a0e78d42b9f3d4 (diff)
downloadaports-766ffa0f26fa85486ce272c8260924bfffcabf65.tar.bz2
aports-766ffa0f26fa85486ce272c8260924bfffcabf65.tar.xz
main/gdnsd: upgrade to 1.9.0 (from testing)
Diffstat (limited to 'main/gdnsd')
-rw-r--r--main/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch265
-rw-r--r--main/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch42
-rw-r--r--main/gdnsd/0001-preliminary-djbdns-support.patch576
-rw-r--r--main/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch823
-rw-r--r--main/gdnsd/APKBUILD42
-rwxr-xr-xmain/gdnsd/gdnsd.initd27
-rw-r--r--main/gdnsd/geoip-autodc.patch211
-rw-r--r--main/gdnsd/geoip-speedup.patch101
8 files changed, 1171 insertions, 916 deletions
diff --git a/main/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch b/main/gdnsd/0001-Fix-auth-section-of-ANY-query-on-CNAME.patch
new file mode 100644
index 000000000..fb703b352
--- /dev/null
+++ b/main/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/main/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch b/main/gdnsd/0001-Fix-ztree_txn_-API-to-work.patch
new file mode 100644
index 000000000..f607d08c5
--- /dev/null
+++ b/main/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/main/gdnsd/0001-preliminary-djbdns-support.patch b/main/gdnsd/0001-preliminary-djbdns-support.patch
deleted file mode 100644
index 238436857..000000000
--- a/main/gdnsd/0001-preliminary-djbdns-support.patch
+++ /dev/null
@@ -1,576 +0,0 @@
-From d72aa39cb88178792c1e058b0b757b7cd9466e82 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
-Date: Tue, 8 May 2012 16:57:06 +0300
-Subject: [PATCH] preliminary djbdns support
-
----
- docs/TODO | 2 +-
- gdnsd/Makefile.am | 2 +-
- gdnsd/conf.c | 6 +-
- gdnsd/conf.h | 1 +
- gdnsd/ltree.c | 10 +-
- gdnsd/zscan-djb.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- gdnsd/zscan.h | 3 +
- 7 files changed, 460 insertions(+), 6 deletions(-)
- create mode 100644 gdnsd/zscan-djb.c
-
-diff --git a/docs/TODO b/docs/TODO
-index 2f84a9f..2a7fd9c 100644
---- a/docs/TODO
-+++ b/docs/TODO
-@@ -58,7 +58,7 @@ Realistically, AXFR is pretty far down the priority list. I think a higher-prio
-
- 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? in both cases, they could periodically update using the same switching mechanism as stat() watcher above...).
-+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 (a SQL connection? in both cases, they could periodically update using the same switching mechanism as stat() watcher above...).
-
- Stuff from conversations w/ Paul Dekkers: --------
-
-diff --git a/gdnsd/Makefile.am b/gdnsd/Makefile.am
-index feaed57..266b344 100644
---- a/gdnsd/Makefile.am
-+++ b/gdnsd/Makefile.am
-@@ -12,7 +12,7 @@ AM_CPPFLAGS = -I$(srcdir)/libgdnsd -I$(builddir)/libgdnsd -DVARDIR=\"$(localstat
-
- # How to build gdnsd
- sbin_PROGRAMS = gdnsd
--gdnsd_SOURCES = main.c conf.c $(ZSCAN_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.h pkterr.h gdnsd.h
-+gdnsd_SOURCES = main.c conf.c $(ZSCAN_C) ltarena.c ltree.c zscan-djb.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.h pkterr.h gdnsd.h
- gdnsd_LDADD = libgdnsd/libgdnsd.la $(CAPLIBS)
-
- zscan.c: zscan.rl
-diff --git a/gdnsd/conf.c b/gdnsd/conf.c
-index b79cbb2..a3357d4 100644
---- a/gdnsd/conf.c
-+++ b/gdnsd/conf.c
-@@ -55,6 +55,7 @@ global_config_t gconfig = {
- .pidfile = def_pidfile,
- .username = def_username,
- .chroot_path = def_chroot_path,
-+ .djbdns_path = NULL,
- .include_optional_ns = false,
- .realtime_stats = false,
- .lock_mem = false,
-@@ -577,7 +578,7 @@ void conf_load(const char* cfg_file) {
-
- const vscf_data_t* options = vscf_hash_get_data_byconstkey(cfg_root, "options", true);
-
-- const char* zdopt = NULL;
-+ const char* zdopt = NULL, * djbopt = NULL;
- char* zones_dir = NULL;
- const vscf_data_t* listen_opt = NULL;
- const vscf_data_t* http_listen_opt = NULL;
-@@ -628,6 +629,7 @@ void conf_load(const char* cfg_file) {
- CFG_OPT_STR(options, pidfile);
- CFG_OPT_STR(options, username);
- CFG_OPT_STR(options, chroot_path);
-+ CFG_OPT_STR_NOCOPY(options, djbdns_path, djbopt);
- CFG_OPT_STR_NOCOPY(options, zones_dir, zdopt);
- listen_opt = vscf_hash_get_data_byconstkey(options, "listen", true);
- http_listen_opt = vscf_hash_get_data_byconstkey(options, "http_listen", true);
-@@ -637,6 +639,8 @@ void conf_load(const char* cfg_file) {
-
- // Potentially a subdirectory of cfg_dir
- zones_dir = make_zones_dir(gdnsd_get_cfdir(), zdopt);
-+ if (djbopt)
-+ gconfig.djbdns_path = make_zones_dir(gdnsd_get_cfdir(), djbopt);
-
- // Set up the http listener data
- process_http_listen(http_listen_opt, def_http_port);
-diff --git a/gdnsd/conf.h b/gdnsd/conf.h
-index 07a39d4..4374aa6 100644
---- a/gdnsd/conf.h
-+++ b/gdnsd/conf.h
-@@ -48,6 +48,7 @@ typedef struct {
- const char* pidfile;
- const char* username;
- const char* chroot_path;
-+ const char* djbdns_path;
- bool include_optional_ns;
- bool realtime_stats;
- bool lock_mem;
-diff --git a/gdnsd/ltree.c b/gdnsd/ltree.c
-index 8d3debf..ef5d46c 100644
---- a/gdnsd/ltree.c
-+++ b/gdnsd/ltree.c
-@@ -1126,9 +1126,13 @@ void ltree_load_zones(void) {
- ltree_find_or_add_dname(zone->dname, true);
- }
-
-- for(unsigned i = 0; i < gconfig.num_zones; i++) {
-- const zoneinfo_t* zone = &gconfig.zones[i];
-- scan_zone(zone);
-+ if (!gconfig.djbdns_path) {
-+ for(unsigned i = 0; i < gconfig.num_zones; i++) {
-+ const zoneinfo_t* zone = &gconfig.zones[i];
-+ scan_zone(zone);
-+ }
-+ } else {
-+ read_djb_directory(gconfig.djbdns_path);
- }
-
- // Close the ltarena to further allocations. Mostly
-diff --git a/gdnsd/zscan-djb.c b/gdnsd/zscan-djb.c
-new file mode 100644
-index 0000000..fb18133
---- /dev/null
-+++ b/gdnsd/zscan-djb.c
-@@ -0,0 +1,442 @@
-+/* Copyright © 2012 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/>.
-+ *
-+ */
-+
-+#include "zscan.h"
-+
-+#include <string.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <dirent.h>
-+
-+#include "conf.h"
-+#include "ltree.h"
-+#include "ltarena.h"
-+#include "gdnsd-misc.h"
-+
-+#define TTL_NS 259200
-+#define TTL_POSITIVE 86400
-+#define TTL_NEGATIVE 2560
-+
-+#define parse_warn(_fmt...) \
-+ log_warn("Zonefile parse error: " _fmt)
-+
-+#define parse_error(_fmt...) \
-+ log_fatal("Zonefile parse error: " _fmt)
-+
-+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;
-+
-+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};
-+
-+F_NONNULL
-+static uint8_t *parse_dname(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 *expand_dname(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(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(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(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(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;
-+}
-+
-+#define TTDCHECK(fno) if (field[fno].len) { skipped++; continue; }
-+#define LOCCHECK(fno) if (field[fno].len) { skipped++; continue; }
-+
-+unsigned read_djb_file(const char *filename, soa_info_t *soas, unsigned mtime) {
-+ field_t field[15];
-+ unsigned skipped = 0;
-+
-+ dmn_assert(filename);
-+
-+ log_debug("Scanning djbzone file '%s'", filename);
-+
-+ FILE *f = fopen(filename, "rt");
-+ if(f == NULL)
-+ log_fatal("Cannot open zone file '%s' for reading: %s", filename, logf_errno());
-+
-+ size_t allocated = 0;
-+ ssize_t len;
-+ char *line = NULL;
-+ uint8_t dname[256], dname2[256], **texts = NULL;
-+ unsigned i, ttl;
-+
-+ while ((len = getline(&line, &allocated, f)) != -1) {
-+ if (len == 0 || line[0] == '#' || line[0] == '-')
-+ continue;
-+ if (line[len-1] == '\n') {
-+ line[len-1] = 0;
-+ len--;
-+ }
-+ if (len == 0)
-+ continue;
-+
-+ /* Skip location records */
-+ if (line[0] == '%')
-+ continue;
-+
-+ char *c;
-+ for (i = 0, c = line + 1; i < sizeof(field)/sizeof(field[0]); i++) {
-+ field[i].ptr = c ?: "";
-+ 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;
-+ }
-+ }
-+ }
-+
-+ parse_dname(dname, &field[0]);
-+
-+ for (i = 0; i < gconfig.num_zones; i++) {
-+ if (dname_isinzone(gconfig.zones[i].dname, dname))
-+ break;
-+ }
-+ if (i >= gconfig.num_zones)
-+ continue;
-+
-+ if (mtime > soas[i].mtime)
-+ soas[i].mtime = mtime;
-+
-+ switch (line[0]) {
-+ case 'Z': /* SOA */
-+ TTDCHECK(9);
-+ LOCCHECK(10);
-+ if (dname_cmp(gconfig.zones[i].dname, dname) == 0) {
-+ parse_dname(soas[i].ns, &field[1]);
-+ parse_dname(soas[i].email, &field[2]);
-+ soas[i].ttl = parse_ttl(&field[8], TTL_NEGATIVE);
-+ soas[i].serial = parse_int(&field[3]);
-+ soas[i].refresh = parse_int(&field[4]) ?: 16384;
-+ soas[i].retry = parse_int(&field[5]) ?: 2048;
-+ soas[i].expire = parse_int(&field[6]) ?: 1048576;
-+ soas[i].cache = parse_int(&field[7]) ?: 2560;
-+ } else {
-+ uint8_t email[256];
-+ ltree_add_rec_soa(dname,
-+ parse_dname(dname2, &field[1]),
-+ parse_dname(email, &field[2]),
-+ parse_ttl(&field[8], TTL_NEGATIVE),
-+ parse_int(&field[3]) ?: mtime, /* serial */
-+ parse_int(&field[4]) ?: 16384, /* refresh */
-+ parse_int(&field[5]) ?: 2048, /* retry */
-+ parse_int(&field[6]) ?: 1048576, /* expire */
-+ parse_int(&field[7]) ?: 2560 /* cache */);
-+ }
-+ break;
-+ case '.': /* NS + SOA (+ A) */
-+ case '&': /* NS (+ A) */
-+ TTDCHECK(4);
-+ LOCCHECK(5);
-+ expand_dname(dname2, &field[2], dname_ns, dname);
-+ ttl = parse_ttl(&field[3], TTL_NS);
-+ ltree_add_rec_ns(dname, dname2, ttl);
-+ if (field[1].len) {
-+ ltree_add_rec_a(dname2,
-+ parse_ipv4(&field[1]),
-+ ttl, 0, NULL);
-+ }
-+ break;
-+ case '@': /* MX (+ A) */
-+ TTDCHECK(5);
-+ LOCCHECK(6);
-+ expand_dname(dname2, &field[2], dname_mx, dname);
-+ ttl = parse_ttl(&field[4], TTL_POSITIVE);
-+ ltree_add_rec_mx(dname, dname2, ttl, parse_int(&field[3]));
-+ if (field[1].len) {
-+ ltree_add_rec_a(dname2,
-+ parse_ipv4(&field[1]),
-+ ttl, 0, NULL);
-+ }
-+ break;
-+ case '+': /* A */
-+ case '=': /* A + PTR */
-+ TTDCHECK(3);
-+ ttl = parse_ttl(&field[2], TTL_POSITIVE);
-+ if (field[4].len == 2 && memcmp(field[4].ptr, "~~", 2) == 0) {
-+ ltree_add_rec_dynaddr(dname, (const uint8_t *) field[1].ptr,
-+ ttl, 0, 0);
-+ } else {
-+ LOCCHECK(4);
-+ ltree_add_rec_a(dname, parse_ipv4(&field[1]), ttl, 0, NULL);
-+#if 0
-+ /* FIXME: autogen PTR record */
-+ if (line[0] == '=') {
-+ ltree_add_rec_ptr();
-+ }
-+#endif
-+ }
-+ break;
-+ case 'C': /* CNAME */
-+ TTDCHECK(3);
-+ ttl = parse_ttl(&field[2], TTL_POSITIVE);
-+ if (field[4].len == 2 && memcmp(field[4].ptr, "~~", 2) == 0) {
-+ ltree_add_rec_dyncname(dname, (const uint8_t *) field[1].ptr,
-+ dname_root, ttl);
-+ } else {
-+ LOCCHECK(4);
-+ ltree_add_rec_cname(dname, parse_dname(dname2, &field[1]), ttl);
-+ }
-+ 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("Text chunk too long (>255 unescaped)");
-+ if(bytes > 65500)
-+ parse_error("Text chunk too long (>65500 unescaped)");
-+
-+ texts = realloc(texts, sizeof(uint8_t *) * (chunks + 1));
-+ for (i = 0; i < chunks; i++) {
-+ int s = (bytes > 255 ? 255 : bytes);
-+ texts[i] = lta_malloc_1(s + 1);
-+ texts[i][0] = s;
-+ memcpy(&texts[i][1], src, s);
-+
-+ bytes -= s;
-+ src += s;
-+ }
-+ texts[i] = NULL;
-+ ltree_add_rec_txt(dname, chunks, texts,
-+ parse_ttl(&field[2], TTL_POSITIVE));
-+ break;
-+ case 'S': /* SRV (+ A) */
-+ TTDCHECK(7);
-+ LOCCHECK(8);
-+ expand_dname(dname2, &field[2], dname_srv, dname);
-+ ttl = parse_ttl(&field[6], TTL_POSITIVE);
-+ ltree_add_rec_srv(dname, dname2,
-+ ttl,
-+ parse_int(&field[4]),
-+ parse_int(&field[5]),
-+ parse_int(&field[3]));
-+ if (field[1].len) {
-+ ltree_add_rec_a(dname2,
-+ parse_ipv4(&field[1]),
-+ ttl, 0, NULL);
-+ }
-+ 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("NAPTR label cannot exceed 255 chars");
-+
-+ texts = realloc(texts, sizeof(uint8_t *) * (3 + 1));
-+ for (i = 0; i < 3; i++) {
-+ texts[i] = lta_malloc_1(field[3+i].len + 1);
-+ texts[i][0] = field[3+i].len;
-+ memcpy(&texts[i][1], field[3+i].ptr, field[3+i].len);
-+ }
-+ texts[i] = NULL;
-+ ltree_add_rec_naptr(dname,
-+ parse_dname(dname2, &field[6]),
-+ parse_ttl(&field[7], TTL_POSITIVE),
-+ parse_int(&field[1]),
-+ parse_int(&field[2]),
-+ 3, texts);
-+ break;
-+#if 0
-+ case '3': /* AAAA */
-+ case '6': /* AAAA + PTR */
-+ case '^': /* PTR */
-+ case ':': /* raw */
-+#endif
-+ default:
-+ log_warn("Unsupported djbdns record type '%c'", line[0]);
-+ }
-+ }
-+ free(texts);
-+ free(line);
-+ fclose(f);
-+
-+ return skipped;
-+}
-+
-+void read_djb_directory(const char *path) {
-+ struct dirent *e;
-+ DIR *dir;
-+ unsigned i, skipped = 0;
-+ soa_info_t *soas;
-+
-+ soas = calloc(gconfig.num_zones, sizeof(soa_info_t));
-+
-+ dir = opendir(path);
-+ if (dir == NULL)
-+ log_fatal("Cannot open djbzone directory '%s': %s", path, logf_errno());
-+ while ((e = readdir(dir)) != NULL) {
-+ if (e->d_name[0] == '.')
-+ continue;
-+ struct stat st;
-+ char *fn = gdnsd_make_abs_fn(gconfig.djbdns_path, e->d_name);
-+ if (stat(fn, &st))
-+ log_fatal("Cannot stat djbzone file '%s': %s", e->d_name, logf_errno());
-+ if((st.st_mode & S_IFMT) == S_IFREG)
-+ skipped += read_djb_file(fn, soas, st.st_mtime);
-+ free(fn);
-+ }
-+ closedir(dir);
-+
-+ for (i = 0; i < gconfig.num_zones; i++) {
-+ if (soas[i].mtime == 0)
-+ continue;
-+
-+ ltree_add_rec_soa(gconfig.zones[i].dname,
-+ soas[i].ns, soas[i].email,
-+ soas[i].ttl,
-+ soas[i].serial ? : soas[i].mtime,
-+ soas[i].refresh,
-+ soas[i].retry,
-+ soas[i].expire,
-+ soas[i].cache);
-+ }
-+
-+ free(soas);
-+
-+ if (skipped)
-+ log_warn("Skipped: %d records with TTD or location", skipped);
-+}
-diff --git a/gdnsd/zscan.h b/gdnsd/zscan.h
-index faaba1f..d246617 100644
---- a/gdnsd/zscan.h
-+++ b/gdnsd/zscan.h
-@@ -36,4 +36,7 @@ typedef struct {
- F_NONNULL
- void scan_zone(const zoneinfo_t* zone);
-
-+F_NONNULL
-+void read_djb_directory(const char* path);
-+
- #endif // _GDNSD_ZSCAN_H
---
-1.7.10.2
-
diff --git a/main/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch b/main/gdnsd/0002-Impelement-loading-of-DJBDNS-zone-files.patch
new file mode 100644
index 000000000..b7b14221e
--- /dev/null
+++ b/main/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/main/gdnsd/APKBUILD b/main/gdnsd/APKBUILD
index 5652bf31d..49ee35bcb 100644
--- a/main/gdnsd/APKBUILD
+++ b/main/gdnsd/APKBUILD
@@ -1,7 +1,7 @@
# Contributor: Natanael Copa <ncopa@alpinelinux.org>
# Maintainer: Timo Teräs <timo.teras@iki.fi>
pkgname=gdnsd
-pkgver=1.6.9
+pkgver=1.9.0
pkgrel=0
pkgdesc="Geographic Authoritative DNS server"
url="https://github.com/blblack/gdnsd/"
@@ -9,13 +9,13 @@ arch="all"
license="GPL-3"
depends=""
depends_dev=""
-makedepends="libev-dev libcap-dev autoconf automake libtool"
+makedepends="userspace-rcu-dev libev-dev libcap-dev ragel autoconf automake libtool"
install="$pkgname.pre-install"
subpackages="$pkgname-dev $pkgname-doc"
-source="https://github.com/downloads/blblack/gdnsd/gdnsd-$pkgver.tar.xz
- geoip-autodc.patch
- geoip-speedup.patch
- 0001-preliminary-djbdns-support.patch
+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
@@ -27,18 +27,12 @@ prepare() {
*.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
esac
done
- libtoolize --force || return 1
- aclocal -I m4 || return 1
- autoconf || return 1
- automake --add-missing || return 1
+ ./autogen.sh || return 1
}
build() {
cd "$_builddir"
- ./configure \
- --build=$CBUILD \
- --host=$CHOST \
- --prefix=/usr \
+ ./configure --prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var \
--enable-fast-install \
@@ -57,8 +51,18 @@ package() {
"$pkgdir"/etc/init.d/gdnsd || return 1
}
-md5sums="c8ea1da00fabc52e3d685528444f1279 gdnsd-1.6.9.tar.xz
-02eb668b6cad54552568a35985f44a09 geoip-autodc.patch
-7fb697653b8295322e53492f9051e831 geoip-speedup.patch
-00f2838e0908effaaa2f6e6a1699f25b gdnsd.initd
-4c8ff14e377fb8f1854b68b7bf9be282 0001-preliminary-djbdns-support.patch"
+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/main/gdnsd/gdnsd.initd b/main/gdnsd/gdnsd.initd
index 2dbb56897..9820052be 100755
--- a/main/gdnsd/gdnsd.initd
+++ b/main/gdnsd/gdnsd.initd
@@ -2,15 +2,17 @@
name="gdnsd daemon"
extra_commands="configtest"
-extra_started_commands="reload"
+extra_started_commands="reload fastrestart"
+description="Geographic Authoritative DNS server"
description_configtest="Run syntax tests for configuration files only."
-description_reload="Fast reload: check config, load files, kill old server, start new server (in this order)."
+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_CONFFILE=/etc/gdnsd/config
+ GDNSD_ROOT=system
else
- GDNSD_CONFFILE=/etc/gdnsd/${SVCNAME}.config
+ GDNSD_ROOT=/var/gdnsd/${SVCNAME}
fi
fi
@@ -23,22 +25,29 @@ depend() {
act() {
ebegin "$1 ${SVCNAME}"
- /usr/sbin/gdnsd -c ${GDNSD_CONFFILE} ${GDNSD_OPTS} $2
+ /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
}
-reload() {
- act "Reloading" restart
+fastrestart() {
+ act "Restarting" restart
}
-configtest() {
- act "Checking configuration" checkconf
+reload() {
+ act "Reloading" reload
}
diff --git a/main/gdnsd/geoip-autodc.patch b/main/gdnsd/geoip-autodc.patch
deleted file mode 100644
index ae313ef38..000000000
--- a/main/gdnsd/geoip-autodc.patch
+++ /dev/null
@@ -1,211 +0,0 @@
-From 8f172f642d4aa3a30f5a356a4611f66227e74681 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
-Date: Tue, 21 Aug 2012 16:45:45 +0300
-Subject: [PATCH] plugin_geoip: allow datacenters to be omitted from
- auto_dc_coords
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Those datacenters will be never returned automatically. They are
-available only from specific territories (map overrides) or subnets
-(net overrides).
-
-Signed-off-by: Timo Teräs <timo.teras@iki.fi>
----
- plugins/meta/libgdmaps/gdmaps.c | 46 +++++++++++++++-----------
- plugins/meta/libgdmaps/t/Makefile.am | 3 +-
- plugins/meta/libgdmaps/t/t14_missingcoords.c | 42 +++++++++++++++++++++++
- plugins/meta/libgdmaps/t/t14_missingcoords.cfg | 29 ++++++++++++++++
- 4 files changed, 100 insertions(+), 20 deletions(-)
- create mode 100644 plugins/meta/libgdmaps/t/t14_missingcoords.c
- create mode 100644 plugins/meta/libgdmaps/t/t14_missingcoords.cfg
-
-diff --git a/plugins/meta/libgdmaps/gdmaps.c b/plugins/meta/libgdmaps/gdmaps.c
-index be23d9b..b367e6f 100644
---- a/plugins/meta/libgdmaps/gdmaps.c
-+++ b/plugins/meta/libgdmaps/gdmaps.c
-@@ -148,6 +148,7 @@ static dcinfo_t* dcinfo_new(const vscf_data_t* dc_cfg, const vscf_data_t* dc_aut
- dcinfo_t* info = malloc(sizeof(dcinfo_t));
-
- const unsigned num_dcs = vscf_array_get_len(dc_cfg);
-+ unsigned num_auto = 0;
- if(!num_dcs)
- log_fatal("plugin_geoip: map '%s': 'datacenters' must be an array of one or more strings", map_name);
- if(num_dcs > 254)
-@@ -164,34 +165,26 @@ static dcinfo_t* dcinfo_new(const vscf_data_t* dc_cfg, const vscf_data_t* dc_aut
- log_fatal("plugin_geoip: map '%s': datacenter name 'auto' is illegal", map_name);
- }
-
-- if(dc_auto_limit_cfg) {
-- unsigned long auto_limit_ul;
-- if(!vscf_is_simple(dc_auto_limit_cfg) || !vscf_simple_get_as_ulong(dc_auto_limit_cfg, &auto_limit_ul))
-- log_fatal("plugin_geoip: map '%s': auto_dc_limit must be a single unsigned integer value", map_name);
-- if(auto_limit_ul > num_dcs || !auto_limit_ul)
-- auto_limit_ul = num_dcs;
-- info->auto_limit = auto_limit_ul;
-- }
-- else {
-- info->auto_limit = (num_dcs > 3) ? 3 : num_dcs;
-- }
--
- if(dc_auto_cfg) {
- if(!vscf_is_hash(dc_auto_cfg))
- log_fatal("plugin_geoip: map '%s': auto_dc_coords must be a key-value hash", map_name);
-- const unsigned num_auto = vscf_hash_get_len(dc_auto_cfg);
-- if(num_auto != num_dcs)
-- log_fatal("plugin_geoip: map '%s': auto_dc_coords hash must contain one entry for each datacenter in 'datacenters'", map_name);
-- info->coords = malloc(num_auto * 2 * sizeof(double));
-+ num_auto = vscf_hash_get_len(dc_auto_cfg);
-+ if (info->auto_limit > num_auto)
-+ info->auto_limit = num_auto;
-+ info->coords = malloc(num_dcs * 2 * sizeof(double));
-+ for(unsigned i = 0; i < 2*num_dcs; i++)
-+ info->coords[i] = NAN;
- for(unsigned i = 0; i < num_auto; i++) {
- const char* dcname = vscf_hash_get_key_byindex(dc_auto_cfg, i, NULL);
- unsigned dcidx;
-- for(dcidx = 0; dcidx < info->num_dcs; dcidx++) {
-+ for(dcidx = 0; dcidx < num_dcs; dcidx++) {
- if(!strcmp(dcname, info->names[dcidx]))
- break;
- }
-- if(dcidx == info->num_dcs)
-+ if(dcidx == num_dcs)
- log_fatal("plugin_geoip: map '%s': auto_dc_coords key '%s' not matched from 'datacenters' list", map_name, dcname);
-+ if(!isnan(info->coords[(dcidx*2)]))
-+ log_fatal("plugin_geoip: map '%s': auto_dc_coords key '%s' defined twice", map_name, dcname);
- const vscf_data_t* coord_cfg = vscf_hash_get_data_byindex(dc_auto_cfg, i);
- const vscf_data_t* lat_cfg;
- const vscf_data_t* lon_cfg;
-@@ -216,6 +209,18 @@ static dcinfo_t* dcinfo_new(const vscf_data_t* dc_cfg, const vscf_data_t* dc_aut
- info->coords = NULL;
- }
-
-+ if(dc_auto_limit_cfg) {
-+ unsigned long auto_limit_ul;
-+ if(!vscf_is_simple(dc_auto_limit_cfg) || !vscf_simple_get_as_ulong(dc_auto_limit_cfg, &auto_limit_ul))
-+ log_fatal("plugin_geoip: map '%s': auto_dc_limit must be a single unsigned integer value", map_name);
-+ if(auto_limit_ul > num_auto || !auto_limit_ul)
-+ auto_limit_ul = num_auto;
-+ info->auto_limit = auto_limit_ul;
-+ }
-+ else {
-+ info->auto_limit = (num_auto > 3) ? 3 : num_auto;
-+ }
-+
- return info;
- }
-
-@@ -438,7 +443,10 @@ static unsigned dclists_city_auto_map(dclists_t* lists, const char* map_name, co
- double dists[store_len];
- for(unsigned i = 0; i < num_dcs; i++) {
- const unsigned c_offs = i * 2;
-- dists[i + 1] = haversine(lat_rad, lon_rad, coords[c_offs], coords[c_offs + 1]);
-+ if (!isnan(coords[c_offs]))
-+ dists[i + 1] = haversine(lat_rad, lon_rad, coords[c_offs], coords[c_offs + 1]);
-+ else
-+ dists[i + 1] = +INFINITY;
- }
-
- // Given the relatively small num_dcs of most configs,
-diff --git a/plugins/meta/libgdmaps/t/Makefile.am b/plugins/meta/libgdmaps/t/Makefile.am
-index f83592f..e9d26ce 100644
---- a/plugins/meta/libgdmaps/t/Makefile.am
-+++ b/plugins/meta/libgdmaps/t/Makefile.am
-@@ -41,7 +41,8 @@ TESTLIST = \
- t10_def \
- t11_def2 \
- t12_defnone \
-- t13_castatdef
-+ t13_castatdef \
-+ t14_missingcoords
-
- check_PROGRAMS = $(TESTLIST:=.bin)
-
-diff --git a/plugins/meta/libgdmaps/t/t14_missingcoords.c b/plugins/meta/libgdmaps/t/t14_missingcoords.c
-new file mode 100644
-index 0000000..9329ee3
---- /dev/null
-+++ b/plugins/meta/libgdmaps/t/t14_missingcoords.c
-@@ -0,0 +1,42 @@
-+/* Copyright © 2012 Brandon L Black <blblack@gmail.com>
-+ *
-+ * This file is part of gdnsd-plugin-geoip.
-+ *
-+ * gdnsd-plugin-geoip 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-plugin-geoip 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/>.
-+ *
-+ */
-+
-+// Unit test for gdmaps
-+
-+#include "config.h"
-+#include <gdnsd-log.h>
-+#include "gdmaps_test.h"
-+
-+int main(int argc, char* argv[]) {
-+ if(argc != 2)
-+ log_fatal("root directory must be set on commandline");
-+
-+ gdmaps_t* gdmaps = gdmaps_test_init(argv[1]);
-+ unsigned tnum = 0;
-+ //datacenters => [ us, ie, sg, tr, br ]
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "137.138.144.168", "\2\1\5\3", 16); // Geneva
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "69.58.186.119", "\1\2\5\3", 16); // US East Coast
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "117.53.170.202", "\3\5\1\2", 20); // Australia
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "133.11.114.194", "\2\4", 8); // JP, horrible custom 'map' entry
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "10.0.0.44", "\4\2", 24); // Custom 'nets' entry
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "10.0.1.44", "", 24); // Custom 'nets' entry, empty
-+ gdmaps_test_lookup_check(tnum++, gdmaps, "my_prod_map", "192.168.1.1", "\1\2\3\4\5", 16); // meta-default, no loc
-+ gdmaps_destroy(gdmaps);
-+}
-+
-diff --git a/plugins/meta/libgdmaps/t/t14_missingcoords.cfg b/plugins/meta/libgdmaps/t/t14_missingcoords.cfg
-new file mode 100644
-index 0000000..8c57cdd
---- /dev/null
-+++ b/plugins/meta/libgdmaps/t/t14_missingcoords.cfg
-@@ -0,0 +1,29 @@
-+options => { debug => true }
-+plugins => {
-+ geoip => {
-+ maps => {
-+ # bringing it all together: city-auto w/ 5 dcs,
-+ # dual GeoIP inputs, custom maps, custom nets
-+ # testing with one datacenter not used in auto coords
-+ my_prod_map => {
-+ geoip_db => GeoLiteCityv6-20111210.dat,
-+ geoip_db_v4_overlay => GeoLiteCity-20111210.dat,
-+ datacenters => [ us, ie, sg, tr, br ]
-+ auto_dc_limit => 5,
-+ auto_dc_coords => {
-+ us = [ 38.9, -77 ]
-+ ie = [ 53.3, -6.3 ]
-+ sg = [ 1.3, 103.9 ]
-+ br = [ -22.9, -43.2 ]
-+ }
-+ map => {
-+ AS => { JP => [ ie, tr ] }
-+ }
-+ nets => {
-+ 10.0.1.0/24 => [ ]
-+ 10.0.0.0/24 => [ tr, ie ]
-+ }
-+ }
-+ }
-+ }
-+}
---
-1.7.12
-
diff --git a/main/gdnsd/geoip-speedup.patch b/main/gdnsd/geoip-speedup.patch
deleted file mode 100644
index 3816df44e..000000000
--- a/main/gdnsd/geoip-speedup.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From: Timo TerÃs <timo.teras@iki.fi>
-
-plugin_geoip: speed up cities database loading
-
-Gives over 10x speed-up in loading the large cities database.
-http://code.google.com/p/gdnsd/issues/detail?id=18
-
-diff --git a/plugins/meta/libgdmaps/gdmaps.c b/plugins/meta/libgdmaps/gdmaps.c
-index 9d20351..6bbc410 100644
---- a/plugins/meta/libgdmaps/gdmaps.c
-+++ b/plugins/meta/libgdmaps/gdmaps.c
-@@ -1215,6 +1215,12 @@ typedef struct {
- } gdmap_t;
-
- typedef struct {
-+ unsigned offset;
-+ unsigned dclist;
-+} offset_cache_item_t;
-+#define OFFSET_CACHE_SIZE (1 << 18)
-+
-+typedef struct {
- char* pathname;
- uint8_t* data;
- const fips_t* fips;
-@@ -1223,6 +1229,8 @@ typedef struct {
- int type;
- unsigned base;
- bool ipv6;
-+
-+ offset_cache_item_t *offset_cache[OFFSET_CACHE_SIZE];
- } geoip_db_t;
-
- F_NONNULL
-@@ -1230,7 +1238,7 @@ static int geoip_db_close(geoip_db_t* db);
- F_NONNULLX(1)
- static geoip_db_t* geoip_db_open(const char* pathname, const fips_t* fips, const char* map_name, const bool city_required);
- F_NONNULLX(1, 2, 3)
--static int geoip_tree_xlate(const gdmap_t* gdmap, ntree_t* tree, const geoip_db_t* db, const geoip_db_t* db_v4o);
-+static int geoip_tree_xlate(const gdmap_t* gdmap, ntree_t* tree, geoip_db_t* db, geoip_db_t* db_v4o);
-
- F_NONNULL
- static ntree_t* gdmap_make_tree(const gdmap_t* gdmap, const dclists_t* old_dclists) {
-@@ -1957,10 +1965,18 @@ static unsigned city_lookup_dclist(const geoip_db_t* db, unsigned int offs, cons
- }
-
- F_NONNULL
--static unsigned get_dclist(const gdmap_t* gdmap, const ntree_t* tree, const geoip_db_t* db, const unsigned int offset) {
-+static unsigned get_dclist(const gdmap_t* gdmap, const ntree_t* tree, geoip_db_t* db, const unsigned int offset) {
- dmn_assert(gdmap); dmn_assert(db);
-
- unsigned dclist = 0;
-+ unsigned bucket_size = 0;
-+ unsigned ndx = offset % OFFSET_CACHE_SIZE;
-+
-+ if (db->offset_cache[ndx]) {
-+ for (bucket_size = 0; db->offset_cache[ndx][bucket_size].offset; bucket_size++)
-+ if (db->offset_cache[ndx][bucket_size].offset == offset)
-+ return db->offset_cache[ndx][bucket_size].dclist;
-+ }
-
- switch(db->type) {
- case GEOIP_CITY_EDITION_REV1_V6:
-@@ -1983,6 +1999,11 @@ static unsigned get_dclist(const gdmap_t* gdmap, const ntree_t* tree, const geoi
- break;
- }
-
-+ db->offset_cache[ndx] = realloc(db->offset_cache[ndx], sizeof(offset_cache_item_t) * (bucket_size+2));
-+ db->offset_cache[ndx][bucket_size].offset = offset;
-+ db->offset_cache[ndx][bucket_size].dclist = dclist;
-+ db->offset_cache[ndx][bucket_size+1].offset = 0;
-+
- return dclist;
- }
-
-@@ -1991,7 +2012,7 @@ static unsigned get_dclist(const gdmap_t* gdmap, const ntree_t* tree, const geoi
- // C really needs a better macro/template idea :(
- #define DEFUN_TREE_XLATE(IPVN, IPTYPE, IPZERO, BITDEPTH, V4ROOT_CODE, SKIP_CODE) \
- F_NONNULL \
--static int geoip_tree_xlate_ ## IPVN(const gdmap_t* gdmap, ntree_t* tree, const geoip_db_t* db) { \
-+static int geoip_tree_xlate_ ## IPVN(const gdmap_t* gdmap, ntree_t* tree, geoip_db_t* db) { \
- dmn_assert(gdmap); dmn_assert(tree); dmn_assert(db); \
- struct { \
- int depth; \
-@@ -2107,7 +2128,7 @@ DEFUN_TREE_XLATE(v4, uint32_t, 0, 32, ;, ;)
-
- DEFUN_TREE_XLATE(v6, struct in6_addr, ip6_zero, 128, V6_V4ROOT_CODE, V6_SKIP_CODE)
-
--static int geoip_tree_xlate(const gdmap_t* gdmap, ntree_t* tree, const geoip_db_t* db, const geoip_db_t* db_v4o) {
-+static int geoip_tree_xlate(const gdmap_t* gdmap, ntree_t* tree, geoip_db_t* db, geoip_db_t* db_v4o) {
- dmn_assert(gdmap); dmn_assert(tree); dmn_assert(db);
-
- log_info("plugin_geoip: map '%s': Processing GeoIP database '%s'...", gdmap->name, gdmap->geoip_path);
-@@ -2145,6 +2166,8 @@ static int geoip_db_close(geoip_db_t* db) {
- }
- }
-
-+ for (unsigned i = 0; i < OFFSET_CACHE_SIZE; i++)
-+ free(db->offset_cache[i]);
- if(db->pathname)
- free(db->pathname);
- free(db);