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
getifaddrs(struct ifaddrs ** ifap)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
freeifaddrs(struct ifaddrs * ifa)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
getallifaddrs(sa_family_t af,struct ifaddrs ** ifap,int64_t flags)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
getallifs(int s,sa_family_t af,struct lifreq ** lifr,int * numifs,int64_t lifc_flags)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