xref: /openbsd-src/lib/libc/asr/asr_debug.c (revision 931108e92d6451cf619fc74dec5b7d66c67f834c)
1*931108e9Sjca /*	$OpenBSD: asr_debug.c,v 1.28 2021/11/22 20:18:27 jca Exp $	*/
2b44da627Seric /*
3d4cf23afSeric  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4b44da627Seric  *
5b44da627Seric  * Permission to use, copy, modify, and distribute this software for any
6b44da627Seric  * purpose with or without fee is hereby granted, provided that the above
7b44da627Seric  * copyright notice and this permission notice appear in all copies.
8b44da627Seric  *
9b44da627Seric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b44da627Seric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b44da627Seric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b44da627Seric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b44da627Seric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b44da627Seric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b44da627Seric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b44da627Seric  */
1780f48568Seric 
18b44da627Seric #include <sys/types.h>
19b44da627Seric #include <sys/socket.h>
20b44da627Seric #include <netinet/in.h>
21b44da627Seric #include <arpa/nameser.h>
22d4cf23afSeric #include <arpa/inet.h>
23d216d6b1Seric #include <netdb.h>
24b44da627Seric 
25d216d6b1Seric #include <asr.h>
26b44da627Seric #include <resolv.h>
2792f75510Seric #include <string.h>
28b44da627Seric 
29b44da627Seric #include "asr_private.h"
30b44da627Seric 
31b44da627Seric static const char *rcodetostr(uint16_t);
32d4cf23afSeric static const char *print_dname(const char *, char *, size_t);
33f90bf415Seric static const char *print_header(const struct asr_dns_header *, char *, size_t);
34f90bf415Seric static const char *print_query(const struct asr_dns_query *, char *, size_t);
35f90bf415Seric static const char *print_rr(const struct asr_dns_rr *, char *, size_t);
36b44da627Seric 
3755f55055Seric FILE *_asr_debug = NULL;
38b44da627Seric 
39b44da627Seric #define OPCODE_SHIFT	11
40b44da627Seric 
41b44da627Seric static const char *
rcodetostr(uint16_t v)42b44da627Seric rcodetostr(uint16_t v)
43b44da627Seric {
44d4cf23afSeric 	switch (v) {
45d4cf23afSeric 	case NOERROR:	return "NOERROR";
46d4cf23afSeric 	case FORMERR:	return "FORMERR";
47d4cf23afSeric 	case SERVFAIL:	return "SERVFAIL";
48d4cf23afSeric 	case NXDOMAIN:	return "NXDOMAIN";
49d4cf23afSeric 	case NOTIMP:	return "NOTIMP";
50d4cf23afSeric 	case REFUSED:	return "REFUSED";
51d4cf23afSeric 	default:	return "?";
52d4cf23afSeric 	}
53b44da627Seric }
54b44da627Seric 
55b44da627Seric static const char *
print_dname(const char * _dname,char * buf,size_t max)56d4cf23afSeric print_dname(const char *_dname, char *buf, size_t max)
57b44da627Seric {
58253ef892Sderaadt 	return (_asr_strdname(_dname, buf, max));
59b44da627Seric }
60b44da627Seric 
61d4cf23afSeric static const char *
print_rr(const struct asr_dns_rr * rr,char * buf,size_t max)62f90bf415Seric print_rr(const struct asr_dns_rr *rr, char *buf, size_t max)
63b44da627Seric {
64b44da627Seric 	char	*res;
65b44da627Seric 	char	 tmp[256];
66b44da627Seric 	char	 tmp2[256];
67b44da627Seric 	int	 r;
68b44da627Seric 
69b44da627Seric 	res = buf;
70b44da627Seric 
71b44da627Seric 	r = snprintf(buf, max, "%s %u %s %s ",
72b44da627Seric 	    print_dname(rr->rr_dname, tmp, sizeof tmp),
73b44da627Seric 	    rr->rr_ttl,
74d4cf23afSeric 	    __p_class(rr->rr_class),
75d4cf23afSeric 	    __p_type(rr->rr_type));
76515e489cSderaadt 	if (r < 0 || r >= max) {
77b44da627Seric 		buf[0] = '\0';
78d4cf23afSeric 		return (buf);
79b44da627Seric 	}
80b44da627Seric 
81b44da627Seric 	if ((size_t)r >= max)
82d4cf23afSeric 		return (buf);
83b44da627Seric 
84b44da627Seric 	max -= r;
85b44da627Seric 	buf += r;
86b44da627Seric 
87b44da627Seric 	switch (rr->rr_type) {
88b44da627Seric 	case T_CNAME:
89b44da627Seric 		print_dname(rr->rr.cname.cname, buf, max);
90b44da627Seric 		break;
91b44da627Seric 	case T_MX:
92d4cf23afSeric 		snprintf(buf, max, "%lu %s",
93d4cf23afSeric 		    (unsigned long)rr->rr.mx.preference,
94b44da627Seric 		    print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
95b44da627Seric 		break;
96b44da627Seric 	case T_NS:
97b44da627Seric 		print_dname(rr->rr.ns.nsname, buf, max);
98b44da627Seric 		break;
99b44da627Seric 	case T_PTR:
100b44da627Seric 		print_dname(rr->rr.ptr.ptrname, buf, max);
101b44da627Seric 		break;
102b44da627Seric 	case T_SOA:
103d4cf23afSeric 		snprintf(buf, max, "%s %s %lu %lu %lu %lu %lu",
104e6029de6Seric 		    print_dname(rr->rr.soa.mname, tmp, sizeof tmp),
105e6029de6Seric 		    print_dname(rr->rr.soa.rname, tmp2, sizeof tmp2),
106d4cf23afSeric 		    (unsigned long)rr->rr.soa.serial,
107d4cf23afSeric 		    (unsigned long)rr->rr.soa.refresh,
108d4cf23afSeric 		    (unsigned long)rr->rr.soa.retry,
109d4cf23afSeric 		    (unsigned long)rr->rr.soa.expire,
110d4cf23afSeric 		    (unsigned long)rr->rr.soa.minimum);
111b44da627Seric 		break;
112b44da627Seric 	case T_A:
113b44da627Seric 		if (rr->rr_class != C_IN)
114b44da627Seric 			goto other;
115d4cf23afSeric 		snprintf(buf, max, "%s", inet_ntop(AF_INET,
116d4cf23afSeric 		    &rr->rr.in_a.addr, tmp, sizeof tmp));
117b44da627Seric 		break;
118b44da627Seric 	case T_AAAA:
119b44da627Seric 		if (rr->rr_class != C_IN)
120b44da627Seric 			goto other;
121d4cf23afSeric 		snprintf(buf, max, "%s", inet_ntop(AF_INET6,
122d4cf23afSeric 		    &rr->rr.in_aaaa.addr6, tmp, sizeof tmp));
123b44da627Seric 		break;
124b44da627Seric 	default:
125b44da627Seric 	other:
126d4cf23afSeric 		snprintf(buf, max, "(rdlen=%i)", (int)rr->rr.other.rdlen);
127b44da627Seric 		break;
128b44da627Seric 	}
129b44da627Seric 
130b44da627Seric 	return (res);
131b44da627Seric }
132b44da627Seric 
133d4cf23afSeric static const char *
print_query(const struct asr_dns_query * q,char * buf,size_t max)134f90bf415Seric print_query(const struct asr_dns_query *q, char *buf, size_t max)
135b44da627Seric {
136b44da627Seric 	char b[256];
137b44da627Seric 
138b44da627Seric 	snprintf(buf, max, "%s	%s %s",
139b44da627Seric 	    print_dname(q->q_dname, b, sizeof b),
140d4cf23afSeric 	    __p_class(q->q_class), __p_type(q->q_type));
141b44da627Seric 
142b44da627Seric 	return (buf);
143b44da627Seric }
144b44da627Seric 
145d4cf23afSeric static const char *
print_header(const struct asr_dns_header * h,char * buf,size_t max)146f90bf415Seric print_header(const struct asr_dns_header *h, char *buf, size_t max)
147b44da627Seric {
148b44da627Seric 	snprintf(buf, max,
1493aff1a83Sjca 	"id:0x%04x %s op:%i %s %s %s %s z:%i %s %s r:%s qd:%i an:%i ns:%i ar:%i",
150d4cf23afSeric 	    ((int)h->id),
151b44da627Seric 	    (h->flags & QR_MASK) ? "QR":"  ",
152b44da627Seric 	    (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
153b44da627Seric 	    (h->flags & AA_MASK) ? "AA":"  ",
154b44da627Seric 	    (h->flags & TC_MASK) ? "TC":"  ",
155b44da627Seric 	    (h->flags & RD_MASK) ? "RD":"  ",
156b44da627Seric 	    (h->flags & RA_MASK) ? "RA":"  ",
1573aff1a83Sjca 	    (h->flags & Z_MASK),
1583aff1a83Sjca 	    (h->flags & AD_MASK) ? "AD":"  ",
1593aff1a83Sjca 	    (h->flags & CD_MASK) ? "CD":"  ",
160b44da627Seric 	    rcodetostr(RCODE(h->flags)),
161b44da627Seric 	    h->qdcount, h->ancount, h->nscount, h->arcount);
162b44da627Seric 
163b44da627Seric 	return (buf);
164b44da627Seric }
165b44da627Seric 
166b44da627Seric void
_asr_dump_packet(FILE * f,const void * data,size_t len)167253ef892Sderaadt _asr_dump_packet(FILE *f, const void *data, size_t len)
168b44da627Seric {
169b44da627Seric 	char			buf[1024];
170f90bf415Seric 	struct asr_unpack	p;
171f90bf415Seric 	struct asr_dns_header	h;
172f90bf415Seric 	struct asr_dns_query	q;
173f90bf415Seric 	struct asr_dns_rr	rr;
174b44da627Seric 	int			i, an, ns, ar, n;
175b44da627Seric 
176b44da627Seric 	if (f == NULL)
177b44da627Seric 		return;
178b44da627Seric 
179253ef892Sderaadt 	_asr_unpack_init(&p, data, len);
180b44da627Seric 
181253ef892Sderaadt 	if (_asr_unpack_header(&p, &h) == -1) {
18292f75510Seric 		fprintf(f, ";; BAD PACKET: %s\n", strerror(p.err));
183b44da627Seric 		return;
184b44da627Seric 	}
185b44da627Seric 
186d4cf23afSeric 	fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf));
187b44da627Seric 
188b44da627Seric 	if (h.qdcount)
189b44da627Seric 		fprintf(f, ";; QUERY SECTION:\n");
190b44da627Seric 	for (i = 0; i < h.qdcount; i++) {
191253ef892Sderaadt 		if (_asr_unpack_query(&p, &q) == -1)
192b44da627Seric 			goto error;
193b44da627Seric 		fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
194b44da627Seric 	}
195b44da627Seric 
196b44da627Seric 	an = 0;
197b44da627Seric 	ns = an + h.ancount;
198b44da627Seric 	ar = ns + h.nscount;
199b44da627Seric 	n = ar + h.arcount;
200b44da627Seric 
201b44da627Seric 	for (i = 0; i < n; i++) {
202b44da627Seric 		if (i == an)
203b44da627Seric 			fprintf(f, "\n;; ANSWER SECTION:\n");
204b44da627Seric 		if (i == ns)
205b44da627Seric 			fprintf(f, "\n;; AUTHORITY SECTION:\n");
206b44da627Seric 		if (i == ar)
207b44da627Seric 			fprintf(f, "\n;; ADDITIONAL SECTION:\n");
208b44da627Seric 
209253ef892Sderaadt 		if (_asr_unpack_rr(&p, &rr) == -1)
210b44da627Seric 			goto error;
211b44da627Seric 		fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
212b44da627Seric 	}
213b44da627Seric 
214b44da627Seric 	if (p.offset != len)
215b44da627Seric 		fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
216b44da627Seric 
217b44da627Seric     error:
218b44da627Seric 	if (p.err)
219b44da627Seric 		fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
22092f75510Seric 		    strerror(p.err));
221b44da627Seric }
222b44da627Seric 
223d4cf23afSeric const char *
_asr_print_sockaddr(const struct sockaddr * sa,char * buf,size_t len)224253ef892Sderaadt _asr_print_sockaddr(const struct sockaddr *sa, char *buf, size_t len)
225b44da627Seric {
226d4cf23afSeric 	char	h[256];
227d4cf23afSeric 	int	portno;
228d4cf23afSeric 	union {
229d4cf23afSeric 		const struct sockaddr		*sa;
230d4cf23afSeric 		const struct sockaddr_in	*sin;
231d4cf23afSeric 		const struct sockaddr_in6	*sin6;
232d4cf23afSeric 	}	s;
233b44da627Seric 
234d4cf23afSeric 	s.sa = sa;
23546ab4803Seric 
236d4cf23afSeric 	switch (sa->sa_family) {
237d4cf23afSeric 	case AF_INET:
238d4cf23afSeric 		inet_ntop(AF_INET, &s.sin->sin_addr, h, sizeof h);
239d4cf23afSeric 		portno = ntohs(s.sin->sin_port);
240d4cf23afSeric 		break;
241d4cf23afSeric 	case AF_INET6:
242d4cf23afSeric 		inet_ntop(AF_INET6, &s.sin6->sin6_addr, h, sizeof h);
243d4cf23afSeric 		portno = ntohs(s.sin6->sin6_port);
244d4cf23afSeric 		break;
245d4cf23afSeric 	default:
246d4cf23afSeric 		snprintf(buf, len, "?");
247d4cf23afSeric 		return (buf);
248d4cf23afSeric 	}
249d4cf23afSeric 
250d4cf23afSeric 	snprintf(buf, len, "%s:%i", h, portno);
251d4cf23afSeric 	return (buf);
252b44da627Seric }
253b44da627Seric 
254b44da627Seric void
_asr_dump_config(FILE * f,struct asr * a)255253ef892Sderaadt _asr_dump_config(FILE *f, struct asr *a)
256b44da627Seric {
257d4cf23afSeric 	char		 buf[256];
258d4cf23afSeric 	int		 i;
259d4cf23afSeric 	struct asr_ctx	*ac;
260d4cf23afSeric 	unsigned int	 o;
261d4cf23afSeric 
262d4cf23afSeric 	if (f == NULL)
263d4cf23afSeric 		return;
264d4cf23afSeric 
265d4cf23afSeric 	ac = a->a_ctx;
266d4cf23afSeric 
267d4cf23afSeric 	fprintf(f, "--------- ASR CONFIG ---------------\n");
268d4cf23afSeric 	fprintf(f, "DOMAIN \"%s\"\n", ac->ac_domain);
269d4cf23afSeric 	fprintf(f, "SEARCH\n");
270d4cf23afSeric 	for (i = 0; i < ac->ac_domcount; i++)
271d4cf23afSeric 		fprintf(f, "   \"%s\"\n", ac->ac_dom[i]);
272d4cf23afSeric 	fprintf(f, "OPTIONS\n");
273d4cf23afSeric 	fprintf(f, " options:");
274d4cf23afSeric 	o = ac->ac_options;
275d4cf23afSeric 
276d4cf23afSeric #define PRINTOPT(flag, n) if (o & (flag)) { fprintf(f, " " n); o &= ~(flag); }
277d4cf23afSeric 	PRINTOPT(RES_INIT, "INIT");
278d4cf23afSeric 	PRINTOPT(RES_DEBUG, "DEBUG");
279d4cf23afSeric 	PRINTOPT(RES_USEVC, "USEVC");
280d4cf23afSeric 	PRINTOPT(RES_IGNTC, "IGNTC");
281d4cf23afSeric 	PRINTOPT(RES_RECURSE, "RECURSE");
282d4cf23afSeric 	PRINTOPT(RES_DEFNAMES, "DEFNAMES");
283d4cf23afSeric 	PRINTOPT(RES_STAYOPEN, "STAYOPEN");
284d4cf23afSeric 	PRINTOPT(RES_DNSRCH, "DNSRCH");
285d4cf23afSeric 	PRINTOPT(RES_NOALIASES, "NOALIASES");
286d4cf23afSeric 	PRINTOPT(RES_USE_EDNS0, "USE_EDNS0");
287d4cf23afSeric 	PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC");
288e6029de6Seric 	PRINTOPT(RES_USE_CD, "USE_CD");
289*931108e9Sjca 	PRINTOPT(RES_TRUSTAD, "TRUSTAD");
290d4cf23afSeric 	if (o)
291d4cf23afSeric 		fprintf(f, " 0x%08x", o);
292d4cf23afSeric 	fprintf(f, "\n");
293d4cf23afSeric 
294d4cf23afSeric 	fprintf(f, " ndots: %i\n", ac->ac_ndots);
295d4cf23afSeric 	fprintf(f, " family:");
296d4cf23afSeric 	for (i = 0; ac->ac_family[i] != -1; i++)
2976a166a79Sotto 		fprintf(f, " %s", (ac->ac_family[i] == AF_INET)?"inet4":"inet6");
298d4cf23afSeric 	fprintf(f, "\n");
299d4cf23afSeric 	fprintf(f, "NAMESERVERS timeout=%i retry=%i\n",
300d4cf23afSeric 		    ac->ac_nstimeout,
301d4cf23afSeric 		    ac->ac_nsretries);
302d4cf23afSeric 	for (i = 0; i < ac->ac_nscount; i++)
303253ef892Sderaadt 		fprintf(f, "	%s\n", _asr_print_sockaddr(ac->ac_ns[i], buf,
304d4cf23afSeric 		    sizeof buf));
3051ed934d0Seric 	fprintf(f, "LOOKUP %s", ac->ac_db);
306d4cf23afSeric 	fprintf(f, "\n------------------------------------\n");
307d4cf23afSeric }
308d4cf23afSeric 
309d4cf23afSeric #define CASE(n) case n: return #n
310d4cf23afSeric 
311d4cf23afSeric const char *
_asr_statestr(int state)312253ef892Sderaadt _asr_statestr(int state)
313d4cf23afSeric {
314d4cf23afSeric 	switch (state) {
315d4cf23afSeric 	CASE(ASR_STATE_INIT);
316d4cf23afSeric 	CASE(ASR_STATE_NEXT_DOMAIN);
317d4cf23afSeric 	CASE(ASR_STATE_NEXT_DB);
318d4cf23afSeric 	CASE(ASR_STATE_SAME_DB);
319d4cf23afSeric 	CASE(ASR_STATE_NEXT_FAMILY);
320d4cf23afSeric 	CASE(ASR_STATE_NEXT_NS);
321d4cf23afSeric 	CASE(ASR_STATE_UDP_SEND);
322d4cf23afSeric 	CASE(ASR_STATE_UDP_RECV);
323d4cf23afSeric 	CASE(ASR_STATE_TCP_WRITE);
324d4cf23afSeric 	CASE(ASR_STATE_TCP_READ);
325d4cf23afSeric 	CASE(ASR_STATE_PACKET);
326d4cf23afSeric 	CASE(ASR_STATE_SUBQUERY);
327d4cf23afSeric 	CASE(ASR_STATE_NOT_FOUND);
328d4cf23afSeric 	CASE(ASR_STATE_HALT);
329d4cf23afSeric 	default:
330d4cf23afSeric 		return "?";
331d4cf23afSeric 	}
332d4cf23afSeric };
333d4cf23afSeric 
334d4cf23afSeric const char *
_asr_querystr(int type)335253ef892Sderaadt _asr_querystr(int type)
336d4cf23afSeric {
337d4cf23afSeric 	switch (type) {
338d4cf23afSeric 	CASE(ASR_SEND);
339d4cf23afSeric 	CASE(ASR_SEARCH);
340d4cf23afSeric 	CASE(ASR_GETRRSETBYNAME);
341d4cf23afSeric 	CASE(ASR_GETHOSTBYNAME);
342d4cf23afSeric 	CASE(ASR_GETHOSTBYADDR);
343d4cf23afSeric 	CASE(ASR_GETADDRINFO);
344d4cf23afSeric 	CASE(ASR_GETNAMEINFO);
345d4cf23afSeric 	default:
346d4cf23afSeric 		return "?";
347d4cf23afSeric 	}
348d4cf23afSeric }
349d4cf23afSeric 
350d4cf23afSeric const char *
_asr_transitionstr(int type)351253ef892Sderaadt _asr_transitionstr(int type)
352d4cf23afSeric {
353d4cf23afSeric 	switch (type) {
354d4cf23afSeric 	CASE(ASYNC_COND);
355d4cf23afSeric 	CASE(ASYNC_DONE);
356d4cf23afSeric 	default:
357d4cf23afSeric 		return "?";
358d4cf23afSeric 	}
359b44da627Seric }
360