diff options
Diffstat (limited to 'bin/named/server.c')
-rw-r--r-- | bin/named/server.c | 762 |
1 files changed, 696 insertions, 66 deletions
diff --git a/bin/named/server.c b/bin/named/server.c index f29321e5..c40228ff 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.339.2.15.2.70 2006/05/24 04:30:24 marka Exp $ */ +/* $Id: server.c,v 1.419.18.45 2006/05/03 01:46:40 marka Exp $ */ + +/*! \file */ #include <config.h> @@ -41,13 +43,18 @@ #include <bind9/check.h> +#include <dns/acache.h> #include <dns/adb.h> #include <dns/cache.h> #include <dns/db.h> #include <dns/dispatch.h> +#ifdef DLZ +#include <dns/dlz.h> +#endif #include <dns/forward.h> #include <dns/journal.h> #include <dns/keytable.h> +#include <dns/lib.h> #include <dns/master.h> #include <dns/masterdump.h> #include <dns/order.h> @@ -86,7 +93,7 @@ #include <stdlib.h> #endif -/* +/*% * Check an operation for failure. Assumes that the function * using it has a 'result' variable and a 'cleanup' label. */ @@ -160,6 +167,54 @@ 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 void fatal(const char *msg, isc_result_t result); @@ -168,11 +223,11 @@ ns_server_reload(isc_task_t *task, isc_event_t *event); static isc_result_t ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, - ns_aclconfctx_t *actx, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, ns_listenelt_t **target); static isc_result_t ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, - ns_aclconfctx_t *actx, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, ns_listenlist_t **target); static isc_result_t @@ -186,19 +241,19 @@ 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, - ns_aclconfctx_t *aclconf); + cfg_aclconfctx_t *aclconf); static void end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); -/* +/*% * Configure a single view ACL at '*aclp'. Get its configuration by * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' * (for a global default). */ static isc_result_t configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, - const char *aclname, ns_aclconfctx_t *actx, + const char *aclname, cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp) { isc_result_t result; @@ -225,7 +280,8 @@ configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, */ return (ISC_R_SUCCESS); - result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp); + result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, + actx, mctx, aclp); return (result); } @@ -326,7 +382,7 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, return (result); } -/* +/*% * Configure DNSSEC keys for a view. Currently used only for * the security roots. * @@ -414,7 +470,7 @@ mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) return (result); } -/* +/*% * Get a dispatch appropriate for the resolver of a given view. */ static isc_result_t @@ -581,15 +637,14 @@ configure_order(dns_order_t *order, const cfg_obj_t *ent) { static isc_result_t configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { - const isc_sockaddr_t *sa; isc_netaddr_t na; dns_peer_t *peer; const cfg_obj_t *obj; const char *str; isc_result_t result; + unsigned int prefixlen; - sa = cfg_obj_assockaddr(cfg_map_getname(cpeer)); - isc_netaddr_fromsockaddr(&na, sa); + cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); peer = NULL; result = dns_peer_new(mctx, &na, &peer); @@ -617,6 +672,28 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); obj = NULL; + (void)cfg_map_get(cpeer, "edns-udp-size", &obj); + if (obj != NULL) { + isc_uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); + } + + obj = NULL; + (void)cfg_map_get(cpeer, "max-udp-size", &obj); + if (obj != NULL) { + isc_uint32_t udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); + } + + obj = NULL; (void)cfg_map_get(cpeer, "transfers", &obj); if (obj != NULL) CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); @@ -644,7 +721,7 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { } obj = NULL; - if (isc_sockaddr_pf(sa) == AF_INET) + if (na.family == AF_INET) (void)cfg_map_get(cpeer, "transfer-source", &obj); else (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); @@ -653,7 +730,35 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { cfg_obj_assockaddr(obj)); if (result != ISC_R_SUCCESS) goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); } + + obj = NULL; + if (na.family == AF_INET) + (void)cfg_map_get(cpeer, "notify-source", &obj); + else + (void)cfg_map_get(cpeer, "notify-source-v6", &obj); + if (obj != NULL) { + result = dns_peer_setnotifysource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + } + + obj = NULL; + if (na.family == AF_INET) + (void)cfg_map_get(cpeer, "query-source", &obj); + else + (void)cfg_map_get(cpeer, "query-source-v6", &obj); + if (obj != NULL) { + result = dns_peer_setquerysource(peer, + cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); + } + *peerp = peer; return (ISC_R_SUCCESS); @@ -708,6 +813,68 @@ disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { return (result); } +static isc_boolean_t +on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { + const cfg_listelt_t *element; + dns_fixedname_t fixed; + dns_name_t *name; + isc_result_t result; + const 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); +} + +static void +check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, + isc_mem_t *mctx) +{ + char **argv = NULL; + unsigned int i; + isc_result_t result; + + result = dns_zone_getdbtype(*zonep, &argv, mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_detach(zonep); + return; + } + + /* + * Check that all the arguments match. + */ + for (i = 0; i < dbtypec; i++) + if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { + dns_zone_detach(zonep); + break; + } + + /* + * Check that there are not extra arguments. + */ + if (i == dbtypec && argv[i] != NULL) + dns_zone_detach(zonep); + isc_mem_free(mctx, argv); +} + + /* * Configure 'view' according to 'vconfig', taking defaults from 'config' * where values are missing in 'vconfig'. @@ -717,8 +884,8 @@ disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { */ static isc_result_t configure_view(dns_view_t *view, const cfg_obj_t *config, - const cfg_obj_t *vconfig, isc_mem_t *mctx, ns_aclconfctx_t *actx, - isc_boolean_t need_hints) + const cfg_obj_t *vconfig, 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]; @@ -728,6 +895,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *forwarders; const cfg_obj_t *alternates; const cfg_obj_t *zonelist; +#ifdef DLZ + const cfg_obj_t *dlz; + unsigned int dlzargc; + char **dlzargv; +#endif const cfg_obj_t *disabled; const cfg_obj_t *obj; const cfg_listelt_t *element; @@ -736,6 +908,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, isc_result_t result; isc_uint32_t max_adb_size; isc_uint32_t max_cache_size; + isc_uint32_t max_acache_size; isc_uint32_t lame_ttl; dns_tsig_keyring_t *ring; dns_view_t *pview = NULL; /* Production view */ @@ -748,6 +921,14 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, 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; + const cfg_obj_t *disablelist = NULL; REQUIRE(DNS_VIEW_VALID(view)); @@ -773,6 +954,12 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, cfgmaps[i++] = config; cfgmaps[i] = NULL; + if (!strcmp(viewname, "_default")) { + sep = ""; + viewname = ""; + forview = ""; + } + /* * Set the view's port number for outgoing queries. */ @@ -780,6 +967,52 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_view_setdstport(view, port); /* + * Create additional cache for this view and zones under the view + * if explicitly enabled. + * XXX950 default to on. + */ + obj = NULL; + (void)ns_config_get(maps, "acache-enable", &obj); + if (obj != NULL && cfg_obj_asboolean(obj)) { + cmctx = NULL; + CHECK(isc_mem_create(0, 0, &cmctx)); + CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, + ns_g_timermgr)); + isc_mem_detach(&cmctx); + } + if (view->acache != NULL) { + obj = NULL; + result = ns_config_get(maps, "acache-cleaning-interval", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_acache_setcleaninginterval(view->acache, + cfg_obj_asuint32(obj) * 60); + + obj = NULL; + result = ns_config_get(maps, "max-acache-size", &obj); + INSIST(result == ISC_R_SUCCESS); + if (cfg_obj_isstring(obj)) { + str = cfg_obj_asstring(obj); + INSIST(strcasecmp(str, "unlimited") == 0); + max_acache_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-acache-size " + "%" ISC_PRINT_QUADFORMAT + "d' is too large", + value); + result = ISC_R_RANGE; + goto cleanup; + } + max_acache_size = (isc_uint32_t)value; + } + dns_acache_setcachesize(view->acache, max_acache_size); + } + + /* * Configure the zones. */ zonelist = NULL; @@ -796,6 +1029,45 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, actx)); } +#ifdef DLZ + /* + * Create Dynamically Loadable Zone driver. + */ + dlz = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "dlz", &dlz); + else + (void)cfg_map_get(config, "dlz", &dlz); + + obj = NULL; + if (dlz != NULL) { + (void)cfg_map_get(cfg_tuple_get(dlz, "options"), + "database", &obj); + if (obj != NULL) { + char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); + if (s == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); + if (result != ISC_R_SUCCESS) { + isc_mem_free(mctx, s); + goto cleanup; + } + + obj = cfg_tuple_get(dlz, "name"); + result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), + dlzargv[0], dlzargc, dlzargv, + &view->dlzdatabase); + isc_mem_free(mctx, s); + isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); + if (result == ISC_R_SUCCESS) + goto cleanup; + } + } +#endif + /* * Configure the view's cache. Try to reuse an existing * cache if possible, otherwise create a new cache. @@ -931,6 +1203,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (lame_ttl > 1800) lame_ttl = 1800; dns_resolver_setlamettl(view->resolver, lame_ttl); + + obj = NULL; + result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj)); /* * Set the resolver's EDNS UDP size. @@ -946,6 +1223,19 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); /* + * Set the maximum UDP response size. + */ + obj = NULL; + result = ns_config_get(maps, "max-udp-size", &obj); + INSIST(result == ISC_R_SUCCESS); + udpsize = cfg_obj_asuint32(obj); + if (udpsize < 512) + udpsize = 512; + if (udpsize > 4096) + udpsize = 4096; + view->maxudp = udpsize; + + /* * Set supported DNSSEC algorithms. */ dns_resolver_reset_algorithms(view->resolver); @@ -1138,8 +1428,12 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, view->additionalfromcache = ISC_TRUE; } - CHECK(configure_view_acl(vconfig, config, "allow-query", + CHECK(configure_view_acl(vconfig, config, "allow-query-cache", actx, ns_g_mctx, &view->queryacl)); + if (view->queryacl == NULL) + CHECK(configure_view_acl(NULL, ns_g_defaults, + "allow-query-cache", actx, + ns_g_mctx, &view->queryacl)); if (strcmp(view->name, "_bind") != 0) CHECK(configure_view_acl(vconfig, config, "allow-recursion", @@ -1152,20 +1446,18 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, 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); - } + + /* + * Set default "allow-recursion" acl. + */ + if (view->recursionacl == NULL && view->recursion) + CHECK(configure_view_acl(NULL, ns_g_defaults, "allow-recursion", + actx, ns_g_mctx, &view->recursionacl)); CHECK(configure_view_acl(vconfig, config, "sortlist", actx, ns_g_mctx, &view->sortlist)); @@ -1179,6 +1471,18 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, result = ns_config_get(maps, "provide-ixfr", &obj); INSIST(result == ISC_R_SUCCESS); view->provideixfr = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "max-clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + max_clients_per_query = cfg_obj_asuint32(obj); + + obj = NULL; + result = ns_config_get(maps, "clients-per-query", &obj); + INSIST(result == ISC_R_SUCCESS); + dns_resolver_setclientsperquery(view->resolver, + cfg_obj_asuint32(obj), + max_clients_per_query); obj = NULL; result = ns_config_get(maps, "dnssec-enable", &obj); @@ -1186,6 +1490,16 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, view->enablednssec = cfg_obj_asboolean(obj); obj = NULL; + result = ns_config_get(maps, "dnssec-accept-expired", &obj); + INSIST(result == ISC_R_SUCCESS); + view->acceptexpired = cfg_obj_asboolean(obj); + + obj = NULL; + result = ns_config_get(maps, "dnssec-validation", &obj); + INSIST(result == ISC_R_SUCCESS); + view->enablevalidation = cfg_obj_asboolean(obj); + + obj = NULL; result = ns_config_get(maps, "dnssec-lookaside", &obj); if (result == ISC_R_SUCCESS) { for (element = cfg_list_first(obj); @@ -1239,6 +1553,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, result = ns_config_get(maps, "dnssec-must-be-secure", &obj); if (result == ISC_R_SUCCESS) CHECK(mustbesecure(obj, view->resolver)); + } else { + if (view->secroots != NULL) + dns_keytable_detach(&view->secroots); + dns_resolver_resetmustbesecure(view->resolver); } obj = NULL; @@ -1295,9 +1613,180 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } 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; + const char *str; + char server[DNS_NAME_FORMATSIZE + 1]; + char contact[DNS_NAME_FORMATSIZE + 1]; + isc_boolean_t logit; + const char *empty_dbtype[4] = + { "_builtin", "empty", NULL, NULL }; + int empty_dbtypec = 4; + + 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; + dns_view_t *pview = 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; + } + + /* + * See if we can re-use a existing zone. + */ + 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) { + (void)dns_view_findzone(pview, name, &zone); + dns_view_detach(&pview); + if (zone != NULL) + check_dbtype(&zone, empty_dbtypec, + empty_dbtype, mctx); + if (zone != NULL) { + dns_zone_setview(zone, view); + dns_zone_detach(&zone); + 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) @@ -1563,7 +2052,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, - ns_aclconfctx_t *aclconf) + cfg_aclconfctx_t *aclconf) { dns_view_t *pview = NULL; /* Production view */ dns_zone_t *zone = NULL; /* New or reused zone */ @@ -1728,10 +2217,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, result = dns_view_findzone(pview, origin, &zone); if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) goto cleanup; - if (zone != NULL) { - if (! ns_zone_reusable(zone, zconfig)) - dns_zone_detach(&zone); - } + if (zone != NULL && !ns_zone_reusable(zone, zconfig)) + dns_zone_detach(&zone); if (zone != NULL) { /* @@ -1739,6 +2226,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, * new view. */ dns_zone_setview(zone, view); + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); } else { /* * We cannot reuse an existing zone, we have @@ -1747,6 +2236,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, CHECK(dns_zone_create(&zone, mctx)); CHECK(dns_zone_setorigin(zone, origin)); dns_zone_setview(zone, view); + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); } @@ -2020,6 +2511,21 @@ heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { } } +static void +pps_timer_tick(isc_task_t *task, isc_event_t *event) { + static unsigned int oldrequests = 0; + unsigned int requests = ns_client_requests; + + UNUSED(task); + isc_event_free(&event); + + /* + * Don't worry about wrapping as the overflow result will be right. + */ + dns_pps = (requests - oldrequests) / 1200; + oldrequests = requests; +} + /* * Replace the current value of '*field', a dynamically allocated * string or NULL, with a dynamically allocated copy of the @@ -2122,10 +2628,36 @@ portlist_fromconf(dns_portlist_t *portlist, unsigned int family, } static isc_result_t +removed(dns_zone_t *zone, void *uap) { + const char *type; + + if (dns_zone_getview(zone) != uap) + return (ISC_R_SUCCESS); + + switch (dns_zone_gettype(zone)) { + case dns_zone_master: + type = "master"; + break; + case dns_zone_slave: + type = "slave"; + break; + case dns_zone_stub: + type = "stub"; + break; + default: + type = "other"; + break; + } + dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); + return (ISC_R_SUCCESS); +} + +static isc_result_t load_configuration(const char *filename, ns_server_t *server, isc_boolean_t first_time) { isc_result_t result; + isc_interval_t interval; cfg_parser_t *parser = NULL; cfg_obj_t *config; const cfg_obj_t *options; @@ -2139,14 +2671,14 @@ load_configuration(const char *filename, ns_server_t *server, dns_view_t *view_next; dns_viewlist_t viewlist; dns_viewlist_t tmpviewlist; - ns_aclconfctx_t aclconfctx; + cfg_aclconfctx_t aclconfctx; isc_uint32_t interface_interval; isc_uint32_t heartbeat_interval; isc_uint32_t udpsize; in_port_t listen_port; int i; - ns_aclconfctx_init(&aclconfctx); + cfg_aclconfctx_init(&aclconfctx); ISC_LIST_INIT(viewlist); /* Ensure exclusive access to configuration data. */ @@ -2401,7 +2933,6 @@ load_configuration(const char *filename, ns_server_t *server, isc_timertype_inactive, NULL, NULL, ISC_TRUE)); } else if (server->interface_interval != interface_interval) { - isc_interval_t interval; isc_interval_set(&interval, interface_interval, 0); CHECK(isc_timer_reset(server->interface_timer, isc_timertype_ticker, @@ -2421,13 +2952,16 @@ load_configuration(const char *filename, ns_server_t *server, isc_timertype_inactive, NULL, NULL, ISC_TRUE)); } else if (server->heartbeat_interval != heartbeat_interval) { - isc_interval_t interval; isc_interval_set(&interval, heartbeat_interval, 0); CHECK(isc_timer_reset(server->heartbeat_timer, isc_timertype_ticker, NULL, &interval, ISC_FALSE)); } server->heartbeat_interval = heartbeat_interval; + + isc_interval_set(&interval, 1200, 0); + CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, + &interval, ISC_FALSE)); /* * Configure and freeze all explicit views. Explicit @@ -2716,7 +3250,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); } @@ -2731,7 +3265,7 @@ load_configuration(const char *filename, ns_server_t *server, result = ISC_R_SUCCESS; cleanup: - ns_aclconfctx_destroy(&aclconfctx); + cfg_aclconfctx_destroy(&aclconfctx); if (parser != NULL) { if (config != NULL) @@ -2752,8 +3286,11 @@ load_configuration(const char *filename, ns_server_t *server, view = view_next) { view_next = ISC_LIST_NEXT(view, link); ISC_LIST_UNLINK(viewlist, view, link); + if (result == ISC_R_SUCCESS && + strcmp(view->name, "_bind") != 0) + (void)dns_zt_apply(view->zonetable, ISC_FALSE, + removed, view); dns_view_detach(&view); - } /* @@ -2860,6 +3397,11 @@ run_server(isc_task_t *task, isc_event_t *event) { server, &server->heartbeat_timer), "creating heartbeat timer"); + CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, + NULL, NULL, server->task, pps_timer_tick, + server, &server->pps_timer), + "creating pps timer"); + CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), "creating default configuration parser"); @@ -2924,6 +3466,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { isc_timer_detach(&server->interface_timer); isc_timer_detach(&server->heartbeat_timer); + isc_timer_detach(&server->pps_timer); ns_interfacemgr_shutdown(server->interfacemgr); ns_interfacemgr_detach(&server->interfacemgr); @@ -3012,6 +3555,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->interface_timer = NULL; server->heartbeat_timer = NULL; + server->pps_timer = NULL; server->interface_interval = 0; server->heartbeat_interval = 0; @@ -3454,35 +3998,49 @@ ns_server_reconfigcommand(ns_server_t *server, char *args) { } /* + * Act on a "notify" command from the command channel. + */ +isc_result_t +ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result; + dns_zone_t *zone = NULL; + const unsigned char msg[] = "zone notify queued"; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + + dns_zone_notify(zone); + dns_zone_detach(&zone); + if (sizeof(msg) <= isc_buffer_availablelength(text)) + isc_buffer_putmem(text, msg, sizeof(msg)); + + return (ISC_R_SUCCESS); +} + +/* * Act on a "refresh" command from the command channel. */ isc_result_t ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { isc_result_t result; dns_zone_t *zone = NULL; - const unsigned char msg1[] = "zone refresh queued"; - const unsigned char msg2[] = "not a slave or stub zone"; - dns_zonetype_t type; + const unsigned char msg[] = "zone refresh queued"; result = zone_from_args(server, args, &zone); if (result != ISC_R_SUCCESS) return (result); if (zone == NULL) return (ISC_R_UNEXPECTEDEND); - - type = dns_zone_gettype(zone); - if (type == dns_zone_slave || type == dns_zone_stub) { - dns_zone_refresh(zone); - dns_zone_detach(&zone); - if (sizeof(msg1) <= isc_buffer_availablelength(text)) - isc_buffer_putmem(text, msg1, sizeof(msg1)); - return (ISC_R_SUCCESS); - } - + + dns_zone_refresh(zone); dns_zone_detach(&zone); - if (sizeof(msg2) <= isc_buffer_availablelength(text)) - isc_buffer_putmem(text, msg2, sizeof(msg2)); - return (ISC_R_FAILURE); + if (sizeof(msg) <= isc_buffer_availablelength(text)) + isc_buffer_putmem(text, msg, sizeof(msg)); + + return (ISC_R_SUCCESS); } isc_result_t @@ -3498,7 +4056,7 @@ ns_server_togglequerylog(ns_server_t *server) { static isc_result_t ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, - ns_aclconfctx_t *actx, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, ns_listenlist_t **target) { isc_result_t result; @@ -3537,7 +4095,7 @@ ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, */ static isc_result_t ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, - ns_aclconfctx_t *actx, + cfg_aclconfctx_t *actx, isc_mem_t *mctx, ns_listenelt_t **target) { isc_result_t result; @@ -3569,8 +4127,8 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, if (result != ISC_R_SUCCESS) return (result); - result = ns_acl_fromconfig(cfg_tuple_get(listener, "acl"), - config, actx, mctx, &delt->acl); + result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), + config, ns_g_lctx, actx, mctx, &delt->acl); if (result != ISC_R_SUCCESS) { ns_listenelt_destroy(delt); return (result); @@ -3951,6 +4509,59 @@ ns_server_setdebuglevel(ns_server_t *server, char *args) { } isc_result_t +ns_server_validation(ns_server_t *server, char *args) { + char *ptr, *viewname; + dns_view_t *view; + isc_boolean_t changed = ISC_FALSE; + isc_result_t result; + isc_boolean_t enable; + + /* Skip the command name. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + /* Find out what we are to do. */ + ptr = next_token(&args, " \t"); + if (ptr == NULL) + return (ISC_R_UNEXPECTEDEND); + + if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || + !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) + enable = ISC_TRUE; + else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || + !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) + enable = ISC_FALSE; + else + return (DNS_R_SYNTAX); + + /* Look for the view name. */ + viewname = next_token(&args, " \t"); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + if (viewname != NULL && strcasecmp(viewname, view->name) != 0) + continue; + result = dns_view_flushcache(view); + if (result != ISC_R_SUCCESS) + goto out; + view->enablevalidation = enable; + changed = ISC_TRUE; + } + if (changed) + result = ISC_R_SUCCESS; + else + result = ISC_R_FAILURE; + out: + isc_task_endexclusive(server->task); + return (result); +} + +isc_result_t ns_server_flushcache(ns_server_t *server, char *args) { char *ptr, *viewname; dns_view_t *view; @@ -4059,12 +4670,13 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { "xfers deferred: %u\n" "soa queries in progress: %u\n" "query logging is %s\n" - "recursive clients: %d/%d\n" + "recursive clients: %d/%d/%d\n" "tcp clients: %d/%d\n" "server is up and running", zonecount, ns_g_debuglevel, xferrunning, xferdeferred, soaqueries, server->log_queries ? "ON" : "OFF", - server->recursionquota.used, server->recursionquota.max, + server->recursionquota.used, server->recursionquota.soft, + server->recursionquota.max, server->tcpquota.used, server->tcpquota.max); if (n >= isc_buffer_availablelength(text)) return (ISC_R_NOSPACE); @@ -4073,11 +4685,11 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { } /* - * Act on a "freeze" or "unfreeze" command from the command channel. + * Act on a "freeze" or "thaw" command from the command channel. */ isc_result_t ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { - isc_result_t result; + isc_result_t result, tresult; dns_zone_t *zone = NULL; dns_zonetype_t type; char classstr[DNS_RDATACLASS_FORMATSIZE]; @@ -4090,8 +4702,26 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { result = zone_from_args(server, args, &zone); if (result != ISC_R_SUCCESS) return (result); - if (zone == NULL) - return (ISC_R_UNEXPECTEDEND); + if (zone == NULL) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + tresult = ISC_R_SUCCESS; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + result = dns_view_freezezones(view, freeze); + if (result != ISC_R_SUCCESS && + tresult == ISC_R_SUCCESS) + tresult = result; + } + isc_task_endexclusive(server->task); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s all zones: %s", + freeze ? "freezing" : "thawing", + isc_result_totext(tresult)); + return (tresult); + } type = dns_zone_gettype(zone); if (type != dns_zone_master) { dns_zone_detach(&zone); @@ -4137,7 +4767,7 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_INFO, "%s zone '%s/%s'%s%s: %s", - freeze ? "freezing" : "unfreezing", + freeze ? "freezing" : "thawing", zonename, classstr, sep, vname, isc_result_totext(result)); dns_zone_detach(&zone); |