dnsdebug.c 8.4 KB

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