ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/reslib.c
Revision: 708
Committed: Fri Jul 7 08:56:45 2006 UTC (19 years, 1 month ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/irc_reslib.c
File size: 30130 byte(s)
Log Message:
- Applied nenolod's parse_resvconf() fix

File Contents

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

Properties

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