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;
106 if (getifaddrs(&iflist) < 0) {
110 /* Loop through interfaces, looking for given IP address */
111 for (ifptr = iflist, total = 0;
112 ifptr != NULL && total < max_interfaces;
113 ifptr = ifptr->ifa_next) {
115 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
117 copy_size = sizeof(struct sockaddr_in);
119 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
123 ifaces[total].flags = ifptr->ifa_flags;
125 /* Check the interface is up. */
126 if (!(ifaces[total].flags & IFF_UP)) {
131 if (ifptr->ifa_addr->sa_family == AF_INET6) {
132 copy_size = sizeof(struct sockaddr_in6);
136 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
137 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
139 if ((ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) &&
140 ifptr->ifa_broadaddr) {
141 memcpy(&ifaces[total].bcast,
142 ifptr->ifa_broadaddr,
144 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
145 ifptr->ifa_dstaddr ) {
146 memcpy(&ifaces[total].bcast,
153 strncpy(ifaces[total].name, ifptr->ifa_name,
154 sizeof(ifaces[total].name)-1);
155 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
164 #define _FOUND_IFACE_ANY
165 #endif /* HAVE_IFACE_GETIFADDRS */
166 #if HAVE_IFACE_IFCONF
168 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
169 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
171 It probably also works on any BSD style system. */
173 /****************************************************************************
174 Get the netmask address for a local interface.
175 ****************************************************************************/
177 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
182 struct ifreq *ifr=NULL;
185 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
189 ifc.ifc_len = sizeof(buff);
192 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
199 n = ifc.ifc_len / sizeof(struct ifreq);
201 /* Loop through interfaces, looking for given IP address */
202 for (i=n-1;i>=0 && total < max_interfaces;i--) {
204 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
206 /* Check the interface is up. */
207 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
211 ifaces[total].flags = ifr[i].ifr_flags;
213 if (!(flags & IFF_UP)) {
217 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
221 strncpy(ifaces[total].name, ifr[i].ifr_name,
222 sizeof(ifaces[total].name)-1);
223 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
225 memcpy(&ifaces[total].ip, &ifr[i].ifr_addr,
226 sizeof(struct sockaddr_in));
228 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
232 memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask,
233 sizeof(struct sockaddr_in));
235 if (ifaces[total].flags & IFF_BROADCAST) {
236 if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
239 memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
240 sizeof(struct sockaddr_in));
241 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
242 if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
245 memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
246 sizeof(struct sockaddr_in));
259 #define _FOUND_IFACE_ANY
260 #endif /* HAVE_IFACE_IFCONF */
261 #ifdef HAVE_IFACE_IFREQ
264 #include <sys/stropts.h>
267 /****************************************************************************
268 This should cover most of the streams based systems.
269 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
270 ****************************************************************************/
272 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
275 struct strioctl strioctl;
278 struct ifreq *ifr=NULL;
281 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
285 strioctl.ic_cmd = SIOCGIFCONF;
286 strioctl.ic_dp = buff;
287 strioctl.ic_len = sizeof(buff);
288 if (ioctl(fd, I_STR, &strioctl) < 0) {
293 /* we can ignore the possible sizeof(int) here as the resulting
294 number of interface structures won't change */
295 n = strioctl.ic_len / sizeof(struct ifreq);
297 /* we will assume that the kernel returns the length as an int
298 at the start of the buffer if the offered size is a
299 multiple of the structure size plus an int */
300 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
301 ifr = (struct ifreq *)(buff + sizeof(int));
303 ifr = (struct ifreq *)buff;
306 /* Loop through interfaces */
308 for (i = 0; i<n && total < max_interfaces; i++) {
310 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
314 strioctl.ic_cmd = SIOCGIFFLAGS;
315 strioctl.ic_dp = (char *)&ifreq;
316 strioctl.ic_len = sizeof(struct ifreq);
317 if (ioctl(fd, I_STR, &strioctl) != 0) {
321 ifaces[total].flags = ifreq.ifr_flags;
323 if (!(ifaces[total].flags & IFF_UP)) {
327 strioctl.ic_cmd = SIOCGIFADDR;
328 strioctl.ic_dp = (char *)&ifreq;
329 strioctl.ic_len = sizeof(struct ifreq);
330 if (ioctl(fd, I_STR, &strioctl) != 0) {
334 strncpy(ifaces[total].name, iname,
335 sizeof(ifaces[total].name)-1);
336 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
338 memcpy(&ifaces[total].ip, &ifreq.ifr_addr,
339 sizeof(struct sockaddr_in));
341 strioctl.ic_cmd = SIOCGIFNETMASK;
342 strioctl.ic_dp = (char *)&ifreq;
343 strioctl.ic_len = sizeof(struct ifreq);
344 if (ioctl(fd, I_STR, &strioctl) != 0) {
348 memcpy(&ifaces[total].netmask, &ifreq.ifr_addr,
349 sizeof(struct sockaddr_in));
351 if (ifaces[total].flags & IFF_BROADCAST) {
352 strioctl.ic_cmd = SIOCGIFBRDADDR;
353 strioctl.ic_dp = (char *)&ifreq;
354 strioctl.ic_len = sizeof(struct ifreq);
355 if (ioctl(fd, I_STR, &strioctl) != 0) {
358 memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr,
359 sizeof(struct sockaddr_in));
360 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
361 strioctl.ic_cmd = SIOCGIFDSTADDR;
362 strioctl.ic_dp = (char *)&ifreq;
363 strioctl.ic_len = sizeof(struct ifreq);
364 if (ioctl(fd, I_STR, &strioctl) != 0) {
367 memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr,
368 sizeof(struct sockaddr_in));
381 #define _FOUND_IFACE_ANY
382 #endif /* HAVE_IFACE_IFREQ */
383 #ifdef HAVE_IFACE_AIX
385 /****************************************************************************
386 This one is for AIX (tested on 4.2).
387 ****************************************************************************/
389 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
394 struct ifreq *ifr=NULL;
397 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
402 ifc.ifc_len = sizeof(buff);
405 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
412 /* Loop through interfaces */
415 while (i > 0 && total < max_interfaces) {
418 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
420 inc = ifr->ifr_addr.sa_len;
422 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
426 ifaces[total].flags = ifr->ifr_flags;
428 if (!(ifaces[total].flags & IFF_UP)) {
432 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
436 memcpy(&ifaces[total].ip, &ifr->ifr_addr,
437 sizeof(struct sockaddr_in));
439 strncpy(ifaces[total].name, ifr->ifr_name,
440 sizeof(ifaces[total].name)-1);
441 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
443 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
447 memcpy(&ifaces[total].netmask, &ifr->ifr_addr,
448 sizeof(struct sockaddr_in));
450 if (ifaces[total].flags & IFF_BROADCAST) {
451 if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
454 memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
455 sizeof(struct sockaddr_in));
456 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
457 if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
460 memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
461 sizeof(struct sockaddr_in));
471 * Patch from Archie Cobbs (archie@whistle.com). The
472 * addresses in the SIOCGIFCONF interface list have a
473 * minimum size. Usually this doesn't matter, but if
474 * your machine has tunnel interfaces, etc. that have
475 * a zero length "link address", this does matter. */
477 if (inc < sizeof(ifr->ifr_addr))
478 inc = sizeof(ifr->ifr_addr);
481 ifr = (struct ifreq*) (((char*) ifr) + inc);
489 #define _FOUND_IFACE_ANY
490 #endif /* HAVE_IFACE_AIX */
491 #ifndef _FOUND_IFACE_ANY
492 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
499 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
505 * If we have IPv6 - sort these interfaces lower
506 * than any IPv4 ones.
508 if (i1->ip.ss_family == AF_INET6 &&
509 i2->ip.ss_family == AF_INET) {
511 } else if (i1->ip.ss_family == AF_INET &&
512 i2->ip.ss_family == AF_INET6) {
516 if (i1->ip.ss_family == AF_INET6) {
517 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
518 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
520 r = memcmp(&s1->sin6_addr,
522 sizeof(struct in6_addr));
527 s1 = (struct sockaddr_in6 *)&i1->netmask;
528 s2 = (struct sockaddr_in6 *)&i2->netmask;
530 r = memcmp(&s1->sin6_addr,
532 sizeof(struct in6_addr));
539 if (i1->ip.ss_family == AF_INET) {
540 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
541 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
543 r = ntohl(s1->sin_addr.s_addr) -
544 ntohl(s2->sin_addr.s_addr);
549 s1 = (struct sockaddr_in *)&i1->netmask;
550 s2 = (struct sockaddr_in *)&i2->netmask;
552 return ntohl(s1->sin_addr.s_addr) -
553 ntohl(s2->sin_addr.s_addr);
558 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
559 /* this wrapper is used to remove duplicates from the interface list generated
561 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
565 total = _get_interfaces(ifaces, max_interfaces);
566 if (total <= 0) return total;
568 /* now we need to remove duplicates */
569 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
572 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
573 for (j=i-1;j<total-1;j++) {
574 ifaces[j] = ifaces[j+1];
587 /* this is the autoconf driver to test get_interfaces() */
591 struct iface_struct ifaces[MAX_INTERFACES];
592 int total = get_interfaces(ifaces, MAX_INTERFACES);
595 printf("got %d interfaces:\n", total);
600 for (i=0;i<total;i++) {
601 char addr[INET6_ADDRSTRLEN];
603 printf("%-10s ", ifaces[i].name);
605 ret = getnameinfo((struct sockaddr *)&ifaces[i].ip,
606 sizeof(ifaces[i].ip),
608 NULL, 0, NI_NUMERICHOST);
609 printf("IP=%s ", addr);
611 ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask,
612 sizeof(ifaces[i].netmask),
614 NULL, 0, NI_NUMERICHOST);
615 printf("NETMASK=%s ", addr);
617 ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast,
618 sizeof(ifaces[i].bcast),
620 NULL, 0, NI_NUMERICHOST);
621 printf("BCAST=%s\n", addr);