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.
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
41 #include <sys/ioctl.h>
42 #ifdef HAVE_SYS_TIME_H
48 #include <sys/sockio.h>
55 struct in_addr netmask
;
59 #include "interfaces.h"
75 #define QSORT_CAST (__compar_fn_t)
79 #define QSORT_CAST (int (*)(const void *, const void *))
84 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
85 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
87 It probably also works on any BSD style system. */
89 /****************************************************************************
90 get the netmask address for a local interface
91 ****************************************************************************/
92 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
97 struct ifreq
*ifr
=NULL
;
99 struct in_addr ipaddr
;
100 struct in_addr nmask
;
103 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
107 ifc
.ifc_len
= sizeof(buff
);
110 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
117 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
119 /* Loop through interfaces, looking for given IP address */
120 for (i
=n
-1;i
>=0 && total
< max_interfaces
;i
--) {
121 if (ioctl(fd
, SIOCGIFADDR
, &ifr
[i
]) != 0) {
125 iname
= ifr
[i
].ifr_name
;
126 ipaddr
= (*(struct sockaddr_in
*)&ifr
[i
].ifr_addr
).sin_addr
;
128 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
[i
]) != 0) {
132 if (!(ifr
[i
].ifr_flags
& IFF_UP
)) {
136 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
[i
]) != 0) {
140 nmask
= ((struct sockaddr_in
*)&ifr
[i
].ifr_addr
)->sin_addr
;
142 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
143 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
144 ifaces
[total
].ip
= ipaddr
;
145 ifaces
[total
].netmask
= nmask
;
154 #elif HAVE_IFACE_IFREQ
157 #include <sys/stropts.h>
160 /****************************************************************************
161 this should cover most of the streams based systems
162 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
163 ****************************************************************************/
164 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
167 struct strioctl strioctl
;
170 struct ifreq
*ifr
=NULL
;
172 struct in_addr ipaddr
;
173 struct in_addr nmask
;
176 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
180 strioctl
.ic_cmd
= SIOCGIFCONF
;
181 strioctl
.ic_dp
= buff
;
182 strioctl
.ic_len
= sizeof(buff
);
183 if (ioctl(fd
, I_STR
, &strioctl
) < 0) {
188 /* we can ignore the possible sizeof(int) here as the resulting
189 number of interface structures won't change */
190 n
= strioctl
.ic_len
/ sizeof(struct ifreq
);
192 /* we will assume that the kernel returns the length as an int
193 at the start of the buffer if the offered size is a
194 multiple of the structure size plus an int */
195 if (n
*sizeof(struct ifreq
) + sizeof(int) == strioctl
.ic_len
) {
196 ifr
= (struct ifreq
*)(buff
+ sizeof(int));
198 ifr
= (struct ifreq
*)buff
;
201 /* Loop through interfaces */
203 for (i
= 0; i
<n
&& total
< max_interfaces
; i
++) {
206 strioctl
.ic_cmd
= SIOCGIFFLAGS
;
207 strioctl
.ic_dp
= (char *)&ifreq
;
208 strioctl
.ic_len
= sizeof(struct ifreq
);
209 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
213 if (!(ifreq
.ifr_flags
& IFF_UP
)) {
217 strioctl
.ic_cmd
= SIOCGIFADDR
;
218 strioctl
.ic_dp
= (char *)&ifreq
;
219 strioctl
.ic_len
= sizeof(struct ifreq
);
220 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
224 ipaddr
= (*(struct sockaddr_in
*) &ifreq
.ifr_addr
).sin_addr
;
225 iname
= ifreq
.ifr_name
;
227 strioctl
.ic_cmd
= SIOCGIFNETMASK
;
228 strioctl
.ic_dp
= (char *)&ifreq
;
229 strioctl
.ic_len
= sizeof(struct ifreq
);
230 if (ioctl(fd
, I_STR
, &strioctl
) != 0) {
234 nmask
= ((struct sockaddr_in
*)&ifreq
.ifr_addr
)->sin_addr
;
236 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
237 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
238 ifaces
[total
].ip
= ipaddr
;
239 ifaces
[total
].netmask
= nmask
;
251 /****************************************************************************
252 this one is for AIX (tested on 4.2)
253 ****************************************************************************/
254 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
259 struct ifreq
*ifr
=NULL
;
260 struct in_addr ipaddr
;
261 struct in_addr nmask
;
265 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
270 ifc
.ifc_len
= sizeof(buff
);
273 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) != 0) {
280 /* Loop through interfaces */
283 while (i
> 0 && total
< max_interfaces
) {
286 inc
= ifr
->ifr_addr
.sa_len
;
288 if (ioctl(fd
, SIOCGIFADDR
, ifr
) != 0) {
292 ipaddr
= (*(struct sockaddr_in
*) &ifr
->ifr_addr
).sin_addr
;
293 iname
= ifr
->ifr_name
;
295 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) != 0) {
299 if (!(ifr
->ifr_flags
& IFF_UP
)) {
303 if (ioctl(fd
, SIOCGIFNETMASK
, ifr
) != 0) {
307 nmask
= ((struct sockaddr_in
*)&ifr
->ifr_addr
)->sin_addr
;
309 strncpy(ifaces
[total
].name
, iname
, sizeof(ifaces
[total
].name
)-1);
310 ifaces
[total
].name
[sizeof(ifaces
[total
].name
)-1] = 0;
311 ifaces
[total
].ip
= ipaddr
;
312 ifaces
[total
].netmask
= nmask
;
318 * Patch from Archie Cobbs (archie@whistle.com). The
319 * addresses in the SIOCGIFCONF interface list have a
320 * minimum size. Usually this doesn't matter, but if
321 * your machine has tunnel interfaces, etc. that have
322 * a zero length "link address", this does matter. */
324 if (inc
< sizeof(ifr
->ifr_addr
))
325 inc
= sizeof(ifr
->ifr_addr
);
328 ifr
= (struct ifreq
*) (((char*) ifr
) + inc
);
337 #else /* a dummy version */
338 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
345 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
348 r
= strcmp(i1
->name
, i2
->name
);
350 r
= ntohl(i1
->ip
.s_addr
) - ntohl(i2
->ip
.s_addr
);
352 r
= ntohl(i1
->netmask
.s_addr
) - ntohl(i2
->netmask
.s_addr
);
356 /* this wrapper is used to remove duplicates from the interface list generated
358 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
362 total
= _get_interfaces(ifaces
, max_interfaces
);
363 if (total
<= 0) return total
;
365 /* now we need to remove duplicates */
366 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
369 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
370 for (j
=i
-1;j
<total
-1;j
++) {
371 ifaces
[j
] = ifaces
[j
+1];
384 /* this is the autoconf driver to test get_interfaces() */
386 #define MAX_INTERFACES 128
390 struct iface_struct ifaces
[MAX_INTERFACES
];
391 int total
= get_interfaces(ifaces
, MAX_INTERFACES
);
394 printf("got %d interfaces:\n", total
);
395 if (total
<= 0) exit(1);
397 for (i
=0;i
<total
;i
++) {
398 printf("%-10s ", ifaces
[i
].name
);
399 printf("IP=%s ", inet_ntoa(ifaces
[i
].ip
));
400 printf("NETMASK=%s\n", inet_ntoa(ifaces
[i
].netmask
));