diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-03-19 20:47:04 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-03-19 20:47:10 +0100 |
commit | 18cd0888ef6285f5f496c01bbcf6884565def06f (patch) | |
tree | 0bf53c62e72aa2a14deaa155ba5f7df2f771675e | |
parent | 7f3fd341178f08c9ddb5b959e02676ad6bca3370 (diff) | |
parent | 52dd40a9febec1f4e70d777821b6764830bdec61 (diff) |
Merge #21328: net, refactor: pass uint16 CService::port as uint16
52dd40a9febec1f4e70d777821b6764830bdec61 test: add missing netaddress include headers (Jon Atack)
6f09c0f6b57ac01a473c587a3e51e9d477866bb0 util: add missing braces and apply clang format to SplitHostPort() (Jon Atack)
2875a764f7d8b1503c7bdb2f262964f7a0cb5fc3 util: add ParseUInt16(), use it in SplitHostPort() (Jon Atack)
6423c8175fad3163c10ffdb49e0df48e4e4931f1 p2p, refactor: pass and use uint16_t CService::port as uint16_t (Jon Atack)
Pull request description:
As noticed during review today in https://github.com/bitcoin/bitcoin/pull/20685#discussion_r584873708 of the upcoming I2P network support, `CService::port` is `uint16_t` but is passed around the codebase and into the ctors as `int`, which causes uneeded conversions and casts. We can avoid these (including in the incoming I2P code without further changes to it) by using ports with the correct type. The remaining conversions are pushed out to the user input boundaries where they can be range-checked and raise with user feedback in the next patch.
ACKs for top commit:
practicalswift:
cr ACK 52dd40a9febec1f4e70d777821b6764830bdec61: patch looks correct
MarcoFalke:
cr ACK 52dd40a9febec1f4e70d777821b6764830bdec61
vasild:
ACK 52dd40a9febec1f4e70d777821b6764830bdec61
Tree-SHA512: 203c1cab3189a206c55ecada77b9548b810281cdc533252b8e3330ae0606b467731c75f730ce9deb07cbaab66facf97e1ffd2051084ff9077cba6750366b0432
-rw-r--r-- | src/bitcoin-cli.cpp | 4 | ||||
-rw-r--r-- | src/chainparams.h | 4 | ||||
-rw-r--r-- | src/httpserver.cpp | 6 | ||||
-rw-r--r-- | src/net.cpp | 6 | ||||
-rw-r--r-- | src/net.h | 2 | ||||
-rw-r--r-- | src/netbase.cpp | 16 | ||||
-rw-r--r-- | src/netbase.h | 20 | ||||
-rw-r--r-- | src/qt/optionsdialog.h | 2 | ||||
-rw-r--r-- | src/rpc/net.cpp | 2 | ||||
-rw-r--r-- | src/test/addrman_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/asmap_direct.cpp | 3 | ||||
-rw-r--r-- | src/test/fuzz/netbase_dns_lookup.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/socks5.cpp | 3 | ||||
-rw-r--r-- | src/test/fuzz/string.cpp | 3 | ||||
-rw-r--r-- | src/test/net_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/netbase_tests.cpp | 19 | ||||
-rw-r--r-- | src/util/strencodings.cpp | 32 | ||||
-rw-r--r-- | src/util/strencodings.h | 9 |
18 files changed, 82 insertions, 56 deletions
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index ecd08c62eb..49f609be2d 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -618,9 +618,9 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co // 1. -rpcport // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6) // 3. default port for chain - int port = BaseParams().RPCPort(); + uint16_t port{BaseParams().RPCPort()}; SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host); - port = gArgs.GetArg("-rpcport", port); + port = static_cast<uint16_t>(gArgs.GetArg("-rpcport", port)); // Obtain event base raii_event_base base = obtain_event_base(); diff --git a/src/chainparams.h b/src/chainparams.h index 4d24dcdb7c..013f075be6 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -84,7 +84,7 @@ public: const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } - int GetDefaultPort() const { return nDefaultPort; } + uint16_t GetDefaultPort() const { return nDefaultPort; } const CBlock& GenesisBlock() const { return genesis; } /** Default value for -checkmempool and -checkblockindex argument */ @@ -121,7 +121,7 @@ protected: Consensus::Params consensus; CMessageHeader::MessageStartChars pchMessageStart; - int nDefaultPort; + uint16_t nDefaultPort; uint64_t nPruneAfterHeight; uint64_t m_assumed_blockchain_size; uint64_t m_assumed_chain_state_size; diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 0a8e58ab67..e1c8ec4ab9 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -290,8 +290,8 @@ static bool ThreadHTTP(struct event_base* base) /** Bind HTTP server to specified addresses */ static bool HTTPBindAddresses(struct evhttp* http) { - int http_port = gArgs.GetArg("-rpcport", BaseParams().RPCPort()); - std::vector<std::pair<std::string, uint16_t> > endpoints; + uint16_t http_port{static_cast<uint16_t>(gArgs.GetArg("-rpcport", BaseParams().RPCPort()))}; + std::vector<std::pair<std::string, uint16_t>> endpoints; // Determine what addresses to bind to if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs @@ -305,7 +305,7 @@ static bool HTTPBindAddresses(struct evhttp* http) } } else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) { - int port = http_port; + uint16_t port{http_port}; std::string host; SplitHostPort(strRPCBind, port, host); endpoints.push_back(std::make_pair(host, port)); diff --git a/src/net.cpp b/src/net.cpp index 6a2469f950..3b1ebede98 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -113,7 +113,7 @@ void CConnman::AddAddrFetch(const std::string& strDest) uint16_t GetListenPort() { - return (uint16_t)(gArgs.GetArg("-port", Params().GetDefaultPort())); + return static_cast<uint16_t>(gArgs.GetArg("-port", Params().GetDefaultPort())); } // find 'best' local address for a particular peer @@ -394,7 +394,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); // Resolve - const int default_port = Params().GetDefaultPort(); + const uint16_t default_port{Params().GetDefaultPort()}; if (pszDest) { std::vector<CService> resolved; if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) { @@ -462,7 +462,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return nullptr; } std::string host; - int port = default_port; + uint16_t port{default_port}; SplitHostPort(std::string(pszDest), port, host); bool proxyConnectionFailed; connected = ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout, @@ -229,7 +229,7 @@ extern std::string strSubVersion; struct LocalServiceInfo { int nScore; - int nPort; + uint16_t nPort; }; extern RecursiveMutex cs_mapLocalHost; diff --git a/src/netbase.cpp b/src/netbase.cpp index ac2392ebed..49e455aa84 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -194,12 +194,12 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL return true; } -bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function) +bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function) { if (name.empty() || !ValidAsCString(name)) { return false; } - int port = portDefault; + uint16_t port{portDefault}; std::string hostname; SplitHostPort(name, port, hostname); @@ -213,7 +213,7 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefau return true; } -bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function) +bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function) { if (!ValidAsCString(name)) { return false; @@ -226,7 +226,7 @@ bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllo return true; } -CService LookupNumeric(const std::string& name, int portDefault, DNSLookupFn dns_lookup_function) +CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function) { if (!ValidAsCString(name)) { return {}; @@ -363,7 +363,7 @@ static std::string Socks5ErrorString(uint8_t err) } } -bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& sock) +bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& sock) { IntrRecvError recvr; LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest); @@ -665,7 +665,7 @@ bool IsProxy(const CNetAddr &addr) { return false; } -bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed) +bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed) { // first connect to proxy server if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) { @@ -677,11 +677,11 @@ bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int ProxyCredentials random_auth; static std::atomic_int counter(0); random_auth.username = random_auth.password = strprintf("%i", counter++); - if (!Socks5(strDest, (uint16_t)port, &random_auth, sock)) { + if (!Socks5(strDest, port, &random_auth, sock)) { return false; } } else { - if (!Socks5(strDest, (uint16_t)port, 0, sock)) { + if (!Socks5(strDest, port, 0, sock)) { return false; } } diff --git a/src/netbase.h b/src/netbase.h index e98a21ce1f..08172b9984 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -111,7 +111,7 @@ extern DNSLookupFn g_dns_lookup; * @returns Whether or not the specified host string successfully resolved to * any resulting network addresses. * - * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn) + * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn) * for additional parameter descriptions. */ bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup); @@ -119,7 +119,7 @@ bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned in /** * Resolve a host string to its first corresponding network address. * - * @see LookupHost(const std::string&, std::vector<CNetAddr>&, unsigned int, bool, DNSLookupFn) + * @see LookupHost(const std::string&, std::vector<CNetAddr>&, uint16_t, bool, DNSLookupFn) * for additional parameter descriptions. */ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup); @@ -129,7 +129,7 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL * * @param name The string representing a service. Could be a name or a * numerical IP address (IPv6 addresses should be in their - * disambiguated bracketed form), optionally followed by a port + * disambiguated bracketed form), optionally followed by a uint16_t port * number. (e.g. example.com:8333 or * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420) * @param[out] vAddr The resulting services to which the specified service string @@ -144,15 +144,15 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL * @returns Whether or not the service string successfully resolved to any * resulting services. */ -bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup); +bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup); /** * Resolve a service string to its first corresponding service. * - * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn) + * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn) * for additional parameter descriptions. */ -bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup); +bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup); /** * Resolve a service string with a numeric IP to its first corresponding @@ -160,10 +160,10 @@ bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllo * * @returns The resulting CService if the resolution was successful, [::]:0 otherwise. * - * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn) + * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn) * for additional parameter descriptions. */ -CService LookupNumeric(const std::string& name, int portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup); +CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup); /** * Parse and resolve a specified subnet string into the appropriate internal @@ -219,7 +219,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i * * @returns Whether or not the operation succeeded. */ -bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed); +bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed); /** Disable or enable blocking-mode for a socket */ bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking); @@ -245,6 +245,6 @@ void InterruptSocks5(bool interrupt); * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol * Version 5</a> */ -bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& socket); +bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& socket); #endif // BITCOIN_NETBASE_H diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 1cc96035c6..ba35ff3b67 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -67,7 +67,7 @@ private Q_SLOTS: void updateDefaultProxyNets(); Q_SIGNALS: - void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort); + void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, uint16_t nProxyPort); private: Ui::OptionsDialog *ui; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index cf4d46cf2c..d4c1ab4b53 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -914,7 +914,7 @@ static RPCHelpMan addpeeraddress() UniValue obj(UniValue::VOBJ); std::string addr_string = request.params[0].get_str(); - uint16_t port = request.params[1].get_int(); + uint16_t port{static_cast<uint16_t>(request.params[1].get_int())}; CNetAddr net_addr; if (!LookupHost(addr_string, net_addr, false)) { diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 37ff8a9afe..d438537606 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -100,7 +100,7 @@ static CNetAddr ResolveIP(const std::string& ip) return addr; } -static CService ResolveService(const std::string& ip, const int port = 0) +static CService ResolveService(const std::string& ip, uint16_t port = 0) { CService serv; BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port)); diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp index 8b7822dc16..8ca4de3919 100644 --- a/src/test/fuzz/asmap_direct.cpp +++ b/src/test/fuzz/asmap_direct.cpp @@ -2,8 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <test/fuzz/fuzz.h> +#include <netaddress.h> #include <util/asmap.h> +#include <test/fuzz/fuzz.h> #include <cstdint> #include <optional> diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp index 7be8b13743..cf2fa33744 100644 --- a/src/test/fuzz/netbase_dns_lookup.cpp +++ b/src/test/fuzz/netbase_dns_lookup.cpp @@ -18,7 +18,7 @@ FUZZ_TARGET(netbase_dns_lookup) const std::string name = fuzzed_data_provider.ConsumeRandomLengthString(512); const unsigned int max_results = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); const bool allow_lookup = fuzzed_data_provider.ConsumeBool(); - const int default_port = fuzzed_data_provider.ConsumeIntegral<int>(); + const uint16_t default_port = fuzzed_data_provider.ConsumeIntegral<uint16_t>(); auto fuzzed_dns_lookup_function = [&](const std::string&, bool) { std::vector<CNetAddr> resolved_addresses; diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index e5cc4cabe5..c3a6eed089 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <netaddress.h> #include <netbase.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> @@ -38,7 +39,7 @@ FUZZ_TARGET_INIT(socks5, initialize_socks5) // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within // a few seconds of fuzzing. (void)Socks5(fuzzed_data_provider.ConsumeRandomLengthString(512), - fuzzed_data_provider.ConsumeIntegral<int>(), + fuzzed_data_provider.ConsumeIntegral<uint16_t>(), fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr, fuzzed_sock); } diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 93b4948a2f..286375f7ae 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -5,6 +5,7 @@ #include <blockfilter.h> #include <clientversion.h> #include <logging.h> +#include <netaddress.h> #include <netbase.h> #include <outputtype.h> #include <rpc/client.h> @@ -82,7 +83,7 @@ FUZZ_TARGET(string) #ifndef WIN32 (void)ShellEscape(random_string_1); #endif // WIN32 - int port_out; + uint16_t port_out; std::string host_out; SplitHostPort(random_string_1, port_out, host_out); (void)TimingResistantEqual(random_string_1, random_string_2); diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 3172f119bd..c336705d50 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -8,6 +8,7 @@ #include <clientversion.h> #include <cstdint> #include <net.h> +#include <netaddress.h> #include <netbase.h> #include <serialize.h> #include <span.h> @@ -91,7 +92,7 @@ BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(cnode_listen_port) { // test default - uint16_t port = GetListenPort(); + uint16_t port{GetListenPort()}; BOOST_CHECK(port == Params().GetDefaultPort()); // test set port uint16_t altPort = 12345; diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 66ad7bb5ea..33b56624a8 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <net_permissions.h> +#include <netaddress.h> #include <netbase.h> #include <protocol.h> #include <serialize.h> @@ -83,31 +84,31 @@ BOOST_AUTO_TEST_CASE(netbase_properties) } -bool static TestSplitHost(std::string test, std::string host, int port) +bool static TestSplitHost(const std::string& test, const std::string& host, uint16_t port) { std::string hostOut; - int portOut = -1; + uint16_t portOut{0}; SplitHostPort(test, portOut, hostOut); return hostOut == host && port == portOut; } BOOST_AUTO_TEST_CASE(netbase_splithost) { - BOOST_CHECK(TestSplitHost("www.bitcoincore.org", "www.bitcoincore.org", -1)); - BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]", "www.bitcoincore.org", -1)); + BOOST_CHECK(TestSplitHost("www.bitcoincore.org", "www.bitcoincore.org", 0)); + BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]", "www.bitcoincore.org", 0)); BOOST_CHECK(TestSplitHost("www.bitcoincore.org:80", "www.bitcoincore.org", 80)); BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]:80", "www.bitcoincore.org", 80)); - BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", 0)); BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333)); - BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", 0)); BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333)); - BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", 0)); BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333)); BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333)); - BOOST_CHECK(TestSplitHost("::8333", "::8333", -1)); + BOOST_CHECK(TestSplitHost("::8333", "::8333", 0)); BOOST_CHECK(TestSplitHost(":8333", "", 8333)); BOOST_CHECK(TestSplitHost("[]:8333", "", 8333)); - BOOST_CHECK(TestSplitHost("", "", -1)); + BOOST_CHECK(TestSplitHost("", "", 0)); } bool static TestParse(std::string src, std::string canon) diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index f3d54a2ac9..4734de3e0b 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -107,23 +107,25 @@ std::vector<unsigned char> ParseHex(const std::string& str) return ParseHex(str.c_str()); } -void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { +void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut) +{ size_t colon = in.find_last_of(':'); // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator bool fHaveColon = colon != in.npos; - bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe - bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos); - if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) { - int32_t n; - if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) { + bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe + bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); + if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { + uint16_t n; + if (ParseUInt16(in.substr(colon + 1), &n)) { in = in.substr(0, colon); portOut = n; } } - if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']') - hostOut = in.substr(1, in.size()-2); - else + if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') { + hostOut = in.substr(1, in.size() - 2); + } else { hostOut = in; + } } std::string EncodeBase64(Span<const unsigned char> input) @@ -334,6 +336,18 @@ bool ParseUInt8(const std::string& str, uint8_t *out) return true; } +bool ParseUInt16(const std::string& str, uint16_t* out) +{ + uint32_t u32; + if (!ParseUInt32(str, &u32) || u32 > std::numeric_limits<uint16_t>::max()) { + return false; + } + if (out != nullptr) { + *out = static_cast<uint16_t>(u32); + } + return true; +} + bool ParseUInt32(const std::string& str, uint32_t *out) { if (!ParsePrechecks(str)) diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 98379e9138..26dc0a0ce3 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -65,7 +65,7 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad = true); */ std::string EncodeBase32(const std::string& str, bool pad = true); -void SplitHostPort(std::string in, int& portOut, std::string& hostOut); +void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut); int64_t atoi64(const std::string& str); int atoi(const std::string& str); @@ -116,6 +116,13 @@ constexpr inline bool IsSpace(char c) noexcept { [[nodiscard]] bool ParseUInt8(const std::string& str, uint8_t *out); /** + * Convert decimal string to unsigned 16-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if the entire string could not be parsed or if overflow or underflow occurred. + */ +[[nodiscard]] bool ParseUInt16(const std::string& str, uint16_t* out); + +/** * Convert decimal string to unsigned 32-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. |