ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/reslib.c
Revision: 1346
Committed: Mon Apr 9 17:35:40 2012 UTC (13 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/irc_reslib.c
File size: 29640 byte(s)
Log Message:
- irc_reslib.c: add localhost as default nameserver in case we cannot find
  a suitable entrie in resolv.conf
- irc_res.c:res_ourserver(): no need to test against INADDR_ANY.
  This is a relict of old BIND versions which added INADDR_ANDY as default
  nameserver if no other servers could be found.

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

Properties

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