back out part of Paul's POSIX-96 patch to fix compile.
[Samba.git] / source / lib / interfaces.c
blobccef8a9781acc0a2b257f1d1939dd034028d985f
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.
35 #include <unistd.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <sys/ioctl.h>
43 #ifdef HAVE_SYS_TIME_H
44 #include <sys/time.h>
45 #endif
46 #include <net/if.h>
48 #ifndef SIOCGIFCONF
49 #include <sys/sockio.h>
50 #endif
52 #ifdef AUTOCONF_TEST
53 struct iface_struct {
54 char name[16];
55 struct in_addr ip;
56 struct in_addr netmask;
58 #else
59 #include "config.h"
60 #include "interfaces.h"
61 #endif
63 #ifdef HAVE_STDLIB_H
64 #include <stdlib.h>
65 #endif
67 #ifdef HAVE_STRING_H
68 #include <string.h>
69 #endif
71 #ifdef HAVE_STRINGS_H
72 #include <strings.h>
73 #endif
75 #ifdef __COMPAR_FN_T
76 #define QSORT_CAST (__compar_fn_t)
77 #endif
79 #ifndef QSORT_CAST
80 #define QSORT_CAST (int (*)(const void *, const void *))
81 #endif
83 #if HAVE_IFACE_IFCONF
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)
95 struct ifconf ifc;
96 char buff[8192];
97 int fd, i, n;
98 struct ifreq *ifr=NULL;
99 int total = 0;
100 struct in_addr ipaddr;
101 struct in_addr nmask;
102 char *iname;
104 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
105 return -1;
108 ifc.ifc_len = sizeof(buff);
109 ifc.ifc_buf = buff;
111 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
112 close(fd);
113 return -1;
116 ifr = ifc.ifc_req;
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) {
123 continue;
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) {
130 continue;
133 if (!(ifr[i].ifr_flags & IFF_UP)) {
134 continue;
137 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
138 continue;
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;
147 total++;
150 close(fd);
152 return total;
155 #elif HAVE_IFACE_IFREQ
157 #ifndef I_STR
158 #include <sys/stropts.h>
159 #endif
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)
167 struct ifreq ifreq;
168 struct strioctl strioctl;
169 char buff[8192];
170 int fd, i, n;
171 struct ifreq *ifr=NULL;
172 int total = 0;
173 struct in_addr ipaddr;
174 struct in_addr nmask;
175 char *iname;
177 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
178 return -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) {
185 close(fd);
186 return -1;
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));
198 } else {
199 ifr = (struct ifreq *)buff;
202 /* Loop through interfaces */
204 for (i = 0; i<n && total < max_interfaces; i++) {
205 ifreq = ifr[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) {
211 continue;
214 if (!(ifreq.ifr_flags & IFF_UP)) {
215 continue;
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) {
222 continue;
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) {
232 continue;
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;
242 total++;
245 close(fd);
247 return total;
250 #elif HAVE_IFACE_AIX
252 /****************************************************************************
253 this one is for AIX (tested on 4.2)
254 ****************************************************************************/
255 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
257 char buff[8192];
258 int fd, i;
259 struct ifconf ifc;
260 struct ifreq *ifr=NULL;
261 struct in_addr ipaddr;
262 struct in_addr nmask;
263 char *iname;
264 int total = 0;
266 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
267 return -1;
271 ifc.ifc_len = sizeof(buff);
272 ifc.ifc_buf = buff;
274 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
275 close(fd);
276 return -1;
279 ifr = ifc.ifc_req;
281 /* Loop through interfaces */
282 i = ifc.ifc_len;
284 while (i > 0 && total < max_interfaces) {
285 unsigned inc;
287 inc = ifr->ifr_addr.sa_len;
289 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290 goto next;
293 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
294 iname = ifr->ifr_name;
296 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
297 goto next;
300 if (!(ifr->ifr_flags & IFF_UP)) {
301 goto next;
304 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
305 goto next;
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;
315 total++;
317 next:
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);
327 inc += IFNAMSIZ;
329 ifr = (struct ifreq*) (((char*) ifr) + inc);
330 i -= inc;
334 close(fd);
335 return total;
338 #else /* a dummy version */
339 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
341 return -1;
343 #endif
346 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
348 int r;
349 r = strcmp(i1->name, i2->name);
350 if (r) return r;
351 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
352 if (r) return r;
353 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
354 return r;
357 /* this wrapper is used to remove duplicates from the interface list generated
358 above */
359 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
361 int total, i, j;
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);
369 for (i=1;i<total;) {
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];
374 total--;
375 } else {
376 i++;
380 return total;
384 #ifdef AUTOCONF_TEST
385 /* this is the autoconf driver to test get_interfaces() */
387 #define MAX_INTERFACES 128
389 int main()
391 struct iface_struct ifaces[MAX_INTERFACES];
392 int total = get_interfaces(ifaces, MAX_INTERFACES);
393 int i;
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));
403 return 0;
405 #endif