xref: /openbsd-src/lib/libc/asr/asr_debug.c (revision b44da6278dfc5a9ac4bcab6662bc7def6c347a68)
1 /*	$OpenBSD: asr_debug.c,v 1.1 2012/04/14 09:24:18 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 	int	e;
267 
268 	if ((e = getnameinfo(sa, sa->sa_len,
269 	    buf, len, NULL, 0, NI_NUMERICHOST)) != 0) {
270 		buf[0] = '\0';
271 		return (NULL);
272 	}
273 	return (buf);
274 }
275 
276 char *
277 print_addr(const struct sockaddr *sa, char *buf, size_t len)
278 {
279 	char	h[256];
280 
281 	print_host(sa, h, sizeof h);
282 
283 	switch (sa->sa_family) {
284 	case AF_INET:
285 		snprintf(buf, len, "%s:%i", h,
286 		    ntohs(((struct sockaddr_in*)(sa))->sin_port));
287 		break;
288 	case AF_INET6:
289 		snprintf(buf, len, "[%s]:%i", h,
290 		    ntohs(((struct sockaddr_in6*)(sa))->sin6_port));
291 		break;
292 	default:
293 		snprintf(buf, len, "?");
294 		break;
295 	}
296 
297 	return (buf);
298 }
299 
300 struct kv { int code; const char *name; };
301 
302 static const char*	kvlookup(struct kv *, int);
303 
304 int	 asr_debug = 0;
305 
306 void
307 asr_dump(struct asr *a)
308 {
309 	char		 buf[256];
310 	int		 i;
311 	struct asr_ctx	*ac;
312 	unsigned int	 options;
313 
314 	ac = a->a_ctx;
315 
316 	asr_printf("--------- ASR CONFIG ---------------\n");
317 	if (a->a_path)
318 		asr_printf("CONF FILE \"%s\"\n", a->a_path);
319 	else
320 		asr_printf("STATIC CONF\n");
321 	asr_printf("DOMAIN \"%s\"\n", ac->ac_domain);
322 	asr_printf("SEARCH\n");
323 	for(i = 0; i < ac->ac_domcount; i++)
324 		asr_printf("   \"%s\"\n", ac->ac_dom[i]);
325 	asr_printf("OPTIONS\n");
326 	asr_printf(" options:");
327 	options = ac->ac_options;
328 	if (options & RES_INIT) {
329 		asr_printf(" INIT"); options &= ~RES_INIT;
330 	}
331 	if (options & RES_DEBUG) {
332 		asr_printf(" DEBUG"); options &= ~RES_DEBUG;
333 	}
334 	if (options & RES_USEVC) {
335 		asr_printf(" USEVC"); options &= ~RES_USEVC;
336 	}
337 	if (options & RES_IGNTC) {
338 		asr_printf(" IGNTC"); options &= ~RES_IGNTC;
339 	}
340 	if (options & RES_RECURSE) {
341 		asr_printf(" RECURSE"); options &= ~RES_RECURSE;
342 	}
343 	if (options & RES_DEFNAMES) {
344 		asr_printf(" DEFNAMES"); options &= ~RES_DEFNAMES;
345 	}
346 	if (options & RES_STAYOPEN) {
347 		asr_printf(" STAYOPEN"); options &= ~RES_STAYOPEN;
348 	}
349 	if (options & RES_DNSRCH) {
350 		asr_printf(" DNSRCH"); options &= ~RES_DNSRCH;
351 	}
352 	if (options & RES_NOALIASES) {
353 		asr_printf(" NOALIASES"); options &= ~RES_NOALIASES;
354 	}
355 	if (options & RES_USE_EDNS0) {
356 		asr_printf(" USE_EDNS0"); options &= ~RES_USE_EDNS0;
357 	}
358 	if (options & RES_USE_DNSSEC) {
359 		asr_printf(" USE_DNSSEC"); options &= ~RES_USE_DNSSEC;
360 	}
361 	if (options)
362 		asr_printf("0x%08x\n", options);
363 	asr_printf("\n", ac->ac_options);
364 
365 	asr_printf(" ndots: %i\n", ac->ac_ndots);
366 	asr_printf(" family:");
367 	for(i = 0; ac->ac_family[i] != -1; i++)
368 		asr_printf(" %s", (ac->ac_family[i] == AF_INET) ? "inet" : "inet6");
369 	asr_printf("\n");
370 	asr_printf("NAMESERVERS timeout=%i retry=%i\n",
371 		   ac->ac_nstimeout,
372 		   ac->ac_nsretries);
373 	for(i = 0; i < ac->ac_nscount; i++)
374 		asr_printf("	%s\n", print_addr(ac->ac_ns[i], buf, sizeof buf));
375 	asr_printf("HOSTFILE %s\n", ac->ac_hostfile);
376 	asr_printf("LOOKUP");
377 	for(i = 0; i < ac->ac_dbcount; i++) {
378 		switch (ac->ac_db[i]) {
379 		case ASR_DB_FILE:
380 			asr_printf(" file");
381 			break;
382 		case ASR_DB_DNS:
383 			asr_printf(" dns");
384 			break;
385 		case ASR_DB_YP:
386 			asr_printf(" yp");
387 			break;
388 		default:
389 			asr_printf(" ?%i", ac->ac_db[i]);
390 		}
391 	}
392 	asr_printf("\n------------------------------------\n");
393 }
394 
395 static const char *
396 kvlookup(struct kv *kv, int code)
397 {
398 	while (kv->name) {
399 		if (kv->code == code)
400 			return (kv->name);
401 		kv++;
402 	}
403 	return "???";
404 }
405 
406 struct kv kv_query_type[] = {
407 	{ ASR_SEND,		"ASR_SEND"		},
408 	{ ASR_SEARCH,		"ASR_SEARCH"		},
409 	{ ASR_GETRRSETBYNAME,	"ASR_GETRRSETBYNAME"	},
410 	{ ASR_GETHOSTBYNAME,	"ASR_GETHOSTBYNAME"	},
411 	{ ASR_GETHOSTBYADDR,	"ASR_GETHOSTBYADDR"	},
412 	{ ASR_GETNETBYNAME,	"ASR_GETNETBYNAME"	},
413 	{ ASR_GETNETBYADDR,	"ASR_GETNETBYADDR"	},
414 	{ ASR_GETADDRINFO,	"ASR_GETADDRINFO"	},
415 	{ ASR_GETNAMEINFO,	"ASR_GETNAMEINFO"	},
416 	{ ASR_HOSTADDR,		"ASR_HOSTADDR"		},
417 	{ 0, NULL }
418 };
419 
420 struct kv kv_db_type[] = {
421 	{ ASR_DB_FILE,			"ASR_DB_FILE"			},
422 	{ ASR_DB_DNS,			"ASR_DB_DNS"			},
423 	{ ASR_DB_YP,			"ASR_DB_YP"			},
424 	{ 0, NULL }
425 };
426 
427 struct kv kv_state[] = {
428 	{ ASR_STATE_INIT,		"ASR_STATE_INIT"		},
429 	{ ASR_STATE_SEARCH_DOMAIN,	"ASR_STATE_SEARCH_DOMAIN"	},
430 	{ ASR_STATE_LOOKUP_DOMAIN,	"ASR_STATE_LOOKUP_DOMAIN"	},
431 	{ ASR_STATE_NEXT_DOMAIN,	"ASR_STATE_NEXT_DOMAIN"		},
432 	{ ASR_STATE_NEXT_DB,		"ASR_STATE_NEXT_DB"		},
433 	{ ASR_STATE_SAME_DB,		"ASR_STATE_SAME_DB"		},
434 	{ ASR_STATE_NEXT_FAMILY,	"ASR_STATE_NEXT_FAMILY"		},
435 	{ ASR_STATE_LOOKUP_FAMILY,	"ASR_STATE_LOOKUP_FAMILY"	},
436 	{ ASR_STATE_NEXT_NS,		"ASR_STATE_NEXT_NS"		},
437 	{ ASR_STATE_READ_RR,		"ASR_STATE_READ_RR"		},
438 	{ ASR_STATE_READ_FILE,		"ASR_STATE_READ_FILE"		},
439 	{ ASR_STATE_UDP_SEND,		"ASR_STATE_UDP_SEND"		},
440 	{ ASR_STATE_UDP_RECV,		"ASR_STATE_UDP_RECV"		},
441 	{ ASR_STATE_TCP_WRITE,		"ASR_STATE_TCP_WRITE"		},
442 	{ ASR_STATE_TCP_READ,		"ASR_STATE_TCP_READ"		},
443 	{ ASR_STATE_PACKET,		"ASR_STATE_PACKET"		},
444 	{ ASR_STATE_SUBQUERY,		"ASR_STATE_SUBQUERY"		},
445 	{ ASR_STATE_NOT_FOUND,		"ASR_STATE_NOT_FOUND",		},
446 	{ ASR_STATE_HALT,		"ASR_STATE_HALT"		},
447 	{ 0, NULL }
448 };
449 
450 struct kv kv_transition[] = {
451 	{ ASYNC_COND,			"ASYNC_COND"			},
452 	{ ASYNC_YIELD,			"ASYNC_YIELD"			},
453 	{ ASYNC_DONE,			"ASYNC_DONE"			},
454         { 0, NULL }
455 };
456 
457 const char *
458 asr_querystr(int type)
459 {
460 	return kvlookup(kv_query_type, type);
461 }
462 
463 const char *
464 asr_transitionstr(int type)
465 {
466 	return kvlookup(kv_transition, type);
467 }
468 
469 void
470 asr_dump_async(struct async *as)
471 {
472 	asr_printf("%s fd=%i timeout=%i"
473 		"   dom_idx=%i db_idx=%i ns_idx=%i ns_cycles=%i\n",
474 		kvlookup(kv_state, as->as_state),
475 		as->as_fd,
476 		as->as_timeout,
477 
478 		as->as_dom_idx,
479 		as->as_db_idx,
480 		as->as_ns_idx,
481 		as->as_ns_cycles);
482 }
483 
484 void
485 asr_dump_packet(FILE *f, const void *data, size_t len, int noid)
486 {
487 	char		buf[1024];
488 	struct packed	p;
489 	struct header	h;
490 	struct query	q;
491 	struct rr	rr;
492 	int		i, an, ns, ar, n;
493 
494 	if (f == NULL)
495 		return;
496 
497 	packed_init(&p, (char *)data, len);
498 
499 	if (unpack_header(&p, &h) == -1) {
500 		fprintf(f, ";; BAD PACKET: %s\n", p.err);
501 		return;
502 	}
503 
504 	fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf, noid));
505 
506 	if (h.qdcount)
507 		fprintf(f, ";; QUERY SECTION:\n");
508 	for (i = 0; i < h.qdcount; i++) {
509 		if (unpack_query(&p, &q) == -1)
510 			goto error;
511 		fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
512 	}
513 
514 	an = 0;
515 	ns = an + h.ancount;
516 	ar = ns + h.nscount;
517 	n = ar + h.arcount;
518 
519 	for (i = 0; i < n; i++) {
520 		if (i == an)
521 			fprintf(f, "\n;; ANSWER SECTION:\n");
522 		if (i == ns)
523 			fprintf(f, "\n;; AUTHORITY SECTION:\n");
524 		if (i == ar)
525 			fprintf(f, "\n;; ADDITIONAL SECTION:\n");
526 
527 		if (unpack_rr(&p, &rr) == -1)
528 			goto error;
529 		fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
530 	}
531 
532 	if (p.offset != len)
533 		fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
534 
535     error:
536 	if (p.err)
537 		fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
538 		    p.err);
539 
540 	return;
541 }
542 
543 static void
544 asr_vdebug(const char *fmt, va_list ap)
545 {
546 	if (asr_debug)
547 		vfprintf(stderr, fmt, ap);
548 }
549 
550 void
551 asr_printf(const char *fmt, ...)
552 {
553 	va_list ap;
554 
555 	va_start(ap, fmt);
556 	asr_vdebug(fmt, ap);
557 	va_end(ap);
558 }
559 
560 void
561 async_set_state(struct async *as, int state)
562 {
563 	asr_printf("asr: [%s@%p] %s -> %s\n",
564 		kvlookup(kv_query_type, as->as_type),
565 		as,
566 		kvlookup(kv_state, as->as_state),
567 		kvlookup(kv_state, state));
568 	as->as_state = state;
569 }
570