aboutsummaryrefslogtreecommitdiff
path: root/src/netbase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/netbase.cpp')
-rw-r--r--src/netbase.cpp201
1 files changed, 122 insertions, 79 deletions
diff --git a/src/netbase.cpp b/src/netbase.cpp
index a2ac6575bc..adac5c2d07 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -12,6 +12,7 @@
#include "hash.h"
#include "sync.h"
#include "uint256.h"
+#include "random.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -34,11 +35,9 @@
#define MSG_NOSIGNAL 0
#endif
-using namespace std;
-
// Settings
static proxyType proxyInfo[NET_MAX];
-static CService nameProxy;
+static proxyType nameProxy;
static CCriticalSection cs_proxyInfos;
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = false;
@@ -285,59 +284,100 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
return len == 0;
}
-bool static Socks5(string strDest, int port, SOCKET& hSocket)
+struct ProxyCredentials
+{
+ std::string username;
+ std::string password;
+};
+
+/** Connect using SOCKS5 (as described in RFC1928) */
+static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{
LogPrintf("SOCKS5 connecting %s\n", strDest);
- if (strDest.size() > 255)
- {
+ if (strDest.size() > 255) {
CloseSocket(hSocket);
return error("Hostname too long");
}
- char pszSocks5Init[] = "\5\1\0";
- ssize_t nSize = sizeof(pszSocks5Init) - 1;
-
- ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL);
- if (ret != nSize)
- {
+ // Accepted authentication methods
+ std::vector<uint8_t> vSocks5Init;
+ vSocks5Init.push_back(0x05);
+ if (auth) {
+ vSocks5Init.push_back(0x02); // # METHODS
+ vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+ vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
+ } else {
+ vSocks5Init.push_back(0x01); // # METHODS
+ vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+ }
+ ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL);
+ if (ret != (ssize_t)vSocks5Init.size()) {
CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet1[2];
- if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket))
- {
+ if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
CloseSocket(hSocket);
return error("Error reading proxy response");
}
- if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00)
- {
+ if (pchRet1[0] != 0x05) {
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.data(), strSocks5.size(), MSG_NOSIGNAL);
- if (ret != (ssize_t)strSocks5.size())
- {
+ if (pchRet1[1] == 0x02 && auth) {
+ // Perform username/password authentication (as described in RFC1929)
+ std::vector<uint8_t> vAuth;
+ vAuth.push_back(0x01);
+ if (auth->username.size() > 255 || auth->password.size() > 255)
+ return error("Proxy username or password too long");
+ vAuth.push_back(auth->username.size());
+ vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
+ vAuth.push_back(auth->password.size());
+ vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
+ ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL);
+ if (ret != (ssize_t)vAuth.size()) {
+ CloseSocket(hSocket);
+ return error("Error sending authentication to proxy");
+ }
+ LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
+ char pchRetA[2];
+ if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ CloseSocket(hSocket);
+ return error("Error reading proxy authentication response");
+ }
+ if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
+ CloseSocket(hSocket);
+ return error("Proxy authentication unsuccesful");
+ }
+ } else if (pchRet1[1] == 0x00) {
+ // Perform no authentication
+ } else {
+ CloseSocket(hSocket);
+ return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
+ }
+ std::vector<uint8_t> vSocks5;
+ vSocks5.push_back(0x05); // VER protocol version
+ vSocks5.push_back(0x01); // CMD CONNECT
+ vSocks5.push_back(0x00); // RSV Reserved
+ vSocks5.push_back(0x03); // ATYP DOMAINNAME
+ vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
+ vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
+ vSocks5.push_back((port >> 8) & 0xFF);
+ vSocks5.push_back((port >> 0) & 0xFF);
+ ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL);
+ if (ret != (ssize_t)vSocks5.size()) {
CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet2[4];
- if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket))
- {
+ if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) {
CloseSocket(hSocket);
return error("Error reading proxy response");
}
- if (pchRet2[0] != 0x05)
- {
+ if (pchRet2[0] != 0x05) {
CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
- if (pchRet2[1] != 0x00)
- {
+ if (pchRet2[1] != 0x00) {
CloseSocket(hSocket);
switch (pchRet2[1])
{
@@ -352,8 +392,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
default: return error("Proxy error: unknown");
}
}
- if (pchRet2[2] != 0x00)
- {
+ if (pchRet2[2] != 0x00) {
CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
@@ -375,13 +414,11 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
}
default: CloseSocket(hSocket); return error("Error: malformed proxy response");
}
- if (!ret)
- {
+ if (!ret) {
CloseSocket(hSocket);
return error("Error reading from proxy");
}
- if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket))
- {
+ if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
CloseSocket(hSocket);
return error("Error reading from proxy");
}
@@ -471,7 +508,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true;
}
-bool SetProxy(enum Network net, CService addrProxy) {
+bool SetProxy(enum Network net, const proxyType &addrProxy) {
assert(net >= 0 && net < NET_MAX);
if (!addrProxy.IsValid())
return false;
@@ -489,7 +526,7 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
return true;
}
-bool SetNameProxy(CService addrProxy) {
+bool SetNameProxy(const proxyType &addrProxy) {
if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
@@ -497,7 +534,7 @@ bool SetNameProxy(CService addrProxy) {
return true;
}
-bool GetNameProxy(CService &nameProxyOut) {
+bool GetNameProxy(proxyType &nameProxyOut) {
LOCK(cs_proxyInfos);
if(!nameProxy.IsValid())
return false;
@@ -513,50 +550,60 @@ bool HaveNameProxy() {
bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) {
- if (addr == (CNetAddr)proxyInfo[i])
+ if (addr == (CNetAddr)proxyInfo[i].proxy)
return true;
}
return false;
}
-bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
{
- proxyType proxy;
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
- // no proxy needed (none set for target network)
- if (!GetProxy(addrDest.GetNetwork(), proxy))
- return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
-
SOCKET hSocket = INVALID_SOCKET;
-
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy, hSocket, nTimeout)) {
+ if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) {
if (outProxyConnectionFailed)
*outProxyConnectionFailed = true;
return false;
}
// do socks negotiation
- if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
- return false;
+ if (proxy.randomize_credentials) {
+ ProxyCredentials random_auth;
+ random_auth.username = strprintf("%i", insecure_rand());
+ random_auth.password = strprintf("%i", insecure_rand());
+ if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
+ return false;
+ } else {
+ if (!Socks5(strDest, (unsigned short)port, 0, hSocket))
+ return false;
+ }
hSocketRet = hSocket;
return true;
}
+bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+{
+ proxyType proxy;
+ if (outProxyConnectionFailed)
+ *outProxyConnectionFailed = false;
+
+ if (GetProxy(addrDest.GetNetwork(), proxy))
+ return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed);
+ else // no proxy needed (none set for target network)
+ return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
+}
+
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
{
- string strDest;
+ std::string strDest;
int port = portDefault;
if (outProxyConnectionFailed)
*outProxyConnectionFailed = false;
- SplitHostPort(string(pszDest), port, strDest);
+ SplitHostPort(std::string(pszDest), port, strDest);
- SOCKET hSocket = INVALID_SOCKET;
-
- CService nameProxy;
+ proxyType nameProxy;
GetNameProxy(nameProxy);
CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port);
@@ -569,18 +616,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
if (!HaveNameProxy())
return false;
- // first connect to name proxy server
- if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout)) {
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = true;
- return false;
- }
- // do socks negotiation
- if (!Socks5(strDest, (unsigned short)port, hSocket))
- return false;
-
- hSocketRet = hSocket;
- return true;
+ return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
}
void CNetAddr::Init()
@@ -1214,15 +1250,15 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
std::string strNetmask = strSubnet.substr(slash + 1);
int32_t n;
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- int noffset = network.IsIPv4() ? (12 * 8) : 0;
+ const int astartofs = network.IsIPv4() ? 12 : 0;
if (ParseInt32(strNetmask, &n)) // If valid number, assume /24 symtex
{
- if(n >= 0 && n <= (128 - noffset)) // Only valid if in range of bits of address
+ if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address
{
- n += noffset;
+ n += astartofs*8;
// Clear bits [n..127]
for (; n < 128; ++n)
- netmask[n>>3] &= ~(1<<(n&7));
+ netmask[n>>3] &= ~(1<<(7-(n&7)));
}
else
{
@@ -1233,12 +1269,10 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
{
if (LookupHost(strNetmask.c_str(), vIP, 1, false)) // Never allow lookup for netmask
{
- // Remember: GetByte returns bytes in reversed order
// Copy only the *last* four bytes in case of IPv4, the rest of the mask should stay 1's as
// we don't want pchIPv4 to be part of the mask.
- int asize = network.IsIPv4() ? 4 : 16;
- for(int x=0; x<asize; ++x)
- netmask[15-x] = vIP[0].GetByte(x);
+ for(int x=astartofs; x<16; ++x)
+ netmask[x] = vIP[0].ip[x];
}
else
{
@@ -1251,6 +1285,10 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
{
valid = false;
}
+
+ // Normalize network according to netmask
+ for(int x=0; x<16; ++x)
+ network.ip[x] &= netmask[x];
}
bool CSubNet::Match(const CNetAddr &addr) const
@@ -1258,7 +1296,7 @@ bool CSubNet::Match(const CNetAddr &addr) const
if (!valid || !addr.IsValid())
return false;
for(int x=0; x<16; ++x)
- if ((addr.GetByte(x) & netmask[15-x]) != network.GetByte(x))
+ if ((addr.ip[x] & netmask[x]) != network.ip[x])
return false;
return true;
}
@@ -1292,6 +1330,11 @@ bool operator!=(const CSubNet& a, const CSubNet& b)
return !(a==b);
}
+bool operator<(const CSubNet& a, const CSubNet& b)
+{
+ return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
+}
+
#ifdef WIN32
std::string NetworkErrorString(int err)
{