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