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 /****************************************************************************
91 Try the "standard" getifaddrs/freeifaddrs interfaces.
92 Also gets IPv6 interfaces.
93 ****************************************************************************/
95 #if HAVE_IFACE_GETIFADDRS
96 /****************************************************************************
97 Get the netmask address for a local interface.
98 ****************************************************************************/
100 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
102 struct ifaddrs
*iflist
= NULL
;
103 struct ifaddrs
*ifptr
= NULL
;
107 if (getifaddrs(&iflist
) < 0) {
111 /* Loop through interfaces, looking for given IP address */
112 for (ifptr
= iflist
, total
= 0;
113 ifptr
!= NULL
&& total
< max_interfaces
;
114 ifptr
= ifptr
->ifa_next
) {
116 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
118 copy_size
= sizeof(struct sockaddr_in
);
120 if (!ifptr
->ifa_addr
|| !ifptr
->ifa_netmask
) {
124 ifaces
[total
].flags
= ifptr
->ifa_flags
;
126 /* Check the interface is up. */
127 if (!(ifaces
[total
].flags
& IFF_UP
)) {
131 #if defined(HAVE_IPV6)
132 if (ifptr
->ifa_addr
->sa_family
== AF_INET6
) {
133 copy_size
= sizeof(struct sockaddr_in6
);
137 memcpy(&ifaces
[total
].ip
, ifptr
->ifa_addr
, copy_size
);
138 memcpy(&ifaces
[total
].netmask
, ifptr
->ifa_netmask
, copy_size
);
140 if ((ifaces
[total
].flags
& (IFF_BROADCAST
|IFF_LOOPBACK
)) &&
141 ifptr
->ifa_broadaddr
) {
142 memcpy(&ifaces
[total
].bcast
,
143 ifptr
->ifa_broadaddr
,
145 } else if ((ifaces
[total
].flags
& IFF_POINTOPOINT
) &&
146 ifptr
->ifa_dstaddr
) {
147 memcpy(&ifaces
[total
].bcast
,
154 strlcpy(ifaces
[total
].name
, ifptr
->ifa_name
,
155 sizeof(ifaces
[total
].name
));
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 (!(ifaces
[total
].flags
& IFF_UP
)) {
217 if (ioctl(fd
, SIOCGIFADDR
, &ifr
[i
]) != 0) {
221 strlcpy(ifaces
[total
].name
, ifr
[i
].ifr_name
,
222 sizeof(ifaces
[total
].name
));
224 memcpy(&ifaces
[total
].ip
, &ifr
[i
].ifr_addr
,
225 sizeof(struct sockaddr_in
));
227 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
[i
]) != 0) {
231 memcpy(&ifaces
[total
].netmask
, &ifr
[i
].ifr_netmask
,
232 sizeof(struct sockaddr_in
));
234 if (ifaces
[total
].flags
& IFF_BROADCAST
) {
235 if (ioctl(fd
, SIOCGIFBRDADDR
, &ifr
[i
]) != 0) {
238 memcpy(&ifaces
[total
].bcast
, &ifr
[i
].ifr_broadaddr
,
239 sizeof(struct sockaddr_in
));
240 } else if (ifaces
[total
].flags
& IFF_POINTOPOINT
) {
241 if (ioctl(fd
, SIOCGIFDSTADDR
, &ifr
[i
]) != 0) {
244 memcpy(&ifaces
[total
].bcast
, &ifr
[i
].ifr_dstaddr
,
245 sizeof(struct sockaddr_in
));
258 #define _FOUND_IFACE_ANY
259 #endif /* HAVE_IFACE_IFCONF */
260 #ifdef HAVE_IFACE_IFREQ
263 #include <sys/stropts.h>
266 /****************************************************************************
267 This should cover most of the streams based systems.
268 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
269 ****************************************************************************/
271 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
274 struct strioctl strioctl
;
277 struct ifreq
*ifr
=NULL
;
280 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
284 strioctl
.ic_cmd
= SIOCGIFCONF
;
285 strioctl
.ic_dp
= buff
;
286 strioctl
.ic_len
= sizeof(buff
);
287 if (ioctl(fd
, I_STR
, &strioctl
) < 0) {
292 /* we can ignore the possible sizeof(int) here as the resulting
293 number of interface structures won't change */
294 n
= strioctl
.ic_len
/ sizeof(struct ifreq
);
296 /* we will assume that the kernel returns the length as an int
297 at the start of the buffer if the offered size is a
298 multiple of the structure size plus an int */
299 if (n
*sizeof(struct ifreq
) + sizeof(int) == strioctl
.ic_len
) {
300 ifr
= (struct ifreq
*)(buff
+ sizeof(int));
302 ifr
= (struct ifreq
*)buff
;
305 /* Loop through interfaces */
307 for (i
= 0; i
<n
&& total
< max_interfaces
; i
++) {
309 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
313 strioctl
.ic_cmd
= SIOCGIFFLAGS
;
314 strioctl
.ic_dp
= (char *)&ifreq
;
315 strioctl
.ic_len
= sizeof(struct ifreq
);
316 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
320 ifaces
[total
].flags
= ifreq
.ifr_flags
;
322 if (!(ifaces
[total
].flags
& IFF_UP
)) {
326 strioctl
.ic_cmd
= SIOCGIFADDR
;
327 strioctl
.ic_dp
= (char *)&ifreq
;
328 strioctl
.ic_len
= sizeof(struct ifreq
);
329 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
333 strlcpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
));
335 memcpy(&ifaces
[total
].ip
, &ifreq
.ifr_addr
,
336 sizeof(struct sockaddr_in
));
338 strioctl
.ic_cmd
= SIOCGIFNETMASK
;
339 strioctl
.ic_dp
= (char *)&ifreq
;
340 strioctl
.ic_len
= sizeof(struct ifreq
);
341 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
345 memcpy(&ifaces
[total
].netmask
, &ifreq
.ifr_addr
,
346 sizeof(struct sockaddr_in
));
348 if (ifaces
[total
].flags
& IFF_BROADCAST
) {
349 strioctl
.ic_cmd
= SIOCGIFBRDADDR
;
350 strioctl
.ic_dp
= (char *)&ifreq
;
351 strioctl
.ic_len
= sizeof(struct ifreq
);
352 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
355 memcpy(&ifaces
[total
].bcast
, &ifreq
.ifr_broadaddr
,
356 sizeof(struct sockaddr_in
));
357 } else if (ifaces
[total
].flags
& IFF_POINTOPOINT
) {
358 strioctl
.ic_cmd
= SIOCGIFDSTADDR
;
359 strioctl
.ic_dp
= (char *)&ifreq
;
360 strioctl
.ic_len
= sizeof(struct ifreq
);
361 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
364 memcpy(&ifaces
[total
].bcast
, &ifreq
.ifr_dstaddr
,
365 sizeof(struct sockaddr_in
));
378 #define _FOUND_IFACE_ANY
379 #endif /* HAVE_IFACE_IFREQ */
380 #ifdef HAVE_IFACE_AIX
382 /****************************************************************************
383 This one is for AIX (tested on 4.2).
384 ****************************************************************************/
386 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
391 struct ifreq
*ifr
=NULL
;
394 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
399 ifc
.ifc_len
= sizeof(buff
);
402 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
409 /* Loop through interfaces */
412 while (i
> 0 && total
< max_interfaces
) {
415 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
417 inc
= ifr
->ifr_addr
.sa_len
;
419 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) != 0) {
423 ifaces
[total
].flags
= ifr
->ifr_flags
;
425 if (!(ifaces
[total
].flags
& IFF_UP
)) {
429 if (ioctl(fd
, SIOCGIFADDR
, ifr
) != 0) {
433 memcpy(&ifaces
[total
].ip
, &ifr
->ifr_addr
,
434 sizeof(struct sockaddr_in
));
436 strlcpy(ifaces
[total
].name
, ifr
->ifr_name
,
437 sizeof(ifaces
[total
].name
));
439 if (ioctl(fd
, SIOCGIFNETMASK
, ifr
) != 0) {
443 memcpy(&ifaces
[total
].netmask
, &ifr
->ifr_addr
,
444 sizeof(struct sockaddr_in
));
446 if (ifaces
[total
].flags
& IFF_BROADCAST
) {
447 if (ioctl(fd
, SIOCGIFBRDADDR
, &ifr
[i
]) != 0) {
450 memcpy(&ifaces
[total
].bcast
, &ifr
[i
].ifr_broadaddr
,
451 sizeof(struct sockaddr_in
));
452 } else if (ifaces
[total
].flags
& IFF_POINTOPOINT
) {
453 if (ioctl(fd
, SIOCGIFDSTADDR
, &ifr
[i
]) != 0) {
456 memcpy(&ifaces
[total
].bcast
, &ifr
[i
].ifr_dstaddr
,
457 sizeof(struct sockaddr_in
));
467 * Patch from Archie Cobbs (archie@whistle.com). The
468 * addresses in the SIOCGIFCONF interface list have a
469 * minimum size. Usually this doesn't matter, but if
470 * your machine has tunnel interfaces, etc. that have
471 * a zero length "link address", this does matter. */
473 if (inc
< sizeof(ifr
->ifr_addr
))
474 inc
= sizeof(ifr
->ifr_addr
);
477 ifr
= (struct ifreq
*) (((char*) ifr
) + inc
);
485 #define _FOUND_IFACE_ANY
486 #endif /* HAVE_IFACE_AIX */
487 #ifndef _FOUND_IFACE_ANY
488 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
495 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
499 #if defined(HAVE_IPV6)
501 * If we have IPv6 - sort these interfaces lower
502 * than any IPv4 ones.
504 if (i1
->ip
.ss_family
== AF_INET6
&&
505 i2
->ip
.ss_family
== AF_INET
) {
507 } else if (i1
->ip
.ss_family
== AF_INET
&&
508 i2
->ip
.ss_family
== AF_INET6
) {
512 if (i1
->ip
.ss_family
== AF_INET6
) {
513 struct sockaddr_in6
*s1
= (struct sockaddr_in6
*)&i1
->ip
;
514 struct sockaddr_in6
*s2
= (struct sockaddr_in6
*)&i2
->ip
;
516 r
= memcmp(&s1
->sin6_addr
,
518 sizeof(struct in6_addr
));
523 s1
= (struct sockaddr_in6
*)&i1
->netmask
;
524 s2
= (struct sockaddr_in6
*)&i2
->netmask
;
526 r
= memcmp(&s1
->sin6_addr
,
528 sizeof(struct in6_addr
));
535 if (i1
->ip
.ss_family
== AF_INET
) {
536 struct sockaddr_in
*s1
= (struct sockaddr_in
*)&i1
->ip
;
537 struct sockaddr_in
*s2
= (struct sockaddr_in
*)&i2
->ip
;
539 r
= ntohl(s1
->sin_addr
.s_addr
) -
540 ntohl(s2
->sin_addr
.s_addr
);
545 s1
= (struct sockaddr_in
*)&i1
->netmask
;
546 s2
= (struct sockaddr_in
*)&i2
->netmask
;
548 return ntohl(s1
->sin_addr
.s_addr
) -
549 ntohl(s2
->sin_addr
.s_addr
);
554 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
);
555 /* this wrapper is used to remove duplicates from the interface list generated
557 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
561 total
= _get_interfaces(ifaces
, max_interfaces
);
562 if (total
<= 0) return total
;
564 /* now we need to remove duplicates */
565 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
568 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
569 for (j
=i
-1;j
<total
-1;j
++) {
570 ifaces
[j
] = ifaces
[j
+1];
583 /* this is the autoconf driver to test get_interfaces() */
587 struct iface_struct ifaces
[MAX_INTERFACES
];
588 int total
= get_interfaces(ifaces
, MAX_INTERFACES
);
591 printf("got %d interfaces:\n", total
);
596 for (i
=0;i
<total
;i
++) {
597 char addr
[INET6_ADDRSTRLEN
];
599 printf("%-10s ", ifaces
[i
].name
);
601 ret
= getnameinfo((struct sockaddr
*)&ifaces
[i
].ip
,
602 sizeof(ifaces
[i
].ip
),
604 NULL
, 0, NI_NUMERICHOST
);
605 printf("IP=%s ", addr
);
607 ret
= getnameinfo((struct sockaddr
*)&ifaces
[i
].netmask
,
608 sizeof(ifaces
[i
].netmask
),
610 NULL
, 0, NI_NUMERICHOST
);
611 printf("NETMASK=%s ", addr
);
613 ret
= getnameinfo((struct sockaddr
*)&ifaces
[i
].bcast
,
614 sizeof(ifaces
[i
].bcast
),
616 NULL
, 0, NI_NUMERICHOST
);
617 printf("BCAST=%s\n", addr
);