1 /* $NetBSD: interfaceiter.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2008, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <sys/types.h> 27 #include <sys/ioctl.h> 28 #ifdef HAVE_SYS_SOCKIO_H 29 #include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ 30 #endif 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <errno.h> 36 37 #include <isc/interfaceiter.h> 38 #include <isc/log.h> 39 #include <isc/magic.h> 40 #include <isc/mem.h> 41 #include <isc/msgs.h> 42 #include <isc/net.h> 43 #include <isc/print.h> 44 #include <isc/result.h> 45 #include <isc/strerror.h> 46 #include <isc/string.h> 47 #include <isc/types.h> 48 #include <isc/util.h> 49 50 /* Must follow <isc/net.h>. */ 51 #ifdef HAVE_NET_IF6_H 52 #include <net/if6.h> 53 #endif 54 #include <net/if.h> 55 56 /* Common utility functions */ 57 58 /*% 59 * Extract the network address part from a "struct sockaddr". 60 * \brief 61 * The address family is given explicitly 62 * instead of using src->sa_family, because the latter does not work 63 * for copying a network mask obtained by SIOCGIFNETMASK (it does 64 * not have a valid address family). 65 */ 66 67 static void 68 get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 69 char *ifname) 70 { 71 struct sockaddr_in6 *sa6; 72 73 #if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 74 !defined(ISC_PLATFORM_HAVESCOPEID) 75 UNUSED(ifname); 76 #endif 77 78 /* clear any remaining value for safety */ 79 memset(dst, 0, sizeof(*dst)); 80 81 dst->family = family; 82 switch (family) { 83 case AF_INET: 84 memmove(&dst->type.in, 85 &((struct sockaddr_in *) src)->sin_addr, 86 sizeof(struct in_addr)); 87 break; 88 case AF_INET6: 89 sa6 = (struct sockaddr_in6 *)src; 90 memmove(&dst->type.in6, &sa6->sin6_addr, 91 sizeof(struct in6_addr)); 92 #ifdef ISC_PLATFORM_HAVESCOPEID 93 if (sa6->sin6_scope_id != 0) 94 isc_netaddr_setzone(dst, sa6->sin6_scope_id); 95 else { 96 /* 97 * BSD variants embed scope zone IDs in the 128bit 98 * address as a kernel internal form. Unfortunately, 99 * the embedded IDs are not hidden from applications 100 * when getting access to them by sysctl or ioctl. 101 * We convert the internal format to the pure address 102 * part and the zone ID part. 103 * Since multicast addresses should not appear here 104 * and they cannot be distinguished from netmasks, 105 * we only consider unicast link-local addresses. 106 */ 107 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 108 isc_uint16_t zone16; 109 110 memmove(&zone16, &sa6->sin6_addr.s6_addr[2], 111 sizeof(zone16)); 112 zone16 = ntohs(zone16); 113 if (zone16 != 0) { 114 /* the zone ID is embedded */ 115 isc_netaddr_setzone(dst, 116 (isc_uint32_t)zone16); 117 dst->type.in6.s6_addr[2] = 0; 118 dst->type.in6.s6_addr[3] = 0; 119 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 120 } else if (ifname != NULL) { 121 unsigned int zone; 122 123 /* 124 * sin6_scope_id is still not provided, 125 * but the corresponding interface name 126 * is know. Use the interface ID as 127 * the link ID. 128 */ 129 zone = if_nametoindex(ifname); 130 if (zone != 0) { 131 isc_netaddr_setzone(dst, 132 (isc_uint32_t)zone); 133 } 134 #endif 135 } 136 } 137 } 138 #endif 139 break; 140 default: 141 INSIST(0); 142 break; 143 } 144 } 145 146 /* 147 * Include system-dependent code. 148 */ 149 150 #ifdef __linux 151 #define ISC_IF_INET6_SZ \ 152 sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 153 static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); 154 static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); 155 static void linux_if_inet6_first(isc_interfaceiter_t *iter); 156 #endif 157 158 #if HAVE_GETIFADDRS 159 #include "ifiter_getifaddrs.c" 160 #elif HAVE_IFLIST_SYSCTL 161 #include "ifiter_sysctl.c" 162 #else 163 #include "ifiter_ioctl.c" 164 #endif 165 166 #ifdef __linux 167 static void 168 linux_if_inet6_first(isc_interfaceiter_t *iter) { 169 if (iter->proc != NULL) { 170 rewind(iter->proc); 171 (void)linux_if_inet6_next(iter); 172 } else 173 iter->valid = ISC_R_NOMORE; 174 } 175 176 static isc_result_t 177 linux_if_inet6_next(isc_interfaceiter_t *iter) { 178 if (iter->proc != NULL && 179 fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 180 iter->valid = ISC_R_SUCCESS; 181 else 182 iter->valid = ISC_R_NOMORE; 183 return (iter->valid); 184 } 185 186 static isc_result_t 187 linux_if_inet6_current(isc_interfaceiter_t *iter) { 188 char address[33]; 189 char name[IF_NAMESIZE+1]; 190 struct in6_addr addr6; 191 int ifindex, prefix, flag3, flag4; 192 int res; 193 unsigned int i; 194 195 if (iter->valid != ISC_R_SUCCESS) 196 return (iter->valid); 197 if (iter->proc == NULL) { 198 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 199 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 200 "/proc/net/if_inet6:iter->proc == NULL"); 201 return (ISC_R_FAILURE); 202 } 203 204 res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 205 address, &ifindex, &prefix, &flag3, &flag4, name); 206 if (res != 6) { 207 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 208 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 209 "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 210 res); 211 return (ISC_R_FAILURE); 212 } 213 if (strlen(address) != 32) { 214 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 215 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 216 "/proc/net/if_inet6:strlen(%s) != 32", address); 217 return (ISC_R_FAILURE); 218 } 219 for (i = 0; i < 16; i++) { 220 unsigned char byte; 221 static const char hex[] = "0123456789abcdef"; 222 byte = ((strchr(hex, address[i * 2]) - hex) << 4) | 223 (strchr(hex, address[i * 2 + 1]) - hex); 224 addr6.s6_addr[i] = byte; 225 } 226 iter->current.af = AF_INET6; 227 iter->current.flags = INTERFACE_F_UP; 228 isc_netaddr_fromin6(&iter->current.address, &addr6); 229 if (isc_netaddr_islinklocal(&iter->current.address)) { 230 isc_netaddr_setzone(&iter->current.address, 231 (isc_uint32_t)ifindex); 232 } 233 for (i = 0; i < 16; i++) { 234 if (prefix > 8) { 235 addr6.s6_addr[i] = 0xff; 236 prefix -= 8; 237 } else { 238 addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 239 prefix = 0; 240 } 241 } 242 isc_netaddr_fromin6(&iter->current.netmask, &addr6); 243 strncpy(iter->current.name, name, sizeof(iter->current.name)); 244 return (ISC_R_SUCCESS); 245 } 246 #endif 247 248 /* 249 * The remaining code is common to the sysctl and ioctl case. 250 */ 251 252 isc_result_t 253 isc_interfaceiter_current(isc_interfaceiter_t *iter, 254 isc_interface_t *ifdata) 255 { 256 REQUIRE(iter->result == ISC_R_SUCCESS); 257 memmove(ifdata, &iter->current, sizeof(*ifdata)); 258 return (ISC_R_SUCCESS); 259 } 260 261 isc_result_t 262 isc_interfaceiter_first(isc_interfaceiter_t *iter) { 263 isc_result_t result; 264 265 REQUIRE(VALID_IFITER(iter)); 266 267 internal_first(iter); 268 for (;;) { 269 result = internal_current(iter); 270 if (result != ISC_R_IGNORE) 271 break; 272 result = internal_next(iter); 273 if (result != ISC_R_SUCCESS) 274 break; 275 } 276 iter->result = result; 277 return (result); 278 } 279 280 isc_result_t 281 isc_interfaceiter_next(isc_interfaceiter_t *iter) { 282 isc_result_t result; 283 284 REQUIRE(VALID_IFITER(iter)); 285 REQUIRE(iter->result == ISC_R_SUCCESS); 286 287 for (;;) { 288 result = internal_next(iter); 289 if (result != ISC_R_SUCCESS) 290 break; 291 result = internal_current(iter); 292 if (result != ISC_R_IGNORE) 293 break; 294 } 295 iter->result = result; 296 return (result); 297 } 298 299 void 300 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 301 { 302 isc_interfaceiter_t *iter; 303 REQUIRE(iterp != NULL); 304 iter = *iterp; 305 REQUIRE(VALID_IFITER(iter)); 306 307 internal_destroy(iter); 308 if (iter->buf != NULL) 309 isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 310 311 iter->magic = 0; 312 isc_mem_put(iter->mctx, iter, sizeof(*iter)); 313 *iterp = NULL; 314 } 315