Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | 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
/*
7
 *  a dictionary of domain names for packing messages
8
 */
9
enum
10
{
11
	Ndict=	64,
12
};
13
typedef struct Dict	Dict;
14
struct Dict
15
{
16
	struct {
17
		ushort	offset;		/* pointer to packed name in message */
18
		char	*name;		/* pointer to unpacked name in buf */
19
	} x[Ndict];
20
	int	n;		/* size of dictionary */
21
	uchar	*start;		/* start of packed message */
22
	char	buf[16*1024];	/* buffer for unpacked names (was 4k) */
23
	char	*ep;		/* first free char in buf */
24
};
25
 
26
#define NAME(x)		p = pname(p, ep, x, dp)
27
#define SYMBOL(x)	p = psym(p, ep, x)
28
#define STRING(x)	p = pstr(p, ep, x)
29
#define BYTES(x, n)	p = pbytes(p, ep, x, n)
30
#define USHORT(x)	p = pushort(p, ep, x)
31
#define UCHAR(x)	p = puchar(p, ep, x)
32
#define ULONG(x)	p = pulong(p, ep, x)
33
#define V4ADDR(x)	p = pv4addr(p, ep, x)
34
#define V6ADDR(x)	p = pv6addr(p, ep, x)
35
 
36
static uchar*
37
psym(uchar *p, uchar *ep, char *np)
38
{
39
	int n;
40
 
41
	n = strlen(np);
42
	if(n >= Strlen)			/* DNS maximum length string */
43
		n = Strlen - 1;
44
	if(ep - p < n+1)		/* see if it fits in the buffer */
45
		return ep+1;
46
	*p++ = n;
47
	memmove(p, np, n);
48
	return p + n;
49
}
50
 
51
static uchar*
52
pstr(uchar *p, uchar *ep, char *np)
53
{
54
	return psym(p, ep, np);
55
}
56
 
57
static uchar*
58
pbytes(uchar *p, uchar *ep, uchar *np, int n)
59
{
60
	if(ep - p < n)
61
		return ep+1;
62
	memmove(p, np, n);
63
	return p + n;
64
}
65
 
66
static uchar*
67
puchar(uchar *p, uchar *ep, int val)
68
{
69
	if(ep - p < 1)
70
		return ep+1;
71
	*p++ = val;
72
	return p;
73
}
74
 
75
static uchar*
76
pushort(uchar *p, uchar *ep, int val)
77
{
78
	if(ep - p < 2)
79
		return ep+1;
80
	*p++ = val>>8;
81
	*p++ = val;
82
	return p;
83
}
84
 
85
static uchar*
86
pulong(uchar *p, uchar *ep, int val)
87
{
88
	if(ep - p < 4)
89
		return ep+1;
90
	*p++ = val>>24;
91
	*p++ = val>>16;
92
	*p++ = val>>8;
93
	*p++ = val;
94
	return p;
95
}
96
 
97
static uchar*
98
pv4addr(uchar *p, uchar *ep, char *name)
99
{
100
	uchar ip[IPaddrlen];
101
 
102
	if(ep - p < 4)
103
		return ep+1;
104
	parseip(ip, name);
105
	v6tov4(p, ip);
106
	return p + 4;
107
}
108
 
109
static uchar*
110
pv6addr(uchar *p, uchar *ep, char *name)
111
{
112
	if(ep - p < IPaddrlen)
113
		return ep+1;
114
	parseip(p, name);
115
	return p + IPaddrlen;
116
}
117
 
118
static uchar*
119
pname(uchar *p, uchar *ep, char *np, Dict *dp)
120
{
121
	int i;
122
	char *cp;
123
	char *last;		/* last component packed */
124
 
125
	if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */
126
		return ep+1;
127
 
128
	last = 0;
129
	while(*np){
130
		/* look through every component in the dictionary for a match */
131
		for(i = 0; i < dp->n; i++)
132
			if(strcmp(np, dp->x[i].name) == 0){
133
				if(ep - p < 2)
134
					return ep+1;
135
				if ((dp->x[i].offset>>8) & 0xc0)
136
					dnslog("convDNS2M: offset too big for "
137
						"DNS packet format");
138
				*p++ = dp->x[i].offset>>8 | 0xc0;
139
				*p++ = dp->x[i].offset;
140
				return p;
141
			}
142
 
143
		/* if there's room, enter this name in dictionary */
144
		if(dp->n < Ndict)
145
			if(last){
146
				/* the whole name is already in dp->buf */
147
				last = strchr(last, '.') + 1;
148
				dp->x[dp->n].name = last;
149
				dp->x[dp->n].offset = p - dp->start;
150
				dp->n++;
151
			} else {
152
				/* add to dp->buf */
153
				i = strlen(np);
154
				if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){
155
					strcpy(dp->ep, np);
156
					dp->x[dp->n].name = dp->ep;
157
					last = dp->ep;
158
					dp->x[dp->n].offset = p - dp->start;
159
					dp->ep += i + 1;
160
					dp->n++;
161
				}
162
			}
163
 
164
		/* put next component into message */
165
		cp = strchr(np, '.');
166
		if(cp == nil){
167
			i = strlen(np);
168
			cp = np + i;	/* point to null terminator */
169
		} else {
170
			i = cp - np;
171
			cp++;		/* point past '.' */
172
		}
173
		if(ep-p < i+1)
174
			return ep+1;
175
		if (i > Labellen)
176
			return ep+1;
177
		*p++ = i;		/* count of chars in label */
178
		memmove(p, np, i);
179
		np = cp;
180
		p += i;
181
	}
182
 
183
	if(p >= ep)
184
		return ep+1;
185
	*p++ = 0;	/* add top level domain */
186
 
187
	return p;
188
}
189
 
190
static uchar*
191
convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
192
{
193
	uchar *lp, *data;
194
	int len, ttl;
195
	Txt *t;
196
 
197
	NAME(rp->owner->name);
198
	USHORT(rp->type);
199
	USHORT(rp->owner->class);
200
 
201
	/* egregious overuse of ttl (it's absolute time in the cache) */
202
	if(rp->db)
203
		ttl = rp->ttl;
204
	else
205
		ttl = rp->ttl - now;
206
	if(ttl < 0)
207
		ttl = 0;
208
	ULONG(ttl);
209
 
210
	lp = p;			/* leave room for the rdata length */
211
	p += 2;
212
	data = p;
213
 
214
	if(data >= ep)
215
		return p+1;
216
 
217
	switch(rp->type){
218
	case Thinfo:
219
		SYMBOL(rp->cpu->name);
220
		SYMBOL(rp->os->name);
221
		break;
222
	case Tcname:
223
	case Tmb:
224
	case Tmd:
225
	case Tmf:
226
	case Tns:
227
		NAME(rp->host->name);
228
		break;
229
	case Tmg:
230
	case Tmr:
231
		NAME(rp->mb->name);
232
		break;
233
	case Tminfo:
234
		NAME(rp->rmb->name);
235
		NAME(rp->mb->name);
236
		break;
237
	case Tmx:
238
		USHORT(rp->pref);
239
		NAME(rp->host->name);
240
		break;
241
	case Ta:
242
		V4ADDR(rp->ip->name);
243
		break;
244
	case Taaaa:
245
		V6ADDR(rp->ip->name);
246
		break;
247
	case Tptr:
248
		NAME(rp->ptr->name);
249
		break;
250
	case Tsoa:
251
		NAME(rp->host->name);
252
		NAME(rp->rmb->name);
253
		ULONG(rp->soa->serial);
254
		ULONG(rp->soa->refresh);
255
		ULONG(rp->soa->retry);
256
		ULONG(rp->soa->expire);
257
		ULONG(rp->soa->minttl);
258
		break;
259
	case Tsrv:
260
		USHORT(rp->srv->pri);
261
		USHORT(rp->srv->weight);
262
		USHORT(rp->port);
263
		STRING(rp->host->name);	/* rfc2782 sez no name compression */
264
		break;
265
	case Ttxt:
266
		for(t = rp->txt; t != nil; t = t->next)
267
			STRING(t->p);
268
		break;
269
	case Tnull:
270
		BYTES(rp->null->data, rp->null->dlen);
271
		break;
272
	case Trp:
273
		NAME(rp->rmb->name);
274
		NAME(rp->rp->name);
275
		break;
276
	case Tkey:
277
		USHORT(rp->key->flags);
278
		UCHAR(rp->key->proto);
279
		UCHAR(rp->key->alg);
280
		BYTES(rp->key->data, rp->key->dlen);
281
		break;
282
	case Tsig:
283
		USHORT(rp->sig->type);
284
		UCHAR(rp->sig->alg);
285
		UCHAR(rp->sig->labels);
286
		ULONG(rp->sig->ttl);
287
		ULONG(rp->sig->exp);
288
		ULONG(rp->sig->incep);
289
		USHORT(rp->sig->tag);
290
		NAME(rp->sig->signer->name);
291
		BYTES(rp->sig->data, rp->sig->dlen);
292
		break;
293
	case Tcert:
294
		USHORT(rp->cert->type);
295
		USHORT(rp->cert->tag);
296
		UCHAR(rp->cert->alg);
297
		BYTES(rp->cert->data, rp->cert->dlen);
298
		break;
299
	}
300
 
301
	/* stuff in the rdata section length */
302
	len = p - data;
303
	*lp++ = len >> 8;
304
	*lp = len;
305
 
306
	return p;
307
}
308
 
309
static uchar*
310
convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
311
{
312
	NAME(rp->owner->name);
313
	USHORT(rp->type);
314
	USHORT(rp->owner->class);
315
	return p;
316
}
317
 
318
static uchar*
319
rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest)
320
{
321
	uchar *np;
322
 
323
	*countp = 0;
324
	for(; rp && p < ep; rp = rp->next){
325
		if(quest)
326
			np = convQ2M(rp, p, ep, dp);
327
		else
328
			np = convRR2M(rp, p, ep, dp);
329
		if(np > ep)
330
			break;
331
		p = np;
332
		(*countp)++;
333
	}
334
	return p;
335
}
336
 
337
/*
338
 *  convert into a message
339
 */
340
int
341
convDNS2M(DNSmsg *m, uchar *buf, int len)
342
{
343
	ulong trunc = 0;
344
	uchar *p, *ep, *np;
345
	Dict d;
346
 
347
	d.n = 0;
348
	d.start = buf;
349
	d.ep = d.buf;
350
	memset(buf, 0, len);
351
	m->qdcount = m->ancount = m->nscount = m->arcount = 0;
352
 
353
	/* first pack in the RR's so we can get real counts */
354
	p = buf + 12;
355
	ep = buf + len;
356
	p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1);
357
	p = rrloop(m->an, &m->ancount, p, ep, &d, 0);
358
	p = rrloop(m->ns, &m->nscount, p, ep, &d, 0);
359
	p = rrloop(m->ar, &m->arcount, p, ep, &d, 0);
360
	if(p > ep) {
361
		trunc = Ftrunc;
362
		dnslog("udp packet full; truncating my reply");
363
		p = ep;
364
	}
365
 
366
	/* now pack the rest */
367
	np = p;
368
	p = buf;
369
	ep = buf + len;
370
	USHORT(m->id);
371
	USHORT(m->flags | trunc);
372
	USHORT(m->qdcount);
373
	USHORT(m->ancount);
374
	USHORT(m->nscount);
375
	USHORT(m->arcount);
376
	USED(p);
377
	return np - buf;
378
}