Annotation of embedaddon/ntp/lib/isc/unix/ifiter_getifaddrs.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 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: ifiter_getifaddrs.c,v 1.11 2008/03/20 23:47:00 tbox Exp $ */
! 19:
! 20: /*! \file
! 21: * \brief
! 22: * Obtain the list of network interfaces using the getifaddrs(3) library.
! 23: */
! 24:
! 25: #include <ifaddrs.h>
! 26:
! 27: /*% Iterator Magic */
! 28: #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
! 29: /*% Valid Iterator */
! 30: #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
! 31:
! 32: #ifdef __linux
! 33: static isc_boolean_t seenv6 = ISC_FALSE;
! 34: #endif
! 35:
! 36: /*% Iterator structure */
! 37: struct isc_interfaceiter {
! 38: unsigned int magic; /*%< Magic number. */
! 39: isc_mem_t *mctx;
! 40: void *buf; /*%< (unused) */
! 41: unsigned int bufsize; /*%< (always 0) */
! 42: struct ifaddrs *ifaddrs; /*%< List of ifaddrs */
! 43: struct ifaddrs *pos; /*%< Ptr to current ifaddr */
! 44: isc_interface_t current; /*%< Current interface data. */
! 45: isc_result_t result; /*%< Last result code. */
! 46: #ifdef __linux
! 47: FILE * proc;
! 48: char entry[ISC_IF_INET6_SZ];
! 49: isc_result_t valid;
! 50: #endif
! 51: };
! 52:
! 53: isc_result_t
! 54: isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
! 55: isc_interfaceiter_t *iter;
! 56: isc_result_t result;
! 57: char strbuf[ISC_STRERRORSIZE];
! 58:
! 59: REQUIRE(mctx != NULL);
! 60: REQUIRE(iterp != NULL);
! 61: REQUIRE(*iterp == NULL);
! 62:
! 63: iter = isc_mem_get(mctx, sizeof(*iter));
! 64: if (iter == NULL)
! 65: return (ISC_R_NOMEMORY);
! 66:
! 67: iter->mctx = mctx;
! 68: iter->buf = NULL;
! 69: iter->bufsize = 0;
! 70: iter->ifaddrs = NULL;
! 71: #ifdef __linux
! 72: /*
! 73: * Only open "/proc/net/if_inet6" if we have never seen a IPv6
! 74: * address returned by getifaddrs().
! 75: */
! 76: if (!seenv6)
! 77: iter->proc = fopen("/proc/net/if_inet6", "r");
! 78: else
! 79: iter->proc = NULL;
! 80: iter->valid = ISC_R_FAILURE;
! 81: #endif
! 82:
! 83: if (getifaddrs(&iter->ifaddrs) < 0) {
! 84: isc__strerror(errno, strbuf, sizeof(strbuf));
! 85: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 86: isc_msgcat_get(isc_msgcat,
! 87: ISC_MSGSET_IFITERGETIFADDRS,
! 88: ISC_MSG_GETIFADDRS,
! 89: "getting interface "
! 90: "addresses: getifaddrs: %s"),
! 91: strbuf);
! 92: result = ISC_R_UNEXPECTED;
! 93: goto failure;
! 94: }
! 95:
! 96: /*
! 97: * A newly created iterator has an undefined position
! 98: * until isc_interfaceiter_first() is called.
! 99: */
! 100: iter->pos = NULL;
! 101: iter->result = ISC_R_FAILURE;
! 102:
! 103: iter->magic = IFITER_MAGIC;
! 104: *iterp = iter;
! 105: return (ISC_R_SUCCESS);
! 106:
! 107: failure:
! 108: #ifdef __linux
! 109: if (iter->proc != NULL)
! 110: fclose(iter->proc);
! 111: #endif
! 112: if (iter->ifaddrs != NULL) /* just in case */
! 113: freeifaddrs(iter->ifaddrs);
! 114: isc_mem_put(mctx, iter, sizeof(*iter));
! 115: return (result);
! 116: }
! 117:
! 118: /*
! 119: * Get information about the current interface to iter->current.
! 120: * If successful, return ISC_R_SUCCESS.
! 121: * If the interface has an unsupported address family,
! 122: * return ISC_R_IGNORE.
! 123: */
! 124:
! 125: static isc_result_t
! 126: internal_current(isc_interfaceiter_t *iter) {
! 127: struct ifaddrs *ifa;
! 128: int family;
! 129: unsigned int namelen;
! 130:
! 131: REQUIRE(VALID_IFITER(iter));
! 132:
! 133: ifa = iter->pos;
! 134:
! 135: #ifdef __linux
! 136: if (iter->pos == NULL)
! 137: return (linux_if_inet6_current(iter));
! 138: #endif
! 139:
! 140: INSIST(ifa != NULL);
! 141: INSIST(ifa->ifa_name != NULL);
! 142:
! 143: if (ifa->ifa_addr == NULL)
! 144: return (ISC_R_IGNORE);
! 145:
! 146: family = ifa->ifa_addr->sa_family;
! 147: if (family != AF_INET && family != AF_INET6)
! 148: return (ISC_R_IGNORE);
! 149:
! 150: #ifdef __linux
! 151: if (family == AF_INET6)
! 152: seenv6 = ISC_TRUE;
! 153: #endif
! 154:
! 155: memset(&iter->current, 0, sizeof(iter->current));
! 156:
! 157: namelen = strlen(ifa->ifa_name);
! 158: if (namelen > sizeof(iter->current.name) - 1)
! 159: namelen = sizeof(iter->current.name) - 1;
! 160:
! 161: memset(iter->current.name, 0, sizeof(iter->current.name));
! 162: memcpy(iter->current.name, ifa->ifa_name, namelen);
! 163:
! 164: iter->current.flags = 0;
! 165:
! 166: if ((ifa->ifa_flags & IFF_UP) != 0)
! 167: iter->current.flags |= INTERFACE_F_UP;
! 168:
! 169: if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
! 170: iter->current.flags |= INTERFACE_F_POINTTOPOINT;
! 171:
! 172: if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
! 173: iter->current.flags |= INTERFACE_F_LOOPBACK;
! 174:
! 175: if ((ifa->ifa_flags & IFF_BROADCAST) != 0)
! 176: iter->current.flags |= INTERFACE_F_BROADCAST;
! 177:
! 178: #ifdef IFF_MULTICAST
! 179: if ((ifa->ifa_flags & IFF_MULTICAST) != 0)
! 180: iter->current.flags |= INTERFACE_F_MULTICAST;
! 181: #endif
! 182:
! 183: iter->current.af = family;
! 184:
! 185: get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
! 186:
! 187: if (ifa->ifa_netmask != NULL)
! 188: get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
! 189: ifa->ifa_name);
! 190:
! 191: if (ifa->ifa_dstaddr != NULL &&
! 192: (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
! 193: get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
! 194: ifa->ifa_name);
! 195:
! 196: if (ifa->ifa_broadaddr != NULL &&
! 197: (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
! 198: get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr,
! 199: ifa->ifa_name);
! 200:
! 201: return (ISC_R_SUCCESS);
! 202: }
! 203:
! 204: /*
! 205: * Step the iterator to the next interface. Unlike
! 206: * isc_interfaceiter_next(), this may leave the iterator
! 207: * positioned on an interface that will ultimately
! 208: * be ignored. Return ISC_R_NOMORE if there are no more
! 209: * interfaces, otherwise ISC_R_SUCCESS.
! 210: */
! 211: static isc_result_t
! 212: internal_next(isc_interfaceiter_t *iter) {
! 213:
! 214: if (iter->pos != NULL)
! 215: iter->pos = iter->pos->ifa_next;
! 216: if (iter->pos == NULL) {
! 217: #ifdef __linux
! 218: if (!seenv6)
! 219: return (linux_if_inet6_next(iter));
! 220: #endif
! 221: return (ISC_R_NOMORE);
! 222: }
! 223:
! 224: return (ISC_R_SUCCESS);
! 225: }
! 226:
! 227: static void
! 228: internal_destroy(isc_interfaceiter_t *iter) {
! 229:
! 230: #ifdef __linux
! 231: if (iter->proc != NULL)
! 232: fclose(iter->proc);
! 233: iter->proc = NULL;
! 234: #endif
! 235: if (iter->ifaddrs)
! 236: freeifaddrs(iter->ifaddrs);
! 237: iter->ifaddrs = NULL;
! 238: }
! 239:
! 240: static
! 241: void internal_first(isc_interfaceiter_t *iter) {
! 242:
! 243: #ifdef __linux
! 244: linux_if_inet6_first(iter);
! 245: #endif
! 246: iter->pos = iter->ifaddrs;
! 247: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>