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 3 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, see <http://www.gnu.org/licenses/>.
21 /* working out the interfaces for a OS is an incredibly non-portable
22 thing. We have several possible implementations below, and autoconf
23 tries each of them to see what works
25 Note that this file does _not_ include includes.h. That is so this code
26 can be called directly from the autoconf tests. That also means
27 this code cannot use any of the normal Samba debug stuff or defines.
28 This is standalone code.
38 #include <sys/types.h>
40 #include <sys/ioctl.h>
42 #include <sys/ioctl.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
48 #ifdef HAVE_SYS_TIME_H
53 #ifdef HAVE_SYS_SOCKIO_H
54 #include <sys/sockio.h>
71 #define QSORT_CAST (__compar_fn_t)
75 #define QSORT_CAST (int (*)(const void *, const void *))
82 #include "interfaces.h"
86 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
87 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
89 It probably also works on any BSD style system. */
91 /****************************************************************************
92 get the netmask address for a local interface
93 ****************************************************************************/
94 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
99 struct ifreq *ifr=NULL;
101 struct in_addr ipaddr;
102 struct in_addr nmask;
105 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
109 ifc.ifc_len = sizeof(buff);
112 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
119 n = ifc.ifc_len / sizeof(struct ifreq);
121 /* Loop through interfaces, looking for given IP address */
122 for (i=n-1;i>=0 && total < max_interfaces;i--) {
123 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
127 iname = ifr[i].ifr_name;
128 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
130 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
134 if (!(ifr[i].ifr_flags & IFF_UP)) {
138 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
142 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
144 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
145 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
146 ifaces[total].ip = ipaddr;
147 ifaces[total].netmask = nmask;
156 #define _FOUND_IFACE_ANY
157 #endif /* HAVE_IFACE_IFCONF */
158 #ifdef HAVE_IFACE_IFREQ
161 #include <sys/stropts.h>
164 /****************************************************************************
165 this should cover most of the streams based systems
166 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
167 ****************************************************************************/
168 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
171 struct strioctl strioctl;
174 struct ifreq *ifr=NULL;
176 struct in_addr ipaddr;
177 struct in_addr nmask;
180 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
184 strioctl.ic_cmd = SIOCGIFCONF;
185 strioctl.ic_dp = buff;
186 strioctl.ic_len = sizeof(buff);
187 if (ioctl(fd, I_STR, &strioctl) < 0) {
192 /* we can ignore the possible sizeof(int) here as the resulting
193 number of interface structures won't change */
194 n = strioctl.ic_len / sizeof(struct ifreq);
196 /* we will assume that the kernel returns the length as an int
197 at the start of the buffer if the offered size is a
198 multiple of the structure size plus an int */
199 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
200 ifr = (struct ifreq *)(buff + sizeof(int));
202 ifr = (struct ifreq *)buff;
205 /* Loop through interfaces */
207 for (i = 0; i<n && total < max_interfaces; i++) {
210 strioctl.ic_cmd = SIOCGIFFLAGS;
211 strioctl.ic_dp = (char *)&ifreq;
212 strioctl.ic_len = sizeof(struct ifreq);
213 if (ioctl(fd, I_STR, &strioctl) != 0) {
217 if (!(ifreq.ifr_flags & IFF_UP)) {
221 strioctl.ic_cmd = SIOCGIFADDR;
222 strioctl.ic_dp = (char *)&ifreq;
223 strioctl.ic_len = sizeof(struct ifreq);
224 if (ioctl(fd, I_STR, &strioctl) != 0) {
228 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
229 iname = ifreq.ifr_name;
231 strioctl.ic_cmd = SIOCGIFNETMASK;
232 strioctl.ic_dp = (char *)&ifreq;
233 strioctl.ic_len = sizeof(struct ifreq);
234 if (ioctl(fd, I_STR, &strioctl) != 0) {
238 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
240 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
241 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
242 ifaces[total].ip = ipaddr;
243 ifaces[total].netmask = nmask;
253 #define _FOUND_IFACE_ANY
254 #endif /* HAVE_IFACE_IFREQ */
255 #ifdef HAVE_IFACE_AIX
257 /****************************************************************************
258 this one is for AIX (tested on 4.2)
259 ****************************************************************************/
260 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
265 struct ifreq *ifr=NULL;
266 struct in_addr ipaddr;
267 struct in_addr nmask;
271 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
276 ifc.ifc_len = sizeof(buff);
279 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
286 /* Loop through interfaces */
289 while (i > 0 && total < max_interfaces) {
292 inc = ifr->ifr_addr.sa_len;
294 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
298 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
299 iname = ifr->ifr_name;
301 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
305 if (!(ifr->ifr_flags & IFF_UP)) {
309 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
313 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
315 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
316 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
317 ifaces[total].ip = ipaddr;
318 ifaces[total].netmask = nmask;
324 * Patch from Archie Cobbs (archie@whistle.com). The
325 * addresses in the SIOCGIFCONF interface list have a
326 * minimum size. Usually this doesn't matter, but if
327 * your machine has tunnel interfaces, etc. that have
328 * a zero length "link address", this does matter. */
330 if (inc < sizeof(ifr->ifr_addr))
331 inc = sizeof(ifr->ifr_addr);
334 ifr = (struct ifreq*) (((char*) ifr) + inc);
343 #define _FOUND_IFACE_ANY
344 #endif /* HAVE_IFACE_AIX */
345 #ifndef _FOUND_IFACE_ANY
346 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
353 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
356 r = strcmp(i1->name, i2->name);
358 r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
360 r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
364 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
365 /* this wrapper is used to remove duplicates from the interface list generated
367 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
371 total = _get_interfaces(ifaces, max_interfaces);
372 if (total <= 0) return total;
374 /* now we need to remove duplicates */
375 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
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];
393 /* this is the autoconf driver to test get_interfaces() */
397 struct iface_struct ifaces[MAX_INTERFACES];
398 int total = get_interfaces(ifaces, MAX_INTERFACES);
401 printf("got %d interfaces:\n", total);
402 if (total <= 0) exit(1);
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));