123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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 *serveraddrs;
- char *dbfile;
- int debug;
- uint8_t ipaddr[IPaddrlen]; /* my ip address */
- char *logfile = "dnsdebug";
- int maxage = 60*60;
- char mntpt[Maxpath];
- int needrefresh;
- uint32_t now;
- int64_t 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(int32_t 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%lu %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 %lu %lu %lu %lu %lu",
- 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%u %u %u %s",
- rp->srv->pri, rp->srv->weight, rp->port, rp->host->name);
- break;
- case Tnull:
- seprint(p, e, "\t%.*H", rp->null->Block.dlen, rp->null->Block.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 %lu %lu %lu %d %s",
- rp->sig->Cert.type, rp->sig->Cert.alg, rp->sig->labels,
- rp->sig->ttl, rp->sig->exp, rp->sig->incep,
- rp->sig->Cert.tag, rp->sig->signer->name);
- break;
- case Tcert:
- seprint(p, e, "\t%d %d %d",
- rp->sig->Cert.type, rp->sig->Cert.tag, rp->sig->Cert.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, uint8_t *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, uint8_t *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;
- }
- memset(&req, 0, sizeof req);
- 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){
- lock(&dnlock);
- rrcopy(rp, l);
- unlock(&dnlock);
- 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("");
- }
|