aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/netbase.cpp69
-rw-r--r--src/netbase.h1
-rw-r--r--src/test/netbase_tests.cpp92
3 files changed, 119 insertions, 43 deletions
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 2b918b2ff3..953ef13f19 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -33,6 +33,27 @@ enum Network ParseNetwork(std::string net) {
return NET_UNROUTABLE;
}
+void SplitHostPort(std::string in, int &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)) {
+ char *endp = NULL;
+ int n = strtol(in.c_str() + colon + 1, &endp, 10);
+ if (endp && *endp == 0 && n >= 0) {
+ in = in.substr(0, colon);
+ if (n > 0 && n < 0x10000)
+ portOut = n;
+ }
+ }
+ if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
+ hostOut = in.substr(1, in.size()-2);
+ else
+ hostOut = in;
+}
+
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
vIP.clear();
@@ -114,36 +135,11 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault,
if (pszName[0] == 0)
return false;
int port = portDefault;
- char psz[256];
- char *pszHost = psz;
- strlcpy(psz, pszName, sizeof(psz));
- char* pszColon = strrchr(psz+1,':');
- char *pszPortEnd = NULL;
- int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
- if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
- {
- if (psz[0] == '[' && pszColon[-1] == ']')
- {
- pszHost = psz+1;
- pszColon[-1] = 0;
- }
- else
- pszColon[0] = 0;
- if (port >= 0 && port <= USHRT_MAX)
- port = portParsed;
- }
- else
- {
- if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
- {
- pszHost = psz+1;
- psz[strlen(psz)-1] = 0;
- }
-
- }
+ std::string hostname = "";
+ SplitHostPort(std::string(pszName), port, hostname);
std::vector<CNetAddr> vIP;
- bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
+ bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
if (!fRet)
return false;
vAddr.resize(vIP.size());
@@ -496,22 +492,9 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
{
- string strDest(pszDest);
+ string strDest;
int port = portDefault;
-
- // split hostname and port
- size_t colon = strDest.find_last_of(':');
- if (colon != strDest.npos) {
- char *endp = NULL;
- int n = strtol(pszDest + colon + 1, &endp, 10);
- if (endp && *endp == 0 && n >= 0) {
- strDest = strDest.substr(0, colon);
- if (n > 0 && n < 0x10000)
- port = n;
- }
- }
- if (strDest[0] == '[' && strDest[strDest.size()-1] == ']')
- strDest = strDest.substr(1, strDest.size()-2);
+ SplitHostPort(string(pszDest), port, strDest);
SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
diff --git a/src/netbase.h b/src/netbase.h
index a66d3e7f61..7a797e2fd6 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -133,6 +133,7 @@ class CService : public CNetAddr
};
enum Network ParseNetwork(std::string net);
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy);
bool IsProxy(const CNetAddr &addr);
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
new file mode 100644
index 0000000000..77a360aca3
--- /dev/null
+++ b/src/test/netbase_tests.cpp
@@ -0,0 +1,92 @@
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+#include <vector>
+
+#include "netbase.h"
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(netbase_tests)
+
+BOOST_AUTO_TEST_CASE(netbase_networks)
+{
+ BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
+ BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE);
+ BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4);
+ BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6);
+ BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
+}
+
+BOOST_AUTO_TEST_CASE(netbase_properties)
+{
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());
+ BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4());
+ BOOST_CHECK(CNetAddr("::1").IsIPv6());
+ BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918());
+ BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918());
+ BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918());
+ BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849());
+ BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927());
+ BOOST_CHECK(CNetAddr("2002::1").IsRFC3964());
+ BOOST_CHECK(CNetAddr("FC00::").IsRFC4193());
+ BOOST_CHECK(CNetAddr("2001::2").IsRFC4380());
+ BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843());
+ BOOST_CHECK(CNetAddr("FE80::").IsRFC4862());
+ BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052());
+ BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsOnionCat());
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal());
+ BOOST_CHECK(CNetAddr("::1").IsLocal());
+ BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable());
+ BOOST_CHECK(CNetAddr("2001::1").IsRoutable());
+ BOOST_CHECK(CNetAddr("127.0.0.1").IsValid());
+}
+
+bool static TestSplitHost(string test, string host, int port)
+{
+ string hostOut;
+ int portOut = -1;
+ SplitHostPort(test, portOut, hostOut);
+ return hostOut == host && port == portOut;
+}
+
+BOOST_AUTO_TEST_CASE(netbase_splithost)
+{
+ BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1));
+ BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80));
+ BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80));
+ BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
+ 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]: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]:8333", "::ffff:127.0.0.1", 8333));
+ BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
+ BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
+ BOOST_CHECK(TestSplitHost(":8333", "", 8333));
+ BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
+ BOOST_CHECK(TestSplitHost("", "", -1));
+}
+
+bool static TestParse(string src, string canon)
+{
+ CService addr;
+ if (!LookupNumeric(src.c_str(), addr, 65535))
+ return canon == "";
+ return canon == addr.ToString();
+}
+
+BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
+{
+ BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333"));
+ BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse("::", "[::]:65535"));
+ BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
+ BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
+ BOOST_CHECK(TestParse(":::", ""));
+ BOOST_CHECK(TestParse("128.5.1", "128.5.0.1:65535"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()