socks.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #if !defined(CURL_DISABLE_PROXY)
26 
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
32 #endif
33 
34 #include "urldata.h"
35 #include "sendf.h"
36 #include "select.h"
37 #include "connect.h"
38 #include "timeval.h"
39 #include "socks.h"
40 
41 /* The last #include file should be: */
42 #include "memdebug.h"
43 
44 /*
45  * Helper read-from-socket functions. Does the same as Curl_read() but it
46  * blocks until all bytes amount of buffersize will be read. No more, no less.
47  *
48  * This is STUPID BLOCKING behaviour which we frown upon, but right now this
49  * is what we have...
50  */
51 int Curl_blockread_all(struct connectdata *conn, /* connection data */
52  curl_socket_t sockfd, /* read from this socket */
53  char *buf, /* store read data here */
54  ssize_t buffersize, /* max amount to read */
55  ssize_t *n) /* amount bytes read */
56 {
57  ssize_t nread;
58  ssize_t allread = 0;
59  int result;
60  time_t timeleft;
61  *n = 0;
62  for(;;) {
63  timeleft = Curl_timeleft(conn->data, NULL, TRUE);
64  if(timeleft < 0) {
65  /* we already got the timeout */
66  result = CURLE_OPERATION_TIMEDOUT;
67  break;
68  }
69  if(SOCKET_READABLE(sockfd, timeleft) <= 0) {
70  result = ~CURLE_OK;
71  break;
72  }
73  result = Curl_read_plain(sockfd, buf, buffersize, &nread);
74  if(CURLE_AGAIN == result)
75  continue;
76  if(result)
77  break;
78 
79  if(buffersize == nread) {
80  allread += nread;
81  *n = allread;
82  result = CURLE_OK;
83  break;
84  }
85  if(!nread) {
86  result = ~CURLE_OK;
87  break;
88  }
89 
90  buffersize -= nread;
91  buf += nread;
92  allread += nread;
93  }
94  return result;
95 }
96 
97 /*
98 * This function logs in to a SOCKS4 proxy and sends the specifics to the final
99 * destination server.
100 *
101 * Reference :
102 * http://socks.permeo.com/protocol/socks4.protocol
103 *
104 * Note :
105 * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
106 * Nonsupport "Identification Protocol (RFC1413)"
107 */
108 CURLcode Curl_SOCKS4(const char *proxy_user,
109  const char *hostname,
110  int remote_port,
111  int sockindex,
112  struct connectdata *conn)
113 {
114  const bool protocol4a =
116 #define SOCKS4REQLEN 262
117  unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
118  id */
119  int result;
120  CURLcode code;
121  curl_socket_t sock = conn->sock[sockindex];
122  struct Curl_easy *data = conn->data;
123 
124  if(Curl_timeleft(data, NULL, TRUE) < 0) {
125  /* time-out, bail out, go home */
126  failf(data, "Connection time-out");
128  }
129 
130  if(conn->bits.httpproxy)
131  infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
132  protocol4a ? "a" : "", hostname, remote_port);
133 
134  (void)curlx_nonblock(sock, FALSE);
135 
136  infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
137 
138  /*
139  * Compose socks4 request
140  *
141  * Request format
142  *
143  * +----+----+----+----+----+----+----+----+----+----+....+----+
144  * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
145  * +----+----+----+----+----+----+----+----+----+----+....+----+
146  * # of bytes: 1 1 2 4 variable 1
147  */
148 
149  socksreq[0] = 4; /* version (SOCKS4) */
150  socksreq[1] = 1; /* connect */
151  socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
152  socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
153 
154  /* DNS resolve only for SOCKS4, not SOCKS4a */
155  if(!protocol4a) {
156  struct Curl_dns_entry *dns;
157  Curl_addrinfo *hp = NULL;
158  int rc;
159 
160  rc = Curl_resolv(conn, hostname, remote_port, &dns);
161 
162  if(rc == CURLRESOLV_ERROR)
164 
165  if(rc == CURLRESOLV_PENDING)
166  /* ignores the return code, but 'dns' remains NULL on failure */
167  (void)Curl_resolver_wait_resolv(conn, &dns);
168 
169  /*
170  * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
171  * returns a Curl_addrinfo pointer that may not always look the same.
172  */
173  if(dns)
174  hp = dns->addr;
175  if(hp) {
176  char buf[64];
177  Curl_printable_address(hp, buf, sizeof(buf));
178 
179  if(hp->ai_family == AF_INET) {
180  struct sockaddr_in *saddr_in;
181 
182  saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
183  socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
184  socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
185  socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
186  socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
187 
188  infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
189  }
190  else {
191  hp = NULL; /* fail! */
192 
193  failf(data, "SOCKS4 connection to %s not supported\n", buf);
194  }
195 
196  Curl_resolv_unlock(data, dns); /* not used anymore from now on */
197  }
198  if(!hp) {
199  failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
200  hostname);
202  }
203  }
204 
205  /*
206  * This is currently not supporting "Identification Protocol (RFC1413)".
207  */
208  socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
209  if(proxy_user) {
210  size_t plen = strlen(proxy_user);
211  if(plen >= sizeof(socksreq) - 8) {
212  failf(data, "Too long SOCKS proxy name, can't use!\n");
213  return CURLE_COULDNT_CONNECT;
214  }
215  /* copy the proxy name WITH trailing zero */
216  memcpy(socksreq + 8, proxy_user, plen + 1);
217  }
218 
219  /*
220  * Make connection
221  */
222  {
223  ssize_t actualread;
224  ssize_t written;
225  ssize_t hostnamelen = 0;
226  int packetsize = 9 +
227  (int)strlen((char *)socksreq + 8); /* size including NUL */
228 
229  /* If SOCKS4a, set special invalid IP address 0.0.0.x */
230  if(protocol4a) {
231  socksreq[4] = 0;
232  socksreq[5] = 0;
233  socksreq[6] = 0;
234  socksreq[7] = 1;
235  /* If still enough room in buffer, also append hostname */
236  hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
237  if(packetsize + hostnamelen <= SOCKS4REQLEN)
238  strcpy((char *)socksreq + packetsize, hostname);
239  else
240  hostnamelen = 0; /* Flag: hostname did not fit in buffer */
241  }
242 
243  /* Send request */
244  code = Curl_write_plain(conn, sock, (char *)socksreq,
245  packetsize + hostnamelen,
246  &written);
247  if(code || (written != packetsize + hostnamelen)) {
248  failf(data, "Failed to send SOCKS4 connect request.");
249  return CURLE_COULDNT_CONNECT;
250  }
251  if(protocol4a && hostnamelen == 0) {
252  /* SOCKS4a with very long hostname - send that name separately */
253  hostnamelen = (ssize_t)strlen(hostname) + 1;
254  code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
255  &written);
256  if(code || (written != hostnamelen)) {
257  failf(data, "Failed to send SOCKS4 connect request.");
258  return CURLE_COULDNT_CONNECT;
259  }
260  }
261 
262  packetsize = 8; /* receive data size */
263 
264  /* Receive response */
265  result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
266  &actualread);
267  if(result || (actualread != packetsize)) {
268  failf(data, "Failed to receive SOCKS4 connect request ack.");
269  return CURLE_COULDNT_CONNECT;
270  }
271 
272  /*
273  * Response format
274  *
275  * +----+----+----+----+----+----+----+----+
276  * | VN | CD | DSTPORT | DSTIP |
277  * +----+----+----+----+----+----+----+----+
278  * # of bytes: 1 1 2 4
279  *
280  * VN is the version of the reply code and should be 0. CD is the result
281  * code with one of the following values:
282  *
283  * 90: request granted
284  * 91: request rejected or failed
285  * 92: request rejected because SOCKS server cannot connect to
286  * identd on the client
287  * 93: request rejected because the client program and identd
288  * report different user-ids
289  */
290 
291  /* wrong version ? */
292  if(socksreq[0] != 0) {
293  failf(data,
294  "SOCKS4 reply has wrong version, version should be 4.");
295  return CURLE_COULDNT_CONNECT;
296  }
297 
298  /* Result */
299  switch(socksreq[1]) {
300  case 90:
301  infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
302  break;
303  case 91:
304  failf(data,
305  "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
306  ", request rejected or failed.",
307  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
308  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
309  (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
310  (unsigned char)socksreq[1]);
311  return CURLE_COULDNT_CONNECT;
312  case 92:
313  failf(data,
314  "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
315  ", request rejected because SOCKS server cannot connect to "
316  "identd on the client.",
317  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
318  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
319  (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
320  (unsigned char)socksreq[1]);
321  return CURLE_COULDNT_CONNECT;
322  case 93:
323  failf(data,
324  "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
325  ", request rejected because the client program and identd "
326  "report different user-ids.",
327  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
328  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
329  (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
330  (unsigned char)socksreq[1]);
331  return CURLE_COULDNT_CONNECT;
332  default:
333  failf(data,
334  "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
335  ", Unknown.",
336  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
337  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
338  (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
339  (unsigned char)socksreq[1]);
340  return CURLE_COULDNT_CONNECT;
341  }
342  }
343 
344  (void)curlx_nonblock(sock, TRUE);
345 
346  return CURLE_OK; /* Proxy was successful! */
347 }
348 
349 /*
350  * This function logs in to a SOCKS5 proxy and sends the specifics to the final
351  * destination server.
352  */
353 CURLcode Curl_SOCKS5(const char *proxy_user,
354  const char *proxy_password,
355  const char *hostname,
356  int remote_port,
357  int sockindex,
358  struct connectdata *conn)
359 {
360  /*
361  According to the RFC1928, section "6. Replies". This is what a SOCK5
362  replies:
363 
364  +----+-----+-------+------+----------+----------+
365  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
366  +----+-----+-------+------+----------+----------+
367  | 1 | 1 | X'00' | 1 | Variable | 2 |
368  +----+-----+-------+------+----------+----------+
369 
370  Where:
371 
372  o VER protocol version: X'05'
373  o REP Reply field:
374  o X'00' succeeded
375  */
376 
377  unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
378  int idx;
379  ssize_t actualread;
380  ssize_t written;
381  int result;
382  CURLcode code;
383  curl_socket_t sock = conn->sock[sockindex];
384  struct Curl_easy *data = conn->data;
385  time_t timeout;
386  bool socks5_resolve_local =
388  const size_t hostname_len = strlen(hostname);
389  ssize_t len = 0;
390  const unsigned long auth = data->set.socks5auth;
391  bool allow_gssapi = FALSE;
392 
393  if(conn->bits.httpproxy)
394  infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
395  hostname, remote_port);
396 
397  /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
398  if(!socks5_resolve_local && hostname_len > 255) {
399  infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
400  "length > 255 [actual len=%zu]\n", hostname_len);
401  socks5_resolve_local = TRUE;
402  }
403 
404  /* get timeout */
405  timeout = Curl_timeleft(data, NULL, TRUE);
406 
407  if(timeout < 0) {
408  /* time-out, bail out, go home */
409  failf(data, "Connection time-out");
411  }
412 
413  (void)curlx_nonblock(sock, TRUE);
414 
415  /* wait until socket gets connected */
416  result = SOCKET_WRITABLE(sock, timeout);
417 
418  if(-1 == result) {
419  failf(conn->data, "SOCKS5: no connection here");
420  return CURLE_COULDNT_CONNECT;
421  }
422  if(0 == result) {
423  failf(conn->data, "SOCKS5: connection timeout");
425  }
426 
427  if(result & CURL_CSELECT_ERR) {
428  failf(conn->data, "SOCKS5: error occurred during connection");
429  return CURLE_COULDNT_CONNECT;
430  }
431 
432  if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
433  infof(conn->data,
434  "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
435  auth);
436  if(!(auth & CURLAUTH_BASIC))
437  /* disable username/password auth */
438  proxy_user = NULL;
439 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
440  if(auth & CURLAUTH_GSSAPI)
441  allow_gssapi = TRUE;
442 #endif
443 
444  idx = 0;
445  socksreq[idx++] = 5; /* version */
446  idx++; /* reserve for the number of authentication methods */
447  socksreq[idx++] = 0; /* no authentication */
448  if(allow_gssapi)
449  socksreq[idx++] = 1; /* GSS-API */
450  if(proxy_user)
451  socksreq[idx++] = 2; /* username/password */
452  /* write the number of authentication methods */
453  socksreq[1] = (unsigned char) (idx - 2);
454 
455  (void)curlx_nonblock(sock, FALSE);
456 
457  infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port);
458 
459  code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
460  &written);
461  if(code || (written != (2 + (int)socksreq[1]))) {
462  failf(data, "Unable to send initial SOCKS5 request.");
463  return CURLE_COULDNT_CONNECT;
464  }
465 
466  (void)curlx_nonblock(sock, TRUE);
467 
468  result = SOCKET_READABLE(sock, timeout);
469 
470  if(-1 == result) {
471  failf(conn->data, "SOCKS5 nothing to read");
472  return CURLE_COULDNT_CONNECT;
473  }
474  if(0 == result) {
475  failf(conn->data, "SOCKS5 read timeout");
477  }
478 
479  if(result & CURL_CSELECT_ERR) {
480  failf(conn->data, "SOCKS5 read error occurred");
481  return CURLE_RECV_ERROR;
482  }
483 
484  (void)curlx_nonblock(sock, FALSE);
485 
486  result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
487  if(result || (actualread != 2)) {
488  failf(data, "Unable to receive initial SOCKS5 response.");
489  return CURLE_COULDNT_CONNECT;
490  }
491 
492  if(socksreq[0] != 5) {
493  failf(data, "Received invalid version in initial SOCKS5 response.");
494  return CURLE_COULDNT_CONNECT;
495  }
496  if(socksreq[1] == 0) {
497  /* Nothing to do, no authentication needed */
498  ;
499  }
500 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
501  else if(allow_gssapi && (socksreq[1] == 1)) {
502  code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
503  if(code) {
504  failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
505  return CURLE_COULDNT_CONNECT;
506  }
507  }
508 #endif
509  else if(socksreq[1] == 2) {
510  /* Needs user name and password */
511  size_t proxy_user_len, proxy_password_len;
512  if(proxy_user && proxy_password) {
513  proxy_user_len = strlen(proxy_user);
514  proxy_password_len = strlen(proxy_password);
515  }
516  else {
517  proxy_user_len = 0;
518  proxy_password_len = 0;
519  }
520 
521  /* username/password request looks like
522  * +----+------+----------+------+----------+
523  * |VER | ULEN | UNAME | PLEN | PASSWD |
524  * +----+------+----------+------+----------+
525  * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
526  * +----+------+----------+------+----------+
527  */
528  len = 0;
529  socksreq[len++] = 1; /* username/pw subnegotiation version */
530  socksreq[len++] = (unsigned char) proxy_user_len;
531  if(proxy_user && proxy_user_len)
532  memcpy(socksreq + len, proxy_user, proxy_user_len);
533  len += proxy_user_len;
534  socksreq[len++] = (unsigned char) proxy_password_len;
535  if(proxy_password && proxy_password_len)
536  memcpy(socksreq + len, proxy_password, proxy_password_len);
537  len += proxy_password_len;
538 
539  code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
540  if(code || (len != written)) {
541  failf(data, "Failed to send SOCKS5 sub-negotiation request.");
542  return CURLE_COULDNT_CONNECT;
543  }
544 
545  result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
546  if(result || (actualread != 2)) {
547  failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
548  return CURLE_COULDNT_CONNECT;
549  }
550 
551  /* ignore the first (VER) byte */
552  if(socksreq[1] != 0) { /* status */
553  failf(data, "User was rejected by the SOCKS5 server (%d %d).",
554  socksreq[0], socksreq[1]);
555  return CURLE_COULDNT_CONNECT;
556  }
557 
558  /* Everything is good so far, user was authenticated! */
559  }
560  else {
561  /* error */
562  if(!allow_gssapi && (socksreq[1] == 1)) {
563  failf(data,
564  "SOCKS5 GSSAPI per-message authentication is not supported.");
565  return CURLE_COULDNT_CONNECT;
566  }
567  if(socksreq[1] == 255) {
568  if(!proxy_user || !*proxy_user) {
569  failf(data,
570  "No authentication method was acceptable. (It is quite likely"
571  " that the SOCKS5 server wanted a username/password, since none"
572  " was supplied to the server on this connection.)");
573  }
574  else {
575  failf(data, "No authentication method was acceptable.");
576  }
577  return CURLE_COULDNT_CONNECT;
578  }
579  else {
580  failf(data,
581  "Undocumented SOCKS5 mode attempted to be used by server.");
582  return CURLE_COULDNT_CONNECT;
583  }
584  }
585 
586  /* Authentication is complete, now specify destination to the proxy */
587  len = 0;
588  socksreq[len++] = 5; /* version (SOCKS5) */
589  socksreq[len++] = 1; /* connect */
590  socksreq[len++] = 0; /* must be zero */
591 
592  if(!socks5_resolve_local) {
593  socksreq[len++] = 3; /* ATYP: domain name = 3 */
594  socksreq[len++] = (char) hostname_len; /* address length */
595  memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */
596  len += hostname_len;
597  }
598  else {
599  struct Curl_dns_entry *dns;
600  Curl_addrinfo *hp = NULL;
601  int rc = Curl_resolv(conn, hostname, remote_port, &dns);
602 
603  if(rc == CURLRESOLV_ERROR)
605 
606  if(rc == CURLRESOLV_PENDING) {
607  /* this requires that we're in "wait for resolve" state */
608  code = Curl_resolver_wait_resolv(conn, &dns);
609  if(code)
610  return code;
611  }
612 
613  /*
614  * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
615  * returns a Curl_addrinfo pointer that may not always look the same.
616  */
617  if(dns)
618  hp = dns->addr;
619  if(hp) {
620  int i;
621  char buf[64];
622  Curl_printable_address(hp, buf, sizeof(buf));
623 
624  if(hp->ai_family == AF_INET) {
625  struct sockaddr_in *saddr_in;
626  socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
627 
628  saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
629  for(i = 0; i < 4; i++) {
630  socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
631  }
632 
633  infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf);
634  }
635 #ifdef ENABLE_IPV6
636  else if(hp->ai_family == AF_INET6) {
637  struct sockaddr_in6 *saddr_in6;
638  socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
639 
640  saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
641  for(i = 0; i < 16; i++) {
642  socksreq[len++] =
643  ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
644  }
645 
646  infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf);
647  }
648 #endif
649  else {
650  hp = NULL; /* fail! */
651 
652  failf(data, "SOCKS5 connection to %s not supported\n", buf);
653  }
654 
655  Curl_resolv_unlock(data, dns); /* not used anymore from now on */
656  }
657  if(!hp) {
658  failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
659  hostname);
661  }
662  }
663 
664  socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
665  socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
666 
667 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
668  if(conn->socks5_gssapi_enctype) {
669  failf(data, "SOCKS5 GSS-API protection not yet implemented.");
670  }
671  else
672 #endif
673  code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
674 
675  if(code || (len != written)) {
676  failf(data, "Failed to send SOCKS5 connect request.");
677  return CURLE_COULDNT_CONNECT;
678  }
679 
680  len = 10; /* minimum packet size is 10 */
681 
682 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
683  if(conn->socks5_gssapi_enctype) {
684  failf(data, "SOCKS5 GSS-API protection not yet implemented.");
685  }
686  else
687 #endif
688  result = Curl_blockread_all(conn, sock, (char *)socksreq,
689  len, &actualread);
690 
691  if(result || (len != actualread)) {
692  failf(data, "Failed to receive SOCKS5 connect request ack.");
693  return CURLE_COULDNT_CONNECT;
694  }
695 
696  if(socksreq[0] != 5) { /* version */
697  failf(data,
698  "SOCKS5 reply has wrong version, version should be 5.");
699  return CURLE_COULDNT_CONNECT;
700  }
701 
702  /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
703  1928, so the reply packet should be read until the end to avoid errors at
704  subsequent protocol level.
705 
706  +----+-----+-------+------+----------+----------+
707  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
708  +----+-----+-------+------+----------+----------+
709  | 1 | 1 | X'00' | 1 | Variable | 2 |
710  +----+-----+-------+------+----------+----------+
711 
712  ATYP:
713  o IP v4 address: X'01', BND.ADDR = 4 byte
714  o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
715  o IP v6 address: X'04', BND.ADDR = 16 byte
716  */
717 
718  /* Calculate real packet size */
719  if(socksreq[3] == 3) {
720  /* domain name */
721  int addrlen = (int) socksreq[4];
722  len = 5 + addrlen + 2;
723  }
724  else if(socksreq[3] == 4) {
725  /* IPv6 */
726  len = 4 + 16 + 2;
727  }
728 
729  /* At this point we already read first 10 bytes */
730 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
731  if(!conn->socks5_gssapi_enctype) {
732  /* decrypt_gssapi_blockread already read the whole packet */
733 #endif
734  if(len > 10) {
735  result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
736  len - 10, &actualread);
737  if(result || ((len - 10) != actualread)) {
738  failf(data, "Failed to receive SOCKS5 connect request ack.");
739  return CURLE_COULDNT_CONNECT;
740  }
741  }
742 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
743  }
744 #endif
745 
746  if(socksreq[1] != 0) { /* Anything besides 0 is an error */
747  if(socksreq[3] == 1) {
748  failf(data,
749  "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
750  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
751  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
752  (((unsigned char)socksreq[8] << 8) |
753  (unsigned char)socksreq[9]),
754  (unsigned char)socksreq[1]);
755  }
756  else if(socksreq[3] == 3) {
757  unsigned char port_upper = (unsigned char)socksreq[len - 2];
758  socksreq[len - 2] = 0;
759  failf(data,
760  "Can't complete SOCKS5 connection to %s:%d. (%d)",
761  (char *)&socksreq[5],
762  ((port_upper << 8) |
763  (unsigned char)socksreq[len - 1]),
764  (unsigned char)socksreq[1]);
765  socksreq[len - 2] = port_upper;
766  }
767  else if(socksreq[3] == 4) {
768  failf(data,
769  "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:"
770  "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)",
771  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
772  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
773  (unsigned char)socksreq[8], (unsigned char)socksreq[9],
774  (unsigned char)socksreq[10], (unsigned char)socksreq[11],
775  (unsigned char)socksreq[12], (unsigned char)socksreq[13],
776  (unsigned char)socksreq[14], (unsigned char)socksreq[15],
777  (unsigned char)socksreq[16], (unsigned char)socksreq[17],
778  (unsigned char)socksreq[18], (unsigned char)socksreq[19],
779  (((unsigned char)socksreq[20] << 8) |
780  (unsigned char)socksreq[21]),
781  (unsigned char)socksreq[1]);
782  }
783  return CURLE_COULDNT_CONNECT;
784  }
785  infof(data, "SOCKS5 request granted.\n");
786 
787  (void)curlx_nonblock(sock, TRUE);
788  return CURLE_OK; /* Proxy was successful! */
789 }
790 
791 #endif /* CURL_DISABLE_PROXY */
792 
struct ConnectBits bits
Definition: urldata.h:893
struct UserDefined set
Definition: urldata.h:1762
#define CURLAUTH_BASIC
Definition: curl.h:697
CURLcode Curl_SOCKS5(const char *proxy_user, const char *proxy_password, const char *hostname, int remote_port, int sockindex, struct connectdata *conn)
Definition: socks.c:353
CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written)
Definition: sendf.c:408
#define failf
Definition: sendf.h:48
Definition: hostip.h:66
uv_timer_t timeout
Definition: multi-uv.c:42
#define CURLRESOLV_PENDING
Definition: hostip.h:85
CURLcode
Definition: curl.h:454
#define CURLAUTH_GSSAPI
Definition: curl.h:703
UNITTEST_START int result
Definition: unit1304.c:49
#define SOCKS4REQLEN
unsigned int i
Definition: unit1303.c:79
CURLcode Curl_SOCKS4(const char *proxy_user, const char *hostname, int remote_port, int sockindex, struct connectdata *conn)
Definition: socks.c:108
int curlx_nonblock(curl_socket_t sockfd, int nonblock)
Definition: nonblock.c:47
struct sockaddr * ai_addr
Definition: curl_addrinfo.h:58
size_t len
Definition: curl_sasl.c:55
CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n)
Definition: sendf.c:655
memcpy(filename, filename1, strlen(filename1))
Definition: urldata.h:1179
#define CURL_CSELECT_ERR
Definition: multi.h:266
#define FALSE
time_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect)
Definition: connect.c:182
UNITTEST_START int rc
Definition: unit1301.c:31
#define SOCKET_READABLE(x, z)
Definition: select.h:79
#define CURLRESOLV_ERROR
Definition: hostip.h:83
bool httpproxy
Definition: urldata.h:383
const char * Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
Definition: hostip.c:166
#define SOCKET_WRITABLE(x, z)
Definition: select.h:81
int Curl_resolv(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry)
Definition: hostip.c:444
void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
Definition: hostip.c:722
Definition: curl.h:455
struct proxy_info socks_proxy
Definition: urldata.h:838
Curl_addrinfo * addr
Definition: hostip.h:67
static struct curl_hash hp
Definition: unit1305.c:43
int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, char *buf, ssize_t buffersize, ssize_t *n)
Definition: socks.c:51
#define ssize_t
Definition: config-win32.h:382
curl_socket_t sock[2]
Definition: urldata.h:876
char buf[3]
Definition: unit1398.c:32
#define infof
Definition: sendf.h:44
CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **dnsentry)
#define TRUE
curl_proxytype proxytype
Definition: urldata.h:760
int curl_socket_t
Definition: curl.h:130
unsigned long socks5auth
Definition: urldata.h:1499
Definition: debug.c:29
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16