dns.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <bio.h>
  6. #include <ctype.h>
  7. #include <ip.h>
  8. #include <pool.h>
  9. #include "dns.h"
  10. enum
  11. {
  12. Maxrequest= 1024,
  13. Ncache= 8,
  14. Maxpath= 128,
  15. Maxreply= 512,
  16. Maxrrr= 16,
  17. Maxfdata= 8192,
  18. Qdir= 0,
  19. Qdns= 1,
  20. };
  21. typedef struct Mfile Mfile;
  22. typedef struct Job Job;
  23. typedef struct Network Network;
  24. int vers; /* incremented each clone/attach */
  25. struct Mfile
  26. {
  27. Mfile *next; /* next free mfile */
  28. int ref;
  29. char *user;
  30. Qid qid;
  31. int fid;
  32. int type; /* reply type */
  33. char reply[Maxreply];
  34. ushort rr[Maxrrr]; /* offset of rr's */
  35. ushort nrr; /* number of rr's */
  36. };
  37. //
  38. // active local requests
  39. //
  40. struct Job
  41. {
  42. Job *next;
  43. int flushed;
  44. Fcall request;
  45. Fcall reply;
  46. };
  47. Lock joblock;
  48. Job *joblist;
  49. struct {
  50. Lock;
  51. Mfile *inuse; /* active mfile's */
  52. } mfalloc;
  53. int mfd[2];
  54. int debug;
  55. int cachedb;
  56. ulong now;
  57. int testing;
  58. char *trace;
  59. int needrefresh;
  60. int resolver;
  61. uchar ipaddr[IPaddrlen]; /* my ip address */
  62. int maxage;
  63. void rversion(Job*);
  64. void rauth(Job*);
  65. void rflush(Job*);
  66. void rattach(Job*, Mfile*);
  67. char* rwalk(Job*, Mfile*);
  68. void ropen(Job*, Mfile*);
  69. void rcreate(Job*, Mfile*);
  70. void rread(Job*, Mfile*);
  71. void rwrite(Job*, Mfile*, Request*);
  72. void rclunk(Job*, Mfile*);
  73. void rremove(Job*, Mfile*);
  74. void rstat(Job*, Mfile*);
  75. void rwstat(Job*, Mfile*);
  76. void sendmsg(Job*, char*);
  77. void mountinit(char*, char*);
  78. void io(void);
  79. int fillreply(Mfile*, int);
  80. Job* newjob(void);
  81. void freejob(Job*);
  82. void setext(char*, int, char*);
  83. char *logfile = "dns";
  84. char *dbfile;
  85. char mntpt[Maxpath];
  86. char *LOG;
  87. void
  88. usage(void)
  89. {
  90. fprint(2, "usage: %s [-rs] [-f ndb-file] [-x netmtpt]\n", argv0);
  91. exits("usage");
  92. }
  93. void
  94. main(int argc, char *argv[])
  95. {
  96. int serve;
  97. char servefile[Maxpath];
  98. char ext[Maxpath];
  99. char *p;
  100. serve = 0;
  101. setnetmtpt(mntpt, sizeof(mntpt), nil);
  102. ext[0] = 0;
  103. ARGBEGIN{
  104. case 'd':
  105. debug = 1;
  106. break;
  107. case 'f':
  108. p = ARGF();
  109. if(p == nil)
  110. usage();
  111. dbfile = p;
  112. break;
  113. case 'x':
  114. p = ARGF();
  115. if(p == nil)
  116. usage();
  117. setnetmtpt(mntpt, sizeof(mntpt), p);
  118. setext(ext, sizeof(ext), mntpt);
  119. break;
  120. case 'r':
  121. resolver = 1;
  122. break;
  123. case 's':
  124. serve = 1; /* serve network */
  125. cachedb = 1;
  126. break;
  127. case 'a':
  128. p = ARGF();
  129. if(p == nil)
  130. usage();
  131. maxage = atoi(p);
  132. break;
  133. case 't':
  134. testing = 1;
  135. break;
  136. }ARGEND
  137. USED(argc);
  138. USED(argv);
  139. if(testing) mainmem->flags |= POOL_NOREUSE;
  140. rfork(RFREND|RFNOTEG);
  141. /* start syslog before we fork */
  142. fmtinstall('F', fcallfmt);
  143. dninit();
  144. if(myipaddr(ipaddr, mntpt) < 0)
  145. sysfatal("can't read my ip address");
  146. syslog(0, logfile, "starting dns on %I", ipaddr);
  147. opendatabase();
  148. snprint(servefile, sizeof(servefile), "#s/dns%s", ext);
  149. unmount(servefile, mntpt);
  150. remove(servefile);
  151. mountinit(servefile, mntpt);
  152. now = time(0);
  153. srand(now*getpid());
  154. db2cache(1);
  155. if(serve)
  156. dnudpserver(mntpt);
  157. io();
  158. syslog(0, logfile, "io returned, exiting");
  159. exits(0);
  160. }
  161. /*
  162. * if a mount point is specified, set the cs extention to be the mount point
  163. * with '_'s replacing '/'s
  164. */
  165. void
  166. setext(char *ext, int n, char *p)
  167. {
  168. int i, c;
  169. n--;
  170. for(i = 0; i < n; i++){
  171. c = p[i];
  172. if(c == 0)
  173. break;
  174. if(c == '/')
  175. c = '_';
  176. ext[i] = c;
  177. }
  178. ext[i] = 0;
  179. }
  180. void
  181. mountinit(char *service, char *mntpt)
  182. {
  183. int f;
  184. int p[2];
  185. char buf[32];
  186. if(pipe(p) < 0)
  187. abort(); /* "pipe failed" */;
  188. switch(rfork(RFFDG|RFPROC|RFNAMEG)){
  189. case 0:
  190. close(p[1]);
  191. break;
  192. case -1:
  193. abort(); /* "fork failed\n" */;
  194. default:
  195. close(p[0]);
  196. /*
  197. * make a /srv/dns
  198. */
  199. f = create(service, 1, 0666);
  200. if(f < 0)
  201. abort(); /* service */;
  202. snprint(buf, sizeof(buf), "%d", p[1]);
  203. if(write(f, buf, strlen(buf)) != strlen(buf))
  204. abort(); /* "write %s", service */;
  205. close(f);
  206. /*
  207. * put ourselves into the file system
  208. */
  209. if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
  210. fprint(2, "dns mount failed: %r\n");
  211. _exits(0);
  212. }
  213. mfd[0] = mfd[1] = p[0];
  214. }
  215. Mfile*
  216. newfid(int fid, int needunused)
  217. {
  218. Mfile *mf;
  219. lock(&mfalloc);
  220. for(mf = mfalloc.inuse; mf != nil; mf = mf->next){
  221. if(mf->fid == fid){
  222. unlock(&mfalloc);
  223. if(needunused)
  224. return nil;
  225. return mf;
  226. }
  227. }
  228. mf = emalloc(sizeof(*mf));
  229. if(mf == nil)
  230. sysfatal("out of memory");
  231. mf->fid = fid;
  232. mf->next = mfalloc.inuse;
  233. mfalloc.inuse = mf;
  234. unlock(&mfalloc);
  235. return mf;
  236. }
  237. void
  238. freefid(Mfile *mf)
  239. {
  240. Mfile **l;
  241. lock(&mfalloc);
  242. for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next){
  243. if(*l == mf){
  244. *l = mf->next;
  245. if(mf->user)
  246. free(mf->user);
  247. free(mf);
  248. unlock(&mfalloc);
  249. return;
  250. }
  251. }
  252. sysfatal("freeing unused fid");
  253. }
  254. Mfile*
  255. copyfid(Mfile *mf, int fid)
  256. {
  257. Mfile *nmf;
  258. nmf = newfid(fid, 1);
  259. if(nmf == nil)
  260. return nil;
  261. nmf->fid = fid;
  262. nmf->user = estrdup(mf->user);
  263. nmf->qid.type = mf->qid.type;
  264. nmf->qid.path = mf->qid.path;
  265. nmf->qid.vers = vers++;
  266. return nmf;
  267. }
  268. Job*
  269. newjob(void)
  270. {
  271. Job *job;
  272. job = emalloc(sizeof(*job));
  273. lock(&joblock);
  274. job->next = joblist;
  275. joblist = job;
  276. job->request.tag = -1;
  277. unlock(&joblock);
  278. return job;
  279. }
  280. void
  281. freejob(Job *job)
  282. {
  283. Job **l;
  284. lock(&joblock);
  285. for(l = &joblist; *l; l = &(*l)->next){
  286. if((*l) == job){
  287. *l = job->next;
  288. free(job);
  289. break;
  290. }
  291. }
  292. unlock(&joblock);
  293. }
  294. void
  295. flushjob(int tag)
  296. {
  297. Job *job;
  298. lock(&joblock);
  299. for(job = joblist; job; job = job->next){
  300. if(job->request.tag == tag && job->request.type != Tflush){
  301. job->flushed = 1;
  302. break;
  303. }
  304. }
  305. unlock(&joblock);
  306. }
  307. void
  308. io(void)
  309. {
  310. long n;
  311. Mfile *mf;
  312. uchar mdata[IOHDRSZ + Maxfdata];
  313. Request req;
  314. Job *job;
  315. /*
  316. * a slave process is sometimes forked to wait for replies from other
  317. * servers. The master process returns immediately via a longjmp
  318. * through 'mret'.
  319. */
  320. if(setjmp(req.mret))
  321. putactivity();
  322. req.isslave = 0;
  323. for(;;){
  324. n = read9pmsg(mfd[0], mdata, sizeof mdata);
  325. if(n<=0){
  326. syslog(0, logfile, "error reading mntpt: %r");
  327. exits(0);
  328. }
  329. job = newjob();
  330. if(convM2S(mdata, n, &job->request) != n){
  331. freejob(job);
  332. continue;
  333. }
  334. mf = newfid(job->request.fid, 0);
  335. if(debug)
  336. syslog(0, logfile, "%F", &job->request);
  337. getactivity(&req);
  338. req.aborttime = now + 60; /* don't spend more than 60 seconds */
  339. switch(job->request.type){
  340. default:
  341. syslog(1, logfile, "unknown request type %d", job->request.type);
  342. break;
  343. case Tversion:
  344. rversion(job);
  345. break;
  346. case Tauth:
  347. rauth(job);
  348. break;
  349. case Tflush:
  350. rflush(job);
  351. break;
  352. case Tattach:
  353. rattach(job, mf);
  354. break;
  355. case Twalk:
  356. rwalk(job, mf);
  357. break;
  358. case Topen:
  359. ropen(job, mf);
  360. break;
  361. case Tcreate:
  362. rcreate(job, mf);
  363. break;
  364. case Tread:
  365. rread(job, mf);
  366. break;
  367. case Twrite:
  368. rwrite(job, mf, &req);
  369. break;
  370. case Tclunk:
  371. rclunk(job, mf);
  372. break;
  373. case Tremove:
  374. rremove(job, mf);
  375. break;
  376. case Tstat:
  377. rstat(job, mf);
  378. break;
  379. case Twstat:
  380. rwstat(job, mf);
  381. break;
  382. }
  383. freejob(job);
  384. /*
  385. * slave processes die after replying
  386. */
  387. if(req.isslave){
  388. putactivity();
  389. _exits(0);
  390. }
  391. putactivity();
  392. }
  393. }
  394. void
  395. rversion(Job *job)
  396. {
  397. if(job->request.msize > IOHDRSZ + Maxfdata)
  398. job->reply.msize = IOHDRSZ + Maxfdata;
  399. else
  400. job->reply.msize = job->request.msize;
  401. if(strncmp(job->request.version, "9P2000", 6) != 0)
  402. sendmsg(job, "unknown 9P version");
  403. else{
  404. job->reply.version = "9P2000";
  405. sendmsg(job, 0);
  406. }
  407. }
  408. void
  409. rauth(Job *job)
  410. {
  411. sendmsg(job, "dns: authentication not required");
  412. }
  413. /*
  414. * don't flush till all the slaves are done
  415. */
  416. void
  417. rflush(Job *job)
  418. {
  419. flushjob(job->request.oldtag);
  420. sendmsg(job, 0);
  421. }
  422. void
  423. rattach(Job *job, Mfile *mf)
  424. {
  425. if(mf->user != nil)
  426. free(mf->user);
  427. mf->user = estrdup(job->request.uname);
  428. mf->qid.vers = vers++;
  429. mf->qid.type = QTDIR;
  430. mf->qid.path = 0LL;
  431. job->reply.qid = mf->qid;
  432. sendmsg(job, 0);
  433. }
  434. char*
  435. rwalk(Job *job, Mfile *mf)
  436. {
  437. char *err;
  438. char **elems;
  439. int nelems;
  440. int i;
  441. Mfile *nmf;
  442. Qid qid;
  443. err = 0;
  444. nmf = nil;
  445. elems = job->request.wname;
  446. nelems = job->request.nwname;
  447. job->reply.nwqid = 0;
  448. if(job->request.newfid != job->request.fid){
  449. /* clone fid */
  450. if(job->request.newfid<0){
  451. err = "clone newfid out of range";
  452. goto send;
  453. }
  454. nmf = copyfid(mf, job->request.newfid);
  455. if(nmf == nil){
  456. err = "clone bad newfid";
  457. goto send;
  458. }
  459. mf = nmf;
  460. }
  461. /* else nmf will be nil */
  462. qid = mf->qid;
  463. if(nelems > 0){
  464. /* walk fid */
  465. for(i=0; i<nelems && i<MAXWELEM; i++){
  466. if((qid.type & QTDIR) == 0){
  467. err = "not a directory";
  468. break;
  469. }
  470. if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
  471. qid.type = QTDIR;
  472. qid.path = Qdir;
  473. Found:
  474. job->reply.wqid[i] = qid;
  475. job->reply.nwqid++;
  476. continue;
  477. }
  478. if(strcmp(elems[i], "dns") == 0){
  479. qid.type = QTFILE;
  480. qid.path = Qdns;
  481. goto Found;
  482. }
  483. err = "file does not exist";
  484. break;
  485. }
  486. }
  487. send:
  488. if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
  489. freefid(nmf);
  490. if(err == nil)
  491. mf->qid = qid;
  492. sendmsg(job, err);
  493. return err;
  494. }
  495. void
  496. ropen(Job *job, Mfile *mf)
  497. {
  498. int mode;
  499. char *err;
  500. err = 0;
  501. mode = job->request.mode;
  502. if(mf->qid.type & QTDIR){
  503. if(mode)
  504. err = "permission denied";
  505. }
  506. job->reply.qid = mf->qid;
  507. job->reply.iounit = 0;
  508. sendmsg(job, err);
  509. }
  510. void
  511. rcreate(Job *job, Mfile *mf)
  512. {
  513. USED(mf);
  514. sendmsg(job, "creation permission denied");
  515. }
  516. void
  517. rread(Job *job, Mfile *mf)
  518. {
  519. int i, n, cnt;
  520. long off;
  521. Dir dir;
  522. uchar buf[Maxfdata];
  523. char *err;
  524. long clock;
  525. n = 0;
  526. err = 0;
  527. off = job->request.offset;
  528. cnt = job->request.count;
  529. if(mf->qid.type & QTDIR){
  530. clock = time(0);
  531. if(off == 0){
  532. dir.name = "dns";
  533. dir.qid.type = QTFILE;
  534. dir.qid.vers = vers;
  535. dir.qid.path = Qdns;
  536. dir.mode = 0666;
  537. dir.length = 0;
  538. dir.uid = mf->user;
  539. dir.gid = mf->user;
  540. dir.muid = mf->user;
  541. dir.atime = clock; /* wrong */
  542. dir.mtime = clock; /* wrong */
  543. n = convD2M(&dir, buf, sizeof buf);
  544. }
  545. job->reply.data = (char*)buf;
  546. } else {
  547. for(i = 1; i <= mf->nrr; i++)
  548. if(mf->rr[i] > off)
  549. break;
  550. if(i > mf->nrr)
  551. goto send;
  552. if(off + cnt > mf->rr[i])
  553. n = mf->rr[i] - off;
  554. else
  555. n = cnt;
  556. job->reply.data = mf->reply + off;
  557. }
  558. send:
  559. job->reply.count = n;
  560. sendmsg(job, err);
  561. }
  562. void
  563. rwrite(Job *job, Mfile *mf, Request *req)
  564. {
  565. int cnt, rooted, status;
  566. long n;
  567. char *err, *p, *atype;
  568. RR *rp, *tp, *neg;
  569. int wantsav;
  570. err = 0;
  571. cnt = job->request.count;
  572. if(mf->qid.type & QTDIR){
  573. err = "can't write directory";
  574. goto send;
  575. }
  576. if(cnt >= Maxrequest){
  577. err = "request too long";
  578. goto send;
  579. }
  580. job->request.data[cnt] = 0;
  581. if(cnt > 0 && job->request.data[cnt-1] == '\n')
  582. job->request.data[cnt-1] = 0;
  583. /*
  584. * special commands
  585. */
  586. if(strncmp(job->request.data, "debug", 5)==0 && job->request.data[5] == 0){
  587. debug ^= 1;
  588. goto send;
  589. } else if(strncmp(job->request.data, "dump", 4)==0 && job->request.data[4] == 0){
  590. dndump("/lib/ndb/dnsdump");
  591. goto send;
  592. } else if(strncmp(job->request.data, "refresh", 7)==0 && job->request.data[7] == 0){
  593. needrefresh = 1;
  594. goto send;
  595. } else if(strncmp(job->request.data, "poolcheck", 9)==0 && job->request.data[9] == 0){
  596. poolcheck(mainmem);
  597. goto send;
  598. }
  599. /*
  600. * kill previous reply
  601. */
  602. mf->nrr = 0;
  603. mf->rr[0] = 0;
  604. /*
  605. * break up request (into a name and a type)
  606. */
  607. atype = strchr(job->request.data, ' ');
  608. if(atype == 0){
  609. err = "illegal request";
  610. goto send;
  611. } else
  612. *atype++ = 0;
  613. /*
  614. * tracing request
  615. */
  616. if(strcmp(atype, "trace") == 0){
  617. if(trace)
  618. free(trace);
  619. if(*job->request.data)
  620. trace = estrdup(job->request.data);
  621. else
  622. trace = 0;
  623. goto send;
  624. }
  625. mf->type = rrtype(atype);
  626. if(mf->type < 0){
  627. err = "unknown type";
  628. goto send;
  629. }
  630. p = atype - 2;
  631. if(p >= job->request.data && *p == '.'){
  632. rooted = 1;
  633. *p = 0;
  634. } else
  635. rooted = 0;
  636. p = job->request.data;
  637. if(*p == '!'){
  638. wantsav = 1;
  639. p++;
  640. } else
  641. wantsav = 0;
  642. dncheck(0, 1);
  643. rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
  644. dncheck(0, 1);
  645. neg = rrremneg(&rp);
  646. if(neg){
  647. status = neg->negrcode;
  648. rrfreelist(neg);
  649. }
  650. if(rp == 0){
  651. if(status == Rname)
  652. err = "name does not exist";
  653. else
  654. err = "no translation found";
  655. } else {
  656. /* format data to be read later */
  657. n = 0;
  658. mf->nrr = 0;
  659. for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
  660. tsame(mf->type, tp->type); tp = tp->next){
  661. mf->rr[mf->nrr++] = n;
  662. if(wantsav)
  663. n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
  664. else
  665. n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
  666. }
  667. mf->rr[mf->nrr] = n;
  668. rrfreelist(rp);
  669. }
  670. send:
  671. dncheck(0, 1);
  672. job->reply.count = cnt;
  673. sendmsg(job, err);
  674. }
  675. void
  676. rclunk(Job *job, Mfile *mf)
  677. {
  678. freefid(mf);
  679. sendmsg(job, 0);
  680. }
  681. void
  682. rremove(Job *job, Mfile *mf)
  683. {
  684. USED(mf);
  685. sendmsg(job, "remove permission denied");
  686. }
  687. void
  688. rstat(Job *job, Mfile *mf)
  689. {
  690. Dir dir;
  691. uchar buf[IOHDRSZ+Maxfdata];
  692. if(mf->qid.type & QTDIR){
  693. dir.name = ".";
  694. dir.mode = DMDIR|0555;
  695. } else {
  696. dir.name = "dns";
  697. dir.mode = 0666;
  698. }
  699. dir.qid = mf->qid;
  700. dir.length = 0;
  701. dir.uid = mf->user;
  702. dir.gid = mf->user;
  703. dir.muid = mf->user;
  704. dir.atime = dir.mtime = time(0);
  705. job->reply.nstat = convD2M(&dir, buf, sizeof buf);
  706. job->reply.stat = buf;
  707. sendmsg(job, 0);
  708. }
  709. void
  710. rwstat(Job *job, Mfile *mf)
  711. {
  712. USED(mf);
  713. sendmsg(job, "wstat permission denied");
  714. }
  715. void
  716. sendmsg(Job *job, char *err)
  717. {
  718. int n;
  719. uchar mdata[IOHDRSZ + Maxfdata];
  720. char ename[ERRMAX];
  721. if(err){
  722. job->reply.type = Rerror;
  723. snprint(ename, sizeof(ename), "dns: %s", err);
  724. job->reply.ename = ename;
  725. }else{
  726. job->reply.type = job->request.type+1;
  727. }
  728. job->reply.tag = job->request.tag;
  729. n = convS2M(&job->reply, mdata, sizeof mdata);
  730. if(n == 0){
  731. syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
  732. abort();
  733. }
  734. lock(&joblock);
  735. if(job->flushed == 0)
  736. if(write(mfd[1], mdata, n)!=n)
  737. sysfatal("mount write");
  738. unlock(&joblock);
  739. if(debug)
  740. syslog(0, logfile, "%F %d", &job->reply, n);
  741. }
  742. /*
  743. * the following varies between dnsdebug and dns
  744. */
  745. void
  746. logreply(int id, uchar *addr, DNSmsg *mp)
  747. {
  748. RR *rp;
  749. syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
  750. mp->flags & Fauth ? " auth" : "",
  751. mp->flags & Ftrunc ? " trunc" : "",
  752. mp->flags & Frecurse ? " rd" : "",
  753. mp->flags & Fcanrec ? " ra" : "",
  754. mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
  755. " nx" : "");
  756. for(rp = mp->qd; rp != nil; rp = rp->next)
  757. syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
  758. for(rp = mp->an; rp != nil; rp = rp->next)
  759. syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
  760. for(rp = mp->ns; rp != nil; rp = rp->next)
  761. syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
  762. for(rp = mp->ar; rp != nil; rp = rp->next)
  763. syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
  764. }
  765. void
  766. logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
  767. {
  768. char buf[12];
  769. syslog(0, LOG, "%d.%d: sending to %I/%s %s %s",
  770. id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
  771. }
  772. RR*
  773. getdnsservers(int class)
  774. {
  775. return dnsservers(class);
  776. }