LCOV - code coverage report
Current view: top level - libaddr - iface.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 73 91 80.2 %
Date: 2021-07-21 12:51:15 Functions: 16 21 76.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2021  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/libaddr
       4             : //
       5             : // Permission is hereby granted, free of charge, to any person obtaining a
       6             : // copy of this software and associated documentation files (the
       7             : // "Software"), to deal in the Software without restriction, including
       8             : // without limitation the rights to use, copy, modify, merge, publish,
       9             : // distribute, sublicense, and/or sell copies of the Software, and to
      10             : // permit persons to whom the Software is furnished to do so, subject to
      11             : // the following conditions:
      12             : //
      13             : // The above copyright notice and this permission notice shall be included
      14             : // in all copies or substantial portions of the Software.
      15             : //
      16             : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      17             : // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      18             : // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      19             : // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      20             : // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      21             : // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      22             : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      23             : 
      24             : 
      25             : /** \file
      26             :  * \brief The implementation of the addr class.
      27             :  *
      28             :  * This file includes the implementation of the addr class. The one that
      29             :  * deals with low level classes.
      30             :  */
      31             : 
      32             : 
      33             : // addr library
      34             : //
      35             : #include    "libaddr/iface.h"
      36             : #include    "libaddr/route.h"
      37             : 
      38             : 
      39             : // C++ library
      40             : //
      41             : #include    <algorithm>
      42             : #include    <iostream>
      43             : 
      44             : 
      45             : // C library
      46             : //
      47             : #include    <ifaddrs.h>
      48             : #include    <net/if.h>
      49             : 
      50             : 
      51             : // last include
      52             : //
      53             : #include    <snapdev/poison.h>
      54             : 
      55             : 
      56             : 
      57             : namespace addr
      58             : {
      59             : 
      60             : 
      61             : /** \brief Details used by the addr class implementation.
      62             :  *
      63             :  * We have a function to check whether an address is part of
      64             :  * the interfaces of your computer. This check requires the
      65             :  * use of a `struct ifaddrs` and as such it requires to
      66             :  * delete that structure. We define a deleter for that
      67             :  * strucure here.
      68             :  */
      69             : namespace
      70             : {
      71             : 
      72             : /** \brief Delete an ifaddrs structure.
      73             :  *
      74             :  * This deleter is used to make sure all the ifaddrs get released when
      75             :  * an exception occurs or the function using such exists.
      76             :  *
      77             :  * \param[in] ia  The ifaddrs structure to free.
      78             :  */
      79          15 : void ifaddrs_deleter(struct ifaddrs * ia)
      80             : {
      81          15 :     freeifaddrs(ia);
      82          15 : }
      83             : 
      84             : 
      85             : }
      86             : // no name namespace
      87             : 
      88             : 
      89             : 
      90             : 
      91             : 
      92             : /** \brief Initializes an interface name/index pair.
      93             :  *
      94             :  * This function creates an interface name/index object.
      95             :  *
      96             :  * In some circumstances (NETLINK) you need to specify the index of an
      97             :  * interface. The kernel keeps a list of interface by index starting at 1
      98             :  * and each have a name such as "eth0". This function initializes
      99             :  * one of those pairs.
     100             :  *
     101             :  * \param[in] index  The index of the interface.
     102             :  * \param[in] name  The name of the interface.
     103             :  */
     104           0 : iface_index_name::iface_index_name(int index, std::string const & name)
     105             :     : f_index(index)
     106           0 :     , f_name(name)
     107             : {
     108           0 : }
     109             : 
     110             : 
     111             : /** \brief Get the index of this interface.
     112             :  *
     113             :  * This function is used to retrieve the index of a name/index pair.
     114             :  *
     115             :  * \return The index of the name/index pair.
     116             :  */
     117           0 : int iface_index_name::get_index() const
     118             : {
     119           0 :     return f_index;
     120             : }
     121             : 
     122             : 
     123             : /** \brief Get the name of this interface.
     124             :  *
     125             :  * This function is used to retrieve the name of a name/index pair.
     126             :  *
     127             :  * \return The name of the name/index pair.
     128             :  */
     129           0 : std::string const & iface_index_name::get_name() const
     130             : {
     131           0 :     return f_name;
     132             : }
     133             : 
     134             : 
     135             : 
     136             : /** \brief Get the list of existing interfaces.
     137             :  *
     138             :  * This function gathers the complete list of interfaces by index and
     139             :  * name pairs. The result is a vector of iface_index_name objects.
     140             :  *
     141             :  * Note that over time the index of an interface can change since interfaces
     142             :  * can be added and removed from your network configuration. It is a good
     143             :  * idea to not cache that information.
     144             :  *
     145             :  * \return A vector of index/name pair objects.
     146             :  */
     147           0 : iface_index_name::vector_t get_interface_name_index()
     148             : {
     149           0 :     iface_index_name::vector_t result;
     150             : 
     151             :     // the index starts at 1
     152             :     //
     153           0 :     for(int index(1);; ++index)
     154             :     {
     155             :         // get the next interface name by index
     156             :         //
     157             :         char name[IF_NAMESIZE + 1];
     158           0 :         if(if_indextoname(index, name) == nullptr)
     159             :         {
     160           0 :             return result;
     161             :         }
     162             : 
     163             :         // make sure the name is null terminated
     164             :         //
     165           0 :         name[IF_NAMESIZE] = '\0';
     166             : 
     167           0 :         iface_index_name const in(index, name);
     168           0 :         result.push_back(in);
     169           0 :     }
     170             :     // NOT REACHED, the loop is broken by a "return"
     171             : }
     172             : 
     173             : 
     174             : /** \brief Get the index of an interface from its name.
     175             :  *
     176             :  * If you are given the name of an interface, you can retrieve its index
     177             :  * by calling this function. The resulting value is the index from 1 to n.
     178             :  *
     179             :  * If the named interface is not found, then the function returns 0.
     180             :  *
     181             :  * \return The interface index or 0 on error.
     182             :  */
     183           0 : unsigned int get_interface_index_by_name(std::string const & name)
     184             : {
     185           0 :     return if_nametoindex(name.c_str());
     186             : }
     187             : 
     188             : 
     189             : 
     190             : 
     191             : 
     192             : 
     193             : /** \brief Return a list of local addresses on this machine.
     194             :  *
     195             :  * Peruse the list of available interfaces, and return any detected
     196             :  * ip addresses in a vector.
     197             :  *
     198             :  * These addresses include:
     199             :  *
     200             :  * \li A mask whenever available (very likely if the interface is up).
     201             :  * \li A name you can retrieve with get_iface_name()
     202             :  * \li A set of flags defining the current status of the network interface
     203             :  *     (i.e. IFF_UP, IFF_BROADCAST, IFF_NOARP, etc.)
     204             :  *
     205             :  * \return A vector of all the local interface IP addresses.
     206             :  */
     207          15 : iface::vector_t iface::get_local_addresses()
     208             : {
     209             :     // get the list of interface addresses
     210             :     //
     211          15 :     struct ifaddrs * ifa_start(nullptr);
     212          15 :     if(getifaddrs(&ifa_start) != 0)
     213             :     {
     214             :         // TODO: Should this throw, or just return an empty list quietly?
     215             :         //
     216             :         return iface::vector_t(); // LCOV_EXCL_LINE
     217             :     }
     218             : 
     219          30 :     std::shared_ptr<struct ifaddrs> auto_free(ifa_start, ifaddrs_deleter);
     220             : 
     221             :     uint8_t mask[16];
     222          30 :     iface::vector_t iface_list;
     223         420 :     for(struct ifaddrs * ifa(ifa_start); ifa != nullptr; ifa = ifa->ifa_next)
     224             :     {
     225             :         // the documentation says there may be no address at all
     226             :         // skip such entries at the moment
     227             :         //
     228         405 :         if(ifa->ifa_addr == nullptr)
     229             :         {
     230         120 :             continue;
     231             :         }
     232             : 
     233             :         // initialize an interface
     234         690 :         iface the_interface;
     235             : 
     236             :         // copy the name and flags as is
     237             :         //
     238             :         // TBD: can the ifa_name even be a null pointer?
     239             :         //
     240         405 :         the_interface.f_name = ifa->ifa_name;
     241         405 :         the_interface.f_flags = ifa->ifa_flags; // IFF_... flags (see `man 7 netdevice` search for SIOCGIFFLAGS)
     242             : 
     243             :         // get the family to know how to treat the address
     244             :         //
     245             :         // when an interface has an IPv4 and an IPv6, there are two entries in
     246             :         // the list, both with the same name
     247             :         //
     248         405 :         uint16_t const family(ifa->ifa_addr->sa_family);
     249             : 
     250         525 :         switch(family)
     251             :         {
     252         210 :         case AF_INET:
     253         210 :             the_interface.f_address.set_ipv4(*(reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr)));
     254             : 
     255         210 :             if((ifa->ifa_flags & IFF_BROADCAST) != 0
     256         195 :             && ifa->ifa_broadaddr != nullptr)
     257             :             {
     258         195 :                 the_interface.f_broadcast_address.set_ipv4(*(reinterpret_cast<struct sockaddr_in *>(ifa->ifa_broadaddr)));
     259             :             }
     260         210 :             if((ifa->ifa_flags & IFF_POINTOPOINT) != 0
     261             :             && ifa->ifa_dstaddr != nullptr)  // LCOV_EXCL_LINE
     262             :             {
     263             :                 the_interface.f_destination_address.set_ipv4(*(reinterpret_cast<struct sockaddr_in *>(ifa->ifa_dstaddr)));  // LCOV_EXCL_LINE
     264             :             }
     265             : 
     266             :             // if present, add the mask as well
     267             :             //
     268         210 :             if(ifa->ifa_netmask != nullptr)
     269             :             {
     270             :                 // for the IPv4 mask, we have to break it down in such a
     271             :                 // way as to make it IPv6 compatible
     272             :                 //
     273         210 :                 memset(mask, 255, 12);
     274         210 :                 mask[12] = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask)->sin_addr.s_addr >>  0;
     275         210 :                 mask[13] = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask)->sin_addr.s_addr >>  8;
     276         210 :                 mask[14] = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask)->sin_addr.s_addr >> 16;
     277         210 :                 mask[15] = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask)->sin_addr.s_addr >> 24;
     278         210 :                 the_interface.f_address.set_mask(mask);
     279             :             }
     280         210 :             break;
     281             : 
     282          75 :         case AF_INET6:
     283          75 :             the_interface.f_address.set_ipv6(*(reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr)));
     284             : 
     285          75 :             if((ifa->ifa_flags & IFF_BROADCAST) != 0
     286          60 :             && ifa->ifa_broadaddr != nullptr)
     287             :             {
     288             :                 the_interface.f_broadcast_address.set_ipv6(*(reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_broadaddr)));  // LCOV_EXCL_LINE
     289             :             }
     290          75 :             if((ifa->ifa_flags & IFF_POINTOPOINT) != 0
     291             :             && ifa->ifa_dstaddr != nullptr)  // LCOV_EXCL_LINE
     292             :             {
     293             :                 the_interface.f_destination_address.set_ipv6(*(reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_dstaddr)));  // LCOV_EXCL_LINE
     294             :             }
     295             : 
     296             :             // if present, add the mask as well
     297             :             //
     298          75 :             if(ifa->ifa_netmask != nullptr)
     299             :             {
     300          75 :                 the_interface.f_address.set_mask(reinterpret_cast<uint8_t *>(&reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_netmask)->sin6_addr));
     301             :             }
     302          75 :             break;
     303             : 
     304         120 :         default:
     305             :             // TODO: can we just ignore unexpected address families?
     306             :             //throw addr_invalid_structure("Unknown address family!");
     307         120 :             continue;
     308             : 
     309             :         }
     310             : 
     311         285 :         iface_list.push_back(the_interface);
     312             :     }
     313             : 
     314          15 :     return iface_list;
     315             : }
     316             : 
     317             : 
     318             : /** \brief Get the interface name.
     319             :  *
     320             :  * This function returns the name of the interface such as 'eth0' or 'p4p1'.
     321             :  *
     322             :  * The name is used in a few places such as the ioctl() function with the
     323             :  * SIOCGIFMTU command. Otherwise, it's mainly for display and easing use
     324             :  * (i.e. to let users select which interface to connect to.)
     325             :  *
     326             :  * \return The interface name.
     327             :  */
     328          21 : std::string iface::get_name() const
     329             : {
     330          21 :     return f_name;
     331             : }
     332             : 
     333             : 
     334             : /** \brief Get the interface setup flags.
     335             :  *
     336             :  * This function returns a set of flags defined on that interface. The flags
     337             :  * are defined in the `man 7 netdevice` as the IFF_... flags. The flags are
     338             :  * defined under the SIOCGIFFLAGS and SIOCSIFFLAGS entries.
     339             :  *
     340             :  * One flag of interest is the IFF_UP flag. This means the interface is
     341             :  * active (even if not actually in use.)
     342             :  *
     343             :  * \return The interface flags.
     344             :  */
     345          57 : unsigned int iface::get_flags() const
     346             : {   
     347          57 :     return f_flags;
     348             : }
     349             : 
     350             : 
     351             : /** \brief Get this interface address.
     352             :  *
     353             :  * This function returns the address of the interface. This address is very
     354             :  * likely to have a mask (i.e. 192.168.0.0/255.255.0.0).
     355             :  *
     356             :  * The address may be an IPv4 or an IPv6 address.
     357             :  *
     358             :  * \return The address of the interface.
     359             :  */
     360         263 : addr const & iface::get_address() const
     361             : {
     362         263 :     return f_address;
     363             : }
     364             : 
     365             : 
     366             : /** \brief Get the broadcast address.
     367             :  *
     368             :  * This function returns a constant reference to the broadcast address
     369             :  * of this interface. The address is always available in this class. It
     370             :  * will be set to the ANY address if it was not defined. Note, however,
     371             :  * that even though the ANY address is not a valid broadcast address,
     372             :  * you should call the has_broadcast_address() function to know whether
     373             :  * this address is indeed defined.
     374             :  *
     375             :  * \return The broadcast address of this interface.
     376             :  */
     377          19 : addr const & iface::get_broadcast_address() const
     378             : {
     379          19 :     return f_broadcast_address;
     380             : }
     381             : 
     382             : 
     383             : /** \brief Get the destination address.
     384             :  *
     385             :  * This function returns a constant reference to the destination address
     386             :  * of this interface. The address is always available in this class. It
     387             :  * will be set to the ANY address if it was not defined. Note, however,
     388             :  * that the ANY address is a valid destination address (i.e. default
     389             :  * route).
     390             :  *
     391             :  * To know whether the destination address is defined in that interface,
     392             :  * make sure to call the has_destination_address() function first.
     393             :  *
     394             :  * \return The destination address of this interface.
     395             :  */
     396          19 : addr const & iface::get_destination_address() const
     397             : {
     398          19 :     return f_destination_address;
     399             : }
     400             : 
     401             : 
     402             : /** \brief Check whether a broadcast address.
     403             :  *
     404             :  * The broadcast address is not present on all interfaces. When it is, this
     405             :  * function returns true.
     406             :  *
     407             :  * Note that you can always call the get_broadcast_address(), but if
     408             :  * undefined it will appear as a default address (NETWORK_TYPE_ANY)
     409             :  * which you can't distinguish from a valid address although a
     410             :  * the NETWORK_TYPE_ANY is not a valid address for a broacast
     411             :  * address.
     412             :  *
     413             :  * \note
     414             :  * When a broadcast address is defined on an interface, then there can't
     415             :  * be a destination address.
     416             :  *
     417             :  * \return true if a broadcast address is defined.
     418             :  */
     419          38 : bool iface::has_broadcast_address() const
     420             : {
     421          38 :     return (f_flags & IFF_BROADCAST) != 0;
     422             : }
     423             : 
     424             : 
     425             : /** \brief Check whether this interface defines a destination address.
     426             :  *
     427             :  * This function returns true if this interface defined a destination
     428             :  * address. Either way you can call the get_destination_address()
     429             :  * function, however, the address will be of type NETWORK_TYPE_ANY
     430             :  * which does not tell you whether it was defined or not.
     431             :  *
     432             :  * Ethernet and the local interfaces all define a destination address.
     433             :  *
     434             :  * \note
     435             :  * The destination address is not assigned any specific mask (all
     436             :  * are ff or 255).
     437             :  *
     438             :  * \note
     439             :  * When there is a destination address defined on an interface, then
     440             :  * there can't be a broadcast address.
     441             :  *
     442             :  * \return true when that interface defined a destination address.
     443             :  */
     444          38 : bool iface::has_destination_address() const
     445             : {
     446          38 :     return (f_flags & IFF_POINTOPOINT) != 0;
     447             : }
     448             : 
     449             : 
     450             : /** \brief Search for the interface corresponding to this address.
     451             :  *
     452             :  * Peruse the list of available interfaces and return the one that matches
     453             :  * this address if any, otherwise return a null pointer.
     454             :  *
     455             :  * Say you create an addr object with the IP address "127.0.0.1" and then
     456             :  * call this function. You will get a pointer to the "lo" interface and
     457             :  * can check the validity of the flags (i.e. is the interface UP, can it
     458             :  * BROADCAST or MULTICAST your UDP packets, etc.)
     459             :  *
     460             :  * If the address is a remote address, then this function returns a null
     461             :  * pointer.
     462             :  *
     463             :  * \note
     464             :  * This function replaces the addr::is_computer_interface_address() function.
     465             :  * If this function returns a non-null pointer when allow_default_destination
     466             :  * set to false, then you've got the same result plus you have access to all
     467             :  * the available information from that interface.
     468             :  *
     469             :  * \warning
     470             :  * If you allow for the default destination, this function calls the
     471             :  * route::get_ipv4_routes() function which can be costly. Try to avoid
     472             :  * doing that in a loop.
     473             :  *
     474             :  * \param[in] a  The address used to search for an interface.
     475             :  * \param[in] allow_default_destination  If true and \p a doesn't match
     476             :  *            any of the interfaces, use the one interface with its
     477             :  *            destination set to 0.0.0.0 or equivalent.
     478             :  *
     479             :  * \return A pointer to an interface IP address.
     480             :  */
     481          14 : iface::pointer_t find_addr_interface(addr const & a, bool allow_default_destination)
     482             : {
     483          28 :     iface::vector_t interfaces(iface::get_local_addresses());
     484             : 
     485         256 :     for(auto i : interfaces)
     486             :     {
     487         244 :         if(i.get_address().match(a))
     488             :         {
     489           2 :             return iface::pointer_t(new iface(i));
     490             :         }
     491             :     }
     492             : 
     493             :     // if there is a default, keep a copy in case we do not find a
     494             :     // local address while looking (and only if the user requested
     495             :     // such, which is the default)
     496             :     //
     497          12 :     if(!allow_default_destination)
     498             :     {
     499          11 :         return iface::pointer_t();
     500             :     }
     501             : 
     502             :     // to determine the default interface, we need the list of routes
     503             :     // so we first gather that information and then search for the
     504             :     // interface that has that name
     505             :     //
     506           2 :     route::vector_t routes(route::get_ipv4_routes());
     507           2 :     route::pointer_t default_route(find_default_route(routes));
     508           1 :     if(default_route == nullptr)
     509             :     {
     510             :         return iface::pointer_t(); // LCOV_EXCL_LINE
     511             :     }
     512             : 
     513           1 :     std::string const & default_iface(default_route->get_interface_name());
     514             :     auto it(std::find_if(
     515             :               interfaces.cbegin()
     516             :             , interfaces.cend()
     517          11 :             , [default_iface](auto & i)
     518             :             {
     519           4 :                 return i.get_name() == default_iface;
     520           5 :             }));
     521           1 :     if(it == interfaces.cend())
     522             :     {
     523             :         return iface::pointer_t(); // LCOV_EXCL_LINE
     524             :     }
     525             : 
     526           1 :     return iface::pointer_t(new iface(*it));
     527             : }
     528             : 
     529             : 
     530             : #if 0
     531             : /** \brief Check whether this address represents this computer.
     532             :  *
     533             :  * This function reads the addresses as given to us by the getifaddrs()
     534             :  * function. This is a system function that returns a complete list of
     535             :  * all the addresses this computer is managing / represents. In other
     536             :  * words, a list of address that other computers can use to connect
     537             :  * to this computer (assuming proper firewall, of course.)
     538             :  *
     539             :  * \warning
     540             :  * The list of addresses from getifaddrs() is not being cached. So you
     541             :  * probably do not want to call this function in a loop. That being
     542             :  * said, I still would imagine that retrieving that list is fast.
     543             :  *
     544             :  * \todo
     545             :  * We need to apply the mask to make this work properly. This is why
     546             :  * the current implementation fails big time (used by snapcommunicator.cpp).
     547             :  *
     548             :  * \return a computer_interface_address_t enumeration: error, true, or
     549             :  *         false at this time; on error errno should be set to represent
     550             :  *         what the error was.
     551             :  */
     552             : 
     553             : // replaced by with a pointer_t == nullptr if there was no match,
     554             : // although make sure to set allow_default_destination to false
     555             : //
     556             : iface::pointer_t find_addr_interface(addr const & a, bool allow_default_destination)
     557             : 
     558             : bool is_computer_interface_address(addr const & a)
     559             : {
     560             :     iface::vector_t interfaces(iface::get_local_addresses());
     561             : 
     562             :     for(auto i : interfaces)
     563             :     {
     564             :     }
     565             : 
     566             : 
     567             :     // TBD: maybe we could cache the ifaddrs for a small amount of time
     568             :     //      (i.e. 1 minute) so additional calls within that time
     569             :     //      can go even faster?
     570             :     //
     571             : 
     572             :     // get the list of interface addresses
     573             :     //
     574             :     struct ifaddrs * ifa_start(nullptr);
     575             :     if(getifaddrs(&ifa_start) != 0)
     576             :     {
     577             :         return computer_interface_address_t::COMPUTER_INTERFACE_ADDRESS_ERROR; // LCOV_EXCL_LINE
     578             :     }
     579             :     std::shared_ptr<struct ifaddrs> auto_free(ifa_start, ifaddrs_deleter);
     580             : 
     581             :     bool const ipv4(a.is_ipv4());
     582             :     uint16_t const family(ipv4 ? AF_INET : AF_INET6);
     583             :     for(struct ifaddrs * ifa(ifa_start); ifa != nullptr; ifa = ifa->ifa_next)
     584             :     {
     585             :         if(ifa->ifa_addr != nullptr
     586             :         && ifa->ifa_addr->sa_family == family)
     587             :         {
     588             :             if(ipv4)
     589             :             {
     590             :                 // the interface address structure is a 'struct sockaddr_in'
     591             :                 //
     592             :                 if(memcmp(&reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr)->sin_addr,
     593             :                             f_address.sin6_addr.s6_addr32 + 3, //&reinterpret_cast<struct sockaddr_in const *>(&f_address)->sin_addr,
     594             :                             sizeof(struct in_addr)) == 0)
     595             :                 {
     596             :                     return computer_interface_address_t::COMPUTER_INTERFACE_ADDRESS_TRUE;
     597             :                 }
     598             :             }
     599             :             else
     600             :             {
     601             :                 // the interface address structure is a 'struct sockaddr_in6'
     602             :                 //
     603             :                 if(memcmp(&reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr)->sin6_addr,
     604             :                             &f_address.sin6_addr,
     605             :                             sizeof(f_address.sin6_addr)) == 0)
     606             :                 {
     607             :                     return computer_interface_address_t::COMPUTER_INTERFACE_ADDRESS_TRUE;
     608             :                 }
     609             :             }
     610             :         }
     611             :     }
     612             : 
     613             :     return computer_interface_address_t::COMPUTER_INTERFACE_ADDRESS_FALSE;
     614             : }
     615             : #endif
     616             : 
     617             : 
     618           6 : }
     619             : // namespace addr
     620             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13