Browse Source

Merge pull request #735 from sipa/netbase

Network stack refactor
0.8
Pieter Wuille 13 years ago
parent
commit
1684f98b27
  1. 2
      bitcoin-qt.pro
  2. 42
      src/compat.h
  3. 2
      src/headers.h
  4. 2
      src/init.cpp
  5. 33
      src/irc.cpp
  6. 13
      src/main.cpp
  7. 2
      src/makefile.linux-mingw
  8. 2
      src/makefile.mingw
  9. 2
      src/makefile.osx
  10. 2
      src/makefile.unix
  11. 308
      src/net.cpp
  12. 20
      src/net.h
  13. 715
      src/netbase.cpp
  14. 138
      src/netbase.h
  15. 172
      src/protocol.cpp
  16. 39
      src/protocol.h
  17. 6
      src/qt/optionsmodel.cpp
  18. 41
      src/test/DoS_tests.cpp
  19. 4
      src/uint256.h
  20. 6
      src/util.cpp
  21. 30
      src/util.h

2
bitcoin-qt.pro

@ -97,6 +97,7 @@ HEADERS += src/qt/bitcoingui.h \
src/base58.h \ src/base58.h \
src/bignum.h \ src/bignum.h \
src/checkpoints.h \ src/checkpoints.h \
src/compat.h \
src/util.h \ src/util.h \
src/uint256.h \ src/uint256.h \
src/serialize.h \ src/serialize.h \
@ -156,6 +157,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/editaddressdialog.cpp \ src/qt/editaddressdialog.cpp \
src/qt/bitcoinaddressvalidator.cpp \ src/qt/bitcoinaddressvalidator.cpp \
src/util.cpp \ src/util.cpp \
src/netbase.cpp \
src/key.cpp \ src/key.cpp \
src/script.cpp \ src/script.cpp \
src/main.cpp \ src/main.cpp \

42
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

2
src/headers.h

@ -12,7 +12,7 @@
#ifdef _WIN32_WINNT #ifdef _WIN32_WINNT
#undef _WIN32_WINNT #undef _WIN32_WINNT
#endif #endif
#define _WIN32_WINNT 0x0500 #define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE #ifdef _WIN32_IE
#undef _WIN32_IE #undef _WIN32_IE
#endif #endif

2
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) if (fTor)
{ {
// Use SoftSetArg here so user can override any of these if they wish. // Use SoftSetArg here so user can override any of these if they wish.

33
src/irc.cpp

@ -22,22 +22,25 @@ void ThreadIRCSeed2(void* parg);
#pragma pack(push, 1) #pragma pack(push, 1)
struct ircaddr struct ircaddr
{ {
int ip; struct in_addr ip;
short port; short port;
}; };
#pragma pack(pop) #pragma pack(pop)
string EncodeAddress(const CAddress& addr) string EncodeAddress(const CService& addr)
{ {
struct ircaddr tmp; struct ircaddr tmp;
tmp.ip = addr.ip; if (addr.GetInAddr(&tmp.ip))
tmp.port = addr.port; {
tmp.port = htons(addr.GetPort());
vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp)); vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
return string("u") + EncodeBase58Check(vch); return string("u") + EncodeBase58Check(vch);
} }
return "";
}
bool DecodeAddress(string str, CAddress& addr) bool DecodeAddress(string str, CService& addr)
{ {
vector<unsigned char> vch; vector<unsigned char> vch;
if (!DecodeBase58Check(str.substr(1), vch)) if (!DecodeBase58Check(str.substr(1), vch))
@ -48,7 +51,7 @@ bool DecodeAddress(string str, CAddress& addr)
return false; return false;
memcpy(&tmp, &vch[0], sizeof(tmp)); memcpy(&tmp, &vch[0], sizeof(tmp));
addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK); addr = CService(tmp.ip, ntohs(tmp.port));
return true; 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()); 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()); printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
if (fUseProxy) if (fUseProxy)
return false; return false;
CAddress addr(strHost, 0, true); CNetAddr addr(strHost, true);
if (!addr.IsValid()) if (!addr.IsValid())
return false; return false;
ipRet = addr.ip; ipRet = addr;
return true; return true;
} }
@ -267,9 +270,9 @@ void ThreadIRCSeed2(void* parg)
while (!fShutdown) 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()) if (addrIRC.IsValid())
addrConnect = addrIRC; addrConnect = addrIRC;
@ -325,15 +328,15 @@ void ThreadIRCSeed2(void* parg)
Sleep(500); Sleep(500);
// Get our external IP from the IRC server and re-nick before joining the channel // Get our external IP from the IRC server and re-nick before joining the channel
CAddress addrFromIRC; CNetAddr addrFromIRC;
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip)) 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()) if (!fUseProxy && addrFromIRC.IsRoutable())
{ {
// IRC lets you to re-nick // IRC lets you to re-nick
fGotExternalIP = true; fGotExternalIP = true;
addrLocalHost.ip = addrFromIRC.ip; addrLocalHost.SetIP(addrFromIRC);
strMyName = EncodeAddress(addrLocalHost); strMyName = EncodeAddress(addrLocalHost);
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
} }

13
src/main.cpp

@ -1931,7 +1931,7 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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(); RandAddSeedPerfmon();
if (fDebug) { if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); 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); pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
AddTimeData(pfrom->addr.ip, nTime); AddTimeData(pfrom->addr, nTime);
// Change version // Change version
if (pfrom->nVersion >= 209) if (pfrom->nVersion >= 209)
@ -2093,7 +2093,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
static uint256 hashSalt; static uint256 hashSalt;
if (hashSalt == 0) if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt)); 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)); hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix; multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes) 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 /// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it // Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip)) if (!mapReuseKey.count(pfrom->addr))
pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true); pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
// Send back approval of order and pubkey to use // Send back approval of order and pubkey to use
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG; scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
} }

2
src/makefile.linux-mingw

@ -33,6 +33,7 @@ HEADERS = \
base58.h \ base58.h \
bignum.h \ bignum.h \
checkpoints.h \ checkpoints.h \
compat.h \
crypter.h \ crypter.h \
db.h \ db.h \
headers.h \ headers.h \
@ -63,6 +64,7 @@ LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l w
OBJS= \ OBJS= \
obj/checkpoints.o \ obj/checkpoints.o \
obj/netbase.o \
obj/crypter.o \ obj/crypter.o \
obj/key.o \ obj/key.o \
obj/db.o \ obj/db.o \

2
src/makefile.mingw

@ -30,6 +30,7 @@ HEADERS = \
base58.h \ base58.h \
bignum.h \ bignum.h \
checkpoints.h \ checkpoints.h \
compat.h \
crypter.h \ crypter.h \
db.h \ db.h \
headers.h \ headers.h \
@ -60,6 +61,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell
OBJS= \ OBJS= \
obj/checkpoints.o \ obj/checkpoints.o \
obj/netbase.o \
obj/crypter.o \ obj/crypter.o \
obj/key.o \ obj/key.o \
obj/db.o \ obj/db.o \

2
src/makefile.osx vendored

@ -51,6 +51,7 @@ HEADERS = \
base58.h \ base58.h \
bignum.h \ bignum.h \
checkpoints.h \ checkpoints.h \
compat.h \
crypter.h \ crypter.h \
db.h \ db.h \
headers.h \ headers.h \
@ -72,6 +73,7 @@ HEADERS = \
OBJS= \ OBJS= \
obj/checkpoints.o \ obj/checkpoints.o \
obj/netbase.o \
obj/crypter.o \ obj/crypter.o \
obj/key.o \ obj/key.o \
obj/db.o \ obj/db.o \

2
src/makefile.unix

@ -88,6 +88,7 @@ HEADERS = \
base58.h \ base58.h \
bignum.h \ bignum.h \
checkpoints.h \ checkpoints.h \
compat.h \
crypter.h \ crypter.h \
db.h \ db.h \
headers.h \ headers.h \
@ -109,6 +110,7 @@ HEADERS = \
OBJS= \ OBJS= \
obj/checkpoints.o \ obj/checkpoints.o \
obj/netbase.o \
obj/crypter.o \ obj/crypter.o \
obj/key.o \ obj/key.o \
obj/db.o \ obj/db.o \

308
src/net.cpp

@ -45,7 +45,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
bool fClient = false; bool fClient = false;
bool fAllowDNS = false; bool fAllowDNS = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); 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; static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0; uint64 nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning; array<int, 10> vnThreadsRunning;
@ -60,10 +60,6 @@ deque<pair<int64, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay; CCriticalSection cs_mapRelay;
map<CInv, int64> mapAlreadyAskedFor; 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) bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
{
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)
{ {
SOCKET hSocket; SOCKET hSocket;
if (!ConnectSocket(addrConnect, 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")); strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
strLine.resize(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()); 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; return false;
ipRet = addr.ip; ipRet.SetIP(addr);
return true; 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 // 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; CAddress addrConnect;
const char* pszGet; const char* pszGet;
@ -363,7 +153,7 @@ bool GetMyExternalIP(unsigned int& ipRet)
if (nLookup == 1) if (nLookup == 1)
{ {
CAddress addrIP("checkip.dyndns.org", 80, true); CService addrIP("checkip.dyndns.org", 80, true);
if (addrIP.IsValid()) if (addrIP.IsValid())
addrConnect = addrIP; addrConnect = addrIP;
} }
@ -382,7 +172,7 @@ bool GetMyExternalIP(unsigned int& ipRet)
if (nLookup == 1) if (nLookup == 1)
{ {
CAddress addrIP("www.showmyip.com", 80, true); CService addrIP("www.showmyip.com", 80, true);
if (addrIP.IsValid()) if (addrIP.IsValid())
addrConnect = addrIP; addrConnect = addrIP;
} }
@ -417,7 +207,7 @@ void ThreadGetMyExternalIP(void* parg)
} }
// Fallback in case IRC fails to get it // Fallback in case IRC fails to get it
if (GetMyExternalIP(addrLocalHost.ip)) if (GetMyExternalIP(addrLocalHost))
{ {
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
if (addrLocalHost.IsRoutable()) if (addrLocalHost.IsRoutable())
@ -441,7 +231,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
{ {
if (!addr.IsRoutable()) if (!addr.IsRoutable())
return false; return false;
if (addr.ip == addrLocalHost.ip) if ((CService)addr == (CService)addrLocalHost)
return false; return false;
addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty); addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
bool fUpdated = false; bool fUpdated = false;
@ -494,7 +284,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
return fNew; return fNew;
} }
void AddressCurrentlyConnected(const CAddress& addr) void AddressCurrentlyConnected(const CService& addr)
{ {
CAddress *paddrFound = NULL; 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) CRITICAL_BLOCK(cs_vNodes)
{ {
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr.ip == ip) if ((CNetAddr)pnode->addr == ip)
return (pnode); return (pnode);
} }
return NULL; return NULL;
} }
CNode* FindNode(CAddress addr) CNode* FindNode(const CService& addr)
{ {
CRITICAL_BLOCK(cs_vNodes) CRITICAL_BLOCK(cs_vNodes)
{ {
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr == addr) if ((CService)pnode->addr == addr)
return (pnode); return (pnode);
} }
return NULL; return NULL;
@ -648,11 +438,11 @@ CNode* FindNode(CAddress addr)
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
{ {
if (addrConnect.ip == addrLocalHost.ip) if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
return NULL; return NULL;
// Look for an existing connection // Look for an existing connection
CNode* pnode = FindNode(addrConnect.ip); CNode* pnode = FindNode((CService)addrConnect);
if (pnode) if (pnode)
{ {
if (nTimeout != 0) 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; CCriticalSection CNode::cs_setBanned;
void CNode::ClearBanned() void CNode::ClearBanned()
@ -754,12 +544,12 @@ void CNode::ClearBanned()
setBanned.clear(); setBanned.clear();
} }
bool CNode::IsBanned(unsigned int ip) bool CNode::IsBanned(CNetAddr ip)
{ {
bool fResult = false; bool fResult = false;
CRITICAL_BLOCK(cs_setBanned) 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()) if (i != setBanned.end())
{ {
int64 t = (*i).second; 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 int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
CRITICAL_BLOCK(cs_setBanned) CRITICAL_BLOCK(cs_setBanned)
if (setBanned[addr.ip] < banTime) if (setBanned[addr] < banTime)
setBanned[addr.ip] = banTime; setBanned[addr] = banTime;
CloseSocketDisconnect(); CloseSocketDisconnect();
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
return true; return true;
@ -962,7 +752,7 @@ void ThreadSocketHandler2(void* parg)
{ {
closesocket(hSocket); closesocket(hSocket);
} }
else if (CNode::IsBanned(addr.ip)) else if (CNode::IsBanned(addr))
{ {
printf("connetion from %s dropped (banned)\n", addr.ToString().c_str()); printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
closesocket(hSocket); closesocket(hSocket);
@ -1277,15 +1067,16 @@ void ThreadDNSAddressSeed2(void* parg)
printf("Loading addresses from DNS seeds (could take a while)\n"); printf("Loading addresses from DNS seeds (could take a while)\n");
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CAddress> vaddr; vector<CNetAddr> vaddr;
if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true)) if (LookupHost(strDNSSeed[seed_idx], vaddr))
{ {
CAddrDB addrDB; CAddrDB addrDB;
addrDB.TxnBegin(); 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; addr.nTime = 0;
AddAddress(addr, 0, &addrDB); AddAddress(addr, 0, &addrDB);
found++; found++;
@ -1470,8 +1261,8 @@ void ThreadOpenConnections2(void* parg)
CRITICAL_BLOCK(cs_mapAddresses) CRITICAL_BLOCK(cs_mapAddresses)
{ {
// Add seed nodes if IRC isn't working // Add seed nodes if IRC isn't working
bool fTOR = (fUseProxy && addrProxy.port == htons(9050)); bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
if (mapAddresses.empty() && (GetTime() - nStart > 60 || fUseProxy) && !fTestNet) if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
fAddSeeds = true; fAddSeeds = true;
} }
@ -1484,8 +1275,9 @@ void ThreadOpenConnections2(void* parg)
// Seed nodes are given a random 'last seen time' of between one and two // Seed nodes are given a random 'last seen time' of between one and two
// weeks ago. // weeks ago.
const int64 nOneWeek = 7*24*60*60; const int64 nOneWeek = 7*24*60*60;
CAddress addr; struct in_addr ip;
addr.ip = pnSeed[i]; memcpy(&ip, &pnSeed[i], sizeof(ip));
CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
AddAddress(addr); AddAddress(addr);
} }
@ -1499,10 +1291,10 @@ void ThreadOpenConnections2(void* parg)
// Only connect to one address per a.b.?.? range. // Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect. // 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) CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff); setConnected.insert(pnode->addr.GetGroup());
int64 nANow = GetAdjustedTime(); int64 nANow = GetAdjustedTime();
@ -1511,14 +1303,14 @@ void ThreadOpenConnections2(void* parg)
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses) BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{ {
const CAddress& addr = item.second; 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; continue;
int64 nSinceLastSeen = nANow - addr.nTime; int64 nSinceLastSeen = nANow - addr.nTime;
int64 nSinceLastTry = nANow - addr.nLastTry; int64 nSinceLastTry = nANow - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first // 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); int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.GetHash()) % (2 * 60 * 60);
if (addr.port != htons(GetDefaultPort())) if (addr.GetPort() != GetDefaultPort())
nRandomizer += 2 * 60 * 60; nRandomizer += 2 * 60 * 60;
// Last seen Base retry frequency // Last seen Base retry frequency
@ -1573,8 +1365,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect)
// //
if (fShutdown) if (fShutdown)
return false; return false;
if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip)) FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
return false; return false;
vnThreadsRunning[1]--; vnThreadsRunning[1]--;
@ -1676,7 +1468,7 @@ bool BindListenPort(string& strError)
{ {
strError = ""; strError = "";
int nOne = 1; int nOne = 1;
addrLocalHost.port = htons(GetListenPort()); addrLocalHost.SetPort(GetListenPort());
#ifdef WIN32 #ifdef WIN32
// Initialize Windows Sockets // Initialize Windows Sockets
@ -1755,19 +1547,19 @@ bool BindListenPort(string& strError)
void StartNode(void* parg) void StartNode(void* parg)
{ {
if (pnodeLocalHost == NULL) 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 #ifdef WIN32
// Get local host ip // Get local host ip
char pszHostName[1000] = ""; char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{ {
vector<CAddress> vaddr; vector<CNetAddr> vaddr;
if (Lookup(pszHostName, vaddr, nLocalServices, -1, true)) if (LookupHost(pszHostName, vaddr))
BOOST_FOREACH (const CAddress &addr, vaddr) BOOST_FOREACH (const CNetAddr &addr, vaddr)
if (addr.GetByte(3) != 127) if (!addr.IsLocal())
{ {
addrLocalHost = addr; addrLocalHost.SetIP(addr);
break; break;
} }
} }
@ -1790,8 +1582,8 @@ void StartNode(void* parg)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x // Take the first IP that isn't loopback 127.x.x.x
CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices); CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127) if (addr.IsValid() && !addr.IsLocal())
{ {
addrLocalHost = addr; addrLocalHost = addr;
break; break;
@ -1812,7 +1604,7 @@ void StartNode(void* parg)
if (fUseProxy || mapArgs.count("-connect") || fNoListen) if (fUseProxy || mapArgs.count("-connect") || fNoListen)
{ {
// Proxies can't take incoming connections // 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()); printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
} }
else else

20
src/net.h

@ -14,6 +14,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "netbase.h"
#include "protocol.h" #include "protocol.h"
class CAddrDB; class CAddrDB;
@ -21,7 +22,6 @@ class CRequestTracker;
class CNode; class CNode;
class CBlockIndex; class CBlockIndex;
extern int nBestHeight; 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); } inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
static const unsigned int PUBLISH_HOPS = 5; static const unsigned int PUBLISH_HOPS = 5;
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout); bool GetMyExternalIP(CNetAddr& ipRet);
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 AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL); bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
void AddressCurrentlyConnected(const CAddress& addr); void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(unsigned int ip); CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
bool AnySubscribed(unsigned int nChannel); bool AnySubscribed(unsigned int nChannel);
@ -88,9 +86,6 @@ extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay; extern CCriticalSection cs_mapRelay;
extern std::map<CInv, int64> mapAlreadyAskedFor; extern std::map<CInv, int64> mapAlreadyAskedFor;
// Settings
extern int fUseProxy;
extern CAddress addrProxy;
@ -126,7 +121,7 @@ protected:
// Denial-of-service detection/prevention // Denial-of-service detection/prevention
// Key is ip address, value is banned-until-time // 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; static CCriticalSection cs_setBanned;
int nMisbehavior; int nMisbehavior;
@ -355,7 +350,6 @@ public:
void PushVersion(); void PushVersion();
@ -581,7 +575,7 @@ public:
// between nodes running old code and nodes running // between nodes running old code and nodes running
// new code. // new code.
static void ClearBanned(); // needed for unit testing 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 bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
}; };

715
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;
}

138
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

172
src/protocol.cpp

@ -5,16 +5,12 @@
#include "protocol.h" #include "protocol.h"
#include "util.h" #include "util.h"
#include "netbase.h"
#ifndef WIN32 #ifndef WIN32
# include <arpa/inet.h> # include <arpa/inet.h>
#endif #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[] = static const char* ppszTypeName[] =
{ {
"ERROR", "ERROR",
@ -77,185 +73,26 @@ bool CMessageHeader::IsValid() const
return true; 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(); 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(); Init();
Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true); nServices = nServicesIn;
} }
void CAddress::Init() void CAddress::Init()
{ {
nServices = NODE_NETWORK; nServices = NODE_NETWORK;
memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
ip = INADDR_NONE;
port = htons(GetDefaultPort());
nTime = 100000000; nTime = 100000000;
nLastTry = 0; 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() CInv::CInv()
{ {
type = 0; type = 0;
@ -310,3 +147,4 @@ void CInv::print() const
{ {
printf("CInv(%s)\n", ToString().c_str()); printf("CInv(%s)\n", ToString().c_str());
} }

39
src/protocol.h

@ -11,6 +11,8 @@
#define __INCLUDED_PROTOCOL_H__ #define __INCLUDED_PROTOCOL_H__
#include "serialize.h" #include "serialize.h"
#include "netbase.h"
#include "util.h"
#include <string> #include <string>
#include "uint256.h" #include "uint256.h"
@ -61,58 +63,33 @@ enum
NODE_NETWORK = (1 << 0), NODE_NETWORK = (1 << 0),
}; };
class CAddress class CAddress : public CService
{ {
public: public:
CAddress(); CAddress();
CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK); CAddress(CService ipIn, 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);
void Init(); void Init();
IMPLEMENT_SERIALIZE IMPLEMENT_SERIALIZE
( (
CAddress* pthis = const_cast<CAddress*>(this);
CService* pip = (CService*)pthis;
if (fRead) if (fRead)
const_cast<CAddress*>(this)->Init(); pthis->Init();
if (nType & SER_DISK) if (nType & SER_DISK)
READWRITE(nVersion); READWRITE(nVersion);
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
READWRITE(nTime); READWRITE(nTime);
READWRITE(nServices); READWRITE(nServices);
READWRITE(FLATDATA(pchReserved)); // for IPv6 READWRITE(*pip);
READWRITE(ip);
READWRITE(port);
) )
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; void print() const;
// TODO: make private (improves encapsulation) // TODO: make private (improves encapsulation)
public: public:
uint64 nServices; uint64 nServices;
unsigned char pchReserved[12];
unsigned int ip;
unsigned short port;
// disk and network only // disk and network only
unsigned int nTime; unsigned int nTime;

6
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 // Use CAddress to parse and check IP
CAddress addr(value.toString().toStdString() + ":1"); 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); walletdb.WriteSetting("addrProxy", addrProxy);
} }
else else
@ -104,7 +104,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
int nPort = atoi(value.toString().toAscii().data()); int nPort = atoi(value.toString().toAscii().data());
if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max()) if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
{ {
addrProxy.port = htons(nPort); addrProxy.SetPort(nPort);
walletdb.WriteSetting("addrProxy", addrProxy); walletdb.WriteSetting("addrProxy", addrProxy);
} }
else else

41
src/test/DoS_tests.cpp

@ -10,40 +10,47 @@
#include "net.h" #include "net.h"
#include "util.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_SUITE(DoS_tests)
BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_AUTO_TEST_CASE(DoS_banning)
{ {
CNode::ClearBanned(); CNode::ClearBanned();
CAddress addr1(0xa0b0c001); CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true); CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100); // Should get banned dummyNode1.Misbehaving(100); // Should get banned
BOOST_CHECK(CNode::IsBanned(addr1.ip)); BOOST_CHECK(CNode::IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(addr1.ip|0x0000ff00)); // Different ip, not banned BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned
CAddress addr2(0xa0b0c002); CAddress addr2(ip(0xa0b0c002));
CNode dummyNode2(INVALID_SOCKET, addr2, true); CNode dummyNode2(INVALID_SOCKET, addr2, true);
dummyNode2.Misbehaving(50); dummyNode2.Misbehaving(50);
BOOST_CHECK(!CNode::IsBanned(addr2.ip)); // 2 not banned yet... BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1.ip)); // ... but 1 still should be BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
dummyNode2.Misbehaving(50); dummyNode2.Misbehaving(50);
BOOST_CHECK(CNode::IsBanned(addr2.ip)); BOOST_CHECK(CNode::IsBanned(addr2));
} }
BOOST_AUTO_TEST_CASE(DoS_banscore) BOOST_AUTO_TEST_CASE(DoS_banscore)
{ {
CNode::ClearBanned(); CNode::ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(0xa0b0c001); CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true); CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100); dummyNode1.Misbehaving(100);
BOOST_CHECK(!CNode::IsBanned(addr1.ip)); BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(10); dummyNode1.Misbehaving(10);
BOOST_CHECK(!CNode::IsBanned(addr1.ip)); BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(1); dummyNode1.Misbehaving(1);
BOOST_CHECK(CNode::IsBanned(addr1.ip)); BOOST_CHECK(CNode::IsBanned(addr1));
mapArgs["-banscore"] = "100"; mapArgs["-banscore"] = "100";
} }
@ -53,20 +60,20 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
int64 nStartTime = GetTime(); int64 nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime() SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(0xa0b0c001); CAddress addr(ip(0xa0b0c001));
CNode dummyNode(INVALID_SOCKET, addr, true); CNode dummyNode(INVALID_SOCKET, addr, true);
dummyNode.Misbehaving(100); dummyNode.Misbehaving(100);
BOOST_CHECK(CNode::IsBanned(addr.ip)); BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60); SetMockTime(nStartTime+60*60);
BOOST_CHECK(CNode::IsBanned(addr.ip)); BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1); 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) if (time1 > time2)
return CheckNBits(nbits2, time2, nbits1, time1); return CheckNBits(nbits2, time2, nbits1, time1);

4
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) inline int Testuint256AdHoc(std::vector<std::string> vArg)
{ {
@ -756,3 +756,5 @@ inline int Testuint256AdHoc(std::vector<std::string> vArg)
} }
#endif #endif
#endif

6
src/util.cpp

@ -948,12 +948,12 @@ int64 GetAdjustedTime()
return GetTime() + nTimeOffset; return GetTime() + nTimeOffset;
} }
void AddTimeData(unsigned int ip, int64 nTime) void AddTimeData(const CNetAddr& ip, int64 nTime)
{ {
int64 nOffsetSample = nTime - GetTime(); int64 nOffsetSample = nTime - GetTime();
// Ignore duplicates // Ignore duplicates
static set<unsigned int> setKnown; static set<CNetAddr> setKnown;
if (!setKnown.insert(ip).second) if (!setKnown.insert(ip).second)
return; return;
@ -1008,7 +1008,6 @@ void AddTimeData(unsigned int ip, int64 nTime)
string FormatVersion(int nVersion) string FormatVersion(int nVersion)
{ {
if (nVersion%100 == 0) if (nVersion%100 == 0)
@ -1178,3 +1177,4 @@ bool CCriticalSection::TryEnter(const char*, const char*, int)
} }
#endif /* DEBUG_LOCKORDER */ #endif /* DEBUG_LOCKORDER */

30
src/util.h

@ -24,6 +24,7 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/ripemd.h> #include <openssl/ripemd.h>
#include "netbase.h"
typedef long long int64; typedef long long int64;
typedef unsigned long long uint64; typedef unsigned long long uint64;
@ -79,20 +80,7 @@ T* alignup(T* p)
#define S_IWUSR 0200 #define S_IWUSR 0200
#endif #endif
#define unlink _unlink #define unlink _unlink
typedef int socklen_t;
#else #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 _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#define strlwr(psz) to_lower(psz) #define strlwr(psz) to_lower(psz)
#define _strlwr(psz) to_lower(psz) #define _strlwr(psz) to_lower(psz)
@ -104,19 +92,6 @@ inline void Sleep(int64 n)
} }
#endif #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) #if !defined(QT_GUI)
inline const char* _(const char* psz) inline const char* _(const char* psz)
{ {
@ -187,9 +162,9 @@ uint64 GetRand(uint64 nMax);
int64 GetTime(); int64 GetTime();
void SetMockTime(int64 nMockTimeIn); void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime(); int64 GetAdjustedTime();
void AddTimeData(unsigned int ip, int64 nTime);
std::string FormatFullVersion(); std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments); 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 #endif

Loading…
Cancel
Save