1 /* $OpenBSD: res_send_async.c,v 1.6 2012/11/24 15:12:48 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 <fcntl.h> 26 #include <resolv.h> /* for res_random */ 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "asr.h" 32 #include "asr_private.h" 33 34 #define OP_QUERY (0) 35 36 static int res_send_async_run(struct async *, struct async_res *); 37 static int sockaddr_connect(const struct sockaddr *, int); 38 static int udp_send(struct async *); 39 static int udp_recv(struct async *); 40 static int tcp_write(struct async *); 41 static int tcp_read(struct async *); 42 static int validate_packet(struct async *); 43 static int setup_query(struct async *, const char *, const char *, int, int); 44 static int ensure_ibuf(struct async *, size_t); 45 46 47 #define AS_NS_SA(p) ((p)->as_ctx->ac_ns[(p)->as_ns_idx - 1]) 48 49 50 struct async * 51 res_send_async(const unsigned char *buf, int buflen, unsigned char *ans, 52 int anslen, struct asr *asr) 53 { 54 struct asr_ctx *ac; 55 struct async *as; 56 struct unpack p; 57 struct header h; 58 struct query q; 59 60 DPRINT_PACKET("asr: res_send_async()", buf, buflen); 61 62 ac = asr_use_resolver(asr); 63 if ((as = async_new(ac, ASR_SEND)) == NULL) { 64 asr_ctx_unref(ac); 65 return (NULL); /* errno set */ 66 } 67 as->as_run = res_send_async_run; 68 69 if (ans) { 70 as->as.dns.flags |= ASYNC_EXTIBUF; 71 as->as.dns.ibuf = ans; 72 as->as.dns.ibufsize = anslen; 73 as->as.dns.ibuflen = 0; 74 } else { 75 as->as.dns.ibuf = NULL; 76 as->as.dns.ibufsize = 0; 77 as->as.dns.ibuflen = 0; 78 } 79 80 as->as.dns.flags |= ASYNC_EXTOBUF; 81 as->as.dns.obuf = (unsigned char*)buf; 82 as->as.dns.obuflen = buflen; 83 as->as.dns.obufsize = buflen; 84 85 unpack_init(&p, buf, buflen); 86 unpack_header(&p, &h); 87 unpack_query(&p, &q); 88 if (p.err) { 89 errno = EINVAL; 90 goto err; 91 } 92 as->as.dns.reqid = h.id; 93 as->as.dns.type = q.q_type; 94 as->as.dns.class = q.q_class; 95 as->as.dns.dname = strdup(q.q_dname); 96 if (as->as.dns.dname == NULL) 97 goto err; /* errno set */ 98 99 asr_ctx_unref(ac); 100 return (as); 101 err: 102 if (as) 103 async_free(as); 104 asr_ctx_unref(ac); 105 return (NULL); 106 } 107 108 /* 109 * Unlike res_query(), this version will actually return the packet 110 * if it has received a valid one (errno == 0) even if h_errno is 111 * not NETDB_SUCCESS. So the packet *must* be freed if necessary 112 * (ans == NULL). 113 */ 114 struct async * 115 res_query_async(const char *name, int class, int type, unsigned char *ans, 116 int anslen, struct asr *asr) 117 { 118 struct asr_ctx *ac; 119 struct async *as; 120 121 DPRINT("asr: res_query_async(\"%s\", %i, %i)\n", name, class, type); 122 123 ac = asr_use_resolver(asr); 124 as = res_query_async_ctx(name, class, type, ans, anslen, ac); 125 asr_ctx_unref(ac); 126 127 return (as); 128 } 129 130 struct async * 131 res_query_async_ctx(const char *name, int class, int type, unsigned char *ans, 132 int anslen, struct asr_ctx *a_ctx) 133 { 134 struct async *as; 135 136 DPRINT("asr: res_query_async_ctx(\"%s\", %i, %i)\n", name, class, type); 137 138 if ((as = async_new(a_ctx, ASR_SEND)) == NULL) 139 return (NULL); /* errno set */ 140 as->as_run = res_send_async_run; 141 142 if (ans) { 143 as->as.dns.flags |= ASYNC_EXTIBUF; 144 as->as.dns.ibuf = ans; 145 as->as.dns.ibufsize = anslen; 146 } else { 147 as->as.dns.ibuf = NULL; 148 as->as.dns.ibufsize = 0; 149 } 150 as->as.dns.ibuflen = 0; 151 152 /* This adds a "." to name if it doesn't already has one. 153 * That's how res_query() behaves (trough res_mkquery"). 154 */ 155 if (setup_query(as, name, NULL, class, type) == -1) 156 goto err; /* errno set */ 157 158 return (as); 159 160 err: 161 if (as) 162 async_free(as); 163 164 return (NULL); 165 } 166 167 static int 168 res_send_async_run(struct async *as, struct async_res *ar) 169 { 170 next: 171 switch (as->as_state) { 172 173 case ASR_STATE_INIT: 174 175 if (as->as_ctx->ac_nscount == 0) { 176 ar->ar_errno = ECONNREFUSED; 177 async_set_state(as, ASR_STATE_HALT); 178 break; 179 } 180 181 async_set_state(as, ASR_STATE_NEXT_NS); 182 break; 183 184 case ASR_STATE_NEXT_NS: 185 186 if (asr_iter_ns(as) == -1) { 187 ar->ar_errno = ETIMEDOUT; 188 async_set_state(as, ASR_STATE_HALT); 189 break; 190 } 191 192 if (as->as_ctx->ac_options & RES_USEVC || 193 as->as.dns.obuflen > PACKETSZ) 194 async_set_state(as, ASR_STATE_TCP_WRITE); 195 else 196 async_set_state(as, ASR_STATE_UDP_SEND); 197 break; 198 199 case ASR_STATE_UDP_SEND: 200 201 if (udp_send(as) == -1) { 202 async_set_state(as, ASR_STATE_NEXT_NS); 203 break; 204 } 205 async_set_state(as, ASR_STATE_UDP_RECV); 206 ar->ar_cond = ASYNC_READ; 207 ar->ar_fd = as->as_fd; 208 ar->ar_timeout = as->as_timeout; 209 return (ASYNC_COND); 210 break; 211 212 case ASR_STATE_UDP_RECV: 213 214 if (udp_recv(as) == -1) { 215 if (errno == ENOMEM) { 216 ar->ar_errno = errno; 217 async_set_state(as, ASR_STATE_HALT); 218 break; 219 } 220 if (errno != EOVERFLOW) { 221 /* Fail or timeout */ 222 async_set_state(as, ASR_STATE_NEXT_NS); 223 break; 224 } 225 if (as->as_ctx->ac_options & RES_IGNTC) 226 async_set_state(as, ASR_STATE_PACKET); 227 else 228 async_set_state(as, ASR_STATE_TCP_WRITE); 229 } else 230 async_set_state(as, ASR_STATE_PACKET); 231 break; 232 233 case ASR_STATE_TCP_WRITE: 234 235 switch (tcp_write(as)) { 236 case -1: /* fail or timeout */ 237 async_set_state(as, ASR_STATE_NEXT_NS); 238 break; 239 case 0: 240 async_set_state(as, ASR_STATE_TCP_READ); 241 ar->ar_cond = ASYNC_READ; 242 ar->ar_fd = as->as_fd; 243 ar->ar_timeout = as->as_timeout; 244 return (ASYNC_COND); 245 case 1: 246 ar->ar_cond = ASYNC_WRITE; 247 ar->ar_fd = as->as_fd; 248 ar->ar_timeout = as->as_timeout; 249 return (ASYNC_COND); 250 } 251 break; 252 253 case ASR_STATE_TCP_READ: 254 255 switch (tcp_read(as)) { 256 case -1: /* Fail or timeout */ 257 if (errno == ENOMEM) { 258 ar->ar_errno = errno; 259 async_set_state(as, ASR_STATE_HALT); 260 } else 261 async_set_state(as, ASR_STATE_NEXT_NS); 262 break; 263 case 0: 264 async_set_state(as, ASR_STATE_PACKET); 265 break; 266 case 1: 267 ar->ar_cond = ASYNC_READ; 268 ar->ar_fd = as->as_fd; 269 ar->ar_timeout = as->as_timeout; 270 return (ASYNC_COND); 271 } 272 break; 273 274 case ASR_STATE_PACKET: 275 276 memmove(&ar->ar_sa.sa, AS_NS_SA(as), AS_NS_SA(as)->sa_len); 277 ar->ar_datalen = as->as.dns.ibuflen; 278 ar->ar_data = as->as.dns.ibuf; 279 as->as.dns.ibuf = NULL; 280 ar->ar_errno = 0; 281 ar->ar_rcode = as->as.dns.rcode; 282 async_set_state(as, ASR_STATE_HALT); 283 break; 284 285 case ASR_STATE_HALT: 286 287 if (ar->ar_errno) { 288 ar->ar_h_errno = TRY_AGAIN; 289 ar->ar_count = 0; 290 ar->ar_datalen = -1; 291 ar->ar_data = NULL; 292 } else if (as->as.dns.ancount) { 293 ar->ar_h_errno = NETDB_SUCCESS; 294 ar->ar_count = as->as.dns.ancount; 295 } else { 296 ar->ar_count = 0; 297 switch (as->as.dns.rcode) { 298 case NXDOMAIN: 299 ar->ar_h_errno = HOST_NOT_FOUND; 300 break; 301 case SERVFAIL: 302 ar->ar_h_errno = TRY_AGAIN; 303 break; 304 case NOERROR: 305 ar->ar_h_errno = NO_DATA; 306 break; 307 default: 308 ar->ar_h_errno = NO_RECOVERY; 309 } 310 } 311 return (ASYNC_DONE); 312 313 default: 314 315 ar->ar_errno = EOPNOTSUPP; 316 ar->ar_h_errno = NETDB_INTERNAL; 317 async_set_state(as, ASR_STATE_HALT); 318 break; 319 } 320 goto next; 321 } 322 323 static int 324 sockaddr_connect(const struct sockaddr *sa, int socktype) 325 { 326 int errno_save, flags, sock; 327 328 if ((sock = socket(sa->sa_family, socktype, 0)) == -1) 329 goto fail; 330 331 if ((flags = fcntl(sock, F_GETFL, 0)) == -1) 332 goto fail; 333 334 flags |= O_NONBLOCK; 335 336 if ((flags = fcntl(sock, F_SETFL, flags)) == -1) 337 goto fail; 338 339 if (connect(sock, sa, sa->sa_len) == -1) { 340 if (errno == EINPROGRESS) 341 return (sock); 342 goto fail; 343 } 344 345 return (sock); 346 347 fail: 348 349 if (sock != -1) { 350 errno_save = errno; 351 close(sock); 352 errno = errno_save; 353 } 354 355 return (-1); 356 } 357 358 /* 359 * Prepare the DNS packet for the query type "type", class "class" and domain 360 * name created by the concatenation on "name" and "dom". 361 * Return 0 on success, set errno and return -1 on error. 362 */ 363 static int 364 setup_query(struct async *as, const char *name, const char *dom, 365 int class, int type) 366 { 367 struct pack p; 368 struct header h; 369 char fqdn[MAXDNAME]; 370 char dname[MAXDNAME]; 371 372 if (as->as.dns.flags & ASYNC_EXTOBUF) { 373 errno = EINVAL; 374 DPRINT("attempting to write in user packet"); 375 return (-1); 376 } 377 378 if (asr_make_fqdn(name, dom, fqdn, sizeof(fqdn)) > sizeof(fqdn)) { 379 errno = EINVAL; 380 DPRINT("asr_make_fqdn: name too long\n"); 381 return (-1); 382 } 383 384 if (dname_from_fqdn(fqdn, dname, sizeof(dname)) == -1) { 385 errno = EINVAL; 386 DPRINT("dname_from_fqdn: invalid\n"); 387 return (-1); 388 } 389 390 if (as->as.dns.obuf == NULL) { 391 as->as.dns.obufsize = PACKETSZ; 392 as->as.dns.obuf = malloc(as->as.dns.obufsize); 393 if (as->as.dns.obuf == NULL) 394 return (-1); /* errno set */ 395 } 396 as->as.dns.obuflen = 0; 397 398 memset(&h, 0, sizeof h); 399 h.id = res_randomid(); 400 if (as->as_ctx->ac_options & RES_RECURSE) 401 h.flags |= RD_MASK; 402 h.qdcount = 1; 403 404 pack_init(&p, as->as.dns.obuf, as->as.dns.obufsize); 405 pack_header(&p, &h); 406 pack_query(&p, type, class, dname); 407 if (p.err) { 408 DPRINT("error packing query"); 409 errno = EINVAL; 410 return (-1); 411 } 412 413 /* Remember the parameters. */ 414 as->as.dns.reqid = h.id; 415 as->as.dns.type = type; 416 as->as.dns.class = class; 417 if (as->as.dns.dname) 418 free(as->as.dns.dname); 419 as->as.dns.dname = strdup(dname); 420 if (as->as.dns.dname == NULL) { 421 DPRINT("strdup"); 422 return (-1); /* errno set */ 423 } 424 as->as.dns.obuflen = p.offset; 425 426 DPRINT_PACKET("asr_setup_query", as->as.dns.obuf, as->as.dns.obuflen); 427 428 return (0); 429 } 430 431 /* 432 * Create a connect UDP socket and send the output packet. 433 * 434 * Return 0 on success, or -1 on error (errno set). 435 */ 436 static int 437 udp_send(struct async *as) 438 { 439 ssize_t n; 440 int save_errno; 441 #ifdef DEBUG 442 char buf[256]; 443 #endif 444 445 DPRINT("asr: [%p] connecting to %s UDP\n", as, 446 print_sockaddr(AS_NS_SA(as), buf, sizeof buf)); 447 448 as->as_fd = sockaddr_connect(AS_NS_SA(as), SOCK_DGRAM); 449 if (as->as_fd == -1) 450 return (-1); /* errno set */ 451 452 as->as_timeout = as->as_ctx->ac_nstimeout; 453 454 n = send(as->as_fd, as->as.dns.obuf, as->as.dns.obuflen, 0); 455 if (n == -1) { 456 save_errno = errno; 457 close(as->as_fd); 458 errno = save_errno; 459 as->as_fd = -1; 460 return (-1); 461 } 462 463 return (0); 464 } 465 466 /* 467 * Try to receive a valid packet from the current UDP socket. 468 * 469 * Return 0 if a full packet could be read, or -1 on error (errno set). 470 */ 471 static int 472 udp_recv(struct async *as) 473 { 474 ssize_t n; 475 int save_errno; 476 477 /* Allocate input buf if needed */ 478 if (as->as.dns.ibuf == NULL) { 479 if (ensure_ibuf(as, PACKETSZ) == -1) { 480 save_errno = errno; 481 close(as->as_fd); 482 errno = save_errno; 483 as->as_fd = -1; 484 return (-1); 485 } 486 } 487 488 n = recv(as->as_fd, as->as.dns.ibuf, as->as.dns.ibufsize, 0); 489 save_errno = errno; 490 close(as->as_fd); 491 errno = save_errno; 492 as->as_fd = -1; 493 if (n == -1) 494 return (-1); 495 496 as->as.dns.ibuflen = n; 497 498 DPRINT_PACKET("asr_udp_recv()", as->as.dns.ibuf, as->as.dns.ibuflen); 499 500 if (validate_packet(as) == -1) 501 return (-1); /* errno set */ 502 503 return (0); 504 } 505 506 /* 507 * Write the output packet to the TCP socket. 508 * 509 * Return 0 when all bytes have been sent, 1 there is no buffer space on the 510 * socket or it is not connected yet, or -1 on error (errno set). 511 */ 512 static int 513 tcp_write(struct async *as) 514 { 515 struct iovec iov[2]; 516 uint16_t len; 517 ssize_t n; 518 int i, se; 519 socklen_t sl; 520 #ifdef DEBUG 521 char buf[256]; 522 #endif 523 524 /* First try to connect if not already */ 525 if (as->as_fd == -1) { 526 DPRINT("asr: [%p] connecting to %s TCP\n", as, 527 print_sockaddr(AS_NS_SA(as), buf, sizeof buf)); 528 as->as_fd = sockaddr_connect(AS_NS_SA(as), SOCK_STREAM); 529 if (as->as_fd == -1) 530 return (-1); /* errno set */ 531 as->as_timeout = as->as_ctx->ac_nstimeout; 532 return (1); 533 } 534 535 i = 0; 536 537 /* Check if the connection succeeded. */ 538 if (as->as.dns.datalen == 0) { 539 sl = sizeof(se); 540 if (getsockopt(as->as_fd, SOL_SOCKET, SO_ERROR, &se, &sl) == -1) 541 goto close; /* errno set */ 542 if (se) { 543 errno = se; 544 goto close; 545 } 546 547 as->as.dns.bufpos = 0; 548 549 /* Send the packet length first */ 550 len = htons(as->as.dns.obuflen); 551 iov[i].iov_base = &len; 552 iov[i].iov_len = sizeof(len); 553 i++; 554 } 555 556 iov[i].iov_base = as->as.dns.obuf + as->as.dns.bufpos; 557 iov[i].iov_len = as->as.dns.obuflen - as->as.dns.bufpos; 558 i++; 559 560 n = writev(as->as_fd, iov, i); 561 if (n == -1) 562 goto close; /* errno set */ 563 564 /* 565 * We want at least the packet length to be written out the first time. 566 * Technically we could recover but that makes little sense to support 567 * that. 568 */ 569 if (as->as.dns.datalen == 0 && n < 2) { 570 errno = EIO; 571 goto close; 572 } 573 574 if (as->as.dns.datalen == 0) { 575 as->as.dns.datalen = len; 576 n -= 2; 577 } 578 579 as->as.dns.bufpos += n; 580 if (as->as.dns.bufpos == as->as.dns.obuflen) { 581 /* All sent. Prepare for TCP read */ 582 as->as.dns.datalen = 0; 583 return (0); 584 } 585 586 /* More data to write */ 587 as->as_timeout = as->as_ctx->ac_nstimeout; 588 return (1); 589 590 close: 591 close(as->as_fd); 592 as->as_fd = -1; 593 return (-1); 594 } 595 596 /* 597 * Try to read a valid packet from the current TCP socket. 598 * 599 * Return 0 if a full packet could be read, 1 if more data is needed and the 600 * socket must be read again, or -1 on error (errno set). 601 */ 602 static int 603 tcp_read(struct async *as) 604 { 605 uint16_t len; 606 ssize_t n; 607 int save_errno; 608 609 /* We must read the packet len first */ 610 if (as->as.dns.datalen == 0) { 611 n = read(as->as_fd, &len, sizeof(len)); 612 if (n == -1) 613 goto close; /* errno set */ 614 /* 615 * If the server has sent us only the first byte, we fail. 616 * Technically, we could recover but it might not be worth 617 * supporting that. 618 */ 619 if (n < 2) { 620 errno = EIO; 621 goto close; 622 } 623 624 as->as.dns.datalen = ntohs(len); 625 as->as.dns.bufpos = 0; 626 as->as.dns.ibuflen = 0; 627 628 if (ensure_ibuf(as, as->as.dns.datalen) == -1) 629 goto close; /* errno set */ 630 } 631 632 n = read(as->as_fd, as->as.dns.ibuf + as->as.dns.ibuflen, 633 as->as.dns.datalen - as->as.dns.ibuflen); 634 if (n == -1) 635 goto close; /* errno set */ 636 if (n == 0) { 637 errno = ECONNRESET; 638 goto close; 639 } 640 as->as.dns.ibuflen += n; 641 642 /* See if we got all the advertised bytes. */ 643 if (as->as.dns.ibuflen != as->as.dns.datalen) 644 return (1); 645 646 DPRINT_PACKET("asr_tcp_read()", as->as.dns.ibuf, as->as.dns.ibuflen); 647 648 if (validate_packet(as) == -1) 649 goto close; /* errno set */ 650 651 errno = 0; 652 close: 653 save_errno = errno; 654 close(as->as_fd); 655 errno = save_errno; 656 as->as_fd = -1; 657 return (errno ? -1 : 0); 658 } 659 660 /* 661 * Make sure the input buffer is at least "n" bytes long. 662 * If not (or not allocated) allocated enough space, unless the 663 * buffer is external (owned by the caller), in which case it fails. 664 */ 665 static int 666 ensure_ibuf(struct async *as, size_t n) 667 { 668 char *t; 669 670 if (as->as.dns.flags & ASYNC_EXTIBUF) { 671 if (n <= as->as.dns.ibufsize) 672 return (0); 673 errno = EINVAL; 674 return (-1); 675 } 676 677 if (as->as.dns.ibuf == NULL) { 678 as->as.dns.ibuf = malloc(n); 679 if (as->as.dns.ibuf == NULL) 680 return (-1); /* errno set */ 681 as->as.dns.ibufsize = n; 682 return (0); 683 } 684 685 if (as->as.dns.ibufsize >= n) 686 return (0); 687 688 t = realloc(as->as.dns.ibuf, n); 689 if (t == NULL) 690 return (-1); /* errno set */ 691 as->as.dns.ibuf = t; 692 as->as.dns.ibufsize = n; 693 694 return (0); 695 } 696 697 /* 698 * Check if the received packet is valid. 699 * Return 0 on success, or set errno and return -1. 700 */ 701 static int 702 validate_packet(struct async *as) 703 { 704 struct unpack p; 705 struct header h; 706 struct query q; 707 struct rr rr; 708 int r; 709 710 unpack_init(&p, as->as.dns.ibuf, as->as.dns.ibuflen); 711 712 unpack_header(&p, &h); 713 if (p.err) 714 goto inval; 715 716 if (h.id != as->as.dns.reqid) { 717 DPRINT("incorrect reqid\n"); 718 goto inval; 719 } 720 if (h.qdcount != 1) 721 goto inval; 722 /* Should be zero, we could allow this */ 723 if ((h.flags & Z_MASK) != 0) 724 goto inval; 725 /* Actually, it depends on the request but we only use OP_QUERY */ 726 if (OPCODE(h.flags) != OP_QUERY) 727 goto inval; 728 /* Must be a response */ 729 if ((h.flags & QR_MASK) == 0) 730 goto inval; 731 732 as->as.dns.rcode = RCODE(h.flags); 733 as->as.dns.ancount = h.ancount; 734 735 unpack_query(&p, &q); 736 if (p.err) 737 goto inval; 738 739 if (q.q_type != as->as.dns.type || 740 q.q_class != as->as.dns.class || 741 strcasecmp(q.q_dname, as->as.dns.dname)) { 742 DPRINT("incorrect type/class/dname '%s' != '%s'\n", 743 q.q_dname, as->as.dns.dname); 744 goto inval; 745 } 746 747 /* Check for truncation */ 748 if (h.flags & TC_MASK) { 749 errno = EOVERFLOW; 750 return (-1); 751 } 752 753 /* Validate the rest of the packet */ 754 for (r = h.ancount + h.nscount + h.arcount; r; r--) 755 unpack_rr(&p, &rr); 756 757 if (p.err || (p.offset != as->as.dns.ibuflen)) 758 goto inval; 759 760 return (0); 761 762 inval: 763 errno = EINVAL; 764 return (-1); 765 } 766