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