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