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