LCOV - code coverage report
Current view: top level - tests - catch_ipv6.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1000 1015 98.5 %
Date: 2022-03-01 21:05:13 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           2 :         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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_PORT, false);
     168           1 :                 p.set_allow(addr::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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::allow_t::ALLOW_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          10 : CATCH_TEST_CASE( "ipv6::address", "[ipv6]" )
     416             : {
     417          16 :     CATCH_GIVEN("addr() with an IPv6")
     418             :     {
     419           6 :         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          20 :                 addr::addr b(in6);
     444          10 :                 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           1 :             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          16 :     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           2 :             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           2 :             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::allow_t::ALLOW_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           2 :                 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::allow_t::ALLOW_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           2 :                 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             : 
     643          16 :     CATCH_GIVEN("addr_parser() with numeric only IPv6 addresses")
     644             :     {
     645           4 :         CATCH_SECTION("Simple numeric IPv6")
     646             :         {
     647           2 :             addr::addr_parser p;
     648           1 :             p.set_protocol(IPPROTO_TCP);
     649           1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_LOOKUP, false);
     650           2 :             addr::addr_range::vector_t ips(p.parse("[4::f003:3001:20af]:5093"));
     651           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     652           1 :             CATCH_REQUIRE(ips.size() == 1);
     653             : 
     654           1 :             addr::addr_range const & r(ips[0]);
     655           1 :             CATCH_REQUIRE(r.has_from());
     656           1 :             CATCH_REQUIRE_FALSE(r.has_to());
     657           1 :             CATCH_REQUIRE_FALSE(r.is_range());
     658           1 :             CATCH_REQUIRE_FALSE(r.is_empty());
     659           2 :             addr::addr f(r.get_from());
     660           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     661             :             // getting an IPv4 would throw, which is checked somewhere else
     662             :             //CATCH_REQUIRE(f.to_ipv4_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "");
     663           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "4::f003:3001:20af");
     664           1 :             CATCH_REQUIRE(f.get_port() == 5093);
     665           1 :             CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     666           1 :             CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
     667           1 :             uint8_t mask[16] = {};
     668           1 :             f.get_mask(mask);
     669          17 :             for(int idx(0); idx < 16; ++idx)
     670             :             {
     671          16 :                 CATCH_REQUIRE(mask[idx] == 255);
     672             :             }
     673             :         }
     674             : 
     675           4 :         CATCH_SECTION("Invalid IPv6 domain name address when we only accept numeric IPs")
     676             :         {
     677             :             // this is exactly the same path as the IPv4 test...
     678             :             // if we have a named domain then IPv4 fails, IPv6 fails, then we err on it
     679             :             //
     680           2 :             addr::addr_parser p;
     681           1 :             p.set_protocol(IPPROTO_TCP);
     682           1 :             p.set_allow(addr::allow_t::ALLOW_ADDRESS_LOOKUP, false);
     683           2 :             addr::addr_range::vector_t ips(p.parse("ipv6.example.com:4471"));
     684           1 :             CATCH_REQUIRE(p.has_errors());
     685           1 :             CATCH_REQUIRE(p.error_count() == 1);
     686           1 :             CATCH_REQUIRE(p.error_messages() == "Unknown address in \"ipv6.example.com\" (no DNS lookup was allowed).\n");
     687           1 :             CATCH_REQUIRE(ips.size() == 0);
     688             :         }
     689             :     }
     690           8 : }
     691             : 
     692             : 
     693           7 : CATCH_TEST_CASE( "ipv6::ports", "[ipv6]" )
     694             : {
     695             :     // by default addr() is an IPv6 address so we test the basic port
     696             :     // functions here, although it could be in a common place instead...
     697             :     //
     698          10 :     CATCH_GIVEN("addr()")
     699             :     {
     700           6 :         addr::addr a;
     701             : 
     702           6 :         CATCH_SECTION("default port")
     703             :         {
     704           1 :             CATCH_REQUIRE(a.get_port() == 0);
     705             :         }
     706             : 
     707           6 :         CATCH_SECTION("set_port()")
     708             :         {
     709             :             // setup a random port to start with
     710             :             //
     711           1 :             int const start_port(rand() & 0xFFFF);
     712           1 :             a.set_port(start_port);
     713             : 
     714             :             // test 100 invalid ports
     715             :             //
     716         101 :             for(int idx(0); idx < 100; ++idx)
     717             :             {
     718             :                 // first try a negative port
     719             :                 int port_too_small;
     720           0 :                 do
     721             :                 {
     722         100 :                     port_too_small = -(rand() & 0xFFFF);
     723             :                 }
     724         100 :                 while(port_too_small == 0);
     725         100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_small), addr::addr_invalid_argument);
     726             : 
     727             :                 // first try a negative port
     728         100 :                 int const port_too_large = (rand() & 0xFFFF) + 65536;
     729         100 :                 CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_large), addr::addr_invalid_argument);
     730             : 
     731             :                 // make sure port does not get modified on errors
     732         100 :                 CATCH_REQUIRE(a.get_port() == start_port);
     733             :             }
     734             : 
     735             :             // test all ports
     736             :             //
     737       65537 :             for(int port(0); port < 65536; ++port)
     738             :             {
     739       65536 :                 a.set_port(port);
     740             : 
     741       65536 :                 CATCH_REQUIRE(a.get_port() == port);
     742             :             }
     743             :         }
     744             : 
     745           6 :         CATCH_SECTION("known ports to test get_service()")
     746             :         {
     747           1 :             a.set_port(80);
     748           1 :             CATCH_REQUIRE(a.get_service() == "http");
     749             : 
     750           1 :             a.set_port(443);
     751           1 :             CATCH_REQUIRE(a.get_service() == "https");
     752             : 
     753             :             // again with UDP
     754             :             // 
     755           1 :             a.set_protocol(IPPROTO_UDP);
     756             : 
     757           1 :             a.set_port(80);
     758           2 :             std::string service(a.get_service());
     759           1 :             CATCH_REQUIRE((service == "http" || service == "80"));
     760             : 
     761           1 :             a.set_port(443);
     762           1 :             service = a.get_service();
     763           1 :             CATCH_REQUIRE((service == "https"|| service == "443"));
     764             :         }
     765             :     }
     766             : 
     767          10 :     CATCH_GIVEN("addr_parser() with IPv6 addresses and port")
     768             :     {
     769           4 :         CATCH_SECTION("verify port")
     770             :         {
     771       65537 :             for(int port(0); port < 65536; ++port)
     772             :             {
     773       65536 :                 int proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     774      131072 :                 addr::addr_parser p;
     775       65536 :                 p.set_protocol(proto);
     776      131072 :                 addr::addr_range::vector_t ips(p.parse("[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port)));
     777       65536 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     778       65536 :                 CATCH_REQUIRE(ips.size() == 1);
     779       65536 :                 addr::addr_range const & r(ips[0]);
     780      131072 :                 addr::addr f(r.get_from());
     781       65536 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     782       65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "ff01:2f3:f041:e301:f:10:11:12");
     783       65536 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[ff01:2f3:f041:e301:f:10:11:12]");
     784       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));
     785       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));
     786       65536 :                 CATCH_REQUIRE(f.get_port() == port);
     787       65536 :                 CATCH_REQUIRE(f.get_protocol() == proto);
     788       65536 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
     789             :             }
     790             :         }
     791             : 
     792           4 :         CATCH_SECTION("default address with various port")
     793             :         {
     794         101 :             for(int idx(0); idx < 100; ++idx)
     795             :             {
     796         100 :                 uint16_t const port(rand());
     797         200 :                 addr::addr_parser p;
     798         100 :                 p.set_protocol(IPPROTO_TCP);
     799         100 :                 p.set_default_address("ff02:23:f41:e31:20:30:40:50");
     800         200 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(static_cast<int>(port))));
     801         100 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     802         100 :                 CATCH_REQUIRE(ips.size() == 1);
     803         100 :                 addr::addr_range const & r(ips[0]);
     804         100 :                 CATCH_REQUIRE(r.has_from());
     805         100 :                 CATCH_REQUIRE_FALSE(r.has_to());
     806         100 :                 CATCH_REQUIRE_FALSE(r.is_range());
     807         100 :                 CATCH_REQUIRE_FALSE(r.is_empty());
     808         200 :                 addr::addr f(r.get_from());
     809         100 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     810         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)));
     811         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)));
     812         100 :                 CATCH_REQUIRE(f.get_port() == port);
     813         100 :                 CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
     814         100 :                 CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
     815             :             }
     816             :         }
     817             :     }
     818           5 : }
     819             : 
     820             : 
     821          14 : CATCH_TEST_CASE( "ipv6::masks", "[ipv6]" )
     822             : {
     823          24 :     CATCH_GIVEN("addr()")
     824             :     {
     825             :         // technically, a default addr object represents and IPv6 so the
     826             :         // dealing with the mask without an IPv4 is done by IPv6 tests
     827             :         //
     828           6 :         addr::addr a;
     829             : 
     830           6 :         CATCH_SECTION("default mask")
     831             :         {
     832           1 :             uint8_t mask[16] = {};
     833           1 :             a.get_mask(mask);
     834          17 :             for(int idx(0); idx < 16; ++idx)
     835             :             {
     836          16 :                 CATCH_REQUIRE(mask[idx] == 255);
     837             :             }
     838             :         }
     839             : 
     840           6 :         CATCH_SECTION("set_mask()")
     841             :         {
     842           1 :             uint8_t mask[16], verify_mask[16];
     843           6 :             for(int idx(0); idx < 5; ++idx)
     844             :             {
     845          85 :                 for(int j(0); j < 16; ++j)
     846             :                 {
     847          80 :                     mask[j] = rand();
     848             :                 }
     849           5 :                 a.set_mask(mask);
     850           5 :                 a.get_mask(verify_mask);
     851          85 :                 for(int j(0); j < 16; ++j)
     852             :                 {
     853          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     854             :                 }
     855             : 
     856             :                 // verify that a copy does copy the mask as expected
     857             :                 //
     858          10 :                 addr::addr b(a);
     859           5 :                 b.get_mask(verify_mask);
     860          85 :                 for(int j(0); j < 16; ++j)
     861             :                 {
     862          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     863             :                 }
     864             :             }
     865             :         }
     866             : 
     867           6 :         CATCH_SECTION("set_mask()")
     868             :         {
     869           1 :             uint8_t mask[16];
     870           1 :             uint8_t verify_mask[16];
     871           6 :             for(int idx(0); idx < 5; ++idx)
     872             :             {
     873          85 :                 for(int j(0); j < 16; ++j)
     874             :                 {
     875          80 :                     mask[j] = rand();
     876             :                 }
     877           5 :                 a.set_mask(mask);
     878           5 :                 a.get_mask(verify_mask);
     879          85 :                 for(int j(0); j < 16; ++j)
     880             :                 {
     881          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     882          80 :                     verify_mask[j] = rand();
     883             :                 }
     884             : 
     885             :                 // verify that a copy does copy the mask as expected
     886             :                 //
     887          10 :                 addr::addr b(a);
     888           5 :                 b.get_mask(verify_mask);
     889          85 :                 for(int j(0); j < 16; ++j)
     890             :                 {
     891          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     892          80 :                     verify_mask[j] = rand();
     893             :                 }
     894             : 
     895             :                 // verify that copying inside a range works too
     896             :                 //
     897          10 :                 addr::addr_range r;
     898           5 :                 r.set_from(a);
     899           5 :                 r.get_from().get_mask(verify_mask);
     900          85 :                 for(int j(0); j < 16; ++j)
     901             :                 {
     902          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     903          80 :                     verify_mask[j] = rand();
     904             :                 }
     905             : 
     906             :                 // then that a range copy works as expected
     907             :                 //
     908          10 :                 addr::addr_range c(r);
     909           5 :                 c.get_from().get_mask(verify_mask);
     910          85 :                 for(int j(0); j < 16; ++j)
     911             :                 {
     912          80 :                     CATCH_REQUIRE(mask[j] == verify_mask[j]);
     913          80 :                     verify_mask[j] = rand();
     914             :                 }
     915             :             }
     916             :         }
     917             :     }
     918             : 
     919          24 :     CATCH_GIVEN("addr_parser() of address:port/mask")
     920             :     {
     921          18 :         CATCH_SECTION("mask allowed, but no mask")
     922             :         {
     923           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     924           1 :             int const port(rand() & 0xFFFF);
     925           2 :             addr::addr_parser p;
     926           1 :             p.set_protocol(proto);
     927           1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     928           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
     929           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     930           1 :             CATCH_REQUIRE(ips.size() == 1);
     931           1 :             addr::addr_range const & r(ips[0]);
     932           2 :             addr::addr f(r.get_from());
     933           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     934           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     935           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     936           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     937           1 :             CATCH_REQUIRE(f.get_port() == port);
     938           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     939             :         }
     940             : 
     941          18 :         CATCH_SECTION("empty mask")
     942             :         {
     943           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     944           1 :             int const port(rand() & 0xFFFF);
     945           2 :             addr::addr_parser p;
     946           1 :             p.set_protocol(proto);
     947           1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     948           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/"));
     949           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     950           1 :             CATCH_REQUIRE(ips.size() == 1);
     951           1 :             addr::addr_range const & r(ips[0]);
     952           2 :             addr::addr f(r.get_from());
     953           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     954           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     955           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     956           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     957           1 :             CATCH_REQUIRE(f.get_port() == port);
     958           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     959             :         }
     960             : 
     961          18 :         CATCH_SECTION("empty mask including the '[]'")
     962             :         {
     963           1 :             int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     964           1 :             int const port(rand() & 0xFFFF);
     965           2 :             addr::addr_parser p;
     966           1 :             p.set_protocol(proto);
     967           1 :             p.set_allow(addr::allow_t::ALLOW_MASK, true);
     968           2 :             addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[]"));
     969           1 :             CATCH_REQUIRE_FALSE(p.has_errors());
     970           1 :             CATCH_REQUIRE(ips.size() == 1);
     971           1 :             addr::addr_range const & r(ips[0]);
     972           2 :             addr::addr f(r.get_from());
     973           1 :             CATCH_REQUIRE_FALSE(f.is_ipv4());
     974           2 :             std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
     975           1 :             CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     976           1 :             CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
     977           1 :             CATCH_REQUIRE(f.get_port() == port);
     978           1 :             CATCH_REQUIRE(f.get_protocol() == proto);
     979             :         }
     980             : 
     981          18 :         CATCH_SECTION("one number masks")
     982             :         {
     983         130 :             for(int idx(0); idx <= 128; ++idx)
     984             :             {
     985         129 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
     986         129 :                 int const port(rand() & 0xFFFF);
     987         258 :                 addr::addr_parser p;
     988         129 :                 p.set_protocol(proto);
     989         129 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
     990         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)));
     991         129 :                 CATCH_REQUIRE_FALSE(p.has_errors());
     992         129 :                 CATCH_REQUIRE(ips.size() == 1);
     993         129 :                 addr::addr_range const & r(ips[0]);
     994         258 :                 addr::addr f(r.get_from());
     995         129 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
     996         129 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
     997         129 :                 int j(15);
     998         129 :                 int m(128 - idx);
     999        2049 :                 for(; m > 8; m -= 8, --j)
    1000             :                 {
    1001         960 :                     mask[j] = 0;
    1002             :                 }
    1003         129 :                 if(j < 0)
    1004             :                 {
    1005           0 :                     throw std::logic_error("invalid j here");
    1006             :                 }
    1007         129 :                 mask[j] = 255 << m;
    1008         129 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1009         129 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1010             :                 {
    1011           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1012             :                 }
    1013         258 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1014         129 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1015         129 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1016         129 :                 CATCH_REQUIRE(f.get_port() == port);
    1017         129 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1018             :             }
    1019             :         }
    1020             : 
    1021          18 :         CATCH_SECTION("address like mask")
    1022             :         {
    1023          26 :             for(int idx(0); idx < 25; ++idx)
    1024             :             {
    1025          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1026          25 :                 int const port(rand() & 0xFFFF);
    1027          50 :                 addr::addr_parser p;
    1028          25 :                 p.set_protocol(proto);
    1029          25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    1030             :                 // when specified as an IP, the mask can be absolutely anything
    1031          25 :                 uint8_t mask[16];
    1032         425 :                 for(int j(0); j < 16; ++j)
    1033             :                 {
    1034         400 :                     mask[j] = rand();
    1035             :                 }
    1036          50 :                 std::stringstream smask;
    1037          25 :                 smask << std::hex
    1038          25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    1039          25 :                       << ":"                            
    1040          25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    1041          25 :                       << ":"                            
    1042          25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    1043          25 :                       << ":"                            
    1044          25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    1045          25 :                       << ":"                            
    1046          25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    1047          25 :                       << ":"                            
    1048          25 :                       << htons((mask[11] << 8) | mask[10])
    1049          25 :                       << ":"                            
    1050          25 :                       << htons((mask[13] << 8) | mask[12])
    1051          25 :                       << ":"                            
    1052          25 :                       << htons((mask[15] << 8) | mask[14]);
    1053          25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1054          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1055             :                 {
    1056           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1057             :                 }
    1058          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + smask.str() + "]"));
    1059          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1060          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1061          25 :                 addr::addr_range const & r(ips[0]);
    1062          50 :                 addr::addr f(r.get_from());
    1063          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1064          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1065          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1066          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1067          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1068          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1069             :             }
    1070             :         }
    1071             : 
    1072          18 :         CATCH_SECTION("address like default mask")
    1073             :         {
    1074          26 :             for(int idx(0); idx < 25; ++idx)
    1075             :             {
    1076          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1077          25 :                 int const port(rand() & 0xFFFF);
    1078          50 :                 addr::addr_parser p;
    1079          25 :                 p.set_protocol(proto);
    1080          25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    1081             :                 // when specified as an IP, the mask can be absolutely anything
    1082             :                 // (here the mask is a string an it will be parsed by the
    1083             :                 // parser if required)
    1084             :                 //
    1085          25 :                 uint8_t mask[16];
    1086         425 :                 for(int j(0); j < 16; ++j)
    1087             :                 {
    1088         400 :                     mask[j] = rand();
    1089             :                 }
    1090          50 :                 std::stringstream smask;
    1091          25 :                 smask << std::hex
    1092          25 :                       << "["
    1093          25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    1094          25 :                       << ":"                            
    1095          25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    1096          25 :                       << ":"                            
    1097          25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    1098          25 :                       << ":"                            
    1099          25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    1100          25 :                       << ":"                            
    1101          25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    1102          25 :                       << ":"                            
    1103          25 :                       << htons((mask[11] << 8) | mask[10])
    1104          25 :                       << ":"                            
    1105          25 :                       << htons((mask[13] << 8) | mask[12])
    1106          25 :                       << ":"                            
    1107          25 :                       << htons((mask[15] << 8) | mask[14])
    1108          25 :                       << "]";
    1109          25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1110          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1111             :                 {
    1112           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1113             :                 }
    1114          25 :                 p.set_default_mask(smask.str());
    1115          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
    1116          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1117          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1118          25 :                 addr::addr_range const & r(ips[0]);
    1119          50 :                 addr::addr f(r.get_from());
    1120          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1121          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1122          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1123          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1124          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1125          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1126          25 :                 uint8_t verify_mask[16];
    1127          25 :                 f.get_mask(verify_mask);
    1128         425 :                 for(int j(0); j < 16; ++j)
    1129             :                 {
    1130         400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    1131             :                 }
    1132             :             }
    1133             :         }
    1134             : 
    1135          18 :         CATCH_SECTION("address like mask with a default")
    1136             :         {
    1137          26 :             for(int idx(0); idx < 25; ++idx)
    1138             :             {
    1139          25 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1140          25 :                 int const port(rand() & 0xFFFF);
    1141          50 :                 addr::addr_parser p;
    1142          25 :                 p.set_protocol(proto);
    1143          25 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    1144             : 
    1145             :                 // here we want a default and an IP with a specific mask
    1146             :                 // to make sure that the specific mask has priority
    1147             :                 //
    1148          25 :                 uint8_t mask[16];
    1149         425 :                 for(int j(0); j < 16; ++j)
    1150             :                 {
    1151         400 :                     mask[j] = rand();
    1152             :                 }
    1153          50 :                 std::stringstream smask;
    1154          25 :                 smask << std::hex
    1155          25 :                       << "["
    1156          25 :                       << htons((mask[ 1] << 8) | mask[ 0])
    1157          25 :                       << ":"                            
    1158          25 :                       << htons((mask[ 3] << 8) | mask[ 2])
    1159          25 :                       << ":"                            
    1160          25 :                       << htons((mask[ 5] << 8) | mask[ 4])
    1161          25 :                       << ":"                            
    1162          25 :                       << htons((mask[ 7] << 8) | mask[ 6])
    1163          25 :                       << ":"                            
    1164          25 :                       << htons((mask[ 9] << 8) | mask[ 8])
    1165          25 :                       << ":"                            
    1166          25 :                       << htons((mask[11] << 8) | mask[10])
    1167          25 :                       << ":"                            
    1168          25 :                       << htons((mask[13] << 8) | mask[12])
    1169          25 :                       << ":"                            
    1170          25 :                       << htons((mask[15] << 8) | mask[14])
    1171          25 :                       << "]";
    1172          25 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1173          25 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1174             :                 {
    1175           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1176             :                 }
    1177             : 
    1178          25 :                 uint8_t default_mask[16];
    1179         425 :                 for(int j(0); j < 16; ++j)
    1180             :                 {
    1181         400 :                     default_mask[j] = rand();
    1182             :                 }
    1183             :                 //std::stringstream default_smask;
    1184             :                 //default_smask << std::hex
    1185             :                 //      << "["
    1186             :                 //      << htons((default_mask[ 1] << 8) | default_mask[ 0])
    1187             :                 //      << ":"                            
    1188             :                 //      << htons((default_mask[ 3] << 8) | default_mask[ 2])
    1189             :                 //      << ":"                            
    1190             :                 //      << htons((default_mask[ 5] << 8) | default_mask[ 4])
    1191             :                 //      << ":"                            
    1192             :                 //      << htons((default_mask[ 7] << 8) | default_mask[ 6])
    1193             :                 //      << ":"                            
    1194             :                 //      << htons((default_mask[ 9] << 8) | default_mask[ 8])
    1195             :                 //      << ":"                            
    1196             :                 //      << htons((default_mask[11] << 8) | default_mask[10])
    1197             :                 //      << ":"                            
    1198             :                 //      << htons((default_mask[13] << 8) | default_mask[12])
    1199             :                 //      << ":"                            
    1200             :                 //      << htons((default_mask[15] << 8) | default_mask[14])
    1201             :                 //      << "]";
    1202          25 :                 char default_buf[1024]; // really large buffer to make sure it does not get truncated
    1203          25 :                 if(inet_ntop(AF_INET6, default_mask, default_buf, sizeof(buf)) == nullptr)
    1204             :                 {
    1205           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1206             :                 }
    1207          25 :                 p.set_default_mask(default_buf);
    1208             : 
    1209          50 :                 addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + smask.str()));
    1210          25 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1211          25 :                 CATCH_REQUIRE(ips.size() == 1);
    1212          25 :                 addr::addr_range const & r(ips[0]);
    1213          50 :                 addr::addr f(r.get_from());
    1214          25 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1215          50 :                 std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
    1216          25 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1217          25 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1218          25 :                 CATCH_REQUIRE(f.get_port() == port);
    1219          25 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1220          25 :                 uint8_t verify_mask[16];
    1221          25 :                 f.get_mask(verify_mask);
    1222         425 :                 for(int j(0); j < 16; ++j)
    1223             :                 {
    1224         400 :                     CATCH_REQUIRE(verify_mask[j] == mask[j]);
    1225             :                 }
    1226             :             }
    1227             :         }
    1228             : 
    1229          18 :         CATCH_SECTION("no address, but one IPv6 number masks")
    1230             :         {
    1231             :             // with just a number, the mask is considered an IPv6 mask
    1232             :             // if it is 33 or more
    1233             :             //
    1234          97 :             for(int idx(33); idx <= 128; ++idx)
    1235             :             {
    1236          96 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1237          96 :                 int const port(rand() & 0xFFFF);
    1238         192 :                 addr::addr_parser p;
    1239          96 :                 p.set_protocol(proto);
    1240          96 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    1241             :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    1242         192 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(idx)));
    1243          96 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1244          96 :                 CATCH_REQUIRE(ips.size() == 1);
    1245          96 :                 addr::addr_range const & r(ips[0]);
    1246         192 :                 addr::addr f(r.get_from());
    1247          96 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1248          96 :                 uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
    1249          96 :                 int j(15);
    1250          96 :                 int m(128 - idx);
    1251        1130 :                 for(; m > 8; m -= 8, --j)
    1252             :                 {
    1253         517 :                     mask[j] = 0;
    1254             :                 }
    1255          96 :                 if(j < 0)
    1256             :                 {
    1257           0 :                     throw std::logic_error("invalid j here");
    1258             :                 }
    1259          96 :                 mask[j] = 255 << m;
    1260          96 :                 char buf[1024]; // really large buffer to make sure it does not get truncated
    1261          96 :                 if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
    1262             :                 {
    1263           0 :                     throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
    1264             :                 }
    1265         192 :                 std::string result("[::]:" + std::to_string(port) + "/[" + buf + "]");
    1266          96 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1267          96 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1268          96 :                 CATCH_REQUIRE(f.get_port() == port);
    1269          96 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1270             :             }
    1271             :         }
    1272             : 
    1273          18 :         CATCH_SECTION("no address, but one IPv6 masks")
    1274             :         {
    1275             :             // with just a number, the mask is considered an IPv6 mask
    1276             :             // if it is 33 or more
    1277             :             //
    1278           6 :             for(int idx(0); idx < 5; ++idx)
    1279             :             {
    1280           5 :                 int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
    1281           5 :                 int const port(rand() & 0xFFFF);
    1282          10 :                 addr::addr_parser p;
    1283           5 :                 p.set_protocol(proto);
    1284           5 :                 p.set_allow(addr::allow_t::ALLOW_MASK, true);
    1285             :                 //p.set_default_address("55:33:22:11:0:cc:bb:aa");
    1286          10 :                 addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]"));
    1287           5 :                 CATCH_REQUIRE_FALSE(p.has_errors());
    1288           5 :                 CATCH_REQUIRE(ips.size() == 1);
    1289           5 :                 addr::addr_range const & r(ips[0]);
    1290          10 :                 addr::addr f(r.get_from());
    1291           5 :                 CATCH_REQUIRE_FALSE(f.is_ipv4());
    1292          10 :                 std::string result("[::]:" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]");
    1293           5 :                 CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1294           5 :                 CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
    1295           5 :                 CATCH_REQUIRE(f.get_port() == port);
    1296           5 :                 CATCH_REQUIRE(f.get_protocol() == proto);
    1297             :             }
    1298             :         }
    1299             :     }
    1300          12 : }
    1301             : 
    1302             : 
    1303           9 : CATCH_TEST_CASE( "ipv6::network_type", "[ipv6]" )
    1304             : {
    1305          14 :     CATCH_GIVEN("addr()")
    1306             :     {
    1307          14 :         addr::addr a;
    1308             : 
    1309          14 :         CATCH_SECTION("any (::)")
    1310             :         {
    1311             :             {
    1312           1 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1313           1 :                 in6.sin6_family = AF_INET6;
    1314           1 :                 in6.sin6_port = htons(rand());
    1315           1 :                 in6.sin6_addr.s6_addr32[0] = 0;
    1316           1 :                 in6.sin6_addr.s6_addr32[1] = 0;
    1317           1 :                 in6.sin6_addr.s6_addr32[2] = 0;
    1318           1 :                 in6.sin6_addr.s6_addr32[3] = 0;
    1319             : 
    1320             :                 // verify network type
    1321             :                 //
    1322           1 :                 a.set_ipv6(in6);
    1323             : 
    1324           1 :                 CATCH_REQUIRE(a.is_default());
    1325           1 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_ANY);
    1326           1 :                 CATCH_REQUIRE(a.get_network_type_string() == "Any");
    1327             :             }
    1328             : 
    1329             :             // make sure that if any byte is set to non-zero it is not
    1330             :             // viewed as the ANY address
    1331             :             //
    1332          17 :             for(int idx(0); idx < 16; ++idx)
    1333             :             {
    1334          16 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1335          16 :                 in6.sin6_family = AF_INET6;
    1336          16 :                 in6.sin6_port = htons(rand());
    1337          16 :                 in6.sin6_addr.s6_addr32[0] = 0;
    1338          16 :                 in6.sin6_addr.s6_addr32[1] = 0;
    1339          16 :                 in6.sin6_addr.s6_addr32[2] = 0;
    1340          16 :                 in6.sin6_addr.s6_addr32[3] = 0;
    1341             : 
    1342             :                 // change one byte only
    1343             :                 //
    1344           0 :                 do
    1345             :                 {
    1346          16 :                     in6.sin6_addr.s6_addr[idx] = rand();
    1347             :                 }
    1348          16 :                 while(in6.sin6_addr.s6_addr[idx] == 0);
    1349             : 
    1350             :                 // verify network type
    1351             :                 //
    1352          16 :                 a.set_ipv6(in6);
    1353             : 
    1354          16 :                 CATCH_REQUIRE(a.get_network_type() != addr::addr::network_type_t::NETWORK_TYPE_ANY);
    1355          16 :                 CATCH_REQUIRE(a.get_network_type_string() != "Any");
    1356             :             }
    1357             :         }
    1358             : 
    1359          14 :         CATCH_SECTION("private address fd00::/8")
    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(0xFD00 | (rand() & 255));
    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_PRIVATE);
    1379          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Private");
    1380             :             }
    1381             :         }
    1382             : 
    1383          14 :         CATCH_SECTION("private address fe80::/10")
    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          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFE80 | (rand() & 63));
    1391          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1392          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1393          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1394          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1395          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1396          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1397          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1398             : 
    1399             :                 // verify network type
    1400             :                 //
    1401          10 :                 a.set_ipv6(in6);
    1402          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    1403          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
    1404             :             }
    1405             :         }
    1406             : 
    1407          14 :         CATCH_SECTION("private address ff02::/16")
    1408             :         {
    1409          11 :             for(int idx(0); idx < 10; ++idx)
    1410             :             {
    1411          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1412          10 :                 in6.sin6_family = AF_INET6;
    1413          10 :                 in6.sin6_port = htons(rand());
    1414          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF02);
    1415          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1416          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1417          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1418          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1419          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1420          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1421          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1422             : 
    1423             :                 // verify network type
    1424             :                 //
    1425          10 :                 a.set_ipv6(in6);
    1426          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
    1427          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
    1428             :             }
    1429             :         }
    1430             : 
    1431          14 :         CATCH_SECTION("private address ff00::/8")
    1432             :         {
    1433          11 :             for(int idx(0); idx < 10; ++idx)
    1434             :             {
    1435          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1436          10 :                 in6.sin6_family = AF_INET6;
    1437          10 :                 in6.sin6_port = htons(rand());
    1438           0 :                 do
    1439             :                 {
    1440          10 :                     in6.sin6_addr.s6_addr16[0] = htons(0xFF00 | (rand() & 255));
    1441             :                 }
    1442          10 :                 while((in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF01)       // ffx1::/16
    1443          10 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF02)       // ffx2::/16
    1444          10 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFFC0)) == htons(0xFE80)       // fe80::/10
    1445          20 :                    || (in6.sin6_addr.s6_addr16[0] & htons(0xFF00)) == htons(0xFD00));     // fd00::/8
    1446          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1447          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1448          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1449          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1450          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1451          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1452          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    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_MULTICAST);
    1458          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Multicast");
    1459             :             }
    1460             :         }
    1461             : 
    1462          14 :         CATCH_SECTION("private address ffx1::/8")
    1463             :         {
    1464          11 :             for(int idx(0); idx < 10; ++idx)
    1465             :             {
    1466          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1467          10 :                 in6.sin6_family = AF_INET6;
    1468          10 :                 in6.sin6_port = htons(rand());
    1469          10 :                 in6.sin6_addr.s6_addr16[0] = htons(0xFF01 | ((rand() & 15) << 4));
    1470          10 :                 in6.sin6_addr.s6_addr16[1] = rand();
    1471          10 :                 in6.sin6_addr.s6_addr16[2] = rand();
    1472          10 :                 in6.sin6_addr.s6_addr16[3] = rand();
    1473          10 :                 in6.sin6_addr.s6_addr16[4] = rand();
    1474          10 :                 in6.sin6_addr.s6_addr16[5] = rand();
    1475          10 :                 in6.sin6_addr.s6_addr16[6] = rand();
    1476          10 :                 in6.sin6_addr.s6_addr16[7] = rand();
    1477             : 
    1478             :                 // verify network type
    1479             :                 //
    1480          10 :                 a.set_ipv6(in6);
    1481          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1482          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1483             :             }
    1484             :         }
    1485             : 
    1486          14 :         CATCH_SECTION("private address ::1")
    1487             :         {
    1488          11 :             for(int idx(0); idx < 10; ++idx)
    1489             :             {
    1490          10 :                 struct sockaddr_in6 in6 = sockaddr_in6();
    1491          10 :                 in6.sin6_family = AF_INET6;
    1492          10 :                 in6.sin6_port = htons(rand());
    1493          10 :                 in6.sin6_addr.s6_addr16[0] = 0;
    1494          10 :                 in6.sin6_addr.s6_addr16[1] = 0;
    1495          10 :                 in6.sin6_addr.s6_addr16[2] = 0;
    1496          10 :                 in6.sin6_addr.s6_addr16[3] = 0;
    1497          10 :                 in6.sin6_addr.s6_addr16[4] = 0;
    1498          10 :                 in6.sin6_addr.s6_addr16[5] = 0;
    1499          10 :                 in6.sin6_addr.s6_addr16[6] = 0;
    1500          10 :                 in6.sin6_addr.s6_addr16[7] = htons(1);
    1501             : 
    1502             :                 // verify network type
    1503             :                 //
    1504          10 :                 a.set_ipv6(in6);
    1505          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1506          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1507             : 
    1508             :                 // try again from a string to confirm
    1509             :                 //
    1510          10 :                 struct addrinfo * addrlist(nullptr);
    1511          10 :                 int const port(rand() & 65535);
    1512          10 :                 int const r(getaddrinfo("::1", std::to_string(port).c_str(), nullptr, &addrlist));
    1513          10 :                 CATCH_REQUIRE(r == 0);
    1514          10 :                 CATCH_REQUIRE(addrlist != nullptr);
    1515          10 :                 CATCH_REQUIRE(addrlist->ai_family == AF_INET6);
    1516          10 :                 CATCH_REQUIRE(addrlist->ai_addrlen == sizeof(struct sockaddr_in6));
    1517          10 :                 a.set_ipv6(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
    1518          10 :                 CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
    1519          10 :                 CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
    1520          10 :                 freeaddrinfo(addrlist);
    1521             :             }
    1522             :         }
    1523             :     }
    1524           7 : }
    1525             : 
    1526             : 
    1527           5 : CATCH_TEST_CASE( "ipv6::network", "[ipv6]" )
    1528             : {
    1529           6 :     CATCH_GIVEN("set_from_socket()")
    1530             :     {
    1531           6 :         CATCH_SECTION("create a server, but do not test it (yet)...")
    1532             :         {
    1533           2 :             addr::addr_parser p;
    1534           2 :             addr::addr_range::vector_t ips(p.parse("[::1]:49999"));
    1535           1 :             CATCH_REQUIRE(ips.size() >= 1);
    1536             : 
    1537           1 :             addr::addr & a(ips[0].get_from());
    1538           1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_NONBLOCK | addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
    1539           1 :             CATCH_REQUIRE(s >= 0);
    1540           2 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    1541             : 
    1542           1 :             CATCH_REQUIRE(a.bind(s) == 0);
    1543             :         }
    1544             : 
    1545           6 :         CATCH_SECTION("connect with TCP to [::1]")
    1546             :         {
    1547           1 :             if(SNAP_CATCH2_NAMESPACE::g_tcp_port != -1)
    1548             :             {
    1549           2 :                 addr::addr_parser p;
    1550           2 :                 addr::addr_range::vector_t ips(p.parse("[::1]:" + std::to_string(SNAP_CATCH2_NAMESPACE::g_tcp_port)));
    1551           1 :                 CATCH_REQUIRE(ips.size() >= 1);
    1552             : 
    1553           1 :                 addr::addr & a(ips[0].get_from());
    1554           1 :                 int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    1555           1 :                 CATCH_REQUIRE(s >= 0);
    1556           2 :                 std::shared_ptr<int> auto_free(&s, socket_deleter);
    1557             : 
    1558           1 :                 CATCH_REQUIRE(a.connect(s) == 0);
    1559             : 
    1560             :                 // get socket info from the other side (peer == true)
    1561             :                 //
    1562           2 :                 addr::addr b;
    1563           1 :                 b.set_from_socket(s, true);
    1564           1 :                 CATCH_REQUIRE_FALSE(b.is_ipv4());
    1565           1 :                 CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::1");
    1566           1 :                 CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
    1567             : 
    1568             :                 // in this case we know what the port is since we specified
    1569             :                 // that when connecting
    1570             :                 //
    1571           1 :                 CATCH_REQUIRE(b.get_port() == SNAP_CATCH2_NAMESPACE::g_tcp_port);
    1572             : 
    1573             :                 // now try this side (peer == false)
    1574             :                 //
    1575           2 :                 addr::addr c;
    1576           1 :                 c.set_from_socket(s, false);
    1577           1 :                 CATCH_REQUIRE_FALSE(c.is_ipv4());
    1578           1 :                 CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::1");
    1579           1 :                 CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
    1580             : 
    1581             :                 // we cannot be sure of the port, there is a range we could
    1582             :                 // test better (more constraining) but for this test is
    1583             :                 // certainly does not matter much; it has to be more than
    1584             :                 // 1023, though
    1585             :                 //
    1586           1 :                 CATCH_REQUIRE(c.get_port() > 1023);
    1587             :             }
    1588             :             else
    1589             :             {
    1590             :                 // avoid issue of no assertions
    1591             :                 //
    1592           0 :                 CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::g_tcp_port == -1);
    1593           0 :                 std::cout << "connect to [::1] test skipped as no TCP port was specified on the command line." << std::endl;
    1594             :             }
    1595             :         }
    1596             : 
    1597           6 :         CATCH_SECTION("connect with UDP to [::1]")
    1598             :         {
    1599           2 :             addr::addr_parser p;
    1600           1 :             p.set_protocol("udp");
    1601           2 :             addr::addr_range::vector_t ips(p.parse("[::1]:53"));
    1602           1 :             CATCH_REQUIRE(ips.size() >= 1);
    1603             : 
    1604           1 :             addr::addr & a(ips[0].get_from());
    1605           1 :             int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
    1606           1 :             CATCH_REQUIRE(s >= 0);
    1607           2 :             std::shared_ptr<int> auto_free(&s, socket_deleter);
    1608             : 
    1609           1 :             CATCH_REQUIRE(a.connect(s) == -1);
    1610             : 
    1611             :             // get socket info from the other side (peer == true)
    1612             :             //
    1613           2 :             addr::addr b;
    1614           1 :             CATCH_REQUIRE_THROWS_AS(b.set_from_socket(s, true), addr::addr_io_error);
    1615           1 :             CATCH_REQUIRE_FALSE(b.is_ipv4());
    1616           1 :             CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::");
    1617           1 :             CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
    1618             : 
    1619             :             // in this case we know what the port is since we specified
    1620             :             // that when connecting
    1621             :             //
    1622           1 :             CATCH_REQUIRE(b.get_port() == 0);
    1623             : 
    1624             :             // now try this side (peer == false)
    1625             :             //
    1626           2 :             addr::addr c;
    1627           1 :             c.set_from_socket(s, false);
    1628           1 :             CATCH_REQUIRE_FALSE(c.is_ipv4());
    1629           1 :             CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY)    == "::");
    1630           1 :             CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
    1631             : 
    1632             :             // we cannot be sure of the port, there is a range we could
    1633             :             // test better (more constraining) but for this test is
    1634             :             // certainly does not matter much; it has to be more than
    1635             :             // 1023, though
    1636             :             //
    1637           1 :             CATCH_REQUIRE(c.get_port() == 0);
    1638             :         }
    1639             :     }
    1640           9 : }
    1641             : 
    1642             : 
    1643             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13