LCOV - code coverage report
Current view: top level - libaddr - addr_parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 413 413 100.0 %
Date: 2021-07-21 12:51:15 Functions: 31 31 100.0 %
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 IP address parser.
      27             :  *
      28             :  * This function is used to parse IP addresses from a string to a
      29             :  * vector of ranges.
      30             :  */
      31             : 
      32             : // self
      33             : //
      34             : #include    "libaddr/addr_parser.h"
      35             : #include    "libaddr/addr_exception.h"
      36             : 
      37             : 
      38             : // C++ library
      39             : //
      40             : #include    <algorithm>
      41             : #include    <iostream>
      42             : 
      43             : 
      44             : // C library
      45             : //
      46             : #include    <ifaddrs.h>
      47             : #include    <netdb.h>
      48             : 
      49             : 
      50             : // last include
      51             : //
      52             : #include    <snapdev/poison.h>
      53             : 
      54             : 
      55             : 
      56             : namespace addr
      57             : {
      58             : 
      59             : 
      60             : namespace
      61             : {
      62             : 
      63             : 
      64             : /** \brief Delete an addrinfo structure.
      65             :  *
      66             :  * This deleter is used to make sure all the addinfo get released when
      67             :  * an exception occurs or the function using such exists.
      68             :  *
      69             :  * \param[in] ai  The addrinfo structure to free.
      70             :  */
      71      131992 : void addrinfo_deleter(struct addrinfo * ai)
      72             : {
      73      131992 :     freeaddrinfo(ai);
      74      131992 : }
      75             : 
      76             : 
      77             : }
      78             : 
      79             : 
      80             : 
      81             : 
      82             : 
      83             : /** \brief Set the default IP addresses.
      84             :  *
      85             :  * This function sets the default IP addresses to be used by the parser
      86             :  * when the input string of the parse() function does not include an IP
      87             :  * address.
      88             :  *
      89             :  * The \p address parameter cannot include a port. See
      90             :  * set_default_port() as a way to change the default port.
      91             :  *
      92             :  * The function expects either an IPv4 or an IPv6 address. It can be
      93             :  * called twice if you need to define both types of addresses (which
      94             :  * is often a good idea.)
      95             :  *
      96             :  * For example, the following input is considered valid when a default
      97             :  * address is defined:
      98             :  *
      99             :  * \code
     100             :  *      parser.parse(":123");
     101             :  * \endcode
     102             :  *
     103             :  * It returns the default address and port 123. Note that by default
     104             :  * an address is mandatory unless a default address is defined.
     105             :  *
     106             :  * To prevent the parser from working when no default and no address
     107             :  * are specified, then make sure to set the REQUIRED_ADDRESS allow
     108             :  * flag to true:
     109             :  *
     110             :  * \code
     111             :  *      parser.set_allow(parser.flag_t::REQUIRED_ADDRESS, true);
     112             :  *      // now address is mandatory
     113             :  * \endcode
     114             :  *
     115             :  * To completely prevent the use of an address in an input string, set
     116             :  * the `ADDRESS` and `REQUIRED_ADDRESS` values to false:
     117             :  *
     118             :  * \code
     119             :  *      parser.set_allow(parser.flag_t::ADDRESS,          false);
     120             :  *      parser.set_allow(parser.flag_t::REQUIRED_ADDRESS, false);
     121             :  * \endcode
     122             :  *
     123             :  * To remove both default IP addresses, call this function with an empty
     124             :  * string:
     125             :  *
     126             :  * \code
     127             :  *      parser.set_default_address(std::string());
     128             :  * \endcode
     129             :  *
     130             :  * \todo
     131             :  * Consider saving the default IPs as addr structures and allow such
     132             :  * as input.
     133             :  *
     134             :  * \param[in] addr  The new address.
     135             :  */
     136         227 : void addr_parser::set_default_address(std::string const & address)
     137             : {
     138         227 :     if(address.empty())
     139             :     {
     140           3 :         f_default_address4.clear();
     141           3 :         f_default_address6.clear();
     142             :     }
     143         224 :     else if(address[0] == '[')
     144             :     {
     145             :         // remove the '[' and ']'
     146             :         //
     147           5 :         if(address.back() != ']')
     148             :         {
     149           3 :             throw addr_invalid_argument("an IPv6 address starting with '[' must end with ']'.");
     150             :         }
     151           2 :         f_default_address6 = address.substr(1, address.length() - 2);
     152             :     }
     153         219 :     else if(address.find(':') != std::string::npos)
     154             :     {
     155         103 :         f_default_address6 = address;
     156             :     }
     157             :     else
     158             :     {
     159         116 :         f_default_address4 = address;
     160             :     }
     161         224 : }
     162             : 
     163             : 
     164             : /** \brief Retrieve the default IP address for IPv4 parsing.
     165             :  *
     166             :  * This function returns a copy of the default IP address used by
     167             :  * the parser when the input string does not include an IP address.
     168             :  *
     169             :  * If the function returns an empty string, then no default address
     170             :  * is defined.
     171             :  *
     172             :  * \return The default IPv4 address.
     173             :  *
     174             :  * \sa get_default_address6()
     175             :  * \sa set_default_address()
     176             :  */
     177         115 : std::string const & addr_parser::get_default_address4() const
     178             : {
     179         115 :     return f_default_address4;
     180             : }
     181             : 
     182             : 
     183             : /** \brief Retrieve the default IP address for IPv4 parsing.
     184             :  *
     185             :  * This function returns a copy of the default IP address used by
     186             :  * the parser when the input string does not include an IP address.
     187             :  *
     188             :  * If the function returns an empty string, then no default address
     189             :  * is defined.
     190             :  *
     191             :  * \return The default IPv6 address, without square brackets.
     192             :  *
     193             :  * \sa get_default_address4()
     194             :  * \sa set_default_address()
     195             :  */
     196         115 : std::string const & addr_parser::get_default_address6() const
     197             : {
     198         115 :     return f_default_address6;
     199             : }
     200             : 
     201             : 
     202             : /** \brief Define the default port.
     203             :  *
     204             :  * This function is used to define the default port to use in the address
     205             :  * parser object. By default this is set to -1 meaning: no default port.
     206             :  *
     207             :  * This function accepts any port number from 0 to 65535. It also accepts
     208             :  * -1 to reset the port back to "no default".
     209             :  *
     210             :  * To prevent the parser from working when no default and no port
     211             :  * are specified, then make sure to set the REQUIRED_PORT allow
     212             :  * flag to true:
     213             :  *
     214             :  * \code
     215             :  *      parser.set_allow(parser.flag_t::REQUIRED_PORT, true);
     216             :  *      // now port is mandatory
     217             :  * \endcode
     218             :  *
     219             :  * To completely prevent the use of a port in an input string, set
     220             :  * the `PORT` and `REQUIRED_PORT` values to false:
     221             :  *
     222             :  * \code
     223             :  *      parser.set_allow(parser.flag_t::PORT,          false);
     224             :  *      parser.set_allow(parser.flag_t::REQUIRED_PORT, false);
     225             :  * \endcode
     226             :  *
     227             :  * \exception addr_invalid_argument_exception
     228             :  * If the port number is out of range, then this expcetion is raised.
     229             :  * The allowed range for a port is 0 to 65535. This function also
     230             :  * accepts -1 meaning that no default port is specified.
     231             :  *
     232             :  * \param[in] port  The new default port.
     233             :  */
     234          84 : void addr_parser::set_default_port(int const port)
     235             : {
     236          84 :     if(port < -1
     237          74 :     || port > 65535)
     238             :     {
     239          25 :         throw addr_invalid_argument("addr_parser::set_default_port(): port must be in range [-1..65535].");
     240             :     }
     241             : 
     242          59 :     f_default_port = port;
     243          59 : }
     244             : 
     245             : 
     246             : /** \brief Retrieve the default port.
     247             :  *
     248             :  * This function retrieves the default port as defined by the
     249             :  * set_default_port() function.
     250             :  */
     251          76 : int addr_parser::get_default_port() const
     252             : {
     253          76 :     return f_default_port;
     254             : }
     255             : 
     256             : 
     257             : /** \brief Define the default mask.
     258             :  *
     259             :  * This function is used to define the default mask. Note that the
     260             :  * default mask will not be used at all if the flag_t::MASK allow
     261             :  * flag is not set to true:
     262             :  *
     263             :  * \code
     264             :  *      parser.set_allow(parser.flag_t::MASK, true);
     265             :  *      parser.set_default_mask("255.255.0.0");
     266             :  *      parser.set_default_mask("[ffff:ffff:ffff::]");
     267             :  * \endcode
     268             :  *
     269             :  * The IPv6 mask does not require the square brackets (`'['` and `']'`).
     270             :  *
     271             :  * To remove the default mask, call this function with an empty
     272             :  * string:
     273             :  *
     274             :  * \code
     275             :  *      parser.set_default_mask(std::string());
     276             :  * \endcode
     277             :  *
     278             :  * \note
     279             :  * As you can see, here we expect the mask to be a string. This is because
     280             :  * it gets parsed as if it came from the input string of the parser. This
     281             :  * also means that if the mask is invalid, it will not be detected until
     282             :  * you attempt to parse an input string that does not include a mask and
     283             :  * the default gets used.
     284             :  *
     285             :  * \todo
     286             :  * Add a check of the default mask when it gets set so we can throw on
     287             :  * errors and that way it is much more likely that programmers can fix
     288             :  * their errors early. (Actually by pre-parsing we could save it as
     289             :  * an addr and allow a `set_default_mask(addr ...)`!)
     290             :  *
     291             :  * \param[in] mask  The mask to use by default.
     292             :  */
     293         111 : void addr_parser::set_default_mask(std::string const & mask)
     294             : {
     295         111 :     if(mask.empty())
     296             :     {
     297           3 :         f_default_mask4.clear();
     298           3 :         f_default_mask6.clear();
     299             :     }
     300         108 :     else if(mask[0] == '[')
     301             :     {
     302             :         // remove the '[' and ']'
     303             :         //
     304          30 :         if(mask.back() != ']')
     305             :         {
     306           3 :             throw addr_invalid_argument("an IPv6 mask starting with '[' must end with ']'.");
     307             :         }
     308          27 :         f_default_mask6 = mask.substr(1, mask.length() - 2);
     309             :     }
     310          78 :     else if(mask.find(':') != std::string::npos)
     311             :     {
     312          25 :         f_default_mask6 = mask;
     313             :     }
     314             :     else
     315             :     {
     316          53 :         f_default_mask4 = mask;
     317             :     }
     318         108 : }
     319             : 
     320             : 
     321             : /** \brief Retrieve the default mask.
     322             :  *
     323             :  * This function returns a reference to the mask as set by the
     324             :  * set_default_mask() function. The value is an empty string by
     325             :  * default.
     326             :  *
     327             :  * The default mask will be used if no mask is specified in the
     328             :  * input string to the parse() function. When no default mask
     329             :  * is defined, the mask is set to all 1s.
     330             :  *
     331             :  * \note
     332             :  * The default mask is a string, not a binary mask. It gets
     333             :  * converted by the parser at the time it is required.
     334             :  *
     335             :  * \return The default mask.
     336             :  *
     337             :  * \sa get_default_mask6()
     338             :  * \sa set_default_mask()
     339             :  */
     340          12 : std::string const & addr_parser::get_default_mask4() const
     341             : {
     342          12 :     return f_default_mask4;
     343             : }
     344             : 
     345             : 
     346             : /** \brief Retrieve the default mask.
     347             :  *
     348             :  * This function returns a reference to the mask as set by the
     349             :  * set_default_mask() function. The value is an empty string by
     350             :  * default.
     351             :  *
     352             :  * The default mask will be used if no mask is specified in the
     353             :  * input string to the parse() function. When no default mask
     354             :  * is defined, the mask is set to all 1s.
     355             :  *
     356             :  * \note
     357             :  * The default mask is a string, not a binary mask. It gets
     358             :  * converted by the parser at the time it is required.
     359             :  *
     360             :  * \return The default mask.
     361             :  *
     362             :  * \sa get_default_mask4()
     363             :  * \sa set_default_mask()
     364             :  */
     365          12 : std::string const & addr_parser::get_default_mask6() const
     366             : {
     367          12 :     return f_default_mask6;
     368             : }
     369             : 
     370             : 
     371             : /** \brief Set the protocol to use to filter addresses.
     372             :  *
     373             :  * This function sets the protocol as one of the following:
     374             :  *
     375             :  * \li "ip" -- only return IP address supporting the IP protocol
     376             :  * (this is offered because getaddrinfo() may return such IP addresses.)
     377             :  * \li "tcp" -- only return IP address supporting TCP
     378             :  * \li "udp" -- only return IP address supporting UDP
     379             :  *
     380             :  * Any other value is refused. To reset the protocol to the default,
     381             :  * which is "do not filter by protocol", call the clear_protocol().
     382             :  *
     383             :  * \exception addr_invalid_argument_exception
     384             :  * If the string passed to this function is not one of the acceptable
     385             :  * protocols (ip, tcp, udp), then this exception is raised.
     386             :  *
     387             :  * \param[in] protocol  The default protocol for this parser.
     388             :  *
     389             :  * \sa clear_protocol()
     390             :  * \sa get_protocol()
     391             :  */
     392         118 : void addr_parser::set_protocol(std::string const & protocol)
     393             : {
     394         118 :     if(protocol == "ip")
     395             :     {
     396           2 :         f_protocol = IPPROTO_IP;
     397             :     }
     398         116 :     else if(protocol == "tcp")
     399             :     {
     400         107 :         f_protocol = IPPROTO_TCP;
     401             :     }
     402           9 :     else if(protocol == "udp")
     403             :     {
     404           6 :         f_protocol = IPPROTO_UDP;
     405             :     }
     406             :     else
     407             :     {
     408             :         // not a protocol we support
     409             :         //
     410             :         throw addr_invalid_argument(
     411           6 :                   std::string("unknown protocol \"")
     412           6 :                 + protocol
     413           9 :                 + "\", expected \"tcp\" or \"udp\".");
     414             :     }
     415         115 : }
     416             : 
     417             : 
     418             : /** \brief Set the protocol to use to filter addresses.
     419             :  *
     420             :  * This function sets the protocol as one of the following:
     421             :  *
     422             :  * \li IPPROTO_IP -- only return IP address supporting the IP protocol
     423             :  * (this is offered because getaddrinfo() may return such IP addresses.)
     424             :  * \li IPPROTO_TCP -- only return IP address supporting TCP
     425             :  * \li IPPROTO_UDP -- only return IP address supporting UDP
     426             :  *
     427             :  * Any other value is refused. To reset the protocol to the default,
     428             :  * which is "do not filter by protocol", call the clear_protocol().
     429             :  *
     430             :  * \exception addr_invalid_argument_exception
     431             :  * If the string passed to this function is not one of the acceptable
     432             :  * protocols (ip, tcp, udp), then this exception is raised.
     433             :  *
     434             :  * \param[in] protocol  The default protocol for this parser.
     435             :  *
     436             :  * \sa clear_protocol()
     437             :  * \sa get_protocol()
     438             :  */
     439      132016 : void addr_parser::set_protocol(int const protocol)
     440             : {
     441             :     // make sure that's a protocol we support
     442             :     //
     443      132016 :     switch(protocol)
     444             :     {
     445      131816 :     case IPPROTO_IP:
     446             :     case IPPROTO_TCP:
     447             :     case IPPROTO_UDP:
     448      131816 :         break;
     449             : 
     450         200 :     default:
     451             :         throw addr_invalid_argument(
     452         400 :                   std::string("unknown protocol \"")
     453         800 :                 + std::to_string(protocol)
     454         600 :                 + "\", expected \"tcp\" or \"udp\".");
     455             : 
     456             :     }
     457             : 
     458      131816 :     f_protocol = protocol;
     459      131816 : }
     460             : 
     461             : 
     462             : /** \brief Use this function to reset the protocol back to "no default."
     463             :  *
     464             :  * This function sets the protocol to -1 (which is something you cannot
     465             :  * do by calling the set_protocol() functions above.)
     466             :  *
     467             :  * The -1 special value means that the protocol is not defined, that
     468             :  * there is no default. In most cases this means all the addresses
     469             :  * that match, ignoring the protocol, will be returned by the parse()
     470             :  * function.
     471             :  *
     472             :  * \sa set_protocol()
     473             :  * \sa get_protocol()
     474             :  */
     475           3 : void addr_parser::clear_protocol()
     476             : {
     477           3 :     f_protocol = -1;
     478           3 : }
     479             : 
     480             : 
     481             : /** \brief Retrieve the protocol as defined by the set_protocol().
     482             :  *
     483             :  * This function returns the protocol number as defined by the
     484             :  * set_protocol.
     485             :  *
     486             :  * When defined, the protocol is used whenever we call the
     487             :  * getaddrinfo() function. In general, this means the IP addresses
     488             :  * returned will have  to match that protocol.
     489             :  *
     490             :  * This function may return -1. The value -1 is used as "do not
     491             :  * filter by protocol". The protocol can be set to -1 by calling
     492             :  * the clear_protocol() function.
     493             :  *
     494             :  * \return The parser default protocol.
     495             :  *
     496             :  * \sa set_protocol()
     497             :  * \sa clear_protocol()
     498             :  */
     499         216 : int addr_parser::get_protocol() const
     500             : {
     501         216 :     return f_protocol;
     502             : }
     503             : 
     504             : 
     505             : /** \brief Set or clear allow flags in the parser.
     506             :  *
     507             :  * This parser has a set of flags it uses to know whether the input
     508             :  * string can include certain things such as a port or a mask.
     509             :  *
     510             :  * This function is used to allow or require certain parameters and
     511             :  * to disallow others.
     512             :  *
     513             :  * By default, the ADDRESS and PORT flags are set, meaning that an
     514             :  * address and a port can appear, but either or both are optinal.
     515             :  * If unspecified, then the default will be used. If not default
     516             :  * is defined, then the parser may fail in this situation.
     517             :  *
     518             :  * One problem is that we include contradictory syntatical features.
     519             :  * The parser supports lists of addresses separated by commas and
     520             :  * lists of ports separated by commas. Both are not supported
     521             :  * simultaneously. This means you want to allow multiple addresses
     522             :  * separated by commas, the function makes sure that the multiple
     523             :  * port separated by commas support is turned off.
     524             :  *
     525             :  * \li ADDRESS -- the IP address is allowed, but optional
     526             :  * \li REQUIRED_ADDRESS -- the IP address is mandatory
     527             :  * \li PORT -- the port is allowed, but optional
     528             :  * \li REQUIRED_PORT -- the port is mandatory
     529             :  * \li MASK -- the mask is allowed, but optional
     530             :  * \li MULTI_ADDRESSES_COMMAS -- the input can have multiple addresses
     531             :  * separated by commas, spaces are not allowed (prevents MULTI_PORTS_COMMAS)
     532             :  * \li MULTI_ADDRESSES_SPACES -- the input can have multiple addresses
     533             :  * separated by spaces
     534             :  * \li MULTI_ADDRESSES_COMMAS_AND_SPACES -- the input can have multiple
     535             :  * addresses separated by spaces and commas (prevents MULTI_PORTS_COMMAS)
     536             :  * \li MULTI_PORTS_SEMICOLONS -- the input can  have multiple ports
     537             :  * separated by semicolons _NOT IMPLEMENTED YET_
     538             :  * \li MULTI_PORTS_COMMAS -- the input can have multiple ports separated
     539             :  * by commas (prevents MULTI_ADDRESSES_COMMAS and
     540             :  * MULTI_ADDRESSES_COMMAS_AND_SPACES) _NOT IMPLEMENTED YET_
     541             :  * \li PORT_RANGE -- the input supports port ranges (p1-p2) _NOT
     542             :  * IMPLEMENTED YET_
     543             :  * \li ADDRESS_RANGE -- the input supports address ranges (addr-addr) _NOT
     544             :  * IMPLEMENTED YET_
     545             :  *
     546             :  * \param[in] flag  The flag to set or clear.
     547             :  * \param[in] allow  Whether to allow (true) or disallow (false).
     548             :  *
     549             :  * \sa get_allow()
     550             :  */
     551         547 : void addr_parser::set_allow(flag_t const flag, bool const allow)
     552             : {
     553         547 :     if(flag < static_cast<flag_t>(0)
     554         527 :     || flag >= flag_t::FLAG_max)
     555             :     {
     556          40 :         throw addr_invalid_argument("addr_parser::set_allow(): flag has to be one of the valid flags.");
     557             :     }
     558             : 
     559         507 :     f_flags[static_cast<int>(flag)] = allow;
     560             : 
     561             :     // if we just set a certain flag, others may need to go to false
     562             :     //
     563         507 :     if(allow)
     564             :     {
     565             :         // we can only support one type of commas
     566             :         //
     567         488 :         switch(flag)
     568             :         {
     569           7 :         case flag_t::MULTI_ADDRESSES_COMMAS:
     570             :         case flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES:
     571           7 :             f_flags[static_cast<int>(flag_t::MULTI_PORTS_COMMAS)] = false;
     572           7 :             break;
     573             : 
     574           2 :         case flag_t::MULTI_PORTS_COMMAS:
     575           2 :             f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)] = false;
     576           2 :             f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES)] = false;
     577           2 :             break;
     578             : 
     579         479 :         default:
     580         479 :             break;
     581             : 
     582             :         }
     583             :     }
     584         507 : }
     585             : 
     586             : 
     587             : /** \brief Retrieve the current statius of an allow flag.
     588             :  *
     589             :  * This function returns the current status of the allow flags.
     590             :  *
     591             :  * By default, the `ADDRESS` and `PORT` flags are set to true.
     592             :  * All the other flags are set to false.
     593             :  *
     594             :  * You may change the value of an allow flag by calling the
     595             :  * set_allow() function.
     596             :  *
     597             :  * \param[in] flag  Which flag is to be checked.
     598             :  *
     599             :  * \return The value of the flag: true or false.
     600             :  *
     601             :  * \sa set_allow()
     602             :  */
     603          57 : bool addr_parser::get_allow(flag_t const flag) const
     604             : {
     605          57 :     if(flag < static_cast<flag_t>(0)
     606          47 :     || flag >= flag_t::FLAG_max)
     607             :     {
     608          20 :         throw addr_invalid_argument("addr_parser::get_allow(): flag has to be one of the valid flags.");
     609             :     }
     610             : 
     611          37 :     return f_flags[static_cast<int>(flag)];
     612             : }
     613             : 
     614             : 
     615             : /** \brief Check whether errors were registered so far.
     616             :  *
     617             :  * This function returns true if the system detected errors in one
     618             :  * of the previous calls to parse(). The flag can be cleared using
     619             :  * the clear_errors() function.
     620             :  *
     621             :  * On construction and after a call to clear_error(), this flag is
     622             :  * always false. If you are to call parser() multiple times with
     623             :  * the same addr_parser object, then you want to make sure to call
     624             :  * the clear_errors() function before calling the parse() function.
     625             :  * Otherwise you won't know whether errors occurred in a earlier
     626             :  * or later call.
     627             :  *
     628             :  * \code
     629             :  *      // first time, not required
     630             :  *      parser.parse(...);
     631             :  *      ...
     632             :  *
     633             :  *      // next time, required
     634             :  *      parser.clear_errors();
     635             :  *      parser.parse(...);
     636             :  *      ...
     637             :  * \endcode
     638             :  *
     639             :  * \return true if errors were generated.
     640             :  */
     641      131827 : bool addr_parser::has_errors() const
     642             : {
     643      131827 :     return !f_error.empty();
     644             : }
     645             : 
     646             : 
     647             : /** \brief Emit an error and save it in this class.
     648             :  *
     649             :  * This function adds the message to the error string part of this
     650             :  * object. A newline is also added at the end of the message.
     651             :  *
     652             :  * Next the function increments the error counter.
     653             :  *
     654             :  * \note
     655             :  * You are expected to emit one error at a time. If you want to
     656             :  * emit several messages in a row, that will work and properly
     657             :  * count each message.
     658             :  *
     659             :  * \param[in] msg  The message to add to the parser error messages.
     660             :  *
     661             :  * \sa error_messages()
     662             :  */
     663          62 : void addr_parser::emit_error(std::string const & msg)
     664             : {
     665          62 :     f_error += msg;
     666          62 :     f_error += "\n";
     667          62 :     ++f_error_count;
     668          62 : }
     669             : 
     670             : 
     671             : /** \brief Return the current error messages.
     672             :  *
     673             :  * The error messages are added to the addr_parser using the
     674             :  * emit_error() function.
     675             :  *
     676             :  * This function does not clear the list of error messages.
     677             :  * To do that, call the clear_errors() function.
     678             :  *
     679             :  * The number of messages can be determined by counting the
     680             :  * number of "\n" characters in the string. The error_count()
     681             :  * will return that same number (assuming no message included
     682             :  * a '\n' character when emit_error() was called.)
     683             :  *
     684             :  * \return A string with the list of messages.
     685             :  *
     686             :  * \sa emit_error()
     687             :  * \sa clear_errors()
     688             :  */
     689          62 : std::string const & addr_parser::error_messages() const
     690             : {
     691          62 :     return f_error;
     692             : }
     693             : 
     694             : 
     695             : /** \brief Return the number of error messages that were emitted.
     696             :  *
     697             :  * Each time the emit_error() function is called, the error
     698             :  * counter is incremented by 1. This function returns that
     699             :  * error counter.
     700             :  *
     701             :  * The clear_errors() function can be used to clear the
     702             :  * counter back to zero.
     703             :  *
     704             :  * \return The number of errors that were emitted so far.
     705             :  *
     706             :  * \sa emit_error()
     707             :  */
     708          62 : int addr_parser::error_count() const
     709             : {
     710          62 :     return f_error_count;
     711             : }
     712             : 
     713             : 
     714             : /** \brief Clear the error message and error counter.
     715             :  *
     716             :  * This function clears all the error messages and reset the
     717             :  * counter back to zero. In order words, it will be possible
     718             :  * to tell how many times the emit_error() was called since
     719             :  * the start or the last clear_errors() call.
     720             :  *
     721             :  * To retrieve a copy of the error counter, use the error_count()
     722             :  * function.
     723             :  *
     724             :  * \sa error_count()
     725             :  */
     726           5 : void addr_parser::clear_errors()
     727             : {
     728           5 :     f_error.clear();
     729           5 :     f_error_count = 0;
     730           5 : }
     731             : 
     732             : 
     733             : /** \brief Parse a string of addresses, ports, and masks.
     734             :  *
     735             :  * This function is used to parse the list of addresses defined
     736             :  * in the \p in parameter.
     737             :  *
     738             :  * One address is composed of one to three elements:
     739             :  *
     740             :  * \code
     741             :  *          [ address ] [ ':' port ] [ '/' mask ]
     742             :  * \endcode
     743             :  *
     744             :  * Although all three elements are optional (at least by default),
     745             :  * a valid address is expected to include at least one of the
     746             :  * three elements. (i.e. an empty string is just skipped silently.)
     747             :  *
     748             :  * ### Multiple Addresses
     749             :  *
     750             :  * Multiple addresses can be defined if at least one of the
     751             :  * `MULTI_ADDRESSES_COMMAS`, `MULTI_ADDRESSES_SPACES`, or
     752             :  * `MULTI_ADDRESSES_COMMAS_AND_SPACES` allow flags is set to true.
     753             :  *
     754             :  * Note that the `MULTI_ADDRESSES_COMMAS_AND_SPACES` has priotity. If
     755             :  * set to true, then both, commas and spaces are allowed between
     756             :  * addresses.
     757             :  *
     758             :  * Next comes `MULTI_ADDRESSES_COMMAS`: if set to true, addresses
     759             :  * must be separated by commas and spaces are not allowed.
     760             :  *
     761             :  * Finally we have `MULTI_ADDRESSES_SPACES`. If that one is true, then
     762             :  * addresses must be separated by spaces and commas are not allowed.
     763             :  *
     764             :  * ### Make Address Field Required
     765             :  *
     766             :  * To make the address field a required field, set the
     767             :  * `REQUIRED_ADDRESS` flag (see set_allow()) to true and do not define a
     768             :  * default address (see set_default_address()).
     769             :  *
     770             :  * ### Make Port Field Required
     771             :  *
     772             :  * To make the port field a required fiel, set the `REQUIRED_PORT`
     773             :  * flag (see set_allow()) to true and do not define a default port
     774             :  * (see set_default_port()).
     775             :  *
     776             :  * ### Allow Mask
     777             :  *
     778             :  * The mask cannot be made mandatory. However, you have to set
     779             :  * the `MASK` flag to true to allow it. By default it is not
     780             :  * allowed.
     781             :  *
     782             :  * ### Ranges
     783             :  *
     784             :  * At this time we do not need support for ranges so it did not yet
     785             :  * get implemented.
     786             :  *
     787             :  * \param[in] in  The input string to be parsed.
     788             :  */
     789      131836 : addr_range::vector_t addr_parser::parse(std::string const & in)
     790             : {
     791      131836 :     addr_range::vector_t result;
     792             : 
     793      131836 :     if(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES)])
     794             :     {
     795           2 :         std::string comma_space(", ");
     796           1 :         std::string::size_type s(0);
     797          17 :         while(s < in.length())
     798             :         {
     799             :             // since C++11 we have a way to search for a set of character
     800             :             // in a string with an algorithm!
     801             :             //
     802           8 :             auto const it(std::find_first_of(in.begin() + s, in.end(), comma_space.begin(), comma_space.end()));
     803           8 :             std::string::size_type const e(it == in.end() ? in.length() : it - in.begin());
     804           8 :             if(e > s)
     805             :             {
     806           3 :                 parse_cidr(in.substr(s, e - s), result);
     807             :             }
     808           8 :             s = e + 1;
     809             :         }
     810             :     }
     811      131835 :     else if(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)]
     812      131834 :          || f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_SPACES)])
     813             :     {
     814           2 :         char sep(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)] ? ',' : ' ');
     815           2 :         std::string::size_type s(0);
     816          24 :         while(s < in.length())
     817             :         {
     818          11 :             std::string::size_type e(in.find(sep, s));
     819          11 :             if(e == std::string::npos)
     820             :             {
     821           2 :                 e = in.length();
     822             :             }
     823          11 :             if(e > s)
     824             :             {
     825           6 :                 parse_cidr(in.substr(s, e - s), result);
     826             :             }
     827          11 :             s = e + 1;
     828           2 :         }
     829             :     }
     830             :     else
     831             :     {
     832      131833 :         parse_cidr(in, result);
     833             :     }
     834             : 
     835      131836 :     return result;
     836             : }
     837             : 
     838             : 
     839             : /** \brief Check one address.
     840             :  *
     841             :  * This function checks one address, although if it is a name, it could
     842             :  * represent multiple IP addresses.
     843             :  *
     844             :  * This function separate the address:port from the mask if the mask is
     845             :  * allowed. Then it parses the address:port part and the mask separately.
     846             :  *
     847             :  * \param[in] in  The address to parse.
     848             :  * \param[in,out] result  The list of resulting addresses.
     849             :  */
     850      131842 : void addr_parser::parse_cidr(std::string const & in, addr_range::vector_t & result)
     851             : {
     852      131842 :     if(f_flags[static_cast<int>(flag_t::MASK)])
     853             :     {
     854             :         // check whether there is a mask
     855             :         //
     856         948 :         std::string mask;
     857             : 
     858         948 :         std::string address;
     859         474 :         std::string::size_type const p(in.find('/'));
     860         474 :         if(p != std::string::npos)
     861             :         {
     862         420 :             address = in.substr(0, p);
     863         420 :             mask = in.substr(p + 1);
     864             :         }
     865             :         else
     866             :         {
     867          54 :             address = in;
     868             :         }
     869             : 
     870         474 :         int const errcnt(f_error_count);
     871             : 
     872             :         // handle the address first
     873             :         //
     874         948 :         addr_range::vector_t addr_mask;
     875         474 :         parse_address(address, mask, addr_mask);
     876             : 
     877             :         // now check for the mask
     878             :         //
     879         948 :         for(auto & am : addr_mask)
     880             :         {
     881         948 :             std::string m(mask);
     882         474 :             if(m.empty())
     883             :             {
     884             :                 // the mask was not defined in the input, then adapt it to
     885             :                 // the type of address we got in 'am'
     886             :                 //
     887          56 :                 if(am.get_from().is_ipv4())
     888             :                 {
     889          29 :                     m = f_default_mask4;
     890             :                 }
     891             :                 else
     892             :                 {
     893             :                     // parse_mask() expects '[...]' around IPv6 addresses
     894             :                     //
     895          27 :                     m = "[" + f_default_mask6 + "]";
     896             :                 }
     897             :             }
     898             : 
     899         474 :             parse_mask(m, am.get_from());
     900             :         }
     901             : 
     902             :         // now append the list to the result if no errors occurred
     903             :         //
     904         474 :         if(errcnt == f_error_count)
     905             :         {
     906         424 :             result.insert(result.end(), addr_mask.begin(), addr_mask.end());
     907             :         }
     908             :     }
     909             :     else
     910             :     {
     911             :         // no mask allowed, if there is one, this call will fail
     912             :         //
     913      131368 :         parse_address(in, std::string(), result);
     914             :     }
     915      131842 : }
     916             : 
     917             : 
     918             : /** \brief Parse one address.
     919             :  *
     920             :  * This function is called with one address. It determines whether we
     921             :  * are dealing with an IPv4 or an IPv6 address and call the
     922             :  * corresponding sub-function.
     923             :  *
     924             :  * An address is considered an IPv6 address if it starts with a '['
     925             :  * character.
     926             :  *
     927             :  * \note
     928             :  * The input cannot include a mask. It has to already have been
     929             :  * removed.
     930             :  *
     931             :  * \note
     932             :  * The mask parameter is only used to determine whether this function
     933             :  * is being called with an IPv6 or not. It is otherwise ignored.
     934             :  *
     935             :  * \param[in] in  The input address eventually including a port.
     936             :  * \param[in] mask  The mask used to determine whether we are dealing with
     937             :  *                  an IPv6 or not.
     938             :  * \param[in,out] result  The list of resulting addresses.
     939             :  */
     940      131842 : void addr_parser::parse_address(std::string const & in, std::string const & mask, addr_range::vector_t & result)
     941             : {
     942             :     // With our only supported format, ipv6 addresses must be between square
     943             :     // brackets. The address may just be a mask in which case the '[' may
     944             :     // not be at the very start (i.e. "/[ffff:ffff::]")
     945             :     //
     946      263684 :     if(in.empty()
     947      131842 :     || in[0] == ':')    // if it start with ':' then there is no address
     948             :     {
     949             :         // if the address is empty, then use the mask to determine the
     950             :         // type of IP address (note: if the address starts with ':'
     951             :         // it is considered empty since an IPv6 would have a '[' at
     952             :         // the start)
     953             :         //
     954         318 :         if(!mask.empty())
     955             :         {
     956         111 :             if(mask[0] == '[')
     957             :             {
     958             :                 // IPv6 parsing
     959             :                 //
     960           5 :                 parse_address6(in, result);
     961             :             }
     962             :             else
     963             :             {
     964             :                 // if the number is 33 or more, it has to be IPv6, otherwise
     965             :                 // we cannot know...
     966             :                 //
     967         106 :                 int mask_count(0);
     968         354 :                 for(char const * s(mask.c_str()); *s != '\0'; ++s)
     969             :                 {
     970         258 :                     if(*s >= '0' && *s <= '9')
     971             :                     {
     972         253 :                         mask_count = mask_count * 10 + *s - '0';
     973         501 :                         if(mask_count > 1000)
     974             :                         {
     975             :                             // not valid
     976             :                             //
     977           5 :                             mask_count = -1;
     978           5 :                             break;;
     979             :                         }
     980             :                     }
     981             :                     else
     982             :                     {
     983             :                         // not a valid decimal number
     984             :                         //
     985           5 :                         mask_count = -1;
     986           5 :                         break;
     987             :                     }
     988             :                 }
     989         106 :                 if(mask_count > 32)
     990             :                 {
     991          96 :                     parse_address6(in, result);
     992             :                 }
     993             :                 else
     994             :                 {
     995          10 :                     parse_address4(in, result);
     996             :                 }
     997             :             }
     998             :         }
     999             :         else
    1000             :         {
    1001         414 :             if(f_default_address4.empty()
    1002         207 :             && !f_default_address6.empty())
    1003             :             {
    1004         102 :                 parse_address6(in, result);
    1005             :             }
    1006             :             else
    1007             :             {
    1008         105 :                 parse_address4(in, result);
    1009             :             }
    1010             :         }
    1011             :     }
    1012             :     else
    1013             :     {
    1014             :         // if an address has a ']' then it is IPv6 even if the '['
    1015             :         // is missing, that being said, it is still considered
    1016             :         // invalid as per our processes
    1017             :         //
    1018      263048 :         if(in[0] == '['
    1019      131524 :         || in.find(']') != std::string::npos)
    1020             :         {
    1021       65777 :             parse_address6(in, result);
    1022             :         }
    1023             :         else
    1024             :         {
    1025             :             // if there is no port, then a ':' can be viewed as an IPv6
    1026             :             // address because there is no other ':', but if there are
    1027             :             // '.' before the ':' then we assume that it is IPv4 still
    1028             :             //
    1029       65747 :             if(!f_flags[static_cast<int>(flag_t::PORT)]
    1030           4 :             && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1031             :             {
    1032           3 :                 std::string::size_type const p(in.find(':'));
    1033           3 :                 if(p != std::string::npos
    1034           3 :                 && in.find('.') > p)
    1035             :                 {
    1036           1 :                     parse_address6(in, result);
    1037             :                 }
    1038             :                 else
    1039             :                 {
    1040           2 :                     parse_address4(in, result);
    1041           3 :                 }
    1042             :             }
    1043             :             else
    1044             :             {
    1045       65744 :                 parse_address4(in, result);
    1046             :             }
    1047             :         }
    1048             :     }
    1049      131842 : }
    1050             : 
    1051             : 
    1052             : /** \brief Parse one IPv4 address.
    1053             :  *
    1054             :  * This function checks the input parameter \p in and extracts the
    1055             :  * address and port. There is a port if the input strings includes
    1056             :  * a `':'` character.
    1057             :  *
    1058             :  * If this function detects that a port is not allowed and yet
    1059             :  * a `':'` character is found, then it generates an error and
    1060             :  * returns without adding anything to `result`.
    1061             :  *
    1062             :  * \param[in] in  The input string with the address and optional port.
    1063             :  * \param[in,out] result  The list of resulting addresses.
    1064             :  */
    1065       65861 : void addr_parser::parse_address4(std::string const & in, addr_range::vector_t & result)
    1066             : {
    1067      131721 :     std::string address;
    1068      131721 :     std::string port_str;
    1069             : 
    1070       65861 :     std::string::size_type const p(in.find(':'));
    1071             : 
    1072       65861 :     if(f_flags[static_cast<int>(flag_t::PORT)]
    1073           4 :     || f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1074             :     {
    1075             :         // the address can include a port
    1076             :         //
    1077      131716 :         if(p != std::string::npos)
    1078             :         {
    1079             :             // get the address only if not empty (otherwise we want to
    1080             :             // keep the default)
    1081             :             //
    1082       65816 :             if(p > 0)
    1083             :             {
    1084       65706 :                 address = in.substr(0, p);
    1085             :             }
    1086             : 
    1087             :             // get the port only if not empty (otherwise we want to
    1088             :             // keep the default)
    1089             :             //
    1090       65816 :             if(p + 1 < in.length())
    1091             :             {
    1092       65791 :                 port_str = in.substr(p + 1);
    1093             :             }
    1094             :         }
    1095          42 :         else if(!in.empty())
    1096             :         {
    1097          38 :             address = in;
    1098             :         }
    1099             :     }
    1100             :     else
    1101             :     {
    1102           3 :         if(p != std::string::npos
    1103           1 :         && !f_flags[static_cast<int>(flag_t::PORT)]
    1104           1 :         && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1105             :         {
    1106           1 :             emit_error("Port not allowed (" + in + ").");
    1107           1 :             return;
    1108             :         }
    1109             : 
    1110           2 :         if(!in.empty())
    1111             :         {
    1112           1 :             address = in;
    1113             :         }
    1114             :     }
    1115             : 
    1116       65860 :     parse_address_port(address, port_str, result, false);
    1117             : }
    1118             : 
    1119             : 
    1120             : /** \brief Parse one IPv6 address.
    1121             :  *
    1122             :  * This function checks the input parameter \p in and extracts the
    1123             :  * address and port. There is a port if the input strings includes
    1124             :  * a `':'` character after the closing square bracket (`']'`).
    1125             :  *
    1126             :  * If this function detects that a port is not allowed and yet
    1127             :  * a `':'` character is found, then it generates an error and
    1128             :  * returns without adding anything to `result`.
    1129             :  *
    1130             :  * \note
    1131             :  * This function can be called with an IPv6
    1132             :  *
    1133             :  * \param[in] in  The input string with the address and optional port.
    1134             :  * \param[in,out] result  The list of resulting addresses.
    1135             :  */
    1136       65981 : void addr_parser::parse_address6(std::string const & in, addr_range::vector_t & result)
    1137             : {
    1138       65981 :     std::string::size_type p(0);
    1139             : 
    1140      131959 :     std::string address;
    1141      131959 :     std::string port_str;
    1142             : 
    1143             :     // if there is an address extract it otherwise put the default
    1144             :     //
    1145      131962 :     if(!in.empty()
    1146       65981 :     && in[0] == '[')
    1147             :     {
    1148       65777 :         p = in.find(']');
    1149             : 
    1150       65777 :         if(p == std::string::npos)
    1151             :         {
    1152           1 :             emit_error("IPv6 is missing the ']' (" + in + ").");
    1153           1 :             return;
    1154             :         }
    1155             : 
    1156       65776 :         if(p != 1)
    1157             :         {
    1158             :             // get the address only if not empty (otherwise we want to
    1159             :             // keep the default) -- so we actually support "[]" to
    1160             :             // represent "use the default address if defined".
    1161             :             //
    1162       65775 :             address = in.substr(1, p - 1);
    1163             :         }
    1164             :     }
    1165             : 
    1166             :     // on entry 'p' is either 0 or the position of the ']' character
    1167             :     //
    1168       65980 :     p = in.find(':', p);
    1169             : 
    1170       65980 :     if(p != std::string::npos)
    1171             :     {
    1172       65972 :         if(f_flags[static_cast<int>(flag_t::PORT)]
    1173           2 :         || f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1174             :         {
    1175             :             // there is also a port, extract it
    1176             :             //
    1177       65970 :             port_str = in.substr(p + 1);
    1178             :         }
    1179           2 :         else if(!f_flags[static_cast<int>(flag_t::PORT)]
    1180           2 :              && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1181             :         {
    1182           2 :             emit_error("Port not allowed (" + in + ").");
    1183           2 :             return;
    1184             :         }
    1185             :     }
    1186             : 
    1187       65978 :     parse_address_port(address, port_str, result, true);
    1188             : }
    1189             : 
    1190             : 
    1191             : /** \brief Parse the address and port.
    1192             :  *
    1193             :  * This function receives an address and a port string and
    1194             :  * convert them in an addr object which gets saved in
    1195             :  * the specified result range vector.
    1196             :  *
    1197             :  * The address can be an IPv4 or an IPv6 address.
    1198             :  *
    1199             :  * The port may be numeric or a name such as `"http"`.
    1200             :  *
    1201             :  * \note
    1202             :  * This function is not responsible for handling the default address
    1203             :  * and default port. This is expected to be dealt with by the caller
    1204             :  * if required.
    1205             :  *
    1206             :  * \param[in] address  The address to convert to binary.
    1207             :  * \param[in] port_str  The port as a string.
    1208             :  * \param[out] result  The range where we save the results.
    1209             :  * \param[in] ipv6  Use the default IPv6 address if the address is empty.
    1210             :  */
    1211      131838 : void addr_parser::parse_address_port(std::string address, std::string port_str, addr_range::vector_t & result, bool ipv6)
    1212             : {
    1213             :     // make sure the port is good
    1214             :     //
    1215      131838 :     if(port_str.empty())
    1216             :     {
    1217          77 :         if(f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
    1218             :         {
    1219           4 :             emit_error("Required port is missing.");
    1220          12 :             return;
    1221             :         }
    1222          73 :         if(f_default_port != -1)
    1223             :         {
    1224          52 :             port_str = std::to_string(f_default_port);
    1225             :         }
    1226             :     }
    1227             : 
    1228             :     // make sure the address is good
    1229             :     //
    1230      131834 :     if(address.empty())
    1231             :     {
    1232         319 :         if(f_flags[static_cast<int>(flag_t::REQUIRED_ADDRESS)])
    1233             :         {
    1234           2 :             emit_error("Required address is missing.");
    1235           2 :             return;
    1236             :         }
    1237             :         // internal default if no address was defined
    1238             :         // (TBD: should it be an IPv6 instead?)
    1239             :         //
    1240         317 :         if(ipv6)
    1241             :         {
    1242         203 :             if(f_default_address6.empty())
    1243             :             {
    1244         101 :                 address = "::";
    1245             :             }
    1246             :             else
    1247             :             {
    1248         102 :                 address = f_default_address6;
    1249             :             }
    1250             :         }
    1251             :         else
    1252             :         {
    1253         114 :             if(f_default_address4.empty())
    1254             :             {
    1255          11 :                 address = "0.0.0.0";
    1256             :             }
    1257             :             else
    1258             :             {
    1259         103 :                 address = f_default_address4;
    1260             :             }
    1261             :         }
    1262             :     }
    1263             : 
    1264             :     // prepare hints for the the getaddrinfo() function
    1265             :     //
    1266             :     struct addrinfo hints;
    1267      131832 :     memset(&hints, 0, sizeof(hints));
    1268      131832 :     hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
    1269      131832 :     hints.ai_family = AF_UNSPEC;
    1270             : 
    1271      131832 :     switch(f_protocol)
    1272             :     {
    1273       66092 :     case IPPROTO_TCP:
    1274       66092 :         hints.ai_socktype = SOCK_STREAM;
    1275       66092 :         hints.ai_protocol = IPPROTO_TCP;
    1276       66092 :         break;
    1277             : 
    1278       65726 :     case IPPROTO_UDP:
    1279       65726 :         hints.ai_socktype = SOCK_DGRAM;
    1280       65726 :         hints.ai_protocol = IPPROTO_UDP;
    1281       65726 :         break;
    1282             : 
    1283             :     }
    1284             : 
    1285             :     // convert address to binary
    1286             :     //
    1287      131832 :     struct addrinfo * addrlist(nullptr);
    1288             :     {
    1289      131832 :         errno = 0;
    1290      131832 :         int const r(getaddrinfo(address.c_str(), port_str.c_str(), &hints, &addrlist));
    1291      131832 :         if(r != 0)
    1292             :         {
    1293             :             // break on invalid addresses
    1294             :             //
    1295           2 :             int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
    1296           2 :             emit_error(
    1297             :                       "Invalid address in \""
    1298           4 :                     + address
    1299           6 :                     + (port_str.empty() ? "" : ":")
    1300           4 :                     + port_str
    1301           4 :                     + "\" error "
    1302           8 :                     + std::to_string(r)
    1303           4 :                     + " -- "
    1304           6 :                     + gai_strerror(r)
    1305           4 :                     + (e == 0
    1306           8 :                         ? ""
    1307             :                         : " (errno: "
    1308           4 :                         + std::to_string(e)
    1309           4 :                         + " -- "
    1310           6 :                         + strerror(e)
    1311             :                         + ")."));
    1312           2 :             return;
    1313             :         }
    1314             :     }
    1315      263660 :     std::shared_ptr<struct addrinfo> ai(addrlist, addrinfo_deleter);
    1316             : 
    1317      131830 :     bool first(true);
    1318      395538 :     while(addrlist != nullptr)
    1319             :     {
    1320             :         // go through the addresses and create ranges and save that in the result
    1321             :         //
    1322      131854 :         if(addrlist->ai_family == AF_INET)
    1323             :         {
    1324       65876 :             if(addrlist->ai_addrlen != sizeof(struct sockaddr_in))
    1325             :             {
    1326             :                 emit_error("Unsupported address size ("                  // LCOV_EXCL_LINE
    1327             :                          + std::to_string(addrlist->ai_addrlen)          // LCOV_EXCL_LINE
    1328             :                          + ", expected"                                  // LCOV_EXCL_LINE
    1329             :                          + std::to_string(sizeof(struct sockaddr_in))    // LCOV_EXCL_LINE
    1330             :                          + ").");                                        // LCOV_EXCL_LINE
    1331             :             }
    1332             :             else
    1333             :             {
    1334       65876 :                 addr a(*reinterpret_cast<struct sockaddr_in *>(addrlist->ai_addr));
    1335             :                 // in most cases we do not get a protocol from
    1336             :                 // the getaddrinfo() function...
    1337       65876 :                 a.set_protocol(addrlist->ai_protocol);
    1338       65876 :                 addr_range r;
    1339       65876 :                 r.set_from(a);
    1340       65876 :                 result.push_back(r);
    1341             :             }
    1342             :         }
    1343       65978 :         else if(addrlist->ai_family == AF_INET6)
    1344             :         {
    1345       65978 :             if(addrlist->ai_addrlen != sizeof(struct sockaddr_in6))
    1346             :             {
    1347             :                 emit_error("Unsupported address size ("                  // LCOV_EXCL_LINE
    1348             :                          + std::to_string(addrlist->ai_addrlen)          // LCOV_EXCL_LINE
    1349             :                          + ", expected "                                 // LCOV_EXCL_LINE
    1350             :                          + std::to_string(sizeof(struct sockaddr_in6))   // LCOV_EXCL_LINE
    1351             :                          + ").");                                        // LCOV_EXCL_LINE
    1352             :             }
    1353             :             else
    1354             :             {
    1355       65978 :                 addr a(*reinterpret_cast<struct sockaddr_in6 *>(addrlist->ai_addr));
    1356       65978 :                 a.set_protocol(addrlist->ai_protocol);
    1357       65978 :                 addr_range r;
    1358       65978 :                 r.set_from(a);
    1359       65978 :                 result.push_back(r);
    1360             :             }
    1361             :         }
    1362             :         else if(first)                                                  // LCOV_EXCL_LINE
    1363             :         {
    1364             :             // ignore errors from further addresses
    1365             :             //
    1366             :             emit_error("Unsupported address family "                     // LCOV_EXCL_LINE
    1367             :                      + std::to_string(addrlist->ai_family)               // LCOV_EXCL_LINE
    1368             :                      + ".");                                             // LCOV_EXCL_LINE
    1369             :         }
    1370             : 
    1371      131854 :         first = false;
    1372             : 
    1373      131854 :         addrlist = addrlist->ai_next;
    1374             :     }
    1375             : }
    1376             : 
    1377             : 
    1378             : /** \brief Parse a mask.
    1379             :  *
    1380             :  * If the input string is a decimal number, then use that as the
    1381             :  * number of bits to clear.
    1382             :  *
    1383             :  * If the mask is not just one decimal number, try to convert it
    1384             :  * as an address.
    1385             :  *
    1386             :  * If the string is neither a decimal number nor a valid IP address
    1387             :  * then the parser adds an error string to the f_error variable.
    1388             :  *
    1389             :  * \param[in] mask  The mask to transform to binary.
    1390             :  * \param[in,out] cidr  The address to which the mask will be added.
    1391             :  */
    1392         474 : void addr_parser::parse_mask(std::string const & mask, addr & cidr)
    1393             : {
    1394             :     // no mask?
    1395             :     //
    1396         474 :     if(mask.empty())
    1397             :     {
    1398             :         // in the current implementation this cannot happen since we
    1399             :         // do not call this function when mask is empty
    1400             :         //
    1401             :         // hwoever, the algorithm below expect that 'mask' is not
    1402             :         // empty (otherwise we get the case of 0 even though it
    1403             :         // may not be correct.)
    1404             :         //
    1405             :         return;  // LCOV_EXCL_LINE
    1406             :     }
    1407             : 
    1408             :     // the mask may be a decimal number or an address, if just one number
    1409             :     // then it's not an address, so test that first
    1410             :     //
    1411         470 :     uint8_t mask_bits[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
    1412             : 
    1413             :     // convert the mask to an integer, if possible
    1414             :     //
    1415         470 :     int mask_count(0);
    1416             :     {
    1417        1304 :         for(char const * s(mask.c_str()); *s != '\0'; ++s)
    1418             :         {
    1419        1032 :             if(*s >= '0' && *s <= '9')
    1420             :             {
    1421         849 :                 mask_count = mask_count * 10 + *s - '0';
    1422        1683 :                 if(mask_count > 1000)
    1423             :                 {
    1424          15 :                     emit_error("Mask number too large ("
    1425          30 :                              + mask
    1426          30 :                              + ", expected a maximum of 128).");
    1427          15 :                     return;
    1428             :                 }
    1429             :             }
    1430             :             else
    1431             :             {
    1432         183 :                 mask_count = -1;
    1433         183 :                 break;
    1434             :             }
    1435             :         }
    1436             :     }
    1437             : 
    1438             :     // the conversion to an integer worked if mask_count != -1
    1439             :     //
    1440         455 :     if(mask_count != -1)
    1441             :     {
    1442         272 :         if(cidr.is_ipv4())
    1443             :         {
    1444          42 :             if(mask_count > 32)
    1445             :             {
    1446           5 :                 emit_error("Unsupported mask size ("
    1447          10 :                          + std::to_string(mask_count)
    1448          10 :                          + ", expected 32 at the most for an IPv4).");
    1449           5 :                 return;
    1450             :             }
    1451          37 :             mask_count = 32 - mask_count;
    1452             :         }
    1453             :         else
    1454             :         {
    1455         230 :             if(mask_count > 128)
    1456             :             {
    1457           5 :                 emit_error("Unsupported mask size ("
    1458          10 :                          + std::to_string(mask_count)
    1459          10 :                          + ", expected 128 at the most for an IPv6).");
    1460           5 :                 return;
    1461             :             }
    1462         225 :             mask_count = 128 - mask_count;
    1463             :         }
    1464             : 
    1465             :         // clear a few bits at the bottom of mask_bits
    1466             :         //
    1467         262 :         int idx(15);
    1468        3322 :         for(; mask_count > 8; mask_count -= 8, --idx)
    1469             :         {
    1470        1530 :             mask_bits[idx] = 0;
    1471             :         }
    1472         262 :         mask_bits[idx] = 255 << mask_count;
    1473             :     }
    1474             :     else //if(mask_count < 0)
    1475             :     {
    1476             :         // prepare hints for the the getaddrinfo() function
    1477             :         //
    1478             :         struct addrinfo hints;
    1479         183 :         memset(&hints, 0, sizeof(hints));
    1480         183 :         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
    1481         183 :         hints.ai_family = AF_UNSPEC;
    1482             : 
    1483         183 :         switch(cidr.get_protocol())
    1484             :         {
    1485          97 :         case IPPROTO_TCP:
    1486          97 :             hints.ai_socktype = SOCK_STREAM;
    1487          97 :             hints.ai_protocol = IPPROTO_TCP;
    1488          97 :             break;
    1489             : 
    1490          86 :         case IPPROTO_UDP:
    1491          86 :             hints.ai_socktype = SOCK_DGRAM;
    1492          86 :             hints.ai_protocol = IPPROTO_UDP;
    1493          86 :             break;
    1494             : 
    1495             :         }
    1496             : 
    1497         338 :         std::string const port_str(std::to_string(cidr.get_port()));
    1498             : 
    1499             :         // if the mask is an IPv6, then it has to have the '[...]'
    1500         338 :         std::string m(mask);
    1501         183 :         if(cidr.is_ipv4())
    1502             :         {
    1503          87 :             if(mask[0] == '[')
    1504             :             {
    1505           1 :                 emit_error("The address uses the IPv4 syntax, the mask cannot use IPv6.");
    1506           1 :                 return;
    1507             :             }
    1508             :         }
    1509             :         else //if(!cidr.is_ipv4())
    1510             :         {
    1511          96 :             if(mask[0] != '[')
    1512             :             {
    1513           1 :                 emit_error("The address uses the IPv6 syntax, the mask cannot use IPv4.");
    1514           1 :                 return;
    1515             :             }
    1516          95 :             if(mask.back() != ']')
    1517             :             {
    1518           1 :                 emit_error("The IPv6 mask is missing the ']' (" + mask + ").");
    1519           1 :                 return;
    1520             :             }
    1521             : 
    1522             :             // note that we know that mask.length() >= 2 here since
    1523             :             // we at least have a '[' and ']'
    1524             :             //
    1525          94 :             m = mask.substr(1, mask.length() - 2);
    1526          94 :             if(m.empty())
    1527             :             {
    1528             :                 // an empty mask is valid, it just means keep the default
    1529             :                 // (getaddrinfo() fails on an empty string)
    1530             :                 //
    1531           3 :                 return;
    1532             :             }
    1533             :         }
    1534             : 
    1535             :         // if negative, we may have a full address here, so call the
    1536             :         // getaddrinfo() on this other string
    1537             :         //
    1538         177 :         struct addrinfo * masklist(nullptr);
    1539         177 :         errno = 0;
    1540         177 :         int const r(getaddrinfo(m.c_str(), port_str.c_str(), &hints, &masklist));
    1541         177 :         if(r != 0)
    1542             :         {
    1543             :             // break on invalid addresses
    1544             :             //
    1545          15 :             int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
    1546          15 :             emit_error("Invalid mask in \"/"
    1547          30 :                      + mask
    1548          30 :                      + "\", error "
    1549          60 :                      + std::to_string(r)
    1550          30 :                      + " -- "
    1551          45 :                      + gai_strerror(r)
    1552          30 :                      + " (errno: "
    1553          60 :                      + std::to_string(e)
    1554          30 :                      + " -- "
    1555          45 :                      + strerror(e)
    1556          30 :                      + ").");
    1557          15 :             return;
    1558             :         }
    1559         317 :         std::shared_ptr<struct addrinfo> mask_ai(masklist, addrinfo_deleter);
    1560             : 
    1561         162 :         if(cidr.is_ipv4())
    1562             :         {
    1563          76 :             if(masklist->ai_family != AF_INET)
    1564             :             {
    1565             :                 // this one happens when the user does not put the '[...]'
    1566             :                 // around an IPv6 address
    1567             :                 //
    1568           1 :                 emit_error("Incompatible address between the address and"
    1569             :                           " mask address (first was an IPv4 second an IPv6).");
    1570           1 :                 return;
    1571             :             }
    1572          75 :             if(masklist->ai_addrlen != sizeof(struct sockaddr_in))
    1573             :             {
    1574             :                 emit_error("Unsupported address size ("                 // LCOV_EXCL_LINE
    1575             :                         + std::to_string(masklist->ai_addrlen)          // LCOV_EXCL_LINE
    1576             :                         + ", expected"                                  // LCOV_EXCL_LINE
    1577             :                         + std::to_string(sizeof(struct sockaddr_in))    // LCOV_EXCL_LINE
    1578             :                         + ").");                                        // LCOV_EXCL_LINE
    1579             :                 return;                                                 // LCOV_EXCL_LINE
    1580             :             }
    1581          75 :             memcpy(mask_bits + 12, &reinterpret_cast<struct sockaddr_in *>(masklist->ai_addr)->sin_addr.s_addr, 4); // last 4 bytes are the IPv4 address, keep the rest as 1s
    1582             :         }
    1583             :         else //if(!cidr.is_ipv4())
    1584             :         {
    1585          86 :             if(masklist->ai_family != AF_INET6)
    1586             :             {
    1587             :                 // this one happens if the user puts the '[...]'
    1588             :                 // around an IPv4 address
    1589             :                 //
    1590           6 :                 emit_error("Incompatible address between the address"
    1591             :                           " and mask address (first was an IPv6 second an IPv4).");
    1592           6 :                 return;
    1593             :             }
    1594          80 :             if(masklist->ai_addrlen != sizeof(struct sockaddr_in6))
    1595             :             {
    1596             :                 emit_error("Unsupported address size ("                 // LCOV_EXCL_LINE
    1597             :                          + std::to_string(masklist->ai_addrlen)         // LCOV_EXCL_LINE
    1598             :                          + ", expected "                                // LCOV_EXCL_LINE
    1599             :                          + std::to_string(sizeof(struct sockaddr_in6))  // LCOV_EXCL_LINE
    1600             :                          + ").");                                       // LCOV_EXCL_LINE
    1601             :                 return;                                                 // LCOV_EXCL_LINE
    1602             :             }
    1603          80 :             memcpy(mask_bits, &reinterpret_cast<struct sockaddr_in6 *>(masklist->ai_addr)->sin6_addr.s6_addr, 16);
    1604             :         }
    1605             :     }
    1606             : 
    1607         417 :     cidr.set_mask(mask_bits);
    1608             : }
    1609             : 
    1610             : 
    1611             : /** \brief Transform a string into an `addr` object.
    1612             :  *
    1613             :  * This function converts the string \p a in an IP address saved in
    1614             :  * the returned addr object or throws an error if the conversion
    1615             :  * fails.
    1616             :  *
    1617             :  * The \p default_address parameter string can be set to an address
    1618             :  * which is returned if the input in \p a does not include an
    1619             :  * address such as in ":123".
    1620             :  *
    1621             :  * The \p port parameter can be specified or set to -1. If -1, then
    1622             :  * there is no default port. Either way, the port can be defined in
    1623             :  * \p a.
    1624             :  *
    1625             :  * The protocol can be specified, as a string. For example, you can
    1626             :  * use "tcp". The default is no specific protocol which means any
    1627             :  * type of IP address can be returned. Note that if more than one
    1628             :  * result is returned when the protocol was not specified, the
    1629             :  * results will be filtered to only keep the address that uses the
    1630             :  * TCP protocol. If as a result we have a single address, then that
    1631             :  * result gets returned.
    1632             :  *
    1633             :  * \note
    1634             :  * This function does not allow for address or port ranges. It is
    1635             :  * expected to return exactly one address. You can allow a \p mask
    1636             :  * by setting that parameter to true.
    1637             :  *
    1638             :  * \exception addr_invalid_argument
    1639             :  * If the parsed address is not returning a valid `addr` object, then
    1640             :  * this function fails by throwing an error. If you would prefer to
    1641             :  * handle the error mechanism, you want to create your own addr_parser
    1642             :  * and then call the addr_parser::parse() function. This will allow
    1643             :  * you to get error messages instead of an exception.
    1644             :  *
    1645             :  * \param[in] a  The address string to be converted.
    1646             :  * \param[in] default_addrress  The default address or an empty string.
    1647             :  * \param[in] default_port  The default port or -1
    1648             :  * \param[in] protocol  The protocol the address has to be of, or the
    1649             :  *                      empty string to allow any protocol.
    1650             :  * \param[in] m  Whether to allow a mask (true) or not (false).
    1651             :  *
    1652             :  * \return The address converted in an `addr` object.
    1653             :  *
    1654             :  * \sa addr_parser::parse()
    1655             :  */
    1656          14 : addr string_to_addr(
    1657             :           std::string const & a
    1658             :         , std::string const & default_address
    1659             :         , int default_port
    1660             :         , std::string const & protocol
    1661             :         , bool mask)
    1662             : {
    1663          28 :     addr_parser p;
    1664             : 
    1665          14 :     if(!default_address.empty())
    1666             :     {
    1667          10 :         p.set_default_address(default_address);
    1668             :     }
    1669             : 
    1670          14 :     if(default_port != -1)
    1671             :     {
    1672           8 :         p.set_default_port(default_port);
    1673             :     }
    1674             : 
    1675          14 :     if(!protocol.empty())
    1676             :     {
    1677           7 :         p.set_protocol(protocol);
    1678             :     }
    1679             : 
    1680          13 :     p.set_allow(addr_parser::flag_t::MASK, mask);
    1681             : 
    1682          26 :     addr_range::vector_t result(p.parse(a));
    1683             : 
    1684          13 :     if(result.size() != 1)
    1685             :     {
    1686             :         // when the protocol is not specified, this happens like all the
    1687             :         // time, we search for an entry with protocol TCP by default
    1688             :         // because in most cases that's what people want
    1689             :         //
    1690           7 :         if(protocol.empty())
    1691             :         {
    1692           7 :             result.erase(
    1693          14 :                       std::remove_if(
    1694             :                           result.begin()
    1695             :                         , result.end()
    1696          21 :                         , [](auto const it)
    1697             :                         {
    1698          21 :                             return it.has_from() && it.get_from().get_protocol() != IPPROTO_TCP;
    1699          28 :                         })
    1700          28 :                     , result.end());
    1701             :         }
    1702           7 :         if(result.size() != 1)
    1703             :         {
    1704             :             // an invalid protocol is caught by the set_protocol()
    1705             :             // function so we should never be able to reach here
    1706             :             //
    1707             :             throw addr_invalid_argument(                                                            // LCOV_EXCL_LINE
    1708             :                       "the address \""                                                              // LCOV_EXCL_LINE
    1709             :                     + a                                                                             // LCOV_EXCL_LINE
    1710             :                     + "\" could not be converted to a single address in string_to_addr(), found "   // LCOV_EXCL_LINE
    1711             :                     + std::to_string(result.size())                                                 // LCOV_EXCL_LINE
    1712             :                     + " entries instead.");                                                         // LCOV_EXCL_LINE
    1713             :         }
    1714             :     }
    1715             : 
    1716             :     // at the movement we only can get a "to" so the following exceptions
    1717             :     // can't happen which is why we have an LCOV_EXCL_LINE
    1718             :     //
    1719          26 :     if(result[0].has_to()
    1720          13 :     || result[0].is_range())
    1721             :     {
    1722             :         throw addr_invalid_argument("string_to_addr() does not support ranges.");     // LCOV_EXCL_LINE
    1723             :     }
    1724             : 
    1725          13 :     if(!result[0].has_from())
    1726             :     {
    1727             :         throw addr_invalid_argument("string_to_addr() has no 'from' address.");       // LCOV_EXCL_LINE
    1728             :     }
    1729             : 
    1730          26 :     return result[0].get_from();
    1731             : }
    1732             : 
    1733             : 
    1734             : 
    1735           6 : }
    1736             : // namespace addr
    1737             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13