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