1*6e91bba0SGirish Moodalbail /* 2*6e91bba0SGirish Moodalbail * CDDL HEADER START 3*6e91bba0SGirish Moodalbail * 4*6e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the 5*6e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License"). 6*6e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License. 7*6e91bba0SGirish Moodalbail * 8*6e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing. 10*6e91bba0SGirish Moodalbail * See the License for the specific language governing permissions 11*6e91bba0SGirish Moodalbail * and limitations under the License. 12*6e91bba0SGirish Moodalbail * 13*6e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each 14*6e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the 16*6e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying 17*6e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner] 18*6e91bba0SGirish Moodalbail * 19*6e91bba0SGirish Moodalbail * CDDL HEADER END 20*6e91bba0SGirish Moodalbail */ 21*6e91bba0SGirish Moodalbail 22*6e91bba0SGirish Moodalbail /* 23*6e91bba0SGirish Moodalbail * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24*6e91bba0SGirish Moodalbail * Use is subject to license terms. 25*6e91bba0SGirish Moodalbail */ 26*6e91bba0SGirish Moodalbail 27*6e91bba0SGirish Moodalbail #include <netdb.h> 28*6e91bba0SGirish Moodalbail #include <nss_dbdefs.h> 29*6e91bba0SGirish Moodalbail #include <netinet/in.h> 30*6e91bba0SGirish Moodalbail #include <sys/socket.h> 31*6e91bba0SGirish Moodalbail #include <string.h> 32*6e91bba0SGirish Moodalbail #include <stdio.h> 33*6e91bba0SGirish Moodalbail #include <sys/sockio.h> 34*6e91bba0SGirish Moodalbail #include <sys/types.h> 35*6e91bba0SGirish Moodalbail #include <stdlib.h> 36*6e91bba0SGirish Moodalbail #include <net/if.h> 37*6e91bba0SGirish Moodalbail #include <ifaddrs.h> 38*6e91bba0SGirish Moodalbail #include <libsocket_priv.h> 39*6e91bba0SGirish Moodalbail 40*6e91bba0SGirish Moodalbail /* 41*6e91bba0SGirish Moodalbail * Create a linked list of `struct ifaddrs' structures, one for each 42*6e91bba0SGirish Moodalbail * address that is UP. If successful, store the list in *ifap and 43*6e91bba0SGirish Moodalbail * return 0. On errors, return -1 and set `errno'. 44*6e91bba0SGirish Moodalbail * 45*6e91bba0SGirish Moodalbail * The storage returned in *ifap is allocated dynamically and can 46*6e91bba0SGirish Moodalbail * only be properly freed by passing it to `freeifaddrs'. 47*6e91bba0SGirish Moodalbail */ 48*6e91bba0SGirish Moodalbail int 49*6e91bba0SGirish Moodalbail getifaddrs(struct ifaddrs **ifap) 50*6e91bba0SGirish Moodalbail { 51*6e91bba0SGirish Moodalbail int err; 52*6e91bba0SGirish Moodalbail char *cp; 53*6e91bba0SGirish Moodalbail struct ifaddrs *curr; 54*6e91bba0SGirish Moodalbail 55*6e91bba0SGirish Moodalbail if (ifap == NULL) { 56*6e91bba0SGirish Moodalbail errno = EINVAL; 57*6e91bba0SGirish Moodalbail return (-1); 58*6e91bba0SGirish Moodalbail } 59*6e91bba0SGirish Moodalbail *ifap = NULL; 60*6e91bba0SGirish Moodalbail err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED); 61*6e91bba0SGirish Moodalbail if (err == 0) { 62*6e91bba0SGirish Moodalbail for (curr = *ifap; curr != NULL; curr = curr->ifa_next) { 63*6e91bba0SGirish Moodalbail if ((cp = strchr(curr->ifa_name, ':')) != NULL) 64*6e91bba0SGirish Moodalbail *cp = '\0'; 65*6e91bba0SGirish Moodalbail } 66*6e91bba0SGirish Moodalbail } 67*6e91bba0SGirish Moodalbail return (err); 68*6e91bba0SGirish Moodalbail } 69*6e91bba0SGirish Moodalbail 70*6e91bba0SGirish Moodalbail void 71*6e91bba0SGirish Moodalbail freeifaddrs(struct ifaddrs *ifa) 72*6e91bba0SGirish Moodalbail { 73*6e91bba0SGirish Moodalbail struct ifaddrs *curr; 74*6e91bba0SGirish Moodalbail 75*6e91bba0SGirish Moodalbail while (ifa != NULL) { 76*6e91bba0SGirish Moodalbail curr = ifa; 77*6e91bba0SGirish Moodalbail ifa = ifa->ifa_next; 78*6e91bba0SGirish Moodalbail free(curr->ifa_name); 79*6e91bba0SGirish Moodalbail free(curr->ifa_addr); 80*6e91bba0SGirish Moodalbail free(curr->ifa_netmask); 81*6e91bba0SGirish Moodalbail free(curr->ifa_dstaddr); 82*6e91bba0SGirish Moodalbail free(curr); 83*6e91bba0SGirish Moodalbail } 84*6e91bba0SGirish Moodalbail } 85*6e91bba0SGirish Moodalbail 86*6e91bba0SGirish Moodalbail /* 87*6e91bba0SGirish Moodalbail * Returns all addresses configured on the system. If flags contain 88*6e91bba0SGirish Moodalbail * LIFC_ENABLED, only the addresses that are UP are returned. 89*6e91bba0SGirish Moodalbail * Address list that is returned by this function must be freed 90*6e91bba0SGirish Moodalbail * using freeifaddrs(). 91*6e91bba0SGirish Moodalbail */ 92*6e91bba0SGirish Moodalbail int 93*6e91bba0SGirish Moodalbail getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags) 94*6e91bba0SGirish Moodalbail { 95*6e91bba0SGirish Moodalbail struct lifreq *buf = NULL; 96*6e91bba0SGirish Moodalbail struct lifreq *lifrp; 97*6e91bba0SGirish Moodalbail struct lifreq lifrl; 98*6e91bba0SGirish Moodalbail int ret; 99*6e91bba0SGirish Moodalbail int s, n, numifs; 100*6e91bba0SGirish Moodalbail struct ifaddrs *curr, *prev; 101*6e91bba0SGirish Moodalbail sa_family_t lifr_af; 102*6e91bba0SGirish Moodalbail int sock4; 103*6e91bba0SGirish Moodalbail int sock6; 104*6e91bba0SGirish Moodalbail int err; 105*6e91bba0SGirish Moodalbail 106*6e91bba0SGirish Moodalbail if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 107*6e91bba0SGirish Moodalbail return (-1); 108*6e91bba0SGirish Moodalbail if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 109*6e91bba0SGirish Moodalbail err = errno; 110*6e91bba0SGirish Moodalbail close(sock4); 111*6e91bba0SGirish Moodalbail errno = err; 112*6e91bba0SGirish Moodalbail return (-1); 113*6e91bba0SGirish Moodalbail } 114*6e91bba0SGirish Moodalbail 115*6e91bba0SGirish Moodalbail retry: 116*6e91bba0SGirish Moodalbail /* Get all interfaces from SIOCGLIFCONF */ 117*6e91bba0SGirish Moodalbail ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED)); 118*6e91bba0SGirish Moodalbail if (ret != 0) 119*6e91bba0SGirish Moodalbail goto fail; 120*6e91bba0SGirish Moodalbail 121*6e91bba0SGirish Moodalbail /* 122*6e91bba0SGirish Moodalbail * Loop through the interfaces obtained from SIOCGLIFCOMF 123*6e91bba0SGirish Moodalbail * and retrieve the addresses, netmask and flags. 124*6e91bba0SGirish Moodalbail */ 125*6e91bba0SGirish Moodalbail prev = NULL; 126*6e91bba0SGirish Moodalbail lifrp = buf; 127*6e91bba0SGirish Moodalbail *ifap = NULL; 128*6e91bba0SGirish Moodalbail for (n = 0; n < numifs; n++, lifrp++) { 129*6e91bba0SGirish Moodalbail 130*6e91bba0SGirish Moodalbail /* Prepare for the ioctl call */ 131*6e91bba0SGirish Moodalbail (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 132*6e91bba0SGirish Moodalbail sizeof (lifrl.lifr_name)); 133*6e91bba0SGirish Moodalbail lifr_af = lifrp->lifr_addr.ss_family; 134*6e91bba0SGirish Moodalbail if (af != AF_UNSPEC && lifr_af != af) 135*6e91bba0SGirish Moodalbail continue; 136*6e91bba0SGirish Moodalbail 137*6e91bba0SGirish Moodalbail s = (lifr_af == AF_INET ? sock4 : sock6); 138*6e91bba0SGirish Moodalbail 139*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) 140*6e91bba0SGirish Moodalbail goto fail; 141*6e91bba0SGirish Moodalbail if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP)) 142*6e91bba0SGirish Moodalbail continue; 143*6e91bba0SGirish Moodalbail 144*6e91bba0SGirish Moodalbail /* 145*6e91bba0SGirish Moodalbail * Allocate the current list node. Each node contains data 146*6e91bba0SGirish Moodalbail * for one ifaddrs structure. 147*6e91bba0SGirish Moodalbail */ 148*6e91bba0SGirish Moodalbail curr = calloc(1, sizeof (struct ifaddrs)); 149*6e91bba0SGirish Moodalbail if (curr == NULL) 150*6e91bba0SGirish Moodalbail goto fail; 151*6e91bba0SGirish Moodalbail 152*6e91bba0SGirish Moodalbail if (prev != NULL) { 153*6e91bba0SGirish Moodalbail prev->ifa_next = curr; 154*6e91bba0SGirish Moodalbail } else { 155*6e91bba0SGirish Moodalbail /* First node in the linked list */ 156*6e91bba0SGirish Moodalbail *ifap = curr; 157*6e91bba0SGirish Moodalbail } 158*6e91bba0SGirish Moodalbail prev = curr; 159*6e91bba0SGirish Moodalbail 160*6e91bba0SGirish Moodalbail curr->ifa_flags = lifrl.lifr_flags; 161*6e91bba0SGirish Moodalbail if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL) 162*6e91bba0SGirish Moodalbail goto fail; 163*6e91bba0SGirish Moodalbail 164*6e91bba0SGirish Moodalbail curr->ifa_addr = malloc(sizeof (struct sockaddr_storage)); 165*6e91bba0SGirish Moodalbail if (curr->ifa_addr == NULL) 166*6e91bba0SGirish Moodalbail goto fail; 167*6e91bba0SGirish Moodalbail *curr->ifa_addr = lifrp->lifr_addr; 168*6e91bba0SGirish Moodalbail 169*6e91bba0SGirish Moodalbail /* Get the netmask */ 170*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0) 171*6e91bba0SGirish Moodalbail goto fail; 172*6e91bba0SGirish Moodalbail curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage)); 173*6e91bba0SGirish Moodalbail if (curr->ifa_netmask == NULL) 174*6e91bba0SGirish Moodalbail goto fail; 175*6e91bba0SGirish Moodalbail *curr->ifa_netmask = lifrl.lifr_addr; 176*6e91bba0SGirish Moodalbail 177*6e91bba0SGirish Moodalbail /* Get the destination for a pt-pt interface */ 178*6e91bba0SGirish Moodalbail if (curr->ifa_flags & IFF_POINTOPOINT) { 179*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0) 180*6e91bba0SGirish Moodalbail goto fail; 181*6e91bba0SGirish Moodalbail curr->ifa_dstaddr = malloc( 182*6e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 183*6e91bba0SGirish Moodalbail if (curr->ifa_dstaddr == NULL) 184*6e91bba0SGirish Moodalbail goto fail; 185*6e91bba0SGirish Moodalbail *curr->ifa_dstaddr = lifrl.lifr_addr; 186*6e91bba0SGirish Moodalbail } else if (curr->ifa_flags & IFF_BROADCAST) { 187*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0) 188*6e91bba0SGirish Moodalbail goto fail; 189*6e91bba0SGirish Moodalbail curr->ifa_broadaddr = malloc( 190*6e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 191*6e91bba0SGirish Moodalbail if (curr->ifa_broadaddr == NULL) 192*6e91bba0SGirish Moodalbail goto fail; 193*6e91bba0SGirish Moodalbail *curr->ifa_broadaddr = lifrl.lifr_addr; 194*6e91bba0SGirish Moodalbail } 195*6e91bba0SGirish Moodalbail 196*6e91bba0SGirish Moodalbail } 197*6e91bba0SGirish Moodalbail free(buf); 198*6e91bba0SGirish Moodalbail close(sock4); 199*6e91bba0SGirish Moodalbail close(sock6); 200*6e91bba0SGirish Moodalbail return (0); 201*6e91bba0SGirish Moodalbail fail: 202*6e91bba0SGirish Moodalbail err = errno; 203*6e91bba0SGirish Moodalbail free(buf); 204*6e91bba0SGirish Moodalbail freeifaddrs(*ifap); 205*6e91bba0SGirish Moodalbail *ifap = NULL; 206*6e91bba0SGirish Moodalbail if (err == ENXIO) 207*6e91bba0SGirish Moodalbail goto retry; 208*6e91bba0SGirish Moodalbail close(sock4); 209*6e91bba0SGirish Moodalbail close(sock6); 210*6e91bba0SGirish Moodalbail errno = err; 211*6e91bba0SGirish Moodalbail return (-1); 212*6e91bba0SGirish Moodalbail } 213*6e91bba0SGirish Moodalbail 214*6e91bba0SGirish Moodalbail /* 215*6e91bba0SGirish Moodalbail * Do a SIOCGLIFCONF and store all the interfaces in `buf'. 216*6e91bba0SGirish Moodalbail */ 217*6e91bba0SGirish Moodalbail int 218*6e91bba0SGirish Moodalbail getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs, 219*6e91bba0SGirish Moodalbail int64_t lifc_flags) 220*6e91bba0SGirish Moodalbail { 221*6e91bba0SGirish Moodalbail struct lifnum lifn; 222*6e91bba0SGirish Moodalbail struct lifconf lifc; 223*6e91bba0SGirish Moodalbail size_t bufsize; 224*6e91bba0SGirish Moodalbail char *tmp; 225*6e91bba0SGirish Moodalbail caddr_t *buf = (caddr_t *)lifr; 226*6e91bba0SGirish Moodalbail 227*6e91bba0SGirish Moodalbail lifn.lifn_family = af; 228*6e91bba0SGirish Moodalbail lifn.lifn_flags = lifc_flags; 229*6e91bba0SGirish Moodalbail 230*6e91bba0SGirish Moodalbail *buf = NULL; 231*6e91bba0SGirish Moodalbail retry: 232*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFNUM, &lifn) < 0) 233*6e91bba0SGirish Moodalbail goto fail; 234*6e91bba0SGirish Moodalbail 235*6e91bba0SGirish Moodalbail /* 236*6e91bba0SGirish Moodalbail * When calculating the buffer size needed, add a small number 237*6e91bba0SGirish Moodalbail * of interfaces to those we counted. We do this to capture 238*6e91bba0SGirish Moodalbail * the interface status of potential interfaces which may have 239*6e91bba0SGirish Moodalbail * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. 240*6e91bba0SGirish Moodalbail */ 241*6e91bba0SGirish Moodalbail bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq); 242*6e91bba0SGirish Moodalbail 243*6e91bba0SGirish Moodalbail if ((tmp = realloc(*buf, bufsize)) == NULL) 244*6e91bba0SGirish Moodalbail goto fail; 245*6e91bba0SGirish Moodalbail 246*6e91bba0SGirish Moodalbail *buf = tmp; 247*6e91bba0SGirish Moodalbail lifc.lifc_family = af; 248*6e91bba0SGirish Moodalbail lifc.lifc_flags = lifc_flags; 249*6e91bba0SGirish Moodalbail lifc.lifc_len = bufsize; 250*6e91bba0SGirish Moodalbail lifc.lifc_buf = *buf; 251*6e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) 252*6e91bba0SGirish Moodalbail goto fail; 253*6e91bba0SGirish Moodalbail 254*6e91bba0SGirish Moodalbail *numifs = lifc.lifc_len / sizeof (struct lifreq); 255*6e91bba0SGirish Moodalbail if (*numifs >= (lifn.lifn_count + 4)) { 256*6e91bba0SGirish Moodalbail /* 257*6e91bba0SGirish Moodalbail * If every entry was filled, there are probably 258*6e91bba0SGirish Moodalbail * more interfaces than (lifn.lifn_count + 4). 259*6e91bba0SGirish Moodalbail * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to 260*6e91bba0SGirish Moodalbail * get all the interfaces. 261*6e91bba0SGirish Moodalbail */ 262*6e91bba0SGirish Moodalbail goto retry; 263*6e91bba0SGirish Moodalbail } 264*6e91bba0SGirish Moodalbail return (0); 265*6e91bba0SGirish Moodalbail fail: 266*6e91bba0SGirish Moodalbail free(*buf); 267*6e91bba0SGirish Moodalbail *buf = NULL; 268*6e91bba0SGirish Moodalbail return (-1); 269*6e91bba0SGirish Moodalbail } 270