summaryrefslogtreecommitdiff
path: root/lib/addns
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2020-07-17 14:30:02 -0700
committerAndreas Schneider <asn@cryptomilk.org>2020-08-07 06:34:36 +0000
commita1b90237d6082faccf69b13dec8ddc589fa3b588 (patch)
tree4e0d1f04b84ea135527ac971c2f1afb2e7244eb9 /lib/addns
parent47c1b8742308cd31ed4267379242446ff40eb494 (diff)
downloadsamba-a1b90237d6082faccf69b13dec8ddc589fa3b588.tar.gz
lib: addns: Add code for asynchronously looking up AAAA 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.c206
-rw-r--r--lib/addns/dnsquery.h16
2 files changed, 222 insertions, 0 deletions
diff --git a/lib/addns/dnsquery.c b/lib/addns/dnsquery.c
index 77bf1b2e86d..03cadfaef0a 100644
--- a/lib/addns/dnsquery.c
+++ b/lib/addns/dnsquery.c
@@ -574,6 +574,212 @@ fail:
return status;
}
+#if defined(HAVE_IPV6)
+/*********************************************************************
+ Async AAAA record lookup.
+*********************************************************************/
+
+struct ads_dns_lookup_aaaa_state {
+ uint8_t rcode;
+ size_t num_names;
+ char **hostnames;
+ struct samba_sockaddr *addrs;
+};
+
+static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name)
+{
+ struct tevent_req *req, *subreq = NULL;
+ struct ads_dns_lookup_aaaa_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ads_dns_lookup_aaaa_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = dns_lookup_send(
+ state,
+ ev,
+ NULL,
+ name,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_AAAA);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_lookup_aaaa_done, req);
+ return req;
+}
+
+static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_aaaa_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 -> IPv6 lookup.
+ */
+ for (i = 0; i < reply->ancount; i++) {
+ if (reply->answers[i].rr_type == DNS_QTYPE_AAAA) {
+ 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_AAAA) {
+ continue;
+ }
+ if (an->name == NULL) {
+ /* Can this happen? */
+ continue;
+ }
+ if (an->rdata.ipv6_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_in6);
+
+ 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_aaaa_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_aaaa_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_aaaa_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 AAAA query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_aaaa(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out)
+{
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_lookup_aaaa_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_aaaa_recv(req,
+ ctx,
+ NULL,
+ num_names_out,
+ hostnames_out,
+ addrs_out);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+#endif
+
/********************************************************************
Query with optional sitename.
********************************************************************/
diff --git a/lib/addns/dnsquery.h b/lib/addns/dnsquery.h
index 6083852e983..3f8cc13983b 100644
--- a/lib/addns/dnsquery.h
+++ b/lib/addns/dnsquery.h
@@ -62,6 +62,22 @@ NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx,
size_t *num_names_out,
char ***hostnames_out,
struct samba_sockaddr **addrs_out);
+#if defined(HAVE_IPV6)
+struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name);
+NTSTATUS ads_dns_lookup_aaaa_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_aaaa(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out);
+#endif
NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
const char *realm,