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