|
1 /* $NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $ */ |
|
2 |
|
3 /* |
|
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
|
5 * Copyright (c) 1996,1999 by Internet Software Consortium. |
|
6 * |
|
7 * Permission to use, copy, modify, and distribute this software for any |
|
8 * purpose with or without fee is hereby granted, provided that the above |
|
9 * copyright notice and this permission notice appear in all copies. |
|
10 * |
|
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
|
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
|
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
|
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
18 */ |
|
19 |
|
20 /* |
|
21 * This version of this file is derived from Android 2.3 "Gingerbread", |
|
22 * which contains uncredited changes by Android/Google developers. It has |
|
23 * been modified in 2011 for use in the Android build of Mozilla Firefox by |
|
24 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>, |
|
25 * and Steve Workman <sjhworkman@gmail.com>). |
|
26 * These changes are offered under the same license as the original NetBSD |
|
27 * file, whose copyright and license are unchanged above. |
|
28 */ |
|
29 |
|
30 #define ANDROID_CHANGES 1 |
|
31 #define MOZILLA_NECKO_EXCLUDE_CODE 1 |
|
32 |
|
33 #include <sys/cdefs.h> |
|
34 #ifndef lint |
|
35 #ifdef notdef |
|
36 static const char rcsid[] = "Id: ns_name.c,v 1.3.2.4.4.2 2004/05/04 03:27:47 marka Exp"; |
|
37 #else |
|
38 __RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $"); |
|
39 #endif |
|
40 #endif |
|
41 |
|
42 #include <sys/types.h> |
|
43 |
|
44 #include <netinet/in.h> |
|
45 #include "arpa_nameser.h" |
|
46 |
|
47 #include <errno.h> |
|
48 #ifdef ANDROID_CHANGES |
|
49 #include "resolv_private.h" |
|
50 #else |
|
51 #include <resolv.h> |
|
52 #endif |
|
53 #include <string.h> |
|
54 #include <ctype.h> |
|
55 #include <stdlib.h> |
|
56 #include <limits.h> |
|
57 |
|
58 #ifdef SPRINTF_CHAR |
|
59 # define SPRINTF(x) strlen(sprintf/**/x) |
|
60 #else |
|
61 # define SPRINTF(x) ((size_t)sprintf x) |
|
62 #endif |
|
63 |
|
64 #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ |
|
65 #define DNS_LABELTYPE_BITSTRING 0x41 |
|
66 |
|
67 /* Data. */ |
|
68 |
|
69 static const char digits[] = "0123456789"; |
|
70 |
|
71 static const char digitvalue[256] = { |
|
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ |
|
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ |
|
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ |
|
75 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ |
|
76 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ |
|
77 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ |
|
78 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ |
|
79 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ |
|
80 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
81 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
82 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
83 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
84 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
85 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
86 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
87 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ |
|
88 }; |
|
89 |
|
90 /* Forward. */ |
|
91 |
|
92 static int special(int); |
|
93 static int printable(int); |
|
94 static int dn_find(const u_char *, const u_char *, |
|
95 const u_char * const *, |
|
96 const u_char * const *); |
|
97 static int encode_bitsring(const char **, const char *, |
|
98 unsigned char **, unsigned char **, |
|
99 unsigned const char *); |
|
100 static int labellen(const u_char *); |
|
101 static int decode_bitstring(const unsigned char **, |
|
102 char *, const char *); |
|
103 |
|
104 /* Public. */ |
|
105 |
|
106 /* |
|
107 * ns_name_ntop(src, dst, dstsiz) |
|
108 * Convert an encoded domain name to printable ascii as per RFC1035. |
|
109 * return: |
|
110 * Number of bytes written to buffer, or -1 (with errno set) |
|
111 * notes: |
|
112 * The root is returned as "." |
|
113 * All other domains are returned in non absolute form |
|
114 */ |
|
115 int |
|
116 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) |
|
117 { |
|
118 const u_char *cp; |
|
119 char *dn, *eom; |
|
120 u_char c; |
|
121 u_int n; |
|
122 int l; |
|
123 |
|
124 cp = src; |
|
125 dn = dst; |
|
126 eom = dst + dstsiz; |
|
127 |
|
128 while ((n = *cp++) != 0) { |
|
129 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
|
130 /* Some kind of compression pointer. */ |
|
131 errno = EMSGSIZE; |
|
132 return (-1); |
|
133 } |
|
134 if (dn != dst) { |
|
135 if (dn >= eom) { |
|
136 errno = EMSGSIZE; |
|
137 return (-1); |
|
138 } |
|
139 *dn++ = '.'; |
|
140 } |
|
141 if ((l = labellen(cp - 1)) < 0) { |
|
142 errno = EMSGSIZE; /* XXX */ |
|
143 return(-1); |
|
144 } |
|
145 if (dn + l >= eom) { |
|
146 errno = EMSGSIZE; |
|
147 return (-1); |
|
148 } |
|
149 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { |
|
150 int m; |
|
151 |
|
152 if (n != DNS_LABELTYPE_BITSTRING) { |
|
153 /* XXX: labellen should reject this case */ |
|
154 errno = EINVAL; |
|
155 return(-1); |
|
156 } |
|
157 if ((m = decode_bitstring(&cp, dn, eom)) < 0) |
|
158 { |
|
159 errno = EMSGSIZE; |
|
160 return(-1); |
|
161 } |
|
162 dn += m; |
|
163 continue; |
|
164 } |
|
165 for (; l > 0; l--) { |
|
166 c = *cp++; |
|
167 if (special(c)) { |
|
168 if (dn + 1 >= eom) { |
|
169 errno = EMSGSIZE; |
|
170 return (-1); |
|
171 } |
|
172 *dn++ = '\\'; |
|
173 *dn++ = (char)c; |
|
174 } else if (!printable(c)) { |
|
175 if (dn + 3 >= eom) { |
|
176 errno = EMSGSIZE; |
|
177 return (-1); |
|
178 } |
|
179 *dn++ = '\\'; |
|
180 *dn++ = digits[c / 100]; |
|
181 *dn++ = digits[(c % 100) / 10]; |
|
182 *dn++ = digits[c % 10]; |
|
183 } else { |
|
184 if (dn >= eom) { |
|
185 errno = EMSGSIZE; |
|
186 return (-1); |
|
187 } |
|
188 *dn++ = (char)c; |
|
189 } |
|
190 } |
|
191 } |
|
192 if (dn == dst) { |
|
193 if (dn >= eom) { |
|
194 errno = EMSGSIZE; |
|
195 return (-1); |
|
196 } |
|
197 *dn++ = '.'; |
|
198 } |
|
199 if (dn >= eom) { |
|
200 errno = EMSGSIZE; |
|
201 return (-1); |
|
202 } |
|
203 *dn++ = '\0'; |
|
204 return (dn - dst); |
|
205 } |
|
206 |
|
207 /* |
|
208 * ns_name_pton(src, dst, dstsiz) |
|
209 * Convert a ascii string into an encoded domain name as per RFC1035. |
|
210 * return: |
|
211 * -1 if it fails |
|
212 * 1 if string was fully qualified |
|
213 * 0 is string was not fully qualified |
|
214 * notes: |
|
215 * Enforces label and domain length limits. |
|
216 */ |
|
217 |
|
218 int |
|
219 ns_name_pton(const char *src, u_char *dst, size_t dstsiz) |
|
220 { |
|
221 u_char *label, *bp, *eom; |
|
222 int c, n, escaped, e = 0; |
|
223 char *cp; |
|
224 |
|
225 escaped = 0; |
|
226 bp = dst; |
|
227 eom = dst + dstsiz; |
|
228 label = bp++; |
|
229 |
|
230 while ((c = *src++) != 0) { |
|
231 if (escaped) { |
|
232 if (c == '[') { /* start a bit string label */ |
|
233 if ((cp = strchr(src, ']')) == NULL) { |
|
234 errno = EINVAL; /* ??? */ |
|
235 return(-1); |
|
236 } |
|
237 if ((e = encode_bitsring(&src, cp + 2, |
|
238 &label, &bp, eom)) |
|
239 != 0) { |
|
240 errno = e; |
|
241 return(-1); |
|
242 } |
|
243 escaped = 0; |
|
244 label = bp++; |
|
245 if ((c = *src++) == 0) |
|
246 goto done; |
|
247 else if (c != '.') { |
|
248 errno = EINVAL; |
|
249 return(-1); |
|
250 } |
|
251 continue; |
|
252 } |
|
253 else if ((cp = strchr(digits, c)) != NULL) { |
|
254 n = (cp - digits) * 100; |
|
255 if ((c = *src++) == 0 || |
|
256 (cp = strchr(digits, c)) == NULL) { |
|
257 errno = EMSGSIZE; |
|
258 return (-1); |
|
259 } |
|
260 n += (cp - digits) * 10; |
|
261 if ((c = *src++) == 0 || |
|
262 (cp = strchr(digits, c)) == NULL) { |
|
263 errno = EMSGSIZE; |
|
264 return (-1); |
|
265 } |
|
266 n += (cp - digits); |
|
267 if (n > 255) { |
|
268 errno = EMSGSIZE; |
|
269 return (-1); |
|
270 } |
|
271 c = n; |
|
272 } |
|
273 escaped = 0; |
|
274 } else if (c == '\\') { |
|
275 escaped = 1; |
|
276 continue; |
|
277 } else if (c == '.') { |
|
278 c = (bp - label - 1); |
|
279 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ |
|
280 errno = EMSGSIZE; |
|
281 return (-1); |
|
282 } |
|
283 if (label >= eom) { |
|
284 errno = EMSGSIZE; |
|
285 return (-1); |
|
286 } |
|
287 *label = c; |
|
288 /* Fully qualified ? */ |
|
289 if (*src == '\0') { |
|
290 if (c != 0) { |
|
291 if (bp >= eom) { |
|
292 errno = EMSGSIZE; |
|
293 return (-1); |
|
294 } |
|
295 *bp++ = '\0'; |
|
296 } |
|
297 if ((bp - dst) > MAXCDNAME) { |
|
298 errno = EMSGSIZE; |
|
299 return (-1); |
|
300 } |
|
301 return (1); |
|
302 } |
|
303 if (c == 0 || *src == '.') { |
|
304 errno = EMSGSIZE; |
|
305 return (-1); |
|
306 } |
|
307 label = bp++; |
|
308 continue; |
|
309 } |
|
310 if (bp >= eom) { |
|
311 errno = EMSGSIZE; |
|
312 return (-1); |
|
313 } |
|
314 *bp++ = (u_char)c; |
|
315 } |
|
316 c = (bp - label - 1); |
|
317 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ |
|
318 errno = EMSGSIZE; |
|
319 return (-1); |
|
320 } |
|
321 done: |
|
322 if (label >= eom) { |
|
323 errno = EMSGSIZE; |
|
324 return (-1); |
|
325 } |
|
326 *label = c; |
|
327 if (c != 0) { |
|
328 if (bp >= eom) { |
|
329 errno = EMSGSIZE; |
|
330 return (-1); |
|
331 } |
|
332 *bp++ = 0; |
|
333 } |
|
334 if ((bp - dst) > MAXCDNAME) { /* src too big */ |
|
335 errno = EMSGSIZE; |
|
336 return (-1); |
|
337 } |
|
338 return (0); |
|
339 } |
|
340 |
|
341 #ifndef MOZILLA_NECKO_EXCLUDE_CODE |
|
342 /* |
|
343 * ns_name_ntol(src, dst, dstsiz) |
|
344 * Convert a network strings labels into all lowercase. |
|
345 * return: |
|
346 * Number of bytes written to buffer, or -1 (with errno set) |
|
347 * notes: |
|
348 * Enforces label and domain length limits. |
|
349 */ |
|
350 |
|
351 int |
|
352 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) |
|
353 { |
|
354 const u_char *cp; |
|
355 u_char *dn, *eom; |
|
356 u_char c; |
|
357 u_int n; |
|
358 int l; |
|
359 |
|
360 cp = src; |
|
361 dn = dst; |
|
362 eom = dst + dstsiz; |
|
363 |
|
364 if (dn >= eom) { |
|
365 errno = EMSGSIZE; |
|
366 return (-1); |
|
367 } |
|
368 while ((n = *cp++) != 0) { |
|
369 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
|
370 /* Some kind of compression pointer. */ |
|
371 errno = EMSGSIZE; |
|
372 return (-1); |
|
373 } |
|
374 *dn++ = n; |
|
375 if ((l = labellen(cp - 1)) < 0) { |
|
376 errno = EMSGSIZE; |
|
377 return (-1); |
|
378 } |
|
379 if (dn + l >= eom) { |
|
380 errno = EMSGSIZE; |
|
381 return (-1); |
|
382 } |
|
383 for (; l > 0; l--) { |
|
384 c = *cp++; |
|
385 if (isupper(c)) |
|
386 *dn++ = tolower(c); |
|
387 else |
|
388 *dn++ = c; |
|
389 } |
|
390 } |
|
391 *dn++ = '\0'; |
|
392 return (dn - dst); |
|
393 } |
|
394 #endif |
|
395 |
|
396 /* |
|
397 * ns_name_unpack(msg, eom, src, dst, dstsiz) |
|
398 * Unpack a domain name from a message, source may be compressed. |
|
399 * return: |
|
400 * -1 if it fails, or consumed octets if it succeeds. |
|
401 */ |
|
402 int |
|
403 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, |
|
404 u_char *dst, size_t dstsiz) |
|
405 { |
|
406 const u_char *srcp, *dstlim; |
|
407 u_char *dstp; |
|
408 int n, len, checked, l; |
|
409 |
|
410 len = -1; |
|
411 checked = 0; |
|
412 dstp = dst; |
|
413 srcp = src; |
|
414 dstlim = dst + dstsiz; |
|
415 if (srcp < msg || srcp >= eom) { |
|
416 errno = EMSGSIZE; |
|
417 return (-1); |
|
418 } |
|
419 /* Fetch next label in domain name. */ |
|
420 while ((n = *srcp++) != 0) { |
|
421 /* Check for indirection. */ |
|
422 switch (n & NS_CMPRSFLGS) { |
|
423 case 0: |
|
424 case NS_TYPE_ELT: |
|
425 /* Limit checks. */ |
|
426 if ((l = labellen(srcp - 1)) < 0) { |
|
427 errno = EMSGSIZE; |
|
428 return(-1); |
|
429 } |
|
430 if (dstp + l + 1 >= dstlim || srcp + l >= eom) { |
|
431 errno = EMSGSIZE; |
|
432 return (-1); |
|
433 } |
|
434 checked += l + 1; |
|
435 *dstp++ = n; |
|
436 memcpy(dstp, srcp, (size_t)l); |
|
437 dstp += l; |
|
438 srcp += l; |
|
439 break; |
|
440 |
|
441 case NS_CMPRSFLGS: |
|
442 if (srcp >= eom) { |
|
443 errno = EMSGSIZE; |
|
444 return (-1); |
|
445 } |
|
446 if (len < 0) |
|
447 len = srcp - src + 1; |
|
448 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); |
|
449 if (srcp < msg || srcp >= eom) { /* Out of range. */ |
|
450 errno = EMSGSIZE; |
|
451 return (-1); |
|
452 } |
|
453 checked += 2; |
|
454 /* |
|
455 * Check for loops in the compressed name; |
|
456 * if we've looked at the whole message, |
|
457 * there must be a loop. |
|
458 */ |
|
459 if (checked >= eom - msg) { |
|
460 errno = EMSGSIZE; |
|
461 return (-1); |
|
462 } |
|
463 break; |
|
464 |
|
465 default: |
|
466 errno = EMSGSIZE; |
|
467 return (-1); /* flag error */ |
|
468 } |
|
469 } |
|
470 *dstp = '\0'; |
|
471 if (len < 0) |
|
472 len = srcp - src; |
|
473 return (len); |
|
474 } |
|
475 |
|
476 /* |
|
477 * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) |
|
478 * Pack domain name 'domain' into 'comp_dn'. |
|
479 * return: |
|
480 * Size of the compressed name, or -1. |
|
481 * notes: |
|
482 * 'dnptrs' is an array of pointers to previous compressed names. |
|
483 * dnptrs[0] is a pointer to the beginning of the message. The array |
|
484 * ends with NULL. |
|
485 * 'lastdnptr' is a pointer to the end of the array pointed to |
|
486 * by 'dnptrs'. |
|
487 * Side effects: |
|
488 * The list of pointers in dnptrs is updated for labels inserted into |
|
489 * the message as we compress the name. If 'dnptr' is NULL, we don't |
|
490 * try to compress names. If 'lastdnptr' is NULL, we don't update the |
|
491 * list. |
|
492 */ |
|
493 int |
|
494 ns_name_pack(const u_char *src, u_char *dst, int dstsiz, |
|
495 const u_char **dnptrs, const u_char **lastdnptr) |
|
496 { |
|
497 u_char *dstp; |
|
498 const u_char **cpp, **lpp, *eob, *msg; |
|
499 const u_char *srcp; |
|
500 int n, l, first = 1; |
|
501 |
|
502 srcp = src; |
|
503 dstp = dst; |
|
504 eob = dstp + dstsiz; |
|
505 lpp = cpp = NULL; |
|
506 if (dnptrs != NULL) { |
|
507 if ((msg = *dnptrs++) != NULL) { |
|
508 for (cpp = dnptrs; *cpp != NULL; cpp++) |
|
509 ; |
|
510 lpp = cpp; /* end of list to search */ |
|
511 } |
|
512 } else |
|
513 msg = NULL; |
|
514 |
|
515 /* make sure the domain we are about to add is legal */ |
|
516 l = 0; |
|
517 do { |
|
518 int l0; |
|
519 |
|
520 n = *srcp; |
|
521 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
|
522 errno = EMSGSIZE; |
|
523 return (-1); |
|
524 } |
|
525 if ((l0 = labellen(srcp)) < 0) { |
|
526 errno = EINVAL; |
|
527 return(-1); |
|
528 } |
|
529 l += l0 + 1; |
|
530 if (l > MAXCDNAME) { |
|
531 errno = EMSGSIZE; |
|
532 return (-1); |
|
533 } |
|
534 srcp += l0 + 1; |
|
535 } while (n != 0); |
|
536 |
|
537 /* from here on we need to reset compression pointer array on error */ |
|
538 srcp = src; |
|
539 do { |
|
540 /* Look to see if we can use pointers. */ |
|
541 n = *srcp; |
|
542 if (n != 0 && msg != NULL) { |
|
543 l = dn_find(srcp, msg, (const u_char * const *)dnptrs, |
|
544 (const u_char * const *)lpp); |
|
545 if (l >= 0) { |
|
546 if (dstp + 1 >= eob) { |
|
547 goto cleanup; |
|
548 } |
|
549 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS; |
|
550 *dstp++ = l % 256; |
|
551 return (dstp - dst); |
|
552 } |
|
553 /* Not found, save it. */ |
|
554 if (lastdnptr != NULL && cpp < lastdnptr - 1 && |
|
555 (dstp - msg) < 0x4000 && first) { |
|
556 *cpp++ = dstp; |
|
557 *cpp = NULL; |
|
558 first = 0; |
|
559 } |
|
560 } |
|
561 /* copy label to buffer */ |
|
562 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
|
563 /* Should not happen. */ |
|
564 goto cleanup; |
|
565 } |
|
566 n = labellen(srcp); |
|
567 if (dstp + 1 + n >= eob) { |
|
568 goto cleanup; |
|
569 } |
|
570 memcpy(dstp, srcp, (size_t)(n + 1)); |
|
571 srcp += n + 1; |
|
572 dstp += n + 1; |
|
573 } while (n != 0); |
|
574 |
|
575 if (dstp > eob) { |
|
576 cleanup: |
|
577 if (msg != NULL) |
|
578 *lpp = NULL; |
|
579 errno = EMSGSIZE; |
|
580 return (-1); |
|
581 } |
|
582 return (dstp - dst); |
|
583 } |
|
584 |
|
585 /* |
|
586 * ns_name_uncompress(msg, eom, src, dst, dstsiz) |
|
587 * Expand compressed domain name to presentation format. |
|
588 * return: |
|
589 * Number of bytes read out of `src', or -1 (with errno set). |
|
590 * note: |
|
591 * Root domain returns as "." not "". |
|
592 */ |
|
593 int |
|
594 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, |
|
595 char *dst, size_t dstsiz) |
|
596 { |
|
597 u_char tmp[NS_MAXCDNAME]; |
|
598 int n; |
|
599 |
|
600 if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) |
|
601 return (-1); |
|
602 if (ns_name_ntop(tmp, dst, dstsiz) == -1) |
|
603 return (-1); |
|
604 return (n); |
|
605 } |
|
606 |
|
607 /* |
|
608 * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) |
|
609 * Compress a domain name into wire format, using compression pointers. |
|
610 * return: |
|
611 * Number of bytes consumed in `dst' or -1 (with errno set). |
|
612 * notes: |
|
613 * 'dnptrs' is an array of pointers to previous compressed names. |
|
614 * dnptrs[0] is a pointer to the beginning of the message. |
|
615 * The list ends with NULL. 'lastdnptr' is a pointer to the end of the |
|
616 * array pointed to by 'dnptrs'. Side effect is to update the list of |
|
617 * pointers for labels inserted into the message as we compress the name. |
|
618 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' |
|
619 * is NULL, we don't update the list. |
|
620 */ |
|
621 int |
|
622 ns_name_compress(const char *src, u_char *dst, size_t dstsiz, |
|
623 const u_char **dnptrs, const u_char **lastdnptr) |
|
624 { |
|
625 u_char tmp[NS_MAXCDNAME]; |
|
626 |
|
627 if (ns_name_pton(src, tmp, sizeof tmp) == -1) |
|
628 return (-1); |
|
629 return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); |
|
630 } |
|
631 |
|
632 #ifndef MOZILLA_NECKO_EXCLUDE_CODE |
|
633 /* |
|
634 * Reset dnptrs so that there are no active references to pointers at or |
|
635 * after src. |
|
636 */ |
|
637 void |
|
638 ns_name_rollback(const u_char *src, const u_char **dnptrs, |
|
639 const u_char **lastdnptr) |
|
640 { |
|
641 while (dnptrs < lastdnptr && *dnptrs != NULL) { |
|
642 if (*dnptrs >= src) { |
|
643 *dnptrs = NULL; |
|
644 break; |
|
645 } |
|
646 dnptrs++; |
|
647 } |
|
648 } |
|
649 #endif |
|
650 |
|
651 /* |
|
652 * ns_name_skip(ptrptr, eom) |
|
653 * Advance *ptrptr to skip over the compressed name it points at. |
|
654 * return: |
|
655 * 0 on success, -1 (with errno set) on failure. |
|
656 */ |
|
657 int |
|
658 ns_name_skip(const u_char **ptrptr, const u_char *eom) |
|
659 { |
|
660 const u_char *cp; |
|
661 u_int n; |
|
662 int l; |
|
663 |
|
664 cp = *ptrptr; |
|
665 while (cp < eom && (n = *cp++) != 0) { |
|
666 /* Check for indirection. */ |
|
667 switch (n & NS_CMPRSFLGS) { |
|
668 case 0: /* normal case, n == len */ |
|
669 cp += n; |
|
670 continue; |
|
671 case NS_TYPE_ELT: /* EDNS0 extended label */ |
|
672 if ((l = labellen(cp - 1)) < 0) { |
|
673 errno = EMSGSIZE; /* XXX */ |
|
674 return(-1); |
|
675 } |
|
676 cp += l; |
|
677 continue; |
|
678 case NS_CMPRSFLGS: /* indirection */ |
|
679 cp++; |
|
680 break; |
|
681 default: /* illegal type */ |
|
682 errno = EMSGSIZE; |
|
683 return (-1); |
|
684 } |
|
685 break; |
|
686 } |
|
687 if (cp > eom) { |
|
688 errno = EMSGSIZE; |
|
689 return (-1); |
|
690 } |
|
691 *ptrptr = cp; |
|
692 return (0); |
|
693 } |
|
694 |
|
695 /* Private. */ |
|
696 |
|
697 /* |
|
698 * special(ch) |
|
699 * Thinking in noninternationalized USASCII (per the DNS spec), |
|
700 * is this characted special ("in need of quoting") ? |
|
701 * return: |
|
702 * boolean. |
|
703 */ |
|
704 static int |
|
705 special(int ch) { |
|
706 switch (ch) { |
|
707 case 0x22: /* '"' */ |
|
708 case 0x2E: /* '.' */ |
|
709 case 0x3B: /* ';' */ |
|
710 case 0x5C: /* '\\' */ |
|
711 case 0x28: /* '(' */ |
|
712 case 0x29: /* ')' */ |
|
713 /* Special modifiers in zone files. */ |
|
714 case 0x40: /* '@' */ |
|
715 case 0x24: /* '$' */ |
|
716 return (1); |
|
717 default: |
|
718 return (0); |
|
719 } |
|
720 } |
|
721 |
|
722 /* |
|
723 * printable(ch) |
|
724 * Thinking in noninternationalized USASCII (per the DNS spec), |
|
725 * is this character visible and not a space when printed ? |
|
726 * return: |
|
727 * boolean. |
|
728 */ |
|
729 static int |
|
730 printable(int ch) { |
|
731 return (ch > 0x20 && ch < 0x7f); |
|
732 } |
|
733 |
|
734 /* |
|
735 * Thinking in noninternationalized USASCII (per the DNS spec), |
|
736 * convert this character to lower case if it's upper case. |
|
737 */ |
|
738 static int |
|
739 mklower(int ch) { |
|
740 if (ch >= 0x41 && ch <= 0x5A) |
|
741 return (ch + 0x20); |
|
742 return (ch); |
|
743 } |
|
744 |
|
745 /* |
|
746 * dn_find(domain, msg, dnptrs, lastdnptr) |
|
747 * Search for the counted-label name in an array of compressed names. |
|
748 * return: |
|
749 * offset from msg if found, or -1. |
|
750 * notes: |
|
751 * dnptrs is the pointer to the first name on the list, |
|
752 * not the pointer to the start of the message. |
|
753 */ |
|
754 static int |
|
755 dn_find(const u_char *domain, const u_char *msg, |
|
756 const u_char * const *dnptrs, |
|
757 const u_char * const *lastdnptr) |
|
758 { |
|
759 const u_char *dn, *cp, *sp; |
|
760 const u_char * const *cpp; |
|
761 u_int n; |
|
762 |
|
763 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { |
|
764 sp = *cpp; |
|
765 /* |
|
766 * terminate search on: |
|
767 * root label |
|
768 * compression pointer |
|
769 * unusable offset |
|
770 */ |
|
771 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && |
|
772 (sp - msg) < 0x4000) { |
|
773 dn = domain; |
|
774 cp = sp; |
|
775 while ((n = *cp++) != 0) { |
|
776 /* |
|
777 * check for indirection |
|
778 */ |
|
779 switch (n & NS_CMPRSFLGS) { |
|
780 case 0: /* normal case, n == len */ |
|
781 n = labellen(cp - 1); /* XXX */ |
|
782 |
|
783 if (n != *dn++) |
|
784 goto next; |
|
785 |
|
786 for (; n > 0; n--) |
|
787 if (mklower(*dn++) != |
|
788 mklower(*cp++)) |
|
789 goto next; |
|
790 /* Is next root for both ? */ |
|
791 if (*dn == '\0' && *cp == '\0') |
|
792 return (sp - msg); |
|
793 if (*dn) |
|
794 continue; |
|
795 goto next; |
|
796 case NS_CMPRSFLGS: /* indirection */ |
|
797 cp = msg + (((n & 0x3f) << 8) | *cp); |
|
798 break; |
|
799 |
|
800 default: /* illegal type */ |
|
801 errno = EMSGSIZE; |
|
802 return (-1); |
|
803 } |
|
804 } |
|
805 next: ; |
|
806 sp += *sp + 1; |
|
807 } |
|
808 } |
|
809 errno = ENOENT; |
|
810 return (-1); |
|
811 } |
|
812 |
|
813 static int |
|
814 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) |
|
815 { |
|
816 const unsigned char *cp = *cpp; |
|
817 char *beg = dn, tc; |
|
818 int b, blen, plen, i; |
|
819 |
|
820 if ((blen = (*cp & 0xff)) == 0) |
|
821 blen = 256; |
|
822 plen = (blen + 3) / 4; |
|
823 plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); |
|
824 if (dn + plen >= eom) |
|
825 return(-1); |
|
826 |
|
827 cp++; |
|
828 i = SPRINTF((dn, "\\[x")); |
|
829 if (i < 0) |
|
830 return (-1); |
|
831 dn += i; |
|
832 for (b = blen; b > 7; b -= 8, cp++) { |
|
833 i = SPRINTF((dn, "%02x", *cp & 0xff)); |
|
834 if (i < 0) |
|
835 return (-1); |
|
836 dn += i; |
|
837 } |
|
838 if (b > 4) { |
|
839 tc = *cp++; |
|
840 i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); |
|
841 if (i < 0) |
|
842 return (-1); |
|
843 dn += i; |
|
844 } else if (b > 0) { |
|
845 tc = *cp++; |
|
846 i = SPRINTF((dn, "%1x", |
|
847 (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b)))); |
|
848 if (i < 0) |
|
849 return (-1); |
|
850 dn += i; |
|
851 } |
|
852 i = SPRINTF((dn, "/%d]", blen)); |
|
853 if (i < 0) |
|
854 return (-1); |
|
855 dn += i; |
|
856 |
|
857 *cpp = cp; |
|
858 return(dn - beg); |
|
859 } |
|
860 |
|
861 static int |
|
862 encode_bitsring(const char **bp, const char *end, unsigned char **labelp, |
|
863 unsigned char ** dst, unsigned const char *eom) |
|
864 { |
|
865 int afterslash = 0; |
|
866 const char *cp = *bp; |
|
867 unsigned char *tp; |
|
868 char c; |
|
869 const char *beg_blen; |
|
870 char *end_blen = NULL; |
|
871 int value = 0, count = 0, tbcount = 0, blen = 0; |
|
872 |
|
873 beg_blen = end_blen = NULL; |
|
874 |
|
875 /* a bitstring must contain at least 2 characters */ |
|
876 if (end - cp < 2) |
|
877 return(EINVAL); |
|
878 |
|
879 /* XXX: currently, only hex strings are supported */ |
|
880 if (*cp++ != 'x') |
|
881 return(EINVAL); |
|
882 if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ |
|
883 return(EINVAL); |
|
884 |
|
885 for (tp = *dst + 1; cp < end && tp < eom; cp++) { |
|
886 switch((c = *cp)) { |
|
887 case ']': /* end of the bitstring */ |
|
888 if (afterslash) { |
|
889 if (beg_blen == NULL) |
|
890 return(EINVAL); |
|
891 blen = (int)strtol(beg_blen, &end_blen, 10); |
|
892 if (*end_blen != ']') |
|
893 return(EINVAL); |
|
894 } |
|
895 if (count) |
|
896 *tp++ = ((value << 4) & 0xff); |
|
897 cp++; /* skip ']' */ |
|
898 goto done; |
|
899 case '/': |
|
900 afterslash = 1; |
|
901 break; |
|
902 default: |
|
903 if (afterslash) { |
|
904 if (!isdigit(c&0xff)) |
|
905 return(EINVAL); |
|
906 if (beg_blen == NULL) { |
|
907 |
|
908 if (c == '0') { |
|
909 /* blen never begings with 0 */ |
|
910 return(EINVAL); |
|
911 } |
|
912 beg_blen = cp; |
|
913 } |
|
914 } else { |
|
915 if (!isxdigit(c&0xff)) |
|
916 return(EINVAL); |
|
917 value <<= 4; |
|
918 value += digitvalue[(int)c]; |
|
919 count += 4; |
|
920 tbcount += 4; |
|
921 if (tbcount > 256) |
|
922 return(EINVAL); |
|
923 if (count == 8) { |
|
924 *tp++ = value; |
|
925 count = 0; |
|
926 } |
|
927 } |
|
928 break; |
|
929 } |
|
930 } |
|
931 done: |
|
932 if (cp >= end || tp >= eom) |
|
933 return(EMSGSIZE); |
|
934 |
|
935 /* |
|
936 * bit length validation: |
|
937 * If a <length> is present, the number of digits in the <bit-data> |
|
938 * MUST be just sufficient to contain the number of bits specified |
|
939 * by the <length>. If there are insignificant bits in a final |
|
940 * hexadecimal or octal digit, they MUST be zero. |
|
941 * RFC 2673, Section 3.2. |
|
942 */ |
|
943 if (blen > 0) { |
|
944 int traillen; |
|
945 |
|
946 if (((blen + 3) & ~3) != tbcount) |
|
947 return(EINVAL); |
|
948 traillen = tbcount - blen; /* between 0 and 3 */ |
|
949 if (((value << (8 - traillen)) & 0xff) != 0) |
|
950 return(EINVAL); |
|
951 } |
|
952 else |
|
953 blen = tbcount; |
|
954 if (blen == 256) |
|
955 blen = 0; |
|
956 |
|
957 /* encode the type and the significant bit fields */ |
|
958 **labelp = DNS_LABELTYPE_BITSTRING; |
|
959 **dst = blen; |
|
960 |
|
961 *bp = cp; |
|
962 *dst = tp; |
|
963 |
|
964 return(0); |
|
965 } |
|
966 |
|
967 static int |
|
968 labellen(const u_char *lp) |
|
969 { |
|
970 int bitlen; |
|
971 u_char l = *lp; |
|
972 |
|
973 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
|
974 /* should be avoided by the caller */ |
|
975 return(-1); |
|
976 } |
|
977 |
|
978 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { |
|
979 if (l == DNS_LABELTYPE_BITSTRING) { |
|
980 if ((bitlen = *(lp + 1)) == 0) |
|
981 bitlen = 256; |
|
982 return((bitlen + 7 ) / 8 + 1); |
|
983 } |
|
984 return(-1); /* unknwon ELT */ |
|
985 } |
|
986 return(l); |
|
987 } |