Browse Source

Merge pull request #735 from sipa/netbase

Network stack refactor
pull/1/head
Pieter Wuille 11 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. 37
      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. 43
      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 \ @@ -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 \ @@ -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 \

42
src/compat.h

@ -0,0 +1,42 @@ @@ -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 @@ @@ -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

2
src/init.cpp

@ -470,7 +470,7 @@ bool AppInit2(int argc, char* argv[]) @@ -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.

37
src/irc.cpp

@ -22,22 +22,25 @@ void ThreadIRCSeed2(void* parg); @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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());
}

13
src/main.cpp

@ -1931,7 +1931,7 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; @@ -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) @@ -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) @@ -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) @@ -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);
}

2
src/makefile.linux-mingw

@ -33,6 +33,7 @@ HEADERS = \ @@ -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 @@ -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 \

2
src/makefile.mingw

@ -30,6 +30,7 @@ HEADERS = \ @@ -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 @@ -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 \

2
src/makefile.osx vendored

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

2
src/makefile.unix

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

308
src/net.cpp

@ -45,7 +45,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect); @@ -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; @@ -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) @@ -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 @@ -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 @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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() @@ -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() @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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

20
src/net.h

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
#include <arpa/inet.h>
#endif
#include "netbase.h"
#include "protocol.h"
class CAddrDB;
@ -21,7 +22,6 @@ class CRequestTracker; @@ -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" @@ -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; @@ -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: @@ -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: @@ -355,7 +350,6 @@ public:
void PushVersion();
@ -581,7 +575,7 @@ public: @@ -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
};

715
src/netbase.cpp

@ -0,0 +1,715 @@ @@ -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;