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