]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/convDNS2M.c
ip/ipconfig: default onlink and autoflag to 1
[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 LABEL(x)        p = pname(p, ep, x, nil)
28 #define SYMBOL(x)       p = psym(p, ep, x)
29 #define STRING(x)       p = pstr(p, ep, x)
30 #define BYTES(x, n)     p = pbytes(p, ep, x, n)
31 #define USHORT(x)       p = pushort(p, ep, x)
32 #define UCHAR(x)        p = puchar(p, ep, x)
33 #define ULONG(x)        p = pulong(p, ep, x)
34 #define V4ADDR(x)       p = pv4addr(p, ep, x)
35 #define V6ADDR(x)       p = pv6addr(p, ep, x)
36
37 static uchar*
38 psym(uchar *p, uchar *ep, char *np)
39 {
40         int n;
41
42         n = strlen(np);
43         if(n >= Strlen)                 /* DNS maximum length string */
44                 n = Strlen - 1;
45         if(ep - p < n+1)                /* see if it fits in the buffer */
46                 return ep+1;
47         *p++ = n;
48         memmove(p, np, n);
49         return p + n;
50 }
51
52 static uchar*
53 pstr(uchar *p, uchar *ep, char *np)
54 {
55         return psym(p, ep, np);
56 }
57
58 static uchar*
59 pbytes(uchar *p, uchar *ep, uchar *np, int n)
60 {
61         if(ep - p < n)
62                 return ep+1;
63         memmove(p, np, n);
64         return p + n;
65 }
66
67 static uchar*
68 puchar(uchar *p, uchar *ep, int val)
69 {
70         if(ep - p < 1)
71                 return ep+1;
72         *p++ = val;
73         return p;
74 }
75
76 static uchar*
77 pushort(uchar *p, uchar *ep, int val)
78 {
79         if(ep - p < 2)
80                 return ep+1;
81         *p++ = val>>8;
82         *p++ = val;
83         return p;
84 }
85
86 static uchar*
87 pulong(uchar *p, uchar *ep, int val)
88 {
89         if(ep - p < 4)
90                 return ep+1;
91         *p++ = val>>24;
92         *p++ = val>>16;
93         *p++ = val>>8;
94         *p++ = val;
95         return p;
96 }
97
98 static uchar*
99 pv4addr(uchar *p, uchar *ep, char *name)
100 {
101         uchar ip[IPaddrlen];
102
103         if(ep - p < 4)
104                 return ep+1;
105         parseip(ip, name);
106         v6tov4(p, ip);
107         return p + 4;
108 }
109
110 static uchar*
111 pv6addr(uchar *p, uchar *ep, char *name)
112 {
113         if(ep - p < IPaddrlen)
114                 return ep+1;
115         parseip(p, name);
116         return p + IPaddrlen;
117 }
118
119 static uchar*
120 pname(uchar *p, uchar *ep, char *np, Dict *dp)
121 {
122         int i;
123         char *cp;
124         char *last;             /* last component packed */
125
126         if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */
127                 return ep+1;
128
129         last = nil;
130         while(*np){
131                 if(dp != nil){
132                         /* look through every component in the dictionary for a match */
133                         for(i = 0; i < dp->n; i++){
134                                 if(strcmp(np, dp->x[i].name) == 0){
135                                         if(ep - p < 2)
136                                                 return ep+1;
137                                         if ((dp->x[i].offset>>8) & 0xc0)
138                                                 break;
139                                         *p++ = dp->x[i].offset>>8 | 0xc0;
140                                         *p++ = dp->x[i].offset;
141                                         return p;
142                                 }
143                         }
144                         /* if there's room, enter this name in dictionary */
145                         if(dp->n < Ndict){
146                                 if(last != nil){
147                                         /* the whole name is already in dp->buf */
148                                         last = strchr(last, '.') + 1;
149                                         dp->x[dp->n].name = last;
150                                         dp->x[dp->n].offset = p - dp->start;
151                                         dp->n++;
152                                 } else {
153                                         /* add to dp->buf */
154                                         i = strlen(np);
155                                         if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){
156                                                 memmove(dp->ep, np, i);
157                                                 dp->ep[i] = 0;
158                                                 dp->x[dp->n].name = dp->ep;
159                                                 last = dp->ep;
160                                                 dp->x[dp->n].offset = p - dp->start;
161                                                 dp->ep += i + 1;
162                                                 dp->n++;
163                                         }
164                                 }
165                         }
166                 }
167
168                 /* put next component into message */
169                 cp = strchr(np, '.');
170                 if(cp == nil){
171                         i = strlen(np);
172                         cp = np + i;    /* point to null terminator */
173                 } else {
174                         i = cp - np;
175                         cp++;           /* point past '.' */
176                 }
177                 if(ep-p < i+1)
178                         return ep+1;
179                 if (i > Labellen)
180                         return ep+1;
181                 *p++ = i;               /* count of chars in label */
182                 memmove(p, np, i);
183                 np = cp;
184                 p += i;
185         }
186
187         if(p >= ep)
188                 return ep+1;
189         *p++ = 0;       /* add top level domain */
190
191         return p;
192 }
193
194 static uchar*
195 convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
196 {
197         uchar *lp, *data;
198         long ttl;
199         int len;
200         Txt *t;
201
202         NAME(rp->owner->name);
203         USHORT(rp->type);
204         USHORT(rp->owner->class);
205
206         if(rp->db || (ttl = (long)(rp->expire - now)) > rp->ttl)
207                 ttl = rp->ttl;
208         if(ttl < 0)
209                 ttl = 0;
210         ULONG(ttl);
211
212         lp = p;                 /* leave room for the rdata length */
213         p += 2;
214         data = p;
215
216         if(data >= ep)
217                 return p+1;
218
219         switch(rp->type){
220         case Thinfo:
221                 SYMBOL(rp->cpu->name);
222                 SYMBOL(rp->os->name);
223                 break;
224         case Tcname:
225         case Tmb:
226         case Tmd:
227         case Tmf:
228         case Tns:
229                 NAME(rp->host->name);
230                 break;
231         case Tmg:
232         case Tmr:
233                 NAME(rp->mb->name);
234                 break;
235         case Tminfo:
236                 NAME(rp->rmb->name);
237                 NAME(rp->mb->name);
238                 break;
239         case Tmx:
240                 USHORT(rp->pref);
241                 NAME(rp->host->name);
242                 break;
243         case Ta:
244                 V4ADDR(rp->ip->name);
245                 break;
246         case Taaaa:
247                 V6ADDR(rp->ip->name);
248                 break;
249         case Tptr:
250                 NAME(rp->ptr->name);
251                 break;
252         case Tsoa:
253                 NAME(rp->host->name);
254                 NAME(rp->rmb->name);
255                 ULONG(rp->soa->serial);
256                 ULONG(rp->soa->refresh);
257                 ULONG(rp->soa->retry);
258                 ULONG(rp->soa->expire);
259                 ULONG(rp->soa->minttl);
260                 break;
261         case Tsrv:
262                 USHORT(rp->srv->pri);
263                 USHORT(rp->srv->weight);
264                 USHORT(rp->port);
265                 LABEL(rp->host->name);  /* rfc2782 sez no name compression */
266                 break;
267         case Ttxt:
268                 for(t = rp->txt; t != nil; t = t->next)
269                         STRING(t->p);
270                 break;
271         case Tnull:
272                 BYTES(rp->null->data, rp->null->dlen);
273                 break;
274         case Trp:
275                 NAME(rp->rmb->name);
276                 NAME(rp->rp->name);
277                 break;
278         case Tkey:
279                 USHORT(rp->key->flags);
280                 UCHAR(rp->key->proto);
281                 UCHAR(rp->key->alg);
282                 BYTES(rp->key->data, rp->key->dlen);
283                 break;
284         case Tsig:
285                 USHORT(rp->sig->type);
286                 UCHAR(rp->sig->alg);
287                 UCHAR(rp->sig->labels);
288                 ULONG(rp->sig->ttl);
289                 ULONG(rp->sig->exp);
290                 ULONG(rp->sig->incep);
291                 USHORT(rp->sig->tag);
292                 NAME(rp->sig->signer->name);
293                 BYTES(rp->sig->data, rp->sig->dlen);
294                 break;
295         case Tcert:
296                 USHORT(rp->cert->type);
297                 USHORT(rp->cert->tag);
298                 UCHAR(rp->cert->alg);
299                 BYTES(rp->cert->data, rp->cert->dlen);
300                 break;
301         }
302
303         /* stuff in the rdata section length */
304         len = p - data;
305         *lp++ = len >> 8;
306         *lp = len;
307
308         return p;
309 }
310
311 static uchar*
312 convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
313 {
314         NAME(rp->owner->name);
315         USHORT(rp->type);
316         USHORT(rp->owner->class);
317         return p;
318 }
319
320 static uchar*
321 rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest)
322 {
323         uchar *np;
324
325         *countp = 0;
326         for(; rp && p < ep; rp = rp->next){
327                 if(quest)
328                         np = convQ2M(rp, p, ep, dp);
329                 else
330                         np = convRR2M(rp, p, ep, dp);
331                 if(np > ep)
332                         break;
333                 p = np;
334                 (*countp)++;
335         }
336         return p;
337 }
338
339 /*
340  *  convert into a message
341  */
342 int
343 convDNS2M(DNSmsg *m, uchar *buf, int len)
344 {
345         ulong trunc = 0;
346         uchar *p, *ep, *np;
347         Dict d;
348
349         d.n = 0;
350         d.start = buf;
351         d.ep = d.buf;
352         memset(buf, 0, len);
353         m->qdcount = m->ancount = m->nscount = m->arcount = 0;
354
355         /* first pack in the RR's so we can get real counts */
356         p = buf + 12;
357         ep = buf + len;
358         p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1);
359         p = rrloop(m->an, &m->ancount, p, ep, &d, 0);
360         p = rrloop(m->ns, &m->nscount, p, ep, &d, 0);
361         p = rrloop(m->ar, &m->arcount, p, ep, &d, 0);
362         if(p > ep) {
363                 trunc = Ftrunc;
364                 dnslog("udp packet full; truncating my reply");
365                 p = ep;
366         }
367
368         /* now pack the rest */
369         np = p;
370         p = buf;
371         ep = buf + len;
372         USHORT(m->id);
373         USHORT(m->flags | trunc);
374         USHORT(m->qdcount);
375         USHORT(m->ancount);
376         USHORT(m->nscount);
377         USHORT(m->arcount);
378         USED(p);
379         return np - buf;
380 }