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