1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * lib/libnsl/nss/netdir_inet.c 27*0Sstevel@tonic-gate * 28*0Sstevel@tonic-gate * This is where we have chosen to combine every useful bit of code for 29*0Sstevel@tonic-gate * all the Solaris frontends to lookup hosts, services, and netdir information 30*0Sstevel@tonic-gate * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and 31*0Sstevel@tonic-gate * netdir_getbyYY() are all implemented on top of this code. Similarly, 32*0Sstevel@tonic-gate * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also 33*0Sstevel@tonic-gate * find a home here. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-" 36*0Sstevel@tonic-gate * in /etc/netconfig), this code calls the name service switch, and 37*0Sstevel@tonic-gate * therefore, /etc/nsswitch.conf is effectively the only place that 38*0Sstevel@tonic-gate * dictates hosts/serv lookup policy. 39*0Sstevel@tonic-gate * If an administrator chooses to bypass the name service switch by 40*0Sstevel@tonic-gate * specifying third party supplied nametoaddr libs in /etc/netconfig, this 41*0Sstevel@tonic-gate * implementation does NOT call the name service switch, it merely loops 42*0Sstevel@tonic-gate * through the nametoaddr libs. In this case, if this code was called 43*0Sstevel@tonic-gate * from gethost/servbyYY() we marshal the inet specific struct into 44*0Sstevel@tonic-gate * transport independent netbuf or hostserv, and unmarshal the resulting 45*0Sstevel@tonic-gate * nd_addrlist or hostservlist back into hostent and servent, as the case 46*0Sstevel@tonic-gate * may be. 47*0Sstevel@tonic-gate * 48*0Sstevel@tonic-gate * Goes without saying that most of the future bugs in gethost/servbyYY 49*0Sstevel@tonic-gate * and netdir_getbyYY are lurking somewhere here. 50*0Sstevel@tonic-gate */ 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate #include "mt.h" 55*0Sstevel@tonic-gate #include <ctype.h> 56*0Sstevel@tonic-gate #include <stdio.h> 57*0Sstevel@tonic-gate #include <stdlib.h> 58*0Sstevel@tonic-gate #include <string.h> 59*0Sstevel@tonic-gate #include <unistd.h> 60*0Sstevel@tonic-gate #include <stropts.h> 61*0Sstevel@tonic-gate #include <sys/types.h> 62*0Sstevel@tonic-gate #include <sys/byteorder.h> 63*0Sstevel@tonic-gate #include <sys/ioctl.h> 64*0Sstevel@tonic-gate #include <sys/param.h> 65*0Sstevel@tonic-gate #include <sys/time.h> 66*0Sstevel@tonic-gate #include <errno.h> 67*0Sstevel@tonic-gate #include <fcntl.h> 68*0Sstevel@tonic-gate #include <thread.h> 69*0Sstevel@tonic-gate #include <synch.h> 70*0Sstevel@tonic-gate #include <sys/utsname.h> 71*0Sstevel@tonic-gate #include <netdb.h> 72*0Sstevel@tonic-gate #include <netconfig.h> 73*0Sstevel@tonic-gate #include <netdir.h> 74*0Sstevel@tonic-gate #include <tiuser.h> 75*0Sstevel@tonic-gate #include <sys/socket.h> 76*0Sstevel@tonic-gate #include <sys/sockio.h> 77*0Sstevel@tonic-gate #include <netinet/in.h> 78*0Sstevel@tonic-gate #include <arpa/inet.h> 79*0Sstevel@tonic-gate #include <net/if.h> 80*0Sstevel@tonic-gate #include <inet/ip.h> 81*0Sstevel@tonic-gate #include <inet/ip6_asp.h> 82*0Sstevel@tonic-gate #include <sys/dlpi.h> 83*0Sstevel@tonic-gate #include <nss_dbdefs.h> 84*0Sstevel@tonic-gate #include <nss_netdir.h> 85*0Sstevel@tonic-gate #include <rpc/trace.h> 86*0Sstevel@tonic-gate #include <syslog.h> 87*0Sstevel@tonic-gate #include <nsswitch.h> 88*0Sstevel@tonic-gate #include "nss.h" 89*0Sstevel@tonic-gate #include "nsl_stdio_prv.h" 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate #define MAXIFS 32 92*0Sstevel@tonic-gate #define UDPDEV "/dev/udp" 93*0Sstevel@tonic-gate #define UDP6DEV "/dev/udp6" 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate #define GETHOSTBUF(host_buf) \ 96*0Sstevel@tonic-gate NSS_XbyY_ALLOC(&host_buf, sizeof (struct hostent), NSS_BUFLEN_HOSTS) 97*0Sstevel@tonic-gate #define GETSERVBUF(serv_buf) \ 98*0Sstevel@tonic-gate NSS_XbyY_ALLOC(&serv_buf, sizeof (struct servent), NSS_BUFLEN_SERVICES) 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #ifdef PIC 101*0Sstevel@tonic-gate #define DOOR_GETHOSTBYNAME_R _door_gethostbyname_r 102*0Sstevel@tonic-gate #define DOOR_GETHOSTBYADDR_R _door_gethostbyaddr_r 103*0Sstevel@tonic-gate #define DOOR_GETIPNODEBYNAME_R _door_getipnodebyname_r 104*0Sstevel@tonic-gate #define DOOR_GETIPNODEBYADDR_R _door_getipnodebyaddr_r 105*0Sstevel@tonic-gate #else 106*0Sstevel@tonic-gate #define DOOR_GETHOSTBYNAME_R _switch_gethostbyname_r 107*0Sstevel@tonic-gate #define DOOR_GETHOSTBYADDR_R _switch_gethostbyaddr_r 108*0Sstevel@tonic-gate #define DOOR_GETIPNODEBYNAME_R _switch_getipnodebyname_r 109*0Sstevel@tonic-gate #define DOOR_GETIPNODEBYADDR_R _switch_getipnodebyaddr_r 110*0Sstevel@tonic-gate #endif /* PIC */ 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate #define DONT_SORT "SORT_ADDRS=NO" 113*0Sstevel@tonic-gate #define DONT_SORT2 "SORT_ADDRS=FALSE" 114*0Sstevel@tonic-gate #define LINESIZE 100 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate /* 117*0Sstevel@tonic-gate * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT 118*0Sstevel@tonic-gate * and localhost. 119*0Sstevel@tonic-gate * 120*0Sstevel@tonic-gate * The following variables are static to the extent that they should 121*0Sstevel@tonic-gate * not be visible outside of this file. 122*0Sstevel@tonic-gate */ 123*0Sstevel@tonic-gate static char *localaddr[] = {"\000\000\000\000", NULL}; 124*0Sstevel@tonic-gate static char *connectaddr[] = {"\177\000\000\001", NULL}; 125*0Sstevel@tonic-gate static char *localaddr6[] = 126*0Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL}; 127*0Sstevel@tonic-gate static char *connectaddr6[] = 128*0Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL}; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* IPv4 nd_addrlist */ 131*0Sstevel@tonic-gate static mutex_t nd_addr_lock = DEFAULTMUTEX; 132*0Sstevel@tonic-gate static struct sockaddr_in sa_con; 133*0Sstevel@tonic-gate static struct netbuf nd_conbuf = {sizeof (sa_con),\ 134*0Sstevel@tonic-gate sizeof (sa_con), (char *)&sa_con}; 135*0Sstevel@tonic-gate static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf}; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* IPv6 nd_addrlist */ 138*0Sstevel@tonic-gate static mutex_t nd6_addr_lock = DEFAULTMUTEX; 139*0Sstevel@tonic-gate static struct sockaddr_in6 sa6_con; 140*0Sstevel@tonic-gate static struct netbuf nd6_conbuf = {sizeof (sa6_con),\ 141*0Sstevel@tonic-gate sizeof (sa6_con), (char *)&sa6_con}; 142*0Sstevel@tonic-gate static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf}; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate #define LOCALHOST "localhost" 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate struct servent *_switch_getservbyname_r(const char *, const char *, 147*0Sstevel@tonic-gate struct servent *, char *, int); 148*0Sstevel@tonic-gate struct servent *_switch_getservbyport_r(int, const char *, struct servent *, 149*0Sstevel@tonic-gate char *, int); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate static int __herrno2netdir(int h_errnop); 152*0Sstevel@tonic-gate static struct ifinfo *get_local_info(void); 153*0Sstevel@tonic-gate static int islocal(); 154*0Sstevel@tonic-gate static int getbroadcastnets(struct netconfig *, struct in_addr **); 155*0Sstevel@tonic-gate static int hent2ndaddr(int, char **, int *, struct nd_addrlist **); 156*0Sstevel@tonic-gate static int ndaddr2hent(int, const char *, struct nd_addrlist *, 157*0Sstevel@tonic-gate struct hostent *, char *, int); 158*0Sstevel@tonic-gate static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t, 159*0Sstevel@tonic-gate struct nd_hostservlist **); 160*0Sstevel@tonic-gate static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *, 161*0Sstevel@tonic-gate char *, int); 162*0Sstevel@tonic-gate static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *, 163*0Sstevel@tonic-gate struct hostent *, char *, int); 164*0Sstevel@tonic-gate static int ndhostserv2srent(int, const char *, struct nd_hostservlist *, 165*0Sstevel@tonic-gate struct servent *, char *, int); 166*0Sstevel@tonic-gate static int nd2herrno(int nerr); 167*0Sstevel@tonic-gate static void order_haddrlist_inet(char **haddrlist, size_t addrcount); 168*0Sstevel@tonic-gate static void order_haddrlist_inet6(char **haddrlist, size_t addrcount); 169*0Sstevel@tonic-gate static int dstcmp(const void *, const void *); 170*0Sstevel@tonic-gate static int nss_strioctl(int af, int cmd, void *ptr, int ilen); 171*0Sstevel@tonic-gate static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t); 172*0Sstevel@tonic-gate static boolean_t _read_nsw_file(void); 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * Begin: PART I 176*0Sstevel@tonic-gate * Top Level Interfaces that gethost/serv/netdir funnel through. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate /* 180*0Sstevel@tonic-gate * gethost/servbyname always call this function; if they call 181*0Sstevel@tonic-gate * with nametoaddr libs in nconf, we call netdir_getbyname 182*0Sstevel@tonic-gate * implementation: __classic_netdir_getbyname, otherwise nsswitch. 183*0Sstevel@tonic-gate * 184*0Sstevel@tonic-gate * netdir_getbyname calls this only if nametoaddr libs are NOT 185*0Sstevel@tonic-gate * specified for inet transports; i.e. it's supposed to follow 186*0Sstevel@tonic-gate * the name service switch. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate int 189*0Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(struct netconfig *nconf, 190*0Sstevel@tonic-gate struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate int server_port; 193*0Sstevel@tonic-gate int *servp = &server_port; 194*0Sstevel@tonic-gate char **haddrlist; 195*0Sstevel@tonic-gate uint32_t dotnameaddr; 196*0Sstevel@tonic-gate char *dotnamelist[2]; 197*0Sstevel@tonic-gate struct in_addr *inaddrs = NULL; 198*0Sstevel@tonic-gate struct in6_addr v6nameaddr; 199*0Sstevel@tonic-gate char **baddrlist = NULL; 200*0Sstevel@tonic-gate extern int _inet_aton(); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (nconf == NULL) { 204*0Sstevel@tonic-gate _nderror = ND_BADARG; 205*0Sstevel@tonic-gate return (ND_BADARG); 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * 1. gethostbyname()/netdir_getbyname() special cases: 210*0Sstevel@tonic-gate */ 211*0Sstevel@tonic-gate switch (args->op_t) { 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate case NSS_HOST: 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * Worth the performance gain -- assuming a lot of inet apps 216*0Sstevel@tonic-gate * actively use "localhost". 217*0Sstevel@tonic-gate */ 218*0Sstevel@tonic-gate if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) { 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate mutex_lock(&nd_addr_lock); 221*0Sstevel@tonic-gate IN_SET_LOOPBACK_ADDR(&sa_con); 222*0Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 223*0Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 224*0Sstevel@tonic-gate args->arg.nss.host.buf, 225*0Sstevel@tonic-gate args->arg.nss.host.buflen); 226*0Sstevel@tonic-gate mutex_unlock(&nd_addr_lock); 227*0Sstevel@tonic-gate if (_nderror != ND_OK) 228*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = 229*0Sstevel@tonic-gate nd2herrno(_nderror); 230*0Sstevel@tonic-gate return (_nderror); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate /* 233*0Sstevel@tonic-gate * If the caller passed in a dot separated IP notation to 234*0Sstevel@tonic-gate * gethostbyname, return that back as the address. 235*0Sstevel@tonic-gate * The nd_addr_lock mutex was added to be truely re-entrant. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate if (_inet_aton(args->arg.nss.host.name, 238*0Sstevel@tonic-gate (struct in_addr *)&dotnameaddr)) { 239*0Sstevel@tonic-gate mutex_lock(&nd_addr_lock); 240*0Sstevel@tonic-gate (void) memset((char *)&sa_con, 0, sizeof (sa_con)); 241*0Sstevel@tonic-gate sa_con.sin_family = AF_INET; 242*0Sstevel@tonic-gate sa_con.sin_addr.s_addr = dotnameaddr; 243*0Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name, 244*0Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 245*0Sstevel@tonic-gate args->arg.nss.host.buf, 246*0Sstevel@tonic-gate args->arg.nss.host.buflen); 247*0Sstevel@tonic-gate mutex_unlock(&nd_addr_lock); 248*0Sstevel@tonic-gate if (_nderror != ND_OK) 249*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = 250*0Sstevel@tonic-gate nd2herrno(_nderror); 251*0Sstevel@tonic-gate return (_nderror); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate break; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate case NSS_HOST6: 256*0Sstevel@tonic-gate /* 257*0Sstevel@tonic-gate * Handle case of literal address string. 258*0Sstevel@tonic-gate */ 259*0Sstevel@tonic-gate if (strchr(args->arg.nss.host6.name, ':') != NULL && 260*0Sstevel@tonic-gate (inet_pton(AF_INET6, args->arg.nss.host6.name, 261*0Sstevel@tonic-gate &v6nameaddr) != 0)) { 262*0Sstevel@tonic-gate int ret; 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate mutex_lock(&nd6_addr_lock); 265*0Sstevel@tonic-gate (void) memset((char *)&sa6_con, 0, sizeof (sa6_con)); 266*0Sstevel@tonic-gate sa6_con.sin6_family = AF_INET6; 267*0Sstevel@tonic-gate memcpy((char *)&(sa6_con.sin6_addr.s6_addr), 268*0Sstevel@tonic-gate &v6nameaddr, sizeof (struct in6_addr)); 269*0Sstevel@tonic-gate ret = ndaddr2hent(AF_INET6, 270*0Sstevel@tonic-gate args->arg.nss.host6.name, 271*0Sstevel@tonic-gate &nd6_conaddrlist, res->nss.host.hent, 272*0Sstevel@tonic-gate args->arg.nss.host6.buf, 273*0Sstevel@tonic-gate args->arg.nss.host6.buflen); 274*0Sstevel@tonic-gate mutex_unlock(&nd6_addr_lock); 275*0Sstevel@tonic-gate if (ret != ND_OK) 276*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(ret); 277*0Sstevel@tonic-gate else 278*0Sstevel@tonic-gate res->nss.host.hent->h_aliases = NULL; 279*0Sstevel@tonic-gate return (ret); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate break; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate case NETDIR_BY: 284*0Sstevel@tonic-gate if (args->arg.nd_hs == 0) { 285*0Sstevel@tonic-gate _nderror = ND_BADARG; 286*0Sstevel@tonic-gate return (ND_BADARG); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate /* 289*0Sstevel@tonic-gate * If servname is NULL, return 0 as the port number 290*0Sstevel@tonic-gate * If servname is rpcbind, return 111 as the port number 291*0Sstevel@tonic-gate * If servname is a number, return it back as the port 292*0Sstevel@tonic-gate * number. 293*0Sstevel@tonic-gate */ 294*0Sstevel@tonic-gate if (args->arg.nd_hs->h_serv == 0) { 295*0Sstevel@tonic-gate *servp = htons(0); 296*0Sstevel@tonic-gate } else if (strcmp(args->arg.nd_hs->h_serv, "rpcbind") 297*0Sstevel@tonic-gate == 0) { 298*0Sstevel@tonic-gate *servp = htons(111); 299*0Sstevel@tonic-gate } else if (strspn(args->arg.nd_hs->h_serv, "0123456789") 300*0Sstevel@tonic-gate == strlen(args->arg.nd_hs->h_serv)) { 301*0Sstevel@tonic-gate *servp = htons(atoi(args->arg.nd_hs->h_serv)); 302*0Sstevel@tonic-gate } else { 303*0Sstevel@tonic-gate /* i.e. need to call a name service on this */ 304*0Sstevel@tonic-gate servp = NULL; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * If the hostname is HOST_SELF_BIND, we return 0.0.0.0 309*0Sstevel@tonic-gate * so the binding can be contacted through all 310*0Sstevel@tonic-gate * interfaces. If the hostname is HOST_SELF_CONNECT, 311*0Sstevel@tonic-gate * we return 127.0.0.1 so the address can be connected 312*0Sstevel@tonic-gate * to locally. If the hostname is HOST_ANY, we return 313*0Sstevel@tonic-gate * no addresses because IP doesn't know how to specify 314*0Sstevel@tonic-gate * a service without a host. And finally if we specify 315*0Sstevel@tonic-gate * HOST_BROADCAST then we ask a tli fd to tell us what 316*0Sstevel@tonic-gate * the broadcast addresses are for any udp 317*0Sstevel@tonic-gate * interfaces on this machine. 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate if (args->arg.nd_hs->h_host == 0) { 320*0Sstevel@tonic-gate _nderror = ND_NOHOST; 321*0Sstevel@tonic-gate return (ND_NOHOST); 322*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 323*0Sstevel@tonic-gate HOST_SELF_BIND) == 0)) { 324*0Sstevel@tonic-gate haddrlist = localaddr; 325*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 326*0Sstevel@tonic-gate HOST_SELF_CONNECT) == 0)) { 327*0Sstevel@tonic-gate haddrlist = connectaddr; 328*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 329*0Sstevel@tonic-gate LOCALHOST) == 0)) { 330*0Sstevel@tonic-gate haddrlist = connectaddr; 331*0Sstevel@tonic-gate } else if ((int)(dotnameaddr = 332*0Sstevel@tonic-gate inet_addr(args->arg.nd_hs->h_host)) != -1) { 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * If the caller passed in a dot separated IP 335*0Sstevel@tonic-gate * notation to netdir_getbyname, convert that 336*0Sstevel@tonic-gate * back into address. 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate dotnamelist[0] = (char *)&dotnameaddr; 340*0Sstevel@tonic-gate dotnamelist[1] = NULL; 341*0Sstevel@tonic-gate haddrlist = dotnamelist; 342*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 343*0Sstevel@tonic-gate HOST_BROADCAST) == 0)) { 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * Now that inaddrs and baddrlist are 346*0Sstevel@tonic-gate * dynamically allocated, care must be 347*0Sstevel@tonic-gate * taken in freeing up the 348*0Sstevel@tonic-gate * memory at each 'return()' point. 349*0Sstevel@tonic-gate * 350*0Sstevel@tonic-gate * Early return protection (using 351*0Sstevel@tonic-gate * FREE_return()) is needed only in NETDIR_BY 352*0Sstevel@tonic-gate * cases because dynamic allocation is used 353*0Sstevel@tonic-gate * when args->op_t == NETDIR_BY. 354*0Sstevel@tonic-gate * 355*0Sstevel@tonic-gate * Early return protection is not needed in 356*0Sstevel@tonic-gate * haddrlist==0 conditionals because dynamic 357*0Sstevel@tonic-gate * allocation guarantees haddrlist!=0. 358*0Sstevel@tonic-gate * 359*0Sstevel@tonic-gate * Early return protection is not needed in most 360*0Sstevel@tonic-gate * servp!=0 conditionals because this is handled 361*0Sstevel@tonic-gate * (and returned) first. 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate #define FREE_return(ret) \ 364*0Sstevel@tonic-gate { \ 365*0Sstevel@tonic-gate if (inaddrs) \ 366*0Sstevel@tonic-gate free(inaddrs); \ 367*0Sstevel@tonic-gate if (baddrlist) \ 368*0Sstevel@tonic-gate free(baddrlist); \ 369*0Sstevel@tonic-gate _nderror = ret; \ 370*0Sstevel@tonic-gate return (ret); \ 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate int i, bnets; 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate bnets = getbroadcastnets(nconf, &inaddrs); 375*0Sstevel@tonic-gate if (bnets == 0) { 376*0Sstevel@tonic-gate _nderror = ND_NOHOST; 377*0Sstevel@tonic-gate return (ND_NOHOST); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate baddrlist = 380*0Sstevel@tonic-gate (char **)malloc((bnets+1)*sizeof (char *)); 381*0Sstevel@tonic-gate if (baddrlist == NULL) 382*0Sstevel@tonic-gate FREE_return(ND_NOMEM); 383*0Sstevel@tonic-gate for (i = 0; i < bnets; i++) 384*0Sstevel@tonic-gate baddrlist[i] = (char *)&inaddrs[i]; 385*0Sstevel@tonic-gate baddrlist[i] = NULL; 386*0Sstevel@tonic-gate haddrlist = baddrlist; 387*0Sstevel@tonic-gate } else { 388*0Sstevel@tonic-gate /* i.e. need to call a name service on this */ 389*0Sstevel@tonic-gate haddrlist = 0; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if (haddrlist && servp) { 393*0Sstevel@tonic-gate int ret; 394*0Sstevel@tonic-gate /* 395*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 396*0Sstevel@tonic-gate * malloc's will be done, freed using 397*0Sstevel@tonic-gate * netdir_free. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, haddrlist, servp, 400*0Sstevel@tonic-gate res->nd_alist); 401*0Sstevel@tonic-gate FREE_return(ret) 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate break; 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate case NETDIR_BY6: 407*0Sstevel@tonic-gate if (args->arg.nd_hs == 0) { 408*0Sstevel@tonic-gate _nderror = ND_BADARG; 409*0Sstevel@tonic-gate return (ND_BADARG); 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * If servname is NULL, return 0 as the port number. 413*0Sstevel@tonic-gate * If servname is rpcbind, return 111 as the port number 414*0Sstevel@tonic-gate * If servname is a number, return it back as the port 415*0Sstevel@tonic-gate * number. 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate if (args->arg.nd_hs->h_serv == 0) { 418*0Sstevel@tonic-gate *servp = htons(0); 419*0Sstevel@tonic-gate } else if (strcmp(args->arg.nd_hs->h_serv, 420*0Sstevel@tonic-gate "rpcbind") == 0) { 421*0Sstevel@tonic-gate *servp = htons(111); 422*0Sstevel@tonic-gate } else if (strspn(args->arg.nd_hs->h_serv, "0123456789") 423*0Sstevel@tonic-gate == strlen(args->arg.nd_hs->h_serv)) { 424*0Sstevel@tonic-gate *servp = htons(atoi(args->arg.nd_hs->h_serv)); 425*0Sstevel@tonic-gate } else { 426*0Sstevel@tonic-gate /* i.e. need to call a name service on this */ 427*0Sstevel@tonic-gate servp = NULL; 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * If the hostname is HOST_SELF_BIND, we return ipv6 432*0Sstevel@tonic-gate * localaddress so the binding can be contacted through 433*0Sstevel@tonic-gate * all interfaces. 434*0Sstevel@tonic-gate * If the hostname is HOST_SELF_CONNECT, we return 435*0Sstevel@tonic-gate * ipv6 loopback address so the address can be connected 436*0Sstevel@tonic-gate * to locally. 437*0Sstevel@tonic-gate * If the hostname is HOST_ANY, we return no addresses 438*0Sstevel@tonic-gate * because IP doesn't know how to specify a service 439*0Sstevel@tonic-gate * without a host. 440*0Sstevel@tonic-gate * And finally if we specify HOST_BROADCAST then we 441*0Sstevel@tonic-gate * disallow since IPV6 does not have any 442*0Sstevel@tonic-gate * broadcast concept. 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate if (args->arg.nd_hs->h_host == 0) { 445*0Sstevel@tonic-gate return (ND_NOHOST); 446*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 447*0Sstevel@tonic-gate HOST_SELF_BIND) == 0)) { 448*0Sstevel@tonic-gate haddrlist = localaddr6; 449*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 450*0Sstevel@tonic-gate HOST_SELF_CONNECT) == 0)) { 451*0Sstevel@tonic-gate haddrlist = connectaddr6; 452*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 453*0Sstevel@tonic-gate LOCALHOST) == 0)) { 454*0Sstevel@tonic-gate haddrlist = connectaddr6; 455*0Sstevel@tonic-gate } else if (strchr(args->arg.nd_hs->h_host, ':') 456*0Sstevel@tonic-gate != NULL) { 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * If the caller passed in a dot separated IP notation 460*0Sstevel@tonic-gate * to netdir_getbyname, convert that back into address. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if ((inet_pton(AF_INET6, 464*0Sstevel@tonic-gate args->arg.nd_hs->h_host, 465*0Sstevel@tonic-gate &v6nameaddr)) != 0) { 466*0Sstevel@tonic-gate dotnamelist[0] = (char *)&v6nameaddr; 467*0Sstevel@tonic-gate dotnamelist[1] = NULL; 468*0Sstevel@tonic-gate haddrlist = dotnamelist; 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate else 471*0Sstevel@tonic-gate /* not sure what to return */ 472*0Sstevel@tonic-gate return (ND_NOHOST); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate } else if ((strcmp(args->arg.nd_hs->h_host, 475*0Sstevel@tonic-gate HOST_BROADCAST) == 0)) { 476*0Sstevel@tonic-gate /* 477*0Sstevel@tonic-gate * Don't support broadcast in 478*0Sstevel@tonic-gate * IPV6 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate return (ND_NOHOST); 481*0Sstevel@tonic-gate } else { 482*0Sstevel@tonic-gate /* i.e. need to call a name service on this */ 483*0Sstevel@tonic-gate haddrlist = 0; 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (haddrlist && servp) { 487*0Sstevel@tonic-gate int ret; 488*0Sstevel@tonic-gate /* 489*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 490*0Sstevel@tonic-gate * malloc's will be done, freed 491*0Sstevel@tonic-gate * using netdir_free. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, haddrlist, 494*0Sstevel@tonic-gate servp, res->nd_alist); 495*0Sstevel@tonic-gate FREE_return(ret) 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate break; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* 503*0Sstevel@tonic-gate * 2. Most common scenario. This is the way we ship /etc/netconfig. 504*0Sstevel@tonic-gate * Emphasis on improving performance in the "if" part. 505*0Sstevel@tonic-gate */ 506*0Sstevel@tonic-gate if (nconf->nc_nlookups == 0) { 507*0Sstevel@tonic-gate struct hostent *he = NULL, *tmphe; 508*0Sstevel@tonic-gate struct servent *se; 509*0Sstevel@tonic-gate int ret; 510*0Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4switch = 0; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate switch (args->op_t) { 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate case NSS_HOST: 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name, 517*0Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 518*0Sstevel@tonic-gate args->arg.nss.host.buflen, 519*0Sstevel@tonic-gate res->nss.host.herrno_p); 520*0Sstevel@tonic-gate if (he == NULL) 521*0Sstevel@tonic-gate return (_nderror = ND_NOHOST); 522*0Sstevel@tonic-gate return (_nderror = ND_OK); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate case NSS_HOST6: 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name, 527*0Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 528*0Sstevel@tonic-gate args->arg.nss.host6.buflen, 529*0Sstevel@tonic-gate args->arg.nss.host6.af_family, 530*0Sstevel@tonic-gate args->arg.nss.host6.flags, 531*0Sstevel@tonic-gate res->nss.host.herrno_p); 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate if (he == NULL) { 534*0Sstevel@tonic-gate trace1(TR__get_hostserv_inetnetdir_byname, 12); 535*0Sstevel@tonic-gate return (_nderror = ND_NOHOST); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate return (_nderror = ND_OK); 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate case NSS_SERV: 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate se = _switch_getservbyname_r(args->arg.nss.serv.name, 542*0Sstevel@tonic-gate args->arg.nss.serv.proto, 543*0Sstevel@tonic-gate res->nss.serv, args->arg.nss.serv.buf, 544*0Sstevel@tonic-gate args->arg.nss.serv.buflen); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate _nderror = ND_OK; 547*0Sstevel@tonic-gate if (se == 0) 548*0Sstevel@tonic-gate _nderror = ND_NOSERV; 549*0Sstevel@tonic-gate return (_nderror); 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate case NETDIR_BY: 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (servp == 0) { 554*0Sstevel@tonic-gate char *proto = 555*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* 558*0Sstevel@tonic-gate * We go through all this for just one port number, 559*0Sstevel@tonic-gate * which is most often constant. How about linking in 560*0Sstevel@tonic-gate * an indexed database of well-known ports in the name 561*0Sstevel@tonic-gate * of performance ? 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate GETSERVBUF(ndbuf4switch); 564*0Sstevel@tonic-gate if (ndbuf4switch == 0) 565*0Sstevel@tonic-gate FREE_return(ND_NOMEM); 566*0Sstevel@tonic-gate se = _switch_getservbyname_r(args->arg.nd_hs->h_serv, 567*0Sstevel@tonic-gate proto, ndbuf4switch->result, 568*0Sstevel@tonic-gate ndbuf4switch->buffer, ndbuf4switch->buflen); 569*0Sstevel@tonic-gate if (!se) { 570*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 571*0Sstevel@tonic-gate FREE_return(ND_NOSERV) 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate server_port = se->s_port; 574*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate if (haddrlist == 0) { 578*0Sstevel@tonic-gate int h_errnop = 0; 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate GETHOSTBUF(ndbuf4switch); 581*0Sstevel@tonic-gate if (ndbuf4switch == 0) { 582*0Sstevel@tonic-gate _nderror = ND_NOMEM; 583*0Sstevel@tonic-gate return (ND_NOMEM); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * Search the ipnodes (v6) path first, 587*0Sstevel@tonic-gate * search will return the v4 addresses 588*0Sstevel@tonic-gate * as v4mapped addresses. 589*0Sstevel@tonic-gate */ 590*0Sstevel@tonic-gate if ((tmphe = DOOR_GETIPNODEBYNAME_R( 591*0Sstevel@tonic-gate args->arg.nd_hs->h_host, 592*0Sstevel@tonic-gate ndbuf4switch->result, ndbuf4switch->buffer, 593*0Sstevel@tonic-gate ndbuf4switch->buflen, args->arg.nss.host6.af_family, 594*0Sstevel@tonic-gate args->arg.nss.host6.flags, &h_errnop)) != NULL) 595*0Sstevel@tonic-gate he = __mappedtov4(tmphe, &h_errnop); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate if (he == NULL) { 598*0Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 599*0Sstevel@tonic-gate he = DOOR_GETHOSTBYNAME_R( 600*0Sstevel@tonic-gate args->arg.nd_hs->h_host, 601*0Sstevel@tonic-gate ndbuf4switch->result, ndbuf4switch->buffer, 602*0Sstevel@tonic-gate ndbuf4switch->buflen, &h_errnop); 603*0Sstevel@tonic-gate if (he == NULL) { 604*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 605*0Sstevel@tonic-gate _nderror = h_errnop ? 606*0Sstevel@tonic-gate __herrno2netdir(h_errnop) : 607*0Sstevel@tonic-gate ND_NOHOST; 608*0Sstevel@tonic-gate return (_nderror); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate /* 611*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 612*0Sstevel@tonic-gate * malloc's will be done, freed using 613*0Sstevel@tonic-gate * netdir_free. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, he->h_addr_list, 616*0Sstevel@tonic-gate &server_port, res->nd_alist); 617*0Sstevel@tonic-gate } else { 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 620*0Sstevel@tonic-gate * malloc's will be done, freed using 621*0Sstevel@tonic-gate * netdir_free. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, he->h_addr_list, 624*0Sstevel@tonic-gate &server_port, res->nd_alist); 625*0Sstevel@tonic-gate freehostent(he); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate _nderror = ret; 629*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 630*0Sstevel@tonic-gate return (ret); 631*0Sstevel@tonic-gate } else { 632*0Sstevel@tonic-gate int ret; 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 635*0Sstevel@tonic-gate * malloc's will be done, freed using netdir_free. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET, haddrlist, 638*0Sstevel@tonic-gate &server_port, res->nd_alist); 639*0Sstevel@tonic-gate FREE_return(ret) 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate case NETDIR_BY6: 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate if (servp == 0) { 646*0Sstevel@tonic-gate char *proto = 647*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * We go through all this for just 651*0Sstevel@tonic-gate * one port number, 652*0Sstevel@tonic-gate * which is most often constant. 653*0Sstevel@tonic-gate * How about linking in 654*0Sstevel@tonic-gate * an indexed database of well-known 655*0Sstevel@tonic-gate * ports in the name 656*0Sstevel@tonic-gate * of performance ? 657*0Sstevel@tonic-gate */ 658*0Sstevel@tonic-gate GETSERVBUF(ndbuf4switch); 659*0Sstevel@tonic-gate if (ndbuf4switch == 0) 660*0Sstevel@tonic-gate FREE_return(ND_NOMEM); 661*0Sstevel@tonic-gate se = _switch_getservbyname_r( 662*0Sstevel@tonic-gate args->arg.nd_hs->h_serv, 663*0Sstevel@tonic-gate proto, ndbuf4switch->result, 664*0Sstevel@tonic-gate ndbuf4switch->buffer, ndbuf4switch->buflen); 665*0Sstevel@tonic-gate if (!se) { 666*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 667*0Sstevel@tonic-gate FREE_return(ND_NOSERV) 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate server_port = se->s_port; 670*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if (haddrlist == 0) { 674*0Sstevel@tonic-gate int h_errnop = 0; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate GETHOSTBUF(ndbuf4switch); 677*0Sstevel@tonic-gate if (ndbuf4switch == 0) { 678*0Sstevel@tonic-gate _nderror = ND_NOMEM; 679*0Sstevel@tonic-gate return (ND_NOMEM); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate he = DOOR_GETIPNODEBYNAME_R( 682*0Sstevel@tonic-gate args->arg.nd_hs->h_host, 683*0Sstevel@tonic-gate ndbuf4switch->result, ndbuf4switch->buffer, 684*0Sstevel@tonic-gate ndbuf4switch->buflen, 685*0Sstevel@tonic-gate args->arg.nss.host6.af_family, 686*0Sstevel@tonic-gate args->arg.nss.host6.flags, &h_errnop); 687*0Sstevel@tonic-gate if (he == NULL) { 688*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 689*0Sstevel@tonic-gate _nderror = h_errnop ? 690*0Sstevel@tonic-gate __herrno2netdir(h_errnop) : 691*0Sstevel@tonic-gate ND_NOHOST; 692*0Sstevel@tonic-gate return (_nderror); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate /* 695*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 696*0Sstevel@tonic-gate * malloc's will be done, 697*0Sstevel@tonic-gate * freed using netdir_free. 698*0Sstevel@tonic-gate */ 699*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, 700*0Sstevel@tonic-gate ((struct hostent *)(ndbuf4switch->result))->h_addr_list, 701*0Sstevel@tonic-gate &server_port, res->nd_alist); 702*0Sstevel@tonic-gate _nderror = ret; 703*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4switch); 704*0Sstevel@tonic-gate return (ret); 705*0Sstevel@tonic-gate } else { 706*0Sstevel@tonic-gate int ret; 707*0Sstevel@tonic-gate /* 708*0Sstevel@tonic-gate * Convert h_addr_list into nd_addrlist. 709*0Sstevel@tonic-gate * malloc's will be done, 710*0Sstevel@tonic-gate * freed using netdir_free. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate ret = hent2ndaddr(AF_INET6, haddrlist, 713*0Sstevel@tonic-gate &server_port, res->nd_alist); 714*0Sstevel@tonic-gate FREE_return(ret) 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate default: 718*0Sstevel@tonic-gate _nderror = ND_BADARG; 719*0Sstevel@tonic-gate return (ND_BADARG); /* should never happen */ 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate } else { 723*0Sstevel@tonic-gate /* haddrlist is no longer used, so clean up */ 724*0Sstevel@tonic-gate if (inaddrs) 725*0Sstevel@tonic-gate free(inaddrs); 726*0Sstevel@tonic-gate if (baddrlist) 727*0Sstevel@tonic-gate free(baddrlist); 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate /* 731*0Sstevel@tonic-gate * 3. We come this far only if nametoaddr libs are specified for 732*0Sstevel@tonic-gate * inet transports and we are called by gethost/servbyname only. 733*0Sstevel@tonic-gate */ 734*0Sstevel@tonic-gate switch (args->op_t) { 735*0Sstevel@tonic-gate struct nd_hostserv service; 736*0Sstevel@tonic-gate struct nd_addrlist *addrs; 737*0Sstevel@tonic-gate int ret; 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate case NSS_HOST: 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate service.h_host = (char *)args->arg.nss.host.name; 742*0Sstevel@tonic-gate service.h_serv = NULL; 743*0Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyname(nconf, 744*0Sstevel@tonic-gate &service, &addrs)) != ND_OK) { 745*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 746*0Sstevel@tonic-gate return (_nderror); 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate /* 749*0Sstevel@tonic-gate * convert addresses back into sockaddr for gethostbyname. 750*0Sstevel@tonic-gate */ 751*0Sstevel@tonic-gate ret = ndaddr2hent(AF_INET, service.h_host, addrs, 752*0Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 753*0Sstevel@tonic-gate args->arg.nss.host.buflen); 754*0Sstevel@tonic-gate if (ret != ND_OK) 755*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(ret); 756*0Sstevel@tonic-gate netdir_free((char *)addrs, ND_ADDRLIST); 757*0Sstevel@tonic-gate _nderror = ret; 758*0Sstevel@tonic-gate return (ret); 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate case NSS_SERV: 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate if (args->arg.nss.serv.proto == NULL) { 763*0Sstevel@tonic-gate /* 764*0Sstevel@tonic-gate * A similar HACK showed up in Solaris 2.3. 765*0Sstevel@tonic-gate * The caller wild-carded proto -- i.e. will 766*0Sstevel@tonic-gate * accept a match using tcp or udp for the port 767*0Sstevel@tonic-gate * number. Since we have no hope of getting 768*0Sstevel@tonic-gate * directly to a name service switch backend 769*0Sstevel@tonic-gate * from here that understands this semantics, 770*0Sstevel@tonic-gate * we try calling the netdir interfaces first 771*0Sstevel@tonic-gate * with "tcp" and then "udp". 772*0Sstevel@tonic-gate */ 773*0Sstevel@tonic-gate args->arg.nss.serv.proto = "tcp"; 774*0Sstevel@tonic-gate _nderror = _get_hostserv_inetnetdir_byname(nconf, args, 775*0Sstevel@tonic-gate res); 776*0Sstevel@tonic-gate if (_nderror != ND_OK) { 777*0Sstevel@tonic-gate args->arg.nss.serv.proto = "udp"; 778*0Sstevel@tonic-gate _nderror = 779*0Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(nconf, 780*0Sstevel@tonic-gate args, res); 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate return (_nderror); 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* 786*0Sstevel@tonic-gate * Third-parties should optimize their nametoaddr 787*0Sstevel@tonic-gate * libraries for the HOST_SELF case. 788*0Sstevel@tonic-gate */ 789*0Sstevel@tonic-gate service.h_host = HOST_SELF; 790*0Sstevel@tonic-gate service.h_serv = (char *)args->arg.nss.serv.name; 791*0Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyname(nconf, 792*0Sstevel@tonic-gate &service, &addrs)) != ND_OK) { 793*0Sstevel@tonic-gate return (_nderror); 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate /* 796*0Sstevel@tonic-gate * convert addresses back into servent for getservbyname. 797*0Sstevel@tonic-gate */ 798*0Sstevel@tonic-gate _nderror = ndaddr2srent(service.h_serv, 799*0Sstevel@tonic-gate args->arg.nss.serv.proto, 800*0Sstevel@tonic-gate ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port, 801*0Sstevel@tonic-gate res->nss.serv, 802*0Sstevel@tonic-gate args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 803*0Sstevel@tonic-gate netdir_free((char *)addrs, ND_ADDRLIST); 804*0Sstevel@tonic-gate return (_nderror); 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate default: 807*0Sstevel@tonic-gate _nderror = ND_BADARG; 808*0Sstevel@tonic-gate return (ND_BADARG); /* should never happen */ 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate } 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate /* 813*0Sstevel@tonic-gate * gethostbyaddr/servbyport always call this function; if they call 814*0Sstevel@tonic-gate * with nametoaddr libs in nconf, we call netdir_getbyaddr 815*0Sstevel@tonic-gate * implementation __classic_netdir_getbyaddr, otherwise nsswitch. 816*0Sstevel@tonic-gate * 817*0Sstevel@tonic-gate * netdir_getbyaddr calls this only if nametoaddr libs are NOT 818*0Sstevel@tonic-gate * specified for inet transports; i.e. it's supposed to follow 819*0Sstevel@tonic-gate * the name service switch. 820*0Sstevel@tonic-gate */ 821*0Sstevel@tonic-gate int 822*0Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf, 823*0Sstevel@tonic-gate struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res) 824*0Sstevel@tonic-gate { 825*0Sstevel@tonic-gate if (nconf == 0) { 826*0Sstevel@tonic-gate _nderror = ND_BADARG; 827*0Sstevel@tonic-gate return (_nderror); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* 831*0Sstevel@tonic-gate * 1. gethostbyaddr()/netdir_getbyaddr() special cases: 832*0Sstevel@tonic-gate */ 833*0Sstevel@tonic-gate switch (args->op_t) { 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate case NSS_HOST: 836*0Sstevel@tonic-gate /* 837*0Sstevel@tonic-gate * Worth the performance gain: assuming a lot of inet apps 838*0Sstevel@tonic-gate * actively use "127.0.0.1". 839*0Sstevel@tonic-gate */ 840*0Sstevel@tonic-gate if (*(uint32_t *)(args->arg.nss.host.addr) == 841*0Sstevel@tonic-gate htonl(INADDR_LOOPBACK)) { 842*0Sstevel@tonic-gate mutex_lock(&nd_addr_lock); 843*0Sstevel@tonic-gate IN_SET_LOOPBACK_ADDR(&sa_con); 844*0Sstevel@tonic-gate _nderror = ndaddr2hent(AF_INET, LOCALHOST, 845*0Sstevel@tonic-gate &nd_conaddrlist, res->nss.host.hent, 846*0Sstevel@tonic-gate args->arg.nss.host.buf, 847*0Sstevel@tonic-gate args->arg.nss.host.buflen); 848*0Sstevel@tonic-gate mutex_unlock(&nd_addr_lock); 849*0Sstevel@tonic-gate if (_nderror != ND_OK) 850*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = 851*0Sstevel@tonic-gate nd2herrno(_nderror); 852*0Sstevel@tonic-gate return (_nderror); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate break; 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate case NETDIR_BY: 857*0Sstevel@tonic-gate case NETDIR_BY_NOSRV: 858*0Sstevel@tonic-gate { 859*0Sstevel@tonic-gate struct sockaddr_in *sin; 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate if (args->arg.nd_nbuf == NULL) { 862*0Sstevel@tonic-gate _nderror = ND_BADARG; 863*0Sstevel@tonic-gate return (_nderror); 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate /* 867*0Sstevel@tonic-gate * Validate the address which was passed 868*0Sstevel@tonic-gate * as the request. 869*0Sstevel@tonic-gate */ 870*0Sstevel@tonic-gate sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if ((args->arg.nd_nbuf->len != 873*0Sstevel@tonic-gate sizeof (struct sockaddr_in)) || 874*0Sstevel@tonic-gate (sin->sin_family != AF_INET)) { 875*0Sstevel@tonic-gate _nderror = ND_BADARG; 876*0Sstevel@tonic-gate return (_nderror); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate } 879*0Sstevel@tonic-gate break; 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate case NETDIR_BY6: 882*0Sstevel@tonic-gate case NETDIR_BY_NOSRV6: 883*0Sstevel@tonic-gate { 884*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate if (args->arg.nd_nbuf == NULL) { 887*0Sstevel@tonic-gate _nderror = ND_BADARG; 888*0Sstevel@tonic-gate return (_nderror); 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate /* 892*0Sstevel@tonic-gate * Validate the address which was passed 893*0Sstevel@tonic-gate * as the request. 894*0Sstevel@tonic-gate */ 895*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf; 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate if ((args->arg.nd_nbuf->len != 898*0Sstevel@tonic-gate sizeof (struct sockaddr_in6)) || 899*0Sstevel@tonic-gate (sin6->sin6_family != AF_INET6)) { 900*0Sstevel@tonic-gate _nderror = ND_BADARG; 901*0Sstevel@tonic-gate return (_nderror); 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate break; 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate /* 909*0Sstevel@tonic-gate * 2. Most common scenario. This is the way we ship /etc/netconfig. 910*0Sstevel@tonic-gate * Emphasis on improving performance in the "if" part. 911*0Sstevel@tonic-gate */ 912*0Sstevel@tonic-gate if (nconf->nc_nlookups == 0) { 913*0Sstevel@tonic-gate struct hostent *he = NULL, *tmphe; 914*0Sstevel@tonic-gate struct servent *se = NULL; 915*0Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4host = 0; 916*0Sstevel@tonic-gate nss_XbyY_buf_t *ndbuf4serv = 0; 917*0Sstevel@tonic-gate char *proto = 918*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP; 919*0Sstevel@tonic-gate struct sockaddr_in *sa; 920*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 921*0Sstevel@tonic-gate struct in_addr *addr4 = 0; 922*0Sstevel@tonic-gate struct in6_addr v4mapbuf; 923*0Sstevel@tonic-gate int h_errnop; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate switch (args->op_t) { 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate case NSS_HOST: 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr, 930*0Sstevel@tonic-gate args->arg.nss.host.len, args->arg.nss.host.type, 931*0Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 932*0Sstevel@tonic-gate args->arg.nss.host.buflen, 933*0Sstevel@tonic-gate res->nss.host.herrno_p); 934*0Sstevel@tonic-gate if (he == 0) 935*0Sstevel@tonic-gate _nderror = ND_NOHOST; 936*0Sstevel@tonic-gate else 937*0Sstevel@tonic-gate _nderror = ND_OK; 938*0Sstevel@tonic-gate return (_nderror); 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate case NSS_HOST6: 942*0Sstevel@tonic-gate he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr, 943*0Sstevel@tonic-gate args->arg.nss.host.len, args->arg.nss.host.type, 944*0Sstevel@tonic-gate res->nss.host.hent, args->arg.nss.host.buf, 945*0Sstevel@tonic-gate args->arg.nss.host.buflen, 946*0Sstevel@tonic-gate res->nss.host.herrno_p); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if (he == 0) 949*0Sstevel@tonic-gate return (ND_NOHOST); 950*0Sstevel@tonic-gate return (ND_OK); 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate case NSS_SERV: 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate se = _switch_getservbyport_r(args->arg.nss.serv.port, 956*0Sstevel@tonic-gate args->arg.nss.serv.proto, 957*0Sstevel@tonic-gate res->nss.serv, args->arg.nss.serv.buf, 958*0Sstevel@tonic-gate args->arg.nss.serv.buflen); 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate if (se == 0) 961*0Sstevel@tonic-gate _nderror = ND_NOSERV; 962*0Sstevel@tonic-gate else 963*0Sstevel@tonic-gate _nderror = ND_OK; 964*0Sstevel@tonic-gate return (_nderror); 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate case NETDIR_BY: 967*0Sstevel@tonic-gate case NETDIR_BY_NOSRV: 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate GETSERVBUF(ndbuf4serv); 970*0Sstevel@tonic-gate if (ndbuf4serv == 0) { 971*0Sstevel@tonic-gate _nderror = ND_NOMEM; 972*0Sstevel@tonic-gate return (_nderror); 973*0Sstevel@tonic-gate } 974*0Sstevel@tonic-gate sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf); 975*0Sstevel@tonic-gate addr4 = (struct in_addr *)&(sa->sin_addr); 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate /* 978*0Sstevel@tonic-gate * if NETDIR_BY_NOSRV or port == 0 skip the service 979*0Sstevel@tonic-gate * lookup. 980*0Sstevel@tonic-gate */ 981*0Sstevel@tonic-gate if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) { 982*0Sstevel@tonic-gate se = _switch_getservbyport_r(sa->sin_port, proto, 983*0Sstevel@tonic-gate ndbuf4serv->result, ndbuf4serv->buffer, 984*0Sstevel@tonic-gate ndbuf4serv->buflen); 985*0Sstevel@tonic-gate if (!se) { 986*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 987*0Sstevel@tonic-gate /* 988*0Sstevel@tonic-gate * We can live with this - i.e. the address 989*0Sstevel@tonic-gate * does not 990*0Sstevel@tonic-gate * belong to a well known service. The caller 991*0Sstevel@tonic-gate * traditionally accepts a stringified port 992*0Sstevel@tonic-gate * number 993*0Sstevel@tonic-gate * as the service name. The state of se is used 994*0Sstevel@tonic-gate * ahead to indicate the same. 995*0Sstevel@tonic-gate * However, we do not tolerate this nonsense 996*0Sstevel@tonic-gate * when we cannot get a host name. See below. 997*0Sstevel@tonic-gate */ 998*0Sstevel@tonic-gate } 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate GETHOSTBUF(ndbuf4host); 1002*0Sstevel@tonic-gate if (ndbuf4host == 0) { 1003*0Sstevel@tonic-gate if (ndbuf4serv) 1004*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1005*0Sstevel@tonic-gate _nderror = ND_NOMEM; 1006*0Sstevel@tonic-gate return (_nderror); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate /* 1010*0Sstevel@tonic-gate * Since we're going to search the ipnodes (v6) path first, 1011*0Sstevel@tonic-gate * we need to treat the address as a v4mapped address. 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf); 1015*0Sstevel@tonic-gate if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf, 1016*0Sstevel@tonic-gate 16, AF_INET6, ndbuf4host->result, 1017*0Sstevel@tonic-gate ndbuf4host->buffer, 1018*0Sstevel@tonic-gate ndbuf4host->buflen, &h_errnop)) != NULL) 1019*0Sstevel@tonic-gate he = __mappedtov4(tmphe, &h_errnop); 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate if (!he) { 1022*0Sstevel@tonic-gate /* Failover case, try hosts db for v4 address */ 1023*0Sstevel@tonic-gate he = DOOR_GETHOSTBYADDR_R((char *) 1024*0Sstevel@tonic-gate &(sa->sin_addr.s_addr), 4, 1025*0Sstevel@tonic-gate sa->sin_family, ndbuf4host->result, 1026*0Sstevel@tonic-gate ndbuf4host->buffer, ndbuf4host->buflen, 1027*0Sstevel@tonic-gate &h_errnop); 1028*0Sstevel@tonic-gate if (!he) { 1029*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 1030*0Sstevel@tonic-gate if (ndbuf4serv) 1031*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1032*0Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 1033*0Sstevel@tonic-gate return (_nderror); 1034*0Sstevel@tonic-gate } 1035*0Sstevel@tonic-gate /* 1036*0Sstevel@tonic-gate * Convert host names and service names into hostserv 1037*0Sstevel@tonic-gate * pairs. malloc's will be done, freed using 1038*0Sstevel@tonic-gate * netdir_free. 1039*0Sstevel@tonic-gate */ 1040*0Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 1041*0Sstevel@tonic-gate sa->sin_port, res->nd_hslist); 1042*0Sstevel@tonic-gate } else { 1043*0Sstevel@tonic-gate /* 1044*0Sstevel@tonic-gate * Convert host names and service names into hostserv 1045*0Sstevel@tonic-gate * pairs. malloc's will be done, freed using 1046*0Sstevel@tonic-gate * netdir_free. 1047*0Sstevel@tonic-gate */ 1048*0Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 1049*0Sstevel@tonic-gate sa->sin_port, res->nd_hslist); 1050*0Sstevel@tonic-gate freehostent(he); 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 1054*0Sstevel@tonic-gate if (ndbuf4serv) 1055*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1056*0Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 1057*0Sstevel@tonic-gate return (_nderror); 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate case NETDIR_BY6: 1060*0Sstevel@tonic-gate case NETDIR_BY_NOSRV6: 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate GETSERVBUF(ndbuf4serv); 1063*0Sstevel@tonic-gate if (ndbuf4serv == 0) { 1064*0Sstevel@tonic-gate _nderror = ND_NOMEM; 1065*0Sstevel@tonic-gate return (ND_NOMEM); 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf); 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate /* 1070*0Sstevel@tonic-gate * if NETDIR_BY_NOSRV6 or port == 0 skip the service 1071*0Sstevel@tonic-gate * lookup. 1072*0Sstevel@tonic-gate */ 1073*0Sstevel@tonic-gate if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) { 1074*0Sstevel@tonic-gate se = _switch_getservbyport_r(sin6->sin6_port, proto, 1075*0Sstevel@tonic-gate ndbuf4serv->result, ndbuf4serv->buffer, 1076*0Sstevel@tonic-gate ndbuf4serv->buflen); 1077*0Sstevel@tonic-gate if (!se) { 1078*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1079*0Sstevel@tonic-gate /* 1080*0Sstevel@tonic-gate * We can live with this - i.e. the address does 1081*0Sstevel@tonic-gate * not * belong to a well known service. The 1082*0Sstevel@tonic-gate * caller traditionally accepts a stringified 1083*0Sstevel@tonic-gate * port number 1084*0Sstevel@tonic-gate * as the service name. The state of se is used 1085*0Sstevel@tonic-gate * ahead to indicate the same. 1086*0Sstevel@tonic-gate * However, we do not tolerate this nonsense 1087*0Sstevel@tonic-gate * when we cannot get a host name. See below. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate GETHOSTBUF(ndbuf4host); 1093*0Sstevel@tonic-gate if (ndbuf4host == 0) { 1094*0Sstevel@tonic-gate if (ndbuf4serv) 1095*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1096*0Sstevel@tonic-gate _nderror = ND_NOMEM; 1097*0Sstevel@tonic-gate return (_nderror); 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr), 1100*0Sstevel@tonic-gate 16, sin6->sin6_family, ndbuf4host->result, 1101*0Sstevel@tonic-gate ndbuf4host->buffer, 1102*0Sstevel@tonic-gate ndbuf4host->buflen, &h_errnop); 1103*0Sstevel@tonic-gate if (!he) { 1104*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 1105*0Sstevel@tonic-gate if (ndbuf4serv) 1106*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1107*0Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 1108*0Sstevel@tonic-gate return (_nderror); 1109*0Sstevel@tonic-gate } 1110*0Sstevel@tonic-gate /* 1111*0Sstevel@tonic-gate * Convert host names and service names into hostserv 1112*0Sstevel@tonic-gate * pairs. malloc's will be done, freed using netdir_free. 1113*0Sstevel@tonic-gate */ 1114*0Sstevel@tonic-gate h_errnop = hsents2ndhostservs(he, se, 1115*0Sstevel@tonic-gate sin6->sin6_port, res->nd_hslist); 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4host); 1118*0Sstevel@tonic-gate if (ndbuf4serv) 1119*0Sstevel@tonic-gate NSS_XbyY_FREE(&ndbuf4serv); 1120*0Sstevel@tonic-gate _nderror = __herrno2netdir(h_errnop); 1121*0Sstevel@tonic-gate return (_nderror); 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate default: 1124*0Sstevel@tonic-gate _nderror = ND_BADARG; 1125*0Sstevel@tonic-gate return (_nderror); /* should never happen */ 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate } 1129*0Sstevel@tonic-gate /* 1130*0Sstevel@tonic-gate * 3. We come this far only if nametoaddr libs are specified for 1131*0Sstevel@tonic-gate * inet transports and we are called by gethost/servbyname only. 1132*0Sstevel@tonic-gate */ 1133*0Sstevel@tonic-gate switch (args->op_t) { 1134*0Sstevel@tonic-gate struct netbuf nbuf; 1135*0Sstevel@tonic-gate struct nd_hostservlist *addrs; 1136*0Sstevel@tonic-gate struct sockaddr_in sa; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate case NSS_HOST: 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr; 1141*0Sstevel@tonic-gate sa.sin_family = AF_INET; 1142*0Sstevel@tonic-gate /* Hopefully, third-parties get this optimization */ 1143*0Sstevel@tonic-gate sa.sin_port = 0; 1144*0Sstevel@tonic-gate nbuf.buf = (char *)&sa; 1145*0Sstevel@tonic-gate nbuf.len = nbuf.maxlen = sizeof (sa); 1146*0Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyaddr(nconf, 1147*0Sstevel@tonic-gate &addrs, &nbuf)) != 0) { 1148*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1149*0Sstevel@tonic-gate return (_nderror); 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate /* 1152*0Sstevel@tonic-gate * convert the host-serv pairs into h_aliases and hent. 1153*0Sstevel@tonic-gate */ 1154*0Sstevel@tonic-gate _nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent, 1155*0Sstevel@tonic-gate args->arg.nss.host.buf, args->arg.nss.host.buflen); 1156*0Sstevel@tonic-gate if (_nderror != ND_OK) 1157*0Sstevel@tonic-gate *(res->nss.host.herrno_p) = nd2herrno(_nderror); 1158*0Sstevel@tonic-gate netdir_free((char *)addrs, ND_HOSTSERVLIST); 1159*0Sstevel@tonic-gate return (_nderror); 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate case NSS_SERV: 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate if (args->arg.nss.serv.proto == NULL) { 1164*0Sstevel@tonic-gate /* 1165*0Sstevel@tonic-gate * A similar HACK showed up in Solaris 2.3. 1166*0Sstevel@tonic-gate * The caller wild-carded proto -- i.e. will 1167*0Sstevel@tonic-gate * accept a match on tcp or udp for the port 1168*0Sstevel@tonic-gate * number. Since we have no hope of getting 1169*0Sstevel@tonic-gate * directly to a name service switch backend 1170*0Sstevel@tonic-gate * from here that understands this semantics, 1171*0Sstevel@tonic-gate * we try calling the netdir interfaces first 1172*0Sstevel@tonic-gate * with "tcp" and then "udp". 1173*0Sstevel@tonic-gate */ 1174*0Sstevel@tonic-gate args->arg.nss.serv.proto = "tcp"; 1175*0Sstevel@tonic-gate _nderror = _get_hostserv_inetnetdir_byaddr(nconf, args, 1176*0Sstevel@tonic-gate res); 1177*0Sstevel@tonic-gate if (_nderror != ND_OK) { 1178*0Sstevel@tonic-gate args->arg.nss.serv.proto = "udp"; 1179*0Sstevel@tonic-gate _nderror = 1180*0Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(nconf, 1181*0Sstevel@tonic-gate args, res); 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate return (_nderror); 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate /* 1187*0Sstevel@tonic-gate * Third-party nametoaddr_libs should be optimized for 1188*0Sstevel@tonic-gate * this case. It also gives a special semantics twist to 1189*0Sstevel@tonic-gate * netdir_getbyaddr. Only for the INADDR_ANY case, it gives 1190*0Sstevel@tonic-gate * higher priority to service lookups (over host lookups). 1191*0Sstevel@tonic-gate * If service lookup fails, the backend returns ND_NOSERV to 1192*0Sstevel@tonic-gate * facilitate lookup in the "next" naming service. 1193*0Sstevel@tonic-gate * BugId: 1075403. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate sa.sin_addr.s_addr = INADDR_ANY; 1196*0Sstevel@tonic-gate sa.sin_family = AF_INET; 1197*0Sstevel@tonic-gate sa.sin_port = (ushort_t)args->arg.nss.serv.port; 1198*0Sstevel@tonic-gate sa.sin_zero[0] = '\0'; 1199*0Sstevel@tonic-gate nbuf.buf = (char *)&sa; 1200*0Sstevel@tonic-gate nbuf.len = nbuf.maxlen = sizeof (sa); 1201*0Sstevel@tonic-gate if ((_nderror = __classic_netdir_getbyaddr(nconf, 1202*0Sstevel@tonic-gate &addrs, &nbuf)) != ND_OK) { 1203*0Sstevel@tonic-gate return (_nderror); 1204*0Sstevel@tonic-gate } 1205*0Sstevel@tonic-gate /* 1206*0Sstevel@tonic-gate * convert the host-serv pairs into s_aliases and servent. 1207*0Sstevel@tonic-gate */ 1208*0Sstevel@tonic-gate _nderror = ndhostserv2srent(args->arg.nss.serv.port, 1209*0Sstevel@tonic-gate args->arg.nss.serv.proto, addrs, res->nss.serv, 1210*0Sstevel@tonic-gate args->arg.nss.serv.buf, args->arg.nss.serv.buflen); 1211*0Sstevel@tonic-gate netdir_free((char *)addrs, ND_HOSTSERVLIST); 1212*0Sstevel@tonic-gate return (_nderror); 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate default: 1215*0Sstevel@tonic-gate _nderror = ND_BADARG; 1216*0Sstevel@tonic-gate return (_nderror); /* should never happen */ 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate /* 1221*0Sstevel@tonic-gate * Part II: Name Service Switch interfacing routines. 1222*0Sstevel@tonic-gate */ 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts); 1225*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes); 1226*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_services); 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate /* 1230*0Sstevel@tonic-gate * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c. 1231*0Sstevel@tonic-gate * It is there because /etc/lib/nss_files.so.1 cannot call 1232*0Sstevel@tonic-gate * routines in libnsl. Care should be taken to keep the two copies 1233*0Sstevel@tonic-gate * in sync. 1234*0Sstevel@tonic-gate */ 1235*0Sstevel@tonic-gate int 1236*0Sstevel@tonic-gate __nss2herrno(nss_status_t nsstat) 1237*0Sstevel@tonic-gate { 1238*0Sstevel@tonic-gate switch (nsstat) { 1239*0Sstevel@tonic-gate case NSS_SUCCESS: 1240*0Sstevel@tonic-gate /* no macro-defined success code for h_errno */ 1241*0Sstevel@tonic-gate return (0); 1242*0Sstevel@tonic-gate case NSS_NOTFOUND: 1243*0Sstevel@tonic-gate return (HOST_NOT_FOUND); 1244*0Sstevel@tonic-gate case NSS_TRYAGAIN: 1245*0Sstevel@tonic-gate return (TRY_AGAIN); 1246*0Sstevel@tonic-gate case NSS_UNAVAIL: 1247*0Sstevel@tonic-gate return (NO_RECOVERY); 1248*0Sstevel@tonic-gate } 1249*0Sstevel@tonic-gate /* NOTREACHED */ 1250*0Sstevel@tonic-gate return (0); /* keep gcc happy */ 1251*0Sstevel@tonic-gate } 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate nss_status_t 1254*0Sstevel@tonic-gate _herrno2nss(int h_errno) 1255*0Sstevel@tonic-gate { 1256*0Sstevel@tonic-gate switch (h_errno) { 1257*0Sstevel@tonic-gate case 0: 1258*0Sstevel@tonic-gate return (NSS_SUCCESS); 1259*0Sstevel@tonic-gate case TRY_AGAIN: 1260*0Sstevel@tonic-gate return (NSS_TRYAGAIN); 1261*0Sstevel@tonic-gate case NO_RECOVERY: 1262*0Sstevel@tonic-gate case NETDB_INTERNAL: 1263*0Sstevel@tonic-gate return (NSS_UNAVAIL); 1264*0Sstevel@tonic-gate case HOST_NOT_FOUND: 1265*0Sstevel@tonic-gate case NO_DATA: 1266*0Sstevel@tonic-gate default: 1267*0Sstevel@tonic-gate return (NSS_NOTFOUND); 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate static int 1272*0Sstevel@tonic-gate __herrno2netdir(int h_errnop) 1273*0Sstevel@tonic-gate { 1274*0Sstevel@tonic-gate switch (h_errnop) { 1275*0Sstevel@tonic-gate case 0: 1276*0Sstevel@tonic-gate return (ND_OK); 1277*0Sstevel@tonic-gate case HOST_NOT_FOUND: 1278*0Sstevel@tonic-gate return (ND_NOHOST); 1279*0Sstevel@tonic-gate case TRY_AGAIN: 1280*0Sstevel@tonic-gate return (ND_TRY_AGAIN); 1281*0Sstevel@tonic-gate case NO_RECOVERY: 1282*0Sstevel@tonic-gate case NETDB_INTERNAL: 1283*0Sstevel@tonic-gate return (ND_NO_RECOVERY); 1284*0Sstevel@tonic-gate case NO_DATA: 1285*0Sstevel@tonic-gate return (ND_NO_DATA); 1286*0Sstevel@tonic-gate default: 1287*0Sstevel@tonic-gate return (ND_NOHOST); 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate /* 1292*0Sstevel@tonic-gate * The _switch_getXXbyYY_r() routines should be static. They used to 1293*0Sstevel@tonic-gate * be exported in SunOS 5.3, and in fact publicised as work-around 1294*0Sstevel@tonic-gate * interfaces for getting CNAME/aliases, and therefore, we preserve 1295*0Sstevel@tonic-gate * their signatures here. Just in case. 1296*0Sstevel@tonic-gate */ 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate struct hostent * 1299*0Sstevel@tonic-gate _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer, 1300*0Sstevel@tonic-gate int buflen, int *h_errnop) 1301*0Sstevel@tonic-gate { 1302*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1303*0Sstevel@tonic-gate nss_status_t res; 1304*0Sstevel@tonic-gate 1305*0Sstevel@tonic-gate trace2(TR__switch_gethostbyname_r, 0, buflen); 1306*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1307*0Sstevel@tonic-gate arg.key.name = name; 1308*0Sstevel@tonic-gate arg.stayopen = 0; 1309*0Sstevel@tonic-gate res = nss_search(&db_root_hosts, _nss_initf_hosts, 1310*0Sstevel@tonic-gate NSS_DBOP_HOSTS_BYNAME, &arg); 1311*0Sstevel@tonic-gate arg.status = res; 1312*0Sstevel@tonic-gate *h_errnop = arg.h_errno; 1313*0Sstevel@tonic-gate if (arg.returnval != NULL) 1314*0Sstevel@tonic-gate order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1315*0Sstevel@tonic-gate trace2(TR__switch_gethostbyname_r, 1, buflen); 1316*0Sstevel@tonic-gate return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate struct hostent * 1320*0Sstevel@tonic-gate _switch_getipnodebyname_r(const char *name, struct hostent *result, 1321*0Sstevel@tonic-gate char *buffer, int buflen, int af_family, int flags, int *h_errnop) 1322*0Sstevel@tonic-gate { 1323*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1324*0Sstevel@tonic-gate nss_status_t res; 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate trace2(TR__switch_getipnodebyname_r, 0, buflen); 1327*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 1328*0Sstevel@tonic-gate arg.key.ipnode.name = name; 1329*0Sstevel@tonic-gate arg.key.ipnode.af_family = af_family; 1330*0Sstevel@tonic-gate arg.key.ipnode.flags = flags; 1331*0Sstevel@tonic-gate arg.stayopen = 0; 1332*0Sstevel@tonic-gate res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 1333*0Sstevel@tonic-gate NSS_DBOP_IPNODES_BYNAME, &arg); 1334*0Sstevel@tonic-gate arg.status = res; 1335*0Sstevel@tonic-gate *h_errnop = arg.h_errno; 1336*0Sstevel@tonic-gate if (arg.returnval != NULL) 1337*0Sstevel@tonic-gate order_haddrlist_af(result->h_addrtype, result->h_addr_list); 1338*0Sstevel@tonic-gate trace2(TR__switch_getipnodebyname_r, 1, buflen); 1339*0Sstevel@tonic-gate return ((struct hostent *)NSS_XbyY_FINI(&arg)); 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate struct hostent * 1343*0Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type, 1344*0Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 1345*0Sstevel@tonic-gate { 1346*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1347*0Sstevel@tonic-gate nss_status_t res; 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate trace3(TR__switch_gethostbyaddr_r, 0, len, buflen); 1350*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 1351*0Sstevel@tonic-gate arg.key.hostaddr.addr = addr; 1352*0Sstevel@tonic-gate arg.key.hostaddr.len = len; 1353*0Sstevel@tonic-gate arg.key.hostaddr.type = type; 1354*0Sstevel@tonic-gate arg.stayopen = 0; 1355*0Sstevel@tonic-gate res = nss_search(&db_root_hosts, _nss_initf_hosts, 1356*0Sstevel@tonic-gate NSS_DBOP_HOSTS_BYADDR, &arg); 1357*0Sstevel@tonic-gate arg.status = res; 1358*0Sstevel@tonic-gate *h_errnop = arg.h_errno; 1359*0Sstevel@tonic-gate trace3(TR__switch_gethostbyaddr_r, 1, len, buflen); 1360*0Sstevel@tonic-gate return (struct hostent *)NSS_XbyY_FINI(&arg); 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate struct hostent * 1364*0Sstevel@tonic-gate _switch_getipnodebyaddr_r(const char *addr, int len, int type, 1365*0Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, int *h_errnop) 1366*0Sstevel@tonic-gate { 1367*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1368*0Sstevel@tonic-gate nss_status_t res; 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate trace3(TR__switch_getipnodebyaddr_r, 0, len, buflen); 1371*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6); 1372*0Sstevel@tonic-gate arg.key.hostaddr.addr = addr; 1373*0Sstevel@tonic-gate arg.key.hostaddr.len = len; 1374*0Sstevel@tonic-gate arg.key.hostaddr.type = type; 1375*0Sstevel@tonic-gate arg.stayopen = 0; 1376*0Sstevel@tonic-gate res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes, 1377*0Sstevel@tonic-gate NSS_DBOP_IPNODES_BYADDR, &arg); 1378*0Sstevel@tonic-gate arg.status = res; 1379*0Sstevel@tonic-gate *h_errnop = arg.h_errno; 1380*0Sstevel@tonic-gate trace3(TR__switch_getipnodebyaddr_r, 1, len, buflen); 1381*0Sstevel@tonic-gate return (struct hostent *)NSS_XbyY_FINI(&arg); 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate static void 1385*0Sstevel@tonic-gate _nss_initf_services(nss_db_params_t *p) 1386*0Sstevel@tonic-gate { 1387*0Sstevel@tonic-gate /* === need tracepoints */ 1388*0Sstevel@tonic-gate p->name = NSS_DBNAM_SERVICES; 1389*0Sstevel@tonic-gate p->default_config = NSS_DEFCONF_SERVICES; 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate struct servent * 1393*0Sstevel@tonic-gate _switch_getservbyname_r(const char *name, const char *proto, 1394*0Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 1395*0Sstevel@tonic-gate { 1396*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1397*0Sstevel@tonic-gate nss_status_t res; 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1400*0Sstevel@tonic-gate arg.key.serv.serv.name = name; 1401*0Sstevel@tonic-gate arg.key.serv.proto = proto; 1402*0Sstevel@tonic-gate arg.stayopen = 0; 1403*0Sstevel@tonic-gate res = nss_search(&db_root_services, _nss_initf_services, 1404*0Sstevel@tonic-gate NSS_DBOP_SERVICES_BYNAME, &arg); 1405*0Sstevel@tonic-gate arg.status = res; 1406*0Sstevel@tonic-gate return ((struct servent *)NSS_XbyY_FINI(&arg)); 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate struct servent * 1410*0Sstevel@tonic-gate _switch_getservbyport_r(int port, const char *proto, struct servent *result, 1411*0Sstevel@tonic-gate char *buffer, int buflen) 1412*0Sstevel@tonic-gate { 1413*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1414*0Sstevel@tonic-gate nss_status_t res; 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent); 1417*0Sstevel@tonic-gate arg.key.serv.serv.port = port; 1418*0Sstevel@tonic-gate arg.key.serv.proto = proto; 1419*0Sstevel@tonic-gate arg.stayopen = 0; 1420*0Sstevel@tonic-gate res = nss_search(&db_root_services, _nss_initf_services, 1421*0Sstevel@tonic-gate NSS_DBOP_SERVICES_BYPORT, &arg); 1422*0Sstevel@tonic-gate arg.status = res; 1423*0Sstevel@tonic-gate return ((struct servent *)NSS_XbyY_FINI(&arg)); 1424*0Sstevel@tonic-gate } 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate /* 1428*0Sstevel@tonic-gate * Return values: 0 = success, 1 = parse error, 2 = erange ... 1429*0Sstevel@tonic-gate * The structure pointer passed in is a structure in the caller's space 1430*0Sstevel@tonic-gate * wherein the field pointers would be set to areas in the buffer if 1431*0Sstevel@tonic-gate * need be. instring and buffer should be separate areas. 1432*0Sstevel@tonic-gate * 1433*0Sstevel@tonic-gate * Defined here because we need it and we (libnsl) cannot have a dependency 1434*0Sstevel@tonic-gate * on libsocket (however, libsocket always depends on libnsl). 1435*0Sstevel@tonic-gate */ 1436*0Sstevel@tonic-gate int 1437*0Sstevel@tonic-gate str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 1438*0Sstevel@tonic-gate { 1439*0Sstevel@tonic-gate struct servent *serv = (struct servent *)ent; 1440*0Sstevel@tonic-gate const char *p, *fieldstart, *limit, *namestart; 1441*0Sstevel@tonic-gate ssize_t fieldlen, namelen = 0; 1442*0Sstevel@tonic-gate char numbuf[12]; 1443*0Sstevel@tonic-gate char *numend; 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate if ((instr >= buffer && (buffer + buflen) > instr) || 1446*0Sstevel@tonic-gate (buffer >= instr && (instr + lenstr) > buffer)) { 1447*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate p = instr; 1451*0Sstevel@tonic-gate limit = p + lenstr; 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate while (p < limit && isspace(*p)) { 1454*0Sstevel@tonic-gate p++; 1455*0Sstevel@tonic-gate } 1456*0Sstevel@tonic-gate namestart = p; 1457*0Sstevel@tonic-gate while (p < limit && !isspace(*p)) { 1458*0Sstevel@tonic-gate p++; /* Skip over the canonical name */ 1459*0Sstevel@tonic-gate } 1460*0Sstevel@tonic-gate namelen = p - namestart; 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate if (buflen <= namelen) { /* not enough buffer */ 1463*0Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 1464*0Sstevel@tonic-gate } 1465*0Sstevel@tonic-gate (void) memcpy(buffer, namestart, namelen); 1466*0Sstevel@tonic-gate buffer[namelen] = '\0'; 1467*0Sstevel@tonic-gate serv->s_name = buffer; 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate while (p < limit && isspace(*p)) { 1470*0Sstevel@tonic-gate p++; 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate fieldstart = p; 1474*0Sstevel@tonic-gate do { 1475*0Sstevel@tonic-gate if (p > limit || isspace(*p)) { 1476*0Sstevel@tonic-gate /* Syntax error -- no port/proto */ 1477*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 1478*0Sstevel@tonic-gate } 1479*0Sstevel@tonic-gate } 1480*0Sstevel@tonic-gate while (*p++ != '/'); 1481*0Sstevel@tonic-gate fieldlen = p - fieldstart - 1; 1482*0Sstevel@tonic-gate if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) { 1483*0Sstevel@tonic-gate /* Syntax error -- supposed number is empty or too long */ 1484*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate (void) memcpy(numbuf, fieldstart, fieldlen); 1487*0Sstevel@tonic-gate numbuf[fieldlen] = '\0'; 1488*0Sstevel@tonic-gate serv->s_port = htons((int)strtol(numbuf, &numend, 10)); 1489*0Sstevel@tonic-gate if (*numend != '\0') { 1490*0Sstevel@tonic-gate /* Syntax error -- port number isn't a number */ 1491*0Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 1492*0Sstevel@tonic-gate } 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate fieldstart = p; 1495*0Sstevel@tonic-gate while (p < limit && !isspace(*p)) { 1496*0Sstevel@tonic-gate p++; /* Scan the protocol name */ 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate fieldlen = p - fieldstart + 1; /* Include '\0' this time */ 1499*0Sstevel@tonic-gate if (fieldlen > buflen - namelen - 1) { 1500*0Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 1501*0Sstevel@tonic-gate } 1502*0Sstevel@tonic-gate serv->s_proto = buffer + namelen + 1; 1503*0Sstevel@tonic-gate (void) memcpy(serv->s_proto, fieldstart, fieldlen - 1); 1504*0Sstevel@tonic-gate serv->s_proto[fieldlen - 1] = '\0'; 1505*0Sstevel@tonic-gate 1506*0Sstevel@tonic-gate while (p < limit && isspace(*p)) { 1507*0Sstevel@tonic-gate p++; 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate /* 1510*0Sstevel@tonic-gate * Although nss_files_XY_all calls us with # stripped, 1511*0Sstevel@tonic-gate * we should be able to deal with it here in order to 1512*0Sstevel@tonic-gate * be more useful. 1513*0Sstevel@tonic-gate */ 1514*0Sstevel@tonic-gate if (p >= limit || *p == '#') { /* no aliases, no problem */ 1515*0Sstevel@tonic-gate char **ptr; 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen, 1518*0Sstevel@tonic-gate sizeof (char *)); 1519*0Sstevel@tonic-gate if ((char *)ptr >= buffer + buflen) { 1520*0Sstevel@tonic-gate /* hope they don't try to peek in */ 1521*0Sstevel@tonic-gate serv->s_aliases = 0; 1522*0Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 1523*0Sstevel@tonic-gate } else { 1524*0Sstevel@tonic-gate *ptr = 0; 1525*0Sstevel@tonic-gate serv->s_aliases = ptr; 1526*0Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 1527*0Sstevel@tonic-gate } 1528*0Sstevel@tonic-gate } 1529*0Sstevel@tonic-gate serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)), 1530*0Sstevel@tonic-gate buffer + namelen + 1 + fieldlen, 1531*0Sstevel@tonic-gate (int)(buflen - namelen - 1 - fieldlen)); 1532*0Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate /* 1536*0Sstevel@tonic-gate * Part III: All `n sundry routines that are useful only in this 1537*0Sstevel@tonic-gate * module. In the interest of keeping this source file shorter, 1538*0Sstevel@tonic-gate * we would create them a new module only if the linker allowed 1539*0Sstevel@tonic-gate * "library-static" functions. 1540*0Sstevel@tonic-gate * 1541*0Sstevel@tonic-gate * Routines to order addresses based on local interfaces and netmasks, 1542*0Sstevel@tonic-gate * to get and check reserved ports, and to get broadcast nets. 1543*0Sstevel@tonic-gate */ 1544*0Sstevel@tonic-gate 1545*0Sstevel@tonic-gate union __v4v6addr { 1546*0Sstevel@tonic-gate struct in6_addr in6; 1547*0Sstevel@tonic-gate struct in_addr in4; 1548*0Sstevel@tonic-gate }; 1549*0Sstevel@tonic-gate 1550*0Sstevel@tonic-gate struct __ifaddr { 1551*0Sstevel@tonic-gate sa_family_t af; 1552*0Sstevel@tonic-gate union __v4v6addr addr; 1553*0Sstevel@tonic-gate union __v4v6addr mask; 1554*0Sstevel@tonic-gate }; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate struct ifinfo { 1557*0Sstevel@tonic-gate int count; 1558*0Sstevel@tonic-gate struct __ifaddr *addresses; 1559*0Sstevel@tonic-gate }; 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t; 1562*0Sstevel@tonic-gate #define ADDR_NUMCLASSES 2 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate typedef enum {IF_ADDR, IF_MASK} __ifaddr_type; 1565*0Sstevel@tonic-gate static int __inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type, 1566*0Sstevel@tonic-gate void *); 1567*0Sstevel@tonic-gate int __inet_address_is_local_af(void *, sa_family_t, void *); 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate #define ifaf(index) (localinfo->addresses[index].af) 1570*0Sstevel@tonic-gate #define ifaddr4(index) (localinfo->addresses[index].addr.in4) 1571*0Sstevel@tonic-gate #define ifaddr6(index) (localinfo->addresses[index].addr.in6) 1572*0Sstevel@tonic-gate #define ifmask4(index) (localinfo->addresses[index].mask.in4) 1573*0Sstevel@tonic-gate #define ifmask6(index) (localinfo->addresses[index].mask.in6) 1574*0Sstevel@tonic-gate #define ifinfosize(n) (sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr)) 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate #define lifraddrp(lifr) ((lifr.lifr_addr.ss_family == AF_INET6) ? \ 1577*0Sstevel@tonic-gate (void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \ 1578*0Sstevel@tonic-gate (void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr) 1579*0Sstevel@tonic-gate 1580*0Sstevel@tonic-gate #define ifassign(lifr, index, type) \ 1581*0Sstevel@tonic-gate __inet_ifassign(lifr.lifr_addr.ss_family, \ 1582*0Sstevel@tonic-gate &localinfo->addresses[index], type, \ 1583*0Sstevel@tonic-gate lifraddrp(lifr)) 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate /* 1586*0Sstevel@tonic-gate * The number of nanoseconds the order_haddrlist_inet() function waits 1587*0Sstevel@tonic-gate * to retreive IP interface information. The default is five minutes. 1588*0Sstevel@tonic-gate */ 1589*0Sstevel@tonic-gate #define IFINFOTIMEOUT ((hrtime_t)300 * NANOSEC) 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate /* 1592*0Sstevel@tonic-gate * Sort the addresses in haddrlist. Since the sorting algorithms are 1593*0Sstevel@tonic-gate * address-family specific, the work is done in the address-family 1594*0Sstevel@tonic-gate * specific order_haddrlist_<family> functions. 1595*0Sstevel@tonic-gate * 1596*0Sstevel@tonic-gate * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE 1597*0Sstevel@tonic-gate * in the configuration file /etc/default/nss. This is useful in case 1598*0Sstevel@tonic-gate * the order of addresses returned by the nameserver needs to be 1599*0Sstevel@tonic-gate * maintained. (DNS round robin feature is one example) 1600*0Sstevel@tonic-gate */ 1601*0Sstevel@tonic-gate void 1602*0Sstevel@tonic-gate order_haddrlist_af(sa_family_t af, char **haddrlist) 1603*0Sstevel@tonic-gate { 1604*0Sstevel@tonic-gate size_t addrcount; 1605*0Sstevel@tonic-gate char **addrptr; 1606*0Sstevel@tonic-gate static boolean_t checksortcfg = B_TRUE; 1607*0Sstevel@tonic-gate static boolean_t nosort = B_FALSE; 1608*0Sstevel@tonic-gate static mutex_t checksortcfg_lock = DEFAULTMUTEX; 1609*0Sstevel@tonic-gate 1610*0Sstevel@tonic-gate if (haddrlist == NULL) 1611*0Sstevel@tonic-gate return; 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate /* 1614*0Sstevel@tonic-gate * Check if SORT_ADDRS is set to NO or FALSE in the configuration 1615*0Sstevel@tonic-gate * file. We do not have to sort addresses in that case. 1616*0Sstevel@tonic-gate */ 1617*0Sstevel@tonic-gate (void) mutex_lock(&checksortcfg_lock); 1618*0Sstevel@tonic-gate if (checksortcfg == B_TRUE) { 1619*0Sstevel@tonic-gate checksortcfg = B_FALSE; 1620*0Sstevel@tonic-gate nosort = _read_nsw_file(); 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate (void) mutex_unlock(&checksortcfg_lock); 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate if (nosort) 1625*0Sstevel@tonic-gate return; 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate /* Count the addresses to sort */ 1628*0Sstevel@tonic-gate addrcount = 0; 1629*0Sstevel@tonic-gate for (addrptr = haddrlist; *addrptr != NULL; addrptr++) 1630*0Sstevel@tonic-gate addrcount++; 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate /* 1633*0Sstevel@tonic-gate * If there's only one address or no addresses to sort, then 1634*0Sstevel@tonic-gate * there's nothing for us to do. 1635*0Sstevel@tonic-gate */ 1636*0Sstevel@tonic-gate if (addrcount <= 1) 1637*0Sstevel@tonic-gate return; 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate /* Call the address-family specific sorting functions. */ 1640*0Sstevel@tonic-gate switch (af) { 1641*0Sstevel@tonic-gate case AF_INET: 1642*0Sstevel@tonic-gate order_haddrlist_inet(haddrlist, addrcount); 1643*0Sstevel@tonic-gate break; 1644*0Sstevel@tonic-gate case AF_INET6: 1645*0Sstevel@tonic-gate order_haddrlist_inet6(haddrlist, addrcount); 1646*0Sstevel@tonic-gate break; 1647*0Sstevel@tonic-gate default: 1648*0Sstevel@tonic-gate break; 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate } 1651*0Sstevel@tonic-gate 1652*0Sstevel@tonic-gate /* 1653*0Sstevel@tonic-gate * Move any local (on-link) addresses toward the beginning of haddrlist. 1654*0Sstevel@tonic-gate * The order within these two classes is preserved. 1655*0Sstevel@tonic-gate * 1656*0Sstevel@tonic-gate * The interface list is retrieved no more often than every 1657*0Sstevel@tonic-gate * IFINFOTIMEOUT nanoseconds. Access to the interface list is 1658*0Sstevel@tonic-gate * protected by an RW lock. 1659*0Sstevel@tonic-gate * 1660*0Sstevel@tonic-gate * If this function encounters an error, haddrlist is unaltered. 1661*0Sstevel@tonic-gate */ 1662*0Sstevel@tonic-gate static void 1663*0Sstevel@tonic-gate order_haddrlist_inet(char **haddrlist, size_t addrcount) 1664*0Sstevel@tonic-gate { 1665*0Sstevel@tonic-gate static struct ifinfo *localinfo = NULL; 1666*0Sstevel@tonic-gate static hrtime_t then = 0; /* the last time localinfo was updated */ 1667*0Sstevel@tonic-gate hrtime_t now; 1668*0Sstevel@tonic-gate static rwlock_t localinfo_lock = DEFAULTRWLOCK; 1669*0Sstevel@tonic-gate uint8_t *sortbuf; 1670*0Sstevel@tonic-gate size_t sortbuf_size; 1671*0Sstevel@tonic-gate struct in_addr **inaddrlist = (struct in_addr **)haddrlist; 1672*0Sstevel@tonic-gate struct in_addr **sorted; 1673*0Sstevel@tonic-gate struct in_addr **classnext[ADDR_NUMCLASSES]; 1674*0Sstevel@tonic-gate uint_t classcount[ADDR_NUMCLASSES]; 1675*0Sstevel@tonic-gate addr_class_t *sortclass; 1676*0Sstevel@tonic-gate int i; 1677*0Sstevel@tonic-gate int rc; 1678*0Sstevel@tonic-gate 1679*0Sstevel@tonic-gate 1680*0Sstevel@tonic-gate /* 1681*0Sstevel@tonic-gate * The classes in the sortclass array correspond to the class 1682*0Sstevel@tonic-gate * of the address in the haddrlist list of the same index. 1683*0Sstevel@tonic-gate * The classes are: 1684*0Sstevel@tonic-gate * 1685*0Sstevel@tonic-gate * ADDR_ONLINK on-link address 1686*0Sstevel@tonic-gate * ADDR_OFFLINK off-link address 1687*0Sstevel@tonic-gate */ 1688*0Sstevel@tonic-gate sortbuf_size = addrcount * 1689*0Sstevel@tonic-gate (sizeof (struct in_addr *) + sizeof (addr_class_t)); 1690*0Sstevel@tonic-gate if ((sortbuf = malloc(sortbuf_size)) == NULL) 1691*0Sstevel@tonic-gate return; 1692*0Sstevel@tonic-gate sorted = (struct in_addr **)sortbuf; 1693*0Sstevel@tonic-gate sortclass = (addr_class_t *)(sortbuf + 1694*0Sstevel@tonic-gate (addrcount * sizeof (struct in_addr *))); 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate /* 1697*0Sstevel@tonic-gate * Get a read lock, and check if the interface information 1698*0Sstevel@tonic-gate * is too old. 1699*0Sstevel@tonic-gate */ 1700*0Sstevel@tonic-gate (void) rw_rdlock(&localinfo_lock); 1701*0Sstevel@tonic-gate now = gethrtime(); 1702*0Sstevel@tonic-gate if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 1703*0Sstevel@tonic-gate /* Need to update I/F info. Upgrade to write lock. */ 1704*0Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 1705*0Sstevel@tonic-gate (void) rw_wrlock(&localinfo_lock); 1706*0Sstevel@tonic-gate /* 1707*0Sstevel@tonic-gate * Another thread might have updated "then" between 1708*0Sstevel@tonic-gate * the rw_unlock() and rw_wrlock() calls above, so 1709*0Sstevel@tonic-gate * re-check the timeout. 1710*0Sstevel@tonic-gate */ 1711*0Sstevel@tonic-gate if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) { 1712*0Sstevel@tonic-gate if (localinfo != NULL) 1713*0Sstevel@tonic-gate free(localinfo); 1714*0Sstevel@tonic-gate if ((localinfo = get_local_info()) == NULL) { 1715*0Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 1716*0Sstevel@tonic-gate free(sortbuf); 1717*0Sstevel@tonic-gate return; 1718*0Sstevel@tonic-gate } 1719*0Sstevel@tonic-gate then = now; 1720*0Sstevel@tonic-gate } 1721*0Sstevel@tonic-gate /* Downgrade to read lock */ 1722*0Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 1723*0Sstevel@tonic-gate (void) rw_rdlock(&localinfo_lock); 1724*0Sstevel@tonic-gate /* 1725*0Sstevel@tonic-gate * Another thread may have updated the I/F info, 1726*0Sstevel@tonic-gate * so verify that the 'localinfo' pointer still 1727*0Sstevel@tonic-gate * is non-NULL. 1728*0Sstevel@tonic-gate */ 1729*0Sstevel@tonic-gate if (localinfo == NULL) { 1730*0Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 1731*0Sstevel@tonic-gate free(sortbuf); 1732*0Sstevel@tonic-gate return; 1733*0Sstevel@tonic-gate } 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate /* 1737*0Sstevel@tonic-gate * Classify the addresses. We also maintain the classcount 1738*0Sstevel@tonic-gate * array to keep track of the number of addresses in each 1739*0Sstevel@tonic-gate * class. 1740*0Sstevel@tonic-gate */ 1741*0Sstevel@tonic-gate memset(classcount, 0, sizeof (classcount)); 1742*0Sstevel@tonic-gate for (i = 0; i < addrcount; i++) { 1743*0Sstevel@tonic-gate if (__inet_address_is_local_af(localinfo, AF_INET, 1744*0Sstevel@tonic-gate inaddrlist[i])) 1745*0Sstevel@tonic-gate sortclass[i] = ADDR_ONLINK; 1746*0Sstevel@tonic-gate else 1747*0Sstevel@tonic-gate sortclass[i] = ADDR_OFFLINK; 1748*0Sstevel@tonic-gate classcount[sortclass[i]]++; 1749*0Sstevel@tonic-gate } 1750*0Sstevel@tonic-gate 1751*0Sstevel@tonic-gate /* Don't need the interface list anymore in this call */ 1752*0Sstevel@tonic-gate (void) rw_unlock(&localinfo_lock); 1753*0Sstevel@tonic-gate 1754*0Sstevel@tonic-gate /* 1755*0Sstevel@tonic-gate * Each element in the classnext array points to the next 1756*0Sstevel@tonic-gate * element for that class in the sorted address list. 'rc' is 1757*0Sstevel@tonic-gate * the running count of elements as we sum the class 1758*0Sstevel@tonic-gate * sub-totals. 1759*0Sstevel@tonic-gate */ 1760*0Sstevel@tonic-gate for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) { 1761*0Sstevel@tonic-gate classnext[i] = &sorted[rc]; 1762*0Sstevel@tonic-gate rc += classcount[i]; 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate /* Now for the actual rearrangement of the addresses */ 1766*0Sstevel@tonic-gate for (i = 0; i < addrcount; i++) { 1767*0Sstevel@tonic-gate *(classnext[sortclass[i]]) = inaddrlist[i]; 1768*0Sstevel@tonic-gate classnext[sortclass[i]]++; 1769*0Sstevel@tonic-gate } 1770*0Sstevel@tonic-gate 1771*0Sstevel@tonic-gate /* Copy the sorted list to inaddrlist */ 1772*0Sstevel@tonic-gate (void) memcpy(inaddrlist, sorted, 1773*0Sstevel@tonic-gate addrcount * sizeof (struct in_addr *)); 1774*0Sstevel@tonic-gate free(sortbuf); 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate /* 1778*0Sstevel@tonic-gate * This function implements the IPv6 Default Address Selection's 1779*0Sstevel@tonic-gate * destination address ordering mechanism. The algorithm is described 1780*0Sstevel@tonic-gate * in getaddrinfo(3SOCKET). 1781*0Sstevel@tonic-gate */ 1782*0Sstevel@tonic-gate static void 1783*0Sstevel@tonic-gate order_haddrlist_inet6(char **haddrlist, size_t addrcount) 1784*0Sstevel@tonic-gate { 1785*0Sstevel@tonic-gate struct dstinforeq *dinfo, *dinfoptr; 1786*0Sstevel@tonic-gate int index; 1787*0Sstevel@tonic-gate struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist; 1788*0Sstevel@tonic-gate struct in6_addr **in6addr; 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL) 1791*0Sstevel@tonic-gate return; 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate /* Initialize the dstinfo array we'll use for SIOCGDSTINFO */ 1794*0Sstevel@tonic-gate dinfoptr = dinfo; 1795*0Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 1796*0Sstevel@tonic-gate dinfoptr->dir_daddr = **in6addr; 1797*0Sstevel@tonic-gate dinfoptr++; 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo, 1801*0Sstevel@tonic-gate addrcount * sizeof (struct dstinforeq)) < 0) { 1802*0Sstevel@tonic-gate free(dinfo); 1803*0Sstevel@tonic-gate return; 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate /* Sort the dinfo array */ 1807*0Sstevel@tonic-gate qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp); 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate /* Copy the addresses back into in6addrlist */ 1810*0Sstevel@tonic-gate dinfoptr = dinfo; 1811*0Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 1812*0Sstevel@tonic-gate **in6addr = dinfoptr->dir_daddr; 1813*0Sstevel@tonic-gate dinfoptr++; 1814*0Sstevel@tonic-gate } 1815*0Sstevel@tonic-gate 1816*0Sstevel@tonic-gate free(dinfo); 1817*0Sstevel@tonic-gate } 1818*0Sstevel@tonic-gate 1819*0Sstevel@tonic-gate /* 1820*0Sstevel@tonic-gate * Determine number of leading bits that are common between two addresses. 1821*0Sstevel@tonic-gate * Only consider bits which fall within the prefix length plen. 1822*0Sstevel@tonic-gate */ 1823*0Sstevel@tonic-gate static uint_t 1824*0Sstevel@tonic-gate ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2) 1825*0Sstevel@tonic-gate { 1826*0Sstevel@tonic-gate uint_t bits; 1827*0Sstevel@tonic-gate uint_t i; 1828*0Sstevel@tonic-gate uint32_t diff; /* Bits that differ */ 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate for (i = 0; i < 4; i++) { 1831*0Sstevel@tonic-gate if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i]) 1832*0Sstevel@tonic-gate break; 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate bits = i * 32; 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate if (bits == IPV6_ABITS) 1837*0Sstevel@tonic-gate return (IPV6_ABITS); 1838*0Sstevel@tonic-gate 1839*0Sstevel@tonic-gate /* 1840*0Sstevel@tonic-gate * Find number of leading common bits in the word which might 1841*0Sstevel@tonic-gate * have some common bits by searching for the first one from the left 1842*0Sstevel@tonic-gate * in the xor of the two addresses. 1843*0Sstevel@tonic-gate */ 1844*0Sstevel@tonic-gate diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]); 1845*0Sstevel@tonic-gate if (diff & 0xffff0000ul) 1846*0Sstevel@tonic-gate diff >>= 16; 1847*0Sstevel@tonic-gate else 1848*0Sstevel@tonic-gate bits += 16; 1849*0Sstevel@tonic-gate if (diff & 0xff00) 1850*0Sstevel@tonic-gate diff >>= 8; 1851*0Sstevel@tonic-gate else 1852*0Sstevel@tonic-gate bits += 8; 1853*0Sstevel@tonic-gate if (diff & 0xf0) 1854*0Sstevel@tonic-gate diff >>= 4; 1855*0Sstevel@tonic-gate else 1856*0Sstevel@tonic-gate bits += 4; 1857*0Sstevel@tonic-gate if (diff & 0xc) 1858*0Sstevel@tonic-gate diff >>= 2; 1859*0Sstevel@tonic-gate else 1860*0Sstevel@tonic-gate bits += 2; 1861*0Sstevel@tonic-gate if (!(diff & 2)) 1862*0Sstevel@tonic-gate bits++; 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate /* 1865*0Sstevel@tonic-gate * We don't need to shift and check for the last bit. The 1866*0Sstevel@tonic-gate * check for IPV6_ABITS above would have caught that. 1867*0Sstevel@tonic-gate */ 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate return (bits); 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate /* 1874*0Sstevel@tonic-gate * The following group of functions named rule_*() are individual 1875*0Sstevel@tonic-gate * sorting rules for the AF_INET6 address sorting algorithm. The 1876*0Sstevel@tonic-gate * functions compare two addresses (described by two dstinforeq 1877*0Sstevel@tonic-gate * structures), and determines if one is "greater" than the other, or 1878*0Sstevel@tonic-gate * if the two are equal according to that rule. 1879*0Sstevel@tonic-gate */ 1880*0Sstevel@tonic-gate typedef int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *); 1881*0Sstevel@tonic-gate 1882*0Sstevel@tonic-gate /* 1883*0Sstevel@tonic-gate * These values of these constants are no accident. Since qsort() 1884*0Sstevel@tonic-gate * implements the AF_INET6 address sorting, the comparison function 1885*0Sstevel@tonic-gate * must return an integer less than, equal to, or greater than zero to 1886*0Sstevel@tonic-gate * indicate if the first address is considered "less than", "equal 1887*0Sstevel@tonic-gate * to", or "greater than" the second one. Since we want the best 1888*0Sstevel@tonic-gate * addresses first on the list, "less than" is considered preferrable. 1889*0Sstevel@tonic-gate */ 1890*0Sstevel@tonic-gate #define RULE_PREFER_DA -1 1891*0Sstevel@tonic-gate #define RULE_PREFER_DB 1 1892*0Sstevel@tonic-gate #define RULE_EQUAL 0 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate /* Prefer the addresses that is reachable. */ 1895*0Sstevel@tonic-gate static int 1896*0Sstevel@tonic-gate rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db) 1897*0Sstevel@tonic-gate { 1898*0Sstevel@tonic-gate if (da->dir_dreachable == db->dir_dreachable) 1899*0Sstevel@tonic-gate return (RULE_EQUAL); 1900*0Sstevel@tonic-gate if (da->dir_dreachable) 1901*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1902*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1903*0Sstevel@tonic-gate } 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate /* Prefer the address whose scope matches that of its source address. */ 1906*0Sstevel@tonic-gate static int 1907*0Sstevel@tonic-gate rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db) 1908*0Sstevel@tonic-gate { 1909*0Sstevel@tonic-gate boolean_t da_scope_match, db_scope_match; 1910*0Sstevel@tonic-gate 1911*0Sstevel@tonic-gate da_scope_match = da->dir_dscope == da->dir_sscope; 1912*0Sstevel@tonic-gate db_scope_match = db->dir_dscope == db->dir_sscope; 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate if (da_scope_match == db_scope_match) 1915*0Sstevel@tonic-gate return (RULE_EQUAL); 1916*0Sstevel@tonic-gate if (da_scope_match) 1917*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1918*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1919*0Sstevel@tonic-gate } 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate /* Avoid the address with the link local source address. */ 1922*0Sstevel@tonic-gate static int 1923*0Sstevel@tonic-gate rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db) 1924*0Sstevel@tonic-gate { 1925*0Sstevel@tonic-gate if (da->dir_sscope == IP6_SCOPE_LINKLOCAL && 1926*0Sstevel@tonic-gate da->dir_dscope != IP6_SCOPE_LINKLOCAL && 1927*0Sstevel@tonic-gate db->dir_sscope != IP6_SCOPE_LINKLOCAL) 1928*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1929*0Sstevel@tonic-gate if (db->dir_sscope == IP6_SCOPE_LINKLOCAL && 1930*0Sstevel@tonic-gate db->dir_dscope != IP6_SCOPE_LINKLOCAL && 1931*0Sstevel@tonic-gate da->dir_sscope != IP6_SCOPE_LINKLOCAL) 1932*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1933*0Sstevel@tonic-gate return (RULE_EQUAL); 1934*0Sstevel@tonic-gate } 1935*0Sstevel@tonic-gate 1936*0Sstevel@tonic-gate /* Prefer the address whose source address isn't deprecated. */ 1937*0Sstevel@tonic-gate static int 1938*0Sstevel@tonic-gate rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db) 1939*0Sstevel@tonic-gate { 1940*0Sstevel@tonic-gate if (da->dir_sdeprecated == db->dir_sdeprecated) 1941*0Sstevel@tonic-gate return (RULE_EQUAL); 1942*0Sstevel@tonic-gate if (db->dir_sdeprecated) 1943*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1944*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1945*0Sstevel@tonic-gate } 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate /* Prefer the address whose label matches that of its source address. */ 1948*0Sstevel@tonic-gate static int 1949*0Sstevel@tonic-gate rule_label(const struct dstinforeq *da, const struct dstinforeq *db) 1950*0Sstevel@tonic-gate { 1951*0Sstevel@tonic-gate if (da->dir_labelmatch == db->dir_labelmatch) 1952*0Sstevel@tonic-gate return (RULE_EQUAL); 1953*0Sstevel@tonic-gate if (da->dir_labelmatch) 1954*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1955*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1956*0Sstevel@tonic-gate } 1957*0Sstevel@tonic-gate 1958*0Sstevel@tonic-gate /* Prefer the address with the higher precedence. */ 1959*0Sstevel@tonic-gate static int 1960*0Sstevel@tonic-gate rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db) 1961*0Sstevel@tonic-gate { 1962*0Sstevel@tonic-gate if (da->dir_precedence == db->dir_precedence) 1963*0Sstevel@tonic-gate return (RULE_EQUAL); 1964*0Sstevel@tonic-gate if (da->dir_precedence > db->dir_precedence) 1965*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1966*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1967*0Sstevel@tonic-gate } 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate /* Prefer the address whose output interface isn't an IP tunnel */ 1970*0Sstevel@tonic-gate static int 1971*0Sstevel@tonic-gate rule_native(const struct dstinforeq *da, const struct dstinforeq *db) 1972*0Sstevel@tonic-gate { 1973*0Sstevel@tonic-gate boolean_t isatun, isbtun; 1974*0Sstevel@tonic-gate 1975*0Sstevel@tonic-gate /* Get the common case out of the way early */ 1976*0Sstevel@tonic-gate if (da->dir_dmactype == db->dir_dmactype) 1977*0Sstevel@tonic-gate return (RULE_EQUAL); 1978*0Sstevel@tonic-gate 1979*0Sstevel@tonic-gate isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6; 1980*0Sstevel@tonic-gate isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6; 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate if (isatun == isbtun) 1983*0Sstevel@tonic-gate return (RULE_EQUAL); 1984*0Sstevel@tonic-gate if (isbtun) 1985*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1986*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1987*0Sstevel@tonic-gate } 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate /* Prefer the address with the smaller scope. */ 1990*0Sstevel@tonic-gate static int 1991*0Sstevel@tonic-gate rule_scope(const struct dstinforeq *da, const struct dstinforeq *db) 1992*0Sstevel@tonic-gate { 1993*0Sstevel@tonic-gate if (da->dir_dscope == db->dir_dscope) 1994*0Sstevel@tonic-gate return (RULE_EQUAL); 1995*0Sstevel@tonic-gate if (da->dir_dscope < db->dir_dscope) 1996*0Sstevel@tonic-gate return (RULE_PREFER_DA); 1997*0Sstevel@tonic-gate return (RULE_PREFER_DB); 1998*0Sstevel@tonic-gate } 1999*0Sstevel@tonic-gate 2000*0Sstevel@tonic-gate /* 2001*0Sstevel@tonic-gate * Prefer the address that has the most leading bits in common with its 2002*0Sstevel@tonic-gate * source address. 2003*0Sstevel@tonic-gate */ 2004*0Sstevel@tonic-gate static int 2005*0Sstevel@tonic-gate rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db) 2006*0Sstevel@tonic-gate { 2007*0Sstevel@tonic-gate uint_t da_commonbits, db_commonbits; 2008*0Sstevel@tonic-gate boolean_t da_isipv4, db_isipv4; 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr); 2011*0Sstevel@tonic-gate db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr); 2012*0Sstevel@tonic-gate 2013*0Sstevel@tonic-gate /* 2014*0Sstevel@tonic-gate * At this point, the order doesn't matter if the two addresses 2015*0Sstevel@tonic-gate * aren't of the same address family. 2016*0Sstevel@tonic-gate */ 2017*0Sstevel@tonic-gate if (da_isipv4 != db_isipv4) 2018*0Sstevel@tonic-gate return (RULE_EQUAL); 2019*0Sstevel@tonic-gate 2020*0Sstevel@tonic-gate da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr); 2021*0Sstevel@tonic-gate db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr); 2022*0Sstevel@tonic-gate 2023*0Sstevel@tonic-gate if (da_commonbits > db_commonbits) 2024*0Sstevel@tonic-gate return (RULE_PREFER_DA); 2025*0Sstevel@tonic-gate if (da_commonbits < db_commonbits) 2026*0Sstevel@tonic-gate return (RULE_PREFER_DB); 2027*0Sstevel@tonic-gate return (RULE_EQUAL); 2028*0Sstevel@tonic-gate } 2029*0Sstevel@tonic-gate 2030*0Sstevel@tonic-gate /* 2031*0Sstevel@tonic-gate * This is the function passed to qsort() that does the AF_INET6 2032*0Sstevel@tonic-gate * address comparisons. It compares two addresses using a list of 2033*0Sstevel@tonic-gate * rules. The rules are applied in order until one prefers one 2034*0Sstevel@tonic-gate * address over the other. 2035*0Sstevel@tonic-gate */ 2036*0Sstevel@tonic-gate static int 2037*0Sstevel@tonic-gate dstcmp(const void *da, const void *db) 2038*0Sstevel@tonic-gate { 2039*0Sstevel@tonic-gate int index, result; 2040*0Sstevel@tonic-gate rulef_t rules[] = { 2041*0Sstevel@tonic-gate rule_reachable, 2042*0Sstevel@tonic-gate rule_matchscope, 2043*0Sstevel@tonic-gate rule_avoidlinklocal, 2044*0Sstevel@tonic-gate rule_deprecated, 2045*0Sstevel@tonic-gate rule_label, 2046*0Sstevel@tonic-gate rule_precedence, 2047*0Sstevel@tonic-gate rule_native, 2048*0Sstevel@tonic-gate rule_scope, 2049*0Sstevel@tonic-gate rule_prefix, 2050*0Sstevel@tonic-gate NULL 2051*0Sstevel@tonic-gate }; 2052*0Sstevel@tonic-gate 2053*0Sstevel@tonic-gate result = 0; 2054*0Sstevel@tonic-gate for (index = 0; rules[index] != NULL; index++) { 2055*0Sstevel@tonic-gate result = (rules[index])(da, db); 2056*0Sstevel@tonic-gate if (result != RULE_EQUAL) 2057*0Sstevel@tonic-gate break; 2058*0Sstevel@tonic-gate } 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate return (result); 2061*0Sstevel@tonic-gate } 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate /* 2064*0Sstevel@tonic-gate * Given haddrlist and a port number, mallocs and populates a new 2065*0Sstevel@tonic-gate * nd_addrlist. The new nd_addrlist maintains the order of the addresses 2066*0Sstevel@tonic-gate * in haddrlist, which have already been sorted by order_haddrlist_inet() 2067*0Sstevel@tonic-gate * or order_haddrlist_inet6(). For IPv6 this function filters out 2068*0Sstevel@tonic-gate * IPv4-mapped IPv6 addresses. 2069*0Sstevel@tonic-gate */ 2070*0Sstevel@tonic-gate int 2071*0Sstevel@tonic-gate hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist) 2072*0Sstevel@tonic-gate { 2073*0Sstevel@tonic-gate struct nd_addrlist *result; 2074*0Sstevel@tonic-gate int num; 2075*0Sstevel@tonic-gate struct netbuf *na; 2076*0Sstevel@tonic-gate struct sockaddr_in *sinbuf, *sin; 2077*0Sstevel@tonic-gate struct sockaddr_in6 *sin6buf, *sin6; 2078*0Sstevel@tonic-gate struct in_addr **inaddr, **inaddrlist; 2079*0Sstevel@tonic-gate struct in6_addr **in6addr, **in6addrlist; 2080*0Sstevel@tonic-gate 2081*0Sstevel@tonic-gate /* Address count */ 2082*0Sstevel@tonic-gate num = 0; 2083*0Sstevel@tonic-gate if (af == AF_INET6) { 2084*0Sstevel@tonic-gate in6addrlist = (struct in6_addr **)haddrlist; 2085*0Sstevel@tonic-gate 2086*0Sstevel@tonic-gate /* 2087*0Sstevel@tonic-gate * Exclude IPv4-mapped IPv6 addresses from the count, as 2088*0Sstevel@tonic-gate * these are not included in the nd_addrlist we return. 2089*0Sstevel@tonic-gate */ 2090*0Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) 2091*0Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(*in6addr)) 2092*0Sstevel@tonic-gate num++; 2093*0Sstevel@tonic-gate } else { 2094*0Sstevel@tonic-gate inaddrlist = (struct in_addr **)haddrlist; 2095*0Sstevel@tonic-gate 2096*0Sstevel@tonic-gate for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) 2097*0Sstevel@tonic-gate num++; 2098*0Sstevel@tonic-gate } 2099*0Sstevel@tonic-gate if (num == 0) 2100*0Sstevel@tonic-gate return (ND_NOHOST); 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate result = malloc(sizeof (struct nd_addrlist)); 2103*0Sstevel@tonic-gate if (result == 0) 2104*0Sstevel@tonic-gate return (ND_NOMEM); 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate result->n_cnt = num; 2107*0Sstevel@tonic-gate result->n_addrs = calloc(num, sizeof (struct netbuf)); 2108*0Sstevel@tonic-gate if (result->n_addrs == 0) { 2109*0Sstevel@tonic-gate free(result); 2110*0Sstevel@tonic-gate return (ND_NOMEM); 2111*0Sstevel@tonic-gate } 2112*0Sstevel@tonic-gate 2113*0Sstevel@tonic-gate na = result->n_addrs; 2114*0Sstevel@tonic-gate if (af == AF_INET) { 2115*0Sstevel@tonic-gate sinbuf = calloc(num, sizeof (struct sockaddr_in)); 2116*0Sstevel@tonic-gate if (sinbuf == NULL) { 2117*0Sstevel@tonic-gate free(result->n_addrs); 2118*0Sstevel@tonic-gate free(result); 2119*0Sstevel@tonic-gate return (ND_NOMEM); 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate 2122*0Sstevel@tonic-gate sin = sinbuf; 2123*0Sstevel@tonic-gate for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) { 2124*0Sstevel@tonic-gate na->len = na->maxlen = sizeof (struct sockaddr_in); 2125*0Sstevel@tonic-gate na->buf = (char *)sin; 2126*0Sstevel@tonic-gate sin->sin_family = AF_INET; 2127*0Sstevel@tonic-gate sin->sin_addr = **inaddr; 2128*0Sstevel@tonic-gate sin->sin_port = *servp; 2129*0Sstevel@tonic-gate na++; 2130*0Sstevel@tonic-gate sin++; 2131*0Sstevel@tonic-gate } 2132*0Sstevel@tonic-gate } else if (af == AF_INET6) { 2133*0Sstevel@tonic-gate sin6buf = calloc(num, sizeof (struct sockaddr_in6)); 2134*0Sstevel@tonic-gate if (sin6buf == NULL) { 2135*0Sstevel@tonic-gate free(result->n_addrs); 2136*0Sstevel@tonic-gate free(result); 2137*0Sstevel@tonic-gate return (ND_NOMEM); 2138*0Sstevel@tonic-gate } 2139*0Sstevel@tonic-gate 2140*0Sstevel@tonic-gate sin6 = sin6buf; 2141*0Sstevel@tonic-gate for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) { 2142*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(*in6addr)) 2143*0Sstevel@tonic-gate continue; 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate na->len = na->maxlen = sizeof (struct sockaddr_in6); 2146*0Sstevel@tonic-gate na->buf = (char *)sin6; 2147*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 2148*0Sstevel@tonic-gate sin6->sin6_addr = **in6addr; 2149*0Sstevel@tonic-gate sin6->sin6_port = *servp; 2150*0Sstevel@tonic-gate na++; 2151*0Sstevel@tonic-gate sin6++; 2152*0Sstevel@tonic-gate } 2153*0Sstevel@tonic-gate } 2154*0Sstevel@tonic-gate *(nd_alist) = result; 2155*0Sstevel@tonic-gate return (ND_OK); 2156*0Sstevel@tonic-gate } 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate /* 2159*0Sstevel@tonic-gate * Given a hostent and a servent, mallocs and populates 2160*0Sstevel@tonic-gate * a new nd_hostservlist with host and service names. 2161*0Sstevel@tonic-gate * 2162*0Sstevel@tonic-gate * We could be passed in a NULL servent, in which case stringify port. 2163*0Sstevel@tonic-gate */ 2164*0Sstevel@tonic-gate int 2165*0Sstevel@tonic-gate hsents2ndhostservs(struct hostent *he, struct servent *se, 2166*0Sstevel@tonic-gate ushort_t port, struct nd_hostservlist **hslist) 2167*0Sstevel@tonic-gate { 2168*0Sstevel@tonic-gate struct nd_hostservlist *result; 2169*0Sstevel@tonic-gate struct nd_hostserv *hs; 2170*0Sstevel@tonic-gate int hosts, servs, i, j; 2171*0Sstevel@tonic-gate char **hn, **sn; 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate if ((result = (struct nd_hostservlist *) 2174*0Sstevel@tonic-gate malloc(sizeof (struct nd_hostservlist))) == 0) 2175*0Sstevel@tonic-gate return (ND_NOMEM); 2176*0Sstevel@tonic-gate 2177*0Sstevel@tonic-gate /* 2178*0Sstevel@tonic-gate * We initialize the counters to 1 rather than zero because 2179*0Sstevel@tonic-gate * we have to count the "official" name as well as the aliases. 2180*0Sstevel@tonic-gate */ 2181*0Sstevel@tonic-gate for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++); 2182*0Sstevel@tonic-gate if (se) 2183*0Sstevel@tonic-gate for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++); 2184*0Sstevel@tonic-gate else 2185*0Sstevel@tonic-gate servs = 1; 2186*0Sstevel@tonic-gate 2187*0Sstevel@tonic-gate if ((hs = (struct nd_hostserv *)calloc(hosts * servs, 2188*0Sstevel@tonic-gate sizeof (struct nd_hostserv))) == 0) { 2189*0Sstevel@tonic-gate free((void *)result); 2190*0Sstevel@tonic-gate return (ND_NOMEM); 2191*0Sstevel@tonic-gate } 2192*0Sstevel@tonic-gate 2193*0Sstevel@tonic-gate result->h_cnt = servs * hosts; 2194*0Sstevel@tonic-gate result->h_hostservs = hs; 2195*0Sstevel@tonic-gate 2196*0Sstevel@tonic-gate for (i = 0, hn = he->h_aliases; i < hosts; i++) { 2197*0Sstevel@tonic-gate sn = se ? se->s_aliases : NULL; 2198*0Sstevel@tonic-gate 2199*0Sstevel@tonic-gate for (j = 0; j < servs; j++) { 2200*0Sstevel@tonic-gate if (i == 0) 2201*0Sstevel@tonic-gate hs->h_host = strdup(he->h_name); 2202*0Sstevel@tonic-gate else 2203*0Sstevel@tonic-gate hs->h_host = strdup(*hn); 2204*0Sstevel@tonic-gate if (j == 0) { 2205*0Sstevel@tonic-gate if (se) 2206*0Sstevel@tonic-gate hs->h_serv = strdup(se->s_name); 2207*0Sstevel@tonic-gate else { 2208*0Sstevel@tonic-gate /* Convert to a number string */ 2209*0Sstevel@tonic-gate char stmp[16]; 2210*0Sstevel@tonic-gate 2211*0Sstevel@tonic-gate (void) sprintf(stmp, "%d", port); 2212*0Sstevel@tonic-gate hs->h_serv = strdup(stmp); 2213*0Sstevel@tonic-gate } 2214*0Sstevel@tonic-gate } else 2215*0Sstevel@tonic-gate hs->h_serv = strdup(*sn++); 2216*0Sstevel@tonic-gate 2217*0Sstevel@tonic-gate if ((hs->h_host == 0) || (hs->h_serv == 0)) { 2218*0Sstevel@tonic-gate free((void *)result->h_hostservs); 2219*0Sstevel@tonic-gate free((void *)result); 2220*0Sstevel@tonic-gate return (ND_NOMEM); 2221*0Sstevel@tonic-gate } 2222*0Sstevel@tonic-gate hs++; 2223*0Sstevel@tonic-gate } 2224*0Sstevel@tonic-gate if (i) 2225*0Sstevel@tonic-gate hn++; 2226*0Sstevel@tonic-gate } 2227*0Sstevel@tonic-gate *(hslist) = result; 2228*0Sstevel@tonic-gate return (ND_OK); 2229*0Sstevel@tonic-gate } 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate /* 2232*0Sstevel@tonic-gate * Process results from nd_addrlist ( returned by netdir_getbyname) 2233*0Sstevel@tonic-gate * into a hostent using buf. 2234*0Sstevel@tonic-gate * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in 2235*0Sstevel@tonic-gate * sockaddr_in's *** 2236*0Sstevel@tonic-gate */ 2237*0Sstevel@tonic-gate int 2238*0Sstevel@tonic-gate ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs, 2239*0Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen) 2240*0Sstevel@tonic-gate { 2241*0Sstevel@tonic-gate int i, count; 2242*0Sstevel@tonic-gate struct in_addr *addrp; 2243*0Sstevel@tonic-gate struct in6_addr *addr6p; 2244*0Sstevel@tonic-gate char **addrvec; 2245*0Sstevel@tonic-gate struct netbuf *na; 2246*0Sstevel@tonic-gate size_t len; 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate result->h_name = buffer; 2249*0Sstevel@tonic-gate result->h_addrtype = af; 2250*0Sstevel@tonic-gate result->h_length = (af == AF_INET) ? sizeof (*addrp): 2251*0Sstevel@tonic-gate sizeof (*addr6p); 2252*0Sstevel@tonic-gate 2253*0Sstevel@tonic-gate /* 2254*0Sstevel@tonic-gate * Build addrlist at start of buffer (after name); store the 2255*0Sstevel@tonic-gate * addresses themselves at the end of the buffer. 2256*0Sstevel@tonic-gate */ 2257*0Sstevel@tonic-gate len = strlen(nam) + 1; 2258*0Sstevel@tonic-gate addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec)); 2259*0Sstevel@tonic-gate result->h_addr_list = addrvec; 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate if (af == AF_INET) { 2262*0Sstevel@tonic-gate addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 2263*0Sstevel@tonic-gate sizeof (*addrp)); 2264*0Sstevel@tonic-gate 2265*0Sstevel@tonic-gate count = addrs->n_cnt; 2266*0Sstevel@tonic-gate if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count])) 2267*0Sstevel@tonic-gate return (ND_NOMEM); 2268*0Sstevel@tonic-gate 2269*0Sstevel@tonic-gate (void) memcpy(buffer, nam, len); 2270*0Sstevel@tonic-gate 2271*0Sstevel@tonic-gate for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2272*0Sstevel@tonic-gate --addrp; 2273*0Sstevel@tonic-gate (void) memcpy(addrp, 2274*0Sstevel@tonic-gate &((struct sockaddr_in *)na->buf)->sin_addr, 2275*0Sstevel@tonic-gate sizeof (*addrp)); 2276*0Sstevel@tonic-gate *addrvec++ = (char *)addrp; 2277*0Sstevel@tonic-gate } 2278*0Sstevel@tonic-gate } else { 2279*0Sstevel@tonic-gate addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 2280*0Sstevel@tonic-gate sizeof (*addr6p)); 2281*0Sstevel@tonic-gate 2282*0Sstevel@tonic-gate count = addrs->n_cnt; 2283*0Sstevel@tonic-gate if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count])) 2284*0Sstevel@tonic-gate return (ND_NOMEM); 2285*0Sstevel@tonic-gate 2286*0Sstevel@tonic-gate (void) memcpy(buffer, nam, len); 2287*0Sstevel@tonic-gate 2288*0Sstevel@tonic-gate for (na = addrs->n_addrs, i = 0; i < count; na++, i++) { 2289*0Sstevel@tonic-gate --addr6p; 2290*0Sstevel@tonic-gate (void) memcpy(addr6p, 2291*0Sstevel@tonic-gate &((struct sockaddr_in6 *)na->buf)->sin6_addr, 2292*0Sstevel@tonic-gate sizeof (*addr6p)); 2293*0Sstevel@tonic-gate *addrvec++ = (char *)addr6p; 2294*0Sstevel@tonic-gate } 2295*0Sstevel@tonic-gate } 2296*0Sstevel@tonic-gate *addrvec = 0; 2297*0Sstevel@tonic-gate result->h_aliases = addrvec; 2298*0Sstevel@tonic-gate 2299*0Sstevel@tonic-gate return (ND_OK); 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate 2302*0Sstevel@tonic-gate /* 2303*0Sstevel@tonic-gate * Process results from nd_addrlist ( returned by netdir_getbyname) 2304*0Sstevel@tonic-gate * into a servent using buf. 2305*0Sstevel@tonic-gate */ 2306*0Sstevel@tonic-gate int 2307*0Sstevel@tonic-gate ndaddr2srent(const char *name, const char *proto, ushort_t port, 2308*0Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 2309*0Sstevel@tonic-gate { 2310*0Sstevel@tonic-gate size_t i; 2311*0Sstevel@tonic-gate char *bufend = (buffer + buflen); 2312*0Sstevel@tonic-gate 2313*0Sstevel@tonic-gate result->s_port = (int)port; 2314*0Sstevel@tonic-gate 2315*0Sstevel@tonic-gate result->s_aliases = 2316*0Sstevel@tonic-gate (char **)ROUND_UP(buffer, sizeof (char *)); 2317*0Sstevel@tonic-gate result->s_aliases[0] = NULL; 2318*0Sstevel@tonic-gate buffer = (char *)&result->s_aliases[1]; 2319*0Sstevel@tonic-gate result->s_name = buffer; 2320*0Sstevel@tonic-gate i = strlen(name) + 1; 2321*0Sstevel@tonic-gate if ((buffer + i) > bufend) 2322*0Sstevel@tonic-gate return (ND_NOMEM); 2323*0Sstevel@tonic-gate (void) memcpy(buffer, name, i); 2324*0Sstevel@tonic-gate buffer += i; 2325*0Sstevel@tonic-gate 2326*0Sstevel@tonic-gate result->s_proto = buffer; 2327*0Sstevel@tonic-gate i = strlen(proto) + 1; 2328*0Sstevel@tonic-gate if ((buffer + i) > bufend) 2329*0Sstevel@tonic-gate return (ND_NOMEM); 2330*0Sstevel@tonic-gate (void) memcpy(buffer, proto, i); 2331*0Sstevel@tonic-gate buffer += i; 2332*0Sstevel@tonic-gate 2333*0Sstevel@tonic-gate return (ND_OK); 2334*0Sstevel@tonic-gate } 2335*0Sstevel@tonic-gate 2336*0Sstevel@tonic-gate /* 2337*0Sstevel@tonic-gate * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2338*0Sstevel@tonic-gate * into a hostent using buf. 2339*0Sstevel@tonic-gate * *** ASSUMES that nd_buf->buf is a sockaddr_in *** 2340*0Sstevel@tonic-gate */ 2341*0Sstevel@tonic-gate int 2342*0Sstevel@tonic-gate ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs, 2343*0Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen) 2344*0Sstevel@tonic-gate { 2345*0Sstevel@tonic-gate int i, count; 2346*0Sstevel@tonic-gate char *aliasp; 2347*0Sstevel@tonic-gate char **aliasvec; 2348*0Sstevel@tonic-gate struct sockaddr_in *sa; 2349*0Sstevel@tonic-gate struct nd_hostserv *hs; 2350*0Sstevel@tonic-gate const char *la; 2351*0Sstevel@tonic-gate size_t length; 2352*0Sstevel@tonic-gate 2353*0Sstevel@tonic-gate /* First, give the lonely address a specious home in h_addr_list. */ 2354*0Sstevel@tonic-gate aliasp = (char *)ROUND_UP(buffer, sizeof (sa->sin_addr)); 2355*0Sstevel@tonic-gate sa = (struct sockaddr_in *)nbuf->buf; 2356*0Sstevel@tonic-gate (void) memcpy(aliasp, (char *)&(sa->sin_addr), sizeof (sa->sin_addr)); 2357*0Sstevel@tonic-gate aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr), 2358*0Sstevel@tonic-gate sizeof (*aliasvec)); 2359*0Sstevel@tonic-gate result->h_addr_list = aliasvec; 2360*0Sstevel@tonic-gate *aliasvec++ = aliasp; 2361*0Sstevel@tonic-gate *aliasvec++ = 0; 2362*0Sstevel@tonic-gate 2363*0Sstevel@tonic-gate /* 2364*0Sstevel@tonic-gate * Build h_aliases at start of buffer (after addr and h_addr_list); 2365*0Sstevel@tonic-gate * store the alias strings at the end of the buffer (before h_name). 2366*0Sstevel@tonic-gate */ 2367*0Sstevel@tonic-gate 2368*0Sstevel@tonic-gate aliasp = buffer + buflen; 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate result->h_aliases = aliasvec; 2371*0Sstevel@tonic-gate 2372*0Sstevel@tonic-gate hs = addrs->h_hostservs; 2373*0Sstevel@tonic-gate if (! hs) 2374*0Sstevel@tonic-gate return (ND_NOHOST); 2375*0Sstevel@tonic-gate 2376*0Sstevel@tonic-gate length = strlen(hs->h_host) + 1; 2377*0Sstevel@tonic-gate aliasp -= length; 2378*0Sstevel@tonic-gate if ((char *)(&aliasvec[1]) > aliasp) 2379*0Sstevel@tonic-gate return (ND_NOMEM); 2380*0Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_host, length); 2381*0Sstevel@tonic-gate 2382*0Sstevel@tonic-gate result->h_name = aliasp; 2383*0Sstevel@tonic-gate result->h_addrtype = AF_INET; 2384*0Sstevel@tonic-gate result->h_length = sizeof (sa->sin_addr); 2385*0Sstevel@tonic-gate 2386*0Sstevel@tonic-gate /* 2387*0Sstevel@tonic-gate * Assumption: the netdir nametoaddr_libs 2388*0Sstevel@tonic-gate * sort the vector of (host, serv) pairs in such a way that 2389*0Sstevel@tonic-gate * all pairs with the same host name are contiguous. 2390*0Sstevel@tonic-gate */ 2391*0Sstevel@tonic-gate la = hs->h_host; 2392*0Sstevel@tonic-gate count = addrs->h_cnt; 2393*0Sstevel@tonic-gate for (i = 0; i < count; i++, hs++) 2394*0Sstevel@tonic-gate if (strcmp(la, hs->h_host) != 0) { 2395*0Sstevel@tonic-gate size_t len = strlen(hs->h_host) + 1; 2396*0Sstevel@tonic-gate 2397*0Sstevel@tonic-gate aliasp -= len; 2398*0Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > aliasp) 2399*0Sstevel@tonic-gate return (ND_NOMEM); 2400*0Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_host, len); 2401*0Sstevel@tonic-gate *aliasvec++ = aliasp; 2402*0Sstevel@tonic-gate la = hs->h_host; 2403*0Sstevel@tonic-gate } 2404*0Sstevel@tonic-gate *aliasvec = 0; 2405*0Sstevel@tonic-gate 2406*0Sstevel@tonic-gate return (ND_OK); 2407*0Sstevel@tonic-gate } 2408*0Sstevel@tonic-gate 2409*0Sstevel@tonic-gate /* 2410*0Sstevel@tonic-gate * Process results from nd_hostservlist ( returned by netdir_getbyaddr) 2411*0Sstevel@tonic-gate * into a servent using buf. 2412*0Sstevel@tonic-gate */ 2413*0Sstevel@tonic-gate int 2414*0Sstevel@tonic-gate ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs, 2415*0Sstevel@tonic-gate struct servent *result, char *buffer, int buflen) 2416*0Sstevel@tonic-gate { 2417*0Sstevel@tonic-gate int i, count; 2418*0Sstevel@tonic-gate char *aliasp; 2419*0Sstevel@tonic-gate char **aliasvec; 2420*0Sstevel@tonic-gate struct nd_hostserv *hs; 2421*0Sstevel@tonic-gate const char *host_cname; 2422*0Sstevel@tonic-gate size_t leni, lenj; 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate result->s_port = port; 2425*0Sstevel@tonic-gate /* 2426*0Sstevel@tonic-gate * Build s_aliases at start of buffer; 2427*0Sstevel@tonic-gate * store proto and aliases at the end of the buffer (before h_name). 2428*0Sstevel@tonic-gate */ 2429*0Sstevel@tonic-gate 2430*0Sstevel@tonic-gate aliasp = buffer + buflen; 2431*0Sstevel@tonic-gate aliasvec = (char **)ROUND_UP(buffer, sizeof (char *)); 2432*0Sstevel@tonic-gate 2433*0Sstevel@tonic-gate result->s_aliases = aliasvec; 2434*0Sstevel@tonic-gate 2435*0Sstevel@tonic-gate hs = addrs->h_hostservs; 2436*0Sstevel@tonic-gate if (! hs) 2437*0Sstevel@tonic-gate return (ND_NOHOST); 2438*0Sstevel@tonic-gate host_cname = hs->h_host; 2439*0Sstevel@tonic-gate 2440*0Sstevel@tonic-gate leni = strlen(proto) + 1; 2441*0Sstevel@tonic-gate lenj = strlen(hs->h_serv) + 1; 2442*0Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj)) 2443*0Sstevel@tonic-gate return (ND_NOMEM); 2444*0Sstevel@tonic-gate 2445*0Sstevel@tonic-gate aliasp -= leni; 2446*0Sstevel@tonic-gate (void) memcpy(aliasp, proto, leni); 2447*0Sstevel@tonic-gate result->s_proto = aliasp; 2448*0Sstevel@tonic-gate 2449*0Sstevel@tonic-gate aliasp -= lenj; 2450*0Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_serv, lenj); 2451*0Sstevel@tonic-gate result->s_name = aliasp; 2452*0Sstevel@tonic-gate 2453*0Sstevel@tonic-gate /* 2454*0Sstevel@tonic-gate * Assumption: the netdir nametoaddr_libs 2455*0Sstevel@tonic-gate * do a host aliases first and serv aliases next 2456*0Sstevel@tonic-gate * enumeration for creating the list of hostserv 2457*0Sstevel@tonic-gate * structures. 2458*0Sstevel@tonic-gate */ 2459*0Sstevel@tonic-gate count = addrs->h_cnt; 2460*0Sstevel@tonic-gate for (i = 0; 2461*0Sstevel@tonic-gate i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0; 2462*0Sstevel@tonic-gate i++, hs++) { 2463*0Sstevel@tonic-gate size_t len = strlen(hs->h_serv) + 1; 2464*0Sstevel@tonic-gate 2465*0Sstevel@tonic-gate aliasp -= len; 2466*0Sstevel@tonic-gate if ((char *)(&aliasvec[2]) > aliasp) 2467*0Sstevel@tonic-gate return (ND_NOMEM); 2468*0Sstevel@tonic-gate (void) memcpy(aliasp, hs->h_serv, len); 2469*0Sstevel@tonic-gate *aliasvec++ = aliasp; 2470*0Sstevel@tonic-gate } 2471*0Sstevel@tonic-gate *aliasvec = NULL; 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate return (ND_OK); 2474*0Sstevel@tonic-gate } 2475*0Sstevel@tonic-gate 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate static int 2478*0Sstevel@tonic-gate nd2herrno(int nerr) 2479*0Sstevel@tonic-gate { 2480*0Sstevel@tonic-gate trace1(TR_nd2herrno, 0); 2481*0Sstevel@tonic-gate switch (nerr) { 2482*0Sstevel@tonic-gate case ND_OK: 2483*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2484*0Sstevel@tonic-gate return (0); 2485*0Sstevel@tonic-gate case ND_TRY_AGAIN: 2486*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2487*0Sstevel@tonic-gate return (TRY_AGAIN); 2488*0Sstevel@tonic-gate case ND_NO_RECOVERY: 2489*0Sstevel@tonic-gate case ND_BADARG: 2490*0Sstevel@tonic-gate case ND_NOMEM: 2491*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2492*0Sstevel@tonic-gate return (NO_RECOVERY); 2493*0Sstevel@tonic-gate case ND_NO_DATA: 2494*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2495*0Sstevel@tonic-gate return (NO_DATA); 2496*0Sstevel@tonic-gate case ND_NOHOST: 2497*0Sstevel@tonic-gate case ND_NOSERV: 2498*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2499*0Sstevel@tonic-gate return (HOST_NOT_FOUND); 2500*0Sstevel@tonic-gate default: 2501*0Sstevel@tonic-gate trace1(TR_nd2herrno, 1); 2502*0Sstevel@tonic-gate return (NO_RECOVERY); 2503*0Sstevel@tonic-gate } 2504*0Sstevel@tonic-gate } 2505*0Sstevel@tonic-gate 2506*0Sstevel@tonic-gate /* 2507*0Sstevel@tonic-gate * This is a utility function so that various parts of libnsl can 2508*0Sstevel@tonic-gate * easily send ioctls down to ip. 2509*0Sstevel@tonic-gate * 2510*0Sstevel@tonic-gate */ 2511*0Sstevel@tonic-gate int 2512*0Sstevel@tonic-gate nss_ioctl(int af, int cmd, void *arg) 2513*0Sstevel@tonic-gate { 2514*0Sstevel@tonic-gate int fd; 2515*0Sstevel@tonic-gate char *devpath; 2516*0Sstevel@tonic-gate int retv; 2517*0Sstevel@tonic-gate 2518*0Sstevel@tonic-gate switch (af) { 2519*0Sstevel@tonic-gate case AF_INET6: 2520*0Sstevel@tonic-gate devpath = UDP6DEV; 2521*0Sstevel@tonic-gate break; 2522*0Sstevel@tonic-gate case AF_INET: 2523*0Sstevel@tonic-gate case AF_UNSPEC: 2524*0Sstevel@tonic-gate default: 2525*0Sstevel@tonic-gate devpath = UDPDEV; 2526*0Sstevel@tonic-gate } 2527*0Sstevel@tonic-gate if ((fd = open(devpath, O_RDONLY)) < 0) { 2528*0Sstevel@tonic-gate return (-1); 2529*0Sstevel@tonic-gate } 2530*0Sstevel@tonic-gate while ((retv = ioctl(fd, cmd, arg)) == -1) { 2531*0Sstevel@tonic-gate if (errno != EINTR) 2532*0Sstevel@tonic-gate break; 2533*0Sstevel@tonic-gate } 2534*0Sstevel@tonic-gate close(fd); 2535*0Sstevel@tonic-gate return (retv); 2536*0Sstevel@tonic-gate } 2537*0Sstevel@tonic-gate 2538*0Sstevel@tonic-gate static int 2539*0Sstevel@tonic-gate nss_strioctl(int af, int cmd, void *ptr, int ilen) 2540*0Sstevel@tonic-gate { 2541*0Sstevel@tonic-gate struct strioctl str; 2542*0Sstevel@tonic-gate 2543*0Sstevel@tonic-gate str.ic_cmd = cmd; 2544*0Sstevel@tonic-gate str.ic_timout = 0; 2545*0Sstevel@tonic-gate str.ic_len = ilen; 2546*0Sstevel@tonic-gate str.ic_dp = ptr; 2547*0Sstevel@tonic-gate 2548*0Sstevel@tonic-gate return (nss_ioctl(af, I_STR, &str)); 2549*0Sstevel@tonic-gate } 2550*0Sstevel@tonic-gate 2551*0Sstevel@tonic-gate static struct ifinfo * 2552*0Sstevel@tonic-gate get_local_info(void) 2553*0Sstevel@tonic-gate { 2554*0Sstevel@tonic-gate int numifs; 2555*0Sstevel@tonic-gate int n; 2556*0Sstevel@tonic-gate char *buf = NULL; 2557*0Sstevel@tonic-gate size_t needed; 2558*0Sstevel@tonic-gate struct lifconf lifc; 2559*0Sstevel@tonic-gate struct lifreq lifreq, *lifr; 2560*0Sstevel@tonic-gate struct lifnum lifn; 2561*0Sstevel@tonic-gate struct ifinfo *localinfo; 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 2564*0Sstevel@tonic-gate lifn.lifn_flags = 0; 2565*0Sstevel@tonic-gate 2566*0Sstevel@tonic-gate getifnum: 2567*0Sstevel@tonic-gate if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) { 2568*0Sstevel@tonic-gate numifs = MAXIFS; 2569*0Sstevel@tonic-gate } else { 2570*0Sstevel@tonic-gate numifs = lifn.lifn_count; 2571*0Sstevel@tonic-gate } 2572*0Sstevel@tonic-gate 2573*0Sstevel@tonic-gate /* 2574*0Sstevel@tonic-gate * Add a small fudge factor in case interfaces get plumbed between 2575*0Sstevel@tonic-gate * the call to SIOCGLIFNUM and SIOCGLIFCONF. 2576*0Sstevel@tonic-gate */ 2577*0Sstevel@tonic-gate needed = (numifs + 4) * sizeof (lifreq); 2578*0Sstevel@tonic-gate if (buf == NULL) 2579*0Sstevel@tonic-gate buf = malloc(needed); 2580*0Sstevel@tonic-gate else 2581*0Sstevel@tonic-gate buf = realloc(buf, needed); 2582*0Sstevel@tonic-gate if (buf == NULL) { 2583*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2584*0Sstevel@tonic-gate _nderror = ND_NOMEM; 2585*0Sstevel@tonic-gate return (NULL); 2586*0Sstevel@tonic-gate } 2587*0Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC; 2588*0Sstevel@tonic-gate lifc.lifc_flags = 0; 2589*0Sstevel@tonic-gate lifc.lifc_len = needed; 2590*0Sstevel@tonic-gate lifc.lifc_buf = buf; 2591*0Sstevel@tonic-gate if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) { 2592*0Sstevel@tonic-gate /* 2593*0Sstevel@tonic-gate * IP returns EINVAL if the buffer was too small to fit 2594*0Sstevel@tonic-gate * all of the entries. If that's the case, go back and 2595*0Sstevel@tonic-gate * try again. 2596*0Sstevel@tonic-gate */ 2597*0Sstevel@tonic-gate if (errno == EINVAL) 2598*0Sstevel@tonic-gate goto getifnum; 2599*0Sstevel@tonic-gate 2600*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: " 2601*0Sstevel@tonic-gate "ioctl (get interface configuration): %m"); 2602*0Sstevel@tonic-gate free(buf); 2603*0Sstevel@tonic-gate _nderror = ND_SYSTEM; 2604*0Sstevel@tonic-gate return (NULL); 2605*0Sstevel@tonic-gate } 2606*0Sstevel@tonic-gate lifr = (struct lifreq *)buf; 2607*0Sstevel@tonic-gate numifs = lifc.lifc_len/sizeof (lifreq); 2608*0Sstevel@tonic-gate localinfo = (struct ifinfo *)malloc(ifinfosize(numifs)); 2609*0Sstevel@tonic-gate if (localinfo == NULL) { 2610*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m"); 2611*0Sstevel@tonic-gate free(buf); 2612*0Sstevel@tonic-gate _nderror = ND_SYSTEM; 2613*0Sstevel@tonic-gate return (NULL); 2614*0Sstevel@tonic-gate } 2615*0Sstevel@tonic-gate 2616*0Sstevel@tonic-gate localinfo->addresses = (struct __ifaddr *) 2617*0Sstevel@tonic-gate ((char *)localinfo + sizeof (struct ifinfo)); 2618*0Sstevel@tonic-gate 2619*0Sstevel@tonic-gate for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) { 2620*0Sstevel@tonic-gate int af; 2621*0Sstevel@tonic-gate 2622*0Sstevel@tonic-gate lifreq = *lifr; 2623*0Sstevel@tonic-gate af = lifreq.lifr_addr.ss_family; 2624*0Sstevel@tonic-gate 2625*0Sstevel@tonic-gate /* Squirrel away the address */ 2626*0Sstevel@tonic-gate if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0) 2627*0Sstevel@tonic-gate continue; 2628*0Sstevel@tonic-gate 2629*0Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) { 2630*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 2631*0Sstevel@tonic-gate "n2a get_local_info: " 2632*0Sstevel@tonic-gate "ioctl (get interface flags): %m"); 2633*0Sstevel@tonic-gate continue; 2634*0Sstevel@tonic-gate } 2635*0Sstevel@tonic-gate if (!(lifreq.lifr_flags & IFF_UP)) 2636*0Sstevel@tonic-gate continue; 2637*0Sstevel@tonic-gate 2638*0Sstevel@tonic-gate if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) { 2639*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 2640*0Sstevel@tonic-gate "n2a get_local_info: " 2641*0Sstevel@tonic-gate "ioctl (get interface netmask): %m"); 2642*0Sstevel@tonic-gate continue; 2643*0Sstevel@tonic-gate } 2644*0Sstevel@tonic-gate 2645*0Sstevel@tonic-gate if (ifassign(lifreq, localinfo->count, IF_MASK) == 0) 2646*0Sstevel@tonic-gate continue; 2647*0Sstevel@tonic-gate 2648*0Sstevel@tonic-gate localinfo->count++; 2649*0Sstevel@tonic-gate } 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gate free(buf); 2652*0Sstevel@tonic-gate return (localinfo); 2653*0Sstevel@tonic-gate } 2654*0Sstevel@tonic-gate 2655*0Sstevel@tonic-gate static int 2656*0Sstevel@tonic-gate __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type, 2657*0Sstevel@tonic-gate void *addr) { 2658*0Sstevel@tonic-gate switch (type) { 2659*0Sstevel@tonic-gate case IF_ADDR: 2660*0Sstevel@tonic-gate ifa->af = af; 2661*0Sstevel@tonic-gate if (af == AF_INET6) { 2662*0Sstevel@tonic-gate ifa->addr.in6 = *(struct in6_addr *)addr; 2663*0Sstevel@tonic-gate } else { 2664*0Sstevel@tonic-gate ifa->addr.in4 = *(struct in_addr *)addr; 2665*0Sstevel@tonic-gate } 2666*0Sstevel@tonic-gate break; 2667*0Sstevel@tonic-gate case IF_MASK: 2668*0Sstevel@tonic-gate if (ifa->af == af) { 2669*0Sstevel@tonic-gate if (af == AF_INET6) { 2670*0Sstevel@tonic-gate ifa->mask.in6 = *(struct in6_addr *)addr; 2671*0Sstevel@tonic-gate } else { 2672*0Sstevel@tonic-gate ifa->mask.in4 = *(struct in_addr *)addr; 2673*0Sstevel@tonic-gate } 2674*0Sstevel@tonic-gate } else { 2675*0Sstevel@tonic-gate return (0); 2676*0Sstevel@tonic-gate } 2677*0Sstevel@tonic-gate break; 2678*0Sstevel@tonic-gate default: 2679*0Sstevel@tonic-gate return (0); 2680*0Sstevel@tonic-gate } 2681*0Sstevel@tonic-gate 2682*0Sstevel@tonic-gate return (1); 2683*0Sstevel@tonic-gate } 2684*0Sstevel@tonic-gate 2685*0Sstevel@tonic-gate static int 2686*0Sstevel@tonic-gate islocal(struct ifinfo *localinfo, struct in_addr addr) 2687*0Sstevel@tonic-gate { 2688*0Sstevel@tonic-gate int i; 2689*0Sstevel@tonic-gate 2690*0Sstevel@tonic-gate if (!localinfo) 2691*0Sstevel@tonic-gate return (0); 2692*0Sstevel@tonic-gate 2693*0Sstevel@tonic-gate for (i = 0; i < localinfo->count; i++) { 2694*0Sstevel@tonic-gate if (ifaf(i) == AF_INET && 2695*0Sstevel@tonic-gate ((addr.s_addr & ifmask4(i).s_addr) == 2696*0Sstevel@tonic-gate (ifaddr4(i).s_addr & ifmask4(i).s_addr))) 2697*0Sstevel@tonic-gate return (1); 2698*0Sstevel@tonic-gate } 2699*0Sstevel@tonic-gate return (0); 2700*0Sstevel@tonic-gate } 2701*0Sstevel@tonic-gate 2702*0Sstevel@tonic-gate /* 2703*0Sstevel@tonic-gate * Some higher-level routines for determining if an address is 2704*0Sstevel@tonic-gate * on a local network. 2705*0Sstevel@tonic-gate * 2706*0Sstevel@tonic-gate * __inet_get_local_interfaces() - get an opaque handle with 2707*0Sstevel@tonic-gate * with a list of local interfaces 2708*0Sstevel@tonic-gate * __inet_address_is_local() - return 1 if an address is 2709*0Sstevel@tonic-gate * on a local network; 0 otherwise 2710*0Sstevel@tonic-gate * __inet_free_local_interfaces() - free handle that was 2711*0Sstevel@tonic-gate * returned by __inet_get_local_interfaces() 2712*0Sstevel@tonic-gate * 2713*0Sstevel@tonic-gate * A typical calling sequence is: 2714*0Sstevel@tonic-gate * 2715*0Sstevel@tonic-gate * p = __inet_get_local_interfaces(); 2716*0Sstevel@tonic-gate * if (__inet_address_is_local(p, inaddr)) { 2717*0Sstevel@tonic-gate * ... 2718*0Sstevel@tonic-gate * } 2719*0Sstevel@tonic-gate * __inet_free_local_interfaces(p); 2720*0Sstevel@tonic-gate */ 2721*0Sstevel@tonic-gate 2722*0Sstevel@tonic-gate /* 2723*0Sstevel@tonic-gate * Return an opaque pointer to a list of configured interfaces. 2724*0Sstevel@tonic-gate */ 2725*0Sstevel@tonic-gate void * 2726*0Sstevel@tonic-gate __inet_get_local_interfaces(void) 2727*0Sstevel@tonic-gate { 2728*0Sstevel@tonic-gate return (get_local_info()); 2729*0Sstevel@tonic-gate } 2730*0Sstevel@tonic-gate 2731*0Sstevel@tonic-gate /* 2732*0Sstevel@tonic-gate * Free memory allocated by inet_local_interfaces(). 2733*0Sstevel@tonic-gate */ 2734*0Sstevel@tonic-gate void 2735*0Sstevel@tonic-gate __inet_free_local_interfaces(void *p) 2736*0Sstevel@tonic-gate { 2737*0Sstevel@tonic-gate free(p); 2738*0Sstevel@tonic-gate } 2739*0Sstevel@tonic-gate 2740*0Sstevel@tonic-gate /* 2741*0Sstevel@tonic-gate * Determine if an address is on a local network. 2742*0Sstevel@tonic-gate * 2743*0Sstevel@tonic-gate * Might have made sense to use SIOCTONLINK, except that it doesn't 2744*0Sstevel@tonic-gate * handle matching on IPv4 network addresses. 2745*0Sstevel@tonic-gate */ 2746*0Sstevel@tonic-gate int 2747*0Sstevel@tonic-gate __inet_address_is_local_af(void *p, sa_family_t af, void *addr) { 2748*0Sstevel@tonic-gate 2749*0Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 2750*0Sstevel@tonic-gate int i, a; 2751*0Sstevel@tonic-gate struct in_addr v4addr; 2752*0Sstevel@tonic-gate 2753*0Sstevel@tonic-gate if (localinfo == 0) 2754*0Sstevel@tonic-gate return (0); 2755*0Sstevel@tonic-gate 2756*0Sstevel@tonic-gate if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { 2757*0Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); 2758*0Sstevel@tonic-gate af = AF_INET; 2759*0Sstevel@tonic-gate addr = (void *)&v4addr; 2760*0Sstevel@tonic-gate } 2761*0Sstevel@tonic-gate 2762*0Sstevel@tonic-gate for (i = 0; i < localinfo->count; i++) { 2763*0Sstevel@tonic-gate if (ifaf(i) == af) { 2764*0Sstevel@tonic-gate if (af == AF_INET6) { 2765*0Sstevel@tonic-gate struct in6_addr *a6 = (struct in6_addr *)addr; 2766*0Sstevel@tonic-gate for (a = 0; a < sizeof (a6->s6_addr); a++) { 2767*0Sstevel@tonic-gate if ((a6->s6_addr[a] & 2768*0Sstevel@tonic-gate ifmask6(i).s6_addr[a]) != 2769*0Sstevel@tonic-gate (ifaddr6(i).s6_addr[a] & 2770*0Sstevel@tonic-gate ifmask6(i).s6_addr[a])) 2771*0Sstevel@tonic-gate break; 2772*0Sstevel@tonic-gate } 2773*0Sstevel@tonic-gate if (a >= sizeof (a6->s6_addr)) 2774*0Sstevel@tonic-gate return (1); 2775*0Sstevel@tonic-gate } else { 2776*0Sstevel@tonic-gate if ((((struct in_addr *)addr)->s_addr & 2777*0Sstevel@tonic-gate ifmask4(i).s_addr) == 2778*0Sstevel@tonic-gate (ifaddr4(i).s_addr & 2779*0Sstevel@tonic-gate ifmask4(i).s_addr)) 2780*0Sstevel@tonic-gate return (1); 2781*0Sstevel@tonic-gate } 2782*0Sstevel@tonic-gate } 2783*0Sstevel@tonic-gate } 2784*0Sstevel@tonic-gate 2785*0Sstevel@tonic-gate return (0); 2786*0Sstevel@tonic-gate } 2787*0Sstevel@tonic-gate 2788*0Sstevel@tonic-gate int 2789*0Sstevel@tonic-gate __inet_address_is_local(void *p, struct in_addr addr) 2790*0Sstevel@tonic-gate { 2791*0Sstevel@tonic-gate return (__inet_address_is_local_af(p, AF_INET, &addr)); 2792*0Sstevel@tonic-gate } 2793*0Sstevel@tonic-gate 2794*0Sstevel@tonic-gate int 2795*0Sstevel@tonic-gate __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr) 2796*0Sstevel@tonic-gate { 2797*0Sstevel@tonic-gate struct netbuf *taddr; 2798*0Sstevel@tonic-gate sa_family_t af; 2799*0Sstevel@tonic-gate int ret; 2800*0Sstevel@tonic-gate 2801*0Sstevel@tonic-gate taddr = uaddr2taddr(nc, uaddr); 2802*0Sstevel@tonic-gate if (taddr == 0) 2803*0Sstevel@tonic-gate return (0); 2804*0Sstevel@tonic-gate 2805*0Sstevel@tonic-gate af = ((struct sockaddr *)taddr->buf)->sa_family; 2806*0Sstevel@tonic-gate 2807*0Sstevel@tonic-gate ret = __inet_address_is_local_af(p, af, 2808*0Sstevel@tonic-gate (af == AF_INET6) ? 2809*0Sstevel@tonic-gate (void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr : 2810*0Sstevel@tonic-gate (void *)&((struct sockaddr_in *)taddr->buf)->sin_addr); 2811*0Sstevel@tonic-gate 2812*0Sstevel@tonic-gate netdir_free(taddr, ND_ADDR); 2813*0Sstevel@tonic-gate return (ret); 2814*0Sstevel@tonic-gate } 2815*0Sstevel@tonic-gate 2816*0Sstevel@tonic-gate 2817*0Sstevel@tonic-gate int 2818*0Sstevel@tonic-gate __inet_address_count(void *p) 2819*0Sstevel@tonic-gate { 2820*0Sstevel@tonic-gate struct ifinfo *lp = (struct ifinfo *)p; 2821*0Sstevel@tonic-gate 2822*0Sstevel@tonic-gate if (lp != 0) { 2823*0Sstevel@tonic-gate return (lp->count); 2824*0Sstevel@tonic-gate } else { 2825*0Sstevel@tonic-gate return (0); 2826*0Sstevel@tonic-gate } 2827*0Sstevel@tonic-gate } 2828*0Sstevel@tonic-gate 2829*0Sstevel@tonic-gate uint32_t 2830*0Sstevel@tonic-gate __inet_get_addr(void *p, int n) 2831*0Sstevel@tonic-gate { 2832*0Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 2833*0Sstevel@tonic-gate 2834*0Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 2835*0Sstevel@tonic-gate return (0); 2836*0Sstevel@tonic-gate 2837*0Sstevel@tonic-gate return (ifaddr4(n).s_addr); 2838*0Sstevel@tonic-gate } 2839*0Sstevel@tonic-gate 2840*0Sstevel@tonic-gate uint32_t 2841*0Sstevel@tonic-gate __inet_get_network(void *p, int n) 2842*0Sstevel@tonic-gate { 2843*0Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET) 2846*0Sstevel@tonic-gate return (0); 2847*0Sstevel@tonic-gate 2848*0Sstevel@tonic-gate return (ifaddr4(n).s_addr & ifmask4(n).s_addr); 2849*0Sstevel@tonic-gate } 2850*0Sstevel@tonic-gate 2851*0Sstevel@tonic-gate char * 2852*0Sstevel@tonic-gate __inet_get_uaddr(void *p, struct netconfig *nc, int n) 2853*0Sstevel@tonic-gate { 2854*0Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 2855*0Sstevel@tonic-gate char *uaddr; 2856*0Sstevel@tonic-gate struct sockaddr_in sin4; 2857*0Sstevel@tonic-gate struct sockaddr_in6 sin6; 2858*0Sstevel@tonic-gate struct sockaddr *sin; 2859*0Sstevel@tonic-gate struct netbuf nb; 2860*0Sstevel@tonic-gate 2861*0Sstevel@tonic-gate if (localinfo == 0 || nc == 0 || n >= localinfo->count) 2862*0Sstevel@tonic-gate return (0); 2863*0Sstevel@tonic-gate 2864*0Sstevel@tonic-gate if (ifaf(n) == AF_INET6) { 2865*0Sstevel@tonic-gate if (strcmp(NC_INET6, nc->nc_protofmly) != 0) 2866*0Sstevel@tonic-gate return (0); 2867*0Sstevel@tonic-gate memset(&sin6, 0, sizeof (sin6)); 2868*0Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 2869*0Sstevel@tonic-gate sin6.sin6_addr = ifaddr6(n); 2870*0Sstevel@tonic-gate nb.buf = (char *)&sin6; 2871*0Sstevel@tonic-gate nb.len = sizeof (sin6); 2872*0Sstevel@tonic-gate } else { 2873*0Sstevel@tonic-gate if (strcmp(NC_INET, nc->nc_protofmly) != 0) 2874*0Sstevel@tonic-gate return (0); 2875*0Sstevel@tonic-gate memset(&sin4, 0, sizeof (sin4)); 2876*0Sstevel@tonic-gate sin4.sin_family = AF_INET; 2877*0Sstevel@tonic-gate sin4.sin_addr = ifaddr4(n); 2878*0Sstevel@tonic-gate nb.buf = (char *)&sin4; 2879*0Sstevel@tonic-gate nb.len = sizeof (sin4); 2880*0Sstevel@tonic-gate } 2881*0Sstevel@tonic-gate 2882*0Sstevel@tonic-gate nb.maxlen = nb.len; 2883*0Sstevel@tonic-gate 2884*0Sstevel@tonic-gate uaddr = taddr2uaddr(nc, &nb); 2885*0Sstevel@tonic-gate return (uaddr); 2886*0Sstevel@tonic-gate } 2887*0Sstevel@tonic-gate 2888*0Sstevel@tonic-gate char * 2889*0Sstevel@tonic-gate __inet_get_networka(void *p, int n) 2890*0Sstevel@tonic-gate { 2891*0Sstevel@tonic-gate struct ifinfo *localinfo = (struct ifinfo *)p; 2892*0Sstevel@tonic-gate 2893*0Sstevel@tonic-gate if (localinfo == 0 || n >= localinfo->count) 2894*0Sstevel@tonic-gate return (0); 2895*0Sstevel@tonic-gate 2896*0Sstevel@tonic-gate if (ifaf(n) == AF_INET6) { 2897*0Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 2898*0Sstevel@tonic-gate struct in6_addr in6; 2899*0Sstevel@tonic-gate int i; 2900*0Sstevel@tonic-gate 2901*0Sstevel@tonic-gate for (i = 0; i < sizeof (in6.s6_addr); i++) { 2902*0Sstevel@tonic-gate in6.s6_addr[i] = ifaddr6(n).s6_addr[i] & 2903*0Sstevel@tonic-gate ifmask6(n).s6_addr[i]; 2904*0Sstevel@tonic-gate } 2905*0Sstevel@tonic-gate return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf)))); 2906*0Sstevel@tonic-gate } else { 2907*0Sstevel@tonic-gate struct in_addr in4; 2908*0Sstevel@tonic-gate 2909*0Sstevel@tonic-gate in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr; 2910*0Sstevel@tonic-gate return (strdup(inet_ntoa(in4))); 2911*0Sstevel@tonic-gate } 2912*0Sstevel@tonic-gate } 2913*0Sstevel@tonic-gate 2914*0Sstevel@tonic-gate static int 2915*0Sstevel@tonic-gate in_list(struct in_addr *addrs, int n, struct in_addr a) 2916*0Sstevel@tonic-gate { 2917*0Sstevel@tonic-gate int i; 2918*0Sstevel@tonic-gate 2919*0Sstevel@tonic-gate for (i = 0; i < n; i++) { 2920*0Sstevel@tonic-gate if (addrs[i].s_addr == a.s_addr) 2921*0Sstevel@tonic-gate return (1); 2922*0Sstevel@tonic-gate } 2923*0Sstevel@tonic-gate return (0); 2924*0Sstevel@tonic-gate } 2925*0Sstevel@tonic-gate 2926*0Sstevel@tonic-gate static int 2927*0Sstevel@tonic-gate getbroadcastnets(struct netconfig *tp, struct in_addr **addrs) 2928*0Sstevel@tonic-gate { 2929*0Sstevel@tonic-gate struct ifconf ifc; 2930*0Sstevel@tonic-gate struct ifreq ifreq, *ifr; 2931*0Sstevel@tonic-gate struct sockaddr_in *sin; 2932*0Sstevel@tonic-gate struct in_addr a; 2933*0Sstevel@tonic-gate int fd; 2934*0Sstevel@tonic-gate int n, i, numifs; 2935*0Sstevel@tonic-gate char *buf; 2936*0Sstevel@tonic-gate int use_loopback = 0; 2937*0Sstevel@tonic-gate 2938*0Sstevel@tonic-gate _nderror = ND_SYSTEM; 2939*0Sstevel@tonic-gate fd = open(tp->nc_device, O_RDONLY); 2940*0Sstevel@tonic-gate if (fd < 0) { 2941*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 2942*0Sstevel@tonic-gate "broadcast: open to get interface configuration: %m"); 2943*0Sstevel@tonic-gate return (0); 2944*0Sstevel@tonic-gate } 2945*0Sstevel@tonic-gate if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) 2946*0Sstevel@tonic-gate numifs = MAXIFS; 2947*0Sstevel@tonic-gate buf = (char *)malloc(numifs * sizeof (struct ifreq)); 2948*0Sstevel@tonic-gate if (buf == NULL) { 2949*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 2950*0Sstevel@tonic-gate (void) close(fd); 2951*0Sstevel@tonic-gate return (0); 2952*0Sstevel@tonic-gate } 2953*0Sstevel@tonic-gate *addrs = (struct in_addr *)malloc(numifs * sizeof (struct in_addr)); 2954*0Sstevel@tonic-gate if (*addrs == NULL) { 2955*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "broadcast: malloc failed: %m"); 2956*0Sstevel@tonic-gate free(buf); 2957*0Sstevel@tonic-gate (void) close(fd); 2958*0Sstevel@tonic-gate return (0); 2959*0Sstevel@tonic-gate } 2960*0Sstevel@tonic-gate ifc.ifc_len = numifs * (int)sizeof (struct ifreq); 2961*0Sstevel@tonic-gate ifc.ifc_buf = buf; 2962*0Sstevel@tonic-gate /* 2963*0Sstevel@tonic-gate * Ideally, this ioctl should also tell me, how many bytes were 2964*0Sstevel@tonic-gate * finally allocated, but it doesnt. 2965*0Sstevel@tonic-gate */ 2966*0Sstevel@tonic-gate if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) { 2967*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 2968*0Sstevel@tonic-gate "broadcast: ioctl (get interface configuration): %m"); 2969*0Sstevel@tonic-gate free(buf); 2970*0Sstevel@tonic-gate free(*addrs); 2971*0Sstevel@tonic-gate (void) close(fd); 2972*0Sstevel@tonic-gate return (0); 2973*0Sstevel@tonic-gate } 2974*0Sstevel@tonic-gate 2975*0Sstevel@tonic-gate retry: 2976*0Sstevel@tonic-gate ifr = (struct ifreq *)buf; 2977*0Sstevel@tonic-gate for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq); 2978*0Sstevel@tonic-gate n > 0; n--, ifr++) { 2979*0Sstevel@tonic-gate ifreq = *ifr; 2980*0Sstevel@tonic-gate if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 2981*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 2982*0Sstevel@tonic-gate "broadcast: ioctl (get interface flags): %m"); 2983*0Sstevel@tonic-gate continue; 2984*0Sstevel@tonic-gate } 2985*0Sstevel@tonic-gate if (!(ifreq.ifr_flags & IFF_UP) || 2986*0Sstevel@tonic-gate (ifr->ifr_addr.sa_family != AF_INET)) 2987*0Sstevel@tonic-gate continue; 2988*0Sstevel@tonic-gate if (ifreq.ifr_flags & IFF_BROADCAST) { 2989*0Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 2990*0Sstevel@tonic-gate if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 2991*0Sstevel@tonic-gate /* May not work with other implementation */ 2992*0Sstevel@tonic-gate a = _inet_makeaddr( 2993*0Sstevel@tonic-gate inet_netof(sin->sin_addr), 2994*0Sstevel@tonic-gate INADDR_ANY); 2995*0Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 2996*0Sstevel@tonic-gate (*addrs)[i++] = a; 2997*0Sstevel@tonic-gate } else { 2998*0Sstevel@tonic-gate a = ((struct sockaddr_in *) 2999*0Sstevel@tonic-gate &ifreq.ifr_addr)->sin_addr; 3000*0Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 3001*0Sstevel@tonic-gate (*addrs)[i++] = a; 3002*0Sstevel@tonic-gate } 3003*0Sstevel@tonic-gate continue; 3004*0Sstevel@tonic-gate } 3005*0Sstevel@tonic-gate if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) { 3006*0Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 3007*0Sstevel@tonic-gate a = sin->sin_addr; 3008*0Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 3009*0Sstevel@tonic-gate (*addrs)[i++] = a; 3010*0Sstevel@tonic-gate continue; 3011*0Sstevel@tonic-gate } 3012*0Sstevel@tonic-gate if (ifreq.ifr_flags & IFF_POINTOPOINT) { 3013*0Sstevel@tonic-gate if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0) 3014*0Sstevel@tonic-gate continue; 3015*0Sstevel@tonic-gate a = ((struct sockaddr_in *) 3016*0Sstevel@tonic-gate &ifreq.ifr_addr)->sin_addr; 3017*0Sstevel@tonic-gate if (!in_list(*addrs, i, a)) 3018*0Sstevel@tonic-gate (*addrs)[i++] = a; 3019*0Sstevel@tonic-gate continue; 3020*0Sstevel@tonic-gate } 3021*0Sstevel@tonic-gate } 3022*0Sstevel@tonic-gate if (i == 0 && !use_loopback) { 3023*0Sstevel@tonic-gate use_loopback = 1; 3024*0Sstevel@tonic-gate goto retry; 3025*0Sstevel@tonic-gate } 3026*0Sstevel@tonic-gate free(buf); 3027*0Sstevel@tonic-gate (void) close(fd); 3028*0Sstevel@tonic-gate if (i) 3029*0Sstevel@tonic-gate _nderror = ND_OK; 3030*0Sstevel@tonic-gate else 3031*0Sstevel@tonic-gate free(*addrs); 3032*0Sstevel@tonic-gate return (i); 3033*0Sstevel@tonic-gate } 3034*0Sstevel@tonic-gate 3035*0Sstevel@tonic-gate /* 3036*0Sstevel@tonic-gate * This is lifted straight from libsocket/inet/inet_mkaddr.c. 3037*0Sstevel@tonic-gate * Copied here to avoid our dependency on libsocket. More importantly, 3038*0Sstevel@tonic-gate * to make sure partially static apps that use libnsl, but not 3039*0Sstevel@tonic-gate * libsocket, don't get screwed up. 3040*0Sstevel@tonic-gate * If you understand the above paragraph, try to get rid of 3041*0Sstevel@tonic-gate * this copy of inet_makeaddr; if you don;t, leave it alone. 3042*0Sstevel@tonic-gate * 3043*0Sstevel@tonic-gate * Formulate an Internet address from network + host. Used in 3044*0Sstevel@tonic-gate * building addresses stored in the ifnet structure. 3045*0Sstevel@tonic-gate */ 3046*0Sstevel@tonic-gate static struct in_addr 3047*0Sstevel@tonic-gate _inet_makeaddr(in_addr_t net, in_addr_t host) 3048*0Sstevel@tonic-gate { 3049*0Sstevel@tonic-gate in_addr_t addr; 3050*0Sstevel@tonic-gate struct in_addr inaddr; 3051*0Sstevel@tonic-gate 3052*0Sstevel@tonic-gate if (net < 128) 3053*0Sstevel@tonic-gate addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST); 3054*0Sstevel@tonic-gate else if (net < 65536) 3055*0Sstevel@tonic-gate addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST); 3056*0Sstevel@tonic-gate else if (net < 16777216L) 3057*0Sstevel@tonic-gate addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST); 3058*0Sstevel@tonic-gate else 3059*0Sstevel@tonic-gate addr = net | host; 3060*0Sstevel@tonic-gate inaddr.s_addr = htonl(addr); 3061*0Sstevel@tonic-gate return (inaddr); 3062*0Sstevel@tonic-gate } 3063*0Sstevel@tonic-gate 3064*0Sstevel@tonic-gate /* 3065*0Sstevel@tonic-gate * Routine to read the default configuration file and check if SORT_ADDRS 3066*0Sstevel@tonic-gate * is set to NO or FALSE. This routine is called by order_haddrlist_af() 3067*0Sstevel@tonic-gate * to determine if the addresses need to be sorted. 3068*0Sstevel@tonic-gate */ 3069*0Sstevel@tonic-gate static boolean_t 3070*0Sstevel@tonic-gate _read_nsw_file(void) 3071*0Sstevel@tonic-gate { 3072*0Sstevel@tonic-gate char defval[LINESIZE]; 3073*0Sstevel@tonic-gate __NSL_FILE *defl; 3074*0Sstevel@tonic-gate boolean_t nosort = B_FALSE; 3075*0Sstevel@tonic-gate 3076*0Sstevel@tonic-gate 3077*0Sstevel@tonic-gate do { 3078*0Sstevel@tonic-gate defl = __nsl_fopen(__NSW_DEFAULT_FILE, "r"); 3079*0Sstevel@tonic-gate } while ((defl == NULL) && (errno == EINTR)); 3080*0Sstevel@tonic-gate 3081*0Sstevel@tonic-gate if (defl == NULL) 3082*0Sstevel@tonic-gate return (B_FALSE); 3083*0Sstevel@tonic-gate 3084*0Sstevel@tonic-gate while (__nsl_fgets(defval, sizeof (defval), defl) != NULL) { 3085*0Sstevel@tonic-gate if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) || 3086*0Sstevel@tonic-gate (strncmp(DONT_SORT2, defval, 3087*0Sstevel@tonic-gate sizeof (DONT_SORT2) - 1) == 0)) { 3088*0Sstevel@tonic-gate nosort = B_TRUE; 3089*0Sstevel@tonic-gate break; 3090*0Sstevel@tonic-gate } 3091*0Sstevel@tonic-gate } 3092*0Sstevel@tonic-gate __nsl_fclose(defl); 3093*0Sstevel@tonic-gate return (nosort); 3094*0Sstevel@tonic-gate } 3095