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