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