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