diff --git a/CHANGES b/CHANGES index 0ee3ee6977..ec63783a19 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +5730. [func] The resolver and the request and dispatch managers + have been substantially refactored, and are now + based on the network manager instead of the old + isc_socket API. All outgoing DNS queries and + requests now use the new API; isc_socket is only + used to monitor for network interface changes. + [GL #2401] + 5729. [func] Allow finer control over the TLS protocol by implementing more options within "tls" clauses, namely: - Diffie-Hellman parameters via diff --git a/bin/delv/delv.c b/bin/delv/delv.c index dd1181076b..3559f1bf63 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -1725,7 +1725,6 @@ main(int argc, char *argv[]) { isc_appctx_t *actx = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_socketmgr_t *socketmgr = NULL; isc_timermgr_t *timermgr = NULL; dns_master_style_t *style = NULL; struct sigaction sa; @@ -1744,8 +1743,8 @@ main(int argc, char *argv[]) { isc_mem_create(&mctx); CHECK(isc_appctx_create(mctx, &actx)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, NULL); parse_args(argc, argv); @@ -1763,7 +1762,7 @@ main(int argc, char *argv[]) { } /* Create client */ - result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, 0, + result = dns_client_create(mctx, actx, taskmgr, netmgr, timermgr, 0, &client, srcaddr4, srcaddr6); if (result != ISC_R_SUCCESS) { delv_log(ISC_LOG_ERROR, "dns_client_create: %s", @@ -1846,7 +1845,9 @@ cleanup: if (client != NULL) { dns_client_detach(&client); } - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, NULL); + if (actx != NULL) { isc_appctx_destroy(&actx); } diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c index 3669cac1dc..caa1055877 100644 --- a/bin/named/controlconf.c +++ b/bin/named/controlconf.c @@ -1050,6 +1050,8 @@ update_listener(named_controls_t *cp, controllistener_t **listenerp, socktext, isc_result_totext(result)); } +#if 0 + /* XXX: no unix socket support yet */ if (result == ISC_R_SUCCESS && type == isc_socktype_unix) { uint32_t perm, owner, group; perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); @@ -1073,6 +1075,7 @@ update_listener(named_controls_t *cp, controllistener_t **listenerp, socktext); } } +#endif *listenerp = listener; } diff --git a/bin/named/server.c b/bin/named/server.c index e9d3bdc59e..31c9af5572 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -160,12 +160,8 @@ #ifdef TUNE_LARGE #define RESOLVER_NTASKS_PERCPU 32 -#define UDPBUFFERS 32768 -#define EXCLBUFFERS 32768 #else #define RESOLVER_NTASKS_PERCPU 8 -#define UDPBUFFERS 1000 -#define EXCLBUFFERS 4096 #endif /* TUNE_LARGE */ /* RFC7828 defines timeout as 16-bit value specified in units of 100 @@ -1260,11 +1256,9 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, dns_dispatch_t **dispatchp, isc_dscp_t *dscpp, bool is_firstview) { isc_result_t result = ISC_R_FAILURE; - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; isc_sockaddr_t sa; - unsigned int attrs; const cfg_obj_t *obj = NULL; - unsigned int maxdispatchbuffers = UDPBUFFERS; isc_dscp_t dscp = -1; switch (af) { @@ -1310,20 +1304,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, /* * Try to find a dispatcher that we can share. */ - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; - switch (af) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - } - if (isc_sockaddr_getport(&sa) == 0) { - attrs |= DNS_DISPATCHATTR_EXCLUSIVE; - maxdispatchbuffers = EXCLBUFFERS; - } else { + if (isc_sockaddr_getport(&sa) != 0) { INSIST(obj != NULL); if (is_firstview) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO, @@ -1333,10 +1314,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } } - disp = NULL; - result = dns_dispatch_getudp( - named_g_dispatchmgr, named_g_socketmgr, named_g_taskmgr, &sa, - 4096, maxdispatchbuffers, 32768, 16411, 16433, attrs, &disp); + result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -4708,8 +4686,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, /* * Resolver. - * - * XXXRTH Hardwired number of tasks. */ CHECK(get_view_querysource_dispatch( maps, AF_INET, &dispatch4, &dscp4, @@ -4719,7 +4695,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, (ISC_LIST_PREV(view, link) == NULL))); if (dispatch4 == NULL && dispatch6 == NULL) { UNEXPECTED_ERROR(__FILE__, __LINE__, - "unable to obtain neither an IPv4 nor" + "unable to obtain either an IPv4 or" " an IPv6 dispatch"); result = ISC_R_UNEXPECTED; goto cleanup; @@ -4738,7 +4714,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH); CHECK(dns_view_createresolver( view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus, - ndisp, named_g_socketmgr, named_g_timermgr, resopts, + ndisp, named_g_netmgr, named_g_timermgr, resopts, named_g_dispatchmgr, dispatch4, dispatch6)); if (dscp4 == -1) { @@ -9884,7 +9860,8 @@ run_server(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); - CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr), + CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr, + &named_g_dispatchmgr), "creating dispatch manager"); dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats); @@ -9898,8 +9875,8 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(ns_interfacemgr_create( named_g_mctx, server->sctx, named_g_taskmgr, named_g_timermgr, named_g_socketmgr, named_g_netmgr, - named_g_dispatchmgr, server->task, named_g_udpdisp, - geoip, named_g_cpus, &server->interfacemgr), + named_g_dispatchmgr, server->task, geoip, + named_g_cpus, &server->interfacemgr), "creating interface manager"); CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, @@ -10024,7 +10001,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ns_interfacemgr_detach(&server->interfacemgr); - dns_dispatchmgr_destroy(&named_g_dispatchmgr); + dns_dispatchmgr_detach(&named_g_dispatchmgr); dns_zonemgr_shutdown(server->zonemgr); @@ -10166,8 +10143,8 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) { server->heartbeat_interval = 0; CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr, - named_g_timermgr, named_g_socketmgr, - named_g_netmgr, &server->zonemgr), + named_g_timermgr, named_g_netmgr, + &server->zonemgr), "dns_zonemgr_create"); CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_" "setsize"); @@ -10352,7 +10329,6 @@ named_add_reserved_dispatch(named_server_t *server, in_port_t port; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; isc_result_t result; - unsigned int attrs; REQUIRE(NAMED_SERVER_VALID(server)); @@ -10379,24 +10355,8 @@ named_add_reserved_dispatch(named_server_t *server, dispatch->dispatchgen = server->dispatchgen; dispatch->dispatch = NULL; - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; - switch (isc_sockaddr_pf(addr)) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - - result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, 4096, - UDPBUFFERS, 32768, 16411, 16433, attrs, - &dispatch->dispatch); + result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr, + &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index fc46a85ce0..4aa9289cb2 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -38,11 +39,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -97,7 +96,6 @@ #define MAXCMD (128 * 1024) #define MAXWIRE (64 * 1024) -#define PACKETSIZE ((64 * 1024) - 1) #define INITTEXT (2 * 1024) #define MAXTEXT (128 * 1024) #define FIND_TIMEOUT 5 @@ -132,8 +130,6 @@ static isc_log_t *glctx = NULL; static isc_mem_t *gmctx = NULL; static dns_dispatchmgr_t *dispatchmgr = NULL; static dns_requestmgr_t *requestmgr = NULL; -static isc_socketmgr_t *socketmgr = NULL; -static isc_timermgr_t *timermgr = NULL; static dns_dispatch_t *dispatchv4 = NULL; static dns_dispatch_t *dispatchv6 = NULL; static dns_message_t *updatemsg = NULL; @@ -739,14 +735,15 @@ doshutdown(void) { } ddebug("Shutting down dispatch manager"); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } static void maybeshutdown(void) { /* when called from getinput, doshutdown might be already finished */ - if (requestmgr == NULL) + if (requestmgr == NULL) { return; + } ddebug("Shutting down request manager"); dns_requestmgr_shutdown(requestmgr); @@ -802,7 +799,6 @@ static void setup_system(void) { isc_result_t result; isc_sockaddr_t bind_any, bind_any6; - unsigned int attrs; isc_sockaddrlist_t *nslist; isc_logconfig_t *logconfig = NULL; irs_resconf_t *resconf = NULL; @@ -919,11 +915,12 @@ setup_system(void) { irs_resconf_destroy(&resconf); - result = dns_dispatchmgr_create(gmctx, &dispatchmgr); - check_result(result, "dns_dispatchmgr_create"); + result = isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, NULL, + NULL); + check_result(result, "isc_managers_create"); - isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + result = dns_dispatchmgr_create(gmctx, netmgr, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); result = isc_task_create(taskmgr, 0, &global_task); check_result(result, "isc_task_create"); @@ -938,30 +935,21 @@ setup_system(void) { set_source_ports(dispatchmgr); if (have_ipv6) { - attrs = DNS_DISPATCHATTR_UDP; - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - attrs |= DNS_DISPATCHATTR_IPV6; isc_sockaddr_any6(&bind_any6); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any6, PACKETSIZE, 4, 2, 3, 5, - attrs, &dispatchv6); - check_result(result, "dns_dispatch_getudp (v6)"); + result = dns_dispatch_createudp(dispatchmgr, &bind_any6, + &dispatchv6); + check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { - attrs = DNS_DISPATCHATTR_UDP; - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - attrs |= DNS_DISPATCHATTR_IPV4; isc_sockaddr_any(&bind_any); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, PACKETSIZE, 4, 2, 3, 5, - attrs, &dispatchv4); - check_result(result, "dns_dispatch_getudp (v4)"); + result = dns_dispatch_createudp(dispatchmgr, &bind_any, + &dispatchv4); + check_result(result, "dns_dispatch_createudp (v4)"); } - result = dns_requestmgr_create(gmctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, dispatchv6, - &requestmgr); + result = dns_requestmgr_create(gmctx, taskmgr, dispatchmgr, dispatchv4, + dispatchv6, &requestmgr); check_result(result, "dns_requestmgr_create"); if (keystr != NULL) { @@ -3332,7 +3320,7 @@ cleanup(void) { } ddebug("Shutting down managers"); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); ddebug("Destroying event"); isc_event_free(&global_event); diff --git a/bin/tests/system/hooks/prereq.sh b/bin/tests/system/hooks/prereq.sh new file mode 100644 index 0000000000..140acc3d36 --- /dev/null +++ b/bin/tests/system/hooks/prereq.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +. ../conf.sh + +$FEATURETEST --tsan && { + echo_i "TSAN - skipping hooks test" + exit 255 +} + +exit 0 diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index b4595c7eff..342ff12039 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -23,12 +23,11 @@ #include #include #include +#include #include #include #include -#include #include -#include #include #include @@ -59,8 +58,8 @@ #define PORT 5300 #define TIMEOUT 30 -static isc_mem_t *mctx; -static dns_requestmgr_t *requestmgr; +static isc_mem_t *mctx = NULL; +static dns_requestmgr_t *requestmgr = NULL; static bool have_src = false; static isc_sockaddr_t srcaddr; static isc_sockaddr_t dstaddr; @@ -70,7 +69,8 @@ static void recvresponse(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query, *response; + dns_message_t *query = NULL; + dns_message_t *response = NULL; isc_buffer_t outbuf; char output[1024]; @@ -86,7 +86,6 @@ recvresponse(isc_task_t *task, isc_event_t *event) { query = reqev->ev_arg; - response = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); result = dns_request_getresponse(reqev->request, response, @@ -126,10 +125,10 @@ recvresponse(isc_task_t *task, isc_event_t *event) { static isc_result_t sendquery(isc_task_t *task) { - dns_request_t *request; - dns_message_t *message; - dns_name_t *qname; - dns_rdataset_t *qrdataset; + dns_request_t *request = NULL; + dns_message_t *message = NULL; + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; isc_result_t result; dns_fixedname_t queryname; isc_buffer_t buf; @@ -150,7 +149,6 @@ sendquery(isc_task_t *task) { dns_rootname, 0, NULL); CHECK("dns_name_fromtext", result); - message = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); message->opcode = dns_opcode_query; @@ -158,11 +156,9 @@ sendquery(isc_task_t *task) { message->rdclass = dns_rdataclass_in; message->id = (unsigned short)(random() & 0xFFFF); - qname = NULL; result = dns_message_gettempname(message, &qname); CHECK("dns_message_gettempname", result); - qrdataset = NULL; result = dns_message_gettemprdataset(message, &qrdataset); CHECK("dns_message_gettemprdataset", result); @@ -172,11 +168,10 @@ sendquery(isc_task_t *task) { ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(message, qname, DNS_SECTION_QUESTION); - request = NULL; - result = dns_request_createvia( - requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, -1, - DNS_REQUESTOPT_TCP | DNS_REQUESTOPT_SHARE, NULL, TIMEOUT, 0, 0, - task, recvresponse, message, &request); + result = dns_request_createvia(requestmgr, message, + have_src ? &srcaddr : NULL, &dstaddr, -1, + DNS_REQUESTOPT_TCP, NULL, TIMEOUT, 0, 0, + task, recvresponse, message, &request); CHECK("dns_request_create", result); return (ISC_R_SUCCESS); @@ -203,17 +198,14 @@ main(int argc, char *argv[]) { isc_sockaddr_t bind_any; struct in_addr inaddr; isc_result_t result; - isc_log_t *lctx; - isc_logconfig_t *lcfg; + isc_log_t *lctx = NULL; + isc_logconfig_t *lcfg = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; - unsigned int attrs; - dns_dispatch_t *dispatchv4; - dns_view_t *view; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; uint16_t port = PORT; int c; @@ -267,35 +259,22 @@ main(int argc, char *argv[]) { } isc_sockaddr_fromin(&dstaddr, &inaddr, port); - mctx = NULL; isc_mem_create(&mctx); - lctx = NULL; - lcfg = NULL; isc_log_create(mctx, &lctx, &lcfg); RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4096, 4, - 2, 3, 5, attrs, &dispatchv4)); - requestmgr = NULL; - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp( + dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); - RUNCHECK(isc_app_onrun(mctx, task, sendqueries, NULL)); (void)isc_app_run(); @@ -306,12 +285,12 @@ main(int argc, char *argv[]) { dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/bin/tests/system/qmin/ns5/named.conf.in b/bin/tests/system/qmin/ns5/named.conf.in index b4163ab066..2171a6265a 100644 --- a/bin/tests/system/qmin/ns5/named.conf.in +++ b/bin/tests/system/qmin/ns5/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization disabled; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/qmin/ns6/named.conf.in b/bin/tests/system/qmin/ns6/named.conf.in index c5fe9adc60..ec34d03146 100644 --- a/bin/tests/system/qmin/ns6/named.conf.in +++ b/bin/tests/system/qmin/ns6/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization strict; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/qmin/ns7/named.conf.in b/bin/tests/system/qmin/ns7/named.conf.in index 0f69d2d26b..50fce36c50 100644 --- a/bin/tests/system/qmin/ns7/named.conf.in +++ b/bin/tests/system/qmin/ns7/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization relaxed; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/resolve.c b/bin/tests/system/resolve.c index c13cb5bee4..6508b6e9ff 100644 --- a/bin/tests/system/resolve.c +++ b/bin/tests/system/resolve.c @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -58,13 +58,11 @@ isc_mem_t *ctxs_mctx = NULL; isc_appctx_t *ctxs_actx = NULL; isc_nm_t *ctxs_netmgr = NULL; isc_taskmgr_t *ctxs_taskmgr = NULL; -isc_socketmgr_t *ctxs_socketmgr = NULL; isc_timermgr_t *ctxs_timermgr = NULL; static void ctxs_destroy(void) { - isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, - &ctxs_socketmgr); + isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, NULL); if (ctxs_actx != NULL) { isc_appctx_destroy(&ctxs_actx); @@ -87,7 +85,7 @@ ctxs_init(void) { } isc_managers_create(ctxs_mctx, 1, 0, 0, &ctxs_netmgr, &ctxs_taskmgr, - &ctxs_timermgr, &ctxs_socketmgr); + &ctxs_timermgr, NULL); result = isc_app_ctxstart(ctxs_actx); if (result != ISC_R_SUCCESS) { @@ -102,7 +100,7 @@ fail: return (result); } -static char *algname; +static char *algname = NULL; static isc_result_t printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { @@ -281,9 +279,9 @@ main(int argc, char *argv[]) { isc_buffer_t b; dns_fixedname_t qname0; unsigned int namelen; - dns_name_t *qname, *name; + dns_name_t *qname = NULL, *name = NULL; dns_rdatatype_t type = dns_rdatatype_a; - dns_rdataset_t *rdataset; + dns_rdataset_t *rdataset = NULL; dns_namelist_t namelist; unsigned int clientopt, resopt = 0; bool is_sep = false; @@ -406,7 +404,7 @@ main(int argc, char *argv[]) { clientopt = 0; result = dns_client_create(ctxs_mctx, ctxs_actx, ctxs_taskmgr, - ctxs_socketmgr, ctxs_timermgr, clientopt, + ctxs_netmgr, ctxs_timermgr, clientopt, &client, addr4, addr6); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_client_create failed: %u, %s\n", result, diff --git a/bin/tests/system/rpz/tests.sh b/bin/tests/system/rpz/tests.sh index c888289db4..b88fe62a48 100644 --- a/bin/tests/system/rpz/tests.sh +++ b/bin/tests/system/rpz/tests.sh @@ -453,6 +453,9 @@ make_proto_nodata() { return 0 } +# ensure that the fast-expire zone is populated before we begin testing +$RNDCCMD $ns3 retransfer fast-expire + for mode in native dnsrps; do status=0 case ${mode} in diff --git a/bin/tests/system/serve-stale/ns3/named2.conf.in b/bin/tests/system/serve-stale/ns3/named2.conf.in index 40c053e07f..57919b7bbe 100644 --- a/bin/tests/system/serve-stale/ns3/named2.conf.in +++ b/bin/tests/system/serve-stale/ns3/named2.conf.in @@ -37,9 +37,9 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 0; - stale-answer-client-timeout 1800; + stale-answer-client-timeout 1800; # 1.8 seconds max-stale-ttl 3600; - resolver-query-timeout 10; + resolver-query-timeout 30000; # 30 seconds }; zone "." { diff --git a/bin/tests/system/serve-stale/ns3/named3.conf.in b/bin/tests/system/serve-stale/ns3/named3.conf.in index 7d50bc8ff8..5a840e9cdf 100644 --- a/bin/tests/system/serve-stale/ns3/named3.conf.in +++ b/bin/tests/system/serve-stale/ns3/named3.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-refresh-time 0; max-stale-ttl 3600; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds }; zone "." { diff --git a/bin/tests/system/serve-stale/ns3/named4.conf.in b/bin/tests/system/serve-stale/ns3/named4.conf.in index 5fd5ef82f4..af3bd868a2 100644 --- a/bin/tests/system/serve-stale/ns3/named4.conf.in +++ b/bin/tests/system/serve-stale/ns3/named4.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-answer-client-timeout 0; stale-refresh-time 0; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; }; diff --git a/bin/tests/system/serve-stale/ns3/named5.conf.in b/bin/tests/system/serve-stale/ns3/named5.conf.in index 92b2cdf108..e62de8bfb1 100644 --- a/bin/tests/system/serve-stale/ns3/named5.conf.in +++ b/bin/tests/system/serve-stale/ns3/named5.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-answer-client-timeout 0; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; }; diff --git a/bin/tests/system/serve-stale/ns3/named6.conf.in b/bin/tests/system/serve-stale/ns3/named6.conf.in index 2b7c42c456..92c0eaf057 100644 --- a/bin/tests/system/serve-stale/ns3/named6.conf.in +++ b/bin/tests/system/serve-stale/ns3/named6.conf.in @@ -37,7 +37,7 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; diff --git a/bin/tests/system/serve-stale/ns3/named7.conf.in b/bin/tests/system/serve-stale/ns3/named7.conf.in index 10e77d7d25..c3582ba084 100644 --- a/bin/tests/system/serve-stale/ns3/named7.conf.in +++ b/bin/tests/system/serve-stale/ns3/named7.conf.in @@ -41,7 +41,7 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; diff --git a/bin/tests/system/serve-stale/tests.sh b/bin/tests/system/serve-stale/tests.sh index c49f6647bf..b524630d9e 100755 --- a/bin/tests/system/serve-stale/tests.sh +++ b/bin/tests/system/serve-stale/tests.sh @@ -124,7 +124,7 @@ $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 longttl.example TXT > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+3)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+4)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+5)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+5)) & wait @@ -282,7 +282,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -336,7 +336,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -402,7 +402,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -594,7 +594,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -672,7 +672,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1006,7 +1006,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1094,7 +1094,7 @@ $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & $DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & -$DIG -p ${PORT} @10.53.0.3 notfound.example TXT > dig.out.test$((n+5)) +$DIG -p ${PORT} @10.53.0.3 notfound.example TXT > dig.out.test$((n+5)) & wait @@ -1247,7 +1247,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.4 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.4 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.4 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1453,7 +1453,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.5 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.5 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.5 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1651,8 +1651,8 @@ nextpart ns3/named.run > /dev/null echo_i "sending queries for tests $((n+1))-$((n+2))..." t1=`$PERL -e 'print time()'` -$DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & -$DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 nodata.example TXT > dig.out.test$((n+2)) +$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & +$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 nodata.example TXT > dig.out.test$((n+2)) & wait t2=`$PERL -e 'print time()'` @@ -1687,14 +1687,14 @@ status=$((status+ret)) nextpart ns3/named.run > /dev/null echo_i "sending queries for tests $((n+2))-$((n+3))..." -$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example TXT > dig.out.test$((n+2)) & +# first dig runs in background for 3 seconds, second in foreground for 3 $DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 longttl.example TXT > dig.out.test$((n+3)) & +$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example TXT > dig.out.test$((n+2)) # Enable the authoritative name server after stale-answer-client-timeout. n=$((n+1)) echo_i "enable responses from authoritative server ($n)" ret=0 -sleep 4 $DIG -p ${PORT} @10.53.0.2 txt enable > dig.out.test$n grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1 grep "TXT.\"1\"" dig.out.test$n > /dev/null || ret=1 @@ -1705,25 +1705,17 @@ n=$((n+1)) echo_i "check not in cache longttl.example times out (stale-answer-client-timeout 1.8) ($n)" ret=0 wait_for_log 4 "longttl.example client timeout, stale answer unavailable" ns3/named.run || ret=1 -check_results() { - [ -s "$1" ] || return 1 - grep "connection timed out" "$1" > /dev/null || return 1 - return 0 -} -retry_quiet 4 check_results dig.out.test$n || ret=1 +grep "connection timed out" dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) +wait + n=$((n+1)) echo_i "check not in cache longttl.example comes from authoritative (stale-answer-client-timeout 1.8) ($n)" ret=0 -check_results() { - [ -s "$1" ] || return 1 - grep "status: NOERROR" "$1" > /dev/null || return 1 - grep "ANSWER: 1," "$1" > /dev/null || return 1 - return 0 -} -retry_quiet 8 check_results dig.out.test$n || ret=1 +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) @@ -2214,7 +2206,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & wait diff --git a/bin/tests/system/statistics/tests.sh b/bin/tests/system/statistics/tests.sh index 2c44788ce1..b019dfac69 100644 --- a/bin/tests/system/statistics/tests.sh +++ b/bin/tests/system/statistics/tests.sh @@ -11,8 +11,7 @@ . ../conf.sh -DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd" -DIGCMD="$DIG $DIGOPTS -p ${PORT}" +DIGCMD="$DIG +tcp -p ${PORT}" RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../common/rndc.conf" status=0 @@ -163,8 +162,8 @@ n=`expr $n + 1` ret=0 echo_i "checking bind9.xsl vs xml ($n)" if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; then - $DIGCMD +notcp +recurse @10.53.0.3 soa . > /dev/null 2>&1 - $DIGCMD +notcp +recurse @10.53.0.3 soa example > /dev/null 2>&1 + $DIGCMD +notcp +recurse @10.53.0.3 soa . > dig.out.test$n.1 2>&1 + $DIGCMD +notcp +recurse @10.53.0.3 soa example > dig.out.test$n.2 2>&1 ${CURL} http://10.53.0.3:${EXTRAPORT1}/xml/v3 > curl.out.${n}.xml 2>/dev/null || ret=1 ${CURL} http://10.53.0.3:${EXTRAPORT1}/bind9.xsl > curl.out.${n}.xsl 2>/dev/null || ret=1 ${XSLTPROC} curl.out.${n}.xsl - < curl.out.${n}.xml > xsltproc.out.${n} 2>/dev/null || ret=1 @@ -181,7 +180,7 @@ if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; th grep "

View " xsltproc.out.${n} >/dev/null || ret=1 grep "

Server Statistics

" xsltproc.out.${n} >/dev/null || ret=1 grep "

Zone Maintenance Statistics

" xsltproc.out.${n} >/dev/null || ret=1 - grep "

Resolver Statistics (Common)

" xsltproc.out.${n} >/dev/null || ret=1 + # grep "

Resolver Statistics (Common)

" xsltproc.out.${n} >/dev/null || ret=1 grep "

Resolver Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 grep "

ADB Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 grep "

Cache Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 @@ -223,7 +222,7 @@ if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; th grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 - grep "0" stats.xml.out >/dev/null || ret=1 + # grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 13da1f6117..79cfdeeb2c 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -18,13 +18,12 @@ #include #include #include +#include #include #include #include #include -#include #include -#include #include #include @@ -56,20 +55,20 @@ static char *ip_address = NULL; static int port = 0; -static dst_key_t *ourkey; -static isc_mem_t *mctx; -static dns_tsigkey_t *tsigkey, *initialkey; -static dns_tsig_keyring_t *ring; +static dst_key_t *ourkey = NULL; +static isc_mem_t *mctx = NULL; +static dns_tsigkey_t *tsigkey = NULL, *initialkey = NULL; +static dns_tsig_keyring_t *ring = NULL; static unsigned char noncedata[16]; static isc_buffer_t nonce; -static dns_requestmgr_t *requestmgr; +static dns_requestmgr_t *requestmgr = NULL; static const char *ownername_str = "."; static void recvquery(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query, *response; + dns_message_t *query = NULL, *response = NULL; char keyname[256]; isc_buffer_t keynamebuf; int type; @@ -86,7 +85,6 @@ recvquery(isc_task_t *task, isc_event_t *event) { query = reqev->ev_arg; - response = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); result = dns_request_getresponse(reqev->request, response, @@ -134,8 +132,8 @@ sendquery(isc_task_t *task, isc_event_t *event) { dns_fixedname_t ownername; isc_buffer_t namestr, keybuf; unsigned char keydata[9]; - dns_message_t *query; - dns_request_t *request; + dns_message_t *query = NULL; + dns_request_t *request = NULL; static char keystr[] = "0123456789ab"; isc_event_free(&event); @@ -166,14 +164,12 @@ sendquery(isc_task_t *task, isc_event_t *event) { isc_buffer_usedregion(&keybuf, &r); - initialkey = NULL; result = dns_tsigkey_create( dns_fixedname_name(&keyname), DNS_TSIG_HMACMD5_NAME, isc_buffer_base(&keybuf), isc_buffer_usedlength(&keybuf), false, NULL, 0, 0, mctx, ring, &initialkey); CHECK("dns_tsigkey_create", result); - query = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); result = dns_tkey_builddhquery(query, ourkey, @@ -181,7 +177,6 @@ sendquery(isc_task_t *task, isc_event_t *event) { DNS_TSIG_HMACMD5_NAME, &nonce, 3600); CHECK("dns_tkey_builddhquery", result); - request = NULL; result = dns_request_create(requestmgr, query, &address, DNS_REQUESTOPT_TCP, initialkey, TIMEOUT, task, recvquery, query, &request); @@ -193,10 +188,6 @@ main(int argc, char *argv[]) { char *ourkeyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; - unsigned int attrs; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -224,50 +215,32 @@ main(int argc, char *argv[]) { dns_result_register(); - mctx = NULL; isc_mem_debugging = ISC_MEM_DEBUGRECORD; isc_mem_create(&mctx); - log = NULL; - logconfig = NULL; isc_log_create(mctx, &log, &logconfig); RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4096, 4, 2, 3, 5, attrs, &dispatchv4)); - requestmgr = NULL; - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); - ring = NULL; RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); - tctx = NULL; RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); dns_tsigkeyring_detach(&ring); - sock = NULL; - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); - ourkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; result = dst_key_fromnamedfile(ourkeyname, NULL, type, mctx, &ourkey); CHECK("dst_key_fromnamedfile", result); @@ -281,11 +254,10 @@ main(int argc, char *argv[]) { dns_requestmgr_shutdown(requestmgr); dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_key_free(&ourkey); dns_tsigkey_detach(&initialkey); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 92f37fb1c1..f5a2a17472 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include @@ -53,18 +51,18 @@ #define TIMEOUT 30 -static char *ip_address; +static char *ip_address = NULL; static int port; -static isc_mem_t *mctx; -static dns_tsigkey_t *tsigkey; -static dns_tsig_keyring_t *ring; -static dns_requestmgr_t *requestmgr; +static isc_mem_t *mctx = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dns_tsig_keyring_t *ring = NULL; +static dns_requestmgr_t *requestmgr = NULL; static void recvquery(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query, *response; + dns_message_t *query = NULL, *response = NULL; UNUSED(task); @@ -78,7 +76,6 @@ recvquery(isc_task_t *task, isc_event_t *event) { query = reqev->ev_arg; - response = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); result = dns_request_getresponse(reqev->request, response, @@ -108,8 +105,8 @@ sendquery(isc_task_t *task, isc_event_t *event) { struct in_addr inaddr; isc_sockaddr_t address; isc_result_t result; - dns_message_t *query; - dns_request_t *request; + dns_message_t *query = NULL; + dns_request_t *request = NULL; isc_event_free(&event); @@ -119,13 +116,11 @@ sendquery(isc_task_t *task, isc_event_t *event) { } isc_sockaddr_fromin(&address, &inaddr, port); - query = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); result = dns_tkey_builddeletequery(query, tsigkey); CHECK("dns_tkey_builddeletequery", result); - request = NULL; result = dns_request_create(requestmgr, query, &address, DNS_REQUESTOPT_TCP, tsigkey, TIMEOUT, task, recvquery, query, &request); @@ -137,10 +132,6 @@ main(int argc, char **argv) { char *keyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; - unsigned int attrs; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -169,47 +160,29 @@ main(int argc, char **argv) { dns_result_register(); - mctx = NULL; isc_mem_create(&mctx); - log = NULL; - logconfig = NULL; isc_log_create(mctx, &log, &logconfig); RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4096, 4, 2, 3, 5, attrs, &dispatchv4)); - requestmgr = NULL; - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); - ring = NULL; RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); - tctx = NULL; RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); - sock = NULL; - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); - dstkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; result = dst_key_fromnamedfile(keyname, NULL, type, mctx, &dstkey); CHECK("dst_key_fromnamedfile", result); @@ -224,11 +197,10 @@ main(int argc, char **argv) { dns_requestmgr_shutdown(requestmgr); dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dns_tsigkeyring_detach(&ring); diff --git a/bin/tests/system/zero/ns3/named.conf.in b/bin/tests/system/zero/ns3/named.conf.in index aa35d03fc5..39044310c6 100644 --- a/bin/tests/system/zero/ns3/named.conf.in +++ b/bin/tests/system/zero/ns3/named.conf.in @@ -19,6 +19,7 @@ options { listen-on-v6 { none; }; recursion yes; dnssec-validation yes; + servfail-ttl 0; }; zone "." { diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index e2ca8ca0f0..2c88c90908 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -24,15 +24,14 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include -#include #include #include @@ -752,14 +751,14 @@ sendquery(struct query *query, isc_task_t *task) { options = 0; if (tcp_mode) { - options |= DNS_REQUESTOPT_TCP | DNS_REQUESTOPT_SHARE; + options |= DNS_REQUESTOPT_TCP; } request = NULL; result = dns_request_createvia( requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, dscp, options, NULL, query->timeout, query->udptimeout, query->udpretries, task, recvresponse, message, &request); - CHECK("dns_request_createvia4", result); + CHECK("dns_request_createvia", result); return (ISC_R_SUCCESS); } @@ -2068,14 +2067,11 @@ main(int argc, char *argv[]) { isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; - unsigned int attrs; dns_dispatch_t *dispatchvx = NULL; dns_view_t *view = NULL; - int ns; unsigned int i; + int ns; RUNCHECK(isc_app_start()); @@ -2094,7 +2090,6 @@ main(int argc, char *argv[]) { preparse_args(argc, argv); isc_mem_create(&mctx); - isc_log_create(mctx, &lctx, &lcfg); RUNCHECK(dst_lib_init(mctx, NULL)); @@ -2124,29 +2119,21 @@ main(int argc, char *argv[]) { fatal("can't choose between IPv4 and IPv6"); } - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); - - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY; if (have_ipv4) { isc_sockaddr_any(&bind_any); - attrs |= DNS_DISPATCHATTR_IPV4; } else { isc_sockaddr_any6(&bind_any); - attrs |= DNS_DISPATCHATTR_IPV6; } - dispatchvx = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4096, 100, - 100, 17, 19, attrs, &dispatchvx)); + RUNCHECK(dns_dispatch_createudp( + dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchvx)); + RUNCHECK(dns_requestmgr_create( - mctx, timermgr, socketmgr, taskmgr, dispatchmgr, - have_ipv4 ? dispatchvx : NULL, have_ipv6 ? dispatchvx : NULL, - &requestmgr)); + mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, + have_ipv6 ? dispatchvx : NULL, &requestmgr)); RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); @@ -2187,12 +2174,12 @@ main(int argc, char *argv[]) { dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchvx); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 94a49630be..5fd296f63a 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -66,6 +66,10 @@ Feature Changes 9.16.0 but no error was reported, although sending UDP messages (such as notifies) would fail. :gl:`#2888` +- The network manager API is now used by ``named`` and related tools, + including ``nsupdate``, ``delv``, ``mdig``, to send all outgoing DNS + queries and requests. :gl:`#2401` + Bug Fixes ~~~~~~~~~ diff --git a/lib/dns/Makefile.am b/lib/dns/Makefile.am index 2bf55ecaf0..d724dbd45b 100644 --- a/lib/dns/Makefile.am +++ b/lib/dns/Makefile.am @@ -126,7 +126,6 @@ libdns_la_HEADERS = \ include/dns/soa.h \ include/dns/ssu.h \ include/dns/stats.h \ - include/dns/tcpmsg.h \ include/dns/time.h \ include/dns/timer.h \ include/dns/transport.h \ @@ -232,7 +231,6 @@ libdns_la_SOURCES = \ ssu.c \ ssu_external.c \ stats.c \ - tcpmsg.c \ time.c \ timer.c \ transport.c \ diff --git a/lib/dns/adb.c b/lib/dns/adb.c index e7fee8d38e..e3a469222f 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -2237,11 +2237,9 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, find->options |= DNS_ADBFIND_LAMEPRUNED; goto nextv4; } + addrinfo = new_adbaddrinfo(adb, entry, find->port); - if (addrinfo == NULL) { - find->partial_result |= DNS_ADBFIND_INET; - goto out; - } + /* * Found a valid entry. Add it to the find's list. */ @@ -2275,10 +2273,7 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, goto nextv6; } addrinfo = new_adbaddrinfo(adb, entry, find->port); - if (addrinfo == NULL) { - find->partial_result |= DNS_ADBFIND_INET6; - goto out; - } + /* * Found a valid entry. Add it to the find's list. */ @@ -2292,7 +2287,6 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, } } -out: if (bucket != DNS_ADB_INVALIDBUCKET) { UNLOCK(&adb->entrylocks[bucket]); } @@ -3962,8 +3956,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); clean_target(adb, &name->target); name->expire_target = INT_MAX; - result = set_target(adb, &name->name, - dns_fixedname_name(&dev->foundname), + result = set_target(adb, &name->name, dev->foundname, dev->rdataset, &name->target); if (result == ISC_R_SUCCESS) { DP(NCACHE_LEVEL, @@ -4533,12 +4526,8 @@ dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *sa, port = isc_sockaddr_getport(sa); addr = new_adbaddrinfo(adb, entry, port); - if (addr == NULL) { - result = ISC_R_NOMEMORY; - } else { - inc_entry_refcnt(adb, entry, false); - *addrp = addr; - } + inc_entry_refcnt(adb, entry, false); + *addrp = addr; unlock: UNLOCK(&adb->entrylocks[bucket]); diff --git a/lib/dns/client.c b/lib/dns/client.c index 78b1efcf4e..9902e2d571 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -86,7 +86,7 @@ struct dns_client { isc_appctx_t *actx; isc_taskmgr_t *taskmgr; isc_task_t *task; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; @@ -202,44 +202,17 @@ cleanup: static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, - bool is_shared, dns_dispatch_t **dispp, - const isc_sockaddr_t *localaddr) { - unsigned int attrs; - dns_dispatch_t *disp; - unsigned buffersize, maxbuffers, maxrequests, buckets, increment; + dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { + dns_dispatch_t *disp = NULL; isc_result_t result; isc_sockaddr_t anyaddr; - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; - switch (family) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - if (localaddr == NULL) { isc_sockaddr_anyofpf(&anyaddr, family); localaddr = &anyaddr; } - buffersize = 4096; - maxbuffers = is_shared ? 1000 : 8; - maxrequests = 32768; - buckets = is_shared ? 16411 : 3; - increment = is_shared ? 16433 : 5; - - disp = NULL; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr, - buffersize, maxbuffers, maxrequests, - buckets, increment, attrs, &disp); + result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -249,10 +222,9 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, static isc_result_t createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, - unsigned int ntasks, isc_socketmgr_t *socketmgr, - isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_view_t **viewp) { + unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_view_t **viewp) { isc_result_t result; dns_view_t *view = NULL; @@ -268,8 +240,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, return (result); } - result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr, - timermgr, 0, dispatchmgr, dispatchv4, + result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr, + 0, dispatchmgr, dispatchv4, dispatchv6); if (result != ISC_R_SUCCESS) { dns_view_detach(&view); @@ -289,13 +261,11 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6) { isc_result_t result; dns_client_t *client = NULL; - dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; dns_dispatch_t *dispatchv6 = NULL; dns_view_t *view = NULL; @@ -303,32 +273,28 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, REQUIRE(mctx != NULL); REQUIRE(taskmgr != NULL); REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); + REQUIRE(nm != NULL); REQUIRE(clientp != NULL && *clientp == NULL); UNUSED(options); client = isc_mem_get(mctx, sizeof(*client)); + *client = (dns_client_t){ + .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm + }; isc_mutex_init(&client->lock); - client->actx = actx; - client->taskmgr = taskmgr; - client->socketmgr = socketmgr; - client->timermgr = timermgr; - - client->task = NULL; result = isc_task_create(client->taskmgr, 0, &client->task); if (result != ISC_R_SUCCESS) { goto cleanup_lock; } - result = dns_dispatchmgr_create(mctx, &dispatchmgr); + result = dns_dispatchmgr_create(mctx, nm, &client->dispatchmgr); if (result != ISC_R_SUCCESS) { goto cleanup_task; } - client->dispatchmgr = dispatchmgr; - (void)setsourceports(mctx, dispatchmgr); + (void)setsourceports(mctx, client->dispatchmgr); /* * If only one address family is specified, use it. @@ -336,8 +302,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, */ client->dispatchv4 = NULL; if (localaddr4 != NULL || localaddr6 == NULL) { - result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, - taskmgr, true, &dispatchv4, localaddr4); + result = getudpdispatch(AF_INET, client->dispatchmgr, + &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; } @@ -345,8 +311,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, client->dispatchv6 = NULL; if (localaddr6 != NULL || localaddr4 == NULL) { - result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, - taskmgr, true, &dispatchv6, localaddr6); + result = getudpdispatch(AF_INET6, client->dispatchmgr, + &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; } @@ -362,7 +328,7 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, /* Create the default view for class IN */ result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS, - socketmgr, timermgr, dispatchmgr, dispatchv4, + nm, timermgr, client->dispatchmgr, dispatchv4, dispatchv6, &view); if (result != ISC_R_SUCCESS) { goto cleanup_references; @@ -375,12 +341,10 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, ISC_LIST_INIT(client->resctxs); - client->mctx = NULL; isc_mem_attach(mctx, &client->mctx); client->find_timeout = DEF_FIND_TIMEOUT; client->find_udpretries = DEF_FIND_UDPRETRIES; - client->attributes = 0; client->magic = DNS_CLIENT_MAGIC; @@ -398,7 +362,7 @@ cleanup_dispatchmgr: if (dispatchv6 != NULL) { dns_dispatch_detach(&dispatchv6); } - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&client->dispatchmgr); cleanup_task: isc_task_detach(&client->task); cleanup_lock: @@ -426,7 +390,7 @@ destroyclient(dns_client_t *client) { dns_dispatch_detach(&client->dispatchv6); } - dns_dispatchmgr_destroy(&client->dispatchmgr); + dns_dispatchmgr_detach(&client->dispatchmgr); isc_task_detach(&client->task); @@ -611,9 +575,9 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { isc_result_t vresult = ISC_R_SUCCESS; bool want_restart; bool send_event = false; - dns_name_t *name, *prefix; + dns_name_t *name = NULL, *prefix = NULL; dns_fixedname_t foundname, fixed; - dns_rdataset_t *trdataset; + dns_rdataset_t *trdataset = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; int order; @@ -675,7 +639,7 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { node = event->node; result = event->result; vresult = event->vresult; - fname = dns_fixedname_name(&event->foundname); + fname = event->foundname; INSIST(event->rdataset == rctx->rdataset); INSIST(event->sigrdataset == rctx->sigrdataset); } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 177695184e..41751ed890 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -17,80 +17,51 @@ #include #include +#include #include #include +#include #include #include #include -#include #include #include -#include #include #include #include #include -#include #include #include #include -#include #include typedef ISC_LIST(dns_dispentry_t) dns_displist_t; -typedef struct dispsocket dispsocket_t; -typedef ISC_LIST(dispsocket_t) dispsocketlist_t; - -typedef struct dispportentry dispportentry_t; -typedef ISC_LIST(dispportentry_t) dispportlist_t; - typedef struct dns_qid { unsigned int magic; + isc_mutex_t lock; unsigned int qid_nbuckets; /*%< hash table size */ unsigned int qid_increment; /*%< id increment on collision */ - isc_mutex_t lock; - dns_displist_t *qid_table; /*%< the table itself */ - dispsocketlist_t *sock_table; /*%< socket table */ + dns_displist_t *qid_table; /*%< the table itself */ } dns_qid_t; struct dns_dispatchmgr { /* Unlocked. */ unsigned int magic; + isc_refcount_t references; isc_mem_t *mctx; dns_acl_t *blackhole; isc_stats_t *stats; + isc_nm_t *nm; /* Locked by "lock". */ isc_mutex_t lock; unsigned int state; ISC_LIST(dns_dispatch_t) list; - /* locked by buffer_lock */ dns_qid_t *qid; - isc_mutex_t buffer_lock; - unsigned int buffers; /*%< allocated buffers */ - unsigned int buffersize; /*%< size of each buffer */ - unsigned int maxbuffers; /*%< max buffers */ - isc_refcount_t irefs; - - /*% - * Locked by qid->lock if qid exists; otherwise, can be used without - * being locked. - * Memory footprint considerations: this is a simple implementation of - * available ports, i.e., an ordered array of the actual port numbers. - * This will require about 256KB of memory in the worst case (128KB for - * each of IPv4 and IPv6). We could reduce it by representing it as a - * more sophisticated way such as a list (or array) of ranges that are - * searched to identify a specific port. Our decision here is the saved - * memory isn't worth the implementation complexity, considering the - * fact that the whole BIND9 process (which is mainly named) already - * requires a pretty large memory footprint. We may, however, have to - * revisit the decision when we want to use it as a separate module for - * an environment where memory requirement is severer. - */ in_port_t *v4ports; /*%< available ports for IPv4 */ unsigned int nv4ports; /*%< # of available ports for IPv4 */ in_port_t *v6ports; /*%< available ports for IPv4 */ @@ -100,127 +71,68 @@ struct dns_dispatchmgr { #define MGR_SHUTTINGDOWN 0x00000001U #define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0) -#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0) - struct dns_dispentry { unsigned int magic; + isc_refcount_t references; dns_dispatch_t *disp; + isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */ + unsigned int bucket; + unsigned int retries; + unsigned int timeout; + isc_time_t start; + isc_sockaddr_t local; + isc_sockaddr_t peer; + in_port_t port; dns_messageid_t id; - in_port_t port; - unsigned int bucket; - isc_sockaddr_t host; - isc_task_t *task; - isc_taskaction_t action; + dispatch_cb_t connected; + dispatch_cb_t sent; + dispatch_cb_t response; void *arg; - bool item_out; - dispsocket_t *dispsocket; - ISC_LIST(dns_dispatchevent_t) items; + bool canceled; ISC_LINK(dns_dispentry_t) link; + ISC_LINK(dns_dispentry_t) alink; + ISC_LINK(dns_dispentry_t) plink; + ISC_LINK(dns_dispentry_t) rlink; }; /*% - * Maximum number of dispatch sockets that can be pooled for reuse. The - * appropriate value may vary, but experiments have shown a busy caching server - * may need more than 1000 sockets concurrently opened. The maximum allowable - * number of dispatch sockets (per manager) will be set to the double of this - * value. + * Fixed UDP buffer size. */ -#ifndef DNS_DISPATCH_POOLSOCKS -#define DNS_DISPATCH_POOLSOCKS 2048 -#endif /* ifndef DNS_DISPATCH_POOLSOCKS */ +#ifndef DNS_DISPATCH_UDPBUFSIZE +#define DNS_DISPATCH_UDPBUFSIZE 4096 +#endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */ -/*% - * Quota to control the number of dispatch sockets. If a dispatch has more - * than the quota of sockets, new queries will purge oldest ones, so that - * a massive number of outstanding queries won't prevent subsequent queries - * (especially if the older ones take longer time and result in timeout). - */ -#ifndef DNS_DISPATCH_SOCKSQUOTA -#define DNS_DISPATCH_SOCKSQUOTA 3072 -#endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ - -struct dispsocket { - unsigned int magic; - isc_socket_t *socket; - dns_dispatch_t *disp; - isc_sockaddr_t host; - in_port_t localport; /* XXX: should be removed later */ - dispportentry_t *portentry; - dns_dispentry_t *resp; - isc_task_t *task; - ISC_LINK(dispsocket_t) link; - unsigned int bucket; - ISC_LINK(dispsocket_t) blink; -}; - -/*% - * A port table entry. We remember every port we first open in a table with a - * reference counter so that we can 'reuse' the same port (with different - * destination addresses) using the SO_REUSEADDR socket option. - */ -struct dispportentry { - in_port_t port; - isc_refcount_t refs; - ISC_LINK(struct dispportentry) link; -}; - -#ifndef DNS_DISPATCH_PORTTABLESIZE -#define DNS_DISPATCH_PORTTABLESIZE 1024 -#endif /* ifndef DNS_DISPATCH_PORTTABLESIZE */ - -#define INVALID_BUCKET (0xffffdead) - -/*% - * Number of tasks for each dispatch that use separate sockets for different - * transactions. This must be a power of 2 as it will divide 32 bit numbers - * to get an uniformly random tasks selection. See get_dispsocket(). - */ -#define MAX_INTERNAL_TASKS 64 +typedef enum { + DNS_DISPATCHSTATE_NONE = 0UL, + DNS_DISPATCHSTATE_CONNECTING, + DNS_DISPATCHSTATE_CONNECTED +} dns_dispatchstate_t; struct dns_dispatch { /* Unlocked. */ unsigned int magic; /*%< magic */ dns_dispatchmgr_t *mgr; /*%< dispatch manager */ - int ntasks; - /*% - * internal task buckets. We use multiple tasks to distribute various - * socket events well when using separate dispatch sockets. We use the - * 1st task (task[0]) for internal control events. - */ - isc_task_t *task[MAX_INTERNAL_TASKS]; - isc_socket_t *socket; /*%< isc socket attached to */ - isc_sockaddr_t local; /*%< local address */ - in_port_t localport; /*%< local UDP port */ - isc_sockaddr_t peer; /*%< peer address (TCP) */ - isc_dscp_t dscp; /*%< "listen-on" DSCP value */ - unsigned int maxrequests; /*%< max requests */ - isc_event_t *ctlevent; - - isc_mem_t *sepool; /*%< pool for socket events */ + isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */ + isc_sockaddr_t local; /*%< local address */ + in_port_t localport; /*%< local UDP port */ + isc_sockaddr_t peer; /*%< peer address (TCP) */ /*% Locked by mgr->lock. */ ISC_LINK(dns_dispatch_t) link; /* Locked by "lock". */ isc_mutex_t lock; /*%< locks all below */ - isc_sockettype_t socktype; - unsigned int attributes; - unsigned int refcount; /*%< number of users */ - dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ - unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, - tcpmsg_valid : 1, recv_pending : 1; /*%< is a - * recv() - * pending? - * */ - isc_result_t shutdown_why; - ISC_LIST(dispsocket_t) activesockets; - ISC_LIST(dispsocket_t) inactivesockets; + isc_socktype_t socktype; + atomic_uint_fast32_t state; + isc_refcount_t references; + unsigned int shutdown_out : 1; + + dns_displist_t pending; + dns_displist_t active; unsigned int nsockets; + unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ - dns_tcpmsg_t tcpmsg; /*%< for tcp streams */ - dns_qid_t *qid; - dispportlist_t *port_table; /*%< hold ports 'owned' by us */ }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -238,91 +150,69 @@ struct dns_dispatch { #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r') #define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC) -#define DNS_QID(disp) \ - ((disp)->socktype == isc_sockettype_tcp) ? (disp)->qid \ - : (disp)->mgr->qid +/*% + * Quota to control the number of UDP dispatch sockets. If a dispatch has + * more than the quota of sockets, new queries will purge oldest ones, so + * that a massive number of outstanding queries won't prevent subsequent + * queries (especially if the older ones take longer time and result in + * timeout). + */ +#ifndef DNS_DISPATCH_SOCKSQUOTA +#define DNS_DISPATCH_SOCKSQUOTA 3072 +#endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ /*% - * Locking a query port buffer is a bit tricky. We access the buffer without - * locking until qid is created. Technically, there is a possibility of race - * between the creation of qid and access to the port buffer; in practice, - * however, this should be safe because qid isn't created until the first - * dispatch is created and there should be no contending situation until then. + * Quota to control the number of concurrent requests that can be handled + * by each TCP dispatch. (UDP dispatches do not currently support socket + * sharing.) */ -#define PORTBUFLOCK(mgr) \ - if ((mgr)->qid != NULL) \ - LOCK(&((mgr)->qid->lock)) -#define PORTBUFUNLOCK(mgr) \ - if ((mgr)->qid != NULL) \ - UNLOCK((&(mgr)->qid->lock)) +#ifndef DNS_DISPATCH_MAXREQUESTS +#define DNS_DISPATCH_MAXREQUESTS 32768 +#endif /* ifndef DNS_DISPATCH_MAXREQUESTS */ + +/*% + * Number of buckets in the QID hash table, and the value to + * increment the QID by when attempting to avoid collisions. + * The number of buckets should be prime, and the increment + * should be the next higher prime number. + */ +#ifndef DNS_QID_BUCKETS +#define DNS_QID_BUCKETS 16411 +#endif /* ifndef DNS_QID_BUCKETS */ +#ifndef DNS_QID_INCREMENT +#define DNS_QID_INCREMENT 16433 +#endif /* ifndef DNS_QID_INCREMENT */ /* * Statics. */ +static void +dispatchmgr_destroy(dns_dispatchmgr_t *mgr); + static dns_dispentry_t * entry_search(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t, unsigned int); -static bool -destroy_disp_ok(dns_dispatch_t *); static void -destroy_disp(isc_task_t *task, isc_event_t *event); +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static void -destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); -static void -deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); -static void -udp_exrecv(isc_task_t *, isc_event_t *); -static void -udp_shrecv(isc_task_t *, isc_event_t *); -static void -udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *); -static void -tcp_recv(isc_task_t *, isc_event_t *); -static isc_result_t -startrecv(dns_dispatch_t *, dispsocket_t *); +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static uint32_t dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t); static void -free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); -static void * -allocate_udp_buffer(dns_dispatch_t *disp); -static inline void -free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); -static inline dns_dispatchevent_t * -allocate_devent(dns_dispatch_t *disp); -static void -do_cancel(dns_dispatch_t *disp); -static dns_dispentry_t * -linear_first(dns_qid_t *disp); -static dns_dispentry_t * -linear_next(dns_qid_t *disp, dns_dispentry_t *resp); -static void dispatch_free(dns_dispatch_t **dispp); static isc_result_t -get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, - isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly); -static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int maxrequests, unsigned int attributes, - dns_dispatch_t **dispp, isc_socket_t *dup_socket); -static bool -destroy_mgr_ok(dns_dispatchmgr_t *mgr); +dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + dns_dispatch_t **dispp); static void -destroy_mgr(dns_dispatchmgr_t **mgrp); -static isc_result_t -qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, - unsigned int increment, dns_qid_t **qidp, bool needaddrtable); +qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp); static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp, - isc_socket_t *dup_socket, bool duponly); -static bool -portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_sockaddr_t *sockaddrp); +static void +startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp); +void +dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout); #define LVL(x) ISC_LOG_DEBUG(x) @@ -384,39 +274,6 @@ dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) { msgbuf); } -static void -request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, - const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); - -static void -request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, - const char *fmt, ...) { - char msgbuf[2048]; - char peerbuf[256]; - va_list ap; - - if (!isc_log_wouldlog(dns_lctx, level)) { - return; - } - - va_start(ap, fmt); - vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); - va_end(ap); - - if (VALID_RESPONSE(resp)) { - isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf)); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, - DNS_LOGMODULE_DISPATCH, level, - "dispatch %p response %p %s: %s", disp, resp, - peerbuf, msgbuf); - } else { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, - DNS_LOGMODULE_DISPATCH, level, - "dispatch %p req/resp %p: %s", disp, resp, - msgbuf); - } -} - /* * Return a hash of the destination and message id. */ @@ -434,434 +291,65 @@ dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, return (ret); } -/* - * Find the first entry in 'qid'. Returns NULL if there are no entries. - */ -static dns_dispentry_t * -linear_first(dns_qid_t *qid) { - dns_dispentry_t *ret; - unsigned int bucket; - - bucket = 0; - - while (bucket < qid->qid_nbuckets) { - ret = ISC_LIST_HEAD(qid->qid_table[bucket]); - if (ret != NULL) { - return (ret); - } - bucket++; - } - - return (NULL); -} - -/* - * Find the next entry after 'resp' in 'qid'. Return NULL if there are - * no more entries. - */ -static dns_dispentry_t * -linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { - dns_dispentry_t *ret; - unsigned int bucket; - - ret = ISC_LIST_NEXT(resp, link); - if (ret != NULL) { - return (ret); - } - - bucket = resp->bucket; - bucket++; - while (bucket < qid->qid_nbuckets) { - ret = ISC_LIST_HEAD(qid->qid_table[bucket]); - if (ret != NULL) { - return (ret); - } - bucket++; - } - - return (NULL); -} - -/* - * The dispatch must be locked. - */ -static bool -destroy_disp_ok(dns_dispatch_t *disp) { - if (disp->refcount != 0) { - return (false); - } - - if (disp->recv_pending != 0) { - return (false); - } - - if (!ISC_LIST_EMPTY(disp->activesockets)) { - return (false); - } - - if (disp->shutting_down == 0) { - return (false); - } - - return (true); -} - -/* - * Called when refcount reaches 0 (and safe to destroy). - * - * The dispatcher must be locked. - * The manager must not be locked. - */ -static void -destroy_disp(isc_task_t *task, isc_event_t *event) { - dns_dispatch_t *disp; - dns_dispatchmgr_t *mgr; - bool killmgr; - dispsocket_t *dispsocket; - int i; - - INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); - - UNUSED(task); - - disp = event->ev_arg; - mgr = disp->mgr; - - LOCK(&mgr->lock); - ISC_LIST_UNLINK(mgr->list, disp, link); - - dispatch_log(disp, LVL(90), - "shutting down; detaching from sock %p, task %p", - disp->socket, disp->task[0]); /* XXXX */ - - if (disp->sepool != NULL) { - isc_mem_destroy(&disp->sepool); - } - - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); - } - while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) { - ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link); - destroy_dispsocket(disp, &dispsocket); - } - for (i = 0; i < disp->ntasks; i++) { - isc_task_detach(&disp->task[i]); - } - isc_event_free(&event); - - dispatch_free(&disp); - - killmgr = destroy_mgr_ok(mgr); - UNLOCK(&mgr->lock); - if (killmgr) { - destroy_mgr(&mgr); - } -} - /*% - * Manipulate port table per dispatch: find an entry for a given port number, - * create a new entry, and decrement a given entry with possible clean-up. - */ -static dispportentry_t * -port_search(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry; - - REQUIRE(disp->port_table != NULL); - - portentry = ISC_LIST_HEAD( - disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE]); - while (portentry != NULL) { - if (portentry->port == port) { - return (portentry); - } - portentry = ISC_LIST_NEXT(portentry, link); - } - - return (NULL); -} - -static dispportentry_t * -new_portentry(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry; - dns_qid_t *qid; - - REQUIRE(disp->port_table != NULL); - - portentry = isc_mem_get(disp->mgr->mctx, sizeof(*portentry)); - - portentry->port = port; - isc_refcount_init(&portentry->refs, 1); - ISC_LINK_INIT(portentry, link); - qid = DNS_QID(disp); - LOCK(&qid->lock); - ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], - portentry, link); - UNLOCK(&qid->lock); - - return (portentry); -} - -/*% - * The caller must hold the qid->lock. - */ -static void -deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { - dispportentry_t *portentry = *portentryp; - *portentryp = NULL; - - REQUIRE(disp->port_table != NULL); - REQUIRE(portentry != NULL); - - if (isc_refcount_decrement(&portentry->refs) == 1) { - ISC_LIST_UNLINK(disp->port_table[portentry->port % - DNS_DISPATCH_PORTTABLESIZE], - portentry, link); - isc_mem_put(disp->mgr->mctx, portentry, sizeof(*portentry)); - } -} - -/*% - * Find a dispsocket for socket address 'dest', and port number 'port'. - * Return NULL if no such entry exists. Requires qid->lock to be held. - */ -static dispsocket_t * -socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, - unsigned int bucket) { - dispsocket_t *dispsock; - - REQUIRE(VALID_QID(qid)); - REQUIRE(bucket < qid->qid_nbuckets); - - dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); - - while (dispsock != NULL) { - if (dispsock->portentry != NULL && - dispsock->portentry->port == port && - isc_sockaddr_equal(dest, &dispsock->host)) - { - return (dispsock); - } - dispsock = ISC_LIST_NEXT(dispsock, blink); - } - - return (NULL); -} - -/*% - * Make a new socket for a single dispatch with a random port number. + * Choose a random port number for a dispatch entry. * The caller must hold the disp->lock */ static isc_result_t -get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, - isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp, - in_port_t *portp) { - int i; +setup_socket(dns_dispatch_t *disp, dns_dispentry_t *resp, + const isc_sockaddr_t *dest, in_port_t *portp) { dns_dispatchmgr_t *mgr = disp->mgr; - isc_socket_t *sock = NULL; - isc_result_t result = ISC_R_FAILURE; - in_port_t port; - isc_sockaddr_t localaddr; - unsigned int bucket = 0; - dispsocket_t *dispsock; unsigned int nports; - in_port_t *ports; - isc_socket_options_t bindoptions; - dispportentry_t *portentry = NULL; - dns_qid_t *qid; + in_port_t *ports = NULL; + in_port_t port; + + if (resp->retries++ > 5) { + return (ISC_R_FAILURE); + } if (isc_sockaddr_pf(&disp->local) == AF_INET) { - nports = disp->mgr->nv4ports; - ports = disp->mgr->v4ports; + nports = mgr->nv4ports; + ports = mgr->v4ports; } else { - nports = disp->mgr->nv6ports; - ports = disp->mgr->v6ports; + nports = mgr->nv6ports; + ports = mgr->v6ports; } if (nports == 0) { return (ISC_R_ADDRNOTAVAIL); } - dispsock = ISC_LIST_HEAD(disp->inactivesockets); - if (dispsock != NULL) { - ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link); - sock = dispsock->socket; - dispsock->socket = NULL; - } else { - dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); + disp->nsockets++; - disp->nsockets++; - dispsock->socket = NULL; - dispsock->disp = disp; - dispsock->resp = NULL; - dispsock->portentry = NULL; - dispsock->task = NULL; - isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)], - &dispsock->task); - ISC_LINK_INIT(dispsock, link); - ISC_LINK_INIT(dispsock, blink); - dispsock->magic = DISPSOCK_MAGIC; - } + resp->local = disp->local; + resp->peer = *dest; - /* - * Pick up a random UDP port and open a new socket with it. Avoid - * choosing ports that share the same destination because it will be - * very likely to fail in bind(2) or connect(2). - */ - localaddr = disp->local; - qid = DNS_QID(disp); + port = ports[isc_random_uniform(nports)]; + isc_sockaddr_setport(&resp->local, port); + resp->port = port; - for (i = 0; i < 64; i++) { - port = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr, port); + *portp = port; - LOCK(&qid->lock); - bucket = dns_hash(qid, dest, 0, port); - if (socket_search(qid, dest, port, bucket) != NULL) { - UNLOCK(&qid->lock); - continue; - } - UNLOCK(&qid->lock); - bindoptions = 0; - portentry = port_search(disp, port); - - if (portentry != NULL) { - bindoptions |= ISC_SOCKET_REUSEADDRESS; - } - result = open_socket(sockmgr, &localaddr, bindoptions, &sock, - NULL, false); - if (result == ISC_R_SUCCESS) { - if (portentry == NULL) { - portentry = new_portentry(disp, port); - if (portentry == NULL) { - result = ISC_R_NOMEMORY; - break; - } - } else { - isc_refcount_increment(&portentry->refs); - } - break; - } else if (result == ISC_R_NOPERM) { - char buf[ISC_SOCKADDR_FORMATSIZE]; - isc_sockaddr_format(&localaddr, buf, sizeof(buf)); - dispatch_log(disp, ISC_LOG_WARNING, - "open_socket(%s) -> %s: continuing", buf, - isc_result_totext(result)); - } else if (result != ISC_R_ADDRINUSE) { - break; - } - } - - if (result == ISC_R_SUCCESS) { - dispsock->socket = sock; - dispsock->host = *dest; - dispsock->bucket = bucket; - LOCK(&qid->lock); - dispsock->portentry = portentry; - ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); - UNLOCK(&qid->lock); - *dispsockp = dispsock; - *portp = port; - } else { - /* - * We could keep it in the inactive list, but since this should - * be an exceptional case and might be resource shortage, we'd - * rather destroy it. - */ - if (sock != NULL) { - isc_socket_detach(&sock); - } - destroy_dispsocket(disp, &dispsock); - } - - return (result); + return (ISC_R_SUCCESS); } /*% - * Destroy a dedicated dispatch socket. + * Deactivate the socket for a dispatch entry. + * The dispatch must be locked. */ static void -destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { - dispsocket_t *dispsock; - dns_qid_t *qid = DNS_QID(disp); +deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) { + if (ISC_LINK_LINKED(resp, alink)) { + ISC_LIST_UNLINK(disp->active, resp, alink); + } - /* - * The dispatch must be locked. - */ + if (resp->handle != NULL) { + INSIST(disp->socktype == isc_socktype_udp); - REQUIRE(dispsockp != NULL && *dispsockp != NULL); - dispsock = *dispsockp; - *dispsockp = NULL; - REQUIRE(!ISC_LINK_LINKED(dispsock, link)); + isc_nm_cancelread(resp->handle); + isc_nmhandle_detach(&resp->handle); + } disp->nsockets--; - dispsock->magic = 0; - if (dispsock->portentry != NULL) { - /* socket_search() tests and dereferences portentry. */ - LOCK(&qid->lock); - deref_portentry(disp, &dispsock->portentry); - UNLOCK(&qid->lock); - } - if (dispsock->socket != NULL) { - isc_socket_detach(&dispsock->socket); - } - if (ISC_LINK_LINKED(dispsock, blink)) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - } - if (dispsock->task != NULL) { - isc_task_detach(&dispsock->task); - } - isc_mem_put(disp->mgr->mctx, dispsock, sizeof(*dispsock)); -} - -/*% - * Deactivate a dedicated dispatch socket. Move it to the inactive list for - * future reuse unless the total number of sockets are exceeding the maximum. - */ -static void -deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t result; - dns_qid_t *qid = DNS_QID(disp); - - /* - * The dispatch must be locked. - */ - ISC_LIST_UNLINK(disp->activesockets, dispsock, link); - if (dispsock->resp != NULL) { - INSIST(dispsock->resp->dispsocket == dispsock); - dispsock->resp->dispsocket = NULL; - } - - INSIST(dispsock->portentry != NULL); - /* socket_search() tests and dereferences portentry. */ - LOCK(&qid->lock); - deref_portentry(disp, &dispsock->portentry); - UNLOCK(&qid->lock); - - if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) { - destroy_dispsocket(disp, &dispsock); - } else { - result = isc_socket_close(dispsock->socket); - - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - - if (result == ISC_R_SUCCESS) { - ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); - } else { - /* - * If the underlying system does not allow this - * optimization, destroy this temporary structure (and - * create a new one for a new transaction). - */ - INSIST(result == ISC_R_NOTIMPLEMENTED); - destroy_dispsocket(disp, &dispsock); - } - } } /* @@ -872,7 +360,7 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { static dns_dispentry_t * entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, in_port_t port, unsigned int bucket) { - dns_dispentry_t *res; + dns_dispentry_t *res = NULL; REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); @@ -880,7 +368,7 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, res = ISC_LIST_HEAD(qid->qid_table[bucket]); while (res != NULL) { - if (res->id == id && isc_sockaddr_equal(dest, &res->host) && + if (res->id == id && isc_sockaddr_equal(dest, &res->peer) && res->port == port) { return (res); } @@ -891,117 +379,70 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, } static void -free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { - unsigned int buffersize; - INSIST(buf != NULL && len != 0); +dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp) { + REQUIRE(VALID_RESPONSE(resp)); + REQUIRE(respp != NULL && *respp == NULL); - switch (disp->socktype) { - case isc_sockettype_tcp: - INSIST(disp->tcpbuffers > 0); - disp->tcpbuffers--; - isc_mem_put(disp->mgr->mctx, buf, len); - break; - case isc_sockettype_udp: - LOCK(&disp->mgr->buffer_lock); - INSIST(disp->mgr->buffers > 0); - INSIST(len == disp->mgr->buffersize); - disp->mgr->buffers--; - buffersize = disp->mgr->buffersize; - UNLOCK(&disp->mgr->buffer_lock); - isc_mem_put(disp->mgr->mctx, buf, buffersize); - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } -} + isc_refcount_increment(&resp->references); -static void * -allocate_udp_buffer(dns_dispatch_t *disp) { - unsigned int buffersize; - - LOCK(&disp->mgr->buffer_lock); - if (disp->mgr->buffers >= disp->mgr->maxbuffers) { - UNLOCK(&disp->mgr->buffer_lock); - return (NULL); - } - buffersize = disp->mgr->buffersize; - disp->mgr->buffers++; - UNLOCK(&disp->mgr->buffer_lock); - - return (isc_mem_get(disp->mgr->mctx, buffersize)); -} - -static inline void -free_sevent(isc_event_t *ev) { - isc_mem_t *pool = ev->ev_destroy_arg; - isc_socketevent_t *sev = (isc_socketevent_t *)ev; - isc_mem_put(pool, sev, sizeof(*sev)); -} - -static inline isc_socketevent_t * -allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock, isc_eventtype_t type, - isc_taskaction_t action, const void *arg) { - isc_socketevent_t *ev; - void *deconst_arg; - - ev = isc_mem_get(disp->sepool, sizeof(*ev)); - DE_CONST(arg, deconst_arg); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, action, deconst_arg, - sock, free_sevent, disp->sepool); - ev->result = ISC_R_UNSET; - ISC_LINK_INIT(ev, ev_link); - ev->region.base = NULL; - ev->n = 0; - ev->offset = 0; - ev->attributes = 0; - - return (ev); -} - -static inline void -free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { - if (disp->failsafe_ev == ev) { - INSIST(disp->shutdown_out == 1); - disp->shutdown_out = 0; - - return; - } - - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); -} - -static inline dns_dispatchevent_t * -allocate_devent(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev; - - ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); - isc_refcount_increment0(&disp->mgr->irefs); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, - NULL); - - return (ev); + *respp = resp; } static void -udp_exrecv(isc_task_t *task, isc_event_t *ev) { - dispsocket_t *dispsock = ev->ev_arg; +dispentry_destroy(dns_dispentry_t *resp) { + dns_dispatch_t *disp = resp->disp; - UNUSED(task); + resp->magic = 0; - REQUIRE(VALID_DISPSOCK(dispsock)); - udp_recv(ev, dispsock->disp, dispsock); + if (ISC_LINK_LINKED(resp, plink)) { + ISC_LIST_UNLINK(disp->pending, resp, plink); + } + + INSIST(!ISC_LINK_LINKED(resp, alink)); + INSIST(!ISC_LINK_LINKED(resp, rlink)); + + if (resp->handle != NULL) { + isc_nmhandle_detach(&resp->handle); + } + + isc_refcount_destroy(&resp->references); + + isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp)); + + dns_dispatch_detach(&disp); } static void -udp_shrecv(isc_task_t *task, isc_event_t *ev) { - dns_dispatch_t *disp = ev->ev_arg; +dispentry_detach(dns_dispentry_t **respp) { + dns_dispentry_t *resp = NULL; + uint_fast32_t ref; - UNUSED(task); + REQUIRE(respp != NULL && VALID_RESPONSE(*respp)); - REQUIRE(VALID_DISPATCH(disp)); - udp_recv(ev, disp, NULL); + resp = *respp; + *respp = NULL; + + ref = isc_refcount_decrement(&resp->references); + if (ref == 1) { + dispentry_destroy(resp); + } +} + +/* + * How long in milliseconds has it been since this dispentry + * started reading? (Only used for UDP, to adjust the timeout + * downward when running getnext.) + */ +static unsigned int +dispentry_runtime(dns_dispentry_t *resp) { + isc_time_t now; + + if (isc_time_isepoch(&resp->start)) { + return (0); + } + + TIME_NOW(&now); + return (isc_time_microdiff(&now, &resp->start) / 1000); } /* @@ -1019,115 +460,55 @@ udp_shrecv(isc_task_t *task, isc_event_t *ev) { * restart. */ static void -udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dns_dispentry_t *resp = (dns_dispentry_t *)arg; + dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; isc_buffer_t source; unsigned int flags; - dns_dispentry_t *resp = NULL; - dns_dispatchevent_t *rev; - unsigned int bucket; - bool killit; - bool queue_response; - dns_dispatchmgr_t *mgr; - dns_qid_t *qid; + isc_sockaddr_t peer; isc_netaddr_t netaddr; - int match; - int result; - bool qidlocked = false; + int match, timeout; + dispatch_cb_t response = NULL; + + REQUIRE(VALID_RESPONSE(resp)); + REQUIRE(VALID_DISPATCH(resp->disp)); + + disp = resp->disp; LOCK(&disp->lock); - mgr = disp->mgr; - qid = mgr->qid; + dispatch_log(disp, LVL(90), "UDP response %p:%s:requests %d", resp, + isc_result_totext(eresult), disp->requests); - LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), - "got packet: requests %d, buffers %d, recvs %d", - disp->requests, disp->mgr->buffers, disp->recv_pending); - UNLOCK(&disp->mgr->buffer_lock); + /* + * The resp may have been deactivated by shutdown; if + * so, we can skip the response callback. + */ + if (ISC_LINK_LINKED(resp, alink)) { + response = resp->response; + } - if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) { + if (eresult != ISC_R_SUCCESS) { /* - * Unless the receive event was imported from a listening - * interface, in which case the event type is - * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending. + * This is most likely a network error on a connected + * socket, a timeout, or the query has been canceled. + * It makes no sense to check the address or parse the + * packet, but we can return the error to the caller. */ - INSIST(disp->recv_pending != 0); - disp->recv_pending = 0; + goto done; } - if (dispsock != NULL && - (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) - { - /* - * dispsock->resp can be NULL if this transaction was canceled - * just after receiving a response. Since this socket is - * exclusively used and there should be at most one receive - * event the canceled event should have been no effect. So - * we can (and should) deactivate the socket right now. - */ - deactivate_dispsocket(disp, dispsock); - dispsock = NULL; - } + INSIST(ISC_LINK_LINKED(resp, alink)); - if (disp->shutting_down) { - /* - * This dispatcher is shutting down. - */ - free_buffer(disp, ev->region.base, ev->region.length); - - isc_event_free(&ev_in); - ev = NULL; - - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); - } - - return; - } - - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - if (dispsock != NULL) { - resp = dispsock->resp; - id = resp->id; - if (ev->result != ISC_R_SUCCESS) { - /* - * This is most likely a network error on a - * connected socket. It makes no sense to - * check the address or parse the packet, but it - * will help to return the error to the caller. - */ - goto sendresponse; - } - } else { - free_buffer(disp, ev->region.base, ev->region.length); - - isc_event_free(&ev_in); - UNLOCK(&disp->lock); - return; - } - } else if (ev->result != ISC_R_SUCCESS) { - free_buffer(disp, ev->region.base, ev->region.length); - - if (ev->result != ISC_R_CANCELED) { - dispatch_log(disp, ISC_LOG_ERROR, - "odd socket result in udp_recv(): %s", - isc_result_totext(ev->result)); - } - - isc_event_free(&ev_in); - UNLOCK(&disp->lock); - return; - } + peer = isc_nmhandle_peeraddr(handle); + isc_netaddr_fromsockaddr(&netaddr, &peer); /* * If this is from a blackholed address, drop it. */ - isc_netaddr_fromsockaddr(&netaddr, &ev->address); if (disp->mgr->blackhole != NULL && dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match, NULL) == ISC_R_SUCCESS && @@ -1140,20 +521,19 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* * Peek into the buffer to see what we can see. */ - isc_buffer_init(&source, ev->region.base, ev->region.length); - isc_buffer_add(&source, ev->n); + id = resp->id; + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { - free_buffer(disp, ev->region.base, ev->region.length); dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1161,145 +541,48 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); /* - * Look at flags. If query, drop it. If response, - * look to see where it goes. + * Look at the message flags. If it's a query, ignore it. */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { - /* query */ - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* - * Search for the corresponding response. If we are using an exclusive - * socket, we've already identified it and we can skip the search; but - * the ID and the address must match the expected ones. + * The QID and the address must match the expected ones. */ - if (resp == NULL) { - bucket = dns_hash(qid, &ev->address, id, disp->localport); - LOCK(&qid->lock); - qidlocked = true; - resp = entry_search(qid, &ev->address, id, disp->localport, - bucket); - dispatch_log(disp, LVL(90), - "search for response in bucket %d: %s", bucket, - (resp == NULL ? "not found" : "found")); - - } else if (resp->id != id || - !isc_sockaddr_equal(&ev->address, &resp->host)) { - dispatch_log(disp, LVL(90), - "response to an exclusive socket doesn't match"); - inc_stats(mgr, dns_resstatscounter_mismatch); - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } - - if (resp == NULL) { - inc_stats(mgr, dns_resstatscounter_mismatch); - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; + if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) { + dispatch_log(disp, LVL(90), "response doesn't match"); + inc_stats(disp->mgr, dns_resstatscounter_mismatch); + goto next; } /* - * Now that we have the original dispatch the query was sent - * from check that the address and port the response was - * sent to make sense. + * We have the right resp, so call the caller back. */ - if (disp != resp->disp) { - isc_sockaddr_t a1; - isc_sockaddr_t a2; - - /* - * Check that the socket types and ports match. - */ - if (disp->socktype != resp->disp->socktype || - isc_sockaddr_getport(&disp->local) != - isc_sockaddr_getport(&resp->disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } - - /* - * If each dispatch is bound to a different address - * then fail. - * - * Note under Linux a packet can be sent out via IPv4 socket - * and the response be received via a IPv6 socket. - * - * Requests sent out via IPv6 should always come back in - * via IPv6. - */ - if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 && - isc_sockaddr_pf(&disp->local) != PF_INET6) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } - isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); - isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); - if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a2, &disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } - } - -sendresponse: - queue_response = resp->item_out; - rev = allocate_devent(resp->disp); - if (rev == NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } + goto done; +next: /* - * At this point, rev contains the event we want to fill in, and - * resp contains the information on the place to send it to. - * Send the event off. + * This is the wrong response. Don't call the caller back + * but keep listening. */ - isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length); - isc_buffer_add(&rev->buffer, ev->n); - rev->result = ev->result; - rev->id = id; - rev->addr = ev->address; - rev->pktinfo = ev->pktinfo; - rev->attributes = ev->attributes; - if (queue_response) { - ISC_LIST_APPEND(resp->items, rev, ev_link); - } else { - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); - request_log(disp, resp, LVL(90), - "[a] Sent event %p buffer %p len %d to task %p", - rev, rev->buffer.base, rev->buffer.length, - resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); - } -unlock: - if (qidlocked) { - UNLOCK(&qid->lock); - } + response = NULL; - /* - * Restart recv() to get the next packet. - */ -restart: - result = startrecv(disp, dispsock); - if (result != ISC_R_SUCCESS && dispsock != NULL) { - /* - * XXX: wired. There seems to be no recovery process other than - * deactivate this socket anyway (since we cannot start - * receiving, we won't be able to receive a cancel event - * from the user). - */ - deactivate_dispsocket(disp, dispsock); + timeout = resp->timeout - dispentry_runtime(resp); + if (timeout <= 0) { + eresult = ISC_R_TIMEDOUT; + goto done; } - isc_event_free(&ev_in); + dispatch_getnext(disp, resp, resp->timeout - dispentry_runtime(resp)); + +done: UNLOCK(&disp->lock); + + if (response != NULL) { + response(eresult, region, resp->arg); + } + + dispentry_detach(&resp); } /* @@ -1318,101 +601,98 @@ restart: * restart. */ static void -tcp_recv(isc_task_t *task, isc_event_t *ev_in) { - dns_dispatch_t *disp = ev_in->ev_arg; - dns_tcpmsg_t *tcpmsg = &disp->tcpmsg; +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dns_dispatch_t *disp = (dns_dispatch_t *)arg; + dns_dispentry_t *resp = NULL, *next = NULL; dns_messageid_t id; isc_result_t dres; unsigned int flags; - dns_dispentry_t *resp; - dns_dispatchevent_t *rev; unsigned int bucket; - bool killit; - bool queue_response; - dns_qid_t *qid; + dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; - - UNUSED(task); + isc_buffer_t source; + isc_sockaddr_t peer; + dns_displist_t resps; REQUIRE(VALID_DISPATCH(disp)); - qid = disp->qid; + qid = disp->mgr->qid; LOCK(&disp->lock); - dispatch_log(disp, LVL(90), - "got TCP packet: requests %d, buffers %d, recvs %d", - disp->requests, disp->tcpbuffers, disp->recv_pending); + dispatch_log(disp, LVL(90), "TCP read:%s:requests %d, buffers %d", + isc_result_totext(eresult), disp->requests, + disp->tcpbuffers); - INSIST(disp->recv_pending != 0); - disp->recv_pending = 0; + peer = isc_nmhandle_peeraddr(handle); + ISC_LIST_INIT(resps); - if (disp->refcount == 0) { + switch (eresult) { + case ISC_R_SUCCESS: + /* got our answer */ + break; + + case ISC_R_SHUTTINGDOWN: + case ISC_R_CANCELED: + case ISC_R_EOF: + dispatch_log(disp, LVL(90), "shutting down: %s", + isc_result_totext(eresult)); /* - * This dispatcher is shutting down. Force cancellation. + * If there are any active responses, shut them all down. */ - tcpmsg->result = ISC_R_CANCELED; - } + for (resp = ISC_LIST_HEAD(disp->active); resp != NULL; + resp = next) { + next = ISC_LIST_NEXT(resp, alink); + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + ISC_LIST_UNLINK(disp->active, resp, alink); + ISC_LIST_APPEND(resps, resp, rlink); + } + goto done; - if (tcpmsg->result != ISC_R_SUCCESS) { - switch (tcpmsg->result) { - case ISC_R_CANCELED: - break; + case ISC_R_TIMEDOUT: + /* + * Time out the oldest response in the active queue, + * and move it to the end. (We don't remove it from the + * active queue immediately, though, because the callback + * might decide to keep waiting and leave it active.) + */ + resp = ISC_LIST_HEAD(disp->active); + if (resp != NULL) { + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + ISC_LIST_UNLINK(disp->active, resp, alink); + ISC_LIST_APPEND(disp->active, resp, alink); + } + goto done; - case ISC_R_EOF: - dispatch_log(disp, LVL(90), "shutting down on EOF"); - do_cancel(disp); - break; - - case ISC_R_CONNECTIONRESET: + default: + if (eresult == ISC_R_CONNECTIONRESET) { level = ISC_LOG_INFO; - goto logit; - - default: + } else { level = ISC_LOG_ERROR; - logit: - isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf)); - dispatch_log(disp, level, - "shutting down due to TCP " - "receive error: %s: %s", - buf, isc_result_totext(tcpmsg->result)); - do_cancel(disp); - break; } - /* - * The event is statically allocated in the tcpmsg - * structure, and destroy_disp() frees the tcpmsg, so we must - * free the event *before* calling destroy_disp(). - */ - isc_event_free(&ev_in); - - disp->shutting_down = 1; - disp->shutdown_why = tcpmsg->result; - - /* - * If the recv() was canceled pass the word on. - */ - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); - } - return; + isc_sockaddr_format(&peer, buf, sizeof(buf)); + dispatch_log(disp, level, + "shutting down due to TCP " + "receive error: %s: %s", + buf, isc_result_totext(eresult)); + goto done; } - dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", - tcpmsg->result, tcpmsg->buffer.length, - tcpmsg->buffer.base); + dispatch_log(disp, LVL(90), "success, length == %d, addr = %p", + region->length, region->base); /* * Peek into the buffer to see what we can see. */ - dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags); + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); + dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1420,283 +700,51 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); /* - * Allocate an event to send to the query or response client, and - * allocate a new buffer for our use. - */ - - /* - * Look at flags. If query, drop it. If response, - * look to see where it goes. + * Look at the message flags. If it's a query, ignore it + * and keep reading. */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* * Query. */ - goto restart; + goto next; } /* - * Response. + * We have a valid response; find the associated dispentry object + * and call the caller back. */ - bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport); + bucket = dns_hash(qid, &peer, id, disp->localport); LOCK(&qid->lock); - resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket); + resp = entry_search(qid, &peer, id, disp->localport, bucket); + if (resp != NULL) { + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + } dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); - - if (resp == NULL) { - goto unlock; - } - queue_response = resp->item_out; - rev = allocate_devent(disp); - if (rev == NULL) { - goto unlock; - } - - /* - * At this point, rev contains the event we want to fill in, and - * resp contains the information on the place to send it to. - * Send the event off. - */ - dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer); - disp->tcpbuffers++; - rev->result = ISC_R_SUCCESS; - rev->id = id; - rev->addr = tcpmsg->address; - if (queue_response) { - ISC_LIST_APPEND(resp->items, rev, ev_link); - } else { - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); - request_log(disp, resp, LVL(90), - "[b] Sent event %p buffer %p len %d to task %p", - rev, rev->buffer.base, rev->buffer.length, - resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); - } -unlock: UNLOCK(&qid->lock); - /* - * Restart recv() to get the next packet. - */ -restart: - (void)startrecv(disp, NULL); +next: + dispatch_getnext(disp, NULL, -1); - isc_event_free(&ev_in); +done: UNLOCK(&disp->lock); -} -/* - * disp must be locked. - */ -static isc_result_t -startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t res; - isc_region_t region; - isc_socket_t *sock; - - if (disp->shutting_down == 1) { - return (ISC_R_SUCCESS); - } - - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) { - return (ISC_R_SUCCESS); - } - - if (disp->recv_pending != 0 && dispsock == NULL) { - return (ISC_R_SUCCESS); - } - - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && - dispsock == NULL) { - return (ISC_R_SUCCESS); - } - - if (dispsock != NULL) { - sock = dispsock->socket; + if (resp != NULL) { + /* We got a matching response, or timed out */ + resp->response(eresult, region, resp->arg); + dispentry_detach(&resp); } else { - sock = disp->socket; - } - INSIST(sock != NULL); - - switch (disp->socktype) { - /* - * UDP reads are always maximal. - */ - case isc_sockettype_udp: - region.length = disp->mgr->buffersize; - region.base = allocate_udp_buffer(disp); - if (region.base == NULL) { - return (ISC_R_NOMEMORY); - } - if (dispsock != NULL) { - isc_task_t *dt = dispsock->task; - isc_socketevent_t *sev = allocate_sevent( - disp, sock, ISC_SOCKEVENT_RECVDONE, udp_exrecv, - dispsock); - if (sev == NULL) { - free_buffer(disp, region.base, region.length); - return (ISC_R_NOMEMORY); - } - - res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - return (res); - } - } else { - isc_task_t *dt = disp->task[0]; - isc_socketevent_t *sev = allocate_sevent( - disp, sock, ISC_SOCKEVENT_RECVDONE, udp_shrecv, - disp); - if (sev == NULL) { - free_buffer(disp, region.base, region.length); - return (ISC_R_NOMEMORY); - } - - res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - disp->shutdown_why = res; - disp->shutting_down = 1; - do_cancel(disp); - return (ISC_R_SUCCESS); /* recover by cancel */ - } - INSIST(disp->recv_pending == 0); - disp->recv_pending = 1; - } - break; - - case isc_sockettype_tcp: - res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0], - tcp_recv, disp); - if (res != ISC_R_SUCCESS) { - disp->shutdown_why = res; - disp->shutting_down = 1; - do_cancel(disp); - return (ISC_R_SUCCESS); /* recover by cancel */ - } - INSIST(disp->recv_pending == 0); - disp->recv_pending = 1; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - - return (ISC_R_SUCCESS); -} - -/* - * Mgr must be locked when calling this function. - */ -static bool -destroy_mgr_ok(dns_dispatchmgr_t *mgr) { - mgr_log(mgr, LVL(90), - "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, ", - MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list)); - if (!MGR_IS_SHUTTINGDOWN(mgr)) { - return (false); - } - if (!ISC_LIST_EMPTY(mgr->list)) { - return (false); - } - if (isc_refcount_current(&mgr->irefs) != 0) { - return (false); - } - - return (true); -} - -/* - * Mgr must be unlocked when calling this function. - */ -static void -destroy_mgr(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; - - mgr = *mgrp; - *mgrp = NULL; - - mgr->magic = 0; - isc_mutex_destroy(&mgr->lock); - mgr->state = 0; - - if (mgr->qid != NULL) { - qid_destroy(mgr->mctx, &mgr->qid); - } - - isc_mutex_destroy(&mgr->buffer_lock); - - if (mgr->blackhole != NULL) { - dns_acl_detach(&mgr->blackhole); - } - - if (mgr->stats != NULL) { - isc_stats_detach(&mgr->stats); - } - - if (mgr->v4ports != NULL) { - isc_mem_put(mgr->mctx, mgr->v4ports, - mgr->nv4ports * sizeof(in_port_t)); - } - if (mgr->v6ports != NULL) { - isc_mem_put(mgr->mctx, mgr->v6ports, - mgr->nv6ports * sizeof(in_port_t)); - } - isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); -} - -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp, - isc_socket_t *dup_socket, bool duponly) { - isc_socket_t *sock; - isc_result_t result; - - sock = *sockp; - if (sock != NULL) { - result = isc_socket_open(sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - } else if (dup_socket != NULL && - (!isc_socket_hasreuseport() || duponly)) { - result = isc_socket_dup(dup_socket, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - - isc_socket_setname(sock, "dispatcher", NULL); - *sockp = sock; - return (ISC_R_SUCCESS); - } else { - result = isc_socket_create(mgr, isc_sockaddr_pf(local), - isc_sockettype_udp, &sock); - if (result != ISC_R_SUCCESS) { - return (result); + /* We're being shut down; cancel all outstanding resps */ + for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, rlink); + ISC_LIST_UNLINK(resps, resp, rlink); + resp->response(ISC_R_SHUTTINGDOWN, region, resp->arg); + dispentry_detach(&resp); } } - isc_socket_setname(sock, "dispatcher", NULL); - -#ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(sock, true); -#endif /* ifndef ISC_ALLOW_MAPPED */ - result = isc_socket_bind(sock, local, options); - if (result != ISC_R_SUCCESS) { - if (*sockp == NULL) { - isc_socket_detach(&sock); - } else { - isc_socket_close(sock); - } - return (result); - } - - *sockp = sock; - return (ISC_R_SUCCESS); + dns_dispatch_detach(&disp); } /*% @@ -1705,15 +753,55 @@ open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, * normally set the ports explicitly, but is provided to fill some minor corner * cases. */ -static isc_result_t +static void create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) { - isc_result_t result; - - result = isc_portset_create(mctx, portsetp); - if (result != ISC_R_SUCCESS) { - return (result); - } + isc_portset_create(mctx, portsetp); isc_portset_addrange(*portsetp, 1024, 65535); +} + +static isc_result_t +setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, + isc_portset_t *v6portset) { + in_port_t *v4ports, *v6ports, p = 0; + unsigned int nv4ports, nv6ports, i4 = 0, i6 = 0; + + nv4ports = isc_portset_nports(v4portset); + nv6ports = isc_portset_nports(v6portset); + + v4ports = NULL; + if (nv4ports != 0) { + v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports); + } + v6ports = NULL; + if (nv6ports != 0) { + v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports); + } + + do { + if (isc_portset_isset(v4portset, p)) { + INSIST(i4 < nv4ports); + v4ports[i4++] = p; + } + if (isc_portset_isset(v6portset, p)) { + INSIST(i6 < nv6ports); + v6ports[i6++] = p; + } + } while (p++ < 65535); + INSIST(i4 == nv4ports && i6 == nv6ports); + + if (mgr->v4ports != NULL) { + isc_mem_put(mgr->mctx, mgr->v4ports, + mgr->nv4ports * sizeof(in_port_t)); + } + mgr->v4ports = v4ports; + mgr->nv4ports = nv4ports; + + if (mgr->v6ports != NULL) { + isc_mem_put(mgr->mctx, mgr->v6ports, + mgr->nv6ports * sizeof(in_port_t)); + } + mgr->v6ports = v6ports; + mgr->nv6ports = nv6ports; return (ISC_R_SUCCESS); } @@ -1723,9 +811,9 @@ create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) { */ isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; - isc_result_t result; +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, + dns_dispatchmgr_t **mgrp) { + dns_dispatchmgr_t *mgr = NULL; isc_portset_t *v4portset = NULL; isc_portset_t *v6portset = NULL; @@ -1733,46 +821,56 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { REQUIRE(mgrp != NULL && *mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); - *mgr = (dns_dispatchmgr_t){ 0 }; + *mgr = (dns_dispatchmgr_t){ .magic = 0 }; + + isc_refcount_init(&mgr->references, 1); isc_mem_attach(mctx, &mgr->mctx); + isc_nm_attach(nm, &mgr->nm); isc_mutex_init(&mgr->lock); - isc_mutex_init(&mgr->buffer_lock); - - isc_refcount_init(&mgr->irefs, 0); ISC_LIST_INIT(mgr->list); - mgr->magic = DNS_DISPATCHMGR_MAGIC; + create_default_portset(mctx, &v4portset); + create_default_portset(mctx, &v6portset); - result = create_default_portset(mctx, &v4portset); - if (result == ISC_R_SUCCESS) { - result = create_default_portset(mctx, &v6portset); - if (result == ISC_R_SUCCESS) { - result = dns_dispatchmgr_setavailports(mgr, v4portset, - v6portset); - } - } - if (v4portset != NULL) { - isc_portset_destroy(mctx, &v4portset); - } - if (v6portset != NULL) { - isc_portset_destroy(mctx, &v6portset); - } - if (result != ISC_R_SUCCESS) { - goto kill_dpool; - } + setavailports(mgr, v4portset, v6portset); + + isc_portset_destroy(mctx, &v4portset); + isc_portset_destroy(mctx, &v6portset); + + qid_allocate(mgr, &mgr->qid); + mgr->magic = DNS_DISPATCHMGR_MAGIC; *mgrp = mgr; return (ISC_R_SUCCESS); +} -kill_dpool: - isc_mutex_destroy(&mgr->buffer_lock); - isc_mutex_destroy(&mgr->lock); - isc_mem_putanddetach(&mctx, mgr, sizeof(dns_dispatchmgr_t)); +void +dns_dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + REQUIRE(mgrp != NULL && *mgrp == NULL); - return (result); + isc_refcount_increment(&mgr->references); + + *mgrp = mgr; +} + +void +dns_dispatchmgr_detach(dns_dispatchmgr_t **mgrp) { + dns_dispatchmgr_t *mgr = NULL; + uint_fast32_t ref; + + REQUIRE(mgrp != NULL && VALID_DISPATCHMGR(*mgrp)); + + mgr = *mgrp; + *mgrp = NULL; + + ref = isc_refcount_decrement(&mgr->references); + if (ref == 1) { + dispatchmgr_destroy(mgr); + } } void @@ -1793,135 +891,42 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { isc_result_t dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, isc_portset_t *v6portset) { - in_port_t *v4ports, *v6ports, p; - unsigned int nv4ports, nv6ports, i4, i6; + REQUIRE(VALID_DISPATCHMGR(mgr)); + return (setavailports(mgr, v4portset, v6portset)); +} +static void +dispatchmgr_destroy(dns_dispatchmgr_t *mgr) { REQUIRE(VALID_DISPATCHMGR(mgr)); - nv4ports = isc_portset_nports(v4portset); - nv6ports = isc_portset_nports(v6portset); + isc_refcount_destroy(&mgr->references); - v4ports = NULL; - if (nv4ports != 0) { - v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports); - } - v6ports = NULL; - if (nv6ports != 0) { - v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports); + mgr->magic = 0; + isc_mutex_destroy(&mgr->lock); + mgr->state = 0; + + qid_destroy(mgr->mctx, &mgr->qid); + + if (mgr->blackhole != NULL) { + dns_acl_detach(&mgr->blackhole); } - p = 0; - i4 = 0; - i6 = 0; - do { - if (isc_portset_isset(v4portset, p)) { - INSIST(i4 < nv4ports); - v4ports[i4++] = p; - } - if (isc_portset_isset(v6portset, p)) { - INSIST(i6 < nv6ports); - v6ports[i6++] = p; - } - } while (p++ < 65535); - INSIST(i4 == nv4ports && i6 == nv6ports); + if (mgr->stats != NULL) { + isc_stats_detach(&mgr->stats); + } - PORTBUFLOCK(mgr); if (mgr->v4ports != NULL) { isc_mem_put(mgr->mctx, mgr->v4ports, mgr->nv4ports * sizeof(in_port_t)); } - mgr->v4ports = v4ports; - mgr->nv4ports = nv4ports; - if (mgr->v6ports != NULL) { isc_mem_put(mgr->mctx, mgr->v6ports, mgr->nv6ports * sizeof(in_port_t)); } - mgr->v6ports = v6ports; - mgr->nv6ports = nv6ports; - PORTBUFUNLOCK(mgr); - return (ISC_R_SUCCESS); -} + isc_nm_detach(&mgr->nm); -static isc_result_t -dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment) { - isc_result_t result; - - REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); - REQUIRE(maxbuffers > 0); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); - UNUSED(maxrequests); - - /* - * Keep some number of items around. This should be a config - * option. For now, keep 8, but later keep at least two even - * if the caller wants less. This allows us to ensure certain - * things, like an event can be "freed" and the next allocation - * will always succeed. - * - * Note that if limits are placed on anything here, we use one - * event internally, so the actual limit should be "wanted + 1." - * - * XXXMLG - */ - - if (maxbuffers < 8) { - maxbuffers = 8; - } - - LOCK(&mgr->buffer_lock); - - if (maxbuffers > mgr->maxbuffers) { - mgr->maxbuffers = maxbuffers; - } - - /* Create or adjust socket pool */ - if (mgr->qid != NULL) { - UNLOCK(&mgr->buffer_lock); - return (ISC_R_SUCCESS); - } - - result = qid_allocate(mgr, buckets, increment, &mgr->qid, true); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - mgr->buffersize = buffersize; - mgr->maxbuffers = maxbuffers; - UNLOCK(&mgr->buffer_lock); - return (ISC_R_SUCCESS); - -cleanup: - UNLOCK(&mgr->buffer_lock); - return (result); -} - -void -dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; - bool killit; - - REQUIRE(mgrp != NULL); - REQUIRE(VALID_DISPATCHMGR(*mgrp)); - - mgr = *mgrp; - *mgrp = NULL; - - LOCK(&mgr->lock); - mgr->state |= MGR_SHUTTINGDOWN; - killit = destroy_mgr_ok(mgr); - UNLOCK(&mgr->lock); - - mgr_log(mgr, LVL(90), "destroy: killit=%d", killit); - - if (killit) { - destroy_mgr(&mgr); - } + isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); } void @@ -1933,105 +938,31 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) { isc_stats_attach(stats, &mgr->stats); } -static int -port_cmp(const void *key, const void *ent) { - in_port_t p1 = *(const in_port_t *)key; - in_port_t p2 = *(const in_port_t *)ent; - - if (p1 < p2) { - return (-1); - } else if (p1 == p2) { - return (0); - } else { - return (1); - } -} - -static bool -portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_sockaddr_t *sockaddrp) { - isc_sockaddr_t sockaddr; - isc_result_t result; - in_port_t *ports, port; - unsigned int nports; - bool available = false; - - REQUIRE(sock != NULL || sockaddrp != NULL); - - PORTBUFLOCK(mgr); - if (sock != NULL) { - sockaddrp = &sockaddr; - result = isc_socket_getsockname(sock, sockaddrp); - if (result != ISC_R_SUCCESS) { - goto unlock; - } - } - - if (isc_sockaddr_pf(sockaddrp) == AF_INET) { - ports = mgr->v4ports; - nports = mgr->nv4ports; - } else { - ports = mgr->v6ports; - nports = mgr->nv6ports; - } - if (ports == NULL) { - goto unlock; - } - - port = isc_sockaddr_getport(sockaddrp); - if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL) - { - available = true; - } - -unlock: - PORTBUFUNLOCK(mgr); - return (available); -} - -#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask))) - -static isc_result_t -qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, - unsigned int increment, dns_qid_t **qidp, bool needsocktable) { - dns_qid_t *qid; +static void +qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp) { + dns_qid_t *qid = NULL; unsigned int i; - REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); REQUIRE(qidp != NULL && *qidp == NULL); qid = isc_mem_get(mgr->mctx, sizeof(*qid)); + *qid = (dns_qid_t){ .qid_nbuckets = DNS_QID_BUCKETS, + .qid_increment = DNS_QID_INCREMENT }; qid->qid_table = isc_mem_get(mgr->mctx, - buckets * sizeof(dns_displist_t)); - - qid->sock_table = NULL; - if (needsocktable) { - qid->sock_table = isc_mem_get( - mgr->mctx, buckets * sizeof(dispsocketlist_t)); + DNS_QID_BUCKETS * sizeof(dns_displist_t)); + for (i = 0; i < qid->qid_nbuckets; i++) { + ISC_LIST_INIT(qid->qid_table[i]); } isc_mutex_init(&qid->lock); - - for (i = 0; i < buckets; i++) { - ISC_LIST_INIT(qid->qid_table[i]); - if (qid->sock_table != NULL) { - ISC_LIST_INIT(qid->sock_table[i]); - } - } - - qid->qid_nbuckets = buckets; - qid->qid_increment = increment; qid->magic = QID_MAGIC; *qidp = qid; - return (ISC_R_SUCCESS); } static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { - dns_qid_t *qid; + dns_qid_t *qid = NULL; REQUIRE(qidp != NULL); qid = *qidp; @@ -2042,10 +973,6 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { qid->magic = 0; isc_mem_put(mctx, qid->qid_table, qid->qid_nbuckets * sizeof(dns_displist_t)); - if (qid->sock_table != NULL) { - isc_mem_put(mctx, qid->sock_table, - qid->qid_nbuckets * sizeof(dispsocketlist_t)); - } isc_mutex_destroy(&qid->lock); isc_mem_put(mctx, qid, sizeof(*qid)); } @@ -2053,11 +980,10 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { /* * Allocate and set important limits. */ -static isc_result_t -dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, +static void +dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - isc_result_t result; + dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(dispp != NULL && *dispp == NULL); @@ -2068,54 +994,19 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, */ disp = isc_mem_get(mgr->mctx, sizeof(*disp)); - isc_refcount_increment0(&mgr->irefs); + *disp = (dns_dispatch_t){ .socktype = type }; - disp->magic = 0; - disp->mgr = mgr; - disp->maxrequests = maxrequests; - disp->attributes = 0; + dns_dispatchmgr_attach(mgr, &disp->mgr); + isc_refcount_init(&disp->references, 1); ISC_LINK_INIT(disp, link); - disp->refcount = 1; - disp->recv_pending = 0; - memset(&disp->local, 0, sizeof(disp->local)); - memset(&disp->peer, 0, sizeof(disp->peer)); - disp->localport = 0; - disp->shutting_down = 0; - disp->shutdown_out = 0; - disp->connected = 0; - disp->tcpmsg_valid = 0; - disp->shutdown_why = ISC_R_UNEXPECTED; - disp->requests = 0; - disp->tcpbuffers = 0; - disp->qid = NULL; - ISC_LIST_INIT(disp->activesockets); - ISC_LIST_INIT(disp->inactivesockets); - disp->nsockets = 0; - disp->port_table = NULL; - disp->dscp = -1; + ISC_LIST_INIT(disp->active); + ISC_LIST_INIT(disp->pending); isc_mutex_init(&disp->lock); - disp->failsafe_ev = allocate_devent(disp); - if (disp->failsafe_ev == NULL) { - result = ISC_R_NOMEMORY; - goto kill_lock; - } - disp->magic = DISPATCH_MAGIC; *dispp = disp; - return (ISC_R_SUCCESS); - - /* - * error returns - */ -kill_lock: - isc_mutex_destroy(&disp->lock); - isc_refcount_decrement(&mgr->irefs); - isc_mem_put(mgr->mctx, disp, sizeof(*disp)); - - return (result); } /* @@ -2123,520 +1014,209 @@ kill_lock: */ static void dispatch_free(dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - dns_dispatchmgr_t *mgr; + dns_dispatch_t *disp = NULL; + dns_dispatchmgr_t *mgr = NULL; REQUIRE(VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; + disp->magic = 0; + mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); - if (disp->tcpmsg_valid) { - dns_tcpmsg_invalidate(&disp->tcpmsg); - disp->tcpmsg_valid = 0; - } - - INSIST(disp->tcpbuffers == 0); INSIST(disp->requests == 0); - INSIST(disp->recv_pending == 0); - INSIST(ISC_LIST_EMPTY(disp->activesockets)); - INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); + INSIST(ISC_LIST_EMPTY(disp->active)); - isc_refcount_decrement(&mgr->irefs); - isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev)); - disp->failsafe_ev = NULL; - - if (disp->qid != NULL) { - qid_destroy(mgr->mctx, &disp->qid); - } - - if (disp->port_table != NULL) { - for (int i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { - INSIST(ISC_LIST_EMPTY(disp->port_table[i])); - } - isc_mem_put(mgr->mctx, disp->port_table, - sizeof(disp->port_table[0]) * - DNS_DISPATCH_PORTTABLESIZE); - } - - disp->mgr = NULL; isc_mutex_destroy(&disp->lock); - disp->magic = 0; - isc_refcount_decrement(&mgr->irefs); + isc_mem_put(mgr->mctx, disp, sizeof(*disp)); } isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - const isc_sockaddr_t *destaddr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp) { - isc_result_t result; - dns_dispatch_t *disp; - - UNUSED(maxbuffers); - UNUSED(buffersize); +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + const isc_sockaddr_t *destaddr, isc_dscp_t dscp, + dns_dispatch_t **dispp) { + dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp); - REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0); - REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0); + REQUIRE(destaddr != NULL); - if (destaddr == NULL) { - attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */ - } + UNUSED(dscp); LOCK(&mgr->lock); - /* - * dispatch_allocate() checks mgr for us. - * qid_allocate() checks buckets and increment for us. - */ - disp = NULL; - result = dispatch_allocate(mgr, maxrequests, &disp); - if (result != ISC_R_SUCCESS) { - UNLOCK(&mgr->lock); - return (result); - } + dispatch_allocate(mgr, isc_socktype_tcp, &disp); - result = qid_allocate(mgr, buckets, increment, &disp->qid, false); - if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; - } + disp->peer = *destaddr; - disp->socktype = isc_sockettype_tcp; - disp->socket = NULL; - isc_socket_attach(sock, &disp->socket); - - disp->sepool = NULL; - - disp->ntasks = 1; - disp->task[0] = NULL; - result = isc_task_create(taskmgr, 50, &disp->task[0]); - if (result != ISC_R_SUCCESS) { - goto kill_socket; - } - - disp->ctlevent = - isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, - destroy_disp, disp, sizeof(isc_event_t)); - - isc_task_setname(disp->task[0], "tcpdispatch", disp); - - dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); - disp->tcpmsg_valid = 1; - - disp->attributes = attributes; - - if (localaddr == NULL) { - if (destaddr != NULL) { - switch (isc_sockaddr_pf(destaddr)) { - case AF_INET: - isc_sockaddr_any(&disp->local); - break; - case AF_INET6: - isc_sockaddr_any6(&disp->local); - break; - } - } - } else { + if (localaddr != NULL) { disp->local = *localaddr; - } - - if (destaddr != NULL) { - disp->peer = *destaddr; + } else { + int pf; + pf = isc_sockaddr_pf(destaddr); + isc_sockaddr_anyofpf(&disp->local, pf); + isc_sockaddr_setport(&disp->local, 0); } /* * Append it to the dispatcher list. */ + + /* FIXME: There should be a lookup hashtable here */ ISC_LIST_APPEND(mgr->list, disp, link); UNLOCK(&mgr->lock); - mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); + mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p", + disp); *dispp = disp; return (ISC_R_SUCCESS); - -kill_socket: - isc_socket_detach(&disp->socket); -deallocate_dispatch: - dispatch_free(&disp); - - UNLOCK(&mgr->lock); - - return (result); } isc_result_t dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - isc_result_t result; - isc_sockaddr_t peeraddr; - isc_sockaddr_t sockname; - unsigned int attributes, mask; - bool match = false; + dns_dispatch_t *disp_connected = NULL; + dns_dispatch_t *disp_fallback = NULL; + isc_result_t result = ISC_R_NOTFOUND; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(destaddr != NULL); + REQUIRE(connected != NULL); REQUIRE(dispp != NULL && *dispp == NULL); - /* First pass */ - attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED; - mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE | - DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED; - LOCK(&mgr->lock); - disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL && !match) { + + for (dns_dispatch_t *disp = ISC_LIST_HEAD(mgr->list); disp != NULL; + disp = ISC_LIST_NEXT(disp, link)) + { + isc_sockaddr_t sockname; + isc_sockaddr_t peeraddr; + LOCK(&disp->lock); - if ((disp->shutting_down == 0) && - ATTRMATCH(disp->attributes, attributes, mask) && - (localaddr == NULL || - isc_sockaddr_eqaddr(localaddr, &disp->local))) - { - result = isc_socket_getsockname(disp->socket, - &sockname); - if (result == ISC_R_SUCCESS) { - result = isc_socket_getpeername(disp->socket, - &peeraddr); - } - if (result == ISC_R_SUCCESS && - isc_sockaddr_equal(destaddr, &peeraddr) && - (localaddr == NULL || - isc_sockaddr_eqaddr(localaddr, &sockname))) - { - /* attach */ - disp->refcount++; - *dispp = disp; - match = true; - if (connected != NULL) { - *connected = true; - } - } + + if (disp->handle != NULL) { + sockname = isc_nmhandle_localaddr(disp->handle); + peeraddr = isc_nmhandle_peeraddr(disp->handle); + } else { + sockname = disp->local; + peeraddr = disp->peer; } + + /* + * The conditions match: + * 1. socktype is TCP + * 2. destination address is same + * 3. local address is either NULL or same + */ + if (disp->socktype == isc_socktype_tcp && + isc_sockaddr_equal(destaddr, &peeraddr) && + (localaddr == NULL || + isc_sockaddr_eqaddr(localaddr, &sockname))) + { + if (atomic_load(&disp->state) == + DNS_DISPATCHSTATE_CONNECTED) { + /* We found connected dispatch */ + disp_connected = disp; + UNLOCK(&disp->lock); + break; + } + + /* We found "a" dispatch, store it for later */ + if (disp_fallback == NULL) { + disp_fallback = disp; + } + + UNLOCK(&disp->lock); + continue; + } + UNLOCK(&disp->lock); - disp = ISC_LIST_NEXT(disp, link); - } - if (match || connected == NULL) { - UNLOCK(&mgr->lock); - return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); } - /* Second pass, only if connected != NULL */ - attributes = DNS_DISPATCHATTR_TCP; + if (disp_connected != NULL) { + /* We found connected dispatch */ + INSIST(disp_connected->handle != NULL); - disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL && !match) { - LOCK(&disp->lock); - if ((disp->shutting_down == 0) && - ATTRMATCH(disp->attributes, attributes, mask) && - (localaddr == NULL || - isc_sockaddr_eqaddr(localaddr, &disp->local)) && - isc_sockaddr_equal(destaddr, &disp->peer)) - { - /* attach */ - disp->refcount++; - *dispp = disp; - match = true; - } - UNLOCK(&disp->lock); - disp = ISC_LIST_NEXT(disp, link); + *connected = true; + dns_dispatch_attach(disp_connected, dispp); + + result = ISC_R_SUCCESS; + } else if (disp_fallback != NULL) { + /* We found matching dispatch */ + *connected = false; + + dns_dispatch_attach(disp_fallback, dispp); + + result = ISC_R_SUCCESS; } + UNLOCK(&mgr->lock); - return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); + + return (result); } isc_result_t -dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int buffersize, unsigned int maxbuffers, - unsigned int maxrequests, unsigned int buckets, - unsigned int increment, unsigned int attributes, - dns_dispatch_t **dispp) { +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); - REQUIRE(taskmgr != NULL); - REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); - REQUIRE(maxbuffers > 0); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); REQUIRE(dispp != NULL && *dispp == NULL); - REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0); - - result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers, - maxrequests, buckets, increment); - if (result != ISC_R_SUCCESS) { - return (result); - } LOCK(&mgr->lock); - - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - REQUIRE(isc_sockaddr_getport(localaddr) == 0); - goto createudp; + result = dispatch_createudp(mgr, localaddr, &disp); + if (result == ISC_R_SUCCESS) { + *dispp = disp; } - -createudp: - /* - * Nope, create one. - */ - result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - maxrequests, attributes, &disp, NULL); - - if (result != ISC_R_SUCCESS) { - UNLOCK(&mgr->lock); - return (result); - } - UNLOCK(&mgr->lock); - *dispp = disp; - - return (ISC_R_SUCCESS); -} - -/* - * mgr should be locked. - */ - -#ifndef DNS_DISPATCH_HELD -#define DNS_DISPATCH_HELD 20U -#endif /* ifndef DNS_DISPATCH_HELD */ - -static isc_result_t -get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, - isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly) { - unsigned int i, j; - isc_socket_t *held[DNS_DISPATCH_HELD]; - isc_sockaddr_t localaddr_bound; - isc_socket_t *sock = NULL; - isc_result_t result = ISC_R_SUCCESS; - bool anyport; - - INSIST(sockp != NULL && *sockp == NULL); - - localaddr_bound = *localaddr; - anyport = (isc_sockaddr_getport(localaddr) == 0); - - if (anyport) { - unsigned int nports; - in_port_t *ports; - - /* - * If no port is specified, we first try to pick up a random - * port by ourselves. - */ - if (isc_sockaddr_pf(localaddr) == AF_INET) { - nports = disp->mgr->nv4ports; - ports = disp->mgr->v4ports; - } else { - nports = disp->mgr->nv6ports; - ports = disp->mgr->v6ports; - } - if (nports == 0) { - return (ISC_R_ADDRNOTAVAIL); - } - - for (i = 0; i < 1024; i++) { - in_port_t prt; - - prt = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr_bound, prt); - result = open_socket(sockmgr, &localaddr_bound, 0, - &sock, NULL, false); - /* - * Continue if the port chosen is already in use - * or the OS has reserved it. - */ - if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE) - { - continue; - } - disp->localport = prt; - *sockp = sock; - return (result); - } - - /* - * If this fails 1024 times, we then ask the kernel for - * choosing one. - */ - } else { - /* Allow to reuse address for non-random ports. */ - result = open_socket(sockmgr, localaddr, - ISC_SOCKET_REUSEADDRESS, &sock, dup_socket, - duponly); - - if (result == ISC_R_SUCCESS) { - *sockp = sock; - } - - return (result); - } - - memset(held, 0, sizeof(held)); - i = 0; - - for (j = 0; j < 0xffffU; j++) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL, false); - if (result != ISC_R_SUCCESS) { - goto end; - } else if (portavailable(mgr, sock, NULL)) { - break; - } - if (held[i] != NULL) { - isc_socket_detach(&held[i]); - } - held[i++] = sock; - sock = NULL; - if (i == DNS_DISPATCH_HELD) { - i = 0; - } - } - if (j == 0xffffU) { - mgr_log(mgr, ISC_LOG_ERROR, - "avoid-v%s-udp-ports: unable to allocate " - "an available port", - isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6"); - result = ISC_R_FAILURE; - goto end; - } - *sockp = sock; - -end: - for (i = 0; i < DNS_DISPATCH_HELD; i++) { - if (held[i] != NULL) { - isc_socket_detach(&held[i]); - } - } return (result); } static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int maxrequests, unsigned int attributes, - dns_dispatch_t **dispp, isc_socket_t *dup_socket) { - isc_result_t result; - dns_dispatch_t *disp; - isc_socket_t *sock = NULL; - int i = 0; - bool duponly = ((attributes & DNS_DISPATCHATTR_CANREUSE) == 0); +dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + dns_dispatch_t **dispp) { + isc_result_t result = ISC_R_SUCCESS; + dns_dispatch_t *disp = NULL; + isc_sockaddr_t sa_any; + + dispatch_allocate(mgr, isc_socktype_udp, &disp); - /* This is an attribute needed only at creation time */ - attributes &= ~DNS_DISPATCHATTR_CANREUSE; /* - * dispatch_allocate() checks mgr for us. + * Check whether this address/port is available locally. */ - disp = NULL; - result = dispatch_allocate(mgr, maxrequests, &disp); - if (result != ISC_R_SUCCESS) { - return (result); - } - - disp->socktype = isc_sockettype_udp; - - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) { - result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock, - dup_socket, duponly); + isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); + if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { + result = isc_nm_checkaddr(localaddr, isc_socktype_udp); if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; - } - - if (isc_log_wouldlog(dns_lctx, 90)) { - char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - - isc_sockaddr_format(localaddr, addrbuf, - ISC_SOCKADDR_FORMATSIZE); - mgr_log(mgr, LVL(90), - "dns_dispatch_createudp: Created" - " UDP dispatch for %s with socket fd %d", - addrbuf, isc_socket_getfd(sock)); - } - } else { - isc_sockaddr_t sa_any; - - /* - * For dispatches using exclusive sockets with a specific - * source address, we only check if the specified address is - * available on the system. Query sockets will be created later - * on demand. - */ - isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); - if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL, - false); - if (sock != NULL) { - isc_socket_detach(&sock); - } - if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; - } - } - - disp->port_table = isc_mem_get( - mgr->mctx, sizeof(disp->port_table[0]) * - DNS_DISPATCH_PORTTABLESIZE); - for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { - ISC_LIST_INIT(disp->port_table[i]); + goto cleanup; } } - disp->socket = sock; + + if (isc_log_wouldlog(dns_lctx, 90)) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(localaddr, addrbuf, + ISC_SOCKADDR_FORMATSIZE); + mgr_log(mgr, LVL(90), + "dispatch_createudp: created UDP dispatch for %s", + addrbuf); + } + disp->local = *localaddr; - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - disp->ntasks = MAX_INTERNAL_TASKS; - } else { - disp->ntasks = 1; - } - for (i = 0; i < disp->ntasks; i++) { - disp->task[i] = NULL; - result = isc_task_create(taskmgr, 0, &disp->task[i]); - if (result != ISC_R_SUCCESS) { - while (--i >= 0) { - isc_task_shutdown(disp->task[i]); - isc_task_detach(&disp->task[i]); - } - goto kill_socket; - } - isc_task_setname(disp->task[i], "udpdispatch", disp); - } - - disp->ctlevent = - isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, - destroy_disp, disp, sizeof(isc_event_t)); - - disp->sepool = NULL; - isc_mem_create(&disp->sepool); - isc_mem_setname(disp->sepool, "disp_sepool"); - - attributes &= ~DNS_DISPATCHATTR_TCP; - attributes |= DNS_DISPATCHATTR_UDP; - disp->attributes = attributes; - /* * Append it to the dispatcher list. */ ISC_LIST_APPEND(mgr->list, disp, link); mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */ - if (disp->socket != NULL) { - dispatch_log(disp, LVL(90), "created socket %p", disp->socket); - } *dispp = disp; @@ -2645,524 +1225,579 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, /* * Error returns. */ -kill_socket: - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); - } -deallocate_dispatch: +cleanup: dispatch_free(&disp); return (result); } +static void +dispatch_destroy(dns_dispatch_t *disp) { + dns_dispatchmgr_t *mgr = disp->mgr; + + LOCK(&mgr->lock); + ISC_LIST_UNLINK(mgr->list, disp, link); + UNLOCK(&mgr->lock); + + dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p", + disp->handle); + + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); + } + + dispatch_free(&disp); + + /* + * Because dispatch uses mgr->mctx, we must detach after freeing + * dispatch, not before. + */ + dns_dispatchmgr_detach(&mgr); +} + void dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(dispp != NULL && *dispp == NULL); - LOCK(&disp->lock); - disp->refcount++; - UNLOCK(&disp->lock); + isc_refcount_increment(&disp->references); *dispp = disp; } -/* - * It is important to lock the manager while we are deleting the dispatch, - * since dns_dispatch_getudp will call dispatch_find, which returns to - * the caller a dispatch but does not attach to it until later. _getudp - * locks the manager, however, so locking it here will keep us from attaching - * to a dispatcher that is in the process of going away. - */ void dns_dispatch_detach(dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - dispsocket_t *dispsock; - bool killit; + dns_dispatch_t *disp = NULL; + uint_fast32_t ref; REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; - LOCK(&disp->lock); + ref = isc_refcount_decrement(&disp->references); + dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1); + if (ref == 1) { + LOCK(&disp->lock); + INSIST(ISC_LIST_EMPTY(disp->pending)); + INSIST(ISC_LIST_EMPTY(disp->active)); + UNLOCK(&disp->lock); - INSIST(disp->refcount > 0); - disp->refcount--; - if (disp->refcount == 0) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - for (dispsock = ISC_LIST_HEAD(disp->activesockets); - dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) - { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); - } - disp->shutting_down = 1; - } - - dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount); - - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + dispatch_destroy(disp); } } isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, - dns_messageid_t *idp, dns_dispentry_t **resp, - isc_socketmgr_t *sockmgr) { - dns_dispentry_t *res; - unsigned int bucket; + unsigned int timeout, const isc_sockaddr_t *dest, + dispatch_cb_t connected, dispatch_cb_t sent, + dispatch_cb_t response, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp) { + dns_dispentry_t *res = NULL; + dns_qid_t *qid = NULL; in_port_t localport = 0; dns_messageid_t id; - int i; - bool ok; - dns_qid_t *qid; - dispsocket_t *dispsocket = NULL; - isc_result_t result; + unsigned int bucket; + bool ok = false; + int i = 0; + dispatch_cb_t oldest_response = NULL; REQUIRE(VALID_DISPATCH(disp)); - REQUIRE(task != NULL); REQUIRE(dest != NULL); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(idp != NULL); - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - REQUIRE(sockmgr != NULL); - } + REQUIRE(disp->socktype == isc_socktype_tcp || + disp->socktype == isc_socktype_udp); LOCK(&disp->lock); - if (disp->shutting_down == 1) { - UNLOCK(&disp->lock); - return (ISC_R_SHUTTINGDOWN); - } - - if (disp->requests >= disp->maxrequests) { + if (disp->requests >= DNS_DISPATCH_MAXREQUESTS) { UNLOCK(&disp->lock); return (ISC_R_QUOTA); } - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && + qid = disp->mgr->qid; + + if (disp->socktype == isc_socktype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { - dispsocket_t *oldestsocket; - dns_dispentry_t *oldestresp; - dns_dispatchevent_t *rev; + dns_dispentry_t *oldest = NULL; /* * Kill oldest outstanding query if the number of sockets * exceeds the quota to keep the room for new queries. */ - oldestsocket = ISC_LIST_HEAD(disp->activesockets); - oldestresp = oldestsocket->resp; - if (oldestresp != NULL && !oldestresp->item_out) { - rev = allocate_devent(oldestresp->disp); - if (rev != NULL) { - rev->buffer.base = NULL; - rev->result = ISC_R_CANCELED; - rev->id = oldestresp->id; - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, - DNS_EVENT_DISPATCH, - oldestresp->action, - oldestresp->arg, oldestresp, - NULL, NULL); - oldestresp->item_out = true; - isc_task_send(oldestresp->task, - ISC_EVENT_PTR(&rev)); - inc_stats(disp->mgr, - dns_resstatscounter_dispabort); - } + oldest = ISC_LIST_HEAD(disp->active); + if (oldest != NULL) { + oldest_response = oldest->response; + inc_stats(disp->mgr, dns_resstatscounter_dispabort); } - - /* - * Move this entry to the tail so that it won't (easily) be - * examined before actually being canceled. - */ - ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link); - ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); } - qid = DNS_QID(disp); + res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - /* - * Get a separate UDP socket with a random port number. - */ - result = get_dispsocket(disp, dest, sockmgr, &dispsocket, - &localport); + *res = (dns_dispentry_t){ .port = localport, + .timeout = timeout, + .peer = *dest, + .connected = connected, + .sent = sent, + .response = response, + .arg = arg }; + + isc_refcount_init(&res->references, 1); + + ISC_LINK_INIT(res, link); + ISC_LINK_INIT(res, alink); + ISC_LINK_INIT(res, plink); + ISC_LINK_INIT(res, rlink); + + if (disp->socktype == isc_socktype_udp) { + isc_result_t result = setup_socket(disp, res, dest, &localport); if (result != ISC_R_SUCCESS) { + isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); UNLOCK(&disp->lock); inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); return (result); } - } else { - localport = disp->localport; } /* - * Try somewhat hard to find an unique ID unless FIXEDID is set - * in which case we use the id passed in via *idp. + * Try somewhat hard to find a unique ID. Start with + * a random number unless DNS_DISPATCHOPT_FIXEDID is set, + * in which case we start with the ID passed in via *idp. */ - LOCK(&qid->lock); if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) { id = *idp; } else { id = (dns_messageid_t)isc_random16(); } - ok = false; - i = 0; + + LOCK(&qid->lock); do { + dns_dispentry_t *entry = NULL; bucket = dns_hash(qid, dest, id, localport); - if (entry_search(qid, dest, id, localport, bucket) == NULL) { + entry = entry_search(qid, dest, id, localport, bucket); + if (entry == NULL) { ok = true; break; } - if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0) { - break; - } id += qid->qid_increment; id &= 0x0000ffff; } while (i++ < 64); UNLOCK(&qid->lock); if (!ok) { + isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); UNLOCK(&disp->lock); return (ISC_R_NOMORE); } - res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); - isc_refcount_increment0(&disp->mgr->irefs); + dns_dispatch_attach(disp, &res->disp); - disp->refcount++; - disp->requests++; - res->task = NULL; - isc_task_attach(task, &res->task); - res->disp = disp; res->id = id; - res->port = localport; res->bucket = bucket; - res->host = *dest; - res->action = action; - res->arg = arg; - res->dispsocket = dispsocket; - if (dispsocket != NULL) { - dispsocket->resp = res; - } - res->item_out = false; - ISC_LIST_INIT(res->items); - ISC_LINK_INIT(res, link); res->magic = RESPONSE_MAGIC; + disp->requests++; + LOCK(&qid->lock); ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); - inc_stats(disp->mgr, (qid == disp->mgr->qid) + inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - request_log(disp, res, LVL(90), "attached to task %p", res->task); - - if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) || - ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) - { - result = startrecv(disp, dispsocket); - if (result != ISC_R_SUCCESS) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); - UNLOCK(&qid->lock); - - if (dispsocket != NULL) { - destroy_dispsocket(disp, &dispsocket); - } - - disp->refcount--; - disp->requests--; - - dec_stats(disp->mgr, - (qid == disp->mgr->qid) - ? dns_resstatscounter_disprequdp - : dns_resstatscounter_dispreqtcp); - - UNLOCK(&disp->lock); - isc_task_detach(&res->task); - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - return (result); - } - } - - if (dispsocket != NULL) { - ISC_LIST_APPEND(disp->activesockets, dispsocket, link); - } + ISC_LIST_APPEND(disp->active, res, alink); UNLOCK(&disp->lock); + if (oldest_response != NULL) { + oldest_response(ISC_R_CANCELED, NULL, res->arg); + } + *idp = id; *resp = res; - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - INSIST(res->dispsocket != NULL); - } - return (ISC_R_SUCCESS); } void -dns_dispatch_starttcp(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); +dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) { + REQUIRE(timeout <= UINT16_MAX); - dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]); + switch (disp->socktype) { + case isc_socktype_udp: + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + if (timeout > 0) { + isc_nmhandle_settimeout(resp->handle, timeout); + } + isc_nm_read(resp->handle, udp_recv, resp); + break; - LOCK(&disp->lock); - if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) { - disp->attributes |= DNS_DISPATCHATTR_CONNECTED; - (void)startrecv(disp, NULL); + case isc_socktype_tcp: + dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); + if (timeout > 0) { + isc_nmhandle_settimeout(disp->handle, timeout); + } + isc_nm_read(disp->handle, tcp_recv, disp); + break; + + default: + INSIST(0); + ISC_UNREACHABLE(); } - UNLOCK(&disp->lock); } isc_result_t -dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { - dns_dispatch_t *disp; - dns_dispatchevent_t *ev; +dns_dispatch_getnext(dns_dispentry_t *resp) { + dns_dispatch_t *disp = NULL; + int32_t timeout; REQUIRE(VALID_RESPONSE(resp)); - REQUIRE(sockevent != NULL && *sockevent != NULL); disp = resp->disp; + REQUIRE(VALID_DISPATCH(disp)); - ev = *sockevent; - *sockevent = NULL; + if (disp->socktype == isc_socktype_udp) { + timeout = resp->timeout - dispentry_runtime(resp); + if (timeout <= 0) { + return (ISC_R_TIMEDOUT); + } + } else { + timeout = -1; + } LOCK(&disp->lock); - - REQUIRE(resp->item_out); - resp->item_out = false; - - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } - free_devent(disp, ev); - - if (disp->shutting_down == 1) { - UNLOCK(&disp->lock); - return (ISC_R_SHUTTINGDOWN); - } - ev = ISC_LIST_HEAD(resp->items); - if (ev != NULL) { - ISC_LIST_UNLINK(resp->items, ev, ev_link); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); - request_log(disp, resp, LVL(90), - "[c] Sent event %p buffer %p len %d to task %p", ev, - ev->buffer.base, ev->buffer.length, resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); - } + dispatch_getnext(disp, resp, timeout); UNLOCK(&disp->lock); return (ISC_R_SUCCESS); } void -dns_dispatch_removeresponse(dns_dispentry_t **resp, - dns_dispatchevent_t **sockevent) { - dns_dispatchmgr_t *mgr; - dns_dispatch_t *disp; - dns_dispentry_t *res; - dispsocket_t *dispsock; - dns_dispatchevent_t *ev; - unsigned int bucket; - bool killit; - unsigned int n; - isc_eventlist_t events; - dns_qid_t *qid; +dns_dispatch_removeresponse(dns_dispentry_t **respp) { + dns_dispatchmgr_t *mgr = NULL; + dns_dispatch_t *disp = NULL; + dns_dispentry_t *resp = NULL; + dns_qid_t *qid = NULL; - REQUIRE(resp != NULL); - REQUIRE(VALID_RESPONSE(*resp)); + REQUIRE(respp != NULL); - res = *resp; - *resp = NULL; + resp = *respp; + + REQUIRE(VALID_RESPONSE(resp)); + + disp = resp->disp; - disp = res->disp; REQUIRE(VALID_DISPATCH(disp)); + mgr = disp->mgr; + REQUIRE(VALID_DISPATCHMGR(mgr)); - qid = DNS_QID(disp); - - if (sockevent != NULL) { - REQUIRE(*sockevent != NULL); - ev = *sockevent; - *sockevent = NULL; - } else { - ev = NULL; - } + qid = mgr->qid; LOCK(&disp->lock); - INSIST(disp->requests > 0); disp->requests--; - dec_stats(disp->mgr, (qid == disp->mgr->qid) + + dec_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - INSIST(disp->refcount > 0); - disp->refcount--; - if (disp->refcount == 0) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - for (dispsock = ISC_LIST_HEAD(disp->activesockets); - dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) - { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); - } - disp->shutting_down = 1; - } - bucket = res->bucket; + deactivate_dispentry(disp, resp); LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); + ISC_LIST_UNLINK(qid->qid_table[resp->bucket], resp, link); UNLOCK(&qid->lock); - - if (ev == NULL && res->item_out) { - /* - * We've posted our event, but the caller hasn't gotten it - * yet. Take it back. - */ - ISC_LIST_INIT(events); - n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH, NULL, - &events); - /* - * We had better have gotten it back. - */ - INSIST(n == 1); - ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events); - } - - if (ev != NULL) { - REQUIRE(res->item_out); - res->item_out = false; - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } - free_devent(disp, ev); - } - - request_log(disp, res, LVL(90), "detaching from task %p", res->task); - isc_task_detach(&res->task); - - if (res->dispsocket != NULL) { - isc_socket_cancel(res->dispsocket->socket, - res->dispsocket->task, ISC_SOCKCANCEL_RECV); - res->dispsocket->resp = NULL; - } - - /* - * Free any buffered responses as well - */ - ev = ISC_LIST_HEAD(res->items); - while (ev != NULL) { - ISC_LIST_UNLINK(res->items, ev, ev_link); - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } - free_devent(disp, ev); - ev = ISC_LIST_HEAD(res->items); - } - res->magic = 0; - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - if (disp->shutting_down == 1) { - do_cancel(disp); - } else { - (void)startrecv(disp, NULL); - } - - killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); - } + + dispentry_detach(respp); } /* * disp must be locked. */ static void -do_cancel(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev; - dns_dispentry_t *resp; - dns_qid_t *qid; +startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) { + switch (disp->socktype) { + case isc_socktype_udp: + REQUIRE(resp != NULL && resp->handle == NULL); - if (disp->shutdown_out == 1) { + TIME_NOW(&resp->start); + isc_nmhandle_attach(handle, &resp->handle); + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + isc_nm_read(resp->handle, udp_recv, resp); + break; + + case isc_socktype_tcp: + REQUIRE(disp != NULL); + LOCK(&disp->lock); + REQUIRE(disp->handle == NULL); + + isc_nmhandle_attach(handle, &disp->handle); + dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); + isc_nm_read(disp->handle, tcp_recv, disp); + UNLOCK(&disp->lock); + + break; + + default: + INSIST(0); + ISC_UNREACHABLE(); + } +} + +static void +tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_dispatch_t *disp = (dns_dispatch_t *)arg; + dns_dispentry_t *resp = NULL, *next = NULL; + dns_displist_t resps; + + dispatch_log(disp, LVL(90), "TCP connected (%p): %s", disp, + isc_result_totext(eresult)); + + ISC_LIST_INIT(resps); + + if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { + eresult = ISC_R_SHUTTINGDOWN; + } + + if (eresult == ISC_R_SUCCESS) { + REQUIRE(atomic_compare_exchange_strong( + &disp->state, + &(uint_fast32_t){ DNS_DISPATCHSTATE_CONNECTING }, + DNS_DISPATCHSTATE_CONNECTED)); + startrecv(handle, disp, NULL); + } + + /* + * If there are pending responses, call the connect + * callbacks for all of them. + */ + LOCK(&disp->lock); + for (resp = ISC_LIST_HEAD(disp->pending); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, plink); + ISC_LIST_UNLINK(disp->pending, resp, plink); + ISC_LIST_APPEND(resps, resp, plink); + } + UNLOCK(&disp->lock); + + for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, plink); + ISC_LIST_UNLINK(resps, resp, plink); + + if (resp->connected != NULL) { + resp->connected(eresult, NULL, resp->arg); + } + dispentry_detach(&resp); + } + + dns_dispatch_detach(&disp); +} + +static void +udp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_dispentry_t *resp = (dns_dispentry_t *)arg; + dns_dispatch_t *disp = resp->disp; + + dispatch_log(disp, LVL(90), "UDP connected (%p): %s", resp, + isc_result_totext(eresult)); + + if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { + eresult = ISC_R_SHUTTINGDOWN; + } + + if (eresult == ISC_R_SUCCESS && resp->canceled) { + eresult = ISC_R_CANCELED; + } else if (eresult == ISC_R_SUCCESS) { + startrecv(handle, disp, resp); + } else if (eresult == ISC_R_ADDRINUSE) { + in_port_t localport = 0; + isc_result_t result; + + /* probably a port collision; try a different one */ + disp->nsockets--; + result = setup_socket(disp, resp, &resp->peer, &localport); + if (result == ISC_R_SUCCESS) { + dns_dispatch_connect(resp); + goto detach; + } + } + + if (resp->connected != NULL) { + resp->connected(eresult, NULL, resp->arg); + } + +detach: + dispentry_detach(&resp); +} + +isc_result_t +dns_dispatch_connect(dns_dispentry_t *resp) { + dns_dispatch_t *disp = NULL; + uint_fast32_t state = DNS_DISPATCHSTATE_NONE; + + REQUIRE(VALID_RESPONSE(resp)); + + disp = resp->disp; + + /* This will be detached once we've connected. */ + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + + switch (disp->socktype) { + case isc_socktype_tcp: + /* + * Check whether the dispatch is already connecting + * or connected. + */ + atomic_compare_exchange_strong(&disp->state, + (uint_fast32_t *)&state, + DNS_DISPATCHSTATE_CONNECTING); + switch (state) { + case DNS_DISPATCHSTATE_NONE: + /* First connection, continue with connecting */ + LOCK(&disp->lock); + INSIST(ISC_LIST_EMPTY(disp->pending)); + ISC_LIST_APPEND(disp->pending, resp, plink); + UNLOCK(&disp->lock); + dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); + isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, + &disp->peer, tcp_connected, disp, + resp->timeout, 0); + break; + + case DNS_DISPATCHSTATE_CONNECTING: + /* Connection pending; add resp to the list */ + LOCK(&disp->lock); + ISC_LIST_APPEND(disp->pending, resp, plink); + UNLOCK(&disp->lock); + break; + + case DNS_DISPATCHSTATE_CONNECTED: + /* We are already connected; call the connected cb */ + if (resp->connected != NULL) { + resp->connected(ISC_R_SUCCESS, NULL, resp->arg); + } + dispentry_detach(&resp); + break; + + default: + INSIST(0); + ISC_UNREACHABLE(); + } + + break; + + case isc_socktype_udp: + isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer, + udp_connected, resp, resp->timeout, 0); + break; + + default: + return (ISC_R_NOTIMPLEMENTED); + } + + return (ISC_R_SUCCESS); +} + +static void +send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { + dns_dispentry_t *resp = (dns_dispentry_t *)cbarg; + + REQUIRE(VALID_RESPONSE(resp)); + + resp->sent(result, NULL, resp->arg); + + if (result != ISC_R_SUCCESS) { + isc_nm_cancelread(handle); + } + + dispentry_detach(&resp); +} + +void +dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout) { + dns_dispatch_t *disp = NULL; + + REQUIRE(VALID_RESPONSE(resp)); + + disp = resp->disp; + + REQUIRE(VALID_DISPATCH(disp)); + + dispatch_getnext(disp, resp, timeout); +} + +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { + isc_nmhandle_t *handle = NULL; + + REQUIRE(VALID_RESPONSE(resp)); + + UNUSED(dscp); + +#if 0 + /* XXX: no DSCP support */ + if (dscp == -1) { + sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = 0; + } else { + sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = dscp; + if (tcp) { + isc_socket_dscp(sock, dscp); + } + } +#endif + + if (resp->disp->socktype == isc_socktype_tcp) { + handle = resp->disp->handle; + } else { + handle = resp->handle; + } + + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + isc_nm_send(handle, r, send_done, resp); +} + +void +dns_dispatch_cancel(dns_dispentry_t *resp) { + REQUIRE(VALID_RESPONSE(resp)); + + resp->canceled = true; + + /* Connected UDP */ + if (resp->handle != NULL) { + isc_nm_cancelread(resp->handle); return; } - qid = DNS_QID(disp); - - /* - * Search for the first response handler without packets outstanding - * unless a specific handler is given. - */ - LOCK(&qid->lock); - for (resp = linear_first(qid); resp != NULL && resp->item_out; - /* Empty. */) - { - resp = linear_next(qid, resp); + /* TCP pending connection. */ + if (ISC_LINK_LINKED(resp, plink)) { + ISC_LIST_UNLINK(resp->disp->pending, resp, plink); + if (resp->connected != NULL) { + resp->connected(ISC_R_CANCELED, NULL, resp->arg); + dispentry_detach(&resp); + } + return; } /* - * No one to send the cancel event to, so nothing to do. + * Connected TCP, or unconnected UDP. + * + * If TCP, we don't want to cancel the dispatch + * unless this is the last resp waiting. */ - if (resp == NULL) { - goto unlock; - } - - /* - * Send the shutdown failsafe event to this resp. - */ - ev = disp->failsafe_ev; - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); - ev->result = disp->shutdown_why; - ev->buffer.base = NULL; - ev->buffer.length = 0; - disp->shutdown_out = 1; - request_log(disp, resp, LVL(10), "cancel: failsafe event %p -> task %p", - ev, resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); -unlock: - UNLOCK(&qid->lock); -} - -isc_socket_t * -dns_dispatch_getsocket(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - return (disp->socket); -} - -isc_socket_t * -dns_dispatch_getentrysocket(dns_dispentry_t *resp) { - REQUIRE(VALID_RESPONSE(resp)); - - if (resp->dispsocket != NULL) { - return (resp->dispsocket->socket); - } else { - return (NULL); + if (ISC_LINK_LINKED(resp, alink)) { + ISC_LIST_UNLINK(resp->disp->active, resp, alink); + if (ISC_LIST_EMPTY(resp->disp->active) && + resp->disp->handle != NULL) { + isc_nm_cancelread(resp->disp->handle); + } else if (resp->response != NULL) { + resp->response(ISC_R_CANCELED, NULL, resp->arg); + } } } @@ -3171,123 +1806,34 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(addrp != NULL); - if (disp->socktype == isc_sockettype_udp) { + if (disp->socktype == isc_socktype_udp) { *addrp = disp->local; return (ISC_R_SUCCESS); } return (ISC_R_NOTIMPLEMENTED); } -void -dns_dispatch_cancel(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); +isc_result_t +dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) { + REQUIRE(VALID_RESPONSE(resp)); + REQUIRE(addrp != NULL); - LOCK(&disp->lock); - - if (disp->shutting_down == 1) { - UNLOCK(&disp->lock); - return; + if (resp->disp->socktype == isc_socktype_tcp) { + *addrp = resp->disp->local; + return (ISC_R_SUCCESS); } - disp->shutdown_why = ISC_R_CANCELED; - disp->shutting_down = 1; - do_cancel(disp); - - UNLOCK(&disp->lock); - - return; -} - -unsigned int -dns_dispatch_getattributes(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - /* - * We don't bother locking disp here; it's the caller's responsibility - * to use only non volatile flags. - */ - return (disp->attributes); -} - -void -dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, - unsigned int mask) { - REQUIRE(VALID_DISPATCH(disp)); - /* Exclusive attribute can only be set on creation */ - REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0); - /* Also, a dispatch with randomport specified cannot start listening */ - REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 || - (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0); - - /* XXXMLG - * Should check for valid attributes here! - */ - - LOCK(&disp->lock); - - if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) { - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 && - (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) - { - disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN; - (void)startrecv(disp, NULL); - } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == - 0 && - (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) - { - disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; - if (disp->recv_pending != 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - } + if (resp->handle != NULL) { + *addrp = isc_nmhandle_localaddr(resp->handle); + return (ISC_R_SUCCESS); } - disp->attributes &= ~mask; - disp->attributes |= (attributes & mask); - UNLOCK(&disp->lock); -} - -void -dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { - void *buf; - isc_socketevent_t *sevent, *newsevent; - - REQUIRE(VALID_DISPATCH(disp)); - REQUIRE(event != NULL); - - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) { - return; - } - - sevent = (isc_socketevent_t *)event; - INSIST(sevent->n <= disp->mgr->buffersize); - - newsevent = (isc_socketevent_t *)isc_event_allocate( - disp->mgr->mctx, NULL, DNS_EVENT_IMPORTRECVDONE, udp_shrecv, - disp, sizeof(isc_socketevent_t)); - - buf = allocate_udp_buffer(disp); - if (buf == NULL) { - isc_event_free(ISC_EVENT_PTR(&newsevent)); - return; - } - memmove(buf, sevent->region.base, sevent->n); - newsevent->region.base = buf; - newsevent->region.length = disp->mgr->buffersize; - newsevent->n = sevent->n; - newsevent->result = sevent->result; - newsevent->address = sevent->address; - newsevent->timestamp = sevent->timestamp; - newsevent->pktinfo = sevent->pktinfo; - newsevent->attributes = sevent->attributes; - - isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent)); + return (ISC_R_NOTIMPLEMENTED); } dns_dispatch_t * dns_dispatchset_get(dns_dispatchset_t *dset) { - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; /* check that dispatch set is configured */ if (dset == NULL || dset->ndisp == 0) { @@ -3306,30 +1852,27 @@ dns_dispatchset_get(dns_dispatchset_t *dset) { } isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, +dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source, dns_dispatchset_t **dsetp, int n) { isc_result_t result; - dns_dispatchset_t *dset; - dns_dispatchmgr_t *mgr; + dns_dispatchset_t *dset = NULL; + dns_dispatchmgr_t *mgr = NULL; int i, j; REQUIRE(VALID_DISPATCH(source)); - REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0); + REQUIRE(source->socktype == isc_socktype_udp); REQUIRE(dsetp != NULL && *dsetp == NULL); mgr = source->mgr; dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t)); - memset(dset, 0, sizeof(*dset)); + *dset = (dns_dispatchset_t){ .ndisp = n }; isc_mutex_init(&dset->lock); dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n); isc_mem_attach(mctx, &dset->mctx); - dset->ndisp = n; - dset->cur = 0; dset->dispatches[0] = NULL; dns_dispatch_attach(source, &dset->dispatches[0]); @@ -3337,10 +1880,8 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, LOCK(&mgr->lock); for (i = 1; i < n; i++) { dset->dispatches[i] = NULL; - result = dispatch_createudp( - mgr, sockmgr, taskmgr, &source->local, - source->maxrequests, source->attributes, - &dset->dispatches[i], source->socket); + result = dispatch_createudp(mgr, &source->local, + &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { goto fail; } @@ -3367,22 +1908,9 @@ fail: return (result); } -void -dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { - int i; - - REQUIRE(dset != NULL); - - for (i = 0; i < dset->ndisp; i++) { - isc_socket_t *sock; - sock = dns_dispatch_getsocket(dset->dispatches[i]); - isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); - } -} - void dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { - dns_dispatchset_t *dset; + dns_dispatchset_t *dset = NULL; int i; REQUIRE(dsetp != NULL && *dsetp != NULL); @@ -3397,30 +1925,3 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { isc_mutex_destroy(&dset->lock); isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t)); } - -void -dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) { - REQUIRE(VALID_DISPATCH(disp)); - disp->dscp = dscp; -} - -isc_dscp_t -dns_dispatch_getdscp(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - return (disp->dscp); -} - -#if 0 -void -dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { - dns_dispatch_t *disp; - char foo[1024]; - - disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL) { - isc_sockaddr_format(&disp->local, foo, sizeof(foo)); - printf("\tdispatch %p, addr %s\n", disp, foo); - disp = ISC_LIST_NEXT(disp, link); - } -} -#endif /* if 0 */ diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index d8fcfd3c9e..9c3114dbd0 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -89,9 +89,8 @@ typedef struct dns_clientresevent { isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6); /*%< * Create a DNS client object with minimal internal resources, such as @@ -113,7 +112,7 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, * *\li 'taskmgr' is a valid task manager. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 8ed9601d16..93f676f5f9 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -9,8 +9,9 @@ * information regarding copyright ownership. */ -#ifndef DNS_DISPATCH_H -#define DNS_DISPATCH_H 1 +#pragma once + +#include /***** ***** Module Info @@ -19,12 +20,12 @@ /*! \file dns/dispatch.h * \brief * DNS Dispatch Management - * Shared UDP and single-use TCP dispatches for queries and responses. + * Shared UDP and single-use TCP dispatches for queries and responses. * * MP: * - *\li All locking is performed internally to each dispatch. - * Restrictions apply to dns_dispatch_removeresponse(). + *\li All locking is performed internally to each dispatch. + * Restrictions apply to dns_dispatch_removeresponse(). * * Reliability: * @@ -50,6 +51,7 @@ #include #include #include +#include #include #include @@ -57,33 +59,6 @@ ISC_LANG_BEGINDECLS -/*% - * This event is sent to a task when a response comes in. - * No part of this structure should ever be modified by the caller, - * other than parts of the buffer. The holy parts of the buffer are - * the base and size of the buffer. All other parts of the buffer may - * be used. On event delivery the used region contains the packet. - * - * "id" is the received message id, - * - * "addr" is the host that sent it to us, - * - * "buffer" holds state on the received data. - * - * The "free" routine for this event will clean up itself as well as - * any buffer space allocated from common pools. - */ - -struct dns_dispatchevent { - ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ - isc_result_t result; /*%< result code */ - int32_t id; /*%< message id */ - isc_sockaddr_t addr; /*%< address recv'd from */ - struct in6_pktinfo pktinfo; /*%< reply info for v6 */ - isc_buffer_t buffer; /*%< data buffer */ - uint32_t attributes; /*%< mirrored from socket.h */ -}; - /*% * This is a set of one or more dispatches which can be retrieved * round-robin fashion. @@ -96,65 +71,21 @@ struct dns_dispatchset { isc_mutex_t lock; }; -/*@{*/ -/*% - * Attributes for added dispatchers. - * - * Values with the mask 0xffff0000 are application defined. - * Values with the mask 0x0000ffff are library defined. - * - * Insane values (like setting both TCP and UDP) are not caught. Don't - * do that. - * - * _PRIVATE - * The dispatcher cannot be shared. - * - * _TCP, _UDP - * The dispatcher is a TCP or UDP socket. - * - * _IPV4, _IPV6 - * The dispatcher uses an IPv4 or IPv6 socket. - * - * _NOLISTEN - * The dispatcher should not listen on the socket. - * - * _MAKEQUERY - * The dispatcher can be used to issue queries to other servers, and - * accept replies from them. - * - * _RANDOMPORT - * Previously used to indicate that the port of a dispatch UDP must be - * chosen randomly. This behavior now always applies and the attribute - * is obsoleted. - * - * _EXCLUSIVE - * A separate socket will be used on-demand for each transaction. - */ -#define DNS_DISPATCHATTR_PRIVATE 0x00000001U -#define DNS_DISPATCHATTR_TCP 0x00000002U -#define DNS_DISPATCHATTR_UDP 0x00000004U -#define DNS_DISPATCHATTR_IPV4 0x00000008U -#define DNS_DISPATCHATTR_IPV6 0x00000010U -#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U -#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U -#define DNS_DISPATCHATTR_CONNECTED 0x00000080U -#define DNS_DISPATCHATTR_FIXEDID 0x00000100U -#define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U -#define DNS_DISPATCHATTR_CANREUSE 0x00000400U -/*@}*/ - /* */ #define DNS_DISPATCHOPT_FIXEDID 0x00000001U isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, dns_dispatchmgr_t **mgrp); /*%< - * Creates a new dispatchmgr object. + * Creates a new dispatchmgr object, and sets the available ports + * to the default range (1024-65535). * * Requires: - *\li "mctx" be a valid memory context. + *\li 'mctx' be a valid memory context. * + *\li 'nm' is a valid network manager. + *\li mgrp != NULL && *mgrp == NULL * * Returns: @@ -164,10 +95,21 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); */ void -dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp); +dns_dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp); /*%< - * Destroys the dispatchmgr when it becomes empty. This could be - * immediately. + * Attach to a dispatch manger. + * + * Requires: + *\li is valid. + * + *\li mgrp != NULL && *mgrp == NULL + */ + +void +dns_dispatchmgr_detach(dns_dispatchmgr_t **mgrp); +/*%< + * Detach from the dispatch manager, and destroy it if no references + * remain. * * Requires: *\li mgrp != NULL && *mgrp is a valid dispatchmgr. @@ -191,7 +133,7 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr); * without incrementing its reference count. * * Requires: - *\li mgr is a valid dispatchmgr + *\li mgr is a valid dispatchmgr * Returns: *\li A pointer to the current blackhole list, or NULL. */ @@ -224,31 +166,16 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); */ isc_result_t -dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int buffersize, unsigned int maxbuffers, - unsigned int maxrequests, unsigned int buckets, - unsigned int increment, unsigned int attributes, - dns_dispatch_t **dispp); +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + dns_dispatch_t **dispp); /*%< - * Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find, - * otherwise create a new UDP dispatch. + * Create a new UDP dispatch. * * Requires: *\li All pointer parameters be valid for their respective types. * *\li dispp != NULL && *disp == NULL * - *\li 512 <= buffersize <= 64k - * - *\li maxbuffers > 0 - * - *\li buckets < 2097169 - * - *\li increment > buckets - * - *\li (attributes & DNS_DISPATCHATTR_TCP) == 0 - * * Returns: *\li ISC_R_SUCCESS -- success. * @@ -256,48 +183,18 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - const isc_sockaddr_t *destaddr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp); +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + const isc_sockaddr_t *destaddr, isc_dscp_t dscp, + dns_dispatch_t **dispp); /*%< * Create a new dns_dispatch and attach it to the provided isc_socket_t. * - * For all dispatches, "buffersize" is the maximum packet size we will - * accept. - * - * "maxbuffers" and "maxrequests" control the number of buffers in the - * overall system and the number of buffers which can be allocated to - * requests. - * - * "buckets" is the number of buckets to use, and should be prime. - * - * "increment" is used in a collision avoidance function, and needs to be - * a prime > buckets, and not 2. - * * Requires: * *\li mgr is a valid dispatch manager. * *\li sock is a valid. * - *\li task is a valid task that can be used internally to this dispatcher. - * - * \li 512 <= buffersize <= 64k - * - *\li maxbuffers > 0. - * - *\li maxrequests <= maxbuffers. - * - *\li buckets < 2097169 (the next prime after 65536 * 32) - * - *\li increment > buckets (and prime). - * - *\li attributes includes #DNS_DISPATCHATTR_TCP and does not include - * #DNS_DISPATCHATTR_UDP. - * * Returns: *\li ISC_R_SUCCESS -- success. * @@ -324,13 +221,44 @@ dns_dispatch_detach(dns_dispatch_t **dispp); *\li dispp != NULL and *dispp be a valid dispatch. */ -void -dns_dispatch_starttcp(dns_dispatch_t *disp); +isc_result_t +dns_dispatch_connect(dns_dispentry_t *resp); /*%< - * Start processing of a TCP dispatch once the socket connects. + * Connect to the remote server configured in 'resp' and run the + * connect callback that was set up via dns_dispatch_addresponse(). * * Requires: - *\li 'disp' is valid. + *\li 'resp' is valid. + */ + +void +dns_dispatch_cancel(dns_dispentry_t *resp); +/*%< + * Cancel pending connects in 'resp', by setting a flag so that + * a read is not started when the connect handler runs. + * + * Requires: + *\li 'resp' is valid. + */ + +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp); +/*%< + * Send region 'r' using the socket in 'resp', then run the specified + * callback. + * + * Requires: + *\li 'resp' is valid. + */ + +void +dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout); +/*%< + * Reset the read timeout in the socket associated with 'resp' and + * continue reading. + * + * Requires: + *\li 'resp' is valid. */ isc_result_t @@ -342,34 +270,38 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, * if connected == NULL). */ +typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region, + void *cbarg); + isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, uint16_t *idp, - dns_dispentry_t **resp, isc_socketmgr_t *sockmgr); + unsigned int timeout, const isc_sockaddr_t *dest, + dispatch_cb_t connected, dispatch_cb_t sent, + dispatch_cb_t response, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp); /*%< * Add a response entry for this dispatch. * * "*idp" is filled in with the assigned message ID, and *resp is filled in - * to contain the magic token used to request event flow stop. + * with the dispatch entry object. * - * Arranges for the given task to get a callback for response packets. When - * the event is delivered, it must be returned using dns_dispatch_freeevent() - * or through dns_dispatch_removeresponse() for another to be delivered. + * The 'connected' and 'sent' callbacks are run to inform the caller when + * the connect and send functions are complete. The 'timedout' callback + * is run to inform the caller that a read has timed out; it may optionally + * reset the read timer. The 'response' callback is run for recv results + * (response packets, timeouts, or cancellations). + * + * All the callback functions are sent 'arg' as a parameter. * * Requires: *\li "idp" be non-NULL. * - *\li "task" "action" and "arg" be set as appropriate. + *\li "response" and "arg" be set as appropriate. * *\li "dest" be non-NULL and valid. * *\li "resp" be non-NULL and *resp be NULL * - *\li "sockmgr" be NULL or a valid socket manager. If 'disp' has - * the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL, - * which also means dns_dispatch_addresponse() cannot be used. - * * Ensures: * *\li <id, dest> is a unique tuple. That means incoming messages @@ -384,34 +316,13 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, */ void -dns_dispatch_removeresponse(dns_dispentry_t ** resp, - dns_dispatchevent_t **sockevent); +dns_dispatch_removeresponse(dns_dispentry_t **resp); /*%< * Stops the flow of responses for the provided id and destination. - * If "sockevent" is non-NULL, the dispatch event and associated buffer is - * also returned to the system. * * Requires: *\li "resp" != NULL and "*resp" contain a value previously allocated * by dns_dispatch_addresponse(); - * - *\li May only be called from within the task given as the 'task' - * argument to dns_dispatch_addresponse() when allocating '*resp'. - */ - -isc_socket_t * -dns_dispatch_getentrysocket(dns_dispentry_t *resp); - -isc_socket_t * -dns_dispatch_getsocket(dns_dispatch_t *disp); -/*%< - * Return the socket associated with this dispatcher. - * - * Requires: - *\li disp is valid. - * - * Returns: - *\li The socket the dispatcher is using. */ isc_result_t @@ -422,70 +333,25 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); * * Requires: *\li disp is valid. - *\li addrp to be non null. + *\li addrp to be non NULL. * * Returns: *\li ISC_R_SUCCESS *\li ISC_R_NOTIMPLEMENTED */ -void -dns_dispatch_cancel(dns_dispatch_t *disp); +isc_result_t +dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp); /*%< - * cancel outstanding clients + * Return the local address for this dispatch entry. * * Requires: - *\li disp is valid. - */ - -unsigned int -dns_dispatch_getattributes(dns_dispatch_t *disp); -/*%< - * Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch. Only the - * non-changeable attributes are expected to be referenced by the caller. + *\li resp is valid. + *\li addrp to be non NULL. * - * Requires: - *\li disp is valid. - */ - -void -dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, - unsigned int mask); -/*%< - * Set the bits described by "mask" to the corresponding values in - * "attributes". - * - * That is: - * - * \code - * new = (old & ~mask) | (attributes & mask) - * \endcode - * - * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes. - * When the flag becomes off, the dispatch will start receiving on the - * corresponding socket. When the flag becomes on, receive events on the - * corresponding socket will be canceled. - * - * Requires: - *\li disp is valid. - * - *\li attributes are reasonable for the dispatch. That is, setting the UDP - * attribute on a TCP socket isn't reasonable. - */ - -void -dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event); -/*%< - * Inform the dispatcher of a socket receive. This is used for sockets - * shared between dispatchers and clients. If the dispatcher fails to copy - * or send the event, nothing happens. - * - * If the attribute DNS_DISPATCHATTR_NOLISTEN is not set, then - * the dispatch is already handling a recv; return immediately. - * - * Requires: - *\li disp is valid, and the attribute DNS_DISPATCHATTR_NOLISTEN is set. - * event != NULL + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTIMPLEMENTED */ dns_dispatch_t * @@ -495,12 +361,11 @@ dns_dispatchset_get(dns_dispatchset_t *dset); * the round-robin counter. * * Requires: - *\li dset != NULL + *\li dset != NULL */ isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, +dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source, dns_dispatchset_t **dsetp, int n); /*%< * Given a valid dispatch 'source', create a dispatch set containing @@ -508,14 +373,8 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, * source. * * Requires: - *\li source is a valid UDP dispatcher - *\li dsetp != NULL, *dsetp == NULL - */ - -void -dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task); -/*%< - * Cancel socket operations for the dispatches in 'dset'. + *\li source is a valid UDP dispatcher + *\li dsetp != NULL, *dsetp == NULL */ void @@ -525,32 +384,16 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp); * memory, and set *dsetp to NULL. * * Requires: - *\li dset is valid - */ - -void -dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp); -isc_dscp_t -dns_dispatch_getdscp(dns_dispatch_t *disp); -/*%< - * Set/get the DSCP value to be used when sending responses to clients, - * as defined in the "listen-on" or "listen-on-v6" statements. - * - * Requires: - *\li disp is valid. + *\li dset is valid */ isc_result_t -dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent); +dns_dispatch_getnext(dns_dispentry_t *resp); /*%< - * Free the sockevent and trigger the sending of the next item off the - * dispatch queue if present. + * Trigger the sending of the next item off the dispatch queue if present. * * Requires: *\li resp is valid - *\li *sockevent to be valid */ ISC_LANG_ENDDECLS - -#endif /* DNS_DISPATCH_H */ diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index 7d93637268..32af3d954c 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -54,7 +54,7 @@ #define DNS_EVENT_DISPATCHCONTROL (ISC_EVENTCLASS_DNS + 32) #define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33) #define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34) -#define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35) +/* #define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35) */ #define DNS_EVENT_FREESTORAGE (ISC_EVENTCLASS_DNS + 36) #define DNS_EVENT_VIEWACACHESHUTDOWN (ISC_EVENTCLASS_DNS + 37) #define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38) diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 6ec7395ae2..9554603b50 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -43,7 +43,6 @@ #define DNS_REQUESTOPT_TCP 0x00000001U #define DNS_REQUESTOPT_CASE 0x00000002U #define DNS_REQUESTOPT_FIXEDID 0x00000004U -#define DNS_REQUESTOPT_SHARE 0x00000008U typedef struct dns_requestevent { ISC_EVENT_COMMON(struct dns_requestevent); @@ -54,8 +53,7 @@ typedef struct dns_requestevent { ISC_LANG_BEGINDECLS isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp); @@ -66,8 +64,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, * *\li 'mctx' is a valid memory context. * - *\li 'timermgr' is a valid timer manager. - * *\li 'socketmgr' is a valid socket manager. * *\li 'taskmgr' is a valid task manager. diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 07b94fdcd1..350bdf0ac2 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -74,7 +74,8 @@ typedef struct dns_fetchevent { dns_dbnode_t * node; dns_rdataset_t * rdataset; dns_rdataset_t * sigrdataset; - dns_fixedname_t foundname; + dns_fixedname_t fname; + dns_name_t * foundname; const isc_sockaddr_t *client; dns_messageid_t id; isc_result_t vresult; @@ -163,11 +164,10 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t; isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp); + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp); /*%< * Create a resolver. @@ -185,7 +185,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, * *\li 'ntasks' > 0. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * @@ -413,9 +413,6 @@ dns_resolver_dispatchv4(dns_resolver_t *resolver); dns_dispatch_t * dns_resolver_dispatchv6(dns_resolver_t *resolver); -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver); - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver); diff --git a/lib/dns/include/dns/tcpmsg.h b/lib/dns/include/dns/tcpmsg.h deleted file mode 100644 index 375df60c7a..0000000000 --- a/lib/dns/include/dns/tcpmsg.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -#ifndef DNS_TCPMSG_H -#define DNS_TCPMSG_H 1 - -/*! \file dns/tcpmsg.h */ - -#include - -#include -#include -#include - -typedef struct dns_tcpmsg { - /* private (don't touch!) */ - unsigned int magic; - uint16_t size; - isc_buffer_t buffer; - unsigned int maxsize; - isc_mem_t * mctx; - isc_socket_t * sock; - isc_task_t * task; - isc_taskaction_t action; - void * arg; - isc_event_t event; - /* public (read-only) */ - isc_result_t result; - isc_sockaddr_t address; -} dns_tcpmsg_t; - -ISC_LANG_BEGINDECLS - -void -dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg); -/*%< - * Associate a tcp message state with a given memory context and - * TCP socket. - * - * Requires: - * - *\li "mctx" and "sock" be non-NULL and valid types. - * - *\li "sock" be a read/write TCP socket. - * - *\li "tcpmsg" be non-NULL and an uninitialized or invalidated structure. - * - * Ensures: - * - *\li "tcpmsg" is a valid structure. - */ - -void -dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize); -/*%< - * Set the maximum packet size to "maxsize" - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li 512 <= "maxsize" <= 65536 - */ - -isc_result_t -dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task, - isc_taskaction_t action, void *arg); -/*%< - * Schedule an event to be delivered when a DNS message is readable, or - * when an error occurs on the socket. - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li "task", "taskaction", and "arg" be valid. - * - * Returns: - * - *\li ISC_R_SUCCESS -- no error - *\li Anything that the isc_socket_recv() call can return. XXXMLG - * - * Notes: - * - *\li The event delivered is a fully generic event. It will contain no - * actual data. The sender will be a pointer to the dns_tcpmsg_t. - * The result code inside that structure should be checked to see - * what the final result was. - */ - -void -dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg); -/*%< - * Cancel a readmessage() call. The event will still be posted with a - * CANCELED result code. - * - * Requires: - * - *\li "tcpmsg" be valid. - */ - -void -dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer); -/*%< - * If a dns buffer is to be kept between calls, this function marks the - * internal state-machine buffer as invalid, and copies all the contents - * of the state into "buffer". - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li "buffer" be non-NULL. - */ - -void -dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg); -/*%< - * Clean up all allocated state, and invalidate the structure. - * - * Requires: - * - *\li "tcpmsg" be valid. - * - * Ensures: - * - *\li "tcpmsg" is invalidated and disassociated with all memory contexts, - * sockets, etc. - */ - -ISC_LANG_ENDDECLS - -#endif /* DNS_TCPMSG_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 6192731846..59d2fb28bd 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -65,7 +65,6 @@ typedef struct dns_dyndbctx dns_dyndbctx_t; typedef struct dns_sdlzimplementation dns_sdlzimplementation_t; typedef struct dns_decompress dns_decompress_t; typedef struct dns_dispatch dns_dispatch_t; -typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_dispatchlist dns_dispatchlist_t; typedef struct dns_dispatchset dns_dispatchset_t; typedef struct dns_dispatchmgr dns_dispatchmgr_t; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index bfe9abd763..5e777229e8 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -393,9 +393,9 @@ dns_view_createzonetable(dns_view_t *view); isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6); /*%< * Create a resolver and address database for the view. @@ -407,7 +407,7 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, *\li 'view' does not have a resolver already. * *\li The requirements of dns_resolver_create() apply to 'taskmgr', - * 'ntasks', 'socketmgr', 'timermgr', 'options', 'dispatchv4', and + * 'ntasks', 'nm', 'timermgr', 'options', 'dispatchv4', and * 'dispatchv6'. * * Returns: diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 354ee64659..10f977cc5a 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -1780,8 +1780,8 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_result_t dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, - isc_nm_t *netmgr, dns_zonemgr_t **zmgrp); + isc_timermgr_t *timermgr, isc_nm_t *netmgr, + dns_zonemgr_t **zmgrp); /*%< * Create a zone manager. Note: the zone manager will not be able to * manage any zones until dns_zonemgr_setsize() has been run. diff --git a/lib/dns/lookup.c b/lib/dns/lookup.c index d62aaee2f4..6d9dadd165 100644 --- a/lib/dns/lookup.c +++ b/lib/dns/lookup.c @@ -140,10 +140,10 @@ view_find(dns_lookup_t *lookup, dns_name_t *foundname) { static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { - isc_result_t result; + isc_result_t result = ISC_R_SUCCESS; bool want_restart; bool send_event; - dns_name_t *name, *fname, *prefix; + dns_name_t *name = NULL, *fname = NULL, *prefix = NULL; dns_fixedname_t foundname, fixed; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; @@ -156,7 +156,6 @@ lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { LOCK(&lookup->lock); - result = ISC_R_SUCCESS; name = dns_fixedname_name(&lookup->name); do { @@ -202,12 +201,10 @@ lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { } } else if (event != NULL) { result = event->result; - fname = dns_fixedname_name(&event->foundname); + fname = event->foundname; dns_resolver_destroyfetch(&lookup->fetch); INSIST(event->rdataset == &lookup->rdataset); INSIST(event->sigrdataset == &lookup->sigrdataset); - } else { - fname = NULL; /* Silence compiler warning. */ } /* diff --git a/lib/dns/request.c b/lib/dns/request.c index 1311de4027..9214225e04 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -16,8 +16,8 @@ #include #include +#include #include -#include #include #include @@ -44,19 +44,17 @@ typedef ISC_LIST(dns_request_t) dns_requestlist_t; struct dns_requestmgr { unsigned int magic; + isc_refcount_t references; + isc_mutex_t lock; isc_mem_t *mctx; /* locked */ - int32_t eref; - int32_t iref; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; isc_taskmgr_t *taskmgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; dns_dispatch_t *dispatchv6; - bool exiting; + atomic_bool exiting; isc_eventlist_t whenshutdown; unsigned int hash; isc_mutex_t locks[DNS_REQUEST_NLOCKS]; @@ -65,6 +63,8 @@ struct dns_requestmgr { struct dns_request { unsigned int magic; + isc_refcount_t references; + unsigned int hash; isc_mem_t *mctx; int32_t flags; @@ -74,28 +74,24 @@ struct dns_request { dns_requestevent_t *event; dns_dispatch_t *dispatch; dns_dispentry_t *dispentry; - isc_timer_t *timer; dns_requestmgr_t *requestmgr; isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; - isc_event_t ctlevent; - bool canceling; /* ctlevent outstanding */ + isc_socketevent_t sendevent; isc_sockaddr_t destaddr; + unsigned int timeout; unsigned int udpcount; isc_dscp_t dscp; }; #define DNS_REQUEST_F_CONNECTING 0x0001 #define DNS_REQUEST_F_SENDING 0x0002 -#define DNS_REQUEST_F_CANCELED \ - 0x0004 /*%< ctlevent received, or otherwise \ - * synchronously canceled */ -#define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */ -#define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */ +#define DNS_REQUEST_F_CANCELED 0x0004 +#define DNS_REQUEST_F_TCP 0x0010 + #define DNS_REQUEST_CANCELED(r) (((r)->flags & DNS_REQUEST_F_CANCELED) != 0) #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0) #define DNS_REQUEST_SENDING(r) (((r)->flags & DNS_REQUEST_F_SENDING) != 0) -#define DNS_REQUEST_TIMEDOUT(r) (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0) /*** *** Forward @@ -103,8 +99,6 @@ struct dns_request { static void mgr_destroy(dns_requestmgr_t *requestmgr); -static void -mgr_shutdown(dns_requestmgr_t *requestmgr); static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr); static void @@ -114,84 +108,67 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, isc_mem_t *mctx); static void -req_senddone(isc_task_t *task, isc_event_t *event); +req_response(isc_result_t result, isc_region_t *region, void *arg); static void -req_response(isc_task_t *task, isc_event_t *event); -static void -req_timeout(isc_task_t *task, isc_event_t *event); -static isc_socket_t * -req_getsocket(dns_request_t *request); -static void -req_connected(isc_task_t *task, isc_event_t *event); +req_senddone(isc_result_t eresult, isc_region_t *region, void *arg); static void req_sendevent(dns_request_t *request, isc_result_t result); static void -req_cancel(dns_request_t *request); +req_connected(isc_result_t eresult, isc_region_t *region, void *arg); +static void +req_attach(dns_request_t *source, dns_request_t **targetp); +static void +req_detach(dns_request_t **requestp); static void req_destroy(dns_request_t *request); static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); -static void -do_cancel(isc_task_t *task, isc_event_t *event); +void +request_cancel(dns_request_t *request); /*** *** Public ***/ isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp) { dns_requestmgr_t *requestmgr; int i; - unsigned int dispattr; req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create"); REQUIRE(requestmgrp != NULL && *requestmgrp == NULL); - REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(dispatchmgr != NULL); - if (dispatchv4 != NULL) { - dispattr = dns_dispatch_getattributes(dispatchv4); - REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0); - } - if (dispatchv6 != NULL) { - dispattr = dns_dispatch_getattributes(dispatchv6); - REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0); - } - requestmgr = isc_mem_get(mctx, sizeof(*requestmgr)); + *requestmgr = (dns_requestmgr_t){ 0 }; + isc_taskmgr_attach(taskmgr, &requestmgr->taskmgr); + dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr); isc_mutex_init(&requestmgr->lock); for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { isc_mutex_init(&requestmgr->locks[i]); } - requestmgr->timermgr = timermgr; - requestmgr->socketmgr = socketmgr; - requestmgr->taskmgr = taskmgr; - requestmgr->dispatchmgr = dispatchmgr; - requestmgr->dispatchv4 = NULL; if (dispatchv4 != NULL) { dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4); } - requestmgr->dispatchv6 = NULL; if (dispatchv6 != NULL) { dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6); } - requestmgr->mctx = NULL; isc_mem_attach(mctx, &requestmgr->mctx); - requestmgr->eref = 1; /* implicit attach */ - requestmgr->iref = 0; + + isc_refcount_init(&requestmgr->references, 1); + ISC_LIST_INIT(requestmgr->whenshutdown); ISC_LIST_INIT(requestmgr->requests); - requestmgr->exiting = false; - requestmgr->hash = 0; + + atomic_init(&requestmgr->exiting, false); + requestmgr->magic = REQUESTMGR_MAGIC; req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr); @@ -216,7 +193,7 @@ dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, LOCK(&requestmgr->lock); - if (requestmgr->exiting) { + if (atomic_load_acquire(&requestmgr->exiting)) { /* * We're already shutdown. Send the event. */ @@ -233,129 +210,73 @@ dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, void dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) { + dns_request_t *request; + REQUIRE(VALID_REQUESTMGR(requestmgr)); req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr); - LOCK(&requestmgr->lock); - mgr_shutdown(requestmgr); - UNLOCK(&requestmgr->lock); -} - -static void -mgr_shutdown(dns_requestmgr_t *requestmgr) { - dns_request_t *request; - - /* - * Caller holds lock. - */ - if (!requestmgr->exiting) { - requestmgr->exiting = true; - for (request = ISC_LIST_HEAD(requestmgr->requests); - request != NULL; request = ISC_LIST_NEXT(request, link)) - { - dns_request_cancel(request); - } - if (requestmgr->iref == 0) { - INSIST(ISC_LIST_EMPTY(requestmgr->requests)); - send_shutdown_events(requestmgr); - } + if (!atomic_compare_exchange_strong(&requestmgr->exiting, + &(bool){ false }, true)) + { + return; } -} - -static void -requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { - /* - * Locked by caller. - */ - - REQUIRE(VALID_REQUESTMGR(source)); - REQUIRE(targetp != NULL && *targetp == NULL); - - REQUIRE(!source->exiting); - - source->iref++; - *targetp = source; - - req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d", - source, source->eref, source->iref); -} - -static void -requestmgr_detach(dns_requestmgr_t **requestmgrp) { - dns_requestmgr_t *requestmgr; - bool need_destroy = false; - - REQUIRE(requestmgrp != NULL); - requestmgr = *requestmgrp; - *requestmgrp = NULL; - REQUIRE(VALID_REQUESTMGR(requestmgr)); LOCK(&requestmgr->lock); - INSIST(requestmgr->iref > 0); - requestmgr->iref--; + for (request = ISC_LIST_HEAD(requestmgr->requests); request != NULL; + request = ISC_LIST_NEXT(request, link)) + { + dns_request_cancel(request); + } - req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d", - requestmgr, requestmgr->eref, requestmgr->iref); - - if (requestmgr->iref == 0 && requestmgr->exiting) { - INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL); + if (ISC_LIST_EMPTY(requestmgr->requests)) { send_shutdown_events(requestmgr); - if (requestmgr->eref == 0) { - need_destroy = true; - } } - UNLOCK(&requestmgr->lock); - if (need_destroy) { - mgr_destroy(requestmgr); - } + UNLOCK(&requestmgr->lock); } void dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { + uint_fast32_t ref; + REQUIRE(VALID_REQUESTMGR(source)); REQUIRE(targetp != NULL && *targetp == NULL); - REQUIRE(!source->exiting); - LOCK(&source->lock); - source->eref++; + REQUIRE(!atomic_load_acquire(&source->exiting)); + + ref = isc_refcount_increment(&source->references); + + req_log(ISC_LOG_DEBUG(3), + "dns_requestmgr_attach: %p: references = %" PRIuFAST32, source, + ref + 1); + *targetp = source; - UNLOCK(&source->lock); - - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d", - source, source->eref, source->iref); } void dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) { - dns_requestmgr_t *requestmgr; - bool need_destroy = false; + dns_requestmgr_t *requestmgr = NULL; + uint_fast32_t ref; + + REQUIRE(requestmgrp != NULL && VALID_REQUESTMGR(*requestmgrp)); - REQUIRE(requestmgrp != NULL); requestmgr = *requestmgrp; *requestmgrp = NULL; - REQUIRE(VALID_REQUESTMGR(requestmgr)); - LOCK(&requestmgr->lock); - INSIST(requestmgr->eref > 0); - requestmgr->eref--; + ref = isc_refcount_decrement(&requestmgr->references); - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d", - requestmgr, requestmgr->eref, requestmgr->iref); + req_log(ISC_LOG_DEBUG(3), + "dns_requestmgr_detach: %p: references = %" PRIuFAST32, + requestmgr, ref - 1); - if (requestmgr->eref == 0 && requestmgr->iref == 0) { - INSIST(requestmgr->exiting && - ISC_LIST_HEAD(requestmgr->requests) == NULL); - need_destroy = true; - } - UNLOCK(&requestmgr->lock); - - if (need_destroy) { + if (ref == 1) { + INSIST(ISC_LIST_EMPTY(requestmgr->requests)); mgr_destroy(requestmgr); } } +/* FIXME */ static void send_shutdown_events(dns_requestmgr_t *requestmgr) { isc_event_t *event, *next_event; @@ -383,8 +304,7 @@ mgr_destroy(dns_requestmgr_t *requestmgr) { req_log(ISC_LOG_DEBUG(3), "mgr_destroy"); - REQUIRE(requestmgr->eref == 0); - REQUIRE(requestmgr->iref == 0); + isc_refcount_destroy(&requestmgr->references); isc_mutex_destroy(&requestmgr->lock); for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { @@ -396,6 +316,12 @@ mgr_destroy(dns_requestmgr_t *requestmgr) { if (requestmgr->dispatchv6 != NULL) { dns_dispatch_detach(&requestmgr->dispatchv6); } + if (requestmgr->dispatchmgr != NULL) { + dns_dispatchmgr_detach(&requestmgr->dispatchmgr); + } + if (requestmgr->taskmgr != NULL) { + isc_taskmgr_detach(&requestmgr->taskmgr); + } requestmgr->magic = 0; isc_mem_putanddetach(&requestmgr->mctx, requestmgr, sizeof(*requestmgr)); @@ -411,74 +337,29 @@ mgr_gethash(dns_requestmgr_t *requestmgr) { return (requestmgr->hash % DNS_REQUEST_NLOCKS); } -static inline isc_result_t -req_send(dns_request_t *request, isc_task_t *task, - const isc_sockaddr_t *address) { +static inline void +req_send(dns_request_t *request) { isc_region_t r; - isc_socket_t *sock; - isc_socketevent_t *sendevent; - isc_result_t result; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); REQUIRE(VALID_REQUEST(request)); - sock = req_getsocket(request); + isc_buffer_usedregion(request->query, &r); - /* - * We could connect the socket when we are using an exclusive dispatch - * as we do in resolver.c, but we prefer implementation simplicity - * at this moment. - */ - sendevent = isc_socket_socketevent(request->mctx, sock, - ISC_SOCKEVENT_SENDDONE, req_senddone, - request); - if (sendevent == NULL) { - return (ISC_R_NOMEMORY); - } - if (request->dscp == -1) { - sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; - sendevent->dscp = 0; - } else { - sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; - sendevent->dscp = request->dscp; - } request->flags |= DNS_REQUEST_F_SENDING; - result = isc_socket_sendto2(sock, &r, task, address, NULL, sendevent, - 0); - INSIST(result == ISC_R_SUCCESS); - return (result); + dns_dispatch_send(request->dispentry, &r, request->dscp); } static isc_result_t new_request(isc_mem_t *mctx, dns_request_t **requestp) { - dns_request_t *request; + dns_request_t *request = NULL; request = isc_mem_get(mctx, sizeof(*request)); - - /* - * Zero structure. - */ - request->magic = 0; - request->mctx = NULL; - request->flags = 0; + *request = (dns_request_t){ .dscp = -1 }; ISC_LINK_INIT(request, link); - request->query = NULL; - request->answer = NULL; - request->event = NULL; - request->dispatch = NULL; - request->dispentry = NULL; - request->timer = NULL; - request->requestmgr = NULL; - request->tsig = NULL; - request->tsigkey = NULL; - request->dscp = -1; - ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL, - DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, - NULL); - request->canceling = false; - request->udpcount = 0; + isc_refcount_init(&request->references, 1); isc_mem_attach(mctx, &request->mctx); request->magic = REQUEST_MAGIC; @@ -490,39 +371,34 @@ static bool isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) { dns_acl_t *blackhole; isc_netaddr_t netaddr; - int match; - bool drop = false; char netaddrstr[ISC_NETADDR_FORMATSIZE]; + int match; + isc_result_t result; blackhole = dns_dispatchmgr_getblackhole(dispatchmgr); - if (blackhole != NULL) { - isc_netaddr_fromsockaddr(&netaddr, destaddr); - if (dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, - NULL) == ISC_R_SUCCESS && - match > 0) - { - drop = true; - } + if (blackhole == NULL) { + return (false); } - if (drop) { - isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); - req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr); + + isc_netaddr_fromsockaddr(&netaddr, destaddr); + result = dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, NULL); + if (result != ISC_R_SUCCESS || match == 0) { + return (false); } - return (drop); + + isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); + req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr); + + return (true); } static isc_result_t -create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, - const isc_sockaddr_t *srcaddr, - const isc_sockaddr_t *destaddr, isc_dscp_t dscp, - bool *connected, dns_dispatch_t **dispatchp) { +tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, + const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, + isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { isc_result_t result; - isc_socket_t *sock = NULL; - isc_sockaddr_t src; - unsigned int attrs; - isc_sockaddr_t bind_any; - if (!newtcp && share) { + if (!newtcp) { result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, srcaddr, connected, dispatchp); if (result == ISC_R_SUCCESS) { @@ -535,65 +411,17 @@ create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, *connected ? "existing" : "pending", peer); return (result); } - } else if (!newtcp) { - result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, - srcaddr, NULL, dispatchp); - if (result == ISC_R_SUCCESS) { - char peer[ISC_SOCKADDR_FORMATSIZE]; - - *connected = true; - isc_sockaddr_format(destaddr, peer, sizeof(peer)); - req_log(ISC_LOG_DEBUG(1), - "attached to existing TCP " - "connection to %s", - peer); - return (result); - } } - result = isc_socket_create(requestmgr->socketmgr, - isc_sockaddr_pf(destaddr), - isc_sockettype_tcp, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } -#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT - if (srcaddr == NULL) { - isc_sockaddr_anyofpf(&bind_any, isc_sockaddr_pf(destaddr)); - result = isc_socket_bind(sock, &bind_any, 0); - } else { - src = *srcaddr; - isc_sockaddr_setport(&src, 0); - result = isc_socket_bind(sock, &src, 0); - } - if (result != ISC_R_SUCCESS) { - goto cleanup; - } -#endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */ - - attrs = 0; - attrs |= DNS_DISPATCHATTR_TCP; - if (isc_sockaddr_pf(destaddr) == AF_INET) { - attrs |= DNS_DISPATCHATTR_IPV4; - } else { - attrs |= DNS_DISPATCHATTR_IPV6; - } - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - - isc_socket_dscp(sock, dscp); - result = dns_dispatch_createtcp( - requestmgr->dispatchmgr, sock, requestmgr->taskmgr, srcaddr, - destaddr, 4096, 32768, 32768, 16411, 16433, attrs, dispatchp); -cleanup: - isc_socket_detach(&sock); + result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr, + destaddr, dscp, dispatchp); return (result); } static isc_result_t -find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, - const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { +udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, + const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { dns_dispatch_t *disp = NULL; - unsigned int attrs; if (srcaddr == NULL) { switch (isc_sockaddr_pf(destaddr)) { @@ -614,58 +442,22 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, dns_dispatch_attach(disp, dispatchp); return (ISC_R_SUCCESS); } - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; - switch (isc_sockaddr_pf(srcaddr)) { - case PF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case PF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - - default: - return (ISC_R_NOTIMPLEMENTED); - } - return (dns_dispatch_getudp(requestmgr->dispatchmgr, - requestmgr->socketmgr, requestmgr->taskmgr, - srcaddr, 4096, 32768, 32768, 16411, 16433, - attrs, dispatchp)); + return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr, + dispatchp)); } static isc_result_t -get_dispatch(bool tcp, bool newtcp, bool share, dns_requestmgr_t *requestmgr, +get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { isc_result_t result; if (tcp) { - result = create_tcp_dispatch(newtcp, share, requestmgr, srcaddr, - destaddr, dscp, connected, - dispatchp); + result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr, + dscp, connected, dispatchp); } else { - result = find_udp_dispatch(requestmgr, srcaddr, destaddr, - dispatchp); - } - return (result); -} - -static isc_result_t -set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) { - isc_time_t expires; - isc_interval_t interval; - isc_result_t result; - isc_timertype_t timertype; - - isc_interval_set(&interval, timeout, 0); - result = isc_time_nowplusinterval(&expires, &interval); - isc_interval_set(&interval, udpresend, 0); - - timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once; - if (result == ISC_R_SUCCESS) { - result = isc_timer_reset(timer, timertype, &expires, &interval, - false); + result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp); } return (result); } @@ -680,13 +472,12 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; - isc_socket_t *sock = NULL; + dns_request_t *rclone = NULL; isc_result_t result; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; dns_messageid_t id; bool tcp = false; bool newtcp = false; - bool share = false; isc_region_t r; bool connected = false; unsigned int dispopt = 0; @@ -706,35 +497,22 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, req_log(ISC_LOG_DEBUG(3), "dns_request_createraw"); + if (atomic_load_acquire(&requestmgr->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + if (isblackholed(requestmgr->dispatchmgr, destaddr)) { return (DNS_R_BLACKHOLED); } - request = NULL; result = new_request(mctx, &request); if (result != ISC_R_SUCCESS) { return (result); } - if (udptimeout == 0 && udpretries != 0) { - udptimeout = timeout / (udpretries + 1); - if (udptimeout == 0) { - udptimeout = 1; - } - } request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -751,12 +529,26 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) { tcp = true; + request->timeout = timeout * 1000; + } else { + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + } + if (udptimeout == 0) { + udptimeout = 1; + } + request->timeout = udptimeout * 1000; + } + + isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); + result = isc_buffer_copyregion(request->query, &r); + if (result != ISC_R_SUCCESS) { + goto cleanup; } - share = (options & DNS_REQUESTOPT_SHARE); again: - result = get_dispatch(tcp, newtcp, share, requestmgr, srcaddr, destaddr, - dscp, &connected, &request->dispatch); + result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr, dscp, + &connected, &request->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -766,65 +558,44 @@ again: dispopt |= DNS_DISPATCHOPT_FIXEDID; } + req_attach(request, &rclone); result = dns_dispatch_addresponse( - request->dispatch, dispopt, destaddr, task, req_response, - request, &id, &request->dispentry, requestmgr->socketmgr); + request->dispatch, dispopt, request->timeout, destaddr, + req_connected, req_senddone, req_response, request, &id, + &request->dispentry); if (result != ISC_R_SUCCESS) { if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) { newtcp = true; connected = false; + req_detach(&rclone); dns_dispatch_detach(&request->dispatch); goto again; } goto cleanup; } - sock = req_getsocket(request); - INSIST(sock != NULL); - - isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(request->query, (uint16_t)r.length); - } - result = isc_buffer_copyregion(request->query, &r); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - /* Add message ID. */ isc_buffer_usedregion(request->query, &r); - if (tcp) { - isc_region_consume(&r, 2); - } r.base[0] = (id >> 8) & 0xff; r.base[1] = id & 0xff; LOCK(&requestmgr->lock); - if (requestmgr->exiting) { - UNLOCK(&requestmgr->lock); - result = ISC_R_SHUTTINGDOWN; - goto cleanup; - } - requestmgr_attach(requestmgr, &request->requestmgr); + dns_requestmgr_attach(requestmgr, &request->requestmgr); request->hash = mgr_gethash(requestmgr); ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = isc_socket_connect(sock, destaddr, task, req_connected, - request); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; + if (tcp && connected) { + req_send(request); + req_detach(&rclone); } else { - result = req_send(request, task, connected ? NULL : destaddr); + request->flags |= DNS_REQUEST_F_CONNECTING; + if (tcp) { + request->flags |= DNS_REQUEST_F_TCP; + } + + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } @@ -843,7 +614,10 @@ cleanup: if (tclone != NULL) { isc_task_detach(&tclone); } - req_destroy(request); + if (rclone != NULL) { + req_detach(&rclone); + } + req_detach(&request); req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s", dns_result_totext(result)); return (result); @@ -871,13 +645,11 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; - isc_socket_t *sock = NULL; + dns_request_t *rclone = NULL; isc_result_t result; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; dns_messageid_t id; - bool tcp; - bool share; - bool settsigkey = true; + bool tcp = false; bool connected = false; REQUIRE(VALID_REQUESTMGR(requestmgr)); @@ -892,6 +664,10 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, req_log(ISC_LOG_DEBUG(3), "dns_request_createvia"); + if (atomic_load_acquire(&requestmgr->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + if (srcaddr != NULL && isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr)) { return (ISC_R_FAMILYMISMATCH); @@ -901,31 +677,14 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, return (DNS_R_BLACKHOLED); } - request = NULL; result = new_request(mctx, &request); if (result != ISC_R_SUCCESS) { return (result); } - if (udptimeout == 0 && udpretries != 0) { - udptimeout = timeout / (udpretries + 1); - if (udptimeout == 0) { - udptimeout = 1; - } - } request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -937,42 +696,51 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, dns_tsigkey_attach(key, &request->tsigkey); } -use_tcp: - tcp = ((options & DNS_REQUESTOPT_TCP) != 0); - share = ((options & DNS_REQUESTOPT_SHARE) != 0); - result = get_dispatch(tcp, false, share, requestmgr, srcaddr, destaddr, - dscp, &connected, &request->dispatch); + result = dns_message_settsigkey(message, request->tsigkey); if (result != ISC_R_SUCCESS) { goto cleanup; } - result = dns_dispatch_addresponse( - request->dispatch, 0, destaddr, task, req_response, request, - &id, &request->dispentry, requestmgr->socketmgr); + if ((options & DNS_REQUESTOPT_TCP) != 0) { + tcp = true; + request->timeout = timeout * 1000; + } else { + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + } + if (udptimeout == 0) { + udptimeout = 1; + } + request->timeout = udptimeout * 1000; + } + +use_tcp: + result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr, dscp, + &connected, &request->dispatch); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + req_attach(request, &rclone); + result = dns_dispatch_addresponse( + request->dispatch, 0, request->timeout, destaddr, req_connected, + req_senddone, req_response, request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } - sock = req_getsocket(request); - INSIST(sock != NULL); message->id = id; - if (settsigkey) { - result = dns_message_settsigkey(message, request->tsigkey); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - } result = req_render(message, &request->query, options, mctx); - if (result == DNS_R_USETCP && (options & DNS_REQUESTOPT_TCP) == 0) { + if (result == DNS_R_USETCP && !tcp) { /* * Try again using TCP. */ + req_detach(&rclone); dns_message_renderreset(message); - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); dns_dispatch_detach(&request->dispatch); - sock = NULL; options |= DNS_REQUESTOPT_TCP; - settsigkey = false; + tcp = true; goto use_tcp; } if (result != ISC_R_SUCCESS) { @@ -985,31 +753,22 @@ use_tcp: } LOCK(&requestmgr->lock); - if (requestmgr->exiting) { - UNLOCK(&requestmgr->lock); - result = ISC_R_SHUTTINGDOWN; - goto cleanup; - } - requestmgr_attach(requestmgr, &request->requestmgr); + dns_requestmgr_attach(requestmgr, &request->requestmgr); request->hash = mgr_gethash(requestmgr); ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = isc_socket_connect(sock, destaddr, task, req_connected, - request); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; + if (tcp && connected) { + req_send(request); + req_detach(&rclone); } else { - result = req_send(request, task, connected ? NULL : destaddr); + request->flags |= DNS_REQUEST_F_CONNECTING; + if (tcp) { + request->flags |= DNS_REQUEST_F_TCP; + } + + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } @@ -1028,7 +787,10 @@ cleanup: if (tclone != NULL) { isc_task_detach(&tclone); } - req_destroy(request); + if (rclone != NULL) { + req_detach(&rclone); + } + req_detach(&request); req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s", dns_result_totext(result)); return (result); @@ -1041,7 +803,6 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, isc_buffer_t *buf2 = NULL; isc_result_t result; isc_region_t r; - bool tcp = false; dns_compress_t cctx; bool cleanup_cctx = false; @@ -1099,16 +860,11 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, * Copy rendered message to exact sized buffer. */ isc_buffer_usedregion(buf1, &r); - if ((options & DNS_REQUESTOPT_TCP) != 0) { - tcp = true; - } else if (r.length > 512) { + if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) { result = DNS_R_USETCP; goto cleanup; } - isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(buf2, (uint16_t)r.length); - } + isc_buffer_allocate(mctx, &buf2, r.length); result = isc_buffer_copyregion(buf2, &r); if (result != ISC_R_SUCCESS) { goto cleanup; @@ -1145,26 +901,27 @@ cleanup: */ static void send_if_done(dns_request_t *request, isc_result_t result) { - if (request->event != NULL && !request->canceling) { + if (request->event != NULL) { req_sendevent(request, result); } } -/* - * Handle the control event. - */ -static void -do_cancel(isc_task_t *task, isc_event_t *event) { - dns_request_t *request = event->ev_arg; - UNUSED(task); - INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL); - LOCK(&request->requestmgr->locks[request->hash]); - request->canceling = false; +void +request_cancel(dns_request_t *request) { if (!DNS_REQUEST_CANCELED(request)) { - req_cancel(request); + req_log(ISC_LOG_DEBUG(3), "request_cancel: request %p", + request); + + request->flags |= DNS_REQUEST_F_CANCELED; + request->flags &= ~DNS_REQUEST_F_CONNECTING; + + if (request->dispentry != NULL) { + dns_dispatch_cancel(request->dispentry); + dns_dispatch_removeresponse(&request->dispentry); + } + + dns_dispatch_detach(&request->dispatch); } - send_if_done(request, ISC_R_CANCELED); - UNLOCK(&request->requestmgr->locks[request->hash]); } void @@ -1172,15 +929,9 @@ dns_request_cancel(dns_request_t *request) { REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request); - - REQUIRE(VALID_REQUEST(request)); - LOCK(&request->requestmgr->locks[request->hash]); - if (!request->canceling && !DNS_REQUEST_CANCELED(request)) { - isc_event_t *ev = &request->ctlevent; - isc_task_send(request->event->ev_sender, &ev); - request->canceling = true; - } + request_cancel(request); + send_if_done(request, ISC_R_CANCELED); UNLOCK(&request->requestmgr->locks[request->hash]); } @@ -1247,147 +998,130 @@ dns_request_destroy(dns_request_t **requestp) { UNLOCK(&request->requestmgr->lock); /* - * These should have been cleaned up by req_cancel() before - * the completion event was sent. + * These should have been cleaned up before the completion + * event was sent. */ INSIST(!ISC_LINK_LINKED(request, link)); INSIST(request->dispentry == NULL); INSIST(request->dispatch == NULL); - INSIST(request->timer == NULL); - req_destroy(request); -} - -/*** - *** Private: request. - ***/ - -static isc_socket_t * -req_getsocket(dns_request_t *request) { - unsigned int dispattr; - isc_socket_t *sock; - - dispattr = dns_dispatch_getattributes(request->dispatch); - if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - INSIST(request->dispentry != NULL); - sock = dns_dispatch_getentrysocket(request->dispentry); - } else { - sock = dns_dispatch_getsocket(request->dispatch); - } - - return (sock); + req_detach(&request); } static void -req_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - isc_result_t result; - dns_request_t *request = event->ev_arg; +req_connected(isc_result_t eresult, isc_region_t *region, void *arg) { + dns_request_t *request = (dns_request_t *)arg; + + UNUSED(region); + + req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request, + isc_result_totext(eresult)); - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_REQUEST(request)); - REQUIRE(DNS_REQUEST_CONNECTING(request)); - - req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request); + REQUIRE(DNS_REQUEST_CONNECTING(request) || + DNS_REQUEST_CANCELED(request)); LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_CONNECTING; - if (DNS_REQUEST_CANCELED(request)) { - /* - * Send delayed event. - */ - if (DNS_REQUEST_TIMEDOUT(request)) { - send_if_done(request, ISC_R_TIMEDOUT); - } else { - send_if_done(request, ISC_R_CANCELED); - } + if (eresult == ISC_R_TIMEDOUT) { + dns_dispatch_removeresponse(&request->dispentry); + dns_dispatch_detach(&request->dispatch); + send_if_done(request, eresult); + } else if (DNS_REQUEST_CANCELED(request)) { + send_if_done(request, ISC_R_CANCELED); + } else if (eresult == ISC_R_SUCCESS) { + req_send(request); } else { - dns_dispatch_starttcp(request->dispatch); - result = sevent->result; - if (result == ISC_R_SUCCESS) { - result = req_send(request, task, NULL); - } - - if (result != ISC_R_SUCCESS) { - req_cancel(request); - send_if_done(request, ISC_R_CANCELED); - } + request_cancel(request); + send_if_done(request, ISC_R_CANCELED); } UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); + + req_detach(&request); } static void -req_senddone(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - dns_request_t *request = event->ev_arg; +req_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { + dns_request_t *request = (dns_request_t *)arg; - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_SENDING(request)); - req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); + UNUSED(region); - UNUSED(task); + req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_SENDING; if (DNS_REQUEST_CANCELED(request)) { - /* - * Send delayed event. - */ - if (DNS_REQUEST_TIMEDOUT(request)) { - send_if_done(request, ISC_R_TIMEDOUT); + if (eresult == ISC_R_TIMEDOUT) { + send_if_done(request, eresult); } else { send_if_done(request, ISC_R_CANCELED); } - } else if (sevent->result != ISC_R_SUCCESS) { - req_cancel(request); + } else if (eresult != ISC_R_SUCCESS) { + request_cancel(request); send_if_done(request, ISC_R_CANCELED); } - UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); + UNLOCK(&request->requestmgr->locks[request->hash]); } static void -req_response(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - dns_request_t *request = event->ev_arg; - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - isc_region_t r; - - REQUIRE(VALID_REQUEST(request)); - REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); - - UNUSED(task); +req_response(isc_result_t result, isc_region_t *region, void *arg) { + dns_request_t *request = (dns_request_t *)arg; req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, - dns_result_totext(devent->result)); + dns_result_totext(result)); + + if (result == ISC_R_CANCELED || result == ISC_R_EOF) { + return; + } + + if (result == ISC_R_TIMEDOUT) { + LOCK(&request->requestmgr->locks[request->hash]); + if (--request->udpcount != 0) { + dns_dispatch_resume(request->dispentry, + request->timeout); + if (!DNS_REQUEST_SENDING(request)) { + req_send(request); + } + UNLOCK(&request->requestmgr->locks[request->hash]); + return; + } + + /* The lock is unlocked below */ + goto done; + } + + REQUIRE(VALID_REQUEST(request)); LOCK(&request->requestmgr->locks[request->hash]); - result = devent->result; + if (result != ISC_R_SUCCESS) { goto done; } /* - * Copy buffer to request. + * Copy region to request. */ - isc_buffer_usedregion(&devent->buffer, &r); - isc_buffer_allocate(request->mctx, &request->answer, r.length); - result = isc_buffer_copyregion(request->answer, &r); + isc_buffer_allocate(request->mctx, &request->answer, region->length); + result = isc_buffer_copyregion(request->answer, region); if (result != ISC_R_SUCCESS) { isc_buffer_free(&request->answer); } + done: /* * Cleanup. */ - dns_dispatch_removeresponse(&request->dispentry, &devent); - req_cancel(request); + if (request->dispentry != NULL) { + dns_dispatch_removeresponse(&request->dispentry); + } + request_cancel(request); + /* * Send completion event. */ @@ -1395,34 +1129,6 @@ done: UNLOCK(&request->requestmgr->locks[request->hash]); } -static void -req_timeout(isc_task_t *task, isc_event_t *event) { - dns_request_t *request = event->ev_arg; - isc_result_t result; - - REQUIRE(VALID_REQUEST(request)); - - req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); - - UNUSED(task); - LOCK(&request->requestmgr->locks[request->hash]); - if (event->ev_type == ISC_TIMEREVENT_TICK && request->udpcount-- != 0) { - if (!DNS_REQUEST_SENDING(request)) { - result = req_send(request, task, &request->destaddr); - if (result != ISC_R_SUCCESS) { - req_cancel(request); - send_if_done(request, result); - } - } - } else { - request->flags |= DNS_REQUEST_F_TIMEDOUT; - req_cancel(request); - send_if_done(request, ISC_R_TIMEDOUT); - } - UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); -} - static void req_sendevent(dns_request_t *request, isc_result_t result) { isc_task_t *task; @@ -1440,12 +1146,52 @@ req_sendevent(dns_request_t *request, isc_result_t result) { isc_task_sendanddetach(&task, (isc_event_t **)&request->event); } +static void +req_attach(dns_request_t *source, dns_request_t **targetp) { + REQUIRE(VALID_REQUEST(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + isc_refcount_increment(&source->references); + + *targetp = source; +} + +static void +req_detach(dns_request_t **requestp) { + dns_request_t *request = NULL; + uint_fast32_t ref; + + REQUIRE(requestp != NULL && VALID_REQUEST(*requestp)); + + request = *requestp; + *requestp = NULL; + + ref = isc_refcount_decrement(&request->references); + + if (request->requestmgr != NULL && + atomic_load_acquire(&request->requestmgr->exiting)) + { + /* We are shutting down and this was last request */ + LOCK(&request->requestmgr->lock); + if (ISC_LIST_EMPTY(request->requestmgr->requests)) { + send_shutdown_events(request->requestmgr); + } + UNLOCK(&request->requestmgr->lock); + } + + if (ref == 1) { + req_destroy(request); + } +} + static void req_destroy(dns_request_t *request) { REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request); + isc_refcount_destroy(&request->references); + request->magic = 0; if (request->query != NULL) { isc_buffer_free(&request->query); @@ -1457,14 +1203,11 @@ req_destroy(dns_request_t *request) { isc_event_free((isc_event_t **)&request->event); } if (request->dispentry != NULL) { - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); } if (request->dispatch != NULL) { dns_dispatch_detach(&request->dispatch); } - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } if (request->tsig != NULL) { isc_buffer_free(&request->tsig); } @@ -1472,55 +1215,11 @@ req_destroy(dns_request_t *request) { dns_tsigkey_detach(&request->tsigkey); } if (request->requestmgr != NULL) { - requestmgr_detach(&request->requestmgr); + dns_requestmgr_detach(&request->requestmgr); } isc_mem_putanddetach(&request->mctx, request, sizeof(*request)); } -/* - * Stop the current request. Must be called from the request's task. - */ -static void -req_cancel(dns_request_t *request) { - isc_socket_t *sock; - unsigned int dispattr; - - REQUIRE(VALID_REQUEST(request)); - - req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request); - - /* - * Lock held by caller. - */ - request->flags |= DNS_REQUEST_F_CANCELED; - - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } - dispattr = dns_dispatch_getattributes(request->dispatch); - sock = NULL; - if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) { - if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - if (request->dispentry != NULL) { - sock = dns_dispatch_getentrysocket( - request->dispentry); - } - } else { - sock = dns_dispatch_getsocket(request->dispatch); - } - if (DNS_REQUEST_CONNECTING(request) && sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); - } - if (DNS_REQUEST_SENDING(request) && sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } - } - if (request->dispentry != NULL) { - dns_dispatch_removeresponse(&request->dispentry, NULL); - } - dns_dispatch_detach(&request->dispatch); -} - static void req_log(int level, const char *fmt, ...) { va_list ap; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 0358241d95..395aa4f92b 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -62,6 +61,7 @@ #include #include #include + #ifdef WANT_QUERYTRACE #define RTRACE(m) \ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, \ @@ -152,6 +152,7 @@ #define US_PER_SEC 1000000U #define US_PER_MSEC 1000U +#define NS_PER_US 1000U /* * The maximum time we will wait for a single query. */ @@ -222,14 +223,13 @@ typedef struct fetchctx fetchctx_t; typedef struct query { /* Locked by task event serialization. */ unsigned int magic; + isc_refcount_t references; fetchctx_t *fctx; dns_message_t *rmessage; isc_mem_t *mctx; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatch; - bool exclusivesocket; dns_adbaddrinfo_t *addrinfo; - isc_socket_t *tcpsocket; isc_time_t start; dns_messageid_t id; dns_dispentry_t *dispentry; @@ -242,8 +242,6 @@ typedef struct query { int ednsversion; unsigned int options; isc_sockeventattr_t attributes; - unsigned int sends; - unsigned int connects; unsigned int udpsize; unsigned char data[512]; } resquery_t; @@ -280,7 +278,8 @@ struct fetchctx { /*% Not locked. */ unsigned int magic; dns_resolver_t *res; - dns_name_t name; + dns_fixedname_t fname; + dns_name_t *name; dns_rdatatype_t type; unsigned int options; unsigned int bucketnum; @@ -288,6 +287,7 @@ struct fetchctx { char *info; isc_mem_t *mctx; isc_stdtime_t now; + isc_task_t *task; /* Atomic */ isc_refcount_t references; @@ -302,13 +302,13 @@ struct fetchctx { ISC_LIST(dns_fetchevent_t) events; /*% Locked by task event serialization. */ - dns_name_t domain; + dns_fixedname_t dfname; + dns_name_t *domain; dns_rdataset_t nameservers; atomic_uint_fast32_t attributes; - isc_timer_t *timer; - isc_timer_t *timer_try_stale; isc_time_t expires; isc_time_t expires_try_stale; + isc_time_t next_timeout; isc_interval_t interval; dns_message_t *qmessage; ISC_LIST(resquery_t) queries; @@ -335,11 +335,13 @@ struct fetchctx { isc_result_t qmin_warning; bool ip6arpaskip; bool forwarding; - dns_name_t qminname; + dns_fixedname_t qminfname; + dns_name_t *qminname; dns_rdatatype_t qmintype; dns_fetch_t *qminfetch; dns_rdataset_t qminrrset; - dns_name_t qmindcname; + dns_fixedname_t qmindcfname; + dns_name_t *qmindcname; /*% * The number of events we're waiting for. @@ -366,7 +368,9 @@ struct fetchctx { /*% * Look aside state for DS lookups. */ - dns_name_t nsname; + dns_fixedname_t nsfname; + dns_name_t *nsname; + dns_fetch_t *nsfetch; dns_rdataset_t nsrrset; @@ -449,6 +453,7 @@ typedef struct { struct dns_fetch { unsigned int magic; isc_mem_t *mctx; + dns_resolver_t *res; fetchctx_t *private; }; @@ -465,7 +470,7 @@ typedef struct fctxbucket { typedef struct fctxcount fctxcount_t; struct fctxcount { - dns_fixedname_t fdname; + dns_fixedname_t dfname; dns_name_t *domain; uint32_t count; uint32_t allowed; @@ -499,7 +504,7 @@ struct dns_resolver { isc_mutex_t lock; isc_mutex_t primelock; dns_rdataclass_t rdclass; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; isc_taskmgr_t *taskmgr; dns_view_t *view; @@ -507,25 +512,17 @@ struct dns_resolver { unsigned int options; dns_dispatchmgr_t *dispatchmgr; dns_dispatchset_t *dispatches4; - bool exclusivev4; dns_dispatchset_t *dispatches6; isc_dscp_t querydscp4; isc_dscp_t querydscp6; - bool exclusivev6; unsigned int nbuckets; fctxbucket_t *buckets; zonebucket_t *dbuckets; uint32_t lame_ttl; ISC_LIST(alternate_t) alternates; uint16_t udpsize; -#if USE_ALGLOCK - isc_rwlock_t alglock; -#endif /* if USE_ALGLOCK */ dns_rbt_t *algorithms; dns_rbt_t *digests; -#if USE_MBSLOCK - isc_rwlock_t mbslock; -#endif /* if USE_MBSLOCK */ dns_rbt_t *mustbesecure; unsigned int spillatmax; unsigned int spillatmin; @@ -548,7 +545,7 @@ struct dns_resolver { /* Locked by lock. */ isc_eventlist_t whenshutdown; - unsigned int activebuckets; + isc_refcount_t activebuckets; unsigned int spillat; /* clients-per-query */ dns_badcache_t *badcache; /* Bad cache. */ @@ -613,9 +610,9 @@ empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); static void -resquery_response(isc_task_t *task, isc_event_t *event); +resquery_response(isc_result_t eresult, isc_region_t *region, void *arg); static void -resquery_connected(isc_task_t *task, isc_event_t *event); +resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg); static void fctx_try(fetchctx_t *fctx, bool retrying, bool badcache); static isc_result_t @@ -714,11 +711,10 @@ resume_qmin(isc_task_t *task, isc_event_t *event); */ typedef struct respctx { - isc_task_t *task; - dns_dispatchevent_t *devent; resquery_t *query; fetchctx_t *fctx; isc_result_t result; + isc_buffer_t buffer; unsigned int retryopts; /* updated options to pass to * fctx_query() when resending */ @@ -780,8 +776,8 @@ typedef struct respctx { } respctx_t; static void -rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, - fetchctx_t *fctx, respctx_t *rctx); +rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result, + isc_region_t *region, respctx_t *rctx); static void rctx_answer_init(respctx_t *rctx); @@ -829,7 +825,7 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, static void rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo); -static void +static isc_result_t rctx_next(respctx_t *rctx); static void @@ -863,6 +859,9 @@ rctx_lameserver(respctx_t *rctx); static isc_result_t rctx_dispfail(respctx_t *rctx); +static isc_result_t +rctx_timedout(respctx_t *rctx); + static void rctx_delonly_zone(respctx_t *rctx); @@ -940,7 +939,7 @@ rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) { dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rrsig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - namereln = dns_name_fullcompare(&rrsig.signer, &fctx->domain, + namereln = dns_name_fullcompare(&rrsig.signer, fctx->domain, &order, &labels); if (namereln == dns_namereln_subdomain) { return (true); @@ -953,7 +952,7 @@ rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) { static bool fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) { dns_name_t *name; - dns_name_t *domain = &fctx->domain; + dns_name_t *domain = fctx->domain; dns_rdataset_t *rdataset; dns_rdatatype_t type; isc_result_t result; @@ -1010,7 +1009,7 @@ fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) { rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { - if (!dns_name_equal(name, &fctx->name)) { + if (!dns_name_equal(name, fctx->name)) { continue; } type = rdataset->type; @@ -1123,97 +1122,34 @@ munge: return (true); } -static inline isc_result_t -fctx_starttimer(fetchctx_t *fctx) { - /* - * Start the lifetime timer for fctx. - * - * This is also used for stopping the idle timer; in that - * case we must purge events already posted to ensure that - * no further idle events are delivered. - */ - return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, - NULL, true)); -} - -static inline isc_result_t -fctx_starttimer_trystale(fetchctx_t *fctx) { - /* - * Start the stale-answer-client-timeout timer for fctx. - */ - - return (isc_timer_reset(fctx->timer_try_stale, isc_timertype_once, - &fctx->expires_try_stale, NULL, true)); -} - static inline void -fctx_stoptimer(fetchctx_t *fctx) { - isc_result_t result; - - /* - * We don't return a result if resetting the timer to inactive fails - * since there's nothing to be done about it. Resetting to inactive - * should never fail anyway, since the code as currently written - * cannot fail in that case. - */ - result = isc_timer_reset(fctx->timer, isc_timertype_inactive, NULL, - NULL, true); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_reset(): %s", - isc_result_totext(result)); - } -} - -static inline void -fctx_stoptimer_trystale(fetchctx_t *fctx) { - isc_result_t result; - - if (fctx->timer_try_stale != NULL) { - result = isc_timer_reset(fctx->timer_try_stale, - isc_timertype_inactive, NULL, NULL, - true); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_timer_reset(): %s", - isc_result_totext(result)); - } - } -} - -static inline isc_result_t -fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) { - /* - * Start the idle timer for fctx. The lifetime timer continues - * to be in effect. - */ - return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, - interval, false)); -} - -/* - * Stopping the idle timer is equivalent to calling fctx_starttimer(), but - * we use fctx_stopidletimer for readability in the code below. - */ -#define fctx_stopidletimer fctx_starttimer - -static inline void -resquery_destroy(resquery_t **queryp) { - dns_resolver_t *res; +resquery_destroy(resquery_t *query) { + fetchctx_t *fctx = query->fctx; + dns_resolver_t *res = fctx->res; + unsigned int bucket = fctx->bucketnum; bool empty; - resquery_t *query; - fetchctx_t *fctx; - unsigned int bucket; - REQUIRE(queryp != NULL); - query = *queryp; - *queryp = NULL; - REQUIRE(!ISC_LINK_LINKED(query, link)); + if (ISC_LINK_LINKED(query, link)) { + ISC_LIST_UNLINK(fctx->queries, query, link); + } - INSIST(query->tcpsocket == NULL); + if (query->tsig != NULL) { + isc_buffer_free(&query->tsig); + } - fctx = query->fctx; - res = fctx->res; - bucket = fctx->bucketnum; + if (query->tsigkey != NULL) { + dns_tsigkey_detach(&query->tsigkey); + } + + if (query->dispentry != NULL) { + dns_dispatch_removeresponse(&query->dispentry); + } + + if (query->dispatch != NULL) { + dns_dispatch_detach(&query->dispatch); + } + + isc_refcount_destroy(&query->references); LOCK(&res->buckets[bucket].lock); fctx->nqueries--; @@ -1232,6 +1168,32 @@ resquery_destroy(resquery_t **queryp) { } } +static void +resquery_attach(resquery_t *source, resquery_t **targetp) { + REQUIRE(VALID_QUERY(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + isc_refcount_increment(&source->references); + + *targetp = source; +} + +static void +resquery_detach(resquery_t **queryp) { + uint_fast32_t ref; + resquery_t *query = NULL; + + REQUIRE(queryp != NULL && VALID_QUERY(*queryp)); + + query = *queryp; + *queryp = NULL; + + ref = isc_refcount_decrement(&query->references); + if (ref == 1) { + resquery_destroy(query); + } +} + /*% * Update EDNS statistics for a server after not getting a response to a UDP * query sent to it. @@ -1252,23 +1214,22 @@ update_edns_stats(resquery_t *query) { } static void -fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, - isc_time_t *finish, bool no_response, bool age_untried) { - fetchctx_t *fctx; - resquery_t *query; +fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, + bool age_untried) { + fetchctx_t *fctx = NULL; unsigned int rtt, rttms; unsigned int factor; - dns_adbfind_t *find; + dns_adbfind_t *find = NULL; dns_adbaddrinfo_t *addrinfo; - isc_socket_t *sock; isc_stdtime_t now; - query = *queryp; fctx = query->fctx; FCTXTRACE("cancelquery"); - REQUIRE(!RESQUERY_CANCELED(query)); + if (RESQUERY_CANCELED(query)) { + return; + } query->attributes |= RESQUERY_ATTR_CANCELED; @@ -1285,7 +1246,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, &query->start); factor = DNS_ADB_RTTADJDEFAULT; - rttms = rtt / 1000; + rttms = rtt / US_PER_MSEC; if (rttms < DNS_RESOLVER_QRYRTTCLASS0) { inc_stats(fctx->res, dns_resstatscounter_queryrtt0); @@ -1366,10 +1327,11 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, } dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); - } - if ((query->options & DNS_FETCHOPT_TCP) == 0) { - /* Inform the ADB that we're ending a UDP fetch */ - dns_adb_endudpfetch(fctx->adb, query->addrinfo); + + if ((query->options & DNS_FETCHOPT_TCP) == 0) { + /* Inform the ADB that we're ending a UDP fetch */ + dns_adb_endudpfetch(fctx->adb, query->addrinfo); + } } /* @@ -1427,83 +1389,25 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, } /* - * Check for any outstanding socket events. If they exist, cancel - * them and let the event handlers finish the cleanup. The resolver - * only needs to worry about managing the connect and send events; - * the dispatcher manages the recv events. + * Check for any outstanding dispatch responses and if they + * exist, cancel them. */ - if (RESQUERY_CONNECTING(query)) { - /* - * Cancel the connect. - */ - if (query->tcpsocket != NULL) { - isc_socket_cancel(query->tcpsocket, NULL, - ISC_SOCKCANCEL_CONNECT); - } else if (query->dispentry != NULL) { - INSIST(query->exclusivesocket); - sock = dns_dispatch_getentrysocket(query->dispentry); - if (sock != NULL) { - isc_socket_cancel(sock, NULL, - ISC_SOCKCANCEL_CONNECT); - } - } - } - if (RESQUERY_SENDING(query)) { - /* - * Cancel the pending send. - */ - if (query->exclusivesocket && query->dispentry != NULL) { - sock = dns_dispatch_getentrysocket(query->dispentry); - } else { - sock = dns_dispatch_getsocket(query->dispatch); - } - if (sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } - } - if (query->dispentry != NULL) { - dns_dispatch_removeresponse(&query->dispentry, deventp); + dns_dispatch_cancel(query->dispentry); + dns_dispatch_removeresponse(&query->dispentry); } - ISC_LIST_UNLINK(fctx->queries, query, link); - - if (query->tsig != NULL) { - isc_buffer_free(&query->tsig); + if (ISC_LINK_LINKED(query, link)) { + ISC_LIST_UNLINK(fctx->queries, query, link); } - if (query->tsigkey != NULL) { - dns_tsigkey_detach(&query->tsigkey); - } - - if (query->dispatch != NULL) { - dns_dispatch_detach(&query->dispatch); - } - - if (!(RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query))) { - /* - * It's safe to destroy the query now. - */ - resquery_destroy(&query); - } + resquery_detach(&query); } static void -fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { - resquery_t *query, *next_query; - - FCTXTRACE("cancelqueries"); - - for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; - query = next_query) { - next_query = ISC_LIST_NEXT(query, link); - fctx_cancelquery(&query, NULL, NULL, no_response, age_untried); - } -} - -static void -fctx_cleanupfinds(fetchctx_t *fctx) { - dns_adbfind_t *find, *next_find; +fctx_cleanup(fetchctx_t *fctx) { + dns_adbfind_t *find = NULL, *next_find = NULL; + dns_adbaddrinfo_t *addr = NULL, *next_addr = NULL; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); @@ -1514,13 +1418,6 @@ fctx_cleanupfinds(fetchctx_t *fctx) { dns_adb_destroyfind(&find); } fctx->find = NULL; -} - -static void -fctx_cleanupaltfinds(fetchctx_t *fctx) { - dns_adbfind_t *find, *next_find; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = next_find) { @@ -1529,13 +1426,6 @@ fctx_cleanupaltfinds(fetchctx_t *fctx) { dns_adb_destroyfind(&find); } fctx->altfind = NULL; -} - -static void -fctx_cleanupforwaddrs(fetchctx_t *fctx) { - dns_adbaddrinfo_t *addr, *next_addr; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->forwaddrs); addr != NULL; addr = next_addr) { @@ -1543,13 +1433,6 @@ fctx_cleanupforwaddrs(fetchctx_t *fctx) { ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); } -} - -static void -fctx_cleanupaltaddrs(fetchctx_t *fctx) { - dns_adbaddrinfo_t *addr, *next_addr; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->altaddrs); addr != NULL; addr = next_addr) { @@ -1559,20 +1442,17 @@ fctx_cleanupaltaddrs(fetchctx_t *fctx) { } } -static inline void -fctx_stopqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { - FCTXTRACE("stopqueries"); - fctx_cancelqueries(fctx, no_response, age_untried); - fctx_stoptimer(fctx); - fctx_stoptimer_trystale(fctx); -} +static void +fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { + resquery_t *query = NULL, *next_query = NULL; -static inline void -fctx_cleanupall(fetchctx_t *fctx) { - fctx_cleanupfinds(fctx); - fctx_cleanupaltfinds(fctx); - fctx_cleanupforwaddrs(fctx); - fctx_cleanupaltaddrs(fctx); + FCTXTRACE("cancelqueries"); + + for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; + query = next_query) { + next_query = ISC_LIST_NEXT(query, link); + fctx_cancelquery(query, NULL, no_response, age_untried); + } } static void @@ -1589,7 +1469,7 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter) { return; } - dns_name_format(&fctx->domain, dbuf, sizeof(dbuf)); + dns_name_format(fctx->domain, dbuf, sizeof(dbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_SPILL, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -1603,16 +1483,15 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter) { static isc_result_t fcount_incr(fetchctx_t *fctx, bool force) { isc_result_t result = ISC_R_SUCCESS; - zonebucket_t *dbucket; - fctxcount_t *counter; + zonebucket_t *dbucket = NULL; + fctxcount_t *counter = NULL; unsigned int bucketnum; REQUIRE(fctx != NULL); REQUIRE(fctx->res != NULL); INSIST(fctx->dbucketnum == RES_NOBUCKET); - bucketnum = dns_name_fullhash(&fctx->domain, false) % - RES_DOMAIN_BUCKETS; + bucketnum = dns_name_fullhash(fctx->domain, false) % RES_DOMAIN_BUCKETS; dbucket = &fctx->res->dbuckets[bucketnum]; @@ -1620,7 +1499,7 @@ fcount_incr(fetchctx_t *fctx, bool force) { for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; counter = ISC_LIST_NEXT(counter, link)) { - if (dns_name_equal(counter->domain, &fctx->domain)) { + if (dns_name_equal(counter->domain, fctx->domain)) { break; } } @@ -1634,8 +1513,8 @@ fcount_incr(fetchctx_t *fctx, bool force) { counter->allowed = 1; counter->dropped = 0; counter->domain = - dns_fixedname_initname(&counter->fdname); - dns_name_copy(&fctx->domain, counter->domain); + dns_fixedname_initname(&counter->dfname); + dns_name_copy(fctx->domain, counter->domain); ISC_LIST_APPEND(dbucket->list, counter, link); } } else { @@ -1660,8 +1539,8 @@ fcount_incr(fetchctx_t *fctx, bool force) { static void fcount_decr(fetchctx_t *fctx) { - zonebucket_t *dbucket; - fctxcount_t *counter; + zonebucket_t *dbucket = NULL; + fctxcount_t *counter = NULL; REQUIRE(fctx != NULL); @@ -1675,7 +1554,7 @@ fcount_decr(fetchctx_t *fctx) { for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; counter = ISC_LIST_NEXT(counter, link)) { - if (dns_name_equal(counter->domain, &fctx->domain)) { + if (dns_name_equal(counter->domain, fctx->domain)) { break; } } @@ -1806,7 +1685,6 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { res = fctx->res; if (result == ISC_R_SUCCESS) { - no_response = true; if (fctx->qmin_warning != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -1816,13 +1694,24 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { fctx->info, isc_result_totext(fctx->qmin_warning)); } + + /* + * A success result indicates we got a response to a + * query. That query should be canceled already. If + * there still are any outstanding queries attached to the + * same fctx, then those have *not* gotten a response, + * so we set 'no_response' to true here: that way, when + * we run fctx_cancelqueries() below, the SRTTs will + * be adjusted. + */ + no_response = true; } else if (result == ISC_R_TIMEDOUT) { age_untried = true; } fctx->qmin_warning = ISC_R_SUCCESS; - fctx_stopqueries(fctx, no_response, age_untried); + fctx_cancelqueries(fctx, no_response, age_untried); LOCK(&res->buckets[fctx->bucketnum].lock); @@ -1834,122 +1723,57 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { } static void -process_sendevent(resquery_t *query, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - bool destroy_query = false; - bool retry = false; - isc_result_t result; - fetchctx_t *fctx; +resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { + resquery_t *query = (resquery_t *)arg; + fetchctx_t *fctx = NULL; + + QTRACE("senddone"); + + UNUSED(region); fctx = query->fctx; if (RESQUERY_CANCELED(query)) { - if (query->sends == 0 && query->connects == 0) { - /* - * This query was canceled while the - * isc_socket_sendto/connect() was in progress. - */ - if (query->tcpsocket != NULL) { - isc_socket_detach(&query->tcpsocket); - } - destroy_query = true; - } - } else { - switch (sevent->result) { - case ISC_R_SUCCESS: - break; - - case ISC_R_HOSTUNREACH: - case ISC_R_NETUNREACH: - case ISC_R_NOPERM: - case ISC_R_ADDRNOTAVAIL: - case ISC_R_CONNREFUSED: - FCTXTRACE3("query canceled in sendevent(): " - "no route to host; no response", - sevent->result); - - /* - * No route to remote. - */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); - fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; - break; - - default: - FCTXTRACE3("query canceled in sendevent() due to " - "unexpected event result; responding", - sevent->result); - - fctx_cancelquery(&query, NULL, NULL, false, false); - break; - } + goto detach; } - if (event->ev_type == ISC_SOCKEVENT_CONNECT) { - isc_event_free(&event); - } + switch (eresult) { + case ISC_R_SUCCESS: + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + break; + + case ISC_R_HOSTUNREACH: + case ISC_R_NETUNREACH: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + case ISC_R_CONNREFUSED: + FCTXTRACE3("query canceled in resquery_senddone(): " + "no route to host; no response", + eresult); - if (retry) { /* - * Behave as if the idle timer has expired. For TCP - * this may not actually reflect the latest timer. + * No route to remote. */ + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); + fctx_cancelquery(query, NULL, true, false); + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); - } + fctx_try(fctx, true, false); + break; + + default: + FCTXTRACE3("query canceled in resquery_senddone() " + "due to unexpected result; responding", + eresult); + fctx_cancelquery(query, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); + break; } - if (destroy_query) { - resquery_destroy(&query); - } -} - -static void -resquery_udpconnected(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); - - QTRACE("udpconnected"); - - UNUSED(task); - - INSIST(RESQUERY_CONNECTING(query)); - - query->connects--; - - process_sendevent(query, event); -} - -static void -resquery_senddone(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); - - QTRACE("senddone"); - - /* - * XXXRTH - * - * Currently we don't wait for the senddone event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ - - UNUSED(task); - - INSIST(RESQUERY_SENDING(query)); - - query->sends--; - - process_sendevent(query, event); +detach: + resquery_detach(&query); } static inline isc_result_t @@ -1968,10 +1792,23 @@ fctx_addopt(dns_message_t *message, unsigned int version, uint16_t udpsize, static inline void fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { - unsigned int seconds; - unsigned int us; + unsigned int seconds, us; + uint64_t limit; + isc_time_t now; + + /* + * Has this fetch already expired? + */ + isc_time_now(&now); + limit = isc_time_microdiff(&fctx->expires, &now); + if (limit < US_PER_MSEC) { + FCTXTRACE("fetch already expired"); + isc_interval_set(&fctx->interval, 0, 0); + return; + } + + us = fctx->res->retryinterval * US_PER_MSEC; - us = fctx->res->retryinterval * 1000; /* * Exponential backoff after the first few tries. */ @@ -2003,78 +1840,148 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { } /* - * But don't ever wait for more than 10 seconds. + * But don't wait past the stale timeout (if any), the final + * expiration of the fetch, or for more than 10 seconds total. */ + if ((fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0) { + uint64_t stale = isc_time_microdiff(&fctx->expires_try_stale, + &now); + if (stale >= US_PER_MSEC && us > stale) { + FCTXTRACE("setting stale timeout"); + us = stale; + } + } + if (us > limit) { + us = limit; + } if (us > MAX_SINGLE_QUERY_TIMEOUT_US) { us = MAX_SINGLE_QUERY_TIMEOUT_US; } seconds = us / US_PER_SEC; us -= seconds * US_PER_SEC; - isc_interval_set(&fctx->interval, seconds, us * 1000); + isc_interval_set(&fctx->interval, seconds, us * NS_PER_US); + isc_time_nowplusinterval(&fctx->next_timeout, &fctx->interval); +} + +static isc_result_t +resquery_timeout(resquery_t *query) { + fetchctx_t *fctx = query->fctx; + dns_fetchevent_t *event = NULL, *next = NULL; + uint64_t timeleft; + isc_time_t now; + + FCTXTRACE("timeout"); + + /* + * If not configured for serve-stale, do nothing. + */ + if ((fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0) { + return (ISC_R_SUCCESS); + } + + /* + * If we haven't reached the serve-stale timeout, do nothing. + * (Note that netmgr timeouts have millisecond accuracy, so + * anything less than 1000 microseconds is close enough to zero.) + */ + isc_time_now(&now); + timeleft = isc_time_microdiff(&fctx->expires_try_stale, &now); + if (timeleft >= US_PER_MSEC) { + return (ISC_R_SUCCESS); + } + + /* + * Send the TRYSTALE events. + */ + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); + for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next) { + isc_task_t *sender = NULL; + + next = ISC_LIST_NEXT(event, ev_link); + if (event->ev_type != DNS_EVENT_TRYSTALE) { + continue; + } + + ISC_LIST_UNLINK(fctx->events, event, ev_link); + sender = event->ev_sender; + event->vresult = ISC_R_TIMEDOUT; + event->result = ISC_R_TIMEDOUT; + isc_task_sendanddetach(&sender, ISC_EVENT_PTR(&event)); + } + UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + + /* + * If the next timeout is more than 1ms in the future, + * resume waiting. + */ + timeleft = isc_time_microdiff(&fctx->next_timeout, &now); + if (timeleft >= US_PER_MSEC) { + dns_dispatch_resume(query->dispentry, (timeleft / US_PER_MSEC)); + return (ISC_R_COMPLETE); + } + + return (ISC_R_SUCCESS); } static isc_result_t fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options) { - dns_resolver_t *res; - isc_task_t *task; isc_result_t result; - resquery_t *query; + dns_resolver_t *res = NULL; + resquery_t *query = NULL; isc_sockaddr_t addr; bool have_addr = false; unsigned int srtt; isc_dscp_t dscp = -1; - unsigned int bucketnum; FCTXTRACE("query"); res = fctx->res; - task = res->buckets[fctx->bucketnum].task; srtt = addrinfo->srtt; /* - * Allow an additional second for the kernel to resend the SYN (or - * SYN without ECN in the case of stupid firewalls blocking ECN - * negotiation) over the current RTT estimate. + * Allow an additional second for the kernel to resend the SYN + * (or SYN without ECN in the case of stupid firewalls blocking + * ECN negotiation) over the current RTT estimate. */ if ((options & DNS_FETCHOPT_TCP) != 0) { - srtt += 1000000; + srtt += US_PER_SEC; } /* * A forwarder needs to make multiple queries. Give it at least * a second to do these in. */ - if (ISFORWARDER(addrinfo) && srtt < 1000000) { - srtt = 1000000; + if (ISFORWARDER(addrinfo) && srtt < US_PER_SEC) { + srtt = US_PER_SEC; } fctx_setretryinterval(fctx, srtt); - result = fctx_startidletimer(fctx, &fctx->interval); - if (result != ISC_R_SUCCESS) { - return (result); + if (isc_interval_iszero(&fctx->interval)) { + FCTXTRACE("fetch expired"); + return (ISC_R_TIMEDOUT); } INSIST(ISC_LIST_EMPTY(fctx->validators)); query = isc_mem_get(fctx->mctx, sizeof(*query)); - query->rmessage = NULL; + *query = (resquery_t){ .mctx = fctx->mctx, + .options = options, + .dscp = addrinfo->dscp, + .addrinfo = addrinfo, + .dispatchmgr = res->dispatchmgr }; + + isc_refcount_init(&query->references, 1); + + /* + * Note that the caller MUST guarantee that 'addrinfo' will + * remain valid until this query is canceled. + */ + dns_message_create(fctx->mctx, DNS_MESSAGE_INTENTPARSE, &query->rmessage); - query->mctx = fctx->mctx; - query->options = options; - query->attributes = 0; - query->sends = 0; - query->connects = 0; - query->dscp = addrinfo->dscp; - query->udpsize = 0; - /* - * Note that the caller MUST guarantee that 'addrinfo' will remain - * valid until this query is canceled. - */ - query->addrinfo = addrinfo; TIME_NOW(&query->start); /* @@ -2082,10 +1989,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * a dispatch for it here. Otherwise we use the resolver's * shared dispatch. */ - query->dispatchmgr = res->dispatchmgr; - query->dispatch = NULL; - query->exclusivesocket = false; - query->tcpsocket = NULL; if (res->view->peers != NULL) { dns_peer_t *peer = NULL; isc_netaddr_t dstip; @@ -2139,44 +2042,29 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->dscp = dscp; } - result = isc_socket_create(res->socketmgr, pf, - isc_sockettype_tcp, - &query->tcpsocket); + result = dns_dispatch_createtcp(res->dispatchmgr, &addr, + &addrinfo->sockaddr, + query->dscp, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } -#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT - result = isc_socket_bind(query->tcpsocket, &addr, 0); - if (result != ISC_R_SUCCESS) { - goto cleanup_socket; - } -#endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */ - - /* - * A dispatch will be created once the connect succeeds. - */ + FCTXTRACE("connecting via TCP"); } else { if (have_addr) { - unsigned int attrs; - attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(&addr)) { case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; dscp = dns_resolver_getquerydscp4(fctx->res); break; case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; dscp = dns_resolver_getquerydscp6(fctx->res); break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } - result = dns_dispatch_getudp( - res->dispatchmgr, res->socketmgr, res->taskmgr, - &addr, 4096, 20000, 32768, 16411, 16433, attrs, - &query->dispatch); + result = dns_dispatch_createudp(res->dispatchmgr, &addr, + &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2186,14 +2074,12 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_dispatch_attach( dns_resolver_dispatchv4(res), &query->dispatch); - query->exclusivesocket = res->exclusivev4; dscp = dns_resolver_getquerydscp4(fctx->res); break; case PF_INET6: dns_dispatch_attach( dns_resolver_dispatchv6(res), &query->dispatch); - query->exclusivesocket = res->exclusivev6; dscp = dns_resolver_getquerydscp6(fctx->res); break; default: @@ -2208,72 +2094,49 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher - * will be NULL, but we shouldn't be finding addresses for - * protocol types we don't support, so the dispatcher - * we found should never be NULL. + * will be NULL, but we shouldn't be finding addresses + * for protocol types we don't support, so the + * dispatcher we found should never be NULL. */ INSIST(query->dispatch != NULL); } - query->dispentry = NULL; query->fctx = fctx; /* reference added by caller */ - query->tsig = NULL; - query->tsigkey = NULL; ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; - if ((query->options & DNS_FETCHOPT_TCP) != 0) { - /* - * Connect to the remote server. - * - * XXXRTH Should we attach to the socket? - */ - if (query->dscp != -1) { - isc_socket_dscp(query->tcpsocket, query->dscp); - } - result = isc_socket_connect(query->tcpsocket, - &addrinfo->sockaddr, task, - resquery_connected, query); - if (result != ISC_R_SUCCESS) { - goto cleanup_socket; - } - query->connects++; - QTRACE("connecting via TCP"); - } else { + if ((query->options & DNS_FETCHOPT_TCP) == 0) { if (dns_adbentry_overquota(addrinfo->entry)) { + result = ISC_R_QUOTA; goto cleanup_dispatch; } /* Inform the ADB that we're starting a UDP fetch */ dns_adb_beginudpfetch(fctx->adb, addrinfo); - - result = resquery_send(query); - if (result != ISC_R_SUCCESS) { - goto cleanup_dispatch; - } } - fctx->querysent++; - + LOCK(&res->buckets[fctx->bucketnum].lock); ISC_LIST_APPEND(fctx->queries, query, link); - bucketnum = fctx->bucketnum; - LOCK(&res->buckets[bucketnum].lock); fctx->nqueries++; - UNLOCK(&res->buckets[bucketnum].lock); - if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) { - inc_stats(res, dns_resstatscounter_queryv4); - } else { - inc_stats(res, dns_resstatscounter_queryv6); - } - if (res->view->resquerystats != NULL) { - dns_rdatatypestats_increment(res->view->resquerystats, - fctx->type); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + + /* Set up the dispatch and set the query ID */ + result = dns_dispatch_addresponse( + query->dispatch, 0, isc_interval_ms(&fctx->interval), + &query->addrinfo->sockaddr, resquery_connected, + resquery_senddone, resquery_response, query, &query->id, + &query->dispentry); + if (result != ISC_R_SUCCESS) { + goto cleanup_dispatch; } - return (ISC_R_SUCCESS); + /* Connect the socket */ + resquery_attach(query, &(resquery_t *){ NULL }); + result = dns_dispatch_connect(query->dispentry); -cleanup_socket: - isc_socket_detach(&query->tcpsocket); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + return (result); cleanup_dispatch: if (query->dispatch != NULL) { @@ -2281,13 +2144,10 @@ cleanup_dispatch: } cleanup_query: - if (query->connects == 0) { - query->magic = 0; - dns_message_detach(&query->rmessage); - isc_mem_put(fctx->mctx, query, sizeof(*query)); - } - RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); + query->magic = 0; + dns_message_detach(&query->rmessage); + isc_mem_put(fctx->mctx, query, sizeof(*query)); return (result); } @@ -2378,15 +2238,6 @@ addr2buf(void *buf, const size_t bufsize, const isc_sockaddr_t *sockaddr) { return (0); } -static inline isc_socket_t * -query2sock(const resquery_t *query) { - if (query->exclusivesocket) { - return (dns_dispatch_getentrysocket(query->dispentry)); - } else { - return (dns_dispatch_getsocket(query->dispatch)); - } -} - static inline size_t add_serveraddr(uint8_t *buf, const size_t bufsize, const resquery_t *query) { return (addr2buf(buf, bufsize, &query->addrinfo->sockaddr)); @@ -2404,7 +2255,8 @@ compute_cc(const resquery_t *query, uint8_t *cookie, const size_t len) { INSIST(len >= CLIENT_COOKIE_SIZE); STATIC_ASSERT(sizeof(query->fctx->res->view->secret) >= ISC_SIPHASH24_KEY_LENGTH, - "The view->secret size can't fit SipHash 2-4 key length"); + "The view->secret size can't fit SipHash 2-4 key " + "length"); uint8_t buf[16] ISC_NONSTRING = { 0 }; size_t buflen = add_serveraddr(buf, sizeof(buf), query); @@ -2439,23 +2291,19 @@ issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, static isc_result_t resquery_send(resquery_t *query) { - fetchctx_t *fctx; isc_result_t result; + fetchctx_t *fctx = query->fctx; + dns_resolver_t *res = fctx->res; + isc_buffer_t buffer; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; - dns_resolver_t *res; - isc_task_t *task; - isc_socket_t *sock; - isc_buffer_t tcpbuffer; - isc_sockaddr_t *address; - isc_buffer_t *buffer; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; - bool useedns; dns_compress_t cctx; bool cleanup_cctx = false; + bool useedns; bool secure_domain; bool tcp = ((query->options & DNS_FETCHOPT_TCP) != 0); dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; @@ -2469,25 +2317,11 @@ resquery_send(resquery_t *query) { isc_buffer_t zb; #endif /* HAVE_DNSTAP */ - fctx = query->fctx; QTRACE("send"); - res = fctx->res; - task = res->buckets[fctx->bucketnum].task; - address = NULL; - - if (tcp) { - /* - * Reserve space for the TCP message length. - */ - isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data)); - isc_buffer_init(&query->buffer, query->data + 2, - sizeof(query->data) - 2); - buffer = &tcpbuffer; - } else { - isc_buffer_init(&query->buffer, query->data, - sizeof(query->data)); - buffer = &query->buffer; + if (atomic_load_acquire(&res->exiting)) { + FCTXTRACE("resquery_send: resolver shutting down"); + return (ISC_R_SHUTTINGDOWN); } result = dns_message_gettempname(fctx->qmessage, &qname); @@ -2499,23 +2333,12 @@ resquery_send(resquery_t *query) { goto cleanup_temps; } - /* - * Get a query id from the dispatch. - */ - result = dns_dispatch_addresponse(query->dispatch, 0, - &query->addrinfo->sockaddr, task, - resquery_response, query, &query->id, - &query->dispentry, res->socketmgr); - if (result != ISC_R_SUCCESS) { - goto cleanup_temps; - } - fctx->qmessage->opcode = dns_opcode_query; /* * Set up question. */ - dns_name_clone(&fctx->name, qname); + dns_name_clone(fctx->name, qname); dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION); @@ -2523,8 +2346,8 @@ resquery_send(resquery_t *query) { qrdataset = NULL; /* - * Set RD if the client has requested that we do a recursive query, - * or if we're sending to a forwarder. + * Set RD if the client has requested that we do a recursive + * query, or if we're sending to a forwarder. */ if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 || ISFORWARDER(query->addrinfo)) @@ -2546,7 +2369,7 @@ resquery_send(resquery_t *query) { { bool checknta = ((query->options & DNS_FETCHOPT_NONTA) == 0); bool ntacovered = false; - result = issecuredomain(res->view, &fctx->name, fctx->type, + result = issecuredomain(res->view, fctx->name, fctx->type, isc_time_seconds(&query->start), checknta, &ntacovered, &secure_domain); if (result != ISC_R_SUCCESS) { @@ -2572,7 +2395,8 @@ resquery_send(resquery_t *query) { } cleanup_cctx = true; - result = dns_message_renderbegin(fctx->qmessage, &cctx, &query->buffer); + isc_buffer_init(&buffer, query->data, sizeof(query->data)); + result = dns_message_renderbegin(fctx->qmessage, &cctx, &buffer); if (result != ISC_R_SUCCESS) { goto cleanup_message; } @@ -2583,13 +2407,12 @@ resquery_send(resquery_t *query) { goto cleanup_message; } - peer = NULL; isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr); (void)dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); /* - * The ADB does not know about servers with "edns no". Check this, - * and then inform the ADB for future use. + * The ADB does not know about servers with "edns no". Check + * this, and then inform the ADB for future use. */ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 && peer != NULL && @@ -2611,12 +2434,13 @@ resquery_send(resquery_t *query) { struct tried *tried; /* - * If this is the first timeout for this server in this fetch - * context, try setting EDNS UDP buffer size to the largest UDP - * response size we have seen from this server so far. + * If this is the first timeout for this server in this + * fetch context, try setting EDNS UDP buffer size to + * the largest UDP response size we have seen from this + * server so far. * - * If this server has already timed out twice or more in this - * fetch context, force TCP. + * If this server has already timed out twice or more in + * this fetch context, force TCP. */ if ((tried = triededns(fctx, sockaddr)) != NULL) { if (tried->count == 1U) { @@ -2630,8 +2454,8 @@ resquery_send(resquery_t *query) { fctx->timeout = false; /* - * Use EDNS0, unless the caller doesn't want it, or we know that the - * remote server doesn't like it. + * Use EDNS0, unless the caller doesn't want it, or we know that + * the remote server doesn't like it. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { @@ -2645,26 +2469,26 @@ resquery_send(resquery_t *query) { uint16_t padding = 0; /* - * Set the default UDP size to what was configured as - * 'edns-buffer-size' + * Set the default UDP size to what was + * configured as 'edns-buffer-size' */ udpsize = res->udpsize; /* - * This server timed out for the first time in this - * fetch context and we received a response from it - * before (either in this fetch context or in a - * different one). Set 'udpsize' to the size of the - * largest UDP response we have received from this - * server so far. + * This server timed out for the first time in + * this fetch context and we received a response + * from it before (either in this fetch context + * or in a different one). Set 'udpsize' to the + * size of the largest UDP response we have + * received from this server so far. */ if (hint != 0U) { udpsize = hint; } /* - * If a fixed EDNS UDP buffer size is configured for - * this server, make sure we obey that. + * If a fixed EDNS UDP buffer size is configured + * for this server, make sure we obey that. */ if (peer != NULL) { (void)dns_peer_getudpsize(peer, &peerudpsize); @@ -2678,7 +2502,8 @@ resquery_send(resquery_t *query) { version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT; } - /* Request NSID/COOKIE/VERSION for current peer? */ + /* Request NSID/COOKIE/VERSION for current peer? + */ if (peer != NULL) { uint8_t ednsversion; (void)dns_peer_getrequestnsid(peer, &reqnsid); @@ -2738,7 +2563,8 @@ resquery_send(resquery_t *query) { ednsopt++; } - /* Add PAD for current peer? Require TCP for now */ + /* Add PAD for current peer? Require TCP for now + */ if ((peer != NULL) && tcp) { (void)dns_peer_getpadding(peer, &padding); } @@ -2757,9 +2583,9 @@ resquery_send(resquery_t *query) { query->options |= DNS_FETCHOPT_WANTNSID; } else if (result != ISC_R_SUCCESS) { /* - * We couldn't add the OPT, but we'll press on. - * We're not using EDNS0, so set the NOEDNS0 - * bit. + * We couldn't add the OPT, but we'll + * press on. We're not using EDNS0, so + * set the NOEDNS0 bit. */ query->options |= DNS_FETCHOPT_NOEDNS0; query->ednsversion = -1; @@ -2768,8 +2594,8 @@ resquery_send(resquery_t *query) { } else { /* * We know this server doesn't like EDNS0, so we - * won't use it. Set the NOEDNS0 bit since we're - * not using EDNS0. + * won't use it. Set the NOEDNS0 bit since + * we're not using EDNS0. */ query->options |= DNS_FETCHOPT_NOEDNS0; query->ednsversion = -1; @@ -2784,7 +2610,8 @@ resquery_send(resquery_t *query) { query->udpsize = udpsize; /* - * If we need EDNS0 to do this query and aren't using it, we lose. + * If we need EDNS0 to do this query and aren't using it, we + * lose. */ if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) { result = DNS_R_SERVFAIL; @@ -2831,7 +2658,7 @@ resquery_send(resquery_t *query) { memset(&zr, 0, sizeof(zr)); isc_buffer_init(&zb, zone, sizeof(zone)); dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE); - result = dns_name_towire(&fctx->domain, &cctx, &zb); + result = dns_name_towire(fctx->domain, &cctx, &zb); if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(&zb, &zr); } @@ -2850,16 +2677,6 @@ resquery_send(resquery_t *query) { } } - /* - * If using TCP, write the length of the message at the beginning - * of the buffer. - */ - if (tcp) { - isc_buffer_usedregion(&query->buffer, &r); - isc_buffer_putuint16(&tcpbuffer, (uint16_t)r.length); - isc_buffer_add(&tcpbuffer, r.length); - } - /* * Log the outgoing packet. */ @@ -2873,50 +2690,10 @@ resquery_send(resquery_t *query) { */ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); - sock = query2sock(query); + isc_buffer_usedregion(&buffer, &r); - /* - * Send the query! - */ - if (!tcp) { - address = &query->addrinfo->sockaddr; - if (query->exclusivesocket) { - result = isc_socket_connect(sock, address, task, - resquery_udpconnected, - query); - if (result != ISC_R_SUCCESS) { - goto cleanup_message; - } - query->connects++; - } - } - isc_buffer_usedregion(buffer, &r); - - /* - * XXXRTH Make sure we don't send to ourselves! We should probably - * prune out these addresses when we get them from the ADB. - */ - memset(&query->sendevent, 0, sizeof(query->sendevent)); - ISC_EVENT_INIT(&query->sendevent, sizeof(query->sendevent), 0, NULL, - ISC_SOCKEVENT_SENDDONE, resquery_senddone, query, NULL, - NULL, NULL); - - if (query->dscp == -1) { - query->sendevent.attributes &= ~ISC_SOCKEVENTATTR_DSCP; - query->sendevent.dscp = 0; - } else { - query->sendevent.attributes |= ISC_SOCKEVENTATTR_DSCP; - query->sendevent.dscp = query->dscp; - if (tcp) { - isc_socket_dscp(sock, query->dscp); - } - } - - result = isc_socket_sendto2(sock, &r, task, address, NULL, - &query->sendevent, 0); - INSIST(result == ISC_R_SUCCESS); - - query->sends++; + resquery_attach(query, &(resquery_t *){ NULL }); + dns_dispatch_send(query->dispentry, &r, query->dscp); QTRACE("sent"); @@ -2930,13 +2707,13 @@ resquery_send(resquery_t *query) { dtmsgtype = DNS_DTTYPE_RQ; } - result = isc_socket_getsockname(sock, &localaddr); + result = dns_dispentry_getlocaladdress(query->dispentry, &localaddr); if (result == ISC_R_SUCCESS) { la = &localaddr; } dns_dt_send(fctx->res->view, dtmsgtype, la, &query->addrinfo->sockaddr, - tcp, &zr, &query->start, NULL, &query->buffer); + tcp, &zr, &query->start, NULL, &buffer); #endif /* HAVE_DNSTAP */ return (ISC_R_SUCCESS); @@ -2951,7 +2728,7 @@ cleanup_message: /* * Stop the dispatcher from listening. */ - dns_dispatch_removeresponse(&query->dispentry, NULL); + dns_dispatch_removeresponse(&query->dispentry); cleanup_temps: if (qname != NULL) { @@ -2965,156 +2742,108 @@ cleanup_temps: } static void -resquery_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - resquery_t *query = event->ev_arg; - bool retry = false; - isc_interval_t interval; +resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { + resquery_t *query = (resquery_t *)arg; isc_result_t result; - unsigned int attrs; - fetchctx_t *fctx; + fetchctx_t *fctx = NULL; + dns_resolver_t *res = NULL; + int pf; - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_QUERY(query)); QTRACE("connected"); - UNUSED(task); + UNUSED(region); - /* - * XXXRTH - * - * Currently we don't wait for the connect event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ - - query->connects--; fctx = query->fctx; + res = fctx->res; if (RESQUERY_CANCELED(query)) { - /* - * This query was canceled while the connect() was in - * progress. - */ - isc_socket_detach(&query->tcpsocket); - resquery_destroy(&query); - } else { - switch (sevent->result) { - case ISC_R_SUCCESS: - - /* - * Extend the idle timer for TCP. Half of - * "resolver-query-timeout" will hopefully be long - * enough for a TCP connection to be established, a - * single DNS request to be sent, and the response - * received. - */ - isc_interval_set(&interval, - fctx->res->query_timeout / 1000 / 2, - 0); - result = fctx_startidletimer(query->fctx, &interval); - if (result != ISC_R_SUCCESS) { - FCTXTRACE("query canceled: idle timer failed; " - "responding"); - - fctx_cancelquery(&query, NULL, NULL, false, - false); - fctx_done(fctx, result, __LINE__); - break; - } - /* - * We are connected. Create a dispatcher and - * send the query. - */ - attrs = 0; - attrs |= DNS_DISPATCHATTR_TCP; - attrs |= DNS_DISPATCHATTR_PRIVATE; - attrs |= DNS_DISPATCHATTR_CONNECTED; - if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == - AF_INET) { - attrs |= DNS_DISPATCHATTR_IPV4; - } else { - attrs |= DNS_DISPATCHATTR_IPV6; - } - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - - result = dns_dispatch_createtcp( - query->dispatchmgr, query->tcpsocket, - query->fctx->res->taskmgr, NULL, NULL, 4096, 2, - 1, 1, 3, attrs, &query->dispatch); - - /* - * Regardless of whether dns_dispatch_create() - * succeeded or not, we don't need our reference - * to the socket anymore. - */ - isc_socket_detach(&query->tcpsocket); - - if (result == ISC_R_SUCCESS) { - result = resquery_send(query); - } - - if (result != ISC_R_SUCCESS) { - FCTXTRACE("query canceled: " - "resquery_send() failed; responding"); - - fctx_cancelquery(&query, NULL, NULL, false, - false); - fctx_done(fctx, result, __LINE__); - } - break; - - case ISC_R_NETUNREACH: - case ISC_R_HOSTUNREACH: - case ISC_R_CONNREFUSED: - case ISC_R_NOPERM: - case ISC_R_ADDRNOTAVAIL: - case ISC_R_CONNECTIONRESET: - FCTXTRACE3("query canceled in connected(): " - "no route to host; no response", - sevent->result); - - /* - * No route to remote. - */ - isc_socket_detach(&query->tcpsocket); - /* - * Do not query this server again in this fetch context - * if the server is unavailable over TCP. - */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); - fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; - break; - - default: - FCTXTRACE3("query canceled in connected() due to " - "unexpected event result; responding", - sevent->result); - - isc_socket_detach(&query->tcpsocket); - fctx_cancelquery(&query, NULL, NULL, false, false); - break; - } + goto detach; } - isc_event_free(&event); + if (atomic_load_acquire(&fctx->res->exiting)) { + eresult = ISC_R_SHUTTINGDOWN; + } - if (retry) { + switch (eresult) { + case ISC_R_SUCCESS: /* - * Behave as if the idle timer has expired. For TCP - * connections this may not actually reflect the latest timer. + * We are connected. Send the query. */ - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); + + result = resquery_send(query); if (result != ISC_R_SUCCESS) { + FCTXTRACE("query canceled: resquery_send() failed; " + "responding"); + + fctx_cancelquery(query, NULL, false, false); fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); + break; } + + fctx->querysent++; + + pf = isc_sockaddr_pf(&query->addrinfo->sockaddr); + if (pf == PF_INET) { + inc_stats(res, dns_resstatscounter_queryv4); + } else { + inc_stats(res, dns_resstatscounter_queryv6); + } + if (res->view->resquerystats != NULL) { + dns_rdatatypestats_increment(res->view->resquerystats, + fctx->type); + } + break; + + case ISC_R_CANCELED: + break; + + case ISC_R_SHUTTINGDOWN: + FCTXTRACE3("shutdown in resquery_connected(): no response", + eresult); + fctx_cancelquery(query, NULL, true, false); + fctx_done(fctx, eresult, __LINE__); + break; + + case ISC_R_NETUNREACH: + case ISC_R_HOSTUNREACH: + case ISC_R_CONNREFUSED: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + case ISC_R_CONNECTIONRESET: + case ISC_R_TIMEDOUT: + FCTXTRACE3("query canceled in " + "resquery_connected(): " + "no route to host; no response", + eresult); + + /* + * Do not query this server again in this fetch + * context if the server is unavailable over + * TCP. + */ + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); + fctx_cancelquery(query, NULL, true, false); + + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + fctx_try(fctx, true, false); + break; + + default: + FCTXTRACE3("query canceled in " + "resquery_connected() " + "due to unexpected result; responding", + eresult); + + fctx_cancelquery(query, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); + break; } + +detach: + resquery_detach(&query); } static void @@ -3155,9 +2884,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { fctx->findfail++; if (fctx->pending == 0) { /* - * We've got nothing else to wait for and don't - * know the answer. There's nothing to do but - * fail the fctx. + * We've got nothing else to wait for + * and don't know the answer. There's + * nothing to do but fail the fctx. */ FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); want_done = true; @@ -3179,13 +2908,14 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { if (want_try) { fctx_try(fctx, true, false); } else if (want_done) { - FCTXTRACE("fetch failed in finddone(); return ISC_R_FAILURE"); + FCTXTRACE("fetch failed in finddone(); return " + "ISC_R_FAILURE"); fctx_done(fctx, ISC_R_FAILURE, __LINE__); } else if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -3313,8 +3043,8 @@ add_bad(fetchctx_t *fctx, dns_message_t *rmessage, dns_adbaddrinfo_t *addrinfo, break; /* counted as 'valfail' */ case badns_forwarder: /* - * We were called to prevent the given forwarder from - * being used again for this fetch context. + * We were called to prevent the given forwarder + * from being used again for this fetch context. */ break; } @@ -3356,7 +3086,7 @@ add_bad(fetchctx_t *fctx, dns_message_t *rmessage, dns_adbaddrinfo_t *addrinfo, } else { code[0] = '\0'; } - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(address, addrbuf, sizeof(addrbuf)); @@ -3468,7 +3198,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, * and we don't know its address (e.g. because the A record has * expired). */ - if (dns_name_issubdomain(name, &fctx->domain)) { + if (dns_name_issubdomain(name, fctx->domain)) { options |= DNS_ADBFIND_STARTATZONE; } options |= DNS_ADBFIND_GLUEOK; @@ -3480,7 +3210,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, find = NULL; result = dns_adb_createfind( fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone, - fctx, name, &fctx->name, fctx->type, options, now, NULL, + fctx, name, fctx->name, fctx->type, options, now, NULL, res->view->dstport, fctx->depth + 1, fctx->qc, &find); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -3560,9 +3290,11 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, fctx->quotacount++; /* quota exceeded */ } else if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) { - fctx->lamecount++; /* cached lame server */ + fctx->lamecount++; /* cached lame server + */ } else { - fctx->adberr++; /* unreachable server, etc. */ + fctx->adberr++; /* unreachable server, + etc. */ } /* @@ -3640,8 +3372,8 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { /* * If we have DNS_FETCHOPT_NOFORWARD set and forwarding policy * allows us to not forward - skip forwarders and go straight - * to NSes. This is currently used to make sure that priming query - * gets root servers' IP addresses in ADDITIONAL section. + * to NSes. This is currently used to make sure that priming + * query gets root servers' IP addresses in ADDITIONAL section. */ if ((fctx->options & DNS_FETCHOPT_NOFORWARD) != 0 && (fctx->fwdpolicy != dns_fwdpolicy_only)) @@ -3657,7 +3389,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { fwd = ISC_LIST_HEAD(fctx->forwarders); if (fwd == NULL) { dns_forwarders_t *forwarders = NULL; - dns_name_t *name = &fctx->name; + dns_name_t *name = fctx->name; dns_name_t suffix; unsigned int labels; dns_fixedname_t fixed; @@ -3682,12 +3414,10 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { fwd = ISC_LIST_HEAD(forwarders->fwdrs); fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy == dns_fwdpolicy_only && - isstrictsubdomain(domain, &fctx->domain)) + isstrictsubdomain(domain, fctx->domain)) { fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(domain, fctx->mctx, &fctx->domain); + dns_name_copy(domain, fctx->domain); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { return (result); @@ -3726,8 +3456,8 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { } /* - * If the forwarding policy is "only", we don't need the addresses - * of the nameservers. + * If the forwarding policy is "only", we don't need the + * addresses of the nameservers. */ if (fctx->fwdpolicy == dns_fwdpolicy_only) { goto out; @@ -3747,8 +3477,9 @@ normal_nses: * can use. * * We don't want to set this option all the time, since - * if fctx->restarts > 1, we've clearly been having trouble - * with the addresses we had, so getting more could help. + * if fctx->restarts > 1, we've clearly been having + * trouble with the addresses we had, so getting more + * could help. */ stdoptions |= DNS_ADBFIND_AVOIDFETCHES; } @@ -3856,8 +3587,9 @@ out: */ if (fctx->pending > 0) { /* - * We're fetching the addresses, but don't have any - * yet. Tell the caller to wait for an answer. + * We're fetching the addresses, but don't have + * any yet. Tell the caller to wait for an + * answer. */ result = DNS_R_WAIT; } else { @@ -3865,8 +3597,8 @@ out: isc_interval_t i; /* * We've lost completely. We don't know any - * addresses, and the ADB has told us it can't get - * them. + * addresses, and the ADB has told us it can't + * get them. */ FCTXTRACE("no addresses"); isc_interval_set(&i, DNS_RESOLVER_BADCACHETTL(fctx), 0); @@ -3876,7 +3608,7 @@ out: fctx->type == dns_rdatatype_ds) && result == ISC_R_SUCCESS) { - dns_resolver_addbadcache(res, &fctx->name, + dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } @@ -3884,8 +3616,8 @@ out: /* * If all of the addresses found were over the - * fetches-per-server quota, return the configured - * response. + * fetches-per-server quota, return the + * configured response. */ if (all_spilled) { result = res->quotaresp[dns_quotatype_server]; @@ -3894,8 +3626,8 @@ out: } } else { /* - * We've found some addresses. We might still be looking - * for more addresses. + * We've found some addresses. We might still be + * looking for more addresses. */ sort_finds(&fctx->finds, res->view->v6bias); sort_finds(&fctx->altfinds, 0); @@ -4176,7 +3908,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { if (addrinfo == NULL) { /* We have no more addresses. Start over. */ fctx_cancelqueries(fctx, true, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); result = fctx_getaddresses(fctx, badcache); if (result == DNS_R_WAIT) { /* @@ -4216,9 +3948,9 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { if (fctx->minimized && !fctx->forwarding) { unsigned int options = fctx->options; /* - * Also clear DNS_FETCHOPT_TRYSTALE_ONTIMEOUT here, otherwise - * every query minimization step will activate the try-stale - * timer again. + * Also clear DNS_FETCHOPT_TRYSTALE_ONTIMEOUT here, + * otherwise every query minimization step will activate + * the try-stale timer again. */ options &= ~(DNS_FETCHOPT_QMINIMIZE | DNS_FETCHOPT_TRYSTALE_ONTIMEOUT); @@ -4232,7 +3964,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; - dns_name_format(&fctx->qminname, namebuf, + dns_name_format(fctx->qminname, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->qmintype, typebuf, sizeof(typebuf)); @@ -4260,13 +3992,11 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { } fctx_increference(fctx); task = res->buckets[bucketnum].task; - fctx_stoptimer(fctx); - fctx_stoptimer_trystale(fctx); result = dns_resolver_createfetch( - fctx->res, &fctx->qminname, fctx->qmintype, - &fctx->domain, &fctx->nameservers, NULL, NULL, 0, - options, 0, fctx->qc, task, resume_qmin, fctx, - &fctx->qminrrset, NULL, &fctx->qminfetch); + fctx->res, fctx->qminname, fctx->qmintype, fctx->domain, + &fctx->nameservers, NULL, NULL, 0, options, 0, fctx->qc, + task, resume_qmin, fctx, &fctx->qminrrset, NULL, + &fctx->qminfetch); if (result != ISC_R_SUCCESS) { LOCK(&fctx->res->buckets[fctx->bucketnum].lock); RUNTIME_CHECK(!fctx_decreference(fctx)); @@ -4287,7 +4017,6 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { } fctx_increference(fctx); - result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) { fctx_done(fctx, result, __LINE__); @@ -4380,7 +4109,8 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { fctx->qmin_labels = DNS_MAX_LABELS + 1; /* * We store the result. If we succeed in the end - * we'll issue a warning that the server is broken. + * we'll issue a warning that the server is + * broken. */ fctx->qmin_warning = result; } else { @@ -4396,14 +4126,14 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { if (dns_rdatatype_atparent(fctx->type)) { findoptions |= DNS_DBFIND_NOEXACT; } - result = dns_view_findzonecut(res->view, &fctx->name, fname, dcname, + result = dns_view_findzonecut(res->view, fctx->name, fname, dcname, fctx->now, findoptions, true, true, &fctx->nameservers, NULL); /* - * DNS_R_NXDOMAIN here means we have not loaded the root zone mirror - * yet - but DNS_R_NXDOMAIN is not a valid return value when doing - * recursion, we need to patch it. + * DNS_R_NXDOMAIN here means we have not loaded the root zone + * mirror yet - but DNS_R_NXDOMAIN is not a valid return value + * when doing recursion, we need to patch it. */ if (result == DNS_R_NXDOMAIN) { result = DNS_R_SERVFAIL; @@ -4414,9 +4144,8 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { goto cleanup; } fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(fname, fctx->mctx, &fctx->domain); + + dns_name_copy(fname, fctx->domain); result = fcount_incr(fctx, false); if (result != ISC_R_SUCCESS) { @@ -4424,9 +4153,7 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { goto cleanup; } - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname); + dns_name_copy(dcname, fctx->qmindcname); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; @@ -4438,12 +4165,13 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { if (!fctx->minimized) { /* - * We have finished minimizing, but fctx->finds was filled at - * the beginning of the run - now we need to clear it before - * sending the final query to use proper nameservers. + * We have finished minimizing, but fctx->finds was + * filled at the beginning of the run - now we need to + * clear it before sending the final query to use proper + * nameservers. */ fctx_cancelqueries(fctx, false, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); } fctx_try(fctx, true, false); @@ -4544,22 +4272,15 @@ fctx_destroy(fetchctx_t *fctx) { isc_counter_detach(&fctx->qc); fcount_decr(fctx); - isc_timer_detach(&fctx->timer); - if (fctx->timer_try_stale != NULL) { - isc_timer_detach(&fctx->timer_try_stale); - } dns_message_detach(&fctx->qmessage); - if (dns_name_countlabels(&fctx->domain) > 0) { - dns_name_free(&fctx->domain, fctx->mctx); - } if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_free(&fctx->name, fctx->mctx); - dns_name_free(&fctx->qminname, fctx->mctx); - dns_name_free(&fctx->qmindcname, fctx->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); + + dns_resolver_detach(&fctx->res); + isc_mem_free(fctx->mctx, fctx->info); isc_mem_putanddetach(&fctx->mctx, fctx, sizeof(*fctx)); } @@ -4568,118 +4289,13 @@ fctx_destroy(fetchctx_t *fctx) { * Fetch event handlers. */ -static void -fctx_timeout(isc_task_t *task, isc_event_t *event) { - fetchctx_t *fctx = event->ev_arg; - isc_timerevent_t *tevent = (isc_timerevent_t *)event; - resquery_t *query; - - REQUIRE(VALID_FCTX(fctx)); - - UNUSED(task); - - FCTXTRACE("timeout"); - - inc_stats(fctx->res, dns_resstatscounter_querytimeout); - - if (event->ev_type == ISC_TIMEREVENT_LIFE) { - fctx_done(fctx, ISC_R_TIMEDOUT, __LINE__); - } else { - isc_result_t result; - - fctx->timeouts++; - fctx->timeout = true; - - /* - * We could cancel the running queries here, or we could let - * them keep going. Since we normally use separate sockets for - * different queries, we adopt the former approach to reduce - * the number of open sockets: cancel the oldest query if it - * expired after the query had started (this is usually the - * case but is not always so, depending on the task schedule - * timing). - */ - query = ISC_LIST_HEAD(fctx->queries); - if (query != NULL && - isc_time_compare(&tevent->due, &query->start) >= 0) { - FCTXTRACE("query timed out; no response"); - fctx_cancelquery(&query, NULL, NULL, true, false); - } - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - - /* - * Our timer has triggered. Reestablish the fctx lifetime - * timer. - */ - result = fctx_starttimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - /* Keep trying */ - fctx_try(fctx, true, false); - } - } - - isc_event_free(&event); -} - -/* - * Fetch event handlers called if stale answers are enabled - * (stale-answer-enabled) and the fetch took more than - * stale-answer-client-timeout to complete. - */ -static void -fctx_timeout_try_stale(isc_task_t *task, isc_event_t *event) { - fetchctx_t *fctx = event->ev_arg; - dns_fetchevent_t *dns_event, *next_event; - isc_task_t *sender_task; - unsigned int count = 0; - - REQUIRE(VALID_FCTX(fctx)); - - UNUSED(task); - - FCTXTRACE("timeout_try_stale"); - - if (event->ev_type != ISC_TIMEREVENT_LIFE) { - return; - } - - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); - - /* - * Trigger events of type DNS_EVENT_TRYSTALE. - */ - for (dns_event = ISC_LIST_HEAD(fctx->events); dns_event != NULL; - dns_event = next_event) - { - next_event = ISC_LIST_NEXT(dns_event, ev_link); - - if (dns_event->ev_type != DNS_EVENT_TRYSTALE) { - continue; - } - - ISC_LIST_UNLINK(fctx->events, dns_event, ev_link); - sender_task = dns_event->ev_sender; - dns_event->ev_sender = fctx; - dns_event->vresult = ISC_R_TIMEDOUT; - dns_event->result = ISC_R_TIMEDOUT; - - isc_task_sendanddetach(&sender_task, ISC_EVENT_PTR(&dns_event)); - count++; - } - - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - - isc_event_free(&event); -} - static void fctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; /* - * Start the shutdown process for fctx, if it isn't already underway. + * Start the shutdown process for fctx, if it isn't already + * underway. */ FCTXTRACE("shutdown"); @@ -4732,7 +4348,8 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { /* * Cancel all pending validators. Note that this must be done - * without the bucket lock held, since that could cause deadlock. + * without the bucket lock held, since that could cause + * deadlock. */ validator = ISC_LIST_HEAD(fctx->validators); while (validator != NULL) { @@ -4752,11 +4369,14 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { * Shut down anything still running on behalf of this * fetch, and clean up finds and addresses. To avoid deadlock * with the ADB, we must do this before we lock the bucket lock. + * Increment the fctx references to avoid a race. */ - fctx_stopqueries(fctx, false, false); - fctx_cleanupall(fctx); + fctx_increference(fctx); + fctx_cancelqueries(fctx, false, false); + fctx_cleanup(fctx); LOCK(&res->buckets[bucketnum].lock); + fctx_decreference(fctx); FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN); @@ -4780,10 +4400,10 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { UNLOCK(&res->buckets[bucketnum].lock); if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -4809,8 +4429,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { INSIST(fctx->state == fetchstate_init); if (fctx->want_shutdown) { /* - * We haven't started this fctx yet, and we've been requested - * to shut it down. + * We haven't started this fctx yet, and we've been + * requested to shut it down. */ FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN); fctx->state = fetchstate_done; @@ -4836,8 +4456,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { */ fctx->state = fetchstate_active; /* - * Reset the control event for later use in shutting down - * the fctx. + * Reset the control event for later use in shutting + * down the fctx. */ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx, @@ -4847,27 +4467,13 @@ fctx_start(isc_task_t *task, isc_event_t *event) { UNLOCK(&res->buckets[bucketnum].lock); if (!done) { - isc_result_t result; - INSIST(!dodestroy); - - /* - * All is well. Start working on the fetch. - */ - result = fctx_starttimer(fctx); - if (result == ISC_R_SUCCESS && fctx->timer_try_stale != NULL) { - result = fctx_starttimer_trystale(fctx); - } - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, false, false); - } + fctx_try(fctx, false, false); } else if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -4875,26 +4481,21 @@ fctx_start(isc_task_t *task, isc_event_t *event) { * Fetch Creation, Joining, and Cancellation. */ -static inline isc_result_t -fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, - dns_messageid_t id, isc_taskaction_t action, void *arg, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - dns_fetch_t *fetch) { - isc_task_t *tclone; - dns_fetchevent_t *event; - - FCTXTRACE("join"); +static inline void +fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, + dns_messageid_t id, isc_taskaction_t action, void *arg, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_fetch_t *fetch, isc_eventtype_t event_type) { + dns_fetchevent_t *event = NULL; /* * We store the task we're going to send this event to in the - * sender field. We'll make the fetch the sender when we actually - * send the event. + * sender field. We'll make the fetch the sender when we + * actually send the event. */ - tclone = NULL; - isc_task_attach(task, &tclone); + isc_task_attach(task, &(isc_task_t *){ NULL }); event = (dns_fetchevent_t *)isc_event_allocate( - fctx->res->mctx, tclone, DNS_EVENT_FETCHDONE, action, arg, - sizeof(*event)); + fctx->res->mctx, task, event_type, action, arg, sizeof(*event)); event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; @@ -4904,17 +4505,28 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, event->fetch = fetch; event->client = client; event->id = id; - dns_fixedname_init(&event->foundname); + event->foundname = dns_fixedname_initname(&event->fname); /* - * Make sure that we can store the sigrdataset in the - * first event if it is needed by any of the events. + * Store the sigrdataset in the first event in case it is needed + * by any of the events. */ if (event->sigrdataset != NULL) { ISC_LIST_PREPEND(fctx->events, event, ev_link); } else { ISC_LIST_APPEND(fctx->events, event, ev_link); } +} + +static inline isc_result_t +fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, + dns_messageid_t id, isc_taskaction_t action, void *arg, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_fetch_t *fetch) { + FCTXTRACE("join"); + + fctx_add_event(fctx, task, client, id, action, arg, rdataset, + sigrdataset, fetch, DNS_EVENT_FETCHDONE); fctx_increference(fctx); @@ -4924,41 +4536,13 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, return (ISC_R_SUCCESS); } -static inline void -fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, - dns_messageid_t id, isc_taskaction_t action, void *arg, - dns_fetch_t *fetch, isc_eventtype_t event_type) { - isc_task_t *tclone; - dns_fetchevent_t *event; - /* - * We store the task we're going to send this event to in the - * sender field. We'll make the fetch the sender when we actually - * send the event. - */ - tclone = NULL; - isc_task_attach(task, &tclone); - event = (dns_fetchevent_t *)isc_event_allocate(fctx->res->mctx, tclone, - event_type, action, arg, - sizeof(*event)); - event->result = DNS_R_SERVFAIL; - event->qtype = fctx->type; - event->db = NULL; - event->node = NULL; - event->rdataset = NULL; - event->sigrdataset = NULL; - event->fetch = fetch; - event->client = client; - event->id = id; - ISC_LIST_APPEND(fctx->events, event, ev_link); -} - static inline void log_ns_ttl(fetchctx_t *fctx, const char *where) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), "log_ns_ttl: fctx %p: %s: %s (in '%s'?): %u %u", fctx, @@ -4966,30 +4550,45 @@ log_ns_ttl(fetchctx_t *fctx, const char *where) { } static isc_result_t -fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, - const dns_name_t *domain, dns_rdataset_t *nameservers, - const isc_sockaddr_t *client, unsigned int options, - unsigned int bucketnum, unsigned int depth, isc_counter_t *qc, - fetchctx_t **fctxp) { - fetchctx_t *fctx; +fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, + dns_rdatatype_t type, const dns_name_t *domain, + dns_rdataset_t *nameservers, const isc_sockaddr_t *client, + unsigned int options, unsigned int bucketnum, unsigned int depth, + isc_counter_t *qc, fetchctx_t **fctxp) { + fetchctx_t *fctx = NULL; isc_result_t result; isc_result_t iresult; isc_interval_t interval; unsigned int findoptions = 0; char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1]; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; size_t p; - bool try_stale; /* - * Caller must be holding the lock for bucket number 'bucketnum'. + * Caller must be holding the lock for bucket number + * 'bucketnum'. */ REQUIRE(fctxp != NULL && *fctxp == NULL); mctx = res->buckets[bucketnum].mctx; fctx = isc_mem_get(mctx, sizeof(*fctx)); + *fctx = (fetchctx_t){ + .type = type, + .qmintype = type, + .options = options, + .task = task, + .bucketnum = bucketnum, + .dbucketnum = RES_NOBUCKET, + .state = fetchstate_init, + .depth = depth, + .qmin_labels = 1, + .fwdpolicy = dns_fwdpolicy_none, + .result = ISC_R_FAILURE, + .exitline = -1, /* sentinel */ + }; + + dns_resolver_attach(res, &fctx->res); - fctx->qc = NULL; if (qc != NULL) { isc_counter_attach(qc, &fctx->qc); } else { @@ -5002,7 +4601,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, /* * Make fctx->info point to a copy of a formatted string - * "name/type". + * "name/type". FCTXTRACE won't work until this is done. */ dns_name_format(name, buf, sizeof(buf)); p = strlcat(buf, "/", sizeof(buf)); @@ -5011,96 +4610,52 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, fctx->info = isc_mem_strdup(mctx, buf); FCTXTRACE("create"); - dns_name_init(&fctx->name, NULL); - dns_name_dup(name, mctx, &fctx->name); - dns_name_init(&fctx->qminname, NULL); - dns_name_dup(name, mctx, &fctx->qminname); - dns_name_init(&fctx->domain, NULL); - dns_rdataset_init(&fctx->nameservers); - fctx->type = type; - fctx->qmintype = type; - fctx->options = options; - /* - * Note! We do not attach to the task. We are relying on the - * resolver to ensure that this task doesn't go away while we are - * using it. - */ - fctx->res = res; isc_refcount_init(&fctx->references, 0); - fctx->bucketnum = bucketnum; - fctx->dbucketnum = RES_NOBUCKET; - fctx->state = fetchstate_init; - fctx->want_shutdown = false; - fctx->cloned = false; - fctx->depth = depth; - fctx->minimized = false; - fctx->ip6arpaskip = false; - fctx->forwarding = false; - fctx->qmin_labels = 1; - fctx->qmin_warning = ISC_R_SUCCESS; - fctx->qminfetch = NULL; - dns_rdataset_init(&fctx->qminrrset); - dns_name_init(&fctx->qmindcname, NULL); - isc_stdtime_get(&fctx->now); + ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->finds); ISC_LIST_INIT(fctx->altfinds); ISC_LIST_INIT(fctx->forwaddrs); ISC_LIST_INIT(fctx->altaddrs); ISC_LIST_INIT(fctx->forwarders); - fctx->fwdpolicy = dns_fwdpolicy_none; ISC_LIST_INIT(fctx->bad); ISC_LIST_INIT(fctx->edns); ISC_LIST_INIT(fctx->bad_edns); ISC_LIST_INIT(fctx->validators); - fctx->validator = NULL; - fctx->find = NULL; - fctx->altfind = NULL; - fctx->pending = 0; - fctx->restarts = 0; - fctx->querysent = 0; - fctx->referrals = 0; - TIME_NOW(&fctx->start); - fctx->timeouts = 0; - fctx->lamecount = 0; - fctx->quotacount = 0; - fctx->adberr = 0; - fctx->neterr = 0; - fctx->badresp = 0; - fctx->findfail = 0; - fctx->valfail = 0; - fctx->result = ISC_R_FAILURE; - fctx->vresult = ISC_R_SUCCESS; - fctx->exitline = -1; /* sentinel */ - fctx->logged = false; + atomic_init(&fctx->attributes, 0); - fctx->spilled = false; - fctx->nqueries = 0; - fctx->rand_buf = 0; - fctx->rand_bits = 0; - fctx->timeout = false; - fctx->addrinfo = NULL; + + fctx->name = dns_fixedname_initname(&fctx->fname); + fctx->nsname = dns_fixedname_initname(&fctx->nsfname); + fctx->domain = dns_fixedname_initname(&fctx->dfname); + fctx->qminname = dns_fixedname_initname(&fctx->qminfname); + fctx->qmindcname = dns_fixedname_initname(&fctx->qmindcfname); + + dns_name_copy(name, fctx->name); + dns_name_copy(name, fctx->qminname); + + dns_rdataset_init(&fctx->nameservers); + dns_rdataset_init(&fctx->qminrrset); + dns_rdataset_init(&fctx->nsrrset); + + TIME_NOW(&fctx->start); + fctx->now = (isc_stdtime_t)fctx->start.seconds; + if (client != NULL) { isc_sockaddr_format(client, fctx->clientstr, sizeof(fctx->clientstr)); } else { strlcpy(fctx->clientstr, "", sizeof(fctx->clientstr)); } - fctx->ns_ttl = 0; - fctx->ns_ttl_ok = false; - - dns_name_init(&fctx->nsname, NULL); - fctx->nsfetch = NULL; - dns_rdataset_init(&fctx->nsrrset); if (domain == NULL) { dns_forwarders_t *forwarders = NULL; dns_fixedname_t fixed; + dns_name_t *fname = dns_fixedname_initname(&fixed); unsigned int labels; const dns_name_t *fwdname = name; dns_name_t suffix; - dns_name_t *fname; /* * DS records are found in the parent server. Strip one @@ -5116,7 +4671,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, } /* Find the forwarder for this name. */ - fname = dns_fixedname_initname(&fixed); result = dns_fwdtable_find(fctx->res->view->fwdtable, fwdname, fname, &forwarders); if (result == ISC_R_SUCCESS) { @@ -5125,12 +4679,12 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, if (fctx->fwdpolicy != dns_fwdpolicy_only) { dns_fixedname_t dcfixed; - dns_name_t *dcname; - dcname = dns_fixedname_initname(&dcfixed); + dns_name_t *dcname = dns_fixedname_initname(&dcfixed); + /* * The caller didn't supply a query domain and - * nameservers, and we're not in forward-only mode, - * so find the best nameservers to use. + * nameservers, and we're not in forward-only + * mode, so find the best nameservers to use. */ if (dns_rdatatype_atparent(fctx->type)) { findoptions |= DNS_DBFIND_NOEXACT; @@ -5143,24 +4697,25 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_nameservers; } - dns_name_dup(fname, mctx, &fctx->domain); - dns_name_dup(dcname, mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(dcname, fctx->qmindcname); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; } else { /* - * We're in forward-only mode. Set the query domain. + * We're in forward-only mode. Set the query + * domain. */ - dns_name_dup(fname, mctx, &fctx->domain); - dns_name_dup(fname, mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(fname, fctx->qmindcname); /* * Disable query minimization */ options &= ~DNS_FETCHOPT_QMINIMIZE; } } else { - dns_name_dup(domain, mctx, &fctx->domain); - dns_name_dup(domain, mctx, &fctx->qmindcname); + dns_name_copy(domain, fctx->domain); + dns_name_copy(domain, fctx->qmindcname); dns_rdataset_clone(nameservers, &fctx->nameservers); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; @@ -5173,13 +4728,13 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, if (result != ISC_R_SUCCESS) { result = fctx->res->quotaresp[dns_quotatype_zone]; inc_stats(res, dns_resstatscounter_zonequota); - goto cleanup_domain; + goto cleanup_nameservers; } log_ns_ttl(fctx, "fctx_create"); - if (!dns_name_issubdomain(&fctx->name, &fctx->domain)) { - dns_name_format(&fctx->domain, buf, sizeof(buf)); + if (!dns_name_issubdomain(fctx->name, fctx->domain)) { + dns_name_format(fctx->domain, buf, sizeof(buf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "'%s' is not subdomain of '%s'", fctx->info, buf); @@ -5187,7 +4742,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_fcount; } - fctx->qmessage = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &fctx->qmessage); /* @@ -5204,15 +4758,21 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_qmessage; } - try_stale = ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0); - if (try_stale) { + /* + * Default retry interval initialization. We set the interval + * now mostly so it won't be uninitialized. It will be set to + * the correct value before a query is issued. + */ + isc_interval_set(&fctx->interval, 2, 0); + + /* + * If stale answers are enabled, compute an expiration time + * after which stale data will be served, if the target RRset is + * available in cache. + */ + if ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0) { INSIST(res->view->staleanswerclienttimeout <= (res->query_timeout - 1000)); - /* - * Compute an expiration time after which stale data will - * attempted to be served, if stale answers are enabled and - * target RRset is available in cache. - */ isc_interval_set( &interval, res->view->staleanswerclienttimeout / 1000, res->view->staleanswerclienttimeout % 1000 * 1000000); @@ -5227,57 +4787,11 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, } } - /* - * Default retry interval initialization. We set the interval now - * mostly so it won't be uninitialized. It will be set to the - * correct value before a query is issued. - */ - isc_interval_set(&fctx->interval, 2, 0); - - /* - * Create an inactive timer for resolver-query-timeout. It - * will be made active when the fetch is actually started. - */ - fctx->timer = NULL; - - iresult = isc_timer_create(res->timermgr, isc_timertype_inactive, NULL, - NULL, res->buckets[bucketnum].task, - fctx_timeout, fctx, &fctx->timer); - if (iresult != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_create: %s", - isc_result_totext(iresult)); - result = ISC_R_UNEXPECTED; - goto cleanup_qmessage; - } - - /* - * If stale answers are enabled, then create an inactive timer - * for stale-answer-client-timeout. It will be made active when - * the fetch is actually started. - */ - fctx->timer_try_stale = NULL; - if (try_stale) { - iresult = isc_timer_create( - res->timermgr, isc_timertype_inactive, NULL, NULL, - res->buckets[bucketnum].task, fctx_timeout_try_stale, - fctx, &fctx->timer_try_stale); - if (iresult != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_timer_create: %s", - isc_result_totext(iresult)); - result = ISC_R_UNEXPECTED; - goto cleanup_qmessage; - } - } - /* * Attach to the view's cache and adb. */ - fctx->cache = NULL; dns_db_attach(res->view->cachedb, &fctx->cache); - fctx->adb = NULL; dns_adb_attach(res->view->adb, &fctx->adb); - fctx->mctx = NULL; isc_mem_attach(mctx, &fctx->mctx); ISC_LIST_INIT(fctx->events); @@ -5289,9 +4803,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, * the name in fctx to proper length. */ if ((options & DNS_FETCHOPT_QMINIMIZE) != 0) { - fctx->ip6arpaskip = - (options & DNS_FETCHOPT_QMIN_SKIP_IP6A) != 0 && - dns_name_issubdomain(&fctx->name, &ip6_arpa); + fctx->ip6arpaskip = (options & DNS_FETCHOPT_QMIN_SKIP_IP6A) != + 0 && + dns_name_issubdomain(fctx->name, &ip6_arpa); result = fctx_minimize_qname(fctx); if (result != ISC_R_SUCCESS) { goto cleanup_mctx; @@ -5313,8 +4827,6 @@ cleanup_mctx: isc_mem_detach(&fctx->mctx); dns_adb_detach(&fctx->adb); dns_db_detach(&fctx->cache); - isc_timer_detach(&fctx->timer); - isc_timer_detach(&fctx->timer_try_stale); cleanup_qmessage: dns_message_detach(&fctx->qmessage); @@ -5322,24 +4834,15 @@ cleanup_qmessage: cleanup_fcount: fcount_decr(fctx); -cleanup_domain: - if (dns_name_countlabels(&fctx->domain) > 0) { - dns_name_free(&fctx->domain, mctx); - } - if (dns_name_countlabels(&fctx->qmindcname) > 0) { - dns_name_free(&fctx->qmindcname, mctx); - } - cleanup_nameservers: if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_free(&fctx->name, mctx); - dns_name_free(&fctx->qminname, mctx); isc_mem_free(mctx, fctx->info); isc_counter_detach(&fctx->qc); cleanup_fetch: + dns_resolver_detach(&fctx->res); isc_mem_put(mctx, fctx, sizeof(*fctx)); return (result); @@ -5382,7 +4885,7 @@ is_lame(fetchctx_t *fctx, dns_message_t *message) { if (rdataset->type != dns_rdatatype_ns) { continue; } - namereln = dns_name_fullcompare(name, &fctx->domain, + namereln = dns_name_fullcompare(name, fctx->domain, &order, &labels); if (namereln == dns_namereln_equal && (message->flags & DNS_MESSAGEFLAG_AA) != 0) @@ -5406,8 +4909,8 @@ log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) { char domainbuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -5436,8 +4939,8 @@ log_formerr(fetchctx_t *fctx, const char *format, ...) { static isc_result_t same_question(fetchctx_t *fctx, dns_message_t *message) { isc_result_t result; - dns_name_t *name; - dns_rdataset_t *rdataset; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; /* * Caller must be holding the fctx lock. @@ -5479,7 +4982,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { if (result != ISC_R_SUCCESS) { return (result); } - name = NULL; + dns_message_currentname(message, DNS_SECTION_QUESTION, &name); rdataset = ISC_LIST_HEAD(name->list); INSIST(rdataset != NULL); @@ -5487,7 +4990,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { if (fctx->type != rdataset->type || fctx->res->rdclass != rdataset->rdclass || - !dns_name_equal(&fctx->name, name)) + !dns_name_equal(fctx->name, name)) { char namebuf[DNS_NAME_FORMATSIZE]; char classbuf[DNS_RDATACLASS_FORMATSIZE]; @@ -5507,8 +5010,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { static void clone_results(fetchctx_t *fctx) { - dns_fetchevent_t *event, *hevent; - dns_name_t *name, *hname; + dns_fetchevent_t *event = NULL, *hevent = NULL; FCTXTRACE("clone_results"); @@ -5520,41 +5022,47 @@ clone_results(fetchctx_t *fctx) { */ fctx->cloned = true; - hevent = ISC_LIST_HEAD(fctx->events); - if (hevent == NULL) { - return; - } - hname = dns_fixedname_name(&hevent->foundname); - for (event = ISC_LIST_NEXT(hevent, ev_link); event != NULL; + + for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = ISC_LIST_NEXT(event, ev_link)) { + /* This is the the head event; keep a pointer and move + * on */ + if (hevent == NULL) { + hevent = ISC_LIST_HEAD(fctx->events); + continue; + } + if (event->ev_type == DNS_EVENT_TRYSTALE) { /* * We don't need to clone resulting data to this - * type of event, as its associated callback is only - * called when stale-answer-client-timeout triggers, - * and the logic in there doesn't expect any result - * as input, as it will itself lookup for stale data - * in cache to use as result, if any is available. + * type of event, as its associated callback is + * only called when stale-answer-client-timeout + * triggers, and the logic in there doesn't + * expect any result as input, as it will itself + * lookup for stale data in cache to use as + * result, if any is available. * - * Also, if we reached this point, then the whole fetch - * context is done, it will cancel timers, process - * associated callbacks of type DNS_EVENT_FETCHDONE, and - * silently remove/free events of type - * DNS_EVENT_TRYSTALE. + * Also, if we reached this point, then the + * whole fetch context is done, it will cancel + * timers, process associated callbacks of type + * DNS_EVENT_FETCHDONE, and silently remove/free + * events of type DNS_EVENT_TRYSTALE. */ continue; } - name = dns_fixedname_name(&event->foundname); - dns_name_copy(hname, name); + event->result = hevent->result; + dns_name_copy(hevent->foundname, event->foundname); dns_db_attach(hevent->db, &event->db); dns_db_attachnode(hevent->db, hevent->node, &event->node); + INSIST(hevent->rdataset != NULL); INSIST(event->rdataset != NULL); if (dns_rdataset_isassociated(hevent->rdataset)) { dns_rdataset_clone(hevent->rdataset, event->rdataset); } + INSIST(!(hevent->sigrdataset == NULL && event->sigrdataset != NULL)); if (hevent->sigrdataset != NULL && @@ -5583,7 +5091,8 @@ clone_results(fetchctx_t *fctx) { * '*fctx' is shutting down. * * Returns: - * true if the resolver is exiting and this is the last fctx in the bucket. + * true if the resolver is exiting and this is the last fctx in the + *bucket. */ static bool maybe_destroy(fetchctx_t *fctx, bool locked) { @@ -5702,8 +5211,8 @@ validated(isc_task_t *task, isc_event_t *event) { /* * If shutting down, ignore the results. Check to see if we're - * done waiting for validator completions and ADB pending events; if - * so, destroy the fctx. + * done waiting for validator completions and ADB pending + * events; if so, destroy the fctx. */ if (SHUTTINGDOWN(fctx) && !sentresponse) { bool bucket_empty; @@ -5718,8 +5227,8 @@ validated(isc_task_t *task, isc_event_t *event) { isc_stdtime_get(&now); /* - * If chaining, we need to make sure that the right result code is - * returned, and that the rdatasets are bound. + * If chaining, we need to make sure that the right result code + * is returned, and that the rdatasets are bound. */ if (vevent->result == ISC_R_SUCCESS && !negative && vevent->rdataset != NULL && CHAINING(vevent->rdataset)) @@ -5736,9 +5245,9 @@ validated(isc_task_t *task, isc_event_t *event) { } /* - * Either we're not shutting down, or we are shutting down but want - * to cache the result anyway (if this was a validation started by - * a query with cd set) + * Either we're not shutting down, or we are shutting down but + * want to cache the result anyway (if this was a validation + * started by a query with cd set) */ hevent = ISC_LIST_HEAD(fctx->events); @@ -5786,7 +5295,8 @@ validated(isc_task_t *task, isc_event_t *event) { } if (fctx->vresult == DNS_R_BROKENCHAIN && !negative) { /* - * Cache the data as pending for later validation. + * Cache the data as pending for later + * validation. */ result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) { @@ -5817,7 +5327,7 @@ validated(isc_task_t *task, isc_event_t *event) { if (fctx->validator != NULL) { dns_validator_send(fctx->validator); } else if (sentresponse) { - fctx_done(fctx, result, __LINE__); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket */ } else if (result == DNS_R_BROKENCHAIN) { isc_result_t tresult; isc_time_t expire; @@ -5830,12 +5340,12 @@ validated(isc_task_t *task, isc_event_t *event) { fctx->type == dns_rdatatype_ds) && tresult == ISC_R_SUCCESS) { - dns_resolver_addbadcache(res, &fctx->name, + dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } - fctx_done(fctx, result, __LINE__); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket */ } else { - fctx_try(fctx, true, true); /* Locks bucket. */ + fctx_try(fctx, true, true); /* Locks bucket */ } dns_message_detach(&message); @@ -5955,8 +5465,8 @@ validated(isc_task_t *task, isc_event_t *event) { if (sentresponse) { bool bucket_empty = false; /* - * If we only deferred the destroy because we wanted to cache - * the data, destroy now. + * If we only deferred the destroy because we wanted to + * cache the data, destroy now. */ dns_db_detachnode(fctx->cache, &node); if (SHUTTINGDOWN(fctx)) { @@ -6086,9 +5596,9 @@ answer_response: INSIST(eresult == DNS_R_NCACHENXDOMAIN || eresult == DNS_R_NCACHENXRRSET); } + hevent->result = eresult; - dns_name_copy(vevent->name, - dns_fixedname_name(&hevent->foundname)); + dns_name_copy(vevent->name, hevent->foundname); dns_db_attach(fctx->cache, &hevent->db); dns_db_transfernode(fctx->cache, &node, &hevent->node); clone_results(fctx); @@ -6264,7 +5774,6 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; dns_dbnode_t *node = NULL, **anodep = NULL; dns_db_t **adbp = NULL; - dns_name_t *aname = NULL; dns_resolver_t *res = fctx->res; bool need_validation = false; bool secure_domain = false; @@ -6317,15 +5826,16 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, if (event != NULL) { adbp = &event->db; - aname = dns_fixedname_name(&event->foundname); - dns_name_copy(name, aname); + dns_name_copy(name, event->foundname); anodep = &event->node; + /* - * If this is an ANY, SIG or RRSIG query, we're not - * going to return any rdatasets, unless we encountered - * a CNAME or DNAME as "the answer". In this case, - * we're going to return DNS_R_CNAME or DNS_R_DNAME - * and we must set up the rdatasets. + * If this is an ANY, SIG or RRSIG query, we're + * not going to return any rdatasets, unless we + * encountered a CNAME or DNAME as "the answer". + * In this case, we're going to return + * DNS_R_CNAME or DNS_R_DNAME and we must set up + * the rdatasets. */ if ((fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_rrsig && @@ -6418,21 +5928,21 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, /* * If this RRset is in a secure domain, is in bailiwick, - * and is not glue, attempt DNSSEC validation. (We do not - * attempt to validate glue or out-of-bailiwick data--even - * though there might be some performance benefit to doing - * so--because it makes it simpler and safer to ensure that - * records from a secure domain are only cached if validated - * within the context of a query to the domain that owns - * them.) + * and is not glue, attempt DNSSEC validation. (We do + * not attempt to validate glue or out-of-bailiwick + * data--even though there might be some performance + * benefit to doing so--because it makes it simpler and + * safer to ensure that records from a secure domain are + * only cached if validated within the context of a + * query to the domain that owns them.) */ if (secure_domain && rdataset->trust != dns_trust_glue && !EXTERNAL(rdataset)) { dns_trust_t trust; /* - * RRSIGs are validated as part of validating the - * type they cover. + * RRSIGs are validated as part of validating + * the type they cover. */ if (rdataset->type == dns_rdatatype_rrsig) { continue; @@ -6442,7 +5952,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, !ANSWER(rdataset)) { /* * Ignore unrelated non-answer - * rdatasets that are missing signatures. + * rdatasets that are missing + * signatures. */ continue; } @@ -6467,9 +5978,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, /* * Cache this rdataset/sigrdataset pair as - * pending data. Track whether it was additional - * or not. If this was a priming query, additional - * should be cached as glue. + * pending data. Track whether it was + * additional or not. If this was a priming + * query, additional should be cached as glue. */ if (rdataset->trust == dns_trust_additional) { trust = dns_trust_pending_additional; @@ -6514,11 +6025,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, ardataset != NULL && NEGATIVE(ardataset)) { /* - * The answer in the cache is - * better than the answer we - * found, and is a negative - * cache entry, so we must set - * eresult appropriately. + * The answer in the + * cache is better than + * the answer we found, + * and is a negative + * cache entry, so we + * must set eresult + * appropriately. */ if (NXDOMAIN(ardataset)) { eresult = @@ -6528,10 +6041,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, DNS_R_NCACHENXRRSET; } /* - * We have a negative response - * from the cache so don't - * attempt to add the RRSIG - * rrset. + * We have a negative + * response from the + * cache so don't + * attempt to add the + * RRSIG rrset. */ continue; } @@ -6563,9 +6077,10 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, { /* * This is The Answer. We will - * validate it, but first we cache - * the rest of the response - it may - * contain useful keys. + * validate it, but first we + * cache the rest of the + * response - it may contain + * useful keys. */ INSIST(valrdataset == NULL && valsigrdataset == NULL); @@ -6622,10 +6137,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, rdataset->covers == dns_rdatatype_ns))) { /* - * If the trust level is 'dns_trust_glue' - * then we are adding data from a referral - * we got while executing the search algorithm. - * New referral data always takes precedence + * If the trust level is + * 'dns_trust_glue' then we are adding + * data from a referral we got while + * executing the search algorithm. New + * referral data always takes precedence * over the existing cache contents. */ options = DNS_DBADD_FORCE; @@ -6660,10 +6176,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, if (ANSWER(rdataset) && ardataset != NULL && NEGATIVE(ardataset)) { /* - * The answer in the cache is better - * than the answer we found, and is - * a negative cache entry, so we - * must set eresult appropriately. + * The answer in the cache is + * better than the answer we + * found, and is a negative + * cache entry, so we must set + * eresult appropriately. */ if (NXDOMAIN(ardataset)) { eresult = DNS_R_NCACHENXDOMAIN; @@ -6697,7 +6214,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); if (event != NULL) { /* - * Negative results must be indicated in event->result. + * Negative results must be indicated in + * event->result. */ if (dns_rdataset_isassociated(event->rdataset) && NEGATIVE(event->rdataset)) { @@ -6766,7 +6284,8 @@ cache_message(fetchctx_t *fctx, dns_message_t *message, } /* - * Do what dns_ncache_addoptout() does, and then compute an appropriate eresult. + * Do what dns_ncache_addoptout() does, and then compute an appropriate + * eresult. */ static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, @@ -6806,10 +6325,10 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, } else { /* * Either we don't care about the nature of the - * cache rdataset (because no fetch is interested - * in the outcome), or the cache rdataset is not - * a negative cache entry. Whichever case it is, - * we can return success. + * cache rdataset (because no fetch is + * interested in the outcome), or the cache + * rdataset is not a negative cache entry. + * Whichever case it is, we can return success. * * XXXRTH There's a CNAME/DNAME problem here. */ @@ -6828,15 +6347,14 @@ static inline isc_result_t ncache_message(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo, dns_rdatatype_t covers, isc_stdtime_t now) { - isc_result_t result, eresult; - dns_name_t *name; - dns_resolver_t *res; - dns_db_t **adbp; - dns_dbnode_t *node, **anodep; - dns_rdataset_t *ardataset; - bool need_validation, secure_domain; - dns_name_t *aname; - dns_fetchevent_t *event; + isc_result_t result, eresult = ISC_R_SUCCESS; + dns_name_t *name = fctx->name; + dns_resolver_t *res = fctx->res; + dns_db_t **adbp = NULL; + dns_dbnode_t *node = NULL, **anodep = NULL; + dns_rdataset_t *ardataset = NULL; + bool need_validation = false, secure_domain = false; + dns_fetchevent_t *event = NULL; uint32_t ttl; unsigned int valoptions = 0; bool checknta = true; @@ -6845,13 +6363,7 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTNCACHE); - res = fctx->res; - need_validation = false; POST(need_validation); - secure_domain = false; - eresult = ISC_R_SUCCESS; - name = &fctx->name; - node = NULL; /* * XXXMPA remove when we follow cnames and adjust the setting @@ -6889,12 +6401,11 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, /* * Mark all rdatasets as pending. */ - dns_rdataset_t *trdataset; - dns_name_t *tname; - result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { - tname = NULL; + dns_rdataset_t *trdataset = NULL; + dns_name_t *tname = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &tname); for (trdataset = ISC_LIST_HEAD(tname->list); @@ -6919,30 +6430,23 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, NULL, NULL, valoptions, res->buckets[fctx->bucketnum].task); /* - * If validation is necessary, return now. Otherwise continue - * to process the message, letting the validation complete - * in its own good time. + * If validation is necessary, return now. Otherwise + * continue to process the message, letting the + * validation complete in its own good time. */ return (result); } LOCK(&res->buckets[fctx->bucketnum].lock); - adbp = NULL; - aname = NULL; - anodep = NULL; - ardataset = NULL; if (!HAVE_ANSWER(fctx)) { event = ISC_LIST_HEAD(fctx->events); if (event != NULL) { adbp = &event->db; - aname = dns_fixedname_name(&event->foundname); - dns_name_copy(name, aname); + dns_name_copy(name, event->foundname); anodep = &event->node; ardataset = event->rdataset; } - } else { - event = NULL; } result = dns_db_findnode(fctx->cache, name, true, &node); @@ -7045,12 +6549,12 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type, #endif /* if CHECK_FOR_GLUE_IN_ANSWER */ gluing = (GLUING(fctx) || (fctx->type == dns_rdatatype_ns && - dns_name_equal(&fctx->name, dns_rootname))); + dns_name_equal(fctx->name, dns_rootname))); result = dns_message_findname(rctx->query->rmessage, section, addname, dns_rdatatype_any, 0, &name, NULL); if (result == ISC_R_SUCCESS) { - external = !dns_name_issubdomain(name, &fctx->domain); + external = !dns_name_issubdomain(name, fctx->domain); if (type == dns_rdatatype_a) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -7131,8 +6635,8 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, } /* - * If the owner name matches one in the exclusion list, either exactly - * or partially, allow it. + * If the owner name matches one in the exclusion list, either + * exactly or partially, allow it. */ if (view->answeracl_exclude != NULL) { dns_rbtnode_t *node = NULL; @@ -7146,9 +6650,9 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, } /* - * Otherwise, search the filter list for a match for each address - * record. If a match is found, the address should be filtered, - * so should the entire answer. + * Otherwise, search the filter list for a match for each + * address record. If a match is found, the address should be + * filtered, so should the entire answer. */ for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) @@ -7261,8 +6765,8 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, } /* - * If the owner name matches one in the exclusion list, either exactly - * or partially, allow it. + * If the owner name matches one in the exclusion list, either + * exactly or partially, allow it. */ if (view->answernames_exclude != NULL) { result = dns_rbt_findnode(view->answernames_exclude, qname, @@ -7273,14 +6777,15 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, } /* - * If the target name is a subdomain of the search domain, allow it. + * If the target name is a subdomain of the search domain, allow + * it. * - * Note that if BIND is configured as a forwarding DNS server, the - * search domain will always match the root domain ("."), so we - * must also check whether forwarding is enabled so that filters - * can be applied; see GL #1574. + * Note that if BIND is configured as a forwarding DNS server, + * the search domain will always match the root domain ("."), so + * we must also check whether forwarding is enabled so that + * filters can be applied; see GL #1574. */ - if (!fctx->forwarding && dns_name_issubdomain(tname, &fctx->domain)) { + if (!fctx->forwarding && dns_name_issubdomain(tname, fctx->domain)) { return (true); } @@ -7313,7 +6818,7 @@ trim_ns_ttl(fetchctx_t *fctx, dns_name_t *name, dns_rdataset_t *rdataset) { if (fctx->ns_ttl_ok && rdataset->ttl > fctx->ns_ttl) { dns_name_format(name, ns_namebuf, sizeof(ns_namebuf)); - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -7372,6 +6877,8 @@ fctx_decreference(fetchctx_t *fctx) { * No one cares about the result of this fetch anymore. */ if (fctx->pending == 0 && fctx->nqueries == 0 && + ISC_LIST_EMPTY(fctx->finds) && + ISC_LIST_EMPTY(fctx->altfinds) && ISC_LIST_EMPTY(fctx->validators) && SHUTTINGDOWN(fctx)) { /* @@ -7454,9 +6961,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(&fctx->nsname, fctx->mctx, &fctx->domain); + dns_name_copy(fctx->nsname, fctx->domain); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); @@ -7471,11 +6976,12 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { dns_rdataset_t *nsrdataset = NULL; /* - * Retrieve state from fctx->nsfetch before we destroy it. + * Retrieve state from fctx->nsfetch before we destroy + * it. */ domain = dns_fixedname_initname(&fixed); - dns_name_copy(&fctx->nsfetch->private->domain, domain); - if (dns_name_equal(&fctx->nsname, domain)) { + dns_name_copy(fctx->nsfetch->private->domain, domain); + if (dns_name_equal(fctx->nsname, domain)) { if (dns_rdataset_isassociated(fevent->rdataset)) { dns_rdataset_disassociate(fevent->rdataset); } @@ -7495,9 +7001,8 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { domain = NULL; } dns_resolver_destroyfetch(&fctx->nsfetch); - n = dns_name_countlabels(&fctx->nsname); - dns_name_getlabelsequence(&fctx->nsname, 1, n - 1, - &fctx->nsname); + n = dns_name_countlabels(fctx->nsname); + dns_name_getlabelsequence(fctx->nsname, 1, n - 1, fctx->nsname); if (dns_rdataset_isassociated(fevent->rdataset)) { dns_rdataset_disassociate(fevent->rdataset); @@ -7508,7 +7013,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { FCTXTRACE("continuing to look for parent's NS records"); result = dns_resolver_createfetch( - fctx->res, &fctx->nsname, dns_rdatatype_ns, domain, + fctx->res, fctx->nsname, dns_rdatatype_ns, domain, nsrdataset, NULL, NULL, 0, fctx->options, 0, NULL, task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); @@ -7651,7 +7156,7 @@ betterreferral(respctx_t *rctx) { name = NULL; dns_message_currentname(rctx->query->rmessage, DNS_SECTION_AUTHORITY, &name); - if (!isstrictsubdomain(name, &rctx->fctx->domain)) { + if (!isstrictsubdomain(name, rctx->fctx->domain)) { continue; } for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -7671,40 +7176,54 @@ betterreferral(respctx_t *rctx) { * resquery_send(). Sets up a response context (respctx_t). */ static void -resquery_response(isc_task_t *task, isc_event_t *event) { - isc_result_t result = ISC_R_SUCCESS; - resquery_t *query = event->ev_arg; - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - fetchctx_t *fctx; +resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) { + isc_result_t result; + resquery_t *query = (resquery_t *)arg; + fetchctx_t *fctx = NULL; respctx_t rctx; + if (eresult == ISC_R_CANCELED || eresult == ISC_R_EOF) { + return; + } + REQUIRE(VALID_QUERY(query)); fctx = query->fctx; REQUIRE(VALID_FCTX(fctx)); - REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); QTRACE("response"); + if (eresult == ISC_R_TIMEDOUT) { + result = resquery_timeout(query); + if (result == ISC_R_COMPLETE) { + return; + } + } + if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) { inc_stats(fctx->res, dns_resstatscounter_responsev4); } else { inc_stats(fctx->res, dns_resstatscounter_responsev6); } - (void)isc_timer_touch(fctx->timer); - - rctx_respinit(task, devent, query, fctx, &rctx); + rctx_respinit(query, fctx, eresult, region, &rctx); if (atomic_load_acquire(&fctx->res->exiting)) { result = ISC_R_SHUTTINGDOWN; FCTXTRACE("resolver shutting down"); + rctx.finish = NULL; rctx_done(&rctx, result); return; } - fctx->timeouts = 0; - fctx->timeout = false; + result = rctx_timedout(&rctx); + if (result == ISC_R_COMPLETE) { + FCTXTRACE("timed out"); + return; + } + fctx->addrinfo = query->addrinfo; + fctx->timeout = false; + fctx->timeouts = 0; /* * Check whether the dispatcher has failed; if so we're done @@ -7723,7 +7242,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } } - if (query->tsigkey) { + if (query->tsigkey != NULL) { result = dns_message_settsigkey(query->rmessage, query->tsigkey); if (result != ISC_R_SUCCESS) { @@ -7737,9 +7256,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if ((rctx.retryopts & DNS_FETCHOPT_TCP) == 0) { if ((rctx.retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { - dns_adb_setudpsize( - fctx->adb, query->addrinfo, - isc_buffer_usedlength(&devent->buffer)); + dns_adb_setudpsize(fctx->adb, query->addrinfo, + isc_buffer_usedlength(&rctx.buffer)); } else { dns_adb_plainresponse(fctx->adb, query->addrinfo); } @@ -7794,9 +7312,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * Is the question the same as the one we asked? - * NOERROR/NXDOMAIN/YXDOMAIN/REFUSED/SERVFAIL/BADCOOKIE must have - * the same question. - * FORMERR/NOTIMP if they have a question section then it must match. + * NOERROR/NXDOMAIN/YXDOMAIN/REFUSED/SERVFAIL/BADCOOKIE must + * have the same question. FORMERR/NOTIMP if they have a + * question section then it must match. */ switch (query->rmessage->rcode) { case dns_rcode_notimp: @@ -7839,21 +7357,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } /* - * The dispatcher should ensure we only get responses with QR set. + * The dispatcher should ensure we only get responses with QR + * set. */ INSIST((query->rmessage->flags & DNS_MESSAGEFLAG_QR) != 0); - /* - * INSIST() that the message comes from the place we sent it to, - * since the dispatch code should ensure this. - * - * INSIST() that the message id is correct (this should also be - * ensured by the dispatch code). - */ /* - * If we have had a server cookie and don't get one retry over TCP. - * This may be a misconfigured anycast server or an attempt to send - * a spoofed response. Skip if we have a valid tsig. + * If we have had a server cookie and don't get one retry over + * TCP. This may be a misconfigured anycast server or an attempt + * to send a spoofed response. Skip if we have a valid tsig. */ if (dns_message_gettsig(query->rmessage, NULL) == NULL && !query->rmessage->cc_ok && !query->rmessage->cc_bad && @@ -7870,7 +7382,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_log_write( dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, - "missing expected cookie from %s", + "missing expected cookie " + "from %s", addrbuf); } rctx.retryopts |= DNS_FETCHOPT_TCP; @@ -7878,10 +7391,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_done(&rctx, result); return; } - /* - * XXXMPA When support for DNS COOKIE becomes ubiquitous, fall - * back to TCP for all non-COOKIE responses. - */ } rctx_edns(&rctx); @@ -7970,8 +7479,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_delonly_zone(&rctx); /* - * Optionally call dns_rdata_checkowner() and dns_rdata_checknames() - * to validate the names in the response message. + * Optionally call dns_rdata_checkowner() and + * dns_rdata_checknames() to validate the names in the response + * message. */ if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0) { checknames(query->rmessage); @@ -8008,7 +7518,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { case DNS_R_CHASEDSSERVERS: break; case DNS_R_DELEGATION: - /* With NOFOLLOW we want to pass the result code */ + /* With NOFOLLOW we want to pass the result code + */ if ((fctx->options & DNS_FETCHOPT_NOFOLLOW) == 0) { result = ISC_R_SUCCESS; } @@ -8042,8 +7553,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_additional(&rctx); /* - * Cache the cacheable parts of the message. This may also cause - * work to be queued to the DNSSEC validator. + * Cache the cacheable parts of the message. This may also + * cause work to be queued to the DNSSEC validator. */ if (WANTCACHE(fctx)) { isc_result_t tresult; @@ -8061,42 +7572,37 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ rctx_ncache(&rctx); + FCTXTRACE("resquery_response done"); rctx_done(&rctx, result); } /* * rctx_respinit(): - * Initialize the response context structure 'rctx' to all zeroes, then set - * the task, event, query and fctx information from resquery_response(). + * Initialize the response context structure 'rctx' to all zeroes, then + * set the task, event, query and fctx information from + * resquery_response(). */ static void -rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, - fetchctx_t *fctx, respctx_t *rctx) { - memset(rctx, 0, sizeof(*rctx)); - - rctx->task = task; - rctx->devent = devent; - rctx->query = query; - rctx->fctx = fctx; - rctx->broken_type = badns_response; - rctx->retryopts = query->options; - - /* - * XXXRTH We should really get the current time just once. We - * need a routine to convert from an isc_time_t to an - * isc_stdtime_t. - */ +rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result, + isc_region_t *region, respctx_t *rctx) { + *rctx = (respctx_t){ .result = result, + .query = query, + .fctx = fctx, + .broken_type = badns_response, + .retryopts = query->options }; + isc_buffer_init(&rctx->buffer, region->base, region->length); + isc_buffer_add(&rctx->buffer, region->length); TIME_NOW(&rctx->tnow); rctx->finish = &rctx->tnow; - isc_stdtime_get(&rctx->now); + rctx->now = (isc_stdtime_t)isc_time_seconds(&rctx->tnow); } /* * rctx_answer_init(): * Clear and reinitialize those portions of 'rctx' that will be needed * when scanning the answer section of the response message. This can be - * called more than once if scanning needs to be restarted (though currently - * there are no cases in which this occurs). + * called more than once if scanning needs to be restarted (though + * currently there are no cases in which this occurs). */ static void rctx_answer_init(respctx_t *rctx) { @@ -8122,8 +7628,8 @@ rctx_answer_init(respctx_t *rctx) { /* * Bigger than any valid DNAME label count. */ - rctx->dname_labels = dns_name_countlabels(&fctx->name); - rctx->domain_labels = dns_name_countlabels(&fctx->domain); + rctx->dname_labels = dns_name_countlabels(fctx->name); + rctx->domain_labels = dns_name_countlabels(fctx->domain); rctx->found_type = dns_rdatatype_none; @@ -8150,20 +7656,18 @@ rctx_answer_init(respctx_t *rctx) { */ static isc_result_t rctx_dispfail(respctx_t *rctx) { - dns_dispatchevent_t *devent = rctx->devent; fetchctx_t *fctx = rctx->fctx; resquery_t *query = rctx->query; - if (devent->result == ISC_R_SUCCESS) { + if (rctx->result == ISC_R_SUCCESS) { return (ISC_R_SUCCESS); } - if (devent->result == ISC_R_EOF && - (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) - { + if (rctx->result == ISC_R_EOF && + (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { /* - * The problem might be that they don't understand EDNS0. - * Turn it off and try again. + * The problem might be that they don't understand + * EDNS0. Turn it off and try again. */ rctx->retryopts |= DNS_FETCHOPT_NOEDNS0; rctx->resend = true; @@ -8175,29 +7679,66 @@ rctx_dispfail(respctx_t *rctx) { rctx->next_server = true; /* - * If this is a network error on an exclusive query - * socket, mark the server as bad so that we won't try - * it for this fetch again. Also adjust finish and - * no_response so that we penalize this address in SRTT - * adjustment later. + * If this is a network error, mark the server as bad so + * that we won't try it for this fetch again. Also + * adjust finish and no_response so that we penalize + * this address in SRTT adjustment later. */ - if (query->exclusivesocket && - (devent->result == ISC_R_HOSTUNREACH || - devent->result == ISC_R_NETUNREACH || - devent->result == ISC_R_CONNREFUSED || - devent->result == ISC_R_CANCELED)) + if (rctx->result == ISC_R_HOSTUNREACH || + rctx->result == ISC_R_NETUNREACH || + rctx->result == ISC_R_CONNREFUSED || + rctx->result == ISC_R_CANCELED || + rctx->result == ISC_R_SHUTTINGDOWN) { - rctx->broken_server = devent->result; + rctx->broken_server = rctx->result; rctx->broken_type = badns_unreachable; rctx->finish = NULL; rctx->no_response = true; } } - FCTXTRACE3("dispatcher failure", devent->result); + FCTXTRACE3("dispatcher failure", rctx->result); rctx_done(rctx, ISC_R_SUCCESS); return (ISC_R_COMPLETE); } +/* + * rctx_timedout(): + * Handle the case where a dispatch read timed out. + */ +static isc_result_t +rctx_timedout(respctx_t *rctx) { + fetchctx_t *fctx = rctx->fctx; + + if (rctx->result == ISC_R_TIMEDOUT) { + isc_time_t now; + + inc_stats(fctx->res, dns_resstatscounter_querytimeout); + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + fctx->timeout = true; + fctx->timeouts++; + + isc_time_now(&now); + /* netmgr timeouts are accurate to the millisecond */ + if (isc_time_microdiff(&fctx->expires, &now) < US_PER_MSEC) { + FCTXTRACE("stopped trying to make fetch happen"); + } else { + FCTXTRACE("query timed out; no response"); + rctx->no_response = true; + rctx->finish = NULL; + if (!ISFORWARDER(rctx->query->addrinfo) || + fctx->fwdpolicy != dns_fwdpolicy_first) + { + rctx->resend = true; + } + } + + rctx_done(rctx, rctx->result); + return (ISC_R_COMPLETE); + } + + return (ISC_R_SUCCESS); +} + /* * rctx_parse(): * Parse the response message. @@ -8208,7 +7749,7 @@ rctx_parse(respctx_t *rctx) { fetchctx_t *fctx = rctx->fctx; resquery_t *query = rctx->query; - result = dns_message_parse(query->rmessage, &rctx->devent->buffer, 0); + result = dns_message_parse(query->rmessage, &rctx->buffer, 0); if (result == ISC_R_SUCCESS) { return (ISC_R_SUCCESS); } @@ -8401,15 +7942,16 @@ rctx_edns(respctx_t *rctx) { (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { /* - * We didn't get a OPT record in response to a EDNS query. + * We didn't get a OPT record in response to a EDNS + * query. * * Old versions of named incorrectly drop the OPT record - * when there is a signed, truncated response so we check - * that TC is not set. + * when there is a signed, truncated response so we + * check that TC is not set. * - * Record that the server is not talking EDNS. While this - * should be safe to do for any rcode we limit it to NOERROR - * and NXDOMAIN. + * Record that the server is not talking EDNS. While + * this should be safe to do for any rcode we limit it + * to NOERROR and NXDOMAIN. */ dns_message_logpacket( query->rmessage, "received packet (no opt) from", @@ -8455,7 +7997,7 @@ rctx_answer(respctx_t *rctx) { if (result != ISC_R_SUCCESS) { FCTXTRACE3("rctx_answer_positive (AA/fwd)", result); } - } else if (iscname(query->rmessage, &fctx->name) && + } else if (iscname(query->rmessage, fctx->name) && fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_cname) { @@ -8525,6 +8067,7 @@ rctx_answer(respctx_t *rctx) { */ rctx->broken_server = DNS_R_LAME; rctx->next_server = true; + FCTXTRACE3("rctx_answer lame", result); rctx_done(rctx, result); return (ISC_R_COMPLETE); } @@ -8534,6 +8077,7 @@ rctx_answer(respctx_t *rctx) { if (result == DNS_R_FORMERR) { rctx->next_server = true; } + FCTXTRACE3("rctx_answer failed", result); rctx_done(rctx, result); return (ISC_R_COMPLETE); } @@ -8601,8 +8145,8 @@ rctx_answer_positive(respctx_t *rctx) { } /* - * We didn't end with an incomplete chain, so the rcode should be - * "no error". + * We didn't end with an incomplete chain, so the rcode should + * be "no error". */ if (rctx->query->rmessage->rcode != dns_rcode_noerror) { log_formerr(fctx, "CNAME/DNAME chain complete, but RCODE " @@ -8619,7 +8163,7 @@ rctx_answer_positive(respctx_t *rctx) { log_ns_ttl(fctx, "rctx_answer"); if (rctx->ns_rdataset != NULL && - dns_name_equal(&fctx->domain, rctx->ns_name) && + dns_name_equal(fctx->domain, rctx->ns_name) && !dns_name_equal(rctx->ns_name, dns_rootname)) { trim_ns_ttl(fctx, rctx->ns_name, rctx->ns_rdataset); @@ -8631,8 +8175,8 @@ rctx_answer_positive(respctx_t *rctx) { /* * rctx_answer_scan(): * Perform a single pass over the answer section of a response, looking - * for an answer that matches QNAME/QTYPE, or a CNAME matching QNAME, or a - * covering DNAME. If more than one rdataset is found matching these + * for an answer that matches QNAME/QTYPE, or a CNAME matching QNAME, or + * a covering DNAME. If more than one rdataset is found matching these * criteria, then only one is kept. Order of preference is 1) the * shortest DNAME, 2) the first matching answer, or 3) the first CNAME. */ @@ -8655,7 +8199,7 @@ rctx_answer_scan(respctx_t *rctx) { dns_message_currentname(rctx->query->rmessage, DNS_SECTION_ANSWER, &name); - namereln = dns_name_fullcompare(&fctx->name, name, &order, + namereln = dns_name_fullcompare(fctx->name, name, &order, &nlabels); switch (namereln) { case dns_namereln_equal: @@ -8692,8 +8236,9 @@ rctx_answer_scan(respctx_t *rctx) { } /* - * We are looking for the shortest DNAME if there - * are multiple ones (which there shouldn't be). + * We are looking for the shortest DNAME if + * there are multiple ones (which there + * shouldn't be). */ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -8715,9 +8260,9 @@ rctx_answer_scan(respctx_t *rctx) { /* * If a DNAME was found, then any CNAME or other answer matching - * QNAME that may also have been found must be ignored. Similarly, - * if a matching answer was found along with a CNAME, the CNAME - * must be ignored. + * QNAME that may also have been found must be ignored. + * Similarly, if a matching answer was found along with a CNAME, + * the CNAME must be ignored. */ if (rctx->dname != NULL) { rctx->aname = NULL; @@ -8767,7 +8312,7 @@ rctx_answer_any(respctx_t *rctx) { if ((rdataset->type == dns_rdatatype_cname || rdataset->type == dns_rdatatype_dname) && - !is_answertarget_allowed(fctx, &fctx->name, rctx->aname, + !is_answertarget_allowed(fctx, fctx->name, rctx->aname, rdataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8816,7 +8361,7 @@ rctx_answer_match(respctx_t *rctx) { rctx->ardataset->type == dns_rdatatype_dname) && rctx->type != rctx->ardataset->type && rctx->type != dns_rdatatype_any && - !is_answertarget_allowed(fctx, &fctx->name, rctx->aname, + !is_answertarget_allowed(fctx, fctx->name, rctx->aname, rctx->ardataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8880,7 +8425,7 @@ rctx_answer_cname(respctx_t *rctx) { return (ISC_R_COMPLETE); } - if (!is_answertarget_allowed(fctx, &fctx->name, rctx->cname, + if (!is_answertarget_allowed(fctx, fctx->name, rctx->cname, rctx->crdataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8934,7 +8479,7 @@ rctx_answer_dname(respctx_t *rctx) { return (ISC_R_COMPLETE); } - if (!is_answertarget_allowed(fctx, &fctx->name, rctx->dname, + if (!is_answertarget_allowed(fctx, fctx->name, rctx->dname, rctx->drdataset, &rctx->chaining)) { rctx->result = DNS_R_SERVFAIL; @@ -8976,9 +8521,9 @@ rctx_answer_dname(respctx_t *rctx) { /* * rctx_authority_positive(): * Examine the records in the authority section (if there are any) for a - * positive answer. We expect the names for all rdatasets in this section - * to be subdomains of the domain being queried; any that are not are - * skipped. We expect to find only *one* owner name; any names + * positive answer. We expect the names for all rdatasets in this + * section to be subdomains of the domain being queried; any that are + * not are skipped. We expect to find only *one* owner name; any names * after the first one processed are ignored. We expect to find only * rdatasets of type NS, RRSIG, or SIG; all others are ignored. Whatever * remains can be cached at trust level authauthority or additional @@ -8998,7 +8543,7 @@ rctx_authority_positive(respctx_t *rctx) { dns_message_currentname(rctx->query->rmessage, DNS_SECTION_AUTHORITY, &name); - external = !dns_name_issubdomain(name, &fctx->domain); + external = !dns_name_issubdomain(name, fctx->domain); if (!external) { dns_rdataset_t *rdataset = NULL; @@ -9033,8 +8578,8 @@ rctx_authority_positive(respctx_t *rctx) { rctx->ns_rdataset = rdataset; } /* - * Mark any additional data related - * to this rdataset. + * Mark any additional data + * related to this rdataset. */ (void)dns_rdataset_additionaldata( rdataset, name, check_related, @@ -9066,8 +8611,8 @@ rctx_answer_none(respctx_t *rctx) { rctx_answer_init(rctx); /* - * Sometimes we can tell if its a negative response by looking at - * the message header. + * Sometimes we can tell if its a negative response by looking + * at the message header. */ if (rctx->query->rmessage->rcode == dns_rcode_nxdomain || (rctx->query->rmessage->counts[DNS_SECTION_ANSWER] == 0 && @@ -9087,7 +8632,7 @@ rctx_answer_none(respctx_t *rctx) { log_ns_ttl(fctx, "rctx_answer_none"); if (rctx->ns_rdataset != NULL && - dns_name_equal(&fctx->domain, rctx->ns_name) && + dns_name_equal(fctx->domain, rctx->ns_name) && !dns_name_equal(rctx->ns_name, dns_rootname)) { trim_ns_ttl(fctx, rctx->ns_name, rctx->ns_rdataset); @@ -9120,8 +8665,8 @@ rctx_answer_none(respctx_t *rctx) { if (rctx->negative && rctx->query->rmessage->rcode == dns_rcode_noerror && fctx->type == dns_rdatatype_ds && rctx->soa_name != NULL && - dns_name_equal(rctx->soa_name, &fctx->name) && - !dns_name_equal(&fctx->name, dns_rootname)) + dns_name_equal(rctx->soa_name, fctx->name) && + !dns_name_equal(fctx->name, dns_rootname)) { return (DNS_R_CHASEDSSERVERS); } @@ -9137,7 +8682,7 @@ rctx_answer_none(respctx_t *rctx) { log_formerr(fctx, "invalid response"); return (DNS_R_FORMERR); } - if (!dns_name_issubdomain(rctx->found_name, &fctx->domain)) { + if (!dns_name_issubdomain(rctx->found_name, fctx->domain)) { char nbuf[DNS_NAME_FORMATSIZE]; char dbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; @@ -9145,7 +8690,7 @@ rctx_answer_none(respctx_t *rctx) { dns_rdatatype_format(rctx->found_type, tbuf, sizeof(tbuf)); dns_name_format(rctx->found_name, nbuf, sizeof(nbuf)); - dns_name_format(&fctx->domain, dbuf, sizeof(dbuf)); + dns_name_format(fctx->domain, dbuf, sizeof(dbuf)); log_formerr(fctx, "Name %s (%s) not subdomain" @@ -9226,7 +8771,7 @@ rctx_authority_negative(respctx_t *rctx) { finished = true; } - if (!dns_name_issubdomain(name, &fctx->domain)) { + if (!dns_name_issubdomain(name, fctx->domain)) { continue; } @@ -9239,15 +8784,14 @@ rctx_authority_negative(respctx_t *rctx) { } if (((type == dns_rdatatype_ns || type == dns_rdatatype_soa) && - !dns_name_issubdomain(&fctx->name, name))) + !dns_name_issubdomain(fctx->name, name))) { char qbuf[DNS_NAME_FORMATSIZE]; char nbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(type, tbuf, sizeof(tbuf)); dns_name_format(name, nbuf, sizeof(nbuf)); - dns_name_format(&fctx->name, qbuf, - sizeof(qbuf)); + dns_name_format(fctx->name, qbuf, sizeof(qbuf)); log_formerr(fctx, "unrelated %s %s in " "%s authority section", @@ -9387,8 +8931,9 @@ rctx_authority_dnssec(respctx_t *rctx) { finished = true; } - if (!dns_name_issubdomain(name, &fctx->domain)) { - /* Invalid name found; preserve it for logging later */ + if (!dns_name_issubdomain(name, fctx->domain)) { + /* Invalid name found; preserve it for logging + * later */ rctx->found_name = name; rctx->found_type = ISC_LIST_HEAD(name->list)->type; continue; @@ -9427,16 +8972,17 @@ rctx_authority_dnssec(respctx_t *rctx) { rdataset->trust = dns_trust_additional; } /* - * No additional data needs to be marked. + * No additional data needs to be + * marked. */ break; case dns_rdatatype_ds: /* * DS or SIG DS. * - * These should only be here if this is a - * referral, and there should only be one - * DS RRset. + * These should only be here if this is + * a referral, and there should only be + * one DS RRset. */ if (rctx->ns_name == NULL) { log_formerr(fctx, "DS with no " @@ -9514,7 +9060,7 @@ rctx_referral(respctx_t *rctx) { * progress. We return DNS_R_FORMERR so that we'll keep * trying other servers. */ - if (dns_name_equal(rctx->ns_name, &fctx->domain)) { + if (dns_name_equal(rctx->ns_name, fctx->domain)) { log_formerr(fctx, "non-improving referral"); rctx->result = DNS_R_FORMERR; return (ISC_R_COMPLETE); @@ -9524,7 +9070,7 @@ rctx_referral(respctx_t *rctx) { * If the referral name is not a parent of the query * name, consider the responder insane. */ - if (!dns_name_issubdomain(&fctx->name, rctx->ns_name)) { + if (!dns_name_issubdomain(fctx->name, rctx->ns_name)) { /* Logged twice */ log_formerr(fctx, "referral to non-parent"); FCTXTRACE("referral to non-parent"); @@ -9575,21 +9121,17 @@ rctx_referral(respctx_t *rctx) { * XXXRTH We should check if we're in forward-only mode, and * if so we should bail out. */ - INSIST(dns_name_countlabels(&fctx->domain) > 0); + INSIST(dns_name_countlabels(fctx->domain) > 0); fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_init(&fctx->domain, NULL); - dns_name_dup(rctx->ns_name, fctx->mctx, &fctx->domain); + dns_name_copy(rctx->ns_name, fctx->domain); if ((fctx->options & DNS_FETCHOPT_QMINIMIZE) != 0) { - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(rctx->ns_name, fctx->mctx, &fctx->qmindcname); + dns_name_copy(rctx->ns_name, fctx->qmindcname); result = fctx_minimize_qname(fctx); if (result != ISC_R_SUCCESS) { @@ -9611,8 +9153,8 @@ rctx_referral(respctx_t *rctx) { /* * Reinitialize 'rctx' to prepare for following the delegation: - * set the get_nameservers and next_server flags appropriately and - * reset the fetch context counters. + * set the get_nameservers and next_server flags appropriately + * and reset the fetch context counters. * */ if ((rctx->fctx->options & DNS_FETCHOPT_NOFOLLOW) == 0) { @@ -9682,6 +9224,7 @@ static void rctx_nextserver(respctx_t *rctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo, isc_result_t result) { fetchctx_t *fctx = rctx->fctx; + bool retrying = true; if (result == DNS_R_FORMERR) { rctx->broken_server = DNS_R_FORMERR; @@ -9711,9 +9254,9 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, findoptions |= DNS_DBFIND_NOEXACT; } if ((rctx->retryopts & DNS_FETCHOPT_UNSHARED) == 0) { - name = &fctx->name; + name = fctx->name; } else { - name = &fctx->domain; + name = fctx->domain; } result = dns_view_findzonecut( fctx->res->view, name, fname, dcname, fctx->now, @@ -9723,9 +9266,10 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } - if (!dns_name_issubdomain(fname, &fctx->domain)) { + if (!dns_name_issubdomain(fname, fctx->domain)) { /* - * The best nameservers are now above our QDOMAIN. + * The best nameservers are now above our + * QDOMAIN. */ FCTXTRACE("nameservers now above QDOMAIN"); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); @@ -9734,12 +9278,8 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(fname, fctx->mctx, &fctx->domain); - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(dcname, fctx->qmindcname); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { @@ -9749,21 +9289,23 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; fctx_cancelqueries(fctx, true, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); + retrying = false; } /* * Try again. */ - fctx_try(fctx, !rctx->get_nameservers, false); + fctx_try(fctx, retrying, false); } /* * rctx_resend(): * - * Resend the query, probably with the options changed. Calls fctx_query(), - * passing rctx->retryopts (which is based on query->options, but may have been - * updated since the last time fctx_query() was called). + * Resend the query, probably with the options changed. Calls + * fctx_query(), passing rctx->retryopts (which is based on + * query->options, but may have been updated since the last time + * fctx_query() was called). */ static void rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { @@ -9777,28 +9319,26 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { inc_stats(fctx->res, dns_resstatscounter_retry); fctx_increference(fctx); result = fctx_query(fctx, addrinfo, rctx->retryopts); - if (result == ISC_R_SUCCESS) { - return; - } - - bucketnum = fctx->bucketnum; - fctx_done(fctx, result, __LINE__); - LOCK(&res->buckets[bucketnum].lock); - bucket_empty = fctx_decreference(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - if (bucket_empty) { - empty_bucket(res); + if (result != ISC_R_SUCCESS) { + bucketnum = fctx->bucketnum; + fctx_done(fctx, result, __LINE__); + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) { + empty_bucket(res); + } } } /* * rctx_next(): - * We got what appeared to be a response but it didn't match the question - * or the cookie; it may have been meant for someone else, or it may be a - * spoofing attack. Drop it and continue listening for the response we - * wanted. + * We got what appeared to be a response but it didn't match the + * question or the cookie; it may have been meant for someone else, or + * it may be a spoofing attack. Drop it and continue listening for the + * response we wanted. */ -static void +static isc_result_t rctx_next(respctx_t *rctx) { #ifdef WANT_QUERYTRACE fetchctx_t *fctx = rctx->fctx; @@ -9809,15 +9349,18 @@ rctx_next(respctx_t *rctx) { inc_stats(rctx->fctx->res, dns_resstatscounter_nextitem); INSIST(rctx->query->dispentry != NULL); dns_message_reset(rctx->query->rmessage, DNS_MESSAGE_INTENTPARSE); - result = dns_dispatch_getnext(rctx->query->dispentry, &rctx->devent); + result = dns_dispatch_getnext(rctx->query->dispentry); if (result != ISC_R_SUCCESS) { fctx_done(rctx->fctx, result, __LINE__); } + + return (result); } /* * rctx_chaseds(): - * Look up the parent zone's NS records so that DS records can be fetched. + * Look up the parent zone's NS records so that DS records can be + * fetched. */ static void rctx_chaseds(respctx_t *rctx, dns_message_t *message, @@ -9827,17 +9370,16 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, add_bad(fctx, message, addrinfo, result, rctx->broken_type); fctx_cancelqueries(fctx, true, false); - fctx_cleanupfinds(fctx); - fctx_cleanupforwaddrs(fctx); + fctx_cleanup(fctx); - n = dns_name_countlabels(&fctx->name); - dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname); + n = dns_name_countlabels(fctx->name); + dns_name_getlabelsequence(fctx->name, 1, n - 1, fctx->nsname); FCTXTRACE("suspending DS lookup to find parent's NS records"); result = dns_resolver_createfetch( - fctx->res, &fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, - NULL, 0, fctx->options, 0, NULL, rctx->task, resume_dslookup, + fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, + NULL, 0, fctx->options, 0, NULL, fctx->task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) { if (result == DNS_R_DUPLICATE) { @@ -9846,83 +9388,80 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, fctx_done(fctx, result, __LINE__); } else { fctx_increference(fctx); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } } } /* * rctx_done(): - * This resolver query response is finished, either because we encountered - * a problem or because we've gotten all the information from it that we - * can. We either wait for another response, resend the query to the - * same server, resend to a new server, or clean up and shut down the fetch. + * This resolver query response is finished, either because we + * encountered a problem or because we've gotten all the information + * from it that we can. We either wait for another response, resend the + * query to the same server, resend to a new server, or clean up and + * shut down the fetch. */ static void rctx_done(respctx_t *rctx, isc_result_t result) { resquery_t *query = rctx->query; fetchctx_t *fctx = rctx->fctx; dns_adbaddrinfo_t *addrinfo = query->addrinfo; + dns_message_t *message = NULL; + /* * Need to attach to the message until the scope * of this function ends, since there are many places - * where te message is used and/or may be destroyed + * where the message is used and/or may be destroyed * before this function ends. */ - dns_message_t *message = NULL; dns_message_attach(query->rmessage, &message); - FCTXTRACE4("query canceled in response(); ", + FCTXTRACE4("query canceled in rctx_done();", rctx->no_response ? "no response" : "responding", result); - /* - * Cancel the query. - * - * XXXRTH Don't cancel the query if waiting for validation? - */ - if (!rctx->nextitem) { - fctx_cancelquery(&query, &rctx->devent, rctx->finish, - rctx->no_response, false); - } - #ifdef ENABLE_AFL if (dns_fuzzing_resolver && (rctx->next_server || rctx->resend || rctx->nextitem)) { - if (rctx->nextitem) { - fctx_cancelquery(&query, &rctx->devent, rctx->finish, - rctx->no_response, false); - } + fctx_cancelquery(query, rctx->finish, rctx->no_response, false); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); - return; - } else + goto detach; + } #endif /* ifdef ENABLE_AFL */ - if (rctx->next_server) - { + + if (rctx->nextitem) { + REQUIRE(!rctx->next_server); + REQUIRE(!rctx->resend); + + result = rctx_next(rctx); + if (result == ISC_R_SUCCESS) { + goto detach; + } + } + + /* Cancel the query */ + fctx_cancelquery(query, rctx->finish, rctx->no_response, false); + + /* + * If nobody's waiting for results, don't resend. + */ + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); + if (ISC_LIST_EMPTY(fctx->events)) { + rctx->resend = false; + } + UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + + if (rctx->next_server) { rctx_nextserver(rctx, message, addrinfo, result); } else if (rctx->resend) { rctx_resend(rctx, addrinfo); - } else if (rctx->nextitem) { - rctx_next(rctx); } else if (result == DNS_R_CHASEDSSERVERS) { rctx_chaseds(rctx, message, addrinfo, result); } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { /* - * All has gone well so far, but we are waiting for the - * DNSSEC validator to validate the answer. + * All has gone well so far, but we are waiting for the DNSSEC + * validator to validate the answer. */ FCTXTRACE("wait for validator"); fctx_cancelqueries(fctx, true, false); - /* - * We must not retransmit while the validator is working; - * it has references to the current rmessage. - */ - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } } else { /* * We're done. @@ -9930,6 +9469,7 @@ rctx_done(respctx_t *rctx, isc_result_t result) { fctx_done(fctx, result, __LINE__); } +detach: dns_message_detach(&message); } @@ -9942,7 +9482,6 @@ rctx_logpacket(respctx_t *rctx) { #ifdef HAVE_DNSTAP isc_result_t result; fetchctx_t *fctx = rctx->fctx; - isc_socket_t *sock = NULL; isc_sockaddr_t localaddr, *la = NULL; unsigned char zone[DNS_NAME_MAXWIRE]; dns_dtmsgtype_t dtmsgtype; @@ -9966,7 +9505,7 @@ rctx_logpacket(respctx_t *rctx) { if (result == ISC_R_SUCCESS) { isc_buffer_init(&zb, zone, sizeof(zone)); dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE); - result = dns_name_towire(&fctx->domain, &cctx, &zb); + result = dns_name_towire(fctx->domain, &cctx, &zb); if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(&zb, &zr); } @@ -9979,19 +9518,16 @@ rctx_logpacket(respctx_t *rctx) { dtmsgtype = DNS_DTTYPE_RR; } - sock = query2sock(rctx->query); - - if (sock != NULL) { - result = isc_socket_getsockname(sock, &localaddr); - if (result == ISC_R_SUCCESS) { - la = &localaddr; - } + result = dns_dispentry_getlocaladdress(rctx->query->dispentry, + &localaddr); + if (result == ISC_R_SUCCESS) { + la = &localaddr; } dns_dt_send(fctx->res->view, dtmsgtype, la, &rctx->query->addrinfo->sockaddr, ((rctx->query->options & DNS_FETCHOPT_TCP) != 0), &zr, - &rctx->query->start, NULL, &rctx->devent->buffer); + &rctx->query->start, NULL, &rctx->buffer); #endif /* HAVE_DNSTAP */ } @@ -10134,7 +9670,7 @@ rctx_lameserver(respctx_t *rctx) { inc_stats(fctx->res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); - result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, + result = dns_adb_marklame(fctx->adb, query->addrinfo, fctx->name, fctx->type, rctx->now + fctx->res->lame_ttl); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -10164,15 +9700,15 @@ rctx_delonly_zone(respctx_t *rctx) { char typebuf[64]; if (ISFORWARDER(rctx->query->addrinfo) || - !dns_view_isdelegationonly(fctx->res->view, &fctx->domain) || - dns_name_equal(&fctx->domain, &fctx->name) || + !dns_view_isdelegationonly(fctx->res->view, fctx->domain) || + dns_name_equal(fctx->domain, fctx->name) || !fix_mustbedelegationornxdomain(rctx->query->rmessage, fctx)) { return; } - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(&rctx->query->addrinfo->sockaddr, addrbuf, @@ -10235,12 +9771,6 @@ destroy(dns_resolver_t *res) { dns_resolver_reset_ds_digests(res); dns_badcache_destroy(&res->badcache); dns_resolver_resetmustbesecure(res); -#if USE_ALGLOCK - isc_rwlock_destroy(&res->alglock); -#endif /* if USE_ALGLOCK */ -#if USE_MBSLOCK - isc_rwlock_destroy(&res->mbslock); -#endif /* if USE_MBSLOCK */ isc_timer_detach(&res->spillattimer); res->magic = 0; isc_mem_put(res->mctx, res, sizeof(*res)); @@ -10270,15 +9800,11 @@ static void empty_bucket(dns_resolver_t *res) { RTRACE("empty_bucket"); - LOCK(&res->lock); - - INSIST(res->activebuckets > 0); - res->activebuckets--; - if (res->activebuckets == 0) { + if (isc_refcount_decrement(&res->activebuckets) == 1) { + LOCK(&res->lock); send_shutdown_events(res); + UNLOCK(&res->lock); } - - UNLOCK(&res->lock); } static void @@ -10317,17 +9843,15 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) { isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp) { - dns_resolver_t *res; + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp) { + dns_resolver_t *res = NULL; isc_result_t result = ISC_R_SUCCESS; unsigned int i, buckets_created = 0, dbuckets_created = 0; isc_task_t *task = NULL; char name[16]; - unsigned dispattr; /* * Create a resolver. @@ -10340,65 +9864,74 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, REQUIRE(dispatchmgr != NULL); REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL); - res = isc_mem_get(view->mctx, sizeof(*res)); RTRACE("create"); - res->mctx = view->mctx; - res->rdclass = view->rdclass; - res->socketmgr = socketmgr; - res->timermgr = timermgr; - res->taskmgr = taskmgr; - res->dispatchmgr = dispatchmgr; - res->view = view; - res->options = options; - res->lame_ttl = 0; + res = isc_mem_get(view->mctx, sizeof(*res)); + *res = (dns_resolver_t){ .mctx = view->mctx, + .rdclass = view->rdclass, + .nm = nm, + .timermgr = timermgr, + .taskmgr = taskmgr, + .dispatchmgr = dispatchmgr, + .view = view, + .options = options, + .udpsize = DEFAULT_EDNS_BUFSIZE, + .spillatmin = 10, + .spillat = 10, + .spillatmax = 100, + .retryinterval = 10000, + .nonbackofftries = 3, + .query_timeout = DEFAULT_QUERY_TIMEOUT, + .maxdepth = DEFAULT_RECURSION_DEPTH, + .maxqueries = DEFAULT_MAX_QUERIES, + .nbuckets = ntasks, + .querydscp4 = -1, + .querydscp6 = -1 }; + + atomic_init(&res->activebuckets, ntasks); + + res->quotaresp[dns_quotatype_zone] = DNS_R_DROP; + res->quotaresp[dns_quotatype_server] = DNS_R_SERVFAIL; + isc_refcount_init(&res->references, 1); + atomic_init(&res->exiting, false); + atomic_init(&res->priming, false); + atomic_init(&res->zspill, 0); + atomic_init(&res->nfctx, 0); + ISC_LIST_INIT(res->whenshutdown); ISC_LIST_INIT(res->alternates); - res->udpsize = DEFAULT_EDNS_BUFSIZE; - res->algorithms = NULL; - res->digests = NULL; - res->badcache = NULL; + result = dns_badcache_init(res->mctx, DNS_RESOLVER_BADCACHESIZE, &res->badcache); if (result != ISC_R_SUCCESS) { goto cleanup_res; } - res->mustbesecure = NULL; - res->spillatmin = res->spillat = 10; - res->spillatmax = 100; - res->spillattimer = NULL; - atomic_init(&res->zspill, 0); - res->zero_no_soa_ttl = false; - res->retryinterval = 30000; - res->nonbackofftries = 3; - res->query_timeout = DEFAULT_QUERY_TIMEOUT; - res->maxdepth = DEFAULT_RECURSION_DEPTH; - res->maxqueries = DEFAULT_MAX_QUERIES; - res->quotaresp[dns_quotatype_zone] = DNS_R_DROP; - res->quotaresp[dns_quotatype_server] = DNS_R_SERVFAIL; - res->nbuckets = ntasks; + if (view->resstats != NULL) { isc_stats_set(view->resstats, ntasks, dns_resstatscounter_buckets); } - res->activebuckets = ntasks; + res->buckets = isc_mem_get(view->mctx, ntasks * sizeof(fctxbucket_t)); for (i = 0; i < ntasks; i++) { isc_mutex_init(&res->buckets[i].lock); - res->buckets[i].task = NULL; /* - * Since we have a pool of tasks we bind them to task queues - * to spread the load evenly + * Since we have a pool of tasks we bind them to task + * queues to spread the load evenly */ + res->buckets[i].task = NULL; result = isc_task_create_bound(taskmgr, 0, &res->buckets[i].task, i); if (result != ISC_R_SUCCESS) { isc_mutex_destroy(&res->buckets[i].lock); goto cleanup_buckets; } - res->buckets[i].mctx = NULL; + snprintf(name, sizeof(name), "res%u", i); - isc_mem_attach(view->mctx, &res->buckets[i].mctx); isc_task_setname(res->buckets[i].task, name, res); + + res->buckets[i].mctx = NULL; + isc_mem_attach(view->mctx, &res->buckets[i].mctx); + ISC_LIST_INIT(res->buckets[i].fctxs); atomic_init(&res->buckets[i].exiting, false); buckets_created++; @@ -10414,37 +9947,19 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, dbuckets_created++; } - res->dispatches4 = NULL; if (dispatchv4 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv4, &res->dispatches4, ndisp); - dispattr = dns_dispatch_getattributes(dispatchv4); - res->exclusivev4 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); + dns_dispatchset_create(view->mctx, dispatchv4, + &res->dispatches4, ndisp); } - res->dispatches6 = NULL; if (dispatchv6 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv6, &res->dispatches6, ndisp); - dispattr = dns_dispatch_getattributes(dispatchv6); - res->exclusivev6 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); + dns_dispatchset_create(view->mctx, dispatchv6, + &res->dispatches6, ndisp); } - res->querydscp4 = -1; - res->querydscp6 = -1; - isc_refcount_init(&res->references, 1); - atomic_init(&res->exiting, false); - res->frozen = false; - ISC_LIST_INIT(res->whenshutdown); - atomic_init(&res->priming, false); - res->primefetch = NULL; - - atomic_init(&res->nfctx, 0); - isc_mutex_init(&res->lock); isc_mutex_init(&res->primelock); - task = NULL; result = isc_task_create(taskmgr, 0, &task); if (result != ISC_R_SUCCESS) { goto cleanup_primelock; @@ -10459,13 +9974,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, goto cleanup_primelock; } -#if USE_ALGLOCK - isc_rwlock_init(&res->alglock, 0, 0); -#endif /* if USE_ALGLOCK */ -#if USE_MBSLOCK - isc_rwlock_init(&res->mbslock, 0, 0); -#endif /* if USE_MBSLOCK */ - res->magic = RES_MAGIC; *resp = res; @@ -10578,12 +10086,12 @@ dns_resolver_prime(dns_resolver_t *res) { if (want_priming) { /* * To avoid any possible recursive locking problems, we - * start the priming fetch like any other fetch, and holding - * no resolver locks. No one else will try to start it - * because we're the ones who set res->priming to true. - * Any other callers of dns_resolver_prime() while we're - * running will see that res->priming is already true and - * do nothing. + * start the priming fetch like any other fetch, and + * holding no resolver locks. No one else will try to + * start it because we're the ones who set res->priming + * to true. Any other callers of dns_resolver_prime() + * while we're running will see that res->priming is + * already true and do nothing. */ RTRACE("priming"); rdataset = isc_mem_get(res->mctx, sizeof(*rdataset)); @@ -10625,10 +10133,8 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { RRTRACE(source, "attach"); - LOCK(&source->lock); REQUIRE(!atomic_load_acquire(&source->exiting)); isc_refcount_increment(&source->references); - UNLOCK(&source->lock); *targetp = source; } @@ -10636,8 +10142,7 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { void dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, isc_event_t **eventp) { - isc_task_t *tclone; - isc_event_t *event; + isc_event_t *event = NULL; REQUIRE(VALID_RESOLVER(res)); REQUIRE(eventp != NULL); @@ -10647,16 +10152,17 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, LOCK(&res->lock); - if (atomic_load_acquire(&res->exiting) && res->activebuckets == 0) { + if (atomic_load_acquire(&res->exiting) && + atomic_load_acquire(&res->activebuckets) == 0) + { /* * We're already shutdown. Send the event. */ event->ev_sender = res; isc_task_send(task, &event); } else { - tclone = NULL; - isc_task_attach(task, &tclone); - event->ev_sender = tclone; + isc_task_attach(task, &(isc_task_t *){ NULL }); + event->ev_sender = task; ISC_LIST_APPEND(res->whenshutdown, event, ev_link); } @@ -10669,6 +10175,7 @@ dns_resolver_shutdown(dns_resolver_t *res) { fetchctx_t *fctx; isc_result_t result; bool is_false = false; + bool is_done = false; REQUIRE(VALID_RESOLVER(res)); @@ -10685,22 +10192,16 @@ dns_resolver_shutdown(dns_resolver_t *res) { { fctx_shutdown(fctx); } - if (res->dispatches4 != NULL && !res->exclusivev4) { - dns_dispatchset_cancelall(res->dispatches4, - res->buckets[i].task); - } - if (res->dispatches6 != NULL && !res->exclusivev6) { - dns_dispatchset_cancelall(res->dispatches6, - res->buckets[i].task); - } atomic_store(&res->buckets[i].exiting, true); if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { - INSIST(res->activebuckets > 0); - res->activebuckets--; + if (isc_refcount_decrement( + &res->activebuckets) == 1) { + is_done = true; + } } UNLOCK(&res->buckets[i].lock); } - if (res->activebuckets == 0) { + if (is_done) { send_shutdown_events(res); } result = isc_timer_reset(res->spillattimer, @@ -10723,10 +10224,8 @@ dns_resolver_detach(dns_resolver_t **resp) { RTRACE("detach"); if (isc_refcount_decrement(&res->references) == 1) { - LOCK(&res->lock); + isc_refcount_destroy(&res->activebuckets); INSIST(atomic_load_acquire(&res->exiting)); - INSIST(res->activebuckets == 0); - UNLOCK(&res->lock); destroy(res); } } @@ -10746,7 +10245,7 @@ fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type, if (fctx->type != type || fctx->options != options) { return (false); } - return (dns_name_equal(&fctx->name, name)); + return (dns_name_equal(fctx->name, name)); } static inline void @@ -10778,10 +10277,8 @@ fctx_minimize_qname(fetchctx_t *fctx) { REQUIRE(VALID_FCTX(fctx)); - dlabels = dns_name_countlabels(&fctx->qmindcname); - nlabels = dns_name_countlabels(&fctx->name); - dns_name_free(&fctx->qminname, fctx->mctx); - dns_name_init(&fctx->qminname, NULL); + dlabels = dns_name_countlabels(fctx->qmindcname); + nlabels = dns_name_countlabels(fctx->name); if (dlabels > fctx->qmin_labels) { fctx->qmin_labels = dlabels + 1; @@ -10795,7 +10292,8 @@ fctx_minimize_qname(fetchctx_t *fctx) { * boundaries at /16, /32, /48, /56, /64 and /128 * In 'label count' terms that's equal to * 7 11 15 17 19 35 - * We fix fctx->qmin_labels to point to the nearest boundary + * We fix fctx->qmin_labels to point to the nearest + * boundary */ if (fctx->qmin_labels < 7) { fctx->qmin_labels = 7; @@ -10822,8 +10320,7 @@ fctx_minimize_qname(fetchctx_t *fctx) { */ dns_fixedname_t fname; dns_name_t *name = dns_fixedname_initname(&fname); - dns_name_split(&fctx->name, fctx->qmin_labels, NULL, - dns_fixedname_name(&fname)); + dns_name_split(fctx->name, fctx->qmin_labels, NULL, name); if ((fctx->options & DNS_FETCHOPT_QMIN_USE_A) != 0) { isc_buffer_t dbuf; dns_fixedname_t tmpname; @@ -10835,25 +10332,23 @@ fctx_minimize_qname(fetchctx_t *fctx) { result = dns_name_concatenate(&underscore_name, name, tname, &dbuf); if (result == ISC_R_SUCCESS) { - dns_name_dup(tname, fctx->mctx, - &fctx->qminname); + dns_name_copy(tname, fctx->qminname); } fctx->qmintype = dns_rdatatype_a; } else { - dns_name_dup(dns_fixedname_name(&fname), fctx->mctx, - &fctx->qminname); + dns_name_copy(name, fctx->qminname); fctx->qmintype = dns_rdatatype_ns; } fctx->minimized = true; } else { /* Minimization is done, we'll ask for whole qname */ fctx->qmintype = fctx->type; - dns_name_dup(&fctx->name, fctx->mctx, &fctx->qminname); + dns_name_copy(fctx->name, fctx->qminname); fctx->minimized = false; } char domainbuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&fctx->qminname, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->qminname, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(5), "QNAME minimization - %s minimized, qmintype %d " @@ -10901,13 +10396,16 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, REQUIRE(sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)); REQUIRE(fetchp != NULL && *fetchp == NULL); + if (atomic_load_acquire(&res->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + log_fetch(name, type); - /* - * XXXRTH use a mempool? - */ fetch = isc_mem_get(res->mctx, sizeof(*fetch)); - fetch->mctx = NULL; + *fetch = (dns_fetch_t){ 0 }; + + dns_resolver_attach(res, &fetch->res); isc_mem_attach(res->mctx, &fetch->mctx); bucketnum = dns_name_fullhash(name, false) % res->nbuckets; @@ -10962,7 +10460,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, } if (fctx == NULL) { - result = fctx_create(res, name, type, domain, nameservers, + result = fctx_create(res, task, name, type, domain, nameservers, client, options, bucketnum, depth, qc, &fctx); if (result != ISC_R_SUCCESS) { @@ -10979,8 +10477,8 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, if (result == ISC_R_SUCCESS && ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0)) { - fctx_add_event(fctx, task, client, id, action, arg, fetch, - DNS_EVENT_TRYSTALE); + fctx_add_event(fctx, task, client, id, action, arg, NULL, NULL, + fetch, DNS_EVENT_TRYSTALE); } if (new_fctx) { @@ -10995,8 +10493,9 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, isc_task_send(res->buckets[bucketnum].task, &event); } else { /* - * We don't care about the result of fctx_unlink() - * since we know we're not exiting. + * We don't care about the result of + * fctx_unlink() since we know we're not + * exiting. */ (void)fctx_unlink(fctx); dodestroy = true; @@ -11014,6 +10513,7 @@ unlock: FTRACE("created"); *fetchp = fetch; } else { + dns_resolver_detach(&fetch->res); isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch)); } @@ -11081,7 +10581,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { REQUIRE(DNS_FETCH_VALID(fetch)); fctx = fetch->private; REQUIRE(VALID_FCTX(fctx)); - res = fctx->res; + res = fetch->res; FTRACE("destroyfetch"); @@ -11109,6 +10609,8 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { if (bucket_empty) { empty_bucket(res); } + + dns_resolver_detach(&res); } void @@ -11128,7 +10630,7 @@ dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, INSIST(fctx->exitline >= 0); if (!fctx->logged || duplicateok) { - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(lctx, category, module, level, "fetch completed at %s:%d for %s in " "%" PRIu64 "." @@ -11169,12 +10671,6 @@ dns_resolver_dispatchv6(dns_resolver_t *resolver) { return (dns_dispatchset_get(resolver->dispatches6)); } -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver) { - REQUIRE(VALID_RESOLVER(resolver)); - return (resolver->socketmgr); -} - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); @@ -11279,15 +10775,9 @@ void dns_resolver_reset_algorithms(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms != NULL) { dns_rbt_destroy(&resolver->algorithms); } -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ } isc_result_t @@ -11310,9 +10800,6 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, return (ISC_R_RANGE); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms == NULL) { result = dns_rbt_create(resolver->mctx, free_algorithm, resolver->mctx, &resolver->algorithms); @@ -11345,7 +10832,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, memmove(tmp, algorithms, *algorithms); } tmp[len - 1] |= mask; - /* 'tmp[0]' should contain the length of 'tmp'. */ + /* tmp[0] should contain the length of 'tmp'. */ *tmp = len; node->data = tmp; /* Free the older bitfield. */ @@ -11359,9 +10846,6 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, } result = ISC_R_SUCCESS; cleanup: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ return (result); } @@ -11383,9 +10867,6 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, return (false); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms == NULL) { goto unlock; } @@ -11399,9 +10880,6 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, } } unlock: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (found) { return (false); } @@ -11421,15 +10899,9 @@ void dns_resolver_reset_ds_digests(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->digests != NULL) { dns_rbt_destroy(&resolver->digests); } -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ } isc_result_t @@ -11451,9 +10923,6 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name, return (ISC_R_RANGE); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->digests == NULL) { result = dns_rbt_create(resolver->mctx, free_digest, resolver->mctx, &resolver->digests); @@ -11496,9 +10965,6 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name, } result = ISC_R_SUCCESS; cleanup: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ return (result); } @@ -11514,9 +10980,6 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver, REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (resolver->digests == NULL) { goto unlock; } @@ -11530,9 +10993,6 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver, } } unlock: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (found) { return (false); } @@ -11543,15 +11003,9 @@ void dns_resolver_resetmustbesecure(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure != NULL) { dns_rbt_destroy(&resolver->mustbesecure); } -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ } static bool yes = true, no = false; @@ -11563,9 +11017,6 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name, REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure == NULL) { result = dns_rbt_create(resolver->mctx, NULL, NULL, &resolver->mustbesecure); @@ -11576,9 +11027,6 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name, result = dns_rbt_addname(resolver->mustbesecure, name, value ? &yes : &no); cleanup: -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ return (result); } @@ -11590,9 +11038,6 @@ dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_read); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure == NULL) { goto unlock; } @@ -11601,9 +11046,6 @@ dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) { value = *(bool *)data; } unlock: -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read); -#endif /* if USE_MBSLOCK */ return (value); } @@ -11758,7 +11200,9 @@ dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format, fc = ISC_LIST_NEXT(fc, link)) { dns_name_print(fc->domain, fp); - fprintf(fp, ": %u active (%u spilled, %u allowed)\n", + fprintf(fp, + ": %u active (%u spilled, %u " + "allowed)\n", fc->count, fc->dropped, fc->allowed); } UNLOCK(&resolver->dbuckets[i].lock); diff --git a/lib/dns/tcpmsg.c b/lib/dns/tcpmsg.c deleted file mode 100644 index 47e1d2e19f..0000000000 --- a/lib/dns/tcpmsg.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -/*! \file */ - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef TCPMSG_DEBUG -#include /* Required for printf. */ -#define XDEBUG(x) printf x -#else /* ifdef TCPMSG_DEBUG */ -#define XDEBUG(x) -#endif /* ifdef TCPMSG_DEBUG */ - -#define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm') -#define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC) - -static void -recv_length(isc_task_t *, isc_event_t *); -static void -recv_message(isc_task_t *, isc_event_t *); - -static void -recv_length(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - isc_event_t *dev; - dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_region_t region; - isc_result_t result; - - INSIST(VALID_TCPMSG(tcpmsg)); - - dev = &tcpmsg->event; - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - /* - * Success. - */ - tcpmsg->size = ntohs(tcpmsg->size); - if (tcpmsg->size == 0) { - tcpmsg->result = ISC_R_UNEXPECTEDEND; - goto send_and_free; - } - if (tcpmsg->size > tcpmsg->maxsize) { - tcpmsg->result = ISC_R_RANGE; - goto send_and_free; - } - - region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size); - region.length = tcpmsg->size; - if (region.base == NULL) { - tcpmsg->result = ISC_R_NOMEMORY; - goto send_and_free; - } - XDEBUG(("Allocated %d bytes\n", tcpmsg->size)); - - isc_buffer_init(&tcpmsg->buffer, region.base, region.length); - result = isc_socket_recv(tcpmsg->sock, ®ion, 0, task, recv_message, - tcpmsg); - if (result != ISC_R_SUCCESS) { - tcpmsg->result = result; - goto send_and_free; - } - - isc_event_free(&ev_in); - return; - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); - return; -} - -static void -recv_message(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - isc_event_t *dev; - dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; - - (void)task; - - INSIST(VALID_TCPMSG(tcpmsg)); - - dev = &tcpmsg->event; - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - tcpmsg->result = ISC_R_SUCCESS; - isc_buffer_add(&tcpmsg->buffer, ev->n); - - XDEBUG(("Received %u bytes (of %d)\n", ev->n, tcpmsg->size)); - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); -} - -void -dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) { - REQUIRE(mctx != NULL); - REQUIRE(sock != NULL); - REQUIRE(tcpmsg != NULL); - - tcpmsg->magic = TCPMSG_MAGIC; - tcpmsg->size = 0; - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - tcpmsg->maxsize = 65535; /* Largest message possible. */ - tcpmsg->mctx = mctx; - tcpmsg->sock = sock; - tcpmsg->task = NULL; /* None yet. */ - tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */ - - /* Should probably initialize the event here, but it can wait. */ -} - -void -dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(maxsize < 65536); - - tcpmsg->maxsize = maxsize; -} - -isc_result_t -dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task, - isc_taskaction_t action, void *arg) { - isc_result_t result; - isc_region_t region; - - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(task != NULL); - REQUIRE(tcpmsg->task == NULL); /* not currently in use */ - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, - tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - } - - tcpmsg->task = task; - tcpmsg->action = action; - tcpmsg->arg = arg; - tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */ - - ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0, - DNS_EVENT_TCPMSG, action, arg, tcpmsg, NULL, NULL); - - region.base = (unsigned char *)&tcpmsg->size; - region.length = 2; /* uint16_t */ - result = isc_socket_recv(tcpmsg->sock, ®ion, 0, tcpmsg->task, - recv_length, tcpmsg); - - if (result != ISC_R_SUCCESS) { - tcpmsg->task = NULL; - } - - return (result); -} - -void -dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV); -} - -void -dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(buffer != NULL); - - *buffer = tcpmsg->buffer; - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; -} - -#if 0 -void -dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - if (tcpmsg->buffer.base == NULL) { - return; - } - - isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; -} -#endif /* if 0 */ - -void -dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - tcpmsg->magic = 0; - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, - tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - } -} diff --git a/lib/dns/tests/Makefile.am b/lib/dns/tests/Makefile.am index bc7250600f..a90f97c79e 100644 --- a/lib/dns/tests/Makefile.am +++ b/lib/dns/tests/Makefile.am @@ -3,6 +3,7 @@ include $(top_srcdir)/Makefile.top AM_CPPFLAGS += \ $(LIBISC_CFLAGS) \ $(LIBDNS_CFLAGS) \ + $(LIBUV_CFLAGS) \ $(KRB5_CFLAGS) \ -DSRCDIR=\"$(abs_srcdir)\" \ -DBUILDDIR=\"$(abs_builddir)\" @@ -10,6 +11,7 @@ AM_CPPFLAGS += \ LDADD += \ libdnstest.la \ $(LIBISC_LIBS) \ + $(LIBUV_LIBS) \ $(LIBDNS_LIBS) check_LTLIBRARIES = libdnstest.la diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index a425091bf6..8b64c82ce0 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -20,16 +20,16 @@ #include #include #include +#include #define UNIT_TESTING #include -#include #include +#include #include #include #include -#include #include #include @@ -38,18 +38,129 @@ #include "dnstest.h" +uv_sem_t sem; + +/* Timeouts in miliseconds */ +#define T_SERVER_INIT 5000 +#define T_SERVER_IDLE 5000 +#define T_SERVER_KEEPALIVE 5000 +#define T_SERVER_ADVERTISED 5000 + +#define T_CLIENT_INIT 2000 +#define T_CLIENT_IDLE 2000 +#define T_CLIENT_KEEPALIVE 2000 +#define T_CLIENT_ADVERTISED 2000 + +#define T_CLIENT_CONNECT 1000 + dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatchset_t *dset = NULL; +isc_nm_t *connect_nm = NULL; +static isc_sockaddr_t udp_server_addr; +static isc_sockaddr_t udp_connect_addr; +static isc_sockaddr_t tcp_server_addr; +static isc_sockaddr_t tcp_connect_addr; + +const struct in6_addr in6addr_blackhole = { { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1 } } }; + +static int +setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { + socklen_t addrlen = sizeof(*addr); + uv_os_sock_t fd; + int r; + + isc_sockaddr_fromin6(addr, &in6addr_loopback, 0); + + fd = socket(AF_INET6, family, 0); + if (fd < 0) { + perror("setup_ephemeral_port: socket()"); + return (-1); + } + + r = bind(fd, (const struct sockaddr *)&addr->type.sa, + sizeof(addr->type.sin6)); + if (r != 0) { + perror("setup_ephemeral_port: bind()"); + close(fd); + return (r); + } + + r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen); + if (r != 0) { + perror("setup_ephemeral_port: getsockname()"); + close(fd); + return (r); + } + +#if IPV6_RECVERR +#define setsockopt_on(socket, level, name) \ + setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) + + r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR); + if (r != 0) { + perror("setup_ephemeral_port"); + close(fd); + return (r); + } +#endif + + return (fd); +} + +static void +reset_testdata(void); static int _setup(void **state) { isc_result_t result; + uv_os_sock_t sock = -1; + int r; UNUSED(state); result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); + udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); + + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + udp_server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&udp_server_addr, SOCK_DGRAM); + if (sock < 0) { + return (-1); + } + close(sock); + + tcp_server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&tcp_server_addr, SOCK_STREAM); + if (sock < 0) { + return (-1); + } + close(sock); + + /* Create a secondary network manager */ + isc_managers_create(dt_mctx, ncpus, 0, 0, &connect_nm, NULL, NULL, + NULL); + + isc_nm_settimeouts(netmgr, T_SERVER_INIT, T_SERVER_IDLE, + T_SERVER_KEEPALIVE, T_SERVER_ADVERTISED); + + /* + * Use shorter client-side timeouts, to ensure that clients + * time out before the server. + */ + isc_nm_settimeouts(connect_nm, T_CLIENT_INIT, T_CLIENT_IDLE, + T_CLIENT_KEEPALIVE, T_CLIENT_ADVERTISED); + + r = uv_sem_init(&sem, 0); + assert_int_equal(r, 0); + + reset_testdata(); + return (0); } @@ -57,6 +168,11 @@ static int _teardown(void **state) { UNUSED(state); + uv_sem_destroy(&sem); + + isc_managers_destroy(&connect_nm, NULL, NULL, NULL); + assert_null(connect_nm); + dns_test_end(); return (0); @@ -66,24 +182,20 @@ static isc_result_t make_dispatchset(unsigned int ndisps) { isc_result_t result; isc_sockaddr_t any; - unsigned int attrs; dns_dispatch_t *disp = NULL; - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); if (result != ISC_R_SUCCESS) { return (result); } isc_sockaddr_any(&any); - attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &any, 512, - 6, 1024, 17, 19, attrs, &disp); + result = dns_dispatch_createudp(dispatchmgr, &any, &disp); if (result != ISC_R_SUCCESS) { return (result); } - result = dns_dispatchset_create(dt_mctx, socketmgr, taskmgr, disp, - &dset, ndisps); + result = dns_dispatchset_create(dt_mctx, disp, &dset, ndisps); dns_dispatch_detach(&disp); return (result); @@ -95,7 +207,7 @@ reset(void) { dns_dispatchset_destroy(&dset); } if (dispatchmgr != NULL) { - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } } @@ -157,149 +269,197 @@ dispatchset_get(void **state) { reset(); } +struct { + atomic_uint_fast32_t responses; + atomic_uint_fast32_t result; +} testdata; + +static dns_dispatch_t *dispatch = NULL; +static dns_dispentry_t *dispentry = NULL; +static atomic_bool first = ATOMIC_VAR_INIT(true); + static void -senddone(isc_task_t *task, isc_event_t *event) { - isc_socket_t *sock = event->ev_arg; - - UNUSED(task); - - isc_socket_detach(&sock); - isc_event_free(&event); +reset_testdata(void) { + atomic_init(&testdata.responses, 0); + atomic_init(&testdata.result, ISC_R_UNSET); } static void -nameserver(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_region_t region; - isc_socket_t *dummy; - isc_socket_t *sock = event->ev_arg; - isc_socketevent_t *ev = (isc_socketevent_t *)event; +server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(cbarg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + return; +} + +static void +nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *cbarg) { + isc_region_t response; static unsigned char buf1[16]; static unsigned char buf2[16]; - memmove(buf1, ev->region.base, 12); + UNUSED(eresult); + UNUSED(cbarg); + + memmove(buf1, region->base, 12); memset(buf1 + 12, 0, 4); buf1[2] |= 0x80; /* qr=1 */ - memmove(buf2, ev->region.base, 12); + memmove(buf2, region->base, 12); memset(buf2 + 12, 1, 4); buf2[2] |= 0x80; /* qr=1 */ /* * send message to be discarded. */ - region.base = buf1; - region.length = sizeof(buf1); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } + response.base = buf1; + response.length = sizeof(buf1); + isc_nm_send(handle, &response, server_senddone, NULL); /* * send nextitem message. */ - region.base = buf2; - region.length = sizeof(buf2); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } - isc_event_free(&event); + response.base = buf2; + response.length = sizeof(buf2); + isc_nm_send(handle, &response, server_senddone, NULL); } -static dns_dispatch_t *dispatch = NULL; -static dns_dispentry_t *dispentry = NULL; -static atomic_bool first = ATOMIC_VAR_INIT(true); -static isc_sockaddr_t local; -static atomic_uint_fast32_t responses; +static isc_result_t +accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(cbarg); + + return (eresult); +} static void -response(isc_task_t *task, isc_event_t *event) { - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - bool exp_true = true; +noop_nameserver(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(region); + UNUSED(cbarg); +} - UNUSED(task); +static void +response_getnext(isc_result_t result, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); - atomic_fetch_add_relaxed(&responses, 1); - if (atomic_compare_exchange_strong(&first, &exp_true, false)) { - isc_result_t result = dns_dispatch_getnext(dispentry, &devent); + atomic_fetch_add_relaxed(&testdata.responses, 1); + + if (atomic_compare_exchange_strong(&first, &(bool){ true }, false)) { + result = dns_dispatch_getnext(dispentry); assert_int_equal(result, ISC_R_SUCCESS); } else { - dns_dispatch_removeresponse(&dispentry, &devent); - isc_app_shutdown(); + uv_sem_post(&sem); } } static void -startit(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_socket_t *sock = NULL; +response(isc_result_t eresult, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); - isc_socket_attach(dns_dispatch_getsocket(dispatch), &sock); - result = isc_socket_sendto(sock, event->ev_arg, task, senddone, sock, - &local, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - isc_event_free(&event); + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + switch (eresult) { + case ISC_R_EOF: + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + break; + default: + atomic_fetch_add_relaxed(&testdata.responses, 1); + atomic_store_relaxed(&testdata.result, eresult); + } + + uv_sem_post(&sem); } -/* test dispatch getnext */ static void -dispatch_getnext(void **state) { - isc_region_t region; +response_timeout(isc_result_t eresult, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + atomic_store_relaxed(&testdata.result, eresult); + + uv_sem_post(&sem); +} + +static void +connected(isc_result_t eresult, isc_region_t *region, void *cbarg) { + isc_region_t *r = (isc_region_t *)cbarg; + + UNUSED(eresult); + UNUSED(region); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + dns_dispatch_send(dispentry, r, -1); +} + +static void +client_senddone(isc_result_t eresult, isc_region_t *region, void *cbarg) { + UNUSED(eresult); + UNUSED(region); + UNUSED(cbarg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + return; +} + +static void +timeout_connected(isc_result_t eresult, isc_region_t *region, void *cbarg) { + UNUSED(region); + UNUSED(cbarg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + atomic_store_relaxed(&testdata.result, eresult); + + uv_sem_post(&sem); +} + +static void +dispatch_timeout_tcp_connect(void **state) { isc_result_t result; - isc_socket_t *sock = NULL; - isc_task_t *task = NULL; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; uint16_t id; - struct in_addr ina; - unsigned char message[12]; - unsigned int attrs; - unsigned char rbuf[12]; UNUSED(state); - atomic_init(&responses, 0); + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_blackhole, 0); - result = isc_task_create(taskmgr, 0, &task); + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); - assert_int_equal(result, ISC_R_SUCCESS); - - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, - 512, 6, 1024, 17, 19, attrs, &dispatch); - assert_int_equal(result, ISC_R_SUCCESS); - - /* - * Create a local udp nameserver on the loopback. - */ - result = isc_socket_create(socketmgr, AF_INET, isc_sockettype_udp, - &sock); - assert_int_equal(result, ISC_R_SUCCESS); - - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - result = isc_socket_bind(sock, &local, 0); - assert_int_equal(result, ISC_R_SUCCESS); - - result = isc_socket_getsockname(sock, &local); + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); region.base = rbuf; region.length = sizeof(rbuf); - result = isc_socket_recv(sock, ®ion, 1, task, nameserver, sock); - assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatch_addresponse(dispatch, 0, &local, task, response, - NULL, &id, &dispentry, NULL); + result = dns_dispatch_addresponse(dispatch, 0, T_CLIENT_CONNECT, + &tcp_server_addr, timeout_connected, + client_senddone, response, ®ion, + &id, &dispentry); assert_int_equal(result, ISC_R_SUCCESS); memset(message, 0, sizeof(message)); @@ -308,31 +468,265 @@ dispatch_getnext(void **state) { region.base = message; region.length = sizeof(message); - result = isc_app_onrun(dt_mctx, task, startit, ®ion); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_app_run(); - assert_int_equal(result, ISC_R_SUCCESS); + dns_dispatch_connect(dispentry); - assert_int_equal(atomic_load_acquire(&responses), 2); + uv_sem_wait(&sem); - /* - * Shutdown nameserver. - */ - isc_socket_cancel(sock, task, ISC_SOCKCANCEL_RECV); - isc_socket_detach(&sock); - isc_task_detach(&task); + dns_dispatch_removeresponse(&dispentry); - /* - * Shutdown the dispatch. - */ dns_dispatch_detach(&dispatch); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); + + /* Skip if the IPv6 is not available or not blackholed */ + + result = atomic_load_acquire(&testdata.result); + if (result == ISC_R_ADDRNOTAVAIL || result == ISC_R_CONNREFUSED) { + skip(); + return; + } + + assert_int_equal(result, ISC_R_TIMEDOUT); +} + +static void +dispatch_timeout_tcp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, noop_nameserver, + NULL, accept_cb, NULL, 0, 0, NULL, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &tcp_server_addr, connected, + client_senddone, response_timeout, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT); + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +static void +dispatch_tcp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, nameserver, NULL, + accept_cb, NULL, 0, 0, NULL, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &tcp_server_addr, connected, + client_senddone, response, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_in_range(atomic_load_acquire(&testdata.responses), 1, 2); + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_SUCCESS); + + /* Cleanup */ + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +static void +dispatch_timeout_udp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createudp(dispatchmgr, &tcp_connect_addr, + &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_nm_listenudp(netmgr, &udp_server_addr, noop_nameserver, + NULL, 0, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &udp_server_addr, connected, + client_senddone, response_timeout, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT); + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +/* test dispatch getnext */ +static void +dispatch_getnext(void **state) { + isc_result_t result; + isc_region_t region; + isc_nmsocket_t *sock = NULL; + unsigned char message[12] = { 0 }; + unsigned char rbuf[12] = { 0 }; + uint16_t id; + + UNUSED(state); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createudp(dispatchmgr, &udp_connect_addr, + &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + /* + * Create a local udp nameserver on the loopback. + */ + result = isc_nm_listenudp(netmgr, &udp_server_addr, nameserver, NULL, 0, + &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &udp_server_addr, connected, + client_senddone, response_getnext, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.responses), 2); + + /* Cleanup */ + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); } int main(void) { const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(dispatch_timeout_tcp_connect, + _setup, _teardown), + cmocka_unit_test_setup_teardown(dispatch_timeout_tcp_response, + _setup, _teardown), + cmocka_unit_test_setup_teardown(dispatch_tcp_response, _setup, + _teardown), + cmocka_unit_test_setup_teardown(dispatch_timeout_udp_response, + _setup, _teardown), cmocka_unit_test_setup_teardown(dispatchset_create, _setup, _teardown), cmocka_unit_test_setup_teardown(dispatchset_get, _setup, diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 5a16027e48..990bc8ceb9 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,6 @@ isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *maintask = NULL; isc_timermgr_t *timermgr = NULL; -isc_socketmgr_t *socketmgr = NULL; dns_zonemgr_t *zonemgr = NULL; bool app_running = false; int ncpus; @@ -96,10 +96,11 @@ cleanup_managers(void) { isc_task_shutdown(maintask); isc_task_destroy(&maintask); } + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, taskmgr == NULL ? NULL : &taskmgr, - timermgr == NULL ? NULL : &timermgr, - socketmgr == NULL ? NULL : &socketmgr); + timermgr == NULL ? NULL : &timermgr, NULL); + if (app_running) { isc_app_finish(); } @@ -111,7 +112,7 @@ create_managers(void) { ncpus = isc_os_ncpus(); isc_managers_create(dt_mctx, ncpus, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + NULL); CHECK(isc_task_create(taskmgr, 0, &maintask)); return (ISC_R_SUCCESS); @@ -293,8 +294,7 @@ dns_test_setupzonemgr(void) { isc_result_t result; REQUIRE(zonemgr == NULL); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, - &zonemgr); + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &zonemgr); return (result); } diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index 53c7c6529f..adc88913c2 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -45,7 +45,7 @@ extern isc_log_t *lctx; extern isc_taskmgr_t *taskmgr; extern isc_task_t *maintask; extern isc_timermgr_t *timermgr; -extern isc_socketmgr_t *socketmgr; +extern isc_nm_t *netmgr; extern dns_zonemgr_t *zonemgr; extern bool app_running; extern int ncpus; diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index c115c34d8c..866498e35e 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -50,15 +50,14 @@ _setup(void **state) { result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_makeview("view", &view); assert_int_equal(result, ISC_R_SUCCESS); isc_sockaddr_any(&local); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, - 4096, 100, 100, 100, 500, 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, &local, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); @@ -70,7 +69,7 @@ _teardown(void **state) { dns_dispatch_detach(&dispatch); dns_view_detach(&view); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); dns_test_end(); return (0); @@ -80,8 +79,8 @@ static void mkres(dns_resolver_t **resolverp) { isc_result_t result; - result = dns_resolver_create(view, taskmgr, 1, 1, socketmgr, timermgr, - 0, dispatchmgr, dispatch, NULL, resolverp); + result = dns_resolver_create(view, taskmgr, 1, 1, netmgr, timermgr, 0, + dispatchmgr, dispatch, NULL, resolverp); assert_int_equal(result, ISC_R_SUCCESS); } diff --git a/lib/dns/tests/zonemgr_test.c b/lib/dns/tests/zonemgr_test.c index ca7559e181..694401e871 100644 --- a/lib/dns/tests/zonemgr_test.c +++ b/lib/dns/tests/zonemgr_test.c @@ -62,7 +62,7 @@ zonemgr_create(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -80,7 +80,7 @@ zonemgr_managezone(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -121,7 +121,7 @@ zonemgr_createzone(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -160,7 +160,7 @@ zonemgr_unreachable(void **state) { TIME_NOW(&now); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 18c35466e8..1ea26f8343 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -576,8 +576,8 @@ fetch_callback_ds(isc_task_t *task, isc_event_t *event) { } else if (eresult == DNS_R_SERVFAIL) { goto unexpected; } else if (eresult != DNS_R_CNAME && - isdelegation(dns_fixedname_name(&devent->foundname), - &val->frdataset, eresult)) + isdelegation(devent->foundname, &val->frdataset, + eresult)) { /* * Failed to find a DS while trying to prove diff --git a/lib/dns/view.c b/lib/dns/view.c index 27df703811..ed2045f131 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -634,6 +634,7 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { dns_zone_t *mkzone = NULL, *rdzone = NULL; isc_refcount_destroy(&view->references); + if (!RESSHUTDOWN(view)) { dns_resolver_shutdown(view->resolver); } @@ -643,14 +644,14 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { if (!REQSHUTDOWN(view)) { dns_requestmgr_shutdown(view->requestmgr); } - LOCK(&view->lock); - if (view->zonetable != NULL) { - if (view->flush) { - dns_zt_flushanddetach(&view->zonetable); - } else { - dns_zt_detach(&view->zonetable); - } + + if (view->zonetable != NULL && view->flush) { + dns_zt_flushanddetach(&view->zonetable); + } else if (view->zonetable != NULL) { + dns_zt_detach(&view->zonetable); } + + LOCK(&view->lock); if (view->managed_keys != NULL) { mkzone = view->managed_keys; view->managed_keys = NULL; @@ -796,9 +797,9 @@ dns_view_createzonetable(dns_view_t *view) { isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6) { isc_result_t result; @@ -815,8 +816,8 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, } isc_task_setname(view->task, "view", view); - result = dns_resolver_create(view, taskmgr, ntasks, ndisp, socketmgr, - timermgr, options, dispatchmgr, dispatchv4, + result = dns_resolver_create(view, taskmgr, ntasks, ndisp, nm, timermgr, + options, dispatchmgr, dispatchv4, dispatchv6, &view->resolver); if (result != ISC_R_SUCCESS) { isc_task_detach(&view->task); @@ -841,11 +842,10 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, atomic_fetch_and(&view->attributes, ~DNS_VIEWATTR_ADBSHUTDOWN); isc_refcount_increment(&view->weakrefs); - result = dns_requestmgr_create(view->mctx, timermgr, socketmgr, - dns_resolver_taskmgr(view->resolver), - dns_resolver_dispatchmgr(view->resolver), - dispatchv4, dispatchv6, - &view->requestmgr); + result = dns_requestmgr_create( + view->mctx, dns_resolver_taskmgr(view->resolver), + dns_resolver_dispatchmgr(view->resolver), dispatchv4, + dispatchv6, &view->requestmgr); if (result != ISC_R_SUCCESS) { dns_adb_shutdown(view->adb); dns_resolver_shutdown(view->resolver); @@ -2502,12 +2502,12 @@ dns_view_setviewcommit(dns_view_t *view) { if (view->managed_keys != NULL) { dns_zone_attach(view->managed_keys, &managed_keys); } - if (view->zonetable != NULL) { - dns_zt_setviewcommit(view->zonetable); - } UNLOCK(&view->lock); + if (view->zonetable != NULL) { + dns_zt_setviewcommit(view->zonetable); + } if (redirect != NULL) { dns_zone_setviewcommit(redirect); dns_zone_detach(&redirect); diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 0d2930506b..0dc3088397 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -957,7 +956,6 @@ xfrin_start(dns_xfrin_ctx_t *xfr) { ISC_UNREACHABLE(); } - /* TODO isc_socket_dscp(xfr->socket, xfr->dscp); */ return (ISC_R_SUCCESS); failure: @@ -1036,6 +1034,7 @@ xfrin_connect_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { xfr->handle = handle; sockaddr = isc_nmhandle_peeraddr(handle); isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext)); + /* TODO set DSCP */ if (xfr->tsigkey != NULL && xfr->tsigkey->key != NULL) { dns_name_format(dst_key_name(xfr->tsigkey->key), signerbuf, diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 7bd8c05c9b..5fbe523b22 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -590,7 +590,6 @@ struct dns_zonemgr { isc_refcount_t refs; isc_taskmgr_t *taskmgr; isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; isc_nm_t *netmgr; isc_taskpool_t *zonetasks; isc_taskpool_t *loadtasks; @@ -14011,8 +14010,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { result = dns_request_getresponse(revent->request, msg, 0); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_INFO, - "refresh: failure trying master " - "%s (source %s): %s", + "refresh: unable to get response, master " + "%s, source %s: %s", master, source, dns_result_totext(result)); goto next_master; } @@ -14603,8 +14602,7 @@ again: zone->task, refresh_callback, zone, &zone->request); if (result != ISC_R_SUCCESS) { zone_idetach(&dummy); - zone_debuglog(zone, me, 1, - "dns_request_createvia4() failed: %s", + zone_debuglog(zone, me, 1, "dns_request_createvia() failed: %s", dns_result_totext(result)); goto skip_master; } else { @@ -18736,8 +18734,8 @@ zonemgr_keymgmt_find(dns_zonemgr_t *zmgr, dns_zone_t *zone, isc_result_t dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, - isc_nm_t *netmgr, dns_zonemgr_t **zmgrp) { + isc_timermgr_t *timermgr, isc_nm_t *netmgr, + dns_zonemgr_t **zmgrp) { dns_zonemgr_t *zmgr; isc_result_t result; @@ -18747,7 +18745,6 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_mem_attach(mctx, &zmgr->mctx); zmgr->taskmgr = taskmgr; zmgr->timermgr = timermgr; - zmgr->socketmgr = socketmgr; zmgr->netmgr = netmgr; zmgr->zonetasks = NULL; zmgr->loadtasks = NULL; diff --git a/lib/dns/zt.c b/lib/dns/zt.c index 8ca9cd65aa..da4f222ab6 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -483,6 +483,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { REQUIRE(VALID_ZT(zt)); + RWLOCK(&zt->rwlock, isc_rwlocktype_read); dns_rbtnodechain_init(&chain); result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); @@ -496,6 +497,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { } dns_rbtnodechain_invalidate(&chain); + RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); } void diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 19cc946bc3..b198713092 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -160,6 +160,12 @@ isc_nmhandle_cleartimeout(isc_nmhandle_t *handle); * a TCPDNS socket wrapping a TCP connection), the timer is set for * both socket layers. */ +bool +isc_nmhandle_timer_running(isc_nmhandle_t *handle); +/*%< + * Return true if the timer for the socket connected to 'handle' + * is running. + */ void isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value); @@ -450,6 +456,16 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats); * full range of socket-related stats counter numbers. */ +isc_result_t +isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type); +/*%< + * Check whether the specified address is available on the local system + * by opening a socket and immediately closing it. + * + * Requires: + *\li 'addr' is not NULL. + */ + void isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index ad6cf29603..23630bdaa5 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -225,12 +225,6 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, *\li #ISC_R_UNEXPECTED */ -isc_result_t -isc_socket_dup(isc_socket_t *sock0, isc_socket_t **socketp); -/*%< - * Duplicate an existing socket, reusing its file descriptor. - */ - void isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how); /*%< diff --git a/lib/isc/include/isc/time.h b/lib/isc/include/isc/time.h index adf56fc19d..6946ecbb3c 100644 --- a/lib/isc/include/isc/time.h +++ b/lib/isc/include/isc/time.h @@ -71,6 +71,16 @@ isc_interval_iszero(const isc_interval_t *i); *\li 'i' is a valid pointer. */ +unsigned int +isc_interval_ms(const isc_interval_t *i); +/*%< + * Returns interval 'i' expressed as a number of milliseconds. + * + * Requires: + * + *\li 'i' is a valid pointer. + */ + /*** *** Absolute Times ***/ diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 84f3be07e1..2890b56a3f 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -98,7 +98,6 @@ typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t; #endif /* HAVE_LIBNGHTTP2 */ typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); -typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int); /* The following cannot be listed alphabetically due to forward reference */ typedef isc_result_t(isc_httpdaction_t)( diff --git a/lib/isc/managers.c b/lib/isc/managers.c index f86d4c8485..628dd33fa9 100644 --- a/lib/isc/managers.c +++ b/lib/isc/managers.c @@ -91,7 +91,7 @@ isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp, /* * If we have a taskmgr to clean up, then we must also have a netmgr. */ - REQUIRE(taskmgrp != NULL || netmgrp == NULL); + REQUIRE(taskmgrp == NULL || netmgrp != NULL); /* * The sequence of operations here is important: diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index abca92731c..faba79a803 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -222,13 +222,6 @@ http_session_active(isc_nm_http_session_t *session) { return (!session->closed && !session->closing); } -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - static void * http_malloc(size_t sz, isc_mem_t *mctx) { return (isc_mem_allocate(mctx, sz)); @@ -1461,7 +1454,7 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, } isc__nmsocket_clearcb(sock); - isc__nm_connectcb(sock, req, ISC_R_CANCELED, true); + isc__nm_connectcb(sock, req, ISC_R_SHUTTINGDOWN, true); isc__nmsocket_prep_destroy(sock); isc__nmsocket_detach(&sock); return; @@ -2154,7 +2147,8 @@ server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, isc_result_t result = ISC_R_SUCCESS; isc_nm_cb_t cb = req->cb.send; void *cbarg = req->cbarg; - if (inactive(sock) || !http_session_active(handle->httpsession)) { + if (isc__nmsocket_closing(sock) || + !http_session_active(handle->httpsession)) { failed_send_cb(sock, req, ISC_R_CANCELED); return; } @@ -2381,7 +2375,7 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { * function gets invoked, so we need to do extra sanity checks to * detect this case. */ - if (inactive(handle->sock) || httpserver == NULL) { + if (isc__nmsocket_closing(handle->sock) || httpserver == NULL) { return (ISC_R_CANCELED); } @@ -2393,8 +2387,9 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { REQUIRE(VALID_NMSOCK(httplistensock)); INSIST(httplistensock == httpserver); - if (inactive(httplistensock) || - !atomic_load(&httplistensock->listening)) { + if (isc__nmsocket_closing(httplistensock) || + !atomic_load(&httplistensock->listening)) + { return (ISC_R_CANCELED); } @@ -3041,7 +3036,7 @@ isc__nm_http_cleartimeout(isc_nmhandle_t *handle) { REQUIRE(handle->sock->type == isc_nm_httpsocket); sock = handle->sock; - if (sock->h2.session != NULL && sock->h2.session->handle) { + if (sock->h2.session != NULL && sock->h2.session->handle != NULL) { INSIST(VALID_HTTP2_SESSION(sock->h2.session)); INSIST(VALID_NMHANDLE(sock->h2.session->handle)); isc_nmhandle_cleartimeout(sock->h2.session->handle); @@ -3057,7 +3052,7 @@ isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { REQUIRE(handle->sock->type == isc_nm_httpsocket); sock = handle->sock; - if (sock->h2.session != NULL && sock->h2.session->handle) { + if (sock->h2.session != NULL && sock->h2.session->handle != NULL) { INSIST(VALID_HTTP2_SESSION(sock->h2.session)); INSIST(VALID_NMHANDLE(sock->h2.session->handle)); isc_nmhandle_settimeout(sock->h2.session->handle, timeout); diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 60d6b83c51..e5a02343b8 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -976,8 +976,8 @@ struct isc_nmsocket { atomic_bool listening; atomic_bool connecting; atomic_bool connected; - bool accepting; - bool reading; + atomic_bool accepting; + atomic_bool reading; isc_refcount_t references; /*% diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 6f10061fcd..b67a94e246 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -1915,7 +1915,7 @@ isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, void isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); + REQUIRE(atomic_load(&sock->accepting)); REQUIRE(sock->server); /* @@ -1929,7 +1929,7 @@ isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { isc__nmsocket_detach(&sock->server); - sock->accepting = false; + atomic_store(&sock->accepting, false); switch (eresult) { case ISC_R_NOTCONNECTED: @@ -2024,11 +2024,13 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); if (atomic_load(&sock->client)) { uv_timer_stop(timer); + sock->recv_read = false; + if (sock->recv_cb != NULL) { isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nm_readcb(sock, req, ISC_R_TIMEDOUT); @@ -2172,7 +2174,7 @@ void isc__nm_start_reading(isc_nmsocket_t *sock) { int r; - if (sock->reading) { + if (atomic_load(&sock->reading)) { return; } @@ -2198,14 +2200,14 @@ isc__nm_start_reading(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } RUNTIME_CHECK(r == 0); - sock->reading = true; + atomic_store(&sock->reading, true); } void isc__nm_stop_reading(isc_nmsocket_t *sock) { int r; - if (!sock->reading) { + if (!atomic_load(&sock->reading)) { return; } @@ -2223,7 +2225,7 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } RUNTIME_CHECK(r == 0); - sock->reading = false; + atomic_store(&sock->reading, false); } bool @@ -2234,7 +2236,7 @@ isc__nm_closing(isc_nmsocket_t *sock) { bool isc__nmsocket_closing(isc_nmsocket_t *sock) { return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || + isc__nm_closing(sock) || (sock->server != NULL && !isc__nmsocket_active(sock->server))); } @@ -2260,8 +2262,8 @@ processbuffer(isc_nmsocket_t *sock) { * Stop reading if this is a client socket, or if the server socket * has been set to sequential mode, or the number of queries we are * processing simultaneously has reached the clients-per-connection - * limit. In this case we'll be called again by resume_processing() - * later. + * limit. In this case we'll be called again later by + * isc__nm_resume_processing(). */ void isc__nm_process_sock_buffer(isc_nmsocket_t *sock) { @@ -2402,6 +2404,14 @@ isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) { } } +bool +isc_nmhandle_timer_running(isc_nmhandle_t *handle) { + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(VALID_NMSOCK(handle->sock)); + + return (isc__nmsocket_timer_running(handle->sock)); +} + void * isc_nmhandle_getextra(isc_nmhandle_t *handle) { REQUIRE(VALID_NMHANDLE(handle)); @@ -2527,13 +2537,6 @@ void isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(VALID_NMHANDLE(handle)); - /* - * This is always called via callback (from accept or connect), and - * caller must attach to the handle, so the references always need to be - * at least 2. - */ - REQUIRE(isc_refcount_current(&handle->references) >= 2); - switch (handle->sock->type) { case isc_nm_udpsocket: isc__nm_udp_read(handle, cb, cbarg); @@ -3130,6 +3133,45 @@ isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) { return (ISC_R_NOTIMPLEMENTED); } +isc_result_t +isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type) { + int proto, pf, addrlen, fd, r; + + REQUIRE(addr != NULL); + + switch (type) { + case isc_socktype_tcp: + proto = SOCK_STREAM; + break; + case isc_socktype_udp: + proto = SOCK_DGRAM; + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + + pf = isc_sockaddr_pf(addr); + if (pf == AF_INET) { + addrlen = sizeof(struct sockaddr_in); + } else { + addrlen = sizeof(struct sockaddr_in6); + } + + fd = socket(pf, proto, 0); + if (fd < 0) { + return (isc_errno_toresult(errno)); + } + + r = bind(fd, (const struct sockaddr *)&addr->type.sa, addrlen); + if (r < 0) { + close(fd); + return (isc_errno_toresult(errno)); + } + + close(fd); + return (ISC_R_SUCCESS); +} + #if defined(TCP_CONNECTIONTIMEOUT) #define TIMEOUT_TYPE int #define TIMEOUT_DIV 1000 @@ -3311,11 +3353,10 @@ isc_nm_sequential(isc_nmhandle_t *handle) { * We don't want pipelining on this connection. That means * that we need to pause after reading each request, and * resume only after the request has been processed. This - * is done in resume_processing(), which is the socket's - * closehandle_cb callback, called whenever a handle + * is done in isc__nm_resume_processing(), which is the + * socket's closehandle_cb callback, called whenever a handle * is released. */ - isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); atomic_store(&sock->sequential, true); @@ -3421,7 +3462,7 @@ nmsocket_dump(isc_nmsocket_t *sock) { atomic_load(&sock->closing) ? " closing" : "", atomic_load(&sock->destroying) ? " destroying" : "", atomic_load(&sock->connecting) ? " connecting" : "", - sock->accepting ? " accepting" : ""); + atomic_load(&sock->accepting) ? " accepting" : ""); fprintf(stderr, "Created by:\n"); isc_backtrace_symbols_fd(sock->backtrace, sock->backtrace_size, STDERR_FILENO); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 382a8360c9..e5bbd1822b 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -86,7 +86,7 @@ stop_tcp_child(isc_nmsocket_t *sock); static void failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); + REQUIRE(atomic_load(&sock->accepting)); REQUIRE(sock->server); /* @@ -100,7 +100,7 @@ failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { isc__nmsocket_detach(&sock->server); - sock->accepting = false; + atomic_store(&sock->accepting, false); switch (eresult) { case ISC_R_NOTCONNECTED: @@ -250,7 +250,11 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) { isc__nm_uvreq_put(&req, sock); return; } else if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tcp_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -732,8 +736,6 @@ isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tcpsocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -770,7 +772,7 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(worker); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -833,7 +835,7 @@ isc__nm_tcp_resumeread(isc_nmhandle_t *handle) { } if (!isc__nmsocket_active(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -856,7 +858,7 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -895,7 +897,7 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { isc__nm_readcb(sock, req, ISC_R_SUCCESS); /* The readcb could have paused the reading */ - if (sock->reading) { + if (atomic_load(&sock->reading)) { /* The timer will be updated */ isc__nmsocket_timer_restart(sock); } @@ -973,7 +975,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[isc_nm_tid()]; @@ -1024,7 +1026,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { goto failure; } - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1354,7 +1356,7 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { return; } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } @@ -1366,7 +1368,11 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { } if (sock->statichandle != NULL) { - isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index b5d2d248ce..9f4a7fc595 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -107,7 +107,7 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { RUNTIME_CHECK(r == 0); if (isc__nm_closing(sock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } @@ -217,7 +217,11 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMHANDLE(req->handle)); if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tcpdns_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -690,8 +694,6 @@ isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tcpdnssocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -729,7 +731,7 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -780,8 +782,8 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_UVREQ(req)); /* - * We need to launch the resume_processing after the buffer has - * been consumed, thus we need to delay the detaching the handle. + * We need to launch isc__nm_resume_processing() after the buffer + * has been consumed, thus we must delay detaching the handle. */ isc_nmhandle_attach(req->handle, &handle); @@ -800,9 +802,10 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { sock->recv_read = false; /* - * The assertion failure here means that there's a errnoneous extra - * nmhandle detach happening in the callback and resume_processing gets - * called while we are still processing the buffer. + * An assertion failure here means that there's an erroneous + * extra nmhandle detach happening in the callback and + * isc__nm_resume_processing() is called while we're + * processing the buffer. */ REQUIRE(sock->processing == false); sock->processing = true; @@ -829,7 +832,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -949,7 +952,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[csock->tid]; @@ -1007,7 +1010,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { goto failure; } - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1056,13 +1059,15 @@ failure: void isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, void *cbarg) { - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - isc_nmsocket_t *sock = handle->sock; isc__netievent_tcpdnssend_t *ievent = NULL; isc__nm_uvreq_t *uvreq = NULL; + isc_nmsocket_t *sock = NULL; + REQUIRE(VALID_NMHANDLE(handle)); + + sock = handle->sock; + + REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_tcpdnssocket); uvreq = isc__nm_uvreq_get(sock->mgr, sock); @@ -1107,24 +1112,26 @@ tcpdns_send_cb(uv_write_t *req, int status) { */ void isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) { + isc_result_t result; isc__netievent_tcpdnssend_t *ievent = (isc__netievent_tcpdnssend_t *)ev0; + isc_nmsocket_t *sock = NULL; + isc__nm_uvreq_t *uvreq = NULL; + int r, nbufs = 2; + + UNUSED(worker); REQUIRE(VALID_UVREQ(ievent->req)); REQUIRE(VALID_NMSOCK(ievent->sock)); REQUIRE(ievent->sock->type == isc_nm_tcpdnssocket); REQUIRE(ievent->sock->tid == isc_nm_tid()); - isc_result_t result; - isc_nmsocket_t *sock = ievent->sock; - isc__nm_uvreq_t *uvreq = ievent->req; + sock = ievent->sock; + uvreq = ievent->req; + uv_buf_t bufs[2] = { { .base = uvreq->tcplen, .len = 2 }, { .base = uvreq->uvbuf.base, .len = uvreq->uvbuf.len } }; - int nbufs = 2; - int r; - - UNUSED(worker); if (isc__nmsocket_closing(sock)) { result = ISC_R_CANCELED; @@ -1380,7 +1387,7 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { return; } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } @@ -1392,7 +1399,11 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { } if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index 72fe096f5c..0b3b43703a 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -124,7 +124,7 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { uv_handle_set_data((uv_handle_t *)&sock->timer, sock); if (isc__nm_closing(sock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } @@ -233,7 +233,11 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMHANDLE(req->handle)); if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -344,6 +348,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, } if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; goto failure; } @@ -373,6 +378,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, BROADCAST(&sock->scond); UNLOCK(&sock->lock); return; + failure: if (isc__nm_in_netthread()) { sock->tid = isc_nm_tid(); @@ -843,8 +849,6 @@ isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tlsdnssocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -884,7 +888,7 @@ isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -938,9 +942,8 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_UVREQ(req)); /* - * We need to launch the resume_processing after the buffer has - * been consumed, thus we need to delay the detaching the - * handle. + * We need to launch isc__nm_resume_processing() after the buffer + * has been consumed, thus we must delay detaching the handle. */ isc_nmhandle_attach(req->handle, &handle); @@ -959,10 +962,10 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { sock->recv_read = false; /* - * The assertion failure here means that there's a errnoneous + * An assertion failure here means that there's an erroneous * extra nmhandle detach happening in the callback and - * resume_processing gets called while we are still processing - * the buffer. + * isc__nm_resume_processing() is called while we're + * processing the buffer. */ REQUIRE(sock->processing == false); sock->processing = true; @@ -1278,6 +1281,8 @@ done: static void async_tlsdns_cycle(isc_nmsocket_t *sock) { + isc__netievent_tlsdnscycle_t *ievent = NULL; + REQUIRE(VALID_NMSOCK(sock)); /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ @@ -1285,8 +1290,7 @@ async_tlsdns_cycle(isc_nmsocket_t *sock) { return; } - isc__netievent_tlsdnscycle_t *ievent = - isc__nm_get_netievent_tlsdnscycle(sock->mgr, sock); + ievent = isc__nm_get_netievent_tlsdnscycle(sock->mgr, sock); isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent); } @@ -1321,7 +1325,7 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -1441,7 +1445,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[csock->tid]; @@ -1530,7 +1534,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { /* FIXME: Set SSL_MODE_RELEASE_BUFFERS */ - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1579,13 +1583,15 @@ failure: void isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, void *cbarg) { - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - isc_nmsocket_t *sock = handle->sock; isc__netievent_tlsdnssend_t *ievent = NULL; isc__nm_uvreq_t *uvreq = NULL; + isc_nmsocket_t *sock = NULL; + REQUIRE(VALID_NMHANDLE(handle)); + + sock = handle->sock; + + REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_tlsdnssocket); uvreq = isc__nm_uvreq_get(sock->mgr, sock); @@ -1936,12 +1942,14 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { (void)SSL_shutdown(sock->tls.tls); } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } /* TLS handshake hasn't been completed yet */ if (atomic_load(&sock->connecting)) { + isc_nmsocket_t *tsock = NULL; + /* * TCP connection has been established, now waiting on * TLS handshake to complete @@ -1956,14 +1964,17 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { } /* The TCP connection hasn't been established yet */ - isc_nmsocket_t *tsock = NULL; isc__nmsocket_attach(sock, &tsock); uv_close(&sock->uv_handle.handle, tlsdns_close_connect_cb); return; } if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index 8321b74f3b..49edb68191 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -83,7 +83,7 @@ inactive(isc_nmsocket_t *sock) { atomic_load(&sock->outerhandle->sock->closing) || (sock->listener != NULL && !isc__nmsocket_active(sock->listener)) || - atomic_load(&sock->mgr->closing)); + isc__nm_closing(sock)); } static void @@ -913,7 +913,7 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { tlssock->iface = handle->sock->iface; tlssock->peer = handle->sock->peer; if (isc__nm_closing(tlssock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index fbf9345592..f4de7d3e73 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -89,7 +89,7 @@ start_udp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock, isc__nmsocket_init(csock, mgr, isc_nm_udpsocket, iface); csock->parent = sock; csock->iface = sock->iface; - csock->reading = true; + atomic_init(&csock->reading, true); csock->recv_cb = sock->recv_cb; csock->recv_cbarg = sock->recv_cbarg; csock->extrahandlesize = sock->extrahandlesize; @@ -344,7 +344,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); #ifdef UV_UDP_MMSG_FREE free_buf = ((flags & UV_UDP_MMSG_FREE) == UV_UDP_MMSG_FREE); @@ -356,7 +356,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, #endif /* - * Three possible reasons to return now without processing: + * Four possible reasons to return now without processing: */ /* @@ -373,6 +373,15 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, goto free; } + /* + * - If there was a networking error. + */ + if (nrecv < 0) { + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv), + false); + goto free; + } + /* * - If addr == NULL, in which case it's the end of stream; * we can free the buffer and bail. @@ -390,12 +399,6 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, goto free; } - if (nrecv < 0) { - isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv), - false); - goto free; - } - result = isc_sockaddr_fromsockaddr(&sockaddr, addr); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -612,6 +615,11 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { RUNTIME_CHECK(r == 0); uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; + goto error; + } + r = uv_udp_open(&sock->uv_handle.udp, sock->fd); if (r != 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]); @@ -653,6 +661,7 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { done: result = isc__nm_uverr2result(r); +error: LOCK(&sock->lock); sock->result = result; @@ -800,6 +809,7 @@ isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, * does not. */ if (!sock->parent) { + isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); } } @@ -856,15 +866,22 @@ void isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0; isc_nmsocket_t *sock = ievent->sock; + isc_result_t result = ISC_R_SUCCESS; UNUSED(worker); REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nmsocket_closing(sock)) { - sock->reading = true; - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; + } else if (isc__nmsocket_closing(sock)) { + result = ISC_R_CANCELED; + } + + if (result != ISC_R_SUCCESS) { + atomic_store(&sock->reading, true); + isc__nm_failed_read_cb(sock, result, false); return; } @@ -881,14 +898,13 @@ isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_udpsocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; sock->recv_read = true; - if (!sock->reading && sock->tid == isc_nm_tid()) { + if (!atomic_load(&sock->reading) && sock->tid == isc_nm_tid()) { isc__netievent_udpread_t ievent = { .sock = sock }; isc__nm_async_udpread(NULL, (isc__netievent_t *)&ievent); } else { @@ -1079,7 +1095,11 @@ isc__nm_udp_shutdown(isc_nmsocket_t *sock) { * interested in the callback. */ if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/socket.c b/lib/isc/socket.c index 12d8c71550..1f3b107bf9 100644 --- a/lib/isc/socket.c +++ b/lib/isc/socket.c @@ -350,8 +350,8 @@ struct isc_socket { unsigned int listener : 1, /* listener socket */ connected : 1, connecting : 1, /* connect pending * */ - bound : 1, /* bound to local addr */ - dupped : 1, active : 1, /* currently active */ + bound : 1, /* bound to local addr */ + active : 1, /* currently active */ pktdscp : 1; /* per packet dscp */ #ifdef ISC_PLATFORM_RECVOVERFLOW @@ -434,7 +434,7 @@ struct isc__socketthread { static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, - isc_socket_t **socketp, isc_socket_t *dup_socket); + isc_socket_t **socketp); static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **); static void @@ -1881,7 +1881,6 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, sock->fd = -1; sock->threadid = -1; sock->dscp = 0; /* TOS/TCLASS is zero until set. */ - sock->dupped = 0; sock->statsindex = NULL; sock->active = 0; @@ -2123,8 +2122,7 @@ set_ip_disable_pmtud(isc_socket_t *sock) { } static isc_result_t -opensocket(isc_socketmgr_t *manager, isc_socket_t *sock, - isc_socket_t *dup_socket) { +opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) { isc_result_t result; char strbuf[ISC_STRERRORSIZE]; const char *err = "socket"; @@ -2138,60 +2136,52 @@ opensocket(isc_socketmgr_t *manager, isc_socket_t *sock, #endif again: - if (dup_socket == NULL) { - switch (sock->type) { - case isc_sockettype_udp: - sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); - break; - case isc_sockettype_tcp: - sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); - break; - case isc_sockettype_unix: - sock->fd = socket(sock->pf, SOCK_STREAM, 0); - break; - case isc_sockettype_raw: - errno = EPFNOSUPPORT; - /* - * PF_ROUTE is a alias for PF_NETLINK on linux. - */ + switch (sock->type) { + case isc_sockettype_udp: + sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); + break; + case isc_sockettype_tcp: + sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); + break; + case isc_sockettype_unix: + sock->fd = socket(sock->pf, SOCK_STREAM, 0); + break; + case isc_sockettype_raw: + errno = EPFNOSUPPORT; + /* + * PF_ROUTE is a alias for PF_NETLINK on linux. + */ #if defined(PF_ROUTE) - if (sock->fd == -1 && sock->pf == PF_ROUTE) { + if (sock->fd == -1 && sock->pf == PF_ROUTE) { #ifdef NETLINK_ROUTE - sock->fd = socket(sock->pf, SOCK_RAW, - NETLINK_ROUTE); + sock->fd = socket(sock->pf, SOCK_RAW, NETLINK_ROUTE); #else /* ifdef NETLINK_ROUTE */ - sock->fd = socket(sock->pf, SOCK_RAW, 0); + sock->fd = socket(sock->pf, SOCK_RAW, 0); #endif /* ifdef NETLINK_ROUTE */ - if (sock->fd != -1) { + if (sock->fd != -1) { #ifdef NETLINK_ROUTE - struct sockaddr_nl sa; - int n; + struct sockaddr_nl sa; + int n; - /* - * Do an implicit bind. - */ - memset(&sa, 0, sizeof(sa)); - sa.nl_family = AF_NETLINK; - sa.nl_groups = RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_IFADDR; - n = bind(sock->fd, - (struct sockaddr *)&sa, - sizeof(sa)); - if (n < 0) { - close(sock->fd); - sock->fd = -1; - } -#endif /* ifdef NETLINK_ROUTE */ - sock->bound = 1; + /* + * Do an implicit bind. + */ + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_IPV4_IFADDR | + RTMGRP_IPV6_IFADDR; + n = bind(sock->fd, (struct sockaddr *)&sa, + sizeof(sa)); + if (n < 0) { + close(sock->fd); + sock->fd = -1; } +#endif /* ifdef NETLINK_ROUTE */ + sock->bound = 1; } -#endif /* if defined(PF_ROUTE) */ - break; } - } else { - sock->fd = dup(dup_socket->fd); - sock->dupped = 1; - sock->bound = dup_socket->bound; +#endif /* if defined(PF_ROUTE) */ + break; } if (sock->fd == -1 && errno == EINTR && tries++ < 42) { goto again; @@ -2268,10 +2258,6 @@ again: } } - if (dup_socket != NULL) { - goto setup_done; - } - result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { (void)close(sock->fd); @@ -2410,7 +2396,6 @@ again: set_ip_disable_pmtud(sock); -setup_done: inc_stats(manager->stats, sock->statsindex[STATID_OPEN]); if (sock->active == 0) { inc_stats(manager->stats, sock->statsindex[STATID_ACTIVE]); @@ -2421,14 +2406,13 @@ setup_done: } /* - * Create a 'type' socket or duplicate an existing socket, managed - * by 'manager'. Events will be posted to 'task' and when dispatched - * 'action' will be called with 'arg' as the arg value. The new - * socket is returned in 'socketp'. + * Create a 'type' socket, managed by 'manager'. Events will be posted to + * 'task' and when dispatched 'action' will be called with 'arg' as the arg + * value. The new socket is returned in 'socketp'. */ static isc_result_t socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, - isc_socket_t **socketp, isc_socket_t *dup_socket) { + isc_socket_t **socketp) { isc_socket_t *sock = NULL; isc__socketthread_t *thread; isc_result_t result; @@ -2466,7 +2450,7 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, sock->pf = pf; - result = opensocket(manager, sock, dup_socket); + result = opensocket(manager, sock); if (result != ISC_R_SUCCESS) { free_socket(&sock); return (result); @@ -2507,8 +2491,7 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #endif /* ifdef USE_SELECT */ UNLOCK(&manager->lock); - socket_log(sock, NULL, CREATION, - dup_socket != NULL ? "dupped" : "created"); + socket_log(sock, NULL, CREATION, "created"); return (ISC_R_SUCCESS); } @@ -2520,22 +2503,9 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, * in 'socketp'. */ isc_result_t -isc_socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, +isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, isc_socket_t **socketp) { - return (socket_create(manager0, pf, type, socketp, NULL)); -} - -/*% - * Duplicate an existing socket. The new socket is returned - * in 'socketp'. - */ -isc_result_t -isc_socket_dup(isc_socket_t *sock, isc_socket_t **socketp) { - REQUIRE(VALID_SOCKET(sock)); - REQUIRE(socketp != NULL && *socketp == NULL); - - return (socket_create(sock->manager, sock->pf, sock->type, socketp, - sock)); + return (socket_create(manager, pf, type, socketp)); } isc_result_t @@ -2551,7 +2521,7 @@ isc_socket_open(isc_socket_t *sock) { REQUIRE(sock->fd == -1); REQUIRE(sock->threadid == -1); - result = opensocket(sock->manager, sock, NULL); + result = opensocket(sock->manager, sock); UNLOCK(&sock->lock); @@ -2623,7 +2593,7 @@ isc_socket_close(isc_socket_t *sock) { int fd; isc_socketmgr_t *manager; isc__socketthread_t *thread; - fflush(stdout); + REQUIRE(VALID_SOCKET(sock)); LOCK(&sock->lock); @@ -2642,7 +2612,6 @@ isc_socket_close(isc_socket_t *sock) { sock->fd = -1; sock->threadid = -1; - sock->dupped = 0; memset(sock->name, 0, sizeof(sock->name)); sock->tag = NULL; sock->listener = 0; @@ -4334,7 +4303,6 @@ isc_socket_bind(isc_socket_t *sock, const isc_sockaddr_t *sockaddr, LOCK(&sock->lock); INSIST(!sock->bound); - INSIST(!sock->dupped); if (sock->pf != sockaddr->type.sa.sa_family) { UNLOCK(&sock->lock); @@ -5078,7 +5046,6 @@ isc_socket_ipv6only(isc_socket_t *sock, bool yes) { #endif /* if defined(IPV6_V6ONLY) */ REQUIRE(VALID_SOCKET(sock)); - INSIST(!sock->dupped); #ifdef IPV6_V6ONLY if (sock->pf == AF_INET6) { @@ -5151,10 +5118,6 @@ isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) { } #endif /* if !defined(IP_TOS) && !defined(IPV6_TCLASS) */ -#ifdef notyet - REQUIRE(!sock->dupped); -#endif /* ifdef notyet */ - setdscp(sock, dscp); } @@ -5200,8 +5163,7 @@ static void init_hasreuseport(void) { /* * SO_REUSEPORT works very differently on *BSD and on Linux (because why not). - * We only want to use it on Linux, if it's available. On BSD we want to dup() - * sockets instead of re-binding them. + * We only want to use it on Linux, if it's available. */ #if (defined(SO_REUSEPORT) && defined(__linux__)) || \ (defined(SO_REUSEPORT_LB) && defined(__FreeBSD_kernel__)) diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c index 285e3c86ab..a98fc11906 100644 --- a/lib/isc/tests/socket_test.c +++ b/lib/isc/tests/socket_test.c @@ -218,89 +218,6 @@ udp_sendto_test(void **state) { assert_string_equal(recvbuf, "Hello"); } -/* Test UDP sendto/recv with duplicated socket */ -static void -udp_dup_test(void **state) { - isc_result_t result; - isc_sockaddr_t addr1, addr2; - struct in_addr in; - char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; - completion_t completion; - isc_region_t r; - - UNUSED(state); - - in.s_addr = inet_addr("127.0.0.1"); - isc_sockaddr_fromin(&addr1, &in, 0); - isc_sockaddr_fromin(&addr2, &in, 0); - - result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_bind(s1, &addr1, 0); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_getsockname(s1, &addr1); - assert_int_equal(result, ISC_R_SUCCESS); - assert_true(isc_sockaddr_getport(&addr1) != 0); - - result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_bind(s2, &addr2, 0); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_getsockname(s2, &addr2); - assert_int_equal(result, ISC_R_SUCCESS); - assert_true(isc_sockaddr_getport(&addr2) != 0); - - result = isc_socket_dup(s2, &s3); - assert_int_equal(result, ISC_R_SUCCESS); - - result = isc_task_create(taskmgr, 0, &test_task); - assert_int_equal(result, ISC_R_SUCCESS); - - snprintf(sendbuf, sizeof(sendbuf), "Hello"); - r.base = (void *)sendbuf; - r.length = strlen(sendbuf) + 1; - - completion_init(&completion); - result = isc_socket_sendto(s1, &r, test_task, event_done, &completion, - &addr2, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - - snprintf(sendbuf, sizeof(sendbuf), "World"); - r.base = (void *)sendbuf; - r.length = strlen(sendbuf) + 1; - - completion_init(&completion); - result = isc_socket_sendto(s1, &r, test_task, event_done, &completion, - &addr2, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - - r.base = (void *)recvbuf; - r.length = BUFSIZ; - completion_init(&completion); - result = isc_socket_recv(s2, &r, 1, test_task, event_done, &completion); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - assert_string_equal(recvbuf, "Hello"); - - r.base = (void *)recvbuf; - r.length = BUFSIZ; - completion_init(&completion); - result = isc_socket_recv(s3, &r, 1, test_task, event_done, &completion); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - assert_string_equal(recvbuf, "World"); -} - /* Test UDP sendto/recv (IPv4) */ static void udp_dscp_v4_test(void **state) { @@ -787,8 +704,6 @@ main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(udp_sendto_test, _setup, _teardown), - cmocka_unit_test_setup_teardown(udp_dup_test, _setup, - _teardown), cmocka_unit_test_setup_teardown(tcp_dscp_v4_test, _setup, _teardown), cmocka_unit_test_setup_teardown(tcp_dscp_v6_test, _setup, diff --git a/lib/isc/time.c b/lib/isc/time.c index 727b399271..19f2ce33c6 100644 --- a/lib/isc/time.c +++ b/lib/isc/time.c @@ -31,6 +31,7 @@ #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ #define NS_PER_MS 1000000 /*%< Nanoseconds per millisecond. */ +#define MS_PER_S 1000 /*%< Milliseonds per second. */ #if defined(CLOCK_REALTIME) #define CLOCKSOURCE_HIRES CLOCK_REALTIME @@ -77,6 +78,14 @@ isc_interval_iszero(const isc_interval_t *i) { return (false); } +unsigned int +isc_interval_ms(const isc_interval_t *i) { + REQUIRE(i != NULL); + INSIST(i->nanoseconds < NS_PER_S); + + return ((i->seconds * MS_PER_S) + (i->nanoseconds / NS_PER_MS)); +} + /*** *** Absolute Times ***/ diff --git a/lib/ns/client.c b/lib/ns/client.c index 34d94d15e7..f06f9bda79 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -2413,6 +2413,7 @@ ns_clientmgr_create(ns_server_t *sctx, isc_taskmgr_t *taskmgr, result = isc_task_create_bound(manager->taskmgr, 20, &manager->task, manager->tid); RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_task_setname(manager->task, "clientmgr", NULL); isc_refcount_init(&manager->references, 1); manager->sctx = NULL; diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index a99835bd4e..c734358dcd 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -70,7 +70,6 @@ #include #include #include -#include #include #include diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 9a975c6eb5..ae552a9656 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -74,23 +73,20 @@ struct ns_interface { isc_sockaddr_t addr; /*%< Address and port. */ unsigned int flags; /*%< Interface flags */ char name[32]; /*%< Null terminated. */ - dns_dispatch_t * udpdispatch[MAX_UDP_DISPATCH]; - /*%< UDP dispatchers. */ - isc_socket_t * tcpsocket; /*%< TCP socket. */ - isc_nmsocket_t *udplistensocket; - isc_nmsocket_t *tcplistensocket; - isc_nmsocket_t *http_listensocket; - isc_nmsocket_t *http_secure_listensocket; - isc_dscp_t dscp; /*%< "listen-on" DSCP value */ - isc_refcount_t ntcpaccepting; /*%< Number of clients - * ready to accept new - * TCP connections on this - * interface */ - isc_refcount_t ntcpactive; /*%< Number of clients - * servicing TCP queries - * (whether accepting or - * connected) */ - int nudpdispatch; /*%< Number of UDP dispatches */ + isc_nmsocket_t * udplistensocket; + isc_nmsocket_t * tcplistensocket; + isc_nmsocket_t * http_listensocket; + isc_nmsocket_t * http_secure_listensocket; + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ + isc_refcount_t ntcpaccepting; /*%< Number of clients + * ready to accept new + * TCP connections on this + * interface */ + isc_refcount_t ntcpactive; /*%< Number of clients + * servicing TCP queries + * (whether accepting or + * connected) */ + ns_clientmgr_t *clientmgr; /*%< Client manager. */ ISC_LINK(ns_interface_t) link; }; @@ -103,8 +99,8 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr, isc_task_t *task, - unsigned int udpdisp, dns_geoip_databases_t *geoip, - int ncpus, ns_interfacemgr_t **mgrp); + dns_geoip_databases_t *geoip, int ncpus, + ns_interfacemgr_t **mgrp); /*%< * Create a new interface manager. * diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 649dbc8ef8..72b86dc0c9 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -86,7 +86,6 @@ struct ns_interfacemgr { ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces */ ISC_LIST(isc_sockaddr_t) listenon; int backlog; /*%< Listen queue size */ - unsigned int udpdisp; /*%< UDP dispatch count */ atomic_bool shuttingdown; /*%< Interfacemgr shutting down */ ns_clientmgr_t **clientmgrs; /*%< Client managers */ #ifdef USE_ROUTE_SOCKET @@ -183,8 +182,8 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr, isc_task_t *task, - unsigned int udpdisp, dns_geoip_databases_t *geoip, - int ncpus, ns_interfacemgr_t **mgrp) { + dns_geoip_databases_t *geoip, int ncpus, + ns_interfacemgr_t **mgrp) { isc_result_t result; ns_interfacemgr_t *mgr; @@ -220,7 +219,6 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, mgr->generation = 1; mgr->listenon4 = NULL; mgr->listenon6 = NULL; - mgr->udpdisp = udpdisp; mgr->ncpus = ncpus; atomic_init(&mgr->shuttingdown, false); @@ -404,8 +402,7 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { 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; - int disp; + ns_interface_t *ifp = NULL; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); @@ -418,10 +415,6 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, isc_mutex_init(&ifp->lock); - for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) { - ifp->udpdispatch[disp] = 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 @@ -489,7 +482,7 @@ ns_interface_listentcp(ns_interface_t *ifp) { #if 0 #ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(ifp->tcpsocket,true); + isc_socket_ipv6only(ifp->tcpsocket, true); #endif /* ifndef ISC_ALLOW_MAPPED */ if (ifp->dscp != -1) { @@ -705,19 +698,6 @@ ns_interface_destroy(ns_interface_t *ifp) { ns_interface_shutdown(ifp); - for (int disp = 0; disp < ifp->nudpdispatch; disp++) { - if (ifp->udpdispatch[disp] != NULL) { - dns_dispatch_changeattributes( - ifp->udpdispatch[disp], 0, - DNS_DISPATCHATTR_NOLISTEN); - dns_dispatch_detach(&(ifp->udpdispatch[disp])); - } - } - - if (ifp->tcpsocket != NULL) { - isc_socket_detach(&ifp->tcpsocket); - } - isc_mutex_destroy(&ifp->lock); ns_interfacemgr_detach(&ifp->mgr); diff --git a/lib/ns/query.c b/lib/ns/query.c index 0916db2010..e5bbb3df1a 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -6652,7 +6652,7 @@ query_resume(query_ctx_t *qctx) { } else if (REDIRECT(qctx->client)) { tname = qctx->client->query.redirect.fname; } else { - tname = dns_fixedname_name(&qctx->event->foundname); + tname = qctx->event->foundname; } dns_name_copy(tname, qctx->fname); diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 50f6e2ad3c..1df32364e1 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -165,7 +165,7 @@ shutdown_managers(isc_task_t *task, isc_event_t *event) { } if (dispatchmgr != NULL) { - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } atomic_store(&shutdown_done, true); @@ -233,11 +233,11 @@ create_managers(void) { CHECK(ns_server_create(mctx, matchview, &sctx)); - CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + CHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, socketmgr, - netmgr, dispatchmgr, maintask, ncpus, NULL, - ncpus, &interfacemgr)); + netmgr, dispatchmgr, maintask, NULL, ncpus, + &interfacemgr)); CHECK(ns_listenlist_default(mctx, port, -1, true, &listenon)); ns_interfacemgr_setlistenon4(interfacemgr, listenon); @@ -442,8 +442,7 @@ ns_test_setupzonemgr(void) { isc_result_t result; REQUIRE(zonemgr == NULL); - result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, NULL, - &zonemgr); + result = dns_zonemgr_create(mctx, taskmgr, timermgr, NULL, &zonemgr); return (result); } diff --git a/util/copyrights b/util/copyrights index 0e24a2361d..42ce88bb7e 100644 --- a/util/copyrights +++ b/util/copyrights @@ -399,6 +399,7 @@ ./bin/tests/system/glue/tests.sh SH 2000,2001,2003,2004,2007,2012,2013,2016,2017,2018,2019,2020,2021 ./bin/tests/system/hooks/clean.sh SH 2020,2021 ./bin/tests/system/hooks/driver/test-async.c C 2020,2021 +./bin/tests/system/hooks/prereq.sh SH 2021 ./bin/tests/system/hooks/setup.sh SH 2020,2021 ./bin/tests/system/hooks/tests.sh SH 2020,2021 ./bin/tests/system/idna/clean.sh SH 2018,2019,2020,2021 @@ -1231,7 +1232,6 @@ ./lib/dns/include/dns/soa.h C 2000,2001,2004,2005,2006,2007,2009,2016,2018,2019,2020,2021 ./lib/dns/include/dns/ssu.h C 2000,2001,2003,2004,2005,2006,2007,2008,2010,2011,2016,2017,2018,2019,2020,2021 ./lib/dns/include/dns/stats.h C 2000,2001,2004,2005,2006,2007,2008,2009,2012,2014,2015,2016,2017,2018,2019,2020,2021 -./lib/dns/include/dns/tcpmsg.h C 1999,2000,2001,2004,2005,2006,2007,2015,2016,2018,2019,2020,2021 ./lib/dns/include/dns/time.h C 1999,2000,2001,2004,2005,2006,2007,2012,2016,2018,2019,2020,2021 ./lib/dns/include/dns/timer.h C 2000,2001,2004,2005,2006,2007,2016,2018,2019,2020,2021 ./lib/dns/include/dns/tkey.h C 1999,2000,2001,2004,2005,2006,2007,2009,2010,2011,2016,2018,2019,2020,2021 @@ -1471,7 +1471,6 @@ ./lib/dns/ssu.c C 2000,2001,2003,2004,2005,2006,2007,2008,2010,2011,2013,2014,2016,2017,2018,2019,2020,2021 ./lib/dns/ssu_external.c C 2011,2012,2013,2016,2017,2018,2019,2020,2021 ./lib/dns/stats.c C 2000,2001,2004,2005,2007,2008,2009,2012,2016,2018,2019,2020,2021 -./lib/dns/tcpmsg.c C 1999,2000,2001,2004,2005,2006,2007,2015,2016,2018,2019,2020,2021 ./lib/dns/tests/Kdh.+002+18602.key X 2014,2018,2019,2020,2021 ./lib/dns/tests/Krsa.+005+29235.key X 2016,2018,2019,2020,2021 ./lib/dns/tests/acl_test.c C 2016,2018,2019,2020,2021