aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-01-07 06:19:46 -0800
committerPieter Wuille <pieter.wuille@gmail.com>2012-01-07 06:19:46 -0800
commit1684f98b27de9323d24ee4489af54dd84083956a (patch)
tree9c4313e815bd77e817f2dc5b796347d343458d0e
parent7486c64dd8436febbe59e82dbb875e83ad6b5194 (diff)
parent67a42f929b1434f647c63922fd02dc2b93b28060 (diff)
Merge pull request #735 from sipa/netbase
Network stack refactor
-rw-r--r--bitcoin-qt.pro2
-rw-r--r--src/compat.h42
-rw-r--r--src/headers.h2
-rw-r--r--src/init.cpp2
-rw-r--r--src/irc.cpp37
-rw-r--r--src/main.cpp13
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw2
-rw-r--r--src/makefile.osx2
-rw-r--r--src/makefile.unix2
-rw-r--r--src/net.cpp308
-rw-r--r--src/net.h20
-rw-r--r--src/netbase.cpp715
-rw-r--r--src/netbase.h138
-rw-r--r--src/protocol.cpp172
-rw-r--r--src/protocol.h39
-rw-r--r--src/qt/optionsmodel.cpp6
-rw-r--r--src/test/DoS_tests.cpp43
-rw-r--r--src/uint256.h4
-rw-r--r--src/util.cpp6
-rw-r--r--src/util.h30
21 files changed, 1041 insertions, 546 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index 2352230049..71ee1fee6e 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -97,6 +97,7 @@ HEADERS += src/qt/bitcoingui.h \
src/base58.h \
src/bignum.h \
src/checkpoints.h \
+ src/compat.h \
src/util.h \
src/uint256.h \
src/serialize.h \
@@ -156,6 +157,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/editaddressdialog.cpp \
src/qt/bitcoinaddressvalidator.cpp \
src/util.cpp \
+ src/netbase.cpp \
src/key.cpp \
src/script.cpp \
src/main.cpp \
diff --git a/src/compat.h b/src/compat.h
new file mode 100644
index 0000000000..5c1fcc3d6e
--- /dev/null
+++ b/src/compat.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef _BITCOIN_COMPAT_H
+#define _BITCOIN_COMPAT_H 1
+
+typedef u_int SOCKET;
+#ifdef WIN32
+#define MSG_NOSIGNAL 0
+#define MSG_DONTWAIT 0
+typedef int socklen_t;
+#else
+#include "errno.h"
+#define WSAGetLastError() errno
+#define WSAEINVAL EINVAL
+#define WSAEALREADY EALREADY
+#define WSAEWOULDBLOCK EWOULDBLOCK
+#define WSAEMSGSIZE EMSGSIZE
+#define WSAEINTR EINTR
+#define WSAEINPROGRESS EINPROGRESS
+#define WSAEADDRINUSE EADDRINUSE
+#define WSAENOTSOCK EBADF
+#define INVALID_SOCKET (SOCKET)(~0)
+#define SOCKET_ERROR -1
+#endif
+
+inline int myclosesocket(SOCKET& hSocket)
+{
+ if (hSocket == INVALID_SOCKET)
+ return WSAENOTSOCK;
+#ifdef WIN32
+ int ret = closesocket(hSocket);
+#else
+ int ret = close(hSocket);
+#endif
+ hSocket = INVALID_SOCKET;
+ return ret;
+}
+#define closesocket(s) myclosesocket(s)
+
+#endif
diff --git a/src/headers.h b/src/headers.h
index b6903fe93e..6a2a3e4ca4 100644
--- a/src/headers.h
+++ b/src/headers.h
@@ -12,7 +12,7 @@
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
-#define _WIN32_WINNT 0x0500
+#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
diff --git a/src/init.cpp b/src/init.cpp
index 8cbf21cc4b..7c33448971 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -470,7 +470,7 @@ bool AppInit2(int argc, char* argv[])
}
}
- bool fTor = (fUseProxy && addrProxy.port == htons(9050));
+ bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
if (fTor)
{
// Use SoftSetArg here so user can override any of these if they wish.
diff --git a/src/irc.cpp b/src/irc.cpp
index fe96a90a1c..8805c7fd5b 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -22,22 +22,25 @@ void ThreadIRCSeed2(void* parg);
#pragma pack(push, 1)
struct ircaddr
{
- int ip;
+ struct in_addr ip;
short port;
};
#pragma pack(pop)
-string EncodeAddress(const CAddress& addr)
+string EncodeAddress(const CService& addr)
{
struct ircaddr tmp;
- tmp.ip = addr.ip;
- tmp.port = addr.port;
+ if (addr.GetInAddr(&tmp.ip))
+ {
+ tmp.port = htons(addr.GetPort());
- vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
- return string("u") + EncodeBase58Check(vch);
+ vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
+ return string("u") + EncodeBase58Check(vch);
+ }
+ return "";
}
-bool DecodeAddress(string str, CAddress& addr)
+bool DecodeAddress(string str, CService& addr)
{
vector<unsigned char> vch;
if (!DecodeBase58Check(str.substr(1), vch))
@@ -48,7 +51,7 @@ bool DecodeAddress(string str, CAddress& addr)
return false;
memcpy(&tmp, &vch[0], sizeof(tmp));
- addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
+ addr = CService(tmp.ip, ntohs(tmp.port));
return true;
}
@@ -204,7 +207,7 @@ bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
}
}
-bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
+bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
{
Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
@@ -227,10 +230,10 @@ bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
if (fUseProxy)
return false;
- CAddress addr(strHost, 0, true);
+ CNetAddr addr(strHost, true);
if (!addr.IsValid())
return false;
- ipRet = addr.ip;
+ ipRet = addr;
return true;
}
@@ -267,9 +270,9 @@ void ThreadIRCSeed2(void* parg)
while (!fShutdown)
{
- CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
+ CService addrConnect("92.243.23.21", 6667); // irc.lfnet.org
- CAddress addrIRC("irc.lfnet.org", 6667, true);
+ CService addrIRC("irc.lfnet.org", 6667, true);
if (addrIRC.IsValid())
addrConnect = addrIRC;
@@ -325,15 +328,15 @@ void ThreadIRCSeed2(void* parg)
Sleep(500);
// Get our external IP from the IRC server and re-nick before joining the channel
- CAddress addrFromIRC;
- if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
+ CNetAddr addrFromIRC;
+ if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
{
- printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
+ printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
if (!fUseProxy && addrFromIRC.IsRoutable())
{
// IRC lets you to re-nick
fGotExternalIP = true;
- addrLocalHost.ip = addrFromIRC.ip;
+ addrLocalHost.SetIP(addrFromIRC);
strMyName = EncodeAddress(addrLocalHost);
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
}
diff --git a/src/main.cpp b/src/main.cpp
index 15f047bf7b..9a3ce65390 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1931,7 +1931,7 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
- static map<unsigned int, vector<unsigned char> > mapReuseKey;
+ static map<CService, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
@@ -1987,7 +1987,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
- AddTimeData(pfrom->addr.ip, nTime);
+ AddTimeData(pfrom->addr, nTime);
// Change version
if (pfrom->nVersion >= 209)
@@ -2093,7 +2093,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
- uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+ int64 hashAddr = addr.GetHash();
+ uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -2392,12 +2393,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
- if (!mapReuseKey.count(pfrom->addr.ip))
- pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
+ if (!mapReuseKey.count(pfrom->addr))
+ pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
// Send back approval of order and pubkey to use
CScript scriptPubKey;
- scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
+ scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
}
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index c96a12182d..d837691f89 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -33,6 +33,7 @@ HEADERS = \
base58.h \
bignum.h \
checkpoints.h \
+ compat.h \
crypter.h \
db.h \
headers.h \
@@ -63,6 +64,7 @@ LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l w
OBJS= \
obj/checkpoints.o \
+ obj/netbase.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
diff --git a/src/makefile.mingw b/src/makefile.mingw
index ed718b89ea..ac1e4c75fd 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -30,6 +30,7 @@ HEADERS = \
base58.h \
bignum.h \
checkpoints.h \
+ compat.h \
crypter.h \
db.h \
headers.h \
@@ -60,6 +61,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell
OBJS= \
obj/checkpoints.o \
+ obj/netbase.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
diff --git a/src/makefile.osx b/src/makefile.osx
index 966829e222..4c124e6f33 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -51,6 +51,7 @@ HEADERS = \
base58.h \
bignum.h \
checkpoints.h \
+ compat.h \
crypter.h \
db.h \
headers.h \
@@ -72,6 +73,7 @@ HEADERS = \
OBJS= \
obj/checkpoints.o \
+ obj/netbase.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
diff --git a/src/makefile.unix b/src/makefile.unix
index 055f7ab297..8b41b74a1b 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -88,6 +88,7 @@ HEADERS = \
base58.h \
bignum.h \
checkpoints.h \
+ compat.h \
crypter.h \
db.h \
headers.h \
@@ -109,6 +110,7 @@ HEADERS = \
OBJS= \
obj/checkpoints.o \
+ obj/netbase.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
diff --git a/src/net.cpp b/src/net.cpp
index 6dab7e8c11..72897687ef 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -45,7 +45,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
bool fClient = false;
bool fAllowDNS = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
-CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
+CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
@@ -60,10 +60,6 @@ deque<pair<int64, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay;
map<CInv, int64> mapAlreadyAskedFor;
-// Settings
-int fUseProxy = false;
-int nConnectTimeout = 5000;
-CAddress addrProxy("127.0.0.1",9050);
@@ -88,213 +84,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
-bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
-{
- hSocketRet = INVALID_SOCKET;
-
- SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (hSocket == INVALID_SOCKET)
- return false;
-#ifdef SO_NOSIGPIPE
- int set = 1;
- setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
-#endif
-
- bool fProxy = (fUseProxy && addrConnect.IsRoutable());
- struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
-
-#ifdef WIN32
- u_long fNonblock = 1;
- if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
-#else
- int fFlags = fcntl(hSocket, F_GETFL, 0);
- if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
-#endif
- {
- closesocket(hSocket);
- return false;
- }
-
-
- if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
- {
- // WSAEINVAL is here because some legacy version of winsock uses it
- if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
- {
- struct timeval timeout;
- timeout.tv_sec = nTimeout / 1000;
- timeout.tv_usec = (nTimeout % 1000) * 1000;
-
- fd_set fdset;
- FD_ZERO(&fdset);
- FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
- if (nRet == 0)
- {
- printf("connection timeout\n");
- closesocket(hSocket);
- return false;
- }
- if (nRet == SOCKET_ERROR)
- {
- printf("select() for connection failed: %i\n",WSAGetLastError());
- closesocket(hSocket);
- return false;
- }
- socklen_t nRetSize = sizeof(nRet);
-#ifdef WIN32
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
-#else
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
-#endif
- {
- printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
- closesocket(hSocket);
- return false;
- }
- if (nRet != 0)
- {
- printf("connect() failed after select(): %s\n",strerror(nRet));
- closesocket(hSocket);
- return false;
- }
- }
-#ifdef WIN32
- else if (WSAGetLastError() != WSAEISCONN)
-#else
- else
-#endif
- {
- printf("connect() failed: %i\n",WSAGetLastError());
- closesocket(hSocket);
- return false;
- }
- }
-
- /*
- this isn't even strictly necessary
- CNode::ConnectNode immediately turns the socket back to non-blocking
- but we'll turn it back to blocking just in case
- */
-#ifdef WIN32
- fNonblock = 0;
- if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
-#else
- fFlags = fcntl(hSocket, F_GETFL, 0);
- if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
-#endif
- {
- closesocket(hSocket);
- return false;
- }
-
- if (fProxy)
- {
- printf("proxy connecting %s\n", addrConnect.ToString().c_str());
- char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
- memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
- memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
- char* pszSocks4 = pszSocks4IP;
- int nSize = sizeof(pszSocks4IP);
-
- int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
- if (ret != nSize)
- {
- closesocket(hSocket);
- return error("Error sending to proxy");
- }
- char pchRet[8];
- if (recv(hSocket, pchRet, 8, 0) != 8)
- {
- closesocket(hSocket);
- return error("Error reading proxy response");
- }
- if (pchRet[1] != 0x5a)
- {
- closesocket(hSocket);
- if (pchRet[1] != 0x5b)
- printf("ERROR: Proxy returned error %d\n", pchRet[1]);
- return false;
- }
- printf("proxy connected %s\n", addrConnect.ToString().c_str());
- }
-
- hSocketRet = hSocket;
- return true;
-}
-
-// portDefault is in host order
-bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
-{
- vaddr.clear();
- if (pszName[0] == 0)
- return false;
- int port = portDefault;
- char psz[256];
- char *pszHost = psz;
- strlcpy(psz, pszName, sizeof(psz));
- if (fAllowPort)
- {
- 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] == ']')
- {
- // Future: enable IPv6 colon-notation inside []
- pszHost = psz+1;
- pszColon[-1] = 0;
- }
- else
- pszColon[0] = 0;
- port = portParsed;
- if (port < 0 || port > std::numeric_limits<unsigned short>::max())
- port = std::numeric_limits<unsigned short>::max();
- }
- }
-
- unsigned int addrIP = inet_addr(pszHost);
- if (addrIP != INADDR_NONE)
- {
- // valid IP address passed
- vaddr.push_back(CAddress(addrIP, port, nServices));
- return true;
- }
-
- if (!fAllowLookup)
- return false;
-
- struct hostent* phostent = gethostbyname(pszHost);
- if (!phostent)
- return false;
-
- if (phostent->h_addrtype != AF_INET)
- return false;
-
- char** ppAddr = phostent->h_addr_list;
- while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
- {
- CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
- if (addr.IsValid())
- vaddr.push_back(addr);
- ppAddr++;
- }
-
- return (vaddr.size() > 0);
-}
-
-// portDefault is in host order
-bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
-{
- vector<CAddress> vaddr;
- bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
- if (fRet)
- addr = vaddr[0];
- return fRet;
-}
-
-bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
+bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
{
SOCKET hSocket;
if (!ConnectSocket(addrConnect, hSocket))
@@ -328,11 +118,11 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
strLine.resize(strLine.size()-1);
- CAddress addr(strLine,0,true);
+ CService addr(strLine,0,true);
printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
- if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
+ if (!addr.IsValid() || !addr.IsRoutable())
return false;
- ipRet = addr.ip;
+ ipRet.SetIP(addr);
return true;
}
}
@@ -341,7 +131,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
}
// We now get our external IP from the IRC server first and only use this as a backup
-bool GetMyExternalIP(unsigned int& ipRet)
+bool GetMyExternalIP(CNetAddr& ipRet)
{
CAddress addrConnect;
const char* pszGet;
@@ -363,7 +153,7 @@ bool GetMyExternalIP(unsigned int& ipRet)
if (nLookup == 1)
{
- CAddress addrIP("checkip.dyndns.org", 80, true);
+ CService addrIP("checkip.dyndns.org", 80, true);
if (addrIP.IsValid())
addrConnect = addrIP;
}
@@ -382,7 +172,7 @@ bool GetMyExternalIP(unsigned int& ipRet)
if (nLookup == 1)
{
- CAddress addrIP("www.showmyip.com", 80, true);
+ CService addrIP("www.showmyip.com", 80, true);
if (addrIP.IsValid())
addrConnect = addrIP;
}
@@ -417,7 +207,7 @@ void ThreadGetMyExternalIP(void* parg)
}
// Fallback in case IRC fails to get it
- if (GetMyExternalIP(addrLocalHost.ip))
+ if (GetMyExternalIP(addrLocalHost))
{
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
if (addrLocalHost.IsRoutable())
@@ -441,7 +231,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
- if (addr.ip == addrLocalHost.ip)
+ if ((CService)addr == (CService)addrLocalHost)
return false;
addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
bool fUpdated = false;
@@ -494,7 +284,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
return fNew;
}
-void AddressCurrentlyConnected(const CAddress& addr)
+void AddressCurrentlyConnected(const CService& addr)
{
CAddress *paddrFound = NULL;
@@ -624,23 +414,23 @@ void CNode::CancelSubscribe(unsigned int nChannel)
-CNode* FindNode(unsigned int ip)
+CNode* FindNode(const CNetAddr& ip)
{
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->addr.ip == ip)
+ if ((CNetAddr)pnode->addr == ip)
return (pnode);
}
return NULL;
}
-CNode* FindNode(CAddress addr)
+CNode* FindNode(const CService& addr)
{
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->addr == addr)
+ if ((CService)pnode->addr == addr)
return (pnode);
}
return NULL;
@@ -648,11 +438,11 @@ CNode* FindNode(CAddress addr)
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
{
- if (addrConnect.ip == addrLocalHost.ip)
+ if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
return NULL;
// Look for an existing connection
- CNode* pnode = FindNode(addrConnect.ip);
+ CNode* pnode = FindNode((CService)addrConnect);
if (pnode)
{
if (nTimeout != 0)
@@ -746,7 +536,7 @@ void CNode::PushVersion()
-std::map<unsigned int, int64> CNode::setBanned;
+std::map<CNetAddr, int64> CNode::setBanned;
CCriticalSection CNode::cs_setBanned;
void CNode::ClearBanned()
@@ -754,12 +544,12 @@ void CNode::ClearBanned()
setBanned.clear();
}
-bool CNode::IsBanned(unsigned int ip)
+bool CNode::IsBanned(CNetAddr ip)
{
bool fResult = false;
CRITICAL_BLOCK(cs_setBanned)
{
- std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
+ std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
if (i != setBanned.end())
{
int64 t = (*i).second;
@@ -783,8 +573,8 @@ bool CNode::Misbehaving(int howmuch)
{
int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
CRITICAL_BLOCK(cs_setBanned)
- if (setBanned[addr.ip] < banTime)
- setBanned[addr.ip] = banTime;
+ if (setBanned[addr] < banTime)
+ setBanned[addr] = banTime;
CloseSocketDisconnect();
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
return true;
@@ -962,7 +752,7 @@ void ThreadSocketHandler2(void* parg)
{
closesocket(hSocket);
}
- else if (CNode::IsBanned(addr.ip))
+ else if (CNode::IsBanned(addr))
{
printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
closesocket(hSocket);
@@ -1277,15 +1067,16 @@ void ThreadDNSAddressSeed2(void* parg)
printf("Loading addresses from DNS seeds (could take a while)\n");
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
- vector<CAddress> vaddr;
- if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
+ vector<CNetAddr> vaddr;
+ if (LookupHost(strDNSSeed[seed_idx], vaddr))
{
CAddrDB addrDB;
addrDB.TxnBegin();
- BOOST_FOREACH (CAddress& addr, vaddr)
+ BOOST_FOREACH (CNetAddr& ip, vaddr)
{
- if (addr.GetByte(3) != 127)
+ if (ip.IsRoutable())
{
+ CAddress addr(CService(ip, GetDefaultPort()), NODE_NETWORK);
addr.nTime = 0;
AddAddress(addr, 0, &addrDB);
found++;
@@ -1470,8 +1261,8 @@ void ThreadOpenConnections2(void* parg)
CRITICAL_BLOCK(cs_mapAddresses)
{
// Add seed nodes if IRC isn't working
- bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
- if (mapAddresses.empty() && (GetTime() - nStart > 60 || fUseProxy) && !fTestNet)
+ bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
+ if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
fAddSeeds = true;
}
@@ -1484,8 +1275,9 @@ void ThreadOpenConnections2(void* parg)
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
const int64 nOneWeek = 7*24*60*60;
- CAddress addr;
- addr.ip = pnSeed[i];
+ struct in_addr ip;
+ memcpy(&ip, &pnSeed[i], sizeof(ip));
+ CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
AddAddress(addr);
}
@@ -1499,10 +1291,10 @@ void ThreadOpenConnections2(void* parg)
// Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
- set<unsigned int> setConnected;
+ set<vector<unsigned char> > setConnected;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
- setConnected.insert(pnode->addr.ip & 0x0000ffff);
+ setConnected.insert(pnode->addr.GetGroup());
int64 nANow = GetAdjustedTime();
@@ -1511,14 +1303,14 @@ void ThreadOpenConnections2(void* parg)
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
- if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
+ if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()))
continue;
int64 nSinceLastSeen = nANow - addr.nTime;
int64 nSinceLastTry = nANow - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
- int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
- if (addr.port != htons(GetDefaultPort()))
+ int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.GetHash()) % (2 * 60 * 60);
+ if (addr.GetPort() != GetDefaultPort())
nRandomizer += 2 * 60 * 60;
// Last seen Base retry frequency
@@ -1573,8 +1365,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect)
//
if (fShutdown)
return false;
- if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
- FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
+ if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
+ FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
return false;
vnThreadsRunning[1]--;
@@ -1676,7 +1468,7 @@ bool BindListenPort(string& strError)
{
strError = "";
int nOne = 1;
- addrLocalHost.port = htons(GetListenPort());
+ addrLocalHost.SetPort(GetListenPort());
#ifdef WIN32
// Initialize Windows Sockets
@@ -1755,19 +1547,19 @@ bool BindListenPort(string& strError)
void StartNode(void* parg)
{
if (pnodeLocalHost == NULL)
- pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
+ pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
#ifdef WIN32
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
- vector<CAddress> vaddr;
- if (Lookup(pszHostName, vaddr, nLocalServices, -1, true))
- BOOST_FOREACH (const CAddress &addr, vaddr)
- if (addr.GetByte(3) != 127)
+ vector<CNetAddr> vaddr;
+ if (LookupHost(pszHostName, vaddr))
+ BOOST_FOREACH (const CNetAddr &addr, vaddr)
+ if (!addr.IsLocal())
{
- addrLocalHost = addr;
+ addrLocalHost.SetIP(addr);
break;
}
}
@@ -1790,8 +1582,8 @@ void StartNode(void* parg)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x
- CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices);
- if (addr.IsValid() && addr.GetByte(3) != 127)
+ CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
+ if (addr.IsValid() && !addr.IsLocal())
{
addrLocalHost = addr;
break;
@@ -1812,7 +1604,7 @@ void StartNode(void* parg)
if (fUseProxy || mapArgs.count("-connect") || fNoListen)
{
// Proxies can't take incoming connections
- addrLocalHost.ip = CAddress("0.0.0.0").ip;
+ addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
else
diff --git a/src/net.h b/src/net.h
index c2637dc6ac..61daf0378c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -14,6 +14,7 @@
#include <arpa/inet.h>
#endif
+#include "netbase.h"
#include "protocol.h"
class CAddrDB;
@@ -21,7 +22,6 @@ class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
-extern int nConnectTimeout;
@@ -29,13 +29,11 @@ inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer"
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
static const unsigned int PUBLISH_HOPS = 5;
-bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
-bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-bool GetMyExternalIP(unsigned int& ipRet);
+bool GetMyExternalIP(CNetAddr& ipRet);
bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
-void AddressCurrentlyConnected(const CAddress& addr);
-CNode* FindNode(unsigned int ip);
+void AddressCurrentlyConnected(const CService& addr);
+CNode* FindNode(const CNetAddr& ip);
+CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
bool AnySubscribed(unsigned int nChannel);
@@ -88,9 +86,6 @@ extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
extern std::map<CInv, int64> mapAlreadyAskedFor;
-// Settings
-extern int fUseProxy;
-extern CAddress addrProxy;
@@ -126,7 +121,7 @@ protected:
// Denial-of-service detection/prevention
// Key is ip address, value is banned-until-time
- static std::map<unsigned int, int64> setBanned;
+ static std::map<CNetAddr, int64> setBanned;
static CCriticalSection cs_setBanned;
int nMisbehavior;
@@ -355,7 +350,6 @@ public:
-
void PushVersion();
@@ -581,7 +575,7 @@ public:
// between nodes running old code and nodes running
// new code.
static void ClearBanned(); // needed for unit testing
- static bool IsBanned(unsigned int ip);
+ static bool IsBanned(CNetAddr ip);
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
};
diff --git a/src/netbase.cpp b/src/netbase.cpp
new file mode 100644
index 0000000000..2c4df7faf8
--- /dev/null
+++ b/src/netbase.cpp
@@ -0,0 +1,715 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#include "netbase.h"
+#include "util.h"
+
+#ifndef WIN32
+#include <sys/fcntl.h>
+#endif
+
+#include "strlcpy.h"
+
+using namespace std;
+
+// Settings
+int fUseProxy = false;
+CService addrProxy("127.0.0.1",9050);
+int nConnectTimeout = 5000;
+
+
+static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup)
+{
+ vIP.clear();
+ struct addrinfo aiHint = {};
+ aiHint.ai_socktype = SOCK_STREAM;
+ aiHint.ai_protocol = IPPROTO_TCP;
+#ifdef WIN32
+# ifdef USE_IPV6
+ aiHint.ai_family = AF_UNSPEC;
+ aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
+# else
+ aiHint.ai_family = AF_INET;
+ aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
+# endif
+#else
+# ifdef USE_IPV6
+ aiHint.ai_family = AF_UNSPEC;
+ aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
+# else
+ aiHint.ai_family = AF_INET;
+ aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
+# endif
+#endif
+ struct addrinfo *aiRes = NULL;
+ int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
+ if (nErr)
+ return false;
+
+ struct addrinfo *aiTrav = aiRes;
+ while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
+ {
+ if (aiTrav->ai_family == AF_INET)
+ {
+ assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
+ vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
+ }
+
+#ifdef USE_IPV6
+ if (aiTrav->ai_family == AF_INET6)
+ {
+ assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
+ vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr));
+ }
+#endif
+
+ aiTrav = aiTrav->ai_next;
+ }
+
+ freeaddrinfo(aiRes);
+
+ return (vIP.size() > 0);
+}
+
+bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions, bool fAllowLookup)
+{
+ if (pszName[0] == 0)
+ return false;
+ char psz[256];
+ char *pszHost = psz;
+ strlcpy(psz, pszName, sizeof(psz));
+ if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
+ {
+ pszHost = psz+1;
+ psz[strlen(psz)-1] = 0;
+ }
+
+ return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup);
+}
+
+bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions)
+{
+ return LookupHost(pszName, vIP, nMaxSolutions, false);
+}
+
+bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)
+{
+ 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::vector<CNetAddr> vIP;
+ bool fRet = LookupIntern(pszHost, vIP, 1, fAllowLookup);
+ if (!fRet)
+ return false;
+ addr = CService(vIP[0], port);
+ return true;
+}
+
+bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
+{
+ return Lookup(pszName, addr, portDefault, false);
+}
+
+bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
+{
+ hSocketRet = INVALID_SOCKET;
+
+ SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (hSocket == INVALID_SOCKET)
+ return false;
+#ifdef SO_NOSIGPIPE
+ int set = 1;
+ setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
+#endif
+
+ bool fProxy = (fUseProxy && addrDest.IsRoutable());
+ struct sockaddr_in sockaddr;
+ if (fProxy)
+ addrProxy.GetSockAddr(&sockaddr);
+ else
+ addrDest.GetSockAddr(&sockaddr);
+
+#ifdef WIN32
+ u_long fNonblock = 1;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ int fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
+#endif
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+
+ if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+ {
+ // WSAEINVAL is here because some legacy version of winsock uses it
+ if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
+ {
+ struct timeval timeout;
+ timeout.tv_sec = nTimeout / 1000;
+ timeout.tv_usec = (nTimeout % 1000) * 1000;
+
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ FD_SET(hSocket, &fdset);
+ int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
+ if (nRet == 0)
+ {
+ printf("connection timeout\n");
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet == SOCKET_ERROR)
+ {
+ printf("select() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ socklen_t nRetSize = sizeof(nRet);
+#ifdef WIN32
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
+#else
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
+#endif
+ {
+ printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet != 0)
+ {
+ printf("connect() failed after select(): %s\n",strerror(nRet));
+ closesocket(hSocket);
+ return false;
+ }
+ }
+#ifdef WIN32
+ else if (WSAGetLastError() != WSAEISCONN)
+#else
+ else
+#endif
+ {
+ printf("connect() failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ }
+
+ // this isn't even strictly necessary
+ // CNode::ConnectNode immediately turns the socket back to non-blocking
+ // but we'll turn it back to blocking just in case
+#ifdef WIN32
+ fNonblock = 0;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
+#endif
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+ if (fProxy)
+ {
+ printf("proxy connecting %s\n", addrDest.ToString().c_str());
+ char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
+ struct sockaddr_in addr;
+ addrDest.GetSockAddr(&addr);
+ memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
+ memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
+ char* pszSocks4 = pszSocks4IP;
+ int nSize = sizeof(pszSocks4IP);
+
+ int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
+ if (ret != nSize)
+ {
+ closesocket(hSocket);
+ return error("Error sending to proxy");
+ }
+ char pchRet[8];
+ if (recv(hSocket, pchRet, 8, 0) != 8)
+ {
+ closesocket(hSocket);
+ return error("Error reading proxy response");
+ }
+ if (pchRet[1] != 0x5a)
+ {
+ closesocket(hSocket);
+ if (pchRet[1] != 0x5b)
+ printf("ERROR: Proxy returned error %d\n", pchRet[1]);
+ return false;
+ }
+ printf("proxy connected %s\n", addrDest.ToString().c_str());
+ }
+
+ hSocketRet = hSocket;
+ return true;
+}
+
+void CNetAddr::Init()
+{
+ memset(ip, 0, 16);
+}
+
+void CNetAddr::SetIP(const CNetAddr& ipIn)
+{
+ memcpy(ip, ipIn.ip, sizeof(ip));
+}
+
+CNetAddr::CNetAddr()
+{
+ Init();
+}
+
+CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
+{
+ memcpy(ip, pchIPv4, 12);
+ memcpy(ip+12, &ipv4Addr, 4);
+}
+
+#ifdef USE_IPV6
+CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr)
+{
+ memcpy(ip, &ipv6Addr, 16);
+}
+#endif
+
+CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup)
+{
+ Init();
+ std::vector<CNetAddr> vIP;
+ if (LookupHost(pszIp, vIP, 1, fAllowLookup))
+ *this = vIP[0];
+}
+
+CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup)
+{
+ Init();
+ std::vector<CNetAddr> vIP;
+ if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup))
+ *this = vIP[0];
+}
+
+int CNetAddr::GetByte(int n) const
+{
+ return ip[15-n];
+}
+
+bool CNetAddr::IsIPv4() const
+{
+ return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
+}
+
+bool CNetAddr::IsRFC1918() const
+{
+ return IsIPv4() && (
+ GetByte(3) == 10 ||
+ (GetByte(3) == 192 && GetByte(2) == 168) ||
+ (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
+}
+
+bool CNetAddr::IsRFC3927() const
+{
+ return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
+}
+
+bool CNetAddr::IsRFC3849() const
+{
+ return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
+}
+
+bool CNetAddr::IsRFC3964() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
+}
+
+bool CNetAddr::IsRFC6052() const
+{
+ static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
+}
+
+bool CNetAddr::IsRFC4380() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);
+}
+
+bool CNetAddr::IsRFC4862() const
+{
+ static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
+}
+
+bool CNetAddr::IsRFC4193() const
+{
+ return ((GetByte(15) & 0xFE) == 0xFC);
+}
+
+bool CNetAddr::IsRFC6145() const
+{
+ static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
+ return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
+}
+
+bool CNetAddr::IsRFC4843() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && GetByte(12) & 0xF0 == 0x10);
+}
+
+bool CNetAddr::IsLocal() const
+{
+ // IPv4 loopback
+ if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
+ return true;
+
+ // IPv6 loopback (::1/128)
+ static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+ if (memcmp(ip, pchLocal, 16) == 0)
+ return true;
+
+ return false;
+}
+
+bool CNetAddr::IsMulticast() const
+{
+ return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0)
+ || (GetByte(15) == 0xFF);
+}
+
+bool CNetAddr::IsValid() const
+{
+ // Clean up 3-byte shifted addresses caused by garbage in size field
+ // of addr messages from versions before 0.2.9 checksum.
+ // Two consecutive addr messages look like this:
+ // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
+ // so if the first length field is garbled, it reads the second batch
+ // of addr misaligned by 3 bytes.
+ if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
+ return false;
+
+ // unspecified IPv6 address (::/128)
+ unsigned char ipNone[16] = {};
+ if (memcmp(ip, ipNone, 16) == 0)
+ return false;
+
+ // documentation IPv6 address
+ if (IsRFC3849())
+ return false;
+
+ if (IsIPv4())
+ {
+ // INADDR_NONE
+ uint32_t ipNone = INADDR_NONE;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+
+ // 0
+ ipNone = 0;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool CNetAddr::IsRoutable() const
+{
+ return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || IsRFC4193() || IsRFC4843() || IsLocal());
+}
+
+std::string CNetAddr::ToStringIP() const
+{
+ if (IsIPv4())
+ return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
+ else
+ return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
+ GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
+ GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
+ GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
+}
+
+std::string CNetAddr::ToString() const
+{
+ return ToStringIP();
+}
+
+bool operator==(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) == 0);
+}
+
+bool operator!=(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) != 0);
+}
+
+bool operator<(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) < 0);
+}
+
+bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
+{
+ if (!IsIPv4())
+ return false;
+ memcpy(pipv4Addr, ip+12, 4);
+ return true;
+}
+
+#ifdef USE_IPV6
+bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
+{
+ memcpy(pipv6Addr, ip, 16);
+ return true;
+}
+#endif
+
+// get canonical identifier of an address' group
+// no two connections will be attempted to addresses with the same group
+std::vector<unsigned char> CNetAddr::GetGroup() const
+{
+ std::vector<unsigned char> vchRet;
+ int nClass = 0; // 0=IPv6, 1=IPv4, 255=unroutable
+ int nStartByte = 0;
+ int nBits = 16;
+
+ // for unroutable addresses, each address is considered different
+ if (!IsRoutable())
+ {
+ nClass = 255;
+ nBits = 128;
+ }
+ // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
+ // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
+ else if (IsIPv4() || IsRFC6145() || IsRFC6052())
+ {
+ nClass = 1;
+ nStartByte = 12;
+ }
+ // for 6to4 tunneled addresses, use the encapsulated IPv4 address
+ else if (IsRFC3964())
+ {
+ nClass = 1;
+ nStartByte = 2;
+ }
+ // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address
+ else if (IsRFC4380())
+ {
+ vchRet.push_back(1);
+ vchRet.push_back(GetByte(3) ^ 0xFF);
+ vchRet.push_back(GetByte(2) ^ 0xFF);
+ return vchRet;
+ }
+ // for he.net, use /36 groups
+ else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
+ nBits = 36;
+ // for the rest of the IPv6 network, use /32 groups
+ else
+ nBits = 32;
+
+ vchRet.push_back(nClass);
+ while (nBits >= 8)
+ {
+ vchRet.push_back(GetByte(15 - nStartByte));
+ nStartByte++;
+ nBits -= 8;
+ }
+ if (nBits > 0)
+ vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1));
+
+ return vchRet;
+}
+
+int64 CNetAddr::GetHash() const
+{
+ uint256 hash = Hash(&ip[0], &ip[16]);
+ int64 nRet;
+ memcpy(&nRet, &hash, sizeof(nRet));
+ return nRet;
+}
+
+void CNetAddr::print() const
+{
+ printf("CNetAddr(%s)\n", ToString().c_str());
+}
+
+void CService::Init()
+{
+ port = 0;
+}
+
+CService::CService()
+{
+ Init();
+}
+
+CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
+{
+}
+
+CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)
+{
+}
+
+#ifdef USE_IPV6
+CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
+{
+}
+#endif
+
+CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
+{
+ assert(addr.sin_family == AF_INET);
+}
+
+#ifdef USE_IPV6
+CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port))
+{
+ assert(addr.sin6_family == AF_INET6);
+}
+#endif
+
+CService::CService(const char *pszIpPort, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(pszIpPort, ip, 0, fAllowLookup))
+ *this = ip;
+}
+
+CService::CService(const char *pszIp, int portIn, bool fAllowLookup)
+{
+ std::vector<CNetAddr> ip;
+ if (LookupHost(pszIp, ip, 1, fAllowLookup))
+ *this = CService(ip[0], portIn);
+}
+
+CService::CService(const std::string &strIpPort, bool fAllowLookup)
+{
+ Init();
+ CService ip;
+ if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup))
+ *this = ip;
+}
+
+CService::CService(const std::string &strIp, int portIn, bool fAllowLookup)
+{
+ std::vector<CNetAddr> ip;
+ if (LookupHost(strIp.c_str(), ip, 1, fAllowLookup))
+ *this = CService(ip[0], portIn);
+}
+
+unsigned short CService::GetPort() const
+{
+ return port;
+}
+
+bool operator==(const CService& a, const CService& b)
+{
+ return (CNetAddr)a == (CNetAddr)b && a.port == b.port;
+}
+
+bool operator!=(const CService& a, const CService& b)
+{
+ return (CNetAddr)a != (CNetAddr)b || a.port != b.port;
+}
+
+bool operator<(const CService& a, const CService& b)
+{
+ return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
+}
+
+bool CService::GetSockAddr(struct sockaddr_in* paddr) const
+{
+ if (!IsIPv4())
+ return false;
+ memset(paddr, 0, sizeof(struct sockaddr_in));
+ if (!GetInAddr(&paddr->sin_addr))
+ return false;
+ paddr->sin_family = AF_INET;
+ paddr->sin_port = htons(port);
+ return true;
+}
+
+#ifdef USE_IPV6
+bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const
+{
+ memset(paddr, 0, sizeof(struct sockaddr_in6));
+ if (!GetIn6Addr(&paddr->sin6_addr))
+ return false;
+ paddr->sin6_family = AF_INET6;
+ paddr->sin6_port = htons(port);
+ return true;
+}
+#endif
+
+std::vector<unsigned char> CService::GetKey() const
+{
+ std::vector<unsigned char> vKey;
+ vKey.resize(18);
+ memcpy(&vKey[0], ip, 16);
+ vKey[16] = port / 0x100;
+ vKey[17] = port & 0x0FF;
+ return vKey;
+}
+
+std::string CService::ToStringPort() const
+{
+ return strprintf(":%i", port);
+}
+
+std::string CService::ToStringIPPort() const
+{
+ return ToStringIP() + ToStringPort();
+}
+
+std::string CService::ToString() const
+{
+ return ToStringIPPort();
+}
+
+void CService::print() const
+{
+ printf("CService(%s)\n", ToString().c_str());
+}
+
+void CService::SetPort(unsigned short portIn)
+{
+ port = portIn;
+}
diff --git a/src/netbase.h b/src/netbase.h
new file mode 100644
index 0000000000..6f06f8fe08
--- /dev/null
+++ b/src/netbase.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2011 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_NETBASE_H
+#define BITCOIN_NETBASE_H
+
+#include <string>
+#include <vector>
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#endif
+#ifdef BSD
+#include <netinet/in.h>
+#endif
+
+#include "serialize.h"
+#include "compat.h"
+
+extern int nConnectTimeout;
+
+
+// IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
+class CNetAddr
+{
+ protected:
+ unsigned char ip[16]; // in network byte order
+
+ public:
+ CNetAddr();
+ CNetAddr(const struct in_addr& ipv4Addr);
+ CNetAddr(const char *pszIp, bool fAllowLookup = false);
+ CNetAddr(const std::string &strIp, bool fAllowLookup = false);
+ void Init();
+ void SetIP(const CNetAddr& ip);
+ bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
+ bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
+ bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
+ bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
+ bool IsRFC3964() const; // IPv6 6to4 tunneling (2002::/16)
+ bool IsRFC4193() const; // IPv6 unique local (FC00::/15)
+ bool IsRFC4380() const; // IPv6 Teredo tunneling (2001::/32)
+ bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
+ bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
+ bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
+ bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
+ bool IsLocal() const;
+ bool IsRoutable() const;
+ bool IsValid() const;
+ bool IsMulticast() const;
+ std::string ToString() const;
+ std::string ToStringIP() const;
+ int GetByte(int n) const;
+ int64 GetHash() const;
+ bool GetInAddr(struct in_addr* pipv4Addr) const;
+ std::vector<unsigned char> GetGroup() const;
+ void print() const;
+
+#ifdef USE_IPV6
+ CNetAddr(const struct in6_addr& pipv6Addr);
+ bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
+#endif
+
+ friend bool operator==(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator<(const CNetAddr& a, const CNetAddr& b);
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(FLATDATA(ip));
+ )
+};
+
+class CService : public CNetAddr
+{
+ protected:
+ unsigned short port; // host order
+
+ public:
+ CService();
+ CService(const CNetAddr& ip, unsigned short port);
+ CService(const struct in_addr& ipv4Addr, unsigned short port);
+ CService(const struct sockaddr_in& addr);
+ CService(const char *pszIp, int port, bool fAllowLookup = false);
+ CService(const char *pszIpPort, bool fAllowLookup = false);
+ CService(const std::string& strIp, int port, bool fAllowLookup = false);
+ CService(const std::string& strIpPort, bool fAllowLookup = false);
+ void Init();
+ void SetPort(unsigned short portIn);
+ unsigned short GetPort() const;
+ bool GetSockAddr(struct sockaddr_in* paddr) const;
+ friend bool operator==(const CService& a, const CService& b);
+ friend bool operator!=(const CService& a, const CService& b);
+ friend bool operator<(const CService& a, const CService& b);
+ std::vector<unsigned char> GetKey() const;
+ std::string ToString() const;
+ std::string ToStringPort() const;
+ std::string ToStringIPPort() const;
+ void print() const;
+
+#ifdef USE_IPV6
+ CService(const struct in6_addr& ipv6Addr, unsigned short port);
+ bool GetSockAddr6(struct sockaddr_in6* paddr) const;
+ CService(const struct sockaddr_in6& addr);
+#endif
+
+ IMPLEMENT_SERIALIZE
+ (
+ CService* pthis = const_cast<CService*>(this);
+ READWRITE(FLATDATA(ip));
+ unsigned short portN = htons(port);
+ READWRITE(portN);
+ if (fRead)
+ pthis->port = ntohs(portN);
+ )
+};
+
+bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions = 0, bool fAllowLookup = true);
+bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, int nMaxSolutions = 0);
+bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);
+bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
+bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
+
+// Settings
+extern int fUseProxy;
+extern CService addrProxy;
+
+#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 27efb8f293..45f08082e9 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -5,16 +5,12 @@
#include "protocol.h"
#include "util.h"
+#include "netbase.h"
#ifndef WIN32
# include <arpa/inet.h>
#endif
-// Prototypes from net.h, but that header (currently) stinks, can't #include it without breaking things
-bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-
-static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const char* ppszTypeName[] =
{
"ERROR",
@@ -77,185 +73,26 @@ bool CMessageHeader::IsValid() const
return true;
}
-CAddress::CAddress()
-{
- Init();
-}
-
-CAddress::CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn)
-{
- Init();
- ip = ipIn;
- port = htons(portIn == 0 ? GetDefaultPort() : portIn);
- nServices = nServicesIn;
-}
-
-CAddress::CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn)
-{
- Init();
- ip = sockaddr.sin_addr.s_addr;
- port = sockaddr.sin_port;
- nServices = nServicesIn;
-}
-
-CAddress::CAddress(const char* pszIn, int portIn, bool fNameLookup, uint64 nServicesIn)
-{
- Init();
- Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
-}
-CAddress::CAddress(const char* pszIn, bool fNameLookup, uint64 nServicesIn)
-{
- Init();
- Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
-}
-CAddress::CAddress(std::string strIn, int portIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress() : CService()
{
Init();
- Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
}
-CAddress::CAddress(std::string strIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn)
{
Init();
- Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
+ nServices = nServicesIn;
}
void CAddress::Init()
{
nServices = NODE_NETWORK;
- memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
- ip = INADDR_NONE;
- port = htons(GetDefaultPort());
nTime = 100000000;
nLastTry = 0;
}
-bool operator==(const CAddress& a, const CAddress& b)
-{
- return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
- a.ip == b.ip &&
- a.port == b.port);
-}
-
-bool operator!=(const CAddress& a, const CAddress& b)
-{
- return (!(a == b));
-}
-
-bool operator<(const CAddress& a, const CAddress& b)
-{
- int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
- if (ret < 0)
- return true;
- else if (ret == 0)
- {
- if (ntohl(a.ip) < ntohl(b.ip))
- return true;
- else if (a.ip == b.ip)
- return ntohs(a.port) < ntohs(b.port);
- }
- return false;
-}
-
-std::vector<unsigned char> CAddress::GetKey() const
-{
- CDataStream ss;
- ss.reserve(18);
- ss << FLATDATA(pchReserved) << ip << port;
-
- #if defined(_MSC_VER) && _MSC_VER < 1300
- return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
- #else
- return std::vector<unsigned char>(ss.begin(), ss.end());
- #endif
-}
-
-struct sockaddr_in CAddress::GetSockAddr() const
-{
- struct sockaddr_in sockaddr;
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_addr.s_addr = ip;
- sockaddr.sin_port = port;
- return sockaddr;
-}
-
-bool CAddress::IsIPv4() const
-{
- return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
-}
-
-bool CAddress::IsRFC1918() const
-{
- return IsIPv4() && (GetByte(3) == 10 ||
- (GetByte(3) == 192 && GetByte(2) == 168) ||
- (GetByte(3) == 172 &&
- (GetByte(2) >= 16 && GetByte(2) <= 31)));
-}
-
-bool CAddress::IsRFC3927() const
-{
- return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
-}
-
-bool CAddress::IsLocal() const
-{
- return IsIPv4() && (GetByte(3) == 127 ||
- GetByte(3) == 0);
-}
-
-bool CAddress::IsRoutable() const
-{
- return IsValid() &&
- !(IsRFC1918() || IsRFC3927() || IsLocal());
-}
-
-bool CAddress::IsValid() const
-{
- // Clean up 3-byte shifted addresses caused by garbage in size field
- // of addr messages from versions before 0.2.9 checksum.
- // Two consecutive addr messages look like this:
- // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
- // so if the first length field is garbled, it reads the second batch
- // of addr misaligned by 3 bytes.
- if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
- return false;
-
- return (ip != 0 && ip != INADDR_NONE && port != htons(std::numeric_limits<unsigned short>::max()));
-}
-
-unsigned char CAddress::GetByte(int n) const
-{
- return ((unsigned char*)&ip)[3-n];
-}
-
-std::string CAddress::ToStringIPPort() const
-{
- return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
-}
-
-std::string CAddress::ToStringIP() const
-{
- return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
-}
-
-std::string CAddress::ToStringPort() const
-{
- return strprintf("%u", ntohs(port));
-}
-
-std::string CAddress::ToString() const
-{
- return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
-}
-
-void CAddress::print() const
-{
- printf("CAddress(%s)\n", ToString().c_str());
-}
-
CInv::CInv()
{
type = 0;
@@ -310,3 +147,4 @@ void CInv::print() const
{
printf("CInv(%s)\n", ToString().c_str());
}
+
diff --git a/src/protocol.h b/src/protocol.h
index 53d3eef4d5..67e20d94e1 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -11,6 +11,8 @@
#define __INCLUDED_PROTOCOL_H__
#include "serialize.h"
+#include "netbase.h"
+#include "util.h"
#include <string>
#include "uint256.h"
@@ -61,58 +63,33 @@ enum
NODE_NETWORK = (1 << 0),
};
-class CAddress
+class CAddress : public CService
{
public:
CAddress();
- CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
+ CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK);
void Init();
IMPLEMENT_SERIALIZE
(
+ CAddress* pthis = const_cast<CAddress*>(this);
+ CService* pip = (CService*)pthis;
if (fRead)
- const_cast<CAddress*>(this)->Init();
+ pthis->Init();
if (nType & SER_DISK)
READWRITE(nVersion);
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
READWRITE(nTime);
READWRITE(nServices);
- READWRITE(FLATDATA(pchReserved)); // for IPv6
- READWRITE(ip);
- READWRITE(port);
+ READWRITE(*pip);
)
- friend bool operator==(const CAddress& a, const CAddress& b);
- friend bool operator!=(const CAddress& a, const CAddress& b);
- friend bool operator<(const CAddress& a, const CAddress& b);
-
- std::vector<unsigned char> GetKey() const;
- struct sockaddr_in GetSockAddr() const;
- bool IsIPv4() const;
- bool IsRFC1918() const;
- bool IsRFC3927() const;
- bool IsLocal() const;
- bool IsRoutable() const;
- bool IsValid() const;
- unsigned char GetByte(int n) const;
- std::string ToStringIPPort() const;
- std::string ToStringIP() const;
- std::string ToStringPort() const;
- std::string ToString() const;
void print() const;
// TODO: make private (improves encapsulation)
public:
uint64 nServices;
- unsigned char pchReserved[12];
- unsigned int ip;
- unsigned short port;
// disk and network only
unsigned int nTime;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index a68c84c957..3237845c2c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -88,9 +88,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
{
// Use CAddress to parse and check IP
CAddress addr(value.toString().toStdString() + ":1");
- if (addr.ip != INADDR_NONE)
+ if (addr.IsValid())
{
- addrProxy.ip = addr.ip;
+ addrProxy.SetIP(addr);
walletdb.WriteSetting("addrProxy", addrProxy);
}
else
@@ -104,7 +104,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
int nPort = atoi(value.toString().toAscii().data());
if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
{
- addrProxy.port = htons(nPort);
+ addrProxy.SetPort(nPort);
walletdb.WriteSetting("addrProxy", addrProxy);
}
else
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index e9b7b4517a..f29f036eb3 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -10,40 +10,47 @@
#include "net.h"
#include "util.h"
-using namespace std;
+#include <stdint.h>
+
+CService ip(uint32_t i)
+{
+ struct in_addr s;
+ s.s_addr = i;
+ return CService(CNetAddr(s), GetDefaultPort());
+}
BOOST_AUTO_TEST_SUITE(DoS_tests)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
CNode::ClearBanned();
- CAddress addr1(0xa0b0c001);
+ CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100); // Should get banned
- BOOST_CHECK(CNode::IsBanned(addr1.ip));
- BOOST_CHECK(!CNode::IsBanned(addr1.ip|0x0000ff00)); // Different ip, not banned
+ BOOST_CHECK(CNode::IsBanned(addr1));
+ BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned
- CAddress addr2(0xa0b0c002);
+ CAddress addr2(ip(0xa0b0c002));
CNode dummyNode2(INVALID_SOCKET, addr2, true);
dummyNode2.Misbehaving(50);
- BOOST_CHECK(!CNode::IsBanned(addr2.ip)); // 2 not banned yet...
- BOOST_CHECK(CNode::IsBanned(addr1.ip)); // ... but 1 still should be
+ BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
+ BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
dummyNode2.Misbehaving(50);
- BOOST_CHECK(CNode::IsBanned(addr2.ip));
+ BOOST_CHECK(CNode::IsBanned(addr2));
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
CNode::ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
- CAddress addr1(0xa0b0c001);
+ CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100);
- BOOST_CHECK(!CNode::IsBanned(addr1.ip));
+ BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(10);
- BOOST_CHECK(!CNode::IsBanned(addr1.ip));
+ BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(1);
- BOOST_CHECK(CNode::IsBanned(addr1.ip));
+ BOOST_CHECK(CNode::IsBanned(addr1));
mapArgs["-banscore"] = "100";
}
@@ -53,20 +60,20 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
int64 nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
- CAddress addr(0xa0b0c001);
+ CAddress addr(ip(0xa0b0c001));
CNode dummyNode(INVALID_SOCKET, addr, true);
dummyNode.Misbehaving(100);
- BOOST_CHECK(CNode::IsBanned(addr.ip));
+ BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60);
- BOOST_CHECK(CNode::IsBanned(addr.ip));
+ BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1);
- BOOST_CHECK(!CNode::IsBanned(addr.ip));
-}
+ BOOST_CHECK(!CNode::IsBanned(addr));
+}
-static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)
+static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
{
if (time1 > time2)
return CheckNBits(nbits2, time2, nbits1, time1);
diff --git a/src/uint256.h b/src/uint256.h
index d3da1f26d2..0d27408575 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -623,7 +623,7 @@ inline const uint256 operator-(const uint256& a, const uint256& b) { return
-
+#ifdef TEST_UINT256
inline int Testuint256AdHoc(std::vector<std::string> vArg)
{
@@ -756,3 +756,5 @@ inline int Testuint256AdHoc(std::vector<std::string> vArg)
}
#endif
+
+#endif
diff --git a/src/util.cpp b/src/util.cpp
index 3805e077a1..ac7bacb7f5 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -948,12 +948,12 @@ int64 GetAdjustedTime()
return GetTime() + nTimeOffset;
}
-void AddTimeData(unsigned int ip, int64 nTime)
+void AddTimeData(const CNetAddr& ip, int64 nTime)
{
int64 nOffsetSample = nTime - GetTime();
// Ignore duplicates
- static set<unsigned int> setKnown;
+ static set<CNetAddr> setKnown;
if (!setKnown.insert(ip).second)
return;
@@ -1008,7 +1008,6 @@ void AddTimeData(unsigned int ip, int64 nTime)
-
string FormatVersion(int nVersion)
{
if (nVersion%100 == 0)
@@ -1178,3 +1177,4 @@ bool CCriticalSection::TryEnter(const char*, const char*, int)
}
#endif /* DEBUG_LOCKORDER */
+
diff --git a/src/util.h b/src/util.h
index 48fea023bf..1c24ed71e9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -24,6 +24,7 @@
#include <openssl/sha.h>
#include <openssl/ripemd.h>
+#include "netbase.h"
typedef long long int64;
typedef unsigned long long uint64;
@@ -79,20 +80,7 @@ T* alignup(T* p)
#define S_IWUSR 0200
#endif
#define unlink _unlink
-typedef int socklen_t;
#else
-#define WSAGetLastError() errno
-#define WSAEINVAL EINVAL
-#define WSAEALREADY EALREADY
-#define WSAEWOULDBLOCK EWOULDBLOCK
-#define WSAEMSGSIZE EMSGSIZE
-#define WSAEINTR EINTR
-#define WSAEINPROGRESS EINPROGRESS
-#define WSAEADDRINUSE EADDRINUSE
-#define WSAENOTSOCK EBADF
-#define INVALID_SOCKET (SOCKET)(~0)
-#define SOCKET_ERROR -1
-typedef u_int SOCKET;
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#define strlwr(psz) to_lower(psz)
#define _strlwr(psz) to_lower(psz)
@@ -104,19 +92,6 @@ inline void Sleep(int64 n)
}
#endif
-inline int myclosesocket(SOCKET& hSocket)
-{
- if (hSocket == INVALID_SOCKET)
- return WSAENOTSOCK;
-#ifdef WIN32
- int ret = closesocket(hSocket);
-#else
- int ret = close(hSocket);
-#endif
- hSocket = INVALID_SOCKET;
- return ret;
-}
-#define closesocket(s) myclosesocket(s)
#if !defined(QT_GUI)
inline const char* _(const char* psz)
{
@@ -187,9 +162,9 @@ uint64 GetRand(uint64 nMax);
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
-void AddTimeData(unsigned int ip, int64 nTime);
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
+void AddTimeData(const CNetAddr& ip, int64 nTime);
@@ -745,3 +720,4 @@ inline uint32_t ByteReverse(uint32_t value)
}
#endif
+