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