dnserver.c 5.0 KB

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