resolve.c revision 178825
155682Smarkm/* 2178825Sdfr * Copyright (c) 1995 - 2006 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 48178825SdfrRCSID("$Id: resolve.c 19869 2007-01-12 16:03:14Z lha $"); 4990926Snectar 50178825Sdfr#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */ 51103423Snectar#undef HAVE_RES_NSEARCH 52178825Sdfr#endif 5355682Smarkm 54178825Sdfr#define DECL(X) {#X, rk_ns_t_##X} 5555682Smarkm 5655682Smarkmstatic struct stot{ 5755682Smarkm const char *name; 5855682Smarkm int type; 5955682Smarkm}stot[] = { 60178825Sdfr DECL(a), 61178825Sdfr DECL(aaaa), 62178825Sdfr DECL(ns), 63178825Sdfr DECL(cname), 64178825Sdfr DECL(soa), 65178825Sdfr DECL(ptr), 66178825Sdfr DECL(mx), 67178825Sdfr DECL(txt), 68178825Sdfr DECL(afsdb), 69178825Sdfr DECL(sig), 70178825Sdfr DECL(key), 71178825Sdfr DECL(srv), 72178825Sdfr DECL(naptr), 73178825Sdfr DECL(sshfp), 74178825Sdfr DECL(ds), 7555682Smarkm {NULL, 0} 7655682Smarkm}; 7755682Smarkm 7872445Sassarint _resolve_debug = 0; 7955682Smarkm 80178825Sdfrint ROKEN_LIB_FUNCTION 8172445Sassardns_string_to_type(const char *name) 8255682Smarkm{ 8355682Smarkm struct stot *p = stot; 8455682Smarkm for(p = stot; p->name; p++) 8555682Smarkm if(strcasecmp(name, p->name) == 0) 8655682Smarkm return p->type; 8755682Smarkm return -1; 8855682Smarkm} 8955682Smarkm 90178825Sdfrconst char * ROKEN_LIB_FUNCTION 9172445Sassardns_type_to_string(int type) 9255682Smarkm{ 9355682Smarkm struct stot *p = stot; 9455682Smarkm for(p = stot; p->name; p++) 9555682Smarkm if(type == p->type) 9655682Smarkm return p->name; 9755682Smarkm return NULL; 9855682Smarkm} 9955682Smarkm 100178825Sdfr#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND) 101178825Sdfr 102178825Sdfrstatic void 103178825Sdfrdns_free_rr(struct resource_record *rr) 104178825Sdfr{ 105178825Sdfr if(rr->domain) 106178825Sdfr free(rr->domain); 107178825Sdfr if(rr->u.data) 108178825Sdfr free(rr->u.data); 109178825Sdfr free(rr); 110178825Sdfr} 111178825Sdfr 112178825Sdfrvoid ROKEN_LIB_FUNCTION 11355682Smarkmdns_free_data(struct dns_reply *r) 11455682Smarkm{ 11555682Smarkm struct resource_record *rr; 11655682Smarkm if(r->q.domain) 11755682Smarkm free(r->q.domain); 11855682Smarkm for(rr = r->head; rr;){ 11955682Smarkm struct resource_record *tmp = rr; 12055682Smarkm rr = rr->next; 121178825Sdfr dns_free_rr(tmp); 12255682Smarkm } 12355682Smarkm free (r); 12455682Smarkm} 12555682Smarkm 126107207Snectarstatic int 127107207Snectarparse_record(const unsigned char *data, const unsigned char *end_data, 128178825Sdfr const unsigned char **pp, struct resource_record **ret_rr) 129107207Snectar{ 130178825Sdfr struct resource_record *rr; 131107207Snectar int type, class, ttl, size; 132107207Snectar int status; 133107207Snectar char host[MAXDNAME]; 134107207Snectar const unsigned char *p = *pp; 135178825Sdfr 136178825Sdfr *ret_rr = NULL; 137178825Sdfr 138107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 139107207Snectar if(status < 0) 140107207Snectar return -1; 141107207Snectar if (p + status + 10 > end_data) 142107207Snectar return -1; 143178825Sdfr 144107207Snectar p += status; 145107207Snectar type = (p[0] << 8) | p[1]; 146107207Snectar p += 2; 147107207Snectar class = (p[0] << 8) | p[1]; 148107207Snectar p += 2; 149107207Snectar ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 150107207Snectar p += 4; 151107207Snectar size = (p[0] << 8) | p[1]; 152107207Snectar p += 2; 153107207Snectar 154107207Snectar if (p + size > end_data) 155107207Snectar return -1; 156107207Snectar 157178825Sdfr rr = calloc(1, sizeof(*rr)); 158178825Sdfr if(rr == NULL) 159107207Snectar return -1; 160178825Sdfr rr->domain = strdup(host); 161178825Sdfr if(rr->domain == NULL) { 162178825Sdfr dns_free_rr(rr); 163107207Snectar return -1; 164107207Snectar } 165178825Sdfr rr->type = type; 166178825Sdfr rr->class = class; 167178825Sdfr rr->ttl = ttl; 168178825Sdfr rr->size = size; 169107207Snectar switch(type){ 170178825Sdfr case rk_ns_t_ns: 171178825Sdfr case rk_ns_t_cname: 172178825Sdfr case rk_ns_t_ptr: 173107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 174107207Snectar if(status < 0) { 175178825Sdfr dns_free_rr(rr); 176107207Snectar return -1; 177107207Snectar } 178178825Sdfr rr->u.txt = strdup(host); 179178825Sdfr if(rr->u.txt == NULL) { 180178825Sdfr dns_free_rr(rr); 181107207Snectar return -1; 182107207Snectar } 183107207Snectar break; 184178825Sdfr case rk_ns_t_mx: 185178825Sdfr case rk_ns_t_afsdb:{ 186120945Snectar size_t hostlen; 187120945Snectar 188107207Snectar status = dn_expand(data, end_data, p + 2, host, sizeof(host)); 189107207Snectar if(status < 0){ 190178825Sdfr dns_free_rr(rr); 191107207Snectar return -1; 192107207Snectar } 193107207Snectar if (status + 2 > size) { 194178825Sdfr dns_free_rr(rr); 195107207Snectar return -1; 196107207Snectar } 197107207Snectar 198120945Snectar hostlen = strlen(host); 199178825Sdfr rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 200120945Snectar hostlen); 201178825Sdfr if(rr->u.mx == NULL) { 202178825Sdfr dns_free_rr(rr); 203107207Snectar return -1; 204107207Snectar } 205178825Sdfr rr->u.mx->preference = (p[0] << 8) | p[1]; 206178825Sdfr strlcpy(rr->u.mx->domain, host, hostlen + 1); 207107207Snectar break; 208107207Snectar } 209178825Sdfr case rk_ns_t_srv:{ 210120945Snectar size_t hostlen; 211107207Snectar status = dn_expand(data, end_data, p + 6, host, sizeof(host)); 212107207Snectar if(status < 0){ 213178825Sdfr dns_free_rr(rr); 214107207Snectar return -1; 215107207Snectar } 216107207Snectar if (status + 6 > size) { 217178825Sdfr dns_free_rr(rr); 218107207Snectar return -1; 219107207Snectar } 220107207Snectar 221120945Snectar hostlen = strlen(host); 222178825Sdfr rr->u.srv = 223107207Snectar (struct srv_record*)malloc(sizeof(struct srv_record) + 224120945Snectar hostlen); 225178825Sdfr if(rr->u.srv == NULL) { 226178825Sdfr dns_free_rr(rr); 227107207Snectar return -1; 228107207Snectar } 229178825Sdfr rr->u.srv->priority = (p[0] << 8) | p[1]; 230178825Sdfr rr->u.srv->weight = (p[2] << 8) | p[3]; 231178825Sdfr rr->u.srv->port = (p[4] << 8) | p[5]; 232178825Sdfr strlcpy(rr->u.srv->target, host, hostlen + 1); 233107207Snectar break; 234107207Snectar } 235178825Sdfr case rk_ns_t_txt:{ 236107207Snectar if(size == 0 || size < *p + 1) { 237178825Sdfr dns_free_rr(rr); 238107207Snectar return -1; 239107207Snectar } 240178825Sdfr rr->u.txt = (char*)malloc(*p + 1); 241178825Sdfr if(rr->u.txt == NULL) { 242178825Sdfr dns_free_rr(rr); 243107207Snectar return -1; 244107207Snectar } 245178825Sdfr strncpy(rr->u.txt, (const char*)(p + 1), *p); 246178825Sdfr rr->u.txt[*p] = '\0'; 247107207Snectar break; 248107207Snectar } 249178825Sdfr case rk_ns_t_key : { 250107207Snectar size_t key_len; 251107207Snectar 252107207Snectar if (size < 4) { 253178825Sdfr dns_free_rr(rr); 254107207Snectar return -1; 255107207Snectar } 256107207Snectar 257107207Snectar key_len = size - 4; 258178825Sdfr rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 259178825Sdfr if (rr->u.key == NULL) { 260178825Sdfr dns_free_rr(rr); 261107207Snectar return -1; 262107207Snectar } 263107207Snectar 264178825Sdfr rr->u.key->flags = (p[0] << 8) | p[1]; 265178825Sdfr rr->u.key->protocol = p[2]; 266178825Sdfr rr->u.key->algorithm = p[3]; 267178825Sdfr rr->u.key->key_len = key_len; 268178825Sdfr memcpy (rr->u.key->key_data, p + 4, key_len); 269107207Snectar break; 270107207Snectar } 271178825Sdfr case rk_ns_t_sig : { 272120945Snectar size_t sig_len, hostlen; 273107207Snectar 274107207Snectar if(size <= 18) { 275178825Sdfr dns_free_rr(rr); 276107207Snectar return -1; 277107207Snectar } 278107207Snectar status = dn_expand (data, end_data, p + 18, host, sizeof(host)); 279107207Snectar if (status < 0) { 280178825Sdfr dns_free_rr(rr); 281107207Snectar return -1; 282107207Snectar } 283107207Snectar if (status + 18 > size) { 284178825Sdfr dns_free_rr(rr); 285107207Snectar return -1; 286107207Snectar } 287107207Snectar 288107207Snectar /* the signer name is placed after the sig_data, to make it 289178825Sdfr easy to free this structure; the size calculation below 290107207Snectar includes the zero-termination if the structure itself. 291107207Snectar don't you just love C? 292107207Snectar */ 293107207Snectar sig_len = size - 18 - status; 294120945Snectar hostlen = strlen(host); 295178825Sdfr rr->u.sig = malloc(sizeof(*rr->u.sig) 296120945Snectar + hostlen + sig_len); 297178825Sdfr if (rr->u.sig == NULL) { 298178825Sdfr dns_free_rr(rr); 299107207Snectar return -1; 300107207Snectar } 301178825Sdfr rr->u.sig->type = (p[0] << 8) | p[1]; 302178825Sdfr rr->u.sig->algorithm = p[2]; 303178825Sdfr rr->u.sig->labels = p[3]; 304178825Sdfr rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16) 305107207Snectar | (p[6] << 8) | p[7]; 306178825Sdfr rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16) 307107207Snectar | (p[10] << 8) | p[11]; 308178825Sdfr rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16) 309107207Snectar | (p[14] << 8) | p[15]; 310178825Sdfr rr->u.sig->key_tag = (p[16] << 8) | p[17]; 311178825Sdfr rr->u.sig->sig_len = sig_len; 312178825Sdfr memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len); 313178825Sdfr rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 314178825Sdfr strlcpy(rr->u.sig->signer, host, hostlen + 1); 315107207Snectar break; 316107207Snectar } 317107207Snectar 318178825Sdfr case rk_ns_t_cert : { 319107207Snectar size_t cert_len; 320107207Snectar 321107207Snectar if (size < 5) { 322178825Sdfr dns_free_rr(rr); 323107207Snectar return -1; 324107207Snectar } 325107207Snectar 326107207Snectar cert_len = size - 5; 327178825Sdfr rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1); 328178825Sdfr if (rr->u.cert == NULL) { 329178825Sdfr dns_free_rr(rr); 330107207Snectar return -1; 331107207Snectar } 332107207Snectar 333178825Sdfr rr->u.cert->type = (p[0] << 8) | p[1]; 334178825Sdfr rr->u.cert->tag = (p[2] << 8) | p[3]; 335178825Sdfr rr->u.cert->algorithm = p[4]; 336178825Sdfr rr->u.cert->cert_len = cert_len; 337178825Sdfr memcpy (rr->u.cert->cert_data, p + 5, cert_len); 338107207Snectar break; 339107207Snectar } 340178825Sdfr case rk_ns_t_sshfp : { 341178825Sdfr size_t sshfp_len; 342178825Sdfr 343178825Sdfr if (size < 2) { 344178825Sdfr dns_free_rr(rr); 345178825Sdfr return -1; 346178825Sdfr } 347178825Sdfr 348178825Sdfr sshfp_len = size - 2; 349178825Sdfr 350178825Sdfr rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1); 351178825Sdfr if (rr->u.sshfp == NULL) { 352178825Sdfr dns_free_rr(rr); 353178825Sdfr return -1; 354178825Sdfr } 355178825Sdfr 356178825Sdfr rr->u.sshfp->algorithm = p[0]; 357178825Sdfr rr->u.sshfp->type = p[1]; 358178825Sdfr rr->u.sshfp->sshfp_len = sshfp_len; 359178825Sdfr memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len); 360178825Sdfr break; 361178825Sdfr } 362178825Sdfr case rk_ns_t_ds: { 363178825Sdfr size_t digest_len; 364178825Sdfr 365178825Sdfr if (size < 4) { 366178825Sdfr dns_free_rr(rr); 367178825Sdfr return -1; 368178825Sdfr } 369178825Sdfr 370178825Sdfr digest_len = size - 4; 371178825Sdfr 372178825Sdfr rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1); 373178825Sdfr if (rr->u.ds == NULL) { 374178825Sdfr dns_free_rr(rr); 375178825Sdfr return -1; 376178825Sdfr } 377178825Sdfr 378178825Sdfr rr->u.ds->key_tag = (p[0] << 8) | p[1]; 379178825Sdfr rr->u.ds->algorithm = p[2]; 380178825Sdfr rr->u.ds->digest_type = p[3]; 381178825Sdfr rr->u.ds->digest_len = digest_len; 382178825Sdfr memcpy (rr->u.ds->digest_data, p + 4, digest_len); 383178825Sdfr break; 384178825Sdfr } 385107207Snectar default: 386178825Sdfr rr->u.data = (unsigned char*)malloc(size); 387178825Sdfr if(size != 0 && rr->u.data == NULL) { 388178825Sdfr dns_free_rr(rr); 389107207Snectar return -1; 390107207Snectar } 391178825Sdfr if (size) 392178825Sdfr memcpy(rr->u.data, p, size); 393107207Snectar } 394107207Snectar *pp = p + size; 395178825Sdfr *ret_rr = rr; 396178825Sdfr 397107207Snectar return 0; 398107207Snectar} 399107207Snectar 400103423Snectar#ifndef TEST_RESOLVE 401103423Snectarstatic 402103423Snectar#endif 403103423Snectarstruct dns_reply* 404103423Snectarparse_reply(const unsigned char *data, size_t len) 40555682Smarkm{ 406102644Snectar const unsigned char *p; 40755682Smarkm int status; 408107207Snectar int i; 409107207Snectar char host[MAXDNAME]; 410102644Snectar const unsigned char *end_data = data + len; 41155682Smarkm struct dns_reply *r; 41255682Smarkm struct resource_record **rr; 41355682Smarkm 41455682Smarkm r = calloc(1, sizeof(*r)); 41555682Smarkm if (r == NULL) 41655682Smarkm return NULL; 41755682Smarkm 41855682Smarkm p = data; 419178825Sdfr 420178825Sdfr r->h.id = (p[0] << 8) | p[1]; 421178825Sdfr r->h.flags = 0; 422178825Sdfr if (p[2] & 0x01) 423178825Sdfr r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG; 424178825Sdfr r->h.opcode = (p[2] >> 1) & 0xf; 425178825Sdfr if (p[2] & 0x20) 426178825Sdfr r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 427178825Sdfr if (p[2] & 0x40) 428178825Sdfr r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE; 429178825Sdfr if (p[2] & 0x80) 430178825Sdfr r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED; 431178825Sdfr if (p[3] & 0x01) 432178825Sdfr r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE; 433178825Sdfr if (p[3] & 0x04) 434178825Sdfr r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 435178825Sdfr if (p[3] & 0x08) 436178825Sdfr r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED; 437178825Sdfr r->h.response_code = (p[3] >> 4) & 0xf; 438178825Sdfr r->h.qdcount = (p[4] << 8) | p[5]; 439178825Sdfr r->h.ancount = (p[6] << 8) | p[7]; 440178825Sdfr r->h.nscount = (p[8] << 8) | p[9]; 441178825Sdfr r->h.arcount = (p[10] << 8) | p[11]; 442178825Sdfr 44355682Smarkm p += 12; 444178825Sdfr 445178825Sdfr if(r->h.qdcount != 1) { 446107207Snectar free(r); 447107207Snectar return NULL; 448107207Snectar } 449102644Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 45055682Smarkm if(status < 0){ 45155682Smarkm dns_free_data(r); 45255682Smarkm return NULL; 45355682Smarkm } 45455682Smarkm r->q.domain = strdup(host); 45555682Smarkm if(r->q.domain == NULL) { 45655682Smarkm dns_free_data(r); 45755682Smarkm return NULL; 45855682Smarkm } 459102644Snectar if (p + status + 4 > end_data) { 460102644Snectar dns_free_data(r); 461102644Snectar return NULL; 462102644Snectar } 46355682Smarkm p += status; 46455682Smarkm r->q.type = (p[0] << 8 | p[1]); 46555682Smarkm p += 2; 46655682Smarkm r->q.class = (p[0] << 8 | p[1]); 46755682Smarkm p += 2; 468107207Snectar 46955682Smarkm rr = &r->head; 470178825Sdfr for(i = 0; i < r->h.ancount; i++) { 471107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 47255682Smarkm dns_free_data(r); 47355682Smarkm return NULL; 47455682Smarkm } 475107207Snectar rr = &(*rr)->next; 476107207Snectar } 477178825Sdfr for(i = 0; i < r->h.nscount; i++) { 478107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 479102644Snectar dns_free_data(r); 480102644Snectar return NULL; 481102644Snectar } 482107207Snectar rr = &(*rr)->next; 483107207Snectar } 484178825Sdfr for(i = 0; i < r->h.arcount; i++) { 485107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 486102644Snectar dns_free_data(r); 487102644Snectar return NULL; 488102644Snectar } 48955682Smarkm rr = &(*rr)->next; 49055682Smarkm } 49155682Smarkm *rr = NULL; 49255682Smarkm return r; 49355682Smarkm} 49455682Smarkm 495178825Sdfr#ifdef HAVE_RES_NSEARCH 496178825Sdfr#ifdef HAVE_RES_NDESTROY 497178825Sdfr#define rk_res_free(x) res_ndestroy(x) 498178825Sdfr#else 499178825Sdfr#define rk_res_free(x) res_nclose(x) 500178825Sdfr#endif 501178825Sdfr#endif 502178825Sdfr 50355682Smarkmstatic struct dns_reply * 50455682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type) 50555682Smarkm{ 506178825Sdfr struct dns_reply *r; 507178825Sdfr unsigned char *reply = NULL; 508178825Sdfr int size; 50955682Smarkm int len; 510103423Snectar#ifdef HAVE_RES_NSEARCH 511178825Sdfr struct __res_state state; 512178825Sdfr memset(&state, 0, sizeof(state)); 513178825Sdfr if(res_ninit(&state)) 514103423Snectar return NULL; /* is this the best we can do? */ 515103423Snectar#elif defined(HAVE__RES) 51655682Smarkm u_long old_options = 0; 517102644Snectar#endif 51855682Smarkm 519178825Sdfr size = 0; 520178825Sdfr len = 1000; 521178825Sdfr do { 522178825Sdfr if (reply) { 523178825Sdfr free(reply); 524178825Sdfr reply = NULL; 525178825Sdfr } 526178825Sdfr if (size <= len) 527178825Sdfr size = len; 528178825Sdfr if (_resolve_debug) { 529103423Snectar#ifdef HAVE_RES_NSEARCH 530178825Sdfr state.options |= RES_DEBUG; 531103423Snectar#elif defined(HAVE__RES) 532178825Sdfr old_options = _res.options; 533178825Sdfr _res.options |= RES_DEBUG; 534102644Snectar#endif 535178825Sdfr fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain, 536178825Sdfr rr_class, dns_type_to_string(rr_type), size); 537178825Sdfr } 538178825Sdfr reply = malloc(size); 539178825Sdfr if (reply == NULL) { 540103423Snectar#ifdef HAVE_RES_NSEARCH 541178825Sdfr rk_res_free(&state); 542178825Sdfr#endif 543178825Sdfr return NULL; 544178825Sdfr } 545178825Sdfr#ifdef HAVE_RES_NSEARCH 546178825Sdfr len = res_nsearch(&state, domain, rr_class, rr_type, reply, size); 547103423Snectar#else 548178825Sdfr len = res_search(domain, rr_class, rr_type, reply, size); 549103423Snectar#endif 550178825Sdfr if (_resolve_debug) { 551103423Snectar#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH) 552178825Sdfr _res.options = old_options; 553102644Snectar#endif 554178825Sdfr fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 555178825Sdfr domain, rr_class, dns_type_to_string(rr_type), len); 556178825Sdfr } 557178825Sdfr if (len < 0) { 558103423Snectar#ifdef HAVE_RES_NSEARCH 559178825Sdfr rk_res_free(&state); 560178825Sdfr#endif 561178825Sdfr free(reply); 562178825Sdfr return NULL; 563178825Sdfr } 564178825Sdfr } while (size < len && len < rk_DNS_MAX_PACKET_SIZE); 565178825Sdfr#ifdef HAVE_RES_NSEARCH 566178825Sdfr rk_res_free(&state); 567178825Sdfr#endif 568178825Sdfr 569178825Sdfr len = min(len, size); 570178825Sdfr r = parse_reply(reply, len); 571178825Sdfr free(reply); 572178825Sdfr return r; 57355682Smarkm} 57455682Smarkm 575178825Sdfrstruct dns_reply * ROKEN_LIB_FUNCTION 57655682Smarkmdns_lookup(const char *domain, const char *type_name) 57755682Smarkm{ 57855682Smarkm int type; 57955682Smarkm 58072445Sassar type = dns_string_to_type(type_name); 58155682Smarkm if(type == -1) { 58255682Smarkm if(_resolve_debug) 58355682Smarkm fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 58455682Smarkm type_name); 58555682Smarkm return NULL; 58655682Smarkm } 58755682Smarkm return dns_lookup_int(domain, C_IN, type); 58855682Smarkm} 58955682Smarkm 59090926Snectarstatic int 59190926Snectarcompare_srv(const void *a, const void *b) 59290926Snectar{ 59390926Snectar const struct resource_record *const* aa = a, *const* bb = b; 59490926Snectar 59590926Snectar if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 59690926Snectar return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 59790926Snectar return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 59890926Snectar} 59990926Snectar 60090926Snectar#ifndef HAVE_RANDOM 60190926Snectar#define random() rand() 60290926Snectar#endif 60390926Snectar 60490926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */ 605178825Sdfrvoid ROKEN_LIB_FUNCTION 60690926Snectardns_srv_order(struct dns_reply *r) 60790926Snectar{ 60890926Snectar struct resource_record **srvs, **ss, **headp; 60990926Snectar struct resource_record *rr; 61090926Snectar int num_srv = 0; 61190926Snectar 61290926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 613102644Snectar int state[256 / sizeof(int)]; 614102644Snectar char *oldstate; 61590926Snectar#endif 61690926Snectar 61790926Snectar for(rr = r->head; rr; rr = rr->next) 618178825Sdfr if(rr->type == rk_ns_t_srv) 61990926Snectar num_srv++; 62090926Snectar 62190926Snectar if(num_srv == 0) 62290926Snectar return; 62390926Snectar 62490926Snectar srvs = malloc(num_srv * sizeof(*srvs)); 62590926Snectar if(srvs == NULL) 62690926Snectar return; /* XXX not much to do here */ 62790926Snectar 62890926Snectar /* unlink all srv-records from the linked list and put them in 62990926Snectar a vector */ 63090926Snectar for(ss = srvs, headp = &r->head; *headp; ) 631178825Sdfr if((*headp)->type == rk_ns_t_srv) { 63290926Snectar *ss = *headp; 63390926Snectar *headp = (*headp)->next; 63490926Snectar (*ss)->next = NULL; 63590926Snectar ss++; 63690926Snectar } else 63790926Snectar headp = &(*headp)->next; 63890926Snectar 63990926Snectar /* sort them by priority and weight */ 64090926Snectar qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 64190926Snectar 64290926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 643102644Snectar oldstate = initstate(time(NULL), (char*)state, sizeof(state)); 64490926Snectar#endif 64590926Snectar 64690926Snectar headp = &r->head; 64790926Snectar 64890926Snectar for(ss = srvs; ss < srvs + num_srv; ) { 64990926Snectar int sum, rnd, count; 65090926Snectar struct resource_record **ee, **tt; 65190926Snectar /* find the last record with the same priority and count the 65290926Snectar sum of all weights */ 65390926Snectar for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 654178825Sdfr assert(*tt != NULL); 65590926Snectar if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 65690926Snectar break; 65790926Snectar sum += (*tt)->u.srv->weight; 65890926Snectar } 65990926Snectar ee = tt; 66090926Snectar /* ss is now the first record of this priority and ee is the 66190926Snectar first of the next */ 66290926Snectar while(ss < ee) { 66390926Snectar rnd = random() % (sum + 1); 66490926Snectar for(count = 0, tt = ss; ; tt++) { 66590926Snectar if(*tt == NULL) 66690926Snectar continue; 66790926Snectar count += (*tt)->u.srv->weight; 66890926Snectar if(count >= rnd) 66990926Snectar break; 67090926Snectar } 67190926Snectar 67290926Snectar assert(tt < ee); 67390926Snectar 67490926Snectar /* insert the selected record at the tail (of the head) of 67590926Snectar the list */ 67690926Snectar (*tt)->next = *headp; 67790926Snectar *headp = *tt; 67890926Snectar headp = &(*tt)->next; 67990926Snectar sum -= (*tt)->u.srv->weight; 68090926Snectar *tt = NULL; 68190926Snectar while(ss < ee && *ss == NULL) 68290926Snectar ss++; 68390926Snectar } 68490926Snectar } 68590926Snectar 68690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 68790926Snectar setstate(oldstate); 68890926Snectar#endif 68990926Snectar free(srvs); 69090926Snectar return; 69190926Snectar} 69290926Snectar 69355682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 69455682Smarkm 695178825Sdfrstruct dns_reply * ROKEN_LIB_FUNCTION 69655682Smarkmdns_lookup(const char *domain, const char *type_name) 69755682Smarkm{ 69855682Smarkm return NULL; 69955682Smarkm} 70055682Smarkm 701178825Sdfrvoid ROKEN_LIB_FUNCTION 70255682Smarkmdns_free_data(struct dns_reply *r) 70355682Smarkm{ 70455682Smarkm} 70555682Smarkm 706178825Sdfrvoid ROKEN_LIB_FUNCTION 70790926Snectardns_srv_order(struct dns_reply *r) 70890926Snectar{ 70990926Snectar} 71090926Snectar 71155682Smarkm#endif 712