dnsdebug.c 8.1 KB

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