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