commit
a3878873f3
14 changed files with 347 additions and 119 deletions
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
61
src/init.cpp
61
src/init.cpp
|
@ -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"))
|
||||||
|
|
|
@ -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));
|
||||||
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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))
|
||||||
|
|
158
src/net.cpp
158
src/net.cpp
|
@ -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
|
||||||
|
|
30
src/net.h
30
src/net.h
|
@ -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;
|
||||||
|
|
164
src/netbase.cpp
164
src/netbase.cpp
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue