ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/irc_reslib.c
Revision: 2611
Committed: Thu Nov 28 19:20:43 2013 UTC (11 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 29401 byte(s)
Log Message:
- src/irc_reslib.c: removed advertising clause

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

Properties

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