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 59 static 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 81 int _resolve_debug = 0; 82 83 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 84 rk_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 93 ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL 94 rk_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 105 static void 106 dns_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 115 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 116 rk_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 131 static int 132 parse_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 407 static 408 #endif 409 struct rk_dns_reply* 410 parse_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 523 static struct rk_dns_reply * 524 dns_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 free(reply); 594 return r; 595 } 596 597 ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 598 rk_dns_lookup(const char *domain, const char *type_name) 599 { 600 int type; 601 602 type = rk_dns_string_to_type(type_name); 603 if(type == -1) { 604 if(_resolve_debug) 605 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 606 type_name); 607 return NULL; 608 } 609 return dns_lookup_int(domain, rk_ns_c_in, type); 610 } 611 612 #endif /* !HAVE_WINDNS */ 613 614 static int 615 compare_srv(const void *a, const void *b) 616 { 617 const struct rk_resource_record *const* aa = a, *const* bb = b; 618 619 if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 620 return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 621 return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 622 } 623 624 /* try to rearrange the srv-records by the algorithm in RFC2782 */ 625 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 626 rk_dns_srv_order(struct rk_dns_reply *r) 627 { 628 struct rk_resource_record **srvs, **ss, **headp; 629 struct rk_resource_record *rr; 630 int num_srv = 0; 631 632 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 633 int state[256 / sizeof(int)]; 634 char *oldstate; 635 #endif 636 637 rk_random_init(); 638 639 for(rr = r->head; rr; rr = rr->next) 640 if(rr->type == rk_ns_t_srv) 641 num_srv++; 642 643 if(num_srv == 0) 644 return; 645 646 srvs = malloc(num_srv * sizeof(*srvs)); 647 if(srvs == NULL) 648 return; /* XXX not much to do here */ 649 650 /* unlink all srv-records from the linked list and put them in 651 a vector */ 652 for(ss = srvs, headp = &r->head; *headp; ) 653 if((*headp)->type == rk_ns_t_srv) { 654 *ss = *headp; 655 *headp = (*headp)->next; 656 (*ss)->next = NULL; 657 ss++; 658 } else 659 headp = &(*headp)->next; 660 661 /* sort them by priority and weight */ 662 qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 663 664 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 665 oldstate = initstate(time(NULL), (char*)state, sizeof(state)); 666 #endif 667 668 headp = &r->head; 669 670 for(ss = srvs; ss < srvs + num_srv; ) { 671 int sum, rnd, count; 672 struct rk_resource_record **ee, **tt; 673 /* find the last record with the same priority and count the 674 sum of all weights */ 675 for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 676 assert(*tt != NULL); 677 if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 678 break; 679 sum += (*tt)->u.srv->weight; 680 } 681 ee = tt; 682 /* ss is now the first record of this priority and ee is the 683 first of the next */ 684 while(ss < ee) { 685 rnd = rk_random() % (sum + 1); 686 for(count = 0, tt = ss; ; tt++) { 687 if(*tt == NULL) 688 continue; 689 count += (*tt)->u.srv->weight; 690 if(count >= rnd) 691 break; 692 } 693 694 assert(tt < ee); 695 696 /* insert the selected record at the tail (of the head) of 697 the list */ 698 (*tt)->next = *headp; 699 *headp = *tt; 700 headp = &(*tt)->next; 701 sum -= (*tt)->u.srv->weight; 702 *tt = NULL; 703 while(ss < ee && *ss == NULL) 704 ss++; 705 } 706 } 707 708 #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 709 setstate(oldstate); 710 #endif 711 free(srvs); 712 return; 713 } 714 715 #ifdef HAVE_WINDNS 716 717 #include <WinDNS.h> 718 719 static struct rk_resource_record * 720 parse_dns_record(PDNS_RECORD pRec) 721 { 722 struct rk_resource_record * rr; 723 724 if (pRec == NULL) 725 return NULL; 726 727 rr = calloc(1, sizeof(*rr)); 728 729 rr->domain = strdup(pRec->pName); 730 rr->type = pRec->wType; 731 rr->class = 0; 732 rr->ttl = pRec->dwTtl; 733 rr->size = 0; 734 735 switch (rr->type) { 736 case rk_ns_t_ns: 737 case rk_ns_t_cname: 738 case rk_ns_t_ptr: 739 rr->u.txt = strdup(pRec->Data.NS.pNameHost); 740 if(rr->u.txt == NULL) { 741 dns_free_rr(rr); 742 return NULL; 743 } 744 break; 745 746 case rk_ns_t_mx: 747 case rk_ns_t_afsdb:{ 748 size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH); 749 750 rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) + 751 hostlen); 752 if (rr->u.mx == NULL) { 753 dns_free_rr(rr); 754 return NULL; 755 } 756 757 strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange); 758 rr->u.mx->preference = pRec->Data.MX.wPreference; 759 break; 760 } 761 762 case rk_ns_t_srv:{ 763 size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH); 764 765 rr->u.srv = 766 (struct srv_record*)malloc(sizeof(struct srv_record) + 767 hostlen); 768 if(rr->u.srv == NULL) { 769 dns_free_rr(rr); 770 return NULL; 771 } 772 773 rr->u.srv->priority = pRec->Data.SRV.wPriority; 774 rr->u.srv->weight = pRec->Data.SRV.wWeight; 775 rr->u.srv->port = pRec->Data.SRV.wPort; 776 strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget); 777 778 break; 779 } 780 781 case rk_ns_t_txt:{ 782 size_t len; 783 784 if (pRec->Data.TXT.dwStringCount == 0) { 785 rr->u.txt = strdup(""); 786 break; 787 } 788 789 len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH); 790 791 rr->u.txt = (char *)malloc(len + 1); 792 strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]); 793 794 break; 795 } 796 797 case rk_ns_t_key : { 798 size_t key_len; 799 800 if (pRec->wDataLength < 4) { 801 dns_free_rr(rr); 802 return NULL; 803 } 804 805 key_len = pRec->wDataLength - 4; 806 rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1); 807 if (rr->u.key == NULL) { 808 dns_free_rr(rr); 809 return NULL; 810 } 811 812 rr->u.key->flags = pRec->Data.KEY.wFlags; 813 rr->u.key->protocol = pRec->Data.KEY.chProtocol; 814 rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm; 815 rr->u.key->key_len = key_len; 816 memcpy_s (rr->u.key->key_data, key_len, 817 pRec->Data.KEY.Key, key_len); 818 break; 819 } 820 821 case rk_ns_t_sig : { 822 size_t sig_len, hostlen; 823 824 if(pRec->wDataLength <= 18) { 825 dns_free_rr(rr); 826 return NULL; 827 } 828 829 sig_len = pRec->wDataLength; 830 831 hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH); 832 833 rr->u.sig = malloc(sizeof(*rr->u.sig) 834 + hostlen + sig_len); 835 if (rr->u.sig == NULL) { 836 dns_free_rr(rr); 837 return NULL; 838 } 839 rr->u.sig->type = pRec->Data.SIG.wTypeCovered; 840 rr->u.sig->algorithm = pRec->Data.SIG.chAlgorithm; 841 rr->u.sig->labels = pRec->Data.SIG.chLabelCount; 842 rr->u.sig->orig_ttl = pRec->Data.SIG.dwOriginalTtl; 843 rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration; 844 rr->u.sig->sig_inception = pRec->Data.SIG.dwTimeSigned; 845 rr->u.sig->key_tag = pRec->Data.SIG.wKeyTag; 846 rr->u.sig->sig_len = sig_len; 847 memcpy_s (rr->u.sig->sig_data, sig_len, 848 pRec->Data.SIG.Signature, sig_len); 849 rr->u.sig->signer = &rr->u.sig->sig_data[sig_len]; 850 strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner); 851 break; 852 } 853 854 #ifdef DNS_TYPE_DS 855 case rk_ns_t_ds: { 856 rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1); 857 if (rr->u.ds == NULL) { 858 dns_free_rr(rr); 859 return NULL; 860 } 861 862 rr->u.ds->key_tag = pRec->Data.DS.wKeyTag; 863 rr->u.ds->algorithm = pRec->Data.DS.chAlgorithm; 864 rr->u.ds->digest_type = pRec->Data.DS.chDigestType; 865 rr->u.ds->digest_len = pRec->Data.DS.wDigestLength; 866 memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength, 867 pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength); 868 break; 869 } 870 #endif 871 872 default: 873 dns_free_rr(rr); 874 return NULL; 875 } 876 877 rr->next = parse_dns_record(pRec->pNext); 878 return rr; 879 } 880 881 ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 882 rk_dns_lookup(const char *domain, const char *type_name) 883 { 884 DNS_STATUS status; 885 int type; 886 PDNS_RECORD pRec = NULL; 887 struct rk_dns_reply * r = NULL; 888 889 __try { 890 891 type = rk_dns_string_to_type(type_name); 892 if(type == -1) { 893 if(_resolve_debug) 894 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 895 type_name); 896 return NULL; 897 } 898 899 status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL, 900 &pRec, NULL); 901 if (status != ERROR_SUCCESS) 902 return NULL; 903 904 r = calloc(1, sizeof(*r)); 905 r->q.domain = strdup(domain); 906 r->q.type = type; 907 r->q.class = 0; 908 909 r->head = parse_dns_record(pRec); 910 911 if (r->head == NULL) { 912 rk_dns_free_data(r); 913 return NULL; 914 } else { 915 return r; 916 } 917 918 } __finally { 919 920 if (pRec) 921 DnsRecordListFree(pRec, DnsFreeRecordList); 922 923 } 924 } 925 #endif /* HAVE_WINDNS */ 926 927 #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 928 929 ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL 930 rk_dns_lookup(const char *domain, const char *type_name) 931 { 932 return NULL; 933 } 934 935 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 936 rk_dns_free_data(struct rk_dns_reply *r) 937 { 938 } 939 940 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 941 rk_dns_srv_order(struct rk_dns_reply *r) 942 { 943 } 944 945 #endif 946