ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/irc_reslib.c
Revision: 912
Committed: Wed Nov 7 22:47:44 2007 UTC (16 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 30131 byte(s)
Log Message:
- Implemented libtool-ltdl. Only shared modules are supported currently
- Several build fixes and cleanups. ircd now builds and runs without any problems
- Added back all files to SVN that are needed to built the daemon
  I really don't want to force other people that want to test the snapshots
  or svn versions to install yyacc, lex, automake, autoconf and libtool...
  No problem having required files in svn
- Removed some automake maintainer stuff which is kinda useless for us

File Contents

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

Properties

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