Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	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
					lock(&dnlock);
113
					rp = repp->ns;
114
					repp->ns = nil;
115
					rrfreelist(rp);
116
					unlock(&dnlock);
117
				}
118
				break;
119
			}
120
 
121
			if (strncmp(nsdp->name, "local#", 6) == 0)
122
				dnslog("returning %s as nameserver", nsdp->name);
123
			repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
124
			if(repp->ns)
125
				break;
126
		}
127
 
128
	/*
129
	 *  add ip addresses as hints
130
	 */
131
	if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
132
		for(tp = repp->ns; tp; tp = tp->next)
133
			hint(&repp->ar, tp);
134
		for(tp = repp->an; tp; tp = tp->next)
135
			hint(&repp->ar, tp);
136
	}
137
 
138
	/* hint calls rrlookup which holds dnlock, so don't lock before this. */
139
 
140
	/*
141
	 *  add an soa to the authority section to help client
142
	 *  with negative caching
143
	 */
144
	if(repp->an == nil)
145
		if(myarea != nil){
146
			lock(&dnlock);
147
			rrcopy(myarea->soarr, &tp);
148
			rrcat(&repp->ns, tp);
149
			unlock(&dnlock);
150
		} else if(neg != nil) {
151
			if(neg->negsoaowner != nil) {
152
				tp = rrlookup(neg->negsoaowner, Tsoa, NOneg);
153
				lock(&dnlock);
154
				rrcat(&repp->ns, tp);
155
				unlock(&dnlock);
156
			}
157
			repp->flags |= neg->negrcode;
158
		}
159
 
160
	/*
161
	 *  get rid of duplicates
162
	 */
163
	lock(&dnlock);
164
	unique(repp->an);
165
	unique(repp->ns);
166
	unique(repp->ar);
167
 
168
	rrfreelist(neg);
169
	unlock(&dnlock);
170
 
171
	dncheck(nil, 1);
172
}
173
 
174
/*
175
 *  satisfy a recursive request.  dnlookup will handle cnames.
176
 */
177
static RR*
178
doextquery(DNSmsg *mp, Request *req, int recurse)
179
{
180
	ushort type;
181
	char *name;
182
	RR *rp, *neg;
183
 
184
	name = mp->qd->owner->name;
185
	type = mp->qd->type;
186
	rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
187
 
188
	lock(&dnlock);
189
	/* don't return soa hints as answers, it's wrong */
190
	if(rp && rp->db && !rp->auth && rp->type == Tsoa) {
191
		rrfreelist(rp);
192
		rp = nil;
193
	}
194
 
195
	/* don't let negative cached entries escape */
196
	neg = rrremneg(&rp);
197
	rrcat(&mp->an, rp);
198
	unlock(&dnlock);
199
	return neg;
200
}
201
 
202
static void
203
hint(RR **last, RR *rp)
204
{
205
	RR *hp;
206
 
207
	switch(rp->type){
208
	case Tns:
209
	case Tmx:
210
	case Tmb:
211
	case Tmf:
212
	case Tmd:
213
		assert(rp->host != nil);
214
		hp = rrlookup(rp->host, Ta, NOneg);
215
		if(hp == nil)
216
			hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
217
		if(hp == nil)
218
			hp = rrlookup(rp->host, Taaaa, NOneg);
219
		if(hp == nil)
220
			hp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
221
		if (hp && hp->owner && hp->owner->name &&
222
		    strncmp(hp->owner->name, "local#", 6) == 0)
223
			dnslog("returning %s as hint", hp->owner->name);
224
		lock(&dnlock);
225
		rrcat(last, hp);
226
		unlock(&dnlock);
227
		break;
228
	}
229
}