root/source4/heimdal/lib/roken/resolve.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dns_string_to_type
  2. dns_type_to_string
  3. dns_free_rr
  4. dns_free_data
  5. parse_record
  6. parse_reply
  7. dns_lookup_int
  8. dns_lookup
  9. compare_srv
  10. dns_srv_order
  11. dns_lookup
  12. dns_free_data
  13. dns_srv_order

   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 #ifdef HAVE_CONFIG_H
  35 #include <config.h>
  36 #endif
  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 #include "resolve.h"
  45 
  46 #include <assert.h>
  47 
  48 RCSID("$Id$");
  49 
  50 #ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
  51 #undef HAVE_RES_NSEARCH
  52 #endif
  53 
  54 #define DECL(X) {#X, rk_ns_t_##X}
  55 
  56 static struct stot{
  57     const char *name;
  58     int type;
  59 }stot[] = {
  60     DECL(a),
  61     DECL(aaaa),
  62     DECL(ns),
  63     DECL(cname),
  64     DECL(soa),
  65     DECL(ptr),
  66     DECL(mx),
  67     DECL(txt),
  68     DECL(afsdb),
  69     DECL(sig),
  70     DECL(key),
  71     DECL(srv),
  72     DECL(naptr),
  73     DECL(sshfp),
  74     DECL(ds),
  75     {NULL,      0}
  76 };
  77 
  78 int _resolve_debug = 0;
  79 
  80 int ROKEN_LIB_FUNCTION
  81 dns_string_to_type(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83     struct stot *p = stot;
  84     for(p = stot; p->name; p++)
  85         if(strcasecmp(name, p->name) == 0)
  86             return p->type;
  87     return -1;
  88 }
  89 
  90 const char * ROKEN_LIB_FUNCTION
  91 dns_type_to_string(int type)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93     struct stot *p = stot;
  94     for(p = stot; p->name; p++)
  95         if(type == p->type)
  96             return p->name;
  97     return NULL;
  98 }
  99 
 100 #if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
 101 
 102 static void
 103 dns_free_rr(struct resource_record *rr)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105     if(rr->domain)
 106         free(rr->domain);
 107     if(rr->u.data)
 108         free(rr->u.data);
 109     free(rr);
 110 }
 111 
 112 void ROKEN_LIB_FUNCTION
 113 dns_free_data(struct dns_reply *r)
     /* [<][>][^][v][top][bottom][index][help] */
 114 {
 115     struct resource_record *rr;
 116     if(r->q.domain)
 117         free(r->q.domain);
 118     for(rr = r->head; rr;){
 119         struct resource_record *tmp = rr;
 120         rr = rr->next;
 121         dns_free_rr(tmp);
 122     }
 123     free (r);
 124 }
 125 
 126 static int
 127 parse_record(const unsigned char *data, const unsigned char *end_data,
     /* [<][>][^][v][top][bottom][index][help] */
 128              const unsigned char **pp, struct resource_record **ret_rr)
 129 {
 130     struct resource_record *rr;
 131     int type, class, ttl;
 132     unsigned size;
 133     int status;
 134     char host[MAXDNAME];
 135     const unsigned char *p = *pp;
 136 
 137     *ret_rr = NULL;
 138 
 139     status = dn_expand(data, end_data, p, host, sizeof(host));
 140     if(status < 0)
 141         return -1;
 142     if (p + status + 10 > end_data)
 143         return -1;
 144 
 145     p += status;
 146     type = (p[0] << 8) | p[1];
 147     p += 2;
 148     class = (p[0] << 8) | p[1];
 149     p += 2;
 150     ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
 151     p += 4;
 152     size = (p[0] << 8) | p[1];
 153     p += 2;
 154 
 155     if (p + size > end_data)
 156         return -1;
 157 
 158     rr = calloc(1, sizeof(*rr));
 159     if(rr == NULL)
 160         return -1;
 161     rr->domain = strdup(host);
 162     if(rr->domain == NULL) {
 163         dns_free_rr(rr);
 164         return -1;
 165     }
 166     rr->type = type;
 167     rr->class = class;
 168     rr->ttl = ttl;
 169     rr->size = size;
 170     switch(type){
 171     case rk_ns_t_ns:
 172     case rk_ns_t_cname:
 173     case rk_ns_t_ptr:
 174         status = dn_expand(data, end_data, p, host, sizeof(host));
 175         if(status < 0) {
 176             dns_free_rr(rr);
 177             return -1;
 178         }
 179         rr->u.txt = strdup(host);
 180         if(rr->u.txt == NULL) {
 181             dns_free_rr(rr);
 182             return -1;
 183         }
 184         break;
 185     case rk_ns_t_mx:
 186     case rk_ns_t_afsdb:{
 187         size_t hostlen;
 188 
 189         status = dn_expand(data, end_data, p + 2, host, sizeof(host));
 190         if(status < 0){
 191             dns_free_rr(rr);
 192             return -1;
 193         }
 194         if (status + 2 > size) {
 195             dns_free_rr(rr);
 196             return -1;
 197         }
 198 
 199         hostlen = strlen(host);
 200         rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
 201                                                 hostlen);
 202         if(rr->u.mx == NULL) {
 203             dns_free_rr(rr);
 204             return -1;
 205         }
 206         rr->u.mx->preference = (p[0] << 8) | p[1];
 207         strlcpy(rr->u.mx->domain, host, hostlen + 1);
 208         break;
 209     }
 210     case rk_ns_t_srv:{
 211         size_t hostlen;
 212         status = dn_expand(data, end_data, p + 6, host, sizeof(host));
 213         if(status < 0){
 214             dns_free_rr(rr);
 215             return -1;
 216         }
 217         if (status + 6 > size) {
 218             dns_free_rr(rr);
 219             return -1;
 220         }
 221 
 222         hostlen = strlen(host);
 223         rr->u.srv =
 224             (struct srv_record*)malloc(sizeof(struct srv_record) +
 225                                        hostlen);
 226         if(rr->u.srv == NULL) {
 227             dns_free_rr(rr);
 228             return -1;
 229         }
 230         rr->u.srv->priority = (p[0] << 8) | p[1];
 231         rr->u.srv->weight = (p[2] << 8) | p[3];
 232         rr->u.srv->port = (p[4] << 8) | p[5];
 233         strlcpy(rr->u.srv->target, host, hostlen + 1);
 234         break;
 235     }
 236     case rk_ns_t_txt:{
 237         if(size == 0 || size < *p + 1) {
 238             dns_free_rr(rr);
 239             return -1;
 240         }
 241         rr->u.txt = (char*)malloc(*p + 1);
 242         if(rr->u.txt == NULL) {
 243             dns_free_rr(rr);
 244             return -1;
 245         }
 246         strncpy(rr->u.txt, (const char*)(p + 1), *p);
 247         rr->u.txt[*p] = '\0';
 248         break;
 249     }
 250     case rk_ns_t_key : {
 251         size_t key_len;
 252 
 253         if (size < 4) {
 254             dns_free_rr(rr);
 255             return -1;
 256         }
 257 
 258         key_len = size - 4;
 259         rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
 260         if (rr->u.key == NULL) {
 261             dns_free_rr(rr);
 262             return -1;
 263         }
 264 
 265         rr->u.key->flags     = (p[0] << 8) | p[1];
 266         rr->u.key->protocol  = p[2];
 267         rr->u.key->algorithm = p[3];
 268         rr->u.key->key_len   = key_len;
 269         memcpy (rr->u.key->key_data, p + 4, key_len);
 270         break;
 271     }
 272     case rk_ns_t_sig : {
 273         size_t sig_len, hostlen;
 274 
 275         if(size <= 18) {
 276             dns_free_rr(rr);
 277             return -1;
 278         }
 279         status = dn_expand (data, end_data, p + 18, host, sizeof(host));
 280         if (status < 0) {
 281             dns_free_rr(rr);
 282             return -1;
 283         }
 284         if (status + 18 > size) {
 285             dns_free_rr(rr);
 286             return -1;
 287         }
 288 
 289         /* the signer name is placed after the sig_data, to make it
 290            easy to free this structure; the size calculation below
 291            includes the zero-termination if the structure itself.
 292            don't you just love C?
 293         */
 294         sig_len = size - 18 - status;
 295         hostlen = strlen(host);
 296         rr->u.sig = malloc(sizeof(*rr->u.sig)
 297                               + hostlen + sig_len);
 298         if (rr->u.sig == NULL) {
 299             dns_free_rr(rr);
 300             return -1;
 301         }
 302         rr->u.sig->type           = (p[0] << 8) | p[1];
 303         rr->u.sig->algorithm      = p[2];
 304         rr->u.sig->labels         = p[3];
 305         rr->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
 306             | (p[6] << 8) | p[7];
 307         rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
 308             | (p[10] << 8) | p[11];
 309         rr->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
 310             | (p[14] << 8) | p[15];
 311         rr->u.sig->key_tag        = (p[16] << 8) | p[17];
 312         rr->u.sig->sig_len        = sig_len;
 313         memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
 314         rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
 315         strlcpy(rr->u.sig->signer, host, hostlen + 1);
 316         break;
 317     }
 318 
 319     case rk_ns_t_cert : {
 320         size_t cert_len;
 321 
 322         if (size < 5) {
 323             dns_free_rr(rr);
 324             return -1;
 325         }
 326 
 327         cert_len = size - 5;
 328         rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
 329         if (rr->u.cert == NULL) {
 330             dns_free_rr(rr);
 331             return -1;
 332         }
 333 
 334         rr->u.cert->type      = (p[0] << 8) | p[1];
 335         rr->u.cert->tag       = (p[2] << 8) | p[3];
 336         rr->u.cert->algorithm = p[4];
 337         rr->u.cert->cert_len  = cert_len;
 338         memcpy (rr->u.cert->cert_data, p + 5, cert_len);
 339         break;
 340     }
 341     case rk_ns_t_sshfp : {
 342         size_t sshfp_len;
 343 
 344         if (size < 2) {
 345             dns_free_rr(rr);
 346             return -1;
 347         }
 348 
 349         sshfp_len = size - 2;
 350 
 351         rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
 352         if (rr->u.sshfp == NULL) {
 353             dns_free_rr(rr);
 354             return -1;
 355         }
 356 
 357         rr->u.sshfp->algorithm = p[0];
 358         rr->u.sshfp->type      = p[1];
 359         rr->u.sshfp->sshfp_len  = sshfp_len;
 360         memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
 361         break;
 362     }
 363     case rk_ns_t_ds: {
 364         size_t digest_len;
 365 
 366         if (size < 4) {
 367             dns_free_rr(rr);
 368             return -1;
 369         }
 370 
 371         digest_len = size - 4;
 372 
 373         rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
 374         if (rr->u.ds == NULL) {
 375             dns_free_rr(rr);
 376             return -1;
 377         }
 378 
 379         rr->u.ds->key_tag     = (p[0] << 8) | p[1];
 380         rr->u.ds->algorithm   = p[2];
 381         rr->u.ds->digest_type = p[3];
 382         rr->u.ds->digest_len  = digest_len;
 383         memcpy (rr->u.ds->digest_data, p + 4, digest_len);
 384         break;
 385     }
 386     default:
 387         rr->u.data = (unsigned char*)malloc(size);
 388         if(size != 0 && rr->u.data == NULL) {
 389             dns_free_rr(rr);
 390             return -1;
 391         }
 392         if (size)
 393             memcpy(rr->u.data, p, size);
 394     }
 395     *pp = p + size;
 396     *ret_rr = rr;
 397 
 398     return 0;
 399 }
 400 
 401 #ifndef TEST_RESOLVE
 402 static
 403 #endif
 404 struct dns_reply*
 405 parse_reply(const unsigned char *data, size_t len)
     /* [<][>][^][v][top][bottom][index][help] */
 406 {
 407     const unsigned char *p;
 408     int status;
 409     int i;
 410     char host[MAXDNAME];
 411     const unsigned char *end_data = data + len;
 412     struct dns_reply *r;
 413     struct resource_record **rr;
 414 
 415     r = calloc(1, sizeof(*r));
 416     if (r == NULL)
 417         return NULL;
 418 
 419     p = data;
 420 
 421     r->h.id = (p[0] << 8) | p[1];
 422     r->h.flags = 0;
 423     if (p[2] & 0x01)
 424         r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
 425     r->h.opcode = (p[2] >> 1) & 0xf;
 426     if (p[2] & 0x20)
 427         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
 428     if (p[2] & 0x40)
 429         r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
 430     if (p[2] & 0x80)
 431         r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
 432     if (p[3] & 0x01)
 433         r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
 434     if (p[3] & 0x04)
 435         r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
 436     if (p[3] & 0x08)
 437         r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
 438     r->h.response_code = (p[3] >> 4) & 0xf;
 439     r->h.qdcount = (p[4] << 8) | p[5];
 440     r->h.ancount = (p[6] << 8) | p[7];
 441     r->h.nscount = (p[8] << 8) | p[9];
 442     r->h.arcount = (p[10] << 8) | p[11];
 443 
 444     p += 12;
 445 
 446     if(r->h.qdcount != 1) {
 447         free(r);
 448         return NULL;
 449     }
 450     status = dn_expand(data, end_data, p, host, sizeof(host));
 451     if(status < 0){
 452         dns_free_data(r);
 453         return NULL;
 454     }
 455     r->q.domain = strdup(host);
 456     if(r->q.domain == NULL) {
 457         dns_free_data(r);
 458         return NULL;
 459     }
 460     if (p + status + 4 > end_data) {
 461         dns_free_data(r);
 462         return NULL;
 463     }
 464     p += status;
 465     r->q.type = (p[0] << 8 | p[1]);
 466     p += 2;
 467     r->q.class = (p[0] << 8 | p[1]);
 468     p += 2;
 469 
 470     rr = &r->head;
 471     for(i = 0; i < r->h.ancount; i++) {
 472         if(parse_record(data, end_data, &p, rr) != 0) {
 473             dns_free_data(r);
 474             return NULL;
 475         }
 476         rr = &(*rr)->next;
 477     }
 478     for(i = 0; i < r->h.nscount; i++) {
 479         if(parse_record(data, end_data, &p, rr) != 0) {
 480             dns_free_data(r);
 481             return NULL;
 482         }
 483         rr = &(*rr)->next;
 484     }
 485     for(i = 0; i < r->h.arcount; i++) {
 486         if(parse_record(data, end_data, &p, rr) != 0) {
 487             dns_free_data(r);
 488             return NULL;
 489         }
 490         rr = &(*rr)->next;
 491     }
 492     *rr = NULL;
 493     return r;
 494 }
 495 
 496 #ifdef HAVE_RES_NSEARCH
 497 #ifdef HAVE_RES_NDESTROY
 498 #define rk_res_free(x) res_ndestroy(x)
 499 #else
 500 #define rk_res_free(x) res_nclose(x)
 501 #endif
 502 #endif
 503 
 504 static struct dns_reply *
 505 dns_lookup_int(const char *domain, int rr_class, int rr_type)
     /* [<][>][^][v][top][bottom][index][help] */
 506 {
 507     struct dns_reply *r;
 508     unsigned char *reply = NULL;
 509     int size;
 510     int len;
 511 #ifdef HAVE_RES_NSEARCH
 512     struct __res_state state;
 513     memset(&state, 0, sizeof(state));
 514     if(res_ninit(&state))
 515         return NULL; /* is this the best we can do? */
 516 #elif defined(HAVE__RES)
 517     u_long old_options = 0;
 518 #endif
 519 
 520     size = 0;
 521     len = 1000;
 522     do {
 523         if (reply) {
 524             free(reply);
 525             reply = NULL;
 526         }
 527         if (size <= len)
 528             size = len;
 529         if (_resolve_debug) {
 530 #ifdef HAVE_RES_NSEARCH
 531             state.options |= RES_DEBUG;
 532 #elif defined(HAVE__RES)
 533             old_options = _res.options;
 534             _res.options |= RES_DEBUG;
 535 #endif
 536             fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
 537                     rr_class, dns_type_to_string(rr_type), size);
 538         }
 539         reply = malloc(size);
 540         if (reply == NULL) {
 541 #ifdef HAVE_RES_NSEARCH
 542             rk_res_free(&state);
 543 #endif
 544             return NULL;
 545         }
 546 #ifdef HAVE_RES_NSEARCH
 547         len = res_nsearch(&state, domain, rr_class, rr_type, reply, size);
 548 #else
 549         len = res_search(domain, rr_class, rr_type, reply, size);
 550 #endif
 551         if (_resolve_debug) {
 552 #if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
 553             _res.options = old_options;
 554 #endif
 555             fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
 556                     domain, rr_class, dns_type_to_string(rr_type), len);
 557         }
 558         if (len < 0) {
 559 #ifdef HAVE_RES_NSEARCH
 560             rk_res_free(&state);
 561 #endif
 562             free(reply);
 563             return NULL;
 564         }
 565     } while (size < len && len < rk_DNS_MAX_PACKET_SIZE);
 566 #ifdef HAVE_RES_NSEARCH
 567     rk_res_free(&state);
 568 #endif
 569 
 570     len = min(len, size);
 571     r = parse_reply(reply, len);
 572     free(reply);
 573     return r;
 574 }
 575 
 576 struct dns_reply * ROKEN_LIB_FUNCTION
 577 dns_lookup(const char *domain, const char *type_name)
     /* [<][>][^][v][top][bottom][index][help] */
 578 {
 579     int type;
 580 
 581     type = dns_string_to_type(type_name);
 582     if(type == -1) {
 583         if(_resolve_debug)
 584             fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
 585                     type_name);
 586         return NULL;
 587     }
 588     return dns_lookup_int(domain, C_IN, type);
 589 }
 590 
 591 static int
 592 compare_srv(const void *a, const void *b)
     /* [<][>][^][v][top][bottom][index][help] */
 593 {
 594     const struct resource_record *const* aa = a, *const* bb = b;
 595 
 596     if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
 597         return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
 598     return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
 599 }
 600 
 601 #ifndef HAVE_RANDOM
 602 #define random() rand()
 603 #endif
 604 
 605 /* try to rearrange the srv-records by the algorithm in RFC2782 */
 606 void ROKEN_LIB_FUNCTION
 607 dns_srv_order(struct dns_reply *r)
     /* [<][>][^][v][top][bottom][index][help] */
 608 {
 609     struct resource_record **srvs, **ss, **headp;
 610     struct resource_record *rr;
 611     int num_srv = 0;
 612 
 613 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
 614     int state[256 / sizeof(int)];
 615     char *oldstate;
 616 #endif
 617 
 618     for(rr = r->head; rr; rr = rr->next)
 619         if(rr->type == rk_ns_t_srv)
 620             num_srv++;
 621 
 622     if(num_srv == 0)
 623         return;
 624 
 625     srvs = malloc(num_srv * sizeof(*srvs));
 626     if(srvs == NULL)
 627         return; /* XXX not much to do here */
 628 
 629     /* unlink all srv-records from the linked list and put them in
 630        a vector */
 631     for(ss = srvs, headp = &r->head; *headp; )
 632         if((*headp)->type == rk_ns_t_srv) {
 633             *ss = *headp;
 634             *headp = (*headp)->next;
 635             (*ss)->next = NULL;
 636             ss++;
 637         } else
 638             headp = &(*headp)->next;
 639 
 640     /* sort them by priority and weight */
 641     qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
 642 
 643 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
 644     oldstate = initstate(time(NULL), (char*)state, sizeof(state));
 645 #endif
 646 
 647     headp = &r->head;
 648 
 649     for(ss = srvs; ss < srvs + num_srv; ) {
 650         int sum, rnd, count;
 651         struct resource_record **ee, **tt;
 652         /* find the last record with the same priority and count the
 653            sum of all weights */
 654         for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
 655             assert(*tt != NULL);
 656             if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
 657                 break;
 658             sum += (*tt)->u.srv->weight;
 659         }
 660         ee = tt;
 661         /* ss is now the first record of this priority and ee is the
 662            first of the next */
 663         while(ss < ee) {
 664             rnd = random() % (sum + 1);
 665             for(count = 0, tt = ss; ; tt++) {
 666                 if(*tt == NULL)
 667                     continue;
 668                 count += (*tt)->u.srv->weight;
 669                 if(count >= rnd)
 670                     break;
 671             }
 672 
 673             assert(tt < ee);
 674 
 675             /* insert the selected record at the tail (of the head) of
 676                the list */
 677             (*tt)->next = *headp;
 678             *headp = *tt;
 679             headp = &(*tt)->next;
 680             sum -= (*tt)->u.srv->weight;
 681             *tt = NULL;
 682             while(ss < ee && *ss == NULL)
 683                 ss++;
 684         }
 685     }
 686 
 687 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
 688     setstate(oldstate);
 689 #endif
 690     free(srvs);
 691     return;
 692 }
 693 
 694 #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
 695 
 696 struct dns_reply * ROKEN_LIB_FUNCTION
 697 dns_lookup(const char *domain, const char *type_name)
     /* [<][>][^][v][top][bottom][index][help] */
 698 {
 699     return NULL;
 700 }
 701 
 702 void ROKEN_LIB_FUNCTION
 703 dns_free_data(struct dns_reply *r)
     /* [<][>][^][v][top][bottom][index][help] */
 704 {
 705 }
 706 
 707 void ROKEN_LIB_FUNCTION
 708 dns_srv_order(struct dns_reply *r)
     /* [<][>][^][v][top][bottom][index][help] */
 709 {
 710 }
 711 
 712 #endif

/* [<][>][^][v][top][bottom][index][help] */