socks.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #if !defined(CURL_DISABLE_PROXY)
00026 
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_ARPA_INET_H
00031 #include <arpa/inet.h>
00032 #endif
00033 
00034 #include "urldata.h"
00035 #include "sendf.h"
00036 #include "select.h"
00037 #include "connect.h"
00038 #include "timeval.h"
00039 #include "socks.h"
00040 
00041 /* The last #include file should be: */
00042 #include "memdebug.h"
00043 
00044 /*
00045  * Helper read-from-socket functions. Does the same as Curl_read() but it
00046  * blocks until all bytes amount of buffersize will be read. No more, no less.
00047  *
00048  * This is STUPID BLOCKING behaviour which we frown upon, but right now this
00049  * is what we have...
00050  */
00051 int Curl_blockread_all(struct connectdata *conn, /* connection data */
00052                        curl_socket_t sockfd,     /* read from this socket */
00053                        char *buf,                /* store read data here */
00054                        ssize_t buffersize,       /* max amount to read */
00055                        ssize_t *n)               /* amount bytes read */
00056 {
00057   ssize_t nread;
00058   ssize_t allread = 0;
00059   int result;
00060   time_t timeleft;
00061   *n = 0;
00062   for(;;) {
00063     timeleft = Curl_timeleft(conn->data, NULL, TRUE);
00064     if(timeleft < 0) {
00065       /* we already got the timeout */
00066       result = CURLE_OPERATION_TIMEDOUT;
00067       break;
00068     }
00069     if(SOCKET_READABLE(sockfd, timeleft) <= 0) {
00070       result = ~CURLE_OK;
00071       break;
00072     }
00073     result = Curl_read_plain(sockfd, buf, buffersize, &nread);
00074     if(CURLE_AGAIN == result)
00075       continue;
00076     else if(result)
00077       break;
00078 
00079     if(buffersize == nread) {
00080       allread += nread;
00081       *n = allread;
00082       result = CURLE_OK;
00083       break;
00084     }
00085     if(!nread) {
00086       result = ~CURLE_OK;
00087       break;
00088     }
00089 
00090     buffersize -= nread;
00091     buf += nread;
00092     allread += nread;
00093   }
00094   return result;
00095 }
00096 
00097 /*
00098 * This function logs in to a SOCKS4 proxy and sends the specifics to the final
00099 * destination server.
00100 *
00101 * Reference :
00102 *   http://socks.permeo.com/protocol/socks4.protocol
00103 *
00104 * Note :
00105 *   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
00106 *   Nonsupport "Identification Protocol (RFC1413)"
00107 */
00108 CURLcode Curl_SOCKS4(const char *proxy_name,
00109                      const char *hostname,
00110                      int remote_port,
00111                      int sockindex,
00112                      struct connectdata *conn)
00113 {
00114   const bool protocol4a =
00115     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
00116 #define SOCKS4REQLEN 262
00117   unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
00118                                            id */
00119   int result;
00120   CURLcode code;
00121   curl_socket_t sock = conn->sock[sockindex];
00122   struct Curl_easy *data = conn->data;
00123 
00124   if(Curl_timeleft(data, NULL, TRUE) < 0) {
00125     /* time-out, bail out, go home */
00126     failf(data, "Connection time-out");
00127     return CURLE_OPERATION_TIMEDOUT;
00128   }
00129 
00130   if(conn->bits.httpproxy)
00131     infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
00132           protocol4a ? "a" : "", hostname, remote_port);
00133 
00134   (void)curlx_nonblock(sock, FALSE);
00135 
00136   infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
00137 
00138   /*
00139    * Compose socks4 request
00140    *
00141    * Request format
00142    *
00143    *     +----+----+----+----+----+----+----+----+----+----+....+----+
00144    *     | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
00145    *     +----+----+----+----+----+----+----+----+----+----+....+----+
00146    * # of bytes:  1    1      2              4           variable       1
00147    */
00148 
00149   socksreq[0] = 4; /* version (SOCKS4) */
00150   socksreq[1] = 1; /* connect */
00151   socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
00152   socksreq[3] = (unsigned char)(remote_port & 0xff);        /* PORT LSB */
00153 
00154   /* DNS resolve only for SOCKS4, not SOCKS4a */
00155   if(!protocol4a) {
00156     struct Curl_dns_entry *dns;
00157     Curl_addrinfo *hp=NULL;
00158     int rc;
00159 
00160     rc = Curl_resolv(conn, hostname, remote_port, &dns);
00161 
00162     if(rc == CURLRESOLV_ERROR)
00163       return CURLE_COULDNT_RESOLVE_PROXY;
00164 
00165     if(rc == CURLRESOLV_PENDING)
00166       /* ignores the return code, but 'dns' remains NULL on failure */
00167       (void)Curl_resolver_wait_resolv(conn, &dns);
00168 
00169     /*
00170      * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
00171      * returns a Curl_addrinfo pointer that may not always look the same.
00172      */
00173     if(dns)
00174       hp=dns->addr;
00175     if(hp) {
00176       char buf[64];
00177       Curl_printable_address(hp, buf, sizeof(buf));
00178 
00179       if(hp->ai_family == AF_INET) {
00180         struct sockaddr_in *saddr_in;
00181 
00182         saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
00183         socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
00184         socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
00185         socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
00186         socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
00187 
00188         infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
00189       }
00190       else {
00191         hp = NULL; /* fail! */
00192 
00193         failf(data, "SOCKS4 connection to %s not supported\n", buf);
00194       }
00195 
00196       Curl_resolv_unlock(data, dns); /* not used anymore from now on */
00197     }
00198     if(!hp) {
00199       failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
00200             hostname);
00201       return CURLE_COULDNT_RESOLVE_HOST;
00202     }
00203   }
00204 
00205   /*
00206    * This is currently not supporting "Identification Protocol (RFC1413)".
00207    */
00208   socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
00209   if(proxy_name) {
00210     size_t plen = strlen(proxy_name);
00211     if(plen >= sizeof(socksreq) - 8) {
00212       failf(data, "Too long SOCKS proxy name, can't use!\n");
00213       return CURLE_COULDNT_CONNECT;
00214     }
00215     /* copy the proxy name WITH trailing zero */
00216     memcpy(socksreq + 8, proxy_name, plen+1);
00217   }
00218 
00219   /*
00220    * Make connection
00221    */
00222   {
00223     ssize_t actualread;
00224     ssize_t written;
00225     ssize_t hostnamelen = 0;
00226     int packetsize = 9 +
00227       (int)strlen((char *)socksreq + 8); /* size including NUL */
00228 
00229     /* If SOCKS4a, set special invalid IP address 0.0.0.x */
00230     if(protocol4a) {
00231       socksreq[4] = 0;
00232       socksreq[5] = 0;
00233       socksreq[6] = 0;
00234       socksreq[7] = 1;
00235       /* If still enough room in buffer, also append hostname */
00236       hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
00237       if(packetsize + hostnamelen <= SOCKS4REQLEN)
00238         strcpy((char *)socksreq + packetsize, hostname);
00239       else
00240         hostnamelen = 0; /* Flag: hostname did not fit in buffer */
00241     }
00242 
00243     /* Send request */
00244     code = Curl_write_plain(conn, sock, (char *)socksreq,
00245                             packetsize + hostnamelen,
00246                             &written);
00247     if(code || (written != packetsize + hostnamelen)) {
00248       failf(data, "Failed to send SOCKS4 connect request.");
00249       return CURLE_COULDNT_CONNECT;
00250     }
00251     if(protocol4a && hostnamelen == 0) {
00252       /* SOCKS4a with very long hostname - send that name separately */
00253       hostnamelen = (ssize_t)strlen(hostname) + 1;
00254       code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
00255                               &written);
00256       if(code || (written != hostnamelen)) {
00257         failf(data, "Failed to send SOCKS4 connect request.");
00258         return CURLE_COULDNT_CONNECT;
00259       }
00260     }
00261 
00262     packetsize = 8; /* receive data size */
00263 
00264     /* Receive response */
00265     result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
00266                                 &actualread);
00267     if(result || (actualread != packetsize)) {
00268       failf(data, "Failed to receive SOCKS4 connect request ack.");
00269       return CURLE_COULDNT_CONNECT;
00270     }
00271 
00272     /*
00273      * Response format
00274      *
00275      *     +----+----+----+----+----+----+----+----+
00276      *     | VN | CD | DSTPORT |      DSTIP        |
00277      *     +----+----+----+----+----+----+----+----+
00278      * # of bytes:  1    1      2              4
00279      *
00280      * VN is the version of the reply code and should be 0. CD is the result
00281      * code with one of the following values:
00282      *
00283      * 90: request granted
00284      * 91: request rejected or failed
00285      * 92: request rejected because SOCKS server cannot connect to
00286      *     identd on the client
00287      * 93: request rejected because the client program and identd
00288      *     report different user-ids
00289      */
00290 
00291     /* wrong version ? */
00292     if(socksreq[0] != 0) {
00293       failf(data,
00294             "SOCKS4 reply has wrong version, version should be 4.");
00295       return CURLE_COULDNT_CONNECT;
00296     }
00297 
00298     /* Result */
00299     switch(socksreq[1]) {
00300     case 90:
00301       infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
00302       break;
00303     case 91:
00304       failf(data,
00305             "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00306             ", request rejected or failed.",
00307             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00308             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00309             (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
00310             (unsigned char)socksreq[1]);
00311       return CURLE_COULDNT_CONNECT;
00312     case 92:
00313       failf(data,
00314             "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00315             ", request rejected because SOCKS server cannot connect to "
00316             "identd on the client.",
00317             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00318             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00319             (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
00320             (unsigned char)socksreq[1]);
00321       return CURLE_COULDNT_CONNECT;
00322     case 93:
00323       failf(data,
00324             "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00325             ", request rejected because the client program and identd "
00326             "report different user-ids.",
00327             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00328             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00329             (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
00330             (unsigned char)socksreq[1]);
00331       return CURLE_COULDNT_CONNECT;
00332     default:
00333       failf(data,
00334             "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00335             ", Unknown.",
00336             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00337             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00338             (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
00339             (unsigned char)socksreq[1]);
00340       return CURLE_COULDNT_CONNECT;
00341     }
00342   }
00343 
00344   (void)curlx_nonblock(sock, TRUE);
00345 
00346   return CURLE_OK; /* Proxy was successful! */
00347 }
00348 
00349 /*
00350  * This function logs in to a SOCKS5 proxy and sends the specifics to the final
00351  * destination server.
00352  */
00353 CURLcode Curl_SOCKS5(const char *proxy_name,
00354                      const char *proxy_password,
00355                      const char *hostname,
00356                      int remote_port,
00357                      int sockindex,
00358                      struct connectdata *conn)
00359 {
00360   /*
00361     According to the RFC1928, section "6.  Replies". This is what a SOCK5
00362     replies:
00363 
00364         +----+-----+-------+------+----------+----------+
00365         |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
00366         +----+-----+-------+------+----------+----------+
00367         | 1  |  1  | X'00' |  1   | Variable |    2     |
00368         +----+-----+-------+------+----------+----------+
00369 
00370     Where:
00371 
00372     o  VER    protocol version: X'05'
00373     o  REP    Reply field:
00374     o  X'00' succeeded
00375   */
00376 
00377   unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
00378   ssize_t actualread;
00379   ssize_t written;
00380   int result;
00381   CURLcode code;
00382   curl_socket_t sock = conn->sock[sockindex];
00383   struct Curl_easy *data = conn->data;
00384   time_t timeout;
00385   bool socks5_resolve_local =
00386     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
00387   const size_t hostname_len = strlen(hostname);
00388   ssize_t len = 0;
00389 
00390   if(conn->bits.httpproxy)
00391     infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
00392           hostname, remote_port);
00393 
00394   /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
00395   if(!socks5_resolve_local && hostname_len > 255) {
00396     infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
00397           "length > 255 [actual len=%zu]\n", hostname_len);
00398     socks5_resolve_local = TRUE;
00399   }
00400 
00401   /* get timeout */
00402   timeout = Curl_timeleft(data, NULL, TRUE);
00403 
00404   if(timeout < 0) {
00405     /* time-out, bail out, go home */
00406     failf(data, "Connection time-out");
00407     return CURLE_OPERATION_TIMEDOUT;
00408   }
00409 
00410   (void)curlx_nonblock(sock, TRUE);
00411 
00412   /* wait until socket gets connected */
00413   result = SOCKET_WRITABLE(sock, timeout);
00414 
00415   if(-1 == result) {
00416     failf(conn->data, "SOCKS5: no connection here");
00417     return CURLE_COULDNT_CONNECT;
00418   }
00419   else if(0 == result) {
00420     failf(conn->data, "SOCKS5: connection timeout");
00421     return CURLE_OPERATION_TIMEDOUT;
00422   }
00423 
00424   if(result & CURL_CSELECT_ERR) {
00425     failf(conn->data, "SOCKS5: error occurred during connection");
00426     return CURLE_COULDNT_CONNECT;
00427   }
00428 
00429   socksreq[0] = 5; /* version */
00430 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00431   socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
00432   socksreq[2] = 0; /* no authentication */
00433   socksreq[3] = 1; /* GSS-API */
00434   socksreq[4] = 2; /* username/password */
00435 #else
00436   socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
00437   socksreq[2] = 0; /* no authentication */
00438   socksreq[3] = 2; /* username/password */
00439 #endif
00440 
00441   (void)curlx_nonblock(sock, FALSE);
00442 
00443   infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port);
00444 
00445   code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
00446                           &written);
00447   if(code || (written != (2 + (int)socksreq[1]))) {
00448     failf(data, "Unable to send initial SOCKS5 request.");
00449     return CURLE_COULDNT_CONNECT;
00450   }
00451 
00452   (void)curlx_nonblock(sock, TRUE);
00453 
00454   result = SOCKET_READABLE(sock, timeout);
00455 
00456   if(-1 == result) {
00457     failf(conn->data, "SOCKS5 nothing to read");
00458     return CURLE_COULDNT_CONNECT;
00459   }
00460   else if(0 == result) {
00461     failf(conn->data, "SOCKS5 read timeout");
00462     return CURLE_OPERATION_TIMEDOUT;
00463   }
00464 
00465   if(result & CURL_CSELECT_ERR) {
00466     failf(conn->data, "SOCKS5 read error occurred");
00467     return CURLE_RECV_ERROR;
00468   }
00469 
00470   (void)curlx_nonblock(sock, FALSE);
00471 
00472   result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
00473   if(result || (actualread != 2)) {
00474     failf(data, "Unable to receive initial SOCKS5 response.");
00475     return CURLE_COULDNT_CONNECT;
00476   }
00477 
00478   if(socksreq[0] != 5) {
00479     failf(data, "Received invalid version in initial SOCKS5 response.");
00480     return CURLE_COULDNT_CONNECT;
00481   }
00482   if(socksreq[1] == 0) {
00483     /* Nothing to do, no authentication needed */
00484     ;
00485   }
00486 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00487   else if(socksreq[1] == 1) {
00488     code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
00489     if(code) {
00490       failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
00491       return CURLE_COULDNT_CONNECT;
00492     }
00493   }
00494 #endif
00495   else if(socksreq[1] == 2) {
00496     /* Needs user name and password */
00497     size_t proxy_name_len, proxy_password_len;
00498     if(proxy_name && proxy_password) {
00499       proxy_name_len = strlen(proxy_name);
00500       proxy_password_len = strlen(proxy_password);
00501     }
00502     else {
00503       proxy_name_len = 0;
00504       proxy_password_len = 0;
00505     }
00506 
00507     /*   username/password request looks like
00508      * +----+------+----------+------+----------+
00509      * |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
00510      * +----+------+----------+------+----------+
00511      * | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
00512      * +----+------+----------+------+----------+
00513      */
00514     len = 0;
00515     socksreq[len++] = 1;    /* username/pw subnegotiation version */
00516     socksreq[len++] = (unsigned char) proxy_name_len;
00517     if(proxy_name && proxy_name_len)
00518       memcpy(socksreq + len, proxy_name, proxy_name_len);
00519     len += proxy_name_len;
00520     socksreq[len++] = (unsigned char) proxy_password_len;
00521     if(proxy_password && proxy_password_len)
00522       memcpy(socksreq + len, proxy_password, proxy_password_len);
00523     len += proxy_password_len;
00524 
00525     code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
00526     if(code || (len != written)) {
00527       failf(data, "Failed to send SOCKS5 sub-negotiation request.");
00528       return CURLE_COULDNT_CONNECT;
00529     }
00530 
00531     result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
00532     if(result || (actualread != 2)) {
00533       failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
00534       return CURLE_COULDNT_CONNECT;
00535     }
00536 
00537     /* ignore the first (VER) byte */
00538     if(socksreq[1] != 0) { /* status */
00539       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
00540             socksreq[0], socksreq[1]);
00541       return CURLE_COULDNT_CONNECT;
00542     }
00543 
00544     /* Everything is good so far, user was authenticated! */
00545   }
00546   else {
00547     /* error */
00548 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00549     if(socksreq[1] == 255) {
00550 #else
00551     if(socksreq[1] == 1) {
00552       failf(data,
00553             "SOCKS5 GSSAPI per-message authentication is not supported.");
00554       return CURLE_COULDNT_CONNECT;
00555     }
00556     else if(socksreq[1] == 255) {
00557 #endif
00558       if(!proxy_name || !*proxy_name) {
00559         failf(data,
00560               "No authentication method was acceptable. (It is quite likely"
00561               " that the SOCKS5 server wanted a username/password, since none"
00562               " was supplied to the server on this connection.)");
00563       }
00564       else {
00565         failf(data, "No authentication method was acceptable.");
00566       }
00567       return CURLE_COULDNT_CONNECT;
00568     }
00569     else {
00570       failf(data,
00571             "Undocumented SOCKS5 mode attempted to be used by server.");
00572       return CURLE_COULDNT_CONNECT;
00573     }
00574   }
00575 
00576   /* Authentication is complete, now specify destination to the proxy */
00577   len = 0;
00578   socksreq[len++] = 5; /* version (SOCKS5) */
00579   socksreq[len++] = 1; /* connect */
00580   socksreq[len++] = 0; /* must be zero */
00581 
00582   if(!socks5_resolve_local) {
00583     socksreq[len++] = 3; /* ATYP: domain name = 3 */
00584     socksreq[len++] = (char) hostname_len; /* address length */
00585     memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */
00586     len += hostname_len;
00587   }
00588   else {
00589     struct Curl_dns_entry *dns;
00590     Curl_addrinfo *hp = NULL;
00591     int rc = Curl_resolv(conn, hostname, remote_port, &dns);
00592 
00593     if(rc == CURLRESOLV_ERROR)
00594       return CURLE_COULDNT_RESOLVE_HOST;
00595 
00596     if(rc == CURLRESOLV_PENDING) {
00597       /* this requires that we're in "wait for resolve" state */
00598       code = Curl_resolver_wait_resolv(conn, &dns);
00599       if(code)
00600         return code;
00601     }
00602 
00603     /*
00604      * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
00605      * returns a Curl_addrinfo pointer that may not always look the same.
00606      */
00607     if(dns)
00608       hp=dns->addr;
00609     if(hp) {
00610       int i;
00611       char buf[64];
00612       Curl_printable_address(hp, buf, sizeof(buf));
00613 
00614       if(hp->ai_family == AF_INET) {
00615         struct sockaddr_in *saddr_in;
00616         socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
00617 
00618         saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
00619         for(i = 0; i < 4; i++) {
00620           socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
00621         }
00622 
00623         infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf);
00624       }
00625 #ifdef ENABLE_IPV6
00626       else if(hp->ai_family == AF_INET6) {
00627         struct sockaddr_in6 *saddr_in6;
00628         socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
00629 
00630         saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
00631         for(i = 0; i < 16; i++) {
00632           socksreq[len++] =
00633             ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
00634         }
00635 
00636         infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf);
00637       }
00638 #endif
00639       else {
00640         hp = NULL; /* fail! */
00641 
00642         failf(data, "SOCKS5 connection to %s not supported\n", buf);
00643       }
00644 
00645       Curl_resolv_unlock(data, dns); /* not used anymore from now on */
00646     }
00647     if(!hp) {
00648       failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
00649             hostname);
00650       return CURLE_COULDNT_RESOLVE_HOST;
00651     }
00652   }
00653 
00654   socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
00655   socksreq[len++] = (unsigned char)(remote_port & 0xff);        /* PORT LSB */
00656 
00657 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00658   if(conn->socks5_gssapi_enctype) {
00659     failf(data, "SOCKS5 GSS-API protection not yet implemented.");
00660   }
00661   else
00662 #endif
00663     code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
00664 
00665   if(code || (len != written)) {
00666     failf(data, "Failed to send SOCKS5 connect request.");
00667     return CURLE_COULDNT_CONNECT;
00668   }
00669 
00670   len = 10; /* minimum packet size is 10 */
00671 
00672 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00673   if(conn->socks5_gssapi_enctype) {
00674     failf(data, "SOCKS5 GSS-API protection not yet implemented.");
00675   }
00676   else
00677 #endif
00678     result = Curl_blockread_all(conn, sock, (char *)socksreq,
00679                                 len, &actualread);
00680 
00681   if(result || (len != actualread)) {
00682     failf(data, "Failed to receive SOCKS5 connect request ack.");
00683     return CURLE_COULDNT_CONNECT;
00684   }
00685 
00686   if(socksreq[0] != 5) { /* version */
00687     failf(data,
00688           "SOCKS5 reply has wrong version, version should be 5.");
00689     return CURLE_COULDNT_CONNECT;
00690   }
00691 
00692   /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
00693      1928, so the reply packet should be read until the end to avoid errors at
00694      subsequent protocol level.
00695 
00696     +----+-----+-------+------+----------+----------+
00697     |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
00698     +----+-----+-------+------+----------+----------+
00699     | 1  |  1  | X'00' |  1   | Variable |    2     |
00700     +----+-----+-------+------+----------+----------+
00701 
00702      ATYP:
00703      o  IP v4 address: X'01', BND.ADDR = 4 byte
00704      o  domain name:  X'03', BND.ADDR = [ 1 byte length, string ]
00705      o  IP v6 address: X'04', BND.ADDR = 16 byte
00706      */
00707 
00708   /* Calculate real packet size */
00709   if(socksreq[3] == 3) {
00710     /* domain name */
00711     int addrlen = (int) socksreq[4];
00712     len = 5 + addrlen + 2;
00713   }
00714   else if(socksreq[3] == 4) {
00715     /* IPv6 */
00716     len = 4 + 16 + 2;
00717   }
00718 
00719   /* At this point we already read first 10 bytes */
00720 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00721   if(!conn->socks5_gssapi_enctype) {
00722     /* decrypt_gssapi_blockread already read the whole packet */
00723 #endif
00724     if(len > 10) {
00725       result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
00726                                   len - 10, &actualread);
00727       if(result || ((len - 10) != actualread)) {
00728         failf(data, "Failed to receive SOCKS5 connect request ack.");
00729         return CURLE_COULDNT_CONNECT;
00730       }
00731     }
00732 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
00733   }
00734 #endif
00735 
00736   if(socksreq[1] != 0) { /* Anything besides 0 is an error */
00737     if(socksreq[3] == 1) {
00738       failf(data,
00739             "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
00740             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00741             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00742             (((unsigned char)socksreq[8] << 8) |
00743              (unsigned char)socksreq[9]),
00744             (unsigned char)socksreq[1]);
00745     }
00746     else if(socksreq[3] == 3) {
00747       unsigned char port_upper = (unsigned char)socksreq[len - 2];
00748       socksreq[len - 2] = 0;
00749       failf(data,
00750             "Can't complete SOCKS5 connection to %s:%d. (%d)",
00751             (char *)&socksreq[5],
00752             ((port_upper << 8) |
00753              (unsigned char)socksreq[len - 1]),
00754             (unsigned char)socksreq[1]);
00755       socksreq[len - 2] = port_upper;
00756     }
00757     else if(socksreq[3] == 4) {
00758       failf(data,
00759             "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:"
00760             "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)",
00761             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00762             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00763             (unsigned char)socksreq[8], (unsigned char)socksreq[9],
00764             (unsigned char)socksreq[10], (unsigned char)socksreq[11],
00765             (unsigned char)socksreq[12], (unsigned char)socksreq[13],
00766             (unsigned char)socksreq[14], (unsigned char)socksreq[15],
00767             (unsigned char)socksreq[16], (unsigned char)socksreq[17],
00768             (unsigned char)socksreq[18], (unsigned char)socksreq[19],
00769             (((unsigned char)socksreq[20] << 8) |
00770              (unsigned char)socksreq[21]),
00771             (unsigned char)socksreq[1]);
00772     }
00773     return CURLE_COULDNT_CONNECT;
00774   }
00775   else {
00776     infof(data, "SOCKS5 request granted.\n");
00777   }
00778 
00779   (void)curlx_nonblock(sock, TRUE);
00780   return CURLE_OK; /* Proxy was successful! */
00781 }
00782 
00783 #endif /* CURL_DISABLE_PROXY */
00784 


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06