>From 5ce8809b522afa1226718ce5b354b24783e90793 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 7 Feb 2017 11:29:55 -0800 Subject: [PATCH 31/33] Move to async name resolution for names returned by SRV lookups For small setups and correctly configured one, DNS servers will add additional records in the SRV response with the A/AAAA entries associated with the name that are returned. But if it's too large or if the server is not correctly configured then the additional names are not returned and we have to resort on calling getaddrinfo. Traditionally we have been doing it in sequence but for large/slow network it can be an issue. With this change resolution is now asynchronous (using pthreadpool_tevent framework), all the DNS requests are fired at once and then we wait for all the threads to provide the results before assembling the ip_list response Signed-off-by: Matthieu Patou Change-Id: Ib755bbe98a5bd649d4959bd2474fc883f0ae65df --- source3/libsmb/namequery.c | 220 +++++++++++++++++++++++++++++++-------------- 1 file changed, 151 insertions(+), 69 deletions(-) diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 945fc64..0bbcc5a 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -28,6 +28,7 @@ #include "libsmb/nmblib.h" #include "../libcli/nbt/libnbt.h" #include "libads/kerberos_proto.h" +#include "lib/pthreadpool/pthreadpool_tevent.h" /* nmbd.c sets this to True. */ bool global_in_nmbd = False; @@ -2361,6 +2362,35 @@ static NTSTATUS resolve_hosts(const char *name, int name_type, return NT_STATUS_UNSUCCESSFUL; } +static void resolve_one_name(void *private_data) +{ + struct dns_rr_srv *rr = private_data; + struct addrinfo *res = NULL; + struct addrinfo *p; + int num_ips = 0; + if (!interpret_string_addr_internal(&res, rr->hostname, 0)) { + return; + } + /* Add in every IP from the lookup. How many is that ? */ + for (p = res; p; p = p->ai_next) { + if (num_ips != 0) { + if (NULL == (rr->ss_s = talloc_realloc(rr->ss_s, rr->ss_s, + struct sockaddr_storage, num_ips + 1))) + { + return; + } + } + memcpy(&rr->ss_s[num_ips], p->ai_addr, p->ai_addrlen); + if (is_zero_addr(&rr->ss_s[num_ips])) { + continue; + } + num_ips++; + } + rr->num_ips = num_ips; + if (res) { + freeaddrinfo(res); + } +} /******************************************************** Resolve via "ADS" method. *********************************************************/ @@ -2380,6 +2410,12 @@ static NTSTATUS resolve_ads(const char *name, struct dns_rr_srv *dcs = NULL; int numdcs = 0; int numaddrs = 0; + int allocated_addrs = 0; + int ret; + struct pthreadpool_tevent *pth_tevent; + struct tevent_context *ev; + struct tevent_req *req1, **allreqs; + bool exec_continue = true; if ((name_type != 0x1c) && (name_type != KDC_NAME_TYPE) && (name_type != 0x1b)) { @@ -2437,98 +2473,144 @@ static NTSTATUS resolve_ads(const char *name, return NT_STATUS_OK; } - for (i=0;i allocated_addrs) { + allocated_addrs = numaddrs + dcs[i].num_ips + delta; + *return_iplist = SMB_REALLOC_ARRAY(*return_iplist, + struct ip_service, + allocated_addrs); + } + for (j = 0; j < dcs[i].num_ips; j++) { + (*return_iplist)[*return_count].port = dcs[i].port; + (*return_iplist)[*return_count].ss = dcs[i].ss_s[j]; + if (is_zero_addr(&(*return_iplist)[*return_count].ss)) { continue; } - /* Add in every IP from the lookup. How - many is that ? */ - for (p = res; p; p = p->ai_next) { - struct sockaddr_storage ss; - memcpy(&ss, p->ai_addr, p->ai_addrlen); - if (is_zero_addr(&ss)) { - continue; - } - extra_addrs++; - } - if (extra_addrs > 1) { - /* We need to expand the return_iplist array - as we only budgeted for one address. */ - numaddrs += (extra_addrs-1); - *return_iplist = SMB_REALLOC_ARRAY(*return_iplist, - struct ip_service, - numaddrs); - if (*return_iplist == NULL) { - if (res) { - freeaddrinfo(res); - } - talloc_destroy(ctx); - return NT_STATUS_NO_MEMORY; - } - } - for (p = res; p; p = p->ai_next) { - (*return_iplist)[*return_count].port = dcs[i].port; - memcpy(&(*return_iplist)[*return_count].ss, - p->ai_addr, - p->ai_addrlen); - if (is_zero_addr(&(*return_iplist)[*return_count].ss)) { - continue; - } - (*return_count)++; - /* Should never happen, but still... */ - if (*return_count>=numaddrs) { - break; - } - } - if (res) { - freeaddrinfo(res); - } - } else { - /* use all the IP addresses from the SRV sresponse */ - int j; - for (j = 0; j < dcs[i].num_ips; j++) { - (*return_iplist)[*return_count].port = dcs[i].port; - (*return_iplist)[*return_count].ss = dcs[i].ss_s[j]; - if (is_zero_addr(&(*return_iplist)[*return_count].ss)) { - continue; - } - (*return_count)++; - /* Should never happen, but still... */ - if (*return_count>=numaddrs) { + (*return_count)++; + numaddrs++; + if (*return_count >= allocated_addrs) { + /* + * This should never happen but if it's the last + * DC and the last entry actually the condition + * is not really unexpected. + */ + if (!((*return_count == allocated_addrs) && + (j == (dcs[i].num_ips - 1)) && + (i == (numdcs - 1)))) { + DEBUG(0,("resolve_ads: unexpected condition met "\ + "return_count > allocated_addrs (%d vs %d) "\ + "while processing %s\n" , + *return_count, + allocated_addrs, + dcs[i].hostname)); break; } } } } + DEBUG(10,("resolve_ads: returning %d entries\n", *return_count)); talloc_destroy(ctx); return NT_STATUS_OK; -- 2.7.4