VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/socks.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 32.3 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, 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.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#include "multiif.h" /* for getsock macros */
41#include "inet_pton.h"
42
43/* The last 3 #include files should be in this order */
44#include "curl_printf.h"
45#include "curl_memory.h"
46#include "memdebug.h"
47
48#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
49/*
50 * Helper read-from-socket functions. Does the same as Curl_read() but it
51 * blocks until all bytes amount of buffersize will be read. No more, no less.
52 *
53 * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
54 */
55int Curl_blockread_all(struct Curl_easy *data, /* transfer */
56 curl_socket_t sockfd, /* read from this socket */
57 char *buf, /* store read data here */
58 ssize_t buffersize, /* max amount to read */
59 ssize_t *n) /* amount bytes read */
60{
61 ssize_t nread = 0;
62 ssize_t allread = 0;
63 int result;
64 *n = 0;
65 for(;;) {
66 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
67 if(timeout_ms < 0) {
68 /* we already got the timeout */
69 result = CURLE_OPERATION_TIMEDOUT;
70 break;
71 }
72 if(!timeout_ms)
73 timeout_ms = TIMEDIFF_T_MAX;
74 if(SOCKET_READABLE(sockfd, timeout_ms) <= 0) {
75 result = ~CURLE_OK;
76 break;
77 }
78 result = Curl_read_plain(sockfd, buf, buffersize, &nread);
79 if(CURLE_AGAIN == result)
80 continue;
81 if(result)
82 break;
83
84 if(buffersize == nread) {
85 allread += nread;
86 *n = allread;
87 result = CURLE_OK;
88 break;
89 }
90 if(!nread) {
91 result = ~CURLE_OK;
92 break;
93 }
94
95 buffersize -= nread;
96 buf += nread;
97 allread += nread;
98 }
99 return result;
100}
101#endif
102
103#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
104#define DEBUG_AND_VERBOSE
105#define sxstate(x,y) socksstate(x,y, __LINE__)
106#else
107#define sxstate(x,y) socksstate(x,y)
108#endif
109
110/* always use this function to change state, to make debugging easier */
111static void socksstate(struct Curl_easy *data,
112 enum connect_t state
113#ifdef DEBUG_AND_VERBOSE
114 , int lineno
115#endif
116)
117{
118 struct connectdata *conn = data->conn;
119 enum connect_t oldstate = conn->cnnct.state;
120#ifdef DEBUG_AND_VERBOSE
121 /* synced with the state list in urldata.h */
122 static const char * const statename[] = {
123 "INIT",
124 "SOCKS_INIT",
125 "SOCKS_SEND",
126 "SOCKS_READ_INIT",
127 "SOCKS_READ",
128 "GSSAPI_INIT",
129 "AUTH_INIT",
130 "AUTH_SEND",
131 "AUTH_READ",
132 "REQ_INIT",
133 "RESOLVING",
134 "RESOLVED",
135 "RESOLVE_REMOTE",
136 "REQ_SEND",
137 "REQ_SENDING",
138 "REQ_READ",
139 "REQ_READ_MORE",
140 "DONE"
141 };
142#endif
143
144 if(oldstate == state)
145 /* don't bother when the new state is the same as the old state */
146 return;
147
148 conn->cnnct.state = state;
149
150#ifdef DEBUG_AND_VERBOSE
151 infof(data,
152 "SXSTATE: %s => %s conn %p; line %d",
153 statename[oldstate], statename[conn->cnnct.state], conn,
154 lineno);
155#endif
156}
157
158int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
159 int sockindex)
160{
161 int rc = 0;
162 sock[0] = conn->sock[sockindex];
163 switch(conn->cnnct.state) {
164 case CONNECT_RESOLVING:
165 case CONNECT_SOCKS_READ:
166 case CONNECT_AUTH_READ:
167 case CONNECT_REQ_READ:
168 case CONNECT_REQ_READ_MORE:
169 rc = GETSOCK_READSOCK(0);
170 break;
171 default:
172 rc = GETSOCK_WRITESOCK(0);
173 break;
174 }
175 return rc;
176}
177
178/*
179* This function logs in to a SOCKS4 proxy and sends the specifics to the final
180* destination server.
181*
182* Reference :
183* https://www.openssh.com/txt/socks4.protocol
184*
185* Note :
186* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
187* Nonsupport "Identification Protocol (RFC1413)"
188*/
189CURLproxycode Curl_SOCKS4(const char *proxy_user,
190 const char *hostname,
191 int remote_port,
192 int sockindex,
193 struct Curl_easy *data,
194 bool *done)
195{
196 struct connectdata *conn = data->conn;
197 const bool protocol4a =
198 (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
199 unsigned char *socksreq = (unsigned char *)data->state.buffer;
200 CURLcode result;
201 curl_socket_t sockfd = conn->sock[sockindex];
202 struct connstate *sx = &conn->cnnct;
203 struct Curl_dns_entry *dns = NULL;
204 ssize_t actualread;
205 ssize_t written;
206
207 /* make sure that the buffer is at least 600 bytes */
208 DEBUGASSERT(READBUFFER_MIN >= 600);
209
210 if(!SOCKS_STATE(sx->state) && !*done)
211 sxstate(data, CONNECT_SOCKS_INIT);
212
213 switch(sx->state) {
214 case CONNECT_SOCKS_INIT:
215 /* SOCKS4 can only do IPv4, insist! */
216 conn->ip_version = CURL_IPRESOLVE_V4;
217 if(conn->bits.httpproxy)
218 infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d",
219 protocol4a ? "a" : "", hostname, remote_port);
220
221 infof(data, "SOCKS4 communication to %s:%d", hostname, remote_port);
222
223 /*
224 * Compose socks4 request
225 *
226 * Request format
227 *
228 * +----+----+----+----+----+----+----+----+----+----+....+----+
229 * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
230 * +----+----+----+----+----+----+----+----+----+----+....+----+
231 * # of bytes: 1 1 2 4 variable 1
232 */
233
234 socksreq[0] = 4; /* version (SOCKS4) */
235 socksreq[1] = 1; /* connect */
236 socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
237 socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
238
239 /* DNS resolve only for SOCKS4, not SOCKS4a */
240 if(!protocol4a) {
241 enum resolve_t rc =
242 Curl_resolv(data, hostname, remote_port, FALSE, &dns);
243
244 if(rc == CURLRESOLV_ERROR)
245 return CURLPX_RESOLVE_HOST;
246 else if(rc == CURLRESOLV_PENDING) {
247 sxstate(data, CONNECT_RESOLVING);
248 infof(data, "SOCKS4 non-blocking resolve of %s", hostname);
249 return CURLPX_OK;
250 }
251 sxstate(data, CONNECT_RESOLVED);
252 goto CONNECT_RESOLVED;
253 }
254
255 /* socks4a doesn't resolve anything locally */
256 sxstate(data, CONNECT_REQ_INIT);
257 goto CONNECT_REQ_INIT;
258
259 case CONNECT_RESOLVING:
260 /* check if we have the name resolved by now */
261 dns = Curl_fetch_addr(data, hostname, (int)conn->port);
262
263 if(dns) {
264#ifdef CURLRES_ASYNCH
265 data->state.async.dns = dns;
266 data->state.async.done = TRUE;
267#endif
268 infof(data, "Hostname '%s' was found", hostname);
269 sxstate(data, CONNECT_RESOLVED);
270 }
271 else {
272 result = Curl_resolv_check(data, &dns);
273 if(!dns) {
274 if(result)
275 return CURLPX_RESOLVE_HOST;
276 return CURLPX_OK;
277 }
278 }
279 /* FALLTHROUGH */
280 CONNECT_RESOLVED:
281 case CONNECT_RESOLVED: {
282 struct Curl_addrinfo *hp = NULL;
283 /*
284 * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
285 * returns a Curl_addrinfo pointer that may not always look the same.
286 */
287 if(dns) {
288 hp = dns->addr;
289
290 /* scan for the first IPv4 address */
291 while(hp && (hp->ai_family != AF_INET))
292 hp = hp->ai_next;
293
294 if(hp) {
295 struct sockaddr_in *saddr_in;
296 char buf[64];
297 Curl_printable_address(hp, buf, sizeof(buf));
298
299 saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
300 socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
301 socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
302 socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
303 socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
304
305 infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf);
306
307 Curl_resolv_unlock(data, dns); /* not used anymore from now on */
308 }
309 else
310 failf(data, "SOCKS4 connection to %s not supported", hostname);
311 }
312 else
313 failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
314 hostname);
315
316 if(!hp)
317 return CURLPX_RESOLVE_HOST;
318 }
319 /* FALLTHROUGH */
320 CONNECT_REQ_INIT:
321 case CONNECT_REQ_INIT:
322 /*
323 * This is currently not supporting "Identification Protocol (RFC1413)".
324 */
325 socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
326 if(proxy_user) {
327 size_t plen = strlen(proxy_user);
328 if(plen >= (size_t)data->set.buffer_size - 8) {
329 failf(data, "Too long SOCKS proxy user name, can't use");
330 return CURLPX_LONG_USER;
331 }
332 /* copy the proxy name WITH trailing zero */
333 memcpy(socksreq + 8, proxy_user, plen + 1);
334 }
335
336 /*
337 * Make connection
338 */
339 {
340 size_t packetsize = 9 +
341 strlen((char *)socksreq + 8); /* size including NUL */
342
343 /* If SOCKS4a, set special invalid IP address 0.0.0.x */
344 if(protocol4a) {
345 size_t hostnamelen = 0;
346 socksreq[4] = 0;
347 socksreq[5] = 0;
348 socksreq[6] = 0;
349 socksreq[7] = 1;
350 /* append hostname */
351 hostnamelen = strlen(hostname) + 1; /* length including NUL */
352 if(hostnamelen <= 255)
353 strcpy((char *)socksreq + packetsize, hostname);
354 else {
355 failf(data, "SOCKS4: too long host name");
356 return CURLPX_LONG_HOSTNAME;
357 }
358 packetsize += hostnamelen;
359 }
360 sx->outp = socksreq;
361 sx->outstanding = packetsize;
362 sxstate(data, CONNECT_REQ_SENDING);
363 }
364 /* FALLTHROUGH */
365 case CONNECT_REQ_SENDING:
366 /* Send request */
367 result = Curl_write_plain(data, sockfd, (char *)sx->outp,
368 sx->outstanding, &written);
369 if(result && (CURLE_AGAIN != result)) {
370 failf(data, "Failed to send SOCKS4 connect request.");
371 return CURLPX_SEND_CONNECT;
372 }
373 if(written != sx->outstanding) {
374 /* not done, remain in state */
375 sx->outstanding -= written;
376 sx->outp += written;
377 return CURLPX_OK;
378 }
379
380 /* done sending! */
381 sx->outstanding = 8; /* receive data size */
382 sx->outp = socksreq;
383 sxstate(data, CONNECT_SOCKS_READ);
384
385 /* FALLTHROUGH */
386 case CONNECT_SOCKS_READ:
387 /* Receive response */
388 result = Curl_read_plain(sockfd, (char *)sx->outp,
389 sx->outstanding, &actualread);
390 if(result && (CURLE_AGAIN != result)) {
391 failf(data, "SOCKS4: Failed receiving connect request ack: %s",
392 curl_easy_strerror(result));
393 return CURLPX_RECV_CONNECT;
394 }
395 else if(!result && !actualread) {
396 /* connection closed */
397 failf(data, "connection to proxy closed");
398 return CURLPX_CLOSED;
399 }
400 else if(actualread != sx->outstanding) {
401 /* remain in reading state */
402 sx->outstanding -= actualread;
403 sx->outp += actualread;
404 return CURLPX_OK;
405 }
406 sxstate(data, CONNECT_DONE);
407 break;
408 default: /* lots of unused states in SOCKS4 */
409 break;
410 }
411
412 /*
413 * Response format
414 *
415 * +----+----+----+----+----+----+----+----+
416 * | VN | CD | DSTPORT | DSTIP |
417 * +----+----+----+----+----+----+----+----+
418 * # of bytes: 1 1 2 4
419 *
420 * VN is the version of the reply code and should be 0. CD is the result
421 * code with one of the following values:
422 *
423 * 90: request granted
424 * 91: request rejected or failed
425 * 92: request rejected because SOCKS server cannot connect to
426 * identd on the client
427 * 93: request rejected because the client program and identd
428 * report different user-ids
429 */
430
431 /* wrong version ? */
432 if(socksreq[0]) {
433 failf(data,
434 "SOCKS4 reply has wrong version, version should be 0.");
435 return CURLPX_BAD_VERSION;
436 }
437
438 /* Result */
439 switch(socksreq[1]) {
440 case 90:
441 infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
442 break;
443 case 91:
444 failf(data,
445 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
446 ", request rejected or failed.",
447 socksreq[4], socksreq[5], socksreq[6], socksreq[7],
448 (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
449 (unsigned char)socksreq[1]);
450 return CURLPX_REQUEST_FAILED;
451 case 92:
452 failf(data,
453 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
454 ", request rejected because SOCKS server cannot connect to "
455 "identd on the client.",
456 socksreq[4], socksreq[5], socksreq[6], socksreq[7],
457 (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
458 (unsigned char)socksreq[1]);
459 return CURLPX_IDENTD;
460 case 93:
461 failf(data,
462 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
463 ", request rejected because the client program and identd "
464 "report different user-ids.",
465 socksreq[4], socksreq[5], socksreq[6], socksreq[7],
466 (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
467 (unsigned char)socksreq[1]);
468 return CURLPX_IDENTD_DIFFER;
469 default:
470 failf(data,
471 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
472 ", Unknown.",
473 socksreq[4], socksreq[5], socksreq[6], socksreq[7],
474 (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
475 (unsigned char)socksreq[1]);
476 return CURLPX_UNKNOWN_FAIL;
477 }
478
479 *done = TRUE;
480 return CURLPX_OK; /* Proxy was successful! */
481}
482
483/*
484 * This function logs in to a SOCKS5 proxy and sends the specifics to the final
485 * destination server.
486 */
487CURLproxycode Curl_SOCKS5(const char *proxy_user,
488 const char *proxy_password,
489 const char *hostname,
490 int remote_port,
491 int sockindex,
492 struct Curl_easy *data,
493 bool *done)
494{
495 /*
496 According to the RFC1928, section "6. Replies". This is what a SOCK5
497 replies:
498
499 +----+-----+-------+------+----------+----------+
500 |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
501 +----+-----+-------+------+----------+----------+
502 | 1 | 1 | X'00' | 1 | Variable | 2 |
503 +----+-----+-------+------+----------+----------+
504
505 Where:
506
507 o VER protocol version: X'05'
508 o REP Reply field:
509 o X'00' succeeded
510 */
511 struct connectdata *conn = data->conn;
512 unsigned char *socksreq = (unsigned char *)data->state.buffer;
513 char dest[256] = "unknown"; /* printable hostname:port */
514 int idx;
515 ssize_t actualread;
516 ssize_t written;
517 CURLcode result;
518 curl_socket_t sockfd = conn->sock[sockindex];
519 bool socks5_resolve_local =
520 (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
521 const size_t hostname_len = strlen(hostname);
522 ssize_t len = 0;
523 const unsigned long auth = data->set.socks5auth;
524 bool allow_gssapi = FALSE;
525 struct connstate *sx = &conn->cnnct;
526 struct Curl_dns_entry *dns = NULL;
527
528 if(!SOCKS_STATE(sx->state) && !*done)
529 sxstate(data, CONNECT_SOCKS_INIT);
530
531 switch(sx->state) {
532 case CONNECT_SOCKS_INIT:
533 if(conn->bits.httpproxy)
534 infof(data, "SOCKS5: connecting to HTTP proxy %s port %d",
535 hostname, remote_port);
536
537 /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
538 if(!socks5_resolve_local && hostname_len > 255) {
539 infof(data, "SOCKS5: server resolving disabled for hostnames of "
540 "length > 255 [actual len=%zu]", hostname_len);
541 socks5_resolve_local = TRUE;
542 }
543
544 if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
545 infof(data,
546 "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu",
547 auth);
548 if(!(auth & CURLAUTH_BASIC))
549 /* disable username/password auth */
550 proxy_user = NULL;
551#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
552 if(auth & CURLAUTH_GSSAPI)
553 allow_gssapi = TRUE;
554#endif
555
556 idx = 0;
557 socksreq[idx++] = 5; /* version */
558 idx++; /* number of authentication methods */
559 socksreq[idx++] = 0; /* no authentication */
560 if(allow_gssapi)
561 socksreq[idx++] = 1; /* GSS-API */
562 if(proxy_user)
563 socksreq[idx++] = 2; /* username/password */
564 /* write the number of authentication methods */
565 socksreq[1] = (unsigned char) (idx - 2);
566
567 result = Curl_write_plain(data, sockfd, (char *)socksreq, idx, &written);
568 if(result && (CURLE_AGAIN != result)) {
569 failf(data, "Unable to send initial SOCKS5 request.");
570 return CURLPX_SEND_CONNECT;
571 }
572 if(written != idx) {
573 sxstate(data, CONNECT_SOCKS_SEND);
574 sx->outstanding = idx - written;
575 sx->outp = &socksreq[written];
576 return CURLPX_OK;
577 }
578 sxstate(data, CONNECT_SOCKS_READ);
579 goto CONNECT_SOCKS_READ_INIT;
580 case CONNECT_SOCKS_SEND:
581 result = Curl_write_plain(data, sockfd, (char *)sx->outp,
582 sx->outstanding, &written);
583 if(result && (CURLE_AGAIN != result)) {
584 failf(data, "Unable to send initial SOCKS5 request.");
585 return CURLPX_SEND_CONNECT;
586 }
587 if(written != sx->outstanding) {
588 /* not done, remain in state */
589 sx->outstanding -= written;
590 sx->outp += written;
591 return CURLPX_OK;
592 }
593 /* FALLTHROUGH */
594 CONNECT_SOCKS_READ_INIT:
595 case CONNECT_SOCKS_READ_INIT:
596 sx->outstanding = 2; /* expect two bytes */
597 sx->outp = socksreq; /* store it here */
598 /* FALLTHROUGH */
599 case CONNECT_SOCKS_READ:
600 result = Curl_read_plain(sockfd, (char *)sx->outp,
601 sx->outstanding, &actualread);
602 if(result && (CURLE_AGAIN != result)) {
603 failf(data, "Unable to receive initial SOCKS5 response.");
604 return CURLPX_RECV_CONNECT;
605 }
606 else if(!result && !actualread) {
607 /* connection closed */
608 failf(data, "Connection to proxy closed");
609 return CURLPX_CLOSED;
610 }
611 else if(actualread != sx->outstanding) {
612 /* remain in reading state */
613 sx->outstanding -= actualread;
614 sx->outp += actualread;
615 return CURLPX_OK;
616 }
617 else if(socksreq[0] != 5) {
618 failf(data, "Received invalid version in initial SOCKS5 response.");
619 return CURLPX_BAD_VERSION;
620 }
621 else if(socksreq[1] == 0) {
622 /* DONE! No authentication needed. Send request. */
623 sxstate(data, CONNECT_REQ_INIT);
624 goto CONNECT_REQ_INIT;
625 }
626 else if(socksreq[1] == 2) {
627 /* regular name + password authentication */
628 sxstate(data, CONNECT_AUTH_INIT);
629 goto CONNECT_AUTH_INIT;
630 }
631#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
632 else if(allow_gssapi && (socksreq[1] == 1)) {
633 sxstate(data, CONNECT_GSSAPI_INIT);
634 result = Curl_SOCKS5_gssapi_negotiate(sockindex, data);
635 if(result) {
636 failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
637 return CURLPX_GSSAPI;
638 }
639 }
640#endif
641 else {
642 /* error */
643 if(!allow_gssapi && (socksreq[1] == 1)) {
644 failf(data,
645 "SOCKS5 GSSAPI per-message authentication is not supported.");
646 return CURLPX_GSSAPI_PERMSG;
647 }
648 else if(socksreq[1] == 255) {
649 failf(data, "No authentication method was acceptable.");
650 return CURLPX_NO_AUTH;
651 }
652 }
653 failf(data,
654 "Undocumented SOCKS5 mode attempted to be used by server.");
655 return CURLPX_UNKNOWN_MODE;
656#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
657 case CONNECT_GSSAPI_INIT:
658 /* GSSAPI stuff done non-blocking */
659 break;
660#endif
661
662 default: /* do nothing! */
663 break;
664
665 CONNECT_AUTH_INIT:
666 case CONNECT_AUTH_INIT: {
667 /* Needs user name and password */
668 size_t proxy_user_len, proxy_password_len;
669 if(proxy_user && proxy_password) {
670 proxy_user_len = strlen(proxy_user);
671 proxy_password_len = strlen(proxy_password);
672 }
673 else {
674 proxy_user_len = 0;
675 proxy_password_len = 0;
676 }
677
678 /* username/password request looks like
679 * +----+------+----------+------+----------+
680 * |VER | ULEN | UNAME | PLEN | PASSWD |
681 * +----+------+----------+------+----------+
682 * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
683 * +----+------+----------+------+----------+
684 */
685 len = 0;
686 socksreq[len++] = 1; /* username/pw subnegotiation version */
687 socksreq[len++] = (unsigned char) proxy_user_len;
688 if(proxy_user && proxy_user_len) {
689 /* the length must fit in a single byte */
690 if(proxy_user_len >= 255) {
691 failf(data, "Excessive user name length for proxy auth");
692 return CURLPX_LONG_USER;
693 }
694 memcpy(socksreq + len, proxy_user, proxy_user_len);
695 }
696 len += proxy_user_len;
697 socksreq[len++] = (unsigned char) proxy_password_len;
698 if(proxy_password && proxy_password_len) {
699 /* the length must fit in a single byte */
700 if(proxy_password_len > 255) {
701 failf(data, "Excessive password length for proxy auth");
702 return CURLPX_LONG_PASSWD;
703 }
704 memcpy(socksreq + len, proxy_password, proxy_password_len);
705 }
706 len += proxy_password_len;
707 sxstate(data, CONNECT_AUTH_SEND);
708 sx->outstanding = len;
709 sx->outp = socksreq;
710 }
711 /* FALLTHROUGH */
712 case CONNECT_AUTH_SEND:
713 result = Curl_write_plain(data, sockfd, (char *)sx->outp,
714 sx->outstanding, &written);
715 if(result && (CURLE_AGAIN != result)) {
716 failf(data, "Failed to send SOCKS5 sub-negotiation request.");
717 return CURLPX_SEND_AUTH;
718 }
719 if(sx->outstanding != written) {
720 /* remain in state */
721 sx->outstanding -= written;
722 sx->outp += written;
723 return CURLPX_OK;
724 }
725 sx->outp = socksreq;
726 sx->outstanding = 2;
727 sxstate(data, CONNECT_AUTH_READ);
728 /* FALLTHROUGH */
729 case CONNECT_AUTH_READ:
730 result = Curl_read_plain(sockfd, (char *)sx->outp,
731 sx->outstanding, &actualread);
732 if(result && (CURLE_AGAIN != result)) {
733 failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
734 return CURLPX_RECV_AUTH;
735 }
736 else if(!result && !actualread) {
737 /* connection closed */
738 failf(data, "connection to proxy closed");
739 return CURLPX_CLOSED;
740 }
741 else if(actualread != sx->outstanding) {
742 /* remain in state */
743 sx->outstanding -= actualread;
744 sx->outp += actualread;
745 return CURLPX_OK;
746 }
747 /* ignore the first (VER) byte */
748 else if(socksreq[1]) { /* status */
749 failf(data, "User was rejected by the SOCKS5 server (%d %d).",
750 socksreq[0], socksreq[1]);
751 return CURLPX_USER_REJECTED;
752 }
753
754 /* Everything is good so far, user was authenticated! */
755 sxstate(data, CONNECT_REQ_INIT);
756 /* FALLTHROUGH */
757 CONNECT_REQ_INIT:
758 case CONNECT_REQ_INIT:
759 if(socks5_resolve_local) {
760 enum resolve_t rc = Curl_resolv(data, hostname, remote_port,
761 FALSE, &dns);
762
763 if(rc == CURLRESOLV_ERROR)
764 return CURLPX_RESOLVE_HOST;
765
766 if(rc == CURLRESOLV_PENDING) {
767 sxstate(data, CONNECT_RESOLVING);
768 return CURLPX_OK;
769 }
770 sxstate(data, CONNECT_RESOLVED);
771 goto CONNECT_RESOLVED;
772 }
773 goto CONNECT_RESOLVE_REMOTE;
774
775 case CONNECT_RESOLVING:
776 /* check if we have the name resolved by now */
777 dns = Curl_fetch_addr(data, hostname, remote_port);
778
779 if(dns) {
780#ifdef CURLRES_ASYNCH
781 data->state.async.dns = dns;
782 data->state.async.done = TRUE;
783#endif
784 infof(data, "SOCKS5: hostname '%s' found", hostname);
785 }
786
787 if(!dns) {
788 result = Curl_resolv_check(data, &dns);
789 if(!dns) {
790 if(result)
791 return CURLPX_RESOLVE_HOST;
792 return CURLPX_OK;
793 }
794 }
795 /* FALLTHROUGH */
796 CONNECT_RESOLVED:
797 case CONNECT_RESOLVED: {
798 struct Curl_addrinfo *hp = NULL;
799 size_t destlen;
800 if(dns)
801 hp = dns->addr;
802 if(!hp) {
803 failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
804 hostname);
805 return CURLPX_RESOLVE_HOST;
806 }
807
808 Curl_printable_address(hp, dest, sizeof(dest));
809 destlen = strlen(dest);
810 msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port);
811
812 len = 0;
813 socksreq[len++] = 5; /* version (SOCKS5) */
814 socksreq[len++] = 1; /* connect */
815 socksreq[len++] = 0; /* must be zero */
816 if(hp->ai_family == AF_INET) {
817 int i;
818 struct sockaddr_in *saddr_in;
819 socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
820
821 saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
822 for(i = 0; i < 4; i++) {
823 socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
824 }
825
826 infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)", dest);
827 }
828#ifdef ENABLE_IPV6
829 else if(hp->ai_family == AF_INET6) {
830 int i;
831 struct sockaddr_in6 *saddr_in6;
832 socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
833
834 saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
835 for(i = 0; i < 16; i++) {
836 socksreq[len++] =
837 ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
838 }
839
840 infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)", dest);
841 }
842#endif
843 else {
844 hp = NULL; /* fail! */
845 failf(data, "SOCKS5 connection to %s not supported", dest);
846 }
847
848 Curl_resolv_unlock(data, dns); /* not used anymore from now on */
849 goto CONNECT_REQ_SEND;
850 }
851 CONNECT_RESOLVE_REMOTE:
852 case CONNECT_RESOLVE_REMOTE:
853 /* Authentication is complete, now specify destination to the proxy */
854 len = 0;
855 socksreq[len++] = 5; /* version (SOCKS5) */
856 socksreq[len++] = 1; /* connect */
857 socksreq[len++] = 0; /* must be zero */
858
859 if(!socks5_resolve_local) {
860 /* ATYP: domain name = 3,
861 IPv6 == 4,
862 IPv4 == 1 */
863 unsigned char ip4[4];
864#ifdef ENABLE_IPV6
865 if(conn->bits.ipv6_ip) {
866 char ip6[16];
867 if(1 != Curl_inet_pton(AF_INET6, hostname, ip6))
868 return CURLPX_BAD_ADDRESS_TYPE;
869 socksreq[len++] = 4;
870 memcpy(&socksreq[len], ip6, sizeof(ip6));
871 len += sizeof(ip6);
872 }
873 else
874#endif
875 if(1 == Curl_inet_pton(AF_INET, hostname, ip4)) {
876 socksreq[len++] = 1;
877 memcpy(&socksreq[len], ip4, sizeof(ip4));
878 len += sizeof(ip4);
879 }
880 else {
881 socksreq[len++] = 3;
882 socksreq[len++] = (char) hostname_len; /* one byte address length */
883 memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
884 len += hostname_len;
885 }
886 infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
887 hostname, remote_port);
888 }
889 /* FALLTHROUGH */
890
891 CONNECT_REQ_SEND:
892 case CONNECT_REQ_SEND:
893 /* PORT MSB */
894 socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff);
895 /* PORT LSB */
896 socksreq[len++] = (unsigned char)(remote_port & 0xff);
897
898#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
899 if(conn->socks5_gssapi_enctype) {
900 failf(data, "SOCKS5 GSS-API protection not yet implemented.");
901 return CURLPX_GSSAPI_PROTECTION;
902 }
903#endif
904 sx->outp = socksreq;
905 sx->outstanding = len;
906 sxstate(data, CONNECT_REQ_SENDING);
907 /* FALLTHROUGH */
908 case CONNECT_REQ_SENDING:
909 result = Curl_write_plain(data, sockfd, (char *)sx->outp,
910 sx->outstanding, &written);
911 if(result && (CURLE_AGAIN != result)) {
912 failf(data, "Failed to send SOCKS5 connect request.");
913 return CURLPX_SEND_REQUEST;
914 }
915 if(sx->outstanding != written) {
916 /* remain in state */
917 sx->outstanding -= written;
918 sx->outp += written;
919 return CURLPX_OK;
920 }
921#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
922 if(conn->socks5_gssapi_enctype) {
923 failf(data, "SOCKS5 GSS-API protection not yet implemented.");
924 return CURLPX_GSSAPI_PROTECTION;
925 }
926#endif
927 sx->outstanding = 10; /* minimum packet size is 10 */
928 sx->outp = socksreq;
929 sxstate(data, CONNECT_REQ_READ);
930 /* FALLTHROUGH */
931 case CONNECT_REQ_READ:
932 result = Curl_read_plain(sockfd, (char *)sx->outp,
933 sx->outstanding, &actualread);
934 if(result && (CURLE_AGAIN != result)) {
935 failf(data, "Failed to receive SOCKS5 connect request ack.");
936 return CURLPX_RECV_REQACK;
937 }
938 else if(!result && !actualread) {
939 /* connection closed */
940 failf(data, "connection to proxy closed");
941 return CURLPX_CLOSED;
942 }
943 else if(actualread != sx->outstanding) {
944 /* remain in state */
945 sx->outstanding -= actualread;
946 sx->outp += actualread;
947 return CURLPX_OK;
948 }
949
950 if(socksreq[0] != 5) { /* version */
951 failf(data,
952 "SOCKS5 reply has wrong version, version should be 5.");
953 return CURLPX_BAD_VERSION;
954 }
955 else if(socksreq[1]) { /* Anything besides 0 is an error */
956 CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
957 int code = socksreq[1];
958 failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
959 hostname, (unsigned char)socksreq[1]);
960 if(code < 9) {
961 /* RFC 1928 section 6 lists: */
962 static const CURLproxycode lookup[] = {
963 CURLPX_OK,
964 CURLPX_REPLY_GENERAL_SERVER_FAILURE,
965 CURLPX_REPLY_NOT_ALLOWED,
966 CURLPX_REPLY_NETWORK_UNREACHABLE,
967 CURLPX_REPLY_HOST_UNREACHABLE,
968 CURLPX_REPLY_CONNECTION_REFUSED,
969 CURLPX_REPLY_TTL_EXPIRED,
970 CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
971 CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
972 };
973 rc = lookup[code];
974 }
975 return rc;
976 }
977
978 /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
979 1928, so the reply packet should be read until the end to avoid errors
980 at subsequent protocol level.
981
982 +----+-----+-------+------+----------+----------+
983 |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
984 +----+-----+-------+------+----------+----------+
985 | 1 | 1 | X'00' | 1 | Variable | 2 |
986 +----+-----+-------+------+----------+----------+
987
988 ATYP:
989 o IP v4 address: X'01', BND.ADDR = 4 byte
990 o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
991 o IP v6 address: X'04', BND.ADDR = 16 byte
992 */
993
994 /* Calculate real packet size */
995 if(socksreq[3] == 3) {
996 /* domain name */
997 int addrlen = (int) socksreq[4];
998 len = 5 + addrlen + 2;
999 }
1000 else if(socksreq[3] == 4) {
1001 /* IPv6 */
1002 len = 4 + 16 + 2;
1003 }
1004 else if(socksreq[3] == 1) {
1005 len = 4 + 4 + 2;
1006 }
1007 else {
1008 failf(data, "SOCKS5 reply has wrong address type.");
1009 return CURLPX_BAD_ADDRESS_TYPE;
1010 }
1011
1012 /* At this point we already read first 10 bytes */
1013#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1014 if(!conn->socks5_gssapi_enctype) {
1015 /* decrypt_gssapi_blockread already read the whole packet */
1016#endif
1017 if(len > 10) {
1018 sx->outstanding = len - 10; /* get the rest */
1019 sx->outp = &socksreq[10];
1020 sxstate(data, CONNECT_REQ_READ_MORE);
1021 }
1022 else {
1023 sxstate(data, CONNECT_DONE);
1024 break;
1025 }
1026#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1027 }
1028#endif
1029 /* FALLTHROUGH */
1030 case CONNECT_REQ_READ_MORE:
1031 result = Curl_read_plain(sockfd, (char *)sx->outp,
1032 sx->outstanding, &actualread);
1033 if(result && (CURLE_AGAIN != result)) {
1034 failf(data, "Failed to receive SOCKS5 connect request ack.");
1035 return CURLPX_RECV_ADDRESS;
1036 }
1037 else if(!result && !actualread) {
1038 /* connection closed */
1039 failf(data, "connection to proxy closed");
1040 return CURLPX_CLOSED;
1041 }
1042 else if(actualread != sx->outstanding) {
1043 /* remain in state */
1044 sx->outstanding -= actualread;
1045 sx->outp += actualread;
1046 return CURLPX_OK;
1047 }
1048 sxstate(data, CONNECT_DONE);
1049 }
1050 infof(data, "SOCKS5 request granted.");
1051
1052 *done = TRUE;
1053 return CURLPX_OK; /* Proxy was successful! */
1054}
1055
1056#endif /* CURL_DISABLE_PROXY */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette