1 /* $OpenBSD: asr_debug.c,v 1.22 2015/10/28 21:38: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 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 _asr_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 fprintf(f, "DOMAIN \"%s\"\n", ac->ac_domain); 267 fprintf(f, "SEARCH\n"); 268 for (i = 0; i < ac->ac_domcount; i++) 269 fprintf(f, " \"%s\"\n", ac->ac_dom[i]); 270 fprintf(f, "OPTIONS\n"); 271 fprintf(f, " options:"); 272 o = ac->ac_options; 273 274 #define PRINTOPT(flag, n) if (o & (flag)) { fprintf(f, " " n); o &= ~(flag); } 275 PRINTOPT(RES_INIT, "INIT"); 276 PRINTOPT(RES_DEBUG, "DEBUG"); 277 PRINTOPT(RES_USEVC, "USEVC"); 278 PRINTOPT(RES_IGNTC, "IGNTC"); 279 PRINTOPT(RES_RECURSE, "RECURSE"); 280 PRINTOPT(RES_DEFNAMES, "DEFNAMES"); 281 PRINTOPT(RES_STAYOPEN, "STAYOPEN"); 282 PRINTOPT(RES_DNSRCH, "DNSRCH"); 283 PRINTOPT(RES_NOALIASES, "NOALIASES"); 284 PRINTOPT(RES_USE_EDNS0, "USE_EDNS0"); 285 PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC"); 286 if (o) 287 fprintf(f, " 0x%08x", o); 288 fprintf(f, "\n"); 289 290 fprintf(f, " ndots: %i\n", ac->ac_ndots); 291 fprintf(f, " family:"); 292 for (i = 0; ac->ac_family[i] != -1; i++) 293 fprintf(f, " %s", (ac->ac_family[i] == AF_INET)?"inet4":"inet6"); 294 fprintf(f, "\n"); 295 fprintf(f, "NAMESERVERS timeout=%i retry=%i\n", 296 ac->ac_nstimeout, 297 ac->ac_nsretries); 298 for (i = 0; i < ac->ac_nscount; i++) 299 fprintf(f, " %s\n", _asr_print_sockaddr(ac->ac_ns[i], buf, 300 sizeof buf)); 301 fprintf(f, "LOOKUP %s", ac->ac_db); 302 fprintf(f, "\n------------------------------------\n"); 303 } 304 305 #define CASE(n) case n: return #n 306 307 const char * 308 _asr_statestr(int state) 309 { 310 switch (state) { 311 CASE(ASR_STATE_INIT); 312 CASE(ASR_STATE_NEXT_DOMAIN); 313 CASE(ASR_STATE_NEXT_DB); 314 CASE(ASR_STATE_SAME_DB); 315 CASE(ASR_STATE_NEXT_FAMILY); 316 CASE(ASR_STATE_NEXT_NS); 317 CASE(ASR_STATE_UDP_SEND); 318 CASE(ASR_STATE_UDP_RECV); 319 CASE(ASR_STATE_TCP_WRITE); 320 CASE(ASR_STATE_TCP_READ); 321 CASE(ASR_STATE_PACKET); 322 CASE(ASR_STATE_SUBQUERY); 323 CASE(ASR_STATE_NOT_FOUND); 324 CASE(ASR_STATE_HALT); 325 default: 326 return "?"; 327 } 328 }; 329 330 const char * 331 _asr_querystr(int type) 332 { 333 switch (type) { 334 CASE(ASR_SEND); 335 CASE(ASR_SEARCH); 336 CASE(ASR_GETRRSETBYNAME); 337 CASE(ASR_GETHOSTBYNAME); 338 CASE(ASR_GETHOSTBYADDR); 339 CASE(ASR_GETNETBYNAME); 340 CASE(ASR_GETNETBYADDR); 341 CASE(ASR_GETADDRINFO); 342 CASE(ASR_GETNAMEINFO); 343 default: 344 return "?"; 345 } 346 } 347 348 const char * 349 _asr_transitionstr(int type) 350 { 351 switch (type) { 352 CASE(ASYNC_COND); 353 CASE(ASYNC_DONE); 354 default: 355 return "?"; 356 } 357 } 358