ifiter_sysctl.c revision 258945
129881Swollman/* 229881Swollman * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 329881Swollman * Copyright (C) 1999-2003 Internet Software Consortium. 429881Swollman * 529881Swollman * Permission to use, copy, modify, and/or distribute this software for any 629881Swollman * purpose with or without fee is hereby granted, provided that the above 729881Swollman * copyright notice and this permission notice appear in all copies. 829881Swollman * 929881Swollman * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 1029881Swollman * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 1129881Swollman * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 1229881Swollman * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 1329881Swollman * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 1429881Swollman * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 1529881Swollman * PERFORMANCE OF THIS SOFTWARE. 1629881Swollman */ 1729881Swollman 1829881Swollman/* $Id: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp $ */ 1929881Swollman 2029881Swollman/*! \file 2129881Swollman * \brief 2229881Swollman * Obtain the list of network interfaces using sysctl. 2329881Swollman * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14, 2429881Swollman * and 19.16. 2529881Swollman */ 2629881Swollman 2729881Swollman#include <sys/param.h> 2829881Swollman#include <sys/sysctl.h> 2929881Swollman 3029881Swollman#include <net/route.h> 3129881Swollman#include <net/if_dl.h> 3229881Swollman 3329881Swollman/* XXX what about Alpha? */ 34126229Sbde#ifdef sgi 35126229Sbde#define ROUNDUP(a) ((a) > 0 ? \ 36126229Sbde (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \ 37126229Sbde sizeof(__uint64_t)) 38126229Sbde#else 39126229Sbde#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 40126229Sbde : sizeof(long)) 41126229Sbde#endif 42126229Sbde 4387715Smarkm#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S') 4487715Smarkm#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC) 4587715Smarkm 4629881Swollmanstruct isc_interfaceiter { 4729881Swollman unsigned int magic; /* Magic number. */ 4829881Swollman isc_mem_t *mctx; 4929881Swollman void *buf; /* Buffer for sysctl data. */ 5029881Swollman unsigned int bufsize; /* Bytes allocated. */ 5129881Swollman unsigned int bufused; /* Bytes used. */ 5229881Swollman unsigned int pos; /* Current offset in 5329881Swollman sysctl data. */ 5429881Swollman isc_interface_t current; /* Current interface data. */ 5529881Swollman isc_result_t result; /* Last result code. */ 5629881Swollman}; 5729881Swollman 5829881Swollmanstatic int mib[6] = { 5929881Swollman CTL_NET, 6029881Swollman PF_ROUTE, 6129881Swollman 0, 6229881Swollman 0, /* Any address family. */ 6387715Smarkm NET_RT_IFLIST, 6429881Swollman 0 /* Flags. */ 6529881Swollman}; 6629881Swollman 6729881Swollmanisc_result_t 6829881Swollmanisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 6929881Swollman isc_interfaceiter_t *iter; 7029881Swollman isc_result_t result; 7129881Swollman size_t bufsize; 7229881Swollman size_t bufused; 73158160Sbde char strbuf[ISC_STRERRORSIZE]; 74158160Sbde 75158160Sbde REQUIRE(mctx != NULL); 76170780Sjhb REQUIRE(iterp != NULL); 77170780Sjhb REQUIRE(*iterp == NULL); 78170780Sjhb 79170780Sjhb iter = isc_mem_get(mctx, sizeof(*iter)); 80170780Sjhb if (iter == NULL) 81170780Sjhb return (ISC_R_NOMEMORY); 82170780Sjhb 83170780Sjhb iter->mctx = mctx; 84170780Sjhb iter->buf = 0; 85170780Sjhb 86170780Sjhb /* 87170780Sjhb * Determine the amount of memory needed. 88170780Sjhb */ 89170780Sjhb bufsize = 0; 90170780Sjhb if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) { 91170780Sjhb isc__strerror(errno, strbuf, sizeof(strbuf)); 92170780Sjhb UNEXPECTED_ERROR(__FILE__, __LINE__, 93170780Sjhb isc_msgcat_get(isc_msgcat, 9429881Swollman ISC_MSGSET_IFITERSYSCTL, 9529881Swollman ISC_MSG_GETIFLISTSIZE, 9629881Swollman "getting interface " 9729881Swollman "list size: sysctl: %s"), 9829881Swollman strbuf); 9929881Swollman result = ISC_R_UNEXPECTED; 10029881Swollman goto failure; 101158160Sbde } 10229881Swollman iter->bufsize = bufsize; 10329881Swollman 10429881Swollman iter->buf = isc_mem_get(iter->mctx, iter->bufsize); 10529881Swollman if (iter->buf == NULL) { 10629881Swollman result = ISC_R_NOMEMORY; 10729881Swollman goto failure; 10829881Swollman } 10929881Swollman 11029881Swollman bufused = bufsize; 11129881Swollman if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) { 112158160Sbde isc__strerror(errno, strbuf, sizeof(strbuf)); 11329881Swollman UNEXPECTED_ERROR(__FILE__, __LINE__, 11429881Swollman isc_msgcat_get(isc_msgcat, 11529881Swollman ISC_MSGSET_IFITERSYSCTL, 11629881Swollman ISC_MSG_GETIFLIST, 11729881Swollman "getting interface list: " 11829881Swollman "sysctl: %s"), 11929881Swollman strbuf); 12029881Swollman result = ISC_R_UNEXPECTED; 121158160Sbde goto failure; 122158160Sbde } 123158160Sbde iter->bufused = bufused; 124170780Sjhb INSIST(iter->bufused <= iter->bufsize); 125170780Sjhb 126170780Sjhb /* 127170780Sjhb * A newly created iterator has an undefined position 128170780Sjhb * until isc_interfaceiter_first() is called. 129170780Sjhb */ 130170780Sjhb iter->pos = (unsigned int) -1; 131170780Sjhb iter->result = ISC_R_FAILURE; 132170780Sjhb 133170780Sjhb iter->magic = IFITER_MAGIC; 134170780Sjhb *iterp = iter; 135170780Sjhb return (ISC_R_SUCCESS); 136170780Sjhb 137170780Sjhb failure: 138170780Sjhb if (iter->buf != NULL) 139170780Sjhb isc_mem_put(mctx, iter->buf, iter->bufsize); 140170780Sjhb isc_mem_put(mctx, iter, sizeof(*iter)); 141170780Sjhb return (result); 14229881Swollman} 14329881Swollman 14429881Swollman/* 14529881Swollman * Get information about the current interface to iter->current. 14629881Swollman * If successful, return ISC_R_SUCCESS. 14729881Swollman * If the interface has an unsupported address family, 14829881Swollman * return ISC_R_IGNORE. In case of other failure, 14929881Swollman * return ISC_R_UNEXPECTED. 15040060Sobrien */ 15129881Swollman 15229881Swollmanstatic isc_result_t 15329881Swollmaninternal_current(isc_interfaceiter_t *iter) { 15429881Swollman struct ifa_msghdr *ifam, *ifam_end; 15529881Swollman 15629881Swollman REQUIRE(VALID_IFITER(iter)); 15729881Swollman REQUIRE (iter->pos < (unsigned int) iter->bufused); 15829881Swollman 15929881Swollman ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos); 16029881Swollman ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused); 16129881Swollman 16229881Swollman if (ifam->ifam_type == RTM_IFINFO) { 16329881Swollman struct if_msghdr *ifm = (struct if_msghdr *) ifam; 16429881Swollman struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1); 16529881Swollman unsigned int namelen; 16629881Swollman 16729881Swollman memset(&iter->current, 0, sizeof(iter->current)); 16829881Swollman 16929881Swollman iter->current.ifindex = sdl->sdl_index; 17029881Swollman namelen = sdl->sdl_nlen; 17129881Swollman if (namelen > sizeof(iter->current.name) - 1) 17229881Swollman namelen = sizeof(iter->current.name) - 1; 17329881Swollman 17429881Swollman memset(iter->current.name, 0, sizeof(iter->current.name)); 17529881Swollman memcpy(iter->current.name, sdl->sdl_data, namelen); 17629881Swollman 17729881Swollman iter->current.flags = 0; 17829881Swollman 17929881Swollman if ((ifam->ifam_flags & IFF_UP) != 0) 18029881Swollman iter->current.flags |= INTERFACE_F_UP; 18129881Swollman 18229881Swollman if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0) 18329881Swollman iter->current.flags |= INTERFACE_F_POINTTOPOINT; 18429881Swollman 18529881Swollman if ((ifam->ifam_flags & IFF_LOOPBACK) != 0) 18629881Swollman iter->current.flags |= INTERFACE_F_LOOPBACK; 18729881Swollman 188170780Sjhb if ((ifam->ifam_flags & IFF_BROADCAST) != 0) 18929881Swollman iter->current.flags |= INTERFACE_F_BROADCAST; 19029881Swollman 19129881Swollman#ifdef IFF_MULTICAST 19229881Swollman if ((ifam->ifam_flags & IFF_MULTICAST) != 0) 19329881Swollman iter->current.flags |= INTERFACE_F_MULTICAST; 19429881Swollman#endif 19529881Swollman 19629881Swollman /* 19729881Swollman * This is not an interface address. 19829881Swollman * Force another iteration. 19929881Swollman */ 20029881Swollman return (ISC_R_IGNORE); 20129881Swollman } else if (ifam->ifam_type == RTM_NEWADDR) { 20229881Swollman int i; 20329881Swollman int family; 20429881Swollman struct sockaddr *mask_sa = NULL; 20529881Swollman struct sockaddr *addr_sa = NULL; 20629881Swollman struct sockaddr *dst_sa = NULL; 20729881Swollman 20829881Swollman struct sockaddr *sa = (struct sockaddr *)(ifam + 1); 20929881Swollman family = sa->sa_family; 21029881Swollman 21129881Swollman for (i = 0; i < RTAX_MAX; i++) 21229881Swollman { 21329881Swollman if ((ifam->ifam_addrs & (1 << i)) == 0) 21429881Swollman continue; 21529881Swollman 21629881Swollman INSIST(sa < (struct sockaddr *) ifam_end); 21729881Swollman 21829881Swollman switch (i) { 21929881Swollman case RTAX_NETMASK: /* Netmask */ 22029881Swollman mask_sa = sa; 22129881Swollman break; 22229881Swollman case RTAX_IFA: /* Interface address */ 22329881Swollman addr_sa = sa; 22429881Swollman break; 22529881Swollman case RTAX_BRD: /* Broadcast or destination address */ 22629881Swollman dst_sa = sa; 22729881Swollman break; 22829881Swollman } 22929881Swollman#ifdef ISC_PLATFORM_HAVESALEN 23029881Swollman sa = (struct sockaddr *)((char*)(sa) 23129881Swollman + ROUNDUP(sa->sa_len)); 232158161Sbde#else 23329881Swollman#ifdef sgi 23429881Swollman /* 23529881Swollman * Do as the contributed SGI code does. 23629881Swollman */ 23729881Swollman sa = (struct sockaddr *)((char*)(sa) 23829881Swollman + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 23929881Swollman#else 24029881Swollman /* XXX untested. */ 24129881Swollman sa = (struct sockaddr *)((char*)(sa) 24229881Swollman + ROUNDUP(sizeof(struct sockaddr))); 24329881Swollman#endif 24429881Swollman#endif 245158160Sbde } 246158160Sbde 247158160Sbde if (addr_sa == NULL) 248170780Sjhb return (ISC_R_IGNORE); 249170780Sjhb 250170780Sjhb family = addr_sa->sa_family; 251170780Sjhb if (family != AF_INET && family != AF_INET6) 252170780Sjhb return (ISC_R_IGNORE); 253170780Sjhb 254170780Sjhb iter->current.af = family; 255170780Sjhb 256170780Sjhb get_addr(family, &iter->current.address, addr_sa, 257170780Sjhb iter->current.name); 258170780Sjhb 259170780Sjhb if (mask_sa != NULL) 260170780Sjhb get_addr(family, &iter->current.netmask, mask_sa, 261170780Sjhb iter->current.name); 262170780Sjhb 263170780Sjhb if (dst_sa != NULL && 264170780Sjhb (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) 26529881Swollman get_addr(family, &iter->current.dstaddress, dst_sa, 26629881Swollman iter->current.name); 26729881Swollman 26829881Swollman if (dst_sa != NULL && 26929881Swollman (iter->current.flags & INTERFACE_F_BROADCAST) != 0) 27029881Swollman get_addr(family, &iter->current.broadcast, dst_sa, 27129881Swollman iter->current.name); 27229881Swollman 27329881Swollman return (ISC_R_SUCCESS); 27429881Swollman } else { 27529881Swollman printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL, 27629881Swollman ISC_MSG_UNEXPECTEDTYPE, 27729881Swollman "warning: unexpected interface list " 27829881Swollman "message type\n")); 27929881Swollman return (ISC_R_IGNORE); 28029881Swollman } 28129881Swollman} 28229881Swollman 28329881Swollman/* 28429881Swollman * Step the iterator to the next interface. Unlike 28529881Swollman * isc_interfaceiter_next(), this may leave the iterator 28629881Swollman * positioned on an interface that will ultimately 28729881Swollman * be ignored. Return ISC_R_NOMORE if there are no more 28829881Swollman * interfaces, otherwise ISC_R_SUCCESS. 28929881Swollman */ 29029881Swollmanstatic isc_result_t 29129881Swollmaninternal_next(isc_interfaceiter_t *iter) { 29229881Swollman struct ifa_msghdr *ifam; 29329881Swollman REQUIRE (iter->pos < (unsigned int) iter->bufused); 29429881Swollman 29529881Swollman ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos); 29629881Swollman 29729881Swollman iter->pos += ifam->ifam_msglen; 29829881Swollman 29929881Swollman if (iter->pos >= iter->bufused) 30029881Swollman return (ISC_R_NOMORE); 30129881Swollman 30229881Swollman return (ISC_R_SUCCESS); 30329881Swollman} 30429881Swollman 30529881Swollmanstatic void 30629881Swollmaninternal_destroy(isc_interfaceiter_t *iter) { 30729881Swollman UNUSED(iter); /* Unused. */ 30829881Swollman /* 30929881Swollman * Do nothing. 31029881Swollman */ 31129881Swollman} 31229881Swollman 31329881Swollmanstatic 31429881Swollmanvoid internal_first(isc_interfaceiter_t *iter) { 31529881Swollman iter->pos = 0; 31629881Swollman} 31729881Swollman