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"
30 * This is the DNS backend for IPv6 addresses.
31 * getbyname() is a local routine, but getbyaddr() actually shares the
32 * same codes as the one in gethostent.c.
35 #define endhostent res_endhostent
40 #include "dns_common.h"
43 * If the DNS name service switch routines are used in a binary that depends
44 * on an older libresolv (libresolv.so.1, say), then having nss_dns.so.1 or
45 * libnss_dns.a depend on a newer libresolv (libresolv.so.2) will cause
46 * relocation problems. In particular, copy relocation of the _res structure
47 * (which changes in size from libresolv.so.1 to libresolv.so.2) could
48 * cause corruption, and result in a number of strange problems, including
49 * core dumps. Hence, we check if a libresolv is already loaded.
53 #pragma weak res_endhostent
55 extern struct hostent
*_gethostbyname(int *, const char *);
56 extern struct hostent
*_nss_dns_gethostbyname2(int *, const char *);
81 #define RNDUP(x) ((1 + (((x)-1)/sizeof (void *))) * sizeof (void *))
86 #define PTROFF(p, o) (((o) == 0) ? 0 : (void *)((char *)(p) + (o)))
90 * Make a copy of h->h_name.
93 cloneName(struct hostent
*h
, int *outerr
) {
104 if (h
== 0 || h
->h_name
== 0) {
109 len
= strlen(h
->h_name
);
111 if ((name
= malloc(len
+1)) == 0) {
116 (void) memcpy(name
, h
->h_name
, len
+1);
124 * Copy the h->h_addr_list[] array to a new array, and append the
125 * moreAddrs[] list. If h->h_addr_list[] contains IPv4 addresses,
126 * convert them to v4 mapped IPv6 addresses.
128 * Note: The pointers to the addresses in the moreAddrs[] array are copied,
129 * but not the IP addresses themselves.
131 static struct in6_addr
**
132 cloneAddrList(struct hostent
*h
, struct in6_addr
**moreAddrs
, int *outerr
) {
134 struct in6_addr
**addrArray
, *addrList
;
135 int domap
, addrlen
, i
, j
, addrCount
, moreAddrCount
= 0;
144 if (h
== 0 || h
->h_addr_list
== 0) {
149 /* Should we map v4 to IPv6 ? */
150 domap
= (h
->h_length
== sizeof (struct in_addr
)) &&
151 (h
->h_addrtype
== AF_INET
);
153 /* If mapping, make sure we allocate enough memory for addresses */
154 addrlen
= h
->h_length
;
155 if (domap
&& addrlen
< sizeof (struct in6_addr
))
156 addrlen
= sizeof (struct in6_addr
);
158 for (addrCount
= 0; h
->h_addr_list
[addrCount
]; addrCount
++);
160 if (moreAddrs
!= 0) {
161 for (moreAddrCount
= 0; moreAddrs
[moreAddrCount
];
165 if ((addrArray
= malloc((addrCount
+moreAddrCount
+1)*sizeof (addrList
) +
166 addrCount
*addrlen
)) == 0) {
171 addrList
= PTROFF(addrArray
, (addrCount
+moreAddrCount
+1) *
174 for (i
= 0; i
< addrCount
; i
++) {
175 addrArray
[i
] = addrList
;
177 /* LINTED: E_BAD_PTR_CAST_ALIGN */
178 IN6_INADDR_TO_V4MAPPED(
179 (struct in_addr
*)h
->h_addr_list
[i
], addrArray
[i
]);
181 (void) memcpy(addrArray
[i
], h
->h_addr_list
[i
],
184 addrList
= PTROFF(addrList
, addrlen
);
187 for (j
= 0; j
< moreAddrCount
; j
++, i
++) {
188 addrArray
[i
] = moreAddrs
[j
];
191 /* Last pointer should be NULL */
200 * Create a new alias array that is is a copy of h->h_aliases[] plus
201 * the aliases in mergeAliases[] which aren't duplicates of any alias
204 * Note 1: Only the string pointers (NOT the strings) in the mergeAliases[]
207 * Note 2: The duplicate aliases in mergeAliases[] are replaced by NULL
211 cloneAliasList(struct hostent
*h
, char **mergeAliases
, int *outerr
) {
213 char **aliasArray
, *aliasList
;
214 int i
, j
, aliasCount
, mergeAliasCount
= 0, realMac
= 0;
224 if (h
== 0 || h
->h_aliases
== 0) {
229 for (aliasCount
= 0; h
->h_aliases
[aliasCount
]; aliasCount
++) {
230 stringSize
+= RNDUP(strlen(h
->h_aliases
[aliasCount
])+1);
233 if (mergeAliases
!= 0) {
234 for (; mergeAliases
[mergeAliasCount
]; mergeAliasCount
++) {
236 /* Skip duplicates */
237 for (j
= 0; j
< aliasCount
; j
++) {
238 if (strcmp(mergeAliases
[mergeAliasCount
],
239 h
->h_aliases
[j
]) == 0) {
247 mergeAliases
[mergeAliasCount
] = 0;
251 if ((aliasArray
= malloc((aliasCount
+realMac
+1)*sizeof (char **)+
257 aliasList
= PTROFF(aliasArray
,
258 (aliasCount
+realMac
+1)*sizeof (char **));
259 for (i
= 0; i
< aliasCount
; i
++) {
260 int len
= strlen(h
->h_aliases
[i
]);
261 aliasArray
[i
] = aliasList
;
262 (void) memcpy(aliasArray
[i
], h
->h_aliases
[i
], len
+1);
263 aliasList
= PTROFF(aliasList
, RNDUP(len
+1));
266 for (j
= 0; j
< mergeAliasCount
; j
++) {
267 if (mergeAliases
[j
] != 0) {
268 aliasArray
[i
++] = mergeAliases
[j
];
281 dns_backend_ptr_t be
;
284 struct hostent
*he
= NULL
;
285 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)a
;
286 int ret
, mt_disabled
;
288 int converr
= 0, gotv6
= 0;
292 struct in6_addr
**v6Addrs
= 0, **mergeAddrs
= 0;
293 char **v6Aliases
= 0, **mergeAliases
= 0;
296 int af
= argp
->key
.ipnode
.af_family
;
297 int flags
= argp
->key
.ipnode
.flags
;
299 switch_resolver_setup(&mt_disabled
, &oldmask
, &old_retry
);
301 /* Now get the AAAA records */
303 he
= _nss_dns_gethostbyname2(&argp
->h_errno
,
304 argp
->key
.ipnode
.name
);
307 * pointer in "he" is part of a static pthread key in libresolv
308 * It should be treated as read only.
309 * So clone a copy first.
311 v6Name
= cloneName(he
, &converr
);
313 argp
->h_errno
= HOST_NOT_FOUND
;
315 switch_resolver_reset(mt_disabled
, oldmask
, old_retry
);
316 return (_herrno2nss(argp
->h_errno
));
318 v6Addrs
= cloneAddrList(he
, 0, &converr
);
322 argp
->h_errno
= HOST_NOT_FOUND
;
324 switch_resolver_reset(mt_disabled
, oldmask
, old_retry
);
325 return (_herrno2nss(argp
->h_errno
));
327 v6Aliases
= cloneAliasList(he
, 0, &converr
);
333 argp
->h_errno
= HOST_NOT_FOUND
;
335 switch_resolver_reset(mt_disabled
, oldmask
, old_retry
);
336 return (_herrno2nss(argp
->h_errno
));
338 v6_h_errno
= argp
->h_errno
;
343 * The conditions to search "A" records:
345 * 2. if af is AF_INET6
346 * then flags are either
347 * 1) (AI_ALL | AI_V4MAPPED) or
348 * 2) AI_V4MAPPED and he == NULL
349 * (No V6 addresses found or no search for V6 at all)
352 /* Get the A records, and store the information */
353 if ((af
== AF_INET
) ||
355 ((flags
& (AI_ALL
| AI_V4MAPPED
)) ||
356 ((flags
& AI_V4MAPPED
) && he
== NULL
))))
357 he
= _gethostbyname(&argp
->h_errno
, argp
->key
.ipnode
.name
);
361 /* Merge the results */
364 mergeAddrs
= cloneAddrList(he
, v6Addrs
, &converr
);
372 argp
->h_errno
= HOST_NOT_FOUND
;
374 switch_resolver_reset(mt_disabled
, oldmask
,
376 return (_herrno2nss(argp
->h_errno
));
378 mhe
.h_addr_list
= (char **)mergeAddrs
;
380 mergeAliases
= cloneAliasList(he
, v6Aliases
, &converr
);
390 argp
->h_errno
= HOST_NOT_FOUND
;
392 switch_resolver_reset(mt_disabled
, oldmask
,
394 return (_herrno2nss(argp
->h_errno
));
396 mhe
.h_aliases
= mergeAliases
;
398 /* reset h_length, h_addrtype */
399 mhe
.h_length
= sizeof (struct in6_addr
);
400 mhe
.h_addrtype
= AF_INET6
;
404 v6he
.h_name
= v6Name
;
405 v6he
.h_length
= sizeof (struct in6_addr
);
406 v6he
.h_addrtype
= AF_INET6
;
407 v6he
.h_addr_list
= (char **)v6Addrs
;
408 v6he
.h_aliases
= v6Aliases
;
410 argp
->h_errno
= v6_h_errno
;
415 * if asked to return data in string,
416 * convert the hostent structure into
419 if (argp
->buf
.result
== NULL
) {
420 ret
= ent2str(he
, a
, AF_INET6
);
421 if (ret
== NSS_STR_PARSE_SUCCESS
)
422 argp
->returnval
= argp
->buf
.buffer
;
424 ret
= ent2result(he
, a
, AF_INET6
);
425 if (ret
== NSS_STR_PARSE_SUCCESS
)
426 argp
->returnval
= argp
->buf
.result
;
429 if (ret
!= NSS_STR_PARSE_SUCCESS
) {
430 argp
->h_errno
= HOST_NOT_FOUND
;
431 if (ret
== NSS_STR_PARSE_ERANGE
) {
445 if (mergeAliases
!= 0)
448 switch_resolver_reset(mt_disabled
, oldmask
, old_retry
);
450 return (_herrno2nss(argp
->h_errno
));
454 extern nss_status_t
__nss_dns_getbyaddr(dns_backend_ptr_t
, void *);
458 dns_backend_ptr_t be
;
461 /* uses the same getbyaddr from IPv4 */
462 return (__nss_dns_getbyaddr(be
, a
));
468 _nss_dns_getent(be
, args
)
469 dns_backend_ptr_t be
;
472 return (NSS_UNAVAIL
);
478 _nss_dns_setent(be
, dummy
)
479 dns_backend_ptr_t be
;
482 /* XXXX not implemented at this point */
483 return (NSS_UNAVAIL
);
489 _nss_dns_endent(be
, dummy
)
490 dns_backend_ptr_t be
;
493 /* XXXX not implemented at this point */
494 return (NSS_UNAVAIL
);
500 _nss_dns_destr(be
, dummy
)
501 dns_backend_ptr_t be
;
507 /* === Should change to invoke ops[ENDENT] ? */
508 sigset_t oldmask
, newmask
;
511 if (enable_mt
== 0 || (mt_disabled
= (*enable_mt
)()) != 0) {
512 (void) sigfillset(&newmask
);
513 (void) thr_sigsetmask(SIG_SETMASK
, &newmask
, &oldmask
);
514 (void) mutex_lock(&one_lane
);
520 (void) mutex_unlock(&one_lane
);
521 (void) thr_sigsetmask(SIG_SETMASK
, &oldmask
, NULL
);
523 (void) (*disable_mt
)();
528 return (NSS_SUCCESS
); /* In case anyone is dumb enough to check */
533 static dns_backend_op_t ipnodes_ops
[] = {
544 _nss_dns_ipnodes_constr(dummy1
, dummy2
, dummy3
)
545 const char *dummy1
, *dummy2
, *dummy3
;
547 return (_nss_dns_constr(ipnodes_ops
,
548 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
552 * optional NSS2 packed backend gethostsbyipnode with ttl
556 * NSS_SUCCESS - successful
557 * NSS_NOTFOUND - successful but nothing found
558 * NSS_ERROR - fallback to NSS backend lookup mode
559 * If successful, buffer will be filled with valid data
565 _nss_get_dns_ipnodes_name(dns_backend_ptr_t
*be
, void **bufp
, size_t *sizep
)
567 return (_nss_dns_gethost_withttl(*bufp
, *sizep
, 1));