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 61extern 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 71struct __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 register 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 register 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 * Routines to insert/extract short/long's. 114 */ 115 116#ifndef HAVE__GETSHORT 117static u_int16_t 118_getshort(msgp) 119 register const u_char *msgp; 120{ 121 register u_int16_t u; 122 123 GETSHORT(u, msgp); 124 return (u); 125} 126#elif defined(HAVE_DECL__GETSHORT) && (HAVE_DECL__GETSHORT == 0) 127u_int16_t _getshort(register const u_char *); 128#endif 129 130#ifndef HAVE__GETLONG 131static u_int32_t 132_getlong(msgp) 133 register const u_char *msgp; 134{ 135 register u_int32_t u; 136 137 GETLONG(u, msgp); 138 return (u); 139} 140#elif defined(HAVE_DECL__GETLONG) && (HAVE_DECL__GETLONG == 0) 141u_int32_t _getlong(register const u_char *); 142#endif 143 144/* ************** */ 145 146#define ANSWER_BUFFER_SIZE 0xffff 147 148struct dns_query { 149 char *name; 150 u_int16_t type; 151 u_int16_t class; 152 struct dns_query *next; 153}; 154 155struct dns_rr { 156 char *name; 157 u_int16_t type; 158 u_int16_t class; 159 u_int16_t ttl; 160 u_int16_t size; 161 void *rdata; 162 struct dns_rr *next; 163}; 164 165/* <rdar://problem/6345666> Remove dependency on BIND_8_COMPAT 166 * Mimicing the used fields of the HEADER structure from the compat library. 167 * 168 * Note, ad is 1 bit in the original structure and 8 here. 169 */ 170struct dns_header { 171 u_int8_t ad; 172 u_int16_t qdcount; 173 u_int16_t ancount; 174 u_int16_t nscount; 175 u_int16_t arcount; 176}; 177 178struct dns_response { 179 struct dns_header header; 180 struct dns_query *query; 181 struct dns_rr *answer; 182 struct dns_rr *authority; 183 struct dns_rr *additional; 184}; 185 186static struct dns_response *parse_dns_response(const u_char *, int); 187static struct dns_query *parse_dns_qsection(const u_char *, int, 188 const u_char **, int); 189static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, 190 int); 191 192static void free_dns_query(struct dns_query *); 193static void free_dns_rr(struct dns_rr *); 194static void free_dns_response(struct dns_response *); 195 196static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); 197 198int 199getrrsetbyname(const char *hostname, unsigned int rdclass, 200 unsigned int rdtype, unsigned int flags, 201 struct rrsetinfo **res) 202{ 203 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res); 204 int result; 205 struct rrsetinfo *rrset = NULL; 206 struct dns_response *response = NULL; 207 struct dns_rr *rr; 208 struct rdatainfo *rdata; 209 int length; 210 unsigned int index_ans, index_sig; 211 u_char answer[ANSWER_BUFFER_SIZE]; 212 213 /* check for invalid class and type */ 214 if (rdclass > 0xffff || rdtype > 0xffff) { 215 result = ERRSET_INVAL; 216 goto fail; 217 } 218 219 /* don't allow queries of class or type ANY */ 220 if (rdclass == 0xff || rdtype == 0xff) { 221 result = ERRSET_INVAL; 222 goto fail; 223 } 224 225 /* don't allow flags yet, unimplemented */ 226 if (flags) { 227 result = ERRSET_INVAL; 228 goto fail; 229 } 230 231 /* initialize resolver */ 232 if ((_resp->options & RES_INIT) == 0 && res_init() == -1) { 233 result = ERRSET_FAIL; 234 goto fail; 235 } 236 237#ifdef DEBUG 238 _resp->options |= RES_DEBUG; 239#endif /* DEBUG */ 240 241#ifdef RES_USE_DNSSEC 242 /* turn on DNSSEC if EDNS0 is configured */ 243 if (_resp->options & RES_USE_EDNS0) 244 _resp->options |= RES_USE_DNSSEC; 245#endif /* RES_USE_DNSEC */ 246 247 /* make query */ 248 length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, 249 answer, sizeof(answer)); 250 if (length < 0) { 251 switch(h_errno) { 252 case HOST_NOT_FOUND: 253 result = ERRSET_NONAME; 254 goto fail; 255 case NO_DATA: 256 result = ERRSET_NODATA; 257 goto fail; 258 default: 259 result = ERRSET_FAIL; 260 goto fail; 261 } 262 } 263 264 /* parse result */ 265 response = parse_dns_response(answer, length); 266 if (response == NULL) { 267 result = ERRSET_FAIL; 268 goto fail; 269 } 270 271 if (response->header.qdcount != 1) { 272 result = ERRSET_FAIL; 273 goto fail; 274 } 275 276 /* initialize rrset */ 277 rrset = calloc(1, sizeof(struct rrsetinfo)); 278 if (rrset == NULL) { 279 result = ERRSET_NOMEMORY; 280 goto fail; 281 } 282 rrset->rri_rdclass = response->query->class; 283 rrset->rri_rdtype = response->query->type; 284 rrset->rri_ttl = response->answer->ttl; 285 rrset->rri_nrdatas = response->header.ancount; 286 287#ifdef HAVE_HEADER_AD 288 /* check for authenticated data */ 289 if (response->header.ad == 1) 290 rrset->rri_flags |= RRSET_VALIDATED; 291#endif 292 293 /* copy name from answer section */ 294 rrset->rri_name = strdup(response->answer->name); 295 if (rrset->rri_name == NULL) { 296 result = ERRSET_NOMEMORY; 297 goto fail; 298 } 299 300 /* count answers */ 301 rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, 302 rrset->rri_rdtype); 303 rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, 304 T_RRSIG); 305 306 /* allocate memory for answers */ 307 rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 308 sizeof(struct rdatainfo)); 309 if (rrset->rri_rdatas == NULL) { 310 result = ERRSET_NOMEMORY; 311 goto fail; 312 } 313 314 /* allocate memory for signatures */ 315 if (rrset->rri_nsigs > 0) { 316 rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); 317 if (rrset->rri_sigs == NULL) { 318 result = ERRSET_NOMEMORY; 319 goto fail; 320 } 321 } 322 323 /* copy answers & signatures */ 324 for (rr = response->answer, index_ans = 0, index_sig = 0; 325 rr; rr = rr->next) { 326 327 rdata = NULL; 328 329 if (rr->class == rrset->rri_rdclass && 330 rr->type == rrset->rri_rdtype) 331 rdata = &rrset->rri_rdatas[index_ans++]; 332 333 if (rr->class == rrset->rri_rdclass && 334 rr->type == T_RRSIG) 335 rdata = &rrset->rri_sigs[index_sig++]; 336 337 if (rdata) { 338 rdata->rdi_length = rr->size; 339 rdata->rdi_data = malloc(rr->size); 340 341 if (rdata->rdi_data == NULL) { 342 result = ERRSET_NOMEMORY; 343 goto fail; 344 } 345 memcpy(rdata->rdi_data, rr->rdata, rr->size); 346 } 347 } 348 free_dns_response(response); 349 350 *res = rrset; 351 return (ERRSET_SUCCESS); 352 353fail: 354 if (rrset != NULL) 355 freerrset(rrset); 356 if (response != NULL) 357 free_dns_response(response); 358 return (result); 359} 360 361void 362freerrset(struct rrsetinfo *rrset) 363{ 364 u_int16_t i; 365 366 if (rrset == NULL) 367 return; 368 369 if (rrset->rri_rdatas) { 370 for (i = 0; i < rrset->rri_nrdatas; i++) { 371 if (rrset->rri_rdatas[i].rdi_data == NULL) 372 break; 373 free(rrset->rri_rdatas[i].rdi_data); 374 } 375 free(rrset->rri_rdatas); 376 } 377 378 if (rrset->rri_sigs) { 379 for (i = 0; i < rrset->rri_nsigs; i++) { 380 if (rrset->rri_sigs[i].rdi_data == NULL) 381 break; 382 free(rrset->rri_sigs[i].rdi_data); 383 } 384 free(rrset->rri_sigs); 385 } 386 387 if (rrset->rri_name) 388 free(rrset->rri_name); 389 free(rrset); 390} 391 392/* 393 * DNS response parsing routines 394 */ 395static struct dns_response * 396parse_dns_response(const u_char *answer, int size) 397{ 398 struct dns_response *resp; 399 const u_char *cp; 400 401 /* allocate memory for the response */ 402 resp = calloc(1, sizeof(*resp)); 403 if (resp == NULL) 404 return (NULL); 405 406 /* initialize current pointer */ 407 cp = answer; 408 409 /* copy header */ 410 memcpy(&resp->header, cp, HFIXEDSZ); 411 cp += HFIXEDSZ; 412 413 /* fix header byte order */ 414 resp->header.qdcount = ntohs(resp->header.qdcount); 415 resp->header.ancount = ntohs(resp->header.ancount); 416 resp->header.nscount = ntohs(resp->header.nscount); 417 resp->header.arcount = ntohs(resp->header.arcount); 418 419 /* there must be at least one query */ 420 if (resp->header.qdcount < 1) { 421 free_dns_response(resp); 422 return (NULL); 423 } 424 425 /* parse query section */ 426 resp->query = parse_dns_qsection(answer, size, &cp, 427 resp->header.qdcount); 428 if (resp->header.qdcount && resp->query == NULL) { 429 free_dns_response(resp); 430 return (NULL); 431 } 432 433 /* parse answer section */ 434 resp->answer = parse_dns_rrsection(answer, size, &cp, 435 resp->header.ancount); 436 if (resp->header.ancount && resp->answer == NULL) { 437 free_dns_response(resp); 438 return (NULL); 439 } 440 441 /* parse authority section */ 442 resp->authority = parse_dns_rrsection(answer, size, &cp, 443 resp->header.nscount); 444 if (resp->header.nscount && resp->authority == NULL) { 445 free_dns_response(resp); 446 return (NULL); 447 } 448 449 /* parse additional section */ 450 resp->additional = parse_dns_rrsection(answer, size, &cp, 451 resp->header.arcount); 452 if (resp->header.arcount && resp->additional == NULL) { 453 free_dns_response(resp); 454 return (NULL); 455 } 456 457 return (resp); 458} 459 460static struct dns_query * 461parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) 462{ 463 struct dns_query *head, *curr, *prev; 464 int i, length; 465 char name[NS_MAXDNAME]; 466 467 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 468 469 /* allocate and initialize struct */ 470 curr = calloc(1, sizeof(struct dns_query)); 471 if (curr == NULL) { 472 free_dns_query(head); 473 return (NULL); 474 } 475 if (head == NULL) 476 head = curr; 477 if (prev != NULL) 478 prev->next = curr; 479 480 /* name */ 481 length = dn_expand(answer, answer + size, *cp, name, 482 sizeof(name)); 483 if (length < 0) { 484 free_dns_query(head); 485 return (NULL); 486 } 487 curr->name = strdup(name); 488 if (curr->name == NULL) { 489 free_dns_query(head); 490 return (NULL); 491 } 492 *cp += length; 493 494 /* type */ 495 curr->type = _getshort(*cp); 496 *cp += INT16SZ; 497 498 /* class */ 499 curr->class = _getshort(*cp); 500 *cp += INT16SZ; 501 } 502 503 return (head); 504} 505 506static struct dns_rr * 507parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, 508 int count) 509{ 510 struct dns_rr *head, *curr, *prev; 511 int i, length; 512 char name[NS_MAXDNAME]; 513 514 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 515 516 /* allocate and initialize struct */ 517 curr = calloc(1, sizeof(struct dns_rr)); 518 if (curr == NULL) { 519 free_dns_rr(head); 520 return (NULL); 521 } 522 if (head == NULL) 523 head = curr; 524 if (prev != NULL) 525 prev->next = curr; 526 527 /* name */ 528 length = dn_expand(answer, answer + size, *cp, name, 529 sizeof(name)); 530 if (length < 0) { 531 free_dns_rr(head); 532 return (NULL); 533 } 534 curr->name = strdup(name); 535 if (curr->name == NULL) { 536 free_dns_rr(head); 537 return (NULL); 538 } 539 *cp += length; 540 541 /* type */ 542 curr->type = _getshort(*cp); 543 *cp += INT16SZ; 544 545 /* class */ 546 curr->class = _getshort(*cp); 547 *cp += INT16SZ; 548 549 /* ttl */ 550 curr->ttl = _getlong(*cp); 551 *cp += INT32SZ; 552 553 /* rdata size */ 554 curr->size = _getshort(*cp); 555 *cp += INT16SZ; 556 557 /* rdata itself */ 558 curr->rdata = malloc(curr->size); 559 if (curr->rdata == NULL) { 560 free_dns_rr(head); 561 return (NULL); 562 } 563 memcpy(curr->rdata, *cp, curr->size); 564 *cp += curr->size; 565 } 566 567 return (head); 568} 569 570static void 571free_dns_query(struct dns_query *p) 572{ 573 if (p == NULL) 574 return; 575 576 if (p->name) 577 free(p->name); 578 free_dns_query(p->next); 579 free(p); 580} 581 582static void 583free_dns_rr(struct dns_rr *p) 584{ 585 if (p == NULL) 586 return; 587 588 if (p->name) 589 free(p->name); 590 if (p->rdata) 591 free(p->rdata); 592 free_dns_rr(p->next); 593 free(p); 594} 595 596static void 597free_dns_response(struct dns_response *p) 598{ 599 if (p == NULL) 600 return; 601 602 free_dns_query(p->query); 603 free_dns_rr(p->answer); 604 free_dns_rr(p->authority); 605 free_dns_rr(p->additional); 606 free(p); 607} 608 609static int 610count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) 611{ 612 int n = 0; 613 614 while(p) { 615 if (p->class == class && p->type == type) 616 n++; 617 p = p->next; 618 } 619 620 return (n); 621} 622 623#endif /* !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) */ 624