ifiter_getifaddrs.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007-2009, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: ifiter_getifaddrs.c,v 1.13 2009/09/24 23:48:13 tbox Exp $ */
00019 
00020 /*! \file
00021  * \brief
00022  * Obtain the list of network interfaces using the getifaddrs(3) library.
00023  */
00024 
00025 #include <ifaddrs.h>
00026 
00027 /*% Iterator Magic */
00028 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'G')
00029 /*% Valid Iterator */
00030 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
00031 
00032 #ifdef __linux
00033 static isc_boolean_t seenv6 = ISC_FALSE;
00034 #endif
00035 
00036 /*% Iterator structure */
00037 struct isc_interfaceiter {
00038         unsigned int            magic;          /*%< Magic number. */
00039         isc_mem_t               *mctx;
00040         void                    *buf;           /*%< (unused) */
00041         unsigned int            bufsize;        /*%< (always 0) */
00042         struct ifaddrs          *ifaddrs;       /*%< List of ifaddrs */
00043         struct ifaddrs          *pos;           /*%< Ptr to current ifaddr */
00044         isc_interface_t         current;        /*%< Current interface data. */
00045         isc_result_t            result;         /*%< Last result code. */
00046 #ifdef  __linux
00047         FILE *                  proc;
00048         char                    entry[ISC_IF_INET6_SZ];
00049         isc_result_t            valid;
00050 #endif
00051 };
00052 
00053 isc_result_t
00054 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
00055         isc_interfaceiter_t *iter;
00056         isc_result_t result;
00057         char strbuf[ISC_STRERRORSIZE];
00058 
00059         REQUIRE(mctx != NULL);
00060         REQUIRE(iterp != NULL);
00061         REQUIRE(*iterp == NULL);
00062 
00063         iter = isc_mem_get(mctx, sizeof(*iter));
00064         if (iter == NULL)
00065                 return (ISC_R_NOMEMORY);
00066 
00067         iter->mctx = mctx;
00068         iter->buf = NULL;
00069         iter->bufsize = 0;
00070         iter->ifaddrs = NULL;
00071 #ifdef __linux
00072         /*
00073          * Only open "/proc/net/if_inet6" if we have never seen a IPv6
00074          * address returned by getifaddrs().
00075          */
00076         if (!seenv6)
00077                 iter->proc = fopen("/proc/net/if_inet6", "r");
00078         else
00079                 iter->proc = NULL;
00080         iter->valid = ISC_R_FAILURE;
00081 #endif
00082 
00083         if (getifaddrs(&iter->ifaddrs) < 0) {
00084                 isc__strerror(errno, strbuf, sizeof(strbuf));
00085                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00086                                  isc_msgcat_get(isc_msgcat,
00087                                                 ISC_MSGSET_IFITERGETIFADDRS,
00088                                                 ISC_MSG_GETIFADDRS,
00089                                                 "getting interface "
00090                                                 "addresses: getifaddrs: %s"),
00091                                  strbuf);
00092                 result = ISC_R_UNEXPECTED;
00093                 goto failure;
00094         }
00095 
00096         /*
00097          * A newly created iterator has an undefined position
00098          * until isc_interfaceiter_first() is called.
00099          */
00100         iter->pos = NULL;
00101         iter->result = ISC_R_FAILURE;
00102 
00103         iter->magic = IFITER_MAGIC;
00104         *iterp = iter;
00105         return (ISC_R_SUCCESS);
00106 
00107  failure:
00108 #ifdef __linux
00109         if (iter->proc != NULL)
00110                 fclose(iter->proc);
00111 #endif
00112         if (iter->ifaddrs != NULL) /* just in case */
00113                 freeifaddrs(iter->ifaddrs);
00114         isc_mem_put(mctx, iter, sizeof(*iter));
00115         return (result);
00116 }
00117 
00118 /*
00119  * Get information about the current interface to iter->current.
00120  * If successful, return ISC_R_SUCCESS.
00121  * If the interface has an unsupported address family,
00122  * return ISC_R_IGNORE.
00123  */
00124 
00125 static isc_result_t
00126 internal_current(isc_interfaceiter_t *iter) {
00127         struct ifaddrs *ifa;
00128         int family;
00129         unsigned int namelen;
00130 
00131         REQUIRE(VALID_IFITER(iter));
00132 
00133         ifa = iter->pos;
00134 
00135 #ifdef __linux
00136         if (iter->pos == NULL)
00137                 return (linux_if_inet6_current(iter));
00138 #endif
00139 
00140         INSIST(ifa != NULL);
00141         INSIST(ifa->ifa_name != NULL);
00142 
00143         if (ifa->ifa_addr == NULL)
00144                 return (ISC_R_IGNORE);
00145 
00146         family = ifa->ifa_addr->sa_family;
00147         if (family != AF_INET && family != AF_INET6)
00148                 return (ISC_R_IGNORE);
00149 
00150 #ifdef __linux
00151         if (family == AF_INET6)
00152                 seenv6 = ISC_TRUE;
00153 #endif
00154 
00155         memset(&iter->current, 0, sizeof(iter->current));
00156 
00157         namelen = strlen(ifa->ifa_name);
00158         if (namelen > sizeof(iter->current.name) - 1)
00159                 namelen = sizeof(iter->current.name) - 1;
00160 
00161         memset(iter->current.name, 0, sizeof(iter->current.name));
00162         memmove(iter->current.name, ifa->ifa_name, namelen);
00163 
00164         iter->current.flags = 0;
00165 
00166         if ((ifa->ifa_flags & IFF_UP) != 0)
00167                 iter->current.flags |= INTERFACE_F_UP;
00168 
00169         if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
00170                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
00171 
00172         if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
00173                 iter->current.flags |= INTERFACE_F_LOOPBACK;
00174 
00175         iter->current.af = family;
00176 
00177         get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
00178 
00179         if (ifa->ifa_netmask != NULL)
00180                 get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
00181                          ifa->ifa_name);
00182 
00183         if (ifa->ifa_dstaddr != NULL &&
00184             (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
00185                 get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
00186                          ifa->ifa_name);
00187 
00188         return (ISC_R_SUCCESS);
00189 }
00190 
00191 /*
00192  * Step the iterator to the next interface.  Unlike
00193  * isc_interfaceiter_next(), this may leave the iterator
00194  * positioned on an interface that will ultimately
00195  * be ignored.  Return ISC_R_NOMORE if there are no more
00196  * interfaces, otherwise ISC_R_SUCCESS.
00197  */
00198 static isc_result_t
00199 internal_next(isc_interfaceiter_t *iter) {
00200 
00201         if (iter->pos != NULL)
00202                 iter->pos = iter->pos->ifa_next;
00203         if (iter->pos == NULL) {
00204 #ifdef __linux
00205                 if (!seenv6)
00206                         return (linux_if_inet6_next(iter));
00207 #endif
00208                 return (ISC_R_NOMORE);
00209         }
00210 
00211         return (ISC_R_SUCCESS);
00212 }
00213 
00214 static void
00215 internal_destroy(isc_interfaceiter_t *iter) {
00216 
00217 #ifdef __linux
00218         if (iter->proc != NULL)
00219                 fclose(iter->proc);
00220         iter->proc = NULL;
00221 #endif
00222         if (iter->ifaddrs)
00223                 freeifaddrs(iter->ifaddrs);
00224         iter->ifaddrs = NULL;
00225 }
00226 
00227 static
00228 void internal_first(isc_interfaceiter_t *iter) {
00229 
00230 #ifdef __linux
00231         linux_if_inet6_first(iter);
00232 #endif
00233         iter->pos = iter->ifaddrs;
00234 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha