r15356: Remove unused 'flags' argument from socket_send() and friends.
[bbaumbach/samba-autobuild/.git] / source4 / lib / netif / netif.c
1 /* 
2    Unix SMB/CIFS implementation.
3    return a list of network interfaces
4    Copyright (C) Andrew Tridgell 1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 /* working out the interfaces for a OS is an incredibly non-portable
23    thing. We have several possible implementations below, and autoconf
24    tries each of them to see what works
25
26    Note that this file does _not_ include includes.h. That is so this code
27    can be called directly from the autoconf tests. That also means
28    this code cannot use any of the normal Samba debug stuff or defines.
29    This is standalone code.
30
31 */
32
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <netdb.h>
37 #include <sys/ioctl.h>
38 #include <netdb.h>
39 #include <sys/ioctl.h>
40 #include <sys/time.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44
45 #ifndef AUTOCONF_TEST
46 #include "config.h"
47 #endif
48
49 #ifdef HAVE_SYS_TIME_H
50 #include <sys/time.h>
51 #endif
52
53 #ifndef SIOCGIFCONF
54 #ifdef HAVE_SYS_SOCKIO_H
55 #include <sys/sockio.h>
56 #endif
57 #endif
58
59 #ifdef HAVE_STDLIB_H
60 #include <stdlib.h>
61 #endif
62
63 #ifdef HAVE_STRING_H
64 #include <string.h>
65 #endif
66
67 #ifdef HAVE_STRINGS_H
68 #include <strings.h>
69 #endif
70
71 #ifdef __COMPAR_FN_T
72 #define QSORT_CAST (__compar_fn_t)
73 #endif
74
75 #ifndef QSORT_CAST
76 #define QSORT_CAST (int (*)(const void *, const void *))
77 #endif
78
79 #include <net/if.h>
80 #define BOOL int
81 #include "netif.h"
82
83 #if HAVE_IFACE_IFCONF
84
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.
87
88    It probably also works on any BSD style system.  */
89
90 /****************************************************************************
91   get the netmask address for a local interface
92 ****************************************************************************/
93 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
94 {  
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;
103
104         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
105                 return -1;
106         }
107   
108         ifc.ifc_len = sizeof(buff);
109         ifc.ifc_buf = buff;
110
111         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
112                 close(fd);
113                 return -1;
114         } 
115
116         ifr = ifc.ifc_req;
117   
118         n = ifc.ifc_len / sizeof(struct ifreq);
119
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;
124                 }
125
126                 iname = ifr[i].ifr_name;
127                 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
128
129                 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
130                         continue;
131                 }  
132
133                 if (!(ifr[i].ifr_flags & IFF_UP)) {
134                         continue;
135                 }
136
137                 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
138                         continue;
139                 }  
140
141                 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
142
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++;
148         }
149
150         close(fd);
151
152         return total;
153 }  
154
155 #elif HAVE_IFACE_IFREQ
156
157 #ifndef I_STR
158 #include <sys/stropts.h>
159 #endif
160
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)
166 {
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;
176
177         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
178                 return -1;
179         }
180   
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;
187         } 
188
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);
192
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;  
200         }
201
202         /* Loop through interfaces */
203
204         for (i = 0; i<n && total < max_interfaces; i++) {
205                 ifreq = ifr[i];
206   
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;
212                 }
213                 
214                 if (!(ifreq.ifr_flags & IFF_UP)) {
215                         continue;
216                 }
217
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;
223                 }
224
225                 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
226                 iname = ifreq.ifr_name;
227
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;
233                 }
234
235                 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
236
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;
241
242                 total++;
243         }
244
245         close(fd);
246
247         return total;
248 }
249
250 #elif HAVE_IFACE_AIX
251
252 /****************************************************************************
253 this one is for AIX (tested on 4.2)
254 ****************************************************************************/
255 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
256 {
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;
265
266         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
267                 return -1;
268         }
269
270
271         ifc.ifc_len = sizeof(buff);
272         ifc.ifc_buf = buff;
273
274         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
275                 close(fd);
276                 return -1;
277         }
278
279         ifr = ifc.ifc_req;
280
281         /* Loop through interfaces */
282         i = ifc.ifc_len;
283
284         while (i > 0 && total < max_interfaces) {
285                 uint_t inc;
286
287                 inc = ifr->ifr_addr.sa_len;
288
289                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290                         goto next;
291                 }
292
293                 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
294                 iname = ifr->ifr_name;
295
296                 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
297                         goto next;
298                 }
299
300                 if (!(ifr->ifr_flags & IFF_UP)) {
301                         goto next;
302                 }
303
304                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
305                         goto next;
306                 }
307
308                 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
309
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;
314
315                 total++;
316
317         next:
318                 /*
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.  */
324
325                 if (inc < sizeof(ifr->ifr_addr))
326                         inc = sizeof(ifr->ifr_addr);
327                 inc += IFNAMSIZ;
328
329                 ifr = (struct ifreq*) (((char*) ifr) + inc);
330                 i -= inc;
331         }
332   
333
334         close(fd);
335         return total;
336 }
337
338 #else /* a dummy version */
339 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
340 {
341         return -1;
342 }
343 #endif
344
345
346 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
347 {
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;
355 }
356
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)
360 {
361         int total, i, j;
362
363         total = _get_interfaces(ifaces, max_interfaces);
364         if (total <= 0) return total;
365
366         /* now we need to remove duplicates */
367         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
368
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];
373                         }
374                         total--;
375                 } else {
376                         i++;
377                 }
378         }
379
380         return total;
381 }
382
383
384 #ifdef AUTOCONF_TEST
385 /* this is the autoconf driver to test get_interfaces() */
386
387  int main()
388 {
389         struct iface_struct ifaces[MAX_INTERFACES];
390         int total = get_interfaces(ifaces, MAX_INTERFACES);
391         int i;
392
393         printf("got %d interfaces:\n", total);
394         if (total <= 0) exit(1);
395
396         for (i=0;i<total;i++) {
397                 printf("%-10s ", ifaces[i].name);
398                 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
399                 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
400         }
401         return 0;
402 }
403 #endif