17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5004388ebScasper * Common Development and Distribution License (the "License"). 6004388ebScasper * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2161961e0fSrobinson 227c478bd9Sstevel@tonic-gate /* 23*6392794bSMichen Chang * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 256c740c0aSraf */ 266c740c0aSraf 276c740c0aSraf /* 287c478bd9Sstevel@tonic-gate * This is where we have chosen to combine every useful bit of code for 297c478bd9Sstevel@tonic-gate * all the Solaris frontends to lookup hosts, services, and netdir information 307c478bd9Sstevel@tonic-gate * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and 317c478bd9Sstevel@tonic-gate * netdir_getbyYY() are all implemented on top of this code. Similarly, 327c478bd9Sstevel@tonic-gate * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also 337c478bd9Sstevel@tonic-gate * find a home here. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-" 367c478bd9Sstevel@tonic-gate * in /etc/netconfig), this code calls the name service switch, and 377c478bd9Sstevel@tonic-gate * therefore, /etc/nsswitch.conf is effectively the only place that 387c478bd9Sstevel@tonic-gate * dictates hosts/serv lookup policy. 397c478bd9Sstevel@tonic-gate * If an administrator chooses to bypass the name service switch by 407c478bd9Sstevel@tonic-gate * specifying third party supplied nametoaddr libs in /etc/netconfig, this 417c478bd9Sstevel@tonic-gate * implementation does NOT call the name service switch, it merely loops 427c478bd9Sstevel@tonic-gate * through the nametoaddr libs. In this case, if this code was called 437c478bd9Sstevel@tonic-gate * from gethost/servbyYY() we marshal the inet specific struct into 447c478bd9Sstevel@tonic-gate * transport independent netbuf or hostserv, and unmarshal the resulting 457c478bd9Sstevel@tonic-gate * nd_addrlist or hostservlist back into hostent and servent, as the case 467c478bd9Sstevel@tonic-gate * may be. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * Goes without saying that most of the future bugs in gethost/servbyYY 497c478bd9Sstevel@tonic-gate * and netdir_getbyYY are lurking somewhere here. 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include "mt.h" 537c478bd9Sstevel@tonic-gate #include <ctype.h> 547c478bd9Sstevel@tonic-gate #include <stdio.h> 557c478bd9Sstevel@tonic-gate #include <stdlib.h> 567c478bd9Sstevel@tonic-gate #include <string.h> 577c478bd9Sstevel@tonic-gate #include <unistd.h> 587c478bd9Sstevel@tonic-gate #include <stropts.h> 597c478bd9Sstevel@tonic-gate #include <sys/types.h> 607c478bd9Sstevel@tonic-gate #include <sys/byteorder.h> 617c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 627c478bd9Sstevel@tonic-gate #include <sys/param.h> 637c478bd9Sstevel@tonic-gate #include <sys/time.h> 647c478bd9Sstevel@tonic-gate #include <errno.h> 657c478bd9Sstevel@tonic-gate #include <fcntl.h> 667c478bd9Sstevel@tonic-gate #include <thread.h> 677c478bd9Sstevel@tonic-gate #include <synch.h> 687c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 697c478bd9Sstevel@tonic-gate #include <netdb.h> 707c478bd9Sstevel@tonic-gate #include <netconfig.h> 717c478bd9Sstevel@tonic-gate #include <netdir.h> 727c478bd9Sstevel@tonic-gate #include <tiuser.h> 737c478bd9Sstevel@tonic-gate #include <sys/socket.h> 747c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 757c478bd9Sstevel@tonic-gate #include <netinet/in.h> 767c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 777c478bd9Sstevel@tonic-gate #include <net/if.h> 787c478bd9Sstevel@tonic-gate #include <inet/ip.h> 797c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h> 807c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 817c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h> 827c478bd9Sstevel@tonic-gate #include <nss_netdir.h> 837c478bd9Sstevel@tonic-gate #include <syslog.h> 847c478bd9Sstevel@tonic-gate #include <nsswitch.h> 857c478bd9Sstevel@tonic-gate #include "nss.h" 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate #define MAXIFS 32 887c478bd9Sstevel@tonic-gate #define UDPDEV "/dev/udp" 897c478bd9Sstevel@tonic-gate #define UDP6DEV "/dev/udp6" 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate #define DOOR_GETHOSTBYNAME_R _switch_gethostbyname_r 927c478bd9Sstevel@tonic-gate #define DOOR_GETHOSTBYADDR_R _switch_gethostbyaddr_r 937c478bd9Sstevel@tonic-gate #define DOOR_GETIPNODEBYNAME_R _switch_getipnodebyname_r 947c478bd9Sstevel@tonic-gate #define DOOR_GETIPNODEBYADDR_R _switch_getipnodebyaddr_r 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate #define DONT_SORT "SORT_ADDRS=NO" 977c478bd9Sstevel@tonic-gate #define DONT_SORT2 "SORT_ADDRS=FALSE" 987c478bd9Sstevel@tonic-gate #define LINESIZE 100 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT 1027c478bd9Sstevel@tonic-gate * and localhost. 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * The following variables are static to the extent that they should 1057c478bd9Sstevel@tonic-gate * not be visible outside of this file. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate static char *localaddr[] = {"\000\000\000\000", NULL}; 1087c478bd9Sstevel@tonic-gate static char *connectaddr[] = {"\177\000\000\001", NULL}; 1097c478bd9Sstevel@tonic-gate static char *localaddr6[] = 1107c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL}; 1117c478bd9Sstevel@tonic-gate static char *connectaddr6[] = 1127c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL}; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* IPv4 nd_addrlist */ 1157c478bd9Sstevel@tonic-gate static mutex_t nd_addr_lock = DEFAULTMUTEX; 1167c478bd9Sstevel@tonic-gate static struct sockaddr_in sa_con; 1177c478bd9Sstevel@tonic-gate static struct netbuf nd_conbuf = {sizeof (sa_con),\ 1187c478bd9Sstevel@tonic-gate sizeof (sa_con), (char *)&sa_con}; 1197c478bd9Sstevel@tonic-gate static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf}; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* IPv6 nd_addrlist */ 1227c478bd9Sstevel@tonic-gate static mutex_t nd6_addr_lock = DEFAULTMUTEX; 1237c478bd9Sstevel@tonic-gate static struct sockaddr_in6 sa6_con; 1247c478bd9Sstevel@tonic-gate static struct netbuf nd6_conbuf = {sizeof (sa6_con),\ 1257c478bd9Sstevel@tonic-gate sizeof (sa6_con), (char *)&sa6_con}; 1267c478bd9Sstevel@tonic-gate static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf}; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate #define LOCALHOST "localhost" 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyname_r(const char *, const char *, 1317c478bd9Sstevel@tonic-gate struct servent *, char *, int); 1327c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyport_r(int, const char *, struct servent *, 1337c478bd9Sstevel@tonic-gate char *, int); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static int __herrno2netdir(int h_errnop); 1367c478bd9Sstevel@tonic-gate static struct ifinfo *get_local_info(void); 1377c478bd9Sstevel@tonic-gate static int getbroadcastnets(struct netconfig *, struct in_addr **); 1387c478bd9Sstevel@tonic-gate static int hent2ndaddr(int, char **, int *, struct nd_addrlist **); 1397c478bd9Sstevel@tonic-gate static int ndaddr2hent(int, const char *, struct nd_addrlist *, 1407c478bd9Sstevel@tonic-gate struct hostent *, char *, int); 1417c478bd9Sstevel@tonic-gate static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t, 1427c478bd9Sstevel@tonic-gate struct nd_hostservlist **); 1437c478bd9Sstevel@tonic-gate static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *, 1447c478bd9Sstevel@tonic-gate char *, int); 1457c478bd9Sstevel@tonic-gate static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *, 1467c478bd9Sstevel@tonic-gate struct hostent *, char *, int); 1477c478bd9Sstevel@tonic-gate static int ndhostserv2srent(int, const char *, struct nd_hostservlist *, 1487c478bd9Sstevel@tonic-gate struct servent *, char *, int); 1497c478bd9Sstevel@tonic-gate static int nd2herrno(int nerr); 1507c478bd9Sstevel@tonic-gate static void order_haddrlist_inet(char **haddrlist, size_t addrcount); 1517c478bd9Sstevel@tonic-gate static void order_haddrlist_inet6(char **haddrlist, size_t addrcount); 1527c478bd9Sstevel@tonic-gate static int dstcmp(const void *, const void *); 1537c478bd9Sstevel@tonic-gate static int nss_strioctl(int af, int cmd, void *ptr, int ilen); 1547c478bd9Sstevel@tonic-gate static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t); 1557c478bd9Sstevel@tonic-gate static boolean_t _read_nsw_file(void); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * Begin: PART I 1597c478bd9Sstevel@tonic-gate * Top Level Interfaces that gethost/serv/netdir funnel through. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * gethost/servbyname always call this function; if they call 1647c478bd9Sstevel@tonic-gate * with nametoaddr libs in nconf, we call netdir_getbyname 1657c478bd9Sstevel@tonic-gate * implementation: __classic_netdir_getbyname, otherwise nsswitch. 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * netdir_getbyname calls this only if nametoaddr libs are NOT 1687c478bd9Sstevel@tonic-gate * specified for inet transports; i.e. it's supposed to follow 1697c478bd9Sstevel@tonic-gate * the name service switch. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate int 1727c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(struct netconfig *nconf, 1737c478bd9Sstevel@tonic-gate struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate int server_port; 1767c478bd9Sstevel@tonic-gate int *servp = &server_port; 1777c478bd9Sstevel@tonic-gate char **haddrlist; 1787c478bd9Sstevel@tonic-gate uint32_t dotnameaddr; 1797c478bd9Sstevel@tonic-gate char *dotnamelist[2]; 1807c478bd9Sstevel@tonic-gate struct in_addr *inaddrs = NULL; 1817c478bd9Sstevel@tonic-gate struct in6_addr v6nameaddr; 1827c478bd9Sstevel@tonic-gate char **baddrlist = NULL; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (nconf == NULL) { 1867c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 1877c478bd9Sstevel@tonic-gate return (ND_BADARG); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * 1. gethostbyname()/netdir_getbyname() special cases: 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate switch (args->op_t) { 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate case NSS_HOST: 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Worth the performance gain -- assuming a lot of inet apps 1987c478bd9Sstevel@tonic-gate * actively use "localhost". 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) { 2017c478bd9Sstevel@tonic-gate 20261961e0fSrobinson (void) mutex_lock(&nd_addr_lock); 2037c478bd9Sstevel@tonic-gate IN_SET_LOOPBACK_ADDR(&sa_con); 2047c478bd9Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 2057c478bd9Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 2067c478bd9Sstevel@tonic-gate args->arg.nss.host.buf, 2077c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen); 20861961e0fSrobinson (void) mutex_unlock(&nd_addr_lock); 2097c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) 2107c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = 2117c478bd9Sstevel@tonic-gate nd2herrno(_nderror); 2127c478bd9Sstevel@tonic-gate return (_nderror); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * If the caller passed in a dot separated IP notation to 2167c478bd9Sstevel@tonic-gate * gethostbyname, return that back as the address. 2177c478bd9Sstevel@tonic-gate * The nd_addr_lock mutex was added to be truely re-entrant. 2187c478bd9Sstevel@tonic-gate */ 2196c740c0aSraf if (inet_aton(args->arg.nss.host.name, 2207c478bd9Sstevel@tonic-gate (struct in_addr *)&dotnameaddr)) { 22161961e0fSrobinson (void) mutex_lock(&nd_addr_lock); 22261961e0fSrobinson (void) memset(&sa_con, 0, sizeof (sa_con)); 2237c478bd9Sstevel@tonic-gate sa_con.sin_family = AF_INET; 2247c478bd9Sstevel@tonic-gate sa_con.sin_addr.s_addr = dotnameaddr; 2257c478bd9Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 2267c478bd9Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 2277c478bd9Sstevel@tonic-gate args->arg.nss.host.buf, 2287c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen); 22961961e0fSrobinson (void) mutex_unlock(&nd_addr_lock); 2307c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) 2317c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = 2327c478bd9Sstevel@tonic-gate nd2herrno(_nderror); 2337c478bd9Sstevel@tonic-gate return (_nderror); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate break; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate case NSS_HOST6: 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * Handle case of literal address string. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate if (strchr(args->arg.nss.host6.name, ':') != NULL && 2427c478bd9Sstevel@tonic-gate (inet_pton(AF_INET6, args->arg.nss.host6.name, 2437c478bd9Sstevel@tonic-gate &v6nameaddr) != 0)) { 2447c478bd9Sstevel@tonic-gate int ret; 2457c478bd9Sstevel@tonic-gate 24661961e0fSrobinson (void) mutex_lock(&nd6_addr_lock); 24761961e0fSrobinson (void) memset(&sa6_con, 0, sizeof (sa6_con)); 2487c478bd9Sstevel@tonic-gate sa6_con.sin6_family = AF_INET6; 24961961e0fSrobinson (void) memcpy(&(sa6_con.sin6_addr.s6_addr), 2507c478bd9Sstevel@tonic-gate &v6nameaddr, sizeof (struct in6_addr)); 2517c478bd9Sstevel@tonic-gate ret = ndaddr2hent(AF_INET6, 2527c478bd9Sstevel@tonic-gate args->arg.nss.host6.name, 2537c478bd9Sstevel@tonic-gate &nd6_conaddrlist, res->nss.host.hent, 2547c478bd9Sstevel@tonic-gate args->arg.nss.host6.buf, 2557c478bd9Sstevel@tonic-gate args->arg.nss.host6.buflen); 25661961e0fSrobinson (void) mutex_unlock(&nd6_addr_lock); 2577c478bd9Sstevel@tonic-gate if (ret != ND_OK) 2587c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(ret); 2597c478bd9Sstevel@tonic-gate else 2607c478bd9Sstevel@tonic-gate res->nss.host.hent->h_aliases = NULL; 2617c478bd9Sstevel@tonic-gate return (ret); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate break; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate case NETDIR_BY: 2667c478bd9Sstevel@tonic-gate if (args->arg.nd_hs == 0) { 2677c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 2687c478bd9Sstevel@tonic-gate return (ND_BADARG); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * If servname is NULL, return 0 as the port number 2727c478bd9Sstevel@tonic-gate * If servname is rpcbind, return 111 as the port number 2737c478bd9Sstevel@tonic-gate * If servname is a number, return it back as the port 2747c478bd9Sstevel@tonic-gate * number. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate if (args->arg.nd_hs->h_serv == 0) { 2777c478bd9Sstevel@tonic-gate *servp = htons(0); 278*6392794bSMichen Chang } else if (strcmp(args->arg.nd_hs->h_serv, 279*6392794bSMichen Chang "rpcbind") == 0) { 2807c478bd9Sstevel@tonic-gate *servp = htons(111); 281*6392794bSMichen Chang } else if (strspn(args->arg.nd_hs->h_serv, 282*6392794bSMichen Chang "0123456789") == 283*6392794bSMichen Chang strlen(args->arg.nd_hs->h_serv)) { 2847c478bd9Sstevel@tonic-gate *servp = htons(atoi(args->arg.nd_hs->h_serv)); 2857c478bd9Sstevel@tonic-gate } else { 2867c478bd9Sstevel@tonic-gate /* i.e. need to call a name service on this */ 2877c478bd9Sstevel@tonic-gate servp = NULL; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * If the hostname is HOST_SELF_BIND, we return 0.0.0.0 2927c478bd9Sstevel@tonic-gate * so the binding can be contacted through all 2937c478bd9Sstevel@tonic-gate * interfaces. If the hostname is HOST_SELF_CONNECT, 2947c478bd9Sstevel@tonic-gate * we return 127.0.0.1 so the address can be connected 2957c478bd9Sstevel@tonic-gate * to locally. If the hostname is HOST_ANY, we return 2967c478bd9Sstevel@tonic-gate * no addresses because IP doesn't know how to specify 2977c478bd9Sstevel@tonic-gate * a service without a host. And finally if we specify 2987c478bd9Sstevel@tonic-gate * HOST_BROADCAST then we ask a tli fd to tell us what 2997c478bd9Sstevel@tonic-gate * the broadcast addresses are for any udp 3007c478bd9Sstevel@tonic-gate * interfaces on this machine. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate if (args->arg.nd_hs->h_host == 0) { 3037c478bd9Sstevel@tonic-gate _nderror = ND_NOHOST; 3047c478bd9Sstevel@tonic-gate return (ND_NOHOST); 3057c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 3067c478bd9Sstevel@tonic-gate HOST_SELF_BIND) == 0)) { 3077c478bd9Sstevel@tonic-gate haddrlist = localaddr; 3087c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 309*6392794bSMichen Chang HOST_SELF_CONNECT) == 0)) { 3107c478bd9Sstevel@tonic-gate haddrlist = connectaddr; 3117c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 312*6392794bSMichen Chang LOCALHOST) == 0)) { 3137c478bd9Sstevel@tonic-gate haddrlist = connectaddr; 3147c478bd9Sstevel@tonic-gate } else if ((int)(dotnameaddr = 315*6392794bSMichen Chang inet_addr(args->arg.nd_hs->h_host)) != -1) { 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * If the caller passed in a dot separated IP 3187c478bd9Sstevel@tonic-gate * notation to netdir_getbyname, convert that 3197c478bd9Sstevel@tonic-gate * back into address. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate dotnamelist[0] = (char *)&dotnameaddr; 3237c478bd9Sstevel@tonic-gate dotnamelist[1] = NULL; 3247c478bd9Sstevel@tonic-gate haddrlist = dotnamelist; 3257c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 326*6392794bSMichen Chang HOST_BROADCAST) == 0)) { 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Now that inaddrs and baddrlist are 3297c478bd9Sstevel@tonic-gate * dynamically allocated, care must be 3307c478bd9Sstevel@tonic-gate * taken in freeing up the 3317c478bd9Sstevel@tonic-gate * memory at each 'return()' point. 3327c478bd9Sstevel@tonic-gate * 3337c478bd9Sstevel@tonic-gate * Early return protection (using 3347c478bd9Sstevel@tonic-gate * FREE_return()) is needed only in NETDIR_BY 3357c478bd9Sstevel@tonic-gate * cases because dynamic allocation is used 3367c478bd9Sstevel@tonic-gate * when args->op_t == NETDIR_BY. 3377c478bd9Sstevel@tonic-gate * 3387c478bd9Sstevel@tonic-gate * Early return protection is not needed in 3397c478bd9Sstevel@tonic-gate * haddrlist==0 conditionals because dynamic 3407c478bd9Sstevel@tonic-gate * allocation guarantees haddrlist!=0. 3417c478bd9Sstevel@tonic-gate * 3427c478bd9Sstevel@tonic-gate * Early return protection is not needed in most 3437c478bd9Sstevel@tonic-gate * servp!=0 conditionals because this is handled 3447c478bd9Sstevel@tonic-gate * (and returned) first. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate #define FREE_return(ret) \ 3477c478bd9Sstevel@tonic-gate { \ 348*6392794bSMichen Chang if (inaddrs) \ 349*6392794bSMichen Chang free(inaddrs); \ 350*6392794bSMichen Chang if (baddrlist) \ 351*6392794bSMichen Chang free(baddrlist); \ 352*6392794bSMichen Chang _nderror = ret; \ 353*6392794bSMichen Chang return (ret); \ 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate int i, bnets; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate bnets = getbroadcastnets(nconf, &inaddrs); 3587c478bd9Sstevel@tonic-gate if (bnets == 0) { 3597c478bd9Sstevel@tonic-gate _nderror = ND_NOHOST; 3607c478bd9Sstevel@tonic-gate return (ND_NOHOST); 3617c478bd9Sstevel@tonic-gate } 36261961e0fSrobinson baddrlist = malloc((bnets+1)*sizeof (char *)); 3637c478bd9Sstevel@tonic-gate if (baddrlist == NULL) 3647c478bd9Sstevel@tonic-gate FREE_return(ND_NOMEM); 3657c478bd9Sstevel@tonic-gate for (i = 0; i < bnets; i++) 3667c478bd9Sstevel@tonic-gate baddrlist[i] = (char *)&inaddrs[i]; 3677c478bd9Sstevel@tonic-gate baddrlist[i] = NULL; 3687c478bd9Sstevel@tonic-gate haddrlist = baddrlist; 3697c478bd9Sstevel@tonic-gate } else { 3707c478bd9Sstevel@tonic-gate /* i.e. need to call a name service on this */ 3717c478bd9Sstevel@tonic-gate haddrlist = 0; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (haddrlist && servp) { 3757c478bd9Sstevel@tonic-gate int ret; 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 3787c478bd9Sstevel@tonic-gate * malloc's will be done, freed using 3797c478bd9Sstevel@tonic-gate * netdir_free. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, haddrlist, servp, 382*6392794bSMichen Chang res->nd_alist); 383*6392794bSMichen Chang FREE_return(ret); 384*6392794bSMichen Chang } 3857c478bd9Sstevel@tonic-gate break; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate case NETDIR_BY6: 3897c478bd9Sstevel@tonic-gate if (args->arg.nd_hs == 0) { 3907c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 3917c478bd9Sstevel@tonic-gate return (ND_BADARG); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * If servname is NULL, return 0 as the port number. 3957c478bd9Sstevel@tonic-gate * If servname is rpcbind, return 111 as the port number 3967c478bd9Sstevel@tonic-gate * If servname is a number, return it back as the port 3977c478bd9Sstevel@tonic-gate * number. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate if (args->arg.nd_hs->h_serv == 0) { 4007c478bd9Sstevel@tonic-gate *servp = htons(0); 4017c478bd9Sstevel@tonic-gate } else if (strcmp(args->arg.nd_hs->h_serv, 402*6392794bSMichen Chang "rpcbind") == 0) { 4037c478bd9Sstevel@tonic-gate *servp = htons(111); 4047c478bd9Sstevel@tonic-gate } else if (strspn(args->arg.nd_hs->h_serv, "0123456789") 405*6392794bSMichen Chang == strlen(args->arg.nd_hs->h_serv)) { 4067c478bd9Sstevel@tonic-gate *servp = htons(atoi(args->arg.nd_hs->h_serv)); 4077c478bd9Sstevel@tonic-gate } else { 4087c478bd9Sstevel@tonic-gate /* i.e. need to call a name service on this */ 4097c478bd9Sstevel@tonic-gate servp = NULL; 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * If the hostname is HOST_SELF_BIND, we return ipv6 4147c478bd9Sstevel@tonic-gate * localaddress so the binding can be contacted through 4157c478bd9Sstevel@tonic-gate * all interfaces. 4167c478bd9Sstevel@tonic-gate * If the hostname is HOST_SELF_CONNECT, we return 4177c478bd9Sstevel@tonic-gate * ipv6 loopback address so the address can be connected 4187c478bd9Sstevel@tonic-gate * to locally. 4197c478bd9Sstevel@tonic-gate * If the hostname is HOST_ANY, we return no addresses 4207c478bd9Sstevel@tonic-gate * because IP doesn't know how to specify a service 4217c478bd9Sstevel@tonic-gate * without a host. 4227c478bd9Sstevel@tonic-gate * And finally if we specify HOST_BROADCAST then we 4237c478bd9Sstevel@tonic-gate * disallow since IPV6 does not have any 4247c478bd9Sstevel@tonic-gate * broadcast concept. 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate if (args->arg.nd_hs->h_host == 0) { 4277c478bd9Sstevel@tonic-gate return (ND_NOHOST); 4287c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 429*6392794bSMichen Chang HOST_SELF_BIND) == 0)) { 4307c478bd9Sstevel@tonic-gate haddrlist = localaddr6; 4317c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 432*6392794bSMichen Chang HOST_SELF_CONNECT) == 0)) { 4337c478bd9Sstevel@tonic-gate haddrlist = connectaddr6; 4347c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 435*6392794bSMichen Chang LOCALHOST) == 0)) { 4367c478bd9Sstevel@tonic-gate haddrlist = connectaddr6; 4377c478bd9Sstevel@tonic-gate } else if (strchr(args->arg.nd_hs->h_host, ':') 438*6392794bSMichen Chang != NULL) { 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * If the caller passed in a dot separated IP notation 4427c478bd9Sstevel@tonic-gate * to netdir_getbyname, convert that back into address. 4437c478bd9Sstevel@tonic-gate */ 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if ((inet_pton(AF_INET6, 446*6392794bSMichen Chang args->arg.nd_hs->h_host, 447*6392794bSMichen Chang &v6nameaddr)) != 0) { 4487c478bd9Sstevel@tonic-gate dotnamelist[0] = (char *)&v6nameaddr; 4497c478bd9Sstevel@tonic-gate dotnamelist[1] = NULL; 4507c478bd9Sstevel@tonic-gate haddrlist = dotnamelist; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate else 4537c478bd9Sstevel@tonic-gate /* not sure what to return */ 4547c478bd9Sstevel@tonic-gate return (ND_NOHOST); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 457*6392794bSMichen Chang HOST_BROADCAST) == 0)) { 4587c478bd9Sstevel@tonic-gate /* 4597c478bd9Sstevel@tonic-gate * Don't support broadcast in 4607c478bd9Sstevel@tonic-gate * IPV6 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate return (ND_NOHOST); 4637c478bd9Sstevel@tonic-gate } else { 4647c478bd9Sstevel@tonic-gate /* i.e. need to call a name service on this */ 4657c478bd9Sstevel@tonic-gate haddrlist = 0; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (haddrlist && servp) { 4697c478bd9Sstevel@tonic-gate int ret; 4707c478bd9Sstevel@tonic-gate /* 4717c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 4727c478bd9Sstevel@tonic-gate * malloc's will be done, freed 4737c478bd9Sstevel@tonic-gate * using netdir_free. 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, haddrlist, 4767c478bd9Sstevel@tonic-gate servp, res->nd_alist); 477*6392794bSMichen Chang FREE_return(ret); 478*6392794bSMichen Chang } 4797c478bd9Sstevel@tonic-gate break; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * 2. Most common scenario. This is the way we ship /etc/netconfig. 4867c478bd9Sstevel@tonic-gate * Emphasis on improving performance in the "if" part. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate if (nconf->nc_nlookups == 0) { 4897c478bd9Sstevel@tonic-gate struct hostent *he = NULL, *tmphe; 4907c478bd9Sstevel@tonic-gate struct servent *se; 4917c478bd9Sstevel@tonic-gate int ret; 4927c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4switch = 0; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate switch (args->op_t) { 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate case NSS_HOST: 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name, 4997c478bd9Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 5007c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen, 5017c478bd9Sstevel@tonic-gate res->nss.host.herrno_p); 5027c478bd9Sstevel@tonic-gate if (he == NULL) 5037c478bd9Sstevel@tonic-gate return (_nderror = ND_NOHOST); 5047c478bd9Sstevel@tonic-gate return (_nderror = ND_OK); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate case NSS_HOST6: 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name, 5097c478bd9Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 5107c478bd9Sstevel@tonic-gate args->arg.nss.host6.buflen, 5117c478bd9Sstevel@tonic-gate args->arg.nss.host6.af_family, 5127c478bd9Sstevel@tonic-gate args->arg.nss.host6.flags, 5137c478bd9Sstevel@tonic-gate res->nss.host.herrno_p); 5147c478bd9Sstevel@tonic-gate 51561961e0fSrobinson if (he == NULL) 5167c478bd9Sstevel@tonic-gate return (_nderror = ND_NOHOST); 5177c478bd9Sstevel@tonic-gate return (_nderror = ND_OK); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate case NSS_SERV: 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate se = _switch_getservbyname_r(args->arg.nss.serv.name, 5227c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto, 5237c478bd9Sstevel@tonic-gate res->nss.serv, args->arg.nss.serv.buf, 5247c478bd9Sstevel@tonic-gate args->arg.nss.serv.buflen); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate _nderror = ND_OK; 5277c478bd9Sstevel@tonic-gate if (se == 0) 5287c478bd9Sstevel@tonic-gate _nderror = ND_NOSERV; 5297c478bd9Sstevel@tonic-gate return (_nderror); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate case NETDIR_BY: 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (servp == 0) { 534*6392794bSMichen Chang char *proto = (strcmp(nconf->nc_proto, 535*6392794bSMichen Chang NC_TCP) == 0) ? NC_TCP : NC_UDP; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * We go through all this for just one port number, 5397c478bd9Sstevel@tonic-gate * which is most often constant. How about linking in 5407c478bd9Sstevel@tonic-gate * an indexed database of well-known ports in the name 5417c478bd9Sstevel@tonic-gate * of performance ? 5427c478bd9Sstevel@tonic-gate */ 54361961e0fSrobinson ndbuf4switch = _nss_XbyY_buf_alloc( 544*6392794bSMichen Chang sizeof (struct servent), NSS_BUFLEN_SERVICES); 5457c478bd9Sstevel@tonic-gate if (ndbuf4switch == 0) 5467c478bd9Sstevel@tonic-gate FREE_return(ND_NOMEM); 5477c478bd9Sstevel@tonic-gate se = _switch_getservbyname_r(args->arg.nd_hs->h_serv, 548*6392794bSMichen Chang proto, ndbuf4switch->result, 549*6392794bSMichen Chang ndbuf4switch->buffer, ndbuf4switch->buflen); 5507c478bd9Sstevel@tonic-gate if (!se) { 5517c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 552*6392794bSMichen Chang FREE_return(ND_NOSERV); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate server_port = se->s_port; 5557c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (haddrlist == 0) { 5597c478bd9Sstevel@tonic-gate int h_errnop = 0; 5607c478bd9Sstevel@tonic-gate 56161961e0fSrobinson ndbuf4switch = _nss_XbyY_buf_alloc( 562*6392794bSMichen Chang sizeof (struct hostent), 563*6392794bSMichen Chang NSS_BUFLEN_HOSTS); 5647c478bd9Sstevel@tonic-gate if (ndbuf4switch == 0) { 5657c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 5667c478bd9Sstevel@tonic-gate return (ND_NOMEM); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * Search the ipnodes (v6) path first, 5707c478bd9Sstevel@tonic-gate * search will return the v4 addresses 5717c478bd9Sstevel@tonic-gate * as v4mapped addresses. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate if ((tmphe = DOOR_GETIPNODEBYNAME_R( 5747c478bd9Sstevel@tonic-gate args->arg.nd_hs->h_host, 5757c478bd9Sstevel@tonic-gate ndbuf4switch->result, ndbuf4switch->buffer, 5767c478bd9Sstevel@tonic-gate ndbuf4switch->buflen, args->arg.nss.host6.af_family, 5777c478bd9Sstevel@tonic-gate args->arg.nss.host6.flags, &h_errnop)) != NULL) 5787c478bd9Sstevel@tonic-gate he = __mappedtov4(tmphe, &h_errnop); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (he == NULL) { 5817c478bd9Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 5827c478bd9Sstevel@tonic-gate he = DOOR_GETHOSTBYNAME_R( 583*6392794bSMichen Chang args->arg.nd_hs->h_host, 584*6392794bSMichen Chang ndbuf4switch->result, ndbuf4switch->buffer, 585*6392794bSMichen Chang ndbuf4switch->buflen, &h_errnop); 5867c478bd9Sstevel@tonic-gate if (he == NULL) { 5877c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 5887c478bd9Sstevel@tonic-gate _nderror = h_errnop ? 5897c478bd9Sstevel@tonic-gate __herrno2netdir(h_errnop) : 5907c478bd9Sstevel@tonic-gate ND_NOHOST; 5917c478bd9Sstevel@tonic-gate return (_nderror); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 5957c478bd9Sstevel@tonic-gate * malloc's will be done, freed using 5967c478bd9Sstevel@tonic-gate * netdir_free. 5977c478bd9Sstevel@tonic-gate */ 5987c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, he->h_addr_list, 599*6392794bSMichen Chang &server_port, res->nd_alist); 6007c478bd9Sstevel@tonic-gate } else { 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 6037c478bd9Sstevel@tonic-gate * malloc's will be done, freed using 6047c478bd9Sstevel@tonic-gate * netdir_free. 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, he->h_addr_list, 607*6392794bSMichen Chang &server_port, res->nd_alist); 6087c478bd9Sstevel@tonic-gate freehostent(he); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate _nderror = ret; 6127c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 6137c478bd9Sstevel@tonic-gate return (ret); 6147c478bd9Sstevel@tonic-gate } else { 6157c478bd9Sstevel@tonic-gate int ret; 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 6187c478bd9Sstevel@tonic-gate * malloc's will be done, freed using netdir_free. 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, haddrlist, 621*6392794bSMichen Chang &server_port, res->nd_alist); 622*6392794bSMichen Chang FREE_return(ret); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate case NETDIR_BY6: 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate if (servp == 0) { 629*6392794bSMichen Chang char *proto = (strcmp(nconf->nc_proto, 630*6392794bSMichen Chang NC_TCP) == 0) ? NC_TCP : NC_UDP; 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * We go through all this for just 6347c478bd9Sstevel@tonic-gate * one port number, 6357c478bd9Sstevel@tonic-gate * which is most often constant. 6367c478bd9Sstevel@tonic-gate * How about linking in 6377c478bd9Sstevel@tonic-gate * an indexed database of well-known 6387c478bd9Sstevel@tonic-gate * ports in the name 6397c478bd9Sstevel@tonic-gate * of performance ? 6407c478bd9Sstevel@tonic-gate */ 64161961e0fSrobinson ndbuf4switch = _nss_XbyY_buf_alloc( 642*6392794bSMichen Chang sizeof (struct servent), 643*6392794bSMichen Chang NSS_BUFLEN_SERVICES); 6447c478bd9Sstevel@tonic-gate if (ndbuf4switch == 0) 6457c478bd9Sstevel@tonic-gate FREE_return(ND_NOMEM); 6467c478bd9Sstevel@tonic-gate se = _switch_getservbyname_r( 647*6392794bSMichen Chang args->arg.nd_hs->h_serv, 6487c478bd9Sstevel@tonic-gate proto, ndbuf4switch->result, 6497c478bd9Sstevel@tonic-gate ndbuf4switch->buffer, ndbuf4switch->buflen); 6507c478bd9Sstevel@tonic-gate if (!se) { 6517c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 652*6392794bSMichen Chang FREE_return(ND_NOSERV); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate server_port = se->s_port; 6557c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if (haddrlist == 0) { 6597c478bd9Sstevel@tonic-gate int h_errnop = 0; 6607c478bd9Sstevel@tonic-gate 66161961e0fSrobinson ndbuf4switch = _nss_XbyY_buf_alloc( 662*6392794bSMichen Chang sizeof (struct hostent), 663*6392794bSMichen Chang NSS_BUFLEN_HOSTS); 6647c478bd9Sstevel@tonic-gate if (ndbuf4switch == 0) { 6657c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 6667c478bd9Sstevel@tonic-gate return (ND_NOMEM); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate he = DOOR_GETIPNODEBYNAME_R( 6697c478bd9Sstevel@tonic-gate args->arg.nd_hs->h_host, 6707c478bd9Sstevel@tonic-gate ndbuf4switch->result, ndbuf4switch->buffer, 6717c478bd9Sstevel@tonic-gate ndbuf4switch->buflen, 6727c478bd9Sstevel@tonic-gate args->arg.nss.host6.af_family, 6737c478bd9Sstevel@tonic-gate args->arg.nss.host6.flags, &h_errnop); 6747c478bd9Sstevel@tonic-gate if (he == NULL) { 6757c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 6767c478bd9Sstevel@tonic-gate _nderror = h_errnop ? 6777c478bd9Sstevel@tonic-gate __herrno2netdir(h_errnop) : 6787c478bd9Sstevel@tonic-gate ND_NOHOST; 6797c478bd9Sstevel@tonic-gate return (_nderror); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 6837c478bd9Sstevel@tonic-gate * malloc's will be done, 6847c478bd9Sstevel@tonic-gate * freed using netdir_free. 6857c478bd9Sstevel@tonic-gate */ 6867c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, 687*6392794bSMichen Chang ((struct hostent *) 688*6392794bSMichen Chang (ndbuf4switch->result))->h_addr_list, 6897c478bd9Sstevel@tonic-gate &server_port, res->nd_alist); 6907c478bd9Sstevel@tonic-gate _nderror = ret; 6917c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 6927c478bd9Sstevel@tonic-gate return (ret); 6937c478bd9Sstevel@tonic-gate } else { 6947c478bd9Sstevel@tonic-gate int ret; 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 6977c478bd9Sstevel@tonic-gate * malloc's will be done, 6987c478bd9Sstevel@tonic-gate * freed using netdir_free. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, haddrlist, 701*6392794bSMichen Chang &server_port, res->nd_alist); 702*6392794bSMichen Chang FREE_return(ret); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate default: 706*6392794bSMichen Chang _nderror = ND_BADARG; 707*6392794bSMichen Chang return (ND_BADARG); /* should never happen */ 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate } else { 7117c478bd9Sstevel@tonic-gate /* haddrlist is no longer used, so clean up */ 7127c478bd9Sstevel@tonic-gate if (inaddrs) 7137c478bd9Sstevel@tonic-gate free(inaddrs); 7147c478bd9Sstevel@tonic-gate if (baddrlist) 7157c478bd9Sstevel@tonic-gate free(baddrlist); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * 3. We come this far only if nametoaddr libs are specified for 7207c478bd9Sstevel@tonic-gate * inet transports and we are called by gethost/servbyname only. 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate switch (args->op_t) { 7237c478bd9Sstevel@tonic-gate struct nd_hostserv service; 7247c478bd9Sstevel@tonic-gate struct nd_addrlist *addrs; 7257c478bd9Sstevel@tonic-gate int ret; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate case NSS_HOST: 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate service.h_host = (char *)args->arg.nss.host.name; 7307c478bd9Sstevel@tonic-gate service.h_serv = NULL; 7317c478bd9Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyname(nconf, 732*6392794bSMichen Chang &service, &addrs)) != ND_OK) { 7337c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 7347c478bd9Sstevel@tonic-gate return (_nderror); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate /* 7377c478bd9Sstevel@tonic-gate * convert addresses back into sockaddr for gethostbyname. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate ret = ndaddr2hent(AF_INET, service.h_host, addrs, 7407c478bd9Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 7417c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen); 7427c478bd9Sstevel@tonic-gate if (ret != ND_OK) 7437c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(ret); 7447c478bd9Sstevel@tonic-gate netdir_free((char *)addrs, ND_ADDRLIST); 7457c478bd9Sstevel@tonic-gate _nderror = ret; 7467c478bd9Sstevel@tonic-gate return (ret); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate case NSS_SERV: 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (args->arg.nss.serv.proto == NULL) { 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * A similar HACK showed up in Solaris 2.3. 7537c478bd9Sstevel@tonic-gate * The caller wild-carded proto -- i.e. will 7547c478bd9Sstevel@tonic-gate * accept a match using tcp or udp for the port 7557c478bd9Sstevel@tonic-gate * number. Since we have no hope of getting 7567c478bd9Sstevel@tonic-gate * directly to a name service switch backend 7577c478bd9Sstevel@tonic-gate * from here that understands this semantics, 7587c478bd9Sstevel@tonic-gate * we try calling the netdir interfaces first 7597c478bd9Sstevel@tonic-gate * with "tcp" and then "udp". 7607c478bd9Sstevel@tonic-gate */ 7617c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto = "tcp"; 7627c478bd9Sstevel@tonic-gate _nderror = _get_hostserv_inetnetdir_byname(nconf, args, 7637c478bd9Sstevel@tonic-gate res); 7647c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) { 7657c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto = "udp"; 7667c478bd9Sstevel@tonic-gate _nderror = 7677c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(nconf, 7687c478bd9Sstevel@tonic-gate args, res); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate return (_nderror); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * Third-parties should optimize their nametoaddr 7757c478bd9Sstevel@tonic-gate * libraries for the HOST_SELF case. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate service.h_host = HOST_SELF; 7787c478bd9Sstevel@tonic-gate service.h_serv = (char *)args->arg.nss.serv.name; 7797c478bd9Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyname(nconf, 780*6392794bSMichen Chang &service, &addrs)) != ND_OK) { 7817c478bd9Sstevel@tonic-gate return (_nderror); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * convert addresses back into servent for getservbyname. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate _nderror = ndaddr2srent(service.h_serv, 7877c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto, 78861961e0fSrobinson /* LINTED pointer cast */ 7897c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port, 7907c478bd9Sstevel@tonic-gate res->nss.serv, 7917c478bd9Sstevel@tonic-gate args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 7927c478bd9Sstevel@tonic-gate netdir_free((char *)addrs, ND_ADDRLIST); 7937c478bd9Sstevel@tonic-gate return (_nderror); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate default: 7967c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 7977c478bd9Sstevel@tonic-gate return (ND_BADARG); /* should never happen */ 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * gethostbyaddr/servbyport always call this function; if they call 8037c478bd9Sstevel@tonic-gate * with nametoaddr libs in nconf, we call netdir_getbyaddr 8047c478bd9Sstevel@tonic-gate * implementation __classic_netdir_getbyaddr, otherwise nsswitch. 8057c478bd9Sstevel@tonic-gate * 8067c478bd9Sstevel@tonic-gate * netdir_getbyaddr calls this only if nametoaddr libs are NOT 8077c478bd9Sstevel@tonic-gate * specified for inet transports; i.e. it's supposed to follow 8087c478bd9Sstevel@tonic-gate * the name service switch. 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate int 8117c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf, 8127c478bd9Sstevel@tonic-gate struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res) 8137c478bd9Sstevel@tonic-gate { 8147c478bd9Sstevel@tonic-gate if (nconf == 0) { 8157c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 8167c478bd9Sstevel@tonic-gate return (_nderror); 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate /* 8207c478bd9Sstevel@tonic-gate * 1. gethostbyaddr()/netdir_getbyaddr() special cases: 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate switch (args->op_t) { 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate case NSS_HOST: 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * Worth the performance gain: assuming a lot of inet apps 8277c478bd9Sstevel@tonic-gate * actively use "127.0.0.1". 8287c478bd9Sstevel@tonic-gate */ 82961961e0fSrobinson /* LINTED pointer cast */ 8307c478bd9Sstevel@tonic-gate if (*(uint32_t *)(args->arg.nss.host.addr) == 831*6392794bSMichen Chang htonl(INADDR_LOOPBACK)) { 83261961e0fSrobinson (void) mutex_lock(&nd_addr_lock); 8337c478bd9Sstevel@tonic-gate IN_SET_LOOPBACK_ADDR(&sa_con); 8347c478bd9Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, LOCALHOST, 8357c478bd9Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 8367c478bd9Sstevel@tonic-gate args->arg.nss.host.buf, 8377c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen); 83861961e0fSrobinson (void) mutex_unlock(&nd_addr_lock); 8397c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) 8407c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = 8417c478bd9Sstevel@tonic-gate nd2herrno(_nderror); 8427c478bd9Sstevel@tonic-gate return (_nderror); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate break; 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate case NETDIR_BY: 8477c478bd9Sstevel@tonic-gate case NETDIR_BY_NOSRV: 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if (args->arg.nd_nbuf == NULL) { 8527c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 8537c478bd9Sstevel@tonic-gate return (_nderror); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * Validate the address which was passed 8587c478bd9Sstevel@tonic-gate * as the request. 8597c478bd9Sstevel@tonic-gate */ 86061961e0fSrobinson /* LINTED pointer cast */ 8617c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate if ((args->arg.nd_nbuf->len != 864*6392794bSMichen Chang sizeof (struct sockaddr_in)) || 8657c478bd9Sstevel@tonic-gate (sin->sin_family != AF_INET)) { 8667c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 8677c478bd9Sstevel@tonic-gate return (_nderror); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate break; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate case NETDIR_BY6: 8737c478bd9Sstevel@tonic-gate case NETDIR_BY_NOSRV6: 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (args->arg.nd_nbuf == NULL) { 8787c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 8797c478bd9Sstevel@tonic-gate return (_nderror); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * Validate the address which was passed 8847c478bd9Sstevel@tonic-gate * as the request. 8857c478bd9Sstevel@tonic-gate */ 88661961e0fSrobinson /* LINTED pointer cast */ 8877c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate if ((args->arg.nd_nbuf->len != 890*6392794bSMichen Chang sizeof (struct sockaddr_in6)) || 8917c478bd9Sstevel@tonic-gate (sin6->sin6_family != AF_INET6)) { 8927c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 8937c478bd9Sstevel@tonic-gate return (_nderror); 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate break; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* 9017c478bd9Sstevel@tonic-gate * 2. Most common scenario. This is the way we ship /etc/netconfig. 9027c478bd9Sstevel@tonic-gate * Emphasis on improving performance in the "if" part. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate if (nconf->nc_nlookups == 0) { 9057c478bd9Sstevel@tonic-gate struct hostent *he = NULL, *tmphe; 9067c478bd9Sstevel@tonic-gate struct servent *se = NULL; 9077c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4host = 0; 9087c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4serv = 0; 9097c478bd9Sstevel@tonic-gate char *proto = 9107c478bd9Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 9117c478bd9Sstevel@tonic-gate struct sockaddr_in *sa; 9127c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 9137c478bd9Sstevel@tonic-gate struct in_addr *addr4 = 0; 9147c478bd9Sstevel@tonic-gate struct in6_addr v4mapbuf; 9157c478bd9Sstevel@tonic-gate int h_errnop; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate switch (args->op_t) { 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate case NSS_HOST: 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr, 9227c478bd9Sstevel@tonic-gate args->arg.nss.host.len, args->arg.nss.host.type, 9237c478bd9Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 9247c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen, 9257c478bd9Sstevel@tonic-gate res->nss.host.herrno_p); 9267c478bd9Sstevel@tonic-gate if (he == 0) 9277c478bd9Sstevel@tonic-gate _nderror = ND_NOHOST; 9287c478bd9Sstevel@tonic-gate else 9297c478bd9Sstevel@tonic-gate _nderror = ND_OK; 9307c478bd9Sstevel@tonic-gate return (_nderror); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate case NSS_HOST6: 9347c478bd9Sstevel@tonic-gate he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr, 9357c478bd9Sstevel@tonic-gate args->arg.nss.host.len, args->arg.nss.host.type, 9367c478bd9Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 9377c478bd9Sstevel@tonic-gate args->arg.nss.host.buflen, 9387c478bd9Sstevel@tonic-gate res->nss.host.herrno_p); 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (he == 0) 9417c478bd9Sstevel@tonic-gate return (ND_NOHOST); 9427c478bd9Sstevel@tonic-gate return (ND_OK); 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate case NSS_SERV: 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate se = _switch_getservbyport_r(args->arg.nss.serv.port, 9487c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto, 9497c478bd9Sstevel@tonic-gate res->nss.serv, args->arg.nss.serv.buf, 9507c478bd9Sstevel@tonic-gate args->arg.nss.serv.buflen); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (se == 0) 9537c478bd9Sstevel@tonic-gate _nderror = ND_NOSERV; 9547c478bd9Sstevel@tonic-gate else 9557c478bd9Sstevel@tonic-gate _nderror = ND_OK; 9567c478bd9Sstevel@tonic-gate return (_nderror); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate case NETDIR_BY: 9597c478bd9Sstevel@tonic-gate case NETDIR_BY_NOSRV: 9607c478bd9Sstevel@tonic-gate 96161961e0fSrobinson ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 962*6392794bSMichen Chang NSS_BUFLEN_SERVICES); 9637c478bd9Sstevel@tonic-gate if (ndbuf4serv == 0) { 9647c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 9657c478bd9Sstevel@tonic-gate return (_nderror); 9667c478bd9Sstevel@tonic-gate } 96761961e0fSrobinson /* LINTED pointer cast */ 9687c478bd9Sstevel@tonic-gate sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf); 9697c478bd9Sstevel@tonic-gate addr4 = (struct in_addr *)&(sa->sin_addr); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * if NETDIR_BY_NOSRV or port == 0 skip the service 9737c478bd9Sstevel@tonic-gate * lookup. 9747c478bd9Sstevel@tonic-gate */ 9757c478bd9Sstevel@tonic-gate if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) { 9767c478bd9Sstevel@tonic-gate se = _switch_getservbyport_r(sa->sin_port, proto, 9777c478bd9Sstevel@tonic-gate ndbuf4serv->result, ndbuf4serv->buffer, 978*6392794bSMichen Chang ndbuf4serv->buflen); 9797c478bd9Sstevel@tonic-gate if (!se) { 9807c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * We can live with this - i.e. the address 9837c478bd9Sstevel@tonic-gate * does not 9847c478bd9Sstevel@tonic-gate * belong to a well known service. The caller 9857c478bd9Sstevel@tonic-gate * traditionally accepts a stringified port 9867c478bd9Sstevel@tonic-gate * number 9877c478bd9Sstevel@tonic-gate * as the service name. The state of se is used 9887c478bd9Sstevel@tonic-gate * ahead to indicate the same. 9897c478bd9Sstevel@tonic-gate * However, we do not tolerate this nonsense 9907c478bd9Sstevel@tonic-gate * when we cannot get a host name. See below. 9917c478bd9Sstevel@tonic-gate */ 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 99561961e0fSrobinson ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 996*6392794bSMichen Chang NSS_BUFLEN_HOSTS); 9977c478bd9Sstevel@tonic-gate if (ndbuf4host == 0) { 9987c478bd9Sstevel@tonic-gate if (ndbuf4serv) 9997c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 10007c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 10017c478bd9Sstevel@tonic-gate return (_nderror); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * Since we're going to search the ipnodes (v6) path first, 10067c478bd9Sstevel@tonic-gate * we need to treat the address as a v4mapped address. 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf); 10107c478bd9Sstevel@tonic-gate if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf, 10117c478bd9Sstevel@tonic-gate 16, AF_INET6, ndbuf4host->result, 1012*6392794bSMichen Chang ndbuf4host->buffer, 1013*6392794bSMichen Chang ndbuf4host->buflen, &h_errnop)) != NULL) 10147c478bd9Sstevel@tonic-gate he = __mappedtov4(tmphe, &h_errnop); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate if (!he) { 10177c478bd9Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 10187c478bd9Sstevel@tonic-gate he = DOOR_GETHOSTBYADDR_R((char *) 1019*6392794bSMichen Chang &(sa->sin_addr.s_addr), 4, 1020*6392794bSMichen Chang sa->sin_family, ndbuf4host->result, 1021*6392794bSMichen Chang ndbuf4host->buffer, ndbuf4host->buflen, 1022*6392794bSMichen Chang &h_errnop); 10237c478bd9Sstevel@tonic-gate if (!he) { 10247c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 10257c478bd9Sstevel@tonic-gate if (ndbuf4serv) 10267c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 10277c478bd9Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 10287c478bd9Sstevel@tonic-gate return (_nderror); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * Convert host names and service names into hostserv 10327c478bd9Sstevel@tonic-gate * pairs. malloc's will be done, freed using 10337c478bd9Sstevel@tonic-gate * netdir_free. 10347c478bd9Sstevel@tonic-gate */ 10357c478bd9Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 10367c478bd9Sstevel@tonic-gate sa->sin_port, res->nd_hslist); 10377c478bd9Sstevel@tonic-gate } else { 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * Convert host names and service names into hostserv 10407c478bd9Sstevel@tonic-gate * pairs. malloc's will be done, freed using 10417c478bd9Sstevel@tonic-gate * netdir_free. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 10447c478bd9Sstevel@tonic-gate sa->sin_port, res->nd_hslist); 10457c478bd9Sstevel@tonic-gate freehostent(he); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 10497c478bd9Sstevel@tonic-gate if (ndbuf4serv) 1050*6392794bSMichen Chang NSS_XbyY_FREE(&ndbuf4serv); 10517c478bd9Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 10527c478bd9Sstevel@tonic-gate return (_nderror); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate case NETDIR_BY6: 10557c478bd9Sstevel@tonic-gate case NETDIR_BY_NOSRV6: 10567c478bd9Sstevel@tonic-gate 105761961e0fSrobinson ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent), 1058*6392794bSMichen Chang NSS_BUFLEN_SERVICES); 10597c478bd9Sstevel@tonic-gate if (ndbuf4serv == 0) { 10607c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 10617c478bd9Sstevel@tonic-gate return (ND_NOMEM); 10627c478bd9Sstevel@tonic-gate } 106361961e0fSrobinson /* LINTED pointer cast */ 10647c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate /* 10677c478bd9Sstevel@tonic-gate * if NETDIR_BY_NOSRV6 or port == 0 skip the service 10687c478bd9Sstevel@tonic-gate * lookup. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) { 10717c478bd9Sstevel@tonic-gate se = _switch_getservbyport_r(sin6->sin6_port, proto, 10727c478bd9Sstevel@tonic-gate ndbuf4serv->result, ndbuf4serv->buffer, 1073*6392794bSMichen Chang ndbuf4serv->buflen); 10747c478bd9Sstevel@tonic-gate if (!se) { 10757c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * We can live with this - i.e. the address does 10787c478bd9Sstevel@tonic-gate * not * belong to a well known service. The 10797c478bd9Sstevel@tonic-gate * caller traditionally accepts a stringified 10807c478bd9Sstevel@tonic-gate * port number 10817c478bd9Sstevel@tonic-gate * as the service name. The state of se is used 10827c478bd9Sstevel@tonic-gate * ahead to indicate the same. 10837c478bd9Sstevel@tonic-gate * However, we do not tolerate this nonsense 10847c478bd9Sstevel@tonic-gate * when we cannot get a host name. See below. 10857c478bd9Sstevel@tonic-gate */ 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 108961961e0fSrobinson ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent), 1090*6392794bSMichen Chang NSS_BUFLEN_HOSTS); 10917c478bd9Sstevel@tonic-gate if (ndbuf4host == 0) { 10927c478bd9Sstevel@tonic-gate if (ndbuf4serv) 10937c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 10947c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 10957c478bd9Sstevel@tonic-gate return (_nderror); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr), 10987c478bd9Sstevel@tonic-gate 16, sin6->sin6_family, ndbuf4host->result, 1099*6392794bSMichen Chang ndbuf4host->buffer, 1100*6392794bSMichen Chang ndbuf4host->buflen, &h_errnop); 11017c478bd9Sstevel@tonic-gate if (!he) { 11027c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 11037c478bd9Sstevel@tonic-gate if (ndbuf4serv) 1104*6392794bSMichen Chang NSS_XbyY_FREE(&ndbuf4serv); 11057c478bd9Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 11067c478bd9Sstevel@tonic-gate return (_nderror); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * Convert host names and service names into hostserv 11107c478bd9Sstevel@tonic-gate * pairs. malloc's will be done, freed using netdir_free. 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 11137c478bd9Sstevel@tonic-gate sin6->sin6_port, res->nd_hslist); 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 11167c478bd9Sstevel@tonic-gate if (ndbuf4serv) 1117*6392794bSMichen Chang NSS_XbyY_FREE(&ndbuf4serv); 11187c478bd9Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 11197c478bd9Sstevel@tonic-gate return (_nderror); 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate default: 11227c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 11237c478bd9Sstevel@tonic-gate return (_nderror); /* should never happen */ 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * 3. We come this far only if nametoaddr libs are specified for 11297c478bd9Sstevel@tonic-gate * inet transports and we are called by gethost/servbyname only. 11307c478bd9Sstevel@tonic-gate */ 11317c478bd9Sstevel@tonic-gate switch (args->op_t) { 11327c478bd9Sstevel@tonic-gate struct netbuf nbuf; 11337c478bd9Sstevel@tonic-gate struct nd_hostservlist *addrs; 11347c478bd9Sstevel@tonic-gate struct sockaddr_in sa; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate case NSS_HOST: 11377c478bd9Sstevel@tonic-gate 113861961e0fSrobinson /* LINTED pointer cast */ 11397c478bd9Sstevel@tonic-gate sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr; 11407c478bd9Sstevel@tonic-gate sa.sin_family = AF_INET; 11417c478bd9Sstevel@tonic-gate /* Hopefully, third-parties get this optimization */ 11427c478bd9Sstevel@tonic-gate sa.sin_port = 0; 11437c478bd9Sstevel@tonic-gate nbuf.buf = (char *)&sa; 11447c478bd9Sstevel@tonic-gate nbuf.len = nbuf.maxlen = sizeof (sa); 11457c478bd9Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyaddr(nconf, 1146*6392794bSMichen Chang &addrs, &nbuf)) != 0) { 11477c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 11487c478bd9Sstevel@tonic-gate return (_nderror); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate /* 11517c478bd9Sstevel@tonic-gate * convert the host-serv pairs into h_aliases and hent. 11527c478bd9Sstevel@tonic-gate */ 11537c478bd9Sstevel@tonic-gate _nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent, 11547c478bd9Sstevel@tonic-gate args->arg.nss.host.buf, args->arg.nss.host.buflen); 11557c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) 11567c478bd9Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 11577c478bd9Sstevel@tonic-gate netdir_free((char *)addrs, ND_HOSTSERVLIST); 11587c478bd9Sstevel@tonic-gate return (_nderror); 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate case NSS_SERV: 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate if (args->arg.nss.serv.proto == NULL) { 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * A similar HACK showed up in Solaris 2.3. 11657c478bd9Sstevel@tonic-gate * The caller wild-carded proto -- i.e. will 11667c478bd9Sstevel@tonic-gate * accept a match on tcp or udp for the port 11677c478bd9Sstevel@tonic-gate * number. Since we have no hope of getting 11687c478bd9Sstevel@tonic-gate * directly to a name service switch backend 11697c478bd9Sstevel@tonic-gate * from here that understands this semantics, 11707c478bd9Sstevel@tonic-gate * we try calling the netdir interfaces first 11717c478bd9Sstevel@tonic-gate * with "tcp" and then "udp". 11727c478bd9Sstevel@tonic-gate */ 11737c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto = "tcp"; 11747c478bd9Sstevel@tonic-gate _nderror = _get_hostserv_inetnetdir_byaddr(nconf, args, 11757c478bd9Sstevel@tonic-gate res); 11767c478bd9Sstevel@tonic-gate if (_nderror != ND_OK) { 11777c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto = "udp"; 11787c478bd9Sstevel@tonic-gate _nderror = 11797c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(nconf, 1180*6392794bSMichen Chang args, res); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate return (_nderror); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* 11867c478bd9Sstevel@tonic-gate * Third-party nametoaddr_libs should be optimized for 11877c478bd9Sstevel@tonic-gate * this case. It also gives a special semantics twist to 11887c478bd9Sstevel@tonic-gate * netdir_getbyaddr. Only for the INADDR_ANY case, it gives 11897c478bd9Sstevel@tonic-gate * higher priority to service lookups (over host lookups). 11907c478bd9Sstevel@tonic-gate * If service lookup fails, the backend returns ND_NOSERV to 11917c478bd9Sstevel@tonic-gate * facilitate lookup in the "next" naming service. 11927c478bd9Sstevel@tonic-gate * BugId: 1075403. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate sa.sin_addr.s_addr = INADDR_ANY; 11957c478bd9Sstevel@tonic-gate sa.sin_family = AF_INET; 11967c478bd9Sstevel@tonic-gate sa.sin_port = (ushort_t)args->arg.nss.serv.port; 11977c478bd9Sstevel@tonic-gate sa.sin_zero[0] = '\0'; 11987c478bd9Sstevel@tonic-gate nbuf.buf = (char *)&sa; 11997c478bd9Sstevel@tonic-gate nbuf.len = nbuf.maxlen = sizeof (sa); 12007c478bd9Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyaddr(nconf, 1201*6392794bSMichen Chang &addrs, &nbuf)) != ND_OK) { 12027c478bd9Sstevel@tonic-gate return (_nderror); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * convert the host-serv pairs into s_aliases and servent. 12067c478bd9Sstevel@tonic-gate */ 12077c478bd9Sstevel@tonic-gate _nderror = ndhostserv2srent(args->arg.nss.serv.port, 12087c478bd9Sstevel@tonic-gate args->arg.nss.serv.proto, addrs, res->nss.serv, 12097c478bd9Sstevel@tonic-gate args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 12107c478bd9Sstevel@tonic-gate netdir_free((char *)addrs, ND_HOSTSERVLIST); 12117c478bd9Sstevel@tonic-gate return (_nderror); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate default: 12147c478bd9Sstevel@tonic-gate _nderror = ND_BADARG; 12157c478bd9Sstevel@tonic-gate return (_nderror); /* should never happen */ 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * Part II: Name Service Switch interfacing routines. 12217c478bd9Sstevel@tonic-gate */ 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts); 12247c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes); 12257c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_services); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c. 12307c478bd9Sstevel@tonic-gate * It is there because /etc/lib/nss_files.so.1 cannot call 12317c478bd9Sstevel@tonic-gate * routines in libnsl. Care should be taken to keep the two copies 1232*6392794bSMichen Chang * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in 1233*6392794bSMichen Chang * nsswitch/files). 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate int 12367c478bd9Sstevel@tonic-gate __nss2herrno(nss_status_t nsstat) 12377c478bd9Sstevel@tonic-gate { 12387c478bd9Sstevel@tonic-gate switch (nsstat) { 12397c478bd9Sstevel@tonic-gate case NSS_SUCCESS: 12407c478bd9Sstevel@tonic-gate /* no macro-defined success code for h_errno */ 12417c478bd9Sstevel@tonic-gate return (0); 12427c478bd9Sstevel@tonic-gate case NSS_NOTFOUND: 12437c478bd9Sstevel@tonic-gate return (HOST_NOT_FOUND); 12447c478bd9Sstevel@tonic-gate case NSS_TRYAGAIN: 12457c478bd9Sstevel@tonic-gate return (TRY_AGAIN); 12467c478bd9Sstevel@tonic-gate case NSS_UNAVAIL: 12477c478bd9Sstevel@tonic-gate return (NO_RECOVERY); 1248*6392794bSMichen Chang case NSS_NISSERVDNS_TRYAGAIN: 1249*6392794bSMichen Chang return (TRY_AGAIN); 12507c478bd9Sstevel@tonic-gate } 1251*6392794bSMichen Chang /* anything else */ 1252*6392794bSMichen Chang return (NO_RECOVERY); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate nss_status_t 12567c478bd9Sstevel@tonic-gate _herrno2nss(int h_errno) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate switch (h_errno) { 12597c478bd9Sstevel@tonic-gate case 0: 12607c478bd9Sstevel@tonic-gate return (NSS_SUCCESS); 12617c478bd9Sstevel@tonic-gate case TRY_AGAIN: 12627c478bd9Sstevel@tonic-gate return (NSS_TRYAGAIN); 12637c478bd9Sstevel@tonic-gate case NO_RECOVERY: 12647c478bd9Sstevel@tonic-gate case NETDB_INTERNAL: 12657c478bd9Sstevel@tonic-gate return (NSS_UNAVAIL); 12667c478bd9Sstevel@tonic-gate case HOST_NOT_FOUND: 12677c478bd9Sstevel@tonic-gate case NO_DATA: 12687c478bd9Sstevel@tonic-gate default: 12697c478bd9Sstevel@tonic-gate return (NSS_NOTFOUND); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate static int 12747c478bd9Sstevel@tonic-gate __herrno2netdir(int h_errnop) 12757c478bd9Sstevel@tonic-gate { 12767c478bd9Sstevel@tonic-gate switch (h_errnop) { 12777c478bd9Sstevel@tonic-gate case 0: 12787c478bd9Sstevel@tonic-gate return (ND_OK); 12797c478bd9Sstevel@tonic-gate case HOST_NOT_FOUND: 12807c478bd9Sstevel@tonic-gate return (ND_NOHOST); 12817c478bd9Sstevel@tonic-gate case TRY_AGAIN: 12827c478bd9Sstevel@tonic-gate return (ND_TRY_AGAIN); 12837c478bd9Sstevel@tonic-gate case NO_RECOVERY: 12847c478bd9Sstevel@tonic-gate case NETDB_INTERNAL: 12857c478bd9Sstevel@tonic-gate return (ND_NO_RECOVERY); 12867c478bd9Sstevel@tonic-gate case NO_DATA: 12877c478bd9Sstevel@tonic-gate return (ND_NO_DATA); 12887c478bd9Sstevel@tonic-gate default: 12897c478bd9Sstevel@tonic-gate return (ND_NOHOST); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * The _switch_getXXbyYY_r() routines should be static. They used to 12957c478bd9Sstevel@tonic-gate * be exported in SunOS 5.3, and in fact publicised as work-around 12967c478bd9Sstevel@tonic-gate * interfaces for getting CNAME/aliases, and therefore, we preserve 12977c478bd9Sstevel@tonic-gate * their signatures here. Just in case. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate struct hostent * 13017c478bd9Sstevel@tonic-gate _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer, 13027c478bd9Sstevel@tonic-gate int buflen, int *h_errnop) 13037c478bd9Sstevel@tonic-gate { 13047c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 13057c478bd9Sstevel@tonic-gate nss_status_t res; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 13087c478bd9Sstevel@tonic-gate arg.key.name = name; 13097c478bd9Sstevel@tonic-gate arg.stayopen = 0; 13107c478bd9Sstevel@tonic-gate res = nss_search(&db_root_hosts, _nss_initf_hosts, 13117c478bd9Sstevel@tonic-gate NSS_DBOP_HOSTS_BYNAME, &arg); 13127c478bd9Sstevel@tonic-gate arg.status = res; 13137c478bd9Sstevel@tonic-gate *h_errnop = arg.h_errno; 13147c478bd9Sstevel@tonic-gate if (arg.returnval != NULL) 13157c478bd9Sstevel@tonic-gate order_haddrlist_af(result->h_addrtype, result->h_addr_list); 13167c478bd9Sstevel@tonic-gate return ((struct hostent *)NSS_XbyY_FINI(&arg)); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate struct hostent * 13207c478bd9Sstevel@tonic-gate _switch_getipnodebyname_r(const char *name, struct hostent *result, 13217c478bd9Sstevel@tonic-gate char *buffer, int buflen, int af_family, int flags, int *h_errnop) 13227c478bd9Sstevel@tonic-gate { 13237c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 13247c478bd9Sstevel@tonic-gate nss_status_t res; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 13277c478bd9Sstevel@tonic-gate arg.key.ipnode.name = name; 13287c478bd9Sstevel@tonic-gate arg.key.ipnode.af_family = af_family; 13297c478bd9Sstevel@tonic-gate arg.key.ipnode.flags = flags; 13307c478bd9Sstevel@tonic-gate arg.stayopen = 0; 13317c478bd9Sstevel@tonic-gate res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 13327c478bd9Sstevel@tonic-gate NSS_DBOP_IPNODES_BYNAME, &arg); 13337c478bd9Sstevel@tonic-gate arg.status = res; 13347c478bd9Sstevel@tonic-gate *h_errnop = arg.h_errno; 13357c478bd9Sstevel@tonic-gate if (arg.returnval != NULL) 13367c478bd9Sstevel@tonic-gate order_haddrlist_af(result->h_addrtype, result->h_addr_list); 13377c478bd9Sstevel@tonic-gate return ((struct hostent *)NSS_XbyY_FINI(&arg)); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate struct hostent * 13417c478bd9Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type, 13427c478bd9Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 13437c478bd9Sstevel@tonic-gate { 13447c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 13457c478bd9Sstevel@tonic-gate nss_status_t res; 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 13487c478bd9Sstevel@tonic-gate arg.key.hostaddr.addr = addr; 13497c478bd9Sstevel@tonic-gate arg.key.hostaddr.len = len; 13507c478bd9Sstevel@tonic-gate arg.key.hostaddr.type = type; 13517c478bd9Sstevel@tonic-gate arg.stayopen = 0; 13527c478bd9Sstevel@tonic-gate res = nss_search(&db_root_hosts, _nss_initf_hosts, 13537c478bd9Sstevel@tonic-gate NSS_DBOP_HOSTS_BYADDR, &arg); 13547c478bd9Sstevel@tonic-gate arg.status = res; 13557c478bd9Sstevel@tonic-gate *h_errnop = arg.h_errno; 13567c478bd9Sstevel@tonic-gate return (struct hostent *)NSS_XbyY_FINI(&arg); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate struct hostent * 13607c478bd9Sstevel@tonic-gate _switch_getipnodebyaddr_r(const char *addr, int len, int type, 13617c478bd9Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 13627c478bd9Sstevel@tonic-gate { 13637c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 13647c478bd9Sstevel@tonic-gate nss_status_t res; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 13677c478bd9Sstevel@tonic-gate arg.key.hostaddr.addr = addr; 13687c478bd9Sstevel@tonic-gate arg.key.hostaddr.len = len; 13697c478bd9Sstevel@tonic-gate arg.key.hostaddr.type = type; 13707c478bd9Sstevel@tonic-gate arg.stayopen = 0; 13717c478bd9Sstevel@tonic-gate res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 13727c478bd9Sstevel@tonic-gate NSS_DBOP_IPNODES_BYADDR, &arg); 13737c478bd9Sstevel@tonic-gate arg.status = res; 13747c478bd9Sstevel@tonic-gate *h_errnop = arg.h_errno; 13757c478bd9Sstevel@tonic-gate return (struct hostent *)NSS_XbyY_FINI(&arg); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate static void 13797c478bd9Sstevel@tonic-gate _nss_initf_services(nss_db_params_t *p) 13807c478bd9Sstevel@tonic-gate { 13817c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_SERVICES; 13827c478bd9Sstevel@tonic-gate p->default_config = NSS_DEFCONF_SERVICES; 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate struct servent * 13867c478bd9Sstevel@tonic-gate _switch_getservbyname_r(const char *name, const char *proto, 13877c478bd9Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 13907c478bd9Sstevel@tonic-gate nss_status_t res; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 13937c478bd9Sstevel@tonic-gate arg.key.serv.serv.name = name; 13947c478bd9Sstevel@tonic-gate arg.key.serv.proto = proto; 13957c478bd9Sstevel@tonic-gate arg.stayopen = 0; 13967c478bd9Sstevel@tonic-gate res = nss_search(&db_root_services, _nss_initf_services, 13977c478bd9Sstevel@tonic-gate NSS_DBOP_SERVICES_BYNAME, &arg); 13987c478bd9Sstevel@tonic-gate arg.status = res; 13997c478bd9Sstevel@tonic-gate return ((struct servent *)NSS_XbyY_FINI(&arg)); 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate struct servent * 14037c478bd9Sstevel@tonic-gate _switch_getservbyport_r(int port, const char *proto, struct servent *result, 14047c478bd9Sstevel@tonic-gate char *buffer, int buflen) 14057c478bd9Sstevel@tonic-gate { 14067c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 14077c478bd9Sstevel@tonic-gate nss_status_t res; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 14107c478bd9Sstevel@tonic-gate arg.key.serv.serv.port = port; 14117c478bd9Sstevel@tonic-gate arg.key.serv.proto = proto; 14127c478bd9Sstevel@tonic-gate arg.stayopen = 0; 14137c478bd9Sstevel@tonic-gate res = nss_search(&db_root_services, _nss_initf_services, 14147c478bd9Sstevel@tonic-gate NSS_DBOP_SERVICES_BYPORT, &arg); 14157c478bd9Sstevel@tonic-gate arg.status = res; 14167c478bd9Sstevel@tonic-gate return ((struct servent *)NSS_XbyY_FINI(&arg)); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * Return values: 0 = success, 1 = parse error, 2 = erange ... 14227c478bd9Sstevel@tonic-gate * The structure pointer passed in is a structure in the caller's space 14237c478bd9Sstevel@tonic-gate * wherein the field pointers would be set to areas in the buffer if 14247c478bd9Sstevel@tonic-gate * need be. instring and buffer should be separate areas. 14257c478bd9Sstevel@tonic-gate * 14267c478bd9Sstevel@tonic-gate * Defined here because we need it and we (libnsl) cannot have a dependency 14277c478bd9Sstevel@tonic-gate * on libsocket (however, libsocket always depends on libnsl). 14287c478bd9Sstevel@tonic-gate */ 14297c478bd9Sstevel@tonic-gate int 14307c478bd9Sstevel@tonic-gate str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 14317c478bd9Sstevel@tonic-gate { 14327c478bd9Sstevel@tonic-gate struct servent *serv = (struct servent *)ent; 14337c478bd9Sstevel@tonic-gate const char *p, *fieldstart, *limit, *namestart; 14347c478bd9Sstevel@tonic-gate ssize_t fieldlen, namelen = 0; 14357c478bd9Sstevel@tonic-gate char numbuf[12]; 14367c478bd9Sstevel@tonic-gate char *numend; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if ((instr >= buffer && (buffer + buflen) > instr) || 14397c478bd9Sstevel@tonic-gate (buffer >= instr && (instr + lenstr) > buffer)) { 14407c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate p = instr; 14447c478bd9Sstevel@tonic-gate limit = p + lenstr; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate while (p < limit && isspace(*p)) { 14477c478bd9Sstevel@tonic-gate p++; 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate namestart = p; 14507c478bd9Sstevel@tonic-gate while (p < limit && !isspace(*p)) { 14517c478bd9Sstevel@tonic-gate p++; /* Skip over the canonical name */ 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate namelen = p - namestart; 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate if (buflen <= namelen) { /* not enough buffer */ 14567c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate (void) memcpy(buffer, namestart, namelen); 14597c478bd9Sstevel@tonic-gate buffer[namelen] = '\0'; 14607c478bd9Sstevel@tonic-gate serv->s_name = buffer; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate while (p < limit && isspace(*p)) { 14637c478bd9Sstevel@tonic-gate p++; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate fieldstart = p; 14677c478bd9Sstevel@tonic-gate do { 14687c478bd9Sstevel@tonic-gate if (p > limit || isspace(*p)) { 14697c478bd9Sstevel@tonic-gate /* Syntax error -- no port/proto */ 14707c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 14717c478bd9Sstevel@tonic-gate } 1472*6392794bSMichen Chang } while (*p++ != '/'); 14737c478bd9Sstevel@tonic-gate fieldlen = p - fieldstart - 1; 14747c478bd9Sstevel@tonic-gate if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) { 14757c478bd9Sstevel@tonic-gate /* Syntax error -- supposed number is empty or too long */ 14767c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate (void) memcpy(numbuf, fieldstart, fieldlen); 14797c478bd9Sstevel@tonic-gate numbuf[fieldlen] = '\0'; 14807c478bd9Sstevel@tonic-gate serv->s_port = htons((int)strtol(numbuf, &numend, 10)); 14817c478bd9Sstevel@tonic-gate if (*numend != '\0') { 14827c478bd9Sstevel@tonic-gate /* Syntax error -- port number isn't a number */ 14837c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate fieldstart = p; 14877c478bd9Sstevel@tonic-gate while (p < limit && !isspace(*p)) { 14887c478bd9Sstevel@tonic-gate p++; /* Scan the protocol name */ 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate fieldlen = p - fieldstart + 1; /* Include '\0' this time */ 14917c478bd9Sstevel@tonic-gate if (fieldlen > buflen - namelen - 1) { 14927c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate serv->s_proto = buffer + namelen + 1; 14957c478bd9Sstevel@tonic-gate (void) memcpy(serv->s_proto, fieldstart, fieldlen - 1); 14967c478bd9Sstevel@tonic-gate serv->s_proto[fieldlen - 1] = '\0'; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate while (p < limit && isspace(*p)) { 14997c478bd9Sstevel@tonic-gate p++; 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate /* 15027c478bd9Sstevel@tonic-gate * Although nss_files_XY_all calls us with # stripped, 15037c478bd9Sstevel@tonic-gate * we should be able to deal with it here in order to 15047c478bd9Sstevel@tonic-gate * be more useful. 15057c478bd9Sstevel@tonic-gate */ 15067c478bd9Sstevel@tonic-gate if (p >= limit || *p == '#') { /* no aliases, no problem */ 15077c478bd9Sstevel@tonic-gate char **ptr; 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen, 15107c478bd9Sstevel@tonic-gate sizeof (char *)); 15117c478bd9Sstevel@tonic-gate if ((char *)ptr >= buffer + buflen) { 15127c478bd9Sstevel@tonic-gate /* hope they don't try to peek in */ 15137c478bd9Sstevel@tonic-gate serv->s_aliases = 0; 15147c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 15157c478bd9Sstevel@tonic-gate } else { 15167c478bd9Sstevel@tonic-gate *ptr = 0; 15177c478bd9Sstevel@tonic-gate serv->s_aliases = ptr; 15187c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)), 15227c478bd9Sstevel@tonic-gate buffer + namelen + 1 + fieldlen, 15237c478bd9Sstevel@tonic-gate (int)(buflen - namelen - 1 - fieldlen)); 15247c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * Part III: All `n sundry routines that are useful only in this 15297c478bd9Sstevel@tonic-gate * module. In the interest of keeping this source file shorter, 15307c478bd9Sstevel@tonic-gate * we would create them a new module only if the linker allowed 15317c478bd9Sstevel@tonic-gate * "library-static" functions. 15327c478bd9Sstevel@tonic-gate * 15337c478bd9Sstevel@tonic-gate * Routines to order addresses based on local interfaces and netmasks, 15347c478bd9Sstevel@tonic-gate * to get and check reserved ports, and to get broadcast nets. 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate union __v4v6addr { 15387c478bd9Sstevel@tonic-gate struct in6_addr in6; 15397c478bd9Sstevel@tonic-gate struct in_addr in4; 15407c478bd9Sstevel@tonic-gate }; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate struct __ifaddr { 15437c478bd9Sstevel@tonic-gate sa_family_t af; 15447c478bd9Sstevel@tonic-gate union __v4v6addr addr; 15457c478bd9Sstevel@tonic-gate union __v4v6addr mask; 15467c478bd9Sstevel@tonic-gate }; 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate struct ifinfo { 15497c478bd9Sstevel@tonic-gate int count; 15507c478bd9Sstevel@tonic-gate struct __ifaddr *addresses; 15517c478bd9Sstevel@tonic-gate }; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t; 15547c478bd9Sstevel@tonic-gate #define ADDR_NUMCLASSES 2 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate typedef enum {IF_ADDR, IF_MASK} __ifaddr_type; 15577c478bd9Sstevel@tonic-gate static int __inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type, 15587c478bd9Sstevel@tonic-gate void *); 15597c478bd9Sstevel@tonic-gate int __inet_address_is_local_af(void *, sa_family_t, void *); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate #define ifaf(index) (localinfo->addresses[index].af) 15627c478bd9Sstevel@tonic-gate #define ifaddr4(index) (localinfo->addresses[index].addr.in4) 15637c478bd9Sstevel@tonic-gate #define ifaddr6(index) (localinfo->addresses[index].addr.in6) 15647c478bd9Sstevel@tonic-gate #define ifmask4(index) (localinfo->addresses[index].mask.in4) 15657c478bd9Sstevel@tonic-gate #define ifmask6(index) (localinfo->addresses[index].mask.in6) 15667c478bd9Sstevel@tonic-gate #define ifinfosize(n) (sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr)) 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate #define lifraddrp(lifr) ((lifr.lifr_addr.ss_family == AF_INET6) ? \ 15697c478bd9Sstevel@tonic-gate (void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \ 15707c478bd9Sstevel@tonic-gate (void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr) 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate #define ifassign(lifr, index, type) \ 15737c478bd9Sstevel@tonic-gate __inet_ifassign(lifr.lifr_addr.ss_family, \ 15747c478bd9Sstevel@tonic-gate &localinfo->addresses[index], type, \ 15757c478bd9Sstevel@tonic-gate lifraddrp(lifr)) 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 15787c478bd9Sstevel@tonic-gate * The number of nanoseconds the order_haddrlist_inet() function waits 15797c478bd9Sstevel@tonic-gate * to retreive IP interface information. The default is five minutes. 15807c478bd9Sstevel@tonic-gate */ 15817c478bd9Sstevel@tonic-gate #define IFINFOTIMEOUT ((hrtime_t)300 * NANOSEC) 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate /* 15847c478bd9Sstevel@tonic-gate * Sort the addresses in haddrlist. Since the sorting algorithms are 15857c478bd9Sstevel@tonic-gate * address-family specific, the work is done in the address-family 15867c478bd9Sstevel@tonic-gate * specific order_haddrlist_<family> functions. 15877c478bd9Sstevel@tonic-gate * 15887c478bd9Sstevel@tonic-gate * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE 15897c478bd9Sstevel@tonic-gate * in the configuration file /etc/default/nss. This is useful in case 15907c478bd9Sstevel@tonic-gate * the order of addresses returned by the nameserver needs to be 15917c478bd9Sstevel@tonic-gate * maintained. (DNS round robin feature is one example) 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate void 15947c478bd9Sstevel@tonic-gate order_haddrlist_af(sa_family_t af, char **haddrlist) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate size_t addrcount; 15977c478bd9Sstevel@tonic-gate char **addrptr; 15987c478bd9Sstevel@tonic-gate static boolean_t checksortcfg = B_TRUE; 15997c478bd9Sstevel@tonic-gate static boolean_t nosort = B_FALSE; 16007c478bd9Sstevel@tonic-gate static mutex_t checksortcfg_lock = DEFAULTMUTEX; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate if (haddrlist == NULL) 16037c478bd9Sstevel@tonic-gate return; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * Check if SORT_ADDRS is set to NO or FALSE in the configuration 16077c478bd9Sstevel@tonic-gate * file. We do not have to sort addresses in that case. 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate (void) mutex_lock(&checksortcfg_lock); 16107c478bd9Sstevel@tonic-gate if (checksortcfg == B_TRUE) { 16117c478bd9Sstevel@tonic-gate checksortcfg = B_FALSE; 16127c478bd9Sstevel@tonic-gate nosort = _read_nsw_file(); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate (void) mutex_unlock(&checksortcfg_lock); 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if (nosort) 16177c478bd9Sstevel@tonic-gate return; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate /* Count the addresses to sort */ 16207c478bd9Sstevel@tonic-gate addrcount = 0; 16217c478bd9Sstevel@tonic-gate for (addrptr = haddrlist; *addrptr != NULL; addrptr++) 16227c478bd9Sstevel@tonic-gate addrcount++; 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * If there's only one address or no addresses to sort, then 16267c478bd9Sstevel@tonic-gate * there's nothing for us to do. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate if (addrcount <= 1) 16297c478bd9Sstevel@tonic-gate return; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate /* Call the address-family specific sorting functions. */ 16327c478bd9Sstevel@tonic-gate switch (af) { 16337c478bd9Sstevel@tonic-gate case AF_INET: 16347c478bd9Sstevel@tonic-gate order_haddrlist_inet(haddrlist, addrcount); 16357c478bd9Sstevel@tonic-gate break; 16367c478bd9Sstevel@tonic-gate case AF_INET6: 16377c478bd9Sstevel@tonic-gate order_haddrlist_inet6(haddrlist, addrcount); 16387c478bd9Sstevel@tonic-gate break; 16397c478bd9Sstevel@tonic-gate default: 16407c478bd9Sstevel@tonic-gate break; 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * Move any local (on-link) addresses toward the beginning of haddrlist. 16467c478bd9Sstevel@tonic-gate * The order within these two classes is preserved. 16477c478bd9Sstevel@tonic-gate * 16487c478bd9Sstevel@tonic-gate * The interface list is retrieved no more often than every 16497c478bd9Sstevel@tonic-gate * IFINFOTIMEOUT nanoseconds. Access to the interface list is 16507c478bd9Sstevel@tonic-gate * protected by an RW lock. 16517c478bd9Sstevel@tonic-gate * 16527c478bd9Sstevel@tonic-gate * If this function encounters an error, haddrlist is unaltered. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate static void 16557c478bd9Sstevel@tonic-gate order_haddrlist_inet(char **haddrlist, size_t addrcount) 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate static struct ifinfo *localinfo = NULL; 16587c478bd9Sstevel@tonic-gate static hrtime_t then = 0; /* the last time localinfo was updated */ 16597c478bd9Sstevel@tonic-gate hrtime_t now; 16607c478bd9Sstevel@tonic-gate static rwlock_t localinfo_lock = DEFAULTRWLOCK; 16617c478bd9Sstevel@tonic-gate uint8_t *sortbuf; 16627c478bd9Sstevel@tonic-gate size_t sortbuf_size; 16637c478bd9Sstevel@tonic-gate struct in_addr **inaddrlist = (struct in_addr **)haddrlist; 16647c478bd9Sstevel@tonic-gate struct in_addr **sorted; 16657c478bd9Sstevel@tonic-gate struct in_addr **classnext[ADDR_NUMCLASSES]; 16667c478bd9Sstevel@tonic-gate uint_t classcount[ADDR_NUMCLASSES]; 16677c478bd9Sstevel@tonic-gate addr_class_t *sortclass; 16687c478bd9Sstevel@tonic-gate int i; 16697c478bd9Sstevel@tonic-gate int rc; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * The classes in the sortclass array correspond to the class 16747c478bd9Sstevel@tonic-gate * of the address in the haddrlist list of the same index. 16757c478bd9Sstevel@tonic-gate * The classes are: 16767c478bd9Sstevel@tonic-gate * 16777c478bd9Sstevel@tonic-gate * ADDR_ONLINK on-link address 16787c478bd9Sstevel@tonic-gate * ADDR_OFFLINK off-link address 16797c478bd9Sstevel@tonic-gate */ 16807c478bd9Sstevel@tonic-gate sortbuf_size = addrcount * 16817c478bd9Sstevel@tonic-gate (sizeof (struct in_addr *) + sizeof (addr_class_t)); 16827c478bd9Sstevel@tonic-gate if ((sortbuf = malloc(sortbuf_size)) == NULL) 16837c478bd9Sstevel@tonic-gate return; 168461961e0fSrobinson /* LINTED pointer cast */ 16857c478bd9Sstevel@tonic-gate sorted = (struct in_addr **)sortbuf; 168661961e0fSrobinson /* LINTED pointer cast */ 16877c478bd9Sstevel@tonic-gate sortclass = (addr_class_t *)(sortbuf + 16887c478bd9Sstevel@tonic-gate (addrcount * sizeof (struct in_addr *))); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate /* 16917c478bd9Sstevel@tonic-gate * Get a read lock, and check if the interface information 16927c478bd9Sstevel@tonic-gate * is too old. 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate (void) rw_rdlock(&localinfo_lock); 16957c478bd9Sstevel@tonic-gate now = gethrtime(); 16967c478bd9Sstevel@tonic-gate if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 16977c478bd9Sstevel@tonic-gate /* Need to update I/F info. Upgrade to write lock. */ 16987c478bd9Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 16997c478bd9Sstevel@tonic-gate (void) rw_wrlock(&localinfo_lock); 17007c478bd9Sstevel@tonic-gate /* 17017c478bd9Sstevel@tonic-gate * Another thread might have updated "then" between 17027c478bd9Sstevel@tonic-gate * the rw_unlock() and rw_wrlock() calls above, so 17037c478bd9Sstevel@tonic-gate * re-check the timeout. 17047c478bd9Sstevel@tonic-gate */ 17057c478bd9Sstevel@tonic-gate if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 17067c478bd9Sstevel@tonic-gate if (localinfo != NULL) 17077c478bd9Sstevel@tonic-gate free(localinfo); 17087c478bd9Sstevel@tonic-gate if ((localinfo = get_local_info()) == NULL) { 17097c478bd9Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 17107c478bd9Sstevel@tonic-gate free(sortbuf); 17117c478bd9Sstevel@tonic-gate return; 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate then = now; 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate /* Downgrade to read lock */ 17167c478bd9Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 17177c478bd9Sstevel@tonic-gate (void) rw_rdlock(&localinfo_lock); 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * Another thread may have updated the I/F info, 17207c478bd9Sstevel@tonic-gate * so verify that the 'localinfo' pointer still 17217c478bd9Sstevel@tonic-gate * is non-NULL. 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate if (localinfo == NULL) { 17247c478bd9Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 17257c478bd9Sstevel@tonic-gate free(sortbuf); 17267c478bd9Sstevel@tonic-gate return; 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate /* 17317c478bd9Sstevel@tonic-gate * Classify the addresses. We also maintain the classcount 17327c478bd9Sstevel@tonic-gate * array to keep track of the number of addresses in each 17337c478bd9Sstevel@tonic-gate * class. 17347c478bd9Sstevel@tonic-gate */ 173561961e0fSrobinson (void) memset(classcount, 0, sizeof (classcount)); 17367c478bd9Sstevel@tonic-gate for (i = 0; i < addrcount; i++) { 17377c478bd9Sstevel@tonic-gate if (__inet_address_is_local_af(localinfo, AF_INET, 17387c478bd9Sstevel@tonic-gate inaddrlist[i])) 17397c478bd9Sstevel@tonic-gate sortclass[i] = ADDR_ONLINK; 17407c478bd9Sstevel@tonic-gate else 17417c478bd9Sstevel@tonic-gate sortclass[i] = ADDR_OFFLINK; 17427c478bd9Sstevel@tonic-gate classcount[sortclass[i]]++; 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate /* Don't need the interface list anymore in this call */ 17467c478bd9Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate /* 17497c478bd9Sstevel@tonic-gate * Each element in the classnext array points to the next 17507c478bd9Sstevel@tonic-gate * element for that class in the sorted address list. 'rc' is 17517c478bd9Sstevel@tonic-gate * the running count of elements as we sum the class 17527c478bd9Sstevel@tonic-gate * sub-totals. 17537c478bd9Sstevel@tonic-gate */ 17547c478bd9Sstevel@tonic-gate for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) { 17557c478bd9Sstevel@tonic-gate classnext[i] = &sorted[rc]; 17567c478bd9Sstevel@tonic-gate rc += classcount[i]; 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate /* Now for the actual rearrangement of the addresses */ 17607c478bd9Sstevel@tonic-gate for (i = 0; i < addrcount; i++) { 17617c478bd9Sstevel@tonic-gate *(classnext[sortclass[i]]) = inaddrlist[i]; 17627c478bd9Sstevel@tonic-gate classnext[sortclass[i]]++; 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* Copy the sorted list to inaddrlist */ 17667c478bd9Sstevel@tonic-gate (void) memcpy(inaddrlist, sorted, 17677c478bd9Sstevel@tonic-gate addrcount * sizeof (struct in_addr *)); 17687c478bd9Sstevel@tonic-gate free(sortbuf); 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate /* 17727c478bd9Sstevel@tonic-gate * This function implements the IPv6 Default Address Selection's 17737c478bd9Sstevel@tonic-gate * destination address ordering mechanism. The algorithm is described 17747c478bd9Sstevel@tonic-gate * in getaddrinfo(3SOCKET). 17757c478bd9Sstevel@tonic-gate */ 17767c478bd9Sstevel@tonic-gate static void 17777c478bd9Sstevel@tonic-gate order_haddrlist_inet6(char **haddrlist, size_t addrcount) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate struct dstinforeq *dinfo, *dinfoptr; 17807c478bd9Sstevel@tonic-gate struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist; 17817c478bd9Sstevel@tonic-gate struct in6_addr **in6addr; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL) 17847c478bd9Sstevel@tonic-gate return; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate /* Initialize the dstinfo array we'll use for SIOCGDSTINFO */ 17877c478bd9Sstevel@tonic-gate dinfoptr = dinfo; 17887c478bd9Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 17897c478bd9Sstevel@tonic-gate dinfoptr->dir_daddr = **in6addr; 17907c478bd9Sstevel@tonic-gate dinfoptr++; 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo, 17947c478bd9Sstevel@tonic-gate addrcount * sizeof (struct dstinforeq)) < 0) { 17957c478bd9Sstevel@tonic-gate free(dinfo); 17967c478bd9Sstevel@tonic-gate return; 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate /* Sort the dinfo array */ 18007c478bd9Sstevel@tonic-gate qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp); 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* Copy the addresses back into in6addrlist */ 18037c478bd9Sstevel@tonic-gate dinfoptr = dinfo; 18047c478bd9Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 18057c478bd9Sstevel@tonic-gate **in6addr = dinfoptr->dir_daddr; 18067c478bd9Sstevel@tonic-gate dinfoptr++; 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate free(dinfo); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate /* 18137c478bd9Sstevel@tonic-gate * Determine number of leading bits that are common between two addresses. 18147c478bd9Sstevel@tonic-gate * Only consider bits which fall within the prefix length plen. 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate static uint_t 18177c478bd9Sstevel@tonic-gate ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2) 18187c478bd9Sstevel@tonic-gate { 18197c478bd9Sstevel@tonic-gate uint_t bits; 18207c478bd9Sstevel@tonic-gate uint_t i; 18217c478bd9Sstevel@tonic-gate uint32_t diff; /* Bits that differ */ 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 18247c478bd9Sstevel@tonic-gate if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i]) 18257c478bd9Sstevel@tonic-gate break; 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate bits = i * 32; 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate if (bits == IPV6_ABITS) 18307c478bd9Sstevel@tonic-gate return (IPV6_ABITS); 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * Find number of leading common bits in the word which might 18347c478bd9Sstevel@tonic-gate * have some common bits by searching for the first one from the left 18357c478bd9Sstevel@tonic-gate * in the xor of the two addresses. 18367c478bd9Sstevel@tonic-gate */ 18377c478bd9Sstevel@tonic-gate diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]); 18387c478bd9Sstevel@tonic-gate if (diff & 0xffff0000ul) 18397c478bd9Sstevel@tonic-gate diff >>= 16; 18407c478bd9Sstevel@tonic-gate else 18417c478bd9Sstevel@tonic-gate bits += 16; 18427c478bd9Sstevel@tonic-gate if (diff & 0xff00) 18437c478bd9Sstevel@tonic-gate diff >>= 8; 18447c478bd9Sstevel@tonic-gate else 18457c478bd9Sstevel@tonic-gate bits += 8; 18467c478bd9Sstevel@tonic-gate if (diff & 0xf0) 18477c478bd9Sstevel@tonic-gate diff >>= 4; 18487c478bd9Sstevel@tonic-gate else 18497c478bd9Sstevel@tonic-gate bits += 4; 18507c478bd9Sstevel@tonic-gate if (diff & 0xc) 18517c478bd9Sstevel@tonic-gate diff >>= 2; 18527c478bd9Sstevel@tonic-gate else 18537c478bd9Sstevel@tonic-gate bits += 2; 18547c478bd9Sstevel@tonic-gate if (!(diff & 2)) 18557c478bd9Sstevel@tonic-gate bits++; 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate /* 18587c478bd9Sstevel@tonic-gate * We don't need to shift and check for the last bit. The 18597c478bd9Sstevel@tonic-gate * check for IPV6_ABITS above would have caught that. 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate return (bits); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate /* 18677c478bd9Sstevel@tonic-gate * The following group of functions named rule_*() are individual 18687c478bd9Sstevel@tonic-gate * sorting rules for the AF_INET6 address sorting algorithm. The 18697c478bd9Sstevel@tonic-gate * functions compare two addresses (described by two dstinforeq 18707c478bd9Sstevel@tonic-gate * structures), and determines if one is "greater" than the other, or 18717c478bd9Sstevel@tonic-gate * if the two are equal according to that rule. 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate typedef int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *); 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate /* 18767c478bd9Sstevel@tonic-gate * These values of these constants are no accident. Since qsort() 18777c478bd9Sstevel@tonic-gate * implements the AF_INET6 address sorting, the comparison function 18787c478bd9Sstevel@tonic-gate * must return an integer less than, equal to, or greater than zero to 18797c478bd9Sstevel@tonic-gate * indicate if the first address is considered "less than", "equal 18807c478bd9Sstevel@tonic-gate * to", or "greater than" the second one. Since we want the best 18817c478bd9Sstevel@tonic-gate * addresses first on the list, "less than" is considered preferrable. 18827c478bd9Sstevel@tonic-gate */ 18837c478bd9Sstevel@tonic-gate #define RULE_PREFER_DA -1 18847c478bd9Sstevel@tonic-gate #define RULE_PREFER_DB 1 18857c478bd9Sstevel@tonic-gate #define RULE_EQUAL 0 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate /* Prefer the addresses that is reachable. */ 18887c478bd9Sstevel@tonic-gate static int 18897c478bd9Sstevel@tonic-gate rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db) 18907c478bd9Sstevel@tonic-gate { 18917c478bd9Sstevel@tonic-gate if (da->dir_dreachable == db->dir_dreachable) 18927c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 18937c478bd9Sstevel@tonic-gate if (da->dir_dreachable) 18947c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 18957c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate /* Prefer the address whose scope matches that of its source address. */ 18997c478bd9Sstevel@tonic-gate static int 19007c478bd9Sstevel@tonic-gate rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db) 19017c478bd9Sstevel@tonic-gate { 19027c478bd9Sstevel@tonic-gate boolean_t da_scope_match, db_scope_match; 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate da_scope_match = da->dir_dscope == da->dir_sscope; 19057c478bd9Sstevel@tonic-gate db_scope_match = db->dir_dscope == db->dir_sscope; 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate if (da_scope_match == db_scope_match) 19087c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19097c478bd9Sstevel@tonic-gate if (da_scope_match) 19107c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19117c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate /* Avoid the address with the link local source address. */ 19157c478bd9Sstevel@tonic-gate static int 19167c478bd9Sstevel@tonic-gate rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db) 19177c478bd9Sstevel@tonic-gate { 19187c478bd9Sstevel@tonic-gate if (da->dir_sscope == IP6_SCOPE_LINKLOCAL && 19197c478bd9Sstevel@tonic-gate da->dir_dscope != IP6_SCOPE_LINKLOCAL && 19207c478bd9Sstevel@tonic-gate db->dir_sscope != IP6_SCOPE_LINKLOCAL) 19217c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19227c478bd9Sstevel@tonic-gate if (db->dir_sscope == IP6_SCOPE_LINKLOCAL && 19237c478bd9Sstevel@tonic-gate db->dir_dscope != IP6_SCOPE_LINKLOCAL && 19247c478bd9Sstevel@tonic-gate da->dir_sscope != IP6_SCOPE_LINKLOCAL) 19257c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19267c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate /* Prefer the address whose source address isn't deprecated. */ 19307c478bd9Sstevel@tonic-gate static int 19317c478bd9Sstevel@tonic-gate rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db) 19327c478bd9Sstevel@tonic-gate { 19337c478bd9Sstevel@tonic-gate if (da->dir_sdeprecated == db->dir_sdeprecated) 19347c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19357c478bd9Sstevel@tonic-gate if (db->dir_sdeprecated) 19367c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19377c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate /* Prefer the address whose label matches that of its source address. */ 19417c478bd9Sstevel@tonic-gate static int 19427c478bd9Sstevel@tonic-gate rule_label(const struct dstinforeq *da, const struct dstinforeq *db) 19437c478bd9Sstevel@tonic-gate { 19447c478bd9Sstevel@tonic-gate if (da->dir_labelmatch == db->dir_labelmatch) 19457c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19467c478bd9Sstevel@tonic-gate if (da->dir_labelmatch) 19477c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19487c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate /* Prefer the address with the higher precedence. */ 19527c478bd9Sstevel@tonic-gate static int 19537c478bd9Sstevel@tonic-gate rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db) 19547c478bd9Sstevel@tonic-gate { 19557c478bd9Sstevel@tonic-gate if (da->dir_precedence == db->dir_precedence) 19567c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19577c478bd9Sstevel@tonic-gate if (da->dir_precedence > db->dir_precedence) 19587c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19597c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate /* Prefer the address whose output interface isn't an IP tunnel */ 19637c478bd9Sstevel@tonic-gate static int 19647c478bd9Sstevel@tonic-gate rule_native(const struct dstinforeq *da, const struct dstinforeq *db) 19657c478bd9Sstevel@tonic-gate { 19667c478bd9Sstevel@tonic-gate boolean_t isatun, isbtun; 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate /* Get the common case out of the way early */ 19697c478bd9Sstevel@tonic-gate if (da->dir_dmactype == db->dir_dmactype) 19707c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6; 19737c478bd9Sstevel@tonic-gate isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6; 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate if (isatun == isbtun) 19767c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19777c478bd9Sstevel@tonic-gate if (isbtun) 19787c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19797c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate /* Prefer the address with the smaller scope. */ 19837c478bd9Sstevel@tonic-gate static int 19847c478bd9Sstevel@tonic-gate rule_scope(const struct dstinforeq *da, const struct dstinforeq *db) 19857c478bd9Sstevel@tonic-gate { 19867c478bd9Sstevel@tonic-gate if (da->dir_dscope == db->dir_dscope) 19877c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 19887c478bd9Sstevel@tonic-gate if (da->dir_dscope < db->dir_dscope) 19897c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 19907c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 19917c478bd9Sstevel@tonic-gate } 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * Prefer the address that has the most leading bits in common with its 19957c478bd9Sstevel@tonic-gate * source address. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate static int 19987c478bd9Sstevel@tonic-gate rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db) 19997c478bd9Sstevel@tonic-gate { 20007c478bd9Sstevel@tonic-gate uint_t da_commonbits, db_commonbits; 20017c478bd9Sstevel@tonic-gate boolean_t da_isipv4, db_isipv4; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr); 20047c478bd9Sstevel@tonic-gate db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * At this point, the order doesn't matter if the two addresses 20087c478bd9Sstevel@tonic-gate * aren't of the same address family. 20097c478bd9Sstevel@tonic-gate */ 20107c478bd9Sstevel@tonic-gate if (da_isipv4 != db_isipv4) 20117c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr); 20147c478bd9Sstevel@tonic-gate db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr); 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate if (da_commonbits > db_commonbits) 20177c478bd9Sstevel@tonic-gate return (RULE_PREFER_DA); 20187c478bd9Sstevel@tonic-gate if (da_commonbits < db_commonbits) 20197c478bd9Sstevel@tonic-gate return (RULE_PREFER_DB); 20207c478bd9Sstevel@tonic-gate return (RULE_EQUAL); 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate /* 20247c478bd9Sstevel@tonic-gate * This is the function passed to qsort() that does the AF_INET6 20257c478bd9Sstevel@tonic-gate * address comparisons. It compares two addresses using a list of 20267c478bd9Sstevel@tonic-gate * rules. The rules are applied in order until one prefers one 20277c478bd9Sstevel@tonic-gate * address over the other. 20287c478bd9Sstevel@tonic-gate */ 20297c478bd9Sstevel@tonic-gate static int 20307c478bd9Sstevel@tonic-gate dstcmp(const void *da, const void *db) 20317c478bd9Sstevel@tonic-gate { 20327c478bd9Sstevel@tonic-gate int index, result; 20337c478bd9Sstevel@tonic-gate rulef_t rules[] = { 2034*6392794bSMichen Chang rule_reachable, 2035*6392794bSMichen Chang rule_matchscope, 2036*6392794bSMichen Chang rule_avoidlinklocal, 2037*6392794bSMichen Chang rule_deprecated, 2038*6392794bSMichen Chang rule_label, 2039*6392794bSMichen Chang rule_precedence, 2040*6392794bSMichen Chang rule_native, 2041*6392794bSMichen Chang rule_scope, 2042*6392794bSMichen Chang rule_prefix, 2043*6392794bSMichen Chang NULL 20447c478bd9Sstevel@tonic-gate }; 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate result = 0; 20477c478bd9Sstevel@tonic-gate for (index = 0; rules[index] != NULL; index++) { 20487c478bd9Sstevel@tonic-gate result = (rules[index])(da, db); 20497c478bd9Sstevel@tonic-gate if (result != RULE_EQUAL) 20507c478bd9Sstevel@tonic-gate break; 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate return (result); 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate /* 20577c478bd9Sstevel@tonic-gate * Given haddrlist and a port number, mallocs and populates a new 20587c478bd9Sstevel@tonic-gate * nd_addrlist. The new nd_addrlist maintains the order of the addresses 20597c478bd9Sstevel@tonic-gate * in haddrlist, which have already been sorted by order_haddrlist_inet() 20607c478bd9Sstevel@tonic-gate * or order_haddrlist_inet6(). For IPv6 this function filters out 20617c478bd9Sstevel@tonic-gate * IPv4-mapped IPv6 addresses. 20627c478bd9Sstevel@tonic-gate */ 20637c478bd9Sstevel@tonic-gate int 20647c478bd9Sstevel@tonic-gate hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist) 20657c478bd9Sstevel@tonic-gate { 20667c478bd9Sstevel@tonic-gate struct nd_addrlist *result; 20677c478bd9Sstevel@tonic-gate int num; 20687c478bd9Sstevel@tonic-gate struct netbuf *na; 20697c478bd9Sstevel@tonic-gate struct sockaddr_in *sinbuf, *sin; 20707c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6buf, *sin6; 20717c478bd9Sstevel@tonic-gate struct in_addr **inaddr, **inaddrlist; 20727c478bd9Sstevel@tonic-gate struct in6_addr **in6addr, **in6addrlist; 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* Address count */ 20757c478bd9Sstevel@tonic-gate num = 0; 20767c478bd9Sstevel@tonic-gate if (af == AF_INET6) { 20777c478bd9Sstevel@tonic-gate in6addrlist = (struct in6_addr **)haddrlist; 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate /* 20807c478bd9Sstevel@tonic-gate * Exclude IPv4-mapped IPv6 addresses from the count, as 20817c478bd9Sstevel@tonic-gate * these are not included in the nd_addrlist we return. 20827c478bd9Sstevel@tonic-gate */ 20837c478bd9Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) 20847c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(*in6addr)) 20857c478bd9Sstevel@tonic-gate num++; 20867c478bd9Sstevel@tonic-gate } else { 20877c478bd9Sstevel@tonic-gate inaddrlist = (struct in_addr **)haddrlist; 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) 20907c478bd9Sstevel@tonic-gate num++; 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate if (num == 0) 20937c478bd9Sstevel@tonic-gate return (ND_NOHOST); 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate result = malloc(sizeof (struct nd_addrlist)); 20967c478bd9Sstevel@tonic-gate if (result == 0) 20977c478bd9Sstevel@tonic-gate return (ND_NOMEM); 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate result->n_cnt = num; 21007c478bd9Sstevel@tonic-gate result->n_addrs = calloc(num, sizeof (struct netbuf)); 21017c478bd9Sstevel@tonic-gate if (result->n_addrs == 0) { 21027c478bd9Sstevel@tonic-gate free(result); 21037c478bd9Sstevel@tonic-gate return (ND_NOMEM); 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate na = result->n_addrs; 21077c478bd9Sstevel@tonic-gate if (af == AF_INET) { 21087c478bd9Sstevel@tonic-gate sinbuf = calloc(num, sizeof (struct sockaddr_in)); 21097c478bd9Sstevel@tonic-gate if (sinbuf == NULL) { 21107c478bd9Sstevel@tonic-gate free(result->n_addrs); 21117c478bd9Sstevel@tonic-gate free(result); 21127c478bd9Sstevel@tonic-gate return (ND_NOMEM); 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate sin = sinbuf; 21167c478bd9Sstevel@tonic-gate for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) { 21177c478bd9Sstevel@tonic-gate na->len = na->maxlen = sizeof (struct sockaddr_in); 21187c478bd9Sstevel@tonic-gate na->buf = (char *)sin; 21197c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 21207c478bd9Sstevel@tonic-gate sin->sin_addr = **inaddr; 21217c478bd9Sstevel@tonic-gate sin->sin_port = *servp; 21227c478bd9Sstevel@tonic-gate na++; 21237c478bd9Sstevel@tonic-gate sin++; 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate } else if (af == AF_INET6) { 21267c478bd9Sstevel@tonic-gate sin6buf = calloc(num, sizeof (struct sockaddr_in6)); 21277c478bd9Sstevel@tonic-gate if (sin6buf == NULL) { 21287c478bd9Sstevel@tonic-gate free(result->n_addrs); 21297c478bd9Sstevel@tonic-gate free(result); 21307c478bd9Sstevel@tonic-gate return (ND_NOMEM); 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate sin6 = sin6buf; 21347c478bd9Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 21357c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(*in6addr)) 21367c478bd9Sstevel@tonic-gate continue; 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate na->len = na->maxlen = sizeof (struct sockaddr_in6); 21397c478bd9Sstevel@tonic-gate na->buf = (char *)sin6; 21407c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 21417c478bd9Sstevel@tonic-gate sin6->sin6_addr = **in6addr; 21427c478bd9Sstevel@tonic-gate sin6->sin6_port = *servp; 21437c478bd9Sstevel@tonic-gate na++; 21447c478bd9Sstevel@tonic-gate sin6++; 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate *(nd_alist) = result; 21487c478bd9Sstevel@tonic-gate return (ND_OK); 21497c478bd9Sstevel@tonic-gate } 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate /* 21527c478bd9Sstevel@tonic-gate * Given a hostent and a servent, mallocs and populates 21537c478bd9Sstevel@tonic-gate * a new nd_hostservlist with host and service names. 21547c478bd9Sstevel@tonic-gate * 21557c478bd9Sstevel@tonic-gate * We could be passed in a NULL servent, in which case stringify port. 21567c478bd9Sstevel@tonic-gate */ 21577c478bd9Sstevel@tonic-gate int 21587c478bd9Sstevel@tonic-gate hsents2ndhostservs(struct hostent *he, struct servent *se, 21597c478bd9Sstevel@tonic-gate ushort_t port, struct nd_hostservlist **hslist) 21607c478bd9Sstevel@tonic-gate { 21617c478bd9Sstevel@tonic-gate struct nd_hostservlist *result; 21627c478bd9Sstevel@tonic-gate struct nd_hostserv *hs; 21637c478bd9Sstevel@tonic-gate int hosts, servs, i, j; 21647c478bd9Sstevel@tonic-gate char **hn, **sn; 21657c478bd9Sstevel@tonic-gate 216661961e0fSrobinson if ((result = malloc(sizeof (struct nd_hostservlist))) == 0) 21677c478bd9Sstevel@tonic-gate return (ND_NOMEM); 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate /* 21707c478bd9Sstevel@tonic-gate * We initialize the counters to 1 rather than zero because 21717c478bd9Sstevel@tonic-gate * we have to count the "official" name as well as the aliases. 21727c478bd9Sstevel@tonic-gate */ 2173*6392794bSMichen Chang for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++) {}; 2174*6392794bSMichen Chang if (se) { 2175*6392794bSMichen Chang for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++) { 2176*6392794bSMichen Chang }; 2177*6392794bSMichen Chang } else 21787c478bd9Sstevel@tonic-gate servs = 1; 21797c478bd9Sstevel@tonic-gate 218061961e0fSrobinson if ((hs = calloc(hosts * servs, sizeof (struct nd_hostserv))) == 0) { 218161961e0fSrobinson free(result); 21827c478bd9Sstevel@tonic-gate return (ND_NOMEM); 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate result->h_cnt = servs * hosts; 21867c478bd9Sstevel@tonic-gate result->h_hostservs = hs; 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate for (i = 0, hn = he->h_aliases; i < hosts; i++) { 21897c478bd9Sstevel@tonic-gate sn = se ? se->s_aliases : NULL; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate for (j = 0; j < servs; j++) { 21927c478bd9Sstevel@tonic-gate if (i == 0) 21937c478bd9Sstevel@tonic-gate hs->h_host = strdup(he->h_name); 21947c478bd9Sstevel@tonic-gate else 21957c478bd9Sstevel@tonic-gate hs->h_host = strdup(*hn); 21967c478bd9Sstevel@tonic-gate if (j == 0) { 21977c478bd9Sstevel@tonic-gate if (se) 21987c478bd9Sstevel@tonic-gate hs->h_serv = strdup(se->s_name); 21997c478bd9Sstevel@tonic-gate else { 22007c478bd9Sstevel@tonic-gate /* Convert to a number string */ 22017c478bd9Sstevel@tonic-gate char stmp[16]; 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate (void) sprintf(stmp, "%d", port); 22047c478bd9Sstevel@tonic-gate hs->h_serv = strdup(stmp); 22057c478bd9Sstevel@tonic-gate } 22067c478bd9Sstevel@tonic-gate } else 22077c478bd9Sstevel@tonic-gate hs->h_serv = strdup(*sn++); 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate if ((hs->h_host == 0) || (hs->h_serv == 0)) { 221061961e0fSrobinson free(result->h_hostservs); 221161961e0fSrobinson free(result); 22127c478bd9Sstevel@tonic-gate return (ND_NOMEM); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate hs++; 22157c478bd9Sstevel@tonic-gate } 22167c478bd9Sstevel@tonic-gate if (i) 22177c478bd9Sstevel@tonic-gate hn++; 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate *(hslist) = result; 22207c478bd9Sstevel@tonic-gate return (ND_OK); 22217c478bd9Sstevel@tonic-gate } 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate /* 22247c478bd9Sstevel@tonic-gate * Process results from nd_addrlist ( returned by netdir_getbyname) 22257c478bd9Sstevel@tonic-gate * into a hostent using buf. 22267c478bd9Sstevel@tonic-gate * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in 22277c478bd9Sstevel@tonic-gate * sockaddr_in's *** 22287c478bd9Sstevel@tonic-gate */ 22297c478bd9Sstevel@tonic-gate int 22307c478bd9Sstevel@tonic-gate ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs, 22317c478bd9Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen) 22327c478bd9Sstevel@tonic-gate { 22337c478bd9Sstevel@tonic-gate int i, count; 22347c478bd9Sstevel@tonic-gate struct in_addr *addrp; 22357c478bd9Sstevel@tonic-gate struct in6_addr *addr6p; 22367c478bd9Sstevel@tonic-gate char **addrvec; 22377c478bd9Sstevel@tonic-gate struct netbuf *na; 22387c478bd9Sstevel@tonic-gate size_t len; 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate result->h_name = buffer; 22417c478bd9Sstevel@tonic-gate result->h_addrtype = af; 22427c478bd9Sstevel@tonic-gate result->h_length = (af == AF_INET) ? sizeof (*addrp): 2243*6392794bSMichen Chang sizeof (*addr6p); 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate /* 22467c478bd9Sstevel@tonic-gate * Build addrlist at start of buffer (after name); store the 22477c478bd9Sstevel@tonic-gate * addresses themselves at the end of the buffer. 22487c478bd9Sstevel@tonic-gate */ 22497c478bd9Sstevel@tonic-gate len = strlen(nam) + 1; 22507c478bd9Sstevel@tonic-gate addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec)); 22517c478bd9Sstevel@tonic-gate result->h_addr_list = addrvec; 22527c478bd9Sstevel@tonic-gate 22537c478bd9Sstevel@tonic-gate if (af == AF_INET) { 22547c478bd9Sstevel@tonic-gate addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 22557c478bd9Sstevel@tonic-gate sizeof (*addrp)); 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate count = addrs->n_cnt; 22587c478bd9Sstevel@tonic-gate if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count])) 22597c478bd9Sstevel@tonic-gate return (ND_NOMEM); 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate (void) memcpy(buffer, nam, len); 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 22647c478bd9Sstevel@tonic-gate --addrp; 22657c478bd9Sstevel@tonic-gate (void) memcpy(addrp, 226661961e0fSrobinson /* LINTED pointer cast */ 22677c478bd9Sstevel@tonic-gate &((struct sockaddr_in *)na->buf)->sin_addr, 22687c478bd9Sstevel@tonic-gate sizeof (*addrp)); 22697c478bd9Sstevel@tonic-gate *addrvec++ = (char *)addrp; 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate } else { 22727c478bd9Sstevel@tonic-gate addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 2273*6392794bSMichen Chang sizeof (*addr6p)); 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate count = addrs->n_cnt; 22767c478bd9Sstevel@tonic-gate if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count])) 22777c478bd9Sstevel@tonic-gate return (ND_NOMEM); 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate (void) memcpy(buffer, nam, len); 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 22827c478bd9Sstevel@tonic-gate --addr6p; 22837c478bd9Sstevel@tonic-gate (void) memcpy(addr6p, 228461961e0fSrobinson /* LINTED pointer cast */ 22857c478bd9Sstevel@tonic-gate &((struct sockaddr_in6 *)na->buf)->sin6_addr, 22867c478bd9Sstevel@tonic-gate sizeof (*addr6p)); 22877c478bd9Sstevel@tonic-gate *addrvec++ = (char *)addr6p; 22887c478bd9Sstevel@tonic-gate } 22897c478bd9Sstevel@tonic-gate } 22907c478bd9Sstevel@tonic-gate *addrvec = 0; 22917c478bd9Sstevel@tonic-gate result->h_aliases = addrvec; 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate return (ND_OK); 22947c478bd9Sstevel@tonic-gate } 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate /* 22977c478bd9Sstevel@tonic-gate * Process results from nd_addrlist ( returned by netdir_getbyname) 22987c478bd9Sstevel@tonic-gate * into a servent using buf. 22997c478bd9Sstevel@tonic-gate */ 23007c478bd9Sstevel@tonic-gate int 23017c478bd9Sstevel@tonic-gate ndaddr2srent(const char *name, const char *proto, ushort_t port, 23027c478bd9Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 23037c478bd9Sstevel@tonic-gate { 23047c478bd9Sstevel@tonic-gate size_t i; 23057c478bd9Sstevel@tonic-gate char *bufend = (buffer + buflen); 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate result->s_port = (int)port; 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate result->s_aliases = 23107c478bd9Sstevel@tonic-gate (char **)ROUND_UP(buffer, sizeof (char *)); 23117c478bd9Sstevel@tonic-gate result->s_aliases[0] = NULL; 23127c478bd9Sstevel@tonic-gate buffer = (char *)&result->s_aliases[1]; 23137c478bd9Sstevel@tonic-gate result->s_name = buffer; 23147c478bd9Sstevel@tonic-gate i = strlen(name) + 1; 23157c478bd9Sstevel@tonic-gate if ((buffer + i) > bufend) 23167c478bd9Sstevel@tonic-gate return (ND_NOMEM); 23177c478bd9Sstevel@tonic-gate (void) memcpy(buffer, name, i); 23187c478bd9Sstevel@tonic-gate buffer += i; 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate result->s_proto = buffer; 23217c478bd9Sstevel@tonic-gate i = strlen(proto) + 1; 23227c478bd9Sstevel@tonic-gate if ((buffer + i) > bufend) 23237c478bd9Sstevel@tonic-gate return (ND_NOMEM); 23247c478bd9Sstevel@tonic-gate (void) memcpy(buffer, proto, i); 23257c478bd9Sstevel@tonic-gate buffer += i; 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate return (ND_OK); 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate /* 23317c478bd9Sstevel@tonic-gate * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 23327c478bd9Sstevel@tonic-gate * into a hostent using buf. 23337c478bd9Sstevel@tonic-gate * *** ASSUMES that nd_buf->buf is a sockaddr_in *** 23347c478bd9Sstevel@tonic-gate */ 23357c478bd9Sstevel@tonic-gate int 23367c478bd9Sstevel@tonic-gate ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs, 23377c478bd9Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen) 23387c478bd9Sstevel@tonic-gate { 23397c478bd9Sstevel@tonic-gate int i, count; 23407c478bd9Sstevel@tonic-gate char *aliasp; 23417c478bd9Sstevel@tonic-gate char **aliasvec; 23427c478bd9Sstevel@tonic-gate struct sockaddr_in *sa; 23437c478bd9Sstevel@tonic-gate struct nd_hostserv *hs; 23447c478bd9Sstevel@tonic-gate const char *la; 23457c478bd9Sstevel@tonic-gate size_t length; 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate /* First, give the lonely address a specious home in h_addr_list. */ 23487c478bd9Sstevel@tonic-gate aliasp = (char *)ROUND_UP(buffer, sizeof (sa->sin_addr)); 234961961e0fSrobinson /* LINTED pointer cast */ 23507c478bd9Sstevel@tonic-gate sa = (struct sockaddr_in *)nbuf->buf; 235161961e0fSrobinson (void) memcpy(aliasp, &(sa->sin_addr), sizeof (sa->sin_addr)); 23527c478bd9Sstevel@tonic-gate aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr), 2353*6392794bSMichen Chang sizeof (*aliasvec)); 23547c478bd9Sstevel@tonic-gate result->h_addr_list = aliasvec; 23557c478bd9Sstevel@tonic-gate *aliasvec++ = aliasp; 23567c478bd9Sstevel@tonic-gate *aliasvec++ = 0; 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate /* 23597c478bd9Sstevel@tonic-gate * Build h_aliases at start of buffer (after addr and h_addr_list); 23607c478bd9Sstevel@tonic-gate * store the alias strings at the end of the buffer (before h_name). 23617c478bd9Sstevel@tonic-gate */ 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate aliasp = buffer + buflen; 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate result->h_aliases = aliasvec; 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate hs = addrs->h_hostservs; 236861961e0fSrobinson if (!hs) 23697c478bd9Sstevel@tonic-gate return (ND_NOHOST); 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate length = strlen(hs->h_host) + 1; 23727c478bd9Sstevel@tonic-gate aliasp -= length; 23737c478bd9Sstevel@tonic-gate if ((char *)(&aliasvec[1]) > aliasp) 23747c478bd9Sstevel@tonic-gate return (ND_NOMEM); 23757c478bd9Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_host, length); 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate result->h_name = aliasp; 23787c478bd9Sstevel@tonic-gate result->h_addrtype = AF_INET; 23797c478bd9Sstevel@tonic-gate result->h_length = sizeof (sa->sin_addr); 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * Assumption: the netdir nametoaddr_libs 23837c478bd9Sstevel@tonic-gate * sort the vector of (host, serv) pairs in such a way that 23847c478bd9Sstevel@tonic-gate * all pairs with the same host name are contiguous. 23857c478bd9Sstevel@tonic-gate */ 23867c478bd9Sstevel@tonic-gate la = hs->h_host; 23877c478bd9Sstevel@tonic-gate count = addrs->h_cnt; 23887c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++, hs++) 23897c478bd9Sstevel@tonic-gate if (strcmp(la, hs->h_host) != 0) { 23907c478bd9Sstevel@tonic-gate size_t len = strlen(hs->h_host) + 1; 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate aliasp -= len; 23937c478bd9Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > aliasp) 23947c478bd9Sstevel@tonic-gate return (ND_NOMEM); 23957c478bd9Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_host, len); 23967c478bd9Sstevel@tonic-gate *aliasvec++ = aliasp; 23977c478bd9Sstevel@tonic-gate la = hs->h_host; 23987c478bd9Sstevel@tonic-gate } 23997c478bd9Sstevel@tonic-gate *aliasvec = 0; 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate return (ND_OK); 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate /* 24057c478bd9Sstevel@tonic-gate * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 24067c478bd9Sstevel@tonic-gate * into a servent using buf. 24077c478bd9Sstevel@tonic-gate */ 24087c478bd9Sstevel@tonic-gate int 24097c478bd9Sstevel@tonic-gate ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs, 24107c478bd9Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 24117c478bd9Sstevel@tonic-gate { 24127c478bd9Sstevel@tonic-gate int i, count; 24137c478bd9Sstevel@tonic-gate char *aliasp; 24147c478bd9Sstevel@tonic-gate char **aliasvec; 24157c478bd9Sstevel@tonic-gate struct nd_hostserv *hs; 24167c478bd9Sstevel@tonic-gate const char *host_cname; 24177c478bd9Sstevel@tonic-gate size_t leni, lenj; 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate result->s_port = port; 24207c478bd9Sstevel@tonic-gate /* 24217c478bd9Sstevel@tonic-gate * Build s_aliases at start of buffer; 24227c478bd9Sstevel@tonic-gate * store proto and aliases at the end of the buffer (before h_name). 24237c478bd9Sstevel@tonic-gate */ 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate aliasp = buffer + buflen; 24267c478bd9Sstevel@tonic-gate aliasvec = (char **)ROUND_UP(buffer, sizeof (char *)); 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate result->s_aliases = aliasvec; 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate hs = addrs->h_hostservs; 243161961e0fSrobinson if (!hs) 24327c478bd9Sstevel@tonic-gate return (ND_NOHOST); 24337c478bd9Sstevel@tonic-gate host_cname = hs->h_host; 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate leni = strlen(proto) + 1; 24367c478bd9Sstevel@tonic-gate lenj = strlen(hs->h_serv) + 1; 24377c478bd9Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj)) 24387c478bd9Sstevel@tonic-gate return (ND_NOMEM); 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate aliasp -= leni; 24417c478bd9Sstevel@tonic-gate (void) memcpy(aliasp, proto, leni); 24427c478bd9Sstevel@tonic-gate result->s_proto = aliasp; 24437c478bd9Sstevel@tonic-gate 24447c478bd9Sstevel@tonic-gate aliasp -= lenj; 24457c478bd9Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_serv, lenj); 24467c478bd9Sstevel@tonic-gate result->s_name = aliasp; 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate /* 24497c478bd9Sstevel@tonic-gate * Assumption: the netdir nametoaddr_libs 24507c478bd9Sstevel@tonic-gate * do a host aliases first and serv aliases next 24517c478bd9Sstevel@tonic-gate * enumeration for creating the list of hostserv 24527c478bd9Sstevel@tonic-gate * structures. 24537c478bd9Sstevel@tonic-gate */ 24547c478bd9Sstevel@tonic-gate count = addrs->h_cnt; 24557c478bd9Sstevel@tonic-gate for (i = 0; 24567c478bd9Sstevel@tonic-gate i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0; 24577c478bd9Sstevel@tonic-gate i++, hs++) { 24587c478bd9Sstevel@tonic-gate size_t len = strlen(hs->h_serv) + 1; 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate aliasp -= len; 24617c478bd9Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > aliasp) 24627c478bd9Sstevel@tonic-gate return (ND_NOMEM); 24637c478bd9Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_serv, len); 24647c478bd9Sstevel@tonic-gate *aliasvec++ = aliasp; 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate *aliasvec = NULL; 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate return (ND_OK); 24697c478bd9Sstevel@tonic-gate } 24707c478bd9Sstevel@tonic-gate 24717c478bd9Sstevel@tonic-gate 24727c478bd9Sstevel@tonic-gate static int 24737c478bd9Sstevel@tonic-gate nd2herrno(int nerr) 24747c478bd9Sstevel@tonic-gate { 24757c478bd9Sstevel@tonic-gate switch (nerr) { 24767c478bd9Sstevel@tonic-gate case ND_OK: 24777c478bd9Sstevel@tonic-gate return (0); 24787c478bd9Sstevel@tonic-gate case ND_TRY_AGAIN: 24797c478bd9Sstevel@tonic-gate return (TRY_AGAIN); 24807c478bd9Sstevel@tonic-gate case ND_NO_RECOVERY: 24817c478bd9Sstevel@tonic-gate case ND_BADARG: 24827c478bd9Sstevel@tonic-gate case ND_NOMEM: 24837c478bd9Sstevel@tonic-gate return (NO_RECOVERY); 24847c478bd9Sstevel@tonic-gate case ND_NO_DATA: 24857c478bd9Sstevel@tonic-gate return (NO_DATA); 24867c478bd9Sstevel@tonic-gate case ND_NOHOST: 24877c478bd9Sstevel@tonic-gate case ND_NOSERV: 24887c478bd9Sstevel@tonic-gate return (HOST_NOT_FOUND); 24897c478bd9Sstevel@tonic-gate default: 24907c478bd9Sstevel@tonic-gate return (NO_RECOVERY); 24917c478bd9Sstevel@tonic-gate } 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate /* 24957c478bd9Sstevel@tonic-gate * This is a utility function so that various parts of libnsl can 24967c478bd9Sstevel@tonic-gate * easily send ioctls down to ip. 24977c478bd9Sstevel@tonic-gate * 24987c478bd9Sstevel@tonic-gate */ 24997c478bd9Sstevel@tonic-gate int 25007c478bd9Sstevel@tonic-gate nss_ioctl(int af, int cmd, void *arg) 25017c478bd9Sstevel@tonic-gate { 25027c478bd9Sstevel@tonic-gate int fd; 25037c478bd9Sstevel@tonic-gate char *devpath; 25047c478bd9Sstevel@tonic-gate int retv; 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate switch (af) { 25077c478bd9Sstevel@tonic-gate case AF_INET6: 25087c478bd9Sstevel@tonic-gate devpath = UDP6DEV; 25097c478bd9Sstevel@tonic-gate break; 25107c478bd9Sstevel@tonic-gate case AF_INET: 25117c478bd9Sstevel@tonic-gate case AF_UNSPEC: 25127c478bd9Sstevel@tonic-gate default: 25137c478bd9Sstevel@tonic-gate devpath = UDPDEV; 25147c478bd9Sstevel@tonic-gate } 25157c478bd9Sstevel@tonic-gate if ((fd = open(devpath, O_RDONLY)) < 0) { 25167c478bd9Sstevel@tonic-gate return (-1); 25177c478bd9Sstevel@tonic-gate } 25187c478bd9Sstevel@tonic-gate while ((retv = ioctl(fd, cmd, arg)) == -1) { 25197c478bd9Sstevel@tonic-gate if (errno != EINTR) 25207c478bd9Sstevel@tonic-gate break; 25217c478bd9Sstevel@tonic-gate } 252261961e0fSrobinson (void) close(fd); 25237c478bd9Sstevel@tonic-gate return (retv); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate static int 25277c478bd9Sstevel@tonic-gate nss_strioctl(int af, int cmd, void *ptr, int ilen) 25287c478bd9Sstevel@tonic-gate { 25297c478bd9Sstevel@tonic-gate struct strioctl str; 25307c478bd9Sstevel@tonic-gate 25317c478bd9Sstevel@tonic-gate str.ic_cmd = cmd; 25327c478bd9Sstevel@tonic-gate str.ic_timout = 0; 25337c478bd9Sstevel@tonic-gate str.ic_len = ilen; 25347c478bd9Sstevel@tonic-gate str.ic_dp = ptr; 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate return (nss_ioctl(af, I_STR, &str)); 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate static struct ifinfo * 25407c478bd9Sstevel@tonic-gate get_local_info(void) 25417c478bd9Sstevel@tonic-gate { 25427c478bd9Sstevel@tonic-gate int numifs; 25437c478bd9Sstevel@tonic-gate int n; 25447c478bd9Sstevel@tonic-gate char *buf = NULL; 25457c478bd9Sstevel@tonic-gate size_t needed; 25467c478bd9Sstevel@tonic-gate struct lifconf lifc; 25477c478bd9Sstevel@tonic-gate struct lifreq lifreq, *lifr; 25487c478bd9Sstevel@tonic-gate struct lifnum lifn; 25497c478bd9Sstevel@tonic-gate struct ifinfo *localinfo; 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 25527c478bd9Sstevel@tonic-gate lifn.lifn_flags = 0; 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate getifnum: 25557c478bd9Sstevel@tonic-gate if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) { 25567c478bd9Sstevel@tonic-gate numifs = MAXIFS; 25577c478bd9Sstevel@tonic-gate } else { 25587c478bd9Sstevel@tonic-gate numifs = lifn.lifn_count; 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate /* 25627c478bd9Sstevel@tonic-gate * Add a small fudge factor in case interfaces get plumbed between 25637c478bd9Sstevel@tonic-gate * the call to SIOCGLIFNUM and SIOCGLIFCONF. 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate needed = (numifs + 4) * sizeof (lifreq); 25667c478bd9Sstevel@tonic-gate if (buf == NULL) 25677c478bd9Sstevel@tonic-gate buf = malloc(needed); 25687c478bd9Sstevel@tonic-gate else 25697c478bd9Sstevel@tonic-gate buf = realloc(buf, needed); 25707c478bd9Sstevel@tonic-gate if (buf == NULL) { 25717c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 25727c478bd9Sstevel@tonic-gate _nderror = ND_NOMEM; 25737c478bd9Sstevel@tonic-gate return (NULL); 25747c478bd9Sstevel@tonic-gate } 25757c478bd9Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC; 25767c478bd9Sstevel@tonic-gate lifc.lifc_flags = 0; 25777c478bd9Sstevel@tonic-gate lifc.lifc_len = needed; 25787c478bd9Sstevel@tonic-gate lifc.lifc_buf = buf; 25797c478bd9Sstevel@tonic-gate if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) { 25807c478bd9Sstevel@tonic-gate /* 25817c478bd9Sstevel@tonic-gate * IP returns EINVAL if the buffer was too small to fit 25827c478bd9Sstevel@tonic-gate * all of the entries. If that's the case, go back and 25837c478bd9Sstevel@tonic-gate * try again. 25847c478bd9Sstevel@tonic-gate */ 25857c478bd9Sstevel@tonic-gate if (errno == EINVAL) 25867c478bd9Sstevel@tonic-gate goto getifnum; 25877c478bd9Sstevel@tonic-gate 25887c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: " 25897c478bd9Sstevel@tonic-gate "ioctl (get interface configuration): %m"); 25907c478bd9Sstevel@tonic-gate free(buf); 25917c478bd9Sstevel@tonic-gate _nderror = ND_SYSTEM; 25927c478bd9Sstevel@tonic-gate return (NULL); 25937c478bd9Sstevel@tonic-gate } 259461961e0fSrobinson /* LINTED pointer cast */ 25957c478bd9Sstevel@tonic-gate lifr = (struct lifreq *)buf; 25967c478bd9Sstevel@tonic-gate numifs = lifc.lifc_len/sizeof (lifreq); 259761961e0fSrobinson localinfo = malloc(ifinfosize(numifs)); 25987c478bd9Sstevel@tonic-gate if (localinfo == NULL) { 25997c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 26007c478bd9Sstevel@tonic-gate free(buf); 26017c478bd9Sstevel@tonic-gate _nderror = ND_SYSTEM; 26027c478bd9Sstevel@tonic-gate return (NULL); 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate 260561961e0fSrobinson /* LINTED pointer cast */ 26067c478bd9Sstevel@tonic-gate localinfo->addresses = (struct __ifaddr *) 26077c478bd9Sstevel@tonic-gate ((char *)localinfo + sizeof (struct ifinfo)); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) { 26107c478bd9Sstevel@tonic-gate int af; 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate lifreq = *lifr; 26137c478bd9Sstevel@tonic-gate af = lifreq.lifr_addr.ss_family; 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate /* Squirrel away the address */ 26167c478bd9Sstevel@tonic-gate if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0) 26177c478bd9Sstevel@tonic-gate continue; 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) { 26207c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 26217c478bd9Sstevel@tonic-gate "n2a get_local_info: " 26227c478bd9Sstevel@tonic-gate "ioctl (get interface flags): %m"); 26237c478bd9Sstevel@tonic-gate continue; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate if (!(lifreq.lifr_flags & IFF_UP)) 26267c478bd9Sstevel@tonic-gate continue; 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) { 26297c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 26307c478bd9Sstevel@tonic-gate "n2a get_local_info: " 26317c478bd9Sstevel@tonic-gate "ioctl (get interface netmask): %m"); 26327c478bd9Sstevel@tonic-gate continue; 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate if (ifassign(lifreq, localinfo->count, IF_MASK) == 0) 26367c478bd9Sstevel@tonic-gate continue; 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate localinfo->count++; 26397c478bd9Sstevel@tonic-gate } 26407c478bd9Sstevel@tonic-gate 26417c478bd9Sstevel@tonic-gate free(buf); 26427c478bd9Sstevel@tonic-gate return (localinfo); 26437c478bd9Sstevel@tonic-gate } 26447c478bd9Sstevel@tonic-gate 26457c478bd9Sstevel@tonic-gate static int 26467c478bd9Sstevel@tonic-gate __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type, 26477c478bd9Sstevel@tonic-gate void *addr) { 26487c478bd9Sstevel@tonic-gate switch (type) { 26497c478bd9Sstevel@tonic-gate case IF_ADDR: 26507c478bd9Sstevel@tonic-gate ifa->af = af; 26517c478bd9Sstevel@tonic-gate if (af == AF_INET6) { 26527c478bd9Sstevel@tonic-gate ifa->addr.in6 = *(struct in6_addr *)addr; 26537c478bd9Sstevel@tonic-gate } else { 26547c478bd9Sstevel@tonic-gate ifa->addr.in4 = *(struct in_addr *)addr; 26557c478bd9Sstevel@tonic-gate } 26567c478bd9Sstevel@tonic-gate break; 26577c478bd9Sstevel@tonic-gate case IF_MASK: 26587c478bd9Sstevel@tonic-gate if (ifa->af == af) { 26597c478bd9Sstevel@tonic-gate if (af == AF_INET6) { 26607c478bd9Sstevel@tonic-gate ifa->mask.in6 = *(struct in6_addr *)addr; 26617c478bd9Sstevel@tonic-gate } else { 26627c478bd9Sstevel@tonic-gate ifa->mask.in4 = *(struct in_addr *)addr; 26637c478bd9Sstevel@tonic-gate } 26647c478bd9Sstevel@tonic-gate } else { 26657c478bd9Sstevel@tonic-gate return (0); 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate break; 26687c478bd9Sstevel@tonic-gate default: 26697c478bd9Sstevel@tonic-gate return (0); 26707c478bd9Sstevel@tonic-gate } 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate return (1); 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* 26767c478bd9Sstevel@tonic-gate * Some higher-level routines for determining if an address is 26777c478bd9Sstevel@tonic-gate * on a local network. 26787c478bd9Sstevel@tonic-gate * 26797c478bd9Sstevel@tonic-gate * __inet_get_local_interfaces() - get an opaque handle with 26807c478bd9Sstevel@tonic-gate * with a list of local interfaces 26817c478bd9Sstevel@tonic-gate * __inet_address_is_local() - return 1 if an address is 26827c478bd9Sstevel@tonic-gate * on a local network; 0 otherwise 26837c478bd9Sstevel@tonic-gate * __inet_free_local_interfaces() - free handle that was 26847c478bd9Sstevel@tonic-gate * returned by __inet_get_local_interfaces() 26857c478bd9Sstevel@tonic-gate * 26867c478bd9Sstevel@tonic-gate * A typical calling sequence is: 26877c478bd9Sstevel@tonic-gate * 26887c478bd9Sstevel@tonic-gate * p = __inet_get_local_interfaces(); 26897c478bd9Sstevel@tonic-gate * if (__inet_address_is_local(p, inaddr)) { 26907c478bd9Sstevel@tonic-gate * ... 26917c478bd9Sstevel@tonic-gate * } 26927c478bd9Sstevel@tonic-gate * __inet_free_local_interfaces(p); 26937c478bd9Sstevel@tonic-gate */ 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate /* 26967c478bd9Sstevel@tonic-gate * Return an opaque pointer to a list of configured interfaces. 26977c478bd9Sstevel@tonic-gate */ 26987c478bd9Sstevel@tonic-gate void * 26997c478bd9Sstevel@tonic-gate __inet_get_local_interfaces(void) 27007c478bd9Sstevel@tonic-gate { 27017c478bd9Sstevel@tonic-gate return (get_local_info()); 27027c478bd9Sstevel@tonic-gate } 27037c478bd9Sstevel@tonic-gate 27047c478bd9Sstevel@tonic-gate /* 27057c478bd9Sstevel@tonic-gate * Free memory allocated by inet_local_interfaces(). 27067c478bd9Sstevel@tonic-gate */ 27077c478bd9Sstevel@tonic-gate void 27087c478bd9Sstevel@tonic-gate __inet_free_local_interfaces(void *p) 27097c478bd9Sstevel@tonic-gate { 27107c478bd9Sstevel@tonic-gate free(p); 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate /* 27147c478bd9Sstevel@tonic-gate * Determine if an address is on a local network. 27157c478bd9Sstevel@tonic-gate * 27167c478bd9Sstevel@tonic-gate * Might have made sense to use SIOCTONLINK, except that it doesn't 27177c478bd9Sstevel@tonic-gate * handle matching on IPv4 network addresses. 27187c478bd9Sstevel@tonic-gate */ 27197c478bd9Sstevel@tonic-gate int 27207c478bd9Sstevel@tonic-gate __inet_address_is_local_af(void *p, sa_family_t af, void *addr) { 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 27237c478bd9Sstevel@tonic-gate int i, a; 27247c478bd9Sstevel@tonic-gate struct in_addr v4addr; 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate if (localinfo == 0) 27277c478bd9Sstevel@tonic-gate return (0); 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { 27307c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); 27317c478bd9Sstevel@tonic-gate af = AF_INET; 27327c478bd9Sstevel@tonic-gate addr = (void *)&v4addr; 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate for (i = 0; i < localinfo->count; i++) { 27367c478bd9Sstevel@tonic-gate if (ifaf(i) == af) { 27377c478bd9Sstevel@tonic-gate if (af == AF_INET6) { 27387c478bd9Sstevel@tonic-gate struct in6_addr *a6 = (struct in6_addr *)addr; 27397c478bd9Sstevel@tonic-gate for (a = 0; a < sizeof (a6->s6_addr); a++) { 27407c478bd9Sstevel@tonic-gate if ((a6->s6_addr[a] & 27417c478bd9Sstevel@tonic-gate ifmask6(i).s6_addr[a]) != 27427c478bd9Sstevel@tonic-gate (ifaddr6(i).s6_addr[a] & 27437c478bd9Sstevel@tonic-gate ifmask6(i).s6_addr[a])) 27447c478bd9Sstevel@tonic-gate break; 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate if (a >= sizeof (a6->s6_addr)) 27477c478bd9Sstevel@tonic-gate return (1); 27487c478bd9Sstevel@tonic-gate } else { 27497c478bd9Sstevel@tonic-gate if ((((struct in_addr *)addr)->s_addr & 27507c478bd9Sstevel@tonic-gate ifmask4(i).s_addr) == 27517c478bd9Sstevel@tonic-gate (ifaddr4(i).s_addr & 27527c478bd9Sstevel@tonic-gate ifmask4(i).s_addr)) 27537c478bd9Sstevel@tonic-gate return (1); 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate return (0); 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate int 27627c478bd9Sstevel@tonic-gate __inet_address_is_local(void *p, struct in_addr addr) 27637c478bd9Sstevel@tonic-gate { 27647c478bd9Sstevel@tonic-gate return (__inet_address_is_local_af(p, AF_INET, &addr)); 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate int 27687c478bd9Sstevel@tonic-gate __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr) 27697c478bd9Sstevel@tonic-gate { 27707c478bd9Sstevel@tonic-gate struct netbuf *taddr; 27717c478bd9Sstevel@tonic-gate sa_family_t af; 27727c478bd9Sstevel@tonic-gate int ret; 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate taddr = uaddr2taddr(nc, uaddr); 27757c478bd9Sstevel@tonic-gate if (taddr == 0) 27767c478bd9Sstevel@tonic-gate return (0); 27777c478bd9Sstevel@tonic-gate 277861961e0fSrobinson /* LINTED pointer cast */ 27797c478bd9Sstevel@tonic-gate af = ((struct sockaddr *)taddr->buf)->sa_family; 27807c478bd9Sstevel@tonic-gate 2781*6392794bSMichen Chang ret = __inet_address_is_local_af(p, af, (af == AF_INET6) ? 2782*6392794bSMichen Chang /* LINTED pointer cast */ 2783*6392794bSMichen Chang (void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr : 2784*6392794bSMichen Chang /* LINTED pointer cast */ 2785*6392794bSMichen Chang (void *)&((struct sockaddr_in *)taddr->buf)->sin_addr); 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate netdir_free(taddr, ND_ADDR); 27887c478bd9Sstevel@tonic-gate return (ret); 27897c478bd9Sstevel@tonic-gate } 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate int 27937c478bd9Sstevel@tonic-gate __inet_address_count(void *p) 27947c478bd9Sstevel@tonic-gate { 27957c478bd9Sstevel@tonic-gate struct ifinfo *lp = (struct ifinfo *)p; 27967c478bd9Sstevel@tonic-gate 27977c478bd9Sstevel@tonic-gate if (lp != 0) { 27987c478bd9Sstevel@tonic-gate return (lp->count); 27997c478bd9Sstevel@tonic-gate } else { 28007c478bd9Sstevel@tonic-gate return (0); 28017c478bd9Sstevel@tonic-gate } 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate 28047c478bd9Sstevel@tonic-gate uint32_t 28057c478bd9Sstevel@tonic-gate __inet_get_addr(void *p, int n) 28067c478bd9Sstevel@tonic-gate { 28077c478bd9Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 28107c478bd9Sstevel@tonic-gate return (0); 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate return (ifaddr4(n).s_addr); 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate uint32_t 28167c478bd9Sstevel@tonic-gate __inet_get_network(void *p, int n) 28177c478bd9Sstevel@tonic-gate { 28187c478bd9Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 28217c478bd9Sstevel@tonic-gate return (0); 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate return (ifaddr4(n).s_addr & ifmask4(n).s_addr); 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate char * 28277c478bd9Sstevel@tonic-gate __inet_get_uaddr(void *p, struct netconfig *nc, int n) 28287c478bd9Sstevel@tonic-gate { 28297c478bd9Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 28307c478bd9Sstevel@tonic-gate char *uaddr; 28317c478bd9Sstevel@tonic-gate struct sockaddr_in sin4; 28327c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 28337c478bd9Sstevel@tonic-gate struct netbuf nb; 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate if (localinfo == 0 || nc == 0 || n >= localinfo->count) 28367c478bd9Sstevel@tonic-gate return (0); 28377c478bd9Sstevel@tonic-gate 28387c478bd9Sstevel@tonic-gate if (ifaf(n) == AF_INET6) { 28397c478bd9Sstevel@tonic-gate if (strcmp(NC_INET6, nc->nc_protofmly) != 0) 28407c478bd9Sstevel@tonic-gate return (0); 284161961e0fSrobinson (void) memset(&sin6, 0, sizeof (sin6)); 28427c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 28437c478bd9Sstevel@tonic-gate sin6.sin6_addr = ifaddr6(n); 28447c478bd9Sstevel@tonic-gate nb.buf = (char *)&sin6; 28457c478bd9Sstevel@tonic-gate nb.len = sizeof (sin6); 28467c478bd9Sstevel@tonic-gate } else { 28477c478bd9Sstevel@tonic-gate if (strcmp(NC_INET, nc->nc_protofmly) != 0) 28487c478bd9Sstevel@tonic-gate return (0); 284961961e0fSrobinson (void) memset(&sin4, 0, sizeof (sin4)); 28507c478bd9Sstevel@tonic-gate sin4.sin_family = AF_INET; 28517c478bd9Sstevel@tonic-gate sin4.sin_addr = ifaddr4(n); 28527c478bd9Sstevel@tonic-gate nb.buf = (char *)&sin4; 28537c478bd9Sstevel@tonic-gate nb.len = sizeof (sin4); 28547c478bd9Sstevel@tonic-gate } 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate nb.maxlen = nb.len; 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate uaddr = taddr2uaddr(nc, &nb); 28597c478bd9Sstevel@tonic-gate return (uaddr); 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate char * 28637c478bd9Sstevel@tonic-gate __inet_get_networka(void *p, int n) 28647c478bd9Sstevel@tonic-gate { 28657c478bd9Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count) 28687c478bd9Sstevel@tonic-gate return (0); 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate if (ifaf(n) == AF_INET6) { 28717c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 28727c478bd9Sstevel@tonic-gate struct in6_addr in6; 28737c478bd9Sstevel@tonic-gate int i; 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (in6.s6_addr); i++) { 28767c478bd9Sstevel@tonic-gate in6.s6_addr[i] = ifaddr6(n).s6_addr[i] & 2877*6392794bSMichen Chang ifmask6(n).s6_addr[i]; 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf)))); 28807c478bd9Sstevel@tonic-gate } else { 28817c478bd9Sstevel@tonic-gate struct in_addr in4; 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr; 28847c478bd9Sstevel@tonic-gate return (strdup(inet_ntoa(in4))); 28857c478bd9Sstevel@tonic-gate } 28867c478bd9Sstevel@tonic-gate } 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate static int 28897c478bd9Sstevel@tonic-gate in_list(struct in_addr *addrs, int n, struct in_addr a) 28907c478bd9Sstevel@tonic-gate { 28917c478bd9Sstevel@tonic-gate int i; 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 28947c478bd9Sstevel@tonic-gate if (addrs[i].s_addr == a.s_addr) 28957c478bd9Sstevel@tonic-gate return (1); 28967c478bd9Sstevel@tonic-gate } 28977c478bd9Sstevel@tonic-gate return (0); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate static int 29017c478bd9Sstevel@tonic-gate getbroadcastnets(struct netconfig *tp, struct in_addr **addrs) 29027c478bd9Sstevel@tonic-gate { 29037c478bd9Sstevel@tonic-gate struct ifconf ifc; 29047c478bd9Sstevel@tonic-gate struct ifreq ifreq, *ifr; 29057c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 29067c478bd9Sstevel@tonic-gate struct in_addr a; 29077c478bd9Sstevel@tonic-gate int fd; 29087c478bd9Sstevel@tonic-gate int n, i, numifs; 29097c478bd9Sstevel@tonic-gate char *buf; 29107c478bd9Sstevel@tonic-gate int use_loopback = 0; 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate _nderror = ND_SYSTEM; 29137c478bd9Sstevel@tonic-gate fd = open(tp->nc_device, O_RDONLY); 29147c478bd9Sstevel@tonic-gate if (fd < 0) { 29157c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 29167c478bd9Sstevel@tonic-gate "broadcast: open to get interface configuration: %m"); 29177c478bd9Sstevel@tonic-gate return (0); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) 29207c478bd9Sstevel@tonic-gate numifs = MAXIFS; 292161961e0fSrobinson buf = malloc(numifs * sizeof (struct ifreq)); 29227c478bd9Sstevel@tonic-gate if (buf == NULL) { 29237c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 29247c478bd9Sstevel@tonic-gate (void) close(fd); 29257c478bd9Sstevel@tonic-gate return (0); 29267c478bd9Sstevel@tonic-gate } 292761961e0fSrobinson *addrs = malloc(numifs * sizeof (struct in_addr)); 29287c478bd9Sstevel@tonic-gate if (*addrs == NULL) { 29297c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 29307c478bd9Sstevel@tonic-gate free(buf); 29317c478bd9Sstevel@tonic-gate (void) close(fd); 29327c478bd9Sstevel@tonic-gate return (0); 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate ifc.ifc_len = numifs * (int)sizeof (struct ifreq); 29357c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 29367c478bd9Sstevel@tonic-gate /* 29377c478bd9Sstevel@tonic-gate * Ideally, this ioctl should also tell me, how many bytes were 29387c478bd9Sstevel@tonic-gate * finally allocated, but it doesnt. 29397c478bd9Sstevel@tonic-gate */ 29407c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) { 29417c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 29427c478bd9Sstevel@tonic-gate "broadcast: ioctl (get interface configuration): %m"); 29437c478bd9Sstevel@tonic-gate free(buf); 29447c478bd9Sstevel@tonic-gate free(*addrs); 29457c478bd9Sstevel@tonic-gate (void) close(fd); 29467c478bd9Sstevel@tonic-gate return (0); 29477c478bd9Sstevel@tonic-gate } 29487c478bd9Sstevel@tonic-gate 29497c478bd9Sstevel@tonic-gate retry: 295061961e0fSrobinson /* LINTED pointer cast */ 29517c478bd9Sstevel@tonic-gate ifr = (struct ifreq *)buf; 29527c478bd9Sstevel@tonic-gate for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq); 2953*6392794bSMichen Chang n > 0; n--, ifr++) { 29547c478bd9Sstevel@tonic-gate ifreq = *ifr; 29557c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 2956*6392794bSMichen Chang (void) syslog(LOG_ERR, "broadcast: " 2957*6392794bSMichen Chang "ioctl (get interface flags): %m"); 29587c478bd9Sstevel@tonic-gate continue; 29597c478bd9Sstevel@tonic-gate } 29607c478bd9Sstevel@tonic-gate if (!(ifreq.ifr_flags & IFF_UP) || 29617c478bd9Sstevel@tonic-gate (ifr->ifr_addr.sa_family != AF_INET)) 29627c478bd9Sstevel@tonic-gate continue; 29637c478bd9Sstevel@tonic-gate if (ifreq.ifr_flags & IFF_BROADCAST) { 296461961e0fSrobinson /* LINTED pointer cast */ 29657c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 29667c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 29677c478bd9Sstevel@tonic-gate /* May not work with other implementation */ 29687c478bd9Sstevel@tonic-gate a = _inet_makeaddr( 29697c478bd9Sstevel@tonic-gate inet_netof(sin->sin_addr), 29707c478bd9Sstevel@tonic-gate INADDR_ANY); 29717c478bd9Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 29727c478bd9Sstevel@tonic-gate (*addrs)[i++] = a; 29737c478bd9Sstevel@tonic-gate } else { 297461961e0fSrobinson /* LINTED pointer cast */ 29757c478bd9Sstevel@tonic-gate a = ((struct sockaddr_in *) 29767c478bd9Sstevel@tonic-gate &ifreq.ifr_addr)->sin_addr; 29777c478bd9Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 29787c478bd9Sstevel@tonic-gate (*addrs)[i++] = a; 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate continue; 29817c478bd9Sstevel@tonic-gate } 29827c478bd9Sstevel@tonic-gate if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) { 298361961e0fSrobinson /* LINTED pointer cast */ 29847c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 29857c478bd9Sstevel@tonic-gate a = sin->sin_addr; 29867c478bd9Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 29877c478bd9Sstevel@tonic-gate (*addrs)[i++] = a; 29887c478bd9Sstevel@tonic-gate continue; 29897c478bd9Sstevel@tonic-gate } 29907c478bd9Sstevel@tonic-gate if (ifreq.ifr_flags & IFF_POINTOPOINT) { 29917c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0) 29927c478bd9Sstevel@tonic-gate continue; 299361961e0fSrobinson /* LINTED pointer cast */ 29947c478bd9Sstevel@tonic-gate a = ((struct sockaddr_in *) 29957c478bd9Sstevel@tonic-gate &ifreq.ifr_addr)->sin_addr; 29967c478bd9Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 29977c478bd9Sstevel@tonic-gate (*addrs)[i++] = a; 29987c478bd9Sstevel@tonic-gate continue; 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate if (i == 0 && !use_loopback) { 30027c478bd9Sstevel@tonic-gate use_loopback = 1; 30037c478bd9Sstevel@tonic-gate goto retry; 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate free(buf); 30067c478bd9Sstevel@tonic-gate (void) close(fd); 30077c478bd9Sstevel@tonic-gate if (i) 30087c478bd9Sstevel@tonic-gate _nderror = ND_OK; 30097c478bd9Sstevel@tonic-gate else 30107c478bd9Sstevel@tonic-gate free(*addrs); 30117c478bd9Sstevel@tonic-gate return (i); 30127c478bd9Sstevel@tonic-gate } 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate /* 30157c478bd9Sstevel@tonic-gate * This is lifted straight from libsocket/inet/inet_mkaddr.c. 30167c478bd9Sstevel@tonic-gate * Copied here to avoid our dependency on libsocket. More importantly, 30177c478bd9Sstevel@tonic-gate * to make sure partially static apps that use libnsl, but not 30187c478bd9Sstevel@tonic-gate * libsocket, don't get screwed up. 30197c478bd9Sstevel@tonic-gate * If you understand the above paragraph, try to get rid of 30207c478bd9Sstevel@tonic-gate * this copy of inet_makeaddr; if you don;t, leave it alone. 30217c478bd9Sstevel@tonic-gate * 30227c478bd9Sstevel@tonic-gate * Formulate an Internet address from network + host. Used in 30237c478bd9Sstevel@tonic-gate * building addresses stored in the ifnet structure. 30247c478bd9Sstevel@tonic-gate */ 30257c478bd9Sstevel@tonic-gate static struct in_addr 30267c478bd9Sstevel@tonic-gate _inet_makeaddr(in_addr_t net, in_addr_t host) 30277c478bd9Sstevel@tonic-gate { 30287c478bd9Sstevel@tonic-gate in_addr_t addr; 30297c478bd9Sstevel@tonic-gate struct in_addr inaddr; 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate if (net < 128) 30327c478bd9Sstevel@tonic-gate addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); 30337c478bd9Sstevel@tonic-gate else if (net < 65536) 30347c478bd9Sstevel@tonic-gate addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); 30357c478bd9Sstevel@tonic-gate else if (net < 16777216L) 30367c478bd9Sstevel@tonic-gate addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); 30377c478bd9Sstevel@tonic-gate else 30387c478bd9Sstevel@tonic-gate addr = net | host; 30397c478bd9Sstevel@tonic-gate inaddr.s_addr = htonl(addr); 30407c478bd9Sstevel@tonic-gate return (inaddr); 30417c478bd9Sstevel@tonic-gate } 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate /* 30447c478bd9Sstevel@tonic-gate * Routine to read the default configuration file and check if SORT_ADDRS 30457c478bd9Sstevel@tonic-gate * is set to NO or FALSE. This routine is called by order_haddrlist_af() 30467c478bd9Sstevel@tonic-gate * to determine if the addresses need to be sorted. 30477c478bd9Sstevel@tonic-gate */ 30487c478bd9Sstevel@tonic-gate static boolean_t 30497c478bd9Sstevel@tonic-gate _read_nsw_file(void) 30507c478bd9Sstevel@tonic-gate { 30517c478bd9Sstevel@tonic-gate char defval[LINESIZE]; 3052004388ebScasper FILE *defl; 30537c478bd9Sstevel@tonic-gate boolean_t nosort = B_FALSE; 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate 30567c478bd9Sstevel@tonic-gate do { 3057004388ebScasper defl = fopen(__NSW_DEFAULT_FILE, "rF"); 30587c478bd9Sstevel@tonic-gate } while ((defl == NULL) && (errno == EINTR)); 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate if (defl == NULL) 30617c478bd9Sstevel@tonic-gate return (B_FALSE); 30627c478bd9Sstevel@tonic-gate 3063004388ebScasper while (fgets(defval, sizeof (defval), defl) != NULL) { 30647c478bd9Sstevel@tonic-gate if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) || 30657c478bd9Sstevel@tonic-gate (strncmp(DONT_SORT2, defval, 3066*6392794bSMichen Chang sizeof (DONT_SORT2) - 1) == 0)) { 30677c478bd9Sstevel@tonic-gate nosort = B_TRUE; 30687c478bd9Sstevel@tonic-gate break; 30697c478bd9Sstevel@tonic-gate } 30707c478bd9Sstevel@tonic-gate } 3071004388ebScasper (void) fclose(defl); 30727c478bd9Sstevel@tonic-gate return (nosort); 30737c478bd9Sstevel@tonic-gate } 3074