/contrib/bind9/bin/named/server.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 7648 lines · 5910 code · 887 blank · 851 comment · 1790 complexity · 0d51a127a90e8c0853cc6539ac9d6bce MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 1999-2003 Internet Software Consortium.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- /* $Id: server.c,v 1.599.8.19 2012/02/22 00:33:32 each Exp $ */
- /*! \file */
- #include <config.h>
- #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>
- #include <isc/dir.h>
- #include <isc/entropy.h>
- #include <isc/file.h>
- #include <isc/hash.h>
- #include <isc/httpd.h>
- #include <isc/lex.h>
- #include <isc/parseint.h>
- #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>
- #include <isc/task.h>
- #include <isc/timer.h>
- #include <isc/util.h>
- #include <isc/xml.h>
- #include <isccfg/namedconf.h>
- #include <bind9/check.h>
- #include <dns/acache.h>
- #include <dns/adb.h>
- #include <dns/cache.h>
- #include <dns/db.h>
- #include <dns/dispatch.h>
- #include <dns/dlz.h>
- #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>
- #include <dns/order.h>
- #include <dns/peer.h>
- #include <dns/portlist.h>
- #include <dns/rbt.h>
- #include <dns/rdataclass.h>
- #include <dns/rdataset.h>
- #include <dns/rdatastruct.h>
- #include <dns/resolver.h>
- #include <dns/rootns.h>
- #include <dns/secalg.h>
- #include <dns/stats.h>
- #include <dns/tkey.h>
- #include <dns/tsig.h>
- #include <dns/view.h>
- #include <dns/zone.h>
- #include <dns/zt.h>
- #include <dst/dst.h>
- #include <dst/result.h>
- #include <named/client.h>
- #include <named/config.h>
- #include <named/control.h>
- #include <named/interfacemgr.h>
- #include <named/log.h>
- #include <named/logconf.h>
- #include <named/lwresd.h>
- #include <named/main.h>
- #include <named/os.h>
- #include <named/server.h>
- #include <named/statschannel.h>
- #include <named/tkeyconf.h>
- #include <named/tsigconf.h>
- #include <named/zoneconf.h>
- #ifdef HAVE_LIBSCF
- #include <named/ns_smf_globals.h>
- #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.
- */
- #define CHECK(op) \
- do { result = (op); \
- if (result != ISC_R_SUCCESS) goto cleanup; \
- } while (0)
- #define CHECKM(op, msg) \
- do { result = (op); \
- if (result != ISC_R_SUCCESS) { \
- isc_log_write(ns_g_lctx, \
- NS_LOGCATEGORY_GENERAL, \
- NS_LOGMODULE_SERVER, \
- ISC_LOG_ERROR, \
- "%s: %s", msg, \
- isc_result_totext(result)); \
- goto cleanup; \
- } \
- } while (0) \
- #define CHECKMF(op, msg, file) \
- do { result = (op); \
- if (result != ISC_R_SUCCESS) { \
- isc_log_write(ns_g_lctx, \
- NS_LOGCATEGORY_GENERAL, \
- NS_LOGMODULE_SERVER, \
- ISC_LOG_ERROR, \
- "%s '%s': %s", msg, file, \
- isc_result_totext(result)); \
- goto cleanup; \
- } \
- } while (0) \
- #define CHECKFATAL(op, msg) \
- do { result = (op); \
- if (result != ISC_R_SUCCESS) \
- 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;
- dns_dispatch_t *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;
- isc_boolean_t dumpzones;
- FILE *fp;
- ISC_LIST(struct viewlistentry) viewlist;
- struct viewlistentry *view;
- struct zonelistentry *zone;
- dns_dumpctx_t *mdctx;
- dns_db_t *db;
- dns_db_t *cache;
- isc_task_t *task;
- dns_dbversion_t *version;
- };
- struct viewlistentry {
- dns_view_t *view;
- ISC_LINK(struct viewlistentry) link;
- ISC_LIST(struct zonelistentry) zonelist;
- };
- struct zonelistentry {
- dns_zone_t *zone;
- 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_parser_t * parser;
- cfg_obj_t * config;
- cfg_parser_t * nzparser;
- cfg_obj_t * nzconfig;
- cfg_aclconfctx_t * actx;
- };
- /*
- * These zones should not leak onto the Internet.
- */
- static const struct {
- const char *zone;
- isc_boolean_t rfc1918;
- } empty_zones[] = {
- /* 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 },
- /* RFC 5735 and RFC 5737 */
- { "0.IN-ADDR.ARPA", ISC_FALSE }, /* THIS NETWORK */
- { "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 */
- { "100.51.198.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET 2 */
- { "113.0.203.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET 3 */
- { "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 ADDRESS 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 */
- /* Example Prefix, RFC 3849. */
- { "8.B.D.0.1.0.0.2.IP6.ARPA", ISC_FALSE },
- { NULL, ISC_FALSE }
- };
- 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);
- static isc_result_t
- ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
- 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,
- cfg_aclconfctx_t *actx,
- isc_mem_t *mctx, ns_listenlist_t **target);
- static isc_result_t
- configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
- const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
- static isc_result_t
- configure_alternates(const cfg_obj_t *config, dns_view_t *view,
- const cfg_obj_t *alternates);
- 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, 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
- newzone_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, 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];
- const cfg_obj_t *aclobj = NULL;
- int i = 0;
- if (*aclp != NULL)
- dns_acl_detach(aclp);
- 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, aclname, &aclobj);
- if (aclobj == NULL)
- /*
- * No value available. *aclp == NULL.
- */
- 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
- * nest_level value of 2.
- */
- static isc_result_t
- configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
- cfg_aclconfctx_t *actx, isc_mem_t *mctx,
- dns_acl_t **aclp)
- {
- isc_result_t result;
- const cfg_obj_t *maps[3];
- const cfg_obj_t *aclobj = NULL;
- int i = 0;
- if (*aclp != NULL)
- dns_acl_detach(aclp);
- 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, "sortlist", &aclobj);
- if (aclobj == NULL)
- return (ISC_R_SUCCESS);
- /*
- * Use a nest level of 3 for the "top level" of the sortlist;
- * this means each entry in the top three levels will be stored
- * as lists of separate, nested ACLs, rather than merged together
- * into IP tables as is usually done with ACLs.
- */
- result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
- actx, mctx, 3, aclp);
- return (result);
- }
- static isc_result_t
- 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;
- isc_uint32_t flags, proto, alg;
- const char *keystr, *keynamestr;
- unsigned char keydata[4096];
- isc_buffer_t keydatabuf;
- unsigned char rrdata[4096];
- isc_buffer_t rrdatabuf;
- isc_region_t r;
- dns_fixedname_t fkeyname;
- dns_name_t *keyname;
- isc_buffer_t namebuf;
- 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 {
- const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
- CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
- &viewclass));
- }
- keystruct.common.rdclass = viewclass;
- keystruct.common.rdtype = dns_rdatatype_dnskey;
- /*
- * The key data in keystruct is not dynamically allocated.
- */
- keystruct.mctx = NULL;
- ISC_LINK_INIT(&keystruct.common, link);
- if (flags > 0xffff)
- CHECKM(ISC_R_RANGE, "key flags");
- if (proto > 0xff)
- CHECKM(ISC_R_RANGE, "key protocol");
- if (alg > 0xff)
- CHECKM(ISC_R_RANGE, "key algorithm");
- keystruct.flags = (isc_uint16_t)flags;
- keystruct.protocol = (isc_uint8_t)proto;
- keystruct.algorithm = (isc_uint8_t)alg;
- isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
- isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
- keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
- CHECK(isc_base64_decodestring(keystr, &keydatabuf));
- isc_buffer_usedregion(&keydatabuf, &r);
- keystruct.datalen = r.length;
- keystruct.data = r.base;
- if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
- 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,
- "%s key '%s' has a weak exponent",
- managed ? "managed" : "trusted",
- keynamestr);
- CHECK(dns_rdata_fromstruct(NULL,
- keystruct.common.rdclass,
- keystruct.common.rdtype,
- &keystruct, &rrdatabuf));
- 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, 0, NULL));
- CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
- mctx, &dstkey));
- *target = dstkey;
- return (ISC_R_SUCCESS);
- cleanup:
- if (result == DST_R_NOCRYPTO) {
- cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
- "ignoring %s key for '%s': no crypto support",
- managed ? "managed" : "trusted",
- keynamestr);
- } 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 %s key for '%s': %s",
- managed ? "managed" : "trusted",
- keynamestr, isc_result_totext(result));
- result = ISC_R_FAILURE;
- }
- if (dstkey != NULL)
- dst_key_free(&dstkey);
- 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.
- *
- * The per-view configuration values and the server-global defaults are read
- * from 'vconfig' and 'config'.
- */
- static isc_result_t
- 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 = 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_obj_t *options = NULL;
- const cfg_obj_t *obj = NULL;
- const char *directory;
- int i = 0;
- /* 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) {
- 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;
- }
- }
- 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;
- }
- }
- 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));
- }
- if (auto_root && 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 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) {
- const cfg_listelt_t *element;
- const cfg_obj_t *obj;
- const char *str;
- dns_fixedname_t fixed;
- dns_name_t *name;
- isc_boolean_t value;
- isc_result_t result;
- isc_buffer_t b;
- dns_fixedname_init(&fixed);
- name = dns_fixedname_name(&fixed);
- for (element = cfg_list_first(mbs);
- element != NULL;
- element = cfg_list_next(element))
- {
- obj = cfg_listelt_value(element);
- 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, 0, NULL));
- value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
- CHECK(dns_resolver_setmustbesecure(resolver, name, value));
- }
- result = ISC_R_SUCCESS;
- cleanup:
- return (result);
- }
- /*%
- * Get a dispatch appropriate for the resolver of a given view.
- */
- static isc_result_t
- get_view_querysource_dispatch(const cfg_obj_t **maps,
- int af, dns_dispatch_t **dispatchp,
- isc_boolean_t is_firstview)
- {
- isc_result_t result = ISC_R_FAILURE;
- dns_dispatch_t *disp;
- isc_sockaddr_t sa;
- unsigned int attrs, attrmask;
- const cfg_obj_t *obj = NULL;
- unsigned int maxdispatchbuffers;
- switch (af) {
- case AF_INET:
- result = ns_config_get(maps, "query-source", &obj);
- INSIST(result == ISC_R_SUCCESS);
- break;
- case AF_INET6:
- result = ns_config_get(maps, "query-source-v6", &obj);
- INSIST(result == ISC_R_SUCCESS);
- break;
- default:
- INSIST(0);
- }
- sa = *(cfg_obj_assockaddr(obj));
- INSIST(isc_sockaddr_pf(&sa) == af);
- /*
- * If we don't support this address family, we're done!
- */
- switch (af) {
- case AF_INET:
- result = isc_net_probeipv4();
- break;
- case AF_INET6:
- result = isc_net_probeipv6();
- break;
- default:
- INSIST(0);
- }
- if (result != ISC_R_SUCCESS)
- return (ISC_R_SUCCESS);
- /*
- * Try to find a dispatcher that we can share.
- */
- attrs = 0;
- attrs |= DNS_DISPATCHATTR_UDP;
- switch (af) {
- case AF_INET:
- attrs |= DNS_DISPATCHATTR_IPV4;
- break;
- case AF_INET6:
- attrs |= DNS_DISPATCHATTR_IPV6;
- break;
- }
- if (isc_sockaddr_getport(&sa) == 0) {
- attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
- maxdispatchbuffers = 4096;
- } else {
- INSIST(obj != NULL);
- if (is_firstview) {
- cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
- "using specific query-source port "
- "suppresses port randomization and can be "
- "insecure.");
- }
- maxdispatchbuffers = 1000;
- }
- attrmask = 0;
- attrmask |= DNS_DISPATCHATTR_UDP;
- attrmask |= DNS_DISPATCHATTR_TCP;
- attrmask |= DNS_DISPATCHATTR_IPV4;
- attrmask |= DNS_DISPATCHATTR_IPV6;
- disp = NULL;
- result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
- ns_g_taskmgr, &sa, 4096,
- maxdispatchbuffers, 32768, 16411, 16433,
- attrs, attrmask, &disp);
- if (result != ISC_R_SUCCESS) {
- isc_sockaddr_t any;
- char buf[ISC_SOCKADDR_FORMATSIZE];
- switch (af) {
- case AF_INET:
- isc_sockaddr_any(&any);
- break;
- case AF_INET6:
- isc_sockaddr_any6(&any);
- break;
- }
- if (isc_sockaddr_equal(&sa, &any))
- return (ISC_R_SUCCESS);
- isc_sockaddr_format(&sa, buf, sizeof(buf));
- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
- NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
- "could not get query source dispatcher (%s)",
- buf);
- return (result);
- }
- *dispatchp = disp;
- return (ISC_R_SUCCESS);
- }
- static isc_result_t
- configure_order(dns_order_t *order, const cfg_obj_t *ent) {
- dns_rdataclass_t rdclass;
- dns_rdatatype_t rdtype;
- const cfg_obj_t *obj;
- dns_fixedname_t fixed;
- unsigned int mode = 0;
- const char *str;
- isc_buffer_t b;
- isc_result_t result;
- isc_boolean_t addroot;
- result = ns_config_getclass(cfg_tuple_get(ent, "class"),
- dns_rdataclass_any, &rdclass);
- if (result != ISC_R_SUCCESS)
- return (result);
- result = ns_config_gettype(cfg_tuple_get(ent, "type"),
- dns_rdatatype_any, &rdtype);
- if (result != ISC_R_SUCCESS)
- return (result);
- obj = cfg_tuple_get(ent, "name");
- if (cfg_obj_isstring(obj))
- str = cfg_obj_asstring(obj);
- else
- str = "*";
- addroot = ISC_TF(strcmp(str, "*") == 0);
- isc_buffer_init(&b, str, strlen(str));
- isc_buffer_add(&b, strlen(str));
- dns_fixedname_init(&fixed);
- result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
- dns_rootname, 0, NULL);
- if (result != ISC_R_SUCCESS)
- return (result);
- obj = cfg_tuple_get(ent, "ordering");
- INSIST(cfg_obj_isstring(obj));
- str = cfg_obj_asstring(obj);
- if (!strcasecmp(str, "fixed"))
- mode = DNS_RDATASETATTR_FIXEDORDER;
- else if (!strcasecmp(str, "random"))
- mode = DNS_RDATASETATTR_RANDOMIZE;
- else if (!strcasecmp(str, "cyclic"))
- mode = 0;
- else
- INSIST(0);
- /*
- * "*" should match everything including the root (BIND 8 compat).
- * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
- * explicit entry for "." when the name is "*".
- */
- if (addroot) {
- result = dns_order_add(order, dns_rootname,
- rdtype, rdclass, mode);
- if (result != ISC_R_SUCCESS)
- return (result);
- }
- return (dns_order_add(order, dns_fixedname_name(&fixed),
- rdtype, rdclass, mode));
- }
- static isc_result_t
- configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
- isc_netaddr_t na;
- dns_peer_t *peer;
- const cfg_obj_t *obj;
- const char *str;
- isc_result_t result;
- unsigned int prefixlen;
- cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
- peer = NULL;
- result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
- if (result != ISC_R_SUCCESS)
- return (result);
- obj = NULL;
- (void)cfg_map_get(cpeer, "bogus", &obj);
- if (obj != NULL)
- CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
- obj = NULL;
- (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
- if (obj != NULL)
- CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
- obj = NULL;
- (void)cfg_map_get(cpeer, "request-ixfr", &obj);
- if (obj != NULL)
- CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
- obj = NULL;
- (void)cfg_map_get(cpeer, "request-nsid", &obj);
- if (obj != NULL)
- CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
- obj = NULL;
- (void)cfg_map_get(cpeer, "edns", &obj);
- if (obj != NULL)
- 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)));
- obj = NULL;
- (void)cfg_map_get(cpeer, "transfer-format", &obj);
- if (obj != NULL) {
- str = cfg_obj_asstring(obj);
- if (strcasecmp(str, "many-answers") == 0)
- CHECK(dns_peer_settransferformat(peer,
- dns_many_answers));
- else if (strcasecmp(str, "one-answer") == 0)
- CHECK(dns_peer_settransferformat(peer,
- dns_one_answer));
- else
- INSIST(0);
- }
- obj = NULL;
- (void)cfg_map_get(cpeer, "keys", &obj);
- if (obj != NULL) {
- result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- }
- obj = NULL;
- if (na.family == AF_INET)
- (void)cfg_map_get(cpeer, "transfer-source", &obj);
- else
- (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
- if (obj != NULL) {
- result = dns_peer_settransfersource(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, "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);
- cleanup:
- dns_peer_detach(&peer);
- return (result);
- }
- static isc_result_t
- disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
- isc_result_t result;
- const cfg_obj_t *algorithms;
- const cfg_listelt_t *element;
- const char *str;
- dns_fixedname_t fixed;
- dns_name_t *name;
- isc_buffer_t b;
- dns_fixedname_init(&fixed);
- name = dns_fixedname_name(&fixed);
- 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, 0, NULL));
- algorithms = cfg_tuple_get(disabled, "algorithms");
- for (element = cfg_list_first(algorithms);
- element != NULL;
- element = cfg_list_next(element))
- {
- isc_textregion_t r;
- dns_secalg_t alg;
- DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
- r.length = strlen(r.base);
- result = dns_secalg_fromtext(&alg, &r);
- if (result != ISC_R_SUCCESS) {
- isc_uint8_t ui;
- result = isc_parse_uint8(&ui, r.base, 10);
- alg = ui;
- }
- if (result != ISC_R_SUCCESS) {
- cfg_obj_log(cfg_listelt_value(element),
- ns_g_lctx, ISC_LOG_ERROR,
- "invalid algorithm");
- CHECK(result);
- }
- CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
- }
- cleanup:
- 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,
- 0, 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);
- }
- static isc_result_t
- setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
- isc_result_t result;
- isc_stats_t *zoneqrystats;
- zoneqrystats = NULL;
- if (on) {
- result = isc_stats_create(mctx, &zoneqrystats,
- dns_nsstatscounter_max);
- if (result != ISC_R_SUCCESS)
- return (result);
- }
- dns_zone_setrequeststats(zone, zoneqrystats);
- if (zoneqrystats != NULL)
- isc_stats_detach(&zoneqrystats);
- 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)
- {
- if (originview->checknames != view->checknames ||
- dns_resolver_getzeronosoattl(originview->resolver) !=
- new_zero_no_soattl ||
- originview->acceptexpired != view->acceptexpired ||
- originview->enablevalidation != view->enablevalidation ||
- originview->maxcachettl != view->maxcachettl ||
- originview->maxncachettl != view->maxncachettl) {
- return (ISC_FALSE);
- }
- 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);
- }
- /*
- * 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);
- }
- 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] = { "_dns64", "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'.
- *
- * When configuring the default view, 'vconfig' will be NULL and the
- * global defaults in 'config' used exclusively.
- */
- static isc_result_t
- configure_view(dns_view_t *view, 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;
- const cfg_obj_t *forwarders;
- const cfg_obj_t *alternates;
- const cfg_obj_t *zonelist;
- const cfg_obj_t *dlz;
- unsigned int dlzargc;
- char **dlzargv;
- const cfg_obj_t *disabled;
- const cfg_obj_t *obj;
- const cfg_listelt_t *element;
- in_port_t port;
- 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 = NULL;
- dns_view_t *pview = NULL; /* Production view */
- isc_mem_t *cmctx = NULL, *hmctx = NULL;
- dns_dispatch_t *dispatch4 = NULL;
- dns_dispatch_t *dispatch6 = NULL;
- isc_boolean_t reused_cache = ISC_FALSE;
- 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;
- 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;
- 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;
- dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
- unsigned int query_timeout;
- struct cfg_context *nzctx;
- REQUIRE(DNS_VIEW_VALID(view));
- if (config != NULL)
- (void)cfg_map_get(config, "options", &options);
- /*
- * 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) {
- maps[i++] = options;
- optionmaps[j++] = options;
- }
- maps[i++] = ns_g_defaults;
- maps[i] = NULL;
- optionmaps[j] = NULL;
- if (config != NULL)
- cfgmaps[k++] = config;
- cfgmaps[k] = NULL;
- if (!strcmp(viewname, "_default")) {
- sep = "";
- viewname = "";
- forview = "";
- POST(forview);
- }
- /*
- * Set the view's port number for outgoing queries.
- */
- CHECKM(ns_config_getport(config, &port), "port");
- 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_setname(cmctx, "acache", NULL);
- 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);
- }
- 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",
- NULL, actx, ns_g_mctx,
- &view->queryacl));
- }
- /*
- * Configure the zones.
- */
- zonelist = NULL;
- if (voptions != NULL)
- (void)cfg_map_get(voptions, "zone", &zonelist);
- else
- (void)cfg_map_get(config, "zone", &zonelist);
- /*
- * Load zone configuration
- */
- 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_FALSE));
- }
- /*
- * If we're allowing added zones, then load zone configuration
- * from the newzone file for zones that were added during previous
- * runs.
- */
- nzctx = view->new_zone_config;
- if (nzctx != NULL && nzctx->nzconfig != NULL) {
- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
- NS_LOGMODULE_SERVER, ISC_LOG_INFO,
- "loading additional zones for view '%s'",
- view->name);
- zonelist = NULL;
- cfg_map_get(nzctx->nzconfig, "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));
- }
- }
- /*
- * 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;
- /*
- * 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;
- }
- }
- /*
- * 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);
- INSIST(result == ISC_R_SUCCESS);
- str = cfg_obj_asstring(obj);
- if (strcasecmp(str, "fail") == 0) {
- resopts |= DNS_RESOLVER_CHECKNAMES |
- DNS_RESOLVER_CHECKNAMESFAIL;
- view->checknames = ISC_TRUE;
- } else if (strcasecmp(str, "warn") == 0) {
- resopts |= DNS_RESOLVER_CHECKNAMES;
- view->checknames = ISC_FALSE;
- } else if (strcasecmp(str, "ignore") == 0) {
- view->chec…