Merge branch 'tmp-ipv6' into merge-ipv6

This commit is contained in:
Jeff Garzik 2012-05-08 19:43:17 -04:00 committed by Jeff Garzik
commit 203f9e6c00
9 changed files with 559 additions and 184 deletions

View file

@ -178,12 +178,17 @@ bool AppInit2(int argc, char* argv[])
" -dbcache=<n> \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" + " -dbcache=<n> \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" +
" -dblogsize=<n> \t\t " + _("Set database disk log size in megabytes (default: 100)") + "\n" + " -dblogsize=<n> \t\t " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" + " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" + " -proxy=<ip:port> \t " + _("Connect through socks proxy") + "\n" +
" -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" + " -socks=<n> \t " + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" +
" -dns \t " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\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" +
" -maxconnections=<n>\t " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" + " -maxconnections=<n>\t " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
" -addnode=<ip> \t " + _("Add a node to connect to and attempt to keep the connection open") + "\n" + " -addnode=<ip> \t " + _("Add a node to connect to and attempt to keep the connection open") + "\n" +
" -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" +
" -externalip=<ip> \t " + _("Specify your own public address") + "\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" +
#ifdef QT_GUI #ifdef QT_GUI
@ -527,6 +532,9 @@ bool AppInit2(int argc, char* argv[])
} }
} }
if (mapArgs.count("-connect"))
SoftSetBoolArg("-dnsseed", false);
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050); bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
if (fTor) if (fTor)
{ {
@ -534,13 +542,20 @@ bool AppInit2(int argc, char* argv[])
// Note: the GetBoolArg() calls for all of these must happen later. // Note: the GetBoolArg() calls for all of these must happen later.
SoftSetBoolArg("-listen", false); SoftSetBoolArg("-listen", false);
SoftSetBoolArg("-irc", false); SoftSetBoolArg("-irc", false);
SoftSetBoolArg("-dnsseed", false); SoftSetBoolArg("-proxydns", true);
SoftSetBoolArg("-upnp", false); SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-dns", false); SoftSetBoolArg("-discover", false);
} }
fAllowDNS = GetBoolArg("-dns"); fNameLookup = GetBoolArg("-dns");
fProxyNameLookup = GetBoolArg("-proxydns");
if (fProxyNameLookup)
fNameLookup = true;
fNoListen = !GetBoolArg("-listen", true); fNoListen = !GetBoolArg("-listen", true);
nSocksVersion = GetArg("-socks", 5);
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
// Continue to put "/P2SH/" in the coinbase to monitor // Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support. // BIP16 support.
@ -558,15 +573,10 @@ bool AppInit2(int argc, char* argv[])
} }
} }
if (mapArgs.count("-addnode")) if (mapArgs.count("-externalip"))
{ {
BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"]) BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"])
{ AddLocal(CNetAddr(strAddr, fNameLookup), LOCAL_MANUAL);
CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
addr.nTime = 0; // so it won't relay unless successfully connected
if (addr.IsValid())
addrman.Add(addr, CNetAddr("127.0.0.1"));
}
} }
if (mapArgs.count("-paytxfee")) if (mapArgs.count("-paytxfee"))

View file

@ -12,7 +12,6 @@ using namespace std;
using namespace boost; using namespace boost;
int nGotIRCAddresses = 0; int nGotIRCAddresses = 0;
bool fGotExternalIP = false;
void ThreadIRCSeed2(void* parg); void ThreadIRCSeed2(void* parg);
@ -216,7 +215,6 @@ void ThreadIRCSeed2(void* parg)
printf("ThreadIRCSeed started\n"); printf("ThreadIRCSeed started\n");
int nErrorWait = 10; int nErrorWait = 10;
int nRetryWait = 10; int nRetryWait = 10;
bool fNameInUse = false;
while (!fShutdown) while (!fShutdown)
{ {
@ -248,9 +246,10 @@ void ThreadIRCSeed2(void* parg)
return; return;
} }
CNetAddr addrLocal;
string strMyName; string strMyName;
if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse) if (GetLocal(addrLocal, &addrConnect))
strMyName = EncodeAddress(addrLocalHost); strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
else else
strMyName = strprintf("x%u", GetRand(1000000000)); strMyName = strprintf("x%u", GetRand(1000000000));
@ -265,7 +264,6 @@ void ThreadIRCSeed2(void* parg)
if (nRet == 2) if (nRet == 2)
{ {
printf("IRC name already in use\n"); printf("IRC name already in use\n");
fNameInUse = true;
Wait(10); Wait(10);
continue; continue;
} }
@ -285,9 +283,8 @@ void ThreadIRCSeed2(void* parg)
if (!fUseProxy && addrFromIRC.IsRoutable()) if (!fUseProxy && addrFromIRC.IsRoutable())
{ {
// IRC lets you to re-nick // IRC lets you to re-nick
fGotExternalIP = true; AddLocal(addrFromIRC, LOCAL_IRC);
addrLocalHost.SetIP(addrFromIRC); strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
strMyName = EncodeAddress(addrLocalHost);
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
} }
} }

View file

@ -8,6 +8,5 @@
void ThreadIRCSeed(void* parg); void ThreadIRCSeed(void* parg);
extern int nGotIRCAddresses; extern int nGotIRCAddresses;
extern bool fGotExternalIP;
#endif #endif

View file

@ -2312,6 +2312,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!vRecv.empty()) if (!vRecv.empty())
vRecv >> pfrom->nStartingHeight; vRecv >> pfrom->nStartingHeight;
if (pfrom->fInbound && addrMe.IsRoutable())
{
pfrom->addrLocal = addrMe;
SeenLocal(addrMe);
}
// Disconnect if we connected to ourself // Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1) if (nNonce == nLocalHostNonce && nNonce > 1)
{ {
@ -2335,16 +2341,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!pfrom->fInbound) if (!pfrom->fInbound)
{ {
// Advertise our address // Advertise our address
if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() && if (!fNoListen && !fUseProxy && !IsInitialBlockDownload())
!IsInitialBlockDownload())
{ {
CAddress addr(addrLocalHost); CAddress addr = GetLocalAddress(&pfrom->addr);
addr.nTime = GetAdjustedTime(); if (addr.IsRoutable())
pfrom->PushAddress(addr); pfrom->PushAddress(addr);
} }
// Get recent addresses // Get recent addresses
if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
{ {
pfrom->PushMessage("getaddr"); pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true; pfrom->fGetAddr = true;
@ -2360,7 +2365,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Ask the first connected node for block updates // Ask the first connected node for block updates
static int nAskedForBlocks = 0; static int nAskedForBlocks = 0;
if (!pfrom->fClient && if (!pfrom->fClient && !pfrom->fOneShot &&
(pfrom->nVersion < NOBLKS_VERSION_START || (pfrom->nVersion < NOBLKS_VERSION_START ||
pfrom->nVersion >= NOBLKS_VERSION_END) && pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1)) (nAskedForBlocks < 1 || vNodes.size() <= 1))
@ -2458,6 +2463,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60); addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000) if (vAddr.size() < 1000)
pfrom->fGetAddr = false; pfrom->fGetAddr = false;
if (pfrom->fOneShot)
pfrom->fDisconnect = true;
} }
@ -2979,10 +2986,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pnode->setAddrKnown.clear(); pnode->setAddrKnown.clear();
// Rebroadcast our address // Rebroadcast our address
if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable()) if (!fNoListen && !fUseProxy)
{ {
CAddress addr(addrLocalHost); CAddress addr = GetLocalAddress(&pnode->addr);
addr.nTime = GetAdjustedTime(); if (addr.IsRoutable())
pnode->PushAddress(addr); pnode->PushAddress(addr);
} }
} }

View file

@ -35,7 +35,7 @@ void ThreadOpenAddedConnections2(void* parg);
void ThreadMapPort2(void* parg); void ThreadMapPort2(void* parg);
#endif #endif
void ThreadDNSAddressSeed2(void* parg); void ThreadDNSAddressSeed2(void* parg);
bool OpenNetworkConnection(const CAddress& addrConnect); bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest = NULL, bool fOneShot = false);
@ -43,10 +43,10 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
// Global state variables // Global state variables
// //
bool fClient = false; bool fClient = false;
bool fAllowDNS = false;
static bool fUseUPnP = false; static bool fUseUPnP = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); CCriticalSection cs_mapLocalHost;
map<CNetAddr, int> mapLocalHost;
static CNode* pnodeLocalHost = NULL; static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0; uint64 nLocalHostNonce = 0;
array<int, THREAD_MAX> vnThreadsRunning; array<int, THREAD_MAX> vnThreadsRunning;
@ -60,6 +60,8 @@ deque<pair<int64, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay; CCriticalSection cs_mapRelay;
map<CInv, int64> mapAlreadyAskedFor; map<CInv, int64> mapAlreadyAskedFor;
static deque<string> vOneShots;
CCriticalSection cs_vOneShots;
set<CNetAddr> setservAddNodeAddresses; set<CNetAddr> setservAddNodeAddresses;
CCriticalSection cs_setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses;
@ -69,6 +71,12 @@ static int nOutbound = 0;
static CConditionVariable condOutbound; static CConditionVariable condOutbound;
void AddOneShot(string strDest)
{
LOCK(cs_vOneShots);
vOneShots.push_back(strDest);
}
unsigned short GetListenPort() unsigned short GetListenPort()
{ {
return (unsigned short)(GetArg("-port", GetDefaultPort())); return (unsigned short)(GetArg("-port", GetDefaultPort()));
@ -85,7 +93,45 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
} }
// find 'best' local address for a particular peer
bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
{
if (fUseProxy || mapArgs.count("-connect") || fNoListen)
return false;
int nBestCount = -1;
int nBestReachability = -1;
{
LOCK(cs_mapLocalHost);
for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
{
int nCount = (*it).second;
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
if (nReachability > nBestReachability || (nReachability == nBestReachability && nCount > nBestCount))
{
addr = (*it).first;
nBestReachability = nReachability;
nBestCount = nCount;
}
}
}
return nBestCount >= 0;
}
// get best local address for a particular peer as a CAddress
CAddress GetLocalAddress(const CNetAddr *paddrPeer)
{
CAddress ret(CService("0.0.0.0",0),0);
CNetAddr addr;
if (GetLocal(addr, paddrPeer))
{
ret.SetIP(addr);
ret.SetPort(GetListenPort());
ret.nServices = nLocalServices;
ret.nTime = GetAdjustedTime();
}
return ret;
}
bool RecvLine(SOCKET hSocket, string& strLine) bool RecvLine(SOCKET hSocket, string& strLine)
{ {
@ -138,6 +184,64 @@ bool RecvLine(SOCKET hSocket, string& strLine)
} }
} }
// used when scores of local addresses may have changed
// pushes better local address to peers
void static AdvertizeLocal()
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->fSuccessfullyConnected)
{
CAddress addrLocal = GetLocalAddress(&pnode->addr);
if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal)
{
pnode->PushAddress(addrLocal);
pnode->addrLocal = addrLocal;
}
}
}
}
// learn a new local address
bool AddLocal(const CNetAddr& addr, int nScore)
{
if (!addr.IsRoutable())
return false;
printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
{
LOCK(cs_mapLocalHost);
mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0);
}
AdvertizeLocal();
return true;
}
// vote for a local address
bool SeenLocal(const CNetAddr& addr)
{
{
LOCK(cs_mapLocalHost);
if (mapLocalHost.count(addr) == 0)
return false;
mapLocalHost[addr]++;
}
AdvertizeLocal();
return true;
}
// check whether a given address is potentially local
bool IsLocal(const CNetAddr& addr)
{
LOCK(cs_mapLocalHost);
return mapLocalHost.count(addr) > 0;
}
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)
@ -251,33 +355,11 @@ bool GetMyExternalIP(CNetAddr& ipRet)
void ThreadGetMyExternalIP(void* parg) void ThreadGetMyExternalIP(void* parg)
{ {
// Wait for IRC to get it first CNetAddr addrLocalHost;
if (GetBoolArg("-irc", false))
{
for (int i = 0; i < 2 * 60; i++)
{
Sleep(1000);
if (fGotExternalIP || fShutdown)
return;
}
}
// Fallback in case IRC fails to get it
if (GetMyExternalIP(addrLocalHost)) if (GetMyExternalIP(addrLocalHost))
{ {
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
if (addrLocalHost.IsRoutable()) AddLocal(addrLocalHost, LOCAL_HTTP);
{
// If we already connected to a few before we had our IP, go back and addr them.
// setAddrKnown automatically filters any duplicate sends.
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushAddress(addr);
}
}
} }
} }
@ -307,6 +389,15 @@ CNode* FindNode(const CNetAddr& ip)
return NULL; return NULL;
} }
CNode* FindNode(std::string addrName)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addrName == addrName)
return (pnode);
return NULL;
}
CNode* FindNode(const CService& addr) CNode* FindNode(const CService& addr)
{ {
{ {
@ -318,9 +409,10 @@ CNode* FindNode(const CService& addr)
return NULL; return NULL;
} }
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout)
{ {
if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost) if (pszDest == NULL) {
if (IsLocal(addrConnect))
return NULL; return NULL;
// Look for an existing connection // Look for an existing connection
@ -333,20 +425,22 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
pnode->AddRef(); pnode->AddRef();
return pnode; return pnode;
} }
}
/// debug print /// debug print
printf("trying connection %s lastseen=%.1fhrs\n", printf("trying connection %s lastseen=%.1fhrs\n",
addrConnect.ToString().c_str(), pszDest ? pszDest : addrConnect.ToString().c_str(),
(double)(addrConnect.nTime - GetAdjustedTime())/3600.0); pszDest ? 0 : (double)(addrConnect.nTime - GetAdjustedTime())/3600.0);
addrman.Attempt(addrConnect);
// Connect // Connect
SOCKET hSocket; SOCKET hSocket;
if (ConnectSocket(addrConnect, hSocket)) if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
{ {
addrman.Attempt(addrConnect);
/// debug print /// debug print
printf("connected %s\n", addrConnect.ToString().c_str()); printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
// Set to nonblocking // Set to nonblocking
#ifdef WIN32 #ifdef WIN32
@ -359,11 +453,12 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
#endif #endif
// Add node // Add node
CNode* pnode = new CNode(hSocket, addrConnect, false); CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
if (nTimeout != 0) if (nTimeout != 0)
pnode->AddRef(nTimeout); pnode->AddRef(nTimeout);
else else
pnode->AddRef(); pnode->AddRef();
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
vNodes.push_back(pnode); vNodes.push_back(pnode);
@ -389,7 +484,7 @@ void CNode::CloseSocketDisconnect()
{ {
if (fDebug) if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("disconnecting node %s\n", addr.ToString().c_str()); printf("disconnecting node %s\n", addrName.c_str());
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET; hSocket = INVALID_SOCKET;
vRecv.clear(); vRecv.clear();
@ -406,7 +501,7 @@ void CNode::PushVersion()
/// when NTP implemented, change to just nTime = GetAdjustedTime() /// when NTP implemented, change to just nTime = GetAdjustedTime()
int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr); CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr);
CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost); CAddress addrMe = GetLocalAddress(&addr);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight); nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
@ -444,7 +539,7 @@ bool CNode::Misbehaving(int howmuch)
{ {
if (addr.IsLocal()) if (addr.IsLocal())
{ {
printf("Warning: local node %s misbehaving\n", addr.ToString().c_str()); printf("Warning: local node %s misbehaving\n", addrName.c_str());
return false; return false;
} }
@ -458,7 +553,7 @@ bool CNode::Misbehaving(int howmuch)
setBanned[addr] = banTime; setBanned[addr] = banTime;
} }
CloseSocketDisconnect(); CloseSocketDisconnect();
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); printf("Disconnected %s for misbehavior (score=%d)\n", addrName.c_str(), nMisbehavior);
return true; return true;
} }
return false; return false;
@ -675,7 +770,7 @@ void ThreadSocketHandler2(void* parg)
else else
{ {
printf("accepted connection %s\n", addr.ToString().c_str()); printf("accepted connection %s\n", addr.ToString().c_str());
CNode* pnode = new CNode(hSocket, addr, true); CNode* pnode = new CNode(hSocket, addr, "", true);
pnode->AddRef(); pnode->AddRef();
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
@ -878,8 +973,7 @@ void ThreadMapPort2(void* parg)
r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
if (r == 1) if (r == 1)
{ {
if (!addrLocalHost.IsRoutable()) if (GetBoolArg("-discover", true)) {
{
char externalIPAddress[40]; char externalIPAddress[40];
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS) if(r != UPNPCOMMAND_SUCCESS)
@ -889,9 +983,7 @@ void ThreadMapPort2(void* parg)
if(externalIPAddress[0]) if(externalIPAddress[0])
{ {
printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices); AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
if (addrExternalFromUPnP.IsRoutable())
addrLocalHost = addrExternalFromUPnP;
} }
else else
printf("UPnP: GetExternalIPAddress failed.\n"); printf("UPnP: GetExternalIPAddress failed.\n");
@ -1025,6 +1117,9 @@ void ThreadDNSAddressSeed2(void* parg)
printf("Loading addresses from DNS seeds (could take a while)\n"); printf("Loading addresses from DNS seeds (could take a while)\n");
for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
if (fProxyNameLookup) {
AddOneShot(strDNSSeed[seed_idx][1]);
} else {
vector<CNetAddr> vaddr; vector<CNetAddr> vaddr;
vector<CAddress> vAdd; vector<CAddress> vAdd;
if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
@ -1041,6 +1136,7 @@ void ThreadDNSAddressSeed2(void* parg)
addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
} }
} }
}
printf("%d addresses found from DNS seeds\n", found); printf("%d addresses found from DNS seeds\n", found);
} }
@ -1188,6 +1284,21 @@ void ThreadOpenConnections(void* parg)
printf("ThreadOpenConnections exiting\n"); printf("ThreadOpenConnections exiting\n");
} }
void static ProcessOneShot()
{
string strDest;
{
LOCK(cs_vOneShots);
if (vOneShots.empty())
return;
strDest = vOneShots.front();
vOneShots.pop_front();
}
CAddress addr;
if (!OpenNetworkConnection(addr, strDest.c_str(), true))
AddOneShot(strDest);
}
void ThreadOpenConnections2(void* parg) void ThreadOpenConnections2(void* parg)
{ {
printf("ThreadOpenConnections started\n"); printf("ThreadOpenConnections started\n");
@ -1197,11 +1308,11 @@ void ThreadOpenConnections2(void* parg)
{ {
for (int64 nLoop = 0;; nLoop++) for (int64 nLoop = 0;; nLoop++)
{ {
ProcessOneShot();
BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
{ {
CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS)); CAddress addr;
if (addr.IsValid()) OpenNetworkConnection(addr, strAddr.c_str());
OpenNetworkConnection(addr);
for (int i = 0; i < 10 && i < nLoop; i++) for (int i = 0; i < 10 && i < nLoop; i++)
{ {
Sleep(500); Sleep(500);
@ -1216,6 +1327,8 @@ void ThreadOpenConnections2(void* parg)
int64 nStart = GetTime(); int64 nStart = GetTime();
loop loop
{ {
ProcessOneShot();
vnThreadsRunning[THREAD_OPENCONNECTIONS]--; vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
Sleep(500); Sleep(500);
vnThreadsRunning[THREAD_OPENCONNECTIONS]++; vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
@ -1277,7 +1390,7 @@ 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()) || addr == addrLocalHost) if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
break; break;
nTries++; nTries++;
@ -1325,11 +1438,25 @@ void ThreadOpenAddedConnections2(void* parg)
if (mapArgs.count("-addnode") == 0) if (mapArgs.count("-addnode") == 0)
return; return;
if (fProxyNameLookup) {
while(!fShutdown) {
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
CAddress addr;
OpenNetworkConnection(addr, strAddNode.c_str());
Sleep(500);
}
vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
Sleep(120000); // Retry every 2 minutes
vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
}
return;
}
vector<vector<CService> > vservAddressesToAdd(0); vector<vector<CService> > vservAddressesToAdd(0);
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
{ {
vector<CService> vservNode(0); vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0)) if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
{ {
vservAddressesToAdd.push_back(vservNode); vservAddressesToAdd.push_back(vservNode);
{ {
@ -1343,7 +1470,7 @@ void ThreadOpenAddedConnections2(void* parg)
{ {
vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd; vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fAllowDNS) // (keeping in mind that addnode entries can have many IPs if fNameLookup)
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
@ -1373,25 +1500,31 @@ void ThreadOpenAddedConnections2(void* parg)
} }
} }
bool OpenNetworkConnection(const CAddress& addrConnect) bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest, bool fOneShot)
{ {
// //
// Initiate outbound network connection // Initiate outbound network connection
// //
if (fShutdown) if (fShutdown)
return false; return false;
if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() || if (!strDest)
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect)) if (IsLocal(addrConnect) ||
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
FindNode(addrConnect.ToStringIPPort().c_str()))
return false;
if (strDest && FindNode(strDest))
return false; return false;
vnThreadsRunning[THREAD_OPENCONNECTIONS]--; vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
CNode* pnode = ConnectNode(addrConnect); CNode* pnode = ConnectNode(addrConnect, strDest);
vnThreadsRunning[THREAD_OPENCONNECTIONS]++; vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
if (fShutdown) if (fShutdown)
return false; return false;
if (!pnode) if (!pnode)
return false; return false;
pnode->fNetworkNode = true; pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
return true; return true;
} }
@ -1489,7 +1622,6 @@ bool BindListenPort(string& strError)
{ {
strError = ""; strError = "";
int nOne = 1; int nOne = 1;
addrLocalHost.SetPort(GetListenPort());
#ifdef WIN32 #ifdef WIN32
// Initialize Windows Sockets // Initialize Windows Sockets
@ -1565,18 +1697,10 @@ bool BindListenPort(string& strError)
return true; return true;
} }
void StartNode(void* parg) void static Discover()
{ {
#ifdef USE_UPNP if (!GetBoolArg("-discover", true))
#if USE_UPNP return;
fUseUPnP = GetBoolArg("-upnp", true);
#else
fUseUPnP = GetBoolArg("-upnp", false);
#endif
#endif
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
#ifdef WIN32 #ifdef WIN32
// Get local host ip // Get local host ip
@ -1588,11 +1712,7 @@ void StartNode(void* parg)
{ {
BOOST_FOREACH (const CNetAddr &addr, vaddr) BOOST_FOREACH (const CNetAddr &addr, vaddr)
{ {
if (!addr.IsLocal()) AddLocal(addr, LOCAL_IF);
{
addrLocalHost.SetIP(addr);
break;
}
} }
} }
} }
@ -1615,35 +1735,45 @@ void StartNode(void* parg)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x // Take the first IP that isn't loopback 127.x.x.x
CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices); CNetAddr addr(s4->sin_addr);
if (addr.IsValid() && !addr.IsLocal()) AddLocal(addr, LOCAL_IF);
{
addrLocalHost = addr;
break;
}
} }
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) 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); printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
#ifdef USE_IPV6
CNetAddr addr(s6->sin6_addr);
AddLocal(addr, LOCAL_IF);
#endif
} }
} }
freeifaddrs(myaddrs); freeifaddrs(myaddrs);
} }
#endif #endif
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
if (fUseProxy || mapArgs.count("-connect") || fNoListen) if (!fUseProxy && !mapArgs.count("-connect") && !fNoListen)
{
// Proxies can't take incoming connections
addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
else
{ {
CreateThread(ThreadGetMyExternalIP, NULL); CreateThread(ThreadGetMyExternalIP, NULL);
} }
}
void StartNode(void* parg)
{
#ifdef USE_UPNP
#if USE_UPNP
fUseUPnP = GetBoolArg("-upnp", true);
#else
fUseUPnP = GetBoolArg("-upnp", false);
#endif
#endif
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
Discover();
// //
// Start threads // Start threads

View file

@ -30,17 +30,36 @@ extern int nBestHeight;
inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); } inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); } inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine); bool RecvLine(SOCKET hSocket, std::string& strLine);
bool GetMyExternalIP(CNetAddr& ipRet); bool GetMyExternalIP(CNetAddr& ipRet);
void AddressCurrentlyConnected(const CService& addr); void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip); CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, 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(std::string& strError=REF(std::string()));
void StartNode(void* parg); void StartNode(void* parg);
bool StopNode(); bool StopNode();
enum
{
LOCAL_NONE,
LOCAL_IF,
LOCAL_UPNP,
LOCAL_IRC,
LOCAL_HTTP,
LOCAL_MANUAL,
LOCAL_MAX
};
bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
bool SeenLocal(const CNetAddr& addr);
bool IsLocal(const CNetAddr& addr);
bool GetLocal(CNetAddr &addr, const CNetAddr *paddrPeer = NULL);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
enum enum
{ {
MSG_TX = 1, MSG_TX = 1,
@ -83,9 +102,7 @@ enum threadId
}; };
extern bool fClient; extern bool fClient;
extern bool fAllowDNS;
extern uint64 nLocalServices; extern uint64 nLocalServices;
extern CAddress addrLocalHost;
extern uint64 nLocalHostNonce; extern uint64 nLocalHostNonce;
extern boost::array<int, THREAD_MAX> vnThreadsRunning; extern boost::array<int, THREAD_MAX> vnThreadsRunning;
extern CAddrMan addrman; extern CAddrMan addrman;
@ -120,8 +137,11 @@ public:
int nHeaderStart; int nHeaderStart;
unsigned int nMessageStart; unsigned int nMessageStart;
CAddress addr; CAddress addr;
std::string addrName;
CNetAddr addrLocal;
int nVersion; int nVersion;
std::string strSubVer; std::string strSubVer;
bool fOneShot;
bool fClient; bool fClient;
bool fInbound; bool fInbound;
bool fNetworkNode; bool fNetworkNode;
@ -157,7 +177,7 @@ public:
CCriticalSection cs_inventory; CCriticalSection cs_inventory;
std::multimap<int64, CInv> mapAskFor; std::multimap<int64, CInv> mapAskFor;
CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION) CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
{ {
nServices = 0; nServices = 0;
hSocket = hSocketIn; hSocket = hSocketIn;
@ -168,8 +188,10 @@ public:
nHeaderStart = -1; nHeaderStart = -1;
nMessageStart = -1; nMessageStart = -1;
addr = addrIn; addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0; nVersion = 0;
strSubVer = ""; strSubVer = "";
fOneShot = false;
fClient = false; // set by version message fClient = false; // set by version message
fInbound = fInboundIn; fInbound = fInboundIn;
fNetworkNode = false; fNetworkNode = false;

View file

@ -15,7 +15,10 @@
using namespace std; using namespace std;
// Settings // Settings
int nSocksVersion = 5;
int fUseProxy = false; int fUseProxy = false;
bool fProxyNameLookup = false;
bool fNameLookup = false;
CService addrProxy("127.0.0.1",9050); CService addrProxy("127.0.0.1",9050);
int nConnectTimeout = 5000; int nConnectTimeout = 5000;
@ -156,7 +159,149 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
return Lookup(pszName, addr, portDefault, false); return Lookup(pszName, addr, portDefault, false);
} }
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) bool static Socks4(const CService &addrDest, SOCKET& hSocket)
{
printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str());
if (!addrDest.IsIPv4())
{
closesocket(hSocket);
return error("Proxy destination is not IPv4");
}
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
struct sockaddr_in addr;
addrDest.GetSockAddr(&addr);
memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
char* pszSocks4 = pszSocks4IP;
int nSize = sizeof(pszSocks4IP);
int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet[8];
if (recv(hSocket, pchRet, 8, 0) != 8)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
if (pchRet[1] != 0x5b)
printf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false;
}
printf("SOCKS4 connected %s\n", addrDest.ToString().c_str());
return true;
}
bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
printf("SOCKS5 connecting %s\n", strDest.c_str());
if (strDest.size() > 255)
{
closesocket(hSocket);
return error("Hostname too long");
}
char pszSocks5Init[] = "\5\1\0";
char *pszSocks5 = pszSocks5Init;
int nSize = sizeof(pszSocks5Init);
int ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet1[2];
if (recv(hSocket, pchRet1, 2, 0) != 2)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00)
{
closesocket(hSocket);
return error("Proxy failed to initialize");
}
string strSocks5("\5\1");
strSocks5 += '\000'; strSocks5 += '\003';
strSocks5 += static_cast<char>(std::min((int)strDest.size(), 255));
strSocks5 += strDest;
strSocks5 += static_cast<char>((port >> 8) & 0xFF);
strSocks5 += static_cast<char>((port >> 0) & 0xFF);
ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL);
if (ret != strSocks5.size())
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet2[4];
if (recv(hSocket, pchRet2, 4, 0) != 4)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet2[0] != 0x05)
{
closesocket(hSocket);
return error("Proxy failed to accept request");
}
if (pchRet2[1] != 0x00)
{
closesocket(hSocket);
switch (pchRet2[1])
{
case 0x01: return error("Proxy error: general failure");
case 0x02: return error("Proxy error: connection not allowed");
case 0x03: return error("Proxy error: network unreachable");
case 0x04: return error("Proxy error: host unreachable");
case 0x05: return error("Proxy error: connection refused");
case 0x06: return error("Proxy error: TTL expired");
case 0x07: return error("Proxy error: protocol error");
case 0x08: return error("Proxy error: address type not supported");
default: return error("Proxy error: unknown");
}
}
if (pchRet2[2] != 0x00)
{
closesocket(hSocket);
return error("Error: malformed proxy response");
}
char pchRet3[256];
switch (pchRet2[3])
{
case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break;
case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break;
case 0x03:
{
ret = recv(hSocket, pchRet3, 1, 0) != 1;
if (ret)
return error("Error reading from proxy");
int nRecv = pchRet3[0];
ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv;
break;
}
default: closesocket(hSocket); return error("Error: malformed proxy response");
}
if (ret)
{
closesocket(hSocket);
return error("Error reading from proxy");
}
if (recv(hSocket, pchRet3, 2, 0) != 2)
{
closesocket(hSocket);
return error("Error reading from proxy");
}
printf("SOCKS5 connected %s\n", strDest.c_str());
return true;
}
bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
{ {
hSocketRet = INVALID_SOCKET; hSocketRet = INVALID_SOCKET;
@ -168,12 +313,12 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif #endif
bool fProxy = (fUseProxy && addrDest.IsRoutable());
struct sockaddr_in sockaddr; struct sockaddr_in sockaddr;
if (fProxy) if (!addrConnect.GetSockAddr(&sockaddr))
addrProxy.GetSockAddr(&sockaddr); {
else closesocket(hSocket);
addrDest.GetSockAddr(&sockaddr); return false;
}
#ifdef WIN32 #ifdef WIN32
u_long fNonblock = 1; u_long fNonblock = 1;
@ -187,7 +332,6 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
return false; return false;
} }
if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{ {
// WSAEINVAL is here because some legacy version of winsock uses it // WSAEINVAL is here because some legacy version of winsock uses it
@ -258,37 +402,75 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
return false; return false;
} }
hSocketRet = hSocket;
return true;
}
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{
SOCKET hSocket = INVALID_SOCKET;
bool fProxy = (fUseProxy && addrDest.IsRoutable());
if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout))
return false;
if (fProxy) if (fProxy)
{ {
printf("proxy connecting %s\n", addrDest.ToString().c_str()); switch(nSocksVersion)
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
struct sockaddr_in addr;
addrDest.GetSockAddr(&addr);
memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
char* pszSocks4 = pszSocks4IP;
int nSize = sizeof(pszSocks4IP);
int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{ {
closesocket(hSocket); case 4:
return error("Error sending to proxy"); if (!Socks4(addrDest, hSocket))
}
char pchRet[8];
if (recv(hSocket, pchRet, 8, 0) != 8)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
if (pchRet[1] != 0x5b)
printf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false; return false;
break;
case 5:
default:
if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
break;
} }
printf("proxy connected %s\n", addrDest.ToString().c_str()); }
hSocketRet = hSocket;
return true;
}
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
{
string strDest(pszDest);
int port = portDefault;
size_t colon = strDest.find_last_of(':');
char *endp = NULL;
int n = strtol(pszDest + colon + 1, &endp, 10);
if (endp && *endp == 0 && n >= 0) {
strDest = strDest.substr(0, colon);
if (n > 0 && n < 0x10000)
port = n;
}
if (strDest[0] == '[' && strDest[strDest.size()-1] == ']')
strDest = strDest.substr(1, strDest.size()-2);
SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !fProxyNameLookup), port);
if (addrResolved.IsValid()) {
addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout);
}
addr = CService("0.0.0.0:0");
if (!fNameLookup)
return false;
if (!ConnectSocketDirectly(addrProxy, hSocket, nTimeout))
return false;
switch(nSocksVersion)
{
case 4: return false;
case 5:
default:
if (!Socks5(strDest, port, hSocket))
return false;
break;
} }
hSocketRet = hSocket; hSocketRet = hSocket;
@ -590,6 +772,29 @@ void CNetAddr::print() const
printf("CNetAddr(%s)\n", ToString().c_str()); printf("CNetAddr(%s)\n", ToString().c_str());
} }
// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners:
// 0 - unroutable // 0 - unroutable // 0 - unroutable
// 1 - teredo // 1 - teredo // 1 - ipv4
// 2 - tunneled ipv6 // 2 - tunneled ipv6
// 3 - ipv4 // 3 - ipv6
// 4 - ipv6 // 4 - ipv4
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
{
if (!IsValid() || !IsRoutable())
return 0;
if (paddrPartner && paddrPartner->IsIPv4())
return IsIPv4() ? 1 : 0;
if (IsRFC4380())
return 1;
if (IsRFC3964() || IsRFC6052())
return 2;
bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable();
if (fRealIPv6)
return IsIPv4() ? 3 : 4;
else
return IsIPv4() ? 4 : 3;
}
void CService::Init() void CService::Init()
{ {
port = 0; port = 0;

View file

@ -51,6 +51,7 @@ class CNetAddr
int64 GetHash() const; int64 GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const; bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const; std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
void print() const; void print() const;
#ifdef USE_IPV6 #ifdef USE_IPV6
@ -119,9 +120,13 @@ bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllo
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0);
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
// Settings // Settings
extern int nSocksVersion;
extern int fUseProxy; extern int fUseProxy;
extern bool fProxyNameLookup;
extern bool fNameLookup;
extern CService addrProxy; extern CService addrProxy;
#endif #endif

View file

@ -31,13 +31,13 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
{ {
CNode::ClearBanned(); CNode::ClearBanned();
CAddress addr1(ip(0xa0b0c001)); CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true); CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.Misbehaving(100); // Should get banned dummyNode1.Misbehaving(100); // Should get banned
BOOST_CHECK(CNode::IsBanned(addr1)); BOOST_CHECK(CNode::IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned
CAddress addr2(ip(0xa0b0c002)); CAddress addr2(ip(0xa0b0c002));
CNode dummyNode2(INVALID_SOCKET, addr2, true); CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
dummyNode2.Misbehaving(50); dummyNode2.Misbehaving(50);
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
CNode::ClearBanned(); CNode::ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001)); CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, true); CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.Misbehaving(100); dummyNode1.Misbehaving(100);
BOOST_CHECK(!CNode::IsBanned(addr1)); BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(10); dummyNode1.Misbehaving(10);
@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime() SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001)); CAddress addr(ip(0xa0b0c001));
CNode dummyNode(INVALID_SOCKET, addr, true); CNode dummyNode(INVALID_SOCKET, addr, "", true);
dummyNode.Misbehaving(100); dummyNode.Misbehaving(100);
BOOST_CHECK(CNode::IsBanned(addr)); BOOST_CHECK(CNode::IsBanned(addr));