diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ndb/dnsdebug.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ndb/dnsdebug.c')
-rwxr-xr-x | sys/src/cmd/ndb/dnsdebug.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/sys/src/cmd/ndb/dnsdebug.c b/sys/src/cmd/ndb/dnsdebug.c new file mode 100755 index 000000000..28ecf9a1c --- /dev/null +++ b/sys/src/cmd/ndb/dnsdebug.c @@ -0,0 +1,483 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <ip.h> +#include <ndb.h> +#include "dns.h" + +enum { + Maxrequest= 128, +}; + +Cfg cfg; + +static char *servername; +static RR *serverrr; +static RR *serveraddrs; + +char *dbfile; +int debug; +uchar ipaddr[IPaddrlen]; /* my ip address */ +char *logfile = "dnsdebug"; +int maxage = 60*60; +char mntpt[Maxpath]; +int needrefresh; +ulong now; +vlong nowns; +int testing; +char *trace; +int traceactivity; +char *zonerefreshprogram; + +void docmd(int, char**); +void doquery(char*, char*); +void preloadserveraddrs(void); +int prettyrrfmt(Fmt*); +int setserver(char*); +void squirrelserveraddrs(void); + +void +usage(void) +{ + fprint(2, "%s: [-rx] [-f db-file] [[@server] domain [type]]\n", argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int n; + Biobuf in; + char *p; + char *f[4]; + + strcpy(mntpt, "/net"); + cfg.inside = 1; + + ARGBEGIN{ + case 'f': + dbfile = EARGF(usage()); + break; + case 'r': + cfg.resolver = 1; + break; + case 'x': + dbfile = "/lib/ndb/external"; + strcpy(mntpt, "/net.alt"); + break; + default: + usage(); + }ARGEND + + now = time(nil); + nowns = nsec(); + dninit(); + fmtinstall('R', prettyrrfmt); + if(myipaddr(ipaddr, mntpt) < 0) + sysfatal("can't read my ip address"); + opendatabase(); + + if(cfg.resolver) + squirrelserveraddrs(); + + debug = 1; + + if(argc > 0){ + docmd(argc, argv); + exits(0); + } + + Binit(&in, 0, OREAD); + for(print("> "); p = Brdline(&in, '\n'); print("> ")){ + p[Blinelen(&in)-1] = 0; + n = tokenize(p, f, 3); + if(n>=1) { + dnpurge(); /* flush the cache */ + docmd(n, f); + } + } + exits(0); +} + +static char* +longtime(long t) +{ + int d, h, m, n; + static char x[128]; + + for(d = 0; t >= 24*60*60; t -= 24*60*60) + d++; + for(h = 0; t >= 60*60; t -= 60*60) + h++; + for(m = 0; t >= 60; t -= 60) + m++; + n = 0; + if(d) + n += sprint(x, "%d day ", d); + if(h) + n += sprint(x+n, "%d hr ", h); + if(m) + n += sprint(x+n, "%d min ", m); + if(t || n == 0) + sprint(x+n, "%ld sec", t); + return x; +} + +int +prettyrrfmt(Fmt *f) +{ + RR *rp; + char buf[3*Domlen]; + char *p, *e; + Txt *t; + + rp = va_arg(f->args, RR*); + if(rp == 0){ + strcpy(buf, "<null>"); + goto out; + } + + p = buf; + e = buf + sizeof(buf); + p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name, + longtime(rp->db? rp->ttl: (rp->ttl - now)), + rrname(rp->type, buf, sizeof buf)); + + if(rp->negative){ + seprint(p, e, "negative rcode %d", rp->negrcode); + goto out; + } + + switch(rp->type){ + case Thinfo: + seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name); + break; + case Tcname: + case Tmb: + case Tmd: + case Tmf: + case Tns: + seprint(p, e, "\t%s", (rp->host? rp->host->name: "")); + break; + case Tmg: + case Tmr: + seprint(p, e, "\t%s", (rp->mb? rp->mb->name: "")); + break; + case Tminfo: + seprint(p, e, "\t%s %s", (rp->mb? rp->mb->name: ""), + (rp->rmb? rp->rmb->name: "")); + break; + case Tmx: + seprint(p, e, "\t%lud %s", rp->pref, + (rp->host? rp->host->name: "")); + break; + case Ta: + case Taaaa: + seprint(p, e, "\t%s", (rp->ip? rp->ip->name: "")); + break; + case Tptr: + seprint(p, e, "\t%s", (rp->ptr? rp->ptr->name: "")); + break; + case Tsoa: + seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", + rp->host->name, rp->rmb->name, rp->soa->serial, + rp->soa->refresh, rp->soa->retry, + rp->soa->expire, rp->soa->minttl); + break; + case Tsrv: + seprint(p, e, "\t%ud %ud %ud %s", + rp->srv->pri, rp->srv->weight, rp->port, rp->host->name); + break; + case Tnull: + seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data); + break; + case Ttxt: + p = seprint(p, e, "\t"); + for(t = rp->txt; t != nil; t = t->next) + p = seprint(p, e, "%s", t->p); + break; + case Trp: + seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name); + break; + case Tkey: + seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto, + rp->key->alg); + break; + case Tsig: + seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s", + rp->sig->type, rp->sig->alg, rp->sig->labels, + rp->sig->ttl, rp->sig->exp, rp->sig->incep, + rp->sig->tag, rp->sig->signer->name); + break; + case Tcert: + seprint(p, e, "\t%d %d %d", + rp->sig->type, rp->sig->tag, rp->sig->alg); + break; + } +out: + return fmtstrcpy(f, buf); +} + +void +logsection(char *flag, RR *rp) +{ + if(rp == nil) + return; + print("\t%s%R\n", flag, rp); + for(rp = rp->next; rp != nil; rp = rp->next) + print("\t %R\n", rp); +} + +void +logreply(int id, uchar *addr, DNSmsg *mp) +{ + RR *rp; + char buf[12], resp[32]; + + switch(mp->flags & Rmask){ + case Rok: + strcpy(resp, "OK"); + break; + case Rformat: + strcpy(resp, "Format error"); + break; + case Rserver: + strcpy(resp, "Server failed"); + break; + case Rname: + strcpy(resp, "Nonexistent"); + break; + case Runimplimented: + strcpy(resp, "Unimplemented"); + break; + case Rrefused: + strcpy(resp, "Refused"); + break; + default: + sprint(resp, "%d", mp->flags & Rmask); + break; + } + + print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr, + mp->flags & Fauth? "authoritative": "", + mp->flags & Ftrunc? " truncated": "", + mp->flags & Frecurse? " recurse": "", + mp->flags & Fcanrec? " can_recurse": "", + (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": ""); + for(rp = mp->qd; rp != nil; rp = rp->next) + print("\tQ: %s %s\n", rp->owner->name, + rrname(rp->type, buf, sizeof buf)); + logsection("Ans: ", mp->an); + logsection("Auth: ", mp->ns); + logsection("Hint: ", mp->ar); +} + +void +logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) +{ + char buf[12]; + + print("%d.%d: sending to %I/%s %s %s\n", id, subid, + addr, sname, rname, rrname(type, buf, sizeof buf)); +} + +RR* +getdnsservers(int class) +{ + RR *rr; + + if(servername == nil) + return dnsservers(class); + + rr = rralloc(Tns); + rr->owner = dnlookup("local#dns#servers", class, 1); + rr->host = dnlookup(servername, class, 1); + + return rr; +} + +void +squirrelserveraddrs(void) +{ + int v4; + char *attr; + RR *rr, *rp, **l; + Request req; + + /* look up the resolver address first */ + cfg.resolver = 0; + debug = 0; + if(serveraddrs) + rrfreelist(serveraddrs); + serveraddrs = nil; + rr = getdnsservers(Cin); + l = &serveraddrs; + for(rp = rr; rp != nil; rp = rp->next){ + attr = ipattr(rp->host->name); + v4 = strcmp(attr, "ip") == 0; + if(v4 || strcmp(attr, "ipv6") == 0){ + *l = rralloc(v4? Ta: Taaaa); + (*l)->owner = rp->host; + (*l)->ip = rp->host; + l = &(*l)->next; + continue; + } + req.isslave = 1; + req.aborttime = NS2MS(nowns) + Maxreqtm; + *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0); + if(*l == nil) + *l = dnresolve(rp->host->name, Cin, Taaaa, &req, + 0, 0, Recurse, 0, 0); + while(*l != nil) + l = &(*l)->next; + } + cfg.resolver = 1; + debug = 1; +} + +void +preloadserveraddrs(void) +{ + RR *rp, **l, *first; + + l = &first; + for(rp = serveraddrs; rp != nil; rp = rp->next){ + rrcopy(rp, l); + rrattach(first, Authoritative); + } +} + +int +setserver(char *server) +{ + if(servername != nil){ + free(servername); + servername = nil; + cfg.resolver = 0; + } + if(server == nil || *server == 0) + return 0; + servername = strdup(server); + squirrelserveraddrs(); + if(serveraddrs == nil){ + print("can't resolve %s\n", servername); + cfg.resolver = 0; + } else + cfg.resolver = 1; + return cfg.resolver? 0: -1; +} + +void +doquery(char *name, char *tstr) +{ + int len, type, rooted; + char *p, *np; + char buf[1024]; + RR *rr, *rp; + Request req; + + if(cfg.resolver) + preloadserveraddrs(); + + /* default to an "ip" request if alpha, "ptr" if numeric */ + if(tstr == nil || *tstr == 0) + if(strcmp(ipattr(name), "ip") == 0) + tstr = "ptr"; + else + tstr = "ip"; + + /* if name end in '.', remove it */ + len = strlen(name); + if(len > 0 && name[len-1] == '.'){ + rooted = 1; + name[len-1] = 0; + } else + rooted = 0; + + /* inverse queries may need to be permuted */ + strncpy(buf, name, sizeof buf); + if(strcmp("ptr", tstr) == 0 && cistrstr(name, ".arpa") == nil){ + /* TODO: reversing v6 addrs is harder */ + for(p = name; *p; p++) + ; + *p = '.'; + np = buf; + len = 0; + while(p >= name){ + len++; + p--; + if(*p == '.'){ + memmove(np, p+1, len); + np += len; + len = 0; + } + } + memmove(np, p+1, len); + np += len; + strcpy(np, "in-addr.arpa"); /* TODO: ip6.arpa for v6 */ + } + + /* look it up */ + type = rrtype(tstr); + if(type < 0){ + print("!unknown type %s\n", tstr); + return; + } + + memset(&req, 0, sizeof req); + getactivity(&req, 0); + req.isslave = 1; + req.aborttime = NS2MS(nowns) + Maxreqtm; + rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); + if(rr){ + print("----------------------------\n"); + for(rp = rr; rp; rp = rp->next) + print("answer %R\n", rp); + print("----------------------------\n"); + } + rrfreelist(rr); + + putactivity(0); +} + +void +docmd(int n, char **f) +{ + int tmpsrv; + char *name, *type; + + name = type = nil; + tmpsrv = 0; + + if(*f[0] == '@') { + if(setserver(f[0]+1) < 0) + return; + + switch(n){ + case 3: + type = f[2]; + /* fall through */ + case 2: + name = f[1]; + tmpsrv = 1; + break; + } + } else + switch(n){ + case 2: + type = f[1]; + /* fall through */ + case 1: + name = f[0]; + break; + } + + if(name == nil) + return; + + doquery(name, type); + + if(tmpsrv) + setserver(""); +} |