From 2855e2772342e369cc8962659beac7b3001b4ec6 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 31 Jan 2012 03:35:41 +0000 Subject: [PATCH] 3271. [func] New "rndc zonestatus" command prints information about the specified zone. [RT #21671] --- CHANGES | 3 + bin/named/control.c | 4 +- bin/named/include/named/control.h | 3 +- bin/named/include/named/server.h | 9 +- bin/named/server.c | 250 ++++++++++++++++++++- bin/rndc/rndc.c | 4 +- bin/tests/system/zonechecks/clean.sh | 5 +- bin/tests/system/zonechecks/ns1/named.conf | 53 +++++ bin/tests/system/zonechecks/ns2/named.conf | 51 +++++ bin/tests/system/zonechecks/setup.sh | 29 +++ bin/tests/system/zonechecks/tests.sh | 74 ++++-- doc/arm/Bv9ARM-book.xml | 22 +- lib/dns/include/dns/master.h | 35 ++- lib/dns/include/dns/zone.h | 35 ++- lib/dns/master.c | 82 +++++-- lib/dns/tests/master_test.c | 73 +++++- lib/dns/zone.c | 120 +++++++++- 17 files changed, 791 insertions(+), 61 deletions(-) create mode 100644 bin/tests/system/zonechecks/ns1/named.conf create mode 100644 bin/tests/system/zonechecks/ns2/named.conf create mode 100644 bin/tests/system/zonechecks/setup.sh diff --git a/CHANGES b/CHANGES index ded8bc2a95..87ee1906a6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3271. [func] New "rndc zonestatus" command prints information + about the specified zone. [RT #21671] + --- 9.9.0rc2 released --- 3270. [bug] "rndc reload" didn't reuse existing zones correctly diff --git a/bin/named/control.c b/bin/named/control.c index 200a359a57..62008f533c 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.c,v 1.47 2011/11/03 23:05:30 each Exp $ */ +/* $Id: control.c,v 1.48 2012/01/31 03:35:39 each Exp $ */ /*! \file */ @@ -207,6 +207,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { result = ns_server_del_zone(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_SIGNING)) { result = ns_server_signing(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_ZONESTATUS)) { + result = ns_server_zonestatus(ns_g_server, command, text); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 064ec50e2a..1ababec607 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.h,v 1.36 2011/10/28 06:20:04 each Exp $ */ +/* $Id: control.h,v 1.37 2012/01/31 03:35:39 each Exp $ */ #ifndef NAMED_CONTROL_H #define NAMED_CONTROL_H 1 @@ -65,6 +65,7 @@ #define NS_COMMAND_DELZONE "delzone" #define NS_COMMAND_SYNC "sync" #define NS_COMMAND_SIGNING "signing" +#define NS_COMMAND_ZONESTATUS "zonestatus" isc_result_t ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp); diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 17eaeefdde..62c36734d9 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.116 2011/11/03 23:05:30 each Exp $ */ +/* $Id: server.h,v 1.117 2012/01/31 03:35:39 each Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -348,4 +348,11 @@ ns_server_del_zone(ns_server_t *server, char *args); */ isc_result_t ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text); + +/*% + * Lists status information for a given zone (e.g., name, type, files, + * load time, expiry, etc). + */ +isc_result_t +ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t *text); #endif /* NAMED_SERVER_H */ diff --git a/bin/named/server.c b/bin/named/server.c index 64e1ad7003..69b51bf609 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.639 2012/01/31 01:13:09 each Exp $ */ +/* $Id: server.c,v 1.640 2012/01/31 03:35:39 each Exp $ */ /*! \file */ @@ -8026,3 +8026,251 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) { return (result); } + +isc_result_t +ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result = ISC_R_SUCCESS; + dns_zone_t *zone = NULL, *raw = NULL; + const char *type, *file, *zonename = NULL; + isc_uint32_t serial, signed_serial, nodes; + char serbuf[16], sserbuf[16], nodebuf[16], resignbuf[512]; + char lbuf[80], xbuf[80], rbuf[80], kbuf[80], rtbuf[80]; + isc_time_t loadtime, expiretime, refreshtime; + isc_time_t refreshkeytime, resigntime; + dns_zonetype_t zonetype; + isc_boolean_t dynamic = ISC_FALSE, frozen = ISC_FALSE; + isc_boolean_t hasraw = ISC_FALSE; + isc_boolean_t secure, maintain, allow; + dns_db_t *db = NULL, *rawdb = NULL; + char **incfiles = NULL; + int nfiles = 0; + + isc_time_settoepoch(&loadtime); + isc_time_settoepoch(&refreshtime); + isc_time_settoepoch(&expiretime); + isc_time_settoepoch(&refreshkeytime); + isc_time_settoepoch(&resigntime); + + CHECK(zone_from_args(server, args, &zone, &zonename, ISC_TRUE)); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + zonetype = dns_zone_gettype(zone); + switch (zonetype) { + case dns_zone_master: + type = "master"; + break; + case dns_zone_slave: + type = "slave"; + break; + case dns_zone_stub: + type = "stub"; + break; + case dns_zone_staticstub: + type = "staticstub"; + break; + case dns_zone_redirect: + type = "redirect"; + break; + case dns_zone_key: + type = "key"; + break; + case dns_zone_dlz: + type = "dlz"; + break; + default: + type = "unknown"; + } + + /* Inline signing? */ + CHECK(dns_zone_getdb(zone, &db)); + dns_zone_getraw(zone, &raw); + hasraw = ISC_TF(raw != NULL); + if (hasraw) + CHECK(dns_zone_getdb(raw, &rawdb)); + + /* Serial number */ + serial = dns_zone_getserial(hasraw ? raw : zone); + snprintf(serbuf, sizeof(serbuf), "%d", serial); + if (hasraw) { + signed_serial = dns_zone_getserial(zone); + snprintf(sserbuf, sizeof(sserbuf), "%d", signed_serial); + } + + /* Database node count */ + nodes = dns_db_nodecount(hasraw ? rawdb : db); + snprintf(nodebuf, sizeof(nodebuf), "%d", nodes); + + /* Security */ + secure = dns_db_issecure(db); + allow = ISC_TF((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0); + maintain = ISC_TF((dns_zone_getkeyopts(zone) & + DNS_ZONEKEY_MAINTAIN) != 0); + + /* Master files */ + file = dns_zone_getfile(hasraw ? raw : zone); + nfiles = dns_zone_getincludes(hasraw ? raw : zone, &incfiles); + + /* Load time */ + dns_zone_getloadtime(zone, &loadtime); + isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf)); + + /* Refresh/expire times */ + if (zonetype == dns_zone_slave || + zonetype == dns_zone_stub || + zonetype == dns_zone_redirect) + { + dns_zone_getexpiretime(zone, &expiretime); + isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf)); + dns_zone_getrefreshtime(zone, &refreshtime); + isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf)); + } + + /* Key refresh time */ + if (zonetype == dns_zone_master || + (zonetype == dns_zone_slave && hasraw)) + { + dns_zone_getrefreshkeytime(zone, &refreshkeytime); + isc_time_formathttptimestamp(&refreshkeytime, kbuf, + sizeof(kbuf)); + } + + /* Dynamic? */ + if (zonetype == dns_zone_master) { + dynamic = dns_zone_isdynamic(hasraw ? raw : zone, ISC_TRUE); + frozen = dynamic && !dns_zone_isdynamic(hasraw ? raw : zone, + ISC_FALSE); + } + + /* Next resign event */ + if (secure && (zonetype == dns_zone_master || + (zonetype == dns_zone_slave && hasraw)) && + ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0)) + { + dns_name_t *name; + dns_fixedname_t fixed; + dns_rdataset_t next; + dns_db_t *signingdb; + + dns_rdataset_init(&next); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + signingdb = hasraw ? rawdb : db; + + result = dns_db_getsigningtime(signingdb, &next, name); + if (result == ISC_R_SUCCESS) { + isc_stdtime_t timenow; + char namebuf[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + + isc_stdtime_get(&timenow); + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(next.covers, + typebuf, sizeof(typebuf)); + snprintf(resignbuf, sizeof(resignbuf), + "%s/%s", namebuf, typebuf); + isc_time_set(&resigntime, next.resign, 0); + isc_time_formathttptimestamp(&resigntime, rtbuf, + sizeof(rtbuf)); + dns_rdataset_disassociate(&next); + } + } + + /* Create text */ + isc_buffer_putstr(text, "name: "); + isc_buffer_putstr(text, zonename); + + isc_buffer_putstr(text, "\ntype: "); + isc_buffer_putstr(text, type); + + if (file != NULL) { + int i; + isc_buffer_putstr(text, "\nfiles: "); + isc_buffer_putstr(text, dns_zone_getfile(zone)); + for (i = 0; i < nfiles; i++) { + isc_buffer_putstr(text, ", "); + isc_buffer_putstr(text, incfiles[i]); + } + } + + isc_buffer_putstr(text, "\nserial: "); + isc_buffer_putstr(text, serbuf); + if (hasraw) { + isc_buffer_putstr(text, "\nsigned serial: "); + isc_buffer_putstr(text, sserbuf); + } + + isc_buffer_putstr(text, "\nnodes: "); + isc_buffer_putstr(text, nodebuf); + + if (! isc_time_isepoch(&loadtime)) { + isc_buffer_putstr(text, "\nlast loaded: "); + isc_buffer_putstr(text, lbuf); + } + + if (! isc_time_isepoch(&refreshtime)) { + isc_buffer_putstr(text, "\nnext refresh: "); + isc_buffer_putstr(text, rbuf); + } + + if (! isc_time_isepoch(&expiretime)) { + isc_buffer_putstr(text, "\nexpires: "); + isc_buffer_putstr(text, lbuf); + } + + if (secure) { + isc_buffer_putstr(text, "\nsecure: yes"); + if (hasraw) + isc_buffer_putstr(text, "\ninline signing: yes"); + else + isc_buffer_putstr(text, "\ninline signing: no"); + } else + isc_buffer_putstr(text, "\nsecure: no"); + + if (maintain) { + isc_buffer_putstr(text, "\nkey maintenance: automatic"); + if (! isc_time_isepoch(&refreshkeytime)) { + isc_buffer_putstr(text, "\nnext key event: "); + isc_buffer_putstr(text, kbuf); + } + } else if (allow) + isc_buffer_putstr(text, "\nkey maintenance: on command"); + else if (secure || hasraw) + isc_buffer_putstr(text, "\nkey maintenance: none"); + + if (!isc_time_isepoch(&resigntime)) { + isc_buffer_putstr(text, "\nnext resign node: "); + isc_buffer_putstr(text, resignbuf); + isc_buffer_putstr(text, "\nnext resign time: "); + isc_buffer_putstr(text, rtbuf); + } + + if (dynamic) { + isc_buffer_putstr(text, "\ndynamic: yes"); + if (frozen) + isc_buffer_putstr(text, "\nfrozen: yes"); + else + isc_buffer_putstr(text, "\nfrozen: no"); + } else + isc_buffer_putstr(text, "\ndynamic: no"); + + isc_buffer_putuint8(text, 0); + + cleanup: + if (db != NULL) + dns_db_detach(&db); + if (hasraw) { + dns_db_detach(&rawdb); + dns_zone_detach(&raw); + } + if (incfiles != NULL) + isc_mem_free(server->mctx, incfiles); + if (zone != NULL) + dns_zone_detach(&zone); + return (result); +} diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c index 20e5db119b..67e521fc52 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rndc.c,v 1.139 2011/11/29 00:49:26 marka Exp $ */ +/* $Id: rndc.c,v 1.140 2012/01/31 03:35:39 each Exp $ */ /*! \file */ @@ -126,6 +126,8 @@ command is one of the following:\n\ Update zone keys, and sign as needed.\n\ loadkeys zone [class [view]]\n\ Update keys without signing immediately.\n\ + zonestatus zone [class [view]]\n\ + Display the current status of a zone.\n\ stats Write server statistics to the statistics file.\n\ querylog newstate\n\ Enable / disable query logging.\n\ diff --git a/bin/tests/system/zonechecks/clean.sh b/bin/tests/system/zonechecks/clean.sh index c103c59b92..b5623b1453 100644 --- a/bin/tests/system/zonechecks/clean.sh +++ b/bin/tests/system/zonechecks/clean.sh @@ -14,7 +14,10 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: clean.sh,v 1.6 2007/09/26 03:22:44 marka Exp $ +# $Id: clean.sh,v 1.7 2012/01/31 03:35:39 each Exp $ rm -f *.out rm -f */named.memstats +rm -f */*.db */*.db.signed */K*.key */K*.private */*.jnl */dsset-* +rm -f rndc.out.* +rm -f random.data diff --git a/bin/tests/system/zonechecks/ns1/named.conf b/bin/tests/system/zonechecks/ns1/named.conf new file mode 100644 index 0000000000..26f61b4453 --- /dev/null +++ b/bin/tests/system/zonechecks/ns1/named.conf @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: named.conf,v 1.2 2012/01/31 03:35:40 each Exp $ */ + +// NS1 + +controls { /* empty */ }; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; + dnssec-enable yes; + dnssec-validation yes; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-md5; +}; + +controls { + inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; +}; + +zone "master.example" { + type master; + file "master.db"; + allow-update { any; }; + allow-transfer { any; }; + auto-dnssec maintain; +}; + diff --git a/bin/tests/system/zonechecks/ns2/named.conf b/bin/tests/system/zonechecks/ns2/named.conf new file mode 100644 index 0000000000..aebfbb4a5d --- /dev/null +++ b/bin/tests/system/zonechecks/ns2/named.conf @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: named.conf,v 1.2 2012/01/31 03:35:40 each Exp $ */ + +// NS2 + +controls { /* empty */ }; + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + recursion no; + notify yes; + dnssec-enable yes; + dnssec-validation yes; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-md5; +}; + +controls { + inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; +}; + +zone "master.example" { + type slave; + masters { 10.53.0.1; }; + file "slave.db"; +}; + diff --git a/bin/tests/system/zonechecks/setup.sh b/bin/tests/system/zonechecks/setup.sh new file mode 100644 index 0000000000..b740b3bfa5 --- /dev/null +++ b/bin/tests/system/zonechecks/setup.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# $Id: setup.sh,v 1.2 2012/01/31 03:35:39 each Exp $ + +sh clean.sh + +../../../tools/genrandom 400 random.data +sh ../genzone.sh 1 > ns1/master.db +cd ns1 +touch master.db.signed +echo '$INCLUDE "master.db.signed"' >> master.db +$KEYGEN -r ../random.data -3q master.example > /dev/null 2>&1 +$KEYGEN -r ../random.data -3qfk master.example > /dev/null 2>&1 +$SIGNER -SD -o master.example master.db > /dev/null 2>&1 + diff --git a/bin/tests/system/zonechecks/tests.sh b/bin/tests/system/zonechecks/tests.sh index 8c09abb91a..f41666d9c5 100644 --- a/bin/tests/system/zonechecks/tests.sh +++ b/bin/tests/system/zonechecks/tests.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.6 2009/12/04 22:06:37 tbox Exp $ +# $Id: tests.sh,v 1.7 2012/01/31 03:35:39 each Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -25,13 +25,13 @@ status=0 echo "I: checking that we detect a NS which refers to a CNAME" if $CHECKZONE . cname.db > cname.out 2>&1 then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "is a CNAME" cname.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -39,13 +39,13 @@ fi echo "I: checking that we detect a NS which is below a DNAME" if $CHECKZONE . dname.db > dname.out 2>&1 then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "is below a DNAME" dname.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -53,13 +53,13 @@ fi echo "I: checking that we detect a NS which has no address records (A/AAAA)" if $CHECKZONE . noaddress.db > noaddress.out then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "has no address records" noaddress.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -67,13 +67,13 @@ fi echo "I: checking that we detect a NS which has no records" if $CHECKZONE . nxdomain.db > nxdomain.out then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "has no address records" noaddress.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -81,13 +81,13 @@ fi echo "I: checking that we detect a NS which looks like a A record (fail)" if $CHECKZONE -n fail . a.db > a.out 2>&1 then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "appears to be an address" a.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -99,10 +99,10 @@ then then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi else - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` fi # @@ -111,25 +111,25 @@ if $CHECKZONE -n ignore . a.db > a.out 2>&1 then if grep "appears to be an address" a.out > /dev/null then - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` else : fi else - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` fi # echo "I: checking that we detect a NS which looks like a AAAA record (fail)" if $CHECKZONE -n fail . aaaa.db > aaaa.out 2>&1 then - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` else if grep "appears to be an address" aaaa.out > /dev/null then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi fi @@ -141,10 +141,10 @@ then then : else - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` fi else - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` fi # @@ -153,12 +153,44 @@ if $CHECKZONE -n ignore . aaaa.db > aaaa.out 2>&1 then if grep "appears to be an address" aaaa.out > /dev/null then - echo "I:failed (message)"; status=1 + echo "I:failed (message)"; status=`expr $status + 1` else : fi else - echo "I:failed (status)"; status=1 + echo "I:failed (status)"; status=`expr $status + 1` fi + +# +echo "I: checking 'rdnc zonestatus' output" +ret=0 +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 zonestatus master.example > rndc.out.master 2>&1 +grep "name: master.example" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "type: master" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "files: master.db, master.db.signed" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "serial: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "nodes: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "last loaded: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "secure: yes" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "inline signing: no" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "key maintenance: automatic" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "next key event: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "next resign node: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "next resign time: " rndc.out.master > /dev/null 2>&1 || ret=1 +grep "dynamic: yes" rndc.out.master > /dev/null 2>&1 || ret=1 +grep "frozen: no" rndc.out.master > /dev/null 2>&1 || ret=1 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 zonestatus master.example > rndc.out.slave 2>&1 +grep "name: master.example" rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "type: slave" rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "files: slave.db" rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "serial: " rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "nodes: " rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "next refresh: " rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "expires: " rndc.out.slave > /dev/null 2>&1 || ret=1 +grep "secure: yes" rndc.out.slave > /dev/null 2>&1 || ret=1 + +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index de50e49ad6..4f2e97fc35 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -1311,6 +1311,26 @@ zone "eng.example.com" { + + zonestatus + zone + class + view + + + Displays the current status of the given zone, + including the master file name and any include + files from which it was loaded, when it was most + recently loaded, the current serial number, the + number of nodes, whether the zone supports + dynamic updates, whether the zone is DNSSEC + signed, whether it uses automatic DNSSEC key + management or inline signing, and the scheduled + refresh or expiry times for the zone. + + + + stats diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 4cf34c4008..e931839bc5 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.h,v 1.55 2011/12/09 23:47:05 tbox Exp $ */ +/* $Id: master.h,v 1.56 2012/01/31 03:35:41 each Exp $ */ #ifndef DNS_MASTER_H #define DNS_MASTER_H 1 @@ -103,6 +103,13 @@ typedef struct { /* followed by encoded owner name, and then rdata */ } dns_masterrawrdataset_t; +/* + * Method prototype: a callback to register each include file as + * it is encountered. + */ +typedef void +(*dns_masterincludecb_t)(const char *file, void *arg); + /*** *** Function ***/ @@ -137,6 +144,18 @@ dns_master_loadfile3(const char *master_file, isc_mem_t *mctx, dns_masterformat_t format); +isc_result_t +dns_master_loadfile4(const char *master_file, + dns_name_t *top, + dns_name_t *origin, + dns_rdataclass_t zclass, + unsigned int options, + isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + dns_masterincludecb_t include_cb, + void *include_arg, isc_mem_t *mctx, + dns_masterformat_t format); + isc_result_t dns_master_loadstream(FILE *stream, dns_name_t *top, @@ -200,6 +219,20 @@ dns_master_loadfileinc3(const char *master_file, dns_loadctx_t **ctxp, isc_mem_t *mctx, dns_masterformat_t format); +isc_result_t +dns_master_loadfileinc4(const char *master_file, + dns_name_t *top, + dns_name_t *origin, + dns_rdataclass_t zclass, + unsigned int options, + isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **ctxp, + dns_masterincludecb_t include_cb, void *include_arg, + isc_mem_t *mctx, dns_masterformat_t format); + isc_result_t dns_master_loadstreaminc(FILE *stream, dns_name_t *top, diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 36b445c452..798449a273 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.201 2012/01/25 23:46:49 tbox Exp $ */ +/* $Id: zone.h,v 1.202 2012/01/31 03:35:41 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -2039,4 +2039,37 @@ dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header); */ ISC_LANG_ENDDECLS +isc_result_t +dns_zone_getloadtime(dns_zone_t *zone, isc_time_t *loadtime); +/*% + * Return the time when the zone was last loaded. + */ + +isc_result_t +dns_zone_getrefreshtime(dns_zone_t *zone, isc_time_t *refreshtime); +/*% + * Return the time when the (slave) zone will need to be refreshed. + */ + +isc_result_t +dns_zone_getexpiretime(dns_zone_t *zone, isc_time_t *expiretime); +/*% + * Return the time when the (slave) zone will expire. + */ + +isc_result_t +dns_zone_getrefreshkeytime(dns_zone_t *zone, isc_time_t *refreshkeytime); +/*% + * Return the time of the next scheduled DNSSEC key event. + */ + +int +dns_zone_getincludes(dns_zone_t *zone, char ***includesp); +/*% + * Return the number include files that were encountered + * during load. If the number is greater than zero, 'includesp' + * will point to an array containing the filenames. + */ + + #endif /* DNS_ZONE_H */ diff --git a/lib/dns/master.c b/lib/dns/master.c index a3e5b4eb4b..d942ec3b60 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.c,v 1.181 2011/12/08 16:07:20 each Exp $ */ +/* $Id: master.c,v 1.182 2012/01/31 03:35:40 each Exp $ */ /*! \file */ @@ -145,6 +145,9 @@ struct dns_loadctx { isc_uint32_t references; dns_incctx_t *inc; isc_uint32_t resign; + + dns_masterincludecb_t include_cb; + void *include_arg; }; struct dns_incctx { @@ -512,8 +515,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options, isc_uint32_t resign, dns_name_t *top, dns_rdataclass_t zclass, dns_name_t *origin, dns_rdatacallbacks_t *callbacks, isc_task_t *task, - dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex, - dns_loadctx_t **lctxp) + dns_loaddonefunc_t done, void *done_arg, + dns_masterincludecb_t include_cb, void *include_arg, + isc_lex_t *lex, dns_loadctx_t **lctxp) { dns_loadctx_t *lctx; isc_result_t result; @@ -588,6 +592,8 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, lctx->zclass = zclass; lctx->resign = resign; lctx->result = ISC_R_SUCCESS; + lctx->include_cb = include_cb; + lctx->include_arg = include_arg; dns_fixedname_init(&lctx->fixed_top); lctx->top = dns_fixedname_name(&lctx->fixed_top); @@ -2044,6 +2050,9 @@ pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) { goto cleanup; new->parent = ictx; lctx->inc = new; + + if (lctx->include_cb != NULL) + lctx->include_cb(master_file, lctx->include_arg); return (ISC_R_SUCCESS); cleanup: @@ -2401,8 +2410,9 @@ dns_master_loadfile(const char *master_file, dns_name_t *top, dns_rdataclass_t zclass, unsigned int options, dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx) { - return (dns_master_loadfile3(master_file, top, origin, zclass, options, - 0, callbacks, mctx, dns_masterformat_text)); + return (dns_master_loadfile4(master_file, top, origin, zclass, options, + 0, callbacks, NULL, NULL, mctx, + dns_masterformat_text)); } isc_result_t @@ -2412,8 +2422,8 @@ dns_master_loadfile2(const char *master_file, dns_name_t *top, dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx, dns_masterformat_t format) { - return (dns_master_loadfile3(master_file, top, origin, zclass, options, - 0, callbacks, mctx, format)); + return (dns_master_loadfile4(master_file, top, origin, zclass, options, + 0, callbacks, NULL, NULL, mctx, format)); } isc_result_t @@ -2422,13 +2432,26 @@ dns_master_loadfile3(const char *master_file, dns_name_t *top, unsigned int options, isc_uint32_t resign, dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx, dns_masterformat_t format) +{ + return (dns_master_loadfile4(master_file, top, origin, zclass, options, + resign, callbacks, NULL, NULL, mctx, + format)); +} + +isc_result_t +dns_master_loadfile4(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + dns_masterincludecb_t include_cb, void *include_arg, + isc_mem_t *mctx, dns_masterformat_t format) { dns_loadctx_t *lctx = NULL; isc_result_t result; result = loadctx_create(format, mctx, options, resign, top, zclass, - origin, callbacks, NULL, NULL, NULL, NULL, - &lctx); + origin, callbacks, NULL, NULL, NULL, + include_cb, include_arg, NULL, &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2451,9 +2474,9 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top, isc_task_t *task, dns_loaddonefunc_t done, void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx) { - return (dns_master_loadfileinc3(master_file, top, origin, zclass, + return (dns_master_loadfileinc4(master_file, top, origin, zclass, options, 0, callbacks, task, done, - done_arg, lctxp, mctx, + done_arg, lctxp, NULL, NULL, mctx, dns_masterformat_text)); } @@ -2465,9 +2488,10 @@ dns_master_loadfileinc2(const char *master_file, dns_name_t *top, void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx, dns_masterformat_t format) { - return (dns_master_loadfileinc3(master_file, top, origin, zclass, + return (dns_master_loadfileinc4(master_file, top, origin, zclass, options, 0, callbacks, task, done, - done_arg, lctxp, mctx, format)); + done_arg, lctxp, NULL, NULL, mctx, + format)); } isc_result_t @@ -2478,6 +2502,22 @@ dns_master_loadfileinc3(const char *master_file, dns_name_t *top, dns_loaddonefunc_t done, void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx, dns_masterformat_t format) +{ + return (dns_master_loadfileinc4(master_file, top, origin, zclass, + options, resign, callbacks, task, + done, done_arg, lctxp, NULL, NULL, + mctx, format)); +} + +isc_result_t +dns_master_loadfileinc4(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + isc_task_t *task, dns_loaddonefunc_t done, + void *done_arg, dns_loadctx_t **lctxp, + dns_masterincludecb_t include_cb, void *include_arg, + isc_mem_t *mctx, dns_masterformat_t format) { dns_loadctx_t *lctx = NULL; isc_result_t result; @@ -2486,8 +2526,8 @@ dns_master_loadfileinc3(const char *master_file, dns_name_t *top, REQUIRE(done != NULL); result = loadctx_create(format, mctx, options, resign, top, zclass, - origin, callbacks, task, done, done_arg, NULL, - &lctx); + origin, callbacks, task, done, done_arg, + include_cb, include_arg, NULL, &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2518,7 +2558,7 @@ dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, - NULL, &lctx); + NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) goto cleanup; @@ -2551,7 +2591,7 @@ dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, - done_arg, NULL, &lctx); + done_arg, NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) goto cleanup; @@ -2584,7 +2624,7 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, - NULL, &lctx); + NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2617,7 +2657,7 @@ dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, - done_arg, NULL, &lctx); + done_arg, NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2649,7 +2689,7 @@ dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, - lex, &lctx); + NULL, NULL, lex, &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2677,7 +2717,7 @@ dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top, result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, - done_arg, lex, &lctx); + done_arg, NULL, NULL, lex, &lctx); if (result != ISC_R_SUCCESS) return (result); diff --git a/lib/dns/tests/master_test.c b/lib/dns/tests/master_test.c index 82d2efd481..6a7937b8ed 100644 --- a/lib/dns/tests/master_test.c +++ b/lib/dns/tests/master_test.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master_test.c,v 1.7 2011/12/08 16:07:22 each Exp $ */ +/* $Id: master_test.c,v 1.8 2012/01/31 03:35:41 each Exp $ */ /*! \file */ @@ -47,6 +47,10 @@ static dns_masterrawheader_t header; static isc_boolean_t headerset; +dns_name_t dns_origin; +dns_rdatacallbacks_t callbacks; +char *include_file = NULL; + static isc_result_t add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset); @@ -74,16 +78,14 @@ rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *h) { headerset = ISC_TRUE; } -static int -test_master(const char *testfile, dns_masterformat_t format) { +static isc_result_t +setup_master() { isc_result_t result; int len; char origin[sizeof(TEST_ORIGIN)]; - dns_name_t dns_origin; isc_buffer_t source; isc_buffer_t target; unsigned char name_buf[BUFLEN]; - dns_rdatacallbacks_t callbacks; strcpy(origin, TEST_ORIGIN); len = strlen(origin); @@ -103,6 +105,13 @@ test_master(const char *testfile, dns_masterformat_t format) { callbacks.add = add_callback; callbacks.rawdata = rawdata_callback; callbacks.zone = NULL; + + return (result); +} + +static isc_result_t +test_master(const char *testfile, dns_masterformat_t format) { + isc_result_t result; headerset = ISC_FALSE; result = dns_master_loadfile2(testfile, &dns_origin, &dns_origin, dns_rdataclass_in, ISC_TRUE, @@ -110,6 +119,12 @@ test_master(const char *testfile, dns_masterformat_t format) { return (result); } +static void +include_callback(const char *filename, void *arg) { + char **argp = (char **) arg; + *argp = isc_mem_strdup(mctx, filename); +} + /* * Individual unit tests */ @@ -128,6 +143,7 @@ ATF_TC_BODY(load, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master1.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -151,6 +167,7 @@ ATF_TC_BODY(unexpected, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master2.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_UNEXPECTEDEND); @@ -174,6 +191,7 @@ ATF_TC_BODY(noowner, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master3.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, DNS_R_NOOWNER); @@ -198,6 +216,7 @@ ATF_TC_BODY(nottl, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master4.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -221,6 +240,7 @@ ATF_TC_BODY(badclass, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master5.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, DNS_R_BADCLASS); @@ -242,6 +262,7 @@ ATF_TC_BODY(dnskey, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master6.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -264,6 +285,7 @@ ATF_TC_BODY(dnsnokey, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master7.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -285,6 +307,7 @@ ATF_TC_BODY(include, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master8.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE); @@ -292,6 +315,37 @@ ATF_TC_BODY(include, tc) { dns_test_end(); } +/* Include file list test */ +ATF_TC(master_includelist); +ATF_TC_HEAD(master_includelist, tc) { + atf_tc_set_md_var(tc, "descr", "dns_master_loadfile4() returns " + "names of included file"); +} +ATF_TC_BODY(master_includelist, tc) { + isc_result_t result; + char *filename = NULL; + + UNUSED(tc); + + result = dns_test_begin(NULL, ISC_FALSE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + setup_master(); + result = dns_master_loadfile4("testdata/master/master8.data", + &dns_origin, &dns_origin, + dns_rdataclass_in, 0, ISC_TRUE, + &callbacks, include_callback, + &filename, mctx, dns_masterformat_text); + ATF_CHECK_EQ(result, DNS_R_SEENINCLUDE); + ATF_CHECK(filename != NULL); + if (filename != NULL) { + ATF_CHECK_STREQ(filename, "testdata/master/master7.data"); + isc_mem_free(mctx, filename); + } + + dns_test_end(); +} + /* Include failure test */ ATF_TC(includefail); ATF_TC_HEAD(includefail, tc) { @@ -306,6 +360,7 @@ ATF_TC_BODY(includefail, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master9.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, DNS_R_BADCLASS); @@ -328,6 +383,7 @@ ATF_TC_BODY(blanklines, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master10.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -349,6 +405,7 @@ ATF_TC_BODY(leadingzero, tc) { result = dns_test_begin(NULL, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("testdata/master/master11.data", dns_masterformat_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); @@ -415,6 +472,7 @@ ATF_TC_BODY(loadraw, tc) { ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* Raw format version 0 */ + setup_master(); result = test_master("testdata/master/master12.data", dns_masterformat_raw); ATF_CHECK_STREQ(isc_result_totext(result), "success"); @@ -422,6 +480,7 @@ ATF_TC_BODY(loadraw, tc) { ATF_CHECK_EQ(header.flags, 0); /* Raw format version 1, no source serial */ + setup_master(); result = test_master("testdata/master/master13.data", dns_masterformat_raw); ATF_CHECK_STREQ(isc_result_totext(result), "success"); @@ -429,6 +488,7 @@ ATF_TC_BODY(loadraw, tc) { ATF_CHECK_EQ(header.flags, 0); /* Raw format version 1, source serial == 2011120101 */ + setup_master(); result = test_master("testdata/master/master14.data", dns_masterformat_raw); ATF_CHECK_STREQ(isc_result_totext(result), "success"); @@ -485,6 +545,7 @@ ATF_TC_BODY(dumpraw, tc) { dns_masterformat_raw); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("test.dump", dns_masterformat_raw); ATF_CHECK_STREQ(isc_result_totext(result), "success"); ATF_CHECK(headerset); @@ -500,6 +561,7 @@ ATF_TC_BODY(dumpraw, tc) { dns_masterformat_raw, &header); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + setup_master(); result = test_master("test.dump", dns_masterformat_raw); ATF_CHECK_STREQ(isc_result_totext(result), "success"); ATF_CHECK(headerset); @@ -524,6 +586,7 @@ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, dnskey); ATF_TP_ADD_TC(tp, dnsnokey); ATF_TP_ADD_TC(tp, include); + ATF_TP_ADD_TC(tp, master_includelist); ATF_TP_ADD_TC(tp, includefail); ATF_TP_ADD_TC(tp, blanklines); ATF_TP_ADD_TC(tp, leadingzero); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index b4039bdb85..6459f8e2df 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.668 2012/01/31 01:13:10 each Exp $ */ +/* $Id: zone.c,v 1.669 2012/01/31 03:35:40 each Exp $ */ /*! \file */ @@ -150,6 +150,7 @@ typedef struct dns_nsec3chain dns_nsec3chain_t; typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t; typedef struct dns_keyfetch dns_keyfetch_t; typedef struct dns_asyncload dns_asyncload_t; +typedef struct dns_include dns_include_t; #define DNS_ZONE_CHECKLOCK #ifdef DNS_ZONE_CHECKLOCK @@ -203,6 +204,8 @@ struct dns_zone { unsigned int irefs; dns_name_t origin; char *masterfile; + ISC_LIST(dns_include_t) includes; /* Include files */ + unsigned int nincludes; dns_masterformat_t masterformat; char *journal; isc_int32_t journalsize; @@ -617,6 +620,14 @@ struct dns_asyncload { void *loaded_arg; }; +/*% + * Reference to an include file encountered during loading + */ +struct dns_include { + char *name; + ISC_LINK(dns_include_t) link; +}; + #define HOUR 3600 #define DAY (24*HOUR) #define MONTH (30*DAY) @@ -805,6 +816,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->strrdclass = NULL; zone->strviewname = NULL; zone->masterfile = NULL; + ISC_LIST_INIT(zone->includes); + zone->nincludes = 0; zone->masterformat = dns_masterformat_none; zone->keydirectory = NULL; zone->journalsize = -1; @@ -942,6 +955,7 @@ zone_free(dns_zone_t *zone) { isc_mem_t *mctx = NULL; dns_signing_t *signing; dns_nsec3chain_t *nsec3chain; + dns_include_t *include; REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(isc_refcount_current(&zone->erefs) == 0); @@ -982,6 +996,13 @@ zone_free(dns_zone_t *zone) { dns_dbiterator_destroy(&nsec3chain->dbiterator); isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); } + for (include = ISC_LIST_HEAD(zone->includes); + include != NULL; + include = ISC_LIST_HEAD(zone->includes)) { + ISC_LIST_UNLINK(zone->includes, include, link); + isc_mem_free(zone->mctx, include->name); + isc_mem_put(zone->mctx, include, sizeof *include); + } if (zone->masterfile != NULL) isc_mem_free(zone->mctx, zone->masterfile); zone->masterfile = NULL; @@ -1810,6 +1831,25 @@ get_master_options(dns_zone_t *zone) { return (options); } +static void +zone_registerinclude(const char *filename, void *arg) { + dns_zone_t *zone = (dns_zone_t *) arg; + dns_include_t *inc = NULL; + + REQUIRE(DNS_ZONE_VALID(zone)); + + if (filename == NULL) + return; + +fprintf(stderr, "register callback: %s\n", filename); + inc = isc_mem_get(zone->mctx, sizeof(dns_include_t)); + inc->name = isc_mem_strdup(zone->mctx, filename); + ISC_LINK_INIT(inc, link); + + ISC_LIST_APPEND(zone->includes, inc, link); + zone->nincludes++; +} + static void zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { dns_load_t *load = event->ev_arg; @@ -1826,14 +1866,16 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { options = get_master_options(load->zone); - result = dns_master_loadfileinc3(load->zone->masterfile, + result = dns_master_loadfileinc4(load->zone->masterfile, dns_db_origin(load->db), dns_db_origin(load->db), load->zone->rdclass, options, load->zone->sigresigninginterval, &load->callbacks, task, zone_loaddone, load, - &load->zone->lctx, load->zone->mctx, + &load->zone->lctx, + zone_registerinclude, + load->zone, load->zone->mctx, load->zone->masterformat); if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE && result != DNS_R_SEENINCLUDE) @@ -1983,11 +2025,13 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { zone_idetach(&callbacks.zone); return (result); } - result = dns_master_loadfile3(zone->masterfile, + result = dns_master_loadfile4(zone->masterfile, &zone->origin, &zone->origin, zone->rdclass, options, zone->sigresigninginterval, - &callbacks, zone->mctx, + &callbacks, + zone_registerinclude, + zone, zone->mctx, zone->masterformat); tresult = dns_db_endload(db, &callbacks.add_private); if (result == ISC_R_SUCCESS) @@ -16211,3 +16255,69 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags, UNLOCK_ZONE(zone); return (result); } + +isc_result_t +dns_zone_getloadtime(dns_zone_t *zone, isc_time_t *loadtime) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(loadtime != NULL); + LOCK_ZONE(zone); + *loadtime = zone->loadtime; + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_zone_getexpiretime(dns_zone_t *zone, isc_time_t *expiretime) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(expiretime != NULL); + LOCK_ZONE(zone); + *expiretime = zone->expiretime; + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_zone_getrefreshtime(dns_zone_t *zone, isc_time_t *refreshtime) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(refreshtime != NULL); + LOCK_ZONE(zone); + *refreshtime = zone->refreshtime; + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_zone_getrefreshkeytime(dns_zone_t *zone, isc_time_t *refreshkeytime) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(refreshkeytime != NULL); + LOCK_ZONE(zone); + *refreshkeytime = zone->refreshkeytime; + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); +} + +int +dns_zone_getincludes(dns_zone_t *zone, char ***includesp) { + dns_include_t *include; + char **array = NULL; + int n = 0; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(includesp != NULL && *includesp == NULL); + + LOCK_ZONE(zone); + if (zone->nincludes == 0) + goto done; + + array = isc_mem_allocate(zone->mctx, sizeof(char *) * n); + for (include = ISC_LIST_HEAD(zone->includes); + include != NULL; + include = ISC_LIST_NEXT(include, link)) { + array[n++] = include->name; + } + *includesp = array; + + done: + UNLOCK_ZONE(zone); + return (n); +}