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