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