dnsdebug.c 8.4 KB

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