155682Smarkm/* 2233294Sstas * Copyright (c) 1995 - 2006 Kungliga Tekniska H��gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 5233294Sstas * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 9233294Sstas * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 12233294Sstas * 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. 16233294Sstas * 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. 20233294Sstas * 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 34233294Sstas 3555682Smarkm#include <config.h> 36233294Sstas 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 44233294Sstas#ifdef HAVE_DNS_H 45233294Sstas#include <dns.h> 46233294Sstas#endif 4755682Smarkm#include "resolve.h" 4855682Smarkm 4990926Snectar#include <assert.h> 5055682Smarkm 51178825Sdfr#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */ 52103423Snectar#undef HAVE_RES_NSEARCH 53178825Sdfr#endif 5455682Smarkm 55178825Sdfr#define DECL(X) {#X, rk_ns_t_##X} 5655682Smarkm 5755682Smarkmstatic struct stot{ 5855682Smarkm const char *name; 5955682Smarkm int type; 6055682Smarkm}stot[] = { 61178825Sdfr DECL(a), 62178825Sdfr DECL(aaaa), 63178825Sdfr DECL(ns), 64178825Sdfr DECL(cname), 65178825Sdfr DECL(soa), 66178825Sdfr DECL(ptr), 67178825Sdfr DECL(mx), 68178825Sdfr DECL(txt), 69178825Sdfr DECL(afsdb), 70178825Sdfr DECL(sig), 71178825Sdfr DECL(key), 72178825Sdfr DECL(srv), 73178825Sdfr DECL(naptr), 74178825Sdfr DECL(sshfp), 75178825Sdfr DECL(ds), 7655682Smarkm {NULL, 0} 7755682Smarkm}; 7855682Smarkm 7972445Sassarint _resolve_debug = 0; 8055682Smarkm 81233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 82233294Sstasrk_dns_string_to_type(const char *name) 8355682Smarkm{ 8455682Smarkm struct stot *p = stot; 8555682Smarkm for(p = stot; p->name; p++) 8655682Smarkm if(strcasecmp(name, p->name) == 0) 8755682Smarkm return p->type; 8855682Smarkm return -1; 8955682Smarkm} 9055682Smarkm 91233294SstasROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL 92233294Sstasrk_dns_type_to_string(int type) 9355682Smarkm{ 9455682Smarkm struct stot *p = stot; 9555682Smarkm for(p = stot; p->name; p++) 9655682Smarkm if(type == p->type) 9755682Smarkm return p->name; 9855682Smarkm return NULL; 9955682Smarkm} 10055682Smarkm 101233294Sstas#if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS) 102178825Sdfr 103178825Sdfrstatic void 104233294Sstasdns_free_rr(struct rk_resource_record *rr) 105178825Sdfr{ 106178825Sdfr if(rr->domain) 107178825Sdfr free(rr->domain); 108178825Sdfr if(rr->u.data) 109178825Sdfr free(rr->u.data); 110178825Sdfr free(rr); 111178825Sdfr} 112178825Sdfr 113233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 114233294Sstasrk_dns_free_data(struct rk_dns_reply *r) 11555682Smarkm{ 116233294Sstas struct rk_resource_record *rr; 11755682Smarkm if(r->q.domain) 11855682Smarkm free(r->q.domain); 11955682Smarkm for(rr = r->head; rr;){ 120233294Sstas struct rk_resource_record *tmp = rr; 12155682Smarkm rr = rr->next; 122178825Sdfr dns_free_rr(tmp); 12355682Smarkm } 12455682Smarkm free (r); 12555682Smarkm} 12655682Smarkm 127233294Sstas#ifndef HAVE_WINDNS 128233294Sstas 129107207Snectarstatic int 130233294Sstasparse_record(const unsigned char *data, const unsigned char *end_data, 131233294Sstas const unsigned char **pp, struct rk_resource_record **ret_rr) 132107207Snectar{ 133233294Sstas struct rk_resource_record *rr; 134233294Sstas int type, class, ttl; 135233294Sstas unsigned size; 136107207Snectar int status; 137107207Snectar char host[MAXDNAME]; 138107207Snectar const unsigned char *p = *pp; 139178825Sdfr 140178825Sdfr *ret_rr = NULL; 141178825Sdfr 142107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 143233294Sstas if(status < 0) 144107207Snectar return -1; 145107207Snectar if (p + status + 10 > end_data) 146107207Snectar return -1; 147178825Sdfr 148107207Snectar p += status; 149107207Snectar type = (p[0] << 8) | p[1]; 150107207Snectar p += 2; 151107207Snectar class = (p[0] << 8) | p[1]; 152107207Snectar p += 2; 153107207Snectar ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 154107207Snectar p += 4; 155107207Snectar size = (p[0] << 8) | p[1]; 156107207Snectar p += 2; 157107207Snectar 158107207Snectar if (p + size > end_data) 159107207Snectar return -1; 160107207Snectar 161178825Sdfr rr = calloc(1, sizeof(*rr)); 162233294Sstas if(rr == NULL) 163107207Snectar return -1; 164178825Sdfr rr->domain = strdup(host); 165178825Sdfr if(rr->domain == NULL) { 166178825Sdfr dns_free_rr(rr); 167107207Snectar return -1; 168107207Snectar } 169178825Sdfr rr->type = type; 170178825Sdfr rr->class = class; 171178825Sdfr rr->ttl = ttl; 172178825Sdfr rr->size = size; 173107207Snectar switch(type){ 174178825Sdfr case rk_ns_t_ns: 175178825Sdfr case rk_ns_t_cname: 176178825Sdfr case rk_ns_t_ptr: 177107207Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 178107207Snectar if(status < 0) { 179178825Sdfr dns_free_rr(rr); 180107207Snectar return -1; 181107207Snectar } 182178825Sdfr rr->u.txt = strdup(host); 183178825Sdfr if(rr->u.txt == NULL) { 184178825Sdfr dns_free_rr(rr); 185107207Snectar return -1; 186107207Snectar } 187107207Snectar break; 188178825Sdfr case rk_ns_t_mx: 189178825Sdfr case rk_ns_t_afsdb:{ 190120945Snectar size_t hostlen; 191120945Snectar 192107207Snectar status = dn_expand(data, end_data, p + 2, host, sizeof(host)); 193107207Snectar if(status < 0){ 194178825Sdfr dns_free_rr(rr); 195107207Snectar return -1; 196107207Snectar } 197233294Sstas if ((size_t)status + 2 > size) { 198178825Sdfr dns_free_rr(rr); 199107207Snectar return -1; 200107207Snectar } 201107207Snectar 202120945Snectar hostlen = strlen(host); 203233294Sstas rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 204120945Snectar hostlen); 205178825Sdfr if(rr->u.mx == NULL) { 206178825Sdfr dns_free_rr(rr); 207107207Snectar return -1; 208107207Snectar } 209178825Sdfr rr->u.mx->preference = (p[0] << 8) | p[1]; 210178825Sdfr strlcpy(rr->u.mx->domain, host, hostlen + 1); 211107207Snectar break; 212107207Snectar } 213178825Sdfr case rk_ns_t_srv:{ 214120945Snectar size_t hostlen; 215107207Snectar status = dn_expand(data, end_data, p + 6, host, sizeof(host)); 216107207Snectar if(status < 0){ 217178825Sdfr dns_free_rr(rr); 218107207Snectar return -1; 219107207Snectar } 220233294Sstas if ((size_t)status + 6 > size) { 221178825Sdfr dns_free_rr(rr); 222107207Snectar return -1; 223107207Snectar } 224107207Snectar 225120945Snectar hostlen = strlen(host); 226233294Sstas rr->u.srv = 227233294Sstas (struct srv_record*)malloc(sizeof(struct srv_record) + 228120945Snectar hostlen); 229178825Sdfr if(rr->u.srv == NULL) { 230178825Sdfr dns_free_rr(rr); 231107207Snectar return -1; 232107207Snectar } 233178825Sdfr rr->u.srv->priority = (p[0] << 8) | p[1]; 234178825Sdfr rr->u.srv->weight = (p[2] << 8) | p[3]; 235178825Sdfr rr->u.srv->port = (p[4] << 8) | p[5]; 236178825Sdfr strlcpy(rr->u.srv->target, host, hostlen + 1); 237107207Snectar break; 238107207Snectar } 239178825Sdfr case rk_ns_t_txt:{ 240233294Sstas if(size == 0 || size < (unsigned)(*p + 1)) { 241178825Sdfr dns_free_rr(rr); 242107207Snectar return -1; 243107207Snectar } 244178825Sdfr rr->u.txt = (char*)malloc(*p + 1); 245178825Sdfr if(rr->u.txt == NULL) { 246178825Sdfr dns_free_rr(rr); 247107207Snectar return -1; 248107207Snectar } 249178825Sdfr strncpy(rr->u.txt, (const char*)(p + 1), *p); 250178825Sdfr rr->u.txt[*p] = '\0'; 251107207Snectar break; 252107207Snectar } 253178825Sdfr case rk_ns_t_key : { 254107207Snectar size_t key_len; 255107207Snectar 256107207Snectar if (size < 4) { 257178825Sdfr dns_free_rr(rr); 258107207Snectar return -1; 259107207Snectar } 260107207Snectar 261107207Snectar key_len = size - 4; 262178825Sdfr rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 263178825Sdfr if (rr->u.key == NULL) { 264178825Sdfr dns_free_rr(rr); 265107207Snectar return -1; 266107207Snectar } 267107207Snectar 268178825Sdfr rr->u.key->flags = (p[0] << 8) | p[1]; 269178825Sdfr rr->u.key->protocol = p[2]; 270178825Sdfr rr->u.key->algorithm = p[3]; 271178825Sdfr rr->u.key->key_len = key_len; 272178825Sdfr memcpy (rr->u.key->key_data, p + 4, key_len); 273107207Snectar break; 274107207Snectar } 275178825Sdfr case rk_ns_t_sig : { 276120945Snectar size_t sig_len, hostlen; 277107207Snectar 278107207Snectar if(size <= 18) { 279178825Sdfr dns_free_rr(rr); 280107207Snectar return -1; 281107207Snectar } 282107207Snectar status = dn_expand (data, end_data, p + 18, host, sizeof(host)); 283107207Snectar if (status < 0) { 284178825Sdfr dns_free_rr(rr); 285107207Snectar return -1; 286107207Snectar } 287233294Sstas if ((size_t)status + 18 > size) { 288178825Sdfr dns_free_rr(rr); 289107207Snectar return -1; 290107207Snectar } 291107207Snectar 292107207Snectar /* the signer name is placed after the sig_data, to make it 293178825Sdfr easy to free this structure; the size calculation below 294107207Snectar includes the zero-termination if the structure itself. 295107207Snectar don't you just love C? 296107207Snectar */ 297107207Snectar sig_len = size - 18 - status; 298120945Snectar hostlen = strlen(host); 299178825Sdfr rr->u.sig = malloc(sizeof(*rr->u.sig) 300120945Snectar + hostlen + sig_len); 301178825Sdfr if (rr->u.sig == NULL) { 302178825Sdfr dns_free_rr(rr); 303107207Snectar return -1; 304107207Snectar } 305178825Sdfr rr->u.sig->type = (p[0] << 8) | p[1]; 306178825Sdfr rr->u.sig->algorithm = p[2]; 307178825Sdfr rr->u.sig->labels = p[3]; 308178825Sdfr rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16) 309107207Snectar | (p[6] << 8) | p[7]; 310178825Sdfr rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16) 311107207Snectar | (p[10] << 8) | p[11]; 312178825Sdfr rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16) 313107207Snectar | (p[14] << 8) | p[15]; 314178825Sdfr rr->u.sig->key_tag = (p[16] << 8) | p[17]; 315178825Sdfr rr->u.sig->sig_len = sig_len; 316178825Sdfr memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len); 317178825Sdfr rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 318178825Sdfr strlcpy(rr->u.sig->signer, host, hostlen + 1); 319107207Snectar break; 320107207Snectar } 321107207Snectar 322178825Sdfr case rk_ns_t_cert : { 323107207Snectar size_t cert_len; 324107207Snectar 325107207Snectar if (size < 5) { 326178825Sdfr dns_free_rr(rr); 327107207Snectar return -1; 328107207Snectar } 329107207Snectar 330107207Snectar cert_len = size - 5; 331178825Sdfr rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1); 332178825Sdfr if (rr->u.cert == NULL) { 333178825Sdfr dns_free_rr(rr); 334107207Snectar return -1; 335107207Snectar } 336107207Snectar 337178825Sdfr rr->u.cert->type = (p[0] << 8) | p[1]; 338178825Sdfr rr->u.cert->tag = (p[2] << 8) | p[3]; 339178825Sdfr rr->u.cert->algorithm = p[4]; 340178825Sdfr rr->u.cert->cert_len = cert_len; 341178825Sdfr memcpy (rr->u.cert->cert_data, p + 5, cert_len); 342107207Snectar break; 343107207Snectar } 344178825Sdfr case rk_ns_t_sshfp : { 345178825Sdfr size_t sshfp_len; 346178825Sdfr 347178825Sdfr if (size < 2) { 348178825Sdfr dns_free_rr(rr); 349178825Sdfr return -1; 350178825Sdfr } 351178825Sdfr 352178825Sdfr sshfp_len = size - 2; 353178825Sdfr 354178825Sdfr rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1); 355178825Sdfr if (rr->u.sshfp == NULL) { 356178825Sdfr dns_free_rr(rr); 357178825Sdfr return -1; 358178825Sdfr } 359178825Sdfr 360178825Sdfr rr->u.sshfp->algorithm = p[0]; 361178825Sdfr rr->u.sshfp->type = p[1]; 362178825Sdfr rr->u.sshfp->sshfp_len = sshfp_len; 363178825Sdfr memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len); 364178825Sdfr break; 365178825Sdfr } 366178825Sdfr case rk_ns_t_ds: { 367178825Sdfr size_t digest_len; 368178825Sdfr 369178825Sdfr if (size < 4) { 370178825Sdfr dns_free_rr(rr); 371178825Sdfr return -1; 372178825Sdfr } 373178825Sdfr 374178825Sdfr digest_len = size - 4; 375178825Sdfr 376178825Sdfr rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1); 377178825Sdfr if (rr->u.ds == NULL) { 378178825Sdfr dns_free_rr(rr); 379178825Sdfr return -1; 380178825Sdfr } 381178825Sdfr 382178825Sdfr rr->u.ds->key_tag = (p[0] << 8) | p[1]; 383178825Sdfr rr->u.ds->algorithm = p[2]; 384178825Sdfr rr->u.ds->digest_type = p[3]; 385178825Sdfr rr->u.ds->digest_len = digest_len; 386178825Sdfr memcpy (rr->u.ds->digest_data, p + 4, digest_len); 387178825Sdfr break; 388178825Sdfr } 389107207Snectar default: 390178825Sdfr rr->u.data = (unsigned char*)malloc(size); 391178825Sdfr if(size != 0 && rr->u.data == NULL) { 392178825Sdfr dns_free_rr(rr); 393107207Snectar return -1; 394107207Snectar } 395178825Sdfr if (size) 396178825Sdfr memcpy(rr->u.data, p, size); 397107207Snectar } 398107207Snectar *pp = p + size; 399178825Sdfr *ret_rr = rr; 400178825Sdfr 401107207Snectar return 0; 402107207Snectar} 403107207Snectar 404103423Snectar#ifndef TEST_RESOLVE 405103423Snectarstatic 406103423Snectar#endif 407233294Sstasstruct rk_dns_reply* 408103423Snectarparse_reply(const unsigned char *data, size_t len) 40955682Smarkm{ 410102644Snectar const unsigned char *p; 41155682Smarkm int status; 412233294Sstas size_t i; 413107207Snectar char host[MAXDNAME]; 414102644Snectar const unsigned char *end_data = data + len; 415233294Sstas struct rk_dns_reply *r; 416233294Sstas struct rk_resource_record **rr; 417233294Sstas 41855682Smarkm r = calloc(1, sizeof(*r)); 41955682Smarkm if (r == NULL) 42055682Smarkm return NULL; 42155682Smarkm 42255682Smarkm p = data; 423178825Sdfr 424178825Sdfr r->h.id = (p[0] << 8) | p[1]; 425178825Sdfr r->h.flags = 0; 426178825Sdfr if (p[2] & 0x01) 427178825Sdfr r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG; 428178825Sdfr r->h.opcode = (p[2] >> 1) & 0xf; 429178825Sdfr if (p[2] & 0x20) 430178825Sdfr r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 431178825Sdfr if (p[2] & 0x40) 432178825Sdfr r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE; 433178825Sdfr if (p[2] & 0x80) 434178825Sdfr r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED; 435178825Sdfr if (p[3] & 0x01) 436178825Sdfr r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE; 437178825Sdfr if (p[3] & 0x04) 438178825Sdfr r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 439178825Sdfr if (p[3] & 0x08) 440178825Sdfr r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED; 441178825Sdfr r->h.response_code = (p[3] >> 4) & 0xf; 442178825Sdfr r->h.qdcount = (p[4] << 8) | p[5]; 443178825Sdfr r->h.ancount = (p[6] << 8) | p[7]; 444178825Sdfr r->h.nscount = (p[8] << 8) | p[9]; 445178825Sdfr r->h.arcount = (p[10] << 8) | p[11]; 446178825Sdfr 44755682Smarkm p += 12; 448178825Sdfr 449178825Sdfr if(r->h.qdcount != 1) { 450107207Snectar free(r); 451107207Snectar return NULL; 452107207Snectar } 453102644Snectar status = dn_expand(data, end_data, p, host, sizeof(host)); 45455682Smarkm if(status < 0){ 455233294Sstas rk_dns_free_data(r); 45655682Smarkm return NULL; 45755682Smarkm } 45855682Smarkm r->q.domain = strdup(host); 45955682Smarkm if(r->q.domain == NULL) { 460233294Sstas rk_dns_free_data(r); 46155682Smarkm return NULL; 46255682Smarkm } 463102644Snectar if (p + status + 4 > end_data) { 464233294Sstas rk_dns_free_data(r); 465102644Snectar return NULL; 466102644Snectar } 46755682Smarkm p += status; 46855682Smarkm r->q.type = (p[0] << 8 | p[1]); 46955682Smarkm p += 2; 47055682Smarkm r->q.class = (p[0] << 8 | p[1]); 47155682Smarkm p += 2; 472233294Sstas 47355682Smarkm rr = &r->head; 474178825Sdfr for(i = 0; i < r->h.ancount; i++) { 475107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 476233294Sstas rk_dns_free_data(r); 47755682Smarkm return NULL; 47855682Smarkm } 479107207Snectar rr = &(*rr)->next; 480107207Snectar } 481178825Sdfr for(i = 0; i < r->h.nscount; i++) { 482107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 483233294Sstas rk_dns_free_data(r); 484102644Snectar return NULL; 485102644Snectar } 486107207Snectar rr = &(*rr)->next; 487107207Snectar } 488178825Sdfr for(i = 0; i < r->h.arcount; i++) { 489107207Snectar if(parse_record(data, end_data, &p, rr) != 0) { 490233294Sstas rk_dns_free_data(r); 491102644Snectar return NULL; 492102644Snectar } 49355682Smarkm rr = &(*rr)->next; 49455682Smarkm } 49555682Smarkm *rr = NULL; 49655682Smarkm return r; 49755682Smarkm} 49855682Smarkm 499178825Sdfr#ifdef HAVE_RES_NSEARCH 500178825Sdfr#ifdef HAVE_RES_NDESTROY 501178825Sdfr#define rk_res_free(x) res_ndestroy(x) 502178825Sdfr#else 503178825Sdfr#define rk_res_free(x) res_nclose(x) 504178825Sdfr#endif 505178825Sdfr#endif 506178825Sdfr 507233294Sstas#if defined(HAVE_DNS_SEARCH) 508233294Sstas#define resolve_search(h,n,c,t,r,l) \ 509233294Sstas ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize)) 510233294Sstas#define resolve_free_handle(h) dns_free(h) 511233294Sstas#elif defined(HAVE_RES_NSEARCH) 512233294Sstas#define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l) 513233294Sstas#define resolve_free_handle(h) rk_res_free(h); 514233294Sstas#else 515233294Sstas#define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l) 516233294Sstas#define handle 0 517233294Sstas#define resolve_free_handle(h) 518233294Sstas#endif 519233294Sstas 520233294Sstas 521233294Sstasstatic struct rk_dns_reply * 52255682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type) 52355682Smarkm{ 524233294Sstas struct rk_dns_reply *r; 525233294Sstas void *reply = NULL; 526233294Sstas int size, len; 527233294Sstas#if defined(HAVE_DNS_SEARCH) 528233294Sstas struct sockaddr_storage from; 529233294Sstas uint32_t fromsize = sizeof(from); 530233294Sstas dns_handle_t handle; 531233294Sstas 532233294Sstas handle = dns_open(NULL); 533233294Sstas if (handle == NULL) 534233294Sstas return NULL; 535233294Sstas#elif defined(HAVE_RES_NSEARCH) 536178825Sdfr struct __res_state state; 537233294Sstas struct __res_state *handle = &state; 538233294Sstas 539178825Sdfr memset(&state, 0, sizeof(state)); 540233294Sstas if(res_ninit(handle)) 541103423Snectar return NULL; /* is this the best we can do? */ 542102644Snectar#endif 543233294Sstas 544233294Sstas len = 1500; 545233294Sstas while(1) { 546178825Sdfr if (reply) { 547178825Sdfr free(reply); 548178825Sdfr reply = NULL; 549178825Sdfr } 550178825Sdfr if (_resolve_debug) { 551233294Sstas#if defined(HAVE_DNS_SEARCH) 552233294Sstas dns_set_debug(handle, 1); 553233294Sstas#elif defined(HAVE_RES_NSEARCH) 554178825Sdfr state.options |= RES_DEBUG; 555102644Snectar#endif 556178825Sdfr fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain, 557233294Sstas rr_class, rk_dns_type_to_string(rr_type), len); 558178825Sdfr } 559233294Sstas reply = malloc(len); 560178825Sdfr if (reply == NULL) { 561233294Sstas resolve_free_handle(handle); 562178825Sdfr return NULL; 563178825Sdfr } 564233294Sstas 565233294Sstas size = resolve_search(handle, domain, rr_class, rr_type, reply, len); 566233294Sstas 567178825Sdfr if (_resolve_debug) { 568178825Sdfr fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 569233294Sstas domain, rr_class, rk_dns_type_to_string(rr_type), size); 570178825Sdfr } 571233294Sstas if (size > len) { 572233294Sstas /* resolver thinks it know better, go for it */ 573233294Sstas len = size; 574233294Sstas } else if (size > 0) { 575233294Sstas /* got a good reply */ 576233294Sstas break; 577233294Sstas } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) { 578233294Sstas len *= 2; 579233294Sstas if (len > rk_DNS_MAX_PACKET_SIZE) 580233294Sstas len = rk_DNS_MAX_PACKET_SIZE; 581233294Sstas } else { 582233294Sstas /* the end, leave */ 583233294Sstas resolve_free_handle(handle); 584178825Sdfr free(reply); 585178825Sdfr return NULL; 586178825Sdfr } 587233294Sstas } 588178825Sdfr 589178825Sdfr len = min(len, size); 590178825Sdfr r = parse_reply(reply, len); 591178825Sdfr free(reply); 592233294Sstas 593233294Sstas resolve_free_handle(handle); 594233294Sstas 595178825Sdfr return r; 59655682Smarkm} 59755682Smarkm 598233294SstasROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 599233294Sstasrk_dns_lookup(const char *domain, const char *type_name) 60055682Smarkm{ 60155682Smarkm int type; 602233294Sstas 603233294Sstas type = rk_dns_string_to_type(type_name); 60455682Smarkm if(type == -1) { 60555682Smarkm if(_resolve_debug) 606233294Sstas fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 60755682Smarkm type_name); 60855682Smarkm return NULL; 60955682Smarkm } 610233294Sstas return dns_lookup_int(domain, rk_ns_c_in, type); 61155682Smarkm} 61255682Smarkm 613233294Sstas#endif /* !HAVE_WINDNS */ 614233294Sstas 61590926Snectarstatic int 61690926Snectarcompare_srv(const void *a, const void *b) 61790926Snectar{ 618233294Sstas const struct rk_resource_record *const* aa = a, *const* bb = b; 61990926Snectar 62090926Snectar if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 62190926Snectar return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 62290926Snectar return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 62390926Snectar} 62490926Snectar 62590926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */ 626233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 627233294Sstasrk_dns_srv_order(struct rk_dns_reply *r) 62890926Snectar{ 629233294Sstas struct rk_resource_record **srvs, **ss, **headp; 630233294Sstas struct rk_resource_record *rr; 63190926Snectar int num_srv = 0; 63290926Snectar 633233294Sstas rk_random_init(); 63490926Snectar 635233294Sstas for(rr = r->head; rr; rr = rr->next) 636178825Sdfr if(rr->type == rk_ns_t_srv) 63790926Snectar num_srv++; 63890926Snectar 63990926Snectar if(num_srv == 0) 64090926Snectar return; 64190926Snectar 64290926Snectar srvs = malloc(num_srv * sizeof(*srvs)); 64390926Snectar if(srvs == NULL) 64490926Snectar return; /* XXX not much to do here */ 645233294Sstas 64690926Snectar /* unlink all srv-records from the linked list and put them in 64790926Snectar a vector */ 64890926Snectar for(ss = srvs, headp = &r->head; *headp; ) 649178825Sdfr if((*headp)->type == rk_ns_t_srv) { 65090926Snectar *ss = *headp; 65190926Snectar *headp = (*headp)->next; 65290926Snectar (*ss)->next = NULL; 65390926Snectar ss++; 65490926Snectar } else 65590926Snectar headp = &(*headp)->next; 656233294Sstas 65790926Snectar /* sort them by priority and weight */ 65890926Snectar qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 65990926Snectar 660233294Sstas headp = &r->head; 66190926Snectar 66290926Snectar for(ss = srvs; ss < srvs + num_srv; ) { 66390926Snectar int sum, rnd, count; 664233294Sstas struct rk_resource_record **ee, **tt; 66590926Snectar /* find the last record with the same priority and count the 66690926Snectar sum of all weights */ 66790926Snectar for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 668178825Sdfr assert(*tt != NULL); 66990926Snectar if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 67090926Snectar break; 67190926Snectar sum += (*tt)->u.srv->weight; 67290926Snectar } 67390926Snectar ee = tt; 67490926Snectar /* ss is now the first record of this priority and ee is the 67590926Snectar first of the next */ 67690926Snectar while(ss < ee) { 677233294Sstas rnd = rk_random() % (sum + 1); 67890926Snectar for(count = 0, tt = ss; ; tt++) { 67990926Snectar if(*tt == NULL) 68090926Snectar continue; 68190926Snectar count += (*tt)->u.srv->weight; 68290926Snectar if(count >= rnd) 68390926Snectar break; 68490926Snectar } 68590926Snectar 68690926Snectar assert(tt < ee); 68790926Snectar 68890926Snectar /* insert the selected record at the tail (of the head) of 68990926Snectar the list */ 69090926Snectar (*tt)->next = *headp; 69190926Snectar *headp = *tt; 69290926Snectar headp = &(*tt)->next; 69390926Snectar sum -= (*tt)->u.srv->weight; 69490926Snectar *tt = NULL; 69590926Snectar while(ss < ee && *ss == NULL) 69690926Snectar ss++; 69790926Snectar } 69890926Snectar } 699233294Sstas 70090926Snectar free(srvs); 70190926Snectar return; 70290926Snectar} 70390926Snectar 704233294Sstas#ifdef HAVE_WINDNS 705233294Sstas 706233294Sstas#include <WinDNS.h> 707233294Sstas 708233294Sstasstatic struct rk_resource_record * 709233294Sstasparse_dns_record(PDNS_RECORD pRec) 710233294Sstas{ 711233294Sstas struct rk_resource_record * rr; 712233294Sstas 713233294Sstas if (pRec == NULL) 714233294Sstas return NULL; 715233294Sstas 716233294Sstas rr = calloc(1, sizeof(*rr)); 717233294Sstas 718233294Sstas rr->domain = strdup(pRec->pName); 719233294Sstas rr->type = pRec->wType; 720233294Sstas rr->class = 0; 721233294Sstas rr->ttl = pRec->dwTtl; 722233294Sstas rr->size = 0; 723233294Sstas 724233294Sstas switch (rr->type) { 725233294Sstas case rk_ns_t_ns: 726233294Sstas case rk_ns_t_cname: 727233294Sstas case rk_ns_t_ptr: 728233294Sstas rr->u.txt = strdup(pRec->Data.NS.pNameHost); 729233294Sstas if(rr->u.txt == NULL) { 730233294Sstas dns_free_rr(rr); 731233294Sstas return NULL; 732233294Sstas } 733233294Sstas break; 734233294Sstas 735233294Sstas case rk_ns_t_mx: 736233294Sstas case rk_ns_t_afsdb:{ 737233294Sstas size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH); 738233294Sstas 739233294Sstas rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) + 740233294Sstas hostlen); 741233294Sstas if (rr->u.mx == NULL) { 742233294Sstas dns_free_rr(rr); 743233294Sstas return NULL; 744233294Sstas } 745233294Sstas 746233294Sstas strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange); 747233294Sstas rr->u.mx->preference = pRec->Data.MX.wPreference; 748233294Sstas break; 749233294Sstas } 750233294Sstas 751233294Sstas case rk_ns_t_srv:{ 752233294Sstas size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH); 753233294Sstas 754233294Sstas rr->u.srv = 755233294Sstas (struct srv_record*)malloc(sizeof(struct srv_record) + 756233294Sstas hostlen); 757233294Sstas if(rr->u.srv == NULL) { 758233294Sstas dns_free_rr(rr); 759233294Sstas return NULL; 760233294Sstas } 761233294Sstas 762233294Sstas rr->u.srv->priority = pRec->Data.SRV.wPriority; 763233294Sstas rr->u.srv->weight = pRec->Data.SRV.wWeight; 764233294Sstas rr->u.srv->port = pRec->Data.SRV.wPort; 765233294Sstas strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget); 766233294Sstas 767233294Sstas break; 768233294Sstas } 769233294Sstas 770233294Sstas case rk_ns_t_txt:{ 771233294Sstas size_t len; 772233294Sstas 773233294Sstas if (pRec->Data.TXT.dwStringCount == 0) { 774233294Sstas rr->u.txt = strdup(""); 775233294Sstas break; 776233294Sstas } 777233294Sstas 778233294Sstas len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH); 779233294Sstas 780233294Sstas rr->u.txt = (char *)malloc(len + 1); 781233294Sstas strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]); 782233294Sstas 783233294Sstas break; 784233294Sstas } 785233294Sstas 786233294Sstas case rk_ns_t_key : { 787233294Sstas size_t key_len; 788233294Sstas 789233294Sstas if (pRec->wDataLength < 4) { 790233294Sstas dns_free_rr(rr); 791233294Sstas return NULL; 792233294Sstas } 793233294Sstas 794233294Sstas key_len = pRec->wDataLength - 4; 795233294Sstas rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 796233294Sstas if (rr->u.key == NULL) { 797233294Sstas dns_free_rr(rr); 798233294Sstas return NULL; 799233294Sstas } 800233294Sstas 801233294Sstas rr->u.key->flags = pRec->Data.KEY.wFlags; 802233294Sstas rr->u.key->protocol = pRec->Data.KEY.chProtocol; 803233294Sstas rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm; 804233294Sstas rr->u.key->key_len = key_len; 805233294Sstas memcpy_s (rr->u.key->key_data, key_len, 806233294Sstas pRec->Data.KEY.Key, key_len); 807233294Sstas break; 808233294Sstas } 809233294Sstas 810233294Sstas case rk_ns_t_sig : { 811233294Sstas size_t sig_len, hostlen; 812233294Sstas 813233294Sstas if(pRec->wDataLength <= 18) { 814233294Sstas dns_free_rr(rr); 815233294Sstas return NULL; 816233294Sstas } 817233294Sstas 818233294Sstas sig_len = pRec->wDataLength; 819233294Sstas 820233294Sstas hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH); 821233294Sstas 822233294Sstas rr->u.sig = malloc(sizeof(*rr->u.sig) 823233294Sstas + hostlen + sig_len); 824233294Sstas if (rr->u.sig == NULL) { 825233294Sstas dns_free_rr(rr); 826233294Sstas return NULL; 827233294Sstas } 828233294Sstas rr->u.sig->type = pRec->Data.SIG.wTypeCovered; 829233294Sstas rr->u.sig->algorithm = pRec->Data.SIG.chAlgorithm; 830233294Sstas rr->u.sig->labels = pRec->Data.SIG.chLabelCount; 831233294Sstas rr->u.sig->orig_ttl = pRec->Data.SIG.dwOriginalTtl; 832233294Sstas rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration; 833233294Sstas rr->u.sig->sig_inception = pRec->Data.SIG.dwTimeSigned; 834233294Sstas rr->u.sig->key_tag = pRec->Data.SIG.wKeyTag; 835233294Sstas rr->u.sig->sig_len = sig_len; 836233294Sstas memcpy_s (rr->u.sig->sig_data, sig_len, 837233294Sstas pRec->Data.SIG.Signature, sig_len); 838233294Sstas rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 839233294Sstas strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner); 840233294Sstas break; 841233294Sstas } 842233294Sstas 843233294Sstas#ifdef DNS_TYPE_DS 844233294Sstas case rk_ns_t_ds: { 845233294Sstas rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1); 846233294Sstas if (rr->u.ds == NULL) { 847233294Sstas dns_free_rr(rr); 848233294Sstas return NULL; 849233294Sstas } 850233294Sstas 851233294Sstas rr->u.ds->key_tag = pRec->Data.DS.wKeyTag; 852233294Sstas rr->u.ds->algorithm = pRec->Data.DS.chAlgorithm; 853233294Sstas rr->u.ds->digest_type = pRec->Data.DS.chDigestType; 854233294Sstas rr->u.ds->digest_len = pRec->Data.DS.wDigestLength; 855233294Sstas memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength, 856233294Sstas pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength); 857233294Sstas break; 858233294Sstas } 859233294Sstas#endif 860233294Sstas 861233294Sstas default: 862233294Sstas dns_free_rr(rr); 863233294Sstas return NULL; 864233294Sstas } 865233294Sstas 866233294Sstas rr->next = parse_dns_record(pRec->pNext); 867233294Sstas return rr; 868233294Sstas} 869233294Sstas 870233294SstasROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 871233294Sstasrk_dns_lookup(const char *domain, const char *type_name) 872233294Sstas{ 873233294Sstas DNS_STATUS status; 874233294Sstas int type; 875233294Sstas PDNS_RECORD pRec = NULL; 876233294Sstas struct rk_dns_reply * r = NULL; 877233294Sstas 878233294Sstas __try { 879233294Sstas 880233294Sstas type = rk_dns_string_to_type(type_name); 881233294Sstas if(type == -1) { 882233294Sstas if(_resolve_debug) 883233294Sstas fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 884233294Sstas type_name); 885233294Sstas return NULL; 886233294Sstas } 887233294Sstas 888233294Sstas status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL, 889233294Sstas &pRec, NULL); 890233294Sstas if (status != ERROR_SUCCESS) 891233294Sstas return NULL; 892233294Sstas 893233294Sstas r = calloc(1, sizeof(*r)); 894233294Sstas r->q.domain = strdup(domain); 895233294Sstas r->q.type = type; 896233294Sstas r->q.class = 0; 897233294Sstas 898233294Sstas r->head = parse_dns_record(pRec); 899233294Sstas 900233294Sstas if (r->head == NULL) { 901233294Sstas rk_dns_free_data(r); 902233294Sstas return NULL; 903233294Sstas } else { 904233294Sstas return r; 905233294Sstas } 906233294Sstas 907233294Sstas } __finally { 908233294Sstas 909233294Sstas if (pRec) 910233294Sstas DnsRecordListFree(pRec, DnsFreeRecordList); 911233294Sstas 912233294Sstas } 913233294Sstas} 914233294Sstas#endif /* HAVE_WINDNS */ 915233294Sstas 91655682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 91755682Smarkm 918233294SstasROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 919233294Sstasrk_dns_lookup(const char *domain, const char *type_name) 92055682Smarkm{ 92155682Smarkm return NULL; 92255682Smarkm} 92355682Smarkm 924233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 925233294Sstasrk_dns_free_data(struct rk_dns_reply *r) 92655682Smarkm{ 92755682Smarkm} 92855682Smarkm 929233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 930233294Sstasrk_dns_srv_order(struct rk_dns_reply *r) 93190926Snectar{ 93290926Snectar} 93390926Snectar 93455682Smarkm#endif 935