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