2 Unix SMB/CIFS implementation.
3 return a list of network interfaces
4 Copyright (C) Andrew Tridgell 1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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>
49 #ifdef HAVE_SYS_TIME_H
54 #ifdef HAVE_SYS_SOCKIO_H
55 #include <sys/sockio.h>
72 #define QSORT_CAST (__compar_fn_t)
76 #define QSORT_CAST (int (*)(const void *, const void *))
83 #include "interfaces.h"
87 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
88 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
90 It probably also works on any BSD style system. */
92 /****************************************************************************
93 get the netmask address for a local interface
94 ****************************************************************************/
95 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
100 struct ifreq
*ifr
=NULL
;
102 struct in_addr ipaddr
;
103 struct in_addr nmask
;
106 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
110 ifc
.ifc_len
= sizeof(buff
);
113 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
120 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
122 /* Loop through interfaces, looking for given IP address */
123 for (i
=n
-1;i
>=0 && total
< max_interfaces
;i
--) {
124 if (ioctl(fd
, SIOCGIFADDR
, &ifr
[i
]) != 0) {
128 iname
= ifr
[i
].ifr_name
;
129 ipaddr
= (*(struct sockaddr_in
*)&ifr
[i
].ifr_addr
).sin_addr
;
131 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
[i
]) != 0) {
135 if (!(ifr
[i
].ifr_flags
& IFF_UP
)) {
139 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
[i
]) != 0) {
143 nmask
= ((struct sockaddr_in
*)&ifr
[i
].ifr_addr
)->sin_addr
;
145 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
146 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
147 ifaces
[total
].ip
= ipaddr
;
148 ifaces
[total
].netmask
= nmask
;
157 #define _FOUND_IFACE_ANY
158 #endif /* HAVE_IFACE_IFCONF */
159 #ifdef HAVE_IFACE_IFREQ
162 #include <sys/stropts.h>
165 /****************************************************************************
166 this should cover most of the streams based systems
167 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
168 ****************************************************************************/
169 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
172 struct strioctl strioctl
;
175 struct ifreq
*ifr
=NULL
;
177 struct in_addr ipaddr
;
178 struct in_addr nmask
;
181 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
185 strioctl
.ic_cmd
= SIOCGIFCONF
;
186 strioctl
.ic_dp
= buff
;
187 strioctl
.ic_len
= sizeof(buff
);
188 if (ioctl(fd
, I_STR
, &strioctl
) < 0) {
193 /* we can ignore the possible sizeof(int) here as the resulting
194 number of interface structures won't change */
195 n
= strioctl
.ic_len
/ sizeof(struct ifreq
);
197 /* we will assume that the kernel returns the length as an int
198 at the start of the buffer if the offered size is a
199 multiple of the structure size plus an int */
200 if (n
*sizeof(struct ifreq
) + sizeof(int) == strioctl
.ic_len
) {
201 ifr
= (struct ifreq
*)(buff
+ sizeof(int));
203 ifr
= (struct ifreq
*)buff
;
206 /* Loop through interfaces */
208 for (i
= 0; i
<n
&& total
< max_interfaces
; i
++) {
211 strioctl
.ic_cmd
= SIOCGIFFLAGS
;
212 strioctl
.ic_dp
= (char *)&ifreq
;
213 strioctl
.ic_len
= sizeof(struct ifreq
);
214 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
218 if (!(ifreq
.ifr_flags
& IFF_UP
)) {
222 strioctl
.ic_cmd
= SIOCGIFADDR
;
223 strioctl
.ic_dp
= (char *)&ifreq
;
224 strioctl
.ic_len
= sizeof(struct ifreq
);
225 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
229 ipaddr
= (*(struct sockaddr_in
*) &ifreq
.ifr_addr
).sin_addr
;
230 iname
= ifreq
.ifr_name
;
232 strioctl
.ic_cmd
= SIOCGIFNETMASK
;
233 strioctl
.ic_dp
= (char *)&ifreq
;
234 strioctl
.ic_len
= sizeof(struct ifreq
);
235 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
239 nmask
= ((struct sockaddr_in
*)&ifreq
.ifr_addr
)->sin_addr
;
241 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
242 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
243 ifaces
[total
].ip
= ipaddr
;
244 ifaces
[total
].netmask
= nmask
;
254 #define _FOUND_IFACE_ANY
255 #endif /* HAVE_IFACE_IFREQ */
256 #ifdef HAVE_IFACE_AIX
258 /****************************************************************************
259 this one is for AIX (tested on 4.2)
260 ****************************************************************************/
261 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
266 struct ifreq
*ifr
=NULL
;
267 struct in_addr ipaddr
;
268 struct in_addr nmask
;
272 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
277 ifc
.ifc_len
= sizeof(buff
);
280 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
287 /* Loop through interfaces */
290 while (i
> 0 && total
< max_interfaces
) {
293 inc
= ifr
->ifr_addr
.sa_len
;
295 if (ioctl(fd
, SIOCGIFADDR
, ifr
) != 0) {
299 ipaddr
= (*(struct sockaddr_in
*) &ifr
->ifr_addr
).sin_addr
;
300 iname
= ifr
->ifr_name
;
302 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) != 0) {
306 if (!(ifr
->ifr_flags
& IFF_UP
)) {
310 if (ioctl(fd
, SIOCGIFNETMASK
, ifr
) != 0) {
314 nmask
= ((struct sockaddr_in
*)&ifr
->ifr_addr
)->sin_addr
;
316 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
317 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
318 ifaces
[total
].ip
= ipaddr
;
319 ifaces
[total
].netmask
= nmask
;
325 * Patch from Archie Cobbs (archie@whistle.com). The
326 * addresses in the SIOCGIFCONF interface list have a
327 * minimum size. Usually this doesn't matter, but if
328 * your machine has tunnel interfaces, etc. that have
329 * a zero length "link address", this does matter. */
331 if (inc
< sizeof(ifr
->ifr_addr
))
332 inc
= sizeof(ifr
->ifr_addr
);
335 ifr
= (struct ifreq
*) (((char*) ifr
) + inc
);
344 #define _FOUND_IFACE_ANY
345 #endif /* HAVE_IFACE_AIX */
346 #ifndef _FOUND_IFACE_ANY
347 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
354 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
357 r
= strcmp(i1
->name
, i2
->name
);
359 r
= ntohl(i1
->ip
.s_addr
) - ntohl(i2
->ip
.s_addr
);
361 r
= ntohl(i1
->netmask
.s_addr
) - ntohl(i2
->netmask
.s_addr
);
365 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
);
366 /* this wrapper is used to remove duplicates from the interface list generated
368 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
372 total
= _get_interfaces(ifaces
, max_interfaces
);
373 if (total
<= 0) return total
;
375 /* now we need to remove duplicates */
376 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
379 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
380 for (j
=i
-1;j
<total
-1;j
++) {
381 ifaces
[j
] = ifaces
[j
+1];
394 /* this is the autoconf driver to test get_interfaces() */
398 struct iface_struct ifaces
[MAX_INTERFACES
];
399 int total
= get_interfaces(ifaces
, MAX_INTERFACES
);
402 printf("got %d interfaces:\n", total
);
403 if (total
<= 0) exit(1);
405 for (i
=0;i
<total
;i
++) {
406 printf("%-10s ", ifaces
[i
].name
);
407 printf("IP=%s ", inet_ntoa(ifaces
[i
].ip
));
408 printf("NETMASK=%s\n", inet_ntoa(ifaces
[i
].netmask
));