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