1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2001-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 18170222Sdougb/*! \file */ 19170222Sdougb 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <stdlib.h> 23135446Strhodes 24135446Strhodes#include <isc/buffer.h> 25135446Strhodes#include <isc/log.h> 26135446Strhodes#include <isc/mem.h> 27170222Sdougb#include <isc/parseint.h> 28135446Strhodes#include <isc/region.h> 29135446Strhodes#include <isc/result.h> 30135446Strhodes#include <isc/sockaddr.h> 31174187Sdougb#include <isc/string.h> 32135446Strhodes#include <isc/util.h> 33135446Strhodes 34135446Strhodes#include <isccfg/namedconf.h> 35135446Strhodes 36135446Strhodes#include <dns/fixedname.h> 37135446Strhodes#include <dns/name.h> 38135446Strhodes#include <dns/rdataclass.h> 39135446Strhodes#include <dns/rdatatype.h> 40135446Strhodes#include <dns/tsig.h> 41135446Strhodes#include <dns/zone.h> 42135446Strhodes 43224092Sdougb#include <dst/dst.h> 44224092Sdougb 45135446Strhodes#include <named/config.h> 46135446Strhodes#include <named/globals.h> 47135446Strhodes 48224092Sdougb#include "bind.keys.h" 49224092Sdougb 50170222Sdougb/*% default configuration */ 51135446Strhodesstatic char defaultconf[] = "\ 52135446Strhodesoptions {\n\ 53135446Strhodes# blackhole {none;};\n" 54135446Strhodes#ifndef WIN32 55135446Strhodes" coresize default;\n\ 56135446Strhodes datasize default;\n\ 57182645Sdougb files unlimited;\n\ 58135446Strhodes stacksize default;\n" 59135446Strhodes#endif 60224092Sdougb"# session-keyfile \"" NS_LOCALSTATEDIR "/run/named/session.key\";\n\ 61224092Sdougb session-keyname local-ddns;\n\ 62224092Sdougb session-keyalg hmac-sha256;\n\ 63224092Sdougb deallocate-on-exit true;\n\ 64135446Strhodes# directory <none>\n\ 65135446Strhodes dump-file \"named_dump.db\";\n\ 66135446Strhodes fake-iquery no;\n\ 67135446Strhodes has-old-clients false;\n\ 68135446Strhodes heartbeat-interval 60;\n\ 69135446Strhodes host-statistics no;\n\ 70135446Strhodes interface-interval 60;\n\ 71135446Strhodes listen-on {any;};\n\ 72135446Strhodes listen-on-v6 {none;};\n\ 73135446Strhodes match-mapped-addresses no;\n\ 74254897Serwin max-rsa-exponent-size 0; /* no limit */\n\ 75135446Strhodes memstatistics-file \"named.memstats\";\n\ 76135446Strhodes multiple-cnames no;\n\ 77135446Strhodes# named-xfer <obsolete>;\n\ 78193149Sdougb# pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\ 79224092Sdougb bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\ 80135446Strhodes port 53;\n\ 81135446Strhodes recursing-file \"named.recursing\";\n\ 82224092Sdougb secroots-file \"named.secroots\";\n\ 83135446Strhodes" 84135446Strhodes#ifdef PATH_RANDOMDEV 85135446Strhodes"\ 86135446Strhodes random-device \"" PATH_RANDOMDEV "\";\n\ 87135446Strhodes" 88135446Strhodes#endif 89135446Strhodes"\ 90135446Strhodes recursive-clients 1000;\n\ 91245163Serwin resolver-query-timeout 10;\n\ 92254897Serwin rrset-order { order random; };\n\ 93135446Strhodes serial-queries 20;\n\ 94135446Strhodes serial-query-rate 20;\n\ 95135446Strhodes server-id none;\n\ 96135446Strhodes statistics-file \"named.stats\";\n\ 97135446Strhodes statistics-interval 60;\n\ 98135446Strhodes tcp-clients 100;\n\ 99262706Serwin tcp-listen-queue 10;\n\ 100135446Strhodes# tkey-dhkey <none>\n\ 101135446Strhodes# tkey-gssapi-credential <none>\n\ 102135446Strhodes# tkey-domain <none>\n\ 103135446Strhodes transfers-per-ns 2;\n\ 104135446Strhodes transfers-in 10;\n\ 105135446Strhodes transfers-out 10;\n\ 106135446Strhodes treat-cr-as-space true;\n\ 107135446Strhodes use-id-pool true;\n\ 108135446Strhodes use-ixfr true;\n\ 109135446Strhodes edns-udp-size 4096;\n\ 110170222Sdougb max-udp-size 4096;\n\ 111193149Sdougb request-nsid false;\n\ 112182645Sdougb reserved-sockets 512;\n\ 113135446Strhodes\n\ 114224092Sdougb /* DLV */\n\ 115224092Sdougb dnssec-lookaside . trust-anchor dlv.isc.org;\n\ 116224092Sdougb\n\ 117135446Strhodes /* view */\n\ 118135446Strhodes allow-notify {none;};\n\ 119135446Strhodes allow-update-forwarding {none;};\n\ 120170222Sdougb allow-query-cache { localnets; localhost; };\n\ 121193149Sdougb allow-query-cache-on { any; };\n\ 122170222Sdougb allow-recursion { localnets; localhost; };\n\ 123193149Sdougb allow-recursion-on { any; };\n\ 124135446Strhodes# allow-v6-synthesis <obsolete>;\n\ 125135446Strhodes# sortlist <none>\n\ 126135446Strhodes# topology <none>\n\ 127135446Strhodes auth-nxdomain false;\n\ 128135446Strhodes minimal-responses false;\n\ 129135446Strhodes recursion true;\n\ 130135446Strhodes provide-ixfr true;\n\ 131135446Strhodes request-ixfr true;\n\ 132135446Strhodes fetch-glue no;\n\ 133135446Strhodes rfc2308-type1 no;\n\ 134135446Strhodes additional-from-auth true;\n\ 135135446Strhodes additional-from-cache true;\n\ 136135446Strhodes query-source address *;\n\ 137135446Strhodes query-source-v6 address *;\n\ 138135446Strhodes notify-source *;\n\ 139135446Strhodes notify-source-v6 *;\n\ 140193149Sdougb cleaning-interval 0; /* now meaningless */\n\ 141135446Strhodes min-roots 2;\n\ 142135446Strhodes lame-ttl 600;\n\ 143135446Strhodes max-ncache-ttl 10800; /* 3 hours */\n\ 144135446Strhodes max-cache-ttl 604800; /* 1 week */\n\ 145135446Strhodes transfer-format many-answers;\n\ 146135446Strhodes max-cache-size 0;\n\ 147135446Strhodes check-names master fail;\n\ 148135446Strhodes check-names slave warn;\n\ 149135446Strhodes check-names response ignore;\n\ 150224092Sdougb check-dup-records warn;\n\ 151170222Sdougb check-mx warn;\n\ 152254402Serwin check-spf warn;\n\ 153170222Sdougb acache-enable no;\n\ 154170222Sdougb acache-cleaning-interval 60;\n\ 155193149Sdougb max-acache-size 16M;\n\ 156170222Sdougb dnssec-enable yes;\n\ 157193149Sdougb dnssec-validation yes; \n\ 158170222Sdougb dnssec-accept-expired no;\n\ 159170222Sdougb clients-per-query 10;\n\ 160170222Sdougb max-clients-per-query 100;\n\ 161275672Sdelphij max-recursion-depth 7;\n\ 162170222Sdougb zero-no-soa-ttl-cache no;\n\ 163193149Sdougb nsec3-test-zone no;\n\ 164224092Sdougb allow-new-zones no;\n\ 165135446Strhodes" 166224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 167224092Sdougb" filter-aaaa-on-v4 no;\n\ 168224092Sdougb filter-aaaa { any; };\n\ 169224092Sdougb" 170224092Sdougb#endif 171135446Strhodes 172135446Strhodes" /* zone */\n\ 173135446Strhodes allow-query {any;};\n\ 174193149Sdougb allow-query-on {any;};\n\ 175135446Strhodes allow-transfer {any;};\n\ 176135446Strhodes notify yes;\n\ 177135446Strhodes# also-notify <none>\n\ 178170222Sdougb notify-delay 5;\n\ 179193149Sdougb notify-to-soa no;\n\ 180135446Strhodes dialup no;\n\ 181135446Strhodes# forward <none>\n\ 182135446Strhodes# forwarders <none>\n\ 183135446Strhodes maintain-ixfr-base no;\n\ 184135446Strhodes# max-ixfr-log-size <obsolete>\n\ 185135446Strhodes transfer-source *;\n\ 186135446Strhodes transfer-source-v6 *;\n\ 187135446Strhodes alt-transfer-source *;\n\ 188135446Strhodes alt-transfer-source-v6 *;\n\ 189135446Strhodes max-transfer-time-in 120;\n\ 190135446Strhodes max-transfer-time-out 120;\n\ 191135446Strhodes max-transfer-idle-in 60;\n\ 192135446Strhodes max-transfer-idle-out 60;\n\ 193135446Strhodes max-retry-time 1209600; /* 2 weeks */\n\ 194135446Strhodes min-retry-time 500;\n\ 195135446Strhodes max-refresh-time 2419200; /* 4 weeks */\n\ 196135446Strhodes min-refresh-time 300;\n\ 197135446Strhodes multi-master no;\n\ 198224092Sdougb dnssec-secure-to-insecure no;\n\ 199135446Strhodes sig-validity-interval 30; /* days */\n\ 200193149Sdougb sig-signing-nodes 100;\n\ 201193149Sdougb sig-signing-signatures 10;\n\ 202193149Sdougb sig-signing-type 65534;\n\ 203254897Serwin inline-signing no;\n\ 204254897Serwin zone-statistics terse;\n\ 205135446Strhodes max-journal-size unlimited;\n\ 206135446Strhodes ixfr-from-differences false;\n\ 207170222Sdougb check-wildcard yes;\n\ 208170222Sdougb check-sibling yes;\n\ 209170222Sdougb check-integrity yes;\n\ 210170222Sdougb check-mx-cname warn;\n\ 211170222Sdougb check-srv-cname warn;\n\ 212170222Sdougb zero-no-soa-ttl yes;\n\ 213170222Sdougb update-check-ksk yes;\n\ 214254897Serwin serial-update-method increment;\n\ 215254897Serwin dnssec-update-mode maintain;\n\ 216224092Sdougb dnssec-dnskey-kskonly no;\n\ 217254897Serwin dnssec-loadkeys-interval 60;\n\ 218193149Sdougb try-tcp-refresh yes; /* BIND 8 compat */\n\ 219135446Strhodes};\n\ 220135446Strhodes" 221135446Strhodes 222135446Strhodes"#\n\ 223174187Sdougb# Zones in the \"_bind\" view are NOT counted in the count of zones.\n\ 224135446Strhodes#\n\ 225135446Strhodesview \"_bind\" chaos {\n\ 226135446Strhodes recursion no;\n\ 227135446Strhodes notify no;\n\ 228224092Sdougb allow-new-zones no;\n\ 229262706Serwin" 230262706Serwin#ifdef USE_RRL 231262706Serwin" # Prevent use of this zone in DNS amplified reflection DoS attacks\n\ 232262706Serwin rate-limit {\n\ 233262706Serwin responses-per-second 3;\n\ 234262706Serwin slip 0;\n\ 235262706Serwin min-table-size 10;\n\ 236262706Serwin };\n\ 237262706Serwin" 238262706Serwin#endif /* USE_RRL */ 239262706Serwin" zone \"version.bind\" chaos {\n\ 240135446Strhodes type master;\n\ 241135446Strhodes database \"_builtin version\";\n\ 242135446Strhodes };\n\ 243135446Strhodes\n\ 244135446Strhodes zone \"hostname.bind\" chaos {\n\ 245135446Strhodes type master;\n\ 246135446Strhodes database \"_builtin hostname\";\n\ 247135446Strhodes };\n\ 248135446Strhodes\n\ 249135446Strhodes zone \"authors.bind\" chaos {\n\ 250135446Strhodes type master;\n\ 251135446Strhodes database \"_builtin authors\";\n\ 252135446Strhodes };\n\ 253224092Sdougb\n\ 254135446Strhodes zone \"id.server\" chaos {\n\ 255135446Strhodes type master;\n\ 256135446Strhodes database \"_builtin id\";\n\ 257135446Strhodes };\n\ 258135446Strhodes};\n\ 259224092Sdougb" 260224092Sdougb"#\n\ 261224092Sdougb# Default trusted key(s) for builtin DLV support\n\ 262224092Sdougb# (used if \"dnssec-lookaside auto;\" is set and\n\ 263224092Sdougb# sysconfdir/bind.keys doesn't exist).\n\ 264224092Sdougb#\n\ 265224092Sdougb# BEGIN MANAGED KEYS\n" 266224092Sdougb 267224092Sdougb/* Imported from bind.keys.h: */ 268224092SdougbMANAGED_KEYS 269224092Sdougb 270224092Sdougb"# END MANAGED KEYS\n\ 271135446Strhodes"; 272135446Strhodes 273135446Strhodesisc_result_t 274135446Strhodesns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) { 275135446Strhodes isc_buffer_t b; 276135446Strhodes 277135446Strhodes isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1); 278135446Strhodes isc_buffer_add(&b, sizeof(defaultconf) - 1); 279135446Strhodes return (cfg_parse_buffer(parser, &b, &cfg_type_namedconf, conf)); 280135446Strhodes} 281135446Strhodes 282135446Strhodesisc_result_t 283165071Sdougbns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { 284135446Strhodes int i; 285135446Strhodes 286135446Strhodes for (i = 0;; i++) { 287135446Strhodes if (maps[i] == NULL) 288135446Strhodes return (ISC_R_NOTFOUND); 289135446Strhodes if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) 290135446Strhodes return (ISC_R_SUCCESS); 291135446Strhodes } 292135446Strhodes} 293135446Strhodes 294135446Strhodesisc_result_t 295165071Sdougbns_checknames_get(const cfg_obj_t **maps, const char *which, 296165071Sdougb const cfg_obj_t **obj) 297165071Sdougb{ 298165071Sdougb const cfg_listelt_t *element; 299165071Sdougb const cfg_obj_t *checknames; 300165071Sdougb const cfg_obj_t *type; 301165071Sdougb const cfg_obj_t *value; 302135446Strhodes int i; 303135446Strhodes 304135446Strhodes for (i = 0;; i++) { 305135446Strhodes if (maps[i] == NULL) 306135446Strhodes return (ISC_R_NOTFOUND); 307135446Strhodes checknames = NULL; 308254897Serwin if (cfg_map_get(maps[i], "check-names", 309254897Serwin &checknames) == ISC_R_SUCCESS) { 310135446Strhodes /* 311135446Strhodes * Zone map entry is not a list. 312135446Strhodes */ 313135446Strhodes if (checknames != NULL && !cfg_obj_islist(checknames)) { 314135446Strhodes *obj = checknames; 315135446Strhodes return (ISC_R_SUCCESS); 316135446Strhodes } 317135446Strhodes for (element = cfg_list_first(checknames); 318135446Strhodes element != NULL; 319135446Strhodes element = cfg_list_next(element)) { 320135446Strhodes value = cfg_listelt_value(element); 321135446Strhodes type = cfg_tuple_get(value, "type"); 322254897Serwin if (strcasecmp(cfg_obj_asstring(type), 323254897Serwin which) == 0) { 324135446Strhodes *obj = cfg_tuple_get(value, "mode"); 325135446Strhodes return (ISC_R_SUCCESS); 326135446Strhodes } 327135446Strhodes } 328135446Strhodes 329135446Strhodes } 330135446Strhodes } 331135446Strhodes} 332135446Strhodes 333135446Strhodesint 334165071Sdougbns_config_listcount(const cfg_obj_t *list) { 335165071Sdougb const cfg_listelt_t *e; 336135446Strhodes int i = 0; 337135446Strhodes 338135446Strhodes for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e)) 339135446Strhodes i++; 340135446Strhodes 341135446Strhodes return (i); 342135446Strhodes} 343135446Strhodes 344135446Strhodesisc_result_t 345165071Sdougbns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, 346135446Strhodes dns_rdataclass_t *classp) { 347135446Strhodes isc_textregion_t r; 348135446Strhodes isc_result_t result; 349135446Strhodes 350135446Strhodes if (!cfg_obj_isstring(classobj)) { 351135446Strhodes *classp = defclass; 352135446Strhodes return (ISC_R_SUCCESS); 353135446Strhodes } 354170222Sdougb DE_CONST(cfg_obj_asstring(classobj), r.base); 355170222Sdougb r.length = strlen(r.base); 356135446Strhodes result = dns_rdataclass_fromtext(classp, &r); 357135446Strhodes if (result != ISC_R_SUCCESS) 358135446Strhodes cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR, 359170222Sdougb "unknown class '%s'", r.base); 360135446Strhodes return (result); 361135446Strhodes} 362135446Strhodes 363135446Strhodesisc_result_t 364165071Sdougbns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, 365135446Strhodes dns_rdatatype_t *typep) { 366135446Strhodes isc_textregion_t r; 367135446Strhodes isc_result_t result; 368135446Strhodes 369135446Strhodes if (!cfg_obj_isstring(typeobj)) { 370135446Strhodes *typep = deftype; 371135446Strhodes return (ISC_R_SUCCESS); 372135446Strhodes } 373170222Sdougb DE_CONST(cfg_obj_asstring(typeobj), r.base); 374170222Sdougb r.length = strlen(r.base); 375135446Strhodes result = dns_rdatatype_fromtext(typep, &r); 376135446Strhodes if (result != ISC_R_SUCCESS) 377135446Strhodes cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR, 378170222Sdougb "unknown type '%s'", r.base); 379135446Strhodes return (result); 380135446Strhodes} 381135446Strhodes 382135446Strhodesdns_zonetype_t 383165071Sdougbns_config_getzonetype(const cfg_obj_t *zonetypeobj) { 384135446Strhodes dns_zonetype_t ztype = dns_zone_none; 385165071Sdougb const char *str; 386135446Strhodes 387135446Strhodes str = cfg_obj_asstring(zonetypeobj); 388135446Strhodes if (strcasecmp(str, "master") == 0) 389135446Strhodes ztype = dns_zone_master; 390135446Strhodes else if (strcasecmp(str, "slave") == 0) 391135446Strhodes ztype = dns_zone_slave; 392135446Strhodes else if (strcasecmp(str, "stub") == 0) 393135446Strhodes ztype = dns_zone_stub; 394224092Sdougb else if (strcasecmp(str, "static-stub") == 0) 395224092Sdougb ztype = dns_zone_staticstub; 396254897Serwin else if (strcasecmp(str, "redirect") == 0) 397254897Serwin ztype = dns_zone_redirect; 398135446Strhodes else 399135446Strhodes INSIST(0); 400135446Strhodes return (ztype); 401135446Strhodes} 402135446Strhodes 403135446Strhodesisc_result_t 404165071Sdougbns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, 405135446Strhodes in_port_t defport, isc_mem_t *mctx, 406135446Strhodes isc_sockaddr_t **addrsp, isc_uint32_t *countp) 407135446Strhodes{ 408135446Strhodes int count, i = 0; 409165071Sdougb const cfg_obj_t *addrlist; 410165071Sdougb const cfg_obj_t *portobj; 411165071Sdougb const cfg_listelt_t *element; 412135446Strhodes isc_sockaddr_t *addrs; 413135446Strhodes in_port_t port; 414135446Strhodes isc_result_t result; 415135446Strhodes 416135446Strhodes INSIST(addrsp != NULL && *addrsp == NULL); 417135446Strhodes INSIST(countp != NULL); 418135446Strhodes 419135446Strhodes addrlist = cfg_tuple_get(list, "addresses"); 420135446Strhodes count = ns_config_listcount(addrlist); 421135446Strhodes 422135446Strhodes portobj = cfg_tuple_get(list, "port"); 423135446Strhodes if (cfg_obj_isuint32(portobj)) { 424135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 425135446Strhodes if (val > ISC_UINT16_MAX) { 426135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 427135446Strhodes "port '%u' out of range", val); 428135446Strhodes return (ISC_R_RANGE); 429135446Strhodes } 430135446Strhodes port = (in_port_t) val; 431135446Strhodes } else if (defport != 0) 432135446Strhodes port = defport; 433135446Strhodes else { 434135446Strhodes result = ns_config_getport(config, &port); 435135446Strhodes if (result != ISC_R_SUCCESS) 436135446Strhodes return (result); 437135446Strhodes } 438135446Strhodes 439135446Strhodes addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); 440135446Strhodes if (addrs == NULL) 441135446Strhodes return (ISC_R_NOMEMORY); 442135446Strhodes 443135446Strhodes for (element = cfg_list_first(addrlist); 444135446Strhodes element != NULL; 445135446Strhodes element = cfg_list_next(element), i++) 446135446Strhodes { 447135446Strhodes INSIST(i < count); 448135446Strhodes addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element)); 449135446Strhodes if (isc_sockaddr_getport(&addrs[i]) == 0) 450135446Strhodes isc_sockaddr_setport(&addrs[i], port); 451135446Strhodes } 452135446Strhodes INSIST(i == count); 453135446Strhodes 454135446Strhodes *addrsp = addrs; 455135446Strhodes *countp = count; 456135446Strhodes 457135446Strhodes return (ISC_R_SUCCESS); 458135446Strhodes} 459135446Strhodes 460135446Strhodesvoid 461135446Strhodesns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, 462135446Strhodes isc_uint32_t count) 463135446Strhodes{ 464135446Strhodes INSIST(addrsp != NULL && *addrsp != NULL); 465135446Strhodes 466135446Strhodes isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); 467135446Strhodes *addrsp = NULL; 468135446Strhodes} 469135446Strhodes 470135446Strhodesstatic isc_result_t 471165071Sdougbget_masters_def(const cfg_obj_t *cctx, const char *name, 472186462Sdougb const cfg_obj_t **ret) 473165071Sdougb{ 474135446Strhodes isc_result_t result; 475165071Sdougb const cfg_obj_t *masters = NULL; 476165071Sdougb const cfg_listelt_t *elt; 477135446Strhodes 478135446Strhodes result = cfg_map_get(cctx, "masters", &masters); 479135446Strhodes if (result != ISC_R_SUCCESS) 480135446Strhodes return (result); 481135446Strhodes for (elt = cfg_list_first(masters); 482135446Strhodes elt != NULL; 483135446Strhodes elt = cfg_list_next(elt)) { 484165071Sdougb const cfg_obj_t *list; 485135446Strhodes const char *listname; 486135446Strhodes 487135446Strhodes list = cfg_listelt_value(elt); 488135446Strhodes listname = cfg_obj_asstring(cfg_tuple_get(list, "name")); 489135446Strhodes 490135446Strhodes if (strcasecmp(listname, name) == 0) { 491135446Strhodes *ret = list; 492135446Strhodes return (ISC_R_SUCCESS); 493135446Strhodes } 494135446Strhodes } 495135446Strhodes return (ISC_R_NOTFOUND); 496135446Strhodes} 497135446Strhodes 498135446Strhodesisc_result_t 499165071Sdougbns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, 500165071Sdougb isc_mem_t *mctx, isc_sockaddr_t **addrsp, 501165071Sdougb dns_name_t ***keysp, isc_uint32_t *countp) 502135446Strhodes{ 503135446Strhodes isc_uint32_t addrcount = 0, keycount = 0, i = 0; 504135446Strhodes isc_uint32_t listcount = 0, l = 0, j; 505135446Strhodes isc_uint32_t stackcount = 0, pushed = 0; 506135446Strhodes isc_result_t result; 507165071Sdougb const cfg_listelt_t *element; 508165071Sdougb const cfg_obj_t *addrlist; 509165071Sdougb const cfg_obj_t *portobj; 510135446Strhodes in_port_t port; 511135446Strhodes dns_fixedname_t fname; 512135446Strhodes isc_sockaddr_t *addrs = NULL; 513135446Strhodes dns_name_t **keys = NULL; 514170222Sdougb struct { const char *name; } *lists = NULL; 515135446Strhodes struct { 516165071Sdougb const cfg_listelt_t *element; 517135446Strhodes in_port_t port; 518135446Strhodes } *stack = NULL; 519135446Strhodes 520135446Strhodes REQUIRE(addrsp != NULL && *addrsp == NULL); 521135446Strhodes REQUIRE(keysp != NULL && *keysp == NULL); 522135446Strhodes REQUIRE(countp != NULL); 523135446Strhodes 524135446Strhodes newlist: 525135446Strhodes addrlist = cfg_tuple_get(list, "addresses"); 526135446Strhodes portobj = cfg_tuple_get(list, "port"); 527135446Strhodes if (cfg_obj_isuint32(portobj)) { 528135446Strhodes isc_uint32_t val = cfg_obj_asuint32(portobj); 529135446Strhodes if (val > ISC_UINT16_MAX) { 530135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 531135446Strhodes "port '%u' out of range", val); 532165071Sdougb result = ISC_R_RANGE; 533165071Sdougb goto cleanup; 534135446Strhodes } 535135446Strhodes port = (in_port_t) val; 536135446Strhodes } else { 537135446Strhodes result = ns_config_getport(config, &port); 538135446Strhodes if (result != ISC_R_SUCCESS) 539165071Sdougb goto cleanup; 540135446Strhodes } 541135446Strhodes 542135446Strhodes result = ISC_R_NOMEMORY; 543135446Strhodes 544135446Strhodes element = cfg_list_first(addrlist); 545135446Strhodes resume: 546135446Strhodes for ( ; 547135446Strhodes element != NULL; 548135446Strhodes element = cfg_list_next(element)) 549135446Strhodes { 550165071Sdougb const cfg_obj_t *addr; 551165071Sdougb const cfg_obj_t *key; 552165071Sdougb const char *keystr; 553135446Strhodes isc_buffer_t b; 554135446Strhodes 555135446Strhodes addr = cfg_tuple_get(cfg_listelt_value(element), 556135446Strhodes "masterselement"); 557135446Strhodes key = cfg_tuple_get(cfg_listelt_value(element), "key"); 558135446Strhodes 559135446Strhodes if (!cfg_obj_issockaddr(addr)) { 560165071Sdougb const char *listname = cfg_obj_asstring(addr); 561135446Strhodes isc_result_t tresult; 562135446Strhodes 563135446Strhodes /* Grow lists? */ 564135446Strhodes if (listcount == l) { 565135446Strhodes void * new; 566135446Strhodes isc_uint32_t newlen = listcount + 16; 567135446Strhodes size_t newsize, oldsize; 568135446Strhodes 569135446Strhodes newsize = newlen * sizeof(*lists); 570135446Strhodes oldsize = listcount * sizeof(*lists); 571135446Strhodes new = isc_mem_get(mctx, newsize); 572135446Strhodes if (new == NULL) 573135446Strhodes goto cleanup; 574135446Strhodes if (listcount != 0) { 575262706Serwin memmove(new, lists, oldsize); 576135446Strhodes isc_mem_put(mctx, lists, oldsize); 577135446Strhodes } 578135446Strhodes lists = new; 579135446Strhodes listcount = newlen; 580135446Strhodes } 581135446Strhodes /* Seen? */ 582135446Strhodes for (j = 0; j < l; j++) 583170222Sdougb if (strcasecmp(lists[j].name, listname) == 0) 584135446Strhodes break; 585135446Strhodes if (j < l) 586135446Strhodes continue; 587135446Strhodes tresult = get_masters_def(config, listname, &list); 588135446Strhodes if (tresult == ISC_R_NOTFOUND) { 589135446Strhodes cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR, 590186462Sdougb "masters \"%s\" not found", listname); 591135446Strhodes 592135446Strhodes result = tresult; 593135446Strhodes goto cleanup; 594135446Strhodes } 595135446Strhodes if (tresult != ISC_R_SUCCESS) 596135446Strhodes goto cleanup; 597170222Sdougb lists[l++].name = listname; 598135446Strhodes /* Grow stack? */ 599135446Strhodes if (stackcount == pushed) { 600135446Strhodes void * new; 601135446Strhodes isc_uint32_t newlen = stackcount + 16; 602135446Strhodes size_t newsize, oldsize; 603135446Strhodes 604135446Strhodes newsize = newlen * sizeof(*stack); 605135446Strhodes oldsize = stackcount * sizeof(*stack); 606135446Strhodes new = isc_mem_get(mctx, newsize); 607135446Strhodes if (new == NULL) 608135446Strhodes goto cleanup; 609135446Strhodes if (stackcount != 0) { 610262706Serwin memmove(new, stack, oldsize); 611135446Strhodes isc_mem_put(mctx, stack, oldsize); 612135446Strhodes } 613135446Strhodes stack = new; 614135446Strhodes stackcount = newlen; 615135446Strhodes } 616135446Strhodes /* 617135446Strhodes * We want to resume processing this list on the 618135446Strhodes * next element. 619135446Strhodes */ 620135446Strhodes stack[pushed].element = cfg_list_next(element); 621135446Strhodes stack[pushed].port = port; 622135446Strhodes pushed++; 623135446Strhodes goto newlist; 624135446Strhodes } 625135446Strhodes 626135446Strhodes if (i == addrcount) { 627135446Strhodes void * new; 628135446Strhodes isc_uint32_t newlen = addrcount + 16; 629135446Strhodes size_t newsize, oldsize; 630135446Strhodes 631135446Strhodes newsize = newlen * sizeof(isc_sockaddr_t); 632135446Strhodes oldsize = addrcount * sizeof(isc_sockaddr_t); 633135446Strhodes new = isc_mem_get(mctx, newsize); 634135446Strhodes if (new == NULL) 635135446Strhodes goto cleanup; 636135446Strhodes if (addrcount != 0) { 637262706Serwin memmove(new, addrs, oldsize); 638135446Strhodes isc_mem_put(mctx, addrs, oldsize); 639135446Strhodes } 640135446Strhodes addrs = new; 641135446Strhodes addrcount = newlen; 642135446Strhodes 643135446Strhodes newsize = newlen * sizeof(dns_name_t *); 644135446Strhodes oldsize = keycount * sizeof(dns_name_t *); 645135446Strhodes new = isc_mem_get(mctx, newsize); 646135446Strhodes if (new == NULL) 647135446Strhodes goto cleanup; 648135446Strhodes if (keycount != 0) { 649262706Serwin memmove(new, keys, oldsize); 650143731Sdougb isc_mem_put(mctx, keys, oldsize); 651135446Strhodes } 652135446Strhodes keys = new; 653135446Strhodes keycount = newlen; 654135446Strhodes } 655135446Strhodes 656135446Strhodes addrs[i] = *cfg_obj_assockaddr(addr); 657135446Strhodes if (isc_sockaddr_getport(&addrs[i]) == 0) 658135446Strhodes isc_sockaddr_setport(&addrs[i], port); 659135446Strhodes keys[i] = NULL; 660254402Serwin i++; /* Increment here so that cleanup on error works. */ 661254402Serwin if (!cfg_obj_isstring(key)) 662135446Strhodes continue; 663254402Serwin keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t)); 664254402Serwin if (keys[i - 1] == NULL) 665135446Strhodes goto cleanup; 666254402Serwin dns_name_init(keys[i - 1], NULL); 667186462Sdougb 668135446Strhodes keystr = cfg_obj_asstring(key); 669254402Serwin isc_buffer_constinit(&b, keystr, strlen(keystr)); 670135446Strhodes isc_buffer_add(&b, strlen(keystr)); 671135446Strhodes dns_fixedname_init(&fname); 672135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&fname), &b, 673224092Sdougb dns_rootname, 0, NULL); 674135446Strhodes if (result != ISC_R_SUCCESS) 675135446Strhodes goto cleanup; 676135446Strhodes result = dns_name_dup(dns_fixedname_name(&fname), mctx, 677254402Serwin keys[i - 1]); 678135446Strhodes if (result != ISC_R_SUCCESS) 679135446Strhodes goto cleanup; 680135446Strhodes } 681135446Strhodes if (pushed != 0) { 682135446Strhodes pushed--; 683135446Strhodes element = stack[pushed].element; 684135446Strhodes port = stack[pushed].port; 685135446Strhodes goto resume; 686135446Strhodes } 687135446Strhodes if (i < addrcount) { 688135446Strhodes void * new; 689135446Strhodes size_t newsize, oldsize; 690135446Strhodes 691135446Strhodes newsize = i * sizeof(isc_sockaddr_t); 692135446Strhodes oldsize = addrcount * sizeof(isc_sockaddr_t); 693135446Strhodes if (i != 0) { 694135446Strhodes new = isc_mem_get(mctx, newsize); 695135446Strhodes if (new == NULL) 696135446Strhodes goto cleanup; 697262706Serwin memmove(new, addrs, newsize); 698135446Strhodes } else 699135446Strhodes new = NULL; 700165071Sdougb isc_mem_put(mctx, addrs, oldsize); 701135446Strhodes addrs = new; 702135446Strhodes addrcount = i; 703135446Strhodes 704135446Strhodes newsize = i * sizeof(dns_name_t *); 705135446Strhodes oldsize = keycount * sizeof(dns_name_t *); 706135446Strhodes if (i != 0) { 707135446Strhodes new = isc_mem_get(mctx, newsize); 708135446Strhodes if (new == NULL) 709135446Strhodes goto cleanup; 710262706Serwin memmove(new, keys, newsize); 711135446Strhodes } else 712135446Strhodes new = NULL; 713165071Sdougb isc_mem_put(mctx, keys, oldsize); 714135446Strhodes keys = new; 715135446Strhodes keycount = i; 716135446Strhodes } 717135446Strhodes 718135446Strhodes if (lists != NULL) 719135446Strhodes isc_mem_put(mctx, lists, listcount * sizeof(*lists)); 720135446Strhodes if (stack != NULL) 721135446Strhodes isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); 722186462Sdougb 723135446Strhodes INSIST(keycount == addrcount); 724135446Strhodes 725135446Strhodes *addrsp = addrs; 726135446Strhodes *keysp = keys; 727135446Strhodes *countp = addrcount; 728135446Strhodes 729135446Strhodes return (ISC_R_SUCCESS); 730135446Strhodes 731135446Strhodes cleanup: 732135446Strhodes if (addrs != NULL) 733135446Strhodes isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); 734135446Strhodes if (keys != NULL) { 735254402Serwin for (j = 0; j < i; j++) { 736135446Strhodes if (keys[j] == NULL) 737135446Strhodes continue; 738135446Strhodes if (dns_name_dynamic(keys[j])) 739135446Strhodes dns_name_free(keys[j], mctx); 740135446Strhodes isc_mem_put(mctx, keys[j], sizeof(dns_name_t)); 741135446Strhodes } 742135446Strhodes isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *)); 743135446Strhodes } 744135446Strhodes if (lists != NULL) 745135446Strhodes isc_mem_put(mctx, lists, listcount * sizeof(*lists)); 746135446Strhodes if (stack != NULL) 747135446Strhodes isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); 748135446Strhodes return (result); 749135446Strhodes} 750135446Strhodes 751135446Strhodesvoid 752135446Strhodesns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, 753135446Strhodes dns_name_t ***keysp, isc_uint32_t count) 754135446Strhodes{ 755135446Strhodes unsigned int i; 756135446Strhodes dns_name_t **keys = *keysp; 757135446Strhodes 758135446Strhodes INSIST(addrsp != NULL && *addrsp != NULL); 759135446Strhodes 760135446Strhodes isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); 761135446Strhodes for (i = 0; i < count; i++) { 762135446Strhodes if (keys[i] == NULL) 763135446Strhodes continue; 764135446Strhodes if (dns_name_dynamic(keys[i])) 765135446Strhodes dns_name_free(keys[i], mctx); 766135446Strhodes isc_mem_put(mctx, keys[i], sizeof(dns_name_t)); 767135446Strhodes } 768135446Strhodes isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *)); 769135446Strhodes *addrsp = NULL; 770135446Strhodes *keysp = NULL; 771135446Strhodes} 772135446Strhodes 773135446Strhodesisc_result_t 774165071Sdougbns_config_getport(const cfg_obj_t *config, in_port_t *portp) { 775165071Sdougb const cfg_obj_t *maps[3]; 776165071Sdougb const cfg_obj_t *options = NULL; 777165071Sdougb const cfg_obj_t *portobj = NULL; 778135446Strhodes isc_result_t result; 779135446Strhodes int i; 780135446Strhodes 781135446Strhodes (void)cfg_map_get(config, "options", &options); 782135446Strhodes i = 0; 783135446Strhodes if (options != NULL) 784135446Strhodes maps[i++] = options; 785135446Strhodes maps[i++] = ns_g_defaults; 786135446Strhodes maps[i] = NULL; 787135446Strhodes 788135446Strhodes result = ns_config_get(maps, "port", &portobj); 789135446Strhodes INSIST(result == ISC_R_SUCCESS); 790135446Strhodes if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 791135446Strhodes cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 792135446Strhodes "port '%u' out of range", 793135446Strhodes cfg_obj_asuint32(portobj)); 794135446Strhodes return (ISC_R_RANGE); 795135446Strhodes } 796135446Strhodes *portp = (in_port_t)cfg_obj_asuint32(portobj); 797135446Strhodes return (ISC_R_SUCCESS); 798135446Strhodes} 799135446Strhodes 800170222Sdougbstruct keyalgorithms { 801170222Sdougb const char *str; 802170222Sdougb enum { hmacnone, hmacmd5, hmacsha1, hmacsha224, 803170222Sdougb hmacsha256, hmacsha384, hmacsha512 } hmac; 804224092Sdougb unsigned int type; 805170222Sdougb isc_uint16_t size; 806170222Sdougb} algorithms[] = { 807224092Sdougb { "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 }, 808224092Sdougb { "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 }, 809224092Sdougb { "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 }, 810224092Sdougb { "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 }, 811224092Sdougb { "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 }, 812224092Sdougb { "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 }, 813224092Sdougb { "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 }, 814224092Sdougb { "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 }, 815224092Sdougb { NULL, hmacnone, DST_ALG_UNKNOWN, 0 } 816170222Sdougb}; 817170222Sdougb 818135446Strhodesisc_result_t 819170222Sdougbns_config_getkeyalgorithm(const char *str, dns_name_t **name, 820170222Sdougb isc_uint16_t *digestbits) 821135446Strhodes{ 822224092Sdougb return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits)); 823224092Sdougb} 824224092Sdougb 825224092Sdougbisc_result_t 826224092Sdougbns_config_getkeyalgorithm2(const char *str, dns_name_t **name, 827224092Sdougb unsigned int *typep, isc_uint16_t *digestbits) 828224092Sdougb{ 829170222Sdougb int i; 830170222Sdougb size_t len = 0; 831170222Sdougb isc_uint16_t bits; 832170222Sdougb isc_result_t result; 833170222Sdougb 834170222Sdougb for (i = 0; algorithms[i].str != NULL; i++) { 835170222Sdougb len = strlen(algorithms[i].str); 836170222Sdougb if (strncasecmp(algorithms[i].str, str, len) == 0 && 837170222Sdougb (str[len] == '\0' || 838170222Sdougb (algorithms[i].size != 0 && str[len] == '-'))) 839170222Sdougb break; 840135446Strhodes } 841170222Sdougb if (algorithms[i].str == NULL) 842170222Sdougb return (ISC_R_NOTFOUND); 843170222Sdougb if (str[len] == '-') { 844170222Sdougb result = isc_parse_uint16(&bits, str + len + 1, 10); 845170222Sdougb if (result != ISC_R_SUCCESS) 846170222Sdougb return (result); 847170222Sdougb if (bits > algorithms[i].size) 848170222Sdougb return (ISC_R_RANGE); 849170222Sdougb } else if (algorithms[i].size == 0) 850170222Sdougb bits = 128; 851170222Sdougb else 852170222Sdougb bits = algorithms[i].size; 853170222Sdougb 854170222Sdougb if (name != NULL) { 855170222Sdougb switch (algorithms[i].hmac) { 856170222Sdougb case hmacmd5: *name = dns_tsig_hmacmd5_name; break; 857170222Sdougb case hmacsha1: *name = dns_tsig_hmacsha1_name; break; 858170222Sdougb case hmacsha224: *name = dns_tsig_hmacsha224_name; break; 859170222Sdougb case hmacsha256: *name = dns_tsig_hmacsha256_name; break; 860170222Sdougb case hmacsha384: *name = dns_tsig_hmacsha384_name; break; 861170222Sdougb case hmacsha512: *name = dns_tsig_hmacsha512_name; break; 862170222Sdougb default: 863170222Sdougb INSIST(0); 864170222Sdougb } 865170222Sdougb } 866224092Sdougb if (typep != NULL) 867224092Sdougb *typep = algorithms[i].type; 868170222Sdougb if (digestbits != NULL) 869170222Sdougb *digestbits = bits; 870170222Sdougb return (ISC_R_SUCCESS); 871135446Strhodes} 872