10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*132Srobinson 230Sstevel@tonic-gate /* 24*132Srobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate * 270Sstevel@tonic-gate * lib/libnsl/nss/netdir_inet_sundry.c 280Sstevel@tonic-gate * 290Sstevel@tonic-gate * This file contains inet-specific implementations of netdir_options, 300Sstevel@tonic-gate * uaddr2taddr, and taddr2uaddr. These implementations 310Sstevel@tonic-gate * used to be in both tcpip.so and switch.so (identical copies). 320Sstevel@tonic-gate * Since we got rid of those, and also it's a good idea to build-in 330Sstevel@tonic-gate * inet-specific implementations in one place, we decided to put 340Sstevel@tonic-gate * them in this file with a not-so glorious name. These are INET-SPECIFIC 350Sstevel@tonic-gate * only, and will not be used for non-inet transports or by third-parties 360Sstevel@tonic-gate * that decide to provide their own nametoaddr libs for inet transports 370Sstevel@tonic-gate * (they are on their own for these as well => they get flexibility). 380Sstevel@tonic-gate * 390Sstevel@tonic-gate * Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include "mt.h" 450Sstevel@tonic-gate #include <stdlib.h> 460Sstevel@tonic-gate #include <stdio.h> 470Sstevel@tonic-gate #include <string.h> 48*132Srobinson #include <strings.h> 490Sstevel@tonic-gate #include <unistd.h> 500Sstevel@tonic-gate #include <sys/types.h> 510Sstevel@tonic-gate #include <sys/stat.h> 520Sstevel@tonic-gate #include <fcntl.h> 530Sstevel@tonic-gate #include <errno.h> 540Sstevel@tonic-gate #include <thread.h> 550Sstevel@tonic-gate #include <netconfig.h> 560Sstevel@tonic-gate #include <netdir.h> 570Sstevel@tonic-gate #include <nss_netdir.h> 580Sstevel@tonic-gate #include <tiuser.h> 590Sstevel@tonic-gate #include <sys/socket.h> 600Sstevel@tonic-gate #include <net/if.h> 610Sstevel@tonic-gate #include <sys/sockio.h> 620Sstevel@tonic-gate #include <sys/fcntl.h> 630Sstevel@tonic-gate #include <netinet/in.h> 640Sstevel@tonic-gate #include <netinet/tcp.h> 650Sstevel@tonic-gate #include <netinet/udp.h> 660Sstevel@tonic-gate #include <arpa/inet.h> 670Sstevel@tonic-gate #include <rpc/types.h> 680Sstevel@tonic-gate #include <rpc/rpc_com.h> 690Sstevel@tonic-gate #include <syslog.h> 700Sstevel@tonic-gate #include <values.h> 710Sstevel@tonic-gate #include <limits.h> 720Sstevel@tonic-gate #ifdef DEBUG 730Sstevel@tonic-gate #include <stdio.h> 740Sstevel@tonic-gate #endif 750Sstevel@tonic-gate #include <nss_dbdefs.h> 760Sstevel@tonic-gate #include "nss.h" 770Sstevel@tonic-gate 780Sstevel@tonic-gate #define MAXIFS 32 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Extracted from socketvar.h 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate #define SOV_DEFAULT 1 /* Select based on so_default_version */ 840Sstevel@tonic-gate #define SOV_SOCKBSD 3 /* Socket with no streams operations */ 850Sstevel@tonic-gate 86*132Srobinson extern int _so_socket(int, int, int, char *, int); 87*132Srobinson extern int _so_connect(int, struct sockaddr *, socklen_t, int); 88*132Srobinson extern int _so_getsockname(int, struct sockaddr *, socklen_t *, int); 890Sstevel@tonic-gate 900Sstevel@tonic-gate 910Sstevel@tonic-gate static char *inet_netdir_mergeaddr(struct netconfig *, char *, char *); 920Sstevel@tonic-gate static int bindresvport(struct netconfig *, int, struct netbuf *); 930Sstevel@tonic-gate static int checkresvport(struct netbuf *); 940Sstevel@tonic-gate static struct netbuf *ip_uaddr2taddr(char *); 950Sstevel@tonic-gate static struct netbuf *ipv6_uaddr2taddr(char *); 960Sstevel@tonic-gate 970Sstevel@tonic-gate 980Sstevel@tonic-gate extern char *inet_ntoa_r(struct in_addr, char *); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate int 101*132Srobinson __inet_netdir_options(struct netconfig *tp, int opts, int fd, char *par) 1020Sstevel@tonic-gate { 1030Sstevel@tonic-gate struct nd_mergearg *ma; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate switch (opts) { 1060Sstevel@tonic-gate case ND_SET_BROADCAST: 1070Sstevel@tonic-gate /* Every one is allowed to broadcast without asking */ 1080Sstevel@tonic-gate return (ND_OK); 1090Sstevel@tonic-gate case ND_SET_RESERVEDPORT: /* bind to a resered port */ 110*132Srobinson /* LINTED pointer cast */ 1110Sstevel@tonic-gate return (bindresvport(tp, fd, (struct netbuf *)par)); 1120Sstevel@tonic-gate case ND_CHECK_RESERVEDPORT: /* check if reserved prot */ 113*132Srobinson /* LINTED pointer cast */ 1140Sstevel@tonic-gate return (checkresvport((struct netbuf *)par)); 1150Sstevel@tonic-gate case ND_MERGEADDR: /* Merge two addresses */ 116*132Srobinson /* LINTED pointer cast */ 1170Sstevel@tonic-gate ma = (struct nd_mergearg *)(par); 1180Sstevel@tonic-gate ma->m_uaddr = inet_netdir_mergeaddr(tp, ma->c_uaddr, 1190Sstevel@tonic-gate ma->s_uaddr); 1200Sstevel@tonic-gate return (_nderror); 1210Sstevel@tonic-gate default: 1220Sstevel@tonic-gate return (ND_NOCTRL); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * This routine will convert a TCP/IP internal format address 1290Sstevel@tonic-gate * into a "universal" format address. In our case it prints out the 1300Sstevel@tonic-gate * decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host 1310Sstevel@tonic-gate * address and p1-p2 are the port number. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate char * 134*132Srobinson __inet_taddr2uaddr(struct netconfig *tp, struct netbuf *addr) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate struct sockaddr_in *sa; /* our internal format */ 1370Sstevel@tonic-gate struct sockaddr_in6 *sa6; /* our internal format */ 1380Sstevel@tonic-gate char tmp[RPC_INET6_MAXUADDRSIZE]; 1390Sstevel@tonic-gate unsigned short myport; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (addr == NULL || tp == NULL || addr->buf == NULL) { 1420Sstevel@tonic-gate _nderror = ND_BADARG; 1430Sstevel@tonic-gate return (NULL); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate if (strcmp(tp->nc_protofmly, NC_INET) == 0) { 146*132Srobinson /* LINTED pointer cast */ 1470Sstevel@tonic-gate sa = (struct sockaddr_in *)(addr->buf); 1480Sstevel@tonic-gate myport = ntohs(sa->sin_port); 149*132Srobinson (void) inet_ntoa_r(sa->sin_addr, tmp); 1500Sstevel@tonic-gate } else { 151*132Srobinson /* LINTED pointer cast */ 1520Sstevel@tonic-gate sa6 = (struct sockaddr_in6 *)(addr->buf); 1530Sstevel@tonic-gate myport = ntohs(sa6->sin6_port); 1540Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)sa6->sin6_addr.s6_addr, 1550Sstevel@tonic-gate tmp, sizeof (tmp)) == 0) { 1560Sstevel@tonic-gate _nderror = ND_BADARG; 1570Sstevel@tonic-gate return (NULL); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate (void) sprintf(tmp + strlen(tmp), ".%d.%d", myport >> 8, myport & 255); 1620Sstevel@tonic-gate return (strdup(tmp)); /* Doesn't return static data ! */ 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* 1660Sstevel@tonic-gate * This internal routine will convert one of those "universal" addresses 1670Sstevel@tonic-gate * to the internal format used by the Sun TLI TCP/IP provider. 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate struct netbuf * 170*132Srobinson __inet_uaddr2taddr(struct netconfig *tp, char *addr) 1710Sstevel@tonic-gate { 1720Sstevel@tonic-gate if (!addr || !tp) { 1730Sstevel@tonic-gate _nderror = ND_BADARG; 1740Sstevel@tonic-gate return (NULL); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate if (strcmp(tp->nc_protofmly, NC_INET) == 0) 1770Sstevel@tonic-gate return (ip_uaddr2taddr(addr)); 1780Sstevel@tonic-gate else 1790Sstevel@tonic-gate return (ipv6_uaddr2taddr(addr)); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate static struct netbuf * 1830Sstevel@tonic-gate ip_uaddr2taddr(char *addr) 1840Sstevel@tonic-gate { 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate struct sockaddr_in *sa; 1870Sstevel@tonic-gate uint32_t inaddr; 1880Sstevel@tonic-gate unsigned short inport; 1890Sstevel@tonic-gate int h1, h2, h3, h4, p1, p2; 1900Sstevel@tonic-gate struct netbuf *result; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate result = malloc(sizeof (struct netbuf)); 1930Sstevel@tonic-gate if (!result) { 1940Sstevel@tonic-gate _nderror = ND_NOMEM; 1950Sstevel@tonic-gate return (NULL); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate sa = calloc(1, sizeof (*sa)); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (!sa) { 2010Sstevel@tonic-gate free(result); 2020Sstevel@tonic-gate _nderror = ND_NOMEM; 2030Sstevel@tonic-gate return (NULL); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate result->buf = (char *)(sa); 2070Sstevel@tonic-gate result->maxlen = sizeof (struct sockaddr_in); 2080Sstevel@tonic-gate result->len = sizeof (struct sockaddr_in); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* XXX there is probably a better way to do this. */ 2110Sstevel@tonic-gate if (sscanf(addr, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, &h4, 2120Sstevel@tonic-gate &p1, &p2) != 6) { 2130Sstevel@tonic-gate free(result); 2140Sstevel@tonic-gate _nderror = ND_NO_RECOVERY; 2150Sstevel@tonic-gate return (NULL); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* convert the host address first */ 2190Sstevel@tonic-gate inaddr = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4; 2200Sstevel@tonic-gate sa->sin_addr.s_addr = htonl(inaddr); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* convert the port */ 2230Sstevel@tonic-gate inport = (p1 << 8) + p2; 2240Sstevel@tonic-gate sa->sin_port = htons(inport); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate sa->sin_family = AF_INET; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate return (result); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate static struct netbuf * 2320Sstevel@tonic-gate ipv6_uaddr2taddr(char *addr) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate struct sockaddr_in6 *sa; 2350Sstevel@tonic-gate unsigned short inport; 2360Sstevel@tonic-gate int p1, p2; 2370Sstevel@tonic-gate struct netbuf *result; 2380Sstevel@tonic-gate char tmpaddr[RPC_INET6_MAXUADDRSIZE]; 2390Sstevel@tonic-gate char *dot; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate result = malloc(sizeof (struct netbuf)); 2420Sstevel@tonic-gate if (!result) { 2430Sstevel@tonic-gate _nderror = ND_NOMEM; 2440Sstevel@tonic-gate return (NULL); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate sa = calloc(1, sizeof (struct sockaddr_in6)); 2480Sstevel@tonic-gate if (!sa) { 2490Sstevel@tonic-gate free(result); 2500Sstevel@tonic-gate _nderror = ND_NOMEM; 2510Sstevel@tonic-gate return (NULL); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate result->buf = (char *)(sa); 2540Sstevel@tonic-gate result->maxlen = sizeof (struct sockaddr_in6); 2550Sstevel@tonic-gate result->len = sizeof (struct sockaddr_in6); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* retrieve the ipv6 address and port info */ 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate if (strlen(addr) > sizeof (tmpaddr) - 1) { 2600Sstevel@tonic-gate free(result); 2610Sstevel@tonic-gate _nderror = ND_NOMEM; 2620Sstevel@tonic-gate return (NULL); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 265*132Srobinson (void) strcpy(tmpaddr, addr); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if ((dot = strrchr(tmpaddr, '.')) != 0) { 2680Sstevel@tonic-gate *dot = '\0'; 2690Sstevel@tonic-gate p2 = atoi(dot+1); 2700Sstevel@tonic-gate if ((dot = strrchr(tmpaddr, '.')) != 0) { 2710Sstevel@tonic-gate *dot = '\0'; 2720Sstevel@tonic-gate p1 = atoi(dot+1); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if (dot == 0) { 2770Sstevel@tonic-gate free(result); 2780Sstevel@tonic-gate _nderror = ND_NOMEM; 2790Sstevel@tonic-gate return (NULL); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate if (inet_pton(AF_INET6, tmpaddr, sa->sin6_addr.s6_addr) == 0) { 2830Sstevel@tonic-gate free(result); 2840Sstevel@tonic-gate _nderror = ND_NOMEM; 2850Sstevel@tonic-gate return (NULL); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* convert the port */ 2890Sstevel@tonic-gate inport = (p1 << 8) + p2; 2900Sstevel@tonic-gate sa->sin6_port = htons(inport); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate sa->sin6_family = AF_INET6; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate return (result); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * Interface caching routines. The cache is refreshed every 2990Sstevel@tonic-gate * IF_CACHE_REFRESH_TIME seconds. A read-write lock is used to 3000Sstevel@tonic-gate * protect the cache. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate #define IF_CACHE_REFRESH_TIME 10 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate static int if_cache_refresh_time = IF_CACHE_REFRESH_TIME; 3050Sstevel@tonic-gate static rwlock_t iflock = DEFAULTRWLOCK; 3060Sstevel@tonic-gate static time_t last_updated = 0; /* protected by iflock */ 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * Changing the data type of if_flags from uint_t to uint64_t to accomodate 3100Sstevel@tonic-gate * extra flags. Refer <net/if.h> for the extra flags. 3110Sstevel@tonic-gate */ 3120Sstevel@tonic-gate typedef struct if_info_s { 3130Sstevel@tonic-gate struct in_addr if_netmask; /* netmask in network order */ 3140Sstevel@tonic-gate struct in_addr if_address; /* address in network order */ 3150Sstevel@tonic-gate uint64_t if_flags; /* interface flags */ 3160Sstevel@tonic-gate } if_info_t; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate static if_info_t *if_info = NULL; /* if cache, protected by iflock */ 3190Sstevel@tonic-gate static int n_ifs = 0; /* number of cached interfaces */ 3200Sstevel@tonic-gate static int numifs_last = 0; /* number of interfaces last seen */ 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Builds the interface cache. Write lock on iflock is needed 3240Sstevel@tonic-gate * for calling this routine. It sets _nderror for error returns. 3250Sstevel@tonic-gate * Returns TRUE if successful, FALSE otherwise. 3260Sstevel@tonic-gate * Changing the structures ifreq and ifconf to lifreq and lifconf to 3270Sstevel@tonic-gate * have larger flag field. This is to accomodate the extra flags associated 3280Sstevel@tonic-gate * with the interface. Also introducing lifn which will contain the number 3290Sstevel@tonic-gate * of IPV4 interfaces present. 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate static bool_t 332*132Srobinson get_if_info(void) 3330Sstevel@tonic-gate { 3340Sstevel@tonic-gate size_t needed; 3350Sstevel@tonic-gate struct lifreq *buf = NULL; 3360Sstevel@tonic-gate int numifs; 3370Sstevel@tonic-gate struct lifconf lifc; 3380Sstevel@tonic-gate struct lifreq *lifr; 3390Sstevel@tonic-gate struct lifnum lifn; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate lifn.lifn_family = AF_INET; 3420Sstevel@tonic-gate lifn.lifn_flags = 0; 3430Sstevel@tonic-gate getifnum: 3440Sstevel@tonic-gate if (nss_ioctl(AF_INET, SIOCGLIFNUM, &lifn) == -1) { 3450Sstevel@tonic-gate numifs = MAXIFS; 3460Sstevel@tonic-gate } else { 3470Sstevel@tonic-gate numifs = lifn.lifn_count; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Add a small fudge factor in case interfaces are plumbed 3510Sstevel@tonic-gate * between the SIOCGLIFNUM and SIOCGLIFCONF. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate needed = (numifs + 4) * sizeof (struct lifreq); 3540Sstevel@tonic-gate if (buf == NULL) 3550Sstevel@tonic-gate buf = malloc(needed); 3560Sstevel@tonic-gate else 3570Sstevel@tonic-gate buf = realloc(buf, needed); 3580Sstevel@tonic-gate if (buf == NULL) { 3590Sstevel@tonic-gate _nderror = ND_NOMEM; 3600Sstevel@tonic-gate return (FALSE); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate lifc.lifc_family = AF_INET; 3640Sstevel@tonic-gate lifc.lifc_flags = 0; 3650Sstevel@tonic-gate lifc.lifc_len = needed; 3660Sstevel@tonic-gate lifc.lifc_buf = (char *)buf; 3670Sstevel@tonic-gate if (nss_ioctl(AF_INET, SIOCGLIFCONF, &lifc) == -1) { 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * IP returns EINVAL if the buffer was too small to fit 3700Sstevel@tonic-gate * all of the entries. If that's the case, go back and 3710Sstevel@tonic-gate * try again. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate if (errno == EINVAL) 3740Sstevel@tonic-gate goto getifnum; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate free(buf); 3770Sstevel@tonic-gate free(if_info); 3780Sstevel@tonic-gate if_info = NULL; 3790Sstevel@tonic-gate _nderror = ND_SYSTEM; 3800Sstevel@tonic-gate return (FALSE); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate numifs = lifc.lifc_len / (int)sizeof (struct lifreq); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate if (if_info == NULL || numifs > numifs_last) { 3850Sstevel@tonic-gate if (if_info == NULL) 3860Sstevel@tonic-gate if_info = malloc(numifs * sizeof (if_info_t)); 3870Sstevel@tonic-gate else 3880Sstevel@tonic-gate if_info = realloc(if_info, numifs * sizeof (if_info_t)); 3890Sstevel@tonic-gate if (if_info == NULL) { 3900Sstevel@tonic-gate free(buf); 3910Sstevel@tonic-gate _nderror = ND_NOMEM; 3920Sstevel@tonic-gate return (FALSE); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate numifs_last = numifs; 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate n_ifs = 0; 3980Sstevel@tonic-gate for (lifr = buf; lifr < (buf + numifs); lifr++) { 3990Sstevel@tonic-gate if (lifr->lifr_addr.ss_family != AF_INET) 4000Sstevel@tonic-gate continue; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if_info[n_ifs].if_address = 4030Sstevel@tonic-gate ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if (nss_ioctl(AF_INET, SIOCGLIFFLAGS, lifr) < 0) 4060Sstevel@tonic-gate continue; 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if ((lifr->lifr_flags & IFF_UP) == 0) 4090Sstevel@tonic-gate continue; 4100Sstevel@tonic-gate if_info[n_ifs].if_flags = lifr->lifr_flags; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (nss_ioctl(AF_INET, SIOCGLIFNETMASK, lifr) < 0) 4130Sstevel@tonic-gate continue; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if_info[n_ifs].if_netmask = 4160Sstevel@tonic-gate ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr; 4170Sstevel@tonic-gate n_ifs++; 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate free(buf); 4200Sstevel@tonic-gate return (TRUE); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * Update the interface cache based on last update time. 4260Sstevel@tonic-gate */ 4270Sstevel@tonic-gate static bool_t 428*132Srobinson update_if_cache(void) 4290Sstevel@tonic-gate { 4300Sstevel@tonic-gate time_t curtime; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate (void) rw_wrlock(&iflock); 4330Sstevel@tonic-gate /* 4340Sstevel@tonic-gate * Check if some other thread has beaten this one to it. 4350Sstevel@tonic-gate */ 4360Sstevel@tonic-gate (void) time(&curtime); 4370Sstevel@tonic-gate if ((curtime - last_updated) >= if_cache_refresh_time) { 4380Sstevel@tonic-gate if (!get_if_info()) { 4390Sstevel@tonic-gate (void) rw_unlock(&iflock); 4400Sstevel@tonic-gate return (FALSE); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate (void) time(&last_updated); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate (void) rw_unlock(&iflock); 4450Sstevel@tonic-gate return (TRUE); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Given an IP address, check if this matches any of the interface 4510Sstevel@tonic-gate * addresses. If an error occurs, return FALSE so that the caller 4520Sstevel@tonic-gate * will not assume that this address belongs to this machine. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate static bool_t 455*132Srobinson is_my_address(struct in_addr addr) 4560Sstevel@tonic-gate { 4570Sstevel@tonic-gate time_t curtime; 4580Sstevel@tonic-gate if_info_t *ifn; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate (void) time(&curtime); 4610Sstevel@tonic-gate if ((curtime - last_updated) >= if_cache_refresh_time) { 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * Cache needs to be refreshed. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate if (!update_if_cache()) 4660Sstevel@tonic-gate return (FALSE); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate (void) rw_rdlock(&iflock); 4690Sstevel@tonic-gate for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 4700Sstevel@tonic-gate if (addr.s_addr == ifn->if_address.s_addr) { 4710Sstevel@tonic-gate (void) rw_unlock(&iflock); 4720Sstevel@tonic-gate return (TRUE); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate (void) rw_unlock(&iflock); 4760Sstevel@tonic-gate return (FALSE); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * Given a host name, check if it is this host. 4820Sstevel@tonic-gate */ 4830Sstevel@tonic-gate bool_t 484*132Srobinson __inet_netdir_is_my_host(const char *host) 4850Sstevel@tonic-gate { 4860Sstevel@tonic-gate int error; 4870Sstevel@tonic-gate char buf[NSS_BUFLEN_HOSTS]; 4880Sstevel@tonic-gate struct hostent res, *h; 4890Sstevel@tonic-gate char **c; 4900Sstevel@tonic-gate struct in_addr in; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate h = gethostbyname_r(host, (void *)&res, buf, sizeof (buf), &error); 4930Sstevel@tonic-gate if (h == NULL) 4940Sstevel@tonic-gate return (FALSE); 4950Sstevel@tonic-gate if (h->h_addrtype != AF_INET) 4960Sstevel@tonic-gate return (FALSE); 4970Sstevel@tonic-gate for (c = h->h_addr_list; *c != NULL; c++) { 498*132Srobinson (void) memcpy(&in.s_addr, *c, sizeof (in.s_addr)); 4990Sstevel@tonic-gate if (is_my_address(in)) 5000Sstevel@tonic-gate return (TRUE); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate return (FALSE); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Given an IP address, find the interface address that has the best 5080Sstevel@tonic-gate * prefix match. Return the address in network order. 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate static uint32_t 511*132Srobinson get_best_match(struct in_addr addr) 5120Sstevel@tonic-gate { 5130Sstevel@tonic-gate if_info_t *bestmatch, *ifn; 5140Sstevel@tonic-gate int bestcount, count, limit; 5150Sstevel@tonic-gate uint32_t mask, netmask, clnt_addr, if_addr; 5160Sstevel@tonic-gate bool_t found, subnet_match; 5170Sstevel@tonic-gate int subnet_count; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate bestmatch = NULL; /* no match yet */ 5200Sstevel@tonic-gate bestcount = BITSPERBYTE * sizeof (uint32_t); /* worst match */ 5210Sstevel@tonic-gate clnt_addr = ntohl(addr.s_addr); /* host order */ 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate subnet_match = FALSE; /* subnet match not found yet */ 5240Sstevel@tonic-gate subnet_count = bestcount; /* worst subnet match */ 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 5270Sstevel@tonic-gate netmask = ntohl(ifn->if_netmask.s_addr); /* host order */ 5280Sstevel@tonic-gate if_addr = ntohl(ifn->if_address.s_addr); /* host order */ 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate /* 5310Sstevel@tonic-gate * Checking if the interface selected is FAILED or DEPRECATED. 5320Sstevel@tonic-gate * In case IFF_FAILED or IFF_DEPRECATED flag for the interface 5330Sstevel@tonic-gate * is set, we move on to the next interface in the list. 5340Sstevel@tonic-gate * Refer IPMP(IP Multi Pathing) for more details. 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate if ((ifn->if_flags & (IFF_FAILED | IFF_DEPRECATED)) != 0) 5380Sstevel@tonic-gate continue; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * set initial count to first bit set in netmask, with 5420Sstevel@tonic-gate * zero being the number of the least significant bit. 5430Sstevel@tonic-gate */ 5440Sstevel@tonic-gate for (count = 0, mask = netmask; mask && ((mask & 1) == 0); 5450Sstevel@tonic-gate count++, mask >>= 1); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * Set limit so that we don't try to match prefixes shorter 5490Sstevel@tonic-gate * than the inherent netmask for the class (A, B, C, etc). 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate if (IN_CLASSC(if_addr)) 5520Sstevel@tonic-gate limit = IN_CLASSC_NSHIFT; 5530Sstevel@tonic-gate else if (IN_CLASSB(if_addr)) 5540Sstevel@tonic-gate limit = IN_CLASSB_NSHIFT; 5550Sstevel@tonic-gate else if (IN_CLASSA(if_addr)) 5560Sstevel@tonic-gate limit = IN_CLASSA_NSHIFT; 5570Sstevel@tonic-gate else 5580Sstevel@tonic-gate limit = 0; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * We assume that the netmask consists of a contiguous 5620Sstevel@tonic-gate * sequence of 1-bits starting with the most significant bit. 5630Sstevel@tonic-gate * Prefix comparison starts at the subnet mask level. 5640Sstevel@tonic-gate * The prefix mask used for comparison is progressively 5650Sstevel@tonic-gate * reduced until it equals the inherent mask for the 5660Sstevel@tonic-gate * interface address class. The algorithm finds an 5670Sstevel@tonic-gate * interface in the following order of preference: 5680Sstevel@tonic-gate * 5690Sstevel@tonic-gate * (1) the longest subnet match 5700Sstevel@tonic-gate * (2) the best partial subnet match 5710Sstevel@tonic-gate * (3) the first non-loopback && non-PPP interface 5720Sstevel@tonic-gate * (4) the first non-loopback interface (PPP is OK) 5730Sstevel@tonic-gate * 5740Sstevel@tonic-gate * While checking for condition (3) and (4), we also look 5750Sstevel@tonic-gate * if the interface we are returning is neither FAILED 5760Sstevel@tonic-gate * nor DEPRECATED. In case there are no interface 5770Sstevel@tonic-gate * available, which are neither FAILED nor DEPRECRATED, 5780Sstevel@tonic-gate * we return 0. 5790Sstevel@tonic-gate */ 5800Sstevel@tonic-gate found = FALSE; 5810Sstevel@tonic-gate while (netmask && count < subnet_count) { 5820Sstevel@tonic-gate if ((netmask & clnt_addr) == (netmask & if_addr)) { 5830Sstevel@tonic-gate bestcount = count; 5840Sstevel@tonic-gate bestmatch = ifn; 5850Sstevel@tonic-gate found = TRUE; 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate netmask <<= 1; 5890Sstevel@tonic-gate count++; 5900Sstevel@tonic-gate if (count >= bestcount || count > limit || subnet_match) 5910Sstevel@tonic-gate break; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * If a subnet level match occurred, note this for 5950Sstevel@tonic-gate * comparison with future subnet matches. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate if (found && (netmask == ntohl(ifn->if_netmask.s_addr))) { 5980Sstevel@tonic-gate subnet_match = TRUE; 5990Sstevel@tonic-gate subnet_count = count; 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate /* 6040Sstevel@tonic-gate * If we don't have a match, select the first interface that 6050Sstevel@tonic-gate * is not a loopback interface (and preferably not a PPP interface) 6060Sstevel@tonic-gate * as the best match. 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate if (bestmatch == NULL) { 6090Sstevel@tonic-gate for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) { 6100Sstevel@tonic-gate if ((ifn->if_flags & (IFF_LOOPBACK | 6110Sstevel@tonic-gate IFF_FAILED | IFF_DEPRECATED)) == 0) { 6120Sstevel@tonic-gate bestmatch = ifn; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * If this isn't a PPP interface, we're 6160Sstevel@tonic-gate * done. Otherwise, keep walking through 6170Sstevel@tonic-gate * the list in case we have a non-loopback 6180Sstevel@tonic-gate * iface that ISN'T a PPP further down our 6190Sstevel@tonic-gate * list... 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate if ((ifn->if_flags & IFF_POINTOPOINT) == 0) { 6220Sstevel@tonic-gate #ifdef DEBUG 6230Sstevel@tonic-gate (void) printf("found !loopback && !non-PPP interface: %s\n", 6240Sstevel@tonic-gate inet_ntoa(ifn->if_address)); 6250Sstevel@tonic-gate #endif 6260Sstevel@tonic-gate break; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate if (bestmatch != NULL) 6330Sstevel@tonic-gate return (bestmatch->if_address.s_addr); 6340Sstevel@tonic-gate else 6350Sstevel@tonic-gate return (0); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate static int 6390Sstevel@tonic-gate is_myself(struct sockaddr_in6 *sa6) 6400Sstevel@tonic-gate { 6410Sstevel@tonic-gate struct sioc_addrreq areq; 6420Sstevel@tonic-gate int s; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if ((s = open("/dev/udp6", O_RDONLY)) < 0) { 6450Sstevel@tonic-gate syslog(LOG_ERR, "is_myself: can't open /dev/udp6: %m"); 6460Sstevel@tonic-gate return (0); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 649*132Srobinson (void) memcpy(&areq.sa_addr, sa6, sizeof (struct sockaddr_storage)); 6500Sstevel@tonic-gate areq.sa_res = -1; 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) { 6530Sstevel@tonic-gate syslog(LOG_ERR, "is_myself:SIOCTMYADDR failed: %m"); 654*132Srobinson (void) close(s); 6550Sstevel@tonic-gate return (0); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 658*132Srobinson (void) close(s); 6590Sstevel@tonic-gate return (areq.sa_res); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate /* 6630Sstevel@tonic-gate * For a given destination address, determine a source address to use. 6640Sstevel@tonic-gate * Returns wildcard address if it cannot determine the source address. 6650Sstevel@tonic-gate * copied from ping.c. 6660Sstevel@tonic-gate */ 6670Sstevel@tonic-gate union any_in_addr { 6680Sstevel@tonic-gate struct in6_addr addr6; 6690Sstevel@tonic-gate struct in_addr addr; 6700Sstevel@tonic-gate }; 671*132Srobinson 6720Sstevel@tonic-gate static bool_t 6730Sstevel@tonic-gate select_server_addr(union any_in_addr *dst_addr, int family, 6740Sstevel@tonic-gate union any_in_addr *src_addr) 6750Sstevel@tonic-gate { 6760Sstevel@tonic-gate struct sockaddr *sock; 6770Sstevel@tonic-gate struct sockaddr_in *sin; 6780Sstevel@tonic-gate struct sockaddr_in6 *sin6; 6790Sstevel@tonic-gate int tmp_fd; 680*132Srobinson socklen_t sock_len; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate sock = calloc(1, sizeof (struct sockaddr_in6)); 6830Sstevel@tonic-gate if (sock == NULL) { 6840Sstevel@tonic-gate return (FALSE); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate if (family == AF_INET) { 688*132Srobinson /* LINTED pointer cast */ 6890Sstevel@tonic-gate sin = (struct sockaddr_in *)sock; 6900Sstevel@tonic-gate sin->sin_family = AF_INET; 6910Sstevel@tonic-gate sin->sin_port = 111; 6920Sstevel@tonic-gate sin->sin_addr = dst_addr->addr; 6930Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in); 6940Sstevel@tonic-gate } else { 695*132Srobinson /* LINTED pointer cast */ 6960Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)sock; 6970Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 6980Sstevel@tonic-gate sin6->sin6_port = 111; 6990Sstevel@tonic-gate sin6->sin6_addr = dst_addr->addr6; 7000Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in6); 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate /* open a UDP socket */ 7040Sstevel@tonic-gate if ((tmp_fd = _so_socket(family, SOCK_DGRAM, 0, 7050Sstevel@tonic-gate NULL, SOV_SOCKBSD)) < 0) { 7060Sstevel@tonic-gate syslog(LOG_ERR, "selsect_server_addr:connect failed\n"); 7070Sstevel@tonic-gate return (FALSE); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /* connect it */ 7110Sstevel@tonic-gate if (_so_connect(tmp_fd, sock, sock_len, SOV_SOCKBSD) < 0) { 7120Sstevel@tonic-gate /* 7130Sstevel@tonic-gate * If there's no route to the destination, this connect() call 7140Sstevel@tonic-gate * fails. We just return all-zero (wildcard) as the source 7150Sstevel@tonic-gate * address, so that user can get to see "no route to dest" 7160Sstevel@tonic-gate * message, as it'll try to send the probe packet out and will 7170Sstevel@tonic-gate * receive ICMP unreachable. 7180Sstevel@tonic-gate */ 7190Sstevel@tonic-gate if (family == AF_INET) 7200Sstevel@tonic-gate src_addr->addr.s_addr = INADDR_ANY; 7210Sstevel@tonic-gate else 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * Since in6addr_any is not in the scope 7240Sstevel@tonic-gate * use the following hack 7250Sstevel@tonic-gate */ 726*132Srobinson (void) memset(src_addr->addr6.s6_addr, 7270Sstevel@tonic-gate 0, sizeof (struct in6_addr)); 7280Sstevel@tonic-gate (void) close(tmp_fd); 7290Sstevel@tonic-gate free(sock); 7300Sstevel@tonic-gate return (FALSE); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate /* get the local sock info */ 7340Sstevel@tonic-gate if (_so_getsockname(tmp_fd, sock, &sock_len, SOV_DEFAULT) < 0) { 7350Sstevel@tonic-gate syslog(LOG_ERR, "selsect_server_addr:getsockname failed\n"); 7360Sstevel@tonic-gate (void) close(tmp_fd); 7370Sstevel@tonic-gate free(sock); 7380Sstevel@tonic-gate return (FALSE); 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate if (family == AF_INET) { 742*132Srobinson /* LINTED pointer cast */ 7430Sstevel@tonic-gate sin = (struct sockaddr_in *)sock; 7440Sstevel@tonic-gate src_addr->addr = sin->sin_addr; 7450Sstevel@tonic-gate } else { 746*132Srobinson /* LINTED pointer cast */ 7470Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)sock; 7480Sstevel@tonic-gate src_addr->addr6 = sin6->sin6_addr; 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate (void) close(tmp_fd); 7520Sstevel@tonic-gate free(sock); 7530Sstevel@tonic-gate return (TRUE); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 7570Sstevel@tonic-gate * This internal routine will merge one of those "universal" addresses 7580Sstevel@tonic-gate * to the one which will make sense to the remote caller. 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate static char * 761*132Srobinson inet_netdir_mergeaddr(struct netconfig *tp, char *ruaddr, char *uaddr) 7620Sstevel@tonic-gate { 7630Sstevel@tonic-gate char tmp[SYS_NMLN], *cp; 7640Sstevel@tonic-gate int j; 7650Sstevel@tonic-gate struct in_addr clientaddr, bestmatch; 7660Sstevel@tonic-gate time_t curtime; 7670Sstevel@tonic-gate int af; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate if (!uaddr || !ruaddr || !tp) { 7700Sstevel@tonic-gate _nderror = ND_BADARG; 7710Sstevel@tonic-gate return (NULL); 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate (void) bzero(tmp, SYS_NMLN); 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate if (strcmp(tp->nc_protofmly, NC_INET) == 0) 7760Sstevel@tonic-gate af = AF_INET; 7770Sstevel@tonic-gate else 7780Sstevel@tonic-gate af = AF_INET6; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate if (af == AF_INET) { 7810Sstevel@tonic-gate if (strncmp(ruaddr, "0.0.0.0.", strlen("0.0.0.0.")) == 0) 7820Sstevel@tonic-gate /* thats me: return the way it is */ 7830Sstevel@tonic-gate return (strdup(uaddr)); 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate /* 7860Sstevel@tonic-gate * Convert remote uaddr into an in_addr so that we can compare 7870Sstevel@tonic-gate * to it. Shave off last two dotted-decimal values. 7880Sstevel@tonic-gate */ 7890Sstevel@tonic-gate for (cp = ruaddr, j = 0; j < 4; j++, cp++) 7900Sstevel@tonic-gate if ((cp = strchr(cp, '.')) == NULL) 7910Sstevel@tonic-gate break; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate if (cp != NULL) 7940Sstevel@tonic-gate *--cp = '\0'; /* null out the dot after the IP addr */ 7950Sstevel@tonic-gate else { 7960Sstevel@tonic-gate _nderror = ND_NOHOST; 7970Sstevel@tonic-gate return (NULL); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate clientaddr.s_addr = inet_addr(ruaddr); 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate #ifdef DEBUG 8030Sstevel@tonic-gate (void) printf("client's address is %s and %s\n", 8040Sstevel@tonic-gate ruaddr, inet_ntoa(clientaddr)); 8050Sstevel@tonic-gate #endif 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* We know cp is not NULL due to the check above */ 8080Sstevel@tonic-gate *cp = '.'; /* Put the dot back in the IP addr */ 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate (void) time(&curtime); 8110Sstevel@tonic-gate if ((curtime - last_updated) >= if_cache_refresh_time) { 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * Cache needs to be refreshed. 8140Sstevel@tonic-gate */ 8150Sstevel@tonic-gate if (!update_if_cache()) 8160Sstevel@tonic-gate return (NULL); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate /* 8200Sstevel@tonic-gate * Find the best match now. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate (void) rw_rdlock(&iflock); 8230Sstevel@tonic-gate bestmatch.s_addr = get_best_match(clientaddr); 8240Sstevel@tonic-gate (void) rw_unlock(&iflock); 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate if (bestmatch.s_addr) 8270Sstevel@tonic-gate _nderror = ND_OK; 8280Sstevel@tonic-gate else { 8290Sstevel@tonic-gate _nderror = ND_NOHOST; 8300Sstevel@tonic-gate return (NULL); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* prepare the reply */ 8340Sstevel@tonic-gate (void) memset(tmp, '\0', sizeof (tmp)); 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate /* reply consists of the IP addr of the closest interface */ 8370Sstevel@tonic-gate (void) strcpy(tmp, inet_ntoa(bestmatch)); 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate /* 8400Sstevel@tonic-gate * ... and the port number part (last two dotted-decimal values) 8410Sstevel@tonic-gate * of uaddr 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate for (cp = uaddr, j = 0; j < 4; j++, cp++) 8440Sstevel@tonic-gate cp = strchr(cp, '.'); 8450Sstevel@tonic-gate (void) strcat(tmp, --cp); 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate } else { 8480Sstevel@tonic-gate /* IPv6 */ 8490Sstevel@tonic-gate char *dot; 8500Sstevel@tonic-gate char *truaddr; 8510Sstevel@tonic-gate struct sockaddr_in6 sa; 8520Sstevel@tonic-gate struct sockaddr_in6 server_addr; 8530Sstevel@tonic-gate union any_in_addr in_addr, out_addr; 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate if (strncmp(ruaddr, "::", strlen("::")) == 0) 8560Sstevel@tonic-gate if (*(ruaddr + strlen("::")) == '\0') 8570Sstevel@tonic-gate /* thats me: return the way it is */ 8580Sstevel@tonic-gate return (strdup(uaddr)); 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate bzero(&sa, sizeof (sa)); 8610Sstevel@tonic-gate bzero(&server_addr, sizeof (server_addr)); 8620Sstevel@tonic-gate truaddr = &tmp[0]; 863*132Srobinson (void) strcpy(truaddr, ruaddr); 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* 8660Sstevel@tonic-gate * now extract the server ip address from 8670Sstevel@tonic-gate * the address supplied by client. It can be 8680Sstevel@tonic-gate * client's own IP address. 8690Sstevel@tonic-gate */ 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate if ((dot = strrchr(truaddr, '.')) != 0) { 8720Sstevel@tonic-gate *dot = '\0'; 8730Sstevel@tonic-gate if ((dot = strrchr(truaddr, '.')) != 0) 8740Sstevel@tonic-gate *dot = '\0'; 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate if (dot == 0) { 8780Sstevel@tonic-gate _nderror = ND_NOHOST; 8790Sstevel@tonic-gate return (NULL); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate if (inet_pton(af, truaddr, sa.sin6_addr.s6_addr) 8830Sstevel@tonic-gate != 1) { 8840Sstevel@tonic-gate _nderror = ND_NOHOST; 8850Sstevel@tonic-gate return (NULL); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate in_addr.addr6 = sa.sin6_addr; 8890Sstevel@tonic-gate sa.sin6_family = AF_INET6; 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* is it my IP address */ 8920Sstevel@tonic-gate if (!is_myself(&sa)) { 8930Sstevel@tonic-gate /* have the kernel select one for me */ 8940Sstevel@tonic-gate if (select_server_addr(&in_addr, af, &out_addr) == 8950Sstevel@tonic-gate FALSE) 8960Sstevel@tonic-gate return (NULL); 8970Sstevel@tonic-gate server_addr.sin6_addr = out_addr.addr6; 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate else 900*132Srobinson (void) memcpy(&server_addr, &sa, 901*132Srobinson sizeof (struct sockaddr_in6)); 9020Sstevel@tonic-gate #ifdef DEBUG 9030Sstevel@tonic-gate printf("%s\n", inet_ntop(af, out_addr.addr6.s6_addr, 9040Sstevel@tonic-gate tmp, sizeof (tmp))); 9050Sstevel@tonic-gate #endif 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate if (inet_ntop(af, server_addr.sin6_addr.s6_addr, 9080Sstevel@tonic-gate tmp, sizeof (tmp)) == NULL) { 9090Sstevel@tonic-gate _nderror = ND_NOHOST; 9100Sstevel@tonic-gate return (NULL); 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* now extract the port info */ 9140Sstevel@tonic-gate if ((dot = strrchr(uaddr, '.')) != 0) { 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate char *p; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate p = --dot; 9190Sstevel@tonic-gate while (*p-- != '.'); 9200Sstevel@tonic-gate p++; 921*132Srobinson (void) strcat(tmp + strlen(tmp), p); 9220Sstevel@tonic-gate _nderror = ND_OK; 9230Sstevel@tonic-gate } else { 9240Sstevel@tonic-gate _nderror = ND_NOHOST; 9250Sstevel@tonic-gate return (NULL); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate return (strdup(tmp)); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate static int 933*132Srobinson bindresvport(struct netconfig *nconf, int fd, struct netbuf *addr) 9340Sstevel@tonic-gate { 9350Sstevel@tonic-gate int res; 9360Sstevel@tonic-gate struct sockaddr_in myaddr; 9370Sstevel@tonic-gate struct sockaddr_in6 myaddr6; 9380Sstevel@tonic-gate struct sockaddr_in *sin; 9390Sstevel@tonic-gate struct sockaddr_in6 *sin6; 9400Sstevel@tonic-gate int i; 9410Sstevel@tonic-gate struct t_bind tbindstr, *tres; 9420Sstevel@tonic-gate struct t_info tinfo; 9430Sstevel@tonic-gate struct t_optmgmt req, resp; 9440Sstevel@tonic-gate struct opthdr *opt; 9450Sstevel@tonic-gate int reqbuf[64/sizeof (int)]; 9460Sstevel@tonic-gate int *optval; 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate union { 9490Sstevel@tonic-gate struct sockaddr_in *sin; 9500Sstevel@tonic-gate struct sockaddr_in6 *sin6; 9510Sstevel@tonic-gate char *buf; 9520Sstevel@tonic-gate } u; 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate _nderror = ND_SYSTEM; 9550Sstevel@tonic-gate if (geteuid()) { 9560Sstevel@tonic-gate errno = EACCES; 9570Sstevel@tonic-gate return (-1); 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate if ((i = t_getstate(fd)) != T_UNBND) { 9600Sstevel@tonic-gate if (t_errno == TBADF) 9610Sstevel@tonic-gate errno = EBADF; 9620Sstevel@tonic-gate if (i != -1) 9630Sstevel@tonic-gate errno = EISCONN; 9640Sstevel@tonic-gate return (-1); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 9680Sstevel@tonic-gate if (addr == NULL) { 9690Sstevel@tonic-gate sin = &myaddr; 970*132Srobinson (void) memset(sin, 0, sizeof (*sin)); 9710Sstevel@tonic-gate sin->sin_family = AF_INET; 9720Sstevel@tonic-gate u.buf = (char *)sin; 9730Sstevel@tonic-gate } else 9740Sstevel@tonic-gate u.buf = (char *)addr->buf; 9750Sstevel@tonic-gate } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 9760Sstevel@tonic-gate if (addr == NULL) { 9770Sstevel@tonic-gate sin6 = &myaddr6; 978*132Srobinson (void) memset(sin6, 0, sizeof (*sin6)); 9790Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 9800Sstevel@tonic-gate u.buf = (char *)sin6; 9810Sstevel@tonic-gate } else 9820Sstevel@tonic-gate u.buf = addr->buf; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate } else { 9850Sstevel@tonic-gate errno = EPFNOSUPPORT; 9860Sstevel@tonic-gate return (-1); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* Transform sockaddr_in to netbuf */ 9900Sstevel@tonic-gate if (t_getinfo(fd, &tinfo) == -1) 9910Sstevel@tonic-gate return (-1); 992*132Srobinson /* LINTED pointer cast */ 9930Sstevel@tonic-gate tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 9940Sstevel@tonic-gate if (tres == NULL) { 9950Sstevel@tonic-gate _nderror = ND_NOMEM; 9960Sstevel@tonic-gate return (-1); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate tbindstr.qlen = 0; /* Always 0; user should change if he wants to */ 10000Sstevel@tonic-gate tbindstr.addr.buf = (char *)u.buf; 10010Sstevel@tonic-gate tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr); 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate /* 10040Sstevel@tonic-gate * Use *_ANONPRIVBIND to ask the kernel to pick a port in the 10050Sstevel@tonic-gate * priviledged range for us. 10060Sstevel@tonic-gate */ 10070Sstevel@tonic-gate opt = (struct opthdr *)reqbuf; 10080Sstevel@tonic-gate if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 10090Sstevel@tonic-gate opt->level = IPPROTO_TCP; 10100Sstevel@tonic-gate opt->name = TCP_ANONPRIVBIND; 10110Sstevel@tonic-gate } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 10120Sstevel@tonic-gate opt->level = IPPROTO_UDP; 10130Sstevel@tonic-gate opt->name = UDP_ANONPRIVBIND; 10140Sstevel@tonic-gate } else { 10150Sstevel@tonic-gate errno = EPROTONOSUPPORT; 10160Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND); 10170Sstevel@tonic-gate return (-1); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate opt->len = sizeof (int); 10210Sstevel@tonic-gate req.flags = T_NEGOTIATE; 10220Sstevel@tonic-gate req.opt.len = sizeof (struct opthdr) + opt->len; 10230Sstevel@tonic-gate req.opt.buf = (char *)opt; 1024*132Srobinson /* LINTED pointer cast */ 10250Sstevel@tonic-gate optval = (int *)((char *)reqbuf + sizeof (struct opthdr)); 10260Sstevel@tonic-gate *optval = 1; 10270Sstevel@tonic-gate resp.flags = 0; 10280Sstevel@tonic-gate resp.opt.buf = (char *)reqbuf; 10290Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 10300Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 10310Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND); 10320Sstevel@tonic-gate return (-1); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (u.sin->sin_family == AF_INET) 10360Sstevel@tonic-gate u.sin->sin_port = htons(0); 10370Sstevel@tonic-gate else 10380Sstevel@tonic-gate u.sin6->sin6_port = htons(0); 10390Sstevel@tonic-gate res = t_bind(fd, &tbindstr, tres); 10400Sstevel@tonic-gate if (res != 0) { 10410Sstevel@tonic-gate if (t_errno == TNOADDR) { 10420Sstevel@tonic-gate _nderror = ND_FAILCTRL; 10430Sstevel@tonic-gate res = 1; 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate } else { 10460Sstevel@tonic-gate _nderror = ND_OK; 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * Always turn off the option when we are done. Note that by doing 10510Sstevel@tonic-gate * this, if the caller has set this option before calling 10520Sstevel@tonic-gate * bindresvport(), it will be unset. Better be safe... 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate *optval = 0; 10550Sstevel@tonic-gate resp.flags = 0; 10560Sstevel@tonic-gate resp.opt.buf = (char *)reqbuf; 10570Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 10580Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 10590Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND); 10600Sstevel@tonic-gate if (res == 0) 10610Sstevel@tonic-gate (void) t_unbind(fd); 10620Sstevel@tonic-gate _nderror = ND_FAILCTRL; 10630Sstevel@tonic-gate return (-1); 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND); 10670Sstevel@tonic-gate return (res); 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate static int 1071*132Srobinson checkresvport(struct netbuf *addr) 10720Sstevel@tonic-gate { 10730Sstevel@tonic-gate struct sockaddr_in *sin; 10740Sstevel@tonic-gate unsigned short port; 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate if (addr == NULL) { 10770Sstevel@tonic-gate _nderror = ND_FAILCTRL; 10780Sstevel@tonic-gate return (-1); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate /* 10810Sstevel@tonic-gate * Still works for IPv6 since the first two memebers of 10820Sstevel@tonic-gate * both address structure point to family and port # respectively 10830Sstevel@tonic-gate */ 1084*132Srobinson /* LINTED pointer cast */ 10850Sstevel@tonic-gate sin = (struct sockaddr_in *)(addr->buf); 10860Sstevel@tonic-gate port = ntohs(sin->sin_port); 10870Sstevel@tonic-gate if (port < IPPORT_RESERVED) 10880Sstevel@tonic-gate return (0); 10890Sstevel@tonic-gate return (1); 10900Sstevel@tonic-gate } 1091