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