LCOV - code coverage report
Current view: top level - lib/addns - dnsquery.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 221 354 62.4 %
Date: 2024-04-21 15:09:00 Functions: 15 17 88.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    DNS utility library
       4             :    Copyright (C) Gerald (Jerry) Carter           2006.
       5             :    Copyright (C) Jeremy Allison                  2007.
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "lib/util/util_net.h"
      23             : #include "lib/util/tsort.h"
      24             : #include "librpc/gen_ndr/dns.h"
      25             : #include "libcli/dns/dns_lookup.h"
      26             : #include "lib/util/tevent_ntstatus.h"
      27             : #include "dnsquery.h"
      28             : 
      29             : /*********************************************************************
      30             :  Sort SRV record list based on weight and priority.  See RFC 2782.
      31             : *********************************************************************/
      32             : 
      33           0 : static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
      34             : {
      35           0 :         if ( a->priority == b->priority ) {
      36             : 
      37             :                 /* randomize entries with an equal weight and priority */
      38           0 :                 if ( a->weight == b->weight )
      39           0 :                         return 0;
      40             : 
      41             :                 /* higher weights should be sorted lower */
      42           0 :                 if ( a->weight > b->weight )
      43           0 :                         return -1;
      44             :                 else
      45           0 :                         return 1;
      46             :         }
      47             : 
      48           0 :         if ( a->priority < b->priority )
      49           0 :                 return -1;
      50             : 
      51           0 :         return 1;
      52             : }
      53             : 
      54             : struct ads_dns_lookup_srv_state {
      55             :         struct dns_rr_srv *srvs;
      56             :         size_t num_srvs;
      57             : };
      58             : 
      59             : static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
      60             : 
      61         466 : struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
      62             :                                            struct tevent_context *ev,
      63             :                                            const char *name)
      64             : {
      65           0 :         struct tevent_req *req, *subreq;
      66           0 :         struct ads_dns_lookup_srv_state *state;
      67             : 
      68         466 :         req = tevent_req_create(mem_ctx, &state,
      69             :                                 struct ads_dns_lookup_srv_state);
      70         466 :         if (req == NULL) {
      71           0 :                 return NULL;
      72             :         }
      73             : 
      74         466 :         subreq = dns_lookup_send(
      75             :                 state,
      76             :                 ev,
      77             :                 NULL,
      78             :                 name,
      79             :                 DNS_QCLASS_IN,
      80             :                 DNS_QTYPE_SRV);
      81             : 
      82         466 :         if (tevent_req_nomem(subreq, req)) {
      83           0 :                 return tevent_req_post(req, ev);
      84             :         }
      85         466 :         tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
      86         466 :         return req;
      87             : }
      88             : 
      89         466 : static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
      90             : {
      91         466 :         struct tevent_req *req = tevent_req_callback_data(
      92             :                 subreq, struct tevent_req);
      93         466 :         struct ads_dns_lookup_srv_state *state = tevent_req_data(
      94             :                 req, struct ads_dns_lookup_srv_state);
      95           0 :         int ret;
      96           0 :         struct dns_name_packet *reply;
      97           0 :         uint16_t i, idx;
      98             : 
      99         466 :         ret = dns_lookup_recv(subreq, state, &reply);
     100         466 :         TALLOC_FREE(subreq);
     101         466 :         if (ret != 0) {
     102          13 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
     103          13 :                 return;
     104             :         }
     105             : 
     106         898 :         for (i=0; i<reply->ancount; i++) {
     107         445 :                 if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
     108             :                         /* uint16_t can't wrap here. */
     109         445 :                         state->num_srvs += 1;
     110             :                 }
     111             :         }
     112             : 
     113         453 :         state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
     114         453 :         if (tevent_req_nomem(state->srvs, req)) {
     115           0 :                 return;
     116             :         }
     117             : 
     118         453 :         idx = 0;
     119             : 
     120         898 :         for (i=0; i<reply->ancount; i++) {
     121         445 :                 struct dns_res_rec *an = &reply->answers[i];
     122         445 :                 struct dns_rr_srv *dst = &state->srvs[idx];
     123           0 :                 struct dns_srv_record *src;
     124             : 
     125         445 :                 if (an->rr_type != DNS_QTYPE_SRV) {
     126           0 :                         continue;
     127             :                 }
     128         445 :                 src = &an->rdata.srv_record;
     129             : 
     130         445 :                 *dst = (struct dns_rr_srv) {
     131         445 :                         .hostname = talloc_move(state->srvs, &src->target),
     132         445 :                         .priority = src->priority,
     133         445 :                         .weight = src->weight,
     134         445 :                         .port = src->port,
     135             :                 };
     136         445 :                 idx += 1;
     137             :         }
     138             : 
     139         453 :         for (i=0; i<reply->arcount; i++) {
     140           0 :                 struct dns_res_rec *ar = &reply->additional[i];
     141           0 :                 struct sockaddr_storage addr;
     142           0 :                 bool ok;
     143           0 :                 size_t j;
     144             : 
     145           0 :                 ok = dns_res_rec_get_sockaddr(ar, &addr);
     146           0 :                 if (!ok) {
     147           0 :                         continue;
     148             :                 }
     149             : 
     150           0 :                 for (j=0; j<state->num_srvs; j++) {
     151           0 :                         struct dns_rr_srv *srv = &state->srvs[j];
     152           0 :                         struct sockaddr_storage *tmp;
     153             : 
     154           0 :                         if (strcmp(srv->hostname, ar->name) != 0) {
     155           0 :                                 continue;
     156             :                         }
     157             :                         /* uint16_t can't wrap here. */
     158           0 :                         tmp = talloc_realloc(
     159             :                                 state->srvs,
     160             :                                 srv->ss_s,
     161             :                                 struct sockaddr_storage,
     162             :                                 srv->num_ips+1);
     163             : 
     164           0 :                         if (tevent_req_nomem(tmp, req)) {
     165           0 :                                 return;
     166             :                         }
     167           0 :                         srv->ss_s = tmp;
     168             : 
     169           0 :                         srv->ss_s[srv->num_ips] = addr;
     170           0 :                         srv->num_ips += 1;
     171             :                 }
     172             :         }
     173             : 
     174         453 :         TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
     175             : 
     176         453 :         tevent_req_done(req);
     177             : }
     178             : 
     179         466 : NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
     180             :                                  TALLOC_CTX *mem_ctx,
     181             :                                  struct dns_rr_srv **srvs,
     182             :                                  size_t *num_srvs)
     183             : {
     184         466 :         struct ads_dns_lookup_srv_state *state = tevent_req_data(
     185             :                 req, struct ads_dns_lookup_srv_state);
     186           0 :         NTSTATUS status;
     187             : 
     188         466 :         if (tevent_req_is_nterror(req, &status)) {
     189          13 :                 return status;
     190             :         }
     191         453 :         *srvs = talloc_move(mem_ctx, &state->srvs);
     192         453 :         *num_srvs = state->num_srvs;
     193         453 :         tevent_req_received(req);
     194         453 :         return NT_STATUS_OK;
     195             : }
     196             : 
     197             : /*********************************************************************
     198             :  Simple wrapper for a DNS SRV query
     199             : *********************************************************************/
     200             : 
     201           0 : NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
     202             :                                 const char *name,
     203             :                                 struct dns_rr_srv **dclist,
     204             :                                 size_t *numdcs)
     205             : {
     206           0 :         struct tevent_context *ev;
     207           0 :         struct tevent_req *req;
     208           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     209           0 :         size_t num_srvs = 0;
     210             : 
     211           0 :         ev = samba_tevent_context_init(ctx);
     212           0 :         if (ev == NULL) {
     213           0 :                 goto fail;
     214             :         }
     215           0 :         req = ads_dns_lookup_srv_send(ev, ev, name);
     216           0 :         if (req == NULL) {
     217           0 :                 goto fail;
     218             :         }
     219           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     220           0 :                 goto fail;
     221             :         }
     222           0 :         status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
     223           0 :         if (NT_STATUS_IS_OK(status)) {
     224           0 :                 *numdcs = num_srvs;
     225             :         }
     226           0 : fail:
     227           0 :         TALLOC_FREE(ev);
     228           0 :         return status;
     229             : }
     230             : 
     231             : struct ads_dns_lookup_ns_state {
     232             :         struct dns_rr_ns *nss;
     233             :         size_t num_nss;
     234             : };
     235             : 
     236             : static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
     237             : 
     238          64 : struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
     239             :                                           struct tevent_context *ev,
     240             :                                           const char *name)
     241             : {
     242           0 :         struct tevent_req *req, *subreq;
     243           0 :         struct ads_dns_lookup_ns_state *state;
     244             : 
     245          64 :         req = tevent_req_create(mem_ctx, &state,
     246             :                                 struct ads_dns_lookup_ns_state);
     247          64 :         if (req == NULL) {
     248           0 :                 return NULL;
     249             :         }
     250             : 
     251          64 :         subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
     252             :                                  DNS_QTYPE_NS);
     253          64 :         if (tevent_req_nomem(subreq, req)) {
     254           0 :                 return tevent_req_post(req, ev);
     255             :         }
     256          64 :         tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
     257          64 :         return req;
     258             : }
     259             : 
     260          64 : static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
     261             : {
     262          64 :         struct tevent_req *req = tevent_req_callback_data(
     263             :                 subreq, struct tevent_req);
     264          64 :         struct ads_dns_lookup_ns_state *state = tevent_req_data(
     265             :                 req, struct ads_dns_lookup_ns_state);
     266           0 :         int ret;
     267           0 :         struct dns_name_packet *reply;
     268           0 :         uint16_t i, idx;
     269             : 
     270          64 :         ret = dns_lookup_recv(subreq, state, &reply);
     271          64 :         TALLOC_FREE(subreq);
     272          64 :         if (ret != 0) {
     273           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
     274           0 :                 return;
     275             :         }
     276             : 
     277         106 :         for (i=0; i<reply->ancount; i++) {
     278          42 :                 if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
     279          42 :                         state->num_nss += 1;
     280             :                 }
     281             :         }
     282             : 
     283          64 :         state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
     284          64 :         if (tevent_req_nomem(state->nss, req)) {
     285           0 :                 return;
     286             :         }
     287             : 
     288          64 :         idx = 0;
     289             : 
     290         106 :         for (i=0; i<reply->ancount; i++) {
     291          42 :                 struct dns_res_rec *an = &reply->answers[i];
     292             : 
     293          42 :                 if (an->rr_type != DNS_QTYPE_NS) {
     294           0 :                         continue;
     295             :                 }
     296             : 
     297          42 :                 state->nss[idx].hostname = talloc_move(state->nss,
     298             :                                                        &an->rdata.ns_record);
     299          42 :                 idx += 1;
     300             :         }
     301             : 
     302          64 :         for (i=0; i<reply->arcount; i++) {
     303           0 :                 struct dns_res_rec *ar = &reply->additional[i];
     304           0 :                 struct sockaddr_storage addr;
     305           0 :                 bool ok;
     306           0 :                 size_t j;
     307             : 
     308           0 :                 ok = dns_res_rec_get_sockaddr(ar, &addr);
     309           0 :                 if (!ok) {
     310           0 :                         continue;
     311             :                 }
     312             : 
     313           0 :                 for (j=0; j<state->num_nss; j++) {
     314           0 :                         struct dns_rr_ns *ns = &state->nss[j];
     315             : 
     316           0 :                         if (strcmp(ns->hostname, ar->name) == 0) {
     317           0 :                                 ns->ss = addr;
     318             :                         }
     319             :                 }
     320             :         }
     321             : 
     322          64 :         tevent_req_done(req);
     323             : }
     324             : 
     325          64 : NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
     326             :                                 TALLOC_CTX *mem_ctx,
     327             :                                 struct dns_rr_ns **nss,
     328             :                                 size_t *num_nss)
     329             : {
     330          64 :         struct ads_dns_lookup_ns_state *state = tevent_req_data(
     331             :                 req, struct ads_dns_lookup_ns_state);
     332           0 :         NTSTATUS status;
     333             : 
     334          64 :         if (tevent_req_is_nterror(req, &status)) {
     335           0 :                 return status;
     336             :         }
     337          64 :         *nss = talloc_move(mem_ctx, &state->nss);
     338          64 :         *num_nss = state->num_nss;
     339          64 :         tevent_req_received(req);
     340          64 :         return NT_STATUS_OK;
     341             : }
     342             : 
     343             : /*********************************************************************
     344             :  Simple wrapper for a DNS NS query
     345             : *********************************************************************/
     346             : 
     347          64 : NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
     348             :                                 const char *dnsdomain,
     349             :                                 struct dns_rr_ns **nslist,
     350             :                                 size_t *numns)
     351             : {
     352           0 :         struct tevent_context *ev;
     353           0 :         struct tevent_req *req;
     354          64 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     355          64 :         size_t num_ns = 0;
     356             : 
     357          64 :         ev = samba_tevent_context_init(ctx);
     358          64 :         if (ev == NULL) {
     359           0 :                 goto fail;
     360             :         }
     361          64 :         req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
     362          64 :         if (req == NULL) {
     363           0 :                 goto fail;
     364             :         }
     365          64 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     366           0 :                 goto fail;
     367             :         }
     368          64 :         status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
     369          64 :         *numns = num_ns;
     370          64 : fail:
     371          64 :         TALLOC_FREE(ev);
     372          64 :         return status;
     373             : }
     374             : 
     375             : /*********************************************************************
     376             :  Async A record lookup.
     377             : *********************************************************************/
     378             : 
     379             : struct ads_dns_lookup_a_state {
     380             :         uint8_t rcode;
     381             :         size_t num_names;
     382             :         char **hostnames;
     383             :         struct samba_sockaddr *addrs;
     384             : };
     385             : 
     386             : static void ads_dns_lookup_a_done(struct tevent_req *subreq);
     387             : 
     388         447 : struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx,
     389             :                                          struct tevent_context *ev,
     390             :                                          const char *name)
     391             : {
     392         447 :         struct tevent_req *req = NULL, *subreq = NULL;
     393         447 :         struct ads_dns_lookup_a_state *state = NULL;
     394             : 
     395         447 :         req = tevent_req_create(mem_ctx, &state,
     396             :                                 struct ads_dns_lookup_a_state);
     397         447 :         if (req == NULL) {
     398           0 :                 return NULL;
     399             :         }
     400             : 
     401         447 :         subreq = dns_lookup_send(
     402             :                 state,
     403             :                 ev,
     404             :                 NULL,
     405             :                 name,
     406             :                 DNS_QCLASS_IN,
     407             :                 DNS_QTYPE_A);
     408             : 
     409         447 :         if (tevent_req_nomem(subreq, req)) {
     410           0 :                 return tevent_req_post(req, ev);
     411             :         }
     412         447 :         tevent_req_set_callback(subreq, ads_dns_lookup_a_done, req);
     413         447 :         return req;
     414             : }
     415             : 
     416         447 : static void ads_dns_lookup_a_done(struct tevent_req *subreq)
     417             : {
     418         447 :         struct tevent_req *req = tevent_req_callback_data(
     419             :                 subreq, struct tevent_req);
     420         447 :         struct ads_dns_lookup_a_state *state = tevent_req_data(
     421             :                 req, struct ads_dns_lookup_a_state);
     422           0 :         int ret;
     423         447 :         struct dns_name_packet *reply = NULL;
     424           0 :         uint16_t i;
     425             : 
     426         447 :         ret = dns_lookup_recv(subreq, state, &reply);
     427         447 :         TALLOC_FREE(subreq);
     428         447 :         if (ret != 0) {
     429           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
     430           0 :                 return;
     431             :         }
     432             : 
     433         447 :         state->rcode = (reply->operation & DNS_RCODE);
     434         447 :         if (state->rcode != DNS_RCODE_OK) {
     435             :                 /* Don't bother looking for answers. */
     436           0 :                 tevent_req_done(req);
     437           0 :                 return;
     438             :         }
     439             : 
     440             :         /*
     441             :          * We don't care about CNAME answers here. We're
     442             :          * just wanting an async name -> IPv4 lookup.
     443             :          */
     444         894 :         for (i = 0; i < reply->ancount; i++) {
     445         447 :                 if (reply->answers[i].rr_type == DNS_QTYPE_A) {
     446         447 :                         state->num_names += 1;
     447             :                 }
     448             :         }
     449             : 
     450         447 :         state->hostnames = talloc_zero_array(state,
     451             :                                              char *,
     452             :                                              state->num_names);
     453         447 :         if (tevent_req_nomem(state->hostnames, req)) {
     454           0 :                 return;
     455             :         }
     456         447 :         state->addrs = talloc_zero_array(state,
     457             :                                          struct samba_sockaddr,
     458             :                                          state->num_names);
     459         447 :         if (tevent_req_nomem(state->addrs, req)) {
     460           0 :                 return;
     461             :         }
     462             : 
     463         447 :         state->num_names = 0;
     464             : 
     465         894 :         for (i = 0; i < reply->ancount; i++) {
     466           0 :                 bool ok;
     467         447 :                 struct sockaddr_storage ss = {0};
     468         447 :                 struct dns_res_rec *an = &reply->answers[i];
     469             : 
     470         447 :                 if (an->rr_type != DNS_QTYPE_A) {
     471           0 :                         continue;
     472             :                 }
     473         447 :                 if (an->name == NULL) {
     474             :                         /* Can this happen? */
     475           0 :                         continue;
     476             :                 }
     477         447 :                 if (an->rdata.ipv4_record == NULL) {
     478             :                         /* Can this happen? */
     479           0 :                         continue;
     480             :                 }
     481         447 :                 ok = dns_res_rec_get_sockaddr(an,
     482             :                                               &ss);
     483         447 :                 if (!ok) {
     484           0 :                         continue;
     485             :                 }
     486         447 :                 if (is_zero_addr(&ss)) {
     487           0 :                         continue;
     488             :                 }
     489         447 :                 state->addrs[state->num_names].u.ss = ss;
     490         447 :                 state->addrs[state->num_names].sa_socklen =
     491             :                                         sizeof(struct sockaddr_in);
     492         894 :                 state->hostnames[state->num_names] = talloc_strdup(
     493         447 :                                                         state->hostnames,
     494             :                                                         an->name);
     495         447 :                 if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
     496           0 :                         return;
     497             :                 }
     498         447 :                 state->num_names += 1;
     499             :         }
     500             : 
     501         447 :         tevent_req_done(req);
     502             : }
     503             : 
     504         447 : NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req,
     505             :                                TALLOC_CTX *mem_ctx,
     506             :                                uint8_t *rcode_out,
     507             :                                size_t *num_names_out,
     508             :                                char ***hostnames_out,
     509             :                                struct samba_sockaddr **addrs_out)
     510             : {
     511         447 :         struct ads_dns_lookup_a_state *state = tevent_req_data(
     512             :                 req, struct ads_dns_lookup_a_state);
     513           0 :         NTSTATUS status;
     514             : 
     515         447 :         if (tevent_req_is_nterror(req, &status)) {
     516           0 :                 return status;
     517             :         }
     518         447 :         if (rcode_out != NULL) {
     519             :                 /*
     520             :                  * If we got no names, an upper layer may
     521             :                  * want to print a debug message.
     522             :                  */
     523         445 :                 *rcode_out = state->rcode;
     524             :         }
     525         447 :         if (hostnames_out != NULL) {
     526         447 :                 *hostnames_out = talloc_move(mem_ctx,
     527             :                                              &state->hostnames);
     528             :         }
     529         447 :         if (addrs_out != NULL) {
     530         447 :                 *addrs_out = talloc_move(mem_ctx,
     531             :                                          &state->addrs);
     532             :         }
     533         447 :         *num_names_out = state->num_names;
     534         447 :         tevent_req_received(req);
     535         447 :         return NT_STATUS_OK;
     536             : }
     537             : 
     538             : /*********************************************************************
     539             :  Simple wrapper for a DNS A query
     540             : *********************************************************************/
     541             : 
     542           2 : NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx,
     543             :                           const char *name_in,
     544             :                           size_t *num_names_out,
     545             :                           char ***hostnames_out,
     546             :                           struct samba_sockaddr **addrs_out)
     547             : {
     548           0 :         struct tevent_context *ev;
     549           0 :         struct tevent_req *req;
     550           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     551             : 
     552           2 :         ev = samba_tevent_context_init(ctx);
     553           2 :         if (ev == NULL) {
     554           0 :                 goto fail;
     555             :         }
     556           2 :         req = ads_dns_lookup_a_send(ev, ev, name_in);
     557           2 :         if (req == NULL) {
     558           0 :                 goto fail;
     559             :         }
     560           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     561           0 :                 goto fail;
     562             :         }
     563             :         /*
     564             :          * Synchronous doesn't need to care about the rcode or
     565             :          * a copy of the name_in.
     566             :          */
     567           2 :         status = ads_dns_lookup_a_recv(req,
     568             :                                        ctx,
     569             :                                        NULL,
     570             :                                        num_names_out,
     571             :                                        hostnames_out,
     572             :                                        addrs_out);
     573           2 : fail:
     574           2 :         TALLOC_FREE(ev);
     575           2 :         return status;
     576             : }
     577             : 
     578             : #if defined(HAVE_IPV6)
     579             : /*********************************************************************
     580             :  Async AAAA record lookup.
     581             : *********************************************************************/
     582             : 
     583             : struct ads_dns_lookup_aaaa_state {
     584             :         uint8_t rcode;
     585             :         size_t num_names;
     586             :         char **hostnames;
     587             :         struct samba_sockaddr *addrs;
     588             : };
     589             : 
     590             : static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq);
     591             : 
     592         447 : struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
     593             :                                             struct tevent_context *ev,
     594             :                                             const char *name)
     595             : {
     596         447 :         struct tevent_req *req, *subreq = NULL;
     597         447 :         struct ads_dns_lookup_aaaa_state *state = NULL;
     598             : 
     599         447 :         req = tevent_req_create(mem_ctx, &state,
     600             :                                 struct ads_dns_lookup_aaaa_state);
     601         447 :         if (req == NULL) {
     602           0 :                 return NULL;
     603             :         }
     604             : 
     605         447 :         subreq = dns_lookup_send(
     606             :                 state,
     607             :                 ev,
     608             :                 NULL,
     609             :                 name,
     610             :                 DNS_QCLASS_IN,
     611             :                 DNS_QTYPE_AAAA);
     612             : 
     613         447 :         if (tevent_req_nomem(subreq, req)) {
     614           0 :                 return tevent_req_post(req, ev);
     615             :         }
     616         447 :         tevent_req_set_callback(subreq, ads_dns_lookup_aaaa_done, req);
     617         447 :         return req;
     618             : }
     619             : 
     620         447 : static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq)
     621             : {
     622         447 :         struct tevent_req *req = tevent_req_callback_data(
     623             :                 subreq, struct tevent_req);
     624         447 :         struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
     625             :                 req, struct ads_dns_lookup_aaaa_state);
     626           0 :         int ret;
     627         447 :         struct dns_name_packet *reply = NULL;
     628           0 :         uint16_t i;
     629             : 
     630         447 :         ret = dns_lookup_recv(subreq, state, &reply);
     631         447 :         TALLOC_FREE(subreq);
     632         447 :         if (ret != 0) {
     633           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
     634           0 :                 return;
     635             :         }
     636             : 
     637         447 :         state->rcode = (reply->operation & DNS_RCODE);
     638         447 :         if (state->rcode != DNS_RCODE_OK) {
     639             :                 /* Don't bother looking for answers. */
     640           0 :                 tevent_req_done(req);
     641           0 :                 return;
     642             :         }
     643             : 
     644             :         /*
     645             :          * We don't care about CNAME answers here. We're
     646             :          * just wanting an async name -> IPv6 lookup.
     647             :          */
     648         892 :         for (i = 0; i < reply->ancount; i++) {
     649         445 :                 if (reply->answers[i].rr_type == DNS_QTYPE_AAAA) {
     650         445 :                         state->num_names += 1;
     651             :                 }
     652             :         }
     653             : 
     654         447 :         state->hostnames = talloc_zero_array(state,
     655             :                                              char *,
     656             :                                              state->num_names);
     657         447 :         if (tevent_req_nomem(state->hostnames, req)) {
     658           0 :                 return;
     659             :         }
     660         447 :         state->addrs = talloc_zero_array(state,
     661             :                                          struct samba_sockaddr,
     662             :                                          state->num_names);
     663         447 :         if (tevent_req_nomem(state->addrs, req)) {
     664           0 :                 return;
     665             :         }
     666             : 
     667         447 :         state->num_names = 0;
     668             : 
     669         892 :         for (i = 0; i < reply->ancount; i++) {
     670           0 :                 bool ok;
     671         445 :                 struct sockaddr_storage ss = {0};
     672         445 :                 struct dns_res_rec *an = &reply->answers[i];
     673             : 
     674         445 :                 if (an->rr_type != DNS_QTYPE_AAAA) {
     675           0 :                         continue;
     676             :                 }
     677         445 :                 if (an->name == NULL) {
     678             :                         /* Can this happen? */
     679           0 :                         continue;
     680             :                 }
     681         445 :                 if (an->rdata.ipv6_record == NULL) {
     682             :                         /* Can this happen? */
     683           0 :                         continue;
     684             :                 }
     685         445 :                 ok = dns_res_rec_get_sockaddr(an,
     686             :                                               &ss);
     687         445 :                 if (!ok) {
     688           0 :                         continue;
     689             :                 }
     690         445 :                 if (is_zero_addr(&ss)) {
     691           0 :                         continue;
     692             :                 }
     693         445 :                 state->addrs[state->num_names].u.ss = ss;
     694         445 :                 state->addrs[state->num_names].sa_socklen =
     695             :                                         sizeof(struct sockaddr_in6);
     696             : 
     697         890 :                 state->hostnames[state->num_names] = talloc_strdup(
     698         445 :                                                         state->hostnames,
     699             :                                                         an->name);
     700         445 :                 if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
     701           0 :                         return;
     702             :                 }
     703         445 :                 state->num_names += 1;
     704             :         }
     705             : 
     706         447 :         tevent_req_done(req);
     707             : }
     708             : 
     709         447 : NTSTATUS ads_dns_lookup_aaaa_recv(struct tevent_req *req,
     710             :                                   TALLOC_CTX *mem_ctx,
     711             :                                   uint8_t *rcode_out,
     712             :                                   size_t *num_names_out,
     713             :                                   char ***hostnames_out,
     714             :                                   struct samba_sockaddr **addrs_out)
     715             : {
     716         447 :         struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
     717             :                 req, struct ads_dns_lookup_aaaa_state);
     718           0 :         NTSTATUS status;
     719             : 
     720         447 :         if (tevent_req_is_nterror(req, &status)) {
     721           0 :                 return status;
     722             :         }
     723         447 :         if (rcode_out != NULL) {
     724             :                 /*
     725             :                  * If we got no names, an upper layer may
     726             :                  * want to print a debug message.
     727             :                  */
     728         445 :                 *rcode_out = state->rcode;
     729             :         }
     730         447 :         if (hostnames_out != NULL) {
     731         447 :                 *hostnames_out = talloc_move(mem_ctx,
     732             :                                              &state->hostnames);
     733             :         }
     734         447 :         if (addrs_out != NULL) {
     735         447 :                 *addrs_out = talloc_move(mem_ctx,
     736             :                                          &state->addrs);
     737             :         }
     738         447 :         *num_names_out = state->num_names;
     739         447 :         tevent_req_received(req);
     740         447 :         return NT_STATUS_OK;
     741             : }
     742             : 
     743             : /*********************************************************************
     744             :  Simple wrapper for a DNS AAAA query
     745             : *********************************************************************/
     746             : 
     747           2 : NTSTATUS ads_dns_lookup_aaaa(TALLOC_CTX *ctx,
     748             :                              const char *name_in,
     749             :                              size_t *num_names_out,
     750             :                              char ***hostnames_out,
     751             :                              struct samba_sockaddr **addrs_out)
     752             : {
     753           2 :         struct tevent_context *ev = NULL;
     754           2 :         struct tevent_req *req = NULL;
     755           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     756             : 
     757           2 :         ev = samba_tevent_context_init(ctx);
     758           2 :         if (ev == NULL) {
     759           0 :                 goto fail;
     760             :         }
     761           2 :         req = ads_dns_lookup_aaaa_send(ev, ev, name_in);
     762           2 :         if (req == NULL) {
     763           0 :                 goto fail;
     764             :         }
     765           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     766           0 :                 goto fail;
     767             :         }
     768             :         /*
     769             :          * Synchronous doesn't need to care about the rcode or
     770             :          * a copy of the name_in.
     771             :          */
     772           2 :         status = ads_dns_lookup_aaaa_recv(req,
     773             :                                           ctx,
     774             :                                           NULL,
     775             :                                           num_names_out,
     776             :                                           hostnames_out,
     777             :                                           addrs_out);
     778           2 : fail:
     779           2 :         TALLOC_FREE(ev);
     780           2 :         return status;
     781             : }
     782             : #endif

Generated by: LCOV version 1.14