1290001Sglebius/* 2290001Sglebius * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * Copyright (C) 1999-2003 Internet Software Consortium. 4290001Sglebius * 5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 6290001Sglebius * purpose with or without fee is hereby granted, provided that the above 7290001Sglebius * copyright notice and this permission notice appear in all copies. 8290001Sglebius * 9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 16290001Sglebius */ 17290001Sglebius 18290001Sglebius/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */ 19290001Sglebius 20290001Sglebius/*! \file */ 21290001Sglebius 22290001Sglebius#include <config.h> 23290001Sglebius 24290001Sglebius#include <sys/types.h> 25290001Sglebius#include <sys/ioctl.h> 26290001Sglebius#ifdef HAVE_SYS_SOCKIO_H 27290001Sglebius#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ 28290001Sglebius#endif 29290001Sglebius 30290001Sglebius#include <stdio.h> 31290001Sglebius#include <stdlib.h> 32290001Sglebius#include <unistd.h> 33290001Sglebius#include <errno.h> 34290001Sglebius 35290001Sglebius#include <isc/interfaceiter.h> 36290001Sglebius#include <isc/log.h> 37290001Sglebius#include <isc/magic.h> 38290001Sglebius#include <isc/mem.h> 39290001Sglebius#include <isc/msgs.h> 40290001Sglebius#include <isc/net.h> 41290001Sglebius#include <isc/print.h> 42290001Sglebius#include <isc/result.h> 43290001Sglebius#include <isc/strerror.h> 44290001Sglebius#include <isc/string.h> 45290001Sglebius#include <isc/types.h> 46290001Sglebius#include <isc/util.h> 47290001Sglebius 48290001Sglebius/* Must follow <isc/net.h>. */ 49290001Sglebius#ifdef HAVE_NET_IF6_H 50290001Sglebius#include <net/if6.h> 51290001Sglebius#endif 52290001Sglebius#include <net/if.h> 53290001Sglebius 54290001Sglebius#ifdef HAVE_LINUX_IF_ADDR_H 55290001Sglebius# include <linux/if_addr.h> 56290001Sglebius#endif 57290001Sglebius 58290001Sglebius/* Common utility functions */ 59290001Sglebius 60290001Sglebius/*% 61290001Sglebius * Extract the network address part from a "struct sockaddr". 62290001Sglebius * \brief 63290001Sglebius * The address family is given explicitly 64290001Sglebius * instead of using src->sa_family, because the latter does not work 65290001Sglebius * for copying a network mask obtained by SIOCGIFNETMASK (it does 66290001Sglebius * not have a valid address family). 67290001Sglebius */ 68290001Sglebius 69290001Sglebiusstatic void 70290001Sglebiusget_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 71290001Sglebius char *ifname) 72290001Sglebius{ 73290001Sglebius struct sockaddr_in6 *sa6; 74290001Sglebius 75290001Sglebius#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 76290001Sglebius !defined(ISC_PLATFORM_HAVESCOPEID) 77290001Sglebius UNUSED(ifname); 78290001Sglebius#endif 79290001Sglebius 80290001Sglebius /* clear any remaining value for safety */ 81290001Sglebius memset(dst, 0, sizeof(*dst)); 82290001Sglebius 83290001Sglebius dst->family = family; 84290001Sglebius switch (family) { 85290001Sglebius case AF_INET: 86290001Sglebius memcpy(&dst->type.in, 87290001Sglebius &((struct sockaddr_in *)(void *)src)->sin_addr, 88290001Sglebius sizeof(struct in_addr)); 89290001Sglebius break; 90290001Sglebius case AF_INET6: 91290001Sglebius sa6 = (struct sockaddr_in6 *)(void *)src; 92290001Sglebius memcpy(&dst->type.in6, &sa6->sin6_addr, 93290001Sglebius sizeof(struct in6_addr)); 94290001Sglebius#ifdef ISC_PLATFORM_HAVESCOPEID 95290001Sglebius if (sa6->sin6_scope_id != 0) 96290001Sglebius isc_netaddr_setzone(dst, sa6->sin6_scope_id); 97290001Sglebius else { 98290001Sglebius /* 99290001Sglebius * BSD variants embed scope zone IDs in the 128bit 100290001Sglebius * address as a kernel internal form. Unfortunately, 101290001Sglebius * the embedded IDs are not hidden from applications 102290001Sglebius * when getting access to them by sysctl or ioctl. 103290001Sglebius * We convert the internal format to the pure address 104290001Sglebius * part and the zone ID part. 105290001Sglebius * Since multicast addresses should not appear here 106290001Sglebius * and they cannot be distinguished from netmasks, 107290001Sglebius * we only consider unicast link-local addresses. 108290001Sglebius */ 109290001Sglebius if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 110290001Sglebius isc_uint16_t zone16; 111290001Sglebius 112290001Sglebius memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], 113290001Sglebius sizeof(zone16)); 114290001Sglebius zone16 = ntohs(zone16); 115290001Sglebius if (zone16 != 0) { 116290001Sglebius /* the zone ID is embedded */ 117290001Sglebius isc_netaddr_setzone(dst, 118290001Sglebius (isc_uint32_t)zone16); 119290001Sglebius dst->type.in6.s6_addr[2] = 0; 120290001Sglebius dst->type.in6.s6_addr[3] = 0; 121290001Sglebius#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 122290001Sglebius } else if (ifname != NULL) { 123290001Sglebius unsigned int zone; 124290001Sglebius 125290001Sglebius /* 126290001Sglebius * sin6_scope_id is still not provided, 127290001Sglebius * but the corresponding interface name 128290001Sglebius * is know. Use the interface ID as 129290001Sglebius * the link ID. 130290001Sglebius */ 131290001Sglebius zone = if_nametoindex(ifname); 132290001Sglebius if (zone != 0) { 133290001Sglebius isc_netaddr_setzone(dst, 134290001Sglebius (isc_uint32_t)zone); 135290001Sglebius } 136290001Sglebius#endif 137290001Sglebius } 138290001Sglebius } 139290001Sglebius } 140290001Sglebius#endif 141290001Sglebius break; 142290001Sglebius default: 143290001Sglebius INSIST(0); 144290001Sglebius break; 145290001Sglebius } 146290001Sglebius} 147290001Sglebius 148290001Sglebius/* 149290001Sglebius * Include system-dependent code. 150290001Sglebius */ 151290001Sglebius 152290001Sglebius#ifdef __linux 153290001Sglebius#define ISC_IF_INET6_SZ \ 154290001Sglebius sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 155290001Sglebiusstatic isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); 156290001Sglebiusstatic isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); 157290001Sglebiusstatic void linux_if_inet6_first(isc_interfaceiter_t *iter); 158290001Sglebius#endif 159290001Sglebius 160290001Sglebius#if HAVE_GETIFADDRS 161290001Sglebius#include "ifiter_getifaddrs.c" 162290001Sglebius#elif HAVE_IFLIST_SYSCTL 163290001Sglebius#include "ifiter_sysctl.c" 164290001Sglebius#else 165290001Sglebius#include "ifiter_ioctl.c" 166290001Sglebius#endif 167290001Sglebius 168290001Sglebius#ifdef __linux 169290001Sglebiusstatic void 170290001Sglebiuslinux_if_inet6_first(isc_interfaceiter_t *iter) { 171290001Sglebius if (iter->proc != NULL) { 172290001Sglebius rewind(iter->proc); 173290001Sglebius (void)linux_if_inet6_next(iter); 174290001Sglebius } else 175290001Sglebius iter->valid = ISC_R_NOMORE; 176290001Sglebius} 177290001Sglebius 178290001Sglebiusstatic isc_result_t 179290001Sglebiuslinux_if_inet6_next(isc_interfaceiter_t *iter) { 180290001Sglebius if (iter->proc != NULL && 181290001Sglebius fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 182290001Sglebius iter->valid = ISC_R_SUCCESS; 183290001Sglebius else 184290001Sglebius iter->valid = ISC_R_NOMORE; 185290001Sglebius return (iter->valid); 186290001Sglebius} 187290001Sglebius 188290001Sglebiusstatic isc_result_t 189290001Sglebiuslinux_if_inet6_current(isc_interfaceiter_t *iter) { 190290001Sglebius char address[33]; 191290001Sglebius char name[IF_NAMESIZE+1]; 192290001Sglebius struct in6_addr addr6; 193290001Sglebius unsigned int ifindex; 194290001Sglebius int prefix, scope, flags; 195290001Sglebius int res; 196290001Sglebius unsigned int i; 197290001Sglebius 198290001Sglebius if (iter->valid != ISC_R_SUCCESS) 199290001Sglebius return (iter->valid); 200290001Sglebius if (iter->proc == NULL) { 201290001Sglebius isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 202290001Sglebius ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 203290001Sglebius "/proc/net/if_inet6:iter->proc == NULL"); 204290001Sglebius return (ISC_R_FAILURE); 205290001Sglebius } 206290001Sglebius 207290001Sglebius res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 208290001Sglebius address, &ifindex, &prefix, &scope, &flags, name); 209290001Sglebius if (res != 6) { 210290001Sglebius isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 211290001Sglebius ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 212290001Sglebius "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 213290001Sglebius res); 214290001Sglebius return (ISC_R_FAILURE); 215290001Sglebius } 216290001Sglebius if (strlen(address) != 32) { 217290001Sglebius isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 218290001Sglebius ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 219290001Sglebius "/proc/net/if_inet6:strlen(%s) != 32", address); 220290001Sglebius return (ISC_R_FAILURE); 221290001Sglebius } 222290001Sglebius /* 223290001Sglebius ** Ignore DAD addresses -- 224290001Sglebius ** we can't bind to them until they are resolved 225290001Sglebius */ 226290001Sglebius#ifdef IFA_F_TENTATIVE 227290001Sglebius if (flags & IFA_F_TENTATIVE) 228290001Sglebius return (ISC_R_IGNORE); 229290001Sglebius#endif 230290001Sglebius 231290001Sglebius for (i = 0; i < 16; i++) { 232290001Sglebius unsigned char byte; 233290001Sglebius static const char hex[] = "0123456789abcdef"; 234290001Sglebius byte = ((strchr(hex, address[i * 2]) - hex) << 4) | 235290001Sglebius (strchr(hex, address[i * 2 + 1]) - hex); 236290001Sglebius addr6.s6_addr[i] = byte; 237290001Sglebius } 238290001Sglebius iter->current.af = AF_INET6; 239290001Sglebius iter->current.flags = INTERFACE_F_UP; 240290001Sglebius isc_netaddr_fromin6(&iter->current.address, &addr6); 241290001Sglebius iter->current.ifindex = ifindex; 242290001Sglebius if (isc_netaddr_islinklocal(&iter->current.address)) { 243290001Sglebius isc_netaddr_setzone(&iter->current.address, 244290001Sglebius (isc_uint32_t)ifindex); 245290001Sglebius } 246290001Sglebius for (i = 0; i < 16; i++) { 247290001Sglebius if (prefix > 8) { 248290001Sglebius addr6.s6_addr[i] = 0xff; 249290001Sglebius prefix -= 8; 250290001Sglebius } else { 251290001Sglebius addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 252290001Sglebius prefix = 0; 253290001Sglebius } 254290001Sglebius } 255290001Sglebius isc_netaddr_fromin6(&iter->current.netmask, &addr6); 256290001Sglebius strncpy(iter->current.name, name, sizeof(iter->current.name)); 257290001Sglebius return (ISC_R_SUCCESS); 258290001Sglebius} 259290001Sglebius#endif 260290001Sglebius 261290001Sglebius/* 262290001Sglebius * The remaining code is common to the sysctl and ioctl case. 263290001Sglebius */ 264290001Sglebius 265290001Sglebiusisc_result_t 266290001Sglebiusisc_interfaceiter_current(isc_interfaceiter_t *iter, 267290001Sglebius isc_interface_t *ifdata) 268290001Sglebius{ 269290001Sglebius REQUIRE(iter->result == ISC_R_SUCCESS); 270290001Sglebius memcpy(ifdata, &iter->current, sizeof(*ifdata)); 271290001Sglebius return (ISC_R_SUCCESS); 272290001Sglebius} 273290001Sglebius 274290001Sglebiusisc_result_t 275290001Sglebiusisc_interfaceiter_first(isc_interfaceiter_t *iter) { 276290001Sglebius isc_result_t result; 277290001Sglebius 278290001Sglebius REQUIRE(VALID_IFITER(iter)); 279290001Sglebius 280290001Sglebius internal_first(iter); 281290001Sglebius for (;;) { 282290001Sglebius result = internal_current(iter); 283290001Sglebius if (result != ISC_R_IGNORE) 284290001Sglebius break; 285290001Sglebius result = internal_next(iter); 286290001Sglebius if (result != ISC_R_SUCCESS) 287290001Sglebius break; 288290001Sglebius } 289290001Sglebius iter->result = result; 290290001Sglebius return (result); 291290001Sglebius} 292290001Sglebius 293290001Sglebiusisc_result_t 294290001Sglebiusisc_interfaceiter_next(isc_interfaceiter_t *iter) { 295290001Sglebius isc_result_t result; 296290001Sglebius 297290001Sglebius REQUIRE(VALID_IFITER(iter)); 298290001Sglebius REQUIRE(iter->result == ISC_R_SUCCESS); 299290001Sglebius 300290001Sglebius for (;;) { 301290001Sglebius result = internal_next(iter); 302290001Sglebius if (result != ISC_R_SUCCESS) 303290001Sglebius break; 304290001Sglebius result = internal_current(iter); 305290001Sglebius if (result != ISC_R_IGNORE) 306290001Sglebius break; 307290001Sglebius } 308290001Sglebius iter->result = result; 309290001Sglebius return (result); 310290001Sglebius} 311290001Sglebius 312290001Sglebiusvoid 313290001Sglebiusisc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 314290001Sglebius{ 315290001Sglebius isc_interfaceiter_t *iter; 316290001Sglebius REQUIRE(iterp != NULL); 317290001Sglebius iter = *iterp; 318290001Sglebius REQUIRE(VALID_IFITER(iter)); 319290001Sglebius 320290001Sglebius internal_destroy(iter); 321290001Sglebius if (iter->buf != NULL) 322290001Sglebius isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 323290001Sglebius 324290001Sglebius iter->magic = 0; 325290001Sglebius isc_mem_put(iter->mctx, iter, sizeof(*iter)); 326290001Sglebius *iterp = NULL; 327290001Sglebius} 328