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.
134 res_build_start(res_state x
)
142 res
= res_state_new();
146 if ((x
->options
& RES_INIT
) != 0) res_ndestroy(x
);
150 if (res
== NULL
) return NULL
;
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
));
155 /* make sure version is set */
158 res
->retry
= RES_DFLRETRY
;
159 res
->options
= RES_DEFAULT
;
160 res
->id
= res_randomid();
165 if (res
->_u
._ext
.ext
!= NULL
)
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");
176 res_build_finish(res_state res
, uint32_t timeout
, uint16_t port
)
178 if (res
== NULL
) return -1;
180 if (res
->nscount
== 0)
183 res
->nsaddr_list
[0].sin_addr
= inet_makeaddr(IN_LOOPBACKNET
, 1);
185 res
->nsaddr_list
[0].sin_addr
.s_addr
= INADDR_ANY
;
188 res
->nsaddr_list
[0].sin_family
= AF_INET
;
189 res
->nsaddr_list
[0].sin_port
= htons(port
);
191 res
->nsaddr_list
[0].sin_len
= sizeof(struct sockaddr_in
);
197 * Force loopback queries to use TCP
198 * so we don't take a timeout if named isn't running.
200 res
->options
|= RES_USEVC
;
203 if (timeout
== 0) res
->retrans
= RES_MAXRETRANS
;
204 else res
->retrans
= timeout
;
206 res
->options
|= RES_INIT
;
211 res_build_sortlist(res_state res
, struct in_addr addr
, struct in_addr mask
)
215 if (res
== NULL
) return -1;
218 if (n
>= MAXRESOLVSORT
) return -1;
220 res
->sort_list
[n
].addr
= addr
;
221 res
->sort_list
[n
].mask
= mask
.s_addr
;
229 res_next_word(char **p
)
233 if (p
== NULL
) return NULL
;
234 if (*p
== NULL
) return NULL
;
238 /* Skip leading white space */
239 while ((*s
== ' ') || (*s
== '\t') || (*s
== '\n')) s
++;
242 if (*s
== '\0') return NULL
;
244 /* Find end of word */
246 while ((*x
!= ' ') && (*x
!= '\t') && (*x
!= '\n') && (*x
!= '\0')) x
++;
255 if (s
== x
) return NULL
;
260 res_build(res_state res
, uint16_t port
, uint32_t *nsrch
, char *key
, char *val
)
262 int32_t dotcount
, semicount
, status
;
266 struct in_addr addr4
, mask
;
267 struct sockaddr_in sin4
;
268 struct in6_addr addr6
;
269 struct sockaddr_in6 sin6
;
271 if (res
== NULL
) return -1;
273 if (!strcmp(key
, "domain"))
275 strncpy(res
->defdname
, val
, sizeof(res
->defdname
) - 1);
276 res
->defdname
[sizeof(res
->defdname
) - 1] = '\0';
280 else if (!strcmp(key
, "search"))
282 len
= strlen(val
) + 1;
283 ival
= sizeof(res
->defdname
);
288 memset(res
->defdname
, 0, sizeof(res
->defdname
));
292 p
= res
->dnsrch
[*nsrch
- 1];
293 for (; (ival
> 0) && (*p
!= '\0'); ival
--) p
++;
297 if (len
> ival
) return -1;
300 res
->dnsrch
[*nsrch
] = p
;
305 else if (!strcmp(key
, "nameserver"))
312 for (p
= val
; *p
!= '\0'; p
++)
314 if (*p
== ':') semicount
++;
322 if ((dotcount
== 4) || ((semicount
> 0) && (lastdot
!= NULL
)))
324 aport
= atoi(lastdot
+ 1);
325 if (aport
== 0) aport
= port
;
329 memset(&addr4
, 0, sizeof(struct in_addr
));
330 memset(&sin4
, 0, sizeof(struct sockaddr_in
));
332 memset(&addr6
, 0, sizeof(struct in6_addr
));
333 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
335 status
= inet_pton(AF_INET6
, val
, &addr6
);
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
)
344 memcpy(&(res
->_u
._ext
.ext
->nsaddrs
[res
->nscount
]), &sin6
, sizeof(struct sockaddr_in6
));
346 res
->nsaddr_list
[res
->nscount
].sin_family
= 0;
351 status
= inet_pton(AF_INET
, val
, &addr4
);
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
)
360 memcpy(&(res
->_u
._ext
.ext
->nsaddrs
[res
->nscount
]), &sin4
, sizeof(struct sockaddr_in
));
362 memcpy(&(res
->nsaddr_list
[res
->nscount
]), &sin4
, sizeof(struct sockaddr_in
));
370 else if (!strcmp(key
, "sortlist"))
372 p
= strchr(val
, '/');
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;
385 if (p
!= NULL
) status
= inet_aton(p
, &mask
);
388 ival
= ntohl(addr4
.s_addr
);
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
);
395 return res_build_sortlist(res
, addr4
, mask
);
398 else if (!strcmp(key
, "ndots"))
401 if (ival
< 0) ival
= 0;
402 if (ival
> RES_MAXNDOTS
) ival
= RES_MAXNDOTS
;
407 else if (!strcmp(key
, "nibble"))
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
);
415 else if (!strcmp(key
, "nibble2"))
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
);
423 else if (!strcmp(key
, "bitstring"))
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
);
431 else if (!strcmp(key
, "attempts"))
434 if (ival
< 0) ival
= 0;
435 if (ival
> RES_MAXRETRY
) ival
= RES_MAXRETRY
;
440 else if (!strcmp(key
, "v6revmode"))
442 if (!strcmp(val
, "single")) res
->options
|= RES_NO_NIBBLE2
;
443 else if (!strcmp(val
, "both")) res
->options
&= ~RES_NO_NIBBLE2
;
447 else if (!strcmp(key
, "debug"))
449 res
->options
|= RES_DEBUG
;
453 else if (!strcmp(key
, "no_tld_query"))
455 res
->options
|= RES_NOTLDQUERY
;
459 else if (!strcmp(key
, "inet6"))
461 res
->options
|= RES_USE_INET6
;
465 else if (!strcmp(key
, "rotate"))
467 res
->options
|= RES_ROTATE
;
471 else if (!strcmp(key
, "no-check-names"))
473 res
->options
|= RES_NOCHECKNAME
;
478 else if (!strcmp(key
, "edns0"))
480 res
->options
|= RES_USE_EDNS0
;
485 else if (!strcmp(key
, "a6"))
487 res
->options
|= RES_USE_A6
;
491 else if (!strcmp(key
, "dname"))
493 res
->options
|= RES_USE_DNAME
;
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().
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.
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.
519 * Return 0 if completes successfully, -1 on error
523 res_vinit_from_file(res_state statp
, int preinit
, char *resconf_file
)
526 register char *cp
, **pp
;
529 int nserv
= 0; /* number of nameserver records read from file */
532 int isresdefault
= 0;
533 unsigned short port
; /* HOST BYTE ORDER */
534 unsigned int i
, total_timeout
;
541 port
= NS_DEFAULTPORT
;
546 statp
->retrans
= RES_TIMEOUT
;
547 statp
->retry
= RES_DFLRETRY
;
548 statp
->options
= RES_DEFAULT
;
549 statp
->id
= res_randomid();
552 if ((statp
->options
& RES_INIT
) != 0) res_ndestroy(statp
);
554 /* N.B. we allocate a new statp->_u._ext.ext below */
556 /* make sure version is set */
561 if ((resconf_file
== NULL
) || (!strcmp(resconf_file
, _PATH_RESCONF
)))
566 statp
->nsaddr
.sin_addr
= inet_makeaddr(IN_LOOPBACKNET
, 1);
568 statp
->nsaddr
.sin_addr
.s_addr
= INADDR_ANY
;
570 statp
->nsaddr
.sin_family
= AF_INET
;
571 statp
->nsaddr
.sin_port
= htons(NS_DEFAULTPORT
);
573 statp
->nsaddr
.sin_len
= sizeof(struct sockaddr_in
);
578 * Force loopback queries to use TCP
579 * so we don't take a timeout if named isn't running.
581 statp
->options
|= RES_USEVC
;
591 statp
->_u
._ext
.nscount
= 0;
592 statp
->_u
._ext
.ext
= (struct __res_state_ext
*)calloc(1, sizeof(struct __res_state_ext
));
594 if (statp
->_u
._ext
.ext
!= NULL
)
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");
607 /* Allow user to override the local domain definition */
608 cp
= getenv("LOCALDOMAIN");
609 if ((cp
!= NULL
) && (isresdefault
!= 0))
611 (void)strncpy(statp
->defdname
, cp
, sizeof(statp
->defdname
) - 1);
612 statp
->defdname
[sizeof(statp
->defdname
) - 1] = '\0';
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)
622 cp
= statp
->defdname
;
625 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++)
627 if (*cp
== '\n') break;
628 else if (*cp
== ' ' || *cp
== '\t')
641 /* null terminate last domain if there are excess */
642 while ((*cp
!= '\0') && (*cp
!= ' ') && (*cp
!= '\t') && (*cp
!= '\n')) cp
++;
647 #define MATCH(line, name) \
648 (!strncmp(line, name, sizeof(name) - 1) && \
649 (line[sizeof(name) - 1] == ' ' || \
650 line[sizeof(name) - 1] == '\t'))
652 if (resconf_file
== NULL
) resconf_file
= _PATH_RESCONF
;
654 if ((fp
= fopen(resconf_file
, "r")) != NULL
)
656 /* look for port number */
657 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
660 if (*buf
== ';' || *buf
== '#') continue;
662 /* read default domain name */
663 if (MATCH(buf
, "port"))
665 cp
= buf
+ sizeof("port") - 1;
666 while (*cp
== ' ' || *cp
== '\t') cp
++;
667 if ((*cp
== '\0') || (*cp
== '\n')) continue;
675 if ((fp
= fopen(resconf_file
, "r")) != NULL
)
677 /* read the config file */
678 while (fgets(buf
, sizeof(buf
), fp
) != NULL
)
681 if ((*buf
== ';') || (*buf
== '#')) continue;
683 /* read default domain name */
684 if (MATCH(buf
, "domain"))
686 /* skip if have from environ */
687 if (haveenv
) continue;
689 cp
= buf
+ sizeof("domain") - 1;
690 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
691 if ((*cp
== '\0') || (*cp
== '\n')) continue;
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';
701 /* set search list */
702 if (MATCH(buf
, "search"))
704 /* skip if have from environ */
705 if (haveenv
) continue;
707 cp
= buf
+ sizeof("search") - 1;
708 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
709 if ((*cp
== '\0') || (*cp
== '\n')) continue;
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';
717 * Set search list to be blank-separated strings
720 cp
= statp
->defdname
;
723 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++)
725 if ((*cp
== ' ') || (*cp
== '\t'))
737 /* null terminate last domain if there are excess */
738 while ((*cp
!= '\0') && (*cp
!= ' ') && (*cp
!= '\t')) cp
++;
745 /* read nameservers to query */
746 if (MATCH(buf
, "nameserver") && (nserv
< MAXNS
))
749 struct addrinfo hints
, *ai
;
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
];
760 const size_t minsiz
= sizeof(statp
->_u
._ext
.ext
->nsaddrs
[0]);
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'))
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
;
779 for (checkp
= cp
; *checkp
!= '\0'; checkp
++)
781 if (*checkp
== ':') semicount
++;
782 else if (*checkp
== '.')
789 if ((dotcount
== 4) || ((semicount
> 0) && (lastdot
!= NULL
)))
791 aport
= atoi(lastdot
+ 1);
792 if (aport
== 0) aport
= port
;
796 sprintf(sbuf
, "%u", aport
);
799 memset(&addr4
, 0, sizeof(struct in_addr
));
800 memset(&sin4
, 0, sizeof(struct sockaddr_in
));
802 memset(&addr6
, 0, sizeof(struct in6_addr
));
803 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
805 status
= inet_pton(AF_INET6
, cp
, &addr6
);
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
)
814 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], &sin6
, sizeof(struct sockaddr_in6
));
816 statp
->nsaddr_list
[nserv
].sin_family
= 0;
821 status
= inet_pton(AF_INET
, cp
, &addr4
);
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
)
830 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], &sin4
, sizeof(struct sockaddr_in
));
832 memcpy(&statp
->nsaddr_list
[nserv
], &sin4
, sizeof(struct sockaddr_in
));
839 if (getaddrinfo(cp
, sbuf
, &hints
, &ai
) == 0 && ai
->ai_addrlen
<= minsiz
)
841 if (statp
->_u
._ext
.ext
!= NULL
)
843 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
], ai
->ai_addr
, ai
->ai_addrlen
);
846 if (ai
->ai_addrlen
<= sizeof(statp
->nsaddr_list
[nserv
]))
848 memcpy(&statp
->nsaddr_list
[nserv
], ai
->ai_addr
, ai
->ai_addrlen
);
852 statp
->nsaddr_list
[nserv
].sin_family
= 0;
865 if (MATCH(buf
, "sortlist"))
869 cp
= buf
+ sizeof("sortlist") - 1;
870 while (nsort
< MAXRESOLVSORT
)
872 while ((*cp
== ' ') || (*cp
== '\t')) cp
++;
873 if ((*cp
== '\0') || (*cp
== '\n') || (*cp
== ';')) break;
876 while (*cp
&& !ISSORTMASK(*cp
) && (*cp
!= ';') && isascii(*cp
) && !isspace((unsigned char)*cp
)) cp
++;
879 if (inet_aton(net
, &a
))
881 statp
->sort_list
[nsort
].addr
= a
;
886 while (*cp
&& (*cp
!= ';') && isascii(*cp
) && !isspace((unsigned char)*cp
)) cp
++;
889 if (inet_aton(net
, &a
))
891 statp
->sort_list
[nsort
].mask
= a
.s_addr
;
895 statp
->sort_list
[nsort
].mask
= net_mask(statp
->sort_list
[nsort
].addr
);
900 statp
->sort_list
[nsort
].mask
= net_mask(statp
->sort_list
[nsort
].addr
);
912 if (MATCH(buf
, "options"))
914 res_setoptions(statp
, buf
+ sizeof("options") - 1, "conf");
918 if (MATCH(buf
, "timeout"))
920 cp
= buf
+ sizeof("timeout") - 1;
921 while (*cp
== ' ' || *cp
== '\t') cp
++;
922 if ((*cp
== '\0') || (*cp
== '\n')) continue;
924 if (i
> RES_MAXRETRANS
) i
= RES_MAXRETRANS
;
930 if (nserv
> 1) statp
->nscount
= nserv
;
932 statp
->nsort
= nsort
;
938 * Last chance to get a nameserver. This should not normally
941 #ifdef NO_RESOLV_CONF
942 if(nserv
== 0) nserv
= get_nameservers(statp
);
945 if (isresdefault
!= 0)
947 if ((statp
->defdname
[0] == 0) && (gethostname(buf
, sizeof(statp
->defdname
) - 1) == 0) && ((cp
= strchr(buf
, '.')) != NULL
))
949 strcpy(statp
->defdname
, cp
+ 1);
953 /* find components of local domain that might be searched */
957 *pp
++ = statp
->defdname
;
961 for (cp
= statp
->defdname
; *cp
; cp
++)
963 if (*cp
== '.') dots
++;
966 /* Back up over any trailing dots and cut them out of the name */
967 for (cp
--; (cp
>= statp
->defdname
) && (*cp
== '.'); cp
--)
973 cp
= statp
->defdname
;
974 while (pp
< statp
->dnsrch
+ MAXDFLSRCH
)
976 if (dots
< LOCALDOMAINPARTS
) break;
978 /* we know there is a dot */
979 cp
= strchr(cp
, '.') + 1;
986 if (statp
->options
& RES_DEBUG
)
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");
995 cp
= getenv("RES_OPTIONS");
996 if ((cp
!= NULL
) && (isresdefault
!= 0))
998 res_setoptions(statp
, cp
, "env");
1003 * Post processing to set the timeout value.
1005 if (total_timeout
!= 0)
1007 /* Timeout was set with a "timeout" line in the file */
1008 statp
->retrans
= total_timeout
;
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.
1018 total_timeout
= statp
->retrans
* (statp
->retry
+ 1) * statp
->nscount
;
1019 statp
->retrans
= total_timeout
;
1023 statp
->options
|= RES_INIT
;
1028 res_setoptions(res_state statp
, const char *options
, const char *source
)
1030 const char *cp
= options
;
1032 struct __res_state_ext
*ext
= statp
->_u
._ext
.ext
;
1035 if (statp
->options
& RES_DEBUG
)
1036 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
1040 /* skip leading and inner runs of spaces */
1041 while (*cp
== ' ' || *cp
== '\t')
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
)
1049 statp
->ndots
= RES_MAXNDOTS
;
1051 if (statp
->options
& RES_DEBUG
)
1052 printf(";;\tndots=%d\n", statp
->ndots
);
1054 } else if (!strncmp(cp
, "timeout:", sizeof("timeout:") - 1)) {
1055 i
= atoi(cp
+ sizeof("timeout:") - 1);
1056 if (i
<= RES_MAXRETRANS
)
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
)
1065 statp
->retry
= RES_MAXRETRY
;
1066 } else if (!strncmp(cp
, "debug", sizeof("debug") - 1)) {
1068 if (!(statp
->options
& RES_DEBUG
)) {
1069 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
1071 statp
->options
|= RES_DEBUG
;
1073 printf(";;\tdebug\n");
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
;
1088 #ifdef RES_USE_EDNS0
1089 else if (!strncmp(cp
, "edns0", sizeof("edns0") - 1)) {
1090 statp
->options
|= RES_USE_EDNS0
;
1093 else if (!strncmp(cp
, "a6", sizeof("a6") - 1)) {
1094 statp
->options
|= RES_USE_A6
;
1096 else if (!strncmp(cp
, "dname", sizeof("dname") - 1)) {
1097 statp
->options
|= RES_USE_DNAME
;
1099 else if (!strncmp(cp
, "nibble:", sizeof("nibble:") - 1)) {
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';
1107 else if (!strncmp(cp
, "nibble2:", sizeof("nibble2:") - 1)) {
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';
1115 else if (!strncmp(cp
, "bitstring:", sizeof("bitstring:") - 1)) {
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';
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)) {
1134 /* XXX - print a warning here? */
1137 /* skip to next run of spaces */
1138 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
1143 /* This function has to be reachable by res_data.c but not publically. */
1145 __res_vinit(res_state statp
, int preinit
)
1147 dns_config_t
*sc_dns
;
1148 dns_resolver_t
*sc_res
;
1149 char val
[256], *p
, *x
;
1151 uint32_t nsearch
, total_timeout
, send_timeout
;
1157 sc_dns
= dns_configuration_copy();
1158 if (sc_dns
== NULL
) return res_vinit_from_file(statp
, preinit
, _PATH_RESCONF
);
1160 sc_res
= sc_dns
->resolver
[0];
1161 port
= sc_res
->port
;
1162 if (port
== 0) port
= NS_DEFAULTPORT
;
1164 if ((statp
->options
& RES_INIT
) != 0) res_ndestroy(statp
);
1166 /* N.B. res_build_start will allocate statp->_u._ext.ext for us */
1167 statp
= res_build_start(statp
);
1169 p
= getenv("RES_RETRY_TIMEOUT");
1170 if (p
!= NULL
) send_timeout
= atoi(p
);
1172 p
= getenv("RES_RETRY");
1173 if (p
!= NULL
) statp
->retry
= atoi(p
);
1175 if (sc_res
->n_nameserver
> MAXNS
) sc_res
->n_nameserver
= MAXNS
;
1176 for (i
= 0; i
< sc_res
->n_nameserver
; i
++)
1178 if (sc_res
->nameserver
[i
]->sa_family
== AF_INET
)
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
);
1184 else if (sc_res
->nameserver
[i
]->sa_family
== AF_INET6
)
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
);
1192 if (sc_res
->n_search
> MAXDNSRCH
) sc_res
->n_search
= MAXDNSRCH
;
1193 for (i
= 0; i
< sc_res
->n_search
; i
++)
1195 res_build(statp
, port
, &nsearch
, "search", sc_res
->search
[i
]);
1198 /* If there was no search list, use "domain" */
1199 if ((sc_res
->n_search
== 0) && (sc_res
->domain
!= NULL
))
1203 for (p
= sc_res
->domain
; *p
!= '\0'; p
++)
1208 /* Back up over any trailing dots and cut them out of the name */
1209 for (p
--; (p
>= sc_res
->domain
) && (*p
== '.'); p
--)
1215 if (p
>= sc_res
->domain
) res_build(statp
, port
, &nsearch
, "search", sc_res
->domain
);
1217 /* dots are separators, so number of components is one larger */
1220 /* Include parent domains with at least LOCALDOMAINPARTS components */
1222 while ((n
> LOCALDOMAINPARTS
) && (nsearch
< MAXDFLSRCH
))
1224 /* Find next component */
1225 while (*p
!= '.') p
++;
1226 if (*p
== '\0') break;
1230 res_build(statp
, port
, &nsearch
, "search", p
);
1234 total_timeout
= sc_res
->timeout
;
1236 snprintf(val
, sizeof(val
), "%d", sc_res
->search_order
);
1237 res_build(statp
, port
, &nsearch
, "search_order", val
);
1239 if (sc_res
->n_sortaddr
> MAXRESOLVSORT
) sc_res
->n_sortaddr
= MAXRESOLVSORT
;
1240 for (i
= 0; i
< sc_res
->n_sortaddr
; i
++)
1242 res_build_sortlist(statp
, sc_res
->sortaddr
[i
]->address
, sc_res
->sortaddr
[i
]->mask
);
1245 p
= sc_res
->options
;
1246 while (NULL
!= (x
= res_next_word(&p
)))
1248 if (!strncmp(x
, "ndots:", 6))
1250 res_build(statp
, port
, &nsearch
, "ndots", x
+6);
1253 else if (!strncmp(x
, "nibble:", 7))
1255 res_build(statp
, port
, &nsearch
, "nibble", x
+7);
1258 else if (!strncmp(x
, "nibble2:", 8))
1260 res_build(statp
, port
, &nsearch
, "nibble2", x
+8);
1263 else if (!strncmp(x
, "timeout:", 8))
1265 send_timeout
= atoi(x
+8);
1268 else if (!strncmp(x
, "attempts:", 9))
1270 res_build(statp
, port
, &nsearch
, "attempts", x
+9);
1273 else if (!strncmp(x
, "bitstring:", 10))
1275 res_build(statp
, port
, &nsearch
, "bitstring", x
+10);
1278 else if (!strncmp(x
, "v6revmode:", 10))
1280 res_build(statp
, port
, &nsearch
, "v6revmode", x
+10);
1283 else if (!strcmp(x
, "debug"))
1285 res_build(statp
, port
, &nsearch
, "debug", NULL
);
1288 else if (!strcmp(x
, "no_tld_query"))
1290 res_build(statp
, port
, &nsearch
, "no_tld_query", NULL
);
1293 else if (!strcmp(x
, "inet6"))
1295 res_build(statp
, port
, &nsearch
, "inet6", NULL
);
1298 else if (!strcmp(x
, "rotate"))
1300 res_build(statp
, port
, &nsearch
, "rotate", NULL
);
1303 else if (!strcmp(x
, "no-check-names"))
1305 res_build(statp
, port
, &nsearch
, "no-check-names", NULL
);
1308 #ifdef RES_USE_EDNS0
1309 else if (!strcmp(x
, "edns0"))
1311 res_build(statp
, port
, &nsearch
, "edns0", NULL
);
1314 else if (!strcmp(x
, "a6"))
1316 res_build(statp
, port
, &nsearch
, "a6", NULL
);
1319 else if (!strcmp(x
, "dname"))
1321 res_build(statp
, port
, &nsearch
, "dname", NULL
);
1328 if (total_timeout
== 0)
1330 if (send_timeout
== 0) total_timeout
= RES_MAXRETRANS
;
1331 else total_timeout
= send_timeout
* statp
->retry
* n
;
1334 dns_configuration_free(sc_dns
);
1336 res_build_finish(statp
, total_timeout
, port
);
1342 res_ninit(res_state statp
)
1344 if (statp
== NULL
) return -1;
1345 memset(statp
, 0, sizeof(struct __res_state
));
1346 return __res_vinit(statp
, 0);
1350 /* XXX - should really support CIDR which means explicit masks always. */
1352 net_mask(in
) /* XXX - should really use system's version of this */
1355 register u_int32_t i
= ntohl(in
.s_addr
);
1358 return (htonl(IN_CLASSA_NET
));
1359 else if (IN_CLASSB(i
))
1360 return (htonl(IN_CLASSB_NET
));
1361 return (htonl(IN_CLASSC_NET
));
1369 return arc4random();
1372 gettimeofday(&now
, NULL
);
1373 return (0xffff & (now
.tv_sec
^ now
.tv_usec
^ getpid()));
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.
1382 * This routine is not expected to be user visible.
1385 res_nclose(res_state statp
)
1389 if (statp
->_vcsock
>= 0)
1391 close(statp
->_vcsock
);
1392 statp
->_vcsock
= -1;
1393 statp
->_flags
&= ~(RES_F_VC
| RES_F_CONN
);
1396 if (statp
->_pad
>= 9)
1398 for (ns
= 0; ns
< statp
->_u
._ext
.nscount
; ns
++)
1400 if (statp
->_u
._ext
.nssocks
[ns
] != -1)
1402 close(statp
->_u
._ext
.nssocks
[ns
]);
1403 statp
->_u
._ext
.nssocks
[ns
] = -1;
1410 res_ndestroy(res_state statp
)
1413 statp
->options
&= ~RES_INIT
;
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.
1420 if (statp
->_pad
>= 9)
1422 if (statp
->_u
._ext
.ext
!= NULL
) free(statp
->_u
._ext
.ext
);
1423 statp
->_u
._ext
.ext
= NULL
;
1429 res_get_nibblesuffix(res_state statp
) {
1430 if (statp
->_u
._ext
.ext
)
1431 return (statp
->_u
._ext
.ext
->nsuffix
);
1432 return ("ip6.arpa");
1436 res_get_nibblesuffix2(res_state statp
) {
1437 if (statp
->_u
._ext
.ext
)
1438 return (statp
->_u
._ext
.ext
->nsuffix2
);
1443 res_get_bitstringsuffix(res_state statp
) {
1444 if (statp
->_u
._ext
.ext
)
1445 return (statp
->_u
._ext
.ext
->bsuffix
);
1446 return ("ip6.arpa");
1450 res_setservers(res_state statp
, const union res_sockaddr_union
*set
, int cnt
) {
1454 /* close open servers */
1457 /* cause rtt times to be forgotten */
1458 statp
->_u
._ext
.nscount
= 0;
1461 for (i
= 0; i
< cnt
&& nserv
< MAXNS
; i
++) {
1462 switch (set
->sin
.sin_family
) {
1464 size
= sizeof(set
->sin
);
1465 if (statp
->_u
._ext
.ext
)
1466 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
1468 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
1469 memcpy(&statp
->nsaddr_list
[nserv
],
1472 statp
->nsaddr_list
[nserv
].sin_family
= 0;
1477 size
= sizeof(set
->sin6
);
1478 if (statp
->_u
._ext
.ext
)
1479 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
1481 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
1482 memcpy(&statp
->nsaddr_list
[nserv
],
1485 statp
->nsaddr_list
[nserv
].sin_family
= 0;
1495 statp
->nscount
= nserv
;
1499 res_getservers(res_state statp
, union res_sockaddr_union
*set
, int cnt
) {
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
;
1508 family
= statp
->nsaddr_list
[i
].sin_family
;
1512 size
= sizeof(set
->sin
);
1513 if (statp
->_u
._ext
.ext
)
1515 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
1518 memcpy(&set
->sin
, &statp
->nsaddr_list
[i
],
1523 size
= sizeof(set
->sin6
);
1524 if (statp
->_u
._ext
.ext
)
1526 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
1529 memcpy(&set
->sin6
, &statp
->nsaddr_list
[i
],
1534 set
->sin
.sin_family
= 0;
1539 return (statp
->nscount
);