From 60a87bce873ce1f76a80b7b8546e83a0cd4e07a5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 1 Apr 2012 20:25:48 +0200 Subject: SOCKS5 support by default Add -socks= to select SOCKS version to use. 4 and 5 are supported, 5 is default. --- src/netbase.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 167 insertions(+), 28 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 8b30ffc140..3c818f76f5 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -156,6 +156,161 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault) return Lookup(pszName, addr, portDefault, false); } +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(const CService &addrDest, SOCKET& hSocket) +{ + printf("SOCKS5 connecting %s\n", addrDest.ToString().c_str()); + 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"); + } + char pszSocks5IPv4[] = "\5\1\0\1\0\0\0\0\0\0"; + char pszSocks5IPv6[] = "\5\1\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + if (addrDest.IsIPv4()) + { + struct sockaddr_in addr; + addrDest.GetSockAddr(&addr); + memcpy(pszSocks5IPv4 + 4, &addr.sin_addr, 4); + memcpy(pszSocks5IPv4 + 8, &addr.sin_port, 2); + pszSocks5 = pszSocks5IPv4; + nSize = sizeof(pszSocks5IPv4); + } + else + { +#ifdef USE_IPV6 + struct sockaddr_in6 addr; + addrDest.GetSockAddr6(&addr); + memcpy(pszSocks5IPv6 + 4, &addr.sin6_addr, 16); + memcpy(pszSocks5IPv6 + 20, &addr.sin6_port, 2); + pszSocks5 = pszSocks5IPv6; + nSize = sizeof(pszSocks5IPv6); +#else + return error("IPv6 support is not compiled in"); +#endif + } + ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); + if (ret != nSize) + { + 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", addrDest.ToString().c_str()); + return true; +} + bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; @@ -260,35 +415,19 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) 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) - { - closesocket(hSocket); - return error("Error reading proxy response"); - } - if (pchRet[1] != 0x5a) + switch(GetArg("-socks", 5)) { - closesocket(hSocket); - if (pchRet[1] != 0x5b) - printf("ERROR: Proxy returned error %d\n", pchRet[1]); - return false; - } - printf("proxy connected %s\n", addrDest.ToString().c_str()); + case 4: + if (!Socks4(addrDest, hSocket)) + return false; + break; + + case 5: + default: + if (!Socks5(addrDest, hSocket)) + return false; + break; + } } hSocketRet = hSocket; -- cgit v1.2.3 From 933f2715d8ff9548cdf90cd3cdec3bda79b898c2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Apr 2012 16:13:30 +0200 Subject: SOCKS5 connect via hostname --- src/netbase.cpp | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 3c818f76f5..2c131947bb 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -219,32 +219,15 @@ bool static Socks5(const CService &addrDest, SOCKET& hSocket) closesocket(hSocket); return error("Proxy failed to initialize"); } - char pszSocks5IPv4[] = "\5\1\0\1\0\0\0\0\0\0"; - char pszSocks5IPv6[] = "\5\1\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - if (addrDest.IsIPv4()) - { - struct sockaddr_in addr; - addrDest.GetSockAddr(&addr); - memcpy(pszSocks5IPv4 + 4, &addr.sin_addr, 4); - memcpy(pszSocks5IPv4 + 8, &addr.sin_port, 2); - pszSocks5 = pszSocks5IPv4; - nSize = sizeof(pszSocks5IPv4); - } - else - { -#ifdef USE_IPV6 - struct sockaddr_in6 addr; - addrDest.GetSockAddr6(&addr); - memcpy(pszSocks5IPv6 + 4, &addr.sin6_addr, 16); - memcpy(pszSocks5IPv6 + 20, &addr.sin6_port, 2); - pszSocks5 = pszSocks5IPv6; - nSize = sizeof(pszSocks5IPv6); -#else - return error("IPv6 support is not compiled in"); -#endif - } - ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); - if (ret != nSize) + string strSocks5("\5\1"); + strSocks5 += '\000'; strSocks5 += '\003'; + string strDest = addrDest.ToStringIP(); + strSocks5 += static_cast(std::min((int)strDest.size(), 255)); + strSocks5 += strDest; + strSocks5 += static_cast((addrDest.GetPort() >> 8) & 0xFF); + strSocks5 += static_cast((addrDest.GetPort() >> 0) & 0xFF); + ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); + if (ret != strSocks5.size()) { closesocket(hSocket); return error("Error sending to proxy"); -- cgit v1.2.3 From a012e2db59585bfa1978615aacade281053e0ae5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Apr 2012 17:02:21 +0200 Subject: refactor ConnectSocket --- src/netbase.cpp | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 2c131947bb..60f34bbd30 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -195,9 +195,14 @@ bool static Socks4(const CService &addrDest, SOCKET& hSocket) return true; } -bool static Socks5(const CService &addrDest, SOCKET& hSocket) +bool static Socks5(string strDest, int port, SOCKET& hSocket) { - printf("SOCKS5 connecting %s\n", addrDest.ToString().c_str()); + 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); @@ -221,11 +226,10 @@ bool static Socks5(const CService &addrDest, SOCKET& hSocket) } string strSocks5("\5\1"); strSocks5 += '\000'; strSocks5 += '\003'; - string strDest = addrDest.ToStringIP(); strSocks5 += static_cast(std::min((int)strDest.size(), 255)); - strSocks5 += strDest; - strSocks5 += static_cast((addrDest.GetPort() >> 8) & 0xFF); - strSocks5 += static_cast((addrDest.GetPort() >> 0) & 0xFF); + strSocks5 += strDest; + strSocks5 += static_cast((port >> 8) & 0xFF); + strSocks5 += static_cast((port >> 0) & 0xFF); ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); if (ret != strSocks5.size()) { @@ -290,11 +294,11 @@ bool static Socks5(const CService &addrDest, SOCKET& hSocket) closesocket(hSocket); return error("Error reading from proxy"); } - printf("SOCKS5 connected %s\n", addrDest.ToString().c_str()); + printf("SOCKS5 connected %s\n", strDest.c_str()); return true; } -bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) +bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; @@ -396,6 +400,18 @@ 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) { switch(GetArg("-socks", 5)) @@ -407,7 +423,7 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) case 5: default: - if (!Socks5(addrDest, hSocket)) + if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) return false; break; } -- cgit v1.2.3 From 9bab521df895c149579b9e64931405c56b008afb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Apr 2012 17:38:03 +0200 Subject: Support connecting by hostnames passed to proxy (-proxydns) --- src/netbase.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index 60f34bbd30..a9cc0cf4d3 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; @@ -310,12 +313,12 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe 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; @@ -329,7 +332,6 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe return false; } - if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { // WSAEINVAL is here because some legacy version of winsock uses it @@ -414,7 +416,7 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) if (fProxy) { - switch(GetArg("-socks", 5)) + switch(nSocksVersion) { case 4: if (!Socks4(addrDest, hSocket)) @@ -433,6 +435,48 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) 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; + return true; +} + void CNetAddr::Init() { memset(ip, 0, 16); -- cgit v1.2.3 From 39857190dee3ed296112cfcfd79b0a375143b6c6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 12 Feb 2012 13:45:24 +0100 Subject: Support for multiple local addresses --- src/netbase.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/netbase.cpp') diff --git a/src/netbase.cpp b/src/netbase.cpp index a9cc0cf4d3..4fe3fb61da 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -772,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; -- cgit v1.2.3