diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-04-01 20:25:48 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2012-05-04 16:11:54 +0200 |
commit | 60a87bce873ce1f76a80b7b8546e83a0cd4e07a5 (patch) | |
tree | 524dc5f42db387f3916c2d3240defe2cf78373c4 | |
parent | 1210aa435f3518080e1b5e2f79397ff68c4978d0 (diff) |
SOCKS5 support by default
Add -socks=<n> to select SOCKS version to use. 4 and 5 are supported,
5 is default.
-rw-r--r-- | src/init.cpp | 3 | ||||
-rw-r--r-- | src/netbase.cpp | 195 |
2 files changed, 169 insertions, 29 deletions
diff --git a/src/init.cpp b/src/init.cpp index 3fe6d1b091..aa1399f813 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -178,7 +178,8 @@ bool AppInit2(int argc, char* argv[]) " -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" + " -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" + + " -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 and connect") + "\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" + 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; |