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 *p; 48 char *f[4]; 49 Ipifc *ifcs; 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', prettyrrconv); 66 ifcs = readipifc(mntpt, nil); 67 if(ifcs == nil) 68 sysfatal("can't read my ip address"); 69 ipmove(ipaddr, ifcs->ip); 70 opendatabase(); 71 72 if(resolver) 73 squirrelserveraddrs(); 74 75 debug = 1; 76 77 if(argc > 0){ 78 docmd(argc, argv); 79 exits(0); 80 } 81 82 Binit(&in, 0, OREAD); 83 for(print("> "); p = Brdline(&in, '\n'); print("> ")){ 84 p[Blinelen(&in)-1] = 0; 85 n = tokenize(p, f, 3); 86 if(n<1) 87 continue; 88 89 /* flush the cache */ 90 dnpurge(); 91 92 docmd(n, f); 93 94 } 95 exits(0); 96 } 97 98 static char* 99 longtime(long t) 100 { 101 int d, h, m, n; 102 static char x[128]; 103 104 for(d = 0; t >= 24*60*60; t -= 24*60*60) 105 d++; 106 for(h = 0; t >= 60*60; t -= 60*60) 107 h++; 108 for(m = 0; t >= 60; t -= 60) 109 m++; 110 n = 0; 111 if(d) 112 n += sprint(x, "%d day ", d); 113 if(h) 114 n += sprint(x+n, "%d hr ", h); 115 if(m) 116 n += sprint(x+n, "%d min ", m); 117 if(t || n == 0) 118 sprint(x+n, "%ld sec", t); 119 return x; 120 } 121 122 int 123 prettyrrconv(va_list *arg, Fconv *f) 124 { 125 RR *rp; 126 char buf[3*Domlen]; 127 char *p, *e; 128 129 rp = va_arg(*arg, 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)); 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 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 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 strconv(buf, f); 202 return sizeof(RR*); 203 } 204 205 void 206 logsection(char *flag, RR *rp) 207 { 208 if(rp == nil) 209 return; 210 print("\t%s%R\n", flag, rp); 211 for(rp = rp->next; rp != nil; rp = rp->next) 212 print("\t %R\n", rp); 213 } 214 215 void 216 logreply(int id, uchar *addr, DNSmsg *mp) 217 { 218 RR *rp; 219 char buf[12]; 220 char resp[32]; 221 222 switch(mp->flags & Rmask){ 223 case Rok: 224 strcpy(resp, "OK"); 225 break; 226 case Rformat: 227 strcpy(resp, "Format error"); 228 break; 229 case Rserver: 230 strcpy(resp, "Server failed"); 231 break; 232 case Rname: 233 strcpy(resp, "Nonexistent"); 234 break; 235 case Runimplimented: 236 strcpy(resp, "Unimplemented"); 237 break; 238 case Rrefused: 239 strcpy(resp, "Refused"); 240 break; 241 default: 242 sprint(resp, "%d", mp->flags & Rmask); 243 break; 244 } 245 246 print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr, 247 mp->flags & Fauth ? "authoritative" : "", 248 mp->flags & Ftrunc ? " truncated" : "", 249 mp->flags & Frecurse ? " recurse" : "", 250 mp->flags & Fcanrec ? " can_recurse" : "", 251 mp->flags & (Fauth|Rname) == (Fauth|Rname) ? 252 " nx" : ""); 253 for(rp = mp->qd; rp != nil; rp = rp->next) 254 print("\tQ: %s %s\n", rp->owner->name, rrname(rp->type, buf)); 255 logsection("Ans: ", mp->an); 256 logsection("Auth: ", mp->ns); 257 logsection("Hint: ", mp->ar); 258 } 259 260 void 261 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 262 { 263 char buf[12]; 264 265 print("%d.%d: sending to %I/%s %s %s\n", id, subid, 266 addr, sname, rname, rrname(type, buf)); 267 } 268 269 RR* 270 getdnsservers(int class) 271 { 272 RR *rr; 273 274 if(servername == nil) 275 return dnsservers(class); 276 277 rr = rralloc(Tns); 278 rr->owner = dnlookup("local#dns#servers", class, 1); 279 rr->host = dnlookup(servername, class, 1); 280 281 return rr; 282 } 283 284 void 285 squirrelserveraddrs(void) 286 { 287 RR *rr, *rp, **l; 288 Request req; 289 290 /* look up the resolver address first */ 291 resolver = 0; 292 debug = 0; 293 if(serveraddrs) 294 rrfreelist(serveraddrs); 295 serveraddrs = nil; 296 rr = getdnsservers(Cin); 297 l = &serveraddrs; 298 for(rp = rr; rp != nil; rp = rp->next){ 299 if(strcmp(ipattr(rp->host->name), "ip") == 0){ 300 *l = rralloc(Ta); 301 (*l)->owner = rp->host; 302 (*l)->ip = rp->host; 303 l = &(*l)->next; 304 continue; 305 } 306 req.isslave = 1; 307 req.aborttime = now + 60; /* don't spend more than 60 seconds */ 308 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 1, 0); 309 while(*l != nil) 310 l = &(*l)->next; 311 } 312 resolver = 1; 313 debug = 1; 314 } 315 316 void 317 preloadserveraddrs(void) 318 { 319 RR *rp, **l, *first; 320 321 l = &first; 322 for(rp = serveraddrs; rp != nil; rp = rp->next){ 323 rrcopy(rp, l); 324 rrattach(first, 1); 325 } 326 } 327 328 int 329 setserver(char *server) 330 { 331 if(servername != nil){ 332 free(servername); 333 servername = nil; 334 resolver = 0; 335 } 336 if(server == nil || *server == 0) 337 return 0; 338 servername = strdup(server); 339 squirrelserveraddrs(); 340 if(serveraddrs == nil){ 341 print("can't resolve %s\n", servername); 342 resolver = 0; 343 } else { 344 resolver = 1; 345 } 346 return resolver ? 0 : -1; 347 } 348 349 void 350 doquery(char *name, char *tstr) 351 { 352 Request req; 353 RR *rr, *rp; 354 int len, type; 355 char *p, *np; 356 char buf[1024]; 357 358 if(resolver) 359 preloadserveraddrs(); 360 361 /* default to an "ip" request if alpha, "ptr" if numeric */ 362 if(tstr == nil || *tstr == 0) { 363 if(strcmp(ipattr(name), "ip") == 0) 364 tstr = "ptr"; 365 else 366 tstr = "ip"; 367 } 368 369 /* if name end in '.', remove it */ 370 len = strlen(name); 371 if(len > 0 && name[len-1] == '.') 372 name[len-1] = 0; 373 374 /* inverse queries may need to be permuted */ 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 strcpy(name, buf); 396 } 397 398 /* look it up */ 399 type = rrtype(tstr); 400 if(type < 0){ 401 print("!unknown type %s\n", tstr); 402 return; 403 } 404 405 getactivity(&req); 406 req.isslave = 1; 407 req.aborttime = now + 60; /* don't spend more than 60 seconds */ 408 rr = dnresolve(name, Cin, type, &req, 0, 0, Recurse, 1, 0); 409 if(rr){ 410 print("----------------------------\n"); 411 for(rp = rr; rp; rp = rp->next) 412 print("answer %R\n", rp); 413 print("----------------------------\n"); 414 } 415 rrfreelist(rr); 416 417 putactivity(); 418 } 419 420 void 421 docmd(int n, char **f) 422 { 423 int tmpsrv; 424 char *name, *type; 425 426 name = nil; 427 type = nil; 428 tmpsrv = 0; 429 430 if(*f[0] == '@') { 431 if(setserver(f[0]+1) < 0) 432 return; 433 434 switch(n){ 435 case 3: 436 type = f[2]; 437 /* fall through */ 438 case 2: 439 name = f[1]; 440 tmpsrv = 1; 441 break; 442 } 443 } else { 444 switch(n){ 445 case 2: 446 type = f[1]; 447 /* fall through */ 448 case 1: 449 name = f[0]; 450 break; 451 } 452 } 453 454 if(name == nil) 455 return; 456 457 doquery(name, type); 458 459 if(tmpsrv) 460 setserver(""); 461 } 462