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