2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
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.
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
55 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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
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 */
77 #include "port_before.h"
80 #include <sys/types.h>
81 #include <sys/param.h>
82 #include <sys/socket.h>
85 #include <netinet/in.h>
86 #include <arpa/inet.h>
87 #include <arpa/nameser.h>
101 #include "port_after.h"
104 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
107 #include "res_private.h"
109 /* Options. Should all be left alone. */
113 static void res_setoptions
__P((res_state
, const char *, const char *));
114 extern res_state
res_state_new();
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
));
122 #if !defined(isascii) /* XXX - could be a function */
123 # define isascii(c) (!(c & 0200))
126 #define INET_NTOP_AF_INET_OFFSET 4
127 #define INET_NTOP_AF_INET6_OFFSET 8
130 * Resolver state default settings.
133 __attribute__((__visibility__("hidden")))
135 res_build_start(res_state x
)
143 res
= res_state_new();
147 if ((x
->options
& RES_INIT
) != 0) res_ndestroy(x
);
151 if (res
== NULL
) return NULL
;
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
));
156 /* make sure version is set */
159 res
->retry
= RES_DFLRETRY
;
160 res
->options
= RES_DEFAULT
;
161 res
->id
= res_randomid();
166 if (res
->_u
._ext
.ext
!= NULL
)
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");
176 __attribute__((__visibility__("hidden")))
178 res_build_finish(res_state res
, uint32_t timeout
, uint16_t port
)
180 if (res
== NULL
) return -1;
182 if (res
->nscount
== 0)
185 res
->nsaddr_list
[0].sin_addr
= inet_makeaddr(IN_LOOPBACKNET
, 1);
187 res
->nsaddr_list
[0].sin_addr
.s_addr
= INADDR_ANY
;
190 res
->nsaddr_list
[0].sin_family
= AF_INET
;
191 res
->nsaddr_list
[0].sin_port
= htons(port
);
193 res
->nsaddr_list
[0].sin_len
= sizeof(struct sockaddr_in
);
199 * Force loopback queries to use TCP
200 * so we don't take a timeout if named isn't running.
202 res
->options
|= RES_USEVC
;
205 if (timeout
== 0) res
->retrans
= RES_MAXRETRANS
;
206 else res
->retrans
= timeout
;
208 res
->options
|= RES_INIT
;
212 __attribute__((__visibility__("hidden")))
214 res_build_sortlist(res_state res
, struct in_addr addr
, struct in_addr mask
)
218 if (res
== NULL
) return -1;
221 if (n
>= MAXRESOLVSORT
) return -1;
223 res
->sort_list
[n
].addr
= addr
;
224 res
->sort_list
[n
].mask
= mask
.s_addr
;
231 __attribute__((__visibility__("hidden")))
233 res_next_word(char **p
)
237 if (p
== NULL
) return NULL
;
238 if (*p
== NULL
) return NULL
;
242 /* Skip leading white space */
243 while ((*s
== ' ') || (*s
== '\t') || (*s
== '\n')) s
++;
246 if (*s
== '\0') return NULL
;
248 /* Find end of word */
250 while ((*x
!= ' ') && (*x
!= '\t') && (*x
!= '\n') && (*x
!= '\0')) x
++;
259 if (s
== x
) return NULL
;
263 __attribute__((__visibility__("hidden")))
265 res_build(res_state res
, uint16_t port
, uint32_t *nsrch
, char *key
, char *val
)
267 int32_t dotcount
, semicount
, status
;
271 struct in_addr addr4
, mask
;
272 struct sockaddr_in sin4
;
273 struct in6_addr addr6
;
274 struct sockaddr_in6 sin6
;
276 if (res
== NULL
) return -1;
278 if (!strcmp(key
, "domain"))
280 strncpy(res
->defdname
, val
, sizeof(res
->defdname
) - 1);
281 res
->defdname
[sizeof(res
->defdname
) - 1] = '\0';
285 else if (!strcmp(key
, "search"))
287 len
= strlen(val
) + 1;
288 ival
= sizeof(res
->defdname
);
293 memset(res
->defdname
, 0, sizeof(res
->defdname
));
297 p
= res
->dnsrch
[*nsrch
- 1];
298 for (; (ival
> 0) && (*p
!= '\0'); ival
--) p
++;
302 if (len
> ival
) return -1;
305 res
->dnsrch
[*nsrch
] = p
;
310 else if (!strcmp(key
, "nameserver"))
317 for (p
= val
; *p
!= '\0'; p
++)
319 if (*p
== ':') semicount
++;
327 if ((dotcount
== 4) || ((semicount
> 0) && (lastdot
!= NULL
)))
329 aport
= atoi(lastdot
+ 1);
330 if (aport
== 0) aport
= port
;
334 memset(&addr4
, 0, sizeof(struct in_addr
));
335 memset(&sin4
, 0, sizeof(struct sockaddr_in
));
337 memset(&addr6
, 0, sizeof(struct in6_addr
));
338 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
340 status
= inet_pton(AF_INET6
, val
, &addr6
);
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
)
349 memcpy(&(res
->_u
._ext
.ext
->nsaddrs
[res
->nscount
]), &sin6
, sizeof(struct sockaddr_in6
));
351 res
->nsaddr_list
[res
->nscount
].sin_family
= 0;
356 status
= inet_pton(AF_INET
, val
, &addr4
);
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
)
365 memcpy(&(res
->_u
._ext
.ext
->nsaddrs
[res
->nscount
]), &sin4
, sizeof(struct sockaddr_in
));
367 memcpy(&(res
->nsaddr_list
[res
->nscount
]), &sin4
, sizeof(struct sockaddr_in
));
375 else if (!strcmp(key
, "sortlist"))
377 p
= strchr(val
, '/');
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;
390 if (p
!= NULL
) status
= inet_aton(p
, &mask
);
393 ival
= ntohl(addr4
.s_addr
);
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
);
400 return res_build_sortlist(res
, addr4
, mask
);
403 else if (!strcmp(key
, "ndots"))
406 if (ival
< 0) ival
= 0;
407 if (ival
> RES_MAXNDOTS
) ival
= RES_MAXNDOTS
;
412 else if (!strcmp(key
, "nibble"))
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
);
420 else if (!strcmp(key
, "nibble2"))
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
);
428 else if (!strcmp(key
, "bitstring"))
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
);
436 else if (!strcmp(key
, "attempts"))
439 if (ival
< 0) ival
= 0;
440 if (ival
> RES_MAXRETRY
) ival
= RES_MAXRETRY
;
445 else if (!strcmp(key
, "v6revmode"))
447 if (!strcmp(val
, "single")) res
->options
|= RES_NO_NIBBLE2
;
448 else if (!strcmp(val
, "both")) res
->options
&= ~RES_NO_NIBBLE2
;
452 else if (!strcmp(key
, "debug"))
454 res
->options
|= RES_DEBUG
;
458 else if (!strcmp(key
, "no_tld_query"))
460 res
->options
|= RES_NOTLDQUERY
;
464 else if (!strcmp(key
, "inet6"))
466 res
->options
|= RES_USE_INET6
;
470 else if (!strcmp(key
, "rotate"))
472 res
->options
|= RES_ROTATE
;
476 else if (!strcmp(key
, "no-check-names"))
478 res
->options
|= RES_NOCHECKNAME
;
483 else if (!strcmp(key
, "edns0"))
485 res
->options
|= RES_USE_EDNS0
;
490 else if (!strcmp(key
, "a6"))
492 res
->options
|= RES_USE_A6
;
496 else if (!strcmp(key
, "dname"))
498 res
->options
|= RES_USE_DNAME
;
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().
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.
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.
524 * Return 0 if completes successfully, -1 on error
528 res_vinit_from_file(res_state statp
, int preinit
, char *resconf_file
)
531 register char *cp
, **pp
;
534 int nserv
= 0; /* number of nameserver records read from file */
537 int isresdefault
= 0;
538 unsigned short port
; /* HOST BYTE ORDER */
539 unsigned int i
, total_timeout
;
546 port
= NS_DEFAULTPORT
;
551 statp
->retrans
= RES_TIMEOUT
;
552 statp
->retry
= RES_DFLRETRY
;
553 statp
->options
= RES_DEFAULT
;
554 statp
->id
= res_randomid();
557 if ((statp
->options
& RES_INIT
) != 0) res_ndestroy(statp
);
559 /* N.B. we allocate a new statp->_u._ext.ext below */
561 /* make sure version is set */
566 if ((resconf_file
== NULL
) || (!strcmp(resconf_file
, _PATH_RESCONF
)))
571 statp
->nsaddr
.sin_addr
= inet_makeaddr(IN_LOOPBACKNET
, 1);
573 statp
->nsaddr
.sin_addr
.s_addr
= INADDR_ANY
;
575 statp
->nsaddr
.sin_family
= AF_INET
;
576 statp
->nsaddr
.sin_port
= htons(NS_DEFAULTPORT
);
578 statp
->nsaddr
.sin_len
= sizeof(struct sockaddr_in
);
583 * Force loopback queries to use TCP
584 * so we don't take a timeout if named isn't running.
586 statp
->options
|= RES_USEVC
;
596 statp
->_u
._ext
.nscount
= 0;
597 statp
->_u
._ext
.ext
= (struct __res_state_ext
*)calloc(1, sizeof(struct __res_state_ext
));
599 if (statp
->_u
._ext
.ext
!= NULL
)
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");
612 /* Allow user to override the local domain definition */
613 cp
= getenv("LOCALDOMAIN");
614 if ((cp
!= NULL
) && (isresdefault
!= 0))
616 (void)strncpy(statp
->defdname
, cp
, sizeof(statp
->defdname
) - 1);
617 statp
->defdname
[sizeof(statp
->defdname
) - 1] = '\0';
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)
627 cp
= statp
->defdname
;
630 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++)
632 if (*cp
== '\n') break;
633 else if (*cp
== ' ' || *cp
== '\t')
646 /* null terminate last domain if there are excess */
647 while ((*cp
!= '\0') && (*cp
!= ' ') && (*cp
!= '\t') && (*cp
!= '\n')) cp
++;
652 #define MATCH(line, name) \
653 (!strncmp(line, name, sizeof(name) - 1) && \
654 (line[sizeof(name) - 1] == ' ' || \
655 line[sizeof(name) - 1] == '\t'))
657 if (resconf_file
== NULL
) resconf_file
= _PATH_RESCONF
;
659 if ((fp
= fopen(resconf_file
, "r")) != NULL
)
661 /* look for port number */
662 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
665 if (*buf
== ';' || *buf
== '#') continue;
667 /* read default domain name */
668 if (MATCH(buf
, "port"))
670 cp
= buf
+ sizeof("port") - 1;
671 while (*cp
== ' ' || *cp
== '\t') cp
++;
672 if ((*cp
== '\0') || (*cp
== '\n')) continue;
680 if ((fp
= fopen(resconf_file
, "r")) != NULL
)
682 /* read the config file */
683 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
686 if ((*buf
== ';') || (*buf
== '#')) continue;
688 /* read default domain name */
689 if (MATCH(buf
, "domain"))
691 /* skip if have from environ */
692 if (haveenv
) continue;
694 cp
= buf
+ sizeof("domain") - 1;
695 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
696 if ((*cp
== '\0') || (*cp
== '\n')) continue;
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';
706 /* set search list */
707 if (MATCH(buf
, "search"))
709 /* skip if have from environ */
710 if (haveenv
) continue;
712 cp
= buf
+ sizeof("search") - 1;
713 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
714 if ((*cp
== '\0') || (*cp
== '\n')) continue;
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';
722 * Set search list to be blank-separated strings
725 cp
= statp
->defdname
;
728 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++)
730 if ((*cp
== ' ') || (*cp
== '\t'))
742 /* null terminate last domain if there are excess */
743 while ((*cp
!= '\0') && (*cp
!= ' ') && (*cp
!= '\t')) cp
++;
750 /* read nameservers to query */
751 if (MATCH(buf
, "nameserver") && (nserv
< MAXNS
))
754 struct addrinfo hints
, *ai
;
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
];
765 const size_t minsiz
= sizeof(statp
->_u
._ext
.ext
->nsaddrs
[0]);
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'))
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
;
784 for (checkp
= cp
; *checkp
!= '\0'; checkp
++)
786 if (*checkp
== ':') semicount
++;
787 else if (*checkp
== '.')
794 if ((dotcount
== 4) || ((semicount
> 0) && (lastdot
!= NULL
)))
796 aport
= atoi(lastdot
+ 1);
797 if (aport
== 0) aport
= port
;
801 sprintf(sbuf
, "%u", aport
);
804 memset(&addr4
, 0, sizeof(struct in_addr
));
805 memset(&sin4
, 0, sizeof(struct sockaddr_in
));
807 memset(&addr6
, 0, sizeof(struct in6_addr
));
808 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
810 status
= inet_pton(AF_INET6
, cp
, &addr6
);
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
)
819 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], &sin6
, sizeof(struct sockaddr_in6
));
821 statp
->nsaddr_list
[nserv
].sin_family
= 0;
826 status
= inet_pton(AF_INET
, cp
, &addr4
);
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
)
835 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], &sin4
, sizeof(struct sockaddr_in
));
837 memcpy(&statp
->nsaddr_list
[nserv
], &sin4
, sizeof(struct sockaddr_in
));
844 if (getaddrinfo(cp
, sbuf
, &hints
, &ai
) == 0 && ai
->ai_addrlen
<= minsiz
)
846 if (statp
->_u
._ext
.ext
!= NULL
)
848 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], ai
->ai_addr
, ai
->ai_addrlen
);
851 if (ai
->ai_addrlen
<= sizeof(statp
->nsaddr_list
[nserv
]))
853 memcpy(&statp
->nsaddr_list
[nserv
], ai
->ai_addr
, ai
->ai_addrlen
);
857 statp
->nsaddr_list
[nserv
].sin_family
= 0;
870 if (MATCH(buf
, "sortlist"))
874 cp
= buf
+ sizeof("sortlist") - 1;
875 while (nsort
< MAXRESOLVSORT
)
877 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
878 if ((*cp
== '\0') || (*cp
== '\n') || (*cp
== ';')) break;
881 while (*cp
&& !ISSORTMASK(*cp
) && (*cp
!= ';') && isascii(*cp
) && !isspace((unsigned char)*cp
)) cp
++;
884 if (inet_aton(net
, &a
))
886 statp
->sort_list
[nsort
].addr
= a
;
891 while (*cp
&& (*cp
!= ';') && isascii(*cp
) && !isspace((unsigned char)*cp
)) cp
++;
894 if (inet_aton(net
, &a
))
896 statp
->sort_list
[nsort
].mask
= a
.s_addr
;
900 statp
->sort_list
[nsort
].mask
= net_mask(statp
->sort_list
[nsort
].addr
);
905 statp
->sort_list
[nsort
].mask
= net_mask(statp
->sort_list
[nsort
].addr
);
917 if (MATCH(buf
, "options"))
919 res_setoptions(statp
, buf
+ sizeof("options") - 1, "conf");
923 if (MATCH(buf
, "timeout"))
925 cp
= buf
+ sizeof("timeout") - 1;
926 while (*cp
== ' ' || *cp
== '\t') cp
++;
927 if ((*cp
== '\0') || (*cp
== '\n')) continue;
929 if (i
> RES_MAXRETRANS
) i
= RES_MAXRETRANS
;
935 if (nserv
> 1) statp
->nscount
= nserv
;
937 statp
->nsort
= nsort
;
943 * Last chance to get a nameserver. This should not normally
946 #ifdef NO_RESOLV_CONF
947 if(nserv
== 0) nserv
= get_nameservers(statp
);
950 if (isresdefault
!= 0)
952 if ((statp
->defdname
[0] == 0) && (gethostname(buf
, sizeof(statp
->defdname
) - 1) == 0) && ((cp
= strchr(buf
, '.')) != NULL
))
954 strcpy(statp
->defdname
, cp
+ 1);
958 /* find components of local domain that might be searched */
962 *pp
++ = statp
->defdname
;
966 for (cp
= statp
->defdname
; *cp
; cp
++)
968 if (*cp
== '.') dots
++;
971 /* Back up over any trailing dots and cut them out of the name */
972 for (cp
--; (cp
>= statp
->defdname
) && (*cp
== '.'); cp
--)
978 cp
= statp
->defdname
;
979 while (pp
< statp
->dnsrch
+ MAXDFLSRCH
)
981 if (dots
< LOCALDOMAINPARTS
) break;
983 /* we know there is a dot */
984 cp
= strchr(cp
, '.') + 1;
991 if (statp
->options
& RES_DEBUG
)
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");
1000 cp
= getenv("RES_OPTIONS");
1001 if ((cp
!= NULL
) && (isresdefault
!= 0))
1003 res_setoptions(statp
, cp
, "env");
1008 * Post processing to set the timeout value.
1010 if (total_timeout
!= 0)
1012 /* Timeout was set with a "timeout" line in the file */
1013 statp
->retrans
= total_timeout
;
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.
1023 total_timeout
= statp
->retrans
* (statp
->retry
+ 1) * statp
->nscount
;
1024 statp
->retrans
= total_timeout
;
1028 statp
->options
|= RES_INIT
;
1033 res_setoptions(res_state statp
, const char *options
, const char *source
)
1035 const char *cp
= options
;
1037 struct __res_state_ext
*ext
= statp
->_u
._ext
.ext
;
1040 if (statp
->options
& RES_DEBUG
)
1041 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
1045 /* skip leading and inner runs of spaces */
1046 while (*cp
== ' ' || *cp
== '\t')
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
)
1054 statp
->ndots
= RES_MAXNDOTS
;
1056 if (statp
->options
& RES_DEBUG
)
1057 printf(";;\tndots=%d\n", statp
->ndots
);
1059 } else if (!strncmp(cp
, "timeout:", sizeof("timeout:") - 1)) {
1060 i
= atoi(cp
+ sizeof("timeout:") - 1);
1061 if (i
<= RES_MAXRETRANS
)
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
)
1070 statp
->retry
= RES_MAXRETRY
;
1071 } else if (!strncmp(cp
, "debug", sizeof("debug") - 1)) {
1073 if (!(statp
->options
& RES_DEBUG
)) {
1074 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
1076 statp
->options
|= RES_DEBUG
;
1078 printf(";;\tdebug\n");
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
;
1093 #ifdef RES_USE_EDNS0
1094 else if (!strncmp(cp
, "edns0", sizeof("edns0") - 1)) {
1095 statp
->options
|= RES_USE_EDNS0
;
1098 else if (!strncmp(cp
, "a6", sizeof("a6") - 1)) {
1099 statp
->options
|= RES_USE_A6
;
1101 else if (!strncmp(cp
, "dname", sizeof("dname") - 1)) {
1102 statp
->options
|= RES_USE_DNAME
;
1104 else if (!strncmp(cp
, "nibble:", sizeof("nibble:") - 1)) {
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';
1112 else if (!strncmp(cp
, "nibble2:", sizeof("nibble2:") - 1)) {
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';
1120 else if (!strncmp(cp
, "bitstring:", sizeof("bitstring:") - 1)) {
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';
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)) {
1139 /* XXX - print a warning here? */
1142 /* skip to next run of spaces */
1143 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
1148 /* This function has to be reachable by res_data.c but not publically. */
1150 __res_vinit(res_state statp
, int preinit
)
1152 dns_config_t
*sc_dns
;
1153 dns_resolver_t
*sc_res
;
1154 char val
[256], *p
, *x
;
1156 uint32_t nsearch
, total_timeout
, send_timeout
;
1162 sc_dns
= dns_configuration_copy();
1163 if (sc_dns
== NULL
) return res_vinit_from_file(statp
, preinit
, _PATH_RESCONF
);
1165 sc_res
= sc_dns
->resolver
[0];
1166 port
= sc_res
->port
;
1167 if (port
== 0) port
= NS_DEFAULTPORT
;
1169 if ((statp
->options
& RES_INIT
) != 0) res_ndestroy(statp
);
1171 /* N.B. res_build_start will allocate statp->_u._ext.ext for us */
1172 statp
= res_build_start(statp
);
1174 p
= getenv("RES_RETRY_TIMEOUT");
1175 if (p
!= NULL
) send_timeout
= atoi(p
);
1177 p
= getenv("RES_RETRY");
1178 if (p
!= NULL
) statp
->retry
= atoi(p
);
1180 if (sc_res
->n_nameserver
> MAXNS
) sc_res
->n_nameserver
= MAXNS
;
1181 for (i
= 0; i
< sc_res
->n_nameserver
; i
++)
1183 if (sc_res
->nameserver
[i
]->sa_family
== AF_INET
)
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
);
1189 else if (sc_res
->nameserver
[i
]->sa_family
== AF_INET6
)
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
);
1197 if (sc_res
->n_search
> MAXDNSRCH
) sc_res
->n_search
= MAXDNSRCH
;
1198 for (i
= 0; i
< sc_res
->n_search
; i
++)
1200 res_build(statp
, port
, &nsearch
, "search", sc_res
->search
[i
]);
1203 /* If there was no search list, use "domain" */
1204 if ((sc_res
->n_search
== 0) && (sc_res
->domain
!= NULL
))
1208 for (p
= sc_res
->domain
; *p
!= '\0'; p
++)
1213 /* Back up over any trailing dots and cut them out of the name */
1214 for (p
--; (p
>= sc_res
->domain
) && (*p
== '.'); p
--)
1220 if (p
>= sc_res
->domain
) res_build(statp
, port
, &nsearch
, "search", sc_res
->domain
);
1222 /* dots are separators, so number of components is one larger */
1225 /* Include parent domains with at least LOCALDOMAINPARTS components */
1227 while ((n
> LOCALDOMAINPARTS
) && (nsearch
< MAXDFLSRCH
))
1229 /* Find next component */
1230 while (*p
!= '.') p
++;
1231 if (*p
== '\0') break;
1235 res_build(statp
, port
, &nsearch
, "search", p
);
1239 total_timeout
= sc_res
->timeout
;
1241 snprintf(val
, sizeof(val
), "%d", sc_res
->search_order
);
1242 res_build(statp
, port
, &nsearch
, "search_order", val
);
1244 if (sc_res
->n_sortaddr
> MAXRESOLVSORT
) sc_res
->n_sortaddr
= MAXRESOLVSORT
;
1245 for (i
= 0; i
< sc_res
->n_sortaddr
; i
++)
1247 res_build_sortlist(statp
, sc_res
->sortaddr
[i
]->address
, sc_res
->sortaddr
[i
]->mask
);
1250 p
= sc_res
->options
;
1251 while (NULL
!= (x
= res_next_word(&p
)))
1253 if (!strncmp(x
, "ndots:", 6))
1255 res_build(statp
, port
, &nsearch
, "ndots", x
+6);
1258 else if (!strncmp(x
, "nibble:", 7))
1260 res_build(statp
, port
, &nsearch
, "nibble", x
+7);
1263 else if (!strncmp(x
, "nibble2:", 8))
1265 res_build(statp
, port
, &nsearch
, "nibble2", x
+8);
1268 else if (!strncmp(x
, "timeout:", 8))
1270 send_timeout
= atoi(x
+8);
1273 else if (!strncmp(x
, "attempts:", 9))
1275 res_build(statp
, port
, &nsearch
, "attempts", x
+9);
1278 else if (!strncmp(x
, "bitstring:", 10))
1280 res_build(statp
, port
, &nsearch
, "bitstring", x
+10);
1283 else if (!strncmp(x
, "v6revmode:", 10))
1285 res_build(statp
, port
, &nsearch
, "v6revmode", x
+10);
1288 else if (!strcmp(x
, "debug"))
1290 res_build(statp
, port
, &nsearch
, "debug", NULL
);
1293 else if (!strcmp(x
, "no_tld_query"))
1295 res_build(statp
, port
, &nsearch
, "no_tld_query", NULL
);
1298 else if (!strcmp(x
, "inet6"))
1300 res_build(statp
, port
, &nsearch
, "inet6", NULL
);
1303 else if (!strcmp(x
, "rotate"))
1305 res_build(statp
, port
, &nsearch
, "rotate", NULL
);
1308 else if (!strcmp(x
, "no-check-names"))
1310 res_build(statp
, port
, &nsearch
, "no-check-names", NULL
);
1313 #ifdef RES_USE_EDNS0
1314 else if (!strcmp(x
, "edns0"))
1316 res_build(statp
, port
, &nsearch
, "edns0", NULL
);
1319 else if (!strcmp(x
, "a6"))
1321 res_build(statp
, port
, &nsearch
, "a6", NULL
);
1324 else if (!strcmp(x
, "dname"))
1326 res_build(statp
, port
, &nsearch
, "dname", NULL
);
1333 if (total_timeout
== 0)
1335 if (send_timeout
== 0) total_timeout
= RES_MAXRETRANS
;
1336 else total_timeout
= send_timeout
* statp
->retry
* n
;
1339 dns_configuration_free(sc_dns
);
1341 res_build_finish(statp
, total_timeout
, port
);
1347 res_ninit(res_state statp
)
1349 if (statp
== NULL
) return -1;
1350 memset(statp
, 0, sizeof(struct __res_state
));
1351 return __res_vinit(statp
, 0);
1355 /* XXX - should really support CIDR which means explicit masks always. */
1357 net_mask(in
) /* XXX - should really use system's version of this */
1360 register u_int32_t i
= ntohl(in
.s_addr
);
1363 return (htonl(IN_CLASSA_NET
));
1364 else if (IN_CLASSB(i
))
1365 return (htonl(IN_CLASSB_NET
));
1366 return (htonl(IN_CLASSC_NET
));
1374 return arc4random();
1377 gettimeofday(&now
, NULL
);
1378 return (0xffff & (now
.tv_sec
^ now
.tv_usec
^ getpid()));
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.
1387 * This routine is not expected to be user visible.
1390 res_nclose(res_state statp
)
1394 if (statp
->_vcsock
>= 0)
1396 close(statp
->_vcsock
);
1397 statp
->_vcsock
= -1;
1398 statp
->_flags
&= ~(RES_F_VC
| RES_F_CONN
);
1401 if (statp
->_pad
>= 9)
1403 for (ns
= 0; ns
< statp
->_u
._ext
.nscount
; ns
++)
1405 if (statp
->_u
._ext
.nssocks
[ns
] != -1)
1407 close(statp
->_u
._ext
.nssocks
[ns
]);
1408 statp
->_u
._ext
.nssocks
[ns
] = -1;
1415 res_ndestroy(res_state statp
)
1418 statp
->options
&= ~RES_INIT
;
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.
1425 if (statp
->_pad
>= 9)
1427 if (statp
->_u
._ext
.ext
!= NULL
) free(statp
->_u
._ext
.ext
);
1428 statp
->_u
._ext
.ext
= NULL
;
1434 res_get_nibblesuffix(res_state statp
) {
1435 if (statp
->_u
._ext
.ext
)
1436 return (statp
->_u
._ext
.ext
->nsuffix
);
1437 return ("ip6.arpa");
1441 res_get_nibblesuffix2(res_state statp
) {
1442 if (statp
->_u
._ext
.ext
)
1443 return (statp
->_u
._ext
.ext
->nsuffix2
);
1448 res_get_bitstringsuffix(res_state statp
) {
1449 if (statp
->_u
._ext
.ext
)
1450 return (statp
->_u
._ext
.ext
->bsuffix
);
1451 return ("ip6.arpa");
1455 res_setservers(res_state statp
, const union res_sockaddr_union
*set
, int cnt
) {
1459 /* close open servers */
1462 /* cause rtt times to be forgotten */
1463 statp
->_u
._ext
.nscount
= 0;
1466 for (i
= 0; i
< cnt
&& nserv
< MAXNS
; i
++) {
1467 switch (set
->sin
.sin_family
) {
1469 size
= sizeof(set
->sin
);
1470 if (statp
->_u
._ext
.ext
)
1471 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
1473 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
1474 memcpy(&statp
->nsaddr_list
[nserv
],
1477 statp
->nsaddr_list
[nserv
].sin_family
= 0;
1482 size
= sizeof(set
->sin6
);
1483 if (statp
->_u
._ext
.ext
)
1484 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
1486 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
1487 memcpy(&statp
->nsaddr_list
[nserv
],
1490 statp
->nsaddr_list
[nserv
].sin_family
= 0;
1500 statp
->nscount
= nserv
;
1504 res_getservers(res_state statp
, union res_sockaddr_union
*set
, int cnt
) {
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
;
1513 family
= statp
->nsaddr_list
[i
].sin_family
;
1517 size
= sizeof(set
->sin
);
1518 if (statp
->_u
._ext
.ext
)
1520 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
1523 memcpy(&set
->sin
, &statp
->nsaddr_list
[i
],
1528 size
= sizeof(set
->sin6
);
1529 if (statp
->_u
._ext
.ext
)
1531 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
1534 memcpy(&set
->sin6
, &statp
->nsaddr_list
[i
],
1539 set
->sin
.sin_family
= 0;
1544 return (statp
->nscount
);