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>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
40 #include <sys/ioctl.h>
45 #include <sys/sockio.h>
52 struct in_addr netmask;
56 #include "interfaces.h"
72 #define QSORT_CAST (__compar_fn_t)
76 #define QSORT_CAST (int (*)(const void *, const void *))
81 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
82 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
84 It probably also works on any BSD style system. */
86 /****************************************************************************
87 get the netmask address for a local interface
88 ****************************************************************************/
89 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
94 struct ifreq *ifr=NULL;
96 struct in_addr ipaddr;
100 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
104 ifc.ifc_len = sizeof(buff);
107 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
114 n = ifc.ifc_len / sizeof(struct ifreq);
116 /* Loop through interfaces, looking for given IP address */
117 for (i=n-1;i>=0 && total < max_interfaces;i--) {
118 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
122 iname = ifr[i].ifr_name;
123 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
125 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
129 if (!(ifr[i].ifr_flags & IFF_UP)) {
133 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
137 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
139 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
140 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
141 ifaces[total].ip = ipaddr;
142 ifaces[total].netmask = nmask;
151 #elif HAVE_IFACE_IFREQ
154 #include <sys/stropts.h>
157 /****************************************************************************
158 this should cover most of the streams based systems
159 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
160 ****************************************************************************/
161 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
164 struct strioctl strioctl;
167 struct ifreq *ifr=NULL;
169 struct in_addr ipaddr;
170 struct in_addr nmask;
173 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
177 strioctl.ic_cmd = SIOCGIFCONF;
178 strioctl.ic_dp = buff;
179 strioctl.ic_len = sizeof(buff);
180 if (ioctl(fd, I_STR, &strioctl) < 0) {
185 /* we can ignore the possible sizeof(int) here as the resulting
186 number of interface structures won't change */
187 n = strioctl.ic_len / sizeof(struct ifreq);
189 /* we will assume that the kernel returns the length as an int
190 at the start of the buffer if the offered size is a
191 multiple of the structure size plus an int */
192 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
193 ifr = (struct ifreq *)(buff + sizeof(int));
195 ifr = (struct ifreq *)buff;
198 /* Loop through interfaces */
200 for (i = 0; i<n && total < max_interfaces; i++) {
203 strioctl.ic_cmd = SIOCGIFFLAGS;
204 strioctl.ic_dp = (char *)&ifreq;
205 strioctl.ic_len = sizeof(struct ifreq);
206 if (ioctl(fd, I_STR, &strioctl) != 0) {
210 if (!(ifreq.ifr_flags & IFF_UP)) {
214 strioctl.ic_cmd = SIOCGIFADDR;
215 strioctl.ic_dp = (char *)&ifreq;
216 strioctl.ic_len = sizeof(struct ifreq);
217 if (ioctl(fd, I_STR, &strioctl) != 0) {
221 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
222 iname = ifreq.ifr_name;
224 strioctl.ic_cmd = SIOCGIFNETMASK;
225 strioctl.ic_dp = (char *)&ifreq;
226 strioctl.ic_len = sizeof(struct ifreq);
227 if (ioctl(fd, I_STR, &strioctl) != 0) {
231 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
233 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
234 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
235 ifaces[total].ip = ipaddr;
236 ifaces[total].netmask = nmask;
248 /****************************************************************************
249 this one is for AIX (tested on 4.2)
250 ****************************************************************************/
251 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
256 struct ifreq *ifr=NULL;
257 struct in_addr ipaddr;
258 struct in_addr nmask;
262 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
267 ifc.ifc_len = sizeof(buff);
270 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
277 /* Loop through interfaces */
280 while (i > 0 && total < max_interfaces) {
283 inc = ifr->ifr_addr.sa_len;
285 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
289 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
290 iname = ifr->ifr_name;
292 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
296 if (!(ifr->ifr_flags & IFF_UP)) {
300 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
304 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
306 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
307 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
308 ifaces[total].ip = ipaddr;
309 ifaces[total].netmask = nmask;
315 * Patch from Archie Cobbs (archie@whistle.com). The
316 * addresses in the SIOCGIFCONF interface list have a
317 * minimum size. Usually this doesn't matter, but if
318 * your machine has tunnel interfaces, etc. that have
319 * a zero length "link address", this does matter. */
321 if (inc < sizeof(ifr->ifr_addr))
322 inc = sizeof(ifr->ifr_addr);
325 ifr = (struct ifreq*) (((char*) ifr) + inc);
334 #else /* a dummy version */
335 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
342 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
345 r = strcmp(i1->name, i2->name);
347 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
349 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
353 /* this wrapper is used to remove duplicates from the interface list generated
355 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
359 total = _get_interfaces(ifaces, max_interfaces);
360 if (total <= 0) return total;
362 /* now we need to remove duplicates */
363 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
366 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
367 for (j=i-1;j<total-1;j++) {
368 ifaces[j] = ifaces[j+1];
381 /* this is the autoconf driver to test get_interfaces() */
383 #define MAX_INTERFACES 128
387 struct iface_struct ifaces[MAX_INTERFACES];
388 int total = get_interfaces(ifaces, MAX_INTERFACES);
391 printf("got %d interfaces:\n", total);
392 if (total <= 0) exit(1);
394 for (i=0;i<total;i++) {
395 printf("%-10s ", ifaces[i].name);
396 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
397 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));