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