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