LCOV - code coverage report
Current view: top level - tests - catch_ipv6.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 951 964 98.7 %
Date: 2021-07-21 12:51:15 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13