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