LCOV - code coverage report
Current view: top level - tests - test_addr_ipv6.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 949 962 98.6 %
Date: 2019-09-02 12:15:29 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2019  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // Project: https://snapwebsites.org/project/libaddr
       4             : //
       5             : // Permission is hereby granted, free of charge, to any
       6             : // person obtaining a copy of this software and
       7             : // associated documentation files (the "Software"), to
       8             : // deal in the Software without restriction, including
       9             : // without limitation the rights to use, copy, modify,
      10             : // merge, publish, distribute, sublicense, and/or sell
      11             : // copies of the Software, and to permit persons to whom
      12             : // the Software is furnished to do so, subject to the
      13             : // following conditions:
      14             : //
      15             : // The above copyright notice and this permission notice
      16             : // shall be included in all copies or substantial
      17             : // portions of the Software.
      18             : //
      19             : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      20             : // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      21             : // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      22             : // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      23             : // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      24             : // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      25             : // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      26             : // ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      27             : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      28             : // SOFTWARE.
      29             : 
      30             : 
      31             : /** \file
      32             :  * \brief Test the IPv6 interface.
      33             :  *
      34             :  * These test verify that the IPv6 side of things function as expected.
      35             :  *
      36             :  * Note that some of the tests between the IPv4 and IPv6 overlap. Here
      37             :  * you mainly find the IPv6 side of things.
      38             :  *
      39             :  * Also, the IPv6 test include a certain number of default/global
      40             :  * test because by default the addr class implements an IPv6 object.
      41             :  */
      42             : 
      43             : // self
      44             : //
      45             : #include "test_addr_main.h"
      46             : 
      47             : // addr lib
      48             : //
      49             : #include "libaddr/iface.h"
      50             : 
      51             : 
      52             : 
      53             : 
      54             : /** \brief Details used by the addr class implementation.
      55             :  *
      56             :  * We have a function to check whether an address is part of
      57             :  * the interfaces of your computer. This check requires the
      58             :  * use of a `struct ifaddrs` and as such it requires to
      59             :  * delete that structure. We define a deleter for that
      60             :  * strucure here.
      61             :  */
      62             : namespace
      63             : {
      64             : 
      65             : /** \brief Delete an ifaddrs structure.
      66             :  *
      67             :  * This deleter is used to make sure all the ifaddrs get released when
      68             :  * an exception occurs or the function using such exists.
      69             :  *
      70             :  * \param[in] ia  The ifaddrs structure to free.
      71             :  */
      72           3 : void socket_deleter(int * s)
      73             : {
      74           3 :     close(*s);
      75           3 : }
      76             : 
      77             : 
      78             : }
      79             : // no name namespace
      80             : 
      81             : 
      82             : 
      83          16 : CATCH_TEST_CASE( "ipv6::invalid_input", "[ipv6]" )
      84             : {
      85          28 :     CATCH_GIVEN("addr()")
      86             :     {
      87           1 :         addr::addr a;
      88             : 
      89           2 :         CATCH_SECTION("set IPv6 with an invalid family")
      90             :         {
      91           1 :             struct sockaddr_in6 in6 = sockaddr_in6();
      92           0 :             do
      93             :             {
      94           1 :                 in6.sin6_family = rand();
      95             :             }
      96           1 :             while(in6.sin6_family == AF_INET6);
      97           1 :             in6.sin6_port = rand();
      98           9 :             for(int idx(0); idx < 8; ++idx)
      99             :             {
     100           8 :                 in6.sin6_addr.s6_addr16[idx] = rand();
     101             :             }
     102           1 :             CATCH_REQUIRE_THROWS_AS(a.set_ipv6(in6), addr::addr_invalid_argument);
     103           1 :             CATCH_REQUIRE_THROWS_AS(addr::addr(in6), addr::addr_invalid_argument);
     104             :         }
     105             :     }
     106             : 
     107          28 :     CATCH_GIVEN("addr_parser() with IPv6 addresses")
     108             :     {
     109           6 :         CATCH_SECTION("bad address")
     110             :         {
     111           2 :             addr::addr_parser p;
     112           2 :             addr::addr_range::vector_t ips(p.parse("[{bad-ip}]"));
     113           1 :             CATCH_REQUIRE(p.has_errors());
     114           1 :             CATCH_REQUIRE(p.error_count() == 1);
     115           1 :             CATCH_REQUIRE(p.error_messages() == "Invalid address in \"{bad-ip}\" error -2 -- Name or service not known (errno: 2 -- No such file or directory).\n");
     116           1 :             CATCH_REQUIRE(ips.size() == 0);
     117             :         }
     118             : 
     119           6 :         CATCH_SECTION("missing ']'")
     120             :         {
     121           2 :             addr::addr_parser p;
     122           2 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7"));
     123           1 :             CATCH_REQUIRE(p.has_errors());
     124           1 :             CATCH_REQUIRE(p.error_count() == 1);
     125           1 :             CATCH_REQUIRE(p.error_messages() == "IPv6 is missing the ']' ([1:2:3:4:5:6:7).\n");
     126           1 :             CATCH_REQUIRE(ips.size() == 0);
     127             :         }
     128             : 
     129           6 :         CATCH_SECTION("required address")
     130             :         {
     131           2 :             addr::addr_parser p;
     132           1 :             p.set_protocol(IPPROTO_TCP);
     133           1 :             p.set_allow(addr::addr_parser::flag_t::REQUIRED_ADDRESS, true);
     134           2 :             addr::addr_range::vector_t ips(p.parse("[]"));
     135           1 :             CATCH_REQUIRE(p.has_errors());
     136           1 :             CATCH_REQUIRE(p.error_count() == 1);
     137           1 :             CATCH_REQUIRE(p.error_messages() == "Required address is missing.\n");
     138           1 :             CATCH_REQUIRE(ips.size() == 0);
     139             :         }
     140             :     }
     141             : 
     142          28 :     CATCH_GIVEN("addr_parser() with IPv4 ports")
     143             :     {
     144           4 :         CATCH_SECTION("required port")
     145             :         {
     146             :             // optional + required -> required
     147             :             {
     148           2 :                 addr::addr_parser p;
     149           1 :                 p.set_protocol(IPPROTO_TCP);
     150           1 :                 p.set_allow(addr::addr_parser::flag_t::REQUIRED_PORT, true);
     151           2 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
     152           1 :                 CATCH_REQUIRE(p.has_errors());
     153           1 :                 CATCH_REQUIRE(p.error_count() == 1);
     154           1 :                 CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
     155           1 :                 CATCH_REQUIRE(ips.size() == 0);
     156             :             }
     157             : 
     158             :             // only required -> required just the same
     159             :             {
     160           2 :                 addr::addr_parser p;
     161           1 :                 p.set_protocol(IPPROTO_TCP);
     162           1 :                 p.set_allow(addr::addr_parser::flag_t::PORT, false);
     163           1 :                 p.set_allow(addr::addr_parser::flag_t::REQUIRED_PORT, true);
     164           2 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
     165           1 :                 CATCH_REQUIRE(p.has_errors());
     166           1 :                 CATCH_REQUIRE(p.error_count() == 1);
     167           1 :                 CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
     168           1 :                 CATCH_REQUIRE(ips.size() == 0);
     169             :             }
     170             :         }
     171             : 
     172           4 :         CATCH_SECTION("port not allowed")
     173             :         {
     174             :             {
     175           2 :                 addr::addr_parser p;
     176           1 :                 p.set_protocol(IPPROTO_TCP);
     177           1 :                 p.set_allow(addr::addr_parser::flag_t::PORT, false);
     178           2 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:123"));
     179           1 :                 CATCH_REQUIRE(p.has_errors());
     180           1 :                 CATCH_REQUIRE(p.error_count() == 1);
     181           1 :                 CATCH_REQUIRE(p.error_messages() == "Port not allowed ([1:2:3:4:5:6:7:8]:123).\n");
     182           1 :                 CATCH_REQUIRE(ips.size() == 0);
     183             :             }
     184             : 
     185             :             {
     186           2 :                 addr::addr_parser p;
     187           1 :                 p.set_protocol(IPPROTO_TCP);
     188           1 :                 p.set_allow(addr::addr_parser::flag_t::PORT, false);
     189           2 :                 addr::addr_range::vector_t ips(p.parse("1:2:3:4:5:6:7:8:123.5"));
     190           1 :                 CATCH_REQUIRE(p.has_errors());
     191           1 :                 CATCH_REQUIRE(p.error_count() == 1);
     192           1 :                 CATCH_REQUIRE(p.error_messages() == "Port not allowed (1:2:3:4:5:6:7:8:123.5).\n");
     193           1 :                 CATCH_REQUIRE(ips.size() == 0);
     194             :             }
     195             :         }
     196             :     }
     197             : 
     198          28 :     CATCH_GIVEN("addr_parser() with invalid masks")
     199             :     {
     200          16 :         CATCH_SECTION("really large numbers (over 1000)")
     201             :         {
     202           6 :             for(int idx(0); idx < 5; ++idx)
     203             :             {
     204           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     205           5 :                 int const port(rand() & 0xFFFF);
     206           5 :                 int const mask((rand() & 0xFF) + 1001);
     207          10 :                 addr::addr_parser p;
     208           5 :                 p.set_protocol(proto);
     209           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     210          10 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
     211           5 :                 CATCH_REQUIRE(p.has_errors());
     212           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     213           5 :                 CATCH_REQUIRE(p.error_messages() == "Mask number too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
     214           5 :                 CATCH_REQUIRE(ips.size() == 0);
     215             :             }
     216             : 
     217             :             // in case the number is between square brackets it looks like
     218             :             // an IPv4 to getaddrinfo() so we get a different error...
     219             :             // (i.e. the '[' is not a digit so we do not get the "too large"
     220             :             // error...)
     221             :             //
     222           6 :             for(int idx(0); idx < 5; ++idx)
     223             :             {
     224           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     225           5 :                 int const port(rand() & 0xFFFF);
     226           5 :                 int const mask((rand() & 0xFF) + 1001);
     227          10 :                 addr::addr_parser p;
     228           5 :                 p.set_protocol(proto);
     229           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     230          10 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[" + std::to_string(mask) + "]"));
     231           5 :                 CATCH_REQUIRE(p.has_errors());
     232           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     233           5 :                 CATCH_REQUIRE(p.error_messages() == "Incompatible address between the address and mask address (first was an IPv6 second an IPv4).\n");
     234           5 :                 CATCH_REQUIRE(ips.size() == 0);
     235             :             }
     236             : 
     237             :             // an empty address with a mask too large gets us to another place
     238             :             //
     239           6 :             for(int idx(0); idx < 5; ++idx)
     240             :             {
     241           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     242           5 :                 int const port(rand() & 0xFFFF);
     243           5 :                 int const mask((rand() & 0xFF) + 1001);
     244          10 :                 addr::addr_parser p;
     245           5 :                 p.set_protocol(proto);
     246           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     247          10 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask)));
     248           5 :                 CATCH_REQUIRE(p.has_errors());
     249           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     250           5 :                 CATCH_REQUIRE(p.error_messages() == "Mask number too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
     251           5 :                 CATCH_REQUIRE(ips.size() == 0);
     252             :             }
     253             : 
     254             :             // an empty address with a mask too large gets us to another place
     255             :             //
     256           6 :             for(int idx(0); idx < 5; ++idx)
     257             :             {
     258           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     259           5 :                 int const port(rand() & 0xFFFF);
     260           5 :                 int const mask((rand() & 0xFF));
     261          10 :                 addr::addr_parser p;
     262           5 :                 p.set_protocol(proto);
     263           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     264          10 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask) + "q"));
     265           5 :                 CATCH_REQUIRE(p.has_errors());
     266           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     267           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");
     268           5 :                 CATCH_REQUIRE(ips.size() == 0);
     269             :             }
     270             :         }
     271             : 
     272          16 :         CATCH_SECTION("ipv6 mask is limited between 0 and 128")
     273             :         {
     274           6 :             for(int idx(0); idx < 5; ++idx)
     275             :             {
     276           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     277           5 :                 int const port(rand() & 0xFFFF);
     278           5 :                 int const mask((rand() & 0xFF) + 129);
     279          10 :                 addr::addr_parser p;
     280           5 :                 p.set_protocol(proto);
     281           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     282          10 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
     283           5 :                 CATCH_REQUIRE(p.has_errors());
     284           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     285           5 :                 CATCH_REQUIRE(p.error_messages() == "Unsupported mask size (" + std::to_string(mask) + ", expected 128 at the most for an IPv6).\n");
     286           5 :                 CATCH_REQUIRE(ips.size() == 0);
     287             :             }
     288             :         }
     289             : 
     290          16 :         CATCH_SECTION("ipv6 mask cannot use name")
     291             :         {
     292           6 :             for(int idx(0); idx < 5; ++idx)
     293             :             {
     294           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     295           5 :                 int const port(rand() & 0xFFFF);
     296          10 :                 addr::addr_parser p;
     297           5 :                 p.set_protocol(proto);
     298           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     299          10 :                 addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[localhost]"));
     300           5 :                 CATCH_REQUIRE(p.has_errors());
     301           5 :                 CATCH_REQUIRE(p.error_count() == 1);
     302           5 :                 CATCH_REQUIRE(p.error_messages() == "Invalid mask in \"/[localhost]\", error -2 -- Name or service not known (errno: 0 -- Success).\n");
     303           5 :                 CATCH_REQUIRE(ips.size() == 0);
     304             :             }
     305             :         }
     306             : 
     307          16 :         CATCH_SECTION("ipv6 mask must be between '[...]'")
     308             :         {
     309           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     310           1 :             int const port(rand() & 0xFFFF);
     311           2 :             addr::addr_parser p;
     312           1 :             p.set_protocol(proto);
     313           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     314           2 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/::3"));
     315           1 :             CATCH_REQUIRE(p.has_errors());
     316           1 :             CATCH_REQUIRE(p.error_count() == 1);
     317           1 :             CATCH_REQUIRE(p.error_messages() == "The address uses the IPv6 syntax, the mask cannot use IPv4.\n");
     318           1 :             CATCH_REQUIRE(ips.size() == 0);
     319             :         }
     320             : 
     321          16 :         CATCH_SECTION("ipv6 mask missing the ']'")
     322             :         {
     323           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     324           1 :             int const port(rand() & 0xFFFF);
     325           2 :             addr::addr_parser p;
     326           1 :             p.set_protocol(proto);
     327           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     328           2 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[::3"));
     329           1 :             CATCH_REQUIRE(p.has_errors());
     330           1 :             CATCH_REQUIRE(p.error_count() == 1);
     331           1 :             CATCH_REQUIRE(p.error_messages() == "The IPv6 mask is missing the ']' ([::3).\n");
     332           1 :             CATCH_REQUIRE(ips.size() == 0);
     333             :         }
     334             : 
     335          16 :         CATCH_SECTION("ipv6 mask with an ipv4 in the '[...]'")
     336             :         {
     337           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     338           1 :             int const port(rand() & 0xFFFF);
     339           2 :             addr::addr_parser p;
     340           1 :             p.set_protocol(proto);
     341           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     342           2 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[1.2.3.4]"));
     343           1 :             CATCH_REQUIRE(p.has_errors());
     344           1 :             CATCH_REQUIRE(p.error_count() == 1);
     345           1 :             CATCH_REQUIRE(p.error_messages() == "Incompatible address between the address and mask address (first was an IPv6 second an IPv4).\n");
     346           1 :             CATCH_REQUIRE(ips.size() == 0);
     347             :         }
     348             : 
     349          16 :         CATCH_SECTION("verify default mask")
     350             :         {
     351           2 :             addr::addr_parser p;
     352             : 
     353           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
     354           1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     355           1 :             CATCH_REQUIRE(p.get_default_address6() == "");
     356             : 
     357           1 :             p.set_default_address("[1:7:1:7:1:7:1:7]");
     358           1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     359           1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     360             : 
     361           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
     362           1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     363           1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     364             : 
     365           1 :             p.set_default_address("12.55.1.9");
     366           1 :             CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
     367           1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     368             : 
     369           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
     370           1 :             CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
     371           1 :             CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
     372             : 
     373           1 :             p.set_default_address("");
     374           1 :             CATCH_REQUIRE(p.get_default_address4() == "");
     375           1 :             CATCH_REQUIRE(p.get_default_address6() == "");
     376             :         }
     377             : 
     378          16 :         CATCH_SECTION("verify default mask")
     379             :         {
     380           2 :             addr::addr_parser p;
     381             : 
     382           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
     383           1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     384           1 :             CATCH_REQUIRE(p.get_default_mask6() == "");
     385             : 
     386           1 :             p.set_default_mask("[1:7:1:7:1:7:1:7]");
     387           1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     388           1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     389             : 
     390           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
     391           1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     392           1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     393             : 
     394           1 :             p.set_default_mask("12.55.1.9");
     395           1 :             CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
     396           1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     397             : 
     398           1 :             CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
     399           1 :             CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
     400           1 :             CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
     401             : 
     402           1 :             p.set_default_mask("");
     403           1 :             CATCH_REQUIRE(p.get_default_mask4() == "");
     404           1 :             CATCH_REQUIRE(p.get_default_mask6() == "");
     405             :         }
     406             :     }
     407          14 : }
     408             : 
     409             : 
     410           8 : CATCH_TEST_CASE( "ipv6::address", "[ipv6]" )
     411             : {
     412          12 :     CATCH_GIVEN("addr() with an IPv6")
     413             :     {
     414           3 :         addr::addr a;
     415             : 
     416           6 :         CATCH_SECTION("set_ipv6() / get_ipv6()")
     417             :         {
     418          11 :             for(int idx(0); idx < 10; ++idx)
     419             :             {
     420          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
     421          10 :                 in6.sin6_family = AF_INET6;
     422          10 :                 in6.sin6_port = htons(rand());
     423          10 :                 in6.sin6_addr.s6_addr16[0] = rand();
     424          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
     425          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
     426          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
     427          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
     428          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
     429          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
     430          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
     431             : 
     432             :                 // verify network type
     433             :                 //
     434          10 :                 a.set_ipv6(in6);
     435             : 
     436             :                 // test constructor
     437             :                 //
     438          10 :                 addr::addr b(in6);
     439             :                 struct sockaddr_in6 out6;
     440          10 :                 b.get_ipv6(out6);
     441          10 :                 CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
     442             : 
     443             :                 // test set
     444             :                 //
     445          10 :                 a.set_ipv6(in6);
     446          10 :                 a.get_ipv6(out6);
     447          10 :                 CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
     448             :             }
     449             :         }
     450             : 
     451           6 :         CATCH_SECTION("set_ipv6() check to_ipv6_string()")
     452             :         {
     453          11 :             for(int idx(0); idx < 10; ++idx)
     454             :             {
     455          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
     456          10 :                 in6.sin6_family = AF_INET6;
     457          10 :                 in6.sin6_port = htons(rand());
     458          90 :                 for(int j(0); j < 8; ++j)
     459             :                 {
     460             :                     // avoid any zeroes so that way we do not have
     461             :                     // to handle the "::" syntax
     462           0 :                     do
     463             :                     {
     464          80 :                         in6.sin6_addr.s6_addr16[j] = rand();
     465             :                     }
     466          80 :                     while(in6.sin6_addr.s6_addr16[j] == 0);
     467             :                 }
     468             : 
     469          20 :                 std::stringstream ip_buf;
     470          10 :                 ip_buf << std::hex
     471          20 :                        << ntohs(in6.sin6_addr.s6_addr16[0])
     472          10 :                        << ":"
     473          20 :                        << ntohs(in6.sin6_addr.s6_addr16[1])
     474          10 :                        << ":"
     475          20 :                        << ntohs(in6.sin6_addr.s6_addr16[2])
     476          10 :                        << ":"
     477          20 :                        << ntohs(in6.sin6_addr.s6_addr16[3])
     478          10 :                        << ":"
     479          20 :                        << ntohs(in6.sin6_addr.s6_addr16[4])
     480          10 :                        << ":"
     481          20 :                        << ntohs(in6.sin6_addr.s6_addr16[5])
     482          10 :                        << ":"
     483          20 :                        << ntohs(in6.sin6_addr.s6_addr16[6])
     484          10 :                        << ":"
     485          20 :                        << ntohs(in6.sin6_addr.s6_addr16[7]);
     486          20 :                 std::string const ip(ip_buf.str());
     487             : 
     488          20 :                 std::string port_str(std::to_string(static_cast<int>(htons(in6.sin6_port))));
     489             : 
     490             :                 // check IPv6 as a string
     491             :                 //
     492          10 :                 a.set_ipv6(in6);
     493          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)          == ip);
     494          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS)      == "[" + ip + "]");
     495          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT)          == "[" + ip + "]:" + port_str);
     496          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_MASK)          == ip + "/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); // will change to 128 at some point
     497          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS_MASK) == "[" + ip + "]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     498          10 :                 CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL)           == "[" + ip + "]:" + port_str + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     499             :             }
     500             :         }
     501             : 
     502           6 :         CATCH_SECTION("name of various IPs")
     503             :         {
     504           1 :             struct sockaddr_in6 in6 = sockaddr_in6();
     505           1 :             in6.sin6_family = AF_INET6;
     506           1 :             in6.sin6_port = htons(rand());
     507             : 
     508             :             // verify network type
     509             :             //
     510           1 :             a.set_ipv6(in6);
     511           1 :             CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (TCP)
     512             : 
     513           1 :             a.set_protocol(IPPROTO_UDP);
     514           1 :             CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (UDP)
     515             : 
     516           1 :             in6 = sockaddr_in6();
     517           1 :             in6.sin6_family = AF_INET6;
     518           1 :             in6.sin6_port = htons(rand());
     519           1 :             in6.sin6_addr.s6_addr16[7] = htons(1);
     520           1 :             a.set_ipv6(in6);
     521             :             char hostname[HOST_NAME_MAX + 1];
     522           1 :             hostname[HOST_NAME_MAX] = '\0';
     523           1 :             CATCH_REQUIRE(gethostname(hostname, sizeof(hostname)) == 0);
     524           1 :             CATCH_REQUIRE(hostname[0] != '\0');
     525           2 :             std::string localhost(a.get_name());
     526           1 :             bool const localhost_flag(localhost == hostname || localhost == "ip6-localhost");
     527           1 :             CATCH_REQUIRE(localhost_flag);
     528             : 
     529           1 :             CATCH_REQUIRE(addr::find_addr_interface(a, false) != nullptr);
     530             :         }
     531             :     }
     532             : 
     533          12 :     CATCH_GIVEN("addr_parser() with IPv6 addresses")
     534             :     {
     535           6 :         CATCH_SECTION("verify basics")
     536             :         {
     537           2 :             addr::addr_parser p;
     538           1 :             p.set_protocol(IPPROTO_TCP);
     539           2 :             addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
     540           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     541           1 :             CATCH_REQUIRE(ips.size() == 1);
     542           1 :             addr::addr_range const & r(ips[0]);
     543           1 :             CATCH_REQUIRE(r.has_from());
     544           1 :             CATCH_REQUIRE_FALSE(r.has_to());
     545           1 :             CATCH_REQUIRE_FALSE(r.is_range());
     546           1 :             CATCH_REQUIRE_FALSE(r.is_empty());
     547           1 :             addr::addr f(r.get_from());
     548           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     549           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "1:2:3:4:5:6:7:8");
     550           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[1:2:3:4:5:6:7:8]");
     551           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "1:2:3:4:5:6:7:8");
     552           1 :             CATCH_REQUIRE(f.get_port() == 0);
     553           1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     554           1 :             CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
     555           1 :             uint8_t mask[16] = {};
     556           1 :             f.get_mask(mask);
     557          17 :             for(int idx(0); idx < 16; ++idx)
     558             :             {
     559          16 :                 CATCH_REQUIRE(mask[idx] == 255);
     560             :             }
     561             :         }
     562             : 
     563           6 :         CATCH_SECTION("default address")
     564             :         {
     565           2 :             addr::addr_parser p;
     566           1 :             p.set_protocol(IPPROTO_TCP);
     567           1 :             p.set_default_address("5:5:5:5:5:5:5:5");
     568           2 :             addr::addr_range::vector_t ips(p.parse(""));
     569           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     570           1 :             CATCH_REQUIRE(ips.size() == 1);
     571           1 :             addr::addr_range const & r(ips[0]);
     572           1 :             CATCH_REQUIRE(r.has_from());
     573           1 :             CATCH_REQUIRE_FALSE(r.has_to());
     574           1 :             CATCH_REQUIRE_FALSE(r.is_range());
     575           1 :             CATCH_REQUIRE_FALSE(r.is_empty());
     576           1 :             addr::addr f(r.get_from());
     577           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     578           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:5:5:5:5:5:5:5");
     579           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[5:5:5:5:5:5:5:5]");
     580           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:5:5:5:5:5:5:5");
     581           1 :             CATCH_REQUIRE(f.get_port() == 0);
     582           1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     583           1 :             CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
     584             :         }
     585             : 
     586           6 :         CATCH_SECTION("address, not port allowed")
     587             :         {
     588             :             // specific address with a default
     589             :             {
     590           2 :                 addr::addr_parser p;
     591           1 :                 p.set_allow(addr::addr_parser::flag_t::PORT, false);
     592           1 :                 p.set_protocol(IPPROTO_TCP);
     593           1 :                 p.set_default_address("8:7:6:5:4:3:2:1");
     594           2 :                 addr::addr_range::vector_t ips(p.parse("[9:9:9:9:4:3:2:1]"));
     595           1 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     596           1 :                 CATCH_REQUIRE(ips.size() == 1);
     597           1 :                 addr::addr_range const & r(ips[0]);
     598           1 :                 CATCH_REQUIRE(r.has_from());
     599           1 :                 CATCH_REQUIRE_FALSE(r.has_to());
     600           1 :                 CATCH_REQUIRE_FALSE(r.is_range());
     601           1 :                 CATCH_REQUIRE_FALSE(r.is_empty());
     602           1 :                 addr::addr f(r.get_from());
     603           1 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     604           1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "9:9:9:9:4:3:2:1");
     605           1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[9:9:9:9:4:3:2:1]");
     606           1 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "9:9:9:9:4:3:2:1");
     607           1 :                 CATCH_REQUIRE(f.get_port() == 0);
     608           1 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     609           1 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
     610             :             }
     611             : 
     612             :             // only a default address
     613             :             {
     614           2 :                 addr::addr_parser p;
     615           1 :                 p.set_allow(addr::addr_parser::flag_t::PORT, false);
     616           1 :                 p.set_protocol(IPPROTO_TCP);
     617           1 :                 p.set_default_address("5:1:6:2:7:3:8:4");
     618           2 :                 addr::addr_range::vector_t ips(p.parse(""));
     619           1 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     620           1 :                 CATCH_REQUIRE(ips.size() == 1);
     621           1 :                 addr::addr_range const & r(ips[0]);
     622           1 :                 CATCH_REQUIRE(r.has_from());
     623           1 :                 CATCH_REQUIRE_FALSE(r.has_to());
     624           1 :                 CATCH_REQUIRE_FALSE(r.is_range());
     625           1 :                 CATCH_REQUIRE_FALSE(r.is_empty());
     626           1 :                 addr::addr f(r.get_from());
     627           1 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     628           1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:1:6:2:7:3:8:4");
     629           1 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[5:1:6:2:7:3:8:4]");
     630           1 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:1:6:2:7:3:8:4");
     631           1 :                 CATCH_REQUIRE(f.get_port() == 0);
     632           1 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     633           1 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
     634             :             }
     635             :         }
     636             :     }
     637           6 : }
     638             : 
     639             : 
     640           7 : CATCH_TEST_CASE( "ipv6::ports", "[ipv6]" )
     641             : {
     642             :     // by default addr() is an IPv6 address so we test the basic port
     643             :     // functions here, although it could be in a common place instead...
     644             :     //
     645          10 :     CATCH_GIVEN("addr()")
     646             :     {
     647           3 :         addr::addr a;
     648             : 
     649           6 :         CATCH_SECTION("default port")
     650             :         {
     651           1 :             CATCH_REQUIRE(a.get_port() == 0);
     652             :         }
     653             : 
     654           6 :         CATCH_SECTION("set_port()")
     655             :         {
     656             :             // setup a random port to start with
     657             :             //
     658           1 :             int const start_port(rand() & 0xFFFF);
     659           1 :             a.set_port(start_port);
     660             : 
     661             :             // test 100 invalid ports
     662             :             //
     663         101 :             for(int idx(0); idx < 100; ++idx)
     664             :             {
     665             :                 // first try a negative port
     666             :                 int port_too_small;
     667           0 :                 do
     668             :                 {
     669         100 :                     port_too_small = -(rand() & 0xFFFF);
     670             :                 }
     671         100 :                 while(port_too_small == 0);
     672         100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_small), addr::addr_invalid_argument);
     673             : 
     674             :                 // first try a negative port
     675         100 :                 int const port_too_large = (rand() & 0xFFFF) + 65536;
     676         100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_large), addr::addr_invalid_argument);
     677             : 
     678             :                 // make sure port does not get modified on errors
     679         100 :                 CATCH_REQUIRE(a.get_port() == start_port);
     680             :             }
     681             : 
     682             :             // test all ports
     683             :             //
     684       65537 :             for(int port(0); port < 65536; ++port)
     685             :             {
     686       65536 :                 a.set_port(port);
     687             : 
     688       65536 :                 CATCH_REQUIRE(a.get_port() == port);
     689             :             }
     690             :         }
     691             : 
     692           6 :         CATCH_SECTION("known ports to test get_service()")
     693             :         {
     694           1 :             a.set_port(80);
     695           1 :             CATCH_REQUIRE(a.get_service() == "http");
     696             : 
     697           1 :             a.set_port(443);
     698           1 :             CATCH_REQUIRE(a.get_service() == "https");
     699             : 
     700             :             // again with UDP
     701             :             // 
     702           1 :             a.set_protocol(IPPROTO_UDP);
     703             : 
     704           1 :             a.set_port(80);
     705           1 :             CATCH_REQUIRE(a.get_service() == "http");
     706             : 
     707           1 :             a.set_port(443);
     708           1 :             CATCH_REQUIRE(a.get_service() == "https");
     709             :         }
     710             :     }
     711             : 
     712          10 :     CATCH_GIVEN("addr_parser() with IPv6 addresses and port")
     713             :     {
     714           4 :         CATCH_SECTION("verify port")
     715             :         {
     716       65537 :             for(int port(0); port < 65536; ++port)
     717             :             {
     718       65536 :                 int proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     719      131072 :                 addr::addr_parser p;
     720       65536 :                 p.set_protocol(proto);
     721      131072 :                 addr::addr_range::vector_t ips(p.parse("[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port)));
     722       65536 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     723       65536 :                 CATCH_REQUIRE(ips.size() == 1);
     724       65536 :                 addr::addr_range const & r(ips[0]);
     725       65536 :                 addr::addr f(r.get_from());
     726       65536 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     727       65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "ff01:2f3:f041:e301:f:10:11:12");
     728       65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[ff01:2f3:f041:e301:f:10:11:12]");
     729       65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
     730       65536 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
     731       65536 :                 CATCH_REQUIRE(f.get_port() == port);
     732       65536 :                 CATCH_REQUIRE(f.get_protocol() == proto);
     733       65536 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
     734             :             }
     735             :         }
     736             : 
     737           4 :         CATCH_SECTION("default address with various port")
     738             :         {
     739         101 :             for(int idx(0); idx < 100; ++idx)
     740             :             {
     741         100 :                 uint16_t const port(rand());
     742         200 :                 addr::addr_parser p;
     743         100 :                 p.set_protocol(IPPROTO_TCP);
     744         100 :                 p.set_default_address("ff02:23:f41:e31:20:30:40:50");
     745         200 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(static_cast<int>(port))));
     746         100 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     747         100 :                 CATCH_REQUIRE(ips.size() == 1);
     748         100 :                 addr::addr_range const & r(ips[0]);
     749         100 :                 CATCH_REQUIRE(r.has_from());
     750         100 :                 CATCH_REQUIRE_FALSE(r.has_to());
     751         100 :                 CATCH_REQUIRE_FALSE(r.is_range());
     752         100 :                 CATCH_REQUIRE_FALSE(r.is_empty());
     753         100 :                 addr::addr f(r.get_from());
     754         100 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     755         100 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
     756         100 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
     757         100 :                 CATCH_REQUIRE(f.get_port() == port);
     758         100 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     759         100 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
     760             :             }
     761             :         }
     762             :     }
     763           5 : }
     764             : 
     765             : 
     766          14 : CATCH_TEST_CASE( "ipv6::masks", "[ipv6]" )
     767             : {
     768          24 :     CATCH_GIVEN("addr()")
     769             :     {
     770             :         // technically, a default addr object represents and IPv6 so the
     771             :         // dealing with the mask without an IPv4 is done by IPv6 tests
     772             :         //
     773           3 :         addr::addr a;
     774             : 
     775           6 :         CATCH_SECTION("default mask")
     776             :         {
     777           1 :             uint8_t mask[16] = {};
     778           1 :             a.get_mask(mask);
     779          17 :             for(int idx(0); idx < 16; ++idx)
     780             :             {
     781          16 :                 CATCH_REQUIRE(mask[idx] == 255);
     782             :             }
     783             :         }
     784             : 
     785           6 :         CATCH_SECTION("set_mask()")
     786             :         {
     787             :             uint8_t mask[16], verify_mask[16];
     788           6 :             for(int idx(0); idx < 5; ++idx)
     789             :             {
     790          85 :                 for(int j(0); j < 16; ++j)
     791             :                 {
     792          80 :                     mask[j] = rand();
     793             :                 }
     794           5 :                 a.set_mask(mask);
     795           5 :                 a.get_mask(verify_mask);
     796          85 :                 for(int j(0); j < 16; ++j)
     797             :                 {
     798          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     799             :                 }
     800             : 
     801             :                 // verify that a copy does copy the mask as expected
     802             :                 //
     803           5 :                 addr::addr b(a);
     804           5 :                 b.get_mask(verify_mask);
     805          85 :                 for(int j(0); j < 16; ++j)
     806             :                 {
     807          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     808             :                 }
     809             :             }
     810             :         }
     811             : 
     812           6 :         CATCH_SECTION("set_mask()")
     813             :         {
     814             :             uint8_t mask[16];
     815             :             uint8_t verify_mask[16];
     816           6 :             for(int idx(0); idx < 5; ++idx)
     817             :             {
     818          85 :                 for(int j(0); j < 16; ++j)
     819             :                 {
     820          80 :                     mask[j] = rand();
     821             :                 }
     822           5 :                 a.set_mask(mask);
     823           5 :                 a.get_mask(verify_mask);
     824          85 :                 for(int j(0); j < 16; ++j)
     825             :                 {
     826          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     827          80 :                     verify_mask[j] = rand();
     828             :                 }
     829             : 
     830             :                 // verify that a copy does copy the mask as expected
     831             :                 //
     832           5 :                 addr::addr b(a);
     833           5 :                 b.get_mask(verify_mask);
     834          85 :                 for(int j(0); j < 16; ++j)
     835             :                 {
     836          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     837          80 :                     verify_mask[j] = rand();
     838             :                 }
     839             : 
     840             :                 // verify that copying inside a range works too
     841             :                 //
     842           5 :                 addr::addr_range r;
     843           5 :                 r.set_from(a);
     844           5 :                 r.get_from().get_mask(verify_mask);
     845          85 :                 for(int j(0); j < 16; ++j)
     846             :                 {
     847          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     848          80 :                     verify_mask[j] = rand();
     849             :                 }
     850             : 
     851             :                 // then that a range copy works as expected
     852             :                 //
     853           5 :                 addr::addr_range c(r);
     854           5 :                 c.get_from().get_mask(verify_mask);
     855          85 :                 for(int j(0); j < 16; ++j)
     856             :                 {
     857          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     858          80 :                     verify_mask[j] = rand();
     859             :                 }
     860             :             }
     861             :         }
     862             :     }
     863             : 
     864          24 :     CATCH_GIVEN("addr_parser() of address:port/mask")
     865             :     {
     866          18 :         CATCH_SECTION("mask allowed, but no mask")
     867             :         {
     868           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     869           1 :             int const port(rand() & 0xFFFF);
     870           2 :             addr::addr_parser p;
     871           1 :             p.set_protocol(proto);
     872           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     873           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
     874           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     875           1 :             CATCH_REQUIRE(ips.size() == 1);
     876           1 :             addr::addr_range const & r(ips[0]);
     877           1 :             addr::addr f(r.get_from());
     878           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     879           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     880           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     881           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     882           1 :             CATCH_REQUIRE(f.get_port() == port);
     883           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     884             :         }
     885             : 
     886          18 :         CATCH_SECTION("empty mask")
     887             :         {
     888           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     889           1 :             int const port(rand() & 0xFFFF);
     890           2 :             addr::addr_parser p;
     891           1 :             p.set_protocol(proto);
     892           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     893           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/"));
     894           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     895           1 :             CATCH_REQUIRE(ips.size() == 1);
     896           1 :             addr::addr_range const & r(ips[0]);
     897           1 :             addr::addr f(r.get_from());
     898           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     899           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     900           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     901           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     902           1 :             CATCH_REQUIRE(f.get_port() == port);
     903           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     904             :         }
     905             : 
     906          18 :         CATCH_SECTION("empty mask including the '[]'")
     907             :         {
     908           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     909           1 :             int const port(rand() & 0xFFFF);
     910           2 :             addr::addr_parser p;
     911           1 :             p.set_protocol(proto);
     912           1 :             p.set_allow(addr::addr_parser::flag_t::MASK, true);
     913           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[]"));
     914           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     915           1 :             CATCH_REQUIRE(ips.size() == 1);
     916           1 :             addr::addr_range const & r(ips[0]);
     917           1 :             addr::addr f(r.get_from());
     918           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     919           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     920           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     921           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     922           1 :             CATCH_REQUIRE(f.get_port() == port);
     923           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     924             :         }
     925             : 
     926          18 :         CATCH_SECTION("one number masks")
     927             :         {
     928         130 :             for(int idx(0); idx <= 128; ++idx)
     929             :             {
     930         129 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     931         129 :                 int const port(rand() & 0xFFFF);
     932         258 :                 addr::addr_parser p;
     933         129 :                 p.set_protocol(proto);
     934         129 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     935         258 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + std::to_string(idx)));
     936         129 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     937         129 :                 CATCH_REQUIRE(ips.size() == 1);
     938         129 :                 addr::addr_range const & r(ips[0]);
     939         129 :                 addr::addr f(r.get_from());
     940         129 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     941         129 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
     942         129 :                 int j(15);
     943         129 :                 int m(128 - idx);
     944        2049 :                 for(; m > 8; m -= 8, --j)
     945             :                 {
     946         960 :                     mask[j] = 0;
     947             :                 }
     948         129 :                 if(j < 0)
     949             :                 {
     950           0 :                     throw std::logic_error("invalid j here");
     951             :                 }
     952         129 :                 mask[j] = 255 << m;
     953             :                 char buf[1024]; // really large buffer to make sure it does not get truncated
     954         129 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
     955             :                 {
     956           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
     957             :                 }
     958         258 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
     959         129 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     960         129 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     961         129 :                 CATCH_REQUIRE(f.get_port() == port);
     962         129 :                 CATCH_REQUIRE(f.get_protocol() == proto);
     963             :             }
     964             :         }
     965             : 
     966          18 :         CATCH_SECTION("address like mask")
     967             :         {
     968          26 :             for(int idx(0); idx < 25; ++idx)
     969             :             {
     970          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     971          25 :                 int const port(rand() & 0xFFFF);
     972          50 :                 addr::addr_parser p;
     973          25 :                 p.set_protocol(proto);
     974          25 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
     975             :                 // when specified as an IP, the mask can be absolutely anything
     976             :                 uint8_t mask[16];
     977         425 :                 for(int j(0); j < 16; ++j)
     978             :                 {
     979         400 :                     mask[j] = rand();
     980             :                 }
     981          50 :                 std::stringstream smask;
     982          25 :                 smask << std::hex
     983          50 :                       << htons((mask[ 1] << 8) | mask[ 0])
     984          25 :                       << ":"                            
     985          50 :                       << htons((mask[ 3] << 8) | mask[ 2])
     986          25 :                       << ":"                            
     987          50 :                       << htons((mask[ 5] << 8) | mask[ 4])
     988          25 :                       << ":"                            
     989          50 :                       << htons((mask[ 7] << 8) | mask[ 6])
     990          25 :                       << ":"                            
     991          50 :                       << htons((mask[ 9] << 8) | mask[ 8])
     992          25 :                       << ":"                            
     993          50 :                       << htons((mask[11] << 8) | mask[10])
     994          25 :                       << ":"                            
     995          50 :                       << htons((mask[13] << 8) | mask[12])
     996          25 :                       << ":"                            
     997          50 :                       << htons((mask[15] << 8) | mask[14]);
     998             :                 char buf[1024]; // really large buffer to make sure it does not get truncated
     999          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1000             :                 {
    1001           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1002             :                 }
    1003          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + smask.str() + "]"));
    1004          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1005          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1006          25 :                 addr::addr_range const & r(ips[0]);
    1007          25 :                 addr::addr f(r.get_from());
    1008          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1009          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1010          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1011          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1012          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1013          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1014             :             }
    1015             :         }
    1016             : 
    1017          18 :         CATCH_SECTION("address like default mask")
    1018             :         {
    1019          26 :             for(int idx(0); idx < 25; ++idx)
    1020             :             {
    1021          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1022          25 :                 int const port(rand() & 0xFFFF);
    1023          50 :                 addr::addr_parser p;
    1024          25 :                 p.set_protocol(proto);
    1025          25 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
    1026             :                 // when specified as an IP, the mask can be absolutely anything
    1027             :                 // (here the mask is a string an it will be parsed by the
    1028             :                 // parser if required)
    1029             :                 //
    1030             :                 uint8_t mask[16];
    1031         425 :                 for(int j(0); j < 16; ++j)
    1032             :                 {
    1033         400 :                     mask[j] = rand();
    1034             :                 }
    1035          50 :                 std::stringstream smask;
    1036          25 :                 smask << std::hex
    1037          25 :                       << "["
    1038          50 :                       << htons((mask[ 1] << 8) | mask[ 0])
    1039          25 :                       << ":"                            
    1040          50 :                       << htons((mask[ 3] << 8) | mask[ 2])
    1041          25 :                       << ":"                            
    1042          50 :                       << htons((mask[ 5] << 8) | mask[ 4])
    1043          25 :                       << ":"                            
    1044          50 :                       << htons((mask[ 7] << 8) | mask[ 6])
    1045          25 :                       << ":"                            
    1046          50 :                       << htons((mask[ 9] << 8) | mask[ 8])
    1047          25 :                       << ":"                            
    1048          50 :                       << htons((mask[11] << 8) | mask[10])
    1049          25 :                       << ":"                            
    1050          50 :                       << htons((mask[13] << 8) | mask[12])
    1051          25 :                       << ":"                            
    1052          50 :                       << htons((mask[15] << 8) | mask[14])
    1053          25 :                       << "]";
    1054             :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1055          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1056             :                 {
    1057           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1058             :                 }
    1059          25 :                 p.set_default_mask(smask.str());
    1060          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
    1061          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1062          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1063          25 :                 addr::addr_range const & r(ips[0]);
    1064          25 :                 addr::addr f(r.get_from());
    1065          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1066          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1067          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1068          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1069          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1070          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1071             :                 uint8_t verify_mask[16];
    1072          25 :                 f.get_mask(verify_mask);
    1073         425 :                 for(int j(0); j < 16; ++j)
    1074             :                 {
    1075         400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    1076             :                 }
    1077             :             }
    1078             :         }
    1079             : 
    1080          18 :         CATCH_SECTION("address like mask with a default")
    1081             :         {
    1082          26 :             for(int idx(0); idx < 25; ++idx)
    1083             :             {
    1084          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1085          25 :                 int const port(rand() & 0xFFFF);
    1086          50 :                 addr::addr_parser p;
    1087          25 :                 p.set_protocol(proto);
    1088          25 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
    1089             : 
    1090             :                 // here we want a default and an IP with a specific mask
    1091             :                 // to make sure that the specific mask has priority
    1092             :                 //
    1093             :                 uint8_t mask[16];
    1094         425 :                 for(int j(0); j < 16; ++j)
    1095             :                 {
    1096         400 :                     mask[j] = rand();
    1097             :                 }
    1098          50 :                 std::stringstream smask;
    1099          25 :                 smask << std::hex
    1100          25 :                       << "["
    1101          50 :                       << htons((mask[ 1] << 8) | mask[ 0])
    1102          25 :                       << ":"                            
    1103          50 :                       << htons((mask[ 3] << 8) | mask[ 2])
    1104          25 :                       << ":"                            
    1105          50 :                       << htons((mask[ 5] << 8) | mask[ 4])
    1106          25 :                       << ":"                            
    1107          50 :                       << htons((mask[ 7] << 8) | mask[ 6])
    1108          25 :                       << ":"                            
    1109          50 :                       << htons((mask[ 9] << 8) | mask[ 8])
    1110          25 :                       << ":"                            
    1111          50 :                       << htons((mask[11] << 8) | mask[10])
    1112          25 :                       << ":"                            
    1113          50 :                       << htons((mask[13] << 8) | mask[12])
    1114          25 :                       << ":"                            
    1115          50 :                       << htons((mask[15] << 8) | mask[14])
    1116          25 :                       << "]";
    1117             :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1118          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1119             :                 {
    1120           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1121             :                 }
    1122             : 
    1123             :                 uint8_t default_mask[16];
    1124         425 :                 for(int j(0); j < 16; ++j)
    1125             :                 {
    1126         400 :                     default_mask[j] = rand();
    1127             :                 }
    1128             :                 //std::stringstream default_smask;
    1129             :                 //default_smask << std::hex
    1130             :                 //      << "["
    1131             :                 //      << htons((default_mask[ 1] << 8) | default_mask[ 0])
    1132             :                 //      << ":"                            
    1133             :                 //      << htons((default_mask[ 3] << 8) | default_mask[ 2])
    1134             :                 //      << ":"                            
    1135             :                 //      << htons((default_mask[ 5] << 8) | default_mask[ 4])
    1136             :                 //      << ":"                            
    1137             :                 //      << htons((default_mask[ 7] << 8) | default_mask[ 6])
    1138             :                 //      << ":"                            
    1139             :                 //      << htons((default_mask[ 9] << 8) | default_mask[ 8])
    1140             :                 //      << ":"                            
    1141             :                 //      << htons((default_mask[11] << 8) | default_mask[10])
    1142             :                 //      << ":"                            
    1143             :                 //      << htons((default_mask[13] << 8) | default_mask[12])
    1144             :                 //      << ":"                            
    1145             :                 //      << htons((default_mask[15] << 8) | default_mask[14])
    1146             :                 //      << "]";
    1147             :                 char default_buf[1024]; // really large buffer to make sure it does not get truncated
    1148          25 :                 if(inet_ntop(AF_INET6, default_mask, default_buf, sizeof(buf)) == nullptr)
    1149             :                 {
    1150           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1151             :                 }
    1152          25 :                 p.set_default_mask(default_buf);
    1153             : 
    1154          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + smask.str()));
    1155          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1156          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1157          25 :                 addr::addr_range const & r(ips[0]);
    1158          25 :                 addr::addr f(r.get_from());
    1159          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1160          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1161          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1162          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1163          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1164          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1165             :                 uint8_t verify_mask[16];
    1166          25 :                 f.get_mask(verify_mask);
    1167         425 :                 for(int j(0); j < 16; ++j)
    1168             :                 {
    1169         400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    1170             :                 }
    1171             :             }
    1172             :         }
    1173             : 
    1174          18 :         CATCH_SECTION("no address, but one IPv6 number masks")
    1175             :         {
    1176             :             // with just a number, the mask is considered an IPv6 mask
    1177             :             // if it is 33 or more
    1178             :             //
    1179          97 :             for(int idx(33); idx <= 128; ++idx)
    1180             :             {
    1181          96 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1182          96 :                 int const port(rand() & 0xFFFF);
    1183         192 :                 addr::addr_parser p;
    1184          96 :                 p.set_protocol(proto);
    1185          96 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
    1186             :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    1187         192 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(idx)));
    1188          96 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1189          96 :                 CATCH_REQUIRE(ips.size() == 1);
    1190          96 :                 addr::addr_range const & r(ips[0]);
    1191          96 :                 addr::addr f(r.get_from());
    1192          96 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1193          96 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
    1194          96 :                 int j(15);
    1195          96 :                 int m(128 - idx);
    1196        1130 :                 for(; m > 8; m -= 8, --j)
    1197             :                 {
    1198         517 :                     mask[j] = 0;
    1199             :                 }
    1200          96 :                 if(j < 0)
    1201             :                 {
    1202           0 :                     throw std::logic_error("invalid j here");
    1203             :                 }
    1204          96 :                 mask[j] = 255 << m;
    1205             :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1206          96 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1207             :                 {
    1208           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1209             :                 }
    1210         192 :                 std::string result("[::]:" + std::to_string(port) + "/[" + buf + "]");
    1211          96 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1212          96 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1213          96 :                 CATCH_REQUIRE(f.get_port() == port);
    1214          96 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1215             :             }
    1216             :         }
    1217             : 
    1218          18 :         CATCH_SECTION("no address, but one IPv6 masks")
    1219             :         {
    1220             :             // with just a number, the mask is considered an IPv6 mask
    1221             :             // if it is 33 or more
    1222             :             //
    1223           6 :             for(int idx(0); idx < 5; ++idx)
    1224             :             {
    1225           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1226           5 :                 int const port(rand() & 0xFFFF);
    1227          10 :                 addr::addr_parser p;
    1228           5 :                 p.set_protocol(proto);
    1229           5 :                 p.set_allow(addr::addr_parser::flag_t::MASK, true);
    1230             :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    1231          10 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]"));
    1232           5 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1233           5 :                 CATCH_REQUIRE(ips.size() == 1);
    1234           5 :                 addr::addr_range const & r(ips[0]);
    1235           5 :                 addr::addr f(r.get_from());
    1236           5 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1237          10 :                 std::string result("[::]:" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]");
    1238           5 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1239           5 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1240           5 :                 CATCH_REQUIRE(f.get_port() == port);
    1241           5 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1242             :             }
    1243             :         }
    1244             :     }
    1245          12 : }
    1246             : 
    1247             : 
    1248           9 : CATCH_TEST_CASE( "ipv6::network_type", "[ipv6]" )
    1249             : {
    1250          14 :     CATCH_GIVEN("addr()")
    1251             :     {
    1252           7 :         addr::addr a;
    1253             : 
    1254          14 :         CATCH_SECTION("any (::)")
    1255             :         {
    1256             :             {
    1257           1 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1258           1 :                 in6.sin6_family = AF_INET6;
    1259           1 :                 in6.sin6_port = htons(rand());
    1260           1 :                 in6.sin6_addr.s6_addr32[0] = 0;
    1261           1 :                 in6.sin6_addr.s6_addr32[1] = 0;
    1262           1 :                 in6.sin6_addr.s6_addr32[2] = 0;
    1263           1 :                 in6.sin6_addr.s6_addr32[3] = 0;
    1264             : 
    1265             :                 // verify network type
    1266             :                 //
    1267           1 :                 a.set_ipv6(in6);
    1268             : 
    1269           1 :                 CATCH_REQUIRE(a.is_default());
    1270           1 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_ANY);
    1271           1 :                 CATCH_REQUIRE(a.get_network_type_string() == "Any");
    1272             :             }
    1273             : 
    1274             :             // make sure that if any byte is set to non-zero it is not
    1275             :             // viewed as the ANY address
    1276             :             //
    1277          17 :             for(int idx(0); idx < 16; ++idx)
    1278             :             {
    1279          16 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1280          16 :                 in6.sin6_family = AF_INET6;
    1281          16 :                 in6.sin6_port = htons(rand());
    1282          16 :                 in6.sin6_addr.s6_addr32[0] = 0;
    1283          16 :                 in6.sin6_addr.s6_addr32[1] = 0;
    1284          16 :                 in6.sin6_addr.s6_addr32[2] = 0;
    1285          16 :                 in6.sin6_addr.s6_addr32[3] = 0;
    1286             : 
    1287             :                 // change one byte only
    1288             :                 //
    1289           0 :                 do
    1290             :                 {
    1291          16 :                     in6.sin6_addr.s6_addr[idx] = rand();
    1292             :                 }
    1293          16 :                 while(in6.sin6_addr.s6_addr[idx] == 0);
    1294             : 
    1295             :                 // verify network type
    1296             :                 //
    1297          16 :                 a.set_ipv6(in6);
    1298             : 
    1299          16 :                 CATCH_REQUIRE(a.get_network_type() != addr::addr::network_type_t::NETWORK_TYPE_ANY);
    1300          16 :                 CATCH_REQUIRE(a.get_network_type_string() != "Any");
    1301             :             }
    1302             :         }
    1303             : 
    1304          14 :         CATCH_SECTION("private address fd00::/8")
    1305             :         {
    1306          11 :             for(int idx(0); idx < 10; ++idx)
    1307             :             {
    1308          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1309          10 :                 in6.sin6_family = AF_INET6;
    1310          10 :                 in6.sin6_port = htons(rand());
    1311          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFD00 | (rand() & 255));
    1312          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1313          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1314          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1315          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1316          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1317          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1318          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1319             : 
    1320             :                 // verify network type
    1321             :                 //
    1322          10 :                 a.set_ipv6(in6);
    1323          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PRIVATE);
    1324          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Private");
    1325             :             }
    1326             :         }
    1327             : 
    1328          14 :         CATCH_SECTION("private address fe80::/10")
    1329             :         {
    1330          11 :             for(int idx(0); idx < 10; ++idx)
    1331             :             {
    1332          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1333          10 :                 in6.sin6_family = AF_INET6;
    1334          10 :                 in6.sin6_port = htons(rand());
    1335          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFE80 | (rand() & 63));
    1336          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1337          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1338          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1339          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1340          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1341          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1342          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1343             : 
    1344             :                 // verify network type
    1345             :                 //
    1346          10 :                 a.set_ipv6(in6);
    1347          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    1348          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
    1349             :             }
    1350             :         }
    1351             : 
    1352          14 :         CATCH_SECTION("private address ff02::/16")
    1353             :         {
    1354          11 :             for(int idx(0); idx < 10; ++idx)
    1355             :             {
    1356          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1357          10 :                 in6.sin6_family = AF_INET6;
    1358          10 :                 in6.sin6_port = htons(rand());
    1359          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF02);
    1360          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1361          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1362          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1363          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1364          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1365          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1366          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1367             : 
    1368             :                 // verify network type
    1369             :                 //
    1370          10 :                 a.set_ipv6(in6);
    1371          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    1372          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
    1373             :             }
    1374             :         }
    1375             : 
    1376          14 :         CATCH_SECTION("private address ff00::/8")
    1377             :         {
    1378          11 :             for(int idx(0); idx < 10; ++idx)
    1379             :             {
    1380          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1381          10 :                 in6.sin6_family = AF_INET6;
    1382          10 :                 in6.sin6_port = htons(rand());
    1383           2 :                 do
    1384             :                 {
    1385          12 :                     in6.sin6_addr.s6_addr16[0] = htons(0xFF00 | (rand() & 255));
    1386             :                 }
    1387          12 :                 while((in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF01)       // ffx1::/16
    1388          12 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF02)       // ffx2::/16
    1389          10 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFFC0)) == htons(0xFE80)       // fe80::/10
    1390          22 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF00)) == htons(0xFD00));     // fd00::/8
    1391          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1392          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1393          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1394          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1395          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1396          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1397          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1398             : 
    1399             :                 // verify network type
    1400             :                 //
    1401          10 :                 a.set_ipv6(in6);
    1402          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_MULTICAST);
    1403          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Multicast");
    1404             :             }
    1405             :         }
    1406             : 
    1407          14 :         CATCH_SECTION("private address ffx1::/8")
    1408             :         {
    1409          11 :             for(int idx(0); idx < 10; ++idx)
    1410             :             {
    1411          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1412          10 :                 in6.sin6_family = AF_INET6;
    1413          10 :                 in6.sin6_port = htons(rand());
    1414          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF01 | ((rand() & 15) << 4));
    1415          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1416          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1417          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1418          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1419          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1420          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1421          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1422             : 
    1423             :                 // verify network type
    1424             :                 //
    1425          10 :                 a.set_ipv6(in6);
    1426          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1427          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1428             :             }
    1429             :         }
    1430             : 
    1431          14 :         CATCH_SECTION("private address ::1")
    1432             :         {
    1433          11 :             for(int idx(0); idx < 10; ++idx)
    1434             :             {
    1435          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1436          10 :                 in6.sin6_family = AF_INET6;
    1437          10 :                 in6.sin6_port = htons(rand());
    1438          10 :                 in6.sin6_addr.s6_addr16[0] = 0;
    1439          10 :                 in6.sin6_addr.s6_addr16[1] = 0;
    1440          10 :                 in6.sin6_addr.s6_addr16[2] = 0;
    1441          10 :                 in6.sin6_addr.s6_addr16[3] = 0;
    1442          10 :                 in6.sin6_addr.s6_addr16[4] = 0;
    1443          10 :                 in6.sin6_addr.s6_addr16[5] = 0;
    1444          10 :                 in6.sin6_addr.s6_addr16[6] = 0;
    1445          10 :                 in6.sin6_addr.s6_addr16[7] = htons(1);
    1446             : 
    1447             :                 // verify network type
    1448             :                 //
    1449          10 :                 a.set_ipv6(in6);
    1450          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1451          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1452             : 
    1453             :                 // try again from a string to confirm
    1454             :                 //
    1455          10 :                 struct addrinfo * addrlist(nullptr);
    1456          10 :                 int const port(rand() & 65535);
    1457          10 :                 int const r(getaddrinfo("::1", std::to_string(port).c_str(), nullptr, &addrlist));
    1458          10 :                 CATCH_REQUIRE(r == 0);
    1459          10 :                 CATCH_REQUIRE(addrlist != nullptr);
    1460          10 :                 CATCH_REQUIRE(addrlist->ai_family == AF_INET6);
    1461          10 :                 CATCH_REQUIRE(addrlist->ai_addrlen == sizeof(struct sockaddr_in6));
    1462          10 :                 a.set_ipv6(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
    1463          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1464          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1465             :             }
    1466             :         }
    1467             :     }
    1468           7 : }
    1469             : 
    1470             : 
    1471           5 : CATCH_TEST_CASE( "ipv6::network", "[ipv6]" )
    1472             : {
    1473           6 :     CATCH_GIVEN("set_from_socket()")
    1474             :     {
    1475           6 :         CATCH_SECTION("create a server, but do not test it (yet)...")
    1476             :         {
    1477           2 :             addr::addr_parser p;
    1478           2 :             addr::addr_range::vector_t ips(p.parse("[::1]:49999"));
    1479           1 :             CATCH_REQUIRE(ips.size() >= 1);
    1480             : 
    1481           1 :             addr::addr & a(ips[0].get_from());
    1482           1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_NONBLOCK | addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
    1483           1 :             CATCH_REQUIRE(s >= 0);
    1484           2 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    1485             : 
    1486           1 :             CATCH_REQUIRE(a.bind(s) == 0);
    1487             :         }
    1488             : 
    1489           6 :         CATCH_SECTION("connect with TCP to [::1]")
    1490             :         {
    1491           1 :             if(SNAP_CATCH2_NAMESPACE::g_tcp_port != -1)
    1492             :             {
    1493           2 :                 addr::addr_parser p;
    1494           2 :                 addr::addr_range::vector_t ips(p.parse("[::1]:" + std::to_string(SNAP_CATCH2_NAMESPACE::g_tcp_port)));
    1495           1 :                 CATCH_REQUIRE(ips.size() >= 1);
    1496             : 
    1497           1 :                 addr::addr & a(ips[0].get_from());
    1498           1 :                 int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    1499           1 :                 CATCH_REQUIRE(s >= 0);
    1500           2 :                 std::shared_ptr<int> auto_free(&s, socket_deleter);
    1501             : 
    1502           1 :                 CATCH_REQUIRE(a.connect(s) == 0);
    1503             : 
    1504             :                 // get socket info from the other side (peer == true)
    1505             :                 //
    1506           1 :                 addr::addr b;
    1507           1 :                 b.set_from_socket(s, true);
    1508           1 :                 CATCH_REQUIRE_FALSE(b.is_ipv4());
    1509           1 :                 CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::1");
    1510           1 :                 CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
    1511             : 
    1512             :                 // in this case we know what the port is since we specified
    1513             :                 // that when connecting
    1514             :                 //
    1515           1 :                 CATCH_REQUIRE(b.get_port() == SNAP_CATCH2_NAMESPACE::g_tcp_port);
    1516             : 
    1517             :                 // now try this side (peer == false)
    1518             :                 //
    1519           1 :                 addr::addr c;
    1520           1 :                 c.set_from_socket(s, false);
    1521           1 :                 CATCH_REQUIRE_FALSE(c.is_ipv4());
    1522           1 :                 CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::1");
    1523           1 :                 CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
    1524             : 
    1525             :                 // we cannot be sure of the port, there is a range we could
    1526             :                 // test better (more constraining) but for this test is
    1527             :                 // certainly does not matter much; it has to be more than
    1528             :                 // 1023, though
    1529             :                 //
    1530           1 :                 CATCH_REQUIRE(c.get_port() > 1023);
    1531             :             }
    1532             :             else
    1533             :             {
    1534           0 :                 std::cout << "connect to [::1] test skipped as no TCP port was specified on the command line." << std::endl;
    1535             :             }
    1536             :         }
    1537             : 
    1538           6 :         CATCH_SECTION("connect with UDP to [::1]")
    1539             :         {
    1540           2 :             addr::addr_parser p;
    1541           1 :             p.set_protocol("udp");
    1542           2 :             addr::addr_range::vector_t ips(p.parse("[::1]:53"));
    1543           1 :             CATCH_REQUIRE(ips.size() >= 1);
    1544             : 
    1545           1 :             addr::addr & a(ips[0].get_from());
    1546           1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    1547           1 :             CATCH_REQUIRE(s >= 0);
    1548           2 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    1549             : 
    1550           1 :             CATCH_REQUIRE(a.connect(s) == -1);
    1551             : 
    1552             :             // get socket info from the other side (peer == true)
    1553             :             //
    1554           1 :             addr::addr b;
    1555           1 :             CATCH_REQUIRE_THROWS_AS(b.set_from_socket(s, true), addr::addr_io_error);
    1556           1 :             CATCH_REQUIRE_FALSE(b.is_ipv4());
    1557           1 :             CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::");
    1558           1 :             CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
    1559             : 
    1560             :             // in this case we know what the port is since we specified
    1561             :             // that when connecting
    1562             :             //
    1563           1 :             CATCH_REQUIRE(b.get_port() == 0);
    1564             : 
    1565             :             // now try this side (peer == false)
    1566             :             //
    1567           1 :             addr::addr c;
    1568           1 :             c.set_from_socket(s, false);
    1569           1 :             CATCH_REQUIRE_FALSE(c.is_ipv4());
    1570           1 :             CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::");
    1571           1 :             CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
    1572             : 
    1573             :             // we cannot be sure of the port, there is a range we could
    1574             :             // test better (more constraining) but for this test is
    1575             :             // certainly does not matter much; it has to be more than
    1576             :             // 1023, though
    1577             :             //
    1578           1 :             CATCH_REQUIRE(c.get_port() == 0);
    1579             :         }
    1580             :     }
    1581           9 : }
    1582             : 
    1583             : 
    1584             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12