1 /* $OpenBSD: getrrsetbyname_async.c,v 1.1 2012/04/14 09:24:18 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 #include <sys/types.h> 18 #include <sys/uio.h> 19 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 NULL, 0, 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 159 if (ar->ar_rrset_errno) 160 ar->ar_rrsetinfo = NULL; 161 return (ASYNC_DONE); 162 163 default: 164 ar->ar_errno = EOPNOTSUPP; 165 ar->ar_h_errno = NETDB_INTERNAL; 166 ar->ar_gai_errno = EAI_SYSTEM; 167 async_set_state(as, ASR_STATE_HALT); 168 break; 169 } 170 goto next; 171 } 172 173 /* The rest of this file is taken from the orignal implementation. */ 174 175 /* $OpenBSD: getrrsetbyname_async.c,v 1.1 2012/04/14 09:24:18 eric Exp $ */ 176 177 /* 178 * Copyright (c) 2001 Jakob Schlyter. All rights reserved. 179 * 180 * Redistribution and use in source and binary forms, with or without 181 * modification, are permitted provided that the following conditions 182 * are met: 183 * 184 * 1. Redistributions of source code must retain the above copyright 185 * notice, this list of conditions and the following disclaimer. 186 * 187 * 2. Redistributions in binary form must reproduce the above copyright 188 * notice, this list of conditions and the following disclaimer in the 189 * documentation and/or other materials provided with the distribution. 190 * 191 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 192 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 193 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 194 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 195 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 196 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 197 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 198 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 199 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 200 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 201 */ 202 203 /* 204 * Portions Copyright (c) 1999-2001 Internet Software Consortium. 205 * 206 * Permission to use, copy, modify, and distribute this software for any 207 * purpose with or without fee is hereby granted, provided that the above 208 * copyright notice and this permission notice appear in all copies. 209 * 210 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 211 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 212 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 213 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 214 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 215 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 216 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 217 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 218 */ 219 220 #define MAXPACKET 1024*64 221 222 struct dns_query { 223 char *name; 224 u_int16_t type; 225 u_int16_t class; 226 struct dns_query *next; 227 }; 228 229 struct dns_rr { 230 char *name; 231 u_int16_t type; 232 u_int16_t class; 233 u_int16_t ttl; 234 u_int16_t size; 235 void *rdata; 236 struct dns_rr *next; 237 }; 238 239 struct dns_response { 240 HEADER header; 241 struct dns_query *query; 242 struct dns_rr *answer; 243 struct dns_rr *authority; 244 struct dns_rr *additional; 245 }; 246 247 static struct dns_response *parse_dns_response(const u_char *, int); 248 static struct dns_query *parse_dns_qsection(const u_char *, int, 249 const u_char **, int); 250 static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, 251 int); 252 253 static void free_dns_query(struct dns_query *); 254 static void free_dns_rr(struct dns_rr *); 255 static void free_dns_response(struct dns_response *); 256 257 static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); 258 259 static void 260 get_response(struct async_res *ar, const char *pkt, int pktlen) 261 { 262 struct rrsetinfo *rrset = NULL; 263 struct dns_response *response = NULL; 264 struct dns_rr *rr; 265 struct rdatainfo *rdata; 266 unsigned int index_ans, index_sig; 267 268 /* parse result */ 269 response = parse_dns_response(pkt, pktlen); 270 if (response == NULL) { 271 ar->ar_rrset_errno = ERRSET_FAIL; 272 goto fail; 273 } 274 275 if (response->header.qdcount != 1) { 276 ar->ar_rrset_errno = ERRSET_FAIL; 277 goto fail; 278 } 279 280 /* initialize rrset */ 281 rrset = calloc(1, sizeof(struct rrsetinfo)); 282 if (rrset == NULL) { 283 ar->ar_rrset_errno = ERRSET_NOMEMORY; 284 goto fail; 285 } 286 rrset->rri_rdclass = response->query->class; 287 rrset->rri_rdtype = response->query->type; 288 rrset->rri_ttl = response->answer->ttl; 289 rrset->rri_nrdatas = response->header.ancount; 290 291 /* check for authenticated data */ 292 if (response->header.ad == 1) 293 rrset->rri_flags |= RRSET_VALIDATED; 294 295 /* copy name from answer section */ 296 rrset->rri_name = strdup(response->answer->name); 297 if (rrset->rri_name == NULL) { 298 ar->ar_rrset_errno = ERRSET_NOMEMORY; 299 goto fail; 300 } 301 302 /* count answers */ 303 rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, 304 rrset->rri_rdtype); 305 rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, 306 T_RRSIG); 307 308 /* allocate memory for answers */ 309 rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 310 sizeof(struct rdatainfo)); 311 if (rrset->rri_rdatas == NULL) { 312 ar->ar_rrset_errno = ERRSET_NOMEMORY; 313 goto fail; 314 } 315 316 /* allocate memory for signatures */ 317 rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); 318 if (rrset->rri_sigs == NULL) { 319 ar->ar_rrset_errno = ERRSET_NOMEMORY; 320 goto fail; 321 } 322 323 /* copy answers & signatures */ 324 for (rr = response->answer, index_ans = 0, index_sig = 0; 325 rr; rr = rr->next) { 326 327 rdata = NULL; 328 329 if (rr->class == rrset->rri_rdclass && 330 rr->type == rrset->rri_rdtype) 331 rdata = &rrset->rri_rdatas[index_ans++]; 332 333 if (rr->class == rrset->rri_rdclass && 334 rr->type == T_RRSIG) 335 rdata = &rrset->rri_sigs[index_sig++]; 336 337 if (rdata) { 338 rdata->rdi_length = rr->size; 339 rdata->rdi_data = malloc(rr->size); 340 341 if (rdata->rdi_data == NULL) { 342 ar->ar_rrset_errno = ERRSET_NOMEMORY; 343 goto fail; 344 } 345 memcpy(rdata->rdi_data, rr->rdata, rr->size); 346 } 347 } 348 free_dns_response(response); 349 350 ar->ar_rrsetinfo = rrset; 351 ar->ar_rrset_errno = ERRSET_SUCCESS; 352 return; 353 354 fail: 355 if (rrset != NULL) 356 freerrset(rrset); 357 if (response != NULL) 358 free_dns_response(response); 359 } 360 361 /* 362 * DNS response parsing routines 363 */ 364 static struct dns_response * 365 parse_dns_response(const u_char *answer, int size) 366 { 367 struct dns_response *resp; 368 const u_char *cp; 369 370 /* allocate memory for the response */ 371 resp = calloc(1, sizeof(*resp)); 372 if (resp == NULL) 373 return (NULL); 374 375 /* initialize current pointer */ 376 cp = answer; 377 378 /* copy header */ 379 memcpy(&resp->header, cp, HFIXEDSZ); 380 cp += HFIXEDSZ; 381 382 /* fix header byte order */ 383 resp->header.qdcount = ntohs(resp->header.qdcount); 384 resp->header.ancount = ntohs(resp->header.ancount); 385 resp->header.nscount = ntohs(resp->header.nscount); 386 resp->header.arcount = ntohs(resp->header.arcount); 387 388 /* there must be at least one query */ 389 if (resp->header.qdcount < 1) { 390 free_dns_response(resp); 391 return (NULL); 392 } 393 394 /* parse query section */ 395 resp->query = parse_dns_qsection(answer, size, &cp, 396 resp->header.qdcount); 397 if (resp->header.qdcount && resp->query == NULL) { 398 free_dns_response(resp); 399 return (NULL); 400 } 401 402 /* parse answer section */ 403 resp->answer = parse_dns_rrsection(answer, size, &cp, 404 resp->header.ancount); 405 if (resp->header.ancount && resp->answer == NULL) { 406 free_dns_response(resp); 407 return (NULL); 408 } 409 410 /* parse authority section */ 411 resp->authority = parse_dns_rrsection(answer, size, &cp, 412 resp->header.nscount); 413 if (resp->header.nscount && resp->authority == NULL) { 414 free_dns_response(resp); 415 return (NULL); 416 } 417 418 /* parse additional section */ 419 resp->additional = parse_dns_rrsection(answer, size, &cp, 420 resp->header.arcount); 421 if (resp->header.arcount && resp->additional == NULL) { 422 free_dns_response(resp); 423 return (NULL); 424 } 425 426 return (resp); 427 } 428 429 static struct dns_query * 430 parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) 431 { 432 struct dns_query *head, *curr, *prev; 433 int i, length; 434 char name[MAXDNAME]; 435 436 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 437 438 /* allocate and initialize struct */ 439 curr = calloc(1, sizeof(struct dns_query)); 440 if (curr == NULL) { 441 free_dns_query(head); 442 return (NULL); 443 } 444 if (head == NULL) 445 head = curr; 446 if (prev != NULL) 447 prev->next = curr; 448 449 /* name */ 450 length = dn_expand(answer, answer + size, *cp, name, 451 sizeof(name)); 452 if (length < 0) { 453 free_dns_query(head); 454 return (NULL); 455 } 456 curr->name = strdup(name); 457 if (curr->name == NULL) { 458 free_dns_query(head); 459 return (NULL); 460 } 461 *cp += length; 462 463 /* type */ 464 curr->type = _getshort(*cp); 465 *cp += INT16SZ; 466 467 /* class */ 468 curr->class = _getshort(*cp); 469 *cp += INT16SZ; 470 } 471 472 return (head); 473 } 474 475 static struct dns_rr * 476 parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, 477 int count) 478 { 479 struct dns_rr *head, *curr, *prev; 480 int i, length; 481 char name[MAXDNAME]; 482 483 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 484 485 /* allocate and initialize struct */ 486 curr = calloc(1, sizeof(struct dns_rr)); 487 if (curr == NULL) { 488 free_dns_rr(head); 489 return (NULL); 490 } 491 if (head == NULL) 492 head = curr; 493 if (prev != NULL) 494 prev->next = curr; 495 496 /* name */ 497 length = dn_expand(answer, answer + size, *cp, name, 498 sizeof(name)); 499 if (length < 0) { 500 free_dns_rr(head); 501 return (NULL); 502 } 503 curr->name = strdup(name); 504 if (curr->name == NULL) { 505 free_dns_rr(head); 506 return (NULL); 507 } 508 *cp += length; 509 510 /* type */ 511 curr->type = _getshort(*cp); 512 *cp += INT16SZ; 513 514 /* class */ 515 curr->class = _getshort(*cp); 516 *cp += INT16SZ; 517 518 /* ttl */ 519 curr->ttl = _getlong(*cp); 520 *cp += INT32SZ; 521 522 /* rdata size */ 523 curr->size = _getshort(*cp); 524 *cp += INT16SZ; 525 526 /* rdata itself */ 527 curr->rdata = malloc(curr->size); 528 if (curr->rdata == NULL) { 529 free_dns_rr(head); 530 return (NULL); 531 } 532 memcpy(curr->rdata, *cp, curr->size); 533 *cp += curr->size; 534 } 535 536 return (head); 537 } 538 539 static void 540 free_dns_query(struct dns_query *p) 541 { 542 if (p == NULL) 543 return; 544 545 if (p->name) 546 free(p->name); 547 free_dns_query(p->next); 548 free(p); 549 } 550 551 static void 552 free_dns_rr(struct dns_rr *p) 553 { 554 if (p == NULL) 555 return; 556 557 if (p->name) 558 free(p->name); 559 if (p->rdata) 560 free(p->rdata); 561 free_dns_rr(p->next); 562 free(p); 563 } 564 565 static void 566 free_dns_response(struct dns_response *p) 567 { 568 if (p == NULL) 569 return; 570 571 free_dns_query(p->query); 572 free_dns_rr(p->answer); 573 free_dns_rr(p->authority); 574 free_dns_rr(p->additional); 575 free(p); 576 } 577 578 static int 579 count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) 580 { 581 int n = 0; 582 583 while(p) { 584 if (p->class == class && p->type == type) 585 n++; 586 p = p->next; 587 } 588 589 return (n); 590 } 591