1 /* $OpenBSD: getrrsetbyname_async.c,v 1.13 2023/03/15 22:12:00 millert 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 <errno.h> 27 #include <resolv.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "asr_private.h" 33 34 static int getrrsetbyname_async_run(struct asr_query *, struct asr_result *); 35 static void get_response(struct asr_result *, const char *, int); 36 37 struct asr_query * 38 getrrsetbyname_async(const char *hostname, unsigned int rdclass, 39 unsigned int rdtype, unsigned int flags, void *asr) 40 { 41 struct asr_ctx *ac; 42 struct asr_query *as; 43 44 ac = _asr_use_resolver(asr); 45 if ((as = _asr_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 _asr_async_free(as); 61 62 _asr_ctx_unref(ac); 63 return (NULL); 64 } 65 DEF_WEAK(getrrsetbyname_async); 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_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_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_subq, ar)) == ASYNC_COND) 114 return (ASYNC_COND); 115 116 as->as_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 original implementation. */ 172 173 /* $OpenBSD: getrrsetbyname_async.c,v 1.13 2023/03/15 22:12:00 millert 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 if (size <= HFIXEDSZ) 369 return (NULL); 370 371 /* allocate memory for the response */ 372 resp = calloc(1, sizeof(*resp)); 373 if (resp == NULL) 374 return (NULL); 375 376 /* initialize current pointer */ 377 cp = answer; 378 379 /* copy header */ 380 memcpy(&resp->header, cp, HFIXEDSZ); 381 cp += HFIXEDSZ; 382 383 /* fix header byte order */ 384 resp->header.qdcount = ntohs(resp->header.qdcount); 385 resp->header.ancount = ntohs(resp->header.ancount); 386 resp->header.nscount = ntohs(resp->header.nscount); 387 resp->header.arcount = ntohs(resp->header.arcount); 388 389 /* there must be at least one query */ 390 if (resp->header.qdcount < 1) { 391 free_dns_response(resp); 392 return (NULL); 393 } 394 395 /* parse query section */ 396 resp->query = parse_dns_qsection(answer, size, &cp, 397 resp->header.qdcount); 398 if (resp->header.qdcount && resp->query == NULL) { 399 free_dns_response(resp); 400 return (NULL); 401 } 402 403 /* parse answer section */ 404 resp->answer = parse_dns_rrsection(answer, size, &cp, 405 resp->header.ancount); 406 if (resp->header.ancount && resp->answer == NULL) { 407 free_dns_response(resp); 408 return (NULL); 409 } 410 411 /* parse authority section */ 412 resp->authority = parse_dns_rrsection(answer, size, &cp, 413 resp->header.nscount); 414 if (resp->header.nscount && resp->authority == NULL) { 415 free_dns_response(resp); 416 return (NULL); 417 } 418 419 /* parse additional section */ 420 resp->additional = parse_dns_rrsection(answer, size, &cp, 421 resp->header.arcount); 422 if (resp->header.arcount && resp->additional == NULL) { 423 free_dns_response(resp); 424 return (NULL); 425 } 426 427 return (resp); 428 } 429 430 static struct dns_query * 431 parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) 432 { 433 struct dns_query *head, *curr, *prev; 434 int i, length; 435 char name[MAXDNAME]; 436 437 #define NEED(need) \ 438 do { \ 439 if (*cp + need > answer + size) \ 440 goto fail; \ 441 } while (0) 442 443 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 444 if (*cp >= answer + size) { 445 fail: 446 free_dns_query(head); 447 return (NULL); 448 } 449 /* allocate and initialize struct */ 450 curr = calloc(1, sizeof(struct dns_query)); 451 if (curr == NULL) 452 goto fail; 453 if (head == NULL) 454 head = curr; 455 if (prev != NULL) 456 prev->next = curr; 457 458 /* name */ 459 length = dn_expand(answer, answer + size, *cp, name, 460 sizeof(name)); 461 if (length < 0) { 462 free_dns_query(head); 463 return (NULL); 464 } 465 curr->name = strdup(name); 466 if (curr->name == NULL) { 467 free_dns_query(head); 468 return (NULL); 469 } 470 NEED(length); 471 *cp += length; 472 473 /* type */ 474 NEED(INT16SZ); 475 curr->type = _getshort(*cp); 476 *cp += INT16SZ; 477 478 /* class */ 479 NEED(INT16SZ); 480 curr->class = _getshort(*cp); 481 *cp += INT16SZ; 482 } 483 #undef NEED 484 485 return (head); 486 } 487 488 static struct dns_rr * 489 parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, 490 int count) 491 { 492 struct dns_rr *head, *curr, *prev; 493 int i, length; 494 char name[MAXDNAME]; 495 496 #define NEED(need) \ 497 do { \ 498 if (*cp + need > answer + size) \ 499 goto fail; \ 500 } while (0) 501 502 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 503 if (*cp >= answer + size) { 504 fail: 505 free_dns_rr(head); 506 return (NULL); 507 } 508 509 /* allocate and initialize struct */ 510 curr = calloc(1, sizeof(struct dns_rr)); 511 if (curr == NULL) 512 goto fail; 513 if (head == NULL) 514 head = curr; 515 if (prev != NULL) 516 prev->next = curr; 517 518 /* name */ 519 length = dn_expand(answer, answer + size, *cp, name, 520 sizeof(name)); 521 if (length < 0) { 522 free_dns_rr(head); 523 return (NULL); 524 } 525 curr->name = strdup(name); 526 if (curr->name == NULL) { 527 free_dns_rr(head); 528 return (NULL); 529 } 530 NEED(length); 531 *cp += length; 532 533 /* type */ 534 NEED(INT16SZ); 535 curr->type = _getshort(*cp); 536 *cp += INT16SZ; 537 538 /* class */ 539 NEED(INT16SZ); 540 curr->class = _getshort(*cp); 541 *cp += INT16SZ; 542 543 /* ttl */ 544 NEED(INT32SZ); 545 curr->ttl = _getlong(*cp); 546 *cp += INT32SZ; 547 548 /* rdata size */ 549 NEED(INT16SZ); 550 curr->size = _getshort(*cp); 551 *cp += INT16SZ; 552 553 /* rdata itself */ 554 NEED(curr->size); 555 curr->rdata = malloc(curr->size); 556 if (curr->rdata == NULL) { 557 free_dns_rr(head); 558 return (NULL); 559 } 560 memcpy(curr->rdata, *cp, curr->size); 561 *cp += curr->size; 562 } 563 #undef NEED 564 565 return (head); 566 } 567 568 static void 569 free_dns_query(struct dns_query *p) 570 { 571 if (p == NULL) 572 return; 573 574 if (p->name) 575 free(p->name); 576 free_dns_query(p->next); 577 free(p); 578 } 579 580 static void 581 free_dns_rr(struct dns_rr *p) 582 { 583 if (p == NULL) 584 return; 585 586 if (p->name) 587 free(p->name); 588 if (p->rdata) 589 free(p->rdata); 590 free_dns_rr(p->next); 591 free(p); 592 } 593 594 static void 595 free_dns_response(struct dns_response *p) 596 { 597 if (p == NULL) 598 return; 599 600 free_dns_query(p->query); 601 free_dns_rr(p->answer); 602 free_dns_rr(p->authority); 603 free_dns_rr(p->additional); 604 free(p); 605 } 606 607 static int 608 count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) 609 { 610 int n = 0; 611 612 while (p) { 613 if (p->class == class && p->type == type) 614 n++; 615 p = p->next; 616 } 617 618 return (n); 619 } 620