1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2008, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <sys/types.h> 25135446Strhodes#include <sys/ioctl.h> 26135446Strhodes#ifdef HAVE_SYS_SOCKIO_H 27135446Strhodes#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ 28135446Strhodes#endif 29135446Strhodes 30135446Strhodes#include <stdio.h> 31135446Strhodes#include <stdlib.h> 32135446Strhodes#include <unistd.h> 33135446Strhodes#include <errno.h> 34135446Strhodes 35135446Strhodes#include <isc/interfaceiter.h> 36135446Strhodes#include <isc/log.h> 37135446Strhodes#include <isc/magic.h> 38135446Strhodes#include <isc/mem.h> 39135446Strhodes#include <isc/msgs.h> 40135446Strhodes#include <isc/net.h> 41135446Strhodes#include <isc/print.h> 42135446Strhodes#include <isc/result.h> 43135446Strhodes#include <isc/strerror.h> 44135446Strhodes#include <isc/string.h> 45135446Strhodes#include <isc/types.h> 46135446Strhodes#include <isc/util.h> 47135446Strhodes 48135446Strhodes/* Must follow <isc/net.h>. */ 49135446Strhodes#ifdef HAVE_NET_IF6_H 50135446Strhodes#include <net/if6.h> 51135446Strhodes#endif 52135446Strhodes#include <net/if.h> 53135446Strhodes 54135446Strhodes/* Common utility functions */ 55135446Strhodes 56170222Sdougb/*% 57135446Strhodes * Extract the network address part from a "struct sockaddr". 58170222Sdougb * \brief 59135446Strhodes * The address family is given explicitly 60135446Strhodes * instead of using src->sa_family, because the latter does not work 61135446Strhodes * for copying a network mask obtained by SIOCGIFNETMASK (it does 62135446Strhodes * not have a valid address family). 63135446Strhodes */ 64135446Strhodes 65135446Strhodesstatic void 66135446Strhodesget_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, 67135446Strhodes char *ifname) 68135446Strhodes{ 69135446Strhodes struct sockaddr_in6 *sa6; 70135446Strhodes 71135446Strhodes#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ 72135446Strhodes !defined(ISC_PLATFORM_HAVESCOPEID) 73135446Strhodes UNUSED(ifname); 74135446Strhodes#endif 75135446Strhodes 76135446Strhodes /* clear any remaining value for safety */ 77135446Strhodes memset(dst, 0, sizeof(*dst)); 78135446Strhodes 79135446Strhodes dst->family = family; 80135446Strhodes switch (family) { 81135446Strhodes case AF_INET: 82262706Serwin memmove(&dst->type.in, 83262706Serwin &((struct sockaddr_in *) src)->sin_addr, 84262706Serwin sizeof(struct in_addr)); 85135446Strhodes break; 86135446Strhodes case AF_INET6: 87135446Strhodes sa6 = (struct sockaddr_in6 *)src; 88262706Serwin memmove(&dst->type.in6, &sa6->sin6_addr, 89262706Serwin sizeof(struct in6_addr)); 90135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID 91135446Strhodes if (sa6->sin6_scope_id != 0) 92135446Strhodes isc_netaddr_setzone(dst, sa6->sin6_scope_id); 93135446Strhodes else { 94135446Strhodes /* 95135446Strhodes * BSD variants embed scope zone IDs in the 128bit 96135446Strhodes * address as a kernel internal form. Unfortunately, 97135446Strhodes * the embedded IDs are not hidden from applications 98135446Strhodes * when getting access to them by sysctl or ioctl. 99135446Strhodes * We convert the internal format to the pure address 100135446Strhodes * part and the zone ID part. 101135446Strhodes * Since multicast addresses should not appear here 102135446Strhodes * and they cannot be distinguished from netmasks, 103135446Strhodes * we only consider unicast link-local addresses. 104135446Strhodes */ 105135446Strhodes if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { 106135446Strhodes isc_uint16_t zone16; 107135446Strhodes 108262706Serwin memmove(&zone16, &sa6->sin6_addr.s6_addr[2], 109262706Serwin sizeof(zone16)); 110135446Strhodes zone16 = ntohs(zone16); 111135446Strhodes if (zone16 != 0) { 112135446Strhodes /* the zone ID is embedded */ 113135446Strhodes isc_netaddr_setzone(dst, 114135446Strhodes (isc_uint32_t)zone16); 115135446Strhodes dst->type.in6.s6_addr[2] = 0; 116135446Strhodes dst->type.in6.s6_addr[3] = 0; 117135446Strhodes#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX 118135446Strhodes } else if (ifname != NULL) { 119135446Strhodes unsigned int zone; 120135446Strhodes 121135446Strhodes /* 122135446Strhodes * sin6_scope_id is still not provided, 123135446Strhodes * but the corresponding interface name 124135446Strhodes * is know. Use the interface ID as 125135446Strhodes * the link ID. 126135446Strhodes */ 127135446Strhodes zone = if_nametoindex(ifname); 128135446Strhodes if (zone != 0) { 129135446Strhodes isc_netaddr_setzone(dst, 130135446Strhodes (isc_uint32_t)zone); 131135446Strhodes } 132135446Strhodes#endif 133135446Strhodes } 134135446Strhodes } 135135446Strhodes } 136135446Strhodes#endif 137135446Strhodes break; 138135446Strhodes default: 139135446Strhodes INSIST(0); 140135446Strhodes break; 141135446Strhodes } 142135446Strhodes} 143135446Strhodes 144135446Strhodes/* 145135446Strhodes * Include system-dependent code. 146135446Strhodes */ 147135446Strhodes 148193149Sdougb#ifdef __linux 149193149Sdougb#define ISC_IF_INET6_SZ \ 150193149Sdougb sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 151193149Sdougbstatic isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); 152193149Sdougbstatic isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); 153193149Sdougbstatic void linux_if_inet6_first(isc_interfaceiter_t *iter); 154193149Sdougb#endif 155193149Sdougb 156135446Strhodes#if HAVE_GETIFADDRS 157135446Strhodes#include "ifiter_getifaddrs.c" 158135446Strhodes#elif HAVE_IFLIST_SYSCTL 159135446Strhodes#include "ifiter_sysctl.c" 160135446Strhodes#else 161135446Strhodes#include "ifiter_ioctl.c" 162135446Strhodes#endif 163135446Strhodes 164193149Sdougb#ifdef __linux 165193149Sdougbstatic void 166193149Sdougblinux_if_inet6_first(isc_interfaceiter_t *iter) { 167193149Sdougb if (iter->proc != NULL) { 168193149Sdougb rewind(iter->proc); 169193149Sdougb (void)linux_if_inet6_next(iter); 170193149Sdougb } else 171193149Sdougb iter->valid = ISC_R_NOMORE; 172193149Sdougb} 173193149Sdougb 174193149Sdougbstatic isc_result_t 175193149Sdougblinux_if_inet6_next(isc_interfaceiter_t *iter) { 176193149Sdougb if (iter->proc != NULL && 177193149Sdougb fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 178193149Sdougb iter->valid = ISC_R_SUCCESS; 179193149Sdougb else 180193149Sdougb iter->valid = ISC_R_NOMORE; 181193149Sdougb return (iter->valid); 182193149Sdougb} 183193149Sdougb 184193149Sdougbstatic isc_result_t 185193149Sdougblinux_if_inet6_current(isc_interfaceiter_t *iter) { 186193149Sdougb char address[33]; 187193149Sdougb char name[IF_NAMESIZE+1]; 188193149Sdougb struct in6_addr addr6; 189193149Sdougb int ifindex, prefix, flag3, flag4; 190193149Sdougb int res; 191193149Sdougb unsigned int i; 192193149Sdougb 193193149Sdougb if (iter->valid != ISC_R_SUCCESS) 194193149Sdougb return (iter->valid); 195193149Sdougb if (iter->proc == NULL) { 196193149Sdougb isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 197193149Sdougb ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 198193149Sdougb "/proc/net/if_inet6:iter->proc == NULL"); 199193149Sdougb return (ISC_R_FAILURE); 200193149Sdougb } 201193149Sdougb 202193149Sdougb res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 203193149Sdougb address, &ifindex, &prefix, &flag3, &flag4, name); 204193149Sdougb if (res != 6) { 205193149Sdougb isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 206193149Sdougb ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 207193149Sdougb "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 208193149Sdougb res); 209193149Sdougb return (ISC_R_FAILURE); 210193149Sdougb } 211193149Sdougb if (strlen(address) != 32) { 212193149Sdougb isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 213193149Sdougb ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, 214193149Sdougb "/proc/net/if_inet6:strlen(%s) != 32", address); 215193149Sdougb return (ISC_R_FAILURE); 216193149Sdougb } 217193149Sdougb for (i = 0; i < 16; i++) { 218193149Sdougb unsigned char byte; 219193149Sdougb static const char hex[] = "0123456789abcdef"; 220193149Sdougb byte = ((strchr(hex, address[i * 2]) - hex) << 4) | 221193149Sdougb (strchr(hex, address[i * 2 + 1]) - hex); 222193149Sdougb addr6.s6_addr[i] = byte; 223193149Sdougb } 224193149Sdougb iter->current.af = AF_INET6; 225193149Sdougb iter->current.flags = INTERFACE_F_UP; 226193149Sdougb isc_netaddr_fromin6(&iter->current.address, &addr6); 227193149Sdougb if (isc_netaddr_islinklocal(&iter->current.address)) { 228193149Sdougb isc_netaddr_setzone(&iter->current.address, 229193149Sdougb (isc_uint32_t)ifindex); 230193149Sdougb } 231193149Sdougb for (i = 0; i < 16; i++) { 232193149Sdougb if (prefix > 8) { 233193149Sdougb addr6.s6_addr[i] = 0xff; 234193149Sdougb prefix -= 8; 235193149Sdougb } else { 236193149Sdougb addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 237193149Sdougb prefix = 0; 238193149Sdougb } 239193149Sdougb } 240193149Sdougb isc_netaddr_fromin6(&iter->current.netmask, &addr6); 241193149Sdougb strncpy(iter->current.name, name, sizeof(iter->current.name)); 242193149Sdougb return (ISC_R_SUCCESS); 243193149Sdougb} 244193149Sdougb#endif 245193149Sdougb 246135446Strhodes/* 247135446Strhodes * The remaining code is common to the sysctl and ioctl case. 248135446Strhodes */ 249135446Strhodes 250135446Strhodesisc_result_t 251135446Strhodesisc_interfaceiter_current(isc_interfaceiter_t *iter, 252135446Strhodes isc_interface_t *ifdata) 253135446Strhodes{ 254135446Strhodes REQUIRE(iter->result == ISC_R_SUCCESS); 255262706Serwin memmove(ifdata, &iter->current, sizeof(*ifdata)); 256135446Strhodes return (ISC_R_SUCCESS); 257135446Strhodes} 258135446Strhodes 259135446Strhodesisc_result_t 260135446Strhodesisc_interfaceiter_first(isc_interfaceiter_t *iter) { 261135446Strhodes isc_result_t result; 262135446Strhodes 263135446Strhodes REQUIRE(VALID_IFITER(iter)); 264135446Strhodes 265135446Strhodes internal_first(iter); 266135446Strhodes for (;;) { 267135446Strhodes result = internal_current(iter); 268135446Strhodes if (result != ISC_R_IGNORE) 269135446Strhodes break; 270135446Strhodes result = internal_next(iter); 271135446Strhodes if (result != ISC_R_SUCCESS) 272135446Strhodes break; 273135446Strhodes } 274135446Strhodes iter->result = result; 275135446Strhodes return (result); 276135446Strhodes} 277135446Strhodes 278135446Strhodesisc_result_t 279135446Strhodesisc_interfaceiter_next(isc_interfaceiter_t *iter) { 280135446Strhodes isc_result_t result; 281135446Strhodes 282135446Strhodes REQUIRE(VALID_IFITER(iter)); 283135446Strhodes REQUIRE(iter->result == ISC_R_SUCCESS); 284135446Strhodes 285135446Strhodes for (;;) { 286135446Strhodes result = internal_next(iter); 287135446Strhodes if (result != ISC_R_SUCCESS) 288135446Strhodes break; 289135446Strhodes result = internal_current(iter); 290135446Strhodes if (result != ISC_R_IGNORE) 291135446Strhodes break; 292135446Strhodes } 293135446Strhodes iter->result = result; 294135446Strhodes return (result); 295135446Strhodes} 296135446Strhodes 297135446Strhodesvoid 298135446Strhodesisc_interfaceiter_destroy(isc_interfaceiter_t **iterp) 299135446Strhodes{ 300135446Strhodes isc_interfaceiter_t *iter; 301135446Strhodes REQUIRE(iterp != NULL); 302135446Strhodes iter = *iterp; 303135446Strhodes REQUIRE(VALID_IFITER(iter)); 304135446Strhodes 305135446Strhodes internal_destroy(iter); 306135446Strhodes if (iter->buf != NULL) 307135446Strhodes isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 308135446Strhodes 309135446Strhodes iter->magic = 0; 310135446Strhodes isc_mem_put(iter->mctx, iter, sizeof(*iter)); 311135446Strhodes *iterp = NULL; 312135446Strhodes} 313