1/* $NetBSD: interfaceiter.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007, 2008 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#ifdef HAVE_LINUX_IF_ADDR_H 57# include <linux/if_addr.h> 58#endif 59 60/* Common utility functions */ 61 62/*% 63 * Extract the network address part from a "struct sockaddr". 64 * \brief 65 * The address family is given explicitly 66 * instead of using src->sa_family, because the latter does not work 67 * for copying a network mask obtained by SIOCGIFNETMASK (it does 68 * not have a valid address family). 69 */ 70 71static void 72get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 73 char *ifname) 74{ 75 struct sockaddr_in6 *sa6; 76 77#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 78 !defined(ISC_PLATFORM_HAVESCOPEID) 79 UNUSED(ifname); 80#endif 81 82 /* clear any remaining value for safety */ 83 memset(dst, 0, sizeof(*dst)); 84 85 dst->family = family; 86 switch (family) { 87 case AF_INET: 88 memcpy(&dst->type.in, 89 &((struct sockaddr_in *)(void *)src)->sin_addr, 90 sizeof(struct in_addr)); 91 break; 92 case AF_INET6: 93 sa6 = (struct sockaddr_in6 *)(void *)src; 94 memcpy(&dst->type.in6, &sa6->sin6_addr, 95 sizeof(struct in6_addr)); 96#ifdef ISC_PLATFORM_HAVESCOPEID 97 if (sa6->sin6_scope_id != 0) 98 isc_netaddr_setzone(dst, sa6->sin6_scope_id); 99 else { 100 /* 101 * BSD variants embed scope zone IDs in the 128bit 102 * address as a kernel internal form. Unfortunately, 103 * the embedded IDs are not hidden from applications 104 * when getting access to them by sysctl or ioctl. 105 * We convert the internal format to the pure address 106 * part and the zone ID part. 107 * Since multicast addresses should not appear here 108 * and they cannot be distinguished from netmasks, 109 * we only consider unicast link-local addresses. 110 */ 111 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 112 isc_uint16_t zone16; 113 114 memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], 115 sizeof(zone16)); 116 zone16 = ntohs(zone16); 117 if (zone16 != 0) { 118 /* the zone ID is embedded */ 119 isc_netaddr_setzone(dst, 120 (isc_uint32_t)zone16); 121 dst->type.in6.s6_addr[2] = 0; 122 dst->type.in6.s6_addr[3] = 0; 123#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 124 } else if (ifname != NULL) { 125 unsigned int zone; 126 127 /* 128 * sin6_scope_id is still not provided, 129 * but the corresponding interface name 130 * is know. Use the interface ID as 131 * the link ID. 132 */ 133 zone = if_nametoindex(ifname); 134 if (zone != 0) { 135 isc_netaddr_setzone(dst, 136 (isc_uint32_t)zone); 137 } 138#endif 139 } 140 } 141 } 142#endif 143 break; 144 default: 145 INSIST(0); 146 break; 147 } 148} 149 150/* 151 * Include system-dependent code. 152 */ 153 154#ifdef __linux 155#define ISC_IF_INET6_SZ \ 156 sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 157static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); 158static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); 159static void linux_if_inet6_first(isc_interfaceiter_t *iter); 160#endif 161 162#if HAVE_GETIFADDRS 163#include "ifiter_getifaddrs.c" 164#elif HAVE_IFLIST_SYSCTL 165#include "ifiter_sysctl.c" 166#else 167#include "ifiter_ioctl.c" 168#endif 169 170#ifdef __linux 171static void 172linux_if_inet6_first(isc_interfaceiter_t *iter) { 173 if (iter->proc != NULL) { 174 rewind(iter->proc); 175 (void)linux_if_inet6_next(iter); 176 } else 177 iter->valid = ISC_R_NOMORE; 178} 179 180static isc_result_t 181linux_if_inet6_next(isc_interfaceiter_t *iter) { 182 if (iter->proc != NULL && 183 fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 184 iter->valid = ISC_R_SUCCESS; 185 else 186 iter->valid = ISC_R_NOMORE; 187 return (iter->valid); 188} 189 190static isc_result_t 191linux_if_inet6_current(isc_interfaceiter_t *iter) { 192 char address[33]; 193 char name[IF_NAMESIZE+1]; 194 struct in6_addr addr6; 195 unsigned int ifindex; 196 int prefix, scope, flags; 197 int res; 198 unsigned int i; 199 200 if (iter->valid != ISC_R_SUCCESS) 201 return (iter->valid); 202 if (iter->proc == NULL) { 203 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 204 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 205 "/proc/net/if_inet6:iter->proc == NULL"); 206 return (ISC_R_FAILURE); 207 } 208 209 res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 210 address, &ifindex, &prefix, &scope, &flags, name); 211 if (res != 6) { 212 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 213 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 214 "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 215 res); 216 return (ISC_R_FAILURE); 217 } 218 if (strlen(address) != 32) { 219 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 220 ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 221 "/proc/net/if_inet6:strlen(%s) != 32", address); 222 return (ISC_R_FAILURE); 223 } 224 /* 225 ** Ignore DAD addresses -- 226 ** we can't bind to them until they are resolved 227 */ 228#ifdef IFA_F_TENTATIVE 229 if (flags & IFA_F_TENTATIVE) 230 return (ISC_R_IGNORE); 231#endif 232 233 for (i = 0; i < 16; i++) { 234 unsigned char byte; 235 static const char hex[] = "0123456789abcdef"; 236 byte = ((strchr(hex, address[i * 2]) - hex) << 4) | 237 (strchr(hex, address[i * 2 + 1]) - hex); 238 addr6.s6_addr[i] = byte; 239 } 240 iter->current.af = AF_INET6; 241 iter->current.flags = INTERFACE_F_UP; 242 isc_netaddr_fromin6(&iter->current.address, &addr6); 243 iter->current.ifindex = ifindex; 244 if (isc_netaddr_islinklocal(&iter->current.address)) { 245 isc_netaddr_setzone(&iter->current.address, 246 (isc_uint32_t)ifindex); 247 } 248 for (i = 0; i < 16; i++) { 249 if (prefix > 8) { 250 addr6.s6_addr[i] = 0xff; 251 prefix -= 8; 252 } else { 253 addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 254 prefix = 0; 255 } 256 } 257 isc_netaddr_fromin6(&iter->current.netmask, &addr6); 258 strncpy(iter->current.name, name, sizeof(iter->current.name)); 259 return (ISC_R_SUCCESS); 260} 261#endif 262 263/* 264 * The remaining code is common to the sysctl and ioctl case. 265 */ 266 267isc_result_t 268isc_interfaceiter_current(isc_interfaceiter_t *iter, 269 isc_interface_t *ifdata) 270{ 271 REQUIRE(iter->result == ISC_R_SUCCESS); 272 memcpy(ifdata, &iter->current, sizeof(*ifdata)); 273 return (ISC_R_SUCCESS); 274} 275 276isc_result_t 277isc_interfaceiter_first(isc_interfaceiter_t *iter) { 278 isc_result_t result; 279 280 REQUIRE(VALID_IFITER(iter)); 281 282 internal_first(iter); 283 for (;;) { 284 result = internal_current(iter); 285 if (result != ISC_R_IGNORE) 286 break; 287 result = internal_next(iter); 288 if (result != ISC_R_SUCCESS) 289 break; 290 } 291 iter->result = result; 292 return (result); 293} 294 295isc_result_t 296isc_interfaceiter_next(isc_interfaceiter_t *iter) { 297 isc_result_t result; 298 299 REQUIRE(VALID_IFITER(iter)); 300 REQUIRE(iter->result == ISC_R_SUCCESS); 301 302 for (;;) { 303 result = internal_next(iter); 304 if (result != ISC_R_SUCCESS) 305 break; 306 result = internal_current(iter); 307 if (result != ISC_R_IGNORE) 308 break; 309 } 310 iter->result = result; 311 return (result); 312} 313 314void 315isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 316{ 317 isc_interfaceiter_t *iter; 318 REQUIRE(iterp != NULL); 319 iter = *iterp; 320 REQUIRE(VALID_IFITER(iter)); 321 322 internal_destroy(iter); 323 if (iter->buf != NULL) 324 isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 325 326 iter->magic = 0; 327 isc_mem_put(iter->mctx, iter, sizeof(*iter)); 328 *iterp = NULL; 329} 330