diff options
Diffstat (limited to 'contrib/bind9/bin/named')
47 files changed, 6553 insertions, 1367 deletions
diff --git a/contrib/bind9/bin/named/Makefile.in b/contrib/bind9/bin/named/Makefile.in index ee7613435759..a3dbb3802dc9 100644 --- a/contrib/bind9/bin/named/Makefile.in +++ b/contrib/bind9/bin/named/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2002 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.101 2008-09-23 17:25:47 jinmei Exp $ +# $Id: Makefile.in,v 1.114 2010-12-22 09:00:40 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -43,9 +43,9 @@ DLZDRIVER_LIBS = @DLZ_DRIVER_LIBS@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \ ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ - ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ -CDEFINES = @USE_DLZ@ +CDEFINES = @USE_DLZ@ @USE_PKCS11@ @USE_OPENSSL@ CWARNINGS = @@ -53,6 +53,7 @@ DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ ISCCCLIBS = ../../lib/isccc/libisccc.@A@ ISCLIBS = ../../lib/isc/libisc.@A@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ LWRESLIBS = ../../lib/lwres/liblwres.@A@ BIND9LIBS = ../../lib/bind9/libbind9.@A@ @@ -70,6 +71,10 @@ LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \ ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ +NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \ + ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ + SUBDIRS = unix TARGETS = named@EXEEXT@ lwresd@EXEEXT@ @@ -86,10 +91,12 @@ OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \ UOBJS = unix/os.@O@ +SYMOBJS = symtbl.@O@ + SRCS = builtin.c client.c config.c control.c \ controlconf.c interfacemgr.c \ listenlist.c log.c logconf.c main.c notify.c \ - query.c server.c sortlist.c statschannel.c \ + query.c server.c sortlist.c statschannel.c symtbl.c symtbl-empty.c \ tkeyconf.c tsigconf.c update.c xfrout.c \ zoneconf.c \ lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ @@ -111,15 +118,20 @@ main.@O@: main.c -DNS_LOCALSTATEDIR=\"${localstatedir}\" \ -DNS_SYSCONFDIR=\"${sysconfdir}\" -c ${srcdir}/main.c -config.@O@: config.c +bind.keys.h: ${top_srcdir}/bind.keys ${srcdir}/bindkeys.pl + ${PERL} ${srcdir}/bindkeys.pl < ${top_srcdir}/bind.keys > $@ + +config.@O@: config.c bind.keys.h ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ -DVERSION=\"${VERSION}\" \ -DNS_LOCALSTATEDIR=\"${localstatedir}\" \ + -DNS_SYSCONFDIR=\"${sysconfdir}\" \ -c ${srcdir}/config.c named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} - ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ - ${OBJS} ${UOBJS} ${LIBS} + export MAKE_SYMTABLE="yes"; \ + export BASEOBJS="${OBJS} ${UOBJS}"; \ + ${FINALBUILDCMD} lwresd@EXEEXT@: named@EXEEXT@ rm -f lwresd@EXEEXT@ @@ -133,7 +145,10 @@ docclean manclean maintainer-clean:: clean distclean maintainer-clean:: rm -f ${TARGETS} ${OBJS} -bind9.xsl.h: bind9.xsl convertxsl.pl +maintainer-clean:: + rm -f bind.keys.h + +bind9.xsl.h: bind9.xsl ${srcdir}/convertxsl.pl ${PERL} ${srcdir}/convertxsl.pl < ${srcdir}/bind9.xsl > bind9.xsl.h depend: bind9.xsl.h diff --git a/contrib/bind9/bin/named/bind.keys.h b/contrib/bind9/bin/named/bind.keys.h new file mode 100644 index 000000000000..0177214159e7 --- /dev/null +++ b/contrib/bind9/bin/named/bind.keys.h @@ -0,0 +1,99 @@ +/* + * Generated by bindkeys.pl 1.7 2011-01-04 23:47:13 tbox Exp + * From bind.keys 1.7 2011-01-03 23:45:07 each Exp + */ +#define TRUSTED_KEYS "\ +# The bind.keys file is used to override the built-in DNSSEC trust anchors\n\ +# which are included as part of BIND 9. As of the current release, the only\n\ +# trust anchors it contains are those for the DNS root zone (\".\"), and for\n\ +# the ISC DNSSEC Lookaside Validation zone (\"dlv.isc.org\"). Trust anchors\n\ +# for any other zones MUST be configured elsewhere; if they are configured\n\ +# here, they will not be recognized or used by named.\n\ +#\n\ +# The built-in trust anchors are provided for convenience of configuration.\n\ +# They are not activated within named.conf unless specifically switched on.\n\ +# To use the built-in root key, set \"dnssec-validation auto;\" in\n\ +# named.conf options. To use the built-in DLV key, set\n\ +# \"dnssec-lookaside auto;\". Without these options being set,\n\ +# the keys in this file are ignored.\n\ +#\n\ +# This file is NOT expected to be user-configured.\n\ +#\n\ +# These keys are current as of January 2011. If any key fails to\n\ +# initialize correctly, it may have expired. In that event you should\n\ +# replace this file with a current version. The latest version of\n\ +# bind.keys can always be obtained from ISC at https://www.isc.org/bind-keys.\n\ +\n\ +trusted-keys {\n\ + # ISC DLV: See https://www.isc.org/solutions/dlv for details.\n\ + # NOTE: This key is activated by setting \"dnssec-lookaside auto;\"\n\ + # in named.conf.\n\ + dlv.isc.org. 257 3 5 \"BEAAAAPHMu/5onzrEE7z1egmhg/WPO0+juoZrW3euWEn4MxDCE1+lLy2\n\ + brhQv5rN32RKtMzX6Mj70jdzeND4XknW58dnJNPCxn8+jAGl2FZLK8t+\n\ + 1uq4W+nnA3qO2+DL+k6BD4mewMLbIYFwe0PG73Te9fZ2kJb56dhgMde5\n\ + ymX4BI/oQ+cAK50/xvJv00Frf8kw6ucMTwFlgPe+jnGxPPEmHAte/URk\n\ + Y62ZfkLoBAADLHQ9IrS2tryAe7mbBZVcOwIeU/Rw/mRx/vwwMCTgNboM\n\ + QKtUdvNXDrYJDSHZws3xiRXF1Rf+al9UmZfSav/4NWLKjHzpT59k/VSt\n\ + TDN0YUuWrBNh\";\n\ +\n\ + # ROOT KEY: See https://data.iana.org/root-anchors/root-anchors.xml\n\ + # for current trust anchor information.\n\ + # NOTE: This key is activated by setting \"dnssec-validation auto;\"\n\ + # in named.conf.\n\ + . 257 3 8 \"AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF\n\ + FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX\n\ + bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD\n\ + X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz\n\ + W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS\n\ + Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq\n\ + QxA+Uk1ihz0=\";\n\ +};\n\ +" + +#define MANAGED_KEYS "\ +# The bind.keys file is used to override the built-in DNSSEC trust anchors\n\ +# which are included as part of BIND 9. As of the current release, the only\n\ +# trust anchors it contains are those for the DNS root zone (\".\"), and for\n\ +# the ISC DNSSEC Lookaside Validation zone (\"dlv.isc.org\"). Trust anchors\n\ +# for any other zones MUST be configured elsewhere; if they are configured\n\ +# here, they will not be recognized or used by named.\n\ +#\n\ +# The built-in trust anchors are provided for convenience of configuration.\n\ +# They are not activated within named.conf unless specifically switched on.\n\ +# To use the built-in root key, set \"dnssec-validation auto;\" in\n\ +# named.conf options. To use the built-in DLV key, set\n\ +# \"dnssec-lookaside auto;\". Without these options being set,\n\ +# the keys in this file are ignored.\n\ +#\n\ +# This file is NOT expected to be user-configured.\n\ +#\n\ +# These keys are current as of January 2011. If any key fails to\n\ +# initialize correctly, it may have expired. In that event you should\n\ +# replace this file with a current version. The latest version of\n\ +# bind.keys can always be obtained from ISC at https://www.isc.org/bind-keys.\n\ +\n\ +managed-keys {\n\ + # ISC DLV: See https://www.isc.org/solutions/dlv for details.\n\ + # NOTE: This key is activated by setting \"dnssec-lookaside auto;\"\n\ + # in named.conf.\n\ + dlv.isc.org. initial-key 257 3 5 \"BEAAAAPHMu/5onzrEE7z1egmhg/WPO0+juoZrW3euWEn4MxDCE1+lLy2\n\ + brhQv5rN32RKtMzX6Mj70jdzeND4XknW58dnJNPCxn8+jAGl2FZLK8t+\n\ + 1uq4W+nnA3qO2+DL+k6BD4mewMLbIYFwe0PG73Te9fZ2kJb56dhgMde5\n\ + ymX4BI/oQ+cAK50/xvJv00Frf8kw6ucMTwFlgPe+jnGxPPEmHAte/URk\n\ + Y62ZfkLoBAADLHQ9IrS2tryAe7mbBZVcOwIeU/Rw/mRx/vwwMCTgNboM\n\ + QKtUdvNXDrYJDSHZws3xiRXF1Rf+al9UmZfSav/4NWLKjHzpT59k/VSt\n\ + TDN0YUuWrBNh\";\n\ +\n\ + # ROOT KEY: See https://data.iana.org/root-anchors/root-anchors.xml\n\ + # for current trust anchor information.\n\ + # NOTE: This key is activated by setting \"dnssec-validation auto;\"\n\ + # in named.conf.\n\ + . initial-key 257 3 8 \"AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF\n\ + FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX\n\ + bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD\n\ + X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz\n\ + W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS\n\ + Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq\n\ + QxA+Uk1ihz0=\";\n\ +};\n\ +" diff --git a/contrib/bind9/bin/named/bind9.xsl b/contrib/bind9/bin/named/bind9.xsl index 71d2eba108d2..5913c1cc2000 100644 --- a/contrib/bind9/bin/named/bind9.xsl +++ b/contrib/bind9/bin/named/bind9.xsl @@ -15,7 +15,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: bind9.xsl,v 1.19.82.2 2009-01-29 23:47:43 tbox Exp $ --> +<!-- $Id: bind9.xsl,v 1.21 2009-01-27 23:47:54 tbox Exp $ --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" diff --git a/contrib/bind9/bin/named/bind9.xsl.h b/contrib/bind9/bin/named/bind9.xsl.h index d68675131eb9..b6f1f5491b95 100644 --- a/contrib/bind9/bin/named/bind9.xsl.h +++ b/contrib/bind9/bin/named/bind9.xsl.h @@ -1,6 +1,6 @@ /* * Generated by convertxsl.pl 1.14 2008-07-17 23:43:26 jinmei Exp - * From bind9.xsl 1.19.82.2 2009-01-29 23:47:43 tbox Exp + * From bind9.xsl 1.21 2009-01-27 23:47:54 tbox Exp */ static char xslmsg[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" @@ -20,7 +20,7 @@ static char xslmsg[] = " - PERFORMANCE OF THIS SOFTWARE.\n" "-->\n" "\n" - "<!-- \045Id: bind9.xsl,v 1.19.82.2 2009-01-29 23:47:43 tbox Exp \045 -->\n" + "<!-- \045Id: bind9.xsl,v 1.21 2009-01-27 23:47:54 tbox Exp \045 -->\n" "\n" "<xsl:stylesheet version=\"1.0\"\n" " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" diff --git a/contrib/bind9/bin/named/builtin.c b/contrib/bind9/bin/named/builtin.c index 60cb634fabd3..d7730e7afed0 100644 --- a/contrib/bind9/bin/named/builtin.c +++ b/contrib/bind9/bin/named/builtin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: builtin.c,v 1.12.334.3 2010-08-03 23:45:47 tbox Exp $ */ +/* $Id: builtin.c,v 1.20 2011-01-07 23:47:07 tbox Exp $ */ /*! \file * \brief @@ -47,6 +47,7 @@ static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup); static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup); static isc_result_t do_id_lookup(dns_sdblookup_t *lookup); static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup); +static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup); /* * We can't use function pointers as the db_data directly @@ -65,9 +66,179 @@ static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL }; static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL }; static builtin_t id_builtin = { do_id_lookup, NULL, NULL }; static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL }; +static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL }; static dns_sdbimplementation_t *builtin_impl; +static const char hex[] = "0123456789abcdef"; +static const char HEX[] = "0123456789ABCDEF"; + +static isc_result_t +dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) { + size_t zlen, nlen, j; + const char *s; + unsigned char v[16]; + unsigned int i; + char reverse[sizeof("123.123.123.123.in-addr.arpa.")]; + + /* + * The sum the length of the relative name and the length of the zone + * name for a IPv6 reverse lookup comes to 71. + * + * The reverse of 2001::10.0.0.1 (dns64 2001::/96) has a zone of + * "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2.ip6.arpa" + * and a name of "1.0.0.0.0.0.a.0". The sum of the lengths of these + * two strings is 71. + * + * The minimum length for a ip6.arpa zone name is 8. + * + * The length of name should always be odd as we are expecting + * a series of nibbles. + */ + zlen = strlen(zone); + nlen = strlen(name); + if ((zlen + nlen) > 71U || zlen < 8U || (nlen % 2) != 1U) + return (ISC_R_NOTFOUND); + + /* + * We assume the zone name is well formed. + */ + + /* + * XXXMPA We could check the dns64 suffix here if we need to. + */ + /* + * Check that name is a series of nibbles. + * Compute the byte values that correspond to the nibbles as we go. + * + * Shift the final result 4 bits, by setting 'i' to 1, if we if we + * have a odd number of nibbles so that "must be zero" tests below + * are byte aligned and we correctly return ISC_R_NOTFOUND or + * ISC_R_SUCCESS. We will not generate a CNAME in this case. + */ + i = (nlen % 4) == 1U ? 1 : 0; + j = nlen; + memset(v, 0, sizeof(v)); + while (j >= 1U) { + INSIST((i/2) < sizeof(v)); + if (j > 1U && name[1] != '.') + return (ISC_R_NOTFOUND); + v[i/2] >>= 4; + if ((s = strchr(hex, name[0])) != NULL) + v[i/2] |= (s - hex) << 4; + else if ((s = strchr(HEX, name[0])) != NULL) + v[i/2] |= (s - HEX) << 4; + else + return (ISC_R_NOTFOUND); + if (j > 1U) + j -= 2; + else + j -= 1; + name += 2; + i++; + } + + /* + * If we get here then we know name only consisted of nibbles. + * Now we need to determine if the name exists or not and whether + * it corresponds to a empty node in the zone or there should be + * a CNAME. + */ + switch (zlen) { + case 24: /* prefix len 32 */ + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[8], v[9], v[10], v[11]); + break; + case 28: /* prefix len 40 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 11U && v[nlen/4 - 3] != 0) + return (ISC_R_NOTFOUND); + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[6], v[8], v[9], v[10]); + break; + case 32: /* prefix len 48 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 7U && v[nlen/4 - 2] != 0) + return (ISC_R_NOTFOUND); + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[5], v[6], v[8], v[9]); + break; + case 36: /* prefix len 56 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (nlen > 3U && v[nlen/4 - 1] != 0) + return (ISC_R_NOTFOUND); + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[4], v[5], v[6], v[8]); + break; + case 40: /* prefix len 64 */ + /* + * The nibbles that map to this byte must be zero for 'name' + * to exist in the zone. + */ + if (v[nlen/4] != 0) + return (ISC_R_NOTFOUND); + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[3], v[4], v[5], v[6]); + break; + case 56: /* prefix len 96 */ + /* + * If the total length is not 71 then this is a empty node + * so return success. + */ + if (nlen + zlen != 71U) + return (ISC_R_SUCCESS); + snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.", + v[0], v[1], v[2], v[3]); + break; + default: + /* + * This should never be reached unless someone adds a + * zone declaration with this internal type to named.conf. + */ + return (ISC_R_NOTFOUND); + } + return (dns_sdb_putrr(lookup, "CNAME", 600, reverse)); +} + static isc_result_t builtin_lookup(const char *zone, const char *name, void *dbdata, dns_sdblookup_t *lookup) @@ -78,6 +249,8 @@ builtin_lookup(const char *zone, const char *name, void *dbdata, if (strcmp(name, "@") == 0) return (b->do_lookup(lookup)); + else if (b->do_lookup == do_dns64_lookup) + return (dns64_cname(zone, name, lookup)); else return (ISC_R_NOTFOUND); } @@ -132,11 +305,13 @@ do_authors_lookup(dns_sdblookup_t *lookup) { "Michael Graff", "Andreas Gustafsson", "Bob Halley", + "Evan Hunt", "JINMEI Tatuya", "David Lawrence", "Danny Mayer", "Damien Neil", "Matt Nelson", + "Jeremy C. Reed", "Michael Sawyer", "Brian Wellington", NULL @@ -174,6 +349,12 @@ do_id_lookup(dns_sdblookup_t *lookup) { } static isc_result_t +do_dns64_lookup(dns_sdblookup_t *lookup) { + UNUSED(lookup); + return (ISC_R_SUCCESS); +} + +static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup) { UNUSED(lookup); @@ -220,7 +401,7 @@ builtin_create(const char *zone, int argc, char **argv, UNUSED(zone); UNUSED(driverdata); - if (strcmp(argv[0], "empty") == 0) { + if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) { if (argc != 3) return (DNS_R_SYNTAX); } else if (argc != 1) @@ -234,7 +415,8 @@ builtin_create(const char *zone, int argc, char **argv, *dbdata = &authors_builtin; else if (strcmp(argv[0], "id") == 0) *dbdata = &id_builtin; - else if (strcmp(argv[0], "empty") == 0) { + else if (strcmp(argv[0], "empty") == 0 || + strcmp(argv[0], "dns64") == 0) { builtin_t *empty; char *server; char *contact; @@ -246,7 +428,10 @@ builtin_create(const char *zone, int argc, char **argv, server = isc_mem_strdup(ns_g_mctx, argv[1]); contact = isc_mem_strdup(ns_g_mctx, argv[2]); if (empty == NULL || server == NULL || contact == NULL) { - *dbdata = &empty_builtin; + if (strcmp(argv[0], "empty") == 0) + *dbdata = &empty_builtin; + else + *dbdata = &dns64_builtin; if (server != NULL) isc_mem_free(ns_g_mctx, server); if (contact != NULL) @@ -254,7 +439,12 @@ builtin_create(const char *zone, int argc, char **argv, if (empty != NULL) isc_mem_put(ns_g_mctx, empty, sizeof (*empty)); } else { - memcpy(empty, &empty_builtin, sizeof (empty_builtin)); + if (strcmp(argv[0], "empty") == 0) + memcpy(empty, &empty_builtin, + sizeof (empty_builtin)); + else + memcpy(empty, &dns64_builtin, + sizeof (empty_builtin)); empty->server = server; empty->contact = contact; *dbdata = empty; @@ -276,7 +466,7 @@ builtin_destroy(const char *zone, void *driverdata, void **dbdata) { */ if (*dbdata == &version_builtin || *dbdata == &hostname_builtin || *dbdata == &authors_builtin || *dbdata == &id_builtin || - *dbdata == &empty_builtin) + *dbdata == &empty_builtin || *dbdata == &dns64_builtin) return; isc_mem_free(ns_g_mctx, b->server); @@ -306,3 +496,4 @@ void ns_builtin_deinit(void) { dns_sdb_unregister(&builtin_impl); } + diff --git a/contrib/bind9/bin/named/client.c b/contrib/bind9/bin/named/client.c index 6236d27f28a0..bc9cc878adbc 100644 --- a/contrib/bind9/bin/named/client.c +++ b/contrib/bind9/bin/named/client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.259.12.5 2010-09-24 08:30:27 tbox Exp $ */ +/* $Id: client.c,v 1.271 2011-01-11 23:47:12 tbox Exp $ */ #include <config.h> @@ -918,7 +918,7 @@ ns_client_send(ns_client_t *client) { dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; unsigned char sendbuf[SEND_BUFFER_SIZE]; - unsigned int dnssec_opts; + unsigned int render_opts; unsigned int preferred_glue; isc_boolean_t opt_included = ISC_FALSE; @@ -930,10 +930,21 @@ ns_client_send(ns_client_t *client) { client->message->flags |= DNS_MESSAGEFLAG_RA; if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) - dnssec_opts = 0; + render_opts = 0; else - dnssec_opts = DNS_MESSAGERENDER_OMITDNSSEC; - + render_opts = DNS_MESSAGERENDER_OMITDNSSEC; +#ifdef ALLOW_FILTER_AAAA_ON_V4 + /* + * filter-aaaa-on-v4 yes or break-dnssec option to suppress + * AAAA records + * We already know that request came via IPv4, + * that we have both AAAA and A records, + * and that we either have no signatures that the client wants + * or we are supposed to break DNSSEC. + */ + if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0) + render_opts |= DNS_MESSAGERENDER_FILTER_AAAA; +#endif preferred_glue = 0; if (client->view != NULL) { if (client->view->preferred_glue == dns_rdatatype_a) @@ -977,7 +988,7 @@ ns_client_send(ns_client_t *client) { result = dns_message_rendersection(client->message, DNS_SECTION_ANSWER, DNS_MESSAGERENDER_PARTIAL | - dnssec_opts); + render_opts); if (result == ISC_R_NOSPACE) { client->message->flags |= DNS_MESSAGEFLAG_TC; goto renderend; @@ -987,7 +998,7 @@ ns_client_send(ns_client_t *client) { result = dns_message_rendersection(client->message, DNS_SECTION_AUTHORITY, DNS_MESSAGERENDER_PARTIAL | - dnssec_opts); + render_opts); if (result == ISC_R_NOSPACE) { client->message->flags |= DNS_MESSAGEFLAG_TC; goto renderend; @@ -996,7 +1007,7 @@ ns_client_send(ns_client_t *client) { goto done; result = dns_message_rendersection(client->message, DNS_SECTION_ADDITIONAL, - preferred_glue | dnssec_opts); + preferred_glue | render_opts); if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) goto done; renderend: @@ -1355,7 +1366,6 @@ client_request(isc_task_t *task, isc_event_t *event) { dns_name_t *signame; isc_boolean_t ra; /* Recursion available. */ isc_netaddr_t netaddr; - isc_netaddr_t destaddr; int match; dns_messageid_t id; unsigned int flags; @@ -1473,7 +1483,7 @@ client_request(isc_task_t *task, isc_event_t *event) { /* * Silently drop multicast requests for the present. - * XXXMPA look at when/if mDNS spec stabilizes. + * XXXMPA revisit this as mDNS spec was published. */ if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, @@ -1647,24 +1657,20 @@ client_request(isc_task_t *task, isc_event_t *event) { * etc), we regard this as an error for safety. */ if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) - isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr); + isc_netaddr_fromsockaddr(&client->destaddr, + &client->interface->addr); else { + isc_sockaddr_t sockaddr; result = ISC_R_FAILURE; - if (TCP_CLIENT(client)) { - isc_sockaddr_t destsockaddr; - + if (TCP_CLIENT(client)) result = isc_socket_getsockname(client->tcpsocket, - &destsockaddr); - if (result == ISC_R_SUCCESS) - isc_netaddr_fromsockaddr(&destaddr, - &destsockaddr); - } + &sockaddr); + if (result == ISC_R_SUCCESS) + isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr); if (result != ISC_R_SUCCESS && client->interface->addr.type.sa.sa_family == AF_INET6 && (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) { - isc_uint32_t zone = 0; - /* * XXXJT technically, we should convert the receiving * interface ID to a proper scope zone ID. However, @@ -1673,12 +1679,11 @@ client_request(isc_task_t *task, isc_event_t *event) { * interface index as link ID. Despite the assumption, * it should cover most typical cases. */ - if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) - zone = (isc_uint32_t)client->pktinfo.ipi6_ifindex; - - isc_netaddr_fromin6(&destaddr, + isc_netaddr_fromin6(&client->destaddr, &client->pktinfo.ipi6_addr); - isc_netaddr_setzone(&destaddr, zone); + if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) + isc_netaddr_setzone(&client->destaddr, + client->pktinfo.ipi6_ifindex); result = ISC_R_SUCCESS; } if (result != ISC_R_SUCCESS) { @@ -1708,7 +1713,8 @@ client_request(isc_task_t *task, isc_event_t *event) { tsig = dns_tsigkey_identity(client->message->tsigkey); if (allowed(&netaddr, tsig, view->matchclients) && - allowed(&destaddr, tsig, view->matchdestinations) && + allowed(&client->destaddr, tsig, + view->matchdestinations) && !((client->message->flags & DNS_MESSAGEFLAG_RD) == 0 && view->matchrecursiveonly)) { @@ -1771,9 +1777,11 @@ client_request(isc_task_t *task, isc_event_t *event) { } if (result == ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(&client->signername, namebuf, sizeof(namebuf)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), - "request has valid signature"); + "request has valid signature: %s", namebuf); client->signer = &client->signername; } else if (result == ISC_R_NOTFOUND) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, @@ -1861,10 +1869,10 @@ client_request(isc_task_t *task, isc_event_t *event) { ns_client_checkaclsilent(client, NULL, client->view->cacheacl, ISC_TRUE) == ISC_R_SUCCESS && - ns_client_checkaclsilent(client, &client->interface->addr, + ns_client_checkaclsilent(client, &client->destaddr, client->view->recursiononacl, ISC_TRUE) == ISC_R_SUCCESS && - ns_client_checkaclsilent(client, &client->interface->addr, + ns_client_checkaclsilent(client, &client->destaddr, client->view->cacheonacl, ISC_TRUE) == ISC_R_SUCCESS) ra = ISC_TRUE; @@ -2600,12 +2608,12 @@ ns_client_getsockaddr(ns_client_t *client) { } isc_result_t -ns_client_checkaclsilent(ns_client_t *client, isc_sockaddr_t *sockaddr, +ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, dns_acl_t *acl, isc_boolean_t default_allow) { isc_result_t result; + isc_netaddr_t tmpnetaddr; int match; - isc_netaddr_t netaddr; if (acl == NULL) { if (default_allow) @@ -2614,15 +2622,13 @@ ns_client_checkaclsilent(ns_client_t *client, isc_sockaddr_t *sockaddr, goto deny; } + if (netaddr == NULL) { + isc_netaddr_fromsockaddr(&tmpnetaddr, &client->peeraddr); + netaddr = &tmpnetaddr; + } - if (sockaddr == NULL) - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); - else - isc_netaddr_fromsockaddr(&netaddr, sockaddr); - - result = dns_acl_match(&netaddr, client->signer, acl, - &ns_g_server->aclenv, - &match, NULL); + result = dns_acl_match(netaddr, client->signer, acl, + &ns_g_server->aclenv, &match, NULL); if (result != ISC_R_SUCCESS) goto deny; /* Internal error, already logged. */ @@ -2642,8 +2648,14 @@ ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr, const char *opname, dns_acl_t *acl, isc_boolean_t default_allow, int log_level) { - isc_result_t result = - ns_client_checkaclsilent(client, sockaddr, acl, default_allow); + isc_result_t result; + isc_netaddr_t netaddr; + + if (sockaddr != NULL) + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + + result = ns_client_checkaclsilent(client, sockaddr ? &netaddr : NULL, + acl, default_allow); if (result == ISC_R_SUCCESS) ns_client_log(client, DNS_LOGCATEGORY_SECURITY, @@ -2753,9 +2765,14 @@ void ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) { ns_client_t *client; char namebuf[DNS_NAME_FORMATSIZE]; + char original[DNS_NAME_FORMATSIZE]; char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; const char *name; const char *sep; + const char *origfor; + dns_rdataset_t *rdataset; REQUIRE(VALID_MANAGER(manager)); @@ -2773,8 +2790,31 @@ ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) { sep = ""; } dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); - fprintf(f, "; client %s%s%s: '%s' requesttime %d\n", - peerbuf, sep, name, namebuf, client->requesttime); + if (client->query.qname != client->query.origqname && + client->query.origqname != NULL) { + origfor = " for "; + dns_name_format(client->query.origqname, original, + sizeof(original)); + } else { + origfor = ""; + original[0] = '\0'; + } + rdataset = ISC_LIST_HEAD(client->query.qname->list); + if (rdataset == NULL && client->query.origqname != NULL) + rdataset = ISC_LIST_HEAD(client->query.origqname->list); + if (rdataset != NULL) { + dns_rdatatype_format(rdataset->type, typebuf, + sizeof(typebuf)); + dns_rdataclass_format(rdataset->rdclass, classbuf, + sizeof(classbuf)); + } else { + strcpy(typebuf, "-"); + strcpy(classbuf, "-"); + } + fprintf(f, "; client %s%s%s: id %u '%s/%s/%s'%s%s " + "requesttime %d\n", peerbuf, sep, name, + client->message->id, namebuf, typebuf, classbuf, + origfor, original, client->requesttime); client = ISC_LIST_NEXT(client, link); } UNLOCK(&manager->lock); diff --git a/contrib/bind9/bin/named/config.c b/contrib/bind9/bin/named/config.c index 43d0e5287d04..704d7ecc55ef 100644 --- a/contrib/bind9/bin/named/config.c +++ b/contrib/bind9/bin/named/config.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.c,v 1.93.14.2 2009-03-17 23:47:28 tbox Exp $ */ +/* $Id: config.c,v 1.113.16.1.2.1 2011-06-02 23:47:28 tbox Exp $ */ /*! \file */ @@ -42,9 +42,13 @@ #include <dns/tsig.h> #include <dns/zone.h> +#include <dst/dst.h> + #include <named/config.h> #include <named/globals.h> +#include "bind.keys.h" + /*% default configuration */ static char defaultconf[] = "\ options {\n\ @@ -55,7 +59,10 @@ options {\n\ files unlimited;\n\ stacksize default;\n" #endif -" deallocate-on-exit true;\n\ +"# session-keyfile \"" NS_LOCALSTATEDIR "/run/named/session.key\";\n\ + session-keyname local-ddns;\n\ + session-keyalg hmac-sha256;\n\ + deallocate-on-exit true;\n\ # directory <none>\n\ dump-file \"named_dump.db\";\n\ fake-iquery no;\n\ @@ -70,8 +77,10 @@ options {\n\ multiple-cnames no;\n\ # named-xfer <obsolete>;\n\ # pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\ + bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\ port 53;\n\ recursing-file \"named.recursing\";\n\ + secroots-file \"named.secroots\";\n\ " #ifdef PATH_RANDOMDEV "\ @@ -80,6 +89,7 @@ options {\n\ #endif "\ recursive-clients 1000;\n\ + resolver-query-timeout 30;\n\ rrset-order {type NS order random; order cyclic; };\n\ serial-queries 20;\n\ serial-query-rate 20;\n\ @@ -102,6 +112,9 @@ options {\n\ request-nsid false;\n\ reserved-sockets 512;\n\ \n\ + /* DLV */\n\ + dnssec-lookaside . trust-anchor dlv.isc.org;\n\ +\n\ /* view */\n\ allow-notify {none;};\n\ allow-update-forwarding {none;};\n\ @@ -135,6 +148,7 @@ options {\n\ check-names master fail;\n\ check-names slave warn;\n\ check-names response ignore;\n\ + check-dup-records warn;\n\ check-mx warn;\n\ acache-enable no;\n\ acache-cleaning-interval 60;\n\ @@ -146,7 +160,13 @@ options {\n\ max-clients-per-query 100;\n\ zero-no-soa-ttl-cache no;\n\ nsec3-test-zone no;\n\ + allow-new-zones no;\n\ +" +#ifdef ALLOW_FILTER_AAAA_ON_V4 +" filter-aaaa-on-v4 no;\n\ + filter-aaaa { any; };\n\ " +#endif " /* zone */\n\ allow-query {any;};\n\ @@ -174,6 +194,7 @@ options {\n\ max-refresh-time 2419200; /* 4 weeks */\n\ min-refresh-time 300;\n\ multi-master no;\n\ + dnssec-secure-to-insecure no;\n\ sig-validity-interval 30; /* days */\n\ sig-signing-nodes 100;\n\ sig-signing-signatures 10;\n\ @@ -188,6 +209,7 @@ options {\n\ check-srv-cname warn;\n\ zero-no-soa-ttl yes;\n\ update-check-ksk yes;\n\ + dnssec-dnskey-kskonly no;\n\ try-tcp-refresh yes; /* BIND 8 compat */\n\ };\n\ " @@ -198,6 +220,7 @@ options {\n\ view \"_bind\" chaos {\n\ recursion no;\n\ notify no;\n\ + allow-new-zones no;\n\ \n\ zone \"version.bind\" chaos {\n\ type master;\n\ @@ -213,11 +236,24 @@ view \"_bind\" chaos {\n\ type master;\n\ database \"_builtin authors\";\n\ };\n\ +\n\ zone \"id.server\" chaos {\n\ type master;\n\ database \"_builtin id\";\n\ };\n\ };\n\ +" +"#\n\ +# Default trusted key(s) for builtin DLV support\n\ +# (used if \"dnssec-lookaside auto;\" is set and\n\ +# sysconfdir/bind.keys doesn't exist).\n\ +#\n\ +# BEGIN MANAGED KEYS\n" + +/* Imported from bind.keys.h: */ +MANAGED_KEYS + +"# END MANAGED KEYS\n\ "; isc_result_t @@ -339,6 +375,8 @@ ns_config_getzonetype(const cfg_obj_t *zonetypeobj) { ztype = dns_zone_slave; else if (strcasecmp(str, "stub") == 0) ztype = dns_zone_stub; + else if (strcasecmp(str, "static-stub") == 0) + ztype = dns_zone_staticstub; else INSIST(0); return (ztype); @@ -615,7 +653,7 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_buffer_add(&b, strlen(keystr)); dns_fixedname_init(&fname); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_name_dup(dns_fixedname_name(&fname), mctx, @@ -747,23 +785,31 @@ struct keyalgorithms { const char *str; enum { hmacnone, hmacmd5, hmacsha1, hmacsha224, hmacsha256, hmacsha384, hmacsha512 } hmac; + unsigned int type; isc_uint16_t size; } algorithms[] = { - { "hmac-md5", hmacmd5, 128 }, - { "hmac-md5.sig-alg.reg.int", hmacmd5, 0 }, - { "hmac-md5.sig-alg.reg.int.", hmacmd5, 0 }, - { "hmac-sha1", hmacsha1, 160 }, - { "hmac-sha224", hmacsha224, 224 }, - { "hmac-sha256", hmacsha256, 256 }, - { "hmac-sha384", hmacsha384, 384 }, - { "hmac-sha512", hmacsha512, 512 }, - { NULL, hmacnone, 0 } + { "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 }, + { "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 }, + { "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 }, + { "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 }, + { "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 }, + { "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 }, + { "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 }, + { "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 }, + { NULL, hmacnone, DST_ALG_UNKNOWN, 0 } }; isc_result_t ns_config_getkeyalgorithm(const char *str, dns_name_t **name, isc_uint16_t *digestbits) { + return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits)); +} + +isc_result_t +ns_config_getkeyalgorithm2(const char *str, dns_name_t **name, + unsigned int *typep, isc_uint16_t *digestbits) +{ int i; size_t len = 0; isc_uint16_t bits; @@ -801,6 +847,8 @@ ns_config_getkeyalgorithm(const char *str, dns_name_t **name, INSIST(0); } } + if (typep != NULL) + *typep = algorithms[i].type; if (digestbits != NULL) *digestbits = bits; return (ISC_R_SUCCESS); diff --git a/contrib/bind9/bin/named/control.c b/contrib/bind9/bin/named/control.c index 38115d607bbb..3fc7bd3916f5 100644 --- a/contrib/bind9/bin/named/control.c +++ b/contrib/bind9/bin/named/control.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.c,v 1.33.266.4 2010-12-03 23:45:46 tbox Exp $ */ +/* $Id: control.c,v 1.41 2010-12-03 22:05:19 each Exp $ */ /*! \file */ @@ -158,6 +158,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { } else if (command_compare(command, NS_COMMAND_DUMPDB)) { ns_server_dumpdb(ns_g_server, command); result = ISC_R_SUCCESS; + } else if (command_compare(command, NS_COMMAND_SECROOTS)) { + result = ns_server_dumpsecroots(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_TRACE)) { result = ns_server_setdebuglevel(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_NOTRACE)) { @@ -192,6 +194,13 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { result = ns_server_notifycommand(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_VALIDATION)) { result = ns_server_validation(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_SIGN) || + command_compare(command, NS_COMMAND_LOADKEYS)) { + result = ns_server_rekey(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_ADDZONE)) { + result = ns_server_add_zone(ns_g_server, command); + } else if (command_compare(command, NS_COMMAND_DELZONE)) { + result = ns_server_del_zone(ns_g_server, command); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, diff --git a/contrib/bind9/bin/named/include/named/client.h b/contrib/bind9/bin/named/include/named/client.h index 5ad9c6bf5ff0..33f124d94c14 100644 --- a/contrib/bind9/bin/named/include/named/client.h +++ b/contrib/bind9/bin/named/include/named/client.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.h,v 1.86.120.2 2009-01-18 23:47:34 tbox Exp $ */ +/* $Id: client.h,v 1.91 2009-10-26 23:14:53 each Exp $ */ #ifndef NAMED_CLIENT_H #define NAMED_CLIENT_H 1 @@ -138,6 +138,7 @@ struct ns_client { ns_interface_t *interface; isc_sockaddr_t peeraddr; isc_boolean_t peeraddr_valid; + isc_netaddr_t destaddr; struct in6_pktinfo pktinfo; isc_event_t ctlevent; /*% @@ -167,6 +168,10 @@ struct ns_client { #define NS_CLIENTATTR_MULTICAST 0x08 /*%< recv'd from multicast */ #define NS_CLIENTATTR_WANTDNSSEC 0x10 /*%< include dnssec records */ #define NS_CLIENTATTR_WANTNSID 0x20 /*%< include nameserver ID */ +#ifdef ALLOW_FILTER_AAAA_ON_V4 +#define NS_CLIENTATTR_FILTER_AAAA 0x40 /*%< suppress AAAAs */ +#define NS_CLIENTATTR_FILTER_AAAA_RC 0x80 /*%< recursing for A against AAAA */ +#endif extern unsigned int ns_client_requests; @@ -274,10 +279,8 @@ ns_client_getsockaddr(ns_client_t *client); */ isc_result_t -ns_client_checkaclsilent(ns_client_t *client, - isc_sockaddr_t *sockaddr, - dns_acl_t *acl, - isc_boolean_t default_allow); +ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, + dns_acl_t *acl, isc_boolean_t default_allow); /*% * Convenience function for client request ACL checking. @@ -296,12 +299,12 @@ ns_client_checkaclsilent(ns_client_t *client, * * Requires: *\li 'client' points to a valid client. - *\li 'sockaddr' points to a valid address, or is NULL. + *\li 'netaddr' points to a valid address, or is NULL. *\li 'acl' points to a valid ACL, or is NULL. * * Returns: *\li ISC_R_SUCCESS if the request should be allowed - * \li ISC_R_REFUSED if the request should be denied + * \li DNS_R_REFUSED if the request should be denied *\li No other return values are possible. */ diff --git a/contrib/bind9/bin/named/include/named/config.h b/contrib/bind9/bin/named/include/named/config.h index fa96d32947e3..d1570b0e5704 100644 --- a/contrib/bind9/bin/named/include/named/config.h +++ b/contrib/bind9/bin/named/include/named/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001, 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.h,v 1.14 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: config.h,v 1.16 2009-06-11 23:47:55 tbox Exp $ */ #ifndef NAMED_CONFIG_H #define NAMED_CONFIG_H 1 @@ -75,5 +75,8 @@ ns_config_getport(const cfg_obj_t *config, in_port_t *portp); isc_result_t ns_config_getkeyalgorithm(const char *str, dns_name_t **name, isc_uint16_t *digestbits); +isc_result_t +ns_config_getkeyalgorithm2(const char *str, dns_name_t **name, + unsigned int *typep, isc_uint16_t *digestbits); #endif /* NAMED_CONFIG_H */ diff --git a/contrib/bind9/bin/named/include/named/control.h b/contrib/bind9/bin/named/include/named/control.h index 436fb19c7bf6..e699892ca4ce 100644 --- a/contrib/bind9/bin/named/include/named/control.h +++ b/contrib/bind9/bin/named/include/named/control.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.h,v 1.25 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: control.h,v 1.31 2010-08-16 22:21:06 marka Exp $ */ #ifndef NAMED_CONTROL_H #define NAMED_CONTROL_H 1 @@ -42,6 +42,7 @@ #define NS_COMMAND_DUMPSTATS "stats" #define NS_COMMAND_QUERYLOG "querylog" #define NS_COMMAND_DUMPDB "dumpdb" +#define NS_COMMAND_SECROOTS "secroots" #define NS_COMMAND_TRACE "trace" #define NS_COMMAND_NOTRACE "notrace" #define NS_COMMAND_FLUSH "flush" @@ -57,6 +58,10 @@ #define NS_COMMAND_NULL "null" #define NS_COMMAND_NOTIFY "notify" #define NS_COMMAND_VALIDATION "validation" +#define NS_COMMAND_SIGN "sign" +#define NS_COMMAND_LOADKEYS "loadkeys" +#define NS_COMMAND_ADDZONE "addzone" +#define NS_COMMAND_DELZONE "delzone" isc_result_t ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp); diff --git a/contrib/bind9/bin/named/include/named/globals.h b/contrib/bind9/bin/named/include/named/globals.h index 1d57a18f2008..f155c7f05ed5 100644 --- a/contrib/bind9/bin/named/include/named/globals.h +++ b/contrib/bind9/bin/named/include/named/globals.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: globals.h,v 1.80.12.3 2010-09-15 12:16:50 marka Exp $ */ +/* $Id: globals.h,v 1.89 2010-09-15 12:07:55 marka Exp $ */ #ifndef NAMED_GLOBALS_H #define NAMED_GLOBALS_H 1 @@ -30,6 +30,8 @@ #include <dns/zone.h> +#include <dst/dst.h> + #include <named/types.h> #undef EXTERN @@ -86,8 +88,13 @@ EXTERN cfg_obj_t * ns_g_config INIT(NULL); EXTERN const cfg_obj_t * ns_g_defaults INIT(NULL); EXTERN const char * ns_g_conffile INIT(NS_SYSCONFDIR "/named.conf"); +EXTERN cfg_obj_t * ns_g_bindkeys INIT(NULL); EXTERN const char * ns_g_keyfile INIT(NS_SYSCONFDIR "/rndc.key"); + +EXTERN dns_tsigkey_t * ns_g_sessionkey INIT(NULL); +EXTERN dns_name_t ns_g_sessionkeyname; + EXTERN const char * lwresd_g_conffile INIT(NS_SYSCONFDIR "/lwresd.conf"); EXTERN const char * lwresd_g_resolvconffile INIT("/etc" @@ -112,6 +119,10 @@ EXTERN const char * ns_g_chrootdir INIT(NULL); EXTERN isc_boolean_t ns_g_foreground INIT(ISC_FALSE); EXTERN isc_boolean_t ns_g_logstderr INIT(ISC_FALSE); +EXTERN const char * ns_g_defaultsessionkeyfile + INIT(NS_LOCALSTATEDIR "/run/named/" + "session.key"); + #if NS_RUN_PID_DIR EXTERN const char * ns_g_defaultpidfile INIT(NS_LOCALSTATEDIR "/run/named/" @@ -128,6 +139,12 @@ EXTERN const char * lwresd_g_defaultpidfile INIT(NS_LOCALSTATEDIR EXTERN const char * ns_g_username INIT(NULL); +#ifdef USE_PKCS11 +EXTERN const char * ns_g_engine INIT("pkcs11"); +#else +EXTERN const char * ns_g_engine INIT(NULL); +#endif + EXTERN int ns_g_listen INIT(3); EXTERN isc_time_t ns_g_boottime; EXTERN isc_boolean_t ns_g_memstatistics INIT(ISC_FALSE); diff --git a/contrib/bind9/bin/named/include/named/log.h b/contrib/bind9/bin/named/include/named/log.h index 0cfbee9ad396..1ce680f31e02 100644 --- a/contrib/bind9/bin/named/include/named/log.h +++ b/contrib/bind9/bin/named/include/named/log.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.h,v 1.25.332.2 2009-01-07 23:47:16 tbox Exp $ */ +/* $Id: log.h,v 1.27 2009-01-07 23:47:46 tbox Exp $ */ #ifndef NAMED_LOG_H #define NAMED_LOG_H 1 diff --git a/contrib/bind9/bin/named/include/named/lwdclient.h b/contrib/bind9/bin/named/include/named/lwdclient.h index 44e1fa6e0878..5451b73675ab 100644 --- a/contrib/bind9/bin/named/include/named/lwdclient.h +++ b/contrib/bind9/bin/named/include/named/lwdclient.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwdclient.h,v 1.18.332.2 2009-01-18 23:47:34 tbox Exp $ */ +/* $Id: lwdclient.h,v 1.20 2009-01-17 23:47:42 tbox Exp $ */ #ifndef NAMED_LWDCLIENT_H #define NAMED_LWDCLIENT_H 1 diff --git a/contrib/bind9/bin/named/include/named/main.h b/contrib/bind9/bin/named/include/named/main.h index 96fb23edd80a..6116add55b85 100644 --- a/contrib/bind9/bin/named/include/named/main.h +++ b/contrib/bind9/bin/named/include/named/main.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,15 +15,16 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.h,v 1.15 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: main.h,v 1.17 2009-09-29 23:48:03 tbox Exp $ */ #ifndef NAMED_MAIN_H #define NAMED_MAIN_H 1 /*! \file */ -void -ns_main_earlyfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); +ISC_PLATFORM_NORETURN_PRE void +ns_main_earlyfatal(const char *format, ...) +ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; void ns_main_earlywarning(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); diff --git a/contrib/bind9/bin/named/include/named/notify.h b/contrib/bind9/bin/named/include/named/notify.h index ac7fe2d3a9a6..34fabcd0620c 100644 --- a/contrib/bind9/bin/named/include/named/notify.h +++ b/contrib/bind9/bin/named/include/named/notify.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: notify.h,v 1.14.332.2 2009-01-18 23:47:34 tbox Exp $ */ +/* $Id: notify.h,v 1.16 2009-01-17 23:47:42 tbox Exp $ */ #ifndef NAMED_NOTIFY_H #define NAMED_NOTIFY_H 1 diff --git a/contrib/bind9/bin/named/include/named/query.h b/contrib/bind9/bin/named/include/named/query.h index 2f00f1ea3843..37f771bd5960 100644 --- a/contrib/bind9/bin/named/include/named/query.h +++ b/contrib/bind9/bin/named/include/named/query.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2010, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.h,v 1.40.332.2 2010-09-24 08:30:28 tbox Exp $ */ +/* $Id: query.h,v 1.45 2011-01-13 04:59:24 tbox Exp $ */ #ifndef NAMED_QUERY_H #define NAMED_QUERY_H 1 @@ -26,6 +26,8 @@ #include <isc/buffer.h> #include <isc/netaddr.h> +#include <dns/rdataset.h> +#include <dns/rpz.h> #include <dns/types.h> #include <named/types.h> @@ -34,6 +36,7 @@ typedef struct ns_dbversion { dns_db_t *db; dns_dbversion_t *version; + isc_boolean_t acl_checked; isc_boolean_t queryok; ISC_LINK(struct ns_dbversion) link; } ns_dbversion_t; @@ -54,9 +57,16 @@ struct ns_query { isc_boolean_t isreferral; isc_mutex_t fetchlock; dns_fetch_t * fetch; + dns_rpz_st_t * rpz_st; isc_bufferlist_t namebufs; ISC_LIST(ns_dbversion_t) activeversions; ISC_LIST(ns_dbversion_t) freeversions; + dns_rdataset_t * dns64_aaaa; + dns_rdataset_t * dns64_sigaaaa; + isc_boolean_t * dns64_aaaaok; + unsigned int dns64_aaaaoklen; + unsigned int dns64_options; + unsigned int dns64_ttl; }; #define NS_QUERYATTR_RECURSIONOK 0x0001 @@ -73,6 +83,9 @@ struct ns_query { #define NS_QUERYATTR_NOADDITIONAL 0x0800 #define NS_QUERYATTR_CACHEACLOKVALID 0x1000 #define NS_QUERYATTR_CACHEACLOK 0x2000 +#define NS_QUERYATTR_DNS64 0x4000 +#define NS_QUERYATTR_DNS64EXCLUDE 0x8000 + isc_result_t ns_query_init(ns_client_t *client); diff --git a/contrib/bind9/bin/named/include/named/server.h b/contrib/bind9/bin/named/include/named/server.h index 3a4c5f7248e2..3c6426eecf61 100644 --- a/contrib/bind9/bin/named/include/named/server.h +++ b/contrib/bind9/bin/named/include/named/server.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.93.120.3 2009-07-11 04:23:53 marka Exp $ */ +/* $Id: server.h,v 1.110 2010-08-16 23:46:52 tbox Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -54,6 +54,8 @@ struct ns_server { dns_acl_t *blackholeacl; char * statsfile; /*%< Statistics file name */ char * dumpfile; /*%< Dump file name */ + char * secrootsfile; /*%< Secroots file name */ + char * bindkeysfile; /*%< bind.keys file name */ char * recfile; /*%< Recursive file name */ isc_boolean_t version_set; /*%< User has set version */ char * version; /*%< User-specified version */ @@ -91,13 +93,14 @@ struct ns_server { isc_boolean_t flushonshutdown; isc_boolean_t log_queries; /*%< For BIND 8 compatibility */ - isc_stats_t * nsstats; /*%< Server statistics */ - dns_stats_t * rcvquerystats; /*% Incoming query statistics */ - dns_stats_t * opcodestats; /*%< Incoming message statistics */ - isc_stats_t * zonestats; /*% Zone management statistics */ - isc_stats_t * resolverstats; /*% Resolver statistics */ + ns_cachelist_t cachelist; /*%< Possibly shared caches */ + isc_stats_t * nsstats; /*%< Server stats */ + dns_stats_t * rcvquerystats; /*% Incoming query stats */ + dns_stats_t * opcodestats; /*%< Incoming message stats */ + isc_stats_t * zonestats; /*% Zone management stats */ + isc_stats_t * resolverstats; /*% Resolver stats */ + isc_stats_t * sockstats; /*%< Socket stats */ - isc_stats_t * sockstats; /*%< Socket statistics */ ns_controls_t * controls; /*%< Control channels */ unsigned int dispatchgen; ns_dispatchlist_t dispatches; @@ -105,6 +108,12 @@ struct ns_server { dns_acache_t *acache; ns_statschannellist_t statschannels; + + dns_tsigkey_t *sessionkey; + char *session_keyfile; + dns_name_t *session_keyname; + unsigned int session_keyalg; + isc_uint16_t session_keybits; }; #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') @@ -237,6 +246,12 @@ isc_result_t ns_server_dumpdb(ns_server_t *server, char *args); /*% + * Dump the current security roots to the secroots file. + */ +isc_result_t +ns_server_dumpsecroots(ns_server_t *server, char *args); + +/*% * Change or increment the server debug level. */ isc_result_t @@ -280,6 +295,16 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, isc_buffer_t *text); /*% + * Update a zone's DNSKEY set from the key repository. If + * the command that triggered the call to this function was "sign", + * then force a full signing of the zone. If it was "loadkeys", + * then don't sign the zone; any needed changes to signatures can + * take place incrementally. + */ +isc_result_t +ns_server_rekey(ns_server_t *server, char *args); + +/*% * Dump the current recursive queries. */ isc_result_t @@ -297,4 +322,16 @@ ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr); isc_result_t ns_server_validation(ns_server_t *server, char *args); +/*% + * Add a zone to a running process + */ +isc_result_t +ns_server_add_zone(ns_server_t *server, char *args); + +/*% + * Deletes a zone from a running process + */ +isc_result_t +ns_server_del_zone(ns_server_t *server, char *args); + #endif /* NAMED_SERVER_H */ diff --git a/contrib/bind9/bin/named/include/named/tsigconf.h b/contrib/bind9/bin/named/include/named/tsigconf.h index a4841bad9df9..4a59ec2c0ff7 100644 --- a/contrib/bind9/bin/named/include/named/tsigconf.h +++ b/contrib/bind9/bin/named/include/named/tsigconf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsigconf.h,v 1.16 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: tsigconf.h,v 1.18 2009-06-11 23:47:55 tbox Exp $ */ #ifndef NS_TSIGCONF_H #define NS_TSIGCONF_H 1 @@ -36,8 +36,9 @@ ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, * * Requires: * \li 'config' is not NULL. + * \li 'vconfig' is not NULL. * \li 'mctx' is not NULL - * \li 'ring' is not NULL, and '*ring' is NULL + * \li 'ringp' is not NULL, and '*ringp' is NULL * * Returns: * \li ISC_R_SUCCESS diff --git a/contrib/bind9/bin/named/include/named/types.h b/contrib/bind9/bin/named/include/named/types.h index b0729a787ba7..96c4c012b71f 100644 --- a/contrib/bind9/bin/named/include/named/types.h +++ b/contrib/bind9/bin/named/include/named/types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.29 2008-01-17 23:46:59 tbox Exp $ */ +/* $Id: types.h,v 1.31 2009-01-09 23:47:45 tbox Exp $ */ #ifndef NAMED_TYPES_H #define NAMED_TYPES_H 1 @@ -24,6 +24,8 @@ #include <dns/types.h> +typedef struct ns_cache ns_cache_t; +typedef ISC_LIST(ns_cache_t) ns_cachelist_t; typedef struct ns_client ns_client_t; typedef struct ns_clientmgr ns_clientmgr_t; typedef struct ns_query ns_query_t; diff --git a/contrib/bind9/bin/named/include/named/zoneconf.h b/contrib/bind9/bin/named/include/named/zoneconf.h index ab84c84515bf..65cf72f9f3ac 100644 --- a/contrib/bind9/bin/named/include/named/zoneconf.h +++ b/contrib/bind9/bin/named/include/named/zoneconf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zoneconf.h,v 1.26 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: zoneconf.h,v 1.28 2010-12-20 23:47:20 tbox Exp $ */ #ifndef NS_ZONECONF_H #define NS_ZONECONF_H 1 @@ -58,6 +58,21 @@ ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig); * and recreated, return ISC_FALSE. */ + +isc_result_t +ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone, + dns_rdataclass_t rdclass, dns_name_t *name); +/*%> + * configure a DLZ zone, setting up the database methods and calling + * postload to load the origin values + * + * Require: + * \li 'dlzdatabase' to be a valid dlz database + * \li 'zone' to be initialized. + * \li 'rdclass' to be a valid rdataclass + * \li 'name' to be a valid zone origin name + */ + ISC_LANG_ENDDECLS #endif /* NS_ZONECONF_H */ diff --git a/contrib/bind9/bin/named/interfacemgr.c b/contrib/bind9/bin/named/interfacemgr.c index fad32137f6df..e99d3b9cfe38 100644 --- a/contrib/bind9/bin/named/interfacemgr.c +++ b/contrib/bind9/bin/named/interfacemgr.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: interfacemgr.c,v 1.93.70.2 2009-01-18 23:47:34 tbox Exp $ */ +/* $Id: interfacemgr.c,v 1.95 2009-01-17 23:47:42 tbox Exp $ */ /*! \file */ diff --git a/contrib/bind9/bin/named/log.c b/contrib/bind9/bin/named/log.c index 867ad56b8c51..5d1c942074ca 100644 --- a/contrib/bind9/bin/named/log.c +++ b/contrib/bind9/bin/named/log.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.c,v 1.46.334.3 2009-01-07 01:50:14 jinmei Exp $ */ +/* $Id: log.c,v 1.49 2009-01-07 01:46:40 jinmei Exp $ */ /*! \file */ diff --git a/contrib/bind9/bin/named/lwdgabn.c b/contrib/bind9/bin/named/lwdgabn.c index 66d724624a5c..6a609c9acc4f 100644 --- a/contrib/bind9/bin/named/lwdgabn.c +++ b/contrib/bind9/bin/named/lwdgabn.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwdgabn.c,v 1.22 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: lwdgabn.c,v 1.24 2009-09-02 23:48:01 tbox Exp $ */ /*! \file */ @@ -619,7 +619,7 @@ ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) { dns_fixedname_init(&client->target_name); dns_fixedname_init(&client->query_name); result = dns_name_fromtext(dns_fixedname_name(&client->query_name), - &namebuf, NULL, ISC_FALSE, NULL); + &namebuf, NULL, 0, NULL); if (result != ISC_R_SUCCESS) goto out; ns_lwsearchctx_init(&client->searchctx, diff --git a/contrib/bind9/bin/named/lwdgrbn.c b/contrib/bind9/bin/named/lwdgrbn.c index bf29a481c488..22b62c625c12 100644 --- a/contrib/bind9/bin/named/lwdgrbn.c +++ b/contrib/bind9/bin/named/lwdgrbn.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwdgrbn.c,v 1.20 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: lwdgrbn.c,v 1.22 2009-09-02 23:48:01 tbox Exp $ */ /*! \file */ @@ -472,7 +472,7 @@ ns_lwdclient_processgrbn(ns_lwdclient_t *client, lwres_buffer_t *b) { dns_fixedname_init(&client->query_name); result = dns_name_fromtext(dns_fixedname_name(&client->query_name), - &namebuf, NULL, ISC_FALSE, NULL); + &namebuf, NULL, 0, NULL); if (result != ISC_R_SUCCESS) goto out; ns_lwsearchctx_init(&client->searchctx, diff --git a/contrib/bind9/bin/named/lwresd.8 b/contrib/bind9/bin/named/lwresd.8 index d1e760d10887..30dfbd55e783 100644 --- a/contrib/bind9/bin/named/lwresd.8 +++ b/contrib/bind9/bin/named/lwresd.8 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwresd.8,v 1.29.14.2 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwresd.8,v 1.31 2009-07-11 01:12:45 tbox Exp $ .\" .hy 0 .ad l diff --git a/contrib/bind9/bin/named/lwresd.c b/contrib/bind9/bin/named/lwresd.c index b7dc0af1038f..ad3670960cb1 100644 --- a/contrib/bind9/bin/named/lwresd.c +++ b/contrib/bind9/bin/named/lwresd.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwresd.c,v 1.58 2008-07-23 23:27:54 marka Exp $ */ +/* $Id: lwresd.c,v 1.60 2009-09-02 23:48:01 tbox Exp $ */ /*! \file * \brief @@ -372,8 +372,7 @@ ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres, strlen(searchstr)); isc_buffer_add(&namebuf, strlen(searchstr)); result = dns_name_fromtext(name, &namebuf, - dns_rootname, ISC_FALSE, - NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, diff --git a/contrib/bind9/bin/named/lwresd.docbook b/contrib/bind9/bin/named/lwresd.docbook index f8e1500d0479..934b5da21dcc 100644 --- a/contrib/bind9/bin/named/lwresd.docbook +++ b/contrib/bind9/bin/named/lwresd.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: lwresd.docbook,v 1.18.14.2 2009-01-22 23:47:05 tbox Exp $ --> +<!-- $Id: lwresd.docbook,v 1.20 2009-01-20 23:47:56 tbox Exp $ --> <refentry> <refentryinfo> <date>June 30, 2000</date> diff --git a/contrib/bind9/bin/named/lwresd.html b/contrib/bind9/bin/named/lwresd.html index dec47caa2b86..223b1c2c5250 100644 --- a/contrib/bind9/bin/named/lwresd.html +++ b/contrib/bind9/bin/named/lwresd.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: lwresd.html,v 1.25.14.2 2009-07-11 01:55:21 tbox Exp $ --> +<!-- $Id: lwresd.html,v 1.27 2009-07-11 01:12:45 tbox Exp $ --> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> diff --git a/contrib/bind9/bin/named/main.c b/contrib/bind9/bin/named/main.c index a1d94fff80d5..84d86b146f4c 100644 --- a/contrib/bind9/bin/named/main.c +++ b/contrib/bind9/bin/named/main.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.166.34.7 2010-09-15 12:16:49 marka Exp $ */ +/* $Id: main.c,v 1.180 2010-12-22 03:59:02 marka Exp $ */ /*! \file */ @@ -26,6 +26,7 @@ #include <string.h> #include <isc/app.h> +#include <isc/backtrace.h> #include <isc/commandline.h> #include <isc/dir.h> #include <isc/entropy.h> @@ -69,6 +70,12 @@ #include <named/ns_smf_globals.h> #endif +#ifdef OPENSSL +#include <openssl/opensslv.h> +#endif +#ifdef HAVE_LIBXML2 +#include <libxml/xmlversion.h> +#endif /* * Include header files for database drivers here. */ @@ -81,12 +88,20 @@ #include <dlz/dlz_drivers.h> #endif +/* + * The maximum number of stack frames to dump on assertion failure. + */ +#ifndef BACKTRACE_MAXFRAME +#define BACKTRACE_MAXFRAME 128 +#endif + static isc_boolean_t want_stats = ISC_FALSE; static char program_name[ISC_DIR_NAMEMAX] = "named"; static char absolute_conffile[ISC_DIR_PATHMAX]; static char saved_command_line[512]; static char version[512]; static unsigned int maxsocks = 0; +static int maxudp = 0; void ns_main_earlywarning(const char *format, ...) { @@ -129,10 +144,20 @@ ns_main_earlyfatal(const char *format, ...) { exit(1); } +ISC_PLATFORM_NORETURN_PRE static void +assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) ISC_PLATFORM_NORETURN_POST; + static void assertion_failed(const char *file, int line, isc_assertiontype_t type, const char *cond) { + void *tracebuf[BACKTRACE_MAXFRAME]; + int i, nframes; + isc_result_t result; + const char *logsuffix = ""; + const char *fname; + /* * Handle assertion failures. */ @@ -144,10 +169,40 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type, */ isc_assertion_setcallback(NULL); + result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, + &nframes); + if (result == ISC_R_SUCCESS && nframes > 0) + logsuffix = ", back trace"; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, - "%s:%d: %s(%s) failed", file, line, - isc_assertion_typetotext(type), cond); + "%s:%d: %s(%s) failed%s", file, line, + isc_assertion_typetotext(type), cond, logsuffix); + if (result == ISC_R_SUCCESS) { + for (i = 0; i < nframes; i++) { + unsigned long offset; + + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], + &fname, + &offset); + if (result == ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, + ISC_LOG_CRITICAL, + "#%d %p in %s()+0x%lx", i, + tracebuf[i], fname, + offset); + } else { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, + ISC_LOG_CRITICAL, + "#%d %p in ??", i, + tracebuf[i]); + } + } + } isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, "exiting (due to assertion failure)"); @@ -162,9 +217,10 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type, exit(1); } -static void +ISC_PLATFORM_NORETURN_PRE static void library_fatal_error(const char *file, int line, const char *format, - va_list args) ISC_FORMAT_PRINTF(3, 0); + va_list args) +ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST; static void library_fatal_error(const char *file, int line, const char *format, @@ -248,8 +304,9 @@ usage(void) { } fprintf(stderr, "usage: named [-4|-6] [-c conffile] [-d debuglevel] " - "[-f|-g] [-n number_of_cpus]\n" - " [-p port] [-s] [-t chrootdir] [-u username]\n" + "[-E engine] [-f|-g]\n" + " [-n number_of_cpus] [-p port] [-s] " + "[-t chrootdir] [-u username]\n" " [-m {usage|trace|record|size|mctx}]\n"); } @@ -358,7 +415,7 @@ parse_command_line(int argc, char *argv[]) { isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "46c:C:d:fgi:lm:n:N:p:P:" + "46c:C:d:E:fFgi:lm:n:N:p:P:" "sS:t:T:u:vVx:")) != -1) { switch (ch) { case '4': @@ -394,6 +451,9 @@ parse_command_line(int argc, char *argv[]) { ns_g_debuglevel = parse_int(isc_commandline_argument, "debug level"); break; + case 'E': + ns_g_engine = isc_commandline_argument; + break; case 'f': ns_g_foreground = ISC_TRUE; break; @@ -451,12 +511,16 @@ parse_command_line(int argc, char *argv[]) { * clienttest: make clients single shot with their * own memory context. */ - if (strcmp(isc_commandline_argument, "clienttest") == 0) + if (!strcmp(isc_commandline_argument, "clienttest")) ns_g_clienttest = ISC_TRUE; else if (!strcmp(isc_commandline_argument, "nosoa")) ns_g_nosoa = ISC_TRUE; else if (!strcmp(isc_commandline_argument, "noaa")) ns_g_noaa = ISC_TRUE; + else if (!strcmp(isc_commandline_argument, "maxudp512")) + maxudp = 512; + else if (!strcmp(isc_commandline_argument, "maxudp1460")) + maxudp = 1460; else fprintf(stderr, "unknown -T flag '%s\n", isc_commandline_argument); @@ -470,13 +534,25 @@ parse_command_line(int argc, char *argv[]) { case 'V': printf("BIND %s built with %s\n", ns_g_version, ns_g_configargs); +#ifdef OPENSSL + printf("using OpenSSL version: %s\n", + OPENSSL_VERSION_TEXT); +#endif +#ifdef HAVE_LIBXML2 + printf("using libxml2 version: %s\n", + LIBXML_DOTTED_VERSION); +#endif exit(0); + case 'F': + /* Reserved for FIPS mode */ + /* FALLTHROUGH */ case '?': usage(); if (isc_commandline_option == '?') exit(0); ns_main_earlyfatal("unknown option '-%c'", isc_commandline_option); + /* FALLTHROUGH */ default: ns_main_earlyfatal("parsing options returned %d", ch); } @@ -529,6 +605,7 @@ create_managers(void) { isc_result_totext(result)); return (ISC_R_UNEXPECTED); } + isc__socketmgr_maxudp(ns_g_socketmgr, maxudp); result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks); if (result == ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, @@ -579,6 +656,34 @@ destroy_managers(void) { } static void +dump_symboltable() { + int i; + isc_result_t result; + const char *fname; + const void *addr; + + if (isc__backtrace_nsymbols == 0) + return; + + if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99))) + return; + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_DEBUG(99), "Symbol table:"); + + for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) { + addr = NULL; + fname = NULL; + result = isc_backtrace_getsymbolfromindex(i, &addr, &fname); + if (result == ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), + "[%d] %p %s", i, addr, fname); + } + } +} + +static void setup(void) { isc_result_t result; isc_resourcevalue_t old_openfiles; @@ -685,6 +790,8 @@ setup(void) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, "built with %s", ns_g_configargs); + dump_symboltable(); + /* * Get the initial resource limits. */ @@ -723,8 +830,8 @@ setup(void) { absolute_conffile, sizeof(absolute_conffile)); if (result != ISC_R_SUCCESS) - ns_main_earlyfatal("could not construct absolute path of " - "configuration file: %s", + ns_main_earlyfatal("could not construct absolute path " + "of configuration file: %s", isc_result_totext(result)); ns_g_conffile = absolute_conffile; } @@ -896,6 +1003,9 @@ main(int argc, char *argv[]) { if (strcmp(program_name, "lwresd") == 0) ns_g_lwresdonly = ISC_TRUE; + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("failed to build internal symbol table"); + isc_assertion_setcallback(assertion_failed); isc_error_setfatal(library_fatal_error); isc_error_setunexpected(library_unexpected_error); diff --git a/contrib/bind9/bin/named/named.8 b/contrib/bind9/bin/named/named.8 index 90782ed8171e..23805b04a935 100644 --- a/contrib/bind9/bin/named/named.8 +++ b/contrib/bind9/bin/named/named.8 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: named.8,v 1.38.14.2 2009-12-03 05:06:38 tbox Exp $ +.\" $Id: named.8,v 1.41 2009-10-06 01:14:41 tbox Exp $ .\" .hy 0 .ad l @@ -33,7 +33,7 @@ named \- Internet domain name server .SH "SYNOPSIS" .HP 6 -\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-m\ \fR\fB\fIflag\fR\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-S\ \fR\fB\fI#max\-socks\fR\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-V\fR] [\fB\-x\ \fR\fB\fIcache\-file\fR\fR] +\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-E\ \fR\fB\fIengine\-name\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-m\ \fR\fB\fIflag\fR\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-S\ \fR\fB\fI#max\-socks\fR\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-V\fR] [\fB\-x\ \fR\fB\fIcache\-file\fR\fR] .SH "DESCRIPTION" .PP \fBnamed\fR @@ -83,6 +83,13 @@ Set the daemon's debug level to become more verbose as the debug level increases. .RE .PP +\-E \fIengine\-name\fR +.RS 4 +Use a crypto hardware (OpenSSL engine) for the crypto operations it supports, for instance re\-signing with private keys from a secure key store. When compiled with PKCS#11 support +\fIengine\-name\fR +defaults to pkcs11, the empty name resets it to no engine. +.RE +.PP \-f .RS 4 Run the server in the foreground (i.e. do not daemonize). diff --git a/contrib/bind9/bin/named/named.conf.5 b/contrib/bind9/bin/named/named.conf.5 index cd0d4ad75543..9dc7002b09c9 100644 --- a/contrib/bind9/bin/named/named.conf.5 +++ b/contrib/bind9/bin/named/named.conf.5 @@ -1,4 +1,4 @@ -.\" Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2004-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 @@ -12,7 +12,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: named.conf.5,v 1.36.48.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: named.conf.5,v 1.44.12.1 2011-02-03 12:29:12 tbox Exp $ .\" .hy 0 .ad l @@ -102,6 +102,15 @@ trusted\-keys { }; .fi .RE +.SH "MANAGED\-KEYS" +.sp +.RS 4 +.nf +managed\-keys { + \fIdomain_name\fR \fBinitial\-key\fR \fIflags\fR \fIprotocol\fR \fIalgorithm\fR \fIkey\fR; ... +}; +.fi +.RE .SH "CONTROLS" .sp .RS 4 @@ -186,6 +195,7 @@ options { tcp\-listen\-queue \fIinteger\fR; tkey\-dhkey \fIquoted_string\fR \fIinteger\fR; tkey\-gssapi\-credential \fIquoted_string\fR; + tkey\-gssapi\-keytab \fIquoted_string\fR; tkey\-domain \fIquoted_string\fR; transfers\-per\-ns \fIinteger\fR; transfers\-in \fIinteger\fR; @@ -214,6 +224,7 @@ options { queryport\-pool\-ports \fIinteger\fR; queryport\-pool\-updateinterval \fIinteger\fR; cleaning\-interval \fIinteger\fR; + resolver\-query\-timeout \fIinteger\fR; min\-roots \fIinteger\fR; // not implemented lame\-ttl \fIinteger\fR; max\-ncache\-ttl \fIinteger\fR; @@ -244,8 +255,19 @@ options { dnssec\-enable \fIboolean\fR; dnssec\-validation \fIboolean\fR; dnssec\-lookaside \fIstring\fR trust\-anchor \fIstring\fR; + dnssec\-lookaside ( \fIauto\fR | \fIdomain\fR trust\-anchor \fIdomain\fR ); dnssec\-must\-be\-secure \fIstring\fR \fIboolean\fR; dnssec\-accept\-expired \fIboolean\fR; + dns64\-server \fIstring\fR; + dns64\-contact \fIstring\fR; + dns64 \fIprefix\fR { + clients { <replacable>acl</replacable>; }; + exclude { <replacable>acl</replacable>; }; + mapped { <replacable>acl</replacable>; }; + break\-dnssec \fIboolean\fR; + recursive\-only \fIboolean\fR; + suffix \fIipv6_address\fR; + }; empty\-server \fIstring\fR; empty\-contact \fIstring\fR; empty\-zones\-enable \fIboolean\fR; @@ -260,6 +282,7 @@ options { allow\-update { \fIaddress_match_element\fR; ... }; allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; update\-check\-ksk \fIboolean\fR; + dnssec\-dnskey\-kskonly \fIboolean\fR; masterfile\-format ( text | raw ); notify \fInotifytype\fR; notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; @@ -299,9 +322,18 @@ options { use\-alt\-transfer\-source \fIboolean\fR; zone\-statistics \fIboolean\fR; key\-directory \fIquoted_string\fR; + managed\-keys\-directory \fIquoted_string\fR; + auto\-dnssec \fBallow\fR|\fBmaintain\fR|\fBcreate\fR|\fBoff\fR; try\-tcp\-refresh \fIboolean\fR; zero\-no\-soa\-ttl \fIboolean\fR; zero\-no\-soa\-ttl\-cache \fIboolean\fR; + dnssec\-secure\-to\-insecure \fIboolean\fR; + deny\-answer\-addresses { + \fIaddress_match_list\fR + } [ except\-from { \fInamelist\fR } ]; + deny\-answer\-aliases { + \fInamelist\fR + } [ except\-from { \fInamelist\fR } ]; nsec3\-test\-zone \fIboolean\fR; // testing only allow\-v6\-synthesis { \fIaddress_match_element\fR; ... }; // obsolete deallocate\-on\-exit \fIboolean\fR; // obsolete @@ -337,7 +369,8 @@ view \fIstring\fR \fIoptional_class\fR { ... }; trusted\-keys { - \fIstring\fR \fIinteger\fR \fIinteger\fR \fIinteger\fR \fIquoted_string\fR; ... + \fIstring\fR \fIinteger\fR \fIinteger\fR \fIinteger\fR \fIquoted_string\fR; + [...] }; allow\-recursion { \fIaddress_match_element\fR; ... }; allow\-recursion\-on { \fIaddress_match_element\fR; ... }; @@ -361,6 +394,7 @@ view \fIstring\fR \fIoptional_class\fR { queryport\-pool\-ports \fIinteger\fR; queryport\-pool\-updateinterval \fIinteger\fR; cleaning\-interval \fIinteger\fR; + resolver\-query\-timeout \fIinteger\fR; min\-roots \fIinteger\fR; // not implemented lame\-ttl \fIinteger\fR; max\-ncache\-ttl \fIinteger\fR; @@ -393,6 +427,16 @@ view \fIstring\fR \fIoptional_class\fR { dnssec\-lookaside \fIstring\fR trust\-anchor \fIstring\fR; dnssec\-must\-be\-secure \fIstring\fR \fIboolean\fR; dnssec\-accept\-expired \fIboolean\fR; + dns64\-server \fIstring\fR; + dns64\-contact \fIstring\fR; + dns64 \fIprefix\fR { + clients { <replacable>acl</replacable>; }; + exclude { <replacable>acl</replacable>; }; + mapped { <replacable>acl</replacable>; }; + break\-dnssec \fIboolean\fR; + recursive\-only \fIboolean\fR; + suffix \fIipv6_address\fR; + }; empty\-server \fIstring\fR; empty\-contact \fIstring\fR; empty\-zones\-enable \fIboolean\fR; @@ -407,6 +451,7 @@ view \fIstring\fR \fIoptional_class\fR { allow\-update { \fIaddress_match_element\fR; ... }; allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; update\-check\-ksk \fIboolean\fR; + dnssec\-dnskey\-kskonly \fIboolean\fR; masterfile\-format ( text | raw ); notify \fInotifytype\fR; notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; @@ -445,6 +490,7 @@ view \fIstring\fR \fIoptional_class\fR { key\-directory \fIquoted_string\fR; zero\-no\-soa\-ttl \fIboolean\fR; zero\-no\-soa\-ttl\-cache \fIboolean\fR; + dnssec\-secure\-to\-insecure \fIboolean\fR; allow\-v6\-synthesis { \fIaddress_match_element\fR; ... }; // obsolete fetch\-glue \fIboolean\fR; // obsolete maintain\-ixfr\-base \fIboolean\fR; // obsolete @@ -476,19 +522,22 @@ zone \fIstring\fR \fIoptional_class\fR { ixfr\-from\-differences \fIboolean\fR; journal \fIquoted_string\fR; zero\-no\-soa\-ttl \fIboolean\fR; + dnssec\-secure\-to\-insecure \fIboolean\fR; allow\-query { \fIaddress_match_element\fR; ... }; allow\-query\-on { \fIaddress_match_element\fR; ... }; allow\-transfer { \fIaddress_match_element\fR; ... }; allow\-update { \fIaddress_match_element\fR; ... }; allow\-update\-forwarding { \fIaddress_match_element\fR; ... }; - update\-policy { - ( grant | deny ) \fIstring\fR + update\-policy \fIlocal\fR | \fI { + ( grant | deny ) \fR\fI\fIstring\fR\fR\fI ( name | subdomain | wildcard | self | selfsub | selfwild | krb5\-self | ms\-self | krb5\-subdomain | ms\-subdomain | - tcp\-self | 6to4\-self ) \fIstring\fR - \fIrrtypelist\fR; ... - }; + tcp\-self | zonesub | 6to4\-self ) \fR\fI\fIstring\fR\fR\fI + \fR\fI\fIrrtypelist\fR\fR\fI; + \fR\fI[...]\fR\fI + }\fR; update\-check\-ksk \fIboolean\fR; + dnssec\-dnskey\-kskonly \fIboolean\fR; masterfile\-format ( text | raw ); notify \fInotifytype\fR; notify\-source ( \fIipv4_address\fR | * ) [ port ( \fIinteger\fR | * ) ]; @@ -544,5 +593,5 @@ zone \fIstring\fR \fIoptional_class\fR { \fBrndc\fR(8), BIND 9 Administrator Reference Manual. .SH "COPYRIGHT" -Copyright \(co 2004\-2008 Internet Systems Consortium, Inc. ("ISC") +Copyright \(co 2004\-2011 Internet Systems Consortium, Inc. ("ISC") .br diff --git a/contrib/bind9/bin/named/named.conf.docbook b/contrib/bind9/bin/named/named.conf.docbook index d98e2899295a..962eaaa0e2bd 100644 --- a/contrib/bind9/bin/named/named.conf.docbook +++ b/contrib/bind9/bin/named/named.conf.docbook @@ -2,7 +2,7 @@ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [<!ENTITY mdash "—">]> <!-- - - Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + - Copyright (C) 2004-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 @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: named.conf.docbook,v 1.39 2008-09-24 02:46:21 marka Exp $ --> +<!-- $Id: named.conf.docbook,v 1.49.14.1 2011-02-03 05:50:05 marka Exp $ --> <refentry> <refentryinfo> <date>Aug 13, 2004</date> @@ -41,6 +41,9 @@ <year>2006</year> <year>2007</year> <year>2008</year> + <year>2009</year> + <year>2010</year> + <year>2011</year> <holder>Internet Systems Consortium, Inc. ("ISC")</holder> </copyright> </docinfo> @@ -132,6 +135,15 @@ trusted-keys { </refsect1> <refsect1> + <title>MANAGED-KEYS</title> + <literallayout> +managed-keys { + <replaceable>domain_name</replaceable> <constant>initial-key</constant> <replaceable>flags</replaceable> <replaceable>protocol</replaceable> <replaceable>algorithm</replaceable> <replaceable>key</replaceable>; ... +}; +</literallayout> + </refsect1> + + <refsect1> <title>CONTROLS</title> <literallayout> controls { @@ -214,6 +226,7 @@ options { tcp-listen-queue <replaceable>integer</replaceable>; tkey-dhkey <replaceable>quoted_string</replaceable> <replaceable>integer</replaceable>; tkey-gssapi-credential <replaceable>quoted_string</replaceable>; + tkey-gssapi-keytab <replaceable>quoted_string</replaceable>; tkey-domain <replaceable>quoted_string</replaceable>; transfers-per-ns <replaceable>integer</replaceable>; transfers-in <replaceable>integer</replaceable>; @@ -242,6 +255,7 @@ options { queryport-pool-ports <replaceable>integer</replaceable>; queryport-pool-updateinterval <replaceable>integer</replaceable>; cleaning-interval <replaceable>integer</replaceable>; + resolver-query-timeout <replaceable>integer</replaceable>; min-roots <replaceable>integer</replaceable>; // not implemented lame-ttl <replaceable>integer</replaceable>; max-ncache-ttl <replaceable>integer</replaceable>; @@ -272,9 +286,21 @@ options { dnssec-enable <replaceable>boolean</replaceable>; dnssec-validation <replaceable>boolean</replaceable>; dnssec-lookaside <replaceable>string</replaceable> trust-anchor <replaceable>string</replaceable>; + dnssec-lookaside ( <replaceable>auto</replaceable> | <replaceable>domain</replaceable> trust-anchor <replaceable>domain</replaceable> ); dnssec-must-be-secure <replaceable>string</replaceable> <replaceable>boolean</replaceable>; dnssec-accept-expired <replaceable>boolean</replaceable>; + dns64-server <replaceable>string</replaceable>; + dns64-contact <replaceable>string</replaceable>; + dns64 <replaceable>prefix</replaceable> { + clients { <replacable>acl</replacable>; }; + exclude { <replacable>acl</replacable>; }; + mapped { <replacable>acl</replacable>; }; + break-dnssec <replaceable>boolean</replaceable>; + recursive-only <replaceable>boolean</replaceable>; + suffix <replaceable>ipv6_address</replaceable>; + }; + empty-server <replaceable>string</replaceable>; empty-contact <replaceable>string</replaceable>; empty-zones-enable <replaceable>boolean</replaceable>; @@ -291,6 +317,7 @@ options { allow-update { <replaceable>address_match_element</replaceable>; ... }; allow-update-forwarding { <replaceable>address_match_element</replaceable>; ... }; update-check-ksk <replaceable>boolean</replaceable>; + dnssec-dnskey-kskonly <replaceable>boolean</replaceable>; masterfile-format ( text | raw ); notify <replaceable>notifytype</replaceable>; @@ -337,9 +364,18 @@ options { zone-statistics <replaceable>boolean</replaceable>; key-directory <replaceable>quoted_string</replaceable>; + managed-keys-directory <replaceable>quoted_string</replaceable>; + auto-dnssec <constant>allow</constant>|<constant>maintain</constant>|<constant>create</constant>|<constant>off</constant>; try-tcp-refresh <replaceable>boolean</replaceable>; zero-no-soa-ttl <replaceable>boolean</replaceable>; zero-no-soa-ttl-cache <replaceable>boolean</replaceable>; + dnssec-secure-to-insecure <replaceable>boolean</replaceable>; + deny-answer-addresses { + <replaceable>address_match_list</replaceable> + } <optional> except-from { <replaceable>namelist</replaceable> } </optional>; + deny-answer-aliases { + <replaceable>namelist</replaceable> + } <optional> except-from { <replaceable>namelist</replaceable> } </optional>; nsec3-test-zone <replaceable>boolean</replaceable>; // testing only @@ -381,7 +417,8 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable> }; trusted-keys { - <replaceable>string</replaceable> <replaceable>integer</replaceable> <replaceable>integer</replaceable> <replaceable>integer</replaceable> <replaceable>quoted_string</replaceable>; ... + <replaceable>string</replaceable> <replaceable>integer</replaceable> <replaceable>integer</replaceable> <replaceable>integer</replaceable> <replaceable>quoted_string</replaceable>; + <optional>...</optional> }; allow-recursion { <replaceable>address_match_element</replaceable>; ... }; @@ -406,6 +443,7 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable> queryport-pool-ports <replaceable>integer</replaceable>; queryport-pool-updateinterval <replaceable>integer</replaceable>; cleaning-interval <replaceable>integer</replaceable>; + resolver-query-timeout <replaceable>integer</replaceable>; min-roots <replaceable>integer</replaceable>; // not implemented lame-ttl <replaceable>integer</replaceable>; max-ncache-ttl <replaceable>integer</replaceable>; @@ -439,6 +477,17 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable> dnssec-must-be-secure <replaceable>string</replaceable> <replaceable>boolean</replaceable>; dnssec-accept-expired <replaceable>boolean</replaceable>; + dns64-server <replaceable>string</replaceable>; + dns64-contact <replaceable>string</replaceable>; + dns64 <replaceable>prefix</replaceable> { + clients { <replacable>acl</replacable>; }; + exclude { <replacable>acl</replacable>; }; + mapped { <replacable>acl</replacable>; }; + break-dnssec <replaceable>boolean</replaceable>; + recursive-only <replaceable>boolean</replaceable>; + suffix <replaceable>ipv6_address</replaceable>; + }; + empty-server <replaceable>string</replaceable>; empty-contact <replaceable>string</replaceable>; empty-zones-enable <replaceable>boolean</replaceable>; @@ -455,6 +504,7 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable> allow-update { <replaceable>address_match_element</replaceable>; ... }; allow-update-forwarding { <replaceable>address_match_element</replaceable>; ... }; update-check-ksk <replaceable>boolean</replaceable>; + dnssec-dnskey-kskonly <replaceable>boolean</replaceable>; masterfile-format ( text | raw ); notify <replaceable>notifytype</replaceable>; @@ -499,6 +549,7 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable> key-directory <replaceable>quoted_string</replaceable>; zero-no-soa-ttl <replaceable>boolean</replaceable>; zero-no-soa-ttl-cache <replaceable>boolean</replaceable>; + dnssec-secure-to-insecure <replaceable>boolean</replaceable>; allow-v6-synthesis { <replaceable>address_match_element</replaceable>; ... }; // obsolete fetch-glue <replaceable>boolean</replaceable>; // obsolete @@ -533,20 +584,23 @@ zone <replaceable>string</replaceable> <replaceable>optional_class</replaceable> ixfr-from-differences <replaceable>boolean</replaceable>; journal <replaceable>quoted_string</replaceable>; zero-no-soa-ttl <replaceable>boolean</replaceable>; + dnssec-secure-to-insecure <replaceable>boolean</replaceable>; allow-query { <replaceable>address_match_element</replaceable>; ... }; allow-query-on { <replaceable>address_match_element</replaceable>; ... }; allow-transfer { <replaceable>address_match_element</replaceable>; ... }; allow-update { <replaceable>address_match_element</replaceable>; ... }; allow-update-forwarding { <replaceable>address_match_element</replaceable>; ... }; - update-policy { + update-policy <replaceable>local</replaceable> | <replaceable> { ( grant | deny ) <replaceable>string</replaceable> ( name | subdomain | wildcard | self | selfsub | selfwild | krb5-self | ms-self | krb5-subdomain | ms-subdomain | - tcp-self | 6to4-self ) <replaceable>string</replaceable> - <replaceable>rrtypelist</replaceable>; ... - }; + tcp-self | zonesub | 6to4-self ) <replaceable>string</replaceable> + <replaceable>rrtypelist</replaceable>; + <optional>...</optional> + }</replaceable>; update-check-ksk <replaceable>boolean</replaceable>; + dnssec-dnskey-kskonly <replaceable>boolean</replaceable>; masterfile-format ( text | raw ); notify <replaceable>notifytype</replaceable>; diff --git a/contrib/bind9/bin/named/named.conf.html b/contrib/bind9/bin/named/named.conf.html index fccad183f9e6..f20e411f45b0 100644 --- a/contrib/bind9/bin/named/named.conf.html +++ b/contrib/bind9/bin/named/named.conf.html @@ -1,5 +1,5 @@ <!-- - - Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + - Copyright (C) 2004-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 @@ -13,7 +13,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: named.conf.html,v 1.45.48.1 2009-07-11 01:55:21 tbox Exp $ --> +<!-- $Id: named.conf.html,v 1.53.12.1 2011-02-03 12:29:12 tbox Exp $ --> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> @@ -31,7 +31,7 @@ <div class="cmdsynopsis"><p><code class="command">named.conf</code> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543342"></a><h2>DESCRIPTION</h2> +<a name="id2543352"></a><h2>DESCRIPTION</h2> <p><code class="filename">named.conf</code> is the configuration file for <span><strong class="command">named</strong></span>. Statements are enclosed @@ -50,14 +50,14 @@ </p> </div> <div class="refsect1" lang="en"> -<a name="id2543370"></a><h2>ACL</h2> +<a name="id2543380"></a><h2>ACL</h2> <div class="literallayout"><p><br> acl <em class="replaceable"><code>string</code></em> { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> <br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543386"></a><h2>KEY</h2> +<a name="id2543396"></a><h2>KEY</h2> <div class="literallayout"><p><br> key <em class="replaceable"><code>domain_name</code></em> {<br> algorithm <em class="replaceable"><code>string</code></em>;<br> @@ -66,7 +66,7 @@ key <em class="replaceable"><code>domain_name</code></em> {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543405"></a><h2>MASTERS</h2> +<a name="id2543415"></a><h2>MASTERS</h2> <div class="literallayout"><p><br> masters <em class="replaceable"><code>string</code></em> [<span class="optional"> port <em class="replaceable"><code>integer</code></em> </span>] {<br> ( <em class="replaceable"><code>masters</code></em> | <em class="replaceable"><code>ipv4_address</code></em> [<span class="optional">port <em class="replaceable"><code>integer</code></em></span>] |<br> @@ -75,7 +75,7 @@ masters <em class="replaceable"><code>string</code></em> [<span class="optional" </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543451"></a><h2>SERVER</h2> +<a name="id2543461"></a><h2>SERVER</h2> <div class="literallayout"><p><br> server ( <em class="replaceable"><code>ipv4_address[<span class="optional">/prefixlen</span>]</code></em> | <em class="replaceable"><code>ipv6_address[<span class="optional">/prefixlen</span>]</code></em> ) {<br> bogus <em class="replaceable"><code>boolean</code></em>;<br> @@ -97,7 +97,7 @@ server ( <em class="replaceable"><code>ipv4_address[<span class="optional">/pref </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543520"></a><h2>TRUSTED-KEYS</h2> +<a name="id2543529"></a><h2>TRUSTED-KEYS</h2> <div class="literallayout"><p><br> trusted-keys {<br> <em class="replaceable"><code>domain_name</code></em> <em class="replaceable"><code>flags</code></em> <em class="replaceable"><code>protocol</code></em> <em class="replaceable"><code>algorithm</code></em> <em class="replaceable"><code>key</code></em>; ... <br> @@ -105,7 +105,15 @@ trusted-keys {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543545"></a><h2>CONTROLS</h2> +<a name="id2543555"></a><h2>MANAGED-KEYS</h2> +<div class="literallayout"><p><br> +managed-keys {<br> + <em class="replaceable"><code>domain_name</code></em> <code class="constant">initial-key</code> <em class="replaceable"><code>flags</code></em> <em class="replaceable"><code>protocol</code></em> <em class="replaceable"><code>algorithm</code></em> <em class="replaceable"><code>key</code></em>; ... <br> +};<br> +</p></div> +</div> +<div class="refsect1" lang="en"> +<a name="id2543584"></a><h2>CONTROLS</h2> <div class="literallayout"><p><br> controls {<br> inet ( <em class="replaceable"><code>ipv4_address</code></em> | <em class="replaceable"><code>ipv6_address</code></em> | * )<br> @@ -117,7 +125,7 @@ controls {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543580"></a><h2>LOGGING</h2> +<a name="id2543619"></a><h2>LOGGING</h2> <div class="literallayout"><p><br> logging {<br> channel <em class="replaceable"><code>string</code></em> {<br> @@ -135,7 +143,7 @@ logging {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543619"></a><h2>LWRES</h2> +<a name="id2543657"></a><h2>LWRES</h2> <div class="literallayout"><p><br> lwres {<br> listen-on [<span class="optional"> port <em class="replaceable"><code>integer</code></em> </span>] {<br> @@ -148,7 +156,7 @@ lwres {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543660"></a><h2>OPTIONS</h2> +<a name="id2543699"></a><h2>OPTIONS</h2> <div class="literallayout"><p><br> options {<br> avoid-v4-udp-ports { <em class="replaceable"><code>port</code></em>; ... };<br> @@ -184,6 +192,7 @@ options {<br> tcp-listen-queue <em class="replaceable"><code>integer</code></em>;<br> tkey-dhkey <em class="replaceable"><code>quoted_string</code></em> <em class="replaceable"><code>integer</code></em>;<br> tkey-gssapi-credential <em class="replaceable"><code>quoted_string</code></em>;<br> + tkey-gssapi-keytab <em class="replaceable"><code>quoted_string</code></em>;<br> tkey-domain <em class="replaceable"><code>quoted_string</code></em>;<br> transfers-per-ns <em class="replaceable"><code>integer</code></em>;<br> transfers-in <em class="replaceable"><code>integer</code></em>;<br> @@ -212,6 +221,7 @@ options {<br> queryport-pool-ports <em class="replaceable"><code>integer</code></em>;<br> queryport-pool-updateinterval <em class="replaceable"><code>integer</code></em>;<br> cleaning-interval <em class="replaceable"><code>integer</code></em>;<br> + resolver-query-timeout <em class="replaceable"><code>integer</code></em>;<br> min-roots <em class="replaceable"><code>integer</code></em>; // not implemented<br> lame-ttl <em class="replaceable"><code>integer</code></em>;<br> max-ncache-ttl <em class="replaceable"><code>integer</code></em>;<br> @@ -242,9 +252,21 @@ options {<br> dnssec-enable <em class="replaceable"><code>boolean</code></em>;<br> dnssec-validation <em class="replaceable"><code>boolean</code></em>;<br> dnssec-lookaside <em class="replaceable"><code>string</code></em> trust-anchor <em class="replaceable"><code>string</code></em>;<br> + dnssec-lookaside ( <em class="replaceable"><code>auto</code></em> | <em class="replaceable"><code>domain</code></em> trust-anchor <em class="replaceable"><code>domain</code></em> );<br> dnssec-must-be-secure <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>boolean</code></em>;<br> dnssec-accept-expired <em class="replaceable"><code>boolean</code></em>;<br> <br> + dns64-server <em class="replaceable"><code>string</code></em>;<br> + dns64-contact <em class="replaceable"><code>string</code></em>;<br> + dns64 <em class="replaceable"><code>prefix</code></em> {<br> + clients { <font color="red"><replacable>acl</replacable></font>; };<br> + exclude { <font color="red"><replacable>acl</replacable></font>; };<br> + mapped { <font color="red"><replacable>acl</replacable></font>; };<br> + break-dnssec <em class="replaceable"><code>boolean</code></em>;<br> + recursive-only <em class="replaceable"><code>boolean</code></em>;<br> + suffix <em class="replaceable"><code>ipv6_address</code></em>;<br> + };<br> +<br> empty-server <em class="replaceable"><code>string</code></em>;<br> empty-contact <em class="replaceable"><code>string</code></em>;<br> empty-zones-enable <em class="replaceable"><code>boolean</code></em>;<br> @@ -261,6 +283,7 @@ options {<br> allow-update { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-update-forwarding { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> update-check-ksk <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-dnskey-kskonly <em class="replaceable"><code>boolean</code></em>;<br> <br> masterfile-format ( text | raw );<br> notify <em class="replaceable"><code>notifytype</code></em>;<br> @@ -307,9 +330,18 @@ options {<br> <br> zone-statistics <em class="replaceable"><code>boolean</code></em>;<br> key-directory <em class="replaceable"><code>quoted_string</code></em>;<br> + managed-keys-directory <em class="replaceable"><code>quoted_string</code></em>;<br> + auto-dnssec <code class="constant">allow</code>|<code class="constant">maintain</code>|<code class="constant">create</code>|<code class="constant">off</code>;<br> try-tcp-refresh <em class="replaceable"><code>boolean</code></em>;<br> zero-no-soa-ttl <em class="replaceable"><code>boolean</code></em>;<br> zero-no-soa-ttl-cache <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-secure-to-insecure <em class="replaceable"><code>boolean</code></em>;<br> + deny-answer-addresses {<br> + <em class="replaceable"><code>address_match_list</code></em><br> + } [<span class="optional"> except-from { <em class="replaceable"><code>namelist</code></em> } </span>];<br> + deny-answer-aliases {<br> + <em class="replaceable"><code>namelist</code></em><br> + } [<span class="optional"> except-from { <em class="replaceable"><code>namelist</code></em> } </span>];<br> <br> nsec3-test-zone <em class="replaceable"><code>boolean</code></em>; // testing only<br> <br> @@ -329,7 +361,7 @@ options {<br> </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2544452"></a><h2>VIEW</h2> +<a name="id2544577"></a><h2>VIEW</h2> <div class="literallayout"><p><br> view <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>optional_class</code></em> {<br> match-clients { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> @@ -350,7 +382,8 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c };<br> <br> trusted-keys {<br> - <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>quoted_string</code></em>; ...<br> + <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>integer</code></em> <em class="replaceable"><code>quoted_string</code></em>;<br> + [<span class="optional">...</span>]<br> };<br> <br> allow-recursion { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> @@ -375,6 +408,7 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c queryport-pool-ports <em class="replaceable"><code>integer</code></em>;<br> queryport-pool-updateinterval <em class="replaceable"><code>integer</code></em>;<br> cleaning-interval <em class="replaceable"><code>integer</code></em>;<br> + resolver-query-timeout <em class="replaceable"><code>integer</code></em>;<br> min-roots <em class="replaceable"><code>integer</code></em>; // not implemented<br> lame-ttl <em class="replaceable"><code>integer</code></em>;<br> max-ncache-ttl <em class="replaceable"><code>integer</code></em>;<br> @@ -408,6 +442,17 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c dnssec-must-be-secure <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>boolean</code></em>;<br> dnssec-accept-expired <em class="replaceable"><code>boolean</code></em>;<br> <br> + dns64-server <em class="replaceable"><code>string</code></em>;<br> + dns64-contact <em class="replaceable"><code>string</code></em>;<br> + dns64 <em class="replaceable"><code>prefix</code></em> {<br> + clients { <font color="red"><replacable>acl</replacable></font>; };<br> + exclude { <font color="red"><replacable>acl</replacable></font>; };<br> + mapped { <font color="red"><replacable>acl</replacable></font>; };<br> + break-dnssec <em class="replaceable"><code>boolean</code></em>;<br> + recursive-only <em class="replaceable"><code>boolean</code></em>;<br> + suffix <em class="replaceable"><code>ipv6_address</code></em>;<br> + };<br> +<br> empty-server <em class="replaceable"><code>string</code></em>;<br> empty-contact <em class="replaceable"><code>string</code></em>;<br> empty-zones-enable <em class="replaceable"><code>boolean</code></em>;<br> @@ -424,6 +469,7 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c allow-update { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-update-forwarding { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> update-check-ksk <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-dnskey-kskonly <em class="replaceable"><code>boolean</code></em>;<br> <br> masterfile-format ( text | raw );<br> notify <em class="replaceable"><code>notifytype</code></em>;<br> @@ -468,6 +514,7 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c key-directory <em class="replaceable"><code>quoted_string</code></em>;<br> zero-no-soa-ttl <em class="replaceable"><code>boolean</code></em>;<br> zero-no-soa-ttl-cache <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-secure-to-insecure <em class="replaceable"><code>boolean</code></em>;<br> <br> allow-v6-synthesis { <em class="replaceable"><code>address_match_element</code></em>; ... }; // obsolete<br> fetch-glue <em class="replaceable"><code>boolean</code></em>; // obsolete<br> @@ -477,7 +524,7 @@ view <em class="replaceable"><code>string</code></em> <em class="replaceable"><c </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2545113"></a><h2>ZONE</h2> +<a name="id2545280"></a><h2>ZONE</h2> <div class="literallayout"><p><br> zone <em class="replaceable"><code>string</code></em> <em class="replaceable"><code>optional_class</code></em> {<br> type ( master | slave | stub | hint |<br> @@ -501,20 +548,23 @@ zone <em class="replaceable"><code>string</code></em> <em class="replaceable"><c ixfr-from-differences <em class="replaceable"><code>boolean</code></em>;<br> journal <em class="replaceable"><code>quoted_string</code></em>;<br> zero-no-soa-ttl <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-secure-to-insecure <em class="replaceable"><code>boolean</code></em>;<br> <br> allow-query { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-query-on { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-transfer { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-update { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> allow-update-forwarding { <em class="replaceable"><code>address_match_element</code></em>; ... };<br> - update-policy {<br> + update-policy <em class="replaceable"><code>local</code></em> | <em class="replaceable"><code> {<br> ( grant | deny ) <em class="replaceable"><code>string</code></em><br> ( name | subdomain | wildcard | self | selfsub | selfwild |<br> krb5-self | ms-self | krb5-subdomain | ms-subdomain |<br> - tcp-self | 6to4-self ) <em class="replaceable"><code>string</code></em><br> - <em class="replaceable"><code>rrtypelist</code></em>; ...<br> - };<br> + tcp-self | zonesub | 6to4-self ) <em class="replaceable"><code>string</code></em><br> + <em class="replaceable"><code>rrtypelist</code></em>;<br> + [<span class="optional">...</span>]<br> + }</code></em>;<br> update-check-ksk <em class="replaceable"><code>boolean</code></em>;<br> + dnssec-dnskey-kskonly <em class="replaceable"><code>boolean</code></em>;<br> <br> masterfile-format ( text | raw );<br> notify <em class="replaceable"><code>notifytype</code></em>;<br> @@ -569,12 +619,12 @@ zone <em class="replaceable"><code>string</code></em> <em class="replaceable"><c </p></div> </div> <div class="refsect1" lang="en"> -<a name="id2545410"></a><h2>FILES</h2> +<a name="id2545659"></a><h2>FILES</h2> <p><code class="filename">/etc/named.conf</code> </p> </div> <div class="refsect1" lang="en"> -<a name="id2545421"></a><h2>SEE ALSO</h2> +<a name="id2545671"></a><h2>SEE ALSO</h2> <p><span class="citerefentry"><span class="refentrytitle">named</span>(8)</span>, <span class="citerefentry"><span class="refentrytitle">named-checkconf</span>(8)</span>, <span class="citerefentry"><span class="refentrytitle">rndc</span>(8)</span>, diff --git a/contrib/bind9/bin/named/named.docbook b/contrib/bind9/bin/named/named.docbook index 808e998eb8a5..214f8ac6e9d7 100644 --- a/contrib/bind9/bin/named/named.docbook +++ b/contrib/bind9/bin/named/named.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: named.docbook,v 1.23.14.2 2009-12-03 04:49:32 tbox Exp $ --> +<!-- $Id: named.docbook,v 1.26 2009-10-05 17:30:49 fdupont Exp $ --> <refentry id="man.named"> <refentryinfo> <date>May 21, 2009</date> @@ -60,6 +60,7 @@ <arg><option>-6</option></arg> <arg><option>-c <replaceable class="parameter">config-file</replaceable></option></arg> <arg><option>-d <replaceable class="parameter">debug-level</replaceable></option></arg> + <arg><option>-E <replaceable class="parameter">engine-name</replaceable></option></arg> <arg><option>-f</option></arg> <arg><option>-g</option></arg> <arg><option>-m <replaceable class="parameter">flag</replaceable></option></arg> @@ -116,6 +117,7 @@ </para> </listitem> </varlistentry> + <varlistentry> <term>-c <replaceable class="parameter">config-file</replaceable></term> <listitem> @@ -145,6 +147,19 @@ </varlistentry> <varlistentry> + <term>-E <replaceable class="parameter">engine-name</replaceable></term> + <listitem> + <para> + Use a crypto hardware (OpenSSL engine) for the crypto operations + it supports, for instance re-signing with private keys from + a secure key store. When compiled with PKCS#11 support + <replaceable class="parameter">engine-name</replaceable> + defaults to pkcs11, the empty name resets it to no engine. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term>-f</term> <listitem> <para> diff --git a/contrib/bind9/bin/named/named.html b/contrib/bind9/bin/named/named.html index 031b4921ff4e..fa869c4c6d10 100644 --- a/contrib/bind9/bin/named/named.html +++ b/contrib/bind9/bin/named/named.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> -<!-- $Id: named.html,v 1.30.14.2 2009-12-03 05:06:38 tbox Exp $ --> +<!-- $Id: named.html,v 1.33 2009-10-06 01:14:41 tbox Exp $ --> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> @@ -29,10 +29,10 @@ </div> <div class="refsynopsisdiv"> <h2>Synopsis</h2> -<div class="cmdsynopsis"><p><code class="command">named</code> [<code class="option">-4</code>] [<code class="option">-6</code>] [<code class="option">-c <em class="replaceable"><code>config-file</code></em></code>] [<code class="option">-d <em class="replaceable"><code>debug-level</code></em></code>] [<code class="option">-f</code>] [<code class="option">-g</code>] [<code class="option">-m <em class="replaceable"><code>flag</code></em></code>] [<code class="option">-n <em class="replaceable"><code>#cpus</code></em></code>] [<code class="option">-p <em class="replaceable"><code>port</code></em></code>] [<code class="option">-s</code>] [<code class="option">-S <em class="replaceable"><code>#max-socks</code></em></code>] [<code class="option">-t <em class="replaceable"><code>directory</code></em></code>] [<code class="option">-u <em class="replaceable"><code>user</code></em></code>] [<code class="option">-v</code>] [<code class="option">-V</code>] [<code class="option">-x <em class="replaceable"><code>cache-file</code></em></code>]</p></div> +<div class="cmdsynopsis"><p><code class="command">named</code> [<code class="option">-4</code>] [<code class="option">-6</code>] [<code class="option">-c <em class="replaceable"><code>config-file</code></em></code>] [<code class="option">-d <em class="replaceable"><code>debug-level</code></em></code>] [<code class="option">-E <em class="replaceable"><code>engine-name</code></em></code>] [<code class="option">-f</code>] [<code class="option">-g</code>] [<code class="option">-m <em class="replaceable"><code>flag</code></em></code>] [<code class="option">-n <em class="replaceable"><code>#cpus</code></em></code>] [<code class="option">-p <em class="replaceable"><code>port</code></em></code>] [<code class="option">-s</code>] [<code class="option">-S <em class="replaceable"><code>#max-socks</code></em></code>] [<code class="option">-t <em class="replaceable"><code>directory</code></em></code>] [<code class="option">-u <em class="replaceable"><code>user</code></em></code>] [<code class="option">-v</code>] [<code class="option">-V</code>] [<code class="option">-x <em class="replaceable"><code>cache-file</code></em></code>]</p></div> </div> <div class="refsect1" lang="en"> -<a name="id2543472"></a><h2>DESCRIPTION</h2> +<a name="id2543480"></a><h2>DESCRIPTION</h2> <p><span><strong class="command">named</strong></span> is a Domain Name System (DNS) server, part of the BIND 9 distribution from ISC. For more @@ -47,7 +47,7 @@ </p> </div> <div class="refsect1" lang="en"> -<a name="id2543496"></a><h2>OPTIONS</h2> +<a name="id2543505"></a><h2>OPTIONS</h2> <div class="variablelist"><dl> <dt><span class="term">-4</span></dt> <dd><p> @@ -79,6 +79,14 @@ Debugging traces from <span><strong class="command">named</strong></span> become more verbose as the debug level increases. </p></dd> +<dt><span class="term">-E <em class="replaceable"><code>engine-name</code></em></span></dt> +<dd><p> + Use a crypto hardware (OpenSSL engine) for the crypto operations + it supports, for instance re-signing with private keys from + a secure key store. When compiled with PKCS#11 support + <em class="replaceable"><code>engine-name</code></em> + defaults to pkcs11, the empty name resets it to no engine. + </p></dd> <dt><span class="term">-f</span></dt> <dd><p> Run the server in the foreground (i.e. do not daemonize). @@ -220,7 +228,7 @@ </dl></div> </div> <div class="refsect1" lang="en"> -<a name="id2543931"></a><h2>SIGNALS</h2> +<a name="id2543962"></a><h2>SIGNALS</h2> <p> In routine operation, signals should not be used to control the nameserver; <span><strong class="command">rndc</strong></span> should be used @@ -241,7 +249,7 @@ </p> </div> <div class="refsect1" lang="en"> -<a name="id2543979"></a><h2>CONFIGURATION</h2> +<a name="id2544010"></a><h2>CONFIGURATION</h2> <p> The <span><strong class="command">named</strong></span> configuration file is too complex to describe in detail here. A complete description is provided @@ -258,7 +266,7 @@ </p> </div> <div class="refsect1" lang="en"> -<a name="id2544016"></a><h2>FILES</h2> +<a name="id2544046"></a><h2>FILES</h2> <div class="variablelist"><dl> <dt><span class="term"><code class="filename">/etc/named.conf</code></span></dt> <dd><p> @@ -271,7 +279,7 @@ </dl></div> </div> <div class="refsect1" lang="en"> -<a name="id2544123"></a><h2>SEE ALSO</h2> +<a name="id2544086"></a><h2>SEE ALSO</h2> <p><em class="citetitle">RFC 1033</em>, <em class="citetitle">RFC 1034</em>, <em class="citetitle">RFC 1035</em>, @@ -284,7 +292,7 @@ </p> </div> <div class="refsect1" lang="en"> -<a name="id2544194"></a><h2>AUTHOR</h2> +<a name="id2544293"></a><h2>AUTHOR</h2> <p><span class="corpauthor">Internet Systems Consortium</span> </p> </div> diff --git a/contrib/bind9/bin/named/query.c b/contrib/bind9/bin/named/query.c index fa34da6e28c0..1950257dca2c 100644 --- a/contrib/bind9/bin/named/query.c +++ b/contrib/bind9/bin/named/query.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.313.20.24 2010-09-24 08:09:07 marka Exp $ */ +/* $Id: query.c,v 1.353.8.2.2.5 2011-06-09 03:17:10 marka Exp $ */ /*! \file */ @@ -34,6 +34,7 @@ #ifdef DLZ #include <dns/dlz.h> #endif +#include <dns/dns64.h> #include <dns/dnssec.h> #include <dns/events.h> #include <dns/message.h> @@ -62,6 +63,17 @@ #include <named/sortlist.h> #include <named/xfrout.h> +#if 0 +/* + * It has been recommended that DNS64 be changed to return excluded + * AAAA addresses if DNS64 synthesis does not occur. This minimises + * the impact on the lookup results. While most DNS AAAA lookups are + * done to send IP packets to a host, not all of them are and filtering + * excluded addresses has a negative impact on those uses. + */ +#define dns64_bis_return_excluded_addresses 1 +#endif + /*% Partial answer? */ #define PARTIALANSWER(c) (((c)->query.attributes & \ NS_QUERYATTR_PARTIALANSWER) != 0) @@ -92,6 +104,12 @@ /*% Secure? */ #define SECURE(c) (((c)->query.attributes & \ NS_QUERYATTR_SECURE) != 0) +/*% DNS64 A lookup? */ +#define DNS64(c) (((c)->query.attributes & \ + NS_QUERYATTR_DNS64) != 0) + +#define DNS64EXCLUDE(c) (((c)->query.attributes & \ + NS_QUERYATTR_DNS64EXCLUDE) != 0) /*% No QNAME Proof? */ #define NOQNAME(r) (((r)->attributes & \ @@ -116,6 +134,7 @@ #define DNS_GETDB_NOEXACT 0x01U #define DNS_GETDB_NOLOG 0x02U #define DNS_GETDB_PARTIAL 0x04U +#define DNS_GETDB_IGNOREACL 0x08U #define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0) @@ -141,6 +160,9 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, static inline void log_queryerror(ns_client_t *client, isc_result_t result, int line, int level); +static void +rpz_st_clear(ns_client_t *client); + /*% * Increment query statistics counters. */ @@ -252,6 +274,19 @@ ns_query_cancel(ns_client_t *client) { } static inline void +query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { + dns_rdataset_t *rdataset = *rdatasetp; + + CTRACE("query_putrdataset"); + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, rdatasetp); + } + CTRACE("query_putrdataset: done"); +} + +static inline void query_reset(ns_client_t *client, isc_boolean_t everything) { isc_buffer_t *dbuf, *dbuf_next; ns_dbversion_t *dbversion, *dbversion_next; @@ -285,6 +320,18 @@ query_reset(ns_client_t *client, isc_boolean_t everything) { if (client->query.authzone != NULL) dns_zone_detach(&client->query.authzone); + if (client->query.dns64_aaaa != NULL) + query_putrdataset(client, &client->query.dns64_aaaa); + if (client->query.dns64_sigaaaa != NULL) + query_putrdataset(client, &client->query.dns64_sigaaaa); + if (client->query.dns64_aaaaok != NULL) { + isc_mem_put(client->mctx, client->query.dns64_aaaaok, + client->query.dns64_aaaaoklen * + sizeof(isc_boolean_t)); + client->query.dns64_aaaaok = NULL; + client->query.dns64_aaaaoklen = 0; + } + query_freefreeversions(client, everything); for (dbuf = ISC_LIST_HEAD(client->query.namebufs); @@ -310,13 +357,22 @@ query_reset(ns_client_t *client, isc_boolean_t everything) { NS_QUERYATTR_SECURE); client->query.restarts = 0; client->query.timerset = ISC_FALSE; + if (client->query.rpz_st != NULL) { + rpz_st_clear(client); + if (everything) { + isc_mem_put(client->mctx, client->query.rpz_st, + sizeof(*client->query.rpz_st)); + client->query.rpz_st = NULL; + } + } client->query.origqname = NULL; - client->query.qname = NULL; client->query.dboptions = 0; client->query.fetchoptions = 0; client->query.gluedb = NULL; client->query.authdbset = ISC_FALSE; client->query.isreferral = ISC_FALSE; + client->query.dns64_options = 0; + client->query.dns64_ttl = ISC_UINT32_MAX; } static void @@ -473,20 +529,6 @@ query_newrdataset(ns_client_t *client) { return (rdataset); } -static inline void -query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { - dns_rdataset_t *rdataset = *rdatasetp; - - CTRACE("query_putrdataset"); - if (rdataset != NULL) { - if (dns_rdataset_isassociated(rdataset)) - dns_rdataset_disassociate(rdataset); - dns_message_puttemprdataset(client->message, rdatasetp); - } - CTRACE("query_putrdataset: done"); -} - - static inline isc_result_t query_newdbversion(ns_client_t *client, unsigned int n) { unsigned int i; @@ -540,6 +582,7 @@ ns_query_init(ns_client_t *client) { ISC_LIST_INIT(client->query.freeversions); client->query.restarts = 0; client->query.timerset = ISC_FALSE; + client->query.rpz_st = NULL; client->query.qname = NULL; result = isc_mutex_init(&client->query.fetchlock); if (result != ISC_R_SUCCESS) @@ -549,6 +592,10 @@ ns_query_init(ns_client_t *client) { client->query.authzone = NULL; client->query.authdbset = ISC_FALSE; client->query.isreferral = ISC_FALSE; + client->query.dns64_aaaa = NULL; + client->query.dns64_sigaaaa = NULL; + client->query.dns64_aaaaok = NULL; + client->query.dns64_aaaaoklen = 0; query_reset(client, ISC_FALSE); result = query_newdbversion(client, 3); if (result != ISC_R_SUCCESS) { @@ -563,8 +610,7 @@ ns_query_init(ns_client_t *client) { } static inline ns_dbversion_t * -query_findversion(ns_client_t *client, dns_db_t *db, - isc_boolean_t *newzonep) +query_findversion(ns_client_t *client, dns_db_t *db) { ns_dbversion_t *dbversion; @@ -590,12 +636,11 @@ query_findversion(ns_client_t *client, dns_db_t *db, return (NULL); dns_db_attach(db, &dbversion->db); dns_db_currentversion(db, &dbversion->version); + dbversion->acl_checked = ISC_FALSE; dbversion->queryok = ISC_FALSE; ISC_LIST_APPEND(client->query.activeversions, dbversion, link); - *newzonep = ISC_TRUE; - } else - *newzonep = ISC_FALSE; + } return (dbversion); } @@ -607,7 +652,6 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name, dns_dbversion_t **versionp) { isc_result_t result; - isc_boolean_t check_acl, new_zone; dns_acl_t *queryacl; ns_dbversion_t *dbversion; @@ -623,7 +667,17 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name, if (!client->view->additionalfromauth && client->query.authdbset && db != client->query.authdb) - goto refuse; + return (DNS_R_REFUSED); + + /* + * Non recursive query to a static-stub zone is prohibited; its + * zone content is not public data, but a part of local configuration + * and should not be disclosed. + */ + if (dns_zone_gettype(zone) == dns_zone_staticstub && + !RECURSIONOK(client)) { + return (DNS_R_REFUSED); + } /* * If the zone has an ACL, we'll check it, otherwise @@ -633,23 +687,19 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name, * Also, get the database version to use. */ - check_acl = ISC_TRUE; /* Keep compiler happy. */ - queryacl = NULL; - /* * Get the current version of this database. */ - dbversion = query_findversion(client, db, &new_zone); - if (dbversion == NULL) { - result = DNS_R_SERVFAIL; - goto fail; - } - if (new_zone) { - check_acl = ISC_TRUE; - } else if (!dbversion->queryok) { - goto refuse; - } else { - check_acl = ISC_FALSE; + dbversion = query_findversion(client, db); + if (dbversion == NULL) + return (DNS_R_SERVFAIL); + + if ((options & DNS_GETDB_IGNOREACL) != 0) + goto approved; + if (dbversion->acl_checked) { + if (!dbversion->queryok) + return (DNS_R_REFUSED); + goto approved; } queryacl = dns_zone_getqueryacl(zone); @@ -663,88 +713,69 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name, * allowed to make queries, otherwise the query should * be refused. */ - check_acl = ISC_FALSE; + dbversion->acl_checked = ISC_TRUE; if ((client->query.attributes & - NS_QUERYATTR_QUERYOK) == 0) - goto refuse; - } else { - /* - * We haven't evaluated the view's queryacl yet. - */ - check_acl = ISC_TRUE; + NS_QUERYATTR_QUERYOK) == 0) { + dbversion->queryok = ISC_FALSE; + return (DNS_R_REFUSED); + } + dbversion->queryok = ISC_TRUE; + goto approved; } } - if (check_acl) { - isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); - - result = ns_client_checkaclsilent(client, NULL, queryacl, - ISC_TRUE); - if (log) { - char msg[NS_CLIENT_ACLMSGSIZE("query")]; - if (result == ISC_R_SUCCESS) { - if (isc_log_wouldlog(ns_g_lctx, - ISC_LOG_DEBUG(3))) - { - ns_client_aclmsg("query", name, qtype, - client->view->rdclass, - msg, sizeof(msg)); - ns_client_log(client, - DNS_LOGCATEGORY_SECURITY, - NS_LOGMODULE_QUERY, - ISC_LOG_DEBUG(3), - "%s approved", msg); - } - } else { + result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); + if ((options & DNS_GETDB_NOLOG) == 0) { + char msg[NS_CLIENT_ACLMSGSIZE("query")]; + if (result == ISC_R_SUCCESS) { + if (isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(3))) { ns_client_aclmsg("query", name, qtype, client->view->rdclass, msg, sizeof(msg)); - ns_client_log(client, DNS_LOGCATEGORY_SECURITY, - NS_LOGMODULE_QUERY, ISC_LOG_INFO, - "%s denied", msg); + ns_client_log(client, + DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, + ISC_LOG_DEBUG(3), + "%s approved", msg); } + } else { + ns_client_aclmsg("query", name, qtype, + client->view->rdclass, + msg, sizeof(msg)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, ISC_LOG_INFO, + "%s denied", msg); } + } - if (queryacl == client->view->queryacl) { - if (result == ISC_R_SUCCESS) { - /* - * We were allowed by the default - * "allow-query" ACL. Remember this so we - * don't have to check again. - */ - client->query.attributes |= - NS_QUERYATTR_QUERYOK; - } + if (queryacl == client->view->queryacl) { + if (result == ISC_R_SUCCESS) { /* - * We've now evaluated the view's query ACL, and - * the NS_QUERYATTR_QUERYOK attribute is now valid. + * We were allowed by the default + * "allow-query" ACL. Remember this so we + * don't have to check again. */ - client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; + client->query.attributes |= NS_QUERYATTR_QUERYOK; } - - if (result != ISC_R_SUCCESS) - goto refuse; + /* + * We've now evaluated the view's query ACL, and + * the NS_QUERYATTR_QUERYOK attribute is now valid. + */ + client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; } - /* Approved. */ - - /* - * Remember the result of the ACL check so we - * don't have to check again. - */ + dbversion->acl_checked = ISC_TRUE; + if (result != ISC_R_SUCCESS) { + dbversion->queryok = ISC_FALSE; + return (DNS_R_REFUSED); + } dbversion->queryok = ISC_TRUE; + approved: /* Transfer ownership, if necessary. */ if (versionp != NULL) *versionp = dbversion->version; - return (ISC_R_SUCCESS); - - refuse: - return (DNS_R_REFUSED); - - fail: - return (result); } static inline isc_result_t @@ -800,6 +831,97 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, return (result); } +static void +rpz_log(ns_client_t *client) { + char namebuf1[DNS_NAME_FORMATSIZE]; + char namebuf2[DNS_NAME_FORMATSIZE]; + dns_rpz_st_t *st; + const char *pat; + + if (!ns_g_server->log_queries || + !isc_log_wouldlog(ns_g_lctx, DNS_RPZ_INFO_LEVEL)) + return; + + st = client->query.rpz_st; + dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1)); + dns_name_format(st->qname, namebuf2, sizeof(namebuf2)); + + switch (st->m.policy) { + case DNS_RPZ_POLICY_NO_OP: + pat ="response policy %s rewrite %s NO-OP using %s"; + break; + case DNS_RPZ_POLICY_NXDOMAIN: + pat = "response policy %s rewrite %s to NXDOMAIN using %s"; + break; + case DNS_RPZ_POLICY_NODATA: + pat = "response policy %s rewrite %s to NODATA using %s"; + break; + case DNS_RPZ_POLICY_RECORD: + case DNS_RPZ_POLICY_CNAME: + pat = "response policy %s rewrite %s using %s"; + break; + default: + INSIST(0); + } + ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, + DNS_RPZ_INFO_LEVEL, pat, dns_rpz_type2str(st->m.type), + namebuf1, namebuf2); +} + +static void +rpz_fail_log(ns_client_t *client, int level, dns_rpz_type_t rpz_type, + dns_name_t *name, const char *str, isc_result_t result) +{ + char namebuf1[DNS_NAME_FORMATSIZE]; + char namebuf2[DNS_NAME_FORMATSIZE]; + + if (!ns_g_server->log_queries || !isc_log_wouldlog(ns_g_lctx, level)) + return; + + dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1)); + dns_name_format(name, namebuf2, sizeof(namebuf2)); + ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, + NS_LOGMODULE_QUERY, level, + "response policy %s rewrite %s via %s %sfailed: %s", + dns_rpz_type2str(rpz_type), + namebuf1, namebuf2, str, isc_result_totext(result)); +} + +/* + * Get a policy rewrite zone database. + */ +static isc_result_t +rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type, + dns_name_t *rpz_qname, dns_zone_t **zonep, + dns_db_t **dbp, dns_dbversion_t **versionp) +{ + char namebuf1[DNS_NAME_FORMATSIZE]; + char namebuf2[DNS_NAME_FORMATSIZE]; + dns_dbversion_t *rpz_version = NULL; + isc_result_t result; + + result = query_getzonedb(client, rpz_qname, dns_rdatatype_any, + DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version); + if (result == ISC_R_SUCCESS) { + if (ns_g_server->log_queries && + isc_log_wouldlog(ns_g_lctx, DNS_RPZ_DEBUG_LEVEL2)) { + dns_name_format(client->query.qname, namebuf1, + sizeof(namebuf1)); + dns_name_format(rpz_qname, namebuf2, sizeof(namebuf2)); + ns_client_log(client, NS_LOGCATEGORY_QUERIES, + NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2, + "try rpz %s rewrite %s via %s", + dns_rpz_type2str(rpz_type), + namebuf1, namebuf2); + } + *versionp = rpz_version; + return (ISC_R_SUCCESS); + } + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname, + "query_getzonedb() ", result); + return (result); +} + static inline isc_result_t query_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, dns_db_t **dbp, unsigned int options) @@ -1958,6 +2080,323 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname, CTRACE("query_addrdataset: done"); } +static isc_result_t +query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset, isc_buffer_t *dbuf, + dns_section_t section) +{ + dns_name_t *name, *mname; + dns_rdata_t *dns64_rdata; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t *dns64_rdatalist; + dns_rdataset_t *dns64_rdataset; + dns_rdataset_t *mrdataset; + isc_buffer_t *buffer; + isc_region_t r; + isc_result_t result; + dns_view_t *view = client->view; + isc_netaddr_t netaddr; + dns_dns64_t *dns64; + unsigned int flags = 0; + + /*% + * To the current response for 'client', add the answer RRset + * '*rdatasetp' and an optional signature set '*sigrdatasetp', with + * owner name '*namep', to section 'section', unless they are + * already there. Also add any pertinent additional data. + * + * If 'dbuf' is not NULL, then '*namep' is the name whose data is + * stored in 'dbuf'. In this case, query_addrrset() guarantees that + * when it returns the name will either have been kept or released. + */ + CTRACE("query_dns64"); + name = *namep; + mname = NULL; + mrdataset = NULL; + buffer = NULL; + dns64_rdata = NULL; + dns64_rdataset = NULL; + dns64_rdatalist = NULL; + result = dns_message_findname(client->message, section, + name, dns_rdatatype_aaaa, + rdataset->covers, + &mname, &mrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We've already got an RRset of the given name and type. + * There's nothing else to do; + */ + CTRACE("query_dns64: dns_message_findname succeeded: done"); + if (dbuf != NULL) + query_releasename(client, namep); + return (ISC_R_SUCCESS); + } else if (result == DNS_R_NXDOMAIN) { + /* + * The name doesn't exist. + */ + if (dbuf != NULL) + query_keepname(client, name, dbuf); + dns_message_addname(client->message, name, section); + *namep = NULL; + mname = name; + } else { + RUNTIME_CHECK(result == DNS_R_NXRRSET); + if (dbuf != NULL) + query_releasename(client, namep); + } + + if (rdataset->trust != dns_trust_secure && + (section == DNS_SECTION_ANSWER || + section == DNS_SECTION_AUTHORITY)) + client->query.attributes &= ~NS_QUERYATTR_SECURE; + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + + result = isc_buffer_allocate(client->mctx, &buffer, view->dns64cnt * + 16 * dns_rdataset_count(rdataset)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(client->message, &dns64_rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdatalist(client->message, + &dns64_rdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdataset_init(dns64_rdataset); + dns_rdatalist_init(dns64_rdatalist); + dns64_rdatalist->rdclass = dns_rdataclass_in; + dns64_rdatalist->type = dns_rdatatype_aaaa; + if (client->query.dns64_ttl != ISC_UINT32_MAX) + dns64_rdatalist->ttl = ISC_MIN(rdataset->ttl, + client->query.dns64_ttl); + else + dns64_rdatalist->ttl = ISC_MIN(rdataset->ttl, 600); + + if (RECURSIONOK(client)) + flags |= DNS_DNS64_RECURSIVE; + + /* + * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC + * as this provides a easy way to see if the answer was signed. + */ + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + flags |= DNS_DNS64_DNSSEC; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + for (dns64 = ISC_LIST_HEAD(client->view->dns64); + dns64 != NULL; dns64 = dns_dns64_next(dns64)) { + + dns_rdataset_current(rdataset, &rdata); + isc__buffer_availableregion(buffer, &r); + INSIST(r.length >= 16); + result = dns_dns64_aaaafroma(dns64, &netaddr, + client->signer, + &ns_g_server->aclenv, + flags, rdata.data, r.base); + if (result != ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); + continue; + } + isc_buffer_add(buffer, 16); + isc_buffer_remainingregion(buffer, &r); + isc_buffer_forward(buffer, 16); + result = dns_message_gettemprdata(client->message, + &dns64_rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdata_init(dns64_rdata); + dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in, + dns_rdatatype_aaaa, &r); + ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata, + link); + dns64_rdata = NULL; + dns_rdata_reset(&rdata); + } + } + if (result != ISC_R_NOMORE) + goto cleanup; + + if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) + goto cleanup; + + result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; + dns64_rdataset->trust = rdataset->trust; + query_addrdataset(client, mname, dns64_rdataset); + dns64_rdataset = NULL; + dns64_rdatalist = NULL; + dns_message_takebuffer(client->message, &buffer); + result = ISC_R_SUCCESS; + + cleanup: + if (buffer != NULL) + isc_buffer_free(&buffer); + + if (dns64_rdata != NULL) + dns_message_puttemprdata(client->message, &dns64_rdata); + + if (dns64_rdataset != NULL) + dns_message_puttemprdataset(client->message, &dns64_rdataset); + + if (dns64_rdatalist != NULL) { + for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata); + dns64_rdata != NULL; + dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata)) + { + ISC_LIST_UNLINK(dns64_rdatalist->rdata, + dns64_rdata, link); + dns_message_puttemprdata(client->message, &dns64_rdata); + } + dns_message_puttemprdatalist(client->message, &dns64_rdatalist); + } + + CTRACE("query_dns64: done"); + return (result); +} + +static void +query_filter64(ns_client_t *client, dns_name_t **namep, + dns_rdataset_t *rdataset, isc_buffer_t *dbuf, + dns_section_t section) +{ + dns_name_t *name, *mname; + dns_rdata_t *myrdata; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t *myrdatalist; + dns_rdataset_t *myrdataset; + isc_buffer_t *buffer; + isc_region_t r; + isc_result_t result; + unsigned int i; + + CTRACE("query_filter64"); + + INSIST(client->query.dns64_aaaaok != NULL); + INSIST(client->query.dns64_aaaaoklen == dns_rdataset_count(rdataset)); + + name = *namep; + mname = NULL; + buffer = NULL; + myrdata = NULL; + myrdataset = NULL; + myrdatalist = NULL; + result = dns_message_findname(client->message, section, + name, dns_rdatatype_aaaa, + rdataset->covers, + &mname, &myrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We've already got an RRset of the given name and type. + * There's nothing else to do; + */ + CTRACE("query_filter64: dns_message_findname succeeded: done"); + if (dbuf != NULL) + query_releasename(client, namep); + return; + } else if (result == DNS_R_NXDOMAIN) { + mname = name; + *namep = NULL; + } else { + RUNTIME_CHECK(result == DNS_R_NXRRSET); + if (dbuf != NULL) + query_releasename(client, namep); + dbuf = NULL; + } + + if (rdataset->trust != dns_trust_secure && + (section == DNS_SECTION_ANSWER || + section == DNS_SECTION_AUTHORITY)) + client->query.attributes &= ~NS_QUERYATTR_SECURE; + + result = isc_buffer_allocate(client->mctx, &buffer, + 16 * dns_rdataset_count(rdataset)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(client->message, &myrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdatalist(client->message, &myrdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdataset_init(myrdataset); + dns_rdatalist_init(myrdatalist); + myrdatalist->rdclass = dns_rdataclass_in; + myrdatalist->type = dns_rdatatype_aaaa; + myrdatalist->ttl = rdataset->ttl; + + i = 0; + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + if (!client->query.dns64_aaaaok[i++]) + continue; + dns_rdataset_current(rdataset, &rdata); + INSIST(rdata.length == 16); + isc_buffer_putmem(buffer, rdata.data, rdata.length); + isc_buffer_remainingregion(buffer, &r); + isc_buffer_forward(buffer, rdata.length); + result = dns_message_gettemprdata(client->message, &myrdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdata_init(myrdata); + dns_rdata_fromregion(myrdata, dns_rdataclass_in, + dns_rdatatype_aaaa, &r); + ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link); + myrdata = NULL; + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto cleanup; + + result = dns_rdatalist_tordataset(myrdatalist, myrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; + if (mname == name) { + if (dbuf != NULL) + query_keepname(client, name, dbuf); + dns_message_addname(client->message, name, section); + dbuf = NULL; + } + myrdataset->trust = rdataset->trust; + query_addrdataset(client, mname, myrdataset); + myrdataset = NULL; + myrdatalist = NULL; + dns_message_takebuffer(client->message, &buffer); + + cleanup: + if (buffer != NULL) + isc_buffer_free(&buffer); + + if (myrdata != NULL) + dns_message_puttemprdata(client->message, &myrdata); + + if (myrdataset != NULL) + dns_message_puttemprdataset(client->message, &myrdataset); + + if (myrdatalist != NULL) { + for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata); + myrdata != NULL; + myrdata = ISC_LIST_HEAD(myrdatalist->rdata)) + { + ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link); + dns_message_puttemprdata(client->message, &myrdata); + } + dns_message_puttemprdatalist(client->message, &myrdatalist); + } + if (dbuf != NULL) + query_releasename(client, &name); + + CTRACE("query_filter64: done"); +} + static void query_addrrset(ns_client_t *client, dns_name_t **namep, dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp, @@ -2036,7 +2475,7 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, static inline isc_result_t query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, - isc_boolean_t zero_ttl, isc_boolean_t isassociated) + unsigned int override_ttl, isc_boolean_t isassociated) { dns_name_t *name; dns_dbnode_t *node; @@ -2119,10 +2558,11 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) goto cleanup; - if (zero_ttl) { - rdataset->ttl = 0; + if (override_ttl != ISC_UINT32_MAX && + override_ttl < rdataset->ttl) { + rdataset->ttl = override_ttl; if (sigrdataset != NULL) - sigrdataset->ttl = 0; + sigrdataset->ttl = override_ttl; } /* @@ -2246,67 +2686,79 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { return (eresult); } -static inline isc_result_t -query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname, - dns_rdataset_t *dname, dns_name_t **anamep, - dns_rdatatype_t type) +static isc_result_t +query_add_cname(ns_client_t *client, dns_name_t *qname, dns_name_t *tname, + dns_trust_t trust, dns_ttl_t ttl) { dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; - isc_result_t result; isc_region_t r; + dns_name_t *aname; + isc_result_t result; /* * We assume the name data referred to by tname won't go away. */ - REQUIRE(anamep != NULL); + aname = NULL; + result = dns_message_gettempname(client->message, &aname); + if (result != ISC_R_SUCCESS) + return (result); + result = dns_name_dup(qname, client->mctx, aname); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &aname); + return (result); + } rdatalist = NULL; result = dns_message_gettemprdatalist(client->message, &rdatalist); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &aname); return (result); + } rdata = NULL; result = dns_message_gettemprdata(client->message, &rdata); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(client->message, &aname); + dns_message_puttemprdatalist(client->message, &rdatalist); return (result); + } rdataset = NULL; result = dns_message_gettemprdataset(client->message, &rdataset); - if (result != ISC_R_SUCCESS) - return (result); - dns_rdataset_init(rdataset); - result = dns_name_dup(qname, client->mctx, *anamep); if (result != ISC_R_SUCCESS) { - dns_message_puttemprdataset(client->message, &rdataset); + dns_message_puttempname(client->message, &aname); + dns_message_puttemprdatalist(client->message, &rdatalist); + dns_message_puttemprdata(client->message, &rdata); return (result); } - - rdatalist->type = type; + dns_rdataset_init(rdataset); + rdatalist->type = dns_rdatatype_cname; rdatalist->covers = 0; rdatalist->rdclass = client->message->rdclass; - rdatalist->ttl = dname->ttl; + rdatalist->ttl = ttl; dns_name_toregion(tname, &r); rdata->data = r.base; rdata->length = r.length; rdata->rdclass = client->message->rdclass; - rdata->type = type; + rdata->type = dns_rdatatype_cname; ISC_LIST_INIT(rdatalist->rdata); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS); - rdataset->trust = dname->trust; + rdataset->trust = trust; - query_addrrset(client, anamep, &rdataset, NULL, NULL, + query_addrrset(client, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER); - if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); dns_message_puttemprdataset(client->message, &rdataset); } + if (aname != NULL) + dns_message_puttempname(client->message, &aname); return (ISC_R_SUCCESS); } @@ -2860,7 +3312,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db, * j.example -> z.i.example NSEC example * owner common example * next common example - * wild *.f.example + * wild *.example */ options = client->query.dboptions | DNS_DBFIND_NOWILD; dns_fixedname_init(&wfixed); @@ -3196,8 +3648,9 @@ query_resume(isc_task_t *task, isc_event_t *event) { } static isc_result_t -query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, - dns_rdataset_t *nameservers, isc_boolean_t resuming) +query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, + dns_name_t *qdomain, dns_rdataset_t *nameservers, + isc_boolean_t resuming) { isc_result_t result; dns_rdataset_t *rdataset, *sigrdataset; @@ -3229,7 +3682,11 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "recursive-clients soft limit " - "exceeded, aborting oldest query"); + "exceeded (%d/%d/%d), " + "aborting oldest query", + client->recursionquota->used, + client->recursionquota->soft, + client->recursionquota->max); } ns_client_killoldestquery(client); result = ISC_R_SUCCESS; @@ -3242,7 +3699,11 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, - "no more recursive clients: %s", + "no more recursive clients " + "(%d/%d/%d): %s", + ns_g_server->recursionquota.used, + ns_g_server->recursionquota.soft, + ns_g_server->recursionquota.max, isc_result_totext(result)); } ns_client_killoldestquery(client); @@ -3289,8 +3750,7 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, else peeraddr = NULL; result = dns_resolver_createfetch2(client->view->resolver, - client->query.qname, - qtype, qdomain, nameservers, + qname, qtype, qdomain, nameservers, NULL, peeraddr, client->message->id, client->query.fetchoptions, client->task, @@ -3313,6 +3773,696 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, return (result); } +static inline void +rpz_clean(dns_zone_t **zonep, dns_db_t **dbp, dns_dbnode_t **nodep, + dns_rdataset_t **rdatasetp) +{ + if (nodep != NULL && *nodep != NULL) { + REQUIRE(dbp != NULL && *dbp != NULL); + dns_db_detachnode(*dbp, nodep); + } + if (dbp != NULL && *dbp != NULL) + dns_db_detach(dbp); + if (zonep != NULL && *zonep != NULL) + dns_zone_detach(zonep); + if (rdatasetp != NULL && *rdatasetp != NULL && + dns_rdataset_isassociated(*rdatasetp)) + dns_rdataset_disassociate(*rdatasetp); +} + +static inline isc_result_t +rpz_ready(ns_client_t *client, dns_zone_t **zonep, dns_db_t **dbp, + dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp) +{ + REQUIRE(rdatasetp != NULL); + + rpz_clean(zonep, dbp, nodep, rdatasetp); + if (*rdatasetp == NULL) { + *rdatasetp = query_newrdataset(client); + if (*rdatasetp == NULL) + return (DNS_R_SERVFAIL); + } + return (ISC_R_SUCCESS); +} + +static void +rpz_st_clear(ns_client_t *client) { + dns_rpz_st_t *st = client->query.rpz_st; + + rpz_clean(&st->m.zone, &st->m.db, &st->m.node, NULL); + if (st->m.rdataset != NULL) + query_putrdataset(client, &st->m.rdataset); + + rpz_clean(NULL, &st->ns.db, NULL, NULL); + if (st->ns.ns_rdataset != NULL) + query_putrdataset(client, &st->ns.ns_rdataset); + if (st->ns.r_rdataset != NULL) + query_putrdataset(client, &st->ns.r_rdataset); + + rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL); + if (st->q.rdataset != NULL) + query_putrdataset(client, &st->q.rdataset); + if (st->q.sigrdataset != NULL) + query_putrdataset(client, &st->q.sigrdataset); + st->state = 0; +} + +/* + * Get NS, A, or AAAA rrset for rpz nsdname or nsip checking. + */ +static isc_result_t +rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, + dns_db_t **dbp, dns_dbversion_t *version, + dns_rdataset_t **rdatasetp, isc_boolean_t resuming) +{ + dns_rpz_st_t *st; + isc_boolean_t is_zone; + dns_dbnode_t *node; + dns_fixedname_t fixed; + dns_name_t *found; + isc_result_t result; + + st = client->query.rpz_st; + if ((st->state & DNS_RPZ_RECURSING) != 0) { + INSIST(st->ns.r_type == type); + INSIST(dns_name_equal(name, st->r_name)); + INSIST(*rdatasetp == NULL || + !dns_rdataset_isassociated(*rdatasetp)); + st->state &= ~DNS_RPZ_RECURSING; + *dbp = st->ns.db; + st->ns.db = NULL; + if (*rdatasetp != NULL) + query_putrdataset(client, rdatasetp); + *rdatasetp = st->ns.r_rdataset; + st->ns.r_rdataset = NULL; + result = st->ns.r_result; + if (result == DNS_R_DELEGATION) { + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, + DNS_RPZ_TYPE_NSIP, name, + "rpz_ns_find() ", result); + st->m.policy = DNS_RPZ_POLICY_ERROR; + result = DNS_R_SERVFAIL; + } + return (result); + } + + result = rpz_ready(client, NULL, NULL, NULL, rdatasetp); + if (result != ISC_R_SUCCESS) { + st->m.policy = DNS_RPZ_POLICY_ERROR; + return (result); + } + if (*dbp != NULL) { + is_zone = ISC_FALSE; + } else { + dns_zone_t *zone; + + version = NULL; + zone = NULL; + result = query_getdb(client, name, type, 0, &zone, dbp, + &version, &is_zone); + if (result != ISC_R_SUCCESS) { + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, + DNS_RPZ_TYPE_NSIP, name, "NS getdb() ", + result); + st->m.policy = DNS_RPZ_POLICY_ERROR; + if (zone != NULL) + dns_zone_detach(&zone); + return (result); + } + if (zone != NULL) + dns_zone_detach(&zone); + } + + node = NULL; + dns_fixedname_init(&fixed); + found = dns_fixedname_name(&fixed); + result = dns_db_find(*dbp, name, version, type, 0, client->now, &node, + found, *rdatasetp, NULL); + if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) { + /* + * Try the cache if we're authoritative for an + * ancestor but not the domain itself. + */ + rpz_clean(NULL, dbp, &node, rdatasetp); + version = NULL; + dns_db_attach(client->view->cachedb, dbp); + result = dns_db_find(*dbp, name, version, dns_rdatatype_ns, + 0, client->now, &node, found, + *rdatasetp, NULL); + } + rpz_clean(NULL, dbp, &node, NULL); + if (result == DNS_R_DELEGATION) { + /* + * Recurse to get NS rrset or A or AAAA rrset for an NS name. + */ + rpz_clean(NULL, NULL, NULL, rdatasetp); + dns_name_copy(name, st->r_name, NULL); + result = query_recurse(client, type, st->r_name, NULL, NULL, + resuming); + if (result == ISC_R_SUCCESS) { + st->state |= DNS_RPZ_RECURSING; + result = DNS_R_DELEGATION; + } + } + return (result); +} + +/* + * Check the IP address in an A or AAAA rdataset against + * the IP or NSIP response policy rules of a view. + */ +static isc_result_t +rpz_rewrite_ip(ns_client_t *client, dns_rdataset_t *rdataset, + dns_rpz_type_t rpz_type) +{ + dns_rpz_st_t *st; + dns_dbversion_t *version; + dns_zone_t *zone; + dns_db_t *db; + dns_rpz_zone_t *new_rpz; + isc_result_t result; + + st = client->query.rpz_st; + if (st->m.rdataset == NULL) { + st->m.rdataset = query_newrdataset(client); + if (st->m.rdataset == NULL) + return (DNS_R_SERVFAIL); + } + zone = NULL; + db = NULL; + for (new_rpz = ISC_LIST_HEAD(client->view->rpz_zones); + new_rpz != NULL; + new_rpz = ISC_LIST_NEXT(new_rpz, link)) { + version = NULL; + + /* + * Find the database for this policy zone to get its + * radix tree. + */ + result = rpz_getdb(client, rpz_type, &new_rpz->origin, + &zone, &db, &version); + if (result != ISC_R_SUCCESS) { + rpz_clean(&zone, &db, NULL, NULL); + continue; + } + /* + * Look for a better (e.g. longer prefix) hit for an IP address + * in this rdataset in this radix tree than than the previous + * hit, if any. Note the domain name and quality of the + * best hit. + */ + result = dns_db_rpz_findips(new_rpz, rpz_type, zone, db, + version, rdataset, st); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + rpz_clean(&zone, &db, NULL, NULL); + } + return (ISC_R_SUCCESS); +} + +static isc_result_t +rpz_rewrite_nsip(ns_client_t *client, dns_rdatatype_t type, dns_name_t *name, + dns_db_t **dbp, dns_dbversion_t *version, + dns_rdataset_t **rdatasetp, isc_boolean_t resuming) +{ + isc_result_t result; + + result = rpz_ns_find(client, name, type, dbp, version, rdatasetp, + resuming); + switch (result) { + case ISC_R_SUCCESS: + result = rpz_rewrite_ip(client, *rdatasetp, DNS_RPZ_TYPE_NSIP); + break; + case DNS_R_EMPTYNAME: + case DNS_R_EMPTYWILD: + case DNS_R_NXDOMAIN: + case DNS_R_NCACHENXDOMAIN: + case DNS_R_NXRRSET: + case DNS_R_NCACHENXRRSET: + result = ISC_R_SUCCESS; + break; + case DNS_R_DELEGATION: + case DNS_R_DUPLICATE: + case DNS_R_DROP: + break; + default: + if (client->query.rpz_st->m.policy != DNS_RPZ_POLICY_ERROR) { + client->query.rpz_st->m.policy = DNS_RPZ_POLICY_ERROR; + rpz_fail_log(client, ISC_LOG_WARNING, DNS_RPZ_TYPE_NSIP, + name, "NS address rewrite nsip ", result); + } + break; + } + return (result); +} + +/* + * Get the rrset from a response policy zone. + */ +static isc_result_t +rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef, + dns_name_t *sname, dns_rpz_type_t rpz_type, dns_zone_t **zonep, + dns_db_t **dbp, dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp, + dns_rpz_policy_t *policyp) +{ + dns_dbversion_t *version; + dns_rpz_policy_t policy; + dns_fixedname_t fixed; + dns_name_t *found; + isc_result_t result; + + result = rpz_ready(client, zonep, dbp, nodep, rdatasetp); + if (result != ISC_R_SUCCESS) { + *policyp = DNS_RPZ_POLICY_ERROR; + return (result); + } + + /* + * Try to get either a CNAME or the type of record demanded by the + * request from the policy zone. + */ + version = NULL; + result = rpz_getdb(client, rpz_type, qnamef, zonep, dbp, &version); + if (result != ISC_R_SUCCESS) { + *policyp = DNS_RPZ_POLICY_MISS; + return (DNS_R_NXDOMAIN); + } + + dns_fixedname_init(&fixed); + found = dns_fixedname_name(&fixed); + result = dns_db_find(*dbp, qnamef, version, dns_rdatatype_any, 0, + client->now, nodep, found, *rdatasetp, NULL); + if (result == ISC_R_SUCCESS) { + dns_rdatasetiter_t *rdsiter; + + rdsiter = NULL; + result = dns_db_allrdatasets(*dbp, *nodep, version, 0, + &rdsiter); + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(*dbp, nodep); + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type, + qnamef, "allrdatasets()", result); + *policyp = DNS_RPZ_POLICY_ERROR; + return (DNS_R_SERVFAIL); + } + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) { + dns_rdatasetiter_current(rdsiter, *rdatasetp); + if ((*rdatasetp)->type == dns_rdatatype_cname || + (*rdatasetp)->type == qtype) + break; + dns_rdataset_disassociate(*rdatasetp); + } + dns_rdatasetiter_destroy(&rdsiter); + if (result != ISC_R_SUCCESS) { + if (result != ISC_R_NOMORE) { + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, + rpz_type, qnamef, "rdatasetiter", + result); + *policyp = DNS_RPZ_POLICY_ERROR; + return (DNS_R_SERVFAIL); + } + /* + * Ask again to get the right DNS_R_DNAME/NXRRSET/... + * result if there is neither a CNAME nor target type. + */ + if (dns_rdataset_isassociated(*rdatasetp)) + dns_rdataset_disassociate(*rdatasetp); + dns_db_detachnode(*dbp, nodep); + + if (qtype == dns_rdatatype_rrsig || + qtype == dns_rdatatype_sig) + result = DNS_R_NXRRSET; + else + result = dns_db_find(*dbp, qnamef, version, + qtype, 0, client->now, + nodep, found, *rdatasetp, + NULL); + } + } + switch (result) { + case ISC_R_SUCCESS: + if ((*rdatasetp)->type != dns_rdatatype_cname) { + policy = DNS_RPZ_POLICY_RECORD; + } else { + policy = dns_rpz_decode_cname(*rdatasetp, sname); + if (policy == DNS_RPZ_POLICY_RECORD && + qtype != dns_rdatatype_cname && + qtype != dns_rdatatype_any) + result = DNS_R_CNAME; + } + break; + case DNS_R_DNAME: + /* + * DNAME policy RRs have very few if any uses that are not + * better served with simple wildcards. Making the work would + * require complications to get the number of labels matched + * in the name or the found name itself to the main DNS_R_DNAME + * case in query_find(). So fall through to treat them as NODATA. + */ + case DNS_R_NXRRSET: + policy = DNS_RPZ_POLICY_NODATA; + break; + case DNS_R_NXDOMAIN: + case DNS_R_EMPTYNAME: + /* + * If we don't get a qname hit, + * see if it is worth looking for other types. + */ + dns_db_rpz_enabled(*dbp, client->query.rpz_st); + dns_db_detach(dbp); + dns_zone_detach(zonep); + policy = DNS_RPZ_POLICY_MISS; + break; + default: + dns_db_detach(dbp); + dns_zone_detach(zonep); + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type, qnamef, + "", result); + policy = DNS_RPZ_POLICY_ERROR; + result = DNS_R_SERVFAIL; + break; + } + + *policyp = policy; + return (result); +} + +/* + * Build and look for a QNAME or NSDNAME owner name in a response policy zone. + */ +static isc_result_t +rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, + dns_rpz_type_t rpz_type, dns_rdataset_t **rdatasetp) +{ + dns_rpz_st_t *st; + dns_rpz_zone_t *rpz; + dns_fixedname_t prefixf, rpz_qnamef; + dns_name_t *prefix, *suffix, *rpz_qname; + dns_zone_t *zone; + dns_db_t *db; + dns_dbnode_t *node; + dns_rpz_policy_t policy; + unsigned int labels; + isc_result_t result; + + st = client->query.rpz_st; + zone = NULL; + db = NULL; + node = NULL; + + for (rpz = ISC_LIST_HEAD(client->view->rpz_zones); + rpz != NULL; + rpz = ISC_LIST_NEXT(rpz, link)) { + /* + * Construct the rule's owner name. + */ + dns_fixedname_init(&prefixf); + prefix = dns_fixedname_name(&prefixf); + dns_name_split(qname, 1, prefix, NULL); + if (rpz_type == DNS_RPZ_TYPE_NSDNAME) + suffix = &rpz->nsdname; + else + suffix = &rpz->origin; + dns_fixedname_init(&rpz_qnamef); + rpz_qname = dns_fixedname_name(&rpz_qnamef); + for (;;) { + result = dns_name_concatenate(prefix, suffix, + rpz_qname, NULL); + if (result == ISC_R_SUCCESS) + break; + INSIST(result == DNS_R_NAMETOOLONG); + labels = dns_name_countlabels(prefix); + if (labels < 2) { + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, + rpz_type, suffix, + "concatentate() ", result); + return (ISC_R_SUCCESS); + } + if (labels+1 == dns_name_countlabels(qname)) { + rpz_fail_log(client, DNS_RPZ_DEBUG_LEVEL1, + rpz_type, suffix, + "concatentate() ", result); + } + dns_name_split(prefix, labels - 1, NULL, prefix); + } + + /* + * See if the qname rule (or RR) exists. + */ + result = rpz_find(client, qtype, rpz_qname, qname, rpz_type, + &zone, &db, &node, rdatasetp, &policy); + switch (result) { + case DNS_R_NXDOMAIN: + case DNS_R_EMPTYNAME: + break; + case DNS_R_SERVFAIL: + rpz_clean(&zone, &db, &node, rdatasetp); + st->m.policy = DNS_RPZ_POLICY_ERROR; + return (DNS_R_SERVFAIL); + default: + /* + * when more than one name or address hits a rule, + * prefer the first set of names (qname or NS), + * the first policy zone, and the smallest name + */ + if (st->m.type == rpz_type && + rpz->num > st->m.rpz->num && + 0 <= dns_name_compare(rpz_qname, st->qname)) + continue; + rpz_clean(&st->m.zone, &st->m.db, &st->m.node, + &st->m.rdataset); + st->m.rpz = rpz; + st->m.type = rpz_type; + st->m.prefix = 0; + st->m.policy = policy; + st->m.result = result; + dns_name_copy(rpz_qname, st->qname, NULL); + if (dns_rdataset_isassociated(*rdatasetp)) { + dns_rdataset_t *trdataset; + + trdataset = st->m.rdataset; + st->m.rdataset = *rdatasetp; + *rdatasetp = trdataset; + st->m.ttl = st->m.rdataset->ttl; + } else { + st->m.ttl = DNS_RPZ_TTL_DEFAULT; + } + st->m.node = node; + node = NULL; + st->m.db = db; + db = NULL; + st->m.zone = zone; + zone = NULL; + } + } + + rpz_clean(&zone, &db, &node, rdatasetp); + return (ISC_R_SUCCESS); +} + +/* + * Look for response policy zone NSIP and NSDNAME rewriting. + */ +static isc_result_t +rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, + isc_boolean_t resuming) +{ + dns_rpz_st_t *st; + dns_db_t *ipdb; + dns_rdataset_t *rdataset; + dns_fixedname_t nsnamef; + dns_name_t *nsname; + dns_dbversion_t *version; + isc_result_t result; + + ipdb = NULL; + rdataset = NULL; + + st = client->query.rpz_st; + if (st == NULL) { + st = isc_mem_get(client->mctx, sizeof(*st)); + if (st == NULL) + return (ISC_R_NOMEMORY); + st->state = 0; + memset(&st->m, 0, sizeof(st->m)); + memset(&st->ns, 0, sizeof(st->ns)); + memset(&st->q, 0, sizeof(st->q)); + dns_fixedname_init(&st->_qnamef); + dns_fixedname_init(&st->_r_namef); + dns_fixedname_init(&st->_fnamef); + st->qname = dns_fixedname_name(&st->_qnamef); + st->r_name = dns_fixedname_name(&st->_r_namef); + st->fname = dns_fixedname_name(&st->_fnamef); + client->query.rpz_st = st; + } + if ((st->state & DNS_RPZ_DONE_QNAME) == 0) { + st->state = DNS_RPZ_DONE_QNAME; + st->m.type = DNS_RPZ_TYPE_BAD; + st->m.policy = DNS_RPZ_POLICY_MISS; + + /* + * Check rules for the name if this it the first time, + * i.e. we've not been recursing. + */ + result = DNS_R_SERVFAIL; + st->state &= ~(DNS_RPZ_HAVE_IP | DNS_RPZ_HAVE_NSIPv4 | + DNS_RPZ_HAVE_NSIPv6 | DNS_RPZ_HAD_NSDNAME); + result = rpz_rewrite_name(client, qtype, client->query.qname, + DNS_RPZ_TYPE_QNAME, &rdataset); + if (st->m.policy != DNS_RPZ_POLICY_MISS) + goto cleanup; + if ((st->state & (DNS_RPZ_HAVE_NSIPv4 | DNS_RPZ_HAVE_NSIPv6 | + DNS_RPZ_HAD_NSDNAME)) == 0) + goto cleanup; + st->ns.label = dns_name_countlabels(client->query.qname); + } + + dns_fixedname_init(&nsnamef); + dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef)); + while (st->ns.label > 1 && st->m.policy == DNS_RPZ_POLICY_MISS) { + if (st->ns.label == dns_name_countlabels(client->query.qname)) { + nsname = client->query.qname; + } else { + nsname = dns_fixedname_name(&nsnamef); + dns_name_split(client->query.qname, st->ns.label, + NULL, nsname); + } + if (st->ns.ns_rdataset == NULL || + !dns_rdataset_isassociated(st->ns.ns_rdataset)) { + dns_db_t *db = NULL; + result = rpz_ns_find(client, nsname, dns_rdatatype_ns, + &db, NULL, &st->ns.ns_rdataset, + resuming); + if (db != NULL) + dns_db_detach(&db); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_DELEGATION) + goto cleanup; + if (result == DNS_R_EMPTYNAME || + result == DNS_R_NXRRSET || + result == DNS_R_EMPTYWILD || + result == DNS_R_NXDOMAIN || + result == DNS_R_NCACHENXDOMAIN || + result == DNS_R_NCACHENXRRSET || + result == DNS_R_CNAME || + result == DNS_R_DNAME) { + rpz_fail_log(client, + DNS_RPZ_DEBUG_LEVEL2, + DNS_RPZ_TYPE_NSIP, nsname, + "NS db_find() ", result); + dns_rdataset_disassociate(st->ns. + ns_rdataset); + st->ns.label--; + continue; + } + if (st->m.policy != DNS_RPZ_POLICY_ERROR) { + rpz_fail_log(client, DNS_RPZ_INFO_LEVEL, + DNS_RPZ_TYPE_NSIP, nsname, + "NS db_find() ", result); + st->m.policy = DNS_RPZ_POLICY_ERROR; + } + goto cleanup; + } + result = dns_rdataset_first(st->ns.ns_rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + /* + * Check all NS names. + */ + do { + dns_rdata_ns_t ns; + dns_rdata_t nsrdata = DNS_RDATA_INIT; + + dns_rdataset_current(st->ns.ns_rdataset, &nsrdata); + result = dns_rdata_tostruct(&nsrdata, &ns, NULL); + dns_rdata_reset(&nsrdata); + if (result != ISC_R_SUCCESS) { + rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, + DNS_RPZ_TYPE_NSIP, nsname, + "rdata_tostruct() ", result); + st->m.policy = DNS_RPZ_POLICY_ERROR; + goto cleanup; + } + if ((st->state & DNS_RPZ_HAD_NSDNAME) != 0) { + result = rpz_rewrite_name(client, qtype, + &ns.name, + DNS_RPZ_TYPE_NSDNAME, + &rdataset); + if (result != ISC_R_SUCCESS) { + dns_rdata_freestruct(&ns); + goto cleanup; + } + } + /* + * Check all IP addresses for this NS name, but don't + * bother without NSIP rules or with a NSDNAME hit. + */ + version = NULL; + if ((st->state & DNS_RPZ_HAVE_NSIPv4) != 0 && + st->m.type != DNS_RPZ_TYPE_NSDNAME && + (st->state & DNS_RPZ_DONE_A) == 0) { + result = rpz_rewrite_nsip(client, + dns_rdatatype_a, + &ns.name, &ipdb, + version, &rdataset, + resuming); + if (result == ISC_R_SUCCESS) + st->state |= DNS_RPZ_DONE_A; + } + if (result == ISC_R_SUCCESS && + (st->state & DNS_RPZ_HAVE_NSIPv6) != 0 && + st->m.type != DNS_RPZ_TYPE_NSDNAME) { + result = rpz_rewrite_nsip(client, + dns_rdatatype_aaaa, + &ns.name, &ipdb, version, + &rdataset, resuming); + } + dns_rdata_freestruct(&ns); + if (ipdb != NULL) + dns_db_detach(&ipdb); + if (result != ISC_R_SUCCESS) + goto cleanup; + st->state &= ~DNS_RPZ_DONE_A; + result = dns_rdataset_next(st->ns.ns_rdataset); + } while (result == ISC_R_SUCCESS); + dns_rdataset_disassociate(st->ns.ns_rdataset); + st->ns.label--; + } + + /* + * Use the best, if any, hit. + */ + result = ISC_R_SUCCESS; + +cleanup: + if (st->m.policy != DNS_RPZ_POLICY_MISS && + st->m.policy != DNS_RPZ_POLICY_NO_OP && + st->m.policy != DNS_RPZ_POLICY_ERROR && + st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN) + st->m.policy = st->m.rpz->policy; + if (st->m.policy == DNS_RPZ_POLICY_NO_OP) + rpz_log(client); + if (st->m.policy == DNS_RPZ_POLICY_MISS || + st->m.policy == DNS_RPZ_POLICY_NO_OP || + st->m.policy == DNS_RPZ_POLICY_ERROR) + rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset); + if (st->m.policy != DNS_RPZ_POLICY_MISS) + st->state |= DNS_RPZ_REWRITTEN; + if (st->m.policy == DNS_RPZ_POLICY_ERROR) { + st->m.type = DNS_RPZ_TYPE_BAD; + result = DNS_R_SERVFAIL; + } + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if ((st->state & DNS_RPZ_RECURSING) == 0) { + rpz_clean(NULL, &st->ns.db, NULL, &st->ns.ns_rdataset); + } + + return (result); +} + #define MAX_RESTARTS 16 #define QUERY_ERROR(r) \ @@ -3698,6 +4848,99 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, return; } +#ifdef ALLOW_FILTER_AAAA_ON_V4 +static isc_boolean_t +is_v4_client(ns_client_t *client) { + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) + return (ISC_TRUE); + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) + return (ISC_TRUE); + return (ISC_FALSE); +} +#endif + +static isc_uint32_t +dns64_ttl(dns_db_t *db, dns_dbversion_t *version) { + dns_dbnode_t *node = NULL; + dns_rdata_soa_t soa; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + isc_result_t result; + isc_uint32_t ttl = ISC_UINT32_MAX; + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, + 0, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_rdataset_first(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ttl = ISC_MIN(rdataset.ttl, soa.minimum); + +cleanup: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (ttl); +} + +static isc_boolean_t +dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + isc_netaddr_t netaddr; + dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64); + unsigned int flags = 0; + unsigned int i, count; + isc_boolean_t *aaaaok; + + INSIST(client->query.dns64_aaaaok == NULL); + INSIST(client->query.dns64_aaaaoklen == 0); + INSIST(client->query.dns64_aaaa == NULL); + INSIST(client->query.dns64_sigaaaa == NULL); + + if (dns64 == NULL) + return (ISC_TRUE); + + if (RECURSIONOK(client)) + flags |= DNS_DNS64_RECURSIVE; + + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + flags |= DNS_DNS64_DNSSEC; + + count = dns_rdataset_count(rdataset); + aaaaok = isc_mem_get(client->mctx, sizeof(isc_boolean_t) * count); + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, + &ns_g_server->aclenv, flags, rdataset, + aaaaok, count)) { + for (i = 0; i < count; i++) { + if (aaaaok != NULL && !aaaaok[i]) { + client->query.dns64_aaaaok = aaaaok; + client->query.dns64_aaaaoklen = count; + break; + } + } + if (i == count) + isc_mem_put(client->mctx, aaaaok, + sizeof(isc_boolean_t) * count); + return (ISC_TRUE); + } + isc_mem_put(client->mctx, aaaaok, sizeof(isc_boolean_t) * count); + return (ISC_FALSE); +} + /* * Do the bulk of query processing for the current query of 'client'. * If 'event' is non-NULL, we are returning from recursion and 'qtype' @@ -3716,6 +4959,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdatasetiter_t *rdsiter; isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof; + isc_boolean_t is_staticstub_zone; unsigned int n, nlabels; dns_namereln_t namereln; int order; @@ -3731,8 +4975,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) unsigned int options; isc_boolean_t empty_wild; dns_rdataset_t *noqname; + dns_rpz_st_t *rpz_st; isc_boolean_t resuming; int line = -1; + isc_boolean_t dns64_exclude, dns64; CTRACE("query_find"); @@ -3758,28 +5004,67 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) zone = NULL; need_wildcardproof = ISC_FALSE; empty_wild = ISC_FALSE; + dns64_exclude = dns64 = ISC_FALSE; options = 0; resuming = ISC_FALSE; is_zone = ISC_FALSE; + is_staticstub_zone = ISC_FALSE; if (event != NULL) { /* * We're returning from recursion. Restore the query context * and resume. */ - want_restart = ISC_FALSE; - authoritative = ISC_FALSE; - qtype = event->qtype; + rpz_st = client->query.rpz_st; + if (rpz_st != NULL && + (rpz_st->state & DNS_RPZ_RECURSING) != 0) { + is_zone = rpz_st->q.is_zone; + authoritative = rpz_st->q.authoritative; + zone = rpz_st->q.zone; + rpz_st->q.zone = NULL; + node = rpz_st->q.node; + rpz_st->q.node = NULL; + db = rpz_st->q.db; + rpz_st->q.db = NULL; + rdataset = rpz_st->q.rdataset; + rpz_st->q.rdataset = NULL; + sigrdataset = rpz_st->q.sigrdataset; + rpz_st->q.sigrdataset = NULL; + qtype = rpz_st->q.qtype; + + if (event->node != NULL) + dns_db_detachnode(db, &event->node); + rpz_st->ns.db = event->db; + rpz_st->ns.r_type = event->qtype; + rpz_st->ns.r_rdataset = event->rdataset; + if (event->sigrdataset != NULL && + dns_rdataset_isassociated(event->sigrdataset)) + dns_rdataset_disassociate(event->sigrdataset); + } else { + authoritative = ISC_FALSE; + + qtype = event->qtype; + db = event->db; + node = event->node; + rdataset = event->rdataset; + sigrdataset = event->sigrdataset; + } + if (qtype == dns_rdatatype_rrsig || qtype == dns_rdatatype_sig) type = dns_rdatatype_any; else type = qtype; - db = event->db; - node = event->node; - rdataset = event->rdataset; - sigrdataset = event->sigrdataset; + + if (DNS64(client)) { + client->query.attributes &= ~NS_QUERYATTR_DNS64; + dns64 = ISC_TRUE; + } + if (DNS64EXCLUDE(client)) { + client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE; + dns64_exclude = ISC_TRUE; + } /* * We'll need some resources... @@ -3794,16 +5079,26 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } - tname = dns_fixedname_name(&event->foundname); + if (rpz_st != NULL && + (rpz_st->state & DNS_RPZ_RECURSING) != 0) { + tname = rpz_st->fname; + } else { + tname = dns_fixedname_name(&event->foundname); + } result = dns_name_copy(tname, fname, NULL); if (result != ISC_R_SUCCESS) { QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } - - result = event->result; + if (rpz_st != NULL && + (rpz_st->state & DNS_RPZ_RECURSING) != 0) { + rpz_st->ns.r_result = event->result; + result = rpz_st->q.result; + isc_event_free(ISC_EVENT_PTR(&event)); + } else { + result = event->result; + } resuming = ISC_TRUE; - goto resume; } @@ -3902,8 +5197,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) goto cleanup; } - if (is_zone) + is_staticstub_zone = ISC_FALSE; + if (is_zone && zone != NULL) { authoritative = ISC_TRUE; + if (dns_zone_gettype(zone) == dns_zone_staticstub) + is_staticstub_zone = ISC_TRUE; + } if (event == NULL && client->query.restarts == 0) { if (is_zone) { @@ -3956,6 +5255,119 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) resume: CTRACE("query_find: resume"); + + if (!ISC_LIST_EMPTY(client->view->rpz_zones) && + RECURSIONOK(client) && !RECURSING(client) && + result != DNS_R_DELEGATION && result != ISC_R_NOTFOUND && + (client->query.rpz_st == NULL || + (client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) && + !dns_name_equal(client->query.qname, dns_rootname)) { + isc_result_t rresult; + + rresult = rpz_rewrite(client, qtype, resuming); + rpz_st = client->query.rpz_st; + switch (rresult) { + case ISC_R_SUCCESS: + break; + case DNS_R_DELEGATION: + /* + * recursing for NS names or addresses, + * so save the main query state + */ + rpz_st->q.qtype = qtype; + rpz_st->q.is_zone = is_zone; + rpz_st->q.authoritative = authoritative; + rpz_st->q.zone = zone; + zone = NULL; + rpz_st->q.db = db; + db = NULL; + rpz_st->q.node = node; + node = NULL; + rpz_st->q.rdataset = rdataset; + rdataset = NULL; + rpz_st->q.sigrdataset = sigrdataset; + sigrdataset = NULL; + dns_name_copy(fname, rpz_st->fname, NULL); + rpz_st->q.result = result; + client->query.attributes |= NS_QUERYATTR_RECURSING; + result = ISC_R_SUCCESS; + goto cleanup; + default: + RECURSE_ERROR(rresult); + goto cleanup; + } + if (rpz_st->m.policy != DNS_RPZ_POLICY_MISS && + rpz_st->m.policy != DNS_RPZ_POLICY_NO_OP) { + result = dns_name_copy(client->query.qname, fname, + NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + finish_rewrite: + rpz_clean(&zone, &db, &node, NULL); + if (rpz_st->m.rdataset != NULL) { + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + rdataset = rpz_st->m.rdataset; + rpz_st->m.rdataset = NULL; + } else if (rdataset != NULL && + dns_rdataset_isassociated(rdataset)) { + dns_rdataset_disassociate(rdataset); + } + node = rpz_st->m.node; + rpz_st->m.node = NULL; + db = rpz_st->m.db; + rpz_st->m.db = NULL; + zone = rpz_st->m.zone; + rpz_st->m.zone = NULL; + + result = rpz_st->m.result; + switch (rpz_st->m.policy) { + case DNS_RPZ_POLICY_NXDOMAIN: + result = DNS_R_NXDOMAIN; + break; + case DNS_RPZ_POLICY_NODATA: + result = DNS_R_NXRRSET; + break; + case DNS_RPZ_POLICY_RECORD: + if (type == dns_rdatatype_any && + result != DNS_R_CNAME && + dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + break; + case DNS_RPZ_POLICY_CNAME: + result = dns_name_copy(&rpz_st->m.rpz->cname, + fname, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + query_keepname(client, fname, dbuf); + result = query_add_cname(client, + client->query.qname, + fname, + dns_trust_authanswer, + rpz_st->m.ttl); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_client_qnamereplace(client, fname); + fname = NULL; + client->attributes &= ~NS_CLIENTATTR_WANTDNSSEC; + rpz_log(client); + want_restart = ISC_TRUE; + goto cleanup; + default: + INSIST(0); + } + + /* + * Turn off DNSSEC because the results of a + * response policy zone cannot verify. + */ + client->attributes &= ~NS_CLIENTATTR_WANTDNSSEC; + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + is_zone = ISC_TRUE; + rpz_log(client); + } + } + switch (result) { case ISC_R_SUCCESS: /* @@ -4008,11 +5420,18 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ if (RECURSIONOK(client)) { result = query_recurse(client, qtype, + client->query.qname, NULL, NULL, resuming); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { client->query.attributes |= NS_QUERYATTR_RECURSING; - else + if (dns64) + client->query.attributes |= + NS_QUERYATTR_DNS64; + if (dns64_exclude) + client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } else RECURSE_ERROR(result); goto cleanup; } else { @@ -4143,12 +5562,22 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } } else { if (zfname != NULL && - !dns_name_issubdomain(fname, zfname)) { + (!dns_name_issubdomain(fname, zfname) || + (is_staticstub_zone && + dns_name_equal(fname, zfname)))) { /* - * We've already got a delegation from - * authoritative data, and it is better - * than what we found in the cache. Use - * it instead of the cache delegation. + * In the following cases use "authoritative" + * data instead of the cache delegation: + * 1. We've already got a delegation from + * authoritative data, and it is better + * than what we found in the cache. + * 2. The query name matches the origin name + * of a static-stub zone. This needs to be + * considered for the case where the NS of + * the static-stub zone and the cached NS + * are different. We still need to contact + * the nameservers configured in the + * static-stub zone. */ query_releasename(client, &fname); fname = zfname; @@ -4183,15 +5612,31 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ if (dns_rdatatype_atparent(type)) result = query_recurse(client, qtype, - NULL, NULL, - resuming); + client->query.qname, + NULL, NULL, resuming); + else if (dns64) + result = query_recurse(client, + dns_rdatatype_a, + client->query.qname, + NULL, NULL, resuming); else result = query_recurse(client, qtype, - fname, rdataset, - resuming); - if (result == ISC_R_SUCCESS) + client->query.qname, + fname, rdataset, + resuming); + + if (result == ISC_R_SUCCESS) { client->query.attributes |= NS_QUERYATTR_RECURSING; + if (dns64) + client->query.attributes |= + NS_QUERYATTR_DNS64; + if (dns64_exclude) + client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } else if (result == DNS_R_DUPLICATE || + result == DNS_R_DROP) + QUERY_ERROR(result); else RECURSE_ERROR(result); } else { @@ -4231,11 +5676,75 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } } goto cleanup; + case DNS_R_EMPTYNAME: - result = DNS_R_NXRRSET; - /* FALLTHROUGH */ case DNS_R_NXRRSET: + nxrrset: INSIST(is_zone); + +#ifdef dns64_bis_return_excluded_addresses + if (dns64) +#else + if (dns64 && !dns64_exclude) +#endif + { + /* + * Restore the answers from the previous AAAA lookup. + */ + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + rdataset = client->query.dns64_aaaa; + sigrdataset = client->query.dns64_sigaaaa; + if (fname == NULL) { + dbuf = query_getnamebuf(client); + if (dbuf == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + fname = query_newname(client, dbuf, &b); + if (fname == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } + dns_name_copy(client->query.qname, fname, NULL); + client->query.dns64_aaaa = NULL; + client->query.dns64_sigaaaa = NULL; + dns64 = ISC_FALSE; +#ifdef dns64_bis_return_excluded_addresses + /* + * Resume the diverted processing of the AAAA response? + */ + if (dns64_excluded) + break; +#endif + } else if (result == DNS_R_NXRRSET && + !ISC_LIST_EMPTY(client->view->dns64) && + client->message->rdclass == dns_rdataclass_in && + qtype == dns_rdatatype_aaaa) + { + /* + * Look to see if there are A records for this + * name. + */ + INSIST(client->query.dns64_aaaa == NULL); + INSIST(client->query.dns64_sigaaaa == NULL); + client->query.dns64_aaaa = rdataset; + client->query.dns64_sigaaaa = sigrdataset; + client->query.dns64_ttl = dns64_ttl(db, version); + query_releasename(client, &fname); + dns_db_detachnode(db, &node); + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; + dns64 = ISC_TRUE; + goto db_find; + } + + result = DNS_R_NXRRSET; + /* * Look for a NSEC3 record if we don't have a NSEC record. */ @@ -4258,10 +5767,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * instead? If so add the nearest to the * closest provable encloser. */ - if (found && - dns_rdataset_isassociated(rdataset) && - !dns_name_equal(qname, found)) - { + if (dns_rdataset_isassociated(rdataset) && + !dns_name_equal(qname, found)) { unsigned int count; unsigned int skip; @@ -4328,7 +5835,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) /* * Add SOA. */ - result = query_addsoa(client, db, version, ISC_FALSE, + result = query_addsoa(client, db, version, ISC_UINT32_MAX, dns_rdataset_isassociated(rdataset)); if (result != ISC_R_SUCCESS) { QUERY_ERROR(result); @@ -4377,10 +5884,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) zone != NULL && #endif dns_zone_getzeronosoattl(zone)) - result = query_addsoa(client, db, version, ISC_TRUE, + result = query_addsoa(client, db, version, 0, dns_rdataset_isassociated(rdataset)); else - result = query_addsoa(client, db, version, ISC_FALSE, + result = query_addsoa(client, db, version, + ISC_UINT32_MAX, dns_rdataset_isassociated(rdataset)); if (result != ISC_R_SUCCESS) { QUERY_ERROR(result); @@ -4411,6 +5919,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) case DNS_R_NCACHENXDOMAIN: case DNS_R_NCACHENXRRSET: + ncache_nxrrset: INSIST(!is_zone); authoritative = ISC_FALSE; /* @@ -4426,6 +5935,74 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) client->message->rdclass == dns_rdataclass_in && dns_name_countlabels(fname) == 7) warn_rfc1918(client, fname, rdataset); + +#ifdef dns64_bis_return_excluded_addresses + if (dns64) +#else + if (dns64 && !dns64_exclude) +#endif + { + /* + * Restore the answers from the previous AAAA lookup. + */ + if (rdataset != NULL) + query_putrdataset(client, &rdataset); + if (sigrdataset != NULL) + query_putrdataset(client, &sigrdataset); + rdataset = client->query.dns64_aaaa; + sigrdataset = client->query.dns64_sigaaaa; + if (fname == NULL) { + dbuf = query_getnamebuf(client); + if (dbuf == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + fname = query_newname(client, dbuf, &b); + if (fname == NULL) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + } + dns_name_copy(client->query.qname, fname, NULL); + client->query.dns64_aaaa = NULL; + client->query.dns64_sigaaaa = NULL; + dns64 = ISC_FALSE; +#ifdef dns64_bis_return_excluded_addresses + if (dns64_excluded) + break; +#endif + } else if (result == DNS_R_NCACHENXRRSET && + !ISC_LIST_EMPTY(client->view->dns64) && + client->message->rdclass == dns_rdataclass_in && + qtype == dns_rdatatype_aaaa) + { + /* + * Look to see if there are A records for this + * name. + */ + INSIST(client->query.dns64_aaaa == NULL); + INSIST(client->query.dns64_sigaaaa == NULL); + client->query.dns64_aaaa = rdataset; + client->query.dns64_sigaaaa = sigrdataset; + /* + * If the ttl is zero we need to workout if we have just + * decremented to zero or if there was no negative cache + * ttl in the answer. + */ + if (rdataset->ttl != 0) + client->query.dns64_ttl = rdataset->ttl; + else if (dns_rdataset_first(rdataset) == ISC_R_SUCCESS) + client->query.dns64_ttl = 0; + query_releasename(client, &fname); + dns_db_detachnode(db, &node); + rdataset = NULL; + sigrdataset = NULL; + fname = NULL; + type = qtype = dns_rdatatype_a; + dns64 = ISC_TRUE; + goto db_find; + } + /* * We don't call query_addrrset() because we don't need any * of its extra features (and things would probably break!). @@ -4562,11 +6139,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_message_puttempname(client->message, &tname); goto cleanup; } - dns_name_init(tname, NULL); dns_name_clone(&dname.dname, tname); dns_rdata_freestruct(&dname); /* - * Construct the new qname. + * Construct the new qname consisting of + * <found name prefix>.<dname target> */ dns_fixedname_init(&fixed); prefix = dns_fixedname_name(&fixed); @@ -4583,8 +6160,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) goto cleanup; } result = dns_name_concatenate(prefix, tname, fname, NULL); + dns_message_puttempname(client->message, &tname); if (result != ISC_R_SUCCESS) { - dns_message_puttempname(client->message, &tname); if (result == ISC_R_NOSPACE) { /* * RFC2672, section 4.1, subsection 3c says @@ -4597,11 +6174,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } query_keepname(client, fname, dbuf); /* - * Synthesize a CNAME for this DNAME. + * Synthesize a CNAME consisting of + * <old qname> <dname ttl> CNAME <new qname> + * with <dname trust value> * - * We want to synthesize a CNAME since if we don't - * then older software that doesn't understand DNAME - * will not chain like it should. + * Synthesize a CNAME so old old clients that don't understand + * DNAME can chain. * * We do not try to synthesize a signature because we hope * that security aware servers will understand DNAME. Also, @@ -4609,12 +6187,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * on-the-fly is costly, and not really legitimate anyway * since the synthesized CNAME is NOT in the zone. */ - dns_name_init(tname, NULL); - (void)query_addcnamelike(client, client->query.qname, fname, - trdataset, &tname, - dns_rdatatype_cname); - if (tname != NULL) - dns_message_puttempname(client->message, &tname); + result = query_add_cname(client, client->query.qname, fname, + trdataset->trust, trdataset->ttl); + if (result != ISC_R_SUCCESS) + goto cleanup; /* * Switch to the new qname and restart. */ @@ -4641,6 +6217,28 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } if (type == dns_rdatatype_any) { +#ifdef ALLOW_FILTER_AAAA_ON_V4 + isc_boolean_t have_aaaa, have_a, have_sig, filter_aaaa; + + /* + * The filter-aaaa-on-v4 option should + * suppress AAAAs for IPv4 clients if there is an A. + * If we are not authoritative, assume there is a A + * even in if it is not in our cache. This assumption could + * be wrong but it is a good bet. + */ + have_aaaa = ISC_FALSE; + have_a = !authoritative; + have_sig = ISC_FALSE; + if (client->view->v4_aaaa != dns_v4_aaaa_ok && + is_v4_client(client) && + ns_client_checkaclsilent(client, NULL, + client->view->v4_aaaa_acl, + ISC_TRUE) == ISC_R_SUCCESS) + filter_aaaa = ISC_TRUE; + else + filter_aaaa = ISC_FALSE; +#endif /* * XXXRTH Need to handle zonecuts with special case * code. @@ -4652,6 +6250,54 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } + + /* + * Check all A and AAAA records in all response policy + * IP address zones + */ + rpz_st = client->query.rpz_st; + if (rpz_st != NULL && + (rpz_st->state & DNS_RPZ_DONE_QNAME) != 0 && + (rpz_st->state & DNS_RPZ_REWRITTEN) == 0 && + RECURSIONOK(client) && !RECURSING(client) && + (rpz_st->state & DNS_RPZ_HAVE_IP) != 0) { + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) { + dns_rdatasetiter_current(rdsiter, rdataset); + if (rdataset->type == dns_rdatatype_a || + rdataset->type == dns_rdatatype_aaaa) + result = rpz_rewrite_ip(client, + rdataset, + DNS_RPZ_TYPE_IP); + dns_rdataset_disassociate(rdataset); + if (result != ISC_R_SUCCESS) + break; + } + if (result != ISC_R_NOMORE) { + dns_rdatasetiter_destroy(&rdsiter); + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + switch (rpz_st->m.policy) { + case DNS_RPZ_POLICY_MISS: + break; + case DNS_RPZ_POLICY_NO_OP: + rpz_log(client); + rpz_st->state |= DNS_RPZ_REWRITTEN; + break; + case DNS_RPZ_POLICY_NXDOMAIN: + case DNS_RPZ_POLICY_NODATA: + case DNS_RPZ_POLICY_RECORD: + case DNS_RPZ_POLICY_CNAME: + dns_rdatasetiter_destroy(&rdsiter); + rpz_st->state |= DNS_RPZ_REWRITTEN; + goto finish_rewrite; + default: + INSIST(0); + } + } + /* * Calling query_addrrset() with a non-NULL dbuf is going * to either keep or release the name. We don't want it to @@ -4668,6 +6314,18 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) result = dns_rdatasetiter_first(rdsiter); while (result == ISC_R_SUCCESS) { dns_rdatasetiter_current(rdsiter, rdataset); +#ifdef ALLOW_FILTER_AAAA_ON_V4 + /* + * Notice the presence of A and AAAAs so + * that AAAAs can be hidden from IPv4 clients. + */ + if (filter_aaaa) { + if (rdataset->type == dns_rdatatype_aaaa) + have_aaaa = ISC_TRUE; + else if (rdataset->type == dns_rdatatype_a) + have_a = ISC_TRUE; + } +#endif if (is_zone && qtype == dns_rdatatype_any && !dns_db_issecure(db) && dns_rdatatype_isdnssec(rdataset->type)) { @@ -4679,6 +6337,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_rdataset_disassociate(rdataset); } else if ((qtype == dns_rdatatype_any || rdataset->type == qtype) && rdataset->type != 0) { +#ifdef ALLOW_FILTER_AAAA_ON_V4 + if (dns_rdatatype_isdnssec(rdataset->type)) + have_sig = ISC_TRUE; +#endif if (NOQNAME(rdataset) && WANTDNSSEC(client)) noqname = rdataset; else @@ -4709,6 +6371,16 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) result = dns_rdatasetiter_next(rdsiter); } +#ifdef ALLOW_FILTER_AAAA_ON_V4 + /* + * Filter AAAAs if there is an A and there is no signature + * or we are supposed to break DNSSEC. + */ + if (filter_aaaa && have_aaaa && have_a && + (!have_sig || !WANTDNSSEC(client) || + client->view->v4_aaaa == dns_v4_aaaa_break_dnssec)) + client->attributes |= NS_CLIENTATTR_FILTER_AAAA; +#endif if (fname != NULL) dns_message_puttempname(client->message, &fname); @@ -4742,10 +6414,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_rdatasetiter_destroy(&rdsiter); if (RECURSIONOK(client)) { result = query_recurse(client, - qtype, - NULL, - NULL, - resuming); + qtype, + client->query.qname, + NULL, NULL, + resuming); if (result == ISC_R_SUCCESS) client->query.attributes |= NS_QUERYATTR_RECURSING; @@ -4763,7 +6435,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * Add SOA. */ result = query_addsoa(client, db, version, - ISC_FALSE, ISC_FALSE); + ISC_UINT32_MAX, + ISC_FALSE); if (result == ISC_R_SUCCESS) result = ISC_R_NOMORE; } else { @@ -4783,6 +6456,162 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * This is the "normal" case -- an ordinary question to which * we know the answer. */ + + /* + * Check all A and AAAA records in all response policy + * IP address zones + */ + rpz_st = client->query.rpz_st; + if (rpz_st != NULL && + (rpz_st->state & DNS_RPZ_DONE_QNAME) != 0 && + (rpz_st->state & DNS_RPZ_REWRITTEN) == 0 && + RECURSIONOK(client) && !RECURSING(client) && + (rpz_st->state & DNS_RPZ_HAVE_IP) != 0 && + (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_a)) { + result = rpz_rewrite_ip(client, rdataset, + DNS_RPZ_TYPE_IP); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(DNS_R_SERVFAIL); + goto cleanup; + } + /* + * After a hit in the radix tree for the policy domain, + * either stop trying to rewrite (DNS_RPZ_POLICY_NO_OP) + * or restart to ask the ordinary database of the + * policy zone for the DNS record corresponding to the + * record in the radix tree. + */ + switch (rpz_st->m.policy) { + case DNS_RPZ_POLICY_MISS: + break; + case DNS_RPZ_POLICY_NO_OP: + rpz_log(client); + rpz_st->state |= DNS_RPZ_REWRITTEN; + break; + case DNS_RPZ_POLICY_NXDOMAIN: + case DNS_RPZ_POLICY_NODATA: + case DNS_RPZ_POLICY_RECORD: + case DNS_RPZ_POLICY_CNAME: + rpz_st->state |= DNS_RPZ_REWRITTEN; + goto finish_rewrite; + default: + INSIST(0); + } + } + +#ifdef ALLOW_FILTER_AAAA_ON_V4 + /* + * Optionally hide AAAAs from IPv4 clients if there is an A. + * We add the AAAAs now, but might refuse to render them later + * after DNSSEC is figured out. + * This could be more efficient, but the whole idea is + * so fundamentally wrong, unavoidably inaccurate, and + * unneeded that it is best to keep it as short as possible. + */ + if (client->view->v4_aaaa != dns_v4_aaaa_ok && + is_v4_client(client) && + ns_client_checkaclsilent(client, NULL, + client->view->v4_aaaa_acl, + ISC_TRUE) == ISC_R_SUCCESS && + (!WANTDNSSEC(client) || + sigrdataset == NULL || + !dns_rdataset_isassociated(sigrdataset) || + client->view->v4_aaaa == dns_v4_aaaa_break_dnssec)) { + if (qtype == dns_rdatatype_aaaa) { + trdataset = query_newrdataset(client); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_a, 0, + client->now, + trdataset, NULL); + if (dns_rdataset_isassociated(trdataset)) + dns_rdataset_disassociate(trdataset); + query_putrdataset(client, &trdataset); + + /* + * We have an AAAA but the A is not in our cache. + * Assume any result other than DNS_R_DELEGATION + * or ISC_R_NOTFOUND means there is no A and + * so AAAAs are ok. + * Assume there is no A if we can't recurse + * for this client, although that could be + * the wrong answer. What else can we do? + * Besides, that we have the AAAA and are using + * this mechanism suggests that we care more + * about As than AAAAs and would have cached + * the A if it existed. + */ + if (result == ISC_R_SUCCESS) { + client->attributes |= + NS_CLIENTATTR_FILTER_AAAA; + + } else if (authoritative || + !RECURSIONOK(client) || + (result != DNS_R_DELEGATION && + result != ISC_R_NOTFOUND)) { + client->attributes &= + ~NS_CLIENTATTR_FILTER_AAAA; + } else { + /* + * This is an ugly kludge to recurse + * for the A and discard the result. + * + * Continue to add the AAAA now. + * We'll make a note to not render it + * if the recursion for the A succeeds. + */ + result = query_recurse(client, + dns_rdatatype_a, + client->query.qname, + NULL, NULL, resuming); + if (result == ISC_R_SUCCESS) { + client->attributes |= + NS_CLIENTATTR_FILTER_AAAA_RC; + client->query.attributes |= + NS_QUERYATTR_RECURSING; + } + } + + } else if (qtype == dns_rdatatype_a && + (client->attributes & + NS_CLIENTATTR_FILTER_AAAA_RC) != 0) { + client->attributes &= + ~NS_CLIENTATTR_FILTER_AAAA_RC; + client->attributes |= + NS_CLIENTATTR_FILTER_AAAA; + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + goto cleanup; + } + } +#endif + /* + * Check to see if the AAAA RRset has non-excluded addresses + * in it. If not look for a A RRset. + */ + INSIST(client->query.dns64_aaaaok == NULL); + + if (qtype == dns_rdatatype_aaaa && !dns64_exclude && + !ISC_LIST_EMPTY(client->view->dns64) && + client->message->rdclass == dns_rdataclass_in && + !dns64_aaaaok(client, rdataset, sigrdataset)) { + /* + * Look to see if there are A records for this + * name. + */ + client->query.dns64_aaaa = rdataset; + client->query.dns64_sigaaaa = sigrdataset; + client->query.dns64_ttl = rdataset->ttl; + query_releasename(client, &fname); + dns_db_detachnode(db, &node); + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; + dns64_exclude = dns64 = ISC_TRUE; + goto db_find; + } + if (sigrdataset != NULL) sigrdatasetp = &sigrdataset; else @@ -4798,8 +6627,43 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_name_equal(client->query.qname, dns_rootname)) client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL; - query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf, - DNS_SECTION_ANSWER); + if (dns64) { + qtype = type = dns_rdatatype_aaaa; + result = query_dns64(client, &fname, rdataset, + sigrdataset, dbuf, + DNS_SECTION_ANSWER); + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, &rdataset); + if (result == ISC_R_NOMORE) { +#ifndef dns64_bis_return_excluded_addresses + if (dns64_exclude) { + if (!is_zone) + goto cleanup; + /* + * Add a fake SOA record. + */ + result = query_addsoa(client, db, + version, 600, + ISC_FALSE); + goto cleanup; + } +#endif + if (is_zone) + goto nxrrset; + else + goto ncache_nxrrset; + } else if (result != ISC_R_SUCCESS) { + eresult = result; + goto cleanup; + } + } else if (client->query.dns64_aaaaok != NULL) { + query_filter64(client, &fname, rdataset, dbuf, + DNS_SECTION_ANSWER); + query_putrdataset(client, &rdataset); + } else + query_addrrset(client, &fname, &rdataset, + sigrdatasetp, dbuf, DNS_SECTION_ANSWER); + if (noqname != NULL) query_addnoqnameproof(client, noqname); /* @@ -4842,6 +6706,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) /* * General cleanup. */ + rpz_st = client->query.rpz_st; + if (rpz_st != NULL && (rpz_st->state & DNS_RPZ_RECURSING) == 0) + rpz_clean(&rpz_st->m.zone, &rpz_st->m.db, &rpz_st->m.node, + &rpz_st->m.rdataset); if (rdataset != NULL) query_putrdataset(client, &rdataset); if (sigrdataset != NULL) @@ -4949,6 +6817,7 @@ log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) { char namebuf[DNS_NAME_FORMATSIZE]; char typename[DNS_RDATATYPE_FORMATSIZE]; char classname[DNS_RDATACLASS_FORMATSIZE]; + char onbuf[ISC_NETADDR_FORMATSIZE]; dns_rdataset_t *rdataset; int level = ISC_LOG_INFO; @@ -4960,14 +6829,18 @@ log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) { dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); dns_rdataclass_format(rdataset->rdclass, classname, sizeof(classname)); dns_rdatatype_format(rdataset->type, typename, sizeof(typename)); + isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf)); ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, - level, "query: %s %s %s %s%s%s%s%s", namebuf, classname, - typename, WANTRECURSION(client) ? "+" : "-", + level, "query: %s %s %s %s%s%s%s%s%s (%s)", namebuf, + classname, typename, WANTRECURSION(client) ? "+" : "-", (client->signer != NULL) ? "S": "", (client->opt != NULL) ? "E" : "", + ((client->attributes & NS_CLIENTATTR_TCP) != 0) ? + "T" : "", ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "", - ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : ""); + ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "", + onbuf); } static inline void diff --git a/contrib/bind9/bin/named/server.c b/contrib/bind9/bin/named/server.c index bc7fc17c3296..5bbf94b9b604 100644 --- a/contrib/bind9/bin/named/server.c +++ b/contrib/bind9/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.520.12.21 2011-01-14 23:45:49 tbox Exp $ */ +/* $Id: server.c,v 1.599.8.4 2011-02-16 19:46:12 each Exp $ */ /*! \file */ @@ -23,6 +23,10 @@ #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> #include <isc/app.h> #include <isc/base64.h> @@ -36,7 +40,9 @@ #include <isc/portset.h> #include <isc/print.h> #include <isc/resource.h> +#include <isc/sha2.h> #include <isc/socket.h> +#include <isc/stat.h> #include <isc/stats.h> #include <isc/stdio.h> #include <isc/string.h> @@ -57,9 +63,11 @@ #ifdef DLZ #include <dns/dlz.h> #endif +#include <dns/dns64.h> #include <dns/forward.h> #include <dns/journal.h> #include <dns/keytable.h> +#include <dns/keyvalues.h> #include <dns/lib.h> #include <dns/master.h> #include <dns/masterdump.h> @@ -102,6 +110,10 @@ #include <stdlib.h> #endif +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + /*% * Check an operation for failure. Assumes that the function * using it has a 'result' variable and a 'cleanup' label. @@ -143,6 +155,14 @@ fatal(msg, result); \ } while (0) \ +/*% + * Maximum ADB size for views that share a cache. Use this limit to suppress + * the total of memory footprint, which should be the main reason for sharing + * a cache. Only effective when a finite max-cache-size is specified. + * This is currently defined to be 8MB. + */ +#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608 + struct ns_dispatch { isc_sockaddr_t addr; unsigned int dispatchgen; @@ -150,6 +170,14 @@ struct ns_dispatch { ISC_LINK(struct ns_dispatch) link; }; +struct ns_cache { + dns_cache_t *cache; + dns_view_t *primaryview; + isc_boolean_t needflush; + isc_boolean_t adbsizeadjusted; + ISC_LINK(ns_cache_t) link; +}; + struct dumpcontext { isc_mem_t *mctx; isc_boolean_t dumpcache; @@ -176,6 +204,17 @@ struct zonelistentry { ISC_LINK(struct zonelistentry) link; }; +/*% + * Configuration context to retain for each view that allows + * new zones to be added at runtime + */ +struct cfg_context { + isc_mem_t * mctx; + cfg_obj_t * config; + cfg_parser_t * parser; + cfg_aclconfctx_t actx; +}; + /* * These zones should not leak onto the Internet. */ @@ -230,8 +269,8 @@ static const struct { { NULL, ISC_FALSE } }; -static void -fatal(const char *msg, isc_result_t result); +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST; static void ns_server_reload(isc_task_t *task, isc_event_t *event); @@ -256,19 +295,25 @@ configure_alternates(const cfg_obj_t *config, dns_view_t *view, static isc_result_t configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, - cfg_aclconfctx_t *aclconf); + cfg_aclconfctx_t *aclconf, isc_boolean_t added); + +static isc_result_t +add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx); static void end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); +static void +cfgctx_destroy(void **cfgp); + /*% * Configure a single view ACL at '*aclp'. Get its configuration from * 'vconfig' (for per-view configuration) and maybe from 'config' */ static isc_result_t configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, - const char *aclname, cfg_aclconfctx_t *actx, - isc_mem_t *mctx, dns_acl_t **aclp) + const char *aclname, const char *acltuplename, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp) { isc_result_t result; const cfg_obj_t *maps[3]; @@ -294,13 +339,21 @@ configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, */ return (ISC_R_SUCCESS); + if (acltuplename != NULL) { + /* + * If the ACL is given in an optional tuple, retrieve it. + * The parser should have ensured that a valid object be + * returned. + */ + aclobj = cfg_tuple_get(aclobj, acltuplename); + } + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx, mctx, 0, aclp); return (result); } - /*% * Configure a sortlist at '*aclp'. Essentially the same as * configure_view_acl() except it calls cfg_acl_fromconfig with a @@ -345,8 +398,88 @@ configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, } static isc_result_t -configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, - dns_keytable_t *keytable, isc_mem_t *mctx) +configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config, + const char *confname, const char *conftuplename, + isc_mem_t *mctx, dns_rbt_t **rbtp) +{ + isc_result_t result; + const cfg_obj_t *maps[3]; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *element; + int i = 0; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t b; + const char *str; + const cfg_obj_t *nameobj; + + if (*rbtp != NULL) + dns_rbt_destroy(rbtp); + if (vconfig != NULL) + maps[i++] = cfg_tuple_get(vconfig, "options"); + if (config != NULL) { + const cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + maps[i++] = options; + } + maps[i] = NULL; + + (void)ns_config_get(maps, confname, &obj); + if (obj == NULL) + /* + * No value available. *rbtp == NULL. + */ + return (ISC_R_SUCCESS); + + if (conftuplename != NULL) { + obj = cfg_tuple_get(obj, conftuplename); + if (cfg_obj_isvoid(obj)) + return (ISC_R_SUCCESS); + } + + result = dns_rbt_create(mctx, NULL, NULL, rbtp); + if (result != ISC_R_SUCCESS) + return (result); + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) { + nameobj = cfg_listelt_value(element); + str = cfg_obj_asstring(nameobj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + /* + * We don't need the node data, but need to set dummy data to + * avoid a partial match with an empty node. For example, if + * we have foo.example.com and bar.example.com, we'd get a match + * for baz.example.com, which is not the expected result. + * We simply use (void *)1 as the dummy data. + */ + result = dns_rbt_addname(*rbtp, name, (void *)1); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR, + "failed to add %s for %s: %s", + str, confname, isc_result_totext(result)); + goto cleanup; + } + + } + + return (result); + + cleanup: + dns_rbt_destroy(rbtp); + return (result); + +} + +static isc_result_t +dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key, + isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx) { dns_rdataclass_t viewclass; dns_rdata_dnskey_t keystruct; @@ -363,12 +496,28 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, isc_result_t result; dst_key_t *dstkey = NULL; + INSIST(target != NULL && *target == NULL); + flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); keyname = dns_fixedname_name(&fkeyname); keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); + if (managed) { + const char *initmethod; + initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init")); + + if (strcasecmp(initmethod, "initial-key") != 0) { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, + "managed key '%s': " + "invalid initialization method '%s'", + keynamestr, initmethod); + result = ISC_R_FAILURE; + goto cleanup; + } + } + if (vconfig == NULL) viewclass = dns_rdataclass_in; else { @@ -408,7 +557,8 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, keystruct.algorithm == DST_ALG_RSAMD5) && r.length > 1 && r.base[0] == 1 && r.base[1] == 3) cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, - "trusted key '%s' has a weak exponent", + "%s key '%s' has a weak exponent", + managed ? "managed" : "trusted", keynamestr); CHECK(dns_rdata_fromstruct(NULL, @@ -418,25 +568,28 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, dns_fixedname_init(&fkeyname); isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); isc_buffer_add(&namebuf, strlen(keynamestr)); - CHECK(dns_name_fromtext(keyname, &namebuf, - dns_rootname, ISC_FALSE, - NULL)); + CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL)); CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, mctx, &dstkey)); - CHECK(dns_keytable_add(keytable, &dstkey)); - INSIST(dstkey == NULL); + *target = dstkey; return (ISC_R_SUCCESS); cleanup: if (result == DST_R_NOCRYPTO) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, - "ignoring trusted key for '%s': no crypto support", + "ignoring %s key for '%s': no crypto support", + managed ? "managed" : "trusted", keynamestr); - result = ISC_R_SUCCESS; + } else if (result == DST_R_UNSUPPORTEDALG) { + cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, + "skipping %s key for '%s': %s", + managed ? "managed" : "trusted", + keynamestr, isc_result_totext(result)); } else { cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, - "configuring trusted key for '%s': %s", + "configuring %s key for '%s': %s", + managed ? "managed" : "trusted", keynamestr, isc_result_totext(result)); result = ISC_R_FAILURE; } @@ -447,63 +600,215 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, return (result); } +static isc_result_t +load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig, + dns_view_t *view, isc_boolean_t managed, + dns_name_t *keyname, isc_mem_t *mctx) +{ + const cfg_listelt_t *elt, *elt2; + const cfg_obj_t *key, *keylist; + dst_key_t *dstkey = NULL; + isc_result_t result; + dns_keytable_t *secroots = NULL; + + CHECK(dns_view_getsecroots(view, &secroots)); + + for (elt = cfg_list_first(keys); + elt != NULL; + elt = cfg_list_next(elt)) { + keylist = cfg_listelt_value(elt); + + for (elt2 = cfg_list_first(keylist); + elt2 != NULL; + elt2 = cfg_list_next(elt2)) { + key = cfg_listelt_value(elt2); + result = dstkey_fromconfig(vconfig, key, managed, + &dstkey, mctx); + if (result == DST_R_UNSUPPORTEDALG) { + result = ISC_R_SUCCESS; + continue; + } + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* + * If keyname was specified, we only add that key. + */ + if (keyname != NULL && + !dns_name_equal(keyname, dst_key_name(dstkey))) + { + dst_key_free(&dstkey); + continue; + } + + CHECK(dns_keytable_add(secroots, managed, &dstkey)); + } + } + + cleanup: + if (dstkey != NULL) + dst_key_free(&dstkey); + if (secroots != NULL) + dns_keytable_detach(&secroots); + if (result == DST_R_NOCRYPTO) + result = ISC_R_SUCCESS; + return (result); +} + /*% - * Configure DNSSEC keys for a view. Currently used only for - * the security roots. + * Configure DNSSEC keys for a view. * * The per-view configuration values and the server-global defaults are read - * from 'vconfig' and 'config'. The variable to be configured is '*target'. + * from 'vconfig' and 'config'. */ static isc_result_t -configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, - isc_mem_t *mctx, dns_keytable_t **target) +configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig, + const cfg_obj_t *config, const cfg_obj_t *bindkeys, + isc_boolean_t auto_dlv, isc_boolean_t auto_root, + isc_mem_t *mctx) { - isc_result_t result; - const cfg_obj_t *keys = NULL; + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *view_keys = NULL; + const cfg_obj_t *global_keys = NULL; + const cfg_obj_t *view_managed_keys = NULL; + const cfg_obj_t *global_managed_keys = NULL; + const cfg_obj_t *maps[4]; const cfg_obj_t *voptions = NULL; - const cfg_listelt_t *element, *element2; - const cfg_obj_t *keylist; - const cfg_obj_t *key; - dns_keytable_t *keytable = NULL; + const cfg_obj_t *options = NULL; + const cfg_obj_t *obj = NULL; + const char *directory; + int i = 0; - CHECK(dns_keytable_create(mctx, &keytable)); + /* We don't need trust anchors for the _bind view */ + if (strcmp(view->name, "_bind") == 0 && + view->rdclass == dns_rdataclass_chaos) { + return (ISC_R_SUCCESS); + } - if (vconfig != NULL) + if (vconfig != NULL) { voptions = cfg_tuple_get(vconfig, "options"); + if (voptions != NULL) { + (void) cfg_map_get(voptions, "trusted-keys", + &view_keys); + (void) cfg_map_get(voptions, "managed-keys", + &view_managed_keys); + maps[i++] = voptions; + } + } - keys = NULL; - if (voptions != NULL) - (void)cfg_map_get(voptions, "trusted-keys", &keys); - if (keys == NULL) - (void)cfg_map_get(config, "trusted-keys", &keys); + if (config != NULL) { + (void)cfg_map_get(config, "trusted-keys", &global_keys); + (void)cfg_map_get(config, "managed-keys", &global_managed_keys); + (void)cfg_map_get(config, "options", &options); + if (options != NULL) { + maps[i++] = options; + } + } - for (element = cfg_list_first(keys); - element != NULL; - element = cfg_list_next(element)) - { - keylist = cfg_listelt_value(element); - for (element2 = cfg_list_first(keylist); - element2 != NULL; - element2 = cfg_list_next(element2)) - { - key = cfg_listelt_value(element2); - CHECK(configure_view_dnsseckey(vconfig, key, - keytable, mctx)); + maps[i++] = ns_g_defaults; + maps[i] = NULL; + + result = dns_view_initsecroots(view, mctx); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "couldn't create keytable"); + return (ISC_R_UNEXPECTED); + } + + if (auto_dlv && view->rdclass == dns_rdataclass_in) { + const cfg_obj_t *builtin_keys = NULL; + const cfg_obj_t *builtin_managed_keys = NULL; + + isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "using built-in DLV key for view %s", + view->name); + + /* + * If bind.keys exists, it overrides the managed-keys + * clause hard-coded in ns_g_config. + */ + if (bindkeys != NULL) { + (void)cfg_map_get(bindkeys, "trusted-keys", + &builtin_keys); + (void)cfg_map_get(bindkeys, "managed-keys", + &builtin_managed_keys); + } else { + (void)cfg_map_get(ns_g_config, "trusted-keys", + &builtin_keys); + (void)cfg_map_get(ns_g_config, "managed-keys", + &builtin_managed_keys); } + + if (builtin_keys != NULL) + CHECK(load_view_keys(builtin_keys, vconfig, view, + ISC_FALSE, view->dlv, mctx)); + if (builtin_managed_keys != NULL) + CHECK(load_view_keys(builtin_managed_keys, vconfig, + view, ISC_TRUE, view->dlv, mctx)); } - dns_keytable_detach(target); - *target = keytable; /* Transfer ownership. */ - keytable = NULL; - result = ISC_R_SUCCESS; + if (auto_root && view->rdclass == dns_rdataclass_in) { + const cfg_obj_t *builtin_keys = NULL; + const cfg_obj_t *builtin_managed_keys = NULL; - cleanup: + isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "using built-in root key for view %s", + view->name); + + /* + * If bind.keys exists, it overrides the managed-keys + * clause hard-coded in ns_g_config. + */ + if (bindkeys != NULL) { + (void)cfg_map_get(bindkeys, "trusted-keys", + &builtin_keys); + (void)cfg_map_get(bindkeys, "managed-keys", + &builtin_managed_keys); + } else { + (void)cfg_map_get(ns_g_config, "trusted-keys", + &builtin_keys); + (void)cfg_map_get(ns_g_config, "managed-keys", + &builtin_managed_keys); + } + + if (builtin_keys != NULL) + CHECK(load_view_keys(builtin_keys, vconfig, view, + ISC_FALSE, dns_rootname, mctx)); + if (builtin_managed_keys != NULL) + CHECK(load_view_keys(builtin_managed_keys, vconfig, + view, ISC_TRUE, dns_rootname, + mctx)); + } + + CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE, + NULL, mctx)); + CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE, + NULL, mctx)); + + if (view->rdclass == dns_rdataclass_in) { + CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE, + NULL, mctx)); + CHECK(load_view_keys(global_managed_keys, vconfig, view, + ISC_TRUE, NULL, mctx)); + } + + /* + * Add key zone for managed-keys. + */ + obj = NULL; + (void)ns_config_get(maps, "managed-keys-directory", &obj); + directory = obj != NULL ? cfg_obj_asstring(obj) : NULL; + CHECK(add_keydata_zone(view, directory, ns_g_mctx)); + + cleanup: return (result); } static isc_result_t -mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) -{ +mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) { const cfg_listelt_t *element; const cfg_obj_t *obj; const char *str; @@ -523,8 +828,7 @@ mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); - CHECK(dns_name_fromtext(name, &b, dns_rootname, - ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); CHECK(dns_resolver_setmustbesecure(resolver, name, value)); } @@ -684,7 +988,7 @@ configure_order(dns_order_t *order, const cfg_obj_t *ent) { isc_buffer_add(&b, strlen(str)); dns_fixedname_init(&fixed); result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) return (result); @@ -868,7 +1172,7 @@ disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); - CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); algorithms = cfg_tuple_get(disabled, "algorithms"); for (element = cfg_list_first(algorithms); @@ -921,7 +1225,7 @@ on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(name, &b, dns_rootname, - ISC_TRUE, NULL); + 0, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); if (dns_name_equal(name, zonename)) return (ISC_TRUE); @@ -979,6 +1283,20 @@ setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) { return (ISC_R_SUCCESS); } +static ns_cache_t * +cachelist_find(ns_cachelist_t *cachelist, const char *cachename) { + ns_cache_t *nsc; + + for (nsc = ISC_LIST_HEAD(*cachelist); + nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) { + if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0) + return (nsc); + } + + return (NULL); +} + static isc_boolean_t cache_reusable(dns_view_t *originview, dns_view_t *view, isc_boolean_t new_zero_no_soattl) @@ -996,6 +1314,238 @@ cache_reusable(dns_view_t *originview, dns_view_t *view, return (ISC_TRUE); } +static isc_boolean_t +cache_sharable(dns_view_t *originview, dns_view_t *view, + isc_boolean_t new_zero_no_soattl, + unsigned int new_cleaning_interval, + isc_uint32_t new_max_cache_size) +{ + /* + * If the cache cannot even reused for the same view, it cannot be + * shared with other views. + */ + if (!cache_reusable(originview, view, new_zero_no_soattl)) + return (ISC_FALSE); + + /* + * Check other cache related parameters that must be consistent among + * the sharing views. + */ + if (dns_cache_getcleaninginterval(originview->cache) != + new_cleaning_interval || + dns_cache_getcachesize(originview->cache) != new_max_cache_size) { + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + +#ifdef DLZ +/* + * Callback from DLZ configure when the driver sets up a writeable zone + */ +static isc_result_t +dlzconfigure_callback(dns_view_t *view, dns_zone_t *zone) { + dns_name_t *origin = dns_zone_getorigin(zone); + dns_rdataclass_t zclass = view->rdclass; + isc_result_t result; + + result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone); + if (result != ISC_R_SUCCESS) + return result; + dns_zone_setstats(zone, ns_g_server->zonestats); + + return ns_zone_configure_writeable_dlz(view->dlzdatabase, + zone, zclass, origin); +} +#endif + +static isc_result_t +dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na, + unsigned int prefixlen, const char *server, + const char *contact) +{ + char *cp; + char reverse[48+sizeof("ip6.arpa.")]; + const char *dns64_dbtype[4] = { "_builtin", "dns64", ".", "." }; + const char *sep = ": view "; + const char *viewname = view->name; + const unsigned char *s6; + dns_fixedname_t fixed; + dns_name_t *name; + dns_zone_t *zone = NULL; + int dns64_dbtypec = 4; + isc_buffer_t b; + isc_result_t result; + + REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || + prefixlen == 56 || prefixlen == 64 || prefixlen == 96); + + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + } + + /* + * Construct the reverse name of the zone. + */ + cp = reverse; + s6 = na->type.in6.s6_addr; + while (prefixlen > 0) { + prefixlen -= 8; + sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf, + (s6[prefixlen/8] >> 4) & 0xf); + cp += 4; + } + strcat(cp, "ip6.arpa."); + + /* + * Create the actual zone. + */ + if (server != NULL) + dns64_dbtype[2] = server; + if (contact != NULL) + dns64_dbtype[3] = contact; + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + isc_buffer_init(&b, reverse, strlen(reverse)); + isc_buffer_add(&b, strlen(reverse)); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + CHECK(dns_zone_create(&zone, mctx)); + CHECK(dns_zone_setorigin(zone, name)); + dns_zone_setview(zone, view); + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + dns_zone_setclass(zone, view->rdclass); + dns_zone_settype(zone, dns_zone_master); + dns_zone_setstats(zone, ns_g_server->zonestats); + CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype)); + if (view->queryacl != NULL) + dns_zone_setqueryacl(zone, view->queryacl); + if (view->queryonacl != NULL) + dns_zone_setqueryonacl(zone, view->queryonacl); + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); + CHECK(setquerystats(zone, mctx, ISC_FALSE)); /* XXXMPA */ + CHECK(dns_view_addzone(view, zone)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep, + viewname, reverse); + +cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + return (result); +} + +static isc_result_t +configure_rpz(dns_view_t *view, const cfg_listelt_t *element) { + const cfg_obj_t *rpz_obj, *policy_obj; + const char *str; + dns_fixedname_t fixed; + dns_name_t *origin; + dns_rpz_zone_t *old, *new; + dns_zone_t *zone = NULL; + isc_result_t result; + unsigned int l1, l2; + + new = isc_mem_get(view->mctx, sizeof(*new)); + if (new == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + memset(new, 0, sizeof(*new)); + dns_name_init(&new->nsdname, NULL); + dns_name_init(&new->origin, NULL); + dns_name_init(&new->cname, NULL); + ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link); + + rpz_obj = cfg_listelt_value(element); + policy_obj = cfg_tuple_get(rpz_obj, "policy"); + if (cfg_obj_isvoid(policy_obj)) { + new->policy = DNS_RPZ_POLICY_GIVEN; + } else { + str = cfg_obj_asstring(policy_obj); + new->policy = dns_rpz_str2policy(str); + INSIST(new->policy != DNS_RPZ_POLICY_ERROR); + } + + dns_fixedname_init(&fixed); + origin = dns_fixedname_name(&fixed); + str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "name")); + result = dns_name_fromstring(origin, str, DNS_NAME_DOWNCASE, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid zone '%s'", str); + goto cleanup; + } + + result = dns_name_fromstring2(&new->nsdname, DNS_RPZ_NSDNAME_ZONE, + origin, DNS_NAME_DOWNCASE, view->mctx); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid zone '%s'", str); + goto cleanup; + } + + /* + * The origin is part of 'nsdname' so we don't need to keep it + * seperately. + */ + l1 = dns_name_countlabels(&new->nsdname); + l2 = dns_name_countlabels(origin); + dns_name_getlabelsequence(&new->nsdname, l1 - l2, l2, &new->origin); + + /* + * Are we configured to with the reponse policy zone? + */ + result = dns_view_findzone(view, &new->origin, &zone); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "unknown zone '%s'", str); + goto cleanup; + } + + if (dns_zone_gettype(zone) != dns_zone_master && + dns_zone_gettype(zone) != dns_zone_slave) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "zone '%s' is neither master nor slave", str); + dns_zone_detach(&zone); + result = DNS_R_NOTMASTER; + goto cleanup; + } + dns_zone_detach(&zone); + + for (old = ISC_LIST_HEAD(view->rpz_zones); + old != new; + old = ISC_LIST_NEXT(old, link)) { + ++new->num; + if (dns_name_equal(&old->origin, &new->origin)) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "duplicate '%s'", str); + result = DNS_R_DUPLICATE; + goto cleanup; + } + } + + if (new->policy == DNS_RPZ_POLICY_CNAME) { + str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "cname")); + result = dns_name_fromstring(&new->cname, str, 0, view->mctx); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, + "invalid cname '%s'", str); + goto cleanup; + } + } + + return (ISC_R_SUCCESS); + + cleanup: + dns_rpz_view_destroy(view); + return (result); +} + /* * Configure 'view' according to 'vconfig', taking defaults from 'config' * where values are missing in 'vconfig'. @@ -1004,12 +1554,15 @@ cache_reusable(dns_view_t *originview, dns_view_t *view, * global defaults in 'config' used exclusively. */ static isc_result_t -configure_view(dns_view_t *view, const cfg_obj_t *config, - const cfg_obj_t *vconfig, isc_mem_t *mctx, - cfg_aclconfctx_t *actx, isc_boolean_t need_hints) +configure_view(dns_view_t *view, cfg_parser_t* parser, + cfg_obj_t *config, cfg_obj_t *vconfig, + ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys, + isc_mem_t *mctx, cfg_aclconfctx_t *actx, + isc_boolean_t need_hints) { const cfg_obj_t *maps[4]; const cfg_obj_t *cfgmaps[3]; + const cfg_obj_t *optionmaps[3]; const cfg_obj_t *options = NULL; const cfg_obj_t *voptions = NULL; const cfg_obj_t *forwardtype; @@ -1028,17 +1581,20 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_cache_t *cache = NULL; isc_result_t result; isc_uint32_t max_adb_size; + unsigned int cleaning_interval; isc_uint32_t max_cache_size; isc_uint32_t max_acache_size; isc_uint32_t lame_ttl; - dns_tsig_keyring_t *ring; + dns_tsig_keyring_t *ring = NULL; dns_view_t *pview = NULL; /* Production view */ isc_mem_t *cmctx; dns_dispatch_t *dispatch4 = NULL; dns_dispatch_t *dispatch6 = NULL; isc_boolean_t reused_cache = ISC_FALSE; - int i; + isc_boolean_t shared_cache = ISC_FALSE; + int i = 0, j = 0, k = 0; const char *str; + const char *cachename = NULL; dns_order_t *order = NULL; isc_uint32_t udpsize; unsigned int resopts = 0; @@ -1052,7 +1608,14 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *disablelist = NULL; isc_stats_t *resstats = NULL; dns_stats_t *resquerystats = NULL; + isc_boolean_t auto_dlv = ISC_FALSE; + isc_boolean_t auto_root = ISC_FALSE; + ns_cache_t *nsc; isc_boolean_t zero_no_soattl; + cfg_parser_t *newzones_parser = NULL; + cfg_obj_t *nzfconf = NULL; + dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; + unsigned int query_timeout; REQUIRE(DNS_VIEW_VALID(view)); @@ -1061,22 +1624,28 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (config != NULL) (void)cfg_map_get(config, "options", &options); - i = 0; + /* + * maps: view options, options, defaults + * cfgmaps: view options, config + * optionmaps: view options, options + */ if (vconfig != NULL) { voptions = cfg_tuple_get(vconfig, "options"); maps[i++] = voptions; + optionmaps[j++] = voptions; + cfgmaps[k++] = voptions; } - if (options != NULL) + if (options != NULL) { maps[i++] = options; + optionmaps[j++] = options; + } + maps[i++] = ns_g_defaults; maps[i] = NULL; - - i = 0; - if (voptions != NULL) - cfgmaps[i++] = voptions; + optionmaps[j] = NULL; if (config != NULL) - cfgmaps[i++] = config; - cfgmaps[i] = NULL; + cfgmaps[k++] = config; + cfgmaps[k] = NULL; if (!strcmp(viewname, "_default")) { sep = ""; @@ -1137,12 +1706,12 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_acache_setcachesize(view->acache, max_acache_size); } - CHECK(configure_view_acl(vconfig, config, "allow-query", actx, + CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx, ns_g_mctx, &view->queryacl)); - if (view->queryacl == NULL) { - CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", actx, - ns_g_mctx, &view->queryacl)); + CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", + NULL, actx, ns_g_mctx, + &view->queryacl)); } /* @@ -1159,7 +1728,62 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, { const cfg_obj_t *zconfig = cfg_listelt_value(element); CHECK(configure_zone(config, zconfig, vconfig, mctx, view, - actx)); + actx, ISC_FALSE)); + } + + /* + * Are we allowing zones to be added and deleted dynamically? + */ + obj = NULL; + result = ns_config_get(maps, "allow-new-zones", &obj); + if (result == ISC_R_SUCCESS) { + isc_boolean_t allow = cfg_obj_asboolean(obj); + struct cfg_context *cfg = NULL; + if (allow) { + cfg = isc_mem_get(view->mctx, sizeof(*cfg)); + if (cfg == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + memset(cfg, 0, sizeof(*cfg)); + isc_mem_attach(view->mctx, &cfg->mctx); + if (config != NULL) + cfg_obj_attach(config, &cfg->config); + cfg_parser_attach(parser, &cfg->parser); + cfg_aclconfctx_clone(actx, &cfg->actx); + } + dns_view_setnewzones(view, allow, cfg, cfgctx_destroy); + } + + /* + * If we're allowing added zones, then load zone configuration + * from the newzone file for zones that were added during previous + * runs. + */ + if (view->new_zone_file != NULL) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "loading additional zones for view '%s'", + view->name); + + CHECK(cfg_parser_create(view->mctx, ns_g_lctx, + &newzones_parser)); + result = cfg_parse_file(newzones_parser, view->new_zone_file, + &cfg_type_newzones, &nzfconf); + if (result == ISC_R_SUCCESS) { + zonelist = NULL; + cfg_map_get(nzfconf, "zone", &zonelist); + for (element = cfg_list_first(zonelist); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *zconfig = + cfg_listelt_value(element); + CHECK(configure_zone(config, zconfig, vconfig, + mctx, view, actx, + ISC_TRUE)); + } + } } #ifdef DLZ @@ -1197,6 +1821,14 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); if (result != ISC_R_SUCCESS) goto cleanup; + + /* + * If the dlz backend supports configuration, + * then call its configure method now. + */ + result = dns_dlzconfigure(view, dlzconfigure_callback); + if (result != ISC_R_SUCCESS) + goto cleanup; } } #endif @@ -1205,6 +1837,32 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * Obtain configuration parameters that affect the decision of whether * we can reuse/share an existing cache. */ + obj = NULL; + result = ns_config_get(maps, "cleaning-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + cleaning_interval = cfg_obj_asuint32(obj) * 60; + + obj = NULL; + result = ns_config_get(maps, "max-cache-size", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + max_cache_size = ISC_UINT32_MAX; + } else { + isc_resourcevalue_t value; + value = cfg_obj_asuint64(obj); + if (value > ISC_UINT32_MAX) { + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, + "'max-cache-size " + "%" ISC_PRINT_QUADFORMAT "d' is too large", + value); + result = ISC_R_RANGE; + goto cleanup; + } + max_cache_size = (isc_uint32_t)value; + } + /* Check-names. */ obj = NULL; result = ns_checknames_get(maps, "response", &obj); @@ -1229,6 +1887,109 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, zero_no_soattl = cfg_obj_asboolean(obj); obj = NULL; + result = ns_config_get(maps, "dns64", &obj); + if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") && + strcmp(view->name, "_meta")) { + const cfg_listelt_t *element; + isc_netaddr_t na, suffix, *sp; + unsigned int prefixlen; + const char *server, *contact; + const cfg_obj_t *myobj; + + myobj = NULL; + result = ns_config_get(maps, "dns64-server", &myobj); + if (result == ISC_R_SUCCESS) + server = cfg_obj_asstring(myobj); + else + server = NULL; + + myobj = NULL; + result = ns_config_get(maps, "dns64-contact", &myobj); + if (result == ISC_R_SUCCESS) + contact = cfg_obj_asstring(myobj); + else + contact = NULL; + + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *map = cfg_listelt_value(element); + dns_dns64_t *dns64 = NULL; + unsigned int dns64options = 0; + + cfg_obj_asnetprefix(cfg_map_getname(map), &na, + &prefixlen); + + obj = NULL; + (void)cfg_map_get(map, "suffix", &obj); + if (obj != NULL) { + sp = &suffix; + isc_netaddr_fromsockaddr(sp, + cfg_obj_assockaddr(obj)); + } else + sp = NULL; + + clients = mapped = excluded = NULL; + obj = NULL; + (void)cfg_map_get(map, "clients", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + ns_g_lctx, actx, + mctx, 0, &clients); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + obj = NULL; + (void)cfg_map_get(map, "mapped", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + ns_g_lctx, actx, + mctx, 0, &mapped); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + obj = NULL; + (void)cfg_map_get(map, "exclude", &obj); + if (obj != NULL) { + result = cfg_acl_fromconfig(obj, config, + ns_g_lctx, actx, + mctx, 0, &excluded); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + obj = NULL; + (void)cfg_map_get(map, "recursive-only", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) + dns64options |= DNS_DNS64_RECURSIVE_ONLY; + + obj = NULL; + (void)cfg_map_get(map, "break-dnssec", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) + dns64options |= DNS_DNS64_BREAK_DNSSEC; + + result = dns_dns64_create(mctx, &na, prefixlen, sp, + clients, mapped, excluded, + dns64options, &dns64); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_dns64_append(&view->dns64, dns64); + view->dns64cnt++; + result = dns64_reverse(view, mctx, &na, prefixlen, + server, contact); + if (result != ISC_R_SUCCESS) + goto cleanup; + if (clients != NULL) + dns_acl_detach(&clients); + if (mapped != NULL) + dns_acl_detach(&mapped); + if (excluded != NULL) + dns_acl_detach(&excluded); + } + } + + obj = NULL; result = ns_config_get(maps, "dnssec-accept-expired", &obj); INSIST(result == ISC_R_SUCCESS); view->acceptexpired = cfg_obj_asboolean(obj); @@ -1236,7 +1997,13 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, obj = NULL; result = ns_config_get(maps, "dnssec-validation", &obj); INSIST(result == ISC_R_SUCCESS); - view->enablevalidation = cfg_obj_asboolean(obj); + if (cfg_obj_isboolean(obj)) { + view->enablevalidation = cfg_obj_asboolean(obj); + } else { + /* If dnssec-validation is not boolean, it must be "auto" */ + view->enablevalidation = ISC_TRUE; + auto_root = ISC_TRUE; + } obj = NULL; result = ns_config_get(maps, "max-cache-ttl", &obj); @@ -1251,53 +2018,113 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, view->maxncachettl = 7 * 24 * 3600; /* - * Configure the view's cache. Try to reuse an existing - * cache if possible, otherwise create a new cache. - * Note that the ADB is not preserved in either case. - * When a matching view is found, the associated statistics are - * also retrieved and reused. + * Configure the view's cache. + * + * First, check to see if there are any attach-cache options. If yes, + * attempt to lookup an existing cache at attach it to the view. If + * there is not one, then try to reuse an existing cache if possible; + * otherwise create a new cache. * - * XXX Determining when it is safe to reuse a cache is tricky. + * Note that the ADB is not preserved or shared in either case. + * + * When a matching view is found, the associated statistics are also + * retrieved and reused. + * + * XXX Determining when it is safe to reuse or share a cache is tricky. * When the view's configuration changes, the cached data may become * invalid because it reflects our old view of the world. We check - * some of the configuration parameters that could invalidate the cache, - * but there are other configuration options that should be checked. - * For example, if a view uses a forwarder, changes in the forwarder - * configuration may invalidate the cache. At the moment, it's the - * administrator's responsibility to ensure these configuration options - * don't invalidate reusing. + * some of the configuration parameters that could invalidate the cache + * or otherwise make it unsharable, but there are other configuration + * options that should be checked. For example, if a view uses a + * forwarder, changes in the forwarder configuration may invalidate + * the cache. At the moment, it's the administrator's responsibility to + * ensure these configuration options don't invalidate reusing/sharing. */ - result = dns_viewlist_find(&ns_g_server->viewlist, - view->name, view->rdclass, - &pview); - if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) - goto cleanup; - if (pview != NULL) { - if (cache_reusable(pview, view, zero_no_soattl)) { - INSIST(pview->cache != NULL); - isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), - "reusing existing cache"); - reused_cache = ISC_TRUE; - dns_cache_attach(pview->cache, &cache); - } else { + obj = NULL; + result = ns_config_get(maps, "attach-cache", &obj); + if (result == ISC_R_SUCCESS) + cachename = cfg_obj_asstring(obj); + else + cachename = view->name; + cache = NULL; + nsc = cachelist_find(cachelist, cachename); + if (nsc != NULL) { + if (!cache_sharable(nsc->primaryview, view, zero_no_soattl, + cleaning_interval, max_cache_size)) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), - "cache cannot be reused for view %s " + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "views %s and %s can't share the cache " "due to configuration parameter mismatch", - view->name); + nsc->primaryview->name, view->name); + result = ISC_R_FAILURE; + goto cleanup; } - dns_view_getresstats(pview, &resstats); - dns_view_getresquerystats(pview, &resquerystats); - dns_view_detach(&pview); - } - if (cache == NULL) { - CHECK(isc_mem_create(0, 0, &cmctx)); - CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, - view->rdclass, "rbt", 0, NULL, &cache)); - isc_mem_setname(cmctx, "cache", NULL); + dns_cache_attach(nsc->cache, &cache); + shared_cache = ISC_TRUE; + } else { + if (strcmp(cachename, view->name) == 0) { + result = dns_viewlist_find(&ns_g_server->viewlist, + cachename, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + goto cleanup; + if (pview != NULL) { + if (!cache_reusable(pview, view, + zero_no_soattl)) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_DEBUG(1), + "cache cannot be reused " + "for view %s due to " + "configuration parameter " + "mismatch", view->name); + } else { + INSIST(pview->cache != NULL); + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_DEBUG(3), + "reusing existing cache"); + reused_cache = ISC_TRUE; + dns_cache_attach(pview->cache, &cache); + } + dns_view_getresstats(pview, &resstats); + dns_view_getresquerystats(pview, + &resquerystats); + dns_view_detach(&pview); + } + } + if (cache == NULL) { + /* + * Create a cache with the desired name. This normally + * equals the view name, but may also be a forward + * reference to a view that share the cache with this + * view but is not yet configured. If it is not the + * view name but not a forward reference either, then it + * is simply a named cache that is not shared. + */ + CHECK(isc_mem_create(0, 0, &cmctx)); + isc_mem_setname(cmctx, "cache", NULL); + CHECK(dns_cache_create2(cmctx, ns_g_taskmgr, + ns_g_timermgr, view->rdclass, + cachename, "rbt", 0, NULL, + &cache)); + } + nsc = isc_mem_get(mctx, sizeof(*nsc)); + if (nsc == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + nsc->cache = NULL; + dns_cache_attach(cache, &nsc->cache); + nsc->primaryview = view; + nsc->needflush = ISC_FALSE; + nsc->adbsizeadjusted = ISC_FALSE; + ISC_LINK_INIT(nsc, link); + ISC_LIST_APPEND(*cachelist, nsc, link); } - dns_view_setcache(view, cache); + dns_view_setcache2(view, cache, shared_cache); /* * cache-file cannot be inherited if views are present, but this @@ -1307,35 +2134,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, result = ns_config_get(maps, "cache-file", &obj); if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); - if (!reused_cache) + if (!reused_cache && !shared_cache) CHECK(dns_cache_load(cache)); } - obj = NULL; - result = ns_config_get(maps, "cleaning-interval", &obj); - INSIST(result == ISC_R_SUCCESS); - dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60); - - obj = NULL; - result = ns_config_get(maps, "max-cache-size", &obj); - INSIST(result == ISC_R_SUCCESS); - if (cfg_obj_isstring(obj)) { - str = cfg_obj_asstring(obj); - INSIST(strcasecmp(str, "unlimited") == 0); - max_cache_size = ISC_UINT32_MAX; - } else { - isc_resourcevalue_t value; - value = cfg_obj_asuint64(obj); - if (value > ISC_UINT32_MAX) { - cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, - "'max-cache-size " - "%" ISC_PRINT_QUADFORMAT "d' is too large", - value); - result = ISC_R_RANGE; - goto cleanup; - } - max_cache_size = (isc_uint32_t)value; - } + dns_cache_setcleaninginterval(cache, cleaning_interval); dns_cache_setcachesize(cache, max_cache_size); dns_cache_detach(&cache); @@ -1373,13 +2176,23 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_view_setresquerystats(view, resquerystats); /* - * Set the ADB cache size to 1/8th of the max-cache-size. + * Set the ADB cache size to 1/8th of the max-cache-size or + * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. */ max_adb_size = 0; if (max_cache_size != 0) { max_adb_size = max_cache_size / 8; if (max_adb_size == 0) max_adb_size = 1; /* Force minimum. */ + if (view != nsc->primaryview && + max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) { + max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE; + if (!nsc->adbsizeadjusted) { + dns_adb_setadbsize(nsc->primaryview->adb, + MAX_ADB_SIZE_FOR_CACHESHARE); + nsc->adbsizeadjusted = ISC_TRUE; + } + } } dns_adb_setadbsize(view->adb, max_adb_size); @@ -1395,6 +2208,18 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_resolver_setlamettl(view->resolver, lame_ttl); /* + * Set the resolver's query timeout. + */ + obj = NULL; + result = ns_config_get(maps, "resolver-query-timeout", &obj); + INSIST(result == ISC_R_SUCCESS); + query_timeout = cfg_obj_asuint32(obj); + dns_resolver_settimeout(view->resolver, query_timeout); + + /* Specify whether to use 0-TTL for negative response for SOA query */ + dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl); + + /* * Set the resolver's EDNS UDP size. */ obj = NULL; @@ -1484,9 +2309,29 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, /* * Configure the view's TSIG keys. */ - ring = NULL; CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); + if (ns_g_server->sessionkey != NULL) { + CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname, + ns_g_server->sessionkey)); + } dns_view_setkeyring(view, ring); + dns_tsigkeyring_detach(&ring); + + /* + * See if we can re-use a dynamic key ring. + */ + result = dns_viewlist_find(&ns_g_server->viewlist, view->name, + view->rdclass, &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) + goto cleanup; + if (pview != NULL) { + dns_view_getdynamickeyring(pview, &ring); + if (ring != NULL) + dns_view_setdynamickeyring(view, ring); + dns_tsigkeyring_detach(&ring); + dns_view_detach(&pview); + } else + dns_view_restorekeyring(view); /* * Configure the view's peer list. @@ -1543,10 +2388,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, /* * Configure the "match-clients" and "match-destinations" ACL. */ - CHECK(configure_view_acl(vconfig, config, "match-clients", actx, + CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx, ns_g_mctx, &view->matchclients)); - CHECK(configure_view_acl(vconfig, config, "match-destinations", actx, - ns_g_mctx, &view->matchdestinations)); + CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL, + actx, ns_g_mctx, &view->matchdestinations)); /* * Configure the "match-recursive-only" option. @@ -1618,20 +2463,20 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * "allow-recursion", and "allow-recursion-on" acls if * configured in named.conf. */ - CHECK(configure_view_acl(vconfig, config, "allow-query-cache", + CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL, actx, ns_g_mctx, &view->cacheacl)); - CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", + CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL, actx, ns_g_mctx, &view->cacheonacl)); if (view->cacheonacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-query-cache-on", actx, + "allow-query-cache-on", NULL, actx, ns_g_mctx, &view->cacheonacl)); if (strcmp(view->name, "_bind") != 0) { CHECK(configure_view_acl(vconfig, config, "allow-recursion", - actx, ns_g_mctx, + NULL, actx, ns_g_mctx, &view->recursionacl)); CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", - actx, ns_g_mctx, + NULL, actx, ns_g_mctx, &view->recursiononacl)); } @@ -1643,8 +2488,14 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ if (view->cacheacl == NULL && view->recursionacl != NULL) dns_acl_attach(view->recursionacl, &view->cacheacl); + /* + * XXXEACH: This call to configure_view_acl() is redundant. We + * are leaving it as it is because we are making a minimal change + * for a patch release. In the future this should be changed to + * dns_acl_attach(view->queryacl, &view->cacheacl). + */ if (view->cacheacl == NULL && view->recursion) - CHECK(configure_view_acl(vconfig, config, "allow-query", + CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx, ns_g_mctx, &view->cacheacl)); if (view->recursion && view->recursionacl == NULL && view->cacheacl != NULL) @@ -1656,24 +2507,44 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ if (view->recursionacl == NULL && view->recursion) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-recursion", + "allow-recursion", NULL, actx, ns_g_mctx, &view->recursionacl)); if (view->recursiononacl == NULL && view->recursion) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-recursion-on", + "allow-recursion-on", NULL, actx, ns_g_mctx, &view->recursiononacl)); if (view->cacheacl == NULL) { if (view->recursion) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-query-cache", actx, - ns_g_mctx, &view->cacheacl)); + "allow-query-cache", NULL, + actx, ns_g_mctx, + &view->cacheacl)); else - CHECK(dns_acl_none(ns_g_mctx, &view->cacheacl)); + CHECK(dns_acl_none(mctx, &view->cacheacl)); } /* + * Filter setting on addresses in the answer section. + */ + CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses", + "acl", actx, ns_g_mctx, &view->denyansweracl)); + CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses", + "except-from", ns_g_mctx, + &view->answeracl_exclude)); + + /* + * Filter setting on names (CNAME/DNAME targets) in the answer section. + */ + CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", + "name", ns_g_mctx, + &view->denyanswernames)); + CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", + "except-from", ns_g_mctx, + &view->answernames_exclude)); + + /* * Configure sortlist, if set */ CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, @@ -1686,19 +2557,19 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ if (view->notifyacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-notify", actx, + "allow-notify", NULL, actx, ns_g_mctx, &view->notifyacl)); if (view->transferacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-transfer", actx, + "allow-transfer", NULL, actx, ns_g_mctx, &view->transferacl)); if (view->updateacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-update", actx, + "allow-update", NULL, actx, ns_g_mctx, &view->updateacl)); if (view->upfwdacl == NULL) CHECK(configure_view_acl(NULL, ns_g_config, - "allow-update-forwarding", actx, + "allow-update-forwarding", NULL, actx, ns_g_mctx, &view->upfwdacl)); obj = NULL; @@ -1728,13 +2599,47 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, cfg_obj_asuint32(obj), max_clients_per_query); +#ifdef ALLOW_FILTER_AAAA_ON_V4 + obj = NULL; + result = ns_config_get(maps, "filter-aaaa-on-v4", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) + view->v4_aaaa = dns_v4_aaaa_filter; + else + view->v4_aaaa = dns_v4_aaaa_ok; + } else { + const char *v4_aaaastr = cfg_obj_asstring(obj); + if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) + view->v4_aaaa = dns_v4_aaaa_break_dnssec; + else + INSIST(0); + } + CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL, + actx, ns_g_mctx, &view->v4_aaaa_acl)); +#endif + obj = NULL; result = ns_config_get(maps, "dnssec-enable", &obj); INSIST(result == ISC_R_SUCCESS); view->enablednssec = cfg_obj_asboolean(obj); obj = NULL; - result = ns_config_get(maps, "dnssec-lookaside", &obj); + result = ns_config_get(optionmaps, "dnssec-lookaside", &obj); + if (result == ISC_R_SUCCESS) { + /* If set to "auto", use the version from the defaults */ + const cfg_obj_t *dlvobj; + dlvobj = cfg_listelt_value(cfg_list_first(obj)); + if (!strcmp(cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain")), + "auto") && + cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) { + auto_dlv = ISC_TRUE; + obj = NULL; + result = cfg_map_get(ns_g_defaults, + "dnssec-lookaside", &obj); + } + } + if (result == ISC_R_SUCCESS) { for (element = cfg_list_first(obj); element != NULL; @@ -1745,31 +2650,13 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_name_t *dlv; obj = cfg_listelt_value(element); -#if 0 - dns_fixedname_t fixed; - dns_name_t *name; - - /* - * When we support multiple dnssec-lookaside - * entries this is how to find the domain to be - * checked. XXXMPA - */ - dns_fixedname_init(&fixed); - name = dns_fixedname_name(&fixed); - str = cfg_obj_asstring(cfg_tuple_get(obj, - "domain")); - isc_buffer_init(&b, str, strlen(str)); - isc_buffer_add(&b, strlen(str)); - CHECK(dns_name_fromtext(name, &b, dns_rootname, - ISC_TRUE, NULL)); -#endif str = cfg_obj_asstring(cfg_tuple_get(obj, "trust-anchor")); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); dlv = dns_fixedname_name(&view->dlv_fixed); CHECK(dns_name_fromtext(dlv, &b, dns_rootname, - ISC_TRUE, NULL)); + DNS_NAME_DOWNCASE, NULL)); view->dlv = dns_fixedname_name(&view->dlv_fixed); } } else @@ -1779,8 +2666,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * For now, there is only one kind of trusted keys, the * "security roots". */ - CHECK(configure_view_dnsseckeys(vconfig, config, mctx, - &view->secroots)); + CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, + auto_dlv, auto_root, mctx)); dns_resolver_resetmustbesecure(view->resolver); obj = NULL; result = ns_config_get(maps, "dnssec-must-be-secure", &obj); @@ -1821,7 +2708,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); CHECK(dns_name_fromtext(name, &b, dns_rootname, - ISC_FALSE, NULL)); + 0, NULL)); CHECK(dns_view_excludedelegationonly(view, name)); } @@ -1874,8 +2761,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, str = cfg_obj_asstring(obj); isc_buffer_init(&buffer, str, strlen(str)); isc_buffer_add(&buffer, strlen(str)); - CHECK(dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, + NULL)); isc_buffer_init(&buffer, server, sizeof(server) - 1); CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); server[isc_buffer_usedlength(&buffer)] = 0; @@ -1889,8 +2776,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, str = cfg_obj_asstring(obj); isc_buffer_init(&buffer, str, strlen(str)); isc_buffer_add(&buffer, strlen(str)); - CHECK(dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, + NULL)); isc_buffer_init(&buffer, contact, sizeof(contact) - 1); CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); contact[isc_buffer_usedlength(&buffer)] = 0; @@ -1916,8 +2803,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, /* * Look for zone on drop list. */ - CHECK(dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, + NULL)); if (disablelist != NULL && on_disable_list(disablelist, name)) continue; @@ -2012,9 +2899,40 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } } + /* + * Make the list of response policy zone names for views that + * are used for real lookups and so care about hints. + */ + zonelist = NULL; + if (view->rdclass == dns_rdataclass_in && need_hints) { + obj = NULL; + result = ns_config_get(maps, "response-policy", &obj); + if (result == ISC_R_SUCCESS) + cfg_map_get(obj, "zone", &zonelist); + } + if (zonelist != NULL) { + + for (element = cfg_list_first(zonelist); + element != NULL; + element = cfg_list_next(element)) { + result = configure_rpz(view, element); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rpz_set_need(ISC_TRUE); + } + } + result = ISC_R_SUCCESS; cleanup: + if (clients != NULL) + dns_acl_detach(&clients); + if (mapped != NULL) + dns_acl_detach(&mapped); + if (excluded != NULL) + dns_acl_detach(&excluded); + if (ring != NULL) + dns_tsigkeyring_detach(&ring); if (zone != NULL) dns_zone_detach(&zone); if (dispatch4 != NULL) @@ -2033,6 +2951,12 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (cache != NULL) dns_cache_detach(&cache); + if (newzones_parser != NULL) { + if (nzfconf != NULL) + cfg_obj_destroy(newzones_parser, &nzfconf); + cfg_parser_destroy(&newzones_parser); + } + return (result); } @@ -2105,8 +3029,8 @@ configure_alternates(const cfg_obj_t *config, dns_view_t *view, isc_buffer_add(&buffer, strlen(str)); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); - CHECK(dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL)); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, + NULL)); portobj = cfg_tuple_get(alternate, "port"); if (cfg_obj_isuint32(portobj)) { @@ -2286,7 +3210,7 @@ create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, static isc_result_t configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, - cfg_aclconfctx_t *aclconf) + cfg_aclconfctx_t *aclconf, isc_boolean_t added) { dns_view_t *pview = NULL; /* Production view */ dns_zone_t *zone = NULL; /* New or reused zone */ @@ -2319,7 +3243,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, isc_buffer_add(&buffer, strlen(zname)); dns_fixedname_init(&fixorigin); CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), - &buffer, dns_rootname, ISC_FALSE, NULL)); + &buffer, dns_rootname, 0, NULL)); origin = dns_fixedname_name(&fixorigin); CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), @@ -2349,7 +3273,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, ztypestr = cfg_obj_asstring(typeobj); /* - * "hints zones" aren't zones. If we've got one, + * "hints zones" aren't zones. If we've got one, * configure it and return. */ if (strcasecmp(ztypestr, "hint") == 0) { @@ -2500,6 +3424,11 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, } /* + * Mark whether the zone was originally added at runtime or not + */ + dns_zone_setadded(zone, added); + + /* * Configure the zone. */ CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); @@ -2519,6 +3448,95 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, } /* + * Configure built-in zone for storing managed-key data. + */ + +#define KEYZONE "managed-keys.bind" +#define MKEYS ".mkeys" + +static isc_result_t +add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { + isc_result_t result; + dns_view_t *pview = NULL; + dns_zone_t *zone = NULL; + dns_acl_t *none = NULL; + char filename[PATH_MAX]; + char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)]; + int n; + + REQUIRE(view != NULL); + + /* See if we can re-use an existing keydata zone. */ + result = dns_viewlist_find(&ns_g_server->viewlist, + view->name, view->rdclass, + &pview); + if (result != ISC_R_NOTFOUND && + result != ISC_R_SUCCESS) + return (result); + + if (pview != NULL && pview->managed_keys != NULL) { + dns_zone_attach(pview->managed_keys, &view->managed_keys); + dns_zone_setview(pview->managed_keys, view); + dns_view_detach(&pview); + return (ISC_R_SUCCESS); + } + + /* No existing keydata zone was found; create one */ + CHECK(dns_zone_create(&zone, mctx)); + CHECK(dns_zone_setorigin(zone, dns_rootname)); + + isc_sha256_data((void *)view->name, strlen(view->name), buffer); + strcat(buffer, MKEYS); + n = snprintf(filename, sizeof(filename), "%s%s%s", + directory ? directory : "", directory ? "/" : "", + strcmp(view->name, "_default") == 0 ? KEYZONE : buffer); + if (n < 0 || (size_t)n >= sizeof(filename)) { + result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE; + goto cleanup; + } + CHECK(dns_zone_setfile(zone, filename)); + + dns_zone_setview(zone, view); + dns_zone_settype(zone, dns_zone_key); + dns_zone_setclass(zone, view->rdclass); + + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); + + CHECK(dns_acl_none(mctx, &none)); + dns_zone_setqueryacl(zone, none); + dns_zone_setqueryonacl(zone, none); + dns_acl_detach(&none); + + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); + dns_zone_setjournalsize(zone, 0); + + dns_zone_setstats(zone, ns_g_server->zonestats); + CHECK(setquerystats(zone, mctx, ISC_FALSE)); + + if (view->managed_keys != NULL) + dns_zone_detach(&view->managed_keys); + dns_zone_attach(zone, &view->managed_keys); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "set up managed keys zone for view %s, file '%s'", + view->name, filename); + +cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (none != NULL) + dns_acl_detach(&none); + + return (result); +} + +/* * Configure a single server quota. */ static void @@ -2914,13 +3932,226 @@ removed(dns_zone_t *zone, void *uap) { return (ISC_R_SUCCESS); } +static void +cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) { + if (server->session_keyfile != NULL) { + isc_file_remove(server->session_keyfile); + isc_mem_free(mctx, server->session_keyfile); + server->session_keyfile = NULL; + } + + if (server->session_keyname != NULL) { + if (dns_name_dynamic(server->session_keyname)) + dns_name_free(server->session_keyname, mctx); + isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t)); + server->session_keyname = NULL; + } + + if (server->sessionkey != NULL) + dns_tsigkey_detach(&server->sessionkey); + + server->session_keyalg = DST_ALG_UNKNOWN; + server->session_keybits = 0; +} + +static isc_result_t +generate_session_key(const char *filename, const char *keynamestr, + dns_name_t *keyname, const char *algstr, + dns_name_t *algname, unsigned int algtype, + isc_uint16_t bits, isc_mem_t *mctx, + dns_tsigkey_t **tsigkeyp) +{ + isc_result_t result = ISC_R_SUCCESS; + dst_key_t *key = NULL; + isc_buffer_t key_txtbuffer; + isc_buffer_t key_rawbuffer; + char key_txtsecret[256]; + char key_rawsecret[64]; + isc_region_t key_rawregion; + isc_stdtime_t now; + dns_tsigkey_t *tsigkey = NULL; + FILE *fp = NULL; + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "generating session key for dynamic DNS"); + + /* generate key */ + result = dst_key_generate(keyname, algtype, bits, 1, 0, + DNS_KEYPROTO_ANY, dns_rdataclass_in, + mctx, &key); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Dump the key to the buffer for later use. Should be done before + * we transfer the ownership of key to tsigkey. + */ + isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); + CHECK(dst_key_tobuffer(key, &key_rawbuffer)); + + isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); + CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer)); + + /* Store the key in tsigkey. */ + isc_stdtime_get(&now); + CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, + ISC_FALSE, NULL, now, now, mctx, NULL, + &tsigkey)); + + /* Dump the key to the key file. */ + fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE); + if (fp == NULL) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "could not create %s", filename); + result = ISC_R_NOPERM; + goto cleanup; + } + + fprintf(fp, "key \"%s\" {\n" + "\talgorithm %s;\n" + "\tsecret \"%.*s\";\n};\n", keynamestr, algstr, + (int) isc_buffer_usedlength(&key_txtbuffer), + (char*) isc_buffer_base(&key_txtbuffer)); + + RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS); + + dst_key_free(&key); + + *tsigkeyp = tsigkey; + + return (ISC_R_SUCCESS); + + cleanup: + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed to generate session key " + "for dynamic DNS: %s", isc_result_totext(result)); + if (tsigkey != NULL) + dns_tsigkey_detach(&tsigkey); + if (key != NULL) + dst_key_free(&key); + + return (result); +} + +static isc_result_t +configure_session_key(const cfg_obj_t **maps, ns_server_t *server, + isc_mem_t *mctx) +{ + const char *keyfile, *keynamestr, *algstr; + unsigned int algtype; + dns_fixedname_t fname; + dns_name_t *keyname, *algname; + isc_buffer_t buffer; + isc_uint16_t bits; + const cfg_obj_t *obj; + isc_boolean_t need_deleteold = ISC_FALSE; + isc_boolean_t need_createnew = ISC_FALSE; + isc_result_t result; + + obj = NULL; + result = ns_config_get(maps, "session-keyfile", &obj); + if (result == ISC_R_SUCCESS) { + if (cfg_obj_isvoid(obj)) + keyfile = NULL; /* disable it */ + else + keyfile = cfg_obj_asstring(obj); + } else + keyfile = ns_g_defaultsessionkeyfile; + + obj = NULL; + result = ns_config_get(maps, "session-keyname", &obj); + INSIST(result == ISC_R_SUCCESS); + keynamestr = cfg_obj_asstring(obj); + dns_fixedname_init(&fname); + isc_buffer_init(&buffer, keynamestr, strlen(keynamestr)); + isc_buffer_add(&buffer, strlen(keynamestr)); + keyname = dns_fixedname_name(&fname); + result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + obj = NULL; + result = ns_config_get(maps, "session-keyalg", &obj); + INSIST(result == ISC_R_SUCCESS); + algstr = cfg_obj_asstring(obj); + algname = NULL; + result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits); + if (result != ISC_R_SUCCESS) { + const char *s = " (keeping current key)"; + + cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: " + "unsupported or unknown algorithm '%s'%s", + algstr, + server->session_keyfile != NULL ? s : ""); + return (result); + } + + /* See if we need to (re)generate a new key. */ + if (keyfile == NULL) { + if (server->session_keyfile != NULL) + need_deleteold = ISC_TRUE; + } else if (server->session_keyfile == NULL) + need_createnew = ISC_TRUE; + else if (strcmp(keyfile, server->session_keyfile) != 0 || + !dns_name_equal(server->session_keyname, keyname) || + server->session_keyalg != algtype || + server->session_keybits != bits) { + need_deleteold = ISC_TRUE; + need_createnew = ISC_TRUE; + } + + if (need_deleteold) { + INSIST(server->session_keyfile != NULL); + INSIST(server->session_keyname != NULL); + INSIST(server->sessionkey != NULL); + + cleanup_session_key(server, mctx); + } + + if (need_createnew) { + INSIST(server->sessionkey == NULL); + INSIST(server->session_keyfile == NULL); + INSIST(server->session_keyname == NULL); + INSIST(server->session_keyalg == DST_ALG_UNKNOWN); + INSIST(server->session_keybits == 0); + + server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t)); + if (server->session_keyname == NULL) + goto cleanup; + dns_name_init(server->session_keyname, NULL); + CHECK(dns_name_dup(keyname, mctx, server->session_keyname)); + + server->session_keyfile = isc_mem_strdup(mctx, keyfile); + if (server->session_keyfile == NULL) + goto cleanup; + + server->session_keyalg = algtype; + server->session_keybits = bits; + + CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr, + algname, algtype, bits, mctx, + &server->sessionkey)); + } + + return (result); + + cleanup: + cleanup_session_key(server, mctx); + return (result); +} + static isc_result_t load_configuration(const char *filename, ns_server_t *server, isc_boolean_t first_time) { cfg_aclconfctx_t aclconfctx; - cfg_obj_t *config; - cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL, *bindkeys = NULL; + cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL; const cfg_listelt_t *element; const cfg_obj_t *builtin_views; const cfg_obj_t *maps[3]; @@ -2931,7 +4162,7 @@ load_configuration(const char *filename, ns_server_t *server, dns_view_t *view = NULL; dns_view_t *view_next; dns_viewlist_t tmpviewlist; - dns_viewlist_t viewlist; + dns_viewlist_t viewlist, builtin_viewlist; in_port_t listen_port, udpport_low, udpport_high; int i; isc_interval_t interval; @@ -2943,10 +4174,14 @@ load_configuration(const char *filename, ns_server_t *server, isc_uint32_t interface_interval; isc_uint32_t reserved; isc_uint32_t udpsize; + ns_cachelist_t cachelist, tmpcachelist; unsigned int maxsocks; + ns_cache_t *nsc; cfg_aclconfctx_init(&aclconfctx); ISC_LIST_INIT(viewlist); + ISC_LIST_INIT(builtin_viewlist); + ISC_LIST_INIT(cachelist); /* Ensure exclusive access to configuration data. */ result = isc_task_beginexclusive(server->task); @@ -2958,8 +4193,7 @@ load_configuration(const char *filename, ns_server_t *server, if (first_time) { CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", - &ns_g_defaults) == - ISC_R_SUCCESS); + &ns_g_defaults) == ISC_R_SUCCESS); } /* @@ -2976,10 +4210,10 @@ load_configuration(const char *filename, ns_server_t *server, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_INFO, "loading configuration from '%s'", filename); - CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); - cfg_parser_setcallback(parser, directory_callback, NULL); - result = cfg_parse_file(parser, filename, &cfg_type_namedconf, - &config); + CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); + cfg_parser_setcallback(conf_parser, directory_callback, NULL); + result = cfg_parse_file(conf_parser, filename, + &cfg_type_namedconf, &config); } /* @@ -2994,10 +4228,10 @@ load_configuration(const char *filename, ns_server_t *server, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_INFO, "loading configuration from '%s'", lwresd_g_resolvconffile); - if (parser != NULL) - cfg_parser_destroy(&parser); - CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); - result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser, + if (conf_parser != NULL) + cfg_parser_destroy(&conf_parser); + CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); + result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser, &config); } CHECK(result); @@ -3019,13 +4253,38 @@ load_configuration(const char *filename, ns_server_t *server, maps[i++] = NULL; /* + * If bind.keys exists, load it. If "dnssec-lookaside auto" + * is turned on, the keys found there will be used as default + * trust anchors. + */ + obj = NULL; + result = ns_config_get(maps, "bindkeys-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->bindkeysfile, + cfg_obj_asstring(obj)), "strdup"); + + if (access(server->bindkeysfile, R_OK) == 0) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "reading built-in trusted " + "keys from file '%s'", server->bindkeysfile); + + CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, + &bindkeys_parser)); + + result = cfg_parse_file(bindkeys_parser, server->bindkeysfile, + &cfg_type_bindkeys, &bindkeys); + CHECK(result); + } + + /* * Set process limits, which (usually) needs to be done as root. */ set_limits(maps); /* * Check if max number of open sockets that the system allows is - * sufficiently large. Failing this condition is not necessarily fatal, + * sufficiently large. Failing this condition is not necessarily fatal, * but may cause subsequent runtime failures for a busy recursive * server. */ @@ -3078,7 +4337,7 @@ load_configuration(const char *filename, ns_server_t *server, else isc_quota_soft(&server->recursionquota, 0); - CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx, + CHECK(configure_view_acl(NULL, config, "blackhole", NULL, &aclconfctx, ns_g_mctx, &server->blackholeacl)); if (server->blackholeacl != NULL) dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, @@ -3318,6 +4577,31 @@ load_configuration(const char *filename, ns_server_t *server, &interval, ISC_FALSE)); /* + * Write the PID file. + */ + obj = NULL; + if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) + if (cfg_obj_isvoid(obj)) + ns_os_writepidfile(NULL, first_time); + else + ns_os_writepidfile(cfg_obj_asstring(obj), first_time); + else if (ns_g_lwresdonly) + ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); + else + ns_os_writepidfile(ns_g_defaultpidfile, first_time); + + /* + * Configure the server-wide session key. This must be done before + * configure views because zone configuration may need to know + * session-keyname. + * + * Failure of session key generation isn't fatal at this time; if it + * turns out that a session key is really needed but doesn't exist, + * we'll treat it as a fatal error then. + */ + (void)configure_session_key(maps, server, ns_g_mctx); + + /* * Configure and freeze all explicit views. Explicit * views that have zones were already created at parsing * time, but views with no zones must be created here. @@ -3328,12 +4612,13 @@ load_configuration(const char *filename, ns_server_t *server, element != NULL; element = cfg_list_next(element)) { - const cfg_obj_t *vconfig = cfg_listelt_value(element); + cfg_obj_t *vconfig = cfg_listelt_value(element); view = NULL; CHECK(create_view(vconfig, &viewlist, &view)); INSIST(view != NULL); - CHECK(configure_view(view, config, vconfig, + CHECK(configure_view(view, conf_parser, config, vconfig, + &cachelist, bindkeys, ns_g_mctx, &aclconfctx, ISC_TRUE)); dns_view_freeze(view); dns_view_detach(&view); @@ -3351,15 +4636,15 @@ load_configuration(const char *filename, ns_server_t *server, * In either case, we need to configure and freeze it. */ CHECK(create_view(NULL, &viewlist, &view)); - CHECK(configure_view(view, config, NULL, ns_g_mctx, - &aclconfctx, ISC_TRUE)); + CHECK(configure_view(view, conf_parser, config, NULL, + &cachelist, bindkeys, + ns_g_mctx, &aclconfctx, ISC_TRUE)); dns_view_freeze(view); dns_view_detach(&view); } /* - * Create (or recreate) the built-in views. Currently - * there is only one, the _bind view. + * Create (or recreate) the built-in views. */ builtin_views = NULL; RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", @@ -3368,25 +4653,38 @@ load_configuration(const char *filename, ns_server_t *server, element != NULL; element = cfg_list_next(element)) { - const cfg_obj_t *vconfig = cfg_listelt_value(element); - CHECK(create_view(vconfig, &viewlist, &view)); - CHECK(configure_view(view, config, vconfig, ns_g_mctx, - &aclconfctx, ISC_FALSE)); + cfg_obj_t *vconfig = cfg_listelt_value(element); + + CHECK(create_view(vconfig, &builtin_viewlist, &view)); + CHECK(configure_view(view, conf_parser, config, vconfig, + &cachelist, bindkeys, + ns_g_mctx, &aclconfctx, ISC_FALSE)); dns_view_freeze(view); dns_view_detach(&view); view = NULL; } - /* - * Swap our new view list with the production one. - */ + /* Now combine the two viewlists into one */ + ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); + + /* Swap our new view list with the production one. */ tmpviewlist = server->viewlist; server->viewlist = viewlist; viewlist = tmpviewlist; - /* - * Load the TKEY information from the configuration. - */ + /* Make the view list available to each of the views */ + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + view->viewlist = &server->viewlist; + view = ISC_LIST_NEXT(view, link); + } + + /* Swap our new cache list with the production one. */ + tmpcachelist = server->cachelist; + server->cachelist = cachelist; + cachelist = tmpcachelist; + + /* Load the TKEY information from the configuration. */ if (options != NULL) { dns_tkeyctx_t *t = NULL; CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, @@ -3551,16 +4849,6 @@ load_configuration(const char *filename, ns_server_t *server, } } - obj = NULL; - if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) - if (cfg_obj_isvoid(obj)) - ns_os_writepidfile(NULL, first_time); - else - ns_os_writepidfile(cfg_obj_asstring(obj), first_time); - else if (ns_g_lwresdonly) - ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); - else - ns_os_writepidfile(ns_g_defaultpidfile, first_time); obj = NULL; if (options != NULL && @@ -3591,6 +4879,12 @@ load_configuration(const char *filename, ns_server_t *server, "strdup"); obj = NULL; + result = ns_config_get(maps, "secroots-file", &obj); + INSIST(result == ISC_R_SUCCESS); + CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)), + "strdup"); + + obj = NULL; result = ns_config_get(maps, "recursing-file", &obj); INSIST(result == ISC_R_SUCCESS); CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), @@ -3647,12 +4941,18 @@ load_configuration(const char *filename, ns_server_t *server, if (v6portset != NULL) isc_portset_destroy(ns_g_mctx, &v6portset); - cfg_aclconfctx_destroy(&aclconfctx); + cfg_aclconfctx_clear(&aclconfctx); - if (parser != NULL) { + if (conf_parser != NULL) { if (config != NULL) - cfg_obj_destroy(parser, &config); - cfg_parser_destroy(&parser); + cfg_obj_destroy(conf_parser, &config); + cfg_parser_destroy(&conf_parser); + } + + if (bindkeys_parser != NULL) { + if (bindkeys != NULL) + cfg_obj_destroy(bindkeys_parser, &bindkeys); + cfg_parser_destroy(&bindkeys_parser); } if (view != NULL) @@ -3675,6 +4975,13 @@ load_configuration(const char *filename, ns_server_t *server, dns_view_detach(&view); } + /* Same cleanup for cache list. */ + while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) { + ISC_LIST_UNLINK(cachelist, nsc, link); + dns_cache_detach(&nsc->cache); + isc_mem_put(server->mctx, nsc, sizeof(*nsc)); + } + /* * Adjust the listening interfaces in accordance with the source * addresses specified in views and zones. @@ -3708,6 +5015,8 @@ load_zones(ns_server_t *server, isc_boolean_t stop) { view = ISC_LIST_NEXT(view, link)) { CHECK(dns_view_load(view, stop)); + if (view->managed_keys != NULL) + CHECK(dns_zone_load(view->managed_keys)); } /* @@ -3737,11 +5046,14 @@ load_new_zones(ns_server_t *server, isc_boolean_t stop) { view = ISC_LIST_NEXT(view, link)) { CHECK(dns_view_loadnew(view, stop)); + + /* Load managed-keys data */ + if (view->managed_keys != NULL) + CHECK(dns_zone_loadnew(view->managed_keys)); } + /* - * Force zone maintenance. Do this after loading - * so that we know when we need to force AXFR of - * slave zones whose master files are missing. + * Resume zone XFRs. */ dns_zonemgr_resumexfrs(server->zonemgr); cleanup: @@ -3820,6 +5132,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { dns_view_t *view, *view_next; ns_server_t *server = (ns_server_t *)event->ev_arg; isc_boolean_t flush = server->flushonshutdown; + ns_cache_t *nsc; UNUSED(task); INSIST(task == server->task); @@ -3834,6 +5147,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ns_statschannels_shutdown(server); ns_controls_shutdown(server->controls); end_reserved_dispatches(server, ISC_TRUE); + cleanup_session_key(server, server->mctx); cfg_obj_destroy(ns_g_parser, &ns_g_config); cfg_parser_destroy(&ns_g_parser); @@ -3849,6 +5163,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { dns_view_detach(&view); } + while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { + ISC_LIST_UNLINK(server->cachelist, nsc, link); + dns_cache_detach(&nsc->cache); + isc_mem_put(server->mctx, nsc, sizeof(*nsc)); + } + isc_timer_detach(&server->interface_timer); isc_timer_detach(&server->heartbeat_timer); isc_timer_detach(&server->pps_timer); @@ -3860,6 +5180,11 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { dns_zonemgr_shutdown(server->zonemgr); + if (ns_g_sessionkey != NULL) { + dns_tsigkey_detach(&ns_g_sessionkey); + dns_name_free(&ns_g_sessionkeyname, server->mctx); + } + if (server->blackholeacl != NULL) dns_acl_detach(&server->blackholeacl); @@ -3918,7 +5243,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { ISC_R_NOMEMORY : ISC_R_SUCCESS, "allocating reload event"); - CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), + CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, + ns_g_engine, ISC_ENTROPY_GOODONLY), "initializing DST"); server->tkeyctx = NULL; @@ -3963,10 +5289,20 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { "isc_stats_create"); isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); + server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys"); + CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY : + ISC_R_SUCCESS, + "isc_mem_strdup"); + server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, "isc_mem_strdup"); + server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots"); + CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY : + ISC_R_SUCCESS, + "isc_mem_strdup"); + server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, "isc_mem_strdup"); @@ -4008,6 +5344,14 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { ISC_LIST_INIT(server->statschannels); + ISC_LIST_INIT(server->cachelist); + + server->sessionkey = NULL; + server->session_keyfile = NULL; + server->session_keyname = NULL; + server->session_keyalg = DST_ALG_UNKNOWN; + server->session_keybits = 0; + server->magic = NS_SERVER_MAGIC; *serverp = server; } @@ -4027,7 +5371,9 @@ ns_server_destroy(ns_server_t **serverp) { isc_stats_detach(&server->sockstats); isc_mem_free(server->mctx, server->statsfile); + isc_mem_free(server->mctx, server->bindkeysfile); isc_mem_free(server->mctx, server->dumpfile); + isc_mem_free(server->mctx, server->secrootsfile); isc_mem_free(server->mctx, server->recfile); if (server->version != NULL) @@ -4047,6 +5393,7 @@ ns_server_destroy(ns_server_t **serverp) { isc_event_free(&server->reload_event); INSIST(ISC_LIST_EMPTY(server->viewlist)); + INSIST(ISC_LIST_EMPTY(server->cachelist)); dns_aclenv_destroy(&server->aclenv); @@ -4278,7 +5625,9 @@ next_token(char **stringp, const char *delim) { * set '*zonep' to NULL. */ static isc_result_t -zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { +zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep, + const char **zonename) +{ char *input, *ptr; const char *zonetxt; char *classtxt; @@ -4302,6 +5651,8 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { zonetxt = next_token(&input, " \t"); if (zonetxt == NULL) return (ISC_R_SUCCESS); + if (zonename) + *zonename = zonetxt; /* Look for the optional class name. */ classtxt = next_token(&input, " \t"); @@ -4314,7 +5665,7 @@ zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { isc_buffer_add(&buf, strlen(zonetxt)); dns_fixedname_init(&name); result = dns_name_fromtext(dns_fixedname_name(&name), - &buf, dns_rootname, ISC_FALSE, NULL); + &buf, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto fail1; @@ -4362,7 +5713,7 @@ ns_server_retransfercommand(ns_server_t *server, char *args) { dns_zone_t *zone = NULL; dns_zonetype_t type; - result = zone_from_args(server, args, &zone); + result = zone_from_args(server, args, &zone, NULL); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -4386,7 +5737,7 @@ ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { dns_zonetype_t type; const char *msg = NULL; - result = zone_from_args(server, args, &zone); + result = zone_from_args(server, args, &zone, NULL); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) { @@ -4446,7 +5797,7 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { dns_zone_t *zone = NULL; const unsigned char msg[] = "zone notify queued"; - result = zone_from_args(server, args, &zone); + result = zone_from_args(server, args, &zone, NULL); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -4471,7 +5822,7 @@ ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { const unsigned char msg2[] = "not a slave or stub zone"; dns_zonetype_t type; - result = zone_from_args(server, args, &zone); + result = zone_from_args(server, args, &zone, NULL); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) @@ -4710,15 +6061,23 @@ dumpdone(void *arg, isc_result_t result) { nextview: fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); resume: - if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) { + if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) { + fprintf(dctx->fp, + ";\n; Cache of view '%s' is shared as '%s'\n", + dctx->view->view->name, + dns_cache_getname(dctx->view->view->cache)); + } else if (dctx->zone == NULL && dctx->cache == NULL && + dctx->dumpcache) + { style = &dns_master_style_cache; /* start cache dump */ if (dctx->view->view->cachedb != NULL) dns_db_attach(dctx->view->view->cachedb, &dctx->cache); if (dctx->cache != NULL) { - - fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n", - dctx->view->view->name); + fprintf(dctx->fp, + ";\n; Cache dump of view '%s' (cache %s)\n;\n", + dctx->view->view->name, + dns_cache_getname(dctx->view->view->cache)); result = dns_master_dumptostreaminc(dctx->mctx, dctx->cache, NULL, style, dctx->fp, @@ -4880,6 +6239,68 @@ ns_server_dumpdb(ns_server_t *server, char *args) { } isc_result_t +ns_server_dumpsecroots(ns_server_t *server, char *args) { + dns_view_t *view; + dns_keytable_t *secroots = NULL; + isc_result_t result; + char *ptr; + FILE *fp = NULL; + isc_time_t now; + char tbuf[64]; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + ptr = next_token(&args, " \t"); + + CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp), + "could not open secroots dump file", server->secrootsfile); + TIME_NOW(&now); + isc_time_formattimestamp(&now, tbuf, sizeof(tbuf)); + fprintf(fp, "%s\n", tbuf); + + nextview: + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (ptr != NULL && strcmp(view->name, ptr) != 0) + continue; + if (secroots != NULL) + dns_keytable_detach(&secroots); + result = dns_view_getsecroots(view, &secroots); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + continue; + } + fprintf(fp, "\n Start view %s\n\n", view->name); + CHECK(dns_keytable_dump(secroots, fp)); + } + if (ptr != NULL) { + ptr = next_token(&args, " \t"); + if (ptr != NULL) + goto nextview; + } + + cleanup: + if (secroots != NULL) + dns_keytable_detach(&secroots); + if (fp != NULL) + (void)isc_stdio_close(fp); + if (result == ISC_R_SUCCESS) + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumpsecroots complete"); + else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "dumpsecroots failed: %s", + dns_result_totext(result)); + return (result); +} + +isc_result_t ns_server_dumprecursing(ns_server_t *server) { FILE *fp = NULL; isc_result_t result; @@ -4997,6 +6418,7 @@ ns_server_flushcache(ns_server_t *server, char *args) { isc_boolean_t flushed; isc_boolean_t found; isc_result_t result; + ns_cache_t *nsc; /* Skip the command name. */ ptr = next_token(&args, " \t"); @@ -5010,22 +6432,96 @@ ns_server_flushcache(ns_server_t *server, char *args) { RUNTIME_CHECK(result == ISC_R_SUCCESS); flushed = ISC_TRUE; found = ISC_FALSE; - for (view = ISC_LIST_HEAD(server->viewlist); - view != NULL; - view = ISC_LIST_NEXT(view, link)) - { - if (viewname != NULL && strcasecmp(viewname, view->name) != 0) - continue; + + /* + * Flushing a cache is tricky when caches are shared by multiple views. + * We first identify which caches should be flushed in the local cache + * list, flush these caches, and then update other views that refer to + * the flushed cache DB. + */ + if (viewname != NULL) { + /* + * Mark caches that need to be flushed. This is an O(#view^2) + * operation in the very worst case, but should be normally + * much more lightweight because only a few (most typically just + * one) views will match. + */ + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (strcasecmp(viewname, view->name) != 0) + continue; + found = ISC_TRUE; + for (nsc = ISC_LIST_HEAD(server->cachelist); + nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) { + if (nsc->cache == view->cache) + break; + } + INSIST(nsc != NULL); + nsc->needflush = ISC_TRUE; + } + } else found = ISC_TRUE; - result = dns_view_flushcache(view); + + /* Perform flush */ + for (nsc = ISC_LIST_HEAD(server->cachelist); + nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) { + if (viewname != NULL && !nsc->needflush) + continue; + nsc->needflush = ISC_TRUE; + result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE); if (result != ISC_R_SUCCESS) { flushed = ISC_FALSE; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "flushing cache in view '%s' failed: %s", - view->name, isc_result_totext(result)); + nsc->primaryview->name, + isc_result_totext(result)); + } + } + + /* + * Fix up views that share a flushed cache: let the views update the + * cache DB they're referring to. This could also be an expensive + * operation, but should typically be marginal: the inner loop is only + * necessary for views that share a cache, and if there are many such + * views the number of shared cache should normally be small. + * A worst case is that we have n views and n/2 caches, each shared by + * two views. Then this will be a O(n^2/4) operation. + */ + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (!dns_view_iscacheshared(view)) + continue; + for (nsc = ISC_LIST_HEAD(server->cachelist); + nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) { + if (!nsc->needflush || nsc->cache != view->cache) + continue; + result = dns_view_flushcache2(view, ISC_TRUE); + if (result != ISC_R_SUCCESS) { + flushed = ISC_FALSE; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "fixing cache in view '%s' " + "failed: %s", view->name, + isc_result_totext(result)); + } } } + + /* Cleanup the cache list. */ + for (nsc = ISC_LIST_HEAD(server->cachelist); + nsc != NULL; + nsc = ISC_LIST_NEXT(nsc, link)) { + nsc->needflush = ISC_FALSE; + } + if (flushed && found) { if (viewname != NULL) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, @@ -5076,7 +6572,7 @@ ns_server_flushname(ns_server_t *server, char *args) { isc_buffer_add(&b, strlen(target)); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); - result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) return (result); @@ -5094,6 +6590,11 @@ ns_server_flushname(ns_server_t *server, char *args) { if (viewname != NULL && strcasecmp(viewname, view->name) != 0) continue; found = ISC_TRUE; + /* + * It's a little inefficient to try flushing name for all views + * if some of the views share a single cache. But since the + * operation is lightweight we prefer simplicity here. + */ result = dns_view_flushname(view, name); if (result != ISC_R_SUCCESS) { flushed = ISC_FALSE; @@ -5408,6 +6909,46 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { } /* + * Act on a "sign" or "loadkeys" command from the command channel. + */ +isc_result_t +ns_server_rekey(ns_server_t *server, char *args) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + isc_uint16_t keyopts; + isc_boolean_t fullsign = ISC_FALSE; + + if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0) + fullsign = ISC_TRUE; + + result = zone_from_args(server, args, &zone, NULL); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */ + + type = dns_zone_gettype(zone); + if (type != dns_zone_master) { + dns_zone_detach(&zone); + return (DNS_R_NOTMASTER); + } + + keyopts = dns_zone_getkeyopts(zone); + + /* "rndc loadkeys" requires "auto-dnssec maintain". */ + if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) + result = ISC_R_NOPERM; + else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) + result = ISC_R_NOPERM; + else + dns_zone_rekey(zone, fullsign); + + dns_zone_detach(&zone); + return (result); +} + +/* * Act on a "freeze" or "thaw" command from the command channel. */ isc_result_t @@ -5425,7 +6966,7 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, isc_boolean_t frozen; const char *msg = NULL; - result = zone_from_args(server, args, &zone); + result = zone_from_args(server, args, &zone, NULL); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) { @@ -5451,7 +6992,7 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, type = dns_zone_gettype(zone); if (type != dns_zone_master) { dns_zone_detach(&zone); - return (ISC_R_NOTFOUND); + return (DNS_R_NOTMASTER); } result = isc_task_beginexclusive(server->task); @@ -5502,8 +7043,8 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, strlen(msg) + 1); view = dns_zone_getview(zone); - if (strcmp(view->name, "_bind") == 0 || - strcmp(view->name, "_default") == 0) + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 0) { vname = ""; sep = ""; @@ -5543,3 +7084,376 @@ ns_smf_add_message(isc_buffer_t *text) { return (ISC_R_SUCCESS); } #endif /* HAVE_LIBSCF */ + +/* + * Act on an "addzone" command from the command channel. + */ +isc_result_t +ns_server_add_zone(ns_server_t *server, char *args) { + isc_result_t result; + isc_buffer_t argbuf; + size_t arglen; + cfg_parser_t *parser = NULL; + cfg_obj_t *config = NULL; + const cfg_obj_t *vconfig = NULL; + const cfg_obj_t *views = NULL; + const cfg_obj_t *parms = NULL; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *element; + const char *zonename; + const char *classname = NULL; + const char *argp; + const char *viewname = NULL; + dns_rdataclass_t rdclass; + dns_view_t *view = 0; + isc_buffer_t buf, *nbuf = NULL; + dns_name_t dnsname; + dns_zone_t *zone = NULL; + FILE *fp = NULL; + struct cfg_context *cfg = NULL; + + /* Try to parse the argument string */ + arglen = strlen(args); + isc_buffer_init(&argbuf, args, arglen); + isc_buffer_add(&argbuf, strlen(args)); + CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); + CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, + &config)); + CHECK(cfg_map_get(config, "addzone", &parms)); + + zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name")); + isc_buffer_init(&buf, zonename, strlen(zonename)); + isc_buffer_add(&buf, strlen(zonename)); + dns_name_init(&dnsname, NULL); + isc_buffer_allocate(server->mctx, &nbuf, 256); + dns_name_setbuffer(&dnsname, nbuf); + CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL)); + + /* Make sense of optional class argument */ + obj = cfg_tuple_get(parms, "class"); + CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass)); + if (rdclass != dns_rdataclass_in && obj) + classname = cfg_obj_asstring(obj); + + /* Make sense of optional view argument */ + obj = cfg_tuple_get(parms, "view"); + if (obj && cfg_obj_isstring(obj)) + viewname = cfg_obj_asstring(obj); + if (viewname == NULL || *viewname == '\0') + viewname = "_default"; + CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view)); + + /* Are we accepting new zones? */ + if (view->new_zone_file == NULL) { + result = ISC_R_NOPERM; + goto cleanup; + } + + cfg = (struct cfg_context *) view->new_zone_config; + if (cfg == NULL) { + result = ISC_R_FAILURE; + goto cleanup; + } + + /* Zone shouldn't already exist */ + result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone); + if (result == ISC_R_SUCCESS) { + result = ISC_R_EXISTS; + goto cleanup; + } else if (result == DNS_R_PARTIALMATCH) { + /* Create our sub-zone anyway */ + dns_zone_detach(&zone); + zone = NULL; + } + else if (result != ISC_R_NOTFOUND) + goto cleanup; + + /* Find the view statement */ + cfg_map_get(cfg->config, "view", &views); + for (element = cfg_list_first(views); + element != NULL; + element = cfg_list_next(element)) + { + const char *vname; + vconfig = cfg_listelt_value(element); + vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); + if (vname && !strcasecmp(vname, viewname)) + break; + vconfig = NULL; + } + + /* Open save file for write configuration */ + CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); + + /* Mark view unfrozen so that zone can be added */ + dns_view_thaw(view); + result = configure_zone(cfg->config, parms, vconfig, + server->mctx, view, &cfg->actx, ISC_FALSE); + dns_view_freeze(view); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + /* Is it there yet? */ + CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone)); + + /* + * Load the zone from the master file. If this fails, we'll + * need to undo the configuration we've done already. + */ + result = dns_zone_loadnew(zone); + if (result != ISC_R_SUCCESS) { + dns_db_t *dbp = NULL; + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "addzone failed; reverting."); + + /* If the zone loaded partially, unload it */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + /* Remove the zone from the zone table */ + dns_zt_unmount(view->zonetable, zone); + goto cleanup; + } + + /* Flag the zone as having been added at runtime */ + dns_zone_setadded(zone, ISC_TRUE); + + /* Emit just the zone name from args */ + CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL)); + CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL)); + CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); + + /* Classname, if not default */ + if (classname != NULL && *classname != '\0') { + CHECK(isc_stdio_write(classname, strlen(classname), 1, fp, + NULL)); + CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); + } + + /* Find beginning of option block from args */ + for (argp = args; *argp; argp++, arglen--) { + if (*argp == '{') { /* Assume matching '}' */ + /* Add that to our file */ + CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL)); + + /* Make sure we end with a LF */ + if (argp[arglen-1] != '\n') { + CHECK(isc_stdio_write("\n", 1, 1, fp, NULL)); + } + break; + } + } + + CHECK(isc_stdio_close(fp)); + fp = NULL; + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "zone %s added to view %s via addzone", + zonename, viewname); + + result = ISC_R_SUCCESS; + + cleanup: + if (fp != NULL) + isc_stdio_close(fp); + if (parser != NULL) { + if (config != NULL) + cfg_obj_destroy(parser, &config); + cfg_parser_destroy(&parser); + } + if (zone != NULL) + dns_zone_detach(&zone); + if (view != NULL) + dns_view_detach(&view); + if (nbuf != NULL) + isc_buffer_free(&nbuf); + + return (result); +} + +/* + * Act on a "delzone" command from the command channel. + */ +isc_result_t +ns_server_del_zone(ns_server_t *server, char *args) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_view_t *view = NULL; + dns_db_t *dbp = NULL; + const char *filename = NULL; + char *tmpname = NULL; + char buf[1024]; + const char *zonename = NULL; + size_t znamelen = 0; + FILE *ifp = NULL, *ofp = NULL; + + /* Parse parameters */ + CHECK(zone_from_args(server, args, &zone, &zonename)); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } + + /* + * Was this zone originally added at runtime? + * If not, we can't delete it now. + */ + if (!dns_zone_getadded(zone)) { + result = ISC_R_NOPERM; + goto cleanup; + } + + if (zonename != NULL) + znamelen = strlen(zonename); + + /* Dig out configuration for this zone */ + view = dns_zone_getview(zone); + filename = view->new_zone_file; + if (filename == NULL) { + /* No adding zones in this view */ + result = ISC_R_FAILURE; + goto cleanup; + } + + /* Rewrite zone list */ + result = isc_stdio_open(filename, "r", &ifp); + if (ifp != NULL && result == ISC_R_SUCCESS) { + char *found = NULL, *p = NULL; + size_t n; + + /* Create a temporary file */ + CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename, + (long)getpid())); + if (!(tmpname = isc_mem_strdup(server->mctx, buf))) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + CHECK(isc_stdio_open(tmpname, "w", &ofp)); + + /* Look for the entry for that zone */ + while (fgets(buf, 1024, ifp)) { + /* A 'zone' line */ + if (strncasecmp(buf, "zone", 4)) { + fputs(buf, ofp); + continue; + } + p = buf+4; + + /* Locate a name */ + while (*p && + ((*p == '"') || isspace((unsigned char)*p))) + p++; + + /* Is that the zone we're looking for */ + if (strncasecmp(p, zonename, znamelen)) { + fputs(buf, ofp); + continue; + } + + /* And nothing else? */ + p += znamelen; + if (isspace((unsigned char)*p) || + *p == '"' || *p == '{') { + /* This must be the entry */ + found = p; + break; + } + + /* Spit it out, keep looking */ + fputs(buf, ofp); + } + + /* Skip over an option block (matching # of braces) */ + if (found) { + int obrace = 0, cbrace = 0; + for (;;) { + while (*p) { + if (*p == '{') obrace++; + if (*p == '}') cbrace++; + p++; + } + if (obrace && (obrace == cbrace)) + break; + if (!fgets(buf, 1024, ifp)) + break; + p = buf; + } + + /* Just spool the remainder of the file out */ + result = isc_stdio_read(buf, 1, 1024, ifp, &n); + while (n > 0U) { + if (result == ISC_R_EOF) + result = ISC_R_SUCCESS; + CHECK(result); + isc_stdio_write(buf, 1, n, ofp, NULL); + result = isc_stdio_read(buf, 1, 1024, ifp, &n); + } + + /* Move temporary into place */ + CHECK(isc_file_rename(tmpname, view->new_zone_file)); + } else { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_WARNING, + "deleted zone %s was missing from " + "new zone file", zonename); + goto cleanup; + } + } + + /* Stop answering for this zone */ + if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(zone); + } + + CHECK(dns_zt_unmount(view->zonetable, zone)); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "zone %s removed via delzone", zonename); + + result = ISC_R_SUCCESS; + + cleanup: + if (ifp != NULL) + isc_stdio_close(ifp); + if (ofp != NULL) { + isc_stdio_close(ofp); + isc_file_remove(tmpname); + } + if (tmpname != NULL) + isc_mem_free(server->mctx, tmpname); + if (zone != NULL) + dns_zone_detach(&zone); + + return (result); +} + +static void +cfgctx_destroy(void **cfgp) { + struct cfg_context *cfg; + isc_mem_t *mctx; + + REQUIRE(cfgp != NULL && *cfgp != NULL); + cfg = *cfgp; + mctx = cfg->mctx; + cfg->mctx = NULL; + + if (cfg->parser != NULL) { + if (cfg->config != NULL) + cfg_obj_destroy(cfg->parser, &cfg->config); + cfg_parser_destroy(&cfg->parser); + } + cfg_aclconfctx_clear(&cfg->actx); + + isc_mem_put(mctx, cfg, sizeof(*cfg)); + isc_mem_detach(&mctx); + *cfgp = NULL; +} diff --git a/contrib/bind9/bin/named/statschannel.c b/contrib/bind9/bin/named/statschannel.c index c77d3ca1bfeb..6dce8e0a77c5 100644 --- a/contrib/bind9/bin/named/statschannel.c +++ b/contrib/bind9/bin/named/statschannel.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: statschannel.c,v 1.14.64.11 2010-02-04 23:47:46 tbox Exp $ */ +/* $Id: statschannel.c,v 1.26 2010-02-04 23:49:13 tbox Exp $ */ /*! \file */ @@ -29,6 +29,7 @@ #include <isc/stats.h> #include <isc/task.h> +#include <dns/cache.h> #include <dns/db.h> #include <dns/opcode.h> #include <dns/resolver.h> @@ -823,9 +824,9 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "cache")); TRY0(xmlTextWriterWriteAttribute(writer, - ISC_XMLCHAR "name", - ISC_XMLCHAR - view->name)); + ISC_XMLCHAR "name", + ISC_XMLCHAR + dns_cache_getname(view->cache))); dumparg.result = ISC_R_SUCCESS; dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, 0); @@ -1405,7 +1406,15 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { if (strcmp(view->name, "_default") == 0) fprintf(fp, "[View: default]\n"); else - fprintf(fp, "[View: %s]\n", view->name); + fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, + dns_cache_getname(view->cache)); + if (dns_view_iscacheshared(view)) { + /* + * Avoid dumping redundant statistics when the cache is + * shared. + */ + continue; + } dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, 0); } diff --git a/contrib/bind9/bin/named/tkeyconf.c b/contrib/bind9/bin/named/tkeyconf.c index 734497803191..66c2d7f47cc9 100644 --- a/contrib/bind9/bin/named/tkeyconf.c +++ b/contrib/bind9/bin/named/tkeyconf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tkeyconf.c,v 1.29 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: tkeyconf.c,v 1.33 2010-12-20 23:47:20 tbox Exp $ */ /*! \file */ @@ -77,8 +77,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); - RETERR(dns_name_fromtext(name, &b, dns_rootname, - ISC_FALSE, NULL)); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY; RETERR(dst_key_fromfile(name, (dns_keytag_t) n, DNS_KEYALG_DH, type, NULL, mctx, &tctx->dhkey)); @@ -92,8 +91,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); - RETERR(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, - NULL)); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); tctx->domain = isc_mem_get(mctx, sizeof(dns_name_t)); if (tctx->domain == NULL) { result = ISC_R_NOMEMORY; @@ -112,12 +110,22 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx, isc_buffer_add(&b, strlen(s)); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); - RETERR(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, - NULL)); - RETERR(dst_gssapi_acquirecred(name, ISC_FALSE, - &tctx->gsscred)); + RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); + RETERR(dst_gssapi_acquirecred(name, ISC_FALSE, &tctx->gsscred)); } + obj = NULL; + result = cfg_map_get(options, "tkey-gssapi-keytab", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + tctx->gssapi_keytab = isc_mem_strdup(mctx, s); + if (tctx->gssapi_keytab == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + } + + *tctxp = tctx; return (ISC_R_SUCCESS); diff --git a/contrib/bind9/bin/named/tsigconf.c b/contrib/bind9/bin/named/tsigconf.c index e90a86b5a783..19e8d385e05b 100644 --- a/contrib/bind9/bin/named/tsigconf.c +++ b/contrib/bind9/bin/named/tsigconf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsigconf.c,v 1.30 2007-06-19 23:46:59 tbox Exp $ */ +/* $Id: tsigconf.c,v 1.35 2011-01-11 23:47:12 tbox Exp $ */ /*! \file */ @@ -82,7 +82,7 @@ add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_buffer_add(&keynamesrc, strlen(keyid)); isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, - ISC_TRUE, &keynamebuf); + DNS_NAME_DOWNCASE, &keynamebuf); if (ret != ISC_R_SUCCESS) goto failure; @@ -149,6 +149,8 @@ ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, isc_result_t result; int i; + REQUIRE(ringp != NULL && *ringp == NULL); + i = 0; if (config != NULL) maps[i++] = config; @@ -176,6 +178,6 @@ ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, return (ISC_R_SUCCESS); failure: - dns_tsigkeyring_destroy(&ring); + dns_tsigkeyring_detach(&ring); return (result); } diff --git a/contrib/bind9/bin/named/unix/Makefile.in b/contrib/bind9/bin/named/unix/Makefile.in index 502db2508c98..ca92c49b5c78 100644 --- a/contrib/bind9/bin/named/unix/Makefile.in +++ b/contrib/bind9/bin/named/unix/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1999-2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.10 2007-06-19 23:46:59 tbox Exp $ +# $Id: Makefile.in,v 1.13 2009-12-05 23:31:40 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/contrib/bind9/bin/named/unix/include/named/os.h b/contrib/bind9/bin/named/unix/include/named/os.h index 0a846080a66f..c2768f426647 100644 --- a/contrib/bind9/bin/named/unix/include/named/os.h +++ b/contrib/bind9/bin/named/unix/include/named/os.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: os.h,v 1.29 2008-10-24 01:44:48 tbox Exp $ */ +/* $Id: os.h,v 1.31 2009-08-05 23:47:43 tbox Exp $ */ #ifndef NS_OS_H #define NS_OS_H 1 @@ -51,8 +51,12 @@ ns_os_adjustnofile(void); void ns_os_minprivs(void); +FILE * +ns_os_openfile(const char *filename, mode_t mode, isc_boolean_t switch_user); + void ns_os_writepidfile(const char *filename, isc_boolean_t first_time); + void ns_os_shutdown(void); diff --git a/contrib/bind9/bin/named/unix/os.c b/contrib/bind9/bin/named/unix/os.c index 3f07784fcb82..53e9e4501249 100644 --- a/contrib/bind9/bin/named/unix/os.c +++ b/contrib/bind9/bin/named/unix/os.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: os.c,v 1.89.12.5 2009-03-02 03:03:54 marka Exp $ */ +/* $Id: os.c,v 1.104 2010-11-17 23:47:08 tbox Exp $ */ /*! \file */ @@ -291,6 +291,12 @@ linux_initialprivs(void) { */ SET_CAP(CAP_SYS_RESOURCE); + /* + * We need to be able to set the ownership of the containing + * directory of the pid file when we create it. + */ + SET_CAP(CAP_CHOWN); + linux_setcaps(caps); #ifdef HAVE_LIBCAP @@ -631,7 +637,7 @@ ns_os_minprivs(void) { } static int -safe_open(const char *filename, isc_boolean_t append) { +safe_open(const char *filename, mode_t mode, isc_boolean_t append) { int fd; struct stat sb; @@ -644,13 +650,11 @@ safe_open(const char *filename, isc_boolean_t append) { } if (append) - fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, mode); else { if (unlink(filename) < 0 && errno != ENOENT) return (-1); - fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, mode); } return (fd); } @@ -686,6 +690,15 @@ mkdirpath(char *filename, void (*report)(const char *, ...)) { } if (mkdirpath(filename, report) == -1) goto error; + /* + * Handle "//", "/./" and "/../" in path. + */ + if (!strcmp(slash + 1, "") || + !strcmp(slash + 1, ".") || + !strcmp(slash + 1, "..")) { + *slash = '/'; + return (0); + } mode = S_IRUSR | S_IWUSR | S_IXUSR; /* u=rwx */ mode |= S_IRGRP | S_IXGRP; /* g=rx */ mode |= S_IROTH | S_IXOTH; /* o=rx */ @@ -695,6 +708,13 @@ mkdirpath(char *filename, void (*report)(const char *, ...)) { strbuf); goto error; } + if (runas_pw != NULL && + chown(filename, runas_pw->pw_uid, + runas_pw->pw_gid) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + (*report)("couldn't chown '%s': %s", filename, + strbuf); + } } *slash = '/'; } @@ -705,11 +725,127 @@ mkdirpath(char *filename, void (*report)(const char *, ...)) { return (-1); } +static void +setperms(uid_t uid, gid_t gid) { + char strbuf[ISC_STRERRORSIZE]; +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) + gid_t oldgid, tmpg; +#endif +#if !defined(HAVE_SETEUID) && defined(HAVE_SETRESUID) + uid_t olduid, tmpu; +#endif +#if defined(HAVE_SETEGID) + if (getegid() != gid && setegid(gid) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("unable to set effective gid to %ld: %s", + (long)gid, strbuf); + } +#elif defined(HAVE_SETRESGID) + if (getresgid(&tmpg, &oldgid, &tmpg) == -1 || oldgid != gid) { + if (setresgid(-1, gid, -1) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("unable to set effective " + "gid to %d: %s", gid, strbuf); + } + } +#endif + +#if defined(HAVE_SETEUID) + if (geteuid() != uid && seteuid(uid) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("unable to set effective uid to %ld: %s", + (long)uid, strbuf); + } +#elif defined(HAVE_SETRESUID) + if (getresuid(&tmpu, &olduid, &tmpu) == -1 || olduid != uid) { + if (setresuid(-1, uid, -1) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("unable to set effective " + "uid to %d: %s", uid, strbuf); + } + } +#endif +} + +FILE * +ns_os_openfile(const char *filename, mode_t mode, isc_boolean_t switch_user) { + char strbuf[ISC_STRERRORSIZE], *f; + FILE *fp; + int fd; + + /* + * Make the containing directory if it doesn't exist. + */ + f = strdup(filename); + if (f == NULL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("couldn't strdup() '%s': %s", + filename, strbuf); + return (NULL); + } + if (mkdirpath(f, ns_main_earlywarning) == -1) { + free(f); + return (NULL); + } + free(f); + + if (switch_user && runas_pw != NULL) { + /* Set UID/GID to the one we'll be running with eventually */ + setperms(runas_pw->pw_uid, runas_pw->pw_gid); + + fd = safe_open(filename, mode, ISC_FALSE); + +#ifndef HAVE_LINUXTHREADS + /* Restore UID/GID to root */ + setperms(0, 0); +#endif /* HAVE_LINUXTHREADS */ + + if (fd == -1) { +#ifndef HAVE_LINUXTHREADS + fd = safe_open(filename, mode, ISC_FALSE); + if (fd != -1) { + ns_main_earlywarning("Required root " + "permissions to open " + "'%s'.", filename); + } else { + ns_main_earlywarning("Could not open " + "'%s'.", filename); + } + ns_main_earlywarning("Please check file and " + "directory permissions " + "or reconfigure the filename."); +#else /* HAVE_LINUXTHREADS */ + ns_main_earlywarning("Could not open " + "'%s'.", filename); + ns_main_earlywarning("Please check file and " + "directory permissions " + "or reconfigure the filename."); +#endif /* HAVE_LINUXTHREADS */ + } + } else { + fd = safe_open(filename, mode, ISC_FALSE); + } + + if (fd < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("could not open file '%s': %s", + filename, strbuf); + return (NULL); + } + + fp = fdopen(fd, "w"); + if (fp == NULL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + ns_main_earlywarning("could not fdopen() file '%s': %s", + filename, strbuf); + } + + return (fp); +} + void ns_os_writepidfile(const char *filename, isc_boolean_t first_time) { - int fd; FILE *lockfile; - size_t len; pid_t pid; char strbuf[ISC_STRERRORSIZE]; void (*report)(const char *, ...); @@ -725,40 +861,16 @@ ns_os_writepidfile(const char *filename, isc_boolean_t first_time) { if (filename == NULL) return; - len = strlen(filename); - pidfile = malloc(len + 1); + pidfile = strdup(filename); if (pidfile == NULL) { isc__strerror(errno, strbuf, sizeof(strbuf)); - (*report)("couldn't malloc '%s': %s", filename, strbuf); + (*report)("couldn't strdup() '%s': %s", filename, strbuf); return; } - /* This is safe. */ - strcpy(pidfile, filename); - - /* - * Make the containing directory if it doesn't exist. - */ - if (mkdirpath(pidfile, report) == -1) { - free(pidfile); - pidfile = NULL; - return; - } - - fd = safe_open(filename, ISC_FALSE); - if (fd < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - (*report)("couldn't open pid file '%s': %s", filename, strbuf); - free(pidfile); - pidfile = NULL; - return; - } - lockfile = fdopen(fd, "w"); + lockfile = ns_os_openfile(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, + first_time); if (lockfile == NULL) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - (*report)("could not fdopen() pid file '%s': %s", - filename, strbuf); - (void)close(fd); cleanup_pidfile(); return; } diff --git a/contrib/bind9/bin/named/update.c b/contrib/bind9/bin/named/update.c index 1504a44b5ad0..eb1ed1d64ef9 100644 --- a/contrib/bind9/bin/named/update.c +++ b/contrib/bind9/bin/named/update.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.151.12.11 2010-02-26 23:48:43 tbox Exp $ */ +/* $Id: update.c,v 1.186.16.1.2.1 2011-06-02 23:47:28 tbox Exp $ */ #include <config.h> @@ -38,6 +38,7 @@ #include <dns/message.h> #include <dns/nsec.h> #include <dns/nsec3.h> +#include <dns/private.h> #include <dns/rdataclass.h> #include <dns/rdataset.h> #include <dns/rdatasetiter.h> @@ -45,6 +46,7 @@ #include <dns/rdatatype.h> #include <dns/soa.h> #include <dns/ssu.h> +#include <dns/tsig.h> #include <dns/view.h> #include <dns/zone.h> #include <dns/zt.h> @@ -281,6 +283,47 @@ inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { } /*% + * Check if we could have queried for the contents of this zone or + * if the zone is potentially updateable. + * If the zone can potentially be updated and the check failed then + * log a error otherwise we log a informational message. + */ +static isc_result_t +checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename, + dns_acl_t *updateacl, dns_ssutable_t *ssutable) +{ + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; + int level; + isc_result_t result; + + result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); + if (result != ISC_R_SUCCESS) { + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); + + level = (updateacl == NULL && ssutable == NULL) ? + ISC_LOG_INFO : ISC_LOG_ERROR; + + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, level, + "update '%s/%s' denied due to allow-query", + namebuf, classbuf); + } else if (updateacl == NULL && ssutable == NULL) { + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); + + result = DNS_R_REFUSED; + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, ISC_LOG_INFO, + "update '%s/%s' denied", namebuf, classbuf); + } + return (result); +} + +/*% * Override the default acl logging when checking whether a client * can update the zone or whether we can forward the request to the * master based on IP address. @@ -809,6 +852,9 @@ typedef struct { /* The ssu table to check against. */ dns_ssutable_t *table; + + /* the key used for TKEY requests */ + dst_key_t *key; } ssu_check_t; static isc_result_t @@ -825,14 +871,14 @@ ssu_checkrule(void *data, dns_rdataset_t *rrset) { return (ISC_R_SUCCESS); result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, ssuinfo->name, ssuinfo->tcpaddr, - rrset->type); + rrset->type, ssuinfo->key); return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE); } static isc_boolean_t ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_ssutable_t *ssutable, dns_name_t *signer, - isc_netaddr_t *tcpaddr) + isc_netaddr_t *tcpaddr, dst_key_t *key) { isc_result_t result; ssu_check_t ssuinfo; @@ -841,6 +887,7 @@ ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, ssuinfo.table = ssutable; ssuinfo.signer = signer; ssuinfo.tcpaddr = tcpaddr; + ssuinfo.key = key; result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); return (ISC_TF(result == ISC_R_SUCCESS)); } @@ -889,7 +936,7 @@ temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { b->op == DNS_DIFFOP_EXISTS); INSIST(a->rdata.type == b->rdata.type); INSIST(dns_name_equal(&a->name, &b->name)); - if (dns_rdata_compare(&a->rdata, &b->rdata) != 0) + if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0) return (DNS_R_NXRRSET); a = ISC_LIST_NEXT(a, link); b = ISC_LIST_NEXT(b, link); @@ -917,7 +964,7 @@ temp_order(const void *av, const void *bv) { r = (b->rdata.type - a->rdata.type); if (r != 0) return (r); - r = dns_rdata_compare(&a->rdata, &b->rdata); + r = dns_rdata_casecompare(&a->rdata, &b->rdata); return (r); } @@ -1146,7 +1193,7 @@ rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { * dns_rdata_equal() (that used dns_name_equal()), since it * would be faster. Not a priority. */ - return (dns_rdata_compare(update_rr, db_rr) == 0 ? + return (dns_rdata_casecompare(update_rr, db_rr) == 0 ? ISC_TRUE : ISC_FALSE); } @@ -1208,11 +1255,10 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { return (ISC_FALSE); INSIST(db_rr->length >= 4 && update_rr->length >= 4); /* - * Replace records added in this UPDATE request. + * Replace NSEC3PARAM records that only differ by the + * flags field. */ if (db_rr->data[0] == update_rr->data[0] && - db_rr->data[1] & DNS_NSEC3FLAG_UPDATE && - update_rr->data[1] & DNS_NSEC3FLAG_UPDATE && memcmp(db_rr->data+2, update_rr->data+2, update_rr->length - 2) == 0) return (ISC_TRUE); @@ -1293,7 +1339,7 @@ add_rr_prepare_action(void *data, rr_t *rr) { * If the update RR is a "duplicate" of the update RR, * the update should be silently ignored. */ - equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0); + equal = ISC_TF(dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0); if (equal && rr->ttl == ctx->update_rr_ttl) { ctx->ignore_add = ISC_TRUE; return (ISC_R_SUCCESS); @@ -1717,35 +1763,6 @@ next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, return (result); } -static isc_boolean_t -has_opt_bit(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) { - isc_result_t result; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t rdataset; - isc_boolean_t has_bit = ISC_FALSE; - - dns_rdataset_init(&rdataset); - CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec, - dns_rdatatype_none, 0, &rdataset, NULL)); - CHECK(dns_rdataset_first(&rdataset)); - dns_rdataset_current(&rdataset, &rdata); - has_bit = dns_nsec_typepresent(&rdata, dns_rdatatype_opt); - failure: - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); - return (has_bit); -} - -static void -set_bit(unsigned char *array, unsigned int index) { - unsigned int shift, bit; - - shift = 7 - (index % 8); - bit = 1 << shift; - - array[index / 8] |= bit; -} - /*% * Add a NSEC record for "name", recording the change in "diff". * The existing NSEC is removed. @@ -1777,24 +1794,6 @@ add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); dns_rdata_init(&rdata); CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); - /* - * Preserve the status of the OPT bit in the origin's NSEC record. - */ - if (dns_name_equal(dns_db_origin(db), name) && - has_opt_bit(db, ver, node)) - { - isc_region_t region; - dns_name_t next; - - dns_name_init(&next, NULL); - dns_rdata_toregion(&rdata, ®ion); - dns_name_fromregion(&next, ®ion); - isc_region_consume(®ion, next.length); - INSIST(region.length > (2 + dns_rdatatype_opt / 8) && - region.base[0] == 0 && - region.base[1] > dns_rdatatype_opt / 8); - set_bit(region.base + 2, dns_rdatatype_opt); - } dns_db_detachnode(db, &node); /* @@ -1856,44 +1855,6 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, return (result); } -static isc_boolean_t -ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) { - isc_boolean_t ret = ISC_FALSE; - isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE; - isc_result_t result; - dns_dbnode_t *node = NULL; - dns_rdataset_t rdataset; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_dnskey_t dnskey; - - dns_rdataset_init(&rdataset); - CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); - CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, - &rdataset, NULL)); - CHECK(dns_rdataset_first(&rdataset)); - while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) { - dns_rdataset_current(&rdataset, &rdata); - CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); - if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) - == DNS_KEYOWNER_ZONE) { - if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) - have_ksk = ISC_TRUE; - else - have_nonksk = ISC_TRUE; - } - dns_rdata_reset(&rdata); - result = dns_rdataset_next(&rdataset); - } - if (have_ksk && have_nonksk) - ret = ISC_TRUE; - failure: - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); - if (node != NULL) - dns_db_detachnode(db, &node); - return (ret); -} - /*% * Add RRSIG records for an RRset, recording the change in "diff". */ @@ -1902,7 +1863,7 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, isc_stdtime_t inception, isc_stdtime_t expire, - isc_boolean_t check_ksk) + isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly) { isc_result_t result; dns_dbnode_t *node = NULL; @@ -1910,7 +1871,7 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_rdata_t sig_rdata = DNS_RDATA_INIT; isc_buffer_t buffer; unsigned char data[1024]; /* XXX */ - unsigned int i; + unsigned int i, j; isc_boolean_t added_sig = ISC_FALSE; isc_mem_t *mctx = client->mctx; @@ -1926,13 +1887,52 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, (isc_stdtime_t) 0, &rdataset, NULL)); dns_db_detachnode(db, &node); +#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0) +#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0) +#define ALG(x) dst_key_alg(x) + + /* + * If we are honoring KSK flags then we need to check that we + * have both KSK and non-KSK keys that are not revoked per + * algorithm. + */ for (i = 0; i < nkeys; i++) { + isc_boolean_t both = ISC_FALSE; - if (check_ksk && type != dns_rdatatype_dnskey && - (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0) + if (!dst_key_isprivate(keys[i])) continue; - if (!dst_key_isprivate(keys[i])) + if (check_ksk && !REVOKE(keys[i])) { + isc_boolean_t have_ksk, have_nonksk; + if (KSK(keys[i])) { + have_ksk = ISC_TRUE; + have_nonksk = ISC_FALSE; + } else { + have_ksk = ISC_FALSE; + have_nonksk = ISC_TRUE; + } + for (j = 0; j < nkeys; j++) { + if (j == i || ALG(keys[i]) != ALG(keys[j])) + continue; + if (REVOKE(keys[j])) + continue; + if (KSK(keys[j])) + have_ksk = ISC_TRUE; + else + have_nonksk = ISC_TRUE; + both = have_ksk && have_nonksk; + if (both) + break; + } + } + + if (both) { + if (type == dns_rdatatype_dnskey) { + if (!KSK(keys[i]) && keyset_kskonly) + continue; + } else if (KSK(keys[i])) + continue; + } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) continue; /* Calculate the signature, creating a RRSIG RDATA. */ @@ -1950,7 +1950,7 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, } if (!added_sig) { update_log(client, zone, ISC_LOG_ERROR, - "found no private keys, " + "found no active private keys, " "unable to generate any signatures"); result = ISC_R_NOTFOUND; } @@ -2044,7 +2044,7 @@ add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, isc_stdtime_t inception, isc_stdtime_t expire, - isc_boolean_t check_ksk) + isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly) { isc_result_t result; dns_dbnode_t *node; @@ -2090,7 +2090,8 @@ add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, if (flag) continue;; result = add_sigs(client, zone, db, ver, name, type, diff, - keys, nkeys, inception, expire, check_ksk); + keys, nkeys, inception, expire, + check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) goto cleanup_iterator; } @@ -2120,8 +2121,7 @@ add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, static isc_result_t update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *oldver, dns_dbversion_t *newver, - dns_diff_t *diff, isc_uint32_t sigvalidityinterval, - isc_boolean_t *deleted_zsk) + dns_diff_t *diff, isc_uint32_t sigvalidityinterval) { isc_result_t result; dns_difftuple_t *t; @@ -2130,7 +2130,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_diff_t sig_diff; dns_diff_t nsec_diff; dns_diff_t nsec_mindiff; - isc_boolean_t flag; + isc_boolean_t flag, build_nsec, build_nsec3; dst_key_t *zone_keys[MAXZONEKEYS]; unsigned int nkeys = 0; unsigned int i; @@ -2140,9 +2140,10 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t rdataset; dns_dbnode_t *node = NULL; - isc_boolean_t check_ksk; + isc_boolean_t check_ksk, keyset_kskonly; isc_boolean_t unsecure; isc_boolean_t cut; + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); dns_diff_init(client->mctx, &diffnames); dns_diff_init(client->mctx, &affected); @@ -2172,27 +2173,8 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, */ check_ksk = ISC_TF((dns_zone_getoptions(zone) & DNS_ZONEOPT_UPDATECHECKKSK) != 0); - /* - * If we are not checking the ZSK flag then all DNSKEY's are - * already signing all RRsets so we don't need to trigger special - * changes. - */ - if (*deleted_zsk && (!check_ksk || !ksk_sanity(db, oldver))) - *deleted_zsk = ISC_FALSE; - - if (check_ksk) { - check_ksk = ksk_sanity(db, newver); - if (!check_ksk && ksk_sanity(db, oldver)) - update_log(client, zone, ISC_LOG_WARNING, - "disabling update-check-ksk"); - } - - /* - * If we have deleted a ZSK and we we still have some ZSK's - * we don't need to convert the KSK's to a ZSK's. - */ - if (*deleted_zsk && check_ksk) - *deleted_zsk = ISC_FALSE; + keyset_kskonly = ISC_TF((dns_zone_getoptions(zone) & + DNS_ZONEOPT_DNSKEYKSKONLY) != 0); /* * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field. @@ -2259,7 +2241,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, CHECK(add_sigs(client, zone, db, newver, name, type, &sig_diff, zone_keys, nkeys, inception, expire, - check_ksk)); + check_ksk, keyset_kskonly)); } skip: /* Skip any other updates to the same RRset. */ @@ -2289,12 +2271,11 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, "removed any orphaned NSEC records"); /* - * If we don't have a NSEC record at the origin then we need to - * update the NSEC3 records. + * See if we need to build NSEC or NSEC3 chains. */ - CHECK(rrset_exists(db, newver, dns_db_origin(db), dns_rdatatype_nsec, - 0, &flag)); - if (!flag) + CHECK(dns_private_chains(db, newver, privatetype, &build_nsec, + &build_nsec3)); + if (!build_nsec) goto update_nsec3; update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain"); @@ -2398,16 +2379,25 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_rdatatype_any, 0, NULL, diff)); } else { /* - * This name is not obscured. It should have a NSEC. + * This name is not obscured. It needs to have a + * NSEC unless it is the at the origin, in which + * case it should already exist if there is a complete + * NSEC chain and if there isn't a complete NSEC chain + * we don't want to add one as that would signal that + * there is a complete NSEC chain. */ - CHECK(rrset_exists(db, newver, name, - dns_rdatatype_nsec, 0, &flag)); - if (! flag) - CHECK(add_placeholder_nsec(db, newver, name, - diff)); + if (!dns_name_equal(name, dns_db_origin(db))) { + CHECK(rrset_exists(db, newver, name, + dns_rdatatype_nsec, 0, + &flag)); + if (!flag) + CHECK(add_placeholder_nsec(db, newver, + name, diff)); + } CHECK(add_exposed_sigs(client, zone, db, newver, name, cut, diff, zone_keys, nkeys, - inception, expire, check_ksk)); + inception, expire, check_ksk, + keyset_kskonly)); } } @@ -2469,7 +2459,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, CHECK(add_sigs(client, zone, db, newver, &t->name, dns_rdatatype_nsec, &sig_diff, zone_keys, nkeys, inception, expire, - check_ksk)); + check_ksk, keyset_kskonly)); } else { INSIST(0); } @@ -2491,13 +2481,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, INSIST(ISC_LIST_EMPTY(nsec_diff.tuples)); INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples)); - /* - * Check if we have any active NSEC3 chains by looking for a - * NSEC3PARAM RRset. - */ - CHECK(rrset_exists(db, newver, dns_db_origin(db), - dns_rdatatype_nsec3param, 0, &flag)); - if (!flag) { + if (!build_nsec3) { update_log(client, zone, ISC_LOG_DEBUG(3), "no NSEC3 chains to rebuild"); goto failure; @@ -2521,6 +2505,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, isc_boolean_t ns_existed, dname_existed; isc_boolean_t ns_exists, dname_exists; + isc_boolean_t exists, existed; if (t->rdata.type == dns_rdatatype_nsec || t->rdata.type == dns_rdatatype_rrsig) { @@ -2539,7 +2524,9 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0, &dname_exists)); - if ((ns_exists || dname_exists) == (ns_existed || dname_existed)) + exists = ns_exists || dname_exists; + existed = ns_existed || dname_existed; + if (exists == existed) goto nextname; /* * There was a delegation change. Mark all subdomains @@ -2563,14 +2550,16 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, if (!flag) { CHECK(delete_if(rrsig_p, db, newver, name, dns_rdatatype_any, 0, NULL, diff)); - CHECK(dns_nsec3_delnsec3s(db, newver, name, - &nsec_diff)); + CHECK(dns_nsec3_delnsec3sx(db, newver, name, + privatetype, &nsec_diff)); } else { CHECK(add_exposed_sigs(client, zone, db, newver, name, cut, diff, zone_keys, nkeys, - inception, expire, check_ksk)); - CHECK(dns_nsec3_addnsec3s(db, newver, name, nsecttl, - unsecure, &nsec_diff)); + inception, expire, check_ksk, + keyset_kskonly)); + CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl, + unsecure, privatetype, + &nsec_diff)); } } @@ -2601,7 +2590,8 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, CHECK(add_sigs(client, zone, db, newver, &t->name, dns_rdatatype_nsec3, &sig_diff, zone_keys, nkeys, - inception, expire, check_ksk)); + inception, expire, check_ksk, + keyset_kskonly)); } else { INSIST(0); } @@ -2734,6 +2724,7 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { switch(dns_zone_gettype(zone)) { case dns_zone_master: + case dns_zone_dlz: /* * We can now fail due to a bad signature as we now know * that we are the master. @@ -2943,7 +2934,7 @@ rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, result = dns_rdataset_next(&rdataset)) { dns_rdata_t myrdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &myrdata); - if (!dns_rdata_compare(&myrdata, rdata)) + if (!dns_rdata_casecompare(&myrdata, rdata)) break; } dns_rdataset_disassociate(&rdataset); @@ -2961,7 +2952,9 @@ rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, } static isc_result_t -get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) { +get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype, + unsigned int *iterationsp) +{ dns_dbnode_t *node = NULL; dns_rdata_nsec3param_t nsec3param; dns_rdataset_t rdataset; @@ -2975,7 +2968,33 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) { return (result); result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0, (isc_stdtime_t) 0, &rdataset, NULL); - dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + goto try_private; + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) + continue; + if (nsec3param.iterations > iterations) + iterations = nsec3param.iterations; + } + if (result != ISC_R_NOMORE) + goto failure; + + dns_rdataset_disassociate(&rdataset); + + try_private: + if (privatetype == 0) + goto success; + + result = dns_db_findrdataset(db, node, ver, privatetype, + 0, (isc_stdtime_t) 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) goto success; if (result != ISC_R_SUCCESS) @@ -2984,8 +3003,14 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) { for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t private = DNS_RDATA_INIT; dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) + continue; CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) continue; @@ -3000,6 +3025,8 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) { result = ISC_R_SUCCESS; failure: + if (node != NULL) + dns_db_detachnode(db, &node); if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); return (result); @@ -3013,77 +3040,83 @@ static isc_result_t check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff) { - dns_diff_t temp_diff; - dns_diffop_t op; - dns_difftuple_t *tuple, *newtuple = NULL, *next; - isc_boolean_t flag; + dns_difftuple_t *tuple; + isc_boolean_t nseconly = ISC_FALSE, nsec3 = ISC_FALSE; isc_result_t result; unsigned int iterations = 0, max; + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); - dns_diff_init(diff->mctx, &temp_diff); - - CHECK(dns_nsec_nseconly(db, ver, &flag)); + /* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */ + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + if (tuple->op != DNS_DIFFOP_ADD) + continue; - if (flag) - CHECK(dns_nsec3_active(db, ver, ISC_FALSE, &flag)); - if (flag) { - update_log(client, zone, ISC_LOG_WARNING, - "NSEC only DNSKEYs and NSEC3 chains not allowed"); - } else { - CHECK(get_iterations(db, ver, &iterations)); - CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max)); - if (max != 0 && iterations > max) { - flag = ISC_TRUE; - update_log(client, zone, ISC_LOG_WARNING, - "too many NSEC3 iterations (%u) for " - "weakest DNSKEY (%u)", iterations, max); + if (tuple->rdata.type == dns_rdatatype_dnskey) { + isc_uint8_t alg; + alg = tuple->rdata.data[3]; + if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || + alg == DST_ALG_DSA || alg == DST_ALG_ECC) { + nseconly = ISC_TRUE; + break; + } + } else if (tuple->rdata.type == dns_rdatatype_nsec3param) { + nsec3 = ISC_TRUE; + break; } } - if (flag) { - for (tuple = ISC_LIST_HEAD(diff->tuples); - tuple != NULL; - tuple = next) { - next = ISC_LIST_NEXT(tuple, link); - if (tuple->rdata.type != dns_rdatatype_dnskey && - tuple->rdata.type != dns_rdatatype_nsec3param) - continue; - op = (tuple->op == DNS_DIFFOP_DEL) ? - DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; - CHECK(dns_difftuple_create(temp_diff.mctx, op, - &tuple->name, tuple->ttl, - &tuple->rdata, &newtuple)); - CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff)); - INSIST(newtuple == NULL); - } - for (tuple = ISC_LIST_HEAD(temp_diff.tuples); - tuple != NULL; - tuple = ISC_LIST_HEAD(temp_diff.tuples)) { - ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); - dns_diff_appendminimal(diff, &tuple); - } + + /* Check existing DB for NSEC-only DNSKEY */ + if (!nseconly) + CHECK(dns_nsec_nseconly(db, ver, &nseconly)); + + /* Check existing DB for NSEC3 */ + if (!nsec3) + CHECK(dns_nsec3_activex(db, ver, ISC_FALSE, + privatetype, &nsec3)); + + /* Refuse to allow NSEC3 with NSEC-only keys */ + if (nseconly && nsec3) { + update_log(client, zone, ISC_LOG_ERROR, + "NSEC only DNSKEYs and NSEC3 chains not allowed"); + result = DNS_R_REFUSED; + goto failure; } + /* Verify NSEC3 params */ + CHECK(get_iterations(db, ver, privatetype, &iterations)); + CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max)); + if (max != 0 && iterations > max) { + update_log(client, zone, ISC_LOG_ERROR, + "too many NSEC3 iterations (%u) for " + "weakest DNSKEY (%u)", iterations, max); + result = DNS_R_REFUSED; + goto failure; + } failure: - dns_diff_clear(&temp_diff); return (result); } -#ifdef ALLOW_NSEC3PARAM_UPDATE /* * Delay NSEC3PARAM changes as they need to be applied to the whole zone. */ static isc_result_t add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, - dns_name_t *name, dns_dbversion_t *ver, dns_diff_t *diff) + dns_dbversion_t *ver, dns_diff_t *diff) { isc_result_t result = ISC_R_SUCCESS; dns_difftuple_t *tuple, *newtuple = NULL, *next; dns_rdata_t rdata = DNS_RDATA_INIT; - unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; dns_diff_t temp_diff; dns_diffop_t op; isc_boolean_t flag; + dns_name_t *name = dns_zone_getorigin(zone); + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); + isc_uint32_t ttl = 0; + isc_boolean_t ttl_good = ISC_FALSE; update_log(client, zone, ISC_LOG_DEBUG(3), "checking for NSEC3PARAM changes"); @@ -3106,55 +3139,143 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, ISC_LIST_APPEND(temp_diff.tuples, tuple, link); } + /* + * Extract TTL changes pairs, we don't need to convert these to + * delayed changes. + */ for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; tuple = next) { - if (tuple->op == DNS_DIFFOP_ADD) { + if (!ttl_good) { + /* + * Any adds here will contain the final + * NSEC3PARAM RRset TTL. + */ + ttl = tuple->ttl; + ttl_good = ISC_TRUE; + } + /* + * Walk the temp_diff list looking for the + * corresponding delete. + */ + next = ISC_LIST_HEAD(temp_diff.tuples); + while (next != NULL) { + unsigned char *next_data = next->rdata.data; + unsigned char *tuple_data = tuple->rdata.data; + if (next->op == DNS_DIFFOP_DEL && + next->rdata.length == tuple->rdata.length && + !memcmp(next_data, tuple_data, + next->rdata.length)) { + ISC_LIST_UNLINK(temp_diff.tuples, next, + link); + ISC_LIST_APPEND(diff->tuples, next, + link); + break; + } + next = ISC_LIST_NEXT(next, link); + } + /* + * If we have not found a pair move onto the next + * tuple. + */ + if (next == NULL) { + next = ISC_LIST_NEXT(tuple, link); + continue; + } + /* + * Find the next tuple to be processed before + * unlinking then complete moving the pair to 'diff'. + */ + next = ISC_LIST_NEXT(tuple, link); + ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); + ISC_LIST_APPEND(diff->tuples, tuple, link); + } else next = ISC_LIST_NEXT(tuple, link); + } + + /* + * Preserve any ongoing changes from a BIND 9.6.x upgrade. + * + * Any NSEC3PARAM records with flags other than OPTOUT named + * in managing and should not be touched so revert such changes + * taking into account any TTL change of the NSEC3PARAM RRset. + */ + for (tuple = ISC_LIST_HEAD(temp_diff.tuples); + tuple != NULL; tuple = next) { + next = ISC_LIST_NEXT(tuple, link); + if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) { + /* + * If we havn't had any adds then the tuple->ttl must + * be the original ttl and should be used for any + * future changes. + */ + if (!ttl_good) { + ttl = tuple->ttl; + ttl_good = ISC_TRUE; + } + op = (tuple->op == DNS_DIFFOP_DEL) ? + DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; + CHECK(dns_difftuple_create(diff->mctx, op, name, + ttl, &tuple->rdata, + &newtuple)); + CHECK(do_one_tuple(&newtuple, db, ver, diff)); + ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); + dns_diff_appendminimal(diff, &tuple); + } + } + + /* + * We now have just the actual changes to the NSEC3PARAM RRset. + * Convert the adds to delayed adds and the deletions into delayed + * deletions. + */ + for (tuple = ISC_LIST_HEAD(temp_diff.tuples); + tuple != NULL; tuple = next) { + /* + * If we havn't had any adds then the tuple->ttl must be the + * original ttl and should be used for any future changes. + */ + if (!ttl_good) { + ttl = tuple->ttl; + ttl_good = ISC_TRUE; + } + if (tuple->op == DNS_DIFFOP_ADD) { + /* + * Look for any deletes which match this ADD ignoring + * OPTOUT. We don't need to explictly remove them as + * they will be removed a side effect of processing + * the add. + */ + next = ISC_LIST_HEAD(temp_diff.tuples); while (next != NULL) { unsigned char *next_data = next->rdata.data; unsigned char *tuple_data = tuple->rdata.data; - if (next_data[0] != tuple_data[0] || - /* Ignore flags. */ + if (next->op != DNS_DIFFOP_DEL || + next->rdata.length != tuple->rdata.length || + next_data[0] != tuple_data[0] || next_data[2] != tuple_data[2] || next_data[3] != tuple_data[3] || - next_data[4] != tuple_data[4] || - !memcmp(&next_data[5], &tuple_data[5], - tuple_data[4])) { + memcmp(next_data + 4, tuple_data + 4, + tuple->rdata.length - 4)) { next = ISC_LIST_NEXT(next, link); continue; } - op = (next->op == DNS_DIFFOP_DEL) ? - DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; - CHECK(dns_difftuple_create(diff->mctx, op, - name, next->ttl, - &next->rdata, - &newtuple)); - CHECK(do_one_tuple(&newtuple, db, ver, diff)); ISC_LIST_UNLINK(temp_diff.tuples, next, link); - dns_diff_appendminimal(diff, &next); - next = ISC_LIST_NEXT(tuple, link); + ISC_LIST_APPEND(diff->tuples, next, link); + next = ISC_LIST_HEAD(temp_diff.tuples); } - - INSIST(tuple->rdata.data[1] & DNS_NSEC3FLAG_UPDATE); - /* * See if we already have a CREATE request in progress. */ - dns_rdata_clone(&tuple->rdata, &rdata); - INSIST(rdata.length <= sizeof(buf)); - memcpy(buf, rdata.data, rdata.length); - buf[1] |= DNS_NSEC3FLAG_CREATE; - buf[1] &= ~DNS_NSEC3FLAG_UPDATE; - rdata.data = buf; - + dns_nsec3param_toprivate(&tuple->rdata, &rdata, + privatetype, buf, sizeof(buf)); + buf[2] |= DNS_NSEC3FLAG_CREATE; CHECK(rr_exists(db, ver, name, &rdata, &flag)); if (!flag) { CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, - name, tuple->ttl, - &rdata, + name, 0, &rdata, &newtuple)); CHECK(do_one_tuple(&newtuple, db, ver, diff)); } @@ -3164,26 +3285,26 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, * otherwise indentical chain with a reversed * OPTOUT state. */ - buf[1] ^= DNS_NSEC3FLAG_OPTOUT; + buf[2] ^= DNS_NSEC3FLAG_OPTOUT; CHECK(rr_exists(db, ver, name, &rdata, &flag)); if (flag) { CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, - name, tuple->ttl, - &rdata, + name, 0, &rdata, &newtuple)); CHECK(do_one_tuple(&newtuple, db, ver, diff)); } /* - * Remove the temporary add record. + * Find the next tuple to be processed and remove the + * temporary add record. */ + next = ISC_LIST_NEXT(tuple, link); CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, - name, tuple->ttl, - &tuple->rdata, &newtuple)); + name, ttl, &tuple->rdata, + &newtuple)); CHECK(do_one_tuple(&newtuple, db, ver, diff)); - next = ISC_LIST_NEXT(tuple, link); ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); dns_diff_appendminimal(diff, &tuple); dns_rdata_reset(&rdata); @@ -3191,50 +3312,33 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, next = ISC_LIST_NEXT(tuple, link); } - /* - * Reverse any pending changes. - */ for (tuple = ISC_LIST_HEAD(temp_diff.tuples); tuple != NULL; tuple = next) { - next = ISC_LIST_NEXT(tuple, link); - if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) { - op = (tuple->op == DNS_DIFFOP_DEL) ? - DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; - CHECK(dns_difftuple_create(diff->mctx, op, name, - tuple->ttl, &tuple->rdata, - &newtuple)); - CHECK(do_one_tuple(&newtuple, db, ver, diff)); - ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); - dns_diff_appendminimal(diff, &tuple); - } - } - /* - * Convert deletions into delayed deletions. - */ - for (tuple = ISC_LIST_HEAD(temp_diff.tuples); - tuple != NULL; tuple = next) { + INSIST(ttl_good); + next = ISC_LIST_NEXT(tuple, link); /* * See if we already have a REMOVE request in progress. */ - dns_rdata_clone(&tuple->rdata, &rdata); - INSIST(rdata.length <= sizeof(buf)); - memcpy(buf, rdata.data, rdata.length); - buf[1] |= DNS_NSEC3FLAG_REMOVE; - rdata.data = buf; + dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype, + buf, sizeof(buf)); + + buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; CHECK(rr_exists(db, ver, name, &rdata, &flag)); + if (!flag) { + buf[2] &= ~DNS_NSEC3FLAG_NONSEC; + CHECK(rr_exists(db, ver, name, &rdata, &flag)); + } if (!flag) { CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, - name, tuple->ttl, &rdata, - &newtuple)); + name, 0, &rdata, &newtuple)); CHECK(do_one_tuple(&newtuple, db, ver, diff)); } CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, - tuple->ttl, &tuple->rdata, - &newtuple)); + ttl, &tuple->rdata, &newtuple)); CHECK(do_one_tuple(&newtuple, db, ver, diff)); ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); dns_diff_appendminimal(diff, &tuple); @@ -3246,17 +3350,75 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_diff_clear(&temp_diff); return (result); } -#endif + +static isc_result_t +rollback_private(dns_db_t *db, dns_rdatatype_t privatetype, + dns_dbversion_t *ver, dns_diff_t *diff) +{ + dns_diff_t temp_diff; + dns_diffop_t op; + dns_difftuple_t *tuple, *newtuple = NULL, *next; + dns_name_t *name = dns_db_origin(db); + isc_mem_t *mctx = diff->mctx; + isc_result_t result; + + if (privatetype == 0) + return (ISC_R_SUCCESS); + + dns_diff_init(mctx, &temp_diff); + + /* + * Extract the changes to be rolled back. + */ + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; tuple = next) { + + next = ISC_LIST_NEXT(tuple, link); + + if (tuple->rdata.type != privatetype || + !dns_name_equal(name, &tuple->name)) + continue; + + /* + * Allow records which indicate that a zone has been + * signed with a DNSKEY to be be removed. + */ + if (tuple->op == DNS_DIFFOP_DEL && + tuple->rdata.length == 5 && + tuple->rdata.data[0] != 0 && + tuple->rdata.data[4] != 0) + continue; + + ISC_LIST_UNLINK(diff->tuples, tuple, link); + ISC_LIST_PREPEND(temp_diff.tuples, tuple, link); + } + + /* + * Rollback the changes. + */ + while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) { + op = (tuple->op == DNS_DIFFOP_DEL) ? + DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; + CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl, + &tuple->rdata, &newtuple)); + CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff)); + } + result = ISC_R_SUCCESS; + + failure: + dns_diff_clear(&temp_diff); + return (result); +} /* * Add records to cause the delayed signing of the zone by added DNSKEY * to remove the RRSIG records generated by a deleted DNSKEY. */ static isc_result_t -add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver, - dns_rdatatype_t privatetype, dns_diff_t *diff) +add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, + dns_dbversion_t *ver, dns_diff_t *diff) { - dns_difftuple_t *tuple, *newtuple = NULL; + dns_difftuple_t *tuple, *newtuple = NULL, *next; dns_rdata_dnskey_t dnskey; dns_rdata_t rdata = DNS_RDATA_INIT; isc_boolean_t flag; @@ -3264,13 +3426,82 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver, isc_result_t result = ISC_R_SUCCESS; isc_uint16_t keyid; unsigned char buf[5]; + dns_name_t *name = dns_db_origin(db); + dns_diff_t temp_diff; + + dns_diff_init(diff->mctx, &temp_diff); + /* + * Extract the DNSKEY tuples from the list. + */ for (tuple = ISC_LIST_HEAD(diff->tuples); - tuple != NULL; - tuple = ISC_LIST_NEXT(tuple, link)) { + tuple != NULL; tuple = next) { + + next = ISC_LIST_NEXT(tuple, link); + if (tuple->rdata.type != dns_rdatatype_dnskey) continue; + ISC_LIST_UNLINK(diff->tuples, tuple, link); + ISC_LIST_APPEND(temp_diff.tuples, tuple, link); + } + + /* + * Extract TTL changes pairs, we don't need signing records for these. + */ + for (tuple = ISC_LIST_HEAD(temp_diff.tuples); + tuple != NULL; tuple = next) { + if (tuple->op == DNS_DIFFOP_ADD) { + /* + * Walk the temp_diff list looking for the + * corresponding delete. + */ + next = ISC_LIST_HEAD(temp_diff.tuples); + while (next != NULL) { + unsigned char *next_data = next->rdata.data; + unsigned char *tuple_data = tuple->rdata.data; + if (next->op == DNS_DIFFOP_DEL && + dns_name_equal(&tuple->name, &next->name) && + next->rdata.length == tuple->rdata.length && + !memcmp(next_data, tuple_data, + next->rdata.length)) { + ISC_LIST_UNLINK(temp_diff.tuples, next, + link); + ISC_LIST_APPEND(diff->tuples, next, + link); + break; + } + next = ISC_LIST_NEXT(next, link); + } + /* + * If we have not found a pair move onto the next + * tuple. + */ + if (next == NULL) { + next = ISC_LIST_NEXT(tuple, link); + continue; + } + /* + * Find the next tuple to be processed before + * unlinking then complete moving the pair to 'diff'. + */ + next = ISC_LIST_NEXT(tuple, link); + ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); + ISC_LIST_APPEND(diff->tuples, tuple, link); + } else + next = ISC_LIST_NEXT(tuple, link); + } + + /* + * Process the remaining DNSKEY entries. + */ + for (tuple = ISC_LIST_HEAD(temp_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_HEAD(temp_diff.tuples)) { + + ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); + ISC_LIST_APPEND(diff->tuples, tuple, link); + dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) @@ -3278,6 +3509,7 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver, continue; dns_rdata_toregion(&tuple->rdata, &r); + keyid = dst_region_computeid(&r, dnskey.algorithm); buf[0] = dnskey.algorithm; @@ -3310,87 +3542,25 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver, INSIST(newtuple == NULL); } } + failure: + dns_diff_clear(&temp_diff); return (result); } -#ifdef ALLOW_NSEC3PARAM_UPDATE -/* - * Mark all NSEC3 chains for deletion without creating a NSEC chain as - * a side effect of deleting the last chain. - */ -static isc_result_t -delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, - dns_diff_t *diff) -{ - dns_dbnode_t *node = NULL; - dns_difftuple_t *tuple = NULL; - dns_name_t next; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t rdataset; - isc_boolean_t flag; - isc_result_t result = ISC_R_SUCCESS; - unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; - - dns_name_init(&next, NULL); - dns_rdataset_init(&rdataset); - - result = dns_db_getoriginnode(db, &node); - if (result != ISC_R_SUCCESS) - return (result); - - /* - * Cause all NSEC3 chains to be deleted. - */ - result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, - 0, (isc_stdtime_t) 0, &rdataset, NULL); - if (result == ISC_R_NOTFOUND) - goto success; - if (result != ISC_R_SUCCESS) - goto failure; - - for (result = dns_rdataset_first(&rdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&rdataset)) { - dns_rdataset_current(&rdataset, &rdata); - INSIST(rdata.length <= sizeof(buf)); - memcpy(buf, rdata.data, rdata.length); - - if (buf[1] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) { - dns_rdata_reset(&rdata); - continue; - } - - CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, - origin, 0, &rdata, &tuple)); - CHECK(do_one_tuple(&tuple, db, ver, diff)); - INSIST(tuple == NULL); - - buf[1] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; - rdata.data = buf; - - CHECK(rr_exists(db, ver, origin, &rdata, &flag)); +static isc_boolean_t +isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) { + isc_result_t result; + isc_boolean_t build_nsec, build_nsec3; - if (!flag) { - CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, - origin, 0, &rdata, &tuple)); - CHECK(do_one_tuple(&tuple, db, ver, diff)); - INSIST(tuple == NULL); - } - dns_rdata_reset(&rdata); - } - if (result != ISC_R_NOMORE) - goto failure; - success: - result = ISC_R_SUCCESS; + if (dns_db_issecure(db)) + return (ISC_TRUE); - failure: - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); - dns_db_detachnode(db, &node); - return (result); + result = dns_private_chains(db, ver, privatetype, + &build_nsec, &build_nsec3); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + return (build_nsec || build_nsec3); } -#endif static void update_action(isc_task_t *task, isc_event_t *event) { @@ -3414,15 +3584,10 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_fixedname_t tmpnamefixed; dns_name_t *tmpname = NULL; unsigned int options; - isc_boolean_t deleted_zsk; dns_difftuple_t *tuple; dns_rdata_dnskey_t dnskey; -#ifdef ALLOW_NSEC3PARAM_UPDATE - unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; -#endif -#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE) isc_boolean_t had_dnskey; -#endif + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); INSIST(event->ev_type == DNS_EVENT_UPDATE); @@ -3433,6 +3598,18 @@ update_action(isc_task_t *task, isc_event_t *event) { zonename = dns_db_origin(db); zoneclass = dns_db_class(db); dns_zone_getssutable(zone, &ssutable); + + /* + * Update message processing can leak record existance information + * so check that we are allowed to query this zone. Additionally + * if we would refuse all updates for this zone we bail out here. + */ + CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename, + dns_zone_getupdateacl(zone), ssutable)); + + /* + * Get old and new versions now that queryacl has been checked. + */ dns_db_currentversion(db, &oldver); CHECK(dns_db_newversion(db, &ver)); @@ -3525,7 +3702,6 @@ update_action(isc_task_t *task, isc_event_t *event) { if (result != ISC_R_NOMORE) FAIL(result); - /* * Perform the final check of the "rrset exists (value dependent)" * prerequisites. @@ -3619,31 +3795,31 @@ update_action(isc_task_t *task, isc_event_t *event) { update_class); FAIL(DNS_R_FORMERR); } + /* * draft-ietf-dnsind-simple-secure-update-01 says * "Unlike traditional dynamic update, the client * is forbidden from updating NSEC records." */ - if (dns_db_issecure(db)) { - if (rdata.type == dns_rdatatype_nsec3) { - FAILC(DNS_R_REFUSED, - "explicit NSEC3 updates are not allowed " - "in secure zones"); - } else if (rdata.type == dns_rdatatype_nsec) { - FAILC(DNS_R_REFUSED, - "explicit NSEC updates are not allowed " - "in secure zones"); - } else if (rdata.type == dns_rdatatype_rrsig && - !dns_name_equal(name, zonename)) { - FAILC(DNS_R_REFUSED, - "explicit RRSIG updates are currently " - "not supported in secure zones except " - "at the apex"); - } + if (rdata.type == dns_rdatatype_nsec3) { + FAILC(DNS_R_REFUSED, + "explicit NSEC3 updates are not allowed " + "in secure zones"); + } else if (rdata.type == dns_rdatatype_nsec) { + FAILC(DNS_R_REFUSED, + "explicit NSEC updates are not allowed " + "in secure zones"); + } else if (rdata.type == dns_rdatatype_rrsig && + !dns_name_equal(name, zonename)) { + FAILC(DNS_R_REFUSED, + "explicit RRSIG updates are currently " + "not supported in secure zones except " + "at the apex"); } if (ssutable != NULL) { isc_netaddr_t *tcpaddr, netaddr; + dst_key_t *tsigkey = NULL; /* * If this is a TCP connection then pass the * address of the client through for tcp-self @@ -3656,16 +3832,22 @@ update_action(isc_task_t *task, isc_event_t *event) { tcpaddr = &netaddr; } else tcpaddr = NULL; + + if (client->message->tsigkey != NULL) + tsigkey = client->message->tsigkey->key; + if (rdata.type != dns_rdatatype_any) { if (!dns_ssutable_checkrules(ssutable, client->signer, name, tcpaddr, - rdata.type)) + rdata.type, + tsigkey)) FAILC(DNS_R_REFUSED, "rejected by secure update"); } else { if (!ssu_checkall(db, ver, name, ssutable, - client->signer, tcpaddr)) + client->signer, tcpaddr, + tsigkey)) FAILC(DNS_R_REFUSED, "rejected by secure update"); } @@ -3774,7 +3956,14 @@ update_action(isc_task_t *task, isc_event_t *event) { soa_serial_changed = ISC_TRUE; } -#ifdef ALLOW_NSEC3PARAM_UPDATE + if (rdata.type == privatetype) { + update_log(client, zone, LOGLEVEL_PROTOCOL, + "attempt to add a private type " + "(%u) record rejected internal " + "use only", privatetype); + continue; + } + if (rdata.type == dns_rdatatype_nsec3param) { /* * Ignore attempts to add NSEC3PARAM records @@ -3788,27 +3977,7 @@ update_action(isc_task_t *task, isc_event_t *event) { "flag"); continue; } - - /* - * Set the NSEC3CHAIN creation flag. - */ - INSIST(rdata.length <= sizeof(buf)); - memcpy(buf, rdata.data, rdata.length); - buf[1] |= DNS_NSEC3FLAG_UPDATE; - rdata.data = buf; - /* - * Force the TTL to zero for NSEC3PARAM records. - */ - ttl = 0; } -#else - if (rdata.type == dns_rdatatype_nsec3param) { - update_log(client, zone, LOGLEVEL_PROTOCOL, - "attempt to add NSEC3PARAM " - "record ignored"); - continue; - }; -#endif if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 && dns_name_internalwildcard(name)) { @@ -3885,13 +4054,6 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_rdatatype_any, 0, &rdata, &diff)); } -#ifndef ALLOW_NSEC3PARAM_UPDATE - } else if (rdata.type == dns_rdatatype_nsec3param) { - update_log(client, zone, LOGLEVEL_PROTOCOL, - "attempt to delete a NSEC3PARAM " - "records ignored"); - continue; -#endif } else if (dns_name_equal(name, zonename) && (rdata.type == dns_rdatatype_soa || rdata.type == dns_rdatatype_ns)) { @@ -3920,6 +4082,9 @@ update_action(isc_task_t *task, isc_event_t *event) { &diff)); } } else if (update_class == dns_rdataclass_none) { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + /* * The (name == zonename) condition appears in * RFC2136 3.4.2.4 but is missing from the pseudocode. @@ -3947,11 +4112,13 @@ update_action(isc_task_t *task, isc_event_t *event) { } } } - update_log(client, zone, - LOGLEVEL_PROTOCOL, - "deleting an RR"); - CHECK(delete_if(rr_equal_p, db, ver, name, - rdata.type, covers, &rdata, &diff)); + dns_name_format(name, namestr, sizeof(namestr)); + dns_rdatatype_format(rdata.type, typestr, + sizeof(typestr)); + update_log(client, zone, LOGLEVEL_PROTOCOL, + "deleting an RR at %s %s", namestr, typestr); + CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type, + covers, &rdata, &diff)); } } if (result != ISC_R_NOMORE) @@ -3965,6 +4132,18 @@ update_action(isc_task_t *task, isc_event_t *event) { if (! ISC_LIST_EMPTY(diff.tuples)) CHECK(check_dnssec(client, zone, db, ver, &diff)); + if (! ISC_LIST_EMPTY(diff.tuples)) { + unsigned int errors = 0; + CHECK(dns_zone_nscheck(zone, db, ver, &errors)); + if (errors != 0) { + update_log(client, zone, LOGLEVEL_PROTOCOL, + "update rejected: post update name server " + "sanity check failed"); + result = DNS_R_REFUSED; + goto failure; + } + } + /* * If any changes were made, increment the SOA serial number, * update RRSIGs and NSECs (if zone is secure), and write the update @@ -3990,37 +4169,29 @@ update_action(isc_task_t *task, isc_event_t *event) { CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey, 0, &has_dnskey)); -#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE) - CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey, - 0, &had_dnskey)); +#define ALLOW_SECURE_TO_INSECURE(zone) \ + ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0) -#ifndef ALLOW_SECURE_TO_INSECURE - if (had_dnskey && !has_dnskey) { - update_log(client, zone, LOGLEVEL_PROTOCOL, - "update rejected: all DNSKEY records " - "removed"); - result = DNS_R_REFUSED; - goto failure; - } -#endif -#ifndef ALLOW_INSECURE_TO_SECURE - if (!had_dnskey && has_dnskey) { - update_log(client, zone, LOGLEVEL_PROTOCOL, - "update rejected: DNSKEY record added"); - result = DNS_R_REFUSED; - goto failure; + if (!ALLOW_SECURE_TO_INSECURE(zone)) { + CHECK(rrset_exists(db, oldver, zonename, + dns_rdatatype_dnskey, 0, + &had_dnskey)); + if (had_dnskey && !has_dnskey) { + update_log(client, zone, LOGLEVEL_PROTOCOL, + "update rejected: all DNSKEY " + "records removed and " + "'dnssec-secure-to-insecure' " + "not set"); + result = DNS_R_REFUSED; + goto failure; + } } -#endif -#endif - CHECK(add_signing_records(db, zonename, ver, - dns_zone_getprivatetype(zone), - &diff)); + CHECK(rollback_private(db, privatetype, ver, &diff)); + + CHECK(add_signing_records(db, privatetype, ver, &diff)); -#ifdef ALLOW_NSEC3PARAM_UPDATE - CHECK(add_nsec3param_records(client, zone, db, zonename, - ver, &diff)); -#endif + CHECK(add_nsec3param_records(client, zone, db, ver, &diff)); if (!has_dnskey) { /* @@ -4029,15 +4200,13 @@ update_action(isc_task_t *task, isc_event_t *event) { * the last signature for the DNSKEY records are * remove any NSEC chain present will also be removed. */ -#ifdef ALLOW_NSEC3PARAM_UPDATE - CHECK(delete_chains(db, ver, zonename, &diff)); -#endif - } else if (has_dnskey && dns_db_isdnssec(db)) { + CHECK(dns_nsec3param_deletechains(db, ver, zone, + &diff)); + } else if (has_dnskey && isdnssec(db, ver, privatetype)) { isc_uint32_t interval; interval = dns_zone_getsigvalidityinterval(zone); result = update_signatures(client, zone, db, oldver, - ver, &diff, interval, - &deleted_zsk); + ver, &diff, interval); if (result != ISC_R_SUCCESS) { update_log(client, zone, ISC_LOG_ERROR, @@ -4123,7 +4292,6 @@ update_action(isc_task_t *task, isc_event_t *event) { } } -#ifdef ALLOW_NSEC3PARAM_UPDATE /* * Cause the zone to add/delete NSEC3 chains for the * deferred NSEC3PARAM changes. @@ -4133,13 +4301,18 @@ update_action(isc_task_t *task, isc_event_t *event) { for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL; tuple = ISC_LIST_NEXT(tuple, link)) { + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_nsec3param_t nsec3param; - if (tuple->rdata.type != dns_rdatatype_nsec3param || + if (tuple->rdata.type != privatetype || tuple->op != DNS_DIFFOP_ADD) continue; - dns_rdata_tostruct(&tuple->rdata, &nsec3param, NULL); + if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata, + buf, sizeof(buf))) + continue; + dns_rdata_tostruct(&rdata, &nsec3param, NULL); if (nsec3param.flags == 0) continue; @@ -4150,7 +4323,6 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_result_totext(result)); } } -#endif } else { update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); dns_db_closeversion(db, &ver, ISC_TRUE); diff --git a/contrib/bind9/bin/named/xfrout.c b/contrib/bind9/bin/named/xfrout.c index e61dc72efda2..b036ed14d57f 100644 --- a/contrib/bind9/bin/named/xfrout.c +++ b/contrib/bind9/bin/named/xfrout.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrout.c,v 1.131.26.6 2010-05-27 23:48:18 tbox Exp $ */ +/* $Id: xfrout.c,v 1.139 2010-12-18 01:56:19 each Exp $ */ #include <config.h> @@ -40,6 +40,7 @@ #include <dns/rdataset.h> #include <dns/rdatasetiter.h> #include <dns/result.h> +#include <dns/rriterator.h> #include <dns/soa.h> #include <dns/stats.h> #include <dns/timer.h> @@ -112,43 +113,6 @@ } while (0) /**************************************************************************/ -/*% - * A db_rr_iterator_t is an iterator that iterates over an entire database, - * returning one RR at a time, in some arbitrary order. - */ - -typedef struct db_rr_iterator db_rr_iterator_t; - -/*% db_rr_iterator structure */ -struct db_rr_iterator { - isc_result_t result; - dns_db_t *db; - dns_dbiterator_t *dbit; - dns_dbversion_t *ver; - isc_stdtime_t now; - dns_dbnode_t *node; - dns_fixedname_t fixedname; - dns_rdatasetiter_t *rdatasetit; - dns_rdataset_t rdataset; - dns_rdata_t rdata; -}; - -static isc_result_t -db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now); - -static isc_result_t -db_rr_iterator_first(db_rr_iterator_t *it); - -static isc_result_t -db_rr_iterator_next(db_rr_iterator_t *it); - -static void -db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, - isc_uint32_t *ttl, dns_rdata_t **rdata); - -static void -db_rr_iterator_destroy(db_rr_iterator_t *it); static inline void inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { @@ -160,145 +124,6 @@ inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { } } -static isc_result_t -db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now) -{ - isc_result_t result; - it->db = db; - it->dbit = NULL; - it->ver = ver; - it->now = now; - it->node = NULL; - result = dns_db_createiterator(it->db, 0, &it->dbit); - if (result != ISC_R_SUCCESS) - return (result); - it->rdatasetit = NULL; - dns_rdata_init(&it->rdata); - dns_rdataset_init(&it->rdataset); - dns_fixedname_init(&it->fixedname); - INSIST(! dns_rdataset_isassociated(&it->rdataset)); - it->result = ISC_R_SUCCESS; - return (it->result); -} - -static isc_result_t -db_rr_iterator_first(db_rr_iterator_t *it) { - it->result = dns_dbiterator_first(it->dbit); - /* - * The top node may be empty when out of zone glue exists. - * Walk the tree to find the first node with data. - */ - while (it->result == ISC_R_SUCCESS) { - it->result = dns_dbiterator_current(it->dbit, &it->node, - dns_fixedname_name(&it->fixedname)); - if (it->result != ISC_R_SUCCESS) - return (it->result); - - it->result = dns_db_allrdatasets(it->db, it->node, - it->ver, it->now, - &it->rdatasetit); - if (it->result != ISC_R_SUCCESS) - return (it->result); - - it->result = dns_rdatasetiter_first(it->rdatasetit); - if (it->result != ISC_R_SUCCESS) { - /* - * This node is empty. Try next node. - */ - dns_rdatasetiter_destroy(&it->rdatasetit); - dns_db_detachnode(it->db, &it->node); - it->result = dns_dbiterator_next(it->dbit); - continue; - } - dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); - it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; - it->result = dns_rdataset_first(&it->rdataset); - return (it->result); - } - return (it->result); -} - - -static isc_result_t -db_rr_iterator_next(db_rr_iterator_t *it) { - if (it->result != ISC_R_SUCCESS) - return (it->result); - - INSIST(it->dbit != NULL); - INSIST(it->node != NULL); - INSIST(it->rdatasetit != NULL); - - it->result = dns_rdataset_next(&it->rdataset); - if (it->result == ISC_R_NOMORE) { - dns_rdataset_disassociate(&it->rdataset); - it->result = dns_rdatasetiter_next(it->rdatasetit); - /* - * The while loop body is executed more than once - * only when an empty dbnode needs to be skipped. - */ - while (it->result == ISC_R_NOMORE) { - dns_rdatasetiter_destroy(&it->rdatasetit); - dns_db_detachnode(it->db, &it->node); - it->result = dns_dbiterator_next(it->dbit); - if (it->result == ISC_R_NOMORE) { - /* We are at the end of the entire database. */ - return (it->result); - } - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_dbiterator_current(it->dbit, - &it->node, - dns_fixedname_name(&it->fixedname)); - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_db_allrdatasets(it->db, it->node, - it->ver, it->now, - &it->rdatasetit); - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_rdatasetiter_first(it->rdatasetit); - } - if (it->result != ISC_R_SUCCESS) - return (it->result); - dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); - it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; - it->result = dns_rdataset_first(&it->rdataset); - if (it->result != ISC_R_SUCCESS) - return (it->result); - } - return (it->result); -} - -static void -db_rr_iterator_pause(db_rr_iterator_t *it) { - RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); -} - -static void -db_rr_iterator_destroy(db_rr_iterator_t *it) { - if (dns_rdataset_isassociated(&it->rdataset)) - dns_rdataset_disassociate(&it->rdataset); - if (it->rdatasetit != NULL) - dns_rdatasetiter_destroy(&it->rdatasetit); - if (it->node != NULL) - dns_db_detachnode(it->db, &it->node); - dns_dbiterator_destroy(&it->dbit); -} - -static void -db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, - isc_uint32_t *ttl, dns_rdata_t **rdata) -{ - REQUIRE(name != NULL && *name == NULL); - REQUIRE(it->result == ISC_R_SUCCESS); - *name = dns_fixedname_name(&it->fixedname); - *ttl = it->rdataset.ttl; - dns_rdata_reset(&it->rdata); - dns_rdataset_current(&it->rdataset, &it->rdata); - *rdata = &it->rdata; -} - /**************************************************************************/ /*% Log an RR (for debugging) */ @@ -488,7 +313,7 @@ static rrstream_methods_t ixfr_rrstream_methods = { typedef struct axfr_rrstream { rrstream_t common; - db_rr_iterator_t it; + dns_rriterator_t it; isc_boolean_t it_valid; } axfr_rrstream_t; @@ -516,7 +341,7 @@ axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, s->common.methods = &axfr_rrstream_methods; s->it_valid = ISC_FALSE; - CHECK(db_rr_iterator_init(&s->it, db, ver, 0)); + CHECK(dns_rriterator_init(&s->it, db, ver, 0)); s->it_valid = ISC_TRUE; *sp = (rrstream_t *) s; @@ -531,7 +356,7 @@ static isc_result_t axfr_rrstream_first(rrstream_t *rs) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; isc_result_t result; - result = db_rr_iterator_first(&s->it); + result = dns_rriterator_first(&s->it); if (result != ISC_R_SUCCESS) return (result); /* Skip SOA records. */ @@ -539,11 +364,11 @@ axfr_rrstream_first(rrstream_t *rs) { dns_name_t *name_dummy = NULL; isc_uint32_t ttl_dummy; dns_rdata_t *rdata = NULL; - db_rr_iterator_current(&s->it, &name_dummy, - &ttl_dummy, &rdata); + dns_rriterator_current(&s->it, &name_dummy, + &ttl_dummy, NULL, &rdata); if (rdata->type != dns_rdatatype_soa) break; - result = db_rr_iterator_next(&s->it); + result = dns_rriterator_next(&s->it); if (result != ISC_R_SUCCESS) break; } @@ -560,11 +385,11 @@ axfr_rrstream_next(rrstream_t *rs) { dns_name_t *name_dummy = NULL; isc_uint32_t ttl_dummy; dns_rdata_t *rdata = NULL; - result = db_rr_iterator_next(&s->it); + result = dns_rriterator_next(&s->it); if (result != ISC_R_SUCCESS) break; - db_rr_iterator_current(&s->it, &name_dummy, - &ttl_dummy, &rdata); + dns_rriterator_current(&s->it, &name_dummy, + &ttl_dummy, NULL, &rdata); if (rdata->type != dns_rdatatype_soa) break; } @@ -576,20 +401,20 @@ axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, dns_rdata_t **rdata) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; - db_rr_iterator_current(&s->it, name, ttl, rdata); + dns_rriterator_current(&s->it, name, ttl, NULL, rdata); } static void axfr_rrstream_pause(rrstream_t *rs) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; - db_rr_iterator_pause(&s->it); + dns_rriterator_pause(&s->it); } static void axfr_rrstream_destroy(rrstream_t **rsp) { axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; if (s->it_valid) - db_rr_iterator_destroy(&s->it); + dns_rriterator_destroy(&s->it); isc_mem_put(s->common.mctx, s, sizeof(*s)); } @@ -1038,6 +863,7 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { switch(dns_zone_gettype(zone)) { case dns_zone_master: case dns_zone_slave: + case dns_zone_dlz: break; /* Master and slave zones are OK for transfer. */ default: FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); diff --git a/contrib/bind9/bin/named/zoneconf.c b/contrib/bind9/bin/named/zoneconf.c index 367ddd320d2c..eb93f1bbe45b 100644 --- a/contrib/bind9/bin/named/zoneconf.c +++ b/contrib/bind9/bin/named/zoneconf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zoneconf.c,v 1.147.50.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: zoneconf.c,v 1.170 2011-01-06 23:47:00 tbox Exp $ */ /*% */ @@ -30,10 +30,16 @@ #include <isc/util.h> #include <dns/acl.h> +#include <dns/db.h> #include <dns/fixedname.h> #include <dns/log.h> #include <dns/name.h> +#include <dns/rdata.h> #include <dns/rdatatype.h> +#include <dns/rdataset.h> +#include <dns/rdatalist.h> +#include <dns/result.h> +#include <dns/sdlz.h> #include <dns/ssu.h> #include <dns/stats.h> #include <dns/view.h> @@ -55,16 +61,18 @@ typedef enum { allow_update_forwarding } acl_type_t; -/*% - * These are BIND9 server defaults, not necessarily identical to the - * library defaults defined in zone.c. - */ #define RETERR(x) do { \ isc_result_t _r = (x); \ if (_r != ISC_R_SUCCESS) \ return (_r); \ } while (0) +#define CHECK(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + /*% * Convenience function for configuring a single zone ACL. */ @@ -133,8 +141,11 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, } /* Check for default ACLs that haven't been parsed yet */ - if (vconfig != NULL) - maps[i++] = cfg_tuple_get(vconfig, "options"); + if (vconfig != NULL) { + const cfg_obj_t *options = cfg_tuple_get(vconfig, "options"); + if (options != NULL) + maps[i++] = options; + } if (config != NULL) { const cfg_obj_t *options = NULL; (void)cfg_map_get(config, "options", &options); @@ -169,19 +180,29 @@ parse_acl: * Parse the zone update-policy statement. */ static isc_result_t -configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { +configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone, + const char *zname) +{ const cfg_obj_t *updatepolicy = NULL; const cfg_listelt_t *element, *element2; dns_ssutable_t *table = NULL; isc_mem_t *mctx = dns_zone_getmctx(zone); + isc_boolean_t autoddns = ISC_FALSE; isc_result_t result; (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); + if (updatepolicy == NULL) { dns_zone_setssutable(zone, NULL); return (ISC_R_SUCCESS); } + if (cfg_obj_isstring(updatepolicy) && + strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) { + autoddns = ISC_TRUE; + updatepolicy = NULL; + } + result = dns_ssutable_create(mctx, &table); if (result != ISC_R_SUCCESS) return (result); @@ -198,6 +219,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); const char *str; isc_boolean_t grant = ISC_FALSE; + isc_boolean_t usezone = ISC_FALSE; unsigned int mtype = DNS_SSUMATCHTYPE_NAME; dns_fixedname_t fname, fident; isc_buffer_t b; @@ -237,6 +259,11 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { mtype = DNS_SSUMATCHTYPE_TCPSELF; else if (strcasecmp(str, "6to4-self") == 0) mtype = DNS_SSUMATCHTYPE_6TO4SELF; + else if (strcasecmp(str, "zonesub") == 0) { + mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; + usezone = ISC_TRUE; + } else if (strcasecmp(str, "external") == 0) + mtype = DNS_SSUMATCHTYPE_EXTERNAL; else INSIST(0); @@ -245,7 +272,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fident), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); @@ -253,15 +280,27 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { } dns_fixedname_init(&fname); - str = cfg_obj_asstring(dname); - isc_buffer_init(&b, str, strlen(str)); - isc_buffer_add(&b, strlen(str)); - result = dns_name_fromtext(dns_fixedname_name(&fname), &b, - dns_rootname, ISC_FALSE, NULL); - if (result != ISC_R_SUCCESS) { - cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, - "'%s' is not a valid name", str); - goto cleanup; + if (usezone) { + result = dns_name_copy(dns_zone_getorigin(zone), + dns_fixedname_name(&fname), + NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, + "error copying origin: %s", + isc_result_totext(result)); + goto cleanup; + } + } else { + str = cfg_obj_asstring(dname); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(dns_fixedname_name(&fname), + &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + goto cleanup; + } } n = ns_config_listcount(typelist); @@ -311,7 +350,34 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { if (result != ISC_R_SUCCESS) { goto cleanup; } + } + + /* + * If "update-policy local;" and a session key exists, + * then use the default policy, which is equivalent to: + * update-policy { grant <session-keyname> zonesub any; }; + */ + if (autoddns) { + dns_rdatatype_t any = dns_rdatatype_any; + + if (ns_g_server->session_keyname == NULL) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "failed to enable auto DDNS policy " + "for zone %s: session key not found", + zname); + result = ISC_R_NOTFOUND; + goto cleanup; + } + result = dns_ssutable_addrule(table, ISC_TRUE, + ns_g_server->session_keyname, + DNS_SSUMATCHTYPE_SUBDOMAIN, + dns_zone_getorigin(zone), + 1, &any); + + if (result != ISC_R_SUCCESS) + goto cleanup; } result = ISC_R_SUCCESS; @@ -322,6 +388,323 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { return (result); } +/* + * This is the TTL used for internally generated RRsets for static-stub zones. + * The value doesn't matter because the mapping is static, but needs to be + * defined for the sake of implementation. + */ +#define STATICSTUB_SERVER_TTL 86400 + +/*% + * Configure an apex NS with glues for a static-stub zone. + * For example, for the zone named "example.com", the following RRs will be + * added to the zone DB: + * example.com. NS example.com. + * example.com. A 192.0.2.1 + * example.com. AAAA 2001:db8::1 + */ +static isc_result_t +configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone, + dns_rdatalist_t *rdatalist_ns, + dns_rdatalist_t *rdatalist_a, + dns_rdatalist_t *rdatalist_aaaa) +{ + const cfg_listelt_t *element; + isc_mem_t *mctx = dns_zone_getmctx(zone); + isc_region_t region, sregion; + dns_rdata_t *rdata; + isc_result_t result = ISC_R_SUCCESS; + + for (element = cfg_list_first(zconfig); + element != NULL; + element = cfg_list_next(element)) + { + const isc_sockaddr_t* sa; + isc_netaddr_t na; + const cfg_obj_t *address = cfg_listelt_value(element); + dns_rdatalist_t *rdatalist; + + sa = cfg_obj_assockaddr(address); + if (isc_sockaddr_getport(sa) != 0) { + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "port is not configurable for " + "static stub server-addresses"); + return (ISC_R_FAILURE); + } + isc_netaddr_fromsockaddr(&na, sa); + if (isc_netaddr_getzone(&na) != 0) { + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "scoped address is not allowed " + "for static stub " + "server-addresses"); + return (ISC_R_FAILURE); + } + + switch (na.family) { + case AF_INET: + region.length = sizeof(na.type.in); + rdatalist = rdatalist_a; + break; + default: + INSIST(na.family == AF_INET6); + region.length = sizeof(na.type.in6); + rdatalist = rdatalist_aaaa; + break; + } + + rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length); + if (rdata == NULL) + return (ISC_R_NOMEMORY); + region.base = (unsigned char *)(rdata + 1); + memcpy(region.base, &na.type, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), + rdatalist->type, ®ion); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + /* + * If no address is specified (unlikely in this context, but possible), + * there's nothing to do anymore. + */ + if (ISC_LIST_EMPTY(rdatalist_a->rdata) && + ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) { + return (ISC_R_SUCCESS); + } + + /* Add to the list an apex NS with the ns name being the origin name */ + dns_name_toregion(dns_zone_getorigin(zone), &sregion); + rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); + if (rdata == NULL) { + /* + * Already allocated data will be freed in the caller, so + * we can simply return here. + */ + return (ISC_R_NOMEMORY); + } + region.length = sregion.length; + region.base = (unsigned char *)(rdata + 1); + memcpy(region.base, sregion.base, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), + dns_rdatatype_ns, ®ion); + ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link); + + return (result); +} + +/*% + * Configure an apex NS with an out-of-zone NS names for a static-stub zone. + * For example, for the zone named "example.com", something like the following + * RRs will be added to the zone DB: + * example.com. NS ns.example.net. + */ +static isc_result_t +configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone, + dns_rdatalist_t *rdatalist, const char *zname) +{ + const cfg_listelt_t *element; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_rdata_t *rdata; + isc_region_t sregion, region; + isc_result_t result = ISC_R_SUCCESS; + + for (element = cfg_list_first(zconfig); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *obj; + const char *str; + dns_fixedname_t fixed_name; + dns_name_t *nsname; + isc_buffer_t b; + + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + + dns_fixedname_init(&fixed_name); + nsname = dns_fixedname_name(&fixed_name); + + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "server-name '%s' is not a valid " + "name", str); + return (result); + } + if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) { + cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, + "server-name '%s' must not be a " + "subdomain of zone name '%s'", + str, zname); + return (ISC_R_FAILURE); + } + + dns_name_toregion(nsname, &sregion); + rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); + if (rdata == NULL) + return (ISC_R_NOMEMORY); + region.length = sregion.length; + region.base = (unsigned char *)(rdata + 1); + memcpy(region.base, sregion.base, region.length); + dns_rdata_init(rdata); + dns_rdata_fromregion(rdata, dns_zone_getclass(zone), + dns_rdatatype_ns, ®ion); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + return (result); +} + +/*% + * Configure static-stub zone. + */ +static isc_result_t +configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone, + const char *zname, const char *dbtype) +{ + int i = 0; + const cfg_obj_t *obj; + isc_mem_t *mctx = dns_zone_getmctx(zone); + dns_db_t *db = NULL; + dns_dbversion_t *dbversion = NULL; + dns_dbnode_t *apexnode = NULL; + dns_name_t apexname; + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa; + dns_rdatalist_t* rdatalists[] = { + &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL + }; + dns_rdata_t *rdata; + isc_region_t region; + + /* Create the DB beforehand */ + RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone), + dns_dbtype_stub, dns_zone_getclass(zone), + 0, NULL, &db)); + dns_zone_setdb(zone, db); + + dns_rdatalist_init(&rdatalist_ns); + rdatalist_ns.rdclass = dns_zone_getclass(zone); + rdatalist_ns.type = dns_rdatatype_ns; + rdatalist_ns.ttl = STATICSTUB_SERVER_TTL; + + dns_rdatalist_init(&rdatalist_a); + rdatalist_a.rdclass = dns_zone_getclass(zone); + rdatalist_a.type = dns_rdatatype_a; + rdatalist_a.ttl = STATICSTUB_SERVER_TTL; + + dns_rdatalist_init(&rdatalist_aaaa); + rdatalist_aaaa.rdclass = dns_zone_getclass(zone); + rdatalist_aaaa.type = dns_rdatatype_aaaa; + rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL; + + /* Prepare zone RRs from the configuration */ + obj = NULL; + result = cfg_map_get(zconfig, "server-addresses", &obj); + if (obj != NULL) { + result = configure_staticstub_serveraddrs(obj, zone, + &rdatalist_ns, + &rdatalist_a, + &rdatalist_aaaa); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + obj = NULL; + result = cfg_map_get(zconfig, "server-names", &obj); + if (obj != NULL) { + result = configure_staticstub_servernames(obj, zone, + &rdatalist_ns, + zname); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + /* + * Sanity check: there should be at least one NS RR at the zone apex + * to trigger delegation. + */ + if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "No NS record is configured for a " + "static-stub zone '%s'", zname); + result = ISC_R_FAILURE; + goto cleanup; + } + + /* + * Now add NS and glue A/AAAA RRsets to the zone DB. + * First open a new version for the add operation and get a pointer + * to the apex node (all RRs are of the apex name). + */ + result = dns_db_newversion(db, &dbversion); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_name_init(&apexname, NULL); + dns_name_clone(dns_zone_getorigin(zone), &apexname); + result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* Add NS RRset */ + dns_rdataset_init(&rdataset); + RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset) + == ISC_R_SUCCESS); + result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, + 0, NULL); + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* Add glue A RRset, if any */ + if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) { + RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset) + == ISC_R_SUCCESS); + result = dns_db_addrdataset(db, apexnode, dbversion, 0, + &rdataset, 0, NULL); + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + /* Add glue AAAA RRset, if any */ + if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) { + RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa, + &rdataset) + == ISC_R_SUCCESS); + result = dns_db_addrdataset(db, apexnode, dbversion, 0, + &rdataset, 0, NULL); + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + + result = ISC_R_SUCCESS; + + cleanup: + if (apexnode != NULL) + dns_db_detachnode(db, &apexnode); + if (dbversion != NULL) + dns_db_closeversion(db, &dbversion, ISC_TRUE); + if (db != NULL) + dns_db_detach(&db); + for (i = 0; rdatalists[i] != NULL; i++) { + while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) { + ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link); + dns_rdata_toregion(rdata, ®ion); + isc_mem_put(mctx, rdata, + sizeof(*rdata) + region.length); + } + } + + return (result); +} + /*% * Convert a config file zone type into a server zone type. */ @@ -503,6 +886,19 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, if (result == ISC_R_SUCCESS) filename = cfg_obj_asstring(obj); + /* + * Unless we're using some alternative database, a master zone + * will be needing a master file. + */ + if (ztype == dns_zone_master && cpval == default_dbtype && + filename == NULL) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "zone '%s': 'file' not specified", + zname); + return (ISC_R_FAILURE); + } + masterformat = dns_masterformat_text; obj = NULL; result= ns_config_get(maps, "masterfile-format", &obj); @@ -577,7 +973,7 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, * to primary masters (type "master") and slaves * acting as masters (type "slave"), but not to stubs. */ - if (ztype != dns_zone_stub) { + if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) { obj = NULL; result = ns_config_get(maps, "notify", &obj); INSIST(result == ISC_R_SUCCESS); @@ -731,6 +1127,7 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, */ if (ztype == dns_zone_master) { dns_acl_t *updateacl; + RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update, ac, zone, dns_zone_setupdateacl, @@ -744,7 +1141,7 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, "address, which is insecure", zname); - RETERR(configure_zone_ssutable(zoptions, zone)); + RETERR(configure_zone_ssutable(zoptions, zone, zname)); obj = NULL; result = ns_config_get(maps, "sig-validity-interval", &obj); @@ -774,12 +1171,6 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, result = ns_config_get(maps, "key-directory", &obj); if (result == ISC_R_SUCCESS) { filename = cfg_obj_asstring(obj); - if (!isc_file_isabsolute(filename)) { - cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, - "key-directory '%s' " - "is not absolute", filename); - return (ISC_R_FAILURE); - } RETERR(dns_zone_setkeydirectory(zone, filename)); } @@ -804,6 +1195,11 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, cfg_obj_asboolean(obj)); + obj = NULL; + result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY, + cfg_obj_asboolean(obj)); } else if (ztype == dns_zone_slave) { RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update_forwarding, ac, zone, @@ -811,11 +1207,13 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_zone_clearforwardacl)); } - /*% * Primary master functionality. */ if (ztype == dns_zone_master) { + isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE; + isc_boolean_t create = ISC_FALSE; + obj = NULL; result = ns_config_get(maps, "check-wildcard", &obj); if (result == ISC_R_SUCCESS) @@ -825,6 +1223,21 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check); obj = NULL; + result = ns_config_get(maps, "check-dup-records", &obj); + INSIST(obj != NULL); + if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { + fail = ISC_FALSE; + check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { + fail = check = ISC_TRUE; + } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { + fail = check = ISC_FALSE; + } else + INSIST(0); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check); + dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail); + + obj = NULL; result = ns_config_get(maps, "check-mx", &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { @@ -874,6 +1287,31 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore); + + obj = NULL; + result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj); + INSIST(obj != NULL); + dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE, + cfg_obj_asboolean(obj)); + + obj = NULL; + result = cfg_map_get(zoptions, "auto-dnssec", &obj); + if (result == ISC_R_SUCCESS) { + const char *arg = cfg_obj_asstring(obj); + if (strcasecmp(arg, "allow") == 0) + allow = ISC_TRUE; + else if (strcasecmp(arg, "maintain") == 0) + allow = maint = ISC_TRUE; + else if (strcasecmp(arg, "create") == 0) + allow = maint = create = ISC_TRUE; + else if (strcasecmp(arg, "off") == 0) + ; + else + INSIST(0); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint); + dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, create); + } } /* @@ -982,6 +1420,11 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, cfg_obj_asboolean(obj)); break; + case dns_zone_staticstub: + RETERR(configure_staticstub(zoptions, zone, zname, + default_dbtype)); + break; + default: break; } @@ -989,6 +1432,31 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, return (ISC_R_SUCCESS); } + +#ifdef DLZ +/* + * Set up a DLZ zone as writeable + */ +isc_result_t +ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone, + dns_rdataclass_t rdclass, dns_name_t *name) +{ + dns_db_t *db = NULL; + isc_time_t now; + isc_result_t result; + + TIME_NOW(&now); + + dns_zone_settype(zone, dns_zone_dlz); + result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db); + if (result != ISC_R_SUCCESS) + return result; + result = dns_zone_dlzpostload(zone, db); + dns_db_detach(&db); + return result; +} +#endif + isc_boolean_t ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) { const cfg_obj_t *zoptions = NULL; @@ -1001,6 +1469,13 @@ ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) { if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone)) return (ISC_FALSE); + /* + * We always reconfigure a static-stub zone for simplicity, assuming + * the amount of data to be loaded is small. + */ + if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) + return (ISC_FALSE); + obj = NULL; (void)cfg_map_get(zoptions, "file", &obj); if (obj != NULL) |