ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/irc_reslib.c
Revision: 1156
Committed: Tue Aug 9 20:29:20 2011 UTC (12 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 29759 byte(s)
Log Message:
- create ircd-hybrid-8 "branch"

File Contents

# Content
1 /*
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 */
53
54 /*
55 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
56 *
57 * Permission to use, copy, modify, and distribute this software for any
58 * purpose with or without fee is hereby granted, provided that the above
59 * copyright notice and this permission notice appear in all copies.
60 *
61 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68 * SOFTWARE.
69 */
70
71 /* Original copyright ISC as above.
72 * Code modified specifically for ircd use from the following orginal files
73 * in bind ...
74 *
75 * res_comp.c
76 * ns_name.c
77 * ns_netint.c
78 * res_init.c
79 *
80 * - Dianora
81 */
82
83 #include "stdinc.h"
84 #include "ircd_defs.h"
85 #include "irc_res.h"
86 #include "irc_reslib.h"
87 #include "fileio.h"
88 #include "irc_string.h"
89
90 #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
91 #define DNS_LABELTYPE_BITSTRING 0x41
92 #define MAXLINE 128
93
94 /* $Id$ */
95
96 struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
97 int irc_nscount = 0;
98
99 static const char digitvalue[256] = {
100 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
101 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
102 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
104 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
105 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
106 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
107 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
108 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
109 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
110 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
111 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
112 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
113 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
114 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
115 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
116 };
117
118 static int parse_resvconf(void);
119 static void add_nameserver(char *arg);
120
121 static const char digits[] = "0123456789";
122 static int labellen(const unsigned char *lp);
123 static int special(int ch);
124 static int printable(int ch);
125 static int irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom);
126 static int irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz,
127 const unsigned char **dnptrs, const unsigned char **lastdnptr);
128 static int irc_dn_find(const unsigned char *, const unsigned char *, const unsigned char * const *,
129 const unsigned char * const *);
130 static int irc_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **,
131 const unsigned char *);
132 static int irc_ns_name_uncompress(const unsigned char *, const unsigned char *,
133 const unsigned char *, char *, size_t);
134 static int irc_ns_name_unpack(const unsigned char *, const unsigned char *,
135 const unsigned char *, unsigned char *,
136 size_t);
137 static int irc_ns_name_ntop(const unsigned char *, char *, size_t);
138 static int irc_ns_name_skip(const unsigned char **, const unsigned char *);
139 static int mklower(int ch);
140
141 int
142 irc_res_init(void)
143 {
144 irc_nscount = 0;
145 memset(irc_nsaddr_list, 0, sizeof(irc_nsaddr_list));
146
147 return parse_resvconf();
148 }
149
150 /* parse_resvconf()
151 *
152 * inputs - NONE
153 * output - -1 if failure 0 if success
154 * side effects - fills in irc_nsaddr_list
155 */
156 static int
157 parse_resvconf(void)
158 {
159 char *p;
160 char *opt;
161 char *arg;
162 char input[MAXLINE];
163 FBFILE *file;
164
165 /* XXX "/etc/resolv.conf" should be from a define in config.h perhaps
166 * for cygwin support etc. this hardcodes it to unix for now -db
167 */
168 if ((file = fbopen("/etc/resolv.conf", "r")) == NULL)
169 return -1;
170
171 while (fbgets(input, sizeof(input), file) != NULL)
172 {
173 /* blow away any newline */
174 if ((p = strpbrk(input, "\r\n")) != NULL)
175 *p = '\0';
176
177 p = input;
178
179 /* skip until something thats not a space is seen */
180 while (IsSpace(*p))
181 ++p;
182
183 /* if at this point, have a '\0' then continue */
184 if (*p == '\0')
185 continue;
186
187 /* Ignore comment lines immediately */
188 if (*p == ';' || *p == '#')
189 continue;
190
191 /* skip until a space is found */
192 opt = p;
193 while (!IsSpace(*p) && *p)
194 ++p;
195
196 if (*p == '\0')
197 continue; /* no arguments?.. ignore this line */
198
199 /* blow away the space character */
200 *p++ = '\0';
201
202 /* skip these spaces that are before the argument */
203 while (IsSpace(*p))
204 ++p;
205
206 /* Now arg should be right where p is pointing */
207 arg = p;
208
209 if ((p = strpbrk(arg, " \t")) != NULL)
210 *p = '\0'; /* take the first word */
211
212 if (irccmp(opt, "nameserver") == 0)
213 add_nameserver(arg);
214 }
215
216 fbclose(file);
217 return 0;
218 }
219
220 /* add_nameserver()
221 *
222 * input - either an IPV4 address in dotted quad
223 * or an IPV6 address in : format
224 * output - NONE
225 * side effects - entry in irc_nsaddr_list is filled in as needed
226 */
227 static void
228 add_nameserver(char *arg)
229 {
230 struct addrinfo hints, *res;
231 /* Done max number of nameservers? */
232 if ((irc_nscount) >= IRCD_MAXNS)
233 return;
234
235 memset(&hints, 0, sizeof(hints));
236 hints.ai_family = PF_UNSPEC;
237 hints.ai_socktype = SOCK_DGRAM;
238 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
239
240 if (getaddrinfo(arg, "domain", &hints, &res))
241 return;
242
243 if (res == NULL)
244 return;
245
246 memcpy(&irc_nsaddr_list[irc_nscount].ss, res->ai_addr, res->ai_addrlen);
247 irc_nsaddr_list[irc_nscount].ss_len = res->ai_addrlen;
248 irc_nscount++;
249 freeaddrinfo(res);
250 }
251
252 /*
253 * Expand compressed domain name 'comp_dn' to full domain name.
254 * 'msg' is a pointer to the begining of the message,
255 * 'eomorig' points to the first location after the message,
256 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
257 * Return size of compressed name or -1 if there was an error.
258 */
259 int
260 irc_dn_expand(const unsigned char *msg, const unsigned char *eom,
261 const unsigned char *src, char *dst, int dstsiz)
262 {
263 int n = irc_ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
264
265 if (n > 0 && dst[0] == '.')
266 dst[0] = '\0';
267 return(n);
268 } /*2*/
269
270 /*
271 * irc_ns_name_uncompress(msg, eom, src, dst, dstsiz)
272 * Expand compressed domain name to presentation format.
273 * return:
274 * Number of bytes read out of `src', or -1 (with errno set).
275 * note:
276 * Root domain returns as "." not "".
277 */
278 static int
279 irc_ns_name_uncompress(const unsigned char *msg, const unsigned char *eom,
280 const unsigned char *src, char *dst, size_t dstsiz)
281 {
282 unsigned char tmp[NS_MAXCDNAME];
283 int n;
284
285 if ((n = irc_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
286 return(-1);
287 if (irc_ns_name_ntop(tmp, dst, dstsiz) == -1)
288 return(-1);
289 return(n);
290 } /*2*/
291
292 /*
293 * irc_ns_name_unpack(msg, eom, src, dst, dstsiz)
294 * Unpack a domain name from a message, source may be compressed.
295 * return:
296 * -1 if it fails, or consumed octets if it succeeds.
297 */
298 static int
299 irc_ns_name_unpack(const unsigned char *msg, const unsigned char *eom,
300 const unsigned char *src, unsigned char *dst,
301 size_t dstsiz)
302 {
303 const unsigned char *srcp, *dstlim;
304 unsigned char *dstp;
305 int n, len, checked, l;
306
307 len = -1;
308 checked = 0;
309 dstp = dst;
310 srcp = src;
311 dstlim = dst + dstsiz;
312 if (srcp < msg || srcp >= eom) {
313 errno = EMSGSIZE;
314 return (-1);
315 }
316 /* Fetch next label in domain name. */
317 while ((n = *srcp++) != 0) {
318 /* Check for indirection. */
319 switch (n & NS_CMPRSFLGS) {
320 case 0:
321 case NS_TYPE_ELT:
322 /* Limit checks. */
323 if ((l = labellen(srcp - 1)) < 0) {
324 errno = EMSGSIZE;
325 return(-1);
326 }
327 if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
328 errno = EMSGSIZE;
329 return (-1);
330 }
331 checked += l + 1;
332 *dstp++ = n;
333 memcpy(dstp, srcp, l);
334 dstp += l;
335 srcp += l;
336 break;
337
338 case NS_CMPRSFLGS:
339 if (srcp >= eom) {
340 errno = EMSGSIZE;
341 return (-1);
342 }
343 if (len < 0)
344 len = srcp - src + 1;
345 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
346 if (srcp < msg || srcp >= eom) { /* Out of range. */
347 errno = EMSGSIZE;
348 return (-1);
349 }
350 checked += 2;
351 /*
352 * Check for loops in the compressed name;
353 * if we've looked at the whole message,
354 * there must be a loop.
355 */
356 if (checked >= eom - msg) {
357 errno = EMSGSIZE;
358 return (-1);
359 }
360 break;
361
362 default:
363 errno = EMSGSIZE;
364 return (-1); /* flag error */
365 }
366 }
367 *dstp = '\0';
368 if (len < 0)
369 len = srcp - src;
370 return (len);
371 } /*2*/
372
373 /*
374 * irc_ns_name_ntop(src, dst, dstsiz)
375 * Convert an encoded domain name to printable ascii as per RFC1035.
376 * return:
377 * Number of bytes written to buffer, or -1 (with errno set)
378 * notes:
379 * The root is returned as "."
380 * All other domains are returned in non absolute form
381 */
382 static int
383 irc_ns_name_ntop(const unsigned char *src, char *dst, size_t dstsiz)
384 {
385 const unsigned char *cp;
386 char *dn, *eom;
387 unsigned char c;
388 unsigned int n;
389 int l;
390
391 cp = src;
392 dn = dst;
393 eom = dst + dstsiz;
394
395 while ((n = *cp++) != 0) {
396 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
397 /* Some kind of compression pointer. */
398 errno = EMSGSIZE;
399 return (-1);
400 }
401 if (dn != dst) {
402 if (dn >= eom) {
403 errno = EMSGSIZE;
404 return (-1);
405 }
406 *dn++ = '.';
407 }
408 if ((l = labellen((cp - 1))) < 0) {
409 errno = EMSGSIZE; /* XXX */
410 return(-1);
411 }
412 if (dn + l >= eom) {
413 errno = EMSGSIZE;
414 return (-1);
415 }
416 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
417 int m;
418
419 if (n != DNS_LABELTYPE_BITSTRING) {
420 /* XXX: labellen should reject this case */
421 errno = EINVAL;
422 return(-1);
423 }
424 if ((m = irc_decode_bitstring(&cp, dn, eom)) < 0)
425 {
426 errno = EMSGSIZE;
427 return(-1);
428 }
429 dn += m;
430 continue;
431 }
432 for ((void)NULL; l > 0; l--) {
433 c = *cp++;
434 if (special(c)) {
435 if (dn + 1 >= eom) {
436 errno = EMSGSIZE;
437 return (-1);
438 }
439 *dn++ = '\\';
440 *dn++ = (char)c;
441 } else if (!printable(c)) {
442 if (dn + 3 >= eom) {
443 errno = EMSGSIZE;
444 return (-1);
445 }
446 *dn++ = '\\';
447 *dn++ = digits[c / 100];
448 *dn++ = digits[(c % 100) / 10];
449 *dn++ = digits[c % 10];
450 } else {
451 if (dn >= eom) {
452 errno = EMSGSIZE;
453 return (-1);
454 }
455 *dn++ = (char)c;
456 }
457 }
458 }
459 if (dn == dst) {
460 if (dn >= eom) {
461 errno = EMSGSIZE;
462 return (-1);
463 }
464 *dn++ = '.';
465 }
466 if (dn >= eom) {
467 errno = EMSGSIZE;
468 return (-1);
469 }
470 *dn++ = '\0';
471 return (dn - dst);
472 } /*2*/
473
474 /*
475 * Skip over a compressed domain name. Return the size or -1.
476 */
477 int
478 irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom) {
479 const unsigned char *saveptr = ptr;
480
481 if (irc_ns_name_skip(&ptr, eom) == -1)
482 return(-1);
483 return(ptr - saveptr);
484 } /*2*/
485
486 /*
487 * ns_name_skip(ptrptr, eom)
488 * Advance *ptrptr to skip over the compressed name it points at.
489 * return:
490 * 0 on success, -1 (with errno set) on failure.
491 */
492 static int
493 irc_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom)
494 {
495 const unsigned char *cp;
496 unsigned int n;
497 int l;
498
499 cp = *ptrptr;
500
501 while (cp < eom && (n = *cp++) != 0)
502 {
503 /* Check for indirection. */
504 switch (n & NS_CMPRSFLGS)
505 {
506 case 0: /* normal case, n == len */
507 cp += n;
508 continue;
509 case NS_TYPE_ELT: /* EDNS0 extended label */
510 if ((l = labellen(cp - 1)) < 0)
511 {
512 errno = EMSGSIZE; /* XXX */
513 return(-1);
514 }
515
516 cp += l;
517 continue;
518 case NS_CMPRSFLGS: /* indirection */
519 cp++;
520 break;
521 default: /* illegal type */
522 errno = EMSGSIZE;
523 return(-1);
524 }
525
526 break;
527 }
528
529 if (cp > eom)
530 {
531 errno = EMSGSIZE;
532 return (-1);
533 }
534
535 *ptrptr = cp;
536 return(0);
537 } /*2*/
538
539 unsigned int
540 irc_ns_get16(const unsigned char *src)
541 {
542 unsigned int dst;
543
544 IRC_NS_GET16(dst, src);
545 return(dst);
546 }
547
548 unsigned long
549 irc_ns_get32(const unsigned char *src)
550 {
551 unsigned long dst;
552
553 IRC_NS_GET32(dst, src);
554 return(dst);
555 }
556
557 void
558 irc_ns_put16(unsigned int src, unsigned char *dst)
559 {
560 IRC_NS_PUT16(src, dst);
561 }
562
563 void
564 irc_ns_put32(unsigned long src, unsigned char *dst)
565 {
566 IRC_NS_PUT32(src, dst);
567 }
568
569 /* From ns_name.c */
570
571 /*
572 * special(ch)
573 * Thinking in noninternationalized USASCII (per the DNS spec),
574 * is this characted special ("in need of quoting") ?
575 * return:
576 * boolean.
577 */
578 static int
579 special(int ch)
580 {
581 switch (ch)
582 {
583 case 0x22: /* '"' */
584 case 0x2E: /* '.' */
585 case 0x3B: /* ';' */
586 case 0x5C: /* '\\' */
587 case 0x28: /* '(' */
588 case 0x29: /* ')' */
589 /* Special modifiers in zone files. */
590 case 0x40: /* '@' */
591 case 0x24: /* '$' */
592 return(1);
593 default:
594 return(0);
595 }
596 } /*2*/
597
598 static int
599 labellen(const unsigned char *lp)
600 {
601 int bitlen;
602 unsigned char l = *lp;
603
604 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS)
605 {
606 /* should be avoided by the caller */
607 return(-1);
608 }
609
610 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT)
611 {
612 if (l == DNS_LABELTYPE_BITSTRING)
613 {
614 if ((bitlen = *(lp + 1)) == 0)
615 bitlen = 256;
616 return((bitlen + 7 ) / 8 + 1);
617 }
618
619 return(-1); /* unknwon ELT */
620 }
621
622 return(l);
623 } /*2*/
624
625
626 /*
627 * printable(ch)
628 * Thinking in noninternationalized USASCII (per the DNS spec),
629 * is this character visible and not a space when printed ?
630 * return:
631 * boolean.
632 */
633 static int
634 printable(int ch)
635 {
636 return(ch > 0x20 && ch < 0x7f);
637 } /*2*/
638
639 static int
640 irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
641 {
642 const unsigned char *cp = *cpp;
643 char *beg = dn, tc;
644 int b, blen, plen;
645
646 if ((blen = (*cp & 0xff)) == 0)
647 blen = 256;
648 plen = (blen + 3) / 4;
649 plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
650 if (dn + plen >= eom)
651 return(-1);
652
653 cp++;
654 dn += sprintf(dn, "\\[x");
655 for (b = blen; b > 7; b -= 8, cp++)
656 dn += sprintf(dn, "%02x", *cp & 0xff);
657 if (b > 4) {
658 tc = *cp++;
659 dn += sprintf(dn, "%02x", tc & (0xff << (8 - b)));
660 } else if (b > 0) {
661 tc = *cp++;
662 dn += sprintf(dn, "%1x",
663 ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
664 }
665 dn += sprintf(dn, "/%d]", blen);
666
667 *cpp = cp;
668 return(dn - beg);
669 } /*2*/
670
671 /*
672 * irc_ns_name_pton(src, dst, dstsiz)
673 * Convert a ascii string into an encoded domain name as per RFC1035.
674 * return:
675 * -1 if it fails
676 * 1 if string was fully qualified
677 * 0 is string was not fully qualified
678 * notes:
679 * Enforces label and domain length limits.
680 */
681 static int
682 irc_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz)
683 {
684 unsigned char *label, *bp, *eom;
685 char *cp;
686 int c, n, escaped, e = 0;
687
688 escaped = 0;
689 bp = dst;
690 eom = dst + dstsiz;
691 label = bp++;
692
693
694 while ((c = *src++) != 0) {
695 if (escaped) {
696 if (c == '[') { /* start a bit string label */
697 if ((cp = strchr(src, ']')) == NULL) {
698 errno = EINVAL; /* ??? */
699 return(-1);
700 }
701 if ((e = irc_encode_bitsring(&src,
702 cp + 2,
703 &label,
704 &bp,
705 eom))
706 != 0) {
707 errno = e;
708 return(-1);
709 }
710 escaped = 0;
711 label = bp++;
712 if ((c = *src++) == 0)
713 goto done;
714 else if (c != '.') {
715 errno = EINVAL;
716 return(-1);
717 }
718 continue;
719 }
720 else if ((cp = strchr(digits, c)) != NULL) {
721 n = (cp - digits) * 100;
722 if ((c = *src++) == 0 ||
723 (cp = strchr(digits, c)) == NULL) {
724 errno = EMSGSIZE;
725 return (-1);
726 }
727 n += (cp - digits) * 10;
728 if ((c = *src++) == 0 ||
729 (cp = strchr(digits, c)) == NULL) {
730 errno = EMSGSIZE;
731 return (-1);
732 }
733 n += (cp - digits);
734 if (n > 255) {
735 errno = EMSGSIZE;
736 return (-1);
737 }
738 c = n;
739 }
740 escaped = 0;
741 } else if (c == '\\') {
742 escaped = 1;
743 continue;
744 } else if (c == '.') {
745 c = (bp - label - 1);
746 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
747 errno = EMSGSIZE;
748 return (-1);
749 }
750 if (label >= eom) {
751 errno = EMSGSIZE;
752 return (-1);
753 }
754 *label = c;
755 /* Fully qualified ? */
756 if (*src == '\0') {
757 if (c != 0) {
758 if (bp >= eom) {
759 errno = EMSGSIZE;
760 return (-1);
761 }
762 *bp++ = '\0';
763 }
764 if ((bp - dst) > NS_MAXCDNAME) {
765 errno = EMSGSIZE;
766 return (-1);
767 }
768 return (1);
769 }
770 if (c == 0 || *src == '.') {
771 errno = EMSGSIZE;
772 return (-1);
773 }
774 label = bp++;
775 continue;
776 }
777 if (bp >= eom) {
778 errno = EMSGSIZE;
779 return (-1);
780 }
781 *bp++ = (unsigned char)c;
782 }
783 c = (bp - label - 1);
784 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
785 errno = EMSGSIZE;
786 return (-1);
787 }
788 done:
789 if (label >= eom) {
790 errno = EMSGSIZE;
791 return (-1);
792 }
793 *label = c;
794 if (c != 0) {
795 if (bp >= eom) {
796 errno = EMSGSIZE;
797 return (-1);
798 }
799 *bp++ = 0;
800 }
801
802 if ((bp - dst) > NS_MAXCDNAME)
803 { /* src too big */
804 errno = EMSGSIZE;
805 return (-1);
806 }
807
808 return (0);
809 } /*2*/
810
811 /*
812 * irc_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
813 * Pack domain name 'domain' into 'comp_dn'.
814 * return:
815 * Size of the compressed name, or -1.
816 * notes:
817 * 'dnptrs' is an array of pointers to previous compressed names.
818 * dnptrs[0] is a pointer to the beginning of the message. The array
819 * ends with NULL.
820 * 'lastdnptr' is a pointer to the end of the array pointed to
821 * by 'dnptrs'.
822 * Side effects:
823 * The list of pointers in dnptrs is updated for labels inserted into
824 * the message as we compress the name. If 'dnptr' is NULL, we don't
825 * try to compress names. If 'lastdnptr' is NULL, we don't update the
826 * list.
827 */
828 static int
829 irc_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz,
830 const unsigned char **dnptrs, const unsigned char **lastdnptr)
831 {
832 unsigned char *dstp;
833 const unsigned char **cpp, **lpp, *eob, *msg;
834 const unsigned char *srcp;
835 int n, l, first = 1;
836
837 srcp = src;
838 dstp = dst;
839 eob = dstp + dstsiz;
840 lpp = cpp = NULL;
841 if (dnptrs != NULL) {
842 if ((msg = *dnptrs++) != NULL) {
843 for (cpp = dnptrs; *cpp != NULL; cpp++)
844 (void)NULL;
845 lpp = cpp; /* end of list to search */
846 }
847 } else
848 msg = NULL;
849
850 /* make sure the domain we are about to add is legal */
851 l = 0;
852 do {
853 int l0;
854
855 n = *srcp;
856 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
857 errno = EMSGSIZE;
858 return (-1);
859 }
860 if ((l0 = labellen(srcp)) < 0) {
861 errno = EINVAL;
862 return(-1);
863 }
864 l += l0 + 1;
865 if (l > NS_MAXCDNAME) {
866 errno = EMSGSIZE;
867 return (-1);
868 }
869 srcp += l0 + 1;
870 } while (n != 0);
871
872 /* from here on we need to reset compression pointer array on error */
873 srcp = src;
874 do {
875 /* Look to see if we can use pointers. */
876 n = *srcp;
877 if (n != 0 && msg != NULL) {
878 l = irc_dn_find(srcp, msg, (const unsigned char * const *)dnptrs,
879 (const unsigned char * const *)lpp);
880 if (l >= 0) {
881 if (dstp + 1 >= eob) {
882 goto cleanup;
883 }
884 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
885 *dstp++ = l % 256;
886 return (dstp - dst);
887 }
888 /* Not found, save it. */
889 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
890 (dstp - msg) < 0x4000 && first) {
891 *cpp++ = dstp;
892 *cpp = NULL;
893 first = 0;
894 }
895 }
896 /* copy label to buffer */
897 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
898 /* Should not happen. */
899 goto cleanup;
900 }
901 n = labellen(srcp);
902 if (dstp + 1 + n >= eob) {
903 goto cleanup;
904 }
905 memcpy(dstp, srcp, n + 1);
906 srcp += n + 1;
907 dstp += n + 1;
908 } while (n != 0);
909
910 if (dstp > eob) {
911 cleanup:
912 if (msg != NULL)
913 *lpp = NULL;
914 errno = EMSGSIZE;
915 return (-1);
916 }
917 return(dstp - dst);
918 } /*2*/
919
920 static int
921 irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz,
922 const unsigned char **dnptrs, const unsigned char **lastdnptr)
923 {
924 unsigned char tmp[NS_MAXCDNAME];
925
926 if (irc_ns_name_pton(src, tmp, sizeof tmp) == -1)
927 return(-1);
928 return(irc_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
929 }
930
931 static int
932 irc_encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
933 unsigned char **dst, const unsigned char *eom)
934 {
935 int afterslash = 0;
936 const char *cp = *bp;
937 unsigned char *tp;
938 char c;
939 const char *beg_blen;
940 char *end_blen = NULL;
941 int value = 0, count = 0, tbcount = 0, blen = 0;
942
943 beg_blen = end_blen = NULL;
944
945 /* a bitstring must contain at least 2 characters */
946 if (end - cp < 2)
947 return(EINVAL);
948
949 /* XXX: currently, only hex strings are supported */
950 if (*cp++ != 'x')
951 return(EINVAL);
952 if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
953 return(EINVAL);
954
955 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
956 switch((c = *cp)) {
957 case ']': /* end of the bitstring */
958 if (afterslash) {
959 if (beg_blen == NULL)
960 return(EINVAL);
961 blen = (int)strtol(beg_blen, &end_blen, 10);
962 if (*end_blen != ']')
963 return(EINVAL);
964 }
965 if (count)
966 *tp++ = ((value << 4) & 0xff);
967 cp++; /* skip ']' */
968 goto done;
969 case '/':
970 afterslash = 1;
971 break;
972 default:
973 if (afterslash) {
974 if (!isdigit(c&0xff))
975 return(EINVAL);
976 if (beg_blen == NULL) {
977
978 if (c == '0') {
979 /* blen never begings with 0 */
980 return(EINVAL);
981 }
982 beg_blen = cp;
983 }
984 } else {
985 if (!isxdigit(c&0xff))
986 return(EINVAL);
987 value <<= 4;
988 value += digitvalue[(int)c];
989 count += 4;
990 tbcount += 4;
991 if (tbcount > 256)
992 return(EINVAL);
993 if (count == 8) {
994 *tp++ = value;
995 count = 0;
996 }
997 }
998 break;
999 }
1000 }
1001 done:
1002 if (cp >= end || tp >= eom)
1003 return(EMSGSIZE);
1004
1005 /*
1006 * bit length validation:
1007 * If a <length> is present, the number of digits in the <bit-data>
1008 * MUST be just sufficient to contain the number of bits specified
1009 * by the <length>. If there are insignificant bits in a final
1010 * hexadecimal or octal digit, they MUST be zero.
1011 * RFC 2673, Section 3.2.
1012 */
1013 if (blen > 0) {
1014 int traillen;
1015
1016 if (((blen + 3) & ~3) != tbcount)
1017 return(EINVAL);
1018 traillen = tbcount - blen; /* between 0 and 3 */
1019 if (((value << (8 - traillen)) & 0xff) != 0)
1020 return(EINVAL);
1021 }
1022 else
1023 blen = tbcount;
1024 if (blen == 256)
1025 blen = 0;
1026
1027 /* encode the type and the significant bit fields */
1028 **labelp = DNS_LABELTYPE_BITSTRING;
1029 **dst = blen;
1030
1031 *bp = cp;
1032 *dst = tp;
1033
1034 return(0);
1035 } /*2*/
1036
1037 /*
1038 * dn_find(domain, msg, dnptrs, lastdnptr)
1039 * Search for the counted-label name in an array of compressed names.
1040 * return:
1041 * offset from msg if found, or -1.
1042 * notes:
1043 * dnptrs is the pointer to the first name on the list,
1044 * not the pointer to the start of the message.
1045 */
1046 static int
1047 irc_dn_find(const unsigned char *domain, const unsigned char *msg,
1048 const unsigned char * const *dnptrs,
1049 const unsigned char * const *lastdnptr)
1050 {
1051 const unsigned char *dn, *cp, *sp;
1052 const unsigned char * const *cpp;
1053 unsigned int n;
1054
1055 for (cpp = dnptrs; cpp < lastdnptr; cpp++)
1056 {
1057 sp = *cpp;
1058 /*
1059 * terminate search on:
1060 * root label
1061 * compression pointer
1062 * unusable offset
1063 */
1064 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
1065 (sp - msg) < 0x4000) {
1066 dn = domain;
1067 cp = sp;
1068 while ((n = *cp++) != 0) {
1069 /*
1070 * check for indirection
1071 */
1072 switch (n & NS_CMPRSFLGS) {
1073 case 0: /* normal case, n == len */
1074 n = labellen(cp - 1); /* XXX */
1075
1076 if (n != *dn++)
1077 goto next;
1078
1079 for ((void)NULL; n > 0; n--)
1080 if (mklower(*dn++) !=
1081 mklower(*cp++))
1082 goto next;
1083 /* Is next root for both ? */
1084 if (*dn == '\0' && *cp == '\0')
1085 return (sp - msg);
1086 if (*dn)
1087 continue;
1088 goto next;
1089 case NS_CMPRSFLGS: /* indirection */
1090 cp = msg + (((n & 0x3f) << 8) | *cp);
1091 break;
1092
1093 default: /* illegal type */
1094 errno = EMSGSIZE;
1095 return (-1);
1096 }
1097 }
1098 next: ;
1099 sp += *sp + 1;
1100 }
1101 }
1102 errno = ENOENT;
1103 return (-1);
1104 } /*2*/
1105
1106 /*
1107 * * Thinking in noninternationalized USASCII (per the DNS spec),
1108 * * convert this character to lower case if it's upper case.
1109 * */
1110 static int
1111 mklower(int ch)
1112 {
1113 if (ch >= 0x41 && ch <= 0x5A)
1114 return(ch + 0x20);
1115
1116 return(ch);
1117 } /*2*/
1118
1119 /* From resolv/mkquery.c */
1120
1121 /*
1122 * Form all types of queries.
1123 * Returns the size of the result or -1.
1124 */
1125 int
1126 irc_res_mkquery(
1127 const char *dname, /* domain name */
1128 int class, int type, /* class and type of query */
1129 unsigned char *buf, /* buffer to put query */
1130 int buflen) /* size of buffer */
1131 {
1132 HEADER *hp;
1133 unsigned char *cp;
1134 int n;
1135 unsigned char *dnptrs[20], **dpp, **lastdnptr;
1136
1137 /*
1138 * Initialize header fields.
1139 */
1140 if ((buf == NULL) || (buflen < HFIXEDSZ))
1141 return (-1);
1142 memset(buf, 0, HFIXEDSZ);
1143 hp = (HEADER *) buf;
1144
1145 hp->id = 0;
1146 hp->opcode = QUERY;
1147 hp->rd = 1; /* recurse */
1148 hp->rcode = NO_ERRORS;
1149 cp = buf + HFIXEDSZ;
1150 buflen -= HFIXEDSZ;
1151 dpp = dnptrs;
1152 *dpp++ = buf;
1153 *dpp++ = NULL;
1154 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
1155
1156 if ((buflen -= QFIXEDSZ) < 0)
1157 return (-1);
1158 if ((n = irc_ns_name_compress(dname, cp, buflen, (const unsigned char **)dnptrs,
1159 (const unsigned char **)lastdnptr)) < 0)
1160 return (-1);
1161
1162 cp += n;
1163 buflen -= n;
1164 IRC_NS_PUT16(type, cp);
1165 IRC_NS_PUT16(class, cp);
1166 hp->qdcount = htons(1);
1167
1168 return (cp - buf);
1169 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision