diff --git a/CHANGES b/CHANGES index b4503afc1a..f1ab391f37 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +5849. [cleanup] Remove use of exclusive mode in ns_interfacemgr in + favor of rwlocked access to localhost and localnets + members of dns_aclenv_t structure. [GL #3229] + 5848. [bug] dig could hang in some cases involving multiple servers in a lookup, when a request fails and the next one refuses to start for some reason, for example if it was diff --git a/lib/dns/acl.c b/lib/dns/acl.c index f38ce3b64b..cea74f72d5 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -177,7 +177,7 @@ dns_acl_isnone(dns_acl_t *acl) { isc_result_t dns_acl_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, - const dns_acl_t *acl, const dns_aclenv_t *env, int *match, + const dns_acl_t *acl, dns_aclenv_t *env, int *match, const dns_aclelement_t **matchelt) { uint16_t bitlen; isc_prefix_t pfx; @@ -251,7 +251,7 @@ dns_acl_match_port_transport(const isc_netaddr_t *reqaddr, const in_port_t local_port, const isc_nmsocket_type_t transport, const bool encrypted, const dns_name_t *reqsigner, - const dns_acl_t *acl, const dns_aclenv_t *env, + const dns_acl_t *acl, dns_aclenv_t *env, int *match, const dns_aclelement_t **matchelt) { isc_result_t result = ISC_R_SUCCESS; dns_acl_port_transports_t *next; @@ -420,7 +420,7 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, bool pos) { bool dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, - const dns_aclelement_t *e, const dns_aclenv_t *env, + const dns_aclelement_t *e, dns_aclenv_t *env, const dns_aclelement_t **matchelt) { dns_acl_t *inner = NULL; int indirectmatch; @@ -439,21 +439,33 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, } case dns_aclelementtype_nestedacl: - inner = e->nestedacl; + dns_acl_attach(e->nestedacl, &inner); break; case dns_aclelementtype_localhost: - if (env == NULL || env->localhost == NULL) { + if (env == NULL) { return (false); } - inner = env->localhost; + RWLOCK(&env->rwlock, isc_rwlocktype_read); + if (env->localhost == NULL) { + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); + return (false); + } + dns_acl_attach(env->localhost, &inner); + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); break; case dns_aclelementtype_localnets: - if (env == NULL || env->localnets == NULL) { + if (env == NULL) { return (false); } - inner = env->localnets; + RWLOCK(&env->rwlock, isc_rwlocktype_read); + if (env->localnets == NULL) { + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); + return (false); + } + dns_acl_attach(env->localnets, &inner); + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); break; #if defined(HAVE_GEOIP2) @@ -471,6 +483,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, matchelt); INSIST(result == ISC_R_SUCCESS); + dns_acl_detach(&inner); + /* * Treat negative matches in indirect ACLs as "no match". * That way, a negated indirect ACL will never become a @@ -695,10 +709,11 @@ dns_aclenv_create(isc_mem_t *mctx, dns_aclenv_t **envp) { isc_mem_attach(mctx, &env->mctx); isc_refcount_init(&env->references, 1); + isc_rwlock_init(&env->rwlock, 0, 0); result = dns_acl_create(mctx, 0, &env->localhost); if (result != ISC_R_SUCCESS) { - goto cleanup_nothing; + goto cleanup_rwlock; } result = dns_acl_create(mctx, 0, &env->localnets); if (result != ISC_R_SUCCESS) { @@ -717,15 +732,31 @@ dns_aclenv_create(isc_mem_t *mctx, dns_aclenv_t **envp) { cleanup_localhost: dns_acl_detach(&env->localhost); -cleanup_nothing: +cleanup_rwlock: + isc_rwlock_destroy(&env->rwlock); + isc_mem_putanddetach(&env->mctx, env, sizeof(*env)); return (result); } +void +dns_aclenv_set(dns_aclenv_t *env, dns_acl_t *localhost, dns_acl_t *localnets) { + REQUIRE(VALID_ACLENV(env)); + + RWLOCK(&env->rwlock, isc_rwlocktype_write); + dns_acl_detach(&env->localhost); + dns_acl_attach(localhost, &env->localhost); + dns_acl_detach(&env->localnets); + dns_acl_attach(localnets, &env->localnets); + RWUNLOCK(&env->rwlock, isc_rwlocktype_write); +} + void dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) { REQUIRE(VALID_ACLENV(s)); REQUIRE(VALID_ACLENV(t)); + RWLOCK(&t->rwlock, isc_rwlocktype_write); + RWLOCK(&s->rwlock, isc_rwlocktype_read); dns_acl_detach(&t->localhost); dns_acl_attach(s->localhost, &t->localhost); dns_acl_detach(&t->localnets); @@ -735,6 +766,9 @@ dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) { #if defined(HAVE_GEOIP2) t->geoip = s->geoip; #endif /* if defined(HAVE_GEOIP2) */ + + RWUNLOCK(&s->rwlock, isc_rwlocktype_read); + RWUNLOCK(&t->rwlock, isc_rwlocktype_write); } static void @@ -743,12 +777,10 @@ dns__aclenv_destroy(dns_aclenv_t *aclenv) { aclenv->magic = 0; - if (aclenv->localhost != NULL) { - dns_acl_detach(&aclenv->localhost); - } - if (aclenv->localnets != NULL) { - dns_acl_detach(&aclenv->localnets); - } + isc_refcount_destroy(&aclenv->references); + dns_acl_detach(&aclenv->localhost); + dns_acl_detach(&aclenv->localnets); + isc_rwlock_destroy(&aclenv->rwlock); isc_mem_putanddetach(&aclenv->mctx, aclenv, sizeof(*aclenv)); } diff --git a/lib/dns/dns64.c b/lib/dns/dns64.c index 70304b53b9..b575726009 100644 --- a/lib/dns/dns64.c +++ b/lib/dns/dns64.c @@ -128,7 +128,7 @@ dns_dns64_destroy(dns_dns64_t **dns64p) { isc_result_t dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, - const dns_name_t *reqsigner, const dns_aclenv_t *env, + const dns_name_t *reqsigner, dns_aclenv_t *env, unsigned int flags, unsigned char *a, unsigned char *aaaa) { unsigned int nbytes, i; isc_result_t result; @@ -212,7 +212,7 @@ dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) { bool dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, - const dns_name_t *reqsigner, const dns_aclenv_t *env, + const dns_name_t *reqsigner, dns_aclenv_t *env, unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok, size_t aaaaoklen) { struct in6_addr in6; diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h index e6ca53d343..532b4592cd 100644 --- a/lib/dns/include/dns/acl.h +++ b/lib/dns/include/dns/acl.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -101,9 +102,12 @@ struct dns_aclenv { unsigned int magic; isc_mem_t *mctx; isc_refcount_t references; + + isc_rwlock_t rwlock; /*%< Locks localhost and localnets */ dns_acl_t *localhost; dns_acl_t *localnets; - bool match_mapped; + + bool match_mapped; #if defined(HAVE_GEOIP2) dns_geoip_databases_t *geoip; #endif /* HAVE_GEOIP2 */ @@ -219,6 +223,12 @@ dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s); *\li both 's' and 't' are valid ACL environments. */ +void +dns_aclenv_set(dns_aclenv_t *env, dns_acl_t *localhost, dns_acl_t *localnets); +/*%< + * Attach the 'localhost' and 'localnets' arguments to 'env' ACL environment + */ + void dns_aclenv_attach(dns_aclenv_t *source, dns_aclenv_t **targetp); /*%< @@ -240,7 +250,7 @@ dns_aclenv_detach(dns_aclenv_t **aclenvp); isc_result_t dns_acl_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, - const dns_acl_t *acl, const dns_aclenv_t *env, int *match, + const dns_acl_t *acl, dns_aclenv_t *env, int *match, const dns_aclelement_t **matchelt); /*%< * General, low-level ACL matching. This is expected to @@ -270,7 +280,7 @@ dns_acl_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, bool dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, - const dns_aclelement_t *e, const dns_aclenv_t *env, + const dns_aclelement_t *e, dns_aclenv_t *env, const dns_aclelement_t **matchelt); /*%< * Like dns_acl_match, but matches against the single ACL element 'e' @@ -287,7 +297,7 @@ dns_acl_match_port_transport(const isc_netaddr_t *reqaddr, const in_port_t local_port, const isc_nmsocket_type_t transport, const bool encrypted, const dns_name_t *reqsigner, - const dns_acl_t *acl, const dns_aclenv_t *env, + const dns_acl_t *acl, dns_aclenv_t *env, int *match, const dns_aclelement_t **matchelt); /*%< * Like dns_acl_match, but able to match the server port and diff --git a/lib/dns/include/dns/dns64.h b/lib/dns/include/dns/dns64.h index 069a491f5f..8dd01032b2 100644 --- a/lib/dns/include/dns/dns64.h +++ b/lib/dns/include/dns/dns64.h @@ -99,7 +99,7 @@ dns_dns64_destroy(dns_dns64_t **dns64p); isc_result_t dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, - const dns_name_t *reqsigner, const dns_aclenv_t *env, + const dns_name_t *reqsigner, dns_aclenv_t *env, unsigned int flags, unsigned char *a, unsigned char *aaaa); /* * dns_dns64_aaaafroma() determines whether to perform a DNS64 address @@ -147,7 +147,7 @@ dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64); bool dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, - const dns_name_t *reqsigner, const dns_aclenv_t *env, + const dns_name_t *reqsigner, dns_aclenv_t *env, unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok, size_t aaaaoklen); /* diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 2adf716259..a4246ee613 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -238,7 +238,7 @@ typedef struct dns_msgblock dns_msgblock_t; struct dns_sortlist_arg { dns_aclenv_t *env; - const dns_acl_t *acl; + dns_acl_t *acl; const dns_aclelement_t *element; }; @@ -1417,7 +1417,7 @@ dns_message_getrawmessage(dns_message_t *msg); void dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, - dns_aclenv_t *env, const dns_acl_t *acl, + dns_aclenv_t *env, dns_acl_t *acl, const dns_aclelement_t *element); /*%< * Define the order in which RR sets get rendered by diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h index 002ccc808d..ead0097632 100644 --- a/lib/dns/include/dns/ssu.h +++ b/lib/dns/include/dns/ssu.h @@ -143,7 +143,7 @@ dns_ssutable_addrule(dns_ssutable_t *table, bool grant, bool dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, const dns_name_t *name, const isc_netaddr_t *addr, - bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type, + bool tcp, dns_aclenv_t *env, dns_rdatatype_t type, const dns_name_t *target, const dst_key_t *key, const dns_ssurule_t **rulep); /*%< diff --git a/lib/dns/message.c b/lib/dns/message.c index 84f750e93d..ccfd6b61e5 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -642,6 +642,13 @@ msgreset(dns_message_t *msg, bool everything) { dynbuf = next_dynbuf; } + if (msg->order_arg.env != NULL) { + dns_aclenv_detach(&msg->order_arg.env); + } + if (msg->order_arg.acl != NULL) { + dns_acl_detach(&msg->order_arg.acl); + } + /* * Set other bits to normal default values. */ @@ -4457,15 +4464,19 @@ dns_message_getrawmessage(dns_message_t *msg) { void dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, - dns_aclenv_t *env, const dns_acl_t *acl, + dns_aclenv_t *env, dns_acl_t *acl, const dns_aclelement_t *elem) { REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE((order == NULL) == (env == NULL)); REQUIRE(env == NULL || (acl != NULL || elem != NULL)); msg->order = order; - msg->order_arg.env = env; - msg->order_arg.acl = acl; + if (env != NULL) { + dns_aclenv_attach(env, &msg->order_arg.env); + } + if (acl != NULL) { + dns_acl_attach(acl, &msg->order_arg.acl); + } msg->order_arg.element = elem; } diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index bc240ce669..5f3df90062 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -279,7 +279,7 @@ stf_from_address(dns_name_t *stfself, const isc_netaddr_t *tcpaddr) { bool dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, const dns_name_t *name, const isc_netaddr_t *addr, - bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type, + bool tcp, dns_aclenv_t *env, dns_rdatatype_t type, const dns_name_t *target, const dst_key_t *key, const dns_ssurule_t **rulep) { dns_fixedname_t fixed; @@ -367,8 +367,10 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, if (!dns_name_issubdomain(name, rule->name)) { continue; } + RWLOCK(&env->rwlock, isc_rwlocktype_read); dns_acl_match(addr, NULL, env->localhost, NULL, &match, NULL); + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); if (match == 0) { if (signer != NULL) { isc_log_write(dns_lctx, diff --git a/lib/ns/include/ns/sortlist.h b/lib/ns/include/ns/sortlist.h index 96f41e0348..f3ad3cb7f5 100644 --- a/lib/ns/include/ns/sortlist.h +++ b/lib/ns/include/ns/sortlist.h @@ -37,7 +37,7 @@ typedef enum { ns_sortlisttype_t ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr, - const void **argp); + void **argp); /*%< * Find the sortlist statement in 'acl' (for ACL environment 'env') * that applies to 'clientaddr', if any. @@ -70,7 +70,7 @@ ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg); void ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, dns_aclenv_t *env, isc_netaddr_t *client_addr, - dns_addressorderfunc_t *orderp, const void **argp); + dns_addressorderfunc_t *orderp, void **argp); /*%< * Find the sortlist statement in 'acl' that applies to 'clientaddr', if any. * If a sortlist statement applies, return in '*orderp' a pointer to a function diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index da7f6e8b2c..d3bdb953e4 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -74,7 +74,7 @@ struct ns_interfacemgr { isc_mem_t *mctx; /*%< Memory context */ ns_server_t *sctx; /*%< Server context */ isc_taskmgr_t *taskmgr; /*%< Task manager */ - isc_task_t *excl; /*%< Exclusive task */ + isc_task_t *task; /*%< Task */ isc_timermgr_t *timermgr; /*%< Timer manager */ isc_nm_t *nm; /*%< Net manager */ uint32_t ncpus; /*%< Number of workers */ @@ -97,16 +97,6 @@ purge_old_interfaces(ns_interfacemgr_t *mgr); static void clearlistenon(ns_interfacemgr_t *mgr); -static void -scan_event(isc_task_t *task, isc_event_t *event) { - ns_interfacemgr_t *mgr = (ns_interfacemgr_t *)event->ev_arg; - - UNUSED(task); - - ns_interfacemgr_scan(mgr, false, false); - isc_event_free(&event); -} - static bool need_rescan(ns_interfacemgr_t *mgr, struct MSGHDR *rtm, size_t len) { if (rtm->MSGTYPE != RTM_NEWADDR && rtm->MSGTYPE != RTM_DELADDR) { @@ -216,7 +206,6 @@ route_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *arg) { ns_interfacemgr_t *mgr = (ns_interfacemgr_t *)arg; struct MSGHDR *rtm = NULL; - bool done = true; size_t rtmlen; isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_DEBUG(9), "route_recv: %s", @@ -262,26 +251,13 @@ route_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } #endif /* ifdef RTM_VERSION */ - if (need_rescan(mgr, rtm, rtmlen) && mgr->route != NULL && - mgr->sctx->interface_auto) - { - isc_event_t *event = NULL; - event = isc_event_allocate(mgr->mctx, mgr, NS_EVENT_IFSCAN, - scan_event, mgr, sizeof(*event)); - isc_task_send(mgr->excl, &event); + REQUIRE(mgr->route != NULL); + + if (need_rescan(mgr, rtm, rtmlen) && mgr->sctx->interface_auto) { + ns_interfacemgr_scan(mgr, false, false); } - LOCK(&mgr->lock); - if (mgr->route != NULL) { - isc_nm_read(handle, route_recv, mgr); - done = false; - } - UNLOCK(&mgr->lock); - - if (done) { - isc_nmhandle_detach(&mgr->route); - ns_interfacemgr_detach(&mgr); - } + isc_nm_read(handle, route_recv, mgr); return; } @@ -333,7 +309,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_mutex_init(&mgr->lock); - result = isc_taskmgr_excltask(taskmgr, &mgr->excl); + result = isc_task_create_bound(taskmgr, 0, &mgr->task, 0); if (result != ISC_R_SUCCESS) { goto cleanup_lock; } @@ -348,7 +324,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, */ result = ns_listenlist_create(mctx, &mgr->listenon4); if (result != ISC_R_SUCCESS) { - goto cleanup_sctx; + goto cleanup_task; } ns_listenlist_attach(mgr->listenon4, &mgr->listenon6); @@ -389,9 +365,10 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, cleanup_listenon: ns_listenlist_detach(&mgr->listenon4); ns_listenlist_detach(&mgr->listenon6); +cleanup_task: + isc_task_detach(&mgr->task); cleanup_lock: isc_mutex_destroy(&mgr->lock); -cleanup_sctx: ns_server_detach(&mgr->sctx); isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); return (result); @@ -417,9 +394,7 @@ ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { if (mgr->sctx != NULL) { ns_server_detach(&mgr->sctx); } - if (mgr->excl != NULL) { - isc_task_detach(&mgr->excl); - } + isc_task_detach(&mgr->task); mgr->magic = 0; isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); } @@ -434,9 +409,15 @@ ns_interfacemgr_setbacklog(ns_interfacemgr_t *mgr, int backlog) { dns_aclenv_t * ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) { + dns_aclenv_t *aclenv = NULL; + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); - return (mgr->aclenv); + LOCK(&mgr->lock); + aclenv = mgr->aclenv; + UNLOCK(&mgr->lock); + + return (aclenv); } void @@ -810,9 +791,9 @@ purge_old_interfaces(ns_interfacemgr_t *mgr) { INSIST(NS_INTERFACE_VALID(ifp)); next = ISC_LIST_NEXT(ifp, link); if (ifp->generation != mgr->generation) { - char sabuf[256]; ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); if (LISTENING(ifp)) { + char sabuf[256]; isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf)); isc_log_write( @@ -826,20 +807,6 @@ purge_old_interfaces(ns_interfacemgr_t *mgr) { UNLOCK(&mgr->lock); } -static isc_result_t -clearacl(isc_mem_t *mctx, dns_acl_t **aclp) { - dns_acl_t *newacl = NULL; - isc_result_t result; - result = dns_acl_create(mctx, 0, &newacl); - if (result != ISC_R_SUCCESS) { - return (result); - } - dns_acl_detach(aclp); - dns_acl_attach(newacl, aclp); - dns_acl_detach(&newacl); - return (ISC_R_SUCCESS); -} - static bool listenon_is_ip6_any(ns_listenelt_t *elt) { REQUIRE(elt && elt->acl); @@ -847,7 +814,8 @@ listenon_is_ip6_any(ns_listenelt_t *elt) { } static isc_result_t -setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) { +setup_locals(isc_interface_t *interface, dns_acl_t *localhost, + dns_acl_t *localnets) { isc_result_t result; unsigned int prefixlen; isc_netaddr_t *netaddr; @@ -856,8 +824,8 @@ setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) { /* First add localhost address */ prefixlen = (netaddr->family == AF_INET) ? 32 : 128; - result = dns_iptable_addprefix(mgr->aclenv->localhost->iptable, netaddr, - prefixlen, true); + result = dns_iptable_addprefix(localhost->iptable, netaddr, prefixlen, + true); if (result != ISC_R_SUCCESS) { return (result); } @@ -887,8 +855,8 @@ setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) { return (ISC_R_SUCCESS); } - result = dns_iptable_addprefix(mgr->aclenv->localnets->iptable, netaddr, - prefixlen, true); + result = dns_iptable_addprefix(localnets->iptable, netaddr, prefixlen, + true); if (result != ISC_R_SUCCESS) { return (result); } @@ -911,30 +879,34 @@ setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface, old = ISC_LIST_NEXT(old, link)) { if (isc_sockaddr_equal(addr, old)) { - break; + /* We found an existing address */ + isc_mem_put(mgr->mctx, addr, sizeof(*addr)); + goto unlock; } } - if (old != NULL) { - isc_mem_put(mgr->mctx, addr, sizeof(*addr)); - } else { - ISC_LIST_APPEND(mgr->listenon, addr, link); - } + ISC_LIST_APPEND(mgr->listenon, addr, link); +unlock: UNLOCK(&mgr->lock); } static void clearlistenon(ns_interfacemgr_t *mgr) { + ISC_LIST(isc_sockaddr_t) listenon; isc_sockaddr_t *old; + ISC_LIST_INIT(listenon); + LOCK(&mgr->lock); - old = ISC_LIST_HEAD(mgr->listenon); - while (old != NULL) { - ISC_LIST_UNLINK(mgr->listenon, old, link); - isc_mem_put(mgr->mctx, old, sizeof(*old)); - old = ISC_LIST_HEAD(mgr->listenon); - } + ISC_LIST_MOVE(listenon, mgr->listenon); UNLOCK(&mgr->lock); + + old = ISC_LIST_HEAD(listenon); + while (old != NULL) { + ISC_LIST_UNLINK(listenon, old, link); + isc_mem_put(mgr->mctx, old, sizeof(*old)); + old = ISC_LIST_HEAD(listenon); + } } static isc_result_t @@ -946,7 +918,7 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { bool ipv6pktinfo = true; isc_result_t result; isc_netaddr_t zero_address, zero_address6; - ns_listenelt_t *le; + ns_listenelt_t *le = NULL; isc_sockaddr_t listen_addr; ns_interface_t *ifp = NULL; bool log_explicit = false; @@ -954,6 +926,8 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { char sabuf[ISC_SOCKADDR_FORMATSIZE]; bool tried_listening; bool all_addresses_in_use; + dns_acl_t *localhost = NULL; + dns_acl_t *localnets = NULL; if (isc_net_probeipv6() == ISC_R_SUCCESS) { scan_ipv6 = true; @@ -1067,14 +1041,15 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { return (result); } - result = clearacl(mgr->mctx, &mgr->aclenv->localhost); + result = dns_acl_create(mgr->mctx, 0, &localhost); if (result != ISC_R_SUCCESS) { goto cleanup_iter; } - result = clearacl(mgr->mctx, &mgr->aclenv->localnets); + result = dns_acl_create(mgr->mctx, 0, &localnets); if (result != ISC_R_SUCCESS) { - goto cleanup_iter; + goto cleanup_localhost; } + clearlistenon(mgr); tried_listening = false; @@ -1083,7 +1058,7 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { result = isc_interfaceiter_next(iter)) { isc_interface_t interface; - ns_listenlist_t *ll; + ns_listenlist_t *ll = NULL; unsigned int family; result = isc_interfaceiter_current(iter, &interface); @@ -1128,7 +1103,7 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { goto listenon; } - result = setup_locals(mgr, &interface); + result = setup_locals(&interface, localhost, localnets); if (result != ISC_R_SUCCESS) { goto ignore_interface; } @@ -1276,17 +1251,27 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { ? ISC_R_ADDRINUSE : ISC_R_SUCCESS); } + + dns_aclenv_set(mgr->aclenv, localhost, localnets); + + /* cleanup_localnets: */ + dns_acl_detach(&localnets); + +cleanup_localhost: + dns_acl_detach(&localhost); + cleanup_iter: isc_interfaceiter_destroy(&iter); return (result); } -static isc_result_t -ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, bool verbose, bool config) { +isc_result_t +ns_interfacemgr_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { isc_result_t result; bool purge = true; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); + REQUIRE(isc_nm_tid() == 0); mgr->generation++; /* Increment the generation count. */ @@ -1323,30 +1308,6 @@ ns_interfacemgr_islistening(ns_interfacemgr_t *mgr) { return (ISC_LIST_EMPTY(mgr->interfaces) ? false : true); } -isc_result_t -ns_interfacemgr_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { - isc_result_t result; - bool unlock = false; - - /* - * Check for success because we may already be task-exclusive - * at this point. Only if we succeed at obtaining an exclusive - * lock now will we need to relinquish it later. - */ - result = isc_task_beginexclusive(mgr->excl); - if (result == ISC_R_SUCCESS) { - unlock = true; - } - - result = ns_interfacemgr_scan0(mgr, verbose, config); - - if (unlock) { - isc_task_endexclusive(mgr->excl); - } - - return (result); -} - void ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) { REQUIRE(NS_INTERFACEMGR_VALID(mgr)); diff --git a/lib/ns/query.c b/lib/ns/query.c index b9e76eb897..ec6b379a0d 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -11584,20 +11584,25 @@ query_setup_sortlist(query_ctx_t *qctx) { isc_netaddr_t netaddr; ns_client_t *client = qctx->client; dns_aclenv_t *env = client->manager->aclenv; - const void *order_arg = NULL; + dns_acl_t *acl = NULL; + dns_aclelement_t *elt = NULL; + void *order_arg = NULL; isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); switch (ns_sortlist_setup(client->view->sortlist, env, &netaddr, &order_arg)) { case NS_SORTLISTTYPE_1ELEMENT: + elt = order_arg; dns_message_setsortorder(client->message, query_sortlist_order_1element, env, - NULL, order_arg); + NULL, elt); break; case NS_SORTLISTTYPE_2ELEMENT: + acl = order_arg; dns_message_setsortorder(client->message, query_sortlist_order_2element, env, - order_arg, NULL); + acl, NULL); + dns_acl_detach(&acl); break; case NS_SORTLISTTYPE_NONE: break; diff --git a/lib/ns/sortlist.c b/lib/ns/sortlist.c index 0c3dc40bf2..3e6a3517e9 100644 --- a/lib/ns/sortlist.c +++ b/lib/ns/sortlist.c @@ -25,14 +25,12 @@ ns_sortlisttype_t ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr, - const void **argp) { - unsigned int i; - + void **argp) { if (acl == NULL) { goto dont_sort; } - for (i = 0; i < acl->length; i++) { + for (size_t i = 0; i < acl->length; i++) { /* * 'e' refers to the current 'top level statement' * in the sortlist (see ARM). @@ -40,7 +38,7 @@ ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr, dns_aclelement_t *e = &acl->elements[i]; dns_aclelement_t *try_elt; dns_aclelement_t *order_elt = NULL; - const dns_aclelement_t *matched_elt = NULL; + dns_aclelement_t *matched_elt = NULL; if (e->type == dns_aclelementtype_nestedacl) { dns_acl_t *inner = e->nestedacl; @@ -65,43 +63,62 @@ ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr, try_elt = e; } - if (dns_aclelement_match(clientaddr, NULL, try_elt, env, - &matched_elt)) { - if (order_elt != NULL) { - if (order_elt->type == - dns_aclelementtype_nestedacl) { - *argp = order_elt->nestedacl; - return (NS_SORTLISTTYPE_2ELEMENT); - } else if (order_elt->type == - dns_aclelementtype_localhost && - env->localhost != NULL) - { - *argp = env->localhost; - return (NS_SORTLISTTYPE_2ELEMENT); - } else if (order_elt->type == - dns_aclelementtype_localnets && - env->localnets != NULL) - { - *argp = env->localnets; - return (NS_SORTLISTTYPE_2ELEMENT); - } else { - /* - * BIND 8 allows a bare IP prefix as - * the 2nd element of a 2-element - * sortlist statement. - */ - *argp = order_elt; - return (NS_SORTLISTTYPE_1ELEMENT); - } - } else { - INSIST(matched_elt != NULL); - *argp = matched_elt; - return (NS_SORTLISTTYPE_1ELEMENT); + if (!dns_aclelement_match( + clientaddr, NULL, try_elt, env, + (const dns_aclelement_t **)&matched_elt)) + { + continue; + } + + if (order_elt == NULL) { + INSIST(matched_elt != NULL); + *argp = matched_elt; + return (NS_SORTLISTTYPE_1ELEMENT); + } + + if (order_elt->type == dns_aclelementtype_nestedacl) { + dns_acl_t *inner = NULL; + dns_acl_attach(order_elt->nestedacl, &inner); + *argp = inner; + return (NS_SORTLISTTYPE_2ELEMENT); + } + + if (order_elt->type == dns_aclelementtype_localhost) { + dns_acl_t *inner = NULL; + RWLOCK(&env->rwlock, isc_rwlocktype_read); + if (env->localhost != NULL) { + dns_acl_attach(env->localhost, &inner); + } + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); + + if (inner != NULL) { + *argp = inner; + return (NS_SORTLISTTYPE_2ELEMENT); } } + + if (order_elt->type == dns_aclelementtype_localnets) { + dns_acl_t *inner = NULL; + RWLOCK(&env->rwlock, isc_rwlocktype_read); + if (env->localnets != NULL) { + dns_acl_attach(env->localnets, &inner); + } + RWUNLOCK(&env->rwlock, isc_rwlocktype_read); + if (inner != NULL) { + *argp = inner; + return (NS_SORTLISTTYPE_2ELEMENT); + } + } + + /* + * BIND 8 allows a bare IP prefix as + * the 2nd element of a 2-element + * sortlist statement. + */ + *argp = order_elt; + return (NS_SORTLISTTYPE_1ELEMENT); } - /* No match; don't sort. */ dont_sort: *argp = NULL; return (NS_SORTLISTTYPE_NONE); @@ -110,7 +127,7 @@ dont_sort: int ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; - const dns_aclenv_t *env = sla->env; + dns_aclenv_t *env = sla->env; const dns_acl_t *sortacl = sla->acl; int match; @@ -127,7 +144,7 @@ ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { int ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; - const dns_aclenv_t *env = sla->env; + dns_aclenv_t *env = sla->env; const dns_aclelement_t *element = sla->element; if (dns_aclelement_match(addr, NULL, element, env, NULL)) { @@ -140,7 +157,7 @@ ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { void ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, dns_aclenv_t *env, isc_netaddr_t *client_addr, - dns_addressorderfunc_t *orderp, const void **argp) { + dns_addressorderfunc_t *orderp, void **argp) { ns_sortlisttype_t sortlisttype; sortlisttype = ns_sortlist_setup(sortlist_acl, env, client_addr, argp);