dnsdebug.c 8.9 KB

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