1/*	$OpenBSD: res_mkquery.c,v 1.3 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
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 */
37static void dump_packet(const void *, size_t);
38
39static char *print_query(struct query *, char *, size_t);
40static char *print_rr(struct rr *, char *, size_t);
41static char *print_host(const struct sockaddr *, char *, size_t);
42static char* print_dname(const char *, char *, size_t);
43
44
45static void
46usage(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
55int
56main(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
109static char*
110print_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
127static void
128dump_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
181static const char *
182inet6_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
194static char*
195print_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
265static char*
266print_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
278static char *
279print_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
294static char*
295print_dname(const char *_dname, char *buf, size_t max)
296{
297	const unsigned char *dname = _dname;
298	char	*res;
299	size_t	 left, count;
300
301	if (_dname[0] == 0) {
302		strlcpy(buf, ".", max);
303		return buf;
304	}
305
306	res = buf;
307	left = max - 1;
308	while (dname[0] && left) {
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