ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/irc_reslib.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 30104 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


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

Properties

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