From: Mark Andrews Date: Thu, 18 Aug 2005 00:57:31 +0000 (+0000) Subject: 1913. [func] Automatic empty zone creation for D.F.IP6.ARPA and X-Git-Tag: v9.2.6b1~28^2~43 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=6b79e960e6ba2991aeb02a6c39af255ab7f06d99;p=thirdparty%2Fbind9.git 1913. [func] Automatic empty zone creation for D.F.IP6.ARPA and friends. Note: RFC 1918 zones are not yet covered by this but are likely to be in a future release. New options: empty-server, empty-contact, empty-zones-enable and disable-empty-zone. --- diff --git a/CHANGES b/CHANGES index daaee612edf..ae205259e63 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +1913. [func] Automatic empty zone creation for D.F.IP6.ARPA and + friends. Note: RFC 1918 zones are not yet covered by + this but are likely to be in a future release. + + New options: empty-server, empty-contact, + empty-zones-enable and disable-empty-zone. + 1912. [func] ISC string copy API. 1911. [func] Attempt to make the amount of work performed in a diff --git a/bin/named/builtin.c b/bin/named/builtin.c index e258b4beab9..a8ecde959aa 100644 --- a/bin/named/builtin.c +++ b/bin/named/builtin.c @@ -15,11 +15,11 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: builtin.c,v 1.7 2005/04/29 00:22:26 marka Exp $ */ +/* $Id: builtin.c,v 1.8 2005/08/18 00:57:26 marka Exp $ */ /*! \file * \brief - * The built-in "version", "hostname", "id" and "authors" databases. + * The built-in "version", "hostname", "id", "authors" and "empty" databases. */ #include @@ -27,12 +27,13 @@ #include #include +#include #include #include #include -#include #include +#include #include #include @@ -45,6 +46,7 @@ static isc_result_t do_version_lookup(dns_sdblookup_t *lookup); 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); /* * We can't use function pointers as the db_data directly @@ -54,12 +56,15 @@ static isc_result_t do_id_lookup(dns_sdblookup_t *lookup); struct builtin { isc_result_t (*do_lookup)(dns_sdblookup_t *lookup); + char *server; + char *contact; }; -static builtin_t version_builtin = { do_version_lookup }; -static builtin_t hostname_builtin = { do_hostname_lookup }; -static builtin_t authors_builtin = { do_authors_lookup }; -static builtin_t id_builtin = { do_id_lookup }; +static builtin_t version_builtin = { do_version_lookup, NULL, NULL }; +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 dns_sdbimplementation_t *builtin_impl; @@ -167,17 +172,38 @@ do_id_lookup(dns_sdblookup_t *lookup) { return (put_txt(lookup, ns_g_server->server_id)); } +static isc_result_t +do_empty_lookup(dns_sdblookup_t *lookup) { + + UNUSED(lookup); + return (ISC_R_SUCCESS); +} + static isc_result_t builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) { isc_result_t result; + const char *contact = "hostmaster"; + const char *server = "@"; + builtin_t *b = (builtin_t *) dbdata; UNUSED(zone); UNUSED(dbdata); - result = dns_sdb_putsoa(lookup, "@", "hostmaster", 0); + if (b == &empty_builtin) { + server = "."; + contact = "."; + } else { + if (b->server != NULL) + server = b->server; + if (b->contact != NULL) + contact = b->contact; + } + + result = dns_sdb_putsoa(lookup, server, contact, 0); if (result != ISC_R_SUCCESS) return (ISC_R_FAILURE); - result = dns_sdb_putrr(lookup, "ns", 0, "@"); + + result = dns_sdb_putrr(lookup, "ns", 0, server); if (result != ISC_R_SUCCESS) return (ISC_R_FAILURE); @@ -190,8 +216,11 @@ builtin_create(const char *zone, int argc, char **argv, { UNUSED(zone); UNUSED(driverdata); - if (argc != 1) + + if ((argc != 1 && strcmp(argv[0], "empty") != 0) || + argc != 3) return (DNS_R_SYNTAX); + if (strcmp(argv[0], "version") == 0) *dbdata = &version_builtin; else if (strcmp(argv[0], "hostname") == 0) @@ -200,17 +229,62 @@ builtin_create(const char *zone, int argc, char **argv, *dbdata = &authors_builtin; else if (strcmp(argv[0], "id") == 0) *dbdata = &id_builtin; - else + else if (strcmp(argv[0], "empty") == 0) { + builtin_t *empty; + char *server; + char *contact; + /* + * We don't want built-in zones to fail. Fallback to + * to the static configuration if memory allocation fails. + */ + empty = isc_mem_get(ns_g_mctx, sizeof(*empty)); + 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 (server != NULL) + isc_mem_free(ns_g_mctx, server); + if (contact != NULL) + isc_mem_free(ns_g_mctx, contact); + if (empty != NULL) + isc_mem_put(ns_g_mctx, empty, sizeof (*empty)); + } else { + memcpy(empty, &empty_builtin, sizeof (empty_builtin)); + empty->server = server; + empty->contact = contact; + *dbdata = empty; + } + } else return (ISC_R_NOTIMPLEMENTED); return (ISC_R_SUCCESS); } +static void +builtin_destroy(const char *zone, void *driverdata, void **dbdata) { + builtin_t *b = (builtin_t *) *dbdata; + + UNUSED(zone); + UNUSED(driverdata); + + /* + * Don't free the static versions. + */ + if (*dbdata == &version_builtin || *dbdata == &hostname_builtin || + *dbdata == &authors_builtin || *dbdata == &id_builtin || + *dbdata == &empty_builtin) + return; + + isc_mem_free(ns_g_mctx, b->server); + isc_mem_free(ns_g_mctx, b->contact); + isc_mem_put(ns_g_mctx, b, sizeof (*b)); +} + static dns_sdbmethods_t builtin_methods = { builtin_lookup, builtin_authority, NULL, /* allnodes */ builtin_create, - NULL /* destroy */ + builtin_destroy }; isc_result_t diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index fc1a0712e51..1237de15fa6 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.79 2005/08/15 01:21:05 marka Exp $ */ +/* $Id: server.h,v 1.80 2005/08/18 00:57:27 marka Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -62,9 +62,6 @@ struct ns_server { isc_boolean_t server_usehostname; char * server_id; /*%< User-specified server id */ - /*% Empty zone SOA ORIGIN and CONTACT */ - char * empty_contact; - char * empty_server; /*% * Current ACL environment. This defines the * current values of the localhost and localnets diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook index adbe9dce8d2..d9d7952363e 100644 --- a/bin/named/named.conf.docbook +++ b/bin/named/named.conf.docbook @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + Aug 13, 2004 @@ -261,6 +261,11 @@ options { dnssec-lookaside string trust-anchor string; dnssec-must-be-secure string boolean; + empty-server string; + empty-contact string; + empty-zones-enable boolean; + disable-empty-zone string; + dialup dialuptype; ixfr-from-differences ixfrdiff; @@ -396,6 +401,12 @@ view string optional_class dnssec-lookaside string trust-anchor string; dnssec-must-be-secure string boolean; + + empty-server string; + empty-contact string; + empty-zones-enable boolean; + disable-empty-zone string; + dialup dialuptype; ixfr-from-differences ixfrdiff; diff --git a/bin/named/query.c b/bin/named/query.c index 84169b53e5d..285f7133fad 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.271 2005/08/11 04:45:38 marka Exp $ */ +/* $Id: query.c,v 1.272 2005/08/18 00:57:26 marka Exp $ */ /*! \file */ @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -2914,6 +2915,109 @@ answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) { } } +#define NS_NAME_INIT(A,B) \ + { \ + DNS_NAME_MAGIC, \ + A, sizeof(A), sizeof(B), \ + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \ + B, NULL, { (void *)-1, (void *)-1}, \ + {NULL, NULL} \ + } + +static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 }; +static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 }; +static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 }; + +static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA"; + +static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA"; + +static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA"; + +static dns_name_t rfc1918names[] = { + NS_NAME_INIT(inaddr10, inaddr10_offsets), + NS_NAME_INIT(inaddr16172, inaddr172_offsets), + NS_NAME_INIT(inaddr17172, inaddr172_offsets), + NS_NAME_INIT(inaddr18172, inaddr172_offsets), + NS_NAME_INIT(inaddr19172, inaddr172_offsets), + NS_NAME_INIT(inaddr20172, inaddr172_offsets), + NS_NAME_INIT(inaddr21172, inaddr172_offsets), + NS_NAME_INIT(inaddr22172, inaddr172_offsets), + NS_NAME_INIT(inaddr23172, inaddr172_offsets), + NS_NAME_INIT(inaddr24172, inaddr172_offsets), + NS_NAME_INIT(inaddr25172, inaddr172_offsets), + NS_NAME_INIT(inaddr26172, inaddr172_offsets), + NS_NAME_INIT(inaddr27172, inaddr172_offsets), + NS_NAME_INIT(inaddr28172, inaddr172_offsets), + NS_NAME_INIT(inaddr29172, inaddr172_offsets), + NS_NAME_INIT(inaddr30172, inaddr172_offsets), + NS_NAME_INIT(inaddr31172, inaddr172_offsets), + NS_NAME_INIT(inaddr168192, inaddr192_offsets) +}; + + +static unsigned char prisoner_data[] = "\010prisoner\004iana\003org"; +static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org"; + +static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 }; +static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 }; + +static dns_name_t prisoner = NS_NAME_INIT(prisoner_data, prisoner_offsets); +static dns_name_t hostmaster = NS_NAME_INIT(hostmaster_data, hostmaster_offsets); + +static void +warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) { + unsigned int i; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + dns_rdataset_t found; + isc_result_t result; + + for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) { + if (dns_name_issubdomain(fname, &rfc1918names[i])) { + dns_rdataset_init(&found); + result = dns_ncache_getrdataset(rdataset, + &rfc1918names[i], + dns_rdatatype_soa, + &found); + if (result != ISC_R_SUCCESS) + return; + + result = dns_rdataset_first(&found); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(&found, &rdata); + dns_rdata_tostruct(&rdata, &soa, NULL); + if (dns_name_equal(&soa.origin, &prisoner) && + dns_name_equal(&soa.contact, &hostmaster)) { + char buf[DNS_NAME_FORMATSIZE]; + dns_name_format(fname, buf, sizeof(buf)); + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_QUERY, + ISC_LOG_WARNING, + "RFC 1918 response from " + "Internet for %s", buf); + } + dns_rdataset_disassociate(&found); + return; + } + } +} + /* * Do the bulk of query processing for the current query of 'client'. * If 'event' is non-NULL, we are returning from recursion and 'qtype' @@ -3518,6 +3622,14 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ if (result == DNS_R_NCACHENXDOMAIN) client->message->rcode = dns_rcode_nxdomain; + /* + * Look for RFC 1918 leakage from Internet. + */ + if (result == DNS_R_NCACHENXDOMAIN && + qtype == dns_rdatatype_ptr && + client->message->rdclass == dns_rdataclass_in && + dns_name_countlabels(fname) == 7) + warn_rfc1918(client, fname, rdataset); /* * We don't call query_addrrset() because we don't need any * of its extra features (and things would probably break!). diff --git a/bin/named/server.c b/bin/named/server.c index 96435cb42dc..0abab522b99 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.447 2005/08/15 01:21:04 marka Exp $ */ +/* $Id: server.c,v 1.448 2005/08/18 00:57:27 marka Exp $ */ /*! \file */ @@ -164,6 +164,58 @@ struct zonelistentry { ISC_LINK(struct zonelistentry) link; }; +/* + * These zones should not leak onto the Internet. + */ +static const struct { + const char *zone; + isc_boolean_t rfc1918; +} empty_zones[] = { +#ifdef notyet + /* RFC 1918 */ + { "10.IN-ADDR.ARPA", ISC_TRUE }, + { "16.172.IN-ADDR.ARPA", ISC_TRUE }, + { "17.172.IN-ADDR.ARPA", ISC_TRUE }, + { "18.172.IN-ADDR.ARPA", ISC_TRUE }, + { "19.172.IN-ADDR.ARPA", ISC_TRUE }, + { "20.172.IN-ADDR.ARPA", ISC_TRUE }, + { "21.172.IN-ADDR.ARPA", ISC_TRUE }, + { "22.172.IN-ADDR.ARPA", ISC_TRUE }, + { "23.172.IN-ADDR.ARPA", ISC_TRUE }, + { "24.172.IN-ADDR.ARPA", ISC_TRUE }, + { "25.172.IN-ADDR.ARPA", ISC_TRUE }, + { "26.172.IN-ADDR.ARPA", ISC_TRUE }, + { "27.172.IN-ADDR.ARPA", ISC_TRUE }, + { "28.172.IN-ADDR.ARPA", ISC_TRUE }, + { "29.172.IN-ADDR.ARPA", ISC_TRUE }, + { "30.172.IN-ADDR.ARPA", ISC_TRUE }, + { "31.172.IN-ADDR.ARPA", ISC_TRUE }, + { "168.192.IN-ADDR.ARPA", ISC_TRUE }, +#endif + + /* RFC 3330 */ + { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */ + { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */ + { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */ + + /* Local IPv6 Unicast Addresses */ + { "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, + { "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA", ISC_FALSE }, + /* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */ + { "D.F.IP6.ARPA", ISC_FALSE }, + { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ + + { NULL, ISC_FALSE } +}; + +static const char *empty_dbtype[] = { "_builtin", "empty", NULL, NULL }; +static unsigned int empty_dbtypec = + (sizeof(empty_dbtype) / sizeof(empty_dbtype[0])); + static void fatal(const char *msg, isc_result_t result); @@ -724,6 +776,36 @@ disable_algorithms(cfg_obj_t *disabled, dns_resolver_t *resolver) { return (result); } +static isc_boolean_t +on_disable_list(cfg_obj_t *disablelist, dns_name_t *zonename) { + cfg_listelt_t *element; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + cfg_obj_t *value; + const char *str; + isc_buffer_t b; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + for (element = cfg_list_first(disablelist); + element != NULL; + element = cfg_list_next(element)) + { + value = cfg_listelt_value(element); + str = cfg_obj_asstring(value); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + result = dns_name_fromtext(name, &b, dns_rootname, + ISC_TRUE, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (dns_name_equal(name, zonename)) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + /* * Configure 'view' according to 'vconfig', taking defaults from 'config' * where values are missing in 'vconfig'. @@ -765,7 +847,14 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, dns_order_t *order = NULL; isc_uint32_t udpsize; unsigned int check = 0; + dns_zone_t *zone = NULL; isc_uint32_t max_clients_per_query; + const char *sep = ": view "; + const char *viewname = view->name; + const char *forview = " for view "; + isc_boolean_t rfc1918; + isc_boolean_t empty_zones_enable; + cfg_obj_t *disablelist = NULL; REQUIRE(DNS_VIEW_VALID(view)); @@ -791,6 +880,12 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, cfgmaps[i++] = config; cfgmaps[i] = NULL; + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + forview = ""; + } + /* * Set the view's port number for outgoing queries. */ @@ -1218,20 +1313,11 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, if (!view->recursion && view->recursionacl != NULL && (view->recursionacl->length != 1 || view->recursionacl->elements[0].type != dns_aclelementtype_any || - view->recursionacl->elements[0].negative != ISC_TRUE)) { - const char *forview = " for view "; - const char *viewname = view->name; - - if (!strcmp(view->name, "_bind") || - !strcmp(view->name, "_default")) { - forview = ""; - viewname = ""; - } + view->recursionacl->elements[0].negative != ISC_TRUE)) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "both \"recursion no;\" and \"allow-recursion\" " "active%s%s", forview, viewname); - } CHECK(configure_view_acl(vconfig, config, "sortlist", actx, ns_g_mctx, &view->sortlist)); @@ -1373,9 +1459,153 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, } else dns_view_setrootdelonly(view, ISC_FALSE); + /* + * Setup automatic empty zones. If recursion is off then + * they are disabled by default. + */ + obj = NULL; + (void)ns_config_get(maps, "empty-zones-enable", &obj); + (void)ns_config_get(maps, "disable-empty-zone", &disablelist); + if (obj == NULL && disablelist == NULL && + view->rdclass == dns_rdataclass_in) { + rfc1918 = ISC_FALSE; + empty_zones_enable = view->recursion; + } else if (view->rdclass == dns_rdataclass_in) { + rfc1918 = ISC_TRUE; + if (obj != NULL) + empty_zones_enable = cfg_obj_asboolean(obj); + else + empty_zones_enable = view->recursion; + } else { + rfc1918 = ISC_FALSE; + empty_zones_enable = ISC_FALSE; + } + if (empty_zones_enable) { + const char *empty; + int empty_zone = 0; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t buffer; + char *str; + char server[DNS_NAME_FORMATSIZE + 1]; + char contact[DNS_NAME_FORMATSIZE + 1]; + isc_boolean_t logit; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + + obj = NULL; + result = ns_config_get(maps, "empty-server", &obj); + if (result == ISC_R_SUCCESS) { + 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)); + isc_buffer_init(&buffer, server, sizeof(server) - 1); + CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); + server[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[2] = server; + } else + empty_dbtype[2] = "@"; + + obj = NULL; + result = ns_config_get(maps, "empty-contact", &obj); + if (result == ISC_R_SUCCESS) { + 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)); + isc_buffer_init(&buffer, contact, sizeof(contact) - 1); + CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); + contact[isc_buffer_usedlength(&buffer)] = 0; + empty_dbtype[3] = contact; + } else + empty_dbtype[3] = "."; + + logit = ISC_TRUE; + for (empty = empty_zones[empty_zone].zone; + empty != NULL; + empty = empty_zones[++empty_zone].zone) + { + dns_forwarders_t *forwarders = NULL; + + isc_buffer_init(&buffer, empty, strlen(empty)); + isc_buffer_add(&buffer, strlen(empty)); + /* + * Look for zone on drop list. + */ + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + if (disablelist != NULL && + on_disable_list(disablelist, name)) + continue; + + /* + * This zone already exists. + */ + (void)dns_view_findzone(view, name, &zone); + if (zone != NULL) { + dns_zone_detach(&zone); + continue; + } + + /* + * If we would forward this name don't add a + * empty zone for it. + */ + result = dns_fwdtable_find(view->fwdtable, name, + &forwarders); + if (result == ISC_R_SUCCESS && + forwarders->fwdpolicy == dns_fwdpolicy_only) + continue; + + if (!rfc1918 && empty_zones[empty_zone].rfc1918) { + if (logit) { + isc_log_write(ns_g_lctx, + NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, + ISC_LOG_WARNING, + "Warning%s%s: " + "'empty-zones-enable/" + "disable-empty-zone' " + "not set: disabling " + "RFC 1918 empty zones", + sep, viewname); + logit = ISC_FALSE; + } + continue; + } + + 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); + CHECK(dns_zone_setdbtype(zone, empty_dbtypec, + empty_dbtype)); + if (view->queryacl != NULL) + dns_zone_setqueryacl(zone, view->queryacl); + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, + ISC_TRUE); + CHECK(dns_view_addzone(view, zone)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "automatic empty zone%s%s: %s", + sep, viewname, empty); + dns_zone_detach(&zone); + } + } + result = ISC_R_SUCCESS; cleanup: + if (zone != NULL) + dns_zone_detach(&zone); if (dispatch4 != NULL) dns_dispatch_detach(&dispatch4); if (dispatch6 != NULL) @@ -2813,7 +3043,7 @@ load_configuration(const char *filename, ns_server_t *server, } else if (result == ISC_R_SUCCESS) { CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); } else { - result = setoptstring(server, &server->server_id, NULL); + result = setstring(server, &server->server_id, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); } diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 149dd062438..e7e263c8175 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -4445,6 +4445,10 @@ category notify { null; }; clients-per-query number ; max-clients-per-query number ; masterfile-format (text|raw) ; + empty-server name ; + empty-contact name ; + empty-zones-enable yes_or_no ; + disable-empty-zone zone_name ; }; @@ -7018,6 +7022,125 @@ query-source-v6 address * port *; + + Built-in Empty Zones + + Named has some built-in empty zones (SOA and NS records only). + These are for zones that should normally be answered locally + and which queries should not be sent to the Internet's root + servers. The offical servers which cover these namespaces + return NXDOMAIN responses to these queries. In particular + these cover the reverse namespace for addresses from RFC 1918 and + RFC 3330. They also include the reverse namespace for IPv6 local + address (locally assigned), IPv6 link local addresses, the IPv6 + loopback address and the IPv6 unknown addresss. + + + Named will attempt to determine if a built in zone already exists + or is active (covered by a forward-only forwarding declaration) + and will not not create a empty zone in that case. + + + The current list of empty zones is: + + 10.IN-ADDR.ARPA + 127.IN-ADDR.ARPA + 254.169.IN-ADDR.ARPA + 16.172.IN-ADDR.ARPA + 17.172.IN-ADDR.ARPA + 18.172.IN-ADDR.ARPA + 19.172.IN-ADDR.ARPA + 20.172.IN-ADDR.ARPA + 21.172.IN-ADDR.ARPA + 22.172.IN-ADDR.ARPA + 23.172.IN-ADDR.ARPA + 24.172.IN-ADDR.ARPA + 25.172.IN-ADDR.ARPA + 26.172.IN-ADDR.ARPA + 27.172.IN-ADDR.ARPA + 28.172.IN-ADDR.ARPA + 29.172.IN-ADDR.ARPA + 30.172.IN-ADDR.ARPA + 31.172.IN-ADDR.ARPA + 168.192.IN-ADDR.ARPA + 2.0.192.IN-ADDR.ARPA + 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA + 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA + D.F.IP6.ARPA + 8.E.F.IP6.ARPA + 9.E.F.IP6.ARPA + A.E.F.IP6.ARPA + B.E.F.IP6.ARPA + + + + Empty zones are settable at the view level and only apply to + views of class IN. Disabled empty zones are only inherited + from options if there are no disabled empty zones specified + at the view level. To override the options list of disabled + zones you can disable the root zone at the view level + (disable-empty-zone ".";). + + + If you are using the address ranges covered here you should + already have reverse zones covering the addresses you use. + In practice this appears to not be the case with many queries + being made to the infrustucture servers for names in these + spaces. So many in fact that sacrificial servers were needed + to be deployed to channel the query load away from the + infrustucture servers. + + + The real parent servers for these zones should disable all + empty zone under the parent zone they serve. For the real + root servers this is all built in empty zones. This will + enable them to return referrals to deeper in the tree. + + + + empty-server + + + Specify what server name will appear in the returned + SOA record for empty zones. If none is specified then + the zone's name will be used. + + + + + + empty-contact + + + Specify what contact name will appear in the returned + SOA record for empty zones. If none is specified then + "." will be used. + + + + + + empty-zones-enable + + + Enable / disable all empty zones. By default they + are enabled. + + + + + + disable-empty-zone + + + Disable a indiviual empty zones. By default none are + disabled. This option can be specified multiple times. + + + + + + The Statistics File diff --git a/lib/bind9/check.c b/lib/bind9/check.c index f6cc674c46a..e682f43db52 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: check.c,v 1.61 2005/07/28 05:42:20 marka Exp $ */ +/* $Id: check.c,v 1.62 2005/08/18 00:57:28 marka Exp $ */ /*! \file */ @@ -413,6 +413,10 @@ check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { cfg_obj_t *obj = NULL; cfg_listelt_t *element; isc_symtab_t *symtab = NULL; + dns_fixedname_t fixed; + const char *str; + dns_name_t *name; + isc_buffer_t b; static intervaltable intervals[] = { { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */ @@ -512,6 +516,9 @@ check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { } } + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + /* * Check the DLV zone name. */ @@ -526,16 +533,11 @@ check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { element != NULL; element = cfg_list_next(element)) { - dns_fixedname_t fixedname; - dns_name_t *name; const char *dlv; - isc_buffer_t b; obj = cfg_listelt_value(element); dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain")); - dns_fixedname_init(&fixedname); - name = dns_fixedname_name(&fixedname); isc_buffer_init(&b, dlv, strlen(dlv)); isc_buffer_add(&b, strlen(dlv)); tresult = dns_name_fromtext(name, &b, dns_rootname, @@ -568,7 +570,6 @@ check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { } dlv = cfg_obj_asstring(cfg_tuple_get(obj, "trust-anchor")); - dns_fixedname_init(&fixedname); isc_buffer_init(&b, dlv, strlen(dlv)); isc_buffer_add(&b, strlen(dlv)); tresult = dns_name_fromtext(name, &b, dns_rootname, @@ -608,6 +609,59 @@ check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { isc_symtab_destroy(&symtab); } + /* + * Check empty zone configuration. + */ + obj = NULL; + (void)cfg_map_get(options, "empty-server", &obj); + if (obj != NULL) { + str = cfg_obj_asstring(obj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, ISC_FALSE, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "empty-server: invalid name '%s'", str); + result = ISC_R_FAILURE; + } + } + + obj = NULL; + (void)cfg_map_get(options, "empty-contact", &obj); + if (obj != NULL) { + str = cfg_obj_asstring(obj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, ISC_FALSE, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "empty-contact: invalid name '%s'", str); + result = ISC_R_FAILURE; + } + } + + obj = NULL; + (void)cfg_map_get(options, "disable-empty-zone", &obj); + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + obj = cfg_listelt_value(element); + str = cfg_obj_asstring(obj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, + dns_rootname, ISC_FALSE, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "disable-empty-zone: invalid name '%s'", + str); + result = ISC_R_FAILURE; + } + } + return (result); } diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 7daa709d4f3..a70a9133719 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.135 2005/06/20 01:03:55 marka Exp $ */ +/* $Id: zone.h,v 1.136 2005/08/18 00:57:30 marka Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -59,6 +59,7 @@ typedef enum { #define DNS_ZONEOPT_CHECKMX 0x00004000U /*%< check-mx */ #define DNS_ZONEOPT_CHECKMXFAIL 0x00008000U /*%< fatal check-mx failures */ #define DNS_ZONEOPT_INTEGRITYCHECK 0x00010000U /*%< perform integrity checks */ +#define DNS_ZONEOPT_NOCHECKNS 0x00020000U /*%< disable IN NS address checks */ #ifndef NOMINUM_PUBLIC /* diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index b8594f76a32..fc6b290f691 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.c,v 1.51 2005/07/12 01:00:16 marka Exp $ */ +/* $Id: sdb.c,v 1.52 2005/08/18 00:57:29 marka Exp $ */ /*! \file */ @@ -267,10 +267,11 @@ dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) { static inline unsigned int initial_size(unsigned int len) { unsigned int size; - for (size = 64; size < (64 * 1024); size *= 2) + + for (size = 1024; size < (64 * 1024); size *= 2) if (len < size) return (size); - return (64 * 1024); + return (65535); } isc_result_t @@ -381,6 +382,8 @@ dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl, if (result != ISC_R_SUCCESS) goto failure; + if (size >= 65535) + size = 65535; p = isc_mem_get(mctx, size); if (p == NULL) { result = ISC_R_NOMEMORY; @@ -396,6 +399,11 @@ dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl, if (result != ISC_R_NOSPACE) break; + /* + * Is the RR too big? + */ + if (size >= 65535) + break; isc_mem_put(mctx, p, size); p = NULL; size *= 2; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 6b315114d06..ee708257372 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.443 2005/07/29 00:32:53 marka Exp $ */ +/* $Id: zone.c,v 1.444 2005/08/18 00:57:29 marka Exp $ */ /*! \file */ @@ -2004,6 +2004,9 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) { dns_name_t *foundname; int level; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS)) + return (ISC_TRUE); + if (zone->type == dns_zone_master) level = ISC_LOG_ERROR; else diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 309d6e79d19..ec04f808dcd 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.54 2005/07/18 05:59:01 marka Exp $ */ +/* $Id: namedconf.c,v 1.55 2005/08/18 00:57:31 marka Exp $ */ /*! \file */ @@ -409,8 +409,8 @@ static cfg_type_t cfg_type_forwardtype = { static const char *zonetype_enums[] = { "master", "slave", "stub", "hint", "forward", "delegation-only", NULL }; static cfg_type_t cfg_type_zonetype = { - "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, - &zonetype_enums + "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, &zonetype_enums }; static const char *loglevel_enums[] = { @@ -747,6 +747,10 @@ view_clauses[] = { { "max-acache-size", &cfg_type_sizenodefault, 0 }, { "clients-per-query", &cfg_type_uint32, 0 }, { "max-clients-per-query", &cfg_type_uint32, 0 }, + { "empty-server", &cfg_type_astring, 0 }, + { "empty-contact", &cfg_type_astring, 0 }, + { "empty-zones-enable", &cfg_type_boolean, 0 }, + { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } };