ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/irc_reslib.c
Revision: 33
Committed: Sun Oct 2 20:50:00 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
Original Path: ircd-hybrid/src/irc_reslib.c
File size: 30104 byte(s)
Log Message:
- svn:keywords

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

Properties

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