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] [[@server] domain [type]]\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 nowns = nsec(); 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(cfg.resolver) 82 squirrelserveraddrs(); 83 84 debug = 1; 85 86 if(argc > 0){ 87 docmd(argc, argv); 88 exits(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 dnpurge(); /* flush the cache */ 97 docmd(n, f); 98 } 99 } 100 exits(0); 101 } 102 103 static char* 104 longtime(long t) 105 { 106 int d, h, m, n; 107 static char x[128]; 108 109 for(d = 0; t >= 24*60*60; t -= 24*60*60) 110 d++; 111 for(h = 0; t >= 60*60; t -= 60*60) 112 h++; 113 for(m = 0; t >= 60; t -= 60) 114 m++; 115 n = 0; 116 if(d) 117 n += sprint(x, "%d day ", d); 118 if(h) 119 n += sprint(x+n, "%d hr ", h); 120 if(m) 121 n += sprint(x+n, "%d min ", m); 122 if(t || n == 0) 123 sprint(x+n, "%ld sec", t); 124 return x; 125 } 126 127 int 128 prettyrrfmt(Fmt *f) 129 { 130 RR *rp; 131 char buf[3*Domlen]; 132 char *p, *e; 133 Txt *t; 134 135 rp = va_arg(f->args, RR*); 136 if(rp == 0){ 137 strcpy(buf, "<null>"); 138 goto out; 139 } 140 141 p = buf; 142 e = buf + sizeof(buf); 143 p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name, 144 longtime(rp->db? rp->ttl: (rp->ttl - now)), 145 rrname(rp->type, buf, sizeof buf)); 146 147 if(rp->negative){ 148 seprint(p, e, "negative rcode %d", rp->negrcode); 149 goto out; 150 } 151 152 switch(rp->type){ 153 case Thinfo: 154 seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name); 155 break; 156 case Tcname: 157 case Tmb: 158 case Tmd: 159 case Tmf: 160 case Tns: 161 seprint(p, e, "\t%s", (rp->host? rp->host->name: "")); 162 break; 163 case Tmg: 164 case Tmr: 165 seprint(p, e, "\t%s", (rp->mb? rp->mb->name: "")); 166 break; 167 case Tminfo: 168 seprint(p, e, "\t%s %s", (rp->mb? rp->mb->name: ""), 169 (rp->rmb? rp->rmb->name: "")); 170 break; 171 case Tmx: 172 seprint(p, e, "\t%lud %s", rp->pref, 173 (rp->host? rp->host->name: "")); 174 break; 175 case Ta: 176 case Taaaa: 177 seprint(p, e, "\t%s", (rp->ip? rp->ip->name: "")); 178 break; 179 case Tptr: 180 seprint(p, e, "\t%s", (rp->ptr? rp->ptr->name: "")); 181 break; 182 case Tsoa: 183 seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", 184 rp->host->name, rp->rmb->name, rp->soa->serial, 185 rp->soa->refresh, rp->soa->retry, 186 rp->soa->expire, rp->soa->minttl); 187 break; 188 case Tsrv: 189 seprint(p, e, "\t%ud %ud %ud %s", 190 rp->srv->pri, rp->srv->weight, rp->port, rp->host->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 int v4; 304 char *attr; 305 RR *rr, *rp, **l; 306 Request req; 307 308 /* look up the resolver address first */ 309 cfg.resolver = 0; 310 debug = 0; 311 if(serveraddrs) 312 rrfreelist(serveraddrs); 313 serveraddrs = nil; 314 rr = getdnsservers(Cin); 315 l = &serveraddrs; 316 for(rp = rr; rp != nil; rp = rp->next){ 317 attr = ipattr(rp->host->name); 318 v4 = strcmp(attr, "ip") == 0; 319 if(v4 || strcmp(attr, "ipv6") == 0){ 320 *l = rralloc(v4? Ta: Taaaa); 321 (*l)->owner = rp->host; 322 (*l)->ip = rp->host; 323 l = &(*l)->next; 324 continue; 325 } 326 memset(&req, 0, sizeof req); 327 req.isslave = 1; 328 req.aborttime = NS2MS(nowns) + Maxreqtm; 329 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0); 330 if(*l == nil) 331 *l = dnresolve(rp->host->name, Cin, Taaaa, &req, 332 0, 0, Recurse, 0, 0); 333 while(*l != nil) 334 l = &(*l)->next; 335 } 336 cfg.resolver = 1; 337 debug = 1; 338 } 339 340 void 341 preloadserveraddrs(void) 342 { 343 RR *rp, **l, *first; 344 345 l = &first; 346 for(rp = serveraddrs; rp != nil; rp = rp->next){ 347 lock(&dnlock); 348 rrcopy(rp, l); 349 unlock(&dnlock); 350 rrattach(first, Authoritative); 351 } 352 } 353 354 int 355 setserver(char *server) 356 { 357 if(servername != nil){ 358 free(servername); 359 servername = nil; 360 cfg.resolver = 0; 361 } 362 if(server == nil || *server == 0) 363 return 0; 364 servername = strdup(server); 365 squirrelserveraddrs(); 366 if(serveraddrs == nil){ 367 print("can't resolve %s\n", servername); 368 cfg.resolver = 0; 369 } else 370 cfg.resolver = 1; 371 return cfg.resolver? 0: -1; 372 } 373 374 void 375 doquery(char *name, char *tstr) 376 { 377 int len, type, rooted; 378 char *p, *np; 379 char buf[1024]; 380 RR *rr, *rp; 381 Request req; 382 383 if(cfg.resolver) 384 preloadserveraddrs(); 385 386 /* default to an "ip" request if alpha, "ptr" if numeric */ 387 if(tstr == nil || *tstr == 0) 388 if(strcmp(ipattr(name), "ip") == 0) 389 tstr = "ptr"; 390 else 391 tstr = "ip"; 392 393 /* if name end in '.', remove it */ 394 len = strlen(name); 395 if(len > 0 && name[len-1] == '.'){ 396 rooted = 1; 397 name[len-1] = 0; 398 } else 399 rooted = 0; 400 401 /* inverse queries may need to be permuted */ 402 strncpy(buf, name, sizeof buf); 403 if(strcmp("ptr", tstr) == 0 && cistrstr(name, ".arpa") == nil){ 404 /* TODO: reversing v6 addrs is harder */ 405 for(p = name; *p; p++) 406 ; 407 *p = '.'; 408 np = buf; 409 len = 0; 410 while(p >= name){ 411 len++; 412 p--; 413 if(*p == '.'){ 414 memmove(np, p+1, len); 415 np += len; 416 len = 0; 417 } 418 } 419 memmove(np, p+1, len); 420 np += len; 421 strcpy(np, "in-addr.arpa"); /* TODO: ip6.arpa for v6 */ 422 } 423 424 /* look it up */ 425 type = rrtype(tstr); 426 if(type < 0){ 427 print("!unknown type %s\n", tstr); 428 return; 429 } 430 431 memset(&req, 0, sizeof req); 432 getactivity(&req, 0); 433 req.isslave = 1; 434 req.aborttime = NS2MS(nowns) + Maxreqtm; 435 rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); 436 if(rr){ 437 print("----------------------------\n"); 438 for(rp = rr; rp; rp = rp->next) 439 print("answer %R\n", rp); 440 print("----------------------------\n"); 441 } 442 rrfreelist(rr); 443 444 putactivity(0); 445 } 446 447 void 448 docmd(int n, char **f) 449 { 450 int tmpsrv; 451 char *name, *type; 452 453 name = type = nil; 454 tmpsrv = 0; 455 456 if(*f[0] == '@') { 457 if(setserver(f[0]+1) < 0) 458 return; 459 460 switch(n){ 461 case 3: 462 type = f[2]; 463 /* fall through */ 464 case 2: 465 name = f[1]; 466 tmpsrv = 1; 467 break; 468 } 469 } else 470 switch(n){ 471 case 2: 472 type = f[1]; 473 /* fall through */ 474 case 1: 475 name = f[0]; 476 break; 477 } 478 479 if(name == nil) 480 return; 481 482 doquery(name, type); 483 484 if(tmpsrv) 485 setserver(""); 486 } 487