summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ndb/dnsdebug.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/ndb/dnsdebug.c483
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("");
+}