xref: /openbsd-src/regress/lib/libc/asr/bin/res_query.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: res_query.c,v 1.1.1.1 2012/07/13 17:49:54 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/socket.h>
20 
21 #include <netinet/in.h>
22 #include <arpa/nameser.h>
23 #include <arpa/inet.h>
24 
25 #include <err.h>
26 #include <errno.h>
27 #include <getopt.h>
28 #include <inttypes.h>
29 #include <resolv.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "common.h"
35 
36 /* in asr.c but we don't want them exposed right now */
37 static void dump_packet(const void *, size_t);
38 
39 static char *print_query(struct query *, char *, size_t);
40 static char *print_rr(struct rr *, char *, size_t);
41 static char *print_host(const struct sockaddr *, char *, size_t);
42 static char* print_dname(const char *, char *, size_t);
43 
44 
45 static int
46 msec(struct timeval start, struct timeval end)
47 {
48 	return (int)((end.tv_sec - start.tv_sec) * 1000
49 	    + (end.tv_usec - start.tv_usec) / 1000);
50 }
51 
52 static void
53 usage(void)
54 {
55 	extern const char * __progname;
56 
57 	fprintf(stderr, "usage: %s [-deq] [-t type] [host...]\n",
58 	    __progname);
59 	exit(1);
60 }
61 
62 int
63 main(int argc, char *argv[])
64 {
65 	struct timeval		 start, end;
66 	time_t			 when;
67 	int			 ch, i, qflag, dflag, r;
68 	uint16_t		 type = T_A;
69 	char			 buf[1024], *host;
70 
71 	dflag = 0;
72 	qflag = 0;
73 
74 	while((ch = getopt(argc, argv, "deqt:")) !=  -1) {
75 		switch(ch) {
76 		case 'd':
77 			dflag = 1;
78 			break;
79 		case 'e':
80 			long_err += 1;
81 			break;
82 		case 'q':
83 			qflag = 1;
84 			break;
85 		case 't':
86 			if ((type = strtotype(optarg)) == 0)
87 				usage();
88 			break;
89 		default:
90 			usage();
91 			/* NOTREACHED */
92 		}
93 	}
94 	argc -= optind;
95 	argv += optind;
96 
97 	for (i = 0; i < argc; i++) {
98 
99 		if (i)
100 			printf("\n");
101 
102 		printf("===> \"%s\"\n", argv[i]);
103 		host = gethostarg(argv[i]);
104 
105 		errno = 0;
106 		h_errno = 0;
107 		gai_errno = 0;
108 		rrset_errno = 0;
109 
110 		if (gettimeofday(&start, NULL) != 0)
111 			err(1, "gettimeofday");
112 
113 		if (qflag)
114 			r = res_query(host, C_IN, type, buf, sizeof(buf));
115 		else
116 			r = res_search(host, C_IN, type, buf, sizeof(buf));
117 
118 		if (gettimeofday(&end, NULL) != 0)
119 			err(1, "gettimeofday");
120 
121 		if (r != -1) {
122 			dump_packet(buf, r);
123 			printf("\n");
124 			if (dflag) {
125 				printf(";; Query time: %d msec\n",
126 				    msec(start, end));
127 				when = time(NULL);
128 				printf(";; WHEN: %s", ctime(&when));
129 			}
130 			printf(";; MSG SIZE  rcvd: %i\n", r);
131 		}
132 		print_errors();
133 	}
134 
135 	return (0);
136 }
137 
138 #define OPCODE_SHIFT	11
139 #define Z_SHIFT		4
140 
141 static char*
142 print_header(struct header *h, char *buf, size_t max)
143 {
144 	snprintf(buf, max,
145 	"id:0x.... %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
146 	    (h->flags & QR_MASK) ? "QR":"  ",
147 	    (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
148 	    (h->flags & AA_MASK) ? "AA":"  ",
149 	    (h->flags & TC_MASK) ? "TC":"  ",
150 	    (h->flags & RD_MASK) ? "RD":"  ",
151 	    (h->flags & RA_MASK) ? "RA":"  ",
152 	    ((h->flags & Z_MASK) >> Z_SHIFT),
153 	    rcodetostr(RCODE(h->flags)),
154 	    h->qdcount, h->ancount, h->nscount, h->arcount);
155 
156 	return buf;
157 }
158 
159 static void
160 dump_packet(const void *data, size_t len)
161 {
162 	char		buf[1024];
163 	struct packed	p;
164 	struct header	h;
165 	struct query	q;
166 	struct rr	rr;
167 	int		i, an, ns, ar, n;
168 
169 	packed_init(&p, (char *)data, len);
170 
171 	if (unpack_header(&p, &h) == -1) {
172 		printf(";; BAD PACKET: %s\n", p.err);
173 		return;
174 	}
175 
176 	printf(";; HEADER %s\n", print_header(&h, buf, sizeof buf));
177 
178 	if (h.qdcount)
179 		printf(";; QUERY SECTION:\n");
180 	for (i = 0; i < h.qdcount; i++) {
181 		if (unpack_query(&p, &q) == -1)
182 			goto error;
183 		printf("%s\n", print_query(&q, buf, sizeof buf));
184 	}
185 
186 	an = 0;
187 	ns = an + h.ancount;
188 	ar = ns + h.nscount;
189 	n = ar + h.arcount;
190 
191 	for (i = 0; i < n; i++) {
192 		if (i == an)
193 			printf("\n;; ANSWER SECTION:\n");
194 		if (i == ns)
195 			printf("\n;; AUTHORITY SECTION:\n");
196 		if (i == ar)
197 			printf("\n;; ADDITIONAL SECTION:\n");
198 
199 		if (unpack_rr(&p, &rr) == -1)
200 			goto error;
201 		printf("%s\n", print_rr(&rr, buf, sizeof buf));
202 	}
203 
204 	if (p.offset != len)
205 		printf(";; REMAINING GARBAGE %zu\n", len - p.offset);
206 
207     error:
208 	if (p.err)
209 		printf(";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
210 		    p.err);
211 }
212 
213 static const char *
214 inet6_ntoa(struct in6_addr a)
215 {
216 	static char buf[256];
217 	struct sockaddr_in6	si;
218 
219 	si.sin6_len = sizeof(si);
220 	si.sin6_family = PF_INET6;
221 	si.sin6_addr = a;
222 
223 	return print_host((struct sockaddr*)&si, buf, sizeof buf);
224 }
225 
226 static char*
227 print_rr(struct rr *rr, char *buf, size_t max)
228 {
229 	char	*res;
230 	char	 tmp[256];
231 	char	 tmp2[256];
232 	int	 r;
233 
234 	res = buf;
235 
236 	r = snprintf(buf, max, "%s %u %s %s ",
237 	    print_dname(rr->rr_dname, tmp, sizeof tmp),
238 	    rr->rr_ttl,
239 	    classtostr(rr->rr_class),
240 	    typetostr(rr->rr_type));
241 	if (r == -1) {
242 		buf[0] = '\0';
243 		return buf;
244 	}
245 
246 	if ((size_t)r >= max)
247 		return buf;
248 
249 	max -= r;
250 	buf += r;
251 
252 	switch(rr->rr_type) {
253 	case T_CNAME:
254 		print_dname(rr->rr.cname.cname, buf, max);
255 		break;
256 	case T_MX:
257 		snprintf(buf, max, "%"PRIu32" %s",
258 		    rr->rr.mx.preference,
259 		    print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
260 		break;
261 	case T_NS:
262 		print_dname(rr->rr.ns.nsname, buf, max);
263 		break;
264 	case T_PTR:
265 		print_dname(rr->rr.ptr.ptrname, buf, max);
266 		break;
267 	case T_SOA:
268 		snprintf(buf, max,
269 		    "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
270 		    print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
271 		    print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
272 		    rr->rr.soa.serial,
273 		    rr->rr.soa.refresh,
274 		    rr->rr.soa.retry,
275 		    rr->rr.soa.expire,
276 		    rr->rr.soa.minimum);
277 		break;
278 	case T_A:
279 		if (rr->rr_class != C_IN)
280 			goto other;
281 		snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr));
282 		break;
283 	case T_AAAA:
284 		if (rr->rr_class != C_IN)
285 			goto other;
286 		snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6));
287 		break;
288 	default:
289 	other:
290 		snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen);
291 		break;
292 	}
293 
294 	return (res);
295 }
296 
297 static char*
298 print_query(struct query *q, char *buf, size_t max)
299 {
300 	char b[256];
301 
302 	snprintf(buf, max, "%s	%s %s",
303 	    print_dname(q->q_dname, b, sizeof b),
304 	    classtostr(q->q_class), typetostr(q->q_type));
305 
306 	return (buf);
307 }
308 
309 
310 static char *
311 print_host(const struct sockaddr *sa, char *buf, size_t len)
312 {
313 	switch (sa->sa_family) {
314 	case AF_INET:
315 		inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, buf, len);
316 		break;
317 	case AF_INET6:
318 		inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr, buf, len);
319 		break;
320 	default:
321 		buf[0] = '\0';
322 	}
323 	return (buf);
324 }
325 
326 static char*
327 print_dname(const char *_dname, char *buf, size_t max)
328 {
329 	const unsigned char *dname = _dname;
330 	char	*res;
331 	size_t	 left, n, count;
332 
333 	if (_dname[0] == 0) {
334 		strlcpy(buf, ".", max);
335 		return buf;
336 	}
337 
338 	res = buf;
339 	left = max - 1;
340 	for (n = 0; dname[0] && left; n += dname[0]) {
341 		count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
342 		memmove(buf, dname + 1, count);
343 		dname += dname[0] + 1;
344 		left -= count;
345 		buf += count;
346 		if (left) {
347 			left -= 1;
348 			*buf++ = '.';
349 		}
350 	}
351 	buf[0] = 0;
352 
353 	return (res);
354 }
355