server.c revision 174187
1/* 2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: server.c,v 1.419.18.57 2007/08/28 07:20:01 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <stdlib.h> 25 26#include <isc/app.h> 27#include <isc/base64.h> 28#include <isc/dir.h> 29#include <isc/entropy.h> 30#include <isc/file.h> 31#include <isc/hash.h> 32#include <isc/lex.h> 33#include <isc/parseint.h> 34#include <isc/print.h> 35#include <isc/resource.h> 36#include <isc/stdio.h> 37#include <isc/string.h> 38#include <isc/task.h> 39#include <isc/timer.h> 40#include <isc/util.h> 41 42#include <isccfg/namedconf.h> 43 44#include <bind9/check.h> 45 46#include <dns/acache.h> 47#include <dns/adb.h> 48#include <dns/cache.h> 49#include <dns/db.h> 50#include <dns/dispatch.h> 51#ifdef DLZ 52#include <dns/dlz.h> 53#endif 54#include <dns/forward.h> 55#include <dns/journal.h> 56#include <dns/keytable.h> 57#include <dns/lib.h> 58#include <dns/master.h> 59#include <dns/masterdump.h> 60#include <dns/order.h> 61#include <dns/peer.h> 62#include <dns/portlist.h> 63#include <dns/rdataclass.h> 64#include <dns/rdataset.h> 65#include <dns/rdatastruct.h> 66#include <dns/resolver.h> 67#include <dns/rootns.h> 68#include <dns/secalg.h> 69#include <dns/stats.h> 70#include <dns/tkey.h> 71#include <dns/view.h> 72#include <dns/zone.h> 73#include <dns/zt.h> 74 75#include <dst/dst.h> 76#include <dst/result.h> 77 78#include <named/client.h> 79#include <named/config.h> 80#include <named/control.h> 81#include <named/interfacemgr.h> 82#include <named/log.h> 83#include <named/logconf.h> 84#include <named/lwresd.h> 85#include <named/main.h> 86#include <named/os.h> 87#include <named/server.h> 88#include <named/tkeyconf.h> 89#include <named/tsigconf.h> 90#include <named/zoneconf.h> 91#ifdef HAVE_LIBSCF 92#include <named/ns_smf_globals.h> 93#include <stdlib.h> 94#endif 95 96/*% 97 * Check an operation for failure. Assumes that the function 98 * using it has a 'result' variable and a 'cleanup' label. 99 */ 100#define CHECK(op) \ 101 do { result = (op); \ 102 if (result != ISC_R_SUCCESS) goto cleanup; \ 103 } while (0) 104 105#define CHECKM(op, msg) \ 106 do { result = (op); \ 107 if (result != ISC_R_SUCCESS) { \ 108 isc_log_write(ns_g_lctx, \ 109 NS_LOGCATEGORY_GENERAL, \ 110 NS_LOGMODULE_SERVER, \ 111 ISC_LOG_ERROR, \ 112 "%s: %s", msg, \ 113 isc_result_totext(result)); \ 114 goto cleanup; \ 115 } \ 116 } while (0) \ 117 118#define CHECKMF(op, msg, file) \ 119 do { result = (op); \ 120 if (result != ISC_R_SUCCESS) { \ 121 isc_log_write(ns_g_lctx, \ 122 NS_LOGCATEGORY_GENERAL, \ 123 NS_LOGMODULE_SERVER, \ 124 ISC_LOG_ERROR, \ 125 "%s '%s': %s", msg, file, \ 126 isc_result_totext(result)); \ 127 goto cleanup; \ 128 } \ 129 } while (0) \ 130 131#define CHECKFATAL(op, msg) \ 132 do { result = (op); \ 133 if (result != ISC_R_SUCCESS) \ 134 fatal(msg, result); \ 135 } while (0) \ 136 137struct ns_dispatch { 138 isc_sockaddr_t addr; 139 unsigned int dispatchgen; 140 dns_dispatch_t *dispatch; 141 ISC_LINK(struct ns_dispatch) link; 142}; 143 144struct dumpcontext { 145 isc_mem_t *mctx; 146 isc_boolean_t dumpcache; 147 isc_boolean_t dumpzones; 148 FILE *fp; 149 ISC_LIST(struct viewlistentry) viewlist; 150 struct viewlistentry *view; 151 struct zonelistentry *zone; 152 dns_dumpctx_t *mdctx; 153 dns_db_t *db; 154 dns_db_t *cache; 155 isc_task_t *task; 156 dns_dbversion_t *version; 157}; 158 159struct viewlistentry { 160 dns_view_t *view; 161 ISC_LINK(struct viewlistentry) link; 162 ISC_LIST(struct zonelistentry) zonelist; 163}; 164 165struct zonelistentry { 166 dns_zone_t *zone; 167 ISC_LINK(struct zonelistentry) link; 168}; 169 170/* 171 * These zones should not leak onto the Internet. 172 */ 173static const struct { 174 const char *zone; 175 isc_boolean_t rfc1918; 176} empty_zones[] = { 177#ifdef notyet 178 /* RFC 1918 */ 179 { "10.IN-ADDR.ARPA", ISC_TRUE }, 180 { "16.172.IN-ADDR.ARPA", ISC_TRUE }, 181 { "17.172.IN-ADDR.ARPA", ISC_TRUE }, 182 { "18.172.IN-ADDR.ARPA", ISC_TRUE }, 183 { "19.172.IN-ADDR.ARPA", ISC_TRUE }, 184 { "20.172.IN-ADDR.ARPA", ISC_TRUE }, 185 { "21.172.IN-ADDR.ARPA", ISC_TRUE }, 186 { "22.172.IN-ADDR.ARPA", ISC_TRUE }, 187 { "23.172.IN-ADDR.ARPA", ISC_TRUE }, 188 { "24.172.IN-ADDR.ARPA", ISC_TRUE }, 189 { "25.172.IN-ADDR.ARPA", ISC_TRUE }, 190 { "26.172.IN-ADDR.ARPA", ISC_TRUE }, 191 { "27.172.IN-ADDR.ARPA", ISC_TRUE }, 192 { "28.172.IN-ADDR.ARPA", ISC_TRUE }, 193 { "29.172.IN-ADDR.ARPA", ISC_TRUE }, 194 { "30.172.IN-ADDR.ARPA", ISC_TRUE }, 195 { "31.172.IN-ADDR.ARPA", ISC_TRUE }, 196 { "168.192.IN-ADDR.ARPA", ISC_TRUE }, 197#endif 198 199 /* RFC 3330 */ 200 { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */ 201 { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */ 202 { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */ 203 { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */ 204 205 /* Local IPv6 Unicast Addresses */ 206 { "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 }, 207 { "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 }, 208 /* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */ 209 { "D.F.IP6.ARPA", ISC_FALSE }, 210 { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 211 { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 212 { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 213 { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */ 214 215 { NULL, ISC_FALSE } 216}; 217 218static void 219fatal(const char *msg, isc_result_t result); 220 221static void 222ns_server_reload(isc_task_t *task, isc_event_t *event); 223 224static isc_result_t 225ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 226 cfg_aclconfctx_t *actx, 227 isc_mem_t *mctx, ns_listenelt_t **target); 228static isc_result_t 229ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 230 cfg_aclconfctx_t *actx, 231 isc_mem_t *mctx, ns_listenlist_t **target); 232 233static isc_result_t 234configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 235 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); 236 237static isc_result_t 238configure_alternates(const cfg_obj_t *config, dns_view_t *view, 239 const cfg_obj_t *alternates); 240 241static isc_result_t 242configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 243 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 244 cfg_aclconfctx_t *aclconf); 245 246static void 247end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); 248 249/*% 250 * Configure a single view ACL at '*aclp'. Get its configuration by 251 * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' 252 * (for a global default). 253 */ 254static isc_result_t 255configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, 256 const char *aclname, cfg_aclconfctx_t *actx, 257 isc_mem_t *mctx, dns_acl_t **aclp) 258{ 259 isc_result_t result; 260 const cfg_obj_t *maps[3]; 261 const cfg_obj_t *aclobj = NULL; 262 int i = 0; 263 264 if (*aclp != NULL) 265 dns_acl_detach(aclp); 266 if (vconfig != NULL) 267 maps[i++] = cfg_tuple_get(vconfig, "options"); 268 if (config != NULL) { 269 const cfg_obj_t *options = NULL; 270 (void)cfg_map_get(config, "options", &options); 271 if (options != NULL) 272 maps[i++] = options; 273 } 274 maps[i] = NULL; 275 276 (void)ns_config_get(maps, aclname, &aclobj); 277 if (aclobj == NULL) 278 /* 279 * No value available. *aclp == NULL. 280 */ 281 return (ISC_R_SUCCESS); 282 283 result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 284 actx, mctx, aclp); 285 286 return (result); 287} 288 289static isc_result_t 290configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, 291 dns_keytable_t *keytable, isc_mem_t *mctx) 292{ 293 dns_rdataclass_t viewclass; 294 dns_rdata_dnskey_t keystruct; 295 isc_uint32_t flags, proto, alg; 296 const char *keystr, *keynamestr; 297 unsigned char keydata[4096]; 298 isc_buffer_t keydatabuf; 299 unsigned char rrdata[4096]; 300 isc_buffer_t rrdatabuf; 301 isc_region_t r; 302 dns_fixedname_t fkeyname; 303 dns_name_t *keyname; 304 isc_buffer_t namebuf; 305 isc_result_t result; 306 dst_key_t *dstkey = NULL; 307 308 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 309 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); 310 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); 311 keyname = dns_fixedname_name(&fkeyname); 312 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 313 314 if (vconfig == NULL) 315 viewclass = dns_rdataclass_in; 316 else { 317 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); 318 CHECK(ns_config_getclass(classobj, dns_rdataclass_in, 319 &viewclass)); 320 } 321 keystruct.common.rdclass = viewclass; 322 keystruct.common.rdtype = dns_rdatatype_dnskey; 323 /* 324 * The key data in keystruct is not dynamically allocated. 325 */ 326 keystruct.mctx = NULL; 327 328 ISC_LINK_INIT(&keystruct.common, link); 329 330 if (flags > 0xffff) 331 CHECKM(ISC_R_RANGE, "key flags"); 332 if (proto > 0xff) 333 CHECKM(ISC_R_RANGE, "key protocol"); 334 if (alg > 0xff) 335 CHECKM(ISC_R_RANGE, "key algorithm"); 336 keystruct.flags = (isc_uint16_t)flags; 337 keystruct.protocol = (isc_uint8_t)proto; 338 keystruct.algorithm = (isc_uint8_t)alg; 339 340 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); 341 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 342 343 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 344 CHECK(isc_base64_decodestring(keystr, &keydatabuf)); 345 isc_buffer_usedregion(&keydatabuf, &r); 346 keystruct.datalen = r.length; 347 keystruct.data = r.base; 348 349 if ((keystruct.algorithm == DST_ALG_RSASHA1 || 350 keystruct.algorithm == DST_ALG_RSAMD5) && 351 r.length > 1 && r.base[0] == 1 && r.base[1] == 3) 352 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 353 "trusted key '%s' has a weak exponent", 354 keynamestr); 355 356 CHECK(dns_rdata_fromstruct(NULL, 357 keystruct.common.rdclass, 358 keystruct.common.rdtype, 359 &keystruct, &rrdatabuf)); 360 dns_fixedname_init(&fkeyname); 361 isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); 362 isc_buffer_add(&namebuf, strlen(keynamestr)); 363 CHECK(dns_name_fromtext(keyname, &namebuf, 364 dns_rootname, ISC_FALSE, 365 NULL)); 366 CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, 367 mctx, &dstkey)); 368 369 CHECK(dns_keytable_add(keytable, &dstkey)); 370 INSIST(dstkey == NULL); 371 return (ISC_R_SUCCESS); 372 373 cleanup: 374 if (result == DST_R_NOCRYPTO) { 375 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 376 "ignoring trusted key for '%s': no crypto support", 377 keynamestr); 378 result = ISC_R_SUCCESS; 379 } else { 380 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 381 "configuring trusted key for '%s': %s", 382 keynamestr, isc_result_totext(result)); 383 result = ISC_R_FAILURE; 384 } 385 386 if (dstkey != NULL) 387 dst_key_free(&dstkey); 388 389 return (result); 390} 391 392/*% 393 * Configure DNSSEC keys for a view. Currently used only for 394 * the security roots. 395 * 396 * The per-view configuration values and the server-global defaults are read 397 * from 'vconfig' and 'config'. The variable to be configured is '*target'. 398 */ 399static isc_result_t 400configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, 401 isc_mem_t *mctx, dns_keytable_t **target) 402{ 403 isc_result_t result; 404 const cfg_obj_t *keys = NULL; 405 const cfg_obj_t *voptions = NULL; 406 const cfg_listelt_t *element, *element2; 407 const cfg_obj_t *keylist; 408 const cfg_obj_t *key; 409 dns_keytable_t *keytable = NULL; 410 411 CHECK(dns_keytable_create(mctx, &keytable)); 412 413 if (vconfig != NULL) 414 voptions = cfg_tuple_get(vconfig, "options"); 415 416 keys = NULL; 417 if (voptions != NULL) 418 (void)cfg_map_get(voptions, "trusted-keys", &keys); 419 if (keys == NULL) 420 (void)cfg_map_get(config, "trusted-keys", &keys); 421 422 for (element = cfg_list_first(keys); 423 element != NULL; 424 element = cfg_list_next(element)) 425 { 426 keylist = cfg_listelt_value(element); 427 for (element2 = cfg_list_first(keylist); 428 element2 != NULL; 429 element2 = cfg_list_next(element2)) 430 { 431 key = cfg_listelt_value(element2); 432 CHECK(configure_view_dnsseckey(vconfig, key, 433 keytable, mctx)); 434 } 435 } 436 437 dns_keytable_detach(target); 438 *target = keytable; /* Transfer ownership. */ 439 keytable = NULL; 440 result = ISC_R_SUCCESS; 441 442 cleanup: 443 return (result); 444} 445 446static isc_result_t 447mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) 448{ 449 const cfg_listelt_t *element; 450 const cfg_obj_t *obj; 451 const char *str; 452 dns_fixedname_t fixed; 453 dns_name_t *name; 454 isc_boolean_t value; 455 isc_result_t result; 456 isc_buffer_t b; 457 458 dns_fixedname_init(&fixed); 459 name = dns_fixedname_name(&fixed); 460 for (element = cfg_list_first(mbs); 461 element != NULL; 462 element = cfg_list_next(element)) 463 { 464 obj = cfg_listelt_value(element); 465 str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 466 isc_buffer_init(&b, str, strlen(str)); 467 isc_buffer_add(&b, strlen(str)); 468 CHECK(dns_name_fromtext(name, &b, dns_rootname, 469 ISC_FALSE, NULL)); 470 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); 471 CHECK(dns_resolver_setmustbesecure(resolver, name, value)); 472 } 473 474 result = ISC_R_SUCCESS; 475 476 cleanup: 477 return (result); 478} 479 480/*% 481 * Get a dispatch appropriate for the resolver of a given view. 482 */ 483static isc_result_t 484get_view_querysource_dispatch(const cfg_obj_t **maps, 485 int af, dns_dispatch_t **dispatchp) 486{ 487 isc_result_t result; 488 dns_dispatch_t *disp; 489 isc_sockaddr_t sa; 490 unsigned int attrs, attrmask; 491 const cfg_obj_t *obj = NULL; 492 493 /* 494 * Make compiler happy. 495 */ 496 result = ISC_R_FAILURE; 497 498 switch (af) { 499 case AF_INET: 500 result = ns_config_get(maps, "query-source", &obj); 501 INSIST(result == ISC_R_SUCCESS); 502 break; 503 case AF_INET6: 504 result = ns_config_get(maps, "query-source-v6", &obj); 505 INSIST(result == ISC_R_SUCCESS); 506 break; 507 default: 508 INSIST(0); 509 } 510 511 sa = *(cfg_obj_assockaddr(obj)); 512 INSIST(isc_sockaddr_pf(&sa) == af); 513 514 /* 515 * If we don't support this address family, we're done! 516 */ 517 switch (af) { 518 case AF_INET: 519 result = isc_net_probeipv4(); 520 break; 521 case AF_INET6: 522 result = isc_net_probeipv6(); 523 break; 524 default: 525 INSIST(0); 526 } 527 if (result != ISC_R_SUCCESS) 528 return (ISC_R_SUCCESS); 529 530 /* 531 * Try to find a dispatcher that we can share. 532 */ 533 attrs = 0; 534 attrs |= DNS_DISPATCHATTR_UDP; 535 switch (af) { 536 case AF_INET: 537 attrs |= DNS_DISPATCHATTR_IPV4; 538 break; 539 case AF_INET6: 540 attrs |= DNS_DISPATCHATTR_IPV6; 541 break; 542 } 543 attrmask = 0; 544 attrmask |= DNS_DISPATCHATTR_UDP; 545 attrmask |= DNS_DISPATCHATTR_TCP; 546 attrmask |= DNS_DISPATCHATTR_IPV4; 547 attrmask |= DNS_DISPATCHATTR_IPV6; 548 549 disp = NULL; 550 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 551 ns_g_taskmgr, &sa, 4096, 552 1000, 32768, 16411, 16433, 553 attrs, attrmask, &disp); 554 if (result != ISC_R_SUCCESS) { 555 isc_sockaddr_t any; 556 char buf[ISC_SOCKADDR_FORMATSIZE]; 557 558 switch (af) { 559 case AF_INET: 560 isc_sockaddr_any(&any); 561 break; 562 case AF_INET6: 563 isc_sockaddr_any6(&any); 564 break; 565 } 566 if (isc_sockaddr_equal(&sa, &any)) 567 return (ISC_R_SUCCESS); 568 isc_sockaddr_format(&sa, buf, sizeof(buf)); 569 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 570 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 571 "could not get query source dispatcher (%s)", 572 buf); 573 return (result); 574 } 575 576 *dispatchp = disp; 577 578 return (ISC_R_SUCCESS); 579} 580 581static isc_result_t 582configure_order(dns_order_t *order, const cfg_obj_t *ent) { 583 dns_rdataclass_t rdclass; 584 dns_rdatatype_t rdtype; 585 const cfg_obj_t *obj; 586 dns_fixedname_t fixed; 587 unsigned int mode = 0; 588 const char *str; 589 isc_buffer_t b; 590 isc_result_t result; 591 isc_boolean_t addroot; 592 593 result = ns_config_getclass(cfg_tuple_get(ent, "class"), 594 dns_rdataclass_any, &rdclass); 595 if (result != ISC_R_SUCCESS) 596 return (result); 597 598 result = ns_config_gettype(cfg_tuple_get(ent, "type"), 599 dns_rdatatype_any, &rdtype); 600 if (result != ISC_R_SUCCESS) 601 return (result); 602 603 obj = cfg_tuple_get(ent, "name"); 604 if (cfg_obj_isstring(obj)) 605 str = cfg_obj_asstring(obj); 606 else 607 str = "*"; 608 addroot = ISC_TF(strcmp(str, "*") == 0); 609 isc_buffer_init(&b, str, strlen(str)); 610 isc_buffer_add(&b, strlen(str)); 611 dns_fixedname_init(&fixed); 612 result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 613 dns_rootname, ISC_FALSE, NULL); 614 if (result != ISC_R_SUCCESS) 615 return (result); 616 617 obj = cfg_tuple_get(ent, "ordering"); 618 INSIST(cfg_obj_isstring(obj)); 619 str = cfg_obj_asstring(obj); 620 if (!strcasecmp(str, "fixed")) 621 mode = DNS_RDATASETATTR_FIXEDORDER; 622 else if (!strcasecmp(str, "random")) 623 mode = DNS_RDATASETATTR_RANDOMIZE; 624 else if (!strcasecmp(str, "cyclic")) 625 mode = 0; 626 else 627 INSIST(0); 628 629 /* 630 * "*" should match everything including the root (BIND 8 compat). 631 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a 632 * explicit entry for "." when the name is "*". 633 */ 634 if (addroot) { 635 result = dns_order_add(order, dns_rootname, 636 rdtype, rdclass, mode); 637 if (result != ISC_R_SUCCESS) 638 return (result); 639 } 640 641 return (dns_order_add(order, dns_fixedname_name(&fixed), 642 rdtype, rdclass, mode)); 643} 644 645static isc_result_t 646configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { 647 isc_netaddr_t na; 648 dns_peer_t *peer; 649 const cfg_obj_t *obj; 650 const char *str; 651 isc_result_t result; 652 unsigned int prefixlen; 653 654 cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); 655 656 peer = NULL; 657 result = dns_peer_new(mctx, &na, &peer); 658 if (result != ISC_R_SUCCESS) 659 return (result); 660 661 obj = NULL; 662 (void)cfg_map_get(cpeer, "bogus", &obj); 663 if (obj != NULL) 664 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); 665 666 obj = NULL; 667 (void)cfg_map_get(cpeer, "provide-ixfr", &obj); 668 if (obj != NULL) 669 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); 670 671 obj = NULL; 672 (void)cfg_map_get(cpeer, "request-ixfr", &obj); 673 if (obj != NULL) 674 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); 675 676 obj = NULL; 677 (void)cfg_map_get(cpeer, "edns", &obj); 678 if (obj != NULL) 679 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); 680 681 obj = NULL; 682 (void)cfg_map_get(cpeer, "edns-udp-size", &obj); 683 if (obj != NULL) { 684 isc_uint32_t udpsize = cfg_obj_asuint32(obj); 685 if (udpsize < 512) 686 udpsize = 512; 687 if (udpsize > 4096) 688 udpsize = 4096; 689 CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); 690 } 691 692 obj = NULL; 693 (void)cfg_map_get(cpeer, "max-udp-size", &obj); 694 if (obj != NULL) { 695 isc_uint32_t udpsize = cfg_obj_asuint32(obj); 696 if (udpsize < 512) 697 udpsize = 512; 698 if (udpsize > 4096) 699 udpsize = 4096; 700 CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); 701 } 702 703 obj = NULL; 704 (void)cfg_map_get(cpeer, "transfers", &obj); 705 if (obj != NULL) 706 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); 707 708 obj = NULL; 709 (void)cfg_map_get(cpeer, "transfer-format", &obj); 710 if (obj != NULL) { 711 str = cfg_obj_asstring(obj); 712 if (strcasecmp(str, "many-answers") == 0) 713 CHECK(dns_peer_settransferformat(peer, 714 dns_many_answers)); 715 else if (strcasecmp(str, "one-answer") == 0) 716 CHECK(dns_peer_settransferformat(peer, 717 dns_one_answer)); 718 else 719 INSIST(0); 720 } 721 722 obj = NULL; 723 (void)cfg_map_get(cpeer, "keys", &obj); 724 if (obj != NULL) { 725 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); 726 if (result != ISC_R_SUCCESS) 727 goto cleanup; 728 } 729 730 obj = NULL; 731 if (na.family == AF_INET) 732 (void)cfg_map_get(cpeer, "transfer-source", &obj); 733 else 734 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); 735 if (obj != NULL) { 736 result = dns_peer_settransfersource(peer, 737 cfg_obj_assockaddr(obj)); 738 if (result != ISC_R_SUCCESS) 739 goto cleanup; 740 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 741 } 742 743 obj = NULL; 744 if (na.family == AF_INET) 745 (void)cfg_map_get(cpeer, "notify-source", &obj); 746 else 747 (void)cfg_map_get(cpeer, "notify-source-v6", &obj); 748 if (obj != NULL) { 749 result = dns_peer_setnotifysource(peer, 750 cfg_obj_assockaddr(obj)); 751 if (result != ISC_R_SUCCESS) 752 goto cleanup; 753 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 754 } 755 756 obj = NULL; 757 if (na.family == AF_INET) 758 (void)cfg_map_get(cpeer, "query-source", &obj); 759 else 760 (void)cfg_map_get(cpeer, "query-source-v6", &obj); 761 if (obj != NULL) { 762 result = dns_peer_setquerysource(peer, 763 cfg_obj_assockaddr(obj)); 764 if (result != ISC_R_SUCCESS) 765 goto cleanup; 766 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 767 } 768 769 *peerp = peer; 770 return (ISC_R_SUCCESS); 771 772 cleanup: 773 dns_peer_detach(&peer); 774 return (result); 775} 776 777static isc_result_t 778disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { 779 isc_result_t result; 780 const cfg_obj_t *algorithms; 781 const cfg_listelt_t *element; 782 const char *str; 783 dns_fixedname_t fixed; 784 dns_name_t *name; 785 isc_buffer_t b; 786 787 dns_fixedname_init(&fixed); 788 name = dns_fixedname_name(&fixed); 789 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); 790 isc_buffer_init(&b, str, strlen(str)); 791 isc_buffer_add(&b, strlen(str)); 792 CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL)); 793 794 algorithms = cfg_tuple_get(disabled, "algorithms"); 795 for (element = cfg_list_first(algorithms); 796 element != NULL; 797 element = cfg_list_next(element)) 798 { 799 isc_textregion_t r; 800 dns_secalg_t alg; 801 802 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 803 r.length = strlen(r.base); 804 805 result = dns_secalg_fromtext(&alg, &r); 806 if (result != ISC_R_SUCCESS) { 807 isc_uint8_t ui; 808 result = isc_parse_uint8(&ui, r.base, 10); 809 alg = ui; 810 } 811 if (result != ISC_R_SUCCESS) { 812 cfg_obj_log(cfg_listelt_value(element), 813 ns_g_lctx, ISC_LOG_ERROR, 814 "invalid algorithm"); 815 CHECK(result); 816 } 817 CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); 818 } 819 cleanup: 820 return (result); 821} 822 823static isc_boolean_t 824on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { 825 const cfg_listelt_t *element; 826 dns_fixedname_t fixed; 827 dns_name_t *name; 828 isc_result_t result; 829 const cfg_obj_t *value; 830 const char *str; 831 isc_buffer_t b; 832 833 dns_fixedname_init(&fixed); 834 name = dns_fixedname_name(&fixed); 835 836 for (element = cfg_list_first(disablelist); 837 element != NULL; 838 element = cfg_list_next(element)) 839 { 840 value = cfg_listelt_value(element); 841 str = cfg_obj_asstring(value); 842 isc_buffer_init(&b, str, strlen(str)); 843 isc_buffer_add(&b, strlen(str)); 844 result = dns_name_fromtext(name, &b, dns_rootname, 845 ISC_TRUE, NULL); 846 RUNTIME_CHECK(result == ISC_R_SUCCESS); 847 if (dns_name_equal(name, zonename)) 848 return (ISC_TRUE); 849 } 850 return (ISC_FALSE); 851} 852 853static void 854check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, 855 isc_mem_t *mctx) 856{ 857 char **argv = NULL; 858 unsigned int i; 859 isc_result_t result; 860 861 result = dns_zone_getdbtype(*zonep, &argv, mctx); 862 if (result != ISC_R_SUCCESS) { 863 dns_zone_detach(zonep); 864 return; 865 } 866 867 /* 868 * Check that all the arguments match. 869 */ 870 for (i = 0; i < dbtypec; i++) 871 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { 872 dns_zone_detach(zonep); 873 break; 874 } 875 876 /* 877 * Check that there are not extra arguments. 878 */ 879 if (i == dbtypec && argv[i] != NULL) 880 dns_zone_detach(zonep); 881 isc_mem_free(mctx, argv); 882} 883 884 885/* 886 * Configure 'view' according to 'vconfig', taking defaults from 'config' 887 * where values are missing in 'vconfig'. 888 * 889 * When configuring the default view, 'vconfig' will be NULL and the 890 * global defaults in 'config' used exclusively. 891 */ 892static isc_result_t 893configure_view(dns_view_t *view, const cfg_obj_t *config, 894 const cfg_obj_t *vconfig, isc_mem_t *mctx, 895 cfg_aclconfctx_t *actx, isc_boolean_t need_hints) 896{ 897 const cfg_obj_t *maps[4]; 898 const cfg_obj_t *cfgmaps[3]; 899 const cfg_obj_t *options = NULL; 900 const cfg_obj_t *voptions = NULL; 901 const cfg_obj_t *forwardtype; 902 const cfg_obj_t *forwarders; 903 const cfg_obj_t *alternates; 904 const cfg_obj_t *zonelist; 905#ifdef DLZ 906 const cfg_obj_t *dlz; 907 unsigned int dlzargc; 908 char **dlzargv; 909#endif 910 const cfg_obj_t *disabled; 911 const cfg_obj_t *obj; 912 const cfg_listelt_t *element; 913 in_port_t port; 914 dns_cache_t *cache = NULL; 915 isc_result_t result; 916 isc_uint32_t max_adb_size; 917 isc_uint32_t max_cache_size; 918 isc_uint32_t max_acache_size; 919 isc_uint32_t lame_ttl; 920 dns_tsig_keyring_t *ring; 921 dns_view_t *pview = NULL; /* Production view */ 922 isc_mem_t *cmctx; 923 dns_dispatch_t *dispatch4 = NULL; 924 dns_dispatch_t *dispatch6 = NULL; 925 isc_boolean_t reused_cache = ISC_FALSE; 926 int i; 927 const char *str; 928 dns_order_t *order = NULL; 929 isc_uint32_t udpsize; 930 unsigned int check = 0; 931 dns_zone_t *zone = NULL; 932 isc_uint32_t max_clients_per_query; 933 const char *sep = ": view "; 934 const char *viewname = view->name; 935 const char *forview = " for view "; 936 isc_boolean_t rfc1918; 937 isc_boolean_t empty_zones_enable; 938 const cfg_obj_t *disablelist = NULL; 939 940 REQUIRE(DNS_VIEW_VALID(view)); 941 942 cmctx = NULL; 943 944 if (config != NULL) 945 (void)cfg_map_get(config, "options", &options); 946 947 i = 0; 948 if (vconfig != NULL) { 949 voptions = cfg_tuple_get(vconfig, "options"); 950 maps[i++] = voptions; 951 } 952 if (options != NULL) 953 maps[i++] = options; 954 maps[i++] = ns_g_defaults; 955 maps[i] = NULL; 956 957 i = 0; 958 if (voptions != NULL) 959 cfgmaps[i++] = voptions; 960 if (config != NULL) 961 cfgmaps[i++] = config; 962 cfgmaps[i] = NULL; 963 964 if (!strcmp(viewname, "_default")) { 965 sep = ""; 966 viewname = ""; 967 forview = ""; 968 } 969 970 /* 971 * Set the view's port number for outgoing queries. 972 */ 973 CHECKM(ns_config_getport(config, &port), "port"); 974 dns_view_setdstport(view, port); 975 976 /* 977 * Create additional cache for this view and zones under the view 978 * if explicitly enabled. 979 * XXX950 default to on. 980 */ 981 obj = NULL; 982 (void)ns_config_get(maps, "acache-enable", &obj); 983 if (obj != NULL && cfg_obj_asboolean(obj)) { 984 cmctx = NULL; 985 CHECK(isc_mem_create(0, 0, &cmctx)); 986 CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, 987 ns_g_timermgr)); 988 isc_mem_detach(&cmctx); 989 } 990 if (view->acache != NULL) { 991 obj = NULL; 992 result = ns_config_get(maps, "acache-cleaning-interval", &obj); 993 INSIST(result == ISC_R_SUCCESS); 994 dns_acache_setcleaninginterval(view->acache, 995 cfg_obj_asuint32(obj) * 60); 996 997 obj = NULL; 998 result = ns_config_get(maps, "max-acache-size", &obj); 999 INSIST(result == ISC_R_SUCCESS); 1000 if (cfg_obj_isstring(obj)) { 1001 str = cfg_obj_asstring(obj); 1002 INSIST(strcasecmp(str, "unlimited") == 0); 1003 max_acache_size = ISC_UINT32_MAX; 1004 } else { 1005 isc_resourcevalue_t value; 1006 1007 value = cfg_obj_asuint64(obj); 1008 if (value > ISC_UINT32_MAX) { 1009 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1010 "'max-acache-size " 1011 "%" ISC_PRINT_QUADFORMAT 1012 "d' is too large", 1013 value); 1014 result = ISC_R_RANGE; 1015 goto cleanup; 1016 } 1017 max_acache_size = (isc_uint32_t)value; 1018 } 1019 dns_acache_setcachesize(view->acache, max_acache_size); 1020 } 1021 1022 /* 1023 * Configure the zones. 1024 */ 1025 zonelist = NULL; 1026 if (voptions != NULL) 1027 (void)cfg_map_get(voptions, "zone", &zonelist); 1028 else 1029 (void)cfg_map_get(config, "zone", &zonelist); 1030 for (element = cfg_list_first(zonelist); 1031 element != NULL; 1032 element = cfg_list_next(element)) 1033 { 1034 const cfg_obj_t *zconfig = cfg_listelt_value(element); 1035 CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 1036 actx)); 1037 } 1038 1039#ifdef DLZ 1040 /* 1041 * Create Dynamically Loadable Zone driver. 1042 */ 1043 dlz = NULL; 1044 if (voptions != NULL) 1045 (void)cfg_map_get(voptions, "dlz", &dlz); 1046 else 1047 (void)cfg_map_get(config, "dlz", &dlz); 1048 1049 obj = NULL; 1050 if (dlz != NULL) { 1051 (void)cfg_map_get(cfg_tuple_get(dlz, "options"), 1052 "database", &obj); 1053 if (obj != NULL) { 1054 char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); 1055 if (s == NULL) { 1056 result = ISC_R_NOMEMORY; 1057 goto cleanup; 1058 } 1059 1060 result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); 1061 if (result != ISC_R_SUCCESS) { 1062 isc_mem_free(mctx, s); 1063 goto cleanup; 1064 } 1065 1066 obj = cfg_tuple_get(dlz, "name"); 1067 result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), 1068 dlzargv[0], dlzargc, dlzargv, 1069 &view->dlzdatabase); 1070 isc_mem_free(mctx, s); 1071 isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); 1072 if (result != ISC_R_SUCCESS) 1073 goto cleanup; 1074 } 1075 } 1076#endif 1077 1078 /* 1079 * Configure the view's cache. Try to reuse an existing 1080 * cache if possible, otherwise create a new cache. 1081 * Note that the ADB is not preserved in either case. 1082 * 1083 * XXX Determining when it is safe to reuse a cache is 1084 * tricky. When the view's configuration changes, the cached 1085 * data may become invalid because it reflects our old 1086 * view of the world. As more view attributes become 1087 * configurable, we will have to add code here to check 1088 * whether they have changed in ways that could 1089 * invalidate the cache. 1090 */ 1091 result = dns_viewlist_find(&ns_g_server->viewlist, 1092 view->name, view->rdclass, 1093 &pview); 1094 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 1095 goto cleanup; 1096 if (pview != NULL) { 1097 INSIST(pview->cache != NULL); 1098 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1099 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), 1100 "reusing existing cache"); 1101 reused_cache = ISC_TRUE; 1102 dns_cache_attach(pview->cache, &cache); 1103 dns_view_detach(&pview); 1104 } else { 1105 CHECK(isc_mem_create(0, 0, &cmctx)); 1106 CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, 1107 view->rdclass, "rbt", 0, NULL, &cache)); 1108 } 1109 dns_view_setcache(view, cache); 1110 1111 /* 1112 * cache-file cannot be inherited if views are present, but this 1113 * should be caught by the configuration checking stage. 1114 */ 1115 obj = NULL; 1116 result = ns_config_get(maps, "cache-file", &obj); 1117 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 1118 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 1119 if (!reused_cache) 1120 CHECK(dns_cache_load(cache)); 1121 } 1122 1123 obj = NULL; 1124 result = ns_config_get(maps, "cleaning-interval", &obj); 1125 INSIST(result == ISC_R_SUCCESS); 1126 dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60); 1127 1128 obj = NULL; 1129 result = ns_config_get(maps, "max-cache-size", &obj); 1130 INSIST(result == ISC_R_SUCCESS); 1131 if (cfg_obj_isstring(obj)) { 1132 str = cfg_obj_asstring(obj); 1133 INSIST(strcasecmp(str, "unlimited") == 0); 1134 max_cache_size = ISC_UINT32_MAX; 1135 } else { 1136 isc_resourcevalue_t value; 1137 value = cfg_obj_asuint64(obj); 1138 if (value > ISC_UINT32_MAX) { 1139 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1140 "'max-cache-size " 1141 "%" ISC_PRINT_QUADFORMAT "d' is too large", 1142 value); 1143 result = ISC_R_RANGE; 1144 goto cleanup; 1145 } 1146 max_cache_size = (isc_uint32_t)value; 1147 } 1148 dns_cache_setcachesize(cache, max_cache_size); 1149 1150 dns_cache_detach(&cache); 1151 1152 /* 1153 * Check-names. 1154 */ 1155 obj = NULL; 1156 result = ns_checknames_get(maps, "response", &obj); 1157 INSIST(result == ISC_R_SUCCESS); 1158 1159 str = cfg_obj_asstring(obj); 1160 if (strcasecmp(str, "fail") == 0) { 1161 check = DNS_RESOLVER_CHECKNAMES | 1162 DNS_RESOLVER_CHECKNAMESFAIL; 1163 view->checknames = ISC_TRUE; 1164 } else if (strcasecmp(str, "warn") == 0) { 1165 check = DNS_RESOLVER_CHECKNAMES; 1166 view->checknames = ISC_FALSE; 1167 } else if (strcasecmp(str, "ignore") == 0) { 1168 check = 0; 1169 view->checknames = ISC_FALSE; 1170 } else 1171 INSIST(0); 1172 1173 /* 1174 * Resolver. 1175 * 1176 * XXXRTH Hardwired number of tasks. 1177 */ 1178 CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4)); 1179 CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6)); 1180 if (dispatch4 == NULL && dispatch6 == NULL) { 1181 UNEXPECTED_ERROR(__FILE__, __LINE__, 1182 "unable to obtain neither an IPv4 nor" 1183 " an IPv6 dispatch"); 1184 result = ISC_R_UNEXPECTED; 1185 goto cleanup; 1186 } 1187 CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, 1188 ns_g_socketmgr, ns_g_timermgr, 1189 check, ns_g_dispatchmgr, 1190 dispatch4, dispatch6)); 1191 1192 /* 1193 * Set the ADB cache size to 1/8th of the max-cache-size. 1194 */ 1195 max_adb_size = 0; 1196 if (max_cache_size != 0) { 1197 max_adb_size = max_cache_size / 8; 1198 if (max_adb_size == 0) 1199 max_adb_size = 1; /* Force minimum. */ 1200 } 1201 dns_adb_setadbsize(view->adb, max_adb_size); 1202 1203 /* 1204 * Set resolver's lame-ttl. 1205 */ 1206 obj = NULL; 1207 result = ns_config_get(maps, "lame-ttl", &obj); 1208 INSIST(result == ISC_R_SUCCESS); 1209 lame_ttl = cfg_obj_asuint32(obj); 1210 if (lame_ttl > 1800) 1211 lame_ttl = 1800; 1212 dns_resolver_setlamettl(view->resolver, lame_ttl); 1213 1214 obj = NULL; 1215 result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); 1216 INSIST(result == ISC_R_SUCCESS); 1217 dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj)); 1218 1219 /* 1220 * Set the resolver's EDNS UDP size. 1221 */ 1222 obj = NULL; 1223 result = ns_config_get(maps, "edns-udp-size", &obj); 1224 INSIST(result == ISC_R_SUCCESS); 1225 udpsize = cfg_obj_asuint32(obj); 1226 if (udpsize < 512) 1227 udpsize = 512; 1228 if (udpsize > 4096) 1229 udpsize = 4096; 1230 dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 1231 1232 /* 1233 * Set the maximum UDP response size. 1234 */ 1235 obj = NULL; 1236 result = ns_config_get(maps, "max-udp-size", &obj); 1237 INSIST(result == ISC_R_SUCCESS); 1238 udpsize = cfg_obj_asuint32(obj); 1239 if (udpsize < 512) 1240 udpsize = 512; 1241 if (udpsize > 4096) 1242 udpsize = 4096; 1243 view->maxudp = udpsize; 1244 1245 /* 1246 * Set supported DNSSEC algorithms. 1247 */ 1248 dns_resolver_reset_algorithms(view->resolver); 1249 disabled = NULL; 1250 (void)ns_config_get(maps, "disable-algorithms", &disabled); 1251 if (disabled != NULL) { 1252 for (element = cfg_list_first(disabled); 1253 element != NULL; 1254 element = cfg_list_next(element)) 1255 CHECK(disable_algorithms(cfg_listelt_value(element), 1256 view->resolver)); 1257 } 1258 1259 /* 1260 * A global or view "forwarders" option, if present, 1261 * creates an entry for "." in the forwarding table. 1262 */ 1263 forwardtype = NULL; 1264 forwarders = NULL; 1265 (void)ns_config_get(maps, "forward", &forwardtype); 1266 (void)ns_config_get(maps, "forwarders", &forwarders); 1267 if (forwarders != NULL) 1268 CHECK(configure_forward(config, view, dns_rootname, 1269 forwarders, forwardtype)); 1270 1271 /* 1272 * Dual Stack Servers. 1273 */ 1274 alternates = NULL; 1275 (void)ns_config_get(maps, "dual-stack-servers", &alternates); 1276 if (alternates != NULL) 1277 CHECK(configure_alternates(config, view, alternates)); 1278 1279 /* 1280 * We have default hints for class IN if we need them. 1281 */ 1282 if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 1283 dns_view_sethints(view, ns_g_server->in_roothints); 1284 1285 /* 1286 * If we still have no hints, this is a non-IN view with no 1287 * "hints zone" configured. Issue a warning, except if this 1288 * is a root server. Root servers never need to consult 1289 * their hints, so it's no point requiring users to configure 1290 * them. 1291 */ 1292 if (view->hints == NULL) { 1293 dns_zone_t *rootzone = NULL; 1294 (void)dns_view_findzone(view, dns_rootname, &rootzone); 1295 if (rootzone != NULL) { 1296 dns_zone_detach(&rootzone); 1297 need_hints = ISC_FALSE; 1298 } 1299 if (need_hints) 1300 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1301 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1302 "no root hints for view '%s'", 1303 view->name); 1304 } 1305 1306 /* 1307 * Configure the view's TSIG keys. 1308 */ 1309 ring = NULL; 1310 CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 1311 dns_view_setkeyring(view, ring); 1312 1313 /* 1314 * Configure the view's peer list. 1315 */ 1316 { 1317 const cfg_obj_t *peers = NULL; 1318 const cfg_listelt_t *element; 1319 dns_peerlist_t *newpeers = NULL; 1320 1321 (void)ns_config_get(cfgmaps, "server", &peers); 1322 CHECK(dns_peerlist_new(mctx, &newpeers)); 1323 for (element = cfg_list_first(peers); 1324 element != NULL; 1325 element = cfg_list_next(element)) 1326 { 1327 const cfg_obj_t *cpeer = cfg_listelt_value(element); 1328 dns_peer_t *peer; 1329 1330 CHECK(configure_peer(cpeer, mctx, &peer)); 1331 dns_peerlist_addpeer(newpeers, peer); 1332 dns_peer_detach(&peer); 1333 } 1334 dns_peerlist_detach(&view->peers); 1335 view->peers = newpeers; /* Transfer ownership. */ 1336 } 1337 1338 /* 1339 * Configure the views rrset-order. 1340 */ 1341 { 1342 const cfg_obj_t *rrsetorder = NULL; 1343 const cfg_listelt_t *element; 1344 1345 (void)ns_config_get(maps, "rrset-order", &rrsetorder); 1346 CHECK(dns_order_create(mctx, &order)); 1347 for (element = cfg_list_first(rrsetorder); 1348 element != NULL; 1349 element = cfg_list_next(element)) 1350 { 1351 const cfg_obj_t *ent = cfg_listelt_value(element); 1352 1353 CHECK(configure_order(order, ent)); 1354 } 1355 if (view->order != NULL) 1356 dns_order_detach(&view->order); 1357 dns_order_attach(order, &view->order); 1358 dns_order_detach(&order); 1359 } 1360 /* 1361 * Copy the aclenv object. 1362 */ 1363 dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 1364 1365 /* 1366 * Configure the "match-clients" and "match-destinations" ACL. 1367 */ 1368 CHECK(configure_view_acl(vconfig, config, "match-clients", actx, 1369 ns_g_mctx, &view->matchclients)); 1370 CHECK(configure_view_acl(vconfig, config, "match-destinations", actx, 1371 ns_g_mctx, &view->matchdestinations)); 1372 1373 /* 1374 * Configure the "match-recursive-only" option. 1375 */ 1376 obj = NULL; 1377 (void)ns_config_get(maps, "match-recursive-only", &obj); 1378 if (obj != NULL && cfg_obj_asboolean(obj)) 1379 view->matchrecursiveonly = ISC_TRUE; 1380 else 1381 view->matchrecursiveonly = ISC_FALSE; 1382 1383 /* 1384 * Configure other configurable data. 1385 */ 1386 obj = NULL; 1387 result = ns_config_get(maps, "recursion", &obj); 1388 INSIST(result == ISC_R_SUCCESS); 1389 view->recursion = cfg_obj_asboolean(obj); 1390 1391 obj = NULL; 1392 result = ns_config_get(maps, "auth-nxdomain", &obj); 1393 INSIST(result == ISC_R_SUCCESS); 1394 view->auth_nxdomain = cfg_obj_asboolean(obj); 1395 1396 obj = NULL; 1397 result = ns_config_get(maps, "minimal-responses", &obj); 1398 INSIST(result == ISC_R_SUCCESS); 1399 view->minimalresponses = cfg_obj_asboolean(obj); 1400 1401 obj = NULL; 1402 result = ns_config_get(maps, "transfer-format", &obj); 1403 INSIST(result == ISC_R_SUCCESS); 1404 str = cfg_obj_asstring(obj); 1405 if (strcasecmp(str, "many-answers") == 0) 1406 view->transfer_format = dns_many_answers; 1407 else if (strcasecmp(str, "one-answer") == 0) 1408 view->transfer_format = dns_one_answer; 1409 else 1410 INSIST(0); 1411 1412 /* 1413 * Set sources where additional data and CNAME/DNAME 1414 * targets for authoritative answers may be found. 1415 */ 1416 obj = NULL; 1417 result = ns_config_get(maps, "additional-from-auth", &obj); 1418 INSIST(result == ISC_R_SUCCESS); 1419 view->additionalfromauth = cfg_obj_asboolean(obj); 1420 if (view->recursion && ! view->additionalfromauth) { 1421 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1422 "'additional-from-auth no' is only supported " 1423 "with 'recursion no'"); 1424 view->additionalfromauth = ISC_TRUE; 1425 } 1426 1427 obj = NULL; 1428 result = ns_config_get(maps, "additional-from-cache", &obj); 1429 INSIST(result == ISC_R_SUCCESS); 1430 view->additionalfromcache = cfg_obj_asboolean(obj); 1431 if (view->recursion && ! view->additionalfromcache) { 1432 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1433 "'additional-from-cache no' is only supported " 1434 "with 'recursion no'"); 1435 view->additionalfromcache = ISC_TRUE; 1436 } 1437 1438 /* 1439 * Set "allow-query-cache" and "allow-recursion" acls if 1440 * configured in named.conf. 1441 */ 1442 CHECK(configure_view_acl(vconfig, config, "allow-query-cache", 1443 actx, ns_g_mctx, &view->queryacl)); 1444 1445 if (strcmp(view->name, "_bind") != 0) 1446 CHECK(configure_view_acl(vconfig, config, "allow-recursion", 1447 actx, ns_g_mctx, &view->recursionacl)); 1448 1449 /* 1450 * Warning if both "recursion no;" and allow-recursion are active 1451 * except for "allow-recursion { none; };". 1452 */ 1453 if (!view->recursion && view->recursionacl != NULL && 1454 (view->recursionacl->length != 1 || 1455 view->recursionacl->elements[0].type != dns_aclelementtype_any || 1456 view->recursionacl->elements[0].negative != ISC_TRUE)) 1457 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1458 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1459 "both \"recursion no;\" and \"allow-recursion\" " 1460 "active%s%s", forview, viewname); 1461 1462 /* 1463 * "allow-query-cache" inherits from "allow-recursion" if set, 1464 * otherwise from "allow-query" if set. 1465 * "allow-recursion" inherits from "allow-query-cache" if set, 1466 * otherwise from "allow-query" if set. 1467 */ 1468 if (view->queryacl == NULL && view->recursionacl != NULL) 1469 dns_acl_attach(view->recursionacl, &view->queryacl); 1470 if (view->queryacl == NULL) 1471 CHECK(configure_view_acl(vconfig, config, "allow-query", 1472 actx, ns_g_mctx, &view->queryacl)); 1473 if (view->recursionacl == NULL && view->queryacl != NULL) 1474 dns_acl_attach(view->queryacl, &view->recursionacl); 1475 1476 /* 1477 * Set default "allow-recursion" and "allow-query-cache" acls. 1478 */ 1479 if (view->recursionacl == NULL && view->recursion) 1480 CHECK(configure_view_acl(NULL, ns_g_config, "allow-recursion", 1481 actx, ns_g_mctx, &view->recursionacl)); 1482 if (view->queryacl == NULL) 1483 CHECK(configure_view_acl(NULL, ns_g_config, 1484 "allow-query-cache", actx, 1485 ns_g_mctx, &view->queryacl)); 1486 1487 CHECK(configure_view_acl(vconfig, config, "sortlist", 1488 actx, ns_g_mctx, &view->sortlist)); 1489 1490 obj = NULL; 1491 result = ns_config_get(maps, "request-ixfr", &obj); 1492 INSIST(result == ISC_R_SUCCESS); 1493 view->requestixfr = cfg_obj_asboolean(obj); 1494 1495 obj = NULL; 1496 result = ns_config_get(maps, "provide-ixfr", &obj); 1497 INSIST(result == ISC_R_SUCCESS); 1498 view->provideixfr = cfg_obj_asboolean(obj); 1499 1500 obj = NULL; 1501 result = ns_config_get(maps, "max-clients-per-query", &obj); 1502 INSIST(result == ISC_R_SUCCESS); 1503 max_clients_per_query = cfg_obj_asuint32(obj); 1504 1505 obj = NULL; 1506 result = ns_config_get(maps, "clients-per-query", &obj); 1507 INSIST(result == ISC_R_SUCCESS); 1508 dns_resolver_setclientsperquery(view->resolver, 1509 cfg_obj_asuint32(obj), 1510 max_clients_per_query); 1511 1512 obj = NULL; 1513 result = ns_config_get(maps, "dnssec-enable", &obj); 1514 INSIST(result == ISC_R_SUCCESS); 1515 view->enablednssec = cfg_obj_asboolean(obj); 1516 1517 obj = NULL; 1518 result = ns_config_get(maps, "dnssec-accept-expired", &obj); 1519 INSIST(result == ISC_R_SUCCESS); 1520 view->acceptexpired = cfg_obj_asboolean(obj); 1521 1522 obj = NULL; 1523 result = ns_config_get(maps, "dnssec-validation", &obj); 1524 INSIST(result == ISC_R_SUCCESS); 1525 view->enablevalidation = cfg_obj_asboolean(obj); 1526 1527 obj = NULL; 1528 result = ns_config_get(maps, "dnssec-lookaside", &obj); 1529 if (result == ISC_R_SUCCESS) { 1530 for (element = cfg_list_first(obj); 1531 element != NULL; 1532 element = cfg_list_next(element)) 1533 { 1534 const char *str; 1535 isc_buffer_t b; 1536 dns_name_t *dlv; 1537 1538 obj = cfg_listelt_value(element); 1539#if 0 1540 dns_fixedname_t fixed; 1541 dns_name_t *name; 1542 1543 /* 1544 * When we support multiple dnssec-lookaside 1545 * entries this is how to find the domain to be 1546 * checked. XXXMPA 1547 */ 1548 dns_fixedname_init(&fixed); 1549 name = dns_fixedname_name(&fixed); 1550 str = cfg_obj_asstring(cfg_tuple_get(obj, 1551 "domain")); 1552 isc_buffer_init(&b, str, strlen(str)); 1553 isc_buffer_add(&b, strlen(str)); 1554 CHECK(dns_name_fromtext(name, &b, dns_rootname, 1555 ISC_TRUE, NULL)); 1556#endif 1557 str = cfg_obj_asstring(cfg_tuple_get(obj, 1558 "trust-anchor")); 1559 isc_buffer_init(&b, str, strlen(str)); 1560 isc_buffer_add(&b, strlen(str)); 1561 dlv = dns_fixedname_name(&view->dlv_fixed); 1562 CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 1563 ISC_TRUE, NULL)); 1564 view->dlv = dns_fixedname_name(&view->dlv_fixed); 1565 } 1566 } else 1567 view->dlv = NULL; 1568 1569 /* 1570 * For now, there is only one kind of trusted keys, the 1571 * "security roots". 1572 */ 1573 CHECK(configure_view_dnsseckeys(vconfig, config, mctx, 1574 &view->secroots)); 1575 dns_resolver_resetmustbesecure(view->resolver); 1576 obj = NULL; 1577 result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 1578 if (result == ISC_R_SUCCESS) 1579 CHECK(mustbesecure(obj, view->resolver)); 1580 1581 obj = NULL; 1582 result = ns_config_get(maps, "max-cache-ttl", &obj); 1583 INSIST(result == ISC_R_SUCCESS); 1584 view->maxcachettl = cfg_obj_asuint32(obj); 1585 1586 obj = NULL; 1587 result = ns_config_get(maps, "max-ncache-ttl", &obj); 1588 INSIST(result == ISC_R_SUCCESS); 1589 view->maxncachettl = cfg_obj_asuint32(obj); 1590 if (view->maxncachettl > 7 * 24 * 3600) 1591 view->maxncachettl = 7 * 24 * 3600; 1592 1593 obj = NULL; 1594 result = ns_config_get(maps, "preferred-glue", &obj); 1595 if (result == ISC_R_SUCCESS) { 1596 str = cfg_obj_asstring(obj); 1597 if (strcasecmp(str, "a") == 0) 1598 view->preferred_glue = dns_rdatatype_a; 1599 else if (strcasecmp(str, "aaaa") == 0) 1600 view->preferred_glue = dns_rdatatype_aaaa; 1601 else 1602 view->preferred_glue = 0; 1603 } else 1604 view->preferred_glue = 0; 1605 1606 obj = NULL; 1607 result = ns_config_get(maps, "root-delegation-only", &obj); 1608 if (result == ISC_R_SUCCESS) { 1609 dns_view_setrootdelonly(view, ISC_TRUE); 1610 if (!cfg_obj_isvoid(obj)) { 1611 dns_fixedname_t fixed; 1612 dns_name_t *name; 1613 isc_buffer_t b; 1614 const char *str; 1615 const cfg_obj_t *exclude; 1616 1617 dns_fixedname_init(&fixed); 1618 name = dns_fixedname_name(&fixed); 1619 for (element = cfg_list_first(obj); 1620 element != NULL; 1621 element = cfg_list_next(element)) { 1622 exclude = cfg_listelt_value(element); 1623 str = cfg_obj_asstring(exclude); 1624 isc_buffer_init(&b, str, strlen(str)); 1625 isc_buffer_add(&b, strlen(str)); 1626 CHECK(dns_name_fromtext(name, &b, dns_rootname, 1627 ISC_FALSE, NULL)); 1628 CHECK(dns_view_excludedelegationonly(view, 1629 name)); 1630 } 1631 } 1632 } else 1633 dns_view_setrootdelonly(view, ISC_FALSE); 1634 1635 /* 1636 * Setup automatic empty zones. If recursion is off then 1637 * they are disabled by default. 1638 */ 1639 obj = NULL; 1640 (void)ns_config_get(maps, "empty-zones-enable", &obj); 1641 (void)ns_config_get(maps, "disable-empty-zone", &disablelist); 1642 if (obj == NULL && disablelist == NULL && 1643 view->rdclass == dns_rdataclass_in) { 1644 rfc1918 = ISC_FALSE; 1645 empty_zones_enable = view->recursion; 1646 } else if (view->rdclass == dns_rdataclass_in) { 1647 rfc1918 = ISC_TRUE; 1648 if (obj != NULL) 1649 empty_zones_enable = cfg_obj_asboolean(obj); 1650 else 1651 empty_zones_enable = view->recursion; 1652 } else { 1653 rfc1918 = ISC_FALSE; 1654 empty_zones_enable = ISC_FALSE; 1655 } 1656 if (empty_zones_enable) { 1657 const char *empty; 1658 int empty_zone = 0; 1659 dns_fixedname_t fixed; 1660 dns_name_t *name; 1661 isc_buffer_t buffer; 1662 const char *str; 1663 char server[DNS_NAME_FORMATSIZE + 1]; 1664 char contact[DNS_NAME_FORMATSIZE + 1]; 1665 isc_boolean_t logit; 1666 const char *empty_dbtype[4] = 1667 { "_builtin", "empty", NULL, NULL }; 1668 int empty_dbtypec = 4; 1669 1670 dns_fixedname_init(&fixed); 1671 name = dns_fixedname_name(&fixed); 1672 1673 obj = NULL; 1674 result = ns_config_get(maps, "empty-server", &obj); 1675 if (result == ISC_R_SUCCESS) { 1676 str = cfg_obj_asstring(obj); 1677 isc_buffer_init(&buffer, str, strlen(str)); 1678 isc_buffer_add(&buffer, strlen(str)); 1679 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1680 ISC_FALSE, NULL)); 1681 isc_buffer_init(&buffer, server, sizeof(server) - 1); 1682 CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 1683 server[isc_buffer_usedlength(&buffer)] = 0; 1684 empty_dbtype[2] = server; 1685 } else 1686 empty_dbtype[2] = "@"; 1687 1688 obj = NULL; 1689 result = ns_config_get(maps, "empty-contact", &obj); 1690 if (result == ISC_R_SUCCESS) { 1691 str = cfg_obj_asstring(obj); 1692 isc_buffer_init(&buffer, str, strlen(str)); 1693 isc_buffer_add(&buffer, strlen(str)); 1694 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1695 ISC_FALSE, NULL)); 1696 isc_buffer_init(&buffer, contact, sizeof(contact) - 1); 1697 CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 1698 contact[isc_buffer_usedlength(&buffer)] = 0; 1699 empty_dbtype[3] = contact; 1700 } else 1701 empty_dbtype[3] = "."; 1702 1703 logit = ISC_TRUE; 1704 for (empty = empty_zones[empty_zone].zone; 1705 empty != NULL; 1706 empty = empty_zones[++empty_zone].zone) 1707 { 1708 dns_forwarders_t *forwarders = NULL; 1709 dns_view_t *pview = NULL; 1710 1711 isc_buffer_init(&buffer, empty, strlen(empty)); 1712 isc_buffer_add(&buffer, strlen(empty)); 1713 /* 1714 * Look for zone on drop list. 1715 */ 1716 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1717 ISC_FALSE, NULL)); 1718 if (disablelist != NULL && 1719 on_disable_list(disablelist, name)) 1720 continue; 1721 1722 /* 1723 * This zone already exists. 1724 */ 1725 (void)dns_view_findzone(view, name, &zone); 1726 if (zone != NULL) { 1727 dns_zone_detach(&zone); 1728 continue; 1729 } 1730 1731 /* 1732 * If we would forward this name don't add a 1733 * empty zone for it. 1734 */ 1735 result = dns_fwdtable_find(view->fwdtable, name, 1736 &forwarders); 1737 if (result == ISC_R_SUCCESS && 1738 forwarders->fwdpolicy == dns_fwdpolicy_only) 1739 continue; 1740 1741 if (!rfc1918 && empty_zones[empty_zone].rfc1918) { 1742 if (logit) { 1743 isc_log_write(ns_g_lctx, 1744 NS_LOGCATEGORY_GENERAL, 1745 NS_LOGMODULE_SERVER, 1746 ISC_LOG_WARNING, 1747 "Warning%s%s: " 1748 "'empty-zones-enable/" 1749 "disable-empty-zone' " 1750 "not set: disabling " 1751 "RFC 1918 empty zones", 1752 sep, viewname); 1753 logit = ISC_FALSE; 1754 } 1755 continue; 1756 } 1757 1758 /* 1759 * See if we can re-use a existing zone. 1760 */ 1761 result = dns_viewlist_find(&ns_g_server->viewlist, 1762 view->name, view->rdclass, 1763 &pview); 1764 if (result != ISC_R_NOTFOUND && 1765 result != ISC_R_SUCCESS) 1766 goto cleanup; 1767 1768 if (pview != NULL) { 1769 (void)dns_view_findzone(pview, name, &zone); 1770 dns_view_detach(&pview); 1771 if (zone != NULL) 1772 check_dbtype(&zone, empty_dbtypec, 1773 empty_dbtype, mctx); 1774 if (zone != NULL) { 1775 dns_zone_setview(zone, view); 1776 CHECK(dns_view_addzone(view, zone)); 1777 dns_zone_detach(&zone); 1778 continue; 1779 } 1780 } 1781 1782 CHECK(dns_zone_create(&zone, mctx)); 1783 CHECK(dns_zone_setorigin(zone, name)); 1784 dns_zone_setview(zone, view); 1785 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1786 dns_zone_setclass(zone, view->rdclass); 1787 dns_zone_settype(zone, dns_zone_master); 1788 CHECK(dns_zone_setdbtype(zone, empty_dbtypec, 1789 empty_dbtype)); 1790 if (view->queryacl != NULL) 1791 dns_zone_setqueryacl(zone, view->queryacl); 1792 dns_zone_setdialup(zone, dns_dialuptype_no); 1793 dns_zone_setnotifytype(zone, dns_notifytype_no); 1794 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, 1795 ISC_TRUE); 1796 CHECK(dns_view_addzone(view, zone)); 1797 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1798 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 1799 "automatic empty zone%s%s: %s", 1800 sep, viewname, empty); 1801 dns_zone_detach(&zone); 1802 } 1803 } 1804 1805 result = ISC_R_SUCCESS; 1806 1807 cleanup: 1808 if (zone != NULL) 1809 dns_zone_detach(&zone); 1810 if (dispatch4 != NULL) 1811 dns_dispatch_detach(&dispatch4); 1812 if (dispatch6 != NULL) 1813 dns_dispatch_detach(&dispatch6); 1814 if (order != NULL) 1815 dns_order_detach(&order); 1816 if (cmctx != NULL) 1817 isc_mem_detach(&cmctx); 1818 1819 if (cache != NULL) 1820 dns_cache_detach(&cache); 1821 1822 return (result); 1823} 1824 1825static isc_result_t 1826configure_hints(dns_view_t *view, const char *filename) { 1827 isc_result_t result; 1828 dns_db_t *db; 1829 1830 db = NULL; 1831 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 1832 if (result == ISC_R_SUCCESS) { 1833 dns_view_sethints(view, db); 1834 dns_db_detach(&db); 1835 } 1836 1837 return (result); 1838} 1839 1840static isc_result_t 1841configure_alternates(const cfg_obj_t *config, dns_view_t *view, 1842 const cfg_obj_t *alternates) 1843{ 1844 const cfg_obj_t *portobj; 1845 const cfg_obj_t *addresses; 1846 const cfg_listelt_t *element; 1847 isc_result_t result = ISC_R_SUCCESS; 1848 in_port_t port; 1849 1850 /* 1851 * Determine which port to send requests to. 1852 */ 1853 if (ns_g_lwresdonly && ns_g_port != 0) 1854 port = ns_g_port; 1855 else 1856 CHECKM(ns_config_getport(config, &port), "port"); 1857 1858 if (alternates != NULL) { 1859 portobj = cfg_tuple_get(alternates, "port"); 1860 if (cfg_obj_isuint32(portobj)) { 1861 isc_uint32_t val = cfg_obj_asuint32(portobj); 1862 if (val > ISC_UINT16_MAX) { 1863 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1864 "port '%u' out of range", val); 1865 return (ISC_R_RANGE); 1866 } 1867 port = (in_port_t) val; 1868 } 1869 } 1870 1871 addresses = NULL; 1872 if (alternates != NULL) 1873 addresses = cfg_tuple_get(alternates, "addresses"); 1874 1875 for (element = cfg_list_first(addresses); 1876 element != NULL; 1877 element = cfg_list_next(element)) 1878 { 1879 const cfg_obj_t *alternate = cfg_listelt_value(element); 1880 isc_sockaddr_t sa; 1881 1882 if (!cfg_obj_issockaddr(alternate)) { 1883 dns_fixedname_t fixed; 1884 dns_name_t *name; 1885 const char *str = cfg_obj_asstring(cfg_tuple_get( 1886 alternate, "name")); 1887 isc_buffer_t buffer; 1888 in_port_t myport = port; 1889 1890 isc_buffer_init(&buffer, str, strlen(str)); 1891 isc_buffer_add(&buffer, strlen(str)); 1892 dns_fixedname_init(&fixed); 1893 name = dns_fixedname_name(&fixed); 1894 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1895 ISC_FALSE, NULL)); 1896 1897 portobj = cfg_tuple_get(alternate, "port"); 1898 if (cfg_obj_isuint32(portobj)) { 1899 isc_uint32_t val = cfg_obj_asuint32(portobj); 1900 if (val > ISC_UINT16_MAX) { 1901 cfg_obj_log(portobj, ns_g_lctx, 1902 ISC_LOG_ERROR, 1903 "port '%u' out of range", 1904 val); 1905 return (ISC_R_RANGE); 1906 } 1907 myport = (in_port_t) val; 1908 } 1909 CHECK(dns_resolver_addalternate(view->resolver, NULL, 1910 name, myport)); 1911 continue; 1912 } 1913 1914 sa = *cfg_obj_assockaddr(alternate); 1915 if (isc_sockaddr_getport(&sa) == 0) 1916 isc_sockaddr_setport(&sa, port); 1917 CHECK(dns_resolver_addalternate(view->resolver, &sa, 1918 NULL, 0)); 1919 } 1920 1921 cleanup: 1922 return (result); 1923} 1924 1925static isc_result_t 1926configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 1927 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 1928{ 1929 const cfg_obj_t *portobj; 1930 const cfg_obj_t *faddresses; 1931 const cfg_listelt_t *element; 1932 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 1933 isc_sockaddrlist_t addresses; 1934 isc_sockaddr_t *sa; 1935 isc_result_t result; 1936 in_port_t port; 1937 1938 /* 1939 * Determine which port to send forwarded requests to. 1940 */ 1941 if (ns_g_lwresdonly && ns_g_port != 0) 1942 port = ns_g_port; 1943 else 1944 CHECKM(ns_config_getport(config, &port), "port"); 1945 1946 if (forwarders != NULL) { 1947 portobj = cfg_tuple_get(forwarders, "port"); 1948 if (cfg_obj_isuint32(portobj)) { 1949 isc_uint32_t val = cfg_obj_asuint32(portobj); 1950 if (val > ISC_UINT16_MAX) { 1951 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1952 "port '%u' out of range", val); 1953 return (ISC_R_RANGE); 1954 } 1955 port = (in_port_t) val; 1956 } 1957 } 1958 1959 faddresses = NULL; 1960 if (forwarders != NULL) 1961 faddresses = cfg_tuple_get(forwarders, "addresses"); 1962 1963 ISC_LIST_INIT(addresses); 1964 1965 for (element = cfg_list_first(faddresses); 1966 element != NULL; 1967 element = cfg_list_next(element)) 1968 { 1969 const cfg_obj_t *forwarder = cfg_listelt_value(element); 1970 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 1971 if (sa == NULL) { 1972 result = ISC_R_NOMEMORY; 1973 goto cleanup; 1974 } 1975 *sa = *cfg_obj_assockaddr(forwarder); 1976 if (isc_sockaddr_getport(sa) == 0) 1977 isc_sockaddr_setport(sa, port); 1978 ISC_LINK_INIT(sa, link); 1979 ISC_LIST_APPEND(addresses, sa, link); 1980 } 1981 1982 if (ISC_LIST_EMPTY(addresses)) { 1983 if (forwardtype != NULL) 1984 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 1985 "no forwarders seen; disabling " 1986 "forwarding"); 1987 fwdpolicy = dns_fwdpolicy_none; 1988 } else { 1989 if (forwardtype == NULL) 1990 fwdpolicy = dns_fwdpolicy_first; 1991 else { 1992 const char *forwardstr = cfg_obj_asstring(forwardtype); 1993 if (strcasecmp(forwardstr, "first") == 0) 1994 fwdpolicy = dns_fwdpolicy_first; 1995 else if (strcasecmp(forwardstr, "only") == 0) 1996 fwdpolicy = dns_fwdpolicy_only; 1997 else 1998 INSIST(0); 1999 } 2000 } 2001 2002 result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 2003 fwdpolicy); 2004 if (result != ISC_R_SUCCESS) { 2005 char namebuf[DNS_NAME_FORMATSIZE]; 2006 dns_name_format(origin, namebuf, sizeof(namebuf)); 2007 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 2008 "could not set up forwarding for domain '%s': %s", 2009 namebuf, isc_result_totext(result)); 2010 goto cleanup; 2011 } 2012 2013 result = ISC_R_SUCCESS; 2014 2015 cleanup: 2016 2017 while (!ISC_LIST_EMPTY(addresses)) { 2018 sa = ISC_LIST_HEAD(addresses); 2019 ISC_LIST_UNLINK(addresses, sa, link); 2020 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 2021 } 2022 2023 return (result); 2024} 2025 2026/* 2027 * Create a new view and add it to the list. 2028 * 2029 * If 'vconfig' is NULL, create the default view. 2030 * 2031 * The view created is attached to '*viewp'. 2032 */ 2033static isc_result_t 2034create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 2035 dns_view_t **viewp) 2036{ 2037 isc_result_t result; 2038 const char *viewname; 2039 dns_rdataclass_t viewclass; 2040 dns_view_t *view = NULL; 2041 2042 if (vconfig != NULL) { 2043 const cfg_obj_t *classobj = NULL; 2044 2045 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 2046 classobj = cfg_tuple_get(vconfig, "class"); 2047 result = ns_config_getclass(classobj, dns_rdataclass_in, 2048 &viewclass); 2049 } else { 2050 viewname = "_default"; 2051 viewclass = dns_rdataclass_in; 2052 } 2053 result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 2054 if (result == ISC_R_SUCCESS) 2055 return (ISC_R_EXISTS); 2056 if (result != ISC_R_NOTFOUND) 2057 return (result); 2058 INSIST(view == NULL); 2059 2060 result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 2061 if (result != ISC_R_SUCCESS) 2062 return (result); 2063 2064 ISC_LIST_APPEND(*viewlist, view, link); 2065 dns_view_attach(view, viewp); 2066 return (ISC_R_SUCCESS); 2067} 2068 2069/* 2070 * Configure or reconfigure a zone. 2071 */ 2072static isc_result_t 2073configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 2074 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 2075 cfg_aclconfctx_t *aclconf) 2076{ 2077 dns_view_t *pview = NULL; /* Production view */ 2078 dns_zone_t *zone = NULL; /* New or reused zone */ 2079 dns_zone_t *dupzone = NULL; 2080 const cfg_obj_t *options = NULL; 2081 const cfg_obj_t *zoptions = NULL; 2082 const cfg_obj_t *typeobj = NULL; 2083 const cfg_obj_t *forwarders = NULL; 2084 const cfg_obj_t *forwardtype = NULL; 2085 const cfg_obj_t *only = NULL; 2086 isc_result_t result; 2087 isc_result_t tresult; 2088 isc_buffer_t buffer; 2089 dns_fixedname_t fixorigin; 2090 dns_name_t *origin; 2091 const char *zname; 2092 dns_rdataclass_t zclass; 2093 const char *ztypestr; 2094 2095 options = NULL; 2096 (void)cfg_map_get(config, "options", &options); 2097 2098 zoptions = cfg_tuple_get(zconfig, "options"); 2099 2100 /* 2101 * Get the zone origin as a dns_name_t. 2102 */ 2103 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 2104 isc_buffer_init(&buffer, zname, strlen(zname)); 2105 isc_buffer_add(&buffer, strlen(zname)); 2106 dns_fixedname_init(&fixorigin); 2107 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 2108 &buffer, dns_rootname, ISC_FALSE, NULL)); 2109 origin = dns_fixedname_name(&fixorigin); 2110 2111 CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 2112 view->rdclass, &zclass)); 2113 if (zclass != view->rdclass) { 2114 const char *vname = NULL; 2115 if (vconfig != NULL) 2116 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 2117 "name")); 2118 else 2119 vname = "<default view>"; 2120 2121 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2122 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2123 "zone '%s': wrong class for view '%s'", 2124 zname, vname); 2125 result = ISC_R_FAILURE; 2126 goto cleanup; 2127 } 2128 2129 (void)cfg_map_get(zoptions, "type", &typeobj); 2130 if (typeobj == NULL) { 2131 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 2132 "zone '%s' 'type' not specified", zname); 2133 return (ISC_R_FAILURE); 2134 } 2135 ztypestr = cfg_obj_asstring(typeobj); 2136 2137 /* 2138 * "hints zones" aren't zones. If we've got one, 2139 * configure it and return. 2140 */ 2141 if (strcasecmp(ztypestr, "hint") == 0) { 2142 const cfg_obj_t *fileobj = NULL; 2143 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 2144 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2145 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2146 "zone '%s': 'file' not specified", 2147 zname); 2148 result = ISC_R_FAILURE; 2149 goto cleanup; 2150 } 2151 if (dns_name_equal(origin, dns_rootname)) { 2152 const char *hintsfile = cfg_obj_asstring(fileobj); 2153 2154 result = configure_hints(view, hintsfile); 2155 if (result != ISC_R_SUCCESS) { 2156 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2157 NS_LOGMODULE_SERVER, 2158 ISC_LOG_ERROR, 2159 "could not configure root hints " 2160 "from '%s': %s", hintsfile, 2161 isc_result_totext(result)); 2162 goto cleanup; 2163 } 2164 /* 2165 * Hint zones may also refer to delegation only points. 2166 */ 2167 only = NULL; 2168 tresult = cfg_map_get(zoptions, "delegation-only", 2169 &only); 2170 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 2171 CHECK(dns_view_adddelegationonly(view, origin)); 2172 } else { 2173 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2174 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2175 "ignoring non-root hint zone '%s'", 2176 zname); 2177 result = ISC_R_SUCCESS; 2178 } 2179 /* Skip ordinary zone processing. */ 2180 goto cleanup; 2181 } 2182 2183 /* 2184 * "forward zones" aren't zones either. Translate this syntax into 2185 * the appropriate selective forwarding configuration and return. 2186 */ 2187 if (strcasecmp(ztypestr, "forward") == 0) { 2188 forwardtype = NULL; 2189 forwarders = NULL; 2190 2191 (void)cfg_map_get(zoptions, "forward", &forwardtype); 2192 (void)cfg_map_get(zoptions, "forwarders", &forwarders); 2193 result = configure_forward(config, view, origin, forwarders, 2194 forwardtype); 2195 goto cleanup; 2196 } 2197 2198 /* 2199 * "delegation-only zones" aren't zones either. 2200 */ 2201 if (strcasecmp(ztypestr, "delegation-only") == 0) { 2202 result = dns_view_adddelegationonly(view, origin); 2203 goto cleanup; 2204 } 2205 2206 /* 2207 * Check for duplicates in the new zone table. 2208 */ 2209 result = dns_view_findzone(view, origin, &dupzone); 2210 if (result == ISC_R_SUCCESS) { 2211 /* 2212 * We already have this zone! 2213 */ 2214 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 2215 "zone '%s' already exists", zname); 2216 dns_zone_detach(&dupzone); 2217 result = ISC_R_EXISTS; 2218 goto cleanup; 2219 } 2220 INSIST(dupzone == NULL); 2221 2222 /* 2223 * See if we can reuse an existing zone. This is 2224 * only possible if all of these are true: 2225 * - The zone's view exists 2226 * - A zone with the right name exists in the view 2227 * - The zone is compatible with the config 2228 * options (e.g., an existing master zone cannot 2229 * be reused if the options specify a slave zone) 2230 */ 2231 result = dns_viewlist_find(&ns_g_server->viewlist, 2232 view->name, view->rdclass, 2233 &pview); 2234 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2235 goto cleanup; 2236 if (pview != NULL) 2237 result = dns_view_findzone(pview, origin, &zone); 2238 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2239 goto cleanup; 2240 if (zone != NULL && !ns_zone_reusable(zone, zconfig)) 2241 dns_zone_detach(&zone); 2242 2243 if (zone != NULL) { 2244 /* 2245 * We found a reusable zone. Make it use the 2246 * new view. 2247 */ 2248 dns_zone_setview(zone, view); 2249 if (view->acache != NULL) 2250 dns_zone_setacache(zone, view->acache); 2251 } else { 2252 /* 2253 * We cannot reuse an existing zone, we have 2254 * to create a new one. 2255 */ 2256 CHECK(dns_zone_create(&zone, mctx)); 2257 CHECK(dns_zone_setorigin(zone, origin)); 2258 dns_zone_setview(zone, view); 2259 if (view->acache != NULL) 2260 dns_zone_setacache(zone, view->acache); 2261 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 2262 } 2263 2264 /* 2265 * If the zone contains a 'forwarders' statement, configure 2266 * selective forwarding. 2267 */ 2268 forwarders = NULL; 2269 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 2270 { 2271 forwardtype = NULL; 2272 (void)cfg_map_get(zoptions, "forward", &forwardtype); 2273 CHECK(configure_forward(config, view, origin, forwarders, 2274 forwardtype)); 2275 } 2276 2277 /* 2278 * Stub and forward zones may also refer to delegation only points. 2279 */ 2280 only = NULL; 2281 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 2282 { 2283 if (cfg_obj_asboolean(only)) 2284 CHECK(dns_view_adddelegationonly(view, origin)); 2285 } 2286 2287 /* 2288 * Configure the zone. 2289 */ 2290 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); 2291 2292 /* 2293 * Add the zone to its view in the new view list. 2294 */ 2295 CHECK(dns_view_addzone(view, zone)); 2296 2297 cleanup: 2298 if (zone != NULL) 2299 dns_zone_detach(&zone); 2300 if (pview != NULL) 2301 dns_view_detach(&pview); 2302 2303 return (result); 2304} 2305 2306/* 2307 * Configure a single server quota. 2308 */ 2309static void 2310configure_server_quota(const cfg_obj_t **maps, const char *name, 2311 isc_quota_t *quota) 2312{ 2313 const cfg_obj_t *obj = NULL; 2314 isc_result_t result; 2315 2316 result = ns_config_get(maps, name, &obj); 2317 INSIST(result == ISC_R_SUCCESS); 2318 isc_quota_max(quota, cfg_obj_asuint32(obj)); 2319} 2320 2321/* 2322 * This function is called as soon as the 'directory' statement has been 2323 * parsed. This can be extended to support other options if necessary. 2324 */ 2325static isc_result_t 2326directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 2327 isc_result_t result; 2328 const char *directory; 2329 2330 REQUIRE(strcasecmp("directory", clausename) == 0); 2331 2332 UNUSED(arg); 2333 UNUSED(clausename); 2334 2335 /* 2336 * Change directory. 2337 */ 2338 directory = cfg_obj_asstring(obj); 2339 2340 if (! isc_file_ischdiridempotent(directory)) 2341 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2342 "option 'directory' contains relative path '%s'", 2343 directory); 2344 2345 result = isc_dir_chdir(directory); 2346 if (result != ISC_R_SUCCESS) { 2347 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 2348 "change directory to '%s' failed: %s", 2349 directory, isc_result_totext(result)); 2350 return (result); 2351 } 2352 2353 return (ISC_R_SUCCESS); 2354} 2355 2356static void 2357scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 2358 isc_boolean_t match_mapped = server->aclenv.match_mapped; 2359 2360 ns_interfacemgr_scan(server->interfacemgr, verbose); 2361 /* 2362 * Update the "localhost" and "localnets" ACLs to match the 2363 * current set of network interfaces. 2364 */ 2365 dns_aclenv_copy(&server->aclenv, 2366 ns_interfacemgr_getaclenv(server->interfacemgr)); 2367 2368 server->aclenv.match_mapped = match_mapped; 2369} 2370 2371static isc_result_t 2372add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) { 2373 ns_listenelt_t *lelt = NULL; 2374 dns_acl_t *src_acl = NULL; 2375 dns_aclelement_t aelt; 2376 isc_result_t result; 2377 isc_sockaddr_t any_sa6; 2378 2379 REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 2380 2381 isc_sockaddr_any6(&any_sa6); 2382 if (!isc_sockaddr_equal(&any_sa6, addr)) { 2383 aelt.type = dns_aclelementtype_ipprefix; 2384 aelt.negative = ISC_FALSE; 2385 aelt.u.ip_prefix.prefixlen = 128; 2386 isc_netaddr_fromin6(&aelt.u.ip_prefix.address, 2387 &addr->type.sin6.sin6_addr); 2388 2389 result = dns_acl_create(mctx, 1, &src_acl); 2390 if (result != ISC_R_SUCCESS) 2391 return (result); 2392 result = dns_acl_appendelement(src_acl, &aelt); 2393 if (result != ISC_R_SUCCESS) 2394 goto clean; 2395 2396 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 2397 src_acl, &lelt); 2398 if (result != ISC_R_SUCCESS) 2399 goto clean; 2400 ISC_LIST_APPEND(list->elts, lelt, link); 2401 } 2402 2403 return (ISC_R_SUCCESS); 2404 2405 clean: 2406 INSIST(lelt == NULL); 2407 dns_acl_detach(&src_acl); 2408 2409 return (result); 2410} 2411 2412/* 2413 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 2414 * to update the listening interfaces accordingly. 2415 * We currently only consider IPv6, because this only affects IPv6 wildcard 2416 * sockets. 2417 */ 2418static void 2419adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 2420 isc_result_t result; 2421 ns_listenlist_t *list = NULL; 2422 dns_view_t *view; 2423 dns_zone_t *zone, *next; 2424 isc_sockaddr_t addr, *addrp; 2425 2426 result = ns_listenlist_create(mctx, &list); 2427 if (result != ISC_R_SUCCESS) 2428 return; 2429 2430 for (view = ISC_LIST_HEAD(server->viewlist); 2431 view != NULL; 2432 view = ISC_LIST_NEXT(view, link)) { 2433 dns_dispatch_t *dispatch6; 2434 2435 dispatch6 = dns_resolver_dispatchv6(view->resolver); 2436 if (dispatch6 == NULL) 2437 continue; 2438 result = dns_dispatch_getlocaladdress(dispatch6, &addr); 2439 if (result != ISC_R_SUCCESS) 2440 goto fail; 2441 result = add_listenelt(mctx, list, &addr); 2442 if (result != ISC_R_SUCCESS) 2443 goto fail; 2444 } 2445 2446 zone = NULL; 2447 for (result = dns_zone_first(server->zonemgr, &zone); 2448 result == ISC_R_SUCCESS; 2449 next = NULL, result = dns_zone_next(zone, &next), zone = next) { 2450 dns_view_t *zoneview; 2451 2452 /* 2453 * At this point the zone list may contain a stale zone 2454 * just removed from the configuration. To see the validity, 2455 * check if the corresponding view is in our current view list. 2456 * There may also be old zones that are still in the process 2457 * of shutting down and have detached from their old view 2458 * (zoneview == NULL). 2459 */ 2460 zoneview = dns_zone_getview(zone); 2461 if (zoneview == NULL) 2462 continue; 2463 for (view = ISC_LIST_HEAD(server->viewlist); 2464 view != NULL && view != zoneview; 2465 view = ISC_LIST_NEXT(view, link)) 2466 ; 2467 if (view == NULL) 2468 continue; 2469 2470 addrp = dns_zone_getnotifysrc6(zone); 2471 result = add_listenelt(mctx, list, addrp); 2472 if (result != ISC_R_SUCCESS) 2473 goto fail; 2474 2475 addrp = dns_zone_getxfrsource6(zone); 2476 result = add_listenelt(mctx, list, addrp); 2477 if (result != ISC_R_SUCCESS) 2478 goto fail; 2479 } 2480 2481 ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 2482 2483 clean: 2484 ns_listenlist_detach(&list); 2485 return; 2486 2487 fail: 2488 /* 2489 * Even when we failed the procedure, most of other interfaces 2490 * should work correctly. We therefore just warn it. 2491 */ 2492 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2493 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2494 "could not adjust the listen-on list; " 2495 "some interfaces may not work"); 2496 goto clean; 2497} 2498 2499/* 2500 * This event callback is invoked to do periodic network 2501 * interface scanning. 2502 */ 2503static void 2504interface_timer_tick(isc_task_t *task, isc_event_t *event) { 2505 isc_result_t result; 2506 ns_server_t *server = (ns_server_t *) event->ev_arg; 2507 INSIST(task == server->task); 2508 UNUSED(task); 2509 isc_event_free(&event); 2510 /* 2511 * XXX should scan interfaces unlocked and get exclusive access 2512 * only to replace ACLs. 2513 */ 2514 result = isc_task_beginexclusive(server->task); 2515 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2516 scan_interfaces(server, ISC_FALSE); 2517 isc_task_endexclusive(server->task); 2518} 2519 2520static void 2521heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 2522 ns_server_t *server = (ns_server_t *) event->ev_arg; 2523 dns_view_t *view; 2524 2525 UNUSED(task); 2526 isc_event_free(&event); 2527 view = ISC_LIST_HEAD(server->viewlist); 2528 while (view != NULL) { 2529 dns_view_dialup(view); 2530 view = ISC_LIST_NEXT(view, link); 2531 } 2532} 2533 2534static void 2535pps_timer_tick(isc_task_t *task, isc_event_t *event) { 2536 static unsigned int oldrequests = 0; 2537 unsigned int requests = ns_client_requests; 2538 2539 UNUSED(task); 2540 isc_event_free(&event); 2541 2542 /* 2543 * Don't worry about wrapping as the overflow result will be right. 2544 */ 2545 dns_pps = (requests - oldrequests) / 1200; 2546 oldrequests = requests; 2547} 2548 2549/* 2550 * Replace the current value of '*field', a dynamically allocated 2551 * string or NULL, with a dynamically allocated copy of the 2552 * null-terminated string pointed to by 'value', or NULL. 2553 */ 2554static isc_result_t 2555setstring(ns_server_t *server, char **field, const char *value) { 2556 char *copy; 2557 2558 if (value != NULL) { 2559 copy = isc_mem_strdup(server->mctx, value); 2560 if (copy == NULL) 2561 return (ISC_R_NOMEMORY); 2562 } else { 2563 copy = NULL; 2564 } 2565 2566 if (*field != NULL) 2567 isc_mem_free(server->mctx, *field); 2568 2569 *field = copy; 2570 return (ISC_R_SUCCESS); 2571} 2572 2573/* 2574 * Replace the current value of '*field', a dynamically allocated 2575 * string or NULL, with another dynamically allocated string 2576 * or NULL if whether 'obj' is a string or void value, respectively. 2577 */ 2578static isc_result_t 2579setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 2580 if (cfg_obj_isvoid(obj)) 2581 return (setstring(server, field, NULL)); 2582 else 2583 return (setstring(server, field, cfg_obj_asstring(obj))); 2584} 2585 2586static void 2587set_limit(const cfg_obj_t **maps, const char *configname, 2588 const char *description, isc_resource_t resourceid, 2589 isc_resourcevalue_t defaultvalue) 2590{ 2591 const cfg_obj_t *obj = NULL; 2592 const char *resource; 2593 isc_resourcevalue_t value; 2594 isc_result_t result; 2595 2596 if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 2597 return; 2598 2599 if (cfg_obj_isstring(obj)) { 2600 resource = cfg_obj_asstring(obj); 2601 if (strcasecmp(resource, "unlimited") == 0) 2602 value = ISC_RESOURCE_UNLIMITED; 2603 else { 2604 INSIST(strcasecmp(resource, "default") == 0); 2605 value = defaultvalue; 2606 } 2607 } else 2608 value = cfg_obj_asuint64(obj); 2609 2610 result = isc_resource_setlimit(resourceid, value); 2611 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2612 result == ISC_R_SUCCESS ? 2613 ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 2614 "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s", 2615 description, value, isc_result_totext(result)); 2616} 2617 2618#define SETLIMIT(cfgvar, resource, description) \ 2619 set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 2620 ns_g_init ## resource) 2621 2622static void 2623set_limits(const cfg_obj_t **maps) { 2624 SETLIMIT("stacksize", stacksize, "stack size"); 2625 SETLIMIT("datasize", datasize, "data size"); 2626 SETLIMIT("coresize", coresize, "core size"); 2627 SETLIMIT("files", openfiles, "open files"); 2628} 2629 2630static isc_result_t 2631portlist_fromconf(dns_portlist_t *portlist, unsigned int family, 2632 const cfg_obj_t *ports) 2633{ 2634 const cfg_listelt_t *element; 2635 isc_result_t result = ISC_R_SUCCESS; 2636 2637 for (element = cfg_list_first(ports); 2638 element != NULL; 2639 element = cfg_list_next(element)) { 2640 const cfg_obj_t *obj = cfg_listelt_value(element); 2641 in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 2642 2643 result = dns_portlist_add(portlist, family, port); 2644 if (result != ISC_R_SUCCESS) 2645 break; 2646 } 2647 return (result); 2648} 2649 2650static isc_result_t 2651removed(dns_zone_t *zone, void *uap) { 2652 const char *type; 2653 2654 if (dns_zone_getview(zone) != uap) 2655 return (ISC_R_SUCCESS); 2656 2657 switch (dns_zone_gettype(zone)) { 2658 case dns_zone_master: 2659 type = "master"; 2660 break; 2661 case dns_zone_slave: 2662 type = "slave"; 2663 break; 2664 case dns_zone_stub: 2665 type = "stub"; 2666 break; 2667 default: 2668 type = "other"; 2669 break; 2670 } 2671 dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); 2672 return (ISC_R_SUCCESS); 2673} 2674 2675static isc_result_t 2676load_configuration(const char *filename, ns_server_t *server, 2677 isc_boolean_t first_time) 2678{ 2679 isc_result_t result; 2680 isc_interval_t interval; 2681 cfg_parser_t *parser = NULL; 2682 cfg_obj_t *config; 2683 const cfg_obj_t *options; 2684 const cfg_obj_t *views; 2685 const cfg_obj_t *obj; 2686 const cfg_obj_t *v4ports, *v6ports; 2687 const cfg_obj_t *maps[3]; 2688 const cfg_obj_t *builtin_views; 2689 const cfg_listelt_t *element; 2690 dns_view_t *view = NULL; 2691 dns_view_t *view_next; 2692 dns_viewlist_t viewlist; 2693 dns_viewlist_t tmpviewlist; 2694 cfg_aclconfctx_t aclconfctx; 2695 isc_uint32_t interface_interval; 2696 isc_uint32_t heartbeat_interval; 2697 isc_uint32_t udpsize; 2698 in_port_t listen_port; 2699 int i; 2700 2701 cfg_aclconfctx_init(&aclconfctx); 2702 ISC_LIST_INIT(viewlist); 2703 2704 /* Ensure exclusive access to configuration data. */ 2705 result = isc_task_beginexclusive(server->task); 2706 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2707 2708 /* 2709 * Parse the global default pseudo-config file. 2710 */ 2711 if (first_time) { 2712 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 2713 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 2714 &ns_g_defaults) == 2715 ISC_R_SUCCESS); 2716 } 2717 2718 /* 2719 * Parse the configuration file using the new config code. 2720 */ 2721 result = ISC_R_FAILURE; 2722 config = NULL; 2723 2724 /* 2725 * Unless this is lwresd with the -C option, parse the config file. 2726 */ 2727 if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 2728 isc_log_write(ns_g_lctx, 2729 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2730 ISC_LOG_INFO, "loading configuration from '%s'", 2731 filename); 2732 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2733 cfg_parser_setcallback(parser, directory_callback, NULL); 2734 result = cfg_parse_file(parser, filename, &cfg_type_namedconf, 2735 &config); 2736 } 2737 2738 /* 2739 * If this is lwresd with the -C option, or lwresd with no -C or -c 2740 * option where the above parsing failed, parse resolv.conf. 2741 */ 2742 if (ns_g_lwresdonly && 2743 (lwresd_g_useresolvconf || 2744 (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 2745 { 2746 isc_log_write(ns_g_lctx, 2747 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2748 ISC_LOG_INFO, "loading configuration from '%s'", 2749 lwresd_g_resolvconffile); 2750 if (parser != NULL) 2751 cfg_parser_destroy(&parser); 2752 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2753 result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser, 2754 &config); 2755 } 2756 CHECK(result); 2757 2758 /* 2759 * Check the validity of the configuration. 2760 */ 2761 CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 2762 2763 /* 2764 * Fill in the maps array, used for resolving defaults. 2765 */ 2766 i = 0; 2767 options = NULL; 2768 result = cfg_map_get(config, "options", &options); 2769 if (result == ISC_R_SUCCESS) 2770 maps[i++] = options; 2771 maps[i++] = ns_g_defaults; 2772 maps[i++] = NULL; 2773 2774 /* 2775 * Set process limits, which (usually) needs to be done as root. 2776 */ 2777 set_limits(maps); 2778 2779 /* 2780 * Configure various server options. 2781 */ 2782 configure_server_quota(maps, "transfers-out", &server->xfroutquota); 2783 configure_server_quota(maps, "tcp-clients", &server->tcpquota); 2784 configure_server_quota(maps, "recursive-clients", 2785 &server->recursionquota); 2786 if (server->recursionquota.max > 1000) 2787 isc_quota_soft(&server->recursionquota, 2788 server->recursionquota.max - 100); 2789 else 2790 isc_quota_soft(&server->recursionquota, 0); 2791 2792 CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx, 2793 ns_g_mctx, &server->blackholeacl)); 2794 if (server->blackholeacl != NULL) 2795 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 2796 server->blackholeacl); 2797 2798 obj = NULL; 2799 result = ns_config_get(maps, "match-mapped-addresses", &obj); 2800 INSIST(result == ISC_R_SUCCESS); 2801 server->aclenv.match_mapped = cfg_obj_asboolean(obj); 2802 2803 v4ports = NULL; 2804 v6ports = NULL; 2805 (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports); 2806 (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports); 2807 if (v4ports != NULL || v6ports != NULL) { 2808 dns_portlist_t *portlist = NULL; 2809 result = dns_portlist_create(ns_g_mctx, &portlist); 2810 if (result == ISC_R_SUCCESS && v4ports != NULL) 2811 result = portlist_fromconf(portlist, AF_INET, v4ports); 2812 if (result == ISC_R_SUCCESS && v6ports != NULL) 2813 portlist_fromconf(portlist, AF_INET6, v6ports); 2814 if (result == ISC_R_SUCCESS) 2815 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist); 2816 if (portlist != NULL) 2817 dns_portlist_detach(&portlist); 2818 CHECK(result); 2819 } else 2820 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL); 2821 2822 /* 2823 * Set the EDNS UDP size when we don't match a view. 2824 */ 2825 obj = NULL; 2826 result = ns_config_get(maps, "edns-udp-size", &obj); 2827 INSIST(result == ISC_R_SUCCESS); 2828 udpsize = cfg_obj_asuint32(obj); 2829 if (udpsize < 512) 2830 udpsize = 512; 2831 if (udpsize > 4096) 2832 udpsize = 4096; 2833 ns_g_udpsize = (isc_uint16_t)udpsize; 2834 2835 /* 2836 * Configure the zone manager. 2837 */ 2838 obj = NULL; 2839 result = ns_config_get(maps, "transfers-in", &obj); 2840 INSIST(result == ISC_R_SUCCESS); 2841 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 2842 2843 obj = NULL; 2844 result = ns_config_get(maps, "transfers-per-ns", &obj); 2845 INSIST(result == ISC_R_SUCCESS); 2846 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 2847 2848 obj = NULL; 2849 result = ns_config_get(maps, "serial-query-rate", &obj); 2850 INSIST(result == ISC_R_SUCCESS); 2851 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 2852 2853 /* 2854 * Determine which port to use for listening for incoming connections. 2855 */ 2856 if (ns_g_port != 0) 2857 listen_port = ns_g_port; 2858 else 2859 CHECKM(ns_config_getport(config, &listen_port), "port"); 2860 2861 /* 2862 * Find the listen queue depth. 2863 */ 2864 obj = NULL; 2865 result = ns_config_get(maps, "tcp-listen-queue", &obj); 2866 INSIST(result == ISC_R_SUCCESS); 2867 ns_g_listen = cfg_obj_asuint32(obj); 2868 if (ns_g_listen < 3) 2869 ns_g_listen = 3; 2870 2871 /* 2872 * Configure the interface manager according to the "listen-on" 2873 * statement. 2874 */ 2875 { 2876 const cfg_obj_t *clistenon = NULL; 2877 ns_listenlist_t *listenon = NULL; 2878 2879 clistenon = NULL; 2880 /* 2881 * Even though listen-on is present in the default 2882 * configuration, we can't use it here, since it isn't 2883 * used if we're in lwresd mode. This way is easier. 2884 */ 2885 if (options != NULL) 2886 (void)cfg_map_get(options, "listen-on", &clistenon); 2887 if (clistenon != NULL) { 2888 result = ns_listenlist_fromconfig(clistenon, 2889 config, 2890 &aclconfctx, 2891 ns_g_mctx, 2892 &listenon); 2893 } else if (!ns_g_lwresdonly) { 2894 /* 2895 * Not specified, use default. 2896 */ 2897 CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2898 ISC_TRUE, &listenon)); 2899 } 2900 if (listenon != NULL) { 2901 ns_interfacemgr_setlistenon4(server->interfacemgr, 2902 listenon); 2903 ns_listenlist_detach(&listenon); 2904 } 2905 } 2906 /* 2907 * Ditto for IPv6. 2908 */ 2909 { 2910 const cfg_obj_t *clistenon = NULL; 2911 ns_listenlist_t *listenon = NULL; 2912 2913 if (options != NULL) 2914 (void)cfg_map_get(options, "listen-on-v6", &clistenon); 2915 if (clistenon != NULL) { 2916 result = ns_listenlist_fromconfig(clistenon, 2917 config, 2918 &aclconfctx, 2919 ns_g_mctx, 2920 &listenon); 2921 } else if (!ns_g_lwresdonly) { 2922 /* 2923 * Not specified, use default. 2924 */ 2925 CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2926 ISC_FALSE, &listenon)); 2927 } 2928 if (listenon != NULL) { 2929 ns_interfacemgr_setlistenon6(server->interfacemgr, 2930 listenon); 2931 ns_listenlist_detach(&listenon); 2932 } 2933 } 2934 2935 /* 2936 * Rescan the interface list to pick up changes in the 2937 * listen-on option. It's important that we do this before we try 2938 * to configure the query source, since the dispatcher we use might 2939 * be shared with an interface. 2940 */ 2941 scan_interfaces(server, ISC_TRUE); 2942 2943 /* 2944 * Arrange for further interface scanning to occur periodically 2945 * as specified by the "interface-interval" option. 2946 */ 2947 obj = NULL; 2948 result = ns_config_get(maps, "interface-interval", &obj); 2949 INSIST(result == ISC_R_SUCCESS); 2950 interface_interval = cfg_obj_asuint32(obj) * 60; 2951 if (interface_interval == 0) { 2952 CHECK(isc_timer_reset(server->interface_timer, 2953 isc_timertype_inactive, 2954 NULL, NULL, ISC_TRUE)); 2955 } else if (server->interface_interval != interface_interval) { 2956 isc_interval_set(&interval, interface_interval, 0); 2957 CHECK(isc_timer_reset(server->interface_timer, 2958 isc_timertype_ticker, 2959 NULL, &interval, ISC_FALSE)); 2960 } 2961 server->interface_interval = interface_interval; 2962 2963 /* 2964 * Configure the dialup heartbeat timer. 2965 */ 2966 obj = NULL; 2967 result = ns_config_get(maps, "heartbeat-interval", &obj); 2968 INSIST(result == ISC_R_SUCCESS); 2969 heartbeat_interval = cfg_obj_asuint32(obj) * 60; 2970 if (heartbeat_interval == 0) { 2971 CHECK(isc_timer_reset(server->heartbeat_timer, 2972 isc_timertype_inactive, 2973 NULL, NULL, ISC_TRUE)); 2974 } else if (server->heartbeat_interval != heartbeat_interval) { 2975 isc_interval_set(&interval, heartbeat_interval, 0); 2976 CHECK(isc_timer_reset(server->heartbeat_timer, 2977 isc_timertype_ticker, 2978 NULL, &interval, ISC_FALSE)); 2979 } 2980 server->heartbeat_interval = heartbeat_interval; 2981 2982 isc_interval_set(&interval, 1200, 0); 2983 CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, 2984 &interval, ISC_FALSE)); 2985 2986 /* 2987 * Configure and freeze all explicit views. Explicit 2988 * views that have zones were already created at parsing 2989 * time, but views with no zones must be created here. 2990 */ 2991 views = NULL; 2992 (void)cfg_map_get(config, "view", &views); 2993 for (element = cfg_list_first(views); 2994 element != NULL; 2995 element = cfg_list_next(element)) 2996 { 2997 const cfg_obj_t *vconfig = cfg_listelt_value(element); 2998 view = NULL; 2999 3000 CHECK(create_view(vconfig, &viewlist, &view)); 3001 INSIST(view != NULL); 3002 CHECK(configure_view(view, config, vconfig, 3003 ns_g_mctx, &aclconfctx, ISC_TRUE)); 3004 dns_view_freeze(view); 3005 dns_view_detach(&view); 3006 } 3007 3008 /* 3009 * Make sure we have a default view if and only if there 3010 * were no explicit views. 3011 */ 3012 if (views == NULL) { 3013 /* 3014 * No explicit views; there ought to be a default view. 3015 * There may already be one created as a side effect 3016 * of zone statements, or we may have to create one. 3017 * In either case, we need to configure and freeze it. 3018 */ 3019 CHECK(create_view(NULL, &viewlist, &view)); 3020 CHECK(configure_view(view, config, NULL, ns_g_mctx, 3021 &aclconfctx, ISC_TRUE)); 3022 dns_view_freeze(view); 3023 dns_view_detach(&view); 3024 } 3025 3026 /* 3027 * Create (or recreate) the built-in views. Currently 3028 * there is only one, the _bind view. 3029 */ 3030 builtin_views = NULL; 3031 RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 3032 &builtin_views) == ISC_R_SUCCESS); 3033 for (element = cfg_list_first(builtin_views); 3034 element != NULL; 3035 element = cfg_list_next(element)) 3036 { 3037 const cfg_obj_t *vconfig = cfg_listelt_value(element); 3038 CHECK(create_view(vconfig, &viewlist, &view)); 3039 CHECK(configure_view(view, config, vconfig, ns_g_mctx, 3040 &aclconfctx, ISC_FALSE)); 3041 dns_view_freeze(view); 3042 dns_view_detach(&view); 3043 view = NULL; 3044 } 3045 3046 /* 3047 * Swap our new view list with the production one. 3048 */ 3049 tmpviewlist = server->viewlist; 3050 server->viewlist = viewlist; 3051 viewlist = tmpviewlist; 3052 3053 /* 3054 * Load the TKEY information from the configuration. 3055 */ 3056 if (options != NULL) { 3057 dns_tkeyctx_t *t = NULL; 3058 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 3059 &t), 3060 "configuring TKEY"); 3061 if (server->tkeyctx != NULL) 3062 dns_tkeyctx_destroy(&server->tkeyctx); 3063 server->tkeyctx = t; 3064 } 3065 3066 /* 3067 * Bind the control port(s). 3068 */ 3069 CHECKM(ns_controls_configure(ns_g_server->controls, config, 3070 &aclconfctx), 3071 "binding control channel(s)"); 3072 3073 /* 3074 * Bind the lwresd port(s). 3075 */ 3076 CHECKM(ns_lwresd_configure(ns_g_mctx, config), 3077 "binding lightweight resolver ports"); 3078 3079 /* 3080 * Open the source of entropy. 3081 */ 3082 if (first_time) { 3083 obj = NULL; 3084 result = ns_config_get(maps, "random-device", &obj); 3085 if (result != ISC_R_SUCCESS) { 3086 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3087 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3088 "no source of entropy found"); 3089 } else { 3090 const char *randomdev = cfg_obj_asstring(obj); 3091 result = isc_entropy_createfilesource(ns_g_entropy, 3092 randomdev); 3093 if (result != ISC_R_SUCCESS) 3094 isc_log_write(ns_g_lctx, 3095 NS_LOGCATEGORY_GENERAL, 3096 NS_LOGMODULE_SERVER, 3097 ISC_LOG_INFO, 3098 "could not open entropy source " 3099 "%s: %s", 3100 randomdev, 3101 isc_result_totext(result)); 3102#ifdef PATH_RANDOMDEV 3103 if (ns_g_fallbackentropy != NULL) { 3104 if (result != ISC_R_SUCCESS) { 3105 isc_log_write(ns_g_lctx, 3106 NS_LOGCATEGORY_GENERAL, 3107 NS_LOGMODULE_SERVER, 3108 ISC_LOG_INFO, 3109 "using pre-chroot entropy source " 3110 "%s", 3111 PATH_RANDOMDEV); 3112 isc_entropy_detach(&ns_g_entropy); 3113 isc_entropy_attach(ns_g_fallbackentropy, 3114 &ns_g_entropy); 3115 } 3116 isc_entropy_detach(&ns_g_fallbackentropy); 3117 } 3118#endif 3119 } 3120 } 3121 3122 /* 3123 * Relinquish root privileges. 3124 */ 3125 if (first_time) 3126 ns_os_changeuser(); 3127 3128 /* 3129 * Configure the logging system. 3130 * 3131 * Do this after changing UID to make sure that any log 3132 * files specified in named.conf get created by the 3133 * unprivileged user, not root. 3134 */ 3135 if (ns_g_logstderr) { 3136 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3137 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3138 "ignoring config file logging " 3139 "statement due to -g option"); 3140 } else { 3141 const cfg_obj_t *logobj = NULL; 3142 isc_logconfig_t *logc = NULL; 3143 3144 CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 3145 "creating new logging configuration"); 3146 3147 logobj = NULL; 3148 (void)cfg_map_get(config, "logging", &logobj); 3149 if (logobj != NULL) { 3150 CHECKM(ns_log_configure(logc, logobj), 3151 "configuring logging"); 3152 } else { 3153 CHECKM(ns_log_setdefaultchannels(logc), 3154 "setting up default logging channels"); 3155 CHECKM(ns_log_setunmatchedcategory(logc), 3156 "setting up default 'category unmatched'"); 3157 CHECKM(ns_log_setdefaultcategory(logc), 3158 "setting up default 'category default'"); 3159 } 3160 3161 result = isc_logconfig_use(ns_g_lctx, logc); 3162 if (result != ISC_R_SUCCESS) { 3163 isc_logconfig_destroy(&logc); 3164 CHECKM(result, "installing logging configuration"); 3165 } 3166 3167 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3168 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 3169 "now using logging configuration from " 3170 "config file"); 3171 } 3172 3173 /* 3174 * Set the default value of the query logging flag depending 3175 * whether a "queries" category has been defined. This is 3176 * a disgusting hack, but we need to do this for BIND 8 3177 * compatibility. 3178 */ 3179 if (first_time) { 3180 const cfg_obj_t *logobj = NULL; 3181 const cfg_obj_t *categories = NULL; 3182 3183 obj = NULL; 3184 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 3185 server->log_queries = cfg_obj_asboolean(obj); 3186 } else { 3187 3188 (void)cfg_map_get(config, "logging", &logobj); 3189 if (logobj != NULL) 3190 (void)cfg_map_get(logobj, "category", 3191 &categories); 3192 if (categories != NULL) { 3193 const cfg_listelt_t *element; 3194 for (element = cfg_list_first(categories); 3195 element != NULL; 3196 element = cfg_list_next(element)) 3197 { 3198 const cfg_obj_t *catobj; 3199 const char *str; 3200 3201 obj = cfg_listelt_value(element); 3202 catobj = cfg_tuple_get(obj, "name"); 3203 str = cfg_obj_asstring(catobj); 3204 if (strcasecmp(str, "queries") == 0) 3205 server->log_queries = ISC_TRUE; 3206 } 3207 } 3208 } 3209 } 3210 3211 obj = NULL; 3212 if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 3213 if (cfg_obj_isvoid(obj)) 3214 ns_os_writepidfile(NULL, first_time); 3215 else 3216 ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 3217 else if (ns_g_lwresdonly) 3218 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 3219 else 3220 ns_os_writepidfile(ns_g_defaultpidfile, first_time); 3221 3222 obj = NULL; 3223 if (options != NULL && 3224 cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS) 3225 ns_main_setmemstats(cfg_obj_asstring(obj)); 3226 else 3227 ns_main_setmemstats(NULL); 3228 3229 obj = NULL; 3230 result = ns_config_get(maps, "statistics-file", &obj); 3231 INSIST(result == ISC_R_SUCCESS); 3232 CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 3233 "strdup"); 3234 3235 obj = NULL; 3236 result = ns_config_get(maps, "dump-file", &obj); 3237 INSIST(result == ISC_R_SUCCESS); 3238 CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 3239 "strdup"); 3240 3241 obj = NULL; 3242 result = ns_config_get(maps, "recursing-file", &obj); 3243 INSIST(result == ISC_R_SUCCESS); 3244 CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 3245 "strdup"); 3246 3247 obj = NULL; 3248 result = ns_config_get(maps, "version", &obj); 3249 if (result == ISC_R_SUCCESS) { 3250 CHECKM(setoptstring(server, &server->version, obj), "strdup"); 3251 server->version_set = ISC_TRUE; 3252 } else { 3253 server->version_set = ISC_FALSE; 3254 } 3255 3256 obj = NULL; 3257 result = ns_config_get(maps, "hostname", &obj); 3258 if (result == ISC_R_SUCCESS) { 3259 CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 3260 server->hostname_set = ISC_TRUE; 3261 } else { 3262 server->hostname_set = ISC_FALSE; 3263 } 3264 3265 obj = NULL; 3266 result = ns_config_get(maps, "server-id", &obj); 3267 server->server_usehostname = ISC_FALSE; 3268 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 3269 server->server_usehostname = ISC_TRUE; 3270 } else if (result == ISC_R_SUCCESS) { 3271 CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 3272 } else { 3273 result = setstring(server, &server->server_id, NULL); 3274 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3275 } 3276 3277 obj = NULL; 3278 result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 3279 if (result == ISC_R_SUCCESS) { 3280 server->flushonshutdown = cfg_obj_asboolean(obj); 3281 } else { 3282 server->flushonshutdown = ISC_FALSE; 3283 } 3284 3285 result = ISC_R_SUCCESS; 3286 3287 cleanup: 3288 cfg_aclconfctx_destroy(&aclconfctx); 3289 3290 if (parser != NULL) { 3291 if (config != NULL) 3292 cfg_obj_destroy(parser, &config); 3293 cfg_parser_destroy(&parser); 3294 } 3295 3296 if (view != NULL) 3297 dns_view_detach(&view); 3298 3299 /* 3300 * This cleans up either the old production view list 3301 * or our temporary list depending on whether they 3302 * were swapped above or not. 3303 */ 3304 for (view = ISC_LIST_HEAD(viewlist); 3305 view != NULL; 3306 view = view_next) { 3307 view_next = ISC_LIST_NEXT(view, link); 3308 ISC_LIST_UNLINK(viewlist, view, link); 3309 if (result == ISC_R_SUCCESS && 3310 strcmp(view->name, "_bind") != 0) 3311 (void)dns_zt_apply(view->zonetable, ISC_FALSE, 3312 removed, view); 3313 dns_view_detach(&view); 3314 } 3315 3316 /* 3317 * Adjust the listening interfaces in accordance with the source 3318 * addresses specified in views and zones. 3319 */ 3320 if (isc_net_probeipv6() == ISC_R_SUCCESS) 3321 adjust_interfaces(server, ns_g_mctx); 3322 3323 /* Relinquish exclusive access to configuration data. */ 3324 isc_task_endexclusive(server->task); 3325 3326 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3327 ISC_LOG_DEBUG(1), "load_configuration: %s", 3328 isc_result_totext(result)); 3329 3330 return (result); 3331} 3332 3333static isc_result_t 3334load_zones(ns_server_t *server, isc_boolean_t stop) { 3335 isc_result_t result; 3336 dns_view_t *view; 3337 3338 result = isc_task_beginexclusive(server->task); 3339 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3340 3341 /* 3342 * Load zone data from disk. 3343 */ 3344 for (view = ISC_LIST_HEAD(server->viewlist); 3345 view != NULL; 3346 view = ISC_LIST_NEXT(view, link)) 3347 { 3348 CHECK(dns_view_load(view, stop)); 3349 } 3350 3351 /* 3352 * Force zone maintenance. Do this after loading 3353 * so that we know when we need to force AXFR of 3354 * slave zones whose master files are missing. 3355 */ 3356 CHECK(dns_zonemgr_forcemaint(server->zonemgr)); 3357 cleanup: 3358 isc_task_endexclusive(server->task); 3359 return (result); 3360} 3361 3362static isc_result_t 3363load_new_zones(ns_server_t *server, isc_boolean_t stop) { 3364 isc_result_t result; 3365 dns_view_t *view; 3366 3367 result = isc_task_beginexclusive(server->task); 3368 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3369 3370 /* 3371 * Load zone data from disk. 3372 */ 3373 for (view = ISC_LIST_HEAD(server->viewlist); 3374 view != NULL; 3375 view = ISC_LIST_NEXT(view, link)) 3376 { 3377 CHECK(dns_view_loadnew(view, stop)); 3378 } 3379 /* 3380 * Force zone maintenance. Do this after loading 3381 * so that we know when we need to force AXFR of 3382 * slave zones whose master files are missing. 3383 */ 3384 dns_zonemgr_resumexfrs(server->zonemgr); 3385 cleanup: 3386 isc_task_endexclusive(server->task); 3387 return (result); 3388} 3389 3390static void 3391run_server(isc_task_t *task, isc_event_t *event) { 3392 isc_result_t result; 3393 ns_server_t *server = (ns_server_t *)event->ev_arg; 3394 3395 INSIST(task == server->task); 3396 3397 isc_event_free(&event); 3398 3399 CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 3400 &ns_g_dispatchmgr), 3401 "creating dispatch manager"); 3402 3403 CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 3404 ns_g_socketmgr, ns_g_dispatchmgr, 3405 &server->interfacemgr), 3406 "creating interface manager"); 3407 3408 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3409 NULL, NULL, server->task, 3410 interface_timer_tick, 3411 server, &server->interface_timer), 3412 "creating interface timer"); 3413 3414 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3415 NULL, NULL, server->task, 3416 heartbeat_timer_tick, 3417 server, &server->heartbeat_timer), 3418 "creating heartbeat timer"); 3419 3420 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 3421 NULL, NULL, server->task, pps_timer_tick, 3422 server, &server->pps_timer), 3423 "creating pps timer"); 3424 3425 CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 3426 "creating default configuration parser"); 3427 3428 if (ns_g_lwresdonly) 3429 CHECKFATAL(load_configuration(lwresd_g_conffile, server, 3430 ISC_TRUE), 3431 "loading configuration"); 3432 else 3433 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 3434 "loading configuration"); 3435 3436 isc_hash_init(); 3437 3438 CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); 3439 3440 ns_os_started(); 3441 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3442 ISC_LOG_NOTICE, "running"); 3443} 3444 3445void 3446ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 3447 3448 REQUIRE(NS_SERVER_VALID(server)); 3449 3450 server->flushonshutdown = flush; 3451} 3452 3453static void 3454shutdown_server(isc_task_t *task, isc_event_t *event) { 3455 isc_result_t result; 3456 dns_view_t *view, *view_next; 3457 ns_server_t *server = (ns_server_t *)event->ev_arg; 3458 isc_boolean_t flush = server->flushonshutdown; 3459 3460 UNUSED(task); 3461 INSIST(task == server->task); 3462 3463 result = isc_task_beginexclusive(server->task); 3464 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3465 3466 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3467 ISC_LOG_INFO, "shutting down%s", 3468 flush ? ": flushing changes" : ""); 3469 3470 ns_controls_shutdown(server->controls); 3471 end_reserved_dispatches(server, ISC_TRUE); 3472 3473 cfg_obj_destroy(ns_g_parser, &ns_g_config); 3474 cfg_parser_destroy(&ns_g_parser); 3475 3476 for (view = ISC_LIST_HEAD(server->viewlist); 3477 view != NULL; 3478 view = view_next) { 3479 view_next = ISC_LIST_NEXT(view, link); 3480 ISC_LIST_UNLINK(server->viewlist, view, link); 3481 if (flush) 3482 dns_view_flushanddetach(&view); 3483 else 3484 dns_view_detach(&view); 3485 } 3486 3487 isc_timer_detach(&server->interface_timer); 3488 isc_timer_detach(&server->heartbeat_timer); 3489 isc_timer_detach(&server->pps_timer); 3490 3491 ns_interfacemgr_shutdown(server->interfacemgr); 3492 ns_interfacemgr_detach(&server->interfacemgr); 3493 3494 dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 3495 3496 dns_zonemgr_shutdown(server->zonemgr); 3497 3498 if (server->blackholeacl != NULL) 3499 dns_acl_detach(&server->blackholeacl); 3500 3501 dns_db_detach(&server->in_roothints); 3502 3503 isc_task_endexclusive(server->task); 3504 3505 isc_task_detach(&server->task); 3506 3507 isc_event_free(&event); 3508} 3509 3510void 3511ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 3512 isc_result_t result; 3513 3514 ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 3515 if (server == NULL) 3516 fatal("allocating server object", ISC_R_NOMEMORY); 3517 3518 server->mctx = mctx; 3519 server->task = NULL; 3520 3521 /* Initialize configuration data with default values. */ 3522 3523 result = isc_quota_init(&server->xfroutquota, 10); 3524 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3525 result = isc_quota_init(&server->tcpquota, 10); 3526 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3527 result = isc_quota_init(&server->recursionquota, 100); 3528 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3529 3530 result = dns_aclenv_init(mctx, &server->aclenv); 3531 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3532 3533 /* Initialize server data structures. */ 3534 server->zonemgr = NULL; 3535 server->interfacemgr = NULL; 3536 ISC_LIST_INIT(server->viewlist); 3537 server->in_roothints = NULL; 3538 server->blackholeacl = NULL; 3539 3540 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 3541 &server->in_roothints), 3542 "setting up root hints"); 3543 3544 CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 3545 "initializing reload event lock"); 3546 server->reload_event = 3547 isc_event_allocate(ns_g_mctx, server, 3548 NS_EVENT_RELOAD, 3549 ns_server_reload, 3550 server, 3551 sizeof(isc_event_t)); 3552 CHECKFATAL(server->reload_event == NULL ? 3553 ISC_R_NOMEMORY : ISC_R_SUCCESS, 3554 "allocating reload event"); 3555 3556 CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), 3557 "initializing DST"); 3558 3559 server->tkeyctx = NULL; 3560 CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 3561 &server->tkeyctx), 3562 "creating TKEY context"); 3563 3564 /* 3565 * Setup the server task, which is responsible for coordinating 3566 * startup and shutdown of the server. 3567 */ 3568 CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 3569 "creating server task"); 3570 isc_task_setname(server->task, "server", server); 3571 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 3572 "isc_task_onshutdown"); 3573 CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 3574 "isc_app_onrun"); 3575 3576 server->interface_timer = NULL; 3577 server->heartbeat_timer = NULL; 3578 server->pps_timer = NULL; 3579 3580 server->interface_interval = 0; 3581 server->heartbeat_interval = 0; 3582 3583 CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 3584 ns_g_socketmgr, &server->zonemgr), 3585 "dns_zonemgr_create"); 3586 3587 server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 3588 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3589 "isc_mem_strdup"); 3590 server->querystats = NULL; 3591 3592 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 3593 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3594 "isc_mem_strdup"); 3595 3596 server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 3597 CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3598 "isc_mem_strdup"); 3599 3600 server->hostname_set = ISC_FALSE; 3601 server->hostname = NULL; 3602 server->version_set = ISC_FALSE; 3603 server->version = NULL; 3604 server->server_usehostname = ISC_FALSE; 3605 server->server_id = NULL; 3606 3607 CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats), 3608 "dns_stats_alloccounters"); 3609 3610 server->flushonshutdown = ISC_FALSE; 3611 server->log_queries = ISC_FALSE; 3612 3613 server->controls = NULL; 3614 CHECKFATAL(ns_controls_create(server, &server->controls), 3615 "ns_controls_create"); 3616 server->dispatchgen = 0; 3617 ISC_LIST_INIT(server->dispatches); 3618 3619 server->magic = NS_SERVER_MAGIC; 3620 *serverp = server; 3621} 3622 3623void 3624ns_server_destroy(ns_server_t **serverp) { 3625 ns_server_t *server = *serverp; 3626 REQUIRE(NS_SERVER_VALID(server)); 3627 3628 ns_controls_destroy(&server->controls); 3629 3630 dns_stats_freecounters(server->mctx, &server->querystats); 3631 3632 isc_mem_free(server->mctx, server->statsfile); 3633 isc_mem_free(server->mctx, server->dumpfile); 3634 isc_mem_free(server->mctx, server->recfile); 3635 3636 if (server->version != NULL) 3637 isc_mem_free(server->mctx, server->version); 3638 if (server->hostname != NULL) 3639 isc_mem_free(server->mctx, server->hostname); 3640 if (server->server_id != NULL) 3641 isc_mem_free(server->mctx, server->server_id); 3642 3643 dns_zonemgr_detach(&server->zonemgr); 3644 3645 if (server->tkeyctx != NULL) 3646 dns_tkeyctx_destroy(&server->tkeyctx); 3647 3648 dst_lib_destroy(); 3649 3650 isc_event_free(&server->reload_event); 3651 3652 INSIST(ISC_LIST_EMPTY(server->viewlist)); 3653 3654 dns_aclenv_destroy(&server->aclenv); 3655 3656 isc_quota_destroy(&server->recursionquota); 3657 isc_quota_destroy(&server->tcpquota); 3658 isc_quota_destroy(&server->xfroutquota); 3659 3660 server->magic = 0; 3661 isc_mem_put(server->mctx, server, sizeof(*server)); 3662 *serverp = NULL; 3663} 3664 3665static void 3666fatal(const char *msg, isc_result_t result) { 3667 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3668 ISC_LOG_CRITICAL, "%s: %s", msg, 3669 isc_result_totext(result)); 3670 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3671 ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 3672 exit(1); 3673} 3674 3675static void 3676start_reserved_dispatches(ns_server_t *server) { 3677 3678 REQUIRE(NS_SERVER_VALID(server)); 3679 3680 server->dispatchgen++; 3681} 3682 3683static void 3684end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 3685 ns_dispatch_t *dispatch, *nextdispatch; 3686 3687 REQUIRE(NS_SERVER_VALID(server)); 3688 3689 for (dispatch = ISC_LIST_HEAD(server->dispatches); 3690 dispatch != NULL; 3691 dispatch = nextdispatch) { 3692 nextdispatch = ISC_LIST_NEXT(dispatch, link); 3693 if (!all && server->dispatchgen == dispatch-> dispatchgen) 3694 continue; 3695 ISC_LIST_UNLINK(server->dispatches, dispatch, link); 3696 dns_dispatch_detach(&dispatch->dispatch); 3697 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3698 } 3699} 3700 3701void 3702ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 3703 ns_dispatch_t *dispatch; 3704 in_port_t port; 3705 char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 3706 isc_result_t result; 3707 unsigned int attrs, attrmask; 3708 3709 REQUIRE(NS_SERVER_VALID(server)); 3710 3711 port = isc_sockaddr_getport(addr); 3712 if (port == 0 || port >= 1024) 3713 return; 3714 3715 for (dispatch = ISC_LIST_HEAD(server->dispatches); 3716 dispatch != NULL; 3717 dispatch = ISC_LIST_NEXT(dispatch, link)) { 3718 if (isc_sockaddr_equal(&dispatch->addr, addr)) 3719 break; 3720 } 3721 if (dispatch != NULL) { 3722 dispatch->dispatchgen = server->dispatchgen; 3723 return; 3724 } 3725 3726 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 3727 if (dispatch == NULL) { 3728 result = ISC_R_NOMEMORY; 3729 goto cleanup; 3730 } 3731 3732 dispatch->addr = *addr; 3733 dispatch->dispatchgen = server->dispatchgen; 3734 dispatch->dispatch = NULL; 3735 3736 attrs = 0; 3737 attrs |= DNS_DISPATCHATTR_UDP; 3738 switch (isc_sockaddr_pf(addr)) { 3739 case AF_INET: 3740 attrs |= DNS_DISPATCHATTR_IPV4; 3741 break; 3742 case AF_INET6: 3743 attrs |= DNS_DISPATCHATTR_IPV6; 3744 break; 3745 default: 3746 result = ISC_R_NOTIMPLEMENTED; 3747 goto cleanup; 3748 } 3749 attrmask = 0; 3750 attrmask |= DNS_DISPATCHATTR_UDP; 3751 attrmask |= DNS_DISPATCHATTR_TCP; 3752 attrmask |= DNS_DISPATCHATTR_IPV4; 3753 attrmask |= DNS_DISPATCHATTR_IPV6; 3754 3755 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 3756 ns_g_taskmgr, &dispatch->addr, 4096, 3757 1000, 32768, 16411, 16433, 3758 attrs, attrmask, &dispatch->dispatch); 3759 if (result != ISC_R_SUCCESS) 3760 goto cleanup; 3761 3762 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 3763 3764 return; 3765 3766 cleanup: 3767 if (dispatch != NULL) 3768 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3769 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 3770 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3771 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3772 "unable to create dispatch for reserved port %s: %s", 3773 addrbuf, isc_result_totext(result)); 3774} 3775 3776 3777static isc_result_t 3778loadconfig(ns_server_t *server) { 3779 isc_result_t result; 3780 start_reserved_dispatches(server); 3781 result = load_configuration(ns_g_lwresdonly ? 3782 lwresd_g_conffile : ns_g_conffile, 3783 server, ISC_FALSE); 3784 if (result == ISC_R_SUCCESS) 3785 end_reserved_dispatches(server, ISC_FALSE); 3786 else 3787 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3788 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3789 "reloading configuration failed: %s", 3790 isc_result_totext(result)); 3791 return (result); 3792} 3793 3794static isc_result_t 3795reload(ns_server_t *server) { 3796 isc_result_t result; 3797 CHECK(loadconfig(server)); 3798 3799 result = load_zones(server, ISC_FALSE); 3800 if (result != ISC_R_SUCCESS) { 3801 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3802 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3803 "reloading zones failed: %s", 3804 isc_result_totext(result)); 3805 } 3806 cleanup: 3807 return (result); 3808} 3809 3810static void 3811reconfig(ns_server_t *server) { 3812 isc_result_t result; 3813 CHECK(loadconfig(server)); 3814 3815 result = load_new_zones(server, ISC_FALSE); 3816 if (result != ISC_R_SUCCESS) { 3817 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3818 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3819 "loading new zones failed: %s", 3820 isc_result_totext(result)); 3821 } 3822 cleanup: ; 3823} 3824 3825/* 3826 * Handle a reload event (from SIGHUP). 3827 */ 3828static void 3829ns_server_reload(isc_task_t *task, isc_event_t *event) { 3830 ns_server_t *server = (ns_server_t *)event->ev_arg; 3831 3832 INSIST(task = server->task); 3833 UNUSED(task); 3834 3835 (void)reload(server); 3836 3837 LOCK(&server->reload_event_lock); 3838 INSIST(server->reload_event == NULL); 3839 server->reload_event = event; 3840 UNLOCK(&server->reload_event_lock); 3841} 3842 3843void 3844ns_server_reloadwanted(ns_server_t *server) { 3845 LOCK(&server->reload_event_lock); 3846 if (server->reload_event != NULL) 3847 isc_task_send(server->task, &server->reload_event); 3848 UNLOCK(&server->reload_event_lock); 3849} 3850 3851static char * 3852next_token(char **stringp, const char *delim) { 3853 char *res; 3854 3855 do { 3856 res = strsep(stringp, delim); 3857 if (res == NULL) 3858 break; 3859 } while (*res == '\0'); 3860 return (res); 3861} 3862 3863/* 3864 * Find the zone specified in the control channel command 'args', 3865 * if any. If a zone is specified, point '*zonep' at it, otherwise 3866 * set '*zonep' to NULL. 3867 */ 3868static isc_result_t 3869zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { 3870 char *input, *ptr; 3871 const char *zonetxt; 3872 char *classtxt; 3873 const char *viewtxt = NULL; 3874 dns_fixedname_t name; 3875 isc_result_t result; 3876 isc_buffer_t buf; 3877 dns_view_t *view = NULL; 3878 dns_rdataclass_t rdclass; 3879 3880 REQUIRE(zonep != NULL && *zonep == NULL); 3881 3882 input = args; 3883 3884 /* Skip the command name. */ 3885 ptr = next_token(&input, " \t"); 3886 if (ptr == NULL) 3887 return (ISC_R_UNEXPECTEDEND); 3888 3889 /* Look for the zone name. */ 3890 zonetxt = next_token(&input, " \t"); 3891 if (zonetxt == NULL) 3892 return (ISC_R_SUCCESS); 3893 3894 /* Look for the optional class name. */ 3895 classtxt = next_token(&input, " \t"); 3896 if (classtxt != NULL) { 3897 /* Look for the optional view name. */ 3898 viewtxt = next_token(&input, " \t"); 3899 } 3900 3901 isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); 3902 isc_buffer_add(&buf, strlen(zonetxt)); 3903 dns_fixedname_init(&name); 3904 result = dns_name_fromtext(dns_fixedname_name(&name), 3905 &buf, dns_rootname, ISC_FALSE, NULL); 3906 if (result != ISC_R_SUCCESS) 3907 goto fail1; 3908 3909 if (classtxt != NULL) { 3910 isc_textregion_t r; 3911 r.base = classtxt; 3912 r.length = strlen(classtxt); 3913 result = dns_rdataclass_fromtext(&rdclass, &r); 3914 if (result != ISC_R_SUCCESS) 3915 goto fail1; 3916 } else { 3917 rdclass = dns_rdataclass_in; 3918 } 3919 3920 if (viewtxt == NULL) 3921 viewtxt = "_default"; 3922 result = dns_viewlist_find(&server->viewlist, viewtxt, 3923 rdclass, &view); 3924 if (result != ISC_R_SUCCESS) 3925 goto fail1; 3926 3927 result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), 3928 0, NULL, zonep); 3929 /* Partial match? */ 3930 if (result != ISC_R_SUCCESS && *zonep != NULL) 3931 dns_zone_detach(zonep); 3932 dns_view_detach(&view); 3933 fail1: 3934 return (result); 3935} 3936 3937/* 3938 * Act on a "retransfer" command from the command channel. 3939 */ 3940isc_result_t 3941ns_server_retransfercommand(ns_server_t *server, char *args) { 3942 isc_result_t result; 3943 dns_zone_t *zone = NULL; 3944 dns_zonetype_t type; 3945 3946 result = zone_from_args(server, args, &zone); 3947 if (result != ISC_R_SUCCESS) 3948 return (result); 3949 if (zone == NULL) 3950 return (ISC_R_UNEXPECTEDEND); 3951 type = dns_zone_gettype(zone); 3952 if (type == dns_zone_slave || type == dns_zone_stub) 3953 dns_zone_forcereload(zone); 3954 else 3955 result = ISC_R_NOTFOUND; 3956 dns_zone_detach(&zone); 3957 return (result); 3958} 3959 3960/* 3961 * Act on a "reload" command from the command channel. 3962 */ 3963isc_result_t 3964ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 3965 isc_result_t result; 3966 dns_zone_t *zone = NULL; 3967 dns_zonetype_t type; 3968 const char *msg = NULL; 3969 3970 result = zone_from_args(server, args, &zone); 3971 if (result != ISC_R_SUCCESS) 3972 return (result); 3973 if (zone == NULL) { 3974 result = reload(server); 3975 if (result == ISC_R_SUCCESS) 3976 msg = "server reload successful"; 3977 } else { 3978 type = dns_zone_gettype(zone); 3979 if (type == dns_zone_slave || type == dns_zone_stub) { 3980 dns_zone_refresh(zone); 3981 dns_zone_detach(&zone); 3982 msg = "zone refresh queued"; 3983 } else { 3984 result = dns_zone_load(zone); 3985 dns_zone_detach(&zone); 3986 switch (result) { 3987 case ISC_R_SUCCESS: 3988 msg = "zone reload successful"; 3989 break; 3990 case DNS_R_CONTINUE: 3991 msg = "zone reload queued"; 3992 result = ISC_R_SUCCESS; 3993 break; 3994 case DNS_R_UPTODATE: 3995 msg = "zone reload up-to-date"; 3996 result = ISC_R_SUCCESS; 3997 break; 3998 default: 3999 /* failure message will be generated by rndc */ 4000 break; 4001 } 4002 } 4003 } 4004 if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 4005 isc_buffer_putmem(text, (const unsigned char *)msg, 4006 strlen(msg) + 1); 4007 return (result); 4008} 4009 4010/* 4011 * Act on a "reconfig" command from the command channel. 4012 */ 4013isc_result_t 4014ns_server_reconfigcommand(ns_server_t *server, char *args) { 4015 UNUSED(args); 4016 4017 reconfig(server); 4018 return (ISC_R_SUCCESS); 4019} 4020 4021/* 4022 * Act on a "notify" command from the command channel. 4023 */ 4024isc_result_t 4025ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { 4026 isc_result_t result; 4027 dns_zone_t *zone = NULL; 4028 const unsigned char msg[] = "zone notify queued"; 4029 4030 result = zone_from_args(server, args, &zone); 4031 if (result != ISC_R_SUCCESS) 4032 return (result); 4033 if (zone == NULL) 4034 return (ISC_R_UNEXPECTEDEND); 4035 4036 dns_zone_notify(zone); 4037 dns_zone_detach(&zone); 4038 if (sizeof(msg) <= isc_buffer_availablelength(text)) 4039 isc_buffer_putmem(text, msg, sizeof(msg)); 4040 4041 return (ISC_R_SUCCESS); 4042} 4043 4044/* 4045 * Act on a "refresh" command from the command channel. 4046 */ 4047isc_result_t 4048ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 4049 isc_result_t result; 4050 dns_zone_t *zone = NULL; 4051 const unsigned char msg1[] = "zone refresh queued"; 4052 const unsigned char msg2[] = "not a slave or stub zone"; 4053 dns_zonetype_t type; 4054 4055 result = zone_from_args(server, args, &zone); 4056 if (result != ISC_R_SUCCESS) 4057 return (result); 4058 if (zone == NULL) 4059 return (ISC_R_UNEXPECTEDEND); 4060 4061 type = dns_zone_gettype(zone); 4062 if (type == dns_zone_slave || type == dns_zone_stub) { 4063 dns_zone_refresh(zone); 4064 dns_zone_detach(&zone); 4065 if (sizeof(msg1) <= isc_buffer_availablelength(text)) 4066 isc_buffer_putmem(text, msg1, sizeof(msg1)); 4067 return (ISC_R_SUCCESS); 4068 } 4069 4070 dns_zone_detach(&zone); 4071 if (sizeof(msg2) <= isc_buffer_availablelength(text)) 4072 isc_buffer_putmem(text, msg2, sizeof(msg2)); 4073 return (ISC_R_FAILURE); 4074} 4075 4076isc_result_t 4077ns_server_togglequerylog(ns_server_t *server) { 4078 server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; 4079 4080 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4081 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4082 "query logging is now %s", 4083 server->log_queries ? "on" : "off"); 4084 return (ISC_R_SUCCESS); 4085} 4086 4087static isc_result_t 4088ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 4089 cfg_aclconfctx_t *actx, 4090 isc_mem_t *mctx, ns_listenlist_t **target) 4091{ 4092 isc_result_t result; 4093 const cfg_listelt_t *element; 4094 ns_listenlist_t *dlist = NULL; 4095 4096 REQUIRE(target != NULL && *target == NULL); 4097 4098 result = ns_listenlist_create(mctx, &dlist); 4099 if (result != ISC_R_SUCCESS) 4100 return (result); 4101 4102 for (element = cfg_list_first(listenlist); 4103 element != NULL; 4104 element = cfg_list_next(element)) 4105 { 4106 ns_listenelt_t *delt = NULL; 4107 const cfg_obj_t *listener = cfg_listelt_value(element); 4108 result = ns_listenelt_fromconfig(listener, config, actx, 4109 mctx, &delt); 4110 if (result != ISC_R_SUCCESS) 4111 goto cleanup; 4112 ISC_LIST_APPEND(dlist->elts, delt, link); 4113 } 4114 *target = dlist; 4115 return (ISC_R_SUCCESS); 4116 4117 cleanup: 4118 ns_listenlist_detach(&dlist); 4119 return (result); 4120} 4121 4122/* 4123 * Create a listen list from the corresponding configuration 4124 * data structure. 4125 */ 4126static isc_result_t 4127ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 4128 cfg_aclconfctx_t *actx, 4129 isc_mem_t *mctx, ns_listenelt_t **target) 4130{ 4131 isc_result_t result; 4132 const cfg_obj_t *portobj; 4133 in_port_t port; 4134 ns_listenelt_t *delt = NULL; 4135 REQUIRE(target != NULL && *target == NULL); 4136 4137 portobj = cfg_tuple_get(listener, "port"); 4138 if (!cfg_obj_isuint32(portobj)) { 4139 if (ns_g_port != 0) { 4140 port = ns_g_port; 4141 } else { 4142 result = ns_config_getport(config, &port); 4143 if (result != ISC_R_SUCCESS) 4144 return (result); 4145 } 4146 } else { 4147 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 4148 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 4149 "port value '%u' is out of range", 4150 cfg_obj_asuint32(portobj)); 4151 return (ISC_R_RANGE); 4152 } 4153 port = (in_port_t)cfg_obj_asuint32(portobj); 4154 } 4155 4156 result = ns_listenelt_create(mctx, port, NULL, &delt); 4157 if (result != ISC_R_SUCCESS) 4158 return (result); 4159 4160 result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), 4161 config, ns_g_lctx, actx, mctx, &delt->acl); 4162 if (result != ISC_R_SUCCESS) { 4163 ns_listenelt_destroy(delt); 4164 return (result); 4165 } 4166 *target = delt; 4167 return (ISC_R_SUCCESS); 4168} 4169 4170isc_result_t 4171ns_server_dumpstats(ns_server_t *server) { 4172 isc_result_t result; 4173 dns_zone_t *zone, *next; 4174 isc_stdtime_t now; 4175 FILE *fp = NULL; 4176 int i; 4177 int ncounters; 4178 4179 isc_stdtime_get(&now); 4180 4181 CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 4182 "could not open statistics dump file", server->statsfile); 4183 4184 ncounters = DNS_STATS_NCOUNTERS; 4185 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); 4186 4187 for (i = 0; i < ncounters; i++) 4188 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", 4189 dns_statscounter_names[i], 4190 server->querystats[i]); 4191 4192 zone = NULL; 4193 for (result = dns_zone_first(server->zonemgr, &zone); 4194 result == ISC_R_SUCCESS; 4195 next = NULL, result = dns_zone_next(zone, &next), zone = next) 4196 { 4197 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); 4198 if (zonestats != NULL) { 4199 char zonename[DNS_NAME_FORMATSIZE]; 4200 dns_view_t *view; 4201 char *viewname; 4202 4203 dns_name_format(dns_zone_getorigin(zone), 4204 zonename, sizeof(zonename)); 4205 view = dns_zone_getview(zone); 4206 viewname = view->name; 4207 for (i = 0; i < ncounters; i++) { 4208 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT 4209 "u %s", 4210 dns_statscounter_names[i], 4211 zonestats[i], 4212 zonename); 4213 if (strcmp(viewname, "_default") != 0) 4214 fprintf(fp, " %s", viewname); 4215 fprintf(fp, "\n"); 4216 } 4217 } 4218 } 4219 if (result == ISC_R_NOMORE) 4220 result = ISC_R_SUCCESS; 4221 CHECK(result); 4222 4223 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); 4224 4225 cleanup: 4226 if (fp != NULL) 4227 (void)isc_stdio_close(fp); 4228 return (result); 4229} 4230 4231static isc_result_t 4232add_zone_tolist(dns_zone_t *zone, void *uap) { 4233 struct dumpcontext *dctx = uap; 4234 struct zonelistentry *zle; 4235 4236 zle = isc_mem_get(dctx->mctx, sizeof *zle); 4237 if (zle == NULL) 4238 return (ISC_R_NOMEMORY); 4239 zle->zone = NULL; 4240 dns_zone_attach(zone, &zle->zone); 4241 ISC_LINK_INIT(zle, link); 4242 ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 4243 return (ISC_R_SUCCESS); 4244} 4245 4246static isc_result_t 4247add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 4248 struct viewlistentry *vle; 4249 isc_result_t result = ISC_R_SUCCESS; 4250 4251 /* 4252 * Prevent duplicate views. 4253 */ 4254 for (vle = ISC_LIST_HEAD(dctx->viewlist); 4255 vle != NULL; 4256 vle = ISC_LIST_NEXT(vle, link)) 4257 if (vle->view == view) 4258 return (ISC_R_SUCCESS); 4259 4260 vle = isc_mem_get(dctx->mctx, sizeof *vle); 4261 if (vle == NULL) 4262 return (ISC_R_NOMEMORY); 4263 vle->view = NULL; 4264 dns_view_attach(view, &vle->view); 4265 ISC_LINK_INIT(vle, link); 4266 ISC_LIST_INIT(vle->zonelist); 4267 ISC_LIST_APPEND(dctx->viewlist, vle, link); 4268 if (dctx->dumpzones) 4269 result = dns_zt_apply(view->zonetable, ISC_TRUE, 4270 add_zone_tolist, dctx); 4271 return (result); 4272} 4273 4274static void 4275dumpcontext_destroy(struct dumpcontext *dctx) { 4276 struct viewlistentry *vle; 4277 struct zonelistentry *zle; 4278 4279 vle = ISC_LIST_HEAD(dctx->viewlist); 4280 while (vle != NULL) { 4281 ISC_LIST_UNLINK(dctx->viewlist, vle, link); 4282 zle = ISC_LIST_HEAD(vle->zonelist); 4283 while (zle != NULL) { 4284 ISC_LIST_UNLINK(vle->zonelist, zle, link); 4285 dns_zone_detach(&zle->zone); 4286 isc_mem_put(dctx->mctx, zle, sizeof *zle); 4287 zle = ISC_LIST_HEAD(vle->zonelist); 4288 } 4289 dns_view_detach(&vle->view); 4290 isc_mem_put(dctx->mctx, vle, sizeof *vle); 4291 vle = ISC_LIST_HEAD(dctx->viewlist); 4292 } 4293 if (dctx->version != NULL) 4294 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 4295 if (dctx->db != NULL) 4296 dns_db_detach(&dctx->db); 4297 if (dctx->cache != NULL) 4298 dns_db_detach(&dctx->cache); 4299 if (dctx->task != NULL) 4300 isc_task_detach(&dctx->task); 4301 if (dctx->fp != NULL) 4302 (void)isc_stdio_close(dctx->fp); 4303 if (dctx->mdctx != NULL) 4304 dns_dumpctx_detach(&dctx->mdctx); 4305 isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 4306} 4307 4308static void 4309dumpdone(void *arg, isc_result_t result) { 4310 struct dumpcontext *dctx = arg; 4311 char buf[1024+32]; 4312 const dns_master_style_t *style; 4313 4314 if (result != ISC_R_SUCCESS) 4315 goto cleanup; 4316 if (dctx->mdctx != NULL) 4317 dns_dumpctx_detach(&dctx->mdctx); 4318 if (dctx->view == NULL) { 4319 dctx->view = ISC_LIST_HEAD(dctx->viewlist); 4320 if (dctx->view == NULL) 4321 goto done; 4322 INSIST(dctx->zone == NULL); 4323 } else 4324 goto resume; 4325 nextview: 4326 fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 4327 resume: 4328 if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) { 4329 style = &dns_master_style_cache; 4330 /* start cache dump */ 4331 if (dctx->view->view->cachedb != NULL) 4332 dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 4333 if (dctx->cache != NULL) { 4334 4335 fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n", 4336 dctx->view->view->name); 4337 result = dns_master_dumptostreaminc(dctx->mctx, 4338 dctx->cache, NULL, 4339 style, dctx->fp, 4340 dctx->task, 4341 dumpdone, dctx, 4342 &dctx->mdctx); 4343 if (result == DNS_R_CONTINUE) 4344 return; 4345 if (result == ISC_R_NOTIMPLEMENTED) 4346 fprintf(dctx->fp, "; %s\n", 4347 dns_result_totext(result)); 4348 else if (result != ISC_R_SUCCESS) 4349 goto cleanup; 4350 } 4351 } 4352 if (dctx->cache != NULL) { 4353 dns_adb_dump(dctx->view->view->adb, dctx->fp); 4354 dns_db_detach(&dctx->cache); 4355 } 4356 if (dctx->dumpzones) { 4357 style = &dns_master_style_full; 4358 nextzone: 4359 if (dctx->version != NULL) 4360 dns_db_closeversion(dctx->db, &dctx->version, 4361 ISC_FALSE); 4362 if (dctx->db != NULL) 4363 dns_db_detach(&dctx->db); 4364 if (dctx->zone == NULL) 4365 dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 4366 else 4367 dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 4368 if (dctx->zone != NULL) { 4369 /* start zone dump */ 4370 dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 4371 fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 4372 result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 4373 if (result != ISC_R_SUCCESS) { 4374 fprintf(dctx->fp, "; %s\n", 4375 dns_result_totext(result)); 4376 goto nextzone; 4377 } 4378 dns_db_currentversion(dctx->db, &dctx->version); 4379 result = dns_master_dumptostreaminc(dctx->mctx, 4380 dctx->db, 4381 dctx->version, 4382 style, dctx->fp, 4383 dctx->task, 4384 dumpdone, dctx, 4385 &dctx->mdctx); 4386 if (result == DNS_R_CONTINUE) 4387 return; 4388 if (result == ISC_R_NOTIMPLEMENTED) { 4389 fprintf(dctx->fp, "; %s\n", 4390 dns_result_totext(result)); 4391 result = ISC_R_SUCCESS; 4392 goto nextzone; 4393 } 4394 if (result != ISC_R_SUCCESS) 4395 goto cleanup; 4396 } 4397 } 4398 if (dctx->view != NULL) 4399 dctx->view = ISC_LIST_NEXT(dctx->view, link); 4400 if (dctx->view != NULL) 4401 goto nextview; 4402 done: 4403 fprintf(dctx->fp, "; Dump complete\n"); 4404 result = isc_stdio_flush(dctx->fp); 4405 if (result == ISC_R_SUCCESS) 4406 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4407 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4408 "dumpdb complete"); 4409 cleanup: 4410 if (result != ISC_R_SUCCESS) 4411 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4412 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4413 "dumpdb failed: %s", dns_result_totext(result)); 4414 dumpcontext_destroy(dctx); 4415} 4416 4417isc_result_t 4418ns_server_dumpdb(ns_server_t *server, char *args) { 4419 struct dumpcontext *dctx = NULL; 4420 dns_view_t *view; 4421 isc_result_t result; 4422 char *ptr; 4423 const char *sep; 4424 4425 /* Skip the command name. */ 4426 ptr = next_token(&args, " \t"); 4427 if (ptr == NULL) 4428 return (ISC_R_UNEXPECTEDEND); 4429 4430 dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 4431 if (dctx == NULL) 4432 return (ISC_R_NOMEMORY); 4433 4434 dctx->mctx = server->mctx; 4435 dctx->dumpcache = ISC_TRUE; 4436 dctx->dumpzones = ISC_FALSE; 4437 dctx->fp = NULL; 4438 ISC_LIST_INIT(dctx->viewlist); 4439 dctx->view = NULL; 4440 dctx->zone = NULL; 4441 dctx->cache = NULL; 4442 dctx->mdctx = NULL; 4443 dctx->db = NULL; 4444 dctx->cache = NULL; 4445 dctx->task = NULL; 4446 dctx->version = NULL; 4447 isc_task_attach(server->task, &dctx->task); 4448 4449 CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 4450 "could not open dump file", server->dumpfile); 4451 4452 sep = (args == NULL) ? "" : ": "; 4453 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4454 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4455 "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 4456 4457 ptr = next_token(&args, " \t"); 4458 if (ptr != NULL && strcmp(ptr, "-all") == 0) { 4459 dctx->dumpzones = ISC_TRUE; 4460 dctx->dumpcache = ISC_TRUE; 4461 ptr = next_token(&args, " \t"); 4462 } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 4463 dctx->dumpzones = ISC_FALSE; 4464 dctx->dumpcache = ISC_TRUE; 4465 ptr = next_token(&args, " \t"); 4466 } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 4467 dctx->dumpzones = ISC_TRUE; 4468 dctx->dumpcache = ISC_FALSE; 4469 ptr = next_token(&args, " \t"); 4470 } 4471 4472 nextview: 4473 for (view = ISC_LIST_HEAD(server->viewlist); 4474 view != NULL; 4475 view = ISC_LIST_NEXT(view, link)) 4476 { 4477 if (ptr != NULL && strcmp(view->name, ptr) != 0) 4478 continue; 4479 CHECK(add_view_tolist(dctx, view)); 4480 } 4481 if (ptr != NULL) { 4482 ptr = next_token(&args, " \t"); 4483 if (ptr != NULL) 4484 goto nextview; 4485 } 4486 dumpdone(dctx, ISC_R_SUCCESS); 4487 return (ISC_R_SUCCESS); 4488 4489 cleanup: 4490 if (dctx != NULL) 4491 dumpcontext_destroy(dctx); 4492 return (result); 4493} 4494 4495isc_result_t 4496ns_server_dumprecursing(ns_server_t *server) { 4497 FILE *fp = NULL; 4498 isc_result_t result; 4499 4500 CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 4501 "could not open dump file", server->recfile); 4502 fprintf(fp,";\n; Recursing Queries\n;\n"); 4503 ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 4504 fprintf(fp, "; Dump complete\n"); 4505 4506 cleanup: 4507 if (fp != NULL) 4508 result = isc_stdio_close(fp); 4509 return (result); 4510} 4511 4512isc_result_t 4513ns_server_setdebuglevel(ns_server_t *server, char *args) { 4514 char *ptr; 4515 char *levelstr; 4516 char *endp; 4517 long newlevel; 4518 4519 UNUSED(server); 4520 4521 /* Skip the command name. */ 4522 ptr = next_token(&args, " \t"); 4523 if (ptr == NULL) 4524 return (ISC_R_UNEXPECTEDEND); 4525 4526 /* Look for the new level name. */ 4527 levelstr = next_token(&args, " \t"); 4528 if (levelstr == NULL) { 4529 if (ns_g_debuglevel < 99) 4530 ns_g_debuglevel++; 4531 } else { 4532 newlevel = strtol(levelstr, &endp, 10); 4533 if (*endp != '\0' || newlevel < 0 || newlevel > 99) 4534 return (ISC_R_RANGE); 4535 ns_g_debuglevel = (unsigned int)newlevel; 4536 } 4537 isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 4538 return (ISC_R_SUCCESS); 4539} 4540 4541isc_result_t 4542ns_server_validation(ns_server_t *server, char *args) { 4543 char *ptr, *viewname; 4544 dns_view_t *view; 4545 isc_boolean_t changed = ISC_FALSE; 4546 isc_result_t result; 4547 isc_boolean_t enable; 4548 4549 /* Skip the command name. */ 4550 ptr = next_token(&args, " \t"); 4551 if (ptr == NULL) 4552 return (ISC_R_UNEXPECTEDEND); 4553 4554 /* Find out what we are to do. */ 4555 ptr = next_token(&args, " \t"); 4556 if (ptr == NULL) 4557 return (ISC_R_UNEXPECTEDEND); 4558 4559 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || 4560 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) 4561 enable = ISC_TRUE; 4562 else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || 4563 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) 4564 enable = ISC_FALSE; 4565 else 4566 return (DNS_R_SYNTAX); 4567 4568 /* Look for the view name. */ 4569 viewname = next_token(&args, " \t"); 4570 4571 result = isc_task_beginexclusive(server->task); 4572 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4573 for (view = ISC_LIST_HEAD(server->viewlist); 4574 view != NULL; 4575 view = ISC_LIST_NEXT(view, link)) 4576 { 4577 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4578 continue; 4579 result = dns_view_flushcache(view); 4580 if (result != ISC_R_SUCCESS) 4581 goto out; 4582 view->enablevalidation = enable; 4583 changed = ISC_TRUE; 4584 } 4585 if (changed) 4586 result = ISC_R_SUCCESS; 4587 else 4588 result = ISC_R_FAILURE; 4589 out: 4590 isc_task_endexclusive(server->task); 4591 return (result); 4592} 4593 4594isc_result_t 4595ns_server_flushcache(ns_server_t *server, char *args) { 4596 char *ptr, *viewname; 4597 dns_view_t *view; 4598 isc_boolean_t flushed; 4599 isc_boolean_t found; 4600 isc_result_t result; 4601 4602 /* Skip the command name. */ 4603 ptr = next_token(&args, " \t"); 4604 if (ptr == NULL) 4605 return (ISC_R_UNEXPECTEDEND); 4606 4607 /* Look for the view name. */ 4608 viewname = next_token(&args, " \t"); 4609 4610 result = isc_task_beginexclusive(server->task); 4611 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4612 flushed = ISC_TRUE; 4613 found = ISC_FALSE; 4614 for (view = ISC_LIST_HEAD(server->viewlist); 4615 view != NULL; 4616 view = ISC_LIST_NEXT(view, link)) 4617 { 4618 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4619 continue; 4620 found = ISC_TRUE; 4621 result = dns_view_flushcache(view); 4622 if (result != ISC_R_SUCCESS) 4623 flushed = ISC_FALSE; 4624 } 4625 if (flushed && found) { 4626 result = ISC_R_SUCCESS; 4627 } else { 4628 if (!found) 4629 result = ISC_R_NOTFOUND; 4630 else 4631 result = ISC_R_FAILURE; 4632 } 4633 isc_task_endexclusive(server->task); 4634 return (result); 4635} 4636 4637isc_result_t 4638ns_server_flushname(ns_server_t *server, char *args) { 4639 char *ptr, *target, *viewname; 4640 dns_view_t *view; 4641 isc_boolean_t flushed; 4642 isc_boolean_t found; 4643 isc_result_t result; 4644 isc_buffer_t b; 4645 dns_fixedname_t fixed; 4646 dns_name_t *name; 4647 4648 /* Skip the command name. */ 4649 ptr = next_token(&args, " \t"); 4650 if (ptr == NULL) 4651 return (ISC_R_UNEXPECTEDEND); 4652 4653 /* Find the domain name to flush. */ 4654 target = next_token(&args, " \t"); 4655 if (target == NULL) 4656 return (ISC_R_UNEXPECTEDEND); 4657 4658 isc_buffer_init(&b, target, strlen(target)); 4659 isc_buffer_add(&b, strlen(target)); 4660 dns_fixedname_init(&fixed); 4661 name = dns_fixedname_name(&fixed); 4662 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); 4663 if (result != ISC_R_SUCCESS) 4664 return (result); 4665 4666 /* Look for the view name. */ 4667 viewname = next_token(&args, " \t"); 4668 4669 result = isc_task_beginexclusive(server->task); 4670 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4671 flushed = ISC_TRUE; 4672 found = ISC_FALSE; 4673 for (view = ISC_LIST_HEAD(server->viewlist); 4674 view != NULL; 4675 view = ISC_LIST_NEXT(view, link)) 4676 { 4677 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4678 continue; 4679 found = ISC_TRUE; 4680 result = dns_view_flushname(view, name); 4681 if (result != ISC_R_SUCCESS) 4682 flushed = ISC_FALSE; 4683 } 4684 if (flushed && found) 4685 result = ISC_R_SUCCESS; 4686 else if (!found) 4687 result = ISC_R_NOTFOUND; 4688 else 4689 result = ISC_R_FAILURE; 4690 isc_task_endexclusive(server->task); 4691 return (result); 4692} 4693 4694isc_result_t 4695ns_server_status(ns_server_t *server, isc_buffer_t *text) { 4696 int zonecount, xferrunning, xferdeferred, soaqueries; 4697 unsigned int n; 4698 4699 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 4700 xferrunning = dns_zonemgr_getcount(server->zonemgr, 4701 DNS_ZONESTATE_XFERRUNNING); 4702 xferdeferred = dns_zonemgr_getcount(server->zonemgr, 4703 DNS_ZONESTATE_XFERDEFERRED); 4704 soaqueries = dns_zonemgr_getcount(server->zonemgr, 4705 DNS_ZONESTATE_SOAQUERY); 4706 n = snprintf((char *)isc_buffer_used(text), 4707 isc_buffer_availablelength(text), 4708 "number of zones: %u\n" 4709 "debug level: %d\n" 4710 "xfers running: %u\n" 4711 "xfers deferred: %u\n" 4712 "soa queries in progress: %u\n" 4713 "query logging is %s\n" 4714 "recursive clients: %d/%d/%d\n" 4715 "tcp clients: %d/%d\n" 4716 "server is up and running", 4717 zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 4718 soaqueries, server->log_queries ? "ON" : "OFF", 4719 server->recursionquota.used, server->recursionquota.soft, 4720 server->recursionquota.max, 4721 server->tcpquota.used, server->tcpquota.max); 4722 if (n >= isc_buffer_availablelength(text)) 4723 return (ISC_R_NOSPACE); 4724 isc_buffer_add(text, n); 4725 return (ISC_R_SUCCESS); 4726} 4727 4728/* 4729 * Act on a "freeze" or "thaw" command from the command channel. 4730 */ 4731isc_result_t 4732ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { 4733 isc_result_t result, tresult; 4734 dns_zone_t *zone = NULL; 4735 dns_zonetype_t type; 4736 char classstr[DNS_RDATACLASS_FORMATSIZE]; 4737 char zonename[DNS_NAME_FORMATSIZE]; 4738 dns_view_t *view; 4739 char *journal; 4740 const char *vname, *sep; 4741 isc_boolean_t frozen; 4742 4743 result = zone_from_args(server, args, &zone); 4744 if (result != ISC_R_SUCCESS) 4745 return (result); 4746 if (zone == NULL) { 4747 result = isc_task_beginexclusive(server->task); 4748 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4749 tresult = ISC_R_SUCCESS; 4750 for (view = ISC_LIST_HEAD(server->viewlist); 4751 view != NULL; 4752 view = ISC_LIST_NEXT(view, link)) { 4753 result = dns_view_freezezones(view, freeze); 4754 if (result != ISC_R_SUCCESS && 4755 tresult == ISC_R_SUCCESS) 4756 tresult = result; 4757 } 4758 isc_task_endexclusive(server->task); 4759 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4760 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4761 "%s all zones: %s", 4762 freeze ? "freezing" : "thawing", 4763 isc_result_totext(tresult)); 4764 return (tresult); 4765 } 4766 type = dns_zone_gettype(zone); 4767 if (type != dns_zone_master) { 4768 dns_zone_detach(&zone); 4769 return (ISC_R_NOTFOUND); 4770 } 4771 4772 frozen = dns_zone_getupdatedisabled(zone); 4773 if (freeze) { 4774 if (frozen) 4775 result = DNS_R_FROZEN; 4776 if (result == ISC_R_SUCCESS) 4777 result = dns_zone_flush(zone); 4778 if (result == ISC_R_SUCCESS) { 4779 journal = dns_zone_getjournal(zone); 4780 if (journal != NULL) 4781 (void)isc_file_remove(journal); 4782 } 4783 } else { 4784 if (frozen) { 4785 result = dns_zone_load(zone); 4786 if (result == DNS_R_CONTINUE || 4787 result == DNS_R_UPTODATE) 4788 result = ISC_R_SUCCESS; 4789 } 4790 } 4791 if (result == ISC_R_SUCCESS) 4792 dns_zone_setupdatedisabled(zone, freeze); 4793 4794 view = dns_zone_getview(zone); 4795 if (strcmp(view->name, "_bind") == 0 || 4796 strcmp(view->name, "_default") == 0) 4797 { 4798 vname = ""; 4799 sep = ""; 4800 } else { 4801 vname = view->name; 4802 sep = " "; 4803 } 4804 dns_rdataclass_format(dns_zone_getclass(zone), classstr, 4805 sizeof(classstr)); 4806 dns_name_format(dns_zone_getorigin(zone), 4807 zonename, sizeof(zonename)); 4808 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4809 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4810 "%s zone '%s/%s'%s%s: %s", 4811 freeze ? "freezing" : "thawing", 4812 zonename, classstr, sep, vname, 4813 isc_result_totext(result)); 4814 dns_zone_detach(&zone); 4815 return (result); 4816} 4817 4818#ifdef HAVE_LIBSCF 4819/* 4820 * This function adds a message for rndc to echo if named 4821 * is managed by smf and is also running chroot. 4822 */ 4823isc_result_t 4824ns_smf_add_message(isc_buffer_t *text) { 4825 unsigned int n; 4826 4827 n = snprintf((char *)isc_buffer_used(text), 4828 isc_buffer_availablelength(text), 4829 "use svcadm(1M) to manage named"); 4830 if (n >= isc_buffer_availablelength(text)) 4831 return (ISC_R_NOSPACE); 4832 isc_buffer_add(text, n); 4833 return (ISC_R_SUCCESS); 4834} 4835#endif /* HAVE_LIBSCF */ 4836