make sure to include config.h so that the #ifdef tests work
[Samba.git] / source / lib / interfaces.c
blobabe8bbb6c701cd756cd5128af62dc75c5da38350
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.0
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.
34 #include "config.h"
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #include <sys/ioctl.h>
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47 #include <net/if.h>
49 #ifndef SIOCGIFCONF
50 #ifdef HAVE_SYS_SOCKIO_H
51 #include <sys/sockio.h>
52 #endif
53 #endif
55 #ifdef AUTOCONF_TEST
56 struct iface_struct {
57 char name[16];
58 struct in_addr ip;
59 struct in_addr netmask;
61 #else
62 #include "config.h"
63 #include "interfaces.h"
64 #endif
66 #ifdef HAVE_STDLIB_H
67 #include <stdlib.h>
68 #endif
70 #ifdef HAVE_STRING_H
71 #include <string.h>
72 #endif
74 #ifdef HAVE_STRINGS_H
75 #include <strings.h>
76 #endif
78 #ifdef __COMPAR_FN_T
79 #define QSORT_CAST (__compar_fn_t)
80 #endif
82 #ifndef QSORT_CAST
83 #define QSORT_CAST (int (*)(const void *, const void *))
84 #endif
86 #if HAVE_IFACE_IFCONF
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)
98 struct ifconf ifc;
99 char buff[8192];
100 int fd, i, n;
101 struct ifreq *ifr=NULL;
102 int total = 0;
103 struct in_addr ipaddr;
104 struct in_addr nmask;
105 char *iname;
107 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
108 return -1;
111 ifc.ifc_len = sizeof(buff);
112 ifc.ifc_buf = buff;
114 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
115 close(fd);
116 return -1;
119 ifr = ifc.ifc_req;
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) {
126 continue;
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) {
133 continue;
136 if (!(ifr[i].ifr_flags & IFF_UP)) {
137 continue;
140 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
141 continue;
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;
150 total++;
153 close(fd);
155 return total;
158 #elif HAVE_IFACE_IFREQ
160 #ifndef I_STR
161 #include <sys/stropts.h>
162 #endif
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)
170 struct ifreq ifreq;
171 struct strioctl strioctl;
172 char buff[8192];
173 int fd, i, n;
174 struct ifreq *ifr=NULL;
175 int total = 0;
176 struct in_addr ipaddr;
177 struct in_addr nmask;
178 char *iname;
180 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
181 return -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) {
188 close(fd);
189 return -1;
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));
201 } else {
202 ifr = (struct ifreq *)buff;
205 /* Loop through interfaces */
207 for (i = 0; i<n && total < max_interfaces; i++) {
208 ifreq = ifr[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) {
214 continue;
217 if (!(ifreq.ifr_flags & IFF_UP)) {
218 continue;
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) {
225 continue;
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) {
235 continue;
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;
245 total++;
248 close(fd);
250 return total;
253 #elif HAVE_IFACE_AIX
255 /****************************************************************************
256 this one is for AIX (tested on 4.2)
257 ****************************************************************************/
258 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
260 char buff[8192];
261 int fd, i;
262 struct ifconf ifc;
263 struct ifreq *ifr=NULL;
264 struct in_addr ipaddr;
265 struct in_addr nmask;
266 char *iname;
267 int total = 0;
269 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
270 return -1;
274 ifc.ifc_len = sizeof(buff);
275 ifc.ifc_buf = buff;
277 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
278 close(fd);
279 return -1;
282 ifr = ifc.ifc_req;
284 /* Loop through interfaces */
285 i = ifc.ifc_len;
287 while (i > 0 && total < max_interfaces) {
288 unsigned inc;
290 inc = ifr->ifr_addr.sa_len;
292 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
293 goto next;
296 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
297 iname = ifr->ifr_name;
299 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
300 goto next;
303 if (!(ifr->ifr_flags & IFF_UP)) {
304 goto next;
307 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
308 goto next;
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;
318 total++;
320 next:
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);
330 inc += IFNAMSIZ;
332 ifr = (struct ifreq*) (((char*) ifr) + inc);
333 i -= inc;
337 close(fd);
338 return total;
341 #else /* a dummy version */
342 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
344 return -1;
346 #endif
349 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
351 int r;
352 r = strcmp(i1->name, i2->name);
353 if (r) return r;
354 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
355 if (r) return r;
356 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
357 return r;
360 /* this wrapper is used to remove duplicates from the interface list generated
361 above */
362 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
364 int total, i, j;
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);
372 for (i=1;i<total;) {
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];
377 total--;
378 } else {
379 i++;
383 return total;
387 #ifdef AUTOCONF_TEST
388 /* this is the autoconf driver to test get_interfaces() */
390 #define MAX_INTERFACES 128
392 int main()
394 struct iface_struct ifaces[MAX_INTERFACES];
395 int total = get_interfaces(ifaces, MAX_INTERFACES);
396 int i;
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));
406 return 0;
408 #endif