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