4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
32 * This file contains all the MT related routines for the DNS backend.
35 #include "dns_common.h"
39 * If the DNS name service switch routines are used in a binary that depends
40 * on an older libresolv (libresolv.so.1, say), then having nss_dns.so.1 or
41 * libnss_dns.a depend on a newer libresolv (libresolv.so.2) will cause
42 * relocation problems. In particular, copy relocation of the _res structure
43 * (which changes in size from libresolv.so.1 to libresolv.so.2) could
44 * cause corruption, and result in a number of strange problems, including
45 * core dumps. Hence, we check if a libresolv is already loaded.
48 #pragma init(_nss_dns_init)
49 static void _nss_dns_init(void);
51 extern struct hostent
*res_gethostbyname(const char *);
52 #pragma weak res_gethostbyname
54 #define RES_SET_NO_HOSTS_FALLBACK "__res_set_no_hosts_fallback"
55 extern void __res_set_no_hosts_fallback(void);
56 #pragma weak __res_set_no_hosts_fallback
58 #define RES_UNSET_NO_HOSTS_FALLBACK "__res_unset_no_hosts_fallback"
59 extern void __res_unset_no_hosts_fallback(void);
60 #pragma weak __res_unset_no_hosts_fallback
62 #define RES_GET_RES "__res_get_res"
63 extern struct __res_state
*__res_get_res(void);
64 #pragma weak __res_get_res
66 #define RES_ENABLE_MT "__res_enable_mt"
67 extern int __res_enable_mt(void);
68 #pragma weak __res_enable_mt
70 #define RES_DISABLE_MT "__res_disable_mt"
71 extern int __res_disable_mt(void);
72 #pragma weak __res_disable_mt
74 #define RES_GET_H_ERRNO "__res_get_h_errno"
75 extern int *__res_get_h_errno();
76 #pragma weak __res_get_h_errno
78 #define __H_ERRNO "__h_errno"
79 extern int *__h_errno(void);
80 #pragma weak __h_errno
82 #define RES_OVERRIDE_RETRY "__res_override_retry"
83 extern int __res_override_retry(int);
84 #pragma weak __res_override_retry
86 static void __fallback_set_no_hosts(void);
87 static int *__fallback_h_errno(void);
88 static int __fallback_override_retry(int);
89 static int __is_mt_safe(void);
91 void (*set_no_hosts_fallback
)(void) = __fallback_set_no_hosts
;
92 void (*unset_no_hosts_fallback
)(void) = __fallback_set_no_hosts
;
93 struct __res_state
*(*set_res_retry
)() = 0;
94 int (*enable_mt
)() = 0;
95 int (*disable_mt
)() = 0;
96 int *(*get_h_errno
)(void) = 0;
97 int (*override_retry
)(int) = 0;
99 /* Usually set from the Makefile */
100 #ifndef NSS_DNS_LIBRESOLV
101 #define NSS_DNS_LIBRESOLV "libresolv.so.2"
107 mutex_t one_lane
= DEFAULTMUTEX
;
112 void *reslib
, (*f_void_ptr
)();
114 /* If no libresolv library, then load one */
115 if (res_gethostbyname
== 0) {
117 dlopen(NSS_DNS_LIBRESOLV
, RTLD_LAZY
|RTLD_GLOBAL
)) != 0) {
118 /* Turn off /etc/hosts fall back in libresolv */
119 if ((f_void_ptr
= (void (*)(void))dlsym(reslib
,
120 RES_SET_NO_HOSTS_FALLBACK
)) != 0) {
121 set_no_hosts_fallback
= f_void_ptr
;
123 if ((f_void_ptr
= (void (*)(void))dlsym(reslib
,
124 RES_SET_NO_HOSTS_FALLBACK
)) != 0) {
125 unset_no_hosts_fallback
= f_void_ptr
;
127 /* Set number of resolver retries */
128 if ((override_retry
= (int (*)(int))dlsym(reslib
,
129 RES_OVERRIDE_RETRY
)) == 0) {
131 (struct __res_state
*(*)(void))dlsym(reslib
,
133 override_retry
= __fallback_override_retry
;
136 * Select h_errno retrieval function. A BIND 8.2.2
137 * libresolv.so.2 will have __h_errno, a BIND 8.1.2
138 * one will have __res_get_h_errno, and other
139 * versions may have nothing at all.
141 * Also try to bind to the relevant MT enable/disable
142 * functions which are also dependent on the version
143 * of the BIND libresolv.so.2 being used.
145 if ((get_h_errno
= (int *(*)(void))dlsym(reslib
,
147 /* BIND 8.2.2 libresolv.so.2 is MT safe. */
148 enable_mt
= __is_mt_safe
;
149 disable_mt
= __is_mt_safe
;
152 (int *(*)(void))dlsym(reslib
,
153 RES_GET_H_ERRNO
)) == 0) {
154 get_h_errno
= __fallback_h_errno
;
157 * Pre-BIND 8.2.2 was not MT safe. Try to
158 * bind the MT enable/disable functions.
160 if ((enable_mt
= (int (*)(void))dlsym(reslib
,
161 RES_ENABLE_MT
)) != 0 &&
162 (disable_mt
= (int (*)(void))dlsym(reslib
,
163 RES_DISABLE_MT
)) == 0) {
169 /* Libresolv already loaded */
170 if ((f_void_ptr
= __res_set_no_hosts_fallback
) != 0) {
171 set_no_hosts_fallback
= f_void_ptr
;
173 if ((f_void_ptr
= __res_unset_no_hosts_fallback
) != 0) {
174 unset_no_hosts_fallback
= f_void_ptr
;
176 if ((override_retry
= __res_override_retry
) == 0) {
177 set_res_retry
= __res_get_res
;
178 override_retry
= __fallback_override_retry
;
180 if ((get_h_errno
= __h_errno
) == 0 &&
181 (get_h_errno
= __res_get_h_errno
) == 0) {
182 get_h_errno
= __fallback_h_errno
;
184 if (get_h_errno
== __h_errno
) {
185 enable_mt
= __is_mt_safe
;
186 disable_mt
= __is_mt_safe
;
188 if ((enable_mt
= __res_enable_mt
) != 0 &&
189 (disable_mt
= __res_disable_mt
) == 0) {
199 * Integration of BIND 8.1.2 introduced two new Sun private functions,
200 * __res_enable_mt() and __res_disable_mt(), that enabled and disabled
201 * MT mode per-thread. These functions are in the private libresolv.so.2
202 * interface, and intended for use by nss_dns.so.1.
204 * BIND 8.2.2 removed the need for those two functions. As similar
205 * functionality was provided in BIND further up the stack. However the
206 * functions remain to satisfy any application that directly called upon
207 * them. Only, __res_enable_mt() was modified to return failure.
208 * Indicated by a non-zero return value. So that those unconventional
209 * applications would not then presume that res_send() and friends are
210 * MT-safe, when in fact they are not.
212 * To prevent nss_dns from locking inappropriately __is_mt_safe() is
213 * called in place of __res_enable_mt() and __res_disable_mt() if BIND
214 * 8.2.2 libresolv.so.2 being used. __is_mt_safe() returns success
215 * indicated by a return code of zero. Signifying that no locking is
218 * MT applications making calls to gethostby*_r() or getipnodeby*()
219 * linked to libresolv.so.1 or linked statically with pre-BIND 8.2.2
220 * libresolv.a, doubtful as we don't ship a static version, would require
221 * locking within the nsswitch back-end. Hence the mechanism can not
232 * Return pointer to the global h_errno variable
235 __fallback_h_errno(void) {
241 * This function is called when the resolver library doesn't provide its
242 * own function to establish an override retry. If we can get a pointer
243 * to the per-thread _res (i.e., set_res_retry != 0), we set the retries
244 * directly, and return the previous number of retries. Otherwise, there's
248 __fallback_override_retry(int retry
) {
249 struct __res_state
*res
;
252 if (set_res_retry
!= 0) {
253 res
= set_res_retry();
254 old_retry
= res
->retry
;
262 __fallback_set_no_hosts(void) {
267 * Common code to enable/disable MT mode, set/unset no-/etc/hosts fallback,
268 * and to set the number of retries.
271 switch_resolver_setup(int *mt_disabled
, sigset_t
*oldmask
, int *old_retry
) {
274 * Try to enable MT mode. If that isn't possible, mask signals,
278 if (enable_mt
== 0 || (*mt_disabled
= (*enable_mt
)()) != 0) {
280 (void) sigfillset(&newmask
);
281 (void) thr_sigsetmask(SIG_SETMASK
, &newmask
, oldmask
);
282 (void) mutex_lock(&one_lane
);
286 * Disable any fallback to /etc/hosts (or /etc/inet/ipnodes, when
287 * libresolv knows about that file).
289 (*set_no_hosts_fallback
)();
292 * The NS switch wants to handle retries on its own.
294 *old_retry
= (*override_retry
)(1);
299 switch_resolver_reset(int mt_disabled
, sigset_t oldmask
, int old_retry
) {
302 (void) mutex_unlock(&one_lane
);
303 (void) thr_sigsetmask(SIG_SETMASK
, &oldmask
, NULL
);
305 (void) (*disable_mt
)();
308 (*unset_no_hosts_fallback
)();
310 (void) (*override_retry
)(old_retry
);