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