MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / NATPMPRequestPortMap

Function NATPMPRequestPortMap

src/common/pcp.cpp:282–404  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

280}
281
282std::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()));
297 return MappingError::NETWORK_ERROR;
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()));
303 return MappingError::NETWORK_ERROR;
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()));
311 return MappingError::NETWORK_ERROR;
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) {

Callers 3

ProcessPCPFunction · 0.85
BOOST_AUTO_TEST_CASEFunction · 0.85
pcp.cppFile · 0.85

Calls 15

CServiceClass · 0.85
NetworkErrorStringFunction · 0.85
PCPSendRecvFunction · 0.85
ReadBE16Function · 0.85
NATPMPResultStringFunction · 0.85
WriteBE16Function · 0.85
WriteBE32Function · 0.85
ReadBE32Function · 0.85
MappingResultClass · 0.85
ToStringAddrMethod · 0.80
GetSockAddrMethod · 0.80
ConnectMethod · 0.45

Tested by 1

BOOST_AUTO_TEST_CASEFunction · 0.68