2 Unix SMB/Netbios implementation.
4 return a list of network interfaces
5 Copyright (C) Andrew Tridgell 1998
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* working out the interfaces for a OS is an incredibly non-portable
24 thing. We have several possible implementations below, and autoconf
25 tries each of them to see what works
27 Note that this file does _not_ include includes.h. That is so this code
28 can be called directly from the autoconf tests. That also means
29 this code cannot use any of the normal Samba debug stuff or defines.
30 This is standalone code.
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
43 #include <sys/ioctl.h>
44 #ifdef HAVE_SYS_TIME_H
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
59 struct in_addr netmask
;
63 #include "interfaces.h"
79 #define QSORT_CAST (__compar_fn_t)
83 #define QSORT_CAST (int (*)(const void *, const void *))
88 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
89 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
91 It probably also works on any BSD style system. */
93 /****************************************************************************
94 get the netmask address for a local interface
95 ****************************************************************************/
96 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
101 struct ifreq
*ifr
=NULL
;
103 struct in_addr ipaddr
;
104 struct in_addr nmask
;
107 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
111 ifc
.ifc_len
= sizeof(buff
);
114 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
121 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
123 /* Loop through interfaces, looking for given IP address */
124 for (i
=n
-1;i
>=0 && total
< max_interfaces
;i
--) {
125 if (ioctl(fd
, SIOCGIFADDR
, &ifr
[i
]) != 0) {
129 iname
= ifr
[i
].ifr_name
;
130 ipaddr
= (*(struct sockaddr_in
*)&ifr
[i
].ifr_addr
).sin_addr
;
132 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
[i
]) != 0) {
136 if (!(ifr
[i
].ifr_flags
& IFF_UP
)) {
140 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
[i
]) != 0) {
144 nmask
= ((struct sockaddr_in
*)&ifr
[i
].ifr_addr
)->sin_addr
;
146 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
147 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
148 ifaces
[total
].ip
= ipaddr
;
149 ifaces
[total
].netmask
= nmask
;
158 #elif HAVE_IFACE_IFREQ
161 #include <sys/stropts.h>
164 /****************************************************************************
165 this should cover most of the streams based systems
166 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
167 ****************************************************************************/
168 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
171 struct strioctl strioctl
;
174 struct ifreq
*ifr
=NULL
;
176 struct in_addr ipaddr
;
177 struct in_addr nmask
;
180 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
184 strioctl
.ic_cmd
= SIOCGIFCONF
;
185 strioctl
.ic_dp
= buff
;
186 strioctl
.ic_len
= sizeof(buff
);
187 if (ioctl(fd
, I_STR
, &strioctl
) < 0) {
192 /* we can ignore the possible sizeof(int) here as the resulting
193 number of interface structures won't change */
194 n
= strioctl
.ic_len
/ sizeof(struct ifreq
);
196 /* we will assume that the kernel returns the length as an int
197 at the start of the buffer if the offered size is a
198 multiple of the structure size plus an int */
199 if (n
*sizeof(struct ifreq
) + sizeof(int) == strioctl
.ic_len
) {
200 ifr
= (struct ifreq
*)(buff
+ sizeof(int));
202 ifr
= (struct ifreq
*)buff
;
205 /* Loop through interfaces */
207 for (i
= 0; i
<n
&& total
< max_interfaces
; i
++) {
210 strioctl
.ic_cmd
= SIOCGIFFLAGS
;
211 strioctl
.ic_dp
= (char *)&ifreq
;
212 strioctl
.ic_len
= sizeof(struct ifreq
);
213 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
217 if (!(ifreq
.ifr_flags
& IFF_UP
)) {
221 strioctl
.ic_cmd
= SIOCGIFADDR
;
222 strioctl
.ic_dp
= (char *)&ifreq
;
223 strioctl
.ic_len
= sizeof(struct ifreq
);
224 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
228 ipaddr
= (*(struct sockaddr_in
*) &ifreq
.ifr_addr
).sin_addr
;
229 iname
= ifreq
.ifr_name
;
231 strioctl
.ic_cmd
= SIOCGIFNETMASK
;
232 strioctl
.ic_dp
= (char *)&ifreq
;
233 strioctl
.ic_len
= sizeof(struct ifreq
);
234 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
238 nmask
= ((struct sockaddr_in
*)&ifreq
.ifr_addr
)->sin_addr
;
240 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
241 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
242 ifaces
[total
].ip
= ipaddr
;
243 ifaces
[total
].netmask
= nmask
;
255 /****************************************************************************
256 this one is for AIX (tested on 4.2)
257 ****************************************************************************/
258 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
263 struct ifreq
*ifr
=NULL
;
264 struct in_addr ipaddr
;
265 struct in_addr nmask
;
269 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
274 ifc
.ifc_len
= sizeof(buff
);
277 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
284 /* Loop through interfaces */
287 while (i
> 0 && total
< max_interfaces
) {
290 inc
= ifr
->ifr_addr
.sa_len
;
292 if (ioctl(fd
, SIOCGIFADDR
, ifr
) != 0) {
296 ipaddr
= (*(struct sockaddr_in
*) &ifr
->ifr_addr
).sin_addr
;
297 iname
= ifr
->ifr_name
;
299 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) != 0) {
303 if (!(ifr
->ifr_flags
& IFF_UP
)) {
307 if (ioctl(fd
, SIOCGIFNETMASK
, ifr
) != 0) {
311 nmask
= ((struct sockaddr_in
*)&ifr
->ifr_addr
)->sin_addr
;
313 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
314 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
315 ifaces
[total
].ip
= ipaddr
;
316 ifaces
[total
].netmask
= nmask
;
322 * Patch from Archie Cobbs (archie@whistle.com). The
323 * addresses in the SIOCGIFCONF interface list have a
324 * minimum size. Usually this doesn't matter, but if
325 * your machine has tunnel interfaces, etc. that have
326 * a zero length "link address", this does matter. */
328 if (inc
< sizeof(ifr
->ifr_addr
))
329 inc
= sizeof(ifr
->ifr_addr
);
332 ifr
= (struct ifreq
*) (((char*) ifr
) + inc
);
341 #else /* a dummy version */
342 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
349 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
352 r
= strcmp(i1
->name
, i2
->name
);
354 r
= ntohl(i1
->ip
.s_addr
) - ntohl(i2
->ip
.s_addr
);
356 r
= ntohl(i1
->netmask
.s_addr
) - ntohl(i2
->netmask
.s_addr
);
360 /* this wrapper is used to remove duplicates from the interface list generated
362 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
366 total
= _get_interfaces(ifaces
, max_interfaces
);
367 if (total
<= 0) return total
;
369 /* now we need to remove duplicates */
370 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
373 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
374 for (j
=i
-1;j
<total
-1;j
++) {
375 ifaces
[j
] = ifaces
[j
+1];
388 /* this is the autoconf driver to test get_interfaces() */
390 #define MAX_INTERFACES 128
394 struct iface_struct ifaces
[MAX_INTERFACES
];
395 int total
= get_interfaces(ifaces
, MAX_INTERFACES
);
398 printf("got %d interfaces:\n", total
);
399 if (total
<= 0) exit(1);
401 for (i
=0;i
<total
;i
++) {
402 printf("%-10s ", ifaces
[i
].name
);
403 printf("IP=%s ", inet_ntoa(ifaces
[i
].ip
));
404 printf("NETMASK=%s\n", inet_ntoa(ifaces
[i
].netmask
));