server.c revision 234010
1135446Strhodes/* 2234010Sdougb * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: server.c,v 1.599.8.19 2012/02/22 00:33:32 each Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25186462Sdougb#include <unistd.h> 26224092Sdougb#include <limits.h> 27224092Sdougb#include <ctype.h> 28224092Sdougb#include <sys/types.h> 29224092Sdougb#include <sys/stat.h> 30135446Strhodes 31135446Strhodes#include <isc/app.h> 32135446Strhodes#include <isc/base64.h> 33135446Strhodes#include <isc/dir.h> 34135446Strhodes#include <isc/entropy.h> 35135446Strhodes#include <isc/file.h> 36135446Strhodes#include <isc/hash.h> 37193149Sdougb#include <isc/httpd.h> 38135446Strhodes#include <isc/lex.h> 39135446Strhodes#include <isc/parseint.h> 40186462Sdougb#include <isc/portset.h> 41135446Strhodes#include <isc/print.h> 42135446Strhodes#include <isc/resource.h> 43224092Sdougb#include <isc/sha2.h> 44186462Sdougb#include <isc/socket.h> 45224092Sdougb#include <isc/stat.h> 46193149Sdougb#include <isc/stats.h> 47135446Strhodes#include <isc/stdio.h> 48135446Strhodes#include <isc/string.h> 49135446Strhodes#include <isc/task.h> 50135446Strhodes#include <isc/timer.h> 51135446Strhodes#include <isc/util.h> 52193149Sdougb#include <isc/xml.h> 53135446Strhodes 54135446Strhodes#include <isccfg/namedconf.h> 55135446Strhodes 56135446Strhodes#include <bind9/check.h> 57135446Strhodes 58170222Sdougb#include <dns/acache.h> 59135446Strhodes#include <dns/adb.h> 60135446Strhodes#include <dns/cache.h> 61135446Strhodes#include <dns/db.h> 62135446Strhodes#include <dns/dispatch.h> 63170222Sdougb#include <dns/dlz.h> 64224092Sdougb#include <dns/dns64.h> 65135446Strhodes#include <dns/forward.h> 66135446Strhodes#include <dns/journal.h> 67135446Strhodes#include <dns/keytable.h> 68224092Sdougb#include <dns/keyvalues.h> 69170222Sdougb#include <dns/lib.h> 70135446Strhodes#include <dns/master.h> 71135446Strhodes#include <dns/masterdump.h> 72135446Strhodes#include <dns/order.h> 73135446Strhodes#include <dns/peer.h> 74135446Strhodes#include <dns/portlist.h> 75193149Sdougb#include <dns/rbt.h> 76135446Strhodes#include <dns/rdataclass.h> 77135446Strhodes#include <dns/rdataset.h> 78135446Strhodes#include <dns/rdatastruct.h> 79135446Strhodes#include <dns/resolver.h> 80135446Strhodes#include <dns/rootns.h> 81135446Strhodes#include <dns/secalg.h> 82135446Strhodes#include <dns/stats.h> 83135446Strhodes#include <dns/tkey.h> 84193149Sdougb#include <dns/tsig.h> 85135446Strhodes#include <dns/view.h> 86135446Strhodes#include <dns/zone.h> 87135446Strhodes#include <dns/zt.h> 88135446Strhodes 89135446Strhodes#include <dst/dst.h> 90135446Strhodes#include <dst/result.h> 91135446Strhodes 92135446Strhodes#include <named/client.h> 93135446Strhodes#include <named/config.h> 94135446Strhodes#include <named/control.h> 95135446Strhodes#include <named/interfacemgr.h> 96135446Strhodes#include <named/log.h> 97135446Strhodes#include <named/logconf.h> 98135446Strhodes#include <named/lwresd.h> 99135446Strhodes#include <named/main.h> 100135446Strhodes#include <named/os.h> 101135446Strhodes#include <named/server.h> 102193149Sdougb#include <named/statschannel.h> 103135446Strhodes#include <named/tkeyconf.h> 104135446Strhodes#include <named/tsigconf.h> 105135446Strhodes#include <named/zoneconf.h> 106153816Sdougb#ifdef HAVE_LIBSCF 107153816Sdougb#include <named/ns_smf_globals.h> 108153816Sdougb#include <stdlib.h> 109153816Sdougb#endif 110135446Strhodes 111224092Sdougb#ifndef PATH_MAX 112224092Sdougb#define PATH_MAX 1024 113224092Sdougb#endif 114224092Sdougb 115170222Sdougb/*% 116135446Strhodes * Check an operation for failure. Assumes that the function 117135446Strhodes * using it has a 'result' variable and a 'cleanup' label. 118135446Strhodes */ 119135446Strhodes#define CHECK(op) \ 120193149Sdougb do { result = (op); \ 121193149Sdougb if (result != ISC_R_SUCCESS) goto cleanup; \ 122135446Strhodes } while (0) 123135446Strhodes 124135446Strhodes#define CHECKM(op, msg) \ 125193149Sdougb do { result = (op); \ 126135446Strhodes if (result != ISC_R_SUCCESS) { \ 127135446Strhodes isc_log_write(ns_g_lctx, \ 128135446Strhodes NS_LOGCATEGORY_GENERAL, \ 129135446Strhodes NS_LOGMODULE_SERVER, \ 130135446Strhodes ISC_LOG_ERROR, \ 131135446Strhodes "%s: %s", msg, \ 132135446Strhodes isc_result_totext(result)); \ 133135446Strhodes goto cleanup; \ 134135446Strhodes } \ 135135446Strhodes } while (0) \ 136135446Strhodes 137135446Strhodes#define CHECKMF(op, msg, file) \ 138193149Sdougb do { result = (op); \ 139135446Strhodes if (result != ISC_R_SUCCESS) { \ 140135446Strhodes isc_log_write(ns_g_lctx, \ 141135446Strhodes NS_LOGCATEGORY_GENERAL, \ 142135446Strhodes NS_LOGMODULE_SERVER, \ 143135446Strhodes ISC_LOG_ERROR, \ 144135446Strhodes "%s '%s': %s", msg, file, \ 145135446Strhodes isc_result_totext(result)); \ 146135446Strhodes goto cleanup; \ 147135446Strhodes } \ 148135446Strhodes } while (0) \ 149135446Strhodes 150135446Strhodes#define CHECKFATAL(op, msg) \ 151193149Sdougb do { result = (op); \ 152135446Strhodes if (result != ISC_R_SUCCESS) \ 153135446Strhodes fatal(msg, result); \ 154135446Strhodes } while (0) \ 155135446Strhodes 156224092Sdougb/*% 157224092Sdougb * Maximum ADB size for views that share a cache. Use this limit to suppress 158224092Sdougb * the total of memory footprint, which should be the main reason for sharing 159224092Sdougb * a cache. Only effective when a finite max-cache-size is specified. 160224092Sdougb * This is currently defined to be 8MB. 161224092Sdougb */ 162224092Sdougb#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608 163224092Sdougb 164135446Strhodesstruct ns_dispatch { 165135446Strhodes isc_sockaddr_t addr; 166135446Strhodes unsigned int dispatchgen; 167135446Strhodes dns_dispatch_t *dispatch; 168135446Strhodes ISC_LINK(struct ns_dispatch) link; 169135446Strhodes}; 170135446Strhodes 171224092Sdougbstruct ns_cache { 172224092Sdougb dns_cache_t *cache; 173224092Sdougb dns_view_t *primaryview; 174224092Sdougb isc_boolean_t needflush; 175224092Sdougb isc_boolean_t adbsizeadjusted; 176224092Sdougb ISC_LINK(ns_cache_t) link; 177224092Sdougb}; 178224092Sdougb 179135446Strhodesstruct dumpcontext { 180135446Strhodes isc_mem_t *mctx; 181135446Strhodes isc_boolean_t dumpcache; 182135446Strhodes isc_boolean_t dumpzones; 183135446Strhodes FILE *fp; 184135446Strhodes ISC_LIST(struct viewlistentry) viewlist; 185135446Strhodes struct viewlistentry *view; 186135446Strhodes struct zonelistentry *zone; 187135446Strhodes dns_dumpctx_t *mdctx; 188135446Strhodes dns_db_t *db; 189135446Strhodes dns_db_t *cache; 190135446Strhodes isc_task_t *task; 191135446Strhodes dns_dbversion_t *version; 192135446Strhodes}; 193135446Strhodes 194135446Strhodesstruct viewlistentry { 195135446Strhodes dns_view_t *view; 196135446Strhodes ISC_LINK(struct viewlistentry) link; 197135446Strhodes ISC_LIST(struct zonelistentry) zonelist; 198135446Strhodes}; 199135446Strhodes 200135446Strhodesstruct zonelistentry { 201135446Strhodes dns_zone_t *zone; 202135446Strhodes ISC_LINK(struct zonelistentry) link; 203135446Strhodes}; 204135446Strhodes 205224092Sdougb/*% 206224092Sdougb * Configuration context to retain for each view that allows 207225361Sdougb * new zones to be added at runtime. 208224092Sdougb */ 209224092Sdougbstruct cfg_context { 210224092Sdougb isc_mem_t * mctx; 211225361Sdougb cfg_parser_t * parser; 212224092Sdougb cfg_obj_t * config; 213225361Sdougb cfg_parser_t * nzparser; 214225361Sdougb cfg_obj_t * nzconfig; 215225361Sdougb cfg_aclconfctx_t * actx; 216224092Sdougb}; 217224092Sdougb 218170222Sdougb/* 219170222Sdougb * These zones should not leak onto the Internet. 220170222Sdougb */ 221170222Sdougbstatic const struct { 222170222Sdougb const char *zone; 223170222Sdougb isc_boolean_t rfc1918; 224170222Sdougb} empty_zones[] = { 225170222Sdougb /* RFC 1918 */ 226170222Sdougb { "10.IN-ADDR.ARPA", ISC_TRUE }, 227170222Sdougb { "16.172.IN-ADDR.ARPA", ISC_TRUE }, 228170222Sdougb { "17.172.IN-ADDR.ARPA", ISC_TRUE }, 229170222Sdougb { "18.172.IN-ADDR.ARPA", ISC_TRUE }, 230170222Sdougb { "19.172.IN-ADDR.ARPA", ISC_TRUE }, 231170222Sdougb { "20.172.IN-ADDR.ARPA", ISC_TRUE }, 232170222Sdougb { "21.172.IN-ADDR.ARPA", ISC_TRUE }, 233170222Sdougb { "22.172.IN-ADDR.ARPA", ISC_TRUE }, 234170222Sdougb { "23.172.IN-ADDR.ARPA", ISC_TRUE }, 235170222Sdougb { "24.172.IN-ADDR.ARPA", ISC_TRUE }, 236170222Sdougb { "25.172.IN-ADDR.ARPA", ISC_TRUE }, 237170222Sdougb { "26.172.IN-ADDR.ARPA", ISC_TRUE }, 238170222Sdougb { "27.172.IN-ADDR.ARPA", ISC_TRUE }, 239170222Sdougb { "28.172.IN-ADDR.ARPA", ISC_TRUE }, 240170222Sdougb { "29.172.IN-ADDR.ARPA", ISC_TRUE }, 241170222Sdougb { "30.172.IN-ADDR.ARPA", ISC_TRUE }, 242170222Sdougb { "31.172.IN-ADDR.ARPA", ISC_TRUE }, 243170222Sdougb { "168.192.IN-ADDR.ARPA", ISC_TRUE }, 244170222Sdougb 245218384Sdougb /* RFC 5735 and RFC 5737 */ 246186462Sdougb { "0.IN-ADDR.ARPA", ISC_FALSE }, /* THIS NETWORK */ 247170222Sdougb { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */ 248170222Sdougb { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */ 249170222Sdougb { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */ 250218384Sdougb { "100.51.198.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET 2 */ 251218384Sdougb { "113.0.203.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET 3 */ 252170222Sdougb { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */ 253170222Sdougb 254170222Sdougb /* Local IPv6 Unicast Addresses */ 255170222Sdougb { "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 }, 256170222Sdougb { "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 }, 257193149Sdougb /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */ 258170222Sdougb { "D.F.IP6.ARPA", ISC_FALSE }, 259170222Sdougb { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 260170222Sdougb { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 261170222Sdougb { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 262170222Sdougb { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 263170222Sdougb 264218384Sdougb /* Example Prefix, RFC 3849. */ 265218384Sdougb { "8.B.D.0.1.0.0.2.IP6.ARPA", ISC_FALSE }, 266218384Sdougb 267170222Sdougb { NULL, ISC_FALSE } 268170222Sdougb}; 269170222Sdougb 270224092SdougbISC_PLATFORM_NORETURN_PRE static void 271224092Sdougbfatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST; 272135446Strhodes 273135446Strhodesstatic void 274135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event); 275135446Strhodes 276135446Strhodesstatic isc_result_t 277165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 278170222Sdougb cfg_aclconfctx_t *actx, 279135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target); 280135446Strhodesstatic isc_result_t 281165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 282170222Sdougb cfg_aclconfctx_t *actx, 283135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target); 284135446Strhodes 285135446Strhodesstatic isc_result_t 286165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 287165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); 288135446Strhodes 289135446Strhodesstatic isc_result_t 290165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 291165071Sdougb const cfg_obj_t *alternates); 292135446Strhodes 293135446Strhodesstatic isc_result_t 294165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 295165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 296224092Sdougb cfg_aclconfctx_t *aclconf, isc_boolean_t added); 297135446Strhodes 298224092Sdougbstatic isc_result_t 299224092Sdougbadd_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx); 300224092Sdougb 301135446Strhodesstatic void 302135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all); 303135446Strhodes 304224092Sdougbstatic void 305225361Sdougbnewzone_cfgctx_destroy(void **cfgp); 306224092Sdougb 307170222Sdougb/*% 308193149Sdougb * Configure a single view ACL at '*aclp'. Get its configuration from 309193149Sdougb * 'vconfig' (for per-view configuration) and maybe from 'config' 310135446Strhodes */ 311135446Strhodesstatic isc_result_t 312165071Sdougbconfigure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, 313224092Sdougb const char *aclname, const char *acltuplename, 314224092Sdougb cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp) 315135446Strhodes{ 316135446Strhodes isc_result_t result; 317165071Sdougb const cfg_obj_t *maps[3]; 318165071Sdougb const cfg_obj_t *aclobj = NULL; 319135446Strhodes int i = 0; 320135446Strhodes 321135446Strhodes if (*aclp != NULL) 322135446Strhodes dns_acl_detach(aclp); 323135446Strhodes if (vconfig != NULL) 324135446Strhodes maps[i++] = cfg_tuple_get(vconfig, "options"); 325135446Strhodes if (config != NULL) { 326165071Sdougb const cfg_obj_t *options = NULL; 327135446Strhodes (void)cfg_map_get(config, "options", &options); 328135446Strhodes if (options != NULL) 329135446Strhodes maps[i++] = options; 330135446Strhodes } 331135446Strhodes maps[i] = NULL; 332135446Strhodes 333165071Sdougb (void)ns_config_get(maps, aclname, &aclobj); 334135446Strhodes if (aclobj == NULL) 335135446Strhodes /* 336193149Sdougb * No value available. *aclp == NULL. 337135446Strhodes */ 338135446Strhodes return (ISC_R_SUCCESS); 339135446Strhodes 340224092Sdougb if (acltuplename != NULL) { 341224092Sdougb /* 342224092Sdougb * If the ACL is given in an optional tuple, retrieve it. 343224092Sdougb * The parser should have ensured that a valid object be 344224092Sdougb * returned. 345224092Sdougb */ 346224092Sdougb aclobj = cfg_tuple_get(aclobj, acltuplename); 347224092Sdougb } 348224092Sdougb 349170222Sdougb result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 350193149Sdougb actx, mctx, 0, aclp); 351135446Strhodes 352135446Strhodes return (result); 353135446Strhodes} 354135446Strhodes 355193149Sdougb/*% 356193149Sdougb * Configure a sortlist at '*aclp'. Essentially the same as 357193149Sdougb * configure_view_acl() except it calls cfg_acl_fromconfig with a 358193149Sdougb * nest_level value of 2. 359193149Sdougb */ 360135446Strhodesstatic isc_result_t 361193149Sdougbconfigure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, 362193149Sdougb cfg_aclconfctx_t *actx, isc_mem_t *mctx, 363193149Sdougb dns_acl_t **aclp) 364193149Sdougb{ 365193149Sdougb isc_result_t result; 366193149Sdougb const cfg_obj_t *maps[3]; 367193149Sdougb const cfg_obj_t *aclobj = NULL; 368193149Sdougb int i = 0; 369193149Sdougb 370193149Sdougb if (*aclp != NULL) 371193149Sdougb dns_acl_detach(aclp); 372193149Sdougb if (vconfig != NULL) 373193149Sdougb maps[i++] = cfg_tuple_get(vconfig, "options"); 374193149Sdougb if (config != NULL) { 375193149Sdougb const cfg_obj_t *options = NULL; 376193149Sdougb (void)cfg_map_get(config, "options", &options); 377193149Sdougb if (options != NULL) 378193149Sdougb maps[i++] = options; 379193149Sdougb } 380193149Sdougb maps[i] = NULL; 381193149Sdougb 382193149Sdougb (void)ns_config_get(maps, "sortlist", &aclobj); 383193149Sdougb if (aclobj == NULL) 384193149Sdougb return (ISC_R_SUCCESS); 385193149Sdougb 386193149Sdougb /* 387193149Sdougb * Use a nest level of 3 for the "top level" of the sortlist; 388193149Sdougb * this means each entry in the top three levels will be stored 389193149Sdougb * as lists of separate, nested ACLs, rather than merged together 390193149Sdougb * into IP tables as is usually done with ACLs. 391193149Sdougb */ 392193149Sdougb result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 393193149Sdougb actx, mctx, 3, aclp); 394193149Sdougb 395193149Sdougb return (result); 396193149Sdougb} 397193149Sdougb 398193149Sdougbstatic isc_result_t 399224092Sdougbconfigure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config, 400224092Sdougb const char *confname, const char *conftuplename, 401224092Sdougb isc_mem_t *mctx, dns_rbt_t **rbtp) 402135446Strhodes{ 403224092Sdougb isc_result_t result; 404224092Sdougb const cfg_obj_t *maps[3]; 405224092Sdougb const cfg_obj_t *obj = NULL; 406224092Sdougb const cfg_listelt_t *element; 407224092Sdougb int i = 0; 408224092Sdougb dns_fixedname_t fixed; 409224092Sdougb dns_name_t *name; 410224092Sdougb isc_buffer_t b; 411224092Sdougb const char *str; 412224092Sdougb const cfg_obj_t *nameobj; 413224092Sdougb 414224092Sdougb if (*rbtp != NULL) 415224092Sdougb dns_rbt_destroy(rbtp); 416224092Sdougb if (vconfig != NULL) 417224092Sdougb maps[i++] = cfg_tuple_get(vconfig, "options"); 418224092Sdougb if (config != NULL) { 419224092Sdougb const cfg_obj_t *options = NULL; 420224092Sdougb (void)cfg_map_get(config, "options", &options); 421224092Sdougb if (options != NULL) 422224092Sdougb maps[i++] = options; 423224092Sdougb } 424224092Sdougb maps[i] = NULL; 425224092Sdougb 426224092Sdougb (void)ns_config_get(maps, confname, &obj); 427224092Sdougb if (obj == NULL) 428224092Sdougb /* 429224092Sdougb * No value available. *rbtp == NULL. 430224092Sdougb */ 431224092Sdougb return (ISC_R_SUCCESS); 432224092Sdougb 433224092Sdougb if (conftuplename != NULL) { 434224092Sdougb obj = cfg_tuple_get(obj, conftuplename); 435224092Sdougb if (cfg_obj_isvoid(obj)) 436224092Sdougb return (ISC_R_SUCCESS); 437224092Sdougb } 438224092Sdougb 439224092Sdougb result = dns_rbt_create(mctx, NULL, NULL, rbtp); 440224092Sdougb if (result != ISC_R_SUCCESS) 441224092Sdougb return (result); 442224092Sdougb 443224092Sdougb dns_fixedname_init(&fixed); 444224092Sdougb name = dns_fixedname_name(&fixed); 445224092Sdougb for (element = cfg_list_first(obj); 446224092Sdougb element != NULL; 447224092Sdougb element = cfg_list_next(element)) { 448224092Sdougb nameobj = cfg_listelt_value(element); 449224092Sdougb str = cfg_obj_asstring(nameobj); 450224092Sdougb isc_buffer_init(&b, str, strlen(str)); 451224092Sdougb isc_buffer_add(&b, strlen(str)); 452224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 453224092Sdougb /* 454224092Sdougb * We don't need the node data, but need to set dummy data to 455224092Sdougb * avoid a partial match with an empty node. For example, if 456224092Sdougb * we have foo.example.com and bar.example.com, we'd get a match 457224092Sdougb * for baz.example.com, which is not the expected result. 458224092Sdougb * We simply use (void *)1 as the dummy data. 459224092Sdougb */ 460224092Sdougb result = dns_rbt_addname(*rbtp, name, (void *)1); 461224092Sdougb if (result != ISC_R_SUCCESS) { 462224092Sdougb cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR, 463224092Sdougb "failed to add %s for %s: %s", 464224092Sdougb str, confname, isc_result_totext(result)); 465224092Sdougb goto cleanup; 466224092Sdougb } 467224092Sdougb 468224092Sdougb } 469224092Sdougb 470224092Sdougb return (result); 471224092Sdougb 472224092Sdougb cleanup: 473224092Sdougb dns_rbt_destroy(rbtp); 474224092Sdougb return (result); 475224092Sdougb 476224092Sdougb} 477224092Sdougb 478224092Sdougbstatic isc_result_t 479224092Sdougbdstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key, 480224092Sdougb isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx) 481224092Sdougb{ 482135446Strhodes dns_rdataclass_t viewclass; 483135446Strhodes dns_rdata_dnskey_t keystruct; 484135446Strhodes isc_uint32_t flags, proto, alg; 485165071Sdougb const char *keystr, *keynamestr; 486135446Strhodes unsigned char keydata[4096]; 487135446Strhodes isc_buffer_t keydatabuf; 488135446Strhodes unsigned char rrdata[4096]; 489135446Strhodes isc_buffer_t rrdatabuf; 490135446Strhodes isc_region_t r; 491135446Strhodes dns_fixedname_t fkeyname; 492135446Strhodes dns_name_t *keyname; 493135446Strhodes isc_buffer_t namebuf; 494135446Strhodes isc_result_t result; 495135446Strhodes dst_key_t *dstkey = NULL; 496135446Strhodes 497224092Sdougb INSIST(target != NULL && *target == NULL); 498224092Sdougb 499135446Strhodes flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 500135446Strhodes proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); 501135446Strhodes alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); 502135446Strhodes keyname = dns_fixedname_name(&fkeyname); 503135446Strhodes keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 504135446Strhodes 505224092Sdougb if (managed) { 506224092Sdougb const char *initmethod; 507224092Sdougb initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init")); 508224092Sdougb 509224092Sdougb if (strcasecmp(initmethod, "initial-key") != 0) { 510224092Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 511224092Sdougb "managed key '%s': " 512224092Sdougb "invalid initialization method '%s'", 513224092Sdougb keynamestr, initmethod); 514224092Sdougb result = ISC_R_FAILURE; 515224092Sdougb goto cleanup; 516224092Sdougb } 517224092Sdougb } 518224092Sdougb 519135446Strhodes if (vconfig == NULL) 520135446Strhodes viewclass = dns_rdataclass_in; 521135446Strhodes else { 522165071Sdougb const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); 523135446Strhodes CHECK(ns_config_getclass(classobj, dns_rdataclass_in, 524135446Strhodes &viewclass)); 525135446Strhodes } 526135446Strhodes keystruct.common.rdclass = viewclass; 527135446Strhodes keystruct.common.rdtype = dns_rdatatype_dnskey; 528135446Strhodes /* 529135446Strhodes * The key data in keystruct is not dynamically allocated. 530135446Strhodes */ 531135446Strhodes keystruct.mctx = NULL; 532135446Strhodes 533135446Strhodes ISC_LINK_INIT(&keystruct.common, link); 534135446Strhodes 535135446Strhodes if (flags > 0xffff) 536135446Strhodes CHECKM(ISC_R_RANGE, "key flags"); 537135446Strhodes if (proto > 0xff) 538135446Strhodes CHECKM(ISC_R_RANGE, "key protocol"); 539135446Strhodes if (alg > 0xff) 540135446Strhodes CHECKM(ISC_R_RANGE, "key algorithm"); 541135446Strhodes keystruct.flags = (isc_uint16_t)flags; 542135446Strhodes keystruct.protocol = (isc_uint8_t)proto; 543135446Strhodes keystruct.algorithm = (isc_uint8_t)alg; 544135446Strhodes 545135446Strhodes isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); 546135446Strhodes isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 547135446Strhodes 548135446Strhodes keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 549135446Strhodes CHECK(isc_base64_decodestring(keystr, &keydatabuf)); 550135446Strhodes isc_buffer_usedregion(&keydatabuf, &r); 551135446Strhodes keystruct.datalen = r.length; 552135446Strhodes keystruct.data = r.base; 553135446Strhodes 554170222Sdougb if ((keystruct.algorithm == DST_ALG_RSASHA1 || 555170222Sdougb keystruct.algorithm == DST_ALG_RSAMD5) && 556170222Sdougb r.length > 1 && r.base[0] == 1 && r.base[1] == 3) 557170222Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 558224092Sdougb "%s key '%s' has a weak exponent", 559224092Sdougb managed ? "managed" : "trusted", 560170222Sdougb keynamestr); 561170222Sdougb 562135446Strhodes CHECK(dns_rdata_fromstruct(NULL, 563135446Strhodes keystruct.common.rdclass, 564135446Strhodes keystruct.common.rdtype, 565135446Strhodes &keystruct, &rrdatabuf)); 566135446Strhodes dns_fixedname_init(&fkeyname); 567135446Strhodes isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); 568135446Strhodes isc_buffer_add(&namebuf, strlen(keynamestr)); 569224092Sdougb CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL)); 570135446Strhodes CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, 571135446Strhodes mctx, &dstkey)); 572135446Strhodes 573224092Sdougb *target = dstkey; 574135446Strhodes return (ISC_R_SUCCESS); 575135446Strhodes 576135446Strhodes cleanup: 577135446Strhodes if (result == DST_R_NOCRYPTO) { 578135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 579224092Sdougb "ignoring %s key for '%s': no crypto support", 580224092Sdougb managed ? "managed" : "trusted", 581135446Strhodes keynamestr); 582224092Sdougb } else if (result == DST_R_UNSUPPORTEDALG) { 583224092Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 584224092Sdougb "skipping %s key for '%s': %s", 585224092Sdougb managed ? "managed" : "trusted", 586224092Sdougb keynamestr, isc_result_totext(result)); 587135446Strhodes } else { 588135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 589224092Sdougb "configuring %s key for '%s': %s", 590224092Sdougb managed ? "managed" : "trusted", 591135446Strhodes keynamestr, isc_result_totext(result)); 592135446Strhodes result = ISC_R_FAILURE; 593135446Strhodes } 594135446Strhodes 595135446Strhodes if (dstkey != NULL) 596135446Strhodes dst_key_free(&dstkey); 597135446Strhodes 598135446Strhodes return (result); 599135446Strhodes} 600135446Strhodes 601224092Sdougbstatic isc_result_t 602224092Sdougbload_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig, 603224092Sdougb dns_view_t *view, isc_boolean_t managed, 604224092Sdougb dns_name_t *keyname, isc_mem_t *mctx) 605224092Sdougb{ 606224092Sdougb const cfg_listelt_t *elt, *elt2; 607224092Sdougb const cfg_obj_t *key, *keylist; 608224092Sdougb dst_key_t *dstkey = NULL; 609224092Sdougb isc_result_t result; 610224092Sdougb dns_keytable_t *secroots = NULL; 611224092Sdougb 612224092Sdougb CHECK(dns_view_getsecroots(view, &secroots)); 613224092Sdougb 614224092Sdougb for (elt = cfg_list_first(keys); 615224092Sdougb elt != NULL; 616224092Sdougb elt = cfg_list_next(elt)) { 617224092Sdougb keylist = cfg_listelt_value(elt); 618224092Sdougb 619224092Sdougb for (elt2 = cfg_list_first(keylist); 620224092Sdougb elt2 != NULL; 621224092Sdougb elt2 = cfg_list_next(elt2)) { 622224092Sdougb key = cfg_listelt_value(elt2); 623224092Sdougb result = dstkey_fromconfig(vconfig, key, managed, 624224092Sdougb &dstkey, mctx); 625224092Sdougb if (result == DST_R_UNSUPPORTEDALG) { 626224092Sdougb result = ISC_R_SUCCESS; 627224092Sdougb continue; 628224092Sdougb } 629224092Sdougb if (result != ISC_R_SUCCESS) 630224092Sdougb goto cleanup; 631224092Sdougb 632224092Sdougb /* 633224092Sdougb * If keyname was specified, we only add that key. 634224092Sdougb */ 635224092Sdougb if (keyname != NULL && 636224092Sdougb !dns_name_equal(keyname, dst_key_name(dstkey))) 637224092Sdougb { 638224092Sdougb dst_key_free(&dstkey); 639224092Sdougb continue; 640224092Sdougb } 641224092Sdougb 642224092Sdougb CHECK(dns_keytable_add(secroots, managed, &dstkey)); 643224092Sdougb } 644224092Sdougb } 645224092Sdougb 646224092Sdougb cleanup: 647224092Sdougb if (dstkey != NULL) 648224092Sdougb dst_key_free(&dstkey); 649224092Sdougb if (secroots != NULL) 650224092Sdougb dns_keytable_detach(&secroots); 651224092Sdougb if (result == DST_R_NOCRYPTO) 652224092Sdougb result = ISC_R_SUCCESS; 653224092Sdougb return (result); 654224092Sdougb} 655224092Sdougb 656170222Sdougb/*% 657224092Sdougb * Configure DNSSEC keys for a view. 658135446Strhodes * 659135446Strhodes * The per-view configuration values and the server-global defaults are read 660224092Sdougb * from 'vconfig' and 'config'. 661135446Strhodes */ 662135446Strhodesstatic isc_result_t 663224092Sdougbconfigure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig, 664224092Sdougb const cfg_obj_t *config, const cfg_obj_t *bindkeys, 665224092Sdougb isc_boolean_t auto_dlv, isc_boolean_t auto_root, 666224092Sdougb isc_mem_t *mctx) 667135446Strhodes{ 668224092Sdougb isc_result_t result = ISC_R_SUCCESS; 669224092Sdougb const cfg_obj_t *view_keys = NULL; 670224092Sdougb const cfg_obj_t *global_keys = NULL; 671224092Sdougb const cfg_obj_t *view_managed_keys = NULL; 672224092Sdougb const cfg_obj_t *global_managed_keys = NULL; 673224092Sdougb const cfg_obj_t *maps[4]; 674165071Sdougb const cfg_obj_t *voptions = NULL; 675224092Sdougb const cfg_obj_t *options = NULL; 676224092Sdougb const cfg_obj_t *obj = NULL; 677224092Sdougb const char *directory; 678224092Sdougb int i = 0; 679135446Strhodes 680224092Sdougb /* We don't need trust anchors for the _bind view */ 681224092Sdougb if (strcmp(view->name, "_bind") == 0 && 682224092Sdougb view->rdclass == dns_rdataclass_chaos) { 683224092Sdougb return (ISC_R_SUCCESS); 684224092Sdougb } 685135446Strhodes 686224092Sdougb if (vconfig != NULL) { 687135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 688224092Sdougb if (voptions != NULL) { 689224092Sdougb (void) cfg_map_get(voptions, "trusted-keys", 690224092Sdougb &view_keys); 691224092Sdougb (void) cfg_map_get(voptions, "managed-keys", 692224092Sdougb &view_managed_keys); 693224092Sdougb maps[i++] = voptions; 694224092Sdougb } 695224092Sdougb } 696135446Strhodes 697224092Sdougb if (config != NULL) { 698224092Sdougb (void)cfg_map_get(config, "trusted-keys", &global_keys); 699224092Sdougb (void)cfg_map_get(config, "managed-keys", &global_managed_keys); 700224092Sdougb (void)cfg_map_get(config, "options", &options); 701224092Sdougb if (options != NULL) { 702224092Sdougb maps[i++] = options; 703224092Sdougb } 704224092Sdougb } 705135446Strhodes 706224092Sdougb maps[i++] = ns_g_defaults; 707224092Sdougb maps[i] = NULL; 708224092Sdougb 709224092Sdougb result = dns_view_initsecroots(view, mctx); 710224092Sdougb if (result != ISC_R_SUCCESS) { 711224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 712224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 713224092Sdougb "couldn't create keytable"); 714224092Sdougb return (ISC_R_UNEXPECTED); 715224092Sdougb } 716224092Sdougb 717224092Sdougb if (auto_dlv && view->rdclass == dns_rdataclass_in) { 718224092Sdougb const cfg_obj_t *builtin_keys = NULL; 719224092Sdougb const cfg_obj_t *builtin_managed_keys = NULL; 720224092Sdougb 721224092Sdougb isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, 722224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 723224092Sdougb "using built-in DLV key for view %s", 724224092Sdougb view->name); 725224092Sdougb 726224092Sdougb /* 727224092Sdougb * If bind.keys exists, it overrides the managed-keys 728224092Sdougb * clause hard-coded in ns_g_config. 729224092Sdougb */ 730224092Sdougb if (bindkeys != NULL) { 731224092Sdougb (void)cfg_map_get(bindkeys, "trusted-keys", 732224092Sdougb &builtin_keys); 733224092Sdougb (void)cfg_map_get(bindkeys, "managed-keys", 734224092Sdougb &builtin_managed_keys); 735224092Sdougb } else { 736224092Sdougb (void)cfg_map_get(ns_g_config, "trusted-keys", 737224092Sdougb &builtin_keys); 738224092Sdougb (void)cfg_map_get(ns_g_config, "managed-keys", 739224092Sdougb &builtin_managed_keys); 740135446Strhodes } 741224092Sdougb 742224092Sdougb if (builtin_keys != NULL) 743224092Sdougb CHECK(load_view_keys(builtin_keys, vconfig, view, 744224092Sdougb ISC_FALSE, view->dlv, mctx)); 745224092Sdougb if (builtin_managed_keys != NULL) 746224092Sdougb CHECK(load_view_keys(builtin_managed_keys, vconfig, 747224092Sdougb view, ISC_TRUE, view->dlv, mctx)); 748135446Strhodes } 749135446Strhodes 750224092Sdougb if (auto_root && view->rdclass == dns_rdataclass_in) { 751224092Sdougb const cfg_obj_t *builtin_keys = NULL; 752224092Sdougb const cfg_obj_t *builtin_managed_keys = NULL; 753186462Sdougb 754224092Sdougb isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, 755224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 756224092Sdougb "using built-in root key for view %s", 757224092Sdougb view->name); 758224092Sdougb 759224092Sdougb /* 760224092Sdougb * If bind.keys exists, it overrides the managed-keys 761224092Sdougb * clause hard-coded in ns_g_config. 762224092Sdougb */ 763224092Sdougb if (bindkeys != NULL) { 764224092Sdougb (void)cfg_map_get(bindkeys, "trusted-keys", 765224092Sdougb &builtin_keys); 766224092Sdougb (void)cfg_map_get(bindkeys, "managed-keys", 767224092Sdougb &builtin_managed_keys); 768224092Sdougb } else { 769224092Sdougb (void)cfg_map_get(ns_g_config, "trusted-keys", 770224092Sdougb &builtin_keys); 771224092Sdougb (void)cfg_map_get(ns_g_config, "managed-keys", 772224092Sdougb &builtin_managed_keys); 773224092Sdougb } 774224092Sdougb 775224092Sdougb if (builtin_keys != NULL) 776224092Sdougb CHECK(load_view_keys(builtin_keys, vconfig, view, 777224092Sdougb ISC_FALSE, dns_rootname, mctx)); 778224092Sdougb if (builtin_managed_keys != NULL) 779224092Sdougb CHECK(load_view_keys(builtin_managed_keys, vconfig, 780224092Sdougb view, ISC_TRUE, dns_rootname, 781224092Sdougb mctx)); 782224092Sdougb } 783224092Sdougb 784224092Sdougb CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE, 785224092Sdougb NULL, mctx)); 786224092Sdougb CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE, 787224092Sdougb NULL, mctx)); 788224092Sdougb 789224092Sdougb if (view->rdclass == dns_rdataclass_in) { 790224092Sdougb CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE, 791224092Sdougb NULL, mctx)); 792224092Sdougb CHECK(load_view_keys(global_managed_keys, vconfig, view, 793224092Sdougb ISC_TRUE, NULL, mctx)); 794224092Sdougb } 795224092Sdougb 796224092Sdougb /* 797224092Sdougb * Add key zone for managed-keys. 798224092Sdougb */ 799224092Sdougb obj = NULL; 800224092Sdougb (void)ns_config_get(maps, "managed-keys-directory", &obj); 801224092Sdougb directory = obj != NULL ? cfg_obj_asstring(obj) : NULL; 802224092Sdougb CHECK(add_keydata_zone(view, directory, ns_g_mctx)); 803224092Sdougb 804224092Sdougb cleanup: 805135446Strhodes return (result); 806135446Strhodes} 807135446Strhodes 808135446Strhodesstatic isc_result_t 809224092Sdougbmustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) { 810165071Sdougb const cfg_listelt_t *element; 811165071Sdougb const cfg_obj_t *obj; 812135446Strhodes const char *str; 813135446Strhodes dns_fixedname_t fixed; 814135446Strhodes dns_name_t *name; 815135446Strhodes isc_boolean_t value; 816135446Strhodes isc_result_t result; 817135446Strhodes isc_buffer_t b; 818186462Sdougb 819135446Strhodes dns_fixedname_init(&fixed); 820135446Strhodes name = dns_fixedname_name(&fixed); 821135446Strhodes for (element = cfg_list_first(mbs); 822135446Strhodes element != NULL; 823135446Strhodes element = cfg_list_next(element)) 824135446Strhodes { 825135446Strhodes obj = cfg_listelt_value(element); 826135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 827135446Strhodes isc_buffer_init(&b, str, strlen(str)); 828135446Strhodes isc_buffer_add(&b, strlen(str)); 829224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 830135446Strhodes value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); 831135446Strhodes CHECK(dns_resolver_setmustbesecure(resolver, name, value)); 832135446Strhodes } 833135446Strhodes 834135446Strhodes result = ISC_R_SUCCESS; 835186462Sdougb 836135446Strhodes cleanup: 837135446Strhodes return (result); 838135446Strhodes} 839135446Strhodes 840170222Sdougb/*% 841135446Strhodes * Get a dispatch appropriate for the resolver of a given view. 842135446Strhodes */ 843135446Strhodesstatic isc_result_t 844165071Sdougbget_view_querysource_dispatch(const cfg_obj_t **maps, 845186462Sdougb int af, dns_dispatch_t **dispatchp, 846186462Sdougb isc_boolean_t is_firstview) 847135446Strhodes{ 848225361Sdougb isc_result_t result = ISC_R_FAILURE; 849135446Strhodes dns_dispatch_t *disp; 850135446Strhodes isc_sockaddr_t sa; 851135446Strhodes unsigned int attrs, attrmask; 852165071Sdougb const cfg_obj_t *obj = NULL; 853186462Sdougb unsigned int maxdispatchbuffers; 854135446Strhodes 855135446Strhodes switch (af) { 856135446Strhodes case AF_INET: 857135446Strhodes result = ns_config_get(maps, "query-source", &obj); 858135446Strhodes INSIST(result == ISC_R_SUCCESS); 859135446Strhodes break; 860135446Strhodes case AF_INET6: 861135446Strhodes result = ns_config_get(maps, "query-source-v6", &obj); 862135446Strhodes INSIST(result == ISC_R_SUCCESS); 863135446Strhodes break; 864135446Strhodes default: 865135446Strhodes INSIST(0); 866135446Strhodes } 867135446Strhodes 868135446Strhodes sa = *(cfg_obj_assockaddr(obj)); 869135446Strhodes INSIST(isc_sockaddr_pf(&sa) == af); 870135446Strhodes 871135446Strhodes /* 872135446Strhodes * If we don't support this address family, we're done! 873135446Strhodes */ 874135446Strhodes switch (af) { 875135446Strhodes case AF_INET: 876135446Strhodes result = isc_net_probeipv4(); 877135446Strhodes break; 878135446Strhodes case AF_INET6: 879135446Strhodes result = isc_net_probeipv6(); 880135446Strhodes break; 881135446Strhodes default: 882135446Strhodes INSIST(0); 883135446Strhodes } 884135446Strhodes if (result != ISC_R_SUCCESS) 885135446Strhodes return (ISC_R_SUCCESS); 886135446Strhodes 887135446Strhodes /* 888135446Strhodes * Try to find a dispatcher that we can share. 889135446Strhodes */ 890135446Strhodes attrs = 0; 891135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 892135446Strhodes switch (af) { 893135446Strhodes case AF_INET: 894135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 895135446Strhodes break; 896135446Strhodes case AF_INET6: 897135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 898135446Strhodes break; 899135446Strhodes } 900186462Sdougb if (isc_sockaddr_getport(&sa) == 0) { 901186462Sdougb attrs |= DNS_DISPATCHATTR_EXCLUSIVE; 902186462Sdougb maxdispatchbuffers = 4096; 903186462Sdougb } else { 904180477Sdougb INSIST(obj != NULL); 905186462Sdougb if (is_firstview) { 906186462Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO, 907186462Sdougb "using specific query-source port " 908186462Sdougb "suppresses port randomization and can be " 909186462Sdougb "insecure."); 910186462Sdougb } 911186462Sdougb maxdispatchbuffers = 1000; 912180477Sdougb } 913180477Sdougb 914135446Strhodes attrmask = 0; 915135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 916135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 917135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 918135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 919135446Strhodes 920135446Strhodes disp = NULL; 921135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 922135446Strhodes ns_g_taskmgr, &sa, 4096, 923186462Sdougb maxdispatchbuffers, 32768, 16411, 16433, 924135446Strhodes attrs, attrmask, &disp); 925135446Strhodes if (result != ISC_R_SUCCESS) { 926135446Strhodes isc_sockaddr_t any; 927135446Strhodes char buf[ISC_SOCKADDR_FORMATSIZE]; 928135446Strhodes 929135446Strhodes switch (af) { 930135446Strhodes case AF_INET: 931135446Strhodes isc_sockaddr_any(&any); 932135446Strhodes break; 933135446Strhodes case AF_INET6: 934135446Strhodes isc_sockaddr_any6(&any); 935135446Strhodes break; 936135446Strhodes } 937135446Strhodes if (isc_sockaddr_equal(&sa, &any)) 938135446Strhodes return (ISC_R_SUCCESS); 939135446Strhodes isc_sockaddr_format(&sa, buf, sizeof(buf)); 940135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 941135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 942135446Strhodes "could not get query source dispatcher (%s)", 943135446Strhodes buf); 944135446Strhodes return (result); 945135446Strhodes } 946135446Strhodes 947135446Strhodes *dispatchp = disp; 948135446Strhodes 949135446Strhodes return (ISC_R_SUCCESS); 950135446Strhodes} 951135446Strhodes 952135446Strhodesstatic isc_result_t 953165071Sdougbconfigure_order(dns_order_t *order, const cfg_obj_t *ent) { 954135446Strhodes dns_rdataclass_t rdclass; 955135446Strhodes dns_rdatatype_t rdtype; 956165071Sdougb const cfg_obj_t *obj; 957135446Strhodes dns_fixedname_t fixed; 958135446Strhodes unsigned int mode = 0; 959135446Strhodes const char *str; 960135446Strhodes isc_buffer_t b; 961135446Strhodes isc_result_t result; 962143731Sdougb isc_boolean_t addroot; 963135446Strhodes 964135446Strhodes result = ns_config_getclass(cfg_tuple_get(ent, "class"), 965135446Strhodes dns_rdataclass_any, &rdclass); 966135446Strhodes if (result != ISC_R_SUCCESS) 967135446Strhodes return (result); 968135446Strhodes 969135446Strhodes result = ns_config_gettype(cfg_tuple_get(ent, "type"), 970135446Strhodes dns_rdatatype_any, &rdtype); 971135446Strhodes if (result != ISC_R_SUCCESS) 972135446Strhodes return (result); 973135446Strhodes 974135446Strhodes obj = cfg_tuple_get(ent, "name"); 975186462Sdougb if (cfg_obj_isstring(obj)) 976135446Strhodes str = cfg_obj_asstring(obj); 977135446Strhodes else 978135446Strhodes str = "*"; 979143731Sdougb addroot = ISC_TF(strcmp(str, "*") == 0); 980135446Strhodes isc_buffer_init(&b, str, strlen(str)); 981135446Strhodes isc_buffer_add(&b, strlen(str)); 982135446Strhodes dns_fixedname_init(&fixed); 983135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 984224092Sdougb dns_rootname, 0, NULL); 985135446Strhodes if (result != ISC_R_SUCCESS) 986135446Strhodes return (result); 987135446Strhodes 988135446Strhodes obj = cfg_tuple_get(ent, "ordering"); 989135446Strhodes INSIST(cfg_obj_isstring(obj)); 990135446Strhodes str = cfg_obj_asstring(obj); 991135446Strhodes if (!strcasecmp(str, "fixed")) 992135446Strhodes mode = DNS_RDATASETATTR_FIXEDORDER; 993135446Strhodes else if (!strcasecmp(str, "random")) 994135446Strhodes mode = DNS_RDATASETATTR_RANDOMIZE; 995135446Strhodes else if (!strcasecmp(str, "cyclic")) 996135446Strhodes mode = 0; 997135446Strhodes else 998135446Strhodes INSIST(0); 999135446Strhodes 1000143731Sdougb /* 1001143731Sdougb * "*" should match everything including the root (BIND 8 compat). 1002143731Sdougb * As dns_name_matcheswildcard(".", "*.") returns FALSE add a 1003165071Sdougb * explicit entry for "." when the name is "*". 1004143731Sdougb */ 1005143731Sdougb if (addroot) { 1006143731Sdougb result = dns_order_add(order, dns_rootname, 1007143731Sdougb rdtype, rdclass, mode); 1008143731Sdougb if (result != ISC_R_SUCCESS) 1009143731Sdougb return (result); 1010143731Sdougb } 1011143731Sdougb 1012135446Strhodes return (dns_order_add(order, dns_fixedname_name(&fixed), 1013135446Strhodes rdtype, rdclass, mode)); 1014135446Strhodes} 1015135446Strhodes 1016135446Strhodesstatic isc_result_t 1017165071Sdougbconfigure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { 1018135446Strhodes isc_netaddr_t na; 1019135446Strhodes dns_peer_t *peer; 1020165071Sdougb const cfg_obj_t *obj; 1021165071Sdougb const char *str; 1022135446Strhodes isc_result_t result; 1023170222Sdougb unsigned int prefixlen; 1024135446Strhodes 1025170222Sdougb cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); 1026135446Strhodes 1027135446Strhodes peer = NULL; 1028186462Sdougb result = dns_peer_newprefix(mctx, &na, prefixlen, &peer); 1029135446Strhodes if (result != ISC_R_SUCCESS) 1030135446Strhodes return (result); 1031135446Strhodes 1032135446Strhodes obj = NULL; 1033135446Strhodes (void)cfg_map_get(cpeer, "bogus", &obj); 1034135446Strhodes if (obj != NULL) 1035135446Strhodes CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); 1036135446Strhodes 1037135446Strhodes obj = NULL; 1038135446Strhodes (void)cfg_map_get(cpeer, "provide-ixfr", &obj); 1039135446Strhodes if (obj != NULL) 1040135446Strhodes CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); 1041135446Strhodes 1042135446Strhodes obj = NULL; 1043135446Strhodes (void)cfg_map_get(cpeer, "request-ixfr", &obj); 1044135446Strhodes if (obj != NULL) 1045135446Strhodes CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); 1046135446Strhodes 1047135446Strhodes obj = NULL; 1048193149Sdougb (void)cfg_map_get(cpeer, "request-nsid", &obj); 1049193149Sdougb if (obj != NULL) 1050193149Sdougb CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); 1051193149Sdougb 1052193149Sdougb obj = NULL; 1053135446Strhodes (void)cfg_map_get(cpeer, "edns", &obj); 1054135446Strhodes if (obj != NULL) 1055135446Strhodes CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); 1056135446Strhodes 1057135446Strhodes obj = NULL; 1058170222Sdougb (void)cfg_map_get(cpeer, "edns-udp-size", &obj); 1059170222Sdougb if (obj != NULL) { 1060170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 1061170222Sdougb if (udpsize < 512) 1062170222Sdougb udpsize = 512; 1063170222Sdougb if (udpsize > 4096) 1064170222Sdougb udpsize = 4096; 1065170222Sdougb CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); 1066170222Sdougb } 1067170222Sdougb 1068170222Sdougb obj = NULL; 1069170222Sdougb (void)cfg_map_get(cpeer, "max-udp-size", &obj); 1070170222Sdougb if (obj != NULL) { 1071170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 1072170222Sdougb if (udpsize < 512) 1073170222Sdougb udpsize = 512; 1074170222Sdougb if (udpsize > 4096) 1075170222Sdougb udpsize = 4096; 1076170222Sdougb CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); 1077170222Sdougb } 1078170222Sdougb 1079170222Sdougb obj = NULL; 1080135446Strhodes (void)cfg_map_get(cpeer, "transfers", &obj); 1081135446Strhodes if (obj != NULL) 1082135446Strhodes CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); 1083135446Strhodes 1084135446Strhodes obj = NULL; 1085135446Strhodes (void)cfg_map_get(cpeer, "transfer-format", &obj); 1086135446Strhodes if (obj != NULL) { 1087135446Strhodes str = cfg_obj_asstring(obj); 1088135446Strhodes if (strcasecmp(str, "many-answers") == 0) 1089135446Strhodes CHECK(dns_peer_settransferformat(peer, 1090135446Strhodes dns_many_answers)); 1091135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 1092135446Strhodes CHECK(dns_peer_settransferformat(peer, 1093135446Strhodes dns_one_answer)); 1094135446Strhodes else 1095135446Strhodes INSIST(0); 1096135446Strhodes } 1097135446Strhodes 1098135446Strhodes obj = NULL; 1099135446Strhodes (void)cfg_map_get(cpeer, "keys", &obj); 1100135446Strhodes if (obj != NULL) { 1101135446Strhodes result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); 1102135446Strhodes if (result != ISC_R_SUCCESS) 1103135446Strhodes goto cleanup; 1104135446Strhodes } 1105135446Strhodes 1106135446Strhodes obj = NULL; 1107170222Sdougb if (na.family == AF_INET) 1108135446Strhodes (void)cfg_map_get(cpeer, "transfer-source", &obj); 1109135446Strhodes else 1110135446Strhodes (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); 1111135446Strhodes if (obj != NULL) { 1112135446Strhodes result = dns_peer_settransfersource(peer, 1113135446Strhodes cfg_obj_assockaddr(obj)); 1114135446Strhodes if (result != ISC_R_SUCCESS) 1115135446Strhodes goto cleanup; 1116170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1117135446Strhodes } 1118170222Sdougb 1119170222Sdougb obj = NULL; 1120170222Sdougb if (na.family == AF_INET) 1121170222Sdougb (void)cfg_map_get(cpeer, "notify-source", &obj); 1122170222Sdougb else 1123170222Sdougb (void)cfg_map_get(cpeer, "notify-source-v6", &obj); 1124170222Sdougb if (obj != NULL) { 1125170222Sdougb result = dns_peer_setnotifysource(peer, 1126170222Sdougb cfg_obj_assockaddr(obj)); 1127170222Sdougb if (result != ISC_R_SUCCESS) 1128170222Sdougb goto cleanup; 1129170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1130170222Sdougb } 1131170222Sdougb 1132170222Sdougb obj = NULL; 1133170222Sdougb if (na.family == AF_INET) 1134170222Sdougb (void)cfg_map_get(cpeer, "query-source", &obj); 1135170222Sdougb else 1136170222Sdougb (void)cfg_map_get(cpeer, "query-source-v6", &obj); 1137170222Sdougb if (obj != NULL) { 1138170222Sdougb result = dns_peer_setquerysource(peer, 1139170222Sdougb cfg_obj_assockaddr(obj)); 1140170222Sdougb if (result != ISC_R_SUCCESS) 1141170222Sdougb goto cleanup; 1142170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1143170222Sdougb } 1144170222Sdougb 1145135446Strhodes *peerp = peer; 1146135446Strhodes return (ISC_R_SUCCESS); 1147135446Strhodes 1148135446Strhodes cleanup: 1149135446Strhodes dns_peer_detach(&peer); 1150135446Strhodes return (result); 1151135446Strhodes} 1152135446Strhodes 1153135446Strhodesstatic isc_result_t 1154165071Sdougbdisable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { 1155135446Strhodes isc_result_t result; 1156165071Sdougb const cfg_obj_t *algorithms; 1157165071Sdougb const cfg_listelt_t *element; 1158135446Strhodes const char *str; 1159135446Strhodes dns_fixedname_t fixed; 1160135446Strhodes dns_name_t *name; 1161135446Strhodes isc_buffer_t b; 1162135446Strhodes 1163135446Strhodes dns_fixedname_init(&fixed); 1164135446Strhodes name = dns_fixedname_name(&fixed); 1165135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); 1166135446Strhodes isc_buffer_init(&b, str, strlen(str)); 1167135446Strhodes isc_buffer_add(&b, strlen(str)); 1168224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 1169135446Strhodes 1170135446Strhodes algorithms = cfg_tuple_get(disabled, "algorithms"); 1171135446Strhodes for (element = cfg_list_first(algorithms); 1172135446Strhodes element != NULL; 1173135446Strhodes element = cfg_list_next(element)) 1174135446Strhodes { 1175135446Strhodes isc_textregion_t r; 1176135446Strhodes dns_secalg_t alg; 1177135446Strhodes 1178165071Sdougb DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 1179135446Strhodes r.length = strlen(r.base); 1180135446Strhodes 1181135446Strhodes result = dns_secalg_fromtext(&alg, &r); 1182135446Strhodes if (result != ISC_R_SUCCESS) { 1183135446Strhodes isc_uint8_t ui; 1184135446Strhodes result = isc_parse_uint8(&ui, r.base, 10); 1185135446Strhodes alg = ui; 1186135446Strhodes } 1187135446Strhodes if (result != ISC_R_SUCCESS) { 1188135446Strhodes cfg_obj_log(cfg_listelt_value(element), 1189135446Strhodes ns_g_lctx, ISC_LOG_ERROR, 1190135446Strhodes "invalid algorithm"); 1191135446Strhodes CHECK(result); 1192135446Strhodes } 1193135446Strhodes CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); 1194135446Strhodes } 1195135446Strhodes cleanup: 1196135446Strhodes return (result); 1197135446Strhodes} 1198135446Strhodes 1199170222Sdougbstatic isc_boolean_t 1200170222Sdougbon_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { 1201170222Sdougb const cfg_listelt_t *element; 1202170222Sdougb dns_fixedname_t fixed; 1203170222Sdougb dns_name_t *name; 1204170222Sdougb isc_result_t result; 1205170222Sdougb const cfg_obj_t *value; 1206170222Sdougb const char *str; 1207170222Sdougb isc_buffer_t b; 1208170222Sdougb 1209170222Sdougb dns_fixedname_init(&fixed); 1210170222Sdougb name = dns_fixedname_name(&fixed); 1211186462Sdougb 1212170222Sdougb for (element = cfg_list_first(disablelist); 1213170222Sdougb element != NULL; 1214170222Sdougb element = cfg_list_next(element)) 1215170222Sdougb { 1216170222Sdougb value = cfg_listelt_value(element); 1217170222Sdougb str = cfg_obj_asstring(value); 1218170222Sdougb isc_buffer_init(&b, str, strlen(str)); 1219170222Sdougb isc_buffer_add(&b, strlen(str)); 1220170222Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 1221224092Sdougb 0, NULL); 1222170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 1223170222Sdougb if (dns_name_equal(name, zonename)) 1224170222Sdougb return (ISC_TRUE); 1225170222Sdougb } 1226170222Sdougb return (ISC_FALSE); 1227170222Sdougb} 1228170222Sdougb 1229170222Sdougbstatic void 1230170222Sdougbcheck_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, 1231170222Sdougb isc_mem_t *mctx) 1232170222Sdougb{ 1233170222Sdougb char **argv = NULL; 1234170222Sdougb unsigned int i; 1235170222Sdougb isc_result_t result; 1236170222Sdougb 1237170222Sdougb result = dns_zone_getdbtype(*zonep, &argv, mctx); 1238170222Sdougb if (result != ISC_R_SUCCESS) { 1239170222Sdougb dns_zone_detach(zonep); 1240170222Sdougb return; 1241170222Sdougb } 1242170222Sdougb 1243170222Sdougb /* 1244170222Sdougb * Check that all the arguments match. 1245170222Sdougb */ 1246170222Sdougb for (i = 0; i < dbtypec; i++) 1247170222Sdougb if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { 1248170222Sdougb dns_zone_detach(zonep); 1249170222Sdougb break; 1250170222Sdougb } 1251170222Sdougb 1252170222Sdougb /* 1253170222Sdougb * Check that there are not extra arguments. 1254170222Sdougb */ 1255170222Sdougb if (i == dbtypec && argv[i] != NULL) 1256170222Sdougb dns_zone_detach(zonep); 1257170222Sdougb isc_mem_free(mctx, argv); 1258170222Sdougb} 1259170222Sdougb 1260193149Sdougbstatic isc_result_t 1261193149Sdougbsetquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) { 1262193149Sdougb isc_result_t result; 1263193149Sdougb isc_stats_t *zoneqrystats; 1264170222Sdougb 1265193149Sdougb zoneqrystats = NULL; 1266193149Sdougb if (on) { 1267193149Sdougb result = isc_stats_create(mctx, &zoneqrystats, 1268193149Sdougb dns_nsstatscounter_max); 1269193149Sdougb if (result != ISC_R_SUCCESS) 1270193149Sdougb return (result); 1271193149Sdougb } 1272193149Sdougb dns_zone_setrequeststats(zone, zoneqrystats); 1273193149Sdougb if (zoneqrystats != NULL) 1274193149Sdougb isc_stats_detach(&zoneqrystats); 1275193149Sdougb 1276193149Sdougb return (ISC_R_SUCCESS); 1277193149Sdougb} 1278193149Sdougb 1279224092Sdougbstatic ns_cache_t * 1280224092Sdougbcachelist_find(ns_cachelist_t *cachelist, const char *cachename) { 1281224092Sdougb ns_cache_t *nsc; 1282224092Sdougb 1283224092Sdougb for (nsc = ISC_LIST_HEAD(*cachelist); 1284224092Sdougb nsc != NULL; 1285224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 1286224092Sdougb if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0) 1287224092Sdougb return (nsc); 1288224092Sdougb } 1289224092Sdougb 1290224092Sdougb return (NULL); 1291224092Sdougb} 1292224092Sdougb 1293193149Sdougbstatic isc_boolean_t 1294193149Sdougbcache_reusable(dns_view_t *originview, dns_view_t *view, 1295193149Sdougb isc_boolean_t new_zero_no_soattl) 1296193149Sdougb{ 1297193149Sdougb if (originview->checknames != view->checknames || 1298193149Sdougb dns_resolver_getzeronosoattl(originview->resolver) != 1299193149Sdougb new_zero_no_soattl || 1300193149Sdougb originview->acceptexpired != view->acceptexpired || 1301193149Sdougb originview->enablevalidation != view->enablevalidation || 1302193149Sdougb originview->maxcachettl != view->maxcachettl || 1303193149Sdougb originview->maxncachettl != view->maxncachettl) { 1304193149Sdougb return (ISC_FALSE); 1305193149Sdougb } 1306193149Sdougb 1307193149Sdougb return (ISC_TRUE); 1308193149Sdougb} 1309193149Sdougb 1310224092Sdougbstatic isc_boolean_t 1311224092Sdougbcache_sharable(dns_view_t *originview, dns_view_t *view, 1312224092Sdougb isc_boolean_t new_zero_no_soattl, 1313224092Sdougb unsigned int new_cleaning_interval, 1314224092Sdougb isc_uint32_t new_max_cache_size) 1315224092Sdougb{ 1316224092Sdougb /* 1317224092Sdougb * If the cache cannot even reused for the same view, it cannot be 1318224092Sdougb * shared with other views. 1319224092Sdougb */ 1320224092Sdougb if (!cache_reusable(originview, view, new_zero_no_soattl)) 1321224092Sdougb return (ISC_FALSE); 1322224092Sdougb 1323224092Sdougb /* 1324224092Sdougb * Check other cache related parameters that must be consistent among 1325224092Sdougb * the sharing views. 1326224092Sdougb */ 1327224092Sdougb if (dns_cache_getcleaninginterval(originview->cache) != 1328224092Sdougb new_cleaning_interval || 1329224092Sdougb dns_cache_getcachesize(originview->cache) != new_max_cache_size) { 1330224092Sdougb return (ISC_FALSE); 1331224092Sdougb } 1332224092Sdougb 1333224092Sdougb return (ISC_TRUE); 1334224092Sdougb} 1335224092Sdougb 1336135446Strhodes/* 1337224092Sdougb * Callback from DLZ configure when the driver sets up a writeable zone 1338224092Sdougb */ 1339224092Sdougbstatic isc_result_t 1340224092Sdougbdlzconfigure_callback(dns_view_t *view, dns_zone_t *zone) { 1341224092Sdougb dns_name_t *origin = dns_zone_getorigin(zone); 1342224092Sdougb dns_rdataclass_t zclass = view->rdclass; 1343224092Sdougb isc_result_t result; 1344224092Sdougb 1345224092Sdougb result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone); 1346224092Sdougb if (result != ISC_R_SUCCESS) 1347224092Sdougb return result; 1348224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 1349224092Sdougb 1350224092Sdougb return ns_zone_configure_writeable_dlz(view->dlzdatabase, 1351224092Sdougb zone, zclass, origin); 1352224092Sdougb} 1353224092Sdougb 1354224092Sdougbstatic isc_result_t 1355224092Sdougbdns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na, 1356224092Sdougb unsigned int prefixlen, const char *server, 1357224092Sdougb const char *contact) 1358224092Sdougb{ 1359224092Sdougb char *cp; 1360224092Sdougb char reverse[48+sizeof("ip6.arpa.")]; 1361224092Sdougb const char *dns64_dbtype[4] = { "_builtin", "dns64", ".", "." }; 1362224092Sdougb const char *sep = ": view "; 1363224092Sdougb const char *viewname = view->name; 1364224092Sdougb const unsigned char *s6; 1365224092Sdougb dns_fixedname_t fixed; 1366224092Sdougb dns_name_t *name; 1367224092Sdougb dns_zone_t *zone = NULL; 1368224092Sdougb int dns64_dbtypec = 4; 1369224092Sdougb isc_buffer_t b; 1370224092Sdougb isc_result_t result; 1371224092Sdougb 1372224092Sdougb REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || 1373224092Sdougb prefixlen == 56 || prefixlen == 64 || prefixlen == 96); 1374224092Sdougb 1375224092Sdougb if (!strcmp(viewname, "_default")) { 1376224092Sdougb sep = ""; 1377224092Sdougb viewname = ""; 1378224092Sdougb } 1379224092Sdougb 1380224092Sdougb /* 1381224092Sdougb * Construct the reverse name of the zone. 1382224092Sdougb */ 1383224092Sdougb cp = reverse; 1384224092Sdougb s6 = na->type.in6.s6_addr; 1385224092Sdougb while (prefixlen > 0) { 1386224092Sdougb prefixlen -= 8; 1387224092Sdougb sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf, 1388224092Sdougb (s6[prefixlen/8] >> 4) & 0xf); 1389224092Sdougb cp += 4; 1390224092Sdougb } 1391224092Sdougb strcat(cp, "ip6.arpa."); 1392224092Sdougb 1393224092Sdougb /* 1394224092Sdougb * Create the actual zone. 1395224092Sdougb */ 1396224092Sdougb if (server != NULL) 1397224092Sdougb dns64_dbtype[2] = server; 1398224092Sdougb if (contact != NULL) 1399224092Sdougb dns64_dbtype[3] = contact; 1400224092Sdougb dns_fixedname_init(&fixed); 1401224092Sdougb name = dns_fixedname_name(&fixed); 1402224092Sdougb isc_buffer_init(&b, reverse, strlen(reverse)); 1403224092Sdougb isc_buffer_add(&b, strlen(reverse)); 1404224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 1405224092Sdougb CHECK(dns_zone_create(&zone, mctx)); 1406224092Sdougb CHECK(dns_zone_setorigin(zone, name)); 1407224092Sdougb dns_zone_setview(zone, view); 1408224092Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1409224092Sdougb dns_zone_setclass(zone, view->rdclass); 1410224092Sdougb dns_zone_settype(zone, dns_zone_master); 1411224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 1412224092Sdougb CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype)); 1413224092Sdougb if (view->queryacl != NULL) 1414224092Sdougb dns_zone_setqueryacl(zone, view->queryacl); 1415224092Sdougb if (view->queryonacl != NULL) 1416224092Sdougb dns_zone_setqueryonacl(zone, view->queryonacl); 1417224092Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 1418224092Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 1419224092Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 1420224092Sdougb CHECK(setquerystats(zone, mctx, ISC_FALSE)); /* XXXMPA */ 1421224092Sdougb CHECK(dns_view_addzone(view, zone)); 1422224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 1423224092Sdougb ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep, 1424224092Sdougb viewname, reverse); 1425224092Sdougb 1426224092Sdougbcleanup: 1427224092Sdougb if (zone != NULL) 1428224092Sdougb dns_zone_detach(&zone); 1429224092Sdougb return (result); 1430224092Sdougb} 1431224092Sdougb 1432224092Sdougbstatic isc_result_t 1433224092Sdougbconfigure_rpz(dns_view_t *view, const cfg_listelt_t *element) { 1434224092Sdougb const cfg_obj_t *rpz_obj, *policy_obj; 1435224092Sdougb const char *str; 1436224092Sdougb dns_fixedname_t fixed; 1437224092Sdougb dns_name_t *origin; 1438224092Sdougb dns_rpz_zone_t *old, *new; 1439224092Sdougb dns_zone_t *zone = NULL; 1440224092Sdougb isc_result_t result; 1441224092Sdougb unsigned int l1, l2; 1442224092Sdougb 1443224092Sdougb new = isc_mem_get(view->mctx, sizeof(*new)); 1444224092Sdougb if (new == NULL) { 1445224092Sdougb result = ISC_R_NOMEMORY; 1446224092Sdougb goto cleanup; 1447224092Sdougb } 1448224092Sdougb 1449224092Sdougb memset(new, 0, sizeof(*new)); 1450224092Sdougb dns_name_init(&new->nsdname, NULL); 1451224092Sdougb dns_name_init(&new->origin, NULL); 1452224092Sdougb dns_name_init(&new->cname, NULL); 1453224092Sdougb ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link); 1454224092Sdougb 1455224092Sdougb rpz_obj = cfg_listelt_value(element); 1456224092Sdougb policy_obj = cfg_tuple_get(rpz_obj, "policy"); 1457224092Sdougb if (cfg_obj_isvoid(policy_obj)) { 1458224092Sdougb new->policy = DNS_RPZ_POLICY_GIVEN; 1459224092Sdougb } else { 1460224092Sdougb str = cfg_obj_asstring(policy_obj); 1461224092Sdougb new->policy = dns_rpz_str2policy(str); 1462224092Sdougb INSIST(new->policy != DNS_RPZ_POLICY_ERROR); 1463224092Sdougb } 1464224092Sdougb 1465224092Sdougb dns_fixedname_init(&fixed); 1466224092Sdougb origin = dns_fixedname_name(&fixed); 1467224092Sdougb str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "name")); 1468224092Sdougb result = dns_name_fromstring(origin, str, DNS_NAME_DOWNCASE, NULL); 1469224092Sdougb if (result != ISC_R_SUCCESS) { 1470224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1471224092Sdougb "invalid zone '%s'", str); 1472224092Sdougb goto cleanup; 1473224092Sdougb } 1474224092Sdougb 1475224092Sdougb result = dns_name_fromstring2(&new->nsdname, DNS_RPZ_NSDNAME_ZONE, 1476224092Sdougb origin, DNS_NAME_DOWNCASE, view->mctx); 1477224092Sdougb if (result != ISC_R_SUCCESS) { 1478224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1479224092Sdougb "invalid zone '%s'", str); 1480224092Sdougb goto cleanup; 1481224092Sdougb } 1482224092Sdougb 1483224092Sdougb /* 1484224092Sdougb * The origin is part of 'nsdname' so we don't need to keep it 1485224092Sdougb * seperately. 1486224092Sdougb */ 1487224092Sdougb l1 = dns_name_countlabels(&new->nsdname); 1488224092Sdougb l2 = dns_name_countlabels(origin); 1489224092Sdougb dns_name_getlabelsequence(&new->nsdname, l1 - l2, l2, &new->origin); 1490224092Sdougb 1491224092Sdougb /* 1492224092Sdougb * Are we configured to with the reponse policy zone? 1493224092Sdougb */ 1494224092Sdougb result = dns_view_findzone(view, &new->origin, &zone); 1495224092Sdougb if (result != ISC_R_SUCCESS) { 1496224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1497224092Sdougb "unknown zone '%s'", str); 1498224092Sdougb goto cleanup; 1499224092Sdougb } 1500224092Sdougb 1501224092Sdougb if (dns_zone_gettype(zone) != dns_zone_master && 1502224092Sdougb dns_zone_gettype(zone) != dns_zone_slave) { 1503224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1504224092Sdougb "zone '%s' is neither master nor slave", str); 1505224092Sdougb dns_zone_detach(&zone); 1506224092Sdougb result = DNS_R_NOTMASTER; 1507224092Sdougb goto cleanup; 1508224092Sdougb } 1509224092Sdougb dns_zone_detach(&zone); 1510224092Sdougb 1511224092Sdougb for (old = ISC_LIST_HEAD(view->rpz_zones); 1512224092Sdougb old != new; 1513224092Sdougb old = ISC_LIST_NEXT(old, link)) { 1514224092Sdougb ++new->num; 1515224092Sdougb if (dns_name_equal(&old->origin, &new->origin)) { 1516224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1517224092Sdougb "duplicate '%s'", str); 1518224092Sdougb result = DNS_R_DUPLICATE; 1519224092Sdougb goto cleanup; 1520224092Sdougb } 1521224092Sdougb } 1522224092Sdougb 1523224092Sdougb if (new->policy == DNS_RPZ_POLICY_CNAME) { 1524224092Sdougb str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "cname")); 1525224092Sdougb result = dns_name_fromstring(&new->cname, str, 0, view->mctx); 1526224092Sdougb if (result != ISC_R_SUCCESS) { 1527224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1528224092Sdougb "invalid cname '%s'", str); 1529224092Sdougb goto cleanup; 1530224092Sdougb } 1531224092Sdougb } 1532224092Sdougb 1533224092Sdougb return (ISC_R_SUCCESS); 1534224092Sdougb 1535224092Sdougb cleanup: 1536224092Sdougb dns_rpz_view_destroy(view); 1537224092Sdougb return (result); 1538224092Sdougb} 1539224092Sdougb 1540224092Sdougb/* 1541135446Strhodes * Configure 'view' according to 'vconfig', taking defaults from 'config' 1542135446Strhodes * where values are missing in 'vconfig'. 1543135446Strhodes * 1544135446Strhodes * When configuring the default view, 'vconfig' will be NULL and the 1545135446Strhodes * global defaults in 'config' used exclusively. 1546135446Strhodes */ 1547135446Strhodesstatic isc_result_t 1548225361Sdougbconfigure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 1549224092Sdougb ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys, 1550224092Sdougb isc_mem_t *mctx, cfg_aclconfctx_t *actx, 1551224092Sdougb isc_boolean_t need_hints) 1552135446Strhodes{ 1553165071Sdougb const cfg_obj_t *maps[4]; 1554165071Sdougb const cfg_obj_t *cfgmaps[3]; 1555224092Sdougb const cfg_obj_t *optionmaps[3]; 1556165071Sdougb const cfg_obj_t *options = NULL; 1557165071Sdougb const cfg_obj_t *voptions = NULL; 1558165071Sdougb const cfg_obj_t *forwardtype; 1559165071Sdougb const cfg_obj_t *forwarders; 1560165071Sdougb const cfg_obj_t *alternates; 1561165071Sdougb const cfg_obj_t *zonelist; 1562186462Sdougb const cfg_obj_t *dlz; 1563186462Sdougb unsigned int dlzargc; 1564186462Sdougb char **dlzargv; 1565165071Sdougb const cfg_obj_t *disabled; 1566165071Sdougb const cfg_obj_t *obj; 1567165071Sdougb const cfg_listelt_t *element; 1568135446Strhodes in_port_t port; 1569135446Strhodes dns_cache_t *cache = NULL; 1570135446Strhodes isc_result_t result; 1571135446Strhodes isc_uint32_t max_adb_size; 1572224092Sdougb unsigned int cleaning_interval; 1573135446Strhodes isc_uint32_t max_cache_size; 1574170222Sdougb isc_uint32_t max_acache_size; 1575135446Strhodes isc_uint32_t lame_ttl; 1576224092Sdougb dns_tsig_keyring_t *ring = NULL; 1577135446Strhodes dns_view_t *pview = NULL; /* Production view */ 1578225361Sdougb isc_mem_t *cmctx = NULL, *hmctx = NULL; 1579135446Strhodes dns_dispatch_t *dispatch4 = NULL; 1580135446Strhodes dns_dispatch_t *dispatch6 = NULL; 1581135446Strhodes isc_boolean_t reused_cache = ISC_FALSE; 1582224092Sdougb isc_boolean_t shared_cache = ISC_FALSE; 1583224092Sdougb int i = 0, j = 0, k = 0; 1584135446Strhodes const char *str; 1585224092Sdougb const char *cachename = NULL; 1586135446Strhodes dns_order_t *order = NULL; 1587135446Strhodes isc_uint32_t udpsize; 1588193149Sdougb unsigned int resopts = 0; 1589170222Sdougb dns_zone_t *zone = NULL; 1590170222Sdougb isc_uint32_t max_clients_per_query; 1591170222Sdougb const char *sep = ": view "; 1592170222Sdougb const char *viewname = view->name; 1593170222Sdougb const char *forview = " for view "; 1594170222Sdougb isc_boolean_t rfc1918; 1595170222Sdougb isc_boolean_t empty_zones_enable; 1596170222Sdougb const cfg_obj_t *disablelist = NULL; 1597193149Sdougb isc_stats_t *resstats = NULL; 1598193149Sdougb dns_stats_t *resquerystats = NULL; 1599224092Sdougb isc_boolean_t auto_dlv = ISC_FALSE; 1600224092Sdougb isc_boolean_t auto_root = ISC_FALSE; 1601224092Sdougb ns_cache_t *nsc; 1602193149Sdougb isc_boolean_t zero_no_soattl; 1603224092Sdougb dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; 1604224092Sdougb unsigned int query_timeout; 1605225361Sdougb struct cfg_context *nzctx; 1606135446Strhodes 1607135446Strhodes REQUIRE(DNS_VIEW_VALID(view)); 1608135446Strhodes 1609135446Strhodes if (config != NULL) 1610135446Strhodes (void)cfg_map_get(config, "options", &options); 1611135446Strhodes 1612224092Sdougb /* 1613224092Sdougb * maps: view options, options, defaults 1614224092Sdougb * cfgmaps: view options, config 1615224092Sdougb * optionmaps: view options, options 1616224092Sdougb */ 1617135446Strhodes if (vconfig != NULL) { 1618135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 1619135446Strhodes maps[i++] = voptions; 1620224092Sdougb optionmaps[j++] = voptions; 1621224092Sdougb cfgmaps[k++] = voptions; 1622135446Strhodes } 1623224092Sdougb if (options != NULL) { 1624135446Strhodes maps[i++] = options; 1625224092Sdougb optionmaps[j++] = options; 1626224092Sdougb } 1627224092Sdougb 1628135446Strhodes maps[i++] = ns_g_defaults; 1629135446Strhodes maps[i] = NULL; 1630224092Sdougb optionmaps[j] = NULL; 1631135446Strhodes if (config != NULL) 1632224092Sdougb cfgmaps[k++] = config; 1633224092Sdougb cfgmaps[k] = NULL; 1634135446Strhodes 1635170222Sdougb if (!strcmp(viewname, "_default")) { 1636170222Sdougb sep = ""; 1637170222Sdougb viewname = ""; 1638170222Sdougb forview = ""; 1639225361Sdougb POST(forview); 1640170222Sdougb } 1641170222Sdougb 1642135446Strhodes /* 1643135446Strhodes * Set the view's port number for outgoing queries. 1644135446Strhodes */ 1645135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 1646135446Strhodes dns_view_setdstport(view, port); 1647135446Strhodes 1648135446Strhodes /* 1649170222Sdougb * Create additional cache for this view and zones under the view 1650170222Sdougb * if explicitly enabled. 1651170222Sdougb * XXX950 default to on. 1652170222Sdougb */ 1653170222Sdougb obj = NULL; 1654170222Sdougb (void)ns_config_get(maps, "acache-enable", &obj); 1655170222Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) { 1656170222Sdougb cmctx = NULL; 1657170222Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 1658170222Sdougb CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, 1659170222Sdougb ns_g_timermgr)); 1660193149Sdougb isc_mem_setname(cmctx, "acache", NULL); 1661170222Sdougb isc_mem_detach(&cmctx); 1662170222Sdougb } 1663170222Sdougb if (view->acache != NULL) { 1664170222Sdougb obj = NULL; 1665170222Sdougb result = ns_config_get(maps, "acache-cleaning-interval", &obj); 1666170222Sdougb INSIST(result == ISC_R_SUCCESS); 1667170222Sdougb dns_acache_setcleaninginterval(view->acache, 1668170222Sdougb cfg_obj_asuint32(obj) * 60); 1669170222Sdougb 1670170222Sdougb obj = NULL; 1671170222Sdougb result = ns_config_get(maps, "max-acache-size", &obj); 1672170222Sdougb INSIST(result == ISC_R_SUCCESS); 1673170222Sdougb if (cfg_obj_isstring(obj)) { 1674170222Sdougb str = cfg_obj_asstring(obj); 1675170222Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 1676170222Sdougb max_acache_size = ISC_UINT32_MAX; 1677170222Sdougb } else { 1678170222Sdougb isc_resourcevalue_t value; 1679170222Sdougb 1680170222Sdougb value = cfg_obj_asuint64(obj); 1681170222Sdougb if (value > ISC_UINT32_MAX) { 1682170222Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1683170222Sdougb "'max-acache-size " 1684170222Sdougb "%" ISC_PRINT_QUADFORMAT 1685170222Sdougb "d' is too large", 1686170222Sdougb value); 1687170222Sdougb result = ISC_R_RANGE; 1688170222Sdougb goto cleanup; 1689170222Sdougb } 1690170222Sdougb max_acache_size = (isc_uint32_t)value; 1691170222Sdougb } 1692170222Sdougb dns_acache_setcachesize(view->acache, max_acache_size); 1693170222Sdougb } 1694170222Sdougb 1695224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx, 1696216175Sdougb ns_g_mctx, &view->queryacl)); 1697216175Sdougb if (view->queryacl == NULL) { 1698224092Sdougb CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", 1699224092Sdougb NULL, actx, ns_g_mctx, 1700224092Sdougb &view->queryacl)); 1701216175Sdougb } 1702216175Sdougb 1703170222Sdougb /* 1704135446Strhodes * Configure the zones. 1705135446Strhodes */ 1706135446Strhodes zonelist = NULL; 1707135446Strhodes if (voptions != NULL) 1708135446Strhodes (void)cfg_map_get(voptions, "zone", &zonelist); 1709135446Strhodes else 1710135446Strhodes (void)cfg_map_get(config, "zone", &zonelist); 1711225361Sdougb 1712225361Sdougb /* 1713225361Sdougb * Load zone configuration 1714225361Sdougb */ 1715135446Strhodes for (element = cfg_list_first(zonelist); 1716135446Strhodes element != NULL; 1717135446Strhodes element = cfg_list_next(element)) 1718135446Strhodes { 1719165071Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 1720135446Strhodes CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 1721224092Sdougb actx, ISC_FALSE)); 1722135446Strhodes } 1723135446Strhodes 1724224092Sdougb /* 1725224092Sdougb * If we're allowing added zones, then load zone configuration 1726224092Sdougb * from the newzone file for zones that were added during previous 1727224092Sdougb * runs. 1728224092Sdougb */ 1729225361Sdougb nzctx = view->new_zone_config; 1730225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) { 1731224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1732224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 1733224092Sdougb "loading additional zones for view '%s'", 1734224092Sdougb view->name); 1735224092Sdougb 1736225361Sdougb zonelist = NULL; 1737225361Sdougb cfg_map_get(nzctx->nzconfig, "zone", &zonelist); 1738225361Sdougb 1739225361Sdougb for (element = cfg_list_first(zonelist); 1740225361Sdougb element != NULL; 1741225361Sdougb element = cfg_list_next(element)) 1742225361Sdougb { 1743225361Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 1744225361Sdougb CHECK(configure_zone(config, zconfig, vconfig, 1745225361Sdougb mctx, view, actx, 1746225361Sdougb ISC_TRUE)); 1747224092Sdougb } 1748224092Sdougb } 1749224092Sdougb 1750135446Strhodes /* 1751170222Sdougb * Create Dynamically Loadable Zone driver. 1752170222Sdougb */ 1753170222Sdougb dlz = NULL; 1754170222Sdougb if (voptions != NULL) 1755170222Sdougb (void)cfg_map_get(voptions, "dlz", &dlz); 1756170222Sdougb else 1757170222Sdougb (void)cfg_map_get(config, "dlz", &dlz); 1758170222Sdougb 1759170222Sdougb obj = NULL; 1760170222Sdougb if (dlz != NULL) { 1761170222Sdougb (void)cfg_map_get(cfg_tuple_get(dlz, "options"), 1762170222Sdougb "database", &obj); 1763170222Sdougb if (obj != NULL) { 1764170222Sdougb char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); 1765170222Sdougb if (s == NULL) { 1766170222Sdougb result = ISC_R_NOMEMORY; 1767170222Sdougb goto cleanup; 1768170222Sdougb } 1769186462Sdougb 1770170222Sdougb result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); 1771170222Sdougb if (result != ISC_R_SUCCESS) { 1772170222Sdougb isc_mem_free(mctx, s); 1773170222Sdougb goto cleanup; 1774170222Sdougb } 1775170222Sdougb 1776170222Sdougb obj = cfg_tuple_get(dlz, "name"); 1777170222Sdougb result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), 1778170222Sdougb dlzargv[0], dlzargc, dlzargv, 1779170222Sdougb &view->dlzdatabase); 1780170222Sdougb isc_mem_free(mctx, s); 1781170222Sdougb isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); 1782170222Sdougb if (result != ISC_R_SUCCESS) 1783170222Sdougb goto cleanup; 1784224092Sdougb 1785224092Sdougb /* 1786224092Sdougb * If the dlz backend supports configuration, 1787224092Sdougb * then call its configure method now. 1788224092Sdougb */ 1789224092Sdougb result = dns_dlzconfigure(view, dlzconfigure_callback); 1790224092Sdougb if (result != ISC_R_SUCCESS) 1791224092Sdougb goto cleanup; 1792170222Sdougb } 1793170222Sdougb } 1794170222Sdougb 1795170222Sdougb /* 1796193149Sdougb * Obtain configuration parameters that affect the decision of whether 1797193149Sdougb * we can reuse/share an existing cache. 1798193149Sdougb */ 1799224092Sdougb obj = NULL; 1800224092Sdougb result = ns_config_get(maps, "cleaning-interval", &obj); 1801224092Sdougb INSIST(result == ISC_R_SUCCESS); 1802224092Sdougb cleaning_interval = cfg_obj_asuint32(obj) * 60; 1803224092Sdougb 1804224092Sdougb obj = NULL; 1805224092Sdougb result = ns_config_get(maps, "max-cache-size", &obj); 1806224092Sdougb INSIST(result == ISC_R_SUCCESS); 1807224092Sdougb if (cfg_obj_isstring(obj)) { 1808224092Sdougb str = cfg_obj_asstring(obj); 1809224092Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 1810224092Sdougb max_cache_size = ISC_UINT32_MAX; 1811224092Sdougb } else { 1812224092Sdougb isc_resourcevalue_t value; 1813224092Sdougb value = cfg_obj_asuint64(obj); 1814224092Sdougb if (value > ISC_UINT32_MAX) { 1815224092Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1816224092Sdougb "'max-cache-size " 1817224092Sdougb "%" ISC_PRINT_QUADFORMAT "d' is too large", 1818224092Sdougb value); 1819224092Sdougb result = ISC_R_RANGE; 1820224092Sdougb goto cleanup; 1821224092Sdougb } 1822224092Sdougb max_cache_size = (isc_uint32_t)value; 1823224092Sdougb } 1824224092Sdougb 1825193149Sdougb /* Check-names. */ 1826193149Sdougb obj = NULL; 1827193149Sdougb result = ns_checknames_get(maps, "response", &obj); 1828193149Sdougb INSIST(result == ISC_R_SUCCESS); 1829193149Sdougb 1830193149Sdougb str = cfg_obj_asstring(obj); 1831193149Sdougb if (strcasecmp(str, "fail") == 0) { 1832193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES | 1833193149Sdougb DNS_RESOLVER_CHECKNAMESFAIL; 1834193149Sdougb view->checknames = ISC_TRUE; 1835193149Sdougb } else if (strcasecmp(str, "warn") == 0) { 1836193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES; 1837193149Sdougb view->checknames = ISC_FALSE; 1838193149Sdougb } else if (strcasecmp(str, "ignore") == 0) { 1839193149Sdougb view->checknames = ISC_FALSE; 1840193149Sdougb } else 1841193149Sdougb INSIST(0); 1842193149Sdougb 1843193149Sdougb obj = NULL; 1844193149Sdougb result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); 1845193149Sdougb INSIST(result == ISC_R_SUCCESS); 1846193149Sdougb zero_no_soattl = cfg_obj_asboolean(obj); 1847193149Sdougb 1848193149Sdougb obj = NULL; 1849224092Sdougb result = ns_config_get(maps, "dns64", &obj); 1850224092Sdougb if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") && 1851224092Sdougb strcmp(view->name, "_meta")) { 1852224092Sdougb const cfg_listelt_t *element; 1853224092Sdougb isc_netaddr_t na, suffix, *sp; 1854224092Sdougb unsigned int prefixlen; 1855224092Sdougb const char *server, *contact; 1856224092Sdougb const cfg_obj_t *myobj; 1857224092Sdougb 1858224092Sdougb myobj = NULL; 1859224092Sdougb result = ns_config_get(maps, "dns64-server", &myobj); 1860224092Sdougb if (result == ISC_R_SUCCESS) 1861224092Sdougb server = cfg_obj_asstring(myobj); 1862224092Sdougb else 1863224092Sdougb server = NULL; 1864224092Sdougb 1865224092Sdougb myobj = NULL; 1866224092Sdougb result = ns_config_get(maps, "dns64-contact", &myobj); 1867224092Sdougb if (result == ISC_R_SUCCESS) 1868224092Sdougb contact = cfg_obj_asstring(myobj); 1869224092Sdougb else 1870224092Sdougb contact = NULL; 1871224092Sdougb 1872224092Sdougb for (element = cfg_list_first(obj); 1873224092Sdougb element != NULL; 1874224092Sdougb element = cfg_list_next(element)) 1875224092Sdougb { 1876224092Sdougb const cfg_obj_t *map = cfg_listelt_value(element); 1877224092Sdougb dns_dns64_t *dns64 = NULL; 1878224092Sdougb unsigned int dns64options = 0; 1879224092Sdougb 1880224092Sdougb cfg_obj_asnetprefix(cfg_map_getname(map), &na, 1881224092Sdougb &prefixlen); 1882224092Sdougb 1883224092Sdougb obj = NULL; 1884224092Sdougb (void)cfg_map_get(map, "suffix", &obj); 1885224092Sdougb if (obj != NULL) { 1886224092Sdougb sp = &suffix; 1887224092Sdougb isc_netaddr_fromsockaddr(sp, 1888224092Sdougb cfg_obj_assockaddr(obj)); 1889224092Sdougb } else 1890224092Sdougb sp = NULL; 1891224092Sdougb 1892224092Sdougb clients = mapped = excluded = NULL; 1893224092Sdougb obj = NULL; 1894224092Sdougb (void)cfg_map_get(map, "clients", &obj); 1895224092Sdougb if (obj != NULL) { 1896224092Sdougb result = cfg_acl_fromconfig(obj, config, 1897224092Sdougb ns_g_lctx, actx, 1898224092Sdougb mctx, 0, &clients); 1899224092Sdougb if (result != ISC_R_SUCCESS) 1900224092Sdougb goto cleanup; 1901224092Sdougb } 1902224092Sdougb obj = NULL; 1903224092Sdougb (void)cfg_map_get(map, "mapped", &obj); 1904224092Sdougb if (obj != NULL) { 1905224092Sdougb result = cfg_acl_fromconfig(obj, config, 1906224092Sdougb ns_g_lctx, actx, 1907224092Sdougb mctx, 0, &mapped); 1908224092Sdougb if (result != ISC_R_SUCCESS) 1909224092Sdougb goto cleanup; 1910224092Sdougb } 1911224092Sdougb obj = NULL; 1912224092Sdougb (void)cfg_map_get(map, "exclude", &obj); 1913224092Sdougb if (obj != NULL) { 1914224092Sdougb result = cfg_acl_fromconfig(obj, config, 1915224092Sdougb ns_g_lctx, actx, 1916224092Sdougb mctx, 0, &excluded); 1917224092Sdougb if (result != ISC_R_SUCCESS) 1918224092Sdougb goto cleanup; 1919224092Sdougb } 1920224092Sdougb 1921224092Sdougb obj = NULL; 1922224092Sdougb (void)cfg_map_get(map, "recursive-only", &obj); 1923224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 1924224092Sdougb dns64options |= DNS_DNS64_RECURSIVE_ONLY; 1925224092Sdougb 1926224092Sdougb obj = NULL; 1927224092Sdougb (void)cfg_map_get(map, "break-dnssec", &obj); 1928224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 1929224092Sdougb dns64options |= DNS_DNS64_BREAK_DNSSEC; 1930224092Sdougb 1931224092Sdougb result = dns_dns64_create(mctx, &na, prefixlen, sp, 1932224092Sdougb clients, mapped, excluded, 1933224092Sdougb dns64options, &dns64); 1934224092Sdougb if (result != ISC_R_SUCCESS) 1935224092Sdougb goto cleanup; 1936224092Sdougb dns_dns64_append(&view->dns64, dns64); 1937224092Sdougb view->dns64cnt++; 1938224092Sdougb result = dns64_reverse(view, mctx, &na, prefixlen, 1939224092Sdougb server, contact); 1940224092Sdougb if (result != ISC_R_SUCCESS) 1941224092Sdougb goto cleanup; 1942224092Sdougb if (clients != NULL) 1943224092Sdougb dns_acl_detach(&clients); 1944224092Sdougb if (mapped != NULL) 1945224092Sdougb dns_acl_detach(&mapped); 1946224092Sdougb if (excluded != NULL) 1947224092Sdougb dns_acl_detach(&excluded); 1948224092Sdougb } 1949224092Sdougb } 1950224092Sdougb 1951224092Sdougb obj = NULL; 1952193149Sdougb result = ns_config_get(maps, "dnssec-accept-expired", &obj); 1953193149Sdougb INSIST(result == ISC_R_SUCCESS); 1954193149Sdougb view->acceptexpired = cfg_obj_asboolean(obj); 1955193149Sdougb 1956193149Sdougb obj = NULL; 1957193149Sdougb result = ns_config_get(maps, "dnssec-validation", &obj); 1958193149Sdougb INSIST(result == ISC_R_SUCCESS); 1959224092Sdougb if (cfg_obj_isboolean(obj)) { 1960224092Sdougb view->enablevalidation = cfg_obj_asboolean(obj); 1961224092Sdougb } else { 1962224092Sdougb /* If dnssec-validation is not boolean, it must be "auto" */ 1963224092Sdougb view->enablevalidation = ISC_TRUE; 1964224092Sdougb auto_root = ISC_TRUE; 1965224092Sdougb } 1966193149Sdougb 1967193149Sdougb obj = NULL; 1968193149Sdougb result = ns_config_get(maps, "max-cache-ttl", &obj); 1969193149Sdougb INSIST(result == ISC_R_SUCCESS); 1970193149Sdougb view->maxcachettl = cfg_obj_asuint32(obj); 1971193149Sdougb 1972193149Sdougb obj = NULL; 1973193149Sdougb result = ns_config_get(maps, "max-ncache-ttl", &obj); 1974193149Sdougb INSIST(result == ISC_R_SUCCESS); 1975193149Sdougb view->maxncachettl = cfg_obj_asuint32(obj); 1976193149Sdougb if (view->maxncachettl > 7 * 24 * 3600) 1977193149Sdougb view->maxncachettl = 7 * 24 * 3600; 1978193149Sdougb 1979193149Sdougb /* 1980224092Sdougb * Configure the view's cache. 1981135446Strhodes * 1982224092Sdougb * First, check to see if there are any attach-cache options. If yes, 1983224092Sdougb * attempt to lookup an existing cache at attach it to the view. If 1984224092Sdougb * there is not one, then try to reuse an existing cache if possible; 1985224092Sdougb * otherwise create a new cache. 1986224092Sdougb * 1987224092Sdougb * Note that the ADB is not preserved or shared in either case. 1988224092Sdougb * 1989224092Sdougb * When a matching view is found, the associated statistics are also 1990224092Sdougb * retrieved and reused. 1991224092Sdougb * 1992224092Sdougb * XXX Determining when it is safe to reuse or share a cache is tricky. 1993193149Sdougb * When the view's configuration changes, the cached data may become 1994193149Sdougb * invalid because it reflects our old view of the world. We check 1995224092Sdougb * some of the configuration parameters that could invalidate the cache 1996224092Sdougb * or otherwise make it unsharable, but there are other configuration 1997224092Sdougb * options that should be checked. For example, if a view uses a 1998224092Sdougb * forwarder, changes in the forwarder configuration may invalidate 1999224092Sdougb * the cache. At the moment, it's the administrator's responsibility to 2000224092Sdougb * ensure these configuration options don't invalidate reusing/sharing. 2001135446Strhodes */ 2002224092Sdougb obj = NULL; 2003224092Sdougb result = ns_config_get(maps, "attach-cache", &obj); 2004224092Sdougb if (result == ISC_R_SUCCESS) 2005224092Sdougb cachename = cfg_obj_asstring(obj); 2006224092Sdougb else 2007224092Sdougb cachename = view->name; 2008224092Sdougb cache = NULL; 2009224092Sdougb nsc = cachelist_find(cachelist, cachename); 2010224092Sdougb if (nsc != NULL) { 2011224092Sdougb if (!cache_sharable(nsc->primaryview, view, zero_no_soattl, 2012224092Sdougb cleaning_interval, max_cache_size)) { 2013193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2014224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2015224092Sdougb "views %s and %s can't share the cache " 2016193149Sdougb "due to configuration parameter mismatch", 2017224092Sdougb nsc->primaryview->name, view->name); 2018224092Sdougb result = ISC_R_FAILURE; 2019224092Sdougb goto cleanup; 2020193149Sdougb } 2021224092Sdougb dns_cache_attach(nsc->cache, &cache); 2022224092Sdougb shared_cache = ISC_TRUE; 2023224092Sdougb } else { 2024224092Sdougb if (strcmp(cachename, view->name) == 0) { 2025224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 2026224092Sdougb cachename, view->rdclass, 2027224092Sdougb &pview); 2028224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2029224092Sdougb goto cleanup; 2030224092Sdougb if (pview != NULL) { 2031224092Sdougb if (!cache_reusable(pview, view, 2032224092Sdougb zero_no_soattl)) { 2033224092Sdougb isc_log_write(ns_g_lctx, 2034224092Sdougb NS_LOGCATEGORY_GENERAL, 2035224092Sdougb NS_LOGMODULE_SERVER, 2036224092Sdougb ISC_LOG_DEBUG(1), 2037224092Sdougb "cache cannot be reused " 2038224092Sdougb "for view %s due to " 2039224092Sdougb "configuration parameter " 2040224092Sdougb "mismatch", view->name); 2041224092Sdougb } else { 2042224092Sdougb INSIST(pview->cache != NULL); 2043224092Sdougb isc_log_write(ns_g_lctx, 2044224092Sdougb NS_LOGCATEGORY_GENERAL, 2045224092Sdougb NS_LOGMODULE_SERVER, 2046224092Sdougb ISC_LOG_DEBUG(3), 2047224092Sdougb "reusing existing cache"); 2048224092Sdougb reused_cache = ISC_TRUE; 2049224092Sdougb dns_cache_attach(pview->cache, &cache); 2050224092Sdougb } 2051224092Sdougb dns_view_getresstats(pview, &resstats); 2052224092Sdougb dns_view_getresquerystats(pview, 2053224092Sdougb &resquerystats); 2054224092Sdougb dns_view_detach(&pview); 2055224092Sdougb } 2056224092Sdougb } 2057224092Sdougb if (cache == NULL) { 2058224092Sdougb /* 2059224092Sdougb * Create a cache with the desired name. This normally 2060224092Sdougb * equals the view name, but may also be a forward 2061224092Sdougb * reference to a view that share the cache with this 2062224092Sdougb * view but is not yet configured. If it is not the 2063224092Sdougb * view name but not a forward reference either, then it 2064224092Sdougb * is simply a named cache that is not shared. 2065225361Sdougb * 2066225361Sdougb * We use two separate memory contexts for the 2067225361Sdougb * cache, for the main cache memory and the heap 2068225361Sdougb * memory. 2069224092Sdougb */ 2070224092Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 2071224092Sdougb isc_mem_setname(cmctx, "cache", NULL); 2072225361Sdougb CHECK(isc_mem_create(0, 0, &hmctx)); 2073225361Sdougb isc_mem_setname(hmctx, "cache_heap", NULL); 2074225361Sdougb CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr, 2075224092Sdougb ns_g_timermgr, view->rdclass, 2076224092Sdougb cachename, "rbt", 0, NULL, 2077224092Sdougb &cache)); 2078225361Sdougb isc_mem_detach(&cmctx); 2079225361Sdougb isc_mem_detach(&hmctx); 2080224092Sdougb } 2081224092Sdougb nsc = isc_mem_get(mctx, sizeof(*nsc)); 2082224092Sdougb if (nsc == NULL) { 2083224092Sdougb result = ISC_R_NOMEMORY; 2084224092Sdougb goto cleanup; 2085224092Sdougb } 2086224092Sdougb nsc->cache = NULL; 2087224092Sdougb dns_cache_attach(cache, &nsc->cache); 2088224092Sdougb nsc->primaryview = view; 2089224092Sdougb nsc->needflush = ISC_FALSE; 2090224092Sdougb nsc->adbsizeadjusted = ISC_FALSE; 2091224092Sdougb ISC_LINK_INIT(nsc, link); 2092224092Sdougb ISC_LIST_APPEND(*cachelist, nsc, link); 2093193149Sdougb } 2094224092Sdougb dns_view_setcache2(view, cache, shared_cache); 2095135446Strhodes 2096135446Strhodes /* 2097135446Strhodes * cache-file cannot be inherited if views are present, but this 2098135446Strhodes * should be caught by the configuration checking stage. 2099135446Strhodes */ 2100135446Strhodes obj = NULL; 2101135446Strhodes result = ns_config_get(maps, "cache-file", &obj); 2102135446Strhodes if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 2103135446Strhodes CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 2104224092Sdougb if (!reused_cache && !shared_cache) 2105135446Strhodes CHECK(dns_cache_load(cache)); 2106135446Strhodes } 2107135446Strhodes 2108224092Sdougb dns_cache_setcleaninginterval(cache, cleaning_interval); 2109135446Strhodes dns_cache_setcachesize(cache, max_cache_size); 2110135446Strhodes 2111135446Strhodes dns_cache_detach(&cache); 2112135446Strhodes 2113135446Strhodes /* 2114135446Strhodes * Resolver. 2115135446Strhodes * 2116135446Strhodes * XXXRTH Hardwired number of tasks. 2117135446Strhodes */ 2118186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, 2119186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2120186462Sdougb == NULL))); 2121186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, 2122186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2123186462Sdougb == NULL))); 2124135446Strhodes if (dispatch4 == NULL && dispatch6 == NULL) { 2125135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 2126135446Strhodes "unable to obtain neither an IPv4 nor" 2127135446Strhodes " an IPv6 dispatch"); 2128135446Strhodes result = ISC_R_UNEXPECTED; 2129135446Strhodes goto cleanup; 2130135446Strhodes } 2131135446Strhodes CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, 2132135446Strhodes ns_g_socketmgr, ns_g_timermgr, 2133193149Sdougb resopts, ns_g_dispatchmgr, 2134135446Strhodes dispatch4, dispatch6)); 2135135446Strhodes 2136193149Sdougb if (resstats == NULL) { 2137193149Sdougb CHECK(isc_stats_create(mctx, &resstats, 2138193149Sdougb dns_resstatscounter_max)); 2139193149Sdougb } 2140193149Sdougb dns_view_setresstats(view, resstats); 2141193149Sdougb if (resquerystats == NULL) 2142193149Sdougb CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); 2143193149Sdougb dns_view_setresquerystats(view, resquerystats); 2144193149Sdougb 2145135446Strhodes /* 2146224092Sdougb * Set the ADB cache size to 1/8th of the max-cache-size or 2147224092Sdougb * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. 2148135446Strhodes */ 2149135446Strhodes max_adb_size = 0; 2150135446Strhodes if (max_cache_size != 0) { 2151135446Strhodes max_adb_size = max_cache_size / 8; 2152135446Strhodes if (max_adb_size == 0) 2153135446Strhodes max_adb_size = 1; /* Force minimum. */ 2154224092Sdougb if (view != nsc->primaryview && 2155224092Sdougb max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) { 2156224092Sdougb max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE; 2157224092Sdougb if (!nsc->adbsizeadjusted) { 2158224092Sdougb dns_adb_setadbsize(nsc->primaryview->adb, 2159224092Sdougb MAX_ADB_SIZE_FOR_CACHESHARE); 2160224092Sdougb nsc->adbsizeadjusted = ISC_TRUE; 2161224092Sdougb } 2162224092Sdougb } 2163135446Strhodes } 2164135446Strhodes dns_adb_setadbsize(view->adb, max_adb_size); 2165135446Strhodes 2166135446Strhodes /* 2167135446Strhodes * Set resolver's lame-ttl. 2168135446Strhodes */ 2169135446Strhodes obj = NULL; 2170135446Strhodes result = ns_config_get(maps, "lame-ttl", &obj); 2171135446Strhodes INSIST(result == ISC_R_SUCCESS); 2172135446Strhodes lame_ttl = cfg_obj_asuint32(obj); 2173135446Strhodes if (lame_ttl > 1800) 2174135446Strhodes lame_ttl = 1800; 2175135446Strhodes dns_resolver_setlamettl(view->resolver, lame_ttl); 2176170222Sdougb 2177135446Strhodes /* 2178224092Sdougb * Set the resolver's query timeout. 2179224092Sdougb */ 2180224092Sdougb obj = NULL; 2181224092Sdougb result = ns_config_get(maps, "resolver-query-timeout", &obj); 2182224092Sdougb INSIST(result == ISC_R_SUCCESS); 2183224092Sdougb query_timeout = cfg_obj_asuint32(obj); 2184224092Sdougb dns_resolver_settimeout(view->resolver, query_timeout); 2185224092Sdougb 2186224092Sdougb /* Specify whether to use 0-TTL for negative response for SOA query */ 2187224092Sdougb dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl); 2188224092Sdougb 2189224092Sdougb /* 2190135446Strhodes * Set the resolver's EDNS UDP size. 2191135446Strhodes */ 2192135446Strhodes obj = NULL; 2193135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 2194135446Strhodes INSIST(result == ISC_R_SUCCESS); 2195135446Strhodes udpsize = cfg_obj_asuint32(obj); 2196135446Strhodes if (udpsize < 512) 2197135446Strhodes udpsize = 512; 2198135446Strhodes if (udpsize > 4096) 2199135446Strhodes udpsize = 4096; 2200135446Strhodes dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 2201186462Sdougb 2202135446Strhodes /* 2203170222Sdougb * Set the maximum UDP response size. 2204170222Sdougb */ 2205170222Sdougb obj = NULL; 2206170222Sdougb result = ns_config_get(maps, "max-udp-size", &obj); 2207170222Sdougb INSIST(result == ISC_R_SUCCESS); 2208170222Sdougb udpsize = cfg_obj_asuint32(obj); 2209170222Sdougb if (udpsize < 512) 2210170222Sdougb udpsize = 512; 2211170222Sdougb if (udpsize > 4096) 2212170222Sdougb udpsize = 4096; 2213170222Sdougb view->maxudp = udpsize; 2214170222Sdougb 2215170222Sdougb /* 2216135446Strhodes * Set supported DNSSEC algorithms. 2217135446Strhodes */ 2218135446Strhodes dns_resolver_reset_algorithms(view->resolver); 2219135446Strhodes disabled = NULL; 2220135446Strhodes (void)ns_config_get(maps, "disable-algorithms", &disabled); 2221135446Strhodes if (disabled != NULL) { 2222135446Strhodes for (element = cfg_list_first(disabled); 2223135446Strhodes element != NULL; 2224135446Strhodes element = cfg_list_next(element)) 2225135446Strhodes CHECK(disable_algorithms(cfg_listelt_value(element), 2226135446Strhodes view->resolver)); 2227135446Strhodes } 2228135446Strhodes 2229135446Strhodes /* 2230135446Strhodes * A global or view "forwarders" option, if present, 2231135446Strhodes * creates an entry for "." in the forwarding table. 2232135446Strhodes */ 2233135446Strhodes forwardtype = NULL; 2234135446Strhodes forwarders = NULL; 2235135446Strhodes (void)ns_config_get(maps, "forward", &forwardtype); 2236135446Strhodes (void)ns_config_get(maps, "forwarders", &forwarders); 2237135446Strhodes if (forwarders != NULL) 2238186462Sdougb CHECK(configure_forward(config, view, dns_rootname, 2239135446Strhodes forwarders, forwardtype)); 2240135446Strhodes 2241135446Strhodes /* 2242135446Strhodes * Dual Stack Servers. 2243135446Strhodes */ 2244135446Strhodes alternates = NULL; 2245135446Strhodes (void)ns_config_get(maps, "dual-stack-servers", &alternates); 2246135446Strhodes if (alternates != NULL) 2247135446Strhodes CHECK(configure_alternates(config, view, alternates)); 2248135446Strhodes 2249135446Strhodes /* 2250135446Strhodes * We have default hints for class IN if we need them. 2251135446Strhodes */ 2252135446Strhodes if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 2253135446Strhodes dns_view_sethints(view, ns_g_server->in_roothints); 2254135446Strhodes 2255135446Strhodes /* 2256135446Strhodes * If we still have no hints, this is a non-IN view with no 2257135446Strhodes * "hints zone" configured. Issue a warning, except if this 2258186462Sdougb * is a root server. Root servers never need to consult 2259135446Strhodes * their hints, so it's no point requiring users to configure 2260135446Strhodes * them. 2261135446Strhodes */ 2262135446Strhodes if (view->hints == NULL) { 2263135446Strhodes dns_zone_t *rootzone = NULL; 2264135446Strhodes (void)dns_view_findzone(view, dns_rootname, &rootzone); 2265135446Strhodes if (rootzone != NULL) { 2266135446Strhodes dns_zone_detach(&rootzone); 2267135446Strhodes need_hints = ISC_FALSE; 2268135446Strhodes } 2269135446Strhodes if (need_hints) 2270135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2271135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2272135446Strhodes "no root hints for view '%s'", 2273135446Strhodes view->name); 2274135446Strhodes } 2275135446Strhodes 2276135446Strhodes /* 2277135446Strhodes * Configure the view's TSIG keys. 2278135446Strhodes */ 2279135446Strhodes CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 2280224092Sdougb if (ns_g_server->sessionkey != NULL) { 2281224092Sdougb CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname, 2282224092Sdougb ns_g_server->sessionkey)); 2283224092Sdougb } 2284135446Strhodes dns_view_setkeyring(view, ring); 2285224092Sdougb dns_tsigkeyring_detach(&ring); 2286135446Strhodes 2287135446Strhodes /* 2288224092Sdougb * See if we can re-use a dynamic key ring. 2289224092Sdougb */ 2290224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, view->name, 2291224092Sdougb view->rdclass, &pview); 2292224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2293224092Sdougb goto cleanup; 2294224092Sdougb if (pview != NULL) { 2295224092Sdougb dns_view_getdynamickeyring(pview, &ring); 2296224092Sdougb if (ring != NULL) 2297224092Sdougb dns_view_setdynamickeyring(view, ring); 2298224092Sdougb dns_tsigkeyring_detach(&ring); 2299224092Sdougb dns_view_detach(&pview); 2300224092Sdougb } else 2301224092Sdougb dns_view_restorekeyring(view); 2302224092Sdougb 2303224092Sdougb /* 2304135446Strhodes * Configure the view's peer list. 2305135446Strhodes */ 2306135446Strhodes { 2307165071Sdougb const cfg_obj_t *peers = NULL; 2308165071Sdougb const cfg_listelt_t *element; 2309135446Strhodes dns_peerlist_t *newpeers = NULL; 2310135446Strhodes 2311135446Strhodes (void)ns_config_get(cfgmaps, "server", &peers); 2312135446Strhodes CHECK(dns_peerlist_new(mctx, &newpeers)); 2313135446Strhodes for (element = cfg_list_first(peers); 2314135446Strhodes element != NULL; 2315135446Strhodes element = cfg_list_next(element)) 2316135446Strhodes { 2317165071Sdougb const cfg_obj_t *cpeer = cfg_listelt_value(element); 2318135446Strhodes dns_peer_t *peer; 2319135446Strhodes 2320135446Strhodes CHECK(configure_peer(cpeer, mctx, &peer)); 2321135446Strhodes dns_peerlist_addpeer(newpeers, peer); 2322135446Strhodes dns_peer_detach(&peer); 2323135446Strhodes } 2324135446Strhodes dns_peerlist_detach(&view->peers); 2325135446Strhodes view->peers = newpeers; /* Transfer ownership. */ 2326135446Strhodes } 2327135446Strhodes 2328135446Strhodes /* 2329135446Strhodes * Configure the views rrset-order. 2330135446Strhodes */ 2331135446Strhodes { 2332165071Sdougb const cfg_obj_t *rrsetorder = NULL; 2333165071Sdougb const cfg_listelt_t *element; 2334135446Strhodes 2335135446Strhodes (void)ns_config_get(maps, "rrset-order", &rrsetorder); 2336135446Strhodes CHECK(dns_order_create(mctx, &order)); 2337135446Strhodes for (element = cfg_list_first(rrsetorder); 2338135446Strhodes element != NULL; 2339135446Strhodes element = cfg_list_next(element)) 2340135446Strhodes { 2341165071Sdougb const cfg_obj_t *ent = cfg_listelt_value(element); 2342135446Strhodes 2343135446Strhodes CHECK(configure_order(order, ent)); 2344135446Strhodes } 2345135446Strhodes if (view->order != NULL) 2346135446Strhodes dns_order_detach(&view->order); 2347135446Strhodes dns_order_attach(order, &view->order); 2348135446Strhodes dns_order_detach(&order); 2349135446Strhodes } 2350135446Strhodes /* 2351135446Strhodes * Copy the aclenv object. 2352135446Strhodes */ 2353135446Strhodes dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 2354135446Strhodes 2355135446Strhodes /* 2356135446Strhodes * Configure the "match-clients" and "match-destinations" ACL. 2357135446Strhodes */ 2358224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx, 2359135446Strhodes ns_g_mctx, &view->matchclients)); 2360224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL, 2361224092Sdougb actx, ns_g_mctx, &view->matchdestinations)); 2362135446Strhodes 2363135446Strhodes /* 2364135446Strhodes * Configure the "match-recursive-only" option. 2365135446Strhodes */ 2366135446Strhodes obj = NULL; 2367165071Sdougb (void)ns_config_get(maps, "match-recursive-only", &obj); 2368135446Strhodes if (obj != NULL && cfg_obj_asboolean(obj)) 2369135446Strhodes view->matchrecursiveonly = ISC_TRUE; 2370135446Strhodes else 2371135446Strhodes view->matchrecursiveonly = ISC_FALSE; 2372135446Strhodes 2373135446Strhodes /* 2374135446Strhodes * Configure other configurable data. 2375135446Strhodes */ 2376135446Strhodes obj = NULL; 2377135446Strhodes result = ns_config_get(maps, "recursion", &obj); 2378135446Strhodes INSIST(result == ISC_R_SUCCESS); 2379135446Strhodes view->recursion = cfg_obj_asboolean(obj); 2380135446Strhodes 2381135446Strhodes obj = NULL; 2382135446Strhodes result = ns_config_get(maps, "auth-nxdomain", &obj); 2383135446Strhodes INSIST(result == ISC_R_SUCCESS); 2384135446Strhodes view->auth_nxdomain = cfg_obj_asboolean(obj); 2385135446Strhodes 2386135446Strhodes obj = NULL; 2387135446Strhodes result = ns_config_get(maps, "minimal-responses", &obj); 2388135446Strhodes INSIST(result == ISC_R_SUCCESS); 2389135446Strhodes view->minimalresponses = cfg_obj_asboolean(obj); 2390135446Strhodes 2391135446Strhodes obj = NULL; 2392135446Strhodes result = ns_config_get(maps, "transfer-format", &obj); 2393135446Strhodes INSIST(result == ISC_R_SUCCESS); 2394135446Strhodes str = cfg_obj_asstring(obj); 2395135446Strhodes if (strcasecmp(str, "many-answers") == 0) 2396135446Strhodes view->transfer_format = dns_many_answers; 2397135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 2398135446Strhodes view->transfer_format = dns_one_answer; 2399135446Strhodes else 2400135446Strhodes INSIST(0); 2401186462Sdougb 2402135446Strhodes /* 2403135446Strhodes * Set sources where additional data and CNAME/DNAME 2404135446Strhodes * targets for authoritative answers may be found. 2405135446Strhodes */ 2406135446Strhodes obj = NULL; 2407135446Strhodes result = ns_config_get(maps, "additional-from-auth", &obj); 2408135446Strhodes INSIST(result == ISC_R_SUCCESS); 2409135446Strhodes view->additionalfromauth = cfg_obj_asboolean(obj); 2410135446Strhodes if (view->recursion && ! view->additionalfromauth) { 2411135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2412135446Strhodes "'additional-from-auth no' is only supported " 2413135446Strhodes "with 'recursion no'"); 2414135446Strhodes view->additionalfromauth = ISC_TRUE; 2415135446Strhodes } 2416135446Strhodes 2417135446Strhodes obj = NULL; 2418135446Strhodes result = ns_config_get(maps, "additional-from-cache", &obj); 2419135446Strhodes INSIST(result == ISC_R_SUCCESS); 2420135446Strhodes view->additionalfromcache = cfg_obj_asboolean(obj); 2421135446Strhodes if (view->recursion && ! view->additionalfromcache) { 2422135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2423135446Strhodes "'additional-from-cache no' is only supported " 2424135446Strhodes "with 'recursion no'"); 2425135446Strhodes view->additionalfromcache = ISC_TRUE; 2426135446Strhodes } 2427135446Strhodes 2428171577Sdougb /* 2429193149Sdougb * Set "allow-query-cache", "allow-query-cache-on", 2430193149Sdougb * "allow-recursion", and "allow-recursion-on" acls if 2431171577Sdougb * configured in named.conf. 2432171577Sdougb */ 2433224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL, 2434216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 2435224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL, 2436216175Sdougb actx, ns_g_mctx, &view->cacheonacl)); 2437216175Sdougb if (view->cacheonacl == NULL) 2438193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2439224092Sdougb "allow-query-cache-on", NULL, actx, 2440216175Sdougb ns_g_mctx, &view->cacheonacl)); 2441193149Sdougb if (strcmp(view->name, "_bind") != 0) { 2442135446Strhodes CHECK(configure_view_acl(vconfig, config, "allow-recursion", 2443224092Sdougb NULL, actx, ns_g_mctx, 2444193149Sdougb &view->recursionacl)); 2445193149Sdougb CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", 2446224092Sdougb NULL, actx, ns_g_mctx, 2447193149Sdougb &view->recursiononacl)); 2448193149Sdougb } 2449135446Strhodes 2450135446Strhodes /* 2451171577Sdougb * "allow-query-cache" inherits from "allow-recursion" if set, 2452171577Sdougb * otherwise from "allow-query" if set. 2453171577Sdougb * "allow-recursion" inherits from "allow-query-cache" if set, 2454171577Sdougb * otherwise from "allow-query" if set. 2455170222Sdougb */ 2456216175Sdougb if (view->cacheacl == NULL && view->recursionacl != NULL) 2457216175Sdougb dns_acl_attach(view->recursionacl, &view->cacheacl); 2458224092Sdougb /* 2459224092Sdougb * XXXEACH: This call to configure_view_acl() is redundant. We 2460224092Sdougb * are leaving it as it is because we are making a minimal change 2461224092Sdougb * for a patch release. In the future this should be changed to 2462224092Sdougb * dns_acl_attach(view->queryacl, &view->cacheacl). 2463224092Sdougb */ 2464216175Sdougb if (view->cacheacl == NULL && view->recursion) 2465224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, 2466216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 2467193149Sdougb if (view->recursion && 2468216175Sdougb view->recursionacl == NULL && view->cacheacl != NULL) 2469216175Sdougb dns_acl_attach(view->cacheacl, &view->recursionacl); 2470171577Sdougb 2471171577Sdougb /* 2472193149Sdougb * Set default "allow-recursion", "allow-recursion-on" and 2473193149Sdougb * "allow-query-cache" acls. 2474171577Sdougb */ 2475170222Sdougb if (view->recursionacl == NULL && view->recursion) 2476171577Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2477224092Sdougb "allow-recursion", NULL, 2478193149Sdougb actx, ns_g_mctx, 2479193149Sdougb &view->recursionacl)); 2480193149Sdougb if (view->recursiononacl == NULL && view->recursion) 2481193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2482224092Sdougb "allow-recursion-on", NULL, 2483193149Sdougb actx, ns_g_mctx, 2484193149Sdougb &view->recursiononacl)); 2485216175Sdougb if (view->cacheacl == NULL) { 2486193149Sdougb if (view->recursion) 2487193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2488224092Sdougb "allow-query-cache", NULL, 2489224092Sdougb actx, ns_g_mctx, 2490224092Sdougb &view->cacheacl)); 2491216175Sdougb else 2492224092Sdougb CHECK(dns_acl_none(mctx, &view->cacheacl)); 2493193149Sdougb } 2494170222Sdougb 2495193149Sdougb /* 2496224092Sdougb * Filter setting on addresses in the answer section. 2497224092Sdougb */ 2498224092Sdougb CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses", 2499224092Sdougb "acl", actx, ns_g_mctx, &view->denyansweracl)); 2500224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses", 2501224092Sdougb "except-from", ns_g_mctx, 2502224092Sdougb &view->answeracl_exclude)); 2503224092Sdougb 2504224092Sdougb /* 2505224092Sdougb * Filter setting on names (CNAME/DNAME targets) in the answer section. 2506224092Sdougb */ 2507224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 2508224092Sdougb "name", ns_g_mctx, 2509224092Sdougb &view->denyanswernames)); 2510224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 2511224092Sdougb "except-from", ns_g_mctx, 2512224092Sdougb &view->answernames_exclude)); 2513224092Sdougb 2514224092Sdougb /* 2515193149Sdougb * Configure sortlist, if set 2516193149Sdougb */ 2517193149Sdougb CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, 2518193149Sdougb &view->sortlist)); 2519135446Strhodes 2520193149Sdougb /* 2521193149Sdougb * Configure default allow-transfer, allow-notify, allow-update 2522193149Sdougb * and allow-update-forwarding ACLs, if set, so they can be 2523193149Sdougb * inherited by zones. 2524193149Sdougb */ 2525193149Sdougb if (view->notifyacl == NULL) 2526193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2527224092Sdougb "allow-notify", NULL, actx, 2528193149Sdougb ns_g_mctx, &view->notifyacl)); 2529193149Sdougb if (view->transferacl == NULL) 2530193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2531224092Sdougb "allow-transfer", NULL, actx, 2532193149Sdougb ns_g_mctx, &view->transferacl)); 2533193149Sdougb if (view->updateacl == NULL) 2534193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2535224092Sdougb "allow-update", NULL, actx, 2536193149Sdougb ns_g_mctx, &view->updateacl)); 2537193149Sdougb if (view->upfwdacl == NULL) 2538193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2539224092Sdougb "allow-update-forwarding", NULL, actx, 2540193149Sdougb ns_g_mctx, &view->upfwdacl)); 2541193149Sdougb 2542135446Strhodes obj = NULL; 2543135446Strhodes result = ns_config_get(maps, "request-ixfr", &obj); 2544135446Strhodes INSIST(result == ISC_R_SUCCESS); 2545135446Strhodes view->requestixfr = cfg_obj_asboolean(obj); 2546135446Strhodes 2547135446Strhodes obj = NULL; 2548135446Strhodes result = ns_config_get(maps, "provide-ixfr", &obj); 2549135446Strhodes INSIST(result == ISC_R_SUCCESS); 2550135446Strhodes view->provideixfr = cfg_obj_asboolean(obj); 2551170222Sdougb 2552170222Sdougb obj = NULL; 2553193149Sdougb result = ns_config_get(maps, "request-nsid", &obj); 2554193149Sdougb INSIST(result == ISC_R_SUCCESS); 2555193149Sdougb view->requestnsid = cfg_obj_asboolean(obj); 2556193149Sdougb 2557193149Sdougb obj = NULL; 2558170222Sdougb result = ns_config_get(maps, "max-clients-per-query", &obj); 2559170222Sdougb INSIST(result == ISC_R_SUCCESS); 2560170222Sdougb max_clients_per_query = cfg_obj_asuint32(obj); 2561170222Sdougb 2562170222Sdougb obj = NULL; 2563170222Sdougb result = ns_config_get(maps, "clients-per-query", &obj); 2564170222Sdougb INSIST(result == ISC_R_SUCCESS); 2565170222Sdougb dns_resolver_setclientsperquery(view->resolver, 2566170222Sdougb cfg_obj_asuint32(obj), 2567170222Sdougb max_clients_per_query); 2568186462Sdougb 2569224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 2570135446Strhodes obj = NULL; 2571224092Sdougb result = ns_config_get(maps, "filter-aaaa-on-v4", &obj); 2572224092Sdougb INSIST(result == ISC_R_SUCCESS); 2573224092Sdougb if (cfg_obj_isboolean(obj)) { 2574224092Sdougb if (cfg_obj_asboolean(obj)) 2575224092Sdougb view->v4_aaaa = dns_v4_aaaa_filter; 2576224092Sdougb else 2577224092Sdougb view->v4_aaaa = dns_v4_aaaa_ok; 2578224092Sdougb } else { 2579224092Sdougb const char *v4_aaaastr = cfg_obj_asstring(obj); 2580224092Sdougb if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) 2581224092Sdougb view->v4_aaaa = dns_v4_aaaa_break_dnssec; 2582224092Sdougb else 2583224092Sdougb INSIST(0); 2584224092Sdougb } 2585224092Sdougb CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL, 2586224092Sdougb actx, ns_g_mctx, &view->v4_aaaa_acl)); 2587224092Sdougb#endif 2588224092Sdougb 2589224092Sdougb obj = NULL; 2590135446Strhodes result = ns_config_get(maps, "dnssec-enable", &obj); 2591135446Strhodes INSIST(result == ISC_R_SUCCESS); 2592135446Strhodes view->enablednssec = cfg_obj_asboolean(obj); 2593135446Strhodes 2594135446Strhodes obj = NULL; 2595224092Sdougb result = ns_config_get(optionmaps, "dnssec-lookaside", &obj); 2596135446Strhodes if (result == ISC_R_SUCCESS) { 2597224092Sdougb /* If set to "auto", use the version from the defaults */ 2598224092Sdougb const cfg_obj_t *dlvobj; 2599234010Sdougb const char *dom; 2600224092Sdougb dlvobj = cfg_listelt_value(cfg_list_first(obj)); 2601234010Sdougb dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain")); 2602234010Sdougb if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) { 2603234010Sdougb /* If "no", skip; if "auto", use global default */ 2604234010Sdougb if (!strcasecmp(dom, "no")) 2605234010Sdougb result = ISC_R_NOTFOUND; 2606234010Sdougb else if (!strcasecmp(dom, "auto")) { 2607234010Sdougb auto_dlv = ISC_TRUE; 2608234010Sdougb obj = NULL; 2609234010Sdougb result = cfg_map_get(ns_g_defaults, 2610234010Sdougb "dnssec-lookaside", &obj); 2611234010Sdougb } 2612224092Sdougb } 2613224092Sdougb } 2614224092Sdougb 2615224092Sdougb if (result == ISC_R_SUCCESS) { 2616135446Strhodes for (element = cfg_list_first(obj); 2617135446Strhodes element != NULL; 2618135446Strhodes element = cfg_list_next(element)) 2619135446Strhodes { 2620135446Strhodes const char *str; 2621135446Strhodes isc_buffer_t b; 2622135446Strhodes dns_name_t *dlv; 2623135446Strhodes 2624135446Strhodes obj = cfg_listelt_value(element); 2625135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, 2626135446Strhodes "trust-anchor")); 2627135446Strhodes isc_buffer_init(&b, str, strlen(str)); 2628135446Strhodes isc_buffer_add(&b, strlen(str)); 2629135446Strhodes dlv = dns_fixedname_name(&view->dlv_fixed); 2630135446Strhodes CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 2631224092Sdougb DNS_NAME_DOWNCASE, NULL)); 2632135446Strhodes view->dlv = dns_fixedname_name(&view->dlv_fixed); 2633135446Strhodes } 2634135446Strhodes } else 2635135446Strhodes view->dlv = NULL; 2636135446Strhodes 2637135446Strhodes /* 2638135446Strhodes * For now, there is only one kind of trusted keys, the 2639135446Strhodes * "security roots". 2640135446Strhodes */ 2641224092Sdougb CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, 2642224092Sdougb auto_dlv, auto_root, mctx)); 2643170222Sdougb dns_resolver_resetmustbesecure(view->resolver); 2644170222Sdougb obj = NULL; 2645170222Sdougb result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 2646170222Sdougb if (result == ISC_R_SUCCESS) 2647170222Sdougb CHECK(mustbesecure(obj, view->resolver)); 2648135446Strhodes 2649135446Strhodes obj = NULL; 2650135446Strhodes result = ns_config_get(maps, "preferred-glue", &obj); 2651135446Strhodes if (result == ISC_R_SUCCESS) { 2652135446Strhodes str = cfg_obj_asstring(obj); 2653135446Strhodes if (strcasecmp(str, "a") == 0) 2654135446Strhodes view->preferred_glue = dns_rdatatype_a; 2655135446Strhodes else if (strcasecmp(str, "aaaa") == 0) 2656135446Strhodes view->preferred_glue = dns_rdatatype_aaaa; 2657135446Strhodes else 2658135446Strhodes view->preferred_glue = 0; 2659135446Strhodes } else 2660135446Strhodes view->preferred_glue = 0; 2661135446Strhodes 2662135446Strhodes obj = NULL; 2663135446Strhodes result = ns_config_get(maps, "root-delegation-only", &obj); 2664135446Strhodes if (result == ISC_R_SUCCESS) { 2665135446Strhodes dns_view_setrootdelonly(view, ISC_TRUE); 2666135446Strhodes if (!cfg_obj_isvoid(obj)) { 2667135446Strhodes dns_fixedname_t fixed; 2668135446Strhodes dns_name_t *name; 2669135446Strhodes isc_buffer_t b; 2670165071Sdougb const char *str; 2671165071Sdougb const cfg_obj_t *exclude; 2672135446Strhodes 2673135446Strhodes dns_fixedname_init(&fixed); 2674135446Strhodes name = dns_fixedname_name(&fixed); 2675135446Strhodes for (element = cfg_list_first(obj); 2676135446Strhodes element != NULL; 2677135446Strhodes element = cfg_list_next(element)) { 2678135446Strhodes exclude = cfg_listelt_value(element); 2679135446Strhodes str = cfg_obj_asstring(exclude); 2680135446Strhodes isc_buffer_init(&b, str, strlen(str)); 2681135446Strhodes isc_buffer_add(&b, strlen(str)); 2682135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 2683224092Sdougb 0, NULL)); 2684135446Strhodes CHECK(dns_view_excludedelegationonly(view, 2685135446Strhodes name)); 2686135446Strhodes } 2687135446Strhodes } 2688135446Strhodes } else 2689135446Strhodes dns_view_setrootdelonly(view, ISC_FALSE); 2690135446Strhodes 2691170222Sdougb /* 2692170222Sdougb * Setup automatic empty zones. If recursion is off then 2693170222Sdougb * they are disabled by default. 2694170222Sdougb */ 2695170222Sdougb obj = NULL; 2696170222Sdougb (void)ns_config_get(maps, "empty-zones-enable", &obj); 2697170222Sdougb (void)ns_config_get(maps, "disable-empty-zone", &disablelist); 2698170222Sdougb if (obj == NULL && disablelist == NULL && 2699170222Sdougb view->rdclass == dns_rdataclass_in) { 2700170222Sdougb rfc1918 = ISC_FALSE; 2701170222Sdougb empty_zones_enable = view->recursion; 2702170222Sdougb } else if (view->rdclass == dns_rdataclass_in) { 2703170222Sdougb rfc1918 = ISC_TRUE; 2704170222Sdougb if (obj != NULL) 2705170222Sdougb empty_zones_enable = cfg_obj_asboolean(obj); 2706170222Sdougb else 2707170222Sdougb empty_zones_enable = view->recursion; 2708170222Sdougb } else { 2709170222Sdougb rfc1918 = ISC_FALSE; 2710170222Sdougb empty_zones_enable = ISC_FALSE; 2711170222Sdougb } 2712234010Sdougb if (empty_zones_enable && !lwresd_g_useresolvconf) { 2713170222Sdougb const char *empty; 2714170222Sdougb int empty_zone = 0; 2715170222Sdougb dns_fixedname_t fixed; 2716170222Sdougb dns_name_t *name; 2717170222Sdougb isc_buffer_t buffer; 2718170222Sdougb const char *str; 2719170222Sdougb char server[DNS_NAME_FORMATSIZE + 1]; 2720170222Sdougb char contact[DNS_NAME_FORMATSIZE + 1]; 2721170222Sdougb isc_boolean_t logit; 2722170222Sdougb const char *empty_dbtype[4] = 2723170222Sdougb { "_builtin", "empty", NULL, NULL }; 2724170222Sdougb int empty_dbtypec = 4; 2725193149Sdougb isc_boolean_t zonestats_on; 2726170222Sdougb 2727170222Sdougb dns_fixedname_init(&fixed); 2728170222Sdougb name = dns_fixedname_name(&fixed); 2729170222Sdougb 2730170222Sdougb obj = NULL; 2731170222Sdougb result = ns_config_get(maps, "empty-server", &obj); 2732170222Sdougb if (result == ISC_R_SUCCESS) { 2733170222Sdougb str = cfg_obj_asstring(obj); 2734170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 2735170222Sdougb isc_buffer_add(&buffer, strlen(str)); 2736224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2737224092Sdougb NULL)); 2738170222Sdougb isc_buffer_init(&buffer, server, sizeof(server) - 1); 2739170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 2740170222Sdougb server[isc_buffer_usedlength(&buffer)] = 0; 2741170222Sdougb empty_dbtype[2] = server; 2742170222Sdougb } else 2743170222Sdougb empty_dbtype[2] = "@"; 2744170222Sdougb 2745170222Sdougb obj = NULL; 2746170222Sdougb result = ns_config_get(maps, "empty-contact", &obj); 2747170222Sdougb if (result == ISC_R_SUCCESS) { 2748170222Sdougb str = cfg_obj_asstring(obj); 2749170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 2750170222Sdougb isc_buffer_add(&buffer, strlen(str)); 2751224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2752224092Sdougb NULL)); 2753170222Sdougb isc_buffer_init(&buffer, contact, sizeof(contact) - 1); 2754170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 2755170222Sdougb contact[isc_buffer_usedlength(&buffer)] = 0; 2756170222Sdougb empty_dbtype[3] = contact; 2757170222Sdougb } else 2758170222Sdougb empty_dbtype[3] = "."; 2759170222Sdougb 2760193149Sdougb obj = NULL; 2761193149Sdougb result = ns_config_get(maps, "zone-statistics", &obj); 2762193149Sdougb INSIST(result == ISC_R_SUCCESS); 2763193149Sdougb zonestats_on = cfg_obj_asboolean(obj); 2764193149Sdougb 2765170222Sdougb logit = ISC_TRUE; 2766170222Sdougb for (empty = empty_zones[empty_zone].zone; 2767170222Sdougb empty != NULL; 2768170222Sdougb empty = empty_zones[++empty_zone].zone) 2769170222Sdougb { 2770170222Sdougb dns_forwarders_t *forwarders = NULL; 2771170222Sdougb dns_view_t *pview = NULL; 2772170222Sdougb 2773170222Sdougb isc_buffer_init(&buffer, empty, strlen(empty)); 2774170222Sdougb isc_buffer_add(&buffer, strlen(empty)); 2775170222Sdougb /* 2776170222Sdougb * Look for zone on drop list. 2777170222Sdougb */ 2778224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2779224092Sdougb NULL)); 2780170222Sdougb if (disablelist != NULL && 2781170222Sdougb on_disable_list(disablelist, name)) 2782170222Sdougb continue; 2783170222Sdougb 2784170222Sdougb /* 2785170222Sdougb * This zone already exists. 2786170222Sdougb */ 2787170222Sdougb (void)dns_view_findzone(view, name, &zone); 2788170222Sdougb if (zone != NULL) { 2789193149Sdougb CHECK(setquerystats(zone, mctx, zonestats_on)); 2790170222Sdougb dns_zone_detach(&zone); 2791170222Sdougb continue; 2792170222Sdougb } 2793170222Sdougb 2794170222Sdougb /* 2795170222Sdougb * If we would forward this name don't add a 2796170222Sdougb * empty zone for it. 2797170222Sdougb */ 2798170222Sdougb result = dns_fwdtable_find(view->fwdtable, name, 2799170222Sdougb &forwarders); 2800170222Sdougb if (result == ISC_R_SUCCESS && 2801170222Sdougb forwarders->fwdpolicy == dns_fwdpolicy_only) 2802170222Sdougb continue; 2803186462Sdougb 2804170222Sdougb if (!rfc1918 && empty_zones[empty_zone].rfc1918) { 2805170222Sdougb if (logit) { 2806170222Sdougb isc_log_write(ns_g_lctx, 2807170222Sdougb NS_LOGCATEGORY_GENERAL, 2808170222Sdougb NS_LOGMODULE_SERVER, 2809170222Sdougb ISC_LOG_WARNING, 2810186462Sdougb "Warning%s%s: " 2811170222Sdougb "'empty-zones-enable/" 2812170222Sdougb "disable-empty-zone' " 2813170222Sdougb "not set: disabling " 2814170222Sdougb "RFC 1918 empty zones", 2815170222Sdougb sep, viewname); 2816170222Sdougb logit = ISC_FALSE; 2817170222Sdougb } 2818170222Sdougb continue; 2819170222Sdougb } 2820170222Sdougb 2821170222Sdougb /* 2822170222Sdougb * See if we can re-use a existing zone. 2823170222Sdougb */ 2824170222Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 2825170222Sdougb view->name, view->rdclass, 2826170222Sdougb &pview); 2827170222Sdougb if (result != ISC_R_NOTFOUND && 2828170222Sdougb result != ISC_R_SUCCESS) 2829170222Sdougb goto cleanup; 2830170222Sdougb 2831170222Sdougb if (pview != NULL) { 2832170222Sdougb (void)dns_view_findzone(pview, name, &zone); 2833170222Sdougb dns_view_detach(&pview); 2834170222Sdougb if (zone != NULL) 2835170222Sdougb check_dbtype(&zone, empty_dbtypec, 2836170222Sdougb empty_dbtype, mctx); 2837170222Sdougb if (zone != NULL) { 2838170222Sdougb dns_zone_setview(zone, view); 2839174187Sdougb CHECK(dns_view_addzone(view, zone)); 2840193149Sdougb CHECK(setquerystats(zone, mctx, 2841193149Sdougb zonestats_on)); 2842170222Sdougb dns_zone_detach(&zone); 2843170222Sdougb continue; 2844170222Sdougb } 2845170222Sdougb } 2846170222Sdougb 2847170222Sdougb CHECK(dns_zone_create(&zone, mctx)); 2848170222Sdougb CHECK(dns_zone_setorigin(zone, name)); 2849170222Sdougb dns_zone_setview(zone, view); 2850234010Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, 2851234010Sdougb zone)); 2852170222Sdougb dns_zone_setclass(zone, view->rdclass); 2853170222Sdougb dns_zone_settype(zone, dns_zone_master); 2854193149Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 2855170222Sdougb CHECK(dns_zone_setdbtype(zone, empty_dbtypec, 2856186462Sdougb empty_dbtype)); 2857170222Sdougb if (view->queryacl != NULL) 2858170222Sdougb dns_zone_setqueryacl(zone, view->queryacl); 2859193149Sdougb if (view->queryonacl != NULL) 2860193149Sdougb dns_zone_setqueryonacl(zone, view->queryonacl); 2861170222Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 2862170222Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 2863170222Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, 2864170222Sdougb ISC_TRUE); 2865193149Sdougb CHECK(setquerystats(zone, mctx, zonestats_on)); 2866170222Sdougb CHECK(dns_view_addzone(view, zone)); 2867170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2868170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 2869170222Sdougb "automatic empty zone%s%s: %s", 2870170222Sdougb sep, viewname, empty); 2871170222Sdougb dns_zone_detach(&zone); 2872170222Sdougb } 2873170222Sdougb } 2874186462Sdougb 2875224092Sdougb /* 2876224092Sdougb * Make the list of response policy zone names for views that 2877224092Sdougb * are used for real lookups and so care about hints. 2878224092Sdougb */ 2879224092Sdougb zonelist = NULL; 2880224092Sdougb if (view->rdclass == dns_rdataclass_in && need_hints) { 2881224092Sdougb obj = NULL; 2882224092Sdougb result = ns_config_get(maps, "response-policy", &obj); 2883224092Sdougb if (result == ISC_R_SUCCESS) 2884224092Sdougb cfg_map_get(obj, "zone", &zonelist); 2885224092Sdougb } 2886225361Sdougb 2887224092Sdougb if (zonelist != NULL) { 2888224092Sdougb for (element = cfg_list_first(zonelist); 2889224092Sdougb element != NULL; 2890224092Sdougb element = cfg_list_next(element)) { 2891224092Sdougb result = configure_rpz(view, element); 2892224092Sdougb if (result != ISC_R_SUCCESS) 2893224092Sdougb goto cleanup; 2894224092Sdougb dns_rpz_set_need(ISC_TRUE); 2895224092Sdougb } 2896224092Sdougb } 2897224092Sdougb 2898135446Strhodes result = ISC_R_SUCCESS; 2899135446Strhodes 2900135446Strhodes cleanup: 2901224092Sdougb if (clients != NULL) 2902224092Sdougb dns_acl_detach(&clients); 2903224092Sdougb if (mapped != NULL) 2904224092Sdougb dns_acl_detach(&mapped); 2905224092Sdougb if (excluded != NULL) 2906224092Sdougb dns_acl_detach(&excluded); 2907224092Sdougb if (ring != NULL) 2908224092Sdougb dns_tsigkeyring_detach(&ring); 2909170222Sdougb if (zone != NULL) 2910170222Sdougb dns_zone_detach(&zone); 2911135446Strhodes if (dispatch4 != NULL) 2912135446Strhodes dns_dispatch_detach(&dispatch4); 2913135446Strhodes if (dispatch6 != NULL) 2914135446Strhodes dns_dispatch_detach(&dispatch6); 2915193149Sdougb if (resstats != NULL) 2916193149Sdougb isc_stats_detach(&resstats); 2917193149Sdougb if (resquerystats != NULL) 2918193149Sdougb dns_stats_detach(&resquerystats); 2919135446Strhodes if (order != NULL) 2920135446Strhodes dns_order_detach(&order); 2921135446Strhodes if (cmctx != NULL) 2922135446Strhodes isc_mem_detach(&cmctx); 2923225361Sdougb if (hmctx != NULL) 2924225361Sdougb isc_mem_detach(&hmctx); 2925135446Strhodes 2926135446Strhodes if (cache != NULL) 2927135446Strhodes dns_cache_detach(&cache); 2928135446Strhodes 2929135446Strhodes return (result); 2930135446Strhodes} 2931135446Strhodes 2932135446Strhodesstatic isc_result_t 2933135446Strhodesconfigure_hints(dns_view_t *view, const char *filename) { 2934135446Strhodes isc_result_t result; 2935135446Strhodes dns_db_t *db; 2936135446Strhodes 2937135446Strhodes db = NULL; 2938135446Strhodes result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 2939135446Strhodes if (result == ISC_R_SUCCESS) { 2940135446Strhodes dns_view_sethints(view, db); 2941135446Strhodes dns_db_detach(&db); 2942135446Strhodes } 2943135446Strhodes 2944135446Strhodes return (result); 2945135446Strhodes} 2946135446Strhodes 2947135446Strhodesstatic isc_result_t 2948165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 2949165071Sdougb const cfg_obj_t *alternates) 2950135446Strhodes{ 2951165071Sdougb const cfg_obj_t *portobj; 2952165071Sdougb const cfg_obj_t *addresses; 2953165071Sdougb const cfg_listelt_t *element; 2954135446Strhodes isc_result_t result = ISC_R_SUCCESS; 2955135446Strhodes in_port_t port; 2956135446Strhodes 2957135446Strhodes /* 2958135446Strhodes * Determine which port to send requests to. 2959135446Strhodes */ 2960135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 2961135446Strhodes port = ns_g_port; 2962135446Strhodes else 2963135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 2964135446Strhodes 2965135446Strhodes if (alternates != NULL) { 2966135446Strhodes portobj = cfg_tuple_get(alternates, "port"); 2967135446Strhodes if (cfg_obj_isuint32(portobj)) { 2968135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 2969135446Strhodes if (val > ISC_UINT16_MAX) { 2970135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 2971135446Strhodes "port '%u' out of range", val); 2972135446Strhodes return (ISC_R_RANGE); 2973135446Strhodes } 2974135446Strhodes port = (in_port_t) val; 2975135446Strhodes } 2976135446Strhodes } 2977135446Strhodes 2978135446Strhodes addresses = NULL; 2979135446Strhodes if (alternates != NULL) 2980135446Strhodes addresses = cfg_tuple_get(alternates, "addresses"); 2981135446Strhodes 2982135446Strhodes for (element = cfg_list_first(addresses); 2983135446Strhodes element != NULL; 2984135446Strhodes element = cfg_list_next(element)) 2985135446Strhodes { 2986165071Sdougb const cfg_obj_t *alternate = cfg_listelt_value(element); 2987135446Strhodes isc_sockaddr_t sa; 2988135446Strhodes 2989135446Strhodes if (!cfg_obj_issockaddr(alternate)) { 2990135446Strhodes dns_fixedname_t fixed; 2991135446Strhodes dns_name_t *name; 2992165071Sdougb const char *str = cfg_obj_asstring(cfg_tuple_get( 2993165071Sdougb alternate, "name")); 2994135446Strhodes isc_buffer_t buffer; 2995135446Strhodes in_port_t myport = port; 2996135446Strhodes 2997135446Strhodes isc_buffer_init(&buffer, str, strlen(str)); 2998135446Strhodes isc_buffer_add(&buffer, strlen(str)); 2999135446Strhodes dns_fixedname_init(&fixed); 3000135446Strhodes name = dns_fixedname_name(&fixed); 3001224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3002224092Sdougb NULL)); 3003135446Strhodes 3004135446Strhodes portobj = cfg_tuple_get(alternate, "port"); 3005135446Strhodes if (cfg_obj_isuint32(portobj)) { 3006135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3007135446Strhodes if (val > ISC_UINT16_MAX) { 3008135446Strhodes cfg_obj_log(portobj, ns_g_lctx, 3009135446Strhodes ISC_LOG_ERROR, 3010135446Strhodes "port '%u' out of range", 3011135446Strhodes val); 3012135446Strhodes return (ISC_R_RANGE); 3013135446Strhodes } 3014135446Strhodes myport = (in_port_t) val; 3015135446Strhodes } 3016135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, NULL, 3017135446Strhodes name, myport)); 3018135446Strhodes continue; 3019135446Strhodes } 3020135446Strhodes 3021135446Strhodes sa = *cfg_obj_assockaddr(alternate); 3022135446Strhodes if (isc_sockaddr_getport(&sa) == 0) 3023135446Strhodes isc_sockaddr_setport(&sa, port); 3024135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, &sa, 3025135446Strhodes NULL, 0)); 3026135446Strhodes } 3027135446Strhodes 3028135446Strhodes cleanup: 3029135446Strhodes return (result); 3030135446Strhodes} 3031135446Strhodes 3032135446Strhodesstatic isc_result_t 3033165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 3034165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 3035135446Strhodes{ 3036165071Sdougb const cfg_obj_t *portobj; 3037165071Sdougb const cfg_obj_t *faddresses; 3038165071Sdougb const cfg_listelt_t *element; 3039135446Strhodes dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 3040135446Strhodes isc_sockaddrlist_t addresses; 3041135446Strhodes isc_sockaddr_t *sa; 3042135446Strhodes isc_result_t result; 3043135446Strhodes in_port_t port; 3044135446Strhodes 3045193149Sdougb ISC_LIST_INIT(addresses); 3046193149Sdougb 3047135446Strhodes /* 3048135446Strhodes * Determine which port to send forwarded requests to. 3049135446Strhodes */ 3050135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 3051135446Strhodes port = ns_g_port; 3052135446Strhodes else 3053135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 3054135446Strhodes 3055135446Strhodes if (forwarders != NULL) { 3056135446Strhodes portobj = cfg_tuple_get(forwarders, "port"); 3057135446Strhodes if (cfg_obj_isuint32(portobj)) { 3058135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3059135446Strhodes if (val > ISC_UINT16_MAX) { 3060135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3061135446Strhodes "port '%u' out of range", val); 3062135446Strhodes return (ISC_R_RANGE); 3063135446Strhodes } 3064135446Strhodes port = (in_port_t) val; 3065135446Strhodes } 3066135446Strhodes } 3067135446Strhodes 3068135446Strhodes faddresses = NULL; 3069135446Strhodes if (forwarders != NULL) 3070135446Strhodes faddresses = cfg_tuple_get(forwarders, "addresses"); 3071135446Strhodes 3072135446Strhodes for (element = cfg_list_first(faddresses); 3073135446Strhodes element != NULL; 3074135446Strhodes element = cfg_list_next(element)) 3075135446Strhodes { 3076165071Sdougb const cfg_obj_t *forwarder = cfg_listelt_value(element); 3077135446Strhodes sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 3078135446Strhodes if (sa == NULL) { 3079135446Strhodes result = ISC_R_NOMEMORY; 3080135446Strhodes goto cleanup; 3081135446Strhodes } 3082135446Strhodes *sa = *cfg_obj_assockaddr(forwarder); 3083135446Strhodes if (isc_sockaddr_getport(sa) == 0) 3084135446Strhodes isc_sockaddr_setport(sa, port); 3085135446Strhodes ISC_LINK_INIT(sa, link); 3086135446Strhodes ISC_LIST_APPEND(addresses, sa, link); 3087135446Strhodes } 3088135446Strhodes 3089135446Strhodes if (ISC_LIST_EMPTY(addresses)) { 3090135446Strhodes if (forwardtype != NULL) 3091135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3092135446Strhodes "no forwarders seen; disabling " 3093135446Strhodes "forwarding"); 3094135446Strhodes fwdpolicy = dns_fwdpolicy_none; 3095135446Strhodes } else { 3096135446Strhodes if (forwardtype == NULL) 3097135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3098135446Strhodes else { 3099165071Sdougb const char *forwardstr = cfg_obj_asstring(forwardtype); 3100135446Strhodes if (strcasecmp(forwardstr, "first") == 0) 3101135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3102135446Strhodes else if (strcasecmp(forwardstr, "only") == 0) 3103135446Strhodes fwdpolicy = dns_fwdpolicy_only; 3104135446Strhodes else 3105135446Strhodes INSIST(0); 3106135446Strhodes } 3107135446Strhodes } 3108135446Strhodes 3109135446Strhodes result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 3110135446Strhodes fwdpolicy); 3111135446Strhodes if (result != ISC_R_SUCCESS) { 3112135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 3113135446Strhodes dns_name_format(origin, namebuf, sizeof(namebuf)); 3114135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3115135446Strhodes "could not set up forwarding for domain '%s': %s", 3116135446Strhodes namebuf, isc_result_totext(result)); 3117135446Strhodes goto cleanup; 3118135446Strhodes } 3119135446Strhodes 3120135446Strhodes result = ISC_R_SUCCESS; 3121135446Strhodes 3122135446Strhodes cleanup: 3123135446Strhodes 3124135446Strhodes while (!ISC_LIST_EMPTY(addresses)) { 3125135446Strhodes sa = ISC_LIST_HEAD(addresses); 3126135446Strhodes ISC_LIST_UNLINK(addresses, sa, link); 3127135446Strhodes isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 3128135446Strhodes } 3129135446Strhodes 3130135446Strhodes return (result); 3131135446Strhodes} 3132135446Strhodes 3133135446Strhodesstatic isc_result_t 3134225361Sdougbget_viewinfo(const cfg_obj_t *vconfig, const char **namep, 3135225361Sdougb dns_rdataclass_t *classp) 3136165071Sdougb{ 3137225361Sdougb isc_result_t result = ISC_R_SUCCESS; 3138135446Strhodes const char *viewname; 3139135446Strhodes dns_rdataclass_t viewclass; 3140135446Strhodes 3141225361Sdougb REQUIRE(namep != NULL && *namep == NULL); 3142225361Sdougb REQUIRE(classp != NULL); 3143225361Sdougb 3144135446Strhodes if (vconfig != NULL) { 3145165071Sdougb const cfg_obj_t *classobj = NULL; 3146135446Strhodes 3147135446Strhodes viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 3148135446Strhodes classobj = cfg_tuple_get(vconfig, "class"); 3149135446Strhodes result = ns_config_getclass(classobj, dns_rdataclass_in, 3150135446Strhodes &viewclass); 3151135446Strhodes } else { 3152135446Strhodes viewname = "_default"; 3153135446Strhodes viewclass = dns_rdataclass_in; 3154135446Strhodes } 3155225361Sdougb 3156225361Sdougb *namep = viewname; 3157225361Sdougb *classp = viewclass; 3158225361Sdougb 3159225361Sdougb return (result); 3160225361Sdougb} 3161225361Sdougb 3162225361Sdougb/* 3163225361Sdougb * Find a view based on its configuration info and attach to it. 3164225361Sdougb * 3165225361Sdougb * If 'vconfig' is NULL, attach to the default view. 3166225361Sdougb */ 3167225361Sdougbstatic isc_result_t 3168225361Sdougbfind_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3169225361Sdougb dns_view_t **viewp) 3170225361Sdougb{ 3171225361Sdougb isc_result_t result; 3172225361Sdougb const char *viewname = NULL; 3173225361Sdougb dns_rdataclass_t viewclass; 3174225361Sdougb dns_view_t *view = NULL; 3175225361Sdougb 3176225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3177225361Sdougb if (result != ISC_R_SUCCESS) 3178225361Sdougb return (result); 3179225361Sdougb 3180135446Strhodes result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3181225361Sdougb if (result != ISC_R_SUCCESS) 3182225361Sdougb return (result); 3183225361Sdougb 3184225361Sdougb *viewp = view; 3185225361Sdougb return (ISC_R_SUCCESS); 3186225361Sdougb} 3187225361Sdougb 3188225361Sdougb/* 3189225361Sdougb * Create a new view and add it to the list. 3190225361Sdougb * 3191225361Sdougb * If 'vconfig' is NULL, create the default view. 3192225361Sdougb * 3193225361Sdougb * The view created is attached to '*viewp'. 3194225361Sdougb */ 3195225361Sdougbstatic isc_result_t 3196225361Sdougbcreate_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3197225361Sdougb dns_view_t **viewp) 3198225361Sdougb{ 3199225361Sdougb isc_result_t result; 3200225361Sdougb const char *viewname = NULL; 3201225361Sdougb dns_rdataclass_t viewclass; 3202225361Sdougb dns_view_t *view = NULL; 3203225361Sdougb 3204225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3205225361Sdougb if (result != ISC_R_SUCCESS) 3206225361Sdougb return (result); 3207225361Sdougb 3208225361Sdougb result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3209135446Strhodes if (result == ISC_R_SUCCESS) 3210135446Strhodes return (ISC_R_EXISTS); 3211135446Strhodes if (result != ISC_R_NOTFOUND) 3212135446Strhodes return (result); 3213135446Strhodes INSIST(view == NULL); 3214135446Strhodes 3215135446Strhodes result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 3216135446Strhodes if (result != ISC_R_SUCCESS) 3217135446Strhodes return (result); 3218135446Strhodes 3219135446Strhodes ISC_LIST_APPEND(*viewlist, view, link); 3220135446Strhodes dns_view_attach(view, viewp); 3221135446Strhodes return (ISC_R_SUCCESS); 3222135446Strhodes} 3223135446Strhodes 3224135446Strhodes/* 3225135446Strhodes * Configure or reconfigure a zone. 3226135446Strhodes */ 3227135446Strhodesstatic isc_result_t 3228165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 3229165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 3230224092Sdougb cfg_aclconfctx_t *aclconf, isc_boolean_t added) 3231135446Strhodes{ 3232135446Strhodes dns_view_t *pview = NULL; /* Production view */ 3233135446Strhodes dns_zone_t *zone = NULL; /* New or reused zone */ 3234135446Strhodes dns_zone_t *dupzone = NULL; 3235165071Sdougb const cfg_obj_t *options = NULL; 3236165071Sdougb const cfg_obj_t *zoptions = NULL; 3237165071Sdougb const cfg_obj_t *typeobj = NULL; 3238165071Sdougb const cfg_obj_t *forwarders = NULL; 3239165071Sdougb const cfg_obj_t *forwardtype = NULL; 3240165071Sdougb const cfg_obj_t *only = NULL; 3241135446Strhodes isc_result_t result; 3242135446Strhodes isc_result_t tresult; 3243135446Strhodes isc_buffer_t buffer; 3244135446Strhodes dns_fixedname_t fixorigin; 3245135446Strhodes dns_name_t *origin; 3246135446Strhodes const char *zname; 3247135446Strhodes dns_rdataclass_t zclass; 3248135446Strhodes const char *ztypestr; 3249135446Strhodes 3250135446Strhodes options = NULL; 3251135446Strhodes (void)cfg_map_get(config, "options", &options); 3252135446Strhodes 3253135446Strhodes zoptions = cfg_tuple_get(zconfig, "options"); 3254135446Strhodes 3255135446Strhodes /* 3256135446Strhodes * Get the zone origin as a dns_name_t. 3257135446Strhodes */ 3258135446Strhodes zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 3259135446Strhodes isc_buffer_init(&buffer, zname, strlen(zname)); 3260135446Strhodes isc_buffer_add(&buffer, strlen(zname)); 3261135446Strhodes dns_fixedname_init(&fixorigin); 3262135446Strhodes CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 3263224092Sdougb &buffer, dns_rootname, 0, NULL)); 3264135446Strhodes origin = dns_fixedname_name(&fixorigin); 3265135446Strhodes 3266135446Strhodes CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 3267135446Strhodes view->rdclass, &zclass)); 3268135446Strhodes if (zclass != view->rdclass) { 3269135446Strhodes const char *vname = NULL; 3270135446Strhodes if (vconfig != NULL) 3271135446Strhodes vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 3272135446Strhodes "name")); 3273135446Strhodes else 3274135446Strhodes vname = "<default view>"; 3275186462Sdougb 3276135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3277135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3278135446Strhodes "zone '%s': wrong class for view '%s'", 3279135446Strhodes zname, vname); 3280135446Strhodes result = ISC_R_FAILURE; 3281135446Strhodes goto cleanup; 3282135446Strhodes } 3283135446Strhodes 3284135446Strhodes (void)cfg_map_get(zoptions, "type", &typeobj); 3285135446Strhodes if (typeobj == NULL) { 3286135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3287135446Strhodes "zone '%s' 'type' not specified", zname); 3288135446Strhodes return (ISC_R_FAILURE); 3289135446Strhodes } 3290135446Strhodes ztypestr = cfg_obj_asstring(typeobj); 3291135446Strhodes 3292135446Strhodes /* 3293224092Sdougb * "hints zones" aren't zones. If we've got one, 3294135446Strhodes * configure it and return. 3295135446Strhodes */ 3296135446Strhodes if (strcasecmp(ztypestr, "hint") == 0) { 3297165071Sdougb const cfg_obj_t *fileobj = NULL; 3298135446Strhodes if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 3299135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3300135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3301135446Strhodes "zone '%s': 'file' not specified", 3302135446Strhodes zname); 3303135446Strhodes result = ISC_R_FAILURE; 3304135446Strhodes goto cleanup; 3305135446Strhodes } 3306135446Strhodes if (dns_name_equal(origin, dns_rootname)) { 3307165071Sdougb const char *hintsfile = cfg_obj_asstring(fileobj); 3308135446Strhodes 3309135446Strhodes result = configure_hints(view, hintsfile); 3310135446Strhodes if (result != ISC_R_SUCCESS) { 3311135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3312135446Strhodes NS_LOGMODULE_SERVER, 3313135446Strhodes ISC_LOG_ERROR, 3314135446Strhodes "could not configure root hints " 3315135446Strhodes "from '%s': %s", hintsfile, 3316135446Strhodes isc_result_totext(result)); 3317135446Strhodes goto cleanup; 3318135446Strhodes } 3319135446Strhodes /* 3320135446Strhodes * Hint zones may also refer to delegation only points. 3321135446Strhodes */ 3322135446Strhodes only = NULL; 3323135446Strhodes tresult = cfg_map_get(zoptions, "delegation-only", 3324135446Strhodes &only); 3325135446Strhodes if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 3326135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 3327135446Strhodes } else { 3328135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3329135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3330135446Strhodes "ignoring non-root hint zone '%s'", 3331135446Strhodes zname); 3332135446Strhodes result = ISC_R_SUCCESS; 3333135446Strhodes } 3334135446Strhodes /* Skip ordinary zone processing. */ 3335135446Strhodes goto cleanup; 3336135446Strhodes } 3337135446Strhodes 3338135446Strhodes /* 3339135446Strhodes * "forward zones" aren't zones either. Translate this syntax into 3340135446Strhodes * the appropriate selective forwarding configuration and return. 3341135446Strhodes */ 3342135446Strhodes if (strcasecmp(ztypestr, "forward") == 0) { 3343135446Strhodes forwardtype = NULL; 3344135446Strhodes forwarders = NULL; 3345135446Strhodes 3346135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 3347135446Strhodes (void)cfg_map_get(zoptions, "forwarders", &forwarders); 3348135446Strhodes result = configure_forward(config, view, origin, forwarders, 3349135446Strhodes forwardtype); 3350135446Strhodes goto cleanup; 3351135446Strhodes } 3352135446Strhodes 3353135446Strhodes /* 3354135446Strhodes * "delegation-only zones" aren't zones either. 3355135446Strhodes */ 3356135446Strhodes if (strcasecmp(ztypestr, "delegation-only") == 0) { 3357135446Strhodes result = dns_view_adddelegationonly(view, origin); 3358135446Strhodes goto cleanup; 3359135446Strhodes } 3360135446Strhodes 3361135446Strhodes /* 3362135446Strhodes * Check for duplicates in the new zone table. 3363135446Strhodes */ 3364135446Strhodes result = dns_view_findzone(view, origin, &dupzone); 3365135446Strhodes if (result == ISC_R_SUCCESS) { 3366135446Strhodes /* 3367135446Strhodes * We already have this zone! 3368135446Strhodes */ 3369135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3370135446Strhodes "zone '%s' already exists", zname); 3371135446Strhodes dns_zone_detach(&dupzone); 3372135446Strhodes result = ISC_R_EXISTS; 3373135446Strhodes goto cleanup; 3374135446Strhodes } 3375135446Strhodes INSIST(dupzone == NULL); 3376135446Strhodes 3377135446Strhodes /* 3378135446Strhodes * See if we can reuse an existing zone. This is 3379135446Strhodes * only possible if all of these are true: 3380135446Strhodes * - The zone's view exists 3381135446Strhodes * - A zone with the right name exists in the view 3382135446Strhodes * - The zone is compatible with the config 3383135446Strhodes * options (e.g., an existing master zone cannot 3384135446Strhodes * be reused if the options specify a slave zone) 3385135446Strhodes */ 3386135446Strhodes result = dns_viewlist_find(&ns_g_server->viewlist, 3387135446Strhodes view->name, view->rdclass, 3388135446Strhodes &pview); 3389135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3390135446Strhodes goto cleanup; 3391135446Strhodes if (pview != NULL) 3392135446Strhodes result = dns_view_findzone(pview, origin, &zone); 3393135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3394135446Strhodes goto cleanup; 3395170222Sdougb if (zone != NULL && !ns_zone_reusable(zone, zconfig)) 3396170222Sdougb dns_zone_detach(&zone); 3397135446Strhodes 3398135446Strhodes if (zone != NULL) { 3399135446Strhodes /* 3400135446Strhodes * We found a reusable zone. Make it use the 3401135446Strhodes * new view. 3402135446Strhodes */ 3403135446Strhodes dns_zone_setview(zone, view); 3404170222Sdougb if (view->acache != NULL) 3405170222Sdougb dns_zone_setacache(zone, view->acache); 3406135446Strhodes } else { 3407135446Strhodes /* 3408135446Strhodes * We cannot reuse an existing zone, we have 3409135446Strhodes * to create a new one. 3410135446Strhodes */ 3411135446Strhodes CHECK(dns_zone_create(&zone, mctx)); 3412135446Strhodes CHECK(dns_zone_setorigin(zone, origin)); 3413135446Strhodes dns_zone_setview(zone, view); 3414170222Sdougb if (view->acache != NULL) 3415170222Sdougb dns_zone_setacache(zone, view->acache); 3416135446Strhodes CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 3417193149Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 3418135446Strhodes } 3419135446Strhodes 3420135446Strhodes /* 3421135446Strhodes * If the zone contains a 'forwarders' statement, configure 3422135446Strhodes * selective forwarding. 3423135446Strhodes */ 3424135446Strhodes forwarders = NULL; 3425135446Strhodes if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 3426135446Strhodes { 3427135446Strhodes forwardtype = NULL; 3428135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 3429135446Strhodes CHECK(configure_forward(config, view, origin, forwarders, 3430135446Strhodes forwardtype)); 3431135446Strhodes } 3432135446Strhodes 3433135446Strhodes /* 3434135446Strhodes * Stub and forward zones may also refer to delegation only points. 3435135446Strhodes */ 3436135446Strhodes only = NULL; 3437135446Strhodes if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 3438135446Strhodes { 3439135446Strhodes if (cfg_obj_asboolean(only)) 3440135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 3441135446Strhodes } 3442135446Strhodes 3443135446Strhodes /* 3444224092Sdougb * Mark whether the zone was originally added at runtime or not 3445224092Sdougb */ 3446224092Sdougb dns_zone_setadded(zone, added); 3447224092Sdougb 3448224092Sdougb /* 3449135446Strhodes * Configure the zone. 3450135446Strhodes */ 3451135446Strhodes CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); 3452135446Strhodes 3453135446Strhodes /* 3454135446Strhodes * Add the zone to its view in the new view list. 3455135446Strhodes */ 3456135446Strhodes CHECK(dns_view_addzone(view, zone)); 3457135446Strhodes 3458234010Sdougb /* 3459234010Sdougb * Ensure that zone keys are reloaded on reconfig 3460234010Sdougb */ 3461234010Sdougb if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) 3462234010Sdougb dns_zone_rekey(zone, ISC_FALSE); 3463234010Sdougb 3464135446Strhodes cleanup: 3465135446Strhodes if (zone != NULL) 3466135446Strhodes dns_zone_detach(&zone); 3467135446Strhodes if (pview != NULL) 3468135446Strhodes dns_view_detach(&pview); 3469135446Strhodes 3470135446Strhodes return (result); 3471135446Strhodes} 3472135446Strhodes 3473135446Strhodes/* 3474224092Sdougb * Configure built-in zone for storing managed-key data. 3475224092Sdougb */ 3476224092Sdougb 3477224092Sdougb#define KEYZONE "managed-keys.bind" 3478224092Sdougb#define MKEYS ".mkeys" 3479224092Sdougb 3480224092Sdougbstatic isc_result_t 3481224092Sdougbadd_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { 3482224092Sdougb isc_result_t result; 3483224092Sdougb dns_view_t *pview = NULL; 3484224092Sdougb dns_zone_t *zone = NULL; 3485224092Sdougb dns_acl_t *none = NULL; 3486224092Sdougb char filename[PATH_MAX]; 3487224092Sdougb char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)]; 3488224092Sdougb int n; 3489224092Sdougb 3490224092Sdougb REQUIRE(view != NULL); 3491224092Sdougb 3492224092Sdougb /* See if we can re-use an existing keydata zone. */ 3493224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 3494224092Sdougb view->name, view->rdclass, 3495224092Sdougb &pview); 3496224092Sdougb if (result != ISC_R_NOTFOUND && 3497224092Sdougb result != ISC_R_SUCCESS) 3498224092Sdougb return (result); 3499224092Sdougb 3500224092Sdougb if (pview != NULL && pview->managed_keys != NULL) { 3501224092Sdougb dns_zone_attach(pview->managed_keys, &view->managed_keys); 3502224092Sdougb dns_zone_setview(pview->managed_keys, view); 3503224092Sdougb dns_view_detach(&pview); 3504234010Sdougb dns_zone_synckeyzone(view->managed_keys); 3505224092Sdougb return (ISC_R_SUCCESS); 3506224092Sdougb } 3507224092Sdougb 3508224092Sdougb /* No existing keydata zone was found; create one */ 3509224092Sdougb CHECK(dns_zone_create(&zone, mctx)); 3510224092Sdougb CHECK(dns_zone_setorigin(zone, dns_rootname)); 3511224092Sdougb 3512224092Sdougb isc_sha256_data((void *)view->name, strlen(view->name), buffer); 3513224092Sdougb strcat(buffer, MKEYS); 3514224092Sdougb n = snprintf(filename, sizeof(filename), "%s%s%s", 3515224092Sdougb directory ? directory : "", directory ? "/" : "", 3516224092Sdougb strcmp(view->name, "_default") == 0 ? KEYZONE : buffer); 3517224092Sdougb if (n < 0 || (size_t)n >= sizeof(filename)) { 3518224092Sdougb result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE; 3519224092Sdougb goto cleanup; 3520224092Sdougb } 3521224092Sdougb CHECK(dns_zone_setfile(zone, filename)); 3522224092Sdougb 3523224092Sdougb dns_zone_setview(zone, view); 3524224092Sdougb dns_zone_settype(zone, dns_zone_key); 3525224092Sdougb dns_zone_setclass(zone, view->rdclass); 3526224092Sdougb 3527224092Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 3528224092Sdougb 3529224092Sdougb if (view->acache != NULL) 3530224092Sdougb dns_zone_setacache(zone, view->acache); 3531224092Sdougb 3532224092Sdougb CHECK(dns_acl_none(mctx, &none)); 3533224092Sdougb dns_zone_setqueryacl(zone, none); 3534224092Sdougb dns_zone_setqueryonacl(zone, none); 3535224092Sdougb dns_acl_detach(&none); 3536224092Sdougb 3537224092Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 3538224092Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 3539224092Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 3540224092Sdougb dns_zone_setjournalsize(zone, 0); 3541224092Sdougb 3542224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 3543224092Sdougb CHECK(setquerystats(zone, mctx, ISC_FALSE)); 3544224092Sdougb 3545224092Sdougb if (view->managed_keys != NULL) 3546224092Sdougb dns_zone_detach(&view->managed_keys); 3547224092Sdougb dns_zone_attach(zone, &view->managed_keys); 3548224092Sdougb 3549224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3550224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3551224092Sdougb "set up managed keys zone for view %s, file '%s'", 3552224092Sdougb view->name, filename); 3553224092Sdougb 3554224092Sdougbcleanup: 3555224092Sdougb if (zone != NULL) 3556224092Sdougb dns_zone_detach(&zone); 3557224092Sdougb if (none != NULL) 3558224092Sdougb dns_acl_detach(&none); 3559224092Sdougb 3560224092Sdougb return (result); 3561224092Sdougb} 3562224092Sdougb 3563224092Sdougb/* 3564135446Strhodes * Configure a single server quota. 3565135446Strhodes */ 3566135446Strhodesstatic void 3567165071Sdougbconfigure_server_quota(const cfg_obj_t **maps, const char *name, 3568165071Sdougb isc_quota_t *quota) 3569135446Strhodes{ 3570165071Sdougb const cfg_obj_t *obj = NULL; 3571135446Strhodes isc_result_t result; 3572135446Strhodes 3573135446Strhodes result = ns_config_get(maps, name, &obj); 3574135446Strhodes INSIST(result == ISC_R_SUCCESS); 3575153816Sdougb isc_quota_max(quota, cfg_obj_asuint32(obj)); 3576135446Strhodes} 3577135446Strhodes 3578135446Strhodes/* 3579135446Strhodes * This function is called as soon as the 'directory' statement has been 3580135446Strhodes * parsed. This can be extended to support other options if necessary. 3581135446Strhodes */ 3582135446Strhodesstatic isc_result_t 3583165071Sdougbdirectory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 3584135446Strhodes isc_result_t result; 3585165071Sdougb const char *directory; 3586135446Strhodes 3587135446Strhodes REQUIRE(strcasecmp("directory", clausename) == 0); 3588135446Strhodes 3589135446Strhodes UNUSED(arg); 3590135446Strhodes UNUSED(clausename); 3591135446Strhodes 3592135446Strhodes /* 3593135446Strhodes * Change directory. 3594135446Strhodes */ 3595135446Strhodes directory = cfg_obj_asstring(obj); 3596135446Strhodes 3597135446Strhodes if (! isc_file_ischdiridempotent(directory)) 3598135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 3599135446Strhodes "option 'directory' contains relative path '%s'", 3600135446Strhodes directory); 3601135446Strhodes 3602135446Strhodes result = isc_dir_chdir(directory); 3603135446Strhodes if (result != ISC_R_SUCCESS) { 3604135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 3605135446Strhodes "change directory to '%s' failed: %s", 3606135446Strhodes directory, isc_result_totext(result)); 3607135446Strhodes return (result); 3608135446Strhodes } 3609135446Strhodes 3610135446Strhodes return (ISC_R_SUCCESS); 3611135446Strhodes} 3612135446Strhodes 3613135446Strhodesstatic void 3614135446Strhodesscan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 3615135446Strhodes isc_boolean_t match_mapped = server->aclenv.match_mapped; 3616135446Strhodes 3617135446Strhodes ns_interfacemgr_scan(server->interfacemgr, verbose); 3618135446Strhodes /* 3619135446Strhodes * Update the "localhost" and "localnets" ACLs to match the 3620135446Strhodes * current set of network interfaces. 3621135446Strhodes */ 3622135446Strhodes dns_aclenv_copy(&server->aclenv, 3623135446Strhodes ns_interfacemgr_getaclenv(server->interfacemgr)); 3624135446Strhodes 3625135446Strhodes server->aclenv.match_mapped = match_mapped; 3626135446Strhodes} 3627135446Strhodes 3628135446Strhodesstatic isc_result_t 3629180477Sdougbadd_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, 3630180477Sdougb isc_boolean_t wcardport_ok) 3631180477Sdougb{ 3632135446Strhodes ns_listenelt_t *lelt = NULL; 3633135446Strhodes dns_acl_t *src_acl = NULL; 3634135446Strhodes isc_result_t result; 3635135446Strhodes isc_sockaddr_t any_sa6; 3636193149Sdougb isc_netaddr_t netaddr; 3637135446Strhodes 3638135446Strhodes REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 3639135446Strhodes 3640135446Strhodes isc_sockaddr_any6(&any_sa6); 3641180477Sdougb if (!isc_sockaddr_equal(&any_sa6, addr) && 3642180477Sdougb (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { 3643193149Sdougb isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr); 3644135446Strhodes 3645193149Sdougb result = dns_acl_create(mctx, 0, &src_acl); 3646135446Strhodes if (result != ISC_R_SUCCESS) 3647135446Strhodes return (result); 3648193149Sdougb 3649193149Sdougb result = dns_iptable_addprefix(src_acl->iptable, 3650193149Sdougb &netaddr, 128, ISC_TRUE); 3651135446Strhodes if (result != ISC_R_SUCCESS) 3652135446Strhodes goto clean; 3653135446Strhodes 3654135446Strhodes result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 3655135446Strhodes src_acl, &lelt); 3656135446Strhodes if (result != ISC_R_SUCCESS) 3657135446Strhodes goto clean; 3658135446Strhodes ISC_LIST_APPEND(list->elts, lelt, link); 3659135446Strhodes } 3660135446Strhodes 3661135446Strhodes return (ISC_R_SUCCESS); 3662135446Strhodes 3663135446Strhodes clean: 3664135446Strhodes INSIST(lelt == NULL); 3665165071Sdougb dns_acl_detach(&src_acl); 3666135446Strhodes 3667135446Strhodes return (result); 3668135446Strhodes} 3669135446Strhodes 3670135446Strhodes/* 3671135446Strhodes * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 3672135446Strhodes * to update the listening interfaces accordingly. 3673135446Strhodes * We currently only consider IPv6, because this only affects IPv6 wildcard 3674135446Strhodes * sockets. 3675135446Strhodes */ 3676135446Strhodesstatic void 3677135446Strhodesadjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 3678135446Strhodes isc_result_t result; 3679135446Strhodes ns_listenlist_t *list = NULL; 3680135446Strhodes dns_view_t *view; 3681135446Strhodes dns_zone_t *zone, *next; 3682135446Strhodes isc_sockaddr_t addr, *addrp; 3683135446Strhodes 3684135446Strhodes result = ns_listenlist_create(mctx, &list); 3685135446Strhodes if (result != ISC_R_SUCCESS) 3686135446Strhodes return; 3687135446Strhodes 3688135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3689135446Strhodes view != NULL; 3690135446Strhodes view = ISC_LIST_NEXT(view, link)) { 3691135446Strhodes dns_dispatch_t *dispatch6; 3692135446Strhodes 3693135446Strhodes dispatch6 = dns_resolver_dispatchv6(view->resolver); 3694143731Sdougb if (dispatch6 == NULL) 3695143731Sdougb continue; 3696135446Strhodes result = dns_dispatch_getlocaladdress(dispatch6, &addr); 3697135446Strhodes if (result != ISC_R_SUCCESS) 3698135446Strhodes goto fail; 3699180477Sdougb 3700180477Sdougb /* 3701180477Sdougb * We always add non-wildcard address regardless of whether 3702180477Sdougb * the port is 'any' (the fourth arg is TRUE): if the port is 3703180477Sdougb * specific, we need to add it since it may conflict with a 3704180477Sdougb * listening interface; if it's zero, we'll dynamically open 3705180477Sdougb * query ports, and some of them may override an existing 3706180477Sdougb * wildcard IPv6 port. 3707180477Sdougb */ 3708180477Sdougb result = add_listenelt(mctx, list, &addr, ISC_TRUE); 3709135446Strhodes if (result != ISC_R_SUCCESS) 3710135446Strhodes goto fail; 3711135446Strhodes } 3712135446Strhodes 3713135446Strhodes zone = NULL; 3714135446Strhodes for (result = dns_zone_first(server->zonemgr, &zone); 3715135446Strhodes result == ISC_R_SUCCESS; 3716135446Strhodes next = NULL, result = dns_zone_next(zone, &next), zone = next) { 3717135446Strhodes dns_view_t *zoneview; 3718135446Strhodes 3719135446Strhodes /* 3720135446Strhodes * At this point the zone list may contain a stale zone 3721135446Strhodes * just removed from the configuration. To see the validity, 3722135446Strhodes * check if the corresponding view is in our current view list. 3723153816Sdougb * There may also be old zones that are still in the process 3724153816Sdougb * of shutting down and have detached from their old view 3725153816Sdougb * (zoneview == NULL). 3726135446Strhodes */ 3727135446Strhodes zoneview = dns_zone_getview(zone); 3728153816Sdougb if (zoneview == NULL) 3729153816Sdougb continue; 3730135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3731135446Strhodes view != NULL && view != zoneview; 3732135446Strhodes view = ISC_LIST_NEXT(view, link)) 3733135446Strhodes ; 3734135446Strhodes if (view == NULL) 3735135446Strhodes continue; 3736135446Strhodes 3737135446Strhodes addrp = dns_zone_getnotifysrc6(zone); 3738180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 3739135446Strhodes if (result != ISC_R_SUCCESS) 3740135446Strhodes goto fail; 3741135446Strhodes 3742135446Strhodes addrp = dns_zone_getxfrsource6(zone); 3743180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 3744135446Strhodes if (result != ISC_R_SUCCESS) 3745135446Strhodes goto fail; 3746135446Strhodes } 3747135446Strhodes 3748135446Strhodes ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 3749186462Sdougb 3750135446Strhodes clean: 3751135446Strhodes ns_listenlist_detach(&list); 3752135446Strhodes return; 3753135446Strhodes 3754135446Strhodes fail: 3755135446Strhodes /* 3756135446Strhodes * Even when we failed the procedure, most of other interfaces 3757135446Strhodes * should work correctly. We therefore just warn it. 3758135446Strhodes */ 3759135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3760135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3761135446Strhodes "could not adjust the listen-on list; " 3762135446Strhodes "some interfaces may not work"); 3763135446Strhodes goto clean; 3764135446Strhodes} 3765135446Strhodes 3766135446Strhodes/* 3767135446Strhodes * This event callback is invoked to do periodic network 3768135446Strhodes * interface scanning. 3769135446Strhodes */ 3770135446Strhodesstatic void 3771135446Strhodesinterface_timer_tick(isc_task_t *task, isc_event_t *event) { 3772135446Strhodes isc_result_t result; 3773135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 3774135446Strhodes INSIST(task == server->task); 3775135446Strhodes UNUSED(task); 3776135446Strhodes isc_event_free(&event); 3777135446Strhodes /* 3778135446Strhodes * XXX should scan interfaces unlocked and get exclusive access 3779135446Strhodes * only to replace ACLs. 3780135446Strhodes */ 3781135446Strhodes result = isc_task_beginexclusive(server->task); 3782135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3783135446Strhodes scan_interfaces(server, ISC_FALSE); 3784135446Strhodes isc_task_endexclusive(server->task); 3785135446Strhodes} 3786135446Strhodes 3787135446Strhodesstatic void 3788135446Strhodesheartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 3789135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 3790135446Strhodes dns_view_t *view; 3791135446Strhodes 3792135446Strhodes UNUSED(task); 3793135446Strhodes isc_event_free(&event); 3794135446Strhodes view = ISC_LIST_HEAD(server->viewlist); 3795135446Strhodes while (view != NULL) { 3796135446Strhodes dns_view_dialup(view); 3797135446Strhodes view = ISC_LIST_NEXT(view, link); 3798135446Strhodes } 3799135446Strhodes} 3800135446Strhodes 3801170222Sdougbstatic void 3802170222Sdougbpps_timer_tick(isc_task_t *task, isc_event_t *event) { 3803170222Sdougb static unsigned int oldrequests = 0; 3804170222Sdougb unsigned int requests = ns_client_requests; 3805170222Sdougb 3806170222Sdougb UNUSED(task); 3807170222Sdougb isc_event_free(&event); 3808170222Sdougb 3809170222Sdougb /* 3810170222Sdougb * Don't worry about wrapping as the overflow result will be right. 3811170222Sdougb */ 3812170222Sdougb dns_pps = (requests - oldrequests) / 1200; 3813170222Sdougb oldrequests = requests; 3814170222Sdougb} 3815170222Sdougb 3816135446Strhodes/* 3817135446Strhodes * Replace the current value of '*field', a dynamically allocated 3818135446Strhodes * string or NULL, with a dynamically allocated copy of the 3819135446Strhodes * null-terminated string pointed to by 'value', or NULL. 3820135446Strhodes */ 3821135446Strhodesstatic isc_result_t 3822135446Strhodessetstring(ns_server_t *server, char **field, const char *value) { 3823135446Strhodes char *copy; 3824135446Strhodes 3825135446Strhodes if (value != NULL) { 3826135446Strhodes copy = isc_mem_strdup(server->mctx, value); 3827135446Strhodes if (copy == NULL) 3828135446Strhodes return (ISC_R_NOMEMORY); 3829135446Strhodes } else { 3830135446Strhodes copy = NULL; 3831135446Strhodes } 3832135446Strhodes 3833135446Strhodes if (*field != NULL) 3834135446Strhodes isc_mem_free(server->mctx, *field); 3835135446Strhodes 3836135446Strhodes *field = copy; 3837135446Strhodes return (ISC_R_SUCCESS); 3838186462Sdougb} 3839135446Strhodes 3840135446Strhodes/* 3841135446Strhodes * Replace the current value of '*field', a dynamically allocated 3842135446Strhodes * string or NULL, with another dynamically allocated string 3843135446Strhodes * or NULL if whether 'obj' is a string or void value, respectively. 3844135446Strhodes */ 3845135446Strhodesstatic isc_result_t 3846165071Sdougbsetoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 3847135446Strhodes if (cfg_obj_isvoid(obj)) 3848135446Strhodes return (setstring(server, field, NULL)); 3849135446Strhodes else 3850135446Strhodes return (setstring(server, field, cfg_obj_asstring(obj))); 3851135446Strhodes} 3852135446Strhodes 3853135446Strhodesstatic void 3854165071Sdougbset_limit(const cfg_obj_t **maps, const char *configname, 3855165071Sdougb const char *description, isc_resource_t resourceid, 3856165071Sdougb isc_resourcevalue_t defaultvalue) 3857135446Strhodes{ 3858165071Sdougb const cfg_obj_t *obj = NULL; 3859165071Sdougb const char *resource; 3860135446Strhodes isc_resourcevalue_t value; 3861135446Strhodes isc_result_t result; 3862135446Strhodes 3863135446Strhodes if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 3864135446Strhodes return; 3865135446Strhodes 3866135446Strhodes if (cfg_obj_isstring(obj)) { 3867135446Strhodes resource = cfg_obj_asstring(obj); 3868135446Strhodes if (strcasecmp(resource, "unlimited") == 0) 3869135446Strhodes value = ISC_RESOURCE_UNLIMITED; 3870135446Strhodes else { 3871135446Strhodes INSIST(strcasecmp(resource, "default") == 0); 3872135446Strhodes value = defaultvalue; 3873135446Strhodes } 3874135446Strhodes } else 3875135446Strhodes value = cfg_obj_asuint64(obj); 3876135446Strhodes 3877135446Strhodes result = isc_resource_setlimit(resourceid, value); 3878135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3879135446Strhodes result == ISC_R_SUCCESS ? 3880186462Sdougb ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 3881204619Sdougb "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s", 3882135446Strhodes description, value, isc_result_totext(result)); 3883135446Strhodes} 3884135446Strhodes 3885135446Strhodes#define SETLIMIT(cfgvar, resource, description) \ 3886135446Strhodes set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 3887135446Strhodes ns_g_init ## resource) 3888135446Strhodes 3889135446Strhodesstatic void 3890165071Sdougbset_limits(const cfg_obj_t **maps) { 3891135446Strhodes SETLIMIT("stacksize", stacksize, "stack size"); 3892135446Strhodes SETLIMIT("datasize", datasize, "data size"); 3893135446Strhodes SETLIMIT("coresize", coresize, "core size"); 3894135446Strhodes SETLIMIT("files", openfiles, "open files"); 3895135446Strhodes} 3896135446Strhodes 3897186462Sdougbstatic void 3898186462Sdougbportset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports, 3899186462Sdougb isc_boolean_t positive) 3900135446Strhodes{ 3901165071Sdougb const cfg_listelt_t *element; 3902135446Strhodes 3903135446Strhodes for (element = cfg_list_first(ports); 3904135446Strhodes element != NULL; 3905135446Strhodes element = cfg_list_next(element)) { 3906165071Sdougb const cfg_obj_t *obj = cfg_listelt_value(element); 3907186462Sdougb 3908186462Sdougb if (cfg_obj_isuint32(obj)) { 3909186462Sdougb in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 3910186462Sdougb 3911186462Sdougb if (positive) 3912186462Sdougb isc_portset_add(portset, port); 3913186462Sdougb else 3914186462Sdougb isc_portset_remove(portset, port); 3915186462Sdougb } else { 3916186462Sdougb const cfg_obj_t *obj_loport, *obj_hiport; 3917186462Sdougb in_port_t loport, hiport; 3918186462Sdougb 3919186462Sdougb obj_loport = cfg_tuple_get(obj, "loport"); 3920186462Sdougb loport = (in_port_t)cfg_obj_asuint32(obj_loport); 3921186462Sdougb obj_hiport = cfg_tuple_get(obj, "hiport"); 3922186462Sdougb hiport = (in_port_t)cfg_obj_asuint32(obj_hiport); 3923186462Sdougb 3924186462Sdougb if (positive) 3925186462Sdougb isc_portset_addrange(portset, loport, hiport); 3926186462Sdougb else { 3927186462Sdougb isc_portset_removerange(portset, loport, 3928186462Sdougb hiport); 3929186462Sdougb } 3930186462Sdougb } 3931135446Strhodes } 3932135446Strhodes} 3933135446Strhodes 3934135446Strhodesstatic isc_result_t 3935170222Sdougbremoved(dns_zone_t *zone, void *uap) { 3936170222Sdougb const char *type; 3937170222Sdougb 3938186462Sdougb if (dns_zone_getview(zone) != uap) 3939170222Sdougb return (ISC_R_SUCCESS); 3940170222Sdougb 3941170222Sdougb switch (dns_zone_gettype(zone)) { 3942170222Sdougb case dns_zone_master: 3943170222Sdougb type = "master"; 3944170222Sdougb break; 3945170222Sdougb case dns_zone_slave: 3946170222Sdougb type = "slave"; 3947170222Sdougb break; 3948170222Sdougb case dns_zone_stub: 3949170222Sdougb type = "stub"; 3950170222Sdougb break; 3951170222Sdougb default: 3952170222Sdougb type = "other"; 3953170222Sdougb break; 3954170222Sdougb } 3955170222Sdougb dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); 3956170222Sdougb return (ISC_R_SUCCESS); 3957170222Sdougb} 3958170222Sdougb 3959224092Sdougbstatic void 3960224092Sdougbcleanup_session_key(ns_server_t *server, isc_mem_t *mctx) { 3961224092Sdougb if (server->session_keyfile != NULL) { 3962224092Sdougb isc_file_remove(server->session_keyfile); 3963224092Sdougb isc_mem_free(mctx, server->session_keyfile); 3964224092Sdougb server->session_keyfile = NULL; 3965224092Sdougb } 3966224092Sdougb 3967224092Sdougb if (server->session_keyname != NULL) { 3968224092Sdougb if (dns_name_dynamic(server->session_keyname)) 3969224092Sdougb dns_name_free(server->session_keyname, mctx); 3970224092Sdougb isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t)); 3971224092Sdougb server->session_keyname = NULL; 3972224092Sdougb } 3973224092Sdougb 3974224092Sdougb if (server->sessionkey != NULL) 3975224092Sdougb dns_tsigkey_detach(&server->sessionkey); 3976224092Sdougb 3977224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 3978224092Sdougb server->session_keybits = 0; 3979224092Sdougb} 3980224092Sdougb 3981170222Sdougbstatic isc_result_t 3982224092Sdougbgenerate_session_key(const char *filename, const char *keynamestr, 3983224092Sdougb dns_name_t *keyname, const char *algstr, 3984224092Sdougb dns_name_t *algname, unsigned int algtype, 3985224092Sdougb isc_uint16_t bits, isc_mem_t *mctx, 3986224092Sdougb dns_tsigkey_t **tsigkeyp) 3987224092Sdougb{ 3988224092Sdougb isc_result_t result = ISC_R_SUCCESS; 3989224092Sdougb dst_key_t *key = NULL; 3990224092Sdougb isc_buffer_t key_txtbuffer; 3991224092Sdougb isc_buffer_t key_rawbuffer; 3992224092Sdougb char key_txtsecret[256]; 3993224092Sdougb char key_rawsecret[64]; 3994224092Sdougb isc_region_t key_rawregion; 3995224092Sdougb isc_stdtime_t now; 3996224092Sdougb dns_tsigkey_t *tsigkey = NULL; 3997224092Sdougb FILE *fp = NULL; 3998224092Sdougb 3999224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4000224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4001224092Sdougb "generating session key for dynamic DNS"); 4002224092Sdougb 4003224092Sdougb /* generate key */ 4004224092Sdougb result = dst_key_generate(keyname, algtype, bits, 1, 0, 4005224092Sdougb DNS_KEYPROTO_ANY, dns_rdataclass_in, 4006224092Sdougb mctx, &key); 4007224092Sdougb if (result != ISC_R_SUCCESS) 4008224092Sdougb return (result); 4009224092Sdougb 4010224092Sdougb /* 4011224092Sdougb * Dump the key to the buffer for later use. Should be done before 4012224092Sdougb * we transfer the ownership of key to tsigkey. 4013224092Sdougb */ 4014224092Sdougb isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); 4015224092Sdougb CHECK(dst_key_tobuffer(key, &key_rawbuffer)); 4016224092Sdougb 4017224092Sdougb isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); 4018224092Sdougb isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 4019224092Sdougb CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer)); 4020224092Sdougb 4021224092Sdougb /* Store the key in tsigkey. */ 4022224092Sdougb isc_stdtime_get(&now); 4023224092Sdougb CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, 4024224092Sdougb ISC_FALSE, NULL, now, now, mctx, NULL, 4025224092Sdougb &tsigkey)); 4026224092Sdougb 4027224092Sdougb /* Dump the key to the key file. */ 4028224092Sdougb fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE); 4029224092Sdougb if (fp == NULL) { 4030224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4031224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4032224092Sdougb "could not create %s", filename); 4033224092Sdougb result = ISC_R_NOPERM; 4034224092Sdougb goto cleanup; 4035224092Sdougb } 4036224092Sdougb 4037224092Sdougb fprintf(fp, "key \"%s\" {\n" 4038224092Sdougb "\talgorithm %s;\n" 4039224092Sdougb "\tsecret \"%.*s\";\n};\n", keynamestr, algstr, 4040224092Sdougb (int) isc_buffer_usedlength(&key_txtbuffer), 4041224092Sdougb (char*) isc_buffer_base(&key_txtbuffer)); 4042224092Sdougb 4043224092Sdougb RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS); 4044224092Sdougb RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS); 4045224092Sdougb 4046224092Sdougb dst_key_free(&key); 4047224092Sdougb 4048224092Sdougb *tsigkeyp = tsigkey; 4049224092Sdougb 4050224092Sdougb return (ISC_R_SUCCESS); 4051224092Sdougb 4052224092Sdougb cleanup: 4053224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4054224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4055224092Sdougb "failed to generate session key " 4056224092Sdougb "for dynamic DNS: %s", isc_result_totext(result)); 4057224092Sdougb if (tsigkey != NULL) 4058224092Sdougb dns_tsigkey_detach(&tsigkey); 4059224092Sdougb if (key != NULL) 4060224092Sdougb dst_key_free(&key); 4061224092Sdougb 4062224092Sdougb return (result); 4063224092Sdougb} 4064224092Sdougb 4065224092Sdougbstatic isc_result_t 4066224092Sdougbconfigure_session_key(const cfg_obj_t **maps, ns_server_t *server, 4067224092Sdougb isc_mem_t *mctx) 4068224092Sdougb{ 4069224092Sdougb const char *keyfile, *keynamestr, *algstr; 4070224092Sdougb unsigned int algtype; 4071224092Sdougb dns_fixedname_t fname; 4072224092Sdougb dns_name_t *keyname, *algname; 4073224092Sdougb isc_buffer_t buffer; 4074224092Sdougb isc_uint16_t bits; 4075224092Sdougb const cfg_obj_t *obj; 4076224092Sdougb isc_boolean_t need_deleteold = ISC_FALSE; 4077224092Sdougb isc_boolean_t need_createnew = ISC_FALSE; 4078224092Sdougb isc_result_t result; 4079224092Sdougb 4080224092Sdougb obj = NULL; 4081224092Sdougb result = ns_config_get(maps, "session-keyfile", &obj); 4082224092Sdougb if (result == ISC_R_SUCCESS) { 4083224092Sdougb if (cfg_obj_isvoid(obj)) 4084224092Sdougb keyfile = NULL; /* disable it */ 4085224092Sdougb else 4086224092Sdougb keyfile = cfg_obj_asstring(obj); 4087224092Sdougb } else 4088224092Sdougb keyfile = ns_g_defaultsessionkeyfile; 4089224092Sdougb 4090224092Sdougb obj = NULL; 4091224092Sdougb result = ns_config_get(maps, "session-keyname", &obj); 4092224092Sdougb INSIST(result == ISC_R_SUCCESS); 4093224092Sdougb keynamestr = cfg_obj_asstring(obj); 4094224092Sdougb dns_fixedname_init(&fname); 4095224092Sdougb isc_buffer_init(&buffer, keynamestr, strlen(keynamestr)); 4096224092Sdougb isc_buffer_add(&buffer, strlen(keynamestr)); 4097224092Sdougb keyname = dns_fixedname_name(&fname); 4098224092Sdougb result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL); 4099224092Sdougb if (result != ISC_R_SUCCESS) 4100224092Sdougb return (result); 4101224092Sdougb 4102224092Sdougb obj = NULL; 4103224092Sdougb result = ns_config_get(maps, "session-keyalg", &obj); 4104224092Sdougb INSIST(result == ISC_R_SUCCESS); 4105224092Sdougb algstr = cfg_obj_asstring(obj); 4106224092Sdougb algname = NULL; 4107224092Sdougb result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits); 4108224092Sdougb if (result != ISC_R_SUCCESS) { 4109224092Sdougb const char *s = " (keeping current key)"; 4110224092Sdougb 4111224092Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: " 4112224092Sdougb "unsupported or unknown algorithm '%s'%s", 4113224092Sdougb algstr, 4114224092Sdougb server->session_keyfile != NULL ? s : ""); 4115224092Sdougb return (result); 4116224092Sdougb } 4117224092Sdougb 4118224092Sdougb /* See if we need to (re)generate a new key. */ 4119224092Sdougb if (keyfile == NULL) { 4120224092Sdougb if (server->session_keyfile != NULL) 4121224092Sdougb need_deleteold = ISC_TRUE; 4122224092Sdougb } else if (server->session_keyfile == NULL) 4123224092Sdougb need_createnew = ISC_TRUE; 4124224092Sdougb else if (strcmp(keyfile, server->session_keyfile) != 0 || 4125224092Sdougb !dns_name_equal(server->session_keyname, keyname) || 4126224092Sdougb server->session_keyalg != algtype || 4127224092Sdougb server->session_keybits != bits) { 4128224092Sdougb need_deleteold = ISC_TRUE; 4129224092Sdougb need_createnew = ISC_TRUE; 4130224092Sdougb } 4131224092Sdougb 4132224092Sdougb if (need_deleteold) { 4133224092Sdougb INSIST(server->session_keyfile != NULL); 4134224092Sdougb INSIST(server->session_keyname != NULL); 4135224092Sdougb INSIST(server->sessionkey != NULL); 4136224092Sdougb 4137224092Sdougb cleanup_session_key(server, mctx); 4138224092Sdougb } 4139224092Sdougb 4140224092Sdougb if (need_createnew) { 4141224092Sdougb INSIST(server->sessionkey == NULL); 4142224092Sdougb INSIST(server->session_keyfile == NULL); 4143224092Sdougb INSIST(server->session_keyname == NULL); 4144224092Sdougb INSIST(server->session_keyalg == DST_ALG_UNKNOWN); 4145224092Sdougb INSIST(server->session_keybits == 0); 4146224092Sdougb 4147224092Sdougb server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t)); 4148224092Sdougb if (server->session_keyname == NULL) 4149224092Sdougb goto cleanup; 4150224092Sdougb dns_name_init(server->session_keyname, NULL); 4151224092Sdougb CHECK(dns_name_dup(keyname, mctx, server->session_keyname)); 4152224092Sdougb 4153224092Sdougb server->session_keyfile = isc_mem_strdup(mctx, keyfile); 4154224092Sdougb if (server->session_keyfile == NULL) 4155224092Sdougb goto cleanup; 4156224092Sdougb 4157224092Sdougb server->session_keyalg = algtype; 4158224092Sdougb server->session_keybits = bits; 4159224092Sdougb 4160224092Sdougb CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr, 4161224092Sdougb algname, algtype, bits, mctx, 4162224092Sdougb &server->sessionkey)); 4163224092Sdougb } 4164224092Sdougb 4165224092Sdougb return (result); 4166224092Sdougb 4167224092Sdougb cleanup: 4168224092Sdougb cleanup_session_key(server, mctx); 4169224092Sdougb return (result); 4170224092Sdougb} 4171224092Sdougb 4172224092Sdougbstatic isc_result_t 4173225361Sdougbsetup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 4174225361Sdougb cfg_parser_t *parser, cfg_aclconfctx_t *actx) 4175225361Sdougb{ 4176225361Sdougb isc_result_t result = ISC_R_SUCCESS; 4177225361Sdougb isc_boolean_t allow = ISC_FALSE; 4178225361Sdougb struct cfg_context *nzcfg = NULL; 4179225361Sdougb cfg_parser_t *nzparser = NULL; 4180225361Sdougb cfg_obj_t *nzconfig = NULL; 4181225361Sdougb const cfg_obj_t *maps[4]; 4182225361Sdougb const cfg_obj_t *options = NULL, *voptions = NULL; 4183225361Sdougb const cfg_obj_t *nz = NULL; 4184225361Sdougb int i = 0; 4185225361Sdougb 4186225361Sdougb REQUIRE (config != NULL); 4187225361Sdougb 4188225361Sdougb if (vconfig != NULL) 4189225361Sdougb voptions = cfg_tuple_get(vconfig, "options"); 4190225361Sdougb if (voptions != NULL) 4191225361Sdougb maps[i++] = voptions; 4192225361Sdougb result = cfg_map_get(config, "options", &options); 4193225361Sdougb if (result == ISC_R_SUCCESS) 4194225361Sdougb maps[i++] = options; 4195225361Sdougb maps[i++] = ns_g_defaults; 4196225361Sdougb maps[i] = NULL; 4197225361Sdougb 4198225361Sdougb result = ns_config_get(maps, "allow-new-zones", &nz); 4199225361Sdougb if (result == ISC_R_SUCCESS) 4200225361Sdougb allow = cfg_obj_asboolean(nz); 4201225361Sdougb 4202225361Sdougb if (!allow) { 4203225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4204225361Sdougb return (ISC_R_SUCCESS); 4205225361Sdougb } 4206225361Sdougb 4207225361Sdougb nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg)); 4208225361Sdougb if (nzcfg == NULL) { 4209225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4210225361Sdougb return (ISC_R_NOMEMORY); 4211225361Sdougb } 4212225361Sdougb 4213225361Sdougb dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy); 4214225361Sdougb 4215225361Sdougb memset(nzcfg, 0, sizeof(*nzcfg)); 4216225361Sdougb isc_mem_attach(view->mctx, &nzcfg->mctx); 4217225361Sdougb cfg_obj_attach(config, &nzcfg->config); 4218225361Sdougb cfg_parser_attach(parser, &nzcfg->parser); 4219225361Sdougb cfg_aclconfctx_attach(actx, &nzcfg->actx); 4220225361Sdougb 4221225361Sdougb /* 4222225361Sdougb * Attempt to create a parser and parse the newzones 4223225361Sdougb * file. If successful, preserve both; otherwise leave 4224225361Sdougb * them NULL. 4225225361Sdougb */ 4226225361Sdougb result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser); 4227225361Sdougb if (result == ISC_R_SUCCESS) 4228225361Sdougb result = cfg_parse_file(nzparser, view->new_zone_file, 4229225361Sdougb &cfg_type_newzones, &nzconfig); 4230225361Sdougb if (result == ISC_R_SUCCESS) { 4231225361Sdougb cfg_parser_attach(nzparser, &nzcfg->nzparser); 4232225361Sdougb cfg_obj_attach(nzconfig, &nzcfg->nzconfig); 4233225361Sdougb } 4234225361Sdougb 4235225361Sdougb if (nzparser != NULL) { 4236225361Sdougb if (nzconfig != NULL) 4237225361Sdougb cfg_obj_destroy(nzparser, &nzconfig); 4238225361Sdougb cfg_parser_destroy(&nzparser); 4239225361Sdougb } 4240225361Sdougb 4241225361Sdougb return (ISC_R_SUCCESS); 4242225361Sdougb} 4243225361Sdougb 4244225361Sdougbstatic int 4245225361Sdougbcount_zones(const cfg_obj_t *conf) { 4246225361Sdougb const cfg_obj_t *zonelist = NULL; 4247225361Sdougb const cfg_listelt_t *element; 4248225361Sdougb int n = 0; 4249225361Sdougb 4250225361Sdougb REQUIRE(conf != NULL); 4251225361Sdougb 4252225361Sdougb cfg_map_get(conf, "zone", &zonelist); 4253225361Sdougb for (element = cfg_list_first(zonelist); 4254225361Sdougb element != NULL; 4255225361Sdougb element = cfg_list_next(element)) 4256225361Sdougb n++; 4257225361Sdougb 4258225361Sdougb return (n); 4259225361Sdougb} 4260225361Sdougb 4261225361Sdougbstatic isc_result_t 4262135446Strhodesload_configuration(const char *filename, ns_server_t *server, 4263135446Strhodes isc_boolean_t first_time) 4264135446Strhodes{ 4265224092Sdougb cfg_obj_t *config = NULL, *bindkeys = NULL; 4266224092Sdougb cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL; 4267182645Sdougb const cfg_listelt_t *element; 4268182645Sdougb const cfg_obj_t *builtin_views; 4269182645Sdougb const cfg_obj_t *maps[3]; 4270182645Sdougb const cfg_obj_t *obj; 4271165071Sdougb const cfg_obj_t *options; 4272186462Sdougb const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports; 4273165071Sdougb const cfg_obj_t *views; 4274135446Strhodes dns_view_t *view = NULL; 4275135446Strhodes dns_view_t *view_next; 4276182645Sdougb dns_viewlist_t tmpviewlist; 4277224092Sdougb dns_viewlist_t viewlist, builtin_viewlist; 4278186462Sdougb in_port_t listen_port, udpport_low, udpport_high; 4279182645Sdougb int i; 4280182645Sdougb isc_interval_t interval; 4281186462Sdougb isc_portset_t *v4portset = NULL; 4282186462Sdougb isc_portset_t *v6portset = NULL; 4283186462Sdougb isc_resourcevalue_t nfiles; 4284182645Sdougb isc_result_t result; 4285182645Sdougb isc_uint32_t heartbeat_interval; 4286135446Strhodes isc_uint32_t interface_interval; 4287182645Sdougb isc_uint32_t reserved; 4288135446Strhodes isc_uint32_t udpsize; 4289224092Sdougb ns_cachelist_t cachelist, tmpcachelist; 4290186462Sdougb unsigned int maxsocks; 4291224092Sdougb ns_cache_t *nsc; 4292225361Sdougb struct cfg_context *nzctx; 4293225361Sdougb int num_zones = 0; 4294234010Sdougb isc_boolean_t exclusive = ISC_FALSE; 4295135446Strhodes 4296135446Strhodes ISC_LIST_INIT(viewlist); 4297224092Sdougb ISC_LIST_INIT(builtin_viewlist); 4298224092Sdougb ISC_LIST_INIT(cachelist); 4299135446Strhodes 4300225361Sdougb /* Create the ACL configuration context */ 4301225361Sdougb if (ns_g_aclconfctx != NULL) 4302225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 4303225361Sdougb CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx)); 4304225361Sdougb 4305135446Strhodes /* 4306135446Strhodes * Parse the global default pseudo-config file. 4307135446Strhodes */ 4308135446Strhodes if (first_time) { 4309135446Strhodes CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 4310135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 4311224092Sdougb &ns_g_defaults) == ISC_R_SUCCESS); 4312135446Strhodes } 4313135446Strhodes 4314135446Strhodes /* 4315135446Strhodes * Parse the configuration file using the new config code. 4316135446Strhodes */ 4317135446Strhodes result = ISC_R_FAILURE; 4318135446Strhodes config = NULL; 4319135446Strhodes 4320135446Strhodes /* 4321135446Strhodes * Unless this is lwresd with the -C option, parse the config file. 4322135446Strhodes */ 4323135446Strhodes if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 4324135446Strhodes isc_log_write(ns_g_lctx, 4325135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4326135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4327135446Strhodes filename); 4328224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4329224092Sdougb cfg_parser_setcallback(conf_parser, directory_callback, NULL); 4330224092Sdougb result = cfg_parse_file(conf_parser, filename, 4331224092Sdougb &cfg_type_namedconf, &config); 4332135446Strhodes } 4333135446Strhodes 4334135446Strhodes /* 4335135446Strhodes * If this is lwresd with the -C option, or lwresd with no -C or -c 4336135446Strhodes * option where the above parsing failed, parse resolv.conf. 4337135446Strhodes */ 4338135446Strhodes if (ns_g_lwresdonly && 4339135446Strhodes (lwresd_g_useresolvconf || 4340135446Strhodes (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 4341135446Strhodes { 4342135446Strhodes isc_log_write(ns_g_lctx, 4343135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4344135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4345135446Strhodes lwresd_g_resolvconffile); 4346224092Sdougb if (conf_parser != NULL) 4347224092Sdougb cfg_parser_destroy(&conf_parser); 4348224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4349224092Sdougb result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser, 4350135446Strhodes &config); 4351135446Strhodes } 4352135446Strhodes CHECK(result); 4353135446Strhodes 4354135446Strhodes /* 4355135446Strhodes * Check the validity of the configuration. 4356135446Strhodes */ 4357135446Strhodes CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 4358135446Strhodes 4359135446Strhodes /* 4360135446Strhodes * Fill in the maps array, used for resolving defaults. 4361135446Strhodes */ 4362135446Strhodes i = 0; 4363135446Strhodes options = NULL; 4364135446Strhodes result = cfg_map_get(config, "options", &options); 4365135446Strhodes if (result == ISC_R_SUCCESS) 4366135446Strhodes maps[i++] = options; 4367135446Strhodes maps[i++] = ns_g_defaults; 4368225361Sdougb maps[i] = NULL; 4369135446Strhodes 4370135446Strhodes /* 4371224092Sdougb * If bind.keys exists, load it. If "dnssec-lookaside auto" 4372224092Sdougb * is turned on, the keys found there will be used as default 4373224092Sdougb * trust anchors. 4374224092Sdougb */ 4375224092Sdougb obj = NULL; 4376224092Sdougb result = ns_config_get(maps, "bindkeys-file", &obj); 4377224092Sdougb INSIST(result == ISC_R_SUCCESS); 4378224092Sdougb CHECKM(setstring(server, &server->bindkeysfile, 4379224092Sdougb cfg_obj_asstring(obj)), "strdup"); 4380224092Sdougb 4381224092Sdougb if (access(server->bindkeysfile, R_OK) == 0) { 4382224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4383224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4384224092Sdougb "reading built-in trusted " 4385224092Sdougb "keys from file '%s'", server->bindkeysfile); 4386224092Sdougb 4387224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, 4388224092Sdougb &bindkeys_parser)); 4389224092Sdougb 4390224092Sdougb result = cfg_parse_file(bindkeys_parser, server->bindkeysfile, 4391224092Sdougb &cfg_type_bindkeys, &bindkeys); 4392224092Sdougb CHECK(result); 4393224092Sdougb } 4394224092Sdougb 4395234010Sdougb /* Ensure exclusive access to configuration data. */ 4396234010Sdougb if (!exclusive) { 4397234010Sdougb result = isc_task_beginexclusive(server->task); 4398234010Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 4399234010Sdougb exclusive = ISC_TRUE; 4400234010Sdougb } 4401234010Sdougb 4402224092Sdougb /* 4403135446Strhodes * Set process limits, which (usually) needs to be done as root. 4404135446Strhodes */ 4405135446Strhodes set_limits(maps); 4406135446Strhodes 4407135446Strhodes /* 4408186462Sdougb * Check if max number of open sockets that the system allows is 4409224092Sdougb * sufficiently large. Failing this condition is not necessarily fatal, 4410186462Sdougb * but may cause subsequent runtime failures for a busy recursive 4411186462Sdougb * server. 4412182645Sdougb */ 4413186462Sdougb result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks); 4414186462Sdougb if (result != ISC_R_SUCCESS) 4415186462Sdougb maxsocks = 0; 4416186462Sdougb result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles); 4417186462Sdougb if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) { 4418182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4419182645Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 4420186462Sdougb "max open files (%" ISC_PRINT_QUADFORMAT "u)" 4421186462Sdougb " is smaller than max sockets (%u)", 4422186462Sdougb nfiles, maxsocks); 4423186462Sdougb } 4424182645Sdougb 4425182645Sdougb /* 4426182645Sdougb * Set the number of socket reserved for TCP, stdio etc. 4427182645Sdougb */ 4428182645Sdougb obj = NULL; 4429182645Sdougb result = ns_config_get(maps, "reserved-sockets", &obj); 4430182645Sdougb INSIST(result == ISC_R_SUCCESS); 4431182645Sdougb reserved = cfg_obj_asuint32(obj); 4432186462Sdougb if (maxsocks != 0) { 4433186462Sdougb if (maxsocks < 128U) /* Prevent underflow. */ 4434186462Sdougb reserved = 0; 4435186462Sdougb else if (reserved > maxsocks - 128U) /* Minimum UDP space. */ 4436186462Sdougb reserved = maxsocks - 128; 4437186462Sdougb } 4438186462Sdougb /* Minimum TCP/stdio space. */ 4439186462Sdougb if (reserved < 128U) 4440182645Sdougb reserved = 128; 4441186462Sdougb if (reserved + 128U > maxsocks && maxsocks != 0) { 4442182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4443186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 4444182645Sdougb "less than 128 UDP sockets available after " 4445186462Sdougb "applying 'reserved-sockets' and 'maxsockets'"); 4446182645Sdougb } 4447182645Sdougb isc__socketmgr_setreserved(ns_g_socketmgr, reserved); 4448186462Sdougb 4449182645Sdougb /* 4450135446Strhodes * Configure various server options. 4451135446Strhodes */ 4452135446Strhodes configure_server_quota(maps, "transfers-out", &server->xfroutquota); 4453135446Strhodes configure_server_quota(maps, "tcp-clients", &server->tcpquota); 4454135446Strhodes configure_server_quota(maps, "recursive-clients", 4455135446Strhodes &server->recursionquota); 4456153816Sdougb if (server->recursionquota.max > 1000) 4457153816Sdougb isc_quota_soft(&server->recursionquota, 4458153816Sdougb server->recursionquota.max - 100); 4459153816Sdougb else 4460153816Sdougb isc_quota_soft(&server->recursionquota, 0); 4461135446Strhodes 4462225361Sdougb CHECK(configure_view_acl(NULL, config, "blackhole", NULL, 4463225361Sdougb ns_g_aclconfctx, ns_g_mctx, 4464225361Sdougb &server->blackholeacl)); 4465135446Strhodes if (server->blackholeacl != NULL) 4466135446Strhodes dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 4467135446Strhodes server->blackholeacl); 4468135446Strhodes 4469135446Strhodes obj = NULL; 4470135446Strhodes result = ns_config_get(maps, "match-mapped-addresses", &obj); 4471135446Strhodes INSIST(result == ISC_R_SUCCESS); 4472135446Strhodes server->aclenv.match_mapped = cfg_obj_asboolean(obj); 4473135446Strhodes 4474225361Sdougb CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx), 4475193149Sdougb "configuring statistics server(s)"); 4476193149Sdougb 4477186462Sdougb /* 4478186462Sdougb * Configure sets of UDP query source ports. 4479186462Sdougb */ 4480186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v4portset), 4481186462Sdougb "creating UDP port set"); 4482186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v6portset), 4483186462Sdougb "creating UDP port set"); 4484135446Strhodes 4485186462Sdougb usev4ports = NULL; 4486186462Sdougb usev6ports = NULL; 4487186462Sdougb avoidv4ports = NULL; 4488186462Sdougb avoidv6ports = NULL; 4489186462Sdougb 4490186462Sdougb (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports); 4491186462Sdougb if (usev4ports != NULL) 4492186462Sdougb portset_fromconf(v4portset, usev4ports, ISC_TRUE); 4493186462Sdougb else { 4494186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low, 4495186462Sdougb &udpport_high), 4496186462Sdougb "get the default UDP/IPv4 port range"); 4497186462Sdougb if (udpport_low == udpport_high) 4498186462Sdougb isc_portset_add(v4portset, udpport_low); 4499186462Sdougb else { 4500186462Sdougb isc_portset_addrange(v4portset, udpport_low, 4501186462Sdougb udpport_high); 4502186462Sdougb } 4503186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4504186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4505186462Sdougb "using default UDP/IPv4 port range: [%d, %d]", 4506186462Sdougb udpport_low, udpport_high); 4507186462Sdougb } 4508186462Sdougb (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports); 4509186462Sdougb if (avoidv4ports != NULL) 4510186462Sdougb portset_fromconf(v4portset, avoidv4ports, ISC_FALSE); 4511186462Sdougb 4512186462Sdougb (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports); 4513186462Sdougb if (usev6ports != NULL) 4514186462Sdougb portset_fromconf(v6portset, usev6ports, ISC_TRUE); 4515186462Sdougb else { 4516186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low, 4517186462Sdougb &udpport_high), 4518186462Sdougb "get the default UDP/IPv6 port range"); 4519186462Sdougb if (udpport_low == udpport_high) 4520186462Sdougb isc_portset_add(v6portset, udpport_low); 4521186462Sdougb else { 4522186462Sdougb isc_portset_addrange(v6portset, udpport_low, 4523186462Sdougb udpport_high); 4524186462Sdougb } 4525186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4526186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4527186462Sdougb "using default UDP/IPv6 port range: [%d, %d]", 4528186462Sdougb udpport_low, udpport_high); 4529186462Sdougb } 4530186462Sdougb (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports); 4531186462Sdougb if (avoidv6ports != NULL) 4532186462Sdougb portset_fromconf(v6portset, avoidv6ports, ISC_FALSE); 4533186462Sdougb 4534186462Sdougb dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset); 4535186462Sdougb 4536135446Strhodes /* 4537135446Strhodes * Set the EDNS UDP size when we don't match a view. 4538135446Strhodes */ 4539135446Strhodes obj = NULL; 4540135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 4541135446Strhodes INSIST(result == ISC_R_SUCCESS); 4542135446Strhodes udpsize = cfg_obj_asuint32(obj); 4543135446Strhodes if (udpsize < 512) 4544135446Strhodes udpsize = 512; 4545135446Strhodes if (udpsize > 4096) 4546135446Strhodes udpsize = 4096; 4547135446Strhodes ns_g_udpsize = (isc_uint16_t)udpsize; 4548135446Strhodes 4549135446Strhodes /* 4550135446Strhodes * Configure the zone manager. 4551135446Strhodes */ 4552135446Strhodes obj = NULL; 4553135446Strhodes result = ns_config_get(maps, "transfers-in", &obj); 4554135446Strhodes INSIST(result == ISC_R_SUCCESS); 4555135446Strhodes dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 4556135446Strhodes 4557135446Strhodes obj = NULL; 4558135446Strhodes result = ns_config_get(maps, "transfers-per-ns", &obj); 4559135446Strhodes INSIST(result == ISC_R_SUCCESS); 4560135446Strhodes dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 4561135446Strhodes 4562135446Strhodes obj = NULL; 4563135446Strhodes result = ns_config_get(maps, "serial-query-rate", &obj); 4564135446Strhodes INSIST(result == ISC_R_SUCCESS); 4565135446Strhodes dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 4566135446Strhodes 4567135446Strhodes /* 4568135446Strhodes * Determine which port to use for listening for incoming connections. 4569135446Strhodes */ 4570135446Strhodes if (ns_g_port != 0) 4571135446Strhodes listen_port = ns_g_port; 4572135446Strhodes else 4573135446Strhodes CHECKM(ns_config_getport(config, &listen_port), "port"); 4574135446Strhodes 4575135446Strhodes /* 4576135446Strhodes * Find the listen queue depth. 4577135446Strhodes */ 4578135446Strhodes obj = NULL; 4579135446Strhodes result = ns_config_get(maps, "tcp-listen-queue", &obj); 4580135446Strhodes INSIST(result == ISC_R_SUCCESS); 4581135446Strhodes ns_g_listen = cfg_obj_asuint32(obj); 4582135446Strhodes if (ns_g_listen < 3) 4583135446Strhodes ns_g_listen = 3; 4584135446Strhodes 4585135446Strhodes /* 4586135446Strhodes * Configure the interface manager according to the "listen-on" 4587135446Strhodes * statement. 4588135446Strhodes */ 4589135446Strhodes { 4590165071Sdougb const cfg_obj_t *clistenon = NULL; 4591135446Strhodes ns_listenlist_t *listenon = NULL; 4592135446Strhodes 4593135446Strhodes clistenon = NULL; 4594135446Strhodes /* 4595135446Strhodes * Even though listen-on is present in the default 4596135446Strhodes * configuration, we can't use it here, since it isn't 4597135446Strhodes * used if we're in lwresd mode. This way is easier. 4598135446Strhodes */ 4599135446Strhodes if (options != NULL) 4600135446Strhodes (void)cfg_map_get(options, "listen-on", &clistenon); 4601135446Strhodes if (clistenon != NULL) { 4602225361Sdougb /* check return code? */ 4603225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 4604225361Sdougb ns_g_aclconfctx, 4605225361Sdougb ns_g_mctx, &listenon); 4606135446Strhodes } else if (!ns_g_lwresdonly) { 4607135446Strhodes /* 4608135446Strhodes * Not specified, use default. 4609135446Strhodes */ 4610135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 4611135446Strhodes ISC_TRUE, &listenon)); 4612135446Strhodes } 4613135446Strhodes if (listenon != NULL) { 4614135446Strhodes ns_interfacemgr_setlistenon4(server->interfacemgr, 4615135446Strhodes listenon); 4616135446Strhodes ns_listenlist_detach(&listenon); 4617135446Strhodes } 4618135446Strhodes } 4619135446Strhodes /* 4620135446Strhodes * Ditto for IPv6. 4621135446Strhodes */ 4622135446Strhodes { 4623165071Sdougb const cfg_obj_t *clistenon = NULL; 4624135446Strhodes ns_listenlist_t *listenon = NULL; 4625135446Strhodes 4626135446Strhodes if (options != NULL) 4627135446Strhodes (void)cfg_map_get(options, "listen-on-v6", &clistenon); 4628135446Strhodes if (clistenon != NULL) { 4629225361Sdougb /* check return code? */ 4630225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 4631225361Sdougb ns_g_aclconfctx, 4632225361Sdougb ns_g_mctx, &listenon); 4633135446Strhodes } else if (!ns_g_lwresdonly) { 4634193149Sdougb isc_boolean_t enable; 4635135446Strhodes /* 4636135446Strhodes * Not specified, use default. 4637135446Strhodes */ 4638193149Sdougb enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS); 4639135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 4640193149Sdougb enable, &listenon)); 4641135446Strhodes } 4642135446Strhodes if (listenon != NULL) { 4643135446Strhodes ns_interfacemgr_setlistenon6(server->interfacemgr, 4644135446Strhodes listenon); 4645135446Strhodes ns_listenlist_detach(&listenon); 4646135446Strhodes } 4647135446Strhodes } 4648135446Strhodes 4649135446Strhodes /* 4650135446Strhodes * Rescan the interface list to pick up changes in the 4651135446Strhodes * listen-on option. It's important that we do this before we try 4652135446Strhodes * to configure the query source, since the dispatcher we use might 4653135446Strhodes * be shared with an interface. 4654135446Strhodes */ 4655135446Strhodes scan_interfaces(server, ISC_TRUE); 4656135446Strhodes 4657135446Strhodes /* 4658135446Strhodes * Arrange for further interface scanning to occur periodically 4659135446Strhodes * as specified by the "interface-interval" option. 4660135446Strhodes */ 4661135446Strhodes obj = NULL; 4662135446Strhodes result = ns_config_get(maps, "interface-interval", &obj); 4663135446Strhodes INSIST(result == ISC_R_SUCCESS); 4664135446Strhodes interface_interval = cfg_obj_asuint32(obj) * 60; 4665135446Strhodes if (interface_interval == 0) { 4666135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 4667135446Strhodes isc_timertype_inactive, 4668135446Strhodes NULL, NULL, ISC_TRUE)); 4669135446Strhodes } else if (server->interface_interval != interface_interval) { 4670135446Strhodes isc_interval_set(&interval, interface_interval, 0); 4671135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 4672135446Strhodes isc_timertype_ticker, 4673135446Strhodes NULL, &interval, ISC_FALSE)); 4674135446Strhodes } 4675135446Strhodes server->interface_interval = interface_interval; 4676135446Strhodes 4677135446Strhodes /* 4678135446Strhodes * Configure the dialup heartbeat timer. 4679135446Strhodes */ 4680135446Strhodes obj = NULL; 4681135446Strhodes result = ns_config_get(maps, "heartbeat-interval", &obj); 4682135446Strhodes INSIST(result == ISC_R_SUCCESS); 4683135446Strhodes heartbeat_interval = cfg_obj_asuint32(obj) * 60; 4684135446Strhodes if (heartbeat_interval == 0) { 4685135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 4686135446Strhodes isc_timertype_inactive, 4687135446Strhodes NULL, NULL, ISC_TRUE)); 4688135446Strhodes } else if (server->heartbeat_interval != heartbeat_interval) { 4689135446Strhodes isc_interval_set(&interval, heartbeat_interval, 0); 4690135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 4691135446Strhodes isc_timertype_ticker, 4692135446Strhodes NULL, &interval, ISC_FALSE)); 4693135446Strhodes } 4694135446Strhodes server->heartbeat_interval = heartbeat_interval; 4695186462Sdougb 4696170222Sdougb isc_interval_set(&interval, 1200, 0); 4697170222Sdougb CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, 4698170222Sdougb &interval, ISC_FALSE)); 4699135446Strhodes 4700135446Strhodes /* 4701224092Sdougb * Write the PID file. 4702224092Sdougb */ 4703224092Sdougb obj = NULL; 4704224092Sdougb if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 4705224092Sdougb if (cfg_obj_isvoid(obj)) 4706224092Sdougb ns_os_writepidfile(NULL, first_time); 4707224092Sdougb else 4708224092Sdougb ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 4709224092Sdougb else if (ns_g_lwresdonly) 4710224092Sdougb ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 4711224092Sdougb else 4712224092Sdougb ns_os_writepidfile(ns_g_defaultpidfile, first_time); 4713224092Sdougb 4714224092Sdougb /* 4715224092Sdougb * Configure the server-wide session key. This must be done before 4716224092Sdougb * configure views because zone configuration may need to know 4717224092Sdougb * session-keyname. 4718224092Sdougb * 4719224092Sdougb * Failure of session key generation isn't fatal at this time; if it 4720224092Sdougb * turns out that a session key is really needed but doesn't exist, 4721224092Sdougb * we'll treat it as a fatal error then. 4722224092Sdougb */ 4723224092Sdougb (void)configure_session_key(maps, server, ns_g_mctx); 4724224092Sdougb 4725225361Sdougb views = NULL; 4726225361Sdougb (void)cfg_map_get(config, "view", &views); 4727225361Sdougb 4728224092Sdougb /* 4729225361Sdougb * Create the views and count all the configured zones in 4730225361Sdougb * order to correctly size the zone manager's task table. 4731225361Sdougb * (We only count zones for configured views; the built-in 4732225361Sdougb * "bind" view can be ignored as it only adds a negligible 4733225361Sdougb * number of zones.) 4734225361Sdougb * 4735225361Sdougb * If we're allowing new zones, we need to be able to find the 4736225361Sdougb * new zone file and count those as well. So we setup the new 4737225361Sdougb * zone configuration context, but otherwise view configuration 4738225361Sdougb * waits until after the zone manager's task list has been sized. 4739225361Sdougb */ 4740225361Sdougb for (element = cfg_list_first(views); 4741225361Sdougb element != NULL; 4742225361Sdougb element = cfg_list_next(element)) 4743225361Sdougb { 4744225361Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4745225361Sdougb const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options"); 4746225361Sdougb view = NULL; 4747225361Sdougb 4748225361Sdougb CHECK(create_view(vconfig, &viewlist, &view)); 4749225361Sdougb INSIST(view != NULL); 4750225361Sdougb 4751225361Sdougb num_zones += count_zones(voptions); 4752225361Sdougb CHECK(setup_newzones(view, config, vconfig, conf_parser, 4753225361Sdougb ns_g_aclconfctx)); 4754225361Sdougb 4755225361Sdougb nzctx = view->new_zone_config; 4756225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 4757225361Sdougb num_zones += count_zones(nzctx->nzconfig); 4758225361Sdougb 4759225361Sdougb dns_view_detach(&view); 4760225361Sdougb } 4761225361Sdougb 4762225361Sdougb /* 4763225361Sdougb * If there were no explicit views then we do the default 4764225361Sdougb * view here. 4765225361Sdougb */ 4766225361Sdougb if (views == NULL) { 4767225361Sdougb CHECK(create_view(NULL, &viewlist, &view)); 4768225361Sdougb INSIST(view != NULL); 4769225361Sdougb 4770225361Sdougb num_zones = count_zones(config); 4771225361Sdougb 4772225361Sdougb CHECK(setup_newzones(view, config, NULL, conf_parser, 4773225361Sdougb ns_g_aclconfctx)); 4774225361Sdougb 4775225361Sdougb nzctx = view->new_zone_config; 4776225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 4777225361Sdougb num_zones += count_zones(nzctx->nzconfig); 4778225361Sdougb 4779225361Sdougb dns_view_detach(&view); 4780225361Sdougb } 4781225361Sdougb 4782225361Sdougb /* 4783225361Sdougb * Zones have been counted; set the zone manager task pool size. 4784225361Sdougb */ 4785225361Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4786225361Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4787225361Sdougb "sizing zone task pool based on %d zones", num_zones); 4788225361Sdougb CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones)); 4789225361Sdougb 4790225361Sdougb /* 4791135446Strhodes * Configure and freeze all explicit views. Explicit 4792135446Strhodes * views that have zones were already created at parsing 4793135446Strhodes * time, but views with no zones must be created here. 4794135446Strhodes */ 4795135446Strhodes for (element = cfg_list_first(views); 4796135446Strhodes element != NULL; 4797135446Strhodes element = cfg_list_next(element)) 4798135446Strhodes { 4799224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4800225361Sdougb 4801135446Strhodes view = NULL; 4802225361Sdougb CHECK(find_view(vconfig, &viewlist, &view)); 4803225361Sdougb CHECK(configure_view(view, config, vconfig, 4804225361Sdougb &cachelist, bindkeys, ns_g_mctx, 4805225361Sdougb ns_g_aclconfctx, ISC_TRUE)); 4806135446Strhodes dns_view_freeze(view); 4807135446Strhodes dns_view_detach(&view); 4808135446Strhodes } 4809135446Strhodes 4810135446Strhodes /* 4811135446Strhodes * Make sure we have a default view if and only if there 4812135446Strhodes * were no explicit views. 4813135446Strhodes */ 4814135446Strhodes if (views == NULL) { 4815225361Sdougb view = NULL; 4816225361Sdougb CHECK(find_view(NULL, &viewlist, &view)); 4817225361Sdougb CHECK(configure_view(view, config, NULL, 4818224092Sdougb &cachelist, bindkeys, 4819225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_TRUE)); 4820135446Strhodes dns_view_freeze(view); 4821135446Strhodes dns_view_detach(&view); 4822135446Strhodes } 4823135446Strhodes 4824135446Strhodes /* 4825224092Sdougb * Create (or recreate) the built-in views. 4826135446Strhodes */ 4827135446Strhodes builtin_views = NULL; 4828135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 4829135446Strhodes &builtin_views) == ISC_R_SUCCESS); 4830135446Strhodes for (element = cfg_list_first(builtin_views); 4831135446Strhodes element != NULL; 4832135446Strhodes element = cfg_list_next(element)) 4833135446Strhodes { 4834224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4835224092Sdougb 4836224092Sdougb CHECK(create_view(vconfig, &builtin_viewlist, &view)); 4837225361Sdougb CHECK(configure_view(view, config, vconfig, 4838224092Sdougb &cachelist, bindkeys, 4839225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_FALSE)); 4840135446Strhodes dns_view_freeze(view); 4841135446Strhodes dns_view_detach(&view); 4842135446Strhodes view = NULL; 4843135446Strhodes } 4844135446Strhodes 4845224092Sdougb /* Now combine the two viewlists into one */ 4846224092Sdougb ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); 4847224092Sdougb 4848224092Sdougb /* Swap our new view list with the production one. */ 4849135446Strhodes tmpviewlist = server->viewlist; 4850135446Strhodes server->viewlist = viewlist; 4851135446Strhodes viewlist = tmpviewlist; 4852135446Strhodes 4853224092Sdougb /* Make the view list available to each of the views */ 4854224092Sdougb view = ISC_LIST_HEAD(server->viewlist); 4855224092Sdougb while (view != NULL) { 4856224092Sdougb view->viewlist = &server->viewlist; 4857224092Sdougb view = ISC_LIST_NEXT(view, link); 4858224092Sdougb } 4859224092Sdougb 4860224092Sdougb /* Swap our new cache list with the production one. */ 4861224092Sdougb tmpcachelist = server->cachelist; 4862224092Sdougb server->cachelist = cachelist; 4863224092Sdougb cachelist = tmpcachelist; 4864224092Sdougb 4865224092Sdougb /* Load the TKEY information from the configuration. */ 4866135446Strhodes if (options != NULL) { 4867135446Strhodes dns_tkeyctx_t *t = NULL; 4868135446Strhodes CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 4869135446Strhodes &t), 4870135446Strhodes "configuring TKEY"); 4871135446Strhodes if (server->tkeyctx != NULL) 4872135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 4873135446Strhodes server->tkeyctx = t; 4874135446Strhodes } 4875135446Strhodes 4876135446Strhodes /* 4877135446Strhodes * Bind the control port(s). 4878135446Strhodes */ 4879135446Strhodes CHECKM(ns_controls_configure(ns_g_server->controls, config, 4880225361Sdougb ns_g_aclconfctx), 4881135446Strhodes "binding control channel(s)"); 4882135446Strhodes 4883135446Strhodes /* 4884135446Strhodes * Bind the lwresd port(s). 4885135446Strhodes */ 4886135446Strhodes CHECKM(ns_lwresd_configure(ns_g_mctx, config), 4887135446Strhodes "binding lightweight resolver ports"); 4888135446Strhodes 4889135446Strhodes /* 4890135446Strhodes * Open the source of entropy. 4891135446Strhodes */ 4892135446Strhodes if (first_time) { 4893135446Strhodes obj = NULL; 4894135446Strhodes result = ns_config_get(maps, "random-device", &obj); 4895135446Strhodes if (result != ISC_R_SUCCESS) { 4896135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4897135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4898135446Strhodes "no source of entropy found"); 4899135446Strhodes } else { 4900135446Strhodes const char *randomdev = cfg_obj_asstring(obj); 4901135446Strhodes result = isc_entropy_createfilesource(ns_g_entropy, 4902135446Strhodes randomdev); 4903135446Strhodes if (result != ISC_R_SUCCESS) 4904135446Strhodes isc_log_write(ns_g_lctx, 4905135446Strhodes NS_LOGCATEGORY_GENERAL, 4906135446Strhodes NS_LOGMODULE_SERVER, 4907135446Strhodes ISC_LOG_INFO, 4908135446Strhodes "could not open entropy source " 4909135446Strhodes "%s: %s", 4910135446Strhodes randomdev, 4911135446Strhodes isc_result_totext(result)); 4912135446Strhodes#ifdef PATH_RANDOMDEV 4913135446Strhodes if (ns_g_fallbackentropy != NULL) { 4914135446Strhodes if (result != ISC_R_SUCCESS) { 4915135446Strhodes isc_log_write(ns_g_lctx, 4916135446Strhodes NS_LOGCATEGORY_GENERAL, 4917135446Strhodes NS_LOGMODULE_SERVER, 4918135446Strhodes ISC_LOG_INFO, 4919135446Strhodes "using pre-chroot entropy source " 4920135446Strhodes "%s", 4921135446Strhodes PATH_RANDOMDEV); 4922135446Strhodes isc_entropy_detach(&ns_g_entropy); 4923135446Strhodes isc_entropy_attach(ns_g_fallbackentropy, 4924135446Strhodes &ns_g_entropy); 4925135446Strhodes } 4926135446Strhodes isc_entropy_detach(&ns_g_fallbackentropy); 4927135446Strhodes } 4928135446Strhodes#endif 4929135446Strhodes } 4930135446Strhodes } 4931135446Strhodes 4932135446Strhodes /* 4933135446Strhodes * Relinquish root privileges. 4934135446Strhodes */ 4935135446Strhodes if (first_time) 4936135446Strhodes ns_os_changeuser(); 4937135446Strhodes 4938135446Strhodes /* 4939186462Sdougb * Check that the working directory is writable. 4940186462Sdougb */ 4941186462Sdougb if (access(".", W_OK) != 0) { 4942186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4943186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4944186462Sdougb "the working directory is not writable"); 4945186462Sdougb } 4946186462Sdougb 4947186462Sdougb /* 4948135446Strhodes * Configure the logging system. 4949135446Strhodes * 4950135446Strhodes * Do this after changing UID to make sure that any log 4951135446Strhodes * files specified in named.conf get created by the 4952135446Strhodes * unprivileged user, not root. 4953135446Strhodes */ 4954135446Strhodes if (ns_g_logstderr) { 4955135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4956135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4957135446Strhodes "ignoring config file logging " 4958135446Strhodes "statement due to -g option"); 4959135446Strhodes } else { 4960165071Sdougb const cfg_obj_t *logobj = NULL; 4961135446Strhodes isc_logconfig_t *logc = NULL; 4962135446Strhodes 4963135446Strhodes CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 4964135446Strhodes "creating new logging configuration"); 4965135446Strhodes 4966135446Strhodes logobj = NULL; 4967135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 4968135446Strhodes if (logobj != NULL) { 4969135446Strhodes CHECKM(ns_log_configure(logc, logobj), 4970135446Strhodes "configuring logging"); 4971135446Strhodes } else { 4972135446Strhodes CHECKM(ns_log_setdefaultchannels(logc), 4973135446Strhodes "setting up default logging channels"); 4974135446Strhodes CHECKM(ns_log_setunmatchedcategory(logc), 4975135446Strhodes "setting up default 'category unmatched'"); 4976135446Strhodes CHECKM(ns_log_setdefaultcategory(logc), 4977135446Strhodes "setting up default 'category default'"); 4978135446Strhodes } 4979135446Strhodes 4980135446Strhodes result = isc_logconfig_use(ns_g_lctx, logc); 4981135446Strhodes if (result != ISC_R_SUCCESS) { 4982135446Strhodes isc_logconfig_destroy(&logc); 4983135446Strhodes CHECKM(result, "installing logging configuration"); 4984135446Strhodes } 4985135446Strhodes 4986135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4987135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 4988135446Strhodes "now using logging configuration from " 4989135446Strhodes "config file"); 4990135446Strhodes } 4991135446Strhodes 4992135446Strhodes /* 4993135446Strhodes * Set the default value of the query logging flag depending 4994135446Strhodes * whether a "queries" category has been defined. This is 4995135446Strhodes * a disgusting hack, but we need to do this for BIND 8 4996135446Strhodes * compatibility. 4997135446Strhodes */ 4998135446Strhodes if (first_time) { 4999165071Sdougb const cfg_obj_t *logobj = NULL; 5000165071Sdougb const cfg_obj_t *categories = NULL; 5001135446Strhodes 5002135446Strhodes obj = NULL; 5003135446Strhodes if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 5004135446Strhodes server->log_queries = cfg_obj_asboolean(obj); 5005135446Strhodes } else { 5006135446Strhodes 5007135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 5008135446Strhodes if (logobj != NULL) 5009135446Strhodes (void)cfg_map_get(logobj, "category", 5010135446Strhodes &categories); 5011135446Strhodes if (categories != NULL) { 5012165071Sdougb const cfg_listelt_t *element; 5013135446Strhodes for (element = cfg_list_first(categories); 5014135446Strhodes element != NULL; 5015135446Strhodes element = cfg_list_next(element)) 5016135446Strhodes { 5017165071Sdougb const cfg_obj_t *catobj; 5018165071Sdougb const char *str; 5019135446Strhodes 5020135446Strhodes obj = cfg_listelt_value(element); 5021135446Strhodes catobj = cfg_tuple_get(obj, "name"); 5022135446Strhodes str = cfg_obj_asstring(catobj); 5023135446Strhodes if (strcasecmp(str, "queries") == 0) 5024135446Strhodes server->log_queries = ISC_TRUE; 5025135446Strhodes } 5026135446Strhodes } 5027135446Strhodes } 5028135446Strhodes } 5029135446Strhodes 5030186462Sdougb 5031135446Strhodes obj = NULL; 5032135446Strhodes if (options != NULL && 5033193149Sdougb cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) 5034193149Sdougb ns_g_memstatistics = cfg_obj_asboolean(obj); 5035193149Sdougb else 5036193149Sdougb ns_g_memstatistics = 5037193149Sdougb ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); 5038193149Sdougb 5039193149Sdougb obj = NULL; 5040193149Sdougb if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) 5041135446Strhodes ns_main_setmemstats(cfg_obj_asstring(obj)); 5042193149Sdougb else if (ns_g_memstatistics) 5043193149Sdougb ns_main_setmemstats("named.memstats"); 5044135446Strhodes else 5045135446Strhodes ns_main_setmemstats(NULL); 5046135446Strhodes 5047135446Strhodes obj = NULL; 5048135446Strhodes result = ns_config_get(maps, "statistics-file", &obj); 5049135446Strhodes INSIST(result == ISC_R_SUCCESS); 5050135446Strhodes CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 5051135446Strhodes "strdup"); 5052135446Strhodes 5053135446Strhodes obj = NULL; 5054135446Strhodes result = ns_config_get(maps, "dump-file", &obj); 5055135446Strhodes INSIST(result == ISC_R_SUCCESS); 5056135446Strhodes CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 5057135446Strhodes "strdup"); 5058135446Strhodes 5059135446Strhodes obj = NULL; 5060224092Sdougb result = ns_config_get(maps, "secroots-file", &obj); 5061224092Sdougb INSIST(result == ISC_R_SUCCESS); 5062224092Sdougb CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)), 5063224092Sdougb "strdup"); 5064224092Sdougb 5065224092Sdougb obj = NULL; 5066135446Strhodes result = ns_config_get(maps, "recursing-file", &obj); 5067135446Strhodes INSIST(result == ISC_R_SUCCESS); 5068135446Strhodes CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 5069135446Strhodes "strdup"); 5070135446Strhodes 5071135446Strhodes obj = NULL; 5072135446Strhodes result = ns_config_get(maps, "version", &obj); 5073135446Strhodes if (result == ISC_R_SUCCESS) { 5074135446Strhodes CHECKM(setoptstring(server, &server->version, obj), "strdup"); 5075135446Strhodes server->version_set = ISC_TRUE; 5076135446Strhodes } else { 5077135446Strhodes server->version_set = ISC_FALSE; 5078135446Strhodes } 5079135446Strhodes 5080135446Strhodes obj = NULL; 5081135446Strhodes result = ns_config_get(maps, "hostname", &obj); 5082135446Strhodes if (result == ISC_R_SUCCESS) { 5083135446Strhodes CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 5084135446Strhodes server->hostname_set = ISC_TRUE; 5085135446Strhodes } else { 5086135446Strhodes server->hostname_set = ISC_FALSE; 5087135446Strhodes } 5088135446Strhodes 5089135446Strhodes obj = NULL; 5090135446Strhodes result = ns_config_get(maps, "server-id", &obj); 5091135446Strhodes server->server_usehostname = ISC_FALSE; 5092135446Strhodes if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 5093193149Sdougb /* The parser translates "hostname" to ISC_TRUE */ 5094193149Sdougb server->server_usehostname = cfg_obj_asboolean(obj); 5095193149Sdougb result = setstring(server, &server->server_id, NULL); 5096193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 5097135446Strhodes } else if (result == ISC_R_SUCCESS) { 5098193149Sdougb /* Found a quoted string */ 5099135446Strhodes CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 5100135446Strhodes } else { 5101170222Sdougb result = setstring(server, &server->server_id, NULL); 5102135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5103135446Strhodes } 5104135446Strhodes 5105135446Strhodes obj = NULL; 5106135446Strhodes result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 5107135446Strhodes if (result == ISC_R_SUCCESS) { 5108135446Strhodes server->flushonshutdown = cfg_obj_asboolean(obj); 5109135446Strhodes } else { 5110135446Strhodes server->flushonshutdown = ISC_FALSE; 5111135446Strhodes } 5112135446Strhodes 5113135446Strhodes result = ISC_R_SUCCESS; 5114135446Strhodes 5115135446Strhodes cleanup: 5116186462Sdougb if (v4portset != NULL) 5117186462Sdougb isc_portset_destroy(ns_g_mctx, &v4portset); 5118186462Sdougb 5119186462Sdougb if (v6portset != NULL) 5120186462Sdougb isc_portset_destroy(ns_g_mctx, &v6portset); 5121186462Sdougb 5122224092Sdougb if (conf_parser != NULL) { 5123135446Strhodes if (config != NULL) 5124224092Sdougb cfg_obj_destroy(conf_parser, &config); 5125224092Sdougb cfg_parser_destroy(&conf_parser); 5126135446Strhodes } 5127135446Strhodes 5128224092Sdougb if (bindkeys_parser != NULL) { 5129224092Sdougb if (bindkeys != NULL) 5130224092Sdougb cfg_obj_destroy(bindkeys_parser, &bindkeys); 5131224092Sdougb cfg_parser_destroy(&bindkeys_parser); 5132224092Sdougb } 5133224092Sdougb 5134135446Strhodes if (view != NULL) 5135135446Strhodes dns_view_detach(&view); 5136135446Strhodes 5137135446Strhodes /* 5138135446Strhodes * This cleans up either the old production view list 5139135446Strhodes * or our temporary list depending on whether they 5140135446Strhodes * were swapped above or not. 5141135446Strhodes */ 5142135446Strhodes for (view = ISC_LIST_HEAD(viewlist); 5143135446Strhodes view != NULL; 5144135446Strhodes view = view_next) { 5145135446Strhodes view_next = ISC_LIST_NEXT(view, link); 5146135446Strhodes ISC_LIST_UNLINK(viewlist, view, link); 5147170222Sdougb if (result == ISC_R_SUCCESS && 5148170222Sdougb strcmp(view->name, "_bind") != 0) 5149170222Sdougb (void)dns_zt_apply(view->zonetable, ISC_FALSE, 5150170222Sdougb removed, view); 5151135446Strhodes dns_view_detach(&view); 5152135446Strhodes } 5153135446Strhodes 5154224092Sdougb /* Same cleanup for cache list. */ 5155224092Sdougb while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) { 5156224092Sdougb ISC_LIST_UNLINK(cachelist, nsc, link); 5157224092Sdougb dns_cache_detach(&nsc->cache); 5158224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 5159224092Sdougb } 5160224092Sdougb 5161135446Strhodes /* 5162135446Strhodes * Adjust the listening interfaces in accordance with the source 5163135446Strhodes * addresses specified in views and zones. 5164135446Strhodes */ 5165135446Strhodes if (isc_net_probeipv6() == ISC_R_SUCCESS) 5166135446Strhodes adjust_interfaces(server, ns_g_mctx); 5167135446Strhodes 5168135446Strhodes /* Relinquish exclusive access to configuration data. */ 5169234010Sdougb if (exclusive) 5170234010Sdougb isc_task_endexclusive(server->task); 5171135446Strhodes 5172135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5173135446Strhodes ISC_LOG_DEBUG(1), "load_configuration: %s", 5174135446Strhodes isc_result_totext(result)); 5175135446Strhodes 5176135446Strhodes return (result); 5177135446Strhodes} 5178135446Strhodes 5179135446Strhodesstatic isc_result_t 5180135446Strhodesload_zones(ns_server_t *server, isc_boolean_t stop) { 5181135446Strhodes isc_result_t result; 5182135446Strhodes dns_view_t *view; 5183135446Strhodes 5184135446Strhodes result = isc_task_beginexclusive(server->task); 5185135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5186135446Strhodes 5187135446Strhodes /* 5188135446Strhodes * Load zone data from disk. 5189135446Strhodes */ 5190135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5191135446Strhodes view != NULL; 5192135446Strhodes view = ISC_LIST_NEXT(view, link)) 5193135446Strhodes { 5194135446Strhodes CHECK(dns_view_load(view, stop)); 5195224092Sdougb if (view->managed_keys != NULL) 5196224092Sdougb CHECK(dns_zone_load(view->managed_keys)); 5197135446Strhodes } 5198135446Strhodes 5199135446Strhodes /* 5200135446Strhodes * Force zone maintenance. Do this after loading 5201135446Strhodes * so that we know when we need to force AXFR of 5202135446Strhodes * slave zones whose master files are missing. 5203135446Strhodes */ 5204135446Strhodes CHECK(dns_zonemgr_forcemaint(server->zonemgr)); 5205135446Strhodes cleanup: 5206186462Sdougb isc_task_endexclusive(server->task); 5207135446Strhodes return (result); 5208135446Strhodes} 5209135446Strhodes 5210135446Strhodesstatic isc_result_t 5211135446Strhodesload_new_zones(ns_server_t *server, isc_boolean_t stop) { 5212135446Strhodes isc_result_t result; 5213135446Strhodes dns_view_t *view; 5214135446Strhodes 5215135446Strhodes result = isc_task_beginexclusive(server->task); 5216135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5217135446Strhodes 5218135446Strhodes /* 5219135446Strhodes * Load zone data from disk. 5220135446Strhodes */ 5221135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5222135446Strhodes view != NULL; 5223135446Strhodes view = ISC_LIST_NEXT(view, link)) 5224135446Strhodes { 5225135446Strhodes CHECK(dns_view_loadnew(view, stop)); 5226224092Sdougb 5227224092Sdougb /* Load managed-keys data */ 5228224092Sdougb if (view->managed_keys != NULL) 5229224092Sdougb CHECK(dns_zone_loadnew(view->managed_keys)); 5230135446Strhodes } 5231224092Sdougb 5232135446Strhodes /* 5233224092Sdougb * Resume zone XFRs. 5234135446Strhodes */ 5235135446Strhodes dns_zonemgr_resumexfrs(server->zonemgr); 5236135446Strhodes cleanup: 5237186462Sdougb isc_task_endexclusive(server->task); 5238135446Strhodes return (result); 5239135446Strhodes} 5240135446Strhodes 5241135446Strhodesstatic void 5242135446Strhodesrun_server(isc_task_t *task, isc_event_t *event) { 5243135446Strhodes isc_result_t result; 5244135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5245135446Strhodes 5246143731Sdougb INSIST(task == server->task); 5247135446Strhodes 5248135446Strhodes isc_event_free(&event); 5249135446Strhodes 5250135446Strhodes CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 5251135446Strhodes &ns_g_dispatchmgr), 5252135446Strhodes "creating dispatch manager"); 5253135446Strhodes 5254193149Sdougb dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); 5255193149Sdougb 5256135446Strhodes CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 5257135446Strhodes ns_g_socketmgr, ns_g_dispatchmgr, 5258135446Strhodes &server->interfacemgr), 5259135446Strhodes "creating interface manager"); 5260135446Strhodes 5261135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5262135446Strhodes NULL, NULL, server->task, 5263135446Strhodes interface_timer_tick, 5264135446Strhodes server, &server->interface_timer), 5265135446Strhodes "creating interface timer"); 5266135446Strhodes 5267135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5268135446Strhodes NULL, NULL, server->task, 5269135446Strhodes heartbeat_timer_tick, 5270135446Strhodes server, &server->heartbeat_timer), 5271135446Strhodes "creating heartbeat timer"); 5272135446Strhodes 5273170222Sdougb CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5274170222Sdougb NULL, NULL, server->task, pps_timer_tick, 5275170222Sdougb server, &server->pps_timer), 5276170222Sdougb "creating pps timer"); 5277170222Sdougb 5278135446Strhodes CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 5279135446Strhodes "creating default configuration parser"); 5280135446Strhodes 5281135446Strhodes if (ns_g_lwresdonly) 5282135446Strhodes CHECKFATAL(load_configuration(lwresd_g_conffile, server, 5283135446Strhodes ISC_TRUE), 5284135446Strhodes "loading configuration"); 5285135446Strhodes else 5286135446Strhodes CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 5287135446Strhodes "loading configuration"); 5288135446Strhodes 5289135446Strhodes isc_hash_init(); 5290135446Strhodes 5291143731Sdougb CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); 5292135446Strhodes 5293143731Sdougb ns_os_started(); 5294135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5295143731Sdougb ISC_LOG_NOTICE, "running"); 5296135446Strhodes} 5297135446Strhodes 5298186462Sdougbvoid 5299135446Strhodesns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 5300135446Strhodes 5301135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5302135446Strhodes 5303135446Strhodes server->flushonshutdown = flush; 5304135446Strhodes} 5305135446Strhodes 5306135446Strhodesstatic void 5307135446Strhodesshutdown_server(isc_task_t *task, isc_event_t *event) { 5308135446Strhodes isc_result_t result; 5309135446Strhodes dns_view_t *view, *view_next; 5310135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5311135446Strhodes isc_boolean_t flush = server->flushonshutdown; 5312224092Sdougb ns_cache_t *nsc; 5313135446Strhodes 5314135446Strhodes UNUSED(task); 5315135446Strhodes INSIST(task == server->task); 5316135446Strhodes 5317135446Strhodes result = isc_task_beginexclusive(server->task); 5318135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5319135446Strhodes 5320135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5321135446Strhodes ISC_LOG_INFO, "shutting down%s", 5322135446Strhodes flush ? ": flushing changes" : ""); 5323135446Strhodes 5324193149Sdougb ns_statschannels_shutdown(server); 5325135446Strhodes ns_controls_shutdown(server->controls); 5326135446Strhodes end_reserved_dispatches(server, ISC_TRUE); 5327224092Sdougb cleanup_session_key(server, server->mctx); 5328135446Strhodes 5329225361Sdougb if (ns_g_aclconfctx != NULL) 5330225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 5331225361Sdougb 5332135446Strhodes cfg_obj_destroy(ns_g_parser, &ns_g_config); 5333135446Strhodes cfg_parser_destroy(&ns_g_parser); 5334135446Strhodes 5335135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5336135446Strhodes view != NULL; 5337135446Strhodes view = view_next) { 5338135446Strhodes view_next = ISC_LIST_NEXT(view, link); 5339135446Strhodes ISC_LIST_UNLINK(server->viewlist, view, link); 5340135446Strhodes if (flush) 5341135446Strhodes dns_view_flushanddetach(&view); 5342135446Strhodes else 5343135446Strhodes dns_view_detach(&view); 5344135446Strhodes } 5345135446Strhodes 5346224092Sdougb while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { 5347224092Sdougb ISC_LIST_UNLINK(server->cachelist, nsc, link); 5348224092Sdougb dns_cache_detach(&nsc->cache); 5349224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 5350224092Sdougb } 5351224092Sdougb 5352135446Strhodes isc_timer_detach(&server->interface_timer); 5353135446Strhodes isc_timer_detach(&server->heartbeat_timer); 5354170222Sdougb isc_timer_detach(&server->pps_timer); 5355135446Strhodes 5356135446Strhodes ns_interfacemgr_shutdown(server->interfacemgr); 5357135446Strhodes ns_interfacemgr_detach(&server->interfacemgr); 5358135446Strhodes 5359135446Strhodes dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 5360135446Strhodes 5361135446Strhodes dns_zonemgr_shutdown(server->zonemgr); 5362135446Strhodes 5363224092Sdougb if (ns_g_sessionkey != NULL) { 5364224092Sdougb dns_tsigkey_detach(&ns_g_sessionkey); 5365224092Sdougb dns_name_free(&ns_g_sessionkeyname, server->mctx); 5366224092Sdougb } 5367224092Sdougb 5368135446Strhodes if (server->blackholeacl != NULL) 5369135446Strhodes dns_acl_detach(&server->blackholeacl); 5370135446Strhodes 5371135446Strhodes dns_db_detach(&server->in_roothints); 5372135446Strhodes 5373135446Strhodes isc_task_endexclusive(server->task); 5374135446Strhodes 5375135446Strhodes isc_task_detach(&server->task); 5376135446Strhodes 5377135446Strhodes isc_event_free(&event); 5378135446Strhodes} 5379135446Strhodes 5380135446Strhodesvoid 5381135446Strhodesns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 5382135446Strhodes isc_result_t result; 5383225361Sdougb ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 5384135446Strhodes 5385135446Strhodes if (server == NULL) 5386135446Strhodes fatal("allocating server object", ISC_R_NOMEMORY); 5387135446Strhodes 5388135446Strhodes server->mctx = mctx; 5389135446Strhodes server->task = NULL; 5390135446Strhodes 5391135446Strhodes /* Initialize configuration data with default values. */ 5392135446Strhodes 5393135446Strhodes result = isc_quota_init(&server->xfroutquota, 10); 5394135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5395135446Strhodes result = isc_quota_init(&server->tcpquota, 10); 5396135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5397135446Strhodes result = isc_quota_init(&server->recursionquota, 100); 5398135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5399135446Strhodes 5400135446Strhodes result = dns_aclenv_init(mctx, &server->aclenv); 5401135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5402135446Strhodes 5403135446Strhodes /* Initialize server data structures. */ 5404135446Strhodes server->zonemgr = NULL; 5405135446Strhodes server->interfacemgr = NULL; 5406135446Strhodes ISC_LIST_INIT(server->viewlist); 5407135446Strhodes server->in_roothints = NULL; 5408135446Strhodes server->blackholeacl = NULL; 5409135446Strhodes 5410135446Strhodes CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 5411135446Strhodes &server->in_roothints), 5412135446Strhodes "setting up root hints"); 5413135446Strhodes 5414135446Strhodes CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 5415135446Strhodes "initializing reload event lock"); 5416135446Strhodes server->reload_event = 5417135446Strhodes isc_event_allocate(ns_g_mctx, server, 5418135446Strhodes NS_EVENT_RELOAD, 5419135446Strhodes ns_server_reload, 5420135446Strhodes server, 5421135446Strhodes sizeof(isc_event_t)); 5422135446Strhodes CHECKFATAL(server->reload_event == NULL ? 5423135446Strhodes ISC_R_NOMEMORY : ISC_R_SUCCESS, 5424135446Strhodes "allocating reload event"); 5425135446Strhodes 5426224092Sdougb CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, 5427224092Sdougb ns_g_engine, ISC_ENTROPY_GOODONLY), 5428135446Strhodes "initializing DST"); 5429135446Strhodes 5430135446Strhodes server->tkeyctx = NULL; 5431135446Strhodes CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 5432135446Strhodes &server->tkeyctx), 5433135446Strhodes "creating TKEY context"); 5434135446Strhodes 5435135446Strhodes /* 5436135446Strhodes * Setup the server task, which is responsible for coordinating 5437135446Strhodes * startup and shutdown of the server. 5438135446Strhodes */ 5439135446Strhodes CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 5440135446Strhodes "creating server task"); 5441135446Strhodes isc_task_setname(server->task, "server", server); 5442135446Strhodes CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 5443135446Strhodes "isc_task_onshutdown"); 5444135446Strhodes CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 5445135446Strhodes "isc_app_onrun"); 5446135446Strhodes 5447135446Strhodes server->interface_timer = NULL; 5448135446Strhodes server->heartbeat_timer = NULL; 5449170222Sdougb server->pps_timer = NULL; 5450186462Sdougb 5451135446Strhodes server->interface_interval = 0; 5452135446Strhodes server->heartbeat_interval = 0; 5453135446Strhodes 5454135446Strhodes CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 5455135446Strhodes ns_g_socketmgr, &server->zonemgr), 5456135446Strhodes "dns_zonemgr_create"); 5457225361Sdougb CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), 5458225361Sdougb "dns_zonemgr_setsize"); 5459135446Strhodes 5460135446Strhodes server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 5461135446Strhodes CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5462135446Strhodes "isc_mem_strdup"); 5463193149Sdougb server->nsstats = NULL; 5464193149Sdougb server->rcvquerystats = NULL; 5465193149Sdougb server->opcodestats = NULL; 5466193149Sdougb server->zonestats = NULL; 5467193149Sdougb server->resolverstats = NULL; 5468193149Sdougb server->sockstats = NULL; 5469193149Sdougb CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, 5470193149Sdougb isc_sockstatscounter_max), 5471193149Sdougb "isc_stats_create"); 5472193149Sdougb isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); 5473135446Strhodes 5474224092Sdougb server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys"); 5475224092Sdougb CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY : 5476224092Sdougb ISC_R_SUCCESS, 5477224092Sdougb "isc_mem_strdup"); 5478224092Sdougb 5479135446Strhodes server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 5480135446Strhodes CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5481135446Strhodes "isc_mem_strdup"); 5482135446Strhodes 5483224092Sdougb server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots"); 5484224092Sdougb CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY : 5485224092Sdougb ISC_R_SUCCESS, 5486224092Sdougb "isc_mem_strdup"); 5487224092Sdougb 5488135446Strhodes server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 5489135446Strhodes CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5490135446Strhodes "isc_mem_strdup"); 5491135446Strhodes 5492135446Strhodes server->hostname_set = ISC_FALSE; 5493135446Strhodes server->hostname = NULL; 5494186462Sdougb server->version_set = ISC_FALSE; 5495135446Strhodes server->version = NULL; 5496135446Strhodes server->server_usehostname = ISC_FALSE; 5497135446Strhodes server->server_id = NULL; 5498135446Strhodes 5499193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats, 5500193149Sdougb dns_nsstatscounter_max), 5501193149Sdougb "dns_stats_create (server)"); 5502135446Strhodes 5503193149Sdougb CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, 5504193149Sdougb &server->rcvquerystats), 5505193149Sdougb "dns_stats_create (rcvquery)"); 5506193149Sdougb 5507193149Sdougb CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), 5508193149Sdougb "dns_stats_create (opcode)"); 5509193149Sdougb 5510193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats, 5511193149Sdougb dns_zonestatscounter_max), 5512193149Sdougb "dns_stats_create (zone)"); 5513193149Sdougb 5514193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats, 5515193149Sdougb dns_resstatscounter_max), 5516193149Sdougb "dns_stats_create (resolver)"); 5517193149Sdougb 5518135446Strhodes server->flushonshutdown = ISC_FALSE; 5519135446Strhodes server->log_queries = ISC_FALSE; 5520135446Strhodes 5521135446Strhodes server->controls = NULL; 5522135446Strhodes CHECKFATAL(ns_controls_create(server, &server->controls), 5523135446Strhodes "ns_controls_create"); 5524135446Strhodes server->dispatchgen = 0; 5525135446Strhodes ISC_LIST_INIT(server->dispatches); 5526135446Strhodes 5527193149Sdougb ISC_LIST_INIT(server->statschannels); 5528193149Sdougb 5529224092Sdougb ISC_LIST_INIT(server->cachelist); 5530224092Sdougb 5531224092Sdougb server->sessionkey = NULL; 5532224092Sdougb server->session_keyfile = NULL; 5533224092Sdougb server->session_keyname = NULL; 5534224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 5535224092Sdougb server->session_keybits = 0; 5536224092Sdougb 5537135446Strhodes server->magic = NS_SERVER_MAGIC; 5538135446Strhodes *serverp = server; 5539135446Strhodes} 5540135446Strhodes 5541135446Strhodesvoid 5542135446Strhodesns_server_destroy(ns_server_t **serverp) { 5543135446Strhodes ns_server_t *server = *serverp; 5544135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5545135446Strhodes 5546135446Strhodes ns_controls_destroy(&server->controls); 5547135446Strhodes 5548193149Sdougb isc_stats_detach(&server->nsstats); 5549193149Sdougb dns_stats_detach(&server->rcvquerystats); 5550193149Sdougb dns_stats_detach(&server->opcodestats); 5551193149Sdougb isc_stats_detach(&server->zonestats); 5552193149Sdougb isc_stats_detach(&server->resolverstats); 5553193149Sdougb isc_stats_detach(&server->sockstats); 5554135446Strhodes 5555135446Strhodes isc_mem_free(server->mctx, server->statsfile); 5556224092Sdougb isc_mem_free(server->mctx, server->bindkeysfile); 5557135446Strhodes isc_mem_free(server->mctx, server->dumpfile); 5558224092Sdougb isc_mem_free(server->mctx, server->secrootsfile); 5559135446Strhodes isc_mem_free(server->mctx, server->recfile); 5560135446Strhodes 5561135446Strhodes if (server->version != NULL) 5562135446Strhodes isc_mem_free(server->mctx, server->version); 5563135446Strhodes if (server->hostname != NULL) 5564135446Strhodes isc_mem_free(server->mctx, server->hostname); 5565135446Strhodes if (server->server_id != NULL) 5566135446Strhodes isc_mem_free(server->mctx, server->server_id); 5567135446Strhodes 5568225361Sdougb if (server->zonemgr != NULL) 5569225361Sdougb dns_zonemgr_detach(&server->zonemgr); 5570135446Strhodes 5571135446Strhodes if (server->tkeyctx != NULL) 5572135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 5573135446Strhodes 5574135446Strhodes dst_lib_destroy(); 5575135446Strhodes 5576135446Strhodes isc_event_free(&server->reload_event); 5577135446Strhodes 5578135446Strhodes INSIST(ISC_LIST_EMPTY(server->viewlist)); 5579224092Sdougb INSIST(ISC_LIST_EMPTY(server->cachelist)); 5580135446Strhodes 5581135446Strhodes dns_aclenv_destroy(&server->aclenv); 5582135446Strhodes 5583135446Strhodes isc_quota_destroy(&server->recursionquota); 5584135446Strhodes isc_quota_destroy(&server->tcpquota); 5585135446Strhodes isc_quota_destroy(&server->xfroutquota); 5586135446Strhodes 5587135446Strhodes server->magic = 0; 5588135446Strhodes isc_mem_put(server->mctx, server, sizeof(*server)); 5589135446Strhodes *serverp = NULL; 5590135446Strhodes} 5591135446Strhodes 5592135446Strhodesstatic void 5593135446Strhodesfatal(const char *msg, isc_result_t result) { 5594135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5595135446Strhodes ISC_LOG_CRITICAL, "%s: %s", msg, 5596135446Strhodes isc_result_totext(result)); 5597135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5598135446Strhodes ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 5599135446Strhodes exit(1); 5600135446Strhodes} 5601135446Strhodes 5602135446Strhodesstatic void 5603135446Strhodesstart_reserved_dispatches(ns_server_t *server) { 5604135446Strhodes 5605135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5606135446Strhodes 5607135446Strhodes server->dispatchgen++; 5608135446Strhodes} 5609135446Strhodes 5610135446Strhodesstatic void 5611135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 5612135446Strhodes ns_dispatch_t *dispatch, *nextdispatch; 5613135446Strhodes 5614135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5615135446Strhodes 5616135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 5617135446Strhodes dispatch != NULL; 5618135446Strhodes dispatch = nextdispatch) { 5619135446Strhodes nextdispatch = ISC_LIST_NEXT(dispatch, link); 5620135446Strhodes if (!all && server->dispatchgen == dispatch-> dispatchgen) 5621135446Strhodes continue; 5622135446Strhodes ISC_LIST_UNLINK(server->dispatches, dispatch, link); 5623135446Strhodes dns_dispatch_detach(&dispatch->dispatch); 5624135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 5625135446Strhodes } 5626135446Strhodes} 5627135446Strhodes 5628135446Strhodesvoid 5629165071Sdougbns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 5630135446Strhodes ns_dispatch_t *dispatch; 5631135446Strhodes in_port_t port; 5632135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 5633135446Strhodes isc_result_t result; 5634135446Strhodes unsigned int attrs, attrmask; 5635135446Strhodes 5636135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5637135446Strhodes 5638135446Strhodes port = isc_sockaddr_getport(addr); 5639135446Strhodes if (port == 0 || port >= 1024) 5640135446Strhodes return; 5641135446Strhodes 5642135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 5643135446Strhodes dispatch != NULL; 5644135446Strhodes dispatch = ISC_LIST_NEXT(dispatch, link)) { 5645135446Strhodes if (isc_sockaddr_equal(&dispatch->addr, addr)) 5646135446Strhodes break; 5647135446Strhodes } 5648135446Strhodes if (dispatch != NULL) { 5649135446Strhodes dispatch->dispatchgen = server->dispatchgen; 5650135446Strhodes return; 5651135446Strhodes } 5652135446Strhodes 5653135446Strhodes dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 5654135446Strhodes if (dispatch == NULL) { 5655135446Strhodes result = ISC_R_NOMEMORY; 5656135446Strhodes goto cleanup; 5657135446Strhodes } 5658135446Strhodes 5659135446Strhodes dispatch->addr = *addr; 5660135446Strhodes dispatch->dispatchgen = server->dispatchgen; 5661135446Strhodes dispatch->dispatch = NULL; 5662135446Strhodes 5663135446Strhodes attrs = 0; 5664135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 5665135446Strhodes switch (isc_sockaddr_pf(addr)) { 5666135446Strhodes case AF_INET: 5667135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 5668135446Strhodes break; 5669135446Strhodes case AF_INET6: 5670135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 5671135446Strhodes break; 5672135446Strhodes default: 5673135446Strhodes result = ISC_R_NOTIMPLEMENTED; 5674135446Strhodes goto cleanup; 5675135446Strhodes } 5676135446Strhodes attrmask = 0; 5677135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 5678135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 5679135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 5680135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 5681135446Strhodes 5682135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 5683135446Strhodes ns_g_taskmgr, &dispatch->addr, 4096, 5684135446Strhodes 1000, 32768, 16411, 16433, 5685186462Sdougb attrs, attrmask, &dispatch->dispatch); 5686135446Strhodes if (result != ISC_R_SUCCESS) 5687135446Strhodes goto cleanup; 5688135446Strhodes 5689135446Strhodes ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 5690135446Strhodes 5691135446Strhodes return; 5692135446Strhodes 5693135446Strhodes cleanup: 5694135446Strhodes if (dispatch != NULL) 5695135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 5696135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 5697135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5698135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 5699135446Strhodes "unable to create dispatch for reserved port %s: %s", 5700135446Strhodes addrbuf, isc_result_totext(result)); 5701135446Strhodes} 5702135446Strhodes 5703135446Strhodes 5704135446Strhodesstatic isc_result_t 5705135446Strhodesloadconfig(ns_server_t *server) { 5706135446Strhodes isc_result_t result; 5707135446Strhodes start_reserved_dispatches(server); 5708135446Strhodes result = load_configuration(ns_g_lwresdonly ? 5709135446Strhodes lwresd_g_conffile : ns_g_conffile, 5710143731Sdougb server, ISC_FALSE); 5711193149Sdougb if (result == ISC_R_SUCCESS) { 5712135446Strhodes end_reserved_dispatches(server, ISC_FALSE); 5713135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5714193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5715193149Sdougb "reloading configuration succeeded"); 5716193149Sdougb } else { 5717193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5718135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5719135446Strhodes "reloading configuration failed: %s", 5720135446Strhodes isc_result_totext(result)); 5721193149Sdougb } 5722135446Strhodes return (result); 5723135446Strhodes} 5724135446Strhodes 5725135446Strhodesstatic isc_result_t 5726135446Strhodesreload(ns_server_t *server) { 5727135446Strhodes isc_result_t result; 5728135446Strhodes CHECK(loadconfig(server)); 5729135446Strhodes 5730135446Strhodes result = load_zones(server, ISC_FALSE); 5731193149Sdougb if (result == ISC_R_SUCCESS) 5732135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5733193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5734193149Sdougb "reloading zones succeeded"); 5735193149Sdougb else 5736193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5737135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5738135446Strhodes "reloading zones failed: %s", 5739135446Strhodes isc_result_totext(result)); 5740193149Sdougb 5741135446Strhodes cleanup: 5742135446Strhodes return (result); 5743135446Strhodes} 5744135446Strhodes 5745135446Strhodesstatic void 5746135446Strhodesreconfig(ns_server_t *server) { 5747135446Strhodes isc_result_t result; 5748135446Strhodes CHECK(loadconfig(server)); 5749135446Strhodes 5750135446Strhodes result = load_new_zones(server, ISC_FALSE); 5751193149Sdougb if (result == ISC_R_SUCCESS) 5752135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5753193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5754193149Sdougb "any newly configured zones are now loaded"); 5755193149Sdougb else 5756193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5757135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5758135446Strhodes "loading new zones failed: %s", 5759135446Strhodes isc_result_totext(result)); 5760193149Sdougb 5761135446Strhodes cleanup: ; 5762135446Strhodes} 5763135446Strhodes 5764135446Strhodes/* 5765135446Strhodes * Handle a reload event (from SIGHUP). 5766135446Strhodes */ 5767135446Strhodesstatic void 5768135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event) { 5769135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5770135446Strhodes 5771135446Strhodes INSIST(task = server->task); 5772135446Strhodes UNUSED(task); 5773135446Strhodes 5774193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5775193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5776193149Sdougb "received SIGHUP signal to reload zones"); 5777135446Strhodes (void)reload(server); 5778135446Strhodes 5779135446Strhodes LOCK(&server->reload_event_lock); 5780135446Strhodes INSIST(server->reload_event == NULL); 5781135446Strhodes server->reload_event = event; 5782135446Strhodes UNLOCK(&server->reload_event_lock); 5783135446Strhodes} 5784135446Strhodes 5785135446Strhodesvoid 5786135446Strhodesns_server_reloadwanted(ns_server_t *server) { 5787135446Strhodes LOCK(&server->reload_event_lock); 5788135446Strhodes if (server->reload_event != NULL) 5789135446Strhodes isc_task_send(server->task, &server->reload_event); 5790135446Strhodes UNLOCK(&server->reload_event_lock); 5791135446Strhodes} 5792135446Strhodes 5793135446Strhodesstatic char * 5794135446Strhodesnext_token(char **stringp, const char *delim) { 5795135446Strhodes char *res; 5796135446Strhodes 5797135446Strhodes do { 5798135446Strhodes res = strsep(stringp, delim); 5799135446Strhodes if (res == NULL) 5800135446Strhodes break; 5801135446Strhodes } while (*res == '\0'); 5802135446Strhodes return (res); 5803186462Sdougb} 5804135446Strhodes 5805135446Strhodes/* 5806135446Strhodes * Find the zone specified in the control channel command 'args', 5807135446Strhodes * if any. If a zone is specified, point '*zonep' at it, otherwise 5808135446Strhodes * set '*zonep' to NULL. 5809135446Strhodes */ 5810135446Strhodesstatic isc_result_t 5811224092Sdougbzone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep, 5812224092Sdougb const char **zonename) 5813224092Sdougb{ 5814135446Strhodes char *input, *ptr; 5815135446Strhodes const char *zonetxt; 5816135446Strhodes char *classtxt; 5817135446Strhodes const char *viewtxt = NULL; 5818135446Strhodes dns_fixedname_t name; 5819135446Strhodes isc_result_t result; 5820135446Strhodes isc_buffer_t buf; 5821135446Strhodes dns_view_t *view = NULL; 5822135446Strhodes dns_rdataclass_t rdclass; 5823135446Strhodes 5824135446Strhodes REQUIRE(zonep != NULL && *zonep == NULL); 5825135446Strhodes 5826135446Strhodes input = args; 5827135446Strhodes 5828135446Strhodes /* Skip the command name. */ 5829135446Strhodes ptr = next_token(&input, " \t"); 5830135446Strhodes if (ptr == NULL) 5831135446Strhodes return (ISC_R_UNEXPECTEDEND); 5832135446Strhodes 5833135446Strhodes /* Look for the zone name. */ 5834135446Strhodes zonetxt = next_token(&input, " \t"); 5835135446Strhodes if (zonetxt == NULL) 5836135446Strhodes return (ISC_R_SUCCESS); 5837224092Sdougb if (zonename) 5838224092Sdougb *zonename = zonetxt; 5839135446Strhodes 5840135446Strhodes /* Look for the optional class name. */ 5841135446Strhodes classtxt = next_token(&input, " \t"); 5842135446Strhodes if (classtxt != NULL) { 5843135446Strhodes /* Look for the optional view name. */ 5844135446Strhodes viewtxt = next_token(&input, " \t"); 5845135446Strhodes } 5846135446Strhodes 5847135446Strhodes isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); 5848135446Strhodes isc_buffer_add(&buf, strlen(zonetxt)); 5849135446Strhodes dns_fixedname_init(&name); 5850135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&name), 5851224092Sdougb &buf, dns_rootname, 0, NULL); 5852135446Strhodes if (result != ISC_R_SUCCESS) 5853135446Strhodes goto fail1; 5854135446Strhodes 5855135446Strhodes if (classtxt != NULL) { 5856135446Strhodes isc_textregion_t r; 5857135446Strhodes r.base = classtxt; 5858135446Strhodes r.length = strlen(classtxt); 5859135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &r); 5860135446Strhodes if (result != ISC_R_SUCCESS) 5861135446Strhodes goto fail1; 5862193149Sdougb } else 5863193149Sdougb rdclass = dns_rdataclass_in; 5864193149Sdougb 5865193149Sdougb if (viewtxt == NULL) { 5866193149Sdougb result = dns_viewlist_findzone(&server->viewlist, 5867193149Sdougb dns_fixedname_name(&name), 5868193149Sdougb ISC_TF(classtxt == NULL), 5869193149Sdougb rdclass, zonep); 5870135446Strhodes } else { 5871193149Sdougb result = dns_viewlist_find(&server->viewlist, viewtxt, 5872193149Sdougb rdclass, &view); 5873193149Sdougb if (result != ISC_R_SUCCESS) 5874193149Sdougb goto fail1; 5875193149Sdougb 5876193149Sdougb result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), 5877193149Sdougb 0, NULL, zonep); 5878193149Sdougb dns_view_detach(&view); 5879135446Strhodes } 5880186462Sdougb 5881135446Strhodes /* Partial match? */ 5882135446Strhodes if (result != ISC_R_SUCCESS && *zonep != NULL) 5883135446Strhodes dns_zone_detach(zonep); 5884204619Sdougb if (result == DNS_R_PARTIALMATCH) 5885204619Sdougb result = ISC_R_NOTFOUND; 5886135446Strhodes fail1: 5887135446Strhodes return (result); 5888135446Strhodes} 5889135446Strhodes 5890135446Strhodes/* 5891135446Strhodes * Act on a "retransfer" command from the command channel. 5892135446Strhodes */ 5893135446Strhodesisc_result_t 5894135446Strhodesns_server_retransfercommand(ns_server_t *server, char *args) { 5895135446Strhodes isc_result_t result; 5896135446Strhodes dns_zone_t *zone = NULL; 5897135446Strhodes dns_zonetype_t type; 5898186462Sdougb 5899224092Sdougb result = zone_from_args(server, args, &zone, NULL); 5900135446Strhodes if (result != ISC_R_SUCCESS) 5901135446Strhodes return (result); 5902135446Strhodes if (zone == NULL) 5903135446Strhodes return (ISC_R_UNEXPECTEDEND); 5904135446Strhodes type = dns_zone_gettype(zone); 5905135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) 5906135446Strhodes dns_zone_forcereload(zone); 5907135446Strhodes else 5908135446Strhodes result = ISC_R_NOTFOUND; 5909135446Strhodes dns_zone_detach(&zone); 5910135446Strhodes return (result); 5911186462Sdougb} 5912135446Strhodes 5913135446Strhodes/* 5914135446Strhodes * Act on a "reload" command from the command channel. 5915135446Strhodes */ 5916135446Strhodesisc_result_t 5917135446Strhodesns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 5918135446Strhodes isc_result_t result; 5919135446Strhodes dns_zone_t *zone = NULL; 5920135446Strhodes dns_zonetype_t type; 5921135446Strhodes const char *msg = NULL; 5922186462Sdougb 5923224092Sdougb result = zone_from_args(server, args, &zone, NULL); 5924135446Strhodes if (result != ISC_R_SUCCESS) 5925135446Strhodes return (result); 5926135446Strhodes if (zone == NULL) { 5927135446Strhodes result = reload(server); 5928135446Strhodes if (result == ISC_R_SUCCESS) 5929135446Strhodes msg = "server reload successful"; 5930135446Strhodes } else { 5931135446Strhodes type = dns_zone_gettype(zone); 5932135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) { 5933135446Strhodes dns_zone_refresh(zone); 5934174187Sdougb dns_zone_detach(&zone); 5935135446Strhodes msg = "zone refresh queued"; 5936135446Strhodes } else { 5937135446Strhodes result = dns_zone_load(zone); 5938135446Strhodes dns_zone_detach(&zone); 5939186462Sdougb switch (result) { 5940135446Strhodes case ISC_R_SUCCESS: 5941135446Strhodes msg = "zone reload successful"; 5942135446Strhodes break; 5943135446Strhodes case DNS_R_CONTINUE: 5944135446Strhodes msg = "zone reload queued"; 5945135446Strhodes result = ISC_R_SUCCESS; 5946135446Strhodes break; 5947135446Strhodes case DNS_R_UPTODATE: 5948135446Strhodes msg = "zone reload up-to-date"; 5949135446Strhodes result = ISC_R_SUCCESS; 5950135446Strhodes break; 5951135446Strhodes default: 5952135446Strhodes /* failure message will be generated by rndc */ 5953135446Strhodes break; 5954135446Strhodes } 5955135446Strhodes } 5956135446Strhodes } 5957135446Strhodes if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 5958135446Strhodes isc_buffer_putmem(text, (const unsigned char *)msg, 5959135446Strhodes strlen(msg) + 1); 5960135446Strhodes return (result); 5961186462Sdougb} 5962135446Strhodes 5963135446Strhodes/* 5964135446Strhodes * Act on a "reconfig" command from the command channel. 5965135446Strhodes */ 5966135446Strhodesisc_result_t 5967135446Strhodesns_server_reconfigcommand(ns_server_t *server, char *args) { 5968135446Strhodes UNUSED(args); 5969135446Strhodes 5970135446Strhodes reconfig(server); 5971135446Strhodes return (ISC_R_SUCCESS); 5972135446Strhodes} 5973135446Strhodes 5974135446Strhodes/* 5975170222Sdougb * Act on a "notify" command from the command channel. 5976170222Sdougb */ 5977170222Sdougbisc_result_t 5978170222Sdougbns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { 5979170222Sdougb isc_result_t result; 5980170222Sdougb dns_zone_t *zone = NULL; 5981170222Sdougb const unsigned char msg[] = "zone notify queued"; 5982170222Sdougb 5983224092Sdougb result = zone_from_args(server, args, &zone, NULL); 5984170222Sdougb if (result != ISC_R_SUCCESS) 5985170222Sdougb return (result); 5986170222Sdougb if (zone == NULL) 5987170222Sdougb return (ISC_R_UNEXPECTEDEND); 5988186462Sdougb 5989170222Sdougb dns_zone_notify(zone); 5990170222Sdougb dns_zone_detach(&zone); 5991170222Sdougb if (sizeof(msg) <= isc_buffer_availablelength(text)) 5992170222Sdougb isc_buffer_putmem(text, msg, sizeof(msg)); 5993170222Sdougb 5994170222Sdougb return (ISC_R_SUCCESS); 5995186462Sdougb} 5996170222Sdougb 5997170222Sdougb/* 5998135446Strhodes * Act on a "refresh" command from the command channel. 5999135446Strhodes */ 6000135446Strhodesisc_result_t 6001135446Strhodesns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6002135446Strhodes isc_result_t result; 6003135446Strhodes dns_zone_t *zone = NULL; 6004165071Sdougb const unsigned char msg1[] = "zone refresh queued"; 6005165071Sdougb const unsigned char msg2[] = "not a slave or stub zone"; 6006165071Sdougb dns_zonetype_t type; 6007135446Strhodes 6008224092Sdougb result = zone_from_args(server, args, &zone, NULL); 6009135446Strhodes if (result != ISC_R_SUCCESS) 6010135446Strhodes return (result); 6011135446Strhodes if (zone == NULL) 6012135446Strhodes return (ISC_R_UNEXPECTEDEND); 6013165071Sdougb 6014165071Sdougb type = dns_zone_gettype(zone); 6015165071Sdougb if (type == dns_zone_slave || type == dns_zone_stub) { 6016165071Sdougb dns_zone_refresh(zone); 6017165071Sdougb dns_zone_detach(&zone); 6018165071Sdougb if (sizeof(msg1) <= isc_buffer_availablelength(text)) 6019165071Sdougb isc_buffer_putmem(text, msg1, sizeof(msg1)); 6020165071Sdougb return (ISC_R_SUCCESS); 6021165071Sdougb } 6022186462Sdougb 6023135446Strhodes dns_zone_detach(&zone); 6024165071Sdougb if (sizeof(msg2) <= isc_buffer_availablelength(text)) 6025165071Sdougb isc_buffer_putmem(text, msg2, sizeof(msg2)); 6026165071Sdougb return (ISC_R_FAILURE); 6027186462Sdougb} 6028135446Strhodes 6029135446Strhodesisc_result_t 6030135446Strhodesns_server_togglequerylog(ns_server_t *server) { 6031135446Strhodes server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; 6032186462Sdougb 6033135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6034135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6035135446Strhodes "query logging is now %s", 6036135446Strhodes server->log_queries ? "on" : "off"); 6037135446Strhodes return (ISC_R_SUCCESS); 6038135446Strhodes} 6039135446Strhodes 6040135446Strhodesstatic isc_result_t 6041165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 6042170222Sdougb cfg_aclconfctx_t *actx, 6043135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target) 6044135446Strhodes{ 6045135446Strhodes isc_result_t result; 6046165071Sdougb const cfg_listelt_t *element; 6047135446Strhodes ns_listenlist_t *dlist = NULL; 6048135446Strhodes 6049135446Strhodes REQUIRE(target != NULL && *target == NULL); 6050135446Strhodes 6051135446Strhodes result = ns_listenlist_create(mctx, &dlist); 6052135446Strhodes if (result != ISC_R_SUCCESS) 6053135446Strhodes return (result); 6054135446Strhodes 6055135446Strhodes for (element = cfg_list_first(listenlist); 6056135446Strhodes element != NULL; 6057135446Strhodes element = cfg_list_next(element)) 6058135446Strhodes { 6059135446Strhodes ns_listenelt_t *delt = NULL; 6060165071Sdougb const cfg_obj_t *listener = cfg_listelt_value(element); 6061135446Strhodes result = ns_listenelt_fromconfig(listener, config, actx, 6062135446Strhodes mctx, &delt); 6063135446Strhodes if (result != ISC_R_SUCCESS) 6064135446Strhodes goto cleanup; 6065135446Strhodes ISC_LIST_APPEND(dlist->elts, delt, link); 6066135446Strhodes } 6067135446Strhodes *target = dlist; 6068135446Strhodes return (ISC_R_SUCCESS); 6069135446Strhodes 6070135446Strhodes cleanup: 6071135446Strhodes ns_listenlist_detach(&dlist); 6072135446Strhodes return (result); 6073135446Strhodes} 6074135446Strhodes 6075135446Strhodes/* 6076135446Strhodes * Create a listen list from the corresponding configuration 6077135446Strhodes * data structure. 6078135446Strhodes */ 6079135446Strhodesstatic isc_result_t 6080165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 6081170222Sdougb cfg_aclconfctx_t *actx, 6082135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target) 6083135446Strhodes{ 6084135446Strhodes isc_result_t result; 6085165071Sdougb const cfg_obj_t *portobj; 6086135446Strhodes in_port_t port; 6087135446Strhodes ns_listenelt_t *delt = NULL; 6088135446Strhodes REQUIRE(target != NULL && *target == NULL); 6089135446Strhodes 6090135446Strhodes portobj = cfg_tuple_get(listener, "port"); 6091135446Strhodes if (!cfg_obj_isuint32(portobj)) { 6092135446Strhodes if (ns_g_port != 0) { 6093135446Strhodes port = ns_g_port; 6094135446Strhodes } else { 6095135446Strhodes result = ns_config_getport(config, &port); 6096135446Strhodes if (result != ISC_R_SUCCESS) 6097135446Strhodes return (result); 6098135446Strhodes } 6099135446Strhodes } else { 6100135446Strhodes if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 6101135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 6102135446Strhodes "port value '%u' is out of range", 6103135446Strhodes cfg_obj_asuint32(portobj)); 6104135446Strhodes return (ISC_R_RANGE); 6105135446Strhodes } 6106135446Strhodes port = (in_port_t)cfg_obj_asuint32(portobj); 6107135446Strhodes } 6108135446Strhodes 6109135446Strhodes result = ns_listenelt_create(mctx, port, NULL, &delt); 6110135446Strhodes if (result != ISC_R_SUCCESS) 6111135446Strhodes return (result); 6112135446Strhodes 6113170222Sdougb result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), 6114193149Sdougb config, ns_g_lctx, actx, mctx, 0, 6115193149Sdougb &delt->acl); 6116135446Strhodes if (result != ISC_R_SUCCESS) { 6117135446Strhodes ns_listenelt_destroy(delt); 6118135446Strhodes return (result); 6119135446Strhodes } 6120135446Strhodes *target = delt; 6121135446Strhodes return (ISC_R_SUCCESS); 6122135446Strhodes} 6123135446Strhodes 6124135446Strhodesisc_result_t 6125135446Strhodesns_server_dumpstats(ns_server_t *server) { 6126135446Strhodes isc_result_t result; 6127135446Strhodes FILE *fp = NULL; 6128135446Strhodes 6129135446Strhodes CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 6130135446Strhodes "could not open statistics dump file", server->statsfile); 6131186462Sdougb 6132193149Sdougb result = ns_stats_dump(server, fp); 6133186462Sdougb 6134135446Strhodes cleanup: 6135135446Strhodes if (fp != NULL) 6136135446Strhodes (void)isc_stdio_close(fp); 6137193149Sdougb if (result == ISC_R_SUCCESS) 6138193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6139193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6140193149Sdougb "dumpstats complete"); 6141193149Sdougb else 6142193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6143193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6144193149Sdougb "dumpstats failed: %s", 6145193149Sdougb dns_result_totext(result)); 6146135446Strhodes return (result); 6147135446Strhodes} 6148135446Strhodes 6149135446Strhodesstatic isc_result_t 6150135446Strhodesadd_zone_tolist(dns_zone_t *zone, void *uap) { 6151135446Strhodes struct dumpcontext *dctx = uap; 6152135446Strhodes struct zonelistentry *zle; 6153135446Strhodes 6154135446Strhodes zle = isc_mem_get(dctx->mctx, sizeof *zle); 6155135446Strhodes if (zle == NULL) 6156135446Strhodes return (ISC_R_NOMEMORY); 6157135446Strhodes zle->zone = NULL; 6158135446Strhodes dns_zone_attach(zone, &zle->zone); 6159135446Strhodes ISC_LINK_INIT(zle, link); 6160135446Strhodes ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 6161135446Strhodes return (ISC_R_SUCCESS); 6162135446Strhodes} 6163135446Strhodes 6164135446Strhodesstatic isc_result_t 6165135446Strhodesadd_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 6166135446Strhodes struct viewlistentry *vle; 6167135446Strhodes isc_result_t result = ISC_R_SUCCESS; 6168186462Sdougb 6169153816Sdougb /* 6170153816Sdougb * Prevent duplicate views. 6171153816Sdougb */ 6172153816Sdougb for (vle = ISC_LIST_HEAD(dctx->viewlist); 6173153816Sdougb vle != NULL; 6174153816Sdougb vle = ISC_LIST_NEXT(vle, link)) 6175153816Sdougb if (vle->view == view) 6176153816Sdougb return (ISC_R_SUCCESS); 6177153816Sdougb 6178135446Strhodes vle = isc_mem_get(dctx->mctx, sizeof *vle); 6179135446Strhodes if (vle == NULL) 6180135446Strhodes return (ISC_R_NOMEMORY); 6181135446Strhodes vle->view = NULL; 6182135446Strhodes dns_view_attach(view, &vle->view); 6183135446Strhodes ISC_LINK_INIT(vle, link); 6184135446Strhodes ISC_LIST_INIT(vle->zonelist); 6185135446Strhodes ISC_LIST_APPEND(dctx->viewlist, vle, link); 6186135446Strhodes if (dctx->dumpzones) 6187135446Strhodes result = dns_zt_apply(view->zonetable, ISC_TRUE, 6188135446Strhodes add_zone_tolist, dctx); 6189135446Strhodes return (result); 6190135446Strhodes} 6191135446Strhodes 6192135446Strhodesstatic void 6193135446Strhodesdumpcontext_destroy(struct dumpcontext *dctx) { 6194135446Strhodes struct viewlistentry *vle; 6195135446Strhodes struct zonelistentry *zle; 6196135446Strhodes 6197135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6198135446Strhodes while (vle != NULL) { 6199135446Strhodes ISC_LIST_UNLINK(dctx->viewlist, vle, link); 6200135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6201135446Strhodes while (zle != NULL) { 6202135446Strhodes ISC_LIST_UNLINK(vle->zonelist, zle, link); 6203135446Strhodes dns_zone_detach(&zle->zone); 6204135446Strhodes isc_mem_put(dctx->mctx, zle, sizeof *zle); 6205135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6206135446Strhodes } 6207135446Strhodes dns_view_detach(&vle->view); 6208135446Strhodes isc_mem_put(dctx->mctx, vle, sizeof *vle); 6209135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6210135446Strhodes } 6211135446Strhodes if (dctx->version != NULL) 6212135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 6213135446Strhodes if (dctx->db != NULL) 6214135446Strhodes dns_db_detach(&dctx->db); 6215135446Strhodes if (dctx->cache != NULL) 6216135446Strhodes dns_db_detach(&dctx->cache); 6217135446Strhodes if (dctx->task != NULL) 6218135446Strhodes isc_task_detach(&dctx->task); 6219135446Strhodes if (dctx->fp != NULL) 6220135446Strhodes (void)isc_stdio_close(dctx->fp); 6221135446Strhodes if (dctx->mdctx != NULL) 6222135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 6223135446Strhodes isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 6224135446Strhodes} 6225135446Strhodes 6226135446Strhodesstatic void 6227135446Strhodesdumpdone(void *arg, isc_result_t result) { 6228135446Strhodes struct dumpcontext *dctx = arg; 6229135446Strhodes char buf[1024+32]; 6230135446Strhodes const dns_master_style_t *style; 6231186462Sdougb 6232135446Strhodes if (result != ISC_R_SUCCESS) 6233135446Strhodes goto cleanup; 6234135446Strhodes if (dctx->mdctx != NULL) 6235135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 6236135446Strhodes if (dctx->view == NULL) { 6237135446Strhodes dctx->view = ISC_LIST_HEAD(dctx->viewlist); 6238135446Strhodes if (dctx->view == NULL) 6239135446Strhodes goto done; 6240135446Strhodes INSIST(dctx->zone == NULL); 6241153816Sdougb } else 6242153816Sdougb goto resume; 6243135446Strhodes nextview: 6244135446Strhodes fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 6245153816Sdougb resume: 6246224092Sdougb if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) { 6247224092Sdougb fprintf(dctx->fp, 6248224092Sdougb ";\n; Cache of view '%s' is shared as '%s'\n", 6249224092Sdougb dctx->view->view->name, 6250224092Sdougb dns_cache_getname(dctx->view->view->cache)); 6251224092Sdougb } else if (dctx->zone == NULL && dctx->cache == NULL && 6252224092Sdougb dctx->dumpcache) 6253224092Sdougb { 6254135446Strhodes style = &dns_master_style_cache; 6255135446Strhodes /* start cache dump */ 6256135446Strhodes if (dctx->view->view->cachedb != NULL) 6257135446Strhodes dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 6258135446Strhodes if (dctx->cache != NULL) { 6259224092Sdougb fprintf(dctx->fp, 6260224092Sdougb ";\n; Cache dump of view '%s' (cache %s)\n;\n", 6261224092Sdougb dctx->view->view->name, 6262224092Sdougb dns_cache_getname(dctx->view->view->cache)); 6263135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 6264135446Strhodes dctx->cache, NULL, 6265135446Strhodes style, dctx->fp, 6266135446Strhodes dctx->task, 6267135446Strhodes dumpdone, dctx, 6268135446Strhodes &dctx->mdctx); 6269135446Strhodes if (result == DNS_R_CONTINUE) 6270135446Strhodes return; 6271135446Strhodes if (result == ISC_R_NOTIMPLEMENTED) 6272135446Strhodes fprintf(dctx->fp, "; %s\n", 6273135446Strhodes dns_result_totext(result)); 6274135446Strhodes else if (result != ISC_R_SUCCESS) 6275135446Strhodes goto cleanup; 6276135446Strhodes } 6277135446Strhodes } 6278135446Strhodes if (dctx->cache != NULL) { 6279135446Strhodes dns_adb_dump(dctx->view->view->adb, dctx->fp); 6280205292Sdougb dns_resolver_printbadcache(dctx->view->view->resolver, 6281205292Sdougb dctx->fp); 6282135446Strhodes dns_db_detach(&dctx->cache); 6283135446Strhodes } 6284135446Strhodes if (dctx->dumpzones) { 6285135446Strhodes style = &dns_master_style_full; 6286135446Strhodes nextzone: 6287135446Strhodes if (dctx->version != NULL) 6288135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, 6289135446Strhodes ISC_FALSE); 6290135446Strhodes if (dctx->db != NULL) 6291135446Strhodes dns_db_detach(&dctx->db); 6292135446Strhodes if (dctx->zone == NULL) 6293135446Strhodes dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 6294135446Strhodes else 6295135446Strhodes dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 6296135446Strhodes if (dctx->zone != NULL) { 6297135446Strhodes /* start zone dump */ 6298135446Strhodes dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 6299135446Strhodes fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 6300135446Strhodes result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 6301135446Strhodes if (result != ISC_R_SUCCESS) { 6302135446Strhodes fprintf(dctx->fp, "; %s\n", 6303135446Strhodes dns_result_totext(result)); 6304135446Strhodes goto nextzone; 6305135446Strhodes } 6306135446Strhodes dns_db_currentversion(dctx->db, &dctx->version); 6307135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 6308135446Strhodes dctx->db, 6309135446Strhodes dctx->version, 6310135446Strhodes style, dctx->fp, 6311135446Strhodes dctx->task, 6312135446Strhodes dumpdone, dctx, 6313135446Strhodes &dctx->mdctx); 6314135446Strhodes if (result == DNS_R_CONTINUE) 6315135446Strhodes return; 6316153816Sdougb if (result == ISC_R_NOTIMPLEMENTED) { 6317135446Strhodes fprintf(dctx->fp, "; %s\n", 6318135446Strhodes dns_result_totext(result)); 6319153816Sdougb result = ISC_R_SUCCESS; 6320225361Sdougb POST(result); 6321153816Sdougb goto nextzone; 6322153816Sdougb } 6323135446Strhodes if (result != ISC_R_SUCCESS) 6324135446Strhodes goto cleanup; 6325135446Strhodes } 6326135446Strhodes } 6327135446Strhodes if (dctx->view != NULL) 6328135446Strhodes dctx->view = ISC_LIST_NEXT(dctx->view, link); 6329135446Strhodes if (dctx->view != NULL) 6330135446Strhodes goto nextview; 6331135446Strhodes done: 6332135446Strhodes fprintf(dctx->fp, "; Dump complete\n"); 6333135446Strhodes result = isc_stdio_flush(dctx->fp); 6334135446Strhodes if (result == ISC_R_SUCCESS) 6335135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6336135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6337135446Strhodes "dumpdb complete"); 6338135446Strhodes cleanup: 6339135446Strhodes if (result != ISC_R_SUCCESS) 6340135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6341193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6342135446Strhodes "dumpdb failed: %s", dns_result_totext(result)); 6343135446Strhodes dumpcontext_destroy(dctx); 6344135446Strhodes} 6345135446Strhodes 6346135446Strhodesisc_result_t 6347135446Strhodesns_server_dumpdb(ns_server_t *server, char *args) { 6348135446Strhodes struct dumpcontext *dctx = NULL; 6349135446Strhodes dns_view_t *view; 6350135446Strhodes isc_result_t result; 6351135446Strhodes char *ptr; 6352135446Strhodes const char *sep; 6353135446Strhodes 6354165071Sdougb /* Skip the command name. */ 6355165071Sdougb ptr = next_token(&args, " \t"); 6356165071Sdougb if (ptr == NULL) 6357165071Sdougb return (ISC_R_UNEXPECTEDEND); 6358165071Sdougb 6359135446Strhodes dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 6360135446Strhodes if (dctx == NULL) 6361135446Strhodes return (ISC_R_NOMEMORY); 6362135446Strhodes 6363135446Strhodes dctx->mctx = server->mctx; 6364135446Strhodes dctx->dumpcache = ISC_TRUE; 6365135446Strhodes dctx->dumpzones = ISC_FALSE; 6366135446Strhodes dctx->fp = NULL; 6367135446Strhodes ISC_LIST_INIT(dctx->viewlist); 6368135446Strhodes dctx->view = NULL; 6369135446Strhodes dctx->zone = NULL; 6370135446Strhodes dctx->cache = NULL; 6371135446Strhodes dctx->mdctx = NULL; 6372135446Strhodes dctx->db = NULL; 6373135446Strhodes dctx->cache = NULL; 6374135446Strhodes dctx->task = NULL; 6375135446Strhodes dctx->version = NULL; 6376135446Strhodes isc_task_attach(server->task, &dctx->task); 6377135446Strhodes 6378135446Strhodes CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 6379135446Strhodes "could not open dump file", server->dumpfile); 6380135446Strhodes 6381135446Strhodes sep = (args == NULL) ? "" : ": "; 6382135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6383135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6384135446Strhodes "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 6385135446Strhodes 6386135446Strhodes ptr = next_token(&args, " \t"); 6387135446Strhodes if (ptr != NULL && strcmp(ptr, "-all") == 0) { 6388135446Strhodes dctx->dumpzones = ISC_TRUE; 6389135446Strhodes dctx->dumpcache = ISC_TRUE; 6390135446Strhodes ptr = next_token(&args, " \t"); 6391135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 6392135446Strhodes dctx->dumpzones = ISC_FALSE; 6393135446Strhodes dctx->dumpcache = ISC_TRUE; 6394135446Strhodes ptr = next_token(&args, " \t"); 6395135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 6396135446Strhodes dctx->dumpzones = ISC_TRUE; 6397135446Strhodes dctx->dumpcache = ISC_FALSE; 6398135446Strhodes ptr = next_token(&args, " \t"); 6399186462Sdougb } 6400135446Strhodes 6401153816Sdougb nextview: 6402135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 6403135446Strhodes view != NULL; 6404135446Strhodes view = ISC_LIST_NEXT(view, link)) 6405135446Strhodes { 6406135446Strhodes if (ptr != NULL && strcmp(view->name, ptr) != 0) 6407135446Strhodes continue; 6408135446Strhodes CHECK(add_view_tolist(dctx, view)); 6409135446Strhodes } 6410153816Sdougb if (ptr != NULL) { 6411153816Sdougb ptr = next_token(&args, " \t"); 6412153816Sdougb if (ptr != NULL) 6413153816Sdougb goto nextview; 6414153816Sdougb } 6415135446Strhodes dumpdone(dctx, ISC_R_SUCCESS); 6416135446Strhodes return (ISC_R_SUCCESS); 6417135446Strhodes 6418135446Strhodes cleanup: 6419135446Strhodes if (dctx != NULL) 6420135446Strhodes dumpcontext_destroy(dctx); 6421135446Strhodes return (result); 6422135446Strhodes} 6423135446Strhodes 6424135446Strhodesisc_result_t 6425224092Sdougbns_server_dumpsecroots(ns_server_t *server, char *args) { 6426224092Sdougb dns_view_t *view; 6427224092Sdougb dns_keytable_t *secroots = NULL; 6428224092Sdougb isc_result_t result; 6429224092Sdougb char *ptr; 6430224092Sdougb FILE *fp = NULL; 6431224092Sdougb isc_time_t now; 6432224092Sdougb char tbuf[64]; 6433224092Sdougb 6434224092Sdougb /* Skip the command name. */ 6435224092Sdougb ptr = next_token(&args, " \t"); 6436224092Sdougb if (ptr == NULL) 6437224092Sdougb return (ISC_R_UNEXPECTEDEND); 6438224092Sdougb ptr = next_token(&args, " \t"); 6439224092Sdougb 6440224092Sdougb CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp), 6441224092Sdougb "could not open secroots dump file", server->secrootsfile); 6442224092Sdougb TIME_NOW(&now); 6443224092Sdougb isc_time_formattimestamp(&now, tbuf, sizeof(tbuf)); 6444224092Sdougb fprintf(fp, "%s\n", tbuf); 6445224092Sdougb 6446225361Sdougb do { 6447225361Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6448225361Sdougb view != NULL; 6449225361Sdougb view = ISC_LIST_NEXT(view, link)) 6450225361Sdougb { 6451225361Sdougb if (ptr != NULL && strcmp(view->name, ptr) != 0) 6452225361Sdougb continue; 6453225361Sdougb if (secroots != NULL) 6454225361Sdougb dns_keytable_detach(&secroots); 6455225361Sdougb result = dns_view_getsecroots(view, &secroots); 6456225361Sdougb if (result == ISC_R_NOTFOUND) { 6457225361Sdougb result = ISC_R_SUCCESS; 6458225361Sdougb continue; 6459225361Sdougb } 6460225361Sdougb fprintf(fp, "\n Start view %s\n\n", view->name); 6461225361Sdougb result = dns_keytable_dump(secroots, fp); 6462225361Sdougb if (result != ISC_R_SUCCESS) 6463225361Sdougb fprintf(fp, " dumpsecroots failed: %s\n", 6464225361Sdougb isc_result_totext(result)); 6465224092Sdougb } 6466224092Sdougb if (ptr != NULL) 6467225361Sdougb ptr = next_token(&args, " \t"); 6468225361Sdougb } while (ptr != NULL); 6469224092Sdougb 6470224092Sdougb cleanup: 6471224092Sdougb if (secroots != NULL) 6472224092Sdougb dns_keytable_detach(&secroots); 6473224092Sdougb if (fp != NULL) 6474224092Sdougb (void)isc_stdio_close(fp); 6475224092Sdougb if (result == ISC_R_SUCCESS) 6476224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6477224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6478224092Sdougb "dumpsecroots complete"); 6479224092Sdougb else 6480224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6481224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6482224092Sdougb "dumpsecroots failed: %s", 6483224092Sdougb dns_result_totext(result)); 6484224092Sdougb return (result); 6485224092Sdougb} 6486224092Sdougb 6487224092Sdougbisc_result_t 6488135446Strhodesns_server_dumprecursing(ns_server_t *server) { 6489135446Strhodes FILE *fp = NULL; 6490135446Strhodes isc_result_t result; 6491135446Strhodes 6492135446Strhodes CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 6493135446Strhodes "could not open dump file", server->recfile); 6494135446Strhodes fprintf(fp,";\n; Recursing Queries\n;\n"); 6495135446Strhodes ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 6496135446Strhodes fprintf(fp, "; Dump complete\n"); 6497135446Strhodes 6498135446Strhodes cleanup: 6499135446Strhodes if (fp != NULL) 6500135446Strhodes result = isc_stdio_close(fp); 6501193149Sdougb if (result == ISC_R_SUCCESS) 6502193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6503193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6504193149Sdougb "dumprecursing complete"); 6505193149Sdougb else 6506193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6507193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6508193149Sdougb "dumprecursing failed: %s", 6509193149Sdougb dns_result_totext(result)); 6510135446Strhodes return (result); 6511135446Strhodes} 6512135446Strhodes 6513135446Strhodesisc_result_t 6514135446Strhodesns_server_setdebuglevel(ns_server_t *server, char *args) { 6515135446Strhodes char *ptr; 6516135446Strhodes char *levelstr; 6517135446Strhodes char *endp; 6518135446Strhodes long newlevel; 6519135446Strhodes 6520135446Strhodes UNUSED(server); 6521135446Strhodes 6522135446Strhodes /* Skip the command name. */ 6523135446Strhodes ptr = next_token(&args, " \t"); 6524135446Strhodes if (ptr == NULL) 6525135446Strhodes return (ISC_R_UNEXPECTEDEND); 6526135446Strhodes 6527135446Strhodes /* Look for the new level name. */ 6528135446Strhodes levelstr = next_token(&args, " \t"); 6529135446Strhodes if (levelstr == NULL) { 6530135446Strhodes if (ns_g_debuglevel < 99) 6531135446Strhodes ns_g_debuglevel++; 6532135446Strhodes } else { 6533135446Strhodes newlevel = strtol(levelstr, &endp, 10); 6534135446Strhodes if (*endp != '\0' || newlevel < 0 || newlevel > 99) 6535135446Strhodes return (ISC_R_RANGE); 6536135446Strhodes ns_g_debuglevel = (unsigned int)newlevel; 6537135446Strhodes } 6538135446Strhodes isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 6539193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6540193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6541193149Sdougb "debug level is now %d", ns_g_debuglevel); 6542135446Strhodes return (ISC_R_SUCCESS); 6543135446Strhodes} 6544135446Strhodes 6545135446Strhodesisc_result_t 6546170222Sdougbns_server_validation(ns_server_t *server, char *args) { 6547170222Sdougb char *ptr, *viewname; 6548170222Sdougb dns_view_t *view; 6549170222Sdougb isc_boolean_t changed = ISC_FALSE; 6550170222Sdougb isc_result_t result; 6551170222Sdougb isc_boolean_t enable; 6552170222Sdougb 6553170222Sdougb /* Skip the command name. */ 6554170222Sdougb ptr = next_token(&args, " \t"); 6555170222Sdougb if (ptr == NULL) 6556170222Sdougb return (ISC_R_UNEXPECTEDEND); 6557170222Sdougb 6558170222Sdougb /* Find out what we are to do. */ 6559170222Sdougb ptr = next_token(&args, " \t"); 6560170222Sdougb if (ptr == NULL) 6561170222Sdougb return (ISC_R_UNEXPECTEDEND); 6562170222Sdougb 6563170222Sdougb if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || 6564170222Sdougb !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) 6565170222Sdougb enable = ISC_TRUE; 6566170222Sdougb else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || 6567170222Sdougb !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) 6568170222Sdougb enable = ISC_FALSE; 6569170222Sdougb else 6570170222Sdougb return (DNS_R_SYNTAX); 6571170222Sdougb 6572170222Sdougb /* Look for the view name. */ 6573170222Sdougb viewname = next_token(&args, " \t"); 6574170222Sdougb 6575170222Sdougb result = isc_task_beginexclusive(server->task); 6576170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 6577170222Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6578170222Sdougb view != NULL; 6579170222Sdougb view = ISC_LIST_NEXT(view, link)) 6580170222Sdougb { 6581170222Sdougb if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 6582170222Sdougb continue; 6583170222Sdougb result = dns_view_flushcache(view); 6584170222Sdougb if (result != ISC_R_SUCCESS) 6585170222Sdougb goto out; 6586170222Sdougb view->enablevalidation = enable; 6587170222Sdougb changed = ISC_TRUE; 6588170222Sdougb } 6589170222Sdougb if (changed) 6590170222Sdougb result = ISC_R_SUCCESS; 6591170222Sdougb else 6592170222Sdougb result = ISC_R_FAILURE; 6593170222Sdougb out: 6594186462Sdougb isc_task_endexclusive(server->task); 6595170222Sdougb return (result); 6596170222Sdougb} 6597170222Sdougb 6598170222Sdougbisc_result_t 6599135446Strhodesns_server_flushcache(ns_server_t *server, char *args) { 6600135446Strhodes char *ptr, *viewname; 6601135446Strhodes dns_view_t *view; 6602174187Sdougb isc_boolean_t flushed; 6603174187Sdougb isc_boolean_t found; 6604135446Strhodes isc_result_t result; 6605224092Sdougb ns_cache_t *nsc; 6606135446Strhodes 6607135446Strhodes /* Skip the command name. */ 6608135446Strhodes ptr = next_token(&args, " \t"); 6609135446Strhodes if (ptr == NULL) 6610135446Strhodes return (ISC_R_UNEXPECTEDEND); 6611135446Strhodes 6612135446Strhodes /* Look for the view name. */ 6613135446Strhodes viewname = next_token(&args, " \t"); 6614135446Strhodes 6615135446Strhodes result = isc_task_beginexclusive(server->task); 6616135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6617174187Sdougb flushed = ISC_TRUE; 6618174187Sdougb found = ISC_FALSE; 6619224092Sdougb 6620224092Sdougb /* 6621224092Sdougb * Flushing a cache is tricky when caches are shared by multiple views. 6622224092Sdougb * We first identify which caches should be flushed in the local cache 6623224092Sdougb * list, flush these caches, and then update other views that refer to 6624224092Sdougb * the flushed cache DB. 6625224092Sdougb */ 6626224092Sdougb if (viewname != NULL) { 6627224092Sdougb /* 6628224092Sdougb * Mark caches that need to be flushed. This is an O(#view^2) 6629224092Sdougb * operation in the very worst case, but should be normally 6630224092Sdougb * much more lightweight because only a few (most typically just 6631224092Sdougb * one) views will match. 6632224092Sdougb */ 6633224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6634224092Sdougb view != NULL; 6635224092Sdougb view = ISC_LIST_NEXT(view, link)) 6636224092Sdougb { 6637224092Sdougb if (strcasecmp(viewname, view->name) != 0) 6638224092Sdougb continue; 6639224092Sdougb found = ISC_TRUE; 6640224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6641224092Sdougb nsc != NULL; 6642224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6643224092Sdougb if (nsc->cache == view->cache) 6644224092Sdougb break; 6645224092Sdougb } 6646224092Sdougb INSIST(nsc != NULL); 6647224092Sdougb nsc->needflush = ISC_TRUE; 6648224092Sdougb } 6649224092Sdougb } else 6650224092Sdougb found = ISC_TRUE; 6651224092Sdougb 6652224092Sdougb /* Perform flush */ 6653224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6654224092Sdougb nsc != NULL; 6655224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6656224092Sdougb if (viewname != NULL && !nsc->needflush) 6657135446Strhodes continue; 6658224092Sdougb nsc->needflush = ISC_TRUE; 6659224092Sdougb result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE); 6660193149Sdougb if (result != ISC_R_SUCCESS) { 6661174187Sdougb flushed = ISC_FALSE; 6662193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6663193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6664193149Sdougb "flushing cache in view '%s' failed: %s", 6665224092Sdougb nsc->primaryview->name, 6666224092Sdougb isc_result_totext(result)); 6667193149Sdougb } 6668135446Strhodes } 6669224092Sdougb 6670224092Sdougb /* 6671224092Sdougb * Fix up views that share a flushed cache: let the views update the 6672224092Sdougb * cache DB they're referring to. This could also be an expensive 6673224092Sdougb * operation, but should typically be marginal: the inner loop is only 6674224092Sdougb * necessary for views that share a cache, and if there are many such 6675224092Sdougb * views the number of shared cache should normally be small. 6676224092Sdougb * A worst case is that we have n views and n/2 caches, each shared by 6677224092Sdougb * two views. Then this will be a O(n^2/4) operation. 6678224092Sdougb */ 6679224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6680224092Sdougb view != NULL; 6681224092Sdougb view = ISC_LIST_NEXT(view, link)) 6682224092Sdougb { 6683224092Sdougb if (!dns_view_iscacheshared(view)) 6684224092Sdougb continue; 6685224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6686224092Sdougb nsc != NULL; 6687224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6688224092Sdougb if (!nsc->needflush || nsc->cache != view->cache) 6689224092Sdougb continue; 6690224092Sdougb result = dns_view_flushcache2(view, ISC_TRUE); 6691224092Sdougb if (result != ISC_R_SUCCESS) { 6692224092Sdougb flushed = ISC_FALSE; 6693224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6694224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6695224092Sdougb "fixing cache in view '%s' " 6696224092Sdougb "failed: %s", view->name, 6697224092Sdougb isc_result_totext(result)); 6698224092Sdougb } 6699224092Sdougb } 6700224092Sdougb } 6701224092Sdougb 6702224092Sdougb /* Cleanup the cache list. */ 6703224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6704224092Sdougb nsc != NULL; 6705224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6706224092Sdougb nsc->needflush = ISC_FALSE; 6707224092Sdougb } 6708224092Sdougb 6709174187Sdougb if (flushed && found) { 6710193149Sdougb if (viewname != NULL) 6711193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6712193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6713193149Sdougb "flushing cache in view '%s' succeeded", 6714193149Sdougb viewname); 6715193149Sdougb else 6716193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6717193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6718193149Sdougb "flushing caches in all views succeeded"); 6719135446Strhodes result = ISC_R_SUCCESS; 6720174187Sdougb } else { 6721193149Sdougb if (!found) { 6722193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6723193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6724193149Sdougb "flushing cache in view '%s' failed: " 6725193149Sdougb "view not found", viewname); 6726174187Sdougb result = ISC_R_NOTFOUND; 6727193149Sdougb } else 6728174187Sdougb result = ISC_R_FAILURE; 6729174187Sdougb } 6730186462Sdougb isc_task_endexclusive(server->task); 6731135446Strhodes return (result); 6732135446Strhodes} 6733135446Strhodes 6734135446Strhodesisc_result_t 6735135446Strhodesns_server_flushname(ns_server_t *server, char *args) { 6736135446Strhodes char *ptr, *target, *viewname; 6737135446Strhodes dns_view_t *view; 6738174187Sdougb isc_boolean_t flushed; 6739174187Sdougb isc_boolean_t found; 6740135446Strhodes isc_result_t result; 6741135446Strhodes isc_buffer_t b; 6742135446Strhodes dns_fixedname_t fixed; 6743135446Strhodes dns_name_t *name; 6744135446Strhodes 6745135446Strhodes /* Skip the command name. */ 6746135446Strhodes ptr = next_token(&args, " \t"); 6747135446Strhodes if (ptr == NULL) 6748135446Strhodes return (ISC_R_UNEXPECTEDEND); 6749135446Strhodes 6750135446Strhodes /* Find the domain name to flush. */ 6751135446Strhodes target = next_token(&args, " \t"); 6752135446Strhodes if (target == NULL) 6753135446Strhodes return (ISC_R_UNEXPECTEDEND); 6754135446Strhodes 6755135446Strhodes isc_buffer_init(&b, target, strlen(target)); 6756135446Strhodes isc_buffer_add(&b, strlen(target)); 6757135446Strhodes dns_fixedname_init(&fixed); 6758135446Strhodes name = dns_fixedname_name(&fixed); 6759224092Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 6760135446Strhodes if (result != ISC_R_SUCCESS) 6761135446Strhodes return (result); 6762135446Strhodes 6763135446Strhodes /* Look for the view name. */ 6764135446Strhodes viewname = next_token(&args, " \t"); 6765135446Strhodes 6766135446Strhodes result = isc_task_beginexclusive(server->task); 6767135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6768135446Strhodes flushed = ISC_TRUE; 6769174187Sdougb found = ISC_FALSE; 6770135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 6771135446Strhodes view != NULL; 6772135446Strhodes view = ISC_LIST_NEXT(view, link)) 6773135446Strhodes { 6774135446Strhodes if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 6775135446Strhodes continue; 6776174187Sdougb found = ISC_TRUE; 6777224092Sdougb /* 6778224092Sdougb * It's a little inefficient to try flushing name for all views 6779224092Sdougb * if some of the views share a single cache. But since the 6780224092Sdougb * operation is lightweight we prefer simplicity here. 6781224092Sdougb */ 6782135446Strhodes result = dns_view_flushname(view, name); 6783193149Sdougb if (result != ISC_R_SUCCESS) { 6784135446Strhodes flushed = ISC_FALSE; 6785193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6786193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6787193149Sdougb "flushing name '%s' in cache view '%s' " 6788193149Sdougb "failed: %s", target, view->name, 6789193149Sdougb isc_result_totext(result)); 6790193149Sdougb } 6791135446Strhodes } 6792193149Sdougb if (flushed && found) { 6793193149Sdougb if (viewname != NULL) 6794193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6795193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6796193149Sdougb "flushing name '%s' in cache view '%s' " 6797193149Sdougb "succeeded", target, viewname); 6798193149Sdougb else 6799193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6800193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6801193149Sdougb "flushing name '%s' in all cache views " 6802193149Sdougb "succeeded", target); 6803135446Strhodes result = ISC_R_SUCCESS; 6804193149Sdougb } else { 6805193149Sdougb if (!found) 6806193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6807193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6808193149Sdougb "flushing name '%s' in cache view '%s' " 6809193149Sdougb "failed: view not found", target, 6810193149Sdougb viewname); 6811135446Strhodes result = ISC_R_FAILURE; 6812193149Sdougb } 6813186462Sdougb isc_task_endexclusive(server->task); 6814135446Strhodes return (result); 6815135446Strhodes} 6816135446Strhodes 6817135446Strhodesisc_result_t 6818135446Strhodesns_server_status(ns_server_t *server, isc_buffer_t *text) { 6819135446Strhodes int zonecount, xferrunning, xferdeferred, soaqueries; 6820135446Strhodes unsigned int n; 6821193149Sdougb const char *ob = "", *cb = "", *alt = ""; 6822135446Strhodes 6823193149Sdougb if (ns_g_server->version_set) { 6824193149Sdougb ob = " ("; 6825193149Sdougb cb = ")"; 6826193149Sdougb if (ns_g_server->version == NULL) 6827193149Sdougb alt = "version.bind/txt/ch disabled"; 6828193149Sdougb else 6829193149Sdougb alt = ns_g_server->version; 6830193149Sdougb } 6831135446Strhodes zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 6832135446Strhodes xferrunning = dns_zonemgr_getcount(server->zonemgr, 6833135446Strhodes DNS_ZONESTATE_XFERRUNNING); 6834135446Strhodes xferdeferred = dns_zonemgr_getcount(server->zonemgr, 6835135446Strhodes DNS_ZONESTATE_XFERDEFERRED); 6836135446Strhodes soaqueries = dns_zonemgr_getcount(server->zonemgr, 6837135446Strhodes DNS_ZONESTATE_SOAQUERY); 6838193149Sdougb 6839135446Strhodes n = snprintf((char *)isc_buffer_used(text), 6840135446Strhodes isc_buffer_availablelength(text), 6841193149Sdougb "version: %s%s%s%s\n" 6842193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 6843193149Sdougb "CPUs found: %u\n" 6844193149Sdougb "worker threads: %u\n" 6845193149Sdougb#endif 6846135446Strhodes "number of zones: %u\n" 6847135446Strhodes "debug level: %d\n" 6848135446Strhodes "xfers running: %u\n" 6849135446Strhodes "xfers deferred: %u\n" 6850135446Strhodes "soa queries in progress: %u\n" 6851135446Strhodes "query logging is %s\n" 6852170222Sdougb "recursive clients: %d/%d/%d\n" 6853135446Strhodes "tcp clients: %d/%d\n" 6854135446Strhodes "server is up and running", 6855193149Sdougb ns_g_version, ob, alt, cb, 6856193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 6857193149Sdougb ns_g_cpus_detected, ns_g_cpus, 6858193149Sdougb#endif 6859135446Strhodes zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 6860135446Strhodes soaqueries, server->log_queries ? "ON" : "OFF", 6861170222Sdougb server->recursionquota.used, server->recursionquota.soft, 6862170222Sdougb server->recursionquota.max, 6863135446Strhodes server->tcpquota.used, server->tcpquota.max); 6864135446Strhodes if (n >= isc_buffer_availablelength(text)) 6865135446Strhodes return (ISC_R_NOSPACE); 6866135446Strhodes isc_buffer_add(text, n); 6867135446Strhodes return (ISC_R_SUCCESS); 6868135446Strhodes} 6869135446Strhodes 6870193149Sdougbstatic isc_result_t 6871193149Sdougbdelete_keynames(dns_tsig_keyring_t *ring, char *target, 6872193149Sdougb unsigned int *foundkeys) 6873193149Sdougb{ 6874193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 6875193149Sdougb isc_result_t result; 6876193149Sdougb dns_rbtnodechain_t chain; 6877193149Sdougb dns_name_t foundname; 6878193149Sdougb dns_fixedname_t fixedorigin; 6879193149Sdougb dns_name_t *origin; 6880193149Sdougb dns_rbtnode_t *node; 6881193149Sdougb dns_tsigkey_t *tkey; 6882193149Sdougb 6883193149Sdougb dns_name_init(&foundname, NULL); 6884193149Sdougb dns_fixedname_init(&fixedorigin); 6885193149Sdougb origin = dns_fixedname_name(&fixedorigin); 6886193149Sdougb 6887193149Sdougb again: 6888193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 6889193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 6890193149Sdougb origin); 6891193149Sdougb if (result == ISC_R_NOTFOUND) { 6892193149Sdougb dns_rbtnodechain_invalidate(&chain); 6893193149Sdougb return (ISC_R_SUCCESS); 6894193149Sdougb } 6895193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 6896193149Sdougb dns_rbtnodechain_invalidate(&chain); 6897193149Sdougb return (result); 6898193149Sdougb } 6899193149Sdougb 6900193149Sdougb for (;;) { 6901193149Sdougb node = NULL; 6902193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 6903193149Sdougb tkey = node->data; 6904193149Sdougb 6905193149Sdougb if (tkey != NULL) { 6906193149Sdougb if (!tkey->generated) 6907193149Sdougb goto nextkey; 6908193149Sdougb 6909193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 6910193149Sdougb if (strcmp(namestr, target) == 0) { 6911193149Sdougb (*foundkeys)++; 6912193149Sdougb dns_rbtnodechain_invalidate(&chain); 6913193149Sdougb (void)dns_rbt_deletename(ring->keys, 6914193149Sdougb &tkey->name, 6915193149Sdougb ISC_FALSE); 6916193149Sdougb goto again; 6917193149Sdougb } 6918193149Sdougb } 6919193149Sdougb 6920193149Sdougb nextkey: 6921193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 6922193149Sdougb if (result == ISC_R_NOMORE) 6923193149Sdougb break; 6924193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 6925193149Sdougb dns_rbtnodechain_invalidate(&chain); 6926193149Sdougb return (result); 6927193149Sdougb } 6928193149Sdougb } 6929193149Sdougb 6930193149Sdougb return (ISC_R_SUCCESS); 6931193149Sdougb} 6932193149Sdougb 6933193149Sdougbisc_result_t 6934193149Sdougbns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) { 6935193149Sdougb isc_result_t result; 6936193149Sdougb unsigned int n; 6937193149Sdougb dns_view_t *view; 6938193149Sdougb unsigned int foundkeys = 0; 6939193149Sdougb char *target; 6940193149Sdougb char *viewname; 6941193149Sdougb 6942193149Sdougb (void)next_token(&command, " \t"); /* skip command name */ 6943193149Sdougb target = next_token(&command, " \t"); 6944193149Sdougb if (target == NULL) 6945193149Sdougb return (ISC_R_UNEXPECTEDEND); 6946193149Sdougb viewname = next_token(&command, " \t"); 6947193149Sdougb 6948193149Sdougb result = isc_task_beginexclusive(server->task); 6949193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 6950193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6951193149Sdougb view != NULL; 6952193149Sdougb view = ISC_LIST_NEXT(view, link)) { 6953193149Sdougb if (viewname == NULL || strcmp(view->name, viewname) == 0) { 6954193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); 6955193149Sdougb result = delete_keynames(view->dynamickeys, target, 6956193149Sdougb &foundkeys); 6957193149Sdougb RWUNLOCK(&view->dynamickeys->lock, 6958193149Sdougb isc_rwlocktype_write); 6959193149Sdougb if (result != ISC_R_SUCCESS) { 6960193149Sdougb isc_task_endexclusive(server->task); 6961193149Sdougb return (result); 6962193149Sdougb } 6963193149Sdougb } 6964193149Sdougb } 6965193149Sdougb isc_task_endexclusive(server->task); 6966193149Sdougb 6967193149Sdougb n = snprintf((char *)isc_buffer_used(text), 6968193149Sdougb isc_buffer_availablelength(text), 6969193149Sdougb "%d tsig keys deleted.\n", foundkeys); 6970218384Sdougb if (n >= isc_buffer_availablelength(text)) 6971193149Sdougb return (ISC_R_NOSPACE); 6972193149Sdougb isc_buffer_add(text, n); 6973193149Sdougb 6974193149Sdougb return (ISC_R_SUCCESS); 6975193149Sdougb} 6976193149Sdougb 6977193149Sdougbstatic isc_result_t 6978193149Sdougblist_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text, 6979193149Sdougb unsigned int *foundkeys) 6980193149Sdougb{ 6981193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 6982193149Sdougb char creatorstr[DNS_NAME_FORMATSIZE]; 6983193149Sdougb isc_result_t result; 6984193149Sdougb dns_rbtnodechain_t chain; 6985193149Sdougb dns_name_t foundname; 6986193149Sdougb dns_fixedname_t fixedorigin; 6987193149Sdougb dns_name_t *origin; 6988193149Sdougb dns_rbtnode_t *node; 6989193149Sdougb dns_tsigkey_t *tkey; 6990193149Sdougb unsigned int n; 6991193149Sdougb const char *viewname; 6992193149Sdougb 6993193149Sdougb if (view != NULL) 6994193149Sdougb viewname = view->name; 6995193149Sdougb else 6996193149Sdougb viewname = "(global)"; 6997193149Sdougb 6998193149Sdougb dns_name_init(&foundname, NULL); 6999193149Sdougb dns_fixedname_init(&fixedorigin); 7000193149Sdougb origin = dns_fixedname_name(&fixedorigin); 7001193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 7002193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 7003193149Sdougb origin); 7004193149Sdougb if (result == ISC_R_NOTFOUND) { 7005193149Sdougb dns_rbtnodechain_invalidate(&chain); 7006193149Sdougb return (ISC_R_SUCCESS); 7007193149Sdougb } 7008193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7009193149Sdougb dns_rbtnodechain_invalidate(&chain); 7010193149Sdougb return (result); 7011193149Sdougb } 7012193149Sdougb 7013193149Sdougb for (;;) { 7014193149Sdougb node = NULL; 7015193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 7016193149Sdougb tkey = node->data; 7017193149Sdougb 7018193149Sdougb if (tkey != NULL) { 7019193149Sdougb (*foundkeys)++; 7020193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 7021193149Sdougb if (tkey->generated) { 7022193149Sdougb dns_name_format(tkey->creator, creatorstr, 7023193149Sdougb sizeof(creatorstr)); 7024193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7025193149Sdougb isc_buffer_availablelength(text), 7026193149Sdougb "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n", 7027193149Sdougb viewname, namestr, creatorstr); 7028193149Sdougb } else { 7029193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7030193149Sdougb isc_buffer_availablelength(text), 7031193149Sdougb "view \"%s\"; type \"static\"; key \"%s\";\n", 7032193149Sdougb viewname, namestr); 7033193149Sdougb } 7034193149Sdougb if (n >= isc_buffer_availablelength(text)) { 7035193149Sdougb dns_rbtnodechain_invalidate(&chain); 7036193149Sdougb return (ISC_R_NOSPACE); 7037193149Sdougb } 7038193149Sdougb isc_buffer_add(text, n); 7039193149Sdougb } 7040193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 7041193149Sdougb if (result == ISC_R_NOMORE) 7042193149Sdougb break; 7043193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7044193149Sdougb dns_rbtnodechain_invalidate(&chain); 7045193149Sdougb return (result); 7046193149Sdougb } 7047193149Sdougb } 7048193149Sdougb 7049193149Sdougb return (ISC_R_SUCCESS); 7050193149Sdougb} 7051193149Sdougb 7052193149Sdougbisc_result_t 7053193149Sdougbns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { 7054193149Sdougb isc_result_t result; 7055193149Sdougb unsigned int n; 7056193149Sdougb dns_view_t *view; 7057193149Sdougb unsigned int foundkeys = 0; 7058193149Sdougb 7059193149Sdougb result = isc_task_beginexclusive(server->task); 7060193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7061193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7062193149Sdougb view != NULL; 7063193149Sdougb view = ISC_LIST_NEXT(view, link)) { 7064193149Sdougb RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7065193149Sdougb result = list_keynames(view, view->statickeys, text, 7066193149Sdougb &foundkeys); 7067193149Sdougb RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7068193149Sdougb if (result != ISC_R_SUCCESS) { 7069193149Sdougb isc_task_endexclusive(server->task); 7070193149Sdougb return (result); 7071193149Sdougb } 7072193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7073193149Sdougb result = list_keynames(view, view->dynamickeys, text, 7074193149Sdougb &foundkeys); 7075193149Sdougb RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7076193149Sdougb if (result != ISC_R_SUCCESS) { 7077193149Sdougb isc_task_endexclusive(server->task); 7078193149Sdougb return (result); 7079193149Sdougb } 7080193149Sdougb } 7081193149Sdougb isc_task_endexclusive(server->task); 7082193149Sdougb 7083193149Sdougb if (foundkeys == 0) { 7084193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7085193149Sdougb isc_buffer_availablelength(text), 7086193149Sdougb "no tsig keys found.\n"); 7087218384Sdougb if (n >= isc_buffer_availablelength(text)) 7088193149Sdougb return (ISC_R_NOSPACE); 7089193149Sdougb isc_buffer_add(text, n); 7090193149Sdougb } 7091193149Sdougb 7092193149Sdougb return (ISC_R_SUCCESS); 7093193149Sdougb} 7094193149Sdougb 7095135446Strhodes/* 7096224092Sdougb * Act on a "sign" or "loadkeys" command from the command channel. 7097224092Sdougb */ 7098224092Sdougbisc_result_t 7099224092Sdougbns_server_rekey(ns_server_t *server, char *args) { 7100224092Sdougb isc_result_t result; 7101224092Sdougb dns_zone_t *zone = NULL; 7102224092Sdougb dns_zonetype_t type; 7103224092Sdougb isc_uint16_t keyopts; 7104224092Sdougb isc_boolean_t fullsign = ISC_FALSE; 7105224092Sdougb 7106224092Sdougb if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0) 7107224092Sdougb fullsign = ISC_TRUE; 7108224092Sdougb 7109224092Sdougb result = zone_from_args(server, args, &zone, NULL); 7110224092Sdougb if (result != ISC_R_SUCCESS) 7111224092Sdougb return (result); 7112224092Sdougb if (zone == NULL) 7113224092Sdougb return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */ 7114224092Sdougb 7115224092Sdougb type = dns_zone_gettype(zone); 7116224092Sdougb if (type != dns_zone_master) { 7117224092Sdougb dns_zone_detach(&zone); 7118224092Sdougb return (DNS_R_NOTMASTER); 7119224092Sdougb } 7120224092Sdougb 7121224092Sdougb keyopts = dns_zone_getkeyopts(zone); 7122224092Sdougb 7123224092Sdougb /* "rndc loadkeys" requires "auto-dnssec maintain". */ 7124224092Sdougb if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) 7125224092Sdougb result = ISC_R_NOPERM; 7126224092Sdougb else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) 7127224092Sdougb result = ISC_R_NOPERM; 7128224092Sdougb else 7129224092Sdougb dns_zone_rekey(zone, fullsign); 7130224092Sdougb 7131224092Sdougb dns_zone_detach(&zone); 7132224092Sdougb return (result); 7133224092Sdougb} 7134224092Sdougb 7135224092Sdougb/* 7136170222Sdougb * Act on a "freeze" or "thaw" command from the command channel. 7137135446Strhodes */ 7138135446Strhodesisc_result_t 7139204619Sdougbns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, 7140204619Sdougb isc_buffer_t *text) 7141204619Sdougb{ 7142170222Sdougb isc_result_t result, tresult; 7143135446Strhodes dns_zone_t *zone = NULL; 7144135446Strhodes dns_zonetype_t type; 7145135446Strhodes char classstr[DNS_RDATACLASS_FORMATSIZE]; 7146135446Strhodes char zonename[DNS_NAME_FORMATSIZE]; 7147135446Strhodes dns_view_t *view; 7148135446Strhodes char *journal; 7149135446Strhodes const char *vname, *sep; 7150135446Strhodes isc_boolean_t frozen; 7151204619Sdougb const char *msg = NULL; 7152186462Sdougb 7153224092Sdougb result = zone_from_args(server, args, &zone, NULL); 7154135446Strhodes if (result != ISC_R_SUCCESS) 7155135446Strhodes return (result); 7156170222Sdougb if (zone == NULL) { 7157170222Sdougb result = isc_task_beginexclusive(server->task); 7158170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7159170222Sdougb tresult = ISC_R_SUCCESS; 7160186462Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7161170222Sdougb view != NULL; 7162170222Sdougb view = ISC_LIST_NEXT(view, link)) { 7163170222Sdougb result = dns_view_freezezones(view, freeze); 7164170222Sdougb if (result != ISC_R_SUCCESS && 7165170222Sdougb tresult == ISC_R_SUCCESS) 7166170222Sdougb tresult = result; 7167170222Sdougb } 7168170222Sdougb isc_task_endexclusive(server->task); 7169170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7170170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7171170222Sdougb "%s all zones: %s", 7172170222Sdougb freeze ? "freezing" : "thawing", 7173170222Sdougb isc_result_totext(tresult)); 7174170222Sdougb return (tresult); 7175170222Sdougb } 7176135446Strhodes type = dns_zone_gettype(zone); 7177135446Strhodes if (type != dns_zone_master) { 7178135446Strhodes dns_zone_detach(&zone); 7179224092Sdougb return (DNS_R_NOTMASTER); 7180135446Strhodes } 7181135446Strhodes 7182204619Sdougb result = isc_task_beginexclusive(server->task); 7183204619Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7184135446Strhodes frozen = dns_zone_getupdatedisabled(zone); 7185135446Strhodes if (freeze) { 7186204619Sdougb if (frozen) { 7187204619Sdougb msg = "WARNING: The zone was already frozen.\n" 7188204619Sdougb "Someone else may be editing it or " 7189204619Sdougb "it may still be re-loading."; 7190135446Strhodes result = DNS_R_FROZEN; 7191204619Sdougb } 7192204619Sdougb if (result == ISC_R_SUCCESS) { 7193135446Strhodes result = dns_zone_flush(zone); 7194204619Sdougb if (result != ISC_R_SUCCESS) 7195204619Sdougb msg = "Flushing the zone updates to " 7196204619Sdougb "disk failed."; 7197204619Sdougb } 7198135446Strhodes if (result == ISC_R_SUCCESS) { 7199135446Strhodes journal = dns_zone_getjournal(zone); 7200135446Strhodes if (journal != NULL) 7201135446Strhodes (void)isc_file_remove(journal); 7202135446Strhodes } 7203204619Sdougb if (result == ISC_R_SUCCESS) 7204204619Sdougb dns_zone_setupdatedisabled(zone, freeze); 7205135446Strhodes } else { 7206135446Strhodes if (frozen) { 7207204619Sdougb result = dns_zone_loadandthaw(zone); 7208204619Sdougb switch (result) { 7209204619Sdougb case ISC_R_SUCCESS: 7210204619Sdougb case DNS_R_UPTODATE: 7211204619Sdougb msg = "The zone reload and thaw was " 7212204619Sdougb "successful."; 7213135446Strhodes result = ISC_R_SUCCESS; 7214204619Sdougb break; 7215204619Sdougb case DNS_R_CONTINUE: 7216204619Sdougb msg = "A zone reload and thaw was started.\n" 7217204619Sdougb "Check the logs to see the result."; 7218204619Sdougb result = ISC_R_SUCCESS; 7219204619Sdougb break; 7220204619Sdougb } 7221135446Strhodes } 7222135446Strhodes } 7223204619Sdougb isc_task_endexclusive(server->task); 7224135446Strhodes 7225204619Sdougb if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 7226204619Sdougb isc_buffer_putmem(text, (const unsigned char *)msg, 7227204619Sdougb strlen(msg) + 1); 7228204619Sdougb 7229135446Strhodes view = dns_zone_getview(zone); 7230224092Sdougb if (strcmp(view->name, "_default") == 0 || 7231224092Sdougb strcmp(view->name, "_bind") == 0) 7232135446Strhodes { 7233135446Strhodes vname = ""; 7234135446Strhodes sep = ""; 7235135446Strhodes } else { 7236135446Strhodes vname = view->name; 7237135446Strhodes sep = " "; 7238135446Strhodes } 7239135446Strhodes dns_rdataclass_format(dns_zone_getclass(zone), classstr, 7240135446Strhodes sizeof(classstr)); 7241135446Strhodes dns_name_format(dns_zone_getorigin(zone), 7242135446Strhodes zonename, sizeof(zonename)); 7243135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7244135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7245135446Strhodes "%s zone '%s/%s'%s%s: %s", 7246170222Sdougb freeze ? "freezing" : "thawing", 7247135446Strhodes zonename, classstr, sep, vname, 7248135446Strhodes isc_result_totext(result)); 7249135446Strhodes dns_zone_detach(&zone); 7250135446Strhodes return (result); 7251135446Strhodes} 7252153816Sdougb 7253153816Sdougb#ifdef HAVE_LIBSCF 7254153816Sdougb/* 7255153816Sdougb * This function adds a message for rndc to echo if named 7256153816Sdougb * is managed by smf and is also running chroot. 7257153816Sdougb */ 7258153816Sdougbisc_result_t 7259153816Sdougbns_smf_add_message(isc_buffer_t *text) { 7260153816Sdougb unsigned int n; 7261153816Sdougb 7262153816Sdougb n = snprintf((char *)isc_buffer_used(text), 7263153816Sdougb isc_buffer_availablelength(text), 7264153816Sdougb "use svcadm(1M) to manage named"); 7265153816Sdougb if (n >= isc_buffer_availablelength(text)) 7266153816Sdougb return (ISC_R_NOSPACE); 7267153816Sdougb isc_buffer_add(text, n); 7268153816Sdougb return (ISC_R_SUCCESS); 7269153816Sdougb} 7270153816Sdougb#endif /* HAVE_LIBSCF */ 7271224092Sdougb 7272224092Sdougb/* 7273224092Sdougb * Act on an "addzone" command from the command channel. 7274224092Sdougb */ 7275224092Sdougbisc_result_t 7276224092Sdougbns_server_add_zone(ns_server_t *server, char *args) { 7277224092Sdougb isc_result_t result; 7278224092Sdougb isc_buffer_t argbuf; 7279224092Sdougb size_t arglen; 7280224092Sdougb cfg_parser_t *parser = NULL; 7281224092Sdougb cfg_obj_t *config = NULL; 7282224092Sdougb const cfg_obj_t *vconfig = NULL; 7283224092Sdougb const cfg_obj_t *views = NULL; 7284224092Sdougb const cfg_obj_t *parms = NULL; 7285224092Sdougb const cfg_obj_t *obj = NULL; 7286224092Sdougb const cfg_listelt_t *element; 7287224092Sdougb const char *zonename; 7288224092Sdougb const char *classname = NULL; 7289224092Sdougb const char *argp; 7290224092Sdougb const char *viewname = NULL; 7291224092Sdougb dns_rdataclass_t rdclass; 7292224092Sdougb dns_view_t *view = 0; 7293224092Sdougb isc_buffer_t buf, *nbuf = NULL; 7294224092Sdougb dns_name_t dnsname; 7295224092Sdougb dns_zone_t *zone = NULL; 7296224092Sdougb FILE *fp = NULL; 7297224092Sdougb struct cfg_context *cfg = NULL; 7298224092Sdougb 7299224092Sdougb /* Try to parse the argument string */ 7300224092Sdougb arglen = strlen(args); 7301224092Sdougb isc_buffer_init(&argbuf, args, arglen); 7302224092Sdougb isc_buffer_add(&argbuf, strlen(args)); 7303224092Sdougb CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); 7304224092Sdougb CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, 7305224092Sdougb &config)); 7306224092Sdougb CHECK(cfg_map_get(config, "addzone", &parms)); 7307224092Sdougb 7308224092Sdougb zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name")); 7309224092Sdougb isc_buffer_init(&buf, zonename, strlen(zonename)); 7310224092Sdougb isc_buffer_add(&buf, strlen(zonename)); 7311224092Sdougb dns_name_init(&dnsname, NULL); 7312224092Sdougb isc_buffer_allocate(server->mctx, &nbuf, 256); 7313224092Sdougb dns_name_setbuffer(&dnsname, nbuf); 7314224092Sdougb CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL)); 7315224092Sdougb 7316224092Sdougb /* Make sense of optional class argument */ 7317224092Sdougb obj = cfg_tuple_get(parms, "class"); 7318224092Sdougb CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass)); 7319224092Sdougb if (rdclass != dns_rdataclass_in && obj) 7320224092Sdougb classname = cfg_obj_asstring(obj); 7321224092Sdougb 7322224092Sdougb /* Make sense of optional view argument */ 7323224092Sdougb obj = cfg_tuple_get(parms, "view"); 7324224092Sdougb if (obj && cfg_obj_isstring(obj)) 7325224092Sdougb viewname = cfg_obj_asstring(obj); 7326224092Sdougb if (viewname == NULL || *viewname == '\0') 7327224092Sdougb viewname = "_default"; 7328224092Sdougb CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view)); 7329224092Sdougb 7330224092Sdougb /* Are we accepting new zones? */ 7331224092Sdougb if (view->new_zone_file == NULL) { 7332224092Sdougb result = ISC_R_NOPERM; 7333224092Sdougb goto cleanup; 7334224092Sdougb } 7335224092Sdougb 7336224092Sdougb cfg = (struct cfg_context *) view->new_zone_config; 7337224092Sdougb if (cfg == NULL) { 7338224092Sdougb result = ISC_R_FAILURE; 7339224092Sdougb goto cleanup; 7340224092Sdougb } 7341224092Sdougb 7342224092Sdougb /* Zone shouldn't already exist */ 7343224092Sdougb result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone); 7344224092Sdougb if (result == ISC_R_SUCCESS) { 7345224092Sdougb result = ISC_R_EXISTS; 7346224092Sdougb goto cleanup; 7347224092Sdougb } else if (result == DNS_R_PARTIALMATCH) { 7348224092Sdougb /* Create our sub-zone anyway */ 7349224092Sdougb dns_zone_detach(&zone); 7350224092Sdougb zone = NULL; 7351224092Sdougb } 7352224092Sdougb else if (result != ISC_R_NOTFOUND) 7353224092Sdougb goto cleanup; 7354224092Sdougb 7355224092Sdougb /* Find the view statement */ 7356224092Sdougb cfg_map_get(cfg->config, "view", &views); 7357224092Sdougb for (element = cfg_list_first(views); 7358224092Sdougb element != NULL; 7359224092Sdougb element = cfg_list_next(element)) 7360224092Sdougb { 7361224092Sdougb const char *vname; 7362224092Sdougb vconfig = cfg_listelt_value(element); 7363224092Sdougb vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 7364224092Sdougb if (vname && !strcasecmp(vname, viewname)) 7365224092Sdougb break; 7366224092Sdougb vconfig = NULL; 7367224092Sdougb } 7368224092Sdougb 7369224092Sdougb /* Open save file for write configuration */ 7370224092Sdougb CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); 7371224092Sdougb 7372224092Sdougb /* Mark view unfrozen so that zone can be added */ 7373234010Sdougb isc_task_beginexclusive(server->task); 7374224092Sdougb dns_view_thaw(view); 7375224092Sdougb result = configure_zone(cfg->config, parms, vconfig, 7376225361Sdougb server->mctx, view, cfg->actx, ISC_FALSE); 7377224092Sdougb dns_view_freeze(view); 7378234010Sdougb isc_task_endexclusive(server->task); 7379234010Sdougb if (result != ISC_R_SUCCESS) 7380224092Sdougb goto cleanup; 7381224092Sdougb 7382224092Sdougb /* Is it there yet? */ 7383224092Sdougb CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone)); 7384224092Sdougb 7385224092Sdougb /* 7386224092Sdougb * Load the zone from the master file. If this fails, we'll 7387224092Sdougb * need to undo the configuration we've done already. 7388224092Sdougb */ 7389224092Sdougb result = dns_zone_loadnew(zone); 7390224092Sdougb if (result != ISC_R_SUCCESS) { 7391224092Sdougb dns_db_t *dbp = NULL; 7392224092Sdougb 7393224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7394224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7395224092Sdougb "addzone failed; reverting."); 7396224092Sdougb 7397224092Sdougb /* If the zone loaded partially, unload it */ 7398224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 7399224092Sdougb dns_db_detach(&dbp); 7400224092Sdougb dns_zone_unload(zone); 7401224092Sdougb } 7402224092Sdougb 7403224092Sdougb /* Remove the zone from the zone table */ 7404224092Sdougb dns_zt_unmount(view->zonetable, zone); 7405224092Sdougb goto cleanup; 7406224092Sdougb } 7407224092Sdougb 7408224092Sdougb /* Flag the zone as having been added at runtime */ 7409224092Sdougb dns_zone_setadded(zone, ISC_TRUE); 7410224092Sdougb 7411224092Sdougb /* Emit just the zone name from args */ 7412224092Sdougb CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL)); 7413224092Sdougb CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL)); 7414224092Sdougb CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); 7415224092Sdougb 7416224092Sdougb /* Classname, if not default */ 7417224092Sdougb if (classname != NULL && *classname != '\0') { 7418224092Sdougb CHECK(isc_stdio_write(classname, strlen(classname), 1, fp, 7419224092Sdougb NULL)); 7420224092Sdougb CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); 7421224092Sdougb } 7422224092Sdougb 7423224092Sdougb /* Find beginning of option block from args */ 7424224092Sdougb for (argp = args; *argp; argp++, arglen--) { 7425224092Sdougb if (*argp == '{') { /* Assume matching '}' */ 7426224092Sdougb /* Add that to our file */ 7427224092Sdougb CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL)); 7428224092Sdougb 7429224092Sdougb /* Make sure we end with a LF */ 7430224092Sdougb if (argp[arglen-1] != '\n') { 7431224092Sdougb CHECK(isc_stdio_write("\n", 1, 1, fp, NULL)); 7432224092Sdougb } 7433224092Sdougb break; 7434224092Sdougb } 7435224092Sdougb } 7436224092Sdougb 7437224092Sdougb CHECK(isc_stdio_close(fp)); 7438224092Sdougb fp = NULL; 7439224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7440224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7441224092Sdougb "zone %s added to view %s via addzone", 7442224092Sdougb zonename, viewname); 7443224092Sdougb 7444224092Sdougb result = ISC_R_SUCCESS; 7445224092Sdougb 7446224092Sdougb cleanup: 7447224092Sdougb if (fp != NULL) 7448224092Sdougb isc_stdio_close(fp); 7449224092Sdougb if (parser != NULL) { 7450224092Sdougb if (config != NULL) 7451224092Sdougb cfg_obj_destroy(parser, &config); 7452224092Sdougb cfg_parser_destroy(&parser); 7453224092Sdougb } 7454224092Sdougb if (zone != NULL) 7455224092Sdougb dns_zone_detach(&zone); 7456224092Sdougb if (view != NULL) 7457224092Sdougb dns_view_detach(&view); 7458224092Sdougb if (nbuf != NULL) 7459224092Sdougb isc_buffer_free(&nbuf); 7460224092Sdougb 7461224092Sdougb return (result); 7462224092Sdougb} 7463224092Sdougb 7464224092Sdougb/* 7465224092Sdougb * Act on a "delzone" command from the command channel. 7466224092Sdougb */ 7467224092Sdougbisc_result_t 7468224092Sdougbns_server_del_zone(ns_server_t *server, char *args) { 7469224092Sdougb isc_result_t result; 7470224092Sdougb dns_zone_t *zone = NULL; 7471224092Sdougb dns_view_t *view = NULL; 7472224092Sdougb dns_db_t *dbp = NULL; 7473224092Sdougb const char *filename = NULL; 7474224092Sdougb char *tmpname = NULL; 7475224092Sdougb char buf[1024]; 7476224092Sdougb const char *zonename = NULL; 7477224092Sdougb size_t znamelen = 0; 7478224092Sdougb FILE *ifp = NULL, *ofp = NULL; 7479224092Sdougb 7480224092Sdougb /* Parse parameters */ 7481224092Sdougb CHECK(zone_from_args(server, args, &zone, &zonename)); 7482224092Sdougb if (result != ISC_R_SUCCESS) 7483224092Sdougb return (result); 7484224092Sdougb if (zone == NULL) { 7485224092Sdougb result = ISC_R_UNEXPECTEDEND; 7486224092Sdougb goto cleanup; 7487224092Sdougb } 7488224092Sdougb 7489224092Sdougb /* 7490224092Sdougb * Was this zone originally added at runtime? 7491224092Sdougb * If not, we can't delete it now. 7492224092Sdougb */ 7493224092Sdougb if (!dns_zone_getadded(zone)) { 7494224092Sdougb result = ISC_R_NOPERM; 7495224092Sdougb goto cleanup; 7496224092Sdougb } 7497224092Sdougb 7498224092Sdougb if (zonename != NULL) 7499224092Sdougb znamelen = strlen(zonename); 7500224092Sdougb 7501224092Sdougb /* Dig out configuration for this zone */ 7502224092Sdougb view = dns_zone_getview(zone); 7503224092Sdougb filename = view->new_zone_file; 7504224092Sdougb if (filename == NULL) { 7505224092Sdougb /* No adding zones in this view */ 7506224092Sdougb result = ISC_R_FAILURE; 7507224092Sdougb goto cleanup; 7508224092Sdougb } 7509224092Sdougb 7510224092Sdougb /* Rewrite zone list */ 7511224092Sdougb result = isc_stdio_open(filename, "r", &ifp); 7512224092Sdougb if (ifp != NULL && result == ISC_R_SUCCESS) { 7513224092Sdougb char *found = NULL, *p = NULL; 7514224092Sdougb size_t n; 7515224092Sdougb 7516224092Sdougb /* Create a temporary file */ 7517224092Sdougb CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename, 7518224092Sdougb (long)getpid())); 7519224092Sdougb if (!(tmpname = isc_mem_strdup(server->mctx, buf))) { 7520224092Sdougb result = ISC_R_NOMEMORY; 7521224092Sdougb goto cleanup; 7522224092Sdougb } 7523224092Sdougb CHECK(isc_stdio_open(tmpname, "w", &ofp)); 7524224092Sdougb 7525224092Sdougb /* Look for the entry for that zone */ 7526224092Sdougb while (fgets(buf, 1024, ifp)) { 7527224092Sdougb /* A 'zone' line */ 7528224092Sdougb if (strncasecmp(buf, "zone", 4)) { 7529224092Sdougb fputs(buf, ofp); 7530224092Sdougb continue; 7531224092Sdougb } 7532224092Sdougb p = buf+4; 7533224092Sdougb 7534224092Sdougb /* Locate a name */ 7535224092Sdougb while (*p && 7536224092Sdougb ((*p == '"') || isspace((unsigned char)*p))) 7537224092Sdougb p++; 7538224092Sdougb 7539224092Sdougb /* Is that the zone we're looking for */ 7540224092Sdougb if (strncasecmp(p, zonename, znamelen)) { 7541224092Sdougb fputs(buf, ofp); 7542224092Sdougb continue; 7543224092Sdougb } 7544224092Sdougb 7545224092Sdougb /* And nothing else? */ 7546224092Sdougb p += znamelen; 7547224092Sdougb if (isspace((unsigned char)*p) || 7548224092Sdougb *p == '"' || *p == '{') { 7549224092Sdougb /* This must be the entry */ 7550224092Sdougb found = p; 7551224092Sdougb break; 7552224092Sdougb } 7553224092Sdougb 7554224092Sdougb /* Spit it out, keep looking */ 7555224092Sdougb fputs(buf, ofp); 7556224092Sdougb } 7557224092Sdougb 7558224092Sdougb /* Skip over an option block (matching # of braces) */ 7559224092Sdougb if (found) { 7560224092Sdougb int obrace = 0, cbrace = 0; 7561224092Sdougb for (;;) { 7562224092Sdougb while (*p) { 7563224092Sdougb if (*p == '{') obrace++; 7564224092Sdougb if (*p == '}') cbrace++; 7565224092Sdougb p++; 7566224092Sdougb } 7567224092Sdougb if (obrace && (obrace == cbrace)) 7568224092Sdougb break; 7569224092Sdougb if (!fgets(buf, 1024, ifp)) 7570224092Sdougb break; 7571224092Sdougb p = buf; 7572224092Sdougb } 7573224092Sdougb 7574224092Sdougb /* Just spool the remainder of the file out */ 7575224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 7576224092Sdougb while (n > 0U) { 7577224092Sdougb if (result == ISC_R_EOF) 7578224092Sdougb result = ISC_R_SUCCESS; 7579224092Sdougb CHECK(result); 7580224092Sdougb isc_stdio_write(buf, 1, n, ofp, NULL); 7581224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 7582224092Sdougb } 7583224092Sdougb 7584224092Sdougb /* Move temporary into place */ 7585224092Sdougb CHECK(isc_file_rename(tmpname, view->new_zone_file)); 7586224092Sdougb } else { 7587224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7588224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 7589224092Sdougb "deleted zone %s was missing from " 7590224092Sdougb "new zone file", zonename); 7591224092Sdougb goto cleanup; 7592224092Sdougb } 7593224092Sdougb } 7594224092Sdougb 7595224092Sdougb /* Stop answering for this zone */ 7596224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 7597224092Sdougb dns_db_detach(&dbp); 7598224092Sdougb dns_zone_unload(zone); 7599224092Sdougb } 7600224092Sdougb 7601224092Sdougb CHECK(dns_zt_unmount(view->zonetable, zone)); 7602224092Sdougb 7603224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7604224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7605224092Sdougb "zone %s removed via delzone", zonename); 7606224092Sdougb 7607224092Sdougb result = ISC_R_SUCCESS; 7608224092Sdougb 7609224092Sdougb cleanup: 7610224092Sdougb if (ifp != NULL) 7611224092Sdougb isc_stdio_close(ifp); 7612224092Sdougb if (ofp != NULL) { 7613224092Sdougb isc_stdio_close(ofp); 7614224092Sdougb isc_file_remove(tmpname); 7615224092Sdougb } 7616224092Sdougb if (tmpname != NULL) 7617224092Sdougb isc_mem_free(server->mctx, tmpname); 7618224092Sdougb if (zone != NULL) 7619224092Sdougb dns_zone_detach(&zone); 7620224092Sdougb 7621224092Sdougb return (result); 7622224092Sdougb} 7623224092Sdougb 7624224092Sdougbstatic void 7625225361Sdougbnewzone_cfgctx_destroy(void **cfgp) { 7626224092Sdougb struct cfg_context *cfg; 7627224092Sdougb 7628224092Sdougb REQUIRE(cfgp != NULL && *cfgp != NULL); 7629225361Sdougb 7630224092Sdougb cfg = *cfgp; 7631224092Sdougb 7632225361Sdougb if (cfg->actx != NULL) 7633225361Sdougb cfg_aclconfctx_detach(&cfg->actx); 7634225361Sdougb 7635224092Sdougb if (cfg->parser != NULL) { 7636224092Sdougb if (cfg->config != NULL) 7637224092Sdougb cfg_obj_destroy(cfg->parser, &cfg->config); 7638224092Sdougb cfg_parser_destroy(&cfg->parser); 7639224092Sdougb } 7640225361Sdougb if (cfg->nzparser != NULL) { 7641225361Sdougb if (cfg->nzconfig != NULL) 7642225361Sdougb cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig); 7643225361Sdougb cfg_parser_destroy(&cfg->nzparser); 7644225361Sdougb } 7645224092Sdougb 7646225361Sdougb isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg)); 7647224092Sdougb *cfgp = NULL; 7648224092Sdougb} 7649