diff --git a/CHANGES b/CHANGES index 5925f440b9..c8f60c16be 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,13 @@ +6130. [func] The new "delv +ns" option activates name server mode, + in which delv sets up an internal recursive + resolver and uses that, rather than an external + server, to look up the requested data. All messages + sent and received during the resolution and + validation process are logged. This can be used in + place of "dig +trace"; it more accurately + replicates the behavior of named when resolving + a query. [GL #3842] + 6129. [cleanup] Value stored to 'source' during its initialization is never read. [GL #3965] diff --git a/bin/delv/Makefile.am b/bin/delv/Makefile.am index df4661f6e9..032da0e545 100644 --- a/bin/delv/Makefile.am +++ b/bin/delv/Makefile.am @@ -4,6 +4,7 @@ AM_CPPFLAGS += \ -I$(top_builddir)/include \ $(LIBISC_CFLAGS) \ $(LIBDNS_CFLAGS) \ + $(LIBNS_CFLAGS) \ $(LIBISCCFG_CFLAGS) AM_CPPFLAGS += \ @@ -17,4 +18,5 @@ delv_SOURCES = \ delv_LDADD = \ $(LIBISC_LIBS) \ $(LIBDNS_LIBS) \ + $(LIBNS_LIBS) \ $(LIBISCCFG_LIBS) diff --git a/bin/delv/delv.c b/bin/delv/delv.c index 7fa6eb8679..357bdfd1ad 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,20 +43,28 @@ #include #include +#include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include #include +#include #include #include @@ -63,6 +72,10 @@ #include #include +#include +#include +#include + #include #define CHECK(r) \ @@ -75,13 +88,24 @@ #define MAXNAME (DNS_NAME_MAXTEXT + 1) /* Variables used internally by delv. */ -char *progname; +char *progname = NULL; static isc_mem_t *mctx = NULL; static isc_log_t *lctx = NULL; +static dns_view_t *view = NULL; +static ns_server_t *sctx = NULL; +static ns_interface_t *ifp = NULL; +static dns_dispatch_t *dispatch = NULL; +static dns_db_t *roothints = NULL; +static isc_stats_t *resstats = NULL; +static dns_stats_t *resquerystats = NULL; +static FILE *logfp = NULL; /* Managers */ static isc_nm_t *netmgr = NULL; static isc_loopmgr_t *loopmgr = NULL; +static dns_dispatchmgr_t *dispatchmgr = NULL; +static dns_requestmgr_t *requestmgr = NULL; +static ns_interfacemgr_t *interfacemgr = NULL; /* TLS */ static isc_tlsctx_cache_t *tlsctx_client_cache = NULL; @@ -89,26 +113,29 @@ static isc_tlsctx_cache_t *tlsctx_client_cache = NULL; /* Configurables */ static char *server = NULL; static const char *port = "53"; +static uint32_t destport = 53; static isc_sockaddr_t *srcaddr4 = NULL, *srcaddr6 = NULL; static isc_sockaddr_t a4, a6; static char *curqname = NULL, *qname = NULL; static bool classset = false; static dns_rdatatype_t qtype = dns_rdatatype_none; static bool typeset = false; +static const char *hintfile = NULL; static unsigned int styleflags = 0; static uint32_t splitwidth = 0xffffffff; static bool showcomments = true, showdnssec = true, showtrust = true, rrcomments = true, noclass = false, nocrypto = false, nottl = false, multiline = false, short_form = false, print_unknown_format = false, - yaml = false; + yaml = false, fulltrace = false; static bool resolve_trace = false, validator_trace = false, - message_trace = false; + message_trace = false, send_trace = false; static bool use_ipv4 = true, use_ipv6 = true; static bool cdflag = false, no_sigs = false, root_validation = true; +static bool qmin = false, qmin_strict = false; static bool use_tcp = false; @@ -189,8 +216,12 @@ usage(void) { "records)\n" " +[no]mtrace (Trace messages " "received)\n" + " +[no]ns (Run internal name " + "server)\n" " +[no]multiline (Print records in an " "expanded format)\n" + " +[no]qmin[=mode] (QNAME minimization: " + "relaxed or strict)\n" " +[no]root (DNSSEC validation trust " "anchor)\n" " +[no]rrcomments (Control display of " @@ -201,6 +232,8 @@ usage(void) { " +[no]short (Short form answer)\n" " +[no]split=## (Split hex/base64 fields " "into chunks)\n" + " +[no]strace (Trace messages " + "sent)\n" " +[no]tcp (TCP mode)\n" " +[no]ttl (Control display of ttls " "in records)\n" @@ -280,6 +313,7 @@ setup_logging(FILE *errout) { isc_result_t result; isc_logdestination_t destination; isc_logconfig_t *logconfig = NULL; + int packetlevel = 10; isc_log_create(mctx, &lctx, &logconfig); isc_log_registercategories(lctx, categories); @@ -332,9 +366,12 @@ setup_logging(FILE *errout) { } } - if (message_trace && loglevel < 10) { + if (send_trace) { + packetlevel = 11; + } + if ((message_trace || send_trace) && loglevel < packetlevel) { isc_log_createchannel(logconfig, "messages", ISC_LOG_TOFILEDESC, - ISC_LOG_DEBUG(10), &destination, + ISC_LOG_DEBUG(packetlevel), &destination, ISC_LOG_PRINTPREFIX); result = isc_log_usechannel(logconfig, "messages", @@ -424,7 +461,7 @@ print_status(dns_rdataset_t *rdataset) { } } -static isc_result_t +static void printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { isc_result_t result = ISC_R_SUCCESS; static dns_trust_t trust; @@ -437,12 +474,13 @@ printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { if (!dns_rdataset_isassociated(rdataset)) { char namebuf[DNS_NAME_FORMATSIZE]; dns_name_format(owner, namebuf, sizeof(namebuf)); - delv_log(ISC_LOG_DEBUG(4), "WARN: empty rdataset %s", namebuf); - return (ISC_R_SUCCESS); + delv_log(ISC_LOG_DEBUG(4), "warning: empty rdataset %s", + namebuf); + return; } if (!showdnssec && rdataset->type == dns_rdatatype_rrsig) { - return (ISC_R_SUCCESS); + return; } if (first || rdataset->trust != trust) { @@ -516,8 +554,6 @@ cleanup: if (t != NULL) { isc_mem_put(mctx, t, len); } - - return (ISC_R_SUCCESS); } static isc_result_t @@ -570,7 +606,7 @@ static isc_result_t convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { isc_result_t result; isc_buffer_t b; - dns_name_t *n; + dns_name_t *n = NULL; unsigned int len; REQUIRE(fn != NULL && name != NULL && text != NULL); @@ -582,7 +618,7 @@ convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { result = dns_name_fromtext(n, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { - delv_log(ISC_LOG_ERROR, "failed to convert QNAME %s: %s", text, + delv_log(ISC_LOG_ERROR, "failed to convert name %s: %s", text, isc_result_totext(result)); return (result); } @@ -592,7 +628,7 @@ convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { } static isc_result_t -key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { +key_fromconfig(const cfg_obj_t *key, dns_client_t *client, dns_view_t *toview) { dns_rdata_dnskey_t dnskey; dns_rdata_ds_t ds; uint32_t rdata1, rdata2, rdata3; @@ -615,6 +651,8 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { } anchortype; const cfg_obj_t *obj; + REQUIRE(client != NULL || toview != NULL); + keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); CHECK(convert_name(&fkeyname, &keyname, keynamestr)); @@ -708,9 +746,15 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { CHECK(dns_rdata_fromstruct(NULL, dnskey.common.rdclass, dnskey.common.rdtype, &dnskey, &rrdatabuf)); - CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, - dns_rdatatype_dnskey, keyname, - &rrdatabuf)); + if (client != NULL) { + CHECK(dns_client_addtrustedkey( + client, dns_rdataclass_in, dns_rdatatype_dnskey, + keyname, &rrdatabuf)); + } else if (toview != NULL) { + CHECK(dns_view_addtrustedkey(toview, + dns_rdatatype_dnskey, + keyname, &rrdatabuf)); + } break; case INITIAL_DS: case STATIC_DS: @@ -751,9 +795,14 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { CHECK(dns_rdata_fromstruct(NULL, ds.common.rdclass, ds.common.rdtype, &ds, &rrdatabuf)); - CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, - dns_rdatatype_ds, keyname, - &rrdatabuf)); + if (client != NULL) { + CHECK(dns_client_addtrustedkey( + client, dns_rdataclass_in, dns_rdatatype_ds, + keyname, &rrdatabuf)); + } else if (toview != NULL) { + CHECK(dns_view_addtrustedkey(toview, dns_rdatatype_ds, + keyname, &rrdatabuf)); + } } num_keys++; @@ -777,7 +826,7 @@ cleanup: } static isc_result_t -load_keys(const cfg_obj_t *keys, dns_client_t *client) { +load_keys(const cfg_obj_t *keys, dns_client_t *client, dns_view_t *toview) { const cfg_listelt_t *elt, *elt2; const cfg_obj_t *key, *keylist; isc_result_t result = ISC_R_SUCCESS; @@ -790,7 +839,7 @@ load_keys(const cfg_obj_t *keys, dns_client_t *client) { elt2 = cfg_list_next(elt2)) { key = cfg_listelt_value(elt2); - CHECK(key_fromconfig(key, client)); + CHECK(key_fromconfig(key, client, toview)); } } @@ -802,7 +851,7 @@ cleanup: } static isc_result_t -setup_dnsseckeys(dns_client_t *client) { +setup_dnsseckeys(dns_client_t *client, dns_view_t *toview) { isc_result_t result; cfg_parser_t *parser = NULL; const cfg_obj_t *trusted_keys = NULL; @@ -853,13 +902,13 @@ setup_dnsseckeys(dns_client_t *client) { cfg_map_get(bindkeys, "trust-anchors", &trust_anchors); if (trusted_keys != NULL) { - CHECK(load_keys(trusted_keys, client)); + CHECK(load_keys(trusted_keys, client, toview)); } if (managed_keys != NULL) { - CHECK(load_keys(managed_keys, client)); + CHECK(load_keys(managed_keys, client, toview)); } if (trust_anchors != NULL) { - CHECK(load_keys(trust_anchors, client)); + CHECK(load_keys(trust_anchors, client, toview)); } result = ISC_R_SUCCESS; @@ -883,21 +932,15 @@ cleanup: static isc_result_t addserver(dns_client_t *client) { - struct addrinfo hints, *res, *cur; + struct addrinfo hints, *res = NULL, *cur = NULL; int gaierror; struct in_addr in4; struct in6_addr in6; - isc_sockaddr_t *sa; + isc_sockaddr_t *sa = NULL; isc_sockaddrlist_t servers; - uint32_t destport; isc_result_t result; dns_name_t *name = NULL; - result = parse_uint(&destport, port, 0xffff, "port"); - if (result != ISC_R_SUCCESS) { - fatal("Couldn't parse port number"); - } - ISC_LIST_INIT(servers); if (inet_pton(AF_INET, server, &in4) == 1) { @@ -975,13 +1018,7 @@ findserver(dns_client_t *client) { isc_result_t result; irs_resconf_t *resconf = NULL; isc_sockaddrlist_t *nameservers; - isc_sockaddr_t *sa, *next; - uint32_t destport; - - result = parse_uint(&destport, port, 0xffff, "port"); - if (result != ISC_R_SUCCESS) { - fatal("Couldn't parse port number"); - } + isc_sockaddr_t *sa = NULL, *next = NULL; result = irs_resconf_load(mctx, "/etc/resolv.conf", &resconf); if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { @@ -1135,9 +1172,26 @@ plus_option(char *option) { goto invalid_option; } break; + case 'h': + switch (cmd[1]) { + case 'i': /* hint */ + if (state) { + if (value == NULL) { + fatal("+hint: must specify hint file"); + } + hintfile = value; + } else { + hintfile = NULL; + } + break; + default: + goto invalid_option; + } + break; case 'm': switch (cmd[1]) { case 't': /* mtrace */ + FULLCHECK("mtrace"); message_trace = state; if (state) { resolve_trace = state; @@ -1151,6 +1205,41 @@ plus_option(char *option) { goto invalid_option; } break; + case 'n': + switch (cmd[1]) { + case 's': /* ns */ + FULLCHECK("ns"); + fulltrace = state; + if (state) { + message_trace = state; + send_trace = state; + resolve_trace = state; + logfp = stdout; + } + break; + default: + goto invalid_option; + } + break; + case 'q': /* qmin */ + FULLCHECK("qmin"); + if (state) { + if (value == NULL || strcasecmp(value, "relaxed") == 0) + { + qmin = true; + } else if (strcasecmp(value, "strict") == 0) { + qmin = true; + qmin_strict = true; + } else { + fatal("Invalid qmin option '%s': " + "use 'relaxed' or 'strict'\n", + value); + } + } else { + qmin = false; + qmin_strict = false; + } + break; case 'r': switch (cmd[1]) { case 'o': /* root */ @@ -1220,6 +1309,13 @@ plus_option(char *option) { fatal("Couldn't parse split"); } break; + case 't': /* strace */ + FULLCHECK("strace"); + send_trace = state; + if (state) { + message_trace = state; + } + break; default: goto invalid_option; } @@ -1234,9 +1330,20 @@ plus_option(char *option) { FULLCHECK("tcp"); use_tcp = state; break; - case 'r': /* trust */ - FULLCHECK("trust"); - showtrust = state; + case 'r': + switch (cmd[2]) { + case 'a': /* trace */ + FULLCHECK("trace"); + fatal("Invalid argument +trace. For " + "delegation path tracing, use +ns."); + break; + case 'u': /* trust */ + FULLCHECK("trust"); + showtrust = state; + break; + default: + goto invalid_option; + } break; case 't': /* ttl */ FULLCHECK("ttl"); @@ -1269,6 +1376,10 @@ plus_option(char *option) { fprintf(stderr, "Invalid option: +%s\n", option); usage(); } + + if (qmin && !fulltrace) { + fatal("'+qmin' cannot be used without '+ns'"); + } return; } @@ -1420,6 +1531,10 @@ dash_option(char *option, char *next, bool *open_type_class) { return (value_from_next); case 'p': port = value; + result = parse_uint(&destport, port, 0xffff, "port"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse port number"); + } return (value_from_next); case 'q': if (curqname != NULL) { @@ -1735,10 +1850,7 @@ resolve_cb(dns_client_t *client, const dns_name_t *query_name, for (rdataset = ISC_LIST_HEAD(response_name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { - result = printdata(rdataset, response_name); - if (result != ISC_R_SUCCESS) { - delv_log(ISC_LOG_ERROR, "print data failed"); - } + printdata(rdataset, response_name); } } @@ -1751,12 +1863,14 @@ resolve_cb(dns_client_t *client, const dns_name_t *query_name, } static void -resolve(void *arg) { - dns_client_t *client = arg; - dns_namelist_t *namelist; +run_resolve(void *arg) { + dns_client_t *client = NULL; + dns_namelist_t *namelist = NULL; unsigned int resopt; isc_result_t result; - dns_name_t *query_name; + dns_name_t *query_name = NULL; + + UNUSED(arg); namelist = isc_mem_get(mctx, sizeof(*namelist)); ISC_LIST_INIT(*namelist); @@ -1779,14 +1893,22 @@ resolve(void *arg) { resopt |= DNS_CLIENTRESOPT_TCP; } - /* Perform resolution */ - result = dns_client_resolve(client, query_name, dns_rdataclass_in, - qtype, resopt, namelist, resolve_cb); + /* Create client */ + CHECK(dns_client_create(mctx, loopmgr, netmgr, 0, tlsctx_client_cache, + &client, srcaddr4, srcaddr6)); - if (result != ISC_R_SUCCESS) { - goto cleanup; + /* Set the nameserver */ + if (server != NULL) { + addserver(client); + } else { + findserver(client); } + CHECK(setup_dnsseckeys(client, NULL)); + + /* Perform resolution */ + CHECK(dns_client_resolve(client, query_name, dns_rdataclass_in, qtype, + resopt, namelist, resolve_cb)); return; cleanup: if (!yaml) { @@ -1800,18 +1922,278 @@ cleanup: dns_client_detach(&client); } +static void +shutdown_server(void) { + if (requestmgr != NULL) { + dns_requestmgr_detach(&requestmgr); + } + if (interfacemgr != NULL) { + ns_interfacemgr_shutdown(interfacemgr); + ns_interfacemgr_detach(&interfacemgr); + } + if (dispatch != NULL) { + dns_dispatch_detach(&dispatch); + } + if (dispatchmgr != NULL) { + dns_dispatchmgr_detach(&dispatchmgr); + } + if (sctx != NULL) { + ns_server_detach(&sctx); + } + + isc_loopmgr_shutdown(loopmgr); +} + +static void +recvresponse(void *arg) { + dns_request_t *request = (dns_request_t *)arg; + dns_message_t *query = dns_request_getarg(request); + isc_result_t result = dns_request_getresult(request); + dns_message_t *response = NULL; + + if (result != ISC_R_SUCCESS) { + fatal("request event result: %s", isc_result_totext(result)); + } + + dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); + + result = dns_request_getresponse(request, response, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result != ISC_R_SUCCESS) { + fatal("request response failed: %s", isc_result_totext(result)); + } + if (response->rcode != dns_rcode_noerror) { + result = dns_result_fromrcode(response->rcode); + delv_log(ISC_LOG_INFO, "response code: %s", + isc_result_totext(result)); + goto cleanup; + } + + for (result = dns_message_firstname(response, DNS_SECTION_ANSWER); + result == ISC_R_SUCCESS; + result = dns_message_nextname(response, DNS_SECTION_ANSWER)) + { + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + + dns_message_currentname(response, DNS_SECTION_ANSWER, &name); + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + dns_rdataset_t rds, sigs; + int options = 0; + + /* + * The response message contains the answer the + * resolver found, but it doesn't contain the + * trust status; so if we're displaying that, we + * need to look up each rdataset in the cache and + * print that version instead. but if not, we + * can just print the rdatasets from the message. + */ + if (!showtrust) { + printdata(rdataset, name); + continue; + } + + /* do the cache lookup */ + if (rdataset->type == dns_rdatatype_rrsig) { + continue; + } + + dns_rdataset_init(&rds); + dns_rdataset_init(&sigs); + + if (cdflag) { + options |= DNS_DBFIND_PENDINGOK; + } + result = dns_view_simplefind(view, name, rdataset->type, + 0, options, false, &rds, + &sigs); + if (result == ISC_R_SUCCESS) { + printdata(&rds, name); + dns_rdataset_disassociate(&rds); + if (dns_rdataset_isassociated(&sigs)) { + printdata(&sigs, name); + dns_rdataset_disassociate(&sigs); + } + } + } + } + +cleanup: + dns_message_detach(&query); + dns_message_detach(&response); + dns_request_destroy(&request); + + dns_view_detach(&view); + shutdown_server(); +} + +static isc_result_t +accept_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { + UNUSED(handle); + UNUSED(arg); + + return (result); +} + +static void +sendquery(void *arg) { + isc_nmsocket_t *sock = (isc_nmsocket_t *)arg; + isc_sockaddr_t peer = isc_nmsocket_getaddr(sock); + isc_result_t result; + dns_message_t *message = NULL; + dns_name_t *query_name = NULL, *mname = NULL; + dns_rdataset_t *mrdataset = NULL; + dns_rdataset_t *opt = NULL; + dns_request_t *request = NULL; + + /* Construct query message */ + CHECK(convert_name(&qfn, &query_name, qname)); + + dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); + message->opcode = dns_opcode_query; + message->flags = DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_AD; + if (cdflag) { + message->flags |= DNS_MESSAGEFLAG_CD; + } + message->rdclass = dns_rdataclass_in; + message->id = (dns_messageid_t)isc_random16(); + + dns_message_gettempname(message, &mname); + dns_message_gettemprdataset(message, &mrdataset); + dns_name_clone(query_name, mname); + dns_rdataset_makequestion(mrdataset, dns_rdataclass_in, qtype); + ISC_LIST_APPEND(mname->list, mrdataset, link); + dns_message_addname(message, mname, DNS_SECTION_QUESTION); + mrdataset = NULL; + mname = NULL; + + CHECK(dns_message_buildopt(message, &opt, 0, 0, DNS_MESSAGEEXTFLAG_DO, + NULL, 0)); + CHECK(dns_message_setopt(message, opt)); + + CHECK(dns_requestmgr_create(mctx, dispatchmgr, NULL, NULL, + &requestmgr)); + + dns_view_attach(view, &(dns_view_t *){ NULL }); + CHECK(dns_request_create(requestmgr, message, NULL, &peer, NULL, NULL, + DNS_REQUESTOPT_TCP, NULL, 1, 0, 0, + isc_loop_current(loopmgr), recvresponse, + message, &request)); + return; + +cleanup: + if (message != NULL) { + if (mname != NULL) { + dns_message_puttempname(message, &mname); + } + if (mrdataset != NULL) { + dns_message_puttemprdataset(message, &mrdataset); + } + dns_message_detach(&message); + } + + shutdown_server(); +} + +static isc_result_t +matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr, + dns_message_t *message, dns_aclenv_t *env, isc_result_t *sigresultp, + dns_view_t **viewp) { + UNUSED(srcaddr); + UNUSED(destaddr); + UNUSED(message); + UNUSED(env); + UNUSED(sigresultp); + + *viewp = view; + return (ISC_R_SUCCESS); +} + +static void +run_server(void *arg) { + isc_result_t result; + dns_cache_t *cache = NULL; + isc_sockaddr_t addr, any; + struct in_addr in; + + UNUSED(arg); + + inet_pton(AF_INET, "127.0.0.1", &in); + isc_sockaddr_fromin(&addr, &in, 0); + + CHECK(ns_server_create(mctx, matchview, &sctx)); + + CHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); + isc_sockaddr_any(&any); + CHECK(dns_dispatch_createudp(dispatchmgr, &any, &dispatch)); + CHECK(ns_interfacemgr_create(mctx, sctx, loopmgr, netmgr, dispatchmgr, + NULL, false, &interfacemgr)); + + CHECK(dns_view_create(mctx, dns_rdataclass_in, "_default", &view)); + CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", &cache)); + dns_view_setcache(view, cache, false); + dns_cache_detach(&cache); + dns_view_setdstport(view, destport); + + CHECK(dns_rootns_create(mctx, dns_rdataclass_in, hintfile, &roothints)); + dns_view_sethints(view, roothints); + dns_db_detach(&roothints); + + view->qminimization = qmin; + view->qmin_strict = qmin_strict; + + CHECK(dns_view_initsecroots(view, mctx)); + CHECK(setup_dnsseckeys(NULL, view)); + + dns_view_setdispatchmgr(view, dispatchmgr); + CHECK(dns_view_createresolver(view, loopmgr, 1, netmgr, 0, + tlsctx_client_cache, dispatch, NULL)); + + CHECK(isc_stats_create(mctx, &resstats, dns_resstatscounter_max)); + dns_resolver_setstats(view->resolver, resstats); + isc_stats_detach(&resstats); + + CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); + dns_resolver_setquerystats(view->resolver, resquerystats); + dns_stats_detach(&resquerystats); + + dns_view_freeze(view); + + ns_interface_create(interfacemgr, &addr, NULL, &ifp); + + CHECK(isc_nm_listenstreamdns(netmgr, ISC_NM_LISTEN_ONE, &addr, + ns_client_request, ifp, accept_cb, ifp, 10, + NULL, NULL, &ifp->tcplistensocket)); + ifp->flags |= NS_INTERFACEFLAG_LISTENING; + isc_job_run(loopmgr, sendquery, ifp->tcplistensocket); + + return; + +cleanup: + if (view != NULL) { + dns_view_detach(&view); + } + shutdown_server(); +} + int main(int argc, char *argv[]) { - dns_client_t *client = NULL; isc_result_t result; + isc_loop_t *loop = NULL; progname = argv[0]; + logfp = stderr; + preparse_args(argc, argv); argc--; argv++; isc_managers_create(&mctx, 1, &loopmgr, &netmgr); + loop = isc_loop_main(loopmgr); result = dst_lib_init(mctx, NULL); if (result != ISC_R_SUCCESS) { @@ -1822,33 +2204,30 @@ main(int argc, char *argv[]) { CHECK(setup_style()); - setup_logging(stderr); + setup_logging(logfp); + + if (!fulltrace && hintfile != NULL) { + delv_log(ISC_LOG_WARNING, + "WARNING: not using internal name server mode, " + "hint file will be ignored"); + } + + if (fulltrace && server != NULL) { + delv_log(ISC_LOG_WARNING, + "WARNING: using internal name server mode: " + "'@%s' will be ignored", + server); + } - /* Create client */ isc_tlsctx_cache_create(mctx, &tlsctx_client_cache); - result = dns_client_create(mctx, loopmgr, netmgr, 0, - tlsctx_client_cache, &client, srcaddr4, - srcaddr6); - if (result != ISC_R_SUCCESS) { - delv_log(ISC_LOG_ERROR, "dns_client_create: %s", - isc_result_totext(result)); - goto cleanup; - } - - /* Set the nameserver */ - if (server != NULL) { - addserver(client); - } else { - findserver(client); - } - - CHECK(setup_dnsseckeys(client)); - - isc_loop_setup(isc_loop_main(loopmgr), resolve, client); + isc_loop_setup(loop, fulltrace ? run_server : run_resolve, NULL); isc_loopmgr_run(loopmgr); cleanup: + if (tlsctx_client_cache != NULL) { + isc_tlsctx_cache_detach(&tlsctx_client_cache); + } if (trust_anchor != NULL) { isc_mem_free(mctx, trust_anchor); } @@ -1861,12 +2240,8 @@ cleanup: if (style != NULL) { dns_master_styledestroy(&style, mctx); } - if (tlsctx_client_cache != NULL) { - isc_tlsctx_cache_detach(&tlsctx_client_cache); - } isc_log_destroy(&lctx); - dst_lib_destroy(); isc_managers_destroy(&mctx, &loopmgr, &netmgr); diff --git a/bin/delv/delv.rst b/bin/delv/delv.rst index 827e3377ba..61d1b701a9 100644 --- a/bin/delv/delv.rst +++ b/bin/delv/delv.rst @@ -230,6 +230,36 @@ assign values to options like the timeout interval. They have the form This option controls whether to display the CLASS when printing a record. The default is to display the CLASS. +.. option:: +hint=FILE, +nohint + + This option specifies a filename from which to load root hints; + this will be used to find the root name servers when name server + mode (``delv +ns``) is in use. If the option is not specified, + built-in root hints will be used. + +.. option:: +ns, +nons + + This option toggles name server mode. When this option is in use, + the ``delv`` process instantiates a full recursive resolver, and uses + that to look up the requested query name and type. Turning on this + option also activates ``+mtrace``, ``+strace`` and ``+rtrace``, so that + every iterative query will be logged, including the full response messages + from each authoritatve server. These logged messages will be written + to ``stdout`` rather than ``stderr`` as usual, so that the full trace + can be captured more easily. + + This is intended to be similar to the behavior of ``dig +trace``, but + because it uses the same code as ``named``, it much more accurately + replicates the behavior of a recursive name server with a cold cache + that is processing a recursive query. + +.. option:: +qmin[=MODE], +noqmin + + When used with ``+ns``, this option enables QNAME minimization mode. + Valid options of MODE are ``relaxed`` and ``strict``. By default, + QNAME minimization is disabled. If ``+qmin`` is specified but MODE + is omitted, then ``relaxed`` mode will be used. + .. option:: +ttl, +nottl This option controls whether to display the TTL when printing a record. The @@ -237,11 +267,11 @@ assign values to options like the timeout interval. They have the form .. option:: +rtrace, +nortrace - This option toggles resolver fetch logging. This reports the name and type of each - query sent by :program:`delv` in the process of carrying out the resolution - and validation process, including the original query - and all subsequent queries to follow CNAMEs and to establish a chain - of trust for DNSSEC validation. + This option toggles resolver fetch logging. This reports the name and + type of each query sent by :program:`delv` in the process of carrying + out the resolution and validation process, including the original query + and all subsequent queries to follow CNAMEs and to establish a chain of + trust for DNSSEC validation. This is equivalent to setting the debug level to 1 in the "resolver" logging category. Setting the systemwide debug level to 1 using the @@ -250,15 +280,27 @@ assign values to options like the timeout interval. They have the form .. option:: +mtrace, +nomtrace - This option toggles message logging. This produces a detailed dump of the - responses received by :program:`delv` in the process of carrying out the - resolution and validation process. + This option toggles logging of messages received. This produces + a detailed dump of the responses received by :program:`delv` in the + process of carrying out the resolution and validation process. This is equivalent to setting the debug level to 10 for the "packets" module of the "resolver" logging category. Setting the systemwide debug level to 10 using the :option:`-d` option produces the same output, but affects other logging categories as well. +.. option:: +strace, +nostrace + + This option toggles logging of messages sent. This produces a detailed + dump of the queries sent by :program:`delv` in the process of carrying + out the resolution and validation process. Turning on this option + also activates ``+mtrace``. + + This is equivalent to setting the debug level to 11 for the "packets" + module of the "resolver" logging category. Setting the systemwide + debug level to 11 using the :option:`-d` option produces the same + output, but affects other logging categories as well. + .. option:: +vtrace, +novtrace This option toggles validation logging. This shows the internal process of the diff --git a/bin/tests/system/digdelv/clean.sh b/bin/tests/system/digdelv/clean.sh index 77e467a499..a64603600c 100644 --- a/bin/tests/system/digdelv/clean.sh +++ b/bin/tests/system/digdelv/clean.sh @@ -13,7 +13,7 @@ set -e -rm -f ./*/anchor.* +rm -f ./anchor.* ./*/anchor.* rm -f ./*/named.conf rm -f ./*/named.memstats rm -f ./*/named.run @@ -28,9 +28,10 @@ rm -f ./dig.out.nn.* rm -f ./host.out.test* rm -f ./ns*/managed-keys.bind* rm -f ./ns*/named.lock -rm -f ./ns2/dsset-example. -rm -f ./ns2/dsset-example.tld. -rm -f ./ns2/example.db ./ns2/K* ./ns2/keyid ./ns2/keydata +rm -f ./ns*/K* ./ns*/keyid ./ns*/keydata +rm -f ./ns1/root.db +rm -f ./ns*/dsset-* +rm -f ./ns2/example.db rm -f ./ns2/example.tld.db rm -f ./nslookup.out.test* rm -f ./nsupdate.out.test* diff --git a/bin/tests/system/digdelv/ns1/root.db b/bin/tests/system/digdelv/ns1/root.db.in similarity index 100% rename from bin/tests/system/digdelv/ns1/root.db rename to bin/tests/system/digdelv/ns1/root.db.in diff --git a/bin/tests/system/digdelv/ns1/sign.sh b/bin/tests/system/digdelv/ns1/sign.sh new file mode 100644 index 0000000000..2651c191c1 --- /dev/null +++ b/bin/tests/system/digdelv/ns1/sign.sh @@ -0,0 +1,31 @@ +#!/bin/sh -e + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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. + +# shellcheck source=conf.sh +. ../../conf.sh + +set -e + +(cd ../ns2 && $SHELL sign.sh ) + +cp "../ns2/dsset-example." . + +ksk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone .) + +cp root.db.in root.db + +"$SIGNER" -Sgz -f root.db -o . root.db.in > /dev/null 2>&1 + +keyfile_to_key_id "$ksk" > keyid +grep -Ev '^;' < "$ksk.key" | cut -f 7- -d ' ' > keydata +keyfile_to_initial_keys "$ksk" > anchor.dnskey diff --git a/bin/tests/system/digdelv/setup.sh b/bin/tests/system/digdelv/setup.sh index ca63977593..92dd6bf3b2 100644 --- a/bin/tests/system/digdelv/setup.sh +++ b/bin/tests/system/digdelv/setup.sh @@ -20,4 +20,4 @@ copy_setports ns1/named.conf.in ns1/named.conf copy_setports ns2/named.conf.in ns2/named.conf copy_setports ns3/named.conf.in ns3/named.conf -cd ns2 && $SHELL sign.sh +cd ns1 && $SHELL sign.sh diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index 9e82298f35..d222e57d10 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -54,7 +54,7 @@ check_ttl_range() { return $result } -# using delv insecure mode as not testing dnssec here +# use delv insecure mode by default, as we're mostly not testing dnssec delv_with_opts() { "$DELV" +noroot -p "$PORT" "$@" } @@ -1404,6 +1404,42 @@ if [ -x "$DELV" ] ; then if [ $ret -ne 0 ]; then echo_i "failed"; fi status=$((status+ret)) + n=$((n+1)) + echo_i "checking delv +ns (no validation) ($n)" + ret=0 + delv_with_opts -i +ns +hint=../common/root.hint a a.example > delv.out.test$n || ret=1 + grep -q '; authoritative' delv.out.test$n || ret=1 + grep -q '_.example' delv.out.test$n && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +ns +qmin (no validation) ($n)" + ret=0 + delv_with_opts -i +ns +qmin +hint=../common/root.hint a a.example > delv.out.test$n || ret=1 + grep -q '; authoritative' delv.out.test$n || ret=1 + grep -q '_.example' delv.out.test$n || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +ns (with validation) ($n)" + ret=0 + delv_with_opts -a ns1/anchor.dnskey +root +ns +hint=../common/root.hint a a.example > delv.out.test$n || ret=1 + grep -q '; fully validated' delv.out.test$n || ret=1 + grep -q '_.example' delv.out.test$n && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +ns +qmin (with validation) ($n)" + ret=0 + delv_with_opts -a ns1/anchor.dnskey +root +ns +qmin +hint=../common/root.hint a a.example > delv.out.test$n || ret=1 + grep -q '; fully validated' delv.out.test$n || ret=1 + grep -q '_.example' delv.out.test$n || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else echo_i "$DELV is needed, so skipping these delv tests" fi diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 438b47c6dd..208086c7e1 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -23,6 +23,17 @@ New Features - BIND now depends on ``liburcu``, Userspace RCU, for lock-free data structures. :gl:`#3934` +- The new ``delv +ns`` option activates name server mode, in which ``delv`` + sets up an internal recursive resolver and uses that, rather than an + external server, to look up the requested query name and type. All messages + sent and received during the resolution and validation process are logged. + This can be used in place of ``dig +trace``: it more accurately + reproduces the behavior of ``named`` when resolving a query. + + The log message ``resolver priming query complete`` was moved from the + INFO log level to the DEBUG(1) log level, to prevent ``delv`` from + emitting that message when setting up its internal resolver. :gl:`#3842` + Removed Features ~~~~~~~~~~~~~~~~ diff --git a/lib/dns/client.c b/lib/dns/client.c index a32f33645b..579b9c3aab 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -1074,45 +1074,8 @@ isc_result_t dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, const dns_name_t *keyname, isc_buffer_t *databuf) { - isc_result_t result; - dns_keytable_t *secroots = NULL; - dns_name_t *name = NULL; - char rdatabuf[DST_KEY_MAXSIZE]; - unsigned char digest[ISC_MAX_MD_SIZE]; - dns_rdata_ds_t ds; - dns_rdata_t rdata; - isc_buffer_t b; - REQUIRE(DNS_CLIENT_VALID(client)); REQUIRE(rdclass == dns_rdataclass_in); - CHECK(dns_view_getsecroots(client->view, &secroots)); - - DE_CONST(keyname, name); - - if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) { - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - - isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); - dns_rdata_init(&rdata); - isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf)); - CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, - DNS_DECOMPRESS_NEVER, &b)); - - if (rdtype == dns_rdatatype_ds) { - CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); - } else { - CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, - digest, &ds)); - } - - CHECK(dns_keytable_add(secroots, false, false, name, &ds, NULL, NULL)); - -cleanup: - if (secroots != NULL) { - dns_keytable_detach(&secroots); - } - return (result); + return (dns_view_addtrustedkey(client->view, rdtype, keyname, databuf)); } diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index 166822433b..543a5ffb5d 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -279,10 +279,11 @@ dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, const dns_name_t *keyname, isc_buffer_t *keydatabuf); /*%< - * Add a DNSSEC trusted key for the 'rdclass' class. A view for the 'rdclass' - * class must be created beforehand. 'rdtype' is the type of the RR data - * for the key, either DNSKEY or DS. 'keyname' is the DNS name of the key, - * and 'keydatabuf' stores the RR data. + * Add a DNSSEC trusted key for the 'rdclass' class (only class 'IN' is + * currently supported). A view for the 'rdclass' class must be created + * beforehand. 'rdtype' is the type of the RR data for the key, either + * DNSKEY or DS. 'keyname' is the DNS name of the key, and 'keydatabuf' + * stores the RR data. * * Requires: * diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 0a697fc8c0..71f7541019 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -1262,4 +1262,29 @@ dns_view_getdispatchmgr(dns_view_t *view); * by the resolver and request managers to send and receive DNS * messages. */ + +isc_result_t +dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype, + const dns_name_t *keyname, isc_buffer_t *databuf); +/*%< + * Add a DNSSEC trusted key to a view of class 'IN'. 'rdtype' is the type + * of the RR data for the key, either DNSKEY or DS. 'keyname' is the DNS + * name of the key, and 'databuf' stores the RR data. + + * Requires: + * + *\li 'view' is a valid view. + + *\li 'view' is class 'IN'. + * + *\li 'keyname' is a valid name. + * + *\li 'keydatabuf' is a valid buffer. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ ISC_LANG_ENDDECLS diff --git a/lib/dns/request.c b/lib/dns/request.c index e3bef774b5..f78a57d7a3 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -921,7 +921,7 @@ req_connected(isc_result_t eresult, isc_region_t *region, void *arg) { req_send(request); } else { request_cancel(request); - req_sendevent(request, ISC_R_CANCELED); + req_sendevent(request, eresult); } UNLOCK(&request->requestmgr->locks[request->hash]); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 1299b9f480..10ba6e807d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -9974,7 +9974,7 @@ prime_done(void *arg) { REQUIRE(VALID_RESOLVER(res)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, - DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), "resolver priming query complete: %s", isc_result_totext(resp->result)); diff --git a/lib/dns/view.c b/lib/dns/view.c index 551b1ebd4c..686075b309 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2323,3 +2324,44 @@ dns_view_getdispatchmgr(dns_view_t *view) { REQUIRE(DNS_VIEW_VALID(view)); return (view->dispatchmgr); } + +isc_result_t +dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype, + const dns_name_t *keyname, isc_buffer_t *databuf) { + isc_result_t result; + dns_name_t *name = NULL; + char rdatabuf[DST_KEY_MAXSIZE]; + unsigned char digest[ISC_MAX_MD_SIZE]; + dns_rdata_ds_t ds; + dns_rdata_t rdata; + isc_buffer_t b; + + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->rdclass == dns_rdataclass_in); + + DE_CONST(keyname, name); + + if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) { + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + + isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); + dns_rdata_init(&rdata); + isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf)); + CHECK(dns_rdata_fromwire(&rdata, view->rdclass, rdtype, databuf, + DNS_DECOMPRESS_NEVER, &b)); + + if (rdtype == dns_rdatatype_ds) { + CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); + } else { + CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, + digest, &ds)); + } + + CHECK(dns_keytable_add(view->secroots_priv, false, false, name, &ds, + NULL, NULL)); + +cleanup: + return (result); +} diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 5c7a4e735a..aa90e6f80a 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -729,3 +729,9 @@ isc_nmhandle_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value); * * \li 'handle' is a valid netmgr handle object. */ + +isc_sockaddr_t +isc_nmsocket_getaddr(isc_nmsocket_t *sock); +/*%< + * Return the local address of 'sock'. + */ diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 96a6aab991..095baf09b0 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -479,7 +479,6 @@ struct isc_nmsocket { isc_nmsocket_type type; isc__networker_t *worker; - isc_mutex_t lock; isc_barrier_t listen_barrier; isc_barrier_t stop_barrier; diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 42b8f834c6..bdc5905aeb 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -2538,6 +2538,12 @@ isc_nmhandle_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value) { return (result); } +isc_sockaddr_t +isc_nmsocket_getaddr(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + return (sock->iface); +} + #if ISC_NETMGR_TRACE /* * Dump all active sockets in netmgr. We output to stderr diff --git a/lib/isc/netmgr/streamdns.c b/lib/isc/netmgr/streamdns.c index 4e3cf5b5dc..2b3c8c38b9 100644 --- a/lib/isc/netmgr/streamdns.c +++ b/lib/isc/netmgr/streamdns.c @@ -748,6 +748,11 @@ isc_nm_listenstreamdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, return (result); } + /* copy the actual port we're listening on into sock->iface */ + if (isc_sockaddr_getport(iface) == 0) { + listener->iface = listener->outer->iface; + } + listener->result = result; atomic_store(&listener->active, true); atomic_store(&listener->listening, true); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 66c3a0f9e4..5de84444ad 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -350,10 +350,10 @@ start_tcp_child_job(void *arg) { REQUIRE(sock->tid == isc_tid()); sa_family_t sa_family = sock->iface.type.sa.sa_family; - int r; - int flags = 0; + int r, flags = 0; isc_result_t result = ISC_R_UNSET; isc_loop_t *loop = sock->worker->loop; + struct sockaddr_storage ss; (void)isc__nm_socket_min_mtu(sock->fd, sa_family); (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG); @@ -418,8 +418,25 @@ start_tcp_child_job(void *arg) { atomic_store(&sock->listening, true); + if (sock->tid == 0) { + r = uv_tcp_getsockname(&sock->uv_handle.tcp, + (struct sockaddr *)&ss, + &(int){ sizeof(ss) }); + if (r != 0) { + goto done; + } + + result = isc_sockaddr_fromsockaddr(&sock->parent->iface, + (struct sockaddr *)&ss); + if (result != ISC_R_SUCCESS) { + goto done_result; + } + } + done: result = isc_uverr2result(r); + +done_result: atomic_fetch_add(&sock->parent->rchildren, 1); if (result != ISC_R_SUCCESS) { diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index 3f74d9608b..6d6cc12df0 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -937,6 +937,11 @@ isc_nm_listentls(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, return (result); } + /* copy the actual port we're listening on into sock->iface */ + if (isc_sockaddr_getport(iface) == 0) { + tlssock->iface = tlssock->outer->iface; + } + /* wait for listen result */ isc__nmsocket_attach(tlssock->outer, &tsock); tlssock->result = result; diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c index 7c99c75c67..512f08bdee 100644 --- a/lib/isc/sockaddr.c +++ b/lib/isc/sockaddr.c @@ -491,9 +491,9 @@ isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) { return (ISC_R_NOTIMPLEMENTED); } - memset(isa, 0, sizeof(isc_sockaddr_t)); + *isa = (isc_sockaddr_t){ .length = length, + .link = ISC_LINK_INITIALIZER }; memmove(isa, sa, length); - isa->length = length; return (ISC_R_SUCCESS); } diff --git a/lib/ns/client.c b/lib/ns/client.c index 13b4b4f49b..c016c8986c 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1680,8 +1680,8 @@ ns__client_put_cb(void *client0) { * or tcpmsg (TCP case). */ void -ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *arg) { +ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *arg) { ns_client_t *client = NULL; isc_result_t result; isc_result_t sigresult = ISC_R_SUCCESS; diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index bfd4e131c4..28f4bfd929 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -445,8 +445,8 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, */ void -ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *arg); +ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *arg); /*%< * Handle client requests. diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 3da1c93d85..651f4d429b 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -193,3 +193,11 @@ ns_interfacemgr_dynamic_updates_are_reliable(void); * disabled. That is the case on the platforms where kernel-based * mechanisms for tracking networking interface states is reliable enough. */ + +void +ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + const char *name, ns_interface_t **ifpret); +/*%< + * Create an interface 'name' associated with address 'addr'. If + * 'name' is NULL then it is set to "default". + */ diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index bb51603960..ae73e42340 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -443,16 +443,20 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { } } -static void -interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, - ns_interface_t **ifpret) { +void +ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + const char *name, ns_interface_t **ifpret) { ns_interface_t *ifp = NULL; + const char *default_name = "default"; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); *ifp = (ns_interface_t){ .generation = mgr->generation, .addr = *addr }; + if (name == NULL) { + name = default_name; + } strlcpy(ifp->name, name, sizeof(ifp->name)); isc_mutex_init(&ifp->lock); @@ -478,7 +482,7 @@ ns_interface_listenudp(ns_interface_t *ifp) { /* Reserve space for an ns_client_t with the netmgr handle */ result = isc_nm_listenudp(ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, - ns__client_request, ifp, + ns_client_request, ifp, &ifp->udplistensocket); return (result); } @@ -488,7 +492,7 @@ ns_interface_listentcp(ns_interface_t *ifp) { isc_result_t result; result = isc_nm_listenstreamdns( - ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, ns__client_request, + ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, ns_client_request, ifp, ns__client_tcpconn, ifp, ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota, NULL, &ifp->tcplistensocket); if (result != ISC_R_SUCCESS) { @@ -521,7 +525,7 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) { isc_result_t result; result = isc_nm_listenstreamdns( - ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, ns__client_request, + ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, ns_client_request, ifp, ns__client_tcpconn, ifp, ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota, sslctx, &ifp->tcplistensocket); @@ -555,7 +559,7 @@ load_http_endpoints(isc_nm_http_endpoints_t *epset, ns_interface_t *ifp, for (size_t i = 0; i < neps; i++) { result = isc_nm_http_endpoints_add(epset, eps[i], - ns__client_request, ifp); + ns_client_request, ifp); if (result != ISC_R_SUCCESS) { break; } @@ -651,7 +655,7 @@ interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ifp = *ifpret; if (ifp == NULL) { - interface_create(mgr, addr, name, &ifp); + ns_interface_create(mgr, addr, name, &ifp); } else { REQUIRE(!LISTENING(ifp)); } @@ -1193,8 +1197,8 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) { mgr->aclenv, &match, NULL); if (match <= 0) { ns_interface_t *new = NULL; - interface_create(mgr, &listen_sockaddr, - interface.name, &new); + ns_interface_create(mgr, &listen_sockaddr, + interface.name, &new); continue; } diff --git a/tests/libtest/ns.c b/tests/libtest/ns.c index 49c60256e2..4e450c86dd 100644 --- a/tests/libtest/ns.c +++ b/tests/libtest/ns.c @@ -456,7 +456,7 @@ ns_test_qctx_create(const ns_test_qctx_create_params_t *params, /* * Allow recursion for the client. As NS_CLIENTATTR_RA normally gets - * set in ns__client_request(), i.e. earlier than the unit tests hook + * set in ns_client_request(), i.e. earlier than the unit tests hook * into the call chain, just set it manually. */ client->attributes |= NS_CLIENTATTR_RA; diff --git a/tests/ns/query_test.c b/tests/ns/query_test.c index d0466cb083..2c538c4320 100644 --- a/tests/ns/query_test.c +++ b/tests/ns/query_test.c @@ -247,19 +247,15 @@ typedef struct { dns_rdatatype_t qtype; /* QTYPE */ unsigned int qflags; /* query flags */ bool disable_name_checks; /* if set to true, owner - * name - * checks will + * name checks will * be disabled for the - * view created - * */ + * view created + */ bool recursive_service; /* if set to true, the view - * created will - * have a cache - * database - * attached */ + * created will have a cache + * database attached */ const char *auth_zone_origin; /* origin name of the zone - * the - * created view will be + * the created view will be * authoritative for */ const char *auth_zone_path; /* path to load the * authoritative