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*
psym(uchar * p,uchar * ep,char * np)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*
pstr(uchar * p,uchar * ep,char * np)52 pstr(uchar *p, uchar *ep, char *np)
53 {
54 return psym(p, ep, np);
55 }
56
57 static uchar*
pbytes(uchar * p,uchar * ep,uchar * np,int n)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*
puchar(uchar * p,uchar * ep,int val)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*
pushort(uchar * p,uchar * ep,int val)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*
pulong(uchar * p,uchar * ep,int val)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*
pv4addr(uchar * p,uchar * ep,char * name)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*
pv6addr(uchar * p,uchar * ep,char * name)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*
pname(uchar * p,uchar * ep,char * np,Dict * dp)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*
convRR2M(RR * rp,uchar * p,uchar * ep,Dict * dp)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*
convQ2M(RR * rp,uchar * p,uchar * ep,Dict * dp)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*
rrloop(RR * rp,int * countp,uchar * p,uchar * ep,Dict * dp,int quest)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
convDNS2M(DNSmsg * m,uchar * buf,int len)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 }
379