1258945Sroberto/* 2280849Scy * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1999-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */ 19258945Sroberto 20258945Sroberto/*! \file */ 21258945Sroberto 22258945Sroberto#include <config.h> 23258945Sroberto 24258945Sroberto#include <sys/types.h> 25258945Sroberto#include <sys/ioctl.h> 26258945Sroberto#ifdef HAVE_SYS_SOCKIO_H 27258945Sroberto#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ 28258945Sroberto#endif 29258945Sroberto 30258945Sroberto#include <stdio.h> 31258945Sroberto#include <stdlib.h> 32258945Sroberto#include <unistd.h> 33258945Sroberto#include <errno.h> 34258945Sroberto 35258945Sroberto#include <isc/interfaceiter.h> 36258945Sroberto#include <isc/log.h> 37258945Sroberto#include <isc/magic.h> 38258945Sroberto#include <isc/mem.h> 39258945Sroberto#include <isc/msgs.h> 40258945Sroberto#include <isc/net.h> 41258945Sroberto#include <isc/print.h> 42258945Sroberto#include <isc/result.h> 43258945Sroberto#include <isc/strerror.h> 44258945Sroberto#include <isc/string.h> 45258945Sroberto#include <isc/types.h> 46258945Sroberto#include <isc/util.h> 47258945Sroberto 48258945Sroberto/* Must follow <isc/net.h>. */ 49258945Sroberto#ifdef HAVE_NET_IF6_H 50258945Sroberto#include <net/if6.h> 51258945Sroberto#endif 52258945Sroberto#include <net/if.h> 53258945Sroberto 54258945Sroberto#ifdef HAVE_LINUX_IF_ADDR_H 55258945Sroberto# include <linux/if_addr.h> 56258945Sroberto#endif 57258945Sroberto 58258945Sroberto/* Common utility functions */ 59258945Sroberto 60258945Sroberto/*% 61258945Sroberto * Extract the network address part from a "struct sockaddr". 62258945Sroberto * \brief 63258945Sroberto * The address family is given explicitly 64258945Sroberto * instead of using src->sa_family, because the latter does not work 65258945Sroberto * for copying a network mask obtained by SIOCGIFNETMASK (it does 66258945Sroberto * not have a valid address family). 67258945Sroberto */ 68258945Sroberto 69258945Srobertostatic void 70258945Srobertoget_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 71258945Sroberto char *ifname) 72258945Sroberto{ 73258945Sroberto struct sockaddr_in6 *sa6; 74258945Sroberto 75258945Sroberto#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 76258945Sroberto !defined(ISC_PLATFORM_HAVESCOPEID) 77258945Sroberto UNUSED(ifname); 78258945Sroberto#endif 79258945Sroberto 80258945Sroberto /* clear any remaining value for safety */ 81258945Sroberto memset(dst, 0, sizeof(*dst)); 82258945Sroberto 83258945Sroberto dst->family = family; 84258945Sroberto switch (family) { 85258945Sroberto case AF_INET: 86258945Sroberto memcpy(&dst->type.in, 87258945Sroberto &((struct sockaddr_in *)(void *)src)->sin_addr, 88258945Sroberto sizeof(struct in_addr)); 89258945Sroberto break; 90258945Sroberto case AF_INET6: 91258945Sroberto sa6 = (struct sockaddr_in6 *)(void *)src; 92258945Sroberto memcpy(&dst->type.in6, &sa6->sin6_addr, 93258945Sroberto sizeof(struct in6_addr)); 94258945Sroberto#ifdef ISC_PLATFORM_HAVESCOPEID 95258945Sroberto if (sa6->sin6_scope_id != 0) 96258945Sroberto isc_netaddr_setzone(dst, sa6->sin6_scope_id); 97258945Sroberto else { 98258945Sroberto /* 99258945Sroberto * BSD variants embed scope zone IDs in the 128bit 100258945Sroberto * address as a kernel internal form. Unfortunately, 101258945Sroberto * the embedded IDs are not hidden from applications 102258945Sroberto * when getting access to them by sysctl or ioctl. 103258945Sroberto * We convert the internal format to the pure address 104258945Sroberto * part and the zone ID part. 105258945Sroberto * Since multicast addresses should not appear here 106258945Sroberto * and they cannot be distinguished from netmasks, 107258945Sroberto * we only consider unicast link-local addresses. 108258945Sroberto */ 109258945Sroberto if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 110258945Sroberto isc_uint16_t zone16; 111258945Sroberto 112258945Sroberto memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], 113258945Sroberto sizeof(zone16)); 114258945Sroberto zone16 = ntohs(zone16); 115258945Sroberto if (zone16 != 0) { 116258945Sroberto /* the zone ID is embedded */ 117258945Sroberto isc_netaddr_setzone(dst, 118258945Sroberto (isc_uint32_t)zone16); 119258945Sroberto dst->type.in6.s6_addr[2] = 0; 120258945Sroberto dst->type.in6.s6_addr[3] = 0; 121258945Sroberto#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 122258945Sroberto } else if (ifname != NULL) { 123258945Sroberto unsigned int zone; 124258945Sroberto 125258945Sroberto /* 126258945Sroberto * sin6_scope_id is still not provided, 127258945Sroberto * but the corresponding interface name 128258945Sroberto * is know. Use the interface ID as 129258945Sroberto * the link ID. 130258945Sroberto */ 131258945Sroberto zone = if_nametoindex(ifname); 132258945Sroberto if (zone != 0) { 133258945Sroberto isc_netaddr_setzone(dst, 134258945Sroberto (isc_uint32_t)zone); 135258945Sroberto } 136258945Sroberto#endif 137258945Sroberto } 138258945Sroberto } 139258945Sroberto } 140258945Sroberto#endif 141258945Sroberto break; 142258945Sroberto default: 143258945Sroberto INSIST(0); 144258945Sroberto break; 145258945Sroberto } 146258945Sroberto} 147258945Sroberto 148258945Sroberto/* 149258945Sroberto * Include system-dependent code. 150258945Sroberto */ 151258945Sroberto 152258945Sroberto#ifdef __linux 153258945Sroberto#define ISC_IF_INET6_SZ \ 154258945Sroberto sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 155258945Srobertostatic isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); 156258945Srobertostatic isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); 157258945Srobertostatic void linux_if_inet6_first(isc_interfaceiter_t *iter); 158258945Sroberto#endif 159258945Sroberto 160258945Sroberto#if HAVE_GETIFADDRS 161258945Sroberto#include "ifiter_getifaddrs.c" 162258945Sroberto#elif HAVE_IFLIST_SYSCTL 163258945Sroberto#include "ifiter_sysctl.c" 164258945Sroberto#else 165258945Sroberto#include "ifiter_ioctl.c" 166258945Sroberto#endif 167258945Sroberto 168258945Sroberto#ifdef __linux 169258945Srobertostatic void 170258945Srobertolinux_if_inet6_first(isc_interfaceiter_t *iter) { 171258945Sroberto if (iter->proc != NULL) { 172258945Sroberto rewind(iter->proc); 173258945Sroberto (void)linux_if_inet6_next(iter); 174258945Sroberto } else 175258945Sroberto iter->valid = ISC_R_NOMORE; 176258945Sroberto} 177258945Sroberto 178258945Srobertostatic isc_result_t 179258945Srobertolinux_if_inet6_next(isc_interfaceiter_t *iter) { 180258945Sroberto if (iter->proc != NULL && 181258945Sroberto fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 182258945Sroberto iter->valid = ISC_R_SUCCESS; 183258945Sroberto else 184258945Sroberto iter->valid = ISC_R_NOMORE; 185258945Sroberto return (iter->valid); 186258945Sroberto} 187258945Sroberto 188258945Srobertostatic isc_result_t 189258945Srobertolinux_if_inet6_current(isc_interfaceiter_t *iter) { 190258945Sroberto char address[33]; 191258945Sroberto char name[IF_NAMESIZE+1]; 192258945Sroberto struct in6_addr addr6; 193258945Sroberto unsigned int ifindex; 194258945Sroberto int prefix, scope, flags; 195258945Sroberto int res; 196258945Sroberto unsigned int i; 197258945Sroberto 198258945Sroberto if (iter->valid != ISC_R_SUCCESS) 199258945Sroberto return (iter->valid); 200258945Sroberto if (iter->proc == NULL) { 201258945Sroberto isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 202258945Sroberto ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 203258945Sroberto "/proc/net/if_inet6:iter->proc == NULL"); 204258945Sroberto return (ISC_R_FAILURE); 205258945Sroberto } 206258945Sroberto 207258945Sroberto res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 208258945Sroberto address, &ifindex, &prefix, &scope, &flags, name); 209258945Sroberto if (res != 6) { 210258945Sroberto isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 211258945Sroberto ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 212258945Sroberto "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 213258945Sroberto res); 214258945Sroberto return (ISC_R_FAILURE); 215258945Sroberto } 216258945Sroberto if (strlen(address) != 32) { 217258945Sroberto isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 218258945Sroberto ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 219258945Sroberto "/proc/net/if_inet6:strlen(%s) != 32", address); 220258945Sroberto return (ISC_R_FAILURE); 221258945Sroberto } 222258945Sroberto /* 223258945Sroberto ** Ignore DAD addresses -- 224258945Sroberto ** we can't bind to them until they are resolved 225258945Sroberto */ 226258945Sroberto#ifdef IFA_F_TENTATIVE 227258945Sroberto if (flags & IFA_F_TENTATIVE) 228258945Sroberto return (ISC_R_IGNORE); 229258945Sroberto#endif 230258945Sroberto 231258945Sroberto for (i = 0; i < 16; i++) { 232258945Sroberto unsigned char byte; 233258945Sroberto static const char hex[] = "0123456789abcdef"; 234258945Sroberto byte = ((strchr(hex, address[i * 2]) - hex) << 4) | 235258945Sroberto (strchr(hex, address[i * 2 + 1]) - hex); 236258945Sroberto addr6.s6_addr[i] = byte; 237258945Sroberto } 238258945Sroberto iter->current.af = AF_INET6; 239280849Scy iter->current.flags = INTERFACE_F_UP; 240258945Sroberto isc_netaddr_fromin6(&iter->current.address, &addr6); 241258945Sroberto iter->current.ifindex = ifindex; 242258945Sroberto if (isc_netaddr_islinklocal(&iter->current.address)) { 243258945Sroberto isc_netaddr_setzone(&iter->current.address, 244258945Sroberto (isc_uint32_t)ifindex); 245258945Sroberto } 246258945Sroberto for (i = 0; i < 16; i++) { 247258945Sroberto if (prefix > 8) { 248258945Sroberto addr6.s6_addr[i] = 0xff; 249258945Sroberto prefix -= 8; 250258945Sroberto } else { 251258945Sroberto addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 252258945Sroberto prefix = 0; 253258945Sroberto } 254258945Sroberto } 255258945Sroberto isc_netaddr_fromin6(&iter->current.netmask, &addr6); 256258945Sroberto strncpy(iter->current.name, name, sizeof(iter->current.name)); 257258945Sroberto return (ISC_R_SUCCESS); 258258945Sroberto} 259258945Sroberto#endif 260258945Sroberto 261258945Sroberto/* 262258945Sroberto * The remaining code is common to the sysctl and ioctl case. 263258945Sroberto */ 264258945Sroberto 265258945Srobertoisc_result_t 266258945Srobertoisc_interfaceiter_current(isc_interfaceiter_t *iter, 267258945Sroberto isc_interface_t *ifdata) 268258945Sroberto{ 269258945Sroberto REQUIRE(iter->result == ISC_R_SUCCESS); 270258945Sroberto memcpy(ifdata, &iter->current, sizeof(*ifdata)); 271258945Sroberto return (ISC_R_SUCCESS); 272258945Sroberto} 273258945Sroberto 274258945Srobertoisc_result_t 275258945Srobertoisc_interfaceiter_first(isc_interfaceiter_t *iter) { 276258945Sroberto isc_result_t result; 277258945Sroberto 278258945Sroberto REQUIRE(VALID_IFITER(iter)); 279258945Sroberto 280258945Sroberto internal_first(iter); 281258945Sroberto for (;;) { 282258945Sroberto result = internal_current(iter); 283258945Sroberto if (result != ISC_R_IGNORE) 284258945Sroberto break; 285258945Sroberto result = internal_next(iter); 286258945Sroberto if (result != ISC_R_SUCCESS) 287258945Sroberto break; 288258945Sroberto } 289258945Sroberto iter->result = result; 290258945Sroberto return (result); 291258945Sroberto} 292258945Sroberto 293258945Srobertoisc_result_t 294258945Srobertoisc_interfaceiter_next(isc_interfaceiter_t *iter) { 295258945Sroberto isc_result_t result; 296258945Sroberto 297258945Sroberto REQUIRE(VALID_IFITER(iter)); 298258945Sroberto REQUIRE(iter->result == ISC_R_SUCCESS); 299258945Sroberto 300258945Sroberto for (;;) { 301258945Sroberto result = internal_next(iter); 302258945Sroberto if (result != ISC_R_SUCCESS) 303258945Sroberto break; 304258945Sroberto result = internal_current(iter); 305258945Sroberto if (result != ISC_R_IGNORE) 306258945Sroberto break; 307258945Sroberto } 308258945Sroberto iter->result = result; 309258945Sroberto return (result); 310258945Sroberto} 311258945Sroberto 312258945Srobertovoid 313258945Srobertoisc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 314258945Sroberto{ 315258945Sroberto isc_interfaceiter_t *iter; 316258945Sroberto REQUIRE(iterp != NULL); 317258945Sroberto iter = *iterp; 318258945Sroberto REQUIRE(VALID_IFITER(iter)); 319258945Sroberto 320258945Sroberto internal_destroy(iter); 321258945Sroberto if (iter->buf != NULL) 322258945Sroberto isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 323258945Sroberto 324258945Sroberto iter->magic = 0; 325258945Sroberto isc_mem_put(iter->mctx, iter, sizeof(*iter)); 326258945Sroberto *iterp = NULL; 327258945Sroberto} 328