]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dnserver.c
ip/ipconfig: default onlink and autoflag to 1
[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         }
71         if(myarea == nil && norecursion) {
72                 /* we don't recurse and we're not authoritative */
73                 repp->flags = Rok | Fresp | Oquery;
74                 neg = nil;
75         } else {
76                 /*
77                  *  get the answer if we can, in *repp
78                  */
79                 if(reqp->flags & Frecurse)
80                         neg = doextquery(repp, req, Recurse);
81                 else
82                         neg = doextquery(repp, req, Dontrecurse);
83
84                 /* authority is transitive */
85                 if(myarea != nil || (repp->an && repp->an->auth))
86                         repp->flags |= Fauth;
87
88                 /* pass on error codes */
89                 if(repp->an == nil){
90                         dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
91                         if(dp->rr == nil)
92                                 if(reqp->flags & Frecurse)
93                                         repp->flags |= dp->respcode | Fauth;
94                 }
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         /*
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         /*
136          *  add an soa to the authority section to help client
137          *  with negative caching
138          */
139         if(repp->an == nil){
140                 if(myarea != nil){
141                         rrcopy(myarea->soarr, &tp);
142                         rrcat(&repp->ns, tp);
143                 } else if(neg != nil) {
144                         if(neg->negsoaowner != nil) {
145                                 tp = rrlookup(neg->negsoaowner, Tsoa, NOneg);
146                                 rrcat(&repp->ns, tp);
147                         }
148                         repp->flags |= neg->negrcode;
149                 }
150         }
151
152         /*
153          *  get rid of duplicates
154          */
155         unique(repp->an);
156         unique(repp->ns);
157         unique(repp->ar);
158
159         rrfreelist(neg);
160 }
161
162 /*
163  *  satisfy a recursive request.  dnlookup will handle cnames.
164  */
165 static RR*
166 doextquery(DNSmsg *mp, Request *req, int recurse)
167 {
168         ushort type;
169         char *name;
170         RR *rp, *neg;
171
172         name = mp->qd->owner->name;
173         type = mp->qd->type;
174         rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
175
176         /* don't return soa hints as answers, it's wrong */
177         if(rp && rp->db && !rp->auth && rp->type == Tsoa) {
178                 rrfreelist(rp);
179                 rp = nil;
180         }
181
182         /* don't let negative cached entries escape */
183         neg = rrremneg(&rp);
184         rrcat(&mp->an, rp);
185
186         return neg;
187 }
188
189 static void
190 hint(RR **last, RR *rp)
191 {
192         RR *hp;
193
194         switch(rp->type){
195         case Tns:
196         case Tmx:
197         case Tmb:
198         case Tmf:
199         case Tmd:
200                 hp = rrlookup(rp->host, Ta, NOneg);
201                 if(hp == nil)
202                         hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
203                 if(hp == nil)
204                         hp = rrlookup(rp->host, Taaaa, NOneg);
205                 if(hp == nil)
206                         hp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
207                 if (hp && strncmp(hp->owner->name, "local#", 6) == 0)
208                         dnslog("returning %s as hint", hp->owner->name);
209                 rrcat(last, hp);
210                 break;
211         }
212 }