server.c revision 182645
1135446Strhodes/* 2182645Sdougb * Copyright (C) 2004-2008 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 18182645Sdougb/* $Id: server.c,v 1.419.18.57.10.3 2008/07/23 12:04:32 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25135446Strhodes 26135446Strhodes#include <isc/app.h> 27135446Strhodes#include <isc/base64.h> 28135446Strhodes#include <isc/dir.h> 29135446Strhodes#include <isc/entropy.h> 30135446Strhodes#include <isc/file.h> 31135446Strhodes#include <isc/hash.h> 32135446Strhodes#include <isc/lex.h> 33135446Strhodes#include <isc/parseint.h> 34135446Strhodes#include <isc/print.h> 35135446Strhodes#include <isc/resource.h> 36135446Strhodes#include <isc/stdio.h> 37135446Strhodes#include <isc/string.h> 38135446Strhodes#include <isc/task.h> 39135446Strhodes#include <isc/timer.h> 40135446Strhodes#include <isc/util.h> 41135446Strhodes 42135446Strhodes#include <isccfg/namedconf.h> 43135446Strhodes 44135446Strhodes#include <bind9/check.h> 45135446Strhodes 46170222Sdougb#include <dns/acache.h> 47135446Strhodes#include <dns/adb.h> 48135446Strhodes#include <dns/cache.h> 49135446Strhodes#include <dns/db.h> 50135446Strhodes#include <dns/dispatch.h> 51170222Sdougb#ifdef DLZ 52170222Sdougb#include <dns/dlz.h> 53170222Sdougb#endif 54135446Strhodes#include <dns/forward.h> 55135446Strhodes#include <dns/journal.h> 56135446Strhodes#include <dns/keytable.h> 57170222Sdougb#include <dns/lib.h> 58135446Strhodes#include <dns/master.h> 59135446Strhodes#include <dns/masterdump.h> 60135446Strhodes#include <dns/order.h> 61135446Strhodes#include <dns/peer.h> 62135446Strhodes#include <dns/portlist.h> 63135446Strhodes#include <dns/rdataclass.h> 64135446Strhodes#include <dns/rdataset.h> 65135446Strhodes#include <dns/rdatastruct.h> 66135446Strhodes#include <dns/resolver.h> 67135446Strhodes#include <dns/rootns.h> 68135446Strhodes#include <dns/secalg.h> 69135446Strhodes#include <dns/stats.h> 70135446Strhodes#include <dns/tkey.h> 71135446Strhodes#include <dns/view.h> 72135446Strhodes#include <dns/zone.h> 73135446Strhodes#include <dns/zt.h> 74135446Strhodes 75135446Strhodes#include <dst/dst.h> 76135446Strhodes#include <dst/result.h> 77135446Strhodes 78135446Strhodes#include <named/client.h> 79135446Strhodes#include <named/config.h> 80135446Strhodes#include <named/control.h> 81135446Strhodes#include <named/interfacemgr.h> 82135446Strhodes#include <named/log.h> 83135446Strhodes#include <named/logconf.h> 84135446Strhodes#include <named/lwresd.h> 85135446Strhodes#include <named/main.h> 86135446Strhodes#include <named/os.h> 87135446Strhodes#include <named/server.h> 88135446Strhodes#include <named/tkeyconf.h> 89135446Strhodes#include <named/tsigconf.h> 90135446Strhodes#include <named/zoneconf.h> 91153816Sdougb#ifdef HAVE_LIBSCF 92153816Sdougb#include <named/ns_smf_globals.h> 93153816Sdougb#include <stdlib.h> 94153816Sdougb#endif 95135446Strhodes 96170222Sdougb/*% 97135446Strhodes * Check an operation for failure. Assumes that the function 98135446Strhodes * using it has a 'result' variable and a 'cleanup' label. 99135446Strhodes */ 100135446Strhodes#define CHECK(op) \ 101135446Strhodes do { result = (op); \ 102135446Strhodes if (result != ISC_R_SUCCESS) goto cleanup; \ 103135446Strhodes } while (0) 104135446Strhodes 105135446Strhodes#define CHECKM(op, msg) \ 106135446Strhodes do { result = (op); \ 107135446Strhodes if (result != ISC_R_SUCCESS) { \ 108135446Strhodes isc_log_write(ns_g_lctx, \ 109135446Strhodes NS_LOGCATEGORY_GENERAL, \ 110135446Strhodes NS_LOGMODULE_SERVER, \ 111135446Strhodes ISC_LOG_ERROR, \ 112135446Strhodes "%s: %s", msg, \ 113135446Strhodes isc_result_totext(result)); \ 114135446Strhodes goto cleanup; \ 115135446Strhodes } \ 116135446Strhodes } while (0) \ 117135446Strhodes 118135446Strhodes#define CHECKMF(op, msg, file) \ 119135446Strhodes do { result = (op); \ 120135446Strhodes if (result != ISC_R_SUCCESS) { \ 121135446Strhodes isc_log_write(ns_g_lctx, \ 122135446Strhodes NS_LOGCATEGORY_GENERAL, \ 123135446Strhodes NS_LOGMODULE_SERVER, \ 124135446Strhodes ISC_LOG_ERROR, \ 125135446Strhodes "%s '%s': %s", msg, file, \ 126135446Strhodes isc_result_totext(result)); \ 127135446Strhodes goto cleanup; \ 128135446Strhodes } \ 129135446Strhodes } while (0) \ 130135446Strhodes 131135446Strhodes#define CHECKFATAL(op, msg) \ 132135446Strhodes do { result = (op); \ 133135446Strhodes if (result != ISC_R_SUCCESS) \ 134135446Strhodes fatal(msg, result); \ 135135446Strhodes } while (0) \ 136135446Strhodes 137135446Strhodesstruct ns_dispatch { 138135446Strhodes isc_sockaddr_t addr; 139135446Strhodes unsigned int dispatchgen; 140135446Strhodes dns_dispatch_t *dispatch; 141135446Strhodes ISC_LINK(struct ns_dispatch) link; 142135446Strhodes}; 143135446Strhodes 144135446Strhodesstruct dumpcontext { 145135446Strhodes isc_mem_t *mctx; 146135446Strhodes isc_boolean_t dumpcache; 147135446Strhodes isc_boolean_t dumpzones; 148135446Strhodes FILE *fp; 149135446Strhodes ISC_LIST(struct viewlistentry) viewlist; 150135446Strhodes struct viewlistentry *view; 151135446Strhodes struct zonelistentry *zone; 152135446Strhodes dns_dumpctx_t *mdctx; 153135446Strhodes dns_db_t *db; 154135446Strhodes dns_db_t *cache; 155135446Strhodes isc_task_t *task; 156135446Strhodes dns_dbversion_t *version; 157135446Strhodes}; 158135446Strhodes 159135446Strhodesstruct viewlistentry { 160135446Strhodes dns_view_t *view; 161135446Strhodes ISC_LINK(struct viewlistentry) link; 162135446Strhodes ISC_LIST(struct zonelistentry) zonelist; 163135446Strhodes}; 164135446Strhodes 165135446Strhodesstruct zonelistentry { 166135446Strhodes dns_zone_t *zone; 167135446Strhodes ISC_LINK(struct zonelistentry) link; 168135446Strhodes}; 169135446Strhodes 170170222Sdougb/* 171170222Sdougb * These zones should not leak onto the Internet. 172170222Sdougb */ 173170222Sdougbstatic const struct { 174170222Sdougb const char *zone; 175170222Sdougb isc_boolean_t rfc1918; 176170222Sdougb} empty_zones[] = { 177170222Sdougb#ifdef notyet 178170222Sdougb /* RFC 1918 */ 179170222Sdougb { "10.IN-ADDR.ARPA", ISC_TRUE }, 180170222Sdougb { "16.172.IN-ADDR.ARPA", ISC_TRUE }, 181170222Sdougb { "17.172.IN-ADDR.ARPA", ISC_TRUE }, 182170222Sdougb { "18.172.IN-ADDR.ARPA", ISC_TRUE }, 183170222Sdougb { "19.172.IN-ADDR.ARPA", ISC_TRUE }, 184170222Sdougb { "20.172.IN-ADDR.ARPA", ISC_TRUE }, 185170222Sdougb { "21.172.IN-ADDR.ARPA", ISC_TRUE }, 186170222Sdougb { "22.172.IN-ADDR.ARPA", ISC_TRUE }, 187170222Sdougb { "23.172.IN-ADDR.ARPA", ISC_TRUE }, 188170222Sdougb { "24.172.IN-ADDR.ARPA", ISC_TRUE }, 189170222Sdougb { "25.172.IN-ADDR.ARPA", ISC_TRUE }, 190170222Sdougb { "26.172.IN-ADDR.ARPA", ISC_TRUE }, 191170222Sdougb { "27.172.IN-ADDR.ARPA", ISC_TRUE }, 192170222Sdougb { "28.172.IN-ADDR.ARPA", ISC_TRUE }, 193170222Sdougb { "29.172.IN-ADDR.ARPA", ISC_TRUE }, 194170222Sdougb { "30.172.IN-ADDR.ARPA", ISC_TRUE }, 195170222Sdougb { "31.172.IN-ADDR.ARPA", ISC_TRUE }, 196170222Sdougb { "168.192.IN-ADDR.ARPA", ISC_TRUE }, 197170222Sdougb#endif 198170222Sdougb 199170222Sdougb /* RFC 3330 */ 200170222Sdougb { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */ 201170222Sdougb { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */ 202170222Sdougb { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */ 203170222Sdougb { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */ 204170222Sdougb 205170222Sdougb /* Local IPv6 Unicast Addresses */ 206170222Sdougb { "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 }, 207170222Sdougb { "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 }, 208170222Sdougb /* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */ 209170222Sdougb { "D.F.IP6.ARPA", ISC_FALSE }, 210170222Sdougb { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 211170222Sdougb { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 212170222Sdougb { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 213170222Sdougb { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 214170222Sdougb 215170222Sdougb { NULL, ISC_FALSE } 216170222Sdougb}; 217170222Sdougb 218135446Strhodesstatic void 219135446Strhodesfatal(const char *msg, isc_result_t result); 220135446Strhodes 221135446Strhodesstatic void 222135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event); 223135446Strhodes 224135446Strhodesstatic isc_result_t 225165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 226170222Sdougb cfg_aclconfctx_t *actx, 227135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target); 228135446Strhodesstatic isc_result_t 229165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 230170222Sdougb cfg_aclconfctx_t *actx, 231135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target); 232135446Strhodes 233135446Strhodesstatic isc_result_t 234165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 235165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); 236135446Strhodes 237135446Strhodesstatic isc_result_t 238165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 239165071Sdougb const cfg_obj_t *alternates); 240135446Strhodes 241135446Strhodesstatic isc_result_t 242165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 243165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 244170222Sdougb cfg_aclconfctx_t *aclconf); 245135446Strhodes 246135446Strhodesstatic void 247135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all); 248135446Strhodes 249170222Sdougb/*% 250135446Strhodes * Configure a single view ACL at '*aclp'. Get its configuration by 251135446Strhodes * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' 252135446Strhodes * (for a global default). 253135446Strhodes */ 254135446Strhodesstatic isc_result_t 255165071Sdougbconfigure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, 256170222Sdougb const char *aclname, cfg_aclconfctx_t *actx, 257135446Strhodes isc_mem_t *mctx, dns_acl_t **aclp) 258135446Strhodes{ 259135446Strhodes isc_result_t result; 260165071Sdougb const cfg_obj_t *maps[3]; 261165071Sdougb const cfg_obj_t *aclobj = NULL; 262135446Strhodes int i = 0; 263135446Strhodes 264135446Strhodes if (*aclp != NULL) 265135446Strhodes dns_acl_detach(aclp); 266135446Strhodes if (vconfig != NULL) 267135446Strhodes maps[i++] = cfg_tuple_get(vconfig, "options"); 268135446Strhodes if (config != NULL) { 269165071Sdougb const cfg_obj_t *options = NULL; 270135446Strhodes (void)cfg_map_get(config, "options", &options); 271135446Strhodes if (options != NULL) 272135446Strhodes maps[i++] = options; 273135446Strhodes } 274135446Strhodes maps[i] = NULL; 275135446Strhodes 276165071Sdougb (void)ns_config_get(maps, aclname, &aclobj); 277135446Strhodes if (aclobj == NULL) 278135446Strhodes /* 279135446Strhodes * No value available. *aclp == NULL. 280135446Strhodes */ 281135446Strhodes return (ISC_R_SUCCESS); 282135446Strhodes 283170222Sdougb result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 284170222Sdougb actx, mctx, aclp); 285135446Strhodes 286135446Strhodes return (result); 287135446Strhodes} 288135446Strhodes 289135446Strhodesstatic isc_result_t 290165071Sdougbconfigure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, 291135446Strhodes dns_keytable_t *keytable, isc_mem_t *mctx) 292135446Strhodes{ 293135446Strhodes dns_rdataclass_t viewclass; 294135446Strhodes dns_rdata_dnskey_t keystruct; 295135446Strhodes isc_uint32_t flags, proto, alg; 296165071Sdougb const char *keystr, *keynamestr; 297135446Strhodes unsigned char keydata[4096]; 298135446Strhodes isc_buffer_t keydatabuf; 299135446Strhodes unsigned char rrdata[4096]; 300135446Strhodes isc_buffer_t rrdatabuf; 301135446Strhodes isc_region_t r; 302135446Strhodes dns_fixedname_t fkeyname; 303135446Strhodes dns_name_t *keyname; 304135446Strhodes isc_buffer_t namebuf; 305135446Strhodes isc_result_t result; 306135446Strhodes dst_key_t *dstkey = NULL; 307135446Strhodes 308135446Strhodes flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 309135446Strhodes proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); 310135446Strhodes alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); 311135446Strhodes keyname = dns_fixedname_name(&fkeyname); 312135446Strhodes keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 313135446Strhodes 314135446Strhodes if (vconfig == NULL) 315135446Strhodes viewclass = dns_rdataclass_in; 316135446Strhodes else { 317165071Sdougb const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); 318135446Strhodes CHECK(ns_config_getclass(classobj, dns_rdataclass_in, 319135446Strhodes &viewclass)); 320135446Strhodes } 321135446Strhodes keystruct.common.rdclass = viewclass; 322135446Strhodes keystruct.common.rdtype = dns_rdatatype_dnskey; 323135446Strhodes /* 324135446Strhodes * The key data in keystruct is not dynamically allocated. 325135446Strhodes */ 326135446Strhodes keystruct.mctx = NULL; 327135446Strhodes 328135446Strhodes ISC_LINK_INIT(&keystruct.common, link); 329135446Strhodes 330135446Strhodes if (flags > 0xffff) 331135446Strhodes CHECKM(ISC_R_RANGE, "key flags"); 332135446Strhodes if (proto > 0xff) 333135446Strhodes CHECKM(ISC_R_RANGE, "key protocol"); 334135446Strhodes if (alg > 0xff) 335135446Strhodes CHECKM(ISC_R_RANGE, "key algorithm"); 336135446Strhodes keystruct.flags = (isc_uint16_t)flags; 337135446Strhodes keystruct.protocol = (isc_uint8_t)proto; 338135446Strhodes keystruct.algorithm = (isc_uint8_t)alg; 339135446Strhodes 340135446Strhodes isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); 341135446Strhodes isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 342135446Strhodes 343135446Strhodes keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 344135446Strhodes CHECK(isc_base64_decodestring(keystr, &keydatabuf)); 345135446Strhodes isc_buffer_usedregion(&keydatabuf, &r); 346135446Strhodes keystruct.datalen = r.length; 347135446Strhodes keystruct.data = r.base; 348135446Strhodes 349170222Sdougb if ((keystruct.algorithm == DST_ALG_RSASHA1 || 350170222Sdougb keystruct.algorithm == DST_ALG_RSAMD5) && 351170222Sdougb r.length > 1 && r.base[0] == 1 && r.base[1] == 3) 352170222Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 353170222Sdougb "trusted key '%s' has a weak exponent", 354170222Sdougb keynamestr); 355170222Sdougb 356135446Strhodes CHECK(dns_rdata_fromstruct(NULL, 357135446Strhodes keystruct.common.rdclass, 358135446Strhodes keystruct.common.rdtype, 359135446Strhodes &keystruct, &rrdatabuf)); 360135446Strhodes dns_fixedname_init(&fkeyname); 361135446Strhodes isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); 362135446Strhodes isc_buffer_add(&namebuf, strlen(keynamestr)); 363135446Strhodes CHECK(dns_name_fromtext(keyname, &namebuf, 364135446Strhodes dns_rootname, ISC_FALSE, 365135446Strhodes NULL)); 366135446Strhodes CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, 367135446Strhodes mctx, &dstkey)); 368135446Strhodes 369135446Strhodes CHECK(dns_keytable_add(keytable, &dstkey)); 370135446Strhodes INSIST(dstkey == NULL); 371135446Strhodes return (ISC_R_SUCCESS); 372135446Strhodes 373135446Strhodes cleanup: 374135446Strhodes if (result == DST_R_NOCRYPTO) { 375135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 376135446Strhodes "ignoring trusted key for '%s': no crypto support", 377135446Strhodes keynamestr); 378135446Strhodes result = ISC_R_SUCCESS; 379135446Strhodes } else { 380135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 381135446Strhodes "configuring trusted key for '%s': %s", 382135446Strhodes keynamestr, isc_result_totext(result)); 383135446Strhodes result = ISC_R_FAILURE; 384135446Strhodes } 385135446Strhodes 386135446Strhodes if (dstkey != NULL) 387135446Strhodes dst_key_free(&dstkey); 388135446Strhodes 389135446Strhodes return (result); 390135446Strhodes} 391135446Strhodes 392170222Sdougb/*% 393135446Strhodes * Configure DNSSEC keys for a view. Currently used only for 394135446Strhodes * the security roots. 395135446Strhodes * 396135446Strhodes * The per-view configuration values and the server-global defaults are read 397135446Strhodes * from 'vconfig' and 'config'. The variable to be configured is '*target'. 398135446Strhodes */ 399135446Strhodesstatic isc_result_t 400165071Sdougbconfigure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, 401135446Strhodes isc_mem_t *mctx, dns_keytable_t **target) 402135446Strhodes{ 403135446Strhodes isc_result_t result; 404165071Sdougb const cfg_obj_t *keys = NULL; 405165071Sdougb const cfg_obj_t *voptions = NULL; 406165071Sdougb const cfg_listelt_t *element, *element2; 407165071Sdougb const cfg_obj_t *keylist; 408165071Sdougb const cfg_obj_t *key; 409135446Strhodes dns_keytable_t *keytable = NULL; 410135446Strhodes 411135446Strhodes CHECK(dns_keytable_create(mctx, &keytable)); 412135446Strhodes 413135446Strhodes if (vconfig != NULL) 414135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 415135446Strhodes 416135446Strhodes keys = NULL; 417135446Strhodes if (voptions != NULL) 418135446Strhodes (void)cfg_map_get(voptions, "trusted-keys", &keys); 419135446Strhodes if (keys == NULL) 420135446Strhodes (void)cfg_map_get(config, "trusted-keys", &keys); 421135446Strhodes 422135446Strhodes for (element = cfg_list_first(keys); 423135446Strhodes element != NULL; 424135446Strhodes element = cfg_list_next(element)) 425135446Strhodes { 426135446Strhodes keylist = cfg_listelt_value(element); 427135446Strhodes for (element2 = cfg_list_first(keylist); 428135446Strhodes element2 != NULL; 429135446Strhodes element2 = cfg_list_next(element2)) 430135446Strhodes { 431135446Strhodes key = cfg_listelt_value(element2); 432135446Strhodes CHECK(configure_view_dnsseckey(vconfig, key, 433135446Strhodes keytable, mctx)); 434135446Strhodes } 435135446Strhodes } 436135446Strhodes 437135446Strhodes dns_keytable_detach(target); 438135446Strhodes *target = keytable; /* Transfer ownership. */ 439135446Strhodes keytable = NULL; 440135446Strhodes result = ISC_R_SUCCESS; 441135446Strhodes 442135446Strhodes cleanup: 443135446Strhodes return (result); 444135446Strhodes} 445135446Strhodes 446135446Strhodesstatic isc_result_t 447165071Sdougbmustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) 448135446Strhodes{ 449165071Sdougb const cfg_listelt_t *element; 450165071Sdougb const cfg_obj_t *obj; 451135446Strhodes const char *str; 452135446Strhodes dns_fixedname_t fixed; 453135446Strhodes dns_name_t *name; 454135446Strhodes isc_boolean_t value; 455135446Strhodes isc_result_t result; 456135446Strhodes isc_buffer_t b; 457135446Strhodes 458135446Strhodes dns_fixedname_init(&fixed); 459135446Strhodes name = dns_fixedname_name(&fixed); 460135446Strhodes for (element = cfg_list_first(mbs); 461135446Strhodes element != NULL; 462135446Strhodes element = cfg_list_next(element)) 463135446Strhodes { 464135446Strhodes obj = cfg_listelt_value(element); 465135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 466135446Strhodes isc_buffer_init(&b, str, strlen(str)); 467135446Strhodes isc_buffer_add(&b, strlen(str)); 468135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 469135446Strhodes ISC_FALSE, NULL)); 470135446Strhodes value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); 471135446Strhodes CHECK(dns_resolver_setmustbesecure(resolver, name, value)); 472135446Strhodes } 473135446Strhodes 474135446Strhodes result = ISC_R_SUCCESS; 475135446Strhodes 476135446Strhodes cleanup: 477135446Strhodes return (result); 478135446Strhodes} 479135446Strhodes 480170222Sdougb/*% 481135446Strhodes * Get a dispatch appropriate for the resolver of a given view. 482135446Strhodes */ 483135446Strhodesstatic isc_result_t 484165071Sdougbget_view_querysource_dispatch(const cfg_obj_t **maps, 485135446Strhodes int af, dns_dispatch_t **dispatchp) 486135446Strhodes{ 487135446Strhodes isc_result_t result; 488135446Strhodes dns_dispatch_t *disp; 489135446Strhodes isc_sockaddr_t sa; 490135446Strhodes unsigned int attrs, attrmask; 491165071Sdougb const cfg_obj_t *obj = NULL; 492135446Strhodes 493135446Strhodes /* 494135446Strhodes * Make compiler happy. 495135446Strhodes */ 496135446Strhodes result = ISC_R_FAILURE; 497135446Strhodes 498135446Strhodes switch (af) { 499135446Strhodes case AF_INET: 500135446Strhodes result = ns_config_get(maps, "query-source", &obj); 501135446Strhodes INSIST(result == ISC_R_SUCCESS); 502135446Strhodes break; 503135446Strhodes case AF_INET6: 504135446Strhodes result = ns_config_get(maps, "query-source-v6", &obj); 505135446Strhodes INSIST(result == ISC_R_SUCCESS); 506135446Strhodes break; 507135446Strhodes default: 508135446Strhodes INSIST(0); 509135446Strhodes } 510135446Strhodes 511135446Strhodes sa = *(cfg_obj_assockaddr(obj)); 512135446Strhodes INSIST(isc_sockaddr_pf(&sa) == af); 513135446Strhodes 514135446Strhodes /* 515135446Strhodes * If we don't support this address family, we're done! 516135446Strhodes */ 517135446Strhodes switch (af) { 518135446Strhodes case AF_INET: 519135446Strhodes result = isc_net_probeipv4(); 520135446Strhodes break; 521135446Strhodes case AF_INET6: 522135446Strhodes result = isc_net_probeipv6(); 523135446Strhodes break; 524135446Strhodes default: 525135446Strhodes INSIST(0); 526135446Strhodes } 527135446Strhodes if (result != ISC_R_SUCCESS) 528135446Strhodes return (ISC_R_SUCCESS); 529135446Strhodes 530135446Strhodes /* 531135446Strhodes * Try to find a dispatcher that we can share. 532135446Strhodes */ 533135446Strhodes attrs = 0; 534135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 535135446Strhodes switch (af) { 536135446Strhodes case AF_INET: 537135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 538135446Strhodes break; 539135446Strhodes case AF_INET6: 540135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 541135446Strhodes break; 542135446Strhodes } 543180477Sdougb 544180477Sdougb if (isc_sockaddr_getport(&sa) != 0) { 545180477Sdougb INSIST(obj != NULL); 546180477Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO, 547180477Sdougb "using specific query-source port suppresses port " 548180477Sdougb "randomization and can be insecure."); 549180477Sdougb } 550180477Sdougb 551135446Strhodes attrmask = 0; 552135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 553135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 554135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 555135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 556135446Strhodes 557135446Strhodes disp = NULL; 558135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 559135446Strhodes ns_g_taskmgr, &sa, 4096, 560180477Sdougb 1024, 32768, 16411, 16433, 561135446Strhodes attrs, attrmask, &disp); 562135446Strhodes if (result != ISC_R_SUCCESS) { 563135446Strhodes isc_sockaddr_t any; 564135446Strhodes char buf[ISC_SOCKADDR_FORMATSIZE]; 565135446Strhodes 566135446Strhodes switch (af) { 567135446Strhodes case AF_INET: 568135446Strhodes isc_sockaddr_any(&any); 569135446Strhodes break; 570135446Strhodes case AF_INET6: 571135446Strhodes isc_sockaddr_any6(&any); 572135446Strhodes break; 573135446Strhodes } 574135446Strhodes if (isc_sockaddr_equal(&sa, &any)) 575135446Strhodes return (ISC_R_SUCCESS); 576135446Strhodes isc_sockaddr_format(&sa, buf, sizeof(buf)); 577135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 578135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 579135446Strhodes "could not get query source dispatcher (%s)", 580135446Strhodes buf); 581135446Strhodes return (result); 582135446Strhodes } 583135446Strhodes 584135446Strhodes *dispatchp = disp; 585135446Strhodes 586135446Strhodes return (ISC_R_SUCCESS); 587135446Strhodes} 588135446Strhodes 589135446Strhodesstatic isc_result_t 590165071Sdougbconfigure_order(dns_order_t *order, const cfg_obj_t *ent) { 591135446Strhodes dns_rdataclass_t rdclass; 592135446Strhodes dns_rdatatype_t rdtype; 593165071Sdougb const cfg_obj_t *obj; 594135446Strhodes dns_fixedname_t fixed; 595135446Strhodes unsigned int mode = 0; 596135446Strhodes const char *str; 597135446Strhodes isc_buffer_t b; 598135446Strhodes isc_result_t result; 599143731Sdougb isc_boolean_t addroot; 600135446Strhodes 601135446Strhodes result = ns_config_getclass(cfg_tuple_get(ent, "class"), 602135446Strhodes dns_rdataclass_any, &rdclass); 603135446Strhodes if (result != ISC_R_SUCCESS) 604135446Strhodes return (result); 605135446Strhodes 606135446Strhodes result = ns_config_gettype(cfg_tuple_get(ent, "type"), 607135446Strhodes dns_rdatatype_any, &rdtype); 608135446Strhodes if (result != ISC_R_SUCCESS) 609135446Strhodes return (result); 610135446Strhodes 611135446Strhodes obj = cfg_tuple_get(ent, "name"); 612135446Strhodes if (cfg_obj_isstring(obj)) 613135446Strhodes str = cfg_obj_asstring(obj); 614135446Strhodes else 615135446Strhodes str = "*"; 616143731Sdougb addroot = ISC_TF(strcmp(str, "*") == 0); 617135446Strhodes isc_buffer_init(&b, str, strlen(str)); 618135446Strhodes isc_buffer_add(&b, strlen(str)); 619135446Strhodes dns_fixedname_init(&fixed); 620135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 621143731Sdougb dns_rootname, ISC_FALSE, NULL); 622135446Strhodes if (result != ISC_R_SUCCESS) 623135446Strhodes return (result); 624135446Strhodes 625135446Strhodes obj = cfg_tuple_get(ent, "ordering"); 626135446Strhodes INSIST(cfg_obj_isstring(obj)); 627135446Strhodes str = cfg_obj_asstring(obj); 628135446Strhodes if (!strcasecmp(str, "fixed")) 629135446Strhodes mode = DNS_RDATASETATTR_FIXEDORDER; 630135446Strhodes else if (!strcasecmp(str, "random")) 631135446Strhodes mode = DNS_RDATASETATTR_RANDOMIZE; 632135446Strhodes else if (!strcasecmp(str, "cyclic")) 633135446Strhodes mode = 0; 634135446Strhodes else 635135446Strhodes INSIST(0); 636135446Strhodes 637143731Sdougb /* 638143731Sdougb * "*" should match everything including the root (BIND 8 compat). 639143731Sdougb * As dns_name_matcheswildcard(".", "*.") returns FALSE add a 640165071Sdougb * explicit entry for "." when the name is "*". 641143731Sdougb */ 642143731Sdougb if (addroot) { 643143731Sdougb result = dns_order_add(order, dns_rootname, 644143731Sdougb rdtype, rdclass, mode); 645143731Sdougb if (result != ISC_R_SUCCESS) 646143731Sdougb return (result); 647143731Sdougb } 648143731Sdougb 649135446Strhodes return (dns_order_add(order, dns_fixedname_name(&fixed), 650135446Strhodes rdtype, rdclass, mode)); 651135446Strhodes} 652135446Strhodes 653135446Strhodesstatic isc_result_t 654165071Sdougbconfigure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { 655135446Strhodes isc_netaddr_t na; 656135446Strhodes dns_peer_t *peer; 657165071Sdougb const cfg_obj_t *obj; 658165071Sdougb const char *str; 659135446Strhodes isc_result_t result; 660170222Sdougb unsigned int prefixlen; 661135446Strhodes 662170222Sdougb cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); 663135446Strhodes 664135446Strhodes peer = NULL; 665135446Strhodes result = dns_peer_new(mctx, &na, &peer); 666135446Strhodes if (result != ISC_R_SUCCESS) 667135446Strhodes return (result); 668135446Strhodes 669135446Strhodes obj = NULL; 670135446Strhodes (void)cfg_map_get(cpeer, "bogus", &obj); 671135446Strhodes if (obj != NULL) 672135446Strhodes CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); 673135446Strhodes 674135446Strhodes obj = NULL; 675135446Strhodes (void)cfg_map_get(cpeer, "provide-ixfr", &obj); 676135446Strhodes if (obj != NULL) 677135446Strhodes CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); 678135446Strhodes 679135446Strhodes obj = NULL; 680135446Strhodes (void)cfg_map_get(cpeer, "request-ixfr", &obj); 681135446Strhodes if (obj != NULL) 682135446Strhodes CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); 683135446Strhodes 684135446Strhodes obj = NULL; 685135446Strhodes (void)cfg_map_get(cpeer, "edns", &obj); 686135446Strhodes if (obj != NULL) 687135446Strhodes CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); 688135446Strhodes 689135446Strhodes obj = NULL; 690170222Sdougb (void)cfg_map_get(cpeer, "edns-udp-size", &obj); 691170222Sdougb if (obj != NULL) { 692170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 693170222Sdougb if (udpsize < 512) 694170222Sdougb udpsize = 512; 695170222Sdougb if (udpsize > 4096) 696170222Sdougb udpsize = 4096; 697170222Sdougb CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); 698170222Sdougb } 699170222Sdougb 700170222Sdougb obj = NULL; 701170222Sdougb (void)cfg_map_get(cpeer, "max-udp-size", &obj); 702170222Sdougb if (obj != NULL) { 703170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 704170222Sdougb if (udpsize < 512) 705170222Sdougb udpsize = 512; 706170222Sdougb if (udpsize > 4096) 707170222Sdougb udpsize = 4096; 708170222Sdougb CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); 709170222Sdougb } 710170222Sdougb 711170222Sdougb obj = NULL; 712135446Strhodes (void)cfg_map_get(cpeer, "transfers", &obj); 713135446Strhodes if (obj != NULL) 714135446Strhodes CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); 715135446Strhodes 716135446Strhodes obj = NULL; 717135446Strhodes (void)cfg_map_get(cpeer, "transfer-format", &obj); 718135446Strhodes if (obj != NULL) { 719135446Strhodes str = cfg_obj_asstring(obj); 720135446Strhodes if (strcasecmp(str, "many-answers") == 0) 721135446Strhodes CHECK(dns_peer_settransferformat(peer, 722135446Strhodes dns_many_answers)); 723135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 724135446Strhodes CHECK(dns_peer_settransferformat(peer, 725135446Strhodes dns_one_answer)); 726135446Strhodes else 727135446Strhodes INSIST(0); 728135446Strhodes } 729135446Strhodes 730135446Strhodes obj = NULL; 731135446Strhodes (void)cfg_map_get(cpeer, "keys", &obj); 732135446Strhodes if (obj != NULL) { 733135446Strhodes result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); 734135446Strhodes if (result != ISC_R_SUCCESS) 735135446Strhodes goto cleanup; 736135446Strhodes } 737135446Strhodes 738135446Strhodes obj = NULL; 739170222Sdougb if (na.family == AF_INET) 740135446Strhodes (void)cfg_map_get(cpeer, "transfer-source", &obj); 741135446Strhodes else 742135446Strhodes (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); 743135446Strhodes if (obj != NULL) { 744135446Strhodes result = dns_peer_settransfersource(peer, 745135446Strhodes cfg_obj_assockaddr(obj)); 746135446Strhodes if (result != ISC_R_SUCCESS) 747135446Strhodes goto cleanup; 748170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 749135446Strhodes } 750170222Sdougb 751170222Sdougb obj = NULL; 752170222Sdougb if (na.family == AF_INET) 753170222Sdougb (void)cfg_map_get(cpeer, "notify-source", &obj); 754170222Sdougb else 755170222Sdougb (void)cfg_map_get(cpeer, "notify-source-v6", &obj); 756170222Sdougb if (obj != NULL) { 757170222Sdougb result = dns_peer_setnotifysource(peer, 758170222Sdougb cfg_obj_assockaddr(obj)); 759170222Sdougb if (result != ISC_R_SUCCESS) 760170222Sdougb goto cleanup; 761170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 762170222Sdougb } 763170222Sdougb 764170222Sdougb obj = NULL; 765170222Sdougb if (na.family == AF_INET) 766170222Sdougb (void)cfg_map_get(cpeer, "query-source", &obj); 767170222Sdougb else 768170222Sdougb (void)cfg_map_get(cpeer, "query-source-v6", &obj); 769170222Sdougb if (obj != NULL) { 770170222Sdougb result = dns_peer_setquerysource(peer, 771170222Sdougb cfg_obj_assockaddr(obj)); 772170222Sdougb if (result != ISC_R_SUCCESS) 773170222Sdougb goto cleanup; 774170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 775170222Sdougb } 776170222Sdougb 777135446Strhodes *peerp = peer; 778135446Strhodes return (ISC_R_SUCCESS); 779135446Strhodes 780135446Strhodes cleanup: 781135446Strhodes dns_peer_detach(&peer); 782135446Strhodes return (result); 783135446Strhodes} 784135446Strhodes 785135446Strhodesstatic isc_result_t 786165071Sdougbdisable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { 787135446Strhodes isc_result_t result; 788165071Sdougb const cfg_obj_t *algorithms; 789165071Sdougb const cfg_listelt_t *element; 790135446Strhodes const char *str; 791135446Strhodes dns_fixedname_t fixed; 792135446Strhodes dns_name_t *name; 793135446Strhodes isc_buffer_t b; 794135446Strhodes 795135446Strhodes dns_fixedname_init(&fixed); 796135446Strhodes name = dns_fixedname_name(&fixed); 797135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); 798135446Strhodes isc_buffer_init(&b, str, strlen(str)); 799135446Strhodes isc_buffer_add(&b, strlen(str)); 800135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL)); 801135446Strhodes 802135446Strhodes algorithms = cfg_tuple_get(disabled, "algorithms"); 803135446Strhodes for (element = cfg_list_first(algorithms); 804135446Strhodes element != NULL; 805135446Strhodes element = cfg_list_next(element)) 806135446Strhodes { 807135446Strhodes isc_textregion_t r; 808135446Strhodes dns_secalg_t alg; 809135446Strhodes 810165071Sdougb DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 811135446Strhodes r.length = strlen(r.base); 812135446Strhodes 813135446Strhodes result = dns_secalg_fromtext(&alg, &r); 814135446Strhodes if (result != ISC_R_SUCCESS) { 815135446Strhodes isc_uint8_t ui; 816135446Strhodes result = isc_parse_uint8(&ui, r.base, 10); 817135446Strhodes alg = ui; 818135446Strhodes } 819135446Strhodes if (result != ISC_R_SUCCESS) { 820135446Strhodes cfg_obj_log(cfg_listelt_value(element), 821135446Strhodes ns_g_lctx, ISC_LOG_ERROR, 822135446Strhodes "invalid algorithm"); 823135446Strhodes CHECK(result); 824135446Strhodes } 825135446Strhodes CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); 826135446Strhodes } 827135446Strhodes cleanup: 828135446Strhodes return (result); 829135446Strhodes} 830135446Strhodes 831170222Sdougbstatic isc_boolean_t 832170222Sdougbon_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { 833170222Sdougb const cfg_listelt_t *element; 834170222Sdougb dns_fixedname_t fixed; 835170222Sdougb dns_name_t *name; 836170222Sdougb isc_result_t result; 837170222Sdougb const cfg_obj_t *value; 838170222Sdougb const char *str; 839170222Sdougb isc_buffer_t b; 840170222Sdougb 841170222Sdougb dns_fixedname_init(&fixed); 842170222Sdougb name = dns_fixedname_name(&fixed); 843170222Sdougb 844170222Sdougb for (element = cfg_list_first(disablelist); 845170222Sdougb element != NULL; 846170222Sdougb element = cfg_list_next(element)) 847170222Sdougb { 848170222Sdougb value = cfg_listelt_value(element); 849170222Sdougb str = cfg_obj_asstring(value); 850170222Sdougb isc_buffer_init(&b, str, strlen(str)); 851170222Sdougb isc_buffer_add(&b, strlen(str)); 852170222Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 853170222Sdougb ISC_TRUE, NULL); 854170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 855170222Sdougb if (dns_name_equal(name, zonename)) 856170222Sdougb return (ISC_TRUE); 857170222Sdougb } 858170222Sdougb return (ISC_FALSE); 859170222Sdougb} 860170222Sdougb 861170222Sdougbstatic void 862170222Sdougbcheck_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, 863170222Sdougb isc_mem_t *mctx) 864170222Sdougb{ 865170222Sdougb char **argv = NULL; 866170222Sdougb unsigned int i; 867170222Sdougb isc_result_t result; 868170222Sdougb 869170222Sdougb result = dns_zone_getdbtype(*zonep, &argv, mctx); 870170222Sdougb if (result != ISC_R_SUCCESS) { 871170222Sdougb dns_zone_detach(zonep); 872170222Sdougb return; 873170222Sdougb } 874170222Sdougb 875170222Sdougb /* 876170222Sdougb * Check that all the arguments match. 877170222Sdougb */ 878170222Sdougb for (i = 0; i < dbtypec; i++) 879170222Sdougb if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { 880170222Sdougb dns_zone_detach(zonep); 881170222Sdougb break; 882170222Sdougb } 883170222Sdougb 884170222Sdougb /* 885170222Sdougb * Check that there are not extra arguments. 886170222Sdougb */ 887170222Sdougb if (i == dbtypec && argv[i] != NULL) 888170222Sdougb dns_zone_detach(zonep); 889170222Sdougb isc_mem_free(mctx, argv); 890170222Sdougb} 891170222Sdougb 892170222Sdougb 893135446Strhodes/* 894135446Strhodes * Configure 'view' according to 'vconfig', taking defaults from 'config' 895135446Strhodes * where values are missing in 'vconfig'. 896135446Strhodes * 897135446Strhodes * When configuring the default view, 'vconfig' will be NULL and the 898135446Strhodes * global defaults in 'config' used exclusively. 899135446Strhodes */ 900135446Strhodesstatic isc_result_t 901165071Sdougbconfigure_view(dns_view_t *view, const cfg_obj_t *config, 902170222Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, 903170222Sdougb cfg_aclconfctx_t *actx, isc_boolean_t need_hints) 904135446Strhodes{ 905165071Sdougb const cfg_obj_t *maps[4]; 906165071Sdougb const cfg_obj_t *cfgmaps[3]; 907165071Sdougb const cfg_obj_t *options = NULL; 908165071Sdougb const cfg_obj_t *voptions = NULL; 909165071Sdougb const cfg_obj_t *forwardtype; 910165071Sdougb const cfg_obj_t *forwarders; 911165071Sdougb const cfg_obj_t *alternates; 912165071Sdougb const cfg_obj_t *zonelist; 913170222Sdougb#ifdef DLZ 914170222Sdougb const cfg_obj_t *dlz; 915170222Sdougb unsigned int dlzargc; 916170222Sdougb char **dlzargv; 917170222Sdougb#endif 918165071Sdougb const cfg_obj_t *disabled; 919165071Sdougb const cfg_obj_t *obj; 920165071Sdougb const cfg_listelt_t *element; 921135446Strhodes in_port_t port; 922135446Strhodes dns_cache_t *cache = NULL; 923135446Strhodes isc_result_t result; 924135446Strhodes isc_uint32_t max_adb_size; 925135446Strhodes isc_uint32_t max_cache_size; 926170222Sdougb isc_uint32_t max_acache_size; 927135446Strhodes isc_uint32_t lame_ttl; 928135446Strhodes dns_tsig_keyring_t *ring; 929135446Strhodes dns_view_t *pview = NULL; /* Production view */ 930135446Strhodes isc_mem_t *cmctx; 931135446Strhodes dns_dispatch_t *dispatch4 = NULL; 932135446Strhodes dns_dispatch_t *dispatch6 = NULL; 933135446Strhodes isc_boolean_t reused_cache = ISC_FALSE; 934135446Strhodes int i; 935135446Strhodes const char *str; 936135446Strhodes dns_order_t *order = NULL; 937135446Strhodes isc_uint32_t udpsize; 938135446Strhodes unsigned int check = 0; 939170222Sdougb dns_zone_t *zone = NULL; 940170222Sdougb isc_uint32_t max_clients_per_query; 941170222Sdougb const char *sep = ": view "; 942170222Sdougb const char *viewname = view->name; 943170222Sdougb const char *forview = " for view "; 944170222Sdougb isc_boolean_t rfc1918; 945170222Sdougb isc_boolean_t empty_zones_enable; 946170222Sdougb const cfg_obj_t *disablelist = NULL; 947135446Strhodes 948135446Strhodes REQUIRE(DNS_VIEW_VALID(view)); 949135446Strhodes 950135446Strhodes cmctx = NULL; 951135446Strhodes 952135446Strhodes if (config != NULL) 953135446Strhodes (void)cfg_map_get(config, "options", &options); 954135446Strhodes 955135446Strhodes i = 0; 956135446Strhodes if (vconfig != NULL) { 957135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 958135446Strhodes maps[i++] = voptions; 959135446Strhodes } 960135446Strhodes if (options != NULL) 961135446Strhodes maps[i++] = options; 962135446Strhodes maps[i++] = ns_g_defaults; 963135446Strhodes maps[i] = NULL; 964135446Strhodes 965135446Strhodes i = 0; 966135446Strhodes if (voptions != NULL) 967135446Strhodes cfgmaps[i++] = voptions; 968135446Strhodes if (config != NULL) 969135446Strhodes cfgmaps[i++] = config; 970135446Strhodes cfgmaps[i] = NULL; 971135446Strhodes 972170222Sdougb if (!strcmp(viewname, "_default")) { 973170222Sdougb sep = ""; 974170222Sdougb viewname = ""; 975170222Sdougb forview = ""; 976170222Sdougb } 977170222Sdougb 978135446Strhodes /* 979135446Strhodes * Set the view's port number for outgoing queries. 980135446Strhodes */ 981135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 982135446Strhodes dns_view_setdstport(view, port); 983135446Strhodes 984135446Strhodes /* 985170222Sdougb * Create additional cache for this view and zones under the view 986170222Sdougb * if explicitly enabled. 987170222Sdougb * XXX950 default to on. 988170222Sdougb */ 989170222Sdougb obj = NULL; 990170222Sdougb (void)ns_config_get(maps, "acache-enable", &obj); 991170222Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) { 992170222Sdougb cmctx = NULL; 993170222Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 994170222Sdougb CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, 995170222Sdougb ns_g_timermgr)); 996170222Sdougb isc_mem_detach(&cmctx); 997170222Sdougb } 998170222Sdougb if (view->acache != NULL) { 999170222Sdougb obj = NULL; 1000170222Sdougb result = ns_config_get(maps, "acache-cleaning-interval", &obj); 1001170222Sdougb INSIST(result == ISC_R_SUCCESS); 1002170222Sdougb dns_acache_setcleaninginterval(view->acache, 1003170222Sdougb cfg_obj_asuint32(obj) * 60); 1004170222Sdougb 1005170222Sdougb obj = NULL; 1006170222Sdougb result = ns_config_get(maps, "max-acache-size", &obj); 1007170222Sdougb INSIST(result == ISC_R_SUCCESS); 1008170222Sdougb if (cfg_obj_isstring(obj)) { 1009170222Sdougb str = cfg_obj_asstring(obj); 1010170222Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 1011170222Sdougb max_acache_size = ISC_UINT32_MAX; 1012170222Sdougb } else { 1013170222Sdougb isc_resourcevalue_t value; 1014170222Sdougb 1015170222Sdougb value = cfg_obj_asuint64(obj); 1016170222Sdougb if (value > ISC_UINT32_MAX) { 1017170222Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1018170222Sdougb "'max-acache-size " 1019170222Sdougb "%" ISC_PRINT_QUADFORMAT 1020170222Sdougb "d' is too large", 1021170222Sdougb value); 1022170222Sdougb result = ISC_R_RANGE; 1023170222Sdougb goto cleanup; 1024170222Sdougb } 1025170222Sdougb max_acache_size = (isc_uint32_t)value; 1026170222Sdougb } 1027170222Sdougb dns_acache_setcachesize(view->acache, max_acache_size); 1028170222Sdougb } 1029170222Sdougb 1030170222Sdougb /* 1031135446Strhodes * Configure the zones. 1032135446Strhodes */ 1033135446Strhodes zonelist = NULL; 1034135446Strhodes if (voptions != NULL) 1035135446Strhodes (void)cfg_map_get(voptions, "zone", &zonelist); 1036135446Strhodes else 1037135446Strhodes (void)cfg_map_get(config, "zone", &zonelist); 1038135446Strhodes for (element = cfg_list_first(zonelist); 1039135446Strhodes element != NULL; 1040135446Strhodes element = cfg_list_next(element)) 1041135446Strhodes { 1042165071Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 1043135446Strhodes CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 1044135446Strhodes actx)); 1045135446Strhodes } 1046135446Strhodes 1047170222Sdougb#ifdef DLZ 1048135446Strhodes /* 1049170222Sdougb * Create Dynamically Loadable Zone driver. 1050170222Sdougb */ 1051170222Sdougb dlz = NULL; 1052170222Sdougb if (voptions != NULL) 1053170222Sdougb (void)cfg_map_get(voptions, "dlz", &dlz); 1054170222Sdougb else 1055170222Sdougb (void)cfg_map_get(config, "dlz", &dlz); 1056170222Sdougb 1057170222Sdougb obj = NULL; 1058170222Sdougb if (dlz != NULL) { 1059170222Sdougb (void)cfg_map_get(cfg_tuple_get(dlz, "options"), 1060170222Sdougb "database", &obj); 1061170222Sdougb if (obj != NULL) { 1062170222Sdougb char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); 1063170222Sdougb if (s == NULL) { 1064170222Sdougb result = ISC_R_NOMEMORY; 1065170222Sdougb goto cleanup; 1066170222Sdougb } 1067170222Sdougb 1068170222Sdougb result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); 1069170222Sdougb if (result != ISC_R_SUCCESS) { 1070170222Sdougb isc_mem_free(mctx, s); 1071170222Sdougb goto cleanup; 1072170222Sdougb } 1073170222Sdougb 1074170222Sdougb obj = cfg_tuple_get(dlz, "name"); 1075170222Sdougb result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), 1076170222Sdougb dlzargv[0], dlzargc, dlzargv, 1077170222Sdougb &view->dlzdatabase); 1078170222Sdougb isc_mem_free(mctx, s); 1079170222Sdougb isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); 1080170222Sdougb if (result != ISC_R_SUCCESS) 1081170222Sdougb goto cleanup; 1082170222Sdougb } 1083170222Sdougb } 1084170222Sdougb#endif 1085170222Sdougb 1086170222Sdougb /* 1087135446Strhodes * Configure the view's cache. Try to reuse an existing 1088135446Strhodes * cache if possible, otherwise create a new cache. 1089135446Strhodes * Note that the ADB is not preserved in either case. 1090135446Strhodes * 1091135446Strhodes * XXX Determining when it is safe to reuse a cache is 1092135446Strhodes * tricky. When the view's configuration changes, the cached 1093135446Strhodes * data may become invalid because it reflects our old 1094135446Strhodes * view of the world. As more view attributes become 1095135446Strhodes * configurable, we will have to add code here to check 1096135446Strhodes * whether they have changed in ways that could 1097135446Strhodes * invalidate the cache. 1098135446Strhodes */ 1099135446Strhodes result = dns_viewlist_find(&ns_g_server->viewlist, 1100135446Strhodes view->name, view->rdclass, 1101135446Strhodes &pview); 1102135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 1103135446Strhodes goto cleanup; 1104135446Strhodes if (pview != NULL) { 1105135446Strhodes INSIST(pview->cache != NULL); 1106135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1107135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), 1108135446Strhodes "reusing existing cache"); 1109135446Strhodes reused_cache = ISC_TRUE; 1110135446Strhodes dns_cache_attach(pview->cache, &cache); 1111135446Strhodes dns_view_detach(&pview); 1112135446Strhodes } else { 1113135446Strhodes CHECK(isc_mem_create(0, 0, &cmctx)); 1114135446Strhodes CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, 1115135446Strhodes view->rdclass, "rbt", 0, NULL, &cache)); 1116135446Strhodes } 1117135446Strhodes dns_view_setcache(view, cache); 1118135446Strhodes 1119135446Strhodes /* 1120135446Strhodes * cache-file cannot be inherited if views are present, but this 1121135446Strhodes * should be caught by the configuration checking stage. 1122135446Strhodes */ 1123135446Strhodes obj = NULL; 1124135446Strhodes result = ns_config_get(maps, "cache-file", &obj); 1125135446Strhodes if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 1126135446Strhodes CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 1127135446Strhodes if (!reused_cache) 1128135446Strhodes CHECK(dns_cache_load(cache)); 1129135446Strhodes } 1130135446Strhodes 1131135446Strhodes obj = NULL; 1132135446Strhodes result = ns_config_get(maps, "cleaning-interval", &obj); 1133135446Strhodes INSIST(result == ISC_R_SUCCESS); 1134135446Strhodes dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60); 1135135446Strhodes 1136135446Strhodes obj = NULL; 1137135446Strhodes result = ns_config_get(maps, "max-cache-size", &obj); 1138135446Strhodes INSIST(result == ISC_R_SUCCESS); 1139135446Strhodes if (cfg_obj_isstring(obj)) { 1140135446Strhodes str = cfg_obj_asstring(obj); 1141135446Strhodes INSIST(strcasecmp(str, "unlimited") == 0); 1142135446Strhodes max_cache_size = ISC_UINT32_MAX; 1143135446Strhodes } else { 1144135446Strhodes isc_resourcevalue_t value; 1145135446Strhodes value = cfg_obj_asuint64(obj); 1146135446Strhodes if (value > ISC_UINT32_MAX) { 1147135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1148135446Strhodes "'max-cache-size " 1149135446Strhodes "%" ISC_PRINT_QUADFORMAT "d' is too large", 1150135446Strhodes value); 1151135446Strhodes result = ISC_R_RANGE; 1152135446Strhodes goto cleanup; 1153135446Strhodes } 1154135446Strhodes max_cache_size = (isc_uint32_t)value; 1155135446Strhodes } 1156135446Strhodes dns_cache_setcachesize(cache, max_cache_size); 1157135446Strhodes 1158135446Strhodes dns_cache_detach(&cache); 1159135446Strhodes 1160135446Strhodes /* 1161135446Strhodes * Check-names. 1162135446Strhodes */ 1163135446Strhodes obj = NULL; 1164135446Strhodes result = ns_checknames_get(maps, "response", &obj); 1165135446Strhodes INSIST(result == ISC_R_SUCCESS); 1166135446Strhodes 1167135446Strhodes str = cfg_obj_asstring(obj); 1168135446Strhodes if (strcasecmp(str, "fail") == 0) { 1169135446Strhodes check = DNS_RESOLVER_CHECKNAMES | 1170135446Strhodes DNS_RESOLVER_CHECKNAMESFAIL; 1171135446Strhodes view->checknames = ISC_TRUE; 1172135446Strhodes } else if (strcasecmp(str, "warn") == 0) { 1173135446Strhodes check = DNS_RESOLVER_CHECKNAMES; 1174135446Strhodes view->checknames = ISC_FALSE; 1175135446Strhodes } else if (strcasecmp(str, "ignore") == 0) { 1176135446Strhodes check = 0; 1177135446Strhodes view->checknames = ISC_FALSE; 1178135446Strhodes } else 1179135446Strhodes INSIST(0); 1180135446Strhodes 1181135446Strhodes /* 1182135446Strhodes * Resolver. 1183135446Strhodes * 1184135446Strhodes * XXXRTH Hardwired number of tasks. 1185135446Strhodes */ 1186135446Strhodes CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4)); 1187135446Strhodes CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6)); 1188135446Strhodes if (dispatch4 == NULL && dispatch6 == NULL) { 1189135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 1190135446Strhodes "unable to obtain neither an IPv4 nor" 1191135446Strhodes " an IPv6 dispatch"); 1192135446Strhodes result = ISC_R_UNEXPECTED; 1193135446Strhodes goto cleanup; 1194135446Strhodes } 1195135446Strhodes CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, 1196135446Strhodes ns_g_socketmgr, ns_g_timermgr, 1197135446Strhodes check, ns_g_dispatchmgr, 1198135446Strhodes dispatch4, dispatch6)); 1199135446Strhodes 1200135446Strhodes /* 1201135446Strhodes * Set the ADB cache size to 1/8th of the max-cache-size. 1202135446Strhodes */ 1203135446Strhodes max_adb_size = 0; 1204135446Strhodes if (max_cache_size != 0) { 1205135446Strhodes max_adb_size = max_cache_size / 8; 1206135446Strhodes if (max_adb_size == 0) 1207135446Strhodes max_adb_size = 1; /* Force minimum. */ 1208135446Strhodes } 1209135446Strhodes dns_adb_setadbsize(view->adb, max_adb_size); 1210135446Strhodes 1211135446Strhodes /* 1212135446Strhodes * Set resolver's lame-ttl. 1213135446Strhodes */ 1214135446Strhodes obj = NULL; 1215135446Strhodes result = ns_config_get(maps, "lame-ttl", &obj); 1216135446Strhodes INSIST(result == ISC_R_SUCCESS); 1217135446Strhodes lame_ttl = cfg_obj_asuint32(obj); 1218135446Strhodes if (lame_ttl > 1800) 1219135446Strhodes lame_ttl = 1800; 1220135446Strhodes dns_resolver_setlamettl(view->resolver, lame_ttl); 1221170222Sdougb 1222170222Sdougb obj = NULL; 1223170222Sdougb result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); 1224170222Sdougb INSIST(result == ISC_R_SUCCESS); 1225170222Sdougb dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj)); 1226135446Strhodes 1227135446Strhodes /* 1228135446Strhodes * Set the resolver's EDNS UDP size. 1229135446Strhodes */ 1230135446Strhodes obj = NULL; 1231135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 1232135446Strhodes INSIST(result == ISC_R_SUCCESS); 1233135446Strhodes udpsize = cfg_obj_asuint32(obj); 1234135446Strhodes if (udpsize < 512) 1235135446Strhodes udpsize = 512; 1236135446Strhodes if (udpsize > 4096) 1237135446Strhodes udpsize = 4096; 1238135446Strhodes dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 1239135446Strhodes 1240135446Strhodes /* 1241170222Sdougb * Set the maximum UDP response size. 1242170222Sdougb */ 1243170222Sdougb obj = NULL; 1244170222Sdougb result = ns_config_get(maps, "max-udp-size", &obj); 1245170222Sdougb INSIST(result == ISC_R_SUCCESS); 1246170222Sdougb udpsize = cfg_obj_asuint32(obj); 1247170222Sdougb if (udpsize < 512) 1248170222Sdougb udpsize = 512; 1249170222Sdougb if (udpsize > 4096) 1250170222Sdougb udpsize = 4096; 1251170222Sdougb view->maxudp = udpsize; 1252170222Sdougb 1253170222Sdougb /* 1254135446Strhodes * Set supported DNSSEC algorithms. 1255135446Strhodes */ 1256135446Strhodes dns_resolver_reset_algorithms(view->resolver); 1257135446Strhodes disabled = NULL; 1258135446Strhodes (void)ns_config_get(maps, "disable-algorithms", &disabled); 1259135446Strhodes if (disabled != NULL) { 1260135446Strhodes for (element = cfg_list_first(disabled); 1261135446Strhodes element != NULL; 1262135446Strhodes element = cfg_list_next(element)) 1263135446Strhodes CHECK(disable_algorithms(cfg_listelt_value(element), 1264135446Strhodes view->resolver)); 1265135446Strhodes } 1266135446Strhodes 1267135446Strhodes /* 1268135446Strhodes * A global or view "forwarders" option, if present, 1269135446Strhodes * creates an entry for "." in the forwarding table. 1270135446Strhodes */ 1271135446Strhodes forwardtype = NULL; 1272135446Strhodes forwarders = NULL; 1273135446Strhodes (void)ns_config_get(maps, "forward", &forwardtype); 1274135446Strhodes (void)ns_config_get(maps, "forwarders", &forwarders); 1275135446Strhodes if (forwarders != NULL) 1276135446Strhodes CHECK(configure_forward(config, view, dns_rootname, 1277135446Strhodes forwarders, forwardtype)); 1278135446Strhodes 1279135446Strhodes /* 1280135446Strhodes * Dual Stack Servers. 1281135446Strhodes */ 1282135446Strhodes alternates = NULL; 1283135446Strhodes (void)ns_config_get(maps, "dual-stack-servers", &alternates); 1284135446Strhodes if (alternates != NULL) 1285135446Strhodes CHECK(configure_alternates(config, view, alternates)); 1286135446Strhodes 1287135446Strhodes /* 1288135446Strhodes * We have default hints for class IN if we need them. 1289135446Strhodes */ 1290135446Strhodes if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 1291135446Strhodes dns_view_sethints(view, ns_g_server->in_roothints); 1292135446Strhodes 1293135446Strhodes /* 1294135446Strhodes * If we still have no hints, this is a non-IN view with no 1295135446Strhodes * "hints zone" configured. Issue a warning, except if this 1296135446Strhodes * is a root server. Root servers never need to consult 1297135446Strhodes * their hints, so it's no point requiring users to configure 1298135446Strhodes * them. 1299135446Strhodes */ 1300135446Strhodes if (view->hints == NULL) { 1301135446Strhodes dns_zone_t *rootzone = NULL; 1302135446Strhodes (void)dns_view_findzone(view, dns_rootname, &rootzone); 1303135446Strhodes if (rootzone != NULL) { 1304135446Strhodes dns_zone_detach(&rootzone); 1305135446Strhodes need_hints = ISC_FALSE; 1306135446Strhodes } 1307135446Strhodes if (need_hints) 1308135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1309135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1310135446Strhodes "no root hints for view '%s'", 1311135446Strhodes view->name); 1312135446Strhodes } 1313135446Strhodes 1314135446Strhodes /* 1315135446Strhodes * Configure the view's TSIG keys. 1316135446Strhodes */ 1317135446Strhodes ring = NULL; 1318135446Strhodes CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 1319135446Strhodes dns_view_setkeyring(view, ring); 1320135446Strhodes 1321135446Strhodes /* 1322135446Strhodes * Configure the view's peer list. 1323135446Strhodes */ 1324135446Strhodes { 1325165071Sdougb const cfg_obj_t *peers = NULL; 1326165071Sdougb const cfg_listelt_t *element; 1327135446Strhodes dns_peerlist_t *newpeers = NULL; 1328135446Strhodes 1329135446Strhodes (void)ns_config_get(cfgmaps, "server", &peers); 1330135446Strhodes CHECK(dns_peerlist_new(mctx, &newpeers)); 1331135446Strhodes for (element = cfg_list_first(peers); 1332135446Strhodes element != NULL; 1333135446Strhodes element = cfg_list_next(element)) 1334135446Strhodes { 1335165071Sdougb const cfg_obj_t *cpeer = cfg_listelt_value(element); 1336135446Strhodes dns_peer_t *peer; 1337135446Strhodes 1338135446Strhodes CHECK(configure_peer(cpeer, mctx, &peer)); 1339135446Strhodes dns_peerlist_addpeer(newpeers, peer); 1340135446Strhodes dns_peer_detach(&peer); 1341135446Strhodes } 1342135446Strhodes dns_peerlist_detach(&view->peers); 1343135446Strhodes view->peers = newpeers; /* Transfer ownership. */ 1344135446Strhodes } 1345135446Strhodes 1346135446Strhodes /* 1347135446Strhodes * Configure the views rrset-order. 1348135446Strhodes */ 1349135446Strhodes { 1350165071Sdougb const cfg_obj_t *rrsetorder = NULL; 1351165071Sdougb const cfg_listelt_t *element; 1352135446Strhodes 1353135446Strhodes (void)ns_config_get(maps, "rrset-order", &rrsetorder); 1354135446Strhodes CHECK(dns_order_create(mctx, &order)); 1355135446Strhodes for (element = cfg_list_first(rrsetorder); 1356135446Strhodes element != NULL; 1357135446Strhodes element = cfg_list_next(element)) 1358135446Strhodes { 1359165071Sdougb const cfg_obj_t *ent = cfg_listelt_value(element); 1360135446Strhodes 1361135446Strhodes CHECK(configure_order(order, ent)); 1362135446Strhodes } 1363135446Strhodes if (view->order != NULL) 1364135446Strhodes dns_order_detach(&view->order); 1365135446Strhodes dns_order_attach(order, &view->order); 1366135446Strhodes dns_order_detach(&order); 1367135446Strhodes } 1368135446Strhodes /* 1369135446Strhodes * Copy the aclenv object. 1370135446Strhodes */ 1371135446Strhodes dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 1372135446Strhodes 1373135446Strhodes /* 1374135446Strhodes * Configure the "match-clients" and "match-destinations" ACL. 1375135446Strhodes */ 1376135446Strhodes CHECK(configure_view_acl(vconfig, config, "match-clients", actx, 1377135446Strhodes ns_g_mctx, &view->matchclients)); 1378135446Strhodes CHECK(configure_view_acl(vconfig, config, "match-destinations", actx, 1379135446Strhodes ns_g_mctx, &view->matchdestinations)); 1380135446Strhodes 1381135446Strhodes /* 1382135446Strhodes * Configure the "match-recursive-only" option. 1383135446Strhodes */ 1384135446Strhodes obj = NULL; 1385165071Sdougb (void)ns_config_get(maps, "match-recursive-only", &obj); 1386135446Strhodes if (obj != NULL && cfg_obj_asboolean(obj)) 1387135446Strhodes view->matchrecursiveonly = ISC_TRUE; 1388135446Strhodes else 1389135446Strhodes view->matchrecursiveonly = ISC_FALSE; 1390135446Strhodes 1391135446Strhodes /* 1392135446Strhodes * Configure other configurable data. 1393135446Strhodes */ 1394135446Strhodes obj = NULL; 1395135446Strhodes result = ns_config_get(maps, "recursion", &obj); 1396135446Strhodes INSIST(result == ISC_R_SUCCESS); 1397135446Strhodes view->recursion = cfg_obj_asboolean(obj); 1398135446Strhodes 1399135446Strhodes obj = NULL; 1400135446Strhodes result = ns_config_get(maps, "auth-nxdomain", &obj); 1401135446Strhodes INSIST(result == ISC_R_SUCCESS); 1402135446Strhodes view->auth_nxdomain = cfg_obj_asboolean(obj); 1403135446Strhodes 1404135446Strhodes obj = NULL; 1405135446Strhodes result = ns_config_get(maps, "minimal-responses", &obj); 1406135446Strhodes INSIST(result == ISC_R_SUCCESS); 1407135446Strhodes view->minimalresponses = cfg_obj_asboolean(obj); 1408135446Strhodes 1409135446Strhodes obj = NULL; 1410135446Strhodes result = ns_config_get(maps, "transfer-format", &obj); 1411135446Strhodes INSIST(result == ISC_R_SUCCESS); 1412135446Strhodes str = cfg_obj_asstring(obj); 1413135446Strhodes if (strcasecmp(str, "many-answers") == 0) 1414135446Strhodes view->transfer_format = dns_many_answers; 1415135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 1416135446Strhodes view->transfer_format = dns_one_answer; 1417135446Strhodes else 1418135446Strhodes INSIST(0); 1419135446Strhodes 1420135446Strhodes /* 1421135446Strhodes * Set sources where additional data and CNAME/DNAME 1422135446Strhodes * targets for authoritative answers may be found. 1423135446Strhodes */ 1424135446Strhodes obj = NULL; 1425135446Strhodes result = ns_config_get(maps, "additional-from-auth", &obj); 1426135446Strhodes INSIST(result == ISC_R_SUCCESS); 1427135446Strhodes view->additionalfromauth = cfg_obj_asboolean(obj); 1428135446Strhodes if (view->recursion && ! view->additionalfromauth) { 1429135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1430135446Strhodes "'additional-from-auth no' is only supported " 1431135446Strhodes "with 'recursion no'"); 1432135446Strhodes view->additionalfromauth = ISC_TRUE; 1433135446Strhodes } 1434135446Strhodes 1435135446Strhodes obj = NULL; 1436135446Strhodes result = ns_config_get(maps, "additional-from-cache", &obj); 1437135446Strhodes INSIST(result == ISC_R_SUCCESS); 1438135446Strhodes view->additionalfromcache = cfg_obj_asboolean(obj); 1439135446Strhodes if (view->recursion && ! view->additionalfromcache) { 1440135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1441135446Strhodes "'additional-from-cache no' is only supported " 1442135446Strhodes "with 'recursion no'"); 1443135446Strhodes view->additionalfromcache = ISC_TRUE; 1444135446Strhodes } 1445135446Strhodes 1446171577Sdougb /* 1447171577Sdougb * Set "allow-query-cache" and "allow-recursion" acls if 1448171577Sdougb * configured in named.conf. 1449171577Sdougb */ 1450170222Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache", 1451135446Strhodes actx, ns_g_mctx, &view->queryacl)); 1452135446Strhodes 1453135446Strhodes if (strcmp(view->name, "_bind") != 0) 1454135446Strhodes CHECK(configure_view_acl(vconfig, config, "allow-recursion", 1455135446Strhodes actx, ns_g_mctx, &view->recursionacl)); 1456135446Strhodes 1457135446Strhodes /* 1458135446Strhodes * Warning if both "recursion no;" and allow-recursion are active 1459135446Strhodes * except for "allow-recursion { none; };". 1460135446Strhodes */ 1461135446Strhodes if (!view->recursion && view->recursionacl != NULL && 1462135446Strhodes (view->recursionacl->length != 1 || 1463135446Strhodes view->recursionacl->elements[0].type != dns_aclelementtype_any || 1464170222Sdougb view->recursionacl->elements[0].negative != ISC_TRUE)) 1465135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1466135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1467135446Strhodes "both \"recursion no;\" and \"allow-recursion\" " 1468135446Strhodes "active%s%s", forview, viewname); 1469135446Strhodes 1470170222Sdougb /* 1471171577Sdougb * "allow-query-cache" inherits from "allow-recursion" if set, 1472171577Sdougb * otherwise from "allow-query" if set. 1473171577Sdougb * "allow-recursion" inherits from "allow-query-cache" if set, 1474171577Sdougb * otherwise from "allow-query" if set. 1475170222Sdougb */ 1476171577Sdougb if (view->queryacl == NULL && view->recursionacl != NULL) 1477171577Sdougb dns_acl_attach(view->recursionacl, &view->queryacl); 1478171577Sdougb if (view->queryacl == NULL) 1479171577Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", 1480171577Sdougb actx, ns_g_mctx, &view->queryacl)); 1481171577Sdougb if (view->recursionacl == NULL && view->queryacl != NULL) 1482171577Sdougb dns_acl_attach(view->queryacl, &view->recursionacl); 1483171577Sdougb 1484171577Sdougb /* 1485171577Sdougb * Set default "allow-recursion" and "allow-query-cache" acls. 1486171577Sdougb */ 1487170222Sdougb if (view->recursionacl == NULL && view->recursion) 1488171577Sdougb CHECK(configure_view_acl(NULL, ns_g_config, "allow-recursion", 1489170222Sdougb actx, ns_g_mctx, &view->recursionacl)); 1490171577Sdougb if (view->queryacl == NULL) 1491171577Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 1492171577Sdougb "allow-query-cache", actx, 1493171577Sdougb ns_g_mctx, &view->queryacl)); 1494170222Sdougb 1495135446Strhodes CHECK(configure_view_acl(vconfig, config, "sortlist", 1496135446Strhodes actx, ns_g_mctx, &view->sortlist)); 1497135446Strhodes 1498135446Strhodes obj = NULL; 1499135446Strhodes result = ns_config_get(maps, "request-ixfr", &obj); 1500135446Strhodes INSIST(result == ISC_R_SUCCESS); 1501135446Strhodes view->requestixfr = cfg_obj_asboolean(obj); 1502135446Strhodes 1503135446Strhodes obj = NULL; 1504135446Strhodes result = ns_config_get(maps, "provide-ixfr", &obj); 1505135446Strhodes INSIST(result == ISC_R_SUCCESS); 1506135446Strhodes view->provideixfr = cfg_obj_asboolean(obj); 1507170222Sdougb 1508170222Sdougb obj = NULL; 1509170222Sdougb result = ns_config_get(maps, "max-clients-per-query", &obj); 1510170222Sdougb INSIST(result == ISC_R_SUCCESS); 1511170222Sdougb max_clients_per_query = cfg_obj_asuint32(obj); 1512170222Sdougb 1513170222Sdougb obj = NULL; 1514170222Sdougb result = ns_config_get(maps, "clients-per-query", &obj); 1515170222Sdougb INSIST(result == ISC_R_SUCCESS); 1516170222Sdougb dns_resolver_setclientsperquery(view->resolver, 1517170222Sdougb cfg_obj_asuint32(obj), 1518170222Sdougb max_clients_per_query); 1519135446Strhodes 1520135446Strhodes obj = NULL; 1521135446Strhodes result = ns_config_get(maps, "dnssec-enable", &obj); 1522135446Strhodes INSIST(result == ISC_R_SUCCESS); 1523135446Strhodes view->enablednssec = cfg_obj_asboolean(obj); 1524135446Strhodes 1525135446Strhodes obj = NULL; 1526170222Sdougb result = ns_config_get(maps, "dnssec-accept-expired", &obj); 1527170222Sdougb INSIST(result == ISC_R_SUCCESS); 1528170222Sdougb view->acceptexpired = cfg_obj_asboolean(obj); 1529170222Sdougb 1530170222Sdougb obj = NULL; 1531170222Sdougb result = ns_config_get(maps, "dnssec-validation", &obj); 1532170222Sdougb INSIST(result == ISC_R_SUCCESS); 1533170222Sdougb view->enablevalidation = cfg_obj_asboolean(obj); 1534170222Sdougb 1535170222Sdougb obj = NULL; 1536135446Strhodes result = ns_config_get(maps, "dnssec-lookaside", &obj); 1537135446Strhodes if (result == ISC_R_SUCCESS) { 1538135446Strhodes for (element = cfg_list_first(obj); 1539135446Strhodes element != NULL; 1540135446Strhodes element = cfg_list_next(element)) 1541135446Strhodes { 1542135446Strhodes const char *str; 1543135446Strhodes isc_buffer_t b; 1544135446Strhodes dns_name_t *dlv; 1545135446Strhodes 1546135446Strhodes obj = cfg_listelt_value(element); 1547135446Strhodes#if 0 1548135446Strhodes dns_fixedname_t fixed; 1549135446Strhodes dns_name_t *name; 1550135446Strhodes 1551135446Strhodes /* 1552135446Strhodes * When we support multiple dnssec-lookaside 1553135446Strhodes * entries this is how to find the domain to be 1554135446Strhodes * checked. XXXMPA 1555135446Strhodes */ 1556135446Strhodes dns_fixedname_init(&fixed); 1557135446Strhodes name = dns_fixedname_name(&fixed); 1558135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, 1559135446Strhodes "domain")); 1560135446Strhodes isc_buffer_init(&b, str, strlen(str)); 1561135446Strhodes isc_buffer_add(&b, strlen(str)); 1562135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 1563135446Strhodes ISC_TRUE, NULL)); 1564135446Strhodes#endif 1565135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, 1566135446Strhodes "trust-anchor")); 1567135446Strhodes isc_buffer_init(&b, str, strlen(str)); 1568135446Strhodes isc_buffer_add(&b, strlen(str)); 1569135446Strhodes dlv = dns_fixedname_name(&view->dlv_fixed); 1570135446Strhodes CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 1571135446Strhodes ISC_TRUE, NULL)); 1572135446Strhodes view->dlv = dns_fixedname_name(&view->dlv_fixed); 1573135446Strhodes } 1574135446Strhodes } else 1575135446Strhodes view->dlv = NULL; 1576135446Strhodes 1577135446Strhodes /* 1578135446Strhodes * For now, there is only one kind of trusted keys, the 1579135446Strhodes * "security roots". 1580135446Strhodes */ 1581170222Sdougb CHECK(configure_view_dnsseckeys(vconfig, config, mctx, 1582170222Sdougb &view->secroots)); 1583170222Sdougb dns_resolver_resetmustbesecure(view->resolver); 1584170222Sdougb obj = NULL; 1585170222Sdougb result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 1586170222Sdougb if (result == ISC_R_SUCCESS) 1587170222Sdougb CHECK(mustbesecure(obj, view->resolver)); 1588135446Strhodes 1589135446Strhodes obj = NULL; 1590135446Strhodes result = ns_config_get(maps, "max-cache-ttl", &obj); 1591135446Strhodes INSIST(result == ISC_R_SUCCESS); 1592135446Strhodes view->maxcachettl = cfg_obj_asuint32(obj); 1593135446Strhodes 1594135446Strhodes obj = NULL; 1595135446Strhodes result = ns_config_get(maps, "max-ncache-ttl", &obj); 1596135446Strhodes INSIST(result == ISC_R_SUCCESS); 1597135446Strhodes view->maxncachettl = cfg_obj_asuint32(obj); 1598135446Strhodes if (view->maxncachettl > 7 * 24 * 3600) 1599135446Strhodes view->maxncachettl = 7 * 24 * 3600; 1600135446Strhodes 1601135446Strhodes obj = NULL; 1602135446Strhodes result = ns_config_get(maps, "preferred-glue", &obj); 1603135446Strhodes if (result == ISC_R_SUCCESS) { 1604135446Strhodes str = cfg_obj_asstring(obj); 1605135446Strhodes if (strcasecmp(str, "a") == 0) 1606135446Strhodes view->preferred_glue = dns_rdatatype_a; 1607135446Strhodes else if (strcasecmp(str, "aaaa") == 0) 1608135446Strhodes view->preferred_glue = dns_rdatatype_aaaa; 1609135446Strhodes else 1610135446Strhodes view->preferred_glue = 0; 1611135446Strhodes } else 1612135446Strhodes view->preferred_glue = 0; 1613135446Strhodes 1614135446Strhodes obj = NULL; 1615135446Strhodes result = ns_config_get(maps, "root-delegation-only", &obj); 1616135446Strhodes if (result == ISC_R_SUCCESS) { 1617135446Strhodes dns_view_setrootdelonly(view, ISC_TRUE); 1618135446Strhodes if (!cfg_obj_isvoid(obj)) { 1619135446Strhodes dns_fixedname_t fixed; 1620135446Strhodes dns_name_t *name; 1621135446Strhodes isc_buffer_t b; 1622165071Sdougb const char *str; 1623165071Sdougb const cfg_obj_t *exclude; 1624135446Strhodes 1625135446Strhodes dns_fixedname_init(&fixed); 1626135446Strhodes name = dns_fixedname_name(&fixed); 1627135446Strhodes for (element = cfg_list_first(obj); 1628135446Strhodes element != NULL; 1629135446Strhodes element = cfg_list_next(element)) { 1630135446Strhodes exclude = cfg_listelt_value(element); 1631135446Strhodes str = cfg_obj_asstring(exclude); 1632135446Strhodes isc_buffer_init(&b, str, strlen(str)); 1633135446Strhodes isc_buffer_add(&b, strlen(str)); 1634135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 1635135446Strhodes ISC_FALSE, NULL)); 1636135446Strhodes CHECK(dns_view_excludedelegationonly(view, 1637135446Strhodes name)); 1638135446Strhodes } 1639135446Strhodes } 1640135446Strhodes } else 1641135446Strhodes dns_view_setrootdelonly(view, ISC_FALSE); 1642135446Strhodes 1643170222Sdougb /* 1644170222Sdougb * Setup automatic empty zones. If recursion is off then 1645170222Sdougb * they are disabled by default. 1646170222Sdougb */ 1647170222Sdougb obj = NULL; 1648170222Sdougb (void)ns_config_get(maps, "empty-zones-enable", &obj); 1649170222Sdougb (void)ns_config_get(maps, "disable-empty-zone", &disablelist); 1650170222Sdougb if (obj == NULL && disablelist == NULL && 1651170222Sdougb view->rdclass == dns_rdataclass_in) { 1652170222Sdougb rfc1918 = ISC_FALSE; 1653170222Sdougb empty_zones_enable = view->recursion; 1654170222Sdougb } else if (view->rdclass == dns_rdataclass_in) { 1655170222Sdougb rfc1918 = ISC_TRUE; 1656170222Sdougb if (obj != NULL) 1657170222Sdougb empty_zones_enable = cfg_obj_asboolean(obj); 1658170222Sdougb else 1659170222Sdougb empty_zones_enable = view->recursion; 1660170222Sdougb } else { 1661170222Sdougb rfc1918 = ISC_FALSE; 1662170222Sdougb empty_zones_enable = ISC_FALSE; 1663170222Sdougb } 1664170222Sdougb if (empty_zones_enable) { 1665170222Sdougb const char *empty; 1666170222Sdougb int empty_zone = 0; 1667170222Sdougb dns_fixedname_t fixed; 1668170222Sdougb dns_name_t *name; 1669170222Sdougb isc_buffer_t buffer; 1670170222Sdougb const char *str; 1671170222Sdougb char server[DNS_NAME_FORMATSIZE + 1]; 1672170222Sdougb char contact[DNS_NAME_FORMATSIZE + 1]; 1673170222Sdougb isc_boolean_t logit; 1674170222Sdougb const char *empty_dbtype[4] = 1675170222Sdougb { "_builtin", "empty", NULL, NULL }; 1676170222Sdougb int empty_dbtypec = 4; 1677170222Sdougb 1678170222Sdougb dns_fixedname_init(&fixed); 1679170222Sdougb name = dns_fixedname_name(&fixed); 1680170222Sdougb 1681170222Sdougb obj = NULL; 1682170222Sdougb result = ns_config_get(maps, "empty-server", &obj); 1683170222Sdougb if (result == ISC_R_SUCCESS) { 1684170222Sdougb str = cfg_obj_asstring(obj); 1685170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 1686170222Sdougb isc_buffer_add(&buffer, strlen(str)); 1687170222Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1688170222Sdougb ISC_FALSE, NULL)); 1689170222Sdougb isc_buffer_init(&buffer, server, sizeof(server) - 1); 1690170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 1691170222Sdougb server[isc_buffer_usedlength(&buffer)] = 0; 1692170222Sdougb empty_dbtype[2] = server; 1693170222Sdougb } else 1694170222Sdougb empty_dbtype[2] = "@"; 1695170222Sdougb 1696170222Sdougb obj = NULL; 1697170222Sdougb result = ns_config_get(maps, "empty-contact", &obj); 1698170222Sdougb if (result == ISC_R_SUCCESS) { 1699170222Sdougb str = cfg_obj_asstring(obj); 1700170222Sdougb isc_buffer_init(&buffer, str, strlen(str)); 1701170222Sdougb isc_buffer_add(&buffer, strlen(str)); 1702170222Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1703170222Sdougb ISC_FALSE, NULL)); 1704170222Sdougb isc_buffer_init(&buffer, contact, sizeof(contact) - 1); 1705170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 1706170222Sdougb contact[isc_buffer_usedlength(&buffer)] = 0; 1707170222Sdougb empty_dbtype[3] = contact; 1708170222Sdougb } else 1709170222Sdougb empty_dbtype[3] = "."; 1710170222Sdougb 1711170222Sdougb logit = ISC_TRUE; 1712170222Sdougb for (empty = empty_zones[empty_zone].zone; 1713170222Sdougb empty != NULL; 1714170222Sdougb empty = empty_zones[++empty_zone].zone) 1715170222Sdougb { 1716170222Sdougb dns_forwarders_t *forwarders = NULL; 1717170222Sdougb dns_view_t *pview = NULL; 1718170222Sdougb 1719170222Sdougb isc_buffer_init(&buffer, empty, strlen(empty)); 1720170222Sdougb isc_buffer_add(&buffer, strlen(empty)); 1721170222Sdougb /* 1722170222Sdougb * Look for zone on drop list. 1723170222Sdougb */ 1724170222Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1725170222Sdougb ISC_FALSE, NULL)); 1726170222Sdougb if (disablelist != NULL && 1727170222Sdougb on_disable_list(disablelist, name)) 1728170222Sdougb continue; 1729170222Sdougb 1730170222Sdougb /* 1731170222Sdougb * This zone already exists. 1732170222Sdougb */ 1733170222Sdougb (void)dns_view_findzone(view, name, &zone); 1734170222Sdougb if (zone != NULL) { 1735170222Sdougb dns_zone_detach(&zone); 1736170222Sdougb continue; 1737170222Sdougb } 1738170222Sdougb 1739170222Sdougb /* 1740170222Sdougb * If we would forward this name don't add a 1741170222Sdougb * empty zone for it. 1742170222Sdougb */ 1743170222Sdougb result = dns_fwdtable_find(view->fwdtable, name, 1744170222Sdougb &forwarders); 1745170222Sdougb if (result == ISC_R_SUCCESS && 1746170222Sdougb forwarders->fwdpolicy == dns_fwdpolicy_only) 1747170222Sdougb continue; 1748170222Sdougb 1749170222Sdougb if (!rfc1918 && empty_zones[empty_zone].rfc1918) { 1750170222Sdougb if (logit) { 1751170222Sdougb isc_log_write(ns_g_lctx, 1752170222Sdougb NS_LOGCATEGORY_GENERAL, 1753170222Sdougb NS_LOGMODULE_SERVER, 1754170222Sdougb ISC_LOG_WARNING, 1755170222Sdougb "Warning%s%s: " 1756170222Sdougb "'empty-zones-enable/" 1757170222Sdougb "disable-empty-zone' " 1758170222Sdougb "not set: disabling " 1759170222Sdougb "RFC 1918 empty zones", 1760170222Sdougb sep, viewname); 1761170222Sdougb logit = ISC_FALSE; 1762170222Sdougb } 1763170222Sdougb continue; 1764170222Sdougb } 1765170222Sdougb 1766170222Sdougb /* 1767170222Sdougb * See if we can re-use a existing zone. 1768170222Sdougb */ 1769170222Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 1770170222Sdougb view->name, view->rdclass, 1771170222Sdougb &pview); 1772170222Sdougb if (result != ISC_R_NOTFOUND && 1773170222Sdougb result != ISC_R_SUCCESS) 1774170222Sdougb goto cleanup; 1775170222Sdougb 1776170222Sdougb if (pview != NULL) { 1777170222Sdougb (void)dns_view_findzone(pview, name, &zone); 1778170222Sdougb dns_view_detach(&pview); 1779170222Sdougb if (zone != NULL) 1780170222Sdougb check_dbtype(&zone, empty_dbtypec, 1781170222Sdougb empty_dbtype, mctx); 1782170222Sdougb if (zone != NULL) { 1783170222Sdougb dns_zone_setview(zone, view); 1784174187Sdougb CHECK(dns_view_addzone(view, zone)); 1785170222Sdougb dns_zone_detach(&zone); 1786170222Sdougb continue; 1787170222Sdougb } 1788170222Sdougb } 1789170222Sdougb 1790170222Sdougb CHECK(dns_zone_create(&zone, mctx)); 1791170222Sdougb CHECK(dns_zone_setorigin(zone, name)); 1792170222Sdougb dns_zone_setview(zone, view); 1793170222Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1794170222Sdougb dns_zone_setclass(zone, view->rdclass); 1795170222Sdougb dns_zone_settype(zone, dns_zone_master); 1796170222Sdougb CHECK(dns_zone_setdbtype(zone, empty_dbtypec, 1797170222Sdougb empty_dbtype)); 1798170222Sdougb if (view->queryacl != NULL) 1799170222Sdougb dns_zone_setqueryacl(zone, view->queryacl); 1800170222Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 1801170222Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 1802170222Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, 1803170222Sdougb ISC_TRUE); 1804170222Sdougb CHECK(dns_view_addzone(view, zone)); 1805170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1806170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 1807170222Sdougb "automatic empty zone%s%s: %s", 1808170222Sdougb sep, viewname, empty); 1809170222Sdougb dns_zone_detach(&zone); 1810170222Sdougb } 1811170222Sdougb } 1812170222Sdougb 1813135446Strhodes result = ISC_R_SUCCESS; 1814135446Strhodes 1815135446Strhodes cleanup: 1816170222Sdougb if (zone != NULL) 1817170222Sdougb dns_zone_detach(&zone); 1818135446Strhodes if (dispatch4 != NULL) 1819135446Strhodes dns_dispatch_detach(&dispatch4); 1820135446Strhodes if (dispatch6 != NULL) 1821135446Strhodes dns_dispatch_detach(&dispatch6); 1822135446Strhodes if (order != NULL) 1823135446Strhodes dns_order_detach(&order); 1824135446Strhodes if (cmctx != NULL) 1825135446Strhodes isc_mem_detach(&cmctx); 1826135446Strhodes 1827135446Strhodes if (cache != NULL) 1828135446Strhodes dns_cache_detach(&cache); 1829135446Strhodes 1830135446Strhodes return (result); 1831135446Strhodes} 1832135446Strhodes 1833135446Strhodesstatic isc_result_t 1834135446Strhodesconfigure_hints(dns_view_t *view, const char *filename) { 1835135446Strhodes isc_result_t result; 1836135446Strhodes dns_db_t *db; 1837135446Strhodes 1838135446Strhodes db = NULL; 1839135446Strhodes result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 1840135446Strhodes if (result == ISC_R_SUCCESS) { 1841135446Strhodes dns_view_sethints(view, db); 1842135446Strhodes dns_db_detach(&db); 1843135446Strhodes } 1844135446Strhodes 1845135446Strhodes return (result); 1846135446Strhodes} 1847135446Strhodes 1848135446Strhodesstatic isc_result_t 1849165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 1850165071Sdougb const cfg_obj_t *alternates) 1851135446Strhodes{ 1852165071Sdougb const cfg_obj_t *portobj; 1853165071Sdougb const cfg_obj_t *addresses; 1854165071Sdougb const cfg_listelt_t *element; 1855135446Strhodes isc_result_t result = ISC_R_SUCCESS; 1856135446Strhodes in_port_t port; 1857135446Strhodes 1858135446Strhodes /* 1859135446Strhodes * Determine which port to send requests to. 1860135446Strhodes */ 1861135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 1862135446Strhodes port = ns_g_port; 1863135446Strhodes else 1864135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 1865135446Strhodes 1866135446Strhodes if (alternates != NULL) { 1867135446Strhodes portobj = cfg_tuple_get(alternates, "port"); 1868135446Strhodes if (cfg_obj_isuint32(portobj)) { 1869135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 1870135446Strhodes if (val > ISC_UINT16_MAX) { 1871135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1872135446Strhodes "port '%u' out of range", val); 1873135446Strhodes return (ISC_R_RANGE); 1874135446Strhodes } 1875135446Strhodes port = (in_port_t) val; 1876135446Strhodes } 1877135446Strhodes } 1878135446Strhodes 1879135446Strhodes addresses = NULL; 1880135446Strhodes if (alternates != NULL) 1881135446Strhodes addresses = cfg_tuple_get(alternates, "addresses"); 1882135446Strhodes 1883135446Strhodes for (element = cfg_list_first(addresses); 1884135446Strhodes element != NULL; 1885135446Strhodes element = cfg_list_next(element)) 1886135446Strhodes { 1887165071Sdougb const cfg_obj_t *alternate = cfg_listelt_value(element); 1888135446Strhodes isc_sockaddr_t sa; 1889135446Strhodes 1890135446Strhodes if (!cfg_obj_issockaddr(alternate)) { 1891135446Strhodes dns_fixedname_t fixed; 1892135446Strhodes dns_name_t *name; 1893165071Sdougb const char *str = cfg_obj_asstring(cfg_tuple_get( 1894165071Sdougb alternate, "name")); 1895135446Strhodes isc_buffer_t buffer; 1896135446Strhodes in_port_t myport = port; 1897135446Strhodes 1898135446Strhodes isc_buffer_init(&buffer, str, strlen(str)); 1899135446Strhodes isc_buffer_add(&buffer, strlen(str)); 1900135446Strhodes dns_fixedname_init(&fixed); 1901135446Strhodes name = dns_fixedname_name(&fixed); 1902135446Strhodes CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1903135446Strhodes ISC_FALSE, NULL)); 1904135446Strhodes 1905135446Strhodes portobj = cfg_tuple_get(alternate, "port"); 1906135446Strhodes if (cfg_obj_isuint32(portobj)) { 1907135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 1908135446Strhodes if (val > ISC_UINT16_MAX) { 1909135446Strhodes cfg_obj_log(portobj, ns_g_lctx, 1910135446Strhodes ISC_LOG_ERROR, 1911135446Strhodes "port '%u' out of range", 1912135446Strhodes val); 1913135446Strhodes return (ISC_R_RANGE); 1914135446Strhodes } 1915135446Strhodes myport = (in_port_t) val; 1916135446Strhodes } 1917135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, NULL, 1918135446Strhodes name, myport)); 1919135446Strhodes continue; 1920135446Strhodes } 1921135446Strhodes 1922135446Strhodes sa = *cfg_obj_assockaddr(alternate); 1923135446Strhodes if (isc_sockaddr_getport(&sa) == 0) 1924135446Strhodes isc_sockaddr_setport(&sa, port); 1925135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, &sa, 1926135446Strhodes NULL, 0)); 1927135446Strhodes } 1928135446Strhodes 1929135446Strhodes cleanup: 1930135446Strhodes return (result); 1931135446Strhodes} 1932135446Strhodes 1933135446Strhodesstatic isc_result_t 1934165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 1935165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 1936135446Strhodes{ 1937165071Sdougb const cfg_obj_t *portobj; 1938165071Sdougb const cfg_obj_t *faddresses; 1939165071Sdougb const cfg_listelt_t *element; 1940135446Strhodes dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 1941135446Strhodes isc_sockaddrlist_t addresses; 1942135446Strhodes isc_sockaddr_t *sa; 1943135446Strhodes isc_result_t result; 1944135446Strhodes in_port_t port; 1945135446Strhodes 1946135446Strhodes /* 1947135446Strhodes * Determine which port to send forwarded requests to. 1948135446Strhodes */ 1949135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 1950135446Strhodes port = ns_g_port; 1951135446Strhodes else 1952135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 1953135446Strhodes 1954135446Strhodes if (forwarders != NULL) { 1955135446Strhodes portobj = cfg_tuple_get(forwarders, "port"); 1956135446Strhodes if (cfg_obj_isuint32(portobj)) { 1957135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 1958135446Strhodes if (val > ISC_UINT16_MAX) { 1959135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1960135446Strhodes "port '%u' out of range", val); 1961135446Strhodes return (ISC_R_RANGE); 1962135446Strhodes } 1963135446Strhodes port = (in_port_t) val; 1964135446Strhodes } 1965135446Strhodes } 1966135446Strhodes 1967135446Strhodes faddresses = NULL; 1968135446Strhodes if (forwarders != NULL) 1969135446Strhodes faddresses = cfg_tuple_get(forwarders, "addresses"); 1970135446Strhodes 1971135446Strhodes ISC_LIST_INIT(addresses); 1972135446Strhodes 1973135446Strhodes for (element = cfg_list_first(faddresses); 1974135446Strhodes element != NULL; 1975135446Strhodes element = cfg_list_next(element)) 1976135446Strhodes { 1977165071Sdougb const cfg_obj_t *forwarder = cfg_listelt_value(element); 1978135446Strhodes sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 1979135446Strhodes if (sa == NULL) { 1980135446Strhodes result = ISC_R_NOMEMORY; 1981135446Strhodes goto cleanup; 1982135446Strhodes } 1983135446Strhodes *sa = *cfg_obj_assockaddr(forwarder); 1984135446Strhodes if (isc_sockaddr_getport(sa) == 0) 1985135446Strhodes isc_sockaddr_setport(sa, port); 1986135446Strhodes ISC_LINK_INIT(sa, link); 1987135446Strhodes ISC_LIST_APPEND(addresses, sa, link); 1988135446Strhodes } 1989135446Strhodes 1990135446Strhodes if (ISC_LIST_EMPTY(addresses)) { 1991135446Strhodes if (forwardtype != NULL) 1992135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 1993135446Strhodes "no forwarders seen; disabling " 1994135446Strhodes "forwarding"); 1995135446Strhodes fwdpolicy = dns_fwdpolicy_none; 1996135446Strhodes } else { 1997135446Strhodes if (forwardtype == NULL) 1998135446Strhodes fwdpolicy = dns_fwdpolicy_first; 1999135446Strhodes else { 2000165071Sdougb const char *forwardstr = cfg_obj_asstring(forwardtype); 2001135446Strhodes if (strcasecmp(forwardstr, "first") == 0) 2002135446Strhodes fwdpolicy = dns_fwdpolicy_first; 2003135446Strhodes else if (strcasecmp(forwardstr, "only") == 0) 2004135446Strhodes fwdpolicy = dns_fwdpolicy_only; 2005135446Strhodes else 2006135446Strhodes INSIST(0); 2007135446Strhodes } 2008135446Strhodes } 2009135446Strhodes 2010135446Strhodes result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 2011135446Strhodes fwdpolicy); 2012135446Strhodes if (result != ISC_R_SUCCESS) { 2013135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 2014135446Strhodes dns_name_format(origin, namebuf, sizeof(namebuf)); 2015135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 2016135446Strhodes "could not set up forwarding for domain '%s': %s", 2017135446Strhodes namebuf, isc_result_totext(result)); 2018135446Strhodes goto cleanup; 2019135446Strhodes } 2020135446Strhodes 2021135446Strhodes result = ISC_R_SUCCESS; 2022135446Strhodes 2023135446Strhodes cleanup: 2024135446Strhodes 2025135446Strhodes while (!ISC_LIST_EMPTY(addresses)) { 2026135446Strhodes sa = ISC_LIST_HEAD(addresses); 2027135446Strhodes ISC_LIST_UNLINK(addresses, sa, link); 2028135446Strhodes isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 2029135446Strhodes } 2030135446Strhodes 2031135446Strhodes return (result); 2032135446Strhodes} 2033135446Strhodes 2034135446Strhodes/* 2035135446Strhodes * Create a new view and add it to the list. 2036135446Strhodes * 2037135446Strhodes * If 'vconfig' is NULL, create the default view. 2038135446Strhodes * 2039135446Strhodes * The view created is attached to '*viewp'. 2040135446Strhodes */ 2041135446Strhodesstatic isc_result_t 2042165071Sdougbcreate_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 2043165071Sdougb dns_view_t **viewp) 2044165071Sdougb{ 2045135446Strhodes isc_result_t result; 2046135446Strhodes const char *viewname; 2047135446Strhodes dns_rdataclass_t viewclass; 2048135446Strhodes dns_view_t *view = NULL; 2049135446Strhodes 2050135446Strhodes if (vconfig != NULL) { 2051165071Sdougb const cfg_obj_t *classobj = NULL; 2052135446Strhodes 2053135446Strhodes viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 2054135446Strhodes classobj = cfg_tuple_get(vconfig, "class"); 2055135446Strhodes result = ns_config_getclass(classobj, dns_rdataclass_in, 2056135446Strhodes &viewclass); 2057135446Strhodes } else { 2058135446Strhodes viewname = "_default"; 2059135446Strhodes viewclass = dns_rdataclass_in; 2060135446Strhodes } 2061135446Strhodes result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 2062135446Strhodes if (result == ISC_R_SUCCESS) 2063135446Strhodes return (ISC_R_EXISTS); 2064135446Strhodes if (result != ISC_R_NOTFOUND) 2065135446Strhodes return (result); 2066135446Strhodes INSIST(view == NULL); 2067135446Strhodes 2068135446Strhodes result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 2069135446Strhodes if (result != ISC_R_SUCCESS) 2070135446Strhodes return (result); 2071135446Strhodes 2072135446Strhodes ISC_LIST_APPEND(*viewlist, view, link); 2073135446Strhodes dns_view_attach(view, viewp); 2074135446Strhodes return (ISC_R_SUCCESS); 2075135446Strhodes} 2076135446Strhodes 2077135446Strhodes/* 2078135446Strhodes * Configure or reconfigure a zone. 2079135446Strhodes */ 2080135446Strhodesstatic isc_result_t 2081165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 2082165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 2083170222Sdougb cfg_aclconfctx_t *aclconf) 2084135446Strhodes{ 2085135446Strhodes dns_view_t *pview = NULL; /* Production view */ 2086135446Strhodes dns_zone_t *zone = NULL; /* New or reused zone */ 2087135446Strhodes dns_zone_t *dupzone = NULL; 2088165071Sdougb const cfg_obj_t *options = NULL; 2089165071Sdougb const cfg_obj_t *zoptions = NULL; 2090165071Sdougb const cfg_obj_t *typeobj = NULL; 2091165071Sdougb const cfg_obj_t *forwarders = NULL; 2092165071Sdougb const cfg_obj_t *forwardtype = NULL; 2093165071Sdougb const cfg_obj_t *only = NULL; 2094135446Strhodes isc_result_t result; 2095135446Strhodes isc_result_t tresult; 2096135446Strhodes isc_buffer_t buffer; 2097135446Strhodes dns_fixedname_t fixorigin; 2098135446Strhodes dns_name_t *origin; 2099135446Strhodes const char *zname; 2100135446Strhodes dns_rdataclass_t zclass; 2101135446Strhodes const char *ztypestr; 2102135446Strhodes 2103135446Strhodes options = NULL; 2104135446Strhodes (void)cfg_map_get(config, "options", &options); 2105135446Strhodes 2106135446Strhodes zoptions = cfg_tuple_get(zconfig, "options"); 2107135446Strhodes 2108135446Strhodes /* 2109135446Strhodes * Get the zone origin as a dns_name_t. 2110135446Strhodes */ 2111135446Strhodes zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 2112135446Strhodes isc_buffer_init(&buffer, zname, strlen(zname)); 2113135446Strhodes isc_buffer_add(&buffer, strlen(zname)); 2114135446Strhodes dns_fixedname_init(&fixorigin); 2115135446Strhodes CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 2116135446Strhodes &buffer, dns_rootname, ISC_FALSE, NULL)); 2117135446Strhodes origin = dns_fixedname_name(&fixorigin); 2118135446Strhodes 2119135446Strhodes CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 2120135446Strhodes view->rdclass, &zclass)); 2121135446Strhodes if (zclass != view->rdclass) { 2122135446Strhodes const char *vname = NULL; 2123135446Strhodes if (vconfig != NULL) 2124135446Strhodes vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 2125135446Strhodes "name")); 2126135446Strhodes else 2127135446Strhodes vname = "<default view>"; 2128135446Strhodes 2129135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2130135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2131135446Strhodes "zone '%s': wrong class for view '%s'", 2132135446Strhodes zname, vname); 2133135446Strhodes result = ISC_R_FAILURE; 2134135446Strhodes goto cleanup; 2135135446Strhodes } 2136135446Strhodes 2137135446Strhodes (void)cfg_map_get(zoptions, "type", &typeobj); 2138135446Strhodes if (typeobj == NULL) { 2139135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 2140135446Strhodes "zone '%s' 'type' not specified", zname); 2141135446Strhodes return (ISC_R_FAILURE); 2142135446Strhodes } 2143135446Strhodes ztypestr = cfg_obj_asstring(typeobj); 2144135446Strhodes 2145135446Strhodes /* 2146135446Strhodes * "hints zones" aren't zones. If we've got one, 2147135446Strhodes * configure it and return. 2148135446Strhodes */ 2149135446Strhodes if (strcasecmp(ztypestr, "hint") == 0) { 2150165071Sdougb const cfg_obj_t *fileobj = NULL; 2151135446Strhodes if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 2152135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2153135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2154135446Strhodes "zone '%s': 'file' not specified", 2155135446Strhodes zname); 2156135446Strhodes result = ISC_R_FAILURE; 2157135446Strhodes goto cleanup; 2158135446Strhodes } 2159135446Strhodes if (dns_name_equal(origin, dns_rootname)) { 2160165071Sdougb const char *hintsfile = cfg_obj_asstring(fileobj); 2161135446Strhodes 2162135446Strhodes result = configure_hints(view, hintsfile); 2163135446Strhodes if (result != ISC_R_SUCCESS) { 2164135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2165135446Strhodes NS_LOGMODULE_SERVER, 2166135446Strhodes ISC_LOG_ERROR, 2167135446Strhodes "could not configure root hints " 2168135446Strhodes "from '%s': %s", hintsfile, 2169135446Strhodes isc_result_totext(result)); 2170135446Strhodes goto cleanup; 2171135446Strhodes } 2172135446Strhodes /* 2173135446Strhodes * Hint zones may also refer to delegation only points. 2174135446Strhodes */ 2175135446Strhodes only = NULL; 2176135446Strhodes tresult = cfg_map_get(zoptions, "delegation-only", 2177135446Strhodes &only); 2178135446Strhodes if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 2179135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 2180135446Strhodes } else { 2181135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2182135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2183135446Strhodes "ignoring non-root hint zone '%s'", 2184135446Strhodes zname); 2185135446Strhodes result = ISC_R_SUCCESS; 2186135446Strhodes } 2187135446Strhodes /* Skip ordinary zone processing. */ 2188135446Strhodes goto cleanup; 2189135446Strhodes } 2190135446Strhodes 2191135446Strhodes /* 2192135446Strhodes * "forward zones" aren't zones either. Translate this syntax into 2193135446Strhodes * the appropriate selective forwarding configuration and return. 2194135446Strhodes */ 2195135446Strhodes if (strcasecmp(ztypestr, "forward") == 0) { 2196135446Strhodes forwardtype = NULL; 2197135446Strhodes forwarders = NULL; 2198135446Strhodes 2199135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 2200135446Strhodes (void)cfg_map_get(zoptions, "forwarders", &forwarders); 2201135446Strhodes result = configure_forward(config, view, origin, forwarders, 2202135446Strhodes forwardtype); 2203135446Strhodes goto cleanup; 2204135446Strhodes } 2205135446Strhodes 2206135446Strhodes /* 2207135446Strhodes * "delegation-only zones" aren't zones either. 2208135446Strhodes */ 2209135446Strhodes if (strcasecmp(ztypestr, "delegation-only") == 0) { 2210135446Strhodes result = dns_view_adddelegationonly(view, origin); 2211135446Strhodes goto cleanup; 2212135446Strhodes } 2213135446Strhodes 2214135446Strhodes /* 2215135446Strhodes * Check for duplicates in the new zone table. 2216135446Strhodes */ 2217135446Strhodes result = dns_view_findzone(view, origin, &dupzone); 2218135446Strhodes if (result == ISC_R_SUCCESS) { 2219135446Strhodes /* 2220135446Strhodes * We already have this zone! 2221135446Strhodes */ 2222135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 2223135446Strhodes "zone '%s' already exists", zname); 2224135446Strhodes dns_zone_detach(&dupzone); 2225135446Strhodes result = ISC_R_EXISTS; 2226135446Strhodes goto cleanup; 2227135446Strhodes } 2228135446Strhodes INSIST(dupzone == NULL); 2229135446Strhodes 2230135446Strhodes /* 2231135446Strhodes * See if we can reuse an existing zone. This is 2232135446Strhodes * only possible if all of these are true: 2233135446Strhodes * - The zone's view exists 2234135446Strhodes * - A zone with the right name exists in the view 2235135446Strhodes * - The zone is compatible with the config 2236135446Strhodes * options (e.g., an existing master zone cannot 2237135446Strhodes * be reused if the options specify a slave zone) 2238135446Strhodes */ 2239135446Strhodes result = dns_viewlist_find(&ns_g_server->viewlist, 2240135446Strhodes view->name, view->rdclass, 2241135446Strhodes &pview); 2242135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2243135446Strhodes goto cleanup; 2244135446Strhodes if (pview != NULL) 2245135446Strhodes result = dns_view_findzone(pview, origin, &zone); 2246135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2247135446Strhodes goto cleanup; 2248170222Sdougb if (zone != NULL && !ns_zone_reusable(zone, zconfig)) 2249170222Sdougb dns_zone_detach(&zone); 2250135446Strhodes 2251135446Strhodes if (zone != NULL) { 2252135446Strhodes /* 2253135446Strhodes * We found a reusable zone. Make it use the 2254135446Strhodes * new view. 2255135446Strhodes */ 2256135446Strhodes dns_zone_setview(zone, view); 2257170222Sdougb if (view->acache != NULL) 2258170222Sdougb dns_zone_setacache(zone, view->acache); 2259135446Strhodes } else { 2260135446Strhodes /* 2261135446Strhodes * We cannot reuse an existing zone, we have 2262135446Strhodes * to create a new one. 2263135446Strhodes */ 2264135446Strhodes CHECK(dns_zone_create(&zone, mctx)); 2265135446Strhodes CHECK(dns_zone_setorigin(zone, origin)); 2266135446Strhodes dns_zone_setview(zone, view); 2267170222Sdougb if (view->acache != NULL) 2268170222Sdougb dns_zone_setacache(zone, view->acache); 2269135446Strhodes CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 2270135446Strhodes } 2271135446Strhodes 2272135446Strhodes /* 2273135446Strhodes * If the zone contains a 'forwarders' statement, configure 2274135446Strhodes * selective forwarding. 2275135446Strhodes */ 2276135446Strhodes forwarders = NULL; 2277135446Strhodes if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 2278135446Strhodes { 2279135446Strhodes forwardtype = NULL; 2280135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 2281135446Strhodes CHECK(configure_forward(config, view, origin, forwarders, 2282135446Strhodes forwardtype)); 2283135446Strhodes } 2284135446Strhodes 2285135446Strhodes /* 2286135446Strhodes * Stub and forward zones may also refer to delegation only points. 2287135446Strhodes */ 2288135446Strhodes only = NULL; 2289135446Strhodes if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 2290135446Strhodes { 2291135446Strhodes if (cfg_obj_asboolean(only)) 2292135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 2293135446Strhodes } 2294135446Strhodes 2295135446Strhodes /* 2296135446Strhodes * Configure the zone. 2297135446Strhodes */ 2298135446Strhodes CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); 2299135446Strhodes 2300135446Strhodes /* 2301135446Strhodes * Add the zone to its view in the new view list. 2302135446Strhodes */ 2303135446Strhodes CHECK(dns_view_addzone(view, zone)); 2304135446Strhodes 2305135446Strhodes cleanup: 2306135446Strhodes if (zone != NULL) 2307135446Strhodes dns_zone_detach(&zone); 2308135446Strhodes if (pview != NULL) 2309135446Strhodes dns_view_detach(&pview); 2310135446Strhodes 2311135446Strhodes return (result); 2312135446Strhodes} 2313135446Strhodes 2314135446Strhodes/* 2315135446Strhodes * Configure a single server quota. 2316135446Strhodes */ 2317135446Strhodesstatic void 2318165071Sdougbconfigure_server_quota(const cfg_obj_t **maps, const char *name, 2319165071Sdougb isc_quota_t *quota) 2320135446Strhodes{ 2321165071Sdougb const cfg_obj_t *obj = NULL; 2322135446Strhodes isc_result_t result; 2323135446Strhodes 2324135446Strhodes result = ns_config_get(maps, name, &obj); 2325135446Strhodes INSIST(result == ISC_R_SUCCESS); 2326153816Sdougb isc_quota_max(quota, cfg_obj_asuint32(obj)); 2327135446Strhodes} 2328135446Strhodes 2329135446Strhodes/* 2330135446Strhodes * This function is called as soon as the 'directory' statement has been 2331135446Strhodes * parsed. This can be extended to support other options if necessary. 2332135446Strhodes */ 2333135446Strhodesstatic isc_result_t 2334165071Sdougbdirectory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 2335135446Strhodes isc_result_t result; 2336165071Sdougb const char *directory; 2337135446Strhodes 2338135446Strhodes REQUIRE(strcasecmp("directory", clausename) == 0); 2339135446Strhodes 2340135446Strhodes UNUSED(arg); 2341135446Strhodes UNUSED(clausename); 2342135446Strhodes 2343135446Strhodes /* 2344135446Strhodes * Change directory. 2345135446Strhodes */ 2346135446Strhodes directory = cfg_obj_asstring(obj); 2347135446Strhodes 2348135446Strhodes if (! isc_file_ischdiridempotent(directory)) 2349135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2350135446Strhodes "option 'directory' contains relative path '%s'", 2351135446Strhodes directory); 2352135446Strhodes 2353135446Strhodes result = isc_dir_chdir(directory); 2354135446Strhodes if (result != ISC_R_SUCCESS) { 2355135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 2356135446Strhodes "change directory to '%s' failed: %s", 2357135446Strhodes directory, isc_result_totext(result)); 2358135446Strhodes return (result); 2359135446Strhodes } 2360135446Strhodes 2361135446Strhodes return (ISC_R_SUCCESS); 2362135446Strhodes} 2363135446Strhodes 2364135446Strhodesstatic void 2365135446Strhodesscan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 2366135446Strhodes isc_boolean_t match_mapped = server->aclenv.match_mapped; 2367135446Strhodes 2368135446Strhodes ns_interfacemgr_scan(server->interfacemgr, verbose); 2369135446Strhodes /* 2370135446Strhodes * Update the "localhost" and "localnets" ACLs to match the 2371135446Strhodes * current set of network interfaces. 2372135446Strhodes */ 2373135446Strhodes dns_aclenv_copy(&server->aclenv, 2374135446Strhodes ns_interfacemgr_getaclenv(server->interfacemgr)); 2375135446Strhodes 2376135446Strhodes server->aclenv.match_mapped = match_mapped; 2377135446Strhodes} 2378135446Strhodes 2379135446Strhodesstatic isc_result_t 2380180477Sdougbadd_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, 2381180477Sdougb isc_boolean_t wcardport_ok) 2382180477Sdougb{ 2383135446Strhodes ns_listenelt_t *lelt = NULL; 2384135446Strhodes dns_acl_t *src_acl = NULL; 2385135446Strhodes dns_aclelement_t aelt; 2386135446Strhodes isc_result_t result; 2387135446Strhodes isc_sockaddr_t any_sa6; 2388135446Strhodes 2389135446Strhodes REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 2390135446Strhodes 2391135446Strhodes isc_sockaddr_any6(&any_sa6); 2392180477Sdougb if (!isc_sockaddr_equal(&any_sa6, addr) && 2393180477Sdougb (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { 2394135446Strhodes aelt.type = dns_aclelementtype_ipprefix; 2395135446Strhodes aelt.negative = ISC_FALSE; 2396135446Strhodes aelt.u.ip_prefix.prefixlen = 128; 2397135446Strhodes isc_netaddr_fromin6(&aelt.u.ip_prefix.address, 2398135446Strhodes &addr->type.sin6.sin6_addr); 2399135446Strhodes 2400135446Strhodes result = dns_acl_create(mctx, 1, &src_acl); 2401135446Strhodes if (result != ISC_R_SUCCESS) 2402135446Strhodes return (result); 2403135446Strhodes result = dns_acl_appendelement(src_acl, &aelt); 2404135446Strhodes if (result != ISC_R_SUCCESS) 2405135446Strhodes goto clean; 2406135446Strhodes 2407135446Strhodes result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 2408135446Strhodes src_acl, &lelt); 2409135446Strhodes if (result != ISC_R_SUCCESS) 2410135446Strhodes goto clean; 2411135446Strhodes ISC_LIST_APPEND(list->elts, lelt, link); 2412135446Strhodes } 2413135446Strhodes 2414135446Strhodes return (ISC_R_SUCCESS); 2415135446Strhodes 2416135446Strhodes clean: 2417135446Strhodes INSIST(lelt == NULL); 2418165071Sdougb dns_acl_detach(&src_acl); 2419135446Strhodes 2420135446Strhodes return (result); 2421135446Strhodes} 2422135446Strhodes 2423135446Strhodes/* 2424135446Strhodes * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 2425135446Strhodes * to update the listening interfaces accordingly. 2426135446Strhodes * We currently only consider IPv6, because this only affects IPv6 wildcard 2427135446Strhodes * sockets. 2428135446Strhodes */ 2429135446Strhodesstatic void 2430135446Strhodesadjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 2431135446Strhodes isc_result_t result; 2432135446Strhodes ns_listenlist_t *list = NULL; 2433135446Strhodes dns_view_t *view; 2434135446Strhodes dns_zone_t *zone, *next; 2435135446Strhodes isc_sockaddr_t addr, *addrp; 2436135446Strhodes 2437135446Strhodes result = ns_listenlist_create(mctx, &list); 2438135446Strhodes if (result != ISC_R_SUCCESS) 2439135446Strhodes return; 2440135446Strhodes 2441135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 2442135446Strhodes view != NULL; 2443135446Strhodes view = ISC_LIST_NEXT(view, link)) { 2444135446Strhodes dns_dispatch_t *dispatch6; 2445135446Strhodes 2446135446Strhodes dispatch6 = dns_resolver_dispatchv6(view->resolver); 2447143731Sdougb if (dispatch6 == NULL) 2448143731Sdougb continue; 2449135446Strhodes result = dns_dispatch_getlocaladdress(dispatch6, &addr); 2450135446Strhodes if (result != ISC_R_SUCCESS) 2451135446Strhodes goto fail; 2452180477Sdougb 2453180477Sdougb /* 2454180477Sdougb * We always add non-wildcard address regardless of whether 2455180477Sdougb * the port is 'any' (the fourth arg is TRUE): if the port is 2456180477Sdougb * specific, we need to add it since it may conflict with a 2457180477Sdougb * listening interface; if it's zero, we'll dynamically open 2458180477Sdougb * query ports, and some of them may override an existing 2459180477Sdougb * wildcard IPv6 port. 2460180477Sdougb */ 2461180477Sdougb result = add_listenelt(mctx, list, &addr, ISC_TRUE); 2462135446Strhodes if (result != ISC_R_SUCCESS) 2463135446Strhodes goto fail; 2464135446Strhodes } 2465135446Strhodes 2466135446Strhodes zone = NULL; 2467135446Strhodes for (result = dns_zone_first(server->zonemgr, &zone); 2468135446Strhodes result == ISC_R_SUCCESS; 2469135446Strhodes next = NULL, result = dns_zone_next(zone, &next), zone = next) { 2470135446Strhodes dns_view_t *zoneview; 2471135446Strhodes 2472135446Strhodes /* 2473135446Strhodes * At this point the zone list may contain a stale zone 2474135446Strhodes * just removed from the configuration. To see the validity, 2475135446Strhodes * check if the corresponding view is in our current view list. 2476153816Sdougb * There may also be old zones that are still in the process 2477153816Sdougb * of shutting down and have detached from their old view 2478153816Sdougb * (zoneview == NULL). 2479135446Strhodes */ 2480135446Strhodes zoneview = dns_zone_getview(zone); 2481153816Sdougb if (zoneview == NULL) 2482153816Sdougb continue; 2483135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 2484135446Strhodes view != NULL && view != zoneview; 2485135446Strhodes view = ISC_LIST_NEXT(view, link)) 2486135446Strhodes ; 2487135446Strhodes if (view == NULL) 2488135446Strhodes continue; 2489135446Strhodes 2490135446Strhodes addrp = dns_zone_getnotifysrc6(zone); 2491180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 2492135446Strhodes if (result != ISC_R_SUCCESS) 2493135446Strhodes goto fail; 2494135446Strhodes 2495135446Strhodes addrp = dns_zone_getxfrsource6(zone); 2496180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 2497135446Strhodes if (result != ISC_R_SUCCESS) 2498135446Strhodes goto fail; 2499135446Strhodes } 2500135446Strhodes 2501135446Strhodes ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 2502135446Strhodes 2503135446Strhodes clean: 2504135446Strhodes ns_listenlist_detach(&list); 2505135446Strhodes return; 2506135446Strhodes 2507135446Strhodes fail: 2508135446Strhodes /* 2509135446Strhodes * Even when we failed the procedure, most of other interfaces 2510135446Strhodes * should work correctly. We therefore just warn it. 2511135446Strhodes */ 2512135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2513135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2514135446Strhodes "could not adjust the listen-on list; " 2515135446Strhodes "some interfaces may not work"); 2516135446Strhodes goto clean; 2517135446Strhodes} 2518135446Strhodes 2519135446Strhodes/* 2520135446Strhodes * This event callback is invoked to do periodic network 2521135446Strhodes * interface scanning. 2522135446Strhodes */ 2523135446Strhodesstatic void 2524135446Strhodesinterface_timer_tick(isc_task_t *task, isc_event_t *event) { 2525135446Strhodes isc_result_t result; 2526135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 2527135446Strhodes INSIST(task == server->task); 2528135446Strhodes UNUSED(task); 2529135446Strhodes isc_event_free(&event); 2530135446Strhodes /* 2531135446Strhodes * XXX should scan interfaces unlocked and get exclusive access 2532135446Strhodes * only to replace ACLs. 2533135446Strhodes */ 2534135446Strhodes result = isc_task_beginexclusive(server->task); 2535135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 2536135446Strhodes scan_interfaces(server, ISC_FALSE); 2537135446Strhodes isc_task_endexclusive(server->task); 2538135446Strhodes} 2539135446Strhodes 2540135446Strhodesstatic void 2541135446Strhodesheartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 2542135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 2543135446Strhodes dns_view_t *view; 2544135446Strhodes 2545135446Strhodes UNUSED(task); 2546135446Strhodes isc_event_free(&event); 2547135446Strhodes view = ISC_LIST_HEAD(server->viewlist); 2548135446Strhodes while (view != NULL) { 2549135446Strhodes dns_view_dialup(view); 2550135446Strhodes view = ISC_LIST_NEXT(view, link); 2551135446Strhodes } 2552135446Strhodes} 2553135446Strhodes 2554170222Sdougbstatic void 2555170222Sdougbpps_timer_tick(isc_task_t *task, isc_event_t *event) { 2556170222Sdougb static unsigned int oldrequests = 0; 2557170222Sdougb unsigned int requests = ns_client_requests; 2558170222Sdougb 2559170222Sdougb UNUSED(task); 2560170222Sdougb isc_event_free(&event); 2561170222Sdougb 2562170222Sdougb /* 2563170222Sdougb * Don't worry about wrapping as the overflow result will be right. 2564170222Sdougb */ 2565170222Sdougb dns_pps = (requests - oldrequests) / 1200; 2566170222Sdougb oldrequests = requests; 2567170222Sdougb} 2568170222Sdougb 2569135446Strhodes/* 2570135446Strhodes * Replace the current value of '*field', a dynamically allocated 2571135446Strhodes * string or NULL, with a dynamically allocated copy of the 2572135446Strhodes * null-terminated string pointed to by 'value', or NULL. 2573135446Strhodes */ 2574135446Strhodesstatic isc_result_t 2575135446Strhodessetstring(ns_server_t *server, char **field, const char *value) { 2576135446Strhodes char *copy; 2577135446Strhodes 2578135446Strhodes if (value != NULL) { 2579135446Strhodes copy = isc_mem_strdup(server->mctx, value); 2580135446Strhodes if (copy == NULL) 2581135446Strhodes return (ISC_R_NOMEMORY); 2582135446Strhodes } else { 2583135446Strhodes copy = NULL; 2584135446Strhodes } 2585135446Strhodes 2586135446Strhodes if (*field != NULL) 2587135446Strhodes isc_mem_free(server->mctx, *field); 2588135446Strhodes 2589135446Strhodes *field = copy; 2590135446Strhodes return (ISC_R_SUCCESS); 2591135446Strhodes} 2592135446Strhodes 2593135446Strhodes/* 2594135446Strhodes * Replace the current value of '*field', a dynamically allocated 2595135446Strhodes * string or NULL, with another dynamically allocated string 2596135446Strhodes * or NULL if whether 'obj' is a string or void value, respectively. 2597135446Strhodes */ 2598135446Strhodesstatic isc_result_t 2599165071Sdougbsetoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 2600135446Strhodes if (cfg_obj_isvoid(obj)) 2601135446Strhodes return (setstring(server, field, NULL)); 2602135446Strhodes else 2603135446Strhodes return (setstring(server, field, cfg_obj_asstring(obj))); 2604135446Strhodes} 2605135446Strhodes 2606135446Strhodesstatic void 2607165071Sdougbset_limit(const cfg_obj_t **maps, const char *configname, 2608165071Sdougb const char *description, isc_resource_t resourceid, 2609165071Sdougb isc_resourcevalue_t defaultvalue) 2610135446Strhodes{ 2611165071Sdougb const cfg_obj_t *obj = NULL; 2612165071Sdougb const char *resource; 2613135446Strhodes isc_resourcevalue_t value; 2614135446Strhodes isc_result_t result; 2615135446Strhodes 2616135446Strhodes if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 2617135446Strhodes return; 2618135446Strhodes 2619135446Strhodes if (cfg_obj_isstring(obj)) { 2620135446Strhodes resource = cfg_obj_asstring(obj); 2621135446Strhodes if (strcasecmp(resource, "unlimited") == 0) 2622135446Strhodes value = ISC_RESOURCE_UNLIMITED; 2623135446Strhodes else { 2624135446Strhodes INSIST(strcasecmp(resource, "default") == 0); 2625135446Strhodes value = defaultvalue; 2626135446Strhodes } 2627135446Strhodes } else 2628135446Strhodes value = cfg_obj_asuint64(obj); 2629135446Strhodes 2630135446Strhodes result = isc_resource_setlimit(resourceid, value); 2631135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2632135446Strhodes result == ISC_R_SUCCESS ? 2633135446Strhodes ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 2634135446Strhodes "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s", 2635135446Strhodes description, value, isc_result_totext(result)); 2636135446Strhodes} 2637135446Strhodes 2638135446Strhodes#define SETLIMIT(cfgvar, resource, description) \ 2639135446Strhodes set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 2640135446Strhodes ns_g_init ## resource) 2641135446Strhodes 2642135446Strhodesstatic void 2643165071Sdougbset_limits(const cfg_obj_t **maps) { 2644135446Strhodes SETLIMIT("stacksize", stacksize, "stack size"); 2645135446Strhodes SETLIMIT("datasize", datasize, "data size"); 2646135446Strhodes SETLIMIT("coresize", coresize, "core size"); 2647135446Strhodes SETLIMIT("files", openfiles, "open files"); 2648135446Strhodes} 2649135446Strhodes 2650135446Strhodesstatic isc_result_t 2651135446Strhodesportlist_fromconf(dns_portlist_t *portlist, unsigned int family, 2652165071Sdougb const cfg_obj_t *ports) 2653135446Strhodes{ 2654165071Sdougb const cfg_listelt_t *element; 2655135446Strhodes isc_result_t result = ISC_R_SUCCESS; 2656135446Strhodes 2657135446Strhodes for (element = cfg_list_first(ports); 2658135446Strhodes element != NULL; 2659135446Strhodes element = cfg_list_next(element)) { 2660165071Sdougb const cfg_obj_t *obj = cfg_listelt_value(element); 2661135446Strhodes in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 2662135446Strhodes 2663135446Strhodes result = dns_portlist_add(portlist, family, port); 2664135446Strhodes if (result != ISC_R_SUCCESS) 2665135446Strhodes break; 2666135446Strhodes } 2667135446Strhodes return (result); 2668135446Strhodes} 2669135446Strhodes 2670135446Strhodesstatic isc_result_t 2671170222Sdougbremoved(dns_zone_t *zone, void *uap) { 2672170222Sdougb const char *type; 2673170222Sdougb 2674170222Sdougb if (dns_zone_getview(zone) != uap) 2675170222Sdougb return (ISC_R_SUCCESS); 2676170222Sdougb 2677170222Sdougb switch (dns_zone_gettype(zone)) { 2678170222Sdougb case dns_zone_master: 2679170222Sdougb type = "master"; 2680170222Sdougb break; 2681170222Sdougb case dns_zone_slave: 2682170222Sdougb type = "slave"; 2683170222Sdougb break; 2684170222Sdougb case dns_zone_stub: 2685170222Sdougb type = "stub"; 2686170222Sdougb break; 2687170222Sdougb default: 2688170222Sdougb type = "other"; 2689170222Sdougb break; 2690170222Sdougb } 2691170222Sdougb dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); 2692170222Sdougb return (ISC_R_SUCCESS); 2693170222Sdougb} 2694170222Sdougb 2695170222Sdougbstatic isc_result_t 2696135446Strhodesload_configuration(const char *filename, ns_server_t *server, 2697135446Strhodes isc_boolean_t first_time) 2698135446Strhodes{ 2699182645Sdougb cfg_aclconfctx_t aclconfctx; 2700182645Sdougb cfg_obj_t *config; 2701135446Strhodes cfg_parser_t *parser = NULL; 2702182645Sdougb const cfg_listelt_t *element; 2703182645Sdougb const cfg_obj_t *builtin_views; 2704182645Sdougb const cfg_obj_t *maps[3]; 2705182645Sdougb const cfg_obj_t *obj; 2706165071Sdougb const cfg_obj_t *options; 2707182645Sdougb const cfg_obj_t *v4ports, *v6ports; 2708165071Sdougb const cfg_obj_t *views; 2709135446Strhodes dns_view_t *view = NULL; 2710135446Strhodes dns_view_t *view_next; 2711182645Sdougb dns_viewlist_t tmpviewlist; 2712135446Strhodes dns_viewlist_t viewlist; 2713182645Sdougb in_port_t listen_port; 2714182645Sdougb int i; 2715182645Sdougb isc_interval_t interval; 2716182645Sdougb isc_resourcevalue_t files; 2717182645Sdougb isc_result_t result; 2718182645Sdougb isc_uint32_t heartbeat_interval; 2719135446Strhodes isc_uint32_t interface_interval; 2720182645Sdougb isc_uint32_t reserved; 2721135446Strhodes isc_uint32_t udpsize; 2722135446Strhodes 2723170222Sdougb cfg_aclconfctx_init(&aclconfctx); 2724135446Strhodes ISC_LIST_INIT(viewlist); 2725135446Strhodes 2726135446Strhodes /* Ensure exclusive access to configuration data. */ 2727135446Strhodes result = isc_task_beginexclusive(server->task); 2728135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 2729135446Strhodes 2730135446Strhodes /* 2731135446Strhodes * Parse the global default pseudo-config file. 2732135446Strhodes */ 2733135446Strhodes if (first_time) { 2734135446Strhodes CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 2735135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 2736135446Strhodes &ns_g_defaults) == 2737135446Strhodes ISC_R_SUCCESS); 2738135446Strhodes } 2739135446Strhodes 2740135446Strhodes /* 2741135446Strhodes * Parse the configuration file using the new config code. 2742135446Strhodes */ 2743135446Strhodes result = ISC_R_FAILURE; 2744135446Strhodes config = NULL; 2745135446Strhodes 2746135446Strhodes /* 2747135446Strhodes * Unless this is lwresd with the -C option, parse the config file. 2748135446Strhodes */ 2749135446Strhodes if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 2750135446Strhodes isc_log_write(ns_g_lctx, 2751135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2752135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 2753135446Strhodes filename); 2754135446Strhodes CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2755135446Strhodes cfg_parser_setcallback(parser, directory_callback, NULL); 2756135446Strhodes result = cfg_parse_file(parser, filename, &cfg_type_namedconf, 2757135446Strhodes &config); 2758135446Strhodes } 2759135446Strhodes 2760135446Strhodes /* 2761135446Strhodes * If this is lwresd with the -C option, or lwresd with no -C or -c 2762135446Strhodes * option where the above parsing failed, parse resolv.conf. 2763135446Strhodes */ 2764135446Strhodes if (ns_g_lwresdonly && 2765135446Strhodes (lwresd_g_useresolvconf || 2766135446Strhodes (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 2767135446Strhodes { 2768135446Strhodes isc_log_write(ns_g_lctx, 2769135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2770135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 2771135446Strhodes lwresd_g_resolvconffile); 2772135446Strhodes if (parser != NULL) 2773135446Strhodes cfg_parser_destroy(&parser); 2774135446Strhodes CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2775135446Strhodes result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser, 2776135446Strhodes &config); 2777135446Strhodes } 2778135446Strhodes CHECK(result); 2779135446Strhodes 2780135446Strhodes /* 2781135446Strhodes * Check the validity of the configuration. 2782135446Strhodes */ 2783135446Strhodes CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 2784135446Strhodes 2785135446Strhodes /* 2786135446Strhodes * Fill in the maps array, used for resolving defaults. 2787135446Strhodes */ 2788135446Strhodes i = 0; 2789135446Strhodes options = NULL; 2790135446Strhodes result = cfg_map_get(config, "options", &options); 2791135446Strhodes if (result == ISC_R_SUCCESS) 2792135446Strhodes maps[i++] = options; 2793135446Strhodes maps[i++] = ns_g_defaults; 2794135446Strhodes maps[i++] = NULL; 2795135446Strhodes 2796135446Strhodes /* 2797135446Strhodes * Set process limits, which (usually) needs to be done as root. 2798135446Strhodes */ 2799135446Strhodes set_limits(maps); 2800135446Strhodes 2801135446Strhodes /* 2802182645Sdougb * Sanity check on "files" limit. 2803182645Sdougb */ 2804182645Sdougb result = isc_resource_curlimit(isc_resource_openfiles, &files); 2805182645Sdougb if (result == ISC_R_SUCCESS && files < FD_SETSIZE) { 2806182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2807182645Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2808182645Sdougb "the 'files' limit (%" ISC_PRINT_QUADFORMAT "u) " 2809182645Sdougb "is less than FD_SETSIZE (%d), increase " 2810182645Sdougb "'files' in named.conf or recompile with a " 2811182645Sdougb "smaller FD_SETSIZE.", files, FD_SETSIZE); 2812182645Sdougb if (files > FD_SETSIZE) 2813182645Sdougb files = FD_SETSIZE; 2814182645Sdougb } else 2815182645Sdougb files = FD_SETSIZE; 2816182645Sdougb 2817182645Sdougb /* 2818182645Sdougb * Set the number of socket reserved for TCP, stdio etc. 2819182645Sdougb */ 2820182645Sdougb obj = NULL; 2821182645Sdougb result = ns_config_get(maps, "reserved-sockets", &obj); 2822182645Sdougb INSIST(result == ISC_R_SUCCESS); 2823182645Sdougb reserved = cfg_obj_asuint32(obj); 2824182645Sdougb if (files < 128U) /* Prevent underflow. */ 2825182645Sdougb reserved = 0; 2826182645Sdougb else if (reserved > files - 128U) /* Mimimum UDP space. */ 2827182645Sdougb reserved = files - 128; 2828182645Sdougb if (reserved < 128U) /* Mimimum TCP/stdio space. */ 2829182645Sdougb reserved = 128; 2830182645Sdougb if (reserved + 128U > files) { 2831182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2832182645Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2833182645Sdougb "less than 128 UDP sockets available after " 2834182645Sdougb "applying 'reserved-sockets' and 'files'"); 2835182645Sdougb } 2836182645Sdougb isc__socketmgr_setreserved(ns_g_socketmgr, reserved); 2837182645Sdougb 2838182645Sdougb /* 2839135446Strhodes * Configure various server options. 2840135446Strhodes */ 2841135446Strhodes configure_server_quota(maps, "transfers-out", &server->xfroutquota); 2842135446Strhodes configure_server_quota(maps, "tcp-clients", &server->tcpquota); 2843135446Strhodes configure_server_quota(maps, "recursive-clients", 2844135446Strhodes &server->recursionquota); 2845153816Sdougb if (server->recursionquota.max > 1000) 2846153816Sdougb isc_quota_soft(&server->recursionquota, 2847153816Sdougb server->recursionquota.max - 100); 2848153816Sdougb else 2849153816Sdougb isc_quota_soft(&server->recursionquota, 0); 2850135446Strhodes 2851135446Strhodes CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx, 2852135446Strhodes ns_g_mctx, &server->blackholeacl)); 2853135446Strhodes if (server->blackholeacl != NULL) 2854135446Strhodes dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 2855135446Strhodes server->blackholeacl); 2856135446Strhodes 2857135446Strhodes obj = NULL; 2858135446Strhodes result = ns_config_get(maps, "match-mapped-addresses", &obj); 2859135446Strhodes INSIST(result == ISC_R_SUCCESS); 2860135446Strhodes server->aclenv.match_mapped = cfg_obj_asboolean(obj); 2861135446Strhodes 2862135446Strhodes v4ports = NULL; 2863135446Strhodes v6ports = NULL; 2864135446Strhodes (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports); 2865135446Strhodes (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports); 2866135446Strhodes if (v4ports != NULL || v6ports != NULL) { 2867135446Strhodes dns_portlist_t *portlist = NULL; 2868135446Strhodes result = dns_portlist_create(ns_g_mctx, &portlist); 2869135446Strhodes if (result == ISC_R_SUCCESS && v4ports != NULL) 2870135446Strhodes result = portlist_fromconf(portlist, AF_INET, v4ports); 2871135446Strhodes if (result == ISC_R_SUCCESS && v6ports != NULL) 2872135446Strhodes portlist_fromconf(portlist, AF_INET6, v6ports); 2873135446Strhodes if (result == ISC_R_SUCCESS) 2874135446Strhodes dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist); 2875135446Strhodes if (portlist != NULL) 2876135446Strhodes dns_portlist_detach(&portlist); 2877135446Strhodes CHECK(result); 2878135446Strhodes } else 2879135446Strhodes dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL); 2880135446Strhodes 2881135446Strhodes /* 2882135446Strhodes * Set the EDNS UDP size when we don't match a view. 2883135446Strhodes */ 2884135446Strhodes obj = NULL; 2885135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 2886135446Strhodes INSIST(result == ISC_R_SUCCESS); 2887135446Strhodes udpsize = cfg_obj_asuint32(obj); 2888135446Strhodes if (udpsize < 512) 2889135446Strhodes udpsize = 512; 2890135446Strhodes if (udpsize > 4096) 2891135446Strhodes udpsize = 4096; 2892135446Strhodes ns_g_udpsize = (isc_uint16_t)udpsize; 2893135446Strhodes 2894135446Strhodes /* 2895135446Strhodes * Configure the zone manager. 2896135446Strhodes */ 2897135446Strhodes obj = NULL; 2898135446Strhodes result = ns_config_get(maps, "transfers-in", &obj); 2899135446Strhodes INSIST(result == ISC_R_SUCCESS); 2900135446Strhodes dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 2901135446Strhodes 2902135446Strhodes obj = NULL; 2903135446Strhodes result = ns_config_get(maps, "transfers-per-ns", &obj); 2904135446Strhodes INSIST(result == ISC_R_SUCCESS); 2905135446Strhodes dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 2906135446Strhodes 2907135446Strhodes obj = NULL; 2908135446Strhodes result = ns_config_get(maps, "serial-query-rate", &obj); 2909135446Strhodes INSIST(result == ISC_R_SUCCESS); 2910135446Strhodes dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 2911135446Strhodes 2912135446Strhodes /* 2913135446Strhodes * Determine which port to use for listening for incoming connections. 2914135446Strhodes */ 2915135446Strhodes if (ns_g_port != 0) 2916135446Strhodes listen_port = ns_g_port; 2917135446Strhodes else 2918135446Strhodes CHECKM(ns_config_getport(config, &listen_port), "port"); 2919135446Strhodes 2920135446Strhodes /* 2921135446Strhodes * Find the listen queue depth. 2922135446Strhodes */ 2923135446Strhodes obj = NULL; 2924135446Strhodes result = ns_config_get(maps, "tcp-listen-queue", &obj); 2925135446Strhodes INSIST(result == ISC_R_SUCCESS); 2926135446Strhodes ns_g_listen = cfg_obj_asuint32(obj); 2927135446Strhodes if (ns_g_listen < 3) 2928135446Strhodes ns_g_listen = 3; 2929135446Strhodes 2930135446Strhodes /* 2931135446Strhodes * Configure the interface manager according to the "listen-on" 2932135446Strhodes * statement. 2933135446Strhodes */ 2934135446Strhodes { 2935165071Sdougb const cfg_obj_t *clistenon = NULL; 2936135446Strhodes ns_listenlist_t *listenon = NULL; 2937135446Strhodes 2938135446Strhodes clistenon = NULL; 2939135446Strhodes /* 2940135446Strhodes * Even though listen-on is present in the default 2941135446Strhodes * configuration, we can't use it here, since it isn't 2942135446Strhodes * used if we're in lwresd mode. This way is easier. 2943135446Strhodes */ 2944135446Strhodes if (options != NULL) 2945135446Strhodes (void)cfg_map_get(options, "listen-on", &clistenon); 2946135446Strhodes if (clistenon != NULL) { 2947135446Strhodes result = ns_listenlist_fromconfig(clistenon, 2948135446Strhodes config, 2949135446Strhodes &aclconfctx, 2950135446Strhodes ns_g_mctx, 2951135446Strhodes &listenon); 2952135446Strhodes } else if (!ns_g_lwresdonly) { 2953135446Strhodes /* 2954135446Strhodes * Not specified, use default. 2955135446Strhodes */ 2956135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2957135446Strhodes ISC_TRUE, &listenon)); 2958135446Strhodes } 2959135446Strhodes if (listenon != NULL) { 2960135446Strhodes ns_interfacemgr_setlistenon4(server->interfacemgr, 2961135446Strhodes listenon); 2962135446Strhodes ns_listenlist_detach(&listenon); 2963135446Strhodes } 2964135446Strhodes } 2965135446Strhodes /* 2966135446Strhodes * Ditto for IPv6. 2967135446Strhodes */ 2968135446Strhodes { 2969165071Sdougb const cfg_obj_t *clistenon = NULL; 2970135446Strhodes ns_listenlist_t *listenon = NULL; 2971135446Strhodes 2972135446Strhodes if (options != NULL) 2973135446Strhodes (void)cfg_map_get(options, "listen-on-v6", &clistenon); 2974135446Strhodes if (clistenon != NULL) { 2975135446Strhodes result = ns_listenlist_fromconfig(clistenon, 2976135446Strhodes config, 2977135446Strhodes &aclconfctx, 2978135446Strhodes ns_g_mctx, 2979135446Strhodes &listenon); 2980135446Strhodes } else if (!ns_g_lwresdonly) { 2981135446Strhodes /* 2982135446Strhodes * Not specified, use default. 2983135446Strhodes */ 2984135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2985135446Strhodes ISC_FALSE, &listenon)); 2986135446Strhodes } 2987135446Strhodes if (listenon != NULL) { 2988135446Strhodes ns_interfacemgr_setlistenon6(server->interfacemgr, 2989135446Strhodes listenon); 2990135446Strhodes ns_listenlist_detach(&listenon); 2991135446Strhodes } 2992135446Strhodes } 2993135446Strhodes 2994135446Strhodes /* 2995135446Strhodes * Rescan the interface list to pick up changes in the 2996135446Strhodes * listen-on option. It's important that we do this before we try 2997135446Strhodes * to configure the query source, since the dispatcher we use might 2998135446Strhodes * be shared with an interface. 2999135446Strhodes */ 3000135446Strhodes scan_interfaces(server, ISC_TRUE); 3001135446Strhodes 3002135446Strhodes /* 3003135446Strhodes * Arrange for further interface scanning to occur periodically 3004135446Strhodes * as specified by the "interface-interval" option. 3005135446Strhodes */ 3006135446Strhodes obj = NULL; 3007135446Strhodes result = ns_config_get(maps, "interface-interval", &obj); 3008135446Strhodes INSIST(result == ISC_R_SUCCESS); 3009135446Strhodes interface_interval = cfg_obj_asuint32(obj) * 60; 3010135446Strhodes if (interface_interval == 0) { 3011135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 3012135446Strhodes isc_timertype_inactive, 3013135446Strhodes NULL, NULL, ISC_TRUE)); 3014135446Strhodes } else if (server->interface_interval != interface_interval) { 3015135446Strhodes isc_interval_set(&interval, interface_interval, 0); 3016135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 3017135446Strhodes isc_timertype_ticker, 3018135446Strhodes NULL, &interval, ISC_FALSE)); 3019135446Strhodes } 3020135446Strhodes server->interface_interval = interface_interval; 3021135446Strhodes 3022135446Strhodes /* 3023135446Strhodes * Configure the dialup heartbeat timer. 3024135446Strhodes */ 3025135446Strhodes obj = NULL; 3026135446Strhodes result = ns_config_get(maps, "heartbeat-interval", &obj); 3027135446Strhodes INSIST(result == ISC_R_SUCCESS); 3028135446Strhodes heartbeat_interval = cfg_obj_asuint32(obj) * 60; 3029135446Strhodes if (heartbeat_interval == 0) { 3030135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 3031135446Strhodes isc_timertype_inactive, 3032135446Strhodes NULL, NULL, ISC_TRUE)); 3033135446Strhodes } else if (server->heartbeat_interval != heartbeat_interval) { 3034135446Strhodes isc_interval_set(&interval, heartbeat_interval, 0); 3035135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 3036135446Strhodes isc_timertype_ticker, 3037135446Strhodes NULL, &interval, ISC_FALSE)); 3038135446Strhodes } 3039135446Strhodes server->heartbeat_interval = heartbeat_interval; 3040170222Sdougb 3041170222Sdougb isc_interval_set(&interval, 1200, 0); 3042170222Sdougb CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, 3043170222Sdougb &interval, ISC_FALSE)); 3044135446Strhodes 3045135446Strhodes /* 3046135446Strhodes * Configure and freeze all explicit views. Explicit 3047135446Strhodes * views that have zones were already created at parsing 3048135446Strhodes * time, but views with no zones must be created here. 3049135446Strhodes */ 3050135446Strhodes views = NULL; 3051135446Strhodes (void)cfg_map_get(config, "view", &views); 3052135446Strhodes for (element = cfg_list_first(views); 3053135446Strhodes element != NULL; 3054135446Strhodes element = cfg_list_next(element)) 3055135446Strhodes { 3056165071Sdougb const cfg_obj_t *vconfig = cfg_listelt_value(element); 3057135446Strhodes view = NULL; 3058135446Strhodes 3059135446Strhodes CHECK(create_view(vconfig, &viewlist, &view)); 3060135446Strhodes INSIST(view != NULL); 3061135446Strhodes CHECK(configure_view(view, config, vconfig, 3062135446Strhodes ns_g_mctx, &aclconfctx, ISC_TRUE)); 3063135446Strhodes dns_view_freeze(view); 3064135446Strhodes dns_view_detach(&view); 3065135446Strhodes } 3066135446Strhodes 3067135446Strhodes /* 3068135446Strhodes * Make sure we have a default view if and only if there 3069135446Strhodes * were no explicit views. 3070135446Strhodes */ 3071135446Strhodes if (views == NULL) { 3072135446Strhodes /* 3073135446Strhodes * No explicit views; there ought to be a default view. 3074135446Strhodes * There may already be one created as a side effect 3075135446Strhodes * of zone statements, or we may have to create one. 3076135446Strhodes * In either case, we need to configure and freeze it. 3077135446Strhodes */ 3078135446Strhodes CHECK(create_view(NULL, &viewlist, &view)); 3079135446Strhodes CHECK(configure_view(view, config, NULL, ns_g_mctx, 3080135446Strhodes &aclconfctx, ISC_TRUE)); 3081135446Strhodes dns_view_freeze(view); 3082135446Strhodes dns_view_detach(&view); 3083135446Strhodes } 3084135446Strhodes 3085135446Strhodes /* 3086135446Strhodes * Create (or recreate) the built-in views. Currently 3087135446Strhodes * there is only one, the _bind view. 3088135446Strhodes */ 3089135446Strhodes builtin_views = NULL; 3090135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 3091135446Strhodes &builtin_views) == ISC_R_SUCCESS); 3092135446Strhodes for (element = cfg_list_first(builtin_views); 3093135446Strhodes element != NULL; 3094135446Strhodes element = cfg_list_next(element)) 3095135446Strhodes { 3096165071Sdougb const cfg_obj_t *vconfig = cfg_listelt_value(element); 3097135446Strhodes CHECK(create_view(vconfig, &viewlist, &view)); 3098135446Strhodes CHECK(configure_view(view, config, vconfig, ns_g_mctx, 3099135446Strhodes &aclconfctx, ISC_FALSE)); 3100135446Strhodes dns_view_freeze(view); 3101135446Strhodes dns_view_detach(&view); 3102135446Strhodes view = NULL; 3103135446Strhodes } 3104135446Strhodes 3105135446Strhodes /* 3106135446Strhodes * Swap our new view list with the production one. 3107135446Strhodes */ 3108135446Strhodes tmpviewlist = server->viewlist; 3109135446Strhodes server->viewlist = viewlist; 3110135446Strhodes viewlist = tmpviewlist; 3111135446Strhodes 3112135446Strhodes /* 3113135446Strhodes * Load the TKEY information from the configuration. 3114135446Strhodes */ 3115135446Strhodes if (options != NULL) { 3116135446Strhodes dns_tkeyctx_t *t = NULL; 3117135446Strhodes CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 3118135446Strhodes &t), 3119135446Strhodes "configuring TKEY"); 3120135446Strhodes if (server->tkeyctx != NULL) 3121135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 3122135446Strhodes server->tkeyctx = t; 3123135446Strhodes } 3124135446Strhodes 3125135446Strhodes /* 3126135446Strhodes * Bind the control port(s). 3127135446Strhodes */ 3128135446Strhodes CHECKM(ns_controls_configure(ns_g_server->controls, config, 3129135446Strhodes &aclconfctx), 3130135446Strhodes "binding control channel(s)"); 3131135446Strhodes 3132135446Strhodes /* 3133135446Strhodes * Bind the lwresd port(s). 3134135446Strhodes */ 3135135446Strhodes CHECKM(ns_lwresd_configure(ns_g_mctx, config), 3136135446Strhodes "binding lightweight resolver ports"); 3137135446Strhodes 3138135446Strhodes /* 3139135446Strhodes * Open the source of entropy. 3140135446Strhodes */ 3141135446Strhodes if (first_time) { 3142135446Strhodes obj = NULL; 3143135446Strhodes result = ns_config_get(maps, "random-device", &obj); 3144135446Strhodes if (result != ISC_R_SUCCESS) { 3145135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3146135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3147135446Strhodes "no source of entropy found"); 3148135446Strhodes } else { 3149135446Strhodes const char *randomdev = cfg_obj_asstring(obj); 3150135446Strhodes result = isc_entropy_createfilesource(ns_g_entropy, 3151135446Strhodes randomdev); 3152135446Strhodes if (result != ISC_R_SUCCESS) 3153135446Strhodes isc_log_write(ns_g_lctx, 3154135446Strhodes NS_LOGCATEGORY_GENERAL, 3155135446Strhodes NS_LOGMODULE_SERVER, 3156135446Strhodes ISC_LOG_INFO, 3157135446Strhodes "could not open entropy source " 3158135446Strhodes "%s: %s", 3159135446Strhodes randomdev, 3160135446Strhodes isc_result_totext(result)); 3161135446Strhodes#ifdef PATH_RANDOMDEV 3162135446Strhodes if (ns_g_fallbackentropy != NULL) { 3163135446Strhodes if (result != ISC_R_SUCCESS) { 3164135446Strhodes isc_log_write(ns_g_lctx, 3165135446Strhodes NS_LOGCATEGORY_GENERAL, 3166135446Strhodes NS_LOGMODULE_SERVER, 3167135446Strhodes ISC_LOG_INFO, 3168135446Strhodes "using pre-chroot entropy source " 3169135446Strhodes "%s", 3170135446Strhodes PATH_RANDOMDEV); 3171135446Strhodes isc_entropy_detach(&ns_g_entropy); 3172135446Strhodes isc_entropy_attach(ns_g_fallbackentropy, 3173135446Strhodes &ns_g_entropy); 3174135446Strhodes } 3175135446Strhodes isc_entropy_detach(&ns_g_fallbackentropy); 3176135446Strhodes } 3177135446Strhodes#endif 3178135446Strhodes } 3179135446Strhodes } 3180135446Strhodes 3181135446Strhodes /* 3182135446Strhodes * Relinquish root privileges. 3183135446Strhodes */ 3184135446Strhodes if (first_time) 3185135446Strhodes ns_os_changeuser(); 3186135446Strhodes 3187135446Strhodes /* 3188135446Strhodes * Configure the logging system. 3189135446Strhodes * 3190135446Strhodes * Do this after changing UID to make sure that any log 3191135446Strhodes * files specified in named.conf get created by the 3192135446Strhodes * unprivileged user, not root. 3193135446Strhodes */ 3194135446Strhodes if (ns_g_logstderr) { 3195135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3196135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3197135446Strhodes "ignoring config file logging " 3198135446Strhodes "statement due to -g option"); 3199135446Strhodes } else { 3200165071Sdougb const cfg_obj_t *logobj = NULL; 3201135446Strhodes isc_logconfig_t *logc = NULL; 3202135446Strhodes 3203135446Strhodes CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 3204135446Strhodes "creating new logging configuration"); 3205135446Strhodes 3206135446Strhodes logobj = NULL; 3207135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 3208135446Strhodes if (logobj != NULL) { 3209135446Strhodes CHECKM(ns_log_configure(logc, logobj), 3210135446Strhodes "configuring logging"); 3211135446Strhodes } else { 3212135446Strhodes CHECKM(ns_log_setdefaultchannels(logc), 3213135446Strhodes "setting up default logging channels"); 3214135446Strhodes CHECKM(ns_log_setunmatchedcategory(logc), 3215135446Strhodes "setting up default 'category unmatched'"); 3216135446Strhodes CHECKM(ns_log_setdefaultcategory(logc), 3217135446Strhodes "setting up default 'category default'"); 3218135446Strhodes } 3219135446Strhodes 3220135446Strhodes result = isc_logconfig_use(ns_g_lctx, logc); 3221135446Strhodes if (result != ISC_R_SUCCESS) { 3222135446Strhodes isc_logconfig_destroy(&logc); 3223135446Strhodes CHECKM(result, "installing logging configuration"); 3224135446Strhodes } 3225135446Strhodes 3226135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3227135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 3228135446Strhodes "now using logging configuration from " 3229135446Strhodes "config file"); 3230135446Strhodes } 3231135446Strhodes 3232135446Strhodes /* 3233135446Strhodes * Set the default value of the query logging flag depending 3234135446Strhodes * whether a "queries" category has been defined. This is 3235135446Strhodes * a disgusting hack, but we need to do this for BIND 8 3236135446Strhodes * compatibility. 3237135446Strhodes */ 3238135446Strhodes if (first_time) { 3239165071Sdougb const cfg_obj_t *logobj = NULL; 3240165071Sdougb const cfg_obj_t *categories = NULL; 3241135446Strhodes 3242135446Strhodes obj = NULL; 3243135446Strhodes if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 3244135446Strhodes server->log_queries = cfg_obj_asboolean(obj); 3245135446Strhodes } else { 3246135446Strhodes 3247135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 3248135446Strhodes if (logobj != NULL) 3249135446Strhodes (void)cfg_map_get(logobj, "category", 3250135446Strhodes &categories); 3251135446Strhodes if (categories != NULL) { 3252165071Sdougb const cfg_listelt_t *element; 3253135446Strhodes for (element = cfg_list_first(categories); 3254135446Strhodes element != NULL; 3255135446Strhodes element = cfg_list_next(element)) 3256135446Strhodes { 3257165071Sdougb const cfg_obj_t *catobj; 3258165071Sdougb const char *str; 3259135446Strhodes 3260135446Strhodes obj = cfg_listelt_value(element); 3261135446Strhodes catobj = cfg_tuple_get(obj, "name"); 3262135446Strhodes str = cfg_obj_asstring(catobj); 3263135446Strhodes if (strcasecmp(str, "queries") == 0) 3264135446Strhodes server->log_queries = ISC_TRUE; 3265135446Strhodes } 3266135446Strhodes } 3267135446Strhodes } 3268135446Strhodes } 3269135446Strhodes 3270135446Strhodes obj = NULL; 3271135446Strhodes if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 3272135446Strhodes if (cfg_obj_isvoid(obj)) 3273135446Strhodes ns_os_writepidfile(NULL, first_time); 3274135446Strhodes else 3275135446Strhodes ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 3276135446Strhodes else if (ns_g_lwresdonly) 3277135446Strhodes ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 3278135446Strhodes else 3279135446Strhodes ns_os_writepidfile(ns_g_defaultpidfile, first_time); 3280135446Strhodes 3281135446Strhodes obj = NULL; 3282135446Strhodes if (options != NULL && 3283135446Strhodes cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS) 3284135446Strhodes ns_main_setmemstats(cfg_obj_asstring(obj)); 3285135446Strhodes else 3286135446Strhodes ns_main_setmemstats(NULL); 3287135446Strhodes 3288135446Strhodes obj = NULL; 3289135446Strhodes result = ns_config_get(maps, "statistics-file", &obj); 3290135446Strhodes INSIST(result == ISC_R_SUCCESS); 3291135446Strhodes CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 3292135446Strhodes "strdup"); 3293135446Strhodes 3294135446Strhodes obj = NULL; 3295135446Strhodes result = ns_config_get(maps, "dump-file", &obj); 3296135446Strhodes INSIST(result == ISC_R_SUCCESS); 3297135446Strhodes CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 3298135446Strhodes "strdup"); 3299135446Strhodes 3300135446Strhodes obj = NULL; 3301135446Strhodes result = ns_config_get(maps, "recursing-file", &obj); 3302135446Strhodes INSIST(result == ISC_R_SUCCESS); 3303135446Strhodes CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 3304135446Strhodes "strdup"); 3305135446Strhodes 3306135446Strhodes obj = NULL; 3307135446Strhodes result = ns_config_get(maps, "version", &obj); 3308135446Strhodes if (result == ISC_R_SUCCESS) { 3309135446Strhodes CHECKM(setoptstring(server, &server->version, obj), "strdup"); 3310135446Strhodes server->version_set = ISC_TRUE; 3311135446Strhodes } else { 3312135446Strhodes server->version_set = ISC_FALSE; 3313135446Strhodes } 3314135446Strhodes 3315135446Strhodes obj = NULL; 3316135446Strhodes result = ns_config_get(maps, "hostname", &obj); 3317135446Strhodes if (result == ISC_R_SUCCESS) { 3318135446Strhodes CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 3319135446Strhodes server->hostname_set = ISC_TRUE; 3320135446Strhodes } else { 3321135446Strhodes server->hostname_set = ISC_FALSE; 3322135446Strhodes } 3323135446Strhodes 3324135446Strhodes obj = NULL; 3325135446Strhodes result = ns_config_get(maps, "server-id", &obj); 3326135446Strhodes server->server_usehostname = ISC_FALSE; 3327135446Strhodes if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 3328135446Strhodes server->server_usehostname = ISC_TRUE; 3329135446Strhodes } else if (result == ISC_R_SUCCESS) { 3330135446Strhodes CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 3331135446Strhodes } else { 3332170222Sdougb result = setstring(server, &server->server_id, NULL); 3333135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3334135446Strhodes } 3335135446Strhodes 3336135446Strhodes obj = NULL; 3337135446Strhodes result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 3338135446Strhodes if (result == ISC_R_SUCCESS) { 3339135446Strhodes server->flushonshutdown = cfg_obj_asboolean(obj); 3340135446Strhodes } else { 3341135446Strhodes server->flushonshutdown = ISC_FALSE; 3342135446Strhodes } 3343135446Strhodes 3344135446Strhodes result = ISC_R_SUCCESS; 3345135446Strhodes 3346135446Strhodes cleanup: 3347170222Sdougb cfg_aclconfctx_destroy(&aclconfctx); 3348135446Strhodes 3349135446Strhodes if (parser != NULL) { 3350135446Strhodes if (config != NULL) 3351135446Strhodes cfg_obj_destroy(parser, &config); 3352135446Strhodes cfg_parser_destroy(&parser); 3353135446Strhodes } 3354135446Strhodes 3355135446Strhodes if (view != NULL) 3356135446Strhodes dns_view_detach(&view); 3357135446Strhodes 3358135446Strhodes /* 3359135446Strhodes * This cleans up either the old production view list 3360135446Strhodes * or our temporary list depending on whether they 3361135446Strhodes * were swapped above or not. 3362135446Strhodes */ 3363135446Strhodes for (view = ISC_LIST_HEAD(viewlist); 3364135446Strhodes view != NULL; 3365135446Strhodes view = view_next) { 3366135446Strhodes view_next = ISC_LIST_NEXT(view, link); 3367135446Strhodes ISC_LIST_UNLINK(viewlist, view, link); 3368170222Sdougb if (result == ISC_R_SUCCESS && 3369170222Sdougb strcmp(view->name, "_bind") != 0) 3370170222Sdougb (void)dns_zt_apply(view->zonetable, ISC_FALSE, 3371170222Sdougb removed, view); 3372135446Strhodes dns_view_detach(&view); 3373135446Strhodes } 3374135446Strhodes 3375135446Strhodes /* 3376135446Strhodes * Adjust the listening interfaces in accordance with the source 3377135446Strhodes * addresses specified in views and zones. 3378135446Strhodes */ 3379135446Strhodes if (isc_net_probeipv6() == ISC_R_SUCCESS) 3380135446Strhodes adjust_interfaces(server, ns_g_mctx); 3381135446Strhodes 3382135446Strhodes /* Relinquish exclusive access to configuration data. */ 3383135446Strhodes isc_task_endexclusive(server->task); 3384135446Strhodes 3385135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3386135446Strhodes ISC_LOG_DEBUG(1), "load_configuration: %s", 3387135446Strhodes isc_result_totext(result)); 3388135446Strhodes 3389135446Strhodes return (result); 3390135446Strhodes} 3391135446Strhodes 3392135446Strhodesstatic isc_result_t 3393135446Strhodesload_zones(ns_server_t *server, isc_boolean_t stop) { 3394135446Strhodes isc_result_t result; 3395135446Strhodes dns_view_t *view; 3396135446Strhodes 3397135446Strhodes result = isc_task_beginexclusive(server->task); 3398135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3399135446Strhodes 3400135446Strhodes /* 3401135446Strhodes * Load zone data from disk. 3402135446Strhodes */ 3403135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3404135446Strhodes view != NULL; 3405135446Strhodes view = ISC_LIST_NEXT(view, link)) 3406135446Strhodes { 3407135446Strhodes CHECK(dns_view_load(view, stop)); 3408135446Strhodes } 3409135446Strhodes 3410135446Strhodes /* 3411135446Strhodes * Force zone maintenance. Do this after loading 3412135446Strhodes * so that we know when we need to force AXFR of 3413135446Strhodes * slave zones whose master files are missing. 3414135446Strhodes */ 3415135446Strhodes CHECK(dns_zonemgr_forcemaint(server->zonemgr)); 3416135446Strhodes cleanup: 3417135446Strhodes isc_task_endexclusive(server->task); 3418135446Strhodes return (result); 3419135446Strhodes} 3420135446Strhodes 3421135446Strhodesstatic isc_result_t 3422135446Strhodesload_new_zones(ns_server_t *server, isc_boolean_t stop) { 3423135446Strhodes isc_result_t result; 3424135446Strhodes dns_view_t *view; 3425135446Strhodes 3426135446Strhodes result = isc_task_beginexclusive(server->task); 3427135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3428135446Strhodes 3429135446Strhodes /* 3430135446Strhodes * Load zone data from disk. 3431135446Strhodes */ 3432135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3433135446Strhodes view != NULL; 3434135446Strhodes view = ISC_LIST_NEXT(view, link)) 3435135446Strhodes { 3436135446Strhodes CHECK(dns_view_loadnew(view, stop)); 3437135446Strhodes } 3438135446Strhodes /* 3439135446Strhodes * Force zone maintenance. Do this after loading 3440135446Strhodes * so that we know when we need to force AXFR of 3441135446Strhodes * slave zones whose master files are missing. 3442135446Strhodes */ 3443135446Strhodes dns_zonemgr_resumexfrs(server->zonemgr); 3444135446Strhodes cleanup: 3445135446Strhodes isc_task_endexclusive(server->task); 3446135446Strhodes return (result); 3447135446Strhodes} 3448135446Strhodes 3449135446Strhodesstatic void 3450135446Strhodesrun_server(isc_task_t *task, isc_event_t *event) { 3451135446Strhodes isc_result_t result; 3452135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 3453135446Strhodes 3454143731Sdougb INSIST(task == server->task); 3455135446Strhodes 3456135446Strhodes isc_event_free(&event); 3457135446Strhodes 3458135446Strhodes CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 3459135446Strhodes &ns_g_dispatchmgr), 3460135446Strhodes "creating dispatch manager"); 3461135446Strhodes 3462135446Strhodes CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 3463135446Strhodes ns_g_socketmgr, ns_g_dispatchmgr, 3464135446Strhodes &server->interfacemgr), 3465135446Strhodes "creating interface manager"); 3466135446Strhodes 3467135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3468135446Strhodes NULL, NULL, server->task, 3469135446Strhodes interface_timer_tick, 3470135446Strhodes server, &server->interface_timer), 3471135446Strhodes "creating interface timer"); 3472135446Strhodes 3473135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3474135446Strhodes NULL, NULL, server->task, 3475135446Strhodes heartbeat_timer_tick, 3476135446Strhodes server, &server->heartbeat_timer), 3477135446Strhodes "creating heartbeat timer"); 3478135446Strhodes 3479170222Sdougb CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3480170222Sdougb NULL, NULL, server->task, pps_timer_tick, 3481170222Sdougb server, &server->pps_timer), 3482170222Sdougb "creating pps timer"); 3483170222Sdougb 3484135446Strhodes CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 3485135446Strhodes "creating default configuration parser"); 3486135446Strhodes 3487135446Strhodes if (ns_g_lwresdonly) 3488135446Strhodes CHECKFATAL(load_configuration(lwresd_g_conffile, server, 3489135446Strhodes ISC_TRUE), 3490135446Strhodes "loading configuration"); 3491135446Strhodes else 3492135446Strhodes CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 3493135446Strhodes "loading configuration"); 3494135446Strhodes 3495135446Strhodes isc_hash_init(); 3496135446Strhodes 3497143731Sdougb CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); 3498135446Strhodes 3499143731Sdougb ns_os_started(); 3500135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3501143731Sdougb ISC_LOG_NOTICE, "running"); 3502135446Strhodes} 3503135446Strhodes 3504135446Strhodesvoid 3505135446Strhodesns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 3506135446Strhodes 3507135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 3508135446Strhodes 3509135446Strhodes server->flushonshutdown = flush; 3510135446Strhodes} 3511135446Strhodes 3512135446Strhodesstatic void 3513135446Strhodesshutdown_server(isc_task_t *task, isc_event_t *event) { 3514135446Strhodes isc_result_t result; 3515135446Strhodes dns_view_t *view, *view_next; 3516135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 3517135446Strhodes isc_boolean_t flush = server->flushonshutdown; 3518135446Strhodes 3519135446Strhodes UNUSED(task); 3520135446Strhodes INSIST(task == server->task); 3521135446Strhodes 3522135446Strhodes result = isc_task_beginexclusive(server->task); 3523135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3524135446Strhodes 3525135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3526135446Strhodes ISC_LOG_INFO, "shutting down%s", 3527135446Strhodes flush ? ": flushing changes" : ""); 3528135446Strhodes 3529135446Strhodes ns_controls_shutdown(server->controls); 3530135446Strhodes end_reserved_dispatches(server, ISC_TRUE); 3531135446Strhodes 3532135446Strhodes cfg_obj_destroy(ns_g_parser, &ns_g_config); 3533135446Strhodes cfg_parser_destroy(&ns_g_parser); 3534135446Strhodes 3535135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 3536135446Strhodes view != NULL; 3537135446Strhodes view = view_next) { 3538135446Strhodes view_next = ISC_LIST_NEXT(view, link); 3539135446Strhodes ISC_LIST_UNLINK(server->viewlist, view, link); 3540135446Strhodes if (flush) 3541135446Strhodes dns_view_flushanddetach(&view); 3542135446Strhodes else 3543135446Strhodes dns_view_detach(&view); 3544135446Strhodes } 3545135446Strhodes 3546135446Strhodes isc_timer_detach(&server->interface_timer); 3547135446Strhodes isc_timer_detach(&server->heartbeat_timer); 3548170222Sdougb isc_timer_detach(&server->pps_timer); 3549135446Strhodes 3550135446Strhodes ns_interfacemgr_shutdown(server->interfacemgr); 3551135446Strhodes ns_interfacemgr_detach(&server->interfacemgr); 3552135446Strhodes 3553135446Strhodes dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 3554135446Strhodes 3555135446Strhodes dns_zonemgr_shutdown(server->zonemgr); 3556135446Strhodes 3557135446Strhodes if (server->blackholeacl != NULL) 3558135446Strhodes dns_acl_detach(&server->blackholeacl); 3559135446Strhodes 3560135446Strhodes dns_db_detach(&server->in_roothints); 3561135446Strhodes 3562135446Strhodes isc_task_endexclusive(server->task); 3563135446Strhodes 3564135446Strhodes isc_task_detach(&server->task); 3565135446Strhodes 3566135446Strhodes isc_event_free(&event); 3567135446Strhodes} 3568135446Strhodes 3569135446Strhodesvoid 3570135446Strhodesns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 3571135446Strhodes isc_result_t result; 3572135446Strhodes 3573135446Strhodes ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 3574135446Strhodes if (server == NULL) 3575135446Strhodes fatal("allocating server object", ISC_R_NOMEMORY); 3576135446Strhodes 3577135446Strhodes server->mctx = mctx; 3578135446Strhodes server->task = NULL; 3579135446Strhodes 3580135446Strhodes /* Initialize configuration data with default values. */ 3581135446Strhodes 3582135446Strhodes result = isc_quota_init(&server->xfroutquota, 10); 3583135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3584135446Strhodes result = isc_quota_init(&server->tcpquota, 10); 3585135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3586135446Strhodes result = isc_quota_init(&server->recursionquota, 100); 3587135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3588135446Strhodes 3589135446Strhodes result = dns_aclenv_init(mctx, &server->aclenv); 3590135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 3591135446Strhodes 3592135446Strhodes /* Initialize server data structures. */ 3593135446Strhodes server->zonemgr = NULL; 3594135446Strhodes server->interfacemgr = NULL; 3595135446Strhodes ISC_LIST_INIT(server->viewlist); 3596135446Strhodes server->in_roothints = NULL; 3597135446Strhodes server->blackholeacl = NULL; 3598135446Strhodes 3599135446Strhodes CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 3600135446Strhodes &server->in_roothints), 3601135446Strhodes "setting up root hints"); 3602135446Strhodes 3603135446Strhodes CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 3604135446Strhodes "initializing reload event lock"); 3605135446Strhodes server->reload_event = 3606135446Strhodes isc_event_allocate(ns_g_mctx, server, 3607135446Strhodes NS_EVENT_RELOAD, 3608135446Strhodes ns_server_reload, 3609135446Strhodes server, 3610135446Strhodes sizeof(isc_event_t)); 3611135446Strhodes CHECKFATAL(server->reload_event == NULL ? 3612135446Strhodes ISC_R_NOMEMORY : ISC_R_SUCCESS, 3613135446Strhodes "allocating reload event"); 3614135446Strhodes 3615135446Strhodes CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), 3616135446Strhodes "initializing DST"); 3617135446Strhodes 3618135446Strhodes server->tkeyctx = NULL; 3619135446Strhodes CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 3620135446Strhodes &server->tkeyctx), 3621135446Strhodes "creating TKEY context"); 3622135446Strhodes 3623135446Strhodes /* 3624135446Strhodes * Setup the server task, which is responsible for coordinating 3625135446Strhodes * startup and shutdown of the server. 3626135446Strhodes */ 3627135446Strhodes CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 3628135446Strhodes "creating server task"); 3629135446Strhodes isc_task_setname(server->task, "server", server); 3630135446Strhodes CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 3631135446Strhodes "isc_task_onshutdown"); 3632135446Strhodes CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 3633135446Strhodes "isc_app_onrun"); 3634135446Strhodes 3635135446Strhodes server->interface_timer = NULL; 3636135446Strhodes server->heartbeat_timer = NULL; 3637170222Sdougb server->pps_timer = NULL; 3638135446Strhodes 3639135446Strhodes server->interface_interval = 0; 3640135446Strhodes server->heartbeat_interval = 0; 3641135446Strhodes 3642135446Strhodes CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 3643135446Strhodes ns_g_socketmgr, &server->zonemgr), 3644135446Strhodes "dns_zonemgr_create"); 3645135446Strhodes 3646135446Strhodes server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 3647135446Strhodes CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3648135446Strhodes "isc_mem_strdup"); 3649135446Strhodes server->querystats = NULL; 3650135446Strhodes 3651135446Strhodes server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 3652135446Strhodes CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3653135446Strhodes "isc_mem_strdup"); 3654135446Strhodes 3655135446Strhodes server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 3656135446Strhodes CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3657135446Strhodes "isc_mem_strdup"); 3658135446Strhodes 3659135446Strhodes server->hostname_set = ISC_FALSE; 3660135446Strhodes server->hostname = NULL; 3661135446Strhodes server->version_set = ISC_FALSE; 3662135446Strhodes server->version = NULL; 3663135446Strhodes server->server_usehostname = ISC_FALSE; 3664135446Strhodes server->server_id = NULL; 3665135446Strhodes 3666135446Strhodes CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats), 3667135446Strhodes "dns_stats_alloccounters"); 3668135446Strhodes 3669135446Strhodes server->flushonshutdown = ISC_FALSE; 3670135446Strhodes server->log_queries = ISC_FALSE; 3671135446Strhodes 3672135446Strhodes server->controls = NULL; 3673135446Strhodes CHECKFATAL(ns_controls_create(server, &server->controls), 3674135446Strhodes "ns_controls_create"); 3675135446Strhodes server->dispatchgen = 0; 3676135446Strhodes ISC_LIST_INIT(server->dispatches); 3677135446Strhodes 3678135446Strhodes server->magic = NS_SERVER_MAGIC; 3679135446Strhodes *serverp = server; 3680135446Strhodes} 3681135446Strhodes 3682135446Strhodesvoid 3683135446Strhodesns_server_destroy(ns_server_t **serverp) { 3684135446Strhodes ns_server_t *server = *serverp; 3685135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 3686135446Strhodes 3687135446Strhodes ns_controls_destroy(&server->controls); 3688135446Strhodes 3689135446Strhodes dns_stats_freecounters(server->mctx, &server->querystats); 3690135446Strhodes 3691135446Strhodes isc_mem_free(server->mctx, server->statsfile); 3692135446Strhodes isc_mem_free(server->mctx, server->dumpfile); 3693135446Strhodes isc_mem_free(server->mctx, server->recfile); 3694135446Strhodes 3695135446Strhodes if (server->version != NULL) 3696135446Strhodes isc_mem_free(server->mctx, server->version); 3697135446Strhodes if (server->hostname != NULL) 3698135446Strhodes isc_mem_free(server->mctx, server->hostname); 3699135446Strhodes if (server->server_id != NULL) 3700135446Strhodes isc_mem_free(server->mctx, server->server_id); 3701135446Strhodes 3702135446Strhodes dns_zonemgr_detach(&server->zonemgr); 3703135446Strhodes 3704135446Strhodes if (server->tkeyctx != NULL) 3705135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 3706135446Strhodes 3707135446Strhodes dst_lib_destroy(); 3708135446Strhodes 3709135446Strhodes isc_event_free(&server->reload_event); 3710135446Strhodes 3711135446Strhodes INSIST(ISC_LIST_EMPTY(server->viewlist)); 3712135446Strhodes 3713135446Strhodes dns_aclenv_destroy(&server->aclenv); 3714135446Strhodes 3715135446Strhodes isc_quota_destroy(&server->recursionquota); 3716135446Strhodes isc_quota_destroy(&server->tcpquota); 3717135446Strhodes isc_quota_destroy(&server->xfroutquota); 3718135446Strhodes 3719135446Strhodes server->magic = 0; 3720135446Strhodes isc_mem_put(server->mctx, server, sizeof(*server)); 3721135446Strhodes *serverp = NULL; 3722135446Strhodes} 3723135446Strhodes 3724135446Strhodesstatic void 3725135446Strhodesfatal(const char *msg, isc_result_t result) { 3726135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3727135446Strhodes ISC_LOG_CRITICAL, "%s: %s", msg, 3728135446Strhodes isc_result_totext(result)); 3729135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3730135446Strhodes ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 3731135446Strhodes exit(1); 3732135446Strhodes} 3733135446Strhodes 3734135446Strhodesstatic void 3735135446Strhodesstart_reserved_dispatches(ns_server_t *server) { 3736135446Strhodes 3737135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 3738135446Strhodes 3739135446Strhodes server->dispatchgen++; 3740135446Strhodes} 3741135446Strhodes 3742135446Strhodesstatic void 3743135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 3744135446Strhodes ns_dispatch_t *dispatch, *nextdispatch; 3745135446Strhodes 3746135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 3747135446Strhodes 3748135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 3749135446Strhodes dispatch != NULL; 3750135446Strhodes dispatch = nextdispatch) { 3751135446Strhodes nextdispatch = ISC_LIST_NEXT(dispatch, link); 3752135446Strhodes if (!all && server->dispatchgen == dispatch-> dispatchgen) 3753135446Strhodes continue; 3754135446Strhodes ISC_LIST_UNLINK(server->dispatches, dispatch, link); 3755135446Strhodes dns_dispatch_detach(&dispatch->dispatch); 3756135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3757135446Strhodes } 3758135446Strhodes} 3759135446Strhodes 3760135446Strhodesvoid 3761165071Sdougbns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 3762135446Strhodes ns_dispatch_t *dispatch; 3763135446Strhodes in_port_t port; 3764135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 3765135446Strhodes isc_result_t result; 3766135446Strhodes unsigned int attrs, attrmask; 3767135446Strhodes 3768135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 3769135446Strhodes 3770135446Strhodes port = isc_sockaddr_getport(addr); 3771135446Strhodes if (port == 0 || port >= 1024) 3772135446Strhodes return; 3773135446Strhodes 3774135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 3775135446Strhodes dispatch != NULL; 3776135446Strhodes dispatch = ISC_LIST_NEXT(dispatch, link)) { 3777135446Strhodes if (isc_sockaddr_equal(&dispatch->addr, addr)) 3778135446Strhodes break; 3779135446Strhodes } 3780135446Strhodes if (dispatch != NULL) { 3781135446Strhodes dispatch->dispatchgen = server->dispatchgen; 3782135446Strhodes return; 3783135446Strhodes } 3784135446Strhodes 3785135446Strhodes dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 3786135446Strhodes if (dispatch == NULL) { 3787135446Strhodes result = ISC_R_NOMEMORY; 3788135446Strhodes goto cleanup; 3789135446Strhodes } 3790135446Strhodes 3791135446Strhodes dispatch->addr = *addr; 3792135446Strhodes dispatch->dispatchgen = server->dispatchgen; 3793135446Strhodes dispatch->dispatch = NULL; 3794135446Strhodes 3795135446Strhodes attrs = 0; 3796135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 3797135446Strhodes switch (isc_sockaddr_pf(addr)) { 3798135446Strhodes case AF_INET: 3799135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 3800135446Strhodes break; 3801135446Strhodes case AF_INET6: 3802135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 3803135446Strhodes break; 3804135446Strhodes default: 3805135446Strhodes result = ISC_R_NOTIMPLEMENTED; 3806135446Strhodes goto cleanup; 3807135446Strhodes } 3808135446Strhodes attrmask = 0; 3809135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 3810135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 3811135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 3812135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 3813135446Strhodes 3814135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 3815135446Strhodes ns_g_taskmgr, &dispatch->addr, 4096, 3816135446Strhodes 1000, 32768, 16411, 16433, 3817135446Strhodes attrs, attrmask, &dispatch->dispatch); 3818135446Strhodes if (result != ISC_R_SUCCESS) 3819135446Strhodes goto cleanup; 3820135446Strhodes 3821135446Strhodes ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 3822135446Strhodes 3823135446Strhodes return; 3824135446Strhodes 3825135446Strhodes cleanup: 3826135446Strhodes if (dispatch != NULL) 3827135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3828135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 3829135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3830135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3831135446Strhodes "unable to create dispatch for reserved port %s: %s", 3832135446Strhodes addrbuf, isc_result_totext(result)); 3833135446Strhodes} 3834135446Strhodes 3835135446Strhodes 3836135446Strhodesstatic isc_result_t 3837135446Strhodesloadconfig(ns_server_t *server) { 3838135446Strhodes isc_result_t result; 3839135446Strhodes start_reserved_dispatches(server); 3840135446Strhodes result = load_configuration(ns_g_lwresdonly ? 3841135446Strhodes lwresd_g_conffile : ns_g_conffile, 3842143731Sdougb server, ISC_FALSE); 3843135446Strhodes if (result == ISC_R_SUCCESS) 3844135446Strhodes end_reserved_dispatches(server, ISC_FALSE); 3845135446Strhodes else 3846135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3847135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3848135446Strhodes "reloading configuration failed: %s", 3849135446Strhodes isc_result_totext(result)); 3850135446Strhodes return (result); 3851135446Strhodes} 3852135446Strhodes 3853135446Strhodesstatic isc_result_t 3854135446Strhodesreload(ns_server_t *server) { 3855135446Strhodes isc_result_t result; 3856135446Strhodes CHECK(loadconfig(server)); 3857135446Strhodes 3858135446Strhodes result = load_zones(server, ISC_FALSE); 3859135446Strhodes if (result != ISC_R_SUCCESS) { 3860135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3861135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3862135446Strhodes "reloading zones failed: %s", 3863135446Strhodes isc_result_totext(result)); 3864135446Strhodes } 3865135446Strhodes cleanup: 3866135446Strhodes return (result); 3867135446Strhodes} 3868135446Strhodes 3869135446Strhodesstatic void 3870135446Strhodesreconfig(ns_server_t *server) { 3871135446Strhodes isc_result_t result; 3872135446Strhodes CHECK(loadconfig(server)); 3873135446Strhodes 3874135446Strhodes result = load_new_zones(server, ISC_FALSE); 3875135446Strhodes if (result != ISC_R_SUCCESS) { 3876135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3877135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3878135446Strhodes "loading new zones failed: %s", 3879135446Strhodes isc_result_totext(result)); 3880135446Strhodes } 3881135446Strhodes cleanup: ; 3882135446Strhodes} 3883135446Strhodes 3884135446Strhodes/* 3885135446Strhodes * Handle a reload event (from SIGHUP). 3886135446Strhodes */ 3887135446Strhodesstatic void 3888135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event) { 3889135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 3890135446Strhodes 3891135446Strhodes INSIST(task = server->task); 3892135446Strhodes UNUSED(task); 3893135446Strhodes 3894135446Strhodes (void)reload(server); 3895135446Strhodes 3896135446Strhodes LOCK(&server->reload_event_lock); 3897135446Strhodes INSIST(server->reload_event == NULL); 3898135446Strhodes server->reload_event = event; 3899135446Strhodes UNLOCK(&server->reload_event_lock); 3900135446Strhodes} 3901135446Strhodes 3902135446Strhodesvoid 3903135446Strhodesns_server_reloadwanted(ns_server_t *server) { 3904135446Strhodes LOCK(&server->reload_event_lock); 3905135446Strhodes if (server->reload_event != NULL) 3906135446Strhodes isc_task_send(server->task, &server->reload_event); 3907135446Strhodes UNLOCK(&server->reload_event_lock); 3908135446Strhodes} 3909135446Strhodes 3910135446Strhodesstatic char * 3911135446Strhodesnext_token(char **stringp, const char *delim) { 3912135446Strhodes char *res; 3913135446Strhodes 3914135446Strhodes do { 3915135446Strhodes res = strsep(stringp, delim); 3916135446Strhodes if (res == NULL) 3917135446Strhodes break; 3918135446Strhodes } while (*res == '\0'); 3919135446Strhodes return (res); 3920135446Strhodes} 3921135446Strhodes 3922135446Strhodes/* 3923135446Strhodes * Find the zone specified in the control channel command 'args', 3924135446Strhodes * if any. If a zone is specified, point '*zonep' at it, otherwise 3925135446Strhodes * set '*zonep' to NULL. 3926135446Strhodes */ 3927135446Strhodesstatic isc_result_t 3928135446Strhodeszone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { 3929135446Strhodes char *input, *ptr; 3930135446Strhodes const char *zonetxt; 3931135446Strhodes char *classtxt; 3932135446Strhodes const char *viewtxt = NULL; 3933135446Strhodes dns_fixedname_t name; 3934135446Strhodes isc_result_t result; 3935135446Strhodes isc_buffer_t buf; 3936135446Strhodes dns_view_t *view = NULL; 3937135446Strhodes dns_rdataclass_t rdclass; 3938135446Strhodes 3939135446Strhodes REQUIRE(zonep != NULL && *zonep == NULL); 3940135446Strhodes 3941135446Strhodes input = args; 3942135446Strhodes 3943135446Strhodes /* Skip the command name. */ 3944135446Strhodes ptr = next_token(&input, " \t"); 3945135446Strhodes if (ptr == NULL) 3946135446Strhodes return (ISC_R_UNEXPECTEDEND); 3947135446Strhodes 3948135446Strhodes /* Look for the zone name. */ 3949135446Strhodes zonetxt = next_token(&input, " \t"); 3950135446Strhodes if (zonetxt == NULL) 3951135446Strhodes return (ISC_R_SUCCESS); 3952135446Strhodes 3953135446Strhodes /* Look for the optional class name. */ 3954135446Strhodes classtxt = next_token(&input, " \t"); 3955135446Strhodes if (classtxt != NULL) { 3956135446Strhodes /* Look for the optional view name. */ 3957135446Strhodes viewtxt = next_token(&input, " \t"); 3958135446Strhodes } 3959135446Strhodes 3960135446Strhodes isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); 3961135446Strhodes isc_buffer_add(&buf, strlen(zonetxt)); 3962135446Strhodes dns_fixedname_init(&name); 3963135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&name), 3964135446Strhodes &buf, dns_rootname, ISC_FALSE, NULL); 3965135446Strhodes if (result != ISC_R_SUCCESS) 3966135446Strhodes goto fail1; 3967135446Strhodes 3968135446Strhodes if (classtxt != NULL) { 3969135446Strhodes isc_textregion_t r; 3970135446Strhodes r.base = classtxt; 3971135446Strhodes r.length = strlen(classtxt); 3972135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &r); 3973135446Strhodes if (result != ISC_R_SUCCESS) 3974135446Strhodes goto fail1; 3975135446Strhodes } else { 3976135446Strhodes rdclass = dns_rdataclass_in; 3977135446Strhodes } 3978135446Strhodes 3979135446Strhodes if (viewtxt == NULL) 3980135446Strhodes viewtxt = "_default"; 3981135446Strhodes result = dns_viewlist_find(&server->viewlist, viewtxt, 3982135446Strhodes rdclass, &view); 3983135446Strhodes if (result != ISC_R_SUCCESS) 3984135446Strhodes goto fail1; 3985135446Strhodes 3986135446Strhodes result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), 3987135446Strhodes 0, NULL, zonep); 3988135446Strhodes /* Partial match? */ 3989135446Strhodes if (result != ISC_R_SUCCESS && *zonep != NULL) 3990135446Strhodes dns_zone_detach(zonep); 3991135446Strhodes dns_view_detach(&view); 3992135446Strhodes fail1: 3993135446Strhodes return (result); 3994135446Strhodes} 3995135446Strhodes 3996135446Strhodes/* 3997135446Strhodes * Act on a "retransfer" command from the command channel. 3998135446Strhodes */ 3999135446Strhodesisc_result_t 4000135446Strhodesns_server_retransfercommand(ns_server_t *server, char *args) { 4001135446Strhodes isc_result_t result; 4002135446Strhodes dns_zone_t *zone = NULL; 4003135446Strhodes dns_zonetype_t type; 4004135446Strhodes 4005135446Strhodes result = zone_from_args(server, args, &zone); 4006135446Strhodes if (result != ISC_R_SUCCESS) 4007135446Strhodes return (result); 4008135446Strhodes if (zone == NULL) 4009135446Strhodes return (ISC_R_UNEXPECTEDEND); 4010135446Strhodes type = dns_zone_gettype(zone); 4011135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) 4012135446Strhodes dns_zone_forcereload(zone); 4013135446Strhodes else 4014135446Strhodes result = ISC_R_NOTFOUND; 4015135446Strhodes dns_zone_detach(&zone); 4016135446Strhodes return (result); 4017135446Strhodes} 4018135446Strhodes 4019135446Strhodes/* 4020135446Strhodes * Act on a "reload" command from the command channel. 4021135446Strhodes */ 4022135446Strhodesisc_result_t 4023135446Strhodesns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 4024135446Strhodes isc_result_t result; 4025135446Strhodes dns_zone_t *zone = NULL; 4026135446Strhodes dns_zonetype_t type; 4027135446Strhodes const char *msg = NULL; 4028135446Strhodes 4029135446Strhodes result = zone_from_args(server, args, &zone); 4030135446Strhodes if (result != ISC_R_SUCCESS) 4031135446Strhodes return (result); 4032135446Strhodes if (zone == NULL) { 4033135446Strhodes result = reload(server); 4034135446Strhodes if (result == ISC_R_SUCCESS) 4035135446Strhodes msg = "server reload successful"; 4036135446Strhodes } else { 4037135446Strhodes type = dns_zone_gettype(zone); 4038135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) { 4039135446Strhodes dns_zone_refresh(zone); 4040174187Sdougb dns_zone_detach(&zone); 4041135446Strhodes msg = "zone refresh queued"; 4042135446Strhodes } else { 4043135446Strhodes result = dns_zone_load(zone); 4044135446Strhodes dns_zone_detach(&zone); 4045135446Strhodes switch (result) { 4046135446Strhodes case ISC_R_SUCCESS: 4047135446Strhodes msg = "zone reload successful"; 4048135446Strhodes break; 4049135446Strhodes case DNS_R_CONTINUE: 4050135446Strhodes msg = "zone reload queued"; 4051135446Strhodes result = ISC_R_SUCCESS; 4052135446Strhodes break; 4053135446Strhodes case DNS_R_UPTODATE: 4054135446Strhodes msg = "zone reload up-to-date"; 4055135446Strhodes result = ISC_R_SUCCESS; 4056135446Strhodes break; 4057135446Strhodes default: 4058135446Strhodes /* failure message will be generated by rndc */ 4059135446Strhodes break; 4060135446Strhodes } 4061135446Strhodes } 4062135446Strhodes } 4063135446Strhodes if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 4064135446Strhodes isc_buffer_putmem(text, (const unsigned char *)msg, 4065135446Strhodes strlen(msg) + 1); 4066135446Strhodes return (result); 4067135446Strhodes} 4068135446Strhodes 4069135446Strhodes/* 4070135446Strhodes * Act on a "reconfig" command from the command channel. 4071135446Strhodes */ 4072135446Strhodesisc_result_t 4073135446Strhodesns_server_reconfigcommand(ns_server_t *server, char *args) { 4074135446Strhodes UNUSED(args); 4075135446Strhodes 4076135446Strhodes reconfig(server); 4077135446Strhodes return (ISC_R_SUCCESS); 4078135446Strhodes} 4079135446Strhodes 4080135446Strhodes/* 4081170222Sdougb * Act on a "notify" command from the command channel. 4082170222Sdougb */ 4083170222Sdougbisc_result_t 4084170222Sdougbns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { 4085170222Sdougb isc_result_t result; 4086170222Sdougb dns_zone_t *zone = NULL; 4087170222Sdougb const unsigned char msg[] = "zone notify queued"; 4088170222Sdougb 4089170222Sdougb result = zone_from_args(server, args, &zone); 4090170222Sdougb if (result != ISC_R_SUCCESS) 4091170222Sdougb return (result); 4092170222Sdougb if (zone == NULL) 4093170222Sdougb return (ISC_R_UNEXPECTEDEND); 4094170222Sdougb 4095170222Sdougb dns_zone_notify(zone); 4096170222Sdougb dns_zone_detach(&zone); 4097170222Sdougb if (sizeof(msg) <= isc_buffer_availablelength(text)) 4098170222Sdougb isc_buffer_putmem(text, msg, sizeof(msg)); 4099170222Sdougb 4100170222Sdougb return (ISC_R_SUCCESS); 4101170222Sdougb} 4102170222Sdougb 4103170222Sdougb/* 4104135446Strhodes * Act on a "refresh" command from the command channel. 4105135446Strhodes */ 4106135446Strhodesisc_result_t 4107135446Strhodesns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 4108135446Strhodes isc_result_t result; 4109135446Strhodes dns_zone_t *zone = NULL; 4110165071Sdougb const unsigned char msg1[] = "zone refresh queued"; 4111165071Sdougb const unsigned char msg2[] = "not a slave or stub zone"; 4112165071Sdougb dns_zonetype_t type; 4113135446Strhodes 4114135446Strhodes result = zone_from_args(server, args, &zone); 4115135446Strhodes if (result != ISC_R_SUCCESS) 4116135446Strhodes return (result); 4117135446Strhodes if (zone == NULL) 4118135446Strhodes return (ISC_R_UNEXPECTEDEND); 4119165071Sdougb 4120165071Sdougb type = dns_zone_gettype(zone); 4121165071Sdougb if (type == dns_zone_slave || type == dns_zone_stub) { 4122165071Sdougb dns_zone_refresh(zone); 4123165071Sdougb dns_zone_detach(&zone); 4124165071Sdougb if (sizeof(msg1) <= isc_buffer_availablelength(text)) 4125165071Sdougb isc_buffer_putmem(text, msg1, sizeof(msg1)); 4126165071Sdougb return (ISC_R_SUCCESS); 4127165071Sdougb } 4128165071Sdougb 4129135446Strhodes dns_zone_detach(&zone); 4130165071Sdougb if (sizeof(msg2) <= isc_buffer_availablelength(text)) 4131165071Sdougb isc_buffer_putmem(text, msg2, sizeof(msg2)); 4132165071Sdougb return (ISC_R_FAILURE); 4133135446Strhodes} 4134135446Strhodes 4135135446Strhodesisc_result_t 4136135446Strhodesns_server_togglequerylog(ns_server_t *server) { 4137135446Strhodes server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; 4138135446Strhodes 4139135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4140135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4141135446Strhodes "query logging is now %s", 4142135446Strhodes server->log_queries ? "on" : "off"); 4143135446Strhodes return (ISC_R_SUCCESS); 4144135446Strhodes} 4145135446Strhodes 4146135446Strhodesstatic isc_result_t 4147165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 4148170222Sdougb cfg_aclconfctx_t *actx, 4149135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target) 4150135446Strhodes{ 4151135446Strhodes isc_result_t result; 4152165071Sdougb const cfg_listelt_t *element; 4153135446Strhodes ns_listenlist_t *dlist = NULL; 4154135446Strhodes 4155135446Strhodes REQUIRE(target != NULL && *target == NULL); 4156135446Strhodes 4157135446Strhodes result = ns_listenlist_create(mctx, &dlist); 4158135446Strhodes if (result != ISC_R_SUCCESS) 4159135446Strhodes return (result); 4160135446Strhodes 4161135446Strhodes for (element = cfg_list_first(listenlist); 4162135446Strhodes element != NULL; 4163135446Strhodes element = cfg_list_next(element)) 4164135446Strhodes { 4165135446Strhodes ns_listenelt_t *delt = NULL; 4166165071Sdougb const cfg_obj_t *listener = cfg_listelt_value(element); 4167135446Strhodes result = ns_listenelt_fromconfig(listener, config, actx, 4168135446Strhodes mctx, &delt); 4169135446Strhodes if (result != ISC_R_SUCCESS) 4170135446Strhodes goto cleanup; 4171135446Strhodes ISC_LIST_APPEND(dlist->elts, delt, link); 4172135446Strhodes } 4173135446Strhodes *target = dlist; 4174135446Strhodes return (ISC_R_SUCCESS); 4175135446Strhodes 4176135446Strhodes cleanup: 4177135446Strhodes ns_listenlist_detach(&dlist); 4178135446Strhodes return (result); 4179135446Strhodes} 4180135446Strhodes 4181135446Strhodes/* 4182135446Strhodes * Create a listen list from the corresponding configuration 4183135446Strhodes * data structure. 4184135446Strhodes */ 4185135446Strhodesstatic isc_result_t 4186165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 4187170222Sdougb cfg_aclconfctx_t *actx, 4188135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target) 4189135446Strhodes{ 4190135446Strhodes isc_result_t result; 4191165071Sdougb const cfg_obj_t *portobj; 4192135446Strhodes in_port_t port; 4193135446Strhodes ns_listenelt_t *delt = NULL; 4194135446Strhodes REQUIRE(target != NULL && *target == NULL); 4195135446Strhodes 4196135446Strhodes portobj = cfg_tuple_get(listener, "port"); 4197135446Strhodes if (!cfg_obj_isuint32(portobj)) { 4198135446Strhodes if (ns_g_port != 0) { 4199135446Strhodes port = ns_g_port; 4200135446Strhodes } else { 4201135446Strhodes result = ns_config_getport(config, &port); 4202135446Strhodes if (result != ISC_R_SUCCESS) 4203135446Strhodes return (result); 4204135446Strhodes } 4205135446Strhodes } else { 4206135446Strhodes if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 4207135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 4208135446Strhodes "port value '%u' is out of range", 4209135446Strhodes cfg_obj_asuint32(portobj)); 4210135446Strhodes return (ISC_R_RANGE); 4211135446Strhodes } 4212135446Strhodes port = (in_port_t)cfg_obj_asuint32(portobj); 4213135446Strhodes } 4214135446Strhodes 4215135446Strhodes result = ns_listenelt_create(mctx, port, NULL, &delt); 4216135446Strhodes if (result != ISC_R_SUCCESS) 4217135446Strhodes return (result); 4218135446Strhodes 4219170222Sdougb result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), 4220170222Sdougb config, ns_g_lctx, actx, mctx, &delt->acl); 4221135446Strhodes if (result != ISC_R_SUCCESS) { 4222135446Strhodes ns_listenelt_destroy(delt); 4223135446Strhodes return (result); 4224135446Strhodes } 4225135446Strhodes *target = delt; 4226135446Strhodes return (ISC_R_SUCCESS); 4227135446Strhodes} 4228135446Strhodes 4229135446Strhodesisc_result_t 4230135446Strhodesns_server_dumpstats(ns_server_t *server) { 4231135446Strhodes isc_result_t result; 4232135446Strhodes dns_zone_t *zone, *next; 4233135446Strhodes isc_stdtime_t now; 4234135446Strhodes FILE *fp = NULL; 4235135446Strhodes int i; 4236135446Strhodes int ncounters; 4237135446Strhodes 4238135446Strhodes isc_stdtime_get(&now); 4239135446Strhodes 4240135446Strhodes CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 4241135446Strhodes "could not open statistics dump file", server->statsfile); 4242135446Strhodes 4243135446Strhodes ncounters = DNS_STATS_NCOUNTERS; 4244135446Strhodes fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); 4245135446Strhodes 4246135446Strhodes for (i = 0; i < ncounters; i++) 4247135446Strhodes fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", 4248135446Strhodes dns_statscounter_names[i], 4249135446Strhodes server->querystats[i]); 4250135446Strhodes 4251135446Strhodes zone = NULL; 4252135446Strhodes for (result = dns_zone_first(server->zonemgr, &zone); 4253135446Strhodes result == ISC_R_SUCCESS; 4254135446Strhodes next = NULL, result = dns_zone_next(zone, &next), zone = next) 4255135446Strhodes { 4256135446Strhodes isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); 4257135446Strhodes if (zonestats != NULL) { 4258135446Strhodes char zonename[DNS_NAME_FORMATSIZE]; 4259135446Strhodes dns_view_t *view; 4260135446Strhodes char *viewname; 4261135446Strhodes 4262135446Strhodes dns_name_format(dns_zone_getorigin(zone), 4263135446Strhodes zonename, sizeof(zonename)); 4264135446Strhodes view = dns_zone_getview(zone); 4265135446Strhodes viewname = view->name; 4266135446Strhodes for (i = 0; i < ncounters; i++) { 4267135446Strhodes fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT 4268135446Strhodes "u %s", 4269135446Strhodes dns_statscounter_names[i], 4270135446Strhodes zonestats[i], 4271135446Strhodes zonename); 4272135446Strhodes if (strcmp(viewname, "_default") != 0) 4273135446Strhodes fprintf(fp, " %s", viewname); 4274135446Strhodes fprintf(fp, "\n"); 4275135446Strhodes } 4276135446Strhodes } 4277135446Strhodes } 4278135446Strhodes if (result == ISC_R_NOMORE) 4279135446Strhodes result = ISC_R_SUCCESS; 4280135446Strhodes CHECK(result); 4281135446Strhodes 4282135446Strhodes fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); 4283135446Strhodes 4284135446Strhodes cleanup: 4285135446Strhodes if (fp != NULL) 4286135446Strhodes (void)isc_stdio_close(fp); 4287135446Strhodes return (result); 4288135446Strhodes} 4289135446Strhodes 4290135446Strhodesstatic isc_result_t 4291135446Strhodesadd_zone_tolist(dns_zone_t *zone, void *uap) { 4292135446Strhodes struct dumpcontext *dctx = uap; 4293135446Strhodes struct zonelistentry *zle; 4294135446Strhodes 4295135446Strhodes zle = isc_mem_get(dctx->mctx, sizeof *zle); 4296135446Strhodes if (zle == NULL) 4297135446Strhodes return (ISC_R_NOMEMORY); 4298135446Strhodes zle->zone = NULL; 4299135446Strhodes dns_zone_attach(zone, &zle->zone); 4300135446Strhodes ISC_LINK_INIT(zle, link); 4301135446Strhodes ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 4302135446Strhodes return (ISC_R_SUCCESS); 4303135446Strhodes} 4304135446Strhodes 4305135446Strhodesstatic isc_result_t 4306135446Strhodesadd_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 4307135446Strhodes struct viewlistentry *vle; 4308135446Strhodes isc_result_t result = ISC_R_SUCCESS; 4309135446Strhodes 4310153816Sdougb /* 4311153816Sdougb * Prevent duplicate views. 4312153816Sdougb */ 4313153816Sdougb for (vle = ISC_LIST_HEAD(dctx->viewlist); 4314153816Sdougb vle != NULL; 4315153816Sdougb vle = ISC_LIST_NEXT(vle, link)) 4316153816Sdougb if (vle->view == view) 4317153816Sdougb return (ISC_R_SUCCESS); 4318153816Sdougb 4319135446Strhodes vle = isc_mem_get(dctx->mctx, sizeof *vle); 4320135446Strhodes if (vle == NULL) 4321135446Strhodes return (ISC_R_NOMEMORY); 4322135446Strhodes vle->view = NULL; 4323135446Strhodes dns_view_attach(view, &vle->view); 4324135446Strhodes ISC_LINK_INIT(vle, link); 4325135446Strhodes ISC_LIST_INIT(vle->zonelist); 4326135446Strhodes ISC_LIST_APPEND(dctx->viewlist, vle, link); 4327135446Strhodes if (dctx->dumpzones) 4328135446Strhodes result = dns_zt_apply(view->zonetable, ISC_TRUE, 4329135446Strhodes add_zone_tolist, dctx); 4330135446Strhodes return (result); 4331135446Strhodes} 4332135446Strhodes 4333135446Strhodesstatic void 4334135446Strhodesdumpcontext_destroy(struct dumpcontext *dctx) { 4335135446Strhodes struct viewlistentry *vle; 4336135446Strhodes struct zonelistentry *zle; 4337135446Strhodes 4338135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 4339135446Strhodes while (vle != NULL) { 4340135446Strhodes ISC_LIST_UNLINK(dctx->viewlist, vle, link); 4341135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 4342135446Strhodes while (zle != NULL) { 4343135446Strhodes ISC_LIST_UNLINK(vle->zonelist, zle, link); 4344135446Strhodes dns_zone_detach(&zle->zone); 4345135446Strhodes isc_mem_put(dctx->mctx, zle, sizeof *zle); 4346135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 4347135446Strhodes } 4348135446Strhodes dns_view_detach(&vle->view); 4349135446Strhodes isc_mem_put(dctx->mctx, vle, sizeof *vle); 4350135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 4351135446Strhodes } 4352135446Strhodes if (dctx->version != NULL) 4353135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 4354135446Strhodes if (dctx->db != NULL) 4355135446Strhodes dns_db_detach(&dctx->db); 4356135446Strhodes if (dctx->cache != NULL) 4357135446Strhodes dns_db_detach(&dctx->cache); 4358135446Strhodes if (dctx->task != NULL) 4359135446Strhodes isc_task_detach(&dctx->task); 4360135446Strhodes if (dctx->fp != NULL) 4361135446Strhodes (void)isc_stdio_close(dctx->fp); 4362135446Strhodes if (dctx->mdctx != NULL) 4363135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 4364135446Strhodes isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 4365135446Strhodes} 4366135446Strhodes 4367135446Strhodesstatic void 4368135446Strhodesdumpdone(void *arg, isc_result_t result) { 4369135446Strhodes struct dumpcontext *dctx = arg; 4370135446Strhodes char buf[1024+32]; 4371135446Strhodes const dns_master_style_t *style; 4372135446Strhodes 4373135446Strhodes if (result != ISC_R_SUCCESS) 4374135446Strhodes goto cleanup; 4375135446Strhodes if (dctx->mdctx != NULL) 4376135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 4377135446Strhodes if (dctx->view == NULL) { 4378135446Strhodes dctx->view = ISC_LIST_HEAD(dctx->viewlist); 4379135446Strhodes if (dctx->view == NULL) 4380135446Strhodes goto done; 4381135446Strhodes INSIST(dctx->zone == NULL); 4382153816Sdougb } else 4383153816Sdougb goto resume; 4384135446Strhodes nextview: 4385135446Strhodes fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 4386153816Sdougb resume: 4387135446Strhodes if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) { 4388135446Strhodes style = &dns_master_style_cache; 4389135446Strhodes /* start cache dump */ 4390135446Strhodes if (dctx->view->view->cachedb != NULL) 4391135446Strhodes dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 4392135446Strhodes if (dctx->cache != NULL) { 4393135446Strhodes 4394135446Strhodes fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n", 4395135446Strhodes dctx->view->view->name); 4396135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 4397135446Strhodes dctx->cache, NULL, 4398135446Strhodes style, dctx->fp, 4399135446Strhodes dctx->task, 4400135446Strhodes dumpdone, dctx, 4401135446Strhodes &dctx->mdctx); 4402135446Strhodes if (result == DNS_R_CONTINUE) 4403135446Strhodes return; 4404135446Strhodes if (result == ISC_R_NOTIMPLEMENTED) 4405135446Strhodes fprintf(dctx->fp, "; %s\n", 4406135446Strhodes dns_result_totext(result)); 4407135446Strhodes else if (result != ISC_R_SUCCESS) 4408135446Strhodes goto cleanup; 4409135446Strhodes } 4410135446Strhodes } 4411135446Strhodes if (dctx->cache != NULL) { 4412135446Strhodes dns_adb_dump(dctx->view->view->adb, dctx->fp); 4413135446Strhodes dns_db_detach(&dctx->cache); 4414135446Strhodes } 4415135446Strhodes if (dctx->dumpzones) { 4416135446Strhodes style = &dns_master_style_full; 4417135446Strhodes nextzone: 4418135446Strhodes if (dctx->version != NULL) 4419135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, 4420135446Strhodes ISC_FALSE); 4421135446Strhodes if (dctx->db != NULL) 4422135446Strhodes dns_db_detach(&dctx->db); 4423135446Strhodes if (dctx->zone == NULL) 4424135446Strhodes dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 4425135446Strhodes else 4426135446Strhodes dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 4427135446Strhodes if (dctx->zone != NULL) { 4428135446Strhodes /* start zone dump */ 4429135446Strhodes dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 4430135446Strhodes fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 4431135446Strhodes result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 4432135446Strhodes if (result != ISC_R_SUCCESS) { 4433135446Strhodes fprintf(dctx->fp, "; %s\n", 4434135446Strhodes dns_result_totext(result)); 4435135446Strhodes goto nextzone; 4436135446Strhodes } 4437135446Strhodes dns_db_currentversion(dctx->db, &dctx->version); 4438135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 4439135446Strhodes dctx->db, 4440135446Strhodes dctx->version, 4441135446Strhodes style, dctx->fp, 4442135446Strhodes dctx->task, 4443135446Strhodes dumpdone, dctx, 4444135446Strhodes &dctx->mdctx); 4445135446Strhodes if (result == DNS_R_CONTINUE) 4446135446Strhodes return; 4447153816Sdougb if (result == ISC_R_NOTIMPLEMENTED) { 4448135446Strhodes fprintf(dctx->fp, "; %s\n", 4449135446Strhodes dns_result_totext(result)); 4450153816Sdougb result = ISC_R_SUCCESS; 4451153816Sdougb goto nextzone; 4452153816Sdougb } 4453135446Strhodes if (result != ISC_R_SUCCESS) 4454135446Strhodes goto cleanup; 4455135446Strhodes } 4456135446Strhodes } 4457135446Strhodes if (dctx->view != NULL) 4458135446Strhodes dctx->view = ISC_LIST_NEXT(dctx->view, link); 4459135446Strhodes if (dctx->view != NULL) 4460135446Strhodes goto nextview; 4461135446Strhodes done: 4462135446Strhodes fprintf(dctx->fp, "; Dump complete\n"); 4463135446Strhodes result = isc_stdio_flush(dctx->fp); 4464135446Strhodes if (result == ISC_R_SUCCESS) 4465135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4466135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4467135446Strhodes "dumpdb complete"); 4468135446Strhodes cleanup: 4469135446Strhodes if (result != ISC_R_SUCCESS) 4470135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4471135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4472135446Strhodes "dumpdb failed: %s", dns_result_totext(result)); 4473135446Strhodes dumpcontext_destroy(dctx); 4474135446Strhodes} 4475135446Strhodes 4476135446Strhodesisc_result_t 4477135446Strhodesns_server_dumpdb(ns_server_t *server, char *args) { 4478135446Strhodes struct dumpcontext *dctx = NULL; 4479135446Strhodes dns_view_t *view; 4480135446Strhodes isc_result_t result; 4481135446Strhodes char *ptr; 4482135446Strhodes const char *sep; 4483135446Strhodes 4484165071Sdougb /* Skip the command name. */ 4485165071Sdougb ptr = next_token(&args, " \t"); 4486165071Sdougb if (ptr == NULL) 4487165071Sdougb return (ISC_R_UNEXPECTEDEND); 4488165071Sdougb 4489135446Strhodes dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 4490135446Strhodes if (dctx == NULL) 4491135446Strhodes return (ISC_R_NOMEMORY); 4492135446Strhodes 4493135446Strhodes dctx->mctx = server->mctx; 4494135446Strhodes dctx->dumpcache = ISC_TRUE; 4495135446Strhodes dctx->dumpzones = ISC_FALSE; 4496135446Strhodes dctx->fp = NULL; 4497135446Strhodes ISC_LIST_INIT(dctx->viewlist); 4498135446Strhodes dctx->view = NULL; 4499135446Strhodes dctx->zone = NULL; 4500135446Strhodes dctx->cache = NULL; 4501135446Strhodes dctx->mdctx = NULL; 4502135446Strhodes dctx->db = NULL; 4503135446Strhodes dctx->cache = NULL; 4504135446Strhodes dctx->task = NULL; 4505135446Strhodes dctx->version = NULL; 4506135446Strhodes isc_task_attach(server->task, &dctx->task); 4507135446Strhodes 4508135446Strhodes CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 4509135446Strhodes "could not open dump file", server->dumpfile); 4510135446Strhodes 4511135446Strhodes sep = (args == NULL) ? "" : ": "; 4512135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4513135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4514135446Strhodes "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 4515135446Strhodes 4516135446Strhodes ptr = next_token(&args, " \t"); 4517135446Strhodes if (ptr != NULL && strcmp(ptr, "-all") == 0) { 4518135446Strhodes dctx->dumpzones = ISC_TRUE; 4519135446Strhodes dctx->dumpcache = ISC_TRUE; 4520135446Strhodes ptr = next_token(&args, " \t"); 4521135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 4522135446Strhodes dctx->dumpzones = ISC_FALSE; 4523135446Strhodes dctx->dumpcache = ISC_TRUE; 4524135446Strhodes ptr = next_token(&args, " \t"); 4525135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 4526135446Strhodes dctx->dumpzones = ISC_TRUE; 4527135446Strhodes dctx->dumpcache = ISC_FALSE; 4528135446Strhodes ptr = next_token(&args, " \t"); 4529135446Strhodes } 4530135446Strhodes 4531153816Sdougb nextview: 4532135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 4533135446Strhodes view != NULL; 4534135446Strhodes view = ISC_LIST_NEXT(view, link)) 4535135446Strhodes { 4536135446Strhodes if (ptr != NULL && strcmp(view->name, ptr) != 0) 4537135446Strhodes continue; 4538135446Strhodes CHECK(add_view_tolist(dctx, view)); 4539135446Strhodes } 4540153816Sdougb if (ptr != NULL) { 4541153816Sdougb ptr = next_token(&args, " \t"); 4542153816Sdougb if (ptr != NULL) 4543153816Sdougb goto nextview; 4544153816Sdougb } 4545135446Strhodes dumpdone(dctx, ISC_R_SUCCESS); 4546135446Strhodes return (ISC_R_SUCCESS); 4547135446Strhodes 4548135446Strhodes cleanup: 4549135446Strhodes if (dctx != NULL) 4550135446Strhodes dumpcontext_destroy(dctx); 4551135446Strhodes return (result); 4552135446Strhodes} 4553135446Strhodes 4554135446Strhodesisc_result_t 4555135446Strhodesns_server_dumprecursing(ns_server_t *server) { 4556135446Strhodes FILE *fp = NULL; 4557135446Strhodes isc_result_t result; 4558135446Strhodes 4559135446Strhodes CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 4560135446Strhodes "could not open dump file", server->recfile); 4561135446Strhodes fprintf(fp,";\n; Recursing Queries\n;\n"); 4562135446Strhodes ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 4563135446Strhodes fprintf(fp, "; Dump complete\n"); 4564135446Strhodes 4565135446Strhodes cleanup: 4566135446Strhodes if (fp != NULL) 4567135446Strhodes result = isc_stdio_close(fp); 4568135446Strhodes return (result); 4569135446Strhodes} 4570135446Strhodes 4571135446Strhodesisc_result_t 4572135446Strhodesns_server_setdebuglevel(ns_server_t *server, char *args) { 4573135446Strhodes char *ptr; 4574135446Strhodes char *levelstr; 4575135446Strhodes char *endp; 4576135446Strhodes long newlevel; 4577135446Strhodes 4578135446Strhodes UNUSED(server); 4579135446Strhodes 4580135446Strhodes /* Skip the command name. */ 4581135446Strhodes ptr = next_token(&args, " \t"); 4582135446Strhodes if (ptr == NULL) 4583135446Strhodes return (ISC_R_UNEXPECTEDEND); 4584135446Strhodes 4585135446Strhodes /* Look for the new level name. */ 4586135446Strhodes levelstr = next_token(&args, " \t"); 4587135446Strhodes if (levelstr == NULL) { 4588135446Strhodes if (ns_g_debuglevel < 99) 4589135446Strhodes ns_g_debuglevel++; 4590135446Strhodes } else { 4591135446Strhodes newlevel = strtol(levelstr, &endp, 10); 4592135446Strhodes if (*endp != '\0' || newlevel < 0 || newlevel > 99) 4593135446Strhodes return (ISC_R_RANGE); 4594135446Strhodes ns_g_debuglevel = (unsigned int)newlevel; 4595135446Strhodes } 4596135446Strhodes isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 4597135446Strhodes return (ISC_R_SUCCESS); 4598135446Strhodes} 4599135446Strhodes 4600135446Strhodesisc_result_t 4601170222Sdougbns_server_validation(ns_server_t *server, char *args) { 4602170222Sdougb char *ptr, *viewname; 4603170222Sdougb dns_view_t *view; 4604170222Sdougb isc_boolean_t changed = ISC_FALSE; 4605170222Sdougb isc_result_t result; 4606170222Sdougb isc_boolean_t enable; 4607170222Sdougb 4608170222Sdougb /* Skip the command name. */ 4609170222Sdougb ptr = next_token(&args, " \t"); 4610170222Sdougb if (ptr == NULL) 4611170222Sdougb return (ISC_R_UNEXPECTEDEND); 4612170222Sdougb 4613170222Sdougb /* Find out what we are to do. */ 4614170222Sdougb ptr = next_token(&args, " \t"); 4615170222Sdougb if (ptr == NULL) 4616170222Sdougb return (ISC_R_UNEXPECTEDEND); 4617170222Sdougb 4618170222Sdougb if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || 4619170222Sdougb !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) 4620170222Sdougb enable = ISC_TRUE; 4621170222Sdougb else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || 4622170222Sdougb !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) 4623170222Sdougb enable = ISC_FALSE; 4624170222Sdougb else 4625170222Sdougb return (DNS_R_SYNTAX); 4626170222Sdougb 4627170222Sdougb /* Look for the view name. */ 4628170222Sdougb viewname = next_token(&args, " \t"); 4629170222Sdougb 4630170222Sdougb result = isc_task_beginexclusive(server->task); 4631170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 4632170222Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 4633170222Sdougb view != NULL; 4634170222Sdougb view = ISC_LIST_NEXT(view, link)) 4635170222Sdougb { 4636170222Sdougb if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4637170222Sdougb continue; 4638170222Sdougb result = dns_view_flushcache(view); 4639170222Sdougb if (result != ISC_R_SUCCESS) 4640170222Sdougb goto out; 4641170222Sdougb view->enablevalidation = enable; 4642170222Sdougb changed = ISC_TRUE; 4643170222Sdougb } 4644170222Sdougb if (changed) 4645170222Sdougb result = ISC_R_SUCCESS; 4646170222Sdougb else 4647170222Sdougb result = ISC_R_FAILURE; 4648170222Sdougb out: 4649170222Sdougb isc_task_endexclusive(server->task); 4650170222Sdougb return (result); 4651170222Sdougb} 4652170222Sdougb 4653170222Sdougbisc_result_t 4654135446Strhodesns_server_flushcache(ns_server_t *server, char *args) { 4655135446Strhodes char *ptr, *viewname; 4656135446Strhodes dns_view_t *view; 4657174187Sdougb isc_boolean_t flushed; 4658174187Sdougb isc_boolean_t found; 4659135446Strhodes isc_result_t result; 4660135446Strhodes 4661135446Strhodes /* Skip the command name. */ 4662135446Strhodes ptr = next_token(&args, " \t"); 4663135446Strhodes if (ptr == NULL) 4664135446Strhodes return (ISC_R_UNEXPECTEDEND); 4665135446Strhodes 4666135446Strhodes /* Look for the view name. */ 4667135446Strhodes viewname = next_token(&args, " \t"); 4668135446Strhodes 4669135446Strhodes result = isc_task_beginexclusive(server->task); 4670135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 4671174187Sdougb flushed = ISC_TRUE; 4672174187Sdougb found = ISC_FALSE; 4673135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 4674135446Strhodes view != NULL; 4675135446Strhodes view = ISC_LIST_NEXT(view, link)) 4676135446Strhodes { 4677135446Strhodes if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4678135446Strhodes continue; 4679174187Sdougb found = ISC_TRUE; 4680135446Strhodes result = dns_view_flushcache(view); 4681135446Strhodes if (result != ISC_R_SUCCESS) 4682174187Sdougb flushed = ISC_FALSE; 4683135446Strhodes } 4684174187Sdougb if (flushed && found) { 4685135446Strhodes result = ISC_R_SUCCESS; 4686174187Sdougb } else { 4687174187Sdougb if (!found) 4688174187Sdougb result = ISC_R_NOTFOUND; 4689174187Sdougb else 4690174187Sdougb result = ISC_R_FAILURE; 4691174187Sdougb } 4692135446Strhodes isc_task_endexclusive(server->task); 4693135446Strhodes return (result); 4694135446Strhodes} 4695135446Strhodes 4696135446Strhodesisc_result_t 4697135446Strhodesns_server_flushname(ns_server_t *server, char *args) { 4698135446Strhodes char *ptr, *target, *viewname; 4699135446Strhodes dns_view_t *view; 4700174187Sdougb isc_boolean_t flushed; 4701174187Sdougb isc_boolean_t found; 4702135446Strhodes isc_result_t result; 4703135446Strhodes isc_buffer_t b; 4704135446Strhodes dns_fixedname_t fixed; 4705135446Strhodes dns_name_t *name; 4706135446Strhodes 4707135446Strhodes /* Skip the command name. */ 4708135446Strhodes ptr = next_token(&args, " \t"); 4709135446Strhodes if (ptr == NULL) 4710135446Strhodes return (ISC_R_UNEXPECTEDEND); 4711135446Strhodes 4712135446Strhodes /* Find the domain name to flush. */ 4713135446Strhodes target = next_token(&args, " \t"); 4714135446Strhodes if (target == NULL) 4715135446Strhodes return (ISC_R_UNEXPECTEDEND); 4716135446Strhodes 4717135446Strhodes isc_buffer_init(&b, target, strlen(target)); 4718135446Strhodes isc_buffer_add(&b, strlen(target)); 4719135446Strhodes dns_fixedname_init(&fixed); 4720135446Strhodes name = dns_fixedname_name(&fixed); 4721135446Strhodes result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); 4722135446Strhodes if (result != ISC_R_SUCCESS) 4723135446Strhodes return (result); 4724135446Strhodes 4725135446Strhodes /* Look for the view name. */ 4726135446Strhodes viewname = next_token(&args, " \t"); 4727135446Strhodes 4728135446Strhodes result = isc_task_beginexclusive(server->task); 4729135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 4730135446Strhodes flushed = ISC_TRUE; 4731174187Sdougb found = ISC_FALSE; 4732135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 4733135446Strhodes view != NULL; 4734135446Strhodes view = ISC_LIST_NEXT(view, link)) 4735135446Strhodes { 4736135446Strhodes if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4737135446Strhodes continue; 4738174187Sdougb found = ISC_TRUE; 4739135446Strhodes result = dns_view_flushname(view, name); 4740135446Strhodes if (result != ISC_R_SUCCESS) 4741135446Strhodes flushed = ISC_FALSE; 4742135446Strhodes } 4743174187Sdougb if (flushed && found) 4744135446Strhodes result = ISC_R_SUCCESS; 4745174187Sdougb else if (!found) 4746174187Sdougb result = ISC_R_NOTFOUND; 4747135446Strhodes else 4748135446Strhodes result = ISC_R_FAILURE; 4749135446Strhodes isc_task_endexclusive(server->task); 4750135446Strhodes return (result); 4751135446Strhodes} 4752135446Strhodes 4753135446Strhodesisc_result_t 4754135446Strhodesns_server_status(ns_server_t *server, isc_buffer_t *text) { 4755135446Strhodes int zonecount, xferrunning, xferdeferred, soaqueries; 4756135446Strhodes unsigned int n; 4757135446Strhodes 4758135446Strhodes zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 4759135446Strhodes xferrunning = dns_zonemgr_getcount(server->zonemgr, 4760135446Strhodes DNS_ZONESTATE_XFERRUNNING); 4761135446Strhodes xferdeferred = dns_zonemgr_getcount(server->zonemgr, 4762135446Strhodes DNS_ZONESTATE_XFERDEFERRED); 4763135446Strhodes soaqueries = dns_zonemgr_getcount(server->zonemgr, 4764135446Strhodes DNS_ZONESTATE_SOAQUERY); 4765135446Strhodes n = snprintf((char *)isc_buffer_used(text), 4766135446Strhodes isc_buffer_availablelength(text), 4767135446Strhodes "number of zones: %u\n" 4768135446Strhodes "debug level: %d\n" 4769135446Strhodes "xfers running: %u\n" 4770135446Strhodes "xfers deferred: %u\n" 4771135446Strhodes "soa queries in progress: %u\n" 4772135446Strhodes "query logging is %s\n" 4773170222Sdougb "recursive clients: %d/%d/%d\n" 4774135446Strhodes "tcp clients: %d/%d\n" 4775135446Strhodes "server is up and running", 4776135446Strhodes zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 4777135446Strhodes soaqueries, server->log_queries ? "ON" : "OFF", 4778170222Sdougb server->recursionquota.used, server->recursionquota.soft, 4779170222Sdougb server->recursionquota.max, 4780135446Strhodes server->tcpquota.used, server->tcpquota.max); 4781135446Strhodes if (n >= isc_buffer_availablelength(text)) 4782135446Strhodes return (ISC_R_NOSPACE); 4783135446Strhodes isc_buffer_add(text, n); 4784135446Strhodes return (ISC_R_SUCCESS); 4785135446Strhodes} 4786135446Strhodes 4787135446Strhodes/* 4788170222Sdougb * Act on a "freeze" or "thaw" command from the command channel. 4789135446Strhodes */ 4790135446Strhodesisc_result_t 4791135446Strhodesns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { 4792170222Sdougb isc_result_t result, tresult; 4793135446Strhodes dns_zone_t *zone = NULL; 4794135446Strhodes dns_zonetype_t type; 4795135446Strhodes char classstr[DNS_RDATACLASS_FORMATSIZE]; 4796135446Strhodes char zonename[DNS_NAME_FORMATSIZE]; 4797135446Strhodes dns_view_t *view; 4798135446Strhodes char *journal; 4799135446Strhodes const char *vname, *sep; 4800135446Strhodes isc_boolean_t frozen; 4801135446Strhodes 4802135446Strhodes result = zone_from_args(server, args, &zone); 4803135446Strhodes if (result != ISC_R_SUCCESS) 4804135446Strhodes return (result); 4805170222Sdougb if (zone == NULL) { 4806170222Sdougb result = isc_task_beginexclusive(server->task); 4807170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 4808170222Sdougb tresult = ISC_R_SUCCESS; 4809170222Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 4810170222Sdougb view != NULL; 4811170222Sdougb view = ISC_LIST_NEXT(view, link)) { 4812170222Sdougb result = dns_view_freezezones(view, freeze); 4813170222Sdougb if (result != ISC_R_SUCCESS && 4814170222Sdougb tresult == ISC_R_SUCCESS) 4815170222Sdougb tresult = result; 4816170222Sdougb } 4817170222Sdougb isc_task_endexclusive(server->task); 4818170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4819170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4820170222Sdougb "%s all zones: %s", 4821170222Sdougb freeze ? "freezing" : "thawing", 4822170222Sdougb isc_result_totext(tresult)); 4823170222Sdougb return (tresult); 4824170222Sdougb } 4825135446Strhodes type = dns_zone_gettype(zone); 4826135446Strhodes if (type != dns_zone_master) { 4827135446Strhodes dns_zone_detach(&zone); 4828135446Strhodes return (ISC_R_NOTFOUND); 4829135446Strhodes } 4830135446Strhodes 4831135446Strhodes frozen = dns_zone_getupdatedisabled(zone); 4832135446Strhodes if (freeze) { 4833135446Strhodes if (frozen) 4834135446Strhodes result = DNS_R_FROZEN; 4835135446Strhodes if (result == ISC_R_SUCCESS) 4836135446Strhodes result = dns_zone_flush(zone); 4837135446Strhodes if (result == ISC_R_SUCCESS) { 4838135446Strhodes journal = dns_zone_getjournal(zone); 4839135446Strhodes if (journal != NULL) 4840135446Strhodes (void)isc_file_remove(journal); 4841135446Strhodes } 4842135446Strhodes } else { 4843135446Strhodes if (frozen) { 4844135446Strhodes result = dns_zone_load(zone); 4845135446Strhodes if (result == DNS_R_CONTINUE || 4846135446Strhodes result == DNS_R_UPTODATE) 4847135446Strhodes result = ISC_R_SUCCESS; 4848135446Strhodes } 4849135446Strhodes } 4850135446Strhodes if (result == ISC_R_SUCCESS) 4851135446Strhodes dns_zone_setupdatedisabled(zone, freeze); 4852135446Strhodes 4853135446Strhodes view = dns_zone_getview(zone); 4854135446Strhodes if (strcmp(view->name, "_bind") == 0 || 4855135446Strhodes strcmp(view->name, "_default") == 0) 4856135446Strhodes { 4857135446Strhodes vname = ""; 4858135446Strhodes sep = ""; 4859135446Strhodes } else { 4860135446Strhodes vname = view->name; 4861135446Strhodes sep = " "; 4862135446Strhodes } 4863135446Strhodes dns_rdataclass_format(dns_zone_getclass(zone), classstr, 4864135446Strhodes sizeof(classstr)); 4865135446Strhodes dns_name_format(dns_zone_getorigin(zone), 4866135446Strhodes zonename, sizeof(zonename)); 4867135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4868135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4869135446Strhodes "%s zone '%s/%s'%s%s: %s", 4870170222Sdougb freeze ? "freezing" : "thawing", 4871135446Strhodes zonename, classstr, sep, vname, 4872135446Strhodes isc_result_totext(result)); 4873135446Strhodes dns_zone_detach(&zone); 4874135446Strhodes return (result); 4875135446Strhodes} 4876153816Sdougb 4877153816Sdougb#ifdef HAVE_LIBSCF 4878153816Sdougb/* 4879153816Sdougb * This function adds a message for rndc to echo if named 4880153816Sdougb * is managed by smf and is also running chroot. 4881153816Sdougb */ 4882153816Sdougbisc_result_t 4883153816Sdougbns_smf_add_message(isc_buffer_t *text) { 4884153816Sdougb unsigned int n; 4885153816Sdougb 4886153816Sdougb n = snprintf((char *)isc_buffer_used(text), 4887153816Sdougb isc_buffer_availablelength(text), 4888153816Sdougb "use svcadm(1M) to manage named"); 4889153816Sdougb if (n >= isc_buffer_availablelength(text)) 4890153816Sdougb return (ISC_R_NOSPACE); 4891153816Sdougb isc_buffer_add(text, n); 4892153816Sdougb return (ISC_R_SUCCESS); 4893153816Sdougb} 4894153816Sdougb#endif /* HAVE_LIBSCF */ 4895