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