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