]> git.saurik.com Git - apple/libresolv.git/blob - res_init.c
0057cbb2f5ea10f935c4cea39ca6934a1859e999
[apple/libresolv.git] / res_init.c
1 /*
2 * Copyright (c) 1985, 1989, 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 #if defined(LIBC_SCCS) && !defined(lint)
72 static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
73 static const char rcsid[] = "$Id: res_init.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
74 #endif /* LIBC_SCCS and not lint */
75
76 #ifndef __APPLE__
77 #include "port_before.h"
78 #endif
79
80 #include <sys/types.h>
81 #include <sys/param.h>
82 #include <sys/socket.h>
83 #include <sys/time.h>
84
85 #include <netinet/in.h>
86 #include <arpa/inet.h>
87 #include <arpa/nameser.h>
88
89 #include <ctype.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <unistd.h>
94 #include <netdb.h>
95 #ifdef __APPLE__
96 #include <fcntl.h>
97 #include <dnsinfo.h>
98 #endif
99
100 #ifndef __APPLE__
101 #include "port_after.h"
102 #endif
103
104 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
105 #include <resolv.h>
106
107 #include "res_private.h"
108
109 /* Options. Should all be left alone. */
110 #define RESOLVSORT
111 #define DEBUG
112
113 static void res_setoptions __P((res_state, const char *, const char *));
114 extern res_state res_state_new();
115
116 #ifdef RESOLVSORT
117 static const char sort_mask[] = "/&";
118 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
119 static u_int32_t net_mask __P((struct in_addr));
120 #endif
121
122 #if !defined(isascii) /* XXX - could be a function */
123 # define isascii(c) (!(c & 0200))
124 #endif
125
126 #define INET_NTOP_AF_INET_OFFSET 4
127 #define INET_NTOP_AF_INET6_OFFSET 8
128
129 /*
130 * Resolver state default settings.
131 */
132
133 res_state
134 res_build_start(res_state x)
135 {
136 res_state res;
137 int rf;
138
139 res = NULL;
140
141 if (x == NULL)
142 {
143 res = res_state_new();
144 }
145 else
146 {
147 if ((x->options & RES_INIT) != 0) res_ndestroy(x);
148 res = x;
149 }
150
151 if (res == NULL) return NULL;
152
153 /* res_ndestroy frees _u._ext.ext so we create a new one if necessary */
154 if (res->_u._ext.ext == NULL) res->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
155
156 /* make sure version is set */
157 res->_pad = 9;
158
159 res->retry = RES_DFLRETRY;
160 res->options = RES_DEFAULT;
161
162 rf = open("/dev/random", O_RDONLY, 0);
163 read(rf, &(res->id), 2);
164 close(rf);
165
166 res->ndots = 1;
167 res->_vcsock = -1;
168
169 if (res->_u._ext.ext != NULL)
170 {
171 strcpy(res->_u._ext.ext->nsuffix, "ip6.arpa");
172 strcpy(res->_u._ext.ext->nsuffix2, "ip6.int");
173 strcpy(res->_u._ext.ext->bsuffix, "ip6.arpa");
174 }
175
176 return res;
177 }
178
179 int
180 res_build_finish(res_state res, uint32_t timeout, uint16_t port)
181 {
182 if (res == NULL) return -1;
183
184 if (res->nscount == 0)
185 {
186 #ifdef USELOOPBACK
187 res->nsaddr_list[0].sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
188 #else
189 res->nsaddr_list[0].sin_addr.s_addr = INADDR_ANY;
190 #endif
191
192 res->nsaddr_list[0].sin_family = AF_INET;
193 res->nsaddr_list[0].sin_port = htons(port);
194 #ifdef HAVE_SA_LEN
195 res->nsaddr_list[0].sin_len = sizeof(struct sockaddr_in);
196 #endif
197
198 res->nscount = 1;
199
200 /*
201 * Force loopback queries to use TCP
202 * so we don't take a timeout if named isn't running.
203 */
204 res->options |= RES_USEVC;
205 }
206
207 if (timeout == 0) res->retrans = RES_MAXRETRANS;
208 else res->retrans = timeout;
209
210 res->options |= RES_INIT;
211 return 0;
212 }
213
214 int
215 res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask)
216 {
217 uint32_t n;
218
219 if (res == NULL) return -1;
220
221 n = res->nsort;
222 if (n >= MAXRESOLVSORT) return -1;
223
224 res->sort_list[n].addr = addr;
225 res->sort_list[n].mask = mask.s_addr;
226 n++;
227 res->nsort = n;
228
229 return 0;
230 }
231
232 char *
233 res_next_word(char **p)
234 {
235 char *s, *x;
236
237 if (p == NULL) return NULL;
238 if (*p == NULL) return NULL;
239
240 s = *p;
241
242 /* Skip leading white space */
243 while ((*s == ' ') || (*s == '\t') || (*s == '\n')) s++;
244 *p = s;
245
246 if (*s == '\0') return NULL;
247
248 /* Find end of word */
249 x = s;
250 while ((*x != ' ') && (*x != '\t') && (*x != '\n') && (*x != '\0')) x++;
251 if (*x != '\0')
252 {
253 *x = '\0';
254 x++;
255 }
256
257 *p = x;
258
259 if (s == x) return NULL;
260 return s;
261 }
262
263 int
264 res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val)
265 {
266 int32_t dotcount, semicount, status;
267 int32_t ival, len;
268 char *p, *lastdot;
269 uint16_t aport;
270 struct in_addr addr4, mask;
271 struct sockaddr_in sin4;
272 struct in6_addr addr6;
273 struct sockaddr_in6 sin6;
274
275 if (res == NULL) return -1;
276
277 if (!strcmp(key, "domain"))
278 {
279 strncpy(res->defdname, val, sizeof(res->defdname) - 1);
280 res->defdname[sizeof(res->defdname) - 1] = '\0';
281 return 0;
282 }
283
284 else if (!strcmp(key, "search"))
285 {
286 len = strlen(val) + 1;
287 ival = sizeof(res->defdname);
288 p = res->defdname;
289
290 if ((*nsrch) == 0)
291 {
292 memset(res->defdname, 0, sizeof(res->defdname));
293 }
294 else
295 {
296 p = res->dnsrch[*nsrch - 1];
297 for (; (ival > 0) && (*p != '\0'); ival--) p++;
298 if (*p == '\0') p++;
299 }
300
301 if (len > ival) return -1;
302
303 memcpy(p, val, len);
304 res->dnsrch[*nsrch] = p;
305 *nsrch = *nsrch + 1;
306 return 0;
307 }
308
309 else if (!strcmp(key, "nameserver"))
310 {
311 dotcount = 0;
312 semicount = 0;
313 lastdot = NULL;
314 aport = port;
315
316 for (p = val; *p != '\0'; p++)
317 {
318 if (*p == ':') semicount++;
319 else if (*p == '.')
320 {
321 dotcount++;
322 lastdot = p;
323 }
324 }
325
326 if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL)))
327 {
328 aport = atoi(lastdot + 1);
329 if (aport == 0) aport = port;
330 *lastdot = '\0';
331 }
332
333 memset(&addr4, 0, sizeof(struct in_addr));
334 memset(&sin4, 0, sizeof(struct sockaddr_in));
335
336 memset(&addr6, 0, sizeof(struct in6_addr));
337 memset(&sin6, 0, sizeof(struct sockaddr_in6));
338
339 status = inet_pton(AF_INET6, val, &addr6);
340 if (status == 1)
341 {
342 sin6.sin6_addr = addr6;
343 sin6.sin6_family = AF_INET6;
344 sin6.sin6_port = htons(aport);
345 sin6.sin6_len = sizeof(struct sockaddr_in6);
346 if (res->_u._ext.ext != NULL)
347 {
348 memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin6, sizeof(struct sockaddr_in6));
349 }
350 res->nsaddr_list[res->nscount].sin_family = 0;
351 res->nscount++;
352 }
353 else
354 {
355 status = inet_pton(AF_INET, val, &addr4);
356 if (status == 1)
357 {
358 sin4.sin_addr = addr4;
359 sin4.sin_family = AF_INET;
360 sin4.sin_port = htons(aport);
361 sin4.sin_len = sizeof(struct sockaddr_in);
362 if (res->_u._ext.ext != NULL)
363 {
364 memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin4, sizeof(struct sockaddr_in));
365 }
366 memcpy(&(res->nsaddr_list[res->nscount]), &sin4, sizeof(struct sockaddr_in));
367 res->nscount++;
368 }
369 }
370
371 return 0;
372 }
373
374 else if (!strcmp(key, "sortlist"))
375 {
376 p = strchr(val, '/');
377
378 if (p != NULL)
379 {
380 *p = '\0';
381 p++;
382 }
383
384 /* we use inet_aton rather than inet_pton to be compatible with res_init() */
385 status = inet_aton(val, &addr4);
386 if (status == 0) return -1;
387
388 status = 0;
389 if (p != NULL) status = inet_aton(p, &mask);
390 if (status == 0)
391 {
392 ival = ntohl(addr4.s_addr);
393
394 if (IN_CLASSA(ival)) mask.s_addr = htonl(IN_CLASSA_NET);
395 else if (IN_CLASSB(ival)) mask.s_addr = htonl(IN_CLASSB_NET);
396 else mask.s_addr = htonl(IN_CLASSC_NET);
397 }
398
399 return res_build_sortlist(res, addr4, mask);
400 }
401
402 else if (!strcmp(key, "ndots"))
403 {
404 ival = atoi(val);
405 if (ival < 0) ival = 0;
406 if (ival > RES_MAXNDOTS) ival = RES_MAXNDOTS;
407 res->ndots = ival;
408 return 0;
409 }
410
411 else if (!strcmp(key, "nibble"))
412 {
413 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
414 if (res->_u._ext.ext == NULL) return -1;
415 strcpy(res->_u._ext.ext->nsuffix, val);
416 return 0;
417 }
418
419 else if (!strcmp(key, "nibble2"))
420 {
421 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
422 if (res->_u._ext.ext == NULL) return -1;
423 strcpy(res->_u._ext.ext->nsuffix2, val);
424 return 0;
425 }
426
427 else if (!strcmp(key, "bitstring"))
428 {
429 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
430 if (res->_u._ext.ext == NULL) return -1;
431 strcpy(res->_u._ext.ext->bsuffix, val);
432 return 0;
433 }
434
435 else if (!strcmp(key, "attempts"))
436 {
437 ival = atoi(val);
438 if (ival < 0) ival = 0;
439 if (ival > RES_MAXRETRY) ival = RES_MAXRETRY;
440 res->retry = ival;
441 return 0;
442 }
443
444 else if (!strcmp(key, "v6revmode"))
445 {
446 if (!strcmp(val, "single")) res->options |= RES_NO_NIBBLE2;
447 else if (!strcmp(val, "both")) res->options &= ~RES_NO_NIBBLE2;
448 return 0;
449 }
450
451 else if (!strcmp(key, "debug"))
452 {
453 res->options |= RES_DEBUG;
454 return 0;
455 }
456
457 else if (!strcmp(key, "no_tld_query"))
458 {
459 res->options |= RES_NOTLDQUERY;
460 return 0;
461 }
462
463 else if (!strcmp(key, "inet6"))
464 {
465 res->options |= RES_USE_INET6;
466 return 0;
467 }
468
469 else if (!strcmp(key, "rotate"))
470 {
471 res->options |= RES_ROTATE;
472 return 0;
473 }
474
475 else if (!strcmp(key, "no-check-names"))
476 {
477 res->options |= RES_NOCHECKNAME;
478 return 0;
479 }
480
481 #ifdef RES_USE_EDNS0
482 else if (!strcmp(key, "edns0"))
483 {
484 res->options |= RES_USE_EDNS0;
485 return 0;
486 }
487 #endif
488
489 else if (!strcmp(key, "a6"))
490 {
491 res->options |= RES_USE_A6;
492 return 0;
493 }
494
495 else if (!strcmp(key, "dname"))
496 {
497 res->options |= RES_USE_DNAME;
498 return 0;
499 }
500
501 return -1;
502 }
503
504 /*
505 * Set up default settings. If the configuration file exist, the values
506 * there will have precedence. Otherwise, the server address is set to
507 * INADDR_ANY and the default domain name comes from the gethostname().
508 *
509 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
510 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
511 * since it was noted that INADDR_ANY actually meant ``the first interface
512 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
513 * it had to be "up" in order for you to reach your own name server. It
514 * was later decided that since the recommended practice is to always
515 * install local static routes through 127.0.0.1 for all your network
516 * interfaces, that we could solve this problem without a code change.
517 *
518 * The configuration file should always be used, since it is the only way
519 * to specify a default domain. If you are running a server on your local
520 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
521 * in the configuration file.
522 *
523 * Return 0 if completes successfully, -1 on error
524 */
525
526 int
527 res_vinit_from_file(res_state statp, int preinit, char *resconf_file)
528 {
529 register FILE *fp;
530 register char *cp, **pp;
531 register int n;
532 char buf[BUFSIZ];
533 int nserv = 0; /* number of nameserver records read from file */
534 int haveenv = 0;
535 int havesearch = 0;
536 int isresdefault = 0;
537 unsigned short port; /* HOST BYTE ORDER */
538 unsigned int i, total_timeout;
539 #ifdef RESOLVSORT
540 int nsort = 0;
541 char *net;
542 #endif
543 int dots;
544
545 port = NS_DEFAULTPORT;
546 total_timeout = 0;
547
548 if (!preinit)
549 {
550 statp->retrans = RES_TIMEOUT;
551 statp->retry = RES_DFLRETRY;
552 statp->options = RES_DEFAULT;
553 statp->id = res_randomid();
554 }
555
556 if ((statp->options & RES_INIT) != 0) res_ndestroy(statp);
557
558 /* N.B. we allocate a new statp->_u._ext.ext below */
559
560 /* make sure version is set */
561 statp->_pad = 9;
562
563 statp->nscount = 0;
564
565 if ((resconf_file == NULL) || (!strcmp(resconf_file, _PATH_RESCONF)))
566 {
567 isresdefault = 1;
568
569 #ifdef USELOOPBACK
570 statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
571 #else
572 statp->nsaddr.sin_addr.s_addr = INADDR_ANY;
573 #endif
574 statp->nsaddr.sin_family = AF_INET;
575 statp->nsaddr.sin_port = htons(NS_DEFAULTPORT);
576 #ifdef HAVE_SA_LEN
577 statp->nsaddr.sin_len = sizeof(struct sockaddr_in);
578 #endif
579 statp->nscount = 1;
580
581 /*
582 * Force loopback queries to use TCP
583 * so we don't take a timeout if named isn't running.
584 */
585 statp->options |= RES_USEVC;
586 }
587
588 statp->ndots = 1;
589 statp->pfcode = 0;
590 statp->_vcsock = -1;
591 statp->_flags = 0;
592 statp->qhook = NULL;
593 statp->rhook = NULL;
594
595 statp->_u._ext.nscount = 0;
596 statp->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
597
598 if (statp->_u._ext.ext != NULL)
599 {
600 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
601 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
602 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
603 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
604 strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa");
605 }
606
607 #ifdef RESOLVSORT
608 statp->nsort = 0;
609 #endif
610
611 /* Allow user to override the local domain definition */
612 cp = getenv("LOCALDOMAIN");
613 if ((cp != NULL) && (isresdefault != 0))
614 {
615 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
616 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
617 haveenv++;
618
619 /*
620 * Set search list to be blank-separated strings
621 * from rest of env value. Permits users of LOCALDOMAIN
622 * to still have a search list, and anyone to set the
623 * one that they want to use as an individual (even more
624 * important now that the rfc1535 stuff restricts searches)
625 */
626 cp = statp->defdname;
627 pp = statp->dnsrch;
628 *pp++ = cp;
629 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
630 {
631 if (*cp == '\n') break;
632 else if (*cp == ' ' || *cp == '\t')
633 {
634 *cp = 0;
635 n = 1;
636 }
637 else if (n != 0)
638 {
639 *pp++ = cp;
640 n = 0;
641 havesearch = 1;
642 }
643 }
644
645 /* null terminate last domain if there are excess */
646 while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) cp++;
647 *cp = '\0';
648 *pp++ = 0;
649 }
650
651 #define MATCH(line, name) \
652 (!strncmp(line, name, sizeof(name) - 1) && \
653 (line[sizeof(name) - 1] == ' ' || \
654 line[sizeof(name) - 1] == '\t'))
655
656 if (resconf_file == NULL) resconf_file = _PATH_RESCONF;
657
658 if ((fp = fopen(resconf_file, "r")) != NULL)
659 {
660 /* look for port number */
661 while (fgets(buf, sizeof(buf), fp) != NULL)
662 {
663 /* skip comments */
664 if (*buf == ';' || *buf == '#') continue;
665
666 /* read default domain name */
667 if (MATCH(buf, "port"))
668 {
669 cp = buf + sizeof("port") - 1;
670 while (*cp == ' ' || *cp == '\t') cp++;
671 if ((*cp == '\0') || (*cp == '\n')) continue;
672 port = atoi(cp);
673 break;
674 }
675 }
676 fclose(fp);
677 }
678
679 if ((fp = fopen(resconf_file, "r")) != NULL)
680 {
681 /* read the config file */
682 while (fgets(buf, sizeof(buf), fp) != NULL)
683 {
684 /* skip comments */
685 if ((*buf == ';') || (*buf == '#')) continue;
686
687 /* read default domain name */
688 if (MATCH(buf, "domain"))
689 {
690 /* skip if have from environ */
691 if (haveenv) continue;
692
693 cp = buf + sizeof("domain") - 1;
694 while ((*cp == ' ') || (*cp == '\t')) cp++;
695 if ((*cp == '\0') || (*cp == '\n')) continue;
696
697 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
698 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
699 cp = strpbrk(statp->defdname, " \t\n");
700 if (cp != NULL) *cp = '\0';
701 havesearch = 0;
702 continue;
703 }
704
705 /* set search list */
706 if (MATCH(buf, "search"))
707 {
708 /* skip if have from environ */
709 if (haveenv) continue;
710
711 cp = buf + sizeof("search") - 1;
712 while ((*cp == ' ') || (*cp == '\t')) cp++;
713 if ((*cp == '\0') || (*cp == '\n')) continue;
714
715 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
716 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
717 cp = strchr(statp->defdname, '\n');
718 if (cp != NULL) *cp = '\0';
719
720 /*
721 * Set search list to be blank-separated strings
722 * on rest of line.
723 */
724 cp = statp->defdname;
725 pp = statp->dnsrch;
726 *pp++ = cp;
727 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
728 {
729 if ((*cp == ' ') || (*cp == '\t'))
730 {
731 *cp = 0;
732 n = 1;
733 }
734 else if (n != 0)
735 {
736 *pp++ = cp;
737 n = 0;
738 }
739 }
740
741 /* null terminate last domain if there are excess */
742 while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t')) cp++;
743 *cp = '\0';
744 *pp++ = 0;
745 havesearch = 1;
746 continue;
747 }
748
749 /* read nameservers to query */
750 if (MATCH(buf, "nameserver") && (nserv < MAXNS))
751 {
752 #ifndef __APPLE__
753 struct addrinfo hints, *ai;
754 #endif
755 int dotcount, semicount, status;
756 struct in_addr addr4;
757 struct sockaddr_in sin4;
758 struct in6_addr addr6;
759 struct sockaddr_in6 sin6;
760 unsigned short aport; /* HOST BYTE ORDER */
761 char *lastdot, *checkp;
762 char sbuf[NI_MAXSERV];
763 #ifndef __APPLE__
764 const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]);
765 #endif
766
767 cp = buf + sizeof("nameserver") - 1;
768 while ((*cp == ' ') || (*cp == '\t')) cp++;
769 cp[strcspn(cp, ";# \t\n")] = '\0';
770 if ((*cp != '\0') && (*cp != '\n'))
771 {
772 #ifndef __APPLE__
773 memset(&hints, 0, sizeof(hints));
774 hints.ai_family = PF_UNSPEC;
775 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
776 hints.ai_flags = AI_NUMERICHOST;
777 #endif
778 dotcount = 0;
779 semicount = 0;
780 lastdot = NULL;
781 aport = port;
782
783 for (checkp = cp; *checkp != '\0'; checkp++)
784 {
785 if (*checkp == ':') semicount++;
786 else if (*checkp == '.')
787 {
788 dotcount++;
789 lastdot = checkp;
790 }
791 }
792
793 if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL)))
794 {
795 aport = atoi(lastdot + 1);
796 if (aport == 0) aport = port;
797 *lastdot = '\0';
798 }
799
800 sprintf(sbuf, "%u", aport);
801
802 #ifdef __APPLE__
803 memset(&addr4, 0, sizeof(struct in_addr));
804 memset(&sin4, 0, sizeof(struct sockaddr_in));
805
806 memset(&addr6, 0, sizeof(struct in6_addr));
807 memset(&sin6, 0, sizeof(struct sockaddr_in6));
808
809 status = inet_pton(AF_INET6, cp, &addr6);
810 if (status == 1)
811 {
812 sin6.sin6_addr = addr6;
813 sin6.sin6_family = AF_INET6;
814 sin6.sin6_port = htons(aport);
815 sin6.sin6_len = sizeof(struct sockaddr_in6);
816 if (statp->_u._ext.ext != NULL)
817 {
818 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin6, sizeof(struct sockaddr_in6));
819 }
820 statp->nsaddr_list[nserv].sin_family = 0;
821 nserv++;
822 }
823 else
824 {
825 status = inet_pton(AF_INET, cp, &addr4);
826 if (status == 1)
827 {
828 sin4.sin_addr = addr4;
829 sin4.sin_family = AF_INET;
830 sin4.sin_port = htons(port);
831 sin4.sin_len = sizeof(struct sockaddr_in);
832 if (statp->_u._ext.ext != NULL)
833 {
834 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin4, sizeof(struct sockaddr_in));
835 }
836 memcpy(&statp->nsaddr_list[nserv], &sin4, sizeof(struct sockaddr_in));
837 nserv++;
838 }
839 }
840
841
842 #else
843 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz)
844 {
845 if (statp->_u._ext.ext != NULL)
846 {
847 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
848 }
849
850 if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv]))
851 {
852 memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen);
853 }
854 else
855 {
856 statp->nsaddr_list[nserv].sin_family = 0;
857 }
858
859 freeaddrinfo(ai);
860 nserv++;
861 }
862 #endif
863 }
864
865 continue;
866 }
867
868 #ifdef RESOLVSORT
869 if (MATCH(buf, "sortlist"))
870 {
871 struct in_addr a;
872
873 cp = buf + sizeof("sortlist") - 1;
874 while (nsort < MAXRESOLVSORT)
875 {
876 while ((*cp == ' ') || (*cp == '\t')) cp++;
877 if ((*cp == '\0') || (*cp == '\n') || (*cp == ';')) break;
878
879 net = cp;
880 while (*cp && !ISSORTMASK(*cp) && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++;
881 n = *cp;
882 *cp = 0;
883 if (inet_aton(net, &a))
884 {
885 statp->sort_list[nsort].addr = a;
886 if (ISSORTMASK(n))
887 {
888 *cp++ = n;
889 net = cp;
890 while (*cp && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++;
891 n = *cp;
892 *cp = 0;
893 if (inet_aton(net, &a))
894 {
895 statp->sort_list[nsort].mask = a.s_addr;
896 }
897 else
898 {
899 statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr);
900 }
901 }
902 else
903 {
904 statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr);
905 }
906 nsort++;
907 }
908
909 *cp = n;
910 }
911
912 continue;
913 }
914 #endif
915
916 if (MATCH(buf, "options"))
917 {
918 res_setoptions(statp, buf + sizeof("options") - 1, "conf");
919 continue;
920 }
921
922 if (MATCH(buf, "timeout"))
923 {
924 cp = buf + sizeof("timeout") - 1;
925 while (*cp == ' ' || *cp == '\t') cp++;
926 if ((*cp == '\0') || (*cp == '\n')) continue;
927 i = atoi(cp);
928 if (i > RES_MAXRETRANS) i = RES_MAXRETRANS;
929 total_timeout = i;
930 continue;
931 }
932 }
933
934 if (nserv > 1) statp->nscount = nserv;
935 #ifdef RESOLVSORT
936 statp->nsort = nsort;
937 #endif
938 fclose(fp);
939 }
940
941 /*
942 * Last chance to get a nameserver. This should not normally
943 * be necessary
944 */
945 #ifdef NO_RESOLV_CONF
946 if(nserv == 0) nserv = get_nameservers(statp);
947 #endif
948
949 if (isresdefault != 0)
950 {
951 if ((statp->defdname[0] == 0) && (gethostname(buf, sizeof(statp->defdname) - 1) == 0) && ((cp = strchr(buf, '.')) != NULL))
952 {
953 strcpy(statp->defdname, cp + 1);
954 }
955 }
956
957 /* find components of local domain that might be searched */
958 if (havesearch == 0)
959 {
960 pp = statp->dnsrch;
961 *pp++ = statp->defdname;
962 *pp = NULL;
963
964 dots = 0;
965 for (cp = statp->defdname; *cp; cp++)
966 {
967 if (*cp == '.') dots++;
968 }
969
970 /* Back up over any trailing dots and cut them out of the name */
971 for (cp--; (cp >= statp->defdname) && (*cp == '.'); cp--)
972 {
973 *cp = '\0';
974 dots--;
975 }
976
977 cp = statp->defdname;
978 while (pp < statp->dnsrch + MAXDFLSRCH)
979 {
980 if (dots < LOCALDOMAINPARTS) break;
981
982 /* we know there is a dot */
983 cp = strchr(cp, '.') + 1;
984 *pp++ = cp;
985 dots--;
986 }
987
988 *pp = NULL;
989 #ifdef DEBUG
990 if (statp->options & RES_DEBUG)
991 {
992 printf(";; res_init()... default dnsrch list:\n");
993 for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp);
994 printf(";;\t..END..\n");
995 }
996 #endif
997 }
998
999 cp = getenv("RES_OPTIONS");
1000 if ((cp != NULL) && (isresdefault != 0))
1001 {
1002 res_setoptions(statp, cp, "env");
1003 }
1004
1005 #ifdef __APPLE__
1006 /*
1007 * Post processing to set the timeout value.
1008 */
1009 if (total_timeout != 0)
1010 {
1011 /* Timeout was set with a "timeout" line in the file */
1012 statp->retrans = total_timeout;
1013 }
1014 else
1015 {
1016 /*
1017 * Timeout is default, or was set with "options timeout:"
1018 * This is a per-select timeout value. Calculate total timeout
1019 * and set statp->restrans which we (Apple) use to indicate
1020 * total time allowed for a query to be resolved.
1021 */
1022 total_timeout = statp->retrans * (statp->retry + 1) * statp->nscount;
1023 statp->retrans = total_timeout;
1024 }
1025 #endif
1026
1027 statp->options |= RES_INIT;
1028 return (0);
1029 }
1030
1031 static void
1032 res_setoptions(res_state statp, const char *options, const char *source)
1033 {
1034 const char *cp = options;
1035 int i;
1036 struct __res_state_ext *ext = statp->_u._ext.ext;
1037
1038 #ifdef DEBUG
1039 if (statp->options & RES_DEBUG)
1040 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
1041 options, source);
1042 #endif
1043 while (*cp) {
1044 /* skip leading and inner runs of spaces */
1045 while (*cp == ' ' || *cp == '\t')
1046 cp++;
1047 /* search for and process individual options */
1048 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
1049 i = atoi(cp + sizeof("ndots:") - 1);
1050 if (i <= RES_MAXNDOTS)
1051 statp->ndots = i;
1052 else
1053 statp->ndots = RES_MAXNDOTS;
1054 #ifdef DEBUG
1055 if (statp->options & RES_DEBUG)
1056 printf(";;\tndots=%d\n", statp->ndots);
1057 #endif
1058 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
1059 i = atoi(cp + sizeof("timeout:") - 1);
1060 if (i <= RES_MAXRETRANS)
1061 statp->retrans = i;
1062 else
1063 statp->retrans = RES_MAXRETRANS;
1064 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
1065 i = atoi(cp + sizeof("attempts:") - 1);
1066 if (i <= RES_MAXRETRY)
1067 statp->retry = i;
1068 else
1069 statp->retry = RES_MAXRETRY;
1070 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
1071 #ifdef DEBUG
1072 if (!(statp->options & RES_DEBUG)) {
1073 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
1074 options, source);
1075 statp->options |= RES_DEBUG;
1076 }
1077 printf(";;\tdebug\n");
1078 #endif
1079 } else if (!strncmp(cp, "no_tld_query",
1080 sizeof("no_tld_query") - 1) ||
1081 !strncmp(cp, "no-tld-query",
1082 sizeof("no-tld-query") - 1)) {
1083 statp->options |= RES_NOTLDQUERY;
1084 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
1085 statp->options |= RES_USE_INET6;
1086 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
1087 statp->options |= RES_ROTATE;
1088 } else if (!strncmp(cp, "no-check-names",
1089 sizeof("no-check-names") - 1)) {
1090 statp->options |= RES_NOCHECKNAME;
1091 }
1092 #ifdef RES_USE_EDNS0
1093 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
1094 statp->options |= RES_USE_EDNS0;
1095 }
1096 #endif
1097 else if (!strncmp(cp, "a6", sizeof("a6") - 1)) {
1098 statp->options |= RES_USE_A6;
1099 }
1100 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
1101 statp->options |= RES_USE_DNAME;
1102 }
1103 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
1104 if (ext == NULL)
1105 goto skip;
1106 cp += sizeof("nibble:") - 1;
1107 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
1108 strncpy(ext->nsuffix, cp, i);
1109 ext->nsuffix[i] = '\0';
1110 }
1111 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
1112 if (ext == NULL)
1113 goto skip;
1114 cp += sizeof("nibble2:") - 1;
1115 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
1116 strncpy(ext->nsuffix2, cp, i);
1117 ext->nsuffix2[i] = '\0';
1118 }
1119 else if (!strncmp(cp, "bitstring:", sizeof("bitstring:") - 1)) {
1120 if (ext == NULL)
1121 goto skip;
1122 cp += sizeof("bitstring:") - 1;
1123 i = MIN(strcspn(cp, " \t"), sizeof(ext->bsuffix) - 1);
1124 strncpy(ext->bsuffix, cp, i);
1125 ext->bsuffix[i] = '\0';
1126 }
1127 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
1128 cp += sizeof("v6revmode:") - 1;
1129 /* "nibble" and "bitstring" used to be valid */
1130 if (!strncmp(cp, "single", sizeof("single") - 1)) {
1131 statp->options |= RES_NO_NIBBLE2;
1132 } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
1133 statp->options &=
1134 ~RES_NO_NIBBLE2;
1135 }
1136 }
1137 else {
1138 /* XXX - print a warning here? */
1139 }
1140 skip:
1141 /* skip to next run of spaces */
1142 while (*cp && *cp != ' ' && *cp != '\t')
1143 cp++;
1144 }
1145 }
1146
1147 /* This function has to be reachable by res_data.c but not publically. */
1148 int
1149 __res_vinit(res_state statp, int preinit)
1150 {
1151 dns_config_t *sc_dns;
1152 dns_resolver_t *sc_res;
1153 char val[256], *p, *x;
1154 int i, n;
1155 uint32_t nsearch, total_timeout, send_timeout;
1156 uint16_t port;
1157
1158 nsearch = 0;
1159 send_timeout = 0;
1160
1161 sc_dns = dns_configuration_copy();
1162 if (sc_dns == NULL) return res_vinit_from_file(statp, preinit, _PATH_RESCONF);
1163
1164 sc_res = sc_dns->resolver[0];
1165 port = sc_res->port;
1166 if (port == 0) port = NS_DEFAULTPORT;
1167
1168 if ((statp->options & RES_INIT) != 0) res_ndestroy(statp);
1169
1170 /* N.B. res_build_start will allocate statp->_u._ext.ext for us */
1171 statp = res_build_start(statp);
1172
1173 p = getenv("RES_RETRY_TIMEOUT");
1174 if (p != NULL) send_timeout = atoi(p);
1175
1176 p = getenv("RES_RETRY");
1177 if (p != NULL) statp->retry= atoi(p);
1178
1179 if (sc_res->n_nameserver > MAXNS) sc_res->n_nameserver = MAXNS;
1180 for (i = 0; i < sc_res->n_nameserver; i++)
1181 {
1182 if (sc_res->nameserver[i]->sa_family == AF_INET)
1183 {
1184 memset(val, 0, sizeof(val));
1185 inet_ntop(AF_INET, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, sizeof(val));
1186 res_build(statp, port, &nsearch, "nameserver", val);
1187 }
1188 else if (sc_res->nameserver[i]->sa_family == AF_INET6)
1189 {
1190 memset(val, 0, sizeof(val));
1191 inet_ntop(AF_INET6, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, sizeof(val));
1192 res_build(statp, port, &nsearch, "nameserver", val);
1193 }
1194 }
1195
1196 if (sc_res->n_search > MAXDNSRCH) sc_res->n_search = MAXDNSRCH;
1197 for (i = 0; i < sc_res->n_search; i++)
1198 {
1199 res_build(statp, port, &nsearch, "search", sc_res->search[i]);
1200 }
1201
1202 /* If there was no search list, use "domain" */
1203 if ((sc_res->n_search == 0) && (sc_res->domain != NULL))
1204 {
1205 /* Count dots */
1206 n = 0;
1207 for (p = sc_res->domain; *p != '\0'; p++)
1208 {
1209 if (*p == '.') n++;
1210 }
1211
1212 /* Back up over any trailing dots and cut them out of the name */
1213 for (p--; (p >= sc_res->domain) && (*p == '.'); p--)
1214 {
1215 *p = '\0';
1216 n--;
1217 }
1218
1219 if (p >= sc_res->domain) res_build(statp, port, &nsearch, "search", sc_res->domain);
1220
1221 /* dots are separators, so number of components is one larger */
1222 n++;
1223
1224 /* Include parent domains with at least LOCALDOMAINPARTS components */
1225 p = sc_res->domain;
1226 while ((n > LOCALDOMAINPARTS) && (nsearch < MAXDFLSRCH))
1227 {
1228 /* Find next component */
1229 while (*p != '.') p++;
1230 if (*p == '\0') break;
1231 p++;
1232
1233 n--;
1234 res_build(statp, port, &nsearch, "search", p);
1235 }
1236 }
1237
1238 total_timeout = sc_res->timeout;
1239
1240 snprintf(val, sizeof(val), "%d", sc_res->search_order);
1241 res_build(statp, port, &nsearch, "search_order", val);
1242
1243 if (sc_res->n_sortaddr > MAXRESOLVSORT) sc_res->n_sortaddr = MAXRESOLVSORT;
1244 for (i = 0; i < sc_res->n_sortaddr; i++)
1245 {
1246 res_build_sortlist(statp, sc_res->sortaddr[i]->address, sc_res->sortaddr[i]->mask);
1247 }
1248
1249 p = sc_res->options;
1250 while (NULL != (x = res_next_word(&p)))
1251 {
1252 if (!strncmp(x, "ndots:", 6))
1253 {
1254 res_build(statp, port, &nsearch, "ndots", x+6);
1255 }
1256
1257 else if (!strncmp(x, "nibble:", 7))
1258 {
1259 res_build(statp, port, &nsearch, "nibble", x+7);
1260 }
1261
1262 else if (!strncmp(x, "nibble2:", 8))
1263 {
1264 res_build(statp, port, &nsearch, "nibble2", x+8);
1265 }
1266
1267 else if (!strncmp(x, "timeout:", 8))
1268 {
1269 send_timeout = atoi(x+8);
1270 }
1271
1272 else if (!strncmp(x, "attempts:", 9))
1273 {
1274 res_build(statp, port, &nsearch, "attempts", x+9);
1275 }
1276
1277 else if (!strncmp(x, "bitstring:", 10))
1278 {
1279 res_build(statp, port, &nsearch, "bitstring", x+10);
1280 }
1281
1282 else if (!strncmp(x, "v6revmode:", 10))
1283 {
1284 res_build(statp, port, &nsearch, "v6revmode", x+10);
1285 }
1286
1287 else if (!strcmp(x, "debug"))
1288 {
1289 res_build(statp, port, &nsearch, "debug", NULL);
1290 }
1291
1292 else if (!strcmp(x, "no_tld_query"))
1293 {
1294 res_build(statp, port, &nsearch, "no_tld_query", NULL);
1295 }
1296
1297 else if (!strcmp(x, "inet6"))
1298 {
1299 res_build(statp, port, &nsearch, "inet6", NULL);
1300 }
1301
1302 else if (!strcmp(x, "rotate"))
1303 {
1304 res_build(statp, port, &nsearch, "rotate", NULL);
1305 }
1306
1307 else if (!strcmp(x, "no-check-names"))
1308 {
1309 res_build(statp, port, &nsearch, "no-check-names", NULL);
1310 }
1311
1312 #ifdef RES_USE_EDNS0
1313 else if (!strcmp(x, "edns0"))
1314 {
1315 res_build(statp, port, &nsearch, "edns0", NULL);
1316 }
1317 #endif
1318 else if (!strcmp(x, "a6"))
1319 {
1320 res_build(statp, port, &nsearch, "a6", NULL);
1321 }
1322
1323 else if (!strcmp(x, "dname"))
1324 {
1325 res_build(statp, port, &nsearch, "dname", NULL);
1326 }
1327 }
1328
1329 n = statp->nscount;
1330 if (n == 0) n = 1;
1331
1332 if (total_timeout == 0)
1333 {
1334 if (send_timeout == 0) total_timeout = RES_MAXRETRANS;
1335 else total_timeout = send_timeout * statp->retry * n;
1336 }
1337
1338 dns_configuration_free(sc_dns);
1339
1340 res_build_finish(statp, total_timeout, port);
1341
1342 return 0;
1343 }
1344
1345 int
1346 res_ninit(res_state statp)
1347 {
1348 if (statp == NULL) return -1;
1349 memset(statp, 0, sizeof(struct __res_state));
1350 return __res_vinit(statp, 0);
1351 }
1352
1353 #ifdef RESOLVSORT
1354 /* XXX - should really support CIDR which means explicit masks always. */
1355 static u_int32_t
1356 net_mask(in) /* XXX - should really use system's version of this */
1357 struct in_addr in;
1358 {
1359 register u_int32_t i = ntohl(in.s_addr);
1360
1361 if (IN_CLASSA(i))
1362 return (htonl(IN_CLASSA_NET));
1363 else if (IN_CLASSB(i))
1364 return (htonl(IN_CLASSB_NET));
1365 return (htonl(IN_CLASSC_NET));
1366 }
1367 #endif
1368
1369 u_int
1370 res_randomid(void) {
1371 struct timeval now;
1372 #ifdef __APPLE__
1373 int rf;
1374 static u_int x = 0;
1375
1376 if (x == 0)
1377 {
1378 rf = open("/dev/random", O_RDONLY, 0);
1379 if (rf >= 0)
1380 {
1381 read(rf, &x, sizeof(u_int));
1382 close(rf);
1383 }
1384 else
1385 {
1386 x = (getpid() << 10) + time(NULL);
1387 }
1388
1389 srandom(x);
1390 }
1391
1392 return random();
1393 #endif
1394
1395 gettimeofday(&now, NULL);
1396 return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
1397 }
1398
1399 /*
1400 * This routine is for closing the socket if a virtual circuit is used and
1401 * the program wants to close it. This provides support for endhostent()
1402 * which expects to close the socket.
1403 *
1404 * This routine is not expected to be user visible.
1405 */
1406 void
1407 res_nclose(res_state statp)
1408 {
1409 int ns;
1410
1411 if (statp->_vcsock >= 0)
1412 {
1413 close(statp->_vcsock);
1414 statp->_vcsock = -1;
1415 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
1416 }
1417
1418 if (statp->_pad >= 9)
1419 {
1420 for (ns = 0; ns < statp->_u._ext.nscount; ns++)
1421 {
1422 if (statp->_u._ext.nssocks[ns] != -1)
1423 {
1424 close(statp->_u._ext.nssocks[ns]);
1425 statp->_u._ext.nssocks[ns] = -1;
1426 }
1427 }
1428 }
1429 }
1430
1431 void
1432 res_ndestroy(res_state statp)
1433 {
1434 res_nclose(statp);
1435 statp->options &= ~RES_INIT;
1436
1437 /*
1438 * _pad (normally unused) is a version number.
1439 * We use it to prevent BIND_9 from trashing memory
1440 * if statp was created by BIND-8.
1441 */
1442 if (statp->_pad >= 9)
1443 {
1444 if (statp->_u._ext.ext != NULL) free(statp->_u._ext.ext);
1445 statp->_u._ext.ext = NULL;
1446 statp->_pad = 9;
1447 }
1448 }
1449
1450 const char *
1451 res_get_nibblesuffix(res_state statp) {
1452 if (statp->_u._ext.ext)
1453 return (statp->_u._ext.ext->nsuffix);
1454 return ("ip6.arpa");
1455 }
1456
1457 const char *
1458 res_get_nibblesuffix2(res_state statp) {
1459 if (statp->_u._ext.ext)
1460 return (statp->_u._ext.ext->nsuffix2);
1461 return ("ip6.int");
1462 }
1463
1464 const char *
1465 res_get_bitstringsuffix(res_state statp) {
1466 if (statp->_u._ext.ext)
1467 return (statp->_u._ext.ext->bsuffix);
1468 return ("ip6.arpa");
1469 }
1470
1471 void
1472 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
1473 int i, nserv;
1474 size_t size;
1475
1476 /* close open servers */
1477 res_nclose(statp);
1478
1479 /* cause rtt times to be forgotten */
1480 statp->_u._ext.nscount = 0;
1481
1482 nserv = 0;
1483 for (i = 0; i < cnt && nserv < MAXNS; i++) {
1484 switch (set->sin.sin_family) {
1485 case AF_INET:
1486 size = sizeof(set->sin);
1487 if (statp->_u._ext.ext)
1488 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
1489 &set->sin, size);
1490 if (size <= sizeof(statp->nsaddr_list[nserv]))
1491 memcpy(&statp->nsaddr_list[nserv],
1492 &set->sin, size);
1493 else
1494 statp->nsaddr_list[nserv].sin_family = 0;
1495 nserv++;
1496 break;
1497
1498 case AF_INET6:
1499 size = sizeof(set->sin6);
1500 if (statp->_u._ext.ext)
1501 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
1502 &set->sin6, size);
1503 if (size <= sizeof(statp->nsaddr_list[nserv]))
1504 memcpy(&statp->nsaddr_list[nserv],
1505 &set->sin6, size);
1506 else
1507 statp->nsaddr_list[nserv].sin_family = 0;
1508 nserv++;
1509 break;
1510
1511 default:
1512 break;
1513 }
1514 set++;
1515 }
1516
1517 statp->nscount = nserv;
1518 }
1519
1520 int
1521 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
1522 int i;
1523 size_t size;
1524 u_int16_t family;
1525
1526 for (i = 0; i < statp->nscount && i < cnt; i++) {
1527 if (statp->_u._ext.ext)
1528 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
1529 else
1530 family = statp->nsaddr_list[i].sin_family;
1531
1532 switch (family) {
1533 case AF_INET:
1534 size = sizeof(set->sin);
1535 if (statp->_u._ext.ext)
1536 memcpy(&set->sin,
1537 &statp->_u._ext.ext->nsaddrs[i],
1538 size);
1539 else
1540 memcpy(&set->sin, &statp->nsaddr_list[i],
1541 size);
1542 break;
1543
1544 case AF_INET6:
1545 size = sizeof(set->sin6);
1546 if (statp->_u._ext.ext)
1547 memcpy(&set->sin6,
1548 &statp->_u._ext.ext->nsaddrs[i],
1549 size);
1550 else
1551 memcpy(&set->sin6, &statp->nsaddr_list[i],
1552 size);
1553 break;
1554
1555 default:
1556 set->sin.sin_family = 0;
1557 break;
1558 }
1559 set++;
1560 }
1561 return (statp->nscount);
1562 }