diff options
author | Jeremy Allison <jra@samba.org> | 2020-07-17 14:21:09 -0700 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2020-08-07 06:34:36 +0000 |
commit | 47c1b8742308cd31ed4267379242446ff40eb494 (patch) | |
tree | 79f7db3797e8ac0c0fc53b55b3caf4c49697f98d /lib/addns | |
parent | fc83b470513890c30bbb26ebd3a9ab4438b3d4a4 (diff) | |
download | samba-47c1b8742308cd31ed4267379242446ff40eb494.tar.gz |
lib: addns: Add code for asynchronously looking up A records.
Returns an array of struct samba_sockaddr.
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'lib/addns')
-rw-r--r-- | lib/addns/dnsquery.c | 202 | ||||
-rw-r--r-- | lib/addns/dnsquery.h | 15 |
2 files changed, 217 insertions, 0 deletions
diff --git a/lib/addns/dnsquery.c b/lib/addns/dnsquery.c index 90e4de9a053..77bf1b2e86d 100644 --- a/lib/addns/dnsquery.c +++ b/lib/addns/dnsquery.c @@ -371,6 +371,208 @@ fail: return status; } +/********************************************************************* + Async A record lookup. +*********************************************************************/ + +struct ads_dns_lookup_a_state { + uint8_t rcode; + size_t num_names; + char **hostnames; + struct samba_sockaddr *addrs; +}; + +static void ads_dns_lookup_a_done(struct tevent_req *subreq); + +struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *name) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct ads_dns_lookup_a_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct ads_dns_lookup_a_state); + if (req == NULL) { + return NULL; + } + + subreq = dns_lookup_send( + state, + ev, + NULL, + name, + DNS_QCLASS_IN, + DNS_QTYPE_A); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ads_dns_lookup_a_done, req); + return req; +} + +static void ads_dns_lookup_a_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ads_dns_lookup_a_state *state = tevent_req_data( + req, struct ads_dns_lookup_a_state); + int ret; + struct dns_name_packet *reply = NULL; + uint16_t i; + + ret = dns_lookup_recv(subreq, state, &reply); + TALLOC_FREE(subreq); + if (ret != 0) { + tevent_req_nterror(req, map_nt_error_from_unix_common(ret)); + return; + } + + state->rcode = (reply->operation & DNS_RCODE); + if (state->rcode != DNS_RCODE_OK) { + /* Don't bother looking for answers. */ + tevent_req_done(req); + return; + } + + /* + * We don't care about CNAME answers here. We're + * just wanting an async name -> IPv4 lookup. + */ + for (i = 0; i < reply->ancount; i++) { + if (reply->answers[i].rr_type == DNS_QTYPE_A) { + state->num_names += 1; + } + } + + state->hostnames = talloc_zero_array(state, + char *, + state->num_names); + if (tevent_req_nomem(state->hostnames, req)) { + return; + } + state->addrs = talloc_zero_array(state, + struct samba_sockaddr, + state->num_names); + if (tevent_req_nomem(state->addrs, req)) { + return; + } + + state->num_names = 0; + + for (i = 0; i < reply->ancount; i++) { + bool ok; + struct sockaddr_storage ss = {0}; + struct dns_res_rec *an = &reply->answers[i]; + + if (an->rr_type != DNS_QTYPE_A) { + continue; + } + if (an->name == NULL) { + /* Can this happen? */ + continue; + } + if (an->rdata.ipv4_record == NULL) { + /* Can this happen? */ + continue; + } + ok = dns_res_rec_get_sockaddr(an, + &ss); + if (!ok) { + continue; + } + if (is_zero_addr(&ss)) { + continue; + } + state->addrs[state->num_names].u.ss = ss; + state->addrs[state->num_names].sa_socklen = + sizeof(struct sockaddr_in); + state->hostnames[state->num_names] = talloc_strdup( + state->hostnames, + an->name); + if (tevent_req_nomem(state->hostnames[state->num_names], req)) { + return; + } + state->num_names += 1; + } + + tevent_req_done(req); +} + +NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uint8_t *rcode_out, + size_t *num_names_out, + char ***hostnames_out, + struct samba_sockaddr **addrs_out) +{ + struct ads_dns_lookup_a_state *state = tevent_req_data( + req, struct ads_dns_lookup_a_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (rcode_out != NULL) { + /* + * If we got no names, an upper layer may + * want to print a debug message. + */ + *rcode_out = state->rcode; + } + if (hostnames_out != NULL) { + *hostnames_out = talloc_move(mem_ctx, + &state->hostnames); + } + if (addrs_out != NULL) { + *addrs_out = talloc_move(mem_ctx, + &state->addrs); + } + *num_names_out = state->num_names; + tevent_req_received(req); + return NT_STATUS_OK; +} + +/********************************************************************* + Simple wrapper for a DNS A query +*********************************************************************/ + +NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx, + const char *name_in, + size_t *num_names_out, + char ***hostnames_out, + struct samba_sockaddr **addrs_out) +{ + struct tevent_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + ev = samba_tevent_context_init(ctx); + if (ev == NULL) { + goto fail; + } + req = ads_dns_lookup_a_send(ev, ev, name_in); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + /* + * Sychronous doesn't need to care about the rcode or + * a copy of the name_in. + */ + status = ads_dns_lookup_a_recv(req, + ctx, + NULL, + num_names_out, + hostnames_out, + addrs_out); +fail: + TALLOC_FREE(ev); + return status; +} /******************************************************************** Query with optional sitename. diff --git a/lib/addns/dnsquery.h b/lib/addns/dnsquery.h index bb691f5d55a..6083852e983 100644 --- a/lib/addns/dnsquery.h +++ b/lib/addns/dnsquery.h @@ -48,6 +48,21 @@ NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx, const char *dnsdomain, struct dns_rr_ns **nslist, int *numns); +struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *name); +NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uint8_t *rcode_out, + size_t *num_names_out, + char ***hostnames_out, + struct samba_sockaddr **addrs_out); +NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx, + const char *name_in, + size_t *num_names_out, + char ***hostnames_out, + struct samba_sockaddr **addrs_out); + NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx, const char *realm, const char *sitename, |