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"
88 #include "lib/replace/replace.h"
90 /****************************************************************************
92 ****************************************************************************/
94 /****************************************************************************
95 Create a struct sockaddr_storage with the netmask bits set to 1.
96 ****************************************************************************/
98 bool make_netmask(struct sockaddr_storage *pss_out,
99 const struct sockaddr_storage *pss_in,
100 unsigned long masklen)
103 /* Now apply masklen bits of mask. */
104 #if defined(HAVE_IPV6)
105 if (pss_in->ss_family == AF_INET6) {
106 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
112 for (i = 0; masklen >= 8; masklen -= 8, i++) {
115 /* Deal with the partial byte. */
116 *p++ &= (0xff & ~(0xff>>masklen));
118 for (;i < sizeof(struct in6_addr); i++) {
124 if (pss_in->ss_family == AF_INET) {
128 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
129 htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
135 /****************************************************************************
136 Create a struct sockaddr_storage set to the broadcast or network adress from
137 an incoming sockaddr_storage.
138 ****************************************************************************/
140 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
141 const struct sockaddr_storage *pss_in,
142 const struct sockaddr_storage *nmask,
145 unsigned int i = 0, len = 0;
150 /* Set all zero netmask bits to 1. */
151 #if defined(HAVE_IPV6)
152 if (pss_in->ss_family == AF_INET6) {
153 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
154 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
158 if (pss_in->ss_family == AF_INET) {
159 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
160 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
164 for (i = 0; i < len; i++, p++, pmask++) {
166 *p = (*p & *pmask) | (*pmask ^ 0xff);
174 void make_bcast(struct sockaddr_storage *pss_out,
175 const struct sockaddr_storage *pss_in,
176 const struct sockaddr_storage *nmask)
178 make_bcast_or_net(pss_out, pss_in, nmask, true);
181 void make_net(struct sockaddr_storage *pss_out,
182 const struct sockaddr_storage *pss_in,
183 const struct sockaddr_storage *nmask)
185 make_bcast_or_net(pss_out, pss_in, nmask, false);
188 /****************************************************************************
189 Try the "standard" getifaddrs/freeifaddrs interfaces.
190 Also gets IPv6 interfaces.
191 ****************************************************************************/
193 #if HAVE_IFACE_GETIFADDRS
194 /****************************************************************************
195 Get the netmask address for a local interface.
196 ****************************************************************************/
198 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
200 struct ifaddrs *iflist = NULL;
201 struct ifaddrs *ifptr = NULL;
205 if (getifaddrs(&iflist) < 0) {
209 /* Loop through interfaces, looking for given IP address */
210 for (ifptr = iflist, total = 0;
211 ifptr != NULL && total < max_interfaces;
212 ifptr = ifptr->ifa_next) {
214 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
216 copy_size = sizeof(struct sockaddr_in);
218 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
222 ifaces[total].flags = ifptr->ifa_flags;
224 /* Check the interface is up. */
225 if (!(ifaces[total].flags & IFF_UP)) {
229 #if defined(HAVE_IPV6)
230 if (ifptr->ifa_addr->sa_family == AF_INET6) {
231 copy_size = sizeof(struct sockaddr_in6);
235 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
236 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
238 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
239 if (ifptr->ifa_broadaddr) {
240 memcpy(&ifaces[total].bcast,
241 ifptr->ifa_broadaddr,
244 /* For some reason ifptr->ifa_broadaddr
245 * is null. Make one from ifa_addr and
248 make_bcast(&ifaces[total].bcast,
250 &ifaces[total].netmask);
252 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
253 ifptr->ifa_dstaddr ) {
254 memcpy(&ifaces[total].bcast,
261 strlcpy(ifaces[total].name, ifptr->ifa_name,
262 sizeof(ifaces[total].name));
271 #define _FOUND_IFACE_ANY
272 #endif /* HAVE_IFACE_GETIFADDRS */
273 #if HAVE_IFACE_IFCONF
275 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
276 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
278 It probably also works on any BSD style system. */
280 /****************************************************************************
281 Get the netmask address for a local interface.
282 ****************************************************************************/
284 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
289 struct ifreq *ifr=NULL;
292 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
296 ifc.ifc_len = sizeof(buff);
299 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
306 n = ifc.ifc_len / sizeof(struct ifreq);
308 /* Loop through interfaces, looking for given IP address */
309 for (i=n-1;i>=0 && total < max_interfaces;i--) {
311 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
313 /* Check the interface is up. */
314 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
318 ifaces[total].flags = ifr[i].ifr_flags;
320 if (!(ifaces[total].flags & IFF_UP)) {
324 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
328 strlcpy(ifaces[total].name, ifr[i].ifr_name,
329 sizeof(ifaces[total].name));
331 memcpy(&ifaces[total].ip, &ifr[i].ifr_addr,
332 sizeof(struct sockaddr_in));
334 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
338 memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask,
339 sizeof(struct sockaddr_in));
341 if (ifaces[total].flags & IFF_BROADCAST) {
342 if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
345 memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
346 sizeof(struct sockaddr_in));
347 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
348 if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
351 memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
352 sizeof(struct sockaddr_in));
365 #define _FOUND_IFACE_ANY
366 #endif /* HAVE_IFACE_IFCONF */
367 #ifdef HAVE_IFACE_IFREQ
370 #include <sys/stropts.h>
373 /****************************************************************************
374 This should cover most of the streams based systems.
375 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
376 ****************************************************************************/
378 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
381 struct strioctl strioctl;
384 struct ifreq *ifr=NULL;
387 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
391 strioctl.ic_cmd = SIOCGIFCONF;
392 strioctl.ic_dp = buff;
393 strioctl.ic_len = sizeof(buff);
394 if (ioctl(fd, I_STR, &strioctl) < 0) {
399 /* we can ignore the possible sizeof(int) here as the resulting
400 number of interface structures won't change */
401 n = strioctl.ic_len / sizeof(struct ifreq);
403 /* we will assume that the kernel returns the length as an int
404 at the start of the buffer if the offered size is a
405 multiple of the structure size plus an int */
406 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
407 ifr = (struct ifreq *)(buff + sizeof(int));
409 ifr = (struct ifreq *)buff;
412 /* Loop through interfaces */
414 for (i = 0; i<n && total < max_interfaces; i++) {
416 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
420 strioctl.ic_cmd = SIOCGIFFLAGS;
421 strioctl.ic_dp = (char *)&ifreq;
422 strioctl.ic_len = sizeof(struct ifreq);
423 if (ioctl(fd, I_STR, &strioctl) != 0) {
427 ifaces[total].flags = ifreq.ifr_flags;
429 if (!(ifaces[total].flags & IFF_UP)) {
433 strioctl.ic_cmd = SIOCGIFADDR;
434 strioctl.ic_dp = (char *)&ifreq;
435 strioctl.ic_len = sizeof(struct ifreq);
436 if (ioctl(fd, I_STR, &strioctl) != 0) {
440 strlcpy(ifaces[total].name,
442 sizeof(ifaces[total].name));
444 memcpy(&ifaces[total].ip, &ifreq.ifr_addr,
445 sizeof(struct sockaddr_in));
447 strioctl.ic_cmd = SIOCGIFNETMASK;
448 strioctl.ic_dp = (char *)&ifreq;
449 strioctl.ic_len = sizeof(struct ifreq);
450 if (ioctl(fd, I_STR, &strioctl) != 0) {
454 memcpy(&ifaces[total].netmask, &ifreq.ifr_addr,
455 sizeof(struct sockaddr_in));
457 if (ifaces[total].flags & IFF_BROADCAST) {
458 strioctl.ic_cmd = SIOCGIFBRDADDR;
459 strioctl.ic_dp = (char *)&ifreq;
460 strioctl.ic_len = sizeof(struct ifreq);
461 if (ioctl(fd, I_STR, &strioctl) != 0) {
464 memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr,
465 sizeof(struct sockaddr_in));
466 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
467 strioctl.ic_cmd = SIOCGIFDSTADDR;
468 strioctl.ic_dp = (char *)&ifreq;
469 strioctl.ic_len = sizeof(struct ifreq);
470 if (ioctl(fd, I_STR, &strioctl) != 0) {
473 memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr,
474 sizeof(struct sockaddr_in));
487 #define _FOUND_IFACE_ANY
488 #endif /* HAVE_IFACE_IFREQ */
489 #ifdef HAVE_IFACE_AIX
491 /****************************************************************************
492 This one is for AIX (tested on 4.2).
493 ****************************************************************************/
495 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
500 struct ifreq *ifr=NULL;
503 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
508 ifc.ifc_len = sizeof(buff);
511 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
518 /* Loop through interfaces */
521 while (i > 0 && total < max_interfaces) {
524 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
526 inc = ifr->ifr_addr.sa_len;
528 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
532 ifaces[total].flags = ifr->ifr_flags;
534 if (!(ifaces[total].flags & IFF_UP)) {
538 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
542 memcpy(&ifaces[total].ip, &ifr->ifr_addr,
543 sizeof(struct sockaddr_in));
545 strlcpy(ifaces[total].name, ifr->ifr_name,
546 sizeof(ifaces[total].name));
548 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
552 memcpy(&ifaces[total].netmask, &ifr->ifr_addr,
553 sizeof(struct sockaddr_in));
555 if (ifaces[total].flags & IFF_BROADCAST) {
556 if (ioctl(fd, SIOCGIFBRDADDR, ifr) != 0) {
559 memcpy(&ifaces[total].bcast, &ifr->ifr_broadaddr,
560 sizeof(struct sockaddr_in));
561 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
562 if (ioctl(fd, SIOCGIFDSTADDR, ifr) != 0) {
565 memcpy(&ifaces[total].bcast, &ifr->ifr_dstaddr,
566 sizeof(struct sockaddr_in));
576 * Patch from Archie Cobbs (archie@whistle.com). The
577 * addresses in the SIOCGIFCONF interface list have a
578 * minimum size. Usually this doesn't matter, but if
579 * your machine has tunnel interfaces, etc. that have
580 * a zero length "link address", this does matter. */
582 if (inc < sizeof(ifr->ifr_addr))
583 inc = sizeof(ifr->ifr_addr);
586 ifr = (struct ifreq*) (((char*) ifr) + inc);
594 #define _FOUND_IFACE_ANY
595 #endif /* HAVE_IFACE_AIX */
596 #ifndef _FOUND_IFACE_ANY
597 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
604 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
608 #if defined(HAVE_IPV6)
610 * If we have IPv6 - sort these interfaces lower
611 * than any IPv4 ones.
613 if (i1->ip.ss_family == AF_INET6 &&
614 i2->ip.ss_family == AF_INET) {
616 } else if (i1->ip.ss_family == AF_INET &&
617 i2->ip.ss_family == AF_INET6) {
621 if (i1->ip.ss_family == AF_INET6) {
622 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
623 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
625 r = memcmp(&s1->sin6_addr,
627 sizeof(struct in6_addr));
632 s1 = (struct sockaddr_in6 *)&i1->netmask;
633 s2 = (struct sockaddr_in6 *)&i2->netmask;
635 r = memcmp(&s1->sin6_addr,
637 sizeof(struct in6_addr));
644 /* AIX uses __ss_family instead of ss_family inside of
645 sockaddr_storage. Instead of trying to figure out which field to
646 use, we can just cast it to a sockaddr.
649 if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
650 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
651 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
653 r = ntohl(s1->sin_addr.s_addr) -
654 ntohl(s2->sin_addr.s_addr);
659 s1 = (struct sockaddr_in *)&i1->netmask;
660 s2 = (struct sockaddr_in *)&i2->netmask;
662 return ntohl(s1->sin_addr.s_addr) -
663 ntohl(s2->sin_addr.s_addr);
668 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
669 /* this wrapper is used to remove duplicates from the interface list generated
671 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
675 total = _get_interfaces(ifaces, max_interfaces);
676 if (total <= 0) return total;
678 /* now we need to remove duplicates */
679 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
682 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
683 for (j=i-1;j<total-1;j++) {
684 ifaces[j] = ifaces[j+1];
697 /* this is the autoconf driver to test get_interfaces() */
701 struct iface_struct ifaces[MAX_INTERFACES];
702 int total = get_interfaces(ifaces, MAX_INTERFACES);
705 printf("got %d interfaces:\n", total);
710 for (i=0;i<total;i++) {
711 char addr[INET6_ADDRSTRLEN];
713 printf("%-10s ", ifaces[i].name);
715 ret = getnameinfo((struct sockaddr *)&ifaces[i].ip,
716 sizeof(ifaces[i].ip),
718 NULL, 0, NI_NUMERICHOST);
719 printf("IP=%s ", addr);
721 ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask,
722 sizeof(ifaces[i].netmask),
724 NULL, 0, NI_NUMERICHOST);
725 printf("NETMASK=%s ", addr);
727 ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast,
728 sizeof(ifaces[i].bcast),
730 NULL, 0, NI_NUMERICHOST);
731 printf("BCAST=%s\n", addr);