diff options
author | Jeremy Allison <jra@samba.org> | 2020-07-21 12:34:02 -0700 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2020-08-07 06:34:37 +0000 |
commit | 5ffcd883ddd4aef9ded18bee65562a8423e2f6c6 (patch) | |
tree | fa907c0c26b41762ae8e1e48c4ef171db9be3e88 | |
parent | 8a140391d6d2bba65275bdc7a85a33cc502dbfb7 (diff) | |
download | samba-5ffcd883ddd4aef9ded18bee65562a8423e2f6c6.tar.gz |
s3: libsmb: Add dns_lookup_list_async() - not yet used.
Take a list of hostnames and does async A and AAAA (if
supported) lookups on them. Interface compatible with
dns_lookup_list() (with the addition of one extra
parameter returning the query name list, for use inside
dsgetdcname() internals later) and we'll replace it in the next
commit. Waits for lp_get_async_dns_timeout() seconds to complete.
Commented out as not yet used.
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r-- | source3/libsmb/namequery.c | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 734d921372c..590113be44c 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -31,6 +31,7 @@ #include "../libcli/nbt/libnbt.h" #include "libads/kerberos_proto.h" #include "lib/gencache.h" +#include "librpc/gen_ndr/dns.h" /* nmbd.c sets this to True. */ bool global_in_nmbd = False; @@ -2280,6 +2281,395 @@ fail: return status; } +#if 0 +/******************************************************** + Use ads_dns_lookup_[a|aaaa]_send() calls to look up a + list of names asynchronously. +*********************************************************/ + +struct dns_query_state { + /* Used to tell our parent we've completed. */ + struct dns_lookup_list_async_state *p_async_state; + const char *query_name; /* For debugging only. */ + size_t num_addrs; + struct samba_sockaddr *addrs; +}; + +struct dns_lookup_list_async_state { + bool timed_out; + size_t num_query_returns; + struct dns_query_state *queries; +}; + +/* Called on query timeout. */ +static void dns_lookup_send_timeout_handler(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval t, + void *private_data) +{ + bool *timed_out = (bool *)private_data; + *timed_out = true; +} + +static void dns_lookup_list_a_done(struct tevent_req *req); +#if defined(HAVE_IPV6) +static void dns_lookup_list_aaaa_done(struct tevent_req *req); +#endif + +static NTSTATUS dns_lookup_list_async(TALLOC_CTX *ctx, + size_t num_dns_names, + const char **dns_lookup_names, + size_t *p_num_addrs, + struct sockaddr_storage **pp_addrs, + char ***pp_dns_names) +{ + struct dns_lookup_list_async_state *state = NULL; + struct tevent_context *ev = NULL; + struct tevent_req *req = NULL; + struct tevent_timer *timer = NULL; + size_t num_queries_sent = 0; + size_t queries_size = num_dns_names; + size_t i; + size_t num_addrs = 0; + struct sockaddr_storage *addr_out = NULL; + char **dns_names_ret = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + /* Nothing to do. */ + if (num_dns_names == 0) { + *p_num_addrs = 0; + *pp_addrs = NULL; + if (pp_dns_names != NULL) { + *pp_dns_names = NULL; + } + return NT_STATUS_OK; + } + + state = talloc_zero(ctx, struct dns_lookup_list_async_state); + if (state == NULL) { + goto fail; + } + ev = samba_tevent_context_init(ctx); + if (ev == NULL) { + goto fail; + } + +#if defined(HAVE_IPV6) + queries_size = 2 * num_dns_names; + /* Wrap protection. */ + if (queries_size < num_dns_names) { + goto fail; + } +#else + queries_size = num_dns_names; +#endif + + state->queries = talloc_zero_array(state, + struct dns_query_state, + queries_size); + if (state == NULL) { + goto fail; + } + + /* Hit all the DNS servers with asnyc lookups for all the names. */ + for (i = 0; i < num_dns_names; i++) { + DBG_INFO("async DNS lookup A record for %s\n", + dns_lookup_names[i]); + + /* Setup the query state. */ + state->queries[num_queries_sent].query_name = + dns_lookup_names[i]; + state->queries[num_queries_sent].p_async_state = state; + + req = ads_dns_lookup_a_send(ev, ev, dns_lookup_names[i]); + if (req == NULL) { + goto fail; + } + tevent_req_set_callback(req, + dns_lookup_list_a_done, + &state->queries[num_queries_sent]); + num_queries_sent++; + +#if defined(HAVE_IPV6) + /* If we're IPv6 capable ask for that too. */ + state->queries[num_queries_sent].query_name = + dns_lookup_names[i]; + state->queries[num_queries_sent].p_async_state = state; + + DBG_INFO("async DNS lookup AAAA record for %s\n", + dns_lookup_names[i]); + + req = ads_dns_lookup_aaaa_send(ev, ev, dns_lookup_names[i]); + if (req == NULL) { + goto fail; + } + tevent_req_set_callback(req, + dns_lookup_list_aaaa_done, + &state->queries[num_queries_sent]); + num_queries_sent++; +#endif + } + + /* We must always have a timeout. */ + timer = tevent_add_timer(ev, + ev, + timeval_current_ofs(lp_get_async_dns_timeout(), + 0), + dns_lookup_send_timeout_handler, + &state->timed_out); + if (timer == NULL) { + goto fail; + } + + /* Loop until timed out or got all replies. */ + for(;;) { + int ret; + + if (state->timed_out) { + break; + } + if (state->num_query_returns == num_queries_sent) { + break; + } + ret = tevent_loop_once(ev); + if (ret != 0) { + goto fail; + } + } + + /* Count what we got back. */ + for (i = 0; i < num_queries_sent; i++) { + struct dns_query_state *query = &state->queries[i]; + + /* Wrap check. */ + if (num_addrs + query->num_addrs < num_addrs) { + goto fail; + } + num_addrs += query->num_addrs; + } + + if (state->timed_out) { + DBG_INFO("async DNS lookup timed out after %zu entries " + "(not an error)\n", + num_addrs); + } + + addr_out = talloc_zero_array(ctx, + struct sockaddr_storage, + num_addrs); + if (addr_out == NULL) { + goto fail; + } + + /* + * Did the caller want an array of names back + * that match the IP addresses ? If we provide + * this, dsgetdcname() internals can now use this + * async lookup code also. + */ + if (pp_dns_names != NULL) { + dns_names_ret = talloc_zero_array(ctx, + char *, + num_addrs); + if (dns_names_ret == NULL) { + goto fail; + } + } + + /* Copy what we got back. */ + num_addrs = 0; + for (i = 0; i < num_queries_sent; i++) { + size_t j; + struct dns_query_state *query = &state->queries[i]; + + if (query->num_addrs == 0) { + continue; + } + + if (dns_names_ret != NULL) { + /* + * If caller wants a name array matched with + * the addrs array, copy the same queried name for + * each IP address returned. + */ + for (j = 0; j < query->num_addrs; j++) { + dns_names_ret[num_addrs + j] = talloc_strdup( + ctx, + query->query_name); + if (dns_names_ret[num_addrs + j] == NULL) { + goto fail; + } + } + } + + for (j = 0; j < query->num_addrs; j++) { + addr_out[num_addrs] = query->addrs[j].u.ss; + } + num_addrs += query->num_addrs; + } + + *p_num_addrs = num_addrs; + *pp_addrs = addr_out; + if (pp_dns_names != NULL) { + *pp_dns_names = dns_names_ret; + } + + status = NT_STATUS_OK; + + fail: + + TALLOC_FREE(state); + TALLOC_FREE(ev); + return status; +} + +/* + Called when an A record lookup completes. +*/ + +static void dns_lookup_list_a_done(struct tevent_req *req) +{ + /* + * Callback data is an element of a talloc'ed array, + * not a talloc object in its own right. So use the + * tevent_req_callback_data_void() void * cast function. + */ + struct dns_query_state *state = (struct dns_query_state *) + tevent_req_callback_data_void(req); + uint8_t rcode = 0; + size_t i; + char **hostnames_out = NULL; + struct samba_sockaddr *addrs = NULL; + size_t num_addrs = 0; + NTSTATUS status; + + /* For good or ill, tell the parent we're finished. */ + state->p_async_state->num_query_returns++; + + status = ads_dns_lookup_a_recv(req, + state->p_async_state, + &rcode, + &num_addrs, + &hostnames_out, + &addrs); + if (!NT_STATUS_IS_OK(status)) { + DBG_INFO("async DNS A lookup for %s returned %s\n", + state->query_name, + nt_errstr(status)); + return; + } + + if (rcode != DNS_RCODE_OK) { + DBG_INFO("async DNS A lookup for %s returned DNS code %u\n", + state->query_name, + (unsigned int)rcode); + return; + } + + if (num_addrs == 0) { + DBG_INFO("async DNS A lookup for %s returned 0 addresses.\n", + state->query_name); + return; + } + + /* Copy data out. */ + state->addrs = talloc_zero_array(state->p_async_state, + struct samba_sockaddr, + num_addrs); + if (state->addrs == NULL) { + return; + } + + for (i = 0; i < num_addrs; i++) { + char addr[INET6_ADDRSTRLEN]; + DBG_INFO("async DNS A lookup for %s [%zu] got %s -> %s\n", + state->query_name, + i, + hostnames_out[i], + print_sockaddr(addr, + sizeof(addr), + &addrs[i].u.ss)); + + state->addrs[i] = addrs[i]; + } + state->num_addrs = num_addrs; +} + +#if defined(HAVE_IPV6) +/* + Called when an AAAA record lookup completes. +*/ + +static void dns_lookup_list_aaaa_done(struct tevent_req *req) +{ + /* + * Callback data is an element of a talloc'ed array, + * not a talloc object in its own right. So use the + * tevent_req_callback_data_void() void * cast function. + */ + struct dns_query_state *state = (struct dns_query_state *) + tevent_req_callback_data_void(req); + uint8_t rcode = 0; + size_t i; + char **hostnames_out = NULL; + struct samba_sockaddr *addrs = NULL; + size_t num_addrs = 0; + NTSTATUS status; + + /* For good or ill, tell the parent we're finished. */ + state->p_async_state->num_query_returns++; + + status = ads_dns_lookup_aaaa_recv(req, + state->p_async_state, + &rcode, + &num_addrs, + &hostnames_out, + &addrs); + if (!NT_STATUS_IS_OK(status)) { + DBG_INFO("async DNS AAAA lookup for %s returned %s\n", + state->query_name, + nt_errstr(status)); + return; + } + + if (rcode != DNS_RCODE_OK) { + DBG_INFO("async DNS AAAA lookup for %s returned DNS code %u\n", + state->query_name, + (unsigned int)rcode); + return; + } + + if (num_addrs == 0) { + DBG_INFO("async DNS AAAA lookup for %s returned 0 addresses.\n", + state->query_name); + return; + } + + /* Copy data out. */ + state->addrs = talloc_zero_array(state->p_async_state, + struct samba_sockaddr, + num_addrs); + if (state->addrs == NULL) { + return; + } + + for (i = 0; i < num_addrs; i++) { + char addr[INET6_ADDRSTRLEN]; + DBG_INFO("async DNS AAAA lookup for %s [%zu] got %s -> %s\n", + state->query_name, + i, + hostnames_out[i], + print_sockaddr(addr, + sizeof(addr), + &addrs[i].u.ss)); + + state->addrs[i] = addrs[i]; + } + state->num_addrs = num_addrs; +} +#endif +#endif + /******************************************************** Resolve a list of DNS names to a list of IP addresses. As this is a DC / LDAP / KDC lookup any IP address will |