dnsdebug.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <ctype.h>
  13. #include <ip.h>
  14. #include <ndb.h>
  15. #include "dns.h"
  16. enum {
  17. Maxrequest= 128,
  18. };
  19. Cfg cfg;
  20. static char *servername;
  21. static RR *serveraddrs;
  22. char *dbfile;
  23. int debug;
  24. uint8_t ipaddr[IPaddrlen]; /* my ip address */
  25. char *logfile = "dnsdebug";
  26. int maxage = 60*60;
  27. char mntpt[Maxpath];
  28. int needrefresh;
  29. uint32_t now;
  30. int64_t nowns;
  31. int testing;
  32. char *trace;
  33. int traceactivity;
  34. char *zonerefreshprogram;
  35. void docmd(int, char**);
  36. void doquery(char*, char*);
  37. void preloadserveraddrs(void);
  38. int prettyrrfmt(Fmt*);
  39. int setserver(char*);
  40. void squirrelserveraddrs(void);
  41. void
  42. usage(void)
  43. {
  44. fprint(2, "%s: [-rx] [-f db-file] [[@server] domain [type]]\n", argv0);
  45. exits("usage");
  46. }
  47. void
  48. main(int argc, char *argv[])
  49. {
  50. int n;
  51. Biobuf in;
  52. char *p;
  53. char *f[4];
  54. strcpy(mntpt, "/net");
  55. cfg.inside = 1;
  56. ARGBEGIN{
  57. case 'f':
  58. dbfile = EARGF(usage());
  59. break;
  60. case 'r':
  61. cfg.resolver = 1;
  62. break;
  63. case 'x':
  64. dbfile = "/lib/ndb/external";
  65. strcpy(mntpt, "/net.alt");
  66. break;
  67. default:
  68. usage();
  69. }ARGEND
  70. now = time(nil);
  71. nowns = nsec();
  72. dninit();
  73. fmtinstall('R', prettyrrfmt);
  74. if(myipaddr(ipaddr, mntpt) < 0)
  75. sysfatal("can't read my ip address");
  76. opendatabase();
  77. if(cfg.resolver)
  78. squirrelserveraddrs();
  79. debug = 1;
  80. if(argc > 0){
  81. docmd(argc, argv);
  82. exits(0);
  83. }
  84. Binit(&in, 0, OREAD);
  85. for(print("> "); p = Brdline(&in, '\n'); print("> ")){
  86. p[Blinelen(&in)-1] = 0;
  87. n = tokenize(p, f, 3);
  88. if(n>=1) {
  89. dnpurge(); /* flush the cache */
  90. docmd(n, f);
  91. }
  92. }
  93. exits(0);
  94. }
  95. static char*
  96. longtime(int32_t t)
  97. {
  98. int d, h, m, n;
  99. static char x[128];
  100. for(d = 0; t >= 24*60*60; t -= 24*60*60)
  101. d++;
  102. for(h = 0; t >= 60*60; t -= 60*60)
  103. h++;
  104. for(m = 0; t >= 60; t -= 60)
  105. m++;
  106. n = 0;
  107. if(d)
  108. n += sprint(x, "%d day ", d);
  109. if(h)
  110. n += sprint(x+n, "%d hr ", h);
  111. if(m)
  112. n += sprint(x+n, "%d min ", m);
  113. if(t || n == 0)
  114. sprint(x+n, "%ld sec", t);
  115. return x;
  116. }
  117. int
  118. prettyrrfmt(Fmt *f)
  119. {
  120. RR *rp;
  121. char buf[3*Domlen];
  122. char *p, *e;
  123. Txt *t;
  124. rp = va_arg(f->args, RR*);
  125. if(rp == 0){
  126. strcpy(buf, "<null>");
  127. goto out;
  128. }
  129. p = buf;
  130. e = buf + sizeof(buf);
  131. p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
  132. longtime(rp->db? rp->ttl: (rp->ttl - now)),
  133. rrname(rp->type, buf, sizeof buf));
  134. if(rp->negative){
  135. seprint(p, e, "negative rcode %d", rp->negrcode);
  136. goto out;
  137. }
  138. switch(rp->type){
  139. case Thinfo:
  140. seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name);
  141. break;
  142. case Tcname:
  143. case Tmb:
  144. case Tmd:
  145. case Tmf:
  146. case Tns:
  147. seprint(p, e, "\t%s", (rp->host? rp->host->name: ""));
  148. break;
  149. case Tmg:
  150. case Tmr:
  151. seprint(p, e, "\t%s", (rp->mb? rp->mb->name: ""));
  152. break;
  153. case Tminfo:
  154. seprint(p, e, "\t%s %s", (rp->mb? rp->mb->name: ""),
  155. (rp->rmb? rp->rmb->name: ""));
  156. break;
  157. case Tmx:
  158. seprint(p, e, "\t%lud %s", rp->pref,
  159. (rp->host? rp->host->name: ""));
  160. break;
  161. case Ta:
  162. case Taaaa:
  163. seprint(p, e, "\t%s", (rp->ip? rp->ip->name: ""));
  164. break;
  165. case Tptr:
  166. seprint(p, e, "\t%s", (rp->ptr? rp->ptr->name: ""));
  167. break;
  168. case Tsoa:
  169. seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud",
  170. rp->host->name, rp->rmb->name, rp->soa->serial,
  171. rp->soa->refresh, rp->soa->retry,
  172. rp->soa->expire, rp->soa->minttl);
  173. break;
  174. case Tsrv:
  175. seprint(p, e, "\t%ud %ud %ud %s",
  176. rp->srv->pri, rp->srv->weight, rp->port, rp->host->name);
  177. break;
  178. case Tnull:
  179. seprint(p, e, "\t%.*H", rp->null->Block.dlen, rp->null->Block.data);
  180. break;
  181. case Ttxt:
  182. p = seprint(p, e, "\t");
  183. for(t = rp->txt; t != nil; t = t->next)
  184. p = seprint(p, e, "%s", t->p);
  185. break;
  186. case Trp:
  187. seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name);
  188. break;
  189. case Tkey:
  190. seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
  191. rp->key->alg);
  192. break;
  193. case Tsig:
  194. seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
  195. rp->sig->Cert.type, rp->sig->Cert.alg, rp->sig->labels,
  196. rp->sig->ttl, rp->sig->exp, rp->sig->incep,
  197. rp->sig->Cert.tag, rp->sig->signer->name);
  198. break;
  199. case Tcert:
  200. seprint(p, e, "\t%d %d %d",
  201. rp->sig->Cert.type, rp->sig->Cert.tag, rp->sig->Cert.alg);
  202. break;
  203. }
  204. out:
  205. return fmtstrcpy(f, buf);
  206. }
  207. void
  208. logsection(char *flag, RR *rp)
  209. {
  210. if(rp == nil)
  211. return;
  212. print("\t%s%R\n", flag, rp);
  213. for(rp = rp->next; rp != nil; rp = rp->next)
  214. print("\t %R\n", rp);
  215. }
  216. void
  217. logreply(int id, uint8_t *addr, DNSmsg *mp)
  218. {
  219. RR *rp;
  220. char buf[12], resp[32];
  221. switch(mp->flags & Rmask){
  222. case Rok:
  223. strcpy(resp, "OK");
  224. break;
  225. case Rformat:
  226. strcpy(resp, "Format error");
  227. break;
  228. case Rserver:
  229. strcpy(resp, "Server failed");
  230. break;
  231. case Rname:
  232. strcpy(resp, "Nonexistent");
  233. break;
  234. case Runimplimented:
  235. strcpy(resp, "Unimplemented");
  236. break;
  237. case Rrefused:
  238. strcpy(resp, "Refused");
  239. break;
  240. default:
  241. sprint(resp, "%d", mp->flags & Rmask);
  242. break;
  243. }
  244. print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
  245. mp->flags & Fauth? "authoritative": "",
  246. mp->flags & Ftrunc? " truncated": "",
  247. mp->flags & Frecurse? " recurse": "",
  248. mp->flags & Fcanrec? " can_recurse": "",
  249. (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
  250. for(rp = mp->qd; rp != nil; rp = rp->next)
  251. print("\tQ: %s %s\n", rp->owner->name,
  252. rrname(rp->type, buf, sizeof buf));
  253. logsection("Ans: ", mp->an);
  254. logsection("Auth: ", mp->ns);
  255. logsection("Hint: ", mp->ar);
  256. }
  257. void
  258. logsend(int id, int subid, uint8_t *addr, char *sname, char *rname,
  259. int type)
  260. {
  261. char buf[12];
  262. print("%d.%d: sending to %I/%s %s %s\n", id, subid,
  263. addr, sname, rname, rrname(type, buf, sizeof buf));
  264. }
  265. RR*
  266. getdnsservers(int class)
  267. {
  268. RR *rr;
  269. if(servername == nil)
  270. return dnsservers(class);
  271. rr = rralloc(Tns);
  272. rr->owner = dnlookup("local#dns#servers", class, 1);
  273. rr->host = dnlookup(servername, class, 1);
  274. return rr;
  275. }
  276. void
  277. squirrelserveraddrs(void)
  278. {
  279. int v4;
  280. char *attr;
  281. RR *rr, *rp, **l;
  282. Request req;
  283. /* look up the resolver address first */
  284. cfg.resolver = 0;
  285. debug = 0;
  286. if(serveraddrs)
  287. rrfreelist(serveraddrs);
  288. serveraddrs = nil;
  289. rr = getdnsservers(Cin);
  290. l = &serveraddrs;
  291. for(rp = rr; rp != nil; rp = rp->next){
  292. attr = ipattr(rp->host->name);
  293. v4 = strcmp(attr, "ip") == 0;
  294. if(v4 || strcmp(attr, "ipv6") == 0){
  295. *l = rralloc(v4? Ta: Taaaa);
  296. (*l)->owner = rp->host;
  297. (*l)->ip = rp->host;
  298. l = &(*l)->next;
  299. continue;
  300. }
  301. memset(&req, 0, sizeof req);
  302. req.isslave = 1;
  303. req.aborttime = NS2MS(nowns) + Maxreqtm;
  304. *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
  305. if(*l == nil)
  306. *l = dnresolve(rp->host->name, Cin, Taaaa, &req,
  307. 0, 0, Recurse, 0, 0);
  308. while(*l != nil)
  309. l = &(*l)->next;
  310. }
  311. cfg.resolver = 1;
  312. debug = 1;
  313. }
  314. void
  315. preloadserveraddrs(void)
  316. {
  317. RR *rp, **l, *first;
  318. l = &first;
  319. for(rp = serveraddrs; rp != nil; rp = rp->next){
  320. lock(&dnlock);
  321. rrcopy(rp, l);
  322. unlock(&dnlock);
  323. rrattach(first, Authoritative);
  324. }
  325. }
  326. int
  327. setserver(char *server)
  328. {
  329. if(servername != nil){
  330. free(servername);
  331. servername = nil;
  332. cfg.resolver = 0;
  333. }
  334. if(server == nil || *server == 0)
  335. return 0;
  336. servername = strdup(server);
  337. squirrelserveraddrs();
  338. if(serveraddrs == nil){
  339. print("can't resolve %s\n", servername);
  340. cfg.resolver = 0;
  341. } else
  342. cfg.resolver = 1;
  343. return cfg.resolver? 0: -1;
  344. }
  345. void
  346. doquery(char *name, char *tstr)
  347. {
  348. int len, type, rooted;
  349. char *p, *np;
  350. char buf[1024];
  351. RR *rr, *rp;
  352. Request req;
  353. if(cfg.resolver)
  354. preloadserveraddrs();
  355. /* default to an "ip" request if alpha, "ptr" if numeric */
  356. if(tstr == nil || *tstr == 0)
  357. if(strcmp(ipattr(name), "ip") == 0)
  358. tstr = "ptr";
  359. else
  360. tstr = "ip";
  361. /* if name end in '.', remove it */
  362. len = strlen(name);
  363. if(len > 0 && name[len-1] == '.'){
  364. rooted = 1;
  365. name[len-1] = 0;
  366. } else
  367. rooted = 0;
  368. /* inverse queries may need to be permuted */
  369. strncpy(buf, name, sizeof buf);
  370. if(strcmp("ptr", tstr) == 0 && cistrstr(name, ".arpa") == nil){
  371. /* TODO: reversing v6 addrs is harder */
  372. for(p = name; *p; p++)
  373. ;
  374. *p = '.';
  375. np = buf;
  376. len = 0;
  377. while(p >= name){
  378. len++;
  379. p--;
  380. if(*p == '.'){
  381. memmove(np, p+1, len);
  382. np += len;
  383. len = 0;
  384. }
  385. }
  386. memmove(np, p+1, len);
  387. np += len;
  388. strcpy(np, "in-addr.arpa"); /* TODO: ip6.arpa for v6 */
  389. }
  390. /* look it up */
  391. type = rrtype(tstr);
  392. if(type < 0){
  393. print("!unknown type %s\n", tstr);
  394. return;
  395. }
  396. memset(&req, 0, sizeof req);
  397. getactivity(&req, 0);
  398. req.isslave = 1;
  399. req.aborttime = NS2MS(nowns) + Maxreqtm;
  400. rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
  401. if(rr){
  402. print("----------------------------\n");
  403. for(rp = rr; rp; rp = rp->next)
  404. print("answer %R\n", rp);
  405. print("----------------------------\n");
  406. }
  407. rrfreelist(rr);
  408. putactivity(0);
  409. }
  410. void
  411. docmd(int n, char **f)
  412. {
  413. int tmpsrv;
  414. char *name, *type;
  415. name = type = nil;
  416. tmpsrv = 0;
  417. if(*f[0] == '@') {
  418. if(setserver(f[0]+1) < 0)
  419. return;
  420. switch(n){
  421. case 3:
  422. type = f[2];
  423. /* fall through */
  424. case 2:
  425. name = f[1];
  426. tmpsrv = 1;
  427. break;
  428. }
  429. } else
  430. switch(n){
  431. case 2:
  432. type = f[1];
  433. /* fall through */
  434. case 1:
  435. name = f[0];
  436. break;
  437. }
  438. if(name == nil)
  439. return;
  440. doquery(name, type);
  441. if(tmpsrv)
  442. setserver("");
  443. }