[Pkg-bitcoin-commits] [bitcoin] 59/126: net: Improve and document SOCKS code

Jonas Smedegaard dr at jones.dk
Mon Nov 13 20:02:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to annotated tag debian/0.15.1_dfsg-1
in repository bitcoin.

commit 27e861a9b394857b0005347962ced92ac65e5dac
Author: Wladimir J. van der Laan <laanwj at gmail.com>
Date:   Sat Sep 23 10:36:23 2017 +0200

    net: Improve and document SOCKS code
    
    Make the SOCKS code more consistent, and document the constants used.
    
    Github-Pull: #11397
    Rebased-From: 22f816ef4dd57785627d801c247714cace7fc5b5
---
 src/netbase.cpp | 125 ++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 89 insertions(+), 36 deletions(-)

diff --git a/src/netbase.cpp b/src/netbase.cpp
index 05f9f69..914124c 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -184,6 +184,48 @@ struct timeval MillisToTimeval(int64_t nTimeout)
     return timeout;
 }
 
+/** SOCKS version */
+enum SOCKSVersion: uint8_t {
+    SOCKS4 = 0x04,
+    SOCKS5 = 0x05
+};
+
+/** Values defined for METHOD in RFC1928 */
+enum SOCKS5Method: uint8_t {
+    NOAUTH = 0x00,        //! No authentication required
+    GSSAPI = 0x01,        //! GSSAPI
+    USER_PASS = 0x02,     //! Username/password
+    NO_ACCEPTABLE = 0xff, //! No acceptable methods
+};
+
+/** Values defined for CMD in RFC1928 */
+enum SOCKS5Command: uint8_t {
+    CONNECT = 0x01,
+    BIND = 0x02,
+    UDP_ASSOCIATE = 0x03
+};
+
+/** Values defined for REP in RFC1928 */
+enum SOCKS5Reply: uint8_t {
+    SUCCEEDED = 0x00,        //! Succeeded
+    GENFAILURE = 0x01,       //! General failure
+    NOTALLOWED = 0x02,       //! Connection not allowed by ruleset
+    NETUNREACHABLE = 0x03,   //! Network unreachable
+    HOSTUNREACHABLE = 0x04,  //! Network unreachable
+    CONNREFUSED = 0x05,      //! Connection refused
+    TTLEXPIRED = 0x06,       //! TTL expired
+    CMDUNSUPPORTED = 0x07,   //! Command not supported
+    ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+};
+
+/** Values defined for ATYPE in RFC1928 */
+enum SOCKS5Atyp: uint8_t {
+    IPV4 = 0x01,
+    DOMAINNAME = 0x03,
+    IPV6 = 0x04,
+};
+
+/** Status codes that can be returned by InterruptibleRecv */
 enum class IntrRecvError {
     OK,
     Timeout,
@@ -203,7 +245,7 @@ enum class IntrRecvError {
  *
  * @note This function requires that hSocket is in non-blocking mode.
  */
-static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, const SOCKET& hSocket)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
 {
     int64_t curTime = GetTimeMillis();
     int64_t endTime = curTime + timeout;
@@ -211,7 +253,7 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
     // to break off in case of an interruption.
     const int64_t maxWait = 1000;
     while (len > 0 && curTime < endTime) {
-        ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
+        ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
         if (ret > 0) {
             len -= ret;
             data += ret;
@@ -242,24 +284,35 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
     return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
 }
 
+/** Credentials for proxy authentication */
 struct ProxyCredentials
 {
     std::string username;
     std::string password;
 };
 
-std::string Socks5ErrorString(int err)
+/** Convert SOCKS5 reply to a an error message */
+std::string Socks5ErrorString(uint8_t err)
 {
     switch(err) {
-        case 0x01: return "general failure";
-        case 0x02: return "connection not allowed";
-        case 0x03: return "network unreachable";
-        case 0x04: return "host unreachable";
-        case 0x05: return "connection refused";
-        case 0x06: return "TTL expired";
-        case 0x07: return "protocol error";
-        case 0x08: return "address type not supported";
-        default:   return "unknown";
+        case SOCKS5Reply::GENFAILURE:
+            return "general failure";
+        case SOCKS5Reply::NOTALLOWED:
+            return "connection not allowed";
+        case SOCKS5Reply::NETUNREACHABLE:
+            return "network unreachable";
+        case SOCKS5Reply::HOSTUNREACHABLE:
+            return "host unreachable";
+        case SOCKS5Reply::CONNREFUSED:
+            return "connection refused";
+        case SOCKS5Reply::TTLEXPIRED:
+            return "TTL expired";
+        case SOCKS5Reply::CMDUNSUPPORTED:
+            return "protocol error";
+        case SOCKS5Reply::ATYPEUNSUPPORTED:
+            return "address type not supported";
+        default:
+            return "unknown";
     }
 }
 
@@ -274,34 +327,34 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
     }
     // Accepted authentication methods
     std::vector<uint8_t> vSocks5Init;
-    vSocks5Init.push_back(0x05);
+    vSocks5Init.push_back(SOCKSVersion::SOCKS5);
     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)
+        vSocks5Init.push_back(0x02); // Number of methods
+        vSocks5Init.push_back(SOCKS5Method::NOAUTH);
+        vSocks5Init.push_back(SOCKS5Method::USER_PASS);
     } else {
-        vSocks5Init.push_back(0x01); // # METHODS
-        vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+        vSocks5Init.push_back(0x01); // Number of methods
+        vSocks5Init.push_back(SOCKS5Method::NOAUTH);
     }
     ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
     if (ret != (ssize_t)vSocks5Init.size()) {
         CloseSocket(hSocket);
         return error("Error sending to proxy");
     }
-    char pchRet1[2];
+    uint8_t pchRet1[2];
     if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
         CloseSocket(hSocket);
         LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
         return false;
     }
-    if (pchRet1[0] != 0x05) {
+    if (pchRet1[0] != SOCKSVersion::SOCKS5) {
         CloseSocket(hSocket);
         return error("Proxy failed to initialize");
     }
-    if (pchRet1[1] == 0x02 && auth) {
+    if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
         // Perform username/password authentication (as described in RFC1929)
         std::vector<uint8_t> vAuth;
-        vAuth.push_back(0x01);
+        vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
         if (auth->username.size() > 255 || auth->password.size() > 255)
             return error("Proxy username or password too long");
         vAuth.push_back(auth->username.size());
@@ -314,7 +367,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
             return error("Error sending authentication to proxy");
         }
         LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
-        char pchRetA[2];
+        uint8_t pchRetA[2];
         if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
             CloseSocket(hSocket);
             return error("Error reading proxy authentication response");
@@ -323,17 +376,17 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
             CloseSocket(hSocket);
             return error("Proxy authentication unsuccessful");
         }
-    } else if (pchRet1[1] == 0x00) {
+    } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
         // 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(SOCKSVersion::SOCKS5); // VER protocol version
+    vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
+    vSocks5.push_back(0x00); // RSV Reserved must be 0
+    vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // 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);
@@ -343,7 +396,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
         CloseSocket(hSocket);
         return error("Error sending to proxy");
     }
-    char pchRet2[4];
+    uint8_t pchRet2[4];
     if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
         CloseSocket(hSocket);
         if (recvr == IntrRecvError::Timeout) {
@@ -355,26 +408,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
             return error("Error while reading proxy response");
         }
     }
-    if (pchRet2[0] != 0x05) {
+    if (pchRet2[0] != SOCKSVersion::SOCKS5) {
         CloseSocket(hSocket);
         return error("Proxy failed to accept request");
     }
-    if (pchRet2[1] != 0x00) {
+    if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
         // Failures to connect to a peer that are not proxy errors
         CloseSocket(hSocket);
         LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
         return false;
     }
-    if (pchRet2[2] != 0x00) {
+    if (pchRet2[2] != 0x00) { // Reserved field must be 0
         CloseSocket(hSocket);
         return error("Error: malformed proxy response");
     }
-    char pchRet3[256];
+    uint8_t pchRet3[256];
     switch (pchRet2[3])
     {
-        case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
-        case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
-        case 0x03:
+        case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
+        case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
+        case SOCKS5Atyp::DOMAINNAME:
         {
             recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
             if (recvr != IntrRecvError::OK) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-bitcoin/bitcoin.git



More information about the Pkg-bitcoin-commits mailing list