ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/reslib.c
Revision: 7504
Committed: Fri Mar 25 18:08:30 2016 UTC (8 years ago) by michael
Content type: text/x-csrc
File size: 29543 byte(s)
Log Message:
- reslib.c:add_nameserver(): remove useless test on 'res'

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

Properties

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