diff options
Diffstat (limited to 'src/netbase.cpp')
-rw-r--r-- | src/netbase.cpp | 273 |
1 files changed, 239 insertions, 34 deletions
diff --git a/src/netbase.cpp b/src/netbase.cpp index 8b30ffc140..4fe3fb61da 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -15,7 +15,10 @@ using namespace std; // Settings +int nSocksVersion = 5; int fUseProxy = false; +bool fProxyNameLookup = false; +bool fNameLookup = false; CService addrProxy("127.0.0.1",9050); int nConnectTimeout = 5000; @@ -156,7 +159,149 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault) 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; @@ -168,12 +313,12 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); #endif - bool fProxy = (fUseProxy && addrDest.IsRoutable()); struct sockaddr_in sockaddr; - if (fProxy) - addrProxy.GetSockAddr(&sockaddr); - else - addrDest.GetSockAddr(&sockaddr); + if (!addrConnect.GetSockAddr(&sockaddr)) + { + closesocket(hSocket); + return false; + } #ifdef WIN32 u_long fNonblock = 1; @@ -187,7 +332,6 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) return false; } - if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { // WSAEINVAL is here because some legacy version of winsock uses it @@ -258,38 +402,76 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) 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) { - printf("proxy connecting %s\n", addrDest.ToString().c_str()); - char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; - struct sockaddr_in addr; - addrDest.GetSockAddr(&addr); - memcpy(pszSocks4IP + 2, &addr.sin_port, 2); - memcpy(pszSocks4IP + 4, &addr.sin_addr, 4); - char* pszSocks4 = pszSocks4IP; - int nSize = sizeof(pszSocks4IP); - - int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL); - if (ret != nSize) - { - closesocket(hSocket); - return error("Error sending to proxy"); - } - char pchRet[8]; - if (recv(hSocket, pchRet, 8, 0) != 8) + switch(nSocksVersion) { - closesocket(hSocket); - return error("Error reading proxy response"); - } - if (pchRet[1] != 0x5a) + case 4: + if (!Socks4(addrDest, hSocket)) + return false; + break; + + case 5: + default: + if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) + return false; + break; + } + } + + 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) { - closesocket(hSocket); - if (pchRet[1] != 0x5b) - printf("ERROR: Proxy returned error %d\n", pchRet[1]); - return false; + case 4: return false; + case 5: + default: + if (!Socks5(strDest, port, hSocket)) + return false; + break; } - printf("proxy connected %s\n", addrDest.ToString().c_str()); - } hSocketRet = hSocket; return true; @@ -590,6 +772,29 @@ void CNetAddr::print() const 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() { port = 0; |