2 Unix SMB/CIFS implementation.
3 return a list of network interfaces
4 Copyright (C) Andrew Tridgell 1998
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.
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.
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.
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
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.
35 #include <sys/types.h>
37 #include <sys/ioctl.h>
41 #include <sys/ioctl.h>
46 #include "lib/netif/netif.h"
50 #ifdef HAVE_SYS_TIME_H
55 #ifdef HAVE_SYS_SOCKIO_H
56 #include <sys/sockio.h>
73 #define QSORT_CAST (__compar_fn_t)
77 #define QSORT_CAST (int (*)(const void *, const void *))
82 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
83 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
85 It probably also works on any BSD style system. */
87 /****************************************************************************
88 get the netmask address for a local interface
89 ****************************************************************************/
90 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
95 struct ifreq *ifr=NULL;
97 struct in_addr ipaddr;
101 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
105 ifc.ifc_len = sizeof(buff);
108 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
115 n = ifc.ifc_len / sizeof(struct ifreq);
117 /* Loop through interfaces, looking for given IP address */
118 for (i=n-1;i>=0 && total < max_interfaces;i--) {
119 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
123 iname = ifr[i].ifr_name;
124 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
126 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
130 if (!(ifr[i].ifr_flags & IFF_UP)) {
134 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
138 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
140 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
141 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
142 ifaces[total].ip = ipaddr;
143 ifaces[total].netmask = nmask;
152 #elif HAVE_IFACE_IFREQ
155 #include <sys/stropts.h>
158 /****************************************************************************
159 this should cover most of the streams based systems
160 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
161 ****************************************************************************/
162 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
165 struct strioctl strioctl;
168 struct ifreq *ifr=NULL;
170 struct in_addr ipaddr;
171 struct in_addr nmask;
174 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
178 strioctl.ic_cmd = SIOCGIFCONF;
179 strioctl.ic_dp = buff;
180 strioctl.ic_len = sizeof(buff);
181 if (ioctl(fd, I_STR, &strioctl) < 0) {
186 /* we can ignore the possible sizeof(int) here as the resulting
187 number of interface structures won't change */
188 n = strioctl.ic_len / sizeof(struct ifreq);
190 /* we will assume that the kernel returns the length as an int
191 at the start of the buffer if the offered size is a
192 multiple of the structure size plus an int */
193 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
194 ifr = (struct ifreq *)(buff + sizeof(int));
196 ifr = (struct ifreq *)buff;
199 /* Loop through interfaces */
201 for (i = 0; i<n && total < max_interfaces; i++) {
204 strioctl.ic_cmd = SIOCGIFFLAGS;
205 strioctl.ic_dp = (char *)&ifreq;
206 strioctl.ic_len = sizeof(struct ifreq);
207 if (ioctl(fd, I_STR, &strioctl) != 0) {
211 if (!(ifreq.ifr_flags & IFF_UP)) {
215 strioctl.ic_cmd = SIOCGIFADDR;
216 strioctl.ic_dp = (char *)&ifreq;
217 strioctl.ic_len = sizeof(struct ifreq);
218 if (ioctl(fd, I_STR, &strioctl) != 0) {
222 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
223 iname = ifreq.ifr_name;
225 strioctl.ic_cmd = SIOCGIFNETMASK;
226 strioctl.ic_dp = (char *)&ifreq;
227 strioctl.ic_len = sizeof(struct ifreq);
228 if (ioctl(fd, I_STR, &strioctl) != 0) {
232 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
234 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
235 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
236 ifaces[total].ip = ipaddr;
237 ifaces[total].netmask = nmask;
249 /****************************************************************************
250 this one is for AIX (tested on 4.2)
251 ****************************************************************************/
252 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
257 struct ifreq *ifr=NULL;
258 struct in_addr ipaddr;
259 struct in_addr nmask;
263 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
268 ifc.ifc_len = sizeof(buff);
271 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
278 /* Loop through interfaces */
281 while (i > 0 && total < max_interfaces) {
284 inc = ifr->ifr_addr.sa_len;
286 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
291 iname = ifr->ifr_name;
293 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
297 if (!(ifr->ifr_flags & IFF_UP)) {
301 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
305 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
307 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
308 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
309 ifaces[total].ip = ipaddr;
310 ifaces[total].netmask = nmask;
316 * Patch from Archie Cobbs (archie@whistle.com). The
317 * addresses in the SIOCGIFCONF interface list have a
318 * minimum size. Usually this doesn't matter, but if
319 * your machine has tunnel interfaces, etc. that have
320 * a zero length "link address", this does matter. */
322 if (inc < sizeof(ifr->ifr_addr))
323 inc = sizeof(ifr->ifr_addr);
326 ifr = (struct ifreq*) (((char*) ifr) + inc);
335 #else /* a dummy version */
336 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
343 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
346 r = strcmp(i1->name, i2->name);
348 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
350 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
354 /* this wrapper is used to remove duplicates from the interface list generated
356 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
360 total = _get_interfaces(ifaces, max_interfaces);
361 if (total <= 0) return total;
363 /* now we need to remove duplicates */
364 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
367 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
368 for (j=i-1;j<total-1;j++) {
369 ifaces[j] = ifaces[j+1];
382 /* this is the autoconf driver to test get_interfaces() */
386 struct iface_struct ifaces[MAX_INTERFACES];
387 int total = get_interfaces(ifaces, MAX_INTERFACES);
390 printf("got %d interfaces:\n", total);
391 if (total <= 0) exit(1);
393 for (i=0;i<total;i++) {
394 printf("%-10s ", ifaces[i].name);
395 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
396 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));