]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/convDNS2M.c
merge
[plan9front.git] / sys / src / cmd / ndb / convDNS2M.c
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                                         memmove(dp->ep, np, i);
156                                         dp->ep[i] = 0;
157                                         dp->x[dp->n].name = dp->ep;
158                                         last = dp->ep;
159                                         dp->x[dp->n].offset = p - dp->start;
160                                         dp->ep += i + 1;
161                                         dp->n++;
162                                 }
163                         }
164
165                 /* put next component into message */
166                 cp = strchr(np, '.');
167                 if(cp == nil){
168                         i = strlen(np);
169                         cp = np + i;    /* point to null terminator */
170                 } else {
171                         i = cp - np;
172                         cp++;           /* point past '.' */
173                 }
174                 if(ep-p < i+1)
175                         return ep+1;
176                 if (i > Labellen)
177                         return ep+1;
178                 *p++ = i;               /* count of chars in label */
179                 memmove(p, np, i);
180                 np = cp;
181                 p += i;
182         }
183
184         if(p >= ep)
185                 return ep+1;
186         *p++ = 0;       /* add top level domain */
187
188         return p;
189 }
190
191 static uchar*
192 convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
193 {
194         uchar *lp, *data;
195         int len, ttl;
196         Txt *t;
197
198         NAME(rp->owner->name);
199         USHORT(rp->type);
200         USHORT(rp->owner->class);
201
202         /* egregious overuse of ttl (it's absolute time in the cache) */
203         if(rp->db)
204                 ttl = rp->ttl;
205         else
206                 ttl = rp->ttl - now;
207         if(ttl < 0)
208                 ttl = 0;
209         ULONG(ttl);
210
211         lp = p;                 /* leave room for the rdata length */
212         p += 2;
213         data = p;
214
215         if(data >= ep)
216                 return p+1;
217
218         switch(rp->type){
219         case Thinfo:
220                 SYMBOL(rp->cpu->name);
221                 SYMBOL(rp->os->name);
222                 break;
223         case Tcname:
224         case Tmb:
225         case Tmd:
226         case Tmf:
227         case Tns:
228                 NAME(rp->host->name);
229                 break;
230         case Tmg:
231         case Tmr:
232                 NAME(rp->mb->name);
233                 break;
234         case Tminfo:
235                 NAME(rp->rmb->name);
236                 NAME(rp->mb->name);
237                 break;
238         case Tmx:
239                 USHORT(rp->pref);
240                 NAME(rp->host->name);
241                 break;
242         case Ta:
243                 V4ADDR(rp->ip->name);
244                 break;
245         case Taaaa:
246                 V6ADDR(rp->ip->name);
247                 break;
248         case Tptr:
249                 NAME(rp->ptr->name);
250                 break;
251         case Tsoa:
252                 NAME(rp->host->name);
253                 NAME(rp->rmb->name);
254                 ULONG(rp->soa->serial);
255                 ULONG(rp->soa->refresh);
256                 ULONG(rp->soa->retry);
257                 ULONG(rp->soa->expire);
258                 ULONG(rp->soa->minttl);
259                 break;
260         case Tsrv:
261                 USHORT(rp->srv->pri);
262                 USHORT(rp->srv->weight);
263                 USHORT(rp->port);
264                 STRING(rp->host->name); /* rfc2782 sez no name compression */
265                 break;
266         case Ttxt:
267                 for(t = rp->txt; t != nil; t = t->next)
268                         STRING(t->p);
269                 break;
270         case Tnull:
271                 BYTES(rp->null->data, rp->null->dlen);
272                 break;
273         case Trp:
274                 NAME(rp->rmb->name);
275                 NAME(rp->rp->name);
276                 break;
277         case Tkey:
278                 USHORT(rp->key->flags);
279                 UCHAR(rp->key->proto);
280                 UCHAR(rp->key->alg);
281                 BYTES(rp->key->data, rp->key->dlen);
282                 break;
283         case Tsig:
284                 USHORT(rp->sig->type);
285                 UCHAR(rp->sig->alg);
286                 UCHAR(rp->sig->labels);
287                 ULONG(rp->sig->ttl);
288                 ULONG(rp->sig->exp);
289                 ULONG(rp->sig->incep);
290                 USHORT(rp->sig->tag);
291                 NAME(rp->sig->signer->name);
292                 BYTES(rp->sig->data, rp->sig->dlen);
293                 break;
294         case Tcert:
295                 USHORT(rp->cert->type);
296                 USHORT(rp->cert->tag);
297                 UCHAR(rp->cert->alg);
298                 BYTES(rp->cert->data, rp->cert->dlen);
299                 break;
300         }
301
302         /* stuff in the rdata section length */
303         len = p - data;
304         *lp++ = len >> 8;
305         *lp = len;
306
307         return p;
308 }
309
310 static uchar*
311 convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
312 {
313         NAME(rp->owner->name);
314         USHORT(rp->type);
315         USHORT(rp->owner->class);
316         return p;
317 }
318
319 static uchar*
320 rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest)
321 {
322         uchar *np;
323
324         *countp = 0;
325         for(; rp && p < ep; rp = rp->next){
326                 if(quest)
327                         np = convQ2M(rp, p, ep, dp);
328                 else
329                         np = convRR2M(rp, p, ep, dp);
330                 if(np > ep)
331                         break;
332                 p = np;
333                 (*countp)++;
334         }
335         return p;
336 }
337
338 /*
339  *  convert into a message
340  */
341 int
342 convDNS2M(DNSmsg *m, uchar *buf, int len)
343 {
344         ulong trunc = 0;
345         uchar *p, *ep, *np;
346         Dict d;
347
348         d.n = 0;
349         d.start = buf;
350         d.ep = d.buf;
351         memset(buf, 0, len);
352         m->qdcount = m->ancount = m->nscount = m->arcount = 0;
353
354         /* first pack in the RR's so we can get real counts */
355         p = buf + 12;
356         ep = buf + len;
357         p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1);
358         p = rrloop(m->an, &m->ancount, p, ep, &d, 0);
359         p = rrloop(m->ns, &m->nscount, p, ep, &d, 0);
360         p = rrloop(m->ar, &m->arcount, p, ep, &d, 0);
361         if(p > ep) {
362                 trunc = Ftrunc;
363                 dnslog("udp packet full; truncating my reply");
364                 p = ep;
365         }
366
367         /* now pack the rest */
368         np = p;
369         p = buf;
370         ep = buf + len;
371         USHORT(m->id);
372         USHORT(m->flags | trunc);
373         USHORT(m->qdcount);
374         USHORT(m->ancount);
375         USHORT(m->nscount);
376         USHORT(m->arcount);
377         USED(p);
378         return np - buf;
379 }