server.c revision 245163
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.")]; 1361236374Sdougb const char *dns64_dbtype[4] = { "_dns64", "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 1433245163Serwinconfigure_rpz(dns_view_t *view, const cfg_listelt_t *element, 1434245163Serwin isc_boolean_t recursive_only_def, dns_ttl_t ttl_def) 1435245163Serwin{ 1436245163Serwin const cfg_obj_t *rpz_obj, *policy_obj, *obj; 1437224092Sdougb const char *str; 1438224092Sdougb dns_rpz_zone_t *old, *new; 1439224092Sdougb dns_zone_t *zone = NULL; 1440224092Sdougb isc_result_t result; 1441224092Sdougb 1442224092Sdougb new = isc_mem_get(view->mctx, sizeof(*new)); 1443224092Sdougb if (new == NULL) { 1444224092Sdougb result = ISC_R_NOMEMORY; 1445224092Sdougb goto cleanup; 1446224092Sdougb } 1447224092Sdougb 1448224092Sdougb memset(new, 0, sizeof(*new)); 1449245163Serwin dns_name_init(&new->origin, NULL); 1450224092Sdougb dns_name_init(&new->nsdname, NULL); 1451224092Sdougb dns_name_init(&new->cname, NULL); 1452245163Serwin dns_name_init(&new->passthru, 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 { 1460245163Serwin str = cfg_obj_asstring(cfg_tuple_get(policy_obj, 1461245163Serwin "policy name")); 1462224092Sdougb new->policy = dns_rpz_str2policy(str); 1463224092Sdougb INSIST(new->policy != DNS_RPZ_POLICY_ERROR); 1464224092Sdougb } 1465224092Sdougb 1466245163Serwin obj = cfg_tuple_get(rpz_obj, "recursive-only"); 1467245163Serwin if (cfg_obj_isvoid(obj)) { 1468245163Serwin new->recursive_only = recursive_only_def; 1469245163Serwin } else { 1470245163Serwin new->recursive_only = cfg_obj_asboolean(obj); 1471245163Serwin } 1472245163Serwin if (!new->recursive_only) 1473245163Serwin view->rpz_recursive_only = ISC_FALSE; 1474245163Serwin 1475245163Serwin obj = cfg_tuple_get(rpz_obj, "max-policy-ttl"); 1476245163Serwin if (cfg_obj_isuint32(obj)) { 1477245163Serwin new->max_policy_ttl = cfg_obj_asuint32(obj); 1478245163Serwin } else { 1479245163Serwin new->max_policy_ttl = ttl_def; 1480245163Serwin } 1481245163Serwin 1482245163Serwin str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name")); 1483245163Serwin result = dns_name_fromstring(&new->origin, str, DNS_NAME_DOWNCASE, 1484245163Serwin view->mctx); 1485224092Sdougb if (result != ISC_R_SUCCESS) { 1486224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1487224092Sdougb "invalid zone '%s'", str); 1488224092Sdougb goto cleanup; 1489224092Sdougb } 1490224092Sdougb 1491224092Sdougb result = dns_name_fromstring2(&new->nsdname, DNS_RPZ_NSDNAME_ZONE, 1492245163Serwin &new->origin, DNS_NAME_DOWNCASE, 1493245163Serwin view->mctx); 1494224092Sdougb if (result != ISC_R_SUCCESS) { 1495224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1496224092Sdougb "invalid zone '%s'", str); 1497224092Sdougb goto cleanup; 1498224092Sdougb } 1499224092Sdougb 1500245163Serwin result = dns_name_fromstring(&new->passthru, DNS_RPZ_PASSTHRU_ZONE, 1501245163Serwin DNS_NAME_DOWNCASE, view->mctx); 1502245163Serwin if (result != ISC_R_SUCCESS) { 1503245163Serwin cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1504245163Serwin "invalid zone '%s'", str); 1505245163Serwin goto cleanup; 1506245163Serwin } 1507224092Sdougb 1508224092Sdougb result = dns_view_findzone(view, &new->origin, &zone); 1509224092Sdougb if (result != ISC_R_SUCCESS) { 1510224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1511224092Sdougb "unknown zone '%s'", str); 1512224092Sdougb goto cleanup; 1513224092Sdougb } 1514224092Sdougb if (dns_zone_gettype(zone) != dns_zone_master && 1515224092Sdougb dns_zone_gettype(zone) != dns_zone_slave) { 1516224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1517224092Sdougb "zone '%s' is neither master nor slave", str); 1518224092Sdougb dns_zone_detach(&zone); 1519224092Sdougb result = DNS_R_NOTMASTER; 1520224092Sdougb goto cleanup; 1521224092Sdougb } 1522224092Sdougb dns_zone_detach(&zone); 1523224092Sdougb 1524224092Sdougb for (old = ISC_LIST_HEAD(view->rpz_zones); 1525224092Sdougb old != new; 1526224092Sdougb old = ISC_LIST_NEXT(old, link)) { 1527224092Sdougb ++new->num; 1528224092Sdougb if (dns_name_equal(&old->origin, &new->origin)) { 1529224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1530224092Sdougb "duplicate '%s'", str); 1531224092Sdougb result = DNS_R_DUPLICATE; 1532224092Sdougb goto cleanup; 1533224092Sdougb } 1534224092Sdougb } 1535224092Sdougb 1536224092Sdougb if (new->policy == DNS_RPZ_POLICY_CNAME) { 1537245163Serwin str = cfg_obj_asstring(cfg_tuple_get(policy_obj, "cname")); 1538245163Serwin result = dns_name_fromstring(&new->cname, str, 1539245163Serwin DNS_NAME_DOWNCASE, view->mctx); 1540224092Sdougb if (result != ISC_R_SUCCESS) { 1541224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1542224092Sdougb "invalid cname '%s'", str); 1543224092Sdougb goto cleanup; 1544224092Sdougb } 1545224092Sdougb } 1546224092Sdougb 1547224092Sdougb return (ISC_R_SUCCESS); 1548224092Sdougb 1549224092Sdougb cleanup: 1550224092Sdougb dns_rpz_view_destroy(view); 1551224092Sdougb return (result); 1552224092Sdougb} 1553224092Sdougb 1554224092Sdougb/* 1555135446Strhodes * Configure 'view' according to 'vconfig', taking defaults from 'config' 1556135446Strhodes * where values are missing in 'vconfig'. 1557135446Strhodes * 1558135446Strhodes * When configuring the default view, 'vconfig' will be NULL and the 1559135446Strhodes * global defaults in 'config' used exclusively. 1560135446Strhodes */ 1561135446Strhodesstatic isc_result_t 1562225361Sdougbconfigure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 1563224092Sdougb ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys, 1564224092Sdougb isc_mem_t *mctx, cfg_aclconfctx_t *actx, 1565224092Sdougb isc_boolean_t need_hints) 1566135446Strhodes{ 1567165071Sdougb const cfg_obj_t *maps[4]; 1568165071Sdougb const cfg_obj_t *cfgmaps[3]; 1569224092Sdougb const cfg_obj_t *optionmaps[3]; 1570165071Sdougb const cfg_obj_t *options = NULL; 1571165071Sdougb const cfg_obj_t *voptions = NULL; 1572165071Sdougb const cfg_obj_t *forwardtype; 1573165071Sdougb const cfg_obj_t *forwarders; 1574165071Sdougb const cfg_obj_t *alternates; 1575165071Sdougb const cfg_obj_t *zonelist; 1576186462Sdougb const cfg_obj_t *dlz; 1577186462Sdougb unsigned int dlzargc; 1578186462Sdougb char **dlzargv; 1579165071Sdougb const cfg_obj_t *disabled; 1580165071Sdougb const cfg_obj_t *obj; 1581165071Sdougb const cfg_listelt_t *element; 1582135446Strhodes in_port_t port; 1583135446Strhodes dns_cache_t *cache = NULL; 1584135446Strhodes isc_result_t result; 1585135446Strhodes isc_uint32_t max_adb_size; 1586224092Sdougb unsigned int cleaning_interval; 1587135446Strhodes isc_uint32_t max_cache_size; 1588170222Sdougb isc_uint32_t max_acache_size; 1589135446Strhodes isc_uint32_t lame_ttl; 1590224092Sdougb dns_tsig_keyring_t *ring = NULL; 1591135446Strhodes dns_view_t *pview = NULL; /* Production view */ 1592225361Sdougb isc_mem_t *cmctx = NULL, *hmctx = NULL; 1593135446Strhodes dns_dispatch_t *dispatch4 = NULL; 1594135446Strhodes dns_dispatch_t *dispatch6 = NULL; 1595135446Strhodes isc_boolean_t reused_cache = ISC_FALSE; 1596224092Sdougb isc_boolean_t shared_cache = ISC_FALSE; 1597224092Sdougb int i = 0, j = 0, k = 0; 1598135446Strhodes const char *str; 1599224092Sdougb const char *cachename = NULL; 1600135446Strhodes dns_order_t *order = NULL; 1601135446Strhodes isc_uint32_t udpsize; 1602193149Sdougb unsigned int resopts = 0; 1603170222Sdougb dns_zone_t *zone = NULL; 1604170222Sdougb isc_uint32_t max_clients_per_query; 1605170222Sdougb const char *sep = ": view "; 1606170222Sdougb const char *viewname = view->name; 1607170222Sdougb const char *forview = " for view "; 1608170222Sdougb isc_boolean_t rfc1918; 1609170222Sdougb isc_boolean_t empty_zones_enable; 1610170222Sdougb const cfg_obj_t *disablelist = NULL; 1611193149Sdougb isc_stats_t *resstats = NULL; 1612193149Sdougb dns_stats_t *resquerystats = NULL; 1613224092Sdougb isc_boolean_t auto_dlv = ISC_FALSE; 1614224092Sdougb isc_boolean_t auto_root = ISC_FALSE; 1615224092Sdougb ns_cache_t *nsc; 1616193149Sdougb isc_boolean_t zero_no_soattl; 1617224092Sdougb dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; 1618224092Sdougb unsigned int query_timeout; 1619225361Sdougb struct cfg_context *nzctx; 1620135446Strhodes 1621135446Strhodes REQUIRE(DNS_VIEW_VALID(view)); 1622135446Strhodes 1623135446Strhodes if (config != NULL) 1624135446Strhodes (void)cfg_map_get(config, "options", &options); 1625135446Strhodes 1626224092Sdougb /* 1627224092Sdougb * maps: view options, options, defaults 1628224092Sdougb * cfgmaps: view options, config 1629224092Sdougb * optionmaps: view options, options 1630224092Sdougb */ 1631135446Strhodes if (vconfig != NULL) { 1632135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 1633135446Strhodes maps[i++] = voptions; 1634224092Sdougb optionmaps[j++] = voptions; 1635224092Sdougb cfgmaps[k++] = voptions; 1636135446Strhodes } 1637224092Sdougb if (options != NULL) { 1638135446Strhodes maps[i++] = options; 1639224092Sdougb optionmaps[j++] = options; 1640224092Sdougb } 1641224092Sdougb 1642135446Strhodes maps[i++] = ns_g_defaults; 1643135446Strhodes maps[i] = NULL; 1644224092Sdougb optionmaps[j] = NULL; 1645135446Strhodes if (config != NULL) 1646224092Sdougb cfgmaps[k++] = config; 1647224092Sdougb cfgmaps[k] = NULL; 1648135446Strhodes 1649170222Sdougb if (!strcmp(viewname, "_default")) { 1650170222Sdougb sep = ""; 1651170222Sdougb viewname = ""; 1652170222Sdougb forview = ""; 1653225361Sdougb POST(forview); 1654170222Sdougb } 1655170222Sdougb 1656135446Strhodes /* 1657135446Strhodes * Set the view's port number for outgoing queries. 1658135446Strhodes */ 1659135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 1660135446Strhodes dns_view_setdstport(view, port); 1661135446Strhodes 1662135446Strhodes /* 1663170222Sdougb * Create additional cache for this view and zones under the view 1664170222Sdougb * if explicitly enabled. 1665170222Sdougb * XXX950 default to on. 1666170222Sdougb */ 1667170222Sdougb obj = NULL; 1668170222Sdougb (void)ns_config_get(maps, "acache-enable", &obj); 1669170222Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) { 1670170222Sdougb cmctx = NULL; 1671170222Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 1672170222Sdougb CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, 1673170222Sdougb ns_g_timermgr)); 1674193149Sdougb isc_mem_setname(cmctx, "acache", NULL); 1675170222Sdougb isc_mem_detach(&cmctx); 1676170222Sdougb } 1677170222Sdougb if (view->acache != NULL) { 1678170222Sdougb obj = NULL; 1679170222Sdougb result = ns_config_get(maps, "acache-cleaning-interval", &obj); 1680170222Sdougb INSIST(result == ISC_R_SUCCESS); 1681170222Sdougb dns_acache_setcleaninginterval(view->acache, 1682170222Sdougb cfg_obj_asuint32(obj) * 60); 1683170222Sdougb 1684170222Sdougb obj = NULL; 1685170222Sdougb result = ns_config_get(maps, "max-acache-size", &obj); 1686170222Sdougb INSIST(result == ISC_R_SUCCESS); 1687170222Sdougb if (cfg_obj_isstring(obj)) { 1688170222Sdougb str = cfg_obj_asstring(obj); 1689170222Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 1690170222Sdougb max_acache_size = ISC_UINT32_MAX; 1691170222Sdougb } else { 1692170222Sdougb isc_resourcevalue_t value; 1693170222Sdougb 1694170222Sdougb value = cfg_obj_asuint64(obj); 1695170222Sdougb if (value > ISC_UINT32_MAX) { 1696170222Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1697170222Sdougb "'max-acache-size " 1698170222Sdougb "%" ISC_PRINT_QUADFORMAT 1699170222Sdougb "d' is too large", 1700170222Sdougb value); 1701170222Sdougb result = ISC_R_RANGE; 1702170222Sdougb goto cleanup; 1703170222Sdougb } 1704170222Sdougb max_acache_size = (isc_uint32_t)value; 1705170222Sdougb } 1706170222Sdougb dns_acache_setcachesize(view->acache, max_acache_size); 1707170222Sdougb } 1708170222Sdougb 1709224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx, 1710216175Sdougb ns_g_mctx, &view->queryacl)); 1711216175Sdougb if (view->queryacl == NULL) { 1712224092Sdougb CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", 1713224092Sdougb NULL, actx, ns_g_mctx, 1714224092Sdougb &view->queryacl)); 1715216175Sdougb } 1716216175Sdougb 1717170222Sdougb /* 1718135446Strhodes * Configure the zones. 1719135446Strhodes */ 1720135446Strhodes zonelist = NULL; 1721135446Strhodes if (voptions != NULL) 1722135446Strhodes (void)cfg_map_get(voptions, "zone", &zonelist); 1723135446Strhodes else 1724135446Strhodes (void)cfg_map_get(config, "zone", &zonelist); 1725225361Sdougb 1726225361Sdougb /* 1727225361Sdougb * Load zone configuration 1728225361Sdougb */ 1729135446Strhodes for (element = cfg_list_first(zonelist); 1730135446Strhodes element != NULL; 1731135446Strhodes element = cfg_list_next(element)) 1732135446Strhodes { 1733165071Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 1734135446Strhodes CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 1735224092Sdougb actx, ISC_FALSE)); 1736135446Strhodes } 1737135446Strhodes 1738224092Sdougb /* 1739224092Sdougb * If we're allowing added zones, then load zone configuration 1740224092Sdougb * from the newzone file for zones that were added during previous 1741224092Sdougb * runs. 1742224092Sdougb */ 1743225361Sdougb nzctx = view->new_zone_config; 1744225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) { 1745224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1746224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 1747224092Sdougb "loading additional zones for view '%s'", 1748224092Sdougb view->name); 1749224092Sdougb 1750225361Sdougb zonelist = NULL; 1751225361Sdougb cfg_map_get(nzctx->nzconfig, "zone", &zonelist); 1752225361Sdougb 1753225361Sdougb for (element = cfg_list_first(zonelist); 1754225361Sdougb element != NULL; 1755225361Sdougb element = cfg_list_next(element)) 1756225361Sdougb { 1757225361Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 1758225361Sdougb CHECK(configure_zone(config, zconfig, vconfig, 1759225361Sdougb mctx, view, actx, 1760225361Sdougb ISC_TRUE)); 1761224092Sdougb } 1762224092Sdougb } 1763224092Sdougb 1764135446Strhodes /* 1765170222Sdougb * Create Dynamically Loadable Zone driver. 1766170222Sdougb */ 1767170222Sdougb dlz = NULL; 1768170222Sdougb if (voptions != NULL) 1769170222Sdougb (void)cfg_map_get(voptions, "dlz", &dlz); 1770170222Sdougb else 1771170222Sdougb (void)cfg_map_get(config, "dlz", &dlz); 1772170222Sdougb 1773170222Sdougb obj = NULL; 1774170222Sdougb if (dlz != NULL) { 1775170222Sdougb (void)cfg_map_get(cfg_tuple_get(dlz, "options"), 1776170222Sdougb "database", &obj); 1777170222Sdougb if (obj != NULL) { 1778170222Sdougb char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); 1779170222Sdougb if (s == NULL) { 1780170222Sdougb result = ISC_R_NOMEMORY; 1781170222Sdougb goto cleanup; 1782170222Sdougb } 1783186462Sdougb 1784170222Sdougb result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); 1785170222Sdougb if (result != ISC_R_SUCCESS) { 1786170222Sdougb isc_mem_free(mctx, s); 1787170222Sdougb goto cleanup; 1788170222Sdougb } 1789170222Sdougb 1790170222Sdougb obj = cfg_tuple_get(dlz, "name"); 1791170222Sdougb result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), 1792170222Sdougb dlzargv[0], dlzargc, dlzargv, 1793170222Sdougb &view->dlzdatabase); 1794170222Sdougb isc_mem_free(mctx, s); 1795170222Sdougb isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); 1796170222Sdougb if (result != ISC_R_SUCCESS) 1797170222Sdougb goto cleanup; 1798224092Sdougb 1799224092Sdougb /* 1800224092Sdougb * If the dlz backend supports configuration, 1801224092Sdougb * then call its configure method now. 1802224092Sdougb */ 1803224092Sdougb result = dns_dlzconfigure(view, dlzconfigure_callback); 1804224092Sdougb if (result != ISC_R_SUCCESS) 1805224092Sdougb goto cleanup; 1806170222Sdougb } 1807170222Sdougb } 1808170222Sdougb 1809170222Sdougb /* 1810193149Sdougb * Obtain configuration parameters that affect the decision of whether 1811193149Sdougb * we can reuse/share an existing cache. 1812193149Sdougb */ 1813224092Sdougb obj = NULL; 1814224092Sdougb result = ns_config_get(maps, "cleaning-interval", &obj); 1815224092Sdougb INSIST(result == ISC_R_SUCCESS); 1816224092Sdougb cleaning_interval = cfg_obj_asuint32(obj) * 60; 1817224092Sdougb 1818224092Sdougb obj = NULL; 1819224092Sdougb result = ns_config_get(maps, "max-cache-size", &obj); 1820224092Sdougb INSIST(result == ISC_R_SUCCESS); 1821224092Sdougb if (cfg_obj_isstring(obj)) { 1822224092Sdougb str = cfg_obj_asstring(obj); 1823224092Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 1824224092Sdougb max_cache_size = ISC_UINT32_MAX; 1825224092Sdougb } else { 1826224092Sdougb isc_resourcevalue_t value; 1827224092Sdougb value = cfg_obj_asuint64(obj); 1828224092Sdougb if (value > ISC_UINT32_MAX) { 1829224092Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1830224092Sdougb "'max-cache-size " 1831224092Sdougb "%" ISC_PRINT_QUADFORMAT "d' is too large", 1832224092Sdougb value); 1833224092Sdougb result = ISC_R_RANGE; 1834224092Sdougb goto cleanup; 1835224092Sdougb } 1836224092Sdougb max_cache_size = (isc_uint32_t)value; 1837224092Sdougb } 1838224092Sdougb 1839193149Sdougb /* Check-names. */ 1840193149Sdougb obj = NULL; 1841193149Sdougb result = ns_checknames_get(maps, "response", &obj); 1842193149Sdougb INSIST(result == ISC_R_SUCCESS); 1843193149Sdougb 1844193149Sdougb str = cfg_obj_asstring(obj); 1845193149Sdougb if (strcasecmp(str, "fail") == 0) { 1846193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES | 1847193149Sdougb DNS_RESOLVER_CHECKNAMESFAIL; 1848193149Sdougb view->checknames = ISC_TRUE; 1849193149Sdougb } else if (strcasecmp(str, "warn") == 0) { 1850193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES; 1851193149Sdougb view->checknames = ISC_FALSE; 1852193149Sdougb } else if (strcasecmp(str, "ignore") == 0) { 1853193149Sdougb view->checknames = ISC_FALSE; 1854193149Sdougb } else 1855193149Sdougb INSIST(0); 1856193149Sdougb 1857193149Sdougb obj = NULL; 1858193149Sdougb result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); 1859193149Sdougb INSIST(result == ISC_R_SUCCESS); 1860193149Sdougb zero_no_soattl = cfg_obj_asboolean(obj); 1861193149Sdougb 1862193149Sdougb obj = NULL; 1863224092Sdougb result = ns_config_get(maps, "dns64", &obj); 1864224092Sdougb if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") && 1865224092Sdougb strcmp(view->name, "_meta")) { 1866224092Sdougb const cfg_listelt_t *element; 1867224092Sdougb isc_netaddr_t na, suffix, *sp; 1868224092Sdougb unsigned int prefixlen; 1869224092Sdougb const char *server, *contact; 1870224092Sdougb const cfg_obj_t *myobj; 1871224092Sdougb 1872224092Sdougb myobj = NULL; 1873224092Sdougb result = ns_config_get(maps, "dns64-server", &myobj); 1874224092Sdougb if (result == ISC_R_SUCCESS) 1875224092Sdougb server = cfg_obj_asstring(myobj); 1876224092Sdougb else 1877224092Sdougb server = NULL; 1878224092Sdougb 1879224092Sdougb myobj = NULL; 1880224092Sdougb result = ns_config_get(maps, "dns64-contact", &myobj); 1881224092Sdougb if (result == ISC_R_SUCCESS) 1882224092Sdougb contact = cfg_obj_asstring(myobj); 1883224092Sdougb else 1884224092Sdougb contact = NULL; 1885224092Sdougb 1886224092Sdougb for (element = cfg_list_first(obj); 1887224092Sdougb element != NULL; 1888224092Sdougb element = cfg_list_next(element)) 1889224092Sdougb { 1890224092Sdougb const cfg_obj_t *map = cfg_listelt_value(element); 1891224092Sdougb dns_dns64_t *dns64 = NULL; 1892224092Sdougb unsigned int dns64options = 0; 1893224092Sdougb 1894224092Sdougb cfg_obj_asnetprefix(cfg_map_getname(map), &na, 1895224092Sdougb &prefixlen); 1896224092Sdougb 1897224092Sdougb obj = NULL; 1898224092Sdougb (void)cfg_map_get(map, "suffix", &obj); 1899224092Sdougb if (obj != NULL) { 1900224092Sdougb sp = &suffix; 1901224092Sdougb isc_netaddr_fromsockaddr(sp, 1902224092Sdougb cfg_obj_assockaddr(obj)); 1903224092Sdougb } else 1904224092Sdougb sp = NULL; 1905224092Sdougb 1906224092Sdougb clients = mapped = excluded = NULL; 1907224092Sdougb obj = NULL; 1908224092Sdougb (void)cfg_map_get(map, "clients", &obj); 1909224092Sdougb if (obj != NULL) { 1910224092Sdougb result = cfg_acl_fromconfig(obj, config, 1911224092Sdougb ns_g_lctx, actx, 1912224092Sdougb mctx, 0, &clients); 1913224092Sdougb if (result != ISC_R_SUCCESS) 1914224092Sdougb goto cleanup; 1915224092Sdougb } 1916224092Sdougb obj = NULL; 1917224092Sdougb (void)cfg_map_get(map, "mapped", &obj); 1918224092Sdougb if (obj != NULL) { 1919224092Sdougb result = cfg_acl_fromconfig(obj, config, 1920224092Sdougb ns_g_lctx, actx, 1921224092Sdougb mctx, 0, &mapped); 1922224092Sdougb if (result != ISC_R_SUCCESS) 1923224092Sdougb goto cleanup; 1924224092Sdougb } 1925224092Sdougb obj = NULL; 1926224092Sdougb (void)cfg_map_get(map, "exclude", &obj); 1927224092Sdougb if (obj != NULL) { 1928224092Sdougb result = cfg_acl_fromconfig(obj, config, 1929224092Sdougb ns_g_lctx, actx, 1930224092Sdougb mctx, 0, &excluded); 1931224092Sdougb if (result != ISC_R_SUCCESS) 1932224092Sdougb goto cleanup; 1933224092Sdougb } 1934224092Sdougb 1935224092Sdougb obj = NULL; 1936224092Sdougb (void)cfg_map_get(map, "recursive-only", &obj); 1937224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 1938224092Sdougb dns64options |= DNS_DNS64_RECURSIVE_ONLY; 1939224092Sdougb 1940224092Sdougb obj = NULL; 1941224092Sdougb (void)cfg_map_get(map, "break-dnssec", &obj); 1942224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 1943224092Sdougb dns64options |= DNS_DNS64_BREAK_DNSSEC; 1944224092Sdougb 1945224092Sdougb result = dns_dns64_create(mctx, &na, prefixlen, sp, 1946224092Sdougb clients, mapped, excluded, 1947224092Sdougb dns64options, &dns64); 1948224092Sdougb if (result != ISC_R_SUCCESS) 1949224092Sdougb goto cleanup; 1950224092Sdougb dns_dns64_append(&view->dns64, dns64); 1951224092Sdougb view->dns64cnt++; 1952224092Sdougb result = dns64_reverse(view, mctx, &na, prefixlen, 1953224092Sdougb server, contact); 1954224092Sdougb if (result != ISC_R_SUCCESS) 1955224092Sdougb goto cleanup; 1956224092Sdougb if (clients != NULL) 1957224092Sdougb dns_acl_detach(&clients); 1958224092Sdougb if (mapped != NULL) 1959224092Sdougb dns_acl_detach(&mapped); 1960224092Sdougb if (excluded != NULL) 1961224092Sdougb dns_acl_detach(&excluded); 1962224092Sdougb } 1963224092Sdougb } 1964224092Sdougb 1965224092Sdougb obj = NULL; 1966193149Sdougb result = ns_config_get(maps, "dnssec-accept-expired", &obj); 1967193149Sdougb INSIST(result == ISC_R_SUCCESS); 1968193149Sdougb view->acceptexpired = cfg_obj_asboolean(obj); 1969193149Sdougb 1970193149Sdougb obj = NULL; 1971193149Sdougb result = ns_config_get(maps, "dnssec-validation", &obj); 1972193149Sdougb INSIST(result == ISC_R_SUCCESS); 1973224092Sdougb if (cfg_obj_isboolean(obj)) { 1974224092Sdougb view->enablevalidation = cfg_obj_asboolean(obj); 1975224092Sdougb } else { 1976224092Sdougb /* If dnssec-validation is not boolean, it must be "auto" */ 1977224092Sdougb view->enablevalidation = ISC_TRUE; 1978224092Sdougb auto_root = ISC_TRUE; 1979224092Sdougb } 1980193149Sdougb 1981193149Sdougb obj = NULL; 1982193149Sdougb result = ns_config_get(maps, "max-cache-ttl", &obj); 1983193149Sdougb INSIST(result == ISC_R_SUCCESS); 1984193149Sdougb view->maxcachettl = cfg_obj_asuint32(obj); 1985193149Sdougb 1986193149Sdougb obj = NULL; 1987193149Sdougb result = ns_config_get(maps, "max-ncache-ttl", &obj); 1988193149Sdougb INSIST(result == ISC_R_SUCCESS); 1989193149Sdougb view->maxncachettl = cfg_obj_asuint32(obj); 1990193149Sdougb if (view->maxncachettl > 7 * 24 * 3600) 1991193149Sdougb view->maxncachettl = 7 * 24 * 3600; 1992193149Sdougb 1993193149Sdougb /* 1994224092Sdougb * Configure the view's cache. 1995135446Strhodes * 1996224092Sdougb * First, check to see if there are any attach-cache options. If yes, 1997224092Sdougb * attempt to lookup an existing cache at attach it to the view. If 1998224092Sdougb * there is not one, then try to reuse an existing cache if possible; 1999224092Sdougb * otherwise create a new cache. 2000224092Sdougb * 2001224092Sdougb * Note that the ADB is not preserved or shared in either case. 2002224092Sdougb * 2003224092Sdougb * When a matching view is found, the associated statistics are also 2004224092Sdougb * retrieved and reused. 2005224092Sdougb * 2006224092Sdougb * XXX Determining when it is safe to reuse or share a cache is tricky. 2007193149Sdougb * When the view's configuration changes, the cached data may become 2008193149Sdougb * invalid because it reflects our old view of the world. We check 2009224092Sdougb * some of the configuration parameters that could invalidate the cache 2010224092Sdougb * or otherwise make it unsharable, but there are other configuration 2011224092Sdougb * options that should be checked. For example, if a view uses a 2012224092Sdougb * forwarder, changes in the forwarder configuration may invalidate 2013224092Sdougb * the cache. At the moment, it's the administrator's responsibility to 2014224092Sdougb * ensure these configuration options don't invalidate reusing/sharing. 2015135446Strhodes */ 2016224092Sdougb obj = NULL; 2017224092Sdougb result = ns_config_get(maps, "attach-cache", &obj); 2018224092Sdougb if (result == ISC_R_SUCCESS) 2019224092Sdougb cachename = cfg_obj_asstring(obj); 2020224092Sdougb else 2021224092Sdougb cachename = view->name; 2022224092Sdougb cache = NULL; 2023224092Sdougb nsc = cachelist_find(cachelist, cachename); 2024224092Sdougb if (nsc != NULL) { 2025224092Sdougb if (!cache_sharable(nsc->primaryview, view, zero_no_soattl, 2026224092Sdougb cleaning_interval, max_cache_size)) { 2027193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2028224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2029224092Sdougb "views %s and %s can't share the cache " 2030193149Sdougb "due to configuration parameter mismatch", 2031224092Sdougb nsc->primaryview->name, view->name); 2032224092Sdougb result = ISC_R_FAILURE; 2033224092Sdougb goto cleanup; 2034193149Sdougb } 2035224092Sdougb dns_cache_attach(nsc->cache, &cache); 2036224092Sdougb shared_cache = ISC_TRUE; 2037224092Sdougb } else { 2038224092Sdougb if (strcmp(cachename, view->name) == 0) { 2039224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 2040224092Sdougb cachename, view->rdclass, 2041224092Sdougb &pview); 2042224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2043224092Sdougb goto cleanup; 2044224092Sdougb if (pview != NULL) { 2045224092Sdougb if (!cache_reusable(pview, view, 2046224092Sdougb zero_no_soattl)) { 2047224092Sdougb isc_log_write(ns_g_lctx, 2048224092Sdougb NS_LOGCATEGORY_GENERAL, 2049224092Sdougb NS_LOGMODULE_SERVER, 2050224092Sdougb ISC_LOG_DEBUG(1), 2051224092Sdougb "cache cannot be reused " 2052224092Sdougb "for view %s due to " 2053224092Sdougb "configuration parameter " 2054224092Sdougb "mismatch", view->name); 2055224092Sdougb } else { 2056224092Sdougb INSIST(pview->cache != NULL); 2057224092Sdougb isc_log_write(ns_g_lctx, 2058224092Sdougb NS_LOGCATEGORY_GENERAL, 2059224092Sdougb NS_LOGMODULE_SERVER, 2060224092Sdougb ISC_LOG_DEBUG(3), 2061224092Sdougb "reusing existing cache"); 2062224092Sdougb reused_cache = ISC_TRUE; 2063224092Sdougb dns_cache_attach(pview->cache, &cache); 2064224092Sdougb } 2065224092Sdougb dns_view_getresstats(pview, &resstats); 2066224092Sdougb dns_view_getresquerystats(pview, 2067224092Sdougb &resquerystats); 2068224092Sdougb dns_view_detach(&pview); 2069224092Sdougb } 2070224092Sdougb } 2071224092Sdougb if (cache == NULL) { 2072224092Sdougb /* 2073224092Sdougb * Create a cache with the desired name. This normally 2074224092Sdougb * equals the view name, but may also be a forward 2075224092Sdougb * reference to a view that share the cache with this 2076224092Sdougb * view but is not yet configured. If it is not the 2077224092Sdougb * view name but not a forward reference either, then it 2078224092Sdougb * is simply a named cache that is not shared. 2079225361Sdougb * 2080225361Sdougb * We use two separate memory contexts for the 2081225361Sdougb * cache, for the main cache memory and the heap 2082225361Sdougb * memory. 2083224092Sdougb */ 2084224092Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 2085224092Sdougb isc_mem_setname(cmctx, "cache", NULL); 2086225361Sdougb CHECK(isc_mem_create(0, 0, &hmctx)); 2087225361Sdougb isc_mem_setname(hmctx, "cache_heap", NULL); 2088225361Sdougb CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr, 2089224092Sdougb ns_g_timermgr, view->rdclass, 2090224092Sdougb cachename, "rbt", 0, NULL, 2091224092Sdougb &cache)); 2092225361Sdougb isc_mem_detach(&cmctx); 2093225361Sdougb isc_mem_detach(&hmctx); 2094224092Sdougb } 2095224092Sdougb nsc = isc_mem_get(mctx, sizeof(*nsc)); 2096224092Sdougb if (nsc == NULL) { 2097224092Sdougb result = ISC_R_NOMEMORY; 2098224092Sdougb goto cleanup; 2099224092Sdougb } 2100224092Sdougb nsc->cache = NULL; 2101224092Sdougb dns_cache_attach(cache, &nsc->cache); 2102224092Sdougb nsc->primaryview = view; 2103224092Sdougb nsc->needflush = ISC_FALSE; 2104224092Sdougb nsc->adbsizeadjusted = ISC_FALSE; 2105224092Sdougb ISC_LINK_INIT(nsc, link); 2106224092Sdougb ISC_LIST_APPEND(*cachelist, nsc, link); 2107193149Sdougb } 2108224092Sdougb dns_view_setcache2(view, cache, shared_cache); 2109135446Strhodes 2110135446Strhodes /* 2111135446Strhodes * cache-file cannot be inherited if views are present, but this 2112135446Strhodes * should be caught by the configuration checking stage. 2113135446Strhodes */ 2114135446Strhodes obj = NULL; 2115135446Strhodes result = ns_config_get(maps, "cache-file", &obj); 2116135446Strhodes if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 2117135446Strhodes CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 2118224092Sdougb if (!reused_cache && !shared_cache) 2119135446Strhodes CHECK(dns_cache_load(cache)); 2120135446Strhodes } 2121135446Strhodes 2122224092Sdougb dns_cache_setcleaninginterval(cache, cleaning_interval); 2123135446Strhodes dns_cache_setcachesize(cache, max_cache_size); 2124135446Strhodes 2125135446Strhodes dns_cache_detach(&cache); 2126135446Strhodes 2127135446Strhodes /* 2128135446Strhodes * Resolver. 2129135446Strhodes * 2130135446Strhodes * XXXRTH Hardwired number of tasks. 2131135446Strhodes */ 2132186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, 2133186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2134186462Sdougb == NULL))); 2135186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, 2136186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2137186462Sdougb == NULL))); 2138135446Strhodes if (dispatch4 == NULL && dispatch6 == NULL) { 2139135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 2140135446Strhodes "unable to obtain neither an IPv4 nor" 2141135446Strhodes " an IPv6 dispatch"); 2142135446Strhodes result = ISC_R_UNEXPECTED; 2143135446Strhodes goto cleanup; 2144135446Strhodes } 2145135446Strhodes CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, 2146135446Strhodes ns_g_socketmgr, ns_g_timermgr, 2147193149Sdougb resopts, ns_g_dispatchmgr, 2148135446Strhodes dispatch4, dispatch6)); 2149135446Strhodes 2150193149Sdougb if (resstats == NULL) { 2151193149Sdougb CHECK(isc_stats_create(mctx, &resstats, 2152193149Sdougb dns_resstatscounter_max)); 2153193149Sdougb } 2154193149Sdougb dns_view_setresstats(view, resstats); 2155193149Sdougb if (resquerystats == NULL) 2156193149Sdougb CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); 2157193149Sdougb dns_view_setresquerystats(view, resquerystats); 2158193149Sdougb 2159135446Strhodes /* 2160224092Sdougb * Set the ADB cache size to 1/8th of the max-cache-size or 2161224092Sdougb * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. 2162135446Strhodes */ 2163135446Strhodes max_adb_size = 0; 2164135446Strhodes if (max_cache_size != 0) { 2165135446Strhodes max_adb_size = max_cache_size / 8; 2166135446Strhodes if (max_adb_size == 0) 2167135446Strhodes max_adb_size = 1; /* Force minimum. */ 2168224092Sdougb if (view != nsc->primaryview && 2169224092Sdougb max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) { 2170224092Sdougb max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE; 2171224092Sdougb if (!nsc->adbsizeadjusted) { 2172224092Sdougb dns_adb_setadbsize(nsc->primaryview->adb, 2173224092Sdougb MAX_ADB_SIZE_FOR_CACHESHARE); 2174224092Sdougb nsc->adbsizeadjusted = ISC_TRUE; 2175224092Sdougb } 2176224092Sdougb } 2177135446Strhodes } 2178135446Strhodes dns_adb_setadbsize(view->adb, max_adb_size); 2179135446Strhodes 2180135446Strhodes /* 2181135446Strhodes * Set resolver's lame-ttl. 2182135446Strhodes */ 2183135446Strhodes obj = NULL; 2184135446Strhodes result = ns_config_get(maps, "lame-ttl", &obj); 2185135446Strhodes INSIST(result == ISC_R_SUCCESS); 2186135446Strhodes lame_ttl = cfg_obj_asuint32(obj); 2187135446Strhodes if (lame_ttl > 1800) 2188135446Strhodes lame_ttl = 1800; 2189135446Strhodes dns_resolver_setlamettl(view->resolver, lame_ttl); 2190170222Sdougb 2191135446Strhodes /* 2192224092Sdougb * Set the resolver's query timeout. 2193224092Sdougb */ 2194224092Sdougb obj = NULL; 2195224092Sdougb result = ns_config_get(maps, "resolver-query-timeout", &obj); 2196224092Sdougb INSIST(result == ISC_R_SUCCESS); 2197224092Sdougb query_timeout = cfg_obj_asuint32(obj); 2198224092Sdougb dns_resolver_settimeout(view->resolver, query_timeout); 2199224092Sdougb 2200224092Sdougb /* Specify whether to use 0-TTL for negative response for SOA query */ 2201224092Sdougb dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl); 2202224092Sdougb 2203224092Sdougb /* 2204135446Strhodes * Set the resolver's EDNS UDP size. 2205135446Strhodes */ 2206135446Strhodes obj = NULL; 2207135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 2208135446Strhodes INSIST(result == ISC_R_SUCCESS); 2209135446Strhodes udpsize = cfg_obj_asuint32(obj); 2210135446Strhodes if (udpsize < 512) 2211135446Strhodes udpsize = 512; 2212135446Strhodes if (udpsize > 4096) 2213135446Strhodes udpsize = 4096; 2214135446Strhodes dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 2215186462Sdougb 2216135446Strhodes /* 2217170222Sdougb * Set the maximum UDP response size. 2218170222Sdougb */ 2219170222Sdougb obj = NULL; 2220170222Sdougb result = ns_config_get(maps, "max-udp-size", &obj); 2221170222Sdougb INSIST(result == ISC_R_SUCCESS); 2222170222Sdougb udpsize = cfg_obj_asuint32(obj); 2223170222Sdougb if (udpsize < 512) 2224170222Sdougb udpsize = 512; 2225170222Sdougb if (udpsize > 4096) 2226170222Sdougb udpsize = 4096; 2227170222Sdougb view->maxudp = udpsize; 2228170222Sdougb 2229170222Sdougb /* 2230135446Strhodes * Set supported DNSSEC algorithms. 2231135446Strhodes */ 2232135446Strhodes dns_resolver_reset_algorithms(view->resolver); 2233135446Strhodes disabled = NULL; 2234135446Strhodes (void)ns_config_get(maps, "disable-algorithms", &disabled); 2235135446Strhodes if (disabled != NULL) { 2236135446Strhodes for (element = cfg_list_first(disabled); 2237135446Strhodes element != NULL; 2238135446Strhodes element = cfg_list_next(element)) 2239135446Strhodes CHECK(disable_algorithms(cfg_listelt_value(element), 2240135446Strhodes view->resolver)); 2241135446Strhodes } 2242135446Strhodes 2243135446Strhodes /* 2244135446Strhodes * A global or view "forwarders" option, if present, 2245135446Strhodes * creates an entry for "." in the forwarding table. 2246135446Strhodes */ 2247135446Strhodes forwardtype = NULL; 2248135446Strhodes forwarders = NULL; 2249135446Strhodes (void)ns_config_get(maps, "forward", &forwardtype); 2250135446Strhodes (void)ns_config_get(maps, "forwarders", &forwarders); 2251135446Strhodes if (forwarders != NULL) 2252186462Sdougb CHECK(configure_forward(config, view, dns_rootname, 2253135446Strhodes forwarders, forwardtype)); 2254135446Strhodes 2255135446Strhodes /* 2256135446Strhodes * Dual Stack Servers. 2257135446Strhodes */ 2258135446Strhodes alternates = NULL; 2259135446Strhodes (void)ns_config_get(maps, "dual-stack-servers", &alternates); 2260135446Strhodes if (alternates != NULL) 2261135446Strhodes CHECK(configure_alternates(config, view, alternates)); 2262135446Strhodes 2263135446Strhodes /* 2264135446Strhodes * We have default hints for class IN if we need them. 2265135446Strhodes */ 2266135446Strhodes if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 2267135446Strhodes dns_view_sethints(view, ns_g_server->in_roothints); 2268135446Strhodes 2269135446Strhodes /* 2270135446Strhodes * If we still have no hints, this is a non-IN view with no 2271135446Strhodes * "hints zone" configured. Issue a warning, except if this 2272186462Sdougb * is a root server. Root servers never need to consult 2273135446Strhodes * their hints, so it's no point requiring users to configure 2274135446Strhodes * them. 2275135446Strhodes */ 2276135446Strhodes if (view->hints == NULL) { 2277135446Strhodes dns_zone_t *rootzone = NULL; 2278135446Strhodes (void)dns_view_findzone(view, dns_rootname, &rootzone); 2279135446Strhodes if (rootzone != NULL) { 2280135446Strhodes dns_zone_detach(&rootzone); 2281135446Strhodes need_hints = ISC_FALSE; 2282135446Strhodes } 2283135446Strhodes if (need_hints) 2284135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2285135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2286135446Strhodes "no root hints for view '%s'", 2287135446Strhodes view->name); 2288135446Strhodes } 2289135446Strhodes 2290135446Strhodes /* 2291135446Strhodes * Configure the view's TSIG keys. 2292135446Strhodes */ 2293135446Strhodes CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 2294224092Sdougb if (ns_g_server->sessionkey != NULL) { 2295224092Sdougb CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname, 2296224092Sdougb ns_g_server->sessionkey)); 2297224092Sdougb } 2298135446Strhodes dns_view_setkeyring(view, ring); 2299224092Sdougb dns_tsigkeyring_detach(&ring); 2300135446Strhodes 2301135446Strhodes /* 2302224092Sdougb * See if we can re-use a dynamic key ring. 2303224092Sdougb */ 2304224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, view->name, 2305224092Sdougb view->rdclass, &pview); 2306224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2307224092Sdougb goto cleanup; 2308224092Sdougb if (pview != NULL) { 2309224092Sdougb dns_view_getdynamickeyring(pview, &ring); 2310224092Sdougb if (ring != NULL) 2311224092Sdougb dns_view_setdynamickeyring(view, ring); 2312224092Sdougb dns_tsigkeyring_detach(&ring); 2313224092Sdougb dns_view_detach(&pview); 2314224092Sdougb } else 2315224092Sdougb dns_view_restorekeyring(view); 2316224092Sdougb 2317224092Sdougb /* 2318135446Strhodes * Configure the view's peer list. 2319135446Strhodes */ 2320135446Strhodes { 2321165071Sdougb const cfg_obj_t *peers = NULL; 2322165071Sdougb const cfg_listelt_t *element; 2323135446Strhodes dns_peerlist_t *newpeers = NULL; 2324135446Strhodes 2325135446Strhodes (void)ns_config_get(cfgmaps, "server", &peers); 2326135446Strhodes CHECK(dns_peerlist_new(mctx, &newpeers)); 2327135446Strhodes for (element = cfg_list_first(peers); 2328135446Strhodes element != NULL; 2329135446Strhodes element = cfg_list_next(element)) 2330135446Strhodes { 2331165071Sdougb const cfg_obj_t *cpeer = cfg_listelt_value(element); 2332135446Strhodes dns_peer_t *peer; 2333135446Strhodes 2334135446Strhodes CHECK(configure_peer(cpeer, mctx, &peer)); 2335135446Strhodes dns_peerlist_addpeer(newpeers, peer); 2336135446Strhodes dns_peer_detach(&peer); 2337135446Strhodes } 2338135446Strhodes dns_peerlist_detach(&view->peers); 2339135446Strhodes view->peers = newpeers; /* Transfer ownership. */ 2340135446Strhodes } 2341135446Strhodes 2342135446Strhodes /* 2343135446Strhodes * Configure the views rrset-order. 2344135446Strhodes */ 2345135446Strhodes { 2346165071Sdougb const cfg_obj_t *rrsetorder = NULL; 2347165071Sdougb const cfg_listelt_t *element; 2348135446Strhodes 2349135446Strhodes (void)ns_config_get(maps, "rrset-order", &rrsetorder); 2350135446Strhodes CHECK(dns_order_create(mctx, &order)); 2351135446Strhodes for (element = cfg_list_first(rrsetorder); 2352135446Strhodes element != NULL; 2353135446Strhodes element = cfg_list_next(element)) 2354135446Strhodes { 2355165071Sdougb const cfg_obj_t *ent = cfg_listelt_value(element); 2356135446Strhodes 2357135446Strhodes CHECK(configure_order(order, ent)); 2358135446Strhodes } 2359135446Strhodes if (view->order != NULL) 2360135446Strhodes dns_order_detach(&view->order); 2361135446Strhodes dns_order_attach(order, &view->order); 2362135446Strhodes dns_order_detach(&order); 2363135446Strhodes } 2364135446Strhodes /* 2365135446Strhodes * Copy the aclenv object. 2366135446Strhodes */ 2367135446Strhodes dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 2368135446Strhodes 2369135446Strhodes /* 2370135446Strhodes * Configure the "match-clients" and "match-destinations" ACL. 2371135446Strhodes */ 2372224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx, 2373135446Strhodes ns_g_mctx, &view->matchclients)); 2374224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL, 2375224092Sdougb actx, ns_g_mctx, &view->matchdestinations)); 2376135446Strhodes 2377135446Strhodes /* 2378135446Strhodes * Configure the "match-recursive-only" option. 2379135446Strhodes */ 2380135446Strhodes obj = NULL; 2381165071Sdougb (void)ns_config_get(maps, "match-recursive-only", &obj); 2382135446Strhodes if (obj != NULL && cfg_obj_asboolean(obj)) 2383135446Strhodes view->matchrecursiveonly = ISC_TRUE; 2384135446Strhodes else 2385135446Strhodes view->matchrecursiveonly = ISC_FALSE; 2386135446Strhodes 2387135446Strhodes /* 2388135446Strhodes * Configure other configurable data. 2389135446Strhodes */ 2390135446Strhodes obj = NULL; 2391135446Strhodes result = ns_config_get(maps, "recursion", &obj); 2392135446Strhodes INSIST(result == ISC_R_SUCCESS); 2393135446Strhodes view->recursion = cfg_obj_asboolean(obj); 2394135446Strhodes 2395135446Strhodes obj = NULL; 2396135446Strhodes result = ns_config_get(maps, "auth-nxdomain", &obj); 2397135446Strhodes INSIST(result == ISC_R_SUCCESS); 2398135446Strhodes view->auth_nxdomain = cfg_obj_asboolean(obj); 2399135446Strhodes 2400135446Strhodes obj = NULL; 2401135446Strhodes result = ns_config_get(maps, "minimal-responses", &obj); 2402135446Strhodes INSIST(result == ISC_R_SUCCESS); 2403135446Strhodes view->minimalresponses = cfg_obj_asboolean(obj); 2404135446Strhodes 2405135446Strhodes obj = NULL; 2406135446Strhodes result = ns_config_get(maps, "transfer-format", &obj); 2407135446Strhodes INSIST(result == ISC_R_SUCCESS); 2408135446Strhodes str = cfg_obj_asstring(obj); 2409135446Strhodes if (strcasecmp(str, "many-answers") == 0) 2410135446Strhodes view->transfer_format = dns_many_answers; 2411135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 2412135446Strhodes view->transfer_format = dns_one_answer; 2413135446Strhodes else 2414135446Strhodes INSIST(0); 2415186462Sdougb 2416135446Strhodes /* 2417135446Strhodes * Set sources where additional data and CNAME/DNAME 2418135446Strhodes * targets for authoritative answers may be found. 2419135446Strhodes */ 2420135446Strhodes obj = NULL; 2421135446Strhodes result = ns_config_get(maps, "additional-from-auth", &obj); 2422135446Strhodes INSIST(result == ISC_R_SUCCESS); 2423135446Strhodes view->additionalfromauth = cfg_obj_asboolean(obj); 2424135446Strhodes if (view->recursion && ! view->additionalfromauth) { 2425135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2426135446Strhodes "'additional-from-auth no' is only supported " 2427135446Strhodes "with 'recursion no'"); 2428135446Strhodes view->additionalfromauth = ISC_TRUE; 2429135446Strhodes } 2430135446Strhodes 2431135446Strhodes obj = NULL; 2432135446Strhodes result = ns_config_get(maps, "additional-from-cache", &obj); 2433135446Strhodes INSIST(result == ISC_R_SUCCESS); 2434135446Strhodes view->additionalfromcache = cfg_obj_asboolean(obj); 2435135446Strhodes if (view->recursion && ! view->additionalfromcache) { 2436135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2437135446Strhodes "'additional-from-cache no' is only supported " 2438135446Strhodes "with 'recursion no'"); 2439135446Strhodes view->additionalfromcache = ISC_TRUE; 2440135446Strhodes } 2441135446Strhodes 2442171577Sdougb /* 2443193149Sdougb * Set "allow-query-cache", "allow-query-cache-on", 2444193149Sdougb * "allow-recursion", and "allow-recursion-on" acls if 2445171577Sdougb * configured in named.conf. 2446171577Sdougb */ 2447224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL, 2448216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 2449224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL, 2450216175Sdougb actx, ns_g_mctx, &view->cacheonacl)); 2451216175Sdougb if (view->cacheonacl == NULL) 2452193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2453224092Sdougb "allow-query-cache-on", NULL, actx, 2454216175Sdougb ns_g_mctx, &view->cacheonacl)); 2455193149Sdougb if (strcmp(view->name, "_bind") != 0) { 2456135446Strhodes CHECK(configure_view_acl(vconfig, config, "allow-recursion", 2457224092Sdougb NULL, actx, ns_g_mctx, 2458193149Sdougb &view->recursionacl)); 2459193149Sdougb CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", 2460224092Sdougb NULL, actx, ns_g_mctx, 2461193149Sdougb &view->recursiononacl)); 2462193149Sdougb } 2463135446Strhodes 2464135446Strhodes /* 2465171577Sdougb * "allow-query-cache" inherits from "allow-recursion" if set, 2466171577Sdougb * otherwise from "allow-query" if set. 2467171577Sdougb * "allow-recursion" inherits from "allow-query-cache" if set, 2468171577Sdougb * otherwise from "allow-query" if set. 2469170222Sdougb */ 2470216175Sdougb if (view->cacheacl == NULL && view->recursionacl != NULL) 2471216175Sdougb dns_acl_attach(view->recursionacl, &view->cacheacl); 2472224092Sdougb /* 2473224092Sdougb * XXXEACH: This call to configure_view_acl() is redundant. We 2474224092Sdougb * are leaving it as it is because we are making a minimal change 2475224092Sdougb * for a patch release. In the future this should be changed to 2476224092Sdougb * dns_acl_attach(view->queryacl, &view->cacheacl). 2477224092Sdougb */ 2478216175Sdougb if (view->cacheacl == NULL && view->recursion) 2479224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, 2480216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 2481193149Sdougb if (view->recursion && 2482216175Sdougb view->recursionacl == NULL && view->cacheacl != NULL) 2483216175Sdougb dns_acl_attach(view->cacheacl, &view->recursionacl); 2484171577Sdougb 2485171577Sdougb /* 2486193149Sdougb * Set default "allow-recursion", "allow-recursion-on" and 2487193149Sdougb * "allow-query-cache" acls. 2488171577Sdougb */ 2489170222Sdougb if (view->recursionacl == NULL && view->recursion) 2490171577Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2491224092Sdougb "allow-recursion", NULL, 2492193149Sdougb actx, ns_g_mctx, 2493193149Sdougb &view->recursionacl)); 2494193149Sdougb if (view->recursiononacl == NULL && view->recursion) 2495193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2496224092Sdougb "allow-recursion-on", NULL, 2497193149Sdougb actx, ns_g_mctx, 2498193149Sdougb &view->recursiononacl)); 2499216175Sdougb if (view->cacheacl == NULL) { 2500193149Sdougb if (view->recursion) 2501193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2502224092Sdougb "allow-query-cache", NULL, 2503224092Sdougb actx, ns_g_mctx, 2504224092Sdougb &view->cacheacl)); 2505216175Sdougb else 2506224092Sdougb CHECK(dns_acl_none(mctx, &view->cacheacl)); 2507193149Sdougb } 2508170222Sdougb 2509193149Sdougb /* 2510224092Sdougb * Filter setting on addresses in the answer section. 2511224092Sdougb */ 2512224092Sdougb CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses", 2513224092Sdougb "acl", actx, ns_g_mctx, &view->denyansweracl)); 2514224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses", 2515224092Sdougb "except-from", ns_g_mctx, 2516224092Sdougb &view->answeracl_exclude)); 2517224092Sdougb 2518224092Sdougb /* 2519224092Sdougb * Filter setting on names (CNAME/DNAME targets) in the answer section. 2520224092Sdougb */ 2521224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 2522224092Sdougb "name", ns_g_mctx, 2523224092Sdougb &view->denyanswernames)); 2524224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 2525224092Sdougb "except-from", ns_g_mctx, 2526224092Sdougb &view->answernames_exclude)); 2527224092Sdougb 2528224092Sdougb /* 2529193149Sdougb * Configure sortlist, if set 2530193149Sdougb */ 2531193149Sdougb CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, 2532193149Sdougb &view->sortlist)); 2533135446Strhodes 2534193149Sdougb /* 2535193149Sdougb * Configure default allow-transfer, allow-notify, allow-update 2536193149Sdougb * and allow-update-forwarding ACLs, if set, so they can be 2537193149Sdougb * inherited by zones. 2538193149Sdougb */ 2539193149Sdougb if (view->notifyacl == NULL) 2540193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2541224092Sdougb "allow-notify", NULL, actx, 2542193149Sdougb ns_g_mctx, &view->notifyacl)); 2543193149Sdougb if (view->transferacl == NULL) 2544193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2545224092Sdougb "allow-transfer", NULL, actx, 2546193149Sdougb ns_g_mctx, &view->transferacl)); 2547193149Sdougb if (view->updateacl == NULL) 2548193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2549224092Sdougb "allow-update", NULL, actx, 2550193149Sdougb ns_g_mctx, &view->updateacl)); 2551193149Sdougb if (view->upfwdacl == NULL) 2552193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 2553224092Sdougb "allow-update-forwarding", NULL, actx, 2554193149Sdougb ns_g_mctx, &view->upfwdacl)); 2555193149Sdougb 2556135446Strhodes obj = NULL; 2557135446Strhodes result = ns_config_get(maps, "request-ixfr", &obj); 2558135446Strhodes INSIST(result == ISC_R_SUCCESS); 2559135446Strhodes view->requestixfr = cfg_obj_asboolean(obj); 2560135446Strhodes 2561135446Strhodes obj = NULL; 2562135446Strhodes result = ns_config_get(maps, "provide-ixfr", &obj); 2563135446Strhodes INSIST(result == ISC_R_SUCCESS); 2564135446Strhodes view->provideixfr = cfg_obj_asboolean(obj); 2565170222Sdougb 2566170222Sdougb obj = NULL; 2567193149Sdougb result = ns_config_get(maps, "request-nsid", &obj); 2568193149Sdougb INSIST(result == ISC_R_SUCCESS); 2569193149Sdougb view->requestnsid = cfg_obj_asboolean(obj); 2570193149Sdougb 2571193149Sdougb obj = NULL; 2572170222Sdougb result = ns_config_get(maps, "max-clients-per-query", &obj); 2573170222Sdougb INSIST(result == ISC_R_SUCCESS); 2574170222Sdougb max_clients_per_query = cfg_obj_asuint32(obj); 2575170222Sdougb 2576170222Sdougb obj = NULL; 2577170222Sdougb result = ns_config_get(maps, "clients-per-query", &obj); 2578170222Sdougb INSIST(result == ISC_R_SUCCESS); 2579170222Sdougb dns_resolver_setclientsperquery(view->resolver, 2580170222Sdougb cfg_obj_asuint32(obj), 2581170222Sdougb max_clients_per_query); 2582186462Sdougb 2583224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 2584135446Strhodes obj = NULL; 2585224092Sdougb result = ns_config_get(maps, "filter-aaaa-on-v4", &obj); 2586224092Sdougb INSIST(result == ISC_R_SUCCESS); 2587224092Sdougb if (cfg_obj_isboolean(obj)) { 2588224092Sdougb if (cfg_obj_asboolean(obj)) 2589224092Sdougb view->v4_aaaa = dns_v4_aaaa_filter; 2590224092Sdougb else 2591224092Sdougb view->v4_aaaa = dns_v4_aaaa_ok; 2592224092Sdougb } else { 2593224092Sdougb const char *v4_aaaastr = cfg_obj_asstring(obj); 2594224092Sdougb if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) 2595224092Sdougb view->v4_aaaa = dns_v4_aaaa_break_dnssec; 2596224092Sdougb else 2597224092Sdougb INSIST(0); 2598224092Sdougb } 2599224092Sdougb CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL, 2600224092Sdougb actx, ns_g_mctx, &view->v4_aaaa_acl)); 2601224092Sdougb#endif 2602224092Sdougb 2603224092Sdougb obj = NULL; 2604135446Strhodes result = ns_config_get(maps, "dnssec-enable", &obj); 2605135446Strhodes INSIST(result == ISC_R_SUCCESS); 2606135446Strhodes view->enablednssec = cfg_obj_asboolean(obj); 2607135446Strhodes 2608135446Strhodes obj = NULL; 2609224092Sdougb result = ns_config_get(optionmaps, "dnssec-lookaside", &obj); 2610135446Strhodes if (result == ISC_R_SUCCESS) { 2611224092Sdougb /* If set to "auto", use the version from the defaults */ 2612224092Sdougb const cfg_obj_t *dlvobj; 2613234010Sdougb const char *dom; 2614224092Sdougb dlvobj = cfg_listelt_value(cfg_list_first(obj)); 2615234010Sdougb dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain")); 2616234010Sdougb if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) { 2617234010Sdougb /* If "no", skip; if "auto", use global default */ 2618234010Sdougb if (!strcasecmp(dom, "no")) 2619234010Sdougb result = ISC_R_NOTFOUND; 2620234010Sdougb else if (!strcasecmp(dom, "auto")) { 2621234010Sdougb auto_dlv = ISC_TRUE; 2622234010Sdougb obj = NULL; 2623234010Sdougb result = cfg_map_get(ns_g_defaults, 2624234010Sdougb "dnssec-lookaside", &obj); 2625234010Sdougb } 2626224092Sdougb } 2627224092Sdougb } 2628224092Sdougb 2629224092Sdougb if (result == ISC_R_SUCCESS) { 2630135446Strhodes for (element = cfg_list_first(obj); 2631135446Strhodes element != NULL; 2632135446Strhodes element = cfg_list_next(element)) 2633135446Strhodes { 2634135446Strhodes const char *str; 2635135446Strhodes isc_buffer_t b; 2636135446Strhodes dns_name_t *dlv; 2637135446Strhodes 2638135446Strhodes obj = cfg_listelt_value(element); 2639135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, 2640135446Strhodes "trust-anchor")); 2641135446Strhodes isc_buffer_init(&b, str, strlen(str)); 2642135446Strhodes isc_buffer_add(&b, strlen(str)); 2643135446Strhodes dlv = dns_fixedname_name(&view->dlv_fixed); 2644135446Strhodes CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 2645224092Sdougb DNS_NAME_DOWNCASE, NULL)); 2646135446Strhodes view->dlv = dns_fixedname_name(&view->dlv_fixed); 2647135446Strhodes } 2648135446Strhodes } else 2649135446Strhodes view->dlv = NULL; 2650135446Strhodes 2651135446Strhodes /* 2652135446Strhodes * For now, there is only one kind of trusted keys, the 2653135446Strhodes * "security roots". 2654135446Strhodes */ 2655224092Sdougb CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, 2656224092Sdougb auto_dlv, auto_root, mctx)); 2657170222Sdougb dns_resolver_resetmustbesecure(view->resolver); 2658170222Sdougb obj = NULL; 2659170222Sdougb result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 2660170222Sdougb if (result == ISC_R_SUCCESS) 2661170222Sdougb CHECK(mustbesecure(obj, view->resolver)); 2662135446Strhodes 2663135446Strhodes obj = NULL; 2664135446Strhodes result = ns_config_get(maps, "preferred-glue", &obj); 2665135446Strhodes if (result == ISC_R_SUCCESS) { 2666135446Strhodes str = cfg_obj_asstring(obj); 2667135446Strhodes if (strcasecmp(str, "a") == 0) 2668135446Strhodes view->preferred_glue = dns_rdatatype_a; 2669135446Strhodes else if (strcasecmp(str, "aaaa") == 0) 2670135446Strhodes view->preferred_glue = dns_rdatatype_aaaa; 2671135446Strhodes else 2672135446Strhodes view->preferred_glue = 0; 2673135446Strhodes } else 2674135446Strhodes view->preferred_glue = 0; 2675135446Strhodes 2676135446Strhodes obj = NULL; 2677135446Strhodes result = ns_config_get(maps, "root-delegation-only", &obj); 2678135446Strhodes if (result == ISC_R_SUCCESS) { 2679135446Strhodes dns_view_setrootdelonly(view, ISC_TRUE); 2680135446Strhodes if (!cfg_obj_isvoid(obj)) { 2681135446Strhodes dns_fixedname_t fixed; 2682135446Strhodes dns_name_t *name; 2683135446Strhodes isc_buffer_t b; 2684165071Sdougb const char *str; 2685165071Sdougb const cfg_obj_t *exclude; 2686135446Strhodes 2687135446Strhodes dns_fixedname_init(&fixed); 2688135446Strhodes name = dns_fixedname_name(&fixed); 2689135446Strhodes for (element = cfg_list_first(obj); 2690135446Strhodes element != NULL; 2691135446Strhodes element = cfg_list_next(element)) { 2692135446Strhodes exclude = cfg_listelt_value(element); 2693135446Strhodes str = cfg_obj_asstring(exclude); 2694135446Strhodes isc_buffer_init(&b, str, strlen(str)); 2695135446Strhodes isc_buffer_add(&b, strlen(str)); 2696135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 2697224092Sdougb 0, NULL)); 2698135446Strhodes CHECK(dns_view_excludedelegationonly(view, 2699135446Strhodes name)); 2700135446Strhodes } 2701135446Strhodes } 2702135446Strhodes } else 2703135446Strhodes dns_view_setrootdelonly(view, ISC_FALSE); 2704135446Strhodes 2705170222Sdougb /* 2706170222Sdougb * Setup automatic empty zones. If recursion is off then 2707170222Sdougb * they are disabled by default. 2708170222Sdougb */ 2709170222Sdougb obj = NULL; 2710170222Sdougb (void)ns_config_get(maps, "empty-zones-enable", &obj); 2711170222Sdougb (void)ns_config_get(maps, "disable-empty-zone", &disablelist); 2712170222Sdougb if (obj == NULL && disablelist == NULL && 2713170222Sdougb view->rdclass == dns_rdataclass_in) { 2714170222Sdougb rfc1918 = ISC_FALSE; 2715170222Sdougb empty_zones_enable = view->recursion; 2716170222Sdougb } else if (view->rdclass == dns_rdataclass_in) { 2717170222Sdougb rfc1918 = ISC_TRUE; 2718170222Sdougb if (obj != NULL) 2719170222Sdougb empty_zones_enable = cfg_obj_asboolean(obj); 2720170222Sdougb else 2721170222Sdougb empty_zones_enable = view->recursion; 2722170222Sdougb } else { 2723170222Sdougb rfc1918 = ISC_FALSE; 2724170222Sdougb empty_zones_enable = ISC_FALSE; 2725170222Sdougb } 2726234010Sdougb if (empty_zones_enable && !lwresd_g_useresolvconf) { 2727170222Sdougb const char *empty; 2728170222Sdougb int empty_zone = 0; 2729170222Sdougb dns_fixedname_t fixed; 2730170222Sdougb dns_name_t *name; 2731170222Sdougb isc_buffer_t buffer; 2732170222Sdougb const char *str; 2733170222Sdougb char server[DNS_NAME_FORMATSIZE + 1]; 2734170222Sdougb char contact[DNS_NAME_FORMATSIZE + 1]; 2735170222Sdougb isc_boolean_t logit; 2736170222Sdougb const char *empty_dbtype[4] = 2737170222Sdougb { "_builtin", "empty", NULL, NULL }; 2738170222Sdougb int empty_dbtypec = 4; 2739193149Sdougb isc_boolean_t zonestats_on; 2740170222Sdougb 2741170222Sdougb dns_fixedname_init(&fixed); 2742170222Sdougb name = dns_fixedname_name(&fixed); 2743170222Sdougb 2744170222Sdougb obj = NULL; 2745170222Sdougb result = ns_config_get(maps, "empty-server", &obj); 2746170222Sdougb if (result == ISC_R_SUCCESS) { 2747170222Sdougb str = cfg_obj_asstring(obj); 2748170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 2749170222Sdougb isc_buffer_add(&buffer, strlen(str)); 2750224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2751224092Sdougb NULL)); 2752170222Sdougb isc_buffer_init(&buffer, server, sizeof(server) - 1); 2753170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 2754170222Sdougb server[isc_buffer_usedlength(&buffer)] = 0; 2755170222Sdougb empty_dbtype[2] = server; 2756170222Sdougb } else 2757170222Sdougb empty_dbtype[2] = "@"; 2758170222Sdougb 2759170222Sdougb obj = NULL; 2760170222Sdougb result = ns_config_get(maps, "empty-contact", &obj); 2761170222Sdougb if (result == ISC_R_SUCCESS) { 2762170222Sdougb str = cfg_obj_asstring(obj); 2763170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 2764170222Sdougb isc_buffer_add(&buffer, strlen(str)); 2765224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2766224092Sdougb NULL)); 2767170222Sdougb isc_buffer_init(&buffer, contact, sizeof(contact) - 1); 2768170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 2769170222Sdougb contact[isc_buffer_usedlength(&buffer)] = 0; 2770170222Sdougb empty_dbtype[3] = contact; 2771170222Sdougb } else 2772170222Sdougb empty_dbtype[3] = "."; 2773170222Sdougb 2774193149Sdougb obj = NULL; 2775193149Sdougb result = ns_config_get(maps, "zone-statistics", &obj); 2776193149Sdougb INSIST(result == ISC_R_SUCCESS); 2777193149Sdougb zonestats_on = cfg_obj_asboolean(obj); 2778193149Sdougb 2779170222Sdougb logit = ISC_TRUE; 2780170222Sdougb for (empty = empty_zones[empty_zone].zone; 2781170222Sdougb empty != NULL; 2782170222Sdougb empty = empty_zones[++empty_zone].zone) 2783170222Sdougb { 2784170222Sdougb dns_forwarders_t *forwarders = NULL; 2785170222Sdougb dns_view_t *pview = NULL; 2786170222Sdougb 2787170222Sdougb isc_buffer_init(&buffer, empty, strlen(empty)); 2788170222Sdougb isc_buffer_add(&buffer, strlen(empty)); 2789170222Sdougb /* 2790170222Sdougb * Look for zone on drop list. 2791170222Sdougb */ 2792224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 2793224092Sdougb NULL)); 2794170222Sdougb if (disablelist != NULL && 2795170222Sdougb on_disable_list(disablelist, name)) 2796170222Sdougb continue; 2797170222Sdougb 2798170222Sdougb /* 2799170222Sdougb * This zone already exists. 2800170222Sdougb */ 2801170222Sdougb (void)dns_view_findzone(view, name, &zone); 2802170222Sdougb if (zone != NULL) { 2803193149Sdougb CHECK(setquerystats(zone, mctx, zonestats_on)); 2804170222Sdougb dns_zone_detach(&zone); 2805170222Sdougb continue; 2806170222Sdougb } 2807170222Sdougb 2808170222Sdougb /* 2809170222Sdougb * If we would forward this name don't add a 2810170222Sdougb * empty zone for it. 2811170222Sdougb */ 2812170222Sdougb result = dns_fwdtable_find(view->fwdtable, name, 2813170222Sdougb &forwarders); 2814170222Sdougb if (result == ISC_R_SUCCESS && 2815170222Sdougb forwarders->fwdpolicy == dns_fwdpolicy_only) 2816170222Sdougb continue; 2817186462Sdougb 2818170222Sdougb if (!rfc1918 && empty_zones[empty_zone].rfc1918) { 2819170222Sdougb if (logit) { 2820170222Sdougb isc_log_write(ns_g_lctx, 2821170222Sdougb NS_LOGCATEGORY_GENERAL, 2822170222Sdougb NS_LOGMODULE_SERVER, 2823170222Sdougb ISC_LOG_WARNING, 2824186462Sdougb "Warning%s%s: " 2825170222Sdougb "'empty-zones-enable/" 2826170222Sdougb "disable-empty-zone' " 2827170222Sdougb "not set: disabling " 2828170222Sdougb "RFC 1918 empty zones", 2829170222Sdougb sep, viewname); 2830170222Sdougb logit = ISC_FALSE; 2831170222Sdougb } 2832170222Sdougb continue; 2833170222Sdougb } 2834170222Sdougb 2835170222Sdougb /* 2836170222Sdougb * See if we can re-use a existing zone. 2837170222Sdougb */ 2838170222Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 2839170222Sdougb view->name, view->rdclass, 2840170222Sdougb &pview); 2841170222Sdougb if (result != ISC_R_NOTFOUND && 2842170222Sdougb result != ISC_R_SUCCESS) 2843170222Sdougb goto cleanup; 2844170222Sdougb 2845170222Sdougb if (pview != NULL) { 2846170222Sdougb (void)dns_view_findzone(pview, name, &zone); 2847170222Sdougb dns_view_detach(&pview); 2848170222Sdougb if (zone != NULL) 2849170222Sdougb check_dbtype(&zone, empty_dbtypec, 2850170222Sdougb empty_dbtype, mctx); 2851170222Sdougb if (zone != NULL) { 2852170222Sdougb dns_zone_setview(zone, view); 2853174187Sdougb CHECK(dns_view_addzone(view, zone)); 2854193149Sdougb CHECK(setquerystats(zone, mctx, 2855193149Sdougb zonestats_on)); 2856170222Sdougb dns_zone_detach(&zone); 2857170222Sdougb continue; 2858170222Sdougb } 2859170222Sdougb } 2860170222Sdougb 2861170222Sdougb CHECK(dns_zone_create(&zone, mctx)); 2862170222Sdougb CHECK(dns_zone_setorigin(zone, name)); 2863170222Sdougb dns_zone_setview(zone, view); 2864234010Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, 2865234010Sdougb zone)); 2866170222Sdougb dns_zone_setclass(zone, view->rdclass); 2867170222Sdougb dns_zone_settype(zone, dns_zone_master); 2868193149Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 2869170222Sdougb CHECK(dns_zone_setdbtype(zone, empty_dbtypec, 2870186462Sdougb empty_dbtype)); 2871170222Sdougb if (view->queryacl != NULL) 2872170222Sdougb dns_zone_setqueryacl(zone, view->queryacl); 2873193149Sdougb if (view->queryonacl != NULL) 2874193149Sdougb dns_zone_setqueryonacl(zone, view->queryonacl); 2875170222Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 2876170222Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 2877170222Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, 2878170222Sdougb ISC_TRUE); 2879193149Sdougb CHECK(setquerystats(zone, mctx, zonestats_on)); 2880170222Sdougb CHECK(dns_view_addzone(view, zone)); 2881170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2882170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 2883170222Sdougb "automatic empty zone%s%s: %s", 2884170222Sdougb sep, viewname, empty); 2885170222Sdougb dns_zone_detach(&zone); 2886170222Sdougb } 2887170222Sdougb } 2888186462Sdougb 2889224092Sdougb /* 2890224092Sdougb * Make the list of response policy zone names for views that 2891224092Sdougb * are used for real lookups and so care about hints. 2892224092Sdougb */ 2893245163Serwin obj = NULL; 2894245163Serwin if (view->rdclass == dns_rdataclass_in && need_hints && 2895245163Serwin ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) { 2896245163Serwin const cfg_obj_t *recursive_only_obj; 2897245163Serwin const cfg_obj_t *break_dnssec_obj, *ttl_obj; 2898245163Serwin isc_boolean_t recursive_only_def; 2899245163Serwin dns_ttl_t ttl_def; 2900225361Sdougb 2901245163Serwin recursive_only_obj = cfg_tuple_get(obj, "recursive-only"); 2902245163Serwin if (!cfg_obj_isvoid(recursive_only_obj) && 2903245163Serwin !cfg_obj_asboolean(recursive_only_obj)) 2904245163Serwin recursive_only_def = ISC_FALSE; 2905245163Serwin else 2906245163Serwin recursive_only_def = ISC_TRUE; 2907245163Serwin 2908245163Serwin break_dnssec_obj = cfg_tuple_get(obj, "break-dnssec"); 2909245163Serwin if (!cfg_obj_isvoid(break_dnssec_obj) && 2910245163Serwin cfg_obj_asboolean(break_dnssec_obj)) 2911245163Serwin view->rpz_break_dnssec = ISC_TRUE; 2912245163Serwin else 2913245163Serwin view->rpz_break_dnssec = ISC_FALSE; 2914245163Serwin 2915245163Serwin ttl_obj = cfg_tuple_get(obj, "max-policy-ttl"); 2916245163Serwin if (cfg_obj_isuint32(ttl_obj)) 2917245163Serwin ttl_def = cfg_obj_asuint32(ttl_obj); 2918245163Serwin else 2919245163Serwin ttl_def = DNS_RPZ_MAX_TTL_DEFAULT; 2920245163Serwin 2921245163Serwin for (element = cfg_list_first(cfg_tuple_get(obj, "zone list")); 2922224092Sdougb element != NULL; 2923224092Sdougb element = cfg_list_next(element)) { 2924245163Serwin result = configure_rpz(view, element, 2925245163Serwin recursive_only_def, ttl_def); 2926224092Sdougb if (result != ISC_R_SUCCESS) 2927224092Sdougb goto cleanup; 2928224092Sdougb dns_rpz_set_need(ISC_TRUE); 2929224092Sdougb } 2930224092Sdougb } 2931224092Sdougb 2932135446Strhodes result = ISC_R_SUCCESS; 2933135446Strhodes 2934135446Strhodes cleanup: 2935224092Sdougb if (clients != NULL) 2936224092Sdougb dns_acl_detach(&clients); 2937224092Sdougb if (mapped != NULL) 2938224092Sdougb dns_acl_detach(&mapped); 2939224092Sdougb if (excluded != NULL) 2940224092Sdougb dns_acl_detach(&excluded); 2941224092Sdougb if (ring != NULL) 2942224092Sdougb dns_tsigkeyring_detach(&ring); 2943170222Sdougb if (zone != NULL) 2944170222Sdougb dns_zone_detach(&zone); 2945135446Strhodes if (dispatch4 != NULL) 2946135446Strhodes dns_dispatch_detach(&dispatch4); 2947135446Strhodes if (dispatch6 != NULL) 2948135446Strhodes dns_dispatch_detach(&dispatch6); 2949193149Sdougb if (resstats != NULL) 2950193149Sdougb isc_stats_detach(&resstats); 2951193149Sdougb if (resquerystats != NULL) 2952193149Sdougb dns_stats_detach(&resquerystats); 2953135446Strhodes if (order != NULL) 2954135446Strhodes dns_order_detach(&order); 2955135446Strhodes if (cmctx != NULL) 2956135446Strhodes isc_mem_detach(&cmctx); 2957225361Sdougb if (hmctx != NULL) 2958225361Sdougb isc_mem_detach(&hmctx); 2959135446Strhodes 2960135446Strhodes if (cache != NULL) 2961135446Strhodes dns_cache_detach(&cache); 2962135446Strhodes 2963135446Strhodes return (result); 2964135446Strhodes} 2965135446Strhodes 2966135446Strhodesstatic isc_result_t 2967135446Strhodesconfigure_hints(dns_view_t *view, const char *filename) { 2968135446Strhodes isc_result_t result; 2969135446Strhodes dns_db_t *db; 2970135446Strhodes 2971135446Strhodes db = NULL; 2972135446Strhodes result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 2973135446Strhodes if (result == ISC_R_SUCCESS) { 2974135446Strhodes dns_view_sethints(view, db); 2975135446Strhodes dns_db_detach(&db); 2976135446Strhodes } 2977135446Strhodes 2978135446Strhodes return (result); 2979135446Strhodes} 2980135446Strhodes 2981135446Strhodesstatic isc_result_t 2982165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 2983165071Sdougb const cfg_obj_t *alternates) 2984135446Strhodes{ 2985165071Sdougb const cfg_obj_t *portobj; 2986165071Sdougb const cfg_obj_t *addresses; 2987165071Sdougb const cfg_listelt_t *element; 2988135446Strhodes isc_result_t result = ISC_R_SUCCESS; 2989135446Strhodes in_port_t port; 2990135446Strhodes 2991135446Strhodes /* 2992135446Strhodes * Determine which port to send requests to. 2993135446Strhodes */ 2994135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 2995135446Strhodes port = ns_g_port; 2996135446Strhodes else 2997135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 2998135446Strhodes 2999135446Strhodes if (alternates != NULL) { 3000135446Strhodes portobj = cfg_tuple_get(alternates, "port"); 3001135446Strhodes if (cfg_obj_isuint32(portobj)) { 3002135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3003135446Strhodes if (val > ISC_UINT16_MAX) { 3004135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3005135446Strhodes "port '%u' out of range", val); 3006135446Strhodes return (ISC_R_RANGE); 3007135446Strhodes } 3008135446Strhodes port = (in_port_t) val; 3009135446Strhodes } 3010135446Strhodes } 3011135446Strhodes 3012135446Strhodes addresses = NULL; 3013135446Strhodes if (alternates != NULL) 3014135446Strhodes addresses = cfg_tuple_get(alternates, "addresses"); 3015135446Strhodes 3016135446Strhodes for (element = cfg_list_first(addresses); 3017135446Strhodes element != NULL; 3018135446Strhodes element = cfg_list_next(element)) 3019135446Strhodes { 3020165071Sdougb const cfg_obj_t *alternate = cfg_listelt_value(element); 3021135446Strhodes isc_sockaddr_t sa; 3022135446Strhodes 3023135446Strhodes if (!cfg_obj_issockaddr(alternate)) { 3024135446Strhodes dns_fixedname_t fixed; 3025135446Strhodes dns_name_t *name; 3026165071Sdougb const char *str = cfg_obj_asstring(cfg_tuple_get( 3027165071Sdougb alternate, "name")); 3028135446Strhodes isc_buffer_t buffer; 3029135446Strhodes in_port_t myport = port; 3030135446Strhodes 3031135446Strhodes isc_buffer_init(&buffer, str, strlen(str)); 3032135446Strhodes isc_buffer_add(&buffer, strlen(str)); 3033135446Strhodes dns_fixedname_init(&fixed); 3034135446Strhodes name = dns_fixedname_name(&fixed); 3035224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3036224092Sdougb NULL)); 3037135446Strhodes 3038135446Strhodes portobj = cfg_tuple_get(alternate, "port"); 3039135446Strhodes if (cfg_obj_isuint32(portobj)) { 3040135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3041135446Strhodes if (val > ISC_UINT16_MAX) { 3042135446Strhodes cfg_obj_log(portobj, ns_g_lctx, 3043135446Strhodes ISC_LOG_ERROR, 3044135446Strhodes "port '%u' out of range", 3045135446Strhodes val); 3046135446Strhodes return (ISC_R_RANGE); 3047135446Strhodes } 3048135446Strhodes myport = (in_port_t) val; 3049135446Strhodes } 3050135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, NULL, 3051135446Strhodes name, myport)); 3052135446Strhodes continue; 3053135446Strhodes } 3054135446Strhodes 3055135446Strhodes sa = *cfg_obj_assockaddr(alternate); 3056135446Strhodes if (isc_sockaddr_getport(&sa) == 0) 3057135446Strhodes isc_sockaddr_setport(&sa, port); 3058135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, &sa, 3059135446Strhodes NULL, 0)); 3060135446Strhodes } 3061135446Strhodes 3062135446Strhodes cleanup: 3063135446Strhodes return (result); 3064135446Strhodes} 3065135446Strhodes 3066135446Strhodesstatic isc_result_t 3067165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 3068165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 3069135446Strhodes{ 3070165071Sdougb const cfg_obj_t *portobj; 3071165071Sdougb const cfg_obj_t *faddresses; 3072165071Sdougb const cfg_listelt_t *element; 3073135446Strhodes dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 3074135446Strhodes isc_sockaddrlist_t addresses; 3075135446Strhodes isc_sockaddr_t *sa; 3076135446Strhodes isc_result_t result; 3077135446Strhodes in_port_t port; 3078135446Strhodes 3079193149Sdougb ISC_LIST_INIT(addresses); 3080193149Sdougb 3081135446Strhodes /* 3082135446Strhodes * Determine which port to send forwarded requests to. 3083135446Strhodes */ 3084135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 3085135446Strhodes port = ns_g_port; 3086135446Strhodes else 3087135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 3088135446Strhodes 3089135446Strhodes if (forwarders != NULL) { 3090135446Strhodes portobj = cfg_tuple_get(forwarders, "port"); 3091135446Strhodes if (cfg_obj_isuint32(portobj)) { 3092135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3093135446Strhodes if (val > ISC_UINT16_MAX) { 3094135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3095135446Strhodes "port '%u' out of range", val); 3096135446Strhodes return (ISC_R_RANGE); 3097135446Strhodes } 3098135446Strhodes port = (in_port_t) val; 3099135446Strhodes } 3100135446Strhodes } 3101135446Strhodes 3102135446Strhodes faddresses = NULL; 3103135446Strhodes if (forwarders != NULL) 3104135446Strhodes faddresses = cfg_tuple_get(forwarders, "addresses"); 3105135446Strhodes 3106135446Strhodes for (element = cfg_list_first(faddresses); 3107135446Strhodes element != NULL; 3108135446Strhodes element = cfg_list_next(element)) 3109135446Strhodes { 3110165071Sdougb const cfg_obj_t *forwarder = cfg_listelt_value(element); 3111135446Strhodes sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 3112135446Strhodes if (sa == NULL) { 3113135446Strhodes result = ISC_R_NOMEMORY; 3114135446Strhodes goto cleanup; 3115135446Strhodes } 3116135446Strhodes *sa = *cfg_obj_assockaddr(forwarder); 3117135446Strhodes if (isc_sockaddr_getport(sa) == 0) 3118135446Strhodes isc_sockaddr_setport(sa, port); 3119135446Strhodes ISC_LINK_INIT(sa, link); 3120135446Strhodes ISC_LIST_APPEND(addresses, sa, link); 3121135446Strhodes } 3122135446Strhodes 3123135446Strhodes if (ISC_LIST_EMPTY(addresses)) { 3124135446Strhodes if (forwardtype != NULL) 3125135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3126135446Strhodes "no forwarders seen; disabling " 3127135446Strhodes "forwarding"); 3128135446Strhodes fwdpolicy = dns_fwdpolicy_none; 3129135446Strhodes } else { 3130135446Strhodes if (forwardtype == NULL) 3131135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3132135446Strhodes else { 3133165071Sdougb const char *forwardstr = cfg_obj_asstring(forwardtype); 3134135446Strhodes if (strcasecmp(forwardstr, "first") == 0) 3135135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3136135446Strhodes else if (strcasecmp(forwardstr, "only") == 0) 3137135446Strhodes fwdpolicy = dns_fwdpolicy_only; 3138135446Strhodes else 3139135446Strhodes INSIST(0); 3140135446Strhodes } 3141135446Strhodes } 3142135446Strhodes 3143135446Strhodes result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 3144135446Strhodes fwdpolicy); 3145135446Strhodes if (result != ISC_R_SUCCESS) { 3146135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 3147135446Strhodes dns_name_format(origin, namebuf, sizeof(namebuf)); 3148135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3149135446Strhodes "could not set up forwarding for domain '%s': %s", 3150135446Strhodes namebuf, isc_result_totext(result)); 3151135446Strhodes goto cleanup; 3152135446Strhodes } 3153135446Strhodes 3154135446Strhodes result = ISC_R_SUCCESS; 3155135446Strhodes 3156135446Strhodes cleanup: 3157135446Strhodes 3158135446Strhodes while (!ISC_LIST_EMPTY(addresses)) { 3159135446Strhodes sa = ISC_LIST_HEAD(addresses); 3160135446Strhodes ISC_LIST_UNLINK(addresses, sa, link); 3161135446Strhodes isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 3162135446Strhodes } 3163135446Strhodes 3164135446Strhodes return (result); 3165135446Strhodes} 3166135446Strhodes 3167135446Strhodesstatic isc_result_t 3168225361Sdougbget_viewinfo(const cfg_obj_t *vconfig, const char **namep, 3169225361Sdougb dns_rdataclass_t *classp) 3170165071Sdougb{ 3171225361Sdougb isc_result_t result = ISC_R_SUCCESS; 3172135446Strhodes const char *viewname; 3173135446Strhodes dns_rdataclass_t viewclass; 3174135446Strhodes 3175225361Sdougb REQUIRE(namep != NULL && *namep == NULL); 3176225361Sdougb REQUIRE(classp != NULL); 3177225361Sdougb 3178135446Strhodes if (vconfig != NULL) { 3179165071Sdougb const cfg_obj_t *classobj = NULL; 3180135446Strhodes 3181135446Strhodes viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 3182135446Strhodes classobj = cfg_tuple_get(vconfig, "class"); 3183135446Strhodes result = ns_config_getclass(classobj, dns_rdataclass_in, 3184135446Strhodes &viewclass); 3185135446Strhodes } else { 3186135446Strhodes viewname = "_default"; 3187135446Strhodes viewclass = dns_rdataclass_in; 3188135446Strhodes } 3189225361Sdougb 3190225361Sdougb *namep = viewname; 3191225361Sdougb *classp = viewclass; 3192225361Sdougb 3193225361Sdougb return (result); 3194225361Sdougb} 3195225361Sdougb 3196225361Sdougb/* 3197225361Sdougb * Find a view based on its configuration info and attach to it. 3198225361Sdougb * 3199225361Sdougb * If 'vconfig' is NULL, attach to the default view. 3200225361Sdougb */ 3201225361Sdougbstatic isc_result_t 3202225361Sdougbfind_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3203225361Sdougb dns_view_t **viewp) 3204225361Sdougb{ 3205225361Sdougb isc_result_t result; 3206225361Sdougb const char *viewname = NULL; 3207225361Sdougb dns_rdataclass_t viewclass; 3208225361Sdougb dns_view_t *view = NULL; 3209225361Sdougb 3210225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3211225361Sdougb if (result != ISC_R_SUCCESS) 3212225361Sdougb return (result); 3213225361Sdougb 3214135446Strhodes result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3215225361Sdougb if (result != ISC_R_SUCCESS) 3216225361Sdougb return (result); 3217225361Sdougb 3218225361Sdougb *viewp = view; 3219225361Sdougb return (ISC_R_SUCCESS); 3220225361Sdougb} 3221225361Sdougb 3222225361Sdougb/* 3223225361Sdougb * Create a new view and add it to the list. 3224225361Sdougb * 3225225361Sdougb * If 'vconfig' is NULL, create the default view. 3226225361Sdougb * 3227225361Sdougb * The view created is attached to '*viewp'. 3228225361Sdougb */ 3229225361Sdougbstatic isc_result_t 3230225361Sdougbcreate_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3231225361Sdougb dns_view_t **viewp) 3232225361Sdougb{ 3233225361Sdougb isc_result_t result; 3234225361Sdougb const char *viewname = NULL; 3235225361Sdougb dns_rdataclass_t viewclass; 3236225361Sdougb dns_view_t *view = NULL; 3237225361Sdougb 3238225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3239225361Sdougb if (result != ISC_R_SUCCESS) 3240225361Sdougb return (result); 3241225361Sdougb 3242225361Sdougb result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3243135446Strhodes if (result == ISC_R_SUCCESS) 3244135446Strhodes return (ISC_R_EXISTS); 3245135446Strhodes if (result != ISC_R_NOTFOUND) 3246135446Strhodes return (result); 3247135446Strhodes INSIST(view == NULL); 3248135446Strhodes 3249135446Strhodes result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 3250135446Strhodes if (result != ISC_R_SUCCESS) 3251135446Strhodes return (result); 3252135446Strhodes 3253135446Strhodes ISC_LIST_APPEND(*viewlist, view, link); 3254135446Strhodes dns_view_attach(view, viewp); 3255135446Strhodes return (ISC_R_SUCCESS); 3256135446Strhodes} 3257135446Strhodes 3258135446Strhodes/* 3259135446Strhodes * Configure or reconfigure a zone. 3260135446Strhodes */ 3261135446Strhodesstatic isc_result_t 3262165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 3263165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 3264224092Sdougb cfg_aclconfctx_t *aclconf, isc_boolean_t added) 3265135446Strhodes{ 3266135446Strhodes dns_view_t *pview = NULL; /* Production view */ 3267135446Strhodes dns_zone_t *zone = NULL; /* New or reused zone */ 3268135446Strhodes dns_zone_t *dupzone = NULL; 3269165071Sdougb const cfg_obj_t *options = NULL; 3270165071Sdougb const cfg_obj_t *zoptions = NULL; 3271165071Sdougb const cfg_obj_t *typeobj = NULL; 3272165071Sdougb const cfg_obj_t *forwarders = NULL; 3273165071Sdougb const cfg_obj_t *forwardtype = NULL; 3274165071Sdougb const cfg_obj_t *only = NULL; 3275135446Strhodes isc_result_t result; 3276135446Strhodes isc_result_t tresult; 3277135446Strhodes isc_buffer_t buffer; 3278135446Strhodes dns_fixedname_t fixorigin; 3279135446Strhodes dns_name_t *origin; 3280135446Strhodes const char *zname; 3281135446Strhodes dns_rdataclass_t zclass; 3282135446Strhodes const char *ztypestr; 3283135446Strhodes 3284135446Strhodes options = NULL; 3285135446Strhodes (void)cfg_map_get(config, "options", &options); 3286135446Strhodes 3287135446Strhodes zoptions = cfg_tuple_get(zconfig, "options"); 3288135446Strhodes 3289135446Strhodes /* 3290135446Strhodes * Get the zone origin as a dns_name_t. 3291135446Strhodes */ 3292135446Strhodes zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 3293135446Strhodes isc_buffer_init(&buffer, zname, strlen(zname)); 3294135446Strhodes isc_buffer_add(&buffer, strlen(zname)); 3295135446Strhodes dns_fixedname_init(&fixorigin); 3296135446Strhodes CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 3297224092Sdougb &buffer, dns_rootname, 0, NULL)); 3298135446Strhodes origin = dns_fixedname_name(&fixorigin); 3299135446Strhodes 3300135446Strhodes CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 3301135446Strhodes view->rdclass, &zclass)); 3302135446Strhodes if (zclass != view->rdclass) { 3303135446Strhodes const char *vname = NULL; 3304135446Strhodes if (vconfig != NULL) 3305135446Strhodes vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 3306135446Strhodes "name")); 3307135446Strhodes else 3308135446Strhodes vname = "<default view>"; 3309186462Sdougb 3310135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3311135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3312135446Strhodes "zone '%s': wrong class for view '%s'", 3313135446Strhodes zname, vname); 3314135446Strhodes result = ISC_R_FAILURE; 3315135446Strhodes goto cleanup; 3316135446Strhodes } 3317135446Strhodes 3318135446Strhodes (void)cfg_map_get(zoptions, "type", &typeobj); 3319135446Strhodes if (typeobj == NULL) { 3320135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3321135446Strhodes "zone '%s' 'type' not specified", zname); 3322135446Strhodes return (ISC_R_FAILURE); 3323135446Strhodes } 3324135446Strhodes ztypestr = cfg_obj_asstring(typeobj); 3325135446Strhodes 3326135446Strhodes /* 3327224092Sdougb * "hints zones" aren't zones. If we've got one, 3328135446Strhodes * configure it and return. 3329135446Strhodes */ 3330135446Strhodes if (strcasecmp(ztypestr, "hint") == 0) { 3331165071Sdougb const cfg_obj_t *fileobj = NULL; 3332135446Strhodes if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 3333135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3334135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3335135446Strhodes "zone '%s': 'file' not specified", 3336135446Strhodes zname); 3337135446Strhodes result = ISC_R_FAILURE; 3338135446Strhodes goto cleanup; 3339135446Strhodes } 3340135446Strhodes if (dns_name_equal(origin, dns_rootname)) { 3341165071Sdougb const char *hintsfile = cfg_obj_asstring(fileobj); 3342135446Strhodes 3343135446Strhodes result = configure_hints(view, hintsfile); 3344135446Strhodes if (result != ISC_R_SUCCESS) { 3345135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3346135446Strhodes NS_LOGMODULE_SERVER, 3347135446Strhodes ISC_LOG_ERROR, 3348135446Strhodes "could not configure root hints " 3349135446Strhodes "from '%s': %s", hintsfile, 3350135446Strhodes isc_result_totext(result)); 3351135446Strhodes goto cleanup; 3352135446Strhodes } 3353135446Strhodes /* 3354135446Strhodes * Hint zones may also refer to delegation only points. 3355135446Strhodes */ 3356135446Strhodes only = NULL; 3357135446Strhodes tresult = cfg_map_get(zoptions, "delegation-only", 3358135446Strhodes &only); 3359135446Strhodes if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 3360135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 3361135446Strhodes } else { 3362135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3363135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3364135446Strhodes "ignoring non-root hint zone '%s'", 3365135446Strhodes zname); 3366135446Strhodes result = ISC_R_SUCCESS; 3367135446Strhodes } 3368135446Strhodes /* Skip ordinary zone processing. */ 3369135446Strhodes goto cleanup; 3370135446Strhodes } 3371135446Strhodes 3372135446Strhodes /* 3373135446Strhodes * "forward zones" aren't zones either. Translate this syntax into 3374135446Strhodes * the appropriate selective forwarding configuration and return. 3375135446Strhodes */ 3376135446Strhodes if (strcasecmp(ztypestr, "forward") == 0) { 3377135446Strhodes forwardtype = NULL; 3378135446Strhodes forwarders = NULL; 3379135446Strhodes 3380135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 3381135446Strhodes (void)cfg_map_get(zoptions, "forwarders", &forwarders); 3382135446Strhodes result = configure_forward(config, view, origin, forwarders, 3383135446Strhodes forwardtype); 3384135446Strhodes goto cleanup; 3385135446Strhodes } 3386135446Strhodes 3387135446Strhodes /* 3388135446Strhodes * "delegation-only zones" aren't zones either. 3389135446Strhodes */ 3390135446Strhodes if (strcasecmp(ztypestr, "delegation-only") == 0) { 3391135446Strhodes result = dns_view_adddelegationonly(view, origin); 3392135446Strhodes goto cleanup; 3393135446Strhodes } 3394135446Strhodes 3395135446Strhodes /* 3396135446Strhodes * Check for duplicates in the new zone table. 3397135446Strhodes */ 3398135446Strhodes result = dns_view_findzone(view, origin, &dupzone); 3399135446Strhodes if (result == ISC_R_SUCCESS) { 3400135446Strhodes /* 3401135446Strhodes * We already have this zone! 3402135446Strhodes */ 3403135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3404135446Strhodes "zone '%s' already exists", zname); 3405135446Strhodes dns_zone_detach(&dupzone); 3406135446Strhodes result = ISC_R_EXISTS; 3407135446Strhodes goto cleanup; 3408135446Strhodes } 3409135446Strhodes INSIST(dupzone == NULL); 3410135446Strhodes 3411135446Strhodes /* 3412135446Strhodes * See if we can reuse an existing zone. This is 3413135446Strhodes * only possible if all of these are true: 3414135446Strhodes * - The zone's view exists 3415135446Strhodes * - A zone with the right name exists in the view 3416135446Strhodes * - The zone is compatible with the config 3417135446Strhodes * options (e.g., an existing master zone cannot 3418135446Strhodes * be reused if the options specify a slave zone) 3419135446Strhodes */ 3420135446Strhodes result = dns_viewlist_find(&ns_g_server->viewlist, 3421135446Strhodes view->name, view->rdclass, 3422135446Strhodes &pview); 3423135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3424135446Strhodes goto cleanup; 3425135446Strhodes if (pview != NULL) 3426135446Strhodes result = dns_view_findzone(pview, origin, &zone); 3427135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3428135446Strhodes goto cleanup; 3429170222Sdougb if (zone != NULL && !ns_zone_reusable(zone, zconfig)) 3430170222Sdougb dns_zone_detach(&zone); 3431135446Strhodes 3432135446Strhodes if (zone != NULL) { 3433135446Strhodes /* 3434135446Strhodes * We found a reusable zone. Make it use the 3435135446Strhodes * new view. 3436135446Strhodes */ 3437135446Strhodes dns_zone_setview(zone, view); 3438170222Sdougb if (view->acache != NULL) 3439170222Sdougb dns_zone_setacache(zone, view->acache); 3440135446Strhodes } else { 3441135446Strhodes /* 3442135446Strhodes * We cannot reuse an existing zone, we have 3443135446Strhodes * to create a new one. 3444135446Strhodes */ 3445135446Strhodes CHECK(dns_zone_create(&zone, mctx)); 3446135446Strhodes CHECK(dns_zone_setorigin(zone, origin)); 3447135446Strhodes dns_zone_setview(zone, view); 3448170222Sdougb if (view->acache != NULL) 3449170222Sdougb dns_zone_setacache(zone, view->acache); 3450135446Strhodes CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 3451193149Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 3452135446Strhodes } 3453135446Strhodes 3454135446Strhodes /* 3455135446Strhodes * If the zone contains a 'forwarders' statement, configure 3456135446Strhodes * selective forwarding. 3457135446Strhodes */ 3458135446Strhodes forwarders = NULL; 3459135446Strhodes if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 3460135446Strhodes { 3461135446Strhodes forwardtype = NULL; 3462135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 3463135446Strhodes CHECK(configure_forward(config, view, origin, forwarders, 3464135446Strhodes forwardtype)); 3465135446Strhodes } 3466135446Strhodes 3467135446Strhodes /* 3468135446Strhodes * Stub and forward zones may also refer to delegation only points. 3469135446Strhodes */ 3470135446Strhodes only = NULL; 3471135446Strhodes if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 3472135446Strhodes { 3473135446Strhodes if (cfg_obj_asboolean(only)) 3474135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 3475135446Strhodes } 3476135446Strhodes 3477135446Strhodes /* 3478224092Sdougb * Mark whether the zone was originally added at runtime or not 3479224092Sdougb */ 3480224092Sdougb dns_zone_setadded(zone, added); 3481224092Sdougb 3482224092Sdougb /* 3483135446Strhodes * Configure the zone. 3484135446Strhodes */ 3485135446Strhodes CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); 3486135446Strhodes 3487135446Strhodes /* 3488135446Strhodes * Add the zone to its view in the new view list. 3489135446Strhodes */ 3490135446Strhodes CHECK(dns_view_addzone(view, zone)); 3491135446Strhodes 3492234010Sdougb /* 3493234010Sdougb * Ensure that zone keys are reloaded on reconfig 3494234010Sdougb */ 3495234010Sdougb if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) 3496234010Sdougb dns_zone_rekey(zone, ISC_FALSE); 3497234010Sdougb 3498135446Strhodes cleanup: 3499135446Strhodes if (zone != NULL) 3500135446Strhodes dns_zone_detach(&zone); 3501135446Strhodes if (pview != NULL) 3502135446Strhodes dns_view_detach(&pview); 3503135446Strhodes 3504135446Strhodes return (result); 3505135446Strhodes} 3506135446Strhodes 3507135446Strhodes/* 3508224092Sdougb * Configure built-in zone for storing managed-key data. 3509224092Sdougb */ 3510224092Sdougb 3511224092Sdougb#define KEYZONE "managed-keys.bind" 3512224092Sdougb#define MKEYS ".mkeys" 3513224092Sdougb 3514224092Sdougbstatic isc_result_t 3515224092Sdougbadd_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { 3516224092Sdougb isc_result_t result; 3517224092Sdougb dns_view_t *pview = NULL; 3518224092Sdougb dns_zone_t *zone = NULL; 3519224092Sdougb dns_acl_t *none = NULL; 3520224092Sdougb char filename[PATH_MAX]; 3521224092Sdougb char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)]; 3522224092Sdougb int n; 3523224092Sdougb 3524224092Sdougb REQUIRE(view != NULL); 3525224092Sdougb 3526224092Sdougb /* See if we can re-use an existing keydata zone. */ 3527224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 3528224092Sdougb view->name, view->rdclass, 3529224092Sdougb &pview); 3530224092Sdougb if (result != ISC_R_NOTFOUND && 3531224092Sdougb result != ISC_R_SUCCESS) 3532224092Sdougb return (result); 3533224092Sdougb 3534224092Sdougb if (pview != NULL && pview->managed_keys != NULL) { 3535224092Sdougb dns_zone_attach(pview->managed_keys, &view->managed_keys); 3536224092Sdougb dns_zone_setview(pview->managed_keys, view); 3537224092Sdougb dns_view_detach(&pview); 3538234010Sdougb dns_zone_synckeyzone(view->managed_keys); 3539224092Sdougb return (ISC_R_SUCCESS); 3540224092Sdougb } 3541224092Sdougb 3542224092Sdougb /* No existing keydata zone was found; create one */ 3543224092Sdougb CHECK(dns_zone_create(&zone, mctx)); 3544224092Sdougb CHECK(dns_zone_setorigin(zone, dns_rootname)); 3545224092Sdougb 3546224092Sdougb isc_sha256_data((void *)view->name, strlen(view->name), buffer); 3547224092Sdougb strcat(buffer, MKEYS); 3548224092Sdougb n = snprintf(filename, sizeof(filename), "%s%s%s", 3549224092Sdougb directory ? directory : "", directory ? "/" : "", 3550224092Sdougb strcmp(view->name, "_default") == 0 ? KEYZONE : buffer); 3551224092Sdougb if (n < 0 || (size_t)n >= sizeof(filename)) { 3552224092Sdougb result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE; 3553224092Sdougb goto cleanup; 3554224092Sdougb } 3555224092Sdougb CHECK(dns_zone_setfile(zone, filename)); 3556224092Sdougb 3557224092Sdougb dns_zone_setview(zone, view); 3558224092Sdougb dns_zone_settype(zone, dns_zone_key); 3559224092Sdougb dns_zone_setclass(zone, view->rdclass); 3560224092Sdougb 3561224092Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 3562224092Sdougb 3563224092Sdougb if (view->acache != NULL) 3564224092Sdougb dns_zone_setacache(zone, view->acache); 3565224092Sdougb 3566224092Sdougb CHECK(dns_acl_none(mctx, &none)); 3567224092Sdougb dns_zone_setqueryacl(zone, none); 3568224092Sdougb dns_zone_setqueryonacl(zone, none); 3569224092Sdougb dns_acl_detach(&none); 3570224092Sdougb 3571224092Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 3572224092Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 3573224092Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 3574224092Sdougb dns_zone_setjournalsize(zone, 0); 3575224092Sdougb 3576224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 3577224092Sdougb CHECK(setquerystats(zone, mctx, ISC_FALSE)); 3578224092Sdougb 3579224092Sdougb if (view->managed_keys != NULL) 3580224092Sdougb dns_zone_detach(&view->managed_keys); 3581224092Sdougb dns_zone_attach(zone, &view->managed_keys); 3582224092Sdougb 3583224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3584224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3585224092Sdougb "set up managed keys zone for view %s, file '%s'", 3586224092Sdougb view->name, filename); 3587224092Sdougb 3588224092Sdougbcleanup: 3589224092Sdougb if (zone != NULL) 3590224092Sdougb dns_zone_detach(&zone); 3591224092Sdougb if (none != NULL) 3592224092Sdougb dns_acl_detach(&none); 3593224092Sdougb 3594224092Sdougb return (result); 3595224092Sdougb} 3596224092Sdougb 3597224092Sdougb/* 3598135446Strhodes * Configure a single server quota. 3599135446Strhodes */ 3600135446Strhodesstatic void 3601165071Sdougbconfigure_server_quota(const cfg_obj_t **maps, const char *name, 3602165071Sdougb isc_quota_t *quota) 3603135446Strhodes{ 3604165071Sdougb const cfg_obj_t *obj = NULL; 3605135446Strhodes isc_result_t result; 3606135446Strhodes 3607135446Strhodes result = ns_config_get(maps, name, &obj); 3608135446Strhodes INSIST(result == ISC_R_SUCCESS); 3609153816Sdougb isc_quota_max(quota, cfg_obj_asuint32(obj)); 3610135446Strhodes} 3611135446Strhodes 3612135446Strhodes/* 3613135446Strhodes * This function is called as soon as the 'directory' statement has been 3614135446Strhodes * parsed. This can be extended to support other options if necessary. 3615135446Strhodes */ 3616135446Strhodesstatic isc_result_t 3617165071Sdougbdirectory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 3618135446Strhodes isc_result_t result; 3619165071Sdougb const char *directory; 3620135446Strhodes 3621135446Strhodes REQUIRE(strcasecmp("directory", clausename) == 0); 3622135446Strhodes 3623135446Strhodes UNUSED(arg); 3624135446Strhodes UNUSED(clausename); 3625135446Strhodes 3626135446Strhodes /* 3627135446Strhodes * Change directory. 3628135446Strhodes */ 3629135446Strhodes directory = cfg_obj_asstring(obj); 3630135446Strhodes 3631135446Strhodes if (! isc_file_ischdiridempotent(directory)) 3632135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 3633135446Strhodes "option 'directory' contains relative path '%s'", 3634135446Strhodes directory); 3635135446Strhodes 3636135446Strhodes result = isc_dir_chdir(directory); 3637135446Strhodes if (result != ISC_R_SUCCESS) { 3638135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 3639135446Strhodes "change directory to '%s' failed: %s", 3640135446Strhodes directory, isc_result_totext(result)); 3641135446Strhodes return (result); 3642135446Strhodes } 3643135446Strhodes 3644135446Strhodes return (ISC_R_SUCCESS); 3645135446Strhodes} 3646135446Strhodes 3647135446Strhodesstatic void 3648135446Strhodesscan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 3649135446Strhodes isc_boolean_t match_mapped = server->aclenv.match_mapped; 3650135446Strhodes 3651135446Strhodes ns_interfacemgr_scan(server->interfacemgr, verbose); 3652135446Strhodes /* 3653135446Strhodes * Update the "localhost" and "localnets" ACLs to match the 3654135446Strhodes * current set of network interfaces. 3655135446Strhodes */ 3656135446Strhodes dns_aclenv_copy(&server->aclenv, 3657135446Strhodes ns_interfacemgr_getaclenv(server->interfacemgr)); 3658135446Strhodes 3659135446Strhodes server->aclenv.match_mapped = match_mapped; 3660135446Strhodes} 3661135446Strhodes 3662135446Strhodesstatic isc_result_t 3663180477Sdougbadd_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, 3664180477Sdougb isc_boolean_t wcardport_ok) 3665180477Sdougb{ 3666135446Strhodes ns_listenelt_t *lelt = NULL; 3667135446Strhodes dns_acl_t *src_acl = NULL; 3668135446Strhodes isc_result_t result; 3669135446Strhodes isc_sockaddr_t any_sa6; 3670193149Sdougb isc_netaddr_t netaddr; 3671135446Strhodes 3672135446Strhodes REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 3673135446Strhodes 3674135446Strhodes isc_sockaddr_any6(&any_sa6); 3675180477Sdougb if (!isc_sockaddr_equal(&any_sa6, addr) && 3676180477Sdougb (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { 3677193149Sdougb isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr); 3678135446Strhodes 3679193149Sdougb result = dns_acl_create(mctx, 0, &src_acl); 3680135446Strhodes if (result != ISC_R_SUCCESS) 3681135446Strhodes return (result); 3682193149Sdougb 3683193149Sdougb result = dns_iptable_addprefix(src_acl->iptable, 3684193149Sdougb &netaddr, 128, ISC_TRUE); 3685135446Strhodes if (result != ISC_R_SUCCESS) 3686135446Strhodes goto clean; 3687135446Strhodes 3688135446Strhodes result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 3689135446Strhodes src_acl, &lelt); 3690135446Strhodes if (result != ISC_R_SUCCESS) 3691135446Strhodes goto clean; 3692135446Strhodes ISC_LIST_APPEND(list->elts, lelt, link); 3693135446Strhodes } 3694135446Strhodes 3695135446Strhodes return (ISC_R_SUCCESS); 3696135446Strhodes 3697135446Strhodes clean: 3698135446Strhodes INSIST(lelt == NULL); 3699165071Sdougb dns_acl_detach(&src_acl); 3700135446Strhodes 3701135446Strhodes return (result); 3702135446Strhodes} 3703135446Strhodes 3704135446Strhodes/* 3705135446Strhodes * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 3706135446Strhodes * to update the listening interfaces accordingly. 3707135446Strhodes * We currently only consider IPv6, because this only affects IPv6 wildcard 3708135446Strhodes * sockets. 3709135446Strhodes */ 3710135446Strhodesstatic void 3711135446Strhodesadjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 3712135446Strhodes isc_result_t result; 3713135446Strhodes ns_listenlist_t *list = NULL; 3714135446Strhodes dns_view_t *view; 3715135446Strhodes dns_zone_t *zone, *next; 3716135446Strhodes isc_sockaddr_t addr, *addrp; 3717135446Strhodes 3718135446Strhodes result = ns_listenlist_create(mctx, &list); 3719135446Strhodes if (result != ISC_R_SUCCESS) 3720135446Strhodes return; 3721135446Strhodes 3722135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3723135446Strhodes view != NULL; 3724135446Strhodes view = ISC_LIST_NEXT(view, link)) { 3725135446Strhodes dns_dispatch_t *dispatch6; 3726135446Strhodes 3727135446Strhodes dispatch6 = dns_resolver_dispatchv6(view->resolver); 3728143731Sdougb if (dispatch6 == NULL) 3729143731Sdougb continue; 3730135446Strhodes result = dns_dispatch_getlocaladdress(dispatch6, &addr); 3731135446Strhodes if (result != ISC_R_SUCCESS) 3732135446Strhodes goto fail; 3733180477Sdougb 3734180477Sdougb /* 3735180477Sdougb * We always add non-wildcard address regardless of whether 3736180477Sdougb * the port is 'any' (the fourth arg is TRUE): if the port is 3737180477Sdougb * specific, we need to add it since it may conflict with a 3738180477Sdougb * listening interface; if it's zero, we'll dynamically open 3739180477Sdougb * query ports, and some of them may override an existing 3740180477Sdougb * wildcard IPv6 port. 3741180477Sdougb */ 3742180477Sdougb result = add_listenelt(mctx, list, &addr, ISC_TRUE); 3743135446Strhodes if (result != ISC_R_SUCCESS) 3744135446Strhodes goto fail; 3745135446Strhodes } 3746135446Strhodes 3747135446Strhodes zone = NULL; 3748135446Strhodes for (result = dns_zone_first(server->zonemgr, &zone); 3749135446Strhodes result == ISC_R_SUCCESS; 3750135446Strhodes next = NULL, result = dns_zone_next(zone, &next), zone = next) { 3751135446Strhodes dns_view_t *zoneview; 3752135446Strhodes 3753135446Strhodes /* 3754135446Strhodes * At this point the zone list may contain a stale zone 3755135446Strhodes * just removed from the configuration. To see the validity, 3756135446Strhodes * check if the corresponding view is in our current view list. 3757153816Sdougb * There may also be old zones that are still in the process 3758153816Sdougb * of shutting down and have detached from their old view 3759153816Sdougb * (zoneview == NULL). 3760135446Strhodes */ 3761135446Strhodes zoneview = dns_zone_getview(zone); 3762153816Sdougb if (zoneview == NULL) 3763153816Sdougb continue; 3764135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3765135446Strhodes view != NULL && view != zoneview; 3766135446Strhodes view = ISC_LIST_NEXT(view, link)) 3767135446Strhodes ; 3768135446Strhodes if (view == NULL) 3769135446Strhodes continue; 3770135446Strhodes 3771135446Strhodes addrp = dns_zone_getnotifysrc6(zone); 3772180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 3773135446Strhodes if (result != ISC_R_SUCCESS) 3774135446Strhodes goto fail; 3775135446Strhodes 3776135446Strhodes addrp = dns_zone_getxfrsource6(zone); 3777180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 3778135446Strhodes if (result != ISC_R_SUCCESS) 3779135446Strhodes goto fail; 3780135446Strhodes } 3781135446Strhodes 3782135446Strhodes ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 3783186462Sdougb 3784135446Strhodes clean: 3785135446Strhodes ns_listenlist_detach(&list); 3786135446Strhodes return; 3787135446Strhodes 3788135446Strhodes fail: 3789135446Strhodes /* 3790135446Strhodes * Even when we failed the procedure, most of other interfaces 3791135446Strhodes * should work correctly. We therefore just warn it. 3792135446Strhodes */ 3793135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3794135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3795135446Strhodes "could not adjust the listen-on list; " 3796135446Strhodes "some interfaces may not work"); 3797135446Strhodes goto clean; 3798135446Strhodes} 3799135446Strhodes 3800135446Strhodes/* 3801135446Strhodes * This event callback is invoked to do periodic network 3802135446Strhodes * interface scanning. 3803135446Strhodes */ 3804135446Strhodesstatic void 3805135446Strhodesinterface_timer_tick(isc_task_t *task, isc_event_t *event) { 3806135446Strhodes isc_result_t result; 3807135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 3808135446Strhodes INSIST(task == server->task); 3809135446Strhodes UNUSED(task); 3810135446Strhodes isc_event_free(&event); 3811135446Strhodes /* 3812135446Strhodes * XXX should scan interfaces unlocked and get exclusive access 3813135446Strhodes * only to replace ACLs. 3814135446Strhodes */ 3815135446Strhodes result = isc_task_beginexclusive(server->task); 3816135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3817135446Strhodes scan_interfaces(server, ISC_FALSE); 3818135446Strhodes isc_task_endexclusive(server->task); 3819135446Strhodes} 3820135446Strhodes 3821135446Strhodesstatic void 3822135446Strhodesheartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 3823135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 3824135446Strhodes dns_view_t *view; 3825135446Strhodes 3826135446Strhodes UNUSED(task); 3827135446Strhodes isc_event_free(&event); 3828135446Strhodes view = ISC_LIST_HEAD(server->viewlist); 3829135446Strhodes while (view != NULL) { 3830135446Strhodes dns_view_dialup(view); 3831135446Strhodes view = ISC_LIST_NEXT(view, link); 3832135446Strhodes } 3833135446Strhodes} 3834135446Strhodes 3835170222Sdougbstatic void 3836170222Sdougbpps_timer_tick(isc_task_t *task, isc_event_t *event) { 3837170222Sdougb static unsigned int oldrequests = 0; 3838170222Sdougb unsigned int requests = ns_client_requests; 3839170222Sdougb 3840170222Sdougb UNUSED(task); 3841170222Sdougb isc_event_free(&event); 3842170222Sdougb 3843170222Sdougb /* 3844170222Sdougb * Don't worry about wrapping as the overflow result will be right. 3845170222Sdougb */ 3846170222Sdougb dns_pps = (requests - oldrequests) / 1200; 3847170222Sdougb oldrequests = requests; 3848170222Sdougb} 3849170222Sdougb 3850135446Strhodes/* 3851135446Strhodes * Replace the current value of '*field', a dynamically allocated 3852135446Strhodes * string or NULL, with a dynamically allocated copy of the 3853135446Strhodes * null-terminated string pointed to by 'value', or NULL. 3854135446Strhodes */ 3855135446Strhodesstatic isc_result_t 3856135446Strhodessetstring(ns_server_t *server, char **field, const char *value) { 3857135446Strhodes char *copy; 3858135446Strhodes 3859135446Strhodes if (value != NULL) { 3860135446Strhodes copy = isc_mem_strdup(server->mctx, value); 3861135446Strhodes if (copy == NULL) 3862135446Strhodes return (ISC_R_NOMEMORY); 3863135446Strhodes } else { 3864135446Strhodes copy = NULL; 3865135446Strhodes } 3866135446Strhodes 3867135446Strhodes if (*field != NULL) 3868135446Strhodes isc_mem_free(server->mctx, *field); 3869135446Strhodes 3870135446Strhodes *field = copy; 3871135446Strhodes return (ISC_R_SUCCESS); 3872186462Sdougb} 3873135446Strhodes 3874135446Strhodes/* 3875135446Strhodes * Replace the current value of '*field', a dynamically allocated 3876135446Strhodes * string or NULL, with another dynamically allocated string 3877135446Strhodes * or NULL if whether 'obj' is a string or void value, respectively. 3878135446Strhodes */ 3879135446Strhodesstatic isc_result_t 3880165071Sdougbsetoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 3881135446Strhodes if (cfg_obj_isvoid(obj)) 3882135446Strhodes return (setstring(server, field, NULL)); 3883135446Strhodes else 3884135446Strhodes return (setstring(server, field, cfg_obj_asstring(obj))); 3885135446Strhodes} 3886135446Strhodes 3887135446Strhodesstatic void 3888165071Sdougbset_limit(const cfg_obj_t **maps, const char *configname, 3889165071Sdougb const char *description, isc_resource_t resourceid, 3890165071Sdougb isc_resourcevalue_t defaultvalue) 3891135446Strhodes{ 3892165071Sdougb const cfg_obj_t *obj = NULL; 3893165071Sdougb const char *resource; 3894135446Strhodes isc_resourcevalue_t value; 3895135446Strhodes isc_result_t result; 3896135446Strhodes 3897135446Strhodes if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 3898135446Strhodes return; 3899135446Strhodes 3900135446Strhodes if (cfg_obj_isstring(obj)) { 3901135446Strhodes resource = cfg_obj_asstring(obj); 3902135446Strhodes if (strcasecmp(resource, "unlimited") == 0) 3903135446Strhodes value = ISC_RESOURCE_UNLIMITED; 3904135446Strhodes else { 3905135446Strhodes INSIST(strcasecmp(resource, "default") == 0); 3906135446Strhodes value = defaultvalue; 3907135446Strhodes } 3908135446Strhodes } else 3909135446Strhodes value = cfg_obj_asuint64(obj); 3910135446Strhodes 3911135446Strhodes result = isc_resource_setlimit(resourceid, value); 3912135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3913135446Strhodes result == ISC_R_SUCCESS ? 3914186462Sdougb ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 3915204619Sdougb "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s", 3916135446Strhodes description, value, isc_result_totext(result)); 3917135446Strhodes} 3918135446Strhodes 3919135446Strhodes#define SETLIMIT(cfgvar, resource, description) \ 3920135446Strhodes set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 3921135446Strhodes ns_g_init ## resource) 3922135446Strhodes 3923135446Strhodesstatic void 3924165071Sdougbset_limits(const cfg_obj_t **maps) { 3925135446Strhodes SETLIMIT("stacksize", stacksize, "stack size"); 3926135446Strhodes SETLIMIT("datasize", datasize, "data size"); 3927135446Strhodes SETLIMIT("coresize", coresize, "core size"); 3928135446Strhodes SETLIMIT("files", openfiles, "open files"); 3929135446Strhodes} 3930135446Strhodes 3931186462Sdougbstatic void 3932186462Sdougbportset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports, 3933186462Sdougb isc_boolean_t positive) 3934135446Strhodes{ 3935165071Sdougb const cfg_listelt_t *element; 3936135446Strhodes 3937135446Strhodes for (element = cfg_list_first(ports); 3938135446Strhodes element != NULL; 3939135446Strhodes element = cfg_list_next(element)) { 3940165071Sdougb const cfg_obj_t *obj = cfg_listelt_value(element); 3941186462Sdougb 3942186462Sdougb if (cfg_obj_isuint32(obj)) { 3943186462Sdougb in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 3944186462Sdougb 3945186462Sdougb if (positive) 3946186462Sdougb isc_portset_add(portset, port); 3947186462Sdougb else 3948186462Sdougb isc_portset_remove(portset, port); 3949186462Sdougb } else { 3950186462Sdougb const cfg_obj_t *obj_loport, *obj_hiport; 3951186462Sdougb in_port_t loport, hiport; 3952186462Sdougb 3953186462Sdougb obj_loport = cfg_tuple_get(obj, "loport"); 3954186462Sdougb loport = (in_port_t)cfg_obj_asuint32(obj_loport); 3955186462Sdougb obj_hiport = cfg_tuple_get(obj, "hiport"); 3956186462Sdougb hiport = (in_port_t)cfg_obj_asuint32(obj_hiport); 3957186462Sdougb 3958186462Sdougb if (positive) 3959186462Sdougb isc_portset_addrange(portset, loport, hiport); 3960186462Sdougb else { 3961186462Sdougb isc_portset_removerange(portset, loport, 3962186462Sdougb hiport); 3963186462Sdougb } 3964186462Sdougb } 3965135446Strhodes } 3966135446Strhodes} 3967135446Strhodes 3968135446Strhodesstatic isc_result_t 3969170222Sdougbremoved(dns_zone_t *zone, void *uap) { 3970170222Sdougb const char *type; 3971170222Sdougb 3972186462Sdougb if (dns_zone_getview(zone) != uap) 3973170222Sdougb return (ISC_R_SUCCESS); 3974170222Sdougb 3975170222Sdougb switch (dns_zone_gettype(zone)) { 3976170222Sdougb case dns_zone_master: 3977170222Sdougb type = "master"; 3978170222Sdougb break; 3979170222Sdougb case dns_zone_slave: 3980170222Sdougb type = "slave"; 3981170222Sdougb break; 3982170222Sdougb case dns_zone_stub: 3983170222Sdougb type = "stub"; 3984170222Sdougb break; 3985170222Sdougb default: 3986170222Sdougb type = "other"; 3987170222Sdougb break; 3988170222Sdougb } 3989170222Sdougb dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); 3990170222Sdougb return (ISC_R_SUCCESS); 3991170222Sdougb} 3992170222Sdougb 3993224092Sdougbstatic void 3994224092Sdougbcleanup_session_key(ns_server_t *server, isc_mem_t *mctx) { 3995224092Sdougb if (server->session_keyfile != NULL) { 3996224092Sdougb isc_file_remove(server->session_keyfile); 3997224092Sdougb isc_mem_free(mctx, server->session_keyfile); 3998224092Sdougb server->session_keyfile = NULL; 3999224092Sdougb } 4000224092Sdougb 4001224092Sdougb if (server->session_keyname != NULL) { 4002224092Sdougb if (dns_name_dynamic(server->session_keyname)) 4003224092Sdougb dns_name_free(server->session_keyname, mctx); 4004224092Sdougb isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t)); 4005224092Sdougb server->session_keyname = NULL; 4006224092Sdougb } 4007224092Sdougb 4008224092Sdougb if (server->sessionkey != NULL) 4009224092Sdougb dns_tsigkey_detach(&server->sessionkey); 4010224092Sdougb 4011224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 4012224092Sdougb server->session_keybits = 0; 4013224092Sdougb} 4014224092Sdougb 4015170222Sdougbstatic isc_result_t 4016224092Sdougbgenerate_session_key(const char *filename, const char *keynamestr, 4017224092Sdougb dns_name_t *keyname, const char *algstr, 4018224092Sdougb dns_name_t *algname, unsigned int algtype, 4019224092Sdougb isc_uint16_t bits, isc_mem_t *mctx, 4020224092Sdougb dns_tsigkey_t **tsigkeyp) 4021224092Sdougb{ 4022224092Sdougb isc_result_t result = ISC_R_SUCCESS; 4023224092Sdougb dst_key_t *key = NULL; 4024224092Sdougb isc_buffer_t key_txtbuffer; 4025224092Sdougb isc_buffer_t key_rawbuffer; 4026224092Sdougb char key_txtsecret[256]; 4027224092Sdougb char key_rawsecret[64]; 4028224092Sdougb isc_region_t key_rawregion; 4029224092Sdougb isc_stdtime_t now; 4030224092Sdougb dns_tsigkey_t *tsigkey = NULL; 4031224092Sdougb FILE *fp = NULL; 4032224092Sdougb 4033224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4034224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4035224092Sdougb "generating session key for dynamic DNS"); 4036224092Sdougb 4037224092Sdougb /* generate key */ 4038224092Sdougb result = dst_key_generate(keyname, algtype, bits, 1, 0, 4039224092Sdougb DNS_KEYPROTO_ANY, dns_rdataclass_in, 4040224092Sdougb mctx, &key); 4041224092Sdougb if (result != ISC_R_SUCCESS) 4042224092Sdougb return (result); 4043224092Sdougb 4044224092Sdougb /* 4045224092Sdougb * Dump the key to the buffer for later use. Should be done before 4046224092Sdougb * we transfer the ownership of key to tsigkey. 4047224092Sdougb */ 4048224092Sdougb isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); 4049224092Sdougb CHECK(dst_key_tobuffer(key, &key_rawbuffer)); 4050224092Sdougb 4051224092Sdougb isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); 4052224092Sdougb isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 4053224092Sdougb CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer)); 4054224092Sdougb 4055224092Sdougb /* Store the key in tsigkey. */ 4056224092Sdougb isc_stdtime_get(&now); 4057224092Sdougb CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, 4058224092Sdougb ISC_FALSE, NULL, now, now, mctx, NULL, 4059224092Sdougb &tsigkey)); 4060224092Sdougb 4061224092Sdougb /* Dump the key to the key file. */ 4062224092Sdougb fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE); 4063224092Sdougb if (fp == NULL) { 4064224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4065224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4066224092Sdougb "could not create %s", filename); 4067224092Sdougb result = ISC_R_NOPERM; 4068224092Sdougb goto cleanup; 4069224092Sdougb } 4070224092Sdougb 4071224092Sdougb fprintf(fp, "key \"%s\" {\n" 4072224092Sdougb "\talgorithm %s;\n" 4073224092Sdougb "\tsecret \"%.*s\";\n};\n", keynamestr, algstr, 4074224092Sdougb (int) isc_buffer_usedlength(&key_txtbuffer), 4075224092Sdougb (char*) isc_buffer_base(&key_txtbuffer)); 4076224092Sdougb 4077224092Sdougb RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS); 4078224092Sdougb RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS); 4079224092Sdougb 4080224092Sdougb dst_key_free(&key); 4081224092Sdougb 4082224092Sdougb *tsigkeyp = tsigkey; 4083224092Sdougb 4084224092Sdougb return (ISC_R_SUCCESS); 4085224092Sdougb 4086224092Sdougb cleanup: 4087224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4088224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4089224092Sdougb "failed to generate session key " 4090224092Sdougb "for dynamic DNS: %s", isc_result_totext(result)); 4091224092Sdougb if (tsigkey != NULL) 4092224092Sdougb dns_tsigkey_detach(&tsigkey); 4093224092Sdougb if (key != NULL) 4094224092Sdougb dst_key_free(&key); 4095224092Sdougb 4096224092Sdougb return (result); 4097224092Sdougb} 4098224092Sdougb 4099224092Sdougbstatic isc_result_t 4100224092Sdougbconfigure_session_key(const cfg_obj_t **maps, ns_server_t *server, 4101224092Sdougb isc_mem_t *mctx) 4102224092Sdougb{ 4103224092Sdougb const char *keyfile, *keynamestr, *algstr; 4104224092Sdougb unsigned int algtype; 4105224092Sdougb dns_fixedname_t fname; 4106224092Sdougb dns_name_t *keyname, *algname; 4107224092Sdougb isc_buffer_t buffer; 4108224092Sdougb isc_uint16_t bits; 4109224092Sdougb const cfg_obj_t *obj; 4110224092Sdougb isc_boolean_t need_deleteold = ISC_FALSE; 4111224092Sdougb isc_boolean_t need_createnew = ISC_FALSE; 4112224092Sdougb isc_result_t result; 4113224092Sdougb 4114224092Sdougb obj = NULL; 4115224092Sdougb result = ns_config_get(maps, "session-keyfile", &obj); 4116224092Sdougb if (result == ISC_R_SUCCESS) { 4117224092Sdougb if (cfg_obj_isvoid(obj)) 4118224092Sdougb keyfile = NULL; /* disable it */ 4119224092Sdougb else 4120224092Sdougb keyfile = cfg_obj_asstring(obj); 4121224092Sdougb } else 4122224092Sdougb keyfile = ns_g_defaultsessionkeyfile; 4123224092Sdougb 4124224092Sdougb obj = NULL; 4125224092Sdougb result = ns_config_get(maps, "session-keyname", &obj); 4126224092Sdougb INSIST(result == ISC_R_SUCCESS); 4127224092Sdougb keynamestr = cfg_obj_asstring(obj); 4128224092Sdougb dns_fixedname_init(&fname); 4129224092Sdougb isc_buffer_init(&buffer, keynamestr, strlen(keynamestr)); 4130224092Sdougb isc_buffer_add(&buffer, strlen(keynamestr)); 4131224092Sdougb keyname = dns_fixedname_name(&fname); 4132224092Sdougb result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL); 4133224092Sdougb if (result != ISC_R_SUCCESS) 4134224092Sdougb return (result); 4135224092Sdougb 4136224092Sdougb obj = NULL; 4137224092Sdougb result = ns_config_get(maps, "session-keyalg", &obj); 4138224092Sdougb INSIST(result == ISC_R_SUCCESS); 4139224092Sdougb algstr = cfg_obj_asstring(obj); 4140224092Sdougb algname = NULL; 4141224092Sdougb result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits); 4142224092Sdougb if (result != ISC_R_SUCCESS) { 4143224092Sdougb const char *s = " (keeping current key)"; 4144224092Sdougb 4145224092Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: " 4146224092Sdougb "unsupported or unknown algorithm '%s'%s", 4147224092Sdougb algstr, 4148224092Sdougb server->session_keyfile != NULL ? s : ""); 4149224092Sdougb return (result); 4150224092Sdougb } 4151224092Sdougb 4152224092Sdougb /* See if we need to (re)generate a new key. */ 4153224092Sdougb if (keyfile == NULL) { 4154224092Sdougb if (server->session_keyfile != NULL) 4155224092Sdougb need_deleteold = ISC_TRUE; 4156224092Sdougb } else if (server->session_keyfile == NULL) 4157224092Sdougb need_createnew = ISC_TRUE; 4158224092Sdougb else if (strcmp(keyfile, server->session_keyfile) != 0 || 4159224092Sdougb !dns_name_equal(server->session_keyname, keyname) || 4160224092Sdougb server->session_keyalg != algtype || 4161224092Sdougb server->session_keybits != bits) { 4162224092Sdougb need_deleteold = ISC_TRUE; 4163224092Sdougb need_createnew = ISC_TRUE; 4164224092Sdougb } 4165224092Sdougb 4166224092Sdougb if (need_deleteold) { 4167224092Sdougb INSIST(server->session_keyfile != NULL); 4168224092Sdougb INSIST(server->session_keyname != NULL); 4169224092Sdougb INSIST(server->sessionkey != NULL); 4170224092Sdougb 4171224092Sdougb cleanup_session_key(server, mctx); 4172224092Sdougb } 4173224092Sdougb 4174224092Sdougb if (need_createnew) { 4175224092Sdougb INSIST(server->sessionkey == NULL); 4176224092Sdougb INSIST(server->session_keyfile == NULL); 4177224092Sdougb INSIST(server->session_keyname == NULL); 4178224092Sdougb INSIST(server->session_keyalg == DST_ALG_UNKNOWN); 4179224092Sdougb INSIST(server->session_keybits == 0); 4180224092Sdougb 4181224092Sdougb server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t)); 4182224092Sdougb if (server->session_keyname == NULL) 4183224092Sdougb goto cleanup; 4184224092Sdougb dns_name_init(server->session_keyname, NULL); 4185224092Sdougb CHECK(dns_name_dup(keyname, mctx, server->session_keyname)); 4186224092Sdougb 4187224092Sdougb server->session_keyfile = isc_mem_strdup(mctx, keyfile); 4188224092Sdougb if (server->session_keyfile == NULL) 4189224092Sdougb goto cleanup; 4190224092Sdougb 4191224092Sdougb server->session_keyalg = algtype; 4192224092Sdougb server->session_keybits = bits; 4193224092Sdougb 4194224092Sdougb CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr, 4195224092Sdougb algname, algtype, bits, mctx, 4196224092Sdougb &server->sessionkey)); 4197224092Sdougb } 4198224092Sdougb 4199224092Sdougb return (result); 4200224092Sdougb 4201224092Sdougb cleanup: 4202224092Sdougb cleanup_session_key(server, mctx); 4203224092Sdougb return (result); 4204224092Sdougb} 4205224092Sdougb 4206224092Sdougbstatic isc_result_t 4207225361Sdougbsetup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 4208225361Sdougb cfg_parser_t *parser, cfg_aclconfctx_t *actx) 4209225361Sdougb{ 4210225361Sdougb isc_result_t result = ISC_R_SUCCESS; 4211225361Sdougb isc_boolean_t allow = ISC_FALSE; 4212225361Sdougb struct cfg_context *nzcfg = NULL; 4213225361Sdougb cfg_parser_t *nzparser = NULL; 4214225361Sdougb cfg_obj_t *nzconfig = NULL; 4215225361Sdougb const cfg_obj_t *maps[4]; 4216225361Sdougb const cfg_obj_t *options = NULL, *voptions = NULL; 4217225361Sdougb const cfg_obj_t *nz = NULL; 4218225361Sdougb int i = 0; 4219225361Sdougb 4220225361Sdougb REQUIRE (config != NULL); 4221225361Sdougb 4222225361Sdougb if (vconfig != NULL) 4223225361Sdougb voptions = cfg_tuple_get(vconfig, "options"); 4224225361Sdougb if (voptions != NULL) 4225225361Sdougb maps[i++] = voptions; 4226225361Sdougb result = cfg_map_get(config, "options", &options); 4227225361Sdougb if (result == ISC_R_SUCCESS) 4228225361Sdougb maps[i++] = options; 4229225361Sdougb maps[i++] = ns_g_defaults; 4230225361Sdougb maps[i] = NULL; 4231225361Sdougb 4232225361Sdougb result = ns_config_get(maps, "allow-new-zones", &nz); 4233225361Sdougb if (result == ISC_R_SUCCESS) 4234225361Sdougb allow = cfg_obj_asboolean(nz); 4235225361Sdougb 4236225361Sdougb if (!allow) { 4237225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4238225361Sdougb return (ISC_R_SUCCESS); 4239225361Sdougb } 4240225361Sdougb 4241225361Sdougb nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg)); 4242225361Sdougb if (nzcfg == NULL) { 4243225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4244225361Sdougb return (ISC_R_NOMEMORY); 4245225361Sdougb } 4246225361Sdougb 4247225361Sdougb dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy); 4248225361Sdougb 4249225361Sdougb memset(nzcfg, 0, sizeof(*nzcfg)); 4250225361Sdougb isc_mem_attach(view->mctx, &nzcfg->mctx); 4251225361Sdougb cfg_obj_attach(config, &nzcfg->config); 4252225361Sdougb cfg_parser_attach(parser, &nzcfg->parser); 4253225361Sdougb cfg_aclconfctx_attach(actx, &nzcfg->actx); 4254225361Sdougb 4255225361Sdougb /* 4256225361Sdougb * Attempt to create a parser and parse the newzones 4257225361Sdougb * file. If successful, preserve both; otherwise leave 4258225361Sdougb * them NULL. 4259225361Sdougb */ 4260225361Sdougb result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser); 4261225361Sdougb if (result == ISC_R_SUCCESS) 4262225361Sdougb result = cfg_parse_file(nzparser, view->new_zone_file, 4263225361Sdougb &cfg_type_newzones, &nzconfig); 4264225361Sdougb if (result == ISC_R_SUCCESS) { 4265225361Sdougb cfg_parser_attach(nzparser, &nzcfg->nzparser); 4266225361Sdougb cfg_obj_attach(nzconfig, &nzcfg->nzconfig); 4267225361Sdougb } 4268225361Sdougb 4269225361Sdougb if (nzparser != NULL) { 4270225361Sdougb if (nzconfig != NULL) 4271225361Sdougb cfg_obj_destroy(nzparser, &nzconfig); 4272225361Sdougb cfg_parser_destroy(&nzparser); 4273225361Sdougb } 4274225361Sdougb 4275225361Sdougb return (ISC_R_SUCCESS); 4276225361Sdougb} 4277225361Sdougb 4278225361Sdougbstatic int 4279225361Sdougbcount_zones(const cfg_obj_t *conf) { 4280225361Sdougb const cfg_obj_t *zonelist = NULL; 4281225361Sdougb const cfg_listelt_t *element; 4282225361Sdougb int n = 0; 4283225361Sdougb 4284225361Sdougb REQUIRE(conf != NULL); 4285225361Sdougb 4286225361Sdougb cfg_map_get(conf, "zone", &zonelist); 4287225361Sdougb for (element = cfg_list_first(zonelist); 4288225361Sdougb element != NULL; 4289225361Sdougb element = cfg_list_next(element)) 4290225361Sdougb n++; 4291225361Sdougb 4292225361Sdougb return (n); 4293225361Sdougb} 4294225361Sdougb 4295225361Sdougbstatic isc_result_t 4296135446Strhodesload_configuration(const char *filename, ns_server_t *server, 4297135446Strhodes isc_boolean_t first_time) 4298135446Strhodes{ 4299224092Sdougb cfg_obj_t *config = NULL, *bindkeys = NULL; 4300224092Sdougb cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL; 4301182645Sdougb const cfg_listelt_t *element; 4302182645Sdougb const cfg_obj_t *builtin_views; 4303182645Sdougb const cfg_obj_t *maps[3]; 4304182645Sdougb const cfg_obj_t *obj; 4305165071Sdougb const cfg_obj_t *options; 4306186462Sdougb const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports; 4307165071Sdougb const cfg_obj_t *views; 4308135446Strhodes dns_view_t *view = NULL; 4309135446Strhodes dns_view_t *view_next; 4310182645Sdougb dns_viewlist_t tmpviewlist; 4311224092Sdougb dns_viewlist_t viewlist, builtin_viewlist; 4312186462Sdougb in_port_t listen_port, udpport_low, udpport_high; 4313182645Sdougb int i; 4314182645Sdougb isc_interval_t interval; 4315186462Sdougb isc_portset_t *v4portset = NULL; 4316186462Sdougb isc_portset_t *v6portset = NULL; 4317186462Sdougb isc_resourcevalue_t nfiles; 4318182645Sdougb isc_result_t result; 4319182645Sdougb isc_uint32_t heartbeat_interval; 4320135446Strhodes isc_uint32_t interface_interval; 4321182645Sdougb isc_uint32_t reserved; 4322135446Strhodes isc_uint32_t udpsize; 4323224092Sdougb ns_cachelist_t cachelist, tmpcachelist; 4324186462Sdougb unsigned int maxsocks; 4325224092Sdougb ns_cache_t *nsc; 4326225361Sdougb struct cfg_context *nzctx; 4327225361Sdougb int num_zones = 0; 4328234010Sdougb isc_boolean_t exclusive = ISC_FALSE; 4329135446Strhodes 4330135446Strhodes ISC_LIST_INIT(viewlist); 4331224092Sdougb ISC_LIST_INIT(builtin_viewlist); 4332224092Sdougb ISC_LIST_INIT(cachelist); 4333135446Strhodes 4334225361Sdougb /* Create the ACL configuration context */ 4335225361Sdougb if (ns_g_aclconfctx != NULL) 4336225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 4337225361Sdougb CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx)); 4338225361Sdougb 4339135446Strhodes /* 4340135446Strhodes * Parse the global default pseudo-config file. 4341135446Strhodes */ 4342135446Strhodes if (first_time) { 4343135446Strhodes CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 4344135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 4345224092Sdougb &ns_g_defaults) == ISC_R_SUCCESS); 4346135446Strhodes } 4347135446Strhodes 4348135446Strhodes /* 4349135446Strhodes * Parse the configuration file using the new config code. 4350135446Strhodes */ 4351135446Strhodes result = ISC_R_FAILURE; 4352135446Strhodes config = NULL; 4353135446Strhodes 4354135446Strhodes /* 4355135446Strhodes * Unless this is lwresd with the -C option, parse the config file. 4356135446Strhodes */ 4357135446Strhodes if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 4358135446Strhodes isc_log_write(ns_g_lctx, 4359135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4360135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4361135446Strhodes filename); 4362224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4363224092Sdougb cfg_parser_setcallback(conf_parser, directory_callback, NULL); 4364224092Sdougb result = cfg_parse_file(conf_parser, filename, 4365224092Sdougb &cfg_type_namedconf, &config); 4366135446Strhodes } 4367135446Strhodes 4368135446Strhodes /* 4369135446Strhodes * If this is lwresd with the -C option, or lwresd with no -C or -c 4370135446Strhodes * option where the above parsing failed, parse resolv.conf. 4371135446Strhodes */ 4372135446Strhodes if (ns_g_lwresdonly && 4373135446Strhodes (lwresd_g_useresolvconf || 4374135446Strhodes (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 4375135446Strhodes { 4376135446Strhodes isc_log_write(ns_g_lctx, 4377135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4378135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4379135446Strhodes lwresd_g_resolvconffile); 4380224092Sdougb if (conf_parser != NULL) 4381224092Sdougb cfg_parser_destroy(&conf_parser); 4382224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4383224092Sdougb result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser, 4384135446Strhodes &config); 4385135446Strhodes } 4386135446Strhodes CHECK(result); 4387135446Strhodes 4388135446Strhodes /* 4389135446Strhodes * Check the validity of the configuration. 4390135446Strhodes */ 4391135446Strhodes CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 4392135446Strhodes 4393135446Strhodes /* 4394135446Strhodes * Fill in the maps array, used for resolving defaults. 4395135446Strhodes */ 4396135446Strhodes i = 0; 4397135446Strhodes options = NULL; 4398135446Strhodes result = cfg_map_get(config, "options", &options); 4399135446Strhodes if (result == ISC_R_SUCCESS) 4400135446Strhodes maps[i++] = options; 4401135446Strhodes maps[i++] = ns_g_defaults; 4402225361Sdougb maps[i] = NULL; 4403135446Strhodes 4404135446Strhodes /* 4405224092Sdougb * If bind.keys exists, load it. If "dnssec-lookaside auto" 4406224092Sdougb * is turned on, the keys found there will be used as default 4407224092Sdougb * trust anchors. 4408224092Sdougb */ 4409224092Sdougb obj = NULL; 4410224092Sdougb result = ns_config_get(maps, "bindkeys-file", &obj); 4411224092Sdougb INSIST(result == ISC_R_SUCCESS); 4412224092Sdougb CHECKM(setstring(server, &server->bindkeysfile, 4413224092Sdougb cfg_obj_asstring(obj)), "strdup"); 4414224092Sdougb 4415224092Sdougb if (access(server->bindkeysfile, R_OK) == 0) { 4416224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4417224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4418224092Sdougb "reading built-in trusted " 4419224092Sdougb "keys from file '%s'", server->bindkeysfile); 4420224092Sdougb 4421224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, 4422224092Sdougb &bindkeys_parser)); 4423224092Sdougb 4424224092Sdougb result = cfg_parse_file(bindkeys_parser, server->bindkeysfile, 4425224092Sdougb &cfg_type_bindkeys, &bindkeys); 4426224092Sdougb CHECK(result); 4427224092Sdougb } 4428224092Sdougb 4429234010Sdougb /* Ensure exclusive access to configuration data. */ 4430234010Sdougb if (!exclusive) { 4431234010Sdougb result = isc_task_beginexclusive(server->task); 4432234010Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 4433234010Sdougb exclusive = ISC_TRUE; 4434234010Sdougb } 4435234010Sdougb 4436224092Sdougb /* 4437135446Strhodes * Set process limits, which (usually) needs to be done as root. 4438135446Strhodes */ 4439135446Strhodes set_limits(maps); 4440135446Strhodes 4441135446Strhodes /* 4442186462Sdougb * Check if max number of open sockets that the system allows is 4443224092Sdougb * sufficiently large. Failing this condition is not necessarily fatal, 4444186462Sdougb * but may cause subsequent runtime failures for a busy recursive 4445186462Sdougb * server. 4446182645Sdougb */ 4447186462Sdougb result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks); 4448186462Sdougb if (result != ISC_R_SUCCESS) 4449186462Sdougb maxsocks = 0; 4450186462Sdougb result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles); 4451186462Sdougb if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) { 4452182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4453182645Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 4454186462Sdougb "max open files (%" ISC_PRINT_QUADFORMAT "u)" 4455186462Sdougb " is smaller than max sockets (%u)", 4456186462Sdougb nfiles, maxsocks); 4457186462Sdougb } 4458182645Sdougb 4459182645Sdougb /* 4460182645Sdougb * Set the number of socket reserved for TCP, stdio etc. 4461182645Sdougb */ 4462182645Sdougb obj = NULL; 4463182645Sdougb result = ns_config_get(maps, "reserved-sockets", &obj); 4464182645Sdougb INSIST(result == ISC_R_SUCCESS); 4465182645Sdougb reserved = cfg_obj_asuint32(obj); 4466186462Sdougb if (maxsocks != 0) { 4467186462Sdougb if (maxsocks < 128U) /* Prevent underflow. */ 4468186462Sdougb reserved = 0; 4469186462Sdougb else if (reserved > maxsocks - 128U) /* Minimum UDP space. */ 4470186462Sdougb reserved = maxsocks - 128; 4471186462Sdougb } 4472186462Sdougb /* Minimum TCP/stdio space. */ 4473186462Sdougb if (reserved < 128U) 4474182645Sdougb reserved = 128; 4475186462Sdougb if (reserved + 128U > maxsocks && maxsocks != 0) { 4476182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4477186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 4478182645Sdougb "less than 128 UDP sockets available after " 4479186462Sdougb "applying 'reserved-sockets' and 'maxsockets'"); 4480182645Sdougb } 4481182645Sdougb isc__socketmgr_setreserved(ns_g_socketmgr, reserved); 4482186462Sdougb 4483182645Sdougb /* 4484135446Strhodes * Configure various server options. 4485135446Strhodes */ 4486135446Strhodes configure_server_quota(maps, "transfers-out", &server->xfroutquota); 4487135446Strhodes configure_server_quota(maps, "tcp-clients", &server->tcpquota); 4488135446Strhodes configure_server_quota(maps, "recursive-clients", 4489135446Strhodes &server->recursionquota); 4490153816Sdougb if (server->recursionquota.max > 1000) 4491153816Sdougb isc_quota_soft(&server->recursionquota, 4492153816Sdougb server->recursionquota.max - 100); 4493153816Sdougb else 4494153816Sdougb isc_quota_soft(&server->recursionquota, 0); 4495135446Strhodes 4496225361Sdougb CHECK(configure_view_acl(NULL, config, "blackhole", NULL, 4497225361Sdougb ns_g_aclconfctx, ns_g_mctx, 4498225361Sdougb &server->blackholeacl)); 4499135446Strhodes if (server->blackholeacl != NULL) 4500135446Strhodes dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 4501135446Strhodes server->blackholeacl); 4502135446Strhodes 4503135446Strhodes obj = NULL; 4504135446Strhodes result = ns_config_get(maps, "match-mapped-addresses", &obj); 4505135446Strhodes INSIST(result == ISC_R_SUCCESS); 4506135446Strhodes server->aclenv.match_mapped = cfg_obj_asboolean(obj); 4507135446Strhodes 4508225361Sdougb CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx), 4509193149Sdougb "configuring statistics server(s)"); 4510193149Sdougb 4511186462Sdougb /* 4512186462Sdougb * Configure sets of UDP query source ports. 4513186462Sdougb */ 4514186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v4portset), 4515186462Sdougb "creating UDP port set"); 4516186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v6portset), 4517186462Sdougb "creating UDP port set"); 4518135446Strhodes 4519186462Sdougb usev4ports = NULL; 4520186462Sdougb usev6ports = NULL; 4521186462Sdougb avoidv4ports = NULL; 4522186462Sdougb avoidv6ports = NULL; 4523186462Sdougb 4524186462Sdougb (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports); 4525186462Sdougb if (usev4ports != NULL) 4526186462Sdougb portset_fromconf(v4portset, usev4ports, ISC_TRUE); 4527186462Sdougb else { 4528186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low, 4529186462Sdougb &udpport_high), 4530186462Sdougb "get the default UDP/IPv4 port range"); 4531186462Sdougb if (udpport_low == udpport_high) 4532186462Sdougb isc_portset_add(v4portset, udpport_low); 4533186462Sdougb else { 4534186462Sdougb isc_portset_addrange(v4portset, udpport_low, 4535186462Sdougb udpport_high); 4536186462Sdougb } 4537186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4538186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4539186462Sdougb "using default UDP/IPv4 port range: [%d, %d]", 4540186462Sdougb udpport_low, udpport_high); 4541186462Sdougb } 4542186462Sdougb (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports); 4543186462Sdougb if (avoidv4ports != NULL) 4544186462Sdougb portset_fromconf(v4portset, avoidv4ports, ISC_FALSE); 4545186462Sdougb 4546186462Sdougb (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports); 4547186462Sdougb if (usev6ports != NULL) 4548186462Sdougb portset_fromconf(v6portset, usev6ports, ISC_TRUE); 4549186462Sdougb else { 4550186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low, 4551186462Sdougb &udpport_high), 4552186462Sdougb "get the default UDP/IPv6 port range"); 4553186462Sdougb if (udpport_low == udpport_high) 4554186462Sdougb isc_portset_add(v6portset, udpport_low); 4555186462Sdougb else { 4556186462Sdougb isc_portset_addrange(v6portset, udpport_low, 4557186462Sdougb udpport_high); 4558186462Sdougb } 4559186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4560186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4561186462Sdougb "using default UDP/IPv6 port range: [%d, %d]", 4562186462Sdougb udpport_low, udpport_high); 4563186462Sdougb } 4564186462Sdougb (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports); 4565186462Sdougb if (avoidv6ports != NULL) 4566186462Sdougb portset_fromconf(v6portset, avoidv6ports, ISC_FALSE); 4567186462Sdougb 4568186462Sdougb dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset); 4569186462Sdougb 4570135446Strhodes /* 4571135446Strhodes * Set the EDNS UDP size when we don't match a view. 4572135446Strhodes */ 4573135446Strhodes obj = NULL; 4574135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 4575135446Strhodes INSIST(result == ISC_R_SUCCESS); 4576135446Strhodes udpsize = cfg_obj_asuint32(obj); 4577135446Strhodes if (udpsize < 512) 4578135446Strhodes udpsize = 512; 4579135446Strhodes if (udpsize > 4096) 4580135446Strhodes udpsize = 4096; 4581135446Strhodes ns_g_udpsize = (isc_uint16_t)udpsize; 4582135446Strhodes 4583135446Strhodes /* 4584135446Strhodes * Configure the zone manager. 4585135446Strhodes */ 4586135446Strhodes obj = NULL; 4587135446Strhodes result = ns_config_get(maps, "transfers-in", &obj); 4588135446Strhodes INSIST(result == ISC_R_SUCCESS); 4589135446Strhodes dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 4590135446Strhodes 4591135446Strhodes obj = NULL; 4592135446Strhodes result = ns_config_get(maps, "transfers-per-ns", &obj); 4593135446Strhodes INSIST(result == ISC_R_SUCCESS); 4594135446Strhodes dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 4595135446Strhodes 4596135446Strhodes obj = NULL; 4597135446Strhodes result = ns_config_get(maps, "serial-query-rate", &obj); 4598135446Strhodes INSIST(result == ISC_R_SUCCESS); 4599135446Strhodes dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 4600135446Strhodes 4601135446Strhodes /* 4602135446Strhodes * Determine which port to use for listening for incoming connections. 4603135446Strhodes */ 4604135446Strhodes if (ns_g_port != 0) 4605135446Strhodes listen_port = ns_g_port; 4606135446Strhodes else 4607135446Strhodes CHECKM(ns_config_getport(config, &listen_port), "port"); 4608135446Strhodes 4609135446Strhodes /* 4610135446Strhodes * Find the listen queue depth. 4611135446Strhodes */ 4612135446Strhodes obj = NULL; 4613135446Strhodes result = ns_config_get(maps, "tcp-listen-queue", &obj); 4614135446Strhodes INSIST(result == ISC_R_SUCCESS); 4615135446Strhodes ns_g_listen = cfg_obj_asuint32(obj); 4616135446Strhodes if (ns_g_listen < 3) 4617135446Strhodes ns_g_listen = 3; 4618135446Strhodes 4619135446Strhodes /* 4620135446Strhodes * Configure the interface manager according to the "listen-on" 4621135446Strhodes * statement. 4622135446Strhodes */ 4623135446Strhodes { 4624165071Sdougb const cfg_obj_t *clistenon = NULL; 4625135446Strhodes ns_listenlist_t *listenon = NULL; 4626135446Strhodes 4627135446Strhodes clistenon = NULL; 4628135446Strhodes /* 4629135446Strhodes * Even though listen-on is present in the default 4630135446Strhodes * configuration, we can't use it here, since it isn't 4631135446Strhodes * used if we're in lwresd mode. This way is easier. 4632135446Strhodes */ 4633135446Strhodes if (options != NULL) 4634135446Strhodes (void)cfg_map_get(options, "listen-on", &clistenon); 4635135446Strhodes if (clistenon != NULL) { 4636225361Sdougb /* check return code? */ 4637225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 4638225361Sdougb ns_g_aclconfctx, 4639225361Sdougb ns_g_mctx, &listenon); 4640135446Strhodes } else if (!ns_g_lwresdonly) { 4641135446Strhodes /* 4642135446Strhodes * Not specified, use default. 4643135446Strhodes */ 4644135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 4645135446Strhodes ISC_TRUE, &listenon)); 4646135446Strhodes } 4647135446Strhodes if (listenon != NULL) { 4648135446Strhodes ns_interfacemgr_setlistenon4(server->interfacemgr, 4649135446Strhodes listenon); 4650135446Strhodes ns_listenlist_detach(&listenon); 4651135446Strhodes } 4652135446Strhodes } 4653135446Strhodes /* 4654135446Strhodes * Ditto for IPv6. 4655135446Strhodes */ 4656135446Strhodes { 4657165071Sdougb const cfg_obj_t *clistenon = NULL; 4658135446Strhodes ns_listenlist_t *listenon = NULL; 4659135446Strhodes 4660135446Strhodes if (options != NULL) 4661135446Strhodes (void)cfg_map_get(options, "listen-on-v6", &clistenon); 4662135446Strhodes if (clistenon != NULL) { 4663225361Sdougb /* check return code? */ 4664225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 4665225361Sdougb ns_g_aclconfctx, 4666225361Sdougb ns_g_mctx, &listenon); 4667135446Strhodes } else if (!ns_g_lwresdonly) { 4668193149Sdougb isc_boolean_t enable; 4669135446Strhodes /* 4670135446Strhodes * Not specified, use default. 4671135446Strhodes */ 4672193149Sdougb enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS); 4673135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 4674193149Sdougb enable, &listenon)); 4675135446Strhodes } 4676135446Strhodes if (listenon != NULL) { 4677135446Strhodes ns_interfacemgr_setlistenon6(server->interfacemgr, 4678135446Strhodes listenon); 4679135446Strhodes ns_listenlist_detach(&listenon); 4680135446Strhodes } 4681135446Strhodes } 4682135446Strhodes 4683135446Strhodes /* 4684135446Strhodes * Rescan the interface list to pick up changes in the 4685135446Strhodes * listen-on option. It's important that we do this before we try 4686135446Strhodes * to configure the query source, since the dispatcher we use might 4687135446Strhodes * be shared with an interface. 4688135446Strhodes */ 4689135446Strhodes scan_interfaces(server, ISC_TRUE); 4690135446Strhodes 4691135446Strhodes /* 4692135446Strhodes * Arrange for further interface scanning to occur periodically 4693135446Strhodes * as specified by the "interface-interval" option. 4694135446Strhodes */ 4695135446Strhodes obj = NULL; 4696135446Strhodes result = ns_config_get(maps, "interface-interval", &obj); 4697135446Strhodes INSIST(result == ISC_R_SUCCESS); 4698135446Strhodes interface_interval = cfg_obj_asuint32(obj) * 60; 4699135446Strhodes if (interface_interval == 0) { 4700135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 4701135446Strhodes isc_timertype_inactive, 4702135446Strhodes NULL, NULL, ISC_TRUE)); 4703135446Strhodes } else if (server->interface_interval != interface_interval) { 4704135446Strhodes isc_interval_set(&interval, interface_interval, 0); 4705135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 4706135446Strhodes isc_timertype_ticker, 4707135446Strhodes NULL, &interval, ISC_FALSE)); 4708135446Strhodes } 4709135446Strhodes server->interface_interval = interface_interval; 4710135446Strhodes 4711135446Strhodes /* 4712135446Strhodes * Configure the dialup heartbeat timer. 4713135446Strhodes */ 4714135446Strhodes obj = NULL; 4715135446Strhodes result = ns_config_get(maps, "heartbeat-interval", &obj); 4716135446Strhodes INSIST(result == ISC_R_SUCCESS); 4717135446Strhodes heartbeat_interval = cfg_obj_asuint32(obj) * 60; 4718135446Strhodes if (heartbeat_interval == 0) { 4719135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 4720135446Strhodes isc_timertype_inactive, 4721135446Strhodes NULL, NULL, ISC_TRUE)); 4722135446Strhodes } else if (server->heartbeat_interval != heartbeat_interval) { 4723135446Strhodes isc_interval_set(&interval, heartbeat_interval, 0); 4724135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 4725135446Strhodes isc_timertype_ticker, 4726135446Strhodes NULL, &interval, ISC_FALSE)); 4727135446Strhodes } 4728135446Strhodes server->heartbeat_interval = heartbeat_interval; 4729186462Sdougb 4730170222Sdougb isc_interval_set(&interval, 1200, 0); 4731170222Sdougb CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, 4732170222Sdougb &interval, ISC_FALSE)); 4733135446Strhodes 4734135446Strhodes /* 4735224092Sdougb * Write the PID file. 4736224092Sdougb */ 4737224092Sdougb obj = NULL; 4738224092Sdougb if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 4739224092Sdougb if (cfg_obj_isvoid(obj)) 4740224092Sdougb ns_os_writepidfile(NULL, first_time); 4741224092Sdougb else 4742224092Sdougb ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 4743224092Sdougb else if (ns_g_lwresdonly) 4744224092Sdougb ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 4745224092Sdougb else 4746224092Sdougb ns_os_writepidfile(ns_g_defaultpidfile, first_time); 4747224092Sdougb 4748224092Sdougb /* 4749224092Sdougb * Configure the server-wide session key. This must be done before 4750224092Sdougb * configure views because zone configuration may need to know 4751224092Sdougb * session-keyname. 4752224092Sdougb * 4753224092Sdougb * Failure of session key generation isn't fatal at this time; if it 4754224092Sdougb * turns out that a session key is really needed but doesn't exist, 4755224092Sdougb * we'll treat it as a fatal error then. 4756224092Sdougb */ 4757224092Sdougb (void)configure_session_key(maps, server, ns_g_mctx); 4758224092Sdougb 4759225361Sdougb views = NULL; 4760225361Sdougb (void)cfg_map_get(config, "view", &views); 4761225361Sdougb 4762224092Sdougb /* 4763225361Sdougb * Create the views and count all the configured zones in 4764225361Sdougb * order to correctly size the zone manager's task table. 4765225361Sdougb * (We only count zones for configured views; the built-in 4766225361Sdougb * "bind" view can be ignored as it only adds a negligible 4767225361Sdougb * number of zones.) 4768225361Sdougb * 4769225361Sdougb * If we're allowing new zones, we need to be able to find the 4770225361Sdougb * new zone file and count those as well. So we setup the new 4771225361Sdougb * zone configuration context, but otherwise view configuration 4772225361Sdougb * waits until after the zone manager's task list has been sized. 4773225361Sdougb */ 4774225361Sdougb for (element = cfg_list_first(views); 4775225361Sdougb element != NULL; 4776225361Sdougb element = cfg_list_next(element)) 4777225361Sdougb { 4778225361Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4779225361Sdougb const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options"); 4780225361Sdougb view = NULL; 4781225361Sdougb 4782225361Sdougb CHECK(create_view(vconfig, &viewlist, &view)); 4783225361Sdougb INSIST(view != NULL); 4784225361Sdougb 4785225361Sdougb num_zones += count_zones(voptions); 4786225361Sdougb CHECK(setup_newzones(view, config, vconfig, conf_parser, 4787225361Sdougb ns_g_aclconfctx)); 4788225361Sdougb 4789225361Sdougb nzctx = view->new_zone_config; 4790225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 4791225361Sdougb num_zones += count_zones(nzctx->nzconfig); 4792225361Sdougb 4793225361Sdougb dns_view_detach(&view); 4794225361Sdougb } 4795225361Sdougb 4796225361Sdougb /* 4797225361Sdougb * If there were no explicit views then we do the default 4798225361Sdougb * view here. 4799225361Sdougb */ 4800225361Sdougb if (views == NULL) { 4801225361Sdougb CHECK(create_view(NULL, &viewlist, &view)); 4802225361Sdougb INSIST(view != NULL); 4803225361Sdougb 4804225361Sdougb num_zones = count_zones(config); 4805225361Sdougb 4806225361Sdougb CHECK(setup_newzones(view, config, NULL, conf_parser, 4807225361Sdougb ns_g_aclconfctx)); 4808225361Sdougb 4809225361Sdougb nzctx = view->new_zone_config; 4810225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 4811225361Sdougb num_zones += count_zones(nzctx->nzconfig); 4812225361Sdougb 4813225361Sdougb dns_view_detach(&view); 4814225361Sdougb } 4815225361Sdougb 4816225361Sdougb /* 4817225361Sdougb * Zones have been counted; set the zone manager task pool size. 4818225361Sdougb */ 4819225361Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4820225361Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4821225361Sdougb "sizing zone task pool based on %d zones", num_zones); 4822225361Sdougb CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones)); 4823225361Sdougb 4824225361Sdougb /* 4825135446Strhodes * Configure and freeze all explicit views. Explicit 4826135446Strhodes * views that have zones were already created at parsing 4827135446Strhodes * time, but views with no zones must be created here. 4828135446Strhodes */ 4829135446Strhodes for (element = cfg_list_first(views); 4830135446Strhodes element != NULL; 4831135446Strhodes element = cfg_list_next(element)) 4832135446Strhodes { 4833224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4834225361Sdougb 4835135446Strhodes view = NULL; 4836225361Sdougb CHECK(find_view(vconfig, &viewlist, &view)); 4837225361Sdougb CHECK(configure_view(view, config, vconfig, 4838225361Sdougb &cachelist, bindkeys, ns_g_mctx, 4839225361Sdougb ns_g_aclconfctx, ISC_TRUE)); 4840135446Strhodes dns_view_freeze(view); 4841135446Strhodes dns_view_detach(&view); 4842135446Strhodes } 4843135446Strhodes 4844135446Strhodes /* 4845135446Strhodes * Make sure we have a default view if and only if there 4846135446Strhodes * were no explicit views. 4847135446Strhodes */ 4848135446Strhodes if (views == NULL) { 4849225361Sdougb view = NULL; 4850225361Sdougb CHECK(find_view(NULL, &viewlist, &view)); 4851225361Sdougb CHECK(configure_view(view, config, NULL, 4852224092Sdougb &cachelist, bindkeys, 4853225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_TRUE)); 4854135446Strhodes dns_view_freeze(view); 4855135446Strhodes dns_view_detach(&view); 4856135446Strhodes } 4857135446Strhodes 4858135446Strhodes /* 4859224092Sdougb * Create (or recreate) the built-in views. 4860135446Strhodes */ 4861135446Strhodes builtin_views = NULL; 4862135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 4863135446Strhodes &builtin_views) == ISC_R_SUCCESS); 4864135446Strhodes for (element = cfg_list_first(builtin_views); 4865135446Strhodes element != NULL; 4866135446Strhodes element = cfg_list_next(element)) 4867135446Strhodes { 4868224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 4869224092Sdougb 4870224092Sdougb CHECK(create_view(vconfig, &builtin_viewlist, &view)); 4871225361Sdougb CHECK(configure_view(view, config, vconfig, 4872224092Sdougb &cachelist, bindkeys, 4873225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_FALSE)); 4874135446Strhodes dns_view_freeze(view); 4875135446Strhodes dns_view_detach(&view); 4876135446Strhodes view = NULL; 4877135446Strhodes } 4878135446Strhodes 4879224092Sdougb /* Now combine the two viewlists into one */ 4880224092Sdougb ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); 4881224092Sdougb 4882224092Sdougb /* Swap our new view list with the production one. */ 4883135446Strhodes tmpviewlist = server->viewlist; 4884135446Strhodes server->viewlist = viewlist; 4885135446Strhodes viewlist = tmpviewlist; 4886135446Strhodes 4887224092Sdougb /* Make the view list available to each of the views */ 4888224092Sdougb view = ISC_LIST_HEAD(server->viewlist); 4889224092Sdougb while (view != NULL) { 4890224092Sdougb view->viewlist = &server->viewlist; 4891224092Sdougb view = ISC_LIST_NEXT(view, link); 4892224092Sdougb } 4893224092Sdougb 4894224092Sdougb /* Swap our new cache list with the production one. */ 4895224092Sdougb tmpcachelist = server->cachelist; 4896224092Sdougb server->cachelist = cachelist; 4897224092Sdougb cachelist = tmpcachelist; 4898224092Sdougb 4899224092Sdougb /* Load the TKEY information from the configuration. */ 4900135446Strhodes if (options != NULL) { 4901135446Strhodes dns_tkeyctx_t *t = NULL; 4902135446Strhodes CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 4903135446Strhodes &t), 4904135446Strhodes "configuring TKEY"); 4905135446Strhodes if (server->tkeyctx != NULL) 4906135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 4907135446Strhodes server->tkeyctx = t; 4908135446Strhodes } 4909135446Strhodes 4910135446Strhodes /* 4911135446Strhodes * Bind the control port(s). 4912135446Strhodes */ 4913135446Strhodes CHECKM(ns_controls_configure(ns_g_server->controls, config, 4914225361Sdougb ns_g_aclconfctx), 4915135446Strhodes "binding control channel(s)"); 4916135446Strhodes 4917135446Strhodes /* 4918135446Strhodes * Bind the lwresd port(s). 4919135446Strhodes */ 4920135446Strhodes CHECKM(ns_lwresd_configure(ns_g_mctx, config), 4921135446Strhodes "binding lightweight resolver ports"); 4922135446Strhodes 4923135446Strhodes /* 4924135446Strhodes * Open the source of entropy. 4925135446Strhodes */ 4926135446Strhodes if (first_time) { 4927135446Strhodes obj = NULL; 4928135446Strhodes result = ns_config_get(maps, "random-device", &obj); 4929135446Strhodes if (result != ISC_R_SUCCESS) { 4930135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4931135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4932135446Strhodes "no source of entropy found"); 4933135446Strhodes } else { 4934135446Strhodes const char *randomdev = cfg_obj_asstring(obj); 4935135446Strhodes result = isc_entropy_createfilesource(ns_g_entropy, 4936135446Strhodes randomdev); 4937135446Strhodes if (result != ISC_R_SUCCESS) 4938135446Strhodes isc_log_write(ns_g_lctx, 4939135446Strhodes NS_LOGCATEGORY_GENERAL, 4940135446Strhodes NS_LOGMODULE_SERVER, 4941135446Strhodes ISC_LOG_INFO, 4942135446Strhodes "could not open entropy source " 4943135446Strhodes "%s: %s", 4944135446Strhodes randomdev, 4945135446Strhodes isc_result_totext(result)); 4946135446Strhodes#ifdef PATH_RANDOMDEV 4947135446Strhodes if (ns_g_fallbackentropy != NULL) { 4948135446Strhodes if (result != ISC_R_SUCCESS) { 4949135446Strhodes isc_log_write(ns_g_lctx, 4950135446Strhodes NS_LOGCATEGORY_GENERAL, 4951135446Strhodes NS_LOGMODULE_SERVER, 4952135446Strhodes ISC_LOG_INFO, 4953135446Strhodes "using pre-chroot entropy source " 4954135446Strhodes "%s", 4955135446Strhodes PATH_RANDOMDEV); 4956135446Strhodes isc_entropy_detach(&ns_g_entropy); 4957135446Strhodes isc_entropy_attach(ns_g_fallbackentropy, 4958135446Strhodes &ns_g_entropy); 4959135446Strhodes } 4960135446Strhodes isc_entropy_detach(&ns_g_fallbackentropy); 4961135446Strhodes } 4962135446Strhodes#endif 4963135446Strhodes } 4964135446Strhodes } 4965135446Strhodes 4966135446Strhodes /* 4967135446Strhodes * Relinquish root privileges. 4968135446Strhodes */ 4969135446Strhodes if (first_time) 4970135446Strhodes ns_os_changeuser(); 4971135446Strhodes 4972135446Strhodes /* 4973186462Sdougb * Check that the working directory is writable. 4974186462Sdougb */ 4975186462Sdougb if (access(".", W_OK) != 0) { 4976186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4977186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4978186462Sdougb "the working directory is not writable"); 4979186462Sdougb } 4980186462Sdougb 4981186462Sdougb /* 4982135446Strhodes * Configure the logging system. 4983135446Strhodes * 4984135446Strhodes * Do this after changing UID to make sure that any log 4985135446Strhodes * files specified in named.conf get created by the 4986135446Strhodes * unprivileged user, not root. 4987135446Strhodes */ 4988135446Strhodes if (ns_g_logstderr) { 4989135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4990135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4991135446Strhodes "ignoring config file logging " 4992135446Strhodes "statement due to -g option"); 4993135446Strhodes } else { 4994165071Sdougb const cfg_obj_t *logobj = NULL; 4995135446Strhodes isc_logconfig_t *logc = NULL; 4996135446Strhodes 4997135446Strhodes CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 4998135446Strhodes "creating new logging configuration"); 4999135446Strhodes 5000135446Strhodes logobj = NULL; 5001135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 5002135446Strhodes if (logobj != NULL) { 5003135446Strhodes CHECKM(ns_log_configure(logc, logobj), 5004135446Strhodes "configuring logging"); 5005135446Strhodes } else { 5006135446Strhodes CHECKM(ns_log_setdefaultchannels(logc), 5007135446Strhodes "setting up default logging channels"); 5008135446Strhodes CHECKM(ns_log_setunmatchedcategory(logc), 5009135446Strhodes "setting up default 'category unmatched'"); 5010135446Strhodes CHECKM(ns_log_setdefaultcategory(logc), 5011135446Strhodes "setting up default 'category default'"); 5012135446Strhodes } 5013135446Strhodes 5014135446Strhodes result = isc_logconfig_use(ns_g_lctx, logc); 5015135446Strhodes if (result != ISC_R_SUCCESS) { 5016135446Strhodes isc_logconfig_destroy(&logc); 5017135446Strhodes CHECKM(result, "installing logging configuration"); 5018135446Strhodes } 5019135446Strhodes 5020135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5021135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 5022135446Strhodes "now using logging configuration from " 5023135446Strhodes "config file"); 5024135446Strhodes } 5025135446Strhodes 5026135446Strhodes /* 5027135446Strhodes * Set the default value of the query logging flag depending 5028135446Strhodes * whether a "queries" category has been defined. This is 5029135446Strhodes * a disgusting hack, but we need to do this for BIND 8 5030135446Strhodes * compatibility. 5031135446Strhodes */ 5032135446Strhodes if (first_time) { 5033165071Sdougb const cfg_obj_t *logobj = NULL; 5034165071Sdougb const cfg_obj_t *categories = NULL; 5035135446Strhodes 5036135446Strhodes obj = NULL; 5037135446Strhodes if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 5038135446Strhodes server->log_queries = cfg_obj_asboolean(obj); 5039135446Strhodes } else { 5040135446Strhodes 5041135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 5042135446Strhodes if (logobj != NULL) 5043135446Strhodes (void)cfg_map_get(logobj, "category", 5044135446Strhodes &categories); 5045135446Strhodes if (categories != NULL) { 5046165071Sdougb const cfg_listelt_t *element; 5047135446Strhodes for (element = cfg_list_first(categories); 5048135446Strhodes element != NULL; 5049135446Strhodes element = cfg_list_next(element)) 5050135446Strhodes { 5051165071Sdougb const cfg_obj_t *catobj; 5052165071Sdougb const char *str; 5053135446Strhodes 5054135446Strhodes obj = cfg_listelt_value(element); 5055135446Strhodes catobj = cfg_tuple_get(obj, "name"); 5056135446Strhodes str = cfg_obj_asstring(catobj); 5057135446Strhodes if (strcasecmp(str, "queries") == 0) 5058135446Strhodes server->log_queries = ISC_TRUE; 5059135446Strhodes } 5060135446Strhodes } 5061135446Strhodes } 5062135446Strhodes } 5063135446Strhodes 5064186462Sdougb 5065135446Strhodes obj = NULL; 5066135446Strhodes if (options != NULL && 5067193149Sdougb cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) 5068193149Sdougb ns_g_memstatistics = cfg_obj_asboolean(obj); 5069193149Sdougb else 5070193149Sdougb ns_g_memstatistics = 5071193149Sdougb ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); 5072193149Sdougb 5073193149Sdougb obj = NULL; 5074193149Sdougb if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) 5075135446Strhodes ns_main_setmemstats(cfg_obj_asstring(obj)); 5076193149Sdougb else if (ns_g_memstatistics) 5077193149Sdougb ns_main_setmemstats("named.memstats"); 5078135446Strhodes else 5079135446Strhodes ns_main_setmemstats(NULL); 5080135446Strhodes 5081135446Strhodes obj = NULL; 5082135446Strhodes result = ns_config_get(maps, "statistics-file", &obj); 5083135446Strhodes INSIST(result == ISC_R_SUCCESS); 5084135446Strhodes CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 5085135446Strhodes "strdup"); 5086135446Strhodes 5087135446Strhodes obj = NULL; 5088135446Strhodes result = ns_config_get(maps, "dump-file", &obj); 5089135446Strhodes INSIST(result == ISC_R_SUCCESS); 5090135446Strhodes CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 5091135446Strhodes "strdup"); 5092135446Strhodes 5093135446Strhodes obj = NULL; 5094224092Sdougb result = ns_config_get(maps, "secroots-file", &obj); 5095224092Sdougb INSIST(result == ISC_R_SUCCESS); 5096224092Sdougb CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)), 5097224092Sdougb "strdup"); 5098224092Sdougb 5099224092Sdougb obj = NULL; 5100135446Strhodes result = ns_config_get(maps, "recursing-file", &obj); 5101135446Strhodes INSIST(result == ISC_R_SUCCESS); 5102135446Strhodes CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 5103135446Strhodes "strdup"); 5104135446Strhodes 5105135446Strhodes obj = NULL; 5106135446Strhodes result = ns_config_get(maps, "version", &obj); 5107135446Strhodes if (result == ISC_R_SUCCESS) { 5108135446Strhodes CHECKM(setoptstring(server, &server->version, obj), "strdup"); 5109135446Strhodes server->version_set = ISC_TRUE; 5110135446Strhodes } else { 5111135446Strhodes server->version_set = ISC_FALSE; 5112135446Strhodes } 5113135446Strhodes 5114135446Strhodes obj = NULL; 5115135446Strhodes result = ns_config_get(maps, "hostname", &obj); 5116135446Strhodes if (result == ISC_R_SUCCESS) { 5117135446Strhodes CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 5118135446Strhodes server->hostname_set = ISC_TRUE; 5119135446Strhodes } else { 5120135446Strhodes server->hostname_set = ISC_FALSE; 5121135446Strhodes } 5122135446Strhodes 5123135446Strhodes obj = NULL; 5124135446Strhodes result = ns_config_get(maps, "server-id", &obj); 5125135446Strhodes server->server_usehostname = ISC_FALSE; 5126135446Strhodes if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 5127193149Sdougb /* The parser translates "hostname" to ISC_TRUE */ 5128193149Sdougb server->server_usehostname = cfg_obj_asboolean(obj); 5129193149Sdougb result = setstring(server, &server->server_id, NULL); 5130193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 5131135446Strhodes } else if (result == ISC_R_SUCCESS) { 5132193149Sdougb /* Found a quoted string */ 5133135446Strhodes CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 5134135446Strhodes } else { 5135170222Sdougb result = setstring(server, &server->server_id, NULL); 5136135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5137135446Strhodes } 5138135446Strhodes 5139135446Strhodes obj = NULL; 5140135446Strhodes result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 5141135446Strhodes if (result == ISC_R_SUCCESS) { 5142135446Strhodes server->flushonshutdown = cfg_obj_asboolean(obj); 5143135446Strhodes } else { 5144135446Strhodes server->flushonshutdown = ISC_FALSE; 5145135446Strhodes } 5146135446Strhodes 5147135446Strhodes result = ISC_R_SUCCESS; 5148135446Strhodes 5149135446Strhodes cleanup: 5150186462Sdougb if (v4portset != NULL) 5151186462Sdougb isc_portset_destroy(ns_g_mctx, &v4portset); 5152186462Sdougb 5153186462Sdougb if (v6portset != NULL) 5154186462Sdougb isc_portset_destroy(ns_g_mctx, &v6portset); 5155186462Sdougb 5156224092Sdougb if (conf_parser != NULL) { 5157135446Strhodes if (config != NULL) 5158224092Sdougb cfg_obj_destroy(conf_parser, &config); 5159224092Sdougb cfg_parser_destroy(&conf_parser); 5160135446Strhodes } 5161135446Strhodes 5162224092Sdougb if (bindkeys_parser != NULL) { 5163224092Sdougb if (bindkeys != NULL) 5164224092Sdougb cfg_obj_destroy(bindkeys_parser, &bindkeys); 5165224092Sdougb cfg_parser_destroy(&bindkeys_parser); 5166224092Sdougb } 5167224092Sdougb 5168135446Strhodes if (view != NULL) 5169135446Strhodes dns_view_detach(&view); 5170135446Strhodes 5171135446Strhodes /* 5172135446Strhodes * This cleans up either the old production view list 5173135446Strhodes * or our temporary list depending on whether they 5174135446Strhodes * were swapped above or not. 5175135446Strhodes */ 5176135446Strhodes for (view = ISC_LIST_HEAD(viewlist); 5177135446Strhodes view != NULL; 5178135446Strhodes view = view_next) { 5179135446Strhodes view_next = ISC_LIST_NEXT(view, link); 5180135446Strhodes ISC_LIST_UNLINK(viewlist, view, link); 5181170222Sdougb if (result == ISC_R_SUCCESS && 5182170222Sdougb strcmp(view->name, "_bind") != 0) 5183170222Sdougb (void)dns_zt_apply(view->zonetable, ISC_FALSE, 5184170222Sdougb removed, view); 5185135446Strhodes dns_view_detach(&view); 5186135446Strhodes } 5187135446Strhodes 5188224092Sdougb /* Same cleanup for cache list. */ 5189224092Sdougb while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) { 5190224092Sdougb ISC_LIST_UNLINK(cachelist, nsc, link); 5191224092Sdougb dns_cache_detach(&nsc->cache); 5192224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 5193224092Sdougb } 5194224092Sdougb 5195135446Strhodes /* 5196135446Strhodes * Adjust the listening interfaces in accordance with the source 5197135446Strhodes * addresses specified in views and zones. 5198135446Strhodes */ 5199135446Strhodes if (isc_net_probeipv6() == ISC_R_SUCCESS) 5200135446Strhodes adjust_interfaces(server, ns_g_mctx); 5201135446Strhodes 5202135446Strhodes /* Relinquish exclusive access to configuration data. */ 5203234010Sdougb if (exclusive) 5204234010Sdougb isc_task_endexclusive(server->task); 5205135446Strhodes 5206135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5207135446Strhodes ISC_LOG_DEBUG(1), "load_configuration: %s", 5208135446Strhodes isc_result_totext(result)); 5209135446Strhodes 5210135446Strhodes return (result); 5211135446Strhodes} 5212135446Strhodes 5213135446Strhodesstatic isc_result_t 5214135446Strhodesload_zones(ns_server_t *server, isc_boolean_t stop) { 5215135446Strhodes isc_result_t result; 5216135446Strhodes dns_view_t *view; 5217135446Strhodes 5218135446Strhodes result = isc_task_beginexclusive(server->task); 5219135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5220135446Strhodes 5221135446Strhodes /* 5222135446Strhodes * Load zone data from disk. 5223135446Strhodes */ 5224135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5225135446Strhodes view != NULL; 5226135446Strhodes view = ISC_LIST_NEXT(view, link)) 5227135446Strhodes { 5228135446Strhodes CHECK(dns_view_load(view, stop)); 5229224092Sdougb if (view->managed_keys != NULL) 5230224092Sdougb CHECK(dns_zone_load(view->managed_keys)); 5231135446Strhodes } 5232135446Strhodes 5233135446Strhodes /* 5234135446Strhodes * Force zone maintenance. Do this after loading 5235135446Strhodes * so that we know when we need to force AXFR of 5236135446Strhodes * slave zones whose master files are missing. 5237135446Strhodes */ 5238135446Strhodes CHECK(dns_zonemgr_forcemaint(server->zonemgr)); 5239135446Strhodes cleanup: 5240186462Sdougb isc_task_endexclusive(server->task); 5241135446Strhodes return (result); 5242135446Strhodes} 5243135446Strhodes 5244135446Strhodesstatic isc_result_t 5245135446Strhodesload_new_zones(ns_server_t *server, isc_boolean_t stop) { 5246135446Strhodes isc_result_t result; 5247135446Strhodes dns_view_t *view; 5248135446Strhodes 5249135446Strhodes result = isc_task_beginexclusive(server->task); 5250135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5251135446Strhodes 5252135446Strhodes /* 5253135446Strhodes * Load zone data from disk. 5254135446Strhodes */ 5255135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5256135446Strhodes view != NULL; 5257135446Strhodes view = ISC_LIST_NEXT(view, link)) 5258135446Strhodes { 5259135446Strhodes CHECK(dns_view_loadnew(view, stop)); 5260224092Sdougb 5261224092Sdougb /* Load managed-keys data */ 5262224092Sdougb if (view->managed_keys != NULL) 5263224092Sdougb CHECK(dns_zone_loadnew(view->managed_keys)); 5264135446Strhodes } 5265224092Sdougb 5266135446Strhodes /* 5267224092Sdougb * Resume zone XFRs. 5268135446Strhodes */ 5269135446Strhodes dns_zonemgr_resumexfrs(server->zonemgr); 5270135446Strhodes cleanup: 5271186462Sdougb isc_task_endexclusive(server->task); 5272135446Strhodes return (result); 5273135446Strhodes} 5274135446Strhodes 5275135446Strhodesstatic void 5276135446Strhodesrun_server(isc_task_t *task, isc_event_t *event) { 5277135446Strhodes isc_result_t result; 5278135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5279135446Strhodes 5280143731Sdougb INSIST(task == server->task); 5281135446Strhodes 5282135446Strhodes isc_event_free(&event); 5283135446Strhodes 5284135446Strhodes CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 5285135446Strhodes &ns_g_dispatchmgr), 5286135446Strhodes "creating dispatch manager"); 5287135446Strhodes 5288193149Sdougb dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); 5289193149Sdougb 5290135446Strhodes CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 5291135446Strhodes ns_g_socketmgr, ns_g_dispatchmgr, 5292135446Strhodes &server->interfacemgr), 5293135446Strhodes "creating interface manager"); 5294135446Strhodes 5295135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5296135446Strhodes NULL, NULL, server->task, 5297135446Strhodes interface_timer_tick, 5298135446Strhodes server, &server->interface_timer), 5299135446Strhodes "creating interface timer"); 5300135446Strhodes 5301135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5302135446Strhodes NULL, NULL, server->task, 5303135446Strhodes heartbeat_timer_tick, 5304135446Strhodes server, &server->heartbeat_timer), 5305135446Strhodes "creating heartbeat timer"); 5306135446Strhodes 5307170222Sdougb CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5308170222Sdougb NULL, NULL, server->task, pps_timer_tick, 5309170222Sdougb server, &server->pps_timer), 5310170222Sdougb "creating pps timer"); 5311170222Sdougb 5312135446Strhodes CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 5313135446Strhodes "creating default configuration parser"); 5314135446Strhodes 5315135446Strhodes if (ns_g_lwresdonly) 5316135446Strhodes CHECKFATAL(load_configuration(lwresd_g_conffile, server, 5317135446Strhodes ISC_TRUE), 5318135446Strhodes "loading configuration"); 5319135446Strhodes else 5320135446Strhodes CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 5321135446Strhodes "loading configuration"); 5322135446Strhodes 5323135446Strhodes isc_hash_init(); 5324135446Strhodes 5325143731Sdougb CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); 5326135446Strhodes 5327143731Sdougb ns_os_started(); 5328135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5329143731Sdougb ISC_LOG_NOTICE, "running"); 5330135446Strhodes} 5331135446Strhodes 5332186462Sdougbvoid 5333135446Strhodesns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 5334135446Strhodes 5335135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5336135446Strhodes 5337135446Strhodes server->flushonshutdown = flush; 5338135446Strhodes} 5339135446Strhodes 5340135446Strhodesstatic void 5341135446Strhodesshutdown_server(isc_task_t *task, isc_event_t *event) { 5342135446Strhodes isc_result_t result; 5343135446Strhodes dns_view_t *view, *view_next; 5344135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5345135446Strhodes isc_boolean_t flush = server->flushonshutdown; 5346224092Sdougb ns_cache_t *nsc; 5347135446Strhodes 5348135446Strhodes UNUSED(task); 5349135446Strhodes INSIST(task == server->task); 5350135446Strhodes 5351135446Strhodes result = isc_task_beginexclusive(server->task); 5352135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5353135446Strhodes 5354135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5355135446Strhodes ISC_LOG_INFO, "shutting down%s", 5356135446Strhodes flush ? ": flushing changes" : ""); 5357135446Strhodes 5358193149Sdougb ns_statschannels_shutdown(server); 5359135446Strhodes ns_controls_shutdown(server->controls); 5360135446Strhodes end_reserved_dispatches(server, ISC_TRUE); 5361224092Sdougb cleanup_session_key(server, server->mctx); 5362135446Strhodes 5363225361Sdougb if (ns_g_aclconfctx != NULL) 5364225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 5365225361Sdougb 5366135446Strhodes cfg_obj_destroy(ns_g_parser, &ns_g_config); 5367135446Strhodes cfg_parser_destroy(&ns_g_parser); 5368135446Strhodes 5369135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5370135446Strhodes view != NULL; 5371135446Strhodes view = view_next) { 5372135446Strhodes view_next = ISC_LIST_NEXT(view, link); 5373135446Strhodes ISC_LIST_UNLINK(server->viewlist, view, link); 5374135446Strhodes if (flush) 5375135446Strhodes dns_view_flushanddetach(&view); 5376135446Strhodes else 5377135446Strhodes dns_view_detach(&view); 5378135446Strhodes } 5379135446Strhodes 5380224092Sdougb while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { 5381224092Sdougb ISC_LIST_UNLINK(server->cachelist, nsc, link); 5382224092Sdougb dns_cache_detach(&nsc->cache); 5383224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 5384224092Sdougb } 5385224092Sdougb 5386135446Strhodes isc_timer_detach(&server->interface_timer); 5387135446Strhodes isc_timer_detach(&server->heartbeat_timer); 5388170222Sdougb isc_timer_detach(&server->pps_timer); 5389135446Strhodes 5390135446Strhodes ns_interfacemgr_shutdown(server->interfacemgr); 5391135446Strhodes ns_interfacemgr_detach(&server->interfacemgr); 5392135446Strhodes 5393135446Strhodes dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 5394135446Strhodes 5395135446Strhodes dns_zonemgr_shutdown(server->zonemgr); 5396135446Strhodes 5397224092Sdougb if (ns_g_sessionkey != NULL) { 5398224092Sdougb dns_tsigkey_detach(&ns_g_sessionkey); 5399224092Sdougb dns_name_free(&ns_g_sessionkeyname, server->mctx); 5400224092Sdougb } 5401224092Sdougb 5402135446Strhodes if (server->blackholeacl != NULL) 5403135446Strhodes dns_acl_detach(&server->blackholeacl); 5404135446Strhodes 5405135446Strhodes dns_db_detach(&server->in_roothints); 5406135446Strhodes 5407135446Strhodes isc_task_endexclusive(server->task); 5408135446Strhodes 5409135446Strhodes isc_task_detach(&server->task); 5410135446Strhodes 5411135446Strhodes isc_event_free(&event); 5412135446Strhodes} 5413135446Strhodes 5414135446Strhodesvoid 5415135446Strhodesns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 5416135446Strhodes isc_result_t result; 5417225361Sdougb ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 5418135446Strhodes 5419135446Strhodes if (server == NULL) 5420135446Strhodes fatal("allocating server object", ISC_R_NOMEMORY); 5421135446Strhodes 5422135446Strhodes server->mctx = mctx; 5423135446Strhodes server->task = NULL; 5424135446Strhodes 5425135446Strhodes /* Initialize configuration data with default values. */ 5426135446Strhodes 5427135446Strhodes result = isc_quota_init(&server->xfroutquota, 10); 5428135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5429135446Strhodes result = isc_quota_init(&server->tcpquota, 10); 5430135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5431135446Strhodes result = isc_quota_init(&server->recursionquota, 100); 5432135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5433135446Strhodes 5434135446Strhodes result = dns_aclenv_init(mctx, &server->aclenv); 5435135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5436135446Strhodes 5437135446Strhodes /* Initialize server data structures. */ 5438135446Strhodes server->zonemgr = NULL; 5439135446Strhodes server->interfacemgr = NULL; 5440135446Strhodes ISC_LIST_INIT(server->viewlist); 5441135446Strhodes server->in_roothints = NULL; 5442135446Strhodes server->blackholeacl = NULL; 5443135446Strhodes 5444135446Strhodes CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 5445135446Strhodes &server->in_roothints), 5446135446Strhodes "setting up root hints"); 5447135446Strhodes 5448135446Strhodes CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 5449135446Strhodes "initializing reload event lock"); 5450135446Strhodes server->reload_event = 5451135446Strhodes isc_event_allocate(ns_g_mctx, server, 5452135446Strhodes NS_EVENT_RELOAD, 5453135446Strhodes ns_server_reload, 5454135446Strhodes server, 5455135446Strhodes sizeof(isc_event_t)); 5456135446Strhodes CHECKFATAL(server->reload_event == NULL ? 5457135446Strhodes ISC_R_NOMEMORY : ISC_R_SUCCESS, 5458135446Strhodes "allocating reload event"); 5459135446Strhodes 5460224092Sdougb CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, 5461224092Sdougb ns_g_engine, ISC_ENTROPY_GOODONLY), 5462135446Strhodes "initializing DST"); 5463135446Strhodes 5464135446Strhodes server->tkeyctx = NULL; 5465135446Strhodes CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 5466135446Strhodes &server->tkeyctx), 5467135446Strhodes "creating TKEY context"); 5468135446Strhodes 5469135446Strhodes /* 5470135446Strhodes * Setup the server task, which is responsible for coordinating 5471245163Serwin * startup and shutdown of the server, as well as all exclusive 5472245163Serwin * tasks. 5473135446Strhodes */ 5474135446Strhodes CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 5475135446Strhodes "creating server task"); 5476135446Strhodes isc_task_setname(server->task, "server", server); 5477245163Serwin isc_taskmgr_setexcltask(ns_g_taskmgr, server->task); 5478135446Strhodes CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 5479135446Strhodes "isc_task_onshutdown"); 5480135446Strhodes CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 5481135446Strhodes "isc_app_onrun"); 5482135446Strhodes 5483135446Strhodes server->interface_timer = NULL; 5484135446Strhodes server->heartbeat_timer = NULL; 5485170222Sdougb server->pps_timer = NULL; 5486186462Sdougb 5487135446Strhodes server->interface_interval = 0; 5488135446Strhodes server->heartbeat_interval = 0; 5489135446Strhodes 5490135446Strhodes CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 5491135446Strhodes ns_g_socketmgr, &server->zonemgr), 5492135446Strhodes "dns_zonemgr_create"); 5493225361Sdougb CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), 5494225361Sdougb "dns_zonemgr_setsize"); 5495135446Strhodes 5496135446Strhodes server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 5497135446Strhodes CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5498135446Strhodes "isc_mem_strdup"); 5499193149Sdougb server->nsstats = NULL; 5500193149Sdougb server->rcvquerystats = NULL; 5501193149Sdougb server->opcodestats = NULL; 5502193149Sdougb server->zonestats = NULL; 5503193149Sdougb server->resolverstats = NULL; 5504193149Sdougb server->sockstats = NULL; 5505193149Sdougb CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, 5506193149Sdougb isc_sockstatscounter_max), 5507193149Sdougb "isc_stats_create"); 5508193149Sdougb isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); 5509135446Strhodes 5510224092Sdougb server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys"); 5511224092Sdougb CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY : 5512224092Sdougb ISC_R_SUCCESS, 5513224092Sdougb "isc_mem_strdup"); 5514224092Sdougb 5515135446Strhodes server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 5516135446Strhodes CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5517135446Strhodes "isc_mem_strdup"); 5518135446Strhodes 5519224092Sdougb server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots"); 5520224092Sdougb CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY : 5521224092Sdougb ISC_R_SUCCESS, 5522224092Sdougb "isc_mem_strdup"); 5523224092Sdougb 5524135446Strhodes server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 5525135446Strhodes CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 5526135446Strhodes "isc_mem_strdup"); 5527135446Strhodes 5528135446Strhodes server->hostname_set = ISC_FALSE; 5529135446Strhodes server->hostname = NULL; 5530186462Sdougb server->version_set = ISC_FALSE; 5531135446Strhodes server->version = NULL; 5532135446Strhodes server->server_usehostname = ISC_FALSE; 5533135446Strhodes server->server_id = NULL; 5534135446Strhodes 5535193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats, 5536193149Sdougb dns_nsstatscounter_max), 5537193149Sdougb "dns_stats_create (server)"); 5538135446Strhodes 5539193149Sdougb CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, 5540193149Sdougb &server->rcvquerystats), 5541193149Sdougb "dns_stats_create (rcvquery)"); 5542193149Sdougb 5543193149Sdougb CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), 5544193149Sdougb "dns_stats_create (opcode)"); 5545193149Sdougb 5546193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats, 5547193149Sdougb dns_zonestatscounter_max), 5548193149Sdougb "dns_stats_create (zone)"); 5549193149Sdougb 5550193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats, 5551193149Sdougb dns_resstatscounter_max), 5552193149Sdougb "dns_stats_create (resolver)"); 5553193149Sdougb 5554135446Strhodes server->flushonshutdown = ISC_FALSE; 5555135446Strhodes server->log_queries = ISC_FALSE; 5556135446Strhodes 5557135446Strhodes server->controls = NULL; 5558135446Strhodes CHECKFATAL(ns_controls_create(server, &server->controls), 5559135446Strhodes "ns_controls_create"); 5560135446Strhodes server->dispatchgen = 0; 5561135446Strhodes ISC_LIST_INIT(server->dispatches); 5562135446Strhodes 5563193149Sdougb ISC_LIST_INIT(server->statschannels); 5564193149Sdougb 5565224092Sdougb ISC_LIST_INIT(server->cachelist); 5566224092Sdougb 5567224092Sdougb server->sessionkey = NULL; 5568224092Sdougb server->session_keyfile = NULL; 5569224092Sdougb server->session_keyname = NULL; 5570224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 5571224092Sdougb server->session_keybits = 0; 5572224092Sdougb 5573135446Strhodes server->magic = NS_SERVER_MAGIC; 5574135446Strhodes *serverp = server; 5575135446Strhodes} 5576135446Strhodes 5577135446Strhodesvoid 5578135446Strhodesns_server_destroy(ns_server_t **serverp) { 5579135446Strhodes ns_server_t *server = *serverp; 5580135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5581135446Strhodes 5582135446Strhodes ns_controls_destroy(&server->controls); 5583135446Strhodes 5584193149Sdougb isc_stats_detach(&server->nsstats); 5585193149Sdougb dns_stats_detach(&server->rcvquerystats); 5586193149Sdougb dns_stats_detach(&server->opcodestats); 5587193149Sdougb isc_stats_detach(&server->zonestats); 5588193149Sdougb isc_stats_detach(&server->resolverstats); 5589193149Sdougb isc_stats_detach(&server->sockstats); 5590135446Strhodes 5591135446Strhodes isc_mem_free(server->mctx, server->statsfile); 5592224092Sdougb isc_mem_free(server->mctx, server->bindkeysfile); 5593135446Strhodes isc_mem_free(server->mctx, server->dumpfile); 5594224092Sdougb isc_mem_free(server->mctx, server->secrootsfile); 5595135446Strhodes isc_mem_free(server->mctx, server->recfile); 5596135446Strhodes 5597135446Strhodes if (server->version != NULL) 5598135446Strhodes isc_mem_free(server->mctx, server->version); 5599135446Strhodes if (server->hostname != NULL) 5600135446Strhodes isc_mem_free(server->mctx, server->hostname); 5601135446Strhodes if (server->server_id != NULL) 5602135446Strhodes isc_mem_free(server->mctx, server->server_id); 5603135446Strhodes 5604225361Sdougb if (server->zonemgr != NULL) 5605225361Sdougb dns_zonemgr_detach(&server->zonemgr); 5606135446Strhodes 5607135446Strhodes if (server->tkeyctx != NULL) 5608135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 5609135446Strhodes 5610135446Strhodes dst_lib_destroy(); 5611135446Strhodes 5612135446Strhodes isc_event_free(&server->reload_event); 5613135446Strhodes 5614135446Strhodes INSIST(ISC_LIST_EMPTY(server->viewlist)); 5615224092Sdougb INSIST(ISC_LIST_EMPTY(server->cachelist)); 5616135446Strhodes 5617135446Strhodes dns_aclenv_destroy(&server->aclenv); 5618135446Strhodes 5619135446Strhodes isc_quota_destroy(&server->recursionquota); 5620135446Strhodes isc_quota_destroy(&server->tcpquota); 5621135446Strhodes isc_quota_destroy(&server->xfroutquota); 5622135446Strhodes 5623135446Strhodes server->magic = 0; 5624135446Strhodes isc_mem_put(server->mctx, server, sizeof(*server)); 5625135446Strhodes *serverp = NULL; 5626135446Strhodes} 5627135446Strhodes 5628135446Strhodesstatic void 5629135446Strhodesfatal(const char *msg, isc_result_t result) { 5630135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5631135446Strhodes ISC_LOG_CRITICAL, "%s: %s", msg, 5632135446Strhodes isc_result_totext(result)); 5633135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5634135446Strhodes ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 5635135446Strhodes exit(1); 5636135446Strhodes} 5637135446Strhodes 5638135446Strhodesstatic void 5639135446Strhodesstart_reserved_dispatches(ns_server_t *server) { 5640135446Strhodes 5641135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5642135446Strhodes 5643135446Strhodes server->dispatchgen++; 5644135446Strhodes} 5645135446Strhodes 5646135446Strhodesstatic void 5647135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 5648135446Strhodes ns_dispatch_t *dispatch, *nextdispatch; 5649135446Strhodes 5650135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5651135446Strhodes 5652135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 5653135446Strhodes dispatch != NULL; 5654135446Strhodes dispatch = nextdispatch) { 5655135446Strhodes nextdispatch = ISC_LIST_NEXT(dispatch, link); 5656135446Strhodes if (!all && server->dispatchgen == dispatch-> dispatchgen) 5657135446Strhodes continue; 5658135446Strhodes ISC_LIST_UNLINK(server->dispatches, dispatch, link); 5659135446Strhodes dns_dispatch_detach(&dispatch->dispatch); 5660135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 5661135446Strhodes } 5662135446Strhodes} 5663135446Strhodes 5664135446Strhodesvoid 5665165071Sdougbns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 5666135446Strhodes ns_dispatch_t *dispatch; 5667135446Strhodes in_port_t port; 5668135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 5669135446Strhodes isc_result_t result; 5670135446Strhodes unsigned int attrs, attrmask; 5671135446Strhodes 5672135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 5673135446Strhodes 5674135446Strhodes port = isc_sockaddr_getport(addr); 5675135446Strhodes if (port == 0 || port >= 1024) 5676135446Strhodes return; 5677135446Strhodes 5678135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 5679135446Strhodes dispatch != NULL; 5680135446Strhodes dispatch = ISC_LIST_NEXT(dispatch, link)) { 5681135446Strhodes if (isc_sockaddr_equal(&dispatch->addr, addr)) 5682135446Strhodes break; 5683135446Strhodes } 5684135446Strhodes if (dispatch != NULL) { 5685135446Strhodes dispatch->dispatchgen = server->dispatchgen; 5686135446Strhodes return; 5687135446Strhodes } 5688135446Strhodes 5689135446Strhodes dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 5690135446Strhodes if (dispatch == NULL) { 5691135446Strhodes result = ISC_R_NOMEMORY; 5692135446Strhodes goto cleanup; 5693135446Strhodes } 5694135446Strhodes 5695135446Strhodes dispatch->addr = *addr; 5696135446Strhodes dispatch->dispatchgen = server->dispatchgen; 5697135446Strhodes dispatch->dispatch = NULL; 5698135446Strhodes 5699135446Strhodes attrs = 0; 5700135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 5701135446Strhodes switch (isc_sockaddr_pf(addr)) { 5702135446Strhodes case AF_INET: 5703135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 5704135446Strhodes break; 5705135446Strhodes case AF_INET6: 5706135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 5707135446Strhodes break; 5708135446Strhodes default: 5709135446Strhodes result = ISC_R_NOTIMPLEMENTED; 5710135446Strhodes goto cleanup; 5711135446Strhodes } 5712135446Strhodes attrmask = 0; 5713135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 5714135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 5715135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 5716135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 5717135446Strhodes 5718135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 5719135446Strhodes ns_g_taskmgr, &dispatch->addr, 4096, 5720135446Strhodes 1000, 32768, 16411, 16433, 5721186462Sdougb attrs, attrmask, &dispatch->dispatch); 5722135446Strhodes if (result != ISC_R_SUCCESS) 5723135446Strhodes goto cleanup; 5724135446Strhodes 5725135446Strhodes ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 5726135446Strhodes 5727135446Strhodes return; 5728135446Strhodes 5729135446Strhodes cleanup: 5730135446Strhodes if (dispatch != NULL) 5731135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 5732135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 5733135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5734135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 5735135446Strhodes "unable to create dispatch for reserved port %s: %s", 5736135446Strhodes addrbuf, isc_result_totext(result)); 5737135446Strhodes} 5738135446Strhodes 5739135446Strhodes 5740135446Strhodesstatic isc_result_t 5741135446Strhodesloadconfig(ns_server_t *server) { 5742135446Strhodes isc_result_t result; 5743135446Strhodes start_reserved_dispatches(server); 5744135446Strhodes result = load_configuration(ns_g_lwresdonly ? 5745135446Strhodes lwresd_g_conffile : ns_g_conffile, 5746143731Sdougb server, ISC_FALSE); 5747193149Sdougb if (result == ISC_R_SUCCESS) { 5748135446Strhodes end_reserved_dispatches(server, ISC_FALSE); 5749135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5750193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5751193149Sdougb "reloading configuration succeeded"); 5752193149Sdougb } else { 5753193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5754135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5755135446Strhodes "reloading configuration failed: %s", 5756135446Strhodes isc_result_totext(result)); 5757193149Sdougb } 5758135446Strhodes return (result); 5759135446Strhodes} 5760135446Strhodes 5761135446Strhodesstatic isc_result_t 5762135446Strhodesreload(ns_server_t *server) { 5763135446Strhodes isc_result_t result; 5764135446Strhodes CHECK(loadconfig(server)); 5765135446Strhodes 5766135446Strhodes result = load_zones(server, ISC_FALSE); 5767193149Sdougb if (result == ISC_R_SUCCESS) 5768135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5769193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5770193149Sdougb "reloading zones succeeded"); 5771193149Sdougb else 5772193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5773135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5774135446Strhodes "reloading zones failed: %s", 5775135446Strhodes isc_result_totext(result)); 5776193149Sdougb 5777135446Strhodes cleanup: 5778135446Strhodes return (result); 5779135446Strhodes} 5780135446Strhodes 5781135446Strhodesstatic void 5782135446Strhodesreconfig(ns_server_t *server) { 5783135446Strhodes isc_result_t result; 5784135446Strhodes CHECK(loadconfig(server)); 5785135446Strhodes 5786135446Strhodes result = load_new_zones(server, ISC_FALSE); 5787193149Sdougb if (result == ISC_R_SUCCESS) 5788135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5789193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5790193149Sdougb "any newly configured zones are now loaded"); 5791193149Sdougb else 5792193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5793135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5794135446Strhodes "loading new zones failed: %s", 5795135446Strhodes isc_result_totext(result)); 5796193149Sdougb 5797135446Strhodes cleanup: ; 5798135446Strhodes} 5799135446Strhodes 5800135446Strhodes/* 5801135446Strhodes * Handle a reload event (from SIGHUP). 5802135446Strhodes */ 5803135446Strhodesstatic void 5804135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event) { 5805135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5806135446Strhodes 5807135446Strhodes INSIST(task = server->task); 5808135446Strhodes UNUSED(task); 5809135446Strhodes 5810193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5811193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5812193149Sdougb "received SIGHUP signal to reload zones"); 5813135446Strhodes (void)reload(server); 5814135446Strhodes 5815135446Strhodes LOCK(&server->reload_event_lock); 5816135446Strhodes INSIST(server->reload_event == NULL); 5817135446Strhodes server->reload_event = event; 5818135446Strhodes UNLOCK(&server->reload_event_lock); 5819135446Strhodes} 5820135446Strhodes 5821135446Strhodesvoid 5822135446Strhodesns_server_reloadwanted(ns_server_t *server) { 5823135446Strhodes LOCK(&server->reload_event_lock); 5824135446Strhodes if (server->reload_event != NULL) 5825135446Strhodes isc_task_send(server->task, &server->reload_event); 5826135446Strhodes UNLOCK(&server->reload_event_lock); 5827135446Strhodes} 5828135446Strhodes 5829135446Strhodesstatic char * 5830135446Strhodesnext_token(char **stringp, const char *delim) { 5831135446Strhodes char *res; 5832135446Strhodes 5833135446Strhodes do { 5834135446Strhodes res = strsep(stringp, delim); 5835135446Strhodes if (res == NULL) 5836135446Strhodes break; 5837135446Strhodes } while (*res == '\0'); 5838135446Strhodes return (res); 5839186462Sdougb} 5840135446Strhodes 5841135446Strhodes/* 5842135446Strhodes * Find the zone specified in the control channel command 'args', 5843135446Strhodes * if any. If a zone is specified, point '*zonep' at it, otherwise 5844135446Strhodes * set '*zonep' to NULL. 5845135446Strhodes */ 5846135446Strhodesstatic isc_result_t 5847224092Sdougbzone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep, 5848224092Sdougb const char **zonename) 5849224092Sdougb{ 5850135446Strhodes char *input, *ptr; 5851135446Strhodes const char *zonetxt; 5852135446Strhodes char *classtxt; 5853135446Strhodes const char *viewtxt = NULL; 5854135446Strhodes dns_fixedname_t name; 5855135446Strhodes isc_result_t result; 5856135446Strhodes isc_buffer_t buf; 5857135446Strhodes dns_view_t *view = NULL; 5858135446Strhodes dns_rdataclass_t rdclass; 5859135446Strhodes 5860135446Strhodes REQUIRE(zonep != NULL && *zonep == NULL); 5861135446Strhodes 5862135446Strhodes input = args; 5863135446Strhodes 5864135446Strhodes /* Skip the command name. */ 5865135446Strhodes ptr = next_token(&input, " \t"); 5866135446Strhodes if (ptr == NULL) 5867135446Strhodes return (ISC_R_UNEXPECTEDEND); 5868135446Strhodes 5869135446Strhodes /* Look for the zone name. */ 5870135446Strhodes zonetxt = next_token(&input, " \t"); 5871135446Strhodes if (zonetxt == NULL) 5872135446Strhodes return (ISC_R_SUCCESS); 5873224092Sdougb if (zonename) 5874224092Sdougb *zonename = zonetxt; 5875135446Strhodes 5876135446Strhodes /* Look for the optional class name. */ 5877135446Strhodes classtxt = next_token(&input, " \t"); 5878135446Strhodes if (classtxt != NULL) { 5879135446Strhodes /* Look for the optional view name. */ 5880135446Strhodes viewtxt = next_token(&input, " \t"); 5881135446Strhodes } 5882135446Strhodes 5883135446Strhodes isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); 5884135446Strhodes isc_buffer_add(&buf, strlen(zonetxt)); 5885135446Strhodes dns_fixedname_init(&name); 5886135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&name), 5887224092Sdougb &buf, dns_rootname, 0, NULL); 5888135446Strhodes if (result != ISC_R_SUCCESS) 5889135446Strhodes goto fail1; 5890135446Strhodes 5891135446Strhodes if (classtxt != NULL) { 5892135446Strhodes isc_textregion_t r; 5893135446Strhodes r.base = classtxt; 5894135446Strhodes r.length = strlen(classtxt); 5895135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &r); 5896135446Strhodes if (result != ISC_R_SUCCESS) 5897135446Strhodes goto fail1; 5898193149Sdougb } else 5899193149Sdougb rdclass = dns_rdataclass_in; 5900193149Sdougb 5901193149Sdougb if (viewtxt == NULL) { 5902193149Sdougb result = dns_viewlist_findzone(&server->viewlist, 5903193149Sdougb dns_fixedname_name(&name), 5904193149Sdougb ISC_TF(classtxt == NULL), 5905193149Sdougb rdclass, zonep); 5906135446Strhodes } else { 5907193149Sdougb result = dns_viewlist_find(&server->viewlist, viewtxt, 5908193149Sdougb rdclass, &view); 5909193149Sdougb if (result != ISC_R_SUCCESS) 5910193149Sdougb goto fail1; 5911193149Sdougb 5912193149Sdougb result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), 5913193149Sdougb 0, NULL, zonep); 5914193149Sdougb dns_view_detach(&view); 5915135446Strhodes } 5916186462Sdougb 5917135446Strhodes /* Partial match? */ 5918135446Strhodes if (result != ISC_R_SUCCESS && *zonep != NULL) 5919135446Strhodes dns_zone_detach(zonep); 5920204619Sdougb if (result == DNS_R_PARTIALMATCH) 5921204619Sdougb result = ISC_R_NOTFOUND; 5922135446Strhodes fail1: 5923135446Strhodes return (result); 5924135446Strhodes} 5925135446Strhodes 5926135446Strhodes/* 5927135446Strhodes * Act on a "retransfer" command from the command channel. 5928135446Strhodes */ 5929135446Strhodesisc_result_t 5930135446Strhodesns_server_retransfercommand(ns_server_t *server, char *args) { 5931135446Strhodes isc_result_t result; 5932135446Strhodes dns_zone_t *zone = NULL; 5933135446Strhodes dns_zonetype_t type; 5934186462Sdougb 5935224092Sdougb result = zone_from_args(server, args, &zone, NULL); 5936135446Strhodes if (result != ISC_R_SUCCESS) 5937135446Strhodes return (result); 5938135446Strhodes if (zone == NULL) 5939135446Strhodes return (ISC_R_UNEXPECTEDEND); 5940135446Strhodes type = dns_zone_gettype(zone); 5941135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) 5942135446Strhodes dns_zone_forcereload(zone); 5943135446Strhodes else 5944135446Strhodes result = ISC_R_NOTFOUND; 5945135446Strhodes dns_zone_detach(&zone); 5946135446Strhodes return (result); 5947186462Sdougb} 5948135446Strhodes 5949135446Strhodes/* 5950135446Strhodes * Act on a "reload" command from the command channel. 5951135446Strhodes */ 5952135446Strhodesisc_result_t 5953135446Strhodesns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 5954135446Strhodes isc_result_t result; 5955135446Strhodes dns_zone_t *zone = NULL; 5956135446Strhodes dns_zonetype_t type; 5957135446Strhodes const char *msg = NULL; 5958186462Sdougb 5959224092Sdougb result = zone_from_args(server, args, &zone, NULL); 5960135446Strhodes if (result != ISC_R_SUCCESS) 5961135446Strhodes return (result); 5962135446Strhodes if (zone == NULL) { 5963135446Strhodes result = reload(server); 5964135446Strhodes if (result == ISC_R_SUCCESS) 5965135446Strhodes msg = "server reload successful"; 5966135446Strhodes } else { 5967135446Strhodes type = dns_zone_gettype(zone); 5968135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) { 5969135446Strhodes dns_zone_refresh(zone); 5970174187Sdougb dns_zone_detach(&zone); 5971135446Strhodes msg = "zone refresh queued"; 5972135446Strhodes } else { 5973135446Strhodes result = dns_zone_load(zone); 5974135446Strhodes dns_zone_detach(&zone); 5975186462Sdougb switch (result) { 5976135446Strhodes case ISC_R_SUCCESS: 5977135446Strhodes msg = "zone reload successful"; 5978135446Strhodes break; 5979135446Strhodes case DNS_R_CONTINUE: 5980135446Strhodes msg = "zone reload queued"; 5981135446Strhodes result = ISC_R_SUCCESS; 5982135446Strhodes break; 5983135446Strhodes case DNS_R_UPTODATE: 5984135446Strhodes msg = "zone reload up-to-date"; 5985135446Strhodes result = ISC_R_SUCCESS; 5986135446Strhodes break; 5987135446Strhodes default: 5988135446Strhodes /* failure message will be generated by rndc */ 5989135446Strhodes break; 5990135446Strhodes } 5991135446Strhodes } 5992135446Strhodes } 5993135446Strhodes if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 5994135446Strhodes isc_buffer_putmem(text, (const unsigned char *)msg, 5995135446Strhodes strlen(msg) + 1); 5996135446Strhodes return (result); 5997186462Sdougb} 5998135446Strhodes 5999135446Strhodes/* 6000135446Strhodes * Act on a "reconfig" command from the command channel. 6001135446Strhodes */ 6002135446Strhodesisc_result_t 6003135446Strhodesns_server_reconfigcommand(ns_server_t *server, char *args) { 6004135446Strhodes UNUSED(args); 6005135446Strhodes 6006135446Strhodes reconfig(server); 6007135446Strhodes return (ISC_R_SUCCESS); 6008135446Strhodes} 6009135446Strhodes 6010135446Strhodes/* 6011170222Sdougb * Act on a "notify" command from the command channel. 6012170222Sdougb */ 6013170222Sdougbisc_result_t 6014170222Sdougbns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6015170222Sdougb isc_result_t result; 6016170222Sdougb dns_zone_t *zone = NULL; 6017170222Sdougb const unsigned char msg[] = "zone notify queued"; 6018170222Sdougb 6019224092Sdougb result = zone_from_args(server, args, &zone, NULL); 6020170222Sdougb if (result != ISC_R_SUCCESS) 6021170222Sdougb return (result); 6022170222Sdougb if (zone == NULL) 6023170222Sdougb return (ISC_R_UNEXPECTEDEND); 6024186462Sdougb 6025170222Sdougb dns_zone_notify(zone); 6026170222Sdougb dns_zone_detach(&zone); 6027170222Sdougb if (sizeof(msg) <= isc_buffer_availablelength(text)) 6028170222Sdougb isc_buffer_putmem(text, msg, sizeof(msg)); 6029170222Sdougb 6030170222Sdougb return (ISC_R_SUCCESS); 6031186462Sdougb} 6032170222Sdougb 6033170222Sdougb/* 6034135446Strhodes * Act on a "refresh" command from the command channel. 6035135446Strhodes */ 6036135446Strhodesisc_result_t 6037135446Strhodesns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6038135446Strhodes isc_result_t result; 6039135446Strhodes dns_zone_t *zone = NULL; 6040165071Sdougb const unsigned char msg1[] = "zone refresh queued"; 6041165071Sdougb const unsigned char msg2[] = "not a slave or stub zone"; 6042165071Sdougb dns_zonetype_t type; 6043135446Strhodes 6044224092Sdougb result = zone_from_args(server, args, &zone, NULL); 6045135446Strhodes if (result != ISC_R_SUCCESS) 6046135446Strhodes return (result); 6047135446Strhodes if (zone == NULL) 6048135446Strhodes return (ISC_R_UNEXPECTEDEND); 6049165071Sdougb 6050165071Sdougb type = dns_zone_gettype(zone); 6051165071Sdougb if (type == dns_zone_slave || type == dns_zone_stub) { 6052165071Sdougb dns_zone_refresh(zone); 6053165071Sdougb dns_zone_detach(&zone); 6054165071Sdougb if (sizeof(msg1) <= isc_buffer_availablelength(text)) 6055165071Sdougb isc_buffer_putmem(text, msg1, sizeof(msg1)); 6056165071Sdougb return (ISC_R_SUCCESS); 6057165071Sdougb } 6058186462Sdougb 6059135446Strhodes dns_zone_detach(&zone); 6060165071Sdougb if (sizeof(msg2) <= isc_buffer_availablelength(text)) 6061165071Sdougb isc_buffer_putmem(text, msg2, sizeof(msg2)); 6062165071Sdougb return (ISC_R_FAILURE); 6063186462Sdougb} 6064135446Strhodes 6065135446Strhodesisc_result_t 6066135446Strhodesns_server_togglequerylog(ns_server_t *server) { 6067135446Strhodes server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; 6068186462Sdougb 6069135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6070135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6071135446Strhodes "query logging is now %s", 6072135446Strhodes server->log_queries ? "on" : "off"); 6073135446Strhodes return (ISC_R_SUCCESS); 6074135446Strhodes} 6075135446Strhodes 6076135446Strhodesstatic isc_result_t 6077165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 6078170222Sdougb cfg_aclconfctx_t *actx, 6079135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target) 6080135446Strhodes{ 6081135446Strhodes isc_result_t result; 6082165071Sdougb const cfg_listelt_t *element; 6083135446Strhodes ns_listenlist_t *dlist = NULL; 6084135446Strhodes 6085135446Strhodes REQUIRE(target != NULL && *target == NULL); 6086135446Strhodes 6087135446Strhodes result = ns_listenlist_create(mctx, &dlist); 6088135446Strhodes if (result != ISC_R_SUCCESS) 6089135446Strhodes return (result); 6090135446Strhodes 6091135446Strhodes for (element = cfg_list_first(listenlist); 6092135446Strhodes element != NULL; 6093135446Strhodes element = cfg_list_next(element)) 6094135446Strhodes { 6095135446Strhodes ns_listenelt_t *delt = NULL; 6096165071Sdougb const cfg_obj_t *listener = cfg_listelt_value(element); 6097135446Strhodes result = ns_listenelt_fromconfig(listener, config, actx, 6098135446Strhodes mctx, &delt); 6099135446Strhodes if (result != ISC_R_SUCCESS) 6100135446Strhodes goto cleanup; 6101135446Strhodes ISC_LIST_APPEND(dlist->elts, delt, link); 6102135446Strhodes } 6103135446Strhodes *target = dlist; 6104135446Strhodes return (ISC_R_SUCCESS); 6105135446Strhodes 6106135446Strhodes cleanup: 6107135446Strhodes ns_listenlist_detach(&dlist); 6108135446Strhodes return (result); 6109135446Strhodes} 6110135446Strhodes 6111135446Strhodes/* 6112135446Strhodes * Create a listen list from the corresponding configuration 6113135446Strhodes * data structure. 6114135446Strhodes */ 6115135446Strhodesstatic isc_result_t 6116165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 6117170222Sdougb cfg_aclconfctx_t *actx, 6118135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target) 6119135446Strhodes{ 6120135446Strhodes isc_result_t result; 6121165071Sdougb const cfg_obj_t *portobj; 6122135446Strhodes in_port_t port; 6123135446Strhodes ns_listenelt_t *delt = NULL; 6124135446Strhodes REQUIRE(target != NULL && *target == NULL); 6125135446Strhodes 6126135446Strhodes portobj = cfg_tuple_get(listener, "port"); 6127135446Strhodes if (!cfg_obj_isuint32(portobj)) { 6128135446Strhodes if (ns_g_port != 0) { 6129135446Strhodes port = ns_g_port; 6130135446Strhodes } else { 6131135446Strhodes result = ns_config_getport(config, &port); 6132135446Strhodes if (result != ISC_R_SUCCESS) 6133135446Strhodes return (result); 6134135446Strhodes } 6135135446Strhodes } else { 6136135446Strhodes if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 6137135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 6138135446Strhodes "port value '%u' is out of range", 6139135446Strhodes cfg_obj_asuint32(portobj)); 6140135446Strhodes return (ISC_R_RANGE); 6141135446Strhodes } 6142135446Strhodes port = (in_port_t)cfg_obj_asuint32(portobj); 6143135446Strhodes } 6144135446Strhodes 6145135446Strhodes result = ns_listenelt_create(mctx, port, NULL, &delt); 6146135446Strhodes if (result != ISC_R_SUCCESS) 6147135446Strhodes return (result); 6148135446Strhodes 6149170222Sdougb result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), 6150193149Sdougb config, ns_g_lctx, actx, mctx, 0, 6151193149Sdougb &delt->acl); 6152135446Strhodes if (result != ISC_R_SUCCESS) { 6153135446Strhodes ns_listenelt_destroy(delt); 6154135446Strhodes return (result); 6155135446Strhodes } 6156135446Strhodes *target = delt; 6157135446Strhodes return (ISC_R_SUCCESS); 6158135446Strhodes} 6159135446Strhodes 6160135446Strhodesisc_result_t 6161135446Strhodesns_server_dumpstats(ns_server_t *server) { 6162135446Strhodes isc_result_t result; 6163135446Strhodes FILE *fp = NULL; 6164135446Strhodes 6165135446Strhodes CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 6166135446Strhodes "could not open statistics dump file", server->statsfile); 6167186462Sdougb 6168193149Sdougb result = ns_stats_dump(server, fp); 6169186462Sdougb 6170135446Strhodes cleanup: 6171135446Strhodes if (fp != NULL) 6172135446Strhodes (void)isc_stdio_close(fp); 6173193149Sdougb if (result == ISC_R_SUCCESS) 6174193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6175193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6176193149Sdougb "dumpstats complete"); 6177193149Sdougb else 6178193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6179193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6180193149Sdougb "dumpstats failed: %s", 6181193149Sdougb dns_result_totext(result)); 6182135446Strhodes return (result); 6183135446Strhodes} 6184135446Strhodes 6185135446Strhodesstatic isc_result_t 6186135446Strhodesadd_zone_tolist(dns_zone_t *zone, void *uap) { 6187135446Strhodes struct dumpcontext *dctx = uap; 6188135446Strhodes struct zonelistentry *zle; 6189135446Strhodes 6190135446Strhodes zle = isc_mem_get(dctx->mctx, sizeof *zle); 6191135446Strhodes if (zle == NULL) 6192135446Strhodes return (ISC_R_NOMEMORY); 6193135446Strhodes zle->zone = NULL; 6194135446Strhodes dns_zone_attach(zone, &zle->zone); 6195135446Strhodes ISC_LINK_INIT(zle, link); 6196135446Strhodes ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 6197135446Strhodes return (ISC_R_SUCCESS); 6198135446Strhodes} 6199135446Strhodes 6200135446Strhodesstatic isc_result_t 6201135446Strhodesadd_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 6202135446Strhodes struct viewlistentry *vle; 6203135446Strhodes isc_result_t result = ISC_R_SUCCESS; 6204186462Sdougb 6205153816Sdougb /* 6206153816Sdougb * Prevent duplicate views. 6207153816Sdougb */ 6208153816Sdougb for (vle = ISC_LIST_HEAD(dctx->viewlist); 6209153816Sdougb vle != NULL; 6210153816Sdougb vle = ISC_LIST_NEXT(vle, link)) 6211153816Sdougb if (vle->view == view) 6212153816Sdougb return (ISC_R_SUCCESS); 6213153816Sdougb 6214135446Strhodes vle = isc_mem_get(dctx->mctx, sizeof *vle); 6215135446Strhodes if (vle == NULL) 6216135446Strhodes return (ISC_R_NOMEMORY); 6217135446Strhodes vle->view = NULL; 6218135446Strhodes dns_view_attach(view, &vle->view); 6219135446Strhodes ISC_LINK_INIT(vle, link); 6220135446Strhodes ISC_LIST_INIT(vle->zonelist); 6221135446Strhodes ISC_LIST_APPEND(dctx->viewlist, vle, link); 6222135446Strhodes if (dctx->dumpzones) 6223135446Strhodes result = dns_zt_apply(view->zonetable, ISC_TRUE, 6224135446Strhodes add_zone_tolist, dctx); 6225135446Strhodes return (result); 6226135446Strhodes} 6227135446Strhodes 6228135446Strhodesstatic void 6229135446Strhodesdumpcontext_destroy(struct dumpcontext *dctx) { 6230135446Strhodes struct viewlistentry *vle; 6231135446Strhodes struct zonelistentry *zle; 6232135446Strhodes 6233135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6234135446Strhodes while (vle != NULL) { 6235135446Strhodes ISC_LIST_UNLINK(dctx->viewlist, vle, link); 6236135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6237135446Strhodes while (zle != NULL) { 6238135446Strhodes ISC_LIST_UNLINK(vle->zonelist, zle, link); 6239135446Strhodes dns_zone_detach(&zle->zone); 6240135446Strhodes isc_mem_put(dctx->mctx, zle, sizeof *zle); 6241135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6242135446Strhodes } 6243135446Strhodes dns_view_detach(&vle->view); 6244135446Strhodes isc_mem_put(dctx->mctx, vle, sizeof *vle); 6245135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6246135446Strhodes } 6247135446Strhodes if (dctx->version != NULL) 6248135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 6249135446Strhodes if (dctx->db != NULL) 6250135446Strhodes dns_db_detach(&dctx->db); 6251135446Strhodes if (dctx->cache != NULL) 6252135446Strhodes dns_db_detach(&dctx->cache); 6253135446Strhodes if (dctx->task != NULL) 6254135446Strhodes isc_task_detach(&dctx->task); 6255135446Strhodes if (dctx->fp != NULL) 6256135446Strhodes (void)isc_stdio_close(dctx->fp); 6257135446Strhodes if (dctx->mdctx != NULL) 6258135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 6259135446Strhodes isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 6260135446Strhodes} 6261135446Strhodes 6262135446Strhodesstatic void 6263135446Strhodesdumpdone(void *arg, isc_result_t result) { 6264135446Strhodes struct dumpcontext *dctx = arg; 6265135446Strhodes char buf[1024+32]; 6266135446Strhodes const dns_master_style_t *style; 6267186462Sdougb 6268135446Strhodes if (result != ISC_R_SUCCESS) 6269135446Strhodes goto cleanup; 6270135446Strhodes if (dctx->mdctx != NULL) 6271135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 6272135446Strhodes if (dctx->view == NULL) { 6273135446Strhodes dctx->view = ISC_LIST_HEAD(dctx->viewlist); 6274135446Strhodes if (dctx->view == NULL) 6275135446Strhodes goto done; 6276135446Strhodes INSIST(dctx->zone == NULL); 6277153816Sdougb } else 6278153816Sdougb goto resume; 6279135446Strhodes nextview: 6280135446Strhodes fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 6281153816Sdougb resume: 6282224092Sdougb if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) { 6283224092Sdougb fprintf(dctx->fp, 6284224092Sdougb ";\n; Cache of view '%s' is shared as '%s'\n", 6285224092Sdougb dctx->view->view->name, 6286224092Sdougb dns_cache_getname(dctx->view->view->cache)); 6287224092Sdougb } else if (dctx->zone == NULL && dctx->cache == NULL && 6288224092Sdougb dctx->dumpcache) 6289224092Sdougb { 6290135446Strhodes style = &dns_master_style_cache; 6291135446Strhodes /* start cache dump */ 6292135446Strhodes if (dctx->view->view->cachedb != NULL) 6293135446Strhodes dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 6294135446Strhodes if (dctx->cache != NULL) { 6295224092Sdougb fprintf(dctx->fp, 6296224092Sdougb ";\n; Cache dump of view '%s' (cache %s)\n;\n", 6297224092Sdougb dctx->view->view->name, 6298224092Sdougb dns_cache_getname(dctx->view->view->cache)); 6299135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 6300135446Strhodes dctx->cache, NULL, 6301135446Strhodes style, dctx->fp, 6302135446Strhodes dctx->task, 6303135446Strhodes dumpdone, dctx, 6304135446Strhodes &dctx->mdctx); 6305135446Strhodes if (result == DNS_R_CONTINUE) 6306135446Strhodes return; 6307135446Strhodes if (result == ISC_R_NOTIMPLEMENTED) 6308135446Strhodes fprintf(dctx->fp, "; %s\n", 6309135446Strhodes dns_result_totext(result)); 6310135446Strhodes else if (result != ISC_R_SUCCESS) 6311135446Strhodes goto cleanup; 6312135446Strhodes } 6313135446Strhodes } 6314135446Strhodes if (dctx->cache != NULL) { 6315135446Strhodes dns_adb_dump(dctx->view->view->adb, dctx->fp); 6316205292Sdougb dns_resolver_printbadcache(dctx->view->view->resolver, 6317205292Sdougb dctx->fp); 6318135446Strhodes dns_db_detach(&dctx->cache); 6319135446Strhodes } 6320135446Strhodes if (dctx->dumpzones) { 6321135446Strhodes style = &dns_master_style_full; 6322135446Strhodes nextzone: 6323135446Strhodes if (dctx->version != NULL) 6324135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, 6325135446Strhodes ISC_FALSE); 6326135446Strhodes if (dctx->db != NULL) 6327135446Strhodes dns_db_detach(&dctx->db); 6328135446Strhodes if (dctx->zone == NULL) 6329135446Strhodes dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 6330135446Strhodes else 6331135446Strhodes dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 6332135446Strhodes if (dctx->zone != NULL) { 6333135446Strhodes /* start zone dump */ 6334135446Strhodes dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 6335135446Strhodes fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 6336135446Strhodes result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 6337135446Strhodes if (result != ISC_R_SUCCESS) { 6338135446Strhodes fprintf(dctx->fp, "; %s\n", 6339135446Strhodes dns_result_totext(result)); 6340135446Strhodes goto nextzone; 6341135446Strhodes } 6342135446Strhodes dns_db_currentversion(dctx->db, &dctx->version); 6343135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 6344135446Strhodes dctx->db, 6345135446Strhodes dctx->version, 6346135446Strhodes style, dctx->fp, 6347135446Strhodes dctx->task, 6348135446Strhodes dumpdone, dctx, 6349135446Strhodes &dctx->mdctx); 6350135446Strhodes if (result == DNS_R_CONTINUE) 6351135446Strhodes return; 6352153816Sdougb if (result == ISC_R_NOTIMPLEMENTED) { 6353135446Strhodes fprintf(dctx->fp, "; %s\n", 6354135446Strhodes dns_result_totext(result)); 6355153816Sdougb result = ISC_R_SUCCESS; 6356225361Sdougb POST(result); 6357153816Sdougb goto nextzone; 6358153816Sdougb } 6359135446Strhodes if (result != ISC_R_SUCCESS) 6360135446Strhodes goto cleanup; 6361135446Strhodes } 6362135446Strhodes } 6363135446Strhodes if (dctx->view != NULL) 6364135446Strhodes dctx->view = ISC_LIST_NEXT(dctx->view, link); 6365135446Strhodes if (dctx->view != NULL) 6366135446Strhodes goto nextview; 6367135446Strhodes done: 6368135446Strhodes fprintf(dctx->fp, "; Dump complete\n"); 6369135446Strhodes result = isc_stdio_flush(dctx->fp); 6370135446Strhodes if (result == ISC_R_SUCCESS) 6371135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6372135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6373135446Strhodes "dumpdb complete"); 6374135446Strhodes cleanup: 6375135446Strhodes if (result != ISC_R_SUCCESS) 6376135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6377193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6378135446Strhodes "dumpdb failed: %s", dns_result_totext(result)); 6379135446Strhodes dumpcontext_destroy(dctx); 6380135446Strhodes} 6381135446Strhodes 6382135446Strhodesisc_result_t 6383135446Strhodesns_server_dumpdb(ns_server_t *server, char *args) { 6384135446Strhodes struct dumpcontext *dctx = NULL; 6385135446Strhodes dns_view_t *view; 6386135446Strhodes isc_result_t result; 6387135446Strhodes char *ptr; 6388135446Strhodes const char *sep; 6389135446Strhodes 6390165071Sdougb /* Skip the command name. */ 6391165071Sdougb ptr = next_token(&args, " \t"); 6392165071Sdougb if (ptr == NULL) 6393165071Sdougb return (ISC_R_UNEXPECTEDEND); 6394165071Sdougb 6395135446Strhodes dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 6396135446Strhodes if (dctx == NULL) 6397135446Strhodes return (ISC_R_NOMEMORY); 6398135446Strhodes 6399135446Strhodes dctx->mctx = server->mctx; 6400135446Strhodes dctx->dumpcache = ISC_TRUE; 6401135446Strhodes dctx->dumpzones = ISC_FALSE; 6402135446Strhodes dctx->fp = NULL; 6403135446Strhodes ISC_LIST_INIT(dctx->viewlist); 6404135446Strhodes dctx->view = NULL; 6405135446Strhodes dctx->zone = NULL; 6406135446Strhodes dctx->cache = NULL; 6407135446Strhodes dctx->mdctx = NULL; 6408135446Strhodes dctx->db = NULL; 6409135446Strhodes dctx->cache = NULL; 6410135446Strhodes dctx->task = NULL; 6411135446Strhodes dctx->version = NULL; 6412135446Strhodes isc_task_attach(server->task, &dctx->task); 6413135446Strhodes 6414135446Strhodes CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 6415135446Strhodes "could not open dump file", server->dumpfile); 6416135446Strhodes 6417135446Strhodes sep = (args == NULL) ? "" : ": "; 6418135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6419135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6420135446Strhodes "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 6421135446Strhodes 6422135446Strhodes ptr = next_token(&args, " \t"); 6423135446Strhodes if (ptr != NULL && strcmp(ptr, "-all") == 0) { 6424135446Strhodes dctx->dumpzones = ISC_TRUE; 6425135446Strhodes dctx->dumpcache = ISC_TRUE; 6426135446Strhodes ptr = next_token(&args, " \t"); 6427135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 6428135446Strhodes dctx->dumpzones = ISC_FALSE; 6429135446Strhodes dctx->dumpcache = ISC_TRUE; 6430135446Strhodes ptr = next_token(&args, " \t"); 6431135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 6432135446Strhodes dctx->dumpzones = ISC_TRUE; 6433135446Strhodes dctx->dumpcache = ISC_FALSE; 6434135446Strhodes ptr = next_token(&args, " \t"); 6435186462Sdougb } 6436135446Strhodes 6437153816Sdougb nextview: 6438135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 6439135446Strhodes view != NULL; 6440135446Strhodes view = ISC_LIST_NEXT(view, link)) 6441135446Strhodes { 6442135446Strhodes if (ptr != NULL && strcmp(view->name, ptr) != 0) 6443135446Strhodes continue; 6444135446Strhodes CHECK(add_view_tolist(dctx, view)); 6445135446Strhodes } 6446153816Sdougb if (ptr != NULL) { 6447153816Sdougb ptr = next_token(&args, " \t"); 6448153816Sdougb if (ptr != NULL) 6449153816Sdougb goto nextview; 6450153816Sdougb } 6451135446Strhodes dumpdone(dctx, ISC_R_SUCCESS); 6452135446Strhodes return (ISC_R_SUCCESS); 6453135446Strhodes 6454135446Strhodes cleanup: 6455135446Strhodes if (dctx != NULL) 6456135446Strhodes dumpcontext_destroy(dctx); 6457135446Strhodes return (result); 6458135446Strhodes} 6459135446Strhodes 6460135446Strhodesisc_result_t 6461224092Sdougbns_server_dumpsecroots(ns_server_t *server, char *args) { 6462224092Sdougb dns_view_t *view; 6463224092Sdougb dns_keytable_t *secroots = NULL; 6464224092Sdougb isc_result_t result; 6465224092Sdougb char *ptr; 6466224092Sdougb FILE *fp = NULL; 6467224092Sdougb isc_time_t now; 6468224092Sdougb char tbuf[64]; 6469224092Sdougb 6470224092Sdougb /* Skip the command name. */ 6471224092Sdougb ptr = next_token(&args, " \t"); 6472224092Sdougb if (ptr == NULL) 6473224092Sdougb return (ISC_R_UNEXPECTEDEND); 6474224092Sdougb ptr = next_token(&args, " \t"); 6475224092Sdougb 6476224092Sdougb CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp), 6477224092Sdougb "could not open secroots dump file", server->secrootsfile); 6478224092Sdougb TIME_NOW(&now); 6479224092Sdougb isc_time_formattimestamp(&now, tbuf, sizeof(tbuf)); 6480224092Sdougb fprintf(fp, "%s\n", tbuf); 6481224092Sdougb 6482225361Sdougb do { 6483225361Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6484225361Sdougb view != NULL; 6485225361Sdougb view = ISC_LIST_NEXT(view, link)) 6486225361Sdougb { 6487225361Sdougb if (ptr != NULL && strcmp(view->name, ptr) != 0) 6488225361Sdougb continue; 6489225361Sdougb if (secroots != NULL) 6490225361Sdougb dns_keytable_detach(&secroots); 6491225361Sdougb result = dns_view_getsecroots(view, &secroots); 6492225361Sdougb if (result == ISC_R_NOTFOUND) { 6493225361Sdougb result = ISC_R_SUCCESS; 6494225361Sdougb continue; 6495225361Sdougb } 6496225361Sdougb fprintf(fp, "\n Start view %s\n\n", view->name); 6497225361Sdougb result = dns_keytable_dump(secroots, fp); 6498225361Sdougb if (result != ISC_R_SUCCESS) 6499225361Sdougb fprintf(fp, " dumpsecroots failed: %s\n", 6500225361Sdougb isc_result_totext(result)); 6501224092Sdougb } 6502224092Sdougb if (ptr != NULL) 6503225361Sdougb ptr = next_token(&args, " \t"); 6504225361Sdougb } while (ptr != NULL); 6505224092Sdougb 6506224092Sdougb cleanup: 6507224092Sdougb if (secroots != NULL) 6508224092Sdougb dns_keytable_detach(&secroots); 6509224092Sdougb if (fp != NULL) 6510224092Sdougb (void)isc_stdio_close(fp); 6511224092Sdougb if (result == ISC_R_SUCCESS) 6512224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6513224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6514224092Sdougb "dumpsecroots complete"); 6515224092Sdougb else 6516224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6517224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6518224092Sdougb "dumpsecroots failed: %s", 6519224092Sdougb dns_result_totext(result)); 6520224092Sdougb return (result); 6521224092Sdougb} 6522224092Sdougb 6523224092Sdougbisc_result_t 6524135446Strhodesns_server_dumprecursing(ns_server_t *server) { 6525135446Strhodes FILE *fp = NULL; 6526135446Strhodes isc_result_t result; 6527135446Strhodes 6528135446Strhodes CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 6529135446Strhodes "could not open dump file", server->recfile); 6530135446Strhodes fprintf(fp,";\n; Recursing Queries\n;\n"); 6531135446Strhodes ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 6532135446Strhodes fprintf(fp, "; Dump complete\n"); 6533135446Strhodes 6534135446Strhodes cleanup: 6535135446Strhodes if (fp != NULL) 6536135446Strhodes result = isc_stdio_close(fp); 6537193149Sdougb if (result == ISC_R_SUCCESS) 6538193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6539193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6540193149Sdougb "dumprecursing complete"); 6541193149Sdougb else 6542193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6543193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6544193149Sdougb "dumprecursing failed: %s", 6545193149Sdougb dns_result_totext(result)); 6546135446Strhodes return (result); 6547135446Strhodes} 6548135446Strhodes 6549135446Strhodesisc_result_t 6550135446Strhodesns_server_setdebuglevel(ns_server_t *server, char *args) { 6551135446Strhodes char *ptr; 6552135446Strhodes char *levelstr; 6553135446Strhodes char *endp; 6554135446Strhodes long newlevel; 6555135446Strhodes 6556135446Strhodes UNUSED(server); 6557135446Strhodes 6558135446Strhodes /* Skip the command name. */ 6559135446Strhodes ptr = next_token(&args, " \t"); 6560135446Strhodes if (ptr == NULL) 6561135446Strhodes return (ISC_R_UNEXPECTEDEND); 6562135446Strhodes 6563135446Strhodes /* Look for the new level name. */ 6564135446Strhodes levelstr = next_token(&args, " \t"); 6565135446Strhodes if (levelstr == NULL) { 6566135446Strhodes if (ns_g_debuglevel < 99) 6567135446Strhodes ns_g_debuglevel++; 6568135446Strhodes } else { 6569135446Strhodes newlevel = strtol(levelstr, &endp, 10); 6570135446Strhodes if (*endp != '\0' || newlevel < 0 || newlevel > 99) 6571135446Strhodes return (ISC_R_RANGE); 6572135446Strhodes ns_g_debuglevel = (unsigned int)newlevel; 6573135446Strhodes } 6574135446Strhodes isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 6575193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6576193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6577193149Sdougb "debug level is now %d", ns_g_debuglevel); 6578135446Strhodes return (ISC_R_SUCCESS); 6579135446Strhodes} 6580135446Strhodes 6581135446Strhodesisc_result_t 6582170222Sdougbns_server_validation(ns_server_t *server, char *args) { 6583170222Sdougb char *ptr, *viewname; 6584170222Sdougb dns_view_t *view; 6585170222Sdougb isc_boolean_t changed = ISC_FALSE; 6586170222Sdougb isc_result_t result; 6587170222Sdougb isc_boolean_t enable; 6588170222Sdougb 6589170222Sdougb /* Skip the command name. */ 6590170222Sdougb ptr = next_token(&args, " \t"); 6591170222Sdougb if (ptr == NULL) 6592170222Sdougb return (ISC_R_UNEXPECTEDEND); 6593170222Sdougb 6594170222Sdougb /* Find out what we are to do. */ 6595170222Sdougb ptr = next_token(&args, " \t"); 6596170222Sdougb if (ptr == NULL) 6597170222Sdougb return (ISC_R_UNEXPECTEDEND); 6598170222Sdougb 6599170222Sdougb if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || 6600170222Sdougb !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) 6601170222Sdougb enable = ISC_TRUE; 6602170222Sdougb else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || 6603170222Sdougb !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) 6604170222Sdougb enable = ISC_FALSE; 6605170222Sdougb else 6606170222Sdougb return (DNS_R_SYNTAX); 6607170222Sdougb 6608170222Sdougb /* Look for the view name. */ 6609170222Sdougb viewname = next_token(&args, " \t"); 6610170222Sdougb 6611170222Sdougb result = isc_task_beginexclusive(server->task); 6612170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 6613170222Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6614170222Sdougb view != NULL; 6615170222Sdougb view = ISC_LIST_NEXT(view, link)) 6616170222Sdougb { 6617170222Sdougb if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 6618170222Sdougb continue; 6619170222Sdougb result = dns_view_flushcache(view); 6620170222Sdougb if (result != ISC_R_SUCCESS) 6621170222Sdougb goto out; 6622170222Sdougb view->enablevalidation = enable; 6623170222Sdougb changed = ISC_TRUE; 6624170222Sdougb } 6625170222Sdougb if (changed) 6626170222Sdougb result = ISC_R_SUCCESS; 6627170222Sdougb else 6628170222Sdougb result = ISC_R_FAILURE; 6629170222Sdougb out: 6630186462Sdougb isc_task_endexclusive(server->task); 6631170222Sdougb return (result); 6632170222Sdougb} 6633170222Sdougb 6634170222Sdougbisc_result_t 6635135446Strhodesns_server_flushcache(ns_server_t *server, char *args) { 6636135446Strhodes char *ptr, *viewname; 6637135446Strhodes dns_view_t *view; 6638174187Sdougb isc_boolean_t flushed; 6639174187Sdougb isc_boolean_t found; 6640135446Strhodes isc_result_t result; 6641224092Sdougb ns_cache_t *nsc; 6642135446Strhodes 6643135446Strhodes /* Skip the command name. */ 6644135446Strhodes ptr = next_token(&args, " \t"); 6645135446Strhodes if (ptr == NULL) 6646135446Strhodes return (ISC_R_UNEXPECTEDEND); 6647135446Strhodes 6648135446Strhodes /* Look for the view name. */ 6649135446Strhodes viewname = next_token(&args, " \t"); 6650135446Strhodes 6651135446Strhodes result = isc_task_beginexclusive(server->task); 6652135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6653174187Sdougb flushed = ISC_TRUE; 6654174187Sdougb found = ISC_FALSE; 6655224092Sdougb 6656224092Sdougb /* 6657224092Sdougb * Flushing a cache is tricky when caches are shared by multiple views. 6658224092Sdougb * We first identify which caches should be flushed in the local cache 6659224092Sdougb * list, flush these caches, and then update other views that refer to 6660224092Sdougb * the flushed cache DB. 6661224092Sdougb */ 6662224092Sdougb if (viewname != NULL) { 6663224092Sdougb /* 6664224092Sdougb * Mark caches that need to be flushed. This is an O(#view^2) 6665224092Sdougb * operation in the very worst case, but should be normally 6666224092Sdougb * much more lightweight because only a few (most typically just 6667224092Sdougb * one) views will match. 6668224092Sdougb */ 6669224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6670224092Sdougb view != NULL; 6671224092Sdougb view = ISC_LIST_NEXT(view, link)) 6672224092Sdougb { 6673224092Sdougb if (strcasecmp(viewname, view->name) != 0) 6674224092Sdougb continue; 6675224092Sdougb found = ISC_TRUE; 6676224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6677224092Sdougb nsc != NULL; 6678224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6679224092Sdougb if (nsc->cache == view->cache) 6680224092Sdougb break; 6681224092Sdougb } 6682224092Sdougb INSIST(nsc != NULL); 6683224092Sdougb nsc->needflush = ISC_TRUE; 6684224092Sdougb } 6685224092Sdougb } else 6686224092Sdougb found = ISC_TRUE; 6687224092Sdougb 6688224092Sdougb /* Perform flush */ 6689224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6690224092Sdougb nsc != NULL; 6691224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6692224092Sdougb if (viewname != NULL && !nsc->needflush) 6693135446Strhodes continue; 6694224092Sdougb nsc->needflush = ISC_TRUE; 6695224092Sdougb result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE); 6696193149Sdougb if (result != ISC_R_SUCCESS) { 6697174187Sdougb flushed = ISC_FALSE; 6698193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6699193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6700193149Sdougb "flushing cache in view '%s' failed: %s", 6701224092Sdougb nsc->primaryview->name, 6702224092Sdougb isc_result_totext(result)); 6703193149Sdougb } 6704135446Strhodes } 6705224092Sdougb 6706224092Sdougb /* 6707224092Sdougb * Fix up views that share a flushed cache: let the views update the 6708224092Sdougb * cache DB they're referring to. This could also be an expensive 6709224092Sdougb * operation, but should typically be marginal: the inner loop is only 6710224092Sdougb * necessary for views that share a cache, and if there are many such 6711224092Sdougb * views the number of shared cache should normally be small. 6712224092Sdougb * A worst case is that we have n views and n/2 caches, each shared by 6713224092Sdougb * two views. Then this will be a O(n^2/4) operation. 6714224092Sdougb */ 6715224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6716224092Sdougb view != NULL; 6717224092Sdougb view = ISC_LIST_NEXT(view, link)) 6718224092Sdougb { 6719224092Sdougb if (!dns_view_iscacheshared(view)) 6720224092Sdougb continue; 6721224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6722224092Sdougb nsc != NULL; 6723224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6724224092Sdougb if (!nsc->needflush || nsc->cache != view->cache) 6725224092Sdougb continue; 6726224092Sdougb result = dns_view_flushcache2(view, ISC_TRUE); 6727224092Sdougb if (result != ISC_R_SUCCESS) { 6728224092Sdougb flushed = ISC_FALSE; 6729224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6730224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6731224092Sdougb "fixing cache in view '%s' " 6732224092Sdougb "failed: %s", view->name, 6733224092Sdougb isc_result_totext(result)); 6734224092Sdougb } 6735224092Sdougb } 6736224092Sdougb } 6737224092Sdougb 6738224092Sdougb /* Cleanup the cache list. */ 6739224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 6740224092Sdougb nsc != NULL; 6741224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 6742224092Sdougb nsc->needflush = ISC_FALSE; 6743224092Sdougb } 6744224092Sdougb 6745174187Sdougb if (flushed && found) { 6746193149Sdougb if (viewname != NULL) 6747193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6748193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6749193149Sdougb "flushing cache in view '%s' succeeded", 6750193149Sdougb viewname); 6751193149Sdougb else 6752193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6753193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6754193149Sdougb "flushing caches in all views succeeded"); 6755135446Strhodes result = ISC_R_SUCCESS; 6756174187Sdougb } else { 6757193149Sdougb if (!found) { 6758193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6759193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6760193149Sdougb "flushing cache in view '%s' failed: " 6761193149Sdougb "view not found", viewname); 6762174187Sdougb result = ISC_R_NOTFOUND; 6763193149Sdougb } else 6764174187Sdougb result = ISC_R_FAILURE; 6765174187Sdougb } 6766186462Sdougb isc_task_endexclusive(server->task); 6767135446Strhodes return (result); 6768135446Strhodes} 6769135446Strhodes 6770135446Strhodesisc_result_t 6771135446Strhodesns_server_flushname(ns_server_t *server, char *args) { 6772135446Strhodes char *ptr, *target, *viewname; 6773135446Strhodes dns_view_t *view; 6774174187Sdougb isc_boolean_t flushed; 6775174187Sdougb isc_boolean_t found; 6776135446Strhodes isc_result_t result; 6777135446Strhodes isc_buffer_t b; 6778135446Strhodes dns_fixedname_t fixed; 6779135446Strhodes dns_name_t *name; 6780135446Strhodes 6781135446Strhodes /* Skip the command name. */ 6782135446Strhodes ptr = next_token(&args, " \t"); 6783135446Strhodes if (ptr == NULL) 6784135446Strhodes return (ISC_R_UNEXPECTEDEND); 6785135446Strhodes 6786135446Strhodes /* Find the domain name to flush. */ 6787135446Strhodes target = next_token(&args, " \t"); 6788135446Strhodes if (target == NULL) 6789135446Strhodes return (ISC_R_UNEXPECTEDEND); 6790135446Strhodes 6791135446Strhodes isc_buffer_init(&b, target, strlen(target)); 6792135446Strhodes isc_buffer_add(&b, strlen(target)); 6793135446Strhodes dns_fixedname_init(&fixed); 6794135446Strhodes name = dns_fixedname_name(&fixed); 6795224092Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 6796135446Strhodes if (result != ISC_R_SUCCESS) 6797135446Strhodes return (result); 6798135446Strhodes 6799135446Strhodes /* Look for the view name. */ 6800135446Strhodes viewname = next_token(&args, " \t"); 6801135446Strhodes 6802135446Strhodes result = isc_task_beginexclusive(server->task); 6803135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6804135446Strhodes flushed = ISC_TRUE; 6805174187Sdougb found = ISC_FALSE; 6806135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 6807135446Strhodes view != NULL; 6808135446Strhodes view = ISC_LIST_NEXT(view, link)) 6809135446Strhodes { 6810135446Strhodes if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 6811135446Strhodes continue; 6812174187Sdougb found = ISC_TRUE; 6813224092Sdougb /* 6814224092Sdougb * It's a little inefficient to try flushing name for all views 6815224092Sdougb * if some of the views share a single cache. But since the 6816224092Sdougb * operation is lightweight we prefer simplicity here. 6817224092Sdougb */ 6818135446Strhodes result = dns_view_flushname(view, name); 6819193149Sdougb if (result != ISC_R_SUCCESS) { 6820135446Strhodes flushed = ISC_FALSE; 6821193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6822193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6823193149Sdougb "flushing name '%s' in cache view '%s' " 6824193149Sdougb "failed: %s", target, view->name, 6825193149Sdougb isc_result_totext(result)); 6826193149Sdougb } 6827135446Strhodes } 6828193149Sdougb if (flushed && found) { 6829193149Sdougb if (viewname != NULL) 6830193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6831193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6832193149Sdougb "flushing name '%s' in cache view '%s' " 6833193149Sdougb "succeeded", target, viewname); 6834193149Sdougb else 6835193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6836193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6837193149Sdougb "flushing name '%s' in all cache views " 6838193149Sdougb "succeeded", target); 6839135446Strhodes result = ISC_R_SUCCESS; 6840193149Sdougb } else { 6841193149Sdougb if (!found) 6842193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6843193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6844193149Sdougb "flushing name '%s' in cache view '%s' " 6845193149Sdougb "failed: view not found", target, 6846193149Sdougb viewname); 6847135446Strhodes result = ISC_R_FAILURE; 6848193149Sdougb } 6849186462Sdougb isc_task_endexclusive(server->task); 6850135446Strhodes return (result); 6851135446Strhodes} 6852135446Strhodes 6853135446Strhodesisc_result_t 6854135446Strhodesns_server_status(ns_server_t *server, isc_buffer_t *text) { 6855135446Strhodes int zonecount, xferrunning, xferdeferred, soaqueries; 6856135446Strhodes unsigned int n; 6857193149Sdougb const char *ob = "", *cb = "", *alt = ""; 6858135446Strhodes 6859193149Sdougb if (ns_g_server->version_set) { 6860193149Sdougb ob = " ("; 6861193149Sdougb cb = ")"; 6862193149Sdougb if (ns_g_server->version == NULL) 6863193149Sdougb alt = "version.bind/txt/ch disabled"; 6864193149Sdougb else 6865193149Sdougb alt = ns_g_server->version; 6866193149Sdougb } 6867135446Strhodes zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 6868135446Strhodes xferrunning = dns_zonemgr_getcount(server->zonemgr, 6869135446Strhodes DNS_ZONESTATE_XFERRUNNING); 6870135446Strhodes xferdeferred = dns_zonemgr_getcount(server->zonemgr, 6871135446Strhodes DNS_ZONESTATE_XFERDEFERRED); 6872135446Strhodes soaqueries = dns_zonemgr_getcount(server->zonemgr, 6873135446Strhodes DNS_ZONESTATE_SOAQUERY); 6874193149Sdougb 6875135446Strhodes n = snprintf((char *)isc_buffer_used(text), 6876135446Strhodes isc_buffer_availablelength(text), 6877193149Sdougb "version: %s%s%s%s\n" 6878193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 6879193149Sdougb "CPUs found: %u\n" 6880193149Sdougb "worker threads: %u\n" 6881193149Sdougb#endif 6882135446Strhodes "number of zones: %u\n" 6883135446Strhodes "debug level: %d\n" 6884135446Strhodes "xfers running: %u\n" 6885135446Strhodes "xfers deferred: %u\n" 6886135446Strhodes "soa queries in progress: %u\n" 6887135446Strhodes "query logging is %s\n" 6888170222Sdougb "recursive clients: %d/%d/%d\n" 6889135446Strhodes "tcp clients: %d/%d\n" 6890135446Strhodes "server is up and running", 6891193149Sdougb ns_g_version, ob, alt, cb, 6892193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 6893193149Sdougb ns_g_cpus_detected, ns_g_cpus, 6894193149Sdougb#endif 6895135446Strhodes zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 6896135446Strhodes soaqueries, server->log_queries ? "ON" : "OFF", 6897170222Sdougb server->recursionquota.used, server->recursionquota.soft, 6898170222Sdougb server->recursionquota.max, 6899135446Strhodes server->tcpquota.used, server->tcpquota.max); 6900135446Strhodes if (n >= isc_buffer_availablelength(text)) 6901135446Strhodes return (ISC_R_NOSPACE); 6902135446Strhodes isc_buffer_add(text, n); 6903135446Strhodes return (ISC_R_SUCCESS); 6904135446Strhodes} 6905135446Strhodes 6906193149Sdougbstatic isc_result_t 6907193149Sdougbdelete_keynames(dns_tsig_keyring_t *ring, char *target, 6908193149Sdougb unsigned int *foundkeys) 6909193149Sdougb{ 6910193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 6911193149Sdougb isc_result_t result; 6912193149Sdougb dns_rbtnodechain_t chain; 6913193149Sdougb dns_name_t foundname; 6914193149Sdougb dns_fixedname_t fixedorigin; 6915193149Sdougb dns_name_t *origin; 6916193149Sdougb dns_rbtnode_t *node; 6917193149Sdougb dns_tsigkey_t *tkey; 6918193149Sdougb 6919193149Sdougb dns_name_init(&foundname, NULL); 6920193149Sdougb dns_fixedname_init(&fixedorigin); 6921193149Sdougb origin = dns_fixedname_name(&fixedorigin); 6922193149Sdougb 6923193149Sdougb again: 6924193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 6925193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 6926193149Sdougb origin); 6927193149Sdougb if (result == ISC_R_NOTFOUND) { 6928193149Sdougb dns_rbtnodechain_invalidate(&chain); 6929193149Sdougb return (ISC_R_SUCCESS); 6930193149Sdougb } 6931193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 6932193149Sdougb dns_rbtnodechain_invalidate(&chain); 6933193149Sdougb return (result); 6934193149Sdougb } 6935193149Sdougb 6936193149Sdougb for (;;) { 6937193149Sdougb node = NULL; 6938193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 6939193149Sdougb tkey = node->data; 6940193149Sdougb 6941193149Sdougb if (tkey != NULL) { 6942193149Sdougb if (!tkey->generated) 6943193149Sdougb goto nextkey; 6944193149Sdougb 6945193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 6946193149Sdougb if (strcmp(namestr, target) == 0) { 6947193149Sdougb (*foundkeys)++; 6948193149Sdougb dns_rbtnodechain_invalidate(&chain); 6949193149Sdougb (void)dns_rbt_deletename(ring->keys, 6950193149Sdougb &tkey->name, 6951193149Sdougb ISC_FALSE); 6952193149Sdougb goto again; 6953193149Sdougb } 6954193149Sdougb } 6955193149Sdougb 6956193149Sdougb nextkey: 6957193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 6958193149Sdougb if (result == ISC_R_NOMORE) 6959193149Sdougb break; 6960193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 6961193149Sdougb dns_rbtnodechain_invalidate(&chain); 6962193149Sdougb return (result); 6963193149Sdougb } 6964193149Sdougb } 6965193149Sdougb 6966193149Sdougb return (ISC_R_SUCCESS); 6967193149Sdougb} 6968193149Sdougb 6969193149Sdougbisc_result_t 6970193149Sdougbns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) { 6971193149Sdougb isc_result_t result; 6972193149Sdougb unsigned int n; 6973193149Sdougb dns_view_t *view; 6974193149Sdougb unsigned int foundkeys = 0; 6975193149Sdougb char *target; 6976193149Sdougb char *viewname; 6977193149Sdougb 6978193149Sdougb (void)next_token(&command, " \t"); /* skip command name */ 6979193149Sdougb target = next_token(&command, " \t"); 6980193149Sdougb if (target == NULL) 6981193149Sdougb return (ISC_R_UNEXPECTEDEND); 6982193149Sdougb viewname = next_token(&command, " \t"); 6983193149Sdougb 6984193149Sdougb result = isc_task_beginexclusive(server->task); 6985193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 6986193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 6987193149Sdougb view != NULL; 6988193149Sdougb view = ISC_LIST_NEXT(view, link)) { 6989193149Sdougb if (viewname == NULL || strcmp(view->name, viewname) == 0) { 6990193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); 6991193149Sdougb result = delete_keynames(view->dynamickeys, target, 6992193149Sdougb &foundkeys); 6993193149Sdougb RWUNLOCK(&view->dynamickeys->lock, 6994193149Sdougb isc_rwlocktype_write); 6995193149Sdougb if (result != ISC_R_SUCCESS) { 6996193149Sdougb isc_task_endexclusive(server->task); 6997193149Sdougb return (result); 6998193149Sdougb } 6999193149Sdougb } 7000193149Sdougb } 7001193149Sdougb isc_task_endexclusive(server->task); 7002193149Sdougb 7003193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7004193149Sdougb isc_buffer_availablelength(text), 7005193149Sdougb "%d tsig keys deleted.\n", foundkeys); 7006218384Sdougb if (n >= isc_buffer_availablelength(text)) 7007193149Sdougb return (ISC_R_NOSPACE); 7008193149Sdougb isc_buffer_add(text, n); 7009193149Sdougb 7010193149Sdougb return (ISC_R_SUCCESS); 7011193149Sdougb} 7012193149Sdougb 7013193149Sdougbstatic isc_result_t 7014193149Sdougblist_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text, 7015193149Sdougb unsigned int *foundkeys) 7016193149Sdougb{ 7017193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 7018193149Sdougb char creatorstr[DNS_NAME_FORMATSIZE]; 7019193149Sdougb isc_result_t result; 7020193149Sdougb dns_rbtnodechain_t chain; 7021193149Sdougb dns_name_t foundname; 7022193149Sdougb dns_fixedname_t fixedorigin; 7023193149Sdougb dns_name_t *origin; 7024193149Sdougb dns_rbtnode_t *node; 7025193149Sdougb dns_tsigkey_t *tkey; 7026193149Sdougb unsigned int n; 7027193149Sdougb const char *viewname; 7028193149Sdougb 7029193149Sdougb if (view != NULL) 7030193149Sdougb viewname = view->name; 7031193149Sdougb else 7032193149Sdougb viewname = "(global)"; 7033193149Sdougb 7034193149Sdougb dns_name_init(&foundname, NULL); 7035193149Sdougb dns_fixedname_init(&fixedorigin); 7036193149Sdougb origin = dns_fixedname_name(&fixedorigin); 7037193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 7038193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 7039193149Sdougb origin); 7040193149Sdougb if (result == ISC_R_NOTFOUND) { 7041193149Sdougb dns_rbtnodechain_invalidate(&chain); 7042193149Sdougb return (ISC_R_SUCCESS); 7043193149Sdougb } 7044193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7045193149Sdougb dns_rbtnodechain_invalidate(&chain); 7046193149Sdougb return (result); 7047193149Sdougb } 7048193149Sdougb 7049193149Sdougb for (;;) { 7050193149Sdougb node = NULL; 7051193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 7052193149Sdougb tkey = node->data; 7053193149Sdougb 7054193149Sdougb if (tkey != NULL) { 7055193149Sdougb (*foundkeys)++; 7056193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 7057193149Sdougb if (tkey->generated) { 7058193149Sdougb dns_name_format(tkey->creator, creatorstr, 7059193149Sdougb sizeof(creatorstr)); 7060193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7061193149Sdougb isc_buffer_availablelength(text), 7062193149Sdougb "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n", 7063193149Sdougb viewname, namestr, creatorstr); 7064193149Sdougb } else { 7065193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7066193149Sdougb isc_buffer_availablelength(text), 7067193149Sdougb "view \"%s\"; type \"static\"; key \"%s\";\n", 7068193149Sdougb viewname, namestr); 7069193149Sdougb } 7070193149Sdougb if (n >= isc_buffer_availablelength(text)) { 7071193149Sdougb dns_rbtnodechain_invalidate(&chain); 7072193149Sdougb return (ISC_R_NOSPACE); 7073193149Sdougb } 7074193149Sdougb isc_buffer_add(text, n); 7075193149Sdougb } 7076193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 7077193149Sdougb if (result == ISC_R_NOMORE) 7078193149Sdougb break; 7079193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7080193149Sdougb dns_rbtnodechain_invalidate(&chain); 7081193149Sdougb return (result); 7082193149Sdougb } 7083193149Sdougb } 7084193149Sdougb 7085193149Sdougb return (ISC_R_SUCCESS); 7086193149Sdougb} 7087193149Sdougb 7088193149Sdougbisc_result_t 7089193149Sdougbns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { 7090193149Sdougb isc_result_t result; 7091193149Sdougb unsigned int n; 7092193149Sdougb dns_view_t *view; 7093193149Sdougb unsigned int foundkeys = 0; 7094193149Sdougb 7095193149Sdougb result = isc_task_beginexclusive(server->task); 7096193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7097193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7098193149Sdougb view != NULL; 7099193149Sdougb view = ISC_LIST_NEXT(view, link)) { 7100193149Sdougb RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7101193149Sdougb result = list_keynames(view, view->statickeys, text, 7102193149Sdougb &foundkeys); 7103193149Sdougb RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7104193149Sdougb if (result != ISC_R_SUCCESS) { 7105193149Sdougb isc_task_endexclusive(server->task); 7106193149Sdougb return (result); 7107193149Sdougb } 7108193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7109193149Sdougb result = list_keynames(view, view->dynamickeys, text, 7110193149Sdougb &foundkeys); 7111193149Sdougb RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7112193149Sdougb if (result != ISC_R_SUCCESS) { 7113193149Sdougb isc_task_endexclusive(server->task); 7114193149Sdougb return (result); 7115193149Sdougb } 7116193149Sdougb } 7117193149Sdougb isc_task_endexclusive(server->task); 7118193149Sdougb 7119193149Sdougb if (foundkeys == 0) { 7120193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7121193149Sdougb isc_buffer_availablelength(text), 7122193149Sdougb "no tsig keys found.\n"); 7123218384Sdougb if (n >= isc_buffer_availablelength(text)) 7124193149Sdougb return (ISC_R_NOSPACE); 7125193149Sdougb isc_buffer_add(text, n); 7126193149Sdougb } 7127193149Sdougb 7128193149Sdougb return (ISC_R_SUCCESS); 7129193149Sdougb} 7130193149Sdougb 7131135446Strhodes/* 7132224092Sdougb * Act on a "sign" or "loadkeys" command from the command channel. 7133224092Sdougb */ 7134224092Sdougbisc_result_t 7135224092Sdougbns_server_rekey(ns_server_t *server, char *args) { 7136224092Sdougb isc_result_t result; 7137224092Sdougb dns_zone_t *zone = NULL; 7138224092Sdougb dns_zonetype_t type; 7139224092Sdougb isc_uint16_t keyopts; 7140224092Sdougb isc_boolean_t fullsign = ISC_FALSE; 7141224092Sdougb 7142224092Sdougb if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0) 7143224092Sdougb fullsign = ISC_TRUE; 7144224092Sdougb 7145224092Sdougb result = zone_from_args(server, args, &zone, NULL); 7146224092Sdougb if (result != ISC_R_SUCCESS) 7147224092Sdougb return (result); 7148224092Sdougb if (zone == NULL) 7149224092Sdougb return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */ 7150224092Sdougb 7151224092Sdougb type = dns_zone_gettype(zone); 7152224092Sdougb if (type != dns_zone_master) { 7153224092Sdougb dns_zone_detach(&zone); 7154224092Sdougb return (DNS_R_NOTMASTER); 7155224092Sdougb } 7156224092Sdougb 7157224092Sdougb keyopts = dns_zone_getkeyopts(zone); 7158224092Sdougb 7159224092Sdougb /* "rndc loadkeys" requires "auto-dnssec maintain". */ 7160224092Sdougb if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) 7161224092Sdougb result = ISC_R_NOPERM; 7162224092Sdougb else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) 7163224092Sdougb result = ISC_R_NOPERM; 7164224092Sdougb else 7165224092Sdougb dns_zone_rekey(zone, fullsign); 7166224092Sdougb 7167224092Sdougb dns_zone_detach(&zone); 7168224092Sdougb return (result); 7169224092Sdougb} 7170224092Sdougb 7171224092Sdougb/* 7172170222Sdougb * Act on a "freeze" or "thaw" command from the command channel. 7173135446Strhodes */ 7174135446Strhodesisc_result_t 7175204619Sdougbns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, 7176204619Sdougb isc_buffer_t *text) 7177204619Sdougb{ 7178170222Sdougb isc_result_t result, tresult; 7179135446Strhodes dns_zone_t *zone = NULL; 7180135446Strhodes dns_zonetype_t type; 7181135446Strhodes char classstr[DNS_RDATACLASS_FORMATSIZE]; 7182135446Strhodes char zonename[DNS_NAME_FORMATSIZE]; 7183135446Strhodes dns_view_t *view; 7184135446Strhodes char *journal; 7185135446Strhodes const char *vname, *sep; 7186135446Strhodes isc_boolean_t frozen; 7187204619Sdougb const char *msg = NULL; 7188186462Sdougb 7189224092Sdougb result = zone_from_args(server, args, &zone, NULL); 7190135446Strhodes if (result != ISC_R_SUCCESS) 7191135446Strhodes return (result); 7192170222Sdougb if (zone == NULL) { 7193170222Sdougb result = isc_task_beginexclusive(server->task); 7194170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7195170222Sdougb tresult = ISC_R_SUCCESS; 7196186462Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7197170222Sdougb view != NULL; 7198170222Sdougb view = ISC_LIST_NEXT(view, link)) { 7199170222Sdougb result = dns_view_freezezones(view, freeze); 7200170222Sdougb if (result != ISC_R_SUCCESS && 7201170222Sdougb tresult == ISC_R_SUCCESS) 7202170222Sdougb tresult = result; 7203170222Sdougb } 7204170222Sdougb isc_task_endexclusive(server->task); 7205170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7206170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7207170222Sdougb "%s all zones: %s", 7208170222Sdougb freeze ? "freezing" : "thawing", 7209170222Sdougb isc_result_totext(tresult)); 7210170222Sdougb return (tresult); 7211170222Sdougb } 7212135446Strhodes type = dns_zone_gettype(zone); 7213135446Strhodes if (type != dns_zone_master) { 7214135446Strhodes dns_zone_detach(&zone); 7215224092Sdougb return (DNS_R_NOTMASTER); 7216135446Strhodes } 7217135446Strhodes 7218204619Sdougb result = isc_task_beginexclusive(server->task); 7219204619Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7220135446Strhodes frozen = dns_zone_getupdatedisabled(zone); 7221135446Strhodes if (freeze) { 7222204619Sdougb if (frozen) { 7223204619Sdougb msg = "WARNING: The zone was already frozen.\n" 7224204619Sdougb "Someone else may be editing it or " 7225204619Sdougb "it may still be re-loading."; 7226135446Strhodes result = DNS_R_FROZEN; 7227204619Sdougb } 7228204619Sdougb if (result == ISC_R_SUCCESS) { 7229135446Strhodes result = dns_zone_flush(zone); 7230204619Sdougb if (result != ISC_R_SUCCESS) 7231204619Sdougb msg = "Flushing the zone updates to " 7232204619Sdougb "disk failed."; 7233204619Sdougb } 7234135446Strhodes if (result == ISC_R_SUCCESS) { 7235135446Strhodes journal = dns_zone_getjournal(zone); 7236135446Strhodes if (journal != NULL) 7237135446Strhodes (void)isc_file_remove(journal); 7238135446Strhodes } 7239204619Sdougb if (result == ISC_R_SUCCESS) 7240204619Sdougb dns_zone_setupdatedisabled(zone, freeze); 7241135446Strhodes } else { 7242135446Strhodes if (frozen) { 7243204619Sdougb result = dns_zone_loadandthaw(zone); 7244204619Sdougb switch (result) { 7245204619Sdougb case ISC_R_SUCCESS: 7246204619Sdougb case DNS_R_UPTODATE: 7247204619Sdougb msg = "The zone reload and thaw was " 7248204619Sdougb "successful."; 7249135446Strhodes result = ISC_R_SUCCESS; 7250204619Sdougb break; 7251204619Sdougb case DNS_R_CONTINUE: 7252204619Sdougb msg = "A zone reload and thaw was started.\n" 7253204619Sdougb "Check the logs to see the result."; 7254204619Sdougb result = ISC_R_SUCCESS; 7255204619Sdougb break; 7256204619Sdougb } 7257135446Strhodes } 7258135446Strhodes } 7259204619Sdougb isc_task_endexclusive(server->task); 7260135446Strhodes 7261204619Sdougb if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 7262204619Sdougb isc_buffer_putmem(text, (const unsigned char *)msg, 7263204619Sdougb strlen(msg) + 1); 7264204619Sdougb 7265135446Strhodes view = dns_zone_getview(zone); 7266224092Sdougb if (strcmp(view->name, "_default") == 0 || 7267224092Sdougb strcmp(view->name, "_bind") == 0) 7268135446Strhodes { 7269135446Strhodes vname = ""; 7270135446Strhodes sep = ""; 7271135446Strhodes } else { 7272135446Strhodes vname = view->name; 7273135446Strhodes sep = " "; 7274135446Strhodes } 7275135446Strhodes dns_rdataclass_format(dns_zone_getclass(zone), classstr, 7276135446Strhodes sizeof(classstr)); 7277135446Strhodes dns_name_format(dns_zone_getorigin(zone), 7278135446Strhodes zonename, sizeof(zonename)); 7279135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7280135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7281135446Strhodes "%s zone '%s/%s'%s%s: %s", 7282170222Sdougb freeze ? "freezing" : "thawing", 7283135446Strhodes zonename, classstr, sep, vname, 7284135446Strhodes isc_result_totext(result)); 7285135446Strhodes dns_zone_detach(&zone); 7286135446Strhodes return (result); 7287135446Strhodes} 7288153816Sdougb 7289153816Sdougb#ifdef HAVE_LIBSCF 7290153816Sdougb/* 7291153816Sdougb * This function adds a message for rndc to echo if named 7292153816Sdougb * is managed by smf and is also running chroot. 7293153816Sdougb */ 7294153816Sdougbisc_result_t 7295153816Sdougbns_smf_add_message(isc_buffer_t *text) { 7296153816Sdougb unsigned int n; 7297153816Sdougb 7298153816Sdougb n = snprintf((char *)isc_buffer_used(text), 7299153816Sdougb isc_buffer_availablelength(text), 7300153816Sdougb "use svcadm(1M) to manage named"); 7301153816Sdougb if (n >= isc_buffer_availablelength(text)) 7302153816Sdougb return (ISC_R_NOSPACE); 7303153816Sdougb isc_buffer_add(text, n); 7304153816Sdougb return (ISC_R_SUCCESS); 7305153816Sdougb} 7306153816Sdougb#endif /* HAVE_LIBSCF */ 7307224092Sdougb 7308224092Sdougb/* 7309224092Sdougb * Act on an "addzone" command from the command channel. 7310224092Sdougb */ 7311224092Sdougbisc_result_t 7312224092Sdougbns_server_add_zone(ns_server_t *server, char *args) { 7313224092Sdougb isc_result_t result; 7314224092Sdougb isc_buffer_t argbuf; 7315224092Sdougb size_t arglen; 7316224092Sdougb cfg_parser_t *parser = NULL; 7317224092Sdougb cfg_obj_t *config = NULL; 7318224092Sdougb const cfg_obj_t *vconfig = NULL; 7319224092Sdougb const cfg_obj_t *views = NULL; 7320224092Sdougb const cfg_obj_t *parms = NULL; 7321224092Sdougb const cfg_obj_t *obj = NULL; 7322224092Sdougb const cfg_listelt_t *element; 7323224092Sdougb const char *zonename; 7324224092Sdougb const char *classname = NULL; 7325224092Sdougb const char *argp; 7326224092Sdougb const char *viewname = NULL; 7327224092Sdougb dns_rdataclass_t rdclass; 7328224092Sdougb dns_view_t *view = 0; 7329224092Sdougb isc_buffer_t buf, *nbuf = NULL; 7330224092Sdougb dns_name_t dnsname; 7331224092Sdougb dns_zone_t *zone = NULL; 7332224092Sdougb FILE *fp = NULL; 7333224092Sdougb struct cfg_context *cfg = NULL; 7334224092Sdougb 7335224092Sdougb /* Try to parse the argument string */ 7336224092Sdougb arglen = strlen(args); 7337224092Sdougb isc_buffer_init(&argbuf, args, arglen); 7338224092Sdougb isc_buffer_add(&argbuf, strlen(args)); 7339224092Sdougb CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); 7340224092Sdougb CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, 7341224092Sdougb &config)); 7342224092Sdougb CHECK(cfg_map_get(config, "addzone", &parms)); 7343224092Sdougb 7344224092Sdougb zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name")); 7345224092Sdougb isc_buffer_init(&buf, zonename, strlen(zonename)); 7346224092Sdougb isc_buffer_add(&buf, strlen(zonename)); 7347224092Sdougb dns_name_init(&dnsname, NULL); 7348224092Sdougb isc_buffer_allocate(server->mctx, &nbuf, 256); 7349224092Sdougb dns_name_setbuffer(&dnsname, nbuf); 7350224092Sdougb CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL)); 7351224092Sdougb 7352224092Sdougb /* Make sense of optional class argument */ 7353224092Sdougb obj = cfg_tuple_get(parms, "class"); 7354224092Sdougb CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass)); 7355224092Sdougb if (rdclass != dns_rdataclass_in && obj) 7356224092Sdougb classname = cfg_obj_asstring(obj); 7357224092Sdougb 7358224092Sdougb /* Make sense of optional view argument */ 7359224092Sdougb obj = cfg_tuple_get(parms, "view"); 7360224092Sdougb if (obj && cfg_obj_isstring(obj)) 7361224092Sdougb viewname = cfg_obj_asstring(obj); 7362224092Sdougb if (viewname == NULL || *viewname == '\0') 7363224092Sdougb viewname = "_default"; 7364224092Sdougb CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view)); 7365224092Sdougb 7366224092Sdougb /* Are we accepting new zones? */ 7367224092Sdougb if (view->new_zone_file == NULL) { 7368224092Sdougb result = ISC_R_NOPERM; 7369224092Sdougb goto cleanup; 7370224092Sdougb } 7371224092Sdougb 7372224092Sdougb cfg = (struct cfg_context *) view->new_zone_config; 7373224092Sdougb if (cfg == NULL) { 7374224092Sdougb result = ISC_R_FAILURE; 7375224092Sdougb goto cleanup; 7376224092Sdougb } 7377224092Sdougb 7378224092Sdougb /* Zone shouldn't already exist */ 7379224092Sdougb result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone); 7380224092Sdougb if (result == ISC_R_SUCCESS) { 7381224092Sdougb result = ISC_R_EXISTS; 7382224092Sdougb goto cleanup; 7383224092Sdougb } else if (result == DNS_R_PARTIALMATCH) { 7384224092Sdougb /* Create our sub-zone anyway */ 7385224092Sdougb dns_zone_detach(&zone); 7386224092Sdougb zone = NULL; 7387224092Sdougb } 7388224092Sdougb else if (result != ISC_R_NOTFOUND) 7389224092Sdougb goto cleanup; 7390224092Sdougb 7391224092Sdougb /* Find the view statement */ 7392224092Sdougb cfg_map_get(cfg->config, "view", &views); 7393224092Sdougb for (element = cfg_list_first(views); 7394224092Sdougb element != NULL; 7395224092Sdougb element = cfg_list_next(element)) 7396224092Sdougb { 7397224092Sdougb const char *vname; 7398224092Sdougb vconfig = cfg_listelt_value(element); 7399224092Sdougb vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 7400224092Sdougb if (vname && !strcasecmp(vname, viewname)) 7401224092Sdougb break; 7402224092Sdougb vconfig = NULL; 7403224092Sdougb } 7404224092Sdougb 7405224092Sdougb /* Open save file for write configuration */ 7406224092Sdougb CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); 7407224092Sdougb 7408224092Sdougb /* Mark view unfrozen so that zone can be added */ 7409234010Sdougb isc_task_beginexclusive(server->task); 7410224092Sdougb dns_view_thaw(view); 7411224092Sdougb result = configure_zone(cfg->config, parms, vconfig, 7412225361Sdougb server->mctx, view, cfg->actx, ISC_FALSE); 7413224092Sdougb dns_view_freeze(view); 7414234010Sdougb isc_task_endexclusive(server->task); 7415234010Sdougb if (result != ISC_R_SUCCESS) 7416224092Sdougb goto cleanup; 7417224092Sdougb 7418224092Sdougb /* Is it there yet? */ 7419224092Sdougb CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone)); 7420224092Sdougb 7421224092Sdougb /* 7422224092Sdougb * Load the zone from the master file. If this fails, we'll 7423224092Sdougb * need to undo the configuration we've done already. 7424224092Sdougb */ 7425224092Sdougb result = dns_zone_loadnew(zone); 7426224092Sdougb if (result != ISC_R_SUCCESS) { 7427224092Sdougb dns_db_t *dbp = NULL; 7428224092Sdougb 7429224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7430224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7431224092Sdougb "addzone failed; reverting."); 7432224092Sdougb 7433224092Sdougb /* If the zone loaded partially, unload it */ 7434224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 7435224092Sdougb dns_db_detach(&dbp); 7436224092Sdougb dns_zone_unload(zone); 7437224092Sdougb } 7438224092Sdougb 7439224092Sdougb /* Remove the zone from the zone table */ 7440224092Sdougb dns_zt_unmount(view->zonetable, zone); 7441224092Sdougb goto cleanup; 7442224092Sdougb } 7443224092Sdougb 7444224092Sdougb /* Flag the zone as having been added at runtime */ 7445224092Sdougb dns_zone_setadded(zone, ISC_TRUE); 7446224092Sdougb 7447224092Sdougb /* Emit just the zone name from args */ 7448224092Sdougb CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL)); 7449224092Sdougb CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL)); 7450224092Sdougb CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); 7451224092Sdougb 7452224092Sdougb /* Classname, if not default */ 7453224092Sdougb if (classname != NULL && *classname != '\0') { 7454224092Sdougb CHECK(isc_stdio_write(classname, strlen(classname), 1, fp, 7455224092Sdougb NULL)); 7456224092Sdougb CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); 7457224092Sdougb } 7458224092Sdougb 7459224092Sdougb /* Find beginning of option block from args */ 7460224092Sdougb for (argp = args; *argp; argp++, arglen--) { 7461224092Sdougb if (*argp == '{') { /* Assume matching '}' */ 7462224092Sdougb /* Add that to our file */ 7463224092Sdougb CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL)); 7464224092Sdougb 7465224092Sdougb /* Make sure we end with a LF */ 7466224092Sdougb if (argp[arglen-1] != '\n') { 7467224092Sdougb CHECK(isc_stdio_write("\n", 1, 1, fp, NULL)); 7468224092Sdougb } 7469224092Sdougb break; 7470224092Sdougb } 7471224092Sdougb } 7472224092Sdougb 7473224092Sdougb CHECK(isc_stdio_close(fp)); 7474224092Sdougb fp = NULL; 7475224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7476224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7477224092Sdougb "zone %s added to view %s via addzone", 7478224092Sdougb zonename, viewname); 7479224092Sdougb 7480224092Sdougb result = ISC_R_SUCCESS; 7481224092Sdougb 7482224092Sdougb cleanup: 7483224092Sdougb if (fp != NULL) 7484224092Sdougb isc_stdio_close(fp); 7485224092Sdougb if (parser != NULL) { 7486224092Sdougb if (config != NULL) 7487224092Sdougb cfg_obj_destroy(parser, &config); 7488224092Sdougb cfg_parser_destroy(&parser); 7489224092Sdougb } 7490224092Sdougb if (zone != NULL) 7491224092Sdougb dns_zone_detach(&zone); 7492224092Sdougb if (view != NULL) 7493224092Sdougb dns_view_detach(&view); 7494224092Sdougb if (nbuf != NULL) 7495224092Sdougb isc_buffer_free(&nbuf); 7496224092Sdougb 7497224092Sdougb return (result); 7498224092Sdougb} 7499224092Sdougb 7500224092Sdougb/* 7501224092Sdougb * Act on a "delzone" command from the command channel. 7502224092Sdougb */ 7503224092Sdougbisc_result_t 7504224092Sdougbns_server_del_zone(ns_server_t *server, char *args) { 7505224092Sdougb isc_result_t result; 7506224092Sdougb dns_zone_t *zone = NULL; 7507224092Sdougb dns_view_t *view = NULL; 7508224092Sdougb dns_db_t *dbp = NULL; 7509224092Sdougb const char *filename = NULL; 7510224092Sdougb char *tmpname = NULL; 7511224092Sdougb char buf[1024]; 7512224092Sdougb const char *zonename = NULL; 7513224092Sdougb size_t znamelen = 0; 7514224092Sdougb FILE *ifp = NULL, *ofp = NULL; 7515224092Sdougb 7516224092Sdougb /* Parse parameters */ 7517224092Sdougb CHECK(zone_from_args(server, args, &zone, &zonename)); 7518224092Sdougb if (result != ISC_R_SUCCESS) 7519224092Sdougb return (result); 7520224092Sdougb if (zone == NULL) { 7521224092Sdougb result = ISC_R_UNEXPECTEDEND; 7522224092Sdougb goto cleanup; 7523224092Sdougb } 7524224092Sdougb 7525224092Sdougb /* 7526224092Sdougb * Was this zone originally added at runtime? 7527224092Sdougb * If not, we can't delete it now. 7528224092Sdougb */ 7529224092Sdougb if (!dns_zone_getadded(zone)) { 7530224092Sdougb result = ISC_R_NOPERM; 7531224092Sdougb goto cleanup; 7532224092Sdougb } 7533224092Sdougb 7534224092Sdougb if (zonename != NULL) 7535224092Sdougb znamelen = strlen(zonename); 7536224092Sdougb 7537224092Sdougb /* Dig out configuration for this zone */ 7538224092Sdougb view = dns_zone_getview(zone); 7539224092Sdougb filename = view->new_zone_file; 7540224092Sdougb if (filename == NULL) { 7541224092Sdougb /* No adding zones in this view */ 7542224092Sdougb result = ISC_R_FAILURE; 7543224092Sdougb goto cleanup; 7544224092Sdougb } 7545224092Sdougb 7546224092Sdougb /* Rewrite zone list */ 7547224092Sdougb result = isc_stdio_open(filename, "r", &ifp); 7548224092Sdougb if (ifp != NULL && result == ISC_R_SUCCESS) { 7549224092Sdougb char *found = NULL, *p = NULL; 7550224092Sdougb size_t n; 7551224092Sdougb 7552224092Sdougb /* Create a temporary file */ 7553224092Sdougb CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename, 7554224092Sdougb (long)getpid())); 7555224092Sdougb if (!(tmpname = isc_mem_strdup(server->mctx, buf))) { 7556224092Sdougb result = ISC_R_NOMEMORY; 7557224092Sdougb goto cleanup; 7558224092Sdougb } 7559224092Sdougb CHECK(isc_stdio_open(tmpname, "w", &ofp)); 7560224092Sdougb 7561224092Sdougb /* Look for the entry for that zone */ 7562224092Sdougb while (fgets(buf, 1024, ifp)) { 7563224092Sdougb /* A 'zone' line */ 7564224092Sdougb if (strncasecmp(buf, "zone", 4)) { 7565224092Sdougb fputs(buf, ofp); 7566224092Sdougb continue; 7567224092Sdougb } 7568224092Sdougb p = buf+4; 7569224092Sdougb 7570224092Sdougb /* Locate a name */ 7571224092Sdougb while (*p && 7572224092Sdougb ((*p == '"') || isspace((unsigned char)*p))) 7573224092Sdougb p++; 7574224092Sdougb 7575224092Sdougb /* Is that the zone we're looking for */ 7576224092Sdougb if (strncasecmp(p, zonename, znamelen)) { 7577224092Sdougb fputs(buf, ofp); 7578224092Sdougb continue; 7579224092Sdougb } 7580224092Sdougb 7581224092Sdougb /* And nothing else? */ 7582224092Sdougb p += znamelen; 7583224092Sdougb if (isspace((unsigned char)*p) || 7584224092Sdougb *p == '"' || *p == '{') { 7585224092Sdougb /* This must be the entry */ 7586224092Sdougb found = p; 7587224092Sdougb break; 7588224092Sdougb } 7589224092Sdougb 7590224092Sdougb /* Spit it out, keep looking */ 7591224092Sdougb fputs(buf, ofp); 7592224092Sdougb } 7593224092Sdougb 7594224092Sdougb /* Skip over an option block (matching # of braces) */ 7595224092Sdougb if (found) { 7596224092Sdougb int obrace = 0, cbrace = 0; 7597224092Sdougb for (;;) { 7598224092Sdougb while (*p) { 7599224092Sdougb if (*p == '{') obrace++; 7600224092Sdougb if (*p == '}') cbrace++; 7601224092Sdougb p++; 7602224092Sdougb } 7603224092Sdougb if (obrace && (obrace == cbrace)) 7604224092Sdougb break; 7605224092Sdougb if (!fgets(buf, 1024, ifp)) 7606224092Sdougb break; 7607224092Sdougb p = buf; 7608224092Sdougb } 7609224092Sdougb 7610224092Sdougb /* Just spool the remainder of the file out */ 7611224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 7612224092Sdougb while (n > 0U) { 7613224092Sdougb if (result == ISC_R_EOF) 7614224092Sdougb result = ISC_R_SUCCESS; 7615224092Sdougb CHECK(result); 7616224092Sdougb isc_stdio_write(buf, 1, n, ofp, NULL); 7617224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 7618224092Sdougb } 7619224092Sdougb 7620224092Sdougb /* Move temporary into place */ 7621224092Sdougb CHECK(isc_file_rename(tmpname, view->new_zone_file)); 7622224092Sdougb } else { 7623224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7624224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 7625224092Sdougb "deleted zone %s was missing from " 7626224092Sdougb "new zone file", zonename); 7627224092Sdougb goto cleanup; 7628224092Sdougb } 7629224092Sdougb } 7630224092Sdougb 7631224092Sdougb /* Stop answering for this zone */ 7632224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 7633224092Sdougb dns_db_detach(&dbp); 7634224092Sdougb dns_zone_unload(zone); 7635224092Sdougb } 7636224092Sdougb 7637224092Sdougb CHECK(dns_zt_unmount(view->zonetable, zone)); 7638224092Sdougb 7639224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7640224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7641224092Sdougb "zone %s removed via delzone", zonename); 7642224092Sdougb 7643224092Sdougb result = ISC_R_SUCCESS; 7644224092Sdougb 7645224092Sdougb cleanup: 7646224092Sdougb if (ifp != NULL) 7647224092Sdougb isc_stdio_close(ifp); 7648224092Sdougb if (ofp != NULL) { 7649224092Sdougb isc_stdio_close(ofp); 7650224092Sdougb isc_file_remove(tmpname); 7651224092Sdougb } 7652224092Sdougb if (tmpname != NULL) 7653224092Sdougb isc_mem_free(server->mctx, tmpname); 7654224092Sdougb if (zone != NULL) 7655224092Sdougb dns_zone_detach(&zone); 7656224092Sdougb 7657224092Sdougb return (result); 7658224092Sdougb} 7659224092Sdougb 7660224092Sdougbstatic void 7661225361Sdougbnewzone_cfgctx_destroy(void **cfgp) { 7662224092Sdougb struct cfg_context *cfg; 7663224092Sdougb 7664224092Sdougb REQUIRE(cfgp != NULL && *cfgp != NULL); 7665225361Sdougb 7666224092Sdougb cfg = *cfgp; 7667224092Sdougb 7668225361Sdougb if (cfg->actx != NULL) 7669225361Sdougb cfg_aclconfctx_detach(&cfg->actx); 7670225361Sdougb 7671224092Sdougb if (cfg->parser != NULL) { 7672224092Sdougb if (cfg->config != NULL) 7673224092Sdougb cfg_obj_destroy(cfg->parser, &cfg->config); 7674224092Sdougb cfg_parser_destroy(&cfg->parser); 7675224092Sdougb } 7676225361Sdougb if (cfg->nzparser != NULL) { 7677225361Sdougb if (cfg->nzconfig != NULL) 7678225361Sdougb cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig); 7679225361Sdougb cfg_parser_destroy(&cfg->nzparser); 7680225361Sdougb } 7681224092Sdougb 7682225361Sdougb isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg)); 7683224092Sdougb *cfgp = NULL; 7684224092Sdougb} 7685