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 #ifndef AUTOCONF_TEST
34 #include "includes.h"
35 #endif
36
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <netdb.h>
41 #include <sys/ioctl.h>
42 #include <netdb.h>
43 #include <sys/ioctl.h>
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
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 #ifdef HAVE_NET_IF_H
80 #include <net/if.h>
81 #endif
82
83 #include "netif.h"
84
85 #if HAVE_IFACE_IFCONF
86
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.
89
90 It probably also works on any BSD style system. */
91
92 /****************************************************************************
93 get the netmask address for a local interface
94 ****************************************************************************/
_get_interfaces(struct iface_struct * ifaces,int max_interfaces)95 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
96 {
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;
105
106 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
107 return -1;
108 }
109
110 ifc.ifc_len = sizeof(buff);
111 ifc.ifc_buf = buff;
112
113 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
114 close(fd);
115 return -1;
116 }
117
118 ifr = ifc.ifc_req;
119
120 n = ifc.ifc_len / sizeof(struct ifreq);
121
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;
126 }
127
128 iname = ifr[i].ifr_name;
129 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
130
131 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
132 continue;
133 }
134
135 if (!(ifr[i].ifr_flags & IFF_UP)) {
136 continue;
137 }
138
139 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
140 continue;
141 }
142
143 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
144
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++;
150 }
151
152 close(fd);
153
154 return total;
155 }
156
157 #define _FOUND_IFACE_ANY
158 #endif /* HAVE_IFACE_IFCONF */
159 #ifdef HAVE_IFACE_IFREQ
160
161 #ifndef I_STR
162 #include <sys/stropts.h>
163 #endif
164
165 /****************************************************************************
166 this should cover most of the streams based systems
167 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
168 ****************************************************************************/
_get_interfaces(struct iface_struct * ifaces,int max_interfaces)169 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
170 {
171 struct ifreq ifreq;
172 struct strioctl strioctl;
173 char buff[8192];
174 int fd, i, n;
175 struct ifreq *ifr=NULL;
176 int total = 0;
177 struct in_addr ipaddr;
178 struct in_addr nmask;
179 char *iname;
180
181 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
182 return -1;
183 }
184
185 strioctl.ic_cmd = SIOCGIFCONF;
186 strioctl.ic_dp = buff;
187 strioctl.ic_len = sizeof(buff);
188 if (ioctl(fd, I_STR, &strioctl) < 0) {
189 close(fd);
190 return -1;
191 }
192
193 /* we can ignore the possible sizeof(int) here as the resulting
194 number of interface structures won't change */
195 n = strioctl.ic_len / sizeof(struct ifreq);
196
197 /* we will assume that the kernel returns the length as an int
198 at the start of the buffer if the offered size is a
199 multiple of the structure size plus an int */
200 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
201 ifr = (struct ifreq *)(buff + sizeof(int));
202 } else {
203 ifr = (struct ifreq *)buff;
204 }
205
206 /* Loop through interfaces */
207
208 for (i = 0; i<n && total < max_interfaces; i++) {
209 ifreq = ifr[i];
210
211 strioctl.ic_cmd = SIOCGIFFLAGS;
212 strioctl.ic_dp = (char *)&ifreq;
213 strioctl.ic_len = sizeof(struct ifreq);
214 if (ioctl(fd, I_STR, &strioctl) != 0) {
215 continue;
216 }
217
218 if (!(ifreq.ifr_flags & IFF_UP)) {
219 continue;
220 }
221
222 strioctl.ic_cmd = SIOCGIFADDR;
223 strioctl.ic_dp = (char *)&ifreq;
224 strioctl.ic_len = sizeof(struct ifreq);
225 if (ioctl(fd, I_STR, &strioctl) != 0) {
226 continue;
227 }
228
229 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
230 iname = ifreq.ifr_name;
231
232 strioctl.ic_cmd = SIOCGIFNETMASK;
233 strioctl.ic_dp = (char *)&ifreq;
234 strioctl.ic_len = sizeof(struct ifreq);
235 if (ioctl(fd, I_STR, &strioctl) != 0) {
236 continue;
237 }
238
239 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
240
241 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
242 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
243 ifaces[total].ip = ipaddr;
244 ifaces[total].netmask = nmask;
245
246 total++;
247 }
248
249 close(fd);
250
251 return total;
252 }
253
254 #define _FOUND_IFACE_ANY
255 #endif /* HAVE_IFACE_IFREQ */
256 #ifdef HAVE_IFACE_AIX
257
258 /****************************************************************************
259 this one is for AIX (tested on 4.2)
260 ****************************************************************************/
_get_interfaces(struct iface_struct * ifaces,int max_interfaces)261 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
262 {
263 char buff[8192];
264 int fd, i;
265 struct ifconf ifc;
266 struct ifreq *ifr=NULL;
267 struct in_addr ipaddr;
268 struct in_addr nmask;
269 char *iname;
270 int total = 0;
271
272 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
273 return -1;
274 }
275
276
277 ifc.ifc_len = sizeof(buff);
278 ifc.ifc_buf = buff;
279
280 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
281 close(fd);
282 return -1;
283 }
284
285 ifr = ifc.ifc_req;
286
287 /* Loop through interfaces */
288 i = ifc.ifc_len;
289
290 while (i > 0 && total < max_interfaces) {
291 uint_t inc;
292
293 inc = ifr->ifr_addr.sa_len;
294
295 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
296 goto next;
297 }
298
299 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
300 iname = ifr->ifr_name;
301
302 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
303 goto next;
304 }
305
306 if (!(ifr->ifr_flags & IFF_UP)) {
307 goto next;
308 }
309
310 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
311 goto next;
312 }
313
314 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
315
316 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
317 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
318 ifaces[total].ip = ipaddr;
319 ifaces[total].netmask = nmask;
320
321 total++;
322
323 next:
324 /*
325 * Patch from Archie Cobbs (archie@whistle.com). The
326 * addresses in the SIOCGIFCONF interface list have a
327 * minimum size. Usually this doesn't matter, but if
328 * your machine has tunnel interfaces, etc. that have
329 * a zero length "link address", this does matter. */
330
331 if (inc < sizeof(ifr->ifr_addr))
332 inc = sizeof(ifr->ifr_addr);
333 inc += IFNAMSIZ;
334
335 ifr = (struct ifreq*) (((char*) ifr) + inc);
336 i -= inc;
337 }
338
339
340 close(fd);
341 return total;
342 }
343
344 #define _FOUND_IFACE_ANY
345 #endif /* HAVE_IFACE_AIX */
346 #ifndef _FOUND_IFACE_ANY
_get_interfaces(struct iface_struct * ifaces,int max_interfaces)347 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
348 {
349 return -1;
350 }
351 #endif
352
353
iface_comp(struct iface_struct * i1,struct iface_struct * i2)354 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
355 {
356 int r;
357 r = strcmp(i1->name, i2->name);
358 if (r) return r;
359 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
360 if (r) return r;
361 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
362 return r;
363 }
364
365 /* this wrapper is used to remove duplicates from the interface list generated
366 above */
get_interfaces(struct iface_struct * ifaces,int max_interfaces)367 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
368 {
369 int total, i, j;
370
371 total = _get_interfaces(ifaces, max_interfaces);
372 if (total <= 0) return total;
373
374 /* now we need to remove duplicates */
375 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
376
377 for (i=1;i<total;) {
378 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
379 for (j=i-1;j<total-1;j++) {
380 ifaces[j] = ifaces[j+1];
381 }
382 total--;
383 } else {
384 i++;
385 }
386 }
387
388 return total;
389 }
390
391
392 #ifdef AUTOCONF_TEST
393 /* this is the autoconf driver to test get_interfaces() */
394
main()395 int main()
396 {
397 struct iface_struct ifaces[MAX_INTERFACES];
398 int total = get_interfaces(ifaces, MAX_INTERFACES);
399 int i;
400
401 printf("got %d interfaces:\n", total);
402 if (total <= 0) exit(1);
403
404 for (i=0;i<total;i++) {
405 printf("%-10s ", ifaces[i].name);
406 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
407 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
408 }
409 return 0;
410 }
411 #endif
412