2 Unix SMB/CIFS implementation.
3 return a list of network interfaces
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* working out the interfaces for a OS is an incredibly non-portable
23 thing. We have several possible implementations below, and autoconf
24 tries each of them to see what works
26 Note that this file does _not_ include includes.h. That is so this code
27 can be called directly from the autoconf tests. That also means
28 this code cannot use any of the normal Samba debug stuff or defines.
29 This is standalone code.
39 #include <sys/types.h>
41 #include <sys/ioctl.h>
43 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
53 #ifdef HAVE_SYS_TIME_H
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
76 #define QSORT_CAST (__compar_fn_t)
80 #define QSORT_CAST (int (*)(const void *, const void *))
87 #include "interfaces.h"
89 /****************************************************************************
90 Try the "standard" getifaddrs/freeifaddrs interfaces.
91 Also gets IPv6 interfaces.
92 ****************************************************************************/
94 #if HAVE_IFACE_GETIFADDRS
95 /****************************************************************************
96 Get the netmask address for a local interface.
97 ****************************************************************************/
99 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
101 struct ifaddrs *iflist = NULL;
102 struct ifaddrs *ifptr = NULL;
105 if (getifaddrs(&iflist) < 0) {
109 /* Loop through interfaces, looking for given IP address */
110 for (ifptr = iflist, total = 0;
111 ifptr != NULL && total < max_interfaces;
112 ifptr = ifptr->ifa_next) {
114 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
118 /* Skip ipv6 for now. */
119 if (ifptr->ifa_addr->sa_family != AF_INET) {
122 if (!(ifptr->ifa_flags & IFF_UP)) {
126 ifaces[total].sa_family = ifptr->ifa_addr->sa_family;
128 ifaces[total].iface_addr.ip =
129 ((struct sockaddr_in *)ifptr->ifa_addr)->sin_addr;
131 ifaces[total].iface_netmask.netmask =
132 ((struct sockaddr_in *)ifptr->ifa_netmask)->sin_addr;
134 strncpy(ifaces[total].name, ifptr->ifa_name,
135 sizeof(ifaces[total].name)-1);
136 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
145 #define _FOUND_IFACE_ANY
146 #endif /* HAVE_IFACE_GETIFADDRS */
147 #if HAVE_IFACE_IFCONF
149 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
150 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
152 It probably also works on any BSD style system. */
154 /****************************************************************************
155 Get the netmask address for a local interface.
156 ****************************************************************************/
158 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
163 struct ifreq *ifr=NULL;
165 struct in_addr ipaddr;
166 struct in_addr nmask;
169 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
173 ifc.ifc_len = sizeof(buff);
176 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
183 n = ifc.ifc_len / sizeof(struct ifreq);
185 /* Loop through interfaces, looking for given IP address */
186 for (i=n-1;i>=0 && total < max_interfaces;i--) {
187 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
191 iname = ifr[i].ifr_name;
192 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
194 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
198 if (!(ifr[i].ifr_flags & IFF_UP)) {
202 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
206 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
208 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
209 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
210 ifaces[total].sa_family = AF_INET;
211 ifaces[total].iface_addr.ip = ipaddr;
212 ifaces[total].iface_netmask.netmask = nmask;
221 #define _FOUND_IFACE_ANY
222 #endif /* HAVE_IFACE_IFCONF */
223 #ifdef HAVE_IFACE_IFREQ
226 #include <sys/stropts.h>
229 /****************************************************************************
230 This should cover most of the streams based systems.
231 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
232 ****************************************************************************/
234 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
237 struct strioctl strioctl;
240 struct ifreq *ifr=NULL;
242 struct in_addr ipaddr;
243 struct in_addr nmask;
246 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
250 strioctl.ic_cmd = SIOCGIFCONF;
251 strioctl.ic_dp = buff;
252 strioctl.ic_len = sizeof(buff);
253 if (ioctl(fd, I_STR, &strioctl) < 0) {
258 /* we can ignore the possible sizeof(int) here as the resulting
259 number of interface structures won't change */
260 n = strioctl.ic_len / sizeof(struct ifreq);
262 /* we will assume that the kernel returns the length as an int
263 at the start of the buffer if the offered size is a
264 multiple of the structure size plus an int */
265 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
266 ifr = (struct ifreq *)(buff + sizeof(int));
268 ifr = (struct ifreq *)buff;
271 /* Loop through interfaces */
273 for (i = 0; i<n && total < max_interfaces; i++) {
276 strioctl.ic_cmd = SIOCGIFFLAGS;
277 strioctl.ic_dp = (char *)&ifreq;
278 strioctl.ic_len = sizeof(struct ifreq);
279 if (ioctl(fd, I_STR, &strioctl) != 0) {
283 if (!(ifreq.ifr_flags & IFF_UP)) {
287 strioctl.ic_cmd = SIOCGIFADDR;
288 strioctl.ic_dp = (char *)&ifreq;
289 strioctl.ic_len = sizeof(struct ifreq);
290 if (ioctl(fd, I_STR, &strioctl) != 0) {
294 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
295 iname = ifreq.ifr_name;
297 strioctl.ic_cmd = SIOCGIFNETMASK;
298 strioctl.ic_dp = (char *)&ifreq;
299 strioctl.ic_len = sizeof(struct ifreq);
300 if (ioctl(fd, I_STR, &strioctl) != 0) {
304 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
306 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
307 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
308 ifaces[total].sa_family = AF_INET;
309 ifaces[total].iface_addr.ip = ipaddr;
310 ifaces[total].iface_netmask.netmask = nmask;
320 #define _FOUND_IFACE_ANY
321 #endif /* HAVE_IFACE_IFREQ */
322 #ifdef HAVE_IFACE_AIX
324 /****************************************************************************
325 This one is for AIX (tested on 4.2).
326 ****************************************************************************/
328 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
333 struct ifreq *ifr=NULL;
334 struct in_addr ipaddr;
335 struct in_addr nmask;
339 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
344 ifc.ifc_len = sizeof(buff);
347 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
354 /* Loop through interfaces */
357 while (i > 0 && total < max_interfaces) {
360 inc = ifr->ifr_addr.sa_len;
362 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
366 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
367 iname = ifr->ifr_name;
369 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
373 if (!(ifr->ifr_flags & IFF_UP)) {
377 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
381 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
383 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
384 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
385 ifaces[total].sa_family = AF_INET;
386 ifaces[total].iface_addr.ip = ipaddr;
387 ifaces[total].iface_netmask.netmask = nmask;
393 * Patch from Archie Cobbs (archie@whistle.com). The
394 * addresses in the SIOCGIFCONF interface list have a
395 * minimum size. Usually this doesn't matter, but if
396 * your machine has tunnel interfaces, etc. that have
397 * a zero length "link address", this does matter. */
399 if (inc < sizeof(ifr->ifr_addr))
400 inc = sizeof(ifr->ifr_addr);
403 ifr = (struct ifreq*) (((char*) ifr) + inc);
411 #define _FOUND_IFACE_ANY
412 #endif /* HAVE_IFACE_AIX */
413 #ifndef _FOUND_IFACE_ANY
414 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
421 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
424 r = strcmp(i1->name, i2->name);
428 r = i1->sa_family - i2->sa_family;
434 if (i1->sa_family == AF_INET6) {
435 r = memcmp(&i1->iface_addr.ip6,
437 sizeof(struct in6_addr));
441 r = memcmp(&i1->iface_netmask.netmask6,
442 &i1->iface_netmask.netmask6,
443 sizeof(struct in6_addr));
450 if (i1->sa_family == AF_INET) {
451 r = ntohl(i1->iface_addr.ip.s_addr) -
452 ntohl(i2->iface_addr.ip.s_addr);
456 r = ntohl(i1->iface_netmask.netmask.s_addr) -
457 ntohl(i2->iface_netmask.netmask.s_addr);
462 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
463 /* this wrapper is used to remove duplicates from the interface list generated
465 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
469 total = _get_interfaces(ifaces, max_interfaces);
470 if (total <= 0) return total;
472 /* now we need to remove duplicates */
473 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
476 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
477 for (j=i-1;j<total-1;j++) {
478 ifaces[j] = ifaces[j+1];
491 /* this is the autoconf driver to test get_interfaces() */
495 struct iface_struct ifaces[MAX_INTERFACES];
496 int total = get_interfaces(ifaces, MAX_INTERFACES);
499 printf("got %d interfaces:\n", total);
504 for (i=0;i<total;i++) {
505 char addr[INET6_ADDRSTRLEN];
506 printf("%-10s ", ifaces[i].name);
507 printf("IP=%s ", inet_ntop(ifaces[i].sa_family,
508 (const void *)&ifaces[i].iface_addr.ip,
511 printf("NETMASK=%s\n", inet_ntop(ifaces[i].sa_family,
512 (const void *)&ifaces[i].iface_netmask.netmask,