ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/irc_reslib.c
Revision: 1325
Committed: Sat Mar 31 10:29:02 2012 UTC (12 years ago) by michael
Content type: text/x-csrc
File size: 29692 byte(s)
Log Message:
- Get rid of fileio.c. Replace some ircsprintf() with snprintf() while on it

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

Properties

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