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