Annotation of embedaddon/ntp/lib/isc/unix/interfaceiter.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 1999-2003 Internet Software Consortium.
! 4: *
! 5: * Permission to use, copy, modify, and/or distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 15: * PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /* $Id: interfaceiter.c,v 1.44.120.2 2009/02/16 23:47:15 tbox Exp $ */
! 19:
! 20: /*! \file */
! 21:
! 22: #include <config.h>
! 23:
! 24: #include <sys/types.h>
! 25: #include <sys/ioctl.h>
! 26: #ifdef HAVE_SYS_SOCKIO_H
! 27: #include <sys/sockio.h> /* Required for ifiter_ioctl.c. */
! 28: #endif
! 29:
! 30: #include <stdio.h>
! 31: #include <stdlib.h>
! 32: #include <unistd.h>
! 33: #include <errno.h>
! 34:
! 35: #include <isc/interfaceiter.h>
! 36: #include <isc/log.h>
! 37: #include <isc/magic.h>
! 38: #include <isc/mem.h>
! 39: #include <isc/msgs.h>
! 40: #include <isc/net.h>
! 41: #include <isc/print.h>
! 42: #include <isc/result.h>
! 43: #include <isc/strerror.h>
! 44: #include <isc/string.h>
! 45: #include <isc/types.h>
! 46: #include <isc/util.h>
! 47:
! 48: /* Must follow <isc/net.h>. */
! 49: #ifdef HAVE_NET_IF6_H
! 50: #include <net/if6.h>
! 51: #endif
! 52: #include <net/if.h>
! 53:
! 54: #ifdef HAVE_LINUX_IF_ADDR_H
! 55: # include <linux/if_addr.h>
! 56: #endif
! 57:
! 58: /* Common utility functions */
! 59:
! 60: /*%
! 61: * Extract the network address part from a "struct sockaddr".
! 62: * \brief
! 63: * The address family is given explicitly
! 64: * instead of using src->sa_family, because the latter does not work
! 65: * for copying a network mask obtained by SIOCGIFNETMASK (it does
! 66: * not have a valid address family).
! 67: */
! 68:
! 69: static void
! 70: get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
! 71: char *ifname)
! 72: {
! 73: struct sockaddr_in6 *sa6;
! 74:
! 75: #if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
! 76: !defined(ISC_PLATFORM_HAVESCOPEID)
! 77: UNUSED(ifname);
! 78: #endif
! 79:
! 80: /* clear any remaining value for safety */
! 81: memset(dst, 0, sizeof(*dst));
! 82:
! 83: dst->family = family;
! 84: switch (family) {
! 85: case AF_INET:
! 86: memcpy(&dst->type.in,
! 87: &((struct sockaddr_in *)(void *)src)->sin_addr,
! 88: sizeof(struct in_addr));
! 89: break;
! 90: case AF_INET6:
! 91: sa6 = (struct sockaddr_in6 *)(void *)src;
! 92: memcpy(&dst->type.in6, &sa6->sin6_addr,
! 93: sizeof(struct in6_addr));
! 94: #ifdef ISC_PLATFORM_HAVESCOPEID
! 95: if (sa6->sin6_scope_id != 0)
! 96: isc_netaddr_setzone(dst, sa6->sin6_scope_id);
! 97: else {
! 98: /*
! 99: * BSD variants embed scope zone IDs in the 128bit
! 100: * address as a kernel internal form. Unfortunately,
! 101: * the embedded IDs are not hidden from applications
! 102: * when getting access to them by sysctl or ioctl.
! 103: * We convert the internal format to the pure address
! 104: * part and the zone ID part.
! 105: * Since multicast addresses should not appear here
! 106: * and they cannot be distinguished from netmasks,
! 107: * we only consider unicast link-local addresses.
! 108: */
! 109: if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
! 110: isc_uint16_t zone16;
! 111:
! 112: memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
! 113: sizeof(zone16));
! 114: zone16 = ntohs(zone16);
! 115: if (zone16 != 0) {
! 116: /* the zone ID is embedded */
! 117: isc_netaddr_setzone(dst,
! 118: (isc_uint32_t)zone16);
! 119: dst->type.in6.s6_addr[2] = 0;
! 120: dst->type.in6.s6_addr[3] = 0;
! 121: #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
! 122: } else if (ifname != NULL) {
! 123: unsigned int zone;
! 124:
! 125: /*
! 126: * sin6_scope_id is still not provided,
! 127: * but the corresponding interface name
! 128: * is know. Use the interface ID as
! 129: * the link ID.
! 130: */
! 131: zone = if_nametoindex(ifname);
! 132: if (zone != 0) {
! 133: isc_netaddr_setzone(dst,
! 134: (isc_uint32_t)zone);
! 135: }
! 136: #endif
! 137: }
! 138: }
! 139: }
! 140: #endif
! 141: break;
! 142: default:
! 143: INSIST(0);
! 144: break;
! 145: }
! 146: }
! 147:
! 148: /*
! 149: * Include system-dependent code.
! 150: */
! 151:
! 152: #ifdef __linux
! 153: #define ISC_IF_INET6_SZ \
! 154: sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
! 155: static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
! 156: static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
! 157: static void linux_if_inet6_first(isc_interfaceiter_t *iter);
! 158: #endif
! 159:
! 160: #if HAVE_GETIFADDRS
! 161: #include "ifiter_getifaddrs.c"
! 162: #elif HAVE_IFLIST_SYSCTL
! 163: #include "ifiter_sysctl.c"
! 164: #else
! 165: #include "ifiter_ioctl.c"
! 166: #endif
! 167:
! 168: #ifdef __linux
! 169: static void
! 170: linux_if_inet6_first(isc_interfaceiter_t *iter) {
! 171: if (iter->proc != NULL) {
! 172: rewind(iter->proc);
! 173: (void)linux_if_inet6_next(iter);
! 174: } else
! 175: iter->valid = ISC_R_NOMORE;
! 176: }
! 177:
! 178: static isc_result_t
! 179: linux_if_inet6_next(isc_interfaceiter_t *iter) {
! 180: if (iter->proc != NULL &&
! 181: fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
! 182: iter->valid = ISC_R_SUCCESS;
! 183: else
! 184: iter->valid = ISC_R_NOMORE;
! 185: return (iter->valid);
! 186: }
! 187:
! 188: static isc_result_t
! 189: linux_if_inet6_current(isc_interfaceiter_t *iter) {
! 190: char address[33];
! 191: char name[IF_NAMESIZE+1];
! 192: char strbuf[ISC_STRERRORSIZE];
! 193: struct in6_addr addr6;
! 194: unsigned int ifindex;
! 195: int prefix, scope, flags;
! 196: struct ifreq ifreq;
! 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 = 0;
! 242: memset(&ifreq, 0, sizeof(ifreq));
! 243: INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
! 244: strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
! 245:
! 246: if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
! 247: isc__strerror(errno, strbuf, sizeof(strbuf));
! 248: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 249: "%s: getting interface flags: %s",
! 250: ifreq.ifr_name, strbuf);
! 251: return (ISC_R_IGNORE);
! 252: }
! 253:
! 254: if ((ifreq.ifr_flags & IFF_UP) != 0)
! 255: iter->current.flags |= INTERFACE_F_UP;
! 256: #ifdef IFF_POINTOPOINT
! 257: if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
! 258: iter->current.flags |= INTERFACE_F_POINTTOPOINT;
! 259: #endif
! 260: if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
! 261: iter->current.flags |= INTERFACE_F_LOOPBACK;
! 262: if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
! 263: iter->current.flags |= INTERFACE_F_BROADCAST;
! 264: #ifdef IFF_MULTICAST
! 265: if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
! 266: iter->current.flags |= INTERFACE_F_MULTICAST;
! 267: #endif
! 268:
! 269: isc_netaddr_fromin6(&iter->current.address, &addr6);
! 270: iter->current.ifindex = ifindex;
! 271: if (isc_netaddr_islinklocal(&iter->current.address)) {
! 272: isc_netaddr_setzone(&iter->current.address,
! 273: (isc_uint32_t)ifindex);
! 274: }
! 275: for (i = 0; i < 16; i++) {
! 276: if (prefix > 8) {
! 277: addr6.s6_addr[i] = 0xff;
! 278: prefix -= 8;
! 279: } else {
! 280: addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
! 281: prefix = 0;
! 282: }
! 283: }
! 284: isc_netaddr_fromin6(&iter->current.netmask, &addr6);
! 285: strncpy(iter->current.name, name, sizeof(iter->current.name));
! 286: return (ISC_R_SUCCESS);
! 287: }
! 288: #endif
! 289:
! 290: /*
! 291: * The remaining code is common to the sysctl and ioctl case.
! 292: */
! 293:
! 294: isc_result_t
! 295: isc_interfaceiter_current(isc_interfaceiter_t *iter,
! 296: isc_interface_t *ifdata)
! 297: {
! 298: REQUIRE(iter->result == ISC_R_SUCCESS);
! 299: memcpy(ifdata, &iter->current, sizeof(*ifdata));
! 300: return (ISC_R_SUCCESS);
! 301: }
! 302:
! 303: isc_result_t
! 304: isc_interfaceiter_first(isc_interfaceiter_t *iter) {
! 305: isc_result_t result;
! 306:
! 307: REQUIRE(VALID_IFITER(iter));
! 308:
! 309: internal_first(iter);
! 310: for (;;) {
! 311: result = internal_current(iter);
! 312: if (result != ISC_R_IGNORE)
! 313: break;
! 314: result = internal_next(iter);
! 315: if (result != ISC_R_SUCCESS)
! 316: break;
! 317: }
! 318: iter->result = result;
! 319: return (result);
! 320: }
! 321:
! 322: isc_result_t
! 323: isc_interfaceiter_next(isc_interfaceiter_t *iter) {
! 324: isc_result_t result;
! 325:
! 326: REQUIRE(VALID_IFITER(iter));
! 327: REQUIRE(iter->result == ISC_R_SUCCESS);
! 328:
! 329: for (;;) {
! 330: result = internal_next(iter);
! 331: if (result != ISC_R_SUCCESS)
! 332: break;
! 333: result = internal_current(iter);
! 334: if (result != ISC_R_IGNORE)
! 335: break;
! 336: }
! 337: iter->result = result;
! 338: return (result);
! 339: }
! 340:
! 341: void
! 342: isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
! 343: {
! 344: isc_interfaceiter_t *iter;
! 345: REQUIRE(iterp != NULL);
! 346: iter = *iterp;
! 347: REQUIRE(VALID_IFITER(iter));
! 348:
! 349: internal_destroy(iter);
! 350: if (iter->buf != NULL)
! 351: isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
! 352:
! 353: iter->magic = 0;
! 354: isc_mem_put(iter->mctx, iter, sizeof(*iter));
! 355: *iterp = NULL;
! 356: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>