Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

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