ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/reslib.c
Revision: 5875
Committed: Wed Apr 29 11:09:28 2015 UTC (10 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 29571 byte(s)
Log Message:
- Style corrections; removed trailing whitespaces

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

Properties

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