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