16e91bba0SGirish Moodalbail /* 26e91bba0SGirish Moodalbail * CDDL HEADER START 36e91bba0SGirish Moodalbail * 46e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the 56e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License"). 66e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License. 76e91bba0SGirish Moodalbail * 86e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing. 106e91bba0SGirish Moodalbail * See the License for the specific language governing permissions 116e91bba0SGirish Moodalbail * and limitations under the License. 126e91bba0SGirish Moodalbail * 136e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each 146e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the 166e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying 176e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner] 186e91bba0SGirish Moodalbail * 196e91bba0SGirish Moodalbail * CDDL HEADER END 206e91bba0SGirish Moodalbail */ 216e91bba0SGirish Moodalbail 226e91bba0SGirish Moodalbail /* 2364639aafSDarren Reed * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 246e91bba0SGirish Moodalbail */ 256e91bba0SGirish Moodalbail 266e91bba0SGirish Moodalbail #include <netdb.h> 276e91bba0SGirish Moodalbail #include <nss_dbdefs.h> 286e91bba0SGirish Moodalbail #include <netinet/in.h> 296e91bba0SGirish Moodalbail #include <sys/socket.h> 306e91bba0SGirish Moodalbail #include <string.h> 316e91bba0SGirish Moodalbail #include <stdio.h> 326e91bba0SGirish Moodalbail #include <sys/sockio.h> 336e91bba0SGirish Moodalbail #include <sys/types.h> 346e91bba0SGirish Moodalbail #include <stdlib.h> 356e91bba0SGirish Moodalbail #include <net/if.h> 366e91bba0SGirish Moodalbail #include <ifaddrs.h> 376e91bba0SGirish Moodalbail #include <libsocket_priv.h> 386e91bba0SGirish Moodalbail 396e91bba0SGirish Moodalbail /* 406e91bba0SGirish Moodalbail * Create a linked list of `struct ifaddrs' structures, one for each 416e91bba0SGirish Moodalbail * address that is UP. If successful, store the list in *ifap and 426e91bba0SGirish Moodalbail * return 0. On errors, return -1 and set `errno'. 436e91bba0SGirish Moodalbail * 446e91bba0SGirish Moodalbail * The storage returned in *ifap is allocated dynamically and can 456e91bba0SGirish Moodalbail * only be properly freed by passing it to `freeifaddrs'. 466e91bba0SGirish Moodalbail */ 476e91bba0SGirish Moodalbail int 486e91bba0SGirish Moodalbail getifaddrs(struct ifaddrs **ifap) 496e91bba0SGirish Moodalbail { 506e91bba0SGirish Moodalbail int err; 516e91bba0SGirish Moodalbail char *cp; 526e91bba0SGirish Moodalbail struct ifaddrs *curr; 536e91bba0SGirish Moodalbail 546e91bba0SGirish Moodalbail if (ifap == NULL) { 556e91bba0SGirish Moodalbail errno = EINVAL; 566e91bba0SGirish Moodalbail return (-1); 576e91bba0SGirish Moodalbail } 586e91bba0SGirish Moodalbail *ifap = NULL; 596e91bba0SGirish Moodalbail err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED); 606e91bba0SGirish Moodalbail if (err == 0) { 616e91bba0SGirish Moodalbail for (curr = *ifap; curr != NULL; curr = curr->ifa_next) { 626e91bba0SGirish Moodalbail if ((cp = strchr(curr->ifa_name, ':')) != NULL) 636e91bba0SGirish Moodalbail *cp = '\0'; 646e91bba0SGirish Moodalbail } 656e91bba0SGirish Moodalbail } 666e91bba0SGirish Moodalbail return (err); 676e91bba0SGirish Moodalbail } 686e91bba0SGirish Moodalbail 696e91bba0SGirish Moodalbail void 706e91bba0SGirish Moodalbail freeifaddrs(struct ifaddrs *ifa) 716e91bba0SGirish Moodalbail { 726e91bba0SGirish Moodalbail struct ifaddrs *curr; 736e91bba0SGirish Moodalbail 746e91bba0SGirish Moodalbail while (ifa != NULL) { 756e91bba0SGirish Moodalbail curr = ifa; 766e91bba0SGirish Moodalbail ifa = ifa->ifa_next; 776e91bba0SGirish Moodalbail free(curr->ifa_name); 786e91bba0SGirish Moodalbail free(curr->ifa_addr); 796e91bba0SGirish Moodalbail free(curr->ifa_netmask); 806e91bba0SGirish Moodalbail free(curr->ifa_dstaddr); 816e91bba0SGirish Moodalbail free(curr); 826e91bba0SGirish Moodalbail } 836e91bba0SGirish Moodalbail } 846e91bba0SGirish Moodalbail 856e91bba0SGirish Moodalbail /* 866e91bba0SGirish Moodalbail * Returns all addresses configured on the system. If flags contain 876e91bba0SGirish Moodalbail * LIFC_ENABLED, only the addresses that are UP are returned. 886e91bba0SGirish Moodalbail * Address list that is returned by this function must be freed 896e91bba0SGirish Moodalbail * using freeifaddrs(). 906e91bba0SGirish Moodalbail */ 916e91bba0SGirish Moodalbail int 926e91bba0SGirish Moodalbail getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags) 936e91bba0SGirish Moodalbail { 946e91bba0SGirish Moodalbail struct lifreq *buf = NULL; 956e91bba0SGirish Moodalbail struct lifreq *lifrp; 966e91bba0SGirish Moodalbail struct lifreq lifrl; 976e91bba0SGirish Moodalbail int ret; 986e91bba0SGirish Moodalbail int s, n, numifs; 996e91bba0SGirish Moodalbail struct ifaddrs *curr, *prev; 1006e91bba0SGirish Moodalbail sa_family_t lifr_af; 1016e91bba0SGirish Moodalbail int sock4; 1026e91bba0SGirish Moodalbail int sock6; 1036e91bba0SGirish Moodalbail int err; 1046e91bba0SGirish Moodalbail 1056e91bba0SGirish Moodalbail if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1066e91bba0SGirish Moodalbail return (-1); 1076e91bba0SGirish Moodalbail if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1086e91bba0SGirish Moodalbail err = errno; 1096e91bba0SGirish Moodalbail close(sock4); 1106e91bba0SGirish Moodalbail errno = err; 1116e91bba0SGirish Moodalbail return (-1); 1126e91bba0SGirish Moodalbail } 1136e91bba0SGirish Moodalbail 1146e91bba0SGirish Moodalbail retry: 1156e91bba0SGirish Moodalbail /* Get all interfaces from SIOCGLIFCONF */ 1166e91bba0SGirish Moodalbail ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED)); 1176e91bba0SGirish Moodalbail if (ret != 0) 1186e91bba0SGirish Moodalbail goto fail; 1196e91bba0SGirish Moodalbail 1206e91bba0SGirish Moodalbail /* 1216e91bba0SGirish Moodalbail * Loop through the interfaces obtained from SIOCGLIFCOMF 1226e91bba0SGirish Moodalbail * and retrieve the addresses, netmask and flags. 1236e91bba0SGirish Moodalbail */ 1246e91bba0SGirish Moodalbail prev = NULL; 1256e91bba0SGirish Moodalbail lifrp = buf; 1266e91bba0SGirish Moodalbail *ifap = NULL; 1276e91bba0SGirish Moodalbail for (n = 0; n < numifs; n++, lifrp++) { 1286e91bba0SGirish Moodalbail 1296e91bba0SGirish Moodalbail /* Prepare for the ioctl call */ 1306e91bba0SGirish Moodalbail (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 1316e91bba0SGirish Moodalbail sizeof (lifrl.lifr_name)); 1326e91bba0SGirish Moodalbail lifr_af = lifrp->lifr_addr.ss_family; 1336e91bba0SGirish Moodalbail if (af != AF_UNSPEC && lifr_af != af) 1346e91bba0SGirish Moodalbail continue; 1356e91bba0SGirish Moodalbail 1366e91bba0SGirish Moodalbail s = (lifr_af == AF_INET ? sock4 : sock6); 1376e91bba0SGirish Moodalbail 1386e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) 1396e91bba0SGirish Moodalbail goto fail; 1406e91bba0SGirish Moodalbail if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP)) 1416e91bba0SGirish Moodalbail continue; 1426e91bba0SGirish Moodalbail 1436e91bba0SGirish Moodalbail /* 1446e91bba0SGirish Moodalbail * Allocate the current list node. Each node contains data 1456e91bba0SGirish Moodalbail * for one ifaddrs structure. 1466e91bba0SGirish Moodalbail */ 1476e91bba0SGirish Moodalbail curr = calloc(1, sizeof (struct ifaddrs)); 1486e91bba0SGirish Moodalbail if (curr == NULL) 1496e91bba0SGirish Moodalbail goto fail; 1506e91bba0SGirish Moodalbail 1516e91bba0SGirish Moodalbail if (prev != NULL) { 1526e91bba0SGirish Moodalbail prev->ifa_next = curr; 1536e91bba0SGirish Moodalbail } else { 1546e91bba0SGirish Moodalbail /* First node in the linked list */ 1556e91bba0SGirish Moodalbail *ifap = curr; 1566e91bba0SGirish Moodalbail } 1576e91bba0SGirish Moodalbail prev = curr; 1586e91bba0SGirish Moodalbail 1596e91bba0SGirish Moodalbail curr->ifa_flags = lifrl.lifr_flags; 1606e91bba0SGirish Moodalbail if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL) 1616e91bba0SGirish Moodalbail goto fail; 1626e91bba0SGirish Moodalbail 1636e91bba0SGirish Moodalbail curr->ifa_addr = malloc(sizeof (struct sockaddr_storage)); 1646e91bba0SGirish Moodalbail if (curr->ifa_addr == NULL) 1656e91bba0SGirish Moodalbail goto fail; 16664639aafSDarren Reed (void) memcpy(curr->ifa_addr, &lifrp->lifr_addr, 16764639aafSDarren Reed sizeof (struct sockaddr_storage)); 1686e91bba0SGirish Moodalbail 1696e91bba0SGirish Moodalbail /* Get the netmask */ 1706e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0) 1716e91bba0SGirish Moodalbail goto fail; 1726e91bba0SGirish Moodalbail curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage)); 1736e91bba0SGirish Moodalbail if (curr->ifa_netmask == NULL) 1746e91bba0SGirish Moodalbail goto fail; 17564639aafSDarren Reed (void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr, 17664639aafSDarren Reed sizeof (struct sockaddr_storage)); 1776e91bba0SGirish Moodalbail 1786e91bba0SGirish Moodalbail /* Get the destination for a pt-pt interface */ 1796e91bba0SGirish Moodalbail if (curr->ifa_flags & IFF_POINTOPOINT) { 1806e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0) 1816e91bba0SGirish Moodalbail goto fail; 1826e91bba0SGirish Moodalbail curr->ifa_dstaddr = malloc( 1836e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 1846e91bba0SGirish Moodalbail if (curr->ifa_dstaddr == NULL) 1856e91bba0SGirish Moodalbail goto fail; 186*08ed54f3SVasumathi Sundaram (void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr, 18764639aafSDarren Reed sizeof (struct sockaddr_storage)); 1886e91bba0SGirish Moodalbail } else if (curr->ifa_flags & IFF_BROADCAST) { 1896e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0) 1906e91bba0SGirish Moodalbail goto fail; 1916e91bba0SGirish Moodalbail curr->ifa_broadaddr = malloc( 1926e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 1936e91bba0SGirish Moodalbail if (curr->ifa_broadaddr == NULL) 1946e91bba0SGirish Moodalbail goto fail; 195*08ed54f3SVasumathi Sundaram (void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr, 19664639aafSDarren Reed sizeof (struct sockaddr_storage)); 1976e91bba0SGirish Moodalbail } 1986e91bba0SGirish Moodalbail 1996e91bba0SGirish Moodalbail } 2006e91bba0SGirish Moodalbail free(buf); 2016e91bba0SGirish Moodalbail close(sock4); 2026e91bba0SGirish Moodalbail close(sock6); 2036e91bba0SGirish Moodalbail return (0); 2046e91bba0SGirish Moodalbail fail: 2056e91bba0SGirish Moodalbail err = errno; 2066e91bba0SGirish Moodalbail free(buf); 2076e91bba0SGirish Moodalbail freeifaddrs(*ifap); 2086e91bba0SGirish Moodalbail *ifap = NULL; 2096e91bba0SGirish Moodalbail if (err == ENXIO) 2106e91bba0SGirish Moodalbail goto retry; 2116e91bba0SGirish Moodalbail close(sock4); 2126e91bba0SGirish Moodalbail close(sock6); 2136e91bba0SGirish Moodalbail errno = err; 2146e91bba0SGirish Moodalbail return (-1); 2156e91bba0SGirish Moodalbail } 2166e91bba0SGirish Moodalbail 2176e91bba0SGirish Moodalbail /* 2186e91bba0SGirish Moodalbail * Do a SIOCGLIFCONF and store all the interfaces in `buf'. 2196e91bba0SGirish Moodalbail */ 2206e91bba0SGirish Moodalbail int 2216e91bba0SGirish Moodalbail getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs, 2226e91bba0SGirish Moodalbail int64_t lifc_flags) 2236e91bba0SGirish Moodalbail { 2246e91bba0SGirish Moodalbail struct lifnum lifn; 2256e91bba0SGirish Moodalbail struct lifconf lifc; 2266e91bba0SGirish Moodalbail size_t bufsize; 2276e91bba0SGirish Moodalbail char *tmp; 2286e91bba0SGirish Moodalbail caddr_t *buf = (caddr_t *)lifr; 2296e91bba0SGirish Moodalbail 2306e91bba0SGirish Moodalbail lifn.lifn_family = af; 2316e91bba0SGirish Moodalbail lifn.lifn_flags = lifc_flags; 2326e91bba0SGirish Moodalbail 2336e91bba0SGirish Moodalbail *buf = NULL; 2346e91bba0SGirish Moodalbail retry: 2356e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFNUM, &lifn) < 0) 2366e91bba0SGirish Moodalbail goto fail; 2376e91bba0SGirish Moodalbail 2386e91bba0SGirish Moodalbail /* 2396e91bba0SGirish Moodalbail * When calculating the buffer size needed, add a small number 2406e91bba0SGirish Moodalbail * of interfaces to those we counted. We do this to capture 2416e91bba0SGirish Moodalbail * the interface status of potential interfaces which may have 2426e91bba0SGirish Moodalbail * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. 2436e91bba0SGirish Moodalbail */ 2446e91bba0SGirish Moodalbail bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq); 2456e91bba0SGirish Moodalbail 2466e91bba0SGirish Moodalbail if ((tmp = realloc(*buf, bufsize)) == NULL) 2476e91bba0SGirish Moodalbail goto fail; 2486e91bba0SGirish Moodalbail 2496e91bba0SGirish Moodalbail *buf = tmp; 2506e91bba0SGirish Moodalbail lifc.lifc_family = af; 2516e91bba0SGirish Moodalbail lifc.lifc_flags = lifc_flags; 2526e91bba0SGirish Moodalbail lifc.lifc_len = bufsize; 2536e91bba0SGirish Moodalbail lifc.lifc_buf = *buf; 2546e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) 2556e91bba0SGirish Moodalbail goto fail; 2566e91bba0SGirish Moodalbail 2576e91bba0SGirish Moodalbail *numifs = lifc.lifc_len / sizeof (struct lifreq); 2586e91bba0SGirish Moodalbail if (*numifs >= (lifn.lifn_count + 4)) { 2596e91bba0SGirish Moodalbail /* 2606e91bba0SGirish Moodalbail * If every entry was filled, there are probably 2616e91bba0SGirish Moodalbail * more interfaces than (lifn.lifn_count + 4). 2626e91bba0SGirish Moodalbail * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to 2636e91bba0SGirish Moodalbail * get all the interfaces. 2646e91bba0SGirish Moodalbail */ 2656e91bba0SGirish Moodalbail goto retry; 2666e91bba0SGirish Moodalbail } 2676e91bba0SGirish Moodalbail return (0); 2686e91bba0SGirish Moodalbail fail: 2696e91bba0SGirish Moodalbail free(*buf); 2706e91bba0SGirish Moodalbail *buf = NULL; 2716e91bba0SGirish Moodalbail return (-1); 2726e91bba0SGirish Moodalbail } 273