1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <ndb.h>
6 #include "dns.h"
7 
8 typedef struct Scan	Scan;
9 struct Scan
10 {
11 	uchar	*base;
12 	uchar	*p;
13 	uchar	*ep;
14 	char	*err;
15 };
16 
17 #define NAME(x)		gname(x, sp)
18 #define SYMBOL(x)	(x = gsym(sp))
19 #define STRING(x)	(x = gstr(sp))
20 #define USHORT(x)	(x = gshort(sp))
21 #define ULONG(x)	(x = glong(sp))
22 #define UCHAR(x)	(x = gchar(sp))
23 #define V4ADDR(x)	(x = gv4addr(sp))
24 #define V6ADDR(x)	(x = gv6addr(sp))
25 #define BYTES(x, y)	(y = gbytes(sp, &x, len - (sp->p - data)))
26 
27 static char *toolong = "too long";
28 
29 /*
30  *  get a ushort/ulong
31  */
32 static ushort
gchar(Scan * sp)33 gchar(Scan *sp)
34 {
35 	ushort x;
36 
37 	if(sp->err)
38 		return 0;
39 	if(sp->ep - sp->p < 1){
40 		sp->err = toolong;
41 		return 0;
42 	}
43 	x = sp->p[0];
44 	sp->p += 1;
45 	return x;
46 }
47 static ushort
gshort(Scan * sp)48 gshort(Scan *sp)
49 {
50 	ushort x;
51 
52 	if(sp->err)
53 		return 0;
54 	if(sp->ep - sp->p < 2){
55 		sp->err = toolong;
56 		return 0;
57 	}
58 	x = (sp->p[0]<<8) | sp->p[1];
59 	sp->p += 2;
60 	return x;
61 }
62 static ulong
glong(Scan * sp)63 glong(Scan *sp)
64 {
65 	ulong x;
66 
67 	if(sp->err)
68 		return 0;
69 	if(sp->ep - sp->p < 4){
70 		sp->err = toolong;
71 		return 0;
72 	}
73 	x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
74 	sp->p += 4;
75 	return x;
76 }
77 
78 /*
79  *  get an ip address
80  */
81 static DN*
gv4addr(Scan * sp)82 gv4addr(Scan *sp)
83 {
84 	char addr[32];
85 
86 	if(sp->err)
87 		return 0;
88 	if(sp->ep - sp->p < 4){
89 		sp->err = toolong;
90 		return 0;
91 	}
92 	snprint(addr, sizeof(addr), "%V", sp->p);
93 	sp->p += 4;
94 
95 	return dnlookup(addr, Cin, 1);
96 }
97 static DN*
gv6addr(Scan * sp)98 gv6addr(Scan *sp)
99 {
100 	char addr[64];
101 
102 	if(sp->err)
103 		return 0;
104 	if(sp->ep - sp->p < IPaddrlen){
105 		sp->err = toolong;
106 		return 0;
107 	}
108 	snprint(addr, sizeof(addr), "%I", sp->p);
109 	sp->p += IPaddrlen;
110 
111 	return dnlookup(addr, Cin, 1);
112 }
113 
114 /*
115  *  get a string.  make it an internal symbol.
116  */
117 static DN*
gsym(Scan * sp)118 gsym(Scan *sp)
119 {
120 	int n;
121 	char sym[Strlen+1];
122 
123 	if(sp->err)
124 		return 0;
125 	n = *(sp->p++);
126 	if(sp->p+n > sp->ep){
127 		sp->err = toolong;
128 		return 0;
129 	}
130 
131 	if(n > Strlen){
132 		sp->err = "illegal string";
133 		return 0;
134 	}
135 	strncpy(sym, (char*)sp->p, n);
136 	sym[n] = 0;
137 	sp->p += n;
138 
139 	return dnlookup(sym, Csym, 1);
140 }
141 
142 /*
143  *  get a string.  don't make it an internal symbol.
144  */
145 static Txt*
gstr(Scan * sp)146 gstr(Scan *sp)
147 {
148 	int n;
149 	char sym[Strlen+1];
150 	Txt *t;
151 
152 	if(sp->err)
153 		return 0;
154 	n = *(sp->p++);
155 	if(sp->p+n > sp->ep){
156 		sp->err = toolong;
157 		return 0;
158 	}
159 
160 	if(n > Strlen){
161 		sp->err = "illegal string";
162 		return 0;
163 	}
164 	strncpy(sym, (char*)sp->p, n);
165 	sym[n] = 0;
166 	sp->p += n;
167 
168 	t = emalloc(sizeof(*t));
169 	t->next = nil;
170 	t->p = estrdup(sym);
171 	return t;
172 }
173 
174 /*
175  *  get a sequence of bytes
176  */
177 static int
gbytes(Scan * sp,uchar ** p,int n)178 gbytes(Scan *sp, uchar **p, int n)
179 {
180 	if(sp->err)
181 		return 0;
182 	if(sp->p+n > sp->ep || n < 0){
183 		sp->err = toolong;
184 		return 0;
185 	}
186 	*p = emalloc(n);
187 	memmove(*p, sp->p, n);
188 	sp->p += n;
189 
190 	return n;
191 }
192 
193 /*
194  *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
195  */
196 static char*
gname(char * to,Scan * sp)197 gname(char *to, Scan *sp)
198 {
199 	int len, off;
200 	int pointer;
201 	int n;
202 	char *tostart;
203 	char *toend;
204 	uchar *p;
205 
206 	tostart = to;
207 	if(sp->err)
208 		goto err;
209 	pointer = 0;
210 	p = sp->p;
211 	toend = to + Domlen;
212 	for(len = 0; *p; len += pointer ? 0 : (n+1)){
213 		if((*p & 0xc0) == 0xc0){
214 			/* pointer to other spot in message */
215 			if(pointer++ > 10){
216 				sp->err = "pointer loop";
217 				goto err;
218 			}
219 			off = ((p[0]<<8) + p[1]) & 0x3ff;
220 			p = sp->base + off;
221 			if(p >= sp->ep){
222 				sp->err = "bad pointer";
223 				goto err;
224 			}
225 			n = 0;
226 			continue;
227 		}
228 		n = *p++;
229 		if(len + n < Domlen - 1){
230 			if(to + n > toend){
231 				sp->err = toolong;
232 				goto err;
233 			}
234 			memmove(to, p, n);
235 			to += n;
236 		}
237 		p += n;
238 		if(*p){
239 			if(to >= toend){
240 				sp->err = toolong;
241 				goto err;
242 			}
243 			*to++ = '.';
244 		}
245 	}
246 	*to = 0;
247 	if(pointer)
248 		sp->p += len + 2;	/* + 2 for pointer */
249 	else
250 		sp->p += len + 1;	/* + 1 for the null domain */
251 	return tostart;
252 err:
253 	*tostart = 0;
254 	return tostart;
255 }
256 
257 /*
258  *  convert the next RR from a message
259  */
260 static RR*
convM2RR(Scan * sp)261 convM2RR(Scan *sp)
262 {
263 	RR *rp;
264 	int type;
265 	int class;
266 	uchar *data;
267 	int len;
268 	char dname[Domlen+1];
269 	Txt *t, **l;
270 
271 retry:
272 	NAME(dname);
273 	USHORT(type);
274 	USHORT(class);
275 
276 	rp = rralloc(type);
277 	rp->owner = dnlookup(dname, class, 1);
278 	rp->type = type;
279 
280 	ULONG(rp->ttl);
281 	rp->ttl += now;
282 	USHORT(len);
283 	data = sp->p;
284 
285 	if(sp->p + len > sp->ep)
286 		sp->err = toolong;
287 	if(sp->err){
288 		rrfree(rp);
289 		return 0;
290 	}
291 
292 	switch(type){
293 	default:
294 		/* unknown type, just ignore it */
295 		sp->p = data + len;
296 		rrfree(rp);
297 		goto retry;
298 	case Thinfo:
299 		SYMBOL(rp->cpu);
300 		SYMBOL(rp->os);
301 		break;
302 	case Tcname:
303 	case Tmb:
304 	case Tmd:
305 	case Tmf:
306 	case Tns:
307 		rp->host = dnlookup(NAME(dname), Cin, 1);
308 		break;
309 	case Tmg:
310 	case Tmr:
311 		rp->mb = dnlookup(NAME(dname), Cin, 1);
312 		break;
313 	case Tminfo:
314 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
315 		rp->mb = dnlookup(NAME(dname), Cin, 1);
316 		break;
317 	case Tmx:
318 		USHORT(rp->pref);
319 		rp->host = dnlookup(NAME(dname), Cin, 1);
320 		break;
321 	case Ta:
322 		V4ADDR(rp->ip);
323 		break;
324 	case Taaaa:
325 		V6ADDR(rp->ip);
326 		break;
327 	case Tptr:
328 		rp->ptr = dnlookup(NAME(dname), Cin, 1);
329 		break;
330 	case Tsoa:
331 		rp->host = dnlookup(NAME(dname), Cin, 1);
332 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
333 		ULONG(rp->soa->serial);
334 		ULONG(rp->soa->refresh);
335 		ULONG(rp->soa->retry);
336 		ULONG(rp->soa->expire);
337 		ULONG(rp->soa->minttl);
338 		break;
339 	case Ttxt:
340 		l = &rp->txt;
341 		*l = nil;
342 		while(sp->p-data < len){
343 			STRING(t);
344 			*l = t;
345 			l = &t->next;
346 		}
347 		break;
348 	case Tnull:
349 		BYTES(rp->null->data, rp->null->dlen);
350 		break;
351 	case Trp:
352 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
353 		rp->rp = dnlookup(NAME(dname), Cin, 1);
354 		break;
355 	case Tkey:
356 		USHORT(rp->key->flags);
357 		UCHAR(rp->key->proto);
358 		UCHAR(rp->key->alg);
359 		BYTES(rp->key->data, rp->key->dlen);
360 		break;
361 	case Tsig:
362 		USHORT(rp->sig->type);
363 		UCHAR(rp->sig->alg);
364 		UCHAR(rp->sig->labels);
365 		ULONG(rp->sig->ttl);
366 		ULONG(rp->sig->exp);
367 		ULONG(rp->sig->incep);
368 		USHORT(rp->sig->tag);
369 		rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
370 		BYTES(rp->sig->data, rp->sig->dlen);
371 		break;
372 	case Tcert:
373 		USHORT(rp->cert->type);
374 		USHORT(rp->cert->tag);
375 		UCHAR(rp->cert->alg);
376 		BYTES(rp->cert->data, rp->cert->dlen);
377 		break;
378 	}
379 	if(sp->p - data != len)
380 		sp->err = "bad RR len";
381 	return rp;
382 }
383 
384 /*
385  *  convert the next question from a message
386  */
387 static RR*
convM2Q(Scan * sp)388 convM2Q(Scan *sp)
389 {
390 	char dname[Domlen+1];
391 	int type;
392 	int class;
393 	RR *rp;
394 
395 	NAME(dname);
396 	USHORT(type);
397 	USHORT(class);
398 	if(sp->err)
399 		return 0;
400 
401 	rp = rralloc(type);
402 	rp->owner = dnlookup(dname, class, 1);
403 
404 	return rp;
405 }
406 
407 static RR*
rrloop(Scan * sp,int count,int quest)408 rrloop(Scan *sp, int count, int quest)
409 {
410 	int i;
411 	RR *first, *rp, **l;
412 
413 	if(sp->err)
414 		return 0;
415 	l = &first;
416 	first = 0;
417 	for(i = 0; i < count; i++){
418 		rp = quest ? convM2Q(sp) : convM2RR(sp);
419 		if(rp == 0)
420 			break;
421 		if(sp->err){
422 			rrfree(rp);
423 			break;
424 		}
425 		*l = rp;
426 		l = &rp->next;
427 	}
428 	return first;
429 }
430 
431 /*
432  *  convert the next DNS from a message stream
433  */
434 char*
convM2DNS(uchar * buf,int len,DNSmsg * m)435 convM2DNS(uchar *buf, int len, DNSmsg *m)
436 {
437 	Scan scan;
438 	Scan *sp;
439 	char *err;
440 
441 	scan.base = buf;
442 	scan.p = buf;
443 	scan.ep = buf + len;
444 	scan.err = 0;
445 	sp = &scan;
446 	memset(m, 0, sizeof(DNSmsg));
447 	USHORT(m->id);
448 	USHORT(m->flags);
449 	USHORT(m->qdcount);
450 	USHORT(m->ancount);
451 	USHORT(m->nscount);
452 	USHORT(m->arcount);
453 	m->qd = rrloop(sp, m->qdcount, 1);
454 	m->an = rrloop(sp, m->ancount, 0);
455 	m->ns = rrloop(sp, m->nscount, 0);
456 	err = scan.err;				/* live with bad ar's */
457 	m->ar = rrloop(sp, m->arcount, 0);
458 	return err;
459 }
460