dnsdebug.c 8.3 KB

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