Blob


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