xref: /openbsd/lib/libc/asr/res_send_async.c (revision 898184e3)
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