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