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