resolve.c revision 120945
155682Smarkm/* 2120945Snectar * Copyright (c) 1995 - 2003 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#ifdef HAVE_CONFIG_H 3555682Smarkm#include <config.h> 3655682Smarkm#endif 3755682Smarkm#include "roken.h" 3855682Smarkm#ifdef HAVE_ARPA_NAMESER_H 3955682Smarkm#include <arpa/nameser.h> 4055682Smarkm#endif 4155682Smarkm#ifdef HAVE_RESOLV_H 4255682Smarkm#include <resolv.h> 4355682Smarkm#endif 4455682Smarkm#include "resolve.h" 4555682Smarkm 4690926Snectar#include <assert.h> 4755682Smarkm 48120945SnectarRCSID("$Id: resolve.c,v 1.38.2.1 2003/04/22 15:02:47 lha Exp $"); 4990926Snectar 50103423Snectar#undef HAVE_RES_NSEARCH 51103423Snectar#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND) 5255682Smarkm 5355682Smarkm#define DECL(X) {#X, T_##X} 5455682Smarkm 5555682Smarkmstatic struct stot{ 5655682Smarkm const char *name; 5755682Smarkm int type; 5855682Smarkm}stot[] = { 5955682Smarkm DECL(A), 6055682Smarkm DECL(NS), 6155682Smarkm DECL(CNAME), 6272445Sassar DECL(SOA), 6355682Smarkm DECL(PTR), 6455682Smarkm DECL(MX), 6555682Smarkm DECL(TXT), 6655682Smarkm DECL(AFSDB), 6772445Sassar DECL(SIG), 6872445Sassar DECL(KEY), 6955682Smarkm DECL(SRV), 7072445Sassar DECL(NAPTR), 7155682Smarkm {NULL, 0} 7255682Smarkm}; 7355682Smarkm 7472445Sassarint _resolve_debug = 0; 7555682Smarkm 7672445Sassarint 7772445Sassardns_string_to_type(const char *name) 7855682Smarkm{ 7955682Smarkm struct stot *p = stot; 8055682Smarkm for(p = stot; p->name; p++) 8155682Smarkm if(strcasecmp(name, p->name) == 0) 8255682Smarkm return p->type; 8355682Smarkm return -1; 8455682Smarkm} 8555682Smarkm 8672445Sassarconst char * 8772445Sassardns_type_to_string(int type) 8855682Smarkm{ 8955682Smarkm struct stot *p = stot; 9055682Smarkm for(p = stot; p->name; p++) 9155682Smarkm if(type == p->type) 9255682Smarkm return p->name; 9355682Smarkm return NULL; 9455682Smarkm} 9555682Smarkm 9655682Smarkmvoid 9755682Smarkmdns_free_data(struct dns_reply *r) 9855682Smarkm{ 9955682Smarkm struct resource_record *rr; 10055682Smarkm if(r->q.domain) 10155682Smarkm free(r->q.domain); 10255682Smarkm for(rr = r->head; rr;){ 10355682Smarkm struct resource_record *tmp = rr; 10455682Smarkm if(rr->domain) 10555682Smarkm free(rr->domain); 10655682Smarkm if(rr->u.data) 10755682Smarkm free(rr->u.data); 10855682Smarkm rr = rr->next; 10955682Smarkm free(tmp); 11055682Smarkm } 11155682Smarkm free (r); 11255682Smarkm} 11355682Smarkm 114107207Snectarstatic int 115107207Snectarparse_record(const unsigned char *data, const unsigned char *end_data, 116107207Snectar const unsigned char **pp, struct resource_record **rr) 117107207Snectar{ 118107207Snectar int type, class, ttl, size; 119107207Snectar int status; 120107207Snectar char host[MAXDNAME]; 121107207Snectar const unsigned char *p = *pp; 122107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 123107207Snectar if(status < 0) 124107207Snectar return -1; 125107207Snectar if (p + status + 10 > end_data) 126107207Snectar return -1; 127107207Snectar p += status; 128107207Snectar type = (p[0] << 8) | p[1]; 129107207Snectar p += 2; 130107207Snectar class = (p[0] << 8) | p[1]; 131107207Snectar p += 2; 132107207Snectar ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 133107207Snectar p += 4; 134107207Snectar size = (p[0] << 8) | p[1]; 135107207Snectar p += 2; 136107207Snectar 137107207Snectar if (p + size > end_data) 138107207Snectar return -1; 139107207Snectar 140107207Snectar *rr = calloc(1, sizeof(**rr)); 141107207Snectar if(*rr == NULL) 142107207Snectar return -1; 143107207Snectar (*rr)->domain = strdup(host); 144107207Snectar if((*rr)->domain == NULL) { 145107207Snectar free(*rr); 146107207Snectar return -1; 147107207Snectar } 148107207Snectar (*rr)->type = type; 149107207Snectar (*rr)->class = class; 150107207Snectar (*rr)->ttl = ttl; 151107207Snectar (*rr)->size = size; 152107207Snectar switch(type){ 153107207Snectar case T_NS: 154107207Snectar case T_CNAME: 155107207Snectar case T_PTR: 156107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 157107207Snectar if(status < 0) { 158107207Snectar free(*rr); 159107207Snectar return -1; 160107207Snectar } 161107207Snectar (*rr)->u.txt = strdup(host); 162107207Snectar if((*rr)->u.txt == NULL) { 163107207Snectar free(*rr); 164107207Snectar return -1; 165107207Snectar } 166107207Snectar break; 167107207Snectar case T_MX: 168107207Snectar case T_AFSDB:{ 169120945Snectar size_t hostlen; 170120945Snectar 171107207Snectar status = dn_expand(data, end_data, p + 2, host, sizeof(host)); 172107207Snectar if(status < 0){ 173107207Snectar free(*rr); 174107207Snectar return -1; 175107207Snectar } 176107207Snectar if (status + 2 > size) { 177107207Snectar free(*rr); 178107207Snectar return -1; 179107207Snectar } 180107207Snectar 181120945Snectar hostlen = strlen(host); 182107207Snectar (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 183120945Snectar hostlen); 184107207Snectar if((*rr)->u.mx == NULL) { 185107207Snectar free(*rr); 186107207Snectar return -1; 187107207Snectar } 188107207Snectar (*rr)->u.mx->preference = (p[0] << 8) | p[1]; 189120945Snectar strlcpy((*rr)->u.mx->domain, host, hostlen + 1); 190107207Snectar break; 191107207Snectar } 192107207Snectar case T_SRV:{ 193120945Snectar size_t hostlen; 194107207Snectar status = dn_expand(data, end_data, p + 6, host, sizeof(host)); 195107207Snectar if(status < 0){ 196107207Snectar free(*rr); 197107207Snectar return -1; 198107207Snectar } 199107207Snectar if (status + 6 > size) { 200107207Snectar free(*rr); 201107207Snectar return -1; 202107207Snectar } 203107207Snectar 204120945Snectar hostlen = strlen(host); 205107207Snectar (*rr)->u.srv = 206107207Snectar (struct srv_record*)malloc(sizeof(struct srv_record) + 207120945Snectar hostlen); 208107207Snectar if((*rr)->u.srv == NULL) { 209107207Snectar free(*rr); 210107207Snectar return -1; 211107207Snectar } 212107207Snectar (*rr)->u.srv->priority = (p[0] << 8) | p[1]; 213107207Snectar (*rr)->u.srv->weight = (p[2] << 8) | p[3]; 214107207Snectar (*rr)->u.srv->port = (p[4] << 8) | p[5]; 215120945Snectar strlcpy((*rr)->u.srv->target, host, hostlen + 1); 216107207Snectar break; 217107207Snectar } 218107207Snectar case T_TXT:{ 219107207Snectar if(size == 0 || size < *p + 1) { 220107207Snectar free(*rr); 221107207Snectar return -1; 222107207Snectar } 223107207Snectar (*rr)->u.txt = (char*)malloc(*p + 1); 224107207Snectar if((*rr)->u.txt == NULL) { 225107207Snectar free(*rr); 226107207Snectar return -1; 227107207Snectar } 228107207Snectar strncpy((*rr)->u.txt, (char*)p + 1, *p); 229107207Snectar (*rr)->u.txt[*p] = '\0'; 230107207Snectar break; 231107207Snectar } 232107207Snectar case T_KEY : { 233107207Snectar size_t key_len; 234107207Snectar 235107207Snectar if (size < 4) { 236107207Snectar free(*rr); 237107207Snectar return -1; 238107207Snectar } 239107207Snectar 240107207Snectar key_len = size - 4; 241107207Snectar (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1); 242107207Snectar if ((*rr)->u.key == NULL) { 243107207Snectar free(*rr); 244107207Snectar return -1; 245107207Snectar } 246107207Snectar 247107207Snectar (*rr)->u.key->flags = (p[0] << 8) | p[1]; 248107207Snectar (*rr)->u.key->protocol = p[2]; 249107207Snectar (*rr)->u.key->algorithm = p[3]; 250107207Snectar (*rr)->u.key->key_len = key_len; 251107207Snectar memcpy ((*rr)->u.key->key_data, p + 4, key_len); 252107207Snectar break; 253107207Snectar } 254107207Snectar case T_SIG : { 255120945Snectar size_t sig_len, hostlen; 256107207Snectar 257107207Snectar if(size <= 18) { 258107207Snectar free(*rr); 259107207Snectar return -1; 260107207Snectar } 261107207Snectar status = dn_expand (data, end_data, p + 18, host, sizeof(host)); 262107207Snectar if (status < 0) { 263107207Snectar free(*rr); 264107207Snectar return -1; 265107207Snectar } 266107207Snectar if (status + 18 > size) { 267107207Snectar free(*rr); 268107207Snectar return -1; 269107207Snectar } 270107207Snectar 271107207Snectar /* the signer name is placed after the sig_data, to make it 272107207Snectar easy to free this struture; the size calculation below 273107207Snectar includes the zero-termination if the structure itself. 274107207Snectar don't you just love C? 275107207Snectar */ 276107207Snectar sig_len = size - 18 - status; 277120945Snectar hostlen = strlen(host); 278107207Snectar (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig) 279120945Snectar + hostlen + sig_len); 280107207Snectar if ((*rr)->u.sig == NULL) { 281107207Snectar free(*rr); 282107207Snectar return -1; 283107207Snectar } 284107207Snectar (*rr)->u.sig->type = (p[0] << 8) | p[1]; 285107207Snectar (*rr)->u.sig->algorithm = p[2]; 286107207Snectar (*rr)->u.sig->labels = p[3]; 287107207Snectar (*rr)->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16) 288107207Snectar | (p[6] << 8) | p[7]; 289107207Snectar (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16) 290107207Snectar | (p[10] << 8) | p[11]; 291107207Snectar (*rr)->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16) 292107207Snectar | (p[14] << 8) | p[15]; 293107207Snectar (*rr)->u.sig->key_tag = (p[16] << 8) | p[17]; 294107207Snectar (*rr)->u.sig->sig_len = sig_len; 295107207Snectar memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len); 296107207Snectar (*rr)->u.sig->signer = &(*rr)->u.sig->sig_data[sig_len]; 297120945Snectar strlcpy((*rr)->u.sig->signer, host, hostlen + 1); 298107207Snectar break; 299107207Snectar } 300107207Snectar 301107207Snectar case T_CERT : { 302107207Snectar size_t cert_len; 303107207Snectar 304107207Snectar if (size < 5) { 305107207Snectar free(*rr); 306107207Snectar return -1; 307107207Snectar } 308107207Snectar 309107207Snectar cert_len = size - 5; 310107207Snectar (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1); 311107207Snectar if ((*rr)->u.cert == NULL) { 312107207Snectar free(*rr); 313107207Snectar return -1; 314107207Snectar } 315107207Snectar 316107207Snectar (*rr)->u.cert->type = (p[0] << 8) | p[1]; 317107207Snectar (*rr)->u.cert->tag = (p[2] << 8) | p[3]; 318107207Snectar (*rr)->u.cert->algorithm = p[4]; 319107207Snectar (*rr)->u.cert->cert_len = cert_len; 320107207Snectar memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len); 321107207Snectar break; 322107207Snectar } 323107207Snectar default: 324107207Snectar (*rr)->u.data = (unsigned char*)malloc(size); 325107207Snectar if(size != 0 && (*rr)->u.data == NULL) { 326107207Snectar free(*rr); 327107207Snectar return -1; 328107207Snectar } 329107207Snectar memcpy((*rr)->u.data, p, size); 330107207Snectar } 331107207Snectar *pp = p + size; 332107207Snectar return 0; 333107207Snectar} 334107207Snectar 335103423Snectar#ifndef TEST_RESOLVE 336103423Snectarstatic 337103423Snectar#endif 338103423Snectarstruct dns_reply* 339103423Snectarparse_reply(const unsigned char *data, size_t len) 34055682Smarkm{ 341102644Snectar const unsigned char *p; 34255682Smarkm int status; 343107207Snectar int i; 344107207Snectar char host[MAXDNAME]; 345102644Snectar const unsigned char *end_data = data + len; 34655682Smarkm struct dns_reply *r; 34755682Smarkm struct resource_record **rr; 34855682Smarkm 34955682Smarkm r = calloc(1, sizeof(*r)); 35055682Smarkm if (r == NULL) 35155682Smarkm return NULL; 35255682Smarkm 35355682Smarkm p = data; 35455682Smarkm#if 0 35555682Smarkm /* doesn't work on Crays */ 35655682Smarkm memcpy(&r->h, p, sizeof(HEADER)); 35755682Smarkm p += sizeof(HEADER); 35855682Smarkm#else 35955682Smarkm memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */ 36055682Smarkm p += 12; 36155682Smarkm#endif 362107207Snectar if(ntohs(r->h.qdcount) != 1) { 363107207Snectar free(r); 364107207Snectar return NULL; 365107207Snectar } 366102644Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 36755682Smarkm if(status < 0){ 36855682Smarkm dns_free_data(r); 36955682Smarkm return NULL; 37055682Smarkm } 37155682Smarkm r->q.domain = strdup(host); 37255682Smarkm if(r->q.domain == NULL) { 37355682Smarkm dns_free_data(r); 37455682Smarkm return NULL; 37555682Smarkm } 376102644Snectar if (p + status + 4 > end_data) { 377102644Snectar dns_free_data(r); 378102644Snectar return NULL; 379102644Snectar } 38055682Smarkm p += status; 38155682Smarkm r->q.type = (p[0] << 8 | p[1]); 38255682Smarkm p += 2; 38355682Smarkm r->q.class = (p[0] << 8 | p[1]); 38455682Smarkm p += 2; 385107207Snectar 38655682Smarkm rr = &r->head; 387107207Snectar for(i = 0; i < ntohs(r->h.ancount); i++) { 388107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 38955682Smarkm dns_free_data(r); 39055682Smarkm return NULL; 39155682Smarkm } 392107207Snectar rr = &(*rr)->next; 393107207Snectar } 394107207Snectar for(i = 0; i < ntohs(r->h.nscount); i++) { 395107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 396102644Snectar dns_free_data(r); 397102644Snectar return NULL; 398102644Snectar } 399107207Snectar rr = &(*rr)->next; 400107207Snectar } 401107207Snectar for(i = 0; i < ntohs(r->h.arcount); i++) { 402107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 403102644Snectar dns_free_data(r); 404102644Snectar return NULL; 405102644Snectar } 40655682Smarkm rr = &(*rr)->next; 40755682Smarkm } 40855682Smarkm *rr = NULL; 40955682Smarkm return r; 41055682Smarkm} 41155682Smarkm 41255682Smarkmstatic struct dns_reply * 41355682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type) 41455682Smarkm{ 41555682Smarkm unsigned char reply[1024]; 41655682Smarkm int len; 417103423Snectar#ifdef HAVE_RES_NSEARCH 418103423Snectar struct __res_state stat; 419103423Snectar memset(&stat, 0, sizeof(stat)); 420103423Snectar if(res_ninit(&stat)) 421103423Snectar return NULL; /* is this the best we can do? */ 422103423Snectar#elif defined(HAVE__RES) 42355682Smarkm u_long old_options = 0; 424102644Snectar#endif 42555682Smarkm 42655682Smarkm if (_resolve_debug) { 427103423Snectar#ifdef HAVE_RES_NSEARCH 428103423Snectar stat.options |= RES_DEBUG; 429103423Snectar#elif defined(HAVE__RES) 43055682Smarkm old_options = _res.options; 43155682Smarkm _res.options |= RES_DEBUG; 432102644Snectar#endif 43355682Smarkm fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain, 43472445Sassar rr_class, dns_type_to_string(rr_type)); 43555682Smarkm } 436103423Snectar#ifdef HAVE_RES_NSEARCH 437103423Snectar len = res_nsearch(&stat, domain, rr_class, rr_type, reply, sizeof(reply)); 438103423Snectar#else 43955682Smarkm len = res_search(domain, rr_class, rr_type, reply, sizeof(reply)); 440103423Snectar#endif 44155682Smarkm if (_resolve_debug) { 442103423Snectar#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH) 44355682Smarkm _res.options = old_options; 444102644Snectar#endif 44555682Smarkm fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 44672445Sassar domain, rr_class, dns_type_to_string(rr_type), len); 44755682Smarkm } 448103423Snectar#ifdef HAVE_RES_NSEARCH 449103423Snectar res_nclose(&stat); 450103423Snectar#endif 451102644Snectar if(len < 0) { 452102644Snectar return NULL; 453102644Snectar } else { 454102644Snectar len = min(len, sizeof(reply)); 455102644Snectar return parse_reply(reply, len); 456102644Snectar } 45755682Smarkm} 45855682Smarkm 45955682Smarkmstruct dns_reply * 46055682Smarkmdns_lookup(const char *domain, const char *type_name) 46155682Smarkm{ 46255682Smarkm int type; 46355682Smarkm 46472445Sassar type = dns_string_to_type(type_name); 46555682Smarkm if(type == -1) { 46655682Smarkm if(_resolve_debug) 46755682Smarkm fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 46855682Smarkm type_name); 46955682Smarkm return NULL; 47055682Smarkm } 47155682Smarkm return dns_lookup_int(domain, C_IN, type); 47255682Smarkm} 47355682Smarkm 47490926Snectarstatic int 47590926Snectarcompare_srv(const void *a, const void *b) 47690926Snectar{ 47790926Snectar const struct resource_record *const* aa = a, *const* bb = b; 47890926Snectar 47990926Snectar if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 48090926Snectar return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 48190926Snectar return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 48290926Snectar} 48390926Snectar 48490926Snectar#ifndef HAVE_RANDOM 48590926Snectar#define random() rand() 48690926Snectar#endif 48790926Snectar 48890926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */ 48990926Snectarvoid 49090926Snectardns_srv_order(struct dns_reply *r) 49190926Snectar{ 49290926Snectar struct resource_record **srvs, **ss, **headp; 49390926Snectar struct resource_record *rr; 49490926Snectar int num_srv = 0; 49590926Snectar 49690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 497102644Snectar int state[256 / sizeof(int)]; 498102644Snectar char *oldstate; 49990926Snectar#endif 50090926Snectar 50190926Snectar for(rr = r->head; rr; rr = rr->next) 50290926Snectar if(rr->type == T_SRV) 50390926Snectar num_srv++; 50490926Snectar 50590926Snectar if(num_srv == 0) 50690926Snectar return; 50790926Snectar 50890926Snectar srvs = malloc(num_srv * sizeof(*srvs)); 50990926Snectar if(srvs == NULL) 51090926Snectar return; /* XXX not much to do here */ 51190926Snectar 51290926Snectar /* unlink all srv-records from the linked list and put them in 51390926Snectar a vector */ 51490926Snectar for(ss = srvs, headp = &r->head; *headp; ) 51590926Snectar if((*headp)->type == T_SRV) { 51690926Snectar *ss = *headp; 51790926Snectar *headp = (*headp)->next; 51890926Snectar (*ss)->next = NULL; 51990926Snectar ss++; 52090926Snectar } else 52190926Snectar headp = &(*headp)->next; 52290926Snectar 52390926Snectar /* sort them by priority and weight */ 52490926Snectar qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 52590926Snectar 52690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 527102644Snectar oldstate = initstate(time(NULL), (char*)state, sizeof(state)); 52890926Snectar#endif 52990926Snectar 53090926Snectar headp = &r->head; 53190926Snectar 53290926Snectar for(ss = srvs; ss < srvs + num_srv; ) { 53390926Snectar int sum, rnd, count; 53490926Snectar struct resource_record **ee, **tt; 53590926Snectar /* find the last record with the same priority and count the 53690926Snectar sum of all weights */ 53790926Snectar for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 53890926Snectar if(*tt == NULL) 53990926Snectar continue; 54090926Snectar if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 54190926Snectar break; 54290926Snectar sum += (*tt)->u.srv->weight; 54390926Snectar } 54490926Snectar ee = tt; 54590926Snectar /* ss is now the first record of this priority and ee is the 54690926Snectar first of the next */ 54790926Snectar while(ss < ee) { 54890926Snectar rnd = random() % (sum + 1); 54990926Snectar for(count = 0, tt = ss; ; tt++) { 55090926Snectar if(*tt == NULL) 55190926Snectar continue; 55290926Snectar count += (*tt)->u.srv->weight; 55390926Snectar if(count >= rnd) 55490926Snectar break; 55590926Snectar } 55690926Snectar 55790926Snectar assert(tt < ee); 55890926Snectar 55990926Snectar /* insert the selected record at the tail (of the head) of 56090926Snectar the list */ 56190926Snectar (*tt)->next = *headp; 56290926Snectar *headp = *tt; 56390926Snectar headp = &(*tt)->next; 56490926Snectar sum -= (*tt)->u.srv->weight; 56590926Snectar *tt = NULL; 56690926Snectar while(ss < ee && *ss == NULL) 56790926Snectar ss++; 56890926Snectar } 56990926Snectar } 57090926Snectar 57190926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 57290926Snectar setstate(oldstate); 57390926Snectar#endif 57490926Snectar free(srvs); 57590926Snectar return; 57690926Snectar} 57790926Snectar 57855682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 57955682Smarkm 58055682Smarkmstruct dns_reply * 58155682Smarkmdns_lookup(const char *domain, const char *type_name) 58255682Smarkm{ 58355682Smarkm return NULL; 58455682Smarkm} 58555682Smarkm 58655682Smarkmvoid 58755682Smarkmdns_free_data(struct dns_reply *r) 58855682Smarkm{ 58955682Smarkm} 59055682Smarkm 59190926Snectarvoid 59290926Snectardns_srv_order(struct dns_reply *r) 59390926Snectar{ 59490926Snectar} 59590926Snectar 59655682Smarkm#endif 59755682Smarkm 59855682Smarkm#ifdef TEST 59955682Smarkmint 60055682Smarkmmain(int argc, char **argv) 60155682Smarkm{ 60255682Smarkm struct dns_reply *r; 60355682Smarkm struct resource_record *rr; 60455682Smarkm r = dns_lookup(argv[1], argv[2]); 60555682Smarkm if(r == NULL){ 60655682Smarkm printf("No reply.\n"); 60755682Smarkm return 1; 60855682Smarkm } 60990926Snectar if(r->q.type == T_SRV) 61090926Snectar dns_srv_order(r); 61190926Snectar 61255682Smarkm for(rr = r->head; rr;rr=rr->next){ 613107207Snectar printf("%-30s %-5s %-6d ", rr->domain, dns_type_to_string(rr->type), rr->ttl); 61455682Smarkm switch(rr->type){ 61555682Smarkm case T_NS: 61672445Sassar case T_CNAME: 61772445Sassar case T_PTR: 61855682Smarkm printf("%s\n", (char*)rr->u.data); 61955682Smarkm break; 62055682Smarkm case T_A: 62172445Sassar printf("%s\n", inet_ntoa(*rr->u.a)); 62255682Smarkm break; 62355682Smarkm case T_MX: 62455682Smarkm case T_AFSDB:{ 62572445Sassar printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain); 62655682Smarkm break; 62755682Smarkm } 62855682Smarkm case T_SRV:{ 62972445Sassar struct srv_record *srv = rr->u.srv; 63055682Smarkm printf("%d %d %d %s\n", srv->priority, srv->weight, 63155682Smarkm srv->port, srv->target); 63255682Smarkm break; 63355682Smarkm } 63472445Sassar case T_TXT: { 63572445Sassar printf("%s\n", rr->u.txt); 63672445Sassar break; 63772445Sassar } 63872445Sassar case T_SIG : { 63972445Sassar struct sig_record *sig = rr->u.sig; 64072445Sassar const char *type_string = dns_type_to_string (sig->type); 64172445Sassar 64272445Sassar printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n", 64372445Sassar sig->type, type_string ? type_string : "", 64472445Sassar sig->algorithm, sig->labels, sig->orig_ttl, 64572445Sassar sig->sig_expiration, sig->sig_inception, sig->key_tag, 64672445Sassar sig->signer); 64772445Sassar break; 64872445Sassar } 64972445Sassar case T_KEY : { 65072445Sassar struct key_record *key = rr->u.key; 65172445Sassar 65272445Sassar printf ("flags %u, protocol %u, algorithm %u\n", 65372445Sassar key->flags, key->protocol, key->algorithm); 65472445Sassar break; 65572445Sassar } 65655682Smarkm default: 65755682Smarkm printf("\n"); 65855682Smarkm break; 65955682Smarkm } 66055682Smarkm } 66155682Smarkm 66255682Smarkm return 0; 66355682Smarkm} 66455682Smarkm#endif 665