dnsdebug.c (8549B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <ctype.h> 5 #include <ip.h> 6 #include <ndb.h> 7 #include <thread.h> 8 #include "dns.h" 9 10 enum 11 { 12 Maxrequest= 128, 13 Ncache= 8, 14 Maxpath= 128, 15 Maxreply= 512, 16 Maxrrr= 16 17 }; 18 19 static char *servername; 20 static RR *serveraddrs; 21 22 int debug; 23 int cachedb; 24 ulong now; 25 int testing; 26 int traceactivity; 27 char *trace; 28 int needrefresh; 29 int resolver; 30 uchar ipaddr[IPaddrlen]; /* my ip address */ 31 int maxage; 32 char *logfile = "dns"; 33 char *dbfile; 34 char mntpt[Maxpath]; 35 char *zonerefreshprogram; 36 char *tcpaddr; 37 char *udpaddr; 38 39 int prettyrrfmt(Fmt*); 40 void preloadserveraddrs(void); 41 void squirrelserveraddrs(void); 42 int setserver(char*); 43 void doquery(char*, char*); 44 void docmd(int, char**); 45 46 void 47 usage(void) 48 { 49 fprint(2, "usage: dnsdebug [-fr] [query ...]\n"); 50 threadexitsall("usage"); 51 } 52 53 void 54 threadmain(int argc, char *argv[]) 55 { 56 int n; 57 Biobuf in; 58 char *p; 59 char *f[4]; 60 61 strcpy(mntpt, "/net"); 62 63 ARGBEGIN{ 64 case 'r': 65 resolver = 1; 66 break; 67 case 'f': 68 dbfile = EARGF(usage()); 69 break; 70 default: 71 usage(); 72 }ARGEND 73 74 now = time(0); 75 dninit(); 76 fmtinstall('R', prettyrrfmt); 77 if(myipaddr(ipaddr, mntpt) < 0) 78 sysfatal("can't read my ip address"); 79 opendatabase(); 80 81 if(resolver) 82 squirrelserveraddrs(); 83 84 debug = 1; 85 86 if(argc > 0){ 87 docmd(argc, argv); 88 threadexitsall(0); 89 } 90 91 Binit(&in, 0, OREAD); 92 for(print("> "); p = Brdline(&in, '\n'); print("> ")){ 93 p[Blinelen(&in)-1] = 0; 94 n = tokenize(p, f, 3); 95 if(n<1) 96 continue; 97 98 /* flush the cache */ 99 dnpurge(); 100 101 docmd(n, f); 102 103 } 104 threadexitsall(0); 105 } 106 107 static char* 108 longtime(long t) 109 { 110 int d, h, m, n; 111 static char x[128]; 112 113 for(d = 0; t >= 24*60*60; t -= 24*60*60) 114 d++; 115 for(h = 0; t >= 60*60; t -= 60*60) 116 h++; 117 for(m = 0; t >= 60; t -= 60) 118 m++; 119 n = 0; 120 if(d) 121 n += sprint(x, "%d day ", d); 122 if(h) 123 n += sprint(x+n, "%d hr ", h); 124 if(m) 125 n += sprint(x+n, "%d min ", m); 126 if(t || n == 0) 127 sprint(x+n, "%ld sec", t); 128 return x; 129 } 130 131 int 132 prettyrrfmt(Fmt *f) 133 { 134 RR *rp; 135 char buf[3*Domlen]; 136 char *p, *e; 137 Txt *t; 138 139 rp = va_arg(f->args, RR*); 140 if(rp == 0){ 141 strcpy(buf, "<null>"); 142 goto out; 143 } 144 145 p = buf; 146 e = buf + sizeof(buf); 147 p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name, 148 longtime(rp->db ? rp->ttl : (rp->ttl-now)), 149 rrname(rp->type, buf, sizeof buf)); 150 151 if(rp->negative){ 152 seprint(p, e, "negative rcode %d\n", rp->negrcode); 153 goto out; 154 } 155 156 switch(rp->type){ 157 case Thinfo: 158 seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name); 159 break; 160 case Tcname: 161 case Tmb: 162 case Tmd: 163 case Tmf: 164 case Tns: 165 seprint(p, e, "\t%s", rp->host->name); 166 break; 167 case Tmg: 168 case Tmr: 169 seprint(p, e, "\t%s", rp->mb->name); 170 break; 171 case Tminfo: 172 seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name); 173 break; 174 case Tmx: 175 seprint(p, e, "\t%lud %s", rp->pref, rp->host->name); 176 break; 177 case Ta: 178 case Taaaa: 179 seprint(p, e, "\t%s", rp->ip->name); 180 break; 181 case Tptr: 182 seprint(p, e, "\t%s", rp->ptr->name); 183 break; 184 case Tsoa: 185 seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name, 186 rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry, 187 rp->soa->expire, rp->soa->minttl); 188 break; 189 case Tnull: 190 seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data); 191 break; 192 case Ttxt: 193 p = seprint(p, e, "\t"); 194 for(t = rp->txt; t != nil; t = t->next) 195 p = seprint(p, e, "%s", t->p); 196 break; 197 case Trp: 198 seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name); 199 break; 200 case Tkey: 201 seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto, 202 rp->key->alg); 203 break; 204 case Tsig: 205 seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s", 206 rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl, 207 rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name); 208 break; 209 case Tcert: 210 seprint(p, e, "\t%d %d %d", 211 rp->sig->type, rp->sig->tag, rp->sig->alg); 212 break; 213 default: 214 break; 215 } 216 out: 217 return fmtstrcpy(f, buf); 218 } 219 220 void 221 logsection(char *flag, RR *rp) 222 { 223 if(rp == nil) 224 return; 225 print("\t%s%R\n", flag, rp); 226 for(rp = rp->next; rp != nil; rp = rp->next) 227 print("\t %R\n", rp); 228 } 229 230 void 231 logreply(int id, uchar *addr, DNSmsg *mp) 232 { 233 RR *rp; 234 char buf[12]; 235 char resp[32]; 236 237 switch(mp->flags & Rmask){ 238 case Rok: 239 strcpy(resp, "OK"); 240 break; 241 case Rformat: 242 strcpy(resp, "Format error"); 243 break; 244 case Rserver: 245 strcpy(resp, "Server failed"); 246 break; 247 case Rname: 248 strcpy(resp, "Nonexistent"); 249 break; 250 case Runimplimented: 251 strcpy(resp, "Unimplemented"); 252 break; 253 case Rrefused: 254 strcpy(resp, "Refused"); 255 break; 256 default: 257 sprint(resp, "%d", mp->flags & Rmask); 258 break; 259 } 260 261 print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr, 262 mp->flags & Fauth ? "authoritative" : "", 263 mp->flags & Ftrunc ? " truncated" : "", 264 mp->flags & Frecurse ? " recurse" : "", 265 mp->flags & Fcanrec ? " can_recurse" : "", 266 mp->flags & (Fauth|Rname) == (Fauth|Rname) ? 267 " nx" : ""); 268 for(rp = mp->qd; rp != nil; rp = rp->next) 269 print("\tQ: %s %s\n", rp->owner->name, rrname(rp->type, buf, sizeof buf)); 270 logsection("Ans: ", mp->an); 271 logsection("Auth: ", mp->ns); 272 logsection("Hint: ", mp->ar); 273 } 274 275 void 276 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 277 { 278 char buf[12]; 279 280 print("%d.%d: sending to %I/%s %s %s\n", id, subid, 281 addr, sname, rname, rrname(type, buf, sizeof buf)); 282 } 283 284 RR* 285 getdnsservers(int class) 286 { 287 RR *rr; 288 289 if(servername == nil) 290 return dnsservers(class); 291 292 rr = rralloc(Tns); 293 rr->owner = dnlookup("local#dns#servers", class, 1); 294 rr->host = dnlookup(servername, class, 1); 295 296 return rr; 297 } 298 299 void 300 squirrelserveraddrs(void) 301 { 302 RR *rr, *rp, **l; 303 Request req; 304 305 /* look up the resolver address first */ 306 resolver = 0; 307 debug = 0; 308 if(serveraddrs) 309 rrfreelist(serveraddrs); 310 serveraddrs = nil; 311 rr = getdnsservers(Cin); 312 l = &serveraddrs; 313 for(rp = rr; rp != nil; rp = rp->next){ 314 if(strcmp(ipattr(rp->host->name), "ip") == 0){ 315 *l = rralloc(Ta); 316 (*l)->owner = rp->host; 317 (*l)->ip = rp->host; 318 l = &(*l)->next; 319 continue; 320 } 321 req.aborttime = now + 60; /* don't spend more than 60 seconds */ 322 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0); 323 while(*l != nil) 324 l = &(*l)->next; 325 } 326 resolver = 1; 327 debug = 1; 328 } 329 330 void 331 preloadserveraddrs(void) 332 { 333 RR *rp, **l, *first; 334 335 l = &first; 336 for(rp = serveraddrs; rp != nil; rp = rp->next){ 337 rrcopy(rp, l); 338 rrattach(first, 1); 339 } 340 } 341 342 int 343 setserver(char *server) 344 { 345 if(servername != nil){ 346 free(servername); 347 servername = nil; 348 resolver = 0; 349 } 350 if(server == nil || *server == 0) 351 return 0; 352 servername = strdup(server); 353 squirrelserveraddrs(); 354 if(serveraddrs == nil){ 355 print("can't resolve %s\n", servername); 356 resolver = 0; 357 } else { 358 resolver = 1; 359 } 360 return resolver ? 0 : -1; 361 } 362 363 void 364 doquery(char *name, char *tstr) 365 { 366 Request req; 367 RR *rr, *rp; 368 int len, type; 369 char *p, *np; 370 int rooted; 371 char buf[1024]; 372 373 if(resolver) 374 preloadserveraddrs(); 375 376 /* default to an "ip" request if alpha, "ptr" if numeric */ 377 if(tstr == nil || *tstr == 0) { 378 if(strcmp(ipattr(name), "ip") == 0) 379 tstr = "ptr"; 380 else 381 tstr = "ip"; 382 } 383 384 /* if name end in '.', remove it */ 385 len = strlen(name); 386 if(len > 0 && name[len-1] == '.'){ 387 rooted = 1; 388 name[len-1] = 0; 389 } else 390 rooted = 0; 391 392 /* inverse queries may need to be permuted */ 393 strncpy(buf, name, sizeof buf); 394 if(strcmp("ptr", tstr) == 0 395 && strstr(name, "IN-ADDR") == 0 396 && strstr(name, "in-addr") == 0){ 397 for(p = name; *p; p++) 398 ; 399 *p = '.'; 400 np = buf; 401 len = 0; 402 while(p >= name){ 403 len++; 404 p--; 405 if(*p == '.'){ 406 memmove(np, p+1, len); 407 np += len; 408 len = 0; 409 } 410 } 411 memmove(np, p+1, len); 412 np += len; 413 strcpy(np, "in-addr.arpa"); 414 } 415 416 /* look it up */ 417 type = rrtype(tstr); 418 if(type < 0){ 419 print("!unknown type %s\n", tstr); 420 return; 421 } 422 423 getactivity(&req); 424 req.aborttime = now + 60; /* don't spend more than 60 seconds */ 425 rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); 426 if(rr){ 427 print("----------------------------\n"); 428 for(rp = rr; rp; rp = rp->next) 429 print("answer %R\n", rp); 430 print("----------------------------\n"); 431 } 432 rrfreelist(rr); 433 434 putactivity(); 435 } 436 437 void 438 docmd(int n, char **f) 439 { 440 int tmpsrv; 441 char *name, *type; 442 443 name = nil; 444 type = nil; 445 tmpsrv = 0; 446 447 if(*f[0] == '@') { 448 if(setserver(f[0]+1) < 0) 449 return; 450 451 switch(n){ 452 case 3: 453 type = f[2]; 454 /* fall through */ 455 case 2: 456 name = f[1]; 457 tmpsrv = 1; 458 break; 459 } 460 } else { 461 switch(n){ 462 case 2: 463 type = f[1]; 464 /* fall through */ 465 case 1: 466 name = f[0]; 467 break; 468 } 469 } 470 471 if(name == nil) 472 return; 473 474 doquery(name, type); 475 476 if(tmpsrv) 477 setserver(""); 478 }