LCOV - code coverage report
Current view: top level - tests - catch_ipv6.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.8 % 2115 2069
Test Date: 2025-04-18 08:03:11 Functions: 100.0 % 11 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2011-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/libaddr
       4              : // contact@m2osw.com
       5              : //
       6              : // Permission is hereby granted, free of charge, to any
       7              : // person obtaining a copy of this software and
       8              : // associated documentation files (the "Software"), to
       9              : // deal in the Software without restriction, including
      10              : // without limitation the rights to use, copy, modify,
      11              : // merge, publish, distribute, sublicense, and/or sell
      12              : // copies of the Software, and to permit persons to whom
      13              : // the Software is furnished to do so, subject to the
      14              : // following conditions:
      15              : //
      16              : // The above copyright notice and this permission notice
      17              : // shall be included in all copies or substantial
      18              : // portions of the Software.
      19              : //
      20              : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      21              : // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      22              : // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      23              : // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      24              : // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      25              : // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      26              : // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      27              : // ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      28              : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      29              : // SOFTWARE.
      30              : 
      31              : 
      32              : /** \file
      33              :  * \brief Test the IPv6 interface.
      34              :  *
      35              :  * These test verify that the IPv6 side of things function as expected.
      36              :  *
      37              :  * Note that some of the tests between the IPv4 and IPv6 overlap. Here
      38              :  * you mainly find the IPv6 side of things.
      39              :  *
      40              :  * Also, the IPv6 tests include a certain number of default/global
      41              :  * tests because internally the addr class implements an IPv6 object.
      42              :  */
      43              : 
      44              : // addr
      45              : //
      46              : #include    <libaddr/iface.h>
      47              : 
      48              : 
      49              : // self
      50              : //
      51              : #include    "catch_main.h"
      52              : 
      53              : 
      54              : // snapdev
      55              : //
      56              : #include    <snapdev/int128_literal.h>
      57              : #include    <snapdev/ostream_int128.h>
      58              : #include    <snapdev/string_replace_many.h>
      59              : 
      60              : 
      61              : // last include
      62              : //
      63              : #include    <snapdev/poison.h>
      64              : 
      65              : 
      66              : using namespace snapdev::literals;
      67              : 
      68              : 
      69              : 
      70              : /** \brief Details used by the addr class implementation.
      71              :  *
      72              :  * We have a function to check whether an address is part of
      73              :  * the interfaces of your computer. This check requires the
      74              :  * use of a `struct ifaddrs` and as such it requires to
      75              :  * delete that structure. We define a deleter for that
      76              :  * structure here.
      77              :  */
      78              : namespace
      79              : {
      80              : 
      81              : /** \brief Close a socket.
      82              :  *
      83              :  * This deleter is used to make sure all the sockets get closed on exit.
      84              :  *
      85              :  * \param[in] s  The socket to close.
      86              :  */
      87            3 : void socket_deleter(int * s)
      88              : {
      89            3 :     close(*s);
      90            3 : }
      91              : 
      92              : 
      93              : }
      94              : // no name namespace
      95              : 
      96              : 
      97              : 
      98           14 : CATCH_TEST_CASE("ipv6::invalid_input", "[ipv6]")
      99              : {
     100           14 :     CATCH_GIVEN("addr()")
     101              :     {
     102            1 :         addr::addr a;
     103              : 
     104            1 :         CATCH_START_SECTION("ipv6::invalid_input: set IPv6 with an invalid family")
     105              :         {
     106            1 :             struct sockaddr_in6 in6 = sockaddr_in6();
     107              :             do
     108              :             {
     109            1 :                 in6.sin6_family = rand();
     110              :             }
     111            1 :             while(in6.sin6_family == AF_INET6);
     112            1 :             in6.sin6_port = rand();
     113            9 :             for(int idx(0); idx < 8; ++idx)
     114              :             {
     115            8 :                 in6.sin6_addr.s6_addr16[idx] = rand();
     116              :             }
     117            1 :             CATCH_REQUIRE_THROWS_AS(a.set_ipv6(in6), addr::addr_invalid_argument);
     118            2 :             CATCH_REQUIRE_THROWS_AS(addr::addr(in6), addr::addr_invalid_argument);
     119              :         }
     120            1 :         CATCH_END_SECTION()
     121           15 :     }
     122              : 
     123           14 :     CATCH_GIVEN("addr_parser() with IPv6 addresses")
     124              :     {
     125            3 :         CATCH_START_SECTION("ipv6::invalid_input: bad address")
     126              :         {
     127            1 :             addr::addr_parser p;
     128            3 :             addr::addr_range::vector_t ips(p.parse("[{bad-ip}]"));
     129            1 :             CATCH_REQUIRE(p.has_errors());
     130            1 :             CATCH_REQUIRE(p.error_count() == 1);
     131            1 :             CATCH_REQUIRE(p.error_messages() == "Invalid address in \"{bad-ip}\" error -2 -- Name or service not known (errno: 22 -- Invalid argument).\n");
     132            1 :             CATCH_REQUIRE(ips.size() == 0);
     133            1 :         }
     134            3 :         CATCH_END_SECTION()
     135              : 
     136            3 :         CATCH_START_SECTION("ipv6::invalid_input: missing ']'")
     137              :         {
     138            1 :             addr::addr_parser p;
     139            3 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7"));
     140            1 :             CATCH_REQUIRE(p.has_errors());
     141            1 :             CATCH_REQUIRE(p.error_count() == 1);
     142            1 :             CATCH_REQUIRE(p.error_messages() == "IPv6 is missing the ']' ([1:2:3:4:5:6:7).\n");
     143            1 :             CATCH_REQUIRE(ips.size() == 0);
     144            1 :         }
     145            3 :         CATCH_END_SECTION()
     146              : 
     147            3 :         CATCH_START_SECTION("ipv6::invalid_input: required address")
     148              :         {
     149            1 :             addr::addr_parser p;
     150            1 :             p.set_protocol(IPPROTO_TCP);
     151            1 :             p.set_allow(addr::allow_t::ALLOW_REQUIRED_ADDRESS, true);
     152            3 :             addr::addr_range::vector_t ips(p.parse("[]"));
     153            1 :             CATCH_REQUIRE(p.has_errors());
     154            1 :             CATCH_REQUIRE(p.error_count() == 1);
     155            1 :             CATCH_REQUIRE(p.error_messages() == "Required address is missing.\n");
     156            1 :             CATCH_REQUIRE(ips.size() == 0);
     157            1 :         }
     158            3 :         CATCH_END_SECTION()
     159           14 :     }
     160              : 
     161           14 :     CATCH_GIVEN("addr_parser() with IPv4 ports")
     162              :     {
     163            2 :         CATCH_START_SECTION("ipv6::invalid_input: required port")
     164              :         {
     165              :             // optional + required -> required
     166              :             {
     167            1 :                 addr::addr_parser p;
     168            1 :                 p.set_protocol(IPPROTO_TCP);
     169            1 :                 p.set_allow(addr::allow_t::ALLOW_REQUIRED_PORT, true);
     170            3 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
     171            1 :                 CATCH_REQUIRE(p.has_errors());
     172            1 :                 CATCH_REQUIRE(p.error_count() == 1);
     173            1 :                 CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
     174            1 :                 CATCH_REQUIRE(ips.size() == 0);
     175            1 :             }
     176              : 
     177              :             // only required -> required just the same
     178              :             {
     179            1 :                 addr::addr_parser p;
     180            1 :                 p.set_protocol(IPPROTO_TCP);
     181            1 :                 p.set_allow(addr::allow_t::ALLOW_PORT, false);
     182            1 :                 p.set_allow(addr::allow_t::ALLOW_REQUIRED_PORT, true);
     183            3 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
     184            1 :                 CATCH_REQUIRE(p.has_errors());
     185            1 :                 CATCH_REQUIRE(p.error_count() == 1);
     186            1 :                 CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
     187            1 :                 CATCH_REQUIRE(ips.size() == 0);
     188            1 :             }
     189              :         }
     190            2 :         CATCH_END_SECTION()
     191              : 
     192            2 :         CATCH_START_SECTION("ipv6::invalid_input: port not allowed")
     193              :         {
     194              :             {
     195            1 :                 addr::addr_parser p;
     196            1 :                 p.set_protocol(IPPROTO_TCP);
     197            1 :                 p.set_allow(addr::allow_t::ALLOW_PORT, false);
     198            3 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:123"));
     199            1 :                 CATCH_REQUIRE(p.has_errors());
     200            1 :                 CATCH_REQUIRE(p.error_count() == 1);
     201            1 :                 CATCH_REQUIRE(p.error_messages() == "Port not allowed ([1:2:3:4:5:6:7:8]:123).\n");
     202            1 :                 CATCH_REQUIRE(ips.size() == 0);
     203            1 :             }
     204              : 
     205              :             {
     206            1 :                 addr::addr_parser p;
     207            1 :                 p.set_protocol(IPPROTO_TCP);
     208            1 :                 p.set_allow(addr::allow_t::ALLOW_PORT, false);
     209            3 :                 addr::addr_range::vector_t ips(p.parse("1:2:3:4:5:6:7:8:123.5"));
     210            1 :                 CATCH_REQUIRE(p.has_errors());
     211            1 :                 CATCH_REQUIRE(p.error_count() == 1);
     212            1 :                 CATCH_REQUIRE(p.error_messages() == "Invalid address in \"1:2:3:4:5:6:7:8:123.5\" error -2 -- Name or service not known (errno: 22 -- Invalid argument).\n");
     213            1 :                 CATCH_REQUIRE(ips.size() == 0);
     214            1 :             }
     215              :         }
     216            2 :         CATCH_END_SECTION()
     217           14 :     }
     218              : 
     219           14 :     CATCH_GIVEN("addr_parser() with invalid masks")
     220              :     {
     221            8 :         CATCH_START_SECTION("ipv6::invalid_input: really large numbers (over 1000)")
     222              :         {
     223            6 :             for(int idx(0); idx < 5; ++idx)
     224              :             {
     225            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     226            5 :                 int const port(rand() & 0xFFFF);
     227            5 :                 int const mask((rand() & 0xFF) + 10001);
     228            5 :                 addr::addr_parser p;
     229            5 :                 p.set_protocol(proto);
     230            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     231            5 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
     232            5 :                 CATCH_REQUIRE(p.has_errors());
     233            5 :                 CATCH_REQUIRE(p.error_count() == 1);
     234            5 :                 CATCH_REQUIRE(p.error_messages() == "Mask size too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
     235            5 :                 CATCH_REQUIRE(ips.size() == 0);
     236            5 :             }
     237              : 
     238              :             // WARNING: I removed the first removal of the '[' and ']'
     239              :             //          the mask as a number should never have to be between
     240              :             //          square brackets, only addresses so here we have the
     241              :             //          same case as the block beforehand
     242              :             //
     243              :             // in case the number is between square brackets it looks like
     244              :             // an IPv4 to getaddrinfo() so we get a different error...
     245              :             // (i.e. the '[' is not a digit so we do not get the "too large"
     246              :             // error...)
     247              :             //
     248              :             //for(int idx(0); idx < 5; ++idx)
     249              :             //{
     250              :             //    int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     251              :             //    int const port(rand() & 0xFFFF);
     252              :             //    int const mask((rand() & 0xFF) + 10001);
     253              :             //    addr::addr_parser p;
     254              :             //    p.set_protocol(proto);
     255              :             //    p.set_allow(addr::allow_t::ALLOW_MASK, true);
     256              :             //    p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     257              :             //    addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
     258              :             //    CATCH_REQUIRE(p.has_errors());
     259              :             //    CATCH_REQUIRE(p.error_count() == 1);
     260              :             //    CATCH_REQUIRE(p.error_messages() == "Mask size too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
     261              :             //    CATCH_REQUIRE(ips.size() == 0);
     262              :             //}
     263              : 
     264              :             // an empty address with a mask too large gets us to another place
     265              :             //
     266            6 :             for(int idx(0); idx < 5; ++idx)
     267              :             {
     268            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     269            5 :                 int const port(rand() & 0xFFFF);
     270            5 :                 int const mask((rand() & 0xFF) + 10001);
     271            5 :                 addr::addr_parser p;
     272            5 :                 p.set_protocol(proto);
     273            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     274            5 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask)));
     275            5 :                 CATCH_REQUIRE(p.has_errors());
     276            5 :                 CATCH_REQUIRE(p.error_count() == 1);
     277            5 :                 CATCH_REQUIRE(p.error_messages() == "Mask size too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
     278            5 :                 CATCH_REQUIRE(ips.size() == 0);
     279            5 :             }
     280              : 
     281              :             // an empty address with a mask too large gets us to another place
     282              :             //
     283            6 :             for(int idx(0); idx < 5; ++idx)
     284              :             {
     285            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     286            5 :                 int const port(rand() & 0xFFFF);
     287            5 :                 int const mask((rand() & 0xFF));
     288            5 :                 addr::addr_parser p;
     289            5 :                 p.set_protocol(proto);
     290            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     291            5 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     292            5 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask) + "q"));
     293            5 :                 CATCH_REQUIRE(p.has_errors());
     294            5 :                 CATCH_REQUIRE(p.error_count() == 1);
     295            5 :                 CATCH_REQUIRE(p.error_messages() == "Invalid mask in \"/" + std::to_string(mask) + "q\", error -2 -- Name or service not known (errno: 0 -- Success).\n");
     296            5 :                 CATCH_REQUIRE(ips.size() == 0);
     297            5 :             }
     298              :         }
     299            8 :         CATCH_END_SECTION()
     300              : 
     301            8 :         CATCH_START_SECTION("ipv6::invalid_input: ipv6 mask is limited between 0 and 128")
     302              :         {
     303            6 :             for(int idx(0); idx < 5; ++idx)
     304              :             {
     305            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     306            5 :                 int const port(rand() & 0xFFFF);
     307            5 :                 int const mask((rand() & 0xFF) + 129);
     308            5 :                 addr::addr_parser p;
     309            5 :                 p.set_protocol(proto);
     310            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     311            5 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
     312            5 :                 CATCH_REQUIRE(p.has_errors());
     313            5 :                 CATCH_REQUIRE(p.error_count() == 1);
     314            5 :                 CATCH_REQUIRE(p.error_messages() == "Unsupported mask size (" + std::to_string(mask) + ", expected 128 at the most for an IPv6).\n");
     315            5 :                 CATCH_REQUIRE(ips.size() == 0);
     316            5 :             }
     317              :         }
     318            8 :         CATCH_END_SECTION()
     319              : 
     320            8 :         CATCH_START_SECTION("ipv6::invalid_input: ipv6 mask cannot use name")
     321              :         {
     322            6 :             for(int idx(0); idx < 5; ++idx)
     323              :             {
     324            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     325            5 :                 int const port(rand() & 0xFFFF);
     326            5 :                 addr::addr_parser p;
     327            5 :                 p.set_protocol(proto);
     328            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     329            5 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     330            5 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[localhost]"));
     331            5 :                 CATCH_REQUIRE(p.has_errors());
     332            5 :                 CATCH_REQUIRE(p.error_count() == 1);
     333            5 :                 CATCH_REQUIRE(p.error_messages() == "Invalid mask in \"/[localhost]\", error -2 -- Name or service not known (errno: 0 -- Success).\n");
     334            5 :                 CATCH_REQUIRE(ips.size() == 0);
     335            5 :             }
     336              :         }
     337            8 :         CATCH_END_SECTION()
     338              : 
     339            8 :         CATCH_START_SECTION("ipv6::invalid_input: ipv6 mask must be between '[...]'")
     340              :         {
     341            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     342            1 :             int const port(rand() & 0xFFFF);
     343            1 :             addr::addr_parser p;
     344            1 :             p.set_protocol(proto);
     345            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     346            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     347            1 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/::3"));
     348            1 :             CATCH_REQUIRE(p.has_errors());
     349            1 :             CATCH_REQUIRE(p.error_count() == 1);
     350            1 :             CATCH_REQUIRE(p.error_messages() == "The address uses the IPv6 syntax, the mask cannot use IPv4.\n");
     351            1 :             CATCH_REQUIRE(ips.size() == 0);
     352            1 :         }
     353            8 :         CATCH_END_SECTION()
     354              : 
     355            8 :         CATCH_START_SECTION("ipv6::invalid_input: ipv6 mask missing the ']'")
     356              :         {
     357            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     358            1 :             int const port(rand() & 0xFFFF);
     359            1 :             addr::addr_parser p;
     360            1 :             p.set_protocol(proto);
     361            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     362            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     363            1 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[::3"));
     364            1 :             CATCH_REQUIRE(p.has_errors());
     365            1 :             CATCH_REQUIRE(p.error_count() == 1);
     366            1 :             CATCH_REQUIRE(p.error_messages() == "The IPv6 mask is missing the ']' ([::3).\n");
     367            1 :             CATCH_REQUIRE(ips.size() == 0);
     368            1 :         }
     369            8 :         CATCH_END_SECTION()
     370              : 
     371            8 :         CATCH_START_SECTION("ipv6::invalid_input: ipv6 mask with an ipv4 in the '[...]'")
     372              :         {
     373            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     374            1 :             int const port(rand() & 0xFFFF);
     375            1 :             addr::addr_parser p;
     376            1 :             p.set_protocol(proto);
     377            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     378            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
     379            1 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[1.2.3.4]"));
     380            1 :             CATCH_REQUIRE(p.has_errors());
     381            1 :             CATCH_REQUIRE(p.error_count() == 1);
     382            1 :             CATCH_REQUIRE(p.error_messages() == "Incompatible address between the address and mask address (first was an IPv6 second an IPv4).\n");
     383            1 :             CATCH_REQUIRE(ips.size() == 0);
     384            1 :         }
     385            8 :         CATCH_END_SECTION()
     386              : 
     387            8 :         CATCH_START_SECTION("ipv6::invalid_input: verify default address")
     388              :         {
     389            1 :             addr::addr_parser p;
     390              : 
     391            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
     392            1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     393            1 :             CATCH_REQUIRE(p.get_default_address6() == "");
     394              : 
     395            3 :             p.set_default_address("[1:7:1:7:1:7:1:7]");
     396            1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     397            1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     398              : 
     399            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
     400            1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     401            1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     402              : 
     403            3 :             p.set_default_address("12.55.1.9");
     404            1 :             CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
     405            1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     406              : 
     407            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
     408            1 :             CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
     409            1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     410              : 
     411            3 :             p.set_default_address("");
     412            1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     413            1 :             CATCH_REQUIRE(p.get_default_address6() == "");
     414            1 :         }
     415            8 :         CATCH_END_SECTION()
     416              : 
     417            8 :         CATCH_START_SECTION("ipv6::invalid_input: verify default mask")
     418              :         {
     419            1 :             addr::addr_parser p;
     420              : 
     421            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
     422            1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     423            1 :             CATCH_REQUIRE(p.get_default_mask6() == "");
     424              : 
     425            3 :             p.set_default_mask("[1:7:1:7:1:7:1:7]");
     426            1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     427            1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     428              : 
     429            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
     430            1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     431            1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     432              : 
     433            3 :             p.set_default_mask("12.55.1.9");
     434            1 :             CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
     435            1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     436              : 
     437            5 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
     438            1 :             CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
     439            1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     440              : 
     441            3 :             p.set_default_mask("55");
     442            1 :             CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
     443            1 :             CATCH_REQUIRE(p.get_default_mask6() == "55");
     444              : 
     445            3 :             p.set_default_mask("16");
     446            1 :             CATCH_REQUIRE(p.get_default_mask4() == "16");
     447            1 :             CATCH_REQUIRE(p.get_default_mask6() == "55");
     448              : 
     449            3 :             p.set_default_mask("");
     450            1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     451            1 :             CATCH_REQUIRE(p.get_default_mask6() == "");
     452              : 
     453           11 :             for(int idx(-10); idx < 0; ++idx)
     454              :             {
     455           50 :                 CATCH_REQUIRE_THROWS_MATCHES(
     456              :                           p.set_default_mask(std::to_string(idx))
     457              :                         , addr::addr_invalid_argument
     458              :                         , Catch::Matchers::ExceptionMessage(
     459              :                                   "addr_error: a mask number must be between 0 and 128."));
     460              :             }
     461              : 
     462            8 :             for(int idx(129); idx <= 135; ++idx)
     463              :             {
     464           35 :                 CATCH_REQUIRE_THROWS_MATCHES(
     465              :                           p.set_default_mask(std::to_string(idx))
     466              :                         , addr::addr_invalid_argument
     467              :                         , Catch::Matchers::ExceptionMessage(
     468              :                                   "addr_error: a mask number must be between 0 and 128."));
     469              :             }
     470            1 :         }
     471            8 :         CATCH_END_SECTION()
     472           14 :     }
     473           14 : }
     474              : 
     475              : 
     476           26 : CATCH_TEST_CASE("ipv6::address", "[ipv6]")
     477              : {
     478           26 :     CATCH_GIVEN("addr() with an IPv6")
     479              :     {
     480            6 :         addr::addr a;
     481              : 
     482            6 :         CATCH_START_SECTION("ipv6::address: default is 128 bit set to zero")
     483              :         {
     484            1 :             CATCH_REQUIRE(a.ip_to_uint128() == 0_uint128);
     485              : 
     486              :             // any address is not the next/previous of itself, even 0
     487            1 :             CATCH_REQUIRE_FALSE(a.is_next(a));
     488            1 :             CATCH_REQUIRE_FALSE(a.is_previous(a));
     489              : 
     490              :             // first address -N is still the first address
     491              :             //
     492            1 :             addr::addr b(a);
     493            1 :             CATCH_REQUIRE(a == b);
     494            1 :             b--;
     495            1 :             CATCH_REQUIRE(a == b);
     496            1 :             --b;
     497            1 :             CATCH_REQUIRE(a == b);
     498           11 :             for(int idx(0); idx < 10; ++idx)
     499              :             {
     500           10 :                 b -= rand() % 0xFFFF;
     501           10 :                 CATCH_REQUIRE(a == b);
     502              : 
     503           10 :                 addr::addr c(b - rand() % 0xFFFF);
     504           10 :                 CATCH_REQUIRE(a == c);
     505           10 :             }
     506              : 
     507            1 :             __int128 diff(a - b);
     508            1 :             CATCH_REQUIRE(diff == 0_int128);
     509            1 :         }
     510            6 :         CATCH_END_SECTION();
     511              : 
     512            6 :         CATCH_START_SECTION("ipv6::address: parse the default IPv6 address \"[::]\" and \"::\"")
     513              :         {
     514            1 :             int proto[] = { IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP };
     515              : 
     516            1 :             CATCH_REQUIRE(a.ip_to_uint128() == 0_uint128);
     517              : 
     518              :             {
     519              :                 // we do not specify the protocol so we receive one response
     520              :                 // per protocol (TCP, UDP, and IP)
     521              :                 //
     522            1 :                 addr::addr_parser p;
     523            3 :                 addr::addr_range::vector_t ips(p.parse("[::]"));
     524            2 :                 CATCH_REQUIRE(ips.size() == std::size(proto));
     525              : 
     526              :                 // the IP address itself is ANY
     527              :                 // the protocol varies, however
     528              :                 //
     529            8 :                 for(std::size_t idx(0); idx < std::size(proto); ++idx)
     530              :                 {
     531            3 :                     CATCH_REQUIRE(ips[idx].has_from());
     532            3 :                     CATCH_REQUIRE_FALSE(ips[idx].has_to());
     533            3 :                     CATCH_REQUIRE(ips[idx].get_from() == a);
     534            3 :                     CATCH_REQUIRE(ips[idx].get_from().get_protocol() == proto[idx]);
     535              :                 }
     536            1 :             }
     537              : 
     538              :             {
     539            1 :                 addr::addr_parser p;
     540            3 :                 addr::addr_range::vector_t ips(p.parse("::"));
     541            2 :                 CATCH_REQUIRE(ips.size() == std::size(proto));
     542              : 
     543              :                 // the IP address itself is ANY
     544              :                 // the protocol varies, however
     545              :                 //
     546            8 :                 for(std::size_t idx(0); idx < std::size(proto); ++idx)
     547              :                 {
     548            3 :                     CATCH_REQUIRE(ips[idx].has_from());
     549            3 :                     CATCH_REQUIRE_FALSE(ips[idx].has_to());
     550            3 :                     CATCH_REQUIRE(ips[idx].get_from() == a);
     551            3 :                     CATCH_REQUIRE(ips[idx].get_from().get_protocol() == proto[idx]);
     552              :                 }
     553            1 :             }
     554              :         }
     555            6 :         CATCH_END_SECTION();
     556              : 
     557              : #pragma GCC diagnostic push
     558              : #pragma GCC diagnostic ignored "-Wpedantic"
     559            6 :         CATCH_START_SECTION("ipv6::address: verify last IPv6 address")
     560              :         {
     561            1 :             CATCH_REQUIRE(a.ip_to_uint128() == 0_uint128);
     562              : 
     563            1 :             struct sockaddr_in6 in6 = sockaddr_in6();
     564            1 :             in6.sin6_family = AF_INET6;
     565            1 :             in6.sin6_port = htons(rand());
     566            1 :             in6.sin6_addr.s6_addr32[0] = 0xFFFFFFFF;
     567            1 :             in6.sin6_addr.s6_addr32[1] = 0xFFFFFFFF;
     568            1 :             in6.sin6_addr.s6_addr32[2] = 0xFFFFFFFF;
     569            1 :             in6.sin6_addr.s6_addr32[3] = 0xFFFFFFFF;
     570            1 :             a.set_ipv6(in6);
     571              : 
     572              :             // any address is not the next/previous of itself, even "-1"
     573            1 :             CATCH_REQUIRE_FALSE(a.is_next(a));
     574            1 :             CATCH_REQUIRE_FALSE(a.is_previous(a));
     575              : 
     576              :             // last address +N is still the last address
     577              :             //
     578            1 :             addr::addr b(a);
     579            1 :             CATCH_REQUIRE(a == b);
     580            1 :             b++;
     581            1 :             CATCH_REQUIRE(a == b);
     582            1 :             ++b;
     583            1 :             CATCH_REQUIRE(a == b);
     584           11 :             for(int idx(0); idx < 10; ++idx)
     585              :             {
     586           10 :                 b += rand() % 0xFFFF;
     587           10 :                 CATCH_REQUIRE(a == b);
     588              : 
     589           10 :                 addr::addr c(b + rand() % 0xFFFF);
     590           10 :                 CATCH_REQUIRE(a == c);
     591           10 :             }
     592              : 
     593            1 :             __int128 diff(a - b);
     594            1 :             CATCH_REQUIRE(diff == 0_int128);
     595            1 :         }
     596            6 :         CATCH_END_SECTION();
     597              : #pragma GCC diagnostic pop
     598              : 
     599              : #pragma GCC diagnostic push
     600              : #pragma GCC diagnostic ignored "-Wpedantic"
     601            6 :         CATCH_START_SECTION("ipv6::address: set_ipv6() / get_ipv6()")
     602              :         {
     603           11 :             for(int idx(0); idx < 10; ++idx)
     604              :             {
     605           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
     606           10 :                 in6.sin6_family = AF_INET6;
     607           10 :                 in6.sin6_port = htons(rand());
     608           10 :                 in6.sin6_addr.s6_addr16[0] = rand();
     609           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
     610           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
     611           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
     612           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
     613           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
     614           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
     615           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
     616              : 
     617           10 :                 unsigned __int128 address(0_uint128);
     618           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 0]) << 120;
     619           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 1]) << 112;
     620           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 2]) << 104;
     621           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 3]) <<  96;
     622           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 4]) <<  88;
     623           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 5]) <<  80;
     624           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 6]) <<  72;
     625           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 7]) <<  64;
     626           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 8]) <<  56;
     627           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[ 9]) <<  48;
     628           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[10]) <<  40;
     629           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[11]) <<  32;
     630           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[12]) <<  24;
     631           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[13]) <<  16;
     632           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[14]) <<   8;
     633           10 :                 address |= static_cast<unsigned __int128>(in6.sin6_addr.s6_addr[15]) <<   0;
     634              : 
     635              :                 // set the address
     636              :                 //
     637           10 :                 a.set_ipv6(in6);
     638           10 :                 CATCH_REQUIRE(a.ip_to_uint128() == address);
     639              : 
     640              :                 // test constructor
     641              :                 //
     642           10 :                 addr::addr b(in6);
     643           10 :                 struct sockaddr_in6 out6;
     644           10 :                 b.get_ipv6(out6);
     645           10 :                 CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
     646              : 
     647              :                 // test set
     648              :                 //
     649           10 :                 a.set_ipv6(in6);
     650           10 :                 a.get_ipv6(out6);
     651           10 :                 CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
     652           10 :                 CATCH_REQUIRE(a.ip_to_uint128() == address);
     653              : 
     654           10 :                 struct sockaddr_in6 in6b = sockaddr_in6();
     655           10 :                 in6b.sin6_family = AF_INET6;
     656           10 :                 in6b.sin6_port = htons(rand());
     657           10 :                 in6b.sin6_addr.s6_addr16[0] = rand();
     658           10 :                 in6b.sin6_addr.s6_addr16[1] = rand();
     659           10 :                 in6b.sin6_addr.s6_addr16[2] = rand();
     660           10 :                 in6b.sin6_addr.s6_addr16[3] = rand();
     661           10 :                 in6b.sin6_addr.s6_addr16[4] = rand();
     662           10 :                 in6b.sin6_addr.s6_addr16[5] = rand();
     663           10 :                 in6b.sin6_addr.s6_addr16[6] = rand();
     664           10 :                 in6b.sin6_addr.s6_addr16[7] = rand();
     665              : 
     666           10 :                 unsigned __int128 new_address(0_uint128);
     667           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 0]) << 120;
     668           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 1]) << 112;
     669           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 2]) << 104;
     670           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 3]) <<  96;
     671           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 4]) <<  88;
     672           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 5]) <<  80;
     673           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 6]) <<  72;
     674           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 7]) <<  64;
     675           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 8]) <<  56;
     676           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[ 9]) <<  48;
     677           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[10]) <<  40;
     678           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[11]) <<  32;
     679           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[12]) <<  24;
     680           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[13]) <<  16;
     681           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[14]) <<   8;
     682           10 :                 new_address |= static_cast<unsigned __int128>(in6b.sin6_addr.s6_addr[15]) <<   0;
     683              : 
     684           10 :                 a.ip_from_uint128(new_address);
     685           10 :                 CATCH_REQUIRE(a.ip_to_uint128() == new_address);
     686              : 
     687           10 :                 if(new_address >= 10)
     688              :                 {
     689           10 :                     addr::addr const e(a + -10);
     690           10 :                     CATCH_REQUIRE(e.ip_to_uint128() == new_address - 10);
     691              : 
     692           10 :                     addr::addr f(a);
     693           10 :                     f += -10;
     694           10 :                     CATCH_REQUIRE(e.ip_to_uint128() == new_address - 10);
     695           10 :                 }
     696           10 :                 if(new_address <= 0xffffffffffffffffffffffffffffffff_uint128 - 10)
     697              :                 {
     698           10 :                     addr::addr const e(a - -10);
     699           10 :                     CATCH_REQUIRE(e.ip_to_uint128() == new_address + 10);
     700              : 
     701           10 :                     addr::addr f(a);
     702           10 :                     f -= -10;
     703           10 :                     CATCH_REQUIRE(e.ip_to_uint128() == new_address + 10);
     704           10 :                 }
     705              : 
     706           10 :                 struct sockaddr_in6 in6c(in6b);
     707           10 :                 for(int p(16); p > 0; )
     708              :                 {
     709           10 :                     --p;
     710           10 :                     ++in6c.sin6_addr.s6_addr[p];
     711           10 :                     if(in6c.sin6_addr.s6_addr[p] != 0)
     712              :                     {
     713           10 :                         break;
     714              :                     }
     715              :                 }
     716              : 
     717           10 :                 addr::addr const c(in6c);
     718           10 :                 CATCH_REQUIRE(a.is_next(c));
     719              : 
     720           10 :                 struct sockaddr_in6 in6d(in6b);
     721           10 :                 for(int p(16); p > 0; )
     722              :                 {
     723           10 :                     --p;
     724           10 :                     --in6d.sin6_addr.s6_addr[p];
     725           10 :                     if(in6d.sin6_addr.s6_addr[p] != 0xFF)
     726              :                     {
     727           10 :                         break;
     728              :                     }
     729              :                 }
     730              : 
     731           10 :                 addr::addr const d(in6d);
     732           10 :                 CATCH_REQUIRE(a.is_previous(d));
     733           10 :             }
     734              :         }
     735            6 :         CATCH_END_SECTION()
     736              : #pragma GCC diagnostic pop
     737              : 
     738            6 :         CATCH_START_SECTION("ipv6::address: set_ipv6() check to_ipv6_string()")
     739              :         {
     740              :             // this requires those locales to be installed
     741              :             // in my case, I install them all with:
     742              :             //
     743              :             //    sudo dpkg-reconfigure locales
     744              :             //    (and in the dialog, choose "Select All" to get everything)
     745              :             //
     746              :             // you can also do them one at a time
     747              :             //
     748              :             //    sudo locale-gen fr_FR.utf8
     749              :             //    sudo update-locale
     750              :             //
     751              :             // to see the list of locales you have defined use:
     752              :             //
     753              :             //    locale -a
     754              :             //
     755            1 :             std::vector<char const *> locales = {
     756              :                 "en_US.utf8",
     757              :                 "fr_FR.utf8",
     758              :                 "ja_JP.utf8",
     759              :                 "zh_SG.utf8",
     760            3 :             };
     761            5 :             for(auto const & l : locales)
     762              :             {
     763            4 :                 std::cout << "--- testing locale \"" << l << "\"" << std::endl;
     764            4 :                 std::locale const loc(l);
     765              : 
     766            4 :                 std::map<addr::string_ip_t, std::string> addr_vec;
     767            4 :                 addr::addr::vector_t addresses;
     768           44 :                 for(int idx(0); idx < 10; ++idx)
     769              :                 {
     770           40 :                     struct sockaddr_in6 in6 = sockaddr_in6();
     771           40 :                     in6.sin6_family = AF_INET6;
     772           40 :                     in6.sin6_port = htons(rand());
     773          360 :                     for(int j(0); j < 8; ++j)
     774              :                     {
     775              :                         // avoid any zeroes so that way we do not have
     776              :                         // to handle the "::" syntax
     777              :                         do
     778              :                         {
     779          320 :                             in6.sin6_addr.s6_addr16[j] = rand();
     780              :                         }
     781          320 :                         while(in6.sin6_addr.s6_addr16[j] == 0);
     782              :                     }
     783              : 
     784           40 :                     std::stringstream ip_buf;
     785           40 :                     ip_buf << std::hex
     786           40 :                            << ntohs(in6.sin6_addr.s6_addr16[0])
     787           40 :                            << ":"
     788           40 :                            << ntohs(in6.sin6_addr.s6_addr16[1])
     789           40 :                            << ":"
     790           40 :                            << ntohs(in6.sin6_addr.s6_addr16[2])
     791           40 :                            << ":"
     792           40 :                            << ntohs(in6.sin6_addr.s6_addr16[3])
     793           40 :                            << ":"
     794           40 :                            << ntohs(in6.sin6_addr.s6_addr16[4])
     795           40 :                            << ":"
     796           40 :                            << ntohs(in6.sin6_addr.s6_addr16[5])
     797           40 :                            << ":"
     798           40 :                            << ntohs(in6.sin6_addr.s6_addr16[6])
     799           40 :                            << ":"
     800           40 :                            << ntohs(in6.sin6_addr.s6_addr16[7]);
     801           40 :                     std::string const ip(ip_buf.str());
     802              : 
     803           40 :                     std::string port_str(std::to_string(static_cast<int>(htons(in6.sin6_port))));
     804              : 
     805              :                     // check IPv6 as a string
     806              :                     //
     807           40 :                     a.set_ipv6(in6);
     808           40 :                     addresses.push_back(a);
     809           40 :                     CATCH_REQUIRE(a.get_str_port() == port_str);
     810              :                     {
     811           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_ADDRESS));
     812           40 :                         if(addr_vec[addr::STRING_IP_ADDRESS] != std::string())
     813              :                         {
     814           36 :                             addr_vec[addr::STRING_IP_ADDRESS] += ",";
     815              :                         }
     816           40 :                         addr_vec[addr::STRING_IP_ADDRESS] += str;
     817           40 :                         CATCH_REQUIRE(str == ip);
     818           40 :                     }
     819              :                     {
     820           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS));
     821           40 :                         if(addr_vec[addr::STRING_IP_BRACKET_ADDRESS] != std::string())
     822              :                         {
     823           36 :                             addr_vec[addr::STRING_IP_BRACKET_ADDRESS] += ",";
     824              :                         }
     825           40 :                         addr_vec[addr::STRING_IP_BRACKET_ADDRESS] += str;
     826           40 :                         CATCH_REQUIRE(str == "[" + ip + "]");
     827           40 :                     }
     828              :                     {
     829           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT));
     830           40 :                         if(addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT] != std::string())
     831              :                         {
     832           36 :                             addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT] += ",";
     833              :                         }
     834           40 :                         addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT] += str;
     835           40 :                         CATCH_REQUIRE(str == "[" + ip + "]:" + port_str);
     836           40 :                     }
     837              :                     {
     838           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK));
     839           40 :                         if(addr_vec[addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK] != std::string())
     840              :                         {
     841           36 :                             addr_vec[addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK] += ",";
     842              :                         }
     843           40 :                         addr_vec[addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK] += str;
     844           40 :                         CATCH_REQUIRE(str == ip + "/128");
     845           40 :                     }
     846              :                     {
     847           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK));
     848           40 :                         if(addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK] != std::string())
     849              :                         {
     850           36 :                             addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK] += ",";
     851              :                         }
     852           40 :                         addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK] += str;
     853           40 :                         CATCH_REQUIRE(str == "[" + ip + "]/128");
     854           40 :                     }
     855              :                     {
     856           40 :                         std::string const str(a.to_ipv6_string(addr::STRING_IP_ALL));
     857           40 :                         if(addr_vec[addr::STRING_IP_ALL] != std::string())
     858              :                         {
     859           36 :                             addr_vec[addr::STRING_IP_ALL] += ",";
     860              :                         }
     861           40 :                         addr_vec[addr::STRING_IP_ALL] += str;
     862           40 :                         CATCH_REQUIRE(str == "[" + ip + "]:" + port_str + "/128");
     863           40 :                     }
     864              : 
     865              :                     // the ostream functions
     866              :                     {
     867           40 :                         std::stringstream ss;
     868           40 :                         ss << a; // mode defaults to ALL
     869           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]:" + port_str + "/128");
     870           40 :                     }
     871              :                     {
     872           40 :                         std::stringstream ss;
     873           40 :                         ss << addr::setaddrmode(addr::STRING_IP_ADDRESS) << a;
     874           40 :                         CATCH_REQUIRE(ss.str() == ip);
     875           40 :                     }
     876              :                     {
     877           40 :                         std::stringstream ss;
     878           40 :                         ss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS) << a;
     879           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]");
     880           40 :                     }
     881              :                     {
     882           40 :                         std::stringstream ss;
     883           40 :                         ss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT) << a;
     884           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]:" + port_str);
     885           40 :                     }
     886              :                     {
     887           40 :                         std::stringstream ss;
     888           40 :                         ss << addr::setaddrmode(addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK) << a;
     889           40 :                         CATCH_REQUIRE(ss.str() == ip + "/128");
     890           40 :                     }
     891              :                     {
     892           40 :                         std::stringstream ss;
     893           40 :                         ss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK) << a;
     894           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]/128");
     895           40 :                     }
     896              :                     {
     897           40 :                         std::stringstream ss;
     898           40 :                         ss << addr::setaddrmode(addr::STRING_IP_ALL) << a;
     899           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]:" + port_str + "/128");
     900           40 :                     }
     901              :                     {
     902           40 :                         std::stringstream ss;
     903           40 :                         ss << addr::setaddrmode(addr::STRING_IP_PORT);
     904           40 :                         ss.copyfmt(std::cout); // we did not change the mode of std::cout so here we expect STRING_IP_ALL after the copy
     905           40 :                         ss << a;
     906           40 :                         CATCH_REQUIRE(ss.str() == "[" + ip + "]:" + port_str + "/128");
     907           40 :                     }
     908              :                     {
     909           40 :                         std::stringstream sss;
     910           40 :                         std::stringstream ssd;
     911           40 :                         sss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT);
     912           40 :                         ssd << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS);
     913           40 :                         ssd.copyfmt(sss);
     914           40 :                         ssd << a;
     915           40 :                         CATCH_REQUIRE(ssd.str() == "[" + ip + "]:" + port_str);
     916           40 :                     }
     917           40 :                 }
     918              : 
     919              :                 {
     920            4 :                     std::stringstream ss;
     921            4 :                     ss << addresses;
     922            4 :                     ss.imbue(loc);
     923            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_ALL]);
     924            4 :                 }
     925              :                 {
     926            4 :                     std::stringstream ss;
     927            4 :                     ss.imbue(loc);
     928           12 :                     ss << addr::setaddrsep(" ");
     929            4 :                     ss.imbue(loc);
     930            4 :                     ss << addresses;
     931           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_ALL], {{",", " "}}));
     932            4 :                     CATCH_REQUIRE(ss.str() == expected);
     933            4 :                 }
     934              :                 {
     935            4 :                     std::stringstream ss;
     936            4 :                     ss << addr::setaddrmode(addr::STRING_IP_ADDRESS);
     937            4 :                     ss.imbue(loc);
     938            4 :                     ss << addresses;
     939            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_ADDRESS]);
     940            4 :                 }
     941              :                 {
     942            4 :                     std::stringstream ss;
     943           12 :                     ss << addr::setaddrsep("|") << addr::setaddrmode(addr::STRING_IP_ADDRESS) << addresses;
     944           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_ADDRESS], {{",", "|"}}));
     945            4 :                     CATCH_REQUIRE(ss.str() == expected);
     946            4 :                 }
     947              :                 {
     948            4 :                     std::stringstream ss;
     949            4 :                     ss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS) << addresses;
     950            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_BRACKET_ADDRESS]);
     951            4 :                 }
     952              :                 {
     953            4 :                     std::stringstream ss;
     954           12 :                     ss << addr::setaddrsep(";") << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS) << addresses;
     955           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_BRACKET_ADDRESS], {{",", ";"}}));
     956            4 :                     CATCH_REQUIRE(ss.str() == expected);
     957            4 :                 }
     958              :                 {
     959            4 :                     std::stringstream ss;
     960            4 :                     ss << addr::setaddrmode(addr::STRING_IP_ADDRESS | addr::STRING_IP_PORT) << addresses;
     961            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT]);
     962            4 :                 }
     963              :                 {
     964            4 :                     std::stringstream ss;
     965           12 :                     ss << addr::setaddrsep("+") << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT);
     966            4 :                     ss.imbue(loc);
     967            4 :                     ss << addresses;
     968           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT], {{",", "+"}}));
     969            4 :                     CATCH_REQUIRE(ss.str() == expected);
     970            4 :                 }
     971              :                 {
     972            4 :                     std::stringstream ss;
     973            4 :                     ss.imbue(loc);
     974            4 :                     ss << addr::setaddrmode(addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK) << addresses;
     975            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK]);
     976            4 :                 }
     977              :                 {
     978            4 :                     std::stringstream ss;
     979           12 :                     ss << addr::setaddrsep(", ") << addr::setaddrmode(addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK) << addresses;
     980           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_ADDRESS | addr::STRING_IP_MASK], {{",", ", "}}));
     981            4 :                     CATCH_REQUIRE(ss.str() == expected);
     982            4 :                 }
     983              :                 {
     984            4 :                     std::stringstream ss;
     985            4 :                     ss << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK) << addresses;
     986            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK]);
     987            4 :                 }
     988              :                 {
     989            4 :                     std::stringstream ss;
     990           12 :                     ss << addr::setaddrsep("$") << addr::setaddrmode(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK) << addresses;
     991           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_BRACKET_MASK], {{",", "$"}}));
     992            4 :                     CATCH_REQUIRE(ss.str() == expected);
     993            4 :                 }
     994              :                 {
     995            4 :                     std::stringstream ss;
     996            4 :                     ss << addr::setaddrmode(addr::STRING_IP_ALL);
     997            4 :                     ss.imbue(loc);
     998            4 :                     ss << addresses;
     999            4 :                     CATCH_REQUIRE(ss.str() == addr_vec[addr::STRING_IP_ALL]);
    1000            4 :                 }
    1001              :                 {
    1002            4 :                     std::stringstream ss;
    1003            4 :                     ss.imbue(loc);
    1004           12 :                     ss << addr::setaddrsep("\n") << addr::setaddrmode(addr::STRING_IP_ALL) << addresses;
    1005           16 :                     std::string const expected(snapdev::string_replace_many(addr_vec[addr::STRING_IP_ALL], {{",", "\n"}}));
    1006            4 :                     CATCH_REQUIRE(ss.str() == expected);
    1007            4 :                 }
    1008            4 :             }
    1009            1 :         }
    1010            6 :         CATCH_END_SECTION()
    1011              : 
    1012            6 :         CATCH_START_SECTION("ipv6::address: name of various IPs")
    1013              :         {
    1014            1 :             struct sockaddr_in6 in6 = sockaddr_in6();
    1015            1 :             in6.sin6_family = AF_INET6;
    1016            1 :             in6.sin6_port = htons(rand());
    1017              : 
    1018              :             // verify network type
    1019              :             //
    1020            1 :             a.set_ipv6(in6);
    1021            1 :             CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (TCP)
    1022              : 
    1023            1 :             a.set_protocol(IPPROTO_UDP);
    1024            1 :             CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (UDP)
    1025              : 
    1026            1 :             in6 = sockaddr_in6();
    1027            1 :             in6.sin6_family = AF_INET6;
    1028            1 :             in6.sin6_port = htons(rand());
    1029            1 :             in6.sin6_addr.s6_addr16[7] = htons(1);
    1030            1 :             a.set_ipv6(in6);
    1031            1 :             char hostname[HOST_NAME_MAX + 1];
    1032            1 :             hostname[HOST_NAME_MAX] = '\0';
    1033            1 :             CATCH_REQUIRE(gethostname(hostname, sizeof(hostname)) == 0);
    1034            1 :             CATCH_REQUIRE(hostname[0] != '\0');
    1035            1 :             std::string localhost(a.get_name());
    1036            1 :             bool const localhost_flag(localhost == hostname || localhost == "ip6-localhost");
    1037            1 :             CATCH_REQUIRE(localhost_flag);
    1038              : 
    1039            1 :             CATCH_REQUIRE(addr::find_addr_interface(a, false) != nullptr);
    1040            1 :         }
    1041            6 :         CATCH_END_SECTION()
    1042           32 :     }
    1043              : 
    1044           26 :     CATCH_GIVEN("addr_parser() with IPv6 addresses")
    1045              :     {
    1046            3 :         CATCH_START_SECTION("ipv6::address: verify basics")
    1047              :         {
    1048            1 :             addr::addr_parser p;
    1049            1 :             p.set_protocol(IPPROTO_TCP);
    1050            3 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
    1051            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1052            1 :             CATCH_REQUIRE(ips.size() == 1);
    1053            1 :             addr::addr_range const & r(ips[0]);
    1054            1 :             CATCH_REQUIRE(r.has_from());
    1055            1 :             CATCH_REQUIRE_FALSE(r.has_to());
    1056            1 :             CATCH_REQUIRE_FALSE(r.is_range());
    1057            1 :             CATCH_REQUIRE_FALSE(r.is_empty());
    1058            1 :             addr::addr f(r.get_from());
    1059            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    1060            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1061            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    1062            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ADDRESS) == "1:2:3:4:5:6:7:8");
    1063            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS) == "[1:2:3:4:5:6:7:8]");
    1064            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "1:2:3:4:5:6:7:8");
    1065            1 :             CATCH_REQUIRE(f.get_port() == 0);
    1066            1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1067            1 :             CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC);
    1068            1 :             CATCH_REQUIRE_FALSE(f.is_lan());
    1069            1 :             CATCH_REQUIRE_FALSE(f.is_lan(true));
    1070            1 :             CATCH_REQUIRE_FALSE(f.is_lan(false));
    1071            1 :             CATCH_REQUIRE(f.is_wan());
    1072            1 :             CATCH_REQUIRE(f.is_wan(true));
    1073            1 :             CATCH_REQUIRE(f.is_wan(false));
    1074            1 :             uint8_t mask[16] = {};
    1075            1 :             f.get_mask(mask);
    1076           17 :             for(int idx(0); idx < 16; ++idx)
    1077              :             {
    1078           16 :                 CATCH_REQUIRE(mask[idx] == 255);
    1079              :             }
    1080            1 :             CATCH_REQUIRE(f.get_mask_size() == 128);
    1081            1 :         }
    1082            3 :         CATCH_END_SECTION()
    1083              : 
    1084            3 :         CATCH_START_SECTION("ipv6::address: default address")
    1085              :         {
    1086            1 :             addr::addr_parser p;
    1087            1 :             p.set_protocol(IPPROTO_TCP);
    1088            3 :             p.set_default_address("5:5:5:5:5:5:5:5");
    1089            3 :             addr::addr_range::vector_t ips(p.parse(""));
    1090            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1091            1 :             CATCH_REQUIRE(ips.size() == 1);
    1092            1 :             addr::addr_range const & r(ips[0]);
    1093            1 :             CATCH_REQUIRE(r.has_from());
    1094            1 :             CATCH_REQUIRE_FALSE(r.has_to());
    1095            1 :             CATCH_REQUIRE_FALSE(r.is_range());
    1096            1 :             CATCH_REQUIRE_FALSE(r.is_empty());
    1097            1 :             addr::addr f(r.get_from());
    1098            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    1099            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1100            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    1101            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ADDRESS) == "5:5:5:5:5:5:5:5");
    1102            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS) == "[5:5:5:5:5:5:5:5]");
    1103            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "5:5:5:5:5:5:5:5");
    1104            1 :             CATCH_REQUIRE(f.get_port() == 0);
    1105            1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1106            1 :             CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC);
    1107            1 :             CATCH_REQUIRE_FALSE(f.is_lan());
    1108            1 :             CATCH_REQUIRE_FALSE(f.is_lan(true));
    1109            1 :             CATCH_REQUIRE_FALSE(f.is_lan(false));
    1110            1 :             CATCH_REQUIRE(f.is_wan());
    1111            1 :             CATCH_REQUIRE(f.is_wan(true));
    1112            1 :             CATCH_REQUIRE(f.is_wan(false));
    1113            1 :         }
    1114            3 :         CATCH_END_SECTION()
    1115              : 
    1116            3 :         CATCH_START_SECTION("ipv6::address: address, no port allowed")
    1117              :         {
    1118              :             // specific address with a default
    1119              :             {
    1120            1 :                 addr::addr_parser p;
    1121            1 :                 p.set_allow(addr::allow_t::ALLOW_PORT, false);
    1122            1 :                 p.set_protocol(IPPROTO_TCP);
    1123            3 :                 p.set_default_address("8:7:6:5:4:3:2:1");
    1124            3 :                 addr::addr_range::vector_t ips(p.parse("[9:9:9:9:4:3:2:1]"));
    1125            1 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1126            1 :                 CATCH_REQUIRE(ips.size() == 1);
    1127            1 :                 addr::addr_range const & r(ips[0]);
    1128            1 :                 CATCH_REQUIRE(r.has_from());
    1129            1 :                 CATCH_REQUIRE_FALSE(r.has_to());
    1130            1 :                 CATCH_REQUIRE_FALSE(r.is_range());
    1131            1 :                 CATCH_REQUIRE_FALSE(r.is_empty());
    1132            1 :                 addr::addr f(r.get_from());
    1133            1 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1134            1 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1135            1 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    1136            1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ADDRESS) == "9:9:9:9:4:3:2:1");
    1137            1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS) == "[9:9:9:9:4:3:2:1]");
    1138            1 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "9:9:9:9:4:3:2:1");
    1139            1 :                 CATCH_REQUIRE(f.get_port() == 0);
    1140            1 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1141            1 :                 CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC);
    1142            1 :                 CATCH_REQUIRE_FALSE(f.is_lan());
    1143            1 :                 CATCH_REQUIRE_FALSE(f.is_lan(true));
    1144            1 :                 CATCH_REQUIRE_FALSE(f.is_lan(false));
    1145            1 :                 CATCH_REQUIRE(f.is_wan());
    1146            1 :                 CATCH_REQUIRE(f.is_wan(true));
    1147            1 :                 CATCH_REQUIRE(f.is_wan(false));
    1148            1 :             }
    1149              : 
    1150              :             // only a default address
    1151              :             {
    1152            1 :                 addr::addr_parser p;
    1153            1 :                 p.set_allow(addr::allow_t::ALLOW_PORT, false);
    1154            1 :                 p.set_protocol(IPPROTO_TCP);
    1155            3 :                 p.set_default_address("5:1:6:2:7:3:8:4");
    1156            3 :                 addr::addr_range::vector_t ips(p.parse(""));
    1157            1 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1158            1 :                 CATCH_REQUIRE(ips.size() == 1);
    1159            1 :                 addr::addr_range const & r(ips[0]);
    1160            1 :                 CATCH_REQUIRE(r.has_from());
    1161            1 :                 CATCH_REQUIRE_FALSE(r.has_to());
    1162            1 :                 CATCH_REQUIRE_FALSE(r.is_range());
    1163            1 :                 CATCH_REQUIRE_FALSE(r.is_empty());
    1164            1 :                 addr::addr f(r.get_from());
    1165            1 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1166            1 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1167            1 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    1168            1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ADDRESS) == "5:1:6:2:7:3:8:4");
    1169            1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS) == "[5:1:6:2:7:3:8:4]");
    1170            1 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "5:1:6:2:7:3:8:4");
    1171            1 :                 CATCH_REQUIRE(f.get_port() == 0);
    1172            1 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1173            1 :                 CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC);
    1174            1 :                 CATCH_REQUIRE_FALSE(f.is_lan());
    1175            1 :                 CATCH_REQUIRE_FALSE(f.is_lan(true));
    1176            1 :                 CATCH_REQUIRE_FALSE(f.is_lan(false));
    1177            1 :                 CATCH_REQUIRE(f.is_wan());
    1178            1 :                 CATCH_REQUIRE(f.is_wan(true));
    1179            1 :                 CATCH_REQUIRE(f.is_wan(false));
    1180            1 :             }
    1181              :         }
    1182            3 :         CATCH_END_SECTION()
    1183           26 :     }
    1184              : 
    1185           26 :     CATCH_GIVEN("addr_parser() with numeric only IPv6 addresses")
    1186              :     {
    1187            3 :         CATCH_START_SECTION("ipv6::address: simple numeric IPv6")
    1188              :         {
    1189            1 :             addr::addr_parser p;
    1190            1 :             p.set_protocol(IPPROTO_TCP);
    1191            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_LOOKUP, false);
    1192            3 :             addr::addr_range::vector_t ips(p.parse("[4::f003:3001:20af]:5093"));
    1193            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1194            1 :             CATCH_REQUIRE(ips.size() == 1);
    1195              : 
    1196            1 :             addr::addr_range const & r(ips[0]);
    1197            1 :             CATCH_REQUIRE(r.has_from());
    1198            1 :             CATCH_REQUIRE_FALSE(r.has_to());
    1199            1 :             CATCH_REQUIRE_FALSE(r.is_range());
    1200            1 :             CATCH_REQUIRE_FALSE(r.is_empty());
    1201            1 :             addr::addr f(r.get_from());
    1202            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    1203            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1204            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    1205              :             // getting an IPv4 would throw, which is checked somewhere else
    1206              :             //CATCH_REQUIRE(f.to_ipv4_string(addr::STRING_IP_ADDRESS) == "");
    1207            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "4::f003:3001:20af");
    1208            1 :             CATCH_REQUIRE(f.get_port() == 5093);
    1209            1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1210            1 :             CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC);
    1211            1 :             CATCH_REQUIRE_FALSE(f.is_lan());
    1212            1 :             CATCH_REQUIRE_FALSE(f.is_lan(true));
    1213            1 :             CATCH_REQUIRE_FALSE(f.is_lan(false));
    1214            1 :             CATCH_REQUIRE(f.is_wan());
    1215            1 :             CATCH_REQUIRE(f.is_wan(true));
    1216            1 :             CATCH_REQUIRE(f.is_wan(false));
    1217            1 :             uint8_t mask[16] = {};
    1218            1 :             f.get_mask(mask);
    1219           17 :             for(int idx(0); idx < 16; ++idx)
    1220              :             {
    1221           16 :                 CATCH_REQUIRE(mask[idx] == 255);
    1222              :             }
    1223            1 :             CATCH_REQUIRE(f.get_mask_size() == 128);
    1224            1 :         }
    1225            3 :         CATCH_END_SECTION()
    1226              : 
    1227            3 :         CATCH_START_SECTION("ipv6::address: invalid IPv6 domain name address when we only accept numeric IPs")
    1228              :         {
    1229              :             // this is exactly the same path as the IPv4 test...
    1230              :             // if we have a named domain then IPv4 fails, IPv6 fails, then we err on it
    1231              :             //
    1232            1 :             addr::addr_parser p;
    1233            1 :             p.set_protocol(IPPROTO_TCP);
    1234            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_LOOKUP, false);
    1235            3 :             addr::addr_range::vector_t const ips(p.parse("ipv6.example.com:4471"));
    1236            1 :             CATCH_REQUIRE(p.has_errors());
    1237            1 :             CATCH_REQUIRE(p.error_count() == 1);
    1238            1 :             CATCH_REQUIRE(p.error_messages() == "Unknown address in \"ipv6.example.com\" (no DNS lookup was allowed).\n");
    1239            1 :             CATCH_REQUIRE(ips.size() == 0);
    1240            1 :         }
    1241            3 :         CATCH_END_SECTION()
    1242              : 
    1243            3 :         CATCH_START_SECTION("ipv6::address: invalid IPv6 domain name address when we only accept numeric IPs")
    1244              :         {
    1245              :             // this is exactly the same path as the IPv4 test...
    1246              :             // if we have a named domain then IPv4 fails, IPv6 fails, then we err on it
    1247              :             //
    1248            1 :             addr::addr_parser p;
    1249            1 :             p.set_protocol(IPPROTO_TCP);
    1250            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_LOOKUP, false);
    1251            1 :             p.set_allow(addr::allow_t::ALLOW_PORT, false);
    1252            1 :             p.set_default_port(4471);
    1253            3 :             addr::addr_range::vector_t const ips(p.parse("[f801::31]"));
    1254            1 :             CATCH_REQUIRE(p.has_errors());
    1255            1 :             CATCH_REQUIRE(p.error_count() == 1);
    1256            1 :             CATCH_REQUIRE(p.error_messages() == "Found a port (\"4471\") when it is not allowed.\n");
    1257            1 :             CATCH_REQUIRE(ips.size() == 0);
    1258            1 :         }
    1259            3 :         CATCH_END_SECTION()
    1260           26 :     }
    1261              : 
    1262           26 :     CATCH_GIVEN("ipv6::address: a set of IPs and a sort")
    1263              :     {
    1264           27 :         std::string const ip_list("7::-3::,10.0.0.32,192.168.2.15-192.168.2.23,::,5.8.9.11,f801::5553,192.168.2.1-192.168.2.14,::3000-::2000");
    1265            9 :         addr::addr_parser p;
    1266            9 :         p.set_protocol(IPPROTO_TCP);
    1267            9 :         p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_COMMAS, true);
    1268            9 :         p.set_allow(addr::allow_t::ALLOW_ADDRESS_RANGE, true);
    1269            9 :         CATCH_REQUIRE(p.get_sort_order() == addr::SORT_NO);
    1270              : 
    1271            9 :         CATCH_START_SECTION("ipv6::address: parse and no sort")
    1272              :         {
    1273            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1274              : 
    1275            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1276            1 :             CATCH_REQUIRE(ips.size() == 8);
    1277            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1278            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1279            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.15-192.168.2.23");
    1280            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "::");
    1281            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1282            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1283            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1284            1 :             CATCH_REQUIRE(ips[7].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1285            1 :         }
    1286            9 :         CATCH_END_SECTION()
    1287              : 
    1288            9 :         CATCH_START_SECTION("ipv6::address: parse and ignore empty")
    1289              :         {
    1290            1 :             addr::sort_t const order(addr::SORT_NO_EMPTY);
    1291            1 :             p.set_sort_order(order);
    1292            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1293            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1294              : 
    1295            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1296            1 :             CATCH_REQUIRE(ips.size() == 6);
    1297            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1298            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.15-192.168.2.23");
    1299            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "::");
    1300            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1301            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1302            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1303            1 :         }
    1304            9 :         CATCH_END_SECTION()
    1305              : 
    1306            9 :         CATCH_START_SECTION("ipv6::address: parse and full sort")
    1307              :         {
    1308            1 :             addr::sort_t const order(addr::SORT_FULL);
    1309            1 :             p.set_sort_order(order);
    1310            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1311            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1312              : 
    1313            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1314            1 :             CATCH_REQUIRE(ips.size() == 8);
    1315            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::");
    1316            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1317            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1318            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1319            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.15-192.168.2.23");
    1320            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1321            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1322            1 :             CATCH_REQUIRE(ips[7].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1323            1 :         }
    1324            9 :         CATCH_END_SECTION()
    1325              : 
    1326            9 :         CATCH_START_SECTION("ipv6::address: parse and put IPv6 addresses first")
    1327              :         {
    1328            1 :             addr::sort_t const order(addr::SORT_IPV6_FIRST);
    1329            1 :             p.set_sort_order(order);
    1330            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1331            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1332              : 
    1333            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1334            1 :             CATCH_REQUIRE(ips.size() == 8);
    1335            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::");
    1336            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1337            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1338            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.15-192.168.2.23");
    1339            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1340            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1341            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1342            1 :             CATCH_REQUIRE(ips[7].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1343            1 :         }
    1344            9 :         CATCH_END_SECTION()
    1345              : 
    1346            9 :         CATCH_START_SECTION("ipv6::address: parse and put IPv4 addresses first")
    1347              :         {
    1348            1 :             addr::sort_t const order(addr::SORT_IPV4_FIRST);
    1349            1 :             p.set_sort_order(order);
    1350            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1351            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1352              : 
    1353            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1354            1 :             CATCH_REQUIRE(ips.size() == 8);
    1355            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1356            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.15-192.168.2.23");
    1357            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1358            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1359            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "::");
    1360            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1361            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1362            1 :             CATCH_REQUIRE(ips[7].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1363            1 :         }
    1364            9 :         CATCH_END_SECTION()
    1365              : 
    1366            9 :         CATCH_START_SECTION("ipv6::address: parse, sort, and merge")
    1367              :         {
    1368            1 :             addr::sort_t const order(addr::SORT_MERGE);
    1369            1 :             p.set_sort_order(order);
    1370            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1371            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1372              : 
    1373            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1374            1 :             CATCH_REQUIRE(ips.size() == 7);
    1375            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::");
    1376            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1377            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1378            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.23");
    1379            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1380            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1381            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1382            1 :         }
    1383            9 :         CATCH_END_SECTION()
    1384              : 
    1385            9 :         CATCH_START_SECTION("ipv6::address: parse, sort, merge, and put IPv4 first")
    1386              :         {
    1387            1 :             addr::sort_t const order(addr::SORT_MERGE | addr::SORT_IPV4_FIRST);
    1388            1 :             p.set_sort_order(order);
    1389            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1390            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1391              : 
    1392            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1393            1 :             CATCH_REQUIRE(ips.size() == 7);
    1394            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1395            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1396            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.23");
    1397            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "::");
    1398            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1399            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1400            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1401            1 :         }
    1402            9 :         CATCH_END_SECTION()
    1403              : 
    1404            9 :         CATCH_START_SECTION("ipv6::address: parse, sort, merge, and put IPv6 first")
    1405              :         {
    1406            1 :             addr::sort_t const order(addr::SORT_MERGE | addr::SORT_IPV6_FIRST);
    1407            1 :             p.set_sort_order(order);
    1408            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1409            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1410              : 
    1411            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1412            1 :             CATCH_REQUIRE(ips.size() == 7);
    1413            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::");
    1414            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1415            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1416            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1417            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.23");
    1418            1 :             CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1419            1 :             CATCH_REQUIRE(ips[6].to_string(addr::STRING_IP_ADDRESS) == "<empty address range>");
    1420            1 :         }
    1421            9 :         CATCH_END_SECTION()
    1422              : 
    1423            9 :         CATCH_START_SECTION("ipv6::address: parse, sort, merge, and put IPv6 first")
    1424              :         {
    1425              :             // this is the one we expect most users to make use of to
    1426              :             //   1. ignore empty entries (useless)
    1427              :             //   2. merge when possible to reduce the number of items
    1428              :             //   3. handle IPv6 first, then try IPv4 is any available
    1429              :             //
    1430            1 :             addr::sort_t const order(addr::SORT_NO_EMPTY | addr::SORT_MERGE | addr::SORT_IPV6_FIRST);
    1431            1 :             p.set_sort_order(order);
    1432            1 :             CATCH_REQUIRE(p.get_sort_order() == order);
    1433            1 :             addr::addr_range::vector_t const ips(p.parse(ip_list));
    1434              : 
    1435            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1436            1 :             CATCH_REQUIRE(ips.size() == 5);
    1437            1 :             CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::");
    1438            1 :             CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1439            1 :             CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "5.8.9.11");
    1440            1 :             CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "10.0.0.32");
    1441            1 :             CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.23");
    1442            1 :         }
    1443            9 :         CATCH_END_SECTION()
    1444           35 :     }
    1445              : 
    1446           26 :     CATCH_START_SECTION("ipv6::address: one side ranges")
    1447              :     {
    1448            1 :         addr::addr_parser p;
    1449            1 :         p.set_protocol(IPPROTO_TCP);
    1450            1 :         p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_COMMAS, true);
    1451            1 :         p.set_allow(addr::allow_t::ALLOW_ADDRESS_RANGE, true);
    1452              : 
    1453            3 :         std::string const ip_list("-::1,-10.0.0.32,f801::5553-,192.168.2.1-");
    1454            1 :         addr::addr_range::vector_t const ips(p.parse(ip_list));
    1455              : 
    1456            1 :         CATCH_REQUIRE_FALSE(p.has_errors());
    1457            1 :         CATCH_REQUIRE(ips.size() == 4);
    1458            1 :         CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "-::1");
    1459            1 :         CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "-10.0.0.32");
    1460            1 :         CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "f801::5553");
    1461            1 :         CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1");
    1462            1 :     }
    1463           26 :     CATCH_END_SECTION()
    1464              : 
    1465           26 :     CATCH_START_SECTION("ipv6::address: test invalid sort (IPv4 vs IPv6)")
    1466              :     {
    1467            1 :         addr::addr_parser p;
    1468              : 
    1469              :         // set something valid
    1470              :         //
    1471            1 :         addr::sort_t const order(addr::SORT_NO_EMPTY);
    1472            1 :         p.set_sort_order(order);
    1473            1 :         CATCH_REQUIRE(p.get_sort_order() == order);
    1474              : 
    1475              :         // try to set something invalid
    1476              :         //
    1477            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1478              :                   p.set_sort_order(addr::SORT_IPV6_FIRST | addr::SORT_IPV4_FIRST)
    1479              :                 , addr::addr_invalid_argument
    1480              :                 , Catch::Matchers::ExceptionMessage(
    1481              :                           "addr_error: addr_parser::set_sort_order(): flags SORT_IPV6_FIRST and SORT_IPV4_FIRST are mutually exclusive."));
    1482              : 
    1483              :         // verify that the invalid attempt did not change anything
    1484              :         //
    1485            1 :         CATCH_REQUIRE(p.get_sort_order() == order);
    1486            1 :     }
    1487           26 :     CATCH_END_SECTION()
    1488              : 
    1489           26 :     CATCH_START_SECTION("ipv6::address: parse & sort multi-address separated by '\\n' with '#' comments")
    1490              :     {
    1491            1 :         addr::addr_parser p;
    1492            1 :         p.set_protocol(IPPROTO_TCP);
    1493            1 :         p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_NEWLINES, true);
    1494            1 :         p.set_allow(addr::allow_t::ALLOW_ADDRESS_RANGE, true);
    1495            1 :         p.set_allow(addr::allow_t::ALLOW_COMMENT_HASH, true);
    1496              : 
    1497            1 :         CATCH_REQUIRE(p.get_sort_order() == addr::SORT_NO); // verify default
    1498            1 :         addr::sort_t const order(addr::SORT_NO_EMPTY | addr::SORT_MERGE | addr::SORT_IPV6_FIRST);
    1499            1 :         p.set_sort_order(order);
    1500            1 :         CATCH_REQUIRE(p.get_sort_order() == order);
    1501              : 
    1502            1 :         std::string const ip_list(
    1503              :                 "9::-a::\n"
    1504              :                 "10.1.0.32\n"
    1505              :                 "192.168.2.23-192.168.2.18\n"
    1506              :                 "#0:0:300f:f00f:3355::3\n"  // commented
    1507              :                 "::1\n"
    1508              :                 "25.8.9.11\n\n"             // extra empty line
    1509              :                 "f801::3332\n"
    1510              :                 "192.168.2.1-192.168.2.14\n"
    1511              :                 "-:45\n"                    // for a range, at least one IP is required
    1512              :                 "a::1-b::3\n\n"             // extra empty line at the end too
    1513            3 :                 "# an actual comment\n");
    1514            1 :         addr::addr_range::vector_t const ips(p.parse(ip_list));
    1515              : 
    1516              :         // note that even though we had errors, the valid IP entries
    1517              :         // appear in the ips vector and we can test them
    1518              :         //
    1519            1 :         CATCH_REQUIRE(p.has_errors());
    1520            1 :         CATCH_REQUIRE(p.error_messages() == "An address range requires at least one of the \"from\" or \"to\" addresses.\n");
    1521              : 
    1522            1 :         CATCH_REQUIRE(ips.size() == 6);
    1523            1 :         CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::1");
    1524            1 :         CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "9::-b::3");
    1525            1 :         CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "f801::3332");
    1526            1 :         CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "10.1.0.32");
    1527            1 :         CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "25.8.9.11");
    1528            1 :         CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1529            1 :     }
    1530           26 :     CATCH_END_SECTION()
    1531              : 
    1532           26 :     CATCH_START_SECTION("ipv6::address: parse & sort multi-address separated by '\\n' with ';' comments")
    1533              :     {
    1534            1 :         addr::addr_parser p;
    1535            1 :         p.set_protocol(IPPROTO_TCP);
    1536            1 :         p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_NEWLINES, true);
    1537            1 :         p.set_allow(addr::allow_t::ALLOW_ADDRESS_RANGE, true);
    1538            1 :         p.set_allow(addr::allow_t::ALLOW_COMMENT_SEMICOLON, true);
    1539              : 
    1540            1 :         CATCH_REQUIRE(p.get_sort_order() == addr::SORT_NO); // verify default
    1541            1 :         addr::sort_t const order(addr::SORT_NO_EMPTY | addr::SORT_MERGE | addr::SORT_IPV6_FIRST);
    1542            1 :         p.set_sort_order(order);
    1543            1 :         CATCH_REQUIRE(p.get_sort_order() == order);
    1544              : 
    1545            1 :         std::string const ip_list(
    1546              :                 "; list of IPs\n"
    1547              :                 "9::-a::\n"
    1548              :                 "10.1.0.32\n"
    1549              :                 "192.168.2.23-192.168.2.18\n"
    1550              :                 ";0:0:300f:f00f:3355::3\n"  // commented
    1551              :                 "::1\n"
    1552              :                 "25.8.9.11\n\n"             // extra empty line
    1553              :                 "f801::3332\n"
    1554              :                 "192.168.2.1-192.168.2.14\n"
    1555              :                 "-:45\n"                    // for a range, at least one IP is required
    1556            3 :                 "a::1-b::3\n\n");           // extra empty line at the end too
    1557            1 :         addr::addr_range::vector_t const ips(p.parse(ip_list));
    1558              : 
    1559              :         // note that even though we had errors, the valid IP entries
    1560              :         // appear in the ips vector and we can test them
    1561              :         //
    1562            1 :         CATCH_REQUIRE(p.has_errors());
    1563            1 :         CATCH_REQUIRE(p.error_messages() == "An address range requires at least one of the \"from\" or \"to\" addresses.\n");
    1564              : 
    1565            1 :         CATCH_REQUIRE(ips.size() == 6);
    1566            1 :         CATCH_REQUIRE(ips[0].to_string(addr::STRING_IP_ADDRESS) == "::1");
    1567            1 :         CATCH_REQUIRE(ips[1].to_string(addr::STRING_IP_ADDRESS) == "9::-b::3");
    1568            1 :         CATCH_REQUIRE(ips[2].to_string(addr::STRING_IP_ADDRESS) == "f801::3332");
    1569            1 :         CATCH_REQUIRE(ips[3].to_string(addr::STRING_IP_ADDRESS) == "10.1.0.32");
    1570            1 :         CATCH_REQUIRE(ips[4].to_string(addr::STRING_IP_ADDRESS) == "25.8.9.11");
    1571            1 :         CATCH_REQUIRE(ips[5].to_string(addr::STRING_IP_ADDRESS) == "192.168.2.1-192.168.2.14");
    1572            1 :     }
    1573           26 :     CATCH_END_SECTION()
    1574              : 
    1575           26 :     CATCH_START_SECTION("ipv6::address: parse invalid range (unknown domain name)")
    1576              :     {
    1577            1 :         addr::addr_parser p;
    1578            1 :         p.set_protocol(IPPROTO_TCP);
    1579            1 :         p.set_allow(addr::allow_t::ALLOW_ADDRESS_RANGE, true);
    1580              : 
    1581              : // the ::1 address in /etc/hosts used to also be named "localhost"; so we
    1582              : // were testing a system bug... [the error is still happening if we do not
    1583              : // set the protocol, although that was not the purpose of this test and
    1584              : // now we ignore the different protocols in a parsed range]
    1585              : //
    1586              : //        addr::addr_range::vector_t const ips1(p.parse("localhost-:45"));
    1587              : //std::cerr << "got localhost as just one IP?! [" << ips1 << "]\n";
    1588              : //
    1589              : //        CATCH_REQUIRE(p.has_errors());
    1590              : //        CATCH_REQUIRE(p.error_messages() == "The \"from\" of an address range must be exactly one address.\n");
    1591              : //
    1592              : //        CATCH_REQUIRE(ips1.empty());
    1593              : //
    1594              : //        p.clear_errors();
    1595              : //        addr::addr_range::vector_t const ips2(p.parse("-localhost:45"));
    1596              : //
    1597              : //        CATCH_REQUIRE(p.has_errors());
    1598              : //        CATCH_REQUIRE(p.error_messages() == "The \"to\" of an address range must be exactly one address.\n");
    1599              : //
    1600              : //        CATCH_REQUIRE(ips2.empty());
    1601              : //
    1602              : //        p.clear_errors();
    1603            3 :         addr::addr_range::vector_t const ips3(p.parse("invalid.from-:45"));
    1604              : 
    1605            1 :         CATCH_REQUIRE(p.has_errors());
    1606              :         bool expected(
    1607            1 :                p.error_messages() == "Invalid address in \"invalid.from:45\" error -2 -- Name or service not known (errno: 22 -- Invalid argument).\n"
    1608            1 :             || p.error_messages() == "Invalid address in \"invalid.from:45\" error -2 -- Name or service not known (errno: 6 -- No such device or address).\n");
    1609            1 :         CATCH_REQUIRE(expected);
    1610              : 
    1611            1 :         CATCH_REQUIRE(ips3.empty());
    1612              : 
    1613              :         // .to is a valid TLD (Tonga) so here I use .tom instead
    1614              :         //
    1615            1 :         p.clear_errors();
    1616            3 :         addr::addr_range::vector_t const ips4(p.parse("-invalid.tom:45"));
    1617              : 
    1618            1 :         CATCH_REQUIRE(p.has_errors());
    1619            1 :         expected =
    1620            1 :                p.error_messages() == "Invalid address in \"invalid.tom:45\" error -2 -- Name or service not known (errno: 22 -- Invalid argument).\n"
    1621            1 :             || p.error_messages() == "Invalid address in \"invalid.tom:45\" error -2 -- Name or service not known (errno: 6 -- No such device or address).\n";
    1622            1 :         CATCH_REQUIRE(expected);
    1623              : 
    1624            1 :         CATCH_REQUIRE(ips4.empty());
    1625            1 :     }
    1626           26 :     CATCH_END_SECTION()
    1627           54 : }
    1628              : 
    1629              : 
    1630           10 : CATCH_TEST_CASE("ipv6::ports", "[ipv6]")
    1631              : {
    1632           10 :     CATCH_START_SECTION("ipv6::addr: verify port names")
    1633              :     {
    1634              :         // test a few ports that we know are and are not defined in /etc/services
    1635              :         //
    1636            1 :         addr::addr a;
    1637              : 
    1638            1 :         struct sockaddr_in6 in6 = sockaddr_in6();
    1639            1 :         in6.sin6_family = AF_INET6;
    1640            1 :         in6.sin6_port = htons(rand());
    1641              :         do
    1642              :         {
    1643            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[0]);
    1644            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[1]);
    1645            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[2]);
    1646            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[3]);
    1647            1 :             a.set_ipv6(in6);
    1648              :         }
    1649            1 :         while(!a.is_valid() || a.is_ipv4());
    1650            1 :         CATCH_REQUIRE(!a.is_ipv4());
    1651              : 
    1652              :         struct port_name_t
    1653              :         {
    1654              :             int             f_port = 0;
    1655              :             char const *    f_name = nullptr;
    1656              :         };
    1657            1 :         port_name_t names[] = {
    1658              :             { 21, "ftp" },
    1659              :             { 22, "ssh" },
    1660              :             { 23, "telnet" },
    1661              :             { 80, "http" },
    1662              :             { 443, "https" },
    1663              :             { 4004, "" },
    1664              :         };
    1665              : 
    1666            7 :         for(auto n : names)
    1667              :         {
    1668            6 :             a.set_port(n.f_port);
    1669            6 :             CATCH_REQUIRE(a.get_port_name() == n.f_name);
    1670              :         }
    1671            1 :     }
    1672           10 :     CATCH_END_SECTION()
    1673              : 
    1674           10 :     CATCH_START_SECTION("ipv6::addr: verify protocol names")
    1675              :     {
    1676              :         // test a few ports that we know are and are not defined in /etc/services
    1677              :         //
    1678            1 :         addr::addr a;
    1679              : 
    1680            1 :         struct sockaddr_in6 in6 = sockaddr_in6();
    1681            1 :         in6.sin6_family = AF_INET6;
    1682            1 :         in6.sin6_port = htons(rand());
    1683              :         do
    1684              :         {
    1685            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[0]);
    1686            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[1]);
    1687            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[2]);
    1688            1 :             SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[3]);
    1689            1 :             a.set_ipv6(in6);
    1690              :         }
    1691            1 :         while(!a.is_valid() || a.is_ipv4());
    1692            1 :         CATCH_REQUIRE(!a.is_ipv4());
    1693              : 
    1694              :         struct protocol_name_t
    1695              :         {
    1696              :             int             f_protocol = 0;
    1697              :             char const *    f_name = nullptr;
    1698              :         };
    1699            1 :         protocol_name_t names[] = {
    1700              :             { 0, "ip" },
    1701              :             { 6, "tcp" },
    1702              :             { 17, "udp" },
    1703              :         };
    1704              : 
    1705            4 :         for(auto n : names)
    1706              :         {
    1707            3 :             a.set_protocol(n.f_protocol);
    1708            3 :             CATCH_REQUIRE(a.get_protocol_name() == n.f_name);
    1709              :         }
    1710              : 
    1711            4 :         for(auto n : names)
    1712              :         {
    1713            3 :             a.set_protocol(n.f_name);
    1714            3 :             CATCH_REQUIRE(a.get_protocol() == n.f_protocol);
    1715            3 :             CATCH_REQUIRE(a.get_protocol_name() == n.f_name);
    1716              :         }
    1717            1 :     }
    1718           10 :     CATCH_END_SECTION()
    1719              : 
    1720              :     // by default addr() is an IPv6 address so we test the basic port
    1721              :     // functions here, although it could be in a common place instead...
    1722              :     //
    1723           10 :     CATCH_GIVEN("addr()")
    1724              :     {
    1725            4 :         addr::addr a;
    1726              : 
    1727            4 :         CATCH_START_SECTION("ipv6::ports: default port")
    1728              :         {
    1729            1 :             CATCH_REQUIRE_FALSE(a.is_port_defined());
    1730            1 :             CATCH_REQUIRE(a.get_port() == 0);
    1731              : 
    1732            1 :             CATCH_REQUIRE_FALSE(a.is_protocol_defined());
    1733            1 :             CATCH_REQUIRE(a.get_protocol() == IPPROTO_TCP);
    1734              :         }
    1735            4 :         CATCH_END_SECTION()
    1736              : 
    1737            4 :         CATCH_START_SECTION("ipv6::ports: named ports")
    1738              :         {
    1739            1 :             CATCH_REQUIRE(a.set_port("ftp"));
    1740            1 :             CATCH_REQUIRE(a.get_port() == 21);
    1741            1 :             CATCH_REQUIRE(a.set_port("ssh"));
    1742            1 :             CATCH_REQUIRE(a.get_port() == 22);
    1743            1 :             CATCH_REQUIRE(a.set_port("http"));
    1744            1 :             CATCH_REQUIRE(a.get_port() == 80);
    1745            1 :             CATCH_REQUIRE(a.set_port("https"));
    1746            1 :             CATCH_REQUIRE(a.get_port() == 443);
    1747              : 
    1748              :             // and a couple of invalid ones
    1749              :             //
    1750            1 :             CATCH_REQUIRE_FALSE(a.set_port("invalid"));
    1751            1 :             CATCH_REQUIRE(a.get_port() == 443); // port not updated
    1752            1 :             CATCH_REQUIRE_FALSE(a.set_port("32.5"));
    1753            1 :             CATCH_REQUIRE(a.get_port() == 443); // port not updated
    1754              :         }
    1755            4 :         CATCH_END_SECTION()
    1756              : 
    1757            4 :         CATCH_START_SECTION("ipv6::ports: set_port()")
    1758              :         {
    1759              :             // setup a valid random port to start with
    1760              :             //
    1761            1 :             int const start_port(rand() & 0xFFFF);
    1762            1 :             a.set_port(start_port);
    1763            1 :             CATCH_REQUIRE(a.is_port_defined());
    1764              : 
    1765              :             // try again with a string
    1766              :             //
    1767            1 :             a.set_port(std::to_string(start_port).c_str());
    1768            1 :             CATCH_REQUIRE(a.get_port() == start_port);
    1769              : 
    1770              :             // test 100 invalid ports
    1771              :             //
    1772          101 :             for(int idx(0); idx < 100; ++idx)
    1773              :             {
    1774              :                 // first try a negative port
    1775              :                 //
    1776              :                 int port_too_small;
    1777              :                 do
    1778              :                 {
    1779          100 :                     port_too_small = -(rand() & 0xFFFF);
    1780              :                 }
    1781          100 :                 while(port_too_small == 0);
    1782          100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_small), addr::addr_invalid_argument);
    1783              : 
    1784              :                 // second try too large a port
    1785              :                 //
    1786          100 :                 int const port_too_large = (rand() & 0xFFFF) + 65536;
    1787          100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_large), addr::addr_invalid_argument);
    1788              : 
    1789              :                 // make sure port does not get modified on errors
    1790              :                 //
    1791          100 :                 CATCH_REQUIRE(a.get_port() == start_port);
    1792              :             }
    1793              : 
    1794              :             // test all ports
    1795              :             //
    1796        65537 :             for(int port(0); port < 65536; ++port)
    1797              :             {
    1798        65536 :                 a.set_port(port);
    1799              : 
    1800        65536 :                 CATCH_REQUIRE(a.get_port() == port);
    1801              :             }
    1802              :         }
    1803            4 :         CATCH_END_SECTION()
    1804              : 
    1805            4 :         CATCH_START_SECTION("ipv6::ports: known ports to test get_service()")
    1806              :         {
    1807              :             // the default is TCP, but it's considered undefined
    1808              :             //
    1809            1 :             CATCH_REQUIRE_FALSE(a.is_protocol_defined());
    1810              : 
    1811            1 :             a.set_port(80);
    1812            1 :             CATCH_REQUIRE(a.get_service() == "http");
    1813              : 
    1814            1 :             a.set_port(443);
    1815            1 :             CATCH_REQUIRE(a.get_service() == "https");
    1816              : 
    1817              :             // again with UDP
    1818              :             // 
    1819            1 :             CATCH_REQUIRE_FALSE(a.is_protocol_defined());
    1820            1 :             a.set_protocol(IPPROTO_UDP);
    1821            1 :             CATCH_REQUIRE(a.is_protocol_defined());
    1822              : 
    1823            1 :             a.set_port(80);
    1824            1 :             std::string service(a.get_service());
    1825            1 :             CATCH_REQUIRE((service == "http" || service == "80"));
    1826              : 
    1827            1 :             a.set_port(443);
    1828            1 :             service = a.get_service();
    1829            1 :             CATCH_REQUIRE((service == "https"|| service == "443"));
    1830              : 
    1831              :             // to change the default we offer the user to mark the protocol as undefined
    1832              :             //
    1833            1 :             CATCH_REQUIRE(a.is_protocol_defined());
    1834            1 :             a.set_protocol_defined(false);
    1835            1 :             CATCH_REQUIRE_FALSE(a.is_protocol_defined());
    1836            1 :             a.set_protocol_defined(true);
    1837            1 :             CATCH_REQUIRE(a.is_protocol_defined());
    1838            1 :         }
    1839            4 :         CATCH_END_SECTION()
    1840           14 :     }
    1841              : 
    1842           10 :     CATCH_GIVEN("addr_parser() with IPv6 addresses and port")
    1843              :     {
    1844            4 :         CATCH_START_SECTION("ipv6::ports: verify port by parser")
    1845              :         {
    1846        65537 :             for(int port(0); port < 65536; ++port)
    1847              :             {
    1848        65536 :                 int proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1849        65536 :                 addr::addr_parser p;
    1850        65536 :                 p.set_protocol(proto);
    1851        65536 :                 addr::addr_range::vector_t ips(p.parse("[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port)));
    1852        65536 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1853        65536 :                 CATCH_REQUIRE(ips.size() == 1);
    1854        65536 :                 addr::addr_range const & r(ips[0]);
    1855        65536 :                 addr::addr f(r.get_from());
    1856        65536 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1857        65536 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1858        65536 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    1859        65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ADDRESS) == "ff01:2f3:f041:e301:f:10:11:12");
    1860        65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS) == "[ff01:2f3:f041:e301:f:10:11:12]");
    1861        65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
    1862        65536 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
    1863        65536 :                 CATCH_REQUIRE(f.get_port() == port);
    1864        65536 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1865        65536 :                 CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1866        65536 :                 CATCH_REQUIRE(f.is_lan());
    1867        65536 :                 CATCH_REQUIRE(f.is_lan(true));
    1868        65536 :                 CATCH_REQUIRE(f.is_lan(false));
    1869        65536 :                 CATCH_REQUIRE_FALSE(f.is_wan());
    1870        65536 :                 CATCH_REQUIRE_FALSE(f.is_wan(true));
    1871        65536 :                 CATCH_REQUIRE_FALSE(f.is_wan(false));
    1872        65536 :             }
    1873              :         }
    1874            4 :         CATCH_END_SECTION()
    1875              : 
    1876            4 :         CATCH_START_SECTION("ipv6::port: default address with various port")
    1877              :         {
    1878          101 :             for(int idx(0); idx < 100; ++idx)
    1879              :             {
    1880          100 :                 uint16_t const port(rand());
    1881          100 :                 addr::addr_parser p;
    1882          100 :                 p.set_protocol(IPPROTO_TCP);
    1883          300 :                 p.set_default_address("ff02:23:f41:e31:20:30:40:50");
    1884          100 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(static_cast<int>(port))));
    1885          100 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1886          100 :                 CATCH_REQUIRE(ips.size() == 1);
    1887          100 :                 addr::addr_range const & r(ips[0]);
    1888          100 :                 CATCH_REQUIRE(r.has_from());
    1889          100 :                 CATCH_REQUIRE_FALSE(r.has_to());
    1890          100 :                 CATCH_REQUIRE_FALSE(r.is_range());
    1891          100 :                 CATCH_REQUIRE_FALSE(r.is_empty());
    1892          100 :                 addr::addr f(r.get_from());
    1893          100 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1894          100 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    1895          100 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    1896          100 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
    1897          100 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_BRACKET_ADDRESS | addr::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
    1898          100 :                 CATCH_REQUIRE(f.get_port() == port);
    1899          100 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
    1900          100 :                 CATCH_REQUIRE(f.get_network_type() == addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    1901          100 :                 CATCH_REQUIRE_FALSE(f.is_lan());
    1902          100 :                 CATCH_REQUIRE(f.is_lan(true));
    1903          100 :                 CATCH_REQUIRE_FALSE(f.is_lan(false));
    1904          100 :                 CATCH_REQUIRE_FALSE(f.is_wan());
    1905          100 :                 CATCH_REQUIRE_FALSE(f.is_wan(true));
    1906          100 :                 CATCH_REQUIRE_FALSE(f.is_wan(false));
    1907          100 :             }
    1908              :         }
    1909            4 :         CATCH_END_SECTION()
    1910              : 
    1911            4 :         CATCH_START_SECTION("ipv6::port: port when not allowed check as IPv6")
    1912              :         {
    1913            1 :             addr::addr_parser p;
    1914            1 :             p.set_allow(addr::allow_t::ALLOW_PORT, false);
    1915            3 :             addr::addr_range::vector_t ips(p.parse("localhost:33.5"));
    1916            1 :             CATCH_REQUIRE(p.has_errors());
    1917            1 :             CATCH_REQUIRE(p.error_count() == 1);
    1918            1 :             CATCH_REQUIRE(p.error_messages() == "Invalid address in \"localhost:33.5\" error -2 -- Name or service not known\n");
    1919            1 :             CATCH_REQUIRE(p.has_errors());
    1920            1 :             p.clear_errors();
    1921            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1922            1 :             CATCH_REQUIRE(ips.size() == 0);
    1923            1 :         }
    1924            4 :         CATCH_END_SECTION()
    1925              : 
    1926            4 :         CATCH_START_SECTION("ipv6::port: space before port")
    1927              :         {
    1928            1 :             addr::addr_parser p;
    1929            3 :             addr::addr_range::vector_t ips(p.parse("[fafa:fefe:ffaa:ffee::3] :456"));
    1930            1 :             CATCH_REQUIRE(p.has_errors());
    1931            1 :             CATCH_REQUIRE(p.error_count() == 1);
    1932            1 :             CATCH_REQUIRE(p.error_messages() == "The IPv6 address \"[fafa:fefe:ffaa:ffee::3] :456\" is followed by unknown data.\n");
    1933            1 :             CATCH_REQUIRE(p.has_errors());
    1934            1 :             p.clear_errors();
    1935            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    1936            1 :             CATCH_REQUIRE(ips.size() == 0);
    1937            1 :         }
    1938            4 :         CATCH_END_SECTION()
    1939           10 :     }
    1940           10 : }
    1941              : 
    1942              : 
    1943           14 : CATCH_TEST_CASE( "ipv6::masks", "[ipv6]" )
    1944              : {
    1945           14 :     CATCH_GIVEN("addr()")
    1946              :     {
    1947              :         // technically, a default addr object represents and IPv6 so the
    1948              :         // dealing with the mask without an IPv4 is done by IPv6 tests
    1949              :         //
    1950            4 :         addr::addr a;
    1951              : 
    1952            4 :         CATCH_START_SECTION("ipv6::masks: default mask")
    1953              :         {
    1954            1 :             CATCH_REQUIRE_FALSE(a.is_mask_defined());
    1955              : 
    1956            1 :             uint8_t mask[16] = {};
    1957            1 :             a.get_mask(mask);
    1958           17 :             for(int idx(0); idx < 16; ++idx)
    1959              :             {
    1960           16 :                 CATCH_REQUIRE(mask[idx] == 255);
    1961              :             }
    1962            1 :             CATCH_REQUIRE(a.get_mask_size() == 128);
    1963              : 
    1964            1 :             CATCH_REQUIRE_FALSE(a.is_mask_defined());
    1965              :         }
    1966            4 :         CATCH_END_SECTION()
    1967              : 
    1968            4 :         CATCH_START_SECTION("ipv6::masks: set_mask_count()")
    1969              :         {
    1970            1 :             CATCH_REQUIRE_FALSE(a.is_mask_defined());
    1971              : 
    1972          130 :             for(int idx(0); idx <= 128; ++idx)
    1973              :             {
    1974          129 :                 a.set_mask_count(idx);
    1975          129 :                 CATCH_REQUIRE(a.is_mask_defined());
    1976          129 :                 CATCH_REQUIRE(a.get_mask_size() == idx);
    1977              :             }
    1978              : 
    1979            1 :             CATCH_REQUIRE(a.is_mask_defined());
    1980            1 :             a.set_mask_defined(false);
    1981            1 :             CATCH_REQUIRE_FALSE(a.is_mask_defined());
    1982              : 
    1983           11 :             for(int idx(-10); idx < 0; ++idx)
    1984              :             {
    1985           10 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1986              :                           a.set_mask_count(idx)
    1987              :                         , addr::out_of_range
    1988              :                         , Catch::Matchers::ExceptionMessage(
    1989              :                                   "out_of_range: the mask size " + std::to_string(idx) + " is out of range."));
    1990              : 
    1991           10 :                 CATCH_REQUIRE_FALSE(a.is_mask_defined());
    1992              :             }
    1993              : 
    1994            3 :             for(int idx(129); idx <= 130; ++idx)
    1995              :             {
    1996            2 :                 CATCH_REQUIRE_THROWS_MATCHES(
    1997              :                           a.set_mask_count(idx)
    1998              :                         , addr::out_of_range
    1999              :                         , Catch::Matchers::ExceptionMessage(
    2000              :                                   "out_of_range: the mask size " + std::to_string(idx) + " is out of range."));
    2001              : 
    2002            2 :                 CATCH_REQUIRE_FALSE(a.is_mask_defined());
    2003              :             }
    2004              : 
    2005            1 :             a.set_mask_defined(true);
    2006            1 :             CATCH_REQUIRE(a.is_mask_defined());
    2007              :         }
    2008            4 :         CATCH_END_SECTION()
    2009              : 
    2010            4 :         CATCH_START_SECTION("ipv6::masks: set_mask()")
    2011              :         {
    2012            1 :             uint8_t mask[16], verify_mask[16];
    2013            6 :             for(int idx(0); idx < 5; ++idx)
    2014              :             {
    2015           85 :                 for(int j(0); j < 16; ++j)
    2016              :                 {
    2017           80 :                     mask[j] = rand();
    2018              :                 }
    2019            5 :                 a.set_mask(mask);
    2020            5 :                 a.get_mask(verify_mask);
    2021           85 :                 for(int j(0); j < 16; ++j)
    2022              :                 {
    2023           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2024              :                 }
    2025              : 
    2026              :                 // verify that a copy does copy the mask as expected
    2027              :                 //
    2028            5 :                 addr::addr b(a);
    2029            5 :                 b.get_mask(verify_mask);
    2030           85 :                 for(int j(0); j < 16; ++j)
    2031              :                 {
    2032           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2033              :                 }
    2034              : 
    2035              :                 // since it's completely random, it should be -1 but it could
    2036              :                 // also be a number, in any event a and b have the same mask
    2037              :                 // so the function has to return the same value
    2038              :                 //
    2039            5 :                 CATCH_REQUIRE(a.get_mask_size() == b.get_mask_size());
    2040            5 :             }
    2041              :         }
    2042            4 :         CATCH_END_SECTION()
    2043              : 
    2044            4 :         CATCH_START_SECTION("ipv6::masks: set_mask()")
    2045              :         {
    2046            1 :             uint8_t mask[16];
    2047            1 :             uint8_t verify_mask[16];
    2048            6 :             for(int idx(0); idx < 5; ++idx)
    2049              :             {
    2050           85 :                 for(int j(0); j < 16; ++j)
    2051              :                 {
    2052           80 :                     mask[j] = rand();
    2053              :                 }
    2054            5 :                 a.set_mask(mask);
    2055            5 :                 a.get_mask(verify_mask);
    2056           85 :                 for(int j(0); j < 16; ++j)
    2057              :                 {
    2058           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2059           80 :                     verify_mask[j] = rand();
    2060              :                 }
    2061              : 
    2062              :                 // verify that a copy does copy the mask as expected
    2063              :                 //
    2064            5 :                 addr::addr b(a);
    2065            5 :                 b.get_mask(verify_mask);
    2066           85 :                 for(int j(0); j < 16; ++j)
    2067              :                 {
    2068           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2069           80 :                     verify_mask[j] = rand();
    2070              :                 }
    2071              : 
    2072              :                 // verify that copying inside a range works too
    2073              :                 //
    2074            5 :                 addr::addr_range r;
    2075            5 :                 r.set_from(a);
    2076            5 :                 r.get_from().get_mask(verify_mask);
    2077           85 :                 for(int j(0); j < 16; ++j)
    2078              :                 {
    2079           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2080           80 :                     verify_mask[j] = rand();
    2081              :                 }
    2082              : 
    2083              :                 // then that a range copy works as expected
    2084              :                 //
    2085            5 :                 addr::addr_range c(r);
    2086            5 :                 c.get_from().get_mask(verify_mask);
    2087           85 :                 for(int j(0); j < 16; ++j)
    2088              :                 {
    2089           80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
    2090           80 :                     verify_mask[j] = rand();
    2091              :                 }
    2092            5 :             }
    2093              :         }
    2094            4 :         CATCH_END_SECTION()
    2095           18 :     }
    2096              : 
    2097           14 :     CATCH_GIVEN("addr_parser() of address:port/mask")
    2098              :     {
    2099           10 :         CATCH_START_SECTION("ipv6::masks: mask allowed, but no mask")
    2100              :         {
    2101            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2102            1 :             int const port(rand() & 0xFFFF);
    2103            1 :             addr::addr_parser p;
    2104            1 :             p.set_protocol(proto);
    2105            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2106            1 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
    2107            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    2108            1 :             CATCH_REQUIRE(ips.size() == 1);
    2109            1 :             addr::addr_range const & r(ips[0]);
    2110            1 :             addr::addr f(r.get_from());
    2111            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    2112            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2113            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    2114            1 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/128");
    2115            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2116            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2117            1 :             CATCH_REQUIRE(f.get_port() == port);
    2118            1 :             CATCH_REQUIRE(f.get_protocol() == proto);
    2119            1 :             CATCH_REQUIRE(f.get_mask_size() == 128);
    2120            1 :         }
    2121           10 :         CATCH_END_SECTION()
    2122              : 
    2123           10 :         CATCH_START_SECTION("ipv6::masks: empty mask")
    2124              :         {
    2125            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2126            1 :             int const port(rand() & 0xFFFF);
    2127            1 :             addr::addr_parser p;
    2128            1 :             p.set_protocol(proto);
    2129            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2130            1 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/"));
    2131            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    2132            1 :             CATCH_REQUIRE(ips.size() == 1);
    2133            1 :             addr::addr_range const & r(ips[0]);
    2134            1 :             addr::addr f(r.get_from());
    2135            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    2136            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2137            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    2138            1 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/128");
    2139            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2140            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2141            1 :             CATCH_REQUIRE(f.get_port() == port);
    2142            1 :             CATCH_REQUIRE(f.get_protocol() == proto);
    2143            1 :             CATCH_REQUIRE(f.get_mask_size() == 128);
    2144            1 :         }
    2145           10 :         CATCH_END_SECTION()
    2146              : 
    2147           10 :         CATCH_START_SECTION("ipv6::masks: empty mask including the '[]'")
    2148              :         {
    2149            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2150            1 :             int const port(rand() & 0xFFFF);
    2151            1 :             addr::addr_parser p;
    2152            1 :             p.set_protocol(proto);
    2153            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2154            1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
    2155            1 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[]"));
    2156            1 :             CATCH_REQUIRE_FALSE(p.has_errors());
    2157            1 :             CATCH_REQUIRE(ips.size() == 1);
    2158            1 :             addr::addr_range const & r(ips[0]);
    2159            1 :             addr::addr f(r.get_from());
    2160            1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
    2161            1 :             CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2162            1 :             CATCH_REQUIRE(f.get_family() == AF_INET6);
    2163            1 :             std::string const result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/128");
    2164            1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2165            1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2166            1 :             CATCH_REQUIRE(f.get_port() == port);
    2167            1 :             CATCH_REQUIRE(f.get_protocol() == proto);
    2168            1 :             CATCH_REQUIRE(f.get_mask_size() == 128);
    2169            1 :         }
    2170           10 :         CATCH_END_SECTION()
    2171              : 
    2172           10 :         CATCH_START_SECTION("ipv6::masks: empty mask '[]' with address mask not allowed")
    2173              :         {
    2174            1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2175            1 :             int const port(rand() & 0xFFFF);
    2176            1 :             addr::addr_parser p;
    2177            1 :             p.set_protocol(proto);
    2178            1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2179            1 :             addr::addr_range::vector_t ips(p.parse("[66:33:cc:11:7:11:bb:dd]:" + std::to_string(port) + "/[]"));
    2180            1 :             CATCH_REQUIRE(p.has_errors());
    2181            1 :             CATCH_REQUIRE(ips.size() == 0);
    2182            1 :         }
    2183           10 :         CATCH_END_SECTION()
    2184              : 
    2185           10 :         CATCH_START_SECTION("ipv6::masks: one number masks")
    2186              :         {
    2187          130 :             for(int idx(0); idx <= 128; ++idx)
    2188              :             {
    2189          129 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2190          129 :                 int const port(rand() & 0xFFFF);
    2191          129 :                 addr::addr_parser p;
    2192          129 :                 p.set_protocol(proto);
    2193          129 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2194          129 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + std::to_string(idx)));
    2195          129 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2196          129 :                 CATCH_REQUIRE(ips.size() == 1);
    2197          129 :                 addr::addr_range const & r(ips[0]);
    2198          129 :                 addr::addr f(r.get_from());
    2199          129 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2200          129 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2201          129 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2202          129 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
    2203          129 :                 int j(15);
    2204          129 :                 int m(128 - idx);
    2205         1089 :                 for(; m > 8; m -= 8, --j)
    2206              :                 {
    2207          960 :                     mask[j] = 0;
    2208              :                 }
    2209          129 :                 if(j < 0)
    2210              :                 {
    2211            0 :                     throw std::logic_error("invalid j here");
    2212              :                 }
    2213          129 :                 mask[j] = 255 << m;
    2214          129 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    2215          129 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    2216              :                 {
    2217            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2218              :                 }
    2219          129 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + std::to_string(idx));
    2220          129 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2221          129 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2222          129 :                 CATCH_REQUIRE(f.get_port() == port);
    2223          129 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2224          129 :                 CATCH_REQUIRE(f.get_mask_size() == idx);
    2225          129 :             }
    2226              :         }
    2227           10 :         CATCH_END_SECTION()
    2228              : 
    2229           10 :         CATCH_START_SECTION("ipv6::masks: address like mask")
    2230              :         {
    2231           26 :             for(int idx(0); idx < 25; ++idx)
    2232              :             {
    2233           25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2234           25 :                 int const port(rand() & 0xFFFF);
    2235           25 :                 addr::addr_parser p;
    2236           25 :                 p.set_protocol(proto);
    2237           25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2238           25 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
    2239              :                 // when specified as an IP, the mask can be absolutely anything
    2240           25 :                 uint8_t mask[16];
    2241          425 :                 for(int j(0); j < 16; ++j)
    2242              :                 {
    2243          400 :                     mask[j] = rand();
    2244              :                 }
    2245           25 :                 std::stringstream smask;
    2246           25 :                 smask << std::hex
    2247           25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    2248           25 :                       << ":"                            
    2249           25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    2250           25 :                       << ":"                            
    2251           25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    2252           25 :                       << ":"                            
    2253           25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    2254           25 :                       << ":"                            
    2255           25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    2256           25 :                       << ":"                            
    2257           25 :                       << htons((mask[11] << 8) | mask[10])
    2258           25 :                       << ":"                            
    2259           25 :                       << htons((mask[13] << 8) | mask[12])
    2260           25 :                       << ":"                            
    2261           25 :                       << htons((mask[15] << 8) | mask[14]);
    2262           25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    2263           25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    2264              :                 {
    2265            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2266              :                 }
    2267           25 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + smask.str() + "]"));
    2268           25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2269           25 :                 CATCH_REQUIRE(ips.size() == 1);
    2270           25 :                 addr::addr_range const & r(ips[0]);
    2271           25 :                 addr::addr f(r.get_from());
    2272           25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2273           25 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2274           25 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2275           25 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    2276           25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2277           25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2278           25 :                 CATCH_REQUIRE(f.get_port() == port);
    2279           25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2280           25 :             }
    2281              :         }
    2282           10 :         CATCH_END_SECTION()
    2283              : 
    2284           10 :         CATCH_START_SECTION("ipv6::masks: address like default mask")
    2285              :         {
    2286           26 :             for(int idx(0); idx < 25; ++idx)
    2287              :             {
    2288           25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2289           25 :                 int const port(rand() & 0xFFFF);
    2290           25 :                 addr::addr_parser p;
    2291           25 :                 p.set_protocol(proto);
    2292           25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2293           25 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
    2294              :                 // when specified as an IP, the mask can be absolutely anything
    2295              :                 // (here the mask is a string an it will be parsed by the
    2296              :                 // parser if required)
    2297              :                 //
    2298           25 :                 uint8_t mask[16];
    2299          425 :                 for(int j(0); j < 16; ++j)
    2300              :                 {
    2301          400 :                     mask[j] = rand();
    2302              :                 }
    2303           25 :                 std::stringstream smask;
    2304           25 :                 smask << std::hex
    2305           25 :                       << "["
    2306           25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    2307           25 :                       << ":"                            
    2308           25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    2309           25 :                       << ":"                            
    2310           25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    2311           25 :                       << ":"                            
    2312           25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    2313           25 :                       << ":"                            
    2314           25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    2315           25 :                       << ":"                            
    2316           25 :                       << htons((mask[11] << 8) | mask[10])
    2317           25 :                       << ":"                            
    2318           25 :                       << htons((mask[13] << 8) | mask[12])
    2319           25 :                       << ":"                            
    2320           25 :                       << htons((mask[15] << 8) | mask[14])
    2321           25 :                       << "]";
    2322           25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    2323           25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    2324              :                 {
    2325            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2326              :                 }
    2327           25 :                 p.set_default_mask(smask.str());
    2328           25 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
    2329           25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2330           25 :                 CATCH_REQUIRE(ips.size() == 1);
    2331           25 :                 addr::addr_range const & r(ips[0]);
    2332           25 :                 addr::addr f(r.get_from());
    2333           25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2334           25 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2335           25 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2336           25 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    2337           25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2338           25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2339           25 :                 CATCH_REQUIRE(f.get_port() == port);
    2340           25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2341           25 :                 uint8_t verify_mask[16];
    2342           25 :                 f.get_mask(verify_mask);
    2343          425 :                 for(int j(0); j < 16; ++j)
    2344              :                 {
    2345          400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    2346              :                 }
    2347           25 :             }
    2348              :         }
    2349           10 :         CATCH_END_SECTION()
    2350              : 
    2351           10 :         CATCH_START_SECTION("ipv6::masks: address like mask with a default")
    2352              :         {
    2353           26 :             for(int idx(0); idx < 25; ++idx)
    2354              :             {
    2355           25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2356           25 :                 int const port(rand() & 0xFFFF);
    2357           25 :                 addr::addr_parser p;
    2358           25 :                 p.set_protocol(proto);
    2359           25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2360           25 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
    2361              : 
    2362              :                 // here we want a default and an IP with a specific mask
    2363              :                 // to make sure that the specific mask has priority
    2364              :                 //
    2365           25 :                 uint8_t mask[16];
    2366          425 :                 for(int j(0); j < 16; ++j)
    2367              :                 {
    2368          400 :                     mask[j] = rand();
    2369              :                 }
    2370           25 :                 std::stringstream smask;
    2371           25 :                 smask << std::hex
    2372           25 :                       << "["
    2373           25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    2374           25 :                       << ":"                            
    2375           25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    2376           25 :                       << ":"                            
    2377           25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    2378           25 :                       << ":"                            
    2379           25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    2380           25 :                       << ":"                            
    2381           25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    2382           25 :                       << ":"                            
    2383           25 :                       << htons((mask[11] << 8) | mask[10])
    2384           25 :                       << ":"                            
    2385           25 :                       << htons((mask[13] << 8) | mask[12])
    2386           25 :                       << ":"                            
    2387           25 :                       << htons((mask[15] << 8) | mask[14])
    2388           25 :                       << "]";
    2389           25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    2390           25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    2391              :                 {
    2392            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2393              :                 }
    2394              : 
    2395           25 :                 uint8_t default_mask[16];
    2396          425 :                 for(int j(0); j < 16; ++j)
    2397              :                 {
    2398          400 :                     default_mask[j] = rand();
    2399              :                 }
    2400              :                 //std::stringstream default_smask;
    2401              :                 //default_smask << std::hex
    2402              :                 //      << "["
    2403              :                 //      << htons((default_mask[ 1] << 8) | default_mask[ 0])
    2404              :                 //      << ":"                            
    2405              :                 //      << htons((default_mask[ 3] << 8) | default_mask[ 2])
    2406              :                 //      << ":"                            
    2407              :                 //      << htons((default_mask[ 5] << 8) | default_mask[ 4])
    2408              :                 //      << ":"                            
    2409              :                 //      << htons((default_mask[ 7] << 8) | default_mask[ 6])
    2410              :                 //      << ":"                            
    2411              :                 //      << htons((default_mask[ 9] << 8) | default_mask[ 8])
    2412              :                 //      << ":"                            
    2413              :                 //      << htons((default_mask[11] << 8) | default_mask[10])
    2414              :                 //      << ":"                            
    2415              :                 //      << htons((default_mask[13] << 8) | default_mask[12])
    2416              :                 //      << ":"                            
    2417              :                 //      << htons((default_mask[15] << 8) | default_mask[14])
    2418              :                 //      << "]";
    2419           25 :                 char default_buf[1024]; // really large buffer to make sure it does not get truncated
    2420           25 :                 if(inet_ntop(AF_INET6, default_mask, default_buf, sizeof(buf)) == nullptr)
    2421              :                 {
    2422            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2423              :                 }
    2424           75 :                 p.set_default_mask(default_buf);
    2425              : 
    2426           25 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + smask.str()));
    2427           25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2428           25 :                 CATCH_REQUIRE(ips.size() == 1);
    2429           25 :                 addr::addr_range const & r(ips[0]);
    2430           25 :                 addr::addr f(r.get_from());
    2431           25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2432           25 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2433           25 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2434           25 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    2435           25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2436           25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2437           25 :                 CATCH_REQUIRE(f.get_port() == port);
    2438           25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2439           25 :                 uint8_t verify_mask[16];
    2440           25 :                 f.get_mask(verify_mask);
    2441          425 :                 for(int j(0); j < 16; ++j)
    2442              :                 {
    2443          400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    2444              :                 }
    2445           25 :             }
    2446              :         }
    2447           10 :         CATCH_END_SECTION()
    2448              : 
    2449           10 :         CATCH_START_SECTION("ipv6::masks: no address, but one IPv6 number masks")
    2450              :         {
    2451              :             // with just a number, the mask is considered an IPv6 mask
    2452              :             // if it is 33 or more
    2453              :             //
    2454           97 :             for(int idx(33); idx <= 128; ++idx)
    2455              :             {
    2456           96 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2457           96 :                 int const port(rand() & 0xFFFF);
    2458           96 :                 addr::addr_parser p;
    2459           96 :                 p.set_protocol(proto);
    2460           96 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2461              :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    2462           96 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(idx)));
    2463           96 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2464           96 :                 CATCH_REQUIRE(ips.size() == 1);
    2465           96 :                 addr::addr_range const & r(ips[0]);
    2466           96 :                 addr::addr f(r.get_from());
    2467           96 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2468           96 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2469           96 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2470           96 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
    2471           96 :                 int j(15);
    2472           96 :                 int m(128 - idx);
    2473          613 :                 for(; m > 8; m -= 8, --j)
    2474              :                 {
    2475          517 :                     mask[j] = 0;
    2476              :                 }
    2477           96 :                 if(j < 0)
    2478              :                 {
    2479            0 :                     throw std::logic_error("invalid j here");
    2480              :                 }
    2481           96 :                 mask[j] = 255 << m;
    2482           96 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    2483           96 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    2484              :                 {
    2485            0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    2486              :                 }
    2487           96 :                 std::string result("[::]:" + std::to_string(port) + "/" + std::to_string(idx));
    2488           96 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2489           96 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2490           96 :                 CATCH_REQUIRE(f.get_port() == port);
    2491           96 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2492           96 :                 CATCH_REQUIRE(f.get_mask_size() == idx);
    2493           96 :             }
    2494              :         }
    2495           10 :         CATCH_END_SECTION()
    2496              : 
    2497           10 :         CATCH_START_SECTION("ipv6::masks: no address, but one IPv6 masks")
    2498              :         {
    2499              :             // with just a number, the mask is considered an IPv6 mask
    2500              :             // if it is 33 or more
    2501              :             //
    2502            6 :             for(int idx(0); idx < 5; ++idx)
    2503              :             {
    2504            5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    2505            5 :                 int const port(rand() & 0xFFFF);
    2506            5 :                 addr::addr_parser p;
    2507            5 :                 p.set_protocol(proto);
    2508            5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    2509            5 :                 p.set_allow(addr::allow_t::ALLOW_ADDRESS_MASK, true);
    2510              :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    2511            5 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]"));
    2512            5 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    2513            5 :                 CATCH_REQUIRE(ips.size() == 1);
    2514            5 :                 addr::addr_range const & r(ips[0]);
    2515            5 :                 addr::addr f(r.get_from());
    2516            5 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    2517            5 :                 CATCH_REQUIRE_FALSE(f.get_family() == AF_INET);
    2518            5 :                 CATCH_REQUIRE(f.get_family() == AF_INET6);
    2519            5 :                 std::string result("[::]:" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]");
    2520            5 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::STRING_IP_ALL) == result);
    2521            5 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::STRING_IP_ALL) == result);
    2522            5 :                 CATCH_REQUIRE(f.get_port() == port);
    2523            5 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    2524            5 :             }
    2525              :         }
    2526           10 :         CATCH_END_SECTION()
    2527           14 :     }
    2528           14 : }
    2529              : 
    2530              : 
    2531            8 : CATCH_TEST_CASE("ipv6::network_type", "[ipv6]")
    2532              : {
    2533            8 :     CATCH_GIVEN("addr()")
    2534              :     {
    2535            8 :         addr::addr a;
    2536              : 
    2537            8 :         CATCH_START_SECTION("ipv6::network_type: any (::)")
    2538              :         {
    2539              :             {
    2540            1 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2541            1 :                 in6.sin6_family = AF_INET6;
    2542            1 :                 in6.sin6_port = htons(rand());
    2543            1 :                 in6.sin6_addr.s6_addr32[0] = 0;
    2544            1 :                 in6.sin6_addr.s6_addr32[1] = 0;
    2545            1 :                 in6.sin6_addr.s6_addr32[2] = 0;
    2546            1 :                 in6.sin6_addr.s6_addr32[3] = 0;
    2547              : 
    2548              :                 // verify network type
    2549              :                 //
    2550            1 :                 a.set_ipv6(in6);
    2551              : 
    2552            1 :                 CATCH_REQUIRE(a.is_default());
    2553            1 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_ANY);
    2554            3 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Any");
    2555            1 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2556            1 :                 CATCH_REQUIRE_FALSE(a.is_lan(true));
    2557            1 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2558            1 :                 CATCH_REQUIRE(a.is_wan());
    2559            1 :                 CATCH_REQUIRE(a.is_wan(true));
    2560            1 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2561            1 :                 CATCH_REQUIRE(a.is_valid());
    2562              :             }
    2563              : 
    2564              :             // make sure that if any byte is set to non-zero it is not
    2565              :             // viewed as the ANY address
    2566              :             //
    2567           17 :             for(int idx(0); idx < 16; ++idx)
    2568              :             {
    2569           16 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2570           16 :                 in6.sin6_family = AF_INET6;
    2571           16 :                 in6.sin6_port = htons(rand());
    2572           16 :                 in6.sin6_addr.s6_addr32[0] = 0;
    2573           16 :                 in6.sin6_addr.s6_addr32[1] = 0;
    2574           16 :                 in6.sin6_addr.s6_addr32[2] = 0;
    2575           16 :                 in6.sin6_addr.s6_addr32[3] = 0;
    2576              : 
    2577              :                 // change one byte only
    2578              :                 //
    2579              :                 do
    2580              :                 {
    2581           16 :                     in6.sin6_addr.s6_addr[idx] = rand();
    2582              :                 }
    2583           16 :                 while(in6.sin6_addr.s6_addr[idx] == 0);
    2584              : 
    2585              :                 // verify network type
    2586              :                 //
    2587           16 :                 a.set_ipv6(in6);
    2588              : 
    2589           48 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) != "Any");
    2590              : 
    2591              :                 // addresses that start with 0xFD are private
    2592              :                 //
    2593              :                 // note that the test algorithm prevents IPv4 addresses so
    2594              :                 // not need to bother with those
    2595              :                 //
    2596           16 :                 switch(a.get_network_type())
    2597              :                 {
    2598            0 :                 case addr::network_type_t::NETWORK_TYPE_UNDEFINED:
    2599              :                 case addr::network_type_t::NETWORK_TYPE_ANY:
    2600              :                     // the address is always defined
    2601              :                     // the address is never all zeroes
    2602              :                     //
    2603            0 :                     CATCH_REQUIRE(false);
    2604            0 :                     break;
    2605              : 
    2606            0 :                 case addr::network_type_t::NETWORK_TYPE_PRIVATE:
    2607              :                 case addr::network_type_t::NETWORK_TYPE_LOOPBACK:
    2608            0 :                     CATCH_REQUIRE(a.is_valid());
    2609            0 :                     CATCH_REQUIRE(a.is_lan());
    2610            0 :                     CATCH_REQUIRE(a.is_lan(true));
    2611            0 :                     CATCH_REQUIRE(a.is_lan(false));
    2612            0 :                     CATCH_REQUIRE_FALSE(a.is_wan());
    2613            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(true));
    2614            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(false));
    2615            0 :                     break;
    2616              : 
    2617            0 :                 case addr::network_type_t::NETWORK_TYPE_CARRIER:
    2618              :                 case addr::network_type_t::NETWORK_TYPE_LINK_LOCAL:
    2619              :                 case addr::network_type_t::NETWORK_TYPE_MULTICAST:
    2620            0 :                     CATCH_REQUIRE(a.is_valid());
    2621            0 :                     CATCH_REQUIRE_FALSE(a.is_lan());
    2622            0 :                     CATCH_REQUIRE(a.is_lan(true));
    2623            0 :                     CATCH_REQUIRE_FALSE(a.is_lan(false));
    2624            0 :                     CATCH_REQUIRE_FALSE(a.is_wan());
    2625            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(true));
    2626            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(false));
    2627            0 :                     break;
    2628              : 
    2629            0 :                 case addr::network_type_t::NETWORK_TYPE_DOCUMENTATION:
    2630            0 :                     CATCH_REQUIRE_FALSE(a.is_valid());
    2631            0 :                     CATCH_REQUIRE_FALSE(a.is_lan());
    2632            0 :                     CATCH_REQUIRE_FALSE(a.is_lan(true));
    2633            0 :                     CATCH_REQUIRE_FALSE(a.is_lan(false));
    2634            0 :                     CATCH_REQUIRE_FALSE(a.is_wan());
    2635            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(true));
    2636            0 :                     CATCH_REQUIRE_FALSE(a.is_wan(false));
    2637            0 :                     break;
    2638              : 
    2639           16 :                 case addr::network_type_t::NETWORK_TYPE_PUBLIC:
    2640           16 :                     CATCH_REQUIRE(a.is_valid());
    2641           16 :                     CATCH_REQUIRE_FALSE(a.is_lan());
    2642           16 :                     CATCH_REQUIRE_FALSE(a.is_lan(true));
    2643           16 :                     CATCH_REQUIRE_FALSE(a.is_lan(false));
    2644           16 :                     CATCH_REQUIRE(a.is_wan());
    2645           16 :                     CATCH_REQUIRE(a.is_wan(true));
    2646           16 :                     CATCH_REQUIRE(a.is_wan(false));
    2647           16 :                     break;
    2648              : 
    2649              :                 }
    2650              :             }
    2651              :         }
    2652            8 :         CATCH_END_SECTION()
    2653              : 
    2654            8 :         CATCH_START_SECTION("ipv6::network_type: private address fd00::/8")
    2655              :         {
    2656           11 :             for(int idx(0); idx < 10; ++idx)
    2657              :             {
    2658           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2659           10 :                 in6.sin6_family = AF_INET6;
    2660           10 :                 in6.sin6_port = htons(rand());
    2661           10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFD00 | (rand() & 255));
    2662           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    2663           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    2664           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    2665           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    2666           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    2667           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    2668           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    2669              : 
    2670              :                 // verify network type
    2671              :                 //
    2672           10 :                 a.set_ipv6(in6);
    2673           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_PRIVATE);
    2674           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Private");
    2675           10 :                 CATCH_REQUIRE(a.is_lan());
    2676           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2677           10 :                 CATCH_REQUIRE(a.is_lan(false));
    2678           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2679           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2680           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2681              :             }
    2682              :         }
    2683            8 :         CATCH_END_SECTION()
    2684              : 
    2685            8 :         CATCH_START_SECTION("ipv6::network_type: private address fe80::/10")
    2686              :         {
    2687           11 :             for(int idx(0); idx < 10; ++idx)
    2688              :             {
    2689           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2690           10 :                 in6.sin6_family = AF_INET6;
    2691           10 :                 in6.sin6_port = htons(rand());
    2692           10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFE80 | (rand() & 63));
    2693           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    2694           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    2695           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    2696           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    2697           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    2698           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    2699           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    2700              : 
    2701              :                 // verify network type
    2702              :                 //
    2703           10 :                 a.set_ipv6(in6);
    2704           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    2705           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Local Link");
    2706           10 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2707           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2708           10 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2709           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2710           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2711           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2712              :             }
    2713              :         }
    2714            8 :         CATCH_END_SECTION()
    2715              : 
    2716            8 :         CATCH_START_SECTION("ipv6::network_type: private address ff02::/16")
    2717              :         {
    2718           11 :             for(int idx(0); idx < 10; ++idx)
    2719              :             {
    2720           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2721           10 :                 in6.sin6_family = AF_INET6;
    2722           10 :                 in6.sin6_port = htons(rand());
    2723           10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF02);
    2724           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    2725           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    2726           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    2727           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    2728           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    2729           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    2730           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    2731              : 
    2732              :                 // verify network type
    2733              :                 //
    2734           10 :                 a.set_ipv6(in6);
    2735           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    2736           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Local Link");
    2737           10 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2738           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2739           10 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2740           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2741           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2742           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2743              :             }
    2744              :         }
    2745            8 :         CATCH_END_SECTION()
    2746              : 
    2747            8 :         CATCH_START_SECTION("ipv6::network_type: private address ff00::/8")
    2748              :         {
    2749           11 :             for(int idx(0); idx < 10; ++idx)
    2750              :             {
    2751           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2752           10 :                 in6.sin6_family = AF_INET6;
    2753           10 :                 in6.sin6_port = htons(rand());
    2754              :                 do
    2755              :                 {
    2756           17 :                     in6.sin6_addr.s6_addr16[0] = htons(0xFF00 | (rand() & 255));
    2757              :                 }
    2758           17 :                 while((in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF01)       // ffx1::/16
    2759           11 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF02)       // ffx2::/16
    2760           10 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFFC0)) == htons(0xFE80)       // fe80::/10
    2761           27 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF00)) == htons(0xFD00));     // fd00::/8
    2762           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    2763           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    2764           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    2765           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    2766           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    2767           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    2768           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    2769              : 
    2770              :                 // verify network type
    2771              :                 //
    2772           10 :                 a.set_ipv6(in6);
    2773           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_MULTICAST);
    2774           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Multicast");
    2775           10 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2776           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2777           10 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2778           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2779           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2780           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2781              :             }
    2782              :         }
    2783            8 :         CATCH_END_SECTION()
    2784              : 
    2785            8 :         CATCH_START_SECTION("ipv6::network_type: private address ffx1::/8")
    2786              :         {
    2787           11 :             for(int idx(0); idx < 10; ++idx)
    2788              :             {
    2789           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2790           10 :                 in6.sin6_family = AF_INET6;
    2791           10 :                 in6.sin6_port = htons(rand());
    2792           10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF01 | ((rand() & 15) << 4));
    2793           10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    2794           10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    2795           10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    2796           10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    2797           10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    2798           10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    2799           10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    2800              : 
    2801              :                 // verify network type
    2802              :                 //
    2803           10 :                 a.set_ipv6(in6);
    2804           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    2805           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Loopback");
    2806           10 :                 CATCH_REQUIRE(a.is_lan());
    2807           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2808           10 :                 CATCH_REQUIRE(a.is_lan(false));
    2809           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2810           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2811           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2812              :             }
    2813              :         }
    2814            8 :         CATCH_END_SECTION()
    2815              : 
    2816            8 :         CATCH_START_SECTION("ipv6::network_type: private address ::1")
    2817              :         {
    2818           11 :             for(int idx(0); idx < 10; ++idx)
    2819              :             {
    2820           10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2821           10 :                 in6.sin6_family = AF_INET6;
    2822           10 :                 in6.sin6_port = htons(rand());
    2823           10 :                 in6.sin6_addr.s6_addr16[0] = 0;
    2824           10 :                 in6.sin6_addr.s6_addr16[1] = 0;
    2825           10 :                 in6.sin6_addr.s6_addr16[2] = 0;
    2826           10 :                 in6.sin6_addr.s6_addr16[3] = 0;
    2827           10 :                 in6.sin6_addr.s6_addr16[4] = 0;
    2828           10 :                 in6.sin6_addr.s6_addr16[5] = 0;
    2829           10 :                 in6.sin6_addr.s6_addr16[6] = 0;
    2830           10 :                 in6.sin6_addr.s6_addr16[7] = htons(1);
    2831              : 
    2832              :                 // verify network type
    2833              :                 //
    2834           10 :                 a.set_ipv6(in6);
    2835           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    2836           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Loopback");
    2837           10 :                 CATCH_REQUIRE(a.is_lan());
    2838           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2839           10 :                 CATCH_REQUIRE(a.is_lan(false));
    2840           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2841           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2842           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2843              : 
    2844              :                 // try again from a string to confirm
    2845              :                 //
    2846           10 :                 struct addrinfo * addrlist(nullptr);
    2847           10 :                 int const port(rand() & 65535);
    2848           10 :                 int const r(getaddrinfo("::1", std::to_string(port).c_str(), nullptr, &addrlist));
    2849           10 :                 CATCH_REQUIRE(r == 0);
    2850           10 :                 CATCH_REQUIRE(addrlist != nullptr);
    2851           10 :                 CATCH_REQUIRE(addrlist->ai_family == AF_INET6);
    2852           10 :                 CATCH_REQUIRE(addrlist->ai_addrlen == sizeof(struct sockaddr_in6));
    2853           10 :                 a.set_ipv6(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
    2854           10 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    2855           30 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Loopback");
    2856           10 :                 CATCH_REQUIRE(a.is_lan());
    2857           10 :                 CATCH_REQUIRE(a.is_lan(true));
    2858           10 :                 CATCH_REQUIRE(a.is_lan(false));
    2859           10 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2860           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2861           10 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2862           10 :                 freeaddrinfo(addrlist);
    2863              :             }
    2864              :         }
    2865            8 :         CATCH_END_SECTION()
    2866              : 
    2867            8 :         CATCH_START_SECTION("ipv6::network_type: documentation (2001:db8:: and 3fff:0XXX::)")
    2868              :         {
    2869          101 :             for(int count(0); count < 100; ++count)
    2870              :             {
    2871          100 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2872          100 :                 in6.sin6_family = AF_INET6;
    2873          100 :                 in6.sin6_port = htons(rand());
    2874          100 :                 in6.sin6_addr.s6_addr16[0] = htons(0x2001);
    2875          100 :                 in6.sin6_addr.s6_addr16[1] = htons(0xdb8);
    2876          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[1]);
    2877          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[2]);
    2878          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[3]);
    2879              : 
    2880              :                 // verify network type
    2881              :                 //
    2882          100 :                 a.set_ipv6(in6);
    2883              : 
    2884          100 :                 CATCH_REQUIRE_FALSE(a.is_default());
    2885          100 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_DOCUMENTATION);
    2886          300 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Documentation");
    2887          100 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2888          100 :                 CATCH_REQUIRE_FALSE(a.is_lan(true));
    2889          100 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2890          100 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2891          100 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2892          100 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2893          100 :                 CATCH_REQUIRE_FALSE(a.is_valid());
    2894              :             }
    2895              : 
    2896          101 :             for(int count(0); count < 100; ++count)
    2897              :             {
    2898          100 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    2899          100 :                 in6.sin6_family = AF_INET6;
    2900          100 :                 in6.sin6_port = htons(rand());
    2901          100 :                 in6.sin6_addr.s6_addr16[0] = htons(0x3fff);
    2902          100 :                 in6.sin6_addr.s6_addr16[1] = htons(rand() & 0xfff);
    2903          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[1]);
    2904          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[2]);
    2905          100 :                 SNAP_CATCH2_NAMESPACE::random(in6.sin6_addr.s6_addr32[3]);
    2906              : 
    2907              :                 // verify network type
    2908              :                 //
    2909          100 :                 a.set_ipv6(in6);
    2910              : 
    2911          100 :                 CATCH_REQUIRE_FALSE(a.is_default());
    2912          100 :                 CATCH_REQUIRE(a.get_network_type() == addr::network_type_t::NETWORK_TYPE_DOCUMENTATION);
    2913          300 :                 CATCH_REQUIRE(std::string(a.get_network_type_string()) == "Documentation");
    2914          100 :                 CATCH_REQUIRE_FALSE(a.is_lan());
    2915          100 :                 CATCH_REQUIRE_FALSE(a.is_lan(true));
    2916          100 :                 CATCH_REQUIRE_FALSE(a.is_lan(false));
    2917          100 :                 CATCH_REQUIRE_FALSE(a.is_wan());
    2918          100 :                 CATCH_REQUIRE_FALSE(a.is_wan(true));
    2919          100 :                 CATCH_REQUIRE_FALSE(a.is_wan(false));
    2920          100 :                 CATCH_REQUIRE_FALSE(a.is_valid());
    2921              :             }
    2922              :         }
    2923            8 :         CATCH_END_SECTION()
    2924           16 :     }
    2925            8 : }
    2926              : 
    2927              : 
    2928            3 : CATCH_TEST_CASE("ipv6::network", "[ipv6]")
    2929              : {
    2930            3 :     CATCH_GIVEN("set_from_socket()")
    2931              :     {
    2932            3 :         CATCH_START_SECTION("ipv6::network: create a server, but do not test it (yet)...")
    2933              :         {
    2934            1 :             addr::addr_parser p;
    2935            3 :             addr::addr_range::vector_t ips(p.parse("[::1]:49999"));
    2936            1 :             CATCH_REQUIRE(ips.size() >= 1);
    2937              : 
    2938            1 :             addr::addr & a(ips[0].get_from());
    2939            1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_NONBLOCK | addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
    2940            1 :             CATCH_REQUIRE(s >= 0);
    2941            1 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    2942              : 
    2943            1 :             CATCH_REQUIRE(a.bind(s) == 0);
    2944            1 :         }
    2945            3 :         CATCH_END_SECTION()
    2946              : 
    2947            3 :         CATCH_START_SECTION("ipv6::network: connect with TCP to [::1]")
    2948              :         {
    2949            1 :             if(SNAP_CATCH2_NAMESPACE::g_tcp_port != -1)
    2950              :             {
    2951            1 :                 addr::addr_parser p;
    2952            1 :                 addr::addr_range::vector_t ips(p.parse("[::1]:" + std::to_string(SNAP_CATCH2_NAMESPACE::g_tcp_port)));
    2953            1 :                 CATCH_REQUIRE(ips.size() >= 1);
    2954              : 
    2955            1 :                 addr::addr & a(ips[0].get_from());
    2956            1 :                 int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    2957            1 :                 CATCH_REQUIRE(s >= 0);
    2958            1 :                 std::shared_ptr<int> auto_free(&s, socket_deleter);
    2959              : 
    2960            1 :                 CATCH_REQUIRE(a.connect(s) == 0);
    2961              : 
    2962              :                 // get socket info from the other side (peer == true)
    2963              :                 //
    2964            1 :                 addr::addr b;
    2965            1 :                 b.set_from_socket(s, true);
    2966            1 :                 CATCH_REQUIRE_FALSE(b.is_ipv4());
    2967            1 :                 CATCH_REQUIRE_FALSE(b.get_family() == AF_INET);
    2968            1 :                 CATCH_REQUIRE(b.get_family() == AF_INET6);
    2969            1 :                 CATCH_REQUIRE(b.to_ipv6_string(addr::STRING_IP_ADDRESS)    == "::1");
    2970            1 :                 CATCH_REQUIRE(b.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "::1");
    2971              : 
    2972              :                 // in this case we know what the port is since we specified
    2973              :                 // that when connecting
    2974              :                 //
    2975            1 :                 CATCH_REQUIRE(b.get_port() == SNAP_CATCH2_NAMESPACE::g_tcp_port);
    2976              : 
    2977              :                 // now try this side (peer == false)
    2978              :                 //
    2979            1 :                 addr::addr c;
    2980            1 :                 c.set_from_socket(s, false);
    2981            1 :                 CATCH_REQUIRE_FALSE(c.is_ipv4());
    2982            1 :                 CATCH_REQUIRE_FALSE(c.get_family() == AF_INET);
    2983            1 :                 CATCH_REQUIRE(c.get_family() == AF_INET6);
    2984            1 :                 CATCH_REQUIRE(c.to_ipv6_string(addr::STRING_IP_ADDRESS)    == "::1");
    2985            1 :                 CATCH_REQUIRE(c.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "::1");
    2986              : 
    2987              :                 // we cannot be sure of the port, there is a range we could
    2988              :                 // test better (more constraining) but for this test is
    2989              :                 // certainly does not matter much; it has to be more than
    2990              :                 // 1023, though
    2991              :                 //
    2992            1 :                 CATCH_REQUIRE(c.get_port() > 1023);
    2993            1 :             }
    2994              :             else
    2995              :             {
    2996              :                 // avoid issue of no assertions
    2997              :                 //
    2998            0 :                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::g_tcp_port == -1);
    2999            0 :                 std::cout << "connect to [::1] test skipped as no TCP port was specified on the command line." << std::endl;
    3000              :             }
    3001              :         }
    3002            3 :         CATCH_END_SECTION()
    3003              : 
    3004            3 :         CATCH_START_SECTION("ipv6::network: connect with UDP to [::1]")
    3005              :         {
    3006            1 :             addr::addr_parser p;
    3007            3 :             p.set_protocol("udp");
    3008            3 :             addr::addr_range::vector_t ips(p.parse("[::1]:53"));
    3009            1 :             CATCH_REQUIRE(ips.size() >= 1);
    3010              : 
    3011            1 :             addr::addr & a(ips[0].get_from());
    3012            1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    3013            1 :             CATCH_REQUIRE(s >= 0);
    3014            1 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    3015              : 
    3016            1 :             CATCH_REQUIRE(a.connect(s) == -1);
    3017              : 
    3018              :             // get socket info from the other side (peer == true)
    3019              :             //
    3020            1 :             addr::addr b;
    3021            1 :             CATCH_REQUIRE_THROWS_AS(b.set_from_socket(s, true), addr::addr_io_error);
    3022            1 :             CATCH_REQUIRE_FALSE(b.is_ipv4());
    3023            1 :             CATCH_REQUIRE_FALSE(b.get_family() == AF_INET);
    3024            1 :             CATCH_REQUIRE(b.get_family() == AF_INET6);
    3025            1 :             CATCH_REQUIRE(b.to_ipv6_string(addr::STRING_IP_ADDRESS)    == "::");
    3026            1 :             CATCH_REQUIRE(b.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "::");
    3027              : 
    3028              :             // in this case we know what the port is since we specified
    3029              :             // that when connecting
    3030              :             //
    3031            1 :             CATCH_REQUIRE(b.get_port() == 0);
    3032              : 
    3033              :             // now try this side (peer == false)
    3034              :             //
    3035            1 :             addr::addr c;
    3036            1 :             c.set_from_socket(s, false);
    3037            1 :             CATCH_REQUIRE_FALSE(c.is_ipv4());
    3038            1 :             CATCH_REQUIRE_FALSE(c.get_family() == AF_INET);
    3039            1 :             CATCH_REQUIRE(c.get_family() == AF_INET6);
    3040            1 :             CATCH_REQUIRE(c.to_ipv6_string(addr::STRING_IP_ADDRESS)    == "::");
    3041            1 :             CATCH_REQUIRE(c.to_ipv4or6_string(addr::STRING_IP_ADDRESS) == "::");
    3042              : 
    3043              :             // we cannot be sure of the port, there is a range we could
    3044              :             // test better (more constraining) but for this test is
    3045              :             // certainly does not matter much; it has to be more than
    3046              :             // 1023, though
    3047              :             //
    3048            1 :             CATCH_REQUIRE(c.get_port() == 0);
    3049            1 :         }
    3050            3 :         CATCH_END_SECTION()
    3051            3 :     }
    3052            3 : }
    3053              : 
    3054              : 
    3055            3 : CATCH_TEST_CASE("ipv6::udp", "[ipv6]")
    3056              : {
    3057            3 :     constexpr int const TEST_PORT(4004);
    3058            3 :     constexpr int const TEST_PROTOCOL(IPPROTO_UDP);
    3059            3 :     constexpr int const TEST_COUNT(10);
    3060              : 
    3061            3 :     CATCH_START_SECTION("ipv6::udp: sendto() and recvfrom()")
    3062              :     {
    3063              :         class sr
    3064              :         {
    3065              :         public:
    3066            1 :             sr()
    3067            1 :             {
    3068            1 :                 f_a.set_protocol(TEST_PROTOCOL);
    3069            1 :                 f_a.set_ipv6_loopback();
    3070            1 :                 f_a.set_port(TEST_PORT);
    3071            1 :                 f_sa = f_a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE);
    3072            1 :                 CATCH_REQUIRE(f_sa != -1);
    3073              : 
    3074            1 :                 f_b.set_protocol(TEST_PROTOCOL);
    3075            1 :                 f_b.set_ipv6_loopback();
    3076            1 :                 f_b.set_port(TEST_PORT);
    3077            1 :                 f_sb = f_b.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE);
    3078            1 :                 CATCH_REQUIRE(f_sb != -1);
    3079            1 :                 f_b.bind(f_sb); // the receive has to be bound
    3080              : 
    3081           11 :                 for(int i(0); i < TEST_COUNT; ++i)
    3082              :                 {
    3083           10 :                     std::size_t const size(rand() % 350 + 50);
    3084           10 :                     f_buf[i].resize(size);
    3085         2099 :                     for(std::size_t idx(0); idx < size; ++idx)
    3086              :                     {
    3087         2089 :                         f_buf[i][idx] = rand();
    3088              :                     }
    3089              :                 }
    3090            1 :             }
    3091              : 
    3092            1 :             void run()
    3093              :             {
    3094            1 :                 int client_port(-1);
    3095           11 :                 for(int i(0); i < TEST_COUNT; ++i)
    3096              :                 {
    3097           10 :                     sendto(i);
    3098              : 
    3099           30 :                     std::vector<std::uint8_t> bb(f_buf[i].size());
    3100           10 :                     int const r(f_b.recvfrom(f_sb, reinterpret_cast<char *>(bb.data()), bb.size()));
    3101           10 :                     if(r == -1)
    3102              :                     {
    3103            0 :                         int const e(errno);
    3104            0 :                         std::cerr << "--- recvfrom() returned an error: " << strerror(e) << std::endl;
    3105            0 :                         return;
    3106              :                     }
    3107              : 
    3108           10 :                     CATCH_REQUIRE(r == static_cast<int>(f_buf[i].size()));
    3109           10 :                     CATCH_REQUIRE(f_buf[i] == bb);
    3110           10 :                     CATCH_REQUIRE_FALSE(f_b.is_ipv4());
    3111           10 :                     if(client_port == -1)
    3112              :                     {
    3113            1 :                         client_port = f_b.get_port();
    3114              :                     }
    3115              :                     else
    3116              :                     {
    3117              :                         // the ephemeral port does not change once we sent
    3118              :                         // the first packet
    3119              :                         //
    3120            9 :                         CATCH_REQUIRE(f_b.get_port() == client_port);
    3121              :                     }
    3122           10 :                     CATCH_REQUIRE(f_b.get_network_type() == addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    3123           10 :                 }
    3124              :             }
    3125              : 
    3126           10 :             void sendto(int idx)
    3127              :             {
    3128           10 :                 int const r(f_a.sendto(f_sa, reinterpret_cast<char const *>(f_buf[idx].data()), f_buf[idx].size()));
    3129           10 :                 if(r == -1)
    3130              :                 {
    3131            0 :                     int const e(errno);
    3132            0 :                     std::cerr << "--- sendto() returned an error: " << strerror(e) << std::endl;
    3133            0 :                     return;
    3134              :                 }
    3135           10 :                 CATCH_REQUIRE(r == static_cast<int>(f_buf[idx].size()));
    3136              :             }
    3137              : 
    3138              :             addr::addr                  f_a = addr::addr();
    3139              :             addr::addr                  f_b = addr::addr();
    3140              :             int                         f_sa = -1;
    3141              :             int                         f_sb = -1;
    3142              :             std::vector<std::uint8_t>   f_buf[TEST_COUNT] = {};
    3143              :         };
    3144              : 
    3145            1 :         sr run;
    3146            1 :         run.run();
    3147            1 :     }
    3148            3 :     CATCH_END_SECTION()
    3149              : 
    3150            3 :     CATCH_START_SECTION("ipv6::udp: sendto() with wrong protocol")
    3151              :     {
    3152            1 :         addr::addr a;
    3153            1 :         a.set_protocol(IPPROTO_TCP);
    3154            1 :         a.set_ipv6_loopback();
    3155            1 :         a.set_port(TEST_PORT);
    3156            1 :         int sa(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
    3157            1 :         CATCH_REQUIRE(sa != -1);
    3158              : 
    3159            1 :         char buf[256];
    3160            1 :         int const r(a.sendto(sa, buf, sizeof(buf)));
    3161            1 :         int const e(errno);
    3162            1 :         CATCH_REQUIRE(r == -1);
    3163            1 :         CATCH_REQUIRE(e == EINVAL);
    3164              : 
    3165            1 :         close(sa);
    3166            1 :     }
    3167            3 :     CATCH_END_SECTION()
    3168              : 
    3169            3 :     CATCH_START_SECTION("ipv6::udp: recvfrom() with wrong protocol")
    3170              :     {
    3171            1 :         addr::addr a;
    3172            1 :         a.set_protocol(IPPROTO_TCP);
    3173            1 :         a.set_ipv6_loopback();
    3174            1 :         a.set_port(TEST_PORT);
    3175            1 :         int sa(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
    3176            1 :         CATCH_REQUIRE(sa != -1);
    3177            1 :         a.bind(sa); // the receive has to be bound
    3178              : 
    3179            1 :         char buf[256];
    3180            1 :         int const r(a.recvfrom(sa, buf, sizeof(buf)));
    3181            1 :         int const e(errno);
    3182            1 :         CATCH_REQUIRE(r == -1);
    3183            1 :         CATCH_REQUIRE(e == EINVAL);
    3184              : 
    3185            1 :         close(sa);
    3186            1 :     }
    3187            3 :     CATCH_END_SECTION()
    3188            3 : }
    3189              : 
    3190              : 
    3191              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions