interfaceiter.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2008, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-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: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <sys/types.h>
00025 #include <sys/ioctl.h>
00026 #ifdef HAVE_SYS_SOCKIO_H
00027 #include <sys/sockio.h>         /* Required for ifiter_ioctl.c. */
00028 #endif
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include <errno.h>
00034 
00035 #include <isc/interfaceiter.h>
00036 #include <isc/log.h>
00037 #include <isc/magic.h>
00038 #include <isc/mem.h>
00039 #include <isc/msgs.h>
00040 #include <isc/net.h>
00041 #include <isc/print.h>
00042 #include <isc/result.h>
00043 #include <isc/strerror.h>
00044 #include <isc/string.h>
00045 #include <isc/types.h>
00046 #include <isc/util.h>
00047 
00048 /* Must follow <isc/net.h>. */
00049 #ifdef HAVE_NET_IF6_H
00050 #include <net/if6.h>
00051 #endif
00052 #include <net/if.h>
00053 
00054 /* Common utility functions */
00055 
00056 /*%
00057  * Extract the network address part from a "struct sockaddr".
00058  * \brief
00059  * The address family is given explicitly
00060  * instead of using src->sa_family, because the latter does not work
00061  * for copying a network mask obtained by SIOCGIFNETMASK (it does
00062  * not have a valid address family).
00063  */
00064 
00065 static void
00066 get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
00067          char *ifname)
00068 {
00069         struct sockaddr_in6 *sa6;
00070 
00071 #if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
00072     !defined(ISC_PLATFORM_HAVESCOPEID)
00073         UNUSED(ifname);
00074 #endif
00075 
00076         /* clear any remaining value for safety */
00077         memset(dst, 0, sizeof(*dst));
00078 
00079         dst->family = family;
00080         switch (family) {
00081         case AF_INET:
00082                 memmove(&dst->type.in,
00083                         &((struct sockaddr_in *) src)->sin_addr,
00084                         sizeof(struct in_addr));
00085                 break;
00086         case AF_INET6:
00087                 sa6 = (struct sockaddr_in6 *)src;
00088                 memmove(&dst->type.in6, &sa6->sin6_addr,
00089                         sizeof(struct in6_addr));
00090 #ifdef ISC_PLATFORM_HAVESCOPEID
00091                 if (sa6->sin6_scope_id != 0)
00092                         isc_netaddr_setzone(dst, sa6->sin6_scope_id);
00093                 else {
00094                         /*
00095                          * BSD variants embed scope zone IDs in the 128bit
00096                          * address as a kernel internal form.  Unfortunately,
00097                          * the embedded IDs are not hidden from applications
00098                          * when getting access to them by sysctl or ioctl.
00099                          * We convert the internal format to the pure address
00100                          * part and the zone ID part.
00101                          * Since multicast addresses should not appear here
00102                          * and they cannot be distinguished from netmasks,
00103                          * we only consider unicast link-local addresses.
00104                          */
00105                         if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
00106                                 isc_uint16_t zone16;
00107 
00108                                 memmove(&zone16, &sa6->sin6_addr.s6_addr[2],
00109                                         sizeof(zone16));
00110                                 zone16 = ntohs(zone16);
00111                                 if (zone16 != 0) {
00112                                         /* the zone ID is embedded */
00113                                         isc_netaddr_setzone(dst,
00114                                                             (isc_uint32_t)zone16);
00115                                         dst->type.in6.s6_addr[2] = 0;
00116                                         dst->type.in6.s6_addr[3] = 0;
00117 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
00118                                 } else if (ifname != NULL) {
00119                                         unsigned int zone;
00120 
00121                                         /*
00122                                          * sin6_scope_id is still not provided,
00123                                          * but the corresponding interface name
00124                                          * is know.  Use the interface ID as
00125                                          * the link ID.
00126                                          */
00127                                         zone = if_nametoindex(ifname);
00128                                         if (zone != 0) {
00129                                                 isc_netaddr_setzone(dst,
00130                                                                     (isc_uint32_t)zone);
00131                                         }
00132 #endif
00133                                 }
00134                         }
00135                 }
00136 #endif
00137                 break;
00138         default:
00139                 INSIST(0);
00140                 break;
00141         }
00142 }
00143 
00144 /*
00145  * Include system-dependent code.
00146  */
00147 
00148 #ifdef __linux
00149 #define ISC_IF_INET6_SZ \
00150     sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
00151 static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
00152 static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
00153 static void linux_if_inet6_first(isc_interfaceiter_t *iter);
00154 #endif
00155 
00156 #if HAVE_GETIFADDRS
00157 #include "ifiter_getifaddrs.c"
00158 #elif HAVE_IFLIST_SYSCTL
00159 #include "ifiter_sysctl.c"
00160 #else
00161 #include "ifiter_ioctl.c"
00162 #endif
00163 
00164 #ifdef __linux
00165 static void
00166 linux_if_inet6_first(isc_interfaceiter_t *iter) {
00167         if (iter->proc != NULL) {
00168                 rewind(iter->proc);
00169                 (void)linux_if_inet6_next(iter);
00170         } else
00171                 iter->valid = ISC_R_NOMORE;
00172 }
00173 
00174 static isc_result_t
00175 linux_if_inet6_next(isc_interfaceiter_t *iter) {
00176         if (iter->proc != NULL &&
00177             fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
00178                 iter->valid = ISC_R_SUCCESS;
00179         else
00180                 iter->valid = ISC_R_NOMORE;
00181         return (iter->valid);
00182 }
00183 
00184 static isc_result_t
00185 linux_if_inet6_current(isc_interfaceiter_t *iter) {
00186         char address[33];
00187         char name[IF_NAMESIZE+1];
00188         struct in6_addr addr6;
00189         int ifindex, prefix, flag3, flag4;
00190         int res;
00191         unsigned int i;
00192 
00193         if (iter->valid != ISC_R_SUCCESS)
00194                 return (iter->valid);
00195         if (iter->proc == NULL) {
00196                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00197                               ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
00198                               "/proc/net/if_inet6:iter->proc == NULL");
00199                 return (ISC_R_FAILURE);
00200         }
00201 
00202         res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
00203                      address, &ifindex, &prefix, &flag3, &flag4, name);
00204         if (res != 6) {
00205                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00206                               ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
00207                               "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
00208                               res);
00209                 return (ISC_R_FAILURE);
00210         }
00211         if (strlen(address) != 32) {
00212                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00213                               ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
00214                               "/proc/net/if_inet6:strlen(%s) != 32", address);
00215                 return (ISC_R_FAILURE);
00216         }
00217         for (i = 0; i < 16; i++) {
00218                 unsigned char byte;
00219                 static const char hex[] = "0123456789abcdef";
00220                 byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
00221                        (strchr(hex, address[i * 2 + 1]) - hex);
00222                 addr6.s6_addr[i] = byte;
00223         }
00224         iter->current.af = AF_INET6;
00225         iter->current.flags = INTERFACE_F_UP;
00226         isc_netaddr_fromin6(&iter->current.address, &addr6);
00227         if (isc_netaddr_islinklocal(&iter->current.address)) {
00228                 isc_netaddr_setzone(&iter->current.address,
00229                                     (isc_uint32_t)ifindex);
00230         }
00231         for (i = 0; i < 16; i++) {
00232                 if (prefix > 8) {
00233                         addr6.s6_addr[i] = 0xff;
00234                         prefix -= 8;
00235                 } else {
00236                         addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
00237                         prefix = 0;
00238                 }
00239         }
00240         isc_netaddr_fromin6(&iter->current.netmask, &addr6);
00241         strncpy(iter->current.name, name, sizeof(iter->current.name));
00242         return (ISC_R_SUCCESS);
00243 }
00244 #endif
00245 
00246 /*
00247  * The remaining code is common to the sysctl and ioctl case.
00248  */
00249 
00250 isc_result_t
00251 isc_interfaceiter_current(isc_interfaceiter_t *iter,
00252                           isc_interface_t *ifdata)
00253 {
00254         REQUIRE(iter->result == ISC_R_SUCCESS);
00255         memmove(ifdata, &iter->current, sizeof(*ifdata));
00256         return (ISC_R_SUCCESS);
00257 }
00258 
00259 isc_result_t
00260 isc_interfaceiter_first(isc_interfaceiter_t *iter) {
00261         isc_result_t result;
00262 
00263         REQUIRE(VALID_IFITER(iter));
00264 
00265         internal_first(iter);
00266         for (;;) {
00267                 result = internal_current(iter);
00268                 if (result != ISC_R_IGNORE)
00269                         break;
00270                 result = internal_next(iter);
00271                 if (result != ISC_R_SUCCESS)
00272                         break;
00273         }
00274         iter->result = result;
00275         return (result);
00276 }
00277 
00278 isc_result_t
00279 isc_interfaceiter_next(isc_interfaceiter_t *iter) {
00280         isc_result_t result;
00281 
00282         REQUIRE(VALID_IFITER(iter));
00283         REQUIRE(iter->result == ISC_R_SUCCESS);
00284 
00285         for (;;) {
00286                 result = internal_next(iter);
00287                 if (result != ISC_R_SUCCESS)
00288                         break;
00289                 result = internal_current(iter);
00290                 if (result != ISC_R_IGNORE)
00291                         break;
00292         }
00293         iter->result = result;
00294         return (result);
00295 }
00296 
00297 void
00298 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
00299 {
00300         isc_interfaceiter_t *iter;
00301         REQUIRE(iterp != NULL);
00302         iter = *iterp;
00303         REQUIRE(VALID_IFITER(iter));
00304 
00305         internal_destroy(iter);
00306         if (iter->buf != NULL)
00307                 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
00308 
00309         iter->magic = 0;
00310         isc_mem_put(iter->mctx, iter, sizeof(*iter));
00311         *iterp = NULL;
00312 }

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