static isc_result_t add_listener(ns_server_t *server, ns_statschannel_t **listenerp, const cfg_obj_t *listen_params, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext) { isc_result_t result; ns_statschannel_t *listener; isc_task_t *task = NULL; isc_socket_t *sock = NULL; const cfg_obj_t *allow; dns_acl_t *new_acl = NULL; listener = isc_mem_get(server->mctx, sizeof(*listener)); if (listener == NULL) return (ISC_R_NOMEMORY); listener->httpdmgr = NULL; listener->address = *addr; listener->acl = NULL; listener->mctx = NULL; ISC_LINK_INIT(listener, link); result = isc_mutex_init(&listener->lock); if (result != ISC_R_SUCCESS) { isc_mem_put(server->mctx, listener, sizeof(*listener)); return (ISC_R_FAILURE); } isc_mem_attach(server->mctx, &listener->mctx); allow = cfg_tuple_get(listen_params, "allow"); if (allow != NULL && cfg_obj_islist(allow)) { result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else result = dns_acl_any(listener->mctx, &new_acl); if (result != ISC_R_SUCCESS) goto cleanup; dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); result = isc_task_create(ns_g_taskmgr, 0, &task); if (result != ISC_R_SUCCESS) goto cleanup; isc_task_setname(task, "statchannel", NULL); result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(addr), isc_sockettype_tcp, &sock); if (result != ISC_R_SUCCESS) goto cleanup; isc_socket_setname(sock, "statchannel", NULL); #ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(sock, ISC_TRUE); #endif result = isc_socket_bind(sock, addr, ISC_SOCKET_REUSEADDRESS); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_httpdmgr_create(server->mctx, sock, task, client_ok, destroy_listener, listener, ns_g_timermgr, &listener->httpdmgr); if (result != ISC_R_SUCCESS) goto cleanup; #ifdef HAVE_LIBXML2 isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server); #endif isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl, server); *listenerp = listener; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_NOTICE, "statistics channel listening on %s", socktext); cleanup: if (result != ISC_R_SUCCESS) { if (listener->acl != NULL) dns_acl_detach(&listener->acl); DESTROYLOCK(&listener->lock); isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener)); } if (task != NULL) isc_task_detach(&task); if (sock != NULL) isc_socket_detach(&sock); return (result); }
/*% * Parse the zone update-policy statement. */ static isc_result_t configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone, const char *zname) { const cfg_obj_t *updatepolicy = NULL; const cfg_listelt_t *element, *element2; dns_ssutable_t *table = NULL; isc_mem_t *mctx = dns_zone_getmctx(zone); isc_boolean_t autoddns = ISC_FALSE; isc_result_t result; (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); if (updatepolicy == NULL) { dns_zone_setssutable(zone, NULL); return (ISC_R_SUCCESS); } if (cfg_obj_isstring(updatepolicy) && strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) { autoddns = ISC_TRUE; updatepolicy = NULL; } result = dns_ssutable_create(mctx, &table); if (result != ISC_R_SUCCESS) return (result); for (element = cfg_list_first(updatepolicy); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *stmt = cfg_listelt_value(element); const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); const char *str; isc_boolean_t grant = ISC_FALSE; isc_boolean_t usezone = ISC_FALSE; unsigned int mtype = DNS_SSUMATCHTYPE_NAME; dns_fixedname_t fname, fident; isc_buffer_t b; dns_rdatatype_t *types; unsigned int i, n; str = cfg_obj_asstring(mode); if (strcasecmp(str, "grant") == 0) grant = ISC_TRUE; else if (strcasecmp(str, "deny") == 0) grant = ISC_FALSE; else INSIST(0); str = cfg_obj_asstring(matchtype); if (strcasecmp(str, "name") == 0) mtype = DNS_SSUMATCHTYPE_NAME; else if (strcasecmp(str, "subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; else if (strcasecmp(str, "wildcard") == 0) mtype = DNS_SSUMATCHTYPE_WILDCARD; else if (strcasecmp(str, "self") == 0) mtype = DNS_SSUMATCHTYPE_SELF; else if (strcasecmp(str, "selfsub") == 0) mtype = DNS_SSUMATCHTYPE_SELFSUB; else if (strcasecmp(str, "selfwild") == 0) mtype = DNS_SSUMATCHTYPE_SELFWILD; else if (strcasecmp(str, "ms-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFMS; else if (strcasecmp(str, "krb5-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFKRB5; else if (strcasecmp(str, "ms-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS; else if (strcasecmp(str, "krb5-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5; else if (strcasecmp(str, "tcp-self") == 0) mtype = DNS_SSUMATCHTYPE_TCPSELF; else if (strcasecmp(str, "6to4-self") == 0) mtype = DNS_SSUMATCHTYPE_6TO4SELF; else if (strcasecmp(str, "zonesub") == 0) { mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; usezone = ISC_TRUE; } else if (strcasecmp(str, "external") == 0) mtype = DNS_SSUMATCHTYPE_EXTERNAL; else INSIST(0); dns_fixedname_init(&fident); str = cfg_obj_asstring(identity); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fident), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } dns_fixedname_init(&fname); if (usezone) { result = dns_name_copy(dns_zone_getorigin(zone), dns_fixedname_name(&fname), NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "error copying origin: %s", isc_result_totext(result)); goto cleanup; } } else { str = cfg_obj_asstring(dname); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } } n = ns_config_listcount(typelist); if (n == 0) types = NULL; else { types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t)); if (types == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } i = 0; for (element2 = cfg_list_first(typelist); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *typeobj; isc_textregion_t r; INSIST(i < n); typeobj = cfg_listelt_value(element2); str = cfg_obj_asstring(typeobj); DE_CONST(str, r.base); r.length = strlen(str); result = dns_rdatatype_fromtext(&types[i++], &r); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid type", str); isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); goto cleanup; } } INSIST(i == n); result = dns_ssutable_addrule(table, grant, dns_fixedname_name(&fident), mtype, dns_fixedname_name(&fname), n, types); if (types != NULL) isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); if (result != ISC_R_SUCCESS) { goto cleanup; } } /* * If "update-policy local;" and a session key exists, * then use the default policy, which is equivalent to: * update-policy { grant <session-keyname> zonesub any; }; */ if (autoddns) { dns_rdatatype_t any = dns_rdatatype_any; if (ns_g_server->session_keyname == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "failed to enable auto DDNS policy " "for zone %s: session key not found", zname); result = ISC_R_NOTFOUND; goto cleanup; } result = dns_ssutable_addrule(table, ISC_TRUE, ns_g_server->session_keyname, DNS_SSUMATCHTYPE_SUBDOMAIN, dns_zone_getorigin(zone), 1, &any); if (result != ISC_R_SUCCESS) goto cleanup; } result = ISC_R_SUCCESS; dns_zone_setssutable(zone, table); cleanup: dns_ssutable_detach(&table); return (result); }
isc_result_t ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, dns_zone_t *zone) { isc_result_t result; const char *zname; dns_rdataclass_t zclass; dns_rdataclass_t vclass; const cfg_obj_t *maps[5]; const cfg_obj_t *zoptions = NULL; const cfg_obj_t *options = NULL; const cfg_obj_t *obj; const char *filename = NULL; dns_notifytype_t notifytype = dns_notifytype_yes; isc_sockaddr_t *addrs; dns_name_t **keynames; isc_uint32_t count; char *cpval; unsigned int dbargc; char **dbargv; static char default_dbtype[] = "rbt"; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_dialuptype_t dialup = dns_dialuptype_no; dns_zonetype_t ztype; int i; isc_int32_t journal_size; isc_boolean_t multi; isc_boolean_t alt; dns_view_t *view; isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE; isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE; isc_boolean_t ixfrdiff; dns_masterformat_t masterformat; isc_stats_t *zoneqrystats; isc_boolean_t zonestats_on; int seconds; i = 0; if (zconfig != NULL) { zoptions = cfg_tuple_get(zconfig, "options"); maps[i++] = zoptions; } if (vconfig != NULL) maps[i++] = cfg_tuple_get(vconfig, "options"); if (config != NULL) { (void)cfg_map_get(config, "options", &options); if (options != NULL) maps[i++] = options; } maps[i++] = ns_g_defaults; maps[i] = NULL; if (vconfig != NULL) RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"), dns_rdataclass_in, &vclass)); else vclass = dns_rdataclass_in; /* * Configure values common to all zone types. */ zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"), vclass, &zclass)); dns_zone_setclass(zone, zclass); ztype = zonetype_fromconfig(zoptions); dns_zone_settype(zone, ztype); obj = NULL; result = cfg_map_get(zoptions, "database", &obj); if (result == ISC_R_SUCCESS) cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); else cpval = default_dbtype; if (cpval == NULL) return(ISC_R_NOMEMORY); result = strtoargv(mctx, cpval, &dbargc, &dbargv); if (result != ISC_R_SUCCESS && cpval != default_dbtype) { isc_mem_free(mctx, cpval); return (result); } /* * ANSI C is strange here. There is no logical reason why (char **) * cannot be promoted automatically to (const char * const *) by the * compiler w/o generating a warning. */ result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv); isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); if (cpval != default_dbtype) isc_mem_free(mctx, cpval); if (result != ISC_R_SUCCESS) return (result); obj = NULL; result = cfg_map_get(zoptions, "file", &obj); if (result == ISC_R_SUCCESS) filename = cfg_obj_asstring(obj); /* * Unless we're using some alternative database, a master zone * will be needing a master file. */ if (ztype == dns_zone_master && cpval == default_dbtype && filename == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "zone '%s': 'file' not specified", zname); return (ISC_R_FAILURE); } masterformat = dns_masterformat_text; obj = NULL; result= ns_config_get(maps, "masterfile-format", &obj); if (result == ISC_R_SUCCESS) { const char *masterformatstr = cfg_obj_asstring(obj); if (strcasecmp(masterformatstr, "text") == 0) masterformat = dns_masterformat_text; else if (strcasecmp(masterformatstr, "raw") == 0) masterformat = dns_masterformat_raw; else INSIST(0); } RETERR(dns_zone_setfile2(zone, filename, masterformat)); obj = NULL; result = cfg_map_get(zoptions, "journal", &obj); if (result == ISC_R_SUCCESS) RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj))); if (ztype == dns_zone_slave) RETERR(configure_zone_acl(zconfig, vconfig, config, allow_notify, ac, zone, dns_zone_setnotifyacl, dns_zone_clearnotifyacl)); /* * XXXAG This probably does not make sense for stubs. */ RETERR(configure_zone_acl(zconfig, vconfig, config, allow_query, ac, zone, dns_zone_setqueryacl, dns_zone_clearqueryacl)); obj = NULL; result = ns_config_get(maps, "dialup", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) dialup = dns_dialuptype_yes; else dialup = dns_dialuptype_no; } else { const char *dialupstr = cfg_obj_asstring(obj); if (strcasecmp(dialupstr, "notify") == 0) dialup = dns_dialuptype_notify; else if (strcasecmp(dialupstr, "notify-passive") == 0) dialup = dns_dialuptype_notifypassive; else if (strcasecmp(dialupstr, "refresh") == 0) dialup = dns_dialuptype_refresh; else if (strcasecmp(dialupstr, "passive") == 0) dialup = dns_dialuptype_passive; else INSIST(0); } dns_zone_setdialup(zone, dialup); obj = NULL; result = ns_config_get(maps, "zone-statistics", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); zonestats_on = cfg_obj_asboolean(obj); zoneqrystats = NULL; if (zonestats_on) { RETERR(isc_stats_create(mctx, &zoneqrystats, dns_nsstatscounter_max)); } dns_zone_setrequeststats(zone, zoneqrystats); if (zoneqrystats != NULL) isc_stats_detach(&zoneqrystats); /* * Configure master functionality. This applies * to primary masters (type "master") and slaves * acting as masters (type "slave"), but not to stubs. */ if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) { obj = NULL; result = ns_config_get(maps, "notify", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) notifytype = dns_notifytype_yes; else notifytype = dns_notifytype_no; } else { const char *notifystr = cfg_obj_asstring(obj); if (strcasecmp(notifystr, "explicit") == 0) notifytype = dns_notifytype_explicit; else if (strcasecmp(notifystr, "master-only") == 0) notifytype = dns_notifytype_masteronly; else INSIST(0); } dns_zone_setnotifytype(zone, notifytype); obj = NULL; result = ns_config_get(maps, "also-notify", &obj); if (result == ISC_R_SUCCESS) { isc_sockaddr_t *addrs = NULL; isc_uint32_t addrcount; result = ns_config_getiplist(config, obj, 0, mctx, &addrs, &addrcount); if (result != ISC_R_SUCCESS) return (result); result = dns_zone_setalsonotify(zone, addrs, addrcount); ns_config_putiplist(mctx, &addrs, addrcount); if (result != ISC_R_SUCCESS) return (result); } else RETERR(dns_zone_setalsonotify(zone, NULL, 0)); obj = NULL; result = ns_config_get(maps, "notify-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-to-soa", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA, cfg_obj_asboolean(obj)); dns_zone_setisself(zone, ns_client_isself, NULL); RETERR(configure_zone_acl(zconfig, vconfig, config, allow_transfer, ac, zone, dns_zone_setxfracl, dns_zone_clearxfracl)); obj = NULL; result = ns_config_get(maps, "max-transfer-time-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-journal-size", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setjournalsize(zone, -1); if (cfg_obj_isstring(obj)) { const char *str = cfg_obj_asstring(obj); INSIST(strcasecmp(str, "unlimited") == 0); journal_size = ISC_UINT32_MAX / 2; } else { isc_resourcevalue_t value; value = cfg_obj_asuint64(obj); if (value > ISC_UINT32_MAX / 2) { cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "'max-journal-size " "%" ISC_PRINT_QUADFORMAT "d' " "is too large", value); RETERR(ISC_R_RANGE); } journal_size = (isc_uint32_t)value; } dns_zone_setjournalsize(zone, journal_size); obj = NULL; result = ns_config_get(maps, "ixfr-from-differences", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) ixfrdiff = cfg_obj_asboolean(obj); else if (!strcasecmp(cfg_obj_asstring(obj), "master") && ztype == dns_zone_master) ixfrdiff = ISC_TRUE; else if (!strcasecmp(cfg_obj_asstring(obj), "slave") && ztype == dns_zone_slave) ixfrdiff = ISC_TRUE; else ixfrdiff = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff); checknames(ztype, maps, &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail); obj = NULL; result = ns_config_get(maps, "notify-delay", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "check-sibling", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "zero-no-soa-ttl", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "nsec3-test-zone", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE, cfg_obj_asboolean(obj)); } /* * Configure update-related options. These apply to * primary masters only. */ if (ztype == dns_zone_master) { dns_acl_t *updateacl; RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update, ac, zone, dns_zone_setupdateacl, dns_zone_clearupdateacl)); updateacl = dns_zone_getupdateacl(zone); if (updateacl != NULL && dns_acl_isinsecure(updateacl)) isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "zone '%s' allows updates by IP " "address, which is insecure", zname); RETERR(configure_zone_ssutable(zoptions, zone, zname)); obj = NULL; result = ns_config_get(maps, "sig-validity-interval", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); { const cfg_obj_t *validity, *resign; validity = cfg_tuple_get(obj, "validity"); seconds = cfg_obj_asuint32(validity) * 86400; dns_zone_setsigvalidityinterval(zone, seconds); resign = cfg_tuple_get(obj, "re-sign"); if (cfg_obj_isvoid(resign)) { seconds /= 4; } else { if (seconds > 7 * 86400) seconds = cfg_obj_asuint32(resign) * 86400; else seconds = cfg_obj_asuint32(resign) * 3600; } dns_zone_setsigresigninginterval(zone, seconds); } obj = NULL; result = ns_config_get(maps, "key-directory", &obj); if (result == ISC_R_SUCCESS) { filename = cfg_obj_asstring(obj); RETERR(dns_zone_setkeydirectory(zone, filename)); } obj = NULL; result = ns_config_get(maps, "sig-signing-signatures", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setsignatures(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-nodes", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setnodes(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-type", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "update-check-ksk", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY, cfg_obj_asboolean(obj)); } else if (ztype == dns_zone_slave) { RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update_forwarding, ac, zone, dns_zone_setforwardacl, dns_zone_clearforwardacl)); } /*% * Primary master functionality. */ if (ztype == dns_zone_master) { isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE; obj = NULL; result = ns_config_get(maps, "check-wildcard", &obj); if (result == ISC_R_SUCCESS) check = cfg_obj_asboolean(obj); else check = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check); obj = NULL; result = ns_config_get(maps, "check-dup-records", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail); obj = NULL; result = ns_config_get(maps, "check-mx", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail); obj = NULL; result = ns_config_get(maps, "check-integrity", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "check-mx-cname", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore); obj = NULL; result = ns_config_get(maps, "check-srv-cname", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore); obj = NULL; result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE, cfg_obj_asboolean(obj)); obj = NULL; result = cfg_map_get(zoptions, "auto-dnssec", &obj); if (result == ISC_R_SUCCESS) { const char *arg = cfg_obj_asstring(obj); if (strcasecmp(arg, "allow") == 0) allow = ISC_TRUE; else if (strcasecmp(arg, "maintain") == 0) allow = maint = ISC_TRUE; else if (strcasecmp(arg, "off") == 0) ; else INSIST(0); dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow); dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint); } } /* * Configure slave functionality. */ switch (ztype) { case dns_zone_slave: case dns_zone_stub: count = 0; obj = NULL; (void)cfg_map_get(zoptions, "masters", &obj); if (obj != NULL) { addrs = NULL; keynames = NULL; RETERR(ns_config_getipandkeylist(config, obj, mctx, &addrs, &keynames, &count)); result = dns_zone_setmasterswithkeys(zone, addrs, keynames, count); ns_config_putipandkeylist(mctx, &addrs, &keynames, count); } else result = dns_zone_setmasters(zone, NULL, 0); RETERR(result); multi = ISC_FALSE; if (count > 1) { obj = NULL; result = ns_config_get(maps, "multi-master", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); multi = cfg_obj_asboolean(obj); } dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi); obj = NULL; result = ns_config_get(maps, "max-transfer-time-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "max-retry-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-retry-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "alt-transfer-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj))); obj = NULL; result = ns_config_get(maps, "alt-transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj))); obj = NULL; (void)ns_config_get(maps, "use-alt-transfer-source", &obj); if (obj == NULL) { /* * Default off when views are in use otherwise * on for BIND 8 compatibility. */ view = dns_zone_getview(zone); if (view != NULL && strcmp(view->name, "_default") == 0) alt = ISC_TRUE; else alt = ISC_FALSE; } else alt = cfg_obj_asboolean(obj); dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt); obj = NULL; (void)ns_config_get(maps, "try-tcp-refresh", &obj); dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH, cfg_obj_asboolean(obj)); break; case dns_zone_staticstub: RETERR(configure_staticstub(zoptions, zone, zname, default_dbtype)); break; default: break; } return (ISC_R_SUCCESS); }
void dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_ns_t ns; dns_rdataset_t hintns, rootns; const char *viewname = "", *sep = ""; isc_stdtime_t now; dns_name_t *name; dns_fixedname_t fixed; REQUIRE(hints != NULL); REQUIRE(db != NULL); REQUIRE(view != NULL); isc_stdtime_get(&now); if (strcmp(view->name, "_bind") != 0 && strcmp(view->name, "_default") != 0) { viewname = view->name; sep = ": view "; } dns_rdataset_init(&hintns); dns_rdataset_init(&rootns); dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0, now, NULL, name, &hintns, NULL); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to get root NS rrset " "from hints: %s", sep, viewname, dns_result_totext(result)); goto cleanup; } result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, now, NULL, name, &rootns, NULL); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to get root NS rrset " "from cache: %s", sep, viewname, dns_result_totext(result)); goto cleanup; } /* * Look for missing root NS names. */ result = dns_rdataset_first(&rootns); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&rootns, &rdata); result = dns_rdata_tostruct(&rdata, &ns, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); result = in_rootns(&hintns, &ns.name); if (result != ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; /* missing from hints */ dns_name_format(&ns.name, namebuf, sizeof(namebuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: unable to find root " "NS '%s' in hints", sep, viewname, namebuf); } else check_address_records(view, hints, db, &ns.name, now); dns_rdata_reset(&rdata); result = dns_rdataset_next(&rootns); } if (result != ISC_R_NOMORE) { goto cleanup; } /* * Look for extra root NS names. */ result = dns_rdataset_first(&hintns); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&hintns, &rdata); result = dns_rdata_tostruct(&rdata, &ns, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); result = in_rootns(&rootns, &ns.name); if (result != ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; /* extra entry in hints */ dns_name_format(&ns.name, namebuf, sizeof(namebuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "checkhints%s%s: extra NS '%s' in hints", sep, viewname, namebuf); } dns_rdata_reset(&rdata); result = dns_rdataset_next(&hintns); } if (result != ISC_R_NOMORE) { goto cleanup; } cleanup: if (dns_rdataset_isassociated(&rootns)) dns_rdataset_disassociate(&rootns); if (dns_rdataset_isassociated(&hintns)) dns_rdataset_disassociate(&hintns); }
isc_result_t dns_diff_load (dns_diff_t * diff, dns_addrdatasetfunc_t addfunc, void *add_private) { dns_difftuple_t *t; isc_result_t result; REQUIRE (DNS_DIFF_VALID (diff)); t = ISC_LIST_HEAD (diff->tuples); while (t != NULL) { dns_name_t *name; name = &t->name; while (t != NULL && dns_name_equal (&t->name, name)) { dns_rdatatype_t type, covers; dns_diffop_t op; dns_rdatalist_t rdl; dns_rdataset_t rds; op = t->op; type = t->rdata.type; covers = rdata_covers (&t->rdata); rdl.type = type; rdl.covers = covers; rdl.rdclass = t->rdata.rdclass; rdl.ttl = t->ttl; ISC_LIST_INIT (rdl.rdata); ISC_LINK_INIT (&rdl, link); while (t != NULL && dns_name_equal (&t->name, name) && t->op == op && t->rdata.type == type && rdata_covers (&t->rdata) == covers) { ISC_LIST_APPEND (rdl.rdata, &t->rdata, link); t = ISC_LIST_NEXT (t, link); } /* * Convert the rdatalist into a rdataset. */ dns_rdataset_init (&rds); CHECK (dns_rdatalist_tordataset (&rdl, &rds)); rds.trust = dns_trust_ultimate; INSIST (op == DNS_DIFFOP_ADD); result = (*addfunc) (add_private, name, &rds); if (result == DNS_R_UNCHANGED) { isc_log_write (DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "dns_diff_load: " "update with no effect"); } else if (result == ISC_R_SUCCESS || result == DNS_R_NXRRSET) { /* * OK. */ } else { CHECK (result); } } } result = ISC_R_SUCCESS; failure: return (result); }
/*% * This function is called to process the incoming command * when a control channel message is received. */ isc_result_t ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { isccc_sexpr_t *data; char *command; isc_result_t result; int log_level; #ifdef HAVE_LIBSCF ns_smf_want_disable = 0; #endif data = isccc_alist_lookup(message, "_data"); if (data == NULL) { /* * No data section. */ return (ISC_R_FAILURE); } result = isccc_cc_lookupstring(data, "type", &command); if (result != ISC_R_SUCCESS) { /* * We have no idea what this is. */ return (result); } /* * Compare the 'command' parameter against all known control commands. */ if (command_compare(command, NS_COMMAND_NULL) || command_compare(command, NS_COMMAND_STATUS)) { log_level = ISC_LOG_DEBUG(1); } else { log_level = ISC_LOG_INFO; } isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, log_level, "received control channel command '%s'", command); if (command_compare(command, NS_COMMAND_RELOAD)) { result = ns_server_reloadcommand(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_RECONFIG)) { result = ns_server_reconfigcommand(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_REFRESH)) { result = ns_server_refreshcommand(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_RETRANSFER)) { result = ns_server_retransfercommand(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_HALT)) { #ifdef HAVE_LIBSCF /* * If we are managed by smf(5), AND in chroot, then * we cannot connect to the smf repository, so just * return with an appropriate message back to rndc. */ if (ns_smf_got_instance == 1 && ns_smf_chroot == 1) { result = ns_smf_add_message(text); return (result); } /* * If we are managed by smf(5) but not in chroot, * try to disable ourselves the smf way. */ if (ns_smf_got_instance == 1 && ns_smf_chroot == 0) ns_smf_want_disable = 1; /* * If ns_smf_got_instance = 0, ns_smf_chroot * is not relevant and we fall through to * isc_app_shutdown below. */ #endif /* Do not flush master files */ ns_server_flushonshutdown(ns_g_server, ISC_FALSE); ns_os_shutdownmsg(command, text); isc_app_shutdown(); result = ISC_R_SUCCESS; } else if (command_compare(command, NS_COMMAND_STOP)) { /* * "stop" is the same as "halt" except it does * flush master files. */ #ifdef HAVE_LIBSCF if (ns_smf_got_instance == 1 && ns_smf_chroot == 1) { result = ns_smf_add_message(text); return (result); } if (ns_smf_got_instance == 1 && ns_smf_chroot == 0) ns_smf_want_disable = 1; #endif ns_server_flushonshutdown(ns_g_server, ISC_TRUE); ns_os_shutdownmsg(command, text); isc_app_shutdown(); result = ISC_R_SUCCESS; } else if (command_compare(command, NS_COMMAND_DUMPSTATS)) { result = ns_server_dumpstats(ns_g_server); } else if (command_compare(command, NS_COMMAND_QUERYLOG)) { result = ns_server_togglequerylog(ns_g_server); } else if (command_compare(command, NS_COMMAND_DUMPDB)) { ns_server_dumpdb(ns_g_server, command); result = ISC_R_SUCCESS; } else if (command_compare(command, NS_COMMAND_SECROOTS)) { result = ns_server_dumpsecroots(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_TRACE)) { result = ns_server_setdebuglevel(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_NOTRACE)) { ns_g_debuglevel = 0; isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); result = ISC_R_SUCCESS; } else if (command_compare(command, NS_COMMAND_FLUSH)) { result = ns_server_flushcache(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_FLUSHNAME)) { result = ns_server_flushname(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_STATUS)) { result = ns_server_status(ns_g_server, text); } else if (command_compare(command, NS_COMMAND_TSIGLIST)) { result = ns_server_tsiglist(ns_g_server, text); } else if (command_compare(command, NS_COMMAND_TSIGDELETE)) { result = ns_server_tsigdelete(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_FREEZE)) { result = ns_server_freeze(ns_g_server, ISC_TRUE, command, text); } else if (command_compare(command, NS_COMMAND_UNFREEZE) || command_compare(command, NS_COMMAND_THAW)) { result = ns_server_freeze(ns_g_server, ISC_FALSE, command, text); } else if (command_compare(command, NS_COMMAND_RECURSING)) { result = ns_server_dumprecursing(ns_g_server); } else if (command_compare(command, NS_COMMAND_TIMERPOKE)) { result = ISC_R_SUCCESS; isc_timermgr_poke(ns_g_timermgr); } else if (command_compare(command, NS_COMMAND_NULL)) { result = ISC_R_SUCCESS; } else if (command_compare(command, NS_COMMAND_NOTIFY)) { result = ns_server_notifycommand(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_VALIDATION)) { result = ns_server_validation(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_SIGN) || command_compare(command, NS_COMMAND_LOADKEYS)) { result = ns_server_rekey(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_ADDZONE)) { result = ns_server_add_zone(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_DELZONE)) { result = ns_server_del_zone(ns_g_server, command); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, "unknown control channel command '%s'", command); result = DNS_R_UNKNOWNCOMMAND; } return (result); }
isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, dns_name_t *creator, isc_stdtime_t inception, isc_stdtime_t expire, isc_mem_t *mctx, dns_tsig_keyring_t *ring, dns_tsigkey_t **key) { dns_tsigkey_t *tkey; isc_result_t ret; unsigned int refs = 0; REQUIRE(key == NULL || *key == NULL); REQUIRE(name != NULL); REQUIRE(algorithm != NULL); REQUIRE(mctx != NULL); REQUIRE(key != NULL || ring != NULL); tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t)); if (tkey == NULL) return (ISC_R_NOMEMORY); dns_name_init(&tkey->name, NULL); ret = dns_name_dup(name, mctx, &tkey->name); if (ret != ISC_R_SUCCESS) goto cleanup_key; (void)dns_name_downcase(&tkey->name, &tkey->name, NULL); if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { tkey->algorithm = DNS_TSIG_HMACMD5_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA1_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA224_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA224) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA256_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA256) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA384_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA384) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { tkey->algorithm = DNS_TSIG_HMACSHA512_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA512) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPI_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME; if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) { ret = DNS_R_BADALG; goto cleanup_name; } } else { if (dstkey != NULL) { ret = DNS_R_BADALG; goto cleanup_name; } tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->algorithm == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_name; } dns_name_init(tkey->algorithm, NULL); ret = dns_name_dup(algorithm, mctx, tkey->algorithm); if (ret != ISC_R_SUCCESS) goto cleanup_algorithm; (void)dns_name_downcase(tkey->algorithm, tkey->algorithm, NULL); } if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); if (tkey->creator == NULL) { ret = ISC_R_NOMEMORY; goto cleanup_algorithm; } dns_name_init(tkey->creator, NULL); ret = dns_name_dup(creator, mctx, tkey->creator); if (ret != ISC_R_SUCCESS) { isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); goto cleanup_algorithm; } } else tkey->creator = NULL; tkey->key = NULL; if (dstkey != NULL) dst_key_attach(dstkey, &tkey->key); tkey->ring = ring; if (key != NULL) refs = 1; if (ring != NULL) refs++; ret = isc_refcount_init(&tkey->refs, refs); if (ret != ISC_R_SUCCESS) goto cleanup_creator; tkey->generated = generated; tkey->inception = inception; tkey->expire = expire; tkey->mctx = NULL; isc_mem_attach(mctx, &tkey->mctx); tkey->magic = TSIG_MAGIC; if (ring != NULL) { ret = keyring_add(ring, name, tkey); if (ret != ISC_R_SUCCESS) goto cleanup_refs; } /* * Ignore this if it's a GSS key, since the key size is meaningless. */ if (dstkey != NULL && dst_key_size(dstkey) < 64 && !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, ISC_LOG_INFO, "the key '%s' is too short to be secure", namestr); } if (key != NULL) *key = tkey; return (ISC_R_SUCCESS); cleanup_refs: tkey->magic = 0; while (refs-- > 0) isc_refcount_decrement(&tkey->refs, NULL); isc_refcount_destroy(&tkey->refs); cleanup_creator: if (tkey->key != NULL) dst_key_free(&tkey->key); if (tkey->creator != NULL) { dns_name_free(tkey->creator, mctx); isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t)); } cleanup_algorithm: if (algname_is_allocated(tkey->algorithm)) { if (dns_name_dynamic(tkey->algorithm)) dns_name_free(tkey->algorithm, mctx); isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t)); } cleanup_name: dns_name_free(&tkey->name, mctx); cleanup_key: isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t)); return (ret); }
static isc_result_t odbc_connect(odbc_instance_t *dbi, odbc_db_t **dbc) { odbc_db_t *ndb = *dbc; SQLRETURN sqlRes; isc_result_t result = ISC_R_SUCCESS; if (ndb != NULL) { /* * if db != null, we have to do some cleanup * if statement handle != null free it */ if (ndb->stmnt != NULL) { SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt); ndb->stmnt = NULL; } /* if connection handle != null free it */ if (ndb->dbc != NULL) { SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc); ndb->dbc = NULL; } } else { ndb = isc_mem_allocate(ns_g_mctx, sizeof(odbc_db_t)); if (ndb == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to allocate memory"); return ISC_R_NOMEMORY; } memset(ndb, 0, sizeof(odbc_db_t)); } sqlRes = SQLAllocHandle(SQL_HANDLE_DBC, dbi->sql_env, &(ndb->dbc)); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to allocate memory"); result = ISC_R_NOMEMORY; goto cleanup; } sqlRes = SQLConnect(ndb->dbc, dbi->dsn, safeLen(dbi->dsn), dbi->user, safeLen(dbi->user), dbi->pass, safeLen(dbi->pass)); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to connect"); result = ISC_R_FAILURE; goto cleanup; } sqlRes = SQLAllocHandle(SQL_HANDLE_STMT, ndb->dbc, &(ndb->stmnt)); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to allocate memory"); result = ISC_R_NOMEMORY; goto cleanup; } *dbc = ndb; return ISC_R_SUCCESS; cleanup: if (ndb != NULL) { /* if statement handle != null free it */ if (ndb->stmnt != NULL) { SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt); ndb->stmnt = NULL; } /* if connection handle != null free it */ if (ndb->dbc != NULL) { SQLDisconnect(ndb->dbc); SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc); ndb->dbc = NULL; } /* free memory holding ndb */ isc_mem_free(ns_g_mctx, ndb); } return result; }
static isc_result_t odbc_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, dbinstance_t **r_dbi) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int j = 0; SQLRETURN sqlRes; REQUIRE(*r_dbi == NULL); /* get db instance / connection */ #ifdef ISC_PLATFORM_USETHREADS /* find an available DBI from the list */ dbi = odbc_find_avail_conn(((odbc_instance_t *) dbdata)->db); #else /* ISC_PLATFORM_USETHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *) ((odbc_instance_t *) dbdata)->db; #endif /* ISC_PLATFORM_USETHREADS */ /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "odbc_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = odbc_escape_string(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = odbc_escape_string(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = odbc_escape_string(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } /* * what type of query are we going to run? * this time we build the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "odbc_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* output the full query string during debug so we can see */ /* what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (j=0; j < 3; j++) { /* try to get result set */ sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt, (SQLCHAR *) querystring, (SQLINTEGER) strlen(querystring)); /* if error, reset DB connection */ if (!sqlOK(sqlRes)) { /* close cursor */ SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt); /* attempt to reconnect */ result = odbc_connect((odbc_instance_t *) dbdata, (odbc_db_t **) &(dbi->dbconn)); /* check if we reconnected */ if (result != ISC_R_SUCCESS) break; /* incase this is the last time through the loop */ result = ISC_R_FAILURE; } else { result = ISC_R_SUCCESS; /* return dbi */ *r_dbi = dbi; /* result set ok, break loop */ break; } } /* end for loop */ cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even allocate DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); #ifdef ISC_PLATFORM_USETHREADS /* if we are done using this dbi, release the lock */ if (result != ISC_R_SUCCESS) isc_mutex_unlock(&dbi->instance_lock); #endif /* ISC_PLATFORM_USETHREADS */ /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring ); /* return result */ return result; }
static isc_result_t odbc_allnodes(const char *zone, void *driverarg, void *dbdata, dns_sdlzallnodes_t *allnodes) { isc_result_t result; dbinstance_t *dbi = NULL; SQLHSTMT *stmnt; SQLSMALLINT fields; char *data; char *type; char *ttl_s; int ttl; char *host; char *endp; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = odbc_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &dbi); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to return " "result set for all nodes query"); return (ISC_R_FAILURE); } stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt; /* get number of columns */ if (!sqlOK(SQLNumResultCols(stmnt, &fields))) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to process result set"); result = ISC_R_FAILURE; goto allnodes_cleanup; } if (fields < 4) { /* gotta have at least 4 columns */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver too few fields returned by " "all nodes query"); result = ISC_R_FAILURE; goto allnodes_cleanup; } /* get things ready for processing */ result = ISC_R_FAILURE; while (sqlOK(SQLFetch(stmnt))) { /* set to null for next pass through */ data = host = type = ttl_s = NULL; /* * attempt to get DNS ttl, type, host, data then tell * Bind about them */ if ((result = odbc_getField(stmnt, 1, &ttl_s)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 2, &type)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 3, &host)) == ISC_R_SUCCESS && (result = odbc_getManyFields(stmnt, 4, fields, &data)) == ISC_R_SUCCESS) { /* convert ttl string to int */ ttl = strtol(ttl_s, &endp, 10); /* failure converting ttl. */ if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver ttl must be " "a postive number"); result = ISC_R_FAILURE; } else { /* successful converting TTL, tell Bind */ result = dns_sdlz_putnamedrr(allnodes, host, type, ttl, data); } } /* closes big if () */ /* clean up mem */ if (ttl_s != NULL) isc_mem_free(ns_g_mctx, ttl_s); if (type != NULL) isc_mem_free(ns_g_mctx, type); if (host != NULL) isc_mem_free(ns_g_mctx, host); if (data != NULL) isc_mem_free(ns_g_mctx, data); /* if we weren't successful, log err msg */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putnamedrr returned error. " "Error code was: %s", isc_result_totext(result)); result = ISC_R_FAILURE; goto allnodes_cleanup; } } /* closes while loop */ allnodes_cleanup: /* close cursor */ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt); #ifdef ISC_PLATFORM_USETHREADS /* free lock on dbi so someone else can use it. */ isc_mutex_unlock(&dbi->instance_lock); #endif return result; }
/*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */ static isc_result_t odbc_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata) { isc_result_t result; odbc_instance_t *odbc_inst = NULL; dbinstance_t *db = NULL; SQLRETURN sqlRes; #ifdef ISC_PLATFORM_USETHREADS /* if multi-threaded, we need a few extra variables. */ int dbcount; int i; char *endp; #endif /* ISC_PLATFORM_USETHREADS */ UNUSED(dlzname); UNUSED(driverarg); #ifdef ISC_PLATFORM_USETHREADS /* if debugging, let user know we are multithreaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Odbc driver running multithreaded"); #else /* ISC_PLATFORM_USETHREADS */ /* if debugging, let user know we are single threaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Odbc driver running single threaded"); #endif /* ISC_PLATFORM_USETHREADS */ /* verify we have at least 5 arg's passed to the driver */ if (argc < 5) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver requires at least " "4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the driver */ if (argc > 8) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver cannot accept more than " "7 command line args."); return (ISC_R_FAILURE); } /* multithreaded build can have multiple DB connections */ #ifdef ISC_PLATFORM_USETHREADS /* check how many db connections we should create */ dbcount = strtol(argv[1], &endp, 10); if (*endp != '\0' || dbcount < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver database connection count " "must be positive."); return (ISC_R_FAILURE); } #endif /* ISC_PLATFORM_USETHREADS */ /* allocate memory for odbc instance */ odbc_inst = isc_mem_get(ns_g_mctx, sizeof(odbc_instance_t)); if (odbc_inst == NULL) return (ISC_R_NOMEMORY); memset(odbc_inst, 0, sizeof(odbc_instance_t)); /* parse connection string and get paramters. */ /* get odbc database dsn - required */ odbc_inst->dsn = (SQLCHAR *) getParameterValue(argv[2], "dsn="); if (odbc_inst->dsn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "odbc driver requires a dns parameter."); result = ISC_R_FAILURE; goto cleanup; } /* get odbc database username */ /* if no username was passed, set odbc_inst.user = NULL; */ odbc_inst->user = (SQLCHAR *) getParameterValue(argv[2], "user="******"pass="******"Odbc driver unable to allocate memory"); result = ISC_R_NOMEMORY; goto cleanup; } /*set ODBC version = 3 */ sqlRes = SQLSetEnvAttr(odbc_inst->sql_env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_INFO, "Unable to configure ODBC environment"); result = ISC_R_NOMEMORY; goto cleanup; } } #ifdef ISC_PLATFORM_USETHREADS /* allocate memory for database connection list */ odbc_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t)); if (odbc_inst->db == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* initialize DB connection list */ ISC_LIST_INIT(*odbc_inst->db); /* create the appropriate number of database instances (DBI) */ /* append each new DBI to the end of the list */ for (i=0; i < dbcount; i++) { #endif /* ISC_PLATFORM_USETHREADS */ /* how many queries were passed in from config file? */ switch(argc) { case 5: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[3], argv[4], NULL, &db); break; case 6: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[5], argv[3], argv[4], NULL, &db); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[6], NULL, argv[5], argv[3], argv[4], NULL, &db); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[6], argv[7], argv[5], argv[3], argv[4], NULL, &db); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } /* unsuccessful?, log err msg and cleanup. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver could not create " "database instance object."); goto cleanup; } #ifdef ISC_PLATFORM_USETHREADS /* when multithreaded, build a list of DBI's */ ISC_LINK_INIT(db, link); ISC_LIST_APPEND(*odbc_inst->db, db, link); #endif result = odbc_connect(odbc_inst, (odbc_db_t **) &(db->dbconn)); if (result != ISC_R_SUCCESS) { #ifdef ISC_PLATFORM_USETHREADS /* * if multi threaded, let user know which * connection failed. user could be * attempting to create 10 db connections and * for some reason the db backend only allows * 9. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver failed to create database " "connection number %u after 3 attempts", i+1); #else isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver failed to create database " "connection after 3 attempts"); #endif goto cleanup; } #ifdef ISC_PLATFORM_USETHREADS /* set DB = null for next loop through. */ db = NULL; } /* end for loop */ #else /* tell odbc_inst about the db connection we just created. */ odbc_inst->db = db; #endif /* set dbdata to the odbc_instance we created. */ *dbdata = odbc_inst; /* hey, we got through all of that ok, return success. */ return(ISC_R_SUCCESS); cleanup: destroy_odbc_instance(odbc_inst); return result; }
static inline isc_result_t schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { isc_result_t result; isc__timermgr_t *manager; isc_time_t due; int cmp; #ifdef USE_TIMER_THREAD isc_boolean_t timedwait; #endif /*! * Note: the caller must ensure locking. */ REQUIRE(timer->type != isc_timertype_inactive); #ifndef USE_TIMER_THREAD UNUSED(signal_ok); #endif /* USE_TIMER_THREAD */ manager = timer->manager; #ifdef USE_TIMER_THREAD /*! * If the manager was timed wait, we may need to signal the * manager to force a wakeup. */ timedwait = ISC_TF(manager->nscheduled > 0 && isc_time_seconds(&manager->due) != 0); #endif /* * Compute the new due time. */ if (timer->type != isc_timertype_once) { result = isc_time_add(now, &timer->interval, &due); if (result != ISC_R_SUCCESS) return (result); if (timer->type == isc_timertype_limited && isc_time_compare(&timer->expires, &due) < 0) due = timer->expires; } else { if (isc_time_isepoch(&timer->idle)) due = timer->expires; else if (isc_time_isepoch(&timer->expires)) due = timer->idle; else if (isc_time_compare(&timer->idle, &timer->expires) < 0) due = timer->idle; else due = timer->expires; } /* * Schedule the timer. */ if (timer->index > 0) { /* * Already scheduled. */ cmp = isc_time_compare(&due, &timer->due); timer->due = due; switch (cmp) { case -1: isc_heap_increased(manager->heap, timer->index); break; case 1: isc_heap_decreased(manager->heap, timer->index); break; case 0: /* Nothing to do. */ break; } } else { timer->due = due; result = isc_heap_insert(manager->heap, timer); if (result != ISC_R_SUCCESS) { INSIST(result == ISC_R_NOMEMORY); return (ISC_R_NOMEMORY); } manager->nscheduled++; } XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SCHEDULE, "schedule"), timer, due); /* * If this timer is at the head of the queue, we need to ensure * that we won't miss it if it has a more recent due time than * the current "next" timer. We do this either by waking up the * run thread, or explicitly setting the value in the manager. */ #ifdef USE_TIMER_THREAD /* * This is a temporary (probably) hack to fix a bug on tru64 5.1 * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually * return when the time expires, so here, we check to see if * we're 15 seconds or more behind, and if we are, we signal * the dispatcher. This isn't such a bad idea as a general purpose * watchdog, so perhaps we should just leave it in here. */ if (signal_ok && timedwait) { isc_interval_t fifteen; isc_time_t then; isc_interval_set(&fifteen, 15, 0); result = isc_time_add(&manager->due, &fifteen, &then); if (result == ISC_R_SUCCESS && isc_time_compare(&then, now) < 0) { SIGNAL(&manager->wakeup); signal_ok = ISC_FALSE; isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_TIMER, ISC_LOG_WARNING, "*** POKED TIMER ***"); } } if (timer->index == 1 && signal_ok) { XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALSCHED, "signal (schedule)")); SIGNAL(&manager->wakeup); } #else /* USE_TIMER_THREAD */ if (timer->index == 1 && isc_time_compare(&timer->due, &manager->due) < 0) manager->due = timer->due; #endif /* USE_TIMER_THREAD */ return (ISC_R_SUCCESS); }
/*% * This function is called to process the incoming command * when a control channel message is received. */ isc_result_t named_control_docommand(isccc_sexpr_t *message, isc_boolean_t readonly, isc_buffer_t **text) { isccc_sexpr_t *data; char *cmdline = NULL; char *command = NULL; isc_result_t result; int log_level; isc_buffer_t src; isc_lex_t *lex = NULL; #ifdef HAVE_LIBSCF named_smf_want_disable = 0; #endif data = isccc_alist_lookup(message, "_data"); if (!isccc_alist_alistp(data)) { /* * No data section. */ return (ISC_R_FAILURE); } result = isccc_cc_lookupstring(data, "type", &cmdline); if (result != ISC_R_SUCCESS) { /* * We have no idea what this is. */ return (result); } result = isc_lex_create(named_g_mctx, strlen(cmdline), &lex); if (result != ISC_R_SUCCESS) return (result); isc_buffer_init(&src, cmdline, strlen(cmdline)); isc_buffer_add(&src, strlen(cmdline)); result = isc_lex_openbuffer(lex, &src); if (result != ISC_R_SUCCESS) goto cleanup; result = getcommand(lex, &command); if (result != ISC_R_SUCCESS) goto cleanup; /* * Compare the 'command' parameter against all known control commands. */ if (command_compare(command, NAMED_COMMAND_NULL) || command_compare(command, NAMED_COMMAND_STATUS)) { log_level = ISC_LOG_DEBUG(1); } else { log_level = ISC_LOG_INFO; } /* * If this listener should have read-only access, reject * restricted commands here. rndc nta is handled specially * below. */ if (readonly && !command_compare(command, NAMED_COMMAND_NTA) && !command_compare(command, NAMED_COMMAND_NULL) && !command_compare(command, NAMED_COMMAND_STATUS) && !command_compare(command, NAMED_COMMAND_SHOWZONE) && !command_compare(command, NAMED_COMMAND_TESTGEN) && !command_compare(command, NAMED_COMMAND_ZONESTATUS)) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_CONTROL, log_level, "rejecting restricted control channel " "command '%s'", cmdline); result = ISC_R_FAILURE; goto cleanup; } isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_CONTROL, log_level, "received control channel command '%s'", cmdline); if (command_compare(command, NAMED_COMMAND_RELOAD)) { result = named_server_reloadcommand(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_RECONFIG)) { result = named_server_reconfigcommand(named_g_server); } else if (command_compare(command, NAMED_COMMAND_REFRESH)) { result = named_server_refreshcommand(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_RETRANSFER)) { result = named_server_retransfercommand(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_HALT)) { #ifdef HAVE_LIBSCF /* * If we are managed by smf(5), AND in chroot, then * we cannot connect to the smf repository, so just * return with an appropriate message back to rndc. */ if (named_smf_got_instance == 1 && named_smf_chroot == 1) { result = named_smf_add_message(text); goto cleanup; } /* * If we are managed by smf(5) but not in chroot, * try to disable ourselves the smf way. */ if (named_smf_got_instance == 1 && named_smf_chroot == 0) named_smf_want_disable = 1; /* * If named_smf_got_instance = 0, named_smf_chroot * is not relevant and we fall through to * isc_app_shutdown below. */ #endif /* Do not flush master files */ named_server_flushonshutdown(named_g_server, ISC_FALSE); named_os_shutdownmsg(cmdline, *text); isc_app_shutdown(); result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_STOP)) { /* * "stop" is the same as "halt" except it does * flush master files. */ #ifdef HAVE_LIBSCF if (named_smf_got_instance == 1 && named_smf_chroot == 1) { result = named_smf_add_message(text); goto cleanup; } if (named_smf_got_instance == 1 && named_smf_chroot == 0) named_smf_want_disable = 1; #endif named_server_flushonshutdown(named_g_server, ISC_TRUE); named_os_shutdownmsg(cmdline, *text); isc_app_shutdown(); result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_DUMPSTATS)) { result = named_server_dumpstats(named_g_server); } else if (command_compare(command, NAMED_COMMAND_QUERYLOG)) { result = named_server_togglequerylog(named_g_server, lex); } else if (command_compare(command, NAMED_COMMAND_DUMPDB)) { named_server_dumpdb(named_g_server, lex, text); result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_SECROOTS)) { result = named_server_dumpsecroots(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_TRACE)) { result = named_server_setdebuglevel(named_g_server, lex); } else if (command_compare(command, NAMED_COMMAND_NOTRACE)) { named_g_debuglevel = 0; isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel); result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_FLUSH)) { result = named_server_flushcache(named_g_server, lex); } else if (command_compare(command, NAMED_COMMAND_FLUSHNAME)) { result = named_server_flushnode(named_g_server, lex, ISC_FALSE); } else if (command_compare(command, NAMED_COMMAND_FLUSHTREE)) { result = named_server_flushnode(named_g_server, lex, ISC_TRUE); } else if (command_compare(command, NAMED_COMMAND_STATUS)) { result = named_server_status(named_g_server, text); } else if (command_compare(command, NAMED_COMMAND_TSIGLIST)) { result = named_server_tsiglist(named_g_server, text); } else if (command_compare(command, NAMED_COMMAND_TSIGDELETE)) { result = named_server_tsigdelete(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_FREEZE)) { result = named_server_freeze(named_g_server, ISC_TRUE, lex, text); } else if (command_compare(command, NAMED_COMMAND_UNFREEZE) || command_compare(command, NAMED_COMMAND_THAW)) { result = named_server_freeze(named_g_server, ISC_FALSE, lex, text); } else if (command_compare(command, NAMED_COMMAND_SCAN)) { result = ISC_R_SUCCESS; named_server_scan_interfaces(named_g_server); } else if (command_compare(command, NAMED_COMMAND_SYNC)) { result = named_server_sync(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_RECURSING)) { result = named_server_dumprecursing(named_g_server); } else if (command_compare(command, NAMED_COMMAND_TIMERPOKE)) { result = ISC_R_SUCCESS; isc_timermgr_poke(named_g_timermgr); } else if (command_compare(command, NAMED_COMMAND_NULL)) { result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_NOTIFY)) { result = named_server_notifycommand(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_VALIDATION)) { result = named_server_validation(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_SIGN) || command_compare(command, NAMED_COMMAND_LOADKEYS)) { result = named_server_rekey(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_ADDZONE) || command_compare(command, NAMED_COMMAND_MODZONE)) { result = named_server_changezone(named_g_server, cmdline, text); } else if (command_compare(command, NAMED_COMMAND_DELZONE)) { result = named_server_delzone(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_SHOWZONE)) { result = named_server_showzone(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_SIGNING)) { result = named_server_signing(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_ZONESTATUS)) { result = named_server_zonestatus(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_NTA)) { result = named_server_nta(named_g_server, lex, readonly, text); } else if (command_compare(command, NAMED_COMMAND_TESTGEN)) { result = named_server_testgen(lex, text); } else if (command_compare(command, NAMED_COMMAND_MKEYS)) { result = named_server_mkeys(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_DNSTAP) || command_compare(command, NAMED_COMMAND_DNSTAPREOPEN)) { result = named_server_dnstap(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_TCPTIMEOUTS)) { result = named_server_tcptimeouts(lex, text); } else if (command_compare(command, NAMED_COMMAND_SERVESTALE)) { result = named_server_servestale(named_g_server, lex, text); } else { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING, "unknown control channel command '%s'", command); result = DNS_R_UNKNOWNCOMMAND; } cleanup: if (lex != NULL) isc_lex_destroy(&lex); return (result); }
isc_result_t ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, cfg_aclconfctx_t *aclconfctx) { ns_statschannel_t *listener, *listener_next; ns_statschannellist_t new_listeners; const cfg_obj_t *statschannellist = NULL; const cfg_listelt_t *element, *element2; char socktext[ISC_SOCKADDR_FORMATSIZE]; RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); ISC_LIST_INIT(new_listeners); /* * Get the list of named.conf 'statistics-channels' statements. */ (void)cfg_map_get(config, "statistics-channels", &statschannellist); /* * Run through the new address/port list, noting sockets that are * already being listened on and moving them to the new list. * * Identifying duplicate addr/port combinations is left to either * the underlying config code, or to the bind attempt getting an * address-in-use error. */ if (statschannellist != NULL) { #ifndef HAVE_LIBXML2 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "statistics-channels specified but not effective " "due to missing XML library"); #endif for (element = cfg_list_first(statschannellist); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *statschannel; const cfg_obj_t *listenercfg = NULL; statschannel = cfg_listelt_value(element); (void)cfg_map_get(statschannel, "inet", &listenercfg); if (listenercfg == NULL) continue; for (element2 = cfg_list_first(listenercfg); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *listen_params; const cfg_obj_t *obj; isc_sockaddr_t addr; listen_params = cfg_listelt_value(element2); obj = cfg_tuple_get(listen_params, "address"); addr = *cfg_obj_assockaddr(obj); if (isc_sockaddr_getport(&addr) == 0) isc_sockaddr_setport(&addr, NS_STATSCHANNEL_HTTPPORT); isc_sockaddr_format(&addr, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(9), "processing statistics " "channel %s", socktext); update_listener(server, &listener, listen_params, config, &addr, aclconfctx, socktext); if (listener != NULL) { /* * Remove the listener from the old * list, so it won't be shut down. */ ISC_LIST_UNLINK(server->statschannels, listener, link); } else { /* * This is a new listener. */ isc_result_t r; r = add_listener(server, &listener, listen_params, config, &addr, aclconfctx, socktext); if (r != ISC_R_SUCCESS) { cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, "couldn't allocate " "statistics channel" " %s: %s", socktext, isc_result_totext(r)); } } if (listener != NULL) ISC_LIST_APPEND(new_listeners, listener, link); } } } for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; listener = listener_next) { listener_next = ISC_LIST_NEXT(listener, link); ISC_LIST_UNLINK(server->statschannels, listener, link); shutdown_listener(listener); } ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); return (ISC_R_SUCCESS); }
static isc_result_t getbuf6(isc_interfaceiter_t *iter) { char strbuf[ISC_STRERRORSIZE]; isc_result_t result; iter->bufsize6 = IFCONF_BUFSIZE_INITIAL; for (;;) { iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6); if (iter->buf6 == NULL) return (ISC_R_NOMEMORY); memset(&iter->lifc, 0, sizeof(iter->lifc)); #ifdef ISC_HAVE_LIFC_FAMILY iter->lifc.lifc_family = AF_INET6; #endif #ifdef ISC_HAVE_LIFC_FLAGS iter->lifc.lifc_flags = 0; #endif iter->lifc.lifc_len = iter->bufsize6; iter->lifc.lifc_buf = iter->buf6; /* * Ignore the HP/UX warning about "integer overflow during * conversion". It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc) == -1) { #ifdef __hpux /* * IPv6 interface scanning is not available on all * kernels w/ IPv6 sockets. */ if (errno == ENOENT) { isc__strerror(errno, strbuf, sizeof(strbuf)); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_DEBUG(1), isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "get interface " "configuration: %s"), strbuf); result = ISC_R_FAILURE; goto cleanup; } #endif if (errno != EINVAL) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "get interface " "configuration: %s"), strbuf); result = ISC_R_UNEXPECTED; goto cleanup; } /* * EINVAL. Retry with a bigger buffer. */ } else { /* * The ioctl succeeded. * Some OS's just return what will fit rather * than set EINVAL if the buffer is too small * to fit all the interfaces in. If * ifc.ifc_len is too near to the end of the * buffer we will grow it just in case and * retry. */ if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ) < iter->bufsize6) break; } if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) { UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_BUFFERMAX, "get interface " "configuration: " "maximum buffer " "size exceeded")); result = ISC_R_UNEXPECTED; goto cleanup; } isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); iter->bufsize6 *= 2; } if (iter->lifc.lifc_len != 0) iter->mode = 6; return (ISC_R_SUCCESS); cleanup: isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); iter->buf6 = NULL; return (result); }
static isc_result_t odbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi) { isc_result_t result; SQLSMALLINT fields; SQLHSTMT *stmnt; char *ttl_s; char *type; char *data; char *endp; int ttl; REQUIRE(dbi != NULL); stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt; /* get number of columns */ if (!sqlOK(SQLNumResultCols(stmnt, &fields))) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to process result set"); result = ISC_R_FAILURE; goto process_rs_cleanup; } /* get things ready for processing */ result = ISC_R_FAILURE; while (sqlOK(SQLFetch(stmnt))) { /* set to null for next pass through */ data = type = ttl_s = NULL; switch(fields) { case 1: /* * one column in rs, it's the data field. use * default type of A record, and default TTL * of 86400. attempt to get data, & tell bind * about it. */ if ((result = odbc_getField(stmnt, 1, &data)) == ISC_R_SUCCESS) { result = dns_sdlz_putrr(lookup, "a", 86400, data); } break; case 2: /* * two columns, data field, and data type. * use default TTL of 86400. attempt to get * DNS type & data, then tell bind about it. */ if ((result = odbc_getField(stmnt, 1, &type)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 2, &data)) == ISC_R_SUCCESS) { result = dns_sdlz_putrr(lookup, type, 86400, data); } break; default: /* * 3 fields or more, concatenate the last ones * together. attempt to get DNS ttl, type, * data then tell Bind about them. */ if ((result = odbc_getField(stmnt, 1, &ttl_s)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 2, &type)) == ISC_R_SUCCESS && (result = odbc_getManyFields(stmnt, 3, fields, &data)) == ISC_R_SUCCESS) { /* try to convert ttl string to int */ ttl = strtol(ttl_s, &endp, 10); /* failure converting ttl. */ if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver ttl must " "be a postive number"); result = ISC_R_FAILURE; } else { /* * successful converting TTL, * tell Bind everything */ result = dns_sdlz_putrr(lookup, type, ttl, data); } } /* closes bid if () */ } /* closes switch(fields) */ /* clean up mem */ if (ttl_s != NULL) isc_mem_free(ns_g_mctx, ttl_s); if (type != NULL) isc_mem_free(ns_g_mctx, type); if (data != NULL) isc_mem_free(ns_g_mctx, data); /* I sure hope we were successful */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putrr returned error. " "Error code was: %s", isc_result_totext(result)); result = ISC_R_FAILURE; goto process_rs_cleanup; } } /* closes while loop */ process_rs_cleanup: /* close cursor */ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt); #ifdef ISC_PLATFORM_USETHREADS /* free lock on dbi so someone else can use it. */ isc_mutex_unlock(&dbi->instance_lock); #endif return result; }
static isc_result_t internal_current4(isc_interfaceiter_t *iter) { struct ifreq *ifrp; struct ifreq ifreq; int family; char strbuf[ISC_STRERRORSIZE]; #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) struct lifreq lifreq; #else char sabuf[256]; #endif int i, bits, prefixlen; REQUIRE(VALID_IFITER(iter)); if (iter->ifc.ifc_len == 0 || iter->pos == (unsigned int)iter->ifc.ifc_len) { #ifdef __linux return (linux_if_inet6_current(iter)); #else return (ISC_R_NOMORE); #endif } INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len); ifrp = (void *)((char *) iter->ifc.ifc_req + iter->pos); memset(&ifreq, 0, sizeof(ifreq)); memcpy(&ifreq, ifrp, sizeof(ifreq)); family = ifreq.ifr_addr.sa_family; #if defined(ISC_PLATFORM_HAVEIPV6) if (family != AF_INET && family != AF_INET6) #else if (family != AF_INET) #endif return (ISC_R_IGNORE); memset(&iter->current, 0, sizeof(iter->current)); iter->current.af = family; INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name)); memset(iter->current.name, 0, sizeof(iter->current.name)); memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name)); get_addr(family, &iter->current.address, (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name); /* * If the interface does not have a address ignore it. */ switch (family) { case AF_INET: if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) return (ISC_R_IGNORE); break; case AF_INET6: if (memcmp(&iter->current.address.type.in6, &in6addr_any, sizeof(in6addr_any)) == 0) return (ISC_R_IGNORE); break; } /* * Get interface flags. */ iter->current.flags = 0; /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: getting interface flags: %s", ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } if ((ifreq.ifr_flags & IFF_UP) != 0) iter->current.flags |= INTERFACE_F_UP; #ifdef IFF_POINTOPOINT if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) iter->current.flags |= INTERFACE_F_POINTTOPOINT; #endif if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0) iter->current.flags |= INTERFACE_F_LOOPBACK; if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) iter->current.flags |= INTERFACE_F_BROADCAST; #ifdef IFF_MULTICAST if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) iter->current.flags |= INTERFACE_F_MULTICAST; #endif if (family == AF_INET) goto inet; #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) memset(&lifreq, 0, sizeof(lifreq)); memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name)); memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6, sizeof(iter->current.address.type.in6)); if (isc_ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: getting interface address: %s", ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } prefixlen = lifreq.lifr_addrlen; #else isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf)); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_INTERFACE, ISC_LOG_INFO, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETIFCONFIG, "prefix length for %s is unknown " "(assume 128)"), sabuf); prefixlen = 128; #endif /* * Netmask already zeroed. */ iter->current.netmask.family = family; for (i = 0; i < 16; i++) { if (prefixlen > 8) { bits = 0; prefixlen -= 8; } else { bits = 8 - prefixlen; prefixlen = 0; } iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff; } #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX iter->current.ifindex = if_nametoindex(iter->current.name); #endif return (ISC_R_SUCCESS); inet: if (family != AF_INET) return (ISC_R_IGNORE); #ifdef IFF_POINTOPOINT /* * If the interface is point-to-point, get the destination address. */ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETDESTADDR, "%s: getting " "destination address: %s"), ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.dstaddress, (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name); } #endif if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETBCSTADDR, "%s: getting " "broadcast address: %s"), ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.broadcast, (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name); } /* * Get the network mask. */ memset(&ifreq, 0, sizeof(ifreq)); memcpy(&ifreq, ifrp, sizeof(ifreq)); /* * Ignore the HP/UX warning about "integer overflow during * conversion. It comes from its own macro definition, * and is really hard to shut up. */ if (isc_ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERIOCTL, ISC_MSG_GETNETMASK, "%s: getting netmask: %s"), ifreq.ifr_name, strbuf); return (ISC_R_IGNORE); } get_addr(family, &iter->current.netmask, (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name); #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX iter->current.ifindex = if_nametoindex(iter->current.name); #endif return (ISC_R_SUCCESS); }
static isc_result_t try_proto(int domain) { int s; isc_result_t result = ISC_R_SUCCESS; char strbuf[ISC_STRERRORSIZE]; s = socket(domain, SOCK_STREAM, 0); if (s == -1) { switch (errno) { #ifdef EAFNOSUPPORT case EAFNOSUPPORT: #endif #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: #endif #ifdef EINVAL case EINVAL: #endif return (ISC_R_NOTFOUND); default: isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "socket() %s: %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed"), strbuf); return (ISC_R_UNEXPECTED); } } #ifdef ISC_PLATFORM_HAVEIPV6 #ifdef WANT_IPV6 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO if (domain == PF_INET6) { struct sockaddr_in6 sin6; GETSOCKNAME_SOCKLEN_TYPE len; /* NTP local change */ /* * Check to see if IPv6 is broken, as is common on Linux. */ len = sizeof(sin6); if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0) { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, "retrieving the address of an IPv6 " "socket from the kernel failed."); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, "IPv6 is not supported."); result = ISC_R_NOTFOUND; } else { if (len == sizeof(struct sockaddr_in6)) result = ISC_R_SUCCESS; else { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, "IPv6 structures in kernel and " "user space do not match."); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, "IPv6 is not supported."); result = ISC_R_NOTFOUND; } } } #endif #endif #endif (void)close(s); return (result); }
isc_result_t dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, const char *directory) { FILE *fp; isc_result_t result; char filename[ISC_DIR_NAMEMAX]; char buffer[MAXFIELDSIZE * 2]; isc_fsaccess_t access; isc_stdtime_t when; isc_uint32_t value; isc_buffer_t b; isc_region_t r; int major, minor; mode_t mode; int i, ret; REQUIRE(priv != NULL); ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external); if (ret < 0) return (DST_R_INVALIDPRIVATEKEY); else if (ret != ISC_R_SUCCESS) return (ret); isc_buffer_init(&b, filename, sizeof(filename)); result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b); if (result != ISC_R_SUCCESS) return (result); result = isc_file_mode(filename, &mode); if (result == ISC_R_SUCCESS && mode != 0600) { /* File exists; warn that we are changing its permissions */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, "Permissions on the file %s " "have changed from 0%o to 0600 as " "a result of this operation.", filename, (unsigned int)mode); } if ((fp = fopen(filename, "w")) == NULL) return (DST_R_WRITEERROR); access = 0; isc_fsaccess_add(ISC_FSACCESS_OWNER, ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access); (void)isc_fsaccess_set(filename, access); dst_key_getprivateformat(key, &major, &minor); if (major == 0 && minor == 0) { major = DST_MAJOR_VERSION; minor = DST_MINOR_VERSION; } /* XXXDCL return value should be checked for full filesystem */ fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor); fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key)); /* XXXVIX this switch statement is too sparse to gen a jump table. */ switch (dst_key_alg(key)) { case DST_ALG_RSAMD5: fprintf(fp, "(RSA)\n"); break; case DST_ALG_DH: fprintf(fp, "(DH)\n"); break; case DST_ALG_DSA: fprintf(fp, "(DSA)\n"); break; case DST_ALG_RSASHA1: fprintf(fp, "(RSASHA1)\n"); break; case DST_ALG_NSEC3RSASHA1: fprintf(fp, "(NSEC3RSASHA1)\n"); break; case DST_ALG_NSEC3DSA: fprintf(fp, "(NSEC3DSA)\n"); break; case DST_ALG_RSASHA256: fprintf(fp, "(RSASHA256)\n"); break; case DST_ALG_RSASHA512: fprintf(fp, "(RSASHA512)\n"); break; case DST_ALG_ECCGOST: fprintf(fp, "(ECC-GOST)\n"); break; case DST_ALG_ECDSA256: fprintf(fp, "(ECDSAP256SHA256)\n"); break; case DST_ALG_ECDSA384: fprintf(fp, "(ECDSAP384SHA384)\n"); break; case DST_ALG_HMACMD5: fprintf(fp, "(HMAC_MD5)\n"); break; case DST_ALG_HMACSHA1: fprintf(fp, "(HMAC_SHA1)\n"); break; case DST_ALG_HMACSHA224: fprintf(fp, "(HMAC_SHA224)\n"); break; case DST_ALG_HMACSHA256: fprintf(fp, "(HMAC_SHA256)\n"); break; case DST_ALG_HMACSHA384: fprintf(fp, "(HMAC_SHA384)\n"); break; case DST_ALG_HMACSHA512: fprintf(fp, "(HMAC_SHA512)\n"); break; default: fprintf(fp, "(?)\n"); break; } for (i = 0; i < priv->nelements; i++) { const char *s; s = find_tag(priv->elements[i].tag); r.base = priv->elements[i].data; r.length = priv->elements[i].length; isc_buffer_init(&b, buffer, sizeof(buffer)); result = isc_base64_totext(&r, sizeof(buffer), "", &b); if (result != ISC_R_SUCCESS) { fclose(fp); return (DST_R_INVALIDPRIVATEKEY); } isc_buffer_usedregion(&b, &r); fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base); } if (key->external) fprintf(fp, "External:\n"); /* Add the metadata tags */ if (major > 1 || (major == 1 && minor >= 3)) { for (i = 0; i < NUMERIC_NTAGS; i++) { result = dst_key_getnum(key, i, &value); if (result != ISC_R_SUCCESS) continue; fprintf(fp, "%s %u\n", numerictags[i], value); } for (i = 0; i < TIMING_NTAGS; i++) { result = dst_key_gettime(key, i, &when); if (result != ISC_R_SUCCESS) continue; isc_buffer_init(&b, buffer, sizeof(buffer)); result = dns_time32_totext(when, &b); if (result != ISC_R_SUCCESS) { fclose(fp); return (DST_R_INVALIDPRIVATEKEY); } isc_buffer_usedregion(&b, &r); fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, r.base); } } fflush(fp); result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; fclose(fp); return (result); }
static isc_result_t ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ns_interface_t **ifpret) { ns_interface_t *ifp; isc_result_t result; int disp; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); if (ifp == NULL) return (ISC_R_NOMEMORY); ifp->mgr = NULL; ifp->generation = mgr->generation; ifp->addr = *addr; ifp->flags = 0; strlcpy(ifp->name, name, sizeof(ifp->name)); ifp->clientmgr = NULL; result = isc_mutex_init(&ifp->lock); if (result != ISC_R_SUCCESS) goto lock_create_failure; result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr, ns_g_timermgr, &ifp->clientmgr); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "ns_clientmgr_create() failed: %s", isc_result_totext(result)); goto clientmgr_create_failure; } for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) ifp->udpdispatch[disp] = NULL; ifp->tcpsocket = NULL; /* * Create a single TCP client object. It will replace itself * with a new one as soon as it gets a connection, so the actual * connections will be handled in parallel even though there is * only one client initially. */ ifp->ntcptarget = 1; ifp->ntcpcurrent = 0; ifp->nudpdispatch = 0; ifp->dscp = -1; ISC_LINK_INIT(ifp, link); ns_interfacemgr_attach(mgr, &ifp->mgr); ISC_LIST_APPEND(mgr->interfaces, ifp, link); ifp->references = 1; ifp->magic = IFACE_MAGIC; *ifpret = ifp; return (ISC_R_SUCCESS); clientmgr_create_failure: DESTROYLOCK(&ifp->lock); lock_create_failure: ifp->magic = 0; isc_mem_put(mgr->mctx, ifp, sizeof(*ifp)); return (ISC_R_UNEXPECTED); }
isc_result_t dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *filename, dns_db_t **target) { isc_result_t result, eresult; isc_buffer_t source; unsigned int len; dns_rdatacallbacks_t callbacks; dns_db_t *db = NULL; REQUIRE(target != NULL && *target == NULL); result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, rdclass, 0, NULL, &db); if (result != ISC_R_SUCCESS) return (result); len = strlen(root_ns); isc_buffer_init(&source, root_ns, len); isc_buffer_add(&source, len); dns_rdatacallbacks_init(&callbacks); result = dns_db_beginload(db, &callbacks); if (result != ISC_R_SUCCESS) return (result); if (filename != NULL) { /* * Load the hints from the specified filename. */ result = dns_master_loadfile(filename, &db->origin, &db->origin, db->rdclass, DNS_MASTER_HINT, &callbacks, db->mctx); } else if (rdclass == dns_rdataclass_in) { /* * Default to using the Internet root servers. */ result = dns_master_loadbuffer(&source, &db->origin, &db->origin, db->rdclass, DNS_MASTER_HINT, &callbacks, db->mctx); } else result = ISC_R_NOTFOUND; eresult = dns_db_endload(db, &callbacks); if (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) result = eresult; if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) goto db_detach; if (check_hints(db) != ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, "extra data in root hints '%s'", (filename != NULL) ? filename : "<BUILT-IN>"); *target = db; return (ISC_R_SUCCESS); db_detach: dns_db_detach(&db); return (result); }
static isc_result_t ns_interface_listenudp(ns_interface_t *ifp) { isc_result_t result; unsigned int attrs; unsigned int attrmask; int disp, i; attrs = 0; attrs |= DNS_DISPATCHATTR_UDP; if (isc_sockaddr_pf(&ifp->addr) == AF_INET) attrs |= DNS_DISPATCHATTR_IPV4; else attrs |= DNS_DISPATCHATTR_IPV6; attrs |= DNS_DISPATCHATTR_NOLISTEN; attrmask = 0; attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH); for (disp = 0; disp < ifp->nudpdispatch; disp++) { result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr, ns_g_socketmgr, ns_g_taskmgr, &ifp->addr, 4096, UDPBUFFERS, 32768, 8219, 8237, attrs, attrmask, &ifp->udpdispatch[disp], disp == 0 ? NULL : ifp->udpdispatch[0]); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "could not listen on UDP socket: %s", isc_result_totext(result)); goto udp_dispatch_failure; } } result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch, ifp, ISC_FALSE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "UDP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto addtodispatch_failure; } return (ISC_R_SUCCESS); addtodispatch_failure: for (i = disp - 1; i >= 0; i--) { dns_dispatch_changeattributes(ifp->udpdispatch[i], 0, DNS_DISPATCHATTR_NOLISTEN); dns_dispatch_detach(&(ifp->udpdispatch[i])); } ifp->nudpdispatch = 0; udp_dispatch_failure: return (result); }
static isc_result_t diff_apply (dns_diff_t * diff, dns_db_t * db, dns_dbversion_t * ver, isc_boolean_t warn) { dns_difftuple_t *t; dns_dbnode_t *node = NULL; isc_result_t result; char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; char classbuf[DNS_RDATACLASS_FORMATSIZE]; REQUIRE (DNS_DIFF_VALID (diff)); REQUIRE (DNS_DB_VALID (db)); t = ISC_LIST_HEAD (diff->tuples); while (t != NULL) { dns_name_t *name; INSIST (node == NULL); name = &t->name; /* * Find the node. * We create the node if it does not exist. * This will cause an empty node to be created if the diff * contains a deletion of an RR at a nonexistent name, * but such diffs should never be created in the first * place. */ while (t != NULL && dns_name_equal (&t->name, name)) { dns_rdatatype_t type, covers; dns_diffop_t op; dns_rdatalist_t rdl; dns_rdataset_t rds; dns_rdataset_t ardataset; dns_rdataset_t *modified = NULL; op = t->op; type = t->rdata.type; covers = rdata_covers (&t->rdata); /* * Collect a contiguous set of updates with * the same operation (add/delete) and RR type * into a single rdatalist so that the * database rrset merging/subtraction code * can work more efficiently than if each * RR were merged into / subtracted from * the database separately. * * This is done by linking rdata structures from the * diff into "rdatalist". This uses the rdata link * field, not the diff link field, so the structure * of the diff itself is not affected. */ rdl.type = type; rdl.covers = covers; rdl.rdclass = t->rdata.rdclass; rdl.ttl = t->ttl; ISC_LIST_INIT (rdl.rdata); ISC_LINK_INIT (&rdl, link); node = NULL; if (type != dns_rdatatype_nsec3 && covers != dns_rdatatype_nsec3) CHECK (dns_db_findnode (db, name, ISC_TRUE, &node)); else CHECK (dns_db_findnsec3node (db, name, ISC_TRUE, &node)); while (t != NULL && dns_name_equal (&t->name, name) && t->op == op && t->rdata.type == type && rdata_covers (&t->rdata) == covers) { dns_name_format (name, namebuf, sizeof (namebuf)); dns_rdatatype_format (t->rdata.type, typebuf, sizeof (typebuf)); dns_rdataclass_format (t->rdata.rdclass, classbuf, sizeof (classbuf)); if (t->ttl != rdl.ttl && warn) isc_log_write (DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "'%s/%s/%s': TTL differs in " "rdataset, adjusting " "%lu -> %lu", namebuf, typebuf, classbuf, (unsigned long) t->ttl, (unsigned long) rdl.ttl); ISC_LIST_APPEND (rdl.rdata, &t->rdata, link); t = ISC_LIST_NEXT (t, link); } /* * Convert the rdatalist into a rdataset. */ dns_rdataset_init (&rds); CHECK (dns_rdatalist_tordataset (&rdl, &rds)); if (rds.type == dns_rdatatype_rrsig) switch (op) { case DNS_DIFFOP_ADDRESIGN: case DNS_DIFFOP_DELRESIGN: modified = &ardataset; dns_rdataset_init (modified); break; default: break; } rds.trust = dns_trust_ultimate; /* * Merge the rdataset into the database. */ switch (op) { case DNS_DIFFOP_ADD: case DNS_DIFFOP_ADDRESIGN: result = dns_db_addrdataset (db, node, ver, 0, &rds, DNS_DBADD_MERGE | DNS_DBADD_EXACT | DNS_DBADD_EXACTTTL, modified); break; case DNS_DIFFOP_DEL: case DNS_DIFFOP_DELRESIGN: result = dns_db_subtractrdataset (db, node, ver, &rds, DNS_DBSUB_EXACT, modified); break; default: INSIST (0); } if (result == ISC_R_SUCCESS) { if (modified != NULL) { isc_stdtime_t resign; resign = setresign (modified, diff->resign); dns_db_setsigningtime (db, modified, resign); if (diff->resign == 0 && (op == DNS_DIFFOP_ADDRESIGN || op == DNS_DIFFOP_DELRESIGN)) isc_log_write (DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "resign requested " "with 0 resign " "interval"); } } else if (result == DNS_R_UNCHANGED) { /* * This will not happen when executing a * dynamic update, because that code will * generate strictly minimal diffs. * It may happen when receiving an IXFR * from a server that is not as careful. * Issue a warning and continue. */ if (warn) { char classbuf[DNS_RDATATYPE_FORMATSIZE]; char namebuf[DNS_NAME_FORMATSIZE]; dns_name_format (dns_db_origin (db), namebuf, sizeof (namebuf)); dns_rdataclass_format (dns_db_class (db), classbuf, sizeof (classbuf)); isc_log_write (DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "%s/%s: dns_diff_apply: " "update with no effect", namebuf, classbuf); } } else if (result == DNS_R_NXRRSET) { /* * OK. */ } else { if (modified != NULL && dns_rdataset_isassociated (modified)) dns_rdataset_disassociate (modified); CHECK (result); } dns_db_detachnode (db, &node); if (modified != NULL && dns_rdataset_isassociated (modified)) dns_rdataset_disassociate (modified); } } return (ISC_R_SUCCESS); failure: if (node != NULL) dns_db_detachnode (db, &node); return (result); }
static isc_result_t ns_interface_accepttcp(ns_interface_t *ifp) { isc_result_t result; /* * Open a TCP socket. */ result = isc_socket_create(ifp->mgr->socketmgr, isc_sockaddr_pf(&ifp->addr), isc_sockettype_tcp, &ifp->tcpsocket); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating TCP socket: %s", isc_result_totext(result)); goto tcp_socket_failure; } isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL); #ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE); #endif result = isc_socket_bind(ifp->tcpsocket, &ifp->addr, ISC_SOCKET_REUSEADDRESS); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "binding TCP socket: %s", isc_result_totext(result)); goto tcp_bind_failure; } if (ifp->dscp != -1) isc_socket_dscp(ifp->tcpsocket, ifp->dscp); result = isc_socket_listen(ifp->tcpsocket, ns_g_listen); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "listening on TCP socket: %s", isc_result_totext(result)); goto tcp_listen_failure; } /* * If/when there a multiple filters listen to the * result. */ (void)isc_socket_filter(ifp->tcpsocket, "dataready"); result = ns_clientmgr_createclients(ifp->clientmgr, ifp->ntcptarget, ifp, ISC_TRUE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "TCP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto accepttcp_failure; } return (ISC_R_SUCCESS); accepttcp_failure: tcp_listen_failure: tcp_bind_failure: isc_socket_detach(&ifp->tcpsocket); tcp_socket_failure: return (ISC_R_SUCCESS); }
isc_result_t dns_diff_print (dns_diff_t * diff, FILE * file) { isc_result_t result; dns_difftuple_t *t; char *mem = NULL; unsigned int size = 2048; const char *op = NULL; REQUIRE (DNS_DIFF_VALID (diff)); mem = isc_mem_get (diff->mctx, size); if (mem == NULL) return (ISC_R_NOMEMORY); for (t = ISC_LIST_HEAD (diff->tuples); t != NULL; t = ISC_LIST_NEXT (t, link)) { isc_buffer_t buf; isc_region_t r; dns_rdatalist_t rdl; dns_rdataset_t rds; dns_rdata_t rd = DNS_RDATA_INIT; result = diff_tuple_tordataset (t, &rd, &rdl, &rds); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR (__FILE__, __LINE__, "diff_tuple_tordataset failed: %s", dns_result_totext (result)); result = ISC_R_UNEXPECTED; goto cleanup; } again: isc_buffer_init (&buf, mem, size); result = dns_rdataset_totext (&rds, &t->name, ISC_FALSE, ISC_FALSE, &buf); if (result == ISC_R_NOSPACE) { isc_mem_put (diff->mctx, mem, size); size += 1024; mem = isc_mem_get (diff->mctx, size); if (mem == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } goto again; } if (result != ISC_R_SUCCESS) goto cleanup; /* * Get rid of final newline. */ INSIST (buf.used >= 1 && ((char *) buf.base)[buf.used - 1] == '\n'); buf.used--; isc_buffer_usedregion (&buf, &r); switch (t->op) { case DNS_DIFFOP_EXISTS: op = "exists"; break; case DNS_DIFFOP_ADD: op = "add"; break; case DNS_DIFFOP_DEL: op = "del"; break; case DNS_DIFFOP_ADDRESIGN: op = "add re-sign"; break; case DNS_DIFFOP_DELRESIGN: op = "del re-sign"; break; } if (file != NULL) fprintf (file, "%s %.*s\n", op, (int) r.length, (char *) r.base); else isc_log_write (DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG (7), "%s %.*s", op, (int) r.length, (char *) r.base); } result = ISC_R_SUCCESS; cleanup: if (mem != NULL) isc_mem_put (diff->mctx, mem, size); return (result); }
static isc_result_t do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, isc_boolean_t verbose) { isc_interfaceiter_t *iter = NULL; isc_boolean_t scan_ipv4 = ISC_FALSE; isc_boolean_t scan_ipv6 = ISC_FALSE; isc_boolean_t adjusting = ISC_FALSE; isc_boolean_t ipv6only = ISC_TRUE; isc_boolean_t ipv6pktinfo = ISC_TRUE; isc_result_t result; isc_netaddr_t zero_address, zero_address6; ns_listenelt_t *le; isc_sockaddr_t listen_addr; ns_interface_t *ifp; isc_boolean_t log_explicit = ISC_FALSE; isc_boolean_t dolistenon; char sabuf[ISC_SOCKADDR_FORMATSIZE]; if (ext_listen != NULL) adjusting = ISC_TRUE; if (isc_net_probeipv6() == ISC_R_SUCCESS) scan_ipv6 = ISC_TRUE; #ifdef WANT_IPV6 else if (!ns_g_disable6) isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv6 interfaces found"); #endif if (isc_net_probeipv4() == ISC_R_SUCCESS) scan_ipv4 = ISC_TRUE; else if (!ns_g_disable4) isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv4 interfaces found"); /* * A special, but typical case; listen-on-v6 { any; }. * When we can make the socket IPv6-only, open a single wildcard * socket for IPv6 communication. Otherwise, make separate socket * for each IPv6 address in order to avoid accepting IPv4 packets * as the form of mapped addresses unintentionally unless explicitly * allowed. */ #ifndef ISC_ALLOW_MAPPED if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6only() != ISC_R_SUCCESS) { ipv6only = ISC_FALSE; log_explicit = ISC_TRUE; } #endif if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) { ipv6pktinfo = ISC_FALSE; log_explicit = ISC_TRUE; } if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) { for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { struct in6_addr in6a; if (!listenon_is_ip6_any(le)) continue; in6a = in6addr_any; isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); ifp = find_matching_interface(mgr, &listen_addr); if (ifp != NULL) { ifp->generation = mgr->generation; if (le->dscp != -1 && ifp->dscp == -1) ifp->dscp = le->dscp; else if (le->dscp != ifp->dscp) { isc_sockaddr_format(&listen_addr, sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, "%s: conflicting DSCP " "values, using %d", sabuf, ifp->dscp); } } else { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "listening on IPv6 " "interfaces, port %u", le->port); result = ns_interface_setup(mgr, &listen_addr, "<any>", &ifp, ISC_TRUE, le->dscp); if (result == ISC_R_SUCCESS) ifp->flags |= NS_INTERFACEFLAG_ANYADDR; else isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "listening on all IPv6 " "interfaces failed"); /* Continue. */ } } } isc_netaddr_any(&zero_address); isc_netaddr_any6(&zero_address6); result = isc_interfaceiter_create(mgr->mctx, &iter); if (result != ISC_R_SUCCESS) return (result); if (adjusting == ISC_FALSE) { result = clearacl(mgr->mctx, &mgr->aclenv.localhost); if (result != ISC_R_SUCCESS) goto cleanup_iter; result = clearacl(mgr->mctx, &mgr->aclenv.localnets); if (result != ISC_R_SUCCESS) goto cleanup_iter; clearlistenon(mgr); } for (result = isc_interfaceiter_first(iter); result == ISC_R_SUCCESS; result = isc_interfaceiter_next(iter)) { isc_interface_t interface; ns_listenlist_t *ll; unsigned int family; result = isc_interfaceiter_current(iter, &interface); if (result != ISC_R_SUCCESS) break; family = interface.address.family; if (family != AF_INET && family != AF_INET6) continue; if (scan_ipv4 == ISC_FALSE && family == AF_INET) continue; if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; /* * Test for the address being nonzero rather than testing * INTERFACE_F_UP, because on some systems the latter * follows the media state and we could end up ignoring * the interface for an entire rescan interval due to * a temporary media glitch at rescan time. */ if (family == AF_INET && isc_netaddr_equal(&interface.address, &zero_address)) { continue; } if (family == AF_INET6 && isc_netaddr_equal(&interface.address, &zero_address6)) { continue; } if (adjusting == ISC_FALSE) { /* * If running with -T fixedlocal, then we only * want 127.0.0.1 and ::1 in the localhost ACL. */ if (ns_g_fixedlocal && !isc_netaddr_isloopback(&interface.address)) { goto listenon; } result = setup_locals(mgr, &interface); if (result != ISC_R_SUCCESS) goto ignore_interface; } listenon: ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; dolistenon = ISC_TRUE; for (le = ISC_LIST_HEAD(ll->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { int match; isc_boolean_t ipv6_wildcard = ISC_FALSE; isc_netaddr_t listen_netaddr; isc_sockaddr_t listen_sockaddr; /* * Construct a socket address for this IP/port * combination. */ if (family == AF_INET) { isc_netaddr_fromin(&listen_netaddr, &interface.address.type.in); } else { isc_netaddr_fromin6(&listen_netaddr, &interface.address.type.in6); isc_netaddr_setzone(&listen_netaddr, interface.address.zone); } isc_sockaddr_fromnetaddr(&listen_sockaddr, &listen_netaddr, le->port); /* * See if the address matches the listen-on statement; * if not, ignore the interface. */ (void)dns_acl_match(&listen_netaddr, NULL, le->acl, &mgr->aclenv, &match, NULL); if (match <= 0) continue; if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) { setup_listenon(mgr, &interface, le->port); dolistenon = ISC_FALSE; } /* * The case of "any" IPv6 address will require * special considerations later, so remember it. */ if (family == AF_INET6 && ipv6only && ipv6pktinfo && listenon_is_ip6_any(le)) ipv6_wildcard = ISC_TRUE; /* * When adjusting interfaces with extra a listening * list, see if the address matches the extra list. * If it does, and is also covered by a wildcard * interface, we need to listen on the address * explicitly. */ if (adjusting == ISC_TRUE) { ns_listenelt_t *ele; match = 0; for (ele = ISC_LIST_HEAD(ext_listen->elts); ele != NULL; ele = ISC_LIST_NEXT(ele, link)) { (void)dns_acl_match(&listen_netaddr, NULL, ele->acl, NULL, &match, NULL); if (match > 0 && (ele->port == le->port || ele->port == 0)) break; else match = 0; } if (ipv6_wildcard == ISC_TRUE && match == 0) continue; } ifp = find_matching_interface(mgr, &listen_sockaddr); if (ifp != NULL) { ifp->generation = mgr->generation; if (le->dscp != -1 && ifp->dscp == -1) ifp->dscp = le->dscp; else if (le->dscp != ifp->dscp) { isc_sockaddr_format(&listen_sockaddr, sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, "%s: conflicting DSCP " "values, using %d", sabuf, ifp->dscp); } } else { if (adjusting == ISC_FALSE && ipv6_wildcard == ISC_TRUE) continue; if (log_explicit && family == AF_INET6 && !adjusting && listenon_is_ip6_any(le)) { isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "IPv6 socket API is " "incomplete; explicitly " "binding to each IPv6 " "address separately"); log_explicit = ISC_FALSE; } isc_sockaddr_format(&listen_sockaddr, sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "%s" "listening on %s interface " "%s, %s", (adjusting == ISC_TRUE) ? "additionally " : "", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, sabuf); result = ns_interface_setup(mgr, &listen_sockaddr, interface.name, &ifp, (adjusting == ISC_TRUE) ? ISC_FALSE : ISC_TRUE, le->dscp); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating %s interface " "%s failed; interface " "ignored", (family == AF_INET) ? "IPv4" : "IPv6", interface.name); } /* Continue. */ } } continue; ignore_interface: isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "ignoring %s interface %s: %s", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, isc_result_totext(result)); continue; } if (result != ISC_R_NOMORE) UNEXPECTED_ERROR(__FILE__, __LINE__, "interface iteration failed: %s", isc_result_totext(result)); else result = ISC_R_SUCCESS; cleanup_iter: isc_interfaceiter_destroy(&iter); return (result); }
/*% * Configure static-stub zone. */ static isc_result_t configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone, const char *zname, const char *dbtype) { int i = 0; const cfg_obj_t *obj; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_db_t *db = NULL; dns_dbversion_t *dbversion = NULL; dns_dbnode_t *apexnode = NULL; dns_name_t apexname; isc_result_t result; dns_rdataset_t rdataset; dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa; dns_rdatalist_t* rdatalists[] = { &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL }; dns_rdata_t *rdata; isc_region_t region; /* Create the DB beforehand */ RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone), dns_dbtype_stub, dns_zone_getclass(zone), 0, NULL, &db)); dns_zone_setdb(zone, db); dns_rdatalist_init(&rdatalist_ns); rdatalist_ns.rdclass = dns_zone_getclass(zone); rdatalist_ns.type = dns_rdatatype_ns; rdatalist_ns.ttl = STATICSTUB_SERVER_TTL; dns_rdatalist_init(&rdatalist_a); rdatalist_a.rdclass = dns_zone_getclass(zone); rdatalist_a.type = dns_rdatatype_a; rdatalist_a.ttl = STATICSTUB_SERVER_TTL; dns_rdatalist_init(&rdatalist_aaaa); rdatalist_aaaa.rdclass = dns_zone_getclass(zone); rdatalist_aaaa.type = dns_rdatatype_aaaa; rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL; /* Prepare zone RRs from the configuration */ obj = NULL; result = cfg_map_get(zconfig, "server-addresses", &obj); if (result == ISC_R_SUCCESS) { INSIST(obj != NULL); result = configure_staticstub_serveraddrs(obj, zone, &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa); if (result != ISC_R_SUCCESS) goto cleanup; } obj = NULL; result = cfg_map_get(zconfig, "server-names", &obj); if (result == ISC_R_SUCCESS) { INSIST(obj != NULL); result = configure_staticstub_servernames(obj, zone, &rdatalist_ns, zname); if (result != ISC_R_SUCCESS) goto cleanup; } /* * Sanity check: there should be at least one NS RR at the zone apex * to trigger delegation. */ if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "No NS record is configured for a " "static-stub zone '%s'", zname); result = ISC_R_FAILURE; goto cleanup; } /* * Now add NS and glue A/AAAA RRsets to the zone DB. * First open a new version for the add operation and get a pointer * to the apex node (all RRs are of the apex name). */ result = dns_db_newversion(db, &dbversion); if (result != ISC_R_SUCCESS) goto cleanup; dns_name_init(&apexname, NULL); dns_name_clone(dns_zone_getorigin(zone), &apexname); result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode); if (result != ISC_R_SUCCESS) goto cleanup; /* Add NS RRset */ dns_rdataset_init(&rdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; /* Add glue A RRset, if any */ if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) { RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; } /* Add glue AAAA RRset, if any */ if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) { RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa, &rdataset) == ISC_R_SUCCESS); result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0, NULL); dns_rdataset_disassociate(&rdataset); if (result != ISC_R_SUCCESS) goto cleanup; } result = ISC_R_SUCCESS; cleanup: if (apexnode != NULL) dns_db_detachnode(db, &apexnode); if (dbversion != NULL) dns_db_closeversion(db, &dbversion, ISC_TRUE); if (db != NULL) dns_db_detach(&db); for (i = 0; rdatalists[i] != NULL; i++) { while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) { ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link); dns_rdata_toregion(rdata, ®ion); isc_mem_put(mctx, rdata, sizeof(*rdata) + region.length); } } return (result); }
static void route_event(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = NULL; ns_interfacemgr_t *mgr = NULL; isc_region_t r; isc_result_t result; struct MSGHDR *rtm; isc_boolean_t done = ISC_TRUE; UNUSED(task); REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); mgr = event->ev_arg; sevent = (isc_socketevent_t *)event; if (sevent->result != ISC_R_SUCCESS) { if (sevent->result != ISC_R_CANCELED) isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "automatic interface scanning " "terminated: %s", isc_result_totext(sevent->result)); ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; } rtm = (struct MSGHDR *)mgr->buf; #ifdef RTM_VERSION if (rtm->rtm_version != RTM_VERSION) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "automatic interface rescanning disabled: " "rtm->rtm_version mismatch (%u != %u) " "recompile required", rtm->rtm_version, RTM_VERSION); ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; } #endif switch (rtm->MSGTYPE) { case RTM_NEWADDR: case RTM_DELADDR: if (mgr->route != NULL && ns_g_server->interface_auto) ns_server_scan_interfaces(ns_g_server); break; default: break; } LOCK(&mgr->lock); if (mgr->route != NULL) { /* * Look for next route event. */ r.base = mgr->buf; r.length = sizeof(mgr->buf); result = isc_socket_recv(mgr->route, &r, 1, mgr->task, route_event, mgr); if (result == ISC_R_SUCCESS) done = ISC_FALSE; } UNLOCK(&mgr->lock); if (done) ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; }
void ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { isc_result_t result; dns_name_t *question_name; dns_rdataset_t *question_rdataset; dns_zone_t *zone = NULL; dns_db_t *db = NULL; dns_dbversion_t *ver = NULL; dns_rdataclass_t question_class; rrstream_t *soa_stream = NULL; rrstream_t *data_stream = NULL; rrstream_t *stream = NULL; dns_difftuple_t *current_soa_tuple = NULL; dns_name_t *soa_name; dns_rdataset_t *soa_rdataset; dns_rdata_t soa_rdata = DNS_RDATA_INIT; isc_boolean_t have_soa = ISC_FALSE; const char *mnemonic = NULL; isc_mem_t *mctx = client->mctx; dns_message_t *request = client->message; xfrout_ctx_t *xfr = NULL; isc_quota_t *quota = NULL; dns_transfer_format_t format = client->view->transfer_format; isc_netaddr_t na; dns_peer_t *peer = NULL; isc_buffer_t *tsigbuf = NULL; char *journalfile; char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; char keyname[DNS_NAME_FORMATSIZE]; isc_boolean_t is_poll = ISC_FALSE; #ifdef DLZ isc_boolean_t is_dlz = ISC_FALSE; #endif switch (reqtype) { case dns_rdatatype_axfr: mnemonic = "AXFR"; break; case dns_rdatatype_ixfr: mnemonic = "IXFR"; break; default: INSIST(0); break; } ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(6), "%s request", mnemonic); /* * Apply quota. */ result = isc_quota_attach(&ns_g_server->xfroutquota, "a); if (result != ISC_R_SUCCESS) { isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, "%s request denied: %s", mnemonic, isc_result_totext(result)); goto failure; } /* * Interpret the question section. */ result = dns_message_firstname(request, DNS_SECTION_QUESTION); INSIST(result == ISC_R_SUCCESS); /* * The question section must contain exactly one question, and * it must be for AXFR/IXFR as appropriate. */ question_name = NULL; dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); question_rdataset = ISC_LIST_HEAD(question_name->list); question_class = question_rdataset->rdclass; INSIST(question_rdataset->type == reqtype); if (ISC_LIST_NEXT(question_rdataset, link) != NULL) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_message_nextname(request, DNS_SECTION_QUESTION); if (result != ISC_R_NOMORE) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, &zone); if (result != ISC_R_SUCCESS) #ifdef DLZ { /* * Normal zone table does not have a match. * Try the DLZ database */ if (client->view->dlzdatabase != NULL) { result = dns_dlzallowzonexfr(client->view, question_name, &client->peeraddr, &db); if (result == ISC_R_NOPERM) { char _buf1[DNS_NAME_FORMATSIZE]; char _buf2[DNS_RDATACLASS_FORMATSIZE]; result = DNS_R_REFUSED; dns_name_format(question_name, _buf1, sizeof(_buf1)); dns_rdataclass_format(question_class, _buf2, sizeof(_buf2)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_XFER_OUT, ISC_LOG_ERROR, "zone transfer '%s/%s' denied", _buf1, _buf2); goto failure; } if (result != ISC_R_SUCCESS) #endif FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); #ifdef DLZ is_dlz = ISC_TRUE; /* * DLZ only support full zone transfer, not incremental */ if (reqtype != dns_rdatatype_axfr) { mnemonic = "AXFR-style IXFR"; reqtype = dns_rdatatype_axfr; } } else { /* * not DLZ and not in normal zone table, we are * not authoritative */ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } } else { /* zone table has a match */ #endif switch(dns_zone_gettype(zone)) { case dns_zone_master: case dns_zone_slave: break; /* Master and slave zones are OK for transfer. */ default: FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } CHECK(dns_zone_getdb(zone, &db)); dns_db_currentversion(db, &ver); #ifdef DLZ } #endif xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s question section OK", mnemonic); /* * Check the authority section. Look for a SOA record with * the same name and class as the question. */ for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) { soa_name = NULL; dns_message_currentname(request, DNS_SECTION_AUTHORITY, &soa_name); /* * Ignore data whose owner name is not the zone apex. */ if (! dns_name_equal(soa_name, question_name)) continue; for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); soa_rdataset != NULL; soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) { /* * Ignore non-SOA data. */ if (soa_rdataset->type != dns_rdatatype_soa) continue; if (soa_rdataset->rdclass != question_class) continue; CHECK(dns_rdataset_first(soa_rdataset)); dns_rdataset_current(soa_rdataset, &soa_rdata); result = dns_rdataset_next(soa_rdataset); if (result == ISC_R_SUCCESS) FAILC(DNS_R_FORMERR, "IXFR authority section " "has multiple SOAs"); have_soa = ISC_TRUE; goto got_soa; } } got_soa: if (result != ISC_R_NOMORE) CHECK(result); xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s authority section OK", mnemonic); /* * Decide whether to allow this transfer. */ #ifdef DLZ /* * if not a DLZ zone decide whether to allow this transfer. */ if (!is_dlz) { #endif ns_client_aclmsg("zone transfer", question_name, reqtype, client->view->rdclass, msg, sizeof(msg)); CHECK(ns_client_checkacl(client, NULL, msg, dns_zone_getxfracl(zone), ISC_TRUE, ISC_LOG_ERROR)); #ifdef DLZ } #endif /* * AXFR over UDP is not possible. */ if (reqtype == dns_rdatatype_axfr && (client->attributes & NS_CLIENTATTR_TCP) == 0) FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); /* * Look up the requesting server in the peer table. */ isc_netaddr_fromsockaddr(&na, &client->peeraddr); (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); /* * Decide on the transfer format (one-answer or many-answers). */ if (peer != NULL) (void)dns_peer_gettransferformat(peer, &format); /* * Get a dynamically allocated copy of the current SOA. */ #ifdef DLZ if (is_dlz) dns_db_currentversion(db, &ver); #endif CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, ¤t_soa_tuple)); if (reqtype == dns_rdatatype_ixfr) { isc_uint32_t begin_serial, current_serial; isc_boolean_t provide_ixfr; /* * Outgoing IXFR may have been disabled for this peer * or globally. */ provide_ixfr = client->view->provideixfr; if (peer != NULL) (void) dns_peer_getprovideixfr(peer, &provide_ixfr); if (provide_ixfr == ISC_FALSE) goto axfr_fallback; if (! have_soa) FAILC(DNS_R_FORMERR, "IXFR request missing SOA"); begin_serial = dns_soa_getserial(&soa_rdata); current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); /* * RFC1995 says "If an IXFR query with the same or * newer version number than that of the server * is received, it is replied to with a single SOA * record of the server's current version, just as * in AXFR". The claim about AXFR is incorrect, * but other than that, we do as the RFC says. * * Sending a single SOA record is also how we refuse * IXFR over UDP (currently, we always do). */ if (DNS_SERIAL_GE(begin_serial, current_serial) || (client->attributes & NS_CLIENTATTR_TCP) == 0) { CHECK(soa_rrstream_create(mctx, db, ver, &stream)); is_poll = ISC_TRUE; goto have_stream; } journalfile = dns_zone_getjournal(zone); if (journalfile != NULL) result = ixfr_rrstream_create(mctx, journalfile, begin_serial, current_serial, &data_stream); else result = ISC_R_NOTFOUND; if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(4), "IXFR version not in journal, " "falling back to AXFR"); mnemonic = "AXFR-style IXFR"; goto axfr_fallback; } CHECK(result); } else { axfr_fallback: CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream)); } /* * Bracket the data stream with SOAs. */ CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, &stream)); soa_stream = NULL; data_stream = NULL; have_stream: CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); /* * Create the xfrout context object. This transfers the ownership * of "stream", "db", "ver", and "quota" to the xfrout context object. */ #ifdef DLZ if (is_dlz) CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, 3600, 3600, (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); else #endif CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, dns_zone_getmaxxfrout(zone), dns_zone_getidleout(zone), (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); xfr->mnemonic = mnemonic; stream = NULL; quota = NULL; CHECK(xfr->stream->methods->first(xfr->stream)); if (xfr->tsigkey != NULL) { dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); } else keyname[0] = '\0'; if (is_poll) xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); else xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); /* * Hand the context over to sendstream(). Set xfr to NULL; * sendstream() is responsible for either passing the * context on to a later event handler or destroying it. */ sendstream(xfr); xfr = NULL; result = ISC_R_SUCCESS; failure: if (result == DNS_R_REFUSED) inc_stats(zone, dns_nsstatscounter_xfrrej); if (quota != NULL) isc_quota_detach("a); if (current_soa_tuple != NULL) dns_difftuple_free(¤t_soa_tuple); if (stream != NULL) stream->methods->destroy(&stream); if (soa_stream != NULL) soa_stream->methods->destroy(&soa_stream); if (data_stream != NULL) data_stream->methods->destroy(&data_stream); if (ver != NULL) dns_db_closeversion(db, &ver, ISC_FALSE); if (db != NULL) dns_db_detach(&db); if (zone != NULL) dns_zone_detach(&zone); /* XXX kludge */ if (xfr != NULL) { xfrout_fail(xfr, result, "setting up zone transfer"); } else if (result != ISC_R_SUCCESS) { ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3), "zone transfer setup failed"); ns_client_error(client, result); } }
static isc_result_t tcldb_lookup(const char *zone, const char *name, void *dbdata, dns_sdblookup_t *lookup) #endif /* DNS_CLIENTINFO_VERSION */ { isc_result_t result = ISC_R_SUCCESS; int tclres; int rrc; /* RR count */ char **rrv; /* RR vector */ int i; char *cmdv[3]; char *cmd; #ifdef DNS_CLIENTINFO_VERSION UNUSED(methods); UNUSED(clientinfo); #endif /* DNS_CLIENTINFO_VERSION */ tcldb_driver_t *driver = (tcldb_driver_t *) dbdata; cmdv[0] = "lookup"; cmdv[1] = zone; cmdv[2] = name; cmd = Tcl_Merge(3, cmdv); tclres = Tcl_Eval(driver->interp, cmd); Tcl_Free(cmd); if (tclres != TCL_OK) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_SDB, ISC_LOG_ERROR, "zone '%s': tcl lookup function failed: %s", zone, driver->interp->result); return (ISC_R_FAILURE); } if (strcmp(driver->interp->result, "NXDOMAIN") == 0) { result = ISC_R_NOTFOUND; goto fail; } tclres = Tcl_SplitList(driver->interp, driver->interp->result, &rrc, &rrv); if (tclres != TCL_OK) goto malformed; for (i = 0; i < rrc; i++) { isc_result_t tmpres; int fieldc; /* Field count */ char **fieldv; /* Field vector */ tclres = Tcl_SplitList(driver->interp, rrv[i], &fieldc, &fieldv); if (tclres != TCL_OK) { tmpres = ISC_R_FAILURE; goto failrr; } if (fieldc != 3) goto malformed; tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]), fieldv[2]); Tcl_Free((char *) fieldv); failrr: if (tmpres != ISC_R_SUCCESS) result = tmpres; } Tcl_Free((char *) rrv); if (result == ISC_R_SUCCESS) return (result); malformed: isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_SDB, ISC_LOG_ERROR, "zone '%s': " "malformed return value from tcl lookup function: %s", zone, driver->interp->result); result = ISC_R_FAILURE; fail: return (result); }