dnserver.c 3.6 KB

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