dnserver.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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, uchar *srcip, int rcode)
  15. {
  16. int recursionflag;
  17. char *cp, *errmsg;
  18. char tname[32];
  19. DN *nsdp, *dp;
  20. Area *myarea;
  21. RR *tp, *neg;
  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 (rcode) {
  33. errmsg = "";
  34. if (rcode >= 0 && rcode < nrname)
  35. errmsg = rname[rcode];
  36. syslog(0, logfile, "server: response code 0%o (%s), req from %I",
  37. rcode, errmsg, srcip);
  38. /* provide feedback to clients who send us trash */
  39. repp->flags = (rcode&Rmask) | Fresp | Fcanrec | Oquery;
  40. return;
  41. }
  42. if(!rrsupported(repp->qd->type)){
  43. syslog(0, logfile, "server: unsupported request %s from %I",
  44. rrname(repp->qd->type, tname, sizeof tname), srcip);
  45. repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
  46. return;
  47. }
  48. if(repp->qd->owner->class != Cin){
  49. syslog(0, logfile, "server: unsupported class %d from %I",
  50. repp->qd->owner->class, srcip);
  51. repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
  52. return;
  53. }
  54. myarea = inmyarea(repp->qd->owner->name);
  55. if(myarea != nil) {
  56. if(repp->qd->type == Tixfr || repp->qd->type == Taxfr){
  57. syslog(0, logfile,
  58. "server: unsupported xfr request %s from %I",
  59. rrname(repp->qd->type, tname, sizeof tname),
  60. srcip);
  61. repp->flags = Runimplimented | Fresp | recursionflag |
  62. Oquery;
  63. return;
  64. }
  65. } else
  66. if(norecursion) {
  67. /* we don't recurse and we're not authoritative */
  68. repp->flags = Rok | Fresp | Oquery;
  69. return;
  70. }
  71. /*
  72. * get the answer if we can
  73. */
  74. if(reqp->flags & Frecurse)
  75. neg = doextquery(repp, req, Recurse);
  76. else
  77. neg = doextquery(repp, req, Dontrecurse);
  78. /* authority is transitive */
  79. if(myarea != nil || (repp->an && repp->an->auth))
  80. repp->flags |= Fauth;
  81. /* pass on error codes */
  82. if(repp->an == 0){
  83. dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
  84. if(dp->rr == nil)
  85. if(reqp->flags & Frecurse)
  86. repp->flags |= dp->respcode | Fauth;
  87. }
  88. if(myarea == nil)
  89. /*
  90. * add name server if we know
  91. */
  92. for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
  93. nsdp = dnlookup(cp, repp->qd->owner->class, 0);
  94. if(nsdp == 0)
  95. continue;
  96. repp->ns = rrlookup(nsdp, Tns, OKneg);
  97. if(repp->ns){
  98. /* don't pass on anything we know is wrong */
  99. if(repp->ns->negative){
  100. rrfreelist(repp->ns);
  101. repp->ns = nil;
  102. }
  103. break;
  104. }
  105. repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
  106. if(repp->ns)
  107. break;
  108. }
  109. /*
  110. * add ip addresses as hints
  111. */
  112. if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
  113. for(tp = repp->ns; tp; tp = tp->next)
  114. hint(&repp->ar, tp);
  115. for(tp = repp->an; tp; tp = tp->next)
  116. hint(&repp->ar, tp);
  117. }
  118. /*
  119. * add an soa to the authority section to help client
  120. * with negative caching
  121. */
  122. if(repp->an == nil)
  123. if(myarea != nil){
  124. rrcopy(myarea->soarr, &tp);
  125. rrcat(&repp->ns, tp);
  126. } else if(neg != nil) {
  127. if(neg->negsoaowner != nil)
  128. rrcat(&repp->ns, rrlookup(neg->negsoaowner,
  129. Tsoa, NOneg));
  130. repp->flags |= neg->negrcode;
  131. }
  132. /*
  133. * get rid of duplicates
  134. */
  135. unique(repp->an);
  136. unique(repp->ns);
  137. unique(repp->ar);
  138. rrfreelist(neg);
  139. dncheck(nil, 1);
  140. }
  141. /*
  142. * satisfy a recursive request. dnlookup will handle cnames.
  143. */
  144. static RR*
  145. doextquery(DNSmsg *mp, Request *req, int recurse)
  146. {
  147. int type;
  148. char *name;
  149. RR *rp, *neg;
  150. name = mp->qd->owner->name;
  151. type = mp->qd->type;
  152. rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
  153. /* don't return soa hints as answers, it's wrong */
  154. if(rp && rp->db && !rp->auth && rp->type == Tsoa)
  155. rrfreelist(rp);
  156. /* don't let negative cached entries escape */
  157. neg = rrremneg(&rp);
  158. rrcat(&mp->an, rp);
  159. return neg;
  160. }
  161. static void
  162. hint(RR **last, RR *rp)
  163. {
  164. RR *hp;
  165. switch(rp->type){
  166. case Tns:
  167. case Tmx:
  168. case Tmb:
  169. case Tmf:
  170. case Tmd:
  171. hp = rrlookup(rp->host, Ta, NOneg);
  172. if(hp == nil)
  173. hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
  174. rrcat(last, hp);
  175. break;
  176. }
  177. }