1/* $NetBSD: resolve.c,v 1.1.1.1 2011/04/13 18:15:42 elric Exp $ */ 2 3/* 4 * Copyright (c) 1995 - 2006 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 37#include <config.h> 38 39#include <krb5/roken.h> 40#ifdef HAVE_ARPA_NAMESER_H 41#include <arpa/nameser.h> 42#endif 43#ifdef HAVE_RESOLV_H 44#include <resolv.h> 45#endif 46#ifdef HAVE_DNS_H 47#include <dns.h> 48#endif 49#include <krb5/resolve.h> 50 51#include <assert.h> 52 53#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */ 54#undef HAVE_RES_NSEARCH 55#endif 56 57#define DECL(X) {#X, rk_ns_t_##X} 58 59static struct stot{ 60 const char *name; 61 int type; 62}stot[] = { 63 DECL(a), 64 DECL(aaaa), 65 DECL(ns), 66 DECL(cname), 67 DECL(soa), 68 DECL(ptr), 69 DECL(mx), 70 DECL(txt), 71 DECL(afsdb), 72 DECL(sig), 73 DECL(key), 74 DECL(srv), 75 DECL(naptr), 76 DECL(sshfp), 77 DECL(ds), 78 {NULL, 0} 79}; 80 81int _resolve_debug = 0; 82 83ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 84rk_dns_string_to_type(const char *name) 85{ 86 struct stot *p = stot; 87 for(p = stot; p->name; p++) 88 if(strcasecmp(name, p->name) == 0) 89 return p->type; 90 return -1; 91} 92 93ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL 94rk_dns_type_to_string(int type) 95{ 96 struct stot *p = stot; 97 for(p = stot; p->name; p++) 98 if(type == p->type) 99 return p->name; 100 return NULL; 101} 102 103#if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS) 104 105static void 106dns_free_rr(struct rk_resource_record *rr) 107{ 108 if(rr->domain) 109 free(rr->domain); 110 if(rr->u.data) 111 free(rr->u.data); 112 free(rr); 113} 114 115ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 116rk_dns_free_data(struct rk_dns_reply *r) 117{ 118 struct rk_resource_record *rr; 119 if(r->q.domain) 120 free(r->q.domain); 121 for(rr = r->head; rr;){ 122 struct rk_resource_record *tmp = rr; 123 rr = rr->next; 124 dns_free_rr(tmp); 125 } 126 free (r); 127} 128 129#ifndef HAVE_WINDNS 130 131static int 132parse_record(const unsigned char *data, const unsigned char *end_data, 133 const unsigned char **pp, struct rk_resource_record **ret_rr) 134{ 135 struct rk_resource_record *rr; 136 int type, class, ttl; 137 unsigned size; 138 int status; 139 char host[MAXDNAME]; 140 const unsigned char *p = *pp; 141 142 *ret_rr = NULL; 143 144 status = dn_expand(data, end_data, p, host, sizeof(host)); 145 if(status < 0) 146 return -1; 147 if (p + status + 10 > end_data) 148 return -1; 149 150 p += status; 151 type = (p[0] << 8) | p[1]; 152 p += 2; 153 class = (p[0] << 8) | p[1]; 154 p += 2; 155 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 156 p += 4; 157 size = (p[0] << 8) | p[1]; 158 p += 2; 159 160 if (p + size > end_data) 161 return -1; 162 163 rr = calloc(1, sizeof(*rr)); 164 if(rr == NULL) 165 return -1; 166 rr->domain = strdup(host); 167 if(rr->domain == NULL) { 168 dns_free_rr(rr); 169 return -1; 170 } 171 rr->type = type; 172 rr->class = class; 173 rr->ttl = ttl; 174 rr->size = size; 175 switch(type){ 176 case rk_ns_t_ns: 177 case rk_ns_t_cname: 178 case rk_ns_t_ptr: 179 status = dn_expand(data, end_data, p, host, sizeof(host)); 180 if(status < 0) { 181 dns_free_rr(rr); 182 return -1; 183 } 184 rr->u.txt = strdup(host); 185 if(rr->u.txt == NULL) { 186 dns_free_rr(rr); 187 return -1; 188 } 189 break; 190 case rk_ns_t_mx: 191 case rk_ns_t_afsdb:{ 192 size_t hostlen; 193 194 status = dn_expand(data, end_data, p + 2, host, sizeof(host)); 195 if(status < 0){ 196 dns_free_rr(rr); 197 return -1; 198 } 199 if (status + 2 > size) { 200 dns_free_rr(rr); 201 return -1; 202 } 203 204 hostlen = strlen(host); 205 rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 206 hostlen); 207 if(rr->u.mx == NULL) { 208 dns_free_rr(rr); 209 return -1; 210 } 211 rr->u.mx->preference = (p[0] << 8) | p[1]; 212 strlcpy(rr->u.mx->domain, host, hostlen + 1); 213 break; 214 } 215 case rk_ns_t_srv:{ 216 size_t hostlen; 217 status = dn_expand(data, end_data, p + 6, host, sizeof(host)); 218 if(status < 0){ 219 dns_free_rr(rr); 220 return -1; 221 } 222 if (status + 6 > size) { 223 dns_free_rr(rr); 224 return -1; 225 } 226 227 hostlen = strlen(host); 228 rr->u.srv = 229 (struct srv_record*)malloc(sizeof(struct srv_record) + 230 hostlen); 231 if(rr->u.srv == NULL) { 232 dns_free_rr(rr); 233 return -1; 234 } 235 rr->u.srv->priority = (p[0] << 8) | p[1]; 236 rr->u.srv->weight = (p[2] << 8) | p[3]; 237 rr->u.srv->port = (p[4] << 8) | p[5]; 238 strlcpy(rr->u.srv->target, host, hostlen + 1); 239 break; 240 } 241 case rk_ns_t_txt:{ 242 if(size == 0 || size < *p + 1) { 243 dns_free_rr(rr); 244 return -1; 245 } 246 rr->u.txt = (char*)malloc(*p + 1); 247 if(rr->u.txt == NULL) { 248 dns_free_rr(rr); 249 return -1; 250 } 251 strncpy(rr->u.txt, (const char*)(p + 1), *p); 252 rr->u.txt[*p] = '\0'; 253 break; 254 } 255 case rk_ns_t_key : { 256 size_t key_len; 257 258 if (size < 4) { 259 dns_free_rr(rr); 260 return -1; 261 } 262 263 key_len = size - 4; 264 rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 265 if (rr->u.key == NULL) { 266 dns_free_rr(rr); 267 return -1; 268 } 269 270 rr->u.key->flags = (p[0] << 8) | p[1]; 271 rr->u.key->protocol = p[2]; 272 rr->u.key->algorithm = p[3]; 273 rr->u.key->key_len = key_len; 274 memcpy (rr->u.key->key_data, p + 4, key_len); 275 break; 276 } 277 case rk_ns_t_sig : { 278 size_t sig_len, hostlen; 279 280 if(size <= 18) { 281 dns_free_rr(rr); 282 return -1; 283 } 284 status = dn_expand (data, end_data, p + 18, host, sizeof(host)); 285 if (status < 0) { 286 dns_free_rr(rr); 287 return -1; 288 } 289 if (status + 18 > size) { 290 dns_free_rr(rr); 291 return -1; 292 } 293 294 /* the signer name is placed after the sig_data, to make it 295 easy to free this structure; the size calculation below 296 includes the zero-termination if the structure itself. 297 don't you just love C? 298 */ 299 sig_len = size - 18 - status; 300 hostlen = strlen(host); 301 rr->u.sig = malloc(sizeof(*rr->u.sig) 302 + hostlen + sig_len); 303 if (rr->u.sig == NULL) { 304 dns_free_rr(rr); 305 return -1; 306 } 307 rr->u.sig->type = (p[0] << 8) | p[1]; 308 rr->u.sig->algorithm = p[2]; 309 rr->u.sig->labels = p[3]; 310 rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16) 311 | (p[6] << 8) | p[7]; 312 rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16) 313 | (p[10] << 8) | p[11]; 314 rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16) 315 | (p[14] << 8) | p[15]; 316 rr->u.sig->key_tag = (p[16] << 8) | p[17]; 317 rr->u.sig->sig_len = sig_len; 318 memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len); 319 rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 320 strlcpy(rr->u.sig->signer, host, hostlen + 1); 321 break; 322 } 323 324 case rk_ns_t_cert : { 325 size_t cert_len; 326 327 if (size < 5) { 328 dns_free_rr(rr); 329 return -1; 330 } 331 332 cert_len = size - 5; 333 rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1); 334 if (rr->u.cert == NULL) { 335 dns_free_rr(rr); 336 return -1; 337 } 338 339 rr->u.cert->type = (p[0] << 8) | p[1]; 340 rr->u.cert->tag = (p[2] << 8) | p[3]; 341 rr->u.cert->algorithm = p[4]; 342 rr->u.cert->cert_len = cert_len; 343 memcpy (rr->u.cert->cert_data, p + 5, cert_len); 344 break; 345 } 346 case rk_ns_t_sshfp : { 347 size_t sshfp_len; 348 349 if (size < 2) { 350 dns_free_rr(rr); 351 return -1; 352 } 353 354 sshfp_len = size - 2; 355 356 rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1); 357 if (rr->u.sshfp == NULL) { 358 dns_free_rr(rr); 359 return -1; 360 } 361 362 rr->u.sshfp->algorithm = p[0]; 363 rr->u.sshfp->type = p[1]; 364 rr->u.sshfp->sshfp_len = sshfp_len; 365 memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len); 366 break; 367 } 368 case rk_ns_t_ds: { 369 size_t digest_len; 370 371 if (size < 4) { 372 dns_free_rr(rr); 373 return -1; 374 } 375 376 digest_len = size - 4; 377 378 rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1); 379 if (rr->u.ds == NULL) { 380 dns_free_rr(rr); 381 return -1; 382 } 383 384 rr->u.ds->key_tag = (p[0] << 8) | p[1]; 385 rr->u.ds->algorithm = p[2]; 386 rr->u.ds->digest_type = p[3]; 387 rr->u.ds->digest_len = digest_len; 388 memcpy (rr->u.ds->digest_data, p + 4, digest_len); 389 break; 390 } 391 default: 392 rr->u.data = (unsigned char*)malloc(size); 393 if(size != 0 && rr->u.data == NULL) { 394 dns_free_rr(rr); 395 return -1; 396 } 397 if (size) 398 memcpy(rr->u.data, p, size); 399 } 400 *pp = p + size; 401 *ret_rr = rr; 402 403 return 0; 404} 405 406#ifndef TEST_RESOLVE 407static 408#endif 409struct rk_dns_reply* 410parse_reply(const unsigned char *data, size_t len) 411{ 412 const unsigned char *p; 413 int status; 414 int i; 415 char host[MAXDNAME]; 416 const unsigned char *end_data = data + len; 417 struct rk_dns_reply *r; 418 struct rk_resource_record **rr; 419 420 r = calloc(1, sizeof(*r)); 421 if (r == NULL) 422 return NULL; 423 424 p = data; 425 426 r->h.id = (p[0] << 8) | p[1]; 427 r->h.flags = 0; 428 if (p[2] & 0x01) 429 r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG; 430 r->h.opcode = (p[2] >> 1) & 0xf; 431 if (p[2] & 0x20) 432 r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 433 if (p[2] & 0x40) 434 r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE; 435 if (p[2] & 0x80) 436 r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED; 437 if (p[3] & 0x01) 438 r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE; 439 if (p[3] & 0x04) 440 r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER; 441 if (p[3] & 0x08) 442 r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED; 443 r->h.response_code = (p[3] >> 4) & 0xf; 444 r->h.qdcount = (p[4] << 8) | p[5]; 445 r->h.ancount = (p[6] << 8) | p[7]; 446 r->h.nscount = (p[8] << 8) | p[9]; 447 r->h.arcount = (p[10] << 8) | p[11]; 448 449 p += 12; 450 451 if(r->h.qdcount != 1) { 452 free(r); 453 return NULL; 454 } 455 status = dn_expand(data, end_data, p, host, sizeof(host)); 456 if(status < 0){ 457 rk_dns_free_data(r); 458 return NULL; 459 } 460 r->q.domain = strdup(host); 461 if(r->q.domain == NULL) { 462 rk_dns_free_data(r); 463 return NULL; 464 } 465 if (p + status + 4 > end_data) { 466 rk_dns_free_data(r); 467 return NULL; 468 } 469 p += status; 470 r->q.type = (p[0] << 8 | p[1]); 471 p += 2; 472 r->q.class = (p[0] << 8 | p[1]); 473 p += 2; 474 475 rr = &r->head; 476 for(i = 0; i < r->h.ancount; i++) { 477 if(parse_record(data, end_data, &p, rr) != 0) { 478 rk_dns_free_data(r); 479 return NULL; 480 } 481 rr = &(*rr)->next; 482 } 483 for(i = 0; i < r->h.nscount; i++) { 484 if(parse_record(data, end_data, &p, rr) != 0) { 485 rk_dns_free_data(r); 486 return NULL; 487 } 488 rr = &(*rr)->next; 489 } 490 for(i = 0; i < r->h.arcount; i++) { 491 if(parse_record(data, end_data, &p, rr) != 0) { 492 rk_dns_free_data(r); 493 return NULL; 494 } 495 rr = &(*rr)->next; 496 } 497 *rr = NULL; 498 return r; 499} 500 501#ifdef HAVE_RES_NSEARCH 502#ifdef HAVE_RES_NDESTROY 503#define rk_res_free(x) res_ndestroy(x) 504#else 505#define rk_res_free(x) res_nclose(x) 506#endif 507#endif 508 509#if defined(HAVE_DNS_SEARCH) 510#define resolve_search(h,n,c,t,r,l) \ 511 ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize)) 512#define resolve_free_handle(h) dns_free(h) 513#elif defined(HAVE_RES_NSEARCH) 514#define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l) 515#define resolve_free_handle(h) rk_res_free(h); 516#else 517#define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l) 518#define handle 0 519#define resolve_free_handle(h) 520#endif 521 522 523static struct rk_dns_reply * 524dns_lookup_int(const char *domain, int rr_class, int rr_type) 525{ 526 struct rk_dns_reply *r; 527 void *reply = NULL; 528 int size, len; 529#if defined(HAVE_DNS_SEARCH) 530 struct sockaddr_storage from; 531 uint32_t fromsize = sizeof(from); 532 dns_handle_t handle; 533 534 handle = dns_open(NULL); 535 if (handle == NULL) 536 return NULL; 537#elif defined(HAVE_RES_NSEARCH) 538 struct __res_state state; 539 struct __res_state *handle = &state; 540 541 memset(&state, 0, sizeof(state)); 542 if(res_ninit(handle)) 543 return NULL; /* is this the best we can do? */ 544#endif 545 546 len = 1500; 547 while(1) { 548 if (reply) { 549 free(reply); 550 reply = NULL; 551 } 552 if (_resolve_debug) { 553#if defined(HAVE_DNS_SEARCH) 554 dns_set_debug(handle, 1); 555#elif defined(HAVE_RES_NSEARCH) 556 state.options |= RES_DEBUG; 557#endif 558 fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain, 559 rr_class, rk_dns_type_to_string(rr_type), len); 560 } 561 reply = malloc(len); 562 if (reply == NULL) { 563 resolve_free_handle(handle); 564 return NULL; 565 } 566 567 size = resolve_search(handle, domain, rr_class, rr_type, reply, len); 568 569 if (_resolve_debug) { 570 fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 571 domain, rr_class, rk_dns_type_to_string(rr_type), size); 572 } 573 if (size > len) { 574 /* resolver thinks it know better, go for it */ 575 len = size; 576 } else if (size > 0) { 577 /* got a good reply */ 578 break; 579 } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) { 580 len *= 2; 581 if (len > rk_DNS_MAX_PACKET_SIZE) 582 len = rk_DNS_MAX_PACKET_SIZE; 583 } else { 584 /* the end, leave */ 585 resolve_free_handle(handle); 586 free(reply); 587 return NULL; 588 } 589 } 590 591 len = min(len, size); 592 r = parse_reply(reply, len); 593 resolve_free_handle(handle); 594 free(reply); 595 return r; 596} 597 598ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 599rk_dns_lookup(const char *domain, const char *type_name) 600{ 601 int type; 602 603 type = rk_dns_string_to_type(type_name); 604 if(type == -1) { 605 if(_resolve_debug) 606 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 607 type_name); 608 return NULL; 609 } 610 return dns_lookup_int(domain, rk_ns_c_in, type); 611} 612 613#endif /* !HAVE_WINDNS */ 614 615static int 616compare_srv(const void *a, const void *b) 617{ 618 const struct rk_resource_record *const* aa = a, *const* bb = b; 619 620 if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 621 return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 622 return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 623} 624 625/* try to rearrange the srv-records by the algorithm in RFC2782 */ 626ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 627rk_dns_srv_order(struct rk_dns_reply *r) 628{ 629 struct rk_resource_record **srvs, **ss, **headp; 630 struct rk_resource_record *rr; 631 int num_srv = 0; 632 633#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 634 int state[256 / sizeof(int)]; 635 char *oldstate; 636#endif 637 638 rk_random_init(); 639 640 for(rr = r->head; rr; rr = rr->next) 641 if(rr->type == rk_ns_t_srv) 642 num_srv++; 643 644 if(num_srv == 0) 645 return; 646 647 srvs = malloc(num_srv * sizeof(*srvs)); 648 if(srvs == NULL) 649 return; /* XXX not much to do here */ 650 651 /* unlink all srv-records from the linked list and put them in 652 a vector */ 653 for(ss = srvs, headp = &r->head; *headp; ) 654 if((*headp)->type == rk_ns_t_srv) { 655 *ss = *headp; 656 *headp = (*headp)->next; 657 (*ss)->next = NULL; 658 ss++; 659 } else 660 headp = &(*headp)->next; 661 662 /* sort them by priority and weight */ 663 qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 664 665#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 666 oldstate = initstate(time(NULL), (char*)state, sizeof(state)); 667#endif 668 669 headp = &r->head; 670 671 for(ss = srvs; ss < srvs + num_srv; ) { 672 int sum, rnd, count; 673 struct rk_resource_record **ee, **tt; 674 /* find the last record with the same priority and count the 675 sum of all weights */ 676 for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 677 assert(*tt != NULL); 678 if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 679 break; 680 sum += (*tt)->u.srv->weight; 681 } 682 ee = tt; 683 /* ss is now the first record of this priority and ee is the 684 first of the next */ 685 while(ss < ee) { 686 rnd = rk_random() % (sum + 1); 687 for(count = 0, tt = ss; ; tt++) { 688 if(*tt == NULL) 689 continue; 690 count += (*tt)->u.srv->weight; 691 if(count >= rnd) 692 break; 693 } 694 695 assert(tt < ee); 696 697 /* insert the selected record at the tail (of the head) of 698 the list */ 699 (*tt)->next = *headp; 700 *headp = *tt; 701 headp = &(*tt)->next; 702 sum -= (*tt)->u.srv->weight; 703 *tt = NULL; 704 while(ss < ee && *ss == NULL) 705 ss++; 706 } 707 } 708 709#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 710 setstate(oldstate); 711#endif 712 free(srvs); 713 return; 714} 715 716#ifdef HAVE_WINDNS 717 718#include <WinDNS.h> 719 720static struct rk_resource_record * 721parse_dns_record(PDNS_RECORD pRec) 722{ 723 struct rk_resource_record * rr; 724 725 if (pRec == NULL) 726 return NULL; 727 728 rr = calloc(1, sizeof(*rr)); 729 730 rr->domain = strdup(pRec->pName); 731 rr->type = pRec->wType; 732 rr->class = 0; 733 rr->ttl = pRec->dwTtl; 734 rr->size = 0; 735 736 switch (rr->type) { 737 case rk_ns_t_ns: 738 case rk_ns_t_cname: 739 case rk_ns_t_ptr: 740 rr->u.txt = strdup(pRec->Data.NS.pNameHost); 741 if(rr->u.txt == NULL) { 742 dns_free_rr(rr); 743 return NULL; 744 } 745 break; 746 747 case rk_ns_t_mx: 748 case rk_ns_t_afsdb:{ 749 size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH); 750 751 rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) + 752 hostlen); 753 if (rr->u.mx == NULL) { 754 dns_free_rr(rr); 755 return NULL; 756 } 757 758 strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange); 759 rr->u.mx->preference = pRec->Data.MX.wPreference; 760 break; 761 } 762 763 case rk_ns_t_srv:{ 764 size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH); 765 766 rr->u.srv = 767 (struct srv_record*)malloc(sizeof(struct srv_record) + 768 hostlen); 769 if(rr->u.srv == NULL) { 770 dns_free_rr(rr); 771 return NULL; 772 } 773 774 rr->u.srv->priority = pRec->Data.SRV.wPriority; 775 rr->u.srv->weight = pRec->Data.SRV.wWeight; 776 rr->u.srv->port = pRec->Data.SRV.wPort; 777 strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget); 778 779 break; 780 } 781 782 case rk_ns_t_txt:{ 783 size_t len; 784 785 if (pRec->Data.TXT.dwStringCount == 0) { 786 rr->u.txt = strdup(""); 787 break; 788 } 789 790 len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH); 791 792 rr->u.txt = (char *)malloc(len + 1); 793 strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]); 794 795 break; 796 } 797 798 case rk_ns_t_key : { 799 size_t key_len; 800 801 if (pRec->wDataLength < 4) { 802 dns_free_rr(rr); 803 return NULL; 804 } 805 806 key_len = pRec->wDataLength - 4; 807 rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 808 if (rr->u.key == NULL) { 809 dns_free_rr(rr); 810 return NULL; 811 } 812 813 rr->u.key->flags = pRec->Data.KEY.wFlags; 814 rr->u.key->protocol = pRec->Data.KEY.chProtocol; 815 rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm; 816 rr->u.key->key_len = key_len; 817 memcpy_s (rr->u.key->key_data, key_len, 818 pRec->Data.KEY.Key, key_len); 819 break; 820 } 821 822 case rk_ns_t_sig : { 823 size_t sig_len, hostlen; 824 825 if(pRec->wDataLength <= 18) { 826 dns_free_rr(rr); 827 return NULL; 828 } 829 830 sig_len = pRec->wDataLength; 831 832 hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH); 833 834 rr->u.sig = malloc(sizeof(*rr->u.sig) 835 + hostlen + sig_len); 836 if (rr->u.sig == NULL) { 837 dns_free_rr(rr); 838 return NULL; 839 } 840 rr->u.sig->type = pRec->Data.SIG.wTypeCovered; 841 rr->u.sig->algorithm = pRec->Data.SIG.chAlgorithm; 842 rr->u.sig->labels = pRec->Data.SIG.chLabelCount; 843 rr->u.sig->orig_ttl = pRec->Data.SIG.dwOriginalTtl; 844 rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration; 845 rr->u.sig->sig_inception = pRec->Data.SIG.dwTimeSigned; 846 rr->u.sig->key_tag = pRec->Data.SIG.wKeyTag; 847 rr->u.sig->sig_len = sig_len; 848 memcpy_s (rr->u.sig->sig_data, sig_len, 849 pRec->Data.SIG.Signature, sig_len); 850 rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 851 strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner); 852 break; 853 } 854 855#ifdef DNS_TYPE_DS 856 case rk_ns_t_ds: { 857 rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1); 858 if (rr->u.ds == NULL) { 859 dns_free_rr(rr); 860 return NULL; 861 } 862 863 rr->u.ds->key_tag = pRec->Data.DS.wKeyTag; 864 rr->u.ds->algorithm = pRec->Data.DS.chAlgorithm; 865 rr->u.ds->digest_type = pRec->Data.DS.chDigestType; 866 rr->u.ds->digest_len = pRec->Data.DS.wDigestLength; 867 memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength, 868 pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength); 869 break; 870 } 871#endif 872 873 default: 874 dns_free_rr(rr); 875 return NULL; 876 } 877 878 rr->next = parse_dns_record(pRec->pNext); 879 return rr; 880} 881 882ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 883rk_dns_lookup(const char *domain, const char *type_name) 884{ 885 DNS_STATUS status; 886 int type; 887 PDNS_RECORD pRec = NULL; 888 struct rk_dns_reply * r = NULL; 889 890 __try { 891 892 type = rk_dns_string_to_type(type_name); 893 if(type == -1) { 894 if(_resolve_debug) 895 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 896 type_name); 897 return NULL; 898 } 899 900 status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL, 901 &pRec, NULL); 902 if (status != ERROR_SUCCESS) 903 return NULL; 904 905 r = calloc(1, sizeof(*r)); 906 r->q.domain = strdup(domain); 907 r->q.type = type; 908 r->q.class = 0; 909 910 r->head = parse_dns_record(pRec); 911 912 if (r->head == NULL) { 913 rk_dns_free_data(r); 914 return NULL; 915 } else { 916 return r; 917 } 918 919 } __finally { 920 921 if (pRec) 922 DnsRecordListFree(pRec, DnsFreeRecordList); 923 924 } 925} 926#endif /* HAVE_WINDNS */ 927 928#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 929 930ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 931rk_dns_lookup(const char *domain, const char *type_name) 932{ 933 return NULL; 934} 935 936ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 937rk_dns_free_data(struct rk_dns_reply *r) 938{ 939} 940 941ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 942rk_dns_srv_order(struct rk_dns_reply *r) 943{ 944} 945 946#endif 947