ifiter_ioctl.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 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: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */
00019 
00020 /*! \file
00021  * \brief
00022  * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
00023  * See netintro(4).
00024  */
00025 
00026 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00027 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
00028 #define lifc_len iflc_len
00029 #define lifc_buf iflc_buf
00030 #define lifc_req iflc_req
00031 #define LIFCONF if_laddrconf
00032 #else
00033 #define ISC_HAVE_LIFC_FAMILY 1
00034 #define ISC_HAVE_LIFC_FLAGS 1
00035 #define LIFCONF lifconf
00036 #endif
00037 
00038 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
00039 #define lifr_addr iflr_addr
00040 #define lifr_name iflr_name
00041 #define lifr_dstaddr iflr_dstaddr
00042 #define lifr_flags iflr_flags
00043 #define ss_family sa_family
00044 #define LIFREQ if_laddrreq
00045 #else
00046 #define LIFREQ lifreq
00047 #endif
00048 #endif
00049 
00050 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'T')
00051 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
00052 
00053 struct isc_interfaceiter {
00054         unsigned int            magic;          /* Magic number. */
00055         isc_mem_t               *mctx;
00056         int                     mode;
00057         int                     socket;
00058         struct ifconf           ifc;
00059         void                    *buf;           /* Buffer for sysctl data. */
00060         unsigned int            bufsize;        /* Bytes allocated. */
00061         unsigned int            pos;            /* Current offset in
00062                                                    SIOCGIFCONF data */
00063 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00064         int                     socket6;
00065         struct LIFCONF          lifc;
00066         void                    *buf6;          /* Buffer for sysctl data. */
00067         unsigned int            bufsize6;       /* Bytes allocated. */
00068         unsigned int            pos6;           /* Current offset in
00069                                                    SIOCGLIFCONF data */
00070         isc_result_t            result6;        /* Last result code. */
00071         isc_boolean_t           first6;
00072 #endif
00073 #ifdef HAVE_TRUCLUSTER
00074         int                     clua_context;   /* Cluster alias context */
00075         isc_boolean_t           clua_done;
00076         struct sockaddr         clua_sa;
00077 #endif
00078 #ifdef  __linux
00079         FILE *                  proc;
00080         char                    entry[ISC_IF_INET6_SZ];
00081         isc_result_t            valid;
00082 #endif
00083         isc_interface_t         current;        /* Current interface data. */
00084         isc_result_t            result;         /* Last result code. */
00085 };
00086 
00087 #ifdef HAVE_TRUCLUSTER
00088 #include <clua/clua.h>
00089 #include <sys/socket.h>
00090 #endif
00091 
00092 
00093 /*%
00094  * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
00095  * will have more than a megabyte of interface configuration data.
00096  */
00097 #define IFCONF_BUFSIZE_INITIAL  4096
00098 #define IFCONF_BUFSIZE_MAX      1048576
00099 
00100 #ifdef __linux
00101 #ifndef IF_NAMESIZE
00102 # ifdef IFNAMSIZ
00103 #  define IF_NAMESIZE  IFNAMSIZ
00104 # else
00105 #  define IF_NAMESIZE 16
00106 # endif
00107 #endif
00108 #endif
00109 
00110 static isc_result_t
00111 getbuf4(isc_interfaceiter_t *iter) {
00112         char strbuf[ISC_STRERRORSIZE];
00113 
00114         iter->bufsize = IFCONF_BUFSIZE_INITIAL;
00115 
00116         for (;;) {
00117                 iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
00118                 if (iter->buf == NULL)
00119                         return (ISC_R_NOMEMORY);
00120 
00121                 memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
00122                 iter->ifc.ifc_len = iter->bufsize;
00123                 iter->ifc.ifc_buf = iter->buf;
00124                 /*
00125                  * Ignore the HP/UX warning about "integer overflow during
00126                  * conversion".  It comes from its own macro definition,
00127                  * and is really hard to shut up.
00128                  */
00129                 if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
00130                     == -1) {
00131                         if (errno != EINVAL) {
00132                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00133                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00134                                                  isc_msgcat_get(isc_msgcat,
00135                                                         ISC_MSGSET_IFITERIOCTL,
00136                                                         ISC_MSG_GETIFCONFIG,
00137                                                         "get interface "
00138                                                         "configuration: %s"),
00139                                                  strbuf);
00140                                 goto unexpected;
00141                         }
00142                         /*
00143                          * EINVAL.  Retry with a bigger buffer.
00144                          */
00145                 } else {
00146                         /*
00147                          * The ioctl succeeded.
00148                          * Some OS's just return what will fit rather
00149                          * than set EINVAL if the buffer is too small
00150                          * to fit all the interfaces in.  If
00151                          * ifc.lifc_len is too near to the end of the
00152                          * buffer we will grow it just in case and
00153                          * retry.
00154                          */
00155                         if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
00156                             < iter->bufsize)
00157                                 break;
00158                 }
00159                 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
00160                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00161                                          isc_msgcat_get(isc_msgcat,
00162                                                         ISC_MSGSET_IFITERIOCTL,
00163                                                         ISC_MSG_BUFFERMAX,
00164                                                         "get interface "
00165                                                         "configuration: "
00166                                                         "maximum buffer "
00167                                                         "size exceeded"));
00168                         goto unexpected;
00169                 }
00170                 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
00171 
00172                 iter->bufsize *= 2;
00173         }
00174         return (ISC_R_SUCCESS);
00175 
00176  unexpected:
00177         isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
00178         iter->buf = NULL;
00179         return (ISC_R_UNEXPECTED);
00180 }
00181 
00182 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00183 static isc_result_t
00184 getbuf6(isc_interfaceiter_t *iter) {
00185         char strbuf[ISC_STRERRORSIZE];
00186         isc_result_t result;
00187 
00188         iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
00189 
00190         for (;;) {
00191                 iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
00192                 if (iter->buf6 == NULL)
00193                         return (ISC_R_NOMEMORY);
00194 
00195                 memset(&iter->lifc, 0, sizeof(iter->lifc));
00196 #ifdef ISC_HAVE_LIFC_FAMILY
00197                 iter->lifc.lifc_family = AF_INET6;
00198 #endif
00199 #ifdef ISC_HAVE_LIFC_FLAGS
00200                 iter->lifc.lifc_flags = 0;
00201 #endif
00202                 iter->lifc.lifc_len = iter->bufsize6;
00203                 iter->lifc.lifc_buf = iter->buf6;
00204                 /*
00205                  * Ignore the HP/UX warning about "integer overflow during
00206                  * conversion".  It comes from its own macro definition,
00207                  * and is really hard to shut up.
00208                  */
00209                 if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
00210                     == -1) {
00211 #ifdef __hpux
00212                         /*
00213                          * IPv6 interface scanning is not available on all
00214                          * kernels w/ IPv6 sockets.
00215                          */
00216                         if (errno == ENOENT) {
00217                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00218                                 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00219                                               ISC_LOGMODULE_INTERFACE,
00220                                               ISC_LOG_DEBUG(1),
00221                                               isc_msgcat_get(isc_msgcat,
00222                                                         ISC_MSGSET_IFITERIOCTL,
00223                                                         ISC_MSG_GETIFCONFIG,
00224                                                         "get interface "
00225                                                         "configuration: %s"),
00226                                                strbuf);
00227                                 result = ISC_R_FAILURE;
00228                                 goto cleanup;
00229                         }
00230 #endif
00231                         if (errno != EINVAL) {
00232                                 isc__strerror(errno, strbuf, sizeof(strbuf));
00233                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00234                                                  isc_msgcat_get(isc_msgcat,
00235                                                         ISC_MSGSET_IFITERIOCTL,
00236                                                         ISC_MSG_GETIFCONFIG,
00237                                                         "get interface "
00238                                                         "configuration: %s"),
00239                                                  strbuf);
00240                                 result = ISC_R_UNEXPECTED;
00241                                 goto cleanup;
00242                         }
00243                         /*
00244                          * EINVAL.  Retry with a bigger buffer.
00245                          */
00246                 } else {
00247                         /*
00248                          * The ioctl succeeded.
00249                          * Some OS's just return what will fit rather
00250                          * than set EINVAL if the buffer is too small
00251                          * to fit all the interfaces in.  If
00252                          * ifc.ifc_len is too near to the end of the
00253                          * buffer we will grow it just in case and
00254                          * retry.
00255                          */
00256                         if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
00257                             < iter->bufsize6)
00258                                 break;
00259                 }
00260                 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
00261                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00262                                          isc_msgcat_get(isc_msgcat,
00263                                                         ISC_MSGSET_IFITERIOCTL,
00264                                                         ISC_MSG_BUFFERMAX,
00265                                                         "get interface "
00266                                                         "configuration: "
00267                                                         "maximum buffer "
00268                                                         "size exceeded"));
00269                         result = ISC_R_UNEXPECTED;
00270                         goto cleanup;
00271                 }
00272                 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
00273 
00274                 iter->bufsize6 *= 2;
00275         }
00276 
00277         if (iter->lifc.lifc_len != 0)
00278                 iter->mode = 6;
00279         return (ISC_R_SUCCESS);
00280 
00281  cleanup:
00282         isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
00283         iter->buf6 = NULL;
00284         return (result);
00285 }
00286 #endif
00287 
00288 isc_result_t
00289 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
00290         isc_interfaceiter_t *iter;
00291         isc_result_t result;
00292         char strbuf[ISC_STRERRORSIZE];
00293 
00294         REQUIRE(mctx != NULL);
00295         REQUIRE(iterp != NULL);
00296         REQUIRE(*iterp == NULL);
00297 
00298         iter = isc_mem_get(mctx, sizeof(*iter));
00299         if (iter == NULL)
00300                 return (ISC_R_NOMEMORY);
00301 
00302         iter->mctx = mctx;
00303         iter->mode = 4;
00304         iter->buf = NULL;
00305         iter->pos = (unsigned int) -1;
00306 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00307         iter->buf6 = NULL;
00308         iter->pos6 = (unsigned int) -1;
00309         iter->result6 = ISC_R_NOMORE;
00310         iter->socket6 = -1;
00311         iter->first6 = ISC_FALSE;
00312 #endif
00313 
00314         /*
00315          * Get the interface configuration, allocating more memory if
00316          * necessary.
00317          */
00318 
00319 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00320         result = isc_net_probeipv6();
00321         if (result == ISC_R_SUCCESS) {
00322                 /*
00323                  * Create an unbound datagram socket to do the SIOCGLIFCONF
00324                  * ioctl on.  HP/UX requires an AF_INET6 socket for
00325                  * SIOCGLIFCONF to get IPv6 addresses.
00326                  */
00327                 if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
00328                         isc__strerror(errno, strbuf, sizeof(strbuf));
00329                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00330                                          isc_msgcat_get(isc_msgcat,
00331                                                         ISC_MSGSET_IFITERIOCTL,
00332                                                         ISC_MSG_MAKESCANSOCKET,
00333                                                         "making interface "
00334                                                         "scan socket: %s"),
00335                                          strbuf);
00336                         result = ISC_R_UNEXPECTED;
00337                         goto socket6_failure;
00338                 }
00339                 result = iter->result6 = getbuf6(iter);
00340                 if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
00341                         goto ioctl6_failure;
00342         }
00343 #endif
00344         if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00345                 isc__strerror(errno, strbuf, sizeof(strbuf));
00346                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00347                                  isc_msgcat_get(isc_msgcat,
00348                                                 ISC_MSGSET_IFITERIOCTL,
00349                                                 ISC_MSG_MAKESCANSOCKET,
00350                                                 "making interface "
00351                                                 "scan socket: %s"),
00352                                  strbuf);
00353                 result = ISC_R_UNEXPECTED;
00354                 goto socket_failure;
00355         }
00356         result = getbuf4(iter);
00357         if (result != ISC_R_SUCCESS)
00358                 goto ioctl_failure;
00359 
00360         /*
00361          * A newly created iterator has an undefined position
00362          * until isc_interfaceiter_first() is called.
00363          */
00364 #ifdef HAVE_TRUCLUSTER
00365         iter->clua_context = -1;
00366         iter->clua_done = ISC_TRUE;
00367 #endif
00368 #ifdef __linux
00369         iter->proc = fopen("/proc/net/if_inet6", "r");
00370         iter->valid = ISC_R_FAILURE;
00371 #endif
00372         iter->result = ISC_R_FAILURE;
00373 
00374         iter->magic = IFITER_MAGIC;
00375         *iterp = iter;
00376         return (ISC_R_SUCCESS);
00377 
00378  ioctl_failure:
00379         if (iter->buf != NULL)
00380                 isc_mem_put(mctx, iter->buf, iter->bufsize);
00381         (void) close(iter->socket);
00382 
00383  socket_failure:
00384 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00385         if (iter->buf6 != NULL)
00386                 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
00387   ioctl6_failure:
00388         if (iter->socket6 != -1)
00389                 (void) close(iter->socket6);
00390   socket6_failure:
00391 #endif
00392 
00393         isc_mem_put(mctx, iter, sizeof(*iter));
00394         return (result);
00395 }
00396 
00397 #ifdef HAVE_TRUCLUSTER
00398 static void
00399 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
00400         dst->family = AF_INET;
00401         memmove(&dst->type.in, src, sizeof(struct in_addr));
00402 }
00403 
00404 static isc_result_t
00405 internal_current_clusteralias(isc_interfaceiter_t *iter) {
00406         struct clua_info ci;
00407         if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
00408                 return (ISC_R_IGNORE);
00409         memset(&iter->current, 0, sizeof(iter->current));
00410         iter->current.af = iter->clua_sa.sa_family;
00411         memset(iter->current.name, 0, sizeof(iter->current.name));
00412         sprintf(iter->current.name, "clua%d", ci.aliasid);
00413         iter->current.flags = INTERFACE_F_UP;
00414         get_inaddr(&iter->current.address, &ci.addr);
00415         get_inaddr(&iter->current.netmask, &ci.netmask);
00416         return (ISC_R_SUCCESS);
00417 }
00418 #endif
00419 
00420 /*
00421  * Get information about the current interface to iter->current.
00422  * If successful, return ISC_R_SUCCESS.
00423  * If the interface has an unsupported address family, or if
00424  * some operation on it fails, return ISC_R_IGNORE to make
00425  * the higher-level iterator code ignore it.
00426  */
00427 
00428 static isc_result_t
00429 internal_current4(isc_interfaceiter_t *iter) {
00430         struct ifreq *ifrp;
00431         struct ifreq ifreq;
00432         int family;
00433         char strbuf[ISC_STRERRORSIZE];
00434 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
00435         struct lifreq lifreq;
00436 #else
00437         char sabuf[256];
00438 #endif
00439         int i, bits, prefixlen;
00440 
00441         REQUIRE(VALID_IFITER(iter));
00442 
00443         if (iter->ifc.ifc_len == 0 ||
00444             iter->pos == (unsigned int)iter->ifc.ifc_len) {
00445 #ifdef __linux
00446                 return (linux_if_inet6_current(iter));
00447 #else
00448                 return (ISC_R_NOMORE);
00449 #endif
00450         }
00451 
00452         INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
00453 
00454         ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
00455 
00456         memset(&ifreq, 0, sizeof(ifreq));
00457         memmove(&ifreq, ifrp, sizeof(ifreq));
00458 
00459         family = ifreq.ifr_addr.sa_family;
00460 #if defined(ISC_PLATFORM_HAVEIPV6)
00461         if (family != AF_INET && family != AF_INET6)
00462 #else
00463         if (family != AF_INET)
00464 #endif
00465                 return (ISC_R_IGNORE);
00466 
00467         memset(&iter->current, 0, sizeof(iter->current));
00468         iter->current.af = family;
00469 
00470         INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
00471         memset(iter->current.name, 0, sizeof(iter->current.name));
00472         memmove(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
00473 
00474         get_addr(family, &iter->current.address,
00475                  (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
00476 
00477         /*
00478          * If the interface does not have a address ignore it.
00479          */
00480         switch (family) {
00481         case AF_INET:
00482                 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
00483                         return (ISC_R_IGNORE);
00484                 break;
00485         case AF_INET6:
00486                 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
00487                            sizeof(in6addr_any)) == 0)
00488                         return (ISC_R_IGNORE);
00489                 break;
00490         }
00491 
00492         /*
00493          * Get interface flags.
00494          */
00495 
00496         iter->current.flags = 0;
00497 
00498         /*
00499          * Ignore the HP/UX warning about "integer overflow during
00500          * conversion.  It comes from its own macro definition,
00501          * and is really hard to shut up.
00502          */
00503         if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
00504                 isc__strerror(errno, strbuf, sizeof(strbuf));
00505                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00506                                  "%s: getting interface flags: %s",
00507                                  ifreq.ifr_name, strbuf);
00508                 return (ISC_R_IGNORE);
00509         }
00510 
00511         if ((ifreq.ifr_flags & IFF_UP) != 0)
00512                 iter->current.flags |= INTERFACE_F_UP;
00513 
00514 #ifdef IFF_POINTOPOINT
00515         if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
00516                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
00517 #endif
00518 
00519         if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
00520                 iter->current.flags |= INTERFACE_F_LOOPBACK;
00521 
00522         if (family == AF_INET)
00523                 goto inet;
00524 
00525 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
00526         memset(&lifreq, 0, sizeof(lifreq));
00527         memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
00528         memmove(&lifreq.lifr_addr, &iter->current.address.type.in6,
00529                sizeof(iter->current.address.type.in6));
00530 
00531         if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
00532                 isc__strerror(errno, strbuf, sizeof(strbuf));
00533                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00534                                  "%s: getting interface address: %s",
00535                                  ifreq.ifr_name, strbuf);
00536                 return (ISC_R_IGNORE);
00537         }
00538         prefixlen = lifreq.lifr_addrlen;
00539 #else
00540         isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
00541         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00542                       ISC_LOGMODULE_INTERFACE,
00543                       ISC_LOG_INFO,
00544                       isc_msgcat_get(isc_msgcat,
00545                                      ISC_MSGSET_IFITERIOCTL,
00546                                      ISC_MSG_GETIFCONFIG,
00547                                      "prefix length for %s is unknown "
00548                                      "(assume 128)"), sabuf);
00549         prefixlen = 128;
00550 #endif
00551 
00552         /*
00553          * Netmask already zeroed.
00554          */
00555         iter->current.netmask.family = family;
00556         for (i = 0; i < 16; i++) {
00557                 if (prefixlen > 8) {
00558                         bits = 0;
00559                         prefixlen -= 8;
00560                 } else {
00561                         bits = 8 - prefixlen;
00562                         prefixlen = 0;
00563                 }
00564                 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
00565         }
00566         return (ISC_R_SUCCESS);
00567 
00568  inet:
00569         if (family != AF_INET)
00570                 return (ISC_R_IGNORE);
00571 #ifdef IFF_POINTOPOINT
00572         /*
00573          * If the interface is point-to-point, get the destination address.
00574          */
00575         if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
00576                 /*
00577                  * Ignore the HP/UX warning about "integer overflow during
00578                  * conversion.  It comes from its own macro definition,
00579                  * and is really hard to shut up.
00580                  */
00581                 if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
00582                     < 0) {
00583                         isc__strerror(errno, strbuf, sizeof(strbuf));
00584                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00585                                 isc_msgcat_get(isc_msgcat,
00586                                                ISC_MSGSET_IFITERIOCTL,
00587                                                ISC_MSG_GETDESTADDR,
00588                                                "%s: getting "
00589                                                "destination address: %s"),
00590                                          ifreq.ifr_name, strbuf);
00591                         return (ISC_R_IGNORE);
00592                 }
00593                 get_addr(family, &iter->current.dstaddress,
00594                          (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
00595         }
00596 #endif
00597 
00598         /*
00599          * Get the network mask.
00600          */
00601         memset(&ifreq, 0, sizeof(ifreq));
00602         memmove(&ifreq, ifrp, sizeof(ifreq));
00603         /*
00604          * Ignore the HP/UX warning about "integer overflow during
00605          * conversion.  It comes from its own macro definition,
00606          * and is really hard to shut up.
00607          */
00608         if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
00609                 isc__strerror(errno, strbuf, sizeof(strbuf));
00610                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00611                         isc_msgcat_get(isc_msgcat,
00612                                        ISC_MSGSET_IFITERIOCTL,
00613                                        ISC_MSG_GETNETMASK,
00614                                        "%s: getting netmask: %s"),
00615                                        ifreq.ifr_name, strbuf);
00616                 return (ISC_R_IGNORE);
00617         }
00618         get_addr(family, &iter->current.netmask,
00619                  (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
00620         return (ISC_R_SUCCESS);
00621 }
00622 
00623 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00624 static isc_result_t
00625 internal_current6(isc_interfaceiter_t *iter) {
00626         struct LIFREQ *ifrp;
00627         struct LIFREQ lifreq;
00628         int family;
00629         char strbuf[ISC_STRERRORSIZE];
00630         int fd;
00631 
00632         REQUIRE(VALID_IFITER(iter));
00633         if (iter->result6 != ISC_R_SUCCESS)
00634                 return (iter->result6);
00635         REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
00636 
00637         ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
00638 
00639         memset(&lifreq, 0, sizeof(lifreq));
00640         memmove(&lifreq, ifrp, sizeof(lifreq));
00641 
00642         family = lifreq.lifr_addr.ss_family;
00643 #ifdef ISC_PLATFORM_HAVEIPV6
00644         if (family != AF_INET && family != AF_INET6)
00645 #else
00646         if (family != AF_INET)
00647 #endif
00648                 return (ISC_R_IGNORE);
00649 
00650         memset(&iter->current, 0, sizeof(iter->current));
00651         iter->current.af = family;
00652 
00653         INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
00654         memset(iter->current.name, 0, sizeof(iter->current.name));
00655         memmove(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
00656 
00657         get_addr(family, &iter->current.address,
00658                  (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
00659 
00660         /*
00661          * If the interface does not have a address ignore it.
00662          */
00663         switch (family) {
00664         case AF_INET:
00665                 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
00666                         return (ISC_R_IGNORE);
00667                 break;
00668         case AF_INET6:
00669                 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
00670                            sizeof(in6addr_any)) == 0)
00671                         return (ISC_R_IGNORE);
00672                 break;
00673         }
00674 
00675         /*
00676          * Get interface flags.
00677          */
00678 
00679         iter->current.flags = 0;
00680 
00681         if (family == AF_INET6)
00682                 fd = iter->socket6;
00683         else
00684                 fd = iter->socket;
00685 
00686         /*
00687          * Ignore the HP/UX warning about "integer overflow during
00688          * conversion.  It comes from its own macro definition,
00689          * and is really hard to shut up.
00690          */
00691         if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
00692                 isc__strerror(errno, strbuf, sizeof(strbuf));
00693                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00694                                  "%s: getting interface flags: %s",
00695                                  lifreq.lifr_name, strbuf);
00696                 return (ISC_R_IGNORE);
00697         }
00698 
00699         if ((lifreq.lifr_flags & IFF_UP) != 0)
00700                 iter->current.flags |= INTERFACE_F_UP;
00701 
00702 #ifdef IFF_POINTOPOINT
00703         if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
00704                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
00705 #endif
00706 
00707         if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
00708                 iter->current.flags |= INTERFACE_F_LOOPBACK;
00709 
00710 #ifdef IFF_POINTOPOINT
00711         /*
00712          * If the interface is point-to-point, get the destination address.
00713          */
00714         if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
00715                 /*
00716                  * Ignore the HP/UX warning about "integer overflow during
00717                  * conversion.  It comes from its own macro definition,
00718                  * and is really hard to shut up.
00719                  */
00720                 if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
00721                     < 0) {
00722                         isc__strerror(errno, strbuf, sizeof(strbuf));
00723                         UNEXPECTED_ERROR(__FILE__, __LINE__,
00724                                 isc_msgcat_get(isc_msgcat,
00725                                                ISC_MSGSET_IFITERIOCTL,
00726                                                ISC_MSG_GETDESTADDR,
00727                                                "%s: getting "
00728                                                "destination address: %s"),
00729                                          lifreq.lifr_name, strbuf);
00730                         return (ISC_R_IGNORE);
00731                 }
00732                 get_addr(family, &iter->current.dstaddress,
00733                          (struct sockaddr *)&lifreq.lifr_dstaddr,
00734                          lifreq.lifr_name);
00735         }
00736 #endif
00737 
00738         /*
00739          * Get the network mask.  Netmask already zeroed.
00740          */
00741         memset(&lifreq, 0, sizeof(lifreq));
00742         memmove(&lifreq, ifrp, sizeof(lifreq));
00743 
00744 #ifdef lifr_addrlen
00745         /*
00746          * Special case: if the system provides lifr_addrlen member, the
00747          * netmask of an IPv6 address can be derived from the length, since
00748          * an IPv6 address always has a contiguous mask.
00749          */
00750         if (family == AF_INET6) {
00751                 int i, bits;
00752 
00753                 iter->current.netmask.family = family;
00754                 for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
00755                         bits = lifreq.lifr_addrlen - i;
00756                         bits = (bits < 8) ? (8 - bits) : 0;
00757                         iter->current.netmask.type.in6.s6_addr[i / 8] =
00758                                 (~0 << bits) & 0xff;
00759                 }
00760 
00761                 return (ISC_R_SUCCESS);
00762         }
00763 #endif
00764 
00765         /*
00766          * Ignore the HP/UX warning about "integer overflow during
00767          * conversion.  It comes from its own macro definition,
00768          * and is really hard to shut up.
00769          */
00770         if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
00771                 isc__strerror(errno, strbuf, sizeof(strbuf));
00772                 UNEXPECTED_ERROR(__FILE__, __LINE__,
00773                                  isc_msgcat_get(isc_msgcat,
00774                                                 ISC_MSGSET_IFITERIOCTL,
00775                                                 ISC_MSG_GETNETMASK,
00776                                                 "%s: getting netmask: %s"),
00777                                  lifreq.lifr_name, strbuf);
00778                 return (ISC_R_IGNORE);
00779         }
00780         get_addr(family, &iter->current.netmask,
00781                  (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
00782 
00783         return (ISC_R_SUCCESS);
00784 }
00785 #endif
00786 
00787 static isc_result_t
00788 internal_current(isc_interfaceiter_t *iter) {
00789 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00790         if (iter->mode == 6) {
00791                 iter->result6 = internal_current6(iter);
00792                 if (iter->result6 != ISC_R_NOMORE)
00793                         return (iter->result6);
00794         }
00795 #endif
00796 #ifdef HAVE_TRUCLUSTER
00797         if (!iter->clua_done)
00798                 return(internal_current_clusteralias(iter));
00799 #endif
00800         return (internal_current4(iter));
00801 }
00802 
00803 /*
00804  * Step the iterator to the next interface.  Unlike
00805  * isc_interfaceiter_next(), this may leave the iterator
00806  * positioned on an interface that will ultimately
00807  * be ignored.  Return ISC_R_NOMORE if there are no more
00808  * interfaces, otherwise ISC_R_SUCCESS.
00809  */
00810 static isc_result_t
00811 internal_next4(isc_interfaceiter_t *iter) {
00812 #ifdef ISC_PLATFORM_HAVESALEN
00813         struct ifreq *ifrp;
00814 #endif
00815 
00816         if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
00817 #ifdef ISC_PLATFORM_HAVESALEN
00818                 ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
00819 
00820                 if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
00821                         iter->pos += sizeof(ifrp->ifr_name) +
00822                                      ifrp->ifr_addr.sa_len;
00823                 else
00824 #endif
00825                         iter->pos += sizeof(struct ifreq);
00826 
00827         } else {
00828                 INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
00829 #ifdef __linux
00830                 return (linux_if_inet6_next(iter));
00831 #else
00832                 return (ISC_R_NOMORE);
00833 #endif
00834         }
00835         return (ISC_R_SUCCESS);
00836 }
00837 
00838 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00839 static isc_result_t
00840 internal_next6(isc_interfaceiter_t *iter) {
00841 #ifdef ISC_PLATFORM_HAVESALEN
00842         struct LIFREQ *ifrp;
00843 #endif
00844 
00845         if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
00846                 return (iter->result6);
00847 
00848         REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
00849 
00850 #ifdef ISC_PLATFORM_HAVESALEN
00851         ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
00852 
00853         if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
00854                 iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
00855         else
00856 #endif
00857                 iter->pos6 += sizeof(struct LIFREQ);
00858 
00859         if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
00860                 return (ISC_R_NOMORE);
00861 
00862         return (ISC_R_SUCCESS);
00863 }
00864 #endif
00865 
00866 static isc_result_t
00867 internal_next(isc_interfaceiter_t *iter) {
00868 #ifdef HAVE_TRUCLUSTER
00869         int clua_result;
00870 #endif
00871 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00872         if (iter->mode == 6) {
00873                 iter->result6 = internal_next6(iter);
00874                 if (iter->result6 != ISC_R_NOMORE)
00875                         return (iter->result6);
00876                 if (iter->first6) {
00877                         iter->first6 = ISC_FALSE;
00878                         return (ISC_R_SUCCESS);
00879                 }
00880         }
00881 #endif
00882 #ifdef HAVE_TRUCLUSTER
00883         if (!iter->clua_done) {
00884                 clua_result = clua_getaliasaddress(&iter->clua_sa,
00885                                                    &iter->clua_context);
00886                 if (clua_result != CLUA_SUCCESS)
00887                         iter->clua_done = ISC_TRUE;
00888                 return (ISC_R_SUCCESS);
00889         }
00890 #endif
00891         return (internal_next4(iter));
00892 }
00893 
00894 static void
00895 internal_destroy(isc_interfaceiter_t *iter) {
00896         (void) close(iter->socket);
00897 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00898         if (iter->socket6 != -1)
00899                 (void) close(iter->socket6);
00900         if (iter->buf6 != NULL) {
00901                 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
00902         }
00903 #endif
00904 #ifdef __linux
00905         if (iter->proc != NULL)
00906                 fclose(iter->proc);
00907 #endif
00908 }
00909 
00910 static
00911 void internal_first(isc_interfaceiter_t *iter) {
00912 #ifdef HAVE_TRUCLUSTER
00913         int clua_result;
00914 #endif
00915         iter->pos = 0;
00916 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
00917         iter->pos6 = 0;
00918         if (iter->result6 == ISC_R_NOMORE)
00919                 iter->result6 = ISC_R_SUCCESS;
00920         iter->first6 = ISC_TRUE;
00921 #endif
00922 #ifdef HAVE_TRUCLUSTER
00923         iter->clua_context = 0;
00924         clua_result = clua_getaliasaddress(&iter->clua_sa,
00925                                            &iter->clua_context);
00926         iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
00927 #endif
00928 #ifdef __linux
00929         linux_if_inet6_first(iter);
00930 #endif
00931 }

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