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 45void rep_freeifaddrs(struct ifaddrs *ifp) 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 57static struct sockaddr *sockaddr_dup(struct sockaddr *sa) 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 81int rep_getifaddrs(struct ifaddrs **ifap) 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/**************************************************************************** 154this should cover most of the streams based systems 155Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code 156****************************************************************************/ 157int rep_getifaddrs(struct ifaddrs **ifap) 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/**************************************************************************** 254this one is for AIX (tested on 4.2) 255****************************************************************************/ 256int rep_getifaddrs(struct ifaddrs **ifap) 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 347int rep_getifaddrs(struct ifaddrs **ifap) 348{ 349 errno = ENOSYS; 350 return -1; 351} 352#endif 353