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