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 extern int inside; 14 15 static char *servername; 16 static RR *serverrr; 17 static RR *serveraddrs; 18 19 int cachedb; 20 char *dbfile; 21 int debug; 22 uchar ipaddr[IPaddrlen]; /* my ip address */ 23 char *logfile = "dns"; 24 int maxage = 60; 25 char mntpt[Maxpath]; 26 int needrefresh; 27 ulong now; 28 int resolver; 29 int testing; 30 char *trace; 31 int traceactivity; 32 char *zonerefreshprogram; 33 34 void docmd(int, char**); 35 void doquery(char*, char*); 36 void preloadserveraddrs(void); 37 int prettyrrfmt(Fmt*); 38 int setserver(char*); 39 void squirrelserveraddrs(void); 40 41 void 42 usage(void) 43 { 44 fprint(2, "%s: [-rx] [-f db-file]\n", argv0); 45 exits("usage"); 46 } 47 48 void 49 main(int argc, char *argv[]) 50 { 51 int n; 52 Biobuf in; 53 char *p; 54 char *f[4]; 55 56 strcpy(mntpt, "/net"); 57 inside = 1; 58 59 ARGBEGIN{ 60 case 'f': 61 dbfile = EARGF(usage()); 62 break; 63 case 'r': 64 resolver = 1; 65 break; 66 case 'x': 67 dbfile = "/lib/ndb/external"; 68 strcpy(mntpt, "/net.alt"); 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 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\n", 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 Tnull: 189 seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data); 190 break; 191 case Ttxt: 192 p = seprint(p, e, "\t"); 193 for(t = rp->txt; t != nil; t = t->next) 194 p = seprint(p, e, "%s", t->p); 195 break; 196 case Trp: 197 seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name); 198 break; 199 case Tkey: 200 seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto, 201 rp->key->alg); 202 break; 203 case Tsig: 204 seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s", 205 rp->sig->type, rp->sig->alg, rp->sig->labels, 206 rp->sig->ttl, rp->sig->exp, rp->sig->incep, 207 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 } 214 out: 215 return fmtstrcpy(f, buf); 216 } 217 218 void 219 logsection(char *flag, RR *rp) 220 { 221 if(rp == nil) 222 return; 223 print("\t%s%R\n", flag, rp); 224 for(rp = rp->next; rp != nil; rp = rp->next) 225 print("\t %R\n", rp); 226 } 227 228 void 229 logreply(int id, uchar *addr, DNSmsg *mp) 230 { 231 RR *rp; 232 char buf[12], resp[32]; 233 234 switch(mp->flags & Rmask){ 235 case Rok: 236 strcpy(resp, "OK"); 237 break; 238 case Rformat: 239 strcpy(resp, "Format error"); 240 break; 241 case Rserver: 242 strcpy(resp, "Server failed"); 243 break; 244 case Rname: 245 strcpy(resp, "Nonexistent"); 246 break; 247 case Runimplimented: 248 strcpy(resp, "Unimplemented"); 249 break; 250 case Rrefused: 251 strcpy(resp, "Refused"); 252 break; 253 default: 254 sprint(resp, "%d", mp->flags & Rmask); 255 break; 256 } 257 258 print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr, 259 mp->flags & Fauth ? "authoritative" : "", 260 mp->flags & Ftrunc ? " truncated" : "", 261 mp->flags & Frecurse ? " recurse" : "", 262 mp->flags & Fcanrec ? " can_recurse" : "", 263 mp->flags & (Fauth|Rname) == (Fauth|Rname) ? 264 " nx" : ""); 265 for(rp = mp->qd; rp != nil; rp = rp->next) 266 print("\tQ: %s %s\n", rp->owner->name, 267 rrname(rp->type, buf, sizeof buf)); 268 logsection("Ans: ", mp->an); 269 logsection("Auth: ", mp->ns); 270 logsection("Hint: ", mp->ar); 271 } 272 273 void 274 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 275 { 276 char buf[12]; 277 278 print("%d.%d: sending to %I/%s %s %s\n", id, subid, 279 addr, sname, rname, rrname(type, buf, sizeof buf)); 280 } 281 282 RR* 283 getdnsservers(int class) 284 { 285 RR *rr; 286 287 if(servername == nil) 288 return dnsservers(class); 289 290 rr = rralloc(Tns); 291 rr->owner = dnlookup("local#dns#servers", class, 1); 292 rr->host = dnlookup(servername, class, 1); 293 294 return rr; 295 } 296 297 void 298 squirrelserveraddrs(void) 299 { 300 RR *rr, *rp, **l; 301 Request req; 302 303 /* look up the resolver address first */ 304 resolver = 0; 305 debug = 0; 306 if(serveraddrs) 307 rrfreelist(serveraddrs); 308 serveraddrs = nil; 309 rr = getdnsservers(Cin); 310 l = &serveraddrs; 311 for(rp = rr; rp != nil; rp = rp->next){ 312 if(strcmp(ipattr(rp->host->name), "ip") == 0){ 313 *l = rralloc(Ta); 314 (*l)->owner = rp->host; 315 (*l)->ip = rp->host; 316 l = &(*l)->next; 317 continue; 318 } 319 req.isslave = 1; 320 req.aborttime = now + Maxreqtm*2; /* be patient */ 321 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0); 322 while(*l != nil) 323 l = &(*l)->next; 324 } 325 resolver = 1; 326 debug = 1; 327 } 328 329 void 330 preloadserveraddrs(void) 331 { 332 RR *rp, **l, *first; 333 334 l = &first; 335 for(rp = serveraddrs; rp != nil; rp = rp->next){ 336 rrcopy(rp, l); 337 rrattach(first, 1); 338 } 339 } 340 341 int 342 setserver(char *server) 343 { 344 if(servername != nil){ 345 free(servername); 346 servername = nil; 347 resolver = 0; 348 } 349 if(server == nil || *server == 0) 350 return 0; 351 servername = strdup(server); 352 squirrelserveraddrs(); 353 if(serveraddrs == nil){ 354 print("can't resolve %s\n", servername); 355 resolver = 0; 356 } else 357 resolver = 1; 358 return resolver ? 0 : -1; 359 } 360 361 void 362 doquery(char *name, char *tstr) 363 { 364 int len, type, rooted; 365 char *p, *np; 366 char buf[1024]; 367 RR *rr, *rp; 368 Request req; 369 370 if(resolver) 371 preloadserveraddrs(); 372 373 /* default to an "ip" request if alpha, "ptr" if numeric */ 374 if(tstr == nil || *tstr == 0) 375 if(strcmp(ipattr(name), "ip") == 0) 376 tstr = "ptr"; 377 else 378 tstr = "ip"; 379 380 /* if name end in '.', remove it */ 381 len = strlen(name); 382 if(len > 0 && name[len-1] == '.'){ 383 rooted = 1; 384 name[len-1] = 0; 385 } else 386 rooted = 0; 387 388 /* inverse queries may need to be permuted */ 389 strncpy(buf, name, sizeof buf); 390 if(strcmp("ptr", tstr) == 0 391 && strstr(name, "IN-ADDR") == 0 392 && strstr(name, "in-addr") == 0){ 393 for(p = name; *p; p++) 394 ; 395 *p = '.'; 396 np = buf; 397 len = 0; 398 while(p >= name){ 399 len++; 400 p--; 401 if(*p == '.'){ 402 memmove(np, p+1, len); 403 np += len; 404 len = 0; 405 } 406 } 407 memmove(np, p+1, len); 408 np += len; 409 strcpy(np, "in-addr.arpa"); 410 } 411 412 /* look it up */ 413 type = rrtype(tstr); 414 if(type < 0){ 415 print("!unknown type %s\n", tstr); 416 return; 417 } 418 419 memset(&req, 0, sizeof req); 420 getactivity(&req, 0); 421 req.isslave = 1; 422 req.aborttime = now + Maxreqtm*2; /* be patient */ 423 rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); 424 if(rr){ 425 print("----------------------------\n"); 426 for(rp = rr; rp; rp = rp->next) 427 print("answer %R\n", rp); 428 print("----------------------------\n"); 429 } 430 rrfreelist(rr); 431 432 putactivity(0); 433 } 434 435 void 436 docmd(int n, char **f) 437 { 438 int tmpsrv; 439 char *name, *type; 440 441 name = type = nil; 442 tmpsrv = 0; 443 444 if(*f[0] == '@') { 445 if(setserver(f[0]+1) < 0) 446 return; 447 448 switch(n){ 449 case 3: 450 type = f[2]; 451 /* fall through */ 452 case 2: 453 name = f[1]; 454 tmpsrv = 1; 455 break; 456 } 457 } else { 458 switch(n){ 459 case 2: 460 type = f[1]; 461 /* fall through */ 462 case 1: 463 name = f[0]; 464 break; 465 } 466 } 467 468 if(name == nil) 469 return; 470 471 doquery(name, type); 472 473 if(tmpsrv) 474 setserver(""); 475 } 476