net: reduce log level for PCP/NAT-PMP NOT_AUTHORIZED failures

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

Co-authored-by: willcl-ark <will@256k1.dev>
This commit is contained in:
ANAVHEOBA 2025-12-19 11:35:00 -05:00 committed by will
parent 64294c8909
commit afea2af139
No known key found for this signature in database
GPG Key ID: CE6EC49945C17EA6

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;
}