1 /* $OpenBSD: asr_debug.c,v 1.28 2021/11/22 20:18:27 jca 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 #include <string.h>
28
29 #include "asr_private.h"
30
31 static const char *rcodetostr(uint16_t);
32 static const char *print_dname(const char *, char *, size_t);
33 static const char *print_header(const struct asr_dns_header *, char *, size_t);
34 static const char *print_query(const struct asr_dns_query *, char *, size_t);
35 static const char *print_rr(const struct asr_dns_rr *, char *, size_t);
36
37 FILE *_asr_debug = NULL;
38
39 #define OPCODE_SHIFT 11
40
41 static const char *
rcodetostr(uint16_t v)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 *
print_dname(const char * _dname,char * buf,size_t max)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 *
print_rr(const struct asr_dns_rr * rr,char * buf,size_t max)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 < 0 || r >= max) {
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.mname, tmp, sizeof tmp),
105 print_dname(rr->rr.soa.rname, 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 *
print_query(const struct asr_dns_query * q,char * buf,size_t max)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 *
print_header(const struct asr_dns_header * h,char * buf,size_t max)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 %s %s 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),
158 (h->flags & AD_MASK) ? "AD":" ",
159 (h->flags & CD_MASK) ? "CD":" ",
160 rcodetostr(RCODE(h->flags)),
161 h->qdcount, h->ancount, h->nscount, h->arcount);
162
163 return (buf);
164 }
165
166 void
_asr_dump_packet(FILE * f,const void * data,size_t len)167 _asr_dump_packet(FILE *f, const void *data, size_t len)
168 {
169 char buf[1024];
170 struct asr_unpack p;
171 struct asr_dns_header h;
172 struct asr_dns_query q;
173 struct asr_dns_rr rr;
174 int i, an, ns, ar, n;
175
176 if (f == NULL)
177 return;
178
179 _asr_unpack_init(&p, data, len);
180
181 if (_asr_unpack_header(&p, &h) == -1) {
182 fprintf(f, ";; BAD PACKET: %s\n", strerror(p.err));
183 return;
184 }
185
186 fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf));
187
188 if (h.qdcount)
189 fprintf(f, ";; QUERY SECTION:\n");
190 for (i = 0; i < h.qdcount; i++) {
191 if (_asr_unpack_query(&p, &q) == -1)
192 goto error;
193 fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
194 }
195
196 an = 0;
197 ns = an + h.ancount;
198 ar = ns + h.nscount;
199 n = ar + h.arcount;
200
201 for (i = 0; i < n; i++) {
202 if (i == an)
203 fprintf(f, "\n;; ANSWER SECTION:\n");
204 if (i == ns)
205 fprintf(f, "\n;; AUTHORITY SECTION:\n");
206 if (i == ar)
207 fprintf(f, "\n;; ADDITIONAL SECTION:\n");
208
209 if (_asr_unpack_rr(&p, &rr) == -1)
210 goto error;
211 fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
212 }
213
214 if (p.offset != len)
215 fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
216
217 error:
218 if (p.err)
219 fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
220 strerror(p.err));
221 }
222
223 const char *
_asr_print_sockaddr(const struct sockaddr * sa,char * buf,size_t len)224 _asr_print_sockaddr(const struct sockaddr *sa, char *buf, size_t len)
225 {
226 char h[256];
227 int portno;
228 union {
229 const struct sockaddr *sa;
230 const struct sockaddr_in *sin;
231 const struct sockaddr_in6 *sin6;
232 } s;
233
234 s.sa = sa;
235
236 switch (sa->sa_family) {
237 case AF_INET:
238 inet_ntop(AF_INET, &s.sin->sin_addr, h, sizeof h);
239 portno = ntohs(s.sin->sin_port);
240 break;
241 case AF_INET6:
242 inet_ntop(AF_INET6, &s.sin6->sin6_addr, h, sizeof h);
243 portno = ntohs(s.sin6->sin6_port);
244 break;
245 default:
246 snprintf(buf, len, "?");
247 return (buf);
248 }
249
250 snprintf(buf, len, "%s:%i", h, portno);
251 return (buf);
252 }
253
254 void
_asr_dump_config(FILE * f,struct asr * a)255 _asr_dump_config(FILE *f, struct asr *a)
256 {
257 char buf[256];
258 int i;
259 struct asr_ctx *ac;
260 unsigned int o;
261
262 if (f == NULL)
263 return;
264
265 ac = a->a_ctx;
266
267 fprintf(f, "--------- ASR CONFIG ---------------\n");
268 fprintf(f, "DOMAIN \"%s\"\n", ac->ac_domain);
269 fprintf(f, "SEARCH\n");
270 for (i = 0; i < ac->ac_domcount; i++)
271 fprintf(f, " \"%s\"\n", ac->ac_dom[i]);
272 fprintf(f, "OPTIONS\n");
273 fprintf(f, " options:");
274 o = ac->ac_options;
275
276 #define PRINTOPT(flag, n) if (o & (flag)) { fprintf(f, " " n); o &= ~(flag); }
277 PRINTOPT(RES_INIT, "INIT");
278 PRINTOPT(RES_DEBUG, "DEBUG");
279 PRINTOPT(RES_USEVC, "USEVC");
280 PRINTOPT(RES_IGNTC, "IGNTC");
281 PRINTOPT(RES_RECURSE, "RECURSE");
282 PRINTOPT(RES_DEFNAMES, "DEFNAMES");
283 PRINTOPT(RES_STAYOPEN, "STAYOPEN");
284 PRINTOPT(RES_DNSRCH, "DNSRCH");
285 PRINTOPT(RES_NOALIASES, "NOALIASES");
286 PRINTOPT(RES_USE_EDNS0, "USE_EDNS0");
287 PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC");
288 PRINTOPT(RES_USE_CD, "USE_CD");
289 PRINTOPT(RES_TRUSTAD, "TRUSTAD");
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", _asr_print_sockaddr(ac->ac_ns[i], buf,
304 sizeof buf));
305 fprintf(f, "LOOKUP %s", ac->ac_db);
306 fprintf(f, "\n------------------------------------\n");
307 }
308
309 #define CASE(n) case n: return #n
310
311 const char *
_asr_statestr(int state)312 _asr_statestr(int state)
313 {
314 switch (state) {
315 CASE(ASR_STATE_INIT);
316 CASE(ASR_STATE_NEXT_DOMAIN);
317 CASE(ASR_STATE_NEXT_DB);
318 CASE(ASR_STATE_SAME_DB);
319 CASE(ASR_STATE_NEXT_FAMILY);
320 CASE(ASR_STATE_NEXT_NS);
321 CASE(ASR_STATE_UDP_SEND);
322 CASE(ASR_STATE_UDP_RECV);
323 CASE(ASR_STATE_TCP_WRITE);
324 CASE(ASR_STATE_TCP_READ);
325 CASE(ASR_STATE_PACKET);
326 CASE(ASR_STATE_SUBQUERY);
327 CASE(ASR_STATE_NOT_FOUND);
328 CASE(ASR_STATE_HALT);
329 default:
330 return "?";
331 }
332 };
333
334 const char *
_asr_querystr(int type)335 _asr_querystr(int type)
336 {
337 switch (type) {
338 CASE(ASR_SEND);
339 CASE(ASR_SEARCH);
340 CASE(ASR_GETRRSETBYNAME);
341 CASE(ASR_GETHOSTBYNAME);
342 CASE(ASR_GETHOSTBYADDR);
343 CASE(ASR_GETADDRINFO);
344 CASE(ASR_GETNAMEINFO);
345 default:
346 return "?";
347 }
348 }
349
350 const char *
_asr_transitionstr(int type)351 _asr_transitionstr(int type)
352 {
353 switch (type) {
354 CASE(ASYNC_COND);
355 CASE(ASYNC_DONE);
356 default:
357 return "?";
358 }
359 }
360