ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/reslib.c
Revision: 6958
Committed: Thu Dec 17 11:52:08 2015 UTC (9 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 29575 byte(s)
Log Message:
- Move IRCD_MAXNS to reslib.h, rename it to RESLIB_MAXNS, and increase it to 8

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 * 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 *
17 * 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 *
33 * 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 *
40 * 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 /* Original copyright ISC as above.
68 * 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 *
76 * - Dianora
77 */
78
79 #include "stdinc.h"
80 #include "ircd_defs.h"
81 #include "res.h"
82 #include "reslib.h"
83 #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 /* $Id$ */
90
91 struct irc_ssaddr irc_nsaddr_list[RESLIB_MAXNS];
92 unsigned int irc_nscount = 0;
93
94 static const char digits[] = "0123456789";
95 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 static int irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom);
118 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 static int irc_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **,
123 const unsigned char *);
124 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 static int irc_ns_name_ntop(const unsigned char *, char *, size_t);
130 static int irc_ns_name_skip(const unsigned char **, const unsigned char *);
131 static int mklower(int ch);
132
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 {
143 struct addrinfo hints, *res;
144
145 /* Done max number of nameservers? */
146 if (irc_nscount >= RESLIB_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 }
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 static void
172 parse_resvconf(void)
173 {
174 char *p;
175 char *opt;
176 char *arg;
177 char input[MAXLINE];
178 FILE *file;
179
180 /* XXX "/etc/resolv.conf" should be from a define in config.h perhaps
181 * for cygwin support etc. this hardcodes it to unix for now -db
182 */
183 if ((file = fopen("/etc/resolv.conf", "r")) == NULL)
184 return;
185
186 while (fgets(input, sizeof(input), file))
187 {
188 /* blow away any newline */
189 if ((p = strpbrk(input, "\r\n")))
190 *p = '\0';
191
192 p = input;
193
194 /* skip until something thats not a space is seen */
195 while (IsSpace(*p))
196 ++p;
197
198 /* if at this point, have a '\0' then continue */
199 if (*p == '\0')
200 continue;
201
202 /* Ignore comment lines immediately */
203 if (*p == ';' || *p == '#')
204 continue;
205
206 /* skip until a space is found */
207 opt = p;
208 while (!IsSpace(*p) && *p)
209 ++p;
210
211 if (*p == '\0')
212 continue; /* no arguments?.. ignore this line */
213
214 /* blow away the space character */
215 *p++ = '\0';
216
217 /* skip these spaces that are before the argument */
218 while (IsSpace(*p))
219 ++p;
220
221 /* Now arg should be right where p is pointing */
222 arg = p;
223
224 if ((p = strpbrk(arg, " \t")))
225 *p = '\0'; /* take the first word */
226
227 if (!strcasecmp(opt, "nameserver"))
228 add_nameserver(arg);
229 }
230
231 fclose(file);
232 }
233
234 void
235 irc_res_init(void)
236 {
237 irc_nscount = 0;
238 memset(irc_nsaddr_list, 0, sizeof(irc_nsaddr_list));
239
240 parse_resvconf();
241
242 if (!irc_nscount)
243 add_nameserver("127.0.0.1");
244 }
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 return n;
262 }
263
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 return -1;
281 if (irc_ns_name_ntop(tmp, dst, dstsiz) == -1)
282 return -1;
283 return n;
284 }
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
307 if (srcp < msg || srcp >= eom)
308 {
309 errno = EMSGSIZE;
310 return -1;
311 }
312
313 /* 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
328 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 {
355 /* 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 /*
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 irc_ns_name_ntop(const unsigned char *src, char *dst, size_t dstsiz)
400 {
401 const unsigned char *cp;
402 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 if ((l = labellen((cp - 1))) < 0) {
425 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 dn += m;
446 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 } /*2*/
489
490 /*
491 * Skip over a compressed domain name. Return the size or -1.
492 */
493 int
494 irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom)
495 {
496 const unsigned char *saveptr = ptr;
497
498 if (irc_ns_name_skip(&ptr, eom) == -1)
499 return -1;
500 return ptr - saveptr;
501 }
502
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 case 0: /* Normal case, n == len */
524 cp += n;
525 continue;
526 case NS_TYPE_ELT: /* EDNS0 extended label */
527 if ((l = labellen(cp - 1)) < 0)
528 {
529 errno = EMSGSIZE; /* XXX */
530 return -1;
531 }
532
533 cp += l;
534 continue;
535 case NS_CMPRSFLGS: /* Indirection */
536 cp++;
537 break;
538 default: /* Illegal type */
539 errno = EMSGSIZE;
540 return -1;
541 }
542
543 break;
544 }
545
546 if (cp > eom)
547 {
548 errno = EMSGSIZE;
549 return -1;
550 }
551
552 *ptrptr = cp;
553 return 0;
554 }
555
556 unsigned int
557 irc_ns_get16(const unsigned char *src)
558 {
559 unsigned int dst;
560
561 IRC_NS_GET16(dst, src);
562 return dst;
563 }
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 return dst;
572 }
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 case 0x22: /* '"' */
601 case 0x2E: /* '.' */
602 case 0x3B: /* ';' */
603 case 0x5C: /* '\\' */
604 case 0x28: /* '(' */
605 case 0x29: /* ')' */
606 /* Special modifiers in zone files. */
607 case 0x40: /* '@' */
608 case 0x24: /* '$' */
609 return 1;
610 default:
611 return 0;
612 }
613 }
614
615 static int
616 labellen(const unsigned char *lp)
617 {
618 int bitlen;
619 unsigned char l = *lp;
620
621 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS)
622 {
623 /* Should be avoided by the caller */
624 return -1;
625 }
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 return (bitlen + 7 ) / 8 + 1;
634 }
635
636 return -1; /* Unknwon ELT */
637 }
638
639 return l;
640 }
641
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 return ch > 0x20 && ch < 0x7f;
654 }
655
656 static int
657 irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
658 {
659 const unsigned char *cp = *cpp;
660 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 } /*2*/
687
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 eom))
723 != 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 } /*2*/
827
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
859 if (dnptrs != NULL)
860 {
861 if ((msg = *dnptrs++))
862 {
863 for (cpp = dnptrs; *cpp != NULL; cpp++)
864 ;
865 lpp = cpp; /* End of list to search */
866 }
867 }
868 else
869 msg = NULL;
870
871 /* Make sure the domain we are about to add is legal */
872 l = 0;
873 do
874 {
875 int l0;
876
877 n = *srcp;
878 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS)
879 {
880 errno = EMSGSIZE;
881 return -1;
882 }
883
884 if ((l0 = labellen(srcp)) < 0)
885 {
886 errno = EINVAL;
887 return -1;
888 }
889
890 l += l0 + 1;
891 if (l > NS_MAXCDNAME)
892 {
893 errno = EMSGSIZE;
894 return -1;
895 }
896
897 srcp += l0 + 1;
898 } while (n != 0);
899
900 /* From here on we need to reset compression pointer array on error */
901 srcp = src;
902 do
903 {
904 /* Look to see if we can use pointers. */
905 n = *srcp;
906
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 goto cleanup;
916
917 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
918 *dstp++ = l % 256;
919 return dstp - dst;
920 }
921
922 /* Not found, save it. */
923 if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - msg) < 0x4000 && first)
924 {
925 *cpp++ = dstp;
926 *cpp = NULL;
927 first = 0;
928 }
929 }
930
931 /* Copy label to buffer */
932 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS)
933 goto cleanup; /* Should not happen. */
934
935 n = labellen(srcp);
936 if (dstp + 1 + n >= eob)
937 goto cleanup;
938
939 memcpy(dstp, srcp, n + 1);
940 srcp += n + 1;
941 dstp += n + 1;
942 } while (n != 0);
943
944 if (dstp > eob)
945 {
946 cleanup:
947 if (msg != NULL)
948 *lpp = NULL;
949 errno = EMSGSIZE;
950 return -1;
951 }
952
953 return dstp - dst;
954 }
955
956 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 return -1;
964 return irc_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
965 }
966
967 static int
968 irc_encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
969 unsigned char **dst, const unsigned char *eom)
970 {
971 int afterslash = 0;
972 const char *cp = *bp;
973 unsigned char *tp;
974 char c;
975 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 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
992 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 *dst = tp;
1069
1070 return(0);
1071 } /*2*/
1072
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 } /*2*/
1141
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 mklower(int ch)
1148 {
1149 if (ch >= 0x41 && ch <= 0x5A)
1150 return(ch + 0x20);
1151
1152 return(ch);
1153 } /*2*/
1154
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 const unsigned char *dnptrs[20], **dpp, **lastdnptr;
1172
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 if ((n = irc_ns_name_compress(dname, cp, buflen, dnptrs,
1195 lastdnptr)) < 0)
1196 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