preparing for release of alpha.1.1
[Samba.git] / source / lib / interfaces.c
blobe7b9efa1f0adad49584325c1f64c43c1da723035
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 <unistd.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <netdb.h>
41 #include <sys/ioctl.h>
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 #include <net/if.h>
47 #ifndef SIOCGIFCONF
48 #include <sys/sockio.h>
49 #endif
51 #ifdef AUTOCONF_TEST
52 struct iface_struct {
53 char name[16];
54 struct in_addr ip;
55 struct in_addr netmask;
57 #else
58 #include "config.h"
59 #include "interfaces.h"
60 #endif
62 #ifdef HAVE_STDLIB_H
63 #include <stdlib.h>
64 #endif
66 #ifdef HAVE_STRING_H
67 #include <string.h>
68 #endif
70 #ifdef HAVE_STRINGS_H
71 #include <strings.h>
72 #endif
74 #ifdef __COMPAR_FN_T
75 #define QSORT_CAST (__compar_fn_t)
76 #endif
78 #ifndef QSORT_CAST
79 #define QSORT_CAST (int (*)(const void *, const void *))
80 #endif
82 #if HAVE_IFACE_IFCONF
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)
94 struct ifconf ifc;
95 char buff[8192];
96 int fd, i, n;
97 struct ifreq *ifr=NULL;
98 int total = 0;
99 struct in_addr ipaddr;
100 struct in_addr nmask;
101 char *iname;
103 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
104 return -1;
107 ifc.ifc_len = sizeof(buff);
108 ifc.ifc_buf = buff;
110 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
111 close(fd);
112 return -1;
115 ifr = ifc.ifc_req;
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) {
122 continue;
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) {
129 continue;
132 if (!(ifr[i].ifr_flags & IFF_UP)) {
133 continue;
136 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
137 continue;
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;
146 total++;
149 close(fd);
151 return total;
154 #elif HAVE_IFACE_IFREQ
156 #ifndef I_STR
157 #include <sys/stropts.h>
158 #endif
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)
166 struct ifreq ifreq;
167 struct strioctl strioctl;
168 char buff[8192];
169 int fd, i, n;
170 struct ifreq *ifr=NULL;
171 int total = 0;
172 struct in_addr ipaddr;
173 struct in_addr nmask;
174 char *iname;
176 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
177 return -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) {
184 close(fd);
185 return -1;
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));
197 } else {
198 ifr = (struct ifreq *)buff;
201 /* Loop through interfaces */
203 for (i = 0; i<n && total < max_interfaces; i++) {
204 ifreq = ifr[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) {
210 continue;
213 if (!(ifreq.ifr_flags & IFF_UP)) {
214 continue;
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) {
221 continue;
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) {
231 continue;
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;
241 total++;
244 close(fd);
246 return total;
249 #elif HAVE_IFACE_AIX
251 /****************************************************************************
252 this one is for AIX (tested on 4.2)
253 ****************************************************************************/
254 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
256 char buff[8192];
257 int fd, i;
258 struct ifconf ifc;
259 struct ifreq *ifr=NULL;
260 struct in_addr ipaddr;
261 struct in_addr nmask;
262 char *iname;
263 int total = 0;
265 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
266 return -1;
270 ifc.ifc_len = sizeof(buff);
271 ifc.ifc_buf = buff;
273 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
274 close(fd);
275 return -1;
278 ifr = ifc.ifc_req;
280 /* Loop through interfaces */
281 i = ifc.ifc_len;
283 while (i > 0 && total < max_interfaces) {
284 unsigned inc;
286 inc = ifr->ifr_addr.sa_len;
288 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
289 goto next;
292 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
293 iname = ifr->ifr_name;
295 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
296 goto next;
299 if (!(ifr->ifr_flags & IFF_UP)) {
300 goto next;
303 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
304 goto next;
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;
314 total++;
316 next:
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);
326 inc += IFNAMSIZ;
328 ifr = (struct ifreq*) (((char*) ifr) + inc);
329 i -= inc;
333 close(fd);
334 return total;
337 #else /* a dummy version */
338 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
340 return -1;
342 #endif
345 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
347 int r;
348 r = strcmp(i1->name, i2->name);
349 if (r) return r;
350 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
351 if (r) return r;
352 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
353 return r;
356 /* this wrapper is used to remove duplicates from the interface list generated
357 above */
358 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
360 int total, i, j;
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);
368 for (i=1;i<total;) {
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];
373 total--;
374 } else {
375 i++;
379 return total;
383 #ifdef AUTOCONF_TEST
384 /* this is the autoconf driver to test get_interfaces() */
386 #define MAX_INTERFACES 128
388 int main()
390 struct iface_struct ifaces[MAX_INTERFACES];
391 int total = get_interfaces(ifaces, MAX_INTERFACES);
392 int i;
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));
402 return 0;
404 #endif