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