Merge pull request #1021 from sipa/ipv6

IPv6 node support
This commit is contained in:
Pieter Wuille 2012-05-11 18:23:56 -07:00
commit a3878873f3
14 changed files with 347 additions and 119 deletions

View file

@ -2,7 +2,7 @@ TEMPLATE = app
TARGET = TARGET =
VERSION = 0.6.99 VERSION = 0.6.99
INCLUDEPATH += src src/json src/qt INCLUDEPATH += src src/json src/qt
DEFINES += QT_GUI BOOST_THREAD_USE_LIB DEFINES += QT_GUI BOOST_THREAD_USE_LIB USE_IPV6
CONFIG += no_include_pwd CONFIG += no_include_pwd
# for boost 1.37, add -mt to the boost libraries # for boost 1.37, add -mt to the boost libraries

View file

@ -44,7 +44,7 @@ sudo port install qrencode
4. Now you should be able to build bitcoind: 4. Now you should be able to build bitcoind:
cd bitcoin/src cd bitcoin/src
make -f makefile.osx make -f makefile.osx USE_IPV6=1
Run: Run:
./bitcoind --help # for a list of command-line options. ./bitcoind --help # for a list of command-line options.

View file

@ -43,6 +43,9 @@ your package manager. Set USE_QRCODE to control this:
USE_QRCODE=0 (the default) No QRCode support - libarcode not required USE_QRCODE=0 (the default) No QRCode support - libarcode not required
USE_QRCODE=1 QRCode support enabled USE_QRCODE=1 QRCode support enabled
IPv6 support may be enabled by setting
USE_IPV6=1 Enable IPv6 support
Licenses of statically linked libraries: Licenses of statically linked libraries:
Berkeley DB New BSD license with additional requirement that linked Berkeley DB New BSD license with additional requirement that linked
software must be free open source software must be free open source
@ -80,7 +83,7 @@ emerge -av1 --noreplace boost glib openssl sys-libs/db:4.8
Take the following steps to build (no UPnP support): Take the following steps to build (no UPnP support):
cd ${BITCOIN_DIR}/src cd ${BITCOIN_DIR}/src
make -f makefile.unix USE_UPNP= BDB_INCLUDE_PATH='/usr/include/db4.8' make -f makefile.unix USE_UPNP= USE_IPV6=1 BDB_INCLUDE_PATH='/usr/include/db4.8'
strip bitcoind strip bitcoind

View file

@ -119,6 +119,18 @@ bool AppInit(int argc, char* argv[])
return fRet; return fRet;
} }
bool static Bind(const CService &addr) {
if (IsLimited(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError))
{
ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
return false;
}
return true;
}
bool AppInit2(int argc, char* argv[]) bool AppInit2(int argc, char* argv[])
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
@ -180,6 +192,7 @@ bool AppInit2(int argc, char* argv[])
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" + " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks proxy") + "\n" + " -proxy=<ip:port> \t " + _("Connect through socks proxy") + "\n" +
" -socks=<n> \t " + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" + " -socks=<n> \t " + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" +
" -noproxy=<net> \t " + _("Do not use proxy for connections to network net (ipv4 or ipv6)") + "\n" +
" -dns \t " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + " -dns \t " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
" -proxydns \t " + _("Pass DNS requests to (SOCKS5) proxy") + "\n" + " -proxydns \t " + _("Pass DNS requests to (SOCKS5) proxy") + "\n" +
" -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" + " -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
@ -188,9 +201,11 @@ bool AppInit2(int argc, char* argv[])
" -connect=<ip> \t\t " + _("Connect only to the specified node") + "\n" + " -connect=<ip> \t\t " + _("Connect only to the specified node") + "\n" +
" -seednode=<ip> \t\t " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + " -seednode=<ip> \t\t " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
" -externalip=<ip> \t " + _("Specify your own public address") + "\n" + " -externalip=<ip> \t " + _("Specify your own public address") + "\n" +
" -blocknet=<net> \t " + _("Do not connect to addresses in network net (ipv4, ipv6)") + "\n" +
" -discover \t " + _("Try to discover public IP address (default: 1)") + "\n" + " -discover \t " + _("Try to discover public IP address (default: 1)") + "\n" +
" -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" + " -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen \t " + _("Accept connections from outside (default: 1)") + "\n" + " -listen \t " + _("Accept connections from outside (default: 1)") + "\n" +
" -bind=<addr> \t " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
#ifdef QT_GUI #ifdef QT_GUI
" -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" + " -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
#endif #endif
@ -532,9 +547,25 @@ bool AppInit2(int argc, char* argv[])
} }
} }
if (mapArgs.count("-noproxy"))
{
BOOST_FOREACH(std::string snet, mapMultiArgs["-noproxy"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE) {
ThreadSafeMessageBox(_("Unknown network specified in -noproxy"), _("Bitcoin"), wxOK | wxMODAL);
return false;
}
SetNoProxy(net);
}
}
if (mapArgs.count("-connect")) if (mapArgs.count("-connect"))
SoftSetBoolArg("-dnsseed", false); SoftSetBoolArg("-dnsseed", false);
// even in Tor mode, if -bind is specified, you really want -listen
if (mapArgs.count("-bind"))
SoftSetBoolArg("-listen", true);
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050); bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
if (fTor) if (fTor)
{ {
@ -547,6 +578,17 @@ bool AppInit2(int argc, char* argv[])
SoftSetBoolArg("-discover", false); SoftSetBoolArg("-discover", false);
} }
if (mapArgs.count("-blocknet")) {
BOOST_FOREACH(std::string snet, mapMultiArgs["-blocknet"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE) {
ThreadSafeMessageBox(_("Unknown network specified in -blocknet"), _("Bitcoin"), wxOK | wxMODAL);
return false;
}
SetLimited(net);
}
}
fNameLookup = GetBoolArg("-dns"); fNameLookup = GetBoolArg("-dns");
fProxyNameLookup = GetBoolArg("-proxydns"); fProxyNameLookup = GetBoolArg("-proxydns");
if (fProxyNameLookup) if (fProxyNameLookup)
@ -563,14 +605,23 @@ bool AppInit2(int argc, char* argv[])
const char* pszP2SH = "/P2SH/"; const char* pszP2SH = "/P2SH/";
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH)); COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
bool fBound = false;
if (!fNoListen) if (!fNoListen)
{ {
std::string strError; std::string strError;
if (!BindListenPort(strError)) if (mapArgs.count("-bind")) {
{ BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL); fBound |= Bind(CService(strBind, GetDefaultPort(), false));
return false; }
} else {
struct in_addr inaddr_any = {s_addr: INADDR_ANY};
fBound |= Bind(CService(inaddr_any, GetDefaultPort()));
#ifdef USE_IPV6
fBound |= Bind(CService(in6addr_any, GetDefaultPort()));
#endif
} }
if (!fBound)
return false;
} }
if (mapArgs.count("-externalip")) if (mapArgs.count("-externalip"))

View file

@ -246,7 +246,7 @@ void ThreadIRCSeed2(void* parg)
return; return;
} }
CNetAddr addrLocal; CService addrLocal;
string strMyName; string strMyName;
if (GetLocal(addrLocal, &addrConnect)) if (GetLocal(addrLocal, &addrConnect))
strMyName = EncodeAddress(GetLocalAddress(&addrConnect)); strMyName = EncodeAddress(GetLocalAddress(&addrConnect));

View file

@ -2419,18 +2419,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
} }
// Store the new addresses // Store the new addresses
vector<CAddress> vAddrOk;
int64 nNow = GetAdjustedTime(); int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60; int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr) BOOST_FOREACH(CAddress& addr, vAddr)
{ {
if (fShutdown) if (fShutdown)
return true; return true;
// ignore IPv6 for now, since it isn't implemented anyway
if (!addr.IsIPv4())
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60; addr.nTime = nNow - 5 * 24 * 60 * 60;
pfrom->AddAddressKnown(addr); pfrom->AddAddressKnown(addr);
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{ {
// Relay to a limited number of other nodes // Relay to a limited number of other nodes
@ -2455,13 +2454,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
hashKey = Hash(BEGIN(hashKey), END(hashKey)); hashKey = Hash(BEGIN(hashKey), END(hashKey));
mapMix.insert(make_pair(hashKey, pnode)); mapMix.insert(make_pair(hashKey, pnode));
} }
int nRelayNodes = 2; int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr); ((*mi).second)->PushAddress(addr);
} }
} }
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
} }
addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60); addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000) if (vAddr.size() < 1000)
pfrom->fGetAddr = false; pfrom->fGetAddr = false;
if (pfrom->fOneShot) if (pfrom->fOneShot)

View file

@ -27,7 +27,7 @@ LIBS= \
-l ssl \ -l ssl \
-l crypto -l crypto
DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
DEBUGFLAGS=-g DEBUGFLAGS=-g
CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)

View file

@ -23,7 +23,7 @@ LIBS= \
-l ssl \ -l ssl \
-l crypto -l crypto
DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
DEBUGFLAGS=-g DEBUGFLAGS=-g
CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)

View file

@ -53,7 +53,7 @@ LIBS += \
TESTDEFS += -DBOOST_TEST_DYN_LINK TESTDEFS += -DBOOST_TEST_DYN_LINK
endif endif
DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_IPV6
ifdef RELEASE ifdef RELEASE
# Compile for maximum compatibility and smallest size. # Compile for maximum compatibility and smallest size.

View file

@ -4,7 +4,7 @@
USE_UPNP:=0 USE_UPNP:=0
DEFS= DEFS=-DUSE_IPV6
DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))

View file

@ -45,12 +45,14 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
bool fClient = false; bool fClient = false;
static bool fUseUPnP = false; static bool fUseUPnP = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CCriticalSection cs_mapLocalHost; static CCriticalSection cs_mapLocalHost;
map<CNetAddr, int> mapLocalHost; static map<CService, int> mapLocalHost;
static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL; static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0; uint64 nLocalHostNonce = 0;
array<int, THREAD_MAX> vnThreadsRunning; array<int, THREAD_MAX> vnThreadsRunning;
static SOCKET hListenSocket = INVALID_SOCKET; static std::vector<SOCKET> vhListenSocket;
CAddrMan addrman; CAddrMan addrman;
vector<CNode*> vNodes; vector<CNode*> vNodes;
@ -91,7 +93,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
} }
// find 'best' local address for a particular peer // find 'best' local address for a particular peer
bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer) bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{ {
if (fUseProxy || mapArgs.count("-connect") || fNoListen) if (fUseProxy || mapArgs.count("-connect") || fNoListen)
return false; return false;
@ -100,7 +102,7 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
int nBestReachability = -1; int nBestReachability = -1;
{ {
LOCK(cs_mapLocalHost); LOCK(cs_mapLocalHost);
for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) for (map<CService, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
{ {
int nCount = (*it).second; int nCount = (*it).second;
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
@ -119,11 +121,10 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
CAddress GetLocalAddress(const CNetAddr *paddrPeer) CAddress GetLocalAddress(const CNetAddr *paddrPeer)
{ {
CAddress ret(CService("0.0.0.0",0),0); CAddress ret(CService("0.0.0.0",0),0);
CNetAddr addr; CService addr;
if (GetLocal(addr, paddrPeer)) if (GetLocal(addr, paddrPeer))
{ {
ret.SetIP(addr); ret = CAddress(addr);
ret.SetPort(GetListenPort());
ret.nServices = nLocalServices; ret.nServices = nLocalServices;
ret.nTime = GetAdjustedTime(); ret.nTime = GetAdjustedTime();
} }
@ -191,7 +192,7 @@ void static AdvertizeLocal()
if (pnode->fSuccessfullyConnected) if (pnode->fSuccessfullyConnected)
{ {
CAddress addrLocal = GetLocalAddress(&pnode->addr); CAddress addrLocal = GetLocalAddress(&pnode->addr);
if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal) if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal)
{ {
pnode->PushAddress(addrLocal); pnode->PushAddress(addrLocal);
pnode->addrLocal = addrLocal; pnode->addrLocal = addrLocal;
@ -201,7 +202,7 @@ void static AdvertizeLocal()
} }
// learn a new local address // learn a new local address
bool AddLocal(const CNetAddr& addr, int nScore) bool AddLocal(const CService& addr, int nScore)
{ {
if (!addr.IsRoutable()) if (!addr.IsRoutable())
return false; return false;
@ -211,6 +212,9 @@ bool AddLocal(const CNetAddr& addr, int nScore)
{ {
LOCK(cs_mapLocalHost); LOCK(cs_mapLocalHost);
mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0); mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0);
enum Network net = addr.GetNetwork();
vfReachable[net] = true;
if (net == NET_IPV6) vfReachable[NET_IPV4] = true;
} }
AdvertizeLocal(); AdvertizeLocal();
@ -218,8 +222,28 @@ bool AddLocal(const CNetAddr& addr, int nScore)
return true; return true;
} }
// vote for a local address bool AddLocal(const CNetAddr& addr, int nScore, int port)
bool SeenLocal(const CNetAddr& addr) {
if (port == -1)
port = GetListenPort();
return AddLocal(CService(addr, port), nScore);
}
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited(enum Network net, bool fLimited)
{
LOCK(cs_mapLocalHost);
vfLimited[net] = fLimited;
}
bool IsLimited(const CNetAddr& addr)
{
LOCK(cs_mapLocalHost);
return vfLimited[addr.GetNetwork()];
}
/** vote for a local address */
bool SeenLocal(const CService& addr)
{ {
{ {
LOCK(cs_mapLocalHost); LOCK(cs_mapLocalHost);
@ -233,13 +257,20 @@ bool SeenLocal(const CNetAddr& addr)
return true; return true;
} }
// check whether a given address is potentially local /** check whether a given address is potentially local */
bool IsLocal(const CNetAddr& addr) bool IsLocal(const CService& addr)
{ {
LOCK(cs_mapLocalHost); LOCK(cs_mapLocalHost);
return mapLocalHost.count(addr) > 0; return mapLocalHost.count(addr) > 0;
} }
/** check whether a given address is in a network we can probably connect to */
bool IsReachable(const CNetAddr& addr)
{
LOCK(cs_mapLocalHost);
enum Network net = addr.GetNetwork();
return vfReachable[net] && !vfLimited[net];
}
bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
{ {
@ -675,9 +706,10 @@ void ThreadSocketHandler2(void* parg)
FD_ZERO(&fdsetError); FD_ZERO(&fdsetError);
SOCKET hSocketMax = 0; SOCKET hSocketMax = 0;
if(hListenSocket != INVALID_SOCKET) BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
FD_SET(hListenSocket, &fdsetRecv); FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket); hSocketMax = max(hSocketMax, hListenSocket);
}
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
@ -718,16 +750,22 @@ void ThreadSocketHandler2(void* parg)
// //
// Accept new connections // Accept new connections
// //
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
{ {
struct sockaddr_in sockaddr; #ifdef USE_IPV6
struct sockaddr_storage sockaddr;
#else
struct sockaddr sockaddr;
#endif
socklen_t len = sizeof(sockaddr); socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
CAddress addr; CAddress addr;
int nInbound = 0; int nInbound = 0;
if (hSocket != INVALID_SOCKET) if (hSocket != INVALID_SOCKET)
addr = CAddress(sockaddr); if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
printf("warning: unknown socket family\n");
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
@ -1380,11 +1418,14 @@ void ThreadOpenConnections2(void* parg)
CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
// if we selected an invalid address, restart // if we selected an invalid address, restart
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
break; break;
nTries++; nTries++;
if (IsLimited(addr))
continue;
// only consider very recently tried nodes after 30 failed attempts // only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30) if (nANow - addr.nLastTry < 600 && nTries < 30)
continue; continue;
@ -1613,7 +1654,7 @@ void ThreadMessageHandler2(void* parg)
bool BindListenPort(string& strError) bool BindListenPort(const CService &addrBind, string& strError)
{ {
strError = ""; strError = "";
int nOne = 1; int nOne = 1;
@ -1631,7 +1672,20 @@ bool BindListenPort(string& strError)
#endif #endif
// Create socket for listening for incoming connections // Create socket for listening for incoming connections
hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #ifdef USE_IPV6
struct sockaddr_storage sockaddr;
#else
struct sockaddr sockaddr;
#endif
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
printf("%s\n", strError.c_str());
return false;
}
SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET) if (hListenSocket == INVALID_SOCKET)
{ {
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@ -1650,6 +1704,7 @@ bool BindListenPort(string& strError)
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif #endif
#ifdef WIN32 #ifdef WIN32
// Set to nonblocking, incoming connections will also inherit this // Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@ -1662,24 +1717,33 @@ bool BindListenPort(string& strError)
return false; return false;
} }
// The sockaddr_in structure specifies the address family, #ifdef USE_IPV6
// IP address, and port for the socket that is being bound // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
struct sockaddr_in sockaddr; // and enable it by default or not. Try to enable it, if possible.
memset(&sockaddr, 0, sizeof(sockaddr)); if (addrBind.IsIPv6()) {
sockaddr.sin_family = AF_INET; #ifdef IPV6_V6ONLY
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
sockaddr.sin_port = htons(GetListenPort()); #endif
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) #ifdef WIN32
int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
// this call is allowed to fail
setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
#endif
}
#endif
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{ {
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE) if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port)); strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str());
else else
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr); strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
printf("%s\n", strError.c_str()); printf("%s\n", strError.c_str());
return false; return false;
} }
printf("Bound to port %d\n", ntohs(sockaddr.sin_port)); printf("Bound to %s\n", addrBind.ToString().c_str());
// Listen for incoming connections // Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@ -1689,6 +1753,11 @@ bool BindListenPort(string& strError)
return false; return false;
} }
vhListenSocket.push_back(hListenSocket);
if (addrBind.IsRoutable() && GetBoolArg("-discover", true))
AddLocal(addrBind, LOCAL_BIND);
return true; return true;
} }
@ -1722,28 +1791,22 @@ void static Discover()
if ((ifa->ifa_flags & IFF_UP) == 0) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue;
if (strcmp(ifa->ifa_name, "lo") == 0) continue; if (strcmp(ifa->ifa_name, "lo") == 0) continue;
if (strcmp(ifa->ifa_name, "lo0") == 0) continue; if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
char pszIP[100];
if (ifa->ifa_addr->sa_family == AF_INET) if (ifa->ifa_addr->sa_family == AF_INET)
{ {
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x
CNetAddr addr(s4->sin_addr); CNetAddr addr(s4->sin_addr);
AddLocal(addr, LOCAL_IF); if (AddLocal(addr, LOCAL_IF))
printf("ipv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
} }
#ifdef USE_IPV6
else if (ifa->ifa_addr->sa_family == AF_INET6) else if (ifa->ifa_addr->sa_family == AF_INET6)
{ {
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
#ifdef USE_IPV6
CNetAddr addr(s6->sin6_addr); CNetAddr addr(s6->sin6_addr);
AddLocal(addr, LOCAL_IF); if (AddLocal(addr, LOCAL_IF))
#endif printf("ipv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
} }
#endif
} }
freeifaddrs(myaddrs); freeifaddrs(myaddrs);
} }
@ -1866,9 +1929,10 @@ public:
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET) if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket); closesocket(pnode->hSocket);
if (hListenSocket != INVALID_SOCKET) BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (closesocket(hListenSocket) == SOCKET_ERROR) if (hListenSocket != INVALID_SOCKET)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
#ifdef WIN32 #ifdef WIN32
// Shutdown Windows Sockets // Shutdown Windows Sockets

View file

@ -38,28 +38,34 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip); CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0); CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
void MapPort(bool fMapPort); void MapPort(bool fMapPort);
bool BindListenPort(std::string& strError=REF(std::string())); bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
void StartNode(void* parg); void StartNode(void* parg);
bool StopNode(); bool StopNode();
enum enum
{ {
LOCAL_NONE, LOCAL_NONE, // unknown
LOCAL_IF, LOCAL_IF, // address a local interface listens on
LOCAL_UPNP, LOCAL_BIND, // address explicit bound to
LOCAL_IRC, LOCAL_UPNP, // address reported by UPnP
LOCAL_HTTP, LOCAL_IRC, // address reported by IRC (deprecated)
LOCAL_MANUAL, LOCAL_HTTP, // address reported by whatismyip.com and similars
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX LOCAL_MAX
}; };
bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); void SetLimited(enum Network net, bool fLimited = true);
bool SeenLocal(const CNetAddr& addr); bool IsLimited(const CNetAddr& addr);
bool IsLocal(const CNetAddr& addr); bool AddLocal(const CService& addr, int nScore = LOCAL_NONE);
bool GetLocal(CNetAddr &addr, const CNetAddr *paddrPeer = NULL); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE, int port = -1);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(const CNetAddr &addr);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
enum enum
{ {
MSG_TX = 1, MSG_TX = 1,
@ -139,7 +145,7 @@ public:
unsigned int nMessageStart; unsigned int nMessageStart;
CAddress addr; CAddress addr;
std::string addrName; std::string addrName;
CNetAddr addrLocal; CService addrLocal;
int nVersion; int nVersion;
std::string strSubVer; std::string strSubVer;
bool fOneShot; bool fOneShot;

View file

@ -21,10 +21,24 @@ bool fProxyNameLookup = false;
bool fNameLookup = false; bool fNameLookup = false;
CService addrProxy("127.0.0.1",9050); CService addrProxy("127.0.0.1",9050);
int nConnectTimeout = 5000; int nConnectTimeout = 5000;
static bool vfNoProxy[NET_MAX] = {};
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
enum Network ParseNetwork(std::string net) {
if (net == "ipv4") return NET_IPV4;
if (net == "ipv6") return NET_IPV6;
if (net == "tor") return NET_TOR;
if (net == "i2p") return NET_I2P;
return NET_UNROUTABLE;
}
void SetNoProxy(enum Network net, bool fNoProxy) {
assert(net >= 0 && net < NET_MAX);
vfNoProxy[net] = fNoProxy;
}
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{ {
vIP.clear(); vIP.clear();
@ -169,7 +183,12 @@ bool static Socks4(const CService &addrDest, SOCKET& hSocket)
} }
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
struct sockaddr_in addr; struct sockaddr_in addr;
addrDest.GetSockAddr(&addr); socklen_t len = sizeof(addr);
if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
{
closesocket(hSocket);
return error("Cannot get proxy destination address");
}
memcpy(pszSocks4IP + 2, &addr.sin_port, 2); memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
memcpy(pszSocks4IP + 4, &addr.sin_addr, 4); memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
char* pszSocks4 = pszSocks4IP; char* pszSocks4 = pszSocks4IP;
@ -305,7 +324,18 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
{ {
hSocketRet = INVALID_SOCKET; hSocketRet = INVALID_SOCKET;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #ifdef USE_IPV6
struct sockaddr_storage sockaddr;
#else
struct sockaddr sockaddr;
#endif
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
return false;
}
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET) if (hSocket == INVALID_SOCKET)
return false; return false;
#ifdef SO_NOSIGPIPE #ifdef SO_NOSIGPIPE
@ -313,13 +343,6 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif #endif
struct sockaddr_in sockaddr;
if (!addrConnect.GetSockAddr(&sockaddr))
{
closesocket(hSocket);
return false;
}
#ifdef WIN32 #ifdef WIN32
u_long fNonblock = 1; u_long fNonblock = 1;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
@ -332,7 +355,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return false; return false;
} }
if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{ {
// WSAEINVAL is here because some legacy version of winsock uses it // WSAEINVAL is here because some legacy version of winsock uses it
if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
@ -409,7 +432,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{ {
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
bool fProxy = (fUseProxy && addrDest.IsRoutable()); bool fProxy = (fUseProxy && addrDest.IsRoutable() && !vfNoProxy[addrDest.GetNetwork()]);
if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout)) if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout))
return false; return false;
@ -531,6 +554,11 @@ bool CNetAddr::IsIPv4() const
return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
} }
bool CNetAddr::IsIPv6() const
{
return (!IsIPv4());
}
bool CNetAddr::IsRFC1918() const bool CNetAddr::IsRFC1918() const
{ {
return IsIPv4() && ( return IsIPv4() && (
@ -587,6 +615,18 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
} }
bool CNetAddr::IsOnionCat() const
{
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
}
bool CNetAddr::IsGarliCat() const
{
static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
}
bool CNetAddr::IsLocal() const bool CNetAddr::IsLocal() const
{ {
// IPv4 loopback // IPv4 loopback
@ -645,7 +685,24 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const bool CNetAddr::IsRoutable() const
{ {
return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || IsRFC4193() || IsRFC4843() || IsLocal()); return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal());
}
enum Network CNetAddr::GetNetwork() const
{
if (!IsRoutable())
return NET_UNROUTABLE;
if (IsIPv4())
return NET_IPV4;
if (IsOnionCat())
return NET_TOR;
if (IsGarliCat())
return NET_I2P;
return NET_IPV6;
} }
std::string CNetAddr::ToStringIP() const std::string CNetAddr::ToStringIP() const
@ -701,40 +758,40 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
std::vector<unsigned char> CNetAddr::GetGroup() const std::vector<unsigned char> CNetAddr::GetGroup() const
{ {
std::vector<unsigned char> vchRet; std::vector<unsigned char> vchRet;
int nClass = 0; // 0=IPv6, 1=IPv4, 254=local, 255=unroutable int nClass = NET_IPV6;
int nStartByte = 0; int nStartByte = 0;
int nBits = 16; int nBits = 16;
// all local addresses belong to the same group // all local addresses belong to the same group
if (IsLocal()) if (IsLocal())
{ {
nClass = 254; nClass = 255;
nBits = 0; nBits = 0;
} }
// all unroutable addresses belong to the same group // all unroutable addresses belong to the same group
if (!IsRoutable()) if (!IsRoutable())
{ {
nClass = 255; nClass = NET_UNROUTABLE;
nBits = 0; nBits = 0;
} }
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
// includes mapped IPv4, SIIT translated IPv4, and the well-known prefix // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
else if (IsIPv4() || IsRFC6145() || IsRFC6052()) else if (IsIPv4() || IsRFC6145() || IsRFC6052())
{ {
nClass = 1; nClass = NET_IPV4;
nStartByte = 12; nStartByte = 12;
} }
// for 6to4 tunneled addresses, use the encapsulated IPv4 address // for 6to4 tunneled addresses, use the encapsulated IPv4 address
else if (IsRFC3964()) else if (IsRFC3964())
{ {
nClass = 1; nClass = NET_IPV4;
nStartByte = 2; nStartByte = 2;
} }
// for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address
else if (IsRFC4380()) else if (IsRFC4380())
{ {
vchRet.push_back(1); vchRet.push_back(NET_IPV4);
vchRet.push_back(GetByte(3) ^ 0xFF); vchRet.push_back(GetByte(3) ^ 0xFF);
vchRet.push_back(GetByte(2) ^ 0xFF); vchRet.push_back(GetByte(2) ^ 0xFF);
return vchRet; return vchRet;
@ -831,6 +888,22 @@ CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr),
} }
#endif #endif
bool CService::SetSockAddr(const struct sockaddr *paddr)
{
switch (paddr->sa_family) {
case AF_INET:
*this = CService(*(const struct sockaddr_in*)paddr);
return true;
#ifdef USE_IPV6
case AF_INET6:
*this = CService(*(const struct sockaddr_in6*)paddr);
return true;
#endif
default:
return false;
}
}
CService::CService(const char *pszIpPort, bool fAllowLookup) CService::CService(const char *pszIpPort, bool fAllowLookup)
{ {
Init(); Init();
@ -883,29 +956,36 @@ bool operator<(const CService& a, const CService& b)
return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
} }
bool CService::GetSockAddr(struct sockaddr_in* paddr) const bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
{ {
if (!IsIPv4()) if (IsIPv4()) {
return false; if (*addrlen < sizeof(struct sockaddr_in))
memset(paddr, 0, sizeof(struct sockaddr_in)); return false;
if (!GetInAddr(&paddr->sin_addr)) *addrlen = sizeof(struct sockaddr_in);
return false; struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
paddr->sin_family = AF_INET; memset(paddrin, 0, *addrlen);
paddr->sin_port = htons(port); if (!GetInAddr(&paddrin->sin_addr))
return true; return false;
} paddrin->sin_family = AF_INET;
paddrin->sin_port = htons(port);
return true;
}
#ifdef USE_IPV6 #ifdef USE_IPV6
bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const if (IsIPv6()) {
{ if (*addrlen < sizeof(struct sockaddr_in6))
memset(paddr, 0, sizeof(struct sockaddr_in6)); return false;
if (!GetIn6Addr(&paddr->sin6_addr)) *addrlen = sizeof(struct sockaddr_in6);
return false; struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
paddr->sin6_family = AF_INET6; memset(paddrin6, 0, *addrlen);
paddr->sin6_port = htons(port); if (!GetIn6Addr(&paddrin6->sin6_addr))
return true; return false;
} paddrin6->sin6_family = AF_INET6;
paddrin6->sin6_port = htons(port);
return true;
}
#endif #endif
return false;
}
std::vector<unsigned char> CService::GetKey() const std::vector<unsigned char> CService::GetKey() const
{ {
@ -919,12 +999,16 @@ std::vector<unsigned char> CService::GetKey() const
std::string CService::ToStringPort() const std::string CService::ToStringPort() const
{ {
return strprintf(":%i", port); return strprintf("%i", port);
} }
std::string CService::ToStringIPPort() const std::string CService::ToStringIPPort() const
{ {
return ToStringIP() + ToStringPort(); if (IsIPv4()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
}
} }
std::string CService::ToString() const std::string CService::ToString() const

View file

@ -17,6 +17,20 @@ extern int nConnectTimeout;
#undef SetPort #undef SetPort
#endif #endif
enum Network
{
NET_UNROUTABLE,
NET_IPV4,
NET_IPV6,
NET_TOR,
NET_I2P,
NET_MAX
};
enum Network ParseNetwork(std::string net);
void SetNoProxy(enum Network net, bool fNoProxy = true);
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr class CNetAddr
{ {
@ -31,6 +45,7 @@ class CNetAddr
void Init(); void Init();
void SetIP(const CNetAddr& ip); void SetIP(const CNetAddr& ip);
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not IPv4)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) 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 IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
@ -41,10 +56,13 @@ class CNetAddr
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
bool IsOnionCat() const;
bool IsGarliCat() const;
bool IsLocal() const; bool IsLocal() const;
bool IsRoutable() const; bool IsRoutable() const;
bool IsValid() const; bool IsValid() const;
bool IsMulticast() const; bool IsMulticast() const;
enum Network GetNetwork() const;
std::string ToString() const; std::string ToString() const;
std::string ToStringIP() const; std::string ToStringIP() const;
int GetByte(int n) const; int GetByte(int n) const;
@ -87,7 +105,8 @@ class CService : public CNetAddr
void Init(); void Init();
void SetPort(unsigned short portIn); void SetPort(unsigned short portIn);
unsigned short GetPort() const; unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr_in* paddr) const; bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr* paddr);
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); 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);
@ -99,7 +118,6 @@ class CService : public CNetAddr
#ifdef USE_IPV6 #ifdef USE_IPV6
CService(const struct in6_addr& ipv6Addr, unsigned short port); CService(const struct in6_addr& ipv6Addr, unsigned short port);
bool GetSockAddr6(struct sockaddr_in6* paddr) const;
CService(const struct sockaddr_in6& addr); CService(const struct sockaddr_in6& addr);
#endif #endif