1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25186462Sdougb#include <unistd.h> 26224092Sdougb#include <limits.h> 27224092Sdougb#include <ctype.h> 28224092Sdougb#include <sys/types.h> 29224092Sdougb#include <sys/stat.h> 30135446Strhodes 31135446Strhodes#include <isc/app.h> 32135446Strhodes#include <isc/base64.h> 33135446Strhodes#include <isc/dir.h> 34135446Strhodes#include <isc/entropy.h> 35135446Strhodes#include <isc/file.h> 36135446Strhodes#include <isc/hash.h> 37254897Serwin#include <isc/hex.h> 38193149Sdougb#include <isc/httpd.h> 39135446Strhodes#include <isc/lex.h> 40135446Strhodes#include <isc/parseint.h> 41186462Sdougb#include <isc/portset.h> 42135446Strhodes#include <isc/print.h> 43254897Serwin#include <isc/refcount.h> 44135446Strhodes#include <isc/resource.h> 45224092Sdougb#include <isc/sha2.h> 46186462Sdougb#include <isc/socket.h> 47224092Sdougb#include <isc/stat.h> 48193149Sdougb#include <isc/stats.h> 49135446Strhodes#include <isc/stdio.h> 50135446Strhodes#include <isc/string.h> 51135446Strhodes#include <isc/task.h> 52135446Strhodes#include <isc/timer.h> 53135446Strhodes#include <isc/util.h> 54193149Sdougb#include <isc/xml.h> 55135446Strhodes 56135446Strhodes#include <isccfg/namedconf.h> 57135446Strhodes 58135446Strhodes#include <bind9/check.h> 59135446Strhodes 60170222Sdougb#include <dns/acache.h> 61135446Strhodes#include <dns/adb.h> 62135446Strhodes#include <dns/cache.h> 63135446Strhodes#include <dns/db.h> 64135446Strhodes#include <dns/dispatch.h> 65170222Sdougb#include <dns/dlz.h> 66224092Sdougb#include <dns/dns64.h> 67135446Strhodes#include <dns/forward.h> 68135446Strhodes#include <dns/journal.h> 69135446Strhodes#include <dns/keytable.h> 70224092Sdougb#include <dns/keyvalues.h> 71170222Sdougb#include <dns/lib.h> 72135446Strhodes#include <dns/master.h> 73135446Strhodes#include <dns/masterdump.h> 74135446Strhodes#include <dns/order.h> 75135446Strhodes#include <dns/peer.h> 76135446Strhodes#include <dns/portlist.h> 77254897Serwin#include <dns/private.h> 78193149Sdougb#include <dns/rbt.h> 79135446Strhodes#include <dns/rdataclass.h> 80262706Serwin#include <dns/rdatalist.h> 81135446Strhodes#include <dns/rdataset.h> 82135446Strhodes#include <dns/rdatastruct.h> 83135446Strhodes#include <dns/resolver.h> 84135446Strhodes#include <dns/rootns.h> 85135446Strhodes#include <dns/secalg.h> 86262706Serwin#include <dns/soa.h> 87135446Strhodes#include <dns/stats.h> 88135446Strhodes#include <dns/tkey.h> 89193149Sdougb#include <dns/tsig.h> 90135446Strhodes#include <dns/view.h> 91135446Strhodes#include <dns/zone.h> 92135446Strhodes#include <dns/zt.h> 93135446Strhodes 94135446Strhodes#include <dst/dst.h> 95135446Strhodes#include <dst/result.h> 96135446Strhodes 97135446Strhodes#include <named/client.h> 98135446Strhodes#include <named/config.h> 99135446Strhodes#include <named/control.h> 100135446Strhodes#include <named/interfacemgr.h> 101135446Strhodes#include <named/log.h> 102135446Strhodes#include <named/logconf.h> 103135446Strhodes#include <named/lwresd.h> 104135446Strhodes#include <named/main.h> 105135446Strhodes#include <named/os.h> 106135446Strhodes#include <named/server.h> 107193149Sdougb#include <named/statschannel.h> 108135446Strhodes#include <named/tkeyconf.h> 109135446Strhodes#include <named/tsigconf.h> 110135446Strhodes#include <named/zoneconf.h> 111153816Sdougb#ifdef HAVE_LIBSCF 112153816Sdougb#include <named/ns_smf_globals.h> 113153816Sdougb#include <stdlib.h> 114153816Sdougb#endif 115135446Strhodes 116224092Sdougb#ifndef PATH_MAX 117224092Sdougb#define PATH_MAX 1024 118224092Sdougb#endif 119224092Sdougb 120254897Serwin#ifndef SIZE_MAX 121254897Serwin#define SIZE_MAX ((size_t)-1) 122254897Serwin#endif 123254897Serwin 124170222Sdougb/*% 125135446Strhodes * Check an operation for failure. Assumes that the function 126135446Strhodes * using it has a 'result' variable and a 'cleanup' label. 127135446Strhodes */ 128135446Strhodes#define CHECK(op) \ 129193149Sdougb do { result = (op); \ 130193149Sdougb if (result != ISC_R_SUCCESS) goto cleanup; \ 131135446Strhodes } while (0) 132135446Strhodes 133135446Strhodes#define CHECKM(op, msg) \ 134193149Sdougb do { result = (op); \ 135135446Strhodes if (result != ISC_R_SUCCESS) { \ 136135446Strhodes isc_log_write(ns_g_lctx, \ 137135446Strhodes NS_LOGCATEGORY_GENERAL, \ 138135446Strhodes NS_LOGMODULE_SERVER, \ 139135446Strhodes ISC_LOG_ERROR, \ 140135446Strhodes "%s: %s", msg, \ 141135446Strhodes isc_result_totext(result)); \ 142135446Strhodes goto cleanup; \ 143135446Strhodes } \ 144135446Strhodes } while (0) \ 145135446Strhodes 146135446Strhodes#define CHECKMF(op, msg, file) \ 147193149Sdougb do { result = (op); \ 148135446Strhodes if (result != ISC_R_SUCCESS) { \ 149135446Strhodes isc_log_write(ns_g_lctx, \ 150135446Strhodes NS_LOGCATEGORY_GENERAL, \ 151135446Strhodes NS_LOGMODULE_SERVER, \ 152135446Strhodes ISC_LOG_ERROR, \ 153135446Strhodes "%s '%s': %s", msg, file, \ 154135446Strhodes isc_result_totext(result)); \ 155135446Strhodes goto cleanup; \ 156135446Strhodes } \ 157135446Strhodes } while (0) \ 158135446Strhodes 159135446Strhodes#define CHECKFATAL(op, msg) \ 160193149Sdougb do { result = (op); \ 161135446Strhodes if (result != ISC_R_SUCCESS) \ 162135446Strhodes fatal(msg, result); \ 163135446Strhodes } while (0) \ 164135446Strhodes 165224092Sdougb/*% 166224092Sdougb * Maximum ADB size for views that share a cache. Use this limit to suppress 167224092Sdougb * the total of memory footprint, which should be the main reason for sharing 168224092Sdougb * a cache. Only effective when a finite max-cache-size is specified. 169224092Sdougb * This is currently defined to be 8MB. 170224092Sdougb */ 171254402Serwin#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U 172224092Sdougb 173135446Strhodesstruct ns_dispatch { 174135446Strhodes isc_sockaddr_t addr; 175135446Strhodes unsigned int dispatchgen; 176135446Strhodes dns_dispatch_t *dispatch; 177135446Strhodes ISC_LINK(struct ns_dispatch) link; 178135446Strhodes}; 179135446Strhodes 180224092Sdougbstruct ns_cache { 181224092Sdougb dns_cache_t *cache; 182224092Sdougb dns_view_t *primaryview; 183224092Sdougb isc_boolean_t needflush; 184224092Sdougb isc_boolean_t adbsizeadjusted; 185224092Sdougb ISC_LINK(ns_cache_t) link; 186224092Sdougb}; 187224092Sdougb 188135446Strhodesstruct dumpcontext { 189135446Strhodes isc_mem_t *mctx; 190135446Strhodes isc_boolean_t dumpcache; 191135446Strhodes isc_boolean_t dumpzones; 192135446Strhodes FILE *fp; 193135446Strhodes ISC_LIST(struct viewlistentry) viewlist; 194135446Strhodes struct viewlistentry *view; 195135446Strhodes struct zonelistentry *zone; 196135446Strhodes dns_dumpctx_t *mdctx; 197135446Strhodes dns_db_t *db; 198135446Strhodes dns_db_t *cache; 199135446Strhodes isc_task_t *task; 200135446Strhodes dns_dbversion_t *version; 201135446Strhodes}; 202135446Strhodes 203135446Strhodesstruct viewlistentry { 204135446Strhodes dns_view_t *view; 205135446Strhodes ISC_LINK(struct viewlistentry) link; 206135446Strhodes ISC_LIST(struct zonelistentry) zonelist; 207135446Strhodes}; 208135446Strhodes 209135446Strhodesstruct zonelistentry { 210135446Strhodes dns_zone_t *zone; 211135446Strhodes ISC_LINK(struct zonelistentry) link; 212135446Strhodes}; 213135446Strhodes 214224092Sdougb/*% 215224092Sdougb * Configuration context to retain for each view that allows 216225361Sdougb * new zones to be added at runtime. 217224092Sdougb */ 218224092Sdougbstruct cfg_context { 219224092Sdougb isc_mem_t * mctx; 220225361Sdougb cfg_parser_t * parser; 221224092Sdougb cfg_obj_t * config; 222225361Sdougb cfg_parser_t * nzparser; 223225361Sdougb cfg_obj_t * nzconfig; 224225361Sdougb cfg_aclconfctx_t * actx; 225224092Sdougb}; 226224092Sdougb 227254897Serwin/*% 228254897Serwin * Holds state information for the initial zone loading process. 229254897Serwin * Uses the isc_refcount structure to count the number of views 230254897Serwin * with pending zone loads, dereferencing as each view finishes. 231254897Serwin */ 232254897Serwintypedef struct { 233254897Serwin ns_server_t *server; 234254897Serwin isc_refcount_t refs; 235254897Serwin} ns_zoneload_t; 236254897Serwin 237170222Sdougb/* 238170222Sdougb * These zones should not leak onto the Internet. 239170222Sdougb */ 240254897Serwinconst char *empty_zones[] = { 241170222Sdougb /* RFC 1918 */ 242254897Serwin "10.IN-ADDR.ARPA", 243254897Serwin "16.172.IN-ADDR.ARPA", 244254897Serwin "17.172.IN-ADDR.ARPA", 245254897Serwin "18.172.IN-ADDR.ARPA", 246254897Serwin "19.172.IN-ADDR.ARPA", 247254897Serwin "20.172.IN-ADDR.ARPA", 248254897Serwin "21.172.IN-ADDR.ARPA", 249254897Serwin "22.172.IN-ADDR.ARPA", 250254897Serwin "23.172.IN-ADDR.ARPA", 251254897Serwin "24.172.IN-ADDR.ARPA", 252254897Serwin "25.172.IN-ADDR.ARPA", 253254897Serwin "26.172.IN-ADDR.ARPA", 254254897Serwin "27.172.IN-ADDR.ARPA", 255254897Serwin "28.172.IN-ADDR.ARPA", 256254897Serwin "29.172.IN-ADDR.ARPA", 257254897Serwin "30.172.IN-ADDR.ARPA", 258254897Serwin "31.172.IN-ADDR.ARPA", 259254897Serwin "168.192.IN-ADDR.ARPA", 260170222Sdougb 261254402Serwin /* RFC 6598 */ 262254897Serwin "64.100.IN-ADDR.ARPA", 263254897Serwin "65.100.IN-ADDR.ARPA", 264254897Serwin "66.100.IN-ADDR.ARPA", 265254897Serwin "67.100.IN-ADDR.ARPA", 266254897Serwin "68.100.IN-ADDR.ARPA", 267254897Serwin "69.100.IN-ADDR.ARPA", 268254897Serwin "70.100.IN-ADDR.ARPA", 269254897Serwin "71.100.IN-ADDR.ARPA", 270254897Serwin "72.100.IN-ADDR.ARPA", 271254897Serwin "73.100.IN-ADDR.ARPA", 272254897Serwin "74.100.IN-ADDR.ARPA", 273254897Serwin "75.100.IN-ADDR.ARPA", 274254897Serwin "76.100.IN-ADDR.ARPA", 275254897Serwin "77.100.IN-ADDR.ARPA", 276254897Serwin "78.100.IN-ADDR.ARPA", 277254897Serwin "79.100.IN-ADDR.ARPA", 278254897Serwin "80.100.IN-ADDR.ARPA", 279254897Serwin "81.100.IN-ADDR.ARPA", 280254897Serwin "82.100.IN-ADDR.ARPA", 281254897Serwin "83.100.IN-ADDR.ARPA", 282254897Serwin "84.100.IN-ADDR.ARPA", 283254897Serwin "85.100.IN-ADDR.ARPA", 284254897Serwin "86.100.IN-ADDR.ARPA", 285254897Serwin "87.100.IN-ADDR.ARPA", 286254897Serwin "88.100.IN-ADDR.ARPA", 287254897Serwin "89.100.IN-ADDR.ARPA", 288254897Serwin "90.100.IN-ADDR.ARPA", 289254897Serwin "91.100.IN-ADDR.ARPA", 290254897Serwin "92.100.IN-ADDR.ARPA", 291254897Serwin "93.100.IN-ADDR.ARPA", 292254897Serwin "94.100.IN-ADDR.ARPA", 293254897Serwin "95.100.IN-ADDR.ARPA", 294254897Serwin "96.100.IN-ADDR.ARPA", 295254897Serwin "97.100.IN-ADDR.ARPA", 296254897Serwin "98.100.IN-ADDR.ARPA", 297254897Serwin "99.100.IN-ADDR.ARPA", 298254897Serwin "100.100.IN-ADDR.ARPA", 299254897Serwin "101.100.IN-ADDR.ARPA", 300254897Serwin "102.100.IN-ADDR.ARPA", 301254897Serwin "103.100.IN-ADDR.ARPA", 302254897Serwin "104.100.IN-ADDR.ARPA", 303254897Serwin "105.100.IN-ADDR.ARPA", 304254897Serwin "106.100.IN-ADDR.ARPA", 305254897Serwin "107.100.IN-ADDR.ARPA", 306254897Serwin "108.100.IN-ADDR.ARPA", 307254897Serwin "109.100.IN-ADDR.ARPA", 308254897Serwin "110.100.IN-ADDR.ARPA", 309254897Serwin "111.100.IN-ADDR.ARPA", 310254897Serwin "112.100.IN-ADDR.ARPA", 311254897Serwin "113.100.IN-ADDR.ARPA", 312254897Serwin "114.100.IN-ADDR.ARPA", 313254897Serwin "115.100.IN-ADDR.ARPA", 314254897Serwin "116.100.IN-ADDR.ARPA", 315254897Serwin "117.100.IN-ADDR.ARPA", 316254897Serwin "118.100.IN-ADDR.ARPA", 317254897Serwin "119.100.IN-ADDR.ARPA", 318254897Serwin "120.100.IN-ADDR.ARPA", 319254897Serwin "121.100.IN-ADDR.ARPA", 320254897Serwin "122.100.IN-ADDR.ARPA", 321254897Serwin "123.100.IN-ADDR.ARPA", 322254897Serwin "124.100.IN-ADDR.ARPA", 323254897Serwin "125.100.IN-ADDR.ARPA", 324254897Serwin "126.100.IN-ADDR.ARPA", 325254897Serwin "127.100.IN-ADDR.ARPA", 326254402Serwin 327218384Sdougb /* RFC 5735 and RFC 5737 */ 328254897Serwin "0.IN-ADDR.ARPA", /* THIS NETWORK */ 329254897Serwin "127.IN-ADDR.ARPA", /* LOOPBACK */ 330254897Serwin "254.169.IN-ADDR.ARPA", /* LINK LOCAL */ 331254897Serwin "2.0.192.IN-ADDR.ARPA", /* TEST NET */ 332254897Serwin "100.51.198.IN-ADDR.ARPA", /* TEST NET 2 */ 333254897Serwin "113.0.203.IN-ADDR.ARPA", /* TEST NET 3 */ 334254897Serwin "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */ 335170222Sdougb 336170222Sdougb /* Local IPv6 Unicast Addresses */ 337254897Serwin "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", 338254897Serwin "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", 339193149Sdougb /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */ 340254897Serwin "D.F.IP6.ARPA", 341254897Serwin "8.E.F.IP6.ARPA", /* LINK LOCAL */ 342254897Serwin "9.E.F.IP6.ARPA", /* LINK LOCAL */ 343254897Serwin "A.E.F.IP6.ARPA", /* LINK LOCAL */ 344254897Serwin "B.E.F.IP6.ARPA", /* LINK LOCAL */ 345170222Sdougb 346218384Sdougb /* Example Prefix, RFC 3849. */ 347254897Serwin "8.B.D.0.1.0.0.2.IP6.ARPA", 348218384Sdougb 349254897Serwin NULL 350170222Sdougb}; 351170222Sdougb 352224092SdougbISC_PLATFORM_NORETURN_PRE static void 353224092Sdougbfatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST; 354135446Strhodes 355135446Strhodesstatic void 356135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event); 357135446Strhodes 358135446Strhodesstatic isc_result_t 359165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 360170222Sdougb cfg_aclconfctx_t *actx, 361135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target); 362135446Strhodesstatic isc_result_t 363165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 364170222Sdougb cfg_aclconfctx_t *actx, 365135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target); 366135446Strhodes 367135446Strhodesstatic isc_result_t 368165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 369165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); 370135446Strhodes 371135446Strhodesstatic isc_result_t 372165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 373165071Sdougb const cfg_obj_t *alternates); 374135446Strhodes 375135446Strhodesstatic isc_result_t 376165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 377165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 378224092Sdougb cfg_aclconfctx_t *aclconf, isc_boolean_t added); 379135446Strhodes 380224092Sdougbstatic isc_result_t 381224092Sdougbadd_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx); 382224092Sdougb 383135446Strhodesstatic void 384135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all); 385135446Strhodes 386224092Sdougbstatic void 387225361Sdougbnewzone_cfgctx_destroy(void **cfgp); 388224092Sdougb 389262706Serwinstatic isc_result_t 390262706Serwinputstr(isc_buffer_t *b, const char *str); 391262706Serwin 392262706Serwinisc_result_t 393262706Serwinadd_comment(FILE *fp, const char *viewname); 394262706Serwin 395170222Sdougb/*% 396193149Sdougb * Configure a single view ACL at '*aclp'. Get its configuration from 397193149Sdougb * 'vconfig' (for per-view configuration) and maybe from 'config' 398135446Strhodes */ 399135446Strhodesstatic isc_result_t 400165071Sdougbconfigure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, 401224092Sdougb const char *aclname, const char *acltuplename, 402224092Sdougb cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp) 403135446Strhodes{ 404135446Strhodes isc_result_t result; 405165071Sdougb const cfg_obj_t *maps[3]; 406165071Sdougb const cfg_obj_t *aclobj = NULL; 407135446Strhodes int i = 0; 408135446Strhodes 409135446Strhodes if (*aclp != NULL) 410135446Strhodes dns_acl_detach(aclp); 411135446Strhodes if (vconfig != NULL) 412135446Strhodes maps[i++] = cfg_tuple_get(vconfig, "options"); 413135446Strhodes if (config != NULL) { 414165071Sdougb const cfg_obj_t *options = NULL; 415135446Strhodes (void)cfg_map_get(config, "options", &options); 416135446Strhodes if (options != NULL) 417135446Strhodes maps[i++] = options; 418135446Strhodes } 419135446Strhodes maps[i] = NULL; 420135446Strhodes 421165071Sdougb (void)ns_config_get(maps, aclname, &aclobj); 422135446Strhodes if (aclobj == NULL) 423135446Strhodes /* 424193149Sdougb * No value available. *aclp == NULL. 425135446Strhodes */ 426135446Strhodes return (ISC_R_SUCCESS); 427135446Strhodes 428224092Sdougb if (acltuplename != NULL) { 429224092Sdougb /* 430224092Sdougb * If the ACL is given in an optional tuple, retrieve it. 431224092Sdougb * The parser should have ensured that a valid object be 432224092Sdougb * returned. 433224092Sdougb */ 434224092Sdougb aclobj = cfg_tuple_get(aclobj, acltuplename); 435224092Sdougb } 436224092Sdougb 437170222Sdougb result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 438193149Sdougb actx, mctx, 0, aclp); 439135446Strhodes 440135446Strhodes return (result); 441135446Strhodes} 442135446Strhodes 443193149Sdougb/*% 444193149Sdougb * Configure a sortlist at '*aclp'. Essentially the same as 445193149Sdougb * configure_view_acl() except it calls cfg_acl_fromconfig with a 446193149Sdougb * nest_level value of 2. 447193149Sdougb */ 448135446Strhodesstatic isc_result_t 449193149Sdougbconfigure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config, 450193149Sdougb cfg_aclconfctx_t *actx, isc_mem_t *mctx, 451193149Sdougb dns_acl_t **aclp) 452193149Sdougb{ 453193149Sdougb isc_result_t result; 454193149Sdougb const cfg_obj_t *maps[3]; 455193149Sdougb const cfg_obj_t *aclobj = NULL; 456193149Sdougb int i = 0; 457193149Sdougb 458193149Sdougb if (*aclp != NULL) 459193149Sdougb dns_acl_detach(aclp); 460193149Sdougb if (vconfig != NULL) 461193149Sdougb maps[i++] = cfg_tuple_get(vconfig, "options"); 462193149Sdougb if (config != NULL) { 463193149Sdougb const cfg_obj_t *options = NULL; 464193149Sdougb (void)cfg_map_get(config, "options", &options); 465193149Sdougb if (options != NULL) 466193149Sdougb maps[i++] = options; 467193149Sdougb } 468193149Sdougb maps[i] = NULL; 469193149Sdougb 470193149Sdougb (void)ns_config_get(maps, "sortlist", &aclobj); 471193149Sdougb if (aclobj == NULL) 472193149Sdougb return (ISC_R_SUCCESS); 473193149Sdougb 474193149Sdougb /* 475193149Sdougb * Use a nest level of 3 for the "top level" of the sortlist; 476193149Sdougb * this means each entry in the top three levels will be stored 477193149Sdougb * as lists of separate, nested ACLs, rather than merged together 478193149Sdougb * into IP tables as is usually done with ACLs. 479193149Sdougb */ 480193149Sdougb result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, 481193149Sdougb actx, mctx, 3, aclp); 482193149Sdougb 483193149Sdougb return (result); 484193149Sdougb} 485193149Sdougb 486193149Sdougbstatic isc_result_t 487224092Sdougbconfigure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config, 488224092Sdougb const char *confname, const char *conftuplename, 489224092Sdougb isc_mem_t *mctx, dns_rbt_t **rbtp) 490135446Strhodes{ 491224092Sdougb isc_result_t result; 492224092Sdougb const cfg_obj_t *maps[3]; 493224092Sdougb const cfg_obj_t *obj = NULL; 494224092Sdougb const cfg_listelt_t *element; 495224092Sdougb int i = 0; 496224092Sdougb dns_fixedname_t fixed; 497224092Sdougb dns_name_t *name; 498224092Sdougb isc_buffer_t b; 499224092Sdougb const char *str; 500224092Sdougb const cfg_obj_t *nameobj; 501224092Sdougb 502224092Sdougb if (*rbtp != NULL) 503224092Sdougb dns_rbt_destroy(rbtp); 504224092Sdougb if (vconfig != NULL) 505224092Sdougb maps[i++] = cfg_tuple_get(vconfig, "options"); 506224092Sdougb if (config != NULL) { 507224092Sdougb const cfg_obj_t *options = NULL; 508224092Sdougb (void)cfg_map_get(config, "options", &options); 509224092Sdougb if (options != NULL) 510224092Sdougb maps[i++] = options; 511224092Sdougb } 512224092Sdougb maps[i] = NULL; 513224092Sdougb 514224092Sdougb (void)ns_config_get(maps, confname, &obj); 515224092Sdougb if (obj == NULL) 516224092Sdougb /* 517224092Sdougb * No value available. *rbtp == NULL. 518224092Sdougb */ 519224092Sdougb return (ISC_R_SUCCESS); 520224092Sdougb 521224092Sdougb if (conftuplename != NULL) { 522224092Sdougb obj = cfg_tuple_get(obj, conftuplename); 523224092Sdougb if (cfg_obj_isvoid(obj)) 524224092Sdougb return (ISC_R_SUCCESS); 525224092Sdougb } 526224092Sdougb 527224092Sdougb result = dns_rbt_create(mctx, NULL, NULL, rbtp); 528224092Sdougb if (result != ISC_R_SUCCESS) 529224092Sdougb return (result); 530224092Sdougb 531224092Sdougb dns_fixedname_init(&fixed); 532224092Sdougb name = dns_fixedname_name(&fixed); 533224092Sdougb for (element = cfg_list_first(obj); 534224092Sdougb element != NULL; 535224092Sdougb element = cfg_list_next(element)) { 536224092Sdougb nameobj = cfg_listelt_value(element); 537224092Sdougb str = cfg_obj_asstring(nameobj); 538254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 539224092Sdougb isc_buffer_add(&b, strlen(str)); 540224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 541224092Sdougb /* 542224092Sdougb * We don't need the node data, but need to set dummy data to 543224092Sdougb * avoid a partial match with an empty node. For example, if 544224092Sdougb * we have foo.example.com and bar.example.com, we'd get a match 545224092Sdougb * for baz.example.com, which is not the expected result. 546224092Sdougb * We simply use (void *)1 as the dummy data. 547224092Sdougb */ 548224092Sdougb result = dns_rbt_addname(*rbtp, name, (void *)1); 549224092Sdougb if (result != ISC_R_SUCCESS) { 550224092Sdougb cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR, 551224092Sdougb "failed to add %s for %s: %s", 552224092Sdougb str, confname, isc_result_totext(result)); 553224092Sdougb goto cleanup; 554224092Sdougb } 555224092Sdougb 556224092Sdougb } 557224092Sdougb 558224092Sdougb return (result); 559224092Sdougb 560224092Sdougb cleanup: 561224092Sdougb dns_rbt_destroy(rbtp); 562224092Sdougb return (result); 563224092Sdougb 564224092Sdougb} 565224092Sdougb 566224092Sdougbstatic isc_result_t 567224092Sdougbdstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key, 568224092Sdougb isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx) 569224092Sdougb{ 570135446Strhodes dns_rdataclass_t viewclass; 571135446Strhodes dns_rdata_dnskey_t keystruct; 572135446Strhodes isc_uint32_t flags, proto, alg; 573165071Sdougb const char *keystr, *keynamestr; 574135446Strhodes unsigned char keydata[4096]; 575135446Strhodes isc_buffer_t keydatabuf; 576135446Strhodes unsigned char rrdata[4096]; 577135446Strhodes isc_buffer_t rrdatabuf; 578135446Strhodes isc_region_t r; 579135446Strhodes dns_fixedname_t fkeyname; 580135446Strhodes dns_name_t *keyname; 581135446Strhodes isc_buffer_t namebuf; 582135446Strhodes isc_result_t result; 583135446Strhodes dst_key_t *dstkey = NULL; 584135446Strhodes 585224092Sdougb INSIST(target != NULL && *target == NULL); 586224092Sdougb 587135446Strhodes flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 588135446Strhodes proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); 589135446Strhodes alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); 590135446Strhodes keyname = dns_fixedname_name(&fkeyname); 591135446Strhodes keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 592135446Strhodes 593224092Sdougb if (managed) { 594224092Sdougb const char *initmethod; 595224092Sdougb initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init")); 596224092Sdougb 597224092Sdougb if (strcasecmp(initmethod, "initial-key") != 0) { 598224092Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 599224092Sdougb "managed key '%s': " 600224092Sdougb "invalid initialization method '%s'", 601224092Sdougb keynamestr, initmethod); 602224092Sdougb result = ISC_R_FAILURE; 603224092Sdougb goto cleanup; 604224092Sdougb } 605224092Sdougb } 606224092Sdougb 607135446Strhodes if (vconfig == NULL) 608135446Strhodes viewclass = dns_rdataclass_in; 609135446Strhodes else { 610165071Sdougb const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); 611135446Strhodes CHECK(ns_config_getclass(classobj, dns_rdataclass_in, 612135446Strhodes &viewclass)); 613135446Strhodes } 614135446Strhodes keystruct.common.rdclass = viewclass; 615135446Strhodes keystruct.common.rdtype = dns_rdatatype_dnskey; 616135446Strhodes /* 617135446Strhodes * The key data in keystruct is not dynamically allocated. 618135446Strhodes */ 619135446Strhodes keystruct.mctx = NULL; 620135446Strhodes 621135446Strhodes ISC_LINK_INIT(&keystruct.common, link); 622135446Strhodes 623135446Strhodes if (flags > 0xffff) 624135446Strhodes CHECKM(ISC_R_RANGE, "key flags"); 625135446Strhodes if (proto > 0xff) 626135446Strhodes CHECKM(ISC_R_RANGE, "key protocol"); 627135446Strhodes if (alg > 0xff) 628135446Strhodes CHECKM(ISC_R_RANGE, "key algorithm"); 629135446Strhodes keystruct.flags = (isc_uint16_t)flags; 630135446Strhodes keystruct.protocol = (isc_uint8_t)proto; 631135446Strhodes keystruct.algorithm = (isc_uint8_t)alg; 632135446Strhodes 633135446Strhodes isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); 634135446Strhodes isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 635135446Strhodes 636135446Strhodes keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 637135446Strhodes CHECK(isc_base64_decodestring(keystr, &keydatabuf)); 638135446Strhodes isc_buffer_usedregion(&keydatabuf, &r); 639135446Strhodes keystruct.datalen = r.length; 640135446Strhodes keystruct.data = r.base; 641135446Strhodes 642170222Sdougb if ((keystruct.algorithm == DST_ALG_RSASHA1 || 643170222Sdougb keystruct.algorithm == DST_ALG_RSAMD5) && 644170222Sdougb r.length > 1 && r.base[0] == 1 && r.base[1] == 3) 645170222Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 646224092Sdougb "%s key '%s' has a weak exponent", 647224092Sdougb managed ? "managed" : "trusted", 648170222Sdougb keynamestr); 649170222Sdougb 650135446Strhodes CHECK(dns_rdata_fromstruct(NULL, 651135446Strhodes keystruct.common.rdclass, 652135446Strhodes keystruct.common.rdtype, 653135446Strhodes &keystruct, &rrdatabuf)); 654135446Strhodes dns_fixedname_init(&fkeyname); 655254402Serwin isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr)); 656135446Strhodes isc_buffer_add(&namebuf, strlen(keynamestr)); 657224092Sdougb CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL)); 658135446Strhodes CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, 659135446Strhodes mctx, &dstkey)); 660135446Strhodes 661224092Sdougb *target = dstkey; 662135446Strhodes return (ISC_R_SUCCESS); 663135446Strhodes 664135446Strhodes cleanup: 665135446Strhodes if (result == DST_R_NOCRYPTO) { 666135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 667224092Sdougb "ignoring %s key for '%s': no crypto support", 668224092Sdougb managed ? "managed" : "trusted", 669135446Strhodes keynamestr); 670224092Sdougb } else if (result == DST_R_UNSUPPORTEDALG) { 671224092Sdougb cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, 672224092Sdougb "skipping %s key for '%s': %s", 673224092Sdougb managed ? "managed" : "trusted", 674224092Sdougb keynamestr, isc_result_totext(result)); 675135446Strhodes } else { 676135446Strhodes cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 677224092Sdougb "configuring %s key for '%s': %s", 678224092Sdougb managed ? "managed" : "trusted", 679135446Strhodes keynamestr, isc_result_totext(result)); 680135446Strhodes result = ISC_R_FAILURE; 681135446Strhodes } 682135446Strhodes 683135446Strhodes if (dstkey != NULL) 684135446Strhodes dst_key_free(&dstkey); 685135446Strhodes 686135446Strhodes return (result); 687135446Strhodes} 688135446Strhodes 689224092Sdougbstatic isc_result_t 690224092Sdougbload_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig, 691224092Sdougb dns_view_t *view, isc_boolean_t managed, 692224092Sdougb dns_name_t *keyname, isc_mem_t *mctx) 693224092Sdougb{ 694224092Sdougb const cfg_listelt_t *elt, *elt2; 695224092Sdougb const cfg_obj_t *key, *keylist; 696224092Sdougb dst_key_t *dstkey = NULL; 697224092Sdougb isc_result_t result; 698224092Sdougb dns_keytable_t *secroots = NULL; 699224092Sdougb 700224092Sdougb CHECK(dns_view_getsecroots(view, &secroots)); 701224092Sdougb 702224092Sdougb for (elt = cfg_list_first(keys); 703224092Sdougb elt != NULL; 704224092Sdougb elt = cfg_list_next(elt)) { 705224092Sdougb keylist = cfg_listelt_value(elt); 706224092Sdougb 707224092Sdougb for (elt2 = cfg_list_first(keylist); 708224092Sdougb elt2 != NULL; 709224092Sdougb elt2 = cfg_list_next(elt2)) { 710224092Sdougb key = cfg_listelt_value(elt2); 711224092Sdougb result = dstkey_fromconfig(vconfig, key, managed, 712224092Sdougb &dstkey, mctx); 713224092Sdougb if (result == DST_R_UNSUPPORTEDALG) { 714224092Sdougb result = ISC_R_SUCCESS; 715224092Sdougb continue; 716224092Sdougb } 717224092Sdougb if (result != ISC_R_SUCCESS) 718224092Sdougb goto cleanup; 719224092Sdougb 720224092Sdougb /* 721224092Sdougb * If keyname was specified, we only add that key. 722224092Sdougb */ 723224092Sdougb if (keyname != NULL && 724224092Sdougb !dns_name_equal(keyname, dst_key_name(dstkey))) 725224092Sdougb { 726224092Sdougb dst_key_free(&dstkey); 727224092Sdougb continue; 728224092Sdougb } 729224092Sdougb 730224092Sdougb CHECK(dns_keytable_add(secroots, managed, &dstkey)); 731224092Sdougb } 732224092Sdougb } 733224092Sdougb 734224092Sdougb cleanup: 735224092Sdougb if (dstkey != NULL) 736224092Sdougb dst_key_free(&dstkey); 737224092Sdougb if (secroots != NULL) 738224092Sdougb dns_keytable_detach(&secroots); 739224092Sdougb if (result == DST_R_NOCRYPTO) 740224092Sdougb result = ISC_R_SUCCESS; 741224092Sdougb return (result); 742224092Sdougb} 743224092Sdougb 744170222Sdougb/*% 745224092Sdougb * Configure DNSSEC keys for a view. 746135446Strhodes * 747135446Strhodes * The per-view configuration values and the server-global defaults are read 748224092Sdougb * from 'vconfig' and 'config'. 749135446Strhodes */ 750135446Strhodesstatic isc_result_t 751224092Sdougbconfigure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig, 752224092Sdougb const cfg_obj_t *config, const cfg_obj_t *bindkeys, 753224092Sdougb isc_boolean_t auto_dlv, isc_boolean_t auto_root, 754224092Sdougb isc_mem_t *mctx) 755135446Strhodes{ 756224092Sdougb isc_result_t result = ISC_R_SUCCESS; 757224092Sdougb const cfg_obj_t *view_keys = NULL; 758224092Sdougb const cfg_obj_t *global_keys = NULL; 759224092Sdougb const cfg_obj_t *view_managed_keys = NULL; 760224092Sdougb const cfg_obj_t *global_managed_keys = NULL; 761224092Sdougb const cfg_obj_t *maps[4]; 762165071Sdougb const cfg_obj_t *voptions = NULL; 763224092Sdougb const cfg_obj_t *options = NULL; 764224092Sdougb const cfg_obj_t *obj = NULL; 765224092Sdougb const char *directory; 766224092Sdougb int i = 0; 767135446Strhodes 768224092Sdougb /* We don't need trust anchors for the _bind view */ 769224092Sdougb if (strcmp(view->name, "_bind") == 0 && 770224092Sdougb view->rdclass == dns_rdataclass_chaos) { 771224092Sdougb return (ISC_R_SUCCESS); 772224092Sdougb } 773135446Strhodes 774224092Sdougb if (vconfig != NULL) { 775135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 776224092Sdougb if (voptions != NULL) { 777224092Sdougb (void) cfg_map_get(voptions, "trusted-keys", 778224092Sdougb &view_keys); 779224092Sdougb (void) cfg_map_get(voptions, "managed-keys", 780224092Sdougb &view_managed_keys); 781224092Sdougb maps[i++] = voptions; 782224092Sdougb } 783224092Sdougb } 784135446Strhodes 785224092Sdougb if (config != NULL) { 786224092Sdougb (void)cfg_map_get(config, "trusted-keys", &global_keys); 787224092Sdougb (void)cfg_map_get(config, "managed-keys", &global_managed_keys); 788224092Sdougb (void)cfg_map_get(config, "options", &options); 789224092Sdougb if (options != NULL) { 790224092Sdougb maps[i++] = options; 791224092Sdougb } 792224092Sdougb } 793135446Strhodes 794224092Sdougb maps[i++] = ns_g_defaults; 795224092Sdougb maps[i] = NULL; 796224092Sdougb 797224092Sdougb result = dns_view_initsecroots(view, mctx); 798224092Sdougb if (result != ISC_R_SUCCESS) { 799224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 800224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 801224092Sdougb "couldn't create keytable"); 802224092Sdougb return (ISC_R_UNEXPECTED); 803224092Sdougb } 804224092Sdougb 805224092Sdougb if (auto_dlv && view->rdclass == dns_rdataclass_in) { 806224092Sdougb const cfg_obj_t *builtin_keys = NULL; 807224092Sdougb const cfg_obj_t *builtin_managed_keys = NULL; 808224092Sdougb 809224092Sdougb isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, 810224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 811224092Sdougb "using built-in DLV key for view %s", 812224092Sdougb view->name); 813224092Sdougb 814224092Sdougb /* 815224092Sdougb * If bind.keys exists, it overrides the managed-keys 816224092Sdougb * clause hard-coded in ns_g_config. 817224092Sdougb */ 818224092Sdougb if (bindkeys != NULL) { 819224092Sdougb (void)cfg_map_get(bindkeys, "trusted-keys", 820224092Sdougb &builtin_keys); 821224092Sdougb (void)cfg_map_get(bindkeys, "managed-keys", 822224092Sdougb &builtin_managed_keys); 823224092Sdougb } else { 824224092Sdougb (void)cfg_map_get(ns_g_config, "trusted-keys", 825224092Sdougb &builtin_keys); 826224092Sdougb (void)cfg_map_get(ns_g_config, "managed-keys", 827224092Sdougb &builtin_managed_keys); 828135446Strhodes } 829224092Sdougb 830224092Sdougb if (builtin_keys != NULL) 831224092Sdougb CHECK(load_view_keys(builtin_keys, vconfig, view, 832224092Sdougb ISC_FALSE, view->dlv, mctx)); 833224092Sdougb if (builtin_managed_keys != NULL) 834224092Sdougb CHECK(load_view_keys(builtin_managed_keys, vconfig, 835224092Sdougb view, ISC_TRUE, view->dlv, mctx)); 836135446Strhodes } 837135446Strhodes 838224092Sdougb if (auto_root && view->rdclass == dns_rdataclass_in) { 839224092Sdougb const cfg_obj_t *builtin_keys = NULL; 840224092Sdougb const cfg_obj_t *builtin_managed_keys = NULL; 841186462Sdougb 842224092Sdougb isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, 843224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 844224092Sdougb "using built-in root key for view %s", 845224092Sdougb view->name); 846224092Sdougb 847224092Sdougb /* 848224092Sdougb * If bind.keys exists, it overrides the managed-keys 849224092Sdougb * clause hard-coded in ns_g_config. 850224092Sdougb */ 851224092Sdougb if (bindkeys != NULL) { 852224092Sdougb (void)cfg_map_get(bindkeys, "trusted-keys", 853224092Sdougb &builtin_keys); 854224092Sdougb (void)cfg_map_get(bindkeys, "managed-keys", 855224092Sdougb &builtin_managed_keys); 856224092Sdougb } else { 857224092Sdougb (void)cfg_map_get(ns_g_config, "trusted-keys", 858224092Sdougb &builtin_keys); 859224092Sdougb (void)cfg_map_get(ns_g_config, "managed-keys", 860224092Sdougb &builtin_managed_keys); 861224092Sdougb } 862224092Sdougb 863224092Sdougb if (builtin_keys != NULL) 864224092Sdougb CHECK(load_view_keys(builtin_keys, vconfig, view, 865224092Sdougb ISC_FALSE, dns_rootname, mctx)); 866224092Sdougb if (builtin_managed_keys != NULL) 867224092Sdougb CHECK(load_view_keys(builtin_managed_keys, vconfig, 868224092Sdougb view, ISC_TRUE, dns_rootname, 869224092Sdougb mctx)); 870224092Sdougb } 871224092Sdougb 872224092Sdougb CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE, 873224092Sdougb NULL, mctx)); 874224092Sdougb CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE, 875224092Sdougb NULL, mctx)); 876224092Sdougb 877224092Sdougb if (view->rdclass == dns_rdataclass_in) { 878224092Sdougb CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE, 879224092Sdougb NULL, mctx)); 880224092Sdougb CHECK(load_view_keys(global_managed_keys, vconfig, view, 881224092Sdougb ISC_TRUE, NULL, mctx)); 882224092Sdougb } 883224092Sdougb 884224092Sdougb /* 885224092Sdougb * Add key zone for managed-keys. 886224092Sdougb */ 887224092Sdougb obj = NULL; 888224092Sdougb (void)ns_config_get(maps, "managed-keys-directory", &obj); 889254402Serwin directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL); 890254402Serwin if (directory != NULL) 891254402Serwin result = isc_file_isdirectory(directory); 892254402Serwin if (result != ISC_R_SUCCESS) { 893254402Serwin isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, 894254402Serwin NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 895254402Serwin "invalid managed-keys-directory %s: %s", 896254402Serwin directory, isc_result_totext(result)); 897254402Serwin goto cleanup; 898254402Serwin 899254402Serwin } 900224092Sdougb CHECK(add_keydata_zone(view, directory, ns_g_mctx)); 901224092Sdougb 902224092Sdougb cleanup: 903135446Strhodes return (result); 904135446Strhodes} 905135446Strhodes 906135446Strhodesstatic isc_result_t 907224092Sdougbmustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) { 908165071Sdougb const cfg_listelt_t *element; 909165071Sdougb const cfg_obj_t *obj; 910135446Strhodes const char *str; 911135446Strhodes dns_fixedname_t fixed; 912135446Strhodes dns_name_t *name; 913135446Strhodes isc_boolean_t value; 914135446Strhodes isc_result_t result; 915135446Strhodes isc_buffer_t b; 916186462Sdougb 917135446Strhodes dns_fixedname_init(&fixed); 918135446Strhodes name = dns_fixedname_name(&fixed); 919135446Strhodes for (element = cfg_list_first(mbs); 920135446Strhodes element != NULL; 921135446Strhodes element = cfg_list_next(element)) 922135446Strhodes { 923135446Strhodes obj = cfg_listelt_value(element); 924135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 925254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 926135446Strhodes isc_buffer_add(&b, strlen(str)); 927224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 928135446Strhodes value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); 929135446Strhodes CHECK(dns_resolver_setmustbesecure(resolver, name, value)); 930135446Strhodes } 931135446Strhodes 932135446Strhodes result = ISC_R_SUCCESS; 933186462Sdougb 934135446Strhodes cleanup: 935135446Strhodes return (result); 936135446Strhodes} 937135446Strhodes 938170222Sdougb/*% 939135446Strhodes * Get a dispatch appropriate for the resolver of a given view. 940135446Strhodes */ 941135446Strhodesstatic isc_result_t 942165071Sdougbget_view_querysource_dispatch(const cfg_obj_t **maps, 943186462Sdougb int af, dns_dispatch_t **dispatchp, 944186462Sdougb isc_boolean_t is_firstview) 945135446Strhodes{ 946225361Sdougb isc_result_t result = ISC_R_FAILURE; 947135446Strhodes dns_dispatch_t *disp; 948135446Strhodes isc_sockaddr_t sa; 949135446Strhodes unsigned int attrs, attrmask; 950165071Sdougb const cfg_obj_t *obj = NULL; 951186462Sdougb unsigned int maxdispatchbuffers; 952135446Strhodes 953135446Strhodes switch (af) { 954135446Strhodes case AF_INET: 955135446Strhodes result = ns_config_get(maps, "query-source", &obj); 956135446Strhodes INSIST(result == ISC_R_SUCCESS); 957135446Strhodes break; 958135446Strhodes case AF_INET6: 959135446Strhodes result = ns_config_get(maps, "query-source-v6", &obj); 960135446Strhodes INSIST(result == ISC_R_SUCCESS); 961135446Strhodes break; 962135446Strhodes default: 963135446Strhodes INSIST(0); 964135446Strhodes } 965135446Strhodes 966135446Strhodes sa = *(cfg_obj_assockaddr(obj)); 967135446Strhodes INSIST(isc_sockaddr_pf(&sa) == af); 968135446Strhodes 969135446Strhodes /* 970135446Strhodes * If we don't support this address family, we're done! 971135446Strhodes */ 972135446Strhodes switch (af) { 973135446Strhodes case AF_INET: 974135446Strhodes result = isc_net_probeipv4(); 975135446Strhodes break; 976135446Strhodes case AF_INET6: 977135446Strhodes result = isc_net_probeipv6(); 978135446Strhodes break; 979135446Strhodes default: 980135446Strhodes INSIST(0); 981135446Strhodes } 982135446Strhodes if (result != ISC_R_SUCCESS) 983135446Strhodes return (ISC_R_SUCCESS); 984135446Strhodes 985135446Strhodes /* 986135446Strhodes * Try to find a dispatcher that we can share. 987135446Strhodes */ 988135446Strhodes attrs = 0; 989135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 990135446Strhodes switch (af) { 991135446Strhodes case AF_INET: 992135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 993135446Strhodes break; 994135446Strhodes case AF_INET6: 995135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 996135446Strhodes break; 997135446Strhodes } 998186462Sdougb if (isc_sockaddr_getport(&sa) == 0) { 999186462Sdougb attrs |= DNS_DISPATCHATTR_EXCLUSIVE; 1000186462Sdougb maxdispatchbuffers = 4096; 1001186462Sdougb } else { 1002180477Sdougb INSIST(obj != NULL); 1003186462Sdougb if (is_firstview) { 1004186462Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO, 1005186462Sdougb "using specific query-source port " 1006186462Sdougb "suppresses port randomization and can be " 1007186462Sdougb "insecure."); 1008186462Sdougb } 1009186462Sdougb maxdispatchbuffers = 1000; 1010180477Sdougb } 1011180477Sdougb 1012135446Strhodes attrmask = 0; 1013135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 1014135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 1015135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 1016135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 1017135446Strhodes 1018135446Strhodes disp = NULL; 1019135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 1020135446Strhodes ns_g_taskmgr, &sa, 4096, 1021186462Sdougb maxdispatchbuffers, 32768, 16411, 16433, 1022135446Strhodes attrs, attrmask, &disp); 1023135446Strhodes if (result != ISC_R_SUCCESS) { 1024135446Strhodes isc_sockaddr_t any; 1025135446Strhodes char buf[ISC_SOCKADDR_FORMATSIZE]; 1026135446Strhodes 1027135446Strhodes switch (af) { 1028135446Strhodes case AF_INET: 1029135446Strhodes isc_sockaddr_any(&any); 1030135446Strhodes break; 1031135446Strhodes case AF_INET6: 1032135446Strhodes isc_sockaddr_any6(&any); 1033135446Strhodes break; 1034135446Strhodes } 1035135446Strhodes if (isc_sockaddr_equal(&sa, &any)) 1036135446Strhodes return (ISC_R_SUCCESS); 1037135446Strhodes isc_sockaddr_format(&sa, buf, sizeof(buf)); 1038135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1039135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 1040135446Strhodes "could not get query source dispatcher (%s)", 1041135446Strhodes buf); 1042135446Strhodes return (result); 1043135446Strhodes } 1044135446Strhodes 1045135446Strhodes *dispatchp = disp; 1046135446Strhodes 1047135446Strhodes return (ISC_R_SUCCESS); 1048135446Strhodes} 1049135446Strhodes 1050135446Strhodesstatic isc_result_t 1051165071Sdougbconfigure_order(dns_order_t *order, const cfg_obj_t *ent) { 1052135446Strhodes dns_rdataclass_t rdclass; 1053135446Strhodes dns_rdatatype_t rdtype; 1054165071Sdougb const cfg_obj_t *obj; 1055135446Strhodes dns_fixedname_t fixed; 1056135446Strhodes unsigned int mode = 0; 1057135446Strhodes const char *str; 1058135446Strhodes isc_buffer_t b; 1059135446Strhodes isc_result_t result; 1060143731Sdougb isc_boolean_t addroot; 1061135446Strhodes 1062135446Strhodes result = ns_config_getclass(cfg_tuple_get(ent, "class"), 1063135446Strhodes dns_rdataclass_any, &rdclass); 1064135446Strhodes if (result != ISC_R_SUCCESS) 1065135446Strhodes return (result); 1066135446Strhodes 1067135446Strhodes result = ns_config_gettype(cfg_tuple_get(ent, "type"), 1068135446Strhodes dns_rdatatype_any, &rdtype); 1069135446Strhodes if (result != ISC_R_SUCCESS) 1070135446Strhodes return (result); 1071135446Strhodes 1072135446Strhodes obj = cfg_tuple_get(ent, "name"); 1073186462Sdougb if (cfg_obj_isstring(obj)) 1074135446Strhodes str = cfg_obj_asstring(obj); 1075135446Strhodes else 1076135446Strhodes str = "*"; 1077143731Sdougb addroot = ISC_TF(strcmp(str, "*") == 0); 1078254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 1079135446Strhodes isc_buffer_add(&b, strlen(str)); 1080135446Strhodes dns_fixedname_init(&fixed); 1081135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 1082224092Sdougb dns_rootname, 0, NULL); 1083135446Strhodes if (result != ISC_R_SUCCESS) 1084135446Strhodes return (result); 1085135446Strhodes 1086135446Strhodes obj = cfg_tuple_get(ent, "ordering"); 1087135446Strhodes INSIST(cfg_obj_isstring(obj)); 1088135446Strhodes str = cfg_obj_asstring(obj); 1089135446Strhodes if (!strcasecmp(str, "fixed")) 1090135446Strhodes mode = DNS_RDATASETATTR_FIXEDORDER; 1091135446Strhodes else if (!strcasecmp(str, "random")) 1092135446Strhodes mode = DNS_RDATASETATTR_RANDOMIZE; 1093135446Strhodes else if (!strcasecmp(str, "cyclic")) 1094135446Strhodes mode = 0; 1095135446Strhodes else 1096135446Strhodes INSIST(0); 1097135446Strhodes 1098143731Sdougb /* 1099143731Sdougb * "*" should match everything including the root (BIND 8 compat). 1100143731Sdougb * As dns_name_matcheswildcard(".", "*.") returns FALSE add a 1101165071Sdougb * explicit entry for "." when the name is "*". 1102143731Sdougb */ 1103143731Sdougb if (addroot) { 1104143731Sdougb result = dns_order_add(order, dns_rootname, 1105143731Sdougb rdtype, rdclass, mode); 1106143731Sdougb if (result != ISC_R_SUCCESS) 1107143731Sdougb return (result); 1108143731Sdougb } 1109143731Sdougb 1110135446Strhodes return (dns_order_add(order, dns_fixedname_name(&fixed), 1111135446Strhodes rdtype, rdclass, mode)); 1112135446Strhodes} 1113135446Strhodes 1114135446Strhodesstatic isc_result_t 1115165071Sdougbconfigure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { 1116135446Strhodes isc_netaddr_t na; 1117135446Strhodes dns_peer_t *peer; 1118165071Sdougb const cfg_obj_t *obj; 1119165071Sdougb const char *str; 1120135446Strhodes isc_result_t result; 1121170222Sdougb unsigned int prefixlen; 1122135446Strhodes 1123170222Sdougb cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen); 1124135446Strhodes 1125135446Strhodes peer = NULL; 1126186462Sdougb result = dns_peer_newprefix(mctx, &na, prefixlen, &peer); 1127135446Strhodes if (result != ISC_R_SUCCESS) 1128135446Strhodes return (result); 1129135446Strhodes 1130135446Strhodes obj = NULL; 1131135446Strhodes (void)cfg_map_get(cpeer, "bogus", &obj); 1132135446Strhodes if (obj != NULL) 1133135446Strhodes CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); 1134135446Strhodes 1135135446Strhodes obj = NULL; 1136135446Strhodes (void)cfg_map_get(cpeer, "provide-ixfr", &obj); 1137135446Strhodes if (obj != NULL) 1138135446Strhodes CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); 1139135446Strhodes 1140135446Strhodes obj = NULL; 1141135446Strhodes (void)cfg_map_get(cpeer, "request-ixfr", &obj); 1142135446Strhodes if (obj != NULL) 1143135446Strhodes CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); 1144135446Strhodes 1145135446Strhodes obj = NULL; 1146193149Sdougb (void)cfg_map_get(cpeer, "request-nsid", &obj); 1147193149Sdougb if (obj != NULL) 1148193149Sdougb CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); 1149193149Sdougb 1150193149Sdougb obj = NULL; 1151135446Strhodes (void)cfg_map_get(cpeer, "edns", &obj); 1152135446Strhodes if (obj != NULL) 1153135446Strhodes CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); 1154135446Strhodes 1155135446Strhodes obj = NULL; 1156170222Sdougb (void)cfg_map_get(cpeer, "edns-udp-size", &obj); 1157170222Sdougb if (obj != NULL) { 1158170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 1159170222Sdougb if (udpsize < 512) 1160170222Sdougb udpsize = 512; 1161170222Sdougb if (udpsize > 4096) 1162170222Sdougb udpsize = 4096; 1163170222Sdougb CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize)); 1164170222Sdougb } 1165170222Sdougb 1166170222Sdougb obj = NULL; 1167170222Sdougb (void)cfg_map_get(cpeer, "max-udp-size", &obj); 1168170222Sdougb if (obj != NULL) { 1169170222Sdougb isc_uint32_t udpsize = cfg_obj_asuint32(obj); 1170170222Sdougb if (udpsize < 512) 1171170222Sdougb udpsize = 512; 1172170222Sdougb if (udpsize > 4096) 1173170222Sdougb udpsize = 4096; 1174170222Sdougb CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize)); 1175170222Sdougb } 1176170222Sdougb 1177170222Sdougb obj = NULL; 1178135446Strhodes (void)cfg_map_get(cpeer, "transfers", &obj); 1179135446Strhodes if (obj != NULL) 1180135446Strhodes CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); 1181135446Strhodes 1182135446Strhodes obj = NULL; 1183135446Strhodes (void)cfg_map_get(cpeer, "transfer-format", &obj); 1184135446Strhodes if (obj != NULL) { 1185135446Strhodes str = cfg_obj_asstring(obj); 1186135446Strhodes if (strcasecmp(str, "many-answers") == 0) 1187135446Strhodes CHECK(dns_peer_settransferformat(peer, 1188135446Strhodes dns_many_answers)); 1189135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 1190135446Strhodes CHECK(dns_peer_settransferformat(peer, 1191135446Strhodes dns_one_answer)); 1192135446Strhodes else 1193135446Strhodes INSIST(0); 1194135446Strhodes } 1195135446Strhodes 1196135446Strhodes obj = NULL; 1197135446Strhodes (void)cfg_map_get(cpeer, "keys", &obj); 1198135446Strhodes if (obj != NULL) { 1199135446Strhodes result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); 1200135446Strhodes if (result != ISC_R_SUCCESS) 1201135446Strhodes goto cleanup; 1202135446Strhodes } 1203135446Strhodes 1204135446Strhodes obj = NULL; 1205170222Sdougb if (na.family == AF_INET) 1206135446Strhodes (void)cfg_map_get(cpeer, "transfer-source", &obj); 1207135446Strhodes else 1208135446Strhodes (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); 1209135446Strhodes if (obj != NULL) { 1210135446Strhodes result = dns_peer_settransfersource(peer, 1211135446Strhodes cfg_obj_assockaddr(obj)); 1212135446Strhodes if (result != ISC_R_SUCCESS) 1213135446Strhodes goto cleanup; 1214170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1215135446Strhodes } 1216170222Sdougb 1217170222Sdougb obj = NULL; 1218170222Sdougb if (na.family == AF_INET) 1219170222Sdougb (void)cfg_map_get(cpeer, "notify-source", &obj); 1220170222Sdougb else 1221170222Sdougb (void)cfg_map_get(cpeer, "notify-source-v6", &obj); 1222170222Sdougb if (obj != NULL) { 1223170222Sdougb result = dns_peer_setnotifysource(peer, 1224170222Sdougb cfg_obj_assockaddr(obj)); 1225170222Sdougb if (result != ISC_R_SUCCESS) 1226170222Sdougb goto cleanup; 1227170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1228170222Sdougb } 1229170222Sdougb 1230170222Sdougb obj = NULL; 1231170222Sdougb if (na.family == AF_INET) 1232170222Sdougb (void)cfg_map_get(cpeer, "query-source", &obj); 1233170222Sdougb else 1234170222Sdougb (void)cfg_map_get(cpeer, "query-source-v6", &obj); 1235170222Sdougb if (obj != NULL) { 1236170222Sdougb result = dns_peer_setquerysource(peer, 1237170222Sdougb cfg_obj_assockaddr(obj)); 1238170222Sdougb if (result != ISC_R_SUCCESS) 1239170222Sdougb goto cleanup; 1240170222Sdougb ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); 1241170222Sdougb } 1242170222Sdougb 1243135446Strhodes *peerp = peer; 1244135446Strhodes return (ISC_R_SUCCESS); 1245135446Strhodes 1246135446Strhodes cleanup: 1247135446Strhodes dns_peer_detach(&peer); 1248135446Strhodes return (result); 1249135446Strhodes} 1250135446Strhodes 1251135446Strhodesstatic isc_result_t 1252165071Sdougbdisable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { 1253135446Strhodes isc_result_t result; 1254165071Sdougb const cfg_obj_t *algorithms; 1255165071Sdougb const cfg_listelt_t *element; 1256135446Strhodes const char *str; 1257135446Strhodes dns_fixedname_t fixed; 1258135446Strhodes dns_name_t *name; 1259135446Strhodes isc_buffer_t b; 1260135446Strhodes 1261135446Strhodes dns_fixedname_init(&fixed); 1262135446Strhodes name = dns_fixedname_name(&fixed); 1263135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); 1264254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 1265135446Strhodes isc_buffer_add(&b, strlen(str)); 1266224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 1267135446Strhodes 1268135446Strhodes algorithms = cfg_tuple_get(disabled, "algorithms"); 1269135446Strhodes for (element = cfg_list_first(algorithms); 1270135446Strhodes element != NULL; 1271135446Strhodes element = cfg_list_next(element)) 1272135446Strhodes { 1273135446Strhodes isc_textregion_t r; 1274135446Strhodes dns_secalg_t alg; 1275135446Strhodes 1276165071Sdougb DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 1277135446Strhodes r.length = strlen(r.base); 1278135446Strhodes 1279135446Strhodes result = dns_secalg_fromtext(&alg, &r); 1280135446Strhodes if (result != ISC_R_SUCCESS) { 1281135446Strhodes isc_uint8_t ui; 1282135446Strhodes result = isc_parse_uint8(&ui, r.base, 10); 1283135446Strhodes alg = ui; 1284135446Strhodes } 1285135446Strhodes if (result != ISC_R_SUCCESS) { 1286135446Strhodes cfg_obj_log(cfg_listelt_value(element), 1287135446Strhodes ns_g_lctx, ISC_LOG_ERROR, 1288135446Strhodes "invalid algorithm"); 1289135446Strhodes CHECK(result); 1290135446Strhodes } 1291135446Strhodes CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); 1292135446Strhodes } 1293135446Strhodes cleanup: 1294135446Strhodes return (result); 1295135446Strhodes} 1296135446Strhodes 1297170222Sdougbstatic isc_boolean_t 1298170222Sdougbon_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) { 1299170222Sdougb const cfg_listelt_t *element; 1300170222Sdougb dns_fixedname_t fixed; 1301170222Sdougb dns_name_t *name; 1302170222Sdougb isc_result_t result; 1303170222Sdougb const cfg_obj_t *value; 1304170222Sdougb const char *str; 1305170222Sdougb isc_buffer_t b; 1306170222Sdougb 1307170222Sdougb dns_fixedname_init(&fixed); 1308170222Sdougb name = dns_fixedname_name(&fixed); 1309186462Sdougb 1310170222Sdougb for (element = cfg_list_first(disablelist); 1311170222Sdougb element != NULL; 1312170222Sdougb element = cfg_list_next(element)) 1313170222Sdougb { 1314170222Sdougb value = cfg_listelt_value(element); 1315170222Sdougb str = cfg_obj_asstring(value); 1316254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 1317170222Sdougb isc_buffer_add(&b, strlen(str)); 1318170222Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 1319224092Sdougb 0, NULL); 1320170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 1321170222Sdougb if (dns_name_equal(name, zonename)) 1322170222Sdougb return (ISC_TRUE); 1323170222Sdougb } 1324170222Sdougb return (ISC_FALSE); 1325170222Sdougb} 1326170222Sdougb 1327262706Serwinstatic isc_result_t 1328262706Serwincheck_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv, 1329170222Sdougb isc_mem_t *mctx) 1330170222Sdougb{ 1331170222Sdougb char **argv = NULL; 1332170222Sdougb unsigned int i; 1333262706Serwin isc_result_t result = ISC_R_SUCCESS; 1334170222Sdougb 1335262706Serwin CHECK(dns_zone_getdbtype(zone, &argv, mctx)); 1336170222Sdougb 1337170222Sdougb /* 1338170222Sdougb * Check that all the arguments match. 1339170222Sdougb */ 1340170222Sdougb for (i = 0; i < dbtypec; i++) 1341170222Sdougb if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) { 1342262706Serwin CHECK(ISC_R_FAILURE); 1343170222Sdougb break; 1344170222Sdougb } 1345170222Sdougb 1346170222Sdougb /* 1347170222Sdougb * Check that there are not extra arguments. 1348170222Sdougb */ 1349170222Sdougb if (i == dbtypec && argv[i] != NULL) 1350262706Serwin result = ISC_R_FAILURE; 1351262706Serwin 1352262706Serwin cleanup: 1353170222Sdougb isc_mem_free(mctx, argv); 1354262706Serwin return (result); 1355170222Sdougb} 1356170222Sdougb 1357193149Sdougbstatic isc_result_t 1358254897Serwinsetquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) { 1359193149Sdougb isc_result_t result; 1360193149Sdougb isc_stats_t *zoneqrystats; 1361170222Sdougb 1362254897Serwin dns_zone_setstatlevel(zone, level); 1363254897Serwin 1364193149Sdougb zoneqrystats = NULL; 1365254897Serwin if (level == dns_zonestat_full) { 1366193149Sdougb result = isc_stats_create(mctx, &zoneqrystats, 1367193149Sdougb dns_nsstatscounter_max); 1368193149Sdougb if (result != ISC_R_SUCCESS) 1369193149Sdougb return (result); 1370193149Sdougb } 1371193149Sdougb dns_zone_setrequeststats(zone, zoneqrystats); 1372193149Sdougb if (zoneqrystats != NULL) 1373193149Sdougb isc_stats_detach(&zoneqrystats); 1374193149Sdougb 1375193149Sdougb return (ISC_R_SUCCESS); 1376193149Sdougb} 1377193149Sdougb 1378224092Sdougbstatic ns_cache_t * 1379224092Sdougbcachelist_find(ns_cachelist_t *cachelist, const char *cachename) { 1380224092Sdougb ns_cache_t *nsc; 1381224092Sdougb 1382224092Sdougb for (nsc = ISC_LIST_HEAD(*cachelist); 1383224092Sdougb nsc != NULL; 1384224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 1385224092Sdougb if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0) 1386224092Sdougb return (nsc); 1387224092Sdougb } 1388224092Sdougb 1389224092Sdougb return (NULL); 1390224092Sdougb} 1391224092Sdougb 1392193149Sdougbstatic isc_boolean_t 1393193149Sdougbcache_reusable(dns_view_t *originview, dns_view_t *view, 1394193149Sdougb isc_boolean_t new_zero_no_soattl) 1395193149Sdougb{ 1396193149Sdougb if (originview->checknames != view->checknames || 1397193149Sdougb dns_resolver_getzeronosoattl(originview->resolver) != 1398193149Sdougb new_zero_no_soattl || 1399193149Sdougb originview->acceptexpired != view->acceptexpired || 1400193149Sdougb originview->enablevalidation != view->enablevalidation || 1401193149Sdougb originview->maxcachettl != view->maxcachettl || 1402193149Sdougb originview->maxncachettl != view->maxncachettl) { 1403193149Sdougb return (ISC_FALSE); 1404193149Sdougb } 1405193149Sdougb 1406193149Sdougb return (ISC_TRUE); 1407193149Sdougb} 1408193149Sdougb 1409224092Sdougbstatic isc_boolean_t 1410224092Sdougbcache_sharable(dns_view_t *originview, dns_view_t *view, 1411224092Sdougb isc_boolean_t new_zero_no_soattl, 1412224092Sdougb unsigned int new_cleaning_interval, 1413254897Serwin isc_uint64_t new_max_cache_size) 1414224092Sdougb{ 1415224092Sdougb /* 1416224092Sdougb * If the cache cannot even reused for the same view, it cannot be 1417224092Sdougb * shared with other views. 1418224092Sdougb */ 1419224092Sdougb if (!cache_reusable(originview, view, new_zero_no_soattl)) 1420224092Sdougb return (ISC_FALSE); 1421224092Sdougb 1422224092Sdougb /* 1423224092Sdougb * Check other cache related parameters that must be consistent among 1424224092Sdougb * the sharing views. 1425224092Sdougb */ 1426224092Sdougb if (dns_cache_getcleaninginterval(originview->cache) != 1427224092Sdougb new_cleaning_interval || 1428224092Sdougb dns_cache_getcachesize(originview->cache) != new_max_cache_size) { 1429224092Sdougb return (ISC_FALSE); 1430224092Sdougb } 1431224092Sdougb 1432224092Sdougb return (ISC_TRUE); 1433224092Sdougb} 1434224092Sdougb 1435135446Strhodes/* 1436224092Sdougb * Callback from DLZ configure when the driver sets up a writeable zone 1437224092Sdougb */ 1438224092Sdougbstatic isc_result_t 1439224092Sdougbdlzconfigure_callback(dns_view_t *view, dns_zone_t *zone) { 1440224092Sdougb dns_name_t *origin = dns_zone_getorigin(zone); 1441224092Sdougb dns_rdataclass_t zclass = view->rdclass; 1442224092Sdougb isc_result_t result; 1443224092Sdougb 1444224092Sdougb result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone); 1445224092Sdougb if (result != ISC_R_SUCCESS) 1446254897Serwin return (result); 1447224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 1448224092Sdougb 1449254897Serwin return (ns_zone_configure_writeable_dlz(view->dlzdatabase, 1450254897Serwin zone, zclass, origin)); 1451224092Sdougb} 1452224092Sdougb 1453224092Sdougbstatic isc_result_t 1454224092Sdougbdns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na, 1455224092Sdougb unsigned int prefixlen, const char *server, 1456224092Sdougb const char *contact) 1457224092Sdougb{ 1458224092Sdougb char *cp; 1459224092Sdougb char reverse[48+sizeof("ip6.arpa.")]; 1460236374Sdougb const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." }; 1461224092Sdougb const char *sep = ": view "; 1462224092Sdougb const char *viewname = view->name; 1463224092Sdougb const unsigned char *s6; 1464224092Sdougb dns_fixedname_t fixed; 1465224092Sdougb dns_name_t *name; 1466224092Sdougb dns_zone_t *zone = NULL; 1467224092Sdougb int dns64_dbtypec = 4; 1468224092Sdougb isc_buffer_t b; 1469224092Sdougb isc_result_t result; 1470224092Sdougb 1471224092Sdougb REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || 1472224092Sdougb prefixlen == 56 || prefixlen == 64 || prefixlen == 96); 1473224092Sdougb 1474224092Sdougb if (!strcmp(viewname, "_default")) { 1475224092Sdougb sep = ""; 1476224092Sdougb viewname = ""; 1477224092Sdougb } 1478224092Sdougb 1479224092Sdougb /* 1480224092Sdougb * Construct the reverse name of the zone. 1481224092Sdougb */ 1482224092Sdougb cp = reverse; 1483224092Sdougb s6 = na->type.in6.s6_addr; 1484224092Sdougb while (prefixlen > 0) { 1485224092Sdougb prefixlen -= 8; 1486224092Sdougb sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf, 1487224092Sdougb (s6[prefixlen/8] >> 4) & 0xf); 1488224092Sdougb cp += 4; 1489224092Sdougb } 1490224092Sdougb strcat(cp, "ip6.arpa."); 1491224092Sdougb 1492224092Sdougb /* 1493224092Sdougb * Create the actual zone. 1494224092Sdougb */ 1495224092Sdougb if (server != NULL) 1496224092Sdougb dns64_dbtype[2] = server; 1497224092Sdougb if (contact != NULL) 1498224092Sdougb dns64_dbtype[3] = contact; 1499224092Sdougb dns_fixedname_init(&fixed); 1500224092Sdougb name = dns_fixedname_name(&fixed); 1501254402Serwin isc_buffer_constinit(&b, reverse, strlen(reverse)); 1502224092Sdougb isc_buffer_add(&b, strlen(reverse)); 1503224092Sdougb CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); 1504224092Sdougb CHECK(dns_zone_create(&zone, mctx)); 1505224092Sdougb CHECK(dns_zone_setorigin(zone, name)); 1506224092Sdougb dns_zone_setview(zone, view); 1507224092Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1508224092Sdougb dns_zone_setclass(zone, view->rdclass); 1509224092Sdougb dns_zone_settype(zone, dns_zone_master); 1510224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 1511224092Sdougb CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype)); 1512224092Sdougb if (view->queryacl != NULL) 1513224092Sdougb dns_zone_setqueryacl(zone, view->queryacl); 1514224092Sdougb if (view->queryonacl != NULL) 1515224092Sdougb dns_zone_setqueryonacl(zone, view->queryonacl); 1516224092Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 1517224092Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 1518224092Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 1519254897Serwin CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */ 1520224092Sdougb CHECK(dns_view_addzone(view, zone)); 1521224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 1522224092Sdougb ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep, 1523224092Sdougb viewname, reverse); 1524224092Sdougb 1525224092Sdougbcleanup: 1526224092Sdougb if (zone != NULL) 1527224092Sdougb dns_zone_detach(&zone); 1528224092Sdougb return (result); 1529224092Sdougb} 1530224092Sdougb 1531224092Sdougbstatic isc_result_t 1532254402Serwinconfigure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name, 1533254402Serwin const char *str, const char *msg) 1534254402Serwin{ 1535254402Serwin isc_result_t result; 1536254402Serwin 1537254402Serwin result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx); 1538254402Serwin if (result != ISC_R_SUCCESS) 1539254402Serwin cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1540254402Serwin "invalid %s '%s'", msg, str); 1541254402Serwin return (result); 1542254402Serwin} 1543254402Serwin 1544254402Serwinstatic isc_result_t 1545254402Serwinconfigure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name, 1546254402Serwin const char *str, const dns_name_t *origin) 1547254402Serwin{ 1548254402Serwin isc_result_t result; 1549254402Serwin 1550254402Serwin result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE, 1551254402Serwin view->mctx); 1552254402Serwin if (result != ISC_R_SUCCESS) 1553254402Serwin cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1554254402Serwin "invalid zone '%s'", str); 1555254402Serwin return (result); 1556254402Serwin} 1557254402Serwin 1558254402Serwinstatic isc_result_t 1559245163Serwinconfigure_rpz(dns_view_t *view, const cfg_listelt_t *element, 1560245163Serwin isc_boolean_t recursive_only_def, dns_ttl_t ttl_def) 1561245163Serwin{ 1562254402Serwin const cfg_obj_t *rpz_obj, *obj; 1563224092Sdougb const char *str; 1564224092Sdougb dns_rpz_zone_t *old, *new; 1565224092Sdougb isc_result_t result; 1566224092Sdougb 1567254402Serwin rpz_obj = cfg_listelt_value(element); 1568254402Serwin 1569224092Sdougb new = isc_mem_get(view->mctx, sizeof(*new)); 1570224092Sdougb if (new == NULL) { 1571254402Serwin cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1572254402Serwin "no memory for response policy zones"); 1573254402Serwin return (ISC_R_NOMEMORY); 1574224092Sdougb } 1575224092Sdougb 1576224092Sdougb memset(new, 0, sizeof(*new)); 1577245163Serwin dns_name_init(&new->origin, NULL); 1578224092Sdougb dns_name_init(&new->nsdname, NULL); 1579254402Serwin dns_name_init(&new->passthru, NULL); 1580224092Sdougb dns_name_init(&new->cname, NULL); 1581224092Sdougb ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link); 1582224092Sdougb 1583245163Serwin obj = cfg_tuple_get(rpz_obj, "recursive-only"); 1584245163Serwin if (cfg_obj_isvoid(obj)) { 1585245163Serwin new->recursive_only = recursive_only_def; 1586245163Serwin } else { 1587245163Serwin new->recursive_only = cfg_obj_asboolean(obj); 1588245163Serwin } 1589245163Serwin if (!new->recursive_only) 1590245163Serwin view->rpz_recursive_only = ISC_FALSE; 1591245163Serwin 1592245163Serwin obj = cfg_tuple_get(rpz_obj, "max-policy-ttl"); 1593245163Serwin if (cfg_obj_isuint32(obj)) { 1594245163Serwin new->max_policy_ttl = cfg_obj_asuint32(obj); 1595245163Serwin } else { 1596245163Serwin new->max_policy_ttl = ttl_def; 1597245163Serwin } 1598245163Serwin 1599245163Serwin str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name")); 1600254402Serwin result = configure_rpz_name(view, rpz_obj, &new->origin, str, "zone"); 1601254402Serwin if (result != ISC_R_SUCCESS) 1602254402Serwin return (result); 1603254402Serwin if (dns_name_equal(&new->origin, dns_rootname)) { 1604224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1605254402Serwin "invalid zone name '%s'", str); 1606254402Serwin return (DNS_R_EMPTYLABEL); 1607224092Sdougb } 1608224092Sdougb for (old = ISC_LIST_HEAD(view->rpz_zones); 1609224092Sdougb old != new; 1610224092Sdougb old = ISC_LIST_NEXT(old, link)) { 1611224092Sdougb ++new->num; 1612224092Sdougb if (dns_name_equal(&old->origin, &new->origin)) { 1613224092Sdougb cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 1614224092Sdougb "duplicate '%s'", str); 1615224092Sdougb result = DNS_R_DUPLICATE; 1616254402Serwin return (result); 1617224092Sdougb } 1618224092Sdougb } 1619224092Sdougb 1620254402Serwin result = configure_rpz_name2(view, rpz_obj, &new->nsdname, 1621254402Serwin DNS_RPZ_NSDNAME_ZONE, &new->origin); 1622254402Serwin if (result != ISC_R_SUCCESS) 1623254402Serwin return (result); 1624254402Serwin 1625254402Serwin result = configure_rpz_name(view, rpz_obj, &new->passthru, 1626254402Serwin DNS_RPZ_PASSTHRU_ZONE, "zone"); 1627254402Serwin if (result != ISC_R_SUCCESS) 1628254402Serwin return (result); 1629254402Serwin 1630254402Serwin obj = cfg_tuple_get(rpz_obj, "policy"); 1631254402Serwin if (cfg_obj_isvoid(obj)) { 1632254402Serwin new->policy = DNS_RPZ_POLICY_GIVEN; 1633254402Serwin } else { 1634254402Serwin str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name")); 1635254402Serwin new->policy = dns_rpz_str2policy(str); 1636254402Serwin INSIST(new->policy != DNS_RPZ_POLICY_ERROR); 1637254402Serwin if (new->policy == DNS_RPZ_POLICY_CNAME) { 1638254402Serwin str = cfg_obj_asstring(cfg_tuple_get(obj, "cname")); 1639254402Serwin result = configure_rpz_name(view, rpz_obj, &new->cname, 1640254402Serwin str, "cname"); 1641254402Serwin if (result != ISC_R_SUCCESS) 1642254402Serwin return (result); 1643224092Sdougb } 1644224092Sdougb } 1645224092Sdougb 1646224092Sdougb return (ISC_R_SUCCESS); 1647224092Sdougb} 1648224092Sdougb 1649262706Serwin#ifdef USE_RRL 1650262706Serwin#define CHECK_RRL(cond, pat, val1, val2) \ 1651262706Serwin do { \ 1652262706Serwin if (!(cond)) { \ 1653262706Serwin cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, \ 1654262706Serwin pat, val1, val2); \ 1655262706Serwin result = ISC_R_RANGE; \ 1656262706Serwin goto cleanup; \ 1657262706Serwin } \ 1658262706Serwin } while (0) 1659262706Serwin 1660262706Serwin#define CHECK_RRL_RATE(rate, def, max_rate, name) \ 1661262706Serwin do { \ 1662262706Serwin obj = NULL; \ 1663262706Serwin rrl->rate.str = name; \ 1664262706Serwin result = cfg_map_get(map, name, &obj); \ 1665262706Serwin if (result == ISC_R_SUCCESS) { \ 1666262706Serwin rrl->rate.r = cfg_obj_asuint32(obj); \ 1667262706Serwin CHECK_RRL(rrl->rate.r <= max_rate, \ 1668262706Serwin name" %d > %d", \ 1669262706Serwin rrl->rate.r, max_rate); \ 1670262706Serwin } else { \ 1671262706Serwin rrl->rate.r = def; \ 1672262706Serwin } \ 1673262706Serwin rrl->rate.scaled = rrl->rate.r; \ 1674262706Serwin } while (0) 1675262706Serwin 1676262706Serwinstatic isc_result_t 1677262706Serwinconfigure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) { 1678262706Serwin const cfg_obj_t *obj; 1679262706Serwin dns_rrl_t *rrl; 1680262706Serwin isc_result_t result; 1681262706Serwin int min_entries, i, j; 1682262706Serwin 1683262706Serwin /* 1684262706Serwin * Most DNS servers have few clients, but intentinally open 1685262706Serwin * recursive and authoritative servers often have many. 1686262706Serwin * So start with a small number of entries unless told otherwise 1687262706Serwin * to reduce cold-start costs. 1688262706Serwin */ 1689262706Serwin min_entries = 500; 1690262706Serwin obj = NULL; 1691262706Serwin result = cfg_map_get(map, "min-table-size", &obj); 1692262706Serwin if (result == ISC_R_SUCCESS) { 1693262706Serwin min_entries = cfg_obj_asuint32(obj); 1694262706Serwin if (min_entries < 1) 1695262706Serwin min_entries = 1; 1696262706Serwin } 1697262706Serwin result = dns_rrl_init(&rrl, view, min_entries); 1698262706Serwin if (result != ISC_R_SUCCESS) 1699262706Serwin return (result); 1700262706Serwin 1701262706Serwin i = ISC_MAX(20000, min_entries); 1702262706Serwin obj = NULL; 1703262706Serwin result = cfg_map_get(map, "max-table-size", &obj); 1704262706Serwin if (result == ISC_R_SUCCESS) { 1705262706Serwin i = cfg_obj_asuint32(obj); 1706262706Serwin CHECK_RRL(i >= min_entries, 1707262706Serwin "max-table-size %d < min-table-size %d", 1708262706Serwin i, min_entries); 1709262706Serwin } 1710262706Serwin rrl->max_entries = i; 1711262706Serwin 1712262706Serwin CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE, 1713262706Serwin "responses-per-second"); 1714262706Serwin CHECK_RRL_RATE(referrals_per_second, 1715262706Serwin rrl->responses_per_second.r, DNS_RRL_MAX_RATE, 1716262706Serwin "referrals-per-second"); 1717262706Serwin CHECK_RRL_RATE(nodata_per_second, 1718262706Serwin rrl->responses_per_second.r, DNS_RRL_MAX_RATE, 1719262706Serwin "nodata-per-second"); 1720262706Serwin CHECK_RRL_RATE(nxdomains_per_second, 1721262706Serwin rrl->responses_per_second.r, DNS_RRL_MAX_RATE, 1722262706Serwin "nxdomains-per-second"); 1723262706Serwin CHECK_RRL_RATE(errors_per_second, 1724262706Serwin rrl->responses_per_second.r, DNS_RRL_MAX_RATE, 1725262706Serwin "errors-per-second"); 1726262706Serwin 1727262706Serwin CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, 1728262706Serwin "all-per-second"); 1729262706Serwin 1730262706Serwin CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, 1731262706Serwin "slip"); 1732262706Serwin 1733262706Serwin i = 15; 1734262706Serwin obj = NULL; 1735262706Serwin result = cfg_map_get(map, "window", &obj); 1736262706Serwin if (result == ISC_R_SUCCESS) { 1737262706Serwin i = cfg_obj_asuint32(obj); 1738262706Serwin CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW, 1739262706Serwin "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW); 1740262706Serwin } 1741262706Serwin rrl->window = i; 1742262706Serwin 1743262706Serwin i = 0; 1744262706Serwin obj = NULL; 1745262706Serwin result = cfg_map_get(map, "qps-scale", &obj); 1746262706Serwin if (result == ISC_R_SUCCESS) { 1747262706Serwin i = cfg_obj_asuint32(obj); 1748262706Serwin CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, ""); 1749262706Serwin } 1750262706Serwin rrl->qps_scale = i; 1751262706Serwin rrl->qps = 1.0; 1752262706Serwin 1753262706Serwin i = 24; 1754262706Serwin obj = NULL; 1755262706Serwin result = cfg_map_get(map, "ipv4-prefix-length", &obj); 1756262706Serwin if (result == ISC_R_SUCCESS) { 1757262706Serwin i = cfg_obj_asuint32(obj); 1758262706Serwin CHECK_RRL(i >= 8 && i <= 32, 1759262706Serwin "invalid 'ipv4-prefix-length %d'%s", i, ""); 1760262706Serwin } 1761262706Serwin rrl->ipv4_prefixlen = i; 1762262706Serwin if (i == 32) 1763262706Serwin rrl->ipv4_mask = 0xffffffff; 1764262706Serwin else 1765262706Serwin rrl->ipv4_mask = htonl(0xffffffff << (32-i)); 1766262706Serwin 1767262706Serwin i = 56; 1768262706Serwin obj = NULL; 1769262706Serwin result = cfg_map_get(map, "ipv6-prefix-length", &obj); 1770262706Serwin if (result == ISC_R_SUCCESS) { 1771262706Serwin i = cfg_obj_asuint32(obj); 1772262706Serwin CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX, 1773262706Serwin "ipv6-prefix-length %d < 16 or > %d", 1774262706Serwin i, DNS_RRL_MAX_PREFIX); 1775262706Serwin } 1776262706Serwin rrl->ipv6_prefixlen = i; 1777262706Serwin for (j = 0; j < 4; ++j) { 1778262706Serwin if (i <= 0) { 1779262706Serwin rrl->ipv6_mask[j] = 0; 1780262706Serwin } else if (i < 32) { 1781262706Serwin rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i)); 1782262706Serwin } else { 1783262706Serwin rrl->ipv6_mask[j] = 0xffffffff; 1784262706Serwin } 1785262706Serwin i -= 32; 1786262706Serwin } 1787262706Serwin 1788262706Serwin obj = NULL; 1789262706Serwin result = cfg_map_get(map, "exempt-clients", &obj); 1790262706Serwin if (result == ISC_R_SUCCESS) { 1791262706Serwin result = cfg_acl_fromconfig(obj, config, ns_g_lctx, 1792262706Serwin ns_g_aclconfctx, ns_g_mctx, 1793262706Serwin 0, &rrl->exempt); 1794262706Serwin CHECK_RRL(result == ISC_R_SUCCESS, 1795262706Serwin "invalid %s%s", "address match list", ""); 1796262706Serwin } 1797262706Serwin 1798262706Serwin obj = NULL; 1799262706Serwin result = cfg_map_get(map, "log-only", &obj); 1800262706Serwin if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) 1801262706Serwin rrl->log_only = ISC_TRUE; 1802262706Serwin else 1803262706Serwin rrl->log_only = ISC_FALSE; 1804262706Serwin 1805262706Serwin return (ISC_R_SUCCESS); 1806262706Serwin 1807262706Serwin cleanup: 1808262706Serwin dns_rrl_view_destroy(view); 1809262706Serwin return (result); 1810262706Serwin} 1811262706Serwin#endif /* USE_RRL */ 1812262706Serwin 1813262706Serwinstatic isc_result_t 1814262706Serwinadd_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, 1815262706Serwin dns_name_t *origin, dns_name_t *contact) 1816262706Serwin{ 1817262706Serwin dns_dbnode_t *node = NULL; 1818262706Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 1819262706Serwin dns_rdatalist_t rdatalist; 1820262706Serwin dns_rdataset_t rdataset; 1821262706Serwin isc_result_t result; 1822262706Serwin unsigned char buf[DNS_SOA_BUFFERSIZE]; 1823262706Serwin 1824262706Serwin dns_rdataset_init(&rdataset); 1825262706Serwin dns_rdatalist_init(&rdatalist); 1826262706Serwin CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 1827262706Serwin 0, 28800, 7200, 604800, 86400, buf, &rdata)); 1828262706Serwin rdatalist.type = rdata.type; 1829262706Serwin rdatalist.covers = 0; 1830262706Serwin rdatalist.rdclass = rdata.rdclass; 1831262706Serwin rdatalist.ttl = 86400; 1832262706Serwin ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); 1833262706Serwin CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); 1834262706Serwin CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); 1835262706Serwin CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); 1836262706Serwin cleanup: 1837262706Serwin if (node != NULL) 1838262706Serwin dns_db_detachnode(db, &node); 1839262706Serwin return (result); 1840262706Serwin} 1841262706Serwin 1842262706Serwinstatic isc_result_t 1843262706Serwinadd_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, 1844262706Serwin dns_name_t *nsname) 1845262706Serwin{ 1846262706Serwin dns_dbnode_t *node = NULL; 1847262706Serwin dns_rdata_ns_t ns; 1848262706Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 1849262706Serwin dns_rdatalist_t rdatalist; 1850262706Serwin dns_rdataset_t rdataset; 1851262706Serwin isc_result_t result; 1852262706Serwin isc_buffer_t b; 1853262706Serwin unsigned char buf[DNS_NAME_MAXWIRE]; 1854262706Serwin 1855262706Serwin isc_buffer_init(&b, buf, sizeof(buf)); 1856262706Serwin 1857262706Serwin dns_rdataset_init(&rdataset); 1858262706Serwin dns_rdatalist_init(&rdatalist); 1859262706Serwin ns.common.rdtype = dns_rdatatype_ns; 1860262706Serwin ns.common.rdclass = dns_db_class(db); 1861262706Serwin ns.mctx = NULL; 1862262706Serwin dns_name_init(&ns.name, NULL); 1863262706Serwin dns_name_clone(nsname, &ns.name); 1864262706Serwin CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns, 1865262706Serwin &ns, &b)); 1866262706Serwin rdatalist.type = rdata.type; 1867262706Serwin rdatalist.covers = 0; 1868262706Serwin rdatalist.rdclass = rdata.rdclass; 1869262706Serwin rdatalist.ttl = 86400; 1870262706Serwin ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); 1871262706Serwin CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); 1872262706Serwin CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); 1873262706Serwin CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); 1874262706Serwin cleanup: 1875262706Serwin if (node != NULL) 1876262706Serwin dns_db_detachnode(db, &node); 1877262706Serwin return (result); 1878262706Serwin} 1879262706Serwin 1880262706Serwinstatic isc_result_t 1881262706Serwincreate_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view, 1882262706Serwin const cfg_obj_t *zonelist, const char **empty_dbtype, 1883262706Serwin int empty_dbtypec, dns_zonestat_level_t statlevel) 1884262706Serwin{ 1885262706Serwin char namebuf[DNS_NAME_FORMATSIZE]; 1886262706Serwin const cfg_listelt_t *element; 1887262706Serwin const cfg_obj_t *obj; 1888262706Serwin const cfg_obj_t *zconfig; 1889262706Serwin const cfg_obj_t *zoptions; 1890262706Serwin const char *rbt_dbtype[4] = { "rbt" }; 1891262706Serwin const char *sep = ": view "; 1892262706Serwin const char *str; 1893262706Serwin const char *viewname = view->name; 1894262706Serwin dns_db_t *db = NULL; 1895262706Serwin dns_dbversion_t *version = NULL; 1896262706Serwin dns_fixedname_t cfixed; 1897262706Serwin dns_fixedname_t fixed; 1898262706Serwin dns_fixedname_t nsfixed; 1899262706Serwin dns_name_t *contact; 1900262706Serwin dns_name_t *ns; 1901262706Serwin dns_name_t *zname; 1902262706Serwin dns_zone_t *myzone = NULL; 1903262706Serwin int rbt_dbtypec = 1; 1904262706Serwin isc_result_t result; 1905262706Serwin dns_namereln_t namereln; 1906262706Serwin int order; 1907262706Serwin unsigned int nlabels; 1908262706Serwin 1909262706Serwin dns_fixedname_init(&fixed); 1910262706Serwin zname = dns_fixedname_name(&fixed); 1911262706Serwin dns_fixedname_init(&nsfixed); 1912262706Serwin ns = dns_fixedname_name(&nsfixed); 1913262706Serwin dns_fixedname_init(&cfixed); 1914262706Serwin contact = dns_fixedname_name(&cfixed); 1915262706Serwin 1916262706Serwin /* 1917262706Serwin * Look for forward "zones" beneath this empty zone and if so 1918262706Serwin * create a custom db for the empty zone. 1919262706Serwin */ 1920262706Serwin for (element = cfg_list_first(zonelist); 1921262706Serwin element != NULL; 1922262706Serwin element = cfg_list_next(element)) { 1923262706Serwin 1924262706Serwin zconfig = cfg_listelt_value(element); 1925262706Serwin str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 1926262706Serwin CHECK(dns_name_fromstring(zname, str, 0, NULL)); 1927262706Serwin namereln = dns_name_fullcompare(zname, name, &order, &nlabels); 1928262706Serwin if (namereln != dns_namereln_subdomain) 1929262706Serwin continue; 1930262706Serwin 1931262706Serwin zoptions = cfg_tuple_get(zconfig, "options"); 1932262706Serwin 1933262706Serwin obj = NULL; 1934262706Serwin (void)cfg_map_get(zoptions, "type", &obj); 1935262706Serwin INSIST(obj != NULL); 1936262706Serwin if (strcasecmp(cfg_obj_asstring(obj), "forward") == 0) { 1937262706Serwin obj = NULL; 1938262706Serwin (void)cfg_map_get(zoptions, "forward", &obj); 1939262706Serwin if (obj == NULL) 1940262706Serwin continue; 1941262706Serwin if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) 1942262706Serwin continue; 1943262706Serwin } 1944262706Serwin if (db == NULL) { 1945262706Serwin CHECK(dns_db_create(view->mctx, "rbt", name, 1946262706Serwin dns_dbtype_zone, view->rdclass, 1947262706Serwin 0, NULL, &db)); 1948262706Serwin CHECK(dns_db_newversion(db, &version)); 1949262706Serwin if (strcmp(empty_dbtype[2], "@") == 0) 1950262706Serwin dns_name_clone(name, ns); 1951262706Serwin else 1952262706Serwin CHECK(dns_name_fromstring(ns, empty_dbtype[2], 1953262706Serwin 0, NULL)); 1954262706Serwin CHECK(dns_name_fromstring(contact, empty_dbtype[3], 1955262706Serwin 0, NULL)); 1956262706Serwin CHECK(add_soa(db, version, name, ns, contact)); 1957262706Serwin CHECK(add_ns(db, version, name, ns)); 1958262706Serwin } 1959262706Serwin CHECK(add_ns(db, version, zname, dns_rootname)); 1960262706Serwin } 1961262706Serwin 1962262706Serwin /* 1963262706Serwin * Is the existing zone the ok to use? 1964262706Serwin */ 1965262706Serwin if (zone != NULL) { 1966262706Serwin unsigned int typec; 1967262706Serwin const char **dbargv; 1968262706Serwin 1969262706Serwin if (db != NULL) { 1970262706Serwin typec = rbt_dbtypec; 1971262706Serwin dbargv = rbt_dbtype; 1972262706Serwin } else { 1973262706Serwin typec = empty_dbtypec; 1974262706Serwin dbargv = empty_dbtype; 1975262706Serwin } 1976262706Serwin 1977262706Serwin result = check_dbtype(zone, typec, dbargv, view->mctx); 1978262706Serwin if (result != ISC_R_SUCCESS) 1979262706Serwin zone = NULL; 1980262706Serwin 1981262706Serwin if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master) 1982262706Serwin zone = NULL; 1983262706Serwin if (zone != NULL && dns_zone_getfile(zone) != NULL) 1984262706Serwin zone = NULL; 1985262706Serwin if (zone != NULL) { 1986262706Serwin dns_zone_getraw(zone, &myzone); 1987262706Serwin if (myzone != NULL) { 1988262706Serwin dns_zone_detach(&myzone); 1989262706Serwin zone = NULL; 1990262706Serwin } 1991262706Serwin } 1992262706Serwin } 1993262706Serwin 1994262706Serwin if (zone == NULL) { 1995262706Serwin CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &myzone)); 1996262706Serwin zone = myzone; 1997262706Serwin CHECK(dns_zone_setorigin(zone, name)); 1998262706Serwin CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1999262706Serwin if (db == NULL) 2000262706Serwin CHECK(dns_zone_setdbtype(zone, empty_dbtypec, 2001262706Serwin empty_dbtype)); 2002262706Serwin dns_zone_setclass(zone, view->rdclass); 2003262706Serwin dns_zone_settype(zone, dns_zone_master); 2004262706Serwin dns_zone_setstats(zone, ns_g_server->zonestats); 2005262706Serwin } 2006262706Serwin 2007262706Serwin dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, ISC_FALSE); 2008262706Serwin dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 2009262706Serwin dns_zone_setnotifytype(zone, dns_notifytype_no); 2010262706Serwin dns_zone_setdialup(zone, dns_dialuptype_no); 2011262706Serwin if (view->queryacl) 2012262706Serwin dns_zone_setqueryacl(zone, view->queryacl); 2013262706Serwin else 2014262706Serwin dns_zone_clearqueryacl(zone); 2015262706Serwin if (view->queryonacl) 2016262706Serwin dns_zone_setqueryonacl(zone, view->queryonacl); 2017262706Serwin else 2018262706Serwin dns_zone_clearqueryonacl(zone); 2019262706Serwin dns_zone_clearupdateacl(zone); 2020262706Serwin dns_zone_clearxfracl(zone); 2021262706Serwin 2022262706Serwin CHECK(setquerystats(zone, view->mctx, statlevel)); 2023262706Serwin if (db != NULL) { 2024262706Serwin dns_db_closeversion(db, &version, ISC_TRUE); 2025262706Serwin CHECK(dns_zone_replacedb(zone, db, ISC_FALSE)); 2026262706Serwin } 2027262706Serwin dns_zone_setview(zone, view); 2028262706Serwin CHECK(dns_view_addzone(view, zone)); 2029262706Serwin 2030262706Serwin if (!strcmp(viewname, "_default")) { 2031262706Serwin sep = ""; 2032262706Serwin viewname = ""; 2033262706Serwin } 2034262706Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 2035262706Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2036262706Serwin ISC_LOG_INFO, "automatic empty zone%s%s: %s", 2037262706Serwin sep, viewname, namebuf); 2038262706Serwin 2039262706Serwin cleanup: 2040262706Serwin if (myzone != NULL) 2041262706Serwin dns_zone_detach(&myzone); 2042262706Serwin if (version != NULL) 2043262706Serwin dns_db_closeversion(db, &version, ISC_FALSE); 2044262706Serwin if (db != NULL) 2045262706Serwin dns_db_detach(&db); 2046262706Serwin return (result); 2047262706Serwin} 2048262706Serwin 2049224092Sdougb/* 2050135446Strhodes * Configure 'view' according to 'vconfig', taking defaults from 'config' 2051135446Strhodes * where values are missing in 'vconfig'. 2052135446Strhodes * 2053135446Strhodes * When configuring the default view, 'vconfig' will be NULL and the 2054135446Strhodes * global defaults in 'config' used exclusively. 2055135446Strhodes */ 2056135446Strhodesstatic isc_result_t 2057225361Sdougbconfigure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 2058224092Sdougb ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys, 2059224092Sdougb isc_mem_t *mctx, cfg_aclconfctx_t *actx, 2060224092Sdougb isc_boolean_t need_hints) 2061135446Strhodes{ 2062165071Sdougb const cfg_obj_t *maps[4]; 2063165071Sdougb const cfg_obj_t *cfgmaps[3]; 2064224092Sdougb const cfg_obj_t *optionmaps[3]; 2065165071Sdougb const cfg_obj_t *options = NULL; 2066165071Sdougb const cfg_obj_t *voptions = NULL; 2067165071Sdougb const cfg_obj_t *forwardtype; 2068165071Sdougb const cfg_obj_t *forwarders; 2069165071Sdougb const cfg_obj_t *alternates; 2070165071Sdougb const cfg_obj_t *zonelist; 2071186462Sdougb const cfg_obj_t *dlz; 2072186462Sdougb unsigned int dlzargc; 2073186462Sdougb char **dlzargv; 2074165071Sdougb const cfg_obj_t *disabled; 2075165071Sdougb const cfg_obj_t *obj; 2076165071Sdougb const cfg_listelt_t *element; 2077135446Strhodes in_port_t port; 2078135446Strhodes dns_cache_t *cache = NULL; 2079135446Strhodes isc_result_t result; 2080224092Sdougb unsigned int cleaning_interval; 2081254897Serwin size_t max_cache_size; 2082254897Serwin size_t max_acache_size; 2083254897Serwin size_t max_adb_size; 2084135446Strhodes isc_uint32_t lame_ttl; 2085224092Sdougb dns_tsig_keyring_t *ring = NULL; 2086135446Strhodes dns_view_t *pview = NULL; /* Production view */ 2087225361Sdougb isc_mem_t *cmctx = NULL, *hmctx = NULL; 2088135446Strhodes dns_dispatch_t *dispatch4 = NULL; 2089135446Strhodes dns_dispatch_t *dispatch6 = NULL; 2090135446Strhodes isc_boolean_t reused_cache = ISC_FALSE; 2091224092Sdougb isc_boolean_t shared_cache = ISC_FALSE; 2092224092Sdougb int i = 0, j = 0, k = 0; 2093135446Strhodes const char *str; 2094224092Sdougb const char *cachename = NULL; 2095135446Strhodes dns_order_t *order = NULL; 2096135446Strhodes isc_uint32_t udpsize; 2097254897Serwin isc_uint32_t maxbits; 2098193149Sdougb unsigned int resopts = 0; 2099170222Sdougb dns_zone_t *zone = NULL; 2100170222Sdougb isc_uint32_t max_clients_per_query; 2101170222Sdougb isc_boolean_t empty_zones_enable; 2102170222Sdougb const cfg_obj_t *disablelist = NULL; 2103193149Sdougb isc_stats_t *resstats = NULL; 2104193149Sdougb dns_stats_t *resquerystats = NULL; 2105224092Sdougb isc_boolean_t auto_dlv = ISC_FALSE; 2106224092Sdougb isc_boolean_t auto_root = ISC_FALSE; 2107224092Sdougb ns_cache_t *nsc; 2108193149Sdougb isc_boolean_t zero_no_soattl; 2109224092Sdougb dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; 2110254897Serwin unsigned int query_timeout, ndisp; 2111225361Sdougb struct cfg_context *nzctx; 2112254402Serwin dns_rpz_zone_t *rpz; 2113135446Strhodes 2114135446Strhodes REQUIRE(DNS_VIEW_VALID(view)); 2115135446Strhodes 2116135446Strhodes if (config != NULL) 2117135446Strhodes (void)cfg_map_get(config, "options", &options); 2118135446Strhodes 2119224092Sdougb /* 2120224092Sdougb * maps: view options, options, defaults 2121224092Sdougb * cfgmaps: view options, config 2122224092Sdougb * optionmaps: view options, options 2123224092Sdougb */ 2124135446Strhodes if (vconfig != NULL) { 2125135446Strhodes voptions = cfg_tuple_get(vconfig, "options"); 2126135446Strhodes maps[i++] = voptions; 2127224092Sdougb optionmaps[j++] = voptions; 2128224092Sdougb cfgmaps[k++] = voptions; 2129135446Strhodes } 2130224092Sdougb if (options != NULL) { 2131135446Strhodes maps[i++] = options; 2132224092Sdougb optionmaps[j++] = options; 2133224092Sdougb } 2134224092Sdougb 2135135446Strhodes maps[i++] = ns_g_defaults; 2136135446Strhodes maps[i] = NULL; 2137224092Sdougb optionmaps[j] = NULL; 2138135446Strhodes if (config != NULL) 2139224092Sdougb cfgmaps[k++] = config; 2140224092Sdougb cfgmaps[k] = NULL; 2141135446Strhodes 2142135446Strhodes /* 2143135446Strhodes * Set the view's port number for outgoing queries. 2144135446Strhodes */ 2145135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 2146135446Strhodes dns_view_setdstport(view, port); 2147135446Strhodes 2148135446Strhodes /* 2149170222Sdougb * Create additional cache for this view and zones under the view 2150170222Sdougb * if explicitly enabled. 2151170222Sdougb * XXX950 default to on. 2152170222Sdougb */ 2153170222Sdougb obj = NULL; 2154170222Sdougb (void)ns_config_get(maps, "acache-enable", &obj); 2155170222Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) { 2156170222Sdougb cmctx = NULL; 2157170222Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 2158170222Sdougb CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr, 2159170222Sdougb ns_g_timermgr)); 2160193149Sdougb isc_mem_setname(cmctx, "acache", NULL); 2161170222Sdougb isc_mem_detach(&cmctx); 2162170222Sdougb } 2163170222Sdougb if (view->acache != NULL) { 2164170222Sdougb obj = NULL; 2165170222Sdougb result = ns_config_get(maps, "acache-cleaning-interval", &obj); 2166170222Sdougb INSIST(result == ISC_R_SUCCESS); 2167170222Sdougb dns_acache_setcleaninginterval(view->acache, 2168170222Sdougb cfg_obj_asuint32(obj) * 60); 2169170222Sdougb 2170170222Sdougb obj = NULL; 2171170222Sdougb result = ns_config_get(maps, "max-acache-size", &obj); 2172170222Sdougb INSIST(result == ISC_R_SUCCESS); 2173170222Sdougb if (cfg_obj_isstring(obj)) { 2174170222Sdougb str = cfg_obj_asstring(obj); 2175170222Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 2176170222Sdougb max_acache_size = ISC_UINT32_MAX; 2177170222Sdougb } else { 2178170222Sdougb isc_resourcevalue_t value; 2179170222Sdougb value = cfg_obj_asuint64(obj); 2180254897Serwin if (value > SIZE_MAX) { 2181254897Serwin cfg_obj_log(obj, ns_g_lctx, 2182254897Serwin ISC_LOG_WARNING, 2183170222Sdougb "'max-acache-size " 2184254897Serwin "%" ISC_PRINT_QUADFORMAT "u' " 2185254897Serwin "is too large for this " 2186254897Serwin "system; reducing to %lu", 2187254897Serwin value, (unsigned long)SIZE_MAX); 2188254897Serwin value = SIZE_MAX; 2189170222Sdougb } 2190254897Serwin max_acache_size = (size_t) value; 2191170222Sdougb } 2192170222Sdougb dns_acache_setcachesize(view->acache, max_acache_size); 2193170222Sdougb } 2194170222Sdougb 2195224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx, 2196216175Sdougb ns_g_mctx, &view->queryacl)); 2197216175Sdougb if (view->queryacl == NULL) { 2198224092Sdougb CHECK(configure_view_acl(NULL, ns_g_config, "allow-query", 2199224092Sdougb NULL, actx, ns_g_mctx, 2200224092Sdougb &view->queryacl)); 2201216175Sdougb } 2202216175Sdougb 2203170222Sdougb /* 2204254402Serwin * Make the list of response policy zone names for a view that 2205254402Serwin * is used for real lookups and so cares about hints. 2206254402Serwin */ 2207254402Serwin obj = NULL; 2208254402Serwin if (view->rdclass == dns_rdataclass_in && need_hints && 2209254402Serwin ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) { 2210254402Serwin const cfg_obj_t *rpz_obj; 2211254402Serwin isc_boolean_t recursive_only_def; 2212254402Serwin dns_ttl_t ttl_def; 2213254402Serwin 2214254402Serwin rpz_obj = cfg_tuple_get(obj, "recursive-only"); 2215254402Serwin if (!cfg_obj_isvoid(rpz_obj) && 2216254402Serwin !cfg_obj_asboolean(rpz_obj)) 2217254402Serwin recursive_only_def = ISC_FALSE; 2218254402Serwin else 2219254402Serwin recursive_only_def = ISC_TRUE; 2220254402Serwin 2221254402Serwin rpz_obj = cfg_tuple_get(obj, "break-dnssec"); 2222254402Serwin if (!cfg_obj_isvoid(rpz_obj) && 2223254402Serwin cfg_obj_asboolean(rpz_obj)) 2224254402Serwin view->rpz_break_dnssec = ISC_TRUE; 2225254402Serwin else 2226254402Serwin view->rpz_break_dnssec = ISC_FALSE; 2227254402Serwin 2228254402Serwin rpz_obj = cfg_tuple_get(obj, "max-policy-ttl"); 2229254402Serwin if (cfg_obj_isuint32(rpz_obj)) 2230254402Serwin ttl_def = cfg_obj_asuint32(rpz_obj); 2231254402Serwin else 2232254402Serwin ttl_def = DNS_RPZ_MAX_TTL_DEFAULT; 2233254402Serwin 2234254402Serwin rpz_obj = cfg_tuple_get(obj, "min-ns-dots"); 2235254402Serwin if (cfg_obj_isuint32(rpz_obj)) 2236254402Serwin view->rpz_min_ns_labels = cfg_obj_asuint32(rpz_obj) + 1; 2237254402Serwin else 2238254402Serwin view->rpz_min_ns_labels = 2; 2239254402Serwin 2240254402Serwin element = cfg_list_first(cfg_tuple_get(obj, "zone list")); 2241254402Serwin while (element != NULL) { 2242254402Serwin result = configure_rpz(view, element, 2243254402Serwin recursive_only_def, ttl_def); 2244254402Serwin if (result != ISC_R_SUCCESS) 2245254402Serwin goto cleanup; 2246254402Serwin element = cfg_list_next(element); 2247254402Serwin } 2248254402Serwin } 2249254402Serwin 2250254402Serwin /* 2251135446Strhodes * Configure the zones. 2252135446Strhodes */ 2253135446Strhodes zonelist = NULL; 2254135446Strhodes if (voptions != NULL) 2255135446Strhodes (void)cfg_map_get(voptions, "zone", &zonelist); 2256135446Strhodes else 2257135446Strhodes (void)cfg_map_get(config, "zone", &zonelist); 2258225361Sdougb 2259225361Sdougb /* 2260225361Sdougb * Load zone configuration 2261225361Sdougb */ 2262135446Strhodes for (element = cfg_list_first(zonelist); 2263135446Strhodes element != NULL; 2264135446Strhodes element = cfg_list_next(element)) 2265135446Strhodes { 2266165071Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 2267135446Strhodes CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 2268224092Sdougb actx, ISC_FALSE)); 2269135446Strhodes } 2270135446Strhodes 2271254402Serwin for (rpz = ISC_LIST_HEAD(view->rpz_zones); 2272254402Serwin rpz != NULL; 2273254402Serwin rpz = ISC_LIST_NEXT(rpz, link)) 2274254402Serwin { 2275254402Serwin if (!rpz->defined) { 2276254402Serwin char namebuf[DNS_NAME_FORMATSIZE]; 2277254402Serwin 2278254402Serwin dns_name_format(&rpz->origin, namebuf, sizeof(namebuf)); 2279254402Serwin cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, 2280254402Serwin "'%s' is not a master or slave zone", 2281254402Serwin namebuf); 2282254402Serwin result = ISC_R_NOTFOUND; 2283254402Serwin goto cleanup; 2284254402Serwin } 2285254402Serwin } 2286254402Serwin 2287224092Sdougb /* 2288224092Sdougb * If we're allowing added zones, then load zone configuration 2289224092Sdougb * from the newzone file for zones that were added during previous 2290224092Sdougb * runs. 2291224092Sdougb */ 2292225361Sdougb nzctx = view->new_zone_config; 2293225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) { 2294224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2295224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 2296224092Sdougb "loading additional zones for view '%s'", 2297224092Sdougb view->name); 2298224092Sdougb 2299225361Sdougb zonelist = NULL; 2300225361Sdougb cfg_map_get(nzctx->nzconfig, "zone", &zonelist); 2301225361Sdougb 2302225361Sdougb for (element = cfg_list_first(zonelist); 2303225361Sdougb element != NULL; 2304225361Sdougb element = cfg_list_next(element)) 2305225361Sdougb { 2306225361Sdougb const cfg_obj_t *zconfig = cfg_listelt_value(element); 2307225361Sdougb CHECK(configure_zone(config, zconfig, vconfig, 2308225361Sdougb mctx, view, actx, 2309225361Sdougb ISC_TRUE)); 2310224092Sdougb } 2311224092Sdougb } 2312224092Sdougb 2313135446Strhodes /* 2314170222Sdougb * Create Dynamically Loadable Zone driver. 2315170222Sdougb */ 2316170222Sdougb dlz = NULL; 2317170222Sdougb if (voptions != NULL) 2318170222Sdougb (void)cfg_map_get(voptions, "dlz", &dlz); 2319170222Sdougb else 2320170222Sdougb (void)cfg_map_get(config, "dlz", &dlz); 2321170222Sdougb 2322170222Sdougb obj = NULL; 2323170222Sdougb if (dlz != NULL) { 2324170222Sdougb (void)cfg_map_get(cfg_tuple_get(dlz, "options"), 2325170222Sdougb "database", &obj); 2326170222Sdougb if (obj != NULL) { 2327170222Sdougb char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); 2328170222Sdougb if (s == NULL) { 2329170222Sdougb result = ISC_R_NOMEMORY; 2330170222Sdougb goto cleanup; 2331170222Sdougb } 2332186462Sdougb 2333170222Sdougb result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); 2334170222Sdougb if (result != ISC_R_SUCCESS) { 2335170222Sdougb isc_mem_free(mctx, s); 2336170222Sdougb goto cleanup; 2337170222Sdougb } 2338170222Sdougb 2339170222Sdougb obj = cfg_tuple_get(dlz, "name"); 2340170222Sdougb result = dns_dlzcreate(mctx, cfg_obj_asstring(obj), 2341170222Sdougb dlzargv[0], dlzargc, dlzargv, 2342170222Sdougb &view->dlzdatabase); 2343170222Sdougb isc_mem_free(mctx, s); 2344170222Sdougb isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv)); 2345170222Sdougb if (result != ISC_R_SUCCESS) 2346170222Sdougb goto cleanup; 2347224092Sdougb 2348224092Sdougb /* 2349224092Sdougb * If the dlz backend supports configuration, 2350224092Sdougb * then call its configure method now. 2351224092Sdougb */ 2352224092Sdougb result = dns_dlzconfigure(view, dlzconfigure_callback); 2353224092Sdougb if (result != ISC_R_SUCCESS) 2354224092Sdougb goto cleanup; 2355170222Sdougb } 2356170222Sdougb } 2357170222Sdougb 2358170222Sdougb /* 2359193149Sdougb * Obtain configuration parameters that affect the decision of whether 2360193149Sdougb * we can reuse/share an existing cache. 2361193149Sdougb */ 2362224092Sdougb obj = NULL; 2363224092Sdougb result = ns_config_get(maps, "cleaning-interval", &obj); 2364224092Sdougb INSIST(result == ISC_R_SUCCESS); 2365224092Sdougb cleaning_interval = cfg_obj_asuint32(obj) * 60; 2366224092Sdougb 2367224092Sdougb obj = NULL; 2368224092Sdougb result = ns_config_get(maps, "max-cache-size", &obj); 2369224092Sdougb INSIST(result == ISC_R_SUCCESS); 2370224092Sdougb if (cfg_obj_isstring(obj)) { 2371224092Sdougb str = cfg_obj_asstring(obj); 2372224092Sdougb INSIST(strcasecmp(str, "unlimited") == 0); 2373224092Sdougb max_cache_size = ISC_UINT32_MAX; 2374224092Sdougb } else { 2375224092Sdougb isc_resourcevalue_t value; 2376224092Sdougb value = cfg_obj_asuint64(obj); 2377254897Serwin if (value > SIZE_MAX) { 2378254897Serwin cfg_obj_log(obj, ns_g_lctx, 2379254897Serwin ISC_LOG_WARNING, 2380224092Sdougb "'max-cache-size " 2381254897Serwin "%" ISC_PRINT_QUADFORMAT "u' " 2382254897Serwin "is too large for this " 2383254897Serwin "system; reducing to %lu", 2384254897Serwin value, (unsigned long)SIZE_MAX); 2385254897Serwin value = SIZE_MAX; 2386224092Sdougb } 2387254897Serwin max_cache_size = (size_t) value; 2388224092Sdougb } 2389224092Sdougb 2390193149Sdougb /* Check-names. */ 2391193149Sdougb obj = NULL; 2392193149Sdougb result = ns_checknames_get(maps, "response", &obj); 2393193149Sdougb INSIST(result == ISC_R_SUCCESS); 2394193149Sdougb 2395193149Sdougb str = cfg_obj_asstring(obj); 2396193149Sdougb if (strcasecmp(str, "fail") == 0) { 2397193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES | 2398193149Sdougb DNS_RESOLVER_CHECKNAMESFAIL; 2399193149Sdougb view->checknames = ISC_TRUE; 2400193149Sdougb } else if (strcasecmp(str, "warn") == 0) { 2401193149Sdougb resopts |= DNS_RESOLVER_CHECKNAMES; 2402193149Sdougb view->checknames = ISC_FALSE; 2403193149Sdougb } else if (strcasecmp(str, "ignore") == 0) { 2404193149Sdougb view->checknames = ISC_FALSE; 2405193149Sdougb } else 2406193149Sdougb INSIST(0); 2407193149Sdougb 2408193149Sdougb obj = NULL; 2409193149Sdougb result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj); 2410193149Sdougb INSIST(result == ISC_R_SUCCESS); 2411193149Sdougb zero_no_soattl = cfg_obj_asboolean(obj); 2412193149Sdougb 2413193149Sdougb obj = NULL; 2414224092Sdougb result = ns_config_get(maps, "dns64", &obj); 2415224092Sdougb if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") && 2416224092Sdougb strcmp(view->name, "_meta")) { 2417224092Sdougb const cfg_listelt_t *element; 2418224092Sdougb isc_netaddr_t na, suffix, *sp; 2419224092Sdougb unsigned int prefixlen; 2420224092Sdougb const char *server, *contact; 2421224092Sdougb const cfg_obj_t *myobj; 2422224092Sdougb 2423224092Sdougb myobj = NULL; 2424224092Sdougb result = ns_config_get(maps, "dns64-server", &myobj); 2425224092Sdougb if (result == ISC_R_SUCCESS) 2426224092Sdougb server = cfg_obj_asstring(myobj); 2427224092Sdougb else 2428224092Sdougb server = NULL; 2429224092Sdougb 2430224092Sdougb myobj = NULL; 2431224092Sdougb result = ns_config_get(maps, "dns64-contact", &myobj); 2432224092Sdougb if (result == ISC_R_SUCCESS) 2433224092Sdougb contact = cfg_obj_asstring(myobj); 2434224092Sdougb else 2435224092Sdougb contact = NULL; 2436224092Sdougb 2437224092Sdougb for (element = cfg_list_first(obj); 2438224092Sdougb element != NULL; 2439224092Sdougb element = cfg_list_next(element)) 2440224092Sdougb { 2441224092Sdougb const cfg_obj_t *map = cfg_listelt_value(element); 2442224092Sdougb dns_dns64_t *dns64 = NULL; 2443224092Sdougb unsigned int dns64options = 0; 2444224092Sdougb 2445224092Sdougb cfg_obj_asnetprefix(cfg_map_getname(map), &na, 2446224092Sdougb &prefixlen); 2447224092Sdougb 2448224092Sdougb obj = NULL; 2449224092Sdougb (void)cfg_map_get(map, "suffix", &obj); 2450224092Sdougb if (obj != NULL) { 2451224092Sdougb sp = &suffix; 2452224092Sdougb isc_netaddr_fromsockaddr(sp, 2453224092Sdougb cfg_obj_assockaddr(obj)); 2454224092Sdougb } else 2455224092Sdougb sp = NULL; 2456224092Sdougb 2457224092Sdougb clients = mapped = excluded = NULL; 2458224092Sdougb obj = NULL; 2459224092Sdougb (void)cfg_map_get(map, "clients", &obj); 2460224092Sdougb if (obj != NULL) { 2461224092Sdougb result = cfg_acl_fromconfig(obj, config, 2462224092Sdougb ns_g_lctx, actx, 2463224092Sdougb mctx, 0, &clients); 2464224092Sdougb if (result != ISC_R_SUCCESS) 2465224092Sdougb goto cleanup; 2466224092Sdougb } 2467224092Sdougb obj = NULL; 2468224092Sdougb (void)cfg_map_get(map, "mapped", &obj); 2469224092Sdougb if (obj != NULL) { 2470224092Sdougb result = cfg_acl_fromconfig(obj, config, 2471224092Sdougb ns_g_lctx, actx, 2472224092Sdougb mctx, 0, &mapped); 2473224092Sdougb if (result != ISC_R_SUCCESS) 2474224092Sdougb goto cleanup; 2475224092Sdougb } 2476224092Sdougb obj = NULL; 2477224092Sdougb (void)cfg_map_get(map, "exclude", &obj); 2478224092Sdougb if (obj != NULL) { 2479224092Sdougb result = cfg_acl_fromconfig(obj, config, 2480224092Sdougb ns_g_lctx, actx, 2481224092Sdougb mctx, 0, &excluded); 2482224092Sdougb if (result != ISC_R_SUCCESS) 2483224092Sdougb goto cleanup; 2484224092Sdougb } 2485224092Sdougb 2486224092Sdougb obj = NULL; 2487224092Sdougb (void)cfg_map_get(map, "recursive-only", &obj); 2488224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 2489224092Sdougb dns64options |= DNS_DNS64_RECURSIVE_ONLY; 2490224092Sdougb 2491224092Sdougb obj = NULL; 2492224092Sdougb (void)cfg_map_get(map, "break-dnssec", &obj); 2493224092Sdougb if (obj != NULL && cfg_obj_asboolean(obj)) 2494224092Sdougb dns64options |= DNS_DNS64_BREAK_DNSSEC; 2495224092Sdougb 2496224092Sdougb result = dns_dns64_create(mctx, &na, prefixlen, sp, 2497224092Sdougb clients, mapped, excluded, 2498224092Sdougb dns64options, &dns64); 2499224092Sdougb if (result != ISC_R_SUCCESS) 2500224092Sdougb goto cleanup; 2501224092Sdougb dns_dns64_append(&view->dns64, dns64); 2502224092Sdougb view->dns64cnt++; 2503224092Sdougb result = dns64_reverse(view, mctx, &na, prefixlen, 2504224092Sdougb server, contact); 2505224092Sdougb if (result != ISC_R_SUCCESS) 2506224092Sdougb goto cleanup; 2507224092Sdougb if (clients != NULL) 2508224092Sdougb dns_acl_detach(&clients); 2509224092Sdougb if (mapped != NULL) 2510224092Sdougb dns_acl_detach(&mapped); 2511224092Sdougb if (excluded != NULL) 2512224092Sdougb dns_acl_detach(&excluded); 2513224092Sdougb } 2514224092Sdougb } 2515224092Sdougb 2516224092Sdougb obj = NULL; 2517193149Sdougb result = ns_config_get(maps, "dnssec-accept-expired", &obj); 2518193149Sdougb INSIST(result == ISC_R_SUCCESS); 2519193149Sdougb view->acceptexpired = cfg_obj_asboolean(obj); 2520193149Sdougb 2521193149Sdougb obj = NULL; 2522193149Sdougb result = ns_config_get(maps, "dnssec-validation", &obj); 2523193149Sdougb INSIST(result == ISC_R_SUCCESS); 2524224092Sdougb if (cfg_obj_isboolean(obj)) { 2525224092Sdougb view->enablevalidation = cfg_obj_asboolean(obj); 2526224092Sdougb } else { 2527224092Sdougb /* If dnssec-validation is not boolean, it must be "auto" */ 2528224092Sdougb view->enablevalidation = ISC_TRUE; 2529224092Sdougb auto_root = ISC_TRUE; 2530224092Sdougb } 2531193149Sdougb 2532193149Sdougb obj = NULL; 2533193149Sdougb result = ns_config_get(maps, "max-cache-ttl", &obj); 2534193149Sdougb INSIST(result == ISC_R_SUCCESS); 2535193149Sdougb view->maxcachettl = cfg_obj_asuint32(obj); 2536193149Sdougb 2537193149Sdougb obj = NULL; 2538193149Sdougb result = ns_config_get(maps, "max-ncache-ttl", &obj); 2539193149Sdougb INSIST(result == ISC_R_SUCCESS); 2540193149Sdougb view->maxncachettl = cfg_obj_asuint32(obj); 2541193149Sdougb if (view->maxncachettl > 7 * 24 * 3600) 2542193149Sdougb view->maxncachettl = 7 * 24 * 3600; 2543193149Sdougb 2544193149Sdougb /* 2545224092Sdougb * Configure the view's cache. 2546135446Strhodes * 2547224092Sdougb * First, check to see if there are any attach-cache options. If yes, 2548224092Sdougb * attempt to lookup an existing cache at attach it to the view. If 2549224092Sdougb * there is not one, then try to reuse an existing cache if possible; 2550224092Sdougb * otherwise create a new cache. 2551224092Sdougb * 2552224092Sdougb * Note that the ADB is not preserved or shared in either case. 2553224092Sdougb * 2554224092Sdougb * When a matching view is found, the associated statistics are also 2555224092Sdougb * retrieved and reused. 2556224092Sdougb * 2557224092Sdougb * XXX Determining when it is safe to reuse or share a cache is tricky. 2558193149Sdougb * When the view's configuration changes, the cached data may become 2559193149Sdougb * invalid because it reflects our old view of the world. We check 2560224092Sdougb * some of the configuration parameters that could invalidate the cache 2561224092Sdougb * or otherwise make it unsharable, but there are other configuration 2562224092Sdougb * options that should be checked. For example, if a view uses a 2563224092Sdougb * forwarder, changes in the forwarder configuration may invalidate 2564224092Sdougb * the cache. At the moment, it's the administrator's responsibility to 2565224092Sdougb * ensure these configuration options don't invalidate reusing/sharing. 2566135446Strhodes */ 2567224092Sdougb obj = NULL; 2568224092Sdougb result = ns_config_get(maps, "attach-cache", &obj); 2569224092Sdougb if (result == ISC_R_SUCCESS) 2570224092Sdougb cachename = cfg_obj_asstring(obj); 2571224092Sdougb else 2572224092Sdougb cachename = view->name; 2573224092Sdougb cache = NULL; 2574224092Sdougb nsc = cachelist_find(cachelist, cachename); 2575224092Sdougb if (nsc != NULL) { 2576224092Sdougb if (!cache_sharable(nsc->primaryview, view, zero_no_soattl, 2577224092Sdougb cleaning_interval, max_cache_size)) { 2578193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2579224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 2580224092Sdougb "views %s and %s can't share the cache " 2581193149Sdougb "due to configuration parameter mismatch", 2582224092Sdougb nsc->primaryview->name, view->name); 2583224092Sdougb result = ISC_R_FAILURE; 2584224092Sdougb goto cleanup; 2585193149Sdougb } 2586224092Sdougb dns_cache_attach(nsc->cache, &cache); 2587224092Sdougb shared_cache = ISC_TRUE; 2588224092Sdougb } else { 2589224092Sdougb if (strcmp(cachename, view->name) == 0) { 2590224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 2591224092Sdougb cachename, view->rdclass, 2592224092Sdougb &pview); 2593224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2594224092Sdougb goto cleanup; 2595224092Sdougb if (pview != NULL) { 2596224092Sdougb if (!cache_reusable(pview, view, 2597224092Sdougb zero_no_soattl)) { 2598224092Sdougb isc_log_write(ns_g_lctx, 2599224092Sdougb NS_LOGCATEGORY_GENERAL, 2600224092Sdougb NS_LOGMODULE_SERVER, 2601224092Sdougb ISC_LOG_DEBUG(1), 2602224092Sdougb "cache cannot be reused " 2603224092Sdougb "for view %s due to " 2604224092Sdougb "configuration parameter " 2605224092Sdougb "mismatch", view->name); 2606224092Sdougb } else { 2607224092Sdougb INSIST(pview->cache != NULL); 2608224092Sdougb isc_log_write(ns_g_lctx, 2609224092Sdougb NS_LOGCATEGORY_GENERAL, 2610224092Sdougb NS_LOGMODULE_SERVER, 2611224092Sdougb ISC_LOG_DEBUG(3), 2612224092Sdougb "reusing existing cache"); 2613224092Sdougb reused_cache = ISC_TRUE; 2614224092Sdougb dns_cache_attach(pview->cache, &cache); 2615224092Sdougb } 2616224092Sdougb dns_view_getresstats(pview, &resstats); 2617224092Sdougb dns_view_getresquerystats(pview, 2618224092Sdougb &resquerystats); 2619224092Sdougb dns_view_detach(&pview); 2620224092Sdougb } 2621224092Sdougb } 2622224092Sdougb if (cache == NULL) { 2623224092Sdougb /* 2624224092Sdougb * Create a cache with the desired name. This normally 2625224092Sdougb * equals the view name, but may also be a forward 2626224092Sdougb * reference to a view that share the cache with this 2627224092Sdougb * view but is not yet configured. If it is not the 2628224092Sdougb * view name but not a forward reference either, then it 2629224092Sdougb * is simply a named cache that is not shared. 2630225361Sdougb * 2631225361Sdougb * We use two separate memory contexts for the 2632225361Sdougb * cache, for the main cache memory and the heap 2633225361Sdougb * memory. 2634224092Sdougb */ 2635224092Sdougb CHECK(isc_mem_create(0, 0, &cmctx)); 2636224092Sdougb isc_mem_setname(cmctx, "cache", NULL); 2637225361Sdougb CHECK(isc_mem_create(0, 0, &hmctx)); 2638225361Sdougb isc_mem_setname(hmctx, "cache_heap", NULL); 2639225361Sdougb CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr, 2640224092Sdougb ns_g_timermgr, view->rdclass, 2641224092Sdougb cachename, "rbt", 0, NULL, 2642224092Sdougb &cache)); 2643225361Sdougb isc_mem_detach(&cmctx); 2644225361Sdougb isc_mem_detach(&hmctx); 2645224092Sdougb } 2646224092Sdougb nsc = isc_mem_get(mctx, sizeof(*nsc)); 2647224092Sdougb if (nsc == NULL) { 2648224092Sdougb result = ISC_R_NOMEMORY; 2649224092Sdougb goto cleanup; 2650224092Sdougb } 2651224092Sdougb nsc->cache = NULL; 2652224092Sdougb dns_cache_attach(cache, &nsc->cache); 2653224092Sdougb nsc->primaryview = view; 2654224092Sdougb nsc->needflush = ISC_FALSE; 2655224092Sdougb nsc->adbsizeadjusted = ISC_FALSE; 2656224092Sdougb ISC_LINK_INIT(nsc, link); 2657224092Sdougb ISC_LIST_APPEND(*cachelist, nsc, link); 2658193149Sdougb } 2659224092Sdougb dns_view_setcache2(view, cache, shared_cache); 2660135446Strhodes 2661135446Strhodes /* 2662135446Strhodes * cache-file cannot be inherited if views are present, but this 2663135446Strhodes * should be caught by the configuration checking stage. 2664135446Strhodes */ 2665135446Strhodes obj = NULL; 2666135446Strhodes result = ns_config_get(maps, "cache-file", &obj); 2667135446Strhodes if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 2668135446Strhodes CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 2669224092Sdougb if (!reused_cache && !shared_cache) 2670135446Strhodes CHECK(dns_cache_load(cache)); 2671135446Strhodes } 2672135446Strhodes 2673224092Sdougb dns_cache_setcleaninginterval(cache, cleaning_interval); 2674135446Strhodes dns_cache_setcachesize(cache, max_cache_size); 2675135446Strhodes 2676135446Strhodes dns_cache_detach(&cache); 2677135446Strhodes 2678135446Strhodes /* 2679135446Strhodes * Resolver. 2680135446Strhodes * 2681135446Strhodes * XXXRTH Hardwired number of tasks. 2682135446Strhodes */ 2683186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, 2684186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2685186462Sdougb == NULL))); 2686186462Sdougb CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, 2687186462Sdougb ISC_TF(ISC_LIST_PREV(view, link) 2688186462Sdougb == NULL))); 2689135446Strhodes if (dispatch4 == NULL && dispatch6 == NULL) { 2690135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 2691135446Strhodes "unable to obtain neither an IPv4 nor" 2692135446Strhodes " an IPv6 dispatch"); 2693135446Strhodes result = ISC_R_UNEXPECTED; 2694135446Strhodes goto cleanup; 2695135446Strhodes } 2696254897Serwin 2697254897Serwin ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH); 2698254897Serwin CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, ndisp, 2699135446Strhodes ns_g_socketmgr, ns_g_timermgr, 2700193149Sdougb resopts, ns_g_dispatchmgr, 2701135446Strhodes dispatch4, dispatch6)); 2702135446Strhodes 2703193149Sdougb if (resstats == NULL) { 2704193149Sdougb CHECK(isc_stats_create(mctx, &resstats, 2705193149Sdougb dns_resstatscounter_max)); 2706193149Sdougb } 2707193149Sdougb dns_view_setresstats(view, resstats); 2708193149Sdougb if (resquerystats == NULL) 2709193149Sdougb CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); 2710193149Sdougb dns_view_setresquerystats(view, resquerystats); 2711193149Sdougb 2712135446Strhodes /* 2713224092Sdougb * Set the ADB cache size to 1/8th of the max-cache-size or 2714224092Sdougb * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. 2715135446Strhodes */ 2716135446Strhodes max_adb_size = 0; 2717254402Serwin if (max_cache_size != 0U) { 2718135446Strhodes max_adb_size = max_cache_size / 8; 2719254402Serwin if (max_adb_size == 0U) 2720135446Strhodes max_adb_size = 1; /* Force minimum. */ 2721224092Sdougb if (view != nsc->primaryview && 2722224092Sdougb max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) { 2723224092Sdougb max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE; 2724224092Sdougb if (!nsc->adbsizeadjusted) { 2725224092Sdougb dns_adb_setadbsize(nsc->primaryview->adb, 2726224092Sdougb MAX_ADB_SIZE_FOR_CACHESHARE); 2727224092Sdougb nsc->adbsizeadjusted = ISC_TRUE; 2728224092Sdougb } 2729224092Sdougb } 2730135446Strhodes } 2731135446Strhodes dns_adb_setadbsize(view->adb, max_adb_size); 2732135446Strhodes 2733135446Strhodes /* 2734135446Strhodes * Set resolver's lame-ttl. 2735135446Strhodes */ 2736135446Strhodes obj = NULL; 2737135446Strhodes result = ns_config_get(maps, "lame-ttl", &obj); 2738135446Strhodes INSIST(result == ISC_R_SUCCESS); 2739135446Strhodes lame_ttl = cfg_obj_asuint32(obj); 2740135446Strhodes if (lame_ttl > 1800) 2741135446Strhodes lame_ttl = 1800; 2742135446Strhodes dns_resolver_setlamettl(view->resolver, lame_ttl); 2743170222Sdougb 2744135446Strhodes /* 2745224092Sdougb * Set the resolver's query timeout. 2746224092Sdougb */ 2747224092Sdougb obj = NULL; 2748224092Sdougb result = ns_config_get(maps, "resolver-query-timeout", &obj); 2749224092Sdougb INSIST(result == ISC_R_SUCCESS); 2750224092Sdougb query_timeout = cfg_obj_asuint32(obj); 2751224092Sdougb dns_resolver_settimeout(view->resolver, query_timeout); 2752224092Sdougb 2753224092Sdougb /* Specify whether to use 0-TTL for negative response for SOA query */ 2754224092Sdougb dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl); 2755224092Sdougb 2756224092Sdougb /* 2757135446Strhodes * Set the resolver's EDNS UDP size. 2758135446Strhodes */ 2759135446Strhodes obj = NULL; 2760135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 2761135446Strhodes INSIST(result == ISC_R_SUCCESS); 2762135446Strhodes udpsize = cfg_obj_asuint32(obj); 2763135446Strhodes if (udpsize < 512) 2764135446Strhodes udpsize = 512; 2765135446Strhodes if (udpsize > 4096) 2766135446Strhodes udpsize = 4096; 2767135446Strhodes dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 2768186462Sdougb 2769135446Strhodes /* 2770170222Sdougb * Set the maximum UDP response size. 2771170222Sdougb */ 2772170222Sdougb obj = NULL; 2773170222Sdougb result = ns_config_get(maps, "max-udp-size", &obj); 2774170222Sdougb INSIST(result == ISC_R_SUCCESS); 2775170222Sdougb udpsize = cfg_obj_asuint32(obj); 2776170222Sdougb if (udpsize < 512) 2777170222Sdougb udpsize = 512; 2778170222Sdougb if (udpsize > 4096) 2779170222Sdougb udpsize = 4096; 2780170222Sdougb view->maxudp = udpsize; 2781170222Sdougb 2782170222Sdougb /* 2783254897Serwin * Set the maximum rsa exponent bits. 2784254897Serwin */ 2785254897Serwin obj = NULL; 2786254897Serwin result = ns_config_get(maps, "max-rsa-exponent-size", &obj); 2787254897Serwin INSIST(result == ISC_R_SUCCESS); 2788254897Serwin maxbits = cfg_obj_asuint32(obj); 2789254897Serwin if (maxbits != 0 && maxbits < 35) 2790254897Serwin maxbits = 35; 2791254897Serwin if (maxbits > 4096) 2792254897Serwin maxbits = 4096; 2793254897Serwin view->maxbits = maxbits; 2794254897Serwin 2795254897Serwin /* 2796135446Strhodes * Set supported DNSSEC algorithms. 2797135446Strhodes */ 2798135446Strhodes dns_resolver_reset_algorithms(view->resolver); 2799135446Strhodes disabled = NULL; 2800135446Strhodes (void)ns_config_get(maps, "disable-algorithms", &disabled); 2801135446Strhodes if (disabled != NULL) { 2802135446Strhodes for (element = cfg_list_first(disabled); 2803135446Strhodes element != NULL; 2804135446Strhodes element = cfg_list_next(element)) 2805135446Strhodes CHECK(disable_algorithms(cfg_listelt_value(element), 2806135446Strhodes view->resolver)); 2807135446Strhodes } 2808135446Strhodes 2809135446Strhodes /* 2810135446Strhodes * A global or view "forwarders" option, if present, 2811135446Strhodes * creates an entry for "." in the forwarding table. 2812135446Strhodes */ 2813135446Strhodes forwardtype = NULL; 2814135446Strhodes forwarders = NULL; 2815135446Strhodes (void)ns_config_get(maps, "forward", &forwardtype); 2816135446Strhodes (void)ns_config_get(maps, "forwarders", &forwarders); 2817135446Strhodes if (forwarders != NULL) 2818186462Sdougb CHECK(configure_forward(config, view, dns_rootname, 2819135446Strhodes forwarders, forwardtype)); 2820135446Strhodes 2821135446Strhodes /* 2822135446Strhodes * Dual Stack Servers. 2823135446Strhodes */ 2824135446Strhodes alternates = NULL; 2825135446Strhodes (void)ns_config_get(maps, "dual-stack-servers", &alternates); 2826135446Strhodes if (alternates != NULL) 2827135446Strhodes CHECK(configure_alternates(config, view, alternates)); 2828135446Strhodes 2829135446Strhodes /* 2830135446Strhodes * We have default hints for class IN if we need them. 2831135446Strhodes */ 2832135446Strhodes if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 2833135446Strhodes dns_view_sethints(view, ns_g_server->in_roothints); 2834135446Strhodes 2835135446Strhodes /* 2836135446Strhodes * If we still have no hints, this is a non-IN view with no 2837135446Strhodes * "hints zone" configured. Issue a warning, except if this 2838186462Sdougb * is a root server. Root servers never need to consult 2839135446Strhodes * their hints, so it's no point requiring users to configure 2840135446Strhodes * them. 2841135446Strhodes */ 2842135446Strhodes if (view->hints == NULL) { 2843135446Strhodes dns_zone_t *rootzone = NULL; 2844135446Strhodes (void)dns_view_findzone(view, dns_rootname, &rootzone); 2845135446Strhodes if (rootzone != NULL) { 2846135446Strhodes dns_zone_detach(&rootzone); 2847135446Strhodes need_hints = ISC_FALSE; 2848135446Strhodes } 2849135446Strhodes if (need_hints) 2850135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2851135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 2852135446Strhodes "no root hints for view '%s'", 2853135446Strhodes view->name); 2854135446Strhodes } 2855135446Strhodes 2856135446Strhodes /* 2857135446Strhodes * Configure the view's TSIG keys. 2858135446Strhodes */ 2859135446Strhodes CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 2860224092Sdougb if (ns_g_server->sessionkey != NULL) { 2861224092Sdougb CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname, 2862224092Sdougb ns_g_server->sessionkey)); 2863224092Sdougb } 2864135446Strhodes dns_view_setkeyring(view, ring); 2865224092Sdougb dns_tsigkeyring_detach(&ring); 2866135446Strhodes 2867135446Strhodes /* 2868224092Sdougb * See if we can re-use a dynamic key ring. 2869224092Sdougb */ 2870224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, view->name, 2871224092Sdougb view->rdclass, &pview); 2872224092Sdougb if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 2873224092Sdougb goto cleanup; 2874224092Sdougb if (pview != NULL) { 2875224092Sdougb dns_view_getdynamickeyring(pview, &ring); 2876224092Sdougb if (ring != NULL) 2877224092Sdougb dns_view_setdynamickeyring(view, ring); 2878224092Sdougb dns_tsigkeyring_detach(&ring); 2879224092Sdougb dns_view_detach(&pview); 2880224092Sdougb } else 2881224092Sdougb dns_view_restorekeyring(view); 2882224092Sdougb 2883224092Sdougb /* 2884135446Strhodes * Configure the view's peer list. 2885135446Strhodes */ 2886135446Strhodes { 2887165071Sdougb const cfg_obj_t *peers = NULL; 2888165071Sdougb const cfg_listelt_t *element; 2889135446Strhodes dns_peerlist_t *newpeers = NULL; 2890135446Strhodes 2891135446Strhodes (void)ns_config_get(cfgmaps, "server", &peers); 2892135446Strhodes CHECK(dns_peerlist_new(mctx, &newpeers)); 2893135446Strhodes for (element = cfg_list_first(peers); 2894135446Strhodes element != NULL; 2895135446Strhodes element = cfg_list_next(element)) 2896135446Strhodes { 2897165071Sdougb const cfg_obj_t *cpeer = cfg_listelt_value(element); 2898135446Strhodes dns_peer_t *peer; 2899135446Strhodes 2900135446Strhodes CHECK(configure_peer(cpeer, mctx, &peer)); 2901135446Strhodes dns_peerlist_addpeer(newpeers, peer); 2902135446Strhodes dns_peer_detach(&peer); 2903135446Strhodes } 2904135446Strhodes dns_peerlist_detach(&view->peers); 2905135446Strhodes view->peers = newpeers; /* Transfer ownership. */ 2906135446Strhodes } 2907135446Strhodes 2908135446Strhodes /* 2909135446Strhodes * Configure the views rrset-order. 2910135446Strhodes */ 2911135446Strhodes { 2912165071Sdougb const cfg_obj_t *rrsetorder = NULL; 2913165071Sdougb const cfg_listelt_t *element; 2914135446Strhodes 2915135446Strhodes (void)ns_config_get(maps, "rrset-order", &rrsetorder); 2916135446Strhodes CHECK(dns_order_create(mctx, &order)); 2917135446Strhodes for (element = cfg_list_first(rrsetorder); 2918135446Strhodes element != NULL; 2919135446Strhodes element = cfg_list_next(element)) 2920135446Strhodes { 2921165071Sdougb const cfg_obj_t *ent = cfg_listelt_value(element); 2922135446Strhodes 2923135446Strhodes CHECK(configure_order(order, ent)); 2924135446Strhodes } 2925135446Strhodes if (view->order != NULL) 2926135446Strhodes dns_order_detach(&view->order); 2927135446Strhodes dns_order_attach(order, &view->order); 2928135446Strhodes dns_order_detach(&order); 2929135446Strhodes } 2930135446Strhodes /* 2931135446Strhodes * Copy the aclenv object. 2932135446Strhodes */ 2933135446Strhodes dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 2934135446Strhodes 2935135446Strhodes /* 2936135446Strhodes * Configure the "match-clients" and "match-destinations" ACL. 2937135446Strhodes */ 2938224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx, 2939135446Strhodes ns_g_mctx, &view->matchclients)); 2940224092Sdougb CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL, 2941224092Sdougb actx, ns_g_mctx, &view->matchdestinations)); 2942135446Strhodes 2943135446Strhodes /* 2944135446Strhodes * Configure the "match-recursive-only" option. 2945135446Strhodes */ 2946135446Strhodes obj = NULL; 2947165071Sdougb (void)ns_config_get(maps, "match-recursive-only", &obj); 2948135446Strhodes if (obj != NULL && cfg_obj_asboolean(obj)) 2949135446Strhodes view->matchrecursiveonly = ISC_TRUE; 2950135446Strhodes else 2951135446Strhodes view->matchrecursiveonly = ISC_FALSE; 2952135446Strhodes 2953135446Strhodes /* 2954135446Strhodes * Configure other configurable data. 2955135446Strhodes */ 2956135446Strhodes obj = NULL; 2957135446Strhodes result = ns_config_get(maps, "recursion", &obj); 2958135446Strhodes INSIST(result == ISC_R_SUCCESS); 2959135446Strhodes view->recursion = cfg_obj_asboolean(obj); 2960135446Strhodes 2961135446Strhodes obj = NULL; 2962135446Strhodes result = ns_config_get(maps, "auth-nxdomain", &obj); 2963135446Strhodes INSIST(result == ISC_R_SUCCESS); 2964135446Strhodes view->auth_nxdomain = cfg_obj_asboolean(obj); 2965135446Strhodes 2966135446Strhodes obj = NULL; 2967135446Strhodes result = ns_config_get(maps, "minimal-responses", &obj); 2968135446Strhodes INSIST(result == ISC_R_SUCCESS); 2969135446Strhodes view->minimalresponses = cfg_obj_asboolean(obj); 2970135446Strhodes 2971135446Strhodes obj = NULL; 2972135446Strhodes result = ns_config_get(maps, "transfer-format", &obj); 2973135446Strhodes INSIST(result == ISC_R_SUCCESS); 2974135446Strhodes str = cfg_obj_asstring(obj); 2975135446Strhodes if (strcasecmp(str, "many-answers") == 0) 2976135446Strhodes view->transfer_format = dns_many_answers; 2977135446Strhodes else if (strcasecmp(str, "one-answer") == 0) 2978135446Strhodes view->transfer_format = dns_one_answer; 2979135446Strhodes else 2980135446Strhodes INSIST(0); 2981186462Sdougb 2982135446Strhodes /* 2983135446Strhodes * Set sources where additional data and CNAME/DNAME 2984135446Strhodes * targets for authoritative answers may be found. 2985135446Strhodes */ 2986135446Strhodes obj = NULL; 2987135446Strhodes result = ns_config_get(maps, "additional-from-auth", &obj); 2988135446Strhodes INSIST(result == ISC_R_SUCCESS); 2989135446Strhodes view->additionalfromauth = cfg_obj_asboolean(obj); 2990135446Strhodes if (view->recursion && ! view->additionalfromauth) { 2991135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 2992135446Strhodes "'additional-from-auth no' is only supported " 2993135446Strhodes "with 'recursion no'"); 2994135446Strhodes view->additionalfromauth = ISC_TRUE; 2995135446Strhodes } 2996135446Strhodes 2997135446Strhodes obj = NULL; 2998135446Strhodes result = ns_config_get(maps, "additional-from-cache", &obj); 2999135446Strhodes INSIST(result == ISC_R_SUCCESS); 3000135446Strhodes view->additionalfromcache = cfg_obj_asboolean(obj); 3001135446Strhodes if (view->recursion && ! view->additionalfromcache) { 3002135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 3003135446Strhodes "'additional-from-cache no' is only supported " 3004135446Strhodes "with 'recursion no'"); 3005135446Strhodes view->additionalfromcache = ISC_TRUE; 3006135446Strhodes } 3007135446Strhodes 3008171577Sdougb /* 3009193149Sdougb * Set "allow-query-cache", "allow-query-cache-on", 3010193149Sdougb * "allow-recursion", and "allow-recursion-on" acls if 3011171577Sdougb * configured in named.conf. 3012171577Sdougb */ 3013224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL, 3014216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 3015224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL, 3016216175Sdougb actx, ns_g_mctx, &view->cacheonacl)); 3017216175Sdougb if (view->cacheonacl == NULL) 3018193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3019224092Sdougb "allow-query-cache-on", NULL, actx, 3020216175Sdougb ns_g_mctx, &view->cacheonacl)); 3021193149Sdougb if (strcmp(view->name, "_bind") != 0) { 3022135446Strhodes CHECK(configure_view_acl(vconfig, config, "allow-recursion", 3023224092Sdougb NULL, actx, ns_g_mctx, 3024193149Sdougb &view->recursionacl)); 3025193149Sdougb CHECK(configure_view_acl(vconfig, config, "allow-recursion-on", 3026224092Sdougb NULL, actx, ns_g_mctx, 3027193149Sdougb &view->recursiononacl)); 3028193149Sdougb } 3029135446Strhodes 3030135446Strhodes /* 3031171577Sdougb * "allow-query-cache" inherits from "allow-recursion" if set, 3032171577Sdougb * otherwise from "allow-query" if set. 3033171577Sdougb * "allow-recursion" inherits from "allow-query-cache" if set, 3034171577Sdougb * otherwise from "allow-query" if set. 3035170222Sdougb */ 3036216175Sdougb if (view->cacheacl == NULL && view->recursionacl != NULL) 3037216175Sdougb dns_acl_attach(view->recursionacl, &view->cacheacl); 3038224092Sdougb /* 3039224092Sdougb * XXXEACH: This call to configure_view_acl() is redundant. We 3040224092Sdougb * are leaving it as it is because we are making a minimal change 3041224092Sdougb * for a patch release. In the future this should be changed to 3042224092Sdougb * dns_acl_attach(view->queryacl, &view->cacheacl). 3043224092Sdougb */ 3044216175Sdougb if (view->cacheacl == NULL && view->recursion) 3045224092Sdougb CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, 3046216175Sdougb actx, ns_g_mctx, &view->cacheacl)); 3047193149Sdougb if (view->recursion && 3048216175Sdougb view->recursionacl == NULL && view->cacheacl != NULL) 3049216175Sdougb dns_acl_attach(view->cacheacl, &view->recursionacl); 3050171577Sdougb 3051171577Sdougb /* 3052193149Sdougb * Set default "allow-recursion", "allow-recursion-on" and 3053193149Sdougb * "allow-query-cache" acls. 3054171577Sdougb */ 3055170222Sdougb if (view->recursionacl == NULL && view->recursion) 3056171577Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3057224092Sdougb "allow-recursion", NULL, 3058193149Sdougb actx, ns_g_mctx, 3059193149Sdougb &view->recursionacl)); 3060193149Sdougb if (view->recursiononacl == NULL && view->recursion) 3061193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3062224092Sdougb "allow-recursion-on", NULL, 3063193149Sdougb actx, ns_g_mctx, 3064193149Sdougb &view->recursiononacl)); 3065216175Sdougb if (view->cacheacl == NULL) { 3066193149Sdougb if (view->recursion) 3067193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3068224092Sdougb "allow-query-cache", NULL, 3069224092Sdougb actx, ns_g_mctx, 3070224092Sdougb &view->cacheacl)); 3071216175Sdougb else 3072224092Sdougb CHECK(dns_acl_none(mctx, &view->cacheacl)); 3073193149Sdougb } 3074170222Sdougb 3075193149Sdougb /* 3076224092Sdougb * Filter setting on addresses in the answer section. 3077224092Sdougb */ 3078224092Sdougb CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses", 3079224092Sdougb "acl", actx, ns_g_mctx, &view->denyansweracl)); 3080224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses", 3081224092Sdougb "except-from", ns_g_mctx, 3082224092Sdougb &view->answeracl_exclude)); 3083224092Sdougb 3084224092Sdougb /* 3085224092Sdougb * Filter setting on names (CNAME/DNAME targets) in the answer section. 3086224092Sdougb */ 3087224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 3088224092Sdougb "name", ns_g_mctx, 3089224092Sdougb &view->denyanswernames)); 3090224092Sdougb CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases", 3091224092Sdougb "except-from", ns_g_mctx, 3092224092Sdougb &view->answernames_exclude)); 3093224092Sdougb 3094224092Sdougb /* 3095193149Sdougb * Configure sortlist, if set 3096193149Sdougb */ 3097193149Sdougb CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx, 3098193149Sdougb &view->sortlist)); 3099135446Strhodes 3100193149Sdougb /* 3101193149Sdougb * Configure default allow-transfer, allow-notify, allow-update 3102193149Sdougb * and allow-update-forwarding ACLs, if set, so they can be 3103193149Sdougb * inherited by zones. 3104193149Sdougb */ 3105193149Sdougb if (view->notifyacl == NULL) 3106193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3107224092Sdougb "allow-notify", NULL, actx, 3108193149Sdougb ns_g_mctx, &view->notifyacl)); 3109193149Sdougb if (view->transferacl == NULL) 3110193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3111224092Sdougb "allow-transfer", NULL, actx, 3112193149Sdougb ns_g_mctx, &view->transferacl)); 3113193149Sdougb if (view->updateacl == NULL) 3114193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3115224092Sdougb "allow-update", NULL, actx, 3116193149Sdougb ns_g_mctx, &view->updateacl)); 3117193149Sdougb if (view->upfwdacl == NULL) 3118193149Sdougb CHECK(configure_view_acl(NULL, ns_g_config, 3119224092Sdougb "allow-update-forwarding", NULL, actx, 3120193149Sdougb ns_g_mctx, &view->upfwdacl)); 3121193149Sdougb 3122135446Strhodes obj = NULL; 3123135446Strhodes result = ns_config_get(maps, "provide-ixfr", &obj); 3124135446Strhodes INSIST(result == ISC_R_SUCCESS); 3125135446Strhodes view->provideixfr = cfg_obj_asboolean(obj); 3126170222Sdougb 3127170222Sdougb obj = NULL; 3128193149Sdougb result = ns_config_get(maps, "request-nsid", &obj); 3129193149Sdougb INSIST(result == ISC_R_SUCCESS); 3130193149Sdougb view->requestnsid = cfg_obj_asboolean(obj); 3131193149Sdougb 3132193149Sdougb obj = NULL; 3133170222Sdougb result = ns_config_get(maps, "max-clients-per-query", &obj); 3134170222Sdougb INSIST(result == ISC_R_SUCCESS); 3135170222Sdougb max_clients_per_query = cfg_obj_asuint32(obj); 3136170222Sdougb 3137170222Sdougb obj = NULL; 3138170222Sdougb result = ns_config_get(maps, "clients-per-query", &obj); 3139170222Sdougb INSIST(result == ISC_R_SUCCESS); 3140170222Sdougb dns_resolver_setclientsperquery(view->resolver, 3141170222Sdougb cfg_obj_asuint32(obj), 3142170222Sdougb max_clients_per_query); 3143186462Sdougb 3144275672Sdelphij obj = NULL; 3145275672Sdelphij result = ns_config_get(maps, "max-recursion-depth", &obj); 3146275672Sdelphij INSIST(result == ISC_R_SUCCESS); 3147275672Sdelphij dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj)); 3148275672Sdelphij 3149224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 3150135446Strhodes obj = NULL; 3151224092Sdougb result = ns_config_get(maps, "filter-aaaa-on-v4", &obj); 3152224092Sdougb INSIST(result == ISC_R_SUCCESS); 3153224092Sdougb if (cfg_obj_isboolean(obj)) { 3154224092Sdougb if (cfg_obj_asboolean(obj)) 3155224092Sdougb view->v4_aaaa = dns_v4_aaaa_filter; 3156224092Sdougb else 3157224092Sdougb view->v4_aaaa = dns_v4_aaaa_ok; 3158224092Sdougb } else { 3159224092Sdougb const char *v4_aaaastr = cfg_obj_asstring(obj); 3160224092Sdougb if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) 3161224092Sdougb view->v4_aaaa = dns_v4_aaaa_break_dnssec; 3162224092Sdougb else 3163224092Sdougb INSIST(0); 3164224092Sdougb } 3165224092Sdougb CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL, 3166224092Sdougb actx, ns_g_mctx, &view->v4_aaaa_acl)); 3167224092Sdougb#endif 3168224092Sdougb 3169224092Sdougb obj = NULL; 3170135446Strhodes result = ns_config_get(maps, "dnssec-enable", &obj); 3171135446Strhodes INSIST(result == ISC_R_SUCCESS); 3172135446Strhodes view->enablednssec = cfg_obj_asboolean(obj); 3173135446Strhodes 3174135446Strhodes obj = NULL; 3175224092Sdougb result = ns_config_get(optionmaps, "dnssec-lookaside", &obj); 3176135446Strhodes if (result == ISC_R_SUCCESS) { 3177224092Sdougb /* If set to "auto", use the version from the defaults */ 3178224092Sdougb const cfg_obj_t *dlvobj; 3179234010Sdougb const char *dom; 3180224092Sdougb dlvobj = cfg_listelt_value(cfg_list_first(obj)); 3181234010Sdougb dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain")); 3182234010Sdougb if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) { 3183234010Sdougb /* If "no", skip; if "auto", use global default */ 3184234010Sdougb if (!strcasecmp(dom, "no")) 3185234010Sdougb result = ISC_R_NOTFOUND; 3186234010Sdougb else if (!strcasecmp(dom, "auto")) { 3187234010Sdougb auto_dlv = ISC_TRUE; 3188234010Sdougb obj = NULL; 3189234010Sdougb result = cfg_map_get(ns_g_defaults, 3190234010Sdougb "dnssec-lookaside", &obj); 3191234010Sdougb } 3192224092Sdougb } 3193224092Sdougb } 3194224092Sdougb 3195224092Sdougb if (result == ISC_R_SUCCESS) { 3196135446Strhodes for (element = cfg_list_first(obj); 3197135446Strhodes element != NULL; 3198135446Strhodes element = cfg_list_next(element)) 3199135446Strhodes { 3200135446Strhodes const char *str; 3201135446Strhodes isc_buffer_t b; 3202135446Strhodes dns_name_t *dlv; 3203135446Strhodes 3204135446Strhodes obj = cfg_listelt_value(element); 3205135446Strhodes str = cfg_obj_asstring(cfg_tuple_get(obj, 3206135446Strhodes "trust-anchor")); 3207254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 3208135446Strhodes isc_buffer_add(&b, strlen(str)); 3209135446Strhodes dlv = dns_fixedname_name(&view->dlv_fixed); 3210135446Strhodes CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 3211224092Sdougb DNS_NAME_DOWNCASE, NULL)); 3212135446Strhodes view->dlv = dns_fixedname_name(&view->dlv_fixed); 3213135446Strhodes } 3214135446Strhodes } else 3215135446Strhodes view->dlv = NULL; 3216135446Strhodes 3217135446Strhodes /* 3218135446Strhodes * For now, there is only one kind of trusted keys, the 3219135446Strhodes * "security roots". 3220135446Strhodes */ 3221224092Sdougb CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, 3222224092Sdougb auto_dlv, auto_root, mctx)); 3223170222Sdougb dns_resolver_resetmustbesecure(view->resolver); 3224170222Sdougb obj = NULL; 3225170222Sdougb result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 3226170222Sdougb if (result == ISC_R_SUCCESS) 3227170222Sdougb CHECK(mustbesecure(obj, view->resolver)); 3228135446Strhodes 3229135446Strhodes obj = NULL; 3230135446Strhodes result = ns_config_get(maps, "preferred-glue", &obj); 3231135446Strhodes if (result == ISC_R_SUCCESS) { 3232135446Strhodes str = cfg_obj_asstring(obj); 3233135446Strhodes if (strcasecmp(str, "a") == 0) 3234135446Strhodes view->preferred_glue = dns_rdatatype_a; 3235135446Strhodes else if (strcasecmp(str, "aaaa") == 0) 3236135446Strhodes view->preferred_glue = dns_rdatatype_aaaa; 3237135446Strhodes else 3238135446Strhodes view->preferred_glue = 0; 3239135446Strhodes } else 3240135446Strhodes view->preferred_glue = 0; 3241135446Strhodes 3242135446Strhodes obj = NULL; 3243135446Strhodes result = ns_config_get(maps, "root-delegation-only", &obj); 3244135446Strhodes if (result == ISC_R_SUCCESS) { 3245135446Strhodes dns_view_setrootdelonly(view, ISC_TRUE); 3246135446Strhodes if (!cfg_obj_isvoid(obj)) { 3247135446Strhodes dns_fixedname_t fixed; 3248135446Strhodes dns_name_t *name; 3249135446Strhodes isc_buffer_t b; 3250165071Sdougb const char *str; 3251165071Sdougb const cfg_obj_t *exclude; 3252135446Strhodes 3253135446Strhodes dns_fixedname_init(&fixed); 3254135446Strhodes name = dns_fixedname_name(&fixed); 3255135446Strhodes for (element = cfg_list_first(obj); 3256135446Strhodes element != NULL; 3257135446Strhodes element = cfg_list_next(element)) { 3258135446Strhodes exclude = cfg_listelt_value(element); 3259135446Strhodes str = cfg_obj_asstring(exclude); 3260254402Serwin isc_buffer_constinit(&b, str, strlen(str)); 3261135446Strhodes isc_buffer_add(&b, strlen(str)); 3262135446Strhodes CHECK(dns_name_fromtext(name, &b, dns_rootname, 3263224092Sdougb 0, NULL)); 3264135446Strhodes CHECK(dns_view_excludedelegationonly(view, 3265135446Strhodes name)); 3266135446Strhodes } 3267135446Strhodes } 3268135446Strhodes } else 3269135446Strhodes dns_view_setrootdelonly(view, ISC_FALSE); 3270135446Strhodes 3271170222Sdougb /* 3272170222Sdougb * Setup automatic empty zones. If recursion is off then 3273170222Sdougb * they are disabled by default. 3274170222Sdougb */ 3275170222Sdougb obj = NULL; 3276170222Sdougb (void)ns_config_get(maps, "empty-zones-enable", &obj); 3277170222Sdougb (void)ns_config_get(maps, "disable-empty-zone", &disablelist); 3278170222Sdougb if (obj == NULL && disablelist == NULL && 3279170222Sdougb view->rdclass == dns_rdataclass_in) { 3280170222Sdougb empty_zones_enable = view->recursion; 3281170222Sdougb } else if (view->rdclass == dns_rdataclass_in) { 3282170222Sdougb if (obj != NULL) 3283170222Sdougb empty_zones_enable = cfg_obj_asboolean(obj); 3284170222Sdougb else 3285170222Sdougb empty_zones_enable = view->recursion; 3286170222Sdougb } else { 3287170222Sdougb empty_zones_enable = ISC_FALSE; 3288170222Sdougb } 3289234010Sdougb if (empty_zones_enable && !lwresd_g_useresolvconf) { 3290170222Sdougb const char *empty; 3291170222Sdougb int empty_zone = 0; 3292170222Sdougb dns_fixedname_t fixed; 3293170222Sdougb dns_name_t *name; 3294170222Sdougb isc_buffer_t buffer; 3295170222Sdougb const char *str; 3296170222Sdougb char server[DNS_NAME_FORMATSIZE + 1]; 3297170222Sdougb char contact[DNS_NAME_FORMATSIZE + 1]; 3298170222Sdougb const char *empty_dbtype[4] = 3299170222Sdougb { "_builtin", "empty", NULL, NULL }; 3300170222Sdougb int empty_dbtypec = 4; 3301254897Serwin dns_zonestat_level_t statlevel; 3302170222Sdougb 3303170222Sdougb dns_fixedname_init(&fixed); 3304170222Sdougb name = dns_fixedname_name(&fixed); 3305170222Sdougb 3306170222Sdougb obj = NULL; 3307170222Sdougb result = ns_config_get(maps, "empty-server", &obj); 3308170222Sdougb if (result == ISC_R_SUCCESS) { 3309170222Sdougb str = cfg_obj_asstring(obj); 3310254402Serwin isc_buffer_constinit(&buffer, str, strlen(str)); 3311170222Sdougb isc_buffer_add(&buffer, strlen(str)); 3312224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3313224092Sdougb NULL)); 3314170222Sdougb isc_buffer_init(&buffer, server, sizeof(server) - 1); 3315170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 3316170222Sdougb server[isc_buffer_usedlength(&buffer)] = 0; 3317170222Sdougb empty_dbtype[2] = server; 3318170222Sdougb } else 3319170222Sdougb empty_dbtype[2] = "@"; 3320170222Sdougb 3321170222Sdougb obj = NULL; 3322170222Sdougb result = ns_config_get(maps, "empty-contact", &obj); 3323170222Sdougb if (result == ISC_R_SUCCESS) { 3324170222Sdougb str = cfg_obj_asstring(obj); 3325254402Serwin isc_buffer_constinit(&buffer, str, strlen(str)); 3326170222Sdougb isc_buffer_add(&buffer, strlen(str)); 3327224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3328224092Sdougb NULL)); 3329170222Sdougb isc_buffer_init(&buffer, contact, sizeof(contact) - 1); 3330170222Sdougb CHECK(dns_name_totext(name, ISC_FALSE, &buffer)); 3331170222Sdougb contact[isc_buffer_usedlength(&buffer)] = 0; 3332170222Sdougb empty_dbtype[3] = contact; 3333170222Sdougb } else 3334170222Sdougb empty_dbtype[3] = "."; 3335170222Sdougb 3336193149Sdougb obj = NULL; 3337193149Sdougb result = ns_config_get(maps, "zone-statistics", &obj); 3338193149Sdougb INSIST(result == ISC_R_SUCCESS); 3339254897Serwin if (cfg_obj_isboolean(obj)) { 3340254897Serwin if (cfg_obj_asboolean(obj)) 3341254897Serwin statlevel = dns_zonestat_full; 3342254897Serwin else 3343254897Serwin statlevel = dns_zonestat_terse; /* XXX */ 3344254897Serwin } else { 3345254897Serwin const char *levelstr = cfg_obj_asstring(obj); 3346254897Serwin if (strcasecmp(levelstr, "full") == 0) 3347254897Serwin statlevel = dns_zonestat_full; 3348254897Serwin else if (strcasecmp(levelstr, "terse") == 0) 3349254897Serwin statlevel = dns_zonestat_terse; 3350254897Serwin else if (strcasecmp(levelstr, "none") == 0) 3351254897Serwin statlevel = dns_zonestat_none; 3352254897Serwin else 3353254897Serwin INSIST(0); 3354254897Serwin } 3355193149Sdougb 3356254897Serwin for (empty = empty_zones[empty_zone]; 3357170222Sdougb empty != NULL; 3358254897Serwin empty = empty_zones[++empty_zone]) 3359170222Sdougb { 3360170222Sdougb dns_forwarders_t *forwarders = NULL; 3361170222Sdougb dns_view_t *pview = NULL; 3362170222Sdougb 3363254402Serwin isc_buffer_constinit(&buffer, empty, strlen(empty)); 3364170222Sdougb isc_buffer_add(&buffer, strlen(empty)); 3365170222Sdougb /* 3366170222Sdougb * Look for zone on drop list. 3367170222Sdougb */ 3368224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3369224092Sdougb NULL)); 3370170222Sdougb if (disablelist != NULL && 3371170222Sdougb on_disable_list(disablelist, name)) 3372170222Sdougb continue; 3373170222Sdougb 3374170222Sdougb /* 3375170222Sdougb * This zone already exists. 3376170222Sdougb */ 3377170222Sdougb (void)dns_view_findzone(view, name, &zone); 3378170222Sdougb if (zone != NULL) { 3379170222Sdougb dns_zone_detach(&zone); 3380170222Sdougb continue; 3381170222Sdougb } 3382170222Sdougb 3383170222Sdougb /* 3384170222Sdougb * If we would forward this name don't add a 3385170222Sdougb * empty zone for it. 3386170222Sdougb */ 3387170222Sdougb result = dns_fwdtable_find(view->fwdtable, name, 3388170222Sdougb &forwarders); 3389170222Sdougb if (result == ISC_R_SUCCESS && 3390170222Sdougb forwarders->fwdpolicy == dns_fwdpolicy_only) 3391170222Sdougb continue; 3392186462Sdougb 3393170222Sdougb /* 3394170222Sdougb * See if we can re-use a existing zone. 3395170222Sdougb */ 3396170222Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 3397170222Sdougb view->name, view->rdclass, 3398170222Sdougb &pview); 3399170222Sdougb if (result != ISC_R_NOTFOUND && 3400170222Sdougb result != ISC_R_SUCCESS) 3401170222Sdougb goto cleanup; 3402170222Sdougb 3403170222Sdougb if (pview != NULL) { 3404170222Sdougb (void)dns_view_findzone(pview, name, &zone); 3405170222Sdougb dns_view_detach(&pview); 3406170222Sdougb } 3407170222Sdougb 3408262706Serwin CHECK(create_empty_zone(zone, name, view, zonelist, 3409262706Serwin empty_dbtype, empty_dbtypec, 3410262706Serwin statlevel)); 3411262706Serwin if (zone != NULL) 3412262706Serwin dns_zone_detach(&zone); 3413170222Sdougb } 3414170222Sdougb } 3415186462Sdougb 3416262706Serwin#ifdef USE_RRL 3417262706Serwin obj = NULL; 3418262706Serwin result = ns_config_get(maps, "rate-limit", &obj); 3419262706Serwin if (result == ISC_R_SUCCESS) { 3420262706Serwin result = configure_rrl(view, config, obj); 3421262706Serwin if (result != ISC_R_SUCCESS) 3422262706Serwin goto cleanup; 3423262706Serwin } 3424262706Serwin#endif /* USE_RRL */ 3425262706Serwin 3426135446Strhodes result = ISC_R_SUCCESS; 3427135446Strhodes 3428135446Strhodes cleanup: 3429224092Sdougb if (clients != NULL) 3430224092Sdougb dns_acl_detach(&clients); 3431224092Sdougb if (mapped != NULL) 3432224092Sdougb dns_acl_detach(&mapped); 3433224092Sdougb if (excluded != NULL) 3434224092Sdougb dns_acl_detach(&excluded); 3435224092Sdougb if (ring != NULL) 3436224092Sdougb dns_tsigkeyring_detach(&ring); 3437170222Sdougb if (zone != NULL) 3438170222Sdougb dns_zone_detach(&zone); 3439135446Strhodes if (dispatch4 != NULL) 3440135446Strhodes dns_dispatch_detach(&dispatch4); 3441135446Strhodes if (dispatch6 != NULL) 3442135446Strhodes dns_dispatch_detach(&dispatch6); 3443193149Sdougb if (resstats != NULL) 3444193149Sdougb isc_stats_detach(&resstats); 3445193149Sdougb if (resquerystats != NULL) 3446193149Sdougb dns_stats_detach(&resquerystats); 3447135446Strhodes if (order != NULL) 3448135446Strhodes dns_order_detach(&order); 3449135446Strhodes if (cmctx != NULL) 3450135446Strhodes isc_mem_detach(&cmctx); 3451225361Sdougb if (hmctx != NULL) 3452225361Sdougb isc_mem_detach(&hmctx); 3453135446Strhodes 3454135446Strhodes if (cache != NULL) 3455135446Strhodes dns_cache_detach(&cache); 3456135446Strhodes 3457135446Strhodes return (result); 3458135446Strhodes} 3459135446Strhodes 3460135446Strhodesstatic isc_result_t 3461135446Strhodesconfigure_hints(dns_view_t *view, const char *filename) { 3462135446Strhodes isc_result_t result; 3463135446Strhodes dns_db_t *db; 3464135446Strhodes 3465135446Strhodes db = NULL; 3466135446Strhodes result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 3467135446Strhodes if (result == ISC_R_SUCCESS) { 3468135446Strhodes dns_view_sethints(view, db); 3469135446Strhodes dns_db_detach(&db); 3470135446Strhodes } 3471135446Strhodes 3472135446Strhodes return (result); 3473135446Strhodes} 3474135446Strhodes 3475135446Strhodesstatic isc_result_t 3476165071Sdougbconfigure_alternates(const cfg_obj_t *config, dns_view_t *view, 3477165071Sdougb const cfg_obj_t *alternates) 3478135446Strhodes{ 3479165071Sdougb const cfg_obj_t *portobj; 3480165071Sdougb const cfg_obj_t *addresses; 3481165071Sdougb const cfg_listelt_t *element; 3482135446Strhodes isc_result_t result = ISC_R_SUCCESS; 3483135446Strhodes in_port_t port; 3484135446Strhodes 3485135446Strhodes /* 3486135446Strhodes * Determine which port to send requests to. 3487135446Strhodes */ 3488135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 3489135446Strhodes port = ns_g_port; 3490135446Strhodes else 3491135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 3492135446Strhodes 3493135446Strhodes if (alternates != NULL) { 3494135446Strhodes portobj = cfg_tuple_get(alternates, "port"); 3495135446Strhodes if (cfg_obj_isuint32(portobj)) { 3496135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3497135446Strhodes if (val > ISC_UINT16_MAX) { 3498135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3499135446Strhodes "port '%u' out of range", val); 3500135446Strhodes return (ISC_R_RANGE); 3501135446Strhodes } 3502135446Strhodes port = (in_port_t) val; 3503135446Strhodes } 3504135446Strhodes } 3505135446Strhodes 3506135446Strhodes addresses = NULL; 3507135446Strhodes if (alternates != NULL) 3508135446Strhodes addresses = cfg_tuple_get(alternates, "addresses"); 3509135446Strhodes 3510135446Strhodes for (element = cfg_list_first(addresses); 3511135446Strhodes element != NULL; 3512135446Strhodes element = cfg_list_next(element)) 3513135446Strhodes { 3514165071Sdougb const cfg_obj_t *alternate = cfg_listelt_value(element); 3515135446Strhodes isc_sockaddr_t sa; 3516135446Strhodes 3517135446Strhodes if (!cfg_obj_issockaddr(alternate)) { 3518135446Strhodes dns_fixedname_t fixed; 3519135446Strhodes dns_name_t *name; 3520165071Sdougb const char *str = cfg_obj_asstring(cfg_tuple_get( 3521165071Sdougb alternate, "name")); 3522135446Strhodes isc_buffer_t buffer; 3523135446Strhodes in_port_t myport = port; 3524135446Strhodes 3525254402Serwin isc_buffer_constinit(&buffer, str, strlen(str)); 3526135446Strhodes isc_buffer_add(&buffer, strlen(str)); 3527135446Strhodes dns_fixedname_init(&fixed); 3528135446Strhodes name = dns_fixedname_name(&fixed); 3529224092Sdougb CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0, 3530224092Sdougb NULL)); 3531135446Strhodes 3532135446Strhodes portobj = cfg_tuple_get(alternate, "port"); 3533135446Strhodes if (cfg_obj_isuint32(portobj)) { 3534135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3535135446Strhodes if (val > ISC_UINT16_MAX) { 3536135446Strhodes cfg_obj_log(portobj, ns_g_lctx, 3537135446Strhodes ISC_LOG_ERROR, 3538135446Strhodes "port '%u' out of range", 3539135446Strhodes val); 3540135446Strhodes return (ISC_R_RANGE); 3541135446Strhodes } 3542135446Strhodes myport = (in_port_t) val; 3543135446Strhodes } 3544135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, NULL, 3545135446Strhodes name, myport)); 3546135446Strhodes continue; 3547135446Strhodes } 3548135446Strhodes 3549135446Strhodes sa = *cfg_obj_assockaddr(alternate); 3550135446Strhodes if (isc_sockaddr_getport(&sa) == 0) 3551135446Strhodes isc_sockaddr_setport(&sa, port); 3552135446Strhodes CHECK(dns_resolver_addalternate(view->resolver, &sa, 3553135446Strhodes NULL, 0)); 3554135446Strhodes } 3555135446Strhodes 3556135446Strhodes cleanup: 3557135446Strhodes return (result); 3558135446Strhodes} 3559135446Strhodes 3560135446Strhodesstatic isc_result_t 3561165071Sdougbconfigure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 3562165071Sdougb const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 3563135446Strhodes{ 3564165071Sdougb const cfg_obj_t *portobj; 3565165071Sdougb const cfg_obj_t *faddresses; 3566165071Sdougb const cfg_listelt_t *element; 3567135446Strhodes dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 3568135446Strhodes isc_sockaddrlist_t addresses; 3569135446Strhodes isc_sockaddr_t *sa; 3570135446Strhodes isc_result_t result; 3571135446Strhodes in_port_t port; 3572135446Strhodes 3573193149Sdougb ISC_LIST_INIT(addresses); 3574193149Sdougb 3575135446Strhodes /* 3576135446Strhodes * Determine which port to send forwarded requests to. 3577135446Strhodes */ 3578135446Strhodes if (ns_g_lwresdonly && ns_g_port != 0) 3579135446Strhodes port = ns_g_port; 3580135446Strhodes else 3581135446Strhodes CHECKM(ns_config_getport(config, &port), "port"); 3582135446Strhodes 3583135446Strhodes if (forwarders != NULL) { 3584135446Strhodes portobj = cfg_tuple_get(forwarders, "port"); 3585135446Strhodes if (cfg_obj_isuint32(portobj)) { 3586135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 3587135446Strhodes if (val > ISC_UINT16_MAX) { 3588135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3589135446Strhodes "port '%u' out of range", val); 3590135446Strhodes return (ISC_R_RANGE); 3591135446Strhodes } 3592135446Strhodes port = (in_port_t) val; 3593135446Strhodes } 3594135446Strhodes } 3595135446Strhodes 3596135446Strhodes faddresses = NULL; 3597135446Strhodes if (forwarders != NULL) 3598135446Strhodes faddresses = cfg_tuple_get(forwarders, "addresses"); 3599135446Strhodes 3600135446Strhodes for (element = cfg_list_first(faddresses); 3601135446Strhodes element != NULL; 3602135446Strhodes element = cfg_list_next(element)) 3603135446Strhodes { 3604165071Sdougb const cfg_obj_t *forwarder = cfg_listelt_value(element); 3605135446Strhodes sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 3606135446Strhodes if (sa == NULL) { 3607135446Strhodes result = ISC_R_NOMEMORY; 3608135446Strhodes goto cleanup; 3609135446Strhodes } 3610135446Strhodes *sa = *cfg_obj_assockaddr(forwarder); 3611135446Strhodes if (isc_sockaddr_getport(sa) == 0) 3612135446Strhodes isc_sockaddr_setport(sa, port); 3613135446Strhodes ISC_LINK_INIT(sa, link); 3614135446Strhodes ISC_LIST_APPEND(addresses, sa, link); 3615135446Strhodes } 3616135446Strhodes 3617135446Strhodes if (ISC_LIST_EMPTY(addresses)) { 3618135446Strhodes if (forwardtype != NULL) 3619135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3620135446Strhodes "no forwarders seen; disabling " 3621135446Strhodes "forwarding"); 3622135446Strhodes fwdpolicy = dns_fwdpolicy_none; 3623135446Strhodes } else { 3624135446Strhodes if (forwardtype == NULL) 3625135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3626135446Strhodes else { 3627165071Sdougb const char *forwardstr = cfg_obj_asstring(forwardtype); 3628135446Strhodes if (strcasecmp(forwardstr, "first") == 0) 3629135446Strhodes fwdpolicy = dns_fwdpolicy_first; 3630135446Strhodes else if (strcasecmp(forwardstr, "only") == 0) 3631135446Strhodes fwdpolicy = dns_fwdpolicy_only; 3632135446Strhodes else 3633135446Strhodes INSIST(0); 3634135446Strhodes } 3635135446Strhodes } 3636135446Strhodes 3637135446Strhodes result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 3638135446Strhodes fwdpolicy); 3639135446Strhodes if (result != ISC_R_SUCCESS) { 3640135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 3641135446Strhodes dns_name_format(origin, namebuf, sizeof(namebuf)); 3642135446Strhodes cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 3643135446Strhodes "could not set up forwarding for domain '%s': %s", 3644135446Strhodes namebuf, isc_result_totext(result)); 3645135446Strhodes goto cleanup; 3646135446Strhodes } 3647135446Strhodes 3648135446Strhodes result = ISC_R_SUCCESS; 3649135446Strhodes 3650135446Strhodes cleanup: 3651135446Strhodes 3652135446Strhodes while (!ISC_LIST_EMPTY(addresses)) { 3653135446Strhodes sa = ISC_LIST_HEAD(addresses); 3654135446Strhodes ISC_LIST_UNLINK(addresses, sa, link); 3655135446Strhodes isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 3656135446Strhodes } 3657135446Strhodes 3658135446Strhodes return (result); 3659135446Strhodes} 3660135446Strhodes 3661135446Strhodesstatic isc_result_t 3662225361Sdougbget_viewinfo(const cfg_obj_t *vconfig, const char **namep, 3663225361Sdougb dns_rdataclass_t *classp) 3664165071Sdougb{ 3665225361Sdougb isc_result_t result = ISC_R_SUCCESS; 3666135446Strhodes const char *viewname; 3667135446Strhodes dns_rdataclass_t viewclass; 3668135446Strhodes 3669225361Sdougb REQUIRE(namep != NULL && *namep == NULL); 3670225361Sdougb REQUIRE(classp != NULL); 3671225361Sdougb 3672135446Strhodes if (vconfig != NULL) { 3673165071Sdougb const cfg_obj_t *classobj = NULL; 3674135446Strhodes 3675135446Strhodes viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 3676135446Strhodes classobj = cfg_tuple_get(vconfig, "class"); 3677135446Strhodes result = ns_config_getclass(classobj, dns_rdataclass_in, 3678135446Strhodes &viewclass); 3679135446Strhodes } else { 3680135446Strhodes viewname = "_default"; 3681135446Strhodes viewclass = dns_rdataclass_in; 3682135446Strhodes } 3683225361Sdougb 3684225361Sdougb *namep = viewname; 3685225361Sdougb *classp = viewclass; 3686225361Sdougb 3687225361Sdougb return (result); 3688225361Sdougb} 3689225361Sdougb 3690225361Sdougb/* 3691225361Sdougb * Find a view based on its configuration info and attach to it. 3692225361Sdougb * 3693225361Sdougb * If 'vconfig' is NULL, attach to the default view. 3694225361Sdougb */ 3695225361Sdougbstatic isc_result_t 3696225361Sdougbfind_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3697225361Sdougb dns_view_t **viewp) 3698225361Sdougb{ 3699225361Sdougb isc_result_t result; 3700225361Sdougb const char *viewname = NULL; 3701225361Sdougb dns_rdataclass_t viewclass; 3702225361Sdougb dns_view_t *view = NULL; 3703225361Sdougb 3704225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3705225361Sdougb if (result != ISC_R_SUCCESS) 3706225361Sdougb return (result); 3707225361Sdougb 3708135446Strhodes result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3709225361Sdougb if (result != ISC_R_SUCCESS) 3710225361Sdougb return (result); 3711225361Sdougb 3712225361Sdougb *viewp = view; 3713225361Sdougb return (ISC_R_SUCCESS); 3714225361Sdougb} 3715225361Sdougb 3716225361Sdougb/* 3717225361Sdougb * Create a new view and add it to the list. 3718225361Sdougb * 3719225361Sdougb * If 'vconfig' is NULL, create the default view. 3720225361Sdougb * 3721225361Sdougb * The view created is attached to '*viewp'. 3722225361Sdougb */ 3723225361Sdougbstatic isc_result_t 3724225361Sdougbcreate_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 3725225361Sdougb dns_view_t **viewp) 3726225361Sdougb{ 3727225361Sdougb isc_result_t result; 3728225361Sdougb const char *viewname = NULL; 3729225361Sdougb dns_rdataclass_t viewclass; 3730225361Sdougb dns_view_t *view = NULL; 3731225361Sdougb 3732225361Sdougb result = get_viewinfo(vconfig, &viewname, &viewclass); 3733225361Sdougb if (result != ISC_R_SUCCESS) 3734225361Sdougb return (result); 3735225361Sdougb 3736225361Sdougb result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 3737135446Strhodes if (result == ISC_R_SUCCESS) 3738135446Strhodes return (ISC_R_EXISTS); 3739135446Strhodes if (result != ISC_R_NOTFOUND) 3740135446Strhodes return (result); 3741135446Strhodes INSIST(view == NULL); 3742135446Strhodes 3743135446Strhodes result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 3744135446Strhodes if (result != ISC_R_SUCCESS) 3745135446Strhodes return (result); 3746135446Strhodes 3747135446Strhodes ISC_LIST_APPEND(*viewlist, view, link); 3748135446Strhodes dns_view_attach(view, viewp); 3749135446Strhodes return (ISC_R_SUCCESS); 3750135446Strhodes} 3751135446Strhodes 3752135446Strhodes/* 3753135446Strhodes * Configure or reconfigure a zone. 3754135446Strhodes */ 3755135446Strhodesstatic isc_result_t 3756165071Sdougbconfigure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 3757165071Sdougb const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 3758224092Sdougb cfg_aclconfctx_t *aclconf, isc_boolean_t added) 3759135446Strhodes{ 3760135446Strhodes dns_view_t *pview = NULL; /* Production view */ 3761135446Strhodes dns_zone_t *zone = NULL; /* New or reused zone */ 3762254897Serwin dns_zone_t *raw = NULL; /* New or reused raw zone */ 3763135446Strhodes dns_zone_t *dupzone = NULL; 3764165071Sdougb const cfg_obj_t *options = NULL; 3765165071Sdougb const cfg_obj_t *zoptions = NULL; 3766165071Sdougb const cfg_obj_t *typeobj = NULL; 3767165071Sdougb const cfg_obj_t *forwarders = NULL; 3768165071Sdougb const cfg_obj_t *forwardtype = NULL; 3769165071Sdougb const cfg_obj_t *only = NULL; 3770254897Serwin const cfg_obj_t *signing = NULL; 3771135446Strhodes isc_result_t result; 3772135446Strhodes isc_result_t tresult; 3773135446Strhodes isc_buffer_t buffer; 3774135446Strhodes dns_fixedname_t fixorigin; 3775135446Strhodes dns_name_t *origin; 3776135446Strhodes const char *zname; 3777135446Strhodes dns_rdataclass_t zclass; 3778135446Strhodes const char *ztypestr; 3779254402Serwin isc_boolean_t is_rpz; 3780254402Serwin dns_rpz_zone_t *rpz; 3781135446Strhodes 3782135446Strhodes options = NULL; 3783135446Strhodes (void)cfg_map_get(config, "options", &options); 3784135446Strhodes 3785135446Strhodes zoptions = cfg_tuple_get(zconfig, "options"); 3786135446Strhodes 3787135446Strhodes /* 3788135446Strhodes * Get the zone origin as a dns_name_t. 3789135446Strhodes */ 3790135446Strhodes zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 3791254402Serwin isc_buffer_constinit(&buffer, zname, strlen(zname)); 3792135446Strhodes isc_buffer_add(&buffer, strlen(zname)); 3793135446Strhodes dns_fixedname_init(&fixorigin); 3794135446Strhodes CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 3795224092Sdougb &buffer, dns_rootname, 0, NULL)); 3796135446Strhodes origin = dns_fixedname_name(&fixorigin); 3797135446Strhodes 3798135446Strhodes CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 3799135446Strhodes view->rdclass, &zclass)); 3800135446Strhodes if (zclass != view->rdclass) { 3801135446Strhodes const char *vname = NULL; 3802135446Strhodes if (vconfig != NULL) 3803135446Strhodes vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 3804135446Strhodes "name")); 3805135446Strhodes else 3806135446Strhodes vname = "<default view>"; 3807186462Sdougb 3808135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3809135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3810135446Strhodes "zone '%s': wrong class for view '%s'", 3811135446Strhodes zname, vname); 3812135446Strhodes result = ISC_R_FAILURE; 3813135446Strhodes goto cleanup; 3814135446Strhodes } 3815135446Strhodes 3816135446Strhodes (void)cfg_map_get(zoptions, "type", &typeobj); 3817135446Strhodes if (typeobj == NULL) { 3818135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3819135446Strhodes "zone '%s' 'type' not specified", zname); 3820135446Strhodes return (ISC_R_FAILURE); 3821135446Strhodes } 3822135446Strhodes ztypestr = cfg_obj_asstring(typeobj); 3823135446Strhodes 3824135446Strhodes /* 3825224092Sdougb * "hints zones" aren't zones. If we've got one, 3826135446Strhodes * configure it and return. 3827135446Strhodes */ 3828135446Strhodes if (strcasecmp(ztypestr, "hint") == 0) { 3829165071Sdougb const cfg_obj_t *fileobj = NULL; 3830135446Strhodes if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 3831135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3832135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3833135446Strhodes "zone '%s': 'file' not specified", 3834135446Strhodes zname); 3835135446Strhodes result = ISC_R_FAILURE; 3836135446Strhodes goto cleanup; 3837135446Strhodes } 3838135446Strhodes if (dns_name_equal(origin, dns_rootname)) { 3839165071Sdougb const char *hintsfile = cfg_obj_asstring(fileobj); 3840135446Strhodes 3841135446Strhodes result = configure_hints(view, hintsfile); 3842135446Strhodes if (result != ISC_R_SUCCESS) { 3843135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3844135446Strhodes NS_LOGMODULE_SERVER, 3845135446Strhodes ISC_LOG_ERROR, 3846135446Strhodes "could not configure root hints " 3847135446Strhodes "from '%s': %s", hintsfile, 3848135446Strhodes isc_result_totext(result)); 3849135446Strhodes goto cleanup; 3850135446Strhodes } 3851135446Strhodes /* 3852135446Strhodes * Hint zones may also refer to delegation only points. 3853135446Strhodes */ 3854135446Strhodes only = NULL; 3855135446Strhodes tresult = cfg_map_get(zoptions, "delegation-only", 3856135446Strhodes &only); 3857135446Strhodes if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 3858135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 3859135446Strhodes } else { 3860135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3861135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3862135446Strhodes "ignoring non-root hint zone '%s'", 3863135446Strhodes zname); 3864135446Strhodes result = ISC_R_SUCCESS; 3865135446Strhodes } 3866135446Strhodes /* Skip ordinary zone processing. */ 3867135446Strhodes goto cleanup; 3868135446Strhodes } 3869135446Strhodes 3870135446Strhodes /* 3871135446Strhodes * "forward zones" aren't zones either. Translate this syntax into 3872135446Strhodes * the appropriate selective forwarding configuration and return. 3873135446Strhodes */ 3874135446Strhodes if (strcasecmp(ztypestr, "forward") == 0) { 3875135446Strhodes forwardtype = NULL; 3876135446Strhodes forwarders = NULL; 3877135446Strhodes 3878135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 3879135446Strhodes (void)cfg_map_get(zoptions, "forwarders", &forwarders); 3880135446Strhodes result = configure_forward(config, view, origin, forwarders, 3881135446Strhodes forwardtype); 3882135446Strhodes goto cleanup; 3883135446Strhodes } 3884135446Strhodes 3885135446Strhodes /* 3886135446Strhodes * "delegation-only zones" aren't zones either. 3887135446Strhodes */ 3888135446Strhodes if (strcasecmp(ztypestr, "delegation-only") == 0) { 3889135446Strhodes result = dns_view_adddelegationonly(view, origin); 3890135446Strhodes goto cleanup; 3891135446Strhodes } 3892135446Strhodes 3893135446Strhodes /* 3894254897Serwin * Redirect zones only require minimal configuration. 3895254897Serwin */ 3896254897Serwin if (strcasecmp(ztypestr, "redirect") == 0) { 3897254897Serwin if (view->redirect != NULL) { 3898254897Serwin cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3899254897Serwin "redirect zone already exists"); 3900254897Serwin result = ISC_R_EXISTS; 3901254897Serwin goto cleanup; 3902254897Serwin } 3903254897Serwin result = dns_viewlist_find(&ns_g_server->viewlist, view->name, 3904254897Serwin view->rdclass, &pview); 3905254897Serwin if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3906254897Serwin goto cleanup; 3907254897Serwin if (pview != NULL && pview->redirect != NULL) { 3908254897Serwin dns_zone_attach(pview->redirect, &zone); 3909254897Serwin dns_zone_setview(zone, view); 3910254897Serwin } else { 3911254897Serwin CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, 3912254897Serwin &zone)); 3913254897Serwin CHECK(dns_zone_setorigin(zone, origin)); 3914254897Serwin dns_zone_setview(zone, view); 3915254897Serwin CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, 3916254897Serwin zone)); 3917254897Serwin dns_zone_setstats(zone, ns_g_server->zonestats); 3918254897Serwin } 3919254897Serwin CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, 3920254897Serwin zone, NULL)); 3921254897Serwin dns_zone_attach(zone, &view->redirect); 3922254897Serwin goto cleanup; 3923254897Serwin } 3924254897Serwin 3925254897Serwin /* 3926135446Strhodes * Check for duplicates in the new zone table. 3927135446Strhodes */ 3928135446Strhodes result = dns_view_findzone(view, origin, &dupzone); 3929135446Strhodes if (result == ISC_R_SUCCESS) { 3930135446Strhodes /* 3931135446Strhodes * We already have this zone! 3932135446Strhodes */ 3933135446Strhodes cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 3934135446Strhodes "zone '%s' already exists", zname); 3935135446Strhodes dns_zone_detach(&dupzone); 3936135446Strhodes result = ISC_R_EXISTS; 3937135446Strhodes goto cleanup; 3938135446Strhodes } 3939135446Strhodes INSIST(dupzone == NULL); 3940135446Strhodes 3941135446Strhodes /* 3942254402Serwin * Note whether this is a response policy zone. 3943254402Serwin */ 3944254402Serwin is_rpz = ISC_FALSE; 3945254402Serwin for (rpz = ISC_LIST_HEAD(view->rpz_zones); 3946254402Serwin rpz != NULL; 3947254402Serwin rpz = ISC_LIST_NEXT(rpz, link)) 3948254402Serwin { 3949254402Serwin if (dns_name_equal(&rpz->origin, origin)) { 3950254402Serwin is_rpz = ISC_TRUE; 3951254402Serwin rpz->defined = ISC_TRUE; 3952254402Serwin break; 3953254402Serwin } 3954254402Serwin } 3955254402Serwin 3956254402Serwin /* 3957135446Strhodes * See if we can reuse an existing zone. This is 3958135446Strhodes * only possible if all of these are true: 3959135446Strhodes * - The zone's view exists 3960135446Strhodes * - A zone with the right name exists in the view 3961135446Strhodes * - The zone is compatible with the config 3962135446Strhodes * options (e.g., an existing master zone cannot 3963135446Strhodes * be reused if the options specify a slave zone) 3964254402Serwin * - The zone was and is or was not and is not a policy zone 3965135446Strhodes */ 3966254897Serwin result = dns_viewlist_find(&ns_g_server->viewlist, view->name, 3967254897Serwin view->rdclass, &pview); 3968135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3969135446Strhodes goto cleanup; 3970135446Strhodes if (pview != NULL) 3971135446Strhodes result = dns_view_findzone(pview, origin, &zone); 3972135446Strhodes if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 3973135446Strhodes goto cleanup; 3974254897Serwin 3975170222Sdougb if (zone != NULL && !ns_zone_reusable(zone, zconfig)) 3976170222Sdougb dns_zone_detach(&zone); 3977135446Strhodes 3978254402Serwin if (zone != NULL && is_rpz != dns_zone_get_rpz(zone)) 3979254402Serwin dns_zone_detach(&zone); 3980254402Serwin 3981135446Strhodes if (zone != NULL) { 3982135446Strhodes /* 3983135446Strhodes * We found a reusable zone. Make it use the 3984135446Strhodes * new view. 3985135446Strhodes */ 3986135446Strhodes dns_zone_setview(zone, view); 3987170222Sdougb if (view->acache != NULL) 3988170222Sdougb dns_zone_setacache(zone, view->acache); 3989135446Strhodes } else { 3990135446Strhodes /* 3991135446Strhodes * We cannot reuse an existing zone, we have 3992135446Strhodes * to create a new one. 3993135446Strhodes */ 3994254897Serwin CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone)); 3995135446Strhodes CHECK(dns_zone_setorigin(zone, origin)); 3996135446Strhodes dns_zone_setview(zone, view); 3997170222Sdougb if (view->acache != NULL) 3998170222Sdougb dns_zone_setacache(zone, view->acache); 3999135446Strhodes CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 4000193149Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 4001135446Strhodes } 4002135446Strhodes 4003254402Serwin if (is_rpz) { 4004254402Serwin result = dns_zone_rpz_enable(zone); 4005254402Serwin if (result != ISC_R_SUCCESS) { 4006254402Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4007254402Serwin NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4008254402Serwin "zone '%s': incompatible" 4009254402Serwin " masterfile-format or database" 4010254402Serwin " for a response policy zone", 4011254402Serwin zname); 4012254402Serwin goto cleanup; 4013254402Serwin } 4014254402Serwin } 4015254402Serwin 4016135446Strhodes /* 4017135446Strhodes * If the zone contains a 'forwarders' statement, configure 4018135446Strhodes * selective forwarding. 4019135446Strhodes */ 4020135446Strhodes forwarders = NULL; 4021135446Strhodes if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 4022135446Strhodes { 4023135446Strhodes forwardtype = NULL; 4024135446Strhodes (void)cfg_map_get(zoptions, "forward", &forwardtype); 4025135446Strhodes CHECK(configure_forward(config, view, origin, forwarders, 4026135446Strhodes forwardtype)); 4027135446Strhodes } 4028135446Strhodes 4029135446Strhodes /* 4030135446Strhodes * Stub and forward zones may also refer to delegation only points. 4031135446Strhodes */ 4032135446Strhodes only = NULL; 4033135446Strhodes if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 4034135446Strhodes { 4035135446Strhodes if (cfg_obj_asboolean(only)) 4036135446Strhodes CHECK(dns_view_adddelegationonly(view, origin)); 4037135446Strhodes } 4038135446Strhodes 4039135446Strhodes /* 4040224092Sdougb * Mark whether the zone was originally added at runtime or not 4041224092Sdougb */ 4042224092Sdougb dns_zone_setadded(zone, added); 4043224092Sdougb 4044254897Serwin signing = NULL; 4045254897Serwin if ((strcasecmp(ztypestr, "master") == 0 || 4046254897Serwin strcasecmp(ztypestr, "slave") == 0) && 4047254897Serwin cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS && 4048254897Serwin cfg_obj_asboolean(signing)) 4049254897Serwin { 4050254897Serwin dns_zone_getraw(zone, &raw); 4051254897Serwin if (raw == NULL) { 4052254897Serwin CHECK(dns_zone_create(&raw, mctx)); 4053254897Serwin CHECK(dns_zone_setorigin(raw, origin)); 4054254897Serwin dns_zone_setview(raw, view); 4055254897Serwin if (view->acache != NULL) 4056254897Serwin dns_zone_setacache(raw, view->acache); 4057254897Serwin dns_zone_setstats(raw, ns_g_server->zonestats); 4058254897Serwin CHECK(dns_zone_link(zone, raw)); 4059254897Serwin } 4060254897Serwin } 4061254897Serwin 4062224092Sdougb /* 4063135446Strhodes * Configure the zone. 4064135446Strhodes */ 4065254897Serwin CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw)); 4066135446Strhodes 4067135446Strhodes /* 4068135446Strhodes * Add the zone to its view in the new view list. 4069135446Strhodes */ 4070135446Strhodes CHECK(dns_view_addzone(view, zone)); 4071135446Strhodes 4072234010Sdougb /* 4073234010Sdougb * Ensure that zone keys are reloaded on reconfig 4074234010Sdougb */ 4075234010Sdougb if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) 4076234010Sdougb dns_zone_rekey(zone, ISC_FALSE); 4077234010Sdougb 4078135446Strhodes cleanup: 4079135446Strhodes if (zone != NULL) 4080135446Strhodes dns_zone_detach(&zone); 4081254897Serwin if (raw != NULL) 4082254897Serwin dns_zone_detach(&raw); 4083135446Strhodes if (pview != NULL) 4084135446Strhodes dns_view_detach(&pview); 4085135446Strhodes 4086135446Strhodes return (result); 4087135446Strhodes} 4088135446Strhodes 4089135446Strhodes/* 4090224092Sdougb * Configure built-in zone for storing managed-key data. 4091224092Sdougb */ 4092224092Sdougb 4093224092Sdougb#define KEYZONE "managed-keys.bind" 4094224092Sdougb#define MKEYS ".mkeys" 4095224092Sdougb 4096224092Sdougbstatic isc_result_t 4097224092Sdougbadd_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { 4098224092Sdougb isc_result_t result; 4099224092Sdougb dns_view_t *pview = NULL; 4100224092Sdougb dns_zone_t *zone = NULL; 4101224092Sdougb dns_acl_t *none = NULL; 4102224092Sdougb char filename[PATH_MAX]; 4103224092Sdougb char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)]; 4104224092Sdougb int n; 4105224092Sdougb 4106224092Sdougb REQUIRE(view != NULL); 4107224092Sdougb 4108224092Sdougb /* See if we can re-use an existing keydata zone. */ 4109224092Sdougb result = dns_viewlist_find(&ns_g_server->viewlist, 4110224092Sdougb view->name, view->rdclass, 4111224092Sdougb &pview); 4112224092Sdougb if (result != ISC_R_NOTFOUND && 4113224092Sdougb result != ISC_R_SUCCESS) 4114224092Sdougb return (result); 4115224092Sdougb 4116224092Sdougb if (pview != NULL && pview->managed_keys != NULL) { 4117224092Sdougb dns_zone_attach(pview->managed_keys, &view->managed_keys); 4118224092Sdougb dns_zone_setview(pview->managed_keys, view); 4119224092Sdougb dns_view_detach(&pview); 4120234010Sdougb dns_zone_synckeyzone(view->managed_keys); 4121224092Sdougb return (ISC_R_SUCCESS); 4122224092Sdougb } 4123224092Sdougb 4124224092Sdougb /* No existing keydata zone was found; create one */ 4125254897Serwin CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone)); 4126224092Sdougb CHECK(dns_zone_setorigin(zone, dns_rootname)); 4127224092Sdougb 4128224092Sdougb isc_sha256_data((void *)view->name, strlen(view->name), buffer); 4129224092Sdougb strcat(buffer, MKEYS); 4130224092Sdougb n = snprintf(filename, sizeof(filename), "%s%s%s", 4131224092Sdougb directory ? directory : "", directory ? "/" : "", 4132224092Sdougb strcmp(view->name, "_default") == 0 ? KEYZONE : buffer); 4133224092Sdougb if (n < 0 || (size_t)n >= sizeof(filename)) { 4134224092Sdougb result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE; 4135224092Sdougb goto cleanup; 4136224092Sdougb } 4137224092Sdougb CHECK(dns_zone_setfile(zone, filename)); 4138224092Sdougb 4139224092Sdougb dns_zone_setview(zone, view); 4140224092Sdougb dns_zone_settype(zone, dns_zone_key); 4141224092Sdougb dns_zone_setclass(zone, view->rdclass); 4142224092Sdougb 4143224092Sdougb CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 4144224092Sdougb 4145224092Sdougb if (view->acache != NULL) 4146224092Sdougb dns_zone_setacache(zone, view->acache); 4147224092Sdougb 4148224092Sdougb CHECK(dns_acl_none(mctx, &none)); 4149224092Sdougb dns_zone_setqueryacl(zone, none); 4150224092Sdougb dns_zone_setqueryonacl(zone, none); 4151224092Sdougb dns_acl_detach(&none); 4152224092Sdougb 4153224092Sdougb dns_zone_setdialup(zone, dns_dialuptype_no); 4154224092Sdougb dns_zone_setnotifytype(zone, dns_notifytype_no); 4155224092Sdougb dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); 4156224092Sdougb dns_zone_setjournalsize(zone, 0); 4157224092Sdougb 4158224092Sdougb dns_zone_setstats(zone, ns_g_server->zonestats); 4159254897Serwin CHECK(setquerystats(zone, mctx, dns_zonestat_none)); 4160224092Sdougb 4161224092Sdougb if (view->managed_keys != NULL) 4162224092Sdougb dns_zone_detach(&view->managed_keys); 4163224092Sdougb dns_zone_attach(zone, &view->managed_keys); 4164224092Sdougb 4165224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4166224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4167224092Sdougb "set up managed keys zone for view %s, file '%s'", 4168224092Sdougb view->name, filename); 4169224092Sdougb 4170224092Sdougbcleanup: 4171224092Sdougb if (zone != NULL) 4172224092Sdougb dns_zone_detach(&zone); 4173224092Sdougb if (none != NULL) 4174224092Sdougb dns_acl_detach(&none); 4175224092Sdougb 4176224092Sdougb return (result); 4177224092Sdougb} 4178224092Sdougb 4179224092Sdougb/* 4180135446Strhodes * Configure a single server quota. 4181135446Strhodes */ 4182135446Strhodesstatic void 4183165071Sdougbconfigure_server_quota(const cfg_obj_t **maps, const char *name, 4184165071Sdougb isc_quota_t *quota) 4185135446Strhodes{ 4186165071Sdougb const cfg_obj_t *obj = NULL; 4187135446Strhodes isc_result_t result; 4188135446Strhodes 4189135446Strhodes result = ns_config_get(maps, name, &obj); 4190135446Strhodes INSIST(result == ISC_R_SUCCESS); 4191153816Sdougb isc_quota_max(quota, cfg_obj_asuint32(obj)); 4192135446Strhodes} 4193135446Strhodes 4194135446Strhodes/* 4195135446Strhodes * This function is called as soon as the 'directory' statement has been 4196135446Strhodes * parsed. This can be extended to support other options if necessary. 4197135446Strhodes */ 4198135446Strhodesstatic isc_result_t 4199165071Sdougbdirectory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 4200135446Strhodes isc_result_t result; 4201165071Sdougb const char *directory; 4202135446Strhodes 4203135446Strhodes REQUIRE(strcasecmp("directory", clausename) == 0); 4204135446Strhodes 4205135446Strhodes UNUSED(arg); 4206135446Strhodes UNUSED(clausename); 4207135446Strhodes 4208135446Strhodes /* 4209135446Strhodes * Change directory. 4210135446Strhodes */ 4211135446Strhodes directory = cfg_obj_asstring(obj); 4212135446Strhodes 4213135446Strhodes if (! isc_file_ischdiridempotent(directory)) 4214135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 4215135446Strhodes "option 'directory' contains relative path '%s'", 4216135446Strhodes directory); 4217135446Strhodes 4218135446Strhodes result = isc_dir_chdir(directory); 4219135446Strhodes if (result != ISC_R_SUCCESS) { 4220135446Strhodes cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 4221135446Strhodes "change directory to '%s' failed: %s", 4222135446Strhodes directory, isc_result_totext(result)); 4223135446Strhodes return (result); 4224135446Strhodes } 4225135446Strhodes 4226135446Strhodes return (ISC_R_SUCCESS); 4227135446Strhodes} 4228135446Strhodes 4229135446Strhodesstatic void 4230135446Strhodesscan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 4231135446Strhodes isc_boolean_t match_mapped = server->aclenv.match_mapped; 4232135446Strhodes 4233135446Strhodes ns_interfacemgr_scan(server->interfacemgr, verbose); 4234135446Strhodes /* 4235135446Strhodes * Update the "localhost" and "localnets" ACLs to match the 4236135446Strhodes * current set of network interfaces. 4237135446Strhodes */ 4238135446Strhodes dns_aclenv_copy(&server->aclenv, 4239135446Strhodes ns_interfacemgr_getaclenv(server->interfacemgr)); 4240135446Strhodes 4241135446Strhodes server->aclenv.match_mapped = match_mapped; 4242135446Strhodes} 4243135446Strhodes 4244135446Strhodesstatic isc_result_t 4245180477Sdougbadd_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, 4246180477Sdougb isc_boolean_t wcardport_ok) 4247180477Sdougb{ 4248135446Strhodes ns_listenelt_t *lelt = NULL; 4249135446Strhodes dns_acl_t *src_acl = NULL; 4250135446Strhodes isc_result_t result; 4251135446Strhodes isc_sockaddr_t any_sa6; 4252193149Sdougb isc_netaddr_t netaddr; 4253135446Strhodes 4254135446Strhodes REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 4255135446Strhodes 4256135446Strhodes isc_sockaddr_any6(&any_sa6); 4257180477Sdougb if (!isc_sockaddr_equal(&any_sa6, addr) && 4258180477Sdougb (wcardport_ok || isc_sockaddr_getport(addr) != 0)) { 4259193149Sdougb isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr); 4260135446Strhodes 4261193149Sdougb result = dns_acl_create(mctx, 0, &src_acl); 4262135446Strhodes if (result != ISC_R_SUCCESS) 4263135446Strhodes return (result); 4264193149Sdougb 4265193149Sdougb result = dns_iptable_addprefix(src_acl->iptable, 4266193149Sdougb &netaddr, 128, ISC_TRUE); 4267135446Strhodes if (result != ISC_R_SUCCESS) 4268135446Strhodes goto clean; 4269135446Strhodes 4270135446Strhodes result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 4271135446Strhodes src_acl, &lelt); 4272135446Strhodes if (result != ISC_R_SUCCESS) 4273135446Strhodes goto clean; 4274135446Strhodes ISC_LIST_APPEND(list->elts, lelt, link); 4275135446Strhodes } 4276135446Strhodes 4277135446Strhodes return (ISC_R_SUCCESS); 4278135446Strhodes 4279135446Strhodes clean: 4280135446Strhodes INSIST(lelt == NULL); 4281165071Sdougb dns_acl_detach(&src_acl); 4282135446Strhodes 4283135446Strhodes return (result); 4284135446Strhodes} 4285135446Strhodes 4286135446Strhodes/* 4287135446Strhodes * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 4288135446Strhodes * to update the listening interfaces accordingly. 4289135446Strhodes * We currently only consider IPv6, because this only affects IPv6 wildcard 4290135446Strhodes * sockets. 4291135446Strhodes */ 4292135446Strhodesstatic void 4293135446Strhodesadjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 4294135446Strhodes isc_result_t result; 4295135446Strhodes ns_listenlist_t *list = NULL; 4296135446Strhodes dns_view_t *view; 4297135446Strhodes dns_zone_t *zone, *next; 4298135446Strhodes isc_sockaddr_t addr, *addrp; 4299135446Strhodes 4300135446Strhodes result = ns_listenlist_create(mctx, &list); 4301135446Strhodes if (result != ISC_R_SUCCESS) 4302135446Strhodes return; 4303135446Strhodes 4304135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 4305135446Strhodes view != NULL; 4306135446Strhodes view = ISC_LIST_NEXT(view, link)) { 4307135446Strhodes dns_dispatch_t *dispatch6; 4308135446Strhodes 4309135446Strhodes dispatch6 = dns_resolver_dispatchv6(view->resolver); 4310143731Sdougb if (dispatch6 == NULL) 4311143731Sdougb continue; 4312135446Strhodes result = dns_dispatch_getlocaladdress(dispatch6, &addr); 4313135446Strhodes if (result != ISC_R_SUCCESS) 4314135446Strhodes goto fail; 4315180477Sdougb 4316180477Sdougb /* 4317180477Sdougb * We always add non-wildcard address regardless of whether 4318180477Sdougb * the port is 'any' (the fourth arg is TRUE): if the port is 4319180477Sdougb * specific, we need to add it since it may conflict with a 4320180477Sdougb * listening interface; if it's zero, we'll dynamically open 4321180477Sdougb * query ports, and some of them may override an existing 4322180477Sdougb * wildcard IPv6 port. 4323180477Sdougb */ 4324180477Sdougb result = add_listenelt(mctx, list, &addr, ISC_TRUE); 4325135446Strhodes if (result != ISC_R_SUCCESS) 4326135446Strhodes goto fail; 4327135446Strhodes } 4328135446Strhodes 4329135446Strhodes zone = NULL; 4330135446Strhodes for (result = dns_zone_first(server->zonemgr, &zone); 4331135446Strhodes result == ISC_R_SUCCESS; 4332135446Strhodes next = NULL, result = dns_zone_next(zone, &next), zone = next) { 4333135446Strhodes dns_view_t *zoneview; 4334135446Strhodes 4335135446Strhodes /* 4336135446Strhodes * At this point the zone list may contain a stale zone 4337135446Strhodes * just removed from the configuration. To see the validity, 4338135446Strhodes * check if the corresponding view is in our current view list. 4339153816Sdougb * There may also be old zones that are still in the process 4340153816Sdougb * of shutting down and have detached from their old view 4341153816Sdougb * (zoneview == NULL). 4342135446Strhodes */ 4343135446Strhodes zoneview = dns_zone_getview(zone); 4344153816Sdougb if (zoneview == NULL) 4345153816Sdougb continue; 4346135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 4347135446Strhodes view != NULL && view != zoneview; 4348135446Strhodes view = ISC_LIST_NEXT(view, link)) 4349135446Strhodes ; 4350135446Strhodes if (view == NULL) 4351135446Strhodes continue; 4352135446Strhodes 4353135446Strhodes addrp = dns_zone_getnotifysrc6(zone); 4354180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 4355135446Strhodes if (result != ISC_R_SUCCESS) 4356135446Strhodes goto fail; 4357135446Strhodes 4358135446Strhodes addrp = dns_zone_getxfrsource6(zone); 4359180477Sdougb result = add_listenelt(mctx, list, addrp, ISC_FALSE); 4360135446Strhodes if (result != ISC_R_SUCCESS) 4361135446Strhodes goto fail; 4362135446Strhodes } 4363135446Strhodes 4364135446Strhodes ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 4365186462Sdougb 4366135446Strhodes clean: 4367135446Strhodes ns_listenlist_detach(&list); 4368135446Strhodes return; 4369135446Strhodes 4370135446Strhodes fail: 4371135446Strhodes /* 4372135446Strhodes * Even when we failed the procedure, most of other interfaces 4373135446Strhodes * should work correctly. We therefore just warn it. 4374135446Strhodes */ 4375135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4376135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 4377135446Strhodes "could not adjust the listen-on list; " 4378135446Strhodes "some interfaces may not work"); 4379135446Strhodes goto clean; 4380135446Strhodes} 4381135446Strhodes 4382135446Strhodes/* 4383135446Strhodes * This event callback is invoked to do periodic network 4384135446Strhodes * interface scanning. 4385135446Strhodes */ 4386135446Strhodesstatic void 4387135446Strhodesinterface_timer_tick(isc_task_t *task, isc_event_t *event) { 4388135446Strhodes isc_result_t result; 4389135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 4390135446Strhodes INSIST(task == server->task); 4391135446Strhodes UNUSED(task); 4392135446Strhodes isc_event_free(&event); 4393135446Strhodes /* 4394135446Strhodes * XXX should scan interfaces unlocked and get exclusive access 4395135446Strhodes * only to replace ACLs. 4396135446Strhodes */ 4397135446Strhodes result = isc_task_beginexclusive(server->task); 4398135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 4399135446Strhodes scan_interfaces(server, ISC_FALSE); 4400135446Strhodes isc_task_endexclusive(server->task); 4401135446Strhodes} 4402135446Strhodes 4403135446Strhodesstatic void 4404135446Strhodesheartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 4405135446Strhodes ns_server_t *server = (ns_server_t *) event->ev_arg; 4406135446Strhodes dns_view_t *view; 4407135446Strhodes 4408135446Strhodes UNUSED(task); 4409135446Strhodes isc_event_free(&event); 4410135446Strhodes view = ISC_LIST_HEAD(server->viewlist); 4411135446Strhodes while (view != NULL) { 4412135446Strhodes dns_view_dialup(view); 4413135446Strhodes view = ISC_LIST_NEXT(view, link); 4414135446Strhodes } 4415135446Strhodes} 4416135446Strhodes 4417170222Sdougbstatic void 4418170222Sdougbpps_timer_tick(isc_task_t *task, isc_event_t *event) { 4419170222Sdougb static unsigned int oldrequests = 0; 4420170222Sdougb unsigned int requests = ns_client_requests; 4421170222Sdougb 4422170222Sdougb UNUSED(task); 4423170222Sdougb isc_event_free(&event); 4424170222Sdougb 4425170222Sdougb /* 4426170222Sdougb * Don't worry about wrapping as the overflow result will be right. 4427170222Sdougb */ 4428170222Sdougb dns_pps = (requests - oldrequests) / 1200; 4429170222Sdougb oldrequests = requests; 4430170222Sdougb} 4431170222Sdougb 4432135446Strhodes/* 4433135446Strhodes * Replace the current value of '*field', a dynamically allocated 4434135446Strhodes * string or NULL, with a dynamically allocated copy of the 4435135446Strhodes * null-terminated string pointed to by 'value', or NULL. 4436135446Strhodes */ 4437135446Strhodesstatic isc_result_t 4438135446Strhodessetstring(ns_server_t *server, char **field, const char *value) { 4439135446Strhodes char *copy; 4440135446Strhodes 4441135446Strhodes if (value != NULL) { 4442135446Strhodes copy = isc_mem_strdup(server->mctx, value); 4443135446Strhodes if (copy == NULL) 4444135446Strhodes return (ISC_R_NOMEMORY); 4445135446Strhodes } else { 4446135446Strhodes copy = NULL; 4447135446Strhodes } 4448135446Strhodes 4449135446Strhodes if (*field != NULL) 4450135446Strhodes isc_mem_free(server->mctx, *field); 4451135446Strhodes 4452135446Strhodes *field = copy; 4453135446Strhodes return (ISC_R_SUCCESS); 4454186462Sdougb} 4455135446Strhodes 4456135446Strhodes/* 4457135446Strhodes * Replace the current value of '*field', a dynamically allocated 4458135446Strhodes * string or NULL, with another dynamically allocated string 4459135446Strhodes * or NULL if whether 'obj' is a string or void value, respectively. 4460135446Strhodes */ 4461135446Strhodesstatic isc_result_t 4462165071Sdougbsetoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 4463135446Strhodes if (cfg_obj_isvoid(obj)) 4464135446Strhodes return (setstring(server, field, NULL)); 4465135446Strhodes else 4466135446Strhodes return (setstring(server, field, cfg_obj_asstring(obj))); 4467135446Strhodes} 4468135446Strhodes 4469135446Strhodesstatic void 4470165071Sdougbset_limit(const cfg_obj_t **maps, const char *configname, 4471165071Sdougb const char *description, isc_resource_t resourceid, 4472165071Sdougb isc_resourcevalue_t defaultvalue) 4473135446Strhodes{ 4474165071Sdougb const cfg_obj_t *obj = NULL; 4475165071Sdougb const char *resource; 4476135446Strhodes isc_resourcevalue_t value; 4477135446Strhodes isc_result_t result; 4478135446Strhodes 4479135446Strhodes if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 4480135446Strhodes return; 4481135446Strhodes 4482135446Strhodes if (cfg_obj_isstring(obj)) { 4483135446Strhodes resource = cfg_obj_asstring(obj); 4484135446Strhodes if (strcasecmp(resource, "unlimited") == 0) 4485135446Strhodes value = ISC_RESOURCE_UNLIMITED; 4486135446Strhodes else { 4487135446Strhodes INSIST(strcasecmp(resource, "default") == 0); 4488135446Strhodes value = defaultvalue; 4489135446Strhodes } 4490135446Strhodes } else 4491135446Strhodes value = cfg_obj_asuint64(obj); 4492135446Strhodes 4493135446Strhodes result = isc_resource_setlimit(resourceid, value); 4494135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4495135446Strhodes result == ISC_R_SUCCESS ? 4496186462Sdougb ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 4497204619Sdougb "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s", 4498135446Strhodes description, value, isc_result_totext(result)); 4499135446Strhodes} 4500135446Strhodes 4501135446Strhodes#define SETLIMIT(cfgvar, resource, description) \ 4502135446Strhodes set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 4503135446Strhodes ns_g_init ## resource) 4504135446Strhodes 4505135446Strhodesstatic void 4506165071Sdougbset_limits(const cfg_obj_t **maps) { 4507135446Strhodes SETLIMIT("stacksize", stacksize, "stack size"); 4508135446Strhodes SETLIMIT("datasize", datasize, "data size"); 4509135446Strhodes SETLIMIT("coresize", coresize, "core size"); 4510135446Strhodes SETLIMIT("files", openfiles, "open files"); 4511135446Strhodes} 4512135446Strhodes 4513186462Sdougbstatic void 4514186462Sdougbportset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports, 4515186462Sdougb isc_boolean_t positive) 4516135446Strhodes{ 4517165071Sdougb const cfg_listelt_t *element; 4518135446Strhodes 4519135446Strhodes for (element = cfg_list_first(ports); 4520135446Strhodes element != NULL; 4521135446Strhodes element = cfg_list_next(element)) { 4522165071Sdougb const cfg_obj_t *obj = cfg_listelt_value(element); 4523186462Sdougb 4524186462Sdougb if (cfg_obj_isuint32(obj)) { 4525186462Sdougb in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 4526186462Sdougb 4527186462Sdougb if (positive) 4528186462Sdougb isc_portset_add(portset, port); 4529186462Sdougb else 4530186462Sdougb isc_portset_remove(portset, port); 4531186462Sdougb } else { 4532186462Sdougb const cfg_obj_t *obj_loport, *obj_hiport; 4533186462Sdougb in_port_t loport, hiport; 4534186462Sdougb 4535186462Sdougb obj_loport = cfg_tuple_get(obj, "loport"); 4536186462Sdougb loport = (in_port_t)cfg_obj_asuint32(obj_loport); 4537186462Sdougb obj_hiport = cfg_tuple_get(obj, "hiport"); 4538186462Sdougb hiport = (in_port_t)cfg_obj_asuint32(obj_hiport); 4539186462Sdougb 4540186462Sdougb if (positive) 4541186462Sdougb isc_portset_addrange(portset, loport, hiport); 4542186462Sdougb else { 4543186462Sdougb isc_portset_removerange(portset, loport, 4544186462Sdougb hiport); 4545186462Sdougb } 4546186462Sdougb } 4547135446Strhodes } 4548135446Strhodes} 4549135446Strhodes 4550135446Strhodesstatic isc_result_t 4551170222Sdougbremoved(dns_zone_t *zone, void *uap) { 4552170222Sdougb const char *type; 4553170222Sdougb 4554186462Sdougb if (dns_zone_getview(zone) != uap) 4555170222Sdougb return (ISC_R_SUCCESS); 4556170222Sdougb 4557170222Sdougb switch (dns_zone_gettype(zone)) { 4558170222Sdougb case dns_zone_master: 4559170222Sdougb type = "master"; 4560170222Sdougb break; 4561170222Sdougb case dns_zone_slave: 4562170222Sdougb type = "slave"; 4563170222Sdougb break; 4564170222Sdougb case dns_zone_stub: 4565170222Sdougb type = "stub"; 4566170222Sdougb break; 4567254897Serwin case dns_zone_redirect: 4568254897Serwin type = "redirect"; 4569254897Serwin break; 4570170222Sdougb default: 4571170222Sdougb type = "other"; 4572170222Sdougb break; 4573170222Sdougb } 4574170222Sdougb dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type); 4575170222Sdougb return (ISC_R_SUCCESS); 4576170222Sdougb} 4577170222Sdougb 4578224092Sdougbstatic void 4579224092Sdougbcleanup_session_key(ns_server_t *server, isc_mem_t *mctx) { 4580224092Sdougb if (server->session_keyfile != NULL) { 4581224092Sdougb isc_file_remove(server->session_keyfile); 4582224092Sdougb isc_mem_free(mctx, server->session_keyfile); 4583224092Sdougb server->session_keyfile = NULL; 4584224092Sdougb } 4585224092Sdougb 4586224092Sdougb if (server->session_keyname != NULL) { 4587224092Sdougb if (dns_name_dynamic(server->session_keyname)) 4588224092Sdougb dns_name_free(server->session_keyname, mctx); 4589224092Sdougb isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t)); 4590224092Sdougb server->session_keyname = NULL; 4591224092Sdougb } 4592224092Sdougb 4593224092Sdougb if (server->sessionkey != NULL) 4594224092Sdougb dns_tsigkey_detach(&server->sessionkey); 4595224092Sdougb 4596224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 4597224092Sdougb server->session_keybits = 0; 4598224092Sdougb} 4599224092Sdougb 4600170222Sdougbstatic isc_result_t 4601224092Sdougbgenerate_session_key(const char *filename, const char *keynamestr, 4602224092Sdougb dns_name_t *keyname, const char *algstr, 4603224092Sdougb dns_name_t *algname, unsigned int algtype, 4604224092Sdougb isc_uint16_t bits, isc_mem_t *mctx, 4605224092Sdougb dns_tsigkey_t **tsigkeyp) 4606224092Sdougb{ 4607224092Sdougb isc_result_t result = ISC_R_SUCCESS; 4608224092Sdougb dst_key_t *key = NULL; 4609224092Sdougb isc_buffer_t key_txtbuffer; 4610224092Sdougb isc_buffer_t key_rawbuffer; 4611224092Sdougb char key_txtsecret[256]; 4612224092Sdougb char key_rawsecret[64]; 4613224092Sdougb isc_region_t key_rawregion; 4614224092Sdougb isc_stdtime_t now; 4615224092Sdougb dns_tsigkey_t *tsigkey = NULL; 4616224092Sdougb FILE *fp = NULL; 4617224092Sdougb 4618224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4619224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4620224092Sdougb "generating session key for dynamic DNS"); 4621224092Sdougb 4622224092Sdougb /* generate key */ 4623224092Sdougb result = dst_key_generate(keyname, algtype, bits, 1, 0, 4624224092Sdougb DNS_KEYPROTO_ANY, dns_rdataclass_in, 4625224092Sdougb mctx, &key); 4626224092Sdougb if (result != ISC_R_SUCCESS) 4627224092Sdougb return (result); 4628224092Sdougb 4629224092Sdougb /* 4630224092Sdougb * Dump the key to the buffer for later use. Should be done before 4631224092Sdougb * we transfer the ownership of key to tsigkey. 4632224092Sdougb */ 4633224092Sdougb isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); 4634224092Sdougb CHECK(dst_key_tobuffer(key, &key_rawbuffer)); 4635224092Sdougb 4636224092Sdougb isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); 4637224092Sdougb isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); 4638224092Sdougb CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer)); 4639224092Sdougb 4640224092Sdougb /* Store the key in tsigkey. */ 4641224092Sdougb isc_stdtime_get(&now); 4642224092Sdougb CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, 4643224092Sdougb ISC_FALSE, NULL, now, now, mctx, NULL, 4644224092Sdougb &tsigkey)); 4645224092Sdougb 4646224092Sdougb /* Dump the key to the key file. */ 4647224092Sdougb fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE); 4648224092Sdougb if (fp == NULL) { 4649224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4650224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4651224092Sdougb "could not create %s", filename); 4652224092Sdougb result = ISC_R_NOPERM; 4653224092Sdougb goto cleanup; 4654224092Sdougb } 4655224092Sdougb 4656224092Sdougb fprintf(fp, "key \"%s\" {\n" 4657224092Sdougb "\talgorithm %s;\n" 4658224092Sdougb "\tsecret \"%.*s\";\n};\n", keynamestr, algstr, 4659224092Sdougb (int) isc_buffer_usedlength(&key_txtbuffer), 4660224092Sdougb (char*) isc_buffer_base(&key_txtbuffer)); 4661224092Sdougb 4662224092Sdougb RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS); 4663224092Sdougb RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS); 4664224092Sdougb 4665224092Sdougb dst_key_free(&key); 4666224092Sdougb 4667224092Sdougb *tsigkeyp = tsigkey; 4668224092Sdougb 4669224092Sdougb return (ISC_R_SUCCESS); 4670224092Sdougb 4671224092Sdougb cleanup: 4672224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4673224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 4674224092Sdougb "failed to generate session key " 4675224092Sdougb "for dynamic DNS: %s", isc_result_totext(result)); 4676224092Sdougb if (tsigkey != NULL) 4677224092Sdougb dns_tsigkey_detach(&tsigkey); 4678224092Sdougb if (key != NULL) 4679224092Sdougb dst_key_free(&key); 4680224092Sdougb 4681224092Sdougb return (result); 4682224092Sdougb} 4683224092Sdougb 4684224092Sdougbstatic isc_result_t 4685224092Sdougbconfigure_session_key(const cfg_obj_t **maps, ns_server_t *server, 4686224092Sdougb isc_mem_t *mctx) 4687224092Sdougb{ 4688224092Sdougb const char *keyfile, *keynamestr, *algstr; 4689224092Sdougb unsigned int algtype; 4690224092Sdougb dns_fixedname_t fname; 4691224092Sdougb dns_name_t *keyname, *algname; 4692224092Sdougb isc_buffer_t buffer; 4693224092Sdougb isc_uint16_t bits; 4694224092Sdougb const cfg_obj_t *obj; 4695224092Sdougb isc_boolean_t need_deleteold = ISC_FALSE; 4696224092Sdougb isc_boolean_t need_createnew = ISC_FALSE; 4697224092Sdougb isc_result_t result; 4698224092Sdougb 4699224092Sdougb obj = NULL; 4700224092Sdougb result = ns_config_get(maps, "session-keyfile", &obj); 4701224092Sdougb if (result == ISC_R_SUCCESS) { 4702224092Sdougb if (cfg_obj_isvoid(obj)) 4703224092Sdougb keyfile = NULL; /* disable it */ 4704224092Sdougb else 4705224092Sdougb keyfile = cfg_obj_asstring(obj); 4706224092Sdougb } else 4707224092Sdougb keyfile = ns_g_defaultsessionkeyfile; 4708224092Sdougb 4709224092Sdougb obj = NULL; 4710224092Sdougb result = ns_config_get(maps, "session-keyname", &obj); 4711224092Sdougb INSIST(result == ISC_R_SUCCESS); 4712224092Sdougb keynamestr = cfg_obj_asstring(obj); 4713224092Sdougb dns_fixedname_init(&fname); 4714254402Serwin isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr)); 4715224092Sdougb isc_buffer_add(&buffer, strlen(keynamestr)); 4716224092Sdougb keyname = dns_fixedname_name(&fname); 4717224092Sdougb result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL); 4718224092Sdougb if (result != ISC_R_SUCCESS) 4719224092Sdougb return (result); 4720224092Sdougb 4721224092Sdougb obj = NULL; 4722224092Sdougb result = ns_config_get(maps, "session-keyalg", &obj); 4723224092Sdougb INSIST(result == ISC_R_SUCCESS); 4724224092Sdougb algstr = cfg_obj_asstring(obj); 4725224092Sdougb algname = NULL; 4726224092Sdougb result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits); 4727224092Sdougb if (result != ISC_R_SUCCESS) { 4728224092Sdougb const char *s = " (keeping current key)"; 4729224092Sdougb 4730224092Sdougb cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: " 4731224092Sdougb "unsupported or unknown algorithm '%s'%s", 4732224092Sdougb algstr, 4733224092Sdougb server->session_keyfile != NULL ? s : ""); 4734224092Sdougb return (result); 4735224092Sdougb } 4736224092Sdougb 4737224092Sdougb /* See if we need to (re)generate a new key. */ 4738224092Sdougb if (keyfile == NULL) { 4739224092Sdougb if (server->session_keyfile != NULL) 4740224092Sdougb need_deleteold = ISC_TRUE; 4741224092Sdougb } else if (server->session_keyfile == NULL) 4742224092Sdougb need_createnew = ISC_TRUE; 4743224092Sdougb else if (strcmp(keyfile, server->session_keyfile) != 0 || 4744224092Sdougb !dns_name_equal(server->session_keyname, keyname) || 4745224092Sdougb server->session_keyalg != algtype || 4746224092Sdougb server->session_keybits != bits) { 4747224092Sdougb need_deleteold = ISC_TRUE; 4748224092Sdougb need_createnew = ISC_TRUE; 4749224092Sdougb } 4750224092Sdougb 4751224092Sdougb if (need_deleteold) { 4752224092Sdougb INSIST(server->session_keyfile != NULL); 4753224092Sdougb INSIST(server->session_keyname != NULL); 4754224092Sdougb INSIST(server->sessionkey != NULL); 4755224092Sdougb 4756224092Sdougb cleanup_session_key(server, mctx); 4757224092Sdougb } 4758224092Sdougb 4759224092Sdougb if (need_createnew) { 4760224092Sdougb INSIST(server->sessionkey == NULL); 4761224092Sdougb INSIST(server->session_keyfile == NULL); 4762224092Sdougb INSIST(server->session_keyname == NULL); 4763224092Sdougb INSIST(server->session_keyalg == DST_ALG_UNKNOWN); 4764224092Sdougb INSIST(server->session_keybits == 0); 4765224092Sdougb 4766224092Sdougb server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t)); 4767224092Sdougb if (server->session_keyname == NULL) 4768224092Sdougb goto cleanup; 4769224092Sdougb dns_name_init(server->session_keyname, NULL); 4770224092Sdougb CHECK(dns_name_dup(keyname, mctx, server->session_keyname)); 4771224092Sdougb 4772224092Sdougb server->session_keyfile = isc_mem_strdup(mctx, keyfile); 4773224092Sdougb if (server->session_keyfile == NULL) 4774224092Sdougb goto cleanup; 4775224092Sdougb 4776224092Sdougb server->session_keyalg = algtype; 4777224092Sdougb server->session_keybits = bits; 4778224092Sdougb 4779224092Sdougb CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr, 4780224092Sdougb algname, algtype, bits, mctx, 4781224092Sdougb &server->sessionkey)); 4782224092Sdougb } 4783224092Sdougb 4784224092Sdougb return (result); 4785224092Sdougb 4786224092Sdougb cleanup: 4787224092Sdougb cleanup_session_key(server, mctx); 4788224092Sdougb return (result); 4789224092Sdougb} 4790224092Sdougb 4791224092Sdougbstatic isc_result_t 4792225361Sdougbsetup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, 4793225361Sdougb cfg_parser_t *parser, cfg_aclconfctx_t *actx) 4794225361Sdougb{ 4795225361Sdougb isc_result_t result = ISC_R_SUCCESS; 4796225361Sdougb isc_boolean_t allow = ISC_FALSE; 4797225361Sdougb struct cfg_context *nzcfg = NULL; 4798225361Sdougb cfg_parser_t *nzparser = NULL; 4799225361Sdougb cfg_obj_t *nzconfig = NULL; 4800225361Sdougb const cfg_obj_t *maps[4]; 4801225361Sdougb const cfg_obj_t *options = NULL, *voptions = NULL; 4802225361Sdougb const cfg_obj_t *nz = NULL; 4803225361Sdougb int i = 0; 4804225361Sdougb 4805225361Sdougb REQUIRE (config != NULL); 4806225361Sdougb 4807225361Sdougb if (vconfig != NULL) 4808225361Sdougb voptions = cfg_tuple_get(vconfig, "options"); 4809225361Sdougb if (voptions != NULL) 4810225361Sdougb maps[i++] = voptions; 4811225361Sdougb result = cfg_map_get(config, "options", &options); 4812225361Sdougb if (result == ISC_R_SUCCESS) 4813225361Sdougb maps[i++] = options; 4814225361Sdougb maps[i++] = ns_g_defaults; 4815225361Sdougb maps[i] = NULL; 4816225361Sdougb 4817225361Sdougb result = ns_config_get(maps, "allow-new-zones", &nz); 4818225361Sdougb if (result == ISC_R_SUCCESS) 4819225361Sdougb allow = cfg_obj_asboolean(nz); 4820225361Sdougb 4821225361Sdougb if (!allow) { 4822225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4823225361Sdougb return (ISC_R_SUCCESS); 4824225361Sdougb } 4825225361Sdougb 4826225361Sdougb nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg)); 4827225361Sdougb if (nzcfg == NULL) { 4828225361Sdougb dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); 4829225361Sdougb return (ISC_R_NOMEMORY); 4830225361Sdougb } 4831225361Sdougb 4832225361Sdougb dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy); 4833225361Sdougb 4834225361Sdougb memset(nzcfg, 0, sizeof(*nzcfg)); 4835225361Sdougb isc_mem_attach(view->mctx, &nzcfg->mctx); 4836225361Sdougb cfg_obj_attach(config, &nzcfg->config); 4837225361Sdougb cfg_parser_attach(parser, &nzcfg->parser); 4838225361Sdougb cfg_aclconfctx_attach(actx, &nzcfg->actx); 4839225361Sdougb 4840225361Sdougb /* 4841225361Sdougb * Attempt to create a parser and parse the newzones 4842225361Sdougb * file. If successful, preserve both; otherwise leave 4843225361Sdougb * them NULL. 4844225361Sdougb */ 4845225361Sdougb result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser); 4846225361Sdougb if (result == ISC_R_SUCCESS) 4847225361Sdougb result = cfg_parse_file(nzparser, view->new_zone_file, 4848225361Sdougb &cfg_type_newzones, &nzconfig); 4849225361Sdougb if (result == ISC_R_SUCCESS) { 4850225361Sdougb cfg_parser_attach(nzparser, &nzcfg->nzparser); 4851225361Sdougb cfg_obj_attach(nzconfig, &nzcfg->nzconfig); 4852225361Sdougb } 4853225361Sdougb 4854225361Sdougb if (nzparser != NULL) { 4855225361Sdougb if (nzconfig != NULL) 4856225361Sdougb cfg_obj_destroy(nzparser, &nzconfig); 4857225361Sdougb cfg_parser_destroy(&nzparser); 4858225361Sdougb } 4859225361Sdougb 4860225361Sdougb return (ISC_R_SUCCESS); 4861225361Sdougb} 4862225361Sdougb 4863225361Sdougbstatic int 4864225361Sdougbcount_zones(const cfg_obj_t *conf) { 4865225361Sdougb const cfg_obj_t *zonelist = NULL; 4866225361Sdougb const cfg_listelt_t *element; 4867225361Sdougb int n = 0; 4868225361Sdougb 4869225361Sdougb REQUIRE(conf != NULL); 4870225361Sdougb 4871225361Sdougb cfg_map_get(conf, "zone", &zonelist); 4872225361Sdougb for (element = cfg_list_first(zonelist); 4873225361Sdougb element != NULL; 4874225361Sdougb element = cfg_list_next(element)) 4875225361Sdougb n++; 4876225361Sdougb 4877225361Sdougb return (n); 4878225361Sdougb} 4879225361Sdougb 4880225361Sdougbstatic isc_result_t 4881135446Strhodesload_configuration(const char *filename, ns_server_t *server, 4882135446Strhodes isc_boolean_t first_time) 4883135446Strhodes{ 4884224092Sdougb cfg_obj_t *config = NULL, *bindkeys = NULL; 4885224092Sdougb cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL; 4886182645Sdougb const cfg_listelt_t *element; 4887182645Sdougb const cfg_obj_t *builtin_views; 4888182645Sdougb const cfg_obj_t *maps[3]; 4889182645Sdougb const cfg_obj_t *obj; 4890165071Sdougb const cfg_obj_t *options; 4891186462Sdougb const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports; 4892165071Sdougb const cfg_obj_t *views; 4893135446Strhodes dns_view_t *view = NULL; 4894135446Strhodes dns_view_t *view_next; 4895182645Sdougb dns_viewlist_t tmpviewlist; 4896224092Sdougb dns_viewlist_t viewlist, builtin_viewlist; 4897186462Sdougb in_port_t listen_port, udpport_low, udpport_high; 4898182645Sdougb int i; 4899262706Serwin int num_zones = 0; 4900262706Serwin isc_boolean_t exclusive = ISC_FALSE; 4901182645Sdougb isc_interval_t interval; 4902262706Serwin isc_logconfig_t *logc = NULL; 4903186462Sdougb isc_portset_t *v4portset = NULL; 4904186462Sdougb isc_portset_t *v6portset = NULL; 4905186462Sdougb isc_resourcevalue_t nfiles; 4906182645Sdougb isc_result_t result; 4907182645Sdougb isc_uint32_t heartbeat_interval; 4908135446Strhodes isc_uint32_t interface_interval; 4909182645Sdougb isc_uint32_t reserved; 4910135446Strhodes isc_uint32_t udpsize; 4911262706Serwin ns_cache_t *nsc; 4912224092Sdougb ns_cachelist_t cachelist, tmpcachelist; 4913262706Serwin struct cfg_context *nzctx; 4914186462Sdougb unsigned int maxsocks; 4915135446Strhodes 4916135446Strhodes ISC_LIST_INIT(viewlist); 4917224092Sdougb ISC_LIST_INIT(builtin_viewlist); 4918224092Sdougb ISC_LIST_INIT(cachelist); 4919135446Strhodes 4920225361Sdougb /* Create the ACL configuration context */ 4921225361Sdougb if (ns_g_aclconfctx != NULL) 4922225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 4923225361Sdougb CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx)); 4924225361Sdougb 4925135446Strhodes /* 4926135446Strhodes * Parse the global default pseudo-config file. 4927135446Strhodes */ 4928135446Strhodes if (first_time) { 4929135446Strhodes CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 4930135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 4931224092Sdougb &ns_g_defaults) == ISC_R_SUCCESS); 4932135446Strhodes } 4933135446Strhodes 4934135446Strhodes /* 4935135446Strhodes * Parse the configuration file using the new config code. 4936135446Strhodes */ 4937135446Strhodes result = ISC_R_FAILURE; 4938135446Strhodes config = NULL; 4939135446Strhodes 4940135446Strhodes /* 4941135446Strhodes * Unless this is lwresd with the -C option, parse the config file. 4942135446Strhodes */ 4943135446Strhodes if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 4944135446Strhodes isc_log_write(ns_g_lctx, 4945135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4946135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4947135446Strhodes filename); 4948224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4949224092Sdougb cfg_parser_setcallback(conf_parser, directory_callback, NULL); 4950224092Sdougb result = cfg_parse_file(conf_parser, filename, 4951224092Sdougb &cfg_type_namedconf, &config); 4952135446Strhodes } 4953135446Strhodes 4954135446Strhodes /* 4955135446Strhodes * If this is lwresd with the -C option, or lwresd with no -C or -c 4956135446Strhodes * option where the above parsing failed, parse resolv.conf. 4957135446Strhodes */ 4958135446Strhodes if (ns_g_lwresdonly && 4959135446Strhodes (lwresd_g_useresolvconf || 4960135446Strhodes (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 4961135446Strhodes { 4962135446Strhodes isc_log_write(ns_g_lctx, 4963135446Strhodes NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 4964135446Strhodes ISC_LOG_INFO, "loading configuration from '%s'", 4965135446Strhodes lwresd_g_resolvconffile); 4966224092Sdougb if (conf_parser != NULL) 4967224092Sdougb cfg_parser_destroy(&conf_parser); 4968224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser)); 4969224092Sdougb result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser, 4970135446Strhodes &config); 4971135446Strhodes } 4972135446Strhodes CHECK(result); 4973135446Strhodes 4974135446Strhodes /* 4975135446Strhodes * Check the validity of the configuration. 4976135446Strhodes */ 4977135446Strhodes CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 4978135446Strhodes 4979135446Strhodes /* 4980135446Strhodes * Fill in the maps array, used for resolving defaults. 4981135446Strhodes */ 4982135446Strhodes i = 0; 4983135446Strhodes options = NULL; 4984135446Strhodes result = cfg_map_get(config, "options", &options); 4985135446Strhodes if (result == ISC_R_SUCCESS) 4986135446Strhodes maps[i++] = options; 4987135446Strhodes maps[i++] = ns_g_defaults; 4988225361Sdougb maps[i] = NULL; 4989135446Strhodes 4990135446Strhodes /* 4991224092Sdougb * If bind.keys exists, load it. If "dnssec-lookaside auto" 4992224092Sdougb * is turned on, the keys found there will be used as default 4993224092Sdougb * trust anchors. 4994224092Sdougb */ 4995224092Sdougb obj = NULL; 4996224092Sdougb result = ns_config_get(maps, "bindkeys-file", &obj); 4997224092Sdougb INSIST(result == ISC_R_SUCCESS); 4998224092Sdougb CHECKM(setstring(server, &server->bindkeysfile, 4999224092Sdougb cfg_obj_asstring(obj)), "strdup"); 5000224092Sdougb 5001224092Sdougb if (access(server->bindkeysfile, R_OK) == 0) { 5002224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5003224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5004224092Sdougb "reading built-in trusted " 5005224092Sdougb "keys from file '%s'", server->bindkeysfile); 5006224092Sdougb 5007224092Sdougb CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, 5008224092Sdougb &bindkeys_parser)); 5009224092Sdougb 5010224092Sdougb result = cfg_parse_file(bindkeys_parser, server->bindkeysfile, 5011224092Sdougb &cfg_type_bindkeys, &bindkeys); 5012224092Sdougb CHECK(result); 5013224092Sdougb } 5014224092Sdougb 5015234010Sdougb /* Ensure exclusive access to configuration data. */ 5016234010Sdougb if (!exclusive) { 5017234010Sdougb result = isc_task_beginexclusive(server->task); 5018234010Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 5019234010Sdougb exclusive = ISC_TRUE; 5020234010Sdougb } 5021234010Sdougb 5022224092Sdougb /* 5023135446Strhodes * Set process limits, which (usually) needs to be done as root. 5024135446Strhodes */ 5025135446Strhodes set_limits(maps); 5026135446Strhodes 5027135446Strhodes /* 5028186462Sdougb * Check if max number of open sockets that the system allows is 5029224092Sdougb * sufficiently large. Failing this condition is not necessarily fatal, 5030186462Sdougb * but may cause subsequent runtime failures for a busy recursive 5031186462Sdougb * server. 5032182645Sdougb */ 5033186462Sdougb result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks); 5034186462Sdougb if (result != ISC_R_SUCCESS) 5035186462Sdougb maxsocks = 0; 5036186462Sdougb result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles); 5037186462Sdougb if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) { 5038182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5039182645Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 5040186462Sdougb "max open files (%" ISC_PRINT_QUADFORMAT "u)" 5041186462Sdougb " is smaller than max sockets (%u)", 5042186462Sdougb nfiles, maxsocks); 5043186462Sdougb } 5044182645Sdougb 5045182645Sdougb /* 5046182645Sdougb * Set the number of socket reserved for TCP, stdio etc. 5047182645Sdougb */ 5048182645Sdougb obj = NULL; 5049182645Sdougb result = ns_config_get(maps, "reserved-sockets", &obj); 5050182645Sdougb INSIST(result == ISC_R_SUCCESS); 5051182645Sdougb reserved = cfg_obj_asuint32(obj); 5052186462Sdougb if (maxsocks != 0) { 5053186462Sdougb if (maxsocks < 128U) /* Prevent underflow. */ 5054186462Sdougb reserved = 0; 5055186462Sdougb else if (reserved > maxsocks - 128U) /* Minimum UDP space. */ 5056186462Sdougb reserved = maxsocks - 128; 5057186462Sdougb } 5058186462Sdougb /* Minimum TCP/stdio space. */ 5059186462Sdougb if (reserved < 128U) 5060182645Sdougb reserved = 128; 5061186462Sdougb if (reserved + 128U > maxsocks && maxsocks != 0) { 5062182645Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5063186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 5064182645Sdougb "less than 128 UDP sockets available after " 5065186462Sdougb "applying 'reserved-sockets' and 'maxsockets'"); 5066182645Sdougb } 5067182645Sdougb isc__socketmgr_setreserved(ns_g_socketmgr, reserved); 5068186462Sdougb 5069182645Sdougb /* 5070135446Strhodes * Configure various server options. 5071135446Strhodes */ 5072135446Strhodes configure_server_quota(maps, "transfers-out", &server->xfroutquota); 5073135446Strhodes configure_server_quota(maps, "tcp-clients", &server->tcpquota); 5074135446Strhodes configure_server_quota(maps, "recursive-clients", 5075135446Strhodes &server->recursionquota); 5076153816Sdougb if (server->recursionquota.max > 1000) 5077153816Sdougb isc_quota_soft(&server->recursionquota, 5078153816Sdougb server->recursionquota.max - 100); 5079153816Sdougb else 5080153816Sdougb isc_quota_soft(&server->recursionquota, 0); 5081135446Strhodes 5082225361Sdougb CHECK(configure_view_acl(NULL, config, "blackhole", NULL, 5083225361Sdougb ns_g_aclconfctx, ns_g_mctx, 5084225361Sdougb &server->blackholeacl)); 5085135446Strhodes if (server->blackholeacl != NULL) 5086135446Strhodes dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 5087135446Strhodes server->blackholeacl); 5088135446Strhodes 5089135446Strhodes obj = NULL; 5090135446Strhodes result = ns_config_get(maps, "match-mapped-addresses", &obj); 5091135446Strhodes INSIST(result == ISC_R_SUCCESS); 5092135446Strhodes server->aclenv.match_mapped = cfg_obj_asboolean(obj); 5093135446Strhodes 5094225361Sdougb CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx), 5095193149Sdougb "configuring statistics server(s)"); 5096193149Sdougb 5097186462Sdougb /* 5098186462Sdougb * Configure sets of UDP query source ports. 5099186462Sdougb */ 5100186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v4portset), 5101186462Sdougb "creating UDP port set"); 5102186462Sdougb CHECKM(isc_portset_create(ns_g_mctx, &v6portset), 5103186462Sdougb "creating UDP port set"); 5104135446Strhodes 5105186462Sdougb usev4ports = NULL; 5106186462Sdougb usev6ports = NULL; 5107186462Sdougb avoidv4ports = NULL; 5108186462Sdougb avoidv6ports = NULL; 5109186462Sdougb 5110186462Sdougb (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports); 5111186462Sdougb if (usev4ports != NULL) 5112186462Sdougb portset_fromconf(v4portset, usev4ports, ISC_TRUE); 5113186462Sdougb else { 5114186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low, 5115186462Sdougb &udpport_high), 5116186462Sdougb "get the default UDP/IPv4 port range"); 5117186462Sdougb if (udpport_low == udpport_high) 5118186462Sdougb isc_portset_add(v4portset, udpport_low); 5119186462Sdougb else { 5120186462Sdougb isc_portset_addrange(v4portset, udpport_low, 5121186462Sdougb udpport_high); 5122186462Sdougb } 5123186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5124186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5125186462Sdougb "using default UDP/IPv4 port range: [%d, %d]", 5126186462Sdougb udpport_low, udpport_high); 5127186462Sdougb } 5128186462Sdougb (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports); 5129186462Sdougb if (avoidv4ports != NULL) 5130186462Sdougb portset_fromconf(v4portset, avoidv4ports, ISC_FALSE); 5131186462Sdougb 5132186462Sdougb (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports); 5133186462Sdougb if (usev6ports != NULL) 5134186462Sdougb portset_fromconf(v6portset, usev6ports, ISC_TRUE); 5135186462Sdougb else { 5136186462Sdougb CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low, 5137186462Sdougb &udpport_high), 5138186462Sdougb "get the default UDP/IPv6 port range"); 5139186462Sdougb if (udpport_low == udpport_high) 5140186462Sdougb isc_portset_add(v6portset, udpport_low); 5141186462Sdougb else { 5142186462Sdougb isc_portset_addrange(v6portset, udpport_low, 5143186462Sdougb udpport_high); 5144186462Sdougb } 5145186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5146186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5147186462Sdougb "using default UDP/IPv6 port range: [%d, %d]", 5148186462Sdougb udpport_low, udpport_high); 5149186462Sdougb } 5150186462Sdougb (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports); 5151186462Sdougb if (avoidv6ports != NULL) 5152186462Sdougb portset_fromconf(v6portset, avoidv6ports, ISC_FALSE); 5153186462Sdougb 5154186462Sdougb dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset); 5155186462Sdougb 5156135446Strhodes /* 5157135446Strhodes * Set the EDNS UDP size when we don't match a view. 5158135446Strhodes */ 5159135446Strhodes obj = NULL; 5160135446Strhodes result = ns_config_get(maps, "edns-udp-size", &obj); 5161135446Strhodes INSIST(result == ISC_R_SUCCESS); 5162135446Strhodes udpsize = cfg_obj_asuint32(obj); 5163135446Strhodes if (udpsize < 512) 5164135446Strhodes udpsize = 512; 5165135446Strhodes if (udpsize > 4096) 5166135446Strhodes udpsize = 4096; 5167135446Strhodes ns_g_udpsize = (isc_uint16_t)udpsize; 5168135446Strhodes 5169135446Strhodes /* 5170135446Strhodes * Configure the zone manager. 5171135446Strhodes */ 5172135446Strhodes obj = NULL; 5173135446Strhodes result = ns_config_get(maps, "transfers-in", &obj); 5174135446Strhodes INSIST(result == ISC_R_SUCCESS); 5175135446Strhodes dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 5176135446Strhodes 5177135446Strhodes obj = NULL; 5178135446Strhodes result = ns_config_get(maps, "transfers-per-ns", &obj); 5179135446Strhodes INSIST(result == ISC_R_SUCCESS); 5180135446Strhodes dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 5181135446Strhodes 5182135446Strhodes obj = NULL; 5183135446Strhodes result = ns_config_get(maps, "serial-query-rate", &obj); 5184135446Strhodes INSIST(result == ISC_R_SUCCESS); 5185135446Strhodes dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 5186135446Strhodes 5187135446Strhodes /* 5188135446Strhodes * Determine which port to use for listening for incoming connections. 5189135446Strhodes */ 5190135446Strhodes if (ns_g_port != 0) 5191135446Strhodes listen_port = ns_g_port; 5192135446Strhodes else 5193135446Strhodes CHECKM(ns_config_getport(config, &listen_port), "port"); 5194135446Strhodes 5195135446Strhodes /* 5196135446Strhodes * Find the listen queue depth. 5197135446Strhodes */ 5198135446Strhodes obj = NULL; 5199135446Strhodes result = ns_config_get(maps, "tcp-listen-queue", &obj); 5200135446Strhodes INSIST(result == ISC_R_SUCCESS); 5201135446Strhodes ns_g_listen = cfg_obj_asuint32(obj); 5202262706Serwin if ((ns_g_listen > 0) && (ns_g_listen < 10)) 5203262706Serwin ns_g_listen = 10; 5204135446Strhodes 5205135446Strhodes /* 5206135446Strhodes * Configure the interface manager according to the "listen-on" 5207135446Strhodes * statement. 5208135446Strhodes */ 5209135446Strhodes { 5210165071Sdougb const cfg_obj_t *clistenon = NULL; 5211135446Strhodes ns_listenlist_t *listenon = NULL; 5212135446Strhodes 5213135446Strhodes clistenon = NULL; 5214135446Strhodes /* 5215135446Strhodes * Even though listen-on is present in the default 5216135446Strhodes * configuration, we can't use it here, since it isn't 5217135446Strhodes * used if we're in lwresd mode. This way is easier. 5218135446Strhodes */ 5219135446Strhodes if (options != NULL) 5220135446Strhodes (void)cfg_map_get(options, "listen-on", &clistenon); 5221135446Strhodes if (clistenon != NULL) { 5222225361Sdougb /* check return code? */ 5223225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 5224225361Sdougb ns_g_aclconfctx, 5225225361Sdougb ns_g_mctx, &listenon); 5226135446Strhodes } else if (!ns_g_lwresdonly) { 5227135446Strhodes /* 5228135446Strhodes * Not specified, use default. 5229135446Strhodes */ 5230135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 5231135446Strhodes ISC_TRUE, &listenon)); 5232135446Strhodes } 5233135446Strhodes if (listenon != NULL) { 5234135446Strhodes ns_interfacemgr_setlistenon4(server->interfacemgr, 5235135446Strhodes listenon); 5236135446Strhodes ns_listenlist_detach(&listenon); 5237135446Strhodes } 5238135446Strhodes } 5239135446Strhodes /* 5240135446Strhodes * Ditto for IPv6. 5241135446Strhodes */ 5242135446Strhodes { 5243165071Sdougb const cfg_obj_t *clistenon = NULL; 5244135446Strhodes ns_listenlist_t *listenon = NULL; 5245135446Strhodes 5246135446Strhodes if (options != NULL) 5247135446Strhodes (void)cfg_map_get(options, "listen-on-v6", &clistenon); 5248135446Strhodes if (clistenon != NULL) { 5249225361Sdougb /* check return code? */ 5250225361Sdougb (void)ns_listenlist_fromconfig(clistenon, config, 5251225361Sdougb ns_g_aclconfctx, 5252225361Sdougb ns_g_mctx, &listenon); 5253135446Strhodes } else if (!ns_g_lwresdonly) { 5254193149Sdougb isc_boolean_t enable; 5255135446Strhodes /* 5256135446Strhodes * Not specified, use default. 5257135446Strhodes */ 5258193149Sdougb enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS); 5259135446Strhodes CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 5260193149Sdougb enable, &listenon)); 5261135446Strhodes } 5262135446Strhodes if (listenon != NULL) { 5263135446Strhodes ns_interfacemgr_setlistenon6(server->interfacemgr, 5264135446Strhodes listenon); 5265135446Strhodes ns_listenlist_detach(&listenon); 5266135446Strhodes } 5267135446Strhodes } 5268135446Strhodes 5269135446Strhodes /* 5270135446Strhodes * Rescan the interface list to pick up changes in the 5271135446Strhodes * listen-on option. It's important that we do this before we try 5272135446Strhodes * to configure the query source, since the dispatcher we use might 5273135446Strhodes * be shared with an interface. 5274135446Strhodes */ 5275135446Strhodes scan_interfaces(server, ISC_TRUE); 5276135446Strhodes 5277135446Strhodes /* 5278135446Strhodes * Arrange for further interface scanning to occur periodically 5279135446Strhodes * as specified by the "interface-interval" option. 5280135446Strhodes */ 5281135446Strhodes obj = NULL; 5282135446Strhodes result = ns_config_get(maps, "interface-interval", &obj); 5283135446Strhodes INSIST(result == ISC_R_SUCCESS); 5284135446Strhodes interface_interval = cfg_obj_asuint32(obj) * 60; 5285135446Strhodes if (interface_interval == 0) { 5286135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 5287135446Strhodes isc_timertype_inactive, 5288135446Strhodes NULL, NULL, ISC_TRUE)); 5289135446Strhodes } else if (server->interface_interval != interface_interval) { 5290135446Strhodes isc_interval_set(&interval, interface_interval, 0); 5291135446Strhodes CHECK(isc_timer_reset(server->interface_timer, 5292135446Strhodes isc_timertype_ticker, 5293135446Strhodes NULL, &interval, ISC_FALSE)); 5294135446Strhodes } 5295135446Strhodes server->interface_interval = interface_interval; 5296135446Strhodes 5297135446Strhodes /* 5298135446Strhodes * Configure the dialup heartbeat timer. 5299135446Strhodes */ 5300135446Strhodes obj = NULL; 5301135446Strhodes result = ns_config_get(maps, "heartbeat-interval", &obj); 5302135446Strhodes INSIST(result == ISC_R_SUCCESS); 5303135446Strhodes heartbeat_interval = cfg_obj_asuint32(obj) * 60; 5304135446Strhodes if (heartbeat_interval == 0) { 5305135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 5306135446Strhodes isc_timertype_inactive, 5307135446Strhodes NULL, NULL, ISC_TRUE)); 5308135446Strhodes } else if (server->heartbeat_interval != heartbeat_interval) { 5309135446Strhodes isc_interval_set(&interval, heartbeat_interval, 0); 5310135446Strhodes CHECK(isc_timer_reset(server->heartbeat_timer, 5311135446Strhodes isc_timertype_ticker, 5312135446Strhodes NULL, &interval, ISC_FALSE)); 5313135446Strhodes } 5314135446Strhodes server->heartbeat_interval = heartbeat_interval; 5315186462Sdougb 5316170222Sdougb isc_interval_set(&interval, 1200, 0); 5317170222Sdougb CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL, 5318170222Sdougb &interval, ISC_FALSE)); 5319135446Strhodes 5320135446Strhodes /* 5321224092Sdougb * Write the PID file. 5322224092Sdougb */ 5323224092Sdougb obj = NULL; 5324224092Sdougb if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 5325224092Sdougb if (cfg_obj_isvoid(obj)) 5326224092Sdougb ns_os_writepidfile(NULL, first_time); 5327224092Sdougb else 5328224092Sdougb ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 5329224092Sdougb else if (ns_g_lwresdonly) 5330224092Sdougb ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 5331224092Sdougb else 5332224092Sdougb ns_os_writepidfile(ns_g_defaultpidfile, first_time); 5333224092Sdougb 5334224092Sdougb /* 5335224092Sdougb * Configure the server-wide session key. This must be done before 5336224092Sdougb * configure views because zone configuration may need to know 5337224092Sdougb * session-keyname. 5338224092Sdougb * 5339224092Sdougb * Failure of session key generation isn't fatal at this time; if it 5340224092Sdougb * turns out that a session key is really needed but doesn't exist, 5341224092Sdougb * we'll treat it as a fatal error then. 5342224092Sdougb */ 5343224092Sdougb (void)configure_session_key(maps, server, ns_g_mctx); 5344224092Sdougb 5345225361Sdougb views = NULL; 5346225361Sdougb (void)cfg_map_get(config, "view", &views); 5347225361Sdougb 5348224092Sdougb /* 5349225361Sdougb * Create the views and count all the configured zones in 5350225361Sdougb * order to correctly size the zone manager's task table. 5351225361Sdougb * (We only count zones for configured views; the built-in 5352225361Sdougb * "bind" view can be ignored as it only adds a negligible 5353225361Sdougb * number of zones.) 5354225361Sdougb * 5355225361Sdougb * If we're allowing new zones, we need to be able to find the 5356225361Sdougb * new zone file and count those as well. So we setup the new 5357225361Sdougb * zone configuration context, but otherwise view configuration 5358225361Sdougb * waits until after the zone manager's task list has been sized. 5359225361Sdougb */ 5360225361Sdougb for (element = cfg_list_first(views); 5361225361Sdougb element != NULL; 5362225361Sdougb element = cfg_list_next(element)) 5363225361Sdougb { 5364225361Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 5365225361Sdougb const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options"); 5366225361Sdougb view = NULL; 5367225361Sdougb 5368225361Sdougb CHECK(create_view(vconfig, &viewlist, &view)); 5369225361Sdougb INSIST(view != NULL); 5370225361Sdougb 5371225361Sdougb num_zones += count_zones(voptions); 5372225361Sdougb CHECK(setup_newzones(view, config, vconfig, conf_parser, 5373225361Sdougb ns_g_aclconfctx)); 5374225361Sdougb 5375225361Sdougb nzctx = view->new_zone_config; 5376225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 5377225361Sdougb num_zones += count_zones(nzctx->nzconfig); 5378225361Sdougb 5379225361Sdougb dns_view_detach(&view); 5380225361Sdougb } 5381225361Sdougb 5382225361Sdougb /* 5383225361Sdougb * If there were no explicit views then we do the default 5384225361Sdougb * view here. 5385225361Sdougb */ 5386225361Sdougb if (views == NULL) { 5387225361Sdougb CHECK(create_view(NULL, &viewlist, &view)); 5388225361Sdougb INSIST(view != NULL); 5389225361Sdougb 5390225361Sdougb num_zones = count_zones(config); 5391225361Sdougb 5392225361Sdougb CHECK(setup_newzones(view, config, NULL, conf_parser, 5393225361Sdougb ns_g_aclconfctx)); 5394225361Sdougb 5395225361Sdougb nzctx = view->new_zone_config; 5396225361Sdougb if (nzctx != NULL && nzctx->nzconfig != NULL) 5397225361Sdougb num_zones += count_zones(nzctx->nzconfig); 5398225361Sdougb 5399225361Sdougb dns_view_detach(&view); 5400225361Sdougb } 5401225361Sdougb 5402225361Sdougb /* 5403225361Sdougb * Zones have been counted; set the zone manager task pool size. 5404225361Sdougb */ 5405225361Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5406225361Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5407225361Sdougb "sizing zone task pool based on %d zones", num_zones); 5408225361Sdougb CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones)); 5409225361Sdougb 5410225361Sdougb /* 5411135446Strhodes * Configure and freeze all explicit views. Explicit 5412135446Strhodes * views that have zones were already created at parsing 5413135446Strhodes * time, but views with no zones must be created here. 5414135446Strhodes */ 5415135446Strhodes for (element = cfg_list_first(views); 5416135446Strhodes element != NULL; 5417135446Strhodes element = cfg_list_next(element)) 5418135446Strhodes { 5419224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 5420225361Sdougb 5421135446Strhodes view = NULL; 5422225361Sdougb CHECK(find_view(vconfig, &viewlist, &view)); 5423225361Sdougb CHECK(configure_view(view, config, vconfig, 5424225361Sdougb &cachelist, bindkeys, ns_g_mctx, 5425225361Sdougb ns_g_aclconfctx, ISC_TRUE)); 5426135446Strhodes dns_view_freeze(view); 5427135446Strhodes dns_view_detach(&view); 5428135446Strhodes } 5429135446Strhodes 5430135446Strhodes /* 5431135446Strhodes * Make sure we have a default view if and only if there 5432135446Strhodes * were no explicit views. 5433135446Strhodes */ 5434135446Strhodes if (views == NULL) { 5435225361Sdougb view = NULL; 5436225361Sdougb CHECK(find_view(NULL, &viewlist, &view)); 5437225361Sdougb CHECK(configure_view(view, config, NULL, 5438224092Sdougb &cachelist, bindkeys, 5439225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_TRUE)); 5440135446Strhodes dns_view_freeze(view); 5441135446Strhodes dns_view_detach(&view); 5442135446Strhodes } 5443135446Strhodes 5444135446Strhodes /* 5445224092Sdougb * Create (or recreate) the built-in views. 5446135446Strhodes */ 5447135446Strhodes builtin_views = NULL; 5448135446Strhodes RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 5449135446Strhodes &builtin_views) == ISC_R_SUCCESS); 5450135446Strhodes for (element = cfg_list_first(builtin_views); 5451135446Strhodes element != NULL; 5452135446Strhodes element = cfg_list_next(element)) 5453135446Strhodes { 5454224092Sdougb cfg_obj_t *vconfig = cfg_listelt_value(element); 5455224092Sdougb 5456224092Sdougb CHECK(create_view(vconfig, &builtin_viewlist, &view)); 5457225361Sdougb CHECK(configure_view(view, config, vconfig, 5458224092Sdougb &cachelist, bindkeys, 5459225361Sdougb ns_g_mctx, ns_g_aclconfctx, ISC_FALSE)); 5460135446Strhodes dns_view_freeze(view); 5461135446Strhodes dns_view_detach(&view); 5462135446Strhodes view = NULL; 5463135446Strhodes } 5464135446Strhodes 5465224092Sdougb /* Now combine the two viewlists into one */ 5466224092Sdougb ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); 5467224092Sdougb 5468224092Sdougb /* Swap our new view list with the production one. */ 5469135446Strhodes tmpviewlist = server->viewlist; 5470135446Strhodes server->viewlist = viewlist; 5471135446Strhodes viewlist = tmpviewlist; 5472135446Strhodes 5473224092Sdougb /* Make the view list available to each of the views */ 5474224092Sdougb view = ISC_LIST_HEAD(server->viewlist); 5475224092Sdougb while (view != NULL) { 5476224092Sdougb view->viewlist = &server->viewlist; 5477224092Sdougb view = ISC_LIST_NEXT(view, link); 5478224092Sdougb } 5479224092Sdougb 5480224092Sdougb /* Swap our new cache list with the production one. */ 5481224092Sdougb tmpcachelist = server->cachelist; 5482224092Sdougb server->cachelist = cachelist; 5483224092Sdougb cachelist = tmpcachelist; 5484224092Sdougb 5485224092Sdougb /* Load the TKEY information from the configuration. */ 5486135446Strhodes if (options != NULL) { 5487135446Strhodes dns_tkeyctx_t *t = NULL; 5488135446Strhodes CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 5489135446Strhodes &t), 5490135446Strhodes "configuring TKEY"); 5491135446Strhodes if (server->tkeyctx != NULL) 5492135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 5493135446Strhodes server->tkeyctx = t; 5494135446Strhodes } 5495135446Strhodes 5496135446Strhodes /* 5497135446Strhodes * Bind the control port(s). 5498135446Strhodes */ 5499135446Strhodes CHECKM(ns_controls_configure(ns_g_server->controls, config, 5500225361Sdougb ns_g_aclconfctx), 5501135446Strhodes "binding control channel(s)"); 5502135446Strhodes 5503135446Strhodes /* 5504135446Strhodes * Bind the lwresd port(s). 5505135446Strhodes */ 5506135446Strhodes CHECKM(ns_lwresd_configure(ns_g_mctx, config), 5507135446Strhodes "binding lightweight resolver ports"); 5508135446Strhodes 5509135446Strhodes /* 5510135446Strhodes * Open the source of entropy. 5511135446Strhodes */ 5512135446Strhodes if (first_time) { 5513135446Strhodes obj = NULL; 5514135446Strhodes result = ns_config_get(maps, "random-device", &obj); 5515135446Strhodes if (result != ISC_R_SUCCESS) { 5516135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5517135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5518135446Strhodes "no source of entropy found"); 5519135446Strhodes } else { 5520135446Strhodes const char *randomdev = cfg_obj_asstring(obj); 5521135446Strhodes result = isc_entropy_createfilesource(ns_g_entropy, 5522135446Strhodes randomdev); 5523135446Strhodes if (result != ISC_R_SUCCESS) 5524135446Strhodes isc_log_write(ns_g_lctx, 5525135446Strhodes NS_LOGCATEGORY_GENERAL, 5526135446Strhodes NS_LOGMODULE_SERVER, 5527135446Strhodes ISC_LOG_INFO, 5528135446Strhodes "could not open entropy source " 5529135446Strhodes "%s: %s", 5530135446Strhodes randomdev, 5531135446Strhodes isc_result_totext(result)); 5532135446Strhodes#ifdef PATH_RANDOMDEV 5533135446Strhodes if (ns_g_fallbackentropy != NULL) { 5534135446Strhodes if (result != ISC_R_SUCCESS) { 5535135446Strhodes isc_log_write(ns_g_lctx, 5536135446Strhodes NS_LOGCATEGORY_GENERAL, 5537135446Strhodes NS_LOGMODULE_SERVER, 5538135446Strhodes ISC_LOG_INFO, 5539135446Strhodes "using pre-chroot entropy source " 5540135446Strhodes "%s", 5541135446Strhodes PATH_RANDOMDEV); 5542135446Strhodes isc_entropy_detach(&ns_g_entropy); 5543135446Strhodes isc_entropy_attach(ns_g_fallbackentropy, 5544135446Strhodes &ns_g_entropy); 5545135446Strhodes } 5546135446Strhodes isc_entropy_detach(&ns_g_fallbackentropy); 5547135446Strhodes } 5548135446Strhodes#endif 5549135446Strhodes } 5550135446Strhodes } 5551135446Strhodes 5552135446Strhodes /* 5553135446Strhodes * Relinquish root privileges. 5554135446Strhodes */ 5555135446Strhodes if (first_time) 5556135446Strhodes ns_os_changeuser(); 5557135446Strhodes 5558135446Strhodes /* 5559186462Sdougb * Check that the working directory is writable. 5560186462Sdougb */ 5561186462Sdougb if (access(".", W_OK) != 0) { 5562186462Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5563186462Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 5564186462Sdougb "the working directory is not writable"); 5565186462Sdougb } 5566186462Sdougb 5567186462Sdougb /* 5568135446Strhodes * Configure the logging system. 5569135446Strhodes * 5570135446Strhodes * Do this after changing UID to make sure that any log 5571135446Strhodes * files specified in named.conf get created by the 5572135446Strhodes * unprivileged user, not root. 5573135446Strhodes */ 5574135446Strhodes if (ns_g_logstderr) { 5575262706Serwin const cfg_obj_t *logobj = NULL; 5576262706Serwin 5577135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5578135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 5579262706Serwin "not using config file logging " 5580262706Serwin "statement for logging due to " 5581262706Serwin "-g option"); 5582262706Serwin 5583262706Serwin (void)cfg_map_get(config, "logging", &logobj); 5584262706Serwin if (logobj != NULL) { 5585262706Serwin result = ns_log_configure(NULL, logobj); 5586262706Serwin if (result != ISC_R_SUCCESS) { 5587262706Serwin isc_log_write(ns_g_lctx, 5588262706Serwin NS_LOGCATEGORY_GENERAL, 5589262706Serwin NS_LOGMODULE_SERVER, 5590262706Serwin ISC_LOG_ERROR, 5591262706Serwin "checking logging configuration " 5592262706Serwin "failed: %s", 5593262706Serwin isc_result_totext(result)); 5594262706Serwin goto cleanup; 5595262706Serwin } 5596262706Serwin } 5597135446Strhodes } else { 5598165071Sdougb const cfg_obj_t *logobj = NULL; 5599135446Strhodes 5600135446Strhodes CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 5601135446Strhodes "creating new logging configuration"); 5602135446Strhodes 5603135446Strhodes logobj = NULL; 5604135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 5605135446Strhodes if (logobj != NULL) { 5606135446Strhodes CHECKM(ns_log_configure(logc, logobj), 5607135446Strhodes "configuring logging"); 5608135446Strhodes } else { 5609135446Strhodes CHECKM(ns_log_setdefaultchannels(logc), 5610135446Strhodes "setting up default logging channels"); 5611135446Strhodes CHECKM(ns_log_setunmatchedcategory(logc), 5612135446Strhodes "setting up default 'category unmatched'"); 5613135446Strhodes CHECKM(ns_log_setdefaultcategory(logc), 5614135446Strhodes "setting up default 'category default'"); 5615135446Strhodes } 5616135446Strhodes 5617262706Serwin CHECKM(isc_logconfig_use(ns_g_lctx, logc), 5618262706Serwin "installing logging configuration"); 5619262706Serwin logc = NULL; 5620135446Strhodes 5621135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 5622135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 5623135446Strhodes "now using logging configuration from " 5624135446Strhodes "config file"); 5625135446Strhodes } 5626135446Strhodes 5627135446Strhodes /* 5628135446Strhodes * Set the default value of the query logging flag depending 5629135446Strhodes * whether a "queries" category has been defined. This is 5630135446Strhodes * a disgusting hack, but we need to do this for BIND 8 5631135446Strhodes * compatibility. 5632135446Strhodes */ 5633135446Strhodes if (first_time) { 5634165071Sdougb const cfg_obj_t *logobj = NULL; 5635165071Sdougb const cfg_obj_t *categories = NULL; 5636135446Strhodes 5637135446Strhodes obj = NULL; 5638135446Strhodes if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 5639135446Strhodes server->log_queries = cfg_obj_asboolean(obj); 5640135446Strhodes } else { 5641135446Strhodes 5642135446Strhodes (void)cfg_map_get(config, "logging", &logobj); 5643135446Strhodes if (logobj != NULL) 5644135446Strhodes (void)cfg_map_get(logobj, "category", 5645135446Strhodes &categories); 5646135446Strhodes if (categories != NULL) { 5647165071Sdougb const cfg_listelt_t *element; 5648135446Strhodes for (element = cfg_list_first(categories); 5649135446Strhodes element != NULL; 5650135446Strhodes element = cfg_list_next(element)) 5651135446Strhodes { 5652165071Sdougb const cfg_obj_t *catobj; 5653165071Sdougb const char *str; 5654135446Strhodes 5655135446Strhodes obj = cfg_listelt_value(element); 5656135446Strhodes catobj = cfg_tuple_get(obj, "name"); 5657135446Strhodes str = cfg_obj_asstring(catobj); 5658135446Strhodes if (strcasecmp(str, "queries") == 0) 5659135446Strhodes server->log_queries = ISC_TRUE; 5660135446Strhodes } 5661135446Strhodes } 5662135446Strhodes } 5663135446Strhodes } 5664135446Strhodes 5665186462Sdougb 5666135446Strhodes obj = NULL; 5667135446Strhodes if (options != NULL && 5668193149Sdougb cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS) 5669193149Sdougb ns_g_memstatistics = cfg_obj_asboolean(obj); 5670193149Sdougb else 5671193149Sdougb ns_g_memstatistics = 5672193149Sdougb ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0); 5673193149Sdougb 5674193149Sdougb obj = NULL; 5675193149Sdougb if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS) 5676135446Strhodes ns_main_setmemstats(cfg_obj_asstring(obj)); 5677193149Sdougb else if (ns_g_memstatistics) 5678193149Sdougb ns_main_setmemstats("named.memstats"); 5679135446Strhodes else 5680135446Strhodes ns_main_setmemstats(NULL); 5681135446Strhodes 5682135446Strhodes obj = NULL; 5683135446Strhodes result = ns_config_get(maps, "statistics-file", &obj); 5684135446Strhodes INSIST(result == ISC_R_SUCCESS); 5685135446Strhodes CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 5686135446Strhodes "strdup"); 5687135446Strhodes 5688135446Strhodes obj = NULL; 5689135446Strhodes result = ns_config_get(maps, "dump-file", &obj); 5690135446Strhodes INSIST(result == ISC_R_SUCCESS); 5691135446Strhodes CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 5692135446Strhodes "strdup"); 5693135446Strhodes 5694135446Strhodes obj = NULL; 5695224092Sdougb result = ns_config_get(maps, "secroots-file", &obj); 5696224092Sdougb INSIST(result == ISC_R_SUCCESS); 5697224092Sdougb CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)), 5698224092Sdougb "strdup"); 5699224092Sdougb 5700224092Sdougb obj = NULL; 5701135446Strhodes result = ns_config_get(maps, "recursing-file", &obj); 5702135446Strhodes INSIST(result == ISC_R_SUCCESS); 5703135446Strhodes CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 5704135446Strhodes "strdup"); 5705135446Strhodes 5706135446Strhodes obj = NULL; 5707135446Strhodes result = ns_config_get(maps, "version", &obj); 5708135446Strhodes if (result == ISC_R_SUCCESS) { 5709135446Strhodes CHECKM(setoptstring(server, &server->version, obj), "strdup"); 5710135446Strhodes server->version_set = ISC_TRUE; 5711135446Strhodes } else { 5712135446Strhodes server->version_set = ISC_FALSE; 5713135446Strhodes } 5714135446Strhodes 5715135446Strhodes obj = NULL; 5716135446Strhodes result = ns_config_get(maps, "hostname", &obj); 5717135446Strhodes if (result == ISC_R_SUCCESS) { 5718135446Strhodes CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 5719135446Strhodes server->hostname_set = ISC_TRUE; 5720135446Strhodes } else { 5721135446Strhodes server->hostname_set = ISC_FALSE; 5722135446Strhodes } 5723135446Strhodes 5724135446Strhodes obj = NULL; 5725135446Strhodes result = ns_config_get(maps, "server-id", &obj); 5726135446Strhodes server->server_usehostname = ISC_FALSE; 5727135446Strhodes if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 5728193149Sdougb /* The parser translates "hostname" to ISC_TRUE */ 5729193149Sdougb server->server_usehostname = cfg_obj_asboolean(obj); 5730193149Sdougb result = setstring(server, &server->server_id, NULL); 5731193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 5732135446Strhodes } else if (result == ISC_R_SUCCESS) { 5733193149Sdougb /* Found a quoted string */ 5734135446Strhodes CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 5735135446Strhodes } else { 5736170222Sdougb result = setstring(server, &server->server_id, NULL); 5737135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5738135446Strhodes } 5739135446Strhodes 5740135446Strhodes obj = NULL; 5741135446Strhodes result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 5742135446Strhodes if (result == ISC_R_SUCCESS) { 5743135446Strhodes server->flushonshutdown = cfg_obj_asboolean(obj); 5744135446Strhodes } else { 5745135446Strhodes server->flushonshutdown = ISC_FALSE; 5746135446Strhodes } 5747135446Strhodes 5748135446Strhodes result = ISC_R_SUCCESS; 5749135446Strhodes 5750135446Strhodes cleanup: 5751262706Serwin if (logc != NULL) 5752262706Serwin isc_logconfig_destroy(&logc); 5753262706Serwin 5754186462Sdougb if (v4portset != NULL) 5755186462Sdougb isc_portset_destroy(ns_g_mctx, &v4portset); 5756186462Sdougb 5757186462Sdougb if (v6portset != NULL) 5758186462Sdougb isc_portset_destroy(ns_g_mctx, &v6portset); 5759186462Sdougb 5760224092Sdougb if (conf_parser != NULL) { 5761135446Strhodes if (config != NULL) 5762224092Sdougb cfg_obj_destroy(conf_parser, &config); 5763224092Sdougb cfg_parser_destroy(&conf_parser); 5764135446Strhodes } 5765135446Strhodes 5766224092Sdougb if (bindkeys_parser != NULL) { 5767224092Sdougb if (bindkeys != NULL) 5768224092Sdougb cfg_obj_destroy(bindkeys_parser, &bindkeys); 5769224092Sdougb cfg_parser_destroy(&bindkeys_parser); 5770224092Sdougb } 5771224092Sdougb 5772135446Strhodes if (view != NULL) 5773135446Strhodes dns_view_detach(&view); 5774135446Strhodes 5775135446Strhodes /* 5776135446Strhodes * This cleans up either the old production view list 5777135446Strhodes * or our temporary list depending on whether they 5778135446Strhodes * were swapped above or not. 5779135446Strhodes */ 5780135446Strhodes for (view = ISC_LIST_HEAD(viewlist); 5781135446Strhodes view != NULL; 5782135446Strhodes view = view_next) { 5783135446Strhodes view_next = ISC_LIST_NEXT(view, link); 5784135446Strhodes ISC_LIST_UNLINK(viewlist, view, link); 5785170222Sdougb if (result == ISC_R_SUCCESS && 5786170222Sdougb strcmp(view->name, "_bind") != 0) 5787170222Sdougb (void)dns_zt_apply(view->zonetable, ISC_FALSE, 5788170222Sdougb removed, view); 5789135446Strhodes dns_view_detach(&view); 5790135446Strhodes } 5791135446Strhodes 5792224092Sdougb /* Same cleanup for cache list. */ 5793224092Sdougb while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) { 5794224092Sdougb ISC_LIST_UNLINK(cachelist, nsc, link); 5795224092Sdougb dns_cache_detach(&nsc->cache); 5796224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 5797224092Sdougb } 5798224092Sdougb 5799135446Strhodes /* 5800135446Strhodes * Adjust the listening interfaces in accordance with the source 5801135446Strhodes * addresses specified in views and zones. 5802135446Strhodes */ 5803135446Strhodes if (isc_net_probeipv6() == ISC_R_SUCCESS) 5804135446Strhodes adjust_interfaces(server, ns_g_mctx); 5805135446Strhodes 5806135446Strhodes /* Relinquish exclusive access to configuration data. */ 5807234010Sdougb if (exclusive) 5808234010Sdougb isc_task_endexclusive(server->task); 5809135446Strhodes 5810135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5811135446Strhodes ISC_LOG_DEBUG(1), "load_configuration: %s", 5812135446Strhodes isc_result_totext(result)); 5813135446Strhodes 5814135446Strhodes return (result); 5815135446Strhodes} 5816135446Strhodes 5817135446Strhodesstatic isc_result_t 5818254897Serwinview_loaded(void *arg) { 5819135446Strhodes isc_result_t result; 5820254897Serwin ns_zoneload_t *zl = (ns_zoneload_t *) arg; 5821254897Serwin ns_server_t *server = zl->server; 5822254897Serwin unsigned int refs; 5823254897Serwin 5824254897Serwin 5825254897Serwin /* 5826254897Serwin * Force zone maintenance. Do this after loading 5827254897Serwin * so that we know when we need to force AXFR of 5828254897Serwin * slave zones whose master files are missing. 5829254897Serwin * 5830254897Serwin * We use the zoneload reference counter to let us 5831254897Serwin * know when all views are finished. 5832254897Serwin */ 5833254897Serwin isc_refcount_decrement(&zl->refs, &refs); 5834254897Serwin if (refs != 0) 5835254897Serwin return (ISC_R_SUCCESS); 5836254897Serwin 5837254897Serwin isc_refcount_destroy(&zl->refs); 5838254897Serwin isc_mem_put(server->mctx, zl, sizeof (*zl)); 5839254897Serwin 5840254897Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5841254897Serwin ISC_LOG_NOTICE, "all zones loaded"); 5842254897Serwin CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr), 5843254897Serwin "forcing zone maintenance"); 5844254897Serwin 5845254897Serwin ns_os_started(); 5846254897Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 5847254897Serwin ISC_LOG_NOTICE, "running"); 5848254897Serwin 5849254897Serwin return (ISC_R_SUCCESS); 5850254897Serwin} 5851254897Serwin 5852254897Serwinstatic isc_result_t 5853262706Serwinload_zones(ns_server_t *server, isc_boolean_t init) { 5854254897Serwin isc_result_t result; 5855135446Strhodes dns_view_t *view; 5856254897Serwin ns_zoneload_t *zl; 5857254897Serwin unsigned int refs = 0; 5858135446Strhodes 5859254897Serwin zl = isc_mem_get(server->mctx, sizeof (*zl)); 5860254897Serwin if (zl == NULL) 5861254897Serwin return (ISC_R_NOMEMORY); 5862254897Serwin zl->server = server; 5863254897Serwin 5864135446Strhodes result = isc_task_beginexclusive(server->task); 5865135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5866135446Strhodes 5867254897Serwin isc_refcount_init(&zl->refs, 1); 5868254897Serwin 5869135446Strhodes /* 5870254897Serwin * Schedule zones to be loaded from disk. 5871135446Strhodes */ 5872135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5873135446Strhodes view != NULL; 5874135446Strhodes view = ISC_LIST_NEXT(view, link)) 5875135446Strhodes { 5876254897Serwin if (view->managed_keys != NULL) { 5877254897Serwin result = dns_zone_load(view->managed_keys); 5878254897Serwin if (result != ISC_R_SUCCESS && 5879254897Serwin result != DNS_R_UPTODATE && 5880254897Serwin result != DNS_R_CONTINUE) 5881254897Serwin goto cleanup; 5882254897Serwin } 5883254897Serwin if (view->redirect != NULL) { 5884254897Serwin result = dns_zone_load(view->redirect); 5885254897Serwin if (result != ISC_R_SUCCESS && 5886254897Serwin result != DNS_R_UPTODATE && 5887254897Serwin result != DNS_R_CONTINUE) 5888254897Serwin goto cleanup; 5889254897Serwin } 5890254897Serwin 5891254897Serwin /* 5892254897Serwin * 'dns_view_asyncload' calls view_loaded if there are no 5893254897Serwin * zones. 5894254897Serwin */ 5895254897Serwin isc_refcount_increment(&zl->refs, NULL); 5896254897Serwin CHECK(dns_view_asyncload(view, view_loaded, zl)); 5897135446Strhodes } 5898135446Strhodes 5899135446Strhodes cleanup: 5900254897Serwin isc_refcount_decrement(&zl->refs, &refs); 5901254897Serwin if (refs == 0) { 5902254897Serwin isc_refcount_destroy(&zl->refs); 5903254897Serwin isc_mem_put(server->mctx, zl, sizeof (*zl)); 5904262706Serwin } else if (init) { 5905254897Serwin /* 5906254897Serwin * Place the task manager into privileged mode. This 5907254897Serwin * ensures that after we leave task-exclusive mode, no 5908254897Serwin * other tasks will be able to run except for the ones 5909262706Serwin * that are loading zones. (This should only be done during 5910262706Serwin * the initial server setup; it isn't necessary during 5911262706Serwin * a reload.) 5912254897Serwin */ 5913254897Serwin isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged); 5914254897Serwin } 5915254897Serwin 5916186462Sdougb isc_task_endexclusive(server->task); 5917135446Strhodes return (result); 5918135446Strhodes} 5919135446Strhodes 5920135446Strhodesstatic isc_result_t 5921135446Strhodesload_new_zones(ns_server_t *server, isc_boolean_t stop) { 5922135446Strhodes isc_result_t result; 5923135446Strhodes dns_view_t *view; 5924135446Strhodes 5925135446Strhodes result = isc_task_beginexclusive(server->task); 5926135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 5927135446Strhodes 5928135446Strhodes /* 5929135446Strhodes * Load zone data from disk. 5930135446Strhodes */ 5931135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 5932135446Strhodes view != NULL; 5933135446Strhodes view = ISC_LIST_NEXT(view, link)) 5934135446Strhodes { 5935135446Strhodes CHECK(dns_view_loadnew(view, stop)); 5936224092Sdougb 5937224092Sdougb /* Load managed-keys data */ 5938224092Sdougb if (view->managed_keys != NULL) 5939224092Sdougb CHECK(dns_zone_loadnew(view->managed_keys)); 5940254897Serwin if (view->redirect != NULL) 5941254897Serwin CHECK(dns_zone_loadnew(view->redirect)); 5942135446Strhodes } 5943224092Sdougb 5944135446Strhodes /* 5945224092Sdougb * Resume zone XFRs. 5946135446Strhodes */ 5947135446Strhodes dns_zonemgr_resumexfrs(server->zonemgr); 5948135446Strhodes cleanup: 5949186462Sdougb isc_task_endexclusive(server->task); 5950135446Strhodes return (result); 5951135446Strhodes} 5952135446Strhodes 5953135446Strhodesstatic void 5954135446Strhodesrun_server(isc_task_t *task, isc_event_t *event) { 5955135446Strhodes isc_result_t result; 5956135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 5957135446Strhodes 5958143731Sdougb INSIST(task == server->task); 5959135446Strhodes 5960135446Strhodes isc_event_free(&event); 5961135446Strhodes 5962135446Strhodes CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 5963135446Strhodes &ns_g_dispatchmgr), 5964135446Strhodes "creating dispatch manager"); 5965135446Strhodes 5966193149Sdougb dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); 5967193149Sdougb 5968135446Strhodes CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 5969135446Strhodes ns_g_socketmgr, ns_g_dispatchmgr, 5970135446Strhodes &server->interfacemgr), 5971135446Strhodes "creating interface manager"); 5972135446Strhodes 5973135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5974135446Strhodes NULL, NULL, server->task, 5975135446Strhodes interface_timer_tick, 5976135446Strhodes server, &server->interface_timer), 5977135446Strhodes "creating interface timer"); 5978135446Strhodes 5979135446Strhodes CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5980135446Strhodes NULL, NULL, server->task, 5981135446Strhodes heartbeat_timer_tick, 5982135446Strhodes server, &server->heartbeat_timer), 5983135446Strhodes "creating heartbeat timer"); 5984135446Strhodes 5985170222Sdougb CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 5986170222Sdougb NULL, NULL, server->task, pps_timer_tick, 5987170222Sdougb server, &server->pps_timer), 5988170222Sdougb "creating pps timer"); 5989170222Sdougb 5990135446Strhodes CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 5991135446Strhodes "creating default configuration parser"); 5992135446Strhodes 5993135446Strhodes if (ns_g_lwresdonly) 5994135446Strhodes CHECKFATAL(load_configuration(lwresd_g_conffile, server, 5995135446Strhodes ISC_TRUE), 5996135446Strhodes "loading configuration"); 5997135446Strhodes else 5998135446Strhodes CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 5999135446Strhodes "loading configuration"); 6000135446Strhodes 6001135446Strhodes isc_hash_init(); 6002135446Strhodes 6003262706Serwin CHECKFATAL(load_zones(server, ISC_TRUE), "loading zones"); 6004135446Strhodes} 6005135446Strhodes 6006186462Sdougbvoid 6007135446Strhodesns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 6008135446Strhodes 6009135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 6010135446Strhodes 6011135446Strhodes server->flushonshutdown = flush; 6012135446Strhodes} 6013135446Strhodes 6014135446Strhodesstatic void 6015135446Strhodesshutdown_server(isc_task_t *task, isc_event_t *event) { 6016135446Strhodes isc_result_t result; 6017135446Strhodes dns_view_t *view, *view_next; 6018135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 6019135446Strhodes isc_boolean_t flush = server->flushonshutdown; 6020224092Sdougb ns_cache_t *nsc; 6021135446Strhodes 6022135446Strhodes UNUSED(task); 6023135446Strhodes INSIST(task == server->task); 6024135446Strhodes 6025135446Strhodes result = isc_task_beginexclusive(server->task); 6026135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6027135446Strhodes 6028135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 6029135446Strhodes ISC_LOG_INFO, "shutting down%s", 6030135446Strhodes flush ? ": flushing changes" : ""); 6031135446Strhodes 6032193149Sdougb ns_statschannels_shutdown(server); 6033135446Strhodes ns_controls_shutdown(server->controls); 6034135446Strhodes end_reserved_dispatches(server, ISC_TRUE); 6035224092Sdougb cleanup_session_key(server, server->mctx); 6036135446Strhodes 6037225361Sdougb if (ns_g_aclconfctx != NULL) 6038225361Sdougb cfg_aclconfctx_detach(&ns_g_aclconfctx); 6039225361Sdougb 6040135446Strhodes cfg_obj_destroy(ns_g_parser, &ns_g_config); 6041135446Strhodes cfg_parser_destroy(&ns_g_parser); 6042135446Strhodes 6043135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 6044135446Strhodes view != NULL; 6045135446Strhodes view = view_next) { 6046135446Strhodes view_next = ISC_LIST_NEXT(view, link); 6047135446Strhodes ISC_LIST_UNLINK(server->viewlist, view, link); 6048135446Strhodes if (flush) 6049135446Strhodes dns_view_flushanddetach(&view); 6050135446Strhodes else 6051135446Strhodes dns_view_detach(&view); 6052135446Strhodes } 6053135446Strhodes 6054224092Sdougb while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { 6055224092Sdougb ISC_LIST_UNLINK(server->cachelist, nsc, link); 6056224092Sdougb dns_cache_detach(&nsc->cache); 6057224092Sdougb isc_mem_put(server->mctx, nsc, sizeof(*nsc)); 6058224092Sdougb } 6059224092Sdougb 6060135446Strhodes isc_timer_detach(&server->interface_timer); 6061135446Strhodes isc_timer_detach(&server->heartbeat_timer); 6062170222Sdougb isc_timer_detach(&server->pps_timer); 6063135446Strhodes 6064135446Strhodes ns_interfacemgr_shutdown(server->interfacemgr); 6065135446Strhodes ns_interfacemgr_detach(&server->interfacemgr); 6066135446Strhodes 6067135446Strhodes dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 6068135446Strhodes 6069135446Strhodes dns_zonemgr_shutdown(server->zonemgr); 6070135446Strhodes 6071224092Sdougb if (ns_g_sessionkey != NULL) { 6072224092Sdougb dns_tsigkey_detach(&ns_g_sessionkey); 6073224092Sdougb dns_name_free(&ns_g_sessionkeyname, server->mctx); 6074224092Sdougb } 6075224092Sdougb 6076135446Strhodes if (server->blackholeacl != NULL) 6077135446Strhodes dns_acl_detach(&server->blackholeacl); 6078135446Strhodes 6079135446Strhodes dns_db_detach(&server->in_roothints); 6080135446Strhodes 6081135446Strhodes isc_task_endexclusive(server->task); 6082135446Strhodes 6083135446Strhodes isc_task_detach(&server->task); 6084135446Strhodes 6085135446Strhodes isc_event_free(&event); 6086135446Strhodes} 6087135446Strhodes 6088135446Strhodesvoid 6089135446Strhodesns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 6090135446Strhodes isc_result_t result; 6091225361Sdougb ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 6092135446Strhodes 6093135446Strhodes if (server == NULL) 6094135446Strhodes fatal("allocating server object", ISC_R_NOMEMORY); 6095135446Strhodes 6096135446Strhodes server->mctx = mctx; 6097135446Strhodes server->task = NULL; 6098135446Strhodes 6099135446Strhodes /* Initialize configuration data with default values. */ 6100135446Strhodes 6101135446Strhodes result = isc_quota_init(&server->xfroutquota, 10); 6102135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6103135446Strhodes result = isc_quota_init(&server->tcpquota, 10); 6104135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6105135446Strhodes result = isc_quota_init(&server->recursionquota, 100); 6106135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6107135446Strhodes 6108135446Strhodes result = dns_aclenv_init(mctx, &server->aclenv); 6109135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 6110135446Strhodes 6111135446Strhodes /* Initialize server data structures. */ 6112135446Strhodes server->zonemgr = NULL; 6113135446Strhodes server->interfacemgr = NULL; 6114135446Strhodes ISC_LIST_INIT(server->viewlist); 6115135446Strhodes server->in_roothints = NULL; 6116135446Strhodes server->blackholeacl = NULL; 6117135446Strhodes 6118135446Strhodes CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 6119135446Strhodes &server->in_roothints), 6120135446Strhodes "setting up root hints"); 6121135446Strhodes 6122135446Strhodes CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 6123135446Strhodes "initializing reload event lock"); 6124135446Strhodes server->reload_event = 6125135446Strhodes isc_event_allocate(ns_g_mctx, server, 6126135446Strhodes NS_EVENT_RELOAD, 6127135446Strhodes ns_server_reload, 6128135446Strhodes server, 6129135446Strhodes sizeof(isc_event_t)); 6130135446Strhodes CHECKFATAL(server->reload_event == NULL ? 6131135446Strhodes ISC_R_NOMEMORY : ISC_R_SUCCESS, 6132135446Strhodes "allocating reload event"); 6133135446Strhodes 6134224092Sdougb CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, 6135224092Sdougb ns_g_engine, ISC_ENTROPY_GOODONLY), 6136135446Strhodes "initializing DST"); 6137135446Strhodes 6138135446Strhodes server->tkeyctx = NULL; 6139135446Strhodes CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 6140135446Strhodes &server->tkeyctx), 6141135446Strhodes "creating TKEY context"); 6142135446Strhodes 6143135446Strhodes /* 6144135446Strhodes * Setup the server task, which is responsible for coordinating 6145245163Serwin * startup and shutdown of the server, as well as all exclusive 6146245163Serwin * tasks. 6147135446Strhodes */ 6148135446Strhodes CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 6149135446Strhodes "creating server task"); 6150135446Strhodes isc_task_setname(server->task, "server", server); 6151245163Serwin isc_taskmgr_setexcltask(ns_g_taskmgr, server->task); 6152135446Strhodes CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 6153135446Strhodes "isc_task_onshutdown"); 6154135446Strhodes CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 6155135446Strhodes "isc_app_onrun"); 6156135446Strhodes 6157135446Strhodes server->interface_timer = NULL; 6158135446Strhodes server->heartbeat_timer = NULL; 6159170222Sdougb server->pps_timer = NULL; 6160186462Sdougb 6161135446Strhodes server->interface_interval = 0; 6162135446Strhodes server->heartbeat_interval = 0; 6163135446Strhodes 6164135446Strhodes CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 6165135446Strhodes ns_g_socketmgr, &server->zonemgr), 6166135446Strhodes "dns_zonemgr_create"); 6167225361Sdougb CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), 6168225361Sdougb "dns_zonemgr_setsize"); 6169135446Strhodes 6170135446Strhodes server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 6171135446Strhodes CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 6172135446Strhodes "isc_mem_strdup"); 6173193149Sdougb server->nsstats = NULL; 6174193149Sdougb server->rcvquerystats = NULL; 6175193149Sdougb server->opcodestats = NULL; 6176193149Sdougb server->zonestats = NULL; 6177193149Sdougb server->resolverstats = NULL; 6178193149Sdougb server->sockstats = NULL; 6179193149Sdougb CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats, 6180193149Sdougb isc_sockstatscounter_max), 6181193149Sdougb "isc_stats_create"); 6182193149Sdougb isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats); 6183135446Strhodes 6184224092Sdougb server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys"); 6185224092Sdougb CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY : 6186224092Sdougb ISC_R_SUCCESS, 6187224092Sdougb "isc_mem_strdup"); 6188224092Sdougb 6189135446Strhodes server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 6190135446Strhodes CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 6191135446Strhodes "isc_mem_strdup"); 6192135446Strhodes 6193224092Sdougb server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots"); 6194224092Sdougb CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY : 6195224092Sdougb ISC_R_SUCCESS, 6196224092Sdougb "isc_mem_strdup"); 6197224092Sdougb 6198135446Strhodes server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 6199135446Strhodes CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 6200135446Strhodes "isc_mem_strdup"); 6201135446Strhodes 6202135446Strhodes server->hostname_set = ISC_FALSE; 6203135446Strhodes server->hostname = NULL; 6204186462Sdougb server->version_set = ISC_FALSE; 6205135446Strhodes server->version = NULL; 6206135446Strhodes server->server_usehostname = ISC_FALSE; 6207135446Strhodes server->server_id = NULL; 6208135446Strhodes 6209193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats, 6210193149Sdougb dns_nsstatscounter_max), 6211193149Sdougb "dns_stats_create (server)"); 6212135446Strhodes 6213193149Sdougb CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, 6214193149Sdougb &server->rcvquerystats), 6215193149Sdougb "dns_stats_create (rcvquery)"); 6216193149Sdougb 6217193149Sdougb CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), 6218193149Sdougb "dns_stats_create (opcode)"); 6219193149Sdougb 6220193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats, 6221193149Sdougb dns_zonestatscounter_max), 6222193149Sdougb "dns_stats_create (zone)"); 6223193149Sdougb 6224193149Sdougb CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats, 6225193149Sdougb dns_resstatscounter_max), 6226193149Sdougb "dns_stats_create (resolver)"); 6227193149Sdougb 6228135446Strhodes server->flushonshutdown = ISC_FALSE; 6229135446Strhodes server->log_queries = ISC_FALSE; 6230135446Strhodes 6231135446Strhodes server->controls = NULL; 6232135446Strhodes CHECKFATAL(ns_controls_create(server, &server->controls), 6233135446Strhodes "ns_controls_create"); 6234135446Strhodes server->dispatchgen = 0; 6235135446Strhodes ISC_LIST_INIT(server->dispatches); 6236135446Strhodes 6237193149Sdougb ISC_LIST_INIT(server->statschannels); 6238193149Sdougb 6239224092Sdougb ISC_LIST_INIT(server->cachelist); 6240224092Sdougb 6241224092Sdougb server->sessionkey = NULL; 6242224092Sdougb server->session_keyfile = NULL; 6243224092Sdougb server->session_keyname = NULL; 6244224092Sdougb server->session_keyalg = DST_ALG_UNKNOWN; 6245224092Sdougb server->session_keybits = 0; 6246224092Sdougb 6247135446Strhodes server->magic = NS_SERVER_MAGIC; 6248135446Strhodes *serverp = server; 6249135446Strhodes} 6250135446Strhodes 6251135446Strhodesvoid 6252135446Strhodesns_server_destroy(ns_server_t **serverp) { 6253135446Strhodes ns_server_t *server = *serverp; 6254135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 6255135446Strhodes 6256135446Strhodes ns_controls_destroy(&server->controls); 6257135446Strhodes 6258193149Sdougb isc_stats_detach(&server->nsstats); 6259193149Sdougb dns_stats_detach(&server->rcvquerystats); 6260193149Sdougb dns_stats_detach(&server->opcodestats); 6261193149Sdougb isc_stats_detach(&server->zonestats); 6262193149Sdougb isc_stats_detach(&server->resolverstats); 6263193149Sdougb isc_stats_detach(&server->sockstats); 6264135446Strhodes 6265135446Strhodes isc_mem_free(server->mctx, server->statsfile); 6266224092Sdougb isc_mem_free(server->mctx, server->bindkeysfile); 6267135446Strhodes isc_mem_free(server->mctx, server->dumpfile); 6268224092Sdougb isc_mem_free(server->mctx, server->secrootsfile); 6269135446Strhodes isc_mem_free(server->mctx, server->recfile); 6270135446Strhodes 6271135446Strhodes if (server->version != NULL) 6272135446Strhodes isc_mem_free(server->mctx, server->version); 6273135446Strhodes if (server->hostname != NULL) 6274135446Strhodes isc_mem_free(server->mctx, server->hostname); 6275135446Strhodes if (server->server_id != NULL) 6276135446Strhodes isc_mem_free(server->mctx, server->server_id); 6277135446Strhodes 6278225361Sdougb if (server->zonemgr != NULL) 6279225361Sdougb dns_zonemgr_detach(&server->zonemgr); 6280135446Strhodes 6281135446Strhodes if (server->tkeyctx != NULL) 6282135446Strhodes dns_tkeyctx_destroy(&server->tkeyctx); 6283135446Strhodes 6284135446Strhodes dst_lib_destroy(); 6285135446Strhodes 6286135446Strhodes isc_event_free(&server->reload_event); 6287135446Strhodes 6288135446Strhodes INSIST(ISC_LIST_EMPTY(server->viewlist)); 6289224092Sdougb INSIST(ISC_LIST_EMPTY(server->cachelist)); 6290135446Strhodes 6291135446Strhodes dns_aclenv_destroy(&server->aclenv); 6292135446Strhodes 6293135446Strhodes isc_quota_destroy(&server->recursionquota); 6294135446Strhodes isc_quota_destroy(&server->tcpquota); 6295135446Strhodes isc_quota_destroy(&server->xfroutquota); 6296135446Strhodes 6297135446Strhodes server->magic = 0; 6298135446Strhodes isc_mem_put(server->mctx, server, sizeof(*server)); 6299135446Strhodes *serverp = NULL; 6300135446Strhodes} 6301135446Strhodes 6302135446Strhodesstatic void 6303135446Strhodesfatal(const char *msg, isc_result_t result) { 6304135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 6305135446Strhodes ISC_LOG_CRITICAL, "%s: %s", msg, 6306135446Strhodes isc_result_totext(result)); 6307135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 6308135446Strhodes ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 6309135446Strhodes exit(1); 6310135446Strhodes} 6311135446Strhodes 6312135446Strhodesstatic void 6313135446Strhodesstart_reserved_dispatches(ns_server_t *server) { 6314135446Strhodes 6315135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 6316135446Strhodes 6317135446Strhodes server->dispatchgen++; 6318135446Strhodes} 6319135446Strhodes 6320135446Strhodesstatic void 6321135446Strhodesend_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 6322135446Strhodes ns_dispatch_t *dispatch, *nextdispatch; 6323135446Strhodes 6324135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 6325135446Strhodes 6326135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 6327135446Strhodes dispatch != NULL; 6328135446Strhodes dispatch = nextdispatch) { 6329135446Strhodes nextdispatch = ISC_LIST_NEXT(dispatch, link); 6330135446Strhodes if (!all && server->dispatchgen == dispatch-> dispatchgen) 6331135446Strhodes continue; 6332135446Strhodes ISC_LIST_UNLINK(server->dispatches, dispatch, link); 6333135446Strhodes dns_dispatch_detach(&dispatch->dispatch); 6334135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 6335135446Strhodes } 6336135446Strhodes} 6337135446Strhodes 6338135446Strhodesvoid 6339165071Sdougbns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 6340135446Strhodes ns_dispatch_t *dispatch; 6341135446Strhodes in_port_t port; 6342135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 6343135446Strhodes isc_result_t result; 6344135446Strhodes unsigned int attrs, attrmask; 6345135446Strhodes 6346135446Strhodes REQUIRE(NS_SERVER_VALID(server)); 6347135446Strhodes 6348135446Strhodes port = isc_sockaddr_getport(addr); 6349135446Strhodes if (port == 0 || port >= 1024) 6350135446Strhodes return; 6351135446Strhodes 6352135446Strhodes for (dispatch = ISC_LIST_HEAD(server->dispatches); 6353135446Strhodes dispatch != NULL; 6354135446Strhodes dispatch = ISC_LIST_NEXT(dispatch, link)) { 6355135446Strhodes if (isc_sockaddr_equal(&dispatch->addr, addr)) 6356135446Strhodes break; 6357135446Strhodes } 6358135446Strhodes if (dispatch != NULL) { 6359135446Strhodes dispatch->dispatchgen = server->dispatchgen; 6360135446Strhodes return; 6361135446Strhodes } 6362135446Strhodes 6363135446Strhodes dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 6364135446Strhodes if (dispatch == NULL) { 6365135446Strhodes result = ISC_R_NOMEMORY; 6366135446Strhodes goto cleanup; 6367135446Strhodes } 6368135446Strhodes 6369135446Strhodes dispatch->addr = *addr; 6370135446Strhodes dispatch->dispatchgen = server->dispatchgen; 6371135446Strhodes dispatch->dispatch = NULL; 6372135446Strhodes 6373135446Strhodes attrs = 0; 6374135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 6375135446Strhodes switch (isc_sockaddr_pf(addr)) { 6376135446Strhodes case AF_INET: 6377135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 6378135446Strhodes break; 6379135446Strhodes case AF_INET6: 6380135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 6381135446Strhodes break; 6382135446Strhodes default: 6383135446Strhodes result = ISC_R_NOTIMPLEMENTED; 6384135446Strhodes goto cleanup; 6385135446Strhodes } 6386135446Strhodes attrmask = 0; 6387135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP; 6388135446Strhodes attrmask |= DNS_DISPATCHATTR_TCP; 6389135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4; 6390135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV6; 6391135446Strhodes 6392135446Strhodes result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 6393135446Strhodes ns_g_taskmgr, &dispatch->addr, 4096, 6394135446Strhodes 1000, 32768, 16411, 16433, 6395186462Sdougb attrs, attrmask, &dispatch->dispatch); 6396135446Strhodes if (result != ISC_R_SUCCESS) 6397135446Strhodes goto cleanup; 6398135446Strhodes 6399135446Strhodes ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 6400135446Strhodes 6401135446Strhodes return; 6402135446Strhodes 6403135446Strhodes cleanup: 6404135446Strhodes if (dispatch != NULL) 6405135446Strhodes isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 6406135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 6407135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6408135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 6409135446Strhodes "unable to create dispatch for reserved port %s: %s", 6410135446Strhodes addrbuf, isc_result_totext(result)); 6411135446Strhodes} 6412135446Strhodes 6413135446Strhodes 6414135446Strhodesstatic isc_result_t 6415135446Strhodesloadconfig(ns_server_t *server) { 6416135446Strhodes isc_result_t result; 6417135446Strhodes start_reserved_dispatches(server); 6418135446Strhodes result = load_configuration(ns_g_lwresdonly ? 6419135446Strhodes lwresd_g_conffile : ns_g_conffile, 6420143731Sdougb server, ISC_FALSE); 6421193149Sdougb if (result == ISC_R_SUCCESS) { 6422135446Strhodes end_reserved_dispatches(server, ISC_FALSE); 6423135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6424193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6425193149Sdougb "reloading configuration succeeded"); 6426193149Sdougb } else { 6427193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6428135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6429135446Strhodes "reloading configuration failed: %s", 6430135446Strhodes isc_result_totext(result)); 6431193149Sdougb } 6432135446Strhodes return (result); 6433135446Strhodes} 6434135446Strhodes 6435135446Strhodesstatic isc_result_t 6436135446Strhodesreload(ns_server_t *server) { 6437135446Strhodes isc_result_t result; 6438135446Strhodes CHECK(loadconfig(server)); 6439135446Strhodes 6440262706Serwin result = load_zones(server, ISC_FALSE); 6441193149Sdougb if (result == ISC_R_SUCCESS) 6442135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6443193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6444193149Sdougb "reloading zones succeeded"); 6445193149Sdougb else 6446193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6447135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6448135446Strhodes "reloading zones failed: %s", 6449135446Strhodes isc_result_totext(result)); 6450193149Sdougb 6451135446Strhodes cleanup: 6452135446Strhodes return (result); 6453135446Strhodes} 6454135446Strhodes 6455135446Strhodesstatic void 6456135446Strhodesreconfig(ns_server_t *server) { 6457135446Strhodes isc_result_t result; 6458135446Strhodes CHECK(loadconfig(server)); 6459135446Strhodes 6460135446Strhodes result = load_new_zones(server, ISC_FALSE); 6461193149Sdougb if (result == ISC_R_SUCCESS) 6462135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6463193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6464193149Sdougb "any newly configured zones are now loaded"); 6465193149Sdougb else 6466193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6467135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6468135446Strhodes "loading new zones failed: %s", 6469135446Strhodes isc_result_totext(result)); 6470193149Sdougb 6471135446Strhodes cleanup: ; 6472135446Strhodes} 6473135446Strhodes 6474135446Strhodes/* 6475135446Strhodes * Handle a reload event (from SIGHUP). 6476135446Strhodes */ 6477135446Strhodesstatic void 6478135446Strhodesns_server_reload(isc_task_t *task, isc_event_t *event) { 6479135446Strhodes ns_server_t *server = (ns_server_t *)event->ev_arg; 6480135446Strhodes 6481135446Strhodes INSIST(task = server->task); 6482135446Strhodes UNUSED(task); 6483135446Strhodes 6484193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6485193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6486193149Sdougb "received SIGHUP signal to reload zones"); 6487135446Strhodes (void)reload(server); 6488135446Strhodes 6489135446Strhodes LOCK(&server->reload_event_lock); 6490135446Strhodes INSIST(server->reload_event == NULL); 6491135446Strhodes server->reload_event = event; 6492135446Strhodes UNLOCK(&server->reload_event_lock); 6493135446Strhodes} 6494135446Strhodes 6495135446Strhodesvoid 6496135446Strhodesns_server_reloadwanted(ns_server_t *server) { 6497135446Strhodes LOCK(&server->reload_event_lock); 6498135446Strhodes if (server->reload_event != NULL) 6499135446Strhodes isc_task_send(server->task, &server->reload_event); 6500135446Strhodes UNLOCK(&server->reload_event_lock); 6501135446Strhodes} 6502135446Strhodes 6503135446Strhodesstatic char * 6504135446Strhodesnext_token(char **stringp, const char *delim) { 6505135446Strhodes char *res; 6506135446Strhodes 6507135446Strhodes do { 6508135446Strhodes res = strsep(stringp, delim); 6509135446Strhodes if (res == NULL) 6510135446Strhodes break; 6511135446Strhodes } while (*res == '\0'); 6512135446Strhodes return (res); 6513186462Sdougb} 6514135446Strhodes 6515135446Strhodes/* 6516135446Strhodes * Find the zone specified in the control channel command 'args', 6517135446Strhodes * if any. If a zone is specified, point '*zonep' at it, otherwise 6518135446Strhodes * set '*zonep' to NULL. 6519135446Strhodes */ 6520135446Strhodesstatic isc_result_t 6521254897Serwinzone_from_args(ns_server_t *server, char *args, const char *zonetxt, 6522262706Serwin dns_zone_t **zonep, const char **zonename, 6523262706Serwin isc_buffer_t *text, isc_boolean_t skip) 6524224092Sdougb{ 6525135446Strhodes char *input, *ptr; 6526135446Strhodes char *classtxt; 6527135446Strhodes const char *viewtxt = NULL; 6528262706Serwin dns_fixedname_t fname; 6529262706Serwin dns_name_t *name; 6530135446Strhodes isc_result_t result; 6531135446Strhodes dns_view_t *view = NULL; 6532135446Strhodes dns_rdataclass_t rdclass; 6533262706Serwin char problem[DNS_NAME_FORMATSIZE + 500] = ""; 6534135446Strhodes 6535135446Strhodes REQUIRE(zonep != NULL && *zonep == NULL); 6536254402Serwin REQUIRE(zonename == NULL || *zonename == NULL); 6537135446Strhodes 6538135446Strhodes input = args; 6539135446Strhodes 6540254897Serwin if (skip) { 6541254897Serwin /* Skip the command name. */ 6542254897Serwin ptr = next_token(&input, " \t"); 6543254897Serwin if (ptr == NULL) 6544254897Serwin return (ISC_R_UNEXPECTEDEND); 6545254897Serwin } 6546135446Strhodes 6547135446Strhodes /* Look for the zone name. */ 6548135446Strhodes if (zonetxt == NULL) 6549254897Serwin zonetxt = next_token(&input, " \t"); 6550254897Serwin if (zonetxt == NULL) 6551135446Strhodes return (ISC_R_SUCCESS); 6552254402Serwin if (zonename != NULL) 6553224092Sdougb *zonename = zonetxt; 6554135446Strhodes 6555135446Strhodes /* Look for the optional class name. */ 6556135446Strhodes classtxt = next_token(&input, " \t"); 6557135446Strhodes if (classtxt != NULL) { 6558135446Strhodes /* Look for the optional view name. */ 6559135446Strhodes viewtxt = next_token(&input, " \t"); 6560135446Strhodes } 6561135446Strhodes 6562262706Serwin dns_fixedname_init(&fname); 6563262706Serwin name = dns_fixedname_name(&fname); 6564262706Serwin CHECK(dns_name_fromstring(name, zonetxt, 0, NULL)); 6565135446Strhodes 6566135446Strhodes if (classtxt != NULL) { 6567135446Strhodes isc_textregion_t r; 6568135446Strhodes r.base = classtxt; 6569135446Strhodes r.length = strlen(classtxt); 6570262706Serwin CHECK(dns_rdataclass_fromtext(&rdclass, &r)); 6571193149Sdougb } else 6572193149Sdougb rdclass = dns_rdataclass_in; 6573193149Sdougb 6574193149Sdougb if (viewtxt == NULL) { 6575262706Serwin result = dns_viewlist_findzone(&server->viewlist, name, 6576193149Sdougb ISC_TF(classtxt == NULL), 6577193149Sdougb rdclass, zonep); 6578262706Serwin if (result == ISC_R_NOTFOUND) 6579262706Serwin snprintf(problem, sizeof(problem), 6580262706Serwin "no matching zone '%s' in any view", 6581262706Serwin zonetxt); 6582135446Strhodes } else { 6583193149Sdougb result = dns_viewlist_find(&server->viewlist, viewtxt, 6584193149Sdougb rdclass, &view); 6585262706Serwin if (result != ISC_R_SUCCESS) { 6586262706Serwin snprintf(problem, sizeof(problem), 6587262706Serwin "no matching view '%s'", viewtxt); 6588262706Serwin goto report; 6589262706Serwin } 6590262706Serwin 6591262706Serwin result = dns_zt_find(view->zonetable, name, 0, NULL, zonep); 6592193149Sdougb if (result != ISC_R_SUCCESS) 6593262706Serwin snprintf(problem, sizeof(problem), 6594262706Serwin "no matching zone '%s' in view '%s'", 6595262706Serwin zonetxt, viewtxt); 6596135446Strhodes } 6597186462Sdougb 6598135446Strhodes /* Partial match? */ 6599135446Strhodes if (result != ISC_R_SUCCESS && *zonep != NULL) 6600135446Strhodes dns_zone_detach(zonep); 6601204619Sdougb if (result == DNS_R_PARTIALMATCH) 6602204619Sdougb result = ISC_R_NOTFOUND; 6603262706Serwin report: 6604262706Serwin if (result != ISC_R_SUCCESS) { 6605262706Serwin isc_result_t tresult; 6606262706Serwin 6607262706Serwin tresult = putstr(text, problem); 6608262706Serwin if (tresult == ISC_R_SUCCESS && 6609262706Serwin isc_buffer_availablelength(text) > 0U) 6610262706Serwin isc_buffer_putuint8(text, 0); 6611262706Serwin } 6612262706Serwin 6613262706Serwin cleanup: 6614262706Serwin if (view != NULL) 6615262706Serwin dns_view_detach(&view); 6616262706Serwin 6617135446Strhodes return (result); 6618135446Strhodes} 6619135446Strhodes 6620135446Strhodes/* 6621135446Strhodes * Act on a "retransfer" command from the command channel. 6622135446Strhodes */ 6623135446Strhodesisc_result_t 6624262706Serwinns_server_retransfercommand(ns_server_t *server, char *args, 6625262706Serwin isc_buffer_t *text) 6626262706Serwin{ 6627135446Strhodes isc_result_t result; 6628135446Strhodes dns_zone_t *zone = NULL; 6629254897Serwin dns_zone_t *raw = NULL; 6630135446Strhodes dns_zonetype_t type; 6631186462Sdougb 6632262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 6633262706Serwin text, ISC_TRUE); 6634135446Strhodes if (result != ISC_R_SUCCESS) 6635135446Strhodes return (result); 6636135446Strhodes if (zone == NULL) 6637135446Strhodes return (ISC_R_UNEXPECTEDEND); 6638254897Serwin dns_zone_getraw(zone, &raw); 6639254897Serwin if (raw != NULL) { 6640254897Serwin dns_zone_detach(&zone); 6641254897Serwin dns_zone_attach(raw, &zone); 6642254897Serwin dns_zone_detach(&raw); 6643254897Serwin } 6644135446Strhodes type = dns_zone_gettype(zone); 6645135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) 6646135446Strhodes dns_zone_forcereload(zone); 6647135446Strhodes else 6648135446Strhodes result = ISC_R_NOTFOUND; 6649135446Strhodes dns_zone_detach(&zone); 6650135446Strhodes return (result); 6651186462Sdougb} 6652135446Strhodes 6653135446Strhodes/* 6654135446Strhodes * Act on a "reload" command from the command channel. 6655135446Strhodes */ 6656135446Strhodesisc_result_t 6657135446Strhodesns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6658135446Strhodes isc_result_t result; 6659135446Strhodes dns_zone_t *zone = NULL; 6660135446Strhodes dns_zonetype_t type; 6661135446Strhodes const char *msg = NULL; 6662186462Sdougb 6663262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 6664262706Serwin text, ISC_TRUE); 6665135446Strhodes if (result != ISC_R_SUCCESS) 6666135446Strhodes return (result); 6667135446Strhodes if (zone == NULL) { 6668135446Strhodes result = reload(server); 6669135446Strhodes if (result == ISC_R_SUCCESS) 6670135446Strhodes msg = "server reload successful"; 6671135446Strhodes } else { 6672135446Strhodes type = dns_zone_gettype(zone); 6673135446Strhodes if (type == dns_zone_slave || type == dns_zone_stub) { 6674135446Strhodes dns_zone_refresh(zone); 6675174187Sdougb dns_zone_detach(&zone); 6676135446Strhodes msg = "zone refresh queued"; 6677135446Strhodes } else { 6678135446Strhodes result = dns_zone_load(zone); 6679135446Strhodes dns_zone_detach(&zone); 6680186462Sdougb switch (result) { 6681135446Strhodes case ISC_R_SUCCESS: 6682135446Strhodes msg = "zone reload successful"; 6683135446Strhodes break; 6684135446Strhodes case DNS_R_CONTINUE: 6685135446Strhodes msg = "zone reload queued"; 6686135446Strhodes result = ISC_R_SUCCESS; 6687135446Strhodes break; 6688135446Strhodes case DNS_R_UPTODATE: 6689135446Strhodes msg = "zone reload up-to-date"; 6690135446Strhodes result = ISC_R_SUCCESS; 6691135446Strhodes break; 6692135446Strhodes default: 6693135446Strhodes /* failure message will be generated by rndc */ 6694135446Strhodes break; 6695135446Strhodes } 6696135446Strhodes } 6697135446Strhodes } 6698135446Strhodes if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 6699135446Strhodes isc_buffer_putmem(text, (const unsigned char *)msg, 6700135446Strhodes strlen(msg) + 1); 6701135446Strhodes return (result); 6702186462Sdougb} 6703135446Strhodes 6704135446Strhodes/* 6705135446Strhodes * Act on a "reconfig" command from the command channel. 6706135446Strhodes */ 6707135446Strhodesisc_result_t 6708135446Strhodesns_server_reconfigcommand(ns_server_t *server, char *args) { 6709135446Strhodes UNUSED(args); 6710135446Strhodes 6711135446Strhodes reconfig(server); 6712135446Strhodes return (ISC_R_SUCCESS); 6713135446Strhodes} 6714135446Strhodes 6715135446Strhodes/* 6716170222Sdougb * Act on a "notify" command from the command channel. 6717170222Sdougb */ 6718170222Sdougbisc_result_t 6719170222Sdougbns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6720170222Sdougb isc_result_t result; 6721170222Sdougb dns_zone_t *zone = NULL; 6722170222Sdougb const unsigned char msg[] = "zone notify queued"; 6723170222Sdougb 6724262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 6725262706Serwin text, ISC_TRUE); 6726170222Sdougb if (result != ISC_R_SUCCESS) 6727170222Sdougb return (result); 6728170222Sdougb if (zone == NULL) 6729170222Sdougb return (ISC_R_UNEXPECTEDEND); 6730186462Sdougb 6731170222Sdougb dns_zone_notify(zone); 6732170222Sdougb dns_zone_detach(&zone); 6733170222Sdougb if (sizeof(msg) <= isc_buffer_availablelength(text)) 6734170222Sdougb isc_buffer_putmem(text, msg, sizeof(msg)); 6735170222Sdougb 6736170222Sdougb return (ISC_R_SUCCESS); 6737186462Sdougb} 6738170222Sdougb 6739170222Sdougb/* 6740135446Strhodes * Act on a "refresh" command from the command channel. 6741135446Strhodes */ 6742135446Strhodesisc_result_t 6743135446Strhodesns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 6744135446Strhodes isc_result_t result; 6745262706Serwin dns_zone_t *zone = NULL, *raw = NULL; 6746165071Sdougb const unsigned char msg1[] = "zone refresh queued"; 6747165071Sdougb const unsigned char msg2[] = "not a slave or stub zone"; 6748165071Sdougb dns_zonetype_t type; 6749135446Strhodes 6750262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 6751262706Serwin text, ISC_TRUE); 6752135446Strhodes if (result != ISC_R_SUCCESS) 6753135446Strhodes return (result); 6754135446Strhodes if (zone == NULL) 6755135446Strhodes return (ISC_R_UNEXPECTEDEND); 6756165071Sdougb 6757262706Serwin dns_zone_getraw(zone, &raw); 6758262706Serwin if (raw != NULL) { 6759262706Serwin dns_zone_detach(&zone); 6760262706Serwin dns_zone_attach(raw, &zone); 6761262706Serwin dns_zone_detach(&raw); 6762262706Serwin } 6763262706Serwin 6764165071Sdougb type = dns_zone_gettype(zone); 6765165071Sdougb if (type == dns_zone_slave || type == dns_zone_stub) { 6766165071Sdougb dns_zone_refresh(zone); 6767165071Sdougb dns_zone_detach(&zone); 6768165071Sdougb if (sizeof(msg1) <= isc_buffer_availablelength(text)) 6769165071Sdougb isc_buffer_putmem(text, msg1, sizeof(msg1)); 6770165071Sdougb return (ISC_R_SUCCESS); 6771165071Sdougb } 6772186462Sdougb 6773135446Strhodes dns_zone_detach(&zone); 6774165071Sdougb if (sizeof(msg2) <= isc_buffer_availablelength(text)) 6775165071Sdougb isc_buffer_putmem(text, msg2, sizeof(msg2)); 6776165071Sdougb return (ISC_R_FAILURE); 6777186462Sdougb} 6778135446Strhodes 6779135446Strhodesisc_result_t 6780254897Serwinns_server_togglequerylog(ns_server_t *server, char *args) { 6781254897Serwin isc_boolean_t value; 6782254897Serwin char *ptr; 6783186462Sdougb 6784254897Serwin /* Skip the command name. */ 6785254897Serwin ptr = next_token(&args, " \t"); 6786254897Serwin if (ptr == NULL) 6787254897Serwin return (ISC_R_UNEXPECTEDEND); 6788254897Serwin 6789254897Serwin ptr = next_token(&args, " \t"); 6790254897Serwin if (ptr == NULL) 6791254897Serwin value = server->log_queries ? ISC_FALSE : ISC_TRUE; 6792254897Serwin else if (strcasecmp(ptr, "yes") == 0 || strcasecmp(ptr, "on") == 0) 6793254897Serwin value = ISC_TRUE; 6794254897Serwin else if (strcasecmp(ptr, "no") == 0 || strcasecmp(ptr, "off") == 0) 6795254897Serwin value = ISC_FALSE; 6796254897Serwin else 6797254897Serwin return (ISC_R_NOTFOUND); 6798254897Serwin 6799254897Serwin if (server->log_queries == value) 6800254897Serwin return (ISC_R_SUCCESS); 6801254897Serwin 6802254897Serwin server->log_queries = value; 6803254897Serwin 6804135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6805135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6806135446Strhodes "query logging is now %s", 6807135446Strhodes server->log_queries ? "on" : "off"); 6808135446Strhodes return (ISC_R_SUCCESS); 6809135446Strhodes} 6810135446Strhodes 6811135446Strhodesstatic isc_result_t 6812165071Sdougbns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 6813170222Sdougb cfg_aclconfctx_t *actx, 6814135446Strhodes isc_mem_t *mctx, ns_listenlist_t **target) 6815135446Strhodes{ 6816135446Strhodes isc_result_t result; 6817165071Sdougb const cfg_listelt_t *element; 6818135446Strhodes ns_listenlist_t *dlist = NULL; 6819135446Strhodes 6820135446Strhodes REQUIRE(target != NULL && *target == NULL); 6821135446Strhodes 6822135446Strhodes result = ns_listenlist_create(mctx, &dlist); 6823135446Strhodes if (result != ISC_R_SUCCESS) 6824135446Strhodes return (result); 6825135446Strhodes 6826135446Strhodes for (element = cfg_list_first(listenlist); 6827135446Strhodes element != NULL; 6828135446Strhodes element = cfg_list_next(element)) 6829135446Strhodes { 6830135446Strhodes ns_listenelt_t *delt = NULL; 6831165071Sdougb const cfg_obj_t *listener = cfg_listelt_value(element); 6832135446Strhodes result = ns_listenelt_fromconfig(listener, config, actx, 6833135446Strhodes mctx, &delt); 6834135446Strhodes if (result != ISC_R_SUCCESS) 6835135446Strhodes goto cleanup; 6836135446Strhodes ISC_LIST_APPEND(dlist->elts, delt, link); 6837135446Strhodes } 6838135446Strhodes *target = dlist; 6839135446Strhodes return (ISC_R_SUCCESS); 6840135446Strhodes 6841135446Strhodes cleanup: 6842135446Strhodes ns_listenlist_detach(&dlist); 6843135446Strhodes return (result); 6844135446Strhodes} 6845135446Strhodes 6846135446Strhodes/* 6847135446Strhodes * Create a listen list from the corresponding configuration 6848135446Strhodes * data structure. 6849135446Strhodes */ 6850135446Strhodesstatic isc_result_t 6851165071Sdougbns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 6852170222Sdougb cfg_aclconfctx_t *actx, 6853135446Strhodes isc_mem_t *mctx, ns_listenelt_t **target) 6854135446Strhodes{ 6855135446Strhodes isc_result_t result; 6856165071Sdougb const cfg_obj_t *portobj; 6857135446Strhodes in_port_t port; 6858135446Strhodes ns_listenelt_t *delt = NULL; 6859135446Strhodes REQUIRE(target != NULL && *target == NULL); 6860135446Strhodes 6861135446Strhodes portobj = cfg_tuple_get(listener, "port"); 6862135446Strhodes if (!cfg_obj_isuint32(portobj)) { 6863135446Strhodes if (ns_g_port != 0) { 6864135446Strhodes port = ns_g_port; 6865135446Strhodes } else { 6866135446Strhodes result = ns_config_getport(config, &port); 6867135446Strhodes if (result != ISC_R_SUCCESS) 6868135446Strhodes return (result); 6869135446Strhodes } 6870135446Strhodes } else { 6871135446Strhodes if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 6872135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 6873135446Strhodes "port value '%u' is out of range", 6874135446Strhodes cfg_obj_asuint32(portobj)); 6875135446Strhodes return (ISC_R_RANGE); 6876135446Strhodes } 6877135446Strhodes port = (in_port_t)cfg_obj_asuint32(portobj); 6878135446Strhodes } 6879135446Strhodes 6880135446Strhodes result = ns_listenelt_create(mctx, port, NULL, &delt); 6881135446Strhodes if (result != ISC_R_SUCCESS) 6882135446Strhodes return (result); 6883135446Strhodes 6884170222Sdougb result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), 6885193149Sdougb config, ns_g_lctx, actx, mctx, 0, 6886193149Sdougb &delt->acl); 6887135446Strhodes if (result != ISC_R_SUCCESS) { 6888135446Strhodes ns_listenelt_destroy(delt); 6889135446Strhodes return (result); 6890135446Strhodes } 6891135446Strhodes *target = delt; 6892135446Strhodes return (ISC_R_SUCCESS); 6893135446Strhodes} 6894135446Strhodes 6895135446Strhodesisc_result_t 6896135446Strhodesns_server_dumpstats(ns_server_t *server) { 6897135446Strhodes isc_result_t result; 6898135446Strhodes FILE *fp = NULL; 6899135446Strhodes 6900135446Strhodes CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 6901135446Strhodes "could not open statistics dump file", server->statsfile); 6902186462Sdougb 6903193149Sdougb result = ns_stats_dump(server, fp); 6904186462Sdougb 6905135446Strhodes cleanup: 6906135446Strhodes if (fp != NULL) 6907135446Strhodes (void)isc_stdio_close(fp); 6908193149Sdougb if (result == ISC_R_SUCCESS) 6909193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6910193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 6911193149Sdougb "dumpstats complete"); 6912193149Sdougb else 6913193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 6914193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 6915193149Sdougb "dumpstats failed: %s", 6916193149Sdougb dns_result_totext(result)); 6917135446Strhodes return (result); 6918135446Strhodes} 6919135446Strhodes 6920135446Strhodesstatic isc_result_t 6921135446Strhodesadd_zone_tolist(dns_zone_t *zone, void *uap) { 6922135446Strhodes struct dumpcontext *dctx = uap; 6923135446Strhodes struct zonelistentry *zle; 6924135446Strhodes 6925135446Strhodes zle = isc_mem_get(dctx->mctx, sizeof *zle); 6926135446Strhodes if (zle == NULL) 6927135446Strhodes return (ISC_R_NOMEMORY); 6928135446Strhodes zle->zone = NULL; 6929135446Strhodes dns_zone_attach(zone, &zle->zone); 6930135446Strhodes ISC_LINK_INIT(zle, link); 6931135446Strhodes ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 6932135446Strhodes return (ISC_R_SUCCESS); 6933135446Strhodes} 6934135446Strhodes 6935135446Strhodesstatic isc_result_t 6936135446Strhodesadd_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 6937135446Strhodes struct viewlistentry *vle; 6938135446Strhodes isc_result_t result = ISC_R_SUCCESS; 6939186462Sdougb 6940153816Sdougb /* 6941153816Sdougb * Prevent duplicate views. 6942153816Sdougb */ 6943153816Sdougb for (vle = ISC_LIST_HEAD(dctx->viewlist); 6944153816Sdougb vle != NULL; 6945153816Sdougb vle = ISC_LIST_NEXT(vle, link)) 6946153816Sdougb if (vle->view == view) 6947153816Sdougb return (ISC_R_SUCCESS); 6948153816Sdougb 6949135446Strhodes vle = isc_mem_get(dctx->mctx, sizeof *vle); 6950135446Strhodes if (vle == NULL) 6951135446Strhodes return (ISC_R_NOMEMORY); 6952135446Strhodes vle->view = NULL; 6953135446Strhodes dns_view_attach(view, &vle->view); 6954135446Strhodes ISC_LINK_INIT(vle, link); 6955135446Strhodes ISC_LIST_INIT(vle->zonelist); 6956135446Strhodes ISC_LIST_APPEND(dctx->viewlist, vle, link); 6957135446Strhodes if (dctx->dumpzones) 6958135446Strhodes result = dns_zt_apply(view->zonetable, ISC_TRUE, 6959135446Strhodes add_zone_tolist, dctx); 6960135446Strhodes return (result); 6961135446Strhodes} 6962135446Strhodes 6963135446Strhodesstatic void 6964135446Strhodesdumpcontext_destroy(struct dumpcontext *dctx) { 6965135446Strhodes struct viewlistentry *vle; 6966135446Strhodes struct zonelistentry *zle; 6967135446Strhodes 6968135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6969135446Strhodes while (vle != NULL) { 6970135446Strhodes ISC_LIST_UNLINK(dctx->viewlist, vle, link); 6971135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6972135446Strhodes while (zle != NULL) { 6973135446Strhodes ISC_LIST_UNLINK(vle->zonelist, zle, link); 6974135446Strhodes dns_zone_detach(&zle->zone); 6975135446Strhodes isc_mem_put(dctx->mctx, zle, sizeof *zle); 6976135446Strhodes zle = ISC_LIST_HEAD(vle->zonelist); 6977135446Strhodes } 6978135446Strhodes dns_view_detach(&vle->view); 6979135446Strhodes isc_mem_put(dctx->mctx, vle, sizeof *vle); 6980135446Strhodes vle = ISC_LIST_HEAD(dctx->viewlist); 6981135446Strhodes } 6982135446Strhodes if (dctx->version != NULL) 6983135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 6984135446Strhodes if (dctx->db != NULL) 6985135446Strhodes dns_db_detach(&dctx->db); 6986135446Strhodes if (dctx->cache != NULL) 6987135446Strhodes dns_db_detach(&dctx->cache); 6988135446Strhodes if (dctx->task != NULL) 6989135446Strhodes isc_task_detach(&dctx->task); 6990135446Strhodes if (dctx->fp != NULL) 6991135446Strhodes (void)isc_stdio_close(dctx->fp); 6992135446Strhodes if (dctx->mdctx != NULL) 6993135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 6994135446Strhodes isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 6995135446Strhodes} 6996135446Strhodes 6997135446Strhodesstatic void 6998135446Strhodesdumpdone(void *arg, isc_result_t result) { 6999135446Strhodes struct dumpcontext *dctx = arg; 7000135446Strhodes char buf[1024+32]; 7001135446Strhodes const dns_master_style_t *style; 7002186462Sdougb 7003135446Strhodes if (result != ISC_R_SUCCESS) 7004135446Strhodes goto cleanup; 7005135446Strhodes if (dctx->mdctx != NULL) 7006135446Strhodes dns_dumpctx_detach(&dctx->mdctx); 7007135446Strhodes if (dctx->view == NULL) { 7008135446Strhodes dctx->view = ISC_LIST_HEAD(dctx->viewlist); 7009135446Strhodes if (dctx->view == NULL) 7010135446Strhodes goto done; 7011135446Strhodes INSIST(dctx->zone == NULL); 7012153816Sdougb } else 7013153816Sdougb goto resume; 7014135446Strhodes nextview: 7015135446Strhodes fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 7016153816Sdougb resume: 7017224092Sdougb if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) { 7018224092Sdougb fprintf(dctx->fp, 7019224092Sdougb ";\n; Cache of view '%s' is shared as '%s'\n", 7020224092Sdougb dctx->view->view->name, 7021224092Sdougb dns_cache_getname(dctx->view->view->cache)); 7022224092Sdougb } else if (dctx->zone == NULL && dctx->cache == NULL && 7023224092Sdougb dctx->dumpcache) 7024224092Sdougb { 7025135446Strhodes style = &dns_master_style_cache; 7026135446Strhodes /* start cache dump */ 7027135446Strhodes if (dctx->view->view->cachedb != NULL) 7028135446Strhodes dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 7029135446Strhodes if (dctx->cache != NULL) { 7030224092Sdougb fprintf(dctx->fp, 7031224092Sdougb ";\n; Cache dump of view '%s' (cache %s)\n;\n", 7032224092Sdougb dctx->view->view->name, 7033224092Sdougb dns_cache_getname(dctx->view->view->cache)); 7034135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 7035135446Strhodes dctx->cache, NULL, 7036135446Strhodes style, dctx->fp, 7037135446Strhodes dctx->task, 7038135446Strhodes dumpdone, dctx, 7039135446Strhodes &dctx->mdctx); 7040135446Strhodes if (result == DNS_R_CONTINUE) 7041135446Strhodes return; 7042135446Strhodes if (result == ISC_R_NOTIMPLEMENTED) 7043135446Strhodes fprintf(dctx->fp, "; %s\n", 7044135446Strhodes dns_result_totext(result)); 7045135446Strhodes else if (result != ISC_R_SUCCESS) 7046135446Strhodes goto cleanup; 7047135446Strhodes } 7048135446Strhodes } 7049135446Strhodes if (dctx->cache != NULL) { 7050135446Strhodes dns_adb_dump(dctx->view->view->adb, dctx->fp); 7051205292Sdougb dns_resolver_printbadcache(dctx->view->view->resolver, 7052205292Sdougb dctx->fp); 7053135446Strhodes dns_db_detach(&dctx->cache); 7054135446Strhodes } 7055135446Strhodes if (dctx->dumpzones) { 7056135446Strhodes style = &dns_master_style_full; 7057135446Strhodes nextzone: 7058135446Strhodes if (dctx->version != NULL) 7059135446Strhodes dns_db_closeversion(dctx->db, &dctx->version, 7060135446Strhodes ISC_FALSE); 7061135446Strhodes if (dctx->db != NULL) 7062135446Strhodes dns_db_detach(&dctx->db); 7063135446Strhodes if (dctx->zone == NULL) 7064135446Strhodes dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 7065135446Strhodes else 7066135446Strhodes dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 7067135446Strhodes if (dctx->zone != NULL) { 7068135446Strhodes /* start zone dump */ 7069135446Strhodes dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 7070135446Strhodes fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 7071135446Strhodes result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 7072135446Strhodes if (result != ISC_R_SUCCESS) { 7073135446Strhodes fprintf(dctx->fp, "; %s\n", 7074135446Strhodes dns_result_totext(result)); 7075135446Strhodes goto nextzone; 7076135446Strhodes } 7077135446Strhodes dns_db_currentversion(dctx->db, &dctx->version); 7078135446Strhodes result = dns_master_dumptostreaminc(dctx->mctx, 7079135446Strhodes dctx->db, 7080135446Strhodes dctx->version, 7081135446Strhodes style, dctx->fp, 7082135446Strhodes dctx->task, 7083135446Strhodes dumpdone, dctx, 7084135446Strhodes &dctx->mdctx); 7085135446Strhodes if (result == DNS_R_CONTINUE) 7086135446Strhodes return; 7087153816Sdougb if (result == ISC_R_NOTIMPLEMENTED) { 7088135446Strhodes fprintf(dctx->fp, "; %s\n", 7089135446Strhodes dns_result_totext(result)); 7090153816Sdougb result = ISC_R_SUCCESS; 7091225361Sdougb POST(result); 7092153816Sdougb goto nextzone; 7093153816Sdougb } 7094135446Strhodes if (result != ISC_R_SUCCESS) 7095135446Strhodes goto cleanup; 7096135446Strhodes } 7097135446Strhodes } 7098135446Strhodes if (dctx->view != NULL) 7099135446Strhodes dctx->view = ISC_LIST_NEXT(dctx->view, link); 7100135446Strhodes if (dctx->view != NULL) 7101135446Strhodes goto nextview; 7102135446Strhodes done: 7103135446Strhodes fprintf(dctx->fp, "; Dump complete\n"); 7104135446Strhodes result = isc_stdio_flush(dctx->fp); 7105135446Strhodes if (result == ISC_R_SUCCESS) 7106135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7107135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7108135446Strhodes "dumpdb complete"); 7109135446Strhodes cleanup: 7110135446Strhodes if (result != ISC_R_SUCCESS) 7111135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7112193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7113135446Strhodes "dumpdb failed: %s", dns_result_totext(result)); 7114135446Strhodes dumpcontext_destroy(dctx); 7115135446Strhodes} 7116135446Strhodes 7117135446Strhodesisc_result_t 7118135446Strhodesns_server_dumpdb(ns_server_t *server, char *args) { 7119135446Strhodes struct dumpcontext *dctx = NULL; 7120135446Strhodes dns_view_t *view; 7121135446Strhodes isc_result_t result; 7122135446Strhodes char *ptr; 7123135446Strhodes const char *sep; 7124135446Strhodes 7125165071Sdougb /* Skip the command name. */ 7126165071Sdougb ptr = next_token(&args, " \t"); 7127165071Sdougb if (ptr == NULL) 7128165071Sdougb return (ISC_R_UNEXPECTEDEND); 7129165071Sdougb 7130135446Strhodes dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 7131135446Strhodes if (dctx == NULL) 7132135446Strhodes return (ISC_R_NOMEMORY); 7133135446Strhodes 7134135446Strhodes dctx->mctx = server->mctx; 7135135446Strhodes dctx->dumpcache = ISC_TRUE; 7136135446Strhodes dctx->dumpzones = ISC_FALSE; 7137135446Strhodes dctx->fp = NULL; 7138135446Strhodes ISC_LIST_INIT(dctx->viewlist); 7139135446Strhodes dctx->view = NULL; 7140135446Strhodes dctx->zone = NULL; 7141135446Strhodes dctx->cache = NULL; 7142135446Strhodes dctx->mdctx = NULL; 7143135446Strhodes dctx->db = NULL; 7144135446Strhodes dctx->cache = NULL; 7145135446Strhodes dctx->task = NULL; 7146135446Strhodes dctx->version = NULL; 7147135446Strhodes isc_task_attach(server->task, &dctx->task); 7148135446Strhodes 7149135446Strhodes CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 7150135446Strhodes "could not open dump file", server->dumpfile); 7151135446Strhodes 7152135446Strhodes sep = (args == NULL) ? "" : ": "; 7153135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7154135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7155135446Strhodes "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 7156135446Strhodes 7157135446Strhodes ptr = next_token(&args, " \t"); 7158135446Strhodes if (ptr != NULL && strcmp(ptr, "-all") == 0) { 7159135446Strhodes dctx->dumpzones = ISC_TRUE; 7160135446Strhodes dctx->dumpcache = ISC_TRUE; 7161135446Strhodes ptr = next_token(&args, " \t"); 7162135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 7163135446Strhodes dctx->dumpzones = ISC_FALSE; 7164135446Strhodes dctx->dumpcache = ISC_TRUE; 7165135446Strhodes ptr = next_token(&args, " \t"); 7166135446Strhodes } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 7167135446Strhodes dctx->dumpzones = ISC_TRUE; 7168135446Strhodes dctx->dumpcache = ISC_FALSE; 7169135446Strhodes ptr = next_token(&args, " \t"); 7170186462Sdougb } 7171135446Strhodes 7172153816Sdougb nextview: 7173135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 7174135446Strhodes view != NULL; 7175135446Strhodes view = ISC_LIST_NEXT(view, link)) 7176135446Strhodes { 7177135446Strhodes if (ptr != NULL && strcmp(view->name, ptr) != 0) 7178135446Strhodes continue; 7179135446Strhodes CHECK(add_view_tolist(dctx, view)); 7180135446Strhodes } 7181153816Sdougb if (ptr != NULL) { 7182153816Sdougb ptr = next_token(&args, " \t"); 7183153816Sdougb if (ptr != NULL) 7184153816Sdougb goto nextview; 7185153816Sdougb } 7186135446Strhodes dumpdone(dctx, ISC_R_SUCCESS); 7187135446Strhodes return (ISC_R_SUCCESS); 7188135446Strhodes 7189135446Strhodes cleanup: 7190135446Strhodes if (dctx != NULL) 7191135446Strhodes dumpcontext_destroy(dctx); 7192135446Strhodes return (result); 7193135446Strhodes} 7194135446Strhodes 7195135446Strhodesisc_result_t 7196224092Sdougbns_server_dumpsecroots(ns_server_t *server, char *args) { 7197224092Sdougb dns_view_t *view; 7198224092Sdougb dns_keytable_t *secroots = NULL; 7199224092Sdougb isc_result_t result; 7200224092Sdougb char *ptr; 7201224092Sdougb FILE *fp = NULL; 7202224092Sdougb isc_time_t now; 7203224092Sdougb char tbuf[64]; 7204224092Sdougb 7205224092Sdougb /* Skip the command name. */ 7206224092Sdougb ptr = next_token(&args, " \t"); 7207224092Sdougb if (ptr == NULL) 7208224092Sdougb return (ISC_R_UNEXPECTEDEND); 7209254897Serwin 7210224092Sdougb ptr = next_token(&args, " \t"); 7211224092Sdougb 7212224092Sdougb CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp), 7213224092Sdougb "could not open secroots dump file", server->secrootsfile); 7214224092Sdougb TIME_NOW(&now); 7215224092Sdougb isc_time_formattimestamp(&now, tbuf, sizeof(tbuf)); 7216224092Sdougb fprintf(fp, "%s\n", tbuf); 7217224092Sdougb 7218225361Sdougb do { 7219225361Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7220225361Sdougb view != NULL; 7221225361Sdougb view = ISC_LIST_NEXT(view, link)) 7222225361Sdougb { 7223225361Sdougb if (ptr != NULL && strcmp(view->name, ptr) != 0) 7224225361Sdougb continue; 7225225361Sdougb if (secroots != NULL) 7226225361Sdougb dns_keytable_detach(&secroots); 7227225361Sdougb result = dns_view_getsecroots(view, &secroots); 7228225361Sdougb if (result == ISC_R_NOTFOUND) { 7229225361Sdougb result = ISC_R_SUCCESS; 7230225361Sdougb continue; 7231225361Sdougb } 7232225361Sdougb fprintf(fp, "\n Start view %s\n\n", view->name); 7233225361Sdougb result = dns_keytable_dump(secroots, fp); 7234225361Sdougb if (result != ISC_R_SUCCESS) 7235225361Sdougb fprintf(fp, " dumpsecroots failed: %s\n", 7236225361Sdougb isc_result_totext(result)); 7237224092Sdougb } 7238224092Sdougb if (ptr != NULL) 7239225361Sdougb ptr = next_token(&args, " \t"); 7240225361Sdougb } while (ptr != NULL); 7241224092Sdougb 7242224092Sdougb cleanup: 7243224092Sdougb if (secroots != NULL) 7244224092Sdougb dns_keytable_detach(&secroots); 7245224092Sdougb if (fp != NULL) 7246224092Sdougb (void)isc_stdio_close(fp); 7247224092Sdougb if (result == ISC_R_SUCCESS) 7248224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7249224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7250224092Sdougb "dumpsecroots complete"); 7251224092Sdougb else 7252224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7253224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7254224092Sdougb "dumpsecroots failed: %s", 7255224092Sdougb dns_result_totext(result)); 7256224092Sdougb return (result); 7257224092Sdougb} 7258224092Sdougb 7259224092Sdougbisc_result_t 7260135446Strhodesns_server_dumprecursing(ns_server_t *server) { 7261135446Strhodes FILE *fp = NULL; 7262135446Strhodes isc_result_t result; 7263135446Strhodes 7264135446Strhodes CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 7265135446Strhodes "could not open dump file", server->recfile); 7266135446Strhodes fprintf(fp,";\n; Recursing Queries\n;\n"); 7267135446Strhodes ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 7268135446Strhodes fprintf(fp, "; Dump complete\n"); 7269135446Strhodes 7270135446Strhodes cleanup: 7271135446Strhodes if (fp != NULL) 7272135446Strhodes result = isc_stdio_close(fp); 7273193149Sdougb if (result == ISC_R_SUCCESS) 7274193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7275193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7276193149Sdougb "dumprecursing complete"); 7277193149Sdougb else 7278193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7279193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7280193149Sdougb "dumprecursing failed: %s", 7281193149Sdougb dns_result_totext(result)); 7282135446Strhodes return (result); 7283135446Strhodes} 7284135446Strhodes 7285135446Strhodesisc_result_t 7286135446Strhodesns_server_setdebuglevel(ns_server_t *server, char *args) { 7287135446Strhodes char *ptr; 7288135446Strhodes char *levelstr; 7289135446Strhodes char *endp; 7290135446Strhodes long newlevel; 7291135446Strhodes 7292135446Strhodes UNUSED(server); 7293135446Strhodes 7294135446Strhodes /* Skip the command name. */ 7295135446Strhodes ptr = next_token(&args, " \t"); 7296135446Strhodes if (ptr == NULL) 7297135446Strhodes return (ISC_R_UNEXPECTEDEND); 7298135446Strhodes 7299135446Strhodes /* Look for the new level name. */ 7300135446Strhodes levelstr = next_token(&args, " \t"); 7301135446Strhodes if (levelstr == NULL) { 7302135446Strhodes if (ns_g_debuglevel < 99) 7303135446Strhodes ns_g_debuglevel++; 7304135446Strhodes } else { 7305135446Strhodes newlevel = strtol(levelstr, &endp, 10); 7306135446Strhodes if (*endp != '\0' || newlevel < 0 || newlevel > 99) 7307135446Strhodes return (ISC_R_RANGE); 7308135446Strhodes ns_g_debuglevel = (unsigned int)newlevel; 7309135446Strhodes } 7310135446Strhodes isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 7311193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7312193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7313193149Sdougb "debug level is now %d", ns_g_debuglevel); 7314135446Strhodes return (ISC_R_SUCCESS); 7315135446Strhodes} 7316135446Strhodes 7317135446Strhodesisc_result_t 7318170222Sdougbns_server_validation(ns_server_t *server, char *args) { 7319170222Sdougb char *ptr, *viewname; 7320170222Sdougb dns_view_t *view; 7321170222Sdougb isc_boolean_t changed = ISC_FALSE; 7322170222Sdougb isc_result_t result; 7323170222Sdougb isc_boolean_t enable; 7324170222Sdougb 7325170222Sdougb /* Skip the command name. */ 7326170222Sdougb ptr = next_token(&args, " \t"); 7327170222Sdougb if (ptr == NULL) 7328170222Sdougb return (ISC_R_UNEXPECTEDEND); 7329170222Sdougb 7330170222Sdougb /* Find out what we are to do. */ 7331170222Sdougb ptr = next_token(&args, " \t"); 7332170222Sdougb if (ptr == NULL) 7333170222Sdougb return (ISC_R_UNEXPECTEDEND); 7334170222Sdougb 7335170222Sdougb if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") || 7336170222Sdougb !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) 7337170222Sdougb enable = ISC_TRUE; 7338170222Sdougb else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") || 7339170222Sdougb !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) 7340170222Sdougb enable = ISC_FALSE; 7341170222Sdougb else 7342170222Sdougb return (DNS_R_SYNTAX); 7343170222Sdougb 7344170222Sdougb /* Look for the view name. */ 7345170222Sdougb viewname = next_token(&args, " \t"); 7346170222Sdougb 7347170222Sdougb result = isc_task_beginexclusive(server->task); 7348170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7349170222Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7350170222Sdougb view != NULL; 7351170222Sdougb view = ISC_LIST_NEXT(view, link)) 7352170222Sdougb { 7353170222Sdougb if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 7354170222Sdougb continue; 7355170222Sdougb result = dns_view_flushcache(view); 7356170222Sdougb if (result != ISC_R_SUCCESS) 7357170222Sdougb goto out; 7358170222Sdougb view->enablevalidation = enable; 7359170222Sdougb changed = ISC_TRUE; 7360170222Sdougb } 7361170222Sdougb if (changed) 7362170222Sdougb result = ISC_R_SUCCESS; 7363170222Sdougb else 7364170222Sdougb result = ISC_R_FAILURE; 7365170222Sdougb out: 7366186462Sdougb isc_task_endexclusive(server->task); 7367170222Sdougb return (result); 7368170222Sdougb} 7369170222Sdougb 7370170222Sdougbisc_result_t 7371135446Strhodesns_server_flushcache(ns_server_t *server, char *args) { 7372135446Strhodes char *ptr, *viewname; 7373135446Strhodes dns_view_t *view; 7374174187Sdougb isc_boolean_t flushed; 7375174187Sdougb isc_boolean_t found; 7376135446Strhodes isc_result_t result; 7377224092Sdougb ns_cache_t *nsc; 7378135446Strhodes 7379135446Strhodes /* Skip the command name. */ 7380135446Strhodes ptr = next_token(&args, " \t"); 7381135446Strhodes if (ptr == NULL) 7382135446Strhodes return (ISC_R_UNEXPECTEDEND); 7383135446Strhodes 7384135446Strhodes /* Look for the view name. */ 7385135446Strhodes viewname = next_token(&args, " \t"); 7386135446Strhodes 7387135446Strhodes result = isc_task_beginexclusive(server->task); 7388135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 7389174187Sdougb flushed = ISC_TRUE; 7390174187Sdougb found = ISC_FALSE; 7391224092Sdougb 7392224092Sdougb /* 7393224092Sdougb * Flushing a cache is tricky when caches are shared by multiple views. 7394224092Sdougb * We first identify which caches should be flushed in the local cache 7395224092Sdougb * list, flush these caches, and then update other views that refer to 7396224092Sdougb * the flushed cache DB. 7397224092Sdougb */ 7398224092Sdougb if (viewname != NULL) { 7399224092Sdougb /* 7400224092Sdougb * Mark caches that need to be flushed. This is an O(#view^2) 7401224092Sdougb * operation in the very worst case, but should be normally 7402224092Sdougb * much more lightweight because only a few (most typically just 7403224092Sdougb * one) views will match. 7404224092Sdougb */ 7405224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7406224092Sdougb view != NULL; 7407224092Sdougb view = ISC_LIST_NEXT(view, link)) 7408224092Sdougb { 7409224092Sdougb if (strcasecmp(viewname, view->name) != 0) 7410224092Sdougb continue; 7411224092Sdougb found = ISC_TRUE; 7412224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 7413224092Sdougb nsc != NULL; 7414224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 7415224092Sdougb if (nsc->cache == view->cache) 7416224092Sdougb break; 7417224092Sdougb } 7418224092Sdougb INSIST(nsc != NULL); 7419224092Sdougb nsc->needflush = ISC_TRUE; 7420224092Sdougb } 7421224092Sdougb } else 7422224092Sdougb found = ISC_TRUE; 7423224092Sdougb 7424224092Sdougb /* Perform flush */ 7425224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 7426224092Sdougb nsc != NULL; 7427224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 7428224092Sdougb if (viewname != NULL && !nsc->needflush) 7429135446Strhodes continue; 7430224092Sdougb nsc->needflush = ISC_TRUE; 7431224092Sdougb result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE); 7432193149Sdougb if (result != ISC_R_SUCCESS) { 7433174187Sdougb flushed = ISC_FALSE; 7434193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7435193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7436193149Sdougb "flushing cache in view '%s' failed: %s", 7437224092Sdougb nsc->primaryview->name, 7438224092Sdougb isc_result_totext(result)); 7439193149Sdougb } 7440135446Strhodes } 7441224092Sdougb 7442224092Sdougb /* 7443224092Sdougb * Fix up views that share a flushed cache: let the views update the 7444224092Sdougb * cache DB they're referring to. This could also be an expensive 7445224092Sdougb * operation, but should typically be marginal: the inner loop is only 7446224092Sdougb * necessary for views that share a cache, and if there are many such 7447224092Sdougb * views the number of shared cache should normally be small. 7448224092Sdougb * A worst case is that we have n views and n/2 caches, each shared by 7449224092Sdougb * two views. Then this will be a O(n^2/4) operation. 7450224092Sdougb */ 7451224092Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7452224092Sdougb view != NULL; 7453224092Sdougb view = ISC_LIST_NEXT(view, link)) 7454224092Sdougb { 7455224092Sdougb if (!dns_view_iscacheshared(view)) 7456224092Sdougb continue; 7457224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 7458224092Sdougb nsc != NULL; 7459224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 7460224092Sdougb if (!nsc->needflush || nsc->cache != view->cache) 7461224092Sdougb continue; 7462224092Sdougb result = dns_view_flushcache2(view, ISC_TRUE); 7463224092Sdougb if (result != ISC_R_SUCCESS) { 7464224092Sdougb flushed = ISC_FALSE; 7465224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7466224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7467224092Sdougb "fixing cache in view '%s' " 7468224092Sdougb "failed: %s", view->name, 7469224092Sdougb isc_result_totext(result)); 7470224092Sdougb } 7471224092Sdougb } 7472224092Sdougb } 7473224092Sdougb 7474224092Sdougb /* Cleanup the cache list. */ 7475224092Sdougb for (nsc = ISC_LIST_HEAD(server->cachelist); 7476224092Sdougb nsc != NULL; 7477224092Sdougb nsc = ISC_LIST_NEXT(nsc, link)) { 7478224092Sdougb nsc->needflush = ISC_FALSE; 7479224092Sdougb } 7480224092Sdougb 7481174187Sdougb if (flushed && found) { 7482193149Sdougb if (viewname != NULL) 7483193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7484193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7485193149Sdougb "flushing cache in view '%s' succeeded", 7486193149Sdougb viewname); 7487193149Sdougb else 7488193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7489193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7490193149Sdougb "flushing caches in all views succeeded"); 7491135446Strhodes result = ISC_R_SUCCESS; 7492174187Sdougb } else { 7493193149Sdougb if (!found) { 7494193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7495193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7496193149Sdougb "flushing cache in view '%s' failed: " 7497193149Sdougb "view not found", viewname); 7498174187Sdougb result = ISC_R_NOTFOUND; 7499193149Sdougb } else 7500174187Sdougb result = ISC_R_FAILURE; 7501174187Sdougb } 7502186462Sdougb isc_task_endexclusive(server->task); 7503135446Strhodes return (result); 7504135446Strhodes} 7505135446Strhodes 7506135446Strhodesisc_result_t 7507254897Serwinns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) { 7508135446Strhodes char *ptr, *target, *viewname; 7509135446Strhodes dns_view_t *view; 7510174187Sdougb isc_boolean_t flushed; 7511174187Sdougb isc_boolean_t found; 7512135446Strhodes isc_result_t result; 7513135446Strhodes isc_buffer_t b; 7514135446Strhodes dns_fixedname_t fixed; 7515135446Strhodes dns_name_t *name; 7516135446Strhodes 7517135446Strhodes /* Skip the command name. */ 7518135446Strhodes ptr = next_token(&args, " \t"); 7519135446Strhodes if (ptr == NULL) 7520135446Strhodes return (ISC_R_UNEXPECTEDEND); 7521135446Strhodes 7522135446Strhodes /* Find the domain name to flush. */ 7523135446Strhodes target = next_token(&args, " \t"); 7524135446Strhodes if (target == NULL) 7525135446Strhodes return (ISC_R_UNEXPECTEDEND); 7526135446Strhodes 7527254402Serwin isc_buffer_constinit(&b, target, strlen(target)); 7528135446Strhodes isc_buffer_add(&b, strlen(target)); 7529135446Strhodes dns_fixedname_init(&fixed); 7530135446Strhodes name = dns_fixedname_name(&fixed); 7531224092Sdougb result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 7532135446Strhodes if (result != ISC_R_SUCCESS) 7533135446Strhodes return (result); 7534135446Strhodes 7535135446Strhodes /* Look for the view name. */ 7536135446Strhodes viewname = next_token(&args, " \t"); 7537135446Strhodes 7538135446Strhodes result = isc_task_beginexclusive(server->task); 7539135446Strhodes RUNTIME_CHECK(result == ISC_R_SUCCESS); 7540135446Strhodes flushed = ISC_TRUE; 7541174187Sdougb found = ISC_FALSE; 7542135446Strhodes for (view = ISC_LIST_HEAD(server->viewlist); 7543135446Strhodes view != NULL; 7544135446Strhodes view = ISC_LIST_NEXT(view, link)) 7545135446Strhodes { 7546135446Strhodes if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 7547135446Strhodes continue; 7548174187Sdougb found = ISC_TRUE; 7549224092Sdougb /* 7550224092Sdougb * It's a little inefficient to try flushing name for all views 7551224092Sdougb * if some of the views share a single cache. But since the 7552224092Sdougb * operation is lightweight we prefer simplicity here. 7553224092Sdougb */ 7554254897Serwin result = dns_view_flushnode(view, name, tree); 7555193149Sdougb if (result != ISC_R_SUCCESS) { 7556135446Strhodes flushed = ISC_FALSE; 7557193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7558193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7559254897Serwin "flushing %s '%s' in cache view '%s' " 7560254897Serwin "failed: %s", 7561254897Serwin tree ? "tree" : "name", 7562254897Serwin target, view->name, 7563193149Sdougb isc_result_totext(result)); 7564193149Sdougb } 7565135446Strhodes } 7566193149Sdougb if (flushed && found) { 7567193149Sdougb if (viewname != NULL) 7568193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7569193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7570254897Serwin "flushing %s '%s' in cache view '%s' " 7571254897Serwin "succeeded", 7572254897Serwin tree ? "tree" : "name", 7573254897Serwin target, viewname); 7574193149Sdougb else 7575193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7576193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7577254897Serwin "flushing %s '%s' in all cache views " 7578254897Serwin "succeeded", 7579254897Serwin tree ? "tree" : "name", 7580254897Serwin target); 7581135446Strhodes result = ISC_R_SUCCESS; 7582193149Sdougb } else { 7583193149Sdougb if (!found) 7584193149Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7585193149Sdougb NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 7586254897Serwin "flushing %s '%s' in cache view '%s' " 7587254897Serwin "failed: view not found", 7588254897Serwin tree ? "tree" : "name", 7589254897Serwin target, viewname); 7590135446Strhodes result = ISC_R_FAILURE; 7591193149Sdougb } 7592186462Sdougb isc_task_endexclusive(server->task); 7593135446Strhodes return (result); 7594135446Strhodes} 7595135446Strhodes 7596135446Strhodesisc_result_t 7597135446Strhodesns_server_status(ns_server_t *server, isc_buffer_t *text) { 7598135446Strhodes int zonecount, xferrunning, xferdeferred, soaqueries; 7599135446Strhodes unsigned int n; 7600193149Sdougb const char *ob = "", *cb = "", *alt = ""; 7601135446Strhodes 7602193149Sdougb if (ns_g_server->version_set) { 7603193149Sdougb ob = " ("; 7604193149Sdougb cb = ")"; 7605193149Sdougb if (ns_g_server->version == NULL) 7606193149Sdougb alt = "version.bind/txt/ch disabled"; 7607193149Sdougb else 7608193149Sdougb alt = ns_g_server->version; 7609193149Sdougb } 7610135446Strhodes zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 7611135446Strhodes xferrunning = dns_zonemgr_getcount(server->zonemgr, 7612135446Strhodes DNS_ZONESTATE_XFERRUNNING); 7613135446Strhodes xferdeferred = dns_zonemgr_getcount(server->zonemgr, 7614135446Strhodes DNS_ZONESTATE_XFERDEFERRED); 7615135446Strhodes soaqueries = dns_zonemgr_getcount(server->zonemgr, 7616135446Strhodes DNS_ZONESTATE_SOAQUERY); 7617193149Sdougb 7618135446Strhodes n = snprintf((char *)isc_buffer_used(text), 7619135446Strhodes isc_buffer_availablelength(text), 7620262706Serwin "version: %s%s%s%s <id:%s>\n" 7621193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 7622193149Sdougb "CPUs found: %u\n" 7623193149Sdougb "worker threads: %u\n" 7624254897Serwin "UDP listeners per interface: %u\n" 7625193149Sdougb#endif 7626135446Strhodes "number of zones: %u\n" 7627135446Strhodes "debug level: %d\n" 7628135446Strhodes "xfers running: %u\n" 7629135446Strhodes "xfers deferred: %u\n" 7630135446Strhodes "soa queries in progress: %u\n" 7631135446Strhodes "query logging is %s\n" 7632170222Sdougb "recursive clients: %d/%d/%d\n" 7633135446Strhodes "tcp clients: %d/%d\n" 7634135446Strhodes "server is up and running", 7635262706Serwin ns_g_version, ob, alt, cb, ns_g_srcid, 7636193149Sdougb#ifdef ISC_PLATFORM_USETHREADS 7637254897Serwin ns_g_cpus_detected, ns_g_cpus, ns_g_udpdisp, 7638193149Sdougb#endif 7639135446Strhodes zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 7640135446Strhodes soaqueries, server->log_queries ? "ON" : "OFF", 7641170222Sdougb server->recursionquota.used, server->recursionquota.soft, 7642170222Sdougb server->recursionquota.max, 7643135446Strhodes server->tcpquota.used, server->tcpquota.max); 7644135446Strhodes if (n >= isc_buffer_availablelength(text)) 7645135446Strhodes return (ISC_R_NOSPACE); 7646135446Strhodes isc_buffer_add(text, n); 7647135446Strhodes return (ISC_R_SUCCESS); 7648135446Strhodes} 7649135446Strhodes 7650193149Sdougbstatic isc_result_t 7651193149Sdougbdelete_keynames(dns_tsig_keyring_t *ring, char *target, 7652193149Sdougb unsigned int *foundkeys) 7653193149Sdougb{ 7654193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 7655193149Sdougb isc_result_t result; 7656193149Sdougb dns_rbtnodechain_t chain; 7657193149Sdougb dns_name_t foundname; 7658193149Sdougb dns_fixedname_t fixedorigin; 7659193149Sdougb dns_name_t *origin; 7660193149Sdougb dns_rbtnode_t *node; 7661193149Sdougb dns_tsigkey_t *tkey; 7662193149Sdougb 7663193149Sdougb dns_name_init(&foundname, NULL); 7664193149Sdougb dns_fixedname_init(&fixedorigin); 7665193149Sdougb origin = dns_fixedname_name(&fixedorigin); 7666193149Sdougb 7667193149Sdougb again: 7668193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 7669193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 7670193149Sdougb origin); 7671193149Sdougb if (result == ISC_R_NOTFOUND) { 7672193149Sdougb dns_rbtnodechain_invalidate(&chain); 7673193149Sdougb return (ISC_R_SUCCESS); 7674193149Sdougb } 7675193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7676193149Sdougb dns_rbtnodechain_invalidate(&chain); 7677193149Sdougb return (result); 7678193149Sdougb } 7679193149Sdougb 7680193149Sdougb for (;;) { 7681193149Sdougb node = NULL; 7682193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 7683193149Sdougb tkey = node->data; 7684193149Sdougb 7685193149Sdougb if (tkey != NULL) { 7686193149Sdougb if (!tkey->generated) 7687193149Sdougb goto nextkey; 7688193149Sdougb 7689193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 7690193149Sdougb if (strcmp(namestr, target) == 0) { 7691193149Sdougb (*foundkeys)++; 7692193149Sdougb dns_rbtnodechain_invalidate(&chain); 7693193149Sdougb (void)dns_rbt_deletename(ring->keys, 7694193149Sdougb &tkey->name, 7695193149Sdougb ISC_FALSE); 7696193149Sdougb goto again; 7697193149Sdougb } 7698193149Sdougb } 7699193149Sdougb 7700193149Sdougb nextkey: 7701193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 7702193149Sdougb if (result == ISC_R_NOMORE) 7703193149Sdougb break; 7704193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7705193149Sdougb dns_rbtnodechain_invalidate(&chain); 7706193149Sdougb return (result); 7707193149Sdougb } 7708193149Sdougb } 7709193149Sdougb 7710193149Sdougb return (ISC_R_SUCCESS); 7711193149Sdougb} 7712193149Sdougb 7713193149Sdougbisc_result_t 7714193149Sdougbns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) { 7715193149Sdougb isc_result_t result; 7716193149Sdougb unsigned int n; 7717193149Sdougb dns_view_t *view; 7718193149Sdougb unsigned int foundkeys = 0; 7719193149Sdougb char *target; 7720193149Sdougb char *viewname; 7721193149Sdougb 7722193149Sdougb (void)next_token(&command, " \t"); /* skip command name */ 7723193149Sdougb target = next_token(&command, " \t"); 7724193149Sdougb if (target == NULL) 7725193149Sdougb return (ISC_R_UNEXPECTEDEND); 7726193149Sdougb viewname = next_token(&command, " \t"); 7727193149Sdougb 7728193149Sdougb result = isc_task_beginexclusive(server->task); 7729193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7730193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7731193149Sdougb view != NULL; 7732193149Sdougb view = ISC_LIST_NEXT(view, link)) { 7733193149Sdougb if (viewname == NULL || strcmp(view->name, viewname) == 0) { 7734193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write); 7735193149Sdougb result = delete_keynames(view->dynamickeys, target, 7736193149Sdougb &foundkeys); 7737193149Sdougb RWUNLOCK(&view->dynamickeys->lock, 7738193149Sdougb isc_rwlocktype_write); 7739193149Sdougb if (result != ISC_R_SUCCESS) { 7740193149Sdougb isc_task_endexclusive(server->task); 7741193149Sdougb return (result); 7742193149Sdougb } 7743193149Sdougb } 7744193149Sdougb } 7745193149Sdougb isc_task_endexclusive(server->task); 7746193149Sdougb 7747193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7748193149Sdougb isc_buffer_availablelength(text), 7749193149Sdougb "%d tsig keys deleted.\n", foundkeys); 7750218384Sdougb if (n >= isc_buffer_availablelength(text)) 7751193149Sdougb return (ISC_R_NOSPACE); 7752193149Sdougb isc_buffer_add(text, n); 7753193149Sdougb 7754193149Sdougb return (ISC_R_SUCCESS); 7755193149Sdougb} 7756193149Sdougb 7757193149Sdougbstatic isc_result_t 7758193149Sdougblist_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text, 7759193149Sdougb unsigned int *foundkeys) 7760193149Sdougb{ 7761193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 7762193149Sdougb char creatorstr[DNS_NAME_FORMATSIZE]; 7763193149Sdougb isc_result_t result; 7764193149Sdougb dns_rbtnodechain_t chain; 7765193149Sdougb dns_name_t foundname; 7766193149Sdougb dns_fixedname_t fixedorigin; 7767193149Sdougb dns_name_t *origin; 7768193149Sdougb dns_rbtnode_t *node; 7769193149Sdougb dns_tsigkey_t *tkey; 7770193149Sdougb unsigned int n; 7771193149Sdougb const char *viewname; 7772193149Sdougb 7773193149Sdougb if (view != NULL) 7774193149Sdougb viewname = view->name; 7775193149Sdougb else 7776193149Sdougb viewname = "(global)"; 7777193149Sdougb 7778193149Sdougb dns_name_init(&foundname, NULL); 7779193149Sdougb dns_fixedname_init(&fixedorigin); 7780193149Sdougb origin = dns_fixedname_name(&fixedorigin); 7781193149Sdougb dns_rbtnodechain_init(&chain, ring->mctx); 7782193149Sdougb result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, 7783193149Sdougb origin); 7784193149Sdougb if (result == ISC_R_NOTFOUND) { 7785193149Sdougb dns_rbtnodechain_invalidate(&chain); 7786193149Sdougb return (ISC_R_SUCCESS); 7787193149Sdougb } 7788193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7789193149Sdougb dns_rbtnodechain_invalidate(&chain); 7790193149Sdougb return (result); 7791193149Sdougb } 7792193149Sdougb 7793193149Sdougb for (;;) { 7794193149Sdougb node = NULL; 7795193149Sdougb dns_rbtnodechain_current(&chain, &foundname, origin, &node); 7796193149Sdougb tkey = node->data; 7797193149Sdougb 7798193149Sdougb if (tkey != NULL) { 7799193149Sdougb (*foundkeys)++; 7800193149Sdougb dns_name_format(&tkey->name, namestr, sizeof(namestr)); 7801193149Sdougb if (tkey->generated) { 7802193149Sdougb dns_name_format(tkey->creator, creatorstr, 7803193149Sdougb sizeof(creatorstr)); 7804193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7805193149Sdougb isc_buffer_availablelength(text), 7806193149Sdougb "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n", 7807193149Sdougb viewname, namestr, creatorstr); 7808193149Sdougb } else { 7809193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7810193149Sdougb isc_buffer_availablelength(text), 7811193149Sdougb "view \"%s\"; type \"static\"; key \"%s\";\n", 7812193149Sdougb viewname, namestr); 7813193149Sdougb } 7814193149Sdougb if (n >= isc_buffer_availablelength(text)) { 7815193149Sdougb dns_rbtnodechain_invalidate(&chain); 7816193149Sdougb return (ISC_R_NOSPACE); 7817193149Sdougb } 7818193149Sdougb isc_buffer_add(text, n); 7819193149Sdougb } 7820193149Sdougb result = dns_rbtnodechain_next(&chain, &foundname, origin); 7821193149Sdougb if (result == ISC_R_NOMORE) 7822193149Sdougb break; 7823193149Sdougb if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { 7824193149Sdougb dns_rbtnodechain_invalidate(&chain); 7825193149Sdougb return (result); 7826193149Sdougb } 7827193149Sdougb } 7828193149Sdougb 7829193149Sdougb return (ISC_R_SUCCESS); 7830193149Sdougb} 7831193149Sdougb 7832193149Sdougbisc_result_t 7833193149Sdougbns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) { 7834193149Sdougb isc_result_t result; 7835193149Sdougb unsigned int n; 7836193149Sdougb dns_view_t *view; 7837193149Sdougb unsigned int foundkeys = 0; 7838193149Sdougb 7839193149Sdougb result = isc_task_beginexclusive(server->task); 7840193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 7841193149Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 7842193149Sdougb view != NULL; 7843193149Sdougb view = ISC_LIST_NEXT(view, link)) { 7844193149Sdougb RWLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7845193149Sdougb result = list_keynames(view, view->statickeys, text, 7846193149Sdougb &foundkeys); 7847193149Sdougb RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read); 7848193149Sdougb if (result != ISC_R_SUCCESS) { 7849193149Sdougb isc_task_endexclusive(server->task); 7850193149Sdougb return (result); 7851193149Sdougb } 7852193149Sdougb RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7853193149Sdougb result = list_keynames(view, view->dynamickeys, text, 7854193149Sdougb &foundkeys); 7855193149Sdougb RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read); 7856193149Sdougb if (result != ISC_R_SUCCESS) { 7857193149Sdougb isc_task_endexclusive(server->task); 7858193149Sdougb return (result); 7859193149Sdougb } 7860193149Sdougb } 7861193149Sdougb isc_task_endexclusive(server->task); 7862193149Sdougb 7863193149Sdougb if (foundkeys == 0) { 7864193149Sdougb n = snprintf((char *)isc_buffer_used(text), 7865193149Sdougb isc_buffer_availablelength(text), 7866193149Sdougb "no tsig keys found.\n"); 7867218384Sdougb if (n >= isc_buffer_availablelength(text)) 7868193149Sdougb return (ISC_R_NOSPACE); 7869193149Sdougb isc_buffer_add(text, n); 7870193149Sdougb } 7871193149Sdougb 7872193149Sdougb return (ISC_R_SUCCESS); 7873193149Sdougb} 7874193149Sdougb 7875135446Strhodes/* 7876224092Sdougb * Act on a "sign" or "loadkeys" command from the command channel. 7877224092Sdougb */ 7878224092Sdougbisc_result_t 7879262706Serwinns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text) { 7880224092Sdougb isc_result_t result; 7881224092Sdougb dns_zone_t *zone = NULL; 7882224092Sdougb dns_zonetype_t type; 7883224092Sdougb isc_uint16_t keyopts; 7884224092Sdougb isc_boolean_t fullsign = ISC_FALSE; 7885224092Sdougb 7886224092Sdougb if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0) 7887224092Sdougb fullsign = ISC_TRUE; 7888224092Sdougb 7889262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 7890262706Serwin text, ISC_TRUE); 7891224092Sdougb if (result != ISC_R_SUCCESS) 7892224092Sdougb return (result); 7893224092Sdougb if (zone == NULL) 7894224092Sdougb return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */ 7895224092Sdougb 7896224092Sdougb type = dns_zone_gettype(zone); 7897224092Sdougb if (type != dns_zone_master) { 7898224092Sdougb dns_zone_detach(&zone); 7899224092Sdougb return (DNS_R_NOTMASTER); 7900224092Sdougb } 7901224092Sdougb 7902224092Sdougb keyopts = dns_zone_getkeyopts(zone); 7903224092Sdougb 7904224092Sdougb /* "rndc loadkeys" requires "auto-dnssec maintain". */ 7905224092Sdougb if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) 7906224092Sdougb result = ISC_R_NOPERM; 7907224092Sdougb else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) 7908224092Sdougb result = ISC_R_NOPERM; 7909224092Sdougb else 7910224092Sdougb dns_zone_rekey(zone, fullsign); 7911224092Sdougb 7912224092Sdougb dns_zone_detach(&zone); 7913224092Sdougb return (result); 7914224092Sdougb} 7915224092Sdougb 7916224092Sdougb/* 7917254897Serwin * Act on a "sync" command from the command channel. 7918254897Serwin*/ 7919254897Serwinstatic isc_result_t 7920254897Serwinsynczone(dns_zone_t *zone, void *uap) { 7921254897Serwin isc_boolean_t cleanup = *(isc_boolean_t *)uap; 7922254897Serwin isc_result_t result; 7923254897Serwin dns_zone_t *raw = NULL; 7924254897Serwin char *journal; 7925254897Serwin 7926254897Serwin dns_zone_getraw(zone, &raw); 7927254897Serwin if (raw != NULL) { 7928254897Serwin synczone(raw, uap); 7929254897Serwin dns_zone_detach(&raw); 7930254897Serwin } 7931254897Serwin 7932254897Serwin result = dns_zone_flush(zone); 7933254897Serwin if (result != ISC_R_SUCCESS) 7934254897Serwin cleanup = ISC_FALSE; 7935254897Serwin if (cleanup) { 7936254897Serwin journal = dns_zone_getjournal(zone); 7937254897Serwin if (journal != NULL) 7938254897Serwin (void)isc_file_remove(journal); 7939254897Serwin } 7940254897Serwin 7941254897Serwin return (result); 7942254897Serwin} 7943254897Serwin 7944254897Serwinisc_result_t 7945254897Serwinns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) { 7946254897Serwin isc_result_t result, tresult; 7947254897Serwin dns_view_t *view; 7948254897Serwin dns_zone_t *zone = NULL; 7949254897Serwin char classstr[DNS_RDATACLASS_FORMATSIZE]; 7950254897Serwin char zonename[DNS_NAME_FORMATSIZE]; 7951254897Serwin const char *vname, *sep, *msg = NULL, *arg; 7952254897Serwin isc_boolean_t cleanup = ISC_FALSE; 7953254897Serwin 7954254897Serwin (void) next_token(&args, " \t"); 7955254897Serwin 7956254897Serwin arg = next_token(&args, " \t"); 7957254897Serwin if (arg != NULL && 7958254897Serwin (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) { 7959254897Serwin cleanup = ISC_TRUE; 7960254897Serwin arg = next_token(&args, " \t"); 7961254897Serwin } 7962254897Serwin 7963262706Serwin result = zone_from_args(server, args, arg, &zone, NULL, 7964262706Serwin text, ISC_FALSE); 7965254897Serwin if (result != ISC_R_SUCCESS) 7966254897Serwin return (result); 7967254897Serwin 7968254897Serwin if (zone == NULL) { 7969254897Serwin result = isc_task_beginexclusive(server->task); 7970254897Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 7971254897Serwin tresult = ISC_R_SUCCESS; 7972254897Serwin for (view = ISC_LIST_HEAD(server->viewlist); 7973254897Serwin view != NULL; 7974254897Serwin view = ISC_LIST_NEXT(view, link)) { 7975254897Serwin result = dns_zt_apply(view->zonetable, ISC_FALSE, 7976254897Serwin synczone, &cleanup); 7977254897Serwin if (result != ISC_R_SUCCESS && 7978254897Serwin tresult == ISC_R_SUCCESS) 7979254897Serwin tresult = result; 7980254897Serwin } 7981254897Serwin isc_task_endexclusive(server->task); 7982254897Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 7983254897Serwin NS_LOGMODULE_SERVER, ISC_LOG_INFO, 7984254897Serwin "dumping all zones%s: %s", 7985254897Serwin cleanup ? ", removing journal files" : "", 7986254897Serwin isc_result_totext(result)); 7987254897Serwin return (tresult); 7988254897Serwin } 7989254897Serwin 7990254897Serwin result = isc_task_beginexclusive(server->task); 7991254897Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 7992254897Serwin result = synczone(zone, &cleanup); 7993254897Serwin isc_task_endexclusive(server->task); 7994254897Serwin 7995254897Serwin if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 7996254897Serwin isc_buffer_putmem(text, (const unsigned char *)msg, 7997254897Serwin strlen(msg) + 1); 7998254897Serwin 7999254897Serwin view = dns_zone_getview(zone); 8000254897Serwin if (strcmp(view->name, "_default") == 0 || 8001254897Serwin strcmp(view->name, "_bind") == 0) 8002254897Serwin { 8003254897Serwin vname = ""; 8004254897Serwin sep = ""; 8005254897Serwin } else { 8006254897Serwin vname = view->name; 8007254897Serwin sep = " "; 8008254897Serwin } 8009254897Serwin dns_rdataclass_format(dns_zone_getclass(zone), classstr, 8010254897Serwin sizeof(classstr)); 8011254897Serwin dns_name_format(dns_zone_getorigin(zone), 8012254897Serwin zonename, sizeof(zonename)); 8013254897Serwin isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8014254897Serwin NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8015254897Serwin "sync: dumping zone '%s/%s'%s%s%s: %s", 8016254897Serwin zonename, classstr, sep, vname, 8017254897Serwin cleanup ? ", removing journal file" : "", 8018254897Serwin isc_result_totext(result)); 8019254897Serwin dns_zone_detach(&zone); 8020254897Serwin return (result); 8021254897Serwin} 8022254897Serwin 8023254897Serwin/* 8024170222Sdougb * Act on a "freeze" or "thaw" command from the command channel. 8025135446Strhodes */ 8026135446Strhodesisc_result_t 8027204619Sdougbns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, 8028204619Sdougb isc_buffer_t *text) 8029204619Sdougb{ 8030170222Sdougb isc_result_t result, tresult; 8031254897Serwin dns_zone_t *zone = NULL, *raw = NULL; 8032135446Strhodes dns_zonetype_t type; 8033135446Strhodes char classstr[DNS_RDATACLASS_FORMATSIZE]; 8034135446Strhodes char zonename[DNS_NAME_FORMATSIZE]; 8035135446Strhodes dns_view_t *view; 8036135446Strhodes const char *vname, *sep; 8037135446Strhodes isc_boolean_t frozen; 8038204619Sdougb const char *msg = NULL; 8039186462Sdougb 8040262706Serwin result = zone_from_args(server, args, NULL, &zone, NULL, 8041262706Serwin text, ISC_TRUE); 8042135446Strhodes if (result != ISC_R_SUCCESS) 8043135446Strhodes return (result); 8044170222Sdougb if (zone == NULL) { 8045170222Sdougb result = isc_task_beginexclusive(server->task); 8046170222Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 8047170222Sdougb tresult = ISC_R_SUCCESS; 8048186462Sdougb for (view = ISC_LIST_HEAD(server->viewlist); 8049170222Sdougb view != NULL; 8050170222Sdougb view = ISC_LIST_NEXT(view, link)) { 8051170222Sdougb result = dns_view_freezezones(view, freeze); 8052170222Sdougb if (result != ISC_R_SUCCESS && 8053170222Sdougb tresult == ISC_R_SUCCESS) 8054170222Sdougb tresult = result; 8055170222Sdougb } 8056170222Sdougb isc_task_endexclusive(server->task); 8057170222Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8058170222Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8059170222Sdougb "%s all zones: %s", 8060170222Sdougb freeze ? "freezing" : "thawing", 8061170222Sdougb isc_result_totext(tresult)); 8062170222Sdougb return (tresult); 8063170222Sdougb } 8064254897Serwin dns_zone_getraw(zone, &raw); 8065254897Serwin if (raw != NULL) { 8066254897Serwin dns_zone_detach(&zone); 8067254897Serwin dns_zone_attach(raw, &zone); 8068254897Serwin dns_zone_detach(&raw); 8069254897Serwin } 8070135446Strhodes type = dns_zone_gettype(zone); 8071135446Strhodes if (type != dns_zone_master) { 8072135446Strhodes dns_zone_detach(&zone); 8073224092Sdougb return (DNS_R_NOTMASTER); 8074135446Strhodes } 8075135446Strhodes 8076254897Serwin if (freeze && !dns_zone_isdynamic(zone, ISC_TRUE)) { 8077254897Serwin dns_zone_detach(&zone); 8078254897Serwin return (DNS_R_NOTDYNAMIC); 8079254897Serwin } 8080254897Serwin 8081204619Sdougb result = isc_task_beginexclusive(server->task); 8082204619Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 8083135446Strhodes frozen = dns_zone_getupdatedisabled(zone); 8084135446Strhodes if (freeze) { 8085204619Sdougb if (frozen) { 8086204619Sdougb msg = "WARNING: The zone was already frozen.\n" 8087204619Sdougb "Someone else may be editing it or " 8088204619Sdougb "it may still be re-loading."; 8089135446Strhodes result = DNS_R_FROZEN; 8090204619Sdougb } 8091204619Sdougb if (result == ISC_R_SUCCESS) { 8092135446Strhodes result = dns_zone_flush(zone); 8093204619Sdougb if (result != ISC_R_SUCCESS) 8094204619Sdougb msg = "Flushing the zone updates to " 8095204619Sdougb "disk failed."; 8096204619Sdougb } 8097204619Sdougb if (result == ISC_R_SUCCESS) 8098204619Sdougb dns_zone_setupdatedisabled(zone, freeze); 8099135446Strhodes } else { 8100135446Strhodes if (frozen) { 8101204619Sdougb result = dns_zone_loadandthaw(zone); 8102204619Sdougb switch (result) { 8103204619Sdougb case ISC_R_SUCCESS: 8104204619Sdougb case DNS_R_UPTODATE: 8105204619Sdougb msg = "The zone reload and thaw was " 8106204619Sdougb "successful."; 8107135446Strhodes result = ISC_R_SUCCESS; 8108204619Sdougb break; 8109204619Sdougb case DNS_R_CONTINUE: 8110204619Sdougb msg = "A zone reload and thaw was started.\n" 8111204619Sdougb "Check the logs to see the result."; 8112204619Sdougb result = ISC_R_SUCCESS; 8113204619Sdougb break; 8114204619Sdougb } 8115135446Strhodes } 8116135446Strhodes } 8117204619Sdougb isc_task_endexclusive(server->task); 8118135446Strhodes 8119204619Sdougb if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 8120204619Sdougb isc_buffer_putmem(text, (const unsigned char *)msg, 8121204619Sdougb strlen(msg) + 1); 8122204619Sdougb 8123135446Strhodes view = dns_zone_getview(zone); 8124224092Sdougb if (strcmp(view->name, "_default") == 0 || 8125224092Sdougb strcmp(view->name, "_bind") == 0) 8126135446Strhodes { 8127135446Strhodes vname = ""; 8128135446Strhodes sep = ""; 8129135446Strhodes } else { 8130135446Strhodes vname = view->name; 8131135446Strhodes sep = " "; 8132135446Strhodes } 8133135446Strhodes dns_rdataclass_format(dns_zone_getclass(zone), classstr, 8134135446Strhodes sizeof(classstr)); 8135135446Strhodes dns_name_format(dns_zone_getorigin(zone), 8136135446Strhodes zonename, sizeof(zonename)); 8137135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8138135446Strhodes NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8139135446Strhodes "%s zone '%s/%s'%s%s: %s", 8140170222Sdougb freeze ? "freezing" : "thawing", 8141135446Strhodes zonename, classstr, sep, vname, 8142135446Strhodes isc_result_totext(result)); 8143135446Strhodes dns_zone_detach(&zone); 8144135446Strhodes return (result); 8145135446Strhodes} 8146153816Sdougb 8147153816Sdougb#ifdef HAVE_LIBSCF 8148153816Sdougb/* 8149153816Sdougb * This function adds a message for rndc to echo if named 8150153816Sdougb * is managed by smf and is also running chroot. 8151153816Sdougb */ 8152153816Sdougbisc_result_t 8153153816Sdougbns_smf_add_message(isc_buffer_t *text) { 8154153816Sdougb unsigned int n; 8155153816Sdougb 8156153816Sdougb n = snprintf((char *)isc_buffer_used(text), 8157153816Sdougb isc_buffer_availablelength(text), 8158153816Sdougb "use svcadm(1M) to manage named"); 8159153816Sdougb if (n >= isc_buffer_availablelength(text)) 8160153816Sdougb return (ISC_R_NOSPACE); 8161153816Sdougb isc_buffer_add(text, n); 8162153816Sdougb return (ISC_R_SUCCESS); 8163153816Sdougb} 8164153816Sdougb#endif /* HAVE_LIBSCF */ 8165224092Sdougb 8166224092Sdougb/* 8167262706Serwin * Emit a comment at the top of the nzf file containing the viewname 8168262706Serwin * Expects the fp to already be open for writing 8169262706Serwin */ 8170262706Serwin#define HEADER1 "# New zone file for view: " 8171262706Serwin#define HEADER2 "\n# This file contains configuration for zones added by\n" \ 8172262706Serwin "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n" 8173262706Serwinisc_result_t 8174262706Serwinadd_comment(FILE *fp, const char *viewname) { 8175262706Serwin isc_result_t result; 8176262706Serwin CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL)); 8177262706Serwin CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL)); 8178262706Serwin CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL)); 8179262706Serwin cleanup: 8180262706Serwin return (result); 8181262706Serwin} 8182262706Serwin 8183262706Serwin/* 8184224092Sdougb * Act on an "addzone" command from the command channel. 8185224092Sdougb */ 8186224092Sdougbisc_result_t 8187224092Sdougbns_server_add_zone(ns_server_t *server, char *args) { 8188224092Sdougb isc_result_t result; 8189224092Sdougb isc_buffer_t argbuf; 8190224092Sdougb size_t arglen; 8191224092Sdougb cfg_parser_t *parser = NULL; 8192224092Sdougb cfg_obj_t *config = NULL; 8193224092Sdougb const cfg_obj_t *vconfig = NULL; 8194224092Sdougb const cfg_obj_t *views = NULL; 8195224092Sdougb const cfg_obj_t *parms = NULL; 8196224092Sdougb const cfg_obj_t *obj = NULL; 8197224092Sdougb const cfg_listelt_t *element; 8198224092Sdougb const char *zonename; 8199224092Sdougb const char *classname = NULL; 8200224092Sdougb const char *argp; 8201224092Sdougb const char *viewname = NULL; 8202224092Sdougb dns_rdataclass_t rdclass; 8203224092Sdougb dns_view_t *view = 0; 8204262706Serwin isc_buffer_t buf; 8205262706Serwin dns_fixedname_t fname; 8206262706Serwin dns_name_t *dnsname; 8207224092Sdougb dns_zone_t *zone = NULL; 8208224092Sdougb FILE *fp = NULL; 8209224092Sdougb struct cfg_context *cfg = NULL; 8210262706Serwin char namebuf[DNS_NAME_FORMATSIZE]; 8211262706Serwin off_t offset; 8212224092Sdougb 8213224092Sdougb /* Try to parse the argument string */ 8214224092Sdougb arglen = strlen(args); 8215262706Serwin isc_buffer_init(&argbuf, args, (unsigned int)arglen); 8216224092Sdougb isc_buffer_add(&argbuf, strlen(args)); 8217224092Sdougb CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser)); 8218224092Sdougb CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf, 8219224092Sdougb &config)); 8220224092Sdougb CHECK(cfg_map_get(config, "addzone", &parms)); 8221224092Sdougb 8222224092Sdougb zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name")); 8223254402Serwin isc_buffer_constinit(&buf, zonename, strlen(zonename)); 8224224092Sdougb isc_buffer_add(&buf, strlen(zonename)); 8225224092Sdougb 8226262706Serwin dns_fixedname_init(&fname); 8227262706Serwin dnsname = dns_fixedname_name(&fname); 8228262706Serwin CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, ISC_FALSE, NULL)); 8229262706Serwin 8230224092Sdougb /* Make sense of optional class argument */ 8231224092Sdougb obj = cfg_tuple_get(parms, "class"); 8232224092Sdougb CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass)); 8233224092Sdougb if (rdclass != dns_rdataclass_in && obj) 8234224092Sdougb classname = cfg_obj_asstring(obj); 8235224092Sdougb 8236224092Sdougb /* Make sense of optional view argument */ 8237224092Sdougb obj = cfg_tuple_get(parms, "view"); 8238224092Sdougb if (obj && cfg_obj_isstring(obj)) 8239224092Sdougb viewname = cfg_obj_asstring(obj); 8240224092Sdougb if (viewname == NULL || *viewname == '\0') 8241224092Sdougb viewname = "_default"; 8242224092Sdougb CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view)); 8243224092Sdougb 8244224092Sdougb /* Are we accepting new zones? */ 8245224092Sdougb if (view->new_zone_file == NULL) { 8246224092Sdougb result = ISC_R_NOPERM; 8247224092Sdougb goto cleanup; 8248224092Sdougb } 8249224092Sdougb 8250224092Sdougb cfg = (struct cfg_context *) view->new_zone_config; 8251224092Sdougb if (cfg == NULL) { 8252224092Sdougb result = ISC_R_FAILURE; 8253224092Sdougb goto cleanup; 8254224092Sdougb } 8255224092Sdougb 8256224092Sdougb /* Zone shouldn't already exist */ 8257262706Serwin result = dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone); 8258224092Sdougb if (result == ISC_R_SUCCESS) { 8259224092Sdougb result = ISC_R_EXISTS; 8260224092Sdougb goto cleanup; 8261224092Sdougb } else if (result == DNS_R_PARTIALMATCH) { 8262224092Sdougb /* Create our sub-zone anyway */ 8263224092Sdougb dns_zone_detach(&zone); 8264224092Sdougb zone = NULL; 8265224092Sdougb } 8266224092Sdougb else if (result != ISC_R_NOTFOUND) 8267224092Sdougb goto cleanup; 8268224092Sdougb 8269224092Sdougb /* Find the view statement */ 8270224092Sdougb cfg_map_get(cfg->config, "view", &views); 8271224092Sdougb for (element = cfg_list_first(views); 8272224092Sdougb element != NULL; 8273224092Sdougb element = cfg_list_next(element)) 8274224092Sdougb { 8275224092Sdougb const char *vname; 8276224092Sdougb vconfig = cfg_listelt_value(element); 8277224092Sdougb vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 8278224092Sdougb if (vname && !strcasecmp(vname, viewname)) 8279224092Sdougb break; 8280224092Sdougb vconfig = NULL; 8281224092Sdougb } 8282224092Sdougb 8283224092Sdougb /* Open save file for write configuration */ 8284224092Sdougb CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); 8285262706Serwin CHECK(isc_stdio_tell(fp, &offset)); 8286262706Serwin if (offset == 0) 8287262706Serwin CHECK(add_comment(fp, view->name)); 8288224092Sdougb 8289224092Sdougb /* Mark view unfrozen so that zone can be added */ 8290254402Serwin result = isc_task_beginexclusive(server->task); 8291254402Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 8292224092Sdougb dns_view_thaw(view); 8293224092Sdougb result = configure_zone(cfg->config, parms, vconfig, 8294225361Sdougb server->mctx, view, cfg->actx, ISC_FALSE); 8295224092Sdougb dns_view_freeze(view); 8296234010Sdougb isc_task_endexclusive(server->task); 8297234010Sdougb if (result != ISC_R_SUCCESS) 8298224092Sdougb goto cleanup; 8299224092Sdougb 8300224092Sdougb /* Is it there yet? */ 8301262706Serwin CHECK(dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone)); 8302224092Sdougb 8303224092Sdougb /* 8304224092Sdougb * Load the zone from the master file. If this fails, we'll 8305224092Sdougb * need to undo the configuration we've done already. 8306224092Sdougb */ 8307224092Sdougb result = dns_zone_loadnew(zone); 8308224092Sdougb if (result != ISC_R_SUCCESS) { 8309224092Sdougb dns_db_t *dbp = NULL; 8310224092Sdougb 8311224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8312224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8313224092Sdougb "addzone failed; reverting."); 8314224092Sdougb 8315224092Sdougb /* If the zone loaded partially, unload it */ 8316224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 8317224092Sdougb dns_db_detach(&dbp); 8318224092Sdougb dns_zone_unload(zone); 8319224092Sdougb } 8320224092Sdougb 8321224092Sdougb /* Remove the zone from the zone table */ 8322224092Sdougb dns_zt_unmount(view->zonetable, zone); 8323224092Sdougb goto cleanup; 8324224092Sdougb } 8325224092Sdougb 8326224092Sdougb /* Flag the zone as having been added at runtime */ 8327224092Sdougb dns_zone_setadded(zone, ISC_TRUE); 8328224092Sdougb 8329262706Serwin /* Emit the zone name, quoted and escaped */ 8330262706Serwin isc_buffer_init(&buf, namebuf, sizeof(namebuf)); 8331262706Serwin CHECK(dns_name_totext(dnsname, ISC_TRUE, &buf)); 8332262706Serwin isc_buffer_putuint8(&buf, 0); 8333262706Serwin CHECK(isc_stdio_write("zone \"", 6, 1, fp, NULL)); 8334262706Serwin CHECK(isc_stdio_write(namebuf, strlen(namebuf), 1, fp, NULL)); 8335262706Serwin CHECK(isc_stdio_write("\" ", 2, 1, fp, NULL)); 8336224092Sdougb 8337224092Sdougb /* Classname, if not default */ 8338224092Sdougb if (classname != NULL && *classname != '\0') { 8339224092Sdougb CHECK(isc_stdio_write(classname, strlen(classname), 1, fp, 8340224092Sdougb NULL)); 8341224092Sdougb CHECK(isc_stdio_write(" ", 1, 1, fp, NULL)); 8342224092Sdougb } 8343224092Sdougb 8344224092Sdougb /* Find beginning of option block from args */ 8345224092Sdougb for (argp = args; *argp; argp++, arglen--) { 8346224092Sdougb if (*argp == '{') { /* Assume matching '}' */ 8347224092Sdougb /* Add that to our file */ 8348224092Sdougb CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL)); 8349224092Sdougb 8350224092Sdougb /* Make sure we end with a LF */ 8351224092Sdougb if (argp[arglen-1] != '\n') { 8352224092Sdougb CHECK(isc_stdio_write("\n", 1, 1, fp, NULL)); 8353224092Sdougb } 8354224092Sdougb break; 8355224092Sdougb } 8356224092Sdougb } 8357224092Sdougb 8358224092Sdougb CHECK(isc_stdio_close(fp)); 8359224092Sdougb fp = NULL; 8360224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8361224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8362224092Sdougb "zone %s added to view %s via addzone", 8363224092Sdougb zonename, viewname); 8364224092Sdougb 8365224092Sdougb result = ISC_R_SUCCESS; 8366224092Sdougb 8367224092Sdougb cleanup: 8368224092Sdougb if (fp != NULL) 8369224092Sdougb isc_stdio_close(fp); 8370224092Sdougb if (parser != NULL) { 8371224092Sdougb if (config != NULL) 8372224092Sdougb cfg_obj_destroy(parser, &config); 8373224092Sdougb cfg_parser_destroy(&parser); 8374224092Sdougb } 8375224092Sdougb if (zone != NULL) 8376224092Sdougb dns_zone_detach(&zone); 8377224092Sdougb if (view != NULL) 8378224092Sdougb dns_view_detach(&view); 8379224092Sdougb 8380224092Sdougb return (result); 8381224092Sdougb} 8382224092Sdougb 8383224092Sdougb/* 8384224092Sdougb * Act on a "delzone" command from the command channel. 8385224092Sdougb */ 8386224092Sdougbisc_result_t 8387262706Serwinns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) { 8388262706Serwin isc_result_t result; 8389262706Serwin dns_zone_t *zone = NULL; 8390262706Serwin dns_view_t *view = NULL; 8391262706Serwin dns_db_t *dbp = NULL; 8392262706Serwin const char *filename = NULL; 8393262706Serwin char *tmpname = NULL; 8394262706Serwin char buf[1024]; 8395262706Serwin const char *zonename = NULL; 8396262706Serwin size_t znamelen = 0; 8397262706Serwin FILE *ifp = NULL, *ofp = NULL; 8398262706Serwin isc_boolean_t inheader = ISC_TRUE; 8399224092Sdougb 8400224092Sdougb /* Parse parameters */ 8401262706Serwin CHECK(zone_from_args(server, args, NULL, &zone, &zonename, 8402262706Serwin text, ISC_TRUE)); 8403254402Serwin 8404224092Sdougb if (zone == NULL) { 8405224092Sdougb result = ISC_R_UNEXPECTEDEND; 8406224092Sdougb goto cleanup; 8407224092Sdougb } 8408224092Sdougb 8409224092Sdougb /* 8410224092Sdougb * Was this zone originally added at runtime? 8411224092Sdougb * If not, we can't delete it now. 8412224092Sdougb */ 8413224092Sdougb if (!dns_zone_getadded(zone)) { 8414224092Sdougb result = ISC_R_NOPERM; 8415224092Sdougb goto cleanup; 8416224092Sdougb } 8417224092Sdougb 8418254402Serwin INSIST(zonename != NULL); 8419254402Serwin znamelen = strlen(zonename); 8420224092Sdougb 8421224092Sdougb /* Dig out configuration for this zone */ 8422224092Sdougb view = dns_zone_getview(zone); 8423224092Sdougb filename = view->new_zone_file; 8424224092Sdougb if (filename == NULL) { 8425224092Sdougb /* No adding zones in this view */ 8426224092Sdougb result = ISC_R_FAILURE; 8427224092Sdougb goto cleanup; 8428224092Sdougb } 8429224092Sdougb 8430224092Sdougb /* Rewrite zone list */ 8431224092Sdougb result = isc_stdio_open(filename, "r", &ifp); 8432224092Sdougb if (ifp != NULL && result == ISC_R_SUCCESS) { 8433224092Sdougb char *found = NULL, *p = NULL; 8434224092Sdougb size_t n; 8435224092Sdougb 8436224092Sdougb /* Create a temporary file */ 8437224092Sdougb CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename, 8438224092Sdougb (long)getpid())); 8439224092Sdougb if (!(tmpname = isc_mem_strdup(server->mctx, buf))) { 8440224092Sdougb result = ISC_R_NOMEMORY; 8441224092Sdougb goto cleanup; 8442224092Sdougb } 8443224092Sdougb CHECK(isc_stdio_open(tmpname, "w", &ofp)); 8444262706Serwin CHECK(add_comment(ofp, view->name)); 8445224092Sdougb 8446224092Sdougb /* Look for the entry for that zone */ 8447224092Sdougb while (fgets(buf, 1024, ifp)) { 8448262706Serwin /* Skip initial comment, if any */ 8449262706Serwin if (inheader && *buf == '#') 8450262706Serwin continue; 8451262706Serwin if (*buf != '#') 8452262706Serwin inheader = ISC_FALSE; 8453262706Serwin 8454262706Serwin /* 8455262706Serwin * Any other lines not starting with zone, copy 8456262706Serwin * them out and continue. 8457262706Serwin */ 8458262706Serwin if (strncasecmp(buf, "zone", 4) != 0) { 8459224092Sdougb fputs(buf, ofp); 8460224092Sdougb continue; 8461224092Sdougb } 8462224092Sdougb p = buf+4; 8463224092Sdougb 8464262706Serwin /* This is a zone; find its name. */ 8465224092Sdougb while (*p && 8466224092Sdougb ((*p == '"') || isspace((unsigned char)*p))) 8467224092Sdougb p++; 8468224092Sdougb 8469262706Serwin /* 8470262706Serwin * If it's not the zone we're looking for, copy 8471262706Serwin * it out and continue 8472262706Serwin */ 8473262706Serwin if (strncasecmp(p, zonename, znamelen) != 0) { 8474224092Sdougb fputs(buf, ofp); 8475224092Sdougb continue; 8476224092Sdougb } 8477224092Sdougb 8478262706Serwin /* 8479262706Serwin * But if it is the zone we want, skip over it 8480262706Serwin * so it will be omitted from the new file 8481262706Serwin */ 8482224092Sdougb p += znamelen; 8483224092Sdougb if (isspace((unsigned char)*p) || 8484224092Sdougb *p == '"' || *p == '{') { 8485224092Sdougb /* This must be the entry */ 8486224092Sdougb found = p; 8487224092Sdougb break; 8488224092Sdougb } 8489224092Sdougb 8490262706Serwin /* Copy the rest of the buffer out and continue */ 8491224092Sdougb fputs(buf, ofp); 8492224092Sdougb } 8493224092Sdougb 8494224092Sdougb /* Skip over an option block (matching # of braces) */ 8495224092Sdougb if (found) { 8496224092Sdougb int obrace = 0, cbrace = 0; 8497224092Sdougb for (;;) { 8498224092Sdougb while (*p) { 8499224092Sdougb if (*p == '{') obrace++; 8500224092Sdougb if (*p == '}') cbrace++; 8501224092Sdougb p++; 8502224092Sdougb } 8503224092Sdougb if (obrace && (obrace == cbrace)) 8504224092Sdougb break; 8505224092Sdougb if (!fgets(buf, 1024, ifp)) 8506224092Sdougb break; 8507224092Sdougb p = buf; 8508224092Sdougb } 8509224092Sdougb 8510224092Sdougb /* Just spool the remainder of the file out */ 8511224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 8512224092Sdougb while (n > 0U) { 8513224092Sdougb if (result == ISC_R_EOF) 8514224092Sdougb result = ISC_R_SUCCESS; 8515224092Sdougb CHECK(result); 8516224092Sdougb isc_stdio_write(buf, 1, n, ofp, NULL); 8517224092Sdougb result = isc_stdio_read(buf, 1, 1024, ifp, &n); 8518224092Sdougb } 8519224092Sdougb 8520224092Sdougb /* Move temporary into place */ 8521224092Sdougb CHECK(isc_file_rename(tmpname, view->new_zone_file)); 8522224092Sdougb } else { 8523224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8524224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 8525224092Sdougb "deleted zone %s was missing from " 8526224092Sdougb "new zone file", zonename); 8527224092Sdougb goto cleanup; 8528224092Sdougb } 8529224092Sdougb } 8530224092Sdougb 8531224092Sdougb /* Stop answering for this zone */ 8532224092Sdougb if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { 8533224092Sdougb dns_db_detach(&dbp); 8534224092Sdougb dns_zone_unload(zone); 8535224092Sdougb } 8536224092Sdougb 8537224092Sdougb CHECK(dns_zt_unmount(view->zonetable, zone)); 8538224092Sdougb 8539224092Sdougb isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 8540224092Sdougb NS_LOGMODULE_SERVER, ISC_LOG_INFO, 8541224092Sdougb "zone %s removed via delzone", zonename); 8542224092Sdougb 8543224092Sdougb result = ISC_R_SUCCESS; 8544224092Sdougb 8545224092Sdougb cleanup: 8546224092Sdougb if (ifp != NULL) 8547224092Sdougb isc_stdio_close(ifp); 8548224092Sdougb if (ofp != NULL) { 8549224092Sdougb isc_stdio_close(ofp); 8550224092Sdougb isc_file_remove(tmpname); 8551224092Sdougb } 8552224092Sdougb if (tmpname != NULL) 8553224092Sdougb isc_mem_free(server->mctx, tmpname); 8554224092Sdougb if (zone != NULL) 8555224092Sdougb dns_zone_detach(&zone); 8556224092Sdougb 8557224092Sdougb return (result); 8558224092Sdougb} 8559224092Sdougb 8560224092Sdougbstatic void 8561225361Sdougbnewzone_cfgctx_destroy(void **cfgp) { 8562224092Sdougb struct cfg_context *cfg; 8563224092Sdougb 8564224092Sdougb REQUIRE(cfgp != NULL && *cfgp != NULL); 8565225361Sdougb 8566224092Sdougb cfg = *cfgp; 8567224092Sdougb 8568225361Sdougb if (cfg->actx != NULL) 8569225361Sdougb cfg_aclconfctx_detach(&cfg->actx); 8570225361Sdougb 8571224092Sdougb if (cfg->parser != NULL) { 8572224092Sdougb if (cfg->config != NULL) 8573224092Sdougb cfg_obj_destroy(cfg->parser, &cfg->config); 8574224092Sdougb cfg_parser_destroy(&cfg->parser); 8575224092Sdougb } 8576225361Sdougb if (cfg->nzparser != NULL) { 8577225361Sdougb if (cfg->nzconfig != NULL) 8578225361Sdougb cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig); 8579225361Sdougb cfg_parser_destroy(&cfg->nzparser); 8580225361Sdougb } 8581224092Sdougb 8582225361Sdougb isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg)); 8583224092Sdougb *cfgp = NULL; 8584224092Sdougb} 8585254897Serwin 8586254897Serwinisc_result_t 8587254897Serwinns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) { 8588254897Serwin isc_result_t result = ISC_R_SUCCESS; 8589254897Serwin dns_zone_t *zone = NULL; 8590254897Serwin dns_name_t *origin; 8591254897Serwin dns_db_t *db = NULL; 8592254897Serwin dns_dbnode_t *node = NULL; 8593254897Serwin dns_dbversion_t *version = NULL; 8594254897Serwin dns_rdatatype_t privatetype; 8595254897Serwin dns_rdataset_t privset; 8596254897Serwin isc_boolean_t first = ISC_TRUE; 8597254897Serwin isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE; 8598254897Serwin isc_boolean_t chain = ISC_FALSE; 8599254897Serwin char keystr[DNS_SECALG_FORMATSIZE + 7]; 8600254897Serwin unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0; 8601254897Serwin unsigned char salt[255]; 8602254897Serwin const char *ptr; 8603254897Serwin size_t n; 8604254897Serwin 8605254897Serwin dns_rdataset_init(&privset); 8606254897Serwin 8607254897Serwin /* Skip the command name. */ 8608254897Serwin ptr = next_token(&args, " \t"); 8609254897Serwin if (ptr == NULL) 8610254897Serwin return (ISC_R_UNEXPECTEDEND); 8611254897Serwin 8612254897Serwin /* Find out what we are to do. */ 8613254897Serwin ptr = next_token(&args, " \t"); 8614254897Serwin if (ptr == NULL) 8615254897Serwin return (ISC_R_UNEXPECTEDEND); 8616254897Serwin 8617254897Serwin if (strcasecmp(ptr, "-list") == 0) 8618254897Serwin list = ISC_TRUE; 8619254897Serwin else if ((strcasecmp(ptr, "-clear") == 0) || 8620254897Serwin (strcasecmp(ptr, "-clean") == 0)) { 8621254897Serwin clear = ISC_TRUE; 8622254897Serwin ptr = next_token(&args, " \t"); 8623254897Serwin if (ptr == NULL) 8624254897Serwin return (ISC_R_UNEXPECTEDEND); 8625262706Serwin memmove(keystr, ptr, sizeof(keystr)); 8626262706Serwin } else if (strcasecmp(ptr, "-nsec3param") == 0) { 8627254897Serwin const char *hashstr, *flagstr, *iterstr; 8628254897Serwin char nbuf[512]; 8629254897Serwin 8630254897Serwin chain = ISC_TRUE; 8631254897Serwin hashstr = next_token(&args, " \t"); 8632254897Serwin if (hashstr == NULL) 8633254897Serwin return (ISC_R_UNEXPECTEDEND); 8634254897Serwin 8635254897Serwin if (strcasecmp(hashstr, "none") == 0) 8636254897Serwin hash = 0; 8637254897Serwin else { 8638254897Serwin flagstr = next_token(&args, " \t"); 8639254897Serwin iterstr = next_token(&args, " \t"); 8640254897Serwin if (flagstr == NULL || iterstr == NULL) 8641254897Serwin return (ISC_R_UNEXPECTEDEND); 8642254897Serwin 8643254897Serwin n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", 8644254897Serwin hashstr, flagstr, iterstr); 8645254897Serwin if (n == sizeof(nbuf)) 8646254897Serwin return (ISC_R_NOSPACE); 8647254897Serwin n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter); 8648254897Serwin if (n != 3U) 8649254897Serwin return (ISC_R_BADNUMBER); 8650254897Serwin 8651254897Serwin if (hash > 0xffU || flags > 0xffU) 8652254897Serwin return (ISC_R_RANGE); 8653254897Serwin 8654254897Serwin ptr = next_token(&args, " \t"); 8655254897Serwin if (ptr == NULL) 8656254897Serwin return (ISC_R_UNEXPECTEDEND); 8657254897Serwin if (strcmp(ptr, "-") != 0) { 8658254897Serwin isc_buffer_t buf; 8659254897Serwin 8660254897Serwin isc_buffer_init(&buf, salt, sizeof(salt)); 8661254897Serwin CHECK(isc_hex_decodestring(ptr, &buf)); 8662254897Serwin saltlen = isc_buffer_usedlength(&buf); 8663254897Serwin } 8664254897Serwin } 8665254897Serwin } else 8666254897Serwin CHECK(DNS_R_SYNTAX); 8667254897Serwin 8668262706Serwin CHECK(zone_from_args(server, args, NULL, &zone, NULL, 8669262706Serwin text, ISC_FALSE)); 8670254897Serwin if (zone == NULL) 8671254897Serwin CHECK(ISC_R_UNEXPECTEDEND); 8672254897Serwin 8673254897Serwin if (clear) { 8674254897Serwin CHECK(dns_zone_keydone(zone, keystr)); 8675254897Serwin isc_buffer_putstr(text, "request queued"); 8676254897Serwin isc_buffer_putuint8(text, 0); 8677254897Serwin } else if (chain) { 8678254897Serwin CHECK(dns_zone_setnsec3param(zone, (isc_uint8_t)hash, 8679254897Serwin (isc_uint8_t)flags, iter, 8680254897Serwin (isc_uint8_t)saltlen, salt, 8681254897Serwin ISC_TRUE)); 8682254897Serwin isc_buffer_putstr(text, "request queued"); 8683254897Serwin isc_buffer_putuint8(text, 0); 8684254897Serwin } else if (list) { 8685254897Serwin privatetype = dns_zone_getprivatetype(zone); 8686254897Serwin origin = dns_zone_getorigin(zone); 8687254897Serwin CHECK(dns_zone_getdb(zone, &db)); 8688254897Serwin CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node)); 8689254897Serwin dns_db_currentversion(db, &version); 8690254897Serwin 8691254897Serwin result = dns_db_findrdataset(db, node, version, privatetype, 8692254897Serwin dns_rdatatype_none, 0, 8693254897Serwin &privset, NULL); 8694254897Serwin if (result == ISC_R_NOTFOUND) { 8695254897Serwin isc_buffer_putstr(text, "No signing records found"); 8696254897Serwin isc_buffer_putuint8(text, 0); 8697254897Serwin result = ISC_R_SUCCESS; 8698254897Serwin goto cleanup; 8699254897Serwin } 8700254897Serwin 8701254897Serwin for (result = dns_rdataset_first(&privset); 8702254897Serwin result == ISC_R_SUCCESS; 8703254897Serwin result = dns_rdataset_next(&privset)) 8704254897Serwin { 8705254897Serwin dns_rdata_t priv = DNS_RDATA_INIT; 8706254897Serwin char output[BUFSIZ]; 8707254897Serwin isc_buffer_t buf; 8708254897Serwin 8709254897Serwin dns_rdataset_current(&privset, &priv); 8710254897Serwin 8711254897Serwin isc_buffer_init(&buf, output, sizeof(output)); 8712254897Serwin CHECK(dns_private_totext(&priv, &buf)); 8713254897Serwin 8714254897Serwin if (!first) 8715254897Serwin isc_buffer_putstr(text, "\n"); 8716254897Serwin first = ISC_FALSE; 8717254897Serwin 8718254897Serwin n = snprintf((char *)isc_buffer_used(text), 8719254897Serwin isc_buffer_availablelength(text), 8720254897Serwin "%s", output); 8721254897Serwin if (n >= isc_buffer_availablelength(text)) 8722254897Serwin CHECK(ISC_R_NOSPACE); 8723254897Serwin 8724262706Serwin isc_buffer_add(text, (unsigned int)n); 8725254897Serwin } 8726262706Serwin if (!first && isc_buffer_availablelength(text) > 0) 8727262706Serwin isc_buffer_putuint8(text, 0); 8728254897Serwin 8729254897Serwin if (result == ISC_R_NOMORE) 8730254897Serwin result = ISC_R_SUCCESS; 8731254897Serwin } 8732254897Serwin 8733254897Serwin cleanup: 8734254897Serwin if (dns_rdataset_isassociated(&privset)) 8735254897Serwin dns_rdataset_disassociate(&privset); 8736254897Serwin if (node != NULL) 8737254897Serwin dns_db_detachnode(db, &node); 8738254897Serwin if (version != NULL) 8739254897Serwin dns_db_closeversion(db, &version, ISC_FALSE); 8740254897Serwin if (db != NULL) 8741254897Serwin dns_db_detach(&db); 8742254897Serwin if (zone != NULL) 8743254897Serwin dns_zone_detach(&zone); 8744254897Serwin 8745254897Serwin return (result); 8746254897Serwin} 8747262706Serwin 8748262706Serwinstatic isc_result_t 8749262706Serwinputstr(isc_buffer_t *b, const char *str) { 8750262706Serwin size_t l = strlen(str); 8751262706Serwin 8752262706Serwin /* 8753262706Serwin * Use >= to leave space for NUL termination. 8754262706Serwin */ 8755262706Serwin if (l >= isc_buffer_availablelength(b)) 8756262706Serwin return (ISC_R_NOSPACE); 8757262706Serwin 8758262706Serwin isc_buffer_putmem(b, (const unsigned char *)str, l); 8759262706Serwin return (ISC_R_SUCCESS); 8760262706Serwin} 8761