Merge bitcoin/bitcoin#34549: net: reduce log level for PCP/NAT-PMP NOT_AUTHORIZED failures

afea2af139 net: reduce log level for PCP/NAT-PMP NOT_AUTHORIZED failures (ANAVHEOBA)

Pull request description:

  Cherry-picks (and tweaks) a commit from #34117 which the ANAVHEOBA
  did not follow up with when changes were requested.

  The tweak here is to log once at `LogWarning`, so that users have a chance
  to spot misconfiguration.

  ----

  Users running on home networks with routers that don't support PCP (Port
  Control Protocol) or NAT-PMP port mapping receive frequent warning-level
  log messages every few minutes:

    "pcp: Mapping failed with result NOT_AUTHORIZED (code 2)"

  This is expected behavior for many consumer routers that have PCP
  disabled by default, not an actionable error.

  Add explicit constants for the NOT_AUTHORIZED result code (value 2)
  for both NAT-PMP and PCP protocols. Log the first NOT_AUTHORIZED
  failure at warning level for visibility, then downgrade subsequent
  occurrences to LogDebug to avoid log noise. Other failure types
  continue to warn unconditionally.

  Fixes #34114

ACKs for top commit:
  achow101:
    ACK afea2af139
  sedited:
    ACK afea2af139

Tree-SHA512: 43dad9f3cca0ef9b82446045a3ccd90418cd5595c9965e938d9d539bbba863dde6b4a358adbee56f8d97d6efbf947eb5ddbbaf426faefcf3b1e36e4c8edb0d94
This commit is contained in:
Ava Chow
2026-02-19 16:57:54 -08:00

View File

@@ -4,6 +4,7 @@
#include <common/pcp.h>
#include <atomic>
#include <common/netif.h>
#include <crypto/common.h>
#include <logging.h>
@@ -81,6 +82,8 @@ constexpr size_t NATPMP_MAP_RESPONSE_LIFETIME_OFS = 12;
constexpr uint8_t NATPMP_RESULT_SUCCESS = 0;
//! Result code representing unsupported version.
constexpr uint8_t NATPMP_RESULT_UNSUPP_VERSION = 1;
//! Result code representing not authorized (router doesn't support port mapping).
constexpr uint8_t NATPMP_RESULT_NOT_AUTHORIZED = 2;
//! Result code representing lack of resources.
constexpr uint8_t NATPMP_RESULT_NO_RESOURCES = 4;
@@ -144,6 +147,8 @@ constexpr size_t PCP_MAP_EXTERNAL_IP_OFS = 20;
//! Result code representing success (RFC6887 7.4), shared with NAT-PMP.
constexpr uint8_t PCP_RESULT_SUCCESS = NATPMP_RESULT_SUCCESS;
//! Result code representing not authorized (RFC6887 7.4), shared with NAT-PMP.
constexpr uint8_t PCP_RESULT_NOT_AUTHORIZED = NATPMP_RESULT_NOT_AUTHORIZED;
//! Result code representing lack of resources (RFC6887 7.4).
constexpr uint8_t PCP_RESULT_NO_RESOURCES = 8;
@@ -374,7 +379,16 @@ std::variant<MappingResult, MappingError> NATPMPRequestPortMap(const CNetAddr &g
Assume(response.size() >= NATPMP_MAP_RESPONSE_SIZE);
uint16_t result_code = ReadBE16(response.data() + NATPMP_RESPONSE_HDR_RESULT_OFS);
if (result_code != NATPMP_RESULT_SUCCESS) {
LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
if (result_code == NATPMP_RESULT_NOT_AUTHORIZED) {
static std::atomic<bool> warned{false};
if (!warned.exchange(true)) {
LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
} else {
LogDebug(BCLog::NET, "natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
}
} else {
LogWarning("natpmp: Port mapping failed with result %s\n", NATPMPResultString(result_code));
}
if (result_code == NATPMP_RESULT_NO_RESOURCES) {
return MappingError::NO_RESOURCES;
}
@@ -508,7 +522,16 @@ std::variant<MappingResult, MappingError> PCPRequestPortMap(const PCPMappingNonc
uint16_t external_port = ReadBE16(response.data() + PCP_HDR_SIZE + PCP_MAP_EXTERNAL_PORT_OFS);
CNetAddr external_addr{PCPUnwrapAddress(response.subspan(PCP_HDR_SIZE + PCP_MAP_EXTERNAL_IP_OFS, ADDR_IPV6_SIZE))};
if (result_code != PCP_RESULT_SUCCESS) {
LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
if (result_code == PCP_RESULT_NOT_AUTHORIZED) {
static std::atomic<bool> warned{false};
if (!warned.exchange(true)) {
LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
} else {
LogDebug(BCLog::NET, "pcp: Mapping failed with result %s\n", PCPResultString(result_code));
}
} else {
LogWarning("pcp: Mapping failed with result %s\n", PCPResultString(result_code));
}
if (result_code == PCP_RESULT_NO_RESOURCES) {
return MappingError::NO_RESOURCES;
}