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