summaryrefslogtreecommitdiff
path: root/lib/addns
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2020-07-17 14:21:09 -0700
committerAndreas Schneider <asn@cryptomilk.org>2020-08-07 06:34:36 +0000
commit47c1b8742308cd31ed4267379242446ff40eb494 (patch)
tree79f7db3797e8ac0c0fc53b55b3caf4c49697f98d /lib/addns
parentfc83b470513890c30bbb26ebd3a9ab4438b3d4a4 (diff)
downloadsamba-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.c202
-rw-r--r--lib/addns/dnsquery.h15
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,