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