1 /* $OpenBSD: getrrsetbyname.c,v 1.11 2007/10/11 18:36:41 jakob Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Jakob Schlyter. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Portions Copyright (c) 1999-2001 Internet Software Consortium. 31 * 32 * Permission to use, copy, modify, and distribute this software for any 33 * purpose with or without fee is hereby granted, provided that the above 34 * copyright notice and this permission notice appear in all copies. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 37 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 39 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 40 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 41 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 42 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 43 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44 */ 45 46 /* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */ 47 48 #include "includes.h" 49 50 #if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) 51 52 #include <stdlib.h> 53 #include <string.h> 54 55 #include <netinet/in.h> 56 #include <arpa/inet.h> 57 58 #include "getrrsetbyname.h" 59 60 #if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO 61 extern int h_errno; 62 #endif 63 64 /* We don't need multithread support here */ 65 #ifdef _THREAD_PRIVATE 66 # undef _THREAD_PRIVATE 67 #endif 68 #define _THREAD_PRIVATE(a,b,c) (c) 69 70 #ifndef HAVE__RES_EXTERN 71 struct __res_state _res; 72 #endif 73 74 /* Necessary functions and macros */ 75 76 /* 77 * Inline versions of get/put short/long. Pointer is advanced. 78 * 79 * These macros demonstrate the property of C whereby it can be 80 * portable or it can be elegant but rarely both. 81 */ 82 83 #ifndef INT32SZ 84 # define INT32SZ 4 85 #endif 86 #ifndef INT16SZ 87 # define INT16SZ 2 88 #endif 89 90 #ifndef GETSHORT 91 #define GETSHORT(s, cp) { \ 92 u_char *t_cp = (u_char *)(cp); \ 93 (s) = ((u_int16_t)t_cp[0] << 8) \ 94 | ((u_int16_t)t_cp[1]) \ 95 ; \ 96 (cp) += INT16SZ; \ 97 } 98 #endif 99 100 #ifndef GETLONG 101 #define GETLONG(l, cp) { \ 102 u_char *t_cp = (u_char *)(cp); \ 103 (l) = ((u_int32_t)t_cp[0] << 24) \ 104 | ((u_int32_t)t_cp[1] << 16) \ 105 | ((u_int32_t)t_cp[2] << 8) \ 106 | ((u_int32_t)t_cp[3]) \ 107 ; \ 108 (cp) += INT32SZ; \ 109 } 110 #endif 111 112 /* 113 * If the system doesn't have _getshort/_getlong or that are not exactly what 114 * we need then use local replacements, avoiding name collisions. 115 */ 116 #if !defined(HAVE__GETSHORT) || !defined(HAVE__GETLONG) || \ 117 !defined(HAVE_DECL__GETSHORT) || HAVE_DECL__GETSHORT == 0 || \ 118 !defined(HAVE_DECL__GETLONG) || HAVE_DECL__GETLONG == 0 119 # ifdef _getshort 120 # undef _getshort 121 # endif 122 # ifdef _getlong 123 # undef _getlong 124 # endif 125 # define _getshort(x) (_ssh_compat_getshort(x)) 126 # define _getlong(x) (_ssh_compat_getlong(x)) 127 /* 128 * Routines to insert/extract short/long's. 129 */ 130 static u_int16_t 131 _getshort(const u_char *msgp) 132 { 133 u_int16_t u; 134 135 GETSHORT(u, msgp); 136 return (u); 137 } 138 139 static u_int32_t 140 _getlong(const u_char *msgp) 141 { 142 u_int32_t u; 143 144 GETLONG(u, msgp); 145 return (u); 146 } 147 #endif /* missing _getshort/_getlong */ 148 149 /* ************** */ 150 151 #define ANSWER_BUFFER_SIZE 0xffff 152 153 struct dns_query { 154 char *name; 155 u_int16_t type; 156 u_int16_t class; 157 struct dns_query *next; 158 }; 159 160 struct dns_rr { 161 char *name; 162 u_int16_t type; 163 u_int16_t class; 164 u_int16_t ttl; 165 u_int16_t size; 166 void *rdata; 167 struct dns_rr *next; 168 }; 169 170 struct dns_response { 171 HEADER header; 172 struct dns_query *query; 173 struct dns_rr *answer; 174 struct dns_rr *authority; 175 struct dns_rr *additional; 176 }; 177 178 static struct dns_response *parse_dns_response(const u_char *, int); 179 static struct dns_query *parse_dns_qsection(const u_char *, int, 180 const u_char **, int); 181 static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, 182 int); 183 184 static void free_dns_query(struct dns_query *); 185 static void free_dns_rr(struct dns_rr *); 186 static void free_dns_response(struct dns_response *); 187 188 static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); 189 190 int 191 getrrsetbyname(const char *hostname, unsigned int rdclass, 192 unsigned int rdtype, unsigned int flags, 193 struct rrsetinfo **res) 194 { 195 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res); 196 int result; 197 struct rrsetinfo *rrset = NULL; 198 struct dns_response *response = NULL; 199 struct dns_rr *rr; 200 struct rdatainfo *rdata; 201 int length; 202 unsigned int index_ans, index_sig; 203 u_char answer[ANSWER_BUFFER_SIZE]; 204 205 /* check for invalid class and type */ 206 if (rdclass > 0xffff || rdtype > 0xffff) { 207 result = ERRSET_INVAL; 208 goto fail; 209 } 210 211 /* don't allow queries of class or type ANY */ 212 if (rdclass == 0xff || rdtype == 0xff) { 213 result = ERRSET_INVAL; 214 goto fail; 215 } 216 217 /* don't allow flags yet, unimplemented */ 218 if (flags) { 219 result = ERRSET_INVAL; 220 goto fail; 221 } 222 223 /* initialize resolver */ 224 if ((_resp->options & RES_INIT) == 0 && res_init() == -1) { 225 result = ERRSET_FAIL; 226 goto fail; 227 } 228 229 #ifdef DEBUG 230 _resp->options |= RES_DEBUG; 231 #endif /* DEBUG */ 232 233 #ifdef RES_USE_DNSSEC 234 /* turn on DNSSEC if EDNS0 is configured */ 235 if (_resp->options & RES_USE_EDNS0) 236 _resp->options |= RES_USE_DNSSEC; 237 #endif /* RES_USE_DNSEC */ 238 239 /* make query */ 240 length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, 241 answer, sizeof(answer)); 242 if (length < 0) { 243 switch(h_errno) { 244 case HOST_NOT_FOUND: 245 result = ERRSET_NONAME; 246 goto fail; 247 case NO_DATA: 248 result = ERRSET_NODATA; 249 goto fail; 250 default: 251 result = ERRSET_FAIL; 252 goto fail; 253 } 254 } 255 256 /* parse result */ 257 response = parse_dns_response(answer, length); 258 if (response == NULL) { 259 result = ERRSET_FAIL; 260 goto fail; 261 } 262 263 if (response->header.qdcount != 1) { 264 result = ERRSET_FAIL; 265 goto fail; 266 } 267 268 /* initialize rrset */ 269 rrset = calloc(1, sizeof(struct rrsetinfo)); 270 if (rrset == NULL) { 271 result = ERRSET_NOMEMORY; 272 goto fail; 273 } 274 rrset->rri_rdclass = response->query->class; 275 rrset->rri_rdtype = response->query->type; 276 rrset->rri_ttl = response->answer->ttl; 277 rrset->rri_nrdatas = response->header.ancount; 278 279 #ifdef HAVE_HEADER_AD 280 /* check for authenticated data */ 281 if (response->header.ad == 1) 282 rrset->rri_flags |= RRSET_VALIDATED; 283 #endif 284 285 /* copy name from answer section */ 286 rrset->rri_name = strdup(response->answer->name); 287 if (rrset->rri_name == NULL) { 288 result = ERRSET_NOMEMORY; 289 goto fail; 290 } 291 292 /* count answers */ 293 rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, 294 rrset->rri_rdtype); 295 rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, 296 T_RRSIG); 297 298 /* allocate memory for answers */ 299 rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 300 sizeof(struct rdatainfo)); 301 if (rrset->rri_rdatas == NULL) { 302 result = ERRSET_NOMEMORY; 303 goto fail; 304 } 305 306 /* allocate memory for signatures */ 307 if (rrset->rri_nsigs > 0) { 308 rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); 309 if (rrset->rri_sigs == NULL) { 310 result = ERRSET_NOMEMORY; 311 goto fail; 312 } 313 } 314 315 /* copy answers & signatures */ 316 for (rr = response->answer, index_ans = 0, index_sig = 0; 317 rr; rr = rr->next) { 318 319 rdata = NULL; 320 321 if (rr->class == rrset->rri_rdclass && 322 rr->type == rrset->rri_rdtype) 323 rdata = &rrset->rri_rdatas[index_ans++]; 324 325 if (rr->class == rrset->rri_rdclass && 326 rr->type == T_RRSIG) 327 rdata = &rrset->rri_sigs[index_sig++]; 328 329 if (rdata) { 330 rdata->rdi_length = rr->size; 331 rdata->rdi_data = malloc(rr->size); 332 333 if (rdata->rdi_data == NULL) { 334 result = ERRSET_NOMEMORY; 335 goto fail; 336 } 337 memcpy(rdata->rdi_data, rr->rdata, rr->size); 338 } 339 } 340 free_dns_response(response); 341 342 *res = rrset; 343 return (ERRSET_SUCCESS); 344 345 fail: 346 if (rrset != NULL) 347 freerrset(rrset); 348 if (response != NULL) 349 free_dns_response(response); 350 return (result); 351 } 352 353 void 354 freerrset(struct rrsetinfo *rrset) 355 { 356 u_int16_t i; 357 358 if (rrset == NULL) 359 return; 360 361 if (rrset->rri_rdatas) { 362 for (i = 0; i < rrset->rri_nrdatas; i++) { 363 if (rrset->rri_rdatas[i].rdi_data == NULL) 364 break; 365 free(rrset->rri_rdatas[i].rdi_data); 366 } 367 free(rrset->rri_rdatas); 368 } 369 370 if (rrset->rri_sigs) { 371 for (i = 0; i < rrset->rri_nsigs; i++) { 372 if (rrset->rri_sigs[i].rdi_data == NULL) 373 break; 374 free(rrset->rri_sigs[i].rdi_data); 375 } 376 free(rrset->rri_sigs); 377 } 378 379 if (rrset->rri_name) 380 free(rrset->rri_name); 381 free(rrset); 382 } 383 384 /* 385 * DNS response parsing routines 386 */ 387 static struct dns_response * 388 parse_dns_response(const u_char *answer, int size) 389 { 390 struct dns_response *resp; 391 const u_char *cp; 392 393 if (size < HFIXEDSZ) 394 return (NULL); 395 396 /* allocate memory for the response */ 397 resp = calloc(1, sizeof(*resp)); 398 if (resp == NULL) 399 return (NULL); 400 401 /* initialize current pointer */ 402 cp = answer; 403 404 /* copy header */ 405 memcpy(&resp->header, cp, HFIXEDSZ); 406 cp += HFIXEDSZ; 407 408 /* fix header byte order */ 409 resp->header.qdcount = ntohs(resp->header.qdcount); 410 resp->header.ancount = ntohs(resp->header.ancount); 411 resp->header.nscount = ntohs(resp->header.nscount); 412 resp->header.arcount = ntohs(resp->header.arcount); 413 414 /* there must be at least one query */ 415 if (resp->header.qdcount < 1) { 416 free_dns_response(resp); 417 return (NULL); 418 } 419 420 /* parse query section */ 421 resp->query = parse_dns_qsection(answer, size, &cp, 422 resp->header.qdcount); 423 if (resp->header.qdcount && resp->query == NULL) { 424 free_dns_response(resp); 425 return (NULL); 426 } 427 428 /* parse answer section */ 429 resp->answer = parse_dns_rrsection(answer, size, &cp, 430 resp->header.ancount); 431 if (resp->header.ancount && resp->answer == NULL) { 432 free_dns_response(resp); 433 return (NULL); 434 } 435 436 /* parse authority section */ 437 resp->authority = parse_dns_rrsection(answer, size, &cp, 438 resp->header.nscount); 439 if (resp->header.nscount && resp->authority == NULL) { 440 free_dns_response(resp); 441 return (NULL); 442 } 443 444 /* parse additional section */ 445 resp->additional = parse_dns_rrsection(answer, size, &cp, 446 resp->header.arcount); 447 if (resp->header.arcount && resp->additional == NULL) { 448 free_dns_response(resp); 449 return (NULL); 450 } 451 452 return (resp); 453 } 454 455 static struct dns_query * 456 parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) 457 { 458 struct dns_query *head, *curr, *prev; 459 int i, length; 460 char name[MAXDNAME]; 461 462 #define NEED(need) \ 463 do { \ 464 if (*cp + need > answer + size) \ 465 goto fail; \ 466 } while (0) 467 468 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 469 if (*cp >= answer + size) { 470 fail: 471 free_dns_query(head); 472 return (NULL); 473 } 474 /* allocate and initialize struct */ 475 curr = calloc(1, sizeof(struct dns_query)); 476 if (curr == NULL) 477 goto fail; 478 if (head == NULL) 479 head = curr; 480 if (prev != NULL) 481 prev->next = curr; 482 483 /* name */ 484 length = dn_expand(answer, answer + size, *cp, name, 485 sizeof(name)); 486 if (length < 0) { 487 free_dns_query(head); 488 return (NULL); 489 } 490 curr->name = strdup(name); 491 if (curr->name == NULL) { 492 free_dns_query(head); 493 return (NULL); 494 } 495 NEED(length); 496 *cp += length; 497 498 /* type */ 499 NEED(INT16SZ); 500 curr->type = _getshort(*cp); 501 *cp += INT16SZ; 502 503 /* class */ 504 NEED(INT16SZ); 505 curr->class = _getshort(*cp); 506 *cp += INT16SZ; 507 } 508 #undef NEED 509 510 return (head); 511 } 512 513 static struct dns_rr * 514 parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, 515 int count) 516 { 517 struct dns_rr *head, *curr, *prev; 518 int i, length; 519 char name[MAXDNAME]; 520 521 #define NEED(need) \ 522 do { \ 523 if (*cp + need > answer + size) \ 524 goto fail; \ 525 } while (0) 526 527 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 528 if (*cp >= answer + size) { 529 fail: 530 free_dns_rr(head); 531 return (NULL); 532 } 533 534 /* allocate and initialize struct */ 535 curr = calloc(1, sizeof(struct dns_rr)); 536 if (curr == NULL) 537 goto fail; 538 if (head == NULL) 539 head = curr; 540 if (prev != NULL) 541 prev->next = curr; 542 543 /* name */ 544 length = dn_expand(answer, answer + size, *cp, name, 545 sizeof(name)); 546 if (length < 0) { 547 free_dns_rr(head); 548 return (NULL); 549 } 550 curr->name = strdup(name); 551 if (curr->name == NULL) { 552 free_dns_rr(head); 553 return (NULL); 554 } 555 NEED(length); 556 *cp += length; 557 558 /* type */ 559 NEED(INT16SZ); 560 curr->type = _getshort(*cp); 561 *cp += INT16SZ; 562 563 /* class */ 564 NEED(INT16SZ); 565 curr->class = _getshort(*cp); 566 *cp += INT16SZ; 567 568 /* ttl */ 569 NEED(INT32SZ); 570 curr->ttl = _getlong(*cp); 571 *cp += INT32SZ; 572 573 /* rdata size */ 574 NEED(INT16SZ); 575 curr->size = _getshort(*cp); 576 *cp += INT16SZ; 577 578 /* rdata itself */ 579 NEED(curr->size); 580 curr->rdata = malloc(curr->size); 581 if (curr->rdata == NULL) { 582 free_dns_rr(head); 583 return (NULL); 584 } 585 memcpy(curr->rdata, *cp, curr->size); 586 *cp += curr->size; 587 } 588 #undef NEED 589 590 return (head); 591 } 592 593 static void 594 free_dns_query(struct dns_query *p) 595 { 596 if (p == NULL) 597 return; 598 599 if (p->name) 600 free(p->name); 601 free_dns_query(p->next); 602 free(p); 603 } 604 605 static void 606 free_dns_rr(struct dns_rr *p) 607 { 608 if (p == NULL) 609 return; 610 611 if (p->name) 612 free(p->name); 613 if (p->rdata) 614 free(p->rdata); 615 free_dns_rr(p->next); 616 free(p); 617 } 618 619 static void 620 free_dns_response(struct dns_response *p) 621 { 622 if (p == NULL) 623 return; 624 625 free_dns_query(p->query); 626 free_dns_rr(p->answer); 627 free_dns_rr(p->authority); 628 free_dns_rr(p->additional); 629 free(p); 630 } 631 632 static int 633 count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) 634 { 635 int n = 0; 636 637 while(p) { 638 if (p->class == class && p->type == type) 639 n++; 640 p = p->next; 641 } 642 643 return (n); 644 } 645 646 #endif /* !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) */ 647