if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / lib / interfaces.c
blob9e8c979aa7bc28d6794e454f18f4ef26c7591436
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 #include <net/if.h>
44 #ifdef AUTOCONF_TEST
45 struct iface_struct {
46 char name[16];
47 struct in_addr ip;
48 struct in_addr netmask;
50 #else
51 #include "config.h"
52 #include "interfaces.h"
53 #endif
55 #ifdef HAVE_SYS_TIME_H
56 #include <sys/time.h>
57 #endif
59 #ifndef SIOCGIFCONF
60 #ifdef HAVE_SYS_SOCKIO_H
61 #include <sys/sockio.h>
62 #endif
63 #endif
65 #ifdef HAVE_STDLIB_H
66 #include <stdlib.h>
67 #endif
69 #ifdef HAVE_STRING_H
70 #include <string.h>
71 #endif
73 #ifdef HAVE_STRINGS_H
74 #include <strings.h>
75 #endif
77 #ifdef __COMPAR_FN_T
78 #define QSORT_CAST (__compar_fn_t)
79 #endif
81 #ifndef QSORT_CAST
82 #define QSORT_CAST (int (*)(const void *, const void *))
83 #endif
85 #if HAVE_IFACE_IFCONF
87 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
88 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
90 It probably also works on any BSD style system. */
92 /****************************************************************************
93 get the netmask address for a local interface
94 ****************************************************************************/
95 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
97 struct ifconf ifc;
98 char buff[8192];
99 int fd, i, n;
100 struct ifreq *ifr=NULL;
101 int total = 0;
102 struct in_addr ipaddr;
103 struct in_addr nmask;
104 char *iname;
106 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
107 return -1;
110 ifc.ifc_len = sizeof(buff);
111 ifc.ifc_buf = buff;
113 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
114 close(fd);
115 return -1;
118 ifr = ifc.ifc_req;
120 n = ifc.ifc_len / sizeof(struct ifreq);
122 /* Loop through interfaces, looking for given IP address */
123 for (i=n-1;i>=0 && total < max_interfaces;i--) {
124 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
125 continue;
128 iname = ifr[i].ifr_name;
129 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
131 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
132 continue;
135 if (!(ifr[i].ifr_flags & IFF_UP)) {
136 continue;
139 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
140 continue;
143 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
145 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
146 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
147 ifaces[total].ip = ipaddr;
148 ifaces[total].netmask = nmask;
149 total++;
152 close(fd);
154 return total;
157 #elif HAVE_IFACE_IFREQ
159 #ifndef I_STR
160 #include <sys/stropts.h>
161 #endif
163 /****************************************************************************
164 this should cover most of the streams based systems
165 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
166 ****************************************************************************/
167 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
169 struct ifreq ifreq;
170 struct strioctl strioctl;
171 char buff[8192];
172 int fd, i, n;
173 struct ifreq *ifr=NULL;
174 int total = 0;
175 struct in_addr ipaddr;
176 struct in_addr nmask;
177 char *iname;
179 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
180 return -1;
183 strioctl.ic_cmd = SIOCGIFCONF;
184 strioctl.ic_dp = buff;
185 strioctl.ic_len = sizeof(buff);
186 if (ioctl(fd, I_STR, &strioctl) < 0) {
187 close(fd);
188 return -1;
191 /* we can ignore the possible sizeof(int) here as the resulting
192 number of interface structures won't change */
193 n = strioctl.ic_len / sizeof(struct ifreq);
195 /* we will assume that the kernel returns the length as an int
196 at the start of the buffer if the offered size is a
197 multiple of the structure size plus an int */
198 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
199 ifr = (struct ifreq *)(buff + sizeof(int));
200 } else {
201 ifr = (struct ifreq *)buff;
204 /* Loop through interfaces */
206 for (i = 0; i<n && total < max_interfaces; i++) {
207 ifreq = ifr[i];
209 strioctl.ic_cmd = SIOCGIFFLAGS;
210 strioctl.ic_dp = (char *)&ifreq;
211 strioctl.ic_len = sizeof(struct ifreq);
212 if (ioctl(fd, I_STR, &strioctl) != 0) {
213 continue;
216 if (!(ifreq.ifr_flags & IFF_UP)) {
217 continue;
220 strioctl.ic_cmd = SIOCGIFADDR;
221 strioctl.ic_dp = (char *)&ifreq;
222 strioctl.ic_len = sizeof(struct ifreq);
223 if (ioctl(fd, I_STR, &strioctl) != 0) {
224 continue;
227 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
228 iname = ifreq.ifr_name;
230 strioctl.ic_cmd = SIOCGIFNETMASK;
231 strioctl.ic_dp = (char *)&ifreq;
232 strioctl.ic_len = sizeof(struct ifreq);
233 if (ioctl(fd, I_STR, &strioctl) != 0) {
234 continue;
237 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
239 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
240 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
241 ifaces[total].ip = ipaddr;
242 ifaces[total].netmask = nmask;
244 total++;
247 close(fd);
249 return total;
252 #elif HAVE_IFACE_AIX
254 /****************************************************************************
255 this one is for AIX (tested on 4.2)
256 ****************************************************************************/
257 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
259 char buff[8192];
260 int fd, i;
261 struct ifconf ifc;
262 struct ifreq *ifr=NULL;
263 struct in_addr ipaddr;
264 struct in_addr nmask;
265 char *iname;
266 int total = 0;
268 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
269 return -1;
273 ifc.ifc_len = sizeof(buff);
274 ifc.ifc_buf = buff;
276 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
277 close(fd);
278 return -1;
281 ifr = ifc.ifc_req;
283 /* Loop through interfaces */
284 i = ifc.ifc_len;
286 while (i > 0 && total < max_interfaces) {
287 unsigned inc;
289 inc = ifr->ifr_addr.sa_len;
291 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
292 goto next;
295 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
296 iname = ifr->ifr_name;
298 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
299 goto next;
302 if (!(ifr->ifr_flags & IFF_UP)) {
303 goto next;
306 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
307 goto next;
310 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
312 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
313 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
314 ifaces[total].ip = ipaddr;
315 ifaces[total].netmask = nmask;
317 total++;
319 next:
321 * Patch from Archie Cobbs (archie@whistle.com). The
322 * addresses in the SIOCGIFCONF interface list have a
323 * minimum size. Usually this doesn't matter, but if
324 * your machine has tunnel interfaces, etc. that have
325 * a zero length "link address", this does matter. */
327 if (inc < sizeof(ifr->ifr_addr))
328 inc = sizeof(ifr->ifr_addr);
329 inc += IFNAMSIZ;
331 ifr = (struct ifreq*) (((char*) ifr) + inc);
332 i -= inc;
336 close(fd);
337 return total;
340 #else /* a dummy version */
341 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
343 return -1;
345 #endif
348 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
350 int r;
351 r = strcmp(i1->name, i2->name);
352 if (r) return r;
353 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
354 if (r) return r;
355 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
356 return r;
359 /* this wrapper is used to remove duplicates from the interface list generated
360 above */
361 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
363 int total, i, j;
365 total = _get_interfaces(ifaces, max_interfaces);
366 if (total <= 0) return total;
368 /* now we need to remove duplicates */
369 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
371 for (i=1;i<total;) {
372 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
373 for (j=i-1;j<total-1;j++) {
374 ifaces[j] = ifaces[j+1];
376 total--;
377 } else {
378 i++;
382 return total;
386 #ifdef AUTOCONF_TEST
387 /* this is the autoconf driver to test get_interfaces() */
389 #define MAX_INTERFACES 128
391 int main()
393 struct iface_struct ifaces[MAX_INTERFACES];
394 int total = get_interfaces(ifaces, MAX_INTERFACES);
395 int i;
397 printf("got %d interfaces:\n", total);
398 if (total <= 0) exit(1);
400 for (i=0;i<total;i++) {
401 printf("%-10s ", ifaces[i].name);
402 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
403 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
405 return 0;
407 #endif