10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*132Srobinson 230Sstevel@tonic-gate /* 24*132Srobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate * 270Sstevel@tonic-gate * This file defines and implements the re-entrant getipnodebyname(), 280Sstevel@tonic-gate * getipnodebyaddr(), and freehostent() routines for IPv6. These routines 290Sstevel@tonic-gate * follow use the netdir_getbyYY() (see netdir_inet.c). 300Sstevel@tonic-gate * 310Sstevel@tonic-gate * lib/libnsl/nss/getipnodeby.c 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include "mt.h" 370Sstevel@tonic-gate #include <stdlib.h> 380Sstevel@tonic-gate #include <unistd.h> 390Sstevel@tonic-gate #include <stropts.h> 400Sstevel@tonic-gate #include <ctype.h> 410Sstevel@tonic-gate #include <string.h> 420Sstevel@tonic-gate #include <strings.h> 430Sstevel@tonic-gate #include <netdb.h> 440Sstevel@tonic-gate #include <stdio.h> 450Sstevel@tonic-gate #include <arpa/inet.h> 460Sstevel@tonic-gate #include <nss_dbdefs.h> 470Sstevel@tonic-gate #include <netinet/in.h> 480Sstevel@tonic-gate #include <sys/socket.h> 490Sstevel@tonic-gate #include <sys/sockio.h> 500Sstevel@tonic-gate #include <nss_netdir.h> 510Sstevel@tonic-gate #include <net/if.h> 520Sstevel@tonic-gate #include <netinet/in.h> 530Sstevel@tonic-gate #include <netdir.h> 540Sstevel@tonic-gate #include <thread.h> 550Sstevel@tonic-gate #include <synch.h> 560Sstevel@tonic-gate #include <fcntl.h> 570Sstevel@tonic-gate #include <sys/time.h> 580Sstevel@tonic-gate #include "nss.h" 590Sstevel@tonic-gate 600Sstevel@tonic-gate #define IPV6_LITERAL_CHAR ':' 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * The number of nanoseconds getipnodebyname() waits before getting 640Sstevel@tonic-gate * fresh interface count information with SIOCGLIFNUM. The default is 650Sstevel@tonic-gate * five minutes. 660Sstevel@tonic-gate */ 670Sstevel@tonic-gate #define IFNUM_TIMEOUT ((hrtime_t)300 * NANOSEC) 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * Bits in the bitfield returned by getipnodebyname_processflags(). 710Sstevel@tonic-gate * 720Sstevel@tonic-gate * IPNODE_WANTIPV6 The user wants IPv6 addresses returned. 730Sstevel@tonic-gate * IPNODE_WANTIPV4 The user wants IPv4 addresses returned. 740Sstevel@tonic-gate * IPNODE_IPV4IFNOIPV6 The user only wants IPv4 addresses returned if no IPv6 750Sstevel@tonic-gate * addresses are returned. 760Sstevel@tonic-gate * IPNODE_LOOKUPIPNODES getipnodebyname() needs to lookup the name in ipnodes. 770Sstevel@tonic-gate * IPNODE_LOOKUPHOSTS getipnodebyname() needs to lookup the name in hosts. 780Sstevel@tonic-gate * IPNODE_ISLITERAL The name supplied is a literal address string. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate #define IPNODE_WANTIPV6 0x00000001u 810Sstevel@tonic-gate #define IPNODE_WANTIPV4 0x00000002u 820Sstevel@tonic-gate #define IPNODE_IPV4IFNOIPV6 0x00000004u 830Sstevel@tonic-gate #define IPNODE_LOOKUPIPNODES 0x00000008u 840Sstevel@tonic-gate #define IPNODE_LOOKUPHOSTS 0x00000010u 850Sstevel@tonic-gate #define IPNODE_LITERAL 0x00000020u 860Sstevel@tonic-gate #define IPNODE_IPV4 (IPNODE_WANTIPV4 | IPNODE_IPV4IFNOIPV6) 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * The default set of bits corresponding to a getipnodebyname() flags 900Sstevel@tonic-gate * argument of AI_DEFAULT. 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate #define IPNODE_DEFAULT (IPNODE_WANTIPV6 | IPNODE_IPV4 | \ 930Sstevel@tonic-gate IPNODE_LOOKUPIPNODES | IPNODE_LOOKUPHOSTS) 940Sstevel@tonic-gate 950Sstevel@tonic-gate extern struct netconfig *__rpc_getconfip(char *); 960Sstevel@tonic-gate 970Sstevel@tonic-gate static struct hostent *__mapv4tov6(struct hostent *, struct hostent *, 980Sstevel@tonic-gate nss_XbyY_buf_t *, int); 990Sstevel@tonic-gate struct hostent *__mappedtov4(struct hostent *, int *); 1000Sstevel@tonic-gate static struct hostent *__filter_addresses(int, struct hostent *); 1010Sstevel@tonic-gate static int __find_mapped(struct hostent *, int); 1020Sstevel@tonic-gate static nss_XbyY_buf_t *__IPv6_alloc(int); 1030Sstevel@tonic-gate static void __IPv6_cleanup(nss_XbyY_buf_t *); 1040Sstevel@tonic-gate static int __ai_addrconfig(int); 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate #ifdef PIC 1080Sstevel@tonic-gate struct hostent * 1090Sstevel@tonic-gate _uncached_getipnodebyname(const char *nam, struct hostent *result, 1100Sstevel@tonic-gate char *buffer, int buflen, int af_family, int flags, int *h_errnop) 1110Sstevel@tonic-gate { 112*132Srobinson return (_switch_getipnodebyname_r(nam, result, buffer, buflen, 113*132Srobinson af_family, flags, h_errnop)); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate struct hostent * 1170Sstevel@tonic-gate _uncached_getipnodebyaddr(const char *addr, int length, int type, 1180Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate if (type == AF_INET) 1210Sstevel@tonic-gate return (_switch_gethostbyaddr_r(addr, length, type, 1220Sstevel@tonic-gate result, buffer, buflen, h_errnop)); 1230Sstevel@tonic-gate else if (type == AF_INET6) 1240Sstevel@tonic-gate return (_switch_getipnodebyaddr_r(addr, length, type, 1250Sstevel@tonic-gate result, buffer, buflen, h_errnop)); 1260Sstevel@tonic-gate return (NULL); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate #endif 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Given a name, an address family, and a set of flags, return a 1320Sstevel@tonic-gate * bitfield that getipnodebyname() will use. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate static uint_t 1350Sstevel@tonic-gate getipnodebyname_processflags(const char *name, int af, int flags) 1360Sstevel@tonic-gate { 1370Sstevel@tonic-gate uint_t ipnode_bits = IPNODE_DEFAULT; 1380Sstevel@tonic-gate boolean_t ipv6configured = B_FALSE; 1390Sstevel@tonic-gate boolean_t ipv4configured = B_FALSE; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1420Sstevel@tonic-gate * If AI_ADDRCONFIG is specified, we need to determine the number 1430Sstevel@tonic-gate * of addresses of each address family configured on the system as 1440Sstevel@tonic-gate * appropriate. 1450Sstevel@tonic-gate */ 1460Sstevel@tonic-gate if (flags & AI_ADDRCONFIG) { 1470Sstevel@tonic-gate ipv6configured = (af == AF_INET6 && 1480Sstevel@tonic-gate __ai_addrconfig(AF_INET6) > 0); 1490Sstevel@tonic-gate ipv4configured = ((af == AF_INET || (flags & AI_V4MAPPED)) && 1500Sstevel@tonic-gate __ai_addrconfig(AF_INET) > 0); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * Determine what kinds of addresses the user is interested 1550Sstevel@tonic-gate * in getting back. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate switch (af) { 1580Sstevel@tonic-gate case AF_INET6: 1590Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv6configured) 1600Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate if (flags & AI_V4MAPPED) { 1630Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv4configured) { 1640Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1650Sstevel@tonic-gate } else if (flags & AI_ALL) { 1660Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4IFNOIPV6; 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate } else { 1690Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate break; 1720Sstevel@tonic-gate case AF_INET: 1730Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv4configured) 1740Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1750Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 1760Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4IFNOIPV6; 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate default: 1790Sstevel@tonic-gate ipnode_bits = 0; 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate /* 1840Sstevel@tonic-gate * If we're not looking for IPv4 addresses, don't bother looking 1850Sstevel@tonic-gate * in hosts. 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate if (!(ipnode_bits & IPNODE_WANTIPV4)) 1880Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * Determine if name is a literal IP address. This will 1920Sstevel@tonic-gate * further narrow down what type of lookup we're going to do. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate if (strchr(name, IPV6_LITERAL_CHAR) != NULL) { 1950Sstevel@tonic-gate /* Literal IPv6 address */ 1960Sstevel@tonic-gate ipnode_bits |= IPNODE_LITERAL; 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * In s9 we accepted the literal without filtering independent 1990Sstevel@tonic-gate * of what family was passed in hints. We continue to do 2000Sstevel@tonic-gate * this. 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate ipnode_bits |= (IPNODE_WANTIPV6 | IPNODE_WANTIPV4); 2030Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 204*132Srobinson } else if (inet_addr(name) != 0xffffffffU) { 2050Sstevel@tonic-gate /* Literal IPv4 address */ 2060Sstevel@tonic-gate ipnode_bits |= (IPNODE_LITERAL | IPNODE_WANTIPV4); 2070Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 2080Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPIPNODES; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate return (ipnode_bits); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate struct hostent * 2140Sstevel@tonic-gate getipnodebyname(const char *name, int af, int flags, int *error_num) 2150Sstevel@tonic-gate { 2160Sstevel@tonic-gate struct hostent *hp = NULL; 2170Sstevel@tonic-gate nss_XbyY_buf_t *buf4 = NULL; 2180Sstevel@tonic-gate nss_XbyY_buf_t *buf6 = NULL; 2190Sstevel@tonic-gate struct netconfig *nconf; 2200Sstevel@tonic-gate struct nss_netdirbyname_in nssin; 2210Sstevel@tonic-gate union nss_netdirbyname_out nssout; 2220Sstevel@tonic-gate int ret; 2230Sstevel@tonic-gate uint_t ipnode_bits; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 2260Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 2270Sstevel@tonic-gate *error_num = NO_RECOVERY; 2280Sstevel@tonic-gate return (NULL); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate ipnode_bits = getipnodebyname_processflags(name, af, flags); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* Make sure we have something to look up. */ 2340Sstevel@tonic-gate if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) { 2350Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 2360Sstevel@tonic-gate goto cleanup; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * Perform the requested lookups. We always look through 2410Sstevel@tonic-gate * ipnodes first for both IPv4 and IPv6 addresses. Depending 2420Sstevel@tonic-gate * on what was returned and what was needed, we either filter 2430Sstevel@tonic-gate * out the garbage, or ask for more using hosts. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate if (ipnode_bits & IPNODE_LOOKUPIPNODES) { 2460Sstevel@tonic-gate if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) { 2470Sstevel@tonic-gate *error_num = NO_RECOVERY; 2480Sstevel@tonic-gate goto cleanup; 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 2510Sstevel@tonic-gate nssin.arg.nss.host6.name = name; 2520Sstevel@tonic-gate nssin.arg.nss.host6.buf = buf6->buffer; 2530Sstevel@tonic-gate nssin.arg.nss.host6.buflen = buf6->buflen; 2540Sstevel@tonic-gate nssin.arg.nss.host6.af_family = af; 2550Sstevel@tonic-gate nssin.arg.nss.host6.flags = flags; 2560Sstevel@tonic-gate nssout.nss.host.hent = buf6->result; 2570Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 2580Sstevel@tonic-gate ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); 2590Sstevel@tonic-gate if (ret != ND_OK) { 2600Sstevel@tonic-gate __IPv6_cleanup(buf6); 2610Sstevel@tonic-gate buf6 = NULL; 2620Sstevel@tonic-gate } else if (ipnode_bits & IPNODE_WANTIPV4) { 2630Sstevel@tonic-gate /* 2640Sstevel@tonic-gate * buf6 may have all that we need if we either 2650Sstevel@tonic-gate * only wanted IPv4 addresses if there were no 2660Sstevel@tonic-gate * IPv6 addresses returned, or if there are 2670Sstevel@tonic-gate * IPv4-mapped addresses in buf6. If either 2680Sstevel@tonic-gate * of these are true, then there's no need to 2690Sstevel@tonic-gate * look in hosts. 2700Sstevel@tonic-gate */ 2710Sstevel@tonic-gate if (ipnode_bits & IPNODE_IPV4IFNOIPV6 || 2720Sstevel@tonic-gate __find_mapped(buf6->result, 0) != 0) { 2730Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 2740Sstevel@tonic-gate } else if (!(ipnode_bits & IPNODE_WANTIPV6)) { 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * If all we're looking for are IPv4 2770Sstevel@tonic-gate * addresses and there are none in 2780Sstevel@tonic-gate * buf6 then buf6 is now useless. 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate __IPv6_cleanup(buf6); 2810Sstevel@tonic-gate buf6 = NULL; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate if (ipnode_bits & IPNODE_LOOKUPHOSTS) { 2860Sstevel@tonic-gate if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) { 2870Sstevel@tonic-gate *error_num = NO_RECOVERY; 2880Sstevel@tonic-gate goto cleanup; 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate nssin.op_t = NSS_HOST; 2910Sstevel@tonic-gate nssin.arg.nss.host.name = name; 2920Sstevel@tonic-gate nssin.arg.nss.host.buf = buf4->buffer; 2930Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf4->buflen; 2940Sstevel@tonic-gate nssout.nss.host.hent = buf4->result; 2950Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 2960Sstevel@tonic-gate ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); 2970Sstevel@tonic-gate if (ret != ND_OK) { 2980Sstevel@tonic-gate __IPv6_cleanup(buf4); 2990Sstevel@tonic-gate buf4 = NULL; 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (buf6 == NULL && buf4 == NULL) { 3040Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 3050Sstevel@tonic-gate goto cleanup; 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* Extract the appropriate addresses from the returned buffer(s). */ 3090Sstevel@tonic-gate switch (af) { 3100Sstevel@tonic-gate case AF_INET6: { 3110Sstevel@tonic-gate if (buf4 != NULL) { 3120Sstevel@tonic-gate nss_XbyY_buf_t *mergebuf; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * The IPv4 results we have need to be 3160Sstevel@tonic-gate * converted to IPv4-mapped addresses, 3170Sstevel@tonic-gate * conditionally merged with the IPv6 3180Sstevel@tonic-gate * results, and the end result needs to be 3190Sstevel@tonic-gate * re-ordered. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES); 3220Sstevel@tonic-gate if (mergebuf == NULL) { 3230Sstevel@tonic-gate *error_num = NO_RECOVERY; 3240Sstevel@tonic-gate goto cleanup; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate hp = __mapv4tov6(buf4->result, 3270Sstevel@tonic-gate ((buf6 != NULL) ? buf6->result : NULL), 3280Sstevel@tonic-gate mergebuf, 1); 3290Sstevel@tonic-gate if (hp != NULL) 3300Sstevel@tonic-gate order_haddrlist_af(AF_INET6, hp->h_addr_list); 3310Sstevel@tonic-gate else 3320Sstevel@tonic-gate *error_num = NO_RECOVERY; 3330Sstevel@tonic-gate free(mergebuf); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if (buf4 == NULL && buf6 != NULL) { 3370Sstevel@tonic-gate hp = buf6->result; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* 3400Sstevel@tonic-gate * We have what we need in buf6, but we may need 3410Sstevel@tonic-gate * to filter out some addresses depending on what 3420Sstevel@tonic-gate * is being asked for. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate if (!(ipnode_bits & IPNODE_WANTIPV4)) 3450Sstevel@tonic-gate hp = __filter_addresses(AF_INET, buf6->result); 3460Sstevel@tonic-gate else if (!(ipnode_bits & IPNODE_WANTIPV6)) 3470Sstevel@tonic-gate hp = __filter_addresses(AF_INET6, buf6->result); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if (hp == NULL) 3500Sstevel@tonic-gate *error_num = NO_ADDRESS; 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate break; 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate case AF_INET: 3570Sstevel@tonic-gate /* We could have results in buf6 or buf4, not both */ 3580Sstevel@tonic-gate if (buf6 != NULL) { 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * Extract the IPv4-mapped addresses from buf6 3610Sstevel@tonic-gate * into hp. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate hp = __mappedtov4(buf6->result, error_num); 3640Sstevel@tonic-gate } else { 3650Sstevel@tonic-gate /* We have what we need in buf4. */ 3660Sstevel@tonic-gate hp = buf4->result; 3670Sstevel@tonic-gate if (ipnode_bits & IPNODE_LITERAL) { 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * There is a special case here for literal 3700Sstevel@tonic-gate * IPv4 address strings. The hosts 3710Sstevel@tonic-gate * front-end sets h_aliases to a one 3720Sstevel@tonic-gate * element array containing a single NULL 3730Sstevel@tonic-gate * pointer (in ndaddr2hent()), while 3740Sstevel@tonic-gate * getipnodebyname() requires h_aliases to 3750Sstevel@tonic-gate * be a NULL pointer itself. We're not 3760Sstevel@tonic-gate * going to change the front-end since it 3770Sstevel@tonic-gate * needs to remain backward compatible for 3780Sstevel@tonic-gate * gethostbyname() and friends. Just set 3790Sstevel@tonic-gate * h_aliases to NULL here instead. 3800Sstevel@tonic-gate */ 3810Sstevel@tonic-gate hp->h_aliases = NULL; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate break; 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate default: 3880Sstevel@tonic-gate break; 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate cleanup: 3920Sstevel@tonic-gate /* 3930Sstevel@tonic-gate * Free the memory we allocated, but make sure we don't free 3940Sstevel@tonic-gate * the memory we're returning to the caller. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate if (buf6 != NULL) { 3970Sstevel@tonic-gate if (buf6->result == hp) 3980Sstevel@tonic-gate buf6->result = NULL; 3990Sstevel@tonic-gate __IPv6_cleanup(buf6); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate if (buf4 != NULL) { 4020Sstevel@tonic-gate if (buf4->result == hp) 4030Sstevel@tonic-gate buf4->result = NULL; 4040Sstevel@tonic-gate __IPv6_cleanup(buf4); 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate (void) freenetconfigent(nconf); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate return (hp); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * This is the IPv6 interface for "gethostbyaddr". 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate struct hostent * 4150Sstevel@tonic-gate getipnodebyaddr(const void *src, size_t len, int type, int *error_num) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate struct in6_addr *addr6 = 0; 4180Sstevel@tonic-gate struct in_addr *addr4 = 0; 4190Sstevel@tonic-gate nss_XbyY_buf_t *buf = 0; 4200Sstevel@tonic-gate nss_XbyY_buf_t *res = 0; 4210Sstevel@tonic-gate struct netconfig *nconf; 4220Sstevel@tonic-gate struct hostent *hp = 0; 4230Sstevel@tonic-gate struct nss_netdirbyaddr_in nssin; 4240Sstevel@tonic-gate union nss_netdirbyaddr_out nssout; 4250Sstevel@tonic-gate int neterr; 4260Sstevel@tonic-gate char tmpbuf[64]; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate if (type == AF_INET6) { 4290Sstevel@tonic-gate if ((addr6 = (struct in6_addr *)src) == NULL) { 4300Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4310Sstevel@tonic-gate return (NULL); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate } else if (type == AF_INET) { 4340Sstevel@tonic-gate if ((addr4 = (struct in_addr *)src) == NULL) { 4350Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4360Sstevel@tonic-gate return (NULL); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate } else { 4390Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4400Sstevel@tonic-gate return (NULL); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate /* 4430Sstevel@tonic-gate * Specific case: query for "::" 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) { 4460Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4470Sstevel@tonic-gate return (NULL); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Step 1: IPv4-mapped address or IPv4 Compat 4510Sstevel@tonic-gate */ 4520Sstevel@tonic-gate if ((type == AF_INET6 && len == 16) && 4530Sstevel@tonic-gate ((IN6_IS_ADDR_V4MAPPED(addr6)) || 4540Sstevel@tonic-gate (IN6_IS_ADDR_V4COMPAT(addr6)))) { 4550Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 4560Sstevel@tonic-gate *error_num = NO_RECOVERY; 4570Sstevel@tonic-gate return (NULL); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 4600Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 4610Sstevel@tonic-gate *error_num = NO_RECOVERY; 4620Sstevel@tonic-gate __IPv6_cleanup(buf); 4630Sstevel@tonic-gate return (NULL); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 4660Sstevel@tonic-gate if (IN6_IS_ADDR_V4COMPAT(addr6)) { 467*132Srobinson (void) memcpy(tmpbuf, addr6, sizeof (*addr6)); 4680Sstevel@tonic-gate tmpbuf[10] = 0xffU; 4690Sstevel@tonic-gate tmpbuf[11] = 0xffU; 4700Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)tmpbuf; 4710Sstevel@tonic-gate } else { 4720Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate nssin.arg.nss.host.len = sizeof (struct in6_addr); 4750Sstevel@tonic-gate nssin.arg.nss.host.type = AF_INET6; 4760Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 4770Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 4800Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 4810Sstevel@tonic-gate /* 4820Sstevel@tonic-gate * We pass in nconf and let the implementation of the 4830Sstevel@tonic-gate * long-named func decide whether to use the switch based on 4840Sstevel@tonic-gate * nc_nlookups. 4850Sstevel@tonic-gate */ 4860Sstevel@tonic-gate neterr = 4870Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate (void) freenetconfigent(nconf); 4900Sstevel@tonic-gate if (neterr != ND_OK) { 4910Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 4920Sstevel@tonic-gate if (!gethostbyaddr_r(((char *)addr6) + 12, 4930Sstevel@tonic-gate sizeof (in_addr_t), AF_INET, buf->result, 4940Sstevel@tonic-gate buf->buffer, buf->buflen, error_num)) { 4950Sstevel@tonic-gate __IPv6_cleanup(buf); 4960Sstevel@tonic-gate return (NULL); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate /* Found one, now format it into mapped/compat addr */ 4990Sstevel@tonic-gate if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 5000Sstevel@tonic-gate __IPv6_cleanup(buf); 5010Sstevel@tonic-gate *error_num = NO_RECOVERY; 5020Sstevel@tonic-gate return (NULL); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate /* Convert IPv4 to mapped/compat address w/name */ 5050Sstevel@tonic-gate hp = res->result; 506*132Srobinson (void) __mapv4tov6(buf->result, 0, res, 5070Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(addr6)); 5080Sstevel@tonic-gate __IPv6_cleanup(buf); 5090Sstevel@tonic-gate free(res); 5100Sstevel@tonic-gate return (hp); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * At this point, we'll have a v4mapped hostent. If that's 5140Sstevel@tonic-gate * what was passed in, just return. If the request was a compat, 5150Sstevel@tonic-gate * twiggle the two bytes to make the mapped address a compat. 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate hp = buf->result; 5180Sstevel@tonic-gate if (IN6_IS_ADDR_V4COMPAT(addr6)) { 519*132Srobinson /* LINTED pointer cast */ 5200Sstevel@tonic-gate addr6 = (struct in6_addr *)hp->h_addr_list[0]; 5210Sstevel@tonic-gate addr6->s6_addr[10] = 0; 5220Sstevel@tonic-gate addr6->s6_addr[11] = 0; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate free(buf); 5250Sstevel@tonic-gate return (hp); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * Step 2: AF_INET, v4 lookup. Since we're going to search the 5290Sstevel@tonic-gate * ipnodes (v6) path first, we need to treat this as a v4mapped 5300Sstevel@tonic-gate * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The 5310Sstevel@tonic-gate * switch backend knows to lookup v4's (not v4mapped) from the 5320Sstevel@tonic-gate * name services. 5330Sstevel@tonic-gate */ 5340Sstevel@tonic-gate if (type == AF_INET) { 5350Sstevel@tonic-gate struct in6_addr v4mapbuf; 5360Sstevel@tonic-gate addr6 = &v4mapbuf; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(addr4, addr6); 5390Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 5400Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 5410Sstevel@tonic-gate *error_num = NO_RECOVERY; 5420Sstevel@tonic-gate return (NULL); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 5450Sstevel@tonic-gate *error_num = NO_RECOVERY; 5460Sstevel@tonic-gate freenetconfigent(nconf); 5470Sstevel@tonic-gate return (NULL); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 5500Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 5510Sstevel@tonic-gate nssin.arg.nss.host.len = sizeof (struct in6_addr); 5520Sstevel@tonic-gate nssin.arg.nss.host.type = AF_INET6; 5530Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 5540Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 5570Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * We pass in nconf and let the implementation of the 5600Sstevel@tonic-gate * long-named func decide whether to use the switch based on 5610Sstevel@tonic-gate * nc_nlookups. 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate neterr = 5640Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate (void) freenetconfigent(nconf); 5670Sstevel@tonic-gate if (neterr != ND_OK) { 5680Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 5690Sstevel@tonic-gate hp = buf->result; 5700Sstevel@tonic-gate if (!gethostbyaddr_r(src, len, type, buf->result, 5710Sstevel@tonic-gate buf->buffer, buf->buflen, error_num)) { 5720Sstevel@tonic-gate __IPv6_cleanup(buf); 5730Sstevel@tonic-gate return (NULL); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate free(buf); 5760Sstevel@tonic-gate return (hp); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate if ((hp = __mappedtov4(buf->result, error_num)) == NULL) { 5790Sstevel@tonic-gate __IPv6_cleanup(buf); 5800Sstevel@tonic-gate return (NULL); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate __IPv6_cleanup(buf); 5830Sstevel@tonic-gate return (hp); 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate /* 5860Sstevel@tonic-gate * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call. 5870Sstevel@tonic-gate */ 5880Sstevel@tonic-gate if (type == AF_INET6) { 5890Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 5900Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 5910Sstevel@tonic-gate *error_num = NO_RECOVERY; 5920Sstevel@tonic-gate return (NULL); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 5950Sstevel@tonic-gate *error_num = NO_RECOVERY; 5960Sstevel@tonic-gate freenetconfigent(nconf); 5970Sstevel@tonic-gate return (NULL); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 6000Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 6010Sstevel@tonic-gate nssin.arg.nss.host.len = len; 6020Sstevel@tonic-gate nssin.arg.nss.host.type = type; 6030Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 6040Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 6070Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * We pass in nconf and let the implementation of the 6100Sstevel@tonic-gate * long-named func decide whether to use the switch based on 6110Sstevel@tonic-gate * nc_nlookups. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate neterr = 6140Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate (void) freenetconfigent(nconf); 6170Sstevel@tonic-gate if (neterr != ND_OK) { 6180Sstevel@tonic-gate __IPv6_cleanup(buf); 6190Sstevel@tonic-gate return (NULL); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate free(buf); 6220Sstevel@tonic-gate return (nssout.nss.host.hent); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * If we got here, unknown type. 6260Sstevel@tonic-gate */ 6270Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 6280Sstevel@tonic-gate return (NULL); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate void 6320Sstevel@tonic-gate freehostent(struct hostent *hent) 6330Sstevel@tonic-gate { 6340Sstevel@tonic-gate free(hent); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate static int 6380Sstevel@tonic-gate __ai_addrconfig(int af) 6390Sstevel@tonic-gate { 6400Sstevel@tonic-gate struct lifnum lifn; 6410Sstevel@tonic-gate hrtime_t now, *then; 6420Sstevel@tonic-gate static hrtime_t then4, then6; /* the last time we updated ifnum# */ 6430Sstevel@tonic-gate static int ifnum4 = -1, ifnum6 = -1; 6440Sstevel@tonic-gate int *num; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate switch (af) { 6470Sstevel@tonic-gate case AF_INET: 6480Sstevel@tonic-gate num = &ifnum4; 6490Sstevel@tonic-gate then = &then4; 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate case AF_INET6: 6520Sstevel@tonic-gate num = &ifnum6; 6530Sstevel@tonic-gate then = &then6; 6540Sstevel@tonic-gate break; 6550Sstevel@tonic-gate default: 6560Sstevel@tonic-gate return (0); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate /* 6600Sstevel@tonic-gate * We don't need to check this every time someone does a name 6610Sstevel@tonic-gate * lookup. Do it every IFNUM_TIMEOUT for each address family. 6620Sstevel@tonic-gate * 6630Sstevel@tonic-gate * There's no need to protect all of this with a lock. The 6640Sstevel@tonic-gate * worst that can happen is that we update the interface count 6650Sstevel@tonic-gate * twice instead of once. That's no big deal. 6660Sstevel@tonic-gate */ 6670Sstevel@tonic-gate now = gethrtime(); 6680Sstevel@tonic-gate if (*num == -1 || ((now - *then) >= IFNUM_TIMEOUT)) { 6690Sstevel@tonic-gate lifn.lifn_family = af; 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * We want to determine if this machine knows anything 6720Sstevel@tonic-gate * at all about the address family; the status of the 6730Sstevel@tonic-gate * interface is less important. Hence, set 6740Sstevel@tonic-gate * 'lifn_flags' to zero. 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate lifn.lifn_flags = 0; 6770Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFNUM, &lifn) < 0) 6780Sstevel@tonic-gate return (-1); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate *num = lifn.lifn_count; 6810Sstevel@tonic-gate *then = now; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate return (*num); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * This routine will either convert an IPv4 address to a mapped or compat 6890Sstevel@tonic-gate * IPv6 (if he6 == NULL) or merge IPv6 (he6) addresses with mapped 6900Sstevel@tonic-gate * v4 (he4) addresses. In either case, the results are returned in res. 6910Sstevel@tonic-gate * Caller must provide all buffers. 6920Sstevel@tonic-gate * Inputs: 6930Sstevel@tonic-gate * he4 pointer to IPv4 buffer 6940Sstevel@tonic-gate * he6 pointer to IPv6 buffer (NULL if not merging v4/v6 6950Sstevel@tonic-gate * res pointer to results buffer 6960Sstevel@tonic-gate * mapped mapped == 1, map IPv4 : mapped == 0, compat IPv4 6970Sstevel@tonic-gate * mapped flag is ignored if he6 != NULL 6980Sstevel@tonic-gate * 6990Sstevel@tonic-gate * The results are packed into the res->buffer as follows: 7000Sstevel@tonic-gate * <--------------- buffer + buflen --------------------------------------> 7010Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 7020Sstevel@tonic-gate * | pointers vector | pointers vector | aliases grow | addresses grow | 7030Sstevel@tonic-gate * | for addresses | for aliases | | | 7040Sstevel@tonic-gate * | this way -> | this way -> | <- this way |<- this way | 7050Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 7060Sstevel@tonic-gate * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate static struct hostent * 7090Sstevel@tonic-gate __mapv4tov6(struct hostent *he4, struct hostent *he6, nss_XbyY_buf_t *res, 7100Sstevel@tonic-gate int mapped) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate char *buffer, *limit; 7130Sstevel@tonic-gate int buflen = res->buflen; 7140Sstevel@tonic-gate struct in6_addr *addr6p; 7150Sstevel@tonic-gate char *buff_locp; 7160Sstevel@tonic-gate struct hostent *host; 7170Sstevel@tonic-gate int count = 0, len, i; 7180Sstevel@tonic-gate char *h_namep; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate if (he4 == NULL || res == NULL) { 7210Sstevel@tonic-gate return (NULL); 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate limit = res->buffer + buflen; 7240Sstevel@tonic-gate host = (struct hostent *)res->result; 7250Sstevel@tonic-gate buffer = res->buffer; 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in6_addr)); 7280Sstevel@tonic-gate host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); 7290Sstevel@tonic-gate if ((char *)host->h_addr_list >= limit || 7300Sstevel@tonic-gate buff_locp <= (char *)host->h_addr_list) { 7310Sstevel@tonic-gate return (NULL); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate if (he6 == NULL) { 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * If he6==NULL, map the v4 address into the v6 address format. 7360Sstevel@tonic-gate * This is used for getipnodebyaddr() (single address, mapped or 7370Sstevel@tonic-gate * compatible) or for v4 mapped for getipnodebyname(), which 7380Sstevel@tonic-gate * could be multiple addresses. This could also be a literal 7390Sstevel@tonic-gate * address string, which is why there is a inet_addr() call. 7400Sstevel@tonic-gate */ 7410Sstevel@tonic-gate for (i = 0; he4->h_addr_list[i] != NULL; i++) { 7420Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 7430Sstevel@tonic-gate if (buff_locp <= 7440Sstevel@tonic-gate (char *)&(host->h_addr_list[count + 1])) { 7450Sstevel@tonic-gate /* 7460Sstevel@tonic-gate * Has to be room for the pointer to the address we're 7470Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate return (NULL); 7500Sstevel@tonic-gate } 751*132Srobinson /* LINTED pointer cast */ 7520Sstevel@tonic-gate addr6p = (struct in6_addr *)buff_locp; 7530Sstevel@tonic-gate host->h_addr_list[count] = (char *)addr6p; 7540Sstevel@tonic-gate bzero(addr6p->s6_addr, sizeof (struct in6_addr)); 7550Sstevel@tonic-gate if (mapped) { 7560Sstevel@tonic-gate addr6p->s6_addr[10] = 0xff; 7570Sstevel@tonic-gate addr6p->s6_addr[11] = 0xff; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate bcopy((char *)he4->h_addr_list[i], 7600Sstevel@tonic-gate &addr6p->s6_addr[12], sizeof (struct in_addr)); 7610Sstevel@tonic-gate ++count; 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Set last array element to NULL and add cname as first alias 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate host->h_addr_list[count] = NULL; 7670Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 7680Sstevel@tonic-gate count = 0; 7690Sstevel@tonic-gate if ((int)(inet_addr(he4->h_name)) != -1) { 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * Literal address string, since we're mapping, we need the IPv6 7720Sstevel@tonic-gate * V4 mapped literal address string for h_name. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate char tmpstr[128]; 775*132Srobinson (void) inet_ntop(AF_INET6, host->h_addr_list[0], tmpstr, 7760Sstevel@tonic-gate sizeof (tmpstr)); 7770Sstevel@tonic-gate buff_locp -= (len = strlen(tmpstr) + 1); 7780Sstevel@tonic-gate h_namep = tmpstr; 7790Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 7800Sstevel@tonic-gate return (NULL); 7810Sstevel@tonic-gate bcopy(h_namep, buff_locp, len); 7820Sstevel@tonic-gate host->h_name = buff_locp; 7830Sstevel@tonic-gate host->h_aliases = NULL; /* no aliases for literal */ 7840Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 7850Sstevel@tonic-gate host->h_addrtype = AF_INET6; 7860Sstevel@tonic-gate return (host); /* we're done, return result */ 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate /* 7890Sstevel@tonic-gate * Not a literal address string, so just copy h_name. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_name) + 1); 7920Sstevel@tonic-gate h_namep = he4->h_name; 7930Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 7940Sstevel@tonic-gate return (NULL); 7950Sstevel@tonic-gate bcopy(h_namep, buff_locp, len); 7960Sstevel@tonic-gate host->h_name = buff_locp; 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Pass 2 (IPv4 aliases): 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate for (i = 0; he4->h_aliases[i] != NULL; i++) { 8010Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_aliases[i]) + 1); 8020Sstevel@tonic-gate if (buff_locp <= 8030Sstevel@tonic-gate (char *)&(host->h_aliases[count + 1])) { 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8060Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8070Sstevel@tonic-gate */ 8080Sstevel@tonic-gate return (NULL); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 8110Sstevel@tonic-gate bcopy((char *)he4->h_aliases[i], buff_locp, len); 8120Sstevel@tonic-gate ++count; 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate host->h_aliases[count] = NULL; 8150Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 8160Sstevel@tonic-gate host->h_addrtype = AF_INET6; 8170Sstevel@tonic-gate return (host); 8180Sstevel@tonic-gate } else { 8190Sstevel@tonic-gate /* 8200Sstevel@tonic-gate * Merge IPv4 mapped addresses with IPv6 addresses. The 8210Sstevel@tonic-gate * IPv6 address will go in first, followed by the v4 mapped. 8220Sstevel@tonic-gate * 8230Sstevel@tonic-gate * Pass 1 (IPv6 addresses): 8240Sstevel@tonic-gate */ 8250Sstevel@tonic-gate for (i = 0; he6->h_addr_list[i] != NULL; i++) { 8260Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 8270Sstevel@tonic-gate if (buff_locp <= 8280Sstevel@tonic-gate (char *)&(host->h_addr_list[count + 1])) { 8290Sstevel@tonic-gate /* 8300Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8310Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate return (NULL); 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate host->h_addr_list[count] = buff_locp; 8360Sstevel@tonic-gate bcopy((char *)he6->h_addr_list[i], buff_locp, 8370Sstevel@tonic-gate sizeof (struct in6_addr)); 8380Sstevel@tonic-gate ++count; 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * Pass 1 (IPv4 mapped addresses): 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate for (i = 0; he4->h_addr_list[i] != NULL; i++) { 8440Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 8450Sstevel@tonic-gate if (buff_locp <= 8460Sstevel@tonic-gate (char *)&(host->h_addr_list[count + 1])) { 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8490Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate return (NULL); 8520Sstevel@tonic-gate } 853*132Srobinson /* LINTED pointer cast */ 8540Sstevel@tonic-gate addr6p = (struct in6_addr *)buff_locp; 8550Sstevel@tonic-gate host->h_addr_list[count] = (char *)addr6p; 8560Sstevel@tonic-gate bzero(addr6p->s6_addr, sizeof (struct in6_addr)); 8570Sstevel@tonic-gate addr6p->s6_addr[10] = 0xff; 8580Sstevel@tonic-gate addr6p->s6_addr[11] = 0xff; 8590Sstevel@tonic-gate bcopy(he4->h_addr_list[i], &addr6p->s6_addr[12], 8600Sstevel@tonic-gate sizeof (struct in_addr)); 8610Sstevel@tonic-gate ++count; 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * Pass 2 (IPv6 aliases, host name first). We start h_aliases 8650Sstevel@tonic-gate * one after where h_addr_list array ended. This is where cname 8660Sstevel@tonic-gate * is put, followed by all aliases. Reset count to 0, for index 8670Sstevel@tonic-gate * in the h_aliases array. 8680Sstevel@tonic-gate */ 8690Sstevel@tonic-gate host->h_addr_list[count] = NULL; 8700Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 8710Sstevel@tonic-gate count = 0; 8720Sstevel@tonic-gate buff_locp -= (len = strlen(he6->h_name) + 1); 8730Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 8740Sstevel@tonic-gate return (NULL); 8750Sstevel@tonic-gate bcopy(he6->h_name, buff_locp, len); 8760Sstevel@tonic-gate host->h_name = buff_locp; 8770Sstevel@tonic-gate for (i = 0; he6->h_aliases[i] != NULL; i++) { 8780Sstevel@tonic-gate buff_locp -= (len = strlen(he6->h_aliases[i]) + 1); 8790Sstevel@tonic-gate if (buff_locp <= 8800Sstevel@tonic-gate (char *)&(host->h_aliases[count + 1])) { 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8830Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8840Sstevel@tonic-gate */ 8850Sstevel@tonic-gate return (NULL); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 8880Sstevel@tonic-gate bcopy((char *)he6->h_aliases[i], buff_locp, len); 8890Sstevel@tonic-gate ++count; 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate /* 8920Sstevel@tonic-gate * Pass 2 (IPv4 aliases): 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate for (i = 0; he4->h_aliases[i] != NULL; i++) { 8950Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_aliases[i]) + 1); 8960Sstevel@tonic-gate if (buff_locp <= 8970Sstevel@tonic-gate (char *)&(host->h_aliases[count + 1])) { 8980Sstevel@tonic-gate /* 8990Sstevel@tonic-gate * Has to be room for the pointer to the address we're 9000Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 9010Sstevel@tonic-gate */ 9020Sstevel@tonic-gate return (NULL); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 9050Sstevel@tonic-gate bcopy((char *)he4->h_aliases[i], buff_locp, len); 9060Sstevel@tonic-gate ++count; 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate host->h_aliases[count] = NULL; 9090Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 9100Sstevel@tonic-gate host->h_addrtype = AF_INET6; 9110Sstevel@tonic-gate return (host); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate /* 9160Sstevel@tonic-gate * This routine will convert a mapped v4 hostent (AF_INET6) to a 9170Sstevel@tonic-gate * AF_INET hostent. If no mapped addrs found, then a NULL is returned. 9180Sstevel@tonic-gate * If mapped addrs found, then a new buffer is alloc'd and all the v4 mapped 9190Sstevel@tonic-gate * addresses are extracted and copied to it. On sucess, a pointer to a new 9200Sstevel@tonic-gate * hostent is returned. 9210Sstevel@tonic-gate * There are two possible errors in which case a NULL is returned. 9220Sstevel@tonic-gate * One of two error codes are returned: 9230Sstevel@tonic-gate * 9240Sstevel@tonic-gate * NO_RECOVERY - a malloc failed or the like for which there's no recovery. 9250Sstevel@tonic-gate * NO_ADDRESS - after filtering all the v4, there was nothing left! 9260Sstevel@tonic-gate * 9270Sstevel@tonic-gate * Inputs: 9280Sstevel@tonic-gate * he pointer to hostent with mapped v4 addresses 9290Sstevel@tonic-gate * filter_error pointer to return error code 9300Sstevel@tonic-gate * Return: 9310Sstevel@tonic-gate * pointer to a malloc'd hostent with v4 addresses. 9320Sstevel@tonic-gate * 9330Sstevel@tonic-gate * The results are packed into the res->buffer as follows: 9340Sstevel@tonic-gate * <--------------- buffer + buflen --------------------------------------> 9350Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 9360Sstevel@tonic-gate * | pointers vector | pointers vector | aliases grow | addresses grow | 9370Sstevel@tonic-gate * | for addresses | for aliases | | | 9380Sstevel@tonic-gate * | this way -> | this way -> | <- this way |<- this way | 9390Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 9400Sstevel@tonic-gate * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate struct hostent * 9430Sstevel@tonic-gate __mappedtov4(struct hostent *he, int *extract_error) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate char *buffer, *limit; 9460Sstevel@tonic-gate nss_XbyY_buf_t *res; 9470Sstevel@tonic-gate int buflen = NSS_BUFLEN_HOSTS; 9480Sstevel@tonic-gate struct in_addr *addr4p; 9490Sstevel@tonic-gate char *buff_locp; 9500Sstevel@tonic-gate struct hostent *host; 9510Sstevel@tonic-gate int count = 0, len, i; 9520Sstevel@tonic-gate char *h_namep; 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate if (he == NULL) { 9550Sstevel@tonic-gate *extract_error = NO_ADDRESS; 9560Sstevel@tonic-gate return (NULL); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate if ((__find_mapped(he, 0)) == 0) { 9590Sstevel@tonic-gate *extract_error = NO_ADDRESS; 9600Sstevel@tonic-gate return (NULL); 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate if ((res = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == 0) { 9630Sstevel@tonic-gate *extract_error = NO_RECOVERY; 9640Sstevel@tonic-gate return (NULL); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate limit = res->buffer + buflen; 9670Sstevel@tonic-gate host = (struct hostent *)res->result; 9680Sstevel@tonic-gate buffer = res->buffer; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in_addr)); 9710Sstevel@tonic-gate host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); 9720Sstevel@tonic-gate if ((char *)host->h_addr_list >= limit || 9730Sstevel@tonic-gate buff_locp <= (char *)host->h_addr_list) 9740Sstevel@tonic-gate goto cleanup; 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * "Unmap" the v4 mapped address(es) into a v4 hostent format. 9770Sstevel@tonic-gate * This is used for getipnodebyaddr() (single address) or for 9780Sstevel@tonic-gate * v4 mapped for getipnodebyname(), which could be multiple 9790Sstevel@tonic-gate * addresses. This could also be a literal address string, 9800Sstevel@tonic-gate * which is why there is a inet_addr() call. 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate for (i = 0; he->h_addr_list[i] != NULL; i++) { 983*132Srobinson /* LINTED pointer cast */ 9840Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED((struct in6_addr *) 9850Sstevel@tonic-gate he->h_addr_list[i])) 9860Sstevel@tonic-gate continue; 9870Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 9880Sstevel@tonic-gate /* 9890Sstevel@tonic-gate * Has to be room for the pointer to the address we're 9900Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 9910Sstevel@tonic-gate */ 9920Sstevel@tonic-gate if (buff_locp <= 9930Sstevel@tonic-gate (char *)&(host->h_addr_list[count + 1])) 9940Sstevel@tonic-gate goto cleanup; 995*132Srobinson /* LINTED pointer cast */ 9960Sstevel@tonic-gate addr4p = (struct in_addr *)buff_locp; 9970Sstevel@tonic-gate host->h_addr_list[count] = (char *)addr4p; 9980Sstevel@tonic-gate bzero((char *)&addr4p->s_addr, 9990Sstevel@tonic-gate sizeof (struct in_addr)); 1000*132Srobinson /* LINTED pointer cast */ 10010Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR( 10020Sstevel@tonic-gate (struct in6_addr *)he->h_addr_list[i], 10030Sstevel@tonic-gate addr4p); 10040Sstevel@tonic-gate ++count; 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate /* 10070Sstevel@tonic-gate * Set last array element to NULL and add cname as first alias 10080Sstevel@tonic-gate */ 10090Sstevel@tonic-gate host->h_addr_list[count] = NULL; 10100Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 10110Sstevel@tonic-gate count = 0; 10120Sstevel@tonic-gate /* Copy official host name */ 10130Sstevel@tonic-gate buff_locp -= (len = strlen(he->h_name) + 1); 10140Sstevel@tonic-gate h_namep = he->h_name; 10150Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 10160Sstevel@tonic-gate goto cleanup; 10170Sstevel@tonic-gate bcopy(h_namep, buff_locp, len); 10180Sstevel@tonic-gate host->h_name = buff_locp; 10190Sstevel@tonic-gate /* 10200Sstevel@tonic-gate * Pass 2 (IPv4 aliases): 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate for (i = 0; he->h_aliases[i] != NULL; i++) { 10230Sstevel@tonic-gate buff_locp -= (len = strlen(he->h_aliases[i]) + 1); 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * Has to be room for the pointer to the address we're 10260Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 10270Sstevel@tonic-gate */ 10280Sstevel@tonic-gate if (buff_locp <= 10290Sstevel@tonic-gate (char *)&(host->h_aliases[count + 1])) 10300Sstevel@tonic-gate goto cleanup; 10310Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 10320Sstevel@tonic-gate bcopy((char *)he->h_aliases[i], buff_locp, len); 10330Sstevel@tonic-gate ++count; 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate host->h_aliases[count] = NULL; 10360Sstevel@tonic-gate host->h_length = sizeof (struct in_addr); 10370Sstevel@tonic-gate host->h_addrtype = AF_INET; 10380Sstevel@tonic-gate free(res); 10390Sstevel@tonic-gate return (host); 10400Sstevel@tonic-gate cleanup: 10410Sstevel@tonic-gate *extract_error = NO_RECOVERY; 10420Sstevel@tonic-gate (void) __IPv6_cleanup(res); 10430Sstevel@tonic-gate return (NULL); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate /* 10470Sstevel@tonic-gate * This routine takes as input a pointer to a hostent and filters out 10480Sstevel@tonic-gate * the type of addresses specified by the af argument. AF_INET 10490Sstevel@tonic-gate * indicates that the caller wishes to filter out IPv4-mapped 10500Sstevel@tonic-gate * addresses, and AF_INET6 indicates that the caller wishes to filter 10510Sstevel@tonic-gate * out IPv6 addresses which aren't IPv4-mapped. If filtering would 10520Sstevel@tonic-gate * result in all addresses being filtered out, a NULL pointer is returned. 10530Sstevel@tonic-gate * Otherwise, the he pointer passed in is returned, even if no addresses 10540Sstevel@tonic-gate * were filtered out. 10550Sstevel@tonic-gate */ 10560Sstevel@tonic-gate static struct hostent * 10570Sstevel@tonic-gate __filter_addresses(int af, struct hostent *he) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate struct in6_addr **in6addrlist, **in6addr; 10600Sstevel@tonic-gate boolean_t isipv4mapped; 10610Sstevel@tonic-gate int i = 0; 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (he == NULL) 10640Sstevel@tonic-gate return (NULL); 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate in6addrlist = (struct in6_addr **)he->h_addr_list; 10670Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 10680Sstevel@tonic-gate isipv4mapped = IN6_IS_ADDR_V4MAPPED(*in6addr); 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate if ((af == AF_INET && !isipv4mapped) || 10710Sstevel@tonic-gate (af == AF_INET6 && isipv4mapped)) { 10720Sstevel@tonic-gate if (in6addrlist[i] != *in6addr) 10730Sstevel@tonic-gate in6addrlist[i] = *in6addr; 10740Sstevel@tonic-gate i++; 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate if (i == 0) { 10790Sstevel@tonic-gate /* We filtered everything out. */ 10800Sstevel@tonic-gate return (NULL); 10810Sstevel@tonic-gate } else { 10820Sstevel@tonic-gate /* NULL terminate the list and return the hostent */ 10830Sstevel@tonic-gate in6addrlist[i] = NULL; 10840Sstevel@tonic-gate return (he); 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* 10890Sstevel@tonic-gate * This routine searches a hostent for v4 mapped IPv6 addresses. 10900Sstevel@tonic-gate * he hostent structure to seach 10910Sstevel@tonic-gate * find_both flag indicating if only want mapped or both map'd and v6 10920Sstevel@tonic-gate * return values: 10930Sstevel@tonic-gate * 0 = No mapped addresses 10940Sstevel@tonic-gate * 1 = Mapped v4 address found (returns on first one found) 10950Sstevel@tonic-gate * 2 = Both v6 and v4 mapped are present 10960Sstevel@tonic-gate * 10970Sstevel@tonic-gate * If hostent passed in with no addresses, zero will be returned. 10980Sstevel@tonic-gate */ 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate static int 11010Sstevel@tonic-gate __find_mapped(struct hostent *he, int find_both) 11020Sstevel@tonic-gate { 11030Sstevel@tonic-gate int i; 11040Sstevel@tonic-gate int mapd_found = 0; 11050Sstevel@tonic-gate int v6_found = 0; 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate for (i = 0; he->h_addr_list[i] != NULL; i++) { 1108*132Srobinson /* LINTED pointer cast */ 11090Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED( 11100Sstevel@tonic-gate (struct in6_addr *)he->h_addr_list[i])) { 11110Sstevel@tonic-gate if (find_both) 11120Sstevel@tonic-gate mapd_found = 1; 11130Sstevel@tonic-gate else 11140Sstevel@tonic-gate return (1); 11150Sstevel@tonic-gate } else { 11160Sstevel@tonic-gate v6_found = 1; 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate /* save some iterations once both found */ 11190Sstevel@tonic-gate if (mapd_found && v6_found) 11200Sstevel@tonic-gate return (2); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate return (mapd_found); 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate /* 11260Sstevel@tonic-gate * This routine was added specifically for the IPv6 getipnodeby*() APIs. This 11270Sstevel@tonic-gate * separates the result pointer (ptr to hostent+data buf) from the 11280Sstevel@tonic-gate * nss_XbyY_buf_t ptr (required for nsswitch API). The returned hostent ptr 11290Sstevel@tonic-gate * can be passed to freehostent() and freed independently. 11300Sstevel@tonic-gate * 11310Sstevel@tonic-gate * bufp->result bufp->buffer 11320Sstevel@tonic-gate * | | 11330Sstevel@tonic-gate * V V 11340Sstevel@tonic-gate * ------------------------------------------------...-- 11350Sstevel@tonic-gate * |struct hostent |addresses aliases | 11360Sstevel@tonic-gate * ------------------------------------------------...-- 11370Sstevel@tonic-gate * | |<--------bufp->buflen-------------->| 11380Sstevel@tonic-gate */ 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate #define ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1)) 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate static nss_XbyY_buf_t * 11430Sstevel@tonic-gate __IPv6_alloc(int bufsz) 11440Sstevel@tonic-gate { 11450Sstevel@tonic-gate nss_XbyY_buf_t *bufp; 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate if ((bufp = malloc(sizeof (nss_XbyY_buf_t))) == NULL) 11480Sstevel@tonic-gate return (NULL); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate if ((bufp->result = malloc(ALIGN(sizeof (struct hostent)) + bufsz)) == 11510Sstevel@tonic-gate NULL) { 11520Sstevel@tonic-gate free(bufp); 11530Sstevel@tonic-gate return (NULL); 11540Sstevel@tonic-gate } 11550Sstevel@tonic-gate bufp->buffer = (char *)(bufp->result) + sizeof (struct hostent); 11560Sstevel@tonic-gate bufp->buflen = bufsz; 11570Sstevel@tonic-gate return (bufp); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* 11610Sstevel@tonic-gate * This routine is use only for error return cleanup. This will free the 11620Sstevel@tonic-gate * hostent pointer, so don't use for successful returns. 11630Sstevel@tonic-gate */ 11640Sstevel@tonic-gate static void 11650Sstevel@tonic-gate __IPv6_cleanup(nss_XbyY_buf_t *bufp) 11660Sstevel@tonic-gate { 11670Sstevel@tonic-gate if (bufp == NULL) 11680Sstevel@tonic-gate return; 11690Sstevel@tonic-gate if (bufp->result != NULL) 11700Sstevel@tonic-gate free(bufp->result); 11710Sstevel@tonic-gate free(bufp); 11720Sstevel@tonic-gate } 1173