Coverage Report

Created: 2026-09-01 13:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/common/pcp.cpp
Line
Count
Source
1
// Copyright (c) 2024-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
4
5
#include <common/pcp.h>
6
7
#include <compat/compat.h>
8
#include <crypto/common.h>
9
#include <crypto/hex_base.h>
10
#include <netaddress.h>
11
#include <netbase.h>
12
#include <tinyformat.h>
13
#include <util/check.h>
14
#include <util/log.h>
15
#include <util/sock.h>
16
#include <util/string.h>
17
#include <util/threadinterrupt.h>
18
#include <util/time.h>
19
20
#include <algorithm>
21
#include <atomic>
22
#include <compare>
23
#include <cstring>
24
#include <functional>
25
#include <map>
26
#include <memory>
27
#include <optional>
28
#include <span>
29
#include <utility>
30
#include <vector>
31
32
namespace {
33
34
// RFC6886 NAT-PMP and RFC6887 Port Control Protocol (PCP) implementation.
35
// NAT-PMP and PCP use network byte order (big-endian).
36
37
// NAT-PMP (v0) protocol constants.
38
//! NAT-PMP uses a fixed server port number (RFC6887 section 1.1).
39
constexpr uint16_t NATPMP_SERVER_PORT = 5351;
40
//! Version byte for NATPMP (RFC6886 1.1)
41
constexpr uint8_t NATPMP_VERSION = 0;
42
//! Request opcode base (RFC6886 3).
43
constexpr uint8_t NATPMP_REQUEST = 0x00;
44
//! Response opcode base (RFC6886 3).
45
constexpr uint8_t NATPMP_RESPONSE = 0x80;
46
//! Get external address (RFC6886 3.2)
47
constexpr uint8_t NATPMP_OP_GETEXTERNAL = 0x00;
48
//! Map TCP port (RFC6886 3.3)
49
constexpr uint8_t NATPMP_OP_MAP_TCP = 0x02;
50
//! Shared request header size in bytes.
51
constexpr size_t NATPMP_REQUEST_HDR_SIZE = 2;
52
//! Shared response header (minimum) size in bytes.
53
constexpr size_t NATPMP_RESPONSE_HDR_SIZE = 8;
54
//! GETEXTERNAL request size in bytes, including header (RFC6886 3.2).
55
constexpr size_t NATPMP_GETEXTERNAL_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 0;
56
//! GETEXTERNAL response size in bytes, including header (RFC6886 3.2).
57
constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_SIZE = NATPMP_RESPONSE_HDR_SIZE + 4;
58
//! MAP request size in bytes, including header (RFC6886 3.3).
59
constexpr size_t NATPMP_MAP_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 10;
60
//! MAP response size in bytes, including header (RFC6886 3.3).
61
constexpr size_t NATPMP_MAP_RESPONSE_SIZE = NATPMP_RESPONSE_HDR_SIZE + 8;
62
63
// Shared header offsets (RFC6886 3.2, 3.3), relative to start of packet.
64
//!  Offset of version field in packets.
65
constexpr size_t NATPMP_HDR_VERSION_OFS = 0;
66
//!  Offset of opcode field in packets
67
constexpr size_t NATPMP_HDR_OP_OFS = 1;
68
//!  Offset of result code in packets. Result codes are 16 bit in NAT-PMP instead of 8 bit in PCP.
69
constexpr size_t NATPMP_RESPONSE_HDR_RESULT_OFS = 2;
70
71
// GETEXTERNAL response offsets (RFC6886 3.2), relative to start of packet.
72
//!  Returned external address
73
constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_IP_OFS = 8;
74
75
// MAP request offsets (RFC6886 3.3), relative to start of packet.
76
//!  Internal port to be mapped.
77
constexpr size_t NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS = 4;
78
//!  Suggested external port for mapping.
79
constexpr size_t NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS = 6;
80
//!  Requested port mapping lifetime in seconds.
81
constexpr size_t NATPMP_MAP_REQUEST_LIFETIME_OFS = 8;
82
83
// MAP response offsets (RFC6886 3.3), relative to start of packet.
84
//!  Internal port for mapping (will match internal port of request).
85
constexpr size_t NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS = 8;
86
//!  External port for mapping.
87
constexpr size_t NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS = 10;
88
//!  Created port mapping lifetime in seconds.
89
constexpr size_t NATPMP_MAP_RESPONSE_LIFETIME_OFS = 12;
90
91
// Relevant NETPMP result codes (RFC6886 3.5).
92
//! Result code representing success status.
93
constexpr uint8_t NATPMP_RESULT_SUCCESS = 0;
94
//! Result code representing unsupported version.
95
constexpr uint8_t NATPMP_RESULT_UNSUPP_VERSION = 1;
96
//! Result code representing not authorized (router doesn't support port mapping).
97
constexpr uint8_t NATPMP_RESULT_NOT_AUTHORIZED = 2;
98
//! Result code representing lack of resources.
99
constexpr uint8_t NATPMP_RESULT_NO_RESOURCES = 4;
100
101
//! Mapping of NATPMP result code to string (RFC6886 3.5). Result codes <=2 match PCP.
102
const std::map<uint16_t, std::string> NATPMP_RESULT_STR{
103
    {0,  "SUCCESS"},
104
    {1,  "UNSUPP_VERSION"},
105
    {2,  "NOT_AUTHORIZED"},
106
    {3,  "NETWORK_FAILURE"},
107
    {4,  "NO_RESOURCES"},
108
    {5,  "UNSUPP_OPCODE"},
109
};
110
111
// PCP (v2) protocol constants.
112
//! Maximum packet size in bytes (RFC6887 section 7).
113
constexpr size_t PCP_MAX_SIZE = 1100;
114
//! PCP uses a fixed server port number (RFC6887 section 19.1). Shared with NAT-PMP.
115
constexpr uint16_t PCP_SERVER_PORT = NATPMP_SERVER_PORT;
116
//! Version byte. 0 is NAT-PMP (RFC6886), 1 is forbidden, 2 for PCP (RFC6887).
117
constexpr uint8_t PCP_VERSION = 2;
118
//! PCP Request Header. See RFC6887 section 7.1. Shared with NAT-PMP.
119
constexpr uint8_t PCP_REQUEST = NATPMP_REQUEST; // R = 0
120
//! PCP Response Header. See RFC6887 section 7.2. Shared with NAT-PMP.
121
constexpr uint8_t PCP_RESPONSE = NATPMP_RESPONSE; // R = 1
122
//! Map opcode. See RFC6887 section 19.2
123
constexpr uint8_t PCP_OP_MAP = 0x01;
124
//! TCP protocol number (IANA).
125
constexpr uint16_t PCP_PROTOCOL_TCP = 6;
126
//! Request and response header size in bytes (RFC6887 section 7.1).
127
constexpr size_t PCP_HDR_SIZE = 24;
128
//! Map request and response size in bytes (RFC6887 section 11.1).
129
constexpr size_t PCP_MAP_SIZE = 36;
130
131
// Header offsets shared between request and responses (RFC6887 7.1, 7.2), relative to start of packet.
132
//!  Version field (1 byte).
133
constexpr size_t PCP_HDR_VERSION_OFS = NATPMP_HDR_VERSION_OFS;
134
//!  Opcode field (1 byte).
135
constexpr size_t PCP_HDR_OP_OFS = NATPMP_HDR_OP_OFS;
136
//!  Requested lifetime (request), granted lifetime (response) (4 bytes).
137
constexpr size_t PCP_HDR_LIFETIME_OFS = 4;
138
139
// Request header offsets (RFC6887 7.1), relative to start of packet.
140
//!  PCP client's IP address (16 bytes).
141
constexpr size_t PCP_REQUEST_HDR_IP_OFS = 8;
142
143
// Response header offsets (RFC6887 7.2), relative to start of packet.
144
//!  Result code (1 byte).
145
constexpr size_t PCP_RESPONSE_HDR_RESULT_OFS = 3;
146
147
// MAP request/response offsets (RFC6887 11.1), relative to start of opcode-specific data.
148
//!  Mapping nonce (12 bytes).
149
constexpr size_t PCP_MAP_NONCE_OFS = 0;
150
//!  Protocol (1 byte).
151
constexpr size_t PCP_MAP_PROTOCOL_OFS = 12;
152
//!  Internal port for mapping (2 bytes).
153
constexpr size_t PCP_MAP_INTERNAL_PORT_OFS = 16;
154
//!  Suggested external port (request), assigned external port (response) (2 bytes).
155
constexpr size_t PCP_MAP_EXTERNAL_PORT_OFS = 18;
156
//!  Suggested external IP (request), assigned external IP (response) (16 bytes).
157
constexpr size_t PCP_MAP_EXTERNAL_IP_OFS = 20;
158
159
//! Result code representing success (RFC6887 7.4), shared with NAT-PMP.
160
constexpr uint8_t PCP_RESULT_SUCCESS = NATPMP_RESULT_SUCCESS;
161
//! Result code representing not authorized (RFC6887 7.4), shared with NAT-PMP.
162
constexpr uint8_t PCP_RESULT_NOT_AUTHORIZED = NATPMP_RESULT_NOT_AUTHORIZED;
163
//! Result code representing lack of resources (RFC6887 7.4).
164
constexpr uint8_t PCP_RESULT_NO_RESOURCES = 8;
165
166
//! Mapping of PCP result code to string (RFC6887 7.4). Result codes <=2 match NAT-PMP.
167
const std::map<uint8_t, std::string> PCP_RESULT_STR{
168
    {0,  "SUCCESS"},
169
    {1,  "UNSUPP_VERSION"},
170
    {2,  "NOT_AUTHORIZED"},
171
    {3,  "MALFORMED_REQUEST"},
172
    {4,  "UNSUPP_OPCODE"},
173
    {5,  "UNSUPP_OPTION"},
174
    {6,  "MALFORMED_OPTION"},
175
    {7,  "NETWORK_FAILURE"},
176
    {8,  "NO_RESOURCES"},
177
    {9,  "UNSUPP_PROTOCOL"},
178
    {10, "USER_EX_QUOTA"},
179
    {11, "CANNOT_PROVIDE_EXTERNAL"},
180
    {12, "ADDRESS_MISMATCH"},
181
    {13, "EXCESSIVE_REMOTE_PEER"},
182
};
183
184
//! Return human-readable string from NATPMP result code.
185
std::string NATPMPResultString(uint16_t result_code)
186
5
{
187
5
    auto result_i = NATPMP_RESULT_STR.find(result_code);
188
5
    return strprintf("%s (code %d)", result_i == NATPMP_RESULT_STR.end() ? "(unknown)" : result_i->second,  result_code);
  Branch (188:38): [True: 1, False: 4]
189
5
}
190
191
//! Return human-readable string from PCP result code.
192
std::string PCPResultString(uint8_t result_code)
193
9
{
194
9
    auto result_i = PCP_RESULT_STR.find(result_code);
195
9
    return strprintf("%s (code %d)", result_i == PCP_RESULT_STR.end() ? "(unknown)" : result_i->second,  result_code);
  Branch (195:38): [True: 1, False: 8]
196
9
}
197
198
//! Wrap address in IPv6 according to RFC6887. wrapped_addr needs to be able to store 16 bytes.
199
[[nodiscard]] bool PCPWrapAddress(std::span<uint8_t> wrapped_addr, const CNetAddr &addr)
200
171
{
201
171
    Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
202
171
    if (addr.IsIPv4()) {
  Branch (202:9): [True: 137, False: 34]
203
137
        struct in_addr addr4;
204
137
        if (!addr.GetInAddr(&addr4)) return false;
  Branch (204:13): [True: 0, False: 137]
205
        // Section 5: "When the address field holds an IPv4 address, an IPv4-mapped IPv6 address [RFC4291] is used (::ffff:0:0/96)."
206
137
        std::memcpy(wrapped_addr.data(), IPV4_IN_IPV6_PREFIX.data(), IPV4_IN_IPV6_PREFIX.size());
207
137
        std::memcpy(wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), &addr4, ADDR_IPV4_SIZE);
208
137
        return true;
209
137
    } else if (addr.IsIPv6()) {
  Branch (209:16): [True: 32, False: 2]
210
32
        struct in6_addr addr6;
211
32
        if (!addr.GetIn6Addr(&addr6)) return false;
  Branch (211:13): [True: 0, False: 32]
212
32
        std::memcpy(wrapped_addr.data(), &addr6, ADDR_IPV6_SIZE);
213
32
        return true;
214
32
    } else {
215
2
        return false;
216
2
    }
217
171
}
218
219
//! Unwrap PCP-encoded address according to RFC6887.
220
CNetAddr PCPUnwrapAddress(std::span<const uint8_t> wrapped_addr)
221
40
{
222
40
    Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
223
40
    if (util::HasPrefix(wrapped_addr, IPV4_IN_IPV6_PREFIX)) {
  Branch (223:9): [True: 3, False: 37]
224
3
        struct in_addr addr4;
225
3
        std::memcpy(&addr4, wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), ADDR_IPV4_SIZE);
226
3
        return CNetAddr(addr4);
227
37
    } else {
228
37
        struct in6_addr addr6;
229
37
        std::memcpy(&addr6, wrapped_addr.data(), ADDR_IPV6_SIZE);
230
37
        return CNetAddr(addr6);
231
37
    }
232
40
}
233
234
//! PCP or NAT-PMP send-receive loop.
235
std::optional<std::vector<uint8_t>> PCPSendRecv(Sock &sock, const std::string &protocol, std::span<const uint8_t> request, int num_tries,
236
        std::chrono::milliseconds timeout_per_try,
237
        std::function<bool(std::span<const uint8_t>)> check_packet,
238
        CThreadInterrupt& interrupt)
239
192
{
240
192
    using namespace std::chrono;
241
    // UDP is a potentially lossy protocol, so we try to send again a few times.
242
192
    uint8_t response[PCP_MAX_SIZE];
243
192
    bool got_response = false;
244
192
    int recvsz = 0;
245
669
    for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) {
  Branch (245:24): [True: 571, False: 98]
  Branch (245:41): [True: 555, False: 16]
246
555
        if (ntry > 0) {
  Branch (246:13): [True: 363, False: 192]
247
363
            LogDebug(BCLog::NET, "%s: Retrying (%d)\n", protocol, ntry);
248
363
        }
249
        // Dispatch packet to gateway.
250
555
        if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) {
  Branch (250:13): [True: 62, False: 493]
251
62
            LogDebug(BCLog::NET, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
252
62
            return std::nullopt; // Network-level error, probably no use retrying.
253
62
        }
254
255
        // Wait for response(s) until we get a valid response, a network error, or time out.
256
493
        auto cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now());
257
493
        auto deadline = cur_time + timeout_per_try;
258
826
        while ((cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now())) < deadline) {
  Branch (258:16): [True: 493, False: 333]
259
493
            if (interrupt) return std::nullopt;
  Branch (259:17): [True: 0, False: 493]
260
493
            Sock::Event occurred = 0;
261
493
            if (!sock.Wait(deadline - cur_time, Sock::RecvEvent, &occurred)) {
  Branch (261:17): [True: 8, False: 485]
262
8
                LogWarning("%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
263
8
                return std::nullopt; // Network-level error, probably no use retrying.
264
8
            }
265
485
            if (!occurred) {
  Branch (265:17): [True: 46, False: 439]
266
46
                LogDebug(BCLog::NET, "%s: Timeout\n", protocol);
267
46
                break; // Retry.
268
46
            }
269
270
            // Receive response.
271
439
            recvsz = sock.Recv(response, sizeof(response), MSG_DONTWAIT);
272
439
            if (recvsz < 0) {
  Branch (272:17): [True: 8, False: 431]
273
8
                LogDebug(BCLog::NET, "%s: Could not receive response: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
274
8
                return std::nullopt; // Network-level error, probably no use retrying.
275
8
            }
276
431
            LogDebug(BCLog::NET, "%s: Received response of %d bytes: %s\n", protocol, recvsz, HexStr(std::span(response, recvsz)));
277
278
431
            if (check_packet(std::span<uint8_t>(response, recvsz))) {
  Branch (278:17): [True: 98, False: 333]
279
98
                got_response = true; // Got expected response, break from receive loop as well as from retry loop.
280
98
                break;
281
98
            }
282
431
        }
283
493
    }
284
114
    if (!got_response) {
  Branch (284:9): [True: 16, False: 98]
285
16
        LogDebug(BCLog::NET, "%s: Giving up after %d tries\n", protocol, num_tries);
286
16
        return std::nullopt;
287
16
    }
288
98
    return std::vector<uint8_t>(response, response + recvsz);
289
114
}
290
291
}
292
293
std::variant<MappingResult, MappingError> NATPMPRequestPortMap(const CNetAddr &gateway, uint16_t port, uint32_t lifetime, CThreadInterrupt& interrupt, int num_tries, std::chrono::milliseconds timeout_per_try)
294
129
{
295
129
    struct sockaddr_storage dest_addr;
296
129
    socklen_t dest_addrlen = sizeof(struct sockaddr_storage);
297
298
129
    LogDebug(BCLog::NET, "natpmp: Requesting port mapping port %d from gateway %s\n", port, gateway.ToStringAddr());
299
300
    // Validate gateway, make sure it's IPv4. NAT-PMP does not support IPv6.
301
129
    if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR;
  Branch (301:9): [True: 19, False: 110]
302
110
    if (dest_addr.ss_family != AF_INET) return MappingError::NETWORK_ERROR;
  Branch (302:9): [True: 25, False: 85]
303
304
    // Create IPv4 UDP socket
305
85
    auto sock{CreateSock(AF_INET, SOCK_DGRAM, IPPROTO_UDP)};
306
85
    if (!sock) {
  Branch (306:9): [True: 0, False: 85]
307
0
        LogWarning("natpmp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError()));
308
0
        return MappingError::NETWORK_ERROR;
309
0
    }
310
311
    // Associate UDP socket to gateway.
312
85
    if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) {
  Branch (312:9): [True: 3, False: 82]
313
3
        LogWarning("natpmp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError()));
314
3
        return MappingError::NETWORK_ERROR;
315
3
    }
316
317
    // Use getsockname to get the address toward the default gateway (the internal address).
318
82
    struct sockaddr_in internal;
319
82
    socklen_t internal_addrlen = sizeof(struct sockaddr_in);
320
82
    if (sock->GetSockName((struct sockaddr*)&internal, &internal_addrlen) != 0) {
  Branch (320:9): [True: 15, False: 67]
321
15
        LogWarning("natpmp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError()));
322
15
        return MappingError::NETWORK_ERROR;
323
15
    }
324
325
    // Request external IP address (RFC6886 section 3.2).
326
67
    std::vector<uint8_t> request(NATPMP_GETEXTERNAL_REQUEST_SIZE);
327
67
    request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION;
328
67
    request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_GETEXTERNAL;
329
330
67
    auto recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try,
331
151
        [&](const std::span<const uint8_t> response) -> bool {
332
151
            if (response.size() < NATPMP_GETEXTERNAL_RESPONSE_SIZE) {
  Branch (332:17): [True: 66, False: 85]
333
66
                LogWarning("natpmp: Response too small\n");
334
66
                return false; // Wasn't response to what we expected, try receiving next packet.
335
66
            }
336
85
            if (response[NATPMP_HDR_VERSION_OFS] != NATPMP_VERSION || response[NATPMP_HDR_OP_OFS] != (NATPMP_RESPONSE | NATPMP_OP_GETEXTERNAL)) {
  Branch (336:17): [True: 24, False: 61]
  Branch (336:71): [True: 18, False: 43]
337
42
                LogWarning("natpmp: Response to wrong command\n");
338
42
                return false; // Wasn't response to what we expected, try receiving next packet.
339
42
            }
340
43
            return true;
341
85
        },
342
67
        interrupt);
343
344
67
    struct in_addr external_addr;
345
67
    if (recv_res) {
  Branch (345:9): [True: 43, False: 24]
346
43
        const std::span<const uint8_t> response = *recv_res;
347
348
43
        Assume(response.size() >= NATPMP_GETEXTERNAL_RESPONSE_SIZE);
349
43
        uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS);
350
43
        if (result_code != NATPMP_RESULT_SUCCESS) {
  Branch (350:13): [True: 2, False: 41]
351
2
            LogWarning("natpmp: Getting external address failed with result %s\n", NATPMPResultString(result_code));
352
2
            return MappingError::PROTOCOL_ERROR;
353
2
        }
354
355
41
        std::memcpy(&external_addr, response.data() + NATPMP_GETEXTERNAL_RESPONSE_IP_OFS, ADDR_IPV4_SIZE);
356
41
    } else {
357
24
        return MappingError::NETWORK_ERROR;
358
24
    }
359
360
    // Create TCP mapping request (RFC6886 section 3.3).
361
41
    request = std::vector<uint8_t>(NATPMP_MAP_REQUEST_SIZE);
362
41
    request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION;
363
41
    request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_MAP_TCP;
364
41
    WriteBE16(request.data() + NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS, port);
365
41
    WriteBE16(request.data() + NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS, port);
366
41
    WriteBE32(request.data() + NATPMP_MAP_REQUEST_LIFETIME_OFS, lifetime);
367
368
41
    recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try,
369
111
        [&](const std::span<const uint8_t> response) -> bool {
370
111
            if (response.size() < NATPMP_MAP_RESPONSE_SIZE) {
  Branch (370:17): [True: 39, False: 72]
371
39
                LogWarning("natpmp: Response too small\n");
372
39
                return false; // Wasn't response to what we expected, try receiving next packet.
373
39
            }
374
72
            if (response[0] != NATPMP_VERSION || response[1] != (NATPMP_RESPONSE | NATPMP_OP_MAP_TCP)) {
  Branch (374:17): [True: 19, False: 53]
  Branch (374:50): [True: 19, False: 34]
375
38
                LogWarning("natpmp: Response to wrong command\n");
376
38
                return false; // Wasn't response to what we expected, try receiving next packet.
377
38
            }
378
34
            uint16_t internal_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS);
379
34
            if (internal_port != port) {
  Branch (379:17): [True: 20, False: 14]
380
20
                LogWarning("natpmp: Response port doesn't match request\n");
381
20
                return false; // Wasn't response to what we expected, try receiving next packet.
382
20
            }
383
14
            return true;
384
34
        },
385
41
        interrupt);
386
387
41
    if (recv_res) {
  Branch (387:9): [True: 14, False: 27]
388
14
        const std::span<uint8_t> response = *recv_res;
389
390
14
        Assume(response.size() >= NATPMP_MAP_RESPONSE_SIZE);
391
14
        uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS);
392
14
        if (result_code != NATPMP_RESULT_SUCCESS) {
  Branch (392:13): [True: 5, False: 9]
393
5
            if (result_code == NATPMP_RESULT_NOT_AUTHORIZED) {
  Branch (393:17): [True: 3, False: 2]
394
3
                static std::atomic<bool> warned{false};
395
3
                if (!warned.exchange(true)) {
  Branch (395:21): [True: 1, False: 2]
396
1
                    LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
397
2
                } else {
398
2
                    LogDebug(BCLog::NET, "natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
399
2
                }
400
3
            } else {
401
2
                LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
402
2
            }
403
5
            if (result_code == NATPMP_RESULT_NO_RESOURCES) {
  Branch (403:17): [True: 1, False: 4]
404
1
                return MappingError::NO_RESOURCES;
405
1
            }
406
4
            return MappingError::PROTOCOL_ERROR;
407
5
        }
408
409
9
        uint32_t lifetime_ret = ReadBE32(response.data() + NATPMP_MAP_RESPONSE_LIFETIME_OFS);
410
9
        uint16_t external_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS);
411
9
        return MappingResult(NATPMP_VERSION, CService(internal.sin_addr, port), CService(external_addr, external_port), lifetime_ret);
412
27
    } else {
413
27
        return MappingError::NETWORK_ERROR;
414
27
    }
415
41
}
416
417
std::variant<MappingResult, MappingError> PCPRequestPortMap(const PCPMappingNonce &nonce, const CNetAddr &gateway, const CNetAddr &bind, uint16_t port, uint32_t lifetime, CThreadInterrupt& interrupt, int num_tries, std::chrono::milliseconds timeout_per_try)
418
170
{
419
170
    struct sockaddr_storage dest_addr, bind_addr;
420
170
    socklen_t dest_addrlen = sizeof(struct sockaddr_storage), bind_addrlen = sizeof(struct sockaddr_storage);
421
422
170
    LogDebug(BCLog::NET, "pcp: Requesting port mapping for addr %s port %d from gateway %s\n", bind.ToStringAddr(), port, gateway.ToStringAddr());
423
424
    // Validate addresses, make sure they're the same network family.
425
170
    if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR;
  Branch (425:9): [True: 20, False: 150]
426
150
    if (!CService(bind, 0).GetSockAddr((struct sockaddr*)&bind_addr, &bind_addrlen)) return MappingError::NETWORK_ERROR;
  Branch (426:9): [True: 5, False: 145]
427
145
    if (dest_addr.ss_family != bind_addr.ss_family) return MappingError::NETWORK_ERROR;
  Branch (427:9): [True: 9, False: 136]
428
429
    // Create UDP socket (IPv4 or IPv6 based on provided gateway).
430
136
    auto sock{CreateSock(dest_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)};
431
136
    if (!sock) {
  Branch (431:9): [True: 0, False: 136]
432
0
        LogWarning("pcp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError()));
433
0
        return MappingError::NETWORK_ERROR;
434
0
    }
435
436
    // Make sure that we send from requested destination address, anything else will be
437
    // rejected by a security-conscious router.
438
136
    if (sock->Bind((struct sockaddr*)&bind_addr, bind_addrlen) != 0) {
  Branch (438:9): [True: 2, False: 134]
439
2
        LogWarning("pcp: Could not bind to address: %s\n", NetworkErrorString(WSAGetLastError()));
440
2
        return MappingError::NETWORK_ERROR;
441
2
    }
442
443
    // Associate UDP socket to gateway.
444
134
    if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) {
  Branch (444:9): [True: 2, False: 132]
445
2
        LogWarning("pcp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError()));
446
2
        return MappingError::NETWORK_ERROR;
447
2
    }
448
449
    // Use getsockname to get the address toward the default gateway (the internal address),
450
    // in case we don't know what address to map
451
    // (this is only needed if bind is INADDR_ANY, but it doesn't hurt as an extra check).
452
132
    struct sockaddr_storage internal_addr;
453
132
    socklen_t internal_addrlen = sizeof(struct sockaddr_storage);
454
132
    if (sock->GetSockName((struct sockaddr*)&internal_addr, &internal_addrlen) != 0) {
  Branch (454:9): [True: 42, False: 90]
455
42
        LogWarning("pcp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError()));
456
42
        return MappingError::NETWORK_ERROR;
457
42
    }
458
90
    CService internal;
459
90
    if (!internal.SetSockAddr((struct sockaddr*)&internal_addr, internal_addrlen)) return MappingError::NETWORK_ERROR;
  Branch (459:9): [True: 4, False: 86]
460
86
    LogDebug(BCLog::NET, "pcp: Internal address after connect: %s\n", internal.ToStringAddr());
461
462
    // Build request packet. Make sure the packet is zeroed so that reserved fields are zero
463
    // as required by the spec (and not potentially leak data).
464
    // Make sure there's space for the request header and MAP specific request data.
465
86
    std::vector<uint8_t> request(PCP_HDR_SIZE + PCP_MAP_SIZE);
466
    // Fill in request header, See RFC6887 Figure 2.
467
86
    size_t ofs = 0;
468
86
    request[ofs + PCP_HDR_VERSION_OFS] = PCP_VERSION;
469
86
    request[ofs + PCP_HDR_OP_OFS] = PCP_REQUEST | PCP_OP_MAP;
470
86
    WriteBE32(request.data() + ofs + PCP_HDR_LIFETIME_OFS, lifetime);
471
86
    if (!PCPWrapAddress(std::span(request).subspan(ofs + PCP_REQUEST_HDR_IP_OFS, ADDR_IPV6_SIZE), internal)) return MappingError::NETWORK_ERROR;
  Branch (471:9): [True: 1, False: 85]
472
473
85
    ofs += PCP_HDR_SIZE;
474
475
    // Fill in MAP request packet, See RFC6887 Figure 9.
476
    // Randomize mapping nonce (this is repeated in the response, to be able to
477
    // correlate requests and responses, and used to authenticate changes to the mapping).
478
85
    std::memcpy(request.data() + ofs + PCP_MAP_NONCE_OFS, nonce.data(), PCP_MAP_NONCE_SIZE);
479
85
    request[ofs + PCP_MAP_PROTOCOL_OFS] = PCP_PROTOCOL_TCP;
480
85
    WriteBE16(request.data() + ofs + PCP_MAP_INTERNAL_PORT_OFS, port);
481
85
    WriteBE16(request.data() + ofs + PCP_MAP_EXTERNAL_PORT_OFS, port);
482
85
    if (!PCPWrapAddress(std::span(request).subspan(ofs + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE), bind)) return MappingError::NETWORK_ERROR;
  Branch (482:9): [True: 1, False: 84]
483
484
84
    ofs += PCP_MAP_SIZE;
485
84
    Assume(ofs == request.size());
486
487
    // Receive loop.
488
84
    bool is_natpmp = false;
489
84
    auto recv_res = PCPSendRecv(*sock, "pcp", request, num_tries, timeout_per_try,
490
169
        [&](const std::span<const uint8_t> response) -> bool {
491
            // Unsupported version according to RFC6887 appendix A and RFC6886 section 3.5, can fall back to NAT-PMP.
492
169
            if (response.size() == NATPMP_RESPONSE_HDR_SIZE && response[PCP_HDR_VERSION_OFS] == NATPMP_VERSION && response[PCP_RESPONSE_HDR_RESULT_OFS] == NATPMP_RESULT_UNSUPP_VERSION) {
  Branch (492:17): [True: 22, False: 147]
  Branch (492:64): [True: 11, False: 11]
  Branch (492:115): [True: 1, False: 10]
493
1
                is_natpmp = true;
494
1
                return true; // Let it through to caller.
495
1
            }
496
168
            if (response.size() < (PCP_HDR_SIZE + PCP_MAP_SIZE)) {
  Branch (496:17): [True: 60, False: 108]
497
60
                LogWarning("pcp: Response too small\n");
498
60
                return false; // Wasn't response to what we expected, try receiving next packet.
499
60
            }
500
108
            if (response[PCP_HDR_VERSION_OFS] != PCP_VERSION || response[PCP_HDR_OP_OFS] != (PCP_RESPONSE | PCP_OP_MAP)) {
  Branch (500:17): [True: 20, False: 88]
  Branch (500:65): [True: 10, False: 78]
501
30
                LogWarning("pcp: Response to wrong command\n");
502
30
                return false; // Wasn't response to what we expected, try receiving next packet.
503
30
            }
504
            // Handle MAP opcode response. See RFC6887 Figure 10.
505
            // Check that returned mapping nonce matches our request.
506
78
            if (!std::ranges::equal(response.subspan(PCP_HDR_SIZE + PCP_MAP_NONCE_OFS, PCP_MAP_NONCE_SIZE), nonce)) {
  Branch (506:17): [True: 10, False: 68]
507
10
                LogWarning("pcp: Mapping nonce mismatch\n");
508
10
                return false; // Wasn't response to what we expected, try receiving next packet.
509
10
            }
510
68
            uint8_t protocol = response[PCP_HDR_SIZE + 12];
511
68
            uint16_t internal_port = ReadBE16(response.data() + PCP_HDR_SIZE + 16);
512
68
            if (protocol != PCP_PROTOCOL_TCP || internal_port != port) {
  Branch (512:17): [True: 17, False: 51]
  Branch (512:49): [True: 11, False: 40]
513
28
                LogWarning("pcp: Response protocol or port doesn't match request\n");
514
28
                return false; // Wasn't response to what we expected, try receiving next packet.
515
28
            }
516
40
            return true;
517
68
        },
518
84
        interrupt);
519
520
84
    if (!recv_res) {
  Branch (520:9): [True: 43, False: 41]
521
43
        return MappingError::NETWORK_ERROR;
522
43
    }
523
41
    if (is_natpmp) {
  Branch (523:9): [True: 1, False: 40]
524
1
        return MappingError::UNSUPP_VERSION;
525
1
    }
526
527
40
    const std::span<const uint8_t> response = *recv_res;
528
    // If we get here, we got a valid MAP response to our request.
529
    // Check to see if we got the result we expected.
530
40
    Assume(response.size() >= (PCP_HDR_SIZE + PCP_MAP_SIZE));
531
40
    uint8_t result_code = response[PCP_RESPONSE_HDR_RESULT_OFS];
532
40
    uint32_t lifetime_ret = ReadBE32(response.data() + PCP_HDR_LIFETIME_OFS);
533
40
    uint16_t external_port = ReadBE16(response.data() + PCP_HDR_SIZE + PCP_MAP_EXTERNAL_PORT_OFS);
534
40
    CNetAddr external_addr{PCPUnwrapAddress(response.subspan(PCP_HDR_SIZE + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE))};
535
40
    if (result_code != PCP_RESULT_SUCCESS) {
  Branch (535:9): [True: 10, False: 30]
536
10
        if (result_code == PCP_RESULT_NOT_AUTHORIZED) {
  Branch (536:13): [True: 2, False: 8]
537
2
            static std::atomic<bool> warned{false};
538
2
            if (!warned.exchange(true)) {
  Branch (538:17): [True: 1, False: 1]
539
1
                LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
540
1
            } else {
541
1
                LogDebug(BCLog::NET, "pcp: Mapping failed with result %s\n", PCPResultString(result_code));
542
1
            }
543
8
        } else {
544
8
            LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
545
8
        }
546
10
        if (result_code == PCP_RESULT_NO_RESOURCES) {
  Branch (546:13): [True: 2, False: 8]
547
2
            return MappingError::NO_RESOURCES;
548
2
        }
549
8
        return MappingError::PROTOCOL_ERROR;
550
10
    }
551
552
30
    return MappingResult(PCP_VERSION, CService(internal, port), CService(external_addr, external_port), lifetime_ret);
553
40
}
554
555
std::string MappingResult::ToString() const
556
39
{
557
39
    Assume(version == NATPMP_VERSION || version == PCP_VERSION);
558
39
    return strprintf("%s:%s -> %s (for %ds)",
559
39
            version == NATPMP_VERSION ? "natpmp" : "pcp",
  Branch (559:13): [True: 9, False: 30]
560
39
            external.ToStringAddrPort(),
561
39
            internal.ToStringAddrPort(),
562
39
            lifetime
563
39
        );
564
39
}