xref: /openbsd-src/lib/libc/asr/asr_debug.c (revision 92f7551051a82acd2ab08ca85a8c34ce754565a5)
1 /*	$OpenBSD: asr_debug.c,v 1.23 2017/02/17 22:24:45 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 #include <netinet/in.h>
21 #include <arpa/nameser.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 
25 #include <asr.h>
26 #include <resolv.h>
27 #include <string.h>
28 
29 #include "asr_private.h"
30 
31 static const char *rcodetostr(uint16_t);
32 static const char *print_dname(const char *, char *, size_t);
33 static const char *print_header(const struct asr_dns_header *, char *, size_t);
34 static const char *print_query(const struct asr_dns_query *, char *, size_t);
35 static const char *print_rr(const struct asr_dns_rr *, char *, size_t);
36 
37 FILE *_asr_debug = NULL;
38 
39 #define OPCODE_SHIFT	11
40 #define Z_SHIFT		 4
41 
42 static const char *
43 rcodetostr(uint16_t v)
44 {
45 	switch (v) {
46 	case NOERROR:	return "NOERROR";
47 	case FORMERR:	return "FORMERR";
48 	case SERVFAIL:	return "SERVFAIL";
49 	case NXDOMAIN:	return "NXDOMAIN";
50 	case NOTIMP:	return "NOTIMP";
51 	case REFUSED:	return "REFUSED";
52 	default:	return "?";
53 	}
54 }
55 
56 static const char *
57 print_dname(const char *_dname, char *buf, size_t max)
58 {
59 	return (_asr_strdname(_dname, buf, max));
60 }
61 
62 static const char *
63 print_rr(const struct asr_dns_rr *rr, char *buf, size_t max)
64 {
65 	char	*res;
66 	char	 tmp[256];
67 	char	 tmp2[256];
68 	int	 r;
69 
70 	res = buf;
71 
72 	r = snprintf(buf, max, "%s %u %s %s ",
73 	    print_dname(rr->rr_dname, tmp, sizeof tmp),
74 	    rr->rr_ttl,
75 	    __p_class(rr->rr_class),
76 	    __p_type(rr->rr_type));
77 	if (r == -1) {
78 		buf[0] = '\0';
79 		return (buf);
80 	}
81 
82 	if ((size_t)r >= max)
83 		return (buf);
84 
85 	max -= r;
86 	buf += r;
87 
88 	switch (rr->rr_type) {
89 	case T_CNAME:
90 		print_dname(rr->rr.cname.cname, buf, max);
91 		break;
92 	case T_MX:
93 		snprintf(buf, max, "%lu %s",
94 		    (unsigned long)rr->rr.mx.preference,
95 		    print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
96 		break;
97 	case T_NS:
98 		print_dname(rr->rr.ns.nsname, buf, max);
99 		break;
100 	case T_PTR:
101 		print_dname(rr->rr.ptr.ptrname, buf, max);
102 		break;
103 	case T_SOA:
104 		snprintf(buf, max, "%s %s %lu %lu %lu %lu %lu",
105 		    print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
106 		    print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
107 		    (unsigned long)rr->rr.soa.serial,
108 		    (unsigned long)rr->rr.soa.refresh,
109 		    (unsigned long)rr->rr.soa.retry,
110 		    (unsigned long)rr->rr.soa.expire,
111 		    (unsigned long)rr->rr.soa.minimum);
112 		break;
113 	case T_A:
114 		if (rr->rr_class != C_IN)
115 			goto other;
116 		snprintf(buf, max, "%s", inet_ntop(AF_INET,
117 		    &rr->rr.in_a.addr, tmp, sizeof tmp));
118 		break;
119 	case T_AAAA:
120 		if (rr->rr_class != C_IN)
121 			goto other;
122 		snprintf(buf, max, "%s", inet_ntop(AF_INET6,
123 		    &rr->rr.in_aaaa.addr6, tmp, sizeof tmp));
124 		break;
125 	default:
126 	other:
127 		snprintf(buf, max, "(rdlen=%i)", (int)rr->rr.other.rdlen);
128 		break;
129 	}
130 
131 	return (res);
132 }
133 
134 static const char *
135 print_query(const struct asr_dns_query *q, char *buf, size_t max)
136 {
137 	char b[256];
138 
139 	snprintf(buf, max, "%s	%s %s",
140 	    print_dname(q->q_dname, b, sizeof b),
141 	    __p_class(q->q_class), __p_type(q->q_type));
142 
143 	return (buf);
144 }
145 
146 static const char *
147 print_header(const struct asr_dns_header *h, char *buf, size_t max)
148 {
149 	snprintf(buf, max,
150 	"id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
151 	    ((int)h->id),
152 	    (h->flags & QR_MASK) ? "QR":"  ",
153 	    (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
154 	    (h->flags & AA_MASK) ? "AA":"  ",
155 	    (h->flags & TC_MASK) ? "TC":"  ",
156 	    (h->flags & RD_MASK) ? "RD":"  ",
157 	    (h->flags & RA_MASK) ? "RA":"  ",
158 	    ((h->flags & Z_MASK) >> Z_SHIFT),
159 	    rcodetostr(RCODE(h->flags)),
160 	    h->qdcount, h->ancount, h->nscount, h->arcount);
161 
162 	return (buf);
163 }
164 
165 void
166 _asr_dump_packet(FILE *f, const void *data, size_t len)
167 {
168 	char			buf[1024];
169 	struct asr_unpack	p;
170 	struct asr_dns_header	h;
171 	struct asr_dns_query	q;
172 	struct asr_dns_rr	rr;
173 	int			i, an, ns, ar, n;
174 
175 	if (f == NULL)
176 		return;
177 
178 	_asr_unpack_init(&p, data, len);
179 
180 	if (_asr_unpack_header(&p, &h) == -1) {
181 		fprintf(f, ";; BAD PACKET: %s\n", strerror(p.err));
182 		return;
183 	}
184 
185 	fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf));
186 
187 	if (h.qdcount)
188 		fprintf(f, ";; QUERY SECTION:\n");
189 	for (i = 0; i < h.qdcount; i++) {
190 		if (_asr_unpack_query(&p, &q) == -1)
191 			goto error;
192 		fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
193 	}
194 
195 	an = 0;
196 	ns = an + h.ancount;
197 	ar = ns + h.nscount;
198 	n = ar + h.arcount;
199 
200 	for (i = 0; i < n; i++) {
201 		if (i == an)
202 			fprintf(f, "\n;; ANSWER SECTION:\n");
203 		if (i == ns)
204 			fprintf(f, "\n;; AUTHORITY SECTION:\n");
205 		if (i == ar)
206 			fprintf(f, "\n;; ADDITIONAL SECTION:\n");
207 
208 		if (_asr_unpack_rr(&p, &rr) == -1)
209 			goto error;
210 		fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
211 	}
212 
213 	if (p.offset != len)
214 		fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
215 
216     error:
217 	if (p.err)
218 		fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
219 		    strerror(p.err));
220 }
221 
222 const char *
223 _asr_print_sockaddr(const struct sockaddr *sa, char *buf, size_t len)
224 {
225 	char	h[256];
226 	int	portno;
227 	union {
228 		const struct sockaddr		*sa;
229 		const struct sockaddr_in	*sin;
230 		const struct sockaddr_in6	*sin6;
231 	}	s;
232 
233 	s.sa = sa;
234 
235 	switch (sa->sa_family) {
236 	case AF_INET:
237 		inet_ntop(AF_INET, &s.sin->sin_addr, h, sizeof h);
238 		portno = ntohs(s.sin->sin_port);
239 		break;
240 	case AF_INET6:
241 		inet_ntop(AF_INET6, &s.sin6->sin6_addr, h, sizeof h);
242 		portno = ntohs(s.sin6->sin6_port);
243 		break;
244 	default:
245 		snprintf(buf, len, "?");
246 		return (buf);
247 	}
248 
249 	snprintf(buf, len, "%s:%i", h, portno);
250 	return (buf);
251 }
252 
253 void
254 _asr_dump_config(FILE *f, struct asr *a)
255 {
256 	char		 buf[256];
257 	int		 i;
258 	struct asr_ctx	*ac;
259 	unsigned int	 o;
260 
261 	if (f == NULL)
262 		return;
263 
264 	ac = a->a_ctx;
265 
266 	fprintf(f, "--------- ASR CONFIG ---------------\n");
267 	fprintf(f, "DOMAIN \"%s\"\n", ac->ac_domain);
268 	fprintf(f, "SEARCH\n");
269 	for (i = 0; i < ac->ac_domcount; i++)
270 		fprintf(f, "   \"%s\"\n", ac->ac_dom[i]);
271 	fprintf(f, "OPTIONS\n");
272 	fprintf(f, " options:");
273 	o = ac->ac_options;
274 
275 #define PRINTOPT(flag, n) if (o & (flag)) { fprintf(f, " " n); o &= ~(flag); }
276 	PRINTOPT(RES_INIT, "INIT");
277 	PRINTOPT(RES_DEBUG, "DEBUG");
278 	PRINTOPT(RES_USEVC, "USEVC");
279 	PRINTOPT(RES_IGNTC, "IGNTC");
280 	PRINTOPT(RES_RECURSE, "RECURSE");
281 	PRINTOPT(RES_DEFNAMES, "DEFNAMES");
282 	PRINTOPT(RES_STAYOPEN, "STAYOPEN");
283 	PRINTOPT(RES_DNSRCH, "DNSRCH");
284 	PRINTOPT(RES_NOALIASES, "NOALIASES");
285 	PRINTOPT(RES_USE_EDNS0, "USE_EDNS0");
286 	PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC");
287 	if (o)
288 		fprintf(f, " 0x%08x", o);
289 	fprintf(f, "\n");
290 
291 	fprintf(f, " ndots: %i\n", ac->ac_ndots);
292 	fprintf(f, " family:");
293 	for (i = 0; ac->ac_family[i] != -1; i++)
294 		fprintf(f, " %s", (ac->ac_family[i] == AF_INET)?"inet4":"inet6");
295 	fprintf(f, "\n");
296 	fprintf(f, "NAMESERVERS timeout=%i retry=%i\n",
297 		    ac->ac_nstimeout,
298 		    ac->ac_nsretries);
299 	for (i = 0; i < ac->ac_nscount; i++)
300 		fprintf(f, "	%s\n", _asr_print_sockaddr(ac->ac_ns[i], buf,
301 		    sizeof buf));
302 	fprintf(f, "LOOKUP %s", ac->ac_db);
303 	fprintf(f, "\n------------------------------------\n");
304 }
305 
306 #define CASE(n) case n: return #n
307 
308 const char *
309 _asr_statestr(int state)
310 {
311 	switch (state) {
312 	CASE(ASR_STATE_INIT);
313 	CASE(ASR_STATE_NEXT_DOMAIN);
314 	CASE(ASR_STATE_NEXT_DB);
315 	CASE(ASR_STATE_SAME_DB);
316 	CASE(ASR_STATE_NEXT_FAMILY);
317 	CASE(ASR_STATE_NEXT_NS);
318 	CASE(ASR_STATE_UDP_SEND);
319 	CASE(ASR_STATE_UDP_RECV);
320 	CASE(ASR_STATE_TCP_WRITE);
321 	CASE(ASR_STATE_TCP_READ);
322 	CASE(ASR_STATE_PACKET);
323 	CASE(ASR_STATE_SUBQUERY);
324 	CASE(ASR_STATE_NOT_FOUND);
325 	CASE(ASR_STATE_HALT);
326 	default:
327 		return "?";
328 	}
329 };
330 
331 const char *
332 _asr_querystr(int type)
333 {
334 	switch (type) {
335 	CASE(ASR_SEND);
336 	CASE(ASR_SEARCH);
337 	CASE(ASR_GETRRSETBYNAME);
338 	CASE(ASR_GETHOSTBYNAME);
339 	CASE(ASR_GETHOSTBYADDR);
340 	CASE(ASR_GETNETBYNAME);
341 	CASE(ASR_GETNETBYADDR);
342 	CASE(ASR_GETADDRINFO);
343 	CASE(ASR_GETNAMEINFO);
344 	default:
345 		return "?";
346 	}
347 }
348 
349 const char *
350 _asr_transitionstr(int type)
351 {
352 	switch (type) {
353 	CASE(ASYNC_COND);
354 	CASE(ASYNC_DONE);
355 	default:
356 		return "?";
357 	}
358 }
359