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