Annotation of embedaddon/ntp/lib/isc/unix/ifiter_sysctl.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004, 2005, 2007 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: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp $ */
! 19:
! 20: /*! \file
! 21: * \brief
! 22: * Obtain the list of network interfaces using sysctl.
! 23: * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
! 24: * and 19.16.
! 25: */
! 26:
! 27: #include <sys/param.h>
! 28: #include <sys/sysctl.h>
! 29:
! 30: #include <net/route.h>
! 31: #include <net/if_dl.h>
! 32:
! 33: /* XXX what about Alpha? */
! 34: #ifdef sgi
! 35: #define ROUNDUP(a) ((a) > 0 ? \
! 36: (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \
! 37: sizeof(__uint64_t))
! 38: #else
! 39: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
! 40: : sizeof(long))
! 41: #endif
! 42:
! 43: #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S')
! 44: #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
! 45:
! 46: struct isc_interfaceiter {
! 47: unsigned int magic; /* Magic number. */
! 48: isc_mem_t *mctx;
! 49: void *buf; /* Buffer for sysctl data. */
! 50: unsigned int bufsize; /* Bytes allocated. */
! 51: unsigned int bufused; /* Bytes used. */
! 52: unsigned int pos; /* Current offset in
! 53: sysctl data. */
! 54: isc_interface_t current; /* Current interface data. */
! 55: isc_result_t result; /* Last result code. */
! 56: };
! 57:
! 58: static int mib[6] = {
! 59: CTL_NET,
! 60: PF_ROUTE,
! 61: 0,
! 62: 0, /* Any address family. */
! 63: NET_RT_IFLIST,
! 64: 0 /* Flags. */
! 65: };
! 66:
! 67: isc_result_t
! 68: isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
! 69: isc_interfaceiter_t *iter;
! 70: isc_result_t result;
! 71: size_t bufsize;
! 72: size_t bufused;
! 73: char strbuf[ISC_STRERRORSIZE];
! 74:
! 75: REQUIRE(mctx != NULL);
! 76: REQUIRE(iterp != NULL);
! 77: REQUIRE(*iterp == NULL);
! 78:
! 79: iter = isc_mem_get(mctx, sizeof(*iter));
! 80: if (iter == NULL)
! 81: return (ISC_R_NOMEMORY);
! 82:
! 83: iter->mctx = mctx;
! 84: iter->buf = 0;
! 85:
! 86: /*
! 87: * Determine the amount of memory needed.
! 88: */
! 89: bufsize = 0;
! 90: if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
! 91: isc__strerror(errno, strbuf, sizeof(strbuf));
! 92: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 93: isc_msgcat_get(isc_msgcat,
! 94: ISC_MSGSET_IFITERSYSCTL,
! 95: ISC_MSG_GETIFLISTSIZE,
! 96: "getting interface "
! 97: "list size: sysctl: %s"),
! 98: strbuf);
! 99: result = ISC_R_UNEXPECTED;
! 100: goto failure;
! 101: }
! 102: iter->bufsize = bufsize;
! 103:
! 104: iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
! 105: if (iter->buf == NULL) {
! 106: result = ISC_R_NOMEMORY;
! 107: goto failure;
! 108: }
! 109:
! 110: bufused = bufsize;
! 111: if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
! 112: isc__strerror(errno, strbuf, sizeof(strbuf));
! 113: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 114: isc_msgcat_get(isc_msgcat,
! 115: ISC_MSGSET_IFITERSYSCTL,
! 116: ISC_MSG_GETIFLIST,
! 117: "getting interface list: "
! 118: "sysctl: %s"),
! 119: strbuf);
! 120: result = ISC_R_UNEXPECTED;
! 121: goto failure;
! 122: }
! 123: iter->bufused = bufused;
! 124: INSIST(iter->bufused <= iter->bufsize);
! 125:
! 126: /*
! 127: * A newly created iterator has an undefined position
! 128: * until isc_interfaceiter_first() is called.
! 129: */
! 130: iter->pos = (unsigned int) -1;
! 131: iter->result = ISC_R_FAILURE;
! 132:
! 133: iter->magic = IFITER_MAGIC;
! 134: *iterp = iter;
! 135: return (ISC_R_SUCCESS);
! 136:
! 137: failure:
! 138: if (iter->buf != NULL)
! 139: isc_mem_put(mctx, iter->buf, iter->bufsize);
! 140: isc_mem_put(mctx, iter, sizeof(*iter));
! 141: return (result);
! 142: }
! 143:
! 144: /*
! 145: * Get information about the current interface to iter->current.
! 146: * If successful, return ISC_R_SUCCESS.
! 147: * If the interface has an unsupported address family,
! 148: * return ISC_R_IGNORE. In case of other failure,
! 149: * return ISC_R_UNEXPECTED.
! 150: */
! 151:
! 152: static isc_result_t
! 153: internal_current(isc_interfaceiter_t *iter) {
! 154: struct ifa_msghdr *ifam, *ifam_end;
! 155:
! 156: REQUIRE(VALID_IFITER(iter));
! 157: REQUIRE (iter->pos < (unsigned int) iter->bufused);
! 158:
! 159: ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
! 160: ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
! 161:
! 162: if (ifam->ifam_type == RTM_IFINFO) {
! 163: struct if_msghdr *ifm = (struct if_msghdr *) ifam;
! 164: struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
! 165: unsigned int namelen;
! 166:
! 167: memset(&iter->current, 0, sizeof(iter->current));
! 168:
! 169: iter->current.ifindex = sdl->sdl_index;
! 170: namelen = sdl->sdl_nlen;
! 171: if (namelen > sizeof(iter->current.name) - 1)
! 172: namelen = sizeof(iter->current.name) - 1;
! 173:
! 174: memset(iter->current.name, 0, sizeof(iter->current.name));
! 175: memcpy(iter->current.name, sdl->sdl_data, namelen);
! 176:
! 177: iter->current.flags = 0;
! 178:
! 179: if ((ifam->ifam_flags & IFF_UP) != 0)
! 180: iter->current.flags |= INTERFACE_F_UP;
! 181:
! 182: if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
! 183: iter->current.flags |= INTERFACE_F_POINTTOPOINT;
! 184:
! 185: if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
! 186: iter->current.flags |= INTERFACE_F_LOOPBACK;
! 187:
! 188: if ((ifam->ifam_flags & IFF_BROADCAST) != 0)
! 189: iter->current.flags |= INTERFACE_F_BROADCAST;
! 190:
! 191: #ifdef IFF_MULTICAST
! 192: if ((ifam->ifam_flags & IFF_MULTICAST) != 0)
! 193: iter->current.flags |= INTERFACE_F_MULTICAST;
! 194: #endif
! 195:
! 196: /*
! 197: * This is not an interface address.
! 198: * Force another iteration.
! 199: */
! 200: return (ISC_R_IGNORE);
! 201: } else if (ifam->ifam_type == RTM_NEWADDR) {
! 202: int i;
! 203: int family;
! 204: struct sockaddr *mask_sa = NULL;
! 205: struct sockaddr *addr_sa = NULL;
! 206: struct sockaddr *dst_sa = NULL;
! 207:
! 208: struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
! 209: family = sa->sa_family;
! 210:
! 211: for (i = 0; i < RTAX_MAX; i++)
! 212: {
! 213: if ((ifam->ifam_addrs & (1 << i)) == 0)
! 214: continue;
! 215:
! 216: INSIST(sa < (struct sockaddr *) ifam_end);
! 217:
! 218: switch (i) {
! 219: case RTAX_NETMASK: /* Netmask */
! 220: mask_sa = sa;
! 221: break;
! 222: case RTAX_IFA: /* Interface address */
! 223: addr_sa = sa;
! 224: break;
! 225: case RTAX_BRD: /* Broadcast or destination address */
! 226: dst_sa = sa;
! 227: break;
! 228: }
! 229: #ifdef ISC_PLATFORM_HAVESALEN
! 230: sa = (struct sockaddr *)((char*)(sa)
! 231: + ROUNDUP(sa->sa_len));
! 232: #else
! 233: #ifdef sgi
! 234: /*
! 235: * Do as the contributed SGI code does.
! 236: */
! 237: sa = (struct sockaddr *)((char*)(sa)
! 238: + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
! 239: #else
! 240: /* XXX untested. */
! 241: sa = (struct sockaddr *)((char*)(sa)
! 242: + ROUNDUP(sizeof(struct sockaddr)));
! 243: #endif
! 244: #endif
! 245: }
! 246:
! 247: if (addr_sa == NULL)
! 248: return (ISC_R_IGNORE);
! 249:
! 250: family = addr_sa->sa_family;
! 251: if (family != AF_INET && family != AF_INET6)
! 252: return (ISC_R_IGNORE);
! 253:
! 254: iter->current.af = family;
! 255:
! 256: get_addr(family, &iter->current.address, addr_sa,
! 257: iter->current.name);
! 258:
! 259: if (mask_sa != NULL)
! 260: get_addr(family, &iter->current.netmask, mask_sa,
! 261: iter->current.name);
! 262:
! 263: if (dst_sa != NULL &&
! 264: (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
! 265: get_addr(family, &iter->current.dstaddress, dst_sa,
! 266: iter->current.name);
! 267:
! 268: if (dst_sa != NULL &&
! 269: (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
! 270: get_addr(family, &iter->current.broadcast, dst_sa,
! 271: iter->current.name);
! 272:
! 273: return (ISC_R_SUCCESS);
! 274: } else {
! 275: printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
! 276: ISC_MSG_UNEXPECTEDTYPE,
! 277: "warning: unexpected interface list "
! 278: "message type\n"));
! 279: return (ISC_R_IGNORE);
! 280: }
! 281: }
! 282:
! 283: /*
! 284: * Step the iterator to the next interface. Unlike
! 285: * isc_interfaceiter_next(), this may leave the iterator
! 286: * positioned on an interface that will ultimately
! 287: * be ignored. Return ISC_R_NOMORE if there are no more
! 288: * interfaces, otherwise ISC_R_SUCCESS.
! 289: */
! 290: static isc_result_t
! 291: internal_next(isc_interfaceiter_t *iter) {
! 292: struct ifa_msghdr *ifam;
! 293: REQUIRE (iter->pos < (unsigned int) iter->bufused);
! 294:
! 295: ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
! 296:
! 297: iter->pos += ifam->ifam_msglen;
! 298:
! 299: if (iter->pos >= iter->bufused)
! 300: return (ISC_R_NOMORE);
! 301:
! 302: return (ISC_R_SUCCESS);
! 303: }
! 304:
! 305: static void
! 306: internal_destroy(isc_interfaceiter_t *iter) {
! 307: UNUSED(iter); /* Unused. */
! 308: /*
! 309: * Do nothing.
! 310: */
! 311: }
! 312:
! 313: static
! 314: void internal_first(isc_interfaceiter_t *iter) {
! 315: iter->pos = 0;
! 316: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>