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