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.
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #include <sys/ioctl.h>
43 #ifdef HAVE_SYS_TIME_H
49 #include <sys/sockio.h>
56 struct in_addr netmask
;
60 #include "interfaces.h"
76 #define QSORT_CAST (__compar_fn_t)
80 #define QSORT_CAST (int (*)(const void *, const void *))
85 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
86 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
88 It probably also works on any BSD style system. */
90 /****************************************************************************
91 get the netmask address for a local interface
92 ****************************************************************************/
93 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
98 struct ifreq
*ifr
=NULL
;
100 struct in_addr ipaddr
;
101 struct in_addr nmask
;
104 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
108 ifc
.ifc_len
= sizeof(buff
);
111 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
118 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
120 /* Loop through interfaces, looking for given IP address */
121 for (i
=n
-1;i
>=0 && total
< max_interfaces
;i
--) {
122 if (ioctl(fd
, SIOCGIFADDR
, &ifr
[i
]) != 0) {
126 iname
= ifr
[i
].ifr_name
;
127 ipaddr
= (*(struct sockaddr_in
*)&ifr
[i
].ifr_addr
).sin_addr
;
129 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
[i
]) != 0) {
133 if (!(ifr
[i
].ifr_flags
& IFF_UP
)) {
137 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
[i
]) != 0) {
141 nmask
= ((struct sockaddr_in
*)&ifr
[i
].ifr_addr
)->sin_addr
;
143 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
144 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
145 ifaces
[total
].ip
= ipaddr
;
146 ifaces
[total
].netmask
= nmask
;
155 #elif HAVE_IFACE_IFREQ
158 #include <sys/stropts.h>
161 /****************************************************************************
162 this should cover most of the streams based systems
163 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
164 ****************************************************************************/
165 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
168 struct strioctl strioctl
;
171 struct ifreq
*ifr
=NULL
;
173 struct in_addr ipaddr
;
174 struct in_addr nmask
;
177 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
181 strioctl
.ic_cmd
= SIOCGIFCONF
;
182 strioctl
.ic_dp
= buff
;
183 strioctl
.ic_len
= sizeof(buff
);
184 if (ioctl(fd
, I_STR
, &strioctl
) < 0) {
189 /* we can ignore the possible sizeof(int) here as the resulting
190 number of interface structures won't change */
191 n
= strioctl
.ic_len
/ sizeof(struct ifreq
);
193 /* we will assume that the kernel returns the length as an int
194 at the start of the buffer if the offered size is a
195 multiple of the structure size plus an int */
196 if (n
*sizeof(struct ifreq
) + sizeof(int) == strioctl
.ic_len
) {
197 ifr
= (struct ifreq
*)(buff
+ sizeof(int));
199 ifr
= (struct ifreq
*)buff
;
202 /* Loop through interfaces */
204 for (i
= 0; i
<n
&& total
< max_interfaces
; i
++) {
207 strioctl
.ic_cmd
= SIOCGIFFLAGS
;
208 strioctl
.ic_dp
= (char *)&ifreq
;
209 strioctl
.ic_len
= sizeof(struct ifreq
);
210 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
214 if (!(ifreq
.ifr_flags
& IFF_UP
)) {
218 strioctl
.ic_cmd
= SIOCGIFADDR
;
219 strioctl
.ic_dp
= (char *)&ifreq
;
220 strioctl
.ic_len
= sizeof(struct ifreq
);
221 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
225 ipaddr
= (*(struct sockaddr_in
*) &ifreq
.ifr_addr
).sin_addr
;
226 iname
= ifreq
.ifr_name
;
228 strioctl
.ic_cmd
= SIOCGIFNETMASK
;
229 strioctl
.ic_dp
= (char *)&ifreq
;
230 strioctl
.ic_len
= sizeof(struct ifreq
);
231 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
235 nmask
= ((struct sockaddr_in
*)&ifreq
.ifr_addr
)->sin_addr
;
237 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
238 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
239 ifaces
[total
].ip
= ipaddr
;
240 ifaces
[total
].netmask
= nmask
;
252 /****************************************************************************
253 this one is for AIX (tested on 4.2)
254 ****************************************************************************/
255 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
260 struct ifreq
*ifr
=NULL
;
261 struct in_addr ipaddr
;
262 struct in_addr nmask
;
266 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
271 ifc
.ifc_len
= sizeof(buff
);
274 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
281 /* Loop through interfaces */
284 while (i
> 0 && total
< max_interfaces
) {
287 inc
= ifr
->ifr_addr
.sa_len
;
289 if (ioctl(fd
, SIOCGIFADDR
, ifr
) != 0) {
293 ipaddr
= (*(struct sockaddr_in
*) &ifr
->ifr_addr
).sin_addr
;
294 iname
= ifr
->ifr_name
;
296 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) != 0) {
300 if (!(ifr
->ifr_flags
& IFF_UP
)) {
304 if (ioctl(fd
, SIOCGIFNETMASK
, ifr
) != 0) {
308 nmask
= ((struct sockaddr_in
*)&ifr
->ifr_addr
)->sin_addr
;
310 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
311 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
312 ifaces
[total
].ip
= ipaddr
;
313 ifaces
[total
].netmask
= nmask
;
319 * Patch from Archie Cobbs (archie@whistle.com). The
320 * addresses in the SIOCGIFCONF interface list have a
321 * minimum size. Usually this doesn't matter, but if
322 * your machine has tunnel interfaces, etc. that have
323 * a zero length "link address", this does matter. */
325 if (inc
< sizeof(ifr
->ifr_addr
))
326 inc
= sizeof(ifr
->ifr_addr
);
329 ifr
= (struct ifreq
*) (((char*) ifr
) + inc
);
338 #else /* a dummy version */
339 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
346 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
349 r
= strcmp(i1
->name
, i2
->name
);
351 r
= ntohl(i1
->ip
.s_addr
) - ntohl(i2
->ip
.s_addr
);
353 r
= ntohl(i1
->netmask
.s_addr
) - ntohl(i2
->netmask
.s_addr
);
357 /* this wrapper is used to remove duplicates from the interface list generated
359 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
363 total
= _get_interfaces(ifaces
, max_interfaces
);
364 if (total
<= 0) return total
;
366 /* now we need to remove duplicates */
367 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
370 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
371 for (j
=i
-1;j
<total
-1;j
++) {
372 ifaces
[j
] = ifaces
[j
+1];
385 /* this is the autoconf driver to test get_interfaces() */
387 #define MAX_INTERFACES 128
391 struct iface_struct ifaces
[MAX_INTERFACES
];
392 int total
= get_interfaces(ifaces
, MAX_INTERFACES
);
395 printf("got %d interfaces:\n", total
);
396 if (total
<= 0) exit(1);
398 for (i
=0;i
<total
;i
++) {
399 printf("%-10s ", ifaces
[i
].name
);
400 printf("IP=%s ", inet_ntoa(ifaces
[i
].ip
));
401 printf("NETMASK=%s\n", inet_ntoa(ifaces
[i
].netmask
));