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