1/* 2 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */ 19 20/* 21 * Note that this code will need to be revisited to support IPv6 Interfaces. 22 * For now we just iterate through IPv4 interfaces. 23 */ 24 25#include <config.h> 26#include <winsock2.h> 27#include <ws2tcpip.h> 28#include <sys/types.h> 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <errno.h> 33 34#include <isc/interfaceiter.h> 35#include <isc/mem.h> 36#include <isc/result.h> 37#include <isc/string.h> 38#include <isc/strerror.h> 39#include <isc/types.h> 40#include <isc/util.h> 41 42void InitSockets(void); 43 44/* Common utility functions */ 45 46/* 47 * Extract the network address part from a "struct sockaddr". 48 * 49 * The address family is given explicitly 50 * instead of using src->sa_family, because the latter does not work 51 * for copying a network mask obtained by SIOCGIFNETMASK (it does 52 * not have a valid address family). 53 */ 54 55 56#define IFITER_MAGIC 0x49464954U /* IFIT. */ 57#define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) 58 59struct isc_interfaceiter { 60 unsigned int magic; /* Magic number. */ 61 isc_mem_t *mctx; 62 int socket; 63 INTERFACE_INFO IFData; /* Current Interface Info */ 64 int numIF; /* Current Interface count */ 65 int v4IF; /* Number of IPv4 Interfaces */ 66 INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */ 67 unsigned int buf4size; /* Bytes allocated. */ 68 INTERFACE_INFO *pos4; /* Current offset in IF List */ 69 SOCKET_ADDRESS_LIST *buf6; 70 unsigned int buf6size; /* Bytes allocated. */ 71 unsigned int pos6; 72 isc_interface_t current; /* Current interface data. */ 73 isc_result_t result; /* Last result code. */ 74}; 75 76 77/* 78 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. 79 * We assume no sane system will have more than than 1K of IP addresses on 80 * all of its adapters. 81 */ 82#define IFCONF_SIZE_INITIAL 16 83#define IFCONF_SIZE_INCREMENT 64 84#define IFCONF_SIZE_MAX 1040 85 86static void 87get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) { 88 dst->family = family; 89 switch (family) { 90 case AF_INET: 91 memcpy(&dst->type.in, 92 &((struct sockaddr_in *) src)->sin_addr, 93 sizeof(struct in_addr)); 94 break; 95 case AF_INET6: 96 memcpy(&dst->type.in6, 97 &((struct sockaddr_in6 *) src)->sin6_addr, 98 sizeof(struct in6_addr)); 99 dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id; 100 break; 101 default: 102 INSIST(0); 103 break; 104 } 105} 106 107isc_result_t 108isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 109 char strbuf[ISC_STRERRORSIZE]; 110 isc_interfaceiter_t *iter; 111 isc_result_t result; 112 int error; 113 unsigned long bytesReturned = 0; 114 115 REQUIRE(mctx != NULL); 116 REQUIRE(iterp != NULL); 117 REQUIRE(*iterp == NULL); 118 119 iter = isc_mem_get(mctx, sizeof(*iter)); 120 if (iter == NULL) 121 return (ISC_R_NOMEMORY); 122 123 InitSockets(); 124 125 iter->mctx = mctx; 126 iter->buf4 = NULL; 127 iter->buf6 = NULL; 128 iter->pos4 = NULL; 129 iter->pos6 = 0; 130 iter->buf6size = 0; 131 iter->buf4size = 0; 132 iter->result = ISC_R_FAILURE; 133 iter->numIF = 0; 134 iter->v4IF = 0; 135 136 /* 137 * Create an unbound datagram socket to do the 138 * SIO_GET_INTERFACE_LIST WSAIoctl on. 139 */ 140 if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 141 error = WSAGetLastError(); 142 if (error == WSAEAFNOSUPPORT) 143 goto inet6_only; 144 isc__strerror(error, strbuf, sizeof(strbuf)); 145 UNEXPECTED_ERROR(__FILE__, __LINE__, 146 "making interface scan socket: %s", 147 strbuf); 148 result = ISC_R_UNEXPECTED; 149 goto socket_failure; 150 } 151 152 /* 153 * Get the interface configuration, allocating more memory if 154 * necessary. 155 */ 156 iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO); 157 158 for (;;) { 159 iter->buf4 = isc_mem_get(mctx, iter->buf4size); 160 if (iter->buf4 == NULL) { 161 result = ISC_R_NOMEMORY; 162 goto alloc_failure; 163 } 164 165 if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, 166 0, 0, iter->buf4, iter->buf4size, 167 &bytesReturned, 0, 0) == SOCKET_ERROR) 168 { 169 error = WSAGetLastError(); 170 if (error != WSAEFAULT && error != WSAENOBUFS) { 171 errno = error; 172 isc__strerror(error, strbuf, sizeof(strbuf)); 173 UNEXPECTED_ERROR(__FILE__, __LINE__, 174 "get interface configuration: %s", 175 strbuf); 176 result = ISC_R_UNEXPECTED; 177 goto ioctl_failure; 178 } 179 /* 180 * EINVAL. Retry with a bigger buffer. 181 */ 182 } else { 183 /* 184 * The WSAIoctl succeeded. 185 * If the number of the returned bytes is the same 186 * as the buffer size, we will grow it just in 187 * case and retry. 188 */ 189 if (bytesReturned > 0 && 190 (bytesReturned < iter->buf4size)) 191 break; 192 } 193 if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) { 194 UNEXPECTED_ERROR(__FILE__, __LINE__, 195 "get interface configuration: " 196 "maximum buffer size exceeded"); 197 result = ISC_R_UNEXPECTED; 198 goto ioctl_failure; 199 } 200 isc_mem_put(mctx, iter->buf4, iter->buf4size); 201 202 iter->buf4size += IFCONF_SIZE_INCREMENT * 203 sizeof(INTERFACE_INFO); 204 } 205 206 /* 207 * A newly created iterator has an undefined position 208 * until isc_interfaceiter_first() is called. 209 */ 210 iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO); 211 212 /* We don't need the socket any more, so close it */ 213 closesocket(iter->socket); 214 215 inet6_only: 216 /* 217 * Create an unbound datagram socket to do the 218 * SIO_ADDRESS_LIST_QUERY WSAIoctl on. 219 */ 220 if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 221 error = WSAGetLastError(); 222 if (error == WSAEAFNOSUPPORT) 223 goto inet_only; 224 isc__strerror(error, strbuf, sizeof(strbuf)); 225 UNEXPECTED_ERROR(__FILE__, __LINE__, 226 "making interface scan socket: %s", 227 strbuf); 228 result = ISC_R_UNEXPECTED; 229 goto ioctl_failure; 230 } 231 232 /* 233 * Get the interface configuration, allocating more memory if 234 * necessary. 235 */ 236 iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) + 237 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS); 238 239 for (;;) { 240 iter->buf6 = isc_mem_get(mctx, iter->buf6size); 241 if (iter->buf6 == NULL) { 242 result = ISC_R_NOMEMORY; 243 goto ioctl_failure; 244 } 245 246 if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, 247 0, 0, iter->buf6, iter->buf6size, 248 &bytesReturned, 0, 0) == SOCKET_ERROR) 249 { 250 error = WSAGetLastError(); 251 if (error != WSAEFAULT && error != WSAENOBUFS) { 252 errno = error; 253 isc__strerror(error, strbuf, sizeof(strbuf)); 254 UNEXPECTED_ERROR(__FILE__, __LINE__, 255 "sio address list query: %s", 256 strbuf); 257 result = ISC_R_UNEXPECTED; 258 goto ioctl6_failure; 259 } 260 /* 261 * EINVAL. Retry with a bigger buffer. 262 */ 263 } else 264 break; 265 266 if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) { 267 UNEXPECTED_ERROR(__FILE__, __LINE__, 268 "get interface configuration: " 269 "maximum buffer size exceeded"); 270 result = ISC_R_UNEXPECTED; 271 goto ioctl6_failure; 272 } 273 isc_mem_put(mctx, iter->buf6, iter->buf6size); 274 275 iter->buf6size += IFCONF_SIZE_INCREMENT * 276 sizeof(SOCKET_ADDRESS); 277 } 278 279 closesocket(iter->socket); 280 281 inet_only: 282 iter->magic = IFITER_MAGIC; 283 *iterp = iter; 284 return (ISC_R_SUCCESS); 285 286 ioctl6_failure: 287 isc_mem_put(mctx, iter->buf6, iter->buf6size); 288 289 ioctl_failure: 290 if (iter->buf4 != NULL) 291 isc_mem_put(mctx, iter->buf4, iter->buf4size); 292 293 alloc_failure: 294 if (iter->socket >= 0) 295 (void) closesocket(iter->socket); 296 297 socket_failure: 298 isc_mem_put(mctx, iter, sizeof(*iter)); 299 return (result); 300} 301 302/* 303 * Get information about the current interface to iter->current. 304 * If successful, return ISC_R_SUCCESS. 305 * If the interface has an unsupported address family, or if 306 * some operation on it fails, return ISC_R_IGNORE to make 307 * the higher-level iterator code ignore it. 308 */ 309 310static isc_result_t 311internal_current(isc_interfaceiter_t *iter) { 312 BOOL ifNamed = FALSE; 313 unsigned long flags; 314 315 REQUIRE(VALID_IFITER(iter)); 316 REQUIRE(iter->numIF >= 0); 317 318 memset(&iter->current, 0, sizeof(iter->current)); 319 iter->current.af = AF_INET; 320 321 get_addr(AF_INET, &iter->current.address, 322 (struct sockaddr *)&(iter->IFData.iiAddress)); 323 324 /* 325 * Get interface flags. 326 */ 327 328 iter->current.flags = 0; 329 flags = iter->IFData.iiFlags; 330 331 if ((flags & IFF_UP) != 0) 332 iter->current.flags |= INTERFACE_F_UP; 333 334 if ((flags & IFF_POINTTOPOINT) != 0) { 335 iter->current.flags |= INTERFACE_F_POINTTOPOINT; 336 sprintf(iter->current.name, "PPP Interface %d", iter->numIF); 337 ifNamed = TRUE; 338 } 339 340 if ((flags & IFF_LOOPBACK) != 0) { 341 iter->current.flags |= INTERFACE_F_LOOPBACK; 342 sprintf(iter->current.name, "Loopback Interface %d", 343 iter->numIF); 344 ifNamed = TRUE; 345 } 346 347 /* 348 * If the interface is point-to-point, get the destination address. 349 */ 350 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { 351 get_addr(AF_INET, &iter->current.dstaddress, 352 (struct sockaddr *)&(iter->IFData.iiBroadcastAddress)); 353 } 354 355 if (ifNamed == FALSE) 356 sprintf(iter->current.name, 357 "TCP/IP Interface %d", iter->numIF); 358 359 /* 360 * Get the network mask. 361 */ 362 get_addr(AF_INET, &iter->current.netmask, 363 (struct sockaddr *)&(iter->IFData.iiNetmask)); 364 365 return (ISC_R_SUCCESS); 366} 367 368static isc_result_t 369internal_current6(isc_interfaceiter_t *iter) { 370 BOOL ifNamed = FALSE; 371 int i; 372 373 REQUIRE(VALID_IFITER(iter)); 374 REQUIRE(iter->pos6 >= 0); 375 REQUIRE(iter->buf6 != 0); 376 377 memset(&iter->current, 0, sizeof(iter->current)); 378 iter->current.af = AF_INET6; 379 380 get_addr(AF_INET6, &iter->current.address, 381 iter->buf6->Address[iter->pos6].lpSockaddr); 382 383 /* 384 * Get interface flags. 385 */ 386 387 iter->current.flags = INTERFACE_F_UP; 388 389 if (ifNamed == FALSE) 390 sprintf(iter->current.name, 391 "TCP/IPv6 Interface %d", iter->pos6 + 1); 392 393 for (i = 0; i< 16; i++) 394 iter->current.netmask.type.in6.s6_addr[i] = 0xff; 395 iter->current.netmask.family = AF_INET6; 396 return (ISC_R_SUCCESS); 397} 398 399/* 400 * Step the iterator to the next interface. Unlike 401 * isc_interfaceiter_next(), this may leave the iterator 402 * positioned on an interface that will ultimately 403 * be ignored. Return ISC_R_NOMORE if there are no more 404 * interfaces, otherwise ISC_R_SUCCESS. 405 */ 406static isc_result_t 407internal_next(isc_interfaceiter_t *iter) { 408 if (iter->numIF >= iter->v4IF) 409 return (ISC_R_NOMORE); 410 411 /* 412 * The first one needs to be set up to point to the last 413 * Element of the array. Go to the end and back up 414 * Microsoft's implementation is peculiar for returning 415 * the list in reverse order 416 */ 417 418 if (iter->numIF == 0) 419 iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF)); 420 421 iter->pos4--; 422 if (&(iter->pos4) < &(iter->buf4)) 423 return (ISC_R_NOMORE); 424 425 memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO)); 426 memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO)); 427 iter->numIF++; 428 429 return (ISC_R_SUCCESS); 430} 431 432static isc_result_t 433internal_next6(isc_interfaceiter_t *iter) { 434 if (iter->pos6 == 0) 435 return (ISC_R_NOMORE); 436 iter->pos6--; 437 return (ISC_R_SUCCESS); 438} 439 440isc_result_t 441isc_interfaceiter_current(isc_interfaceiter_t *iter, 442 isc_interface_t *ifdata) { 443 REQUIRE(iter->result == ISC_R_SUCCESS); 444 memcpy(ifdata, &iter->current, sizeof(*ifdata)); 445 return (ISC_R_SUCCESS); 446} 447 448isc_result_t 449isc_interfaceiter_first(isc_interfaceiter_t *iter) { 450 451 REQUIRE(VALID_IFITER(iter)); 452 453 if (iter->buf6 != NULL) 454 iter->pos6 = iter->buf6->iAddressCount; 455 iter->result = ISC_R_SUCCESS; 456 return (isc_interfaceiter_next(iter)); 457} 458 459isc_result_t 460isc_interfaceiter_next(isc_interfaceiter_t *iter) { 461 isc_result_t result; 462 463 REQUIRE(VALID_IFITER(iter)); 464 REQUIRE(iter->result == ISC_R_SUCCESS); 465 466 for (;;) { 467 result = internal_next(iter); 468 if (result == ISC_R_NOMORE) { 469 result = internal_next6(iter); 470 if (result != ISC_R_SUCCESS) 471 break; 472 result = internal_current6(iter); 473 if (result != ISC_R_IGNORE) 474 break; 475 } else if (result != ISC_R_SUCCESS) 476 break; 477 result = internal_current(iter); 478 if (result != ISC_R_IGNORE) 479 break; 480 } 481 iter->result = result; 482 return (result); 483} 484 485void 486isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { 487 isc_interfaceiter_t *iter; 488 REQUIRE(iterp != NULL); 489 iter = *iterp; 490 REQUIRE(VALID_IFITER(iter)); 491 492 if (iter->buf4 != NULL) 493 isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); 494 if (iter->buf6 != NULL) 495 isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); 496 497 iter->magic = 0; 498 isc_mem_put(iter->mctx, iter, sizeof(*iter)); 499 *iterp = NULL; 500} 501