dnserver.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include "dns.h"
  5. static RR* doextquery(DNSmsg*, Request*, int);
  6. static void hint(RR**, RR*);
  7. extern char *logfile;
  8. /* set in dns.c */
  9. int norecursion; /* don't allow recursive requests */
  10. /*
  11. * answer a dns request
  12. */
  13. void
  14. dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
  15. {
  16. RR *tp, *neg;
  17. char *cp;
  18. DN *nsdp, *dp;
  19. Area *myarea;
  20. char tname[32];
  21. int recursionflag;
  22. dncheck(nil, 1);
  23. recursionflag = norecursion?0:Fcanrec;
  24. memset(repp, 0, sizeof(*repp));
  25. repp->id = reqp->id;
  26. repp->flags = Fresp | recursionflag | Oquery;
  27. /* move one question from reqp to repp */
  28. tp = reqp->qd;
  29. reqp->qd = tp->next;
  30. tp->next = 0;
  31. repp->qd = tp;
  32. if(!rrsupported(repp->qd->type)){
  33. syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
  34. repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
  35. return;
  36. }
  37. if(repp->qd->owner->class != Cin){
  38. syslog(0, logfile, "server: class %d", repp->qd->owner->class);
  39. repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
  40. return;
  41. }
  42. myarea = inmyarea(repp->qd->owner->name);
  43. if(myarea != nil) {
  44. if(repp->qd->type == Tixfr || repp->qd->type == Taxfr){
  45. syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
  46. repp->flags = Runimplimented | Fresp | recursionflag | Oquery;
  47. return;
  48. }
  49. } else {
  50. if(norecursion) {
  51. /* we don't recurse and we're not authoritative */
  52. repp->flags = Rok | Fresp | Oquery;
  53. return;
  54. }
  55. }
  56. /*
  57. * get the answer if we can
  58. */
  59. if(reqp->flags & Frecurse)
  60. neg = doextquery(repp, req, Recurse);
  61. else
  62. neg = doextquery(repp, req, Dontrecurse);
  63. /* authority is transitive */
  64. if(myarea != nil || (repp->an && repp->an->auth))
  65. repp->flags |= Fauth;
  66. /* pass on error codes */
  67. if(repp->an == 0){
  68. dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
  69. if(dp->rr == 0)
  70. if(reqp->flags & Frecurse)
  71. repp->flags |= dp->nonexistent|Fauth;
  72. }
  73. if(myarea == nil){
  74. /*
  75. * add name server if we know
  76. */
  77. for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
  78. nsdp = dnlookup(cp, repp->qd->owner->class, 0);
  79. if(nsdp == 0)
  80. continue;
  81. repp->ns = rrlookup(nsdp, Tns, OKneg);
  82. if(repp->ns){
  83. /* don't pass on anything we know is wrong */
  84. if(repp->ns->negative){
  85. rrfreelist(repp->ns);
  86. repp->ns = nil;
  87. }
  88. break;
  89. }
  90. repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
  91. if(repp->ns)
  92. break;
  93. }
  94. }
  95. /*
  96. * add ip addresses as hints
  97. */
  98. if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
  99. for(tp = repp->ns; tp; tp = tp->next)
  100. hint(&repp->ar, tp);
  101. for(tp = repp->an; tp; tp = tp->next)
  102. hint(&repp->ar, tp);
  103. }
  104. /*
  105. * add an soa to the authority section to help client with negative caching
  106. */
  107. if(repp->an == nil){
  108. if(myarea != nil){
  109. rrcopy(myarea->soarr, &tp);
  110. rrcat(&repp->ns, tp);
  111. } else if(neg != nil) {
  112. if(neg->negsoaowner != nil)
  113. rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
  114. repp->flags |= neg->negrcode;
  115. }
  116. }
  117. /*
  118. * get rid of duplicates
  119. */
  120. unique(repp->an);
  121. unique(repp->ns);
  122. unique(repp->ar);
  123. rrfreelist(neg);
  124. dncheck(nil, 1);
  125. }
  126. /*
  127. * satisfy a recursive request. dnlookup will handle cnames.
  128. */
  129. static RR*
  130. doextquery(DNSmsg *mp, Request *req, int recurse)
  131. {
  132. int type;
  133. char *name;
  134. RR *rp, *neg;
  135. name = mp->qd->owner->name;
  136. type = mp->qd->type;
  137. rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
  138. /* don't return soa hints as answers, it's wrong */
  139. if(rp && rp->db && !rp->auth && rp->type == Tsoa)
  140. rrfreelist(rp);
  141. /* don't let negative cached entries escape */
  142. neg = rrremneg(&rp);
  143. rrcat(&mp->an, rp);
  144. return neg;
  145. }
  146. static void
  147. hint(RR **last, RR *rp)
  148. {
  149. RR *hp;
  150. switch(rp->type){
  151. case Tns:
  152. case Tmx:
  153. case Tmb:
  154. case Tmf:
  155. case Tmd:
  156. hp = rrlookup(rp->host, Ta, NOneg);
  157. if(hp == nil)
  158. hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
  159. rrcat(last, hp);
  160. break;
  161. }
  162. }