LCOV - code coverage report
Current view: top level - src - addr_parser.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 388 388 100.0 %
Date: 2018-05-30 23:58:02 Functions: 31 31 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12