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