Bitcoin Core  31.0.0
P2P Digital Currency
pcp.cpp
Go to the documentation of this file.
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.
28 constexpr uint16_t NATPMP_SERVER_PORT = 5351;
30 constexpr uint8_t NATPMP_VERSION = 0;
32 constexpr uint8_t NATPMP_REQUEST = 0x00;
34 constexpr uint8_t NATPMP_RESPONSE = 0x80;
36 constexpr uint8_t NATPMP_OP_GETEXTERNAL = 0x00;
38 constexpr uint8_t NATPMP_OP_MAP_TCP = 0x02;
40 constexpr size_t NATPMP_REQUEST_HDR_SIZE = 2;
42 constexpr size_t NATPMP_RESPONSE_HDR_SIZE = 8;
44 constexpr size_t NATPMP_GETEXTERNAL_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 0;
46 constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_SIZE = NATPMP_RESPONSE_HDR_SIZE + 4;
48 constexpr size_t NATPMP_MAP_REQUEST_SIZE = NATPMP_REQUEST_HDR_SIZE + 10;
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.
54 constexpr size_t NATPMP_HDR_VERSION_OFS = 0;
56 constexpr size_t NATPMP_HDR_OP_OFS = 1;
58 constexpr size_t NATPMP_RESPONSE_HDR_RESULT_OFS = 2;
59 
60 // GETEXTERNAL response offsets (RFC6886 3.2), relative to start of packet.
62 constexpr size_t NATPMP_GETEXTERNAL_RESPONSE_IP_OFS = 8;
63 
64 // MAP request offsets (RFC6886 3.3), relative to start of packet.
66 constexpr size_t NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS = 4;
68 constexpr size_t NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS = 6;
70 constexpr size_t NATPMP_MAP_REQUEST_LIFETIME_OFS = 8;
71 
72 // MAP response offsets (RFC6886 3.3), relative to start of packet.
74 constexpr size_t NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS = 8;
76 constexpr size_t NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS = 10;
78 constexpr size_t NATPMP_MAP_RESPONSE_LIFETIME_OFS = 12;
79 
80 // Relevant NETPMP result codes (RFC6886 3.5).
82 constexpr uint8_t NATPMP_RESULT_SUCCESS = 0;
84 constexpr uint8_t NATPMP_RESULT_UNSUPP_VERSION = 1;
86 constexpr uint8_t NATPMP_RESULT_NOT_AUTHORIZED = 2;
88 constexpr uint8_t NATPMP_RESULT_NO_RESOURCES = 4;
89 
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.
102 constexpr size_t PCP_MAX_SIZE = 1100;
104 constexpr uint16_t PCP_SERVER_PORT = NATPMP_SERVER_PORT;
106 constexpr uint8_t PCP_VERSION = 2;
108 constexpr uint8_t PCP_REQUEST = NATPMP_REQUEST; // R = 0
110 constexpr uint8_t PCP_RESPONSE = NATPMP_RESPONSE; // R = 1
112 constexpr uint8_t PCP_OP_MAP = 0x01;
114 constexpr uint16_t PCP_PROTOCOL_TCP = 6;
116 constexpr size_t PCP_HDR_SIZE = 24;
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.
122 constexpr size_t PCP_HDR_VERSION_OFS = NATPMP_HDR_VERSION_OFS;
124 constexpr size_t PCP_HDR_OP_OFS = NATPMP_HDR_OP_OFS;
126 constexpr size_t PCP_HDR_LIFETIME_OFS = 4;
127 
128 // Request header offsets (RFC6887 7.1), relative to start of packet.
130 constexpr size_t PCP_REQUEST_HDR_IP_OFS = 8;
131 
132 // Response header offsets (RFC6887 7.2), relative to start of packet.
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.
138 constexpr size_t PCP_MAP_NONCE_OFS = 0;
140 constexpr size_t PCP_MAP_PROTOCOL_OFS = 12;
142 constexpr size_t PCP_MAP_INTERNAL_PORT_OFS = 16;
144 constexpr size_t PCP_MAP_EXTERNAL_PORT_OFS = 18;
146 constexpr size_t PCP_MAP_EXTERNAL_IP_OFS = 20;
147 
149 constexpr uint8_t PCP_RESULT_SUCCESS = NATPMP_RESULT_SUCCESS;
151 constexpr uint8_t PCP_RESULT_NOT_AUTHORIZED = NATPMP_RESULT_NOT_AUTHORIZED;
153 constexpr uint8_t PCP_RESULT_NO_RESOURCES = 8;
154 
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 
174 std::string NATPMPResultString(uint16_t result_code)
175 {
176  auto result_i = NATPMP_RESULT_STR.find(result_code);
177  return strprintf("%s (code %d)", result_i == NATPMP_RESULT_STR.end() ? "(unknown)" : result_i->second, result_code);
178 }
179 
181 std::string PCPResultString(uint8_t result_code)
182 {
183  auto result_i = PCP_RESULT_STR.find(result_code);
184  return strprintf("%s (code %d)", result_i == PCP_RESULT_STR.end() ? "(unknown)" : result_i->second, result_code);
185 }
186 
188 [[nodiscard]] bool PCPWrapAddress(std::span<uint8_t> wrapped_addr, const CNetAddr &addr)
189 {
190  Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
191  if (addr.IsIPv4()) {
192  struct in_addr addr4;
193  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  std::memcpy(wrapped_addr.data(), IPV4_IN_IPV6_PREFIX.data(), IPV4_IN_IPV6_PREFIX.size());
196  std::memcpy(wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), &addr4, ADDR_IPV4_SIZE);
197  return true;
198  } else if (addr.IsIPv6()) {
199  struct in6_addr addr6;
200  if (!addr.GetIn6Addr(&addr6)) return false;
201  std::memcpy(wrapped_addr.data(), &addr6, ADDR_IPV6_SIZE);
202  return true;
203  } else {
204  return false;
205  }
206 }
207 
209 CNetAddr PCPUnwrapAddress(std::span<const uint8_t> wrapped_addr)
210 {
211  Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
212  if (util::HasPrefix(wrapped_addr, IPV4_IN_IPV6_PREFIX)) {
213  struct in_addr addr4;
214  std::memcpy(&addr4, wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), ADDR_IPV4_SIZE);
215  return CNetAddr(addr4);
216  } else {
217  struct in6_addr addr6;
218  std::memcpy(&addr6, wrapped_addr.data(), ADDR_IPV6_SIZE);
219  return CNetAddr(addr6);
220  }
221 }
222 
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 {
229  using namespace std::chrono;
230  // UDP is a potentially lossy protocol, so we try to send again a few times.
231  uint8_t response[PCP_MAX_SIZE];
232  bool got_response = false;
233  int recvsz = 0;
234  for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) {
235  if (ntry > 0) {
236  LogDebug(BCLog::NET, "%s: Retrying (%d)\n", protocol, ntry);
237  }
238  // Dispatch packet to gateway.
239  if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) {
240  LogDebug(BCLog::NET, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
241  return std::nullopt; // Network-level error, probably no use retrying.
242  }
243 
244  // Wait for response(s) until we get a valid response, a network error, or time out.
245  auto cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now());
246  auto deadline = cur_time + timeout_per_try;
247  while ((cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now())) < deadline) {
248  if (interrupt) return std::nullopt;
249  Sock::Event occurred = 0;
250  if (!sock.Wait(deadline - cur_time, Sock::RECV, &occurred)) {
251  LogWarning("%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
252  return std::nullopt; // Network-level error, probably no use retrying.
253  }
254  if (!occurred) {
255  LogDebug(BCLog::NET, "%s: Timeout\n", protocol);
256  break; // Retry.
257  }
258 
259  // Receive response.
260  recvsz = sock.Recv(response, sizeof(response), MSG_DONTWAIT);
261  if (recvsz < 0) {
262  LogDebug(BCLog::NET, "%s: Could not receive response: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
263  return std::nullopt; // Network-level error, probably no use retrying.
264  }
265  LogDebug(BCLog::NET, "%s: Received response of %d bytes: %s\n", protocol, recvsz, HexStr(std::span(response, recvsz)));
266 
267  if (check_packet(std::span<uint8_t>(response, recvsz))) {
268  got_response = true; // Got expected response, break from receive loop as well as from retry loop.
269  break;
270  }
271  }
272  }
273  if (!got_response) {
274  LogDebug(BCLog::NET, "%s: Giving up after %d tries\n", protocol, num_tries);
275  return std::nullopt;
276  }
277  return std::vector<uint8_t>(response, response + recvsz);
278 }
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 {
284  struct sockaddr_storage dest_addr;
285  socklen_t dest_addrlen = sizeof(struct sockaddr_storage);
286 
287  LogDebug(BCLog::NET, "natpmp: Requesting port mapping port %d from gateway %s\n", port, gateway.ToStringAddr());
288 
289  // Validate gateway, make sure it's IPv4. NAT-PMP does not support IPv6.
290  if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR;
291  if (dest_addr.ss_family != AF_INET) return MappingError::NETWORK_ERROR;
292 
293  // Create IPv4 UDP socket
294  auto sock{CreateSock(AF_INET, SOCK_DGRAM, IPPROTO_UDP)};
295  if (!sock) {
296  LogWarning("natpmp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError()));
298  }
299 
300  // Associate UDP socket to gateway.
301  if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) {
302  LogWarning("natpmp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError()));
304  }
305 
306  // Use getsockname to get the address toward the default gateway (the internal address).
307  struct sockaddr_in internal;
308  socklen_t internal_addrlen = sizeof(struct sockaddr_in);
309  if (sock->GetSockName((struct sockaddr*)&internal, &internal_addrlen) != 0) {
310  LogWarning("natpmp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError()));
312  }
313 
314  // Request external IP address (RFC6886 section 3.2).
315  std::vector<uint8_t> request(NATPMP_GETEXTERNAL_REQUEST_SIZE);
316  request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION;
317  request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_GETEXTERNAL;
318 
319  auto recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try,
320  [&](const std::span<const uint8_t> response) -> bool {
321  if (response.size() < NATPMP_GETEXTERNAL_RESPONSE_SIZE) {
322  LogWarning("natpmp: Response too small\n");
323  return false; // Wasn't response to what we expected, try receiving next packet.
324  }
325  if (response[NATPMP_HDR_VERSION_OFS] != NATPMP_VERSION || response[NATPMP_HDR_OP_OFS] != (NATPMP_RESPONSE | NATPMP_OP_GETEXTERNAL)) {
326  LogWarning("natpmp: Response to wrong command\n");
327  return false; // Wasn't response to what we expected, try receiving next packet.
328  }
329  return true;
330  },
331  interrupt);
332 
333  struct in_addr external_addr;
334  if (recv_res) {
335  const std::span<const uint8_t> response = *recv_res;
336 
337  Assume(response.size() >= NATPMP_GETEXTERNAL_RESPONSE_SIZE);
338  uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS);
339  if (result_code != NATPMP_RESULT_SUCCESS) {
340  LogWarning("natpmp: Getting external address failed with result %s\n", NATPMPResultString(result_code));
342  }
343 
344  std::memcpy(&external_addr, response.data() + NATPMP_GETEXTERNAL_RESPONSE_IP_OFS, ADDR_IPV4_SIZE);
345  } else {
347  }
348 
349  // Create TCP mapping request (RFC6886 section 3.3).
350  request = std::vector<uint8_t>(NATPMP_MAP_REQUEST_SIZE);
351  request[NATPMP_HDR_VERSION_OFS] = NATPMP_VERSION;
352  request[NATPMP_HDR_OP_OFS] = NATPMP_REQUEST | NATPMP_OP_MAP_TCP;
353  WriteBE16(request.data() + NATPMP_MAP_REQUEST_INTERNAL_PORT_OFS, port);
354  WriteBE16(request.data() + NATPMP_MAP_REQUEST_EXTERNAL_PORT_OFS, port);
355  WriteBE32(request.data() + NATPMP_MAP_REQUEST_LIFETIME_OFS, lifetime);
356 
357  recv_res = PCPSendRecv(*sock, "natpmp", request, num_tries, timeout_per_try,
358  [&](const std::span<const uint8_t> response) -> bool {
359  if (response.size() < NATPMP_MAP_RESPONSE_SIZE) {
360  LogWarning("natpmp: Response too small\n");
361  return false; // Wasn't response to what we expected, try receiving next packet.
362  }
363  if (response[0] != NATPMP_VERSION || response[1] != (NATPMP_RESPONSE | NATPMP_OP_MAP_TCP)) {
364  LogWarning("natpmp: Response to wrong command\n");
365  return false; // Wasn't response to what we expected, try receiving next packet.
366  }
367  uint16_t internal_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_INTERNAL_PORT_OFS);
368  if (internal_port != port) {
369  LogWarning("natpmp: Response port doesn't match request\n");
370  return false; // Wasn't response to what we expected, try receiving next packet.
371  }
372  return true;
373  },
374  interrupt);
375 
376  if (recv_res) {
377  const std::span<uint8_t> response = *recv_res;
378 
379  Assume(response.size() >= NATPMP_MAP_RESPONSE_SIZE);
380  uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS);
381  if (result_code != NATPMP_RESULT_SUCCESS) {
382  if (result_code == NATPMP_RESULT_NOT_AUTHORIZED) {
383  static std::atomic<bool> warned{false};
384  if (!warned.exchange(true)) {
385  LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
386  } else {
387  LogDebug(BCLog::NET, "natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
388  }
389  } else {
390  LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
391  }
392  if (result_code == NATPMP_RESULT_NO_RESOURCES) {
394  }
396  }
397 
398  uint32_t lifetime_ret = ReadBE32(response.data() + NATPMP_MAP_RESPONSE_LIFETIME_OFS);
399  uint16_t external_port = ReadBE16(response.data() + NATPMP_MAP_RESPONSE_EXTERNAL_PORT_OFS);
400  return MappingResult(NATPMP_VERSION, CService(internal.sin_addr, port), CService(external_addr, external_port), lifetime_ret);
401  } else {
403  }
404 }
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 {
408  struct sockaddr_storage dest_addr, bind_addr;
409  socklen_t dest_addrlen = sizeof(struct sockaddr_storage), bind_addrlen = sizeof(struct sockaddr_storage);
410 
411  LogDebug(BCLog::NET, "pcp: Requesting port mapping for addr %s port %d from gateway %s\n", bind.ToStringAddr(), port, gateway.ToStringAddr());
412 
413  // Validate addresses, make sure they're the same network family.
414  if (!CService(gateway, PCP_SERVER_PORT).GetSockAddr((struct sockaddr*)&dest_addr, &dest_addrlen)) return MappingError::NETWORK_ERROR;
415  if (!CService(bind, 0).GetSockAddr((struct sockaddr*)&bind_addr, &bind_addrlen)) return MappingError::NETWORK_ERROR;
416  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  auto sock{CreateSock(dest_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)};
420  if (!sock) {
421  LogWarning("pcp: Could not create UDP socket: %s\n", NetworkErrorString(WSAGetLastError()));
423  }
424 
425  // Make sure that we send from requested destination address, anything else will be
426  // rejected by a security-conscious router.
427  if (sock->Bind((struct sockaddr*)&bind_addr, bind_addrlen) != 0) {
428  LogWarning("pcp: Could not bind to address: %s\n", NetworkErrorString(WSAGetLastError()));
430  }
431 
432  // Associate UDP socket to gateway.
433  if (sock->Connect((struct sockaddr*)&dest_addr, dest_addrlen) != 0) {
434  LogWarning("pcp: Could not connect to gateway: %s\n", NetworkErrorString(WSAGetLastError()));
436  }
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  struct sockaddr_storage internal_addr;
442  socklen_t internal_addrlen = sizeof(struct sockaddr_storage);
443  if (sock->GetSockName((struct sockaddr*)&internal_addr, &internal_addrlen) != 0) {
444  LogWarning("pcp: Could not get sock name: %s\n", NetworkErrorString(WSAGetLastError()));
446  }
447  CService internal;
448  if (!internal.SetSockAddr((struct sockaddr*)&internal_addr, internal_addrlen)) return MappingError::NETWORK_ERROR;
449  LogDebug(BCLog::NET, "pcp: Internal address after connect: %s\n", internal.ToStringAddr());
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  std::vector<uint8_t> request(PCP_HDR_SIZE + PCP_MAP_SIZE);
455  // Fill in request header, See RFC6887 Figure 2.
456  size_t ofs = 0;
457  request[ofs + PCP_HDR_VERSION_OFS] = PCP_VERSION;
458  request[ofs + PCP_HDR_OP_OFS] = PCP_REQUEST | PCP_OP_MAP;
459  WriteBE32(request.data() + ofs + PCP_HDR_LIFETIME_OFS, lifetime);
460  if (!PCPWrapAddress(std::span(request).subspan(ofs + PCP_REQUEST_HDR_IP_OFS, ADDR_IPV6_SIZE), internal)) return MappingError::NETWORK_ERROR;
461 
462  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  std::memcpy(request.data() + ofs + PCP_MAP_NONCE_OFS, nonce.data(), PCP_MAP_NONCE_SIZE);
468  request[ofs + PCP_MAP_PROTOCOL_OFS] = PCP_PROTOCOL_TCP;
469  WriteBE16(request.data() + ofs + PCP_MAP_INTERNAL_PORT_OFS, port);
470  WriteBE16(request.data() + ofs + PCP_MAP_EXTERNAL_PORT_OFS, port);
471  if (!PCPWrapAddress(std::span(request).subspan(ofs + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE), bind)) return MappingError::NETWORK_ERROR;
472 
473  ofs += PCP_MAP_SIZE;
474  Assume(ofs == request.size());
475 
476  // Receive loop.
477  bool is_natpmp = false;
478  auto recv_res = PCPSendRecv(*sock, "pcp", request, num_tries, timeout_per_try,
479  [&](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  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  is_natpmp = true;
483  return true; // Let it through to caller.
484  }
485  if (response.size() < (PCP_HDR_SIZE + PCP_MAP_SIZE)) {
486  LogWarning("pcp: Response too small\n");
487  return false; // Wasn't response to what we expected, try receiving next packet.
488  }
489  if (response[PCP_HDR_VERSION_OFS] != PCP_VERSION || response[PCP_HDR_OP_OFS] != (PCP_RESPONSE | PCP_OP_MAP)) {
490  LogWarning("pcp: Response to wrong command\n");
491  return false; // Wasn't response to what we expected, try receiving next packet.
492  }
493  // Handle MAP opcode response. See RFC6887 Figure 10.
494  // Check that returned mapping nonce matches our request.
495  if (!std::ranges::equal(response.subspan(PCP_HDR_SIZE + PCP_MAP_NONCE_OFS, PCP_MAP_NONCE_SIZE), nonce)) {
496  LogWarning("pcp: Mapping nonce mismatch\n");
497  return false; // Wasn't response to what we expected, try receiving next packet.
498  }
499  uint8_t protocol = response[PCP_HDR_SIZE + 12];
500  uint16_t internal_port = ReadBE16(response.data() + PCP_HDR_SIZE + 16);
501  if (protocol != PCP_PROTOCOL_TCP || internal_port != port) {
502  LogWarning("pcp: Response protocol or port doesn't match request\n");
503  return false; // Wasn't response to what we expected, try receiving next packet.
504  }
505  return true;
506  },
507  interrupt);
508 
509  if (!recv_res) {
511  }
512  if (is_natpmp) {
514  }
515 
516  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  Assume(response.size() >= (PCP_HDR_SIZE + PCP_MAP_SIZE));
520  uint8_t result_code = response[PCP_RESPONSE_HDR_RESULT_OFS];
521  uint32_t lifetime_ret = ReadBE32(response.data() + PCP_HDR_LIFETIME_OFS);
522  uint16_t external_port = ReadBE16(response.data() + PCP_HDR_SIZE + PCP_MAP_EXTERNAL_PORT_OFS);
523  CNetAddr external_addr{PCPUnwrapAddress(response.subspan(PCP_HDR_SIZE + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE))};
524  if (result_code != PCP_RESULT_SUCCESS) {
525  if (result_code == PCP_RESULT_NOT_AUTHORIZED) {
526  static std::atomic<bool> warned{false};
527  if (!warned.exchange(true)) {
528  LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
529  } else {
530  LogDebug(BCLog::NET, "pcp: Mapping failed with result %s\n", PCPResultString(result_code));
531  }
532  } else {
533  LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
534  }
535  if (result_code == PCP_RESULT_NO_RESOURCES) {
537  }
539  }
540 
541  return MappingResult(PCP_VERSION, CService(internal, port), CService(external_addr, external_port), lifetime_ret);
542 }
543 
544 std::string MappingResult::ToString() const
545 {
546  Assume(version == NATPMP_VERSION || version == PCP_VERSION);
547  return strprintf("%s:%s -> %s (for %ds)",
548  version == NATPMP_VERSION ? "natpmp" : "pcp",
549  external.ToStringAddrPort(),
550  internal.ToStringAddrPort(),
551  lifetime
552  );
553 }
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:57
void WriteBE16(B *ptr, uint16_t x)
Definition: common.h:88
std::array< uint8_t, PCP_MAP_NONCE_SIZE > PCPMappingNonce
PCP mapping nonce. Arbitrary data chosen by the client to identify a mapping.
Definition: pcp.h:20
uint32_t ReadBE32(const B *ptr)
Definition: common.h:72
unsigned int nonce
Definition: miner_tests.cpp:82
#define LogWarning(...)
Definition: log.h:96
virtual int Bind(const sockaddr *addr, socklen_t addr_len) const
bind(2) wrapper.
Definition: sock.cpp:62
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bool IsIPv6() const
Definition: netaddress.h:159
static constexpr size_t ADDR_IPV4_SIZE
Size of IPv4 address (in bytes).
Definition: netaddress.h:86
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)
Try to open a port using RFC 6887 Port Control Protocol (PCP).
Definition: pcp.cpp:406
memcpy(result.begin(), stream.data(), stream.size())
bool GetInAddr(struct in_addr *pipv4Addr) const
Try to get our IPv4 address.
Definition: netaddress.cpp:623
virtual ssize_t Recv(void *buf, size_t len, int flags) const
recv(2) wrapper.
Definition: sock.cpp:52
bool GetIn6Addr(struct in6_addr *pipv6Addr) const
Try to get our IPv6 (or CJDNS) address.
Definition: netaddress.cpp:642
#define WSAGetLastError()
Definition: compat.h:59
virtual bool Wait(std::chrono::milliseconds timeout, Event requested, Event *occurred=nullptr) const
Wait for readiness for input (recv) or output (send).
Definition: sock.cpp:141
Any kind of network-level error.
std::string ToStringAddr() const
Definition: netaddress.cpp:580
uint16_t ReadBE16(const B *ptr)
Definition: common.h:64
bool IsIPv4() const
Definition: netaddress.h:158
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:89
Any kind of protocol-level error, except unsupported version or no resources.
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
Definition: netaddress.cpp:862
virtual ssize_t Send(const void *data, size_t len, int flags) const
send(2) wrapper.
Definition: sock.cpp:47
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:529
bool HasPrefix(const T1 &obj, const std::array< uint8_t, PREFIX_LEN > &prefix)
Check whether a container begins with the given prefix.
Definition: string.h:258
uint8_t Event
Definition: sock.h:139
A helper class for interruptible sleeps.
#define Assume(val)
Assume is the identity function.
Definition: check.h:125
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition: sock.cpp:426
Network address.
Definition: netaddress.h:112
#define LogDebug(category,...)
Definition: log.h:115
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)
Try to open a port using RFC 6886 NAT-PMP.
Definition: pcp.cpp:282
void WriteBE32(B *ptr, uint32_t x)
Definition: common.h:95
static constexpr Event RECV
If passed to Wait(), then it will wait for readiness to read from the socket.
Definition: sock.h:144
#define MSG_DONTWAIT
Definition: compat.h:115
RAII helper class that manages a socket and closes it automatically when it goes out of scope...
Definition: sock.h:27
static const std::array< uint8_t, 12 > IPV4_IN_IPV6_PREFIX
Prefix of an IPv6 address when it contains an embedded IPv4 address.
Definition: netaddress.h:62
std::function< std::unique_ptr< Sock >int, int, int)> CreateSock
Socket factory.
Definition: netbase.cpp:577
std::string ToString() const
Format mapping as string for logging.
Definition: pcp.cpp:544
virtual int GetSockName(sockaddr *name, socklen_t *name_len) const
getsockname(2) wrapper.
Definition: sock.cpp:108
Unsupported protocol version.
No resources available (port probably already mapped).
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
virtual int Connect(const sockaddr *addr, socklen_t addr_len) const
connect(2) wrapper.
Definition: sock.cpp:57
Successful response to a port mapping.
Definition: pcp.h:31
constexpr size_t PCP_MAP_NONCE_SIZE
Mapping nonce size in bytes (see RFC6887 section 11.1).
Definition: pcp.h:17