1 /* $NetBSD: res_init.c,v 1.21 2009/10/24 05:35:37 christos Exp $ */
4 * Copyright (c) 1985, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
39 * Permission to use, copy, modify, and distribute this software for any
40 * purpose with or without fee is hereby granted, provided that the above
41 * copyright notice and this permission notice appear in all copies, and that
42 * the name of Digital Equipment Corporation not be used in advertising or
43 * publicity pertaining to distribution of the document or software without
44 * specific, written prior permission.
46 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
47 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
49 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
50 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
51 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
52 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
57 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
58 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
60 * Permission to use, copy, modify, and distribute this software for any
61 * purpose with or without fee is hereby granted, provided that the above
62 * copyright notice and this permission notice appear in all copies.
64 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
65 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
66 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
67 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
68 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
69 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
70 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
73 #include <sys/cdefs.h>
74 #if defined(LIBC_SCCS) && !defined(lint)
76 static const char sccsid
[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
77 static const char rcsid
[] = "Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp";
79 __RCSID("$NetBSD: res_init.c,v 1.21 2009/10/24 05:35:37 christos Exp $");
81 #endif /* LIBC_SCCS and not lint */
83 #include "port_before.h"
85 #include "namespace.h"
86 #include <sys/types.h>
87 #include <sys/param.h>
88 #include <sys/socket.h>
91 #include <sys/event.h>
93 #include <netinet/in.h>
94 #include <arpa/inet.h>
95 #include <arpa/nameser.h>
109 # include "../dst/md5.h"
112 # include <sys/md5.h>
116 # define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
119 #include "port_after.h"
123 __weak_alias(res_ninit
,_res_ninit
)
124 __weak_alias(res_randomid
,__res_randomid
)
125 __weak_alias(res_nclose
,_res_nclose
)
126 __weak_alias(res_ndestroy
,_res_ndestroy
)
127 __weak_alias(res_get_nibblesuffix
,__res_get_nibblesuffix
)
128 __weak_alias(res_get_nibblesuffix2
,__res_get_nibblesuffix2
)
129 __weak_alias(res_getservers
,__res_getservers
)
130 __weak_alias(res_setservers
,__res_setservers
)
135 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
138 #include "res_private.h"
141 /*% Options. Should all be left alone. */
147 #include <sys/systeminfo.h>
150 static void res_setoptions
__P((res_state
, const char *, const char *));
153 static const char sort_mask
[] = "/&";
154 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
155 static u_int32_t net_mask
__P((struct in_addr
));
158 #if !defined(isascii) /*%< XXX - could be a function */
159 # define isascii(c) (!(c & 0200))
162 static struct timespec __res_conf_time
;
163 static const struct timespec ts
= { 0, 0 };
166 * Resolver state default settings.
170 * Set up default settings. If the configuration file exist, the values
171 * there will have precedence. Otherwise, the server address is set to
172 * INADDR_ANY and the default domain name comes from the gethostname().
174 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
175 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
176 * since it was noted that INADDR_ANY actually meant ``the first interface
177 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
178 * it had to be "up" in order for you to reach your own name server. It
179 * was later decided that since the recommended practice is to always
180 * install local static routes through 127.0.0.1 for all your network
181 * interfaces, that we could solve this problem without a code change.
183 * The configuration file should always be used, since it is the only way
184 * to specify a default domain. If you are running a server on your local
185 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
186 * in the configuration file.
188 * Return 0 if completes successfully, -1 on error
191 res_ninit(res_state statp
) {
192 return (__res_vinit(statp
, 0));
195 /*% This function has to be reachable by res_data.c but not publically. */
197 __res_vinit(res_state statp
, int preinit
) {
199 register char *cp
, **pp
;
202 int nserv
= 0; /*%< number of nameserver records read from file */
210 union res_sockaddr_union u
[2];
213 RES_SET_H_ERRNO(statp
, 0);
215 if ((statp
->options
& RES_INIT
) != 0U)
219 statp
->retrans
= RES_TIMEOUT
;
220 statp
->retry
= RES_DFLRETRY
;
221 statp
->options
= RES_DEFAULT
;
223 statp
->_rnd
= malloc(16);
225 statp
->id
= res_nrandomid(statp
);
227 memset(u
, 0, sizeof(u
));
229 u
[nserv
].sin
.sin_addr
= inet_makeaddr(IN_LOOPBACKNET
, 1);
231 u
[nserv
].sin
.sin_addr
.s_addr
= INADDR_ANY
;
233 u
[nserv
].sin
.sin_family
= AF_INET
;
234 u
[nserv
].sin
.sin_port
= htons(NAMESERVER_PORT
);
236 u
[nserv
].sin
.sin_len
= sizeof(struct sockaddr_in
);
239 #ifdef HAS_INET6_STRUCTS
241 u
[nserv
].sin6
.sin6_addr
= in6addr_loopback
;
243 u
[nserv
].sin6
.sin6_addr
= in6addr_any
;
245 u
[nserv
].sin6
.sin6_family
= AF_INET6
;
246 u
[nserv
].sin6
.sin6_port
= htons(NAMESERVER_PORT
);
248 u
[nserv
].sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
259 statp
->_u
._ext
.nscount
= 0;
260 statp
->_u
._ext
.ext
= malloc(sizeof(*statp
->_u
._ext
.ext
));
261 if (statp
->_u
._ext
.ext
!= NULL
) {
262 memset(statp
->_u
._ext
.ext
, 0, sizeof(*statp
->_u
._ext
.ext
));
263 statp
->_u
._ext
.ext
->nsaddrs
[0].sin
= statp
->nsaddr
;
264 strcpy(statp
->_u
._ext
.ext
->nsuffix
, "ip6.arpa");
265 strcpy(statp
->_u
._ext
.ext
->nsuffix2
, "ip6.int");
268 * Historically res_init() rarely, if at all, failed.
269 * Examples and applications exist which do not check
270 * our return code. Furthermore several applications
271 * simply call us to get the systems domainname. So
272 * rather then immediately fail here we store the
273 * failure, which is returned later, in h_errno. And
274 * prevent the collection of 'nameserver' information
275 * by setting maxns to 0. Thus applications that fail
276 * to check our return code wont be able to make
279 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
285 res_setservers(statp
, u
, nserv
);
289 * The old libresolv derived the defaultdomain from NIS/NIS+.
290 * We want to keep this behaviour
293 char buf
[sizeof(statp
->defdname
)], *cp
;
296 if ((ret
= sysinfo(SI_SRPC_DOMAIN
, buf
, sizeof(buf
))) > 0 &&
297 (unsigned int)ret
<= sizeof(buf
)) {
300 cp
= strchr(buf
, '.');
301 cp
= (cp
== NULL
) ? buf
: (cp
+ 1);
302 (void)strlcpy(statp
->defdname
, cp
,
303 sizeof(statp
->defdname
));
306 #endif /* SOLARIS2 */
308 /* Allow user to override the local domain definition */
309 if ((cp
= getenv("LOCALDOMAIN")) != NULL
) {
310 (void)strncpy(statp
->defdname
, cp
, sizeof(statp
->defdname
) - 1);
311 statp
->defdname
[sizeof(statp
->defdname
) - 1] = '\0';
315 * Set search list to be blank-separated strings
316 * from rest of env value. Permits users of LOCALDOMAIN
317 * to still have a search list, and anyone to set the
318 * one that they want to use as an individual (even more
319 * important now that the rfc1535 stuff restricts searches)
321 cp
= statp
->defdname
;
324 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++) {
325 if (*cp
== '\n') /*%< silly backwards compat */
327 else if (*cp
== ' ' || *cp
== '\t') {
336 /* null terminate last domain if there are excess */
337 while (*cp
!= '\0' && *cp
!= ' ' && *cp
!= '\t' && *cp
!= '\n')
343 #define MATCH(line, name) \
344 (!strncmp(line, name, sizeof(name) - 1) && \
345 (line[sizeof(name) - 1] == ' ' || \
346 line[sizeof(name) - 1] == '\t'))
349 if ((fp
= fopen(_PATH_RESCONF
, "r")) != NULL
) {
353 /* read the config file */
354 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
356 if (*buf
== ';' || *buf
== '#')
358 /* read default domain name */
359 if (MATCH(buf
, "domain")) {
360 if (haveenv
) /*%< skip if have from environ */
362 cp
= buf
+ sizeof("domain") - 1;
363 while (*cp
== ' ' || *cp
== '\t')
365 if ((*cp
== '\0') || (*cp
== '\n'))
367 strncpy(statp
->defdname
, cp
, sizeof(statp
->defdname
) - 1);
368 statp
->defdname
[sizeof(statp
->defdname
) - 1] = '\0';
369 if ((cp
= strpbrk(statp
->defdname
, " \t\n")) != NULL
)
374 /* set search list */
375 if (MATCH(buf
, "search")) {
376 if (haveenv
) /*%< skip if have from environ */
378 cp
= buf
+ sizeof("search") - 1;
379 while (*cp
== ' ' || *cp
== '\t')
381 if ((*cp
== '\0') || (*cp
== '\n'))
383 strncpy(statp
->defdname
, cp
, sizeof(statp
->defdname
) - 1);
384 statp
->defdname
[sizeof(statp
->defdname
) - 1] = '\0';
385 if ((cp
= strchr(statp
->defdname
, '\n')) != NULL
)
388 * Set search list to be blank-separated strings
391 cp
= statp
->defdname
;
394 for (n
= 0; *cp
&& pp
< statp
->dnsrch
+ MAXDNSRCH
; cp
++) {
395 if (*cp
== ' ' || *cp
== '\t') {
403 /* null terminate last domain if there are excess */
404 while (*cp
!= '\0' && *cp
!= ' ' && *cp
!= '\t')
411 /* read nameservers to query */
412 if (MATCH(buf
, "nameserver") && nserv
< maxns
) {
413 struct addrinfo hints
, *ai
;
414 char sbuf
[NI_MAXSERV
];
415 const size_t minsiz
=
416 sizeof(statp
->_u
._ext
.ext
->nsaddrs
[0]);
418 cp
= buf
+ sizeof("nameserver") - 1;
419 while (*cp
== ' ' || *cp
== '\t')
421 cp
[strcspn(cp
, ";# \t\n")] = '\0';
422 if ((*cp
!= '\0') && (*cp
!= '\n')) {
423 memset(&hints
, 0, sizeof(hints
));
424 hints
.ai_family
= PF_UNSPEC
;
425 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
426 hints
.ai_flags
= AI_NUMERICHOST
;
427 sprintf(sbuf
, "%u", NAMESERVER_PORT
);
428 if (getaddrinfo(cp
, sbuf
, &hints
, &ai
) == 0 &&
429 ai
->ai_addrlen
<= minsiz
) {
430 if (statp
->_u
._ext
.ext
!= NULL
) {
431 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
432 ai
->ai_addr
, ai
->ai_addrlen
);
434 if (ai
->ai_addrlen
<=
435 sizeof(statp
->nsaddr_list
[nserv
])) {
436 memcpy(&statp
->nsaddr_list
[nserv
],
437 ai
->ai_addr
, ai
->ai_addrlen
);
439 statp
->nsaddr_list
[nserv
].sin_family
= 0;
447 if (MATCH(buf
, "sortlist")) {
450 cp
= buf
+ sizeof("sortlist") - 1;
451 while (nsort
< MAXRESOLVSORT
) {
452 while (*cp
== ' ' || *cp
== '\t')
454 if (*cp
== '\0' || *cp
== '\n' || *cp
== ';')
457 while (*cp
&& !ISSORTMASK(*cp
) && *cp
!= ';' &&
458 isascii(*cp
) && !isspace((unsigned char)*cp
))
462 if (inet_aton(net
, &a
)) {
463 statp
->sort_list
[nsort
].addr
= a
;
467 while (*cp
&& *cp
!= ';' &&
469 !isspace((unsigned char)*cp
))
473 if (inet_aton(net
, &a
)) {
474 statp
->sort_list
[nsort
].mask
= a
.s_addr
;
476 statp
->sort_list
[nsort
].mask
=
477 net_mask(statp
->sort_list
[nsort
].addr
);
480 statp
->sort_list
[nsort
].mask
=
481 net_mask(statp
->sort_list
[nsort
].addr
);
490 if (MATCH(buf
, "options")) {
491 res_setoptions(statp
, buf
+ sizeof("options") - 1, "conf");
496 statp
->nscount
= nserv
;
498 statp
->nsort
= nsort
;
500 statp
->_u
._ext
.ext
->resfd
= dup(fileno(fp
));
502 if (fstat(statp
->_u
._ext
.ext
->resfd
, &st
) != -1)
503 __res_conf_time
= statp
->_u
._ext
.ext
->res_conf_time
=
505 statp
->_u
._ext
.ext
->kq
= kqueue();
506 (void)fcntl(statp
->_u
._ext
.ext
->kq
, F_SETFD
, FD_CLOEXEC
);
507 (void)fcntl(statp
->_u
._ext
.ext
->resfd
, F_SETFD
, FD_CLOEXEC
);
508 EV_SET(&kc
, statp
->_u
._ext
.ext
->resfd
, EVFILT_VNODE
,
509 EV_ADD
|EV_ENABLE
|EV_CLEAR
, NOTE_DELETE
|NOTE_WRITE
| NOTE_EXTEND
|
510 NOTE_ATTRIB
|NOTE_LINK
|NOTE_RENAME
|NOTE_REVOKE
, 0, 0);
511 (void)kevent(statp
->_u
._ext
.ext
->kq
, &kc
, 1, NULL
, 0, &ts
);
513 statp
->_u
._ext
.ext
->kq
= -1;
514 statp
->_u
._ext
.ext
->resfd
= -1;
517 * Last chance to get a nameserver. This should not normally
520 #ifdef NO_RESOLV_CONF
522 nserv
= get_nameservers(statp
);
525 if (statp
->defdname
[0] == 0 &&
526 gethostname(buf
, sizeof(statp
->defdname
) - 1) == 0 &&
527 (cp
= strchr(buf
, '.')) != NULL
)
528 strcpy(statp
->defdname
, cp
+ 1);
530 /* find components of local domain that might be searched */
531 if (havesearch
== 0) {
533 *pp
++ = statp
->defdname
;
537 for (cp
= statp
->defdname
; *cp
; cp
++)
538 dots
+= (*cp
== '.');
540 cp
= statp
->defdname
;
541 while (pp
< statp
->dnsrch
+ MAXDFLSRCH
) {
542 if (dots
< LOCALDOMAINPARTS
)
544 cp
= strchr(cp
, '.') + 1; /*%< we know there is one */
550 if (statp
->options
& RES_DEBUG
) {
551 printf(";; res_init()... default dnsrch list:\n");
552 for (pp
= statp
->dnsrch
; *pp
; pp
++)
553 printf(";;\t%s\n", *pp
);
554 printf(";;\t..END..\n");
559 if ((cp
= getenv("RES_OPTIONS")) != NULL
)
560 res_setoptions(statp
, cp
, "env");
561 statp
->options
|= RES_INIT
;
562 return (statp
->res_h_errno
);
566 res_check(res_state statp
, struct timespec
*mtime
)
569 * If the times are equal, then we check if there
570 * was a kevent related to resolv.conf and reload.
571 * If the times are not equal, then we don't bother
572 * to check the kevent, because another thread already
573 * did, loaded and changed the time.
575 if (timespeccmp(&statp
->_u
._ext
.ext
->res_conf_time
,
576 &__res_conf_time
, ==)) {
578 if (statp
->_u
._ext
.ext
->kq
== -1)
581 switch (kevent(statp
->_u
._ext
.ext
->kq
, NULL
, 0, &ke
, 1, &ts
)) {
586 *mtime
= __res_conf_time
;
592 (void)__res_vinit(statp
, 0);
594 *mtime
= __res_conf_time
;
599 res_setoptions(res_state statp
, const char *options
, const char *source
)
601 const char *cp
= options
;
603 struct __res_state_ext
*ext
= statp
->_u
._ext
.ext
;
606 if (statp
->options
& RES_DEBUG
)
607 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
611 /* skip leading and inner runs of spaces */
612 while (*cp
== ' ' || *cp
== '\t')
614 /* search for and process individual options */
615 if (!strncmp(cp
, "ndots:", sizeof("ndots:") - 1)) {
616 i
= atoi(cp
+ sizeof("ndots:") - 1);
617 if (i
<= RES_MAXNDOTS
)
620 statp
->ndots
= RES_MAXNDOTS
;
622 if (statp
->options
& RES_DEBUG
)
623 printf(";;\tndots=%d\n", statp
->ndots
);
625 } else if (!strncmp(cp
, "timeout:", sizeof("timeout:") - 1)) {
626 i
= atoi(cp
+ sizeof("timeout:") - 1);
627 if (i
<= RES_MAXRETRANS
)
630 statp
->retrans
= RES_MAXRETRANS
;
632 if (statp
->options
& RES_DEBUG
)
633 printf(";;\ttimeout=%d\n", statp
->retrans
);
636 } else if (!strncmp(cp
, "retrans:", sizeof("retrans:") - 1)) {
638 * For backward compatibility, 'retrans' is
639 * supported as an alias for 'timeout', though
640 * without an imposed maximum.
642 statp
->retrans
= atoi(cp
+ sizeof("retrans:") - 1);
643 } else if (!strncmp(cp
, "retry:", sizeof("retry:") - 1)){
645 * For backward compatibility, 'retry' is
646 * supported as an alias for 'attempts', though
647 * without an imposed maximum.
649 statp
->retry
= atoi(cp
+ sizeof("retry:") - 1);
650 #endif /* SOLARIS2 */
651 } else if (!strncmp(cp
, "attempts:", sizeof("attempts:") - 1)){
652 i
= atoi(cp
+ sizeof("attempts:") - 1);
653 if (i
<= RES_MAXRETRY
)
656 statp
->retry
= RES_MAXRETRY
;
658 if (statp
->options
& RES_DEBUG
)
659 printf(";;\tattempts=%d\n", statp
->retry
);
661 } else if (!strncmp(cp
, "debug", sizeof("debug") - 1)) {
663 if (!(statp
->options
& RES_DEBUG
)) {
664 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
666 statp
->options
|= RES_DEBUG
;
668 printf(";;\tdebug\n");
670 } else if (!strncmp(cp
, "no_tld_query",
671 sizeof("no_tld_query") - 1) ||
672 !strncmp(cp
, "no-tld-query",
673 sizeof("no-tld-query") - 1)) {
674 statp
->options
|= RES_NOTLDQUERY
;
675 } else if (!strncmp(cp
, "inet6", sizeof("inet6") - 1)) {
676 statp
->options
|= RES_USE_INET6
;
677 } else if (!strncmp(cp
, "rotate", sizeof("rotate") - 1)) {
678 statp
->options
|= RES_ROTATE
;
679 } else if (!strncmp(cp
, "no-check-names",
680 sizeof("no-check-names") - 1)) {
681 statp
->options
|= RES_NOCHECKNAME
;
684 else if (!strncmp(cp
, "edns0", sizeof("edns0") - 1)) {
685 statp
->options
|= RES_USE_EDNS0
;
688 else if (!strncmp(cp
, "dname", sizeof("dname") - 1)) {
689 statp
->options
|= RES_USE_DNAME
;
691 else if (!strncmp(cp
, "nibble:", sizeof("nibble:") - 1)) {
694 cp
+= sizeof("nibble:") - 1;
695 i
= MIN(strcspn(cp
, " \t"), sizeof(ext
->nsuffix
) - 1);
696 strncpy(ext
->nsuffix
, cp
, (size_t)i
);
697 ext
->nsuffix
[i
] = '\0';
699 else if (!strncmp(cp
, "nibble2:", sizeof("nibble2:") - 1)) {
702 cp
+= sizeof("nibble2:") - 1;
703 i
= MIN(strcspn(cp
, " \t"), sizeof(ext
->nsuffix2
) - 1);
704 strncpy(ext
->nsuffix2
, cp
, (size_t)i
);
705 ext
->nsuffix2
[i
] = '\0';
707 else if (!strncmp(cp
, "v6revmode:", sizeof("v6revmode:") - 1)) {
708 cp
+= sizeof("v6revmode:") - 1;
709 /* "nibble" and "bitstring" used to be valid */
710 if (!strncmp(cp
, "single", sizeof("single") - 1)) {
711 statp
->options
|= RES_NO_NIBBLE2
;
712 } else if (!strncmp(cp
, "both", sizeof("both") - 1)) {
718 /* XXX - print a warning here? */
721 /* skip to next run of spaces */
722 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
728 /* XXX - should really support CIDR which means explicit masks always. */
730 net_mask(in
) /*!< XXX - should really use system's version of this */
733 register u_int32_t i
= ntohl(in
.s_addr
);
736 return (htonl(IN_CLASSA_NET
));
737 else if (IN_CLASSB(i
))
738 return (htonl(IN_CLASSB_NET
));
739 return (htonl(IN_CLASSC_NET
));
743 static u_char srnd
[16];
746 res_rndinit(res_state statp
)
751 u_char
*rnd
= statp
->_rnd
== NULL
? srnd
: statp
->_rnd
;
753 gettimeofday(&now
, NULL
);
754 u32
= (u_int32_t
)now
.tv_sec
;
755 memcpy(rnd
, &u32
, 4);
757 memcpy(rnd
+ 4, &u32
, 4);
758 u32
+= (u_int32_t
)now
.tv_sec
;
759 memcpy(rnd
+ 8, &u32
, 4);
761 memcpy(rnd
+ 12, &u16
, 2);
765 res_nrandomid(res_state statp
) {
769 u_char
*rnd
= statp
->_rnd
== NULL
? srnd
: statp
->_rnd
;
771 gettimeofday(&now
, NULL
);
772 u16
= (u_int16_t
) (now
.tv_sec
^ now
.tv_usec
);
773 memcpy(rnd
+ 14, &u16
, 2);
776 MD5_Update(&ctx
, rnd
, 16);
777 MD5_Final(rnd
, &ctx
);
780 MD5Update(&ctx
, rnd
, 16);
783 memcpy(&u16
, rnd
+ 14, 2);
784 return ((u_int
) u16
);
788 * This routine is for closing the socket if a virtual circuit is used and
789 * the program wants to close it. This provides support for endhostent()
790 * which expects to close the socket.
792 * This routine is not expected to be user visible.
795 res_nclose(res_state statp
) {
798 if (statp
->_vcsock
>= 0) {
799 (void) close(statp
->_vcsock
);
801 statp
->_flags
&= ~(RES_F_VC
| RES_F_CONN
);
803 for (ns
= 0; ns
< statp
->_u
._ext
.nscount
; ns
++) {
804 if (statp
->_u
._ext
.nssocks
[ns
] != -1) {
805 (void) close(statp
->_u
._ext
.nssocks
[ns
]);
806 statp
->_u
._ext
.nssocks
[ns
] = -1;
812 res_ndestroy(res_state statp
) {
814 if (statp
->_u
._ext
.ext
!= NULL
) {
815 if (statp
->_u
._ext
.ext
->kq
!= -1)
816 (void)close(statp
->_u
._ext
.ext
->kq
);
817 if (statp
->_u
._ext
.ext
->resfd
!= -1)
818 (void)close(statp
->_u
._ext
.ext
->resfd
);
819 free(statp
->_u
._ext
.ext
);
820 statp
->_u
._ext
.ext
= NULL
;
822 if (statp
->_rnd
!= NULL
) {
826 statp
->options
&= ~RES_INIT
;
830 res_get_nibblesuffix(res_state statp
) {
831 if (statp
->_u
._ext
.ext
)
832 return (statp
->_u
._ext
.ext
->nsuffix
);
837 res_get_nibblesuffix2(res_state statp
) {
838 if (statp
->_u
._ext
.ext
)
839 return (statp
->_u
._ext
.ext
->nsuffix2
);
844 res_setservers(res_state statp
, const union res_sockaddr_union
*set
, int cnt
) {
848 /* close open servers */
851 /* cause rtt times to be forgotten */
852 statp
->_u
._ext
.nscount
= 0;
855 for (i
= 0; i
< cnt
&& nserv
< MAXNS
; i
++) {
856 switch (set
->sin
.sin_family
) {
858 size
= sizeof(set
->sin
);
859 if (statp
->_u
._ext
.ext
)
860 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
862 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
863 memcpy(&statp
->nsaddr_list
[nserv
],
866 statp
->nsaddr_list
[nserv
].sin_family
= 0;
870 #ifdef HAS_INET6_STRUCTS
872 size
= sizeof(set
->sin6
);
873 if (statp
->_u
._ext
.ext
)
874 memcpy(&statp
->_u
._ext
.ext
->nsaddrs
[nserv
],
876 if (size
<= sizeof(statp
->nsaddr_list
[nserv
]))
877 memcpy(&statp
->nsaddr_list
[nserv
],
880 statp
->nsaddr_list
[nserv
].sin_family
= 0;
890 statp
->nscount
= nserv
;
895 res_getservers(res_state statp
, union res_sockaddr_union
*set
, int cnt
) {
900 for (i
= 0; i
< statp
->nscount
&& i
< cnt
; i
++) {
901 if (statp
->_u
._ext
.ext
)
902 family
= statp
->_u
._ext
.ext
->nsaddrs
[i
].sin
.sin_family
;
904 family
= statp
->nsaddr_list
[i
].sin_family
;
908 size
= sizeof(set
->sin
);
909 if (statp
->_u
._ext
.ext
)
911 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
914 memcpy(&set
->sin
, &statp
->nsaddr_list
[i
],
918 #ifdef HAS_INET6_STRUCTS
920 size
= sizeof(set
->sin6
);
921 if (statp
->_u
._ext
.ext
)
923 &statp
->_u
._ext
.ext
->nsaddrs
[i
],
926 memcpy(&set
->sin6
, &statp
->nsaddr_list
[i
],
932 set
->sin
.sin_family
= 0;
937 return (statp
->nscount
);