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