LCOV - code coverage report
Current view: top level - src/test - pcp_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 89.4 % 255 228
Test Date: 2025-09-13 05:20:27 Functions: 82.4 % 51 42
Branches: 49.8 % 1322 659

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <common/pcp.h>
       6                 :             : #include <netbase.h>
       7                 :             : #include <test/util/logging.h>
       8                 :             : #include <test/util/setup_common.h>
       9                 :             : #include <util/time.h>
      10                 :             : 
      11                 :             : #include <boost/test/unit_test.hpp>
      12                 :             : 
      13                 :             : #include <algorithm>
      14                 :             : #include <deque>
      15                 :             : 
      16                 :             : using namespace std::literals;
      17                 :             : 
      18                 :             : static CThreadInterrupt g_interrupt;
      19                 :             : 
      20                 :             : /// UDP test server operation.
      21   [ +  -  +  - ]:         104 : struct TestOp {
      22                 :             :     std::chrono::milliseconds delay;
      23                 :             :     enum Op {
      24                 :             :         SEND, // Expect send (with optional data)
      25                 :             :         RECV, // Expect receive (with data)
      26                 :             :         NOP,  // Just delay
      27                 :             :     } op;
      28                 :             :     std::vector<uint8_t> data;
      29                 :             : 
      30                 :             :     //! Injected error.
      31                 :             :     //! Set this field to a non-zero value to return the errno code from send or receive operation.
      32                 :             :     int error;
      33                 :             : 
      34                 :          26 :     TestOp(std::chrono::milliseconds delay_in, Op op_in, const std::vector<uint8_t> &data_in, int error_in):
      35   [ +  -  +  -  :          23 :         delay(delay_in), op(op_in), data(data_in), error(error_in) {}
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
      36                 :             : };
      37                 :             : 
      38                 :             : /// Save the value of CreateSock and restore when the test ends.
      39                 :             : class PCPTestingSetup : public BasicTestingSetup
      40                 :             : {
      41                 :             : public:
      42                 :          10 :     explicit PCPTestingSetup(const ChainType chainType = ChainType::MAIN,
      43                 :             :                              TestOpts opts = {})
      44                 :          10 :         : BasicTestingSetup{chainType, opts},
      45   [ +  -  +  -  :          20 :           m_create_sock_orig{CreateSock}
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      46                 :             :     {
      47   [ +  -  +  -  :          20 :         const std::optional<CService> local_ipv4{Lookup("192.168.0.6", 1, false)};
                   +  - ]
      48   [ +  -  +  -  :          20 :         const std::optional<CService> local_ipv6{Lookup("2a10:1234:5678:9abc:def0:1234:5678:9abc", 1, false)};
                   +  - ]
      49   [ +  -  +  -  :          20 :         const std::optional<CService> gateway_ipv4{Lookup("192.168.0.1", 1, false)};
                   +  - ]
      50   [ +  -  +  -  :          20 :         const std::optional<CService> gateway_ipv6{Lookup("2a10:1234:5678:9abc:def0:0000:0000:0000", 1, false)};
                   +  - ]
      51   [ +  -  +  -  :          20 :         BOOST_REQUIRE(local_ipv4 && local_ipv6 && gateway_ipv4 && gateway_ipv6);
          +  -  +  -  -  
                +  +  - ]
      52                 :          10 :         default_local_ipv4 = *local_ipv4;
      53                 :          10 :         default_local_ipv6 = *local_ipv6;
      54                 :          10 :         default_gateway_ipv4 = *gateway_ipv4;
      55                 :          10 :         default_gateway_ipv6 = *gateway_ipv6;
      56                 :             : 
      57                 :          10 :         struct in_addr inaddr_any;
      58         [ +  - ]:          10 :         inaddr_any.s_addr = htonl(INADDR_ANY);
      59         [ +  - ]:          10 :         bind_any_ipv4 = CNetAddr(inaddr_any);
      60                 :          10 :     }
      61                 :             : 
      62                 :          10 :     ~PCPTestingSetup()
      63                 :          10 :     {
      64                 :          10 :         CreateSock = m_create_sock_orig;
      65                 :          10 :         MockableSteadyClock::ClearMockTime();
      66                 :          10 :     }
      67                 :             : 
      68                 :             :     // Default testing nonce.
      69                 :             :     static constexpr PCPMappingNonce TEST_NONCE{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
      70                 :             :     // Default network addresses.
      71                 :             :     CNetAddr default_local_ipv4;
      72                 :             :     CNetAddr default_local_ipv6;
      73                 :             :     CNetAddr default_gateway_ipv4;
      74                 :             :     CNetAddr default_gateway_ipv6;
      75                 :             :     // IPv4 bind
      76                 :             :     CNetAddr bind_any_ipv4;
      77                 :             : private:
      78                 :             :     const decltype(CreateSock) m_create_sock_orig;
      79                 :             : };
      80                 :             : 
      81                 :             : /** Simple scripted UDP server emulation for testing.
      82                 :             :  */
      83                 :             : class PCPTestSock final : public Sock
      84                 :             : {
      85                 :             : public:
      86                 :             :     // Note: we awkwardly mark all methods as const, and properties as mutable,
      87                 :             :     // because Sock expects all networking calls to be const.
      88                 :          11 :     explicit PCPTestSock(const CNetAddr &local_ip, const CNetAddr &gateway_ip, const std::vector<TestOp> &script)
      89                 :          11 :         : Sock{INVALID_SOCKET},
      90                 :          11 :           m_script(script),
      91                 :          11 :           m_local_ip(local_ip),
      92   [ +  -  +  - ]:          22 :           m_gateway_ip(gateway_ip)
      93                 :             :     {
      94                 :          22 :         ElapseTime(std::chrono::seconds(0)); // start mocking steady time
      95         [ +  - ]:          11 :         PrepareOp();
      96                 :          11 :     }
      97                 :             : 
      98                 :           0 :     PCPTestSock& operator=(Sock&& other) override
      99                 :             :     {
     100                 :           0 :         assert(false && "Move of Sock into PCPTestSock not allowed.");
     101                 :             :         return *this;
     102                 :             :     }
     103                 :             : 
     104                 :          16 :     ssize_t Send(const void* data, size_t len, int) const override {
     105         [ +  - ]:          16 :         if (!m_connected) return -1;
     106         [ -  + ]:          16 :         std::span in_pkt = std::span(static_cast<const uint8_t*>(data), len);
     107         [ -  + ]:          13 :         if (AtEndOfScript() || CurOp().op != TestOp::SEND) {
     108                 :             :             // Ignore sends after end of script, or sends when we expect a receive.
     109                 :           6 :             FailScript();
     110                 :           3 :             return len;
     111                 :             :         }
     112         [ +  - ]:          13 :         if (CurOp().error) return -1; // Inject failure
     113   [ +  +  -  + ]:          13 :         if (CurOp().data.empty() || std::ranges::equal(CurOp().data, in_pkt)) {
     114                 :          13 :             AdvanceOp();
     115                 :             :         } else {
     116                 :             :             // Wrong send, fail script
     117                 :           0 :             FailScript();
     118                 :             :         }
     119                 :          13 :         return len;
     120                 :             :     }
     121                 :             : 
     122                 :          12 :     ssize_t Recv(void* buf, size_t len, int flags) const override
     123                 :             :     {
     124   [ +  -  +  -  :          24 :         if (!m_connected || AtEndOfScript() || CurOp().op != TestOp::RECV || m_time_left != 0s) {
                   -  + ]
     125                 :           0 :             return -1;
     126                 :             :         }
     127         [ +  + ]:          12 :         if (CurOp().error) return -1; // Inject failure
     128                 :          11 :         const auto &recv_pkt = CurOp().data;
     129   [ -  +  -  + ]:          11 :         const size_t consume_bytes{std::min(len, recv_pkt.size())};
     130         [ +  - ]:          11 :         std::memcpy(buf, recv_pkt.data(), consume_bytes);
     131         [ +  - ]:          11 :         if ((flags & MSG_PEEK) == 0) {
     132                 :          11 :             AdvanceOp();
     133                 :             :         }
     134                 :          11 :         return consume_bytes;
     135                 :             :     }
     136                 :             : 
     137                 :          11 :     int Connect(const sockaddr* sa, socklen_t sa_len) const override {
     138                 :          11 :         CService service;
     139   [ +  -  +  -  :          22 :         if (service.SetSockAddr(sa, sa_len) && service == CService(m_gateway_ip, 5351)) {
          +  -  +  -  +  
                -  +  - ]
     140   [ +  -  +  + ]:          11 :             if (m_bound.IsBindAny()) { // If bind-any, bind to local ip.
     141         [ +  - ]:           9 :                 m_bound = CService(m_local_ip, 0);
     142                 :             :             }
     143   [ +  -  +  - ]:          11 :             if (m_bound.GetPort() == 0) { // If no port assigned, assign port 1.
     144         [ +  - ]:          11 :                 m_bound = CService(m_bound, 1);
     145                 :             :             }
     146                 :          11 :             m_connected = true;
     147                 :          11 :             return 0;
     148                 :             :         }
     149                 :             :         return -1;
     150                 :          11 :     }
     151                 :             : 
     152                 :           8 :     int Bind(const sockaddr* sa, socklen_t sa_len) const override {
     153                 :           8 :         CService service;
     154   [ +  -  +  - ]:           8 :         if (service.SetSockAddr(sa, sa_len)) {
     155                 :             :             // Can only bind to one of our local ips
     156   [ +  -  +  +  :           8 :             if (!service.IsBindAny() && service != m_local_ip) {
             +  -  +  - ]
     157                 :             :                 return -1;
     158                 :             :             }
     159                 :           8 :             m_bound = service;
     160                 :           8 :             return 0;
     161                 :             :         }
     162                 :             :         return -1;
     163                 :           8 :     }
     164                 :             : 
     165                 :           0 :     int Listen(int) const override { return -1; }
     166                 :             : 
     167                 :           0 :     std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override
     168                 :             :     {
     169                 :           0 :         return nullptr;
     170                 :             :     };
     171                 :             : 
     172                 :           0 :     int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override
     173                 :             :     {
     174                 :           0 :         return -1;
     175                 :             :     }
     176                 :             : 
     177                 :           0 :     int SetSockOpt(int, int, const void*, socklen_t) const override { return 0; }
     178                 :             : 
     179                 :          11 :     int GetSockName(sockaddr* name, socklen_t* name_len) const override
     180                 :             :     {
     181                 :             :         // Return the address we've been bound to.
     182         [ -  + ]:          11 :         return m_bound.GetSockAddr(name, name_len) ? 0 : -1;
     183                 :             :     }
     184                 :             : 
     185                 :           0 :     bool SetNonBlocking() const override { return true; }
     186                 :             : 
     187                 :           0 :     bool IsSelectable() const override { return true; }
     188                 :             : 
     189                 :          16 :     bool Wait(std::chrono::milliseconds timeout,
     190                 :             :               Event requested,
     191                 :             :               Event* occurred = nullptr) const override
     192                 :             :     {
     193                 :             :         // Only handles receive events.
     194         [ +  - ]:          13 :         if (AtEndOfScript() || requested != Sock::RECV) {
     195                 :           3 :             ElapseTime(timeout);
     196                 :             :         } else {
     197                 :          13 :             std::chrono::milliseconds delay = std::min(m_time_left, timeout);
     198                 :          26 :             ElapseTime(delay);
     199                 :          13 :             m_time_left -= delay;
     200   [ +  +  +  -  :          13 :             if (CurOp().op == TestOp::RECV && m_time_left == 0s && occurred != nullptr) {
                   +  - ]
     201                 :          12 :                 *occurred = Sock::RECV;
     202                 :             :             }
     203         [ +  + ]:          13 :             if (CurOp().op == TestOp::NOP) {
     204                 :             :                 // This was a pure delay operation, move to the next op.
     205                 :           1 :                 AdvanceOp();
     206                 :             :             }
     207                 :             :         }
     208                 :          16 :         return true;
     209                 :             :     }
     210                 :             : 
     211                 :           0 :     bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override
     212                 :             :     {
     213                 :           0 :         return false;
     214                 :             :     }
     215                 :             : 
     216                 :           0 :     bool IsConnected(std::string&) const override
     217                 :             :     {
     218                 :           0 :         return true;
     219                 :             :     }
     220                 :             : 
     221                 :             : private:
     222                 :             :     const std::vector<TestOp> m_script;
     223                 :             :     mutable size_t m_script_ptr = 0;
     224                 :             :     mutable std::chrono::milliseconds m_time_left;
     225                 :             :     mutable std::chrono::milliseconds m_time{MockableSteadyClock::INITIAL_MOCK_TIME};
     226                 :             :     mutable bool m_connected{false};
     227                 :             :     mutable CService m_bound;
     228                 :             :     mutable CNetAddr m_local_ip;
     229                 :             :     mutable CNetAddr m_gateway_ip;
     230                 :             : 
     231                 :          27 :     void ElapseTime(std::chrono::milliseconds duration) const
     232                 :             :     {
     233         [ +  - ]:          27 :         m_time += duration;
     234         [ +  - ]:          27 :         MockableSteadyClock::SetMockTime(m_time);
     235                 :          14 :     }
     236                 :             : 
     237   [ -  +  +  +  :          44 :     bool AtEndOfScript() const { return m_script_ptr == m_script.size(); }
          -  +  +  -  -  
                +  +  + ]
     238                 :         138 :     const TestOp &CurOp() const {
     239   [ -  +  +  - ]:         276 :         BOOST_REQUIRE(m_script_ptr < m_script.size());
     240                 :         138 :         return m_script[m_script_ptr];
     241                 :             :     }
     242                 :             : 
     243                 :          36 :     void PrepareOp() const {
     244   [ -  +  +  + ]:          36 :         if (AtEndOfScript()) return;
     245                 :          26 :         m_time_left = CurOp().delay;
     246                 :             :     }
     247                 :             : 
     248                 :          25 :     void AdvanceOp() const
     249                 :             :     {
     250                 :          25 :         m_script_ptr += 1;
     251                 :          25 :         PrepareOp();
     252                 :          25 :     }
     253                 :             : 
     254   [ -  +  -  - ]:           3 :     void FailScript() const { m_script_ptr = m_script.size(); }
     255                 :             : };
     256                 :             : 
     257                 :             : BOOST_FIXTURE_TEST_SUITE(pcp_tests, PCPTestingSetup)
     258                 :             : 
     259                 :             : // NAT-PMP IPv4 good-weather scenario.
     260   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(natpmp_ipv4)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     261                 :             : {
     262                 :           1 :     const std::vector<TestOp> script{
     263                 :             :         {
     264                 :             :             0ms, TestOp::SEND,
     265                 :             :             {
     266                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     267                 :             :             }, 0
     268                 :             :         },
     269                 :             :         {
     270                 :             :             2ms, TestOp::RECV,
     271                 :             :             {
     272                 :             :                 0x00, 0x80, 0x00, 0x00, // version, opcode (external IP), result code (success)
     273                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     274                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     275                 :             :             }, 0
     276                 :             :         },
     277                 :             :         {
     278                 :             :             0ms, TestOp::SEND,
     279                 :             :             {
     280                 :             :                 0x00, 0x02, 0x00, 0x00, // version, opcode (request map TCP)
     281                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     282                 :             :                 0x00, 0x00, 0x03, 0xe8, // requested mapping lifetime in seconds
     283                 :             :             }, 0
     284                 :             :         },
     285                 :             :         {
     286                 :             :             2ms, TestOp::RECV,
     287                 :             :             {
     288                 :             :                 0x00, 0x82, 0x00, 0x00, // version, opcode (mapped TCP)
     289                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     290                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, mapped external port
     291                 :             :                 0x00, 0x00, 0x01, 0xf4, // mapping lifetime in seconds
     292                 :             :             }, 0
     293                 :             :         },
     294   [ +  +  -  - ]:           6 :     };
     295                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     296   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     297                 :           0 :         return std::unique_ptr<PCPTestSock>();
     298                 :           1 :     };
     299                 :             : 
     300         [ +  - ]:           1 :     auto res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, g_interrupt, 1, 200ms);
     301                 :             : 
     302         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     303   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     304   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 0);
     305   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "192.168.0.6:1234");
                   +  - ]
     306   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "1.2.3.4:1234");
                   +  - ]
     307   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     308   [ +  -  +  -  :           6 : }
          +  -  +  -  +  
                -  -  - ]
     309                 :             : 
     310                 :             : // PCP IPv4 good-weather scenario.
     311   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     312                 :             : {
     313                 :           1 :     const std::vector<TestOp> script{
     314                 :             :         {
     315                 :             :             0ms, TestOp::SEND,
     316                 :             :             {
     317                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     318                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     319                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     320                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     321                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     322                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     323                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     324                 :             :             }, 0
     325                 :             :         },
     326                 :             :         {
     327                 :             :             250ms, TestOp::RECV, // 250ms delay before answer
     328                 :             :             {
     329                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     330                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     331                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     332                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     333                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     334                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     335                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, // assigned external IP
     336                 :             :             }, 0
     337                 :             :         },
     338   [ +  +  -  - ]:           4 :     };
     339                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     340   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     341                 :           0 :         return std::unique_ptr<PCPTestSock>();
     342                 :           1 :     };
     343                 :             : 
     344         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 1, 1000ms);
     345                 :             : 
     346         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     347   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     348   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 2);
     349   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "192.168.0.6:1234");
                   +  - ]
     350   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "1.2.3.4:1234");
                   +  - ]
     351   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     352   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     353                 :             : 
     354                 :             : // PCP IPv6 good-weather scenario.
     355   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv6)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     356                 :             : {
     357                 :           1 :     const std::vector<TestOp> script{
     358                 :             :         {
     359                 :             :             0ms, TestOp::SEND,
     360                 :             :             {
     361                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     362                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     363                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     364                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     365                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     366                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     367                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     368                 :             :             }, 0
     369                 :             :         },
     370                 :             :         {
     371                 :             :             500ms, TestOp::RECV, // 500ms delay before answer
     372                 :             :             {
     373                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     374                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     375                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     376                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     377                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     378                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     379                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     380                 :             :             }, 0
     381                 :             :         },
     382   [ +  +  -  - ]:           4 :     };
     383                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     384   [ +  -  +  - ]:           1 :         if (domain == AF_INET6 && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv6, default_gateway_ipv6, script);
     385                 :           0 :         return std::unique_ptr<PCPTestSock>();
     386                 :           1 :     };
     387                 :             : 
     388         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv6, default_local_ipv6, 1234, 1000, g_interrupt, 1, 1000ms);
     389                 :             : 
     390         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     391   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     392   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 2);
     393   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "[2a10:1234:5678:9abc:def0:1234:5678:9abc]:1234");
                   +  - ]
     394   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "[2a10:1234:5678:9abc:def0:1234:5678:9abc]:1234");
                   +  - ]
     395   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     396   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     397                 :             : 
     398                 :             : // PCP timeout.
     399   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_timeout)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     400                 :             : {
     401                 :           1 :     const std::vector<TestOp> script{};
     402                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     403   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     404                 :           0 :         return std::unique_ptr<PCPTestSock>();
     405                 :           1 :     };
     406                 :             : 
     407   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (1)");
     408   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (2)");
     409   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Timeout");
     410                 :             : 
     411         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 3, 2000ms);
     412                 :             : 
     413         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     414   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     415   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NETWORK_ERROR);
     416   [ +  -  +  -  :           1 : }
                   +  - ]
     417                 :             : 
     418                 :             : // PCP failure receiving (router sends ICMP port closed).
     419   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_connrefused)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     420                 :             : {
     421                 :           1 :     const std::vector<TestOp> script{
     422                 :             :         {
     423                 :             :             0ms, TestOp::SEND,
     424                 :             :             { // May send anything.
     425                 :             :             }, 0
     426                 :             :         },
     427                 :             :         {
     428                 :             :             0ms, TestOp::RECV,
     429                 :             :             {
     430                 :             :             }, ECONNREFUSED
     431                 :             :         },
     432   [ +  +  -  - ]:           4 :     };
     433                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     434   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     435                 :           0 :         return std::unique_ptr<PCPTestSock>();
     436                 :           1 :     };
     437                 :             : 
     438   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Could not receive response");
     439                 :             : 
     440         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 3, 2000ms);
     441                 :             : 
     442         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     443   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     444   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NETWORK_ERROR);
     445   [ +  -  +  -  :           2 : }
          +  -  +  -  -  
                      - ]
     446                 :             : 
     447                 :             : // PCP IPv6 success after one timeout.
     448   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv6_timeout_success)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     449                 :             : {
     450                 :           1 :     const std::vector<TestOp> script{
     451                 :             :         {
     452                 :             :             0ms, TestOp::SEND,
     453                 :             :             {
     454                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     455                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     456                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     457                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     458                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     459                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     460                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     461                 :             :             }, 0
     462                 :             :         },
     463                 :             :         {
     464                 :             :             2001ms, TestOp::NOP, // Takes longer to respond than timeout of 2000ms
     465                 :             :             {}, 0
     466                 :             :         },
     467                 :             :         {
     468                 :             :             0ms, TestOp::SEND, // Repeated send (try 2)
     469                 :             :             {
     470                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     471                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     472                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     473                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     474                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     475                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     476                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     477                 :             :             }, 0
     478                 :             :         },
     479                 :             :         {
     480                 :             :             200ms, TestOp::RECV, // This time we're in time
     481                 :             :             {
     482                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     483                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     484                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     485                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     486                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     487                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     488                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     489                 :             :             }, 0
     490                 :             :         },
     491   [ +  +  -  - ]:           6 :     };
     492                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     493   [ +  -  +  - ]:           1 :         if (domain == AF_INET6 && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv6, default_gateway_ipv6, script);
     494                 :           0 :         return std::unique_ptr<PCPTestSock>();
     495                 :           1 :     };
     496                 :             : 
     497   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (1)");
     498   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Timeout");
     499                 :             : 
     500         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv6, default_local_ipv6, 1234, 1000, g_interrupt, 2, 2000ms);
     501                 :             : 
     502   [ +  -  +  -  :           3 :     BOOST_CHECK(std::get_if<MappingResult>(&res));
                   +  - ]
     503   [ +  -  +  -  :           5 : }
          +  -  +  -  +  
          -  +  -  +  -  
                   -  - ]
     504                 :             : 
     505                 :             : // PCP IPv4 failure (no resources).
     506   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4_fail_no_resources)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     507                 :             : {
     508                 :           1 :     const std::vector<TestOp> script{
     509                 :             :         {
     510                 :             :             0ms, TestOp::SEND,
     511                 :             :             {
     512                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     513                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     514                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     515                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     516                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     517                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     518                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     519                 :             :             }, 0
     520                 :             :         },
     521                 :             :         {
     522                 :             :             500ms, TestOp::RECV,
     523                 :             :             {
     524                 :             :                 0x02, 0x81, 0x00, 0x08, // version, opcode, result 0x08: no resources
     525                 :             :                 0x00, 0x00, 0x00, 0x00, // granted lifetime
     526                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     527                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     528                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     529                 :             :                 0x04, 0xd2, 0x00, 0x00, // internal port, assigned external port
     530                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // assigned external IP
     531                 :             :             }, 0
     532                 :             :         },
     533   [ +  +  -  - ]:           4 :     };
     534                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     535   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     536                 :           0 :         return std::unique_ptr<PCPTestSock>();
     537                 :           1 :     };
     538                 :             : 
     539         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 3, 1000ms);
     540                 :             : 
     541         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     542   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     543   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NO_RESOURCES);
     544   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     545                 :             : 
     546                 :             : // PCP IPv4 failure (test NATPMP downgrade scenario).
     547   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4_fail_unsupported_version)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     548                 :             : {
     549                 :           1 :     const std::vector<TestOp> script{
     550                 :             :         {
     551                 :             :             0ms, TestOp::SEND,
     552                 :             :             {
     553                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     554                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     555                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     556                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     557                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     558                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     559                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     560                 :             :             }, 0
     561                 :             :         },
     562                 :             :         {
     563                 :             :             500ms, TestOp::RECV,
     564                 :             :             {
     565                 :             :                 0x00, 0x81, 0x00, 0x01, // version, opcode, result 0x01: unsupported version
     566                 :             :                 0x00, 0x00, 0x00, 0x00,
     567                 :             :             }, 0
     568                 :             :         },
     569   [ +  +  -  - ]:           4 :     };
     570                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     571   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     572                 :           0 :         return std::unique_ptr<PCPTestSock>();
     573                 :           1 :     };
     574                 :             : 
     575         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 3, 1000ms);
     576                 :             : 
     577         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     578   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     579   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::UNSUPP_VERSION);
     580   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     581                 :             : 
     582                 :             : // NAT-PMP IPv4 protocol error scenarii.
     583   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(natpmp_protocol_error)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     584                 :             : {
     585                 :             :     // First scenario: non-0 result code when requesting external IP.
     586                 :           1 :     std::vector<TestOp> script{
     587                 :             :         {
     588                 :             :             0ms, TestOp::SEND,
     589                 :             :             {
     590                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     591                 :             :             }, 0
     592                 :             :         },
     593                 :             :         {
     594                 :             :             2ms, TestOp::RECV,
     595                 :             :             {
     596                 :             :                 0x00, 0x80, 0x00, 0x42, // version, opcode (external IP), result code (*NOT* success)
     597                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     598                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     599                 :             :             }, 0
     600                 :             :         },
     601   [ +  +  -  - ]:           4 :     };
     602                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     603   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     604                 :           0 :         return std::unique_ptr<PCPTestSock>();
     605                 :           1 :     };
     606                 :             : 
     607         [ +  - ]:           1 :     auto res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, g_interrupt, 1, 200ms);
     608                 :             : 
     609         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     610   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     611   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     612                 :             : 
     613                 :             :     // First scenario: non-0 result code when requesting port mapping.
     614                 :           1 :     script = {
     615                 :             :         {
     616                 :             :             0ms, TestOp::SEND,
     617                 :             :             {
     618                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     619                 :             :             }, 0
     620                 :             :         },
     621                 :             :         {
     622                 :             :             2ms, TestOp::RECV,
     623                 :             :             {
     624                 :             :                 0x00, 0x80, 0x00, 0x00, // version, opcode (external IP), result code (success)
     625                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     626                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     627                 :             :             }, 0
     628                 :             :         },
     629                 :             :         {
     630                 :             :             0ms, TestOp::SEND,
     631                 :             :             {
     632                 :             :                 0x00, 0x02, 0x00, 0x00, // version, opcode (request map TCP)
     633                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     634                 :             :                 0x00, 0x00, 0x03, 0xe8, // requested mapping lifetime in seconds
     635                 :             :             }, 0
     636                 :             :         },
     637                 :             :         {
     638                 :             :             2ms, TestOp::RECV,
     639                 :             :             {
     640                 :             :                 0x00, 0x82, 0x00, 0x43, // version, opcode (mapped TCP)
     641                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     642                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, mapped external port
     643                 :             :                 0x00, 0x00, 0x01, 0xf4, // mapping lifetime in seconds
     644                 :             :             }, 0
     645                 :             :         },
     646   [ +  +  -  - ]:           6 :     };
     647                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     648   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     649                 :           0 :         return std::unique_ptr<PCPTestSock>();
     650                 :           1 :     };
     651                 :             : 
     652         [ +  - ]:           2 :     res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, g_interrupt, 1, 200ms);
     653                 :             : 
     654         [ +  - ]:           1 :     err = std::get_if<MappingError>(&res);
     655   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     656   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     657   [ +  -  +  -  :           9 : }
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  -  -  
                      - ]
     658                 :             : 
     659                 :             : // PCP IPv4 protocol error scenario.
     660   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_protocol_error)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     661                 :             : {
     662                 :           1 :     const std::vector<TestOp> script{
     663                 :             :         {
     664                 :             :             0ms, TestOp::SEND,
     665                 :             :             {
     666                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     667                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     668                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     669                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     670                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     671                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     672                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     673                 :             :             }, 0
     674                 :             :         },
     675                 :             :         {
     676                 :             :             250ms, TestOp::RECV, // 250ms delay before answer
     677                 :             :             {
     678                 :             :                 0x02, 0x81, 0x00, 0x42, // version, opcode, result error
     679                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     680                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     681                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     682                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     683                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     684                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, // assigned external IP
     685                 :             :             }, 0
     686                 :             :         },
     687   [ +  +  -  - ]:           4 :     };
     688                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     689   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     690                 :           0 :         return std::unique_ptr<PCPTestSock>();
     691                 :           1 :     };
     692                 :             : 
     693         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, g_interrupt, 1, 1000ms);
     694                 :             : 
     695         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     696   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     697   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     698   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     699                 :             : 
     700                 :             : BOOST_AUTO_TEST_SUITE_END()
     701                 :             : 
        

Generated by: LCOV version 2.0-1