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