xref: /openbsd-src/lib/libc/asr/asr_debug.c (revision 68cad45c03231783b0da81f6a64d823fad170129)
1 /*	$OpenBSD: asr_debug.c,v 1.2 2012/04/15 21:42:58 eric Exp $	*/
2 /*
3  * Copyright (c) 2010-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 #include <sys/types.h>
18 #include <sys/socket.h>
19 
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <arpa/nameser.h>
23 
24 #include <inttypes.h>
25 #include <resolv.h>
26 #include <string.h>
27 #include <stdarg.h>
28 
29 #include "asr.h"
30 #include "asr_private.h"
31 
32 static void asr_vdebug(const char *, va_list);
33 
34 static char *print_dname(const char *, char *, size_t);
35 static char *print_host(const struct sockaddr *, char *, size_t);
36 
37 static const char *typetostr(uint16_t);
38 static const char *classtostr(uint16_t);
39 static const char *rcodetostr(uint16_t);
40 
41 static const char *inet6_ntoa(struct in6_addr);
42 
43 
44 #define OPCODE_SHIFT	11
45 #define Z_SHIFT		 4
46 
47 struct keyval {
48 	const char	*key;
49 	uint16_t	 value;
50 };
51 
52 static struct keyval kv_class[] = {
53 	{ "IN",	C_IN },
54 	{ "CHAOS", C_CHAOS },
55 	{ "HS", C_HS },
56 	{ "ANY", C_ANY },
57 	{ NULL, 	0 },
58 };
59 
60 static struct keyval kv_type[] = {
61 	{ "A",		T_A	},
62 	{ "NS",		T_NS	},
63 	{ "MD",		T_MD	},
64 	{ "MF",		T_MF	},
65 	{ "CNAME",	T_CNAME	},
66 	{ "SOA",	T_SOA	},
67 	{ "MB",		T_MB	},
68 	{ "MG",		T_MG	},
69 	{ "MR",		T_MR	},
70 	{ "NULL",	T_NULL	},
71 	{ "WKS",	T_WKS	},
72 	{ "PTR",	T_PTR	},
73 	{ "HINFO",	T_HINFO	},
74 	{ "MINFO",	T_MINFO	},
75 	{ "MX",		T_MX	},
76 	{ "TXT",	T_TXT	},
77 
78 	{ "AAAA",	T_AAAA	},
79 
80 	{ "AXFR",	T_AXFR	},
81 	{ "MAILB",	T_MAILB	},
82 	{ "MAILA",	T_MAILA	},
83 	{ "ANY",	T_ANY	},
84 	{ NULL, 	0 },
85 };
86 
87 static struct keyval kv_rcode[] = {
88 	{ "NOERROR",	NOERROR	},
89 	{ "FORMERR",	FORMERR },
90 	{ "SERVFAIL",	SERVFAIL },
91 	{ "NXDOMAIN",	NXDOMAIN },
92 	{ "NOTIMP",	NOTIMP },
93 	{ "REFUSED",	REFUSED },
94 	{ NULL, 	0 },
95 };
96 
97 static const char *
98 typetostr(uint16_t v)
99 {
100 	static char	 buf[16];
101 	size_t		 i;
102 
103 	for(i = 0; kv_type[i].key; i++)
104 		if (kv_type[i].value == v)
105 			return (kv_type[i].key);
106 
107 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
108 
109 	return (buf);
110 }
111 
112 static const char *
113 classtostr(uint16_t v)
114 {
115 	static char	 buf[16];
116 	size_t		 i;
117 
118 	for(i = 0; kv_class[i].key; i++)
119 		if (kv_class[i].value == v)
120 			return (kv_class[i].key);
121 
122 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
123 
124 	return (buf);
125 }
126 
127 static const char *
128 rcodetostr(uint16_t v)
129 {
130 	static char      buf[16];
131 	size_t           i;
132 
133 	for(i = 0; kv_rcode[i].key; i++)
134 		if (kv_rcode[i].value == v)
135 			return (kv_rcode[i].key);
136 
137 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
138 
139 	return (buf);
140 }
141 
142 static const char *
143 inet6_ntoa(struct in6_addr a)
144 {
145 	static char buf[256];
146 	struct sockaddr_in6	si;
147 
148 	si.sin6_len = sizeof(si);
149 	si.sin6_family = PF_INET6;
150 	si.sin6_addr = a;
151 
152 	return print_host((struct sockaddr*)&si, buf, sizeof buf);
153 }
154 
155 static char*
156 print_rr(struct rr *rr, char *buf, size_t max)
157 {
158 	char	*res;
159 	char	 tmp[256];
160 	char	 tmp2[256];
161 	int	 r;
162 
163 	res = buf;
164 
165 	r = snprintf(buf, max, "%s %u %s %s ",
166 	    print_dname(rr->rr_dname, tmp, sizeof tmp),
167 	    rr->rr_ttl,
168 	    classtostr(rr->rr_class),
169 	    typetostr(rr->rr_type));
170 	if (r == -1) {
171 		buf[0] = '\0';
172 		return buf;
173 	}
174 
175 	if ((size_t)r >= max)
176 		return buf;
177 
178 	max -= r;
179 	buf += r;
180 
181 	switch(rr->rr_type) {
182 	case T_CNAME:
183 		print_dname(rr->rr.cname.cname, buf, max);
184 		break;
185 	case T_MX:
186 		snprintf(buf, max, "%"PRIu32" %s",
187 		    rr->rr.mx.preference,
188 		    print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
189 		break;
190 	case T_NS:
191 		print_dname(rr->rr.ns.nsname, buf, max);
192 		break;
193 	case T_PTR:
194 		print_dname(rr->rr.ptr.ptrname, buf, max);
195 		break;
196 	case T_SOA:
197 		snprintf(buf, max,
198 		    "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
199 		    print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
200 		    print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
201 		    rr->rr.soa.serial,
202 		    rr->rr.soa.refresh,
203 		    rr->rr.soa.retry,
204 		    rr->rr.soa.expire,
205 		    rr->rr.soa.minimum);
206 		break;
207 	case T_A:
208 		if (rr->rr_class != C_IN)
209 			goto other;
210 		snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr));
211 		break;
212 	case T_AAAA:
213 		if (rr->rr_class != C_IN)
214 			goto other;
215 		snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6));
216 		break;
217 	default:
218 	other:
219 		snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen);
220 		break;
221 	}
222 
223 	return (res);
224 }
225 
226 static char*
227 print_query(struct query *q, char *buf, size_t max)
228 {
229 	char b[256];
230 
231 	snprintf(buf, max, "%s	%s %s",
232 	    print_dname(q->q_dname, b, sizeof b),
233 	    classtostr(q->q_class), typetostr(q->q_type));
234 
235 	return (buf);
236 }
237 
238 static char*
239 print_dname(const char *_dname, char *buf, size_t max)
240 {
241 	return asr_strdname(_dname, buf, max);
242 }
243 
244 static char*
245 print_header(struct header *h, char *buf, size_t max, int noid)
246 {
247 	snprintf(buf, max,
248 	"id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
249 	    noid ? 0 : ((int)h->id),
250 	    (h->flags & QR_MASK) ? "QR":"  ",
251 	    (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
252 	    (h->flags & AA_MASK) ? "AA":"  ",
253 	    (h->flags & TC_MASK) ? "TC":"  ",
254 	    (h->flags & RD_MASK) ? "RD":"  ",
255 	    (h->flags & RA_MASK) ? "RA":"  ",
256 	    ((h->flags & Z_MASK) >> Z_SHIFT),
257 	    rcodetostr(RCODE(h->flags)),
258 	    h->qdcount, h->ancount, h->nscount, h->arcount);
259 
260 	return buf;
261 }
262 
263 static char *
264 print_host(const struct sockaddr *sa, char *buf, size_t len)
265 {
266 	switch (sa->sa_family) {
267 	case AF_INET:
268 		inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, buf, len);
269 		break;
270 	case AF_INET6:
271 		inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr, buf, len);
272 		break;
273 	default:
274 		buf[0] = '\0';
275 	}
276 	return (buf);
277 }
278 
279 char *
280 print_addr(const struct sockaddr *sa, char *buf, size_t len)
281 {
282 	char	h[256];
283 
284 	print_host(sa, h, sizeof h);
285 
286 	switch (sa->sa_family) {
287 	case AF_INET:
288 		snprintf(buf, len, "%s:%i", h,
289 		    ntohs(((struct sockaddr_in*)(sa))->sin_port));
290 		break;
291 	case AF_INET6:
292 		snprintf(buf, len, "[%s]:%i", h,
293 		    ntohs(((struct sockaddr_in6*)(sa))->sin6_port));
294 		break;
295 	default:
296 		snprintf(buf, len, "?");
297 		break;
298 	}
299 
300 	return (buf);
301 }
302 
303 struct kv { int code; const char *name; };
304 
305 static const char*	kvlookup(struct kv *, int);
306 
307 int	 asr_debug = 0;
308 
309 void
310 asr_dump(struct asr *a)
311 {
312 	char		 buf[256];
313 	int		 i;
314 	struct asr_ctx	*ac;
315 	unsigned int	 options;
316 
317 	ac = a->a_ctx;
318 
319 	asr_printf("--------- ASR CONFIG ---------------\n");
320 	if (a->a_path)
321 		asr_printf("CONF FILE \"%s\"\n", a->a_path);
322 	else
323 		asr_printf("STATIC CONF\n");
324 	asr_printf("DOMAIN \"%s\"\n", ac->ac_domain);
325 	asr_printf("SEARCH\n");
326 	for(i = 0; i < ac->ac_domcount; i++)
327 		asr_printf("   \"%s\"\n", ac->ac_dom[i]);
328 	asr_printf("OPTIONS\n");
329 	asr_printf(" options:");
330 	options = ac->ac_options;
331 	if (options & RES_INIT) {
332 		asr_printf(" INIT"); options &= ~RES_INIT;
333 	}
334 	if (options & RES_DEBUG) {
335 		asr_printf(" DEBUG"); options &= ~RES_DEBUG;
336 	}
337 	if (options & RES_USEVC) {
338 		asr_printf(" USEVC"); options &= ~RES_USEVC;
339 	}
340 	if (options & RES_IGNTC) {
341 		asr_printf(" IGNTC"); options &= ~RES_IGNTC;
342 	}
343 	if (options & RES_RECURSE) {
344 		asr_printf(" RECURSE"); options &= ~RES_RECURSE;
345 	}
346 	if (options & RES_DEFNAMES) {
347 		asr_printf(" DEFNAMES"); options &= ~RES_DEFNAMES;
348 	}
349 	if (options & RES_STAYOPEN) {
350 		asr_printf(" STAYOPEN"); options &= ~RES_STAYOPEN;
351 	}
352 	if (options & RES_DNSRCH) {
353 		asr_printf(" DNSRCH"); options &= ~RES_DNSRCH;
354 	}
355 	if (options & RES_NOALIASES) {
356 		asr_printf(" NOALIASES"); options &= ~RES_NOALIASES;
357 	}
358 	if (options & RES_USE_EDNS0) {
359 		asr_printf(" USE_EDNS0"); options &= ~RES_USE_EDNS0;
360 	}
361 	if (options & RES_USE_DNSSEC) {
362 		asr_printf(" USE_DNSSEC"); options &= ~RES_USE_DNSSEC;
363 	}
364 	if (options)
365 		asr_printf("0x%08x\n", options);
366 	asr_printf("\n", ac->ac_options);
367 
368 	asr_printf(" ndots: %i\n", ac->ac_ndots);
369 	asr_printf(" family:");
370 	for(i = 0; ac->ac_family[i] != -1; i++)
371 		asr_printf(" %s", (ac->ac_family[i] == AF_INET) ? "inet" : "inet6");
372 	asr_printf("\n");
373 	asr_printf("NAMESERVERS timeout=%i retry=%i\n",
374 		   ac->ac_nstimeout,
375 		   ac->ac_nsretries);
376 	for(i = 0; i < ac->ac_nscount; i++)
377 		asr_printf("	%s\n", print_addr(ac->ac_ns[i], buf, sizeof buf));
378 	asr_printf("HOSTFILE %s\n", ac->ac_hostfile);
379 	asr_printf("LOOKUP");
380 	for(i = 0; i < ac->ac_dbcount; i++) {
381 		switch (ac->ac_db[i]) {
382 		case ASR_DB_FILE:
383 			asr_printf(" file");
384 			break;
385 		case ASR_DB_DNS:
386 			asr_printf(" dns");
387 			break;
388 		case ASR_DB_YP:
389 			asr_printf(" yp");
390 			break;
391 		default:
392 			asr_printf(" ?%i", ac->ac_db[i]);
393 		}
394 	}
395 	asr_printf("\n------------------------------------\n");
396 }
397 
398 static const char *
399 kvlookup(struct kv *kv, int code)
400 {
401 	while (kv->name) {
402 		if (kv->code == code)
403 			return (kv->name);
404 		kv++;
405 	}
406 	return "???";
407 }
408 
409 struct kv kv_query_type[] = {
410 	{ ASR_SEND,		"ASR_SEND"		},
411 	{ ASR_SEARCH,		"ASR_SEARCH"		},
412 	{ ASR_GETRRSETBYNAME,	"ASR_GETRRSETBYNAME"	},
413 	{ ASR_GETHOSTBYNAME,	"ASR_GETHOSTBYNAME"	},
414 	{ ASR_GETHOSTBYADDR,	"ASR_GETHOSTBYADDR"	},
415 	{ ASR_GETNETBYNAME,	"ASR_GETNETBYNAME"	},
416 	{ ASR_GETNETBYADDR,	"ASR_GETNETBYADDR"	},
417 	{ ASR_GETADDRINFO,	"ASR_GETADDRINFO"	},
418 	{ ASR_GETNAMEINFO,	"ASR_GETNAMEINFO"	},
419 	{ ASR_HOSTADDR,		"ASR_HOSTADDR"		},
420 	{ 0, NULL }
421 };
422 
423 struct kv kv_db_type[] = {
424 	{ ASR_DB_FILE,			"ASR_DB_FILE"			},
425 	{ ASR_DB_DNS,			"ASR_DB_DNS"			},
426 	{ ASR_DB_YP,			"ASR_DB_YP"			},
427 	{ 0, NULL }
428 };
429 
430 struct kv kv_state[] = {
431 	{ ASR_STATE_INIT,		"ASR_STATE_INIT"		},
432 	{ ASR_STATE_SEARCH_DOMAIN,	"ASR_STATE_SEARCH_DOMAIN"	},
433 	{ ASR_STATE_LOOKUP_DOMAIN,	"ASR_STATE_LOOKUP_DOMAIN"	},
434 	{ ASR_STATE_NEXT_DOMAIN,	"ASR_STATE_NEXT_DOMAIN"		},
435 	{ ASR_STATE_NEXT_DB,		"ASR_STATE_NEXT_DB"		},
436 	{ ASR_STATE_SAME_DB,		"ASR_STATE_SAME_DB"		},
437 	{ ASR_STATE_NEXT_FAMILY,	"ASR_STATE_NEXT_FAMILY"		},
438 	{ ASR_STATE_LOOKUP_FAMILY,	"ASR_STATE_LOOKUP_FAMILY"	},
439 	{ ASR_STATE_NEXT_NS,		"ASR_STATE_NEXT_NS"		},
440 	{ ASR_STATE_READ_RR,		"ASR_STATE_READ_RR"		},
441 	{ ASR_STATE_READ_FILE,		"ASR_STATE_READ_FILE"		},
442 	{ ASR_STATE_UDP_SEND,		"ASR_STATE_UDP_SEND"		},
443 	{ ASR_STATE_UDP_RECV,		"ASR_STATE_UDP_RECV"		},
444 	{ ASR_STATE_TCP_WRITE,		"ASR_STATE_TCP_WRITE"		},
445 	{ ASR_STATE_TCP_READ,		"ASR_STATE_TCP_READ"		},
446 	{ ASR_STATE_PACKET,		"ASR_STATE_PACKET"		},
447 	{ ASR_STATE_SUBQUERY,		"ASR_STATE_SUBQUERY"		},
448 	{ ASR_STATE_NOT_FOUND,		"ASR_STATE_NOT_FOUND",		},
449 	{ ASR_STATE_HALT,		"ASR_STATE_HALT"		},
450 	{ 0, NULL }
451 };
452 
453 struct kv kv_transition[] = {
454 	{ ASYNC_COND,			"ASYNC_COND"			},
455 	{ ASYNC_YIELD,			"ASYNC_YIELD"			},
456 	{ ASYNC_DONE,			"ASYNC_DONE"			},
457         { 0, NULL }
458 };
459 
460 const char *
461 asr_querystr(int type)
462 {
463 	return kvlookup(kv_query_type, type);
464 }
465 
466 const char *
467 asr_transitionstr(int type)
468 {
469 	return kvlookup(kv_transition, type);
470 }
471 
472 void
473 asr_dump_async(struct async *as)
474 {
475 	asr_printf("%s fd=%i timeout=%i"
476 		"   dom_idx=%i db_idx=%i ns_idx=%i ns_cycles=%i\n",
477 		kvlookup(kv_state, as->as_state),
478 		as->as_fd,
479 		as->as_timeout,
480 
481 		as->as_dom_idx,
482 		as->as_db_idx,
483 		as->as_ns_idx,
484 		as->as_ns_cycles);
485 }
486 
487 void
488 asr_dump_packet(FILE *f, const void *data, size_t len, int noid)
489 {
490 	char		buf[1024];
491 	struct packed	p;
492 	struct header	h;
493 	struct query	q;
494 	struct rr	rr;
495 	int		i, an, ns, ar, n;
496 
497 	if (f == NULL)
498 		return;
499 
500 	packed_init(&p, (char *)data, len);
501 
502 	if (unpack_header(&p, &h) == -1) {
503 		fprintf(f, ";; BAD PACKET: %s\n", p.err);
504 		return;
505 	}
506 
507 	fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf, noid));
508 
509 	if (h.qdcount)
510 		fprintf(f, ";; QUERY SECTION:\n");
511 	for (i = 0; i < h.qdcount; i++) {
512 		if (unpack_query(&p, &q) == -1)
513 			goto error;
514 		fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
515 	}
516 
517 	an = 0;
518 	ns = an + h.ancount;
519 	ar = ns + h.nscount;
520 	n = ar + h.arcount;
521 
522 	for (i = 0; i < n; i++) {
523 		if (i == an)
524 			fprintf(f, "\n;; ANSWER SECTION:\n");
525 		if (i == ns)
526 			fprintf(f, "\n;; AUTHORITY SECTION:\n");
527 		if (i == ar)
528 			fprintf(f, "\n;; ADDITIONAL SECTION:\n");
529 
530 		if (unpack_rr(&p, &rr) == -1)
531 			goto error;
532 		fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
533 	}
534 
535 	if (p.offset != len)
536 		fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
537 
538     error:
539 	if (p.err)
540 		fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
541 		    p.err);
542 
543 	return;
544 }
545 
546 static void
547 asr_vdebug(const char *fmt, va_list ap)
548 {
549 	if (asr_debug)
550 		vfprintf(stderr, fmt, ap);
551 }
552 
553 void
554 asr_printf(const char *fmt, ...)
555 {
556 	va_list ap;
557 
558 	va_start(ap, fmt);
559 	asr_vdebug(fmt, ap);
560 	va_end(ap);
561 }
562 
563 void
564 async_set_state(struct async *as, int state)
565 {
566 	asr_printf("asr: [%s@%p] %s -> %s\n",
567 		kvlookup(kv_query_type, as->as_type),
568 		as,
569 		kvlookup(kv_state, as->as_state),
570 		kvlookup(kv_state, state));
571 	as->as_state = state;
572 }
573