]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/convDNS2M.c
Import sources from 2011-03-30 iso image - lib
[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                                         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 }