/Users/eugenesiegel/btc/bitcoin/src/net_permissions.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-2021 The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #include <common/messages.h> | 
| 6 |  | #include <common/system.h> | 
| 7 |  | #include <net_permissions.h> | 
| 8 |  | #include <netbase.h> | 
| 9 |  | #include <util/translation.h> | 
| 10 |  |  | 
| 11 |  | using common::ResolveErrMsg; | 
| 12 |  |  | 
| 13 |  | const 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 |  | }; | 
| 22 |  |  | 
| 23 |  | namespace { | 
| 24 |  |  | 
| 25 |  | // Parse the following format: "perm1,perm2@xxxxxx" | 
| 26 |  | static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error) | 
| 27 | 0 | { | 
| 28 | 0 |     NetPermissionFlags flags = NetPermissionFlags::None; | 
| 29 | 0 |     ConnectionDirection connection_direction = ConnectionDirection::None; | 
| 30 | 0 |     const auto atSeparator = str.find('@'); | 
| 31 |  |  | 
| 32 |  |     // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions | 
| 33 | 0 |     if (atSeparator == std::string::npos) { | 
| 34 | 0 |         NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit); | 
| 35 | 0 |         readen = 0; | 
| 36 | 0 |     } | 
| 37 |  |     // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags | 
| 38 | 0 |     else { | 
| 39 | 0 |         readen = 0; | 
| 40 |  |         // permissions == perm1,perm2 | 
| 41 | 0 |         const auto permissions = str.substr(0, atSeparator); | 
| 42 | 0 |         while (readen < permissions.length()) { | 
| 43 | 0 |             const auto commaSeparator = permissions.find(',', readen); | 
| 44 | 0 |             const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen; | 
| 45 |  |             // permission == perm1 | 
| 46 | 0 |             const auto permission = permissions.substr(readen, len); | 
| 47 | 0 |             readen += len; // We read "perm1" | 
| 48 | 0 |             if (commaSeparator != std::string::npos) readen++; // We read "," | 
| 49 |  | 
 | 
| 50 | 0 |             if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter); | 
| 51 | 0 |             else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan); | 
| 52 | 0 |             else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay); | 
| 53 | 0 |             else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool); | 
| 54 | 0 |             else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download); | 
| 55 | 0 |             else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All); | 
| 56 | 0 |             else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay); | 
| 57 | 0 |             else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr); | 
| 58 | 0 |             else if (permission == "in") connection_direction |= ConnectionDirection::In; | 
| 59 | 0 |             else if (permission == "out") { | 
| 60 | 0 |                 if (output_connection_direction == nullptr) { | 
| 61 |  |                     // Only NetWhitebindPermissions() should pass a nullptr. | 
| 62 | 0 |                     error = _("whitebind may only be used for incoming connections (\"out\" was passed)"); | 
| 63 | 0 |                     return false; | 
| 64 | 0 |                 } | 
| 65 | 0 |                 connection_direction |= ConnectionDirection::Out; | 
| 66 | 0 |             } | 
| 67 | 0 |             else if (permission.length() == 0); // Allow empty entries | 
| 68 | 0 |             else { | 
| 69 | 0 |                 error = strprintf(_("Invalid P2P permission: '%s'"), permission);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 70 | 0 |                 return false; | 
| 71 | 0 |             } | 
| 72 | 0 |         } | 
| 73 | 0 |         readen++; | 
| 74 | 0 |     } | 
| 75 |  |  | 
| 76 |  |     // By default, whitelist only applies to incoming connections | 
| 77 | 0 |     if (connection_direction == ConnectionDirection::None) { | 
| 78 | 0 |         connection_direction = ConnectionDirection::In; | 
| 79 | 0 |     } else if (flags == NetPermissionFlags::None) { | 
| 80 | 0 |         error = strprintf(_("Only direction was set, no permissions: '%s'"), str);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 81 | 0 |         return false; | 
| 82 | 0 |     } | 
| 83 |  |  | 
| 84 | 0 |     output = flags; | 
| 85 | 0 |     if (output_connection_direction) *output_connection_direction = connection_direction; | 
| 86 | 0 |     error = Untranslated(""); | 
| 87 | 0 |     return true; | 
| 88 | 0 | } | 
| 89 |  |  | 
| 90 |  | } | 
| 91 |  |  | 
| 92 |  | std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags) | 
| 93 | 0 | { | 
| 94 | 0 |     std::vector<std::string> strings; | 
| 95 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter"); | 
| 96 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban"); | 
| 97 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay"); | 
| 98 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay"); | 
| 99 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool"); | 
| 100 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download"); | 
| 101 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr"); | 
| 102 | 0 |     return strings; | 
| 103 | 0 | } | 
| 104 |  |  | 
| 105 |  | bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error) | 
| 106 | 0 | { | 
| 107 | 0 |     NetPermissionFlags flags; | 
| 108 | 0 |     size_t offset; | 
| 109 | 0 |     if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false; | 
| 110 |  |  | 
| 111 | 0 |     const std::string strBind = str.substr(offset); | 
| 112 | 0 |     const std::optional<CService> addrBind{Lookup(strBind, 0, false)}; | 
| 113 | 0 |     if (!addrBind.has_value()) { | 
| 114 | 0 |         error = ResolveErrMsg("whitebind", strBind); | 
| 115 | 0 |         return false; | 
| 116 | 0 |     } | 
| 117 | 0 |     if (addrBind.value().GetPort() == 0) { | 
| 118 | 0 |         error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 119 | 0 |         return false; | 
| 120 | 0 |     } | 
| 121 |  |  | 
| 122 | 0 |     output.m_flags = flags; | 
| 123 | 0 |     output.m_service = addrBind.value(); | 
| 124 | 0 |     error = Untranslated(""); | 
| 125 | 0 |     return true; | 
| 126 | 0 | } | 
| 127 |  |  | 
| 128 |  | bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error) | 
| 129 | 0 | { | 
| 130 | 0 |     NetPermissionFlags flags; | 
| 131 | 0 |     size_t offset; | 
| 132 |  |     // Only NetWhitebindPermissions should pass a nullptr for output_connection_direction. | 
| 133 | 0 |     if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false; | 
| 134 |  |  | 
| 135 | 0 |     const std::string net = str.substr(offset); | 
| 136 | 0 |     const CSubNet subnet{LookupSubNet(net)}; | 
| 137 | 0 |     if (!subnet.IsValid()) { | 
| 138 | 0 |         error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 139 | 0 |         return false; | 
| 140 | 0 |     } | 
| 141 |  |  | 
| 142 | 0 |     output.m_flags = flags; | 
| 143 | 0 |     output.m_subnet = subnet; | 
| 144 | 0 |     error = Untranslated(""); | 
| 145 | 0 |     return true; | 
| 146 | 0 | } |