LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/roken - resolve.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 192 412 46.6 %
Date: 2024-04-21 15:09:00 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         153 : rk_dns_string_to_type(const char *name)
      83             : {
      84         153 :     struct stot *p = stot;
      85        1836 :     for(p = stot; p->name; p++)
      86        1836 :         if(strcasecmp(name, p->name) == 0)
      87         153 :             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          90 : dns_free_rr(struct rk_resource_record *rr)
     105             : {
     106          90 :     if(rr->domain)
     107          90 :         free(rr->domain);
     108          90 :     if(rr->u.data)
     109          90 :         free(rr->u.data);
     110          90 :     free(rr);
     111          90 : }
     112             : 
     113             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     114          81 : rk_dns_free_data(struct rk_dns_reply *r)
     115             : {
     116           0 :     struct rk_resource_record *rr;
     117          81 :     if(r->q.domain)
     118          81 :         free(r->q.domain);
     119         171 :     for(rr = r->head; rr;){
     120          90 :         struct rk_resource_record *tmp = rr;
     121          90 :         rr = rr->next;
     122          90 :         dns_free_rr(tmp);
     123             :     }
     124          81 :     free (r);
     125          81 : }
     126             : 
     127             : #ifndef HAVE_WINDNS
     128             : 
     129             : static int
     130          90 : parse_record(const unsigned char *data, const unsigned char *end_data,
     131             :              const unsigned char **pp, struct rk_resource_record **ret_rr)
     132             : {
     133           0 :     struct rk_resource_record *rr;
     134           0 :     int type, class, ttl;
     135           0 :     unsigned size;
     136           0 :     int status;
     137           0 :     char host[MAXDNAME];
     138          90 :     const unsigned char *p = *pp;
     139             : 
     140          90 :     *ret_rr = NULL;
     141             : 
     142          90 :     status = dn_expand(data, end_data, p, host, sizeof(host));
     143          90 :     if(status < 0)
     144           0 :         return -1;
     145          90 :     if (p + status + 10 > end_data)
     146           0 :         return -1;
     147             : 
     148          90 :     p += status;
     149          90 :     type = (p[0] << 8) | p[1];
     150          90 :     p += 2;
     151          90 :     class = (p[0] << 8) | p[1];
     152          90 :     p += 2;
     153          90 :     ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
     154          90 :     p += 4;
     155          90 :     size = (p[0] << 8) | p[1];
     156          90 :     p += 2;
     157             : 
     158          90 :     if (p + size > end_data)
     159           0 :         return -1;
     160             : 
     161          90 :     rr = calloc(1, sizeof(*rr));
     162          90 :     if(rr == NULL)
     163           0 :         return -1;
     164          90 :     rr->domain = strdup(host);
     165          90 :     if(rr->domain == NULL) {
     166           0 :         dns_free_rr(rr);
     167           0 :         return -1;
     168             :     }
     169          90 :     rr->type = type;
     170          90 :     rr->class = class;
     171          90 :     rr->ttl = ttl;
     172          90 :     rr->size = size;
     173          90 :     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           0 :         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          45 :     case rk_ns_t_srv:{
     214           0 :         size_t hostlen;
     215          45 :         status = dn_expand(data, end_data, p + 6, host, sizeof(host));
     216          45 :         if(status < 0){
     217           0 :             dns_free_rr(rr);
     218           0 :             return -1;
     219             :         }
     220          45 :         if ((size_t)status + 6 > size) {
     221           0 :             dns_free_rr(rr);
     222           0 :             return -1;
     223             :         }
     224             : 
     225          45 :         hostlen = strlen(host);
     226          45 :         rr->u.srv =
     227          45 :             (struct srv_record*)malloc(sizeof(struct srv_record) +
     228             :                                        hostlen);
     229          45 :         if(rr->u.srv == NULL) {
     230           0 :             dns_free_rr(rr);
     231           0 :             return -1;
     232             :         }
     233          45 :         rr->u.srv->priority = (p[0] << 8) | p[1];
     234          45 :         rr->u.srv->weight = (p[2] << 8) | p[3];
     235          45 :         rr->u.srv->port = (p[4] << 8) | p[5];
     236          45 :         strlcpy(rr->u.srv->target, host, hostlen + 1);
     237          45 :         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           0 :         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           0 :         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           0 :         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           0 :         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           0 :         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          45 :     default:
     390          45 :         rr->u.data = (unsigned char*)malloc(size);
     391          45 :         if(size != 0 && rr->u.data == NULL) {
     392           0 :             dns_free_rr(rr);
     393           0 :             return -1;
     394             :         }
     395          45 :         if (size)
     396          45 :             memcpy(rr->u.data, p, size);
     397             :     }
     398          90 :     *pp = p + size;
     399          90 :     *ret_rr = rr;
     400             : 
     401          90 :     return 0;
     402             : }
     403             : 
     404             : #ifndef TEST_RESOLVE
     405             : static
     406             : #endif
     407             : struct rk_dns_reply*
     408          81 : parse_reply(const unsigned char *data, size_t len)
     409             : {
     410           0 :     const unsigned char *p;
     411           0 :     int status;
     412           0 :     size_t i;
     413           0 :     char host[MAXDNAME];
     414          81 :     const unsigned char *end_data = data + len;
     415           0 :     struct rk_dns_reply *r;
     416           0 :     struct rk_resource_record **rr;
     417             : 
     418          81 :     r = calloc(1, sizeof(*r));
     419          81 :     if (r == NULL)
     420           0 :         return NULL;
     421             : 
     422          81 :     p = data;
     423             : 
     424          81 :     r->h.id = (p[0] << 8) | p[1];
     425          81 :     r->h.flags = 0;
     426          81 :     if (p[2] & 0x01)
     427          81 :         r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
     428          81 :     r->h.opcode = (p[2] >> 1) & 0xf;
     429          81 :     if (p[2] & 0x20)
     430           0 :         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
     431          81 :     if (p[2] & 0x40)
     432           0 :         r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
     433          81 :     if (p[2] & 0x80)
     434          81 :         r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
     435          81 :     if (p[3] & 0x01)
     436           0 :         r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
     437          81 :     if (p[3] & 0x04)
     438           0 :         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
     439          81 :     if (p[3] & 0x08)
     440           0 :         r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
     441          81 :     r->h.response_code = (p[3] >> 4) & 0xf;
     442          81 :     r->h.qdcount = (p[4] << 8) | p[5];
     443          81 :     r->h.ancount = (p[6] << 8) | p[7];
     444          81 :     r->h.nscount = (p[8] << 8) | p[9];
     445          81 :     r->h.arcount = (p[10] << 8) | p[11];
     446             : 
     447          81 :     p += 12;
     448             : 
     449          81 :     if(r->h.qdcount != 1) {
     450           0 :         free(r);
     451           0 :         return NULL;
     452             :     }
     453          81 :     status = dn_expand(data, end_data, p, host, sizeof(host));
     454          81 :     if(status < 0){
     455           0 :         rk_dns_free_data(r);
     456           0 :         return NULL;
     457             :     }
     458          81 :     r->q.domain = strdup(host);
     459          81 :     if(r->q.domain == NULL) {
     460           0 :         rk_dns_free_data(r);
     461           0 :         return NULL;
     462             :     }
     463          81 :     if (p + status + 4 > end_data) {
     464           0 :         rk_dns_free_data(r);
     465           0 :         return NULL;
     466             :     }
     467          81 :     p += status;
     468          81 :     r->q.type = (p[0] << 8 | p[1]);
     469          81 :     p += 2;
     470          81 :     r->q.class = (p[0] << 8 | p[1]);
     471          81 :     p += 2;
     472             : 
     473          81 :     rr = &r->head;
     474         126 :     for(i = 0; i < r->h.ancount; i++) {
     475          45 :         if(parse_record(data, end_data, &p, rr) != 0) {
     476           0 :             rk_dns_free_data(r);
     477           0 :             return NULL;
     478             :         }
     479          45 :         rr = &(*rr)->next;
     480             :     }
     481          81 :     for(i = 0; i < r->h.nscount; i++) {
     482           0 :         if(parse_record(data, end_data, &p, rr) != 0) {
     483           0 :             rk_dns_free_data(r);
     484           0 :             return NULL;
     485             :         }
     486           0 :         rr = &(*rr)->next;
     487             :     }
     488         126 :     for(i = 0; i < r->h.arcount; i++) {
     489          45 :         if(parse_record(data, end_data, &p, rr) != 0) {
     490           0 :             rk_dns_free_data(r);
     491           0 :             return NULL;
     492             :         }
     493          45 :         rr = &(*rr)->next;
     494             :     }
     495          81 :     *rr = NULL;
     496          81 :     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         153 : dns_lookup_int(const char *domain, int rr_class, int rr_type)
     523             : {
     524           0 :     struct rk_dns_reply *r;
     525         153 :     void *reply = NULL;
     526           0 :     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           0 :     struct __res_state state;
     537         153 :     struct __res_state *handle = &state;
     538             : 
     539         153 :     memset(&state, 0, sizeof(state));
     540         153 :     if(res_ninit(handle))
     541           0 :         return NULL; /* is this the best we can do? */
     542             : #endif
     543             : 
     544         153 :     len = 1500;
     545           0 :     while(1) {
     546         585 :         if (reply) {
     547         432 :             free(reply);
     548         432 :             reply = NULL;
     549             :         }
     550         585 :         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         585 :         reply = malloc(len);
     560         585 :         if (reply == NULL) {
     561           0 :             resolve_free_handle(handle);
     562           0 :             return NULL;
     563             :         }
     564             : 
     565         585 :         size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
     566             : 
     567         585 :         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         585 :         if (size > len) {
     572             :             /* resolver thinks it know better, go for it */
     573           0 :             len = size;
     574         585 :         } else if (size > 0) {
     575             :             /* got a good reply */
     576          81 :             break;
     577         504 :         } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
     578         432 :             len *= 2;
     579         432 :             if (len > rk_DNS_MAX_PACKET_SIZE)
     580          72 :                 len = rk_DNS_MAX_PACKET_SIZE;
     581             :         } else {
     582             :             /* the end, leave */
     583          72 :             resolve_free_handle(handle);
     584          72 :             free(reply);
     585          72 :             return NULL;
     586             :         }
     587             :     }
     588             : 
     589          81 :     len = min(len, size);
     590          81 :     r = parse_reply(reply, len);
     591          81 :     free(reply);
     592             : 
     593          81 :     resolve_free_handle(handle);
     594             : 
     595          81 :     return r;
     596             : }
     597             : 
     598             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     599         153 : rk_dns_lookup(const char *domain, const char *type_name)
     600             : {
     601           0 :     int type;
     602             : 
     603         153 :     type = rk_dns_string_to_type(type_name);
     604         153 :     if(type == -1) {
     605           0 :         if(_resolve_debug)
     606           0 :             fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
     607             :                     type_name);
     608           0 :         return NULL;
     609             :     }
     610         153 :     return dns_lookup_int(domain, rk_ns_c_in, type);
     611             : }
     612             : 
     613             : #endif  /* !HAVE_WINDNS */
     614             : 
     615             : static int
     616           0 : compare_srv(const void *a, const void *b)
     617             : {
     618           0 :     const struct rk_resource_record *const* aa = a, *const* bb = b;
     619             : 
     620           0 :     if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
     621           0 :         return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
     622           0 :     return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
     623             : }
     624             : 
     625             : /* try to rearrange the srv-records by the algorithm in RFC2782 */
     626             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     627          45 : rk_dns_srv_order(struct rk_dns_reply *r)
     628             : {
     629           0 :     struct rk_resource_record **srvs, **ss, **headp;
     630           0 :     struct rk_resource_record *rr;
     631          45 :     int num_srv = 0;
     632          45 :     unsigned int srv_found = FALSE;
     633             : 
     634          45 :     rk_random_init();
     635             : 
     636         135 :     for(rr = r->head; rr; rr = rr->next)
     637          90 :         if(rr->type == rk_ns_t_srv) {
     638          45 :             num_srv++;
     639          45 :             srv_found = TRUE;
     640             :         }
     641             : 
     642          45 :     if(srv_found == FALSE)
     643           0 :         return;
     644             : 
     645          45 :     srvs = malloc(num_srv * sizeof(*srvs));
     646          45 :     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         135 :     for(ss = srvs, headp = &r->head; *headp; )
     652          90 :         if((*headp)->type == rk_ns_t_srv) {
     653          45 :             *ss = *headp;
     654          45 :             *headp = (*headp)->next;
     655          45 :             (*ss)->next = NULL;
     656          45 :             ss++;
     657             :         } else
     658          45 :             headp = &(*headp)->next;
     659             : 
     660             :     /* sort them by priority and weight */
     661          45 :     qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
     662             : 
     663          45 :     headp = &r->head;
     664             : 
     665          90 :     for (ss = srvs; ss < srvs + num_srv; ) {
     666             :         int sum, zeros, rnd, count; /* zeros -> weight scaling */
     667             :         struct rk_resource_record **ee, **tt;
     668             : 
     669             :         /*
     670             :          * find the last record with the same priority and count the sum of all
     671             :          * weights
     672             :          */
     673          90 :         for (sum = 0, zeros = 0, tt = ss; tt < srvs + num_srv; tt++) {
     674          45 :             assert(*tt != NULL);
     675          45 :             if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
     676           0 :                 break;
     677          45 :             sum += (*tt)->u.srv->weight;
     678          45 :             if ((*tt)->u.srv->weight == 0)
     679           0 :                 zeros++;
     680             :         }
     681             :         /* make sure scale (`zeros') is > 0 then scale out */
     682          45 :         sum += zeros ? 1 : zeros++;
     683          45 :         sum *= zeros;
     684          45 :         ee = tt;
     685             : 
     686             :         /*
     687             :          * ss is now the first record of this priority and ee is the first of
     688             :          * the next or the first past the end of srvs
     689             :          */
     690          90 :         while (ss < ee) {
     691          45 :             rnd = rk_random() % sum + 1;
     692          45 :             for (count = 0, tt = ss; tt < ee; tt++) {
     693          45 :                 if (*tt == NULL)
     694           0 :                     continue;   /* this one's already been picked */
     695          45 :                 if ((*tt)->u.srv->weight == 0)
     696           0 :                     count++;
     697             :                 else
     698          45 :                     count += (*tt)->u.srv->weight * zeros;
     699          45 :                 if (count >= rnd)
     700          45 :                     break;
     701             :             }
     702          45 :             assert(tt < ee);
     703             : 
     704             :             /* push the selected record */
     705          45 :             (*tt)->next = *headp;
     706          45 :             *headp = *tt;
     707          45 :             headp = &(*tt)->next;
     708             :             /*
     709             :              * reduce the sum so the next iteration is sure to reach the random
     710             :              * total after examining all the remaining records.
     711             :              */
     712          45 :             if ((*tt)->u.srv->weight == 0)
     713           0 :                 sum--;
     714             :             else
     715          45 :                 sum -= (*tt)->u.srv->weight * zeros;
     716          45 :             *tt = NULL;
     717          90 :             while (ss < ee && *ss == NULL)
     718          45 :                 ss++;
     719             :         }
     720             :     }
     721             : 
     722          45 :     free(srvs);
     723          45 :     return;
     724             : }
     725             : 
     726             : #ifdef HAVE_WINDNS
     727             : 
     728             : #include <WinDNS.h>
     729             : 
     730             : static struct rk_resource_record *
     731             : parse_dns_record(PDNS_RECORD pRec)
     732             : {
     733             :     struct rk_resource_record * rr;
     734             : 
     735             :     if (pRec == NULL)
     736             :         return NULL;
     737             : 
     738             :     rr = calloc(1, sizeof(*rr));
     739             : 
     740             :     rr->domain = strdup(pRec->pName);
     741             :     rr->type = pRec->wType;
     742             :     rr->class = 0;
     743             :     rr->ttl = pRec->dwTtl;
     744             :     rr->size = 0;
     745             : 
     746             :     switch (rr->type) {
     747             :     case rk_ns_t_ns:
     748             :     case rk_ns_t_cname:
     749             :     case rk_ns_t_ptr:
     750             :         rr->u.txt = strdup(pRec->Data.NS.pNameHost);
     751             :         if(rr->u.txt == NULL) {
     752             :             dns_free_rr(rr);
     753             :             return NULL;
     754             :         }
     755             :         break;
     756             : 
     757             :     case rk_ns_t_mx:
     758             :     case rk_ns_t_afsdb:{
     759             :         size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH);
     760             : 
     761             :         rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) +
     762             :                                               hostlen);
     763             :         if (rr->u.mx == NULL) {
     764             :             dns_free_rr(rr);
     765             :             return NULL;
     766             :         }
     767             : 
     768             :         strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange);
     769             :         rr->u.mx->preference = pRec->Data.MX.wPreference;
     770             :         break;
     771             :     }
     772             : 
     773             :     case rk_ns_t_srv:{
     774             :         size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH);
     775             : 
     776             :         rr->u.srv =
     777             :             (struct srv_record*)malloc(sizeof(struct srv_record) +
     778             :                                        hostlen);
     779             :         if(rr->u.srv == NULL) {
     780             :             dns_free_rr(rr);
     781             :             return NULL;
     782             :         }
     783             : 
     784             :         rr->u.srv->priority = pRec->Data.SRV.wPriority;
     785             :         rr->u.srv->weight = pRec->Data.SRV.wWeight;
     786             :         rr->u.srv->port = pRec->Data.SRV.wPort;
     787             :         strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget);
     788             : 
     789             :         break;
     790             :     }
     791             : 
     792             :     case rk_ns_t_txt:{
     793             :         size_t len;
     794             : 
     795             :         if (pRec->Data.TXT.dwStringCount == 0) {
     796             :             rr->u.txt = strdup("");
     797             :             break;
     798             :         }
     799             : 
     800             :         len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH);
     801             : 
     802             :         rr->u.txt = (char *)malloc(len + 1);
     803             :         strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]);
     804             : 
     805             :         break;
     806             :     }
     807             : 
     808             :     case rk_ns_t_key : {
     809             :         size_t key_len;
     810             : 
     811             :         if (pRec->wDataLength < 4) {
     812             :             dns_free_rr(rr);
     813             :             return NULL;
     814             :         }
     815             : 
     816             :         key_len = pRec->wDataLength - 4;
     817             :         rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
     818             :         if (rr->u.key == NULL) {
     819             :             dns_free_rr(rr);
     820             :             return NULL;
     821             :         }
     822             : 
     823             :         rr->u.key->flags     = pRec->Data.KEY.wFlags;
     824             :         rr->u.key->protocol  = pRec->Data.KEY.chProtocol;
     825             :         rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm;
     826             :         rr->u.key->key_len   = key_len;
     827             :         memcpy_s (rr->u.key->key_data, key_len,
     828             :                   pRec->Data.KEY.Key, key_len);
     829             :         break;
     830             :     }
     831             : 
     832             :     case rk_ns_t_sig : {
     833             :         size_t sig_len, hostlen;
     834             : 
     835             :         if(pRec->wDataLength <= 18) {
     836             :             dns_free_rr(rr);
     837             :             return NULL;
     838             :         }
     839             : 
     840             :         sig_len = pRec->wDataLength;
     841             : 
     842             :         hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH);
     843             : 
     844             :         rr->u.sig = malloc(sizeof(*rr->u.sig)
     845             :                               + hostlen + sig_len);
     846             :         if (rr->u.sig == NULL) {
     847             :             dns_free_rr(rr);
     848             :             return NULL;
     849             :         }
     850             :         rr->u.sig->type           = pRec->Data.SIG.wTypeCovered;
     851             :         rr->u.sig->algorithm      = pRec->Data.SIG.chAlgorithm;
     852             :         rr->u.sig->labels         = pRec->Data.SIG.chLabelCount;
     853             :         rr->u.sig->orig_ttl       = pRec->Data.SIG.dwOriginalTtl;
     854             :         rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration;
     855             :         rr->u.sig->sig_inception  = pRec->Data.SIG.dwTimeSigned;
     856             :         rr->u.sig->key_tag        = pRec->Data.SIG.wKeyTag;
     857             :         rr->u.sig->sig_len        = sig_len;
     858             :         memcpy_s (rr->u.sig->sig_data, sig_len,
     859             :                   pRec->Data.SIG.Signature, sig_len);
     860             :         rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
     861             :         strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner);
     862             :         break;
     863             :     }
     864             : 
     865             : #ifdef DNS_TYPE_DS
     866             :     case rk_ns_t_ds: {
     867             :         rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1);
     868             :         if (rr->u.ds == NULL) {
     869             :             dns_free_rr(rr);
     870             :             return NULL;
     871             :         }
     872             : 
     873             :         rr->u.ds->key_tag     = pRec->Data.DS.wKeyTag;
     874             :         rr->u.ds->algorithm   = pRec->Data.DS.chAlgorithm;
     875             :         rr->u.ds->digest_type = pRec->Data.DS.chDigestType;
     876             :         rr->u.ds->digest_len  = pRec->Data.DS.wDigestLength;
     877             :         memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength,
     878             :                   pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength);
     879             :         break;
     880             :     }
     881             : #endif
     882             : 
     883             :     default:
     884             :         dns_free_rr(rr);
     885             :         return NULL;
     886             :     }
     887             : 
     888             :     rr->next = parse_dns_record(pRec->pNext);
     889             :     return rr;
     890             : }
     891             : 
     892             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     893             : rk_dns_lookup(const char *domain, const char *type_name)
     894             : {
     895             :     DNS_STATUS status;
     896             :     int type;
     897             :     PDNS_RECORD pRec = NULL;
     898             :     struct rk_dns_reply * r = NULL;
     899             : 
     900             :     __try {
     901             : 
     902             :         type = rk_dns_string_to_type(type_name);
     903             :         if(type == -1) {
     904             :             if(_resolve_debug)
     905             :                 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
     906             :                         type_name);
     907             :             return NULL;
     908             :         }
     909             : 
     910             :         status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL,
     911             :                                &pRec, NULL);
     912             :         if (status != ERROR_SUCCESS)
     913             :             return NULL;
     914             : 
     915             :         r = calloc(1, sizeof(*r));
     916             :         r->q.domain = strdup(domain);
     917             :         r->q.type = type;
     918             :         r->q.class = 0;
     919             : 
     920             :         r->head = parse_dns_record(pRec);
     921             : 
     922             :         if (r->head == NULL) {
     923             :             rk_dns_free_data(r);
     924             :             return NULL;
     925             :         } else {
     926             :             return r;
     927             :         }
     928             : 
     929             :     } __finally {
     930             : 
     931             :         if (pRec)
     932             :             DnsRecordListFree(pRec, DnsFreeRecordList);
     933             : 
     934             :     }
     935             : }
     936             : #endif  /* HAVE_WINDNS */
     937             : 
     938             : #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
     939             : 
     940             : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
     941             : rk_dns_lookup(const char *domain, const char *type_name)
     942             : {
     943             :     return NULL;
     944             : }
     945             : 
     946             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     947             : rk_dns_free_data(struct rk_dns_reply *r)
     948             : {
     949             : }
     950             : 
     951             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     952             : rk_dns_srv_order(struct rk_dns_reply *r)
     953             : {
     954             : }
     955             : 
     956             : #endif

Generated by: LCOV version 1.14