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