LCOV - code coverage report
Current view: top level - libaddr - addr.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 304 374 81.3 %
Date: 2022-03-01 21:05:13 Functions: 39 46 84.8 %
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             : // self
      33             : //
      34             : #include    "libaddr/addr.h"
      35             : #include    "libaddr/addr_exception.h"
      36             : 
      37             : 
      38             : // snapdev
      39             : //
      40             : #include    <snapdev/int128_literal.h>
      41             : 
      42             : 
      43             : // C++ library
      44             : //
      45             : #include    <sstream>
      46             : #include    <iostream>
      47             : 
      48             : 
      49             : // C library
      50             : //
      51             : #include    <netdb.h>
      52             : 
      53             : 
      54             : // last include
      55             : //
      56             : #include    <snapdev/poison.h>
      57             : 
      58             : 
      59             : 
      60             : /** \mainpage
      61             :  * \brief libaddr, a C++ library to handle network IP addresses in IPv4 and IPv6.
      62             :  *
      63             :  * ### Introduction
      64             :  *
      65             :  * This library is used to parse strings of IP addresses to lists of
      66             :  * binary IP addresses ready to be used by functions such as bind(),
      67             :  * send(), recv(), etc.
      68             :  *
      69             :  * The library supports multiple addresses separated by commas and/or
      70             :  * spaces, ports, and CIDR masks. It can check whether an address matches
      71             :  * another taking the mask in account. It can sort IPs numerically. It
      72             :  * can determine the type of an IP address (i.e. is it a local address,
      73             :  * a private address, a public address?)
      74             :  *
      75             :  * The library also has a function to read IP addresses from your
      76             :  * computer interfaces and return that list. Very practical to know
      77             :  * whether an IP address represents your computer or not.
      78             :  *
      79             :  * ### Usage
      80             :  *
      81             :  * The library is composed of three main classes:
      82             :  *
      83             :  * \li addr
      84             :  *
      85             :  * The address class holds one address, a port, a protocol and a few
      86             :  * other parts. This is what one uses to connect or listen with an
      87             :  * address.
      88             :  *
      89             :  * The address is kept by addr in an IPv6 address structure.
      90             :  *
      91             :  * By default the CIDR of the address is all 1s (i.e. no masking, all
      92             :  * bits considered important.) The mask is always 128 bits. If you are
      93             :  * dealing with IPv4, make sure that the first 12 bytes are set to 255.
      94             :  *
      95             :  * The class also offers a set of functions to transform the binary
      96             :  * address it is holding to a string.
      97             :  *
      98             :  * \li addr_range
      99             :  *
     100             :  * It is possible to define a range of addresses and ports. This class
     101             :  * holds a 'from' address and a 'to' address. By default neither is
     102             :  * defined. You have to call the set_from() and set_to() functions.
     103             :  *
     104             :  * The addr_range::vector_t is what the addr_parser returns after
     105             :  * parsing a string representing one of more addresses.
     106             :  *
     107             :  * \note
     108             :  * The range is functional, however, the parser does not yet support
     109             :  * parsing range of addresses and ports.
     110             :  *
     111             :  * \li addr_parser
     112             :  *
     113             :  * The parser is used to transform a string to an address.
     114             :  *
     115             :  * It supports many variations of its input, which are handled by
     116             :  * the 'allow' flags. The set_allow() and get_allow() functions can
     117             :  * be used to tweak the parser in supporting such and such feature.
     118             :  *
     119             :  * By default, the input is expected to be an address and a port
     120             :  * separated by a colon (i.e. `"1.2.3.4:1234"` in IPv4 and `"[::1]:1234"`
     121             :  * in IPv6.)
     122             :  *
     123             :  * ### Parser
     124             :  *
     125             :  * The parser supports the following syntax (ranges are not yet supported
     126             :  * and they do not appear in the following list):
     127             :  *
     128             :  * \code
     129             :  *    start: address_list
     130             :  *
     131             :  *    address_list: address_cidr
     132             :  *                | address_list address_list_separators address_cidr
     133             :  *
     134             :  *    address_list_separators: ' '
     135             :  *                           | ','
     136             :  *                           | address_list_separators address_list_separators
     137             :  *
     138             :  *    address_cidr: address_port
     139             :  *                | address_port '/' cidr
     140             :  *
     141             :  *    address_port: address
     142             :  *                | address ':' port
     143             :  *
     144             :  *    address: ipv4
     145             :  *           | ipv6
     146             :  *
     147             :  *    cidr: decimal_number
     148             :  *        | ipv4
     149             :  *        | ipv6
     150             :  *
     151             :  *    ipv4: decimal_number '.' decimal_number '.' decimal_number '.' decimal_number
     152             :  *
     153             :  *    ipv6: '[' hexadecimal_number_list ']'
     154             :  *
     155             :  *    port: decimal_number
     156             :  *
     157             :  *    hexadecimal_number_list: hexadecimal_number
     158             :  *                           | hexadecimal_number_list ':' hexadecimal_number
     159             :  *
     160             :  *    decimal_number: [0-9]+
     161             :  *
     162             :  *    hexadecimal_number: [0-9a-fA-F]+
     163             :  * \endcode
     164             :  *
     165             :  * When accepting multiple addresses separated by commas or spaces, the
     166             :  * number of commas and spaces separating two address is not significant.
     167             :  * The input string can also start or end with commas and spaces. The
     168             :  * following variable defines exactly two IP address:
     169             :  *
     170             :  * \code
     171             :  *       addresses=  ,1.2.3.4,   ,5.6.7.8,,
     172             :  * \endcode
     173             :  *
     174             :  * (note that the parser should not be passed the "addresses=" part.)
     175             :  */
     176             : 
     177             : 
     178             : /** \brief The libaddr classes are all defined in this namespace.
     179             :  *
     180             :  * The addr namespace includes all the addr classes.
     181             :  */
     182             : namespace addr
     183             : {
     184             : 
     185             : /*
     186             :  * Various sytem address structures
     187             : 
     188             : // Any address is 16 bytes or less
     189             : struct sockaddr {
     190             :    unsigned short    sa_family;    // address family, AF_xxx
     191             :    char              sa_data[14];  // 14 bytes of protocol address
     192             : };
     193             : 
     194             : struct sockaddr_storage {
     195             :     sa_family_t  ss_family;     // address family
     196             : 
     197             :     // all this is padding, implementation specific, ignore it:
     198             :     char      __ss_pad1[_SS_PAD1SIZE];
     199             :     int64_t   __ss_align;
     200             :     char      __ss_pad2[_SS_PAD2SIZE];
     201             : };
     202             : 
     203             : 
     204             : typedef uint32_t in_addr_t;   // or `__be32`
     205             : struct in_addr {
     206             :     in_addr_t        s_addr;
     207             : };
     208             : 
     209             : 
     210             : // IPv4
     211             : struct sockaddr_in {
     212             :     short            sin_family;   // e.g. AF_INET, AF_INET6
     213             :     unsigned short   sin_port;     // e.g. htons(3490)
     214             :     struct in_addr   sin_addr;     // see struct in_addr, below
     215             :     char             sin_zero[8];  // zero this if you want to
     216             : };
     217             : 
     218             : 
     219             : struct in6_addr
     220             : {
     221             :     union
     222             :     {
     223             :          uint8_t    __u6_addr8[16];
     224             : #ifdef __USE_MISC
     225             :          uint16_t   __u6_addr16[8];
     226             :          uint32_t   __u6_addr32[4];
     227             : #endif
     228             :     } __in6_u;
     229             : #define s6_addr                 __in6_u.__u6_addr8
     230             : #ifdef __USE_MISC
     231             : # define s6_addr16              __in6_u.__u6_addr16
     232             : # define s6_addr32              __in6_u.__u6_addr32
     233             : #endif
     234             : };
     235             : 
     236             : // IPv6
     237             : struct sockaddr_in6 {
     238             :     u_int16_t       sin6_family;   // address family, AF_INET6
     239             :     u_int16_t       sin6_port;     // port number, Network Byte Order
     240             :     u_int32_t       sin6_flowinfo; // IPv6 flow information
     241             :     struct in6_addr sin6_addr;     // IPv6 address
     242             :     u_int32_t       sin6_scope_id; // Scope ID
     243             : };
     244             : 
     245             : 
     246             : */
     247             : 
     248             : 
     249             : 
     250             : 
     251             : 
     252             : /** \brief Create an addr object that represents an ANY address.
     253             :  *
     254             :  * This function initializes the addr object with the ANY address.
     255             :  * The port is set to 0 and the protocol to TCP.
     256             :  *
     257             :  * It is strongly suggested that you change those parameters
     258             :  * before really using this address since a port of zero and
     259             :  * the protocol may be wrong.
     260             :  */
     261      265124 : addr::addr()
     262             : {
     263             :     // keep default protocol (TCP)
     264      265124 : }
     265             : 
     266             : 
     267             : /** \brief Create an addr object from a binary IPv4 address.
     268             :  *
     269             :  * This function initializes this addr object with the specified IPv4
     270             :  * address. The is_ipv4() function will return true.
     271             :  *
     272             :  * \param[in] in  The binary IPv4 address.
     273             :  */
     274       66029 : addr::addr(sockaddr_in const & in)
     275             : {
     276       66004 :     set_ipv4(in);
     277             :     // keep default protocol (TCP)
     278       65979 : }
     279             : 
     280             : 
     281             : /** \brief Create an addr object from a binary IPv6 address.
     282             :  *
     283             :  * This function initializes this addr object with the specified IPv6
     284             :  * address. The is_ipv4() function will return false.
     285             :  *
     286             :  * \param[in] in6  The binary IPv6 address.
     287             :  */
     288       65992 : addr::addr(sockaddr_in6 const & in6)
     289             : {
     290       65991 :     set_ipv6(in6);
     291             :     // keep default protocol (TCP)
     292       65990 : }
     293             : 
     294             : 
     295             : /** \brief Save an IPv4 in this addr object.
     296             :  *
     297             :  * This function saves the specified IPv4 in this addr object.
     298             :  *
     299             :  * Since we save the data in an IPv6 structure, it is kept in
     300             :  * the addr as an IPv4 mapped in an IPv6 address. It can still
     301             :  * be retrieved right back as an IPv4 with the get_ipv4() function.
     302             :  *
     303             :  * \param[in] in  The IPv4 address to save in this addr object.
     304             :  */
     305       66820 : void addr::set_ipv4(sockaddr_in const & in)
     306             : {
     307       66820 :     if(in.sin_family != AF_INET)
     308             :     {
     309             :         // although we convert the IPv4 to an IPv6 below, we really only
     310             :         // support AF_INET on entry
     311             :         //
     312          50 :         throw addr_invalid_argument("addr::set_ipv4(): the input address does not represent an IPv4 address (family is not AF_INET).");
     313             :     }
     314             : 
     315             :     // reset the address first
     316       66770 :     memset(&f_address, 0, sizeof(f_address));
     317             : 
     318             :     // then transform the IPv4 to an IPv6
     319             :     //
     320             :     // Note: this is not an IPv6 per se, it is an IPv4 mapped within an
     321             :     //       IPv6 and your network stack needs to support IPv4 anyway
     322             :     //       in order to use that IP...
     323             :     //
     324       66770 :     f_address.sin6_family = AF_INET6;
     325       66770 :     f_address.sin6_port = in.sin_port;
     326       66770 :     f_address.sin6_addr.s6_addr16[5] = 0xFFFF;
     327       66770 :     f_address.sin6_addr.s6_addr32[3] = in.sin_addr.s_addr;
     328             : 
     329       66770 :     address_changed();
     330       66770 : }
     331             : 
     332             : 
     333             : /** \brief Set the port of this address.
     334             :  *
     335             :  * This function changes the port of this address to \p port.
     336             :  *
     337             :  * \exception addr_invalid_argument
     338             :  * This exception is raised whenever the \p port parameter is set to
     339             :  * an invalid number (negative or larger than 65535.)
     340             :  *
     341             :  * \param[in] port  The new port to save in this address.
     342             :  */
     343       65741 : void addr::set_port(int port)
     344             : {
     345       65741 :     if(port > 65535 
     346       65641 :     || port < 0)
     347             :     {
     348         200 :         throw addr_invalid_argument("port to set_port() cannot be out of the allowed range [0..65535].");
     349             :     }
     350       65541 :     f_address.sin6_port = htons(port);
     351       65541 : }
     352             : 
     353             : 
     354             : /** \brief Change the protocol using a string.
     355             :  *
     356             :  * This function is used to change the current protocol defined in
     357             :  * this addr object.
     358             :  *
     359             :  * \exception addr_invalid_argument
     360             :  * We currently support "tcp", "udp", and "ip". Any other protocol
     361             :  * name generates this exception.
     362             :  *
     363             :  * \param[in] protocol  The name of the protocol ("tcp", "udp", or "ip")
     364             :  */
     365           7 : void addr::set_protocol(char const * protocol)
     366             : {
     367           7 :     if(protocol == nullptr)
     368             :     {
     369           1 :         throw addr_invalid_argument("protocol pointer to set_protocol() cannot be a nullptr.");
     370             :     }
     371             : 
     372           6 :     if(strcmp(protocol, "ip") == 0)
     373             :     {
     374           1 :         f_protocol = IPPROTO_IP;
     375             :     }
     376           5 :     else if(strcmp(protocol, "tcp") == 0)
     377             :     {
     378           1 :         f_protocol = IPPROTO_TCP;
     379             :     }
     380           4 :     else if(strcmp(protocol, "udp") == 0)
     381             :     {
     382           1 :         f_protocol = IPPROTO_UDP;
     383             :     }
     384             :     else
     385             :     {
     386             :         throw addr_invalid_argument(
     387           6 :                           std::string("unknown protocol \"")
     388           9 :                         + protocol
     389           9 :                         + "\", expected \"tcp\" or \"udp\" (string).");
     390             :     }
     391             : 
     392           3 :     address_changed();
     393           3 : }
     394             : 
     395             : 
     396             : /** \brief Set the protocol numerically.
     397             :  *
     398             :  * This function sets the protocol from a number instead of a name.
     399             :  *
     400             :  * Note that we only support IPPROTO_TCP and IPPROTO_UDP for now.
     401             :  * Any other protocol will make this function raise an exception.
     402             :  *
     403             :  * \todo
     404             :  * We may want to support any protocol number at this level. If your
     405             :  * application is limited then it should verify the protocol and
     406             :  * make sure it supports it before using this address. At the same
     407             :  * time, the IP protocol is pretty much locked up with just TCP
     408             :  * and UDP these days (there is the IP protocol, but that's not
     409             :  * useful at our level.)
     410             :  *
     411             :  * \exception addr_invalid_argument
     412             :  * This exception is raised if the specified protocol is not currently
     413             :  * supported by the addr implementation.
     414             :  *
     415             :  * \param[in] protocol  The new numeric protocol.
     416             :  */
     417      131963 : void addr::set_protocol(int protocol)
     418             : {
     419      131963 :     switch(protocol)
     420             :     {
     421      131863 :     case IPPROTO_IP:
     422             :     case IPPROTO_TCP:
     423             :     case IPPROTO_UDP:
     424      131863 :         f_protocol = protocol;
     425      131863 :         break;
     426             : 
     427         100 :     default:
     428             :         throw addr_invalid_argument(
     429             :                           "unknown protocol number "
     430         200 :                         + std::to_string(protocol)
     431         300 :                         + ", expected \"tcp\" ("
     432         400 :                         + std::to_string(static_cast<int>(IPPROTO_TCP))
     433         300 :                         + ") or \"udp\" ("
     434         400 :                         + std::to_string(static_cast<int>(IPPROTO_UDP))
     435         300 :                         + ") (numeric).");
     436             : 
     437             :     }
     438      131863 : }
     439             : 
     440             : 
     441             : /** \brief Set the mask.
     442             :  *
     443             :  * The input mask must be at least 16 bytes. If you are dealing with an
     444             :  * IPv4, make sure the first 12 bytes are 255.
     445             :  *
     446             :  * \todo
     447             :  * Look into having a type that clearly defines the buffer size.
     448             :  *
     449             :  * \param[in] mask  The mask to save in this address.
     450             :  */
     451         682 : void addr::set_mask(std::uint8_t const * mask)
     452             : {
     453         682 :     memcpy(f_mask, mask, sizeof(f_mask));
     454         682 : }
     455             : 
     456             : 
     457             : /** \brief Apply the mask to the IP address.
     458             :  *
     459             :  * This function applies the mask to this address IP address. This means
     460             :  * the bits that are 0 in the mask will also be 0 in the address once
     461             :  * the function returns.
     462             :  *
     463             :  * This should be called if you are trying to canonicalize an IP/mask.
     464             :  */
     465           1 : void addr::apply_mask()
     466             : {
     467          17 :     for(int idx(0); idx < 16; ++idx)
     468             :     {
     469          16 :         f_address.sin6_addr.s6_addr[idx] &= f_mask[idx];
     470             :     }
     471           1 : }
     472             : 
     473             : 
     474             : /** \brief Get the mask.
     475             :  *
     476             :  * The output buffer for the mask must be at least 16 bytes. If you are
     477             :  * dealing with an IPv4, all the bytes are expected to be 255 except
     478             :  * the bottom 4 bytes (offset 12, 13, 14, 15).
     479             :  *
     480             :  * \todo
     481             :  * Look into having a type that clearly defines the buffer size.
     482             :  *
     483             :  * \param[out] mask  The buffer where the mask gets copied.
     484             :  */
     485         156 : void addr::get_mask(std::uint8_t * mask) const
     486             : {
     487         156 :     memcpy(mask, f_mask, sizeof(f_mask));
     488         156 : }
     489             : 
     490             : 
     491             : /** \brief Get the mask as a number of bits set to 1.
     492             :  *
     493             :  * This function computes the number of bits set to 1 starting from the most
     494             :  * significant bit.
     495             :  *
     496             :  * If the function detects that a simple number of bits cannot represent
     497             :  * the mask, then the function returns -1.
     498             :  *
     499             :  * A count of 0 means that the mask is all zeroes.
     500             :  *
     501             :  * A count of 128 means that the mask is all ones.
     502             :  *
     503             :  * To compute an IPv4 count, subtract 96 from the result. If the result is
     504             :  * not at least 96, then the mask is not a valid IPv4 mask.
     505             :  *
     506             :  * \note
     507             :  * The current Internet consortium says that only masks that can be
     508             :  * represented as a simple number are valid. In other words, if this
     509             :  * function returns -1, this means the mask is considered invalid.
     510             :  *
     511             :  * \return The number of bits in the mask or -1 if the mask has holes.
     512             :  */
     513           0 : int addr::get_mask_size() const
     514             : {
     515           0 :     int count(0);
     516             : 
     517           0 :     bool found(false);
     518           0 :     for(std::size_t i(0); i < sizeof(f_mask); ++i)
     519             :     {
     520           0 :         if(found)
     521             :         {
     522           0 :             if(f_mask[i] != 0x00)
     523             :             {
     524           0 :                 return -1;
     525             :             }
     526             :         }
     527             :         else
     528             :         {
     529           0 :             switch(f_mask[i])
     530             :             {
     531           0 :             case 0xFF:
     532           0 :                 count += 8;
     533           0 :                 break;
     534             : 
     535           0 :             case 0xFE:
     536           0 :                 count += 7;
     537           0 :                 found = true;
     538           0 :                 break;
     539             : 
     540           0 :             case 0xFC:
     541           0 :                 count += 6;
     542           0 :                 found = true;
     543           0 :                 break;
     544             : 
     545           0 :             case 0xF8:
     546           0 :                 count += 5;
     547           0 :                 found = true;
     548           0 :                 break;
     549             : 
     550           0 :             case 0xF0:
     551           0 :                 count += 4;
     552           0 :                 found = true;
     553           0 :                 break;
     554             : 
     555           0 :             case 0xE0:
     556           0 :                 count += 3;
     557           0 :                 found = true;
     558           0 :                 break;
     559             : 
     560           0 :             case 0xC0:
     561           0 :                 count += 2;
     562           0 :                 found = true;
     563           0 :                 break;
     564             : 
     565           0 :             case 0x80:
     566           0 :                 count += 1;
     567           0 :                 found = true;
     568           0 :                 break;
     569             : 
     570           0 :             case 0x00:
     571           0 :                 found = true;
     572           0 :                 break;
     573             : 
     574           0 :             default:
     575           0 :                 return -1;
     576             : 
     577             :             }
     578             :         }
     579             :     }
     580             : 
     581           0 :     return count;
     582             : }
     583             : 
     584             : 
     585             : /** \brief Return the original hostname.
     586             :  *
     587             :  * When parsing an address with the addr::addr_parser::parse() function,
     588             :  * the hostnames appearing in the input get transformed in IP addresses.
     589             :  * It also saves the corresponding address in the hostname parameter
     590             :  * of the address and it can be retrieved with this function.
     591             :  *
     592             :  * You can use the set_hostname() function if you would like to change
     593             :  * this value.
     594             :  *
     595             :  * \note
     596             :  * The parser saves the original address which means the hostname may
     597             :  * actually be an IP address. You can check that with the
     598             :  * is_hostname_an_ip() function.
     599             :  *
     600             :  * \return The original hostname.
     601             :  *
     602             :  * \sa set_hostname()
     603             :  */
     604           0 : std::string addr::get_hostname() const
     605             : {
     606           0 :     return f_hostname;
     607             : }
     608             : 
     609             : 
     610             : /** \brief Check whether the hostname is an IP address or not.
     611             :  *
     612             :  * Check whether the hostname represents a valid IP address (opposed to
     613             :  * an actual domain name).
     614             :  *
     615             :  * \warning
     616             :  * If you did not use the parser, the hostname is empty and therefore
     617             :  * it is neither an IP nor a hostname. However, in this special case
     618             :  * this function returns true.
     619             :  *
     620             :  * \return true if the hostname parameter represents an IP address.
     621             :  */
     622           0 : bool addr::is_hostname_an_ip() const
     623             : {
     624           0 :     if(f_hostname.empty())
     625             :     {
     626             :         // this is not a valid hostname, so return true
     627             :         //
     628           0 :         return true;
     629             :     }
     630             : 
     631           0 :     in6_addr ignore;
     632             :     static_assert(sizeof(ignore) >= sizeof(in_addr));
     633           0 :     return inet_pton(AF_INET, f_hostname.c_str(), &ignore) == 1
     634           0 :         || inet_pton(AF_INET6, f_hostname.c_str(), &ignore) == 1;
     635             : }
     636             : 
     637             : 
     638             : /** \brief Get the family representing this IP address.
     639             :  *
     640             :  * This is either an IPv4, so AF_INET, or an IPv6, in which case the function
     641             :  * returns AF_INET6. No other family is supported by the addr at the moment.
     642             :  *
     643             :  * \return One of AF_INET or AF_INET6.
     644             :  */
     645           0 : int addr::get_family() const
     646             : {
     647           0 :     return is_ipv4() ? AF_INET : AF_INET6;
     648             : }
     649             : 
     650             : 
     651             : /** \brief Check whether this address represents the ANY or NULL address.
     652             :  *
     653             :  * The IPv4 and IPv6 have an ANY address also called the default address
     654             :  * and the null address. This function returns true if this address
     655             :  * represents the ANY address.
     656             :  *
     657             :  * The any address is represented by `"0.0.0.0"` in IPv4 and `"::"` in
     658             :  * IPv6. (i.e. all zeroes)
     659             :  *
     660             :  * \note
     661             :  * You can also determine this by calling the get_network_type() function
     662             :  * and compare the result against `network_type_t::NETWORK_TYPE_ANY`.
     663             :  *
     664             :  * \return true if this addr represents the any address.
     665             :  */
     666          40 : bool addr::is_default() const
     667             : {
     668             :     // this is for IPv4 or IPv6
     669             :     //
     670          40 :     return f_address.sin6_addr.s6_addr32[0] == 0
     671          40 :         && f_address.sin6_addr.s6_addr32[1] == 0
     672          40 :         && f_address.sin6_addr.s6_addr16[4] == 0
     673          40 :         && (f_address.sin6_addr.s6_addr16[5] == 0 || f_address.sin6_addr.s6_addr16[5] == 0xFFFF)
     674          80 :         && f_address.sin6_addr.s6_addr32[3] == 0;
     675             : }
     676             : 
     677             : 
     678             : /** \brief Check whether this address represents an IPv4 address.
     679             :  *
     680             :  * The IPv6 format supports embedding IPv4 addresses. This function
     681             :  * returns true if the embedded address is an IPv4. When this function
     682             :  * returns true, the get_ipv4() can be called. Otherwise, the get_ipv4()
     683             :  * function throws an exception.
     684             :  *
     685             :  * \return true if this address represents an IPv4 address.
     686             :  */
     687      527647 : bool addr::is_ipv4() const
     688             : {
     689      527647 :     return f_address.sin6_addr.s6_addr32[0] == 0
     690      329919 :         && f_address.sin6_addr.s6_addr32[1] == 0
     691      329915 :         && f_address.sin6_addr.s6_addr16[4] == 0
     692      857560 :         && f_address.sin6_addr.s6_addr16[5] == 0xFFFF;
     693             : }
     694             : 
     695             : 
     696             : /** \brief Retreive the IPv4 address.
     697             :  *
     698             :  * This function can be used to retrieve the IPv4 address of this addr
     699             :  * object. If the address is not an IPv4, then the function throws.
     700             :  *
     701             :  * \exception addr_invalid_state
     702             :  * This exception is raised if the address is not an IPv4 address.
     703             :  *
     704             :  * \param[out] in  The structure where the IPv4 Internet address gets saved.
     705             :  */
     706          66 : void addr::get_ipv4(sockaddr_in & in) const
     707             : {
     708          66 :     if(is_ipv4())
     709             :     {
     710             :         // this is an IPv4 mapped in an IPv6, "unmap" that IP
     711             :         //
     712          65 :         memset(&in, 0, sizeof(in));
     713          65 :         in.sin_family = AF_INET;
     714          65 :         in.sin_port = f_address.sin6_port;
     715          65 :         in.sin_addr.s_addr = f_address.sin6_addr.s6_addr32[3];
     716         130 :         return;
     717             :     }
     718             : 
     719           1 :     throw addr_invalid_state("Not an IPv4 compatible address.");
     720             : }
     721             : 
     722             : 
     723             : /** \brief Save the specified IPv6 address in this addr object.
     724             :  *
     725             :  * This function saves the specified IPv6 address in this addr object.
     726             :  * The function does not check the validity of the address. It is
     727             :  * expected to be valid.
     728             :  *
     729             :  * The address may be an embedded IPv4 address.
     730             :  *
     731             :  * \param[in] in6  The source IPv6 to save in the addr object.
     732             :  */
     733       66189 : void addr::set_ipv6(sockaddr_in6 const & in6)
     734             : {
     735       66189 :     if(in6.sin6_family != AF_INET6)
     736             :     {
     737           2 :         throw addr_invalid_argument("addr::set_ipv6(): the input address does not represent an IPv6 address (family is not AF_INET6).");
     738             :     }
     739       66187 :     memcpy(&f_address, &in6, sizeof(in6));
     740             : 
     741       66187 :     address_changed();
     742       66187 : }
     743             : 
     744             : 
     745             : /** \brief Retrieve a copy of this addr IP address.
     746             :  *
     747             :  * This function returns the current IP address saved in this
     748             :  * addr object. The IP may represent an IPv4 address in which
     749             :  * case the is_ipv4() returns true.
     750             :  *
     751             :  * \param[out] in6  The structure where the address gets saved.
     752             :  */
     753          21 : void addr::get_ipv6(sockaddr_in6 & in6) const
     754             : {
     755          21 :     memcpy(&in6, &f_address, sizeof(in6));
     756          21 : }
     757             : 
     758             : 
     759             : /** \brief Retrive the IPv4 as a string.
     760             :  *
     761             :  * This function returns a string representing the IP address
     762             :  * defined in this addr object.
     763             :  *
     764             :  * The \p mode parameter defines what gets output.
     765             :  *
     766             :  * \li ip_string_t::IP_STRING_ONLY -- only the IP address
     767             :  * \li ip_string_t::IP_STRING_PORT -- the IP and port
     768             :  * \li ip_string_t::IP_STRING_MASK -- the IP and mask
     769             :  * \li ip_string_t::IP_STRING_ALL -- the IP, port, and mask
     770             :  *
     771             :  * The ip_string_t::IP_STRING_BRACKET is viewed as
     772             :  * ip_string_t::IP_STRING_ONLY.
     773             :  *
     774             :  * The ip_string_t::IP_STRING_BRACKET_MASK is viewed as
     775             :  * ip_string_t::IP_STRING_MASK.
     776             :  *
     777             :  * \exception addr_invalid_state_exception
     778             :  * If the addr object does not currently represent an IPv4 then
     779             :  * this exception is raised.
     780             :  *
     781             :  * \param[in] mode  How the output string is to be built.
     782             :  */
     783      131705 : std::string addr::to_ipv4_string(string_ip_t mode) const
     784             : {
     785      131705 :     if(is_ipv4())
     786             :     {
     787             :         // this is an IPv4 mapped in an IPv6, "unmap" that IP
     788             :         // so the inet_ntop() can correctly generate an output IP
     789             :         //
     790      131699 :         in_addr in;
     791      131699 :         memset(&in, 0, sizeof(in));
     792      131699 :         in.s_addr = f_address.sin6_addr.s6_addr32[3];
     793      131699 :         char buf[INET_ADDRSTRLEN + 1];
     794      131699 :         if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
     795             :         {
     796      131699 :             if(mode != string_ip_t::STRING_IP_ONLY)
     797             :             {
     798        1152 :                 std::stringstream result;
     799         576 :                 result << buf;
     800         576 :                 if(mode == string_ip_t::STRING_IP_PORT
     801         266 :                 || mode == string_ip_t::STRING_IP_ALL)
     802             :                 {
     803         546 :                     result << ":";
     804         546 :                     result << ntohs(f_address.sin6_port);
     805             :                 }
     806         576 :                 if(mode == string_ip_t::STRING_IP_MASK
     807         566 :                 || mode == string_ip_t::STRING_IP_BRACKETS_MASK
     808         556 :                 || mode == string_ip_t::STRING_IP_ALL)
     809             :                 {
     810         256 :                     memset(&in, 0, sizeof(in));
     811         256 :                     in.s_addr = htonl((f_mask[12] << 24) | (f_mask[13] << 16) | (f_mask[14] << 8) | f_mask[15]);
     812         256 :                     if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
     813             :                     {
     814         256 :                         result << "/";
     815         256 :                         result << buf; // TODO: convert to simple number if possible
     816             :                     }
     817             :                 }
     818         576 :                 return result.str();
     819             :             }
     820      131123 :             return std::string(buf);
     821             :         }
     822             :         // IPv4 should never fail converting the address unless the
     823             :         // buffer was too small...
     824             :     }
     825             : 
     826           6 :     throw addr_invalid_state("Not an IPv4 compatible address.");
     827             : }
     828             : 
     829             : 
     830             : /** \brief Convert the addr object to a string.
     831             :  *
     832             :  * This function converts the addr object to a canonicalized string.
     833             :  * This can be used to compare two IPv6 together as strings, although
     834             :  * it is probably better to compare them using the < and == operators.
     835             :  *
     836             :  * By default the function returns with the IPv6 address defined
     837             :  * between square bracket, so the output of this function can be
     838             :  * used as the input of the set_addr_port() function. You may
     839             :  * also request the address without the brackets.
     840             :  *
     841             :  * \exception addr_invalid_state_exception
     842             :  * If the binary IP address cannot be converted to ASCII, this exception
     843             :  * is raised.
     844             :  *
     845             :  * \param[in] mode  How the output string is to be built.
     846             :  *
     847             :  * \return The addr object converted to an IPv6 address.
     848             :  */
     849      263055 : std::string addr::to_ipv6_string(string_ip_t mode) const
     850             : {
     851      263055 :     char buf[INET6_ADDRSTRLEN + 1];
     852      263055 :     if(inet_ntop(AF_INET6, &f_address.sin6_addr, buf, sizeof(buf)) != nullptr)
     853             :     {
     854      263055 :         bool const include_brackets(mode == string_ip_t::STRING_IP_BRACKETS
     855      197503 :                                  || mode == string_ip_t::STRING_IP_BRACKETS_MASK
     856      197491 :                                  || mode == string_ip_t::STRING_IP_PORT // port requires us to add brackets
     857      329262 :                                  || mode == string_ip_t::STRING_IP_ALL);
     858             : 
     859      526110 :         std::stringstream result;
     860             : 
     861             :         // always insert the IP, even if ANY or "BROADCAST"
     862             :         //
     863      263055 :         if(include_brackets)
     864             :         {
     865      197476 :             result << "[";
     866             :         }
     867      263055 :         result << buf;
     868      263055 :         if(include_brackets)
     869             :         {
     870      197476 :             result << "]";
     871             :         }
     872             : 
     873             :         // got a port?
     874             :         //
     875      263055 :         if(mode == string_ip_t::STRING_IP_PORT
     876      131771 :         || mode == string_ip_t::STRING_IP_ALL)
     877             :         {
     878      131912 :             result << ":";
     879      131912 :             result << ntohs(f_address.sin6_port);
     880             :         }
     881             : 
     882             :         // got a mask?
     883             :         //
     884      263055 :         if(mode == string_ip_t::STRING_IP_MASK
     885      263043 :         || mode == string_ip_t::STRING_IP_BRACKETS_MASK
     886      263031 :         || mode == string_ip_t::STRING_IP_ALL)
     887             :         {
     888         652 :             if(inet_ntop(AF_INET6, f_mask, buf, sizeof(buf)) != nullptr)
     889             :             {
     890         652 :                 result << "/";
     891         652 :                 if(include_brackets)
     892             :                 {
     893         640 :                     result << "[";
     894             :                 }
     895         652 :                 result << buf; // TODO: convert to simple number if possible
     896         652 :                 if(include_brackets)
     897             :                 {
     898         640 :                     result << "]";
     899             :                 }
     900             :             }
     901             :         }
     902             : 
     903      526110 :         return result.str();
     904             :     }
     905             : 
     906             :     throw addr_invalid_state("The address from this addr could not be converted to a valid canonicalized IPv6 address.");  // LCOV_EXCL_LINE
     907             : }
     908             : 
     909             : 
     910             : /** \brief Return the address as IPv4 or IPv6.
     911             :  *
     912             :  * Depending on whether the address represents an IPv4 or an IPv6,
     913             :  * this function returns the corresponding address. Since the format
     914             :  * of both types of addresses can always be distinguished, it poses
     915             :  * no concerns.
     916             :  *
     917             :  * \exception 
     918             :  * If include_brackets is false and include_port is true, this
     919             :  * exception is raised because we cannot furfill the request.
     920             :  *
     921             :  * \param[in] mode  How the output string is to be built.
     922             :  *
     923             :  * \return The addr object converted to an IPv4 or an IPv6 address.
     924             :  */
     925      131776 : std::string addr::to_ipv4or6_string(string_ip_t mode) const
     926             : {
     927      131776 :     return is_ipv4() ? to_ipv4_string(mode)
     928      131776 :                      : to_ipv6_string(mode);
     929             : }
     930             : 
     931             : 
     932             : /** \brief Convert the IP address to an unsigned 128 bit ingeter.
     933             :  *
     934             :  * This function converts the IP address to an integer of 128 bits which
     935             :  * supports IPv6 and IPv4.
     936             :  *
     937             :  * \return The address converted to a unsigned int128 bit integer.
     938             :  */
     939             : #pragma GCC diagnostic push
     940             : #pragma GCC diagnostic ignored "-Wpedantic"
     941           0 : unsigned __int128 addr::ip_to_uint128() const
     942             : {
     943             :     // warning: the address is defined in big endian so we want to
     944             :     //          swap those bytes
     945             :     //
     946           0 :     unsigned __int128 result(0);
     947           0 :     for(std::size_t idx(0); idx < sizeof(f_address.sin6_addr.s6_addr); ++idx)
     948             :     {
     949           0 :         result <<= 8;
     950           0 :         result |= static_cast<unsigned __int128>(f_address.sin6_addr.s6_addr[idx]);
     951             :     }
     952             : 
     953           0 :     return result;
     954             : }
     955             : #pragma GCC diagnostic pop
     956             : 
     957             : 
     958             : /** \brief Determine the type of network this IP represents.
     959             :  *
     960             :  * The IP address may represent various type of networks. This
     961             :  * function returns that type.
     962             :  *
     963             :  * The function checks the address either as IPv4 when is_ipv4()
     964             :  * returns true, otherwise as IPv6.
     965             :  *
     966             :  * See:
     967             :  *
     968             :  * \li https://en.wikipedia.org/wiki/Reserved_IP_addresses
     969             :  * \li https://tools.ietf.org/html/rfc3330
     970             :  * \li https://tools.ietf.org/html/rfc5735 (IPv4)
     971             :  * \li https://tools.ietf.org/html/rfc5156 (IPv6)
     972             :  *
     973             :  * \return One of the possible network types as defined in the
     974             :  *         network_type_t enumeration.
     975             :  */
     976      131790 : addr::network_type_t addr::get_network_type() const
     977             : {
     978      131790 :     if(f_private_network == network_type_t::NETWORK_TYPE_UNDEFINED)
     979             :     {
     980      131631 :         f_private_network = network_type_t::NETWORK_TYPE_UNKNOWN;
     981             : 
     982      131631 :         if(is_ipv4())
     983             :         {
     984             :             // get the address in host order
     985             :             //
     986             :             // we can use a simple mask + compare to know whether it is
     987             :             // this or that once in host order
     988             :             //
     989       65897 :             uint32_t const host_ip(ntohl(f_address.sin6_addr.s6_addr32[3]));
     990             : 
     991       65897 :             if((host_ip & 0xFF000000) == 0x0A000000         // 10.0.0.0/8
     992       65882 :             || (host_ip & 0xFFF00000) == 0xAC100000         // 172.16.0.0/12
     993       65760 :             || (host_ip & 0xFFFF0000) == 0xC0A80000)        // 192.168.0.0/16
     994             :             {
     995       65690 :                 f_private_network = network_type_t::NETWORK_TYPE_PRIVATE;
     996             :             }
     997         207 :             else if((host_ip & 0xFFC00000) == 0x64400000)   // 100.64.0.0/10
     998             :             {
     999          10 :                 f_private_network = network_type_t::NETWORK_TYPE_CARRIER;
    1000             :             }
    1001         197 :             else if((host_ip & 0xFFFF0000) == 0xA9FE0000)   // 169.254.0.0/16
    1002             :             {
    1003          10 :                 f_private_network = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
    1004             :             }
    1005         187 :             else if((host_ip & 0xF0000000) == 0xE0000000)   // 224.0.0.0/4
    1006             :             {
    1007             :                 // there are many sub-groups on this one which are probably
    1008             :                 // still in use...
    1009             :                 //
    1010          10 :                 f_private_network = network_type_t::NETWORK_TYPE_MULTICAST;
    1011             :             }
    1012         177 :             else if((host_ip & 0xFF000000) == 0x7F000000)   // 127.0.0.0/8
    1013             :             {
    1014          14 :                 f_private_network = network_type_t::NETWORK_TYPE_LOOPBACK; // i.e. localhost
    1015             :             }
    1016         163 :             else if(host_ip == 0x00000000)
    1017             :             {
    1018           1 :                 f_private_network = network_type_t::NETWORK_TYPE_ANY; // i.e. 0.0.0.0
    1019             :             }
    1020             :         }
    1021             :         else //if(is_ipv6()) -- if not IPv4, we have an IPv6
    1022             :         {
    1023             :             // for IPv6 it was simplified by using a prefix for
    1024             :             // all types; really way easier than IPv4
    1025             :             //
    1026       65734 :             if(f_address.sin6_addr.s6_addr32[0] == 0      // ::
    1027          35 :             && f_address.sin6_addr.s6_addr32[1] == 0
    1028          31 :             && f_address.sin6_addr.s6_addr32[2] == 0
    1029          27 :             && f_address.sin6_addr.s6_addr32[3] == 0)
    1030             :             {
    1031             :                 // this is the "any" IP address
    1032           2 :                 f_private_network = network_type_t::NETWORK_TYPE_ANY;
    1033             :             }
    1034             :             else
    1035             :             {
    1036       65732 :                 uint16_t const prefix(ntohs(f_address.sin6_addr.s6_addr16[0]));
    1037             : 
    1038       65732 :                 if((prefix & 0xFF00) == 0xFD00)                 // fd00::/8
    1039             :                 {
    1040          10 :                     f_private_network = network_type_t::NETWORK_TYPE_PRIVATE;
    1041             :                 }
    1042       65722 :                 else if((prefix & 0xFFC0) == 0xFE80    // fe80::/10
    1043       65709 :                      || (prefix & 0xFF0F) == 0xFF02)   // ffx2::/16
    1044             :                 {
    1045         123 :                     f_private_network = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
    1046             :                 }
    1047       65599 :                 else if((prefix & 0xFF0F) == 0xFF01    // ffx1::/16
    1048          53 :                      || (f_address.sin6_addr.s6_addr32[0] == 0      // ::1
    1049          33 :                       && f_address.sin6_addr.s6_addr32[1] == 0
    1050          29 :                       && f_address.sin6_addr.s6_addr32[2] == 0
    1051          25 :                       && f_address.sin6_addr.s6_addr16[6] == 0
    1052          23 :                       && f_address.sin6_addr.s6_addr16[7] == htons(1)))
    1053             :                 {
    1054       65567 :                     f_private_network = network_type_t::NETWORK_TYPE_LOOPBACK;
    1055             :                 }
    1056          32 :                 else if((prefix & 0xFF00) == 0xFF00)   // ff00::/8
    1057             :                 {
    1058             :                     // this one must be after the link-local and loopback networks
    1059          10 :                     f_private_network = network_type_t::NETWORK_TYPE_MULTICAST;
    1060             :                 }
    1061             :             }
    1062             :         }
    1063             :     }
    1064             : 
    1065      131790 :     return f_private_network;
    1066             : }
    1067             : 
    1068             : 
    1069             : /** \brief Get the network type string
    1070             :  *
    1071             :  * Translate the network type into a string, which can be really useful
    1072             :  * to log that information.
    1073             :  *
    1074             :  * Note that PUBLIC is the same as UNKNOWN, this function returns
    1075             :  * "Unknown" in that case, though.
    1076             :  *
    1077             :  * \return The string representing the type of network.
    1078             :  */
    1079         159 : std::string addr::get_network_type_string() const
    1080             : {
    1081         159 :     std::string name;
    1082         159 :     switch( get_network_type() )
    1083             :     {
    1084             :     case addr::network_type_t::NETWORK_TYPE_UNDEFINED  : name = "Undefined";  break; // LCOV_EXCL_LINE -- get_network_type() defines it...
    1085          40 :     case addr::network_type_t::NETWORK_TYPE_PRIVATE    : name = "Private";    break;
    1086          10 :     case addr::network_type_t::NETWORK_TYPE_CARRIER    : name = "Carrier";    break;
    1087          30 :     case addr::network_type_t::NETWORK_TYPE_LINK_LOCAL : name = "Local Link"; break;
    1088          20 :     case addr::network_type_t::NETWORK_TYPE_MULTICAST  : name = "Multicast";  break;
    1089          40 :     case addr::network_type_t::NETWORK_TYPE_LOOPBACK   : name = "Loopback";   break;
    1090           3 :     case addr::network_type_t::NETWORK_TYPE_ANY        : name = "Any";        break;
    1091          16 :     case addr::network_type_t::NETWORK_TYPE_UNKNOWN    : name = "Unknown";    break; // == NETWORK_TYPE_PUBLIC
    1092             :     }
    1093         159 :     return name;
    1094             : }
    1095             : 
    1096             : 
    1097             : /** \brief Create a socket from the IP address held by this addr object.
    1098             :  *
    1099             :  * This function creates a socket that corresponds to the addr object
    1100             :  * definitions, it takes the protocol and family information in account.
    1101             :  *
    1102             :  * The flags can be used to add one or more of the following flags:
    1103             :  *
    1104             :  * \li SOCKET_FLAG_NONBLOCK -- create socket as non-block
    1105             :  * \li SOCKET_FLAG_CLOEXEC -- close socket on an execv()
    1106             :  * \li SOCKET_FLAG_REUSE -- for TCP socket, mark the address as immediately
    1107             :  * reusable, ignored for UDP; only useful for server (bind + listen after
    1108             :  * this call)
    1109             :  *
    1110             :  * \note
    1111             :  * The IP protocol is viewed as TCP in this function.
    1112             :  *
    1113             :  * \warning
    1114             :  * This class does not hold the socket created by this function.
    1115             :  *
    1116             :  * \param[in] flags  A set of socket flags to use when creating the socket.
    1117             :  * \param[in] reuse_address  Set the reuse address flag.
    1118             :  *
    1119             :  * \return The socket file descriptor or -1 on errors.
    1120             :  */
    1121           6 : int addr::create_socket(socket_flag_t flags) const
    1122             : {
    1123           6 :     int const sock_flags(
    1124           6 :               ((flags & SOCKET_FLAG_CLOEXEC)  != 0 ? SOCK_CLOEXEC  : 0)
    1125           6 :             | ((flags & SOCKET_FLAG_NONBLOCK) != 0 ? SOCK_NONBLOCK : 0));
    1126           6 :     int const family(is_ipv4() ? AF_INET : AF_INET6);
    1127             : 
    1128           6 :     switch(f_protocol)
    1129             :     {
    1130           4 :     case IPPROTO_IP: // interpret as TCP...
    1131             :     case IPPROTO_TCP:
    1132             :         {
    1133           4 :             int s(socket(family, SOCK_STREAM | sock_flags, IPPROTO_TCP));
    1134             : 
    1135           4 :             if(s >= 0
    1136           4 :             && (flags & SOCKET_FLAG_REUSE) != 0)
    1137             :             {
    1138             :                 // set the "reuse that address immediately" flag, we totally
    1139             :                 // ignore errors on that one
    1140             :                 //
    1141           2 :                 int optval(1);
    1142           2 :                 socklen_t const optlen(sizeof(optval));
    1143           2 :                 static_cast<void>(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, optlen));
    1144             :             }
    1145           4 :             return s;
    1146             :         }
    1147             : 
    1148           2 :     case IPPROTO_UDP:
    1149           2 :         return socket(family, SOCK_DGRAM | sock_flags, IPPROTO_UDP);
    1150             : 
    1151             :     default:            // LCOV_EXCL_LINE
    1152             :         // this should never happen since we control the f_protocol field
    1153             :         //
    1154             :         return -1;      // LCOV_EXCL_LINE
    1155             : 
    1156             :     }
    1157             : }
    1158             : 
    1159             : 
    1160             : /** \brief Connect the specified socket to this IP address.
    1161             :  *
    1162             :  * When you create a TCP client, you can connect to a server. This
    1163             :  * is done by using the connect() function which makes use of the
    1164             :  * address to connect to the server.
    1165             :  *
    1166             :  * This function makes sure to select the correct connect() function
    1167             :  * depending on whether this IP address is an IPv4 or an IPv6 address
    1168             :  * (although we could always try with the IPv6 structure, it may or
    1169             :  * may not work properly on all systems, so for now we use the
    1170             :  * distinction.)
    1171             :  *
    1172             :  * \param[in] s  The socket to connect to the address.
    1173             :  *
    1174             :  * \return 0 if the bind() succeeded, -1 on errors
    1175             :  */
    1176           4 : int addr::connect(int s) const
    1177             : {
    1178             :     // only TCP can connect, UDP binds and sends only
    1179             :     //
    1180           4 :     switch(f_protocol)
    1181             :     {
    1182           2 :     case IPPROTO_IP: // interpret as TCP...
    1183             :     case IPPROTO_TCP:
    1184           2 :         if(is_ipv4())
    1185             :         {
    1186             :             // this would most certainly work using the IPv6 address
    1187             :             // as in the else part, but to be sure, we use the IPv4
    1188             :             // as specified in the address (there could be other reasons
    1189             :             // than just your OS for this to fail if using IPv6.)
    1190             :             //
    1191             :             // IMPORTANT NOTE: also the family is used in the socket()
    1192             :             //                 call above and must match the address here...
    1193             :             //
    1194           1 :             sockaddr_in ipv4;
    1195           1 :             get_ipv4(ipv4);
    1196           1 :             return ::connect(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
    1197             :         }
    1198             :         else
    1199             :         {
    1200           1 :             return ::connect(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(sockaddr_in6));
    1201             :         }
    1202             :         break;
    1203             : 
    1204             :     }
    1205             : 
    1206           2 :     return -1;
    1207             : }
    1208             : 
    1209             : 
    1210             : /** \brief Create a server with this socket listening on this IP address.
    1211             :  *
    1212             :  * This function will bind the socket \p s to the address defined in
    1213             :  * this addr object. This creates a server listening on that IP address.
    1214             :  *
    1215             :  * If the IP address is 127.0.0.1, then only local processes can connect
    1216             :  * to that server. If the IP address is 0.0.0.0, then anyone can connect
    1217             :  * to the server.
    1218             :  *
    1219             :  * This function works for TCP and UDP servers.
    1220             :  *
    1221             :  * If the IP address represents an IPv4 addressm then the bind() is done
    1222             :  * with an IPv4 address and not the IPv6 as it is stored.
    1223             :  *
    1224             :  * \param[in] s  The socket to bind to this address.
    1225             :  *
    1226             :  * \return 0 if the bind() succeeded, -1 on errors
    1227             :  */
    1228           2 : int addr::bind(int s) const
    1229             : {
    1230           2 :     if(is_ipv4())
    1231             :     {
    1232           1 :         sockaddr_in ipv4;
    1233           1 :         get_ipv4(ipv4);
    1234           1 :         return ::bind(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
    1235             :     }
    1236             :     else
    1237             :     {
    1238           1 :         return ::bind(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(sockaddr_in6));
    1239             :     }
    1240             : }
    1241             : 
    1242             : 
    1243             : /** \brief Set the corresponding host.
    1244             :  *
    1245             :  * When parsing an address, we transform the hostnames to IP addresses.
    1246             :  *
    1247             :  * When connecting to a web server via TLS, you need to enter the SNI,
    1248             :  * which is the server name. To make it available, we use this function
    1249             :  * to save the hostname as is.
    1250             :  *
    1251             :  * \param[in] hostname  The name of the host to connect to.
    1252             :  *
    1253             :  * \sa get_host()
    1254             :  */
    1255      131856 : void addr::set_hostname(std::string const & hostname)
    1256             : {
    1257      131856 :     f_hostname = hostname;
    1258      131856 : }
    1259             : 
    1260             : 
    1261             : /** \brief Initializes this addr object from a socket information.
    1262             :  *
    1263             :  * When you connect to a server or a clients connect to your server, the
    1264             :  * socket defines two IP addresses and ports: one on your side and one on
    1265             :  * the other side.
    1266             :  *
    1267             :  * The other side is called the _peer name_.
    1268             :  *
    1269             :  * You side is called the _socket name_ (i.e. the IP address of your computer,
    1270             :  * representing the interface used to perform that connection.)
    1271             :  *
    1272             :  * If you call this function with \p peer set to false then you get the
    1273             :  * address and port from your side. If you set \p peer to true,
    1274             :  * you get the other side address and port details.
    1275             :  *
    1276             :  * \todo
    1277             :  * Move this to our eventdispatcher once we create that separate library.
    1278             :  * Probably within a form of low level socket class.
    1279             :  *
    1280             :  * \param[in] s  The socket from which you want to retrieve peer information.
    1281             :  * \param[in] peer  Whether to retrieve the peer or socket name.
    1282             :  */
    1283          14 : void addr::set_from_socket(int s, bool peer)
    1284             : {
    1285             :     // make sure the socket is defined and well
    1286             :     //
    1287          14 :     if(s < 0)
    1288             :     {
    1289           2 :         throw addr_invalid_argument("addr::set_from_socket(): the socket cannot be a negative number.");
    1290             :     }
    1291             : 
    1292          12 :     sockaddr_storage address = sockaddr_storage();
    1293          12 :     socklen_t length(sizeof(address));
    1294             :     int r;
    1295          12 :     if(peer)
    1296             :     {
    1297             :         // this retrieves the information from the other side
    1298             :         //
    1299           6 :         r = getpeername(s, reinterpret_cast<sockaddr *>(&address), &length);
    1300             :     }
    1301             :     else
    1302             :     {
    1303             :         // retrieve the local socket information
    1304             :         //
    1305           6 :         r = getsockname(s, reinterpret_cast<sockaddr *>(&address), &length);
    1306             :     }
    1307          12 :     if(r != 0)
    1308             :     {
    1309           5 :         int const e(errno);
    1310             :         throw addr_io_error(
    1311          10 :                   std::string("addr::set_from_socket(): ")
    1312          15 :                 + (peer ? "getpeername()" : "getsockname()")
    1313          15 :                 + " failed to retrieve IP address details (errno: "
    1314          20 :                 + std::to_string(e)
    1315          15 :                 + ", "
    1316          15 :                 + strerror(e)
    1317          15 :                 + ").");
    1318             :     }
    1319             : 
    1320           7 :     switch(address.ss_family)
    1321             :     {
    1322           3 :     case AF_INET:
    1323           3 :         set_ipv4(reinterpret_cast<sockaddr_in &>(address));
    1324           3 :         break;
    1325             : 
    1326           3 :     case AF_INET6:
    1327           3 :         set_ipv6(reinterpret_cast<sockaddr_in6 &>(address));
    1328           3 :         break;
    1329             : 
    1330           1 :     default:
    1331             :         throw addr_invalid_state(
    1332           2 :                   std::string("addr::set_from_socket(): ")
    1333           3 :                 + (peer ? "getpeername()" : "getsockname()")
    1334           3 :                 + " returned a type of address, which is not understood, i.e. not AF_INET or AF_INET6.");
    1335             : 
    1336             :     }
    1337           6 : }
    1338             : 
    1339             : 
    1340             : /** \brief Transform the IP into a domain name.
    1341             :  *
    1342             :  * This function transforms the IP address in this `addr` object in a
    1343             :  * name such as "snap.website".
    1344             :  *
    1345             :  * \note
    1346             :  * The function does not cache the result because it is rarely used (at least
    1347             :  * at this time). So you should cache the result and avoid calling this
    1348             :  * function more than once as the process can be very slow.
    1349             :  *
    1350             :  * \todo
    1351             :  * Speed enhancement can be achieved by using getaddrinfo_a(). That would
    1352             :  * work with a vector of addr objects.
    1353             :  *
    1354             :  * \return The domain name. If not available, an empty string.
    1355             :  */
    1356           7 : std::string addr::get_name() const
    1357             : {
    1358           7 :     char host[NI_MAXHOST];
    1359             : 
    1360           7 :     int flags(NI_NAMEREQD);
    1361           7 :     if(f_protocol == IPPROTO_UDP)
    1362             :     {
    1363           4 :         flags |= NI_DGRAM;
    1364             :     }
    1365             : 
    1366             :     // TODO: test with the NI_IDN* flags and make sure we know what we get
    1367             :     //       (i.e. we want UTF-8 as a result)
    1368             :     //
    1369             :     int const r(getnameinfo(
    1370           7 :               reinterpret_cast<sockaddr const *>(&f_address)
    1371             :             , sizeof(f_address)
    1372             :             , host
    1373             :             , sizeof(host)
    1374             :             , nullptr
    1375             :             , 0
    1376           7 :             , flags));
    1377             : 
    1378             :     // if return value is 0, then it worked
    1379             :     //
    1380           7 :     return r == 0 ? host : std::string();
    1381             : }
    1382             : 
    1383             : 
    1384             : /** \brief Transform the port into a service name.
    1385             :  *
    1386             :  * This function transforms the port in this `addr` object in a
    1387             :  * name such as "http".
    1388             :  *
    1389             :  * \note
    1390             :  * The function does not cache the result because it is rarely used (at least
    1391             :  * at this time). So you should cache the result and avoid calling this
    1392             :  * function more than once as the process is somewhat slow.
    1393             :  *
    1394             :  * \warning
    1395             :  * The getnameinfo() will return a string with a number if it does not
    1396             :  * know the server (i.e. this is the equivalent to std::to_string() of
    1397             :  * the port.) For port 0, the function always returns an empty string.
    1398             :  *
    1399             :  * \return The service name. If not available, an empty string.
    1400             :  */
    1401           5 : std::string addr::get_service() const
    1402             : {
    1403           5 :     if(f_address.sin6_port == 0)
    1404             :     {
    1405           1 :         return std::string();
    1406             :     }
    1407             : 
    1408           4 :     char service[NI_MAXSERV];
    1409             : 
    1410           4 :     int flags(NI_NAMEREQD);
    1411           4 :     if(f_protocol == IPPROTO_UDP)
    1412             :     {
    1413           2 :         flags |= NI_DGRAM;
    1414             :     }
    1415             :     int const r(getnameinfo(
    1416           4 :               reinterpret_cast<sockaddr const *>(&f_address)
    1417             :             , sizeof(f_address)
    1418             :             , nullptr
    1419             :             , 0
    1420             :             , service
    1421             :             , sizeof(service)
    1422           4 :             , flags));
    1423             : 
    1424             :     // return value is 0, then it worked
    1425             :     //
    1426             :     return r == 0 ? service
    1427           4 :                   : std::string();
    1428             : }
    1429             : 
    1430             : 
    1431             : /** \brief Retrieve the port.
    1432             :  *
    1433             :  * This function retrieves the port of the IP address in host order.
    1434             :  *
    1435             :  * \return The port defined along this address.
    1436             :  */
    1437      197594 : int addr::get_port() const
    1438             : {
    1439      197594 :     return ntohs(f_address.sin6_port);
    1440             : }
    1441             : 
    1442             : 
    1443             : /** \brief Retrieve the protocol.
    1444             :  *
    1445             :  * This function retrieves the protocol as specified on the
    1446             :  * set_addr_port() function or corresponding constructor.
    1447             :  *
    1448             :  * You may change the protocol with the set_protocol() function.
    1449             :  *
    1450             :  * \return protocol such as IPPROTO_TCP or IPPROTO_UDP.
    1451             :  */
    1452      132074 : int addr::get_protocol() const
    1453             : {
    1454      132074 :     return f_protocol;
    1455             : }
    1456             : 
    1457             : 
    1458             : /** \brief Check whether an IP matches a CIDR.
    1459             :  *
    1460             :  * When an IP address is defined along a mask, it can match a set of
    1461             :  * other IP addresses. This function can be used to see whether
    1462             :  * \p ip matches \p this IP address and mask.
    1463             :  *
    1464             :  * So in other words, the mask of `this` addr object is used to mask
    1465             :  * both, `this` and `p` before comparing the masked result.
    1466             :  *
    1467             :  * \warning
    1468             :  * This function only checks the IP address. It totally ignores the
    1469             :  * port, family, protocol and other peripheral details.
    1470             :  *
    1471             :  * \param[in] ip  The address to match against this IP/mask CIDR.
    1472             :  * \param[in] any  If `this` addr object is an ANY address (see is_default())
    1473             :  * then always return true.
    1474             :  *
    1475             :  * \return true if \p ip is a match.
    1476             :  *
    1477             :  * \sa is_default()
    1478             :  */
    1479         214 : bool addr::match(addr const & ip, bool any) const
    1480             : {
    1481         214 :     if(any
    1482         214 :     && is_default())
    1483             :     {
    1484           0 :         return true;
    1485             :     }
    1486             : 
    1487        2186 :     for(int idx(0); idx < 16; ++idx)
    1488             :     {
    1489        2172 :         if((f_address.sin6_addr.s6_addr[idx] & f_mask[idx]) != (ip.f_address.sin6_addr.s6_addr[idx] & f_mask[idx]))
    1490             :         {
    1491         200 :             return false;
    1492             :         }
    1493             :     }
    1494             : 
    1495          14 :     return true;
    1496             : }
    1497             : 
    1498             : 
    1499             : /** \brief Determine whether addresses are adjacent.
    1500             :  *
    1501             :  * This function returns true if the specified address (\p a) is the very
    1502             :  * next address of `this` address.
    1503             :  *
    1504             :  * \note
    1505             :  * The addresses do not wrap around. So the default address (all 0's) is not
    1506             :  * just after the address with all f's.
    1507             :  *
    1508             :  * \param[in] a  The address to check against.
    1509             :  *
    1510             :  * \return true if this address + 1 equal \p a.
    1511             :  */
    1512           0 : bool addr::is_next(addr const & a) const
    1513             : {
    1514             :     using namespace snapdev::literals;
    1515             : 
    1516             : #pragma GCC diagnostic push
    1517             : #pragma GCC diagnostic ignored "-Wpedantic"
    1518           0 :     unsigned __int128 lhs(ip_to_uint128());
    1519           0 :     unsigned __int128 rhs(a.ip_to_uint128());
    1520             : #pragma GCC diagnostic pop
    1521           0 :     return lhs != 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_uint128 && lhs + 1 == rhs;
    1522             : }
    1523             : 
    1524             : 
    1525             : /** \brief Determine whether addresses are adjacent.
    1526             :  *
    1527             :  * This function returns true if the specified address (\p a) is the very
    1528             :  * previous address of `this` address.
    1529             :  *
    1530             :  * \note
    1531             :  * The addresses do not wrap around. So the address with all f's is not
    1532             :  * just before the default address.
    1533             :  *
    1534             :  * \param[in] a  The address to check against.
    1535             :  *
    1536             :  * \return true if this address - 1 equal \p a.
    1537             :  */
    1538           0 : bool addr::is_previous(addr const & a) const
    1539             : {
    1540             : #pragma GCC diagnostic push
    1541             : #pragma GCC diagnostic ignored "-Wpedantic"
    1542           0 :     unsigned __int128 lhs(ip_to_uint128());
    1543           0 :     unsigned __int128 rhs(a.ip_to_uint128());
    1544             : #pragma GCC diagnostic pop
    1545           0 :     return lhs != 0 && lhs - 1 == rhs;
    1546             : }
    1547             : 
    1548             : 
    1549             : /** \brief Check whether two addresses are equal.
    1550             :  *
    1551             :  * This function compares the left hand side (this) and the right
    1552             :  * hand side (rhs) for equality. If both represent the same IP
    1553             :  * address, then the function returns true.
    1554             :  *
    1555             :  * \warning
    1556             :  * The function only compares the address itself. The family, port,
    1557             :  * flow info, scope identifier, protocol are all ignored.
    1558             :  *
    1559             :  * \return true if \p this is equal to \p rhs.
    1560             :  */
    1561          35 : bool addr::operator == (addr const & rhs) const
    1562             : {
    1563          35 :     return f_address.sin6_addr == rhs.f_address.sin6_addr;
    1564             : }
    1565             : 
    1566             : 
    1567             : /** \brief Check whether two addresses are not equal.
    1568             :  *
    1569             :  * This function compares the left hand side (this) and the right
    1570             :  * hand side (rhs) for inequality. If both represent the same IP
    1571             :  * address, then the function returns false.
    1572             :  *
    1573             :  * \warning
    1574             :  * The function only compares the address itself. The family, port,
    1575             :  * flow info, scope identifier, protocol are all ignored.
    1576             :  *
    1577             :  * \return true if \p this is not equal to \p rhs.
    1578             :  */
    1579           9 : bool addr::operator != (addr const & rhs) const
    1580             : {
    1581           9 :     return f_address.sin6_addr != rhs.f_address.sin6_addr;
    1582             : }
    1583             : 
    1584             : 
    1585             : /** \brief Compare two addresses to know which one is smaller.
    1586             :  *
    1587             :  * This function compares the left hand side (this) and the right
    1588             :  * hand side (rhs) to know which one is the smallest. If both
    1589             :  * are equal or the left hand side is larger than the right hand
    1590             :  * side, then it returns false, otherwise it returns true.
    1591             :  *
    1592             :  * \warning
    1593             :  * The function only compares the address itself. The family, port,
    1594             :  * flow info, scope identifier, protocol are all ignored.
    1595             :  *
    1596             :  * \return true if \p this is smaller than \p rhs.
    1597             :  */
    1598           7 : bool addr::operator < (addr const & rhs) const
    1599             : {
    1600           7 :     return f_address.sin6_addr < rhs.f_address.sin6_addr;
    1601             : }
    1602             : 
    1603             : 
    1604             : /** \brief Compare two addresses to know which one is smaller or equal.
    1605             :  *
    1606             :  * This function compares the left hand side (this) and the right
    1607             :  * hand side (rhs) to know whether the left hand side is smaller or
    1608             :  * equal to thr right handside.
    1609             :  *
    1610             :  * \warning
    1611             :  * The function only compares the address itself. The family, port,
    1612             :  * flow info, scope identifier, protocol are all ignored.
    1613             :  *
    1614             :  * \return true if \p this is smaller than \p rhs.
    1615             :  */
    1616         685 : bool addr::operator <= (addr const & rhs) const
    1617             : {
    1618         685 :     return f_address.sin6_addr <= rhs.f_address.sin6_addr;
    1619             : }
    1620             : 
    1621             : 
    1622             : /** \brief Compare two addresses to know which one is smaller.
    1623             :  *
    1624             :  * This function compares the left hand side (this) and the right
    1625             :  * hand side (rhs) to know which one is the smallest. If both
    1626             :  * are equal or the left hand side is larger than the right hand
    1627             :  * side, then it returns false, otherwise it returns true.
    1628             :  *
    1629             :  * \warning
    1630             :  * The function only compares the address itself. The family, port,
    1631             :  * flow info, scope identifier, protocol are all ignored.
    1632             :  *
    1633             :  * \return true if \p this is smaller than \p rhs.
    1634             :  */
    1635          27 : bool addr::operator > (addr const & rhs) const
    1636             : {
    1637          27 :     return f_address.sin6_addr > rhs.f_address.sin6_addr;
    1638             : }
    1639             : 
    1640             : 
    1641             : /** \brief Compare two addresses to know which one is smaller.
    1642             :  *
    1643             :  * This function compares the left hand side (this) and the right
    1644             :  * hand side (rhs) to know which one is the smallest. If both
    1645             :  * are equal or the left hand side is larger than the right hand
    1646             :  * side, then it returns false, otherwise it returns true.
    1647             :  *
    1648             :  * \warning
    1649             :  * The function only compares the address itself. The family, port,
    1650             :  * flow info, scope identifier, protocol are all ignored.
    1651             :  *
    1652             :  * \return true if \p this is smaller than \p rhs.
    1653             :  */
    1654         290 : bool addr::operator >= (addr const & rhs) const
    1655             : {
    1656         290 :     return f_address.sin6_addr >= rhs.f_address.sin6_addr;
    1657             : }
    1658             : 
    1659             : 
    1660             : /** \brief Mark that the address changed.
    1661             :  *
    1662             :  * This functions makes sure that some of the parameters being cached
    1663             :  * get reset in such a way that checking the cache will again return
    1664             :  * the correct answer.
    1665             :  *
    1666             :  * \sa get_network_type()
    1667             :  */
    1668      132960 : void addr::address_changed()
    1669             : {
    1670      132960 :     f_private_network = network_type_t::NETWORK_TYPE_UNDEFINED;
    1671      132960 : }
    1672             : 
    1673             : 
    1674             : 
    1675             : 
    1676           6 : }
    1677             : // namespace addr
    1678             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13