root/lib/replace/getifaddrs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rep_freeifaddrs
  2. sockaddr_dup
  3. rep_getifaddrs
  4. rep_getifaddrs
  5. rep_getifaddrs
  6. rep_getifaddrs

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Samba utility functions
   4    Copyright (C) Andrew Tridgell 1998
   5    Copyright (C) Jeremy Allison 2007
   6    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #define SOCKET_WRAPPER_NOT_REPLACE
  23 
  24 #include "replace.h"
  25 #include "system/network.h"
  26 
  27 #include <unistd.h>
  28 #include <stdio.h>
  29 #include <sys/types.h>
  30 
  31 #ifdef HAVE_SYS_TIME_H
  32 #include <sys/time.h>
  33 #endif
  34 
  35 #ifndef SIOCGIFCONF
  36 #ifdef HAVE_SYS_SOCKIO_H
  37 #include <sys/sockio.h>
  38 #endif
  39 #endif
  40 
  41 #ifdef HAVE_IFACE_GETIFADDRS
  42 #define _FOUND_IFACE_ANY
  43 #else
  44 
  45 void rep_freeifaddrs(struct ifaddrs *ifp)
     /* [<][>][^][v][top][bottom][index][help] */
  46 {
  47         if (ifp != NULL) {
  48                 free(ifp->ifa_name);
  49                 free(ifp->ifa_addr);
  50                 free(ifp->ifa_netmask);
  51                 free(ifp->ifa_dstaddr);
  52                 freeifaddrs(ifp->ifa_next);
  53                 free(ifp);
  54         }
  55 }
  56 
  57 static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         struct sockaddr *ret;
  60         socklen_t socklen;
  61 #ifdef HAVE_SOCKADDR_SA_LEN
  62         socklen = sa->sa_len;
  63 #else
  64         socklen = sizeof(struct sockaddr_storage);
  65 #endif
  66         ret = calloc(1, socklen);
  67         if (ret == NULL)
  68                 return NULL;
  69         memcpy(ret, sa, socklen);
  70         return ret;
  71 }
  72 #endif
  73 
  74 #if HAVE_IFACE_IFCONF
  75 
  76 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
  77    V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
  78 
  79    It probably also works on any BSD style system.  */
  80 
  81 int rep_getifaddrs(struct ifaddrs **ifap)
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83         struct ifconf ifc;
  84         char buff[8192];
  85         int fd, i, n;
  86         struct ifreq *ifr=NULL;
  87         struct ifaddrs *curif;
  88         struct ifaddrs *lastif = NULL;
  89 
  90         *ifap = NULL;
  91 
  92         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  93                 return -1;
  94         }
  95   
  96         ifc.ifc_len = sizeof(buff);
  97         ifc.ifc_buf = buff;
  98 
  99         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
 100                 close(fd);
 101                 return -1;
 102         } 
 103 
 104         ifr = ifc.ifc_req;
 105   
 106         n = ifc.ifc_len / sizeof(struct ifreq);
 107 
 108         /* Loop through interfaces, looking for given IP address */
 109         for (i=n-1; i>=0; i--) {
 110                 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
 111                         freeifaddrs(*ifap);
 112                         return -1;
 113                 }
 114 
 115                 curif = calloc(1, sizeof(struct ifaddrs));
 116                 curif->ifa_name = strdup(ifr[i].ifr_name);
 117                 curif->ifa_flags = ifr[i].ifr_flags;
 118                 curif->ifa_dstaddr = NULL;
 119                 curif->ifa_data = NULL;
 120                 curif->ifa_next = NULL;
 121 
 122                 curif->ifa_addr = NULL;
 123                 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
 124                         curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
 125                 }
 126 
 127                 curif->ifa_netmask = NULL;
 128                 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
 129                         curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
 130                 }
 131 
 132                 if (lastif == NULL) {
 133                         *ifap = curif;
 134                 } else {
 135                         lastif->ifa_next = curif;
 136                 }
 137                 lastif = curif;
 138         }
 139 
 140         close(fd);
 141 
 142         return 0;
 143 }  
 144 
 145 #define _FOUND_IFACE_ANY
 146 #endif /* HAVE_IFACE_IFCONF */
 147 #ifdef HAVE_IFACE_IFREQ
 148 
 149 #ifndef I_STR
 150 #include <sys/stropts.h>
 151 #endif
 152 
 153 /****************************************************************************
 154 this should cover most of the streams based systems
 155 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
 156 ****************************************************************************/
 157 int rep_getifaddrs(struct ifaddrs **ifap)
     /* [<][>][^][v][top][bottom][index][help] */
 158 {
 159         struct ifreq ifreq;
 160         struct strioctl strioctl;
 161         char buff[8192];
 162         int fd, i, n;
 163         struct ifreq *ifr=NULL;
 164         struct ifaddrs *curif;
 165         struct ifaddrs *lastif = NULL;
 166 
 167         *ifap = NULL;
 168 
 169         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
 170                 return -1;
 171         }
 172   
 173         strioctl.ic_cmd = SIOCGIFCONF;
 174         strioctl.ic_dp  = buff;
 175         strioctl.ic_len = sizeof(buff);
 176         if (ioctl(fd, I_STR, &strioctl) < 0) {
 177                 close(fd);
 178                 return -1;
 179         } 
 180 
 181         /* we can ignore the possible sizeof(int) here as the resulting
 182            number of interface structures won't change */
 183         n = strioctl.ic_len / sizeof(struct ifreq);
 184 
 185         /* we will assume that the kernel returns the length as an int
 186            at the start of the buffer if the offered size is a
 187            multiple of the structure size plus an int */
 188         if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
 189                 ifr = (struct ifreq *)(buff + sizeof(int));  
 190         } else {
 191                 ifr = (struct ifreq *)buff;  
 192         }
 193 
 194         /* Loop through interfaces */
 195 
 196         for (i = 0; i<n; i++) {
 197                 ifreq = ifr[i];
 198   
 199                 curif = calloc(1, sizeof(struct ifaddrs));
 200                 if (lastif == NULL) {
 201                         *ifap = curif;
 202                 } else {
 203                         lastif->ifa_next = curif;
 204                 }
 205 
 206                 strioctl.ic_cmd = SIOCGIFFLAGS;
 207                 strioctl.ic_dp  = (char *)&ifreq;
 208                 strioctl.ic_len = sizeof(struct ifreq);
 209                 if (ioctl(fd, I_STR, &strioctl) != 0) {
 210                         freeifaddrs(*ifap);
 211                         return -1;
 212                 }
 213 
 214                 curif->ifa_flags = ifreq.ifr_flags;
 215                 
 216                 strioctl.ic_cmd = SIOCGIFADDR;
 217                 strioctl.ic_dp  = (char *)&ifreq;
 218                 strioctl.ic_len = sizeof(struct ifreq);
 219                 if (ioctl(fd, I_STR, &strioctl) != 0) {
 220                         freeifaddrs(*ifap);
 221                         return -1;
 222                 }
 223 
 224                 curif->ifa_name = strdup(ifreq.ifr_name);
 225                 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
 226                 curif->ifa_dstaddr = NULL;
 227                 curif->ifa_data = NULL;
 228                 curif->ifa_next = NULL;
 229                 curif->ifa_netmask = NULL;
 230 
 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) {
 235                         freeifaddrs(*ifap);
 236                         return -1;
 237                 }
 238 
 239                 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
 240 
 241                 lastif = curif;
 242         }
 243 
 244         close(fd);
 245 
 246         return 0;
 247 }
 248 
 249 #define _FOUND_IFACE_ANY
 250 #endif /* HAVE_IFACE_IFREQ */
 251 #ifdef HAVE_IFACE_AIX
 252 
 253 /****************************************************************************
 254 this one is for AIX (tested on 4.2)
 255 ****************************************************************************/
 256 int rep_getifaddrs(struct ifaddrs **ifap)
     /* [<][>][^][v][top][bottom][index][help] */
 257 {
 258         char buff[8192];
 259         int fd, i;
 260         struct ifconf ifc;
 261         struct ifreq *ifr=NULL;
 262         struct ifaddrs *curif;
 263         struct ifaddrs *lastif = NULL;
 264 
 265         *ifap = NULL;
 266 
 267         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
 268                 return -1;
 269         }
 270 
 271         ifc.ifc_len = sizeof(buff);
 272         ifc.ifc_buf = buff;
 273 
 274         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
 275                 close(fd);
 276                 return -1;
 277         }
 278 
 279         ifr = ifc.ifc_req;
 280 
 281         /* Loop through interfaces */
 282         i = ifc.ifc_len;
 283 
 284         while (i > 0) {
 285                 uint_t inc;
 286 
 287                 inc = ifr->ifr_addr.sa_len;
 288 
 289                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
 290                         freeaddrinfo(*ifap);
 291                         return -1;
 292                 }
 293 
 294                 curif = calloc(1, sizeof(struct ifaddrs));
 295                 if (lastif == NULL) {
 296                         *ifap = curif;
 297                 } else {
 298                         lastif->ifa_next = curif;
 299                 }
 300 
 301                 curif->ifa_name = strdup(ifr->ifr_name);
 302                 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
 303                 curif->ifa_dstaddr = NULL;
 304                 curif->ifa_data = NULL;
 305                 curif->ifa_netmask = NULL;
 306                 curif->ifa_next = NULL;
 307 
 308                 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
 309                         freeaddrinfo(*ifap);
 310                         return -1;
 311                 }
 312 
 313                 curif->ifa_flags = ifr->ifr_flags;
 314 
 315                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
 316                         freeaddrinfo(*ifap);
 317                         return -1;
 318                 }
 319 
 320                 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
 321 
 322                 lastif = curif;
 323 
 324         next:
 325                 /*
 326                  * Patch from Archie Cobbs (archie@whistle.com).  The
 327                  * addresses in the SIOCGIFCONF interface list have a
 328                  * minimum size. Usually this doesn't matter, but if
 329                  * your machine has tunnel interfaces, etc. that have
 330                  * a zero length "link address", this does matter.  */
 331 
 332                 if (inc < sizeof(ifr->ifr_addr))
 333                         inc = sizeof(ifr->ifr_addr);
 334                 inc += IFNAMSIZ;
 335 
 336                 ifr = (struct ifreq*) (((char*) ifr) + inc);
 337                 i -= inc;
 338         }
 339 
 340         close(fd);
 341         return 0;
 342 }
 343 
 344 #define _FOUND_IFACE_ANY
 345 #endif /* HAVE_IFACE_AIX */
 346 #ifndef _FOUND_IFACE_ANY
 347 int rep_getifaddrs(struct ifaddrs **ifap)
     /* [<][>][^][v][top][bottom][index][help] */
 348 {
 349         errno = ENOSYS;
 350         return -1;
 351 }
 352 #endif

/* [<][>][^][v][top][bottom][index][help] */