ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/reslib.c
Revision: 1155
Committed: Tue Aug 9 20:27:45 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/src/irc_reslib.c
File size: 29759 byte(s)
Log Message:
- recreate "trunk"

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 michael 1011 #include "ircd_defs.h"
85 michael 998 #include "irc_res.h"
86     #include "irc_reslib.h"
87 adx 30 #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 knight 31 /* $Id$ */
95 adx 30
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 michael 993 static int irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom);
126 adx 30 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 michael 993 const unsigned char *);
132 adx 30 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 michael 993 static int irc_ns_name_ntop(const unsigned char *, char *, size_t);
138 adx 30 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 michael 996 memset(irc_nsaddr_list, 0, sizeof(irc_nsaddr_list));
146    
147 adx 30 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 michael 912 /* XXX "/etc/resolv.conf" should be from a define in config.h perhaps
166 adx 30 * 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 michael 995 if (irccmp(opt, "nameserver") == 0)
213 adx 30 add_nameserver(arg);
214     }
215    
216     fbclose(file);
217 michael 708 return 0;
218 adx 30 }
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 michael 1123 if (getaddrinfo(arg, "domain", &hints, &res))
241 adx 30 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 michael 1123 freeaddrinfo(res);
250 adx 30 }
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 michael 993 } /*2*/
269 adx 30
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 michael 993 if (irc_ns_name_ntop(tmp, dst, dstsiz) == -1)
288 adx 30 return(-1);
289     return(n);
290 michael 993 } /*2*/
291    
292 adx 30 /*
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 michael 993 } /*2*/
372 adx 30
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 michael 993 irc_ns_name_ntop(const unsigned char *src, char *dst, size_t dstsiz)
384 adx 30 {
385 michael 993 const unsigned char *cp;
386 adx 30 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 michael 993 if ((l = labellen((cp - 1))) < 0) {
409 adx 30 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 michael 993 } /*2*/
473 adx 30
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 michael 993 } /*2*/
485 adx 30
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 michael 993 } /*2*/
538 adx 30
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 michael 993 } /*2*/
597 adx 30
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 michael 993 } /*2*/
624 adx 30
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 michael 993 } /*2*/
638 adx 30
639     static int
640 michael 993 irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
641 adx 30 {
642 michael 993 const unsigned char *cp = *cpp;
643 adx 30 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 michael 993 } /*2*/
670 adx 30
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 michael 993 eom))
706 adx 30 != 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 michael 993 } /*2*/
810 adx 30
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 michael 993 } /*2*/
919 adx 30
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 michael 993 unsigned char **dst, const unsigned char *eom)
934 adx 30 {
935     int afterslash = 0;
936     const char *cp = *bp;
937 michael 993 unsigned char *tp;
938     char c;
939 adx 30 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 michael 993 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
956 adx 30 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 michael 993 *dst = tp;
1033 adx 30
1034     return(0);
1035 michael 993 } /*2*/
1036 adx 30
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 michael 993 } /*2*/
1105 adx 30
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 michael 993 } /*2*/
1118 adx 30
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 michael 993 if ((n = irc_ns_name_compress(dname, cp, buflen, (const unsigned char **)dnptrs,
1159     (const unsigned char **)lastdnptr)) < 0)
1160 adx 30 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