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 "config.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 "interfaces.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****************************************************************************/ 95static 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/**************************************************************************** 166this should cover most of the streams based systems 167Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code 168****************************************************************************/ 169static 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/**************************************************************************** 259this one is for AIX (tested on 4.2) 260****************************************************************************/ 261static 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 347static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) 348{ 349 return -1; 350} 351#endif 352 353 354static 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 365int get_interfaces(struct iface_struct *ifaces, int max_interfaces); 366/* this wrapper is used to remove duplicates from the interface list generated 367 above */ 368int get_interfaces(struct iface_struct *ifaces, int max_interfaces) 369{ 370 int total, i, j; 371 372 total = _get_interfaces(ifaces, max_interfaces); 373 if (total <= 0) return total; 374 375 /* now we need to remove duplicates */ 376 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp); 377 378 for (i=1;i<total;) { 379 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) { 380 for (j=i-1;j<total-1;j++) { 381 ifaces[j] = ifaces[j+1]; 382 } 383 total--; 384 } else { 385 i++; 386 } 387 } 388 389 return total; 390} 391 392 393#ifdef AUTOCONF_TEST 394/* this is the autoconf driver to test get_interfaces() */ 395 396 int main() 397{ 398 struct iface_struct ifaces[MAX_INTERFACES]; 399 int total = get_interfaces(ifaces, MAX_INTERFACES); 400 int i; 401 402 printf("got %d interfaces:\n", total); 403 if (total <= 0) exit(1); 404 405 for (i=0;i<total;i++) { 406 printf("%-10s ", ifaces[i].name); 407 printf("IP=%s ", inet_ntoa(ifaces[i].ip)); 408 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask)); 409 } 410 return 0; 411} 412#endif 413