dnserver.c 5.4 KB

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