Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <common/messages.h>6#include <common/system.h>7#include <net_permissions.h>8#include <netbase.h>9#include <util/translation.h>11using common::ResolveErrMsg;13const std::vector<std::string> NET_PERMISSIONS_DOC{14"bloomfilter (allow requesting BIP37 filtered blocks and transactions)",15"noban (do not ban for misbehavior; implies download)",16"forcerelay (relay transactions that are already in the mempool; implies relay)",17"relay (relay even in -blocksonly mode, and unlimited transaction announcements)",18"mempool (allow requesting BIP35 mempool contents)",19"download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",20"addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"21};23namespace {25// Parse the following format: "perm1,perm2@xxxxxx"26static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error)27{28NetPermissionFlags flags = NetPermissionFlags::None;29ConnectionDirection connection_direction = ConnectionDirection::None;30const auto atSeparator = str.find('@');32// if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions33if (atSeparator == std::string::npos) {34NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);35readen = 0;36}37// else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags38else {39readen = 0;40// permissions == perm1,perm241const auto permissions = str.substr(0, atSeparator);42while (readen < permissions.length()) {43const auto commaSeparator = permissions.find(',', readen);44const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;45// permission == perm146const auto permission = permissions.substr(readen, len);47readen += len; // We read "perm1"48if (commaSeparator != std::string::npos) readen++; // We read ","50if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);51else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);52else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);53else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);54else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);55else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);56else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);57else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);58else if (permission == "in") connection_direction |= ConnectionDirection::In;59else if (permission == "out") {60if (output_connection_direction == nullptr) {61// Only NetWhitebindPermissions() should pass a nullptr.62error = _("whitebind may only be used for incoming connections (\"out\" was passed)");63return false;64}65connection_direction |= ConnectionDirection::Out;66}67else if (permission.length() == 0); // Allow empty entries68else {69error = strprintf(_("Invalid P2P permission: '%s'"), permission);70return false;71}72}73readen++;74}76// By default, whitelist only applies to incoming connections77if (connection_direction == ConnectionDirection::None) {78connection_direction = ConnectionDirection::In;79} else if (flags == NetPermissionFlags::None) {80error = strprintf(_("Only direction was set, no permissions: '%s'"), str);81return false;82}84output = flags;85if (output_connection_direction) *output_connection_direction = connection_direction;86error = Untranslated("");87return true;88}90}92std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)93{94std::vector<std::string> strings;95if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");96if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");97if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");98if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");99if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");100if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");101if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");102return strings;103}105bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)106{107NetPermissionFlags flags;108size_t offset;109if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false;111const std::string strBind = str.substr(offset);112const std::optional<CService> addrBind{Lookup(strBind, 0, false)};113if (!addrBind.has_value()) {114error = ResolveErrMsg("whitebind", strBind);115return false;116}117if (addrBind.value().GetPort() == 0) {118error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);119return false;120}122output.m_flags = flags;123output.m_service = addrBind.value();124error = Untranslated("");125return true;126}128bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error)129{130NetPermissionFlags flags;131size_t offset;132// Only NetWhitebindPermissions should pass a nullptr for output_connection_direction.133if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false;135const std::string net = str.substr(offset);136const CSubNet subnet{LookupSubNet(net)};137if (!subnet.IsValid()) {138error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);139return false;140}142output.m_flags = flags;143output.m_subnet = subnet;144error = Untranslated("");145return true;146}