LCOV - code coverage report
Current view: top level - src - net_permissions.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 97 97
Test Date: 2024-09-01 05:20:30 Functions: 100.0 % 4 4
Branches: 65.7 % 210 138

             Branch data     Line data    Source code
       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   [ +  -  #  # ]:           1 : const std::vector<std::string> NET_PERMISSIONS_DOC{
      14         [ +  - ]:           1 :     "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
      15         [ +  - ]:           1 :     "noban (do not ban for misbehavior; implies download)",
      16         [ +  - ]:           1 :     "forcerelay (relay transactions that are already in the mempool; implies relay)",
      17         [ +  - ]:           1 :     "relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
      18         [ +  - ]:           1 :     "mempool (allow requesting BIP35 mempool contents)",
      19         [ +  - ]:           1 :     "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
      20         [ +  - ]:           1 :     "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                 :        1096 : static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error)
      27                 :             : {
      28                 :        1096 :     NetPermissionFlags flags = NetPermissionFlags::None;
      29                 :        1096 :     ConnectionDirection connection_direction = ConnectionDirection::None;
      30                 :        1096 :     const auto atSeparator = str.find('@');
      31                 :             : 
      32                 :             :     // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
      33         [ +  + ]:        1096 :     if (atSeparator == std::string::npos) {
      34                 :         604 :         NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
      35                 :         604 :         readen = 0;
      36                 :         604 :     }
      37                 :             :     // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
      38                 :             :     else {
      39                 :         492 :         readen = 0;
      40                 :             :         // permissions == perm1,perm2
      41                 :         492 :         const auto permissions = str.substr(0, atSeparator);
      42         [ +  + ]:       21973 :         while (readen < permissions.length()) {
      43                 :       21701 :             const auto commaSeparator = permissions.find(',', readen);
      44         [ +  + ]:       21701 :             const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
      45                 :             :             // permission == perm1
      46         [ +  - ]:       21701 :             const auto permission = permissions.substr(readen, len);
      47                 :       21701 :             readen += len; // We read "perm1"
      48         [ +  + ]:       21701 :             if (commaSeparator != std::string::npos) readen++; // We read ","
      49                 :             : 
      50   [ +  -  +  +  :       21701 :             if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
          +  -  +  +  +  
                      - ]
      51   [ +  -  +  +  :       21117 :             else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
                   +  - ]
      52   [ +  -  +  +  :       20324 :             else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
                   +  - ]
      53   [ +  -  +  +  :       20204 :             else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
                   +  - ]
      54   [ +  -  +  +  :       19792 :             else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
                   +  - ]
      55   [ +  -  +  +  :       19333 :             else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
                   +  - ]
      56   [ +  -  +  +  :       18545 :             else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
                   +  - ]
      57   [ +  -  +  +  :       17928 :             else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
                   +  - ]
      58   [ +  -  +  +  :       17434 :             else if (permission == "in") connection_direction |= ConnectionDirection::In;
                   +  - ]
      59   [ +  -  +  + ]:       15613 :             else if (permission == "out") {
      60         [ +  + ]:         770 :                 if (output_connection_direction == nullptr) {
      61                 :             :                     // Only NetWhitebindPermissions() should pass a nullptr.
      62         [ +  - ]:          81 :                     error = _("whitebind may only be used for incoming connections (\"out\" was passed)");
      63                 :          81 :                     return false;
      64                 :             :                 }
      65         [ +  - ]:         689 :                 connection_direction |= ConnectionDirection::Out;
      66                 :         689 :             }
      67         [ +  + ]:       14843 :             else if (permission.length() == 0); // Allow empty entries
      68                 :             :             else {
      69   [ -  +  +  - ]:         139 :                 error = strprintf(_("Invalid P2P permission: '%s'"), permission);
      70                 :         139 :                 return false;
      71                 :             :             }
      72         [ +  + ]:       21701 :         }
      73                 :         272 :         readen++;
      74         [ +  + ]:         492 :     }
      75                 :             : 
      76                 :             :     // By default, whitelist only applies to incoming connections
      77         [ +  + ]:         876 :     if (connection_direction == ConnectionDirection::None) {
      78                 :         806 :         connection_direction = ConnectionDirection::In;
      79         [ +  + ]:         876 :     } else if (flags == NetPermissionFlags::None) {
      80         [ +  - ]:          17 :         error = strprintf(_("Only direction was set, no permissions: '%s'"), str);
      81                 :          17 :         return false;
      82                 :             :     }
      83                 :             : 
      84                 :         859 :     output = flags;
      85         [ +  + ]:         859 :     if (output_connection_direction) *output_connection_direction = connection_direction;
      86   [ +  -  +  - ]:         859 :     error = Untranslated("");
      87                 :         859 :     return true;
      88                 :        1096 : }
      89                 :             : 
      90                 :             : }
      91                 :             : 
      92                 :         252 : std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
      93                 :             : {
      94                 :         252 :     std::vector<std::string> strings;
      95   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");
                   +  - ]
      96   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");
                   +  - ]
      97   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");
                   +  - ]
      98   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");
                   +  - ]
      99   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");
                   +  - ]
     100   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");
                   +  - ]
     101   [ +  -  +  +  :         252 :     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");
                   +  - ]
     102                 :         252 :     return strings;
     103         [ +  - ]:         252 : }
     104                 :             : 
     105                 :         548 : bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
     106                 :             : {
     107                 :         548 :     NetPermissionFlags flags;
     108                 :         548 :     size_t offset;
     109         [ +  + ]:         548 :     if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false;
     110                 :             : 
     111                 :         410 :     const std::string strBind = str.substr(offset);
     112   [ +  -  +  - ]:         410 :     const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
     113         [ +  + ]:         410 :     if (!addrBind.has_value()) {
     114   [ +  -  +  - ]:         333 :         error = ResolveErrMsg("whitebind", strBind);
     115                 :         333 :         return false;
     116                 :             :     }
     117   [ +  -  +  -  :          77 :     if (addrBind.value().GetPort() == 0) {
                   +  + ]
     118   [ +  -  +  - ]:          57 :         error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
     119                 :          57 :         return false;
     120                 :             :     }
     121                 :             : 
     122                 :          20 :     output.m_flags = flags;
     123   [ +  -  +  - ]:          20 :     output.m_service = addrBind.value();
     124   [ +  -  +  - ]:          20 :     error = Untranslated("");
     125                 :          20 :     return true;
     126                 :         548 : }
     127                 :             : 
     128                 :         548 : bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error)
     129                 :             : {
     130                 :         548 :     NetPermissionFlags flags;
     131                 :         548 :     size_t offset;
     132                 :             :     // Only NetWhitebindPermissions should pass a nullptr for output_connection_direction.
     133         [ +  + ]:         548 :     if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false;
     134                 :             : 
     135                 :         449 :     const std::string net = str.substr(offset);
     136         [ +  - ]:         449 :     const CSubNet subnet{LookupSubNet(net)};
     137   [ +  -  +  + ]:         449 :     if (!subnet.IsValid()) {
     138   [ +  -  +  - ]:         343 :         error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
     139                 :         343 :         return false;
     140                 :             :     }
     141                 :             : 
     142                 :         106 :     output.m_flags = flags;
     143         [ +  - ]:         106 :     output.m_subnet = subnet;
     144   [ +  -  +  - ]:         106 :     error = Untranslated("");
     145                 :         106 :     return true;
     146                 :         548 : }
        

Generated by: LCOV version 2.0-1