LCOV - code coverage report
Current view: top level - source4/heimdal/lib/roken - resolve.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 186 376 49.5 %
Date: 2021-08-25 13:27:56 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : 
      35             : #include <config.h>
      36             : 
      37             : #include "roken.h"
      38             : #ifdef HAVE_ARPA_NAMESER_H
      39             : #include <arpa/nameser.h>
      40             : #endif
      41             : #ifdef HAVE_RESOLV_H
      42             : #include <resolv.h>
      43             : #endif
      44             : #ifdef HAVE_DNS_H
      45             : #include <dns.h>
      46             : #endif
      47             : #include "resolve.h"
      48             : 
      49             : #include <assert.h>
      50             : 
      51             : #ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
      52             : #undef HAVE_RES_NSEARCH
      53             : #endif
      54             : 
      55             : #define DECL(X) {#X, rk_ns_t_##X}
      56             : 
      57             : static struct stot{
      58             :     const char *name;
      59             :     int type;
      60             : }stot[] = {
      61             :     DECL(a),
      62             :     DECL(aaaa),
      63             :     DECL(ns),
      64             :     DECL(cname),
      65             :     DECL(soa),
      66             :     DECL(ptr),
      67             :     DECL(mx),
      68             :     DECL(txt),
      69             :     DECL(afsdb),
      70             :     DECL(sig),
      71             :     DECL(key),
      72             :     DECL(srv),
      73             :     DECL(naptr),
      74             :     DECL(sshfp),
      75             :     DECL(ds),
      76             :     {NULL,      0}
      77             : };
      78             : 
      79             : int _resolve_debug = 0;
      80             : 
      81             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
      82        2059 : rk_dns_string_to_type(const char *name)
      83             : {
      84        2059 :     struct stot *p = stot;
      85       24708 :     for(p = stot; p->name; p++)
      86       24708 :         if(strcasecmp(name, p->name) == 0)
      87        2059 :             return p->type;
      88           0 :     return -1;
      89             : }
      90             : 
      91             : ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
      92           0 : rk_dns_type_to_string(int type)
      93             : {
      94           0 :     struct stot *p = stot;
      95           0 :     for(p = stot; p->name; p++)
      96           0 :         if(type == p->type)
      97           0 :             return p->name;
      98           0 :     return NULL;
      99             : }
     100             : 
     101             : #if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS)
     102             : 
     103             : static void
     104          86 : dns_free_rr(struct rk_resource_record *rr)
     105             : {
     106          86 :     if(rr->domain)
     107          86 :         free(rr->domain);
     108          86 :     if(rr->u.data)
     109          86 :         free(rr->u.data);
     110          86 :     free(rr);
     111          86 : }
     112             : 
     113             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     114          43 : rk_dns_free_data(struct rk_dns_reply *r)
     115             : {
     116             :     struct rk_resource_record *rr;
     117          43 :     if(r->q.domain)
     118          43 :         free(r->q.domain);
     119         172 :     for(rr = r->head; rr;){
     120          86 :         struct rk_resource_record *tmp = rr;
     121          86 :         rr = rr->next;
     122          86 :         dns_free_rr(tmp);
     123             :     }
     124          43 :     free (r);
     125          43 : }
     126             : 
     127             : #ifndef HAVE_WINDNS
     128             : 
     129             : static int
     130          86 : parse_record(const unsigned char *data, const unsigned char *end_data,
     131             :              const unsigned char **pp, struct rk_resource_record **ret_rr)
     132             : {
     133             :     struct rk_resource_record *rr;
     134             :     int type, class, ttl;
     135             :     unsigned size;
     136             :     int status;
     137             :     char host[MAXDNAME];
     138          86 :     const unsigned char *p = *pp;
     139             : 
     140          86 :     *ret_rr = NULL;
     141             : 
     142          86 :     status = dn_expand(data, end_data, p, host, sizeof(host));
     143          86 :     if(status < 0)
     144           0 :         return -1;
     145          86 :     if (p + status + 10 > end_data)
     146           0 :         return -1;
     147             : 
     148          86 :     p += status;
     149          86 :     type = (p[0] << 8) | p[1];
     150          86 :     p += 2;
     151          86 :     class = (p[0] << 8) | p[1];
     152          86 :     p += 2;
     153          86 :     ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
     154          86 :     p += 4;
     155          86 :     size = (p[0] << 8) | p[1];
     156          86 :     p += 2;
     157             : 
     158          86 :     if (p + size > end_data)
     159           0 :         return -1;
     160             : 
     161          86 :     rr = calloc(1, sizeof(*rr));
     162          86 :     if(rr == NULL)
     163           0 :         return -1;
     164          86 :     rr->domain = strdup(host);
     165          86 :     if(rr->domain == NULL) {
     166           0 :         dns_free_rr(rr);
     167           0 :         return -1;
     168             :     }
     169          86 :     rr->type = type;
     170          86 :     rr->class = class;
     171          86 :     rr->ttl = ttl;
     172          86 :     rr->size = size;
     173          86 :     switch(type){
     174           0 :     case rk_ns_t_ns:
     175             :     case rk_ns_t_cname:
     176             :     case rk_ns_t_ptr:
     177           0 :         status = dn_expand(data, end_data, p, host, sizeof(host));
     178           0 :         if(status < 0) {
     179           0 :             dns_free_rr(rr);
     180           0 :             return -1;
     181             :         }
     182           0 :         rr->u.txt = strdup(host);
     183           0 :         if(rr->u.txt == NULL) {
     184           0 :             dns_free_rr(rr);
     185           0 :             return -1;
     186             :         }
     187           0 :         break;
     188           0 :     case rk_ns_t_mx:
     189             :     case rk_ns_t_afsdb:{
     190             :         size_t hostlen;
     191             : 
     192           0 :         status = dn_expand(data, end_data, p + 2, host, sizeof(host));
     193           0 :         if(status < 0){
     194           0 :             dns_free_rr(rr);
     195           0 :             return -1;
     196             :         }
     197           0 :         if ((size_t)status + 2 > size) {
     198           0 :             dns_free_rr(rr);
     199           0 :             return -1;
     200             :         }
     201             : 
     202           0 :         hostlen = strlen(host);
     203           0 :         rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
     204             :                                                 hostlen);
     205           0 :         if(rr->u.mx == NULL) {
     206           0 :             dns_free_rr(rr);
     207           0 :             return -1;
     208             :         }
     209           0 :         rr->u.mx->preference = (p[0] << 8) | p[1];
     210           0 :         strlcpy(rr->u.mx->domain, host, hostlen + 1);
     211           0 :         break;
     212             :     }
     213          43 :     case rk_ns_t_srv:{
     214             :         size_t hostlen;
     215          43 :         status = dn_expand(data, end_data, p + 6, host, sizeof(host));
     216          43 :         if(status < 0){
     217           0 :             dns_free_rr(rr);
     218           0 :             return -1;
     219             :         }
     220          43 :         if ((size_t)status + 6 > size) {
     221           0 :             dns_free_rr(rr);
     222           0 :             return -1;
     223             :         }
     224             : 
     225          43 :         hostlen = strlen(host);
     226          43 :         rr->u.srv =
     227          43 :             (struct srv_record*)malloc(sizeof(struct srv_record) +
     228             :                                        hostlen);
     229          43 :         if(rr->u.srv == NULL) {
     230           0 :             dns_free_rr(rr);
     231           0 :             return -1;
     232             :         }
     233          43 :         rr->u.srv->priority = (p[0] << 8) | p[1];
     234          43 :         rr->u.srv->weight = (p[2] << 8) | p[3];
     235          43 :         rr->u.srv->port = (p[4] << 8) | p[5];
     236          43 :         strlcpy(rr->u.srv->target, host, hostlen + 1);
     237          43 :         break;
     238             :     }
     239           0 :     case rk_ns_t_txt:{
     240           0 :         if(size == 0 || size < (unsigned)(*p + 1)) {
     241           0 :             dns_free_rr(rr);
     242           0 :             return -1;
     243             :         }
     244           0 :         rr->u.txt = (char*)malloc(*p + 1);
     245           0 :         if(rr->u.txt == NULL) {
     246           0 :             dns_free_rr(rr);
     247           0 :             return -1;
     248             :         }
     249           0 :         strncpy(rr->u.txt, (const char*)(p + 1), *p);
     250           0 :         rr->u.txt[*p] = '\0';
     251           0 :         break;
     252             :     }
     253           0 :     case rk_ns_t_key : {
     254             :         size_t key_len;
     255             : 
     256           0 :         if (size < 4) {
     257           0 :             dns_free_rr(rr);
     258           0 :             return -1;
     259             :         }
     260             : 
     261           0 :         key_len = size - 4;
     262           0 :         rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
     263           0 :         if (rr->u.key == NULL) {
     264           0 :             dns_free_rr(rr);
     265           0 :             return -1;
     266             :         }
     267             : 
     268           0 :         rr->u.key->flags     = (p[0] << 8) | p[1];
     269           0 :         rr->u.key->protocol  = p[2];
     270           0 :         rr->u.key->algorithm = p[3];
     271           0 :         rr->u.key->key_len   = key_len;
     272           0 :         memcpy (rr->u.key->key_data, p + 4, key_len);
     273           0 :         break;
     274             :     }
     275           0 :     case rk_ns_t_sig : {
     276             :         size_t sig_len, hostlen;
     277             : 
     278           0 :         if(size <= 18) {
     279           0 :             dns_free_rr(rr);
     280           0 :             return -1;
     281             :         }
     282           0 :         status = dn_expand (data, end_data, p + 18, host, sizeof(host));
     283           0 :         if (status < 0) {
     284           0 :             dns_free_rr(rr);
     285           0 :             return -1;
     286             :         }
     287           0 :         if ((size_t)status + 18 > size) {
     288           0 :             dns_free_rr(rr);
     289           0 :             return -1;
     290             :         }
     291             : 
     292             :         /* the signer name is placed after the sig_data, to make it
     293             :            easy to free this structure; the size calculation below
     294             :            includes the zero-termination if the structure itself.
     295             :            don't you just love C?
     296             :         */
     297           0 :         sig_len = size - 18 - status;
     298           0 :         hostlen = strlen(host);
     299           0 :         rr->u.sig = malloc(sizeof(*rr->u.sig)
     300           0 :                               + hostlen + sig_len);
     301           0 :         if (rr->u.sig == NULL) {
     302           0 :             dns_free_rr(rr);
     303           0 :             return -1;
     304             :         }
     305           0 :         rr->u.sig->type           = (p[0] << 8) | p[1];
     306           0 :         rr->u.sig->algorithm      = p[2];
     307           0 :         rr->u.sig->labels         = p[3];
     308           0 :         rr->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
     309           0 :             | (p[6] << 8) | p[7];
     310           0 :         rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
     311           0 :             | (p[10] << 8) | p[11];
     312           0 :         rr->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
     313           0 :             | (p[14] << 8) | p[15];
     314           0 :         rr->u.sig->key_tag        = (p[16] << 8) | p[17];
     315           0 :         rr->u.sig->sig_len        = sig_len;
     316           0 :         memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
     317           0 :         rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
     318           0 :         strlcpy(rr->u.sig->signer, host, hostlen + 1);
     319           0 :         break;
     320             :     }
     321             : 
     322           0 :     case rk_ns_t_cert : {
     323             :         size_t cert_len;
     324             : 
     325           0 :         if (size < 5) {
     326           0 :             dns_free_rr(rr);
     327           0 :             return -1;
     328             :         }
     329             : 
     330           0 :         cert_len = size - 5;
     331           0 :         rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
     332           0 :         if (rr->u.cert == NULL) {
     333           0 :             dns_free_rr(rr);
     334           0 :             return -1;
     335             :         }
     336             : 
     337           0 :         rr->u.cert->type      = (p[0] << 8) | p[1];
     338           0 :         rr->u.cert->tag       = (p[2] << 8) | p[3];
     339           0 :         rr->u.cert->algorithm = p[4];
     340           0 :         rr->u.cert->cert_len  = cert_len;
     341           0 :         memcpy (rr->u.cert->cert_data, p + 5, cert_len);
     342           0 :         break;
     343             :     }
     344           0 :     case rk_ns_t_sshfp : {
     345             :         size_t sshfp_len;
     346             : 
     347           0 :         if (size < 2) {
     348           0 :             dns_free_rr(rr);
     349           0 :             return -1;
     350             :         }
     351             : 
     352           0 :         sshfp_len = size - 2;
     353             : 
     354           0 :         rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
     355           0 :         if (rr->u.sshfp == NULL) {
     356           0 :             dns_free_rr(rr);
     357           0 :             return -1;
     358             :         }
     359             : 
     360           0 :         rr->u.sshfp->algorithm = p[0];
     361           0 :         rr->u.sshfp->type      = p[1];
     362           0 :         rr->u.sshfp->sshfp_len  = sshfp_len;
     363           0 :         memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
     364           0 :         break;
     365             :     }
     366           0 :     case rk_ns_t_ds: {
     367             :         size_t digest_len;
     368             : 
     369           0 :         if (size < 4) {
     370           0 :             dns_free_rr(rr);
     371           0 :             return -1;
     372             :         }
     373             : 
     374           0 :         digest_len = size - 4;
     375             : 
     376           0 :         rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
     377           0 :         if (rr->u.ds == NULL) {
     378           0 :             dns_free_rr(rr);
     379           0 :             return -1;
     380             :         }
     381             : 
     382           0 :         rr->u.ds->key_tag     = (p[0] << 8) | p[1];
     383           0 :         rr->u.ds->algorithm   = p[2];
     384           0 :         rr->u.ds->digest_type = p[3];
     385           0 :         rr->u.ds->digest_len  = digest_len;
     386           0 :         memcpy (rr->u.ds->digest_data, p + 4, digest_len);
     387           0 :         break;
     388             :     }
     389          43 :     default:
     390          43 :         rr->u.data = (unsigned char*)malloc(size);
     391          43 :         if(size != 0 && rr->u.data == NULL) {
     392           0 :             dns_free_rr(rr);
     393           0 :             return -1;
     394             :         }
     395          43 :         if (size)
     396          43 :             memcpy(rr->u.data, p, size);
     397             :     }
     398          86 :     *pp = p + size;
     399          86 :     *ret_rr = rr;
     400             : 
     401          86 :     return 0;
     402             : }
     403             : 
     404             : #ifndef TEST_RESOLVE
     405             : static
     406             : #endif
     407             : struct rk_dns_reply*
     408          43 : parse_reply(const unsigned char *data, size_t len)
     409             : {
     410             :     const unsigned char *p;
     411             :     int status;
     412             :     size_t i;
     413             :     char host[MAXDNAME];
     414          43 :     const unsigned char *end_data = data + len;
     415             :     struct rk_dns_reply *r;
     416             :     struct rk_resource_record **rr;
     417             : 
     418          43 :     r = calloc(1, sizeof(*r));
     419          43 :     if (r == NULL)
     420           0 :         return NULL;
     421             : 
     422          43 :     p = data;
     423             : 
     424          43 :     r->h.id = (p[0] << 8) | p[1];
     425          43 :     r->h.flags = 0;
     426          43 :     if (p[2] & 0x01)
     427          43 :         r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
     428          43 :     r->h.opcode = (p[2] >> 1) & 0xf;
     429          43 :     if (p[2] & 0x20)
     430           0 :         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
     431          43 :     if (p[2] & 0x40)
     432           0 :         r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
     433          43 :     if (p[2] & 0x80)
     434          43 :         r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
     435          43 :     if (p[3] & 0x01)
     436           0 :         r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
     437          43 :     if (p[3] & 0x04)
     438           0 :         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
     439          43 :     if (p[3] & 0x08)
     440           0 :         r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
     441          43 :     r->h.response_code = (p[3] >> 4) & 0xf;
     442          43 :     r->h.qdcount = (p[4] << 8) | p[5];
     443          43 :     r->h.ancount = (p[6] << 8) | p[7];
     444          43 :     r->h.nscount = (p[8] << 8) | p[9];
     445          43 :     r->h.arcount = (p[10] << 8) | p[11];
     446             : 
     447          43 :     p += 12;
     448             : 
     449          43 :     if(r->h.qdcount != 1) {
     450           0 :         free(r);
     451           0 :         return NULL;
     452             :     }
     453          43 :     status = dn_expand(data, end_data, p, host, sizeof(host));
     454          43 :     if(status < 0){
     455           0 :         rk_dns_free_data(r);
     456           0 :         return NULL;
     457             :     }
     458          43 :     r->q.domain = strdup(host);
     459          43 :     if(r->q.domain == NULL) {
     460           0 :         rk_dns_free_data(r);
     461           0 :         return NULL;
     462             :     }
     463          43 :     if (p + status + 4 > end_data) {
     464           0 :         rk_dns_free_data(r);
     465           0 :         return NULL;
     466             :     }
     467          43 :     p += status;
     468          43 :     r->q.type = (p[0] << 8 | p[1]);
     469          43 :     p += 2;
     470          43 :     r->q.class = (p[0] << 8 | p[1]);
     471          43 :     p += 2;
     472             : 
     473          43 :     rr = &r->head;
     474          86 :     for(i = 0; i < r->h.ancount; i++) {
     475          43 :         if(parse_record(data, end_data, &p, rr) != 0) {
     476           0 :             rk_dns_free_data(r);
     477           0 :             return NULL;
     478             :         }
     479          43 :         rr = &(*rr)->next;
     480             :     }
     481          86 :     for(i = 0; i < r->h.nscount; i++) {
     482          43 :         if(parse_record(data, end_data, &p, rr) != 0) {
     483           0 :             rk_dns_free_data(r);
     484           0 :             return NULL;
     485             :         }
     486          43 :         rr = &(*rr)->next;
     487             :     }
     488          43 :     for(i = 0; i < r->h.arcount; i++) {
     489           0 :         if(parse_record(data, end_data, &p, rr) != 0) {
     490           0 :             rk_dns_free_data(r);
     491           0 :             return NULL;
     492             :         }
     493           0 :         rr = &(*rr)->next;
     494             :     }
     495          43 :     *rr = NULL;
     496          43 :     return r;
     497             : }
     498             : 
     499             : #ifdef HAVE_RES_NSEARCH
     500             : #ifdef HAVE_RES_NDESTROY
     501             : #define rk_res_free(x) res_ndestroy(x)
     502             : #else
     503             : #define rk_res_free(x) res_nclose(x)
     504             : #endif
     505             : #endif
     506             : 
     507             : #if defined(HAVE_DNS_SEARCH)
     508             : #define resolve_search(h,n,c,t,r,l) \
     509             :         ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
     510             : #define resolve_free_handle(h) dns_free(h)
     511             : #elif defined(HAVE_RES_NSEARCH)
     512             : #define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
     513             : #define resolve_free_handle(h) rk_res_free(h);
     514             : #else
     515             : #define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
     516             : #define handle 0
     517             : #define resolve_free_handle(h)
     518             : #endif
     519             : 
     520             : 
     521             : static struct rk_dns_reply *
     522        2059 : dns_lookup_int(const char *domain, int rr_class, int rr_type)
     523             : {
     524             :     struct rk_dns_reply *r;
     525        2059 :     void *reply = NULL;
     526             :     int size, len;
     527             : #if defined(HAVE_DNS_SEARCH)
     528             :     struct sockaddr_storage from;
     529             :     uint32_t fromsize = sizeof(from);
     530             :     dns_handle_t handle;
     531             : 
     532             :     handle = dns_open(NULL);
     533             :     if (handle == NULL)
     534             :         return NULL;
     535             : #elif defined(HAVE_RES_NSEARCH)
     536             :     struct __res_state state;
     537        2059 :     struct __res_state *handle = &state;
     538             : 
     539        2059 :     memset(&state, 0, sizeof(state));
     540        2059 :     if(res_ninit(handle))
     541          72 :         return NULL; /* is this the best we can do? */
     542             : #endif
     543             : 
     544        1987 :     len = 1500;
     545             :     while(1) {
     546       25315 :         if (reply) {
     547       11664 :             free(reply);
     548       11664 :             reply = NULL;
     549             :         }
     550       13651 :         if (_resolve_debug) {
     551             : #if defined(HAVE_DNS_SEARCH)
     552             :             dns_set_debug(handle, 1);
     553             : #elif defined(HAVE_RES_NSEARCH)
     554           0 :             state.options |= RES_DEBUG;
     555             : #endif
     556           0 :             fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
     557             :                     rr_class, rk_dns_type_to_string(rr_type), len);
     558             :         }
     559       13651 :         reply = malloc(len);
     560       13651 :         if (reply == NULL) {
     561           0 :             resolve_free_handle(handle);
     562           0 :             return NULL;
     563             :         }
     564             : 
     565       13651 :         size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
     566             : 
     567       13651 :         if (_resolve_debug) {
     568           0 :             fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
     569             :                     domain, rr_class, rk_dns_type_to_string(rr_type), size);
     570             :         }
     571       13651 :         if (size > len) {
     572             :             /* resolver thinks it know better, go for it */
     573           0 :             len = size;
     574       13651 :         } else if (size > 0) {
     575             :             /* got a good reply */
     576          43 :             break;
     577       13608 :         } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
     578       11664 :             len *= 2;
     579       23328 :             if (len > rk_DNS_MAX_PACKET_SIZE)
     580        1944 :                 len = rk_DNS_MAX_PACKET_SIZE;
     581             :         } else {
     582             :             /* the end, leave */
     583        1944 :             resolve_free_handle(handle);
     584        1944 :             free(reply);
     585        1944 :             return NULL;
     586             :         }
     587             :     }
     588             : 
     589          43 :     len = min(len, size);
     590          43 :     r = parse_reply(reply, len);
     591          43 :     resolve_free_handle(handle);
     592          43 :     free(reply);
     593          43 :     return r;
     594             : }
     595             : 
     596             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     597        2059 : rk_dns_lookup(const char *domain, const char *type_name)
     598             : {
     599             :     int type;
     600             : 
     601        2059 :     type = rk_dns_string_to_type(type_name);
     602        2059 :     if(type == -1) {
     603           0 :         if(_resolve_debug)
     604           0 :             fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
     605             :                     type_name);
     606           0 :         return NULL;
     607             :     }
     608        2059 :     return dns_lookup_int(domain, rk_ns_c_in, type);
     609             : }
     610             : 
     611             : #endif  /* !HAVE_WINDNS */
     612             : 
     613             : static int
     614           0 : compare_srv(const void *a, const void *b)
     615             : {
     616           0 :     const struct rk_resource_record *const* aa = a, *const* bb = b;
     617             : 
     618           0 :     if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
     619           0 :         return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
     620           0 :     return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
     621             : }
     622             : 
     623             : /* try to rearrange the srv-records by the algorithm in RFC2782 */
     624             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     625          43 : rk_dns_srv_order(struct rk_dns_reply *r)
     626             : {
     627             :     struct rk_resource_record **srvs, **ss, **headp;
     628             :     struct rk_resource_record *rr;
     629          43 :     size_t num_srv = 0;
     630             : 
     631             : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
     632             :     int state[256 / sizeof(int)];
     633             :     char *oldstate;
     634             : #endif
     635             : 
     636          43 :     rk_random_init();
     637             : 
     638         129 :     for(rr = r->head; rr; rr = rr->next)
     639          86 :         if(rr->type == rk_ns_t_srv)
     640          43 :             num_srv++;
     641             : 
     642          43 :     if(num_srv == 0)
     643           0 :         return;
     644             : 
     645          43 :     srvs = malloc(num_srv * sizeof(*srvs));
     646          43 :     if(srvs == NULL)
     647           0 :         return; /* XXX not much to do here */
     648             : 
     649             :     /* unlink all srv-records from the linked list and put them in
     650             :        a vector */
     651         172 :     for(ss = srvs, headp = &r->head; *headp; )
     652          86 :         if((*headp)->type == rk_ns_t_srv) {
     653          43 :             *ss = *headp;
     654          43 :             *headp = (*headp)->next;
     655          43 :             (*ss)->next = NULL;
     656          43 :             ss++;
     657             :         } else
     658          43 :             headp = &(*headp)->next;
     659             : 
     660             :     /* sort them by priority and weight */
     661          43 :     qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
     662             : 
     663             : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
     664             :     oldstate = initstate(time(NULL), (char*)state, sizeof(state));
     665             : #endif
     666             : 
     667          43 :     headp = &r->head;
     668             : 
     669         129 :     for(ss = srvs; ss < srvs + num_srv; ) {
     670             :         int sum, rnd, count;
     671             :         struct rk_resource_record **ee, **tt;
     672             :         /* find the last record with the same priority and count the
     673             :            sum of all weights */
     674          86 :         for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
     675          43 :             assert(*tt != NULL);
     676          43 :             if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
     677           0 :                 break;
     678          43 :             sum += (*tt)->u.srv->weight;
     679             :         }
     680          43 :         ee = tt;
     681             :         /* ss is now the first record of this priority and ee is the
     682             :            first of the next */
     683         129 :         while(ss < ee) {
     684          43 :             rnd = rk_random() % (sum + 1);
     685          43 :             for(count = 0, tt = ss; ; tt++) {
     686          43 :                 if(*tt == NULL)
     687           0 :                     continue;
     688          43 :                 count += (*tt)->u.srv->weight;
     689          43 :                 if(count >= rnd)
     690          43 :                     break;
     691             :             }
     692             : 
     693          43 :             assert(tt < ee);
     694             : 
     695             :             /* insert the selected record at the tail (of the head) of
     696             :                the list */
     697          43 :             (*tt)->next = *headp;
     698          43 :             *headp = *tt;
     699          43 :             headp = &(*tt)->next;
     700          43 :             sum -= (*tt)->u.srv->weight;
     701          43 :             *tt = NULL;
     702         129 :             while(ss < ee && *ss == NULL)
     703          43 :                 ss++;
     704             :         }
     705             :     }
     706             : 
     707             : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
     708             :     setstate(oldstate);
     709             : #endif
     710          43 :     free(srvs);
     711          43 :     return;
     712             : }
     713             : 
     714             : #ifdef HAVE_WINDNS
     715             : 
     716             : #include <WinDNS.h>
     717             : 
     718             : static struct rk_resource_record *
     719             : parse_dns_record(PDNS_RECORD pRec)
     720             : {
     721             :     struct rk_resource_record * rr;
     722             : 
     723             :     if (pRec == NULL)
     724             :         return NULL;
     725             : 
     726             :     rr = calloc(1, sizeof(*rr));
     727             : 
     728             :     rr->domain = strdup(pRec->pName);
     729             :     rr->type = pRec->wType;
     730             :     rr->class = 0;
     731             :     rr->ttl = pRec->dwTtl;
     732             :     rr->size = 0;
     733             : 
     734             :     switch (rr->type) {
     735             :     case rk_ns_t_ns:
     736             :     case rk_ns_t_cname:
     737             :     case rk_ns_t_ptr:
     738             :         rr->u.txt = strdup(pRec->Data.NS.pNameHost);
     739             :         if(rr->u.txt == NULL) {
     740             :             dns_free_rr(rr);
     741             :             return NULL;
     742             :         }
     743             :         break;
     744             : 
     745             :     case rk_ns_t_mx:
     746             :     case rk_ns_t_afsdb:{
     747             :         size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH);
     748             : 
     749             :         rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) +
     750             :                                               hostlen);
     751             :         if (rr->u.mx == NULL) {
     752             :             dns_free_rr(rr);
     753             :             return NULL;
     754             :         }
     755             : 
     756             :         strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange);
     757             :         rr->u.mx->preference = pRec->Data.MX.wPreference;
     758             :         break;
     759             :     }
     760             : 
     761             :     case rk_ns_t_srv:{
     762             :         size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH);
     763             : 
     764             :         rr->u.srv =
     765             :             (struct srv_record*)malloc(sizeof(struct srv_record) +
     766             :                                        hostlen);
     767             :         if(rr->u.srv == NULL) {
     768             :             dns_free_rr(rr);
     769             :             return NULL;
     770             :         }
     771             : 
     772             :         rr->u.srv->priority = pRec->Data.SRV.wPriority;
     773             :         rr->u.srv->weight = pRec->Data.SRV.wWeight;
     774             :         rr->u.srv->port = pRec->Data.SRV.wPort;
     775             :         strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget);
     776             : 
     777             :         break;
     778             :     }
     779             : 
     780             :     case rk_ns_t_txt:{
     781             :         size_t len;
     782             : 
     783             :         if (pRec->Data.TXT.dwStringCount == 0) {
     784             :             rr->u.txt = strdup("");
     785             :             break;
     786             :         }
     787             : 
     788             :         len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH);
     789             : 
     790             :         rr->u.txt = (char *)malloc(len + 1);
     791             :         strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]);
     792             : 
     793             :         break;
     794             :     }
     795             : 
     796             :     case rk_ns_t_key : {
     797             :         size_t key_len;
     798             : 
     799             :         if (pRec->wDataLength < 4) {
     800             :             dns_free_rr(rr);
     801             :             return NULL;
     802             :         }
     803             : 
     804             :         key_len = pRec->wDataLength - 4;
     805             :         rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
     806             :         if (rr->u.key == NULL) {
     807             :             dns_free_rr(rr);
     808             :             return NULL;
     809             :         }
     810             : 
     811             :         rr->u.key->flags     = pRec->Data.KEY.wFlags;
     812             :         rr->u.key->protocol  = pRec->Data.KEY.chProtocol;
     813             :         rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm;
     814             :         rr->u.key->key_len   = key_len;
     815             :         memcpy_s (rr->u.key->key_data, key_len,
     816             :                   pRec->Data.KEY.Key, key_len);
     817             :         break;
     818             :     }
     819             : 
     820             :     case rk_ns_t_sig : {
     821             :         size_t sig_len, hostlen;
     822             : 
     823             :         if(pRec->wDataLength <= 18) {
     824             :             dns_free_rr(rr);
     825             :             return NULL;
     826             :         }
     827             : 
     828             :         sig_len = pRec->wDataLength;
     829             : 
     830             :         hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH);
     831             : 
     832             :         rr->u.sig = malloc(sizeof(*rr->u.sig)
     833             :                               + hostlen + sig_len);
     834             :         if (rr->u.sig == NULL) {
     835             :             dns_free_rr(rr);
     836             :             return NULL;
     837             :         }
     838             :         rr->u.sig->type           = pRec->Data.SIG.wTypeCovered;
     839             :         rr->u.sig->algorithm      = pRec->Data.SIG.chAlgorithm;
     840             :         rr->u.sig->labels         = pRec->Data.SIG.chLabelCount;
     841             :         rr->u.sig->orig_ttl       = pRec->Data.SIG.dwOriginalTtl;
     842             :         rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration;
     843             :         rr->u.sig->sig_inception  = pRec->Data.SIG.dwTimeSigned;
     844             :         rr->u.sig->key_tag        = pRec->Data.SIG.wKeyTag;
     845             :         rr->u.sig->sig_len        = sig_len;
     846             :         memcpy_s (rr->u.sig->sig_data, sig_len,
     847             :                   pRec->Data.SIG.Signature, sig_len);
     848             :         rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
     849             :         strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner);
     850             :         break;
     851             :     }
     852             : 
     853             : #ifdef DNS_TYPE_DS
     854             :     case rk_ns_t_ds: {
     855             :         rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1);
     856             :         if (rr->u.ds == NULL) {
     857             :             dns_free_rr(rr);
     858             :             return NULL;
     859             :         }
     860             : 
     861             :         rr->u.ds->key_tag     = pRec->Data.DS.wKeyTag;
     862             :         rr->u.ds->algorithm   = pRec->Data.DS.chAlgorithm;
     863             :         rr->u.ds->digest_type = pRec->Data.DS.chDigestType;
     864             :         rr->u.ds->digest_len  = pRec->Data.DS.wDigestLength;
     865             :         memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength,
     866             :                   pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength);
     867             :         break;
     868             :     }
     869             : #endif
     870             : 
     871             :     default:
     872             :         dns_free_rr(rr);
     873             :         return NULL;
     874             :     }
     875             : 
     876             :     rr->next = parse_dns_record(pRec->pNext);
     877             :     return rr;
     878             : }
     879             : 
     880             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     881             : rk_dns_lookup(const char *domain, const char *type_name)
     882             : {
     883             :     DNS_STATUS status;
     884             :     int type;
     885             :     PDNS_RECORD pRec = NULL;
     886             :     struct rk_dns_reply * r = NULL;
     887             : 
     888             :     __try {
     889             : 
     890             :         type = rk_dns_string_to_type(type_name);
     891             :         if(type == -1) {
     892             :             if(_resolve_debug)
     893             :                 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
     894             :                         type_name);
     895             :             return NULL;
     896             :         }
     897             : 
     898             :         status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL,
     899             :                                &pRec, NULL);
     900             :         if (status != ERROR_SUCCESS)
     901             :             return NULL;
     902             : 
     903             :         r = calloc(1, sizeof(*r));
     904             :         r->q.domain = strdup(domain);
     905             :         r->q.type = type;
     906             :         r->q.class = 0;
     907             : 
     908             :         r->head = parse_dns_record(pRec);
     909             : 
     910             :         if (r->head == NULL) {
     911             :             rk_dns_free_data(r);
     912             :             return NULL;
     913             :         } else {
     914             :             return r;
     915             :         }
     916             : 
     917             :     } __finally {
     918             : 
     919             :         if (pRec)
     920             :             DnsRecordListFree(pRec, DnsFreeRecordList);
     921             : 
     922             :     }
     923             : }
     924             : #endif  /* HAVE_WINDNS */
     925             : 
     926             : #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
     927             : 
     928             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     929             : rk_dns_lookup(const char *domain, const char *type_name)
     930             : {
     931             :     return NULL;
     932             : }
     933             : 
     934             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     935             : rk_dns_free_data(struct rk_dns_reply *r)
     936             : {
     937             : }
     938             : 
     939             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     940             : rk_dns_srv_order(struct rk_dns_reply *r)
     941             : {
     942             : }
     943             : 
     944             : #endif

Generated by: LCOV version 1.13