/contrib/ntp/libisc/interfaceiter.c
C | 220 lines | 140 code | 28 blank | 52 comment | 28 complexity | b2711ff2be231b929598dbdfc8569faa MD5 | raw file
1/* 2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and 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.22.2.1.10.14 2004/08/28 06:25:22 marka Exp $ */ 19 20#include <config.h> 21 22#define ISC_ONLY_IPV6 23 24#include <sys/types.h> 25#include <sys/ioctl.h> 26#ifdef HAVE_SYS_SOCKIO_H 27#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ 28#endif 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33#include <errno.h> 34 35#include <isc/interfaceiter.h> 36#include <isc/magic.h> 37#include <isc/mem.h> 38#include <isc/msgs.h> 39#include <isc/net.h> 40#include <isc/print.h> 41#include <isc/result.h> 42#include <isc/strerror.h> 43#include <isc/string.h> 44#include <isc/types.h> 45#include <isc/util.h> 46 47/* Must follow <isc/net.h>. */ 48#ifdef HAVE_NET_IF6_H 49#include <net/if6.h> 50#endif 51 52/* Common utility functions */ 53 54/* 55 * Extract the network address part from a "struct sockaddr". 56 * 57 * The address family is given explicitly 58 * instead of using src->sa_family, because the latter does not work 59 * for copying a network mask obtained by SIOCGIFNETMASK (it does 60 * not have a valid address family). 61 */ 62 63static void 64get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 65 char *ifname) 66{ 67 struct sockaddr_in6 *sa6; 68 69#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 70 !defined(ISC_PLATFORM_HAVESCOPEID) 71 UNUSED(ifname); 72#endif 73 74 /* clear any remaining value for safety */ 75 memset(dst, 0, sizeof(*dst)); 76 77 dst->family = family; 78 switch (family) { 79 case AF_INET: 80 memcpy(&dst->type.in, 81 &((struct sockaddr_in *) src)->sin_addr, 82 sizeof(struct in_addr)); 83 break; 84 case AF_INET6: 85 sa6 = (struct sockaddr_in6 *)src; 86 memcpy(&dst->type.in6, &sa6->sin6_addr, 87 sizeof(struct in6_addr)); 88#ifdef ISC_PLATFORM_HAVESCOPEID 89 if (sa6->sin6_scope_id != 0) 90 isc_netaddr_setzone(dst, sa6->sin6_scope_id); 91 else { 92 /* 93 * BSD variants embed scope zone IDs in the 128bit 94 * address as a kernel internal form. Unfortunately, 95 * the embedded IDs are not hidden from applications 96 * when getting access to them by sysctl or ioctl. 97 * We convert the internal format to the pure address 98 * part and the zone ID part. 99 * Since multicast addresses should not appear here 100 * and they cannot be distinguished from netmasks, 101 * we only consider unicast link-local addresses. 102 */ 103 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 104 isc_uint16_t zone16; 105 106 memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], 107 sizeof(zone16)); 108 zone16 = ntohs(zone16); 109 if (zone16 != 0) { 110 /* the zone ID is embedded */ 111 isc_netaddr_setzone(dst, 112 (isc_uint32_t)zone16); 113 dst->type.in6.s6_addr[2] = 0; 114 dst->type.in6.s6_addr[3] = 0; 115#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 116 } else if (ifname != NULL) { 117 unsigned int zone; 118 119 /* 120 * sin6_scope_id is still not provided, 121 * but the corresponding interface name 122 * is know. Use the interface ID as 123 * the link ID. 124 */ 125 zone = if_nametoindex(ifname); 126 if (zone != 0) { 127 isc_netaddr_setzone(dst, 128 (isc_uint32_t)zone); 129 } 130#endif 131 } 132 } 133 } 134#endif 135 break; 136 default: 137 INSIST(0); 138 break; 139 } 140} 141 142/* 143 * Include system-dependent code. 144 */ 145 146#if HAVE_GETIFADDRS 147#include "ifiter_getifaddrs.c" 148#elif HAVE_IFLIST_SYSCTL 149#include "ifiter_sysctl.c" 150#else 151#include "ifiter_ioctl.c" 152#endif 153 154/* 155 * The remaining code is common to the sysctl and ioctl case. 156 */ 157 158isc_result_t 159isc_interfaceiter_current(isc_interfaceiter_t *iter, 160 isc_interface_t *ifdata) 161{ 162 REQUIRE(iter->result == ISC_R_SUCCESS); 163 memcpy(ifdata, &iter->current, sizeof(*ifdata)); 164 return (ISC_R_SUCCESS); 165} 166 167isc_result_t 168isc_interfaceiter_first(isc_interfaceiter_t *iter) { 169 isc_result_t result; 170 171 REQUIRE(VALID_IFITER(iter)); 172 173 internal_first(iter); 174 for (;;) { 175 result = internal_current(iter); 176 if (result != ISC_R_IGNORE) 177 break; 178 result = internal_next(iter); 179 if (result != ISC_R_SUCCESS) 180 break; 181 } 182 iter->result = result; 183 return (result); 184} 185 186isc_result_t 187isc_interfaceiter_next(isc_interfaceiter_t *iter) { 188 isc_result_t result; 189 190 REQUIRE(VALID_IFITER(iter)); 191 REQUIRE(iter->result == ISC_R_SUCCESS); 192 193 for (;;) { 194 result = internal_next(iter); 195 if (result != ISC_R_SUCCESS) 196 break; 197 result = internal_current(iter); 198 if (result != ISC_R_IGNORE) 199 break; 200 } 201 iter->result = result; 202 return (result); 203} 204 205void 206isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 207{ 208 isc_interfaceiter_t *iter; 209 REQUIRE(iterp != NULL); 210 iter = *iterp; 211 REQUIRE(VALID_IFITER(iter)); 212 213 internal_destroy(iter); 214 if (iter->buf != NULL) 215 isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 216 217 iter->magic = 0; 218 isc_mem_put(iter->mctx, iter, sizeof(*iter)); 219 *iterp = NULL; 220}