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 58867SGirish.Moodalbail@Sun.COM * Common Development and Distribution License (the "License"). 68867SGirish.Moodalbail@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21132Srobinson 220Sstevel@tonic-gate /* 23*11537SCasper.Dik@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * This file defines and implements the re-entrant getipnodebyname(), 270Sstevel@tonic-gate * getipnodebyaddr(), and freehostent() routines for IPv6. These routines 280Sstevel@tonic-gate * follow use the netdir_getbyYY() (see netdir_inet.c). 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * lib/libnsl/nss/getipnodeby.c 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include "mt.h" 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <unistd.h> 360Sstevel@tonic-gate #include <stropts.h> 370Sstevel@tonic-gate #include <ctype.h> 380Sstevel@tonic-gate #include <string.h> 390Sstevel@tonic-gate #include <strings.h> 400Sstevel@tonic-gate #include <netdb.h> 410Sstevel@tonic-gate #include <stdio.h> 420Sstevel@tonic-gate #include <arpa/inet.h> 430Sstevel@tonic-gate #include <nss_dbdefs.h> 440Sstevel@tonic-gate #include <netinet/in.h> 450Sstevel@tonic-gate #include <sys/socket.h> 460Sstevel@tonic-gate #include <sys/sockio.h> 470Sstevel@tonic-gate #include <nss_netdir.h> 480Sstevel@tonic-gate #include <net/if.h> 490Sstevel@tonic-gate #include <netinet/in.h> 500Sstevel@tonic-gate #include <netdir.h> 510Sstevel@tonic-gate #include <thread.h> 520Sstevel@tonic-gate #include <synch.h> 530Sstevel@tonic-gate #include <fcntl.h> 540Sstevel@tonic-gate #include <sys/time.h> 550Sstevel@tonic-gate #include "nss.h" 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define IPV6_LITERAL_CHAR ':' 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * The number of nanoseconds getipnodebyname() waits before getting 610Sstevel@tonic-gate * fresh interface count information with SIOCGLIFNUM. The default is 620Sstevel@tonic-gate * five minutes. 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate #define IFNUM_TIMEOUT ((hrtime_t)300 * NANOSEC) 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Bits in the bitfield returned by getipnodebyname_processflags(). 680Sstevel@tonic-gate * 690Sstevel@tonic-gate * IPNODE_WANTIPV6 The user wants IPv6 addresses returned. 700Sstevel@tonic-gate * IPNODE_WANTIPV4 The user wants IPv4 addresses returned. 710Sstevel@tonic-gate * IPNODE_IPV4IFNOIPV6 The user only wants IPv4 addresses returned if no IPv6 720Sstevel@tonic-gate * addresses are returned. 730Sstevel@tonic-gate * IPNODE_LOOKUPIPNODES getipnodebyname() needs to lookup the name in ipnodes. 740Sstevel@tonic-gate * IPNODE_LOOKUPHOSTS getipnodebyname() needs to lookup the name in hosts. 750Sstevel@tonic-gate * IPNODE_ISLITERAL The name supplied is a literal address string. 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate #define IPNODE_WANTIPV6 0x00000001u 780Sstevel@tonic-gate #define IPNODE_WANTIPV4 0x00000002u 790Sstevel@tonic-gate #define IPNODE_IPV4IFNOIPV6 0x00000004u 800Sstevel@tonic-gate #define IPNODE_LOOKUPIPNODES 0x00000008u 810Sstevel@tonic-gate #define IPNODE_LOOKUPHOSTS 0x00000010u 820Sstevel@tonic-gate #define IPNODE_LITERAL 0x00000020u 830Sstevel@tonic-gate #define IPNODE_IPV4 (IPNODE_WANTIPV4 | IPNODE_IPV4IFNOIPV6) 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * The default set of bits corresponding to a getipnodebyname() flags 870Sstevel@tonic-gate * argument of AI_DEFAULT. 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate #define IPNODE_DEFAULT (IPNODE_WANTIPV6 | IPNODE_IPV4 | \ 900Sstevel@tonic-gate IPNODE_LOOKUPIPNODES | IPNODE_LOOKUPHOSTS) 910Sstevel@tonic-gate 920Sstevel@tonic-gate extern struct netconfig *__rpc_getconfip(char *); 930Sstevel@tonic-gate 940Sstevel@tonic-gate static struct hostent *__mapv4tov6(struct hostent *, struct hostent *, 950Sstevel@tonic-gate nss_XbyY_buf_t *, int); 960Sstevel@tonic-gate struct hostent *__mappedtov4(struct hostent *, int *); 970Sstevel@tonic-gate static struct hostent *__filter_addresses(int, struct hostent *); 980Sstevel@tonic-gate static int __find_mapped(struct hostent *, int); 990Sstevel@tonic-gate static nss_XbyY_buf_t *__IPv6_alloc(int); 1000Sstevel@tonic-gate static void __IPv6_cleanup(nss_XbyY_buf_t *); 1010Sstevel@tonic-gate static int __ai_addrconfig(int); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate #ifdef PIC 1050Sstevel@tonic-gate struct hostent * 1060Sstevel@tonic-gate _uncached_getipnodebyname(const char *nam, struct hostent *result, 1070Sstevel@tonic-gate char *buffer, int buflen, int af_family, int flags, int *h_errnop) 1080Sstevel@tonic-gate { 109132Srobinson return (_switch_getipnodebyname_r(nam, result, buffer, buflen, 1108867SGirish.Moodalbail@Sun.COM af_family, flags, h_errnop)); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate struct hostent * 1140Sstevel@tonic-gate _uncached_getipnodebyaddr(const char *addr, int length, int type, 1150Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate if (type == AF_INET) 1180Sstevel@tonic-gate return (_switch_gethostbyaddr_r(addr, length, type, 1198867SGirish.Moodalbail@Sun.COM result, buffer, buflen, h_errnop)); 1200Sstevel@tonic-gate else if (type == AF_INET6) 1210Sstevel@tonic-gate return (_switch_getipnodebyaddr_r(addr, length, type, 1228867SGirish.Moodalbail@Sun.COM result, buffer, buflen, h_errnop)); 1230Sstevel@tonic-gate return (NULL); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate #endif 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Given a name, an address family, and a set of flags, return a 1290Sstevel@tonic-gate * bitfield that getipnodebyname() will use. 1300Sstevel@tonic-gate */ 1310Sstevel@tonic-gate static uint_t 1320Sstevel@tonic-gate getipnodebyname_processflags(const char *name, int af, int flags) 1330Sstevel@tonic-gate { 1340Sstevel@tonic-gate uint_t ipnode_bits = IPNODE_DEFAULT; 1350Sstevel@tonic-gate boolean_t ipv6configured = B_FALSE; 1360Sstevel@tonic-gate boolean_t ipv4configured = B_FALSE; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * If AI_ADDRCONFIG is specified, we need to determine the number 1400Sstevel@tonic-gate * of addresses of each address family configured on the system as 1410Sstevel@tonic-gate * appropriate. 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate if (flags & AI_ADDRCONFIG) { 1440Sstevel@tonic-gate ipv6configured = (af == AF_INET6 && 1450Sstevel@tonic-gate __ai_addrconfig(AF_INET6) > 0); 1460Sstevel@tonic-gate ipv4configured = ((af == AF_INET || (flags & AI_V4MAPPED)) && 1470Sstevel@tonic-gate __ai_addrconfig(AF_INET) > 0); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * Determine what kinds of addresses the user is interested 1520Sstevel@tonic-gate * in getting back. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate switch (af) { 1550Sstevel@tonic-gate case AF_INET6: 1560Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv6configured) 1570Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate if (flags & AI_V4MAPPED) { 1600Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv4configured) { 1610Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1620Sstevel@tonic-gate } else if (flags & AI_ALL) { 1630Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4IFNOIPV6; 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate } else { 1660Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate break; 1690Sstevel@tonic-gate case AF_INET: 1700Sstevel@tonic-gate if ((flags & AI_ADDRCONFIG) && !ipv4configured) 1710Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4; 1720Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 1730Sstevel@tonic-gate ipnode_bits &= ~IPNODE_IPV4IFNOIPV6; 1740Sstevel@tonic-gate break; 1750Sstevel@tonic-gate default: 1760Sstevel@tonic-gate ipnode_bits = 0; 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * If we're not looking for IPv4 addresses, don't bother looking 1820Sstevel@tonic-gate * in hosts. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate if (!(ipnode_bits & IPNODE_WANTIPV4)) 1850Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * Determine if name is a literal IP address. This will 1890Sstevel@tonic-gate * further narrow down what type of lookup we're going to do. 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate if (strchr(name, IPV6_LITERAL_CHAR) != NULL) { 1920Sstevel@tonic-gate /* Literal IPv6 address */ 1930Sstevel@tonic-gate ipnode_bits |= IPNODE_LITERAL; 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * In s9 we accepted the literal without filtering independent 1960Sstevel@tonic-gate * of what family was passed in hints. We continue to do 1970Sstevel@tonic-gate * this. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate ipnode_bits |= (IPNODE_WANTIPV6 | IPNODE_WANTIPV4); 2000Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 201132Srobinson } else if (inet_addr(name) != 0xffffffffU) { 2020Sstevel@tonic-gate /* Literal IPv4 address */ 2030Sstevel@tonic-gate ipnode_bits |= (IPNODE_LITERAL | IPNODE_WANTIPV4); 2040Sstevel@tonic-gate ipnode_bits &= ~IPNODE_WANTIPV6; 2050Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPIPNODES; 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate return (ipnode_bits); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate struct hostent * 2110Sstevel@tonic-gate getipnodebyname(const char *name, int af, int flags, int *error_num) 2120Sstevel@tonic-gate { 2130Sstevel@tonic-gate struct hostent *hp = NULL; 2140Sstevel@tonic-gate nss_XbyY_buf_t *buf4 = NULL; 2150Sstevel@tonic-gate nss_XbyY_buf_t *buf6 = NULL; 2160Sstevel@tonic-gate struct netconfig *nconf; 2170Sstevel@tonic-gate struct nss_netdirbyname_in nssin; 2180Sstevel@tonic-gate union nss_netdirbyname_out nssout; 2190Sstevel@tonic-gate int ret; 2200Sstevel@tonic-gate uint_t ipnode_bits; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 2230Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 2240Sstevel@tonic-gate *error_num = NO_RECOVERY; 2250Sstevel@tonic-gate return (NULL); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate ipnode_bits = getipnodebyname_processflags(name, af, flags); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* Make sure we have something to look up. */ 2310Sstevel@tonic-gate if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) { 2320Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 2330Sstevel@tonic-gate goto cleanup; 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * Perform the requested lookups. We always look through 2380Sstevel@tonic-gate * ipnodes first for both IPv4 and IPv6 addresses. Depending 2390Sstevel@tonic-gate * on what was returned and what was needed, we either filter 2400Sstevel@tonic-gate * out the garbage, or ask for more using hosts. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate if (ipnode_bits & IPNODE_LOOKUPIPNODES) { 2430Sstevel@tonic-gate if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) { 2440Sstevel@tonic-gate *error_num = NO_RECOVERY; 2450Sstevel@tonic-gate goto cleanup; 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 2480Sstevel@tonic-gate nssin.arg.nss.host6.name = name; 2490Sstevel@tonic-gate nssin.arg.nss.host6.buf = buf6->buffer; 2500Sstevel@tonic-gate nssin.arg.nss.host6.buflen = buf6->buflen; 2510Sstevel@tonic-gate nssin.arg.nss.host6.af_family = af; 2520Sstevel@tonic-gate nssin.arg.nss.host6.flags = flags; 2530Sstevel@tonic-gate nssout.nss.host.hent = buf6->result; 2540Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 2550Sstevel@tonic-gate ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); 2560Sstevel@tonic-gate if (ret != ND_OK) { 2570Sstevel@tonic-gate __IPv6_cleanup(buf6); 2580Sstevel@tonic-gate buf6 = NULL; 2590Sstevel@tonic-gate } else if (ipnode_bits & IPNODE_WANTIPV4) { 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * buf6 may have all that we need if we either 2620Sstevel@tonic-gate * only wanted IPv4 addresses if there were no 2630Sstevel@tonic-gate * IPv6 addresses returned, or if there are 2640Sstevel@tonic-gate * IPv4-mapped addresses in buf6. If either 2650Sstevel@tonic-gate * of these are true, then there's no need to 2660Sstevel@tonic-gate * look in hosts. 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate if (ipnode_bits & IPNODE_IPV4IFNOIPV6 || 2690Sstevel@tonic-gate __find_mapped(buf6->result, 0) != 0) { 2700Sstevel@tonic-gate ipnode_bits &= ~IPNODE_LOOKUPHOSTS; 2710Sstevel@tonic-gate } else if (!(ipnode_bits & IPNODE_WANTIPV6)) { 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * If all we're looking for are IPv4 2740Sstevel@tonic-gate * addresses and there are none in 2750Sstevel@tonic-gate * buf6 then buf6 is now useless. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate __IPv6_cleanup(buf6); 2780Sstevel@tonic-gate buf6 = NULL; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate if (ipnode_bits & IPNODE_LOOKUPHOSTS) { 2830Sstevel@tonic-gate if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) { 2840Sstevel@tonic-gate *error_num = NO_RECOVERY; 2850Sstevel@tonic-gate goto cleanup; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate nssin.op_t = NSS_HOST; 2880Sstevel@tonic-gate nssin.arg.nss.host.name = name; 2890Sstevel@tonic-gate nssin.arg.nss.host.buf = buf4->buffer; 2900Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf4->buflen; 2910Sstevel@tonic-gate nssout.nss.host.hent = buf4->result; 2920Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 2930Sstevel@tonic-gate ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); 2940Sstevel@tonic-gate if (ret != ND_OK) { 2950Sstevel@tonic-gate __IPv6_cleanup(buf4); 2960Sstevel@tonic-gate buf4 = NULL; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate if (buf6 == NULL && buf4 == NULL) { 3010Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 3020Sstevel@tonic-gate goto cleanup; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* Extract the appropriate addresses from the returned buffer(s). */ 3060Sstevel@tonic-gate switch (af) { 3070Sstevel@tonic-gate case AF_INET6: { 3080Sstevel@tonic-gate if (buf4 != NULL) { 3090Sstevel@tonic-gate nss_XbyY_buf_t *mergebuf; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * The IPv4 results we have need to be 3130Sstevel@tonic-gate * converted to IPv4-mapped addresses, 3140Sstevel@tonic-gate * conditionally merged with the IPv6 3150Sstevel@tonic-gate * results, and the end result needs to be 3160Sstevel@tonic-gate * re-ordered. 3170Sstevel@tonic-gate */ 3180Sstevel@tonic-gate mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES); 3190Sstevel@tonic-gate if (mergebuf == NULL) { 3200Sstevel@tonic-gate *error_num = NO_RECOVERY; 3210Sstevel@tonic-gate goto cleanup; 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate hp = __mapv4tov6(buf4->result, 3240Sstevel@tonic-gate ((buf6 != NULL) ? buf6->result : NULL), 3250Sstevel@tonic-gate mergebuf, 1); 3260Sstevel@tonic-gate if (hp != NULL) 3270Sstevel@tonic-gate order_haddrlist_af(AF_INET6, hp->h_addr_list); 3280Sstevel@tonic-gate else 3290Sstevel@tonic-gate *error_num = NO_RECOVERY; 3300Sstevel@tonic-gate free(mergebuf); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (buf4 == NULL && buf6 != NULL) { 3340Sstevel@tonic-gate hp = buf6->result; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * We have what we need in buf6, but we may need 3380Sstevel@tonic-gate * to filter out some addresses depending on what 3390Sstevel@tonic-gate * is being asked for. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate if (!(ipnode_bits & IPNODE_WANTIPV4)) 3420Sstevel@tonic-gate hp = __filter_addresses(AF_INET, buf6->result); 3430Sstevel@tonic-gate else if (!(ipnode_bits & IPNODE_WANTIPV6)) 3440Sstevel@tonic-gate hp = __filter_addresses(AF_INET6, buf6->result); 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate if (hp == NULL) 3470Sstevel@tonic-gate *error_num = NO_ADDRESS; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate break; 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate case AF_INET: 3540Sstevel@tonic-gate /* We could have results in buf6 or buf4, not both */ 3550Sstevel@tonic-gate if (buf6 != NULL) { 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * Extract the IPv4-mapped addresses from buf6 3580Sstevel@tonic-gate * into hp. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate hp = __mappedtov4(buf6->result, error_num); 3610Sstevel@tonic-gate } else { 3620Sstevel@tonic-gate /* We have what we need in buf4. */ 3630Sstevel@tonic-gate hp = buf4->result; 3640Sstevel@tonic-gate if (ipnode_bits & IPNODE_LITERAL) { 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * There is a special case here for literal 3670Sstevel@tonic-gate * IPv4 address strings. The hosts 3680Sstevel@tonic-gate * front-end sets h_aliases to a one 3690Sstevel@tonic-gate * element array containing a single NULL 3700Sstevel@tonic-gate * pointer (in ndaddr2hent()), while 3710Sstevel@tonic-gate * getipnodebyname() requires h_aliases to 3720Sstevel@tonic-gate * be a NULL pointer itself. We're not 3730Sstevel@tonic-gate * going to change the front-end since it 3740Sstevel@tonic-gate * needs to remain backward compatible for 3750Sstevel@tonic-gate * gethostbyname() and friends. Just set 3760Sstevel@tonic-gate * h_aliases to NULL here instead. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate hp->h_aliases = NULL; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate default: 3850Sstevel@tonic-gate break; 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate cleanup: 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * Free the memory we allocated, but make sure we don't free 3910Sstevel@tonic-gate * the memory we're returning to the caller. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate if (buf6 != NULL) { 3940Sstevel@tonic-gate if (buf6->result == hp) 3950Sstevel@tonic-gate buf6->result = NULL; 3960Sstevel@tonic-gate __IPv6_cleanup(buf6); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate if (buf4 != NULL) { 3990Sstevel@tonic-gate if (buf4->result == hp) 4000Sstevel@tonic-gate buf4->result = NULL; 4010Sstevel@tonic-gate __IPv6_cleanup(buf4); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate (void) freenetconfigent(nconf); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate return (hp); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * This is the IPv6 interface for "gethostbyaddr". 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate struct hostent * 4120Sstevel@tonic-gate getipnodebyaddr(const void *src, size_t len, int type, int *error_num) 4130Sstevel@tonic-gate { 4140Sstevel@tonic-gate struct in6_addr *addr6 = 0; 4150Sstevel@tonic-gate struct in_addr *addr4 = 0; 4160Sstevel@tonic-gate nss_XbyY_buf_t *buf = 0; 4170Sstevel@tonic-gate nss_XbyY_buf_t *res = 0; 4180Sstevel@tonic-gate struct netconfig *nconf; 4190Sstevel@tonic-gate struct hostent *hp = 0; 4200Sstevel@tonic-gate struct nss_netdirbyaddr_in nssin; 4210Sstevel@tonic-gate union nss_netdirbyaddr_out nssout; 4220Sstevel@tonic-gate int neterr; 4230Sstevel@tonic-gate char tmpbuf[64]; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (type == AF_INET6) { 4260Sstevel@tonic-gate if ((addr6 = (struct in6_addr *)src) == NULL) { 4270Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4280Sstevel@tonic-gate return (NULL); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate } else if (type == AF_INET) { 4310Sstevel@tonic-gate if ((addr4 = (struct in_addr *)src) == NULL) { 4320Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4330Sstevel@tonic-gate return (NULL); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate } else { 4360Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4370Sstevel@tonic-gate return (NULL); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Specific case: query for "::" 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) { 4430Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 4440Sstevel@tonic-gate return (NULL); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate /* 4470Sstevel@tonic-gate * Step 1: IPv4-mapped address or IPv4 Compat 4480Sstevel@tonic-gate */ 4490Sstevel@tonic-gate if ((type == AF_INET6 && len == 16) && 4508867SGirish.Moodalbail@Sun.COM ((IN6_IS_ADDR_V4MAPPED(addr6)) || 4518867SGirish.Moodalbail@Sun.COM (IN6_IS_ADDR_V4COMPAT(addr6)))) { 4520Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 4530Sstevel@tonic-gate *error_num = NO_RECOVERY; 4540Sstevel@tonic-gate return (NULL); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 4570Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 4580Sstevel@tonic-gate *error_num = NO_RECOVERY; 4590Sstevel@tonic-gate __IPv6_cleanup(buf); 4600Sstevel@tonic-gate return (NULL); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 4630Sstevel@tonic-gate if (IN6_IS_ADDR_V4COMPAT(addr6)) { 464132Srobinson (void) memcpy(tmpbuf, addr6, sizeof (*addr6)); 4650Sstevel@tonic-gate tmpbuf[10] = 0xffU; 4660Sstevel@tonic-gate tmpbuf[11] = 0xffU; 4670Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)tmpbuf; 4680Sstevel@tonic-gate } else { 4690Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate nssin.arg.nss.host.len = sizeof (struct in6_addr); 4720Sstevel@tonic-gate nssin.arg.nss.host.type = AF_INET6; 4730Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 4740Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 4770Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * We pass in nconf and let the implementation of the 4800Sstevel@tonic-gate * long-named func decide whether to use the switch based on 4810Sstevel@tonic-gate * nc_nlookups. 4820Sstevel@tonic-gate */ 4830Sstevel@tonic-gate neterr = 4848867SGirish.Moodalbail@Sun.COM _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate (void) freenetconfigent(nconf); 4870Sstevel@tonic-gate if (neterr != ND_OK) { 4880Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 4890Sstevel@tonic-gate if (!gethostbyaddr_r(((char *)addr6) + 12, 4908867SGirish.Moodalbail@Sun.COM sizeof (in_addr_t), AF_INET, buf->result, 4918867SGirish.Moodalbail@Sun.COM buf->buffer, buf->buflen, error_num)) { 4920Sstevel@tonic-gate __IPv6_cleanup(buf); 4930Sstevel@tonic-gate return (NULL); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate /* Found one, now format it into mapped/compat addr */ 4960Sstevel@tonic-gate if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 4970Sstevel@tonic-gate __IPv6_cleanup(buf); 4980Sstevel@tonic-gate *error_num = NO_RECOVERY; 4990Sstevel@tonic-gate return (NULL); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate /* Convert IPv4 to mapped/compat address w/name */ 5020Sstevel@tonic-gate hp = res->result; 503132Srobinson (void) __mapv4tov6(buf->result, 0, res, 5048867SGirish.Moodalbail@Sun.COM IN6_IS_ADDR_V4MAPPED(addr6)); 5050Sstevel@tonic-gate __IPv6_cleanup(buf); 5060Sstevel@tonic-gate free(res); 5070Sstevel@tonic-gate return (hp); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * At this point, we'll have a v4mapped hostent. If that's 5110Sstevel@tonic-gate * what was passed in, just return. If the request was a compat, 5120Sstevel@tonic-gate * twiggle the two bytes to make the mapped address a compat. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate hp = buf->result; 5150Sstevel@tonic-gate if (IN6_IS_ADDR_V4COMPAT(addr6)) { 516132Srobinson /* LINTED pointer cast */ 5170Sstevel@tonic-gate addr6 = (struct in6_addr *)hp->h_addr_list[0]; 5180Sstevel@tonic-gate addr6->s6_addr[10] = 0; 5190Sstevel@tonic-gate addr6->s6_addr[11] = 0; 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate free(buf); 5220Sstevel@tonic-gate return (hp); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Step 2: AF_INET, v4 lookup. Since we're going to search the 5260Sstevel@tonic-gate * ipnodes (v6) path first, we need to treat this as a v4mapped 5270Sstevel@tonic-gate * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The 5280Sstevel@tonic-gate * switch backend knows to lookup v4's (not v4mapped) from the 5290Sstevel@tonic-gate * name services. 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate if (type == AF_INET) { 5320Sstevel@tonic-gate struct in6_addr v4mapbuf; 5330Sstevel@tonic-gate addr6 = &v4mapbuf; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(addr4, addr6); 5360Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 5370Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 5380Sstevel@tonic-gate *error_num = NO_RECOVERY; 5390Sstevel@tonic-gate return (NULL); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 5420Sstevel@tonic-gate *error_num = NO_RECOVERY; 5430Sstevel@tonic-gate freenetconfigent(nconf); 5440Sstevel@tonic-gate return (NULL); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 5470Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 5480Sstevel@tonic-gate nssin.arg.nss.host.len = sizeof (struct in6_addr); 5490Sstevel@tonic-gate nssin.arg.nss.host.type = AF_INET6; 5500Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 5510Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 5540Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 5550Sstevel@tonic-gate /* 5560Sstevel@tonic-gate * We pass in nconf and let the implementation of the 5570Sstevel@tonic-gate * long-named func decide whether to use the switch based on 5580Sstevel@tonic-gate * nc_nlookups. 5590Sstevel@tonic-gate */ 5600Sstevel@tonic-gate neterr = 5618867SGirish.Moodalbail@Sun.COM _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate (void) freenetconfigent(nconf); 5640Sstevel@tonic-gate if (neterr != ND_OK) { 5650Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 5660Sstevel@tonic-gate hp = buf->result; 5670Sstevel@tonic-gate if (!gethostbyaddr_r(src, len, type, buf->result, 5688867SGirish.Moodalbail@Sun.COM buf->buffer, buf->buflen, error_num)) { 5690Sstevel@tonic-gate __IPv6_cleanup(buf); 5700Sstevel@tonic-gate return (NULL); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate free(buf); 5730Sstevel@tonic-gate return (hp); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate if ((hp = __mappedtov4(buf->result, error_num)) == NULL) { 5760Sstevel@tonic-gate __IPv6_cleanup(buf); 5770Sstevel@tonic-gate return (NULL); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate __IPv6_cleanup(buf); 5800Sstevel@tonic-gate return (hp); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate /* 5830Sstevel@tonic-gate * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call. 5840Sstevel@tonic-gate */ 5850Sstevel@tonic-gate if (type == AF_INET6) { 5860Sstevel@tonic-gate if ((nconf = __rpc_getconfip("udp")) == NULL && 5870Sstevel@tonic-gate (nconf = __rpc_getconfip("tcp")) == NULL) { 5880Sstevel@tonic-gate *error_num = NO_RECOVERY; 5890Sstevel@tonic-gate return (NULL); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { 5920Sstevel@tonic-gate *error_num = NO_RECOVERY; 5930Sstevel@tonic-gate freenetconfigent(nconf); 5940Sstevel@tonic-gate return (NULL); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate nssin.op_t = NSS_HOST6; 5970Sstevel@tonic-gate nssin.arg.nss.host.addr = (const char *)addr6; 5980Sstevel@tonic-gate nssin.arg.nss.host.len = len; 5990Sstevel@tonic-gate nssin.arg.nss.host.type = type; 6000Sstevel@tonic-gate nssin.arg.nss.host.buf = buf->buffer; 6010Sstevel@tonic-gate nssin.arg.nss.host.buflen = buf->buflen; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate nssout.nss.host.hent = buf->result; 6040Sstevel@tonic-gate nssout.nss.host.herrno_p = error_num; 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * We pass in nconf and let the implementation of the 6070Sstevel@tonic-gate * long-named func decide whether to use the switch based on 6080Sstevel@tonic-gate * nc_nlookups. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate neterr = 6118867SGirish.Moodalbail@Sun.COM _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate (void) freenetconfigent(nconf); 6140Sstevel@tonic-gate if (neterr != ND_OK) { 6150Sstevel@tonic-gate __IPv6_cleanup(buf); 6160Sstevel@tonic-gate return (NULL); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate free(buf); 6190Sstevel@tonic-gate return (nssout.nss.host.hent); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate /* 6220Sstevel@tonic-gate * If we got here, unknown type. 6230Sstevel@tonic-gate */ 6240Sstevel@tonic-gate *error_num = HOST_NOT_FOUND; 6250Sstevel@tonic-gate return (NULL); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate void 6290Sstevel@tonic-gate freehostent(struct hostent *hent) 6300Sstevel@tonic-gate { 6310Sstevel@tonic-gate free(hent); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate static int 6350Sstevel@tonic-gate __ai_addrconfig(int af) 6360Sstevel@tonic-gate { 6370Sstevel@tonic-gate struct lifnum lifn; 6389642SGirish.Moodalbail@Sun.COM struct lifconf lifc; 6399642SGirish.Moodalbail@Sun.COM struct lifreq *lifp, *buf = NULL; 6409642SGirish.Moodalbail@Sun.COM size_t bufsize; 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; 6459642SGirish.Moodalbail@Sun.COM int nlifr, count = 0; 6469642SGirish.Moodalbail@Sun.COM 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate switch (af) { 6490Sstevel@tonic-gate case AF_INET: 6500Sstevel@tonic-gate num = &ifnum4; 6510Sstevel@tonic-gate then = &then4; 6520Sstevel@tonic-gate break; 6530Sstevel@tonic-gate case AF_INET6: 6540Sstevel@tonic-gate num = &ifnum6; 6550Sstevel@tonic-gate then = &then6; 6560Sstevel@tonic-gate break; 6570Sstevel@tonic-gate default: 6580Sstevel@tonic-gate return (0); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * We don't need to check this every time someone does a name 6630Sstevel@tonic-gate * lookup. Do it every IFNUM_TIMEOUT for each address family. 6640Sstevel@tonic-gate * 6650Sstevel@tonic-gate * There's no need to protect all of this with a lock. The 6660Sstevel@tonic-gate * worst that can happen is that we update the interface count 6670Sstevel@tonic-gate * twice instead of once. That's no big deal. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate now = gethrtime(); 6700Sstevel@tonic-gate if (*num == -1 || ((now - *then) >= IFNUM_TIMEOUT)) { 6710Sstevel@tonic-gate lifn.lifn_family = af; 6720Sstevel@tonic-gate /* 6730Sstevel@tonic-gate * We want to determine if this machine knows anything 6740Sstevel@tonic-gate * at all about the address family; the status of the 6750Sstevel@tonic-gate * interface is less important. Hence, set 6760Sstevel@tonic-gate * 'lifn_flags' to zero. 6770Sstevel@tonic-gate */ 6780Sstevel@tonic-gate lifn.lifn_flags = 0; 6799642SGirish.Moodalbail@Sun.COM again: 6800Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFNUM, &lifn) < 0) 6819642SGirish.Moodalbail@Sun.COM goto fail; 6829642SGirish.Moodalbail@Sun.COM 6839642SGirish.Moodalbail@Sun.COM if (lifn.lifn_count == 0) { 6849642SGirish.Moodalbail@Sun.COM *num = 0; 6859642SGirish.Moodalbail@Sun.COM *then = now; 6869642SGirish.Moodalbail@Sun.COM return (*num); 6879642SGirish.Moodalbail@Sun.COM } 6889642SGirish.Moodalbail@Sun.COM 6899642SGirish.Moodalbail@Sun.COM /* 6909642SGirish.Moodalbail@Sun.COM * Pad the interface count to detect when additional 6919642SGirish.Moodalbail@Sun.COM * interfaces have been configured between SIOCGLIFNUM 6929642SGirish.Moodalbail@Sun.COM * and SIOCGLIFCONF. 6939642SGirish.Moodalbail@Sun.COM */ 6949642SGirish.Moodalbail@Sun.COM lifn.lifn_count += 4; 6959642SGirish.Moodalbail@Sun.COM 6969642SGirish.Moodalbail@Sun.COM bufsize = lifn.lifn_count * sizeof (struct lifreq); 6979642SGirish.Moodalbail@Sun.COM if ((buf = realloc(buf, bufsize)) == NULL) 6989642SGirish.Moodalbail@Sun.COM goto fail; 6999642SGirish.Moodalbail@Sun.COM 7009642SGirish.Moodalbail@Sun.COM lifc.lifc_family = af; 7019642SGirish.Moodalbail@Sun.COM lifc.lifc_flags = 0; 7029642SGirish.Moodalbail@Sun.COM lifc.lifc_len = bufsize; 7039642SGirish.Moodalbail@Sun.COM lifc.lifc_buf = (caddr_t)buf; 7049642SGirish.Moodalbail@Sun.COM if (nss_ioctl(af, SIOCGLIFCONF, &lifc) < 0) 7059642SGirish.Moodalbail@Sun.COM goto fail; 7060Sstevel@tonic-gate 7079642SGirish.Moodalbail@Sun.COM nlifr = lifc.lifc_len / sizeof (struct lifreq); 7089642SGirish.Moodalbail@Sun.COM if (nlifr >= lifn.lifn_count) 7099642SGirish.Moodalbail@Sun.COM goto again; 7109642SGirish.Moodalbail@Sun.COM /* 7119642SGirish.Moodalbail@Sun.COM * Do not include any loopback addresses, 127.0.0.1 for AF_INET 7129642SGirish.Moodalbail@Sun.COM * and ::1 for AF_INET6, while counting the number of available 7139642SGirish.Moodalbail@Sun.COM * IPv4 or IPv6 addresses. (RFC 3493 requires this, whenever 7149642SGirish.Moodalbail@Sun.COM * AI_ADDRCONFIG flag is set) 7159642SGirish.Moodalbail@Sun.COM */ 7169642SGirish.Moodalbail@Sun.COM for (lifp = buf; lifp < buf + nlifr; lifp++) { 7179642SGirish.Moodalbail@Sun.COM switch (af) { 7189642SGirish.Moodalbail@Sun.COM case AF_INET: { 7199642SGirish.Moodalbail@Sun.COM struct sockaddr_in *in; 7209642SGirish.Moodalbail@Sun.COM 7219642SGirish.Moodalbail@Sun.COM in = (struct sockaddr_in *)&lifp->lifr_addr; 7229642SGirish.Moodalbail@Sun.COM if (ntohl(in->sin_addr.s_addr) == 7239642SGirish.Moodalbail@Sun.COM INADDR_LOOPBACK) { 7249642SGirish.Moodalbail@Sun.COM count++; 7259642SGirish.Moodalbail@Sun.COM } 7269642SGirish.Moodalbail@Sun.COM break; 7279642SGirish.Moodalbail@Sun.COM } 7289642SGirish.Moodalbail@Sun.COM case AF_INET6: { 7299642SGirish.Moodalbail@Sun.COM struct sockaddr_in6 *in6; 7309642SGirish.Moodalbail@Sun.COM 7319642SGirish.Moodalbail@Sun.COM in6 = (struct sockaddr_in6 *)&lifp->lifr_addr; 7329642SGirish.Moodalbail@Sun.COM if (IN6_IS_ADDR_LOOPBACK(&in6->sin6_addr)) 7339642SGirish.Moodalbail@Sun.COM count++; 7349642SGirish.Moodalbail@Sun.COM break; 7359642SGirish.Moodalbail@Sun.COM } 7369642SGirish.Moodalbail@Sun.COM } 7379642SGirish.Moodalbail@Sun.COM } 7389642SGirish.Moodalbail@Sun.COM *num = nlifr - count; 7390Sstevel@tonic-gate *then = now; 7409642SGirish.Moodalbail@Sun.COM free(buf); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate return (*num); 7439642SGirish.Moodalbail@Sun.COM fail: 7449642SGirish.Moodalbail@Sun.COM free(buf); 745*11537SCasper.Dik@Sun.COM /* 746*11537SCasper.Dik@Sun.COM * If the process is running without the NET_ACCESS basic privilege, 747*11537SCasper.Dik@Sun.COM * pretend we still have inet/inet6 interfaces. 748*11537SCasper.Dik@Sun.COM */ 749*11537SCasper.Dik@Sun.COM if (errno == EACCES) 750*11537SCasper.Dik@Sun.COM return (1); 7519642SGirish.Moodalbail@Sun.COM return (-1); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * This routine will either convert an IPv4 address to a mapped or compat 7560Sstevel@tonic-gate * IPv6 (if he6 == NULL) or merge IPv6 (he6) addresses with mapped 7570Sstevel@tonic-gate * v4 (he4) addresses. In either case, the results are returned in res. 7580Sstevel@tonic-gate * Caller must provide all buffers. 7590Sstevel@tonic-gate * Inputs: 7600Sstevel@tonic-gate * he4 pointer to IPv4 buffer 7610Sstevel@tonic-gate * he6 pointer to IPv6 buffer (NULL if not merging v4/v6 7620Sstevel@tonic-gate * res pointer to results buffer 7630Sstevel@tonic-gate * mapped mapped == 1, map IPv4 : mapped == 0, compat IPv4 7640Sstevel@tonic-gate * mapped flag is ignored if he6 != NULL 7650Sstevel@tonic-gate * 7660Sstevel@tonic-gate * The results are packed into the res->buffer as follows: 7670Sstevel@tonic-gate * <--------------- buffer + buflen --------------------------------------> 7680Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 7690Sstevel@tonic-gate * | pointers vector | pointers vector | aliases grow | addresses grow | 7700Sstevel@tonic-gate * | for addresses | for aliases | | | 7710Sstevel@tonic-gate * | this way -> | this way -> | <- this way |<- this way | 7720Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 7730Sstevel@tonic-gate * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate static struct hostent * 7760Sstevel@tonic-gate __mapv4tov6(struct hostent *he4, struct hostent *he6, nss_XbyY_buf_t *res, 7770Sstevel@tonic-gate int mapped) 7780Sstevel@tonic-gate { 7790Sstevel@tonic-gate char *buffer, *limit; 7800Sstevel@tonic-gate int buflen = res->buflen; 7810Sstevel@tonic-gate struct in6_addr *addr6p; 7820Sstevel@tonic-gate char *buff_locp; 7830Sstevel@tonic-gate struct hostent *host; 7840Sstevel@tonic-gate int count = 0, len, i; 7850Sstevel@tonic-gate char *h_namep; 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate if (he4 == NULL || res == NULL) { 7880Sstevel@tonic-gate return (NULL); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate limit = res->buffer + buflen; 7910Sstevel@tonic-gate host = (struct hostent *)res->result; 7920Sstevel@tonic-gate buffer = res->buffer; 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in6_addr)); 7950Sstevel@tonic-gate host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); 7960Sstevel@tonic-gate if ((char *)host->h_addr_list >= limit || 7978867SGirish.Moodalbail@Sun.COM buff_locp <= (char *)host->h_addr_list) { 7980Sstevel@tonic-gate return (NULL); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate if (he6 == NULL) { 8010Sstevel@tonic-gate /* 8020Sstevel@tonic-gate * If he6==NULL, map the v4 address into the v6 address format. 8030Sstevel@tonic-gate * This is used for getipnodebyaddr() (single address, mapped or 8040Sstevel@tonic-gate * compatible) or for v4 mapped for getipnodebyname(), which 8050Sstevel@tonic-gate * could be multiple addresses. This could also be a literal 8060Sstevel@tonic-gate * address string, which is why there is a inet_addr() call. 8070Sstevel@tonic-gate */ 8080Sstevel@tonic-gate for (i = 0; he4->h_addr_list[i] != NULL; i++) { 8090Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 8100Sstevel@tonic-gate if (buff_locp <= 8118867SGirish.Moodalbail@Sun.COM (char *)&(host->h_addr_list[count + 1])) { 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8140Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8150Sstevel@tonic-gate */ 8160Sstevel@tonic-gate return (NULL); 8170Sstevel@tonic-gate } 818132Srobinson /* LINTED pointer cast */ 8190Sstevel@tonic-gate addr6p = (struct in6_addr *)buff_locp; 8200Sstevel@tonic-gate host->h_addr_list[count] = (char *)addr6p; 8210Sstevel@tonic-gate bzero(addr6p->s6_addr, sizeof (struct in6_addr)); 8220Sstevel@tonic-gate if (mapped) { 8230Sstevel@tonic-gate addr6p->s6_addr[10] = 0xff; 8240Sstevel@tonic-gate addr6p->s6_addr[11] = 0xff; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate bcopy((char *)he4->h_addr_list[i], 8278867SGirish.Moodalbail@Sun.COM &addr6p->s6_addr[12], sizeof (struct in_addr)); 8280Sstevel@tonic-gate ++count; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate /* 8310Sstevel@tonic-gate * Set last array element to NULL and add cname as first alias 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate host->h_addr_list[count] = NULL; 8340Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 8350Sstevel@tonic-gate count = 0; 8360Sstevel@tonic-gate if ((int)(inet_addr(he4->h_name)) != -1) { 8370Sstevel@tonic-gate /* 8380Sstevel@tonic-gate * Literal address string, since we're mapping, we need the IPv6 8390Sstevel@tonic-gate * V4 mapped literal address string for h_name. 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate char tmpstr[128]; 842132Srobinson (void) inet_ntop(AF_INET6, host->h_addr_list[0], tmpstr, 8438867SGirish.Moodalbail@Sun.COM sizeof (tmpstr)); 8440Sstevel@tonic-gate buff_locp -= (len = strlen(tmpstr) + 1); 8450Sstevel@tonic-gate h_namep = tmpstr; 8460Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 8470Sstevel@tonic-gate return (NULL); 8480Sstevel@tonic-gate bcopy(h_namep, buff_locp, len); 8490Sstevel@tonic-gate host->h_name = buff_locp; 8500Sstevel@tonic-gate host->h_aliases = NULL; /* no aliases for literal */ 8510Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 8520Sstevel@tonic-gate host->h_addrtype = AF_INET6; 8530Sstevel@tonic-gate return (host); /* we're done, return result */ 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate /* 8560Sstevel@tonic-gate * Not a literal address string, so just copy h_name. 8570Sstevel@tonic-gate */ 8580Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_name) + 1); 8590Sstevel@tonic-gate h_namep = he4->h_name; 8600Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 8610Sstevel@tonic-gate return (NULL); 8620Sstevel@tonic-gate bcopy(h_namep, buff_locp, len); 8630Sstevel@tonic-gate host->h_name = buff_locp; 8640Sstevel@tonic-gate /* 8650Sstevel@tonic-gate * Pass 2 (IPv4 aliases): 8660Sstevel@tonic-gate */ 8670Sstevel@tonic-gate for (i = 0; he4->h_aliases[i] != NULL; i++) { 8680Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_aliases[i]) + 1); 8690Sstevel@tonic-gate if (buff_locp <= 8708867SGirish.Moodalbail@Sun.COM (char *)&(host->h_aliases[count + 1])) { 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8730Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8740Sstevel@tonic-gate */ 8750Sstevel@tonic-gate return (NULL); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 8780Sstevel@tonic-gate bcopy((char *)he4->h_aliases[i], buff_locp, len); 8790Sstevel@tonic-gate ++count; 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate host->h_aliases[count] = NULL; 8820Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 8830Sstevel@tonic-gate host->h_addrtype = AF_INET6; 8840Sstevel@tonic-gate return (host); 8850Sstevel@tonic-gate } else { 8860Sstevel@tonic-gate /* 8870Sstevel@tonic-gate * Merge IPv4 mapped addresses with IPv6 addresses. The 8880Sstevel@tonic-gate * IPv6 address will go in first, followed by the v4 mapped. 8890Sstevel@tonic-gate * 8900Sstevel@tonic-gate * Pass 1 (IPv6 addresses): 8910Sstevel@tonic-gate */ 8920Sstevel@tonic-gate for (i = 0; he6->h_addr_list[i] != NULL; i++) { 8930Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 8940Sstevel@tonic-gate if (buff_locp <= 8958867SGirish.Moodalbail@Sun.COM (char *)&(host->h_addr_list[count + 1])) { 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * Has to be room for the pointer to the address we're 8980Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 8990Sstevel@tonic-gate */ 9000Sstevel@tonic-gate return (NULL); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate host->h_addr_list[count] = buff_locp; 9030Sstevel@tonic-gate bcopy((char *)he6->h_addr_list[i], buff_locp, 9048867SGirish.Moodalbail@Sun.COM sizeof (struct in6_addr)); 9050Sstevel@tonic-gate ++count; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate /* 9080Sstevel@tonic-gate * Pass 1 (IPv4 mapped addresses): 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate for (i = 0; he4->h_addr_list[i] != NULL; i++) { 9110Sstevel@tonic-gate buff_locp -= sizeof (struct in6_addr); 9120Sstevel@tonic-gate if (buff_locp <= 9138867SGirish.Moodalbail@Sun.COM (char *)&(host->h_addr_list[count + 1])) { 9140Sstevel@tonic-gate /* 9150Sstevel@tonic-gate * Has to be room for the pointer to the address we're 9160Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 9170Sstevel@tonic-gate */ 9180Sstevel@tonic-gate return (NULL); 9190Sstevel@tonic-gate } 920132Srobinson /* LINTED pointer cast */ 9210Sstevel@tonic-gate addr6p = (struct in6_addr *)buff_locp; 9220Sstevel@tonic-gate host->h_addr_list[count] = (char *)addr6p; 9230Sstevel@tonic-gate bzero(addr6p->s6_addr, sizeof (struct in6_addr)); 9240Sstevel@tonic-gate addr6p->s6_addr[10] = 0xff; 9250Sstevel@tonic-gate addr6p->s6_addr[11] = 0xff; 9260Sstevel@tonic-gate bcopy(he4->h_addr_list[i], &addr6p->s6_addr[12], 9278867SGirish.Moodalbail@Sun.COM sizeof (struct in_addr)); 9280Sstevel@tonic-gate ++count; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate /* 9310Sstevel@tonic-gate * Pass 2 (IPv6 aliases, host name first). We start h_aliases 9320Sstevel@tonic-gate * one after where h_addr_list array ended. This is where cname 9330Sstevel@tonic-gate * is put, followed by all aliases. Reset count to 0, for index 9340Sstevel@tonic-gate * in the h_aliases array. 9350Sstevel@tonic-gate */ 9360Sstevel@tonic-gate host->h_addr_list[count] = NULL; 9370Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 9380Sstevel@tonic-gate count = 0; 9390Sstevel@tonic-gate buff_locp -= (len = strlen(he6->h_name) + 1); 9400Sstevel@tonic-gate if (buff_locp <= (char *)(host->h_aliases)) 9410Sstevel@tonic-gate return (NULL); 9420Sstevel@tonic-gate bcopy(he6->h_name, buff_locp, len); 9430Sstevel@tonic-gate host->h_name = buff_locp; 9440Sstevel@tonic-gate for (i = 0; he6->h_aliases[i] != NULL; i++) { 9450Sstevel@tonic-gate buff_locp -= (len = strlen(he6->h_aliases[i]) + 1); 9460Sstevel@tonic-gate if (buff_locp <= 9478867SGirish.Moodalbail@Sun.COM (char *)&(host->h_aliases[count + 1])) { 9480Sstevel@tonic-gate /* 9490Sstevel@tonic-gate * Has to be room for the pointer to the address we're 9500Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 9510Sstevel@tonic-gate */ 9520Sstevel@tonic-gate return (NULL); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 9550Sstevel@tonic-gate bcopy((char *)he6->h_aliases[i], buff_locp, len); 9560Sstevel@tonic-gate ++count; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * Pass 2 (IPv4 aliases): 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate for (i = 0; he4->h_aliases[i] != NULL; i++) { 9620Sstevel@tonic-gate buff_locp -= (len = strlen(he4->h_aliases[i]) + 1); 9630Sstevel@tonic-gate if (buff_locp <= 9648867SGirish.Moodalbail@Sun.COM (char *)&(host->h_aliases[count + 1])) { 9650Sstevel@tonic-gate /* 9660Sstevel@tonic-gate * Has to be room for the pointer to the address we're 9670Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 9680Sstevel@tonic-gate */ 9690Sstevel@tonic-gate return (NULL); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 9720Sstevel@tonic-gate bcopy((char *)he4->h_aliases[i], buff_locp, len); 9730Sstevel@tonic-gate ++count; 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate host->h_aliases[count] = NULL; 9760Sstevel@tonic-gate host->h_length = sizeof (struct in6_addr); 9770Sstevel@tonic-gate host->h_addrtype = AF_INET6; 9780Sstevel@tonic-gate return (host); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate /* 9830Sstevel@tonic-gate * This routine will convert a mapped v4 hostent (AF_INET6) to a 9840Sstevel@tonic-gate * AF_INET hostent. If no mapped addrs found, then a NULL is returned. 9850Sstevel@tonic-gate * If mapped addrs found, then a new buffer is alloc'd and all the v4 mapped 9860Sstevel@tonic-gate * addresses are extracted and copied to it. On sucess, a pointer to a new 9870Sstevel@tonic-gate * hostent is returned. 9880Sstevel@tonic-gate * There are two possible errors in which case a NULL is returned. 9890Sstevel@tonic-gate * One of two error codes are returned: 9900Sstevel@tonic-gate * 9910Sstevel@tonic-gate * NO_RECOVERY - a malloc failed or the like for which there's no recovery. 9920Sstevel@tonic-gate * NO_ADDRESS - after filtering all the v4, there was nothing left! 9930Sstevel@tonic-gate * 9940Sstevel@tonic-gate * Inputs: 9950Sstevel@tonic-gate * he pointer to hostent with mapped v4 addresses 9960Sstevel@tonic-gate * filter_error pointer to return error code 9970Sstevel@tonic-gate * Return: 9980Sstevel@tonic-gate * pointer to a malloc'd hostent with v4 addresses. 9990Sstevel@tonic-gate * 10000Sstevel@tonic-gate * The results are packed into the res->buffer as follows: 10010Sstevel@tonic-gate * <--------------- buffer + buflen --------------------------------------> 10020Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 10030Sstevel@tonic-gate * | pointers vector | pointers vector | aliases grow | addresses grow | 10040Sstevel@tonic-gate * | for addresses | for aliases | | | 10050Sstevel@tonic-gate * | this way -> | this way -> | <- this way |<- this way | 10060Sstevel@tonic-gate * |-----------------|-----------------|----------------|----------------| 10070Sstevel@tonic-gate * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| 10080Sstevel@tonic-gate */ 10090Sstevel@tonic-gate struct hostent * 10100Sstevel@tonic-gate __mappedtov4(struct hostent *he, int *extract_error) 10110Sstevel@tonic-gate { 10120Sstevel@tonic-gate char *buffer, *limit; 10130Sstevel@tonic-gate nss_XbyY_buf_t *res; 10140Sstevel@tonic-gate int buflen = NSS_BUFLEN_HOSTS; 10150Sstevel@tonic-gate struct in_addr *addr4p; 10160Sstevel@tonic-gate char *buff_locp; 10170Sstevel@tonic-gate struct hostent *host; 10180Sstevel@tonic-gate int count = 0, len, i; 10190Sstevel@tonic-gate char *h_namep; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate if (he == NULL) { 10220Sstevel@tonic-gate *extract_error = NO_ADDRESS; 10230Sstevel@tonic-gate return (NULL); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate if ((__find_mapped(he, 0)) == 0) { 10260Sstevel@tonic-gate *extract_error = NO_ADDRESS; 10270Sstevel@tonic-gate return (NULL); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate if ((res = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == 0) { 10300Sstevel@tonic-gate *extract_error = NO_RECOVERY; 10310Sstevel@tonic-gate return (NULL); 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate limit = res->buffer + buflen; 10340Sstevel@tonic-gate host = (struct hostent *)res->result; 10350Sstevel@tonic-gate buffer = res->buffer; 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in_addr)); 10380Sstevel@tonic-gate host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); 10390Sstevel@tonic-gate if ((char *)host->h_addr_list >= limit || 10408867SGirish.Moodalbail@Sun.COM buff_locp <= (char *)host->h_addr_list) 10410Sstevel@tonic-gate goto cleanup; 10420Sstevel@tonic-gate /* 10430Sstevel@tonic-gate * "Unmap" the v4 mapped address(es) into a v4 hostent format. 10440Sstevel@tonic-gate * This is used for getipnodebyaddr() (single address) or for 10450Sstevel@tonic-gate * v4 mapped for getipnodebyname(), which could be multiple 10460Sstevel@tonic-gate * addresses. This could also be a literal address string, 10470Sstevel@tonic-gate * which is why there is a inet_addr() call. 10480Sstevel@tonic-gate */ 10498867SGirish.Moodalbail@Sun.COM for (i = 0; he->h_addr_list[i] != NULL; i++) { 10508867SGirish.Moodalbail@Sun.COM /* LINTED pointer cast */ 10518867SGirish.Moodalbail@Sun.COM if (!IN6_IS_ADDR_V4MAPPED((struct in6_addr *) 10528867SGirish.Moodalbail@Sun.COM he->h_addr_list[i])) 10530Sstevel@tonic-gate continue; 10548867SGirish.Moodalbail@Sun.COM buff_locp -= sizeof (struct in6_addr); 10550Sstevel@tonic-gate /* 10568867SGirish.Moodalbail@Sun.COM * Has to be room for the pointer to the address we're 10578867SGirish.Moodalbail@Sun.COM * about to add, as well as the final NULL ptr. 10580Sstevel@tonic-gate */ 10598867SGirish.Moodalbail@Sun.COM if (buff_locp <= 10608867SGirish.Moodalbail@Sun.COM (char *)&(host->h_addr_list[count + 1])) 10610Sstevel@tonic-gate goto cleanup; 10628867SGirish.Moodalbail@Sun.COM /* LINTED pointer cast */ 10638867SGirish.Moodalbail@Sun.COM addr4p = (struct in_addr *)buff_locp; 10648867SGirish.Moodalbail@Sun.COM host->h_addr_list[count] = (char *)addr4p; 10658867SGirish.Moodalbail@Sun.COM bzero((char *)&addr4p->s_addr, 10668867SGirish.Moodalbail@Sun.COM sizeof (struct in_addr)); 10678867SGirish.Moodalbail@Sun.COM /* LINTED pointer cast */ 10688867SGirish.Moodalbail@Sun.COM IN6_V4MAPPED_TO_INADDR( 10698867SGirish.Moodalbail@Sun.COM (struct in6_addr *)he->h_addr_list[i], addr4p); 10708867SGirish.Moodalbail@Sun.COM ++count; 10718867SGirish.Moodalbail@Sun.COM } 10728867SGirish.Moodalbail@Sun.COM /* 10738867SGirish.Moodalbail@Sun.COM * Set last array element to NULL and add cname as first alias 10748867SGirish.Moodalbail@Sun.COM */ 10758867SGirish.Moodalbail@Sun.COM host->h_addr_list[count] = NULL; 10768867SGirish.Moodalbail@Sun.COM host->h_aliases = host->h_addr_list + count + 1; 10778867SGirish.Moodalbail@Sun.COM count = 0; 10788867SGirish.Moodalbail@Sun.COM /* Copy official host name */ 10798867SGirish.Moodalbail@Sun.COM buff_locp -= (len = strlen(he->h_name) + 1); 10808867SGirish.Moodalbail@Sun.COM h_namep = he->h_name; 10818867SGirish.Moodalbail@Sun.COM if (buff_locp <= (char *)(host->h_aliases)) 10828867SGirish.Moodalbail@Sun.COM goto cleanup; 10838867SGirish.Moodalbail@Sun.COM bcopy(h_namep, buff_locp, len); 10848867SGirish.Moodalbail@Sun.COM host->h_name = buff_locp; 10858867SGirish.Moodalbail@Sun.COM /* 10868867SGirish.Moodalbail@Sun.COM * Pass 2 (IPv4 aliases): 10878867SGirish.Moodalbail@Sun.COM */ 10888867SGirish.Moodalbail@Sun.COM if (he->h_aliases != NULL) { 10890Sstevel@tonic-gate for (i = 0; he->h_aliases[i] != NULL; i++) { 10900Sstevel@tonic-gate buff_locp -= (len = strlen(he->h_aliases[i]) + 1); 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * Has to be room for the pointer to the address we're 10930Sstevel@tonic-gate * about to add, as well as the final NULL ptr. 10940Sstevel@tonic-gate */ 10950Sstevel@tonic-gate if (buff_locp <= 10968867SGirish.Moodalbail@Sun.COM (char *)&(host->h_aliases[count + 1])) 10970Sstevel@tonic-gate goto cleanup; 10980Sstevel@tonic-gate host->h_aliases[count] = buff_locp; 10990Sstevel@tonic-gate bcopy((char *)he->h_aliases[i], buff_locp, len); 11000Sstevel@tonic-gate ++count; 11010Sstevel@tonic-gate } 11028867SGirish.Moodalbail@Sun.COM } 11038867SGirish.Moodalbail@Sun.COM host->h_aliases[count] = NULL; 11048867SGirish.Moodalbail@Sun.COM host->h_length = sizeof (struct in_addr); 11058867SGirish.Moodalbail@Sun.COM host->h_addrtype = AF_INET; 11068867SGirish.Moodalbail@Sun.COM free(res); 11078867SGirish.Moodalbail@Sun.COM return (host); 11080Sstevel@tonic-gate cleanup: 11090Sstevel@tonic-gate *extract_error = NO_RECOVERY; 11100Sstevel@tonic-gate (void) __IPv6_cleanup(res); 11110Sstevel@tonic-gate return (NULL); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * This routine takes as input a pointer to a hostent and filters out 11160Sstevel@tonic-gate * the type of addresses specified by the af argument. AF_INET 11170Sstevel@tonic-gate * indicates that the caller wishes to filter out IPv4-mapped 11180Sstevel@tonic-gate * addresses, and AF_INET6 indicates that the caller wishes to filter 11190Sstevel@tonic-gate * out IPv6 addresses which aren't IPv4-mapped. If filtering would 11200Sstevel@tonic-gate * result in all addresses being filtered out, a NULL pointer is returned. 11210Sstevel@tonic-gate * Otherwise, the he pointer passed in is returned, even if no addresses 11220Sstevel@tonic-gate * were filtered out. 11230Sstevel@tonic-gate */ 11240Sstevel@tonic-gate static struct hostent * 11250Sstevel@tonic-gate __filter_addresses(int af, struct hostent *he) 11260Sstevel@tonic-gate { 11270Sstevel@tonic-gate struct in6_addr **in6addrlist, **in6addr; 11280Sstevel@tonic-gate boolean_t isipv4mapped; 11290Sstevel@tonic-gate int i = 0; 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate if (he == NULL) 11320Sstevel@tonic-gate return (NULL); 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate in6addrlist = (struct in6_addr **)he->h_addr_list; 11350Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 11360Sstevel@tonic-gate isipv4mapped = IN6_IS_ADDR_V4MAPPED(*in6addr); 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate if ((af == AF_INET && !isipv4mapped) || 11390Sstevel@tonic-gate (af == AF_INET6 && isipv4mapped)) { 11400Sstevel@tonic-gate if (in6addrlist[i] != *in6addr) 11410Sstevel@tonic-gate in6addrlist[i] = *in6addr; 11420Sstevel@tonic-gate i++; 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate if (i == 0) { 11470Sstevel@tonic-gate /* We filtered everything out. */ 11480Sstevel@tonic-gate return (NULL); 11490Sstevel@tonic-gate } else { 11500Sstevel@tonic-gate /* NULL terminate the list and return the hostent */ 11510Sstevel@tonic-gate in6addrlist[i] = NULL; 11520Sstevel@tonic-gate return (he); 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate } 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate /* 11570Sstevel@tonic-gate * This routine searches a hostent for v4 mapped IPv6 addresses. 11580Sstevel@tonic-gate * he hostent structure to seach 11590Sstevel@tonic-gate * find_both flag indicating if only want mapped or both map'd and v6 11600Sstevel@tonic-gate * return values: 11610Sstevel@tonic-gate * 0 = No mapped addresses 11620Sstevel@tonic-gate * 1 = Mapped v4 address found (returns on first one found) 11630Sstevel@tonic-gate * 2 = Both v6 and v4 mapped are present 11640Sstevel@tonic-gate * 11650Sstevel@tonic-gate * If hostent passed in with no addresses, zero will be returned. 11660Sstevel@tonic-gate */ 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate static int 11690Sstevel@tonic-gate __find_mapped(struct hostent *he, int find_both) 11700Sstevel@tonic-gate { 11710Sstevel@tonic-gate int i; 11720Sstevel@tonic-gate int mapd_found = 0; 11730Sstevel@tonic-gate int v6_found = 0; 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate for (i = 0; he->h_addr_list[i] != NULL; i++) { 1176132Srobinson /* LINTED pointer cast */ 11770Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED( 11780Sstevel@tonic-gate (struct in6_addr *)he->h_addr_list[i])) { 11790Sstevel@tonic-gate if (find_both) 11800Sstevel@tonic-gate mapd_found = 1; 11810Sstevel@tonic-gate else 11820Sstevel@tonic-gate return (1); 11830Sstevel@tonic-gate } else { 11840Sstevel@tonic-gate v6_found = 1; 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate /* save some iterations once both found */ 11870Sstevel@tonic-gate if (mapd_found && v6_found) 11880Sstevel@tonic-gate return (2); 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate return (mapd_found); 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate /* 11940Sstevel@tonic-gate * This routine was added specifically for the IPv6 getipnodeby*() APIs. This 11950Sstevel@tonic-gate * separates the result pointer (ptr to hostent+data buf) from the 11960Sstevel@tonic-gate * nss_XbyY_buf_t ptr (required for nsswitch API). The returned hostent ptr 11970Sstevel@tonic-gate * can be passed to freehostent() and freed independently. 11980Sstevel@tonic-gate * 11990Sstevel@tonic-gate * bufp->result bufp->buffer 12000Sstevel@tonic-gate * | | 12010Sstevel@tonic-gate * V V 12020Sstevel@tonic-gate * ------------------------------------------------...-- 12030Sstevel@tonic-gate * |struct hostent |addresses aliases | 12040Sstevel@tonic-gate * ------------------------------------------------...-- 12050Sstevel@tonic-gate * | |<--------bufp->buflen-------------->| 12060Sstevel@tonic-gate */ 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate #define ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1)) 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate static nss_XbyY_buf_t * 12110Sstevel@tonic-gate __IPv6_alloc(int bufsz) 12120Sstevel@tonic-gate { 12130Sstevel@tonic-gate nss_XbyY_buf_t *bufp; 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate if ((bufp = malloc(sizeof (nss_XbyY_buf_t))) == NULL) 12160Sstevel@tonic-gate return (NULL); 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate if ((bufp->result = malloc(ALIGN(sizeof (struct hostent)) + bufsz)) == 12190Sstevel@tonic-gate NULL) { 12200Sstevel@tonic-gate free(bufp); 12210Sstevel@tonic-gate return (NULL); 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate bufp->buffer = (char *)(bufp->result) + sizeof (struct hostent); 12240Sstevel@tonic-gate bufp->buflen = bufsz; 12250Sstevel@tonic-gate return (bufp); 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate /* 12290Sstevel@tonic-gate * This routine is use only for error return cleanup. This will free the 12300Sstevel@tonic-gate * hostent pointer, so don't use for successful returns. 12310Sstevel@tonic-gate */ 12320Sstevel@tonic-gate static void 12330Sstevel@tonic-gate __IPv6_cleanup(nss_XbyY_buf_t *bufp) 12340Sstevel@tonic-gate { 12350Sstevel@tonic-gate if (bufp == NULL) 12360Sstevel@tonic-gate return; 12370Sstevel@tonic-gate if (bufp->result != NULL) 12380Sstevel@tonic-gate free(bufp->result); 12390Sstevel@tonic-gate free(bufp); 12400Sstevel@tonic-gate } 1241