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

Generated by: LCOV version 1.12