1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 #include "core/or/or.h"
8 #include "feature/client/addressmap.h"
9 #include "lib/container/buffers.h"
10 #include "core/mainloop/connection.h"
11 #include "feature/control/control.h"
12 #include "app/config/config.h"
13 #include "lib/crypt_ops/crypto_util.h"
14 #include "feature/relay/ext_orport.h"
15 #include "core/proto/proto_socks.h"
16 #include "core/or/reasons.h"
18 #include "core/or/socks_request_st.h"
20 #include "trunnel/socks5.h"
22 #define SOCKS_VER_5 0x05 /* First octet of non-auth SOCKS5 messages */
23 #define SOCKS_VER_4 0x04 /* SOCKS4 messages */
24 #define SOCKS_AUTH 0x01 /* SOCKS5 auth messages */
27 SOCKS_RESULT_INVALID
= -1, /* Message invalid. */
28 SOCKS_RESULT_TRUNCATED
= 0, /* Message incomplete/truncated. */
29 SOCKS_RESULT_DONE
= 1, /* OK, we're done. */
30 SOCKS_RESULT_MORE_EXPECTED
= 2, /* OK, more messages expected. */
33 static void socks_request_set_socks5_error(socks_request_t
*req
,
34 socks5_reply_status_t reason
);
36 static socks_result_t
parse_socks(const char *data
,
42 static int parse_socks_client(const uint8_t *data
, size_t datalen
,
43 int state
, char **reason
,
46 * Wait this many seconds before warning the user about using SOCKS unsafely
48 #define SOCKS_WARN_INTERVAL 5
50 /** Warn that the user application has made an unsafe socks request using
51 * protocol <b>socks_protocol</b> on port <b>port</b>. Don't warn more than
52 * once per SOCKS_WARN_INTERVAL, unless <b>safe_socks</b> is set. */
54 log_unsafe_socks_warning(int socks_protocol
, const char *address
,
55 uint16_t port
, int safe_socks
)
57 static ratelim_t socks_ratelim
= RATELIM_INIT(SOCKS_WARN_INTERVAL
);
60 log_fn_ratelim(&socks_ratelim
, LOG_WARN
, LD_APP
,
61 "Your application (using socks%d to port %d) is giving "
62 "Tor only an IP address. Applications that do DNS resolves "
63 "themselves may leak information. Consider using Socks4A "
64 "(e.g. via privoxy or socat) instead. For more information, "
65 "please see https://wiki.torproject.org/TheOnionRouter/"
66 "TorFAQ#SOCKSAndDNS.%s",
69 safe_socks
? " Rejecting." : "");
71 control_event_client_status(LOG_WARN
,
72 "DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d",
73 socks_protocol
, address
, (int)port
);
76 /** Do not attempt to parse socks messages longer than this. This value is
77 * actually significantly higher than the longest possible socks message. */
78 #define MAX_SOCKS_MESSAGE_LEN 512
80 /** Return a new socks_request_t. */
82 socks_request_new(void)
84 return tor_malloc_zero(sizeof(socks_request_t
));
87 /** Free all storage held in the socks_request_t <b>req</b>. */
89 socks_request_free_(socks_request_t
*req
)
94 memwipe(req
->username
, 0x10, req
->usernamelen
);
95 tor_free(req
->username
);
98 memwipe(req
->password
, 0x04, req
->passwordlen
);
99 tor_free(req
->password
);
101 memwipe(req
, 0xCC, sizeof(socks_request_t
));
106 * Parse a single SOCKS4 request from buffer <b>raw_data</b> of length
107 * <b>datalen</b> and update relevant fields of <b>req</b>. If SOCKS4a
108 * request is detected, set <b>*is_socks4a<b> to true. Set <b>*drain_out</b>
109 * to number of bytes we parsed so far.
111 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
112 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
113 * failed due to incomplete (truncated) input.
115 static socks_result_t
116 parse_socks4_request(const uint8_t *raw_data
, socks_request_t
*req
,
117 size_t datalen
, int *is_socks4a
, size_t *drain_out
)
119 // http://ss5.sourceforge.net/socks4.protocol.txt
120 // http://ss5.sourceforge.net/socks4A.protocol.txt
121 socks_result_t res
= SOCKS_RESULT_DONE
;
124 tor_assert(is_socks4a
);
125 tor_assert(drain_out
);
130 req
->socks_version
= SOCKS_VER_4
;
132 socks4_client_request_t
*trunnel_req
;
135 socks4_client_request_parse(&trunnel_req
, raw_data
, datalen
);
138 log_warn(LD_APP
, "socks4: parsing failed - invalid request.");
139 res
= SOCKS_RESULT_INVALID
;
141 } else if (parsed
== -2) {
142 res
= SOCKS_RESULT_TRUNCATED
;
143 if (datalen
>= MAX_SOCKS_MESSAGE_LEN
) {
144 log_warn(LD_APP
, "socks4: parsing failed - invalid request.");
145 res
= SOCKS_RESULT_INVALID
;
150 tor_assert(parsed
>= 0);
151 *drain_out
= (size_t)parsed
;
153 uint8_t command
= socks4_client_request_get_command(trunnel_req
);
154 req
->command
= command
;
156 req
->port
= socks4_client_request_get_port(trunnel_req
);
157 uint32_t dest_ip
= socks4_client_request_get_addr(trunnel_req
);
159 if ((!req
->port
&& req
->command
!= SOCKS_COMMAND_RESOLVE
) ||
161 log_warn(LD_APP
, "socks4: Port or DestIP is zero. Rejecting.");
162 res
= SOCKS_RESULT_INVALID
;
166 *is_socks4a
= (dest_ip
>> 8) == 0;
168 const char *username
= socks4_client_request_get_username(trunnel_req
);
169 const size_t usernamelen
= username
? strlen(username
) : 0;
170 if (username
&& usernamelen
) {
171 if (usernamelen
> MAX_SOCKS_MESSAGE_LEN
) {
172 log_warn(LD_APP
, "Socks4 user name too long; rejecting.");
173 res
= SOCKS_RESULT_INVALID
;
177 tor_free(req
->username
);
179 req
->username
= tor_strdup(username
);
180 req
->usernamelen
= usernamelen
;
184 // We cannot rely on trunnel here, as we want to detect if
185 // we have abnormally long hostname field.
186 const char *hostname
= (char *)raw_data
+ SOCKS4_NETWORK_LEN
+
188 size_t hostname_len
= (char *)raw_data
+ datalen
- hostname
;
190 if (hostname_len
<= sizeof(req
->address
)) {
191 const char *trunnel_hostname
=
192 socks4_client_request_get_socks4a_addr_hostname(trunnel_req
);
194 if (trunnel_hostname
)
195 strlcpy(req
->address
, trunnel_hostname
, sizeof(req
->address
));
197 log_warn(LD_APP
, "socks4: Destaddr too long. Rejecting.");
198 res
= SOCKS_RESULT_INVALID
;
202 tor_addr_from_ipv4h(&destaddr
, dest_ip
);
204 if (!tor_addr_to_str(req
->address
, &destaddr
,
205 MAX_SOCKS_ADDR_LEN
, 0)) {
206 res
= SOCKS_RESULT_INVALID
;
212 socks4_client_request_free(trunnel_req
);
218 * Validate SOCKS4/4a related fields in <b>req</b>. Expect SOCKS4a
219 * if <b>is_socks4a</b> is true. If <b>log_sockstype</b> is true,
220 * log a notice about possible DNS leaks on local system. If
221 * <b>safe_socks</b> is true, reject insecure usage of SOCKS
224 * Return SOCKS_RESULT_DONE if validation passed or
225 * SOCKS_RESULT_INVALID if it failed.
227 static socks_result_t
228 process_socks4_request(const socks_request_t
*req
, int is_socks4a
,
229 int log_sockstype
, int safe_socks
)
231 if (is_socks4a
&& !addressmap_have_mapping(req
->address
, 0)) {
232 log_unsafe_socks_warning(4, req
->address
, req
->port
, safe_socks
);
235 return SOCKS_RESULT_INVALID
;
238 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
239 req
->command
!= SOCKS_COMMAND_RESOLVE
) {
240 /* not a connect or resolve? we don't support it. (No resolve_ptr with
242 log_warn(LD_APP
, "socks4: command %d not recognized. Rejecting.",
244 return SOCKS_RESULT_INVALID
;
250 "Your application (using socks4a to port %d) instructed "
251 "Tor to take care of the DNS resolution itself if "
252 "necessary. This is good.", req
->port
);
255 if (!string_is_valid_dest(req
->address
)) {
256 log_warn(LD_PROTOCOL
,
257 "Your application (using socks4 to port %d) gave Tor "
258 "a malformed hostname: %s. Rejecting the connection.",
259 req
->port
, escaped_safe_str_client(req
->address
));
260 return SOCKS_RESULT_INVALID
;
263 return SOCKS_RESULT_DONE
;
266 /** Parse a single SOCKS5 version identifier/method selection message
267 * from buffer <b>raw_data</b> (of length <b>datalen</b>). Update
268 * relevant fields of <b>req</b> (if any). Set <b>*have_user_pass</b> to
269 * true if username/password method is found. Set <b>*have_no_auth</b>
270 * if no-auth method is found. Set <b>*drain_out</b> to number of bytes
273 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
274 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
275 * failed due to incomplete (truncated) input.
277 static socks_result_t
278 parse_socks5_methods_request(const uint8_t *raw_data
, socks_request_t
*req
,
279 size_t datalen
, int *have_user_pass
,
280 int *have_no_auth
, size_t *drain_out
)
282 socks_result_t res
= SOCKS_RESULT_DONE
;
283 socks5_client_version_t
*trunnel_req
;
285 ssize_t parsed
= socks5_client_version_parse(&trunnel_req
, raw_data
,
290 tor_assert(have_no_auth
);
291 tor_assert(have_user_pass
);
292 tor_assert(drain_out
);
297 log_warn(LD_APP
, "socks5: parsing failed - invalid version "
298 "id/method selection message.");
299 res
= SOCKS_RESULT_INVALID
;
301 } else if (parsed
== -2) {
302 res
= SOCKS_RESULT_TRUNCATED
;
303 if (datalen
> MAX_SOCKS_MESSAGE_LEN
) {
304 log_warn(LD_APP
, "socks5: parsing failed - invalid version "
305 "id/method selection message.");
306 res
= SOCKS_RESULT_INVALID
;
311 tor_assert(parsed
>= 0);
312 *drain_out
= (size_t)parsed
;
314 size_t n_methods
= (size_t)socks5_client_version_get_n_methods(trunnel_req
);
315 if (n_methods
== 0) {
316 res
= SOCKS_RESULT_INVALID
;
323 for (size_t i
= 0; i
< n_methods
; i
++) {
324 uint8_t method
= socks5_client_version_get_methods(trunnel_req
,
327 if (method
== SOCKS_USER_PASS
) {
329 } else if (method
== SOCKS_NO_AUTH
) {
335 socks5_client_version_free(trunnel_req
);
341 * Validate and respond to version identifier/method selection message
342 * we parsed in parse_socks5_methods_request (corresponding to <b>req</b>
343 * and having user/pass method if <b>have_user_pass</b> is true, no-auth
344 * method if <b>have_no_auth</b> is true). Set <b>req->reply</b> to
345 * an appropriate response (in SOCKS5 wire format).
347 * On success, return SOCKS_RESULT_DONE. On failure, return
348 * SOCKS_RESULT_INVALID.
350 static socks_result_t
351 process_socks5_methods_request(socks_request_t
*req
, int have_user_pass
,
354 socks_result_t res
= SOCKS_RESULT_DONE
;
355 socks5_server_method_t
*trunnel_resp
= socks5_server_method_new();
356 tor_assert(trunnel_resp
);
358 socks5_server_method_set_version(trunnel_resp
, SOCKS_VER_5
);
360 if (have_user_pass
&& !(have_no_auth
&& req
->socks_prefer_no_auth
)) {
361 req
->auth_type
= SOCKS_USER_PASS
;
362 socks5_server_method_set_method(trunnel_resp
, SOCKS_USER_PASS
);
364 req
->socks_version
= SOCKS_VER_5
;
365 // FIXME: come up with better way to remember
366 // that we negotiated auth
368 log_debug(LD_APP
,"socks5: accepted method 2 (username/password)");
369 } else if (have_no_auth
) {
370 req
->auth_type
= SOCKS_NO_AUTH
;
371 socks5_server_method_set_method(trunnel_resp
, SOCKS_NO_AUTH
);
373 req
->socks_version
= SOCKS_VER_5
;
375 log_debug(LD_APP
,"socks5: accepted method 0 (no authentication)");
378 "socks5: offered methods don't include 'no auth' or "
379 "username/password. Rejecting.");
380 socks5_server_method_set_method(trunnel_resp
, 0xFF); // reject all
381 res
= SOCKS_RESULT_INVALID
;
384 const char *errmsg
= socks5_server_method_check(trunnel_resp
);
386 log_warn(LD_APP
, "socks5: method selection validation failed: %s",
388 res
= SOCKS_RESULT_INVALID
;
391 socks5_server_method_encode(req
->reply
, sizeof(req
->reply
),
395 log_warn(LD_APP
, "socks5: method selection encoding failed");
396 res
= SOCKS_RESULT_INVALID
;
398 req
->replylen
= (size_t)encoded
;
402 socks5_server_method_free(trunnel_resp
);
407 * Parse SOCKS5/RFC1929 username/password request from buffer
408 * <b>raw_data</b> of length <b>datalen</b> and update relevant
409 * fields of <b>req</b>. Set <b>*drain_out</b> to number of bytes
412 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
413 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
414 * failed due to incomplete (truncated) input.
416 static socks_result_t
417 parse_socks5_userpass_auth(const uint8_t *raw_data
, socks_request_t
*req
,
418 size_t datalen
, size_t *drain_out
)
420 socks_result_t res
= SOCKS_RESULT_DONE
;
421 socks5_client_userpass_auth_t
*trunnel_req
= NULL
;
422 ssize_t parsed
= socks5_client_userpass_auth_parse(&trunnel_req
, raw_data
,
424 tor_assert(drain_out
);
428 log_warn(LD_APP
, "socks5: parsing failed - invalid user/pass "
429 "authentication message.");
430 res
= SOCKS_RESULT_INVALID
;
432 } else if (parsed
== -2) {
433 res
= SOCKS_RESULT_TRUNCATED
;
437 tor_assert(parsed
>= 0);
438 *drain_out
= (size_t)parsed
;
440 uint8_t usernamelen
=
441 socks5_client_userpass_auth_get_username_len(trunnel_req
);
442 uint8_t passwordlen
=
443 socks5_client_userpass_auth_get_passwd_len(trunnel_req
);
444 const char *username
=
445 socks5_client_userpass_auth_getconstarray_username(trunnel_req
);
446 const char *password
=
447 socks5_client_userpass_auth_getconstarray_passwd(trunnel_req
);
449 if (usernamelen
&& username
) {
450 tor_free(req
->username
);
451 req
->username
= tor_memdup_nulterm(username
, usernamelen
);
452 req
->usernamelen
= usernamelen
;
455 if (passwordlen
&& password
) {
456 tor_free(req
->password
);
457 req
->password
= tor_memdup_nulterm(password
, passwordlen
);
458 req
->passwordlen
= passwordlen
;
462 * Yes, we allow username and/or password to be empty. Yes, that does
463 * violate RFC 1929. However, some client software can send a username/
464 * password message with these fields being empty and we want to allow them
465 * to be used with Tor.
470 socks5_client_userpass_auth_free(trunnel_req
);
475 * Validate and respond to SOCKS5 username/password request we
476 * parsed in parse_socks5_userpass_auth (corresponding to <b>req</b>.
477 * Set <b>req->reply</b> to appropriate responsed. Return
478 * SOCKS_RESULT_DONE on success or SOCKS_RESULT_INVALID on failure.
480 static socks_result_t
481 process_socks5_userpass_auth(socks_request_t
*req
)
483 socks_result_t res
= SOCKS_RESULT_DONE
;
484 socks5_server_userpass_auth_t
*trunnel_resp
=
485 socks5_server_userpass_auth_new();
486 tor_assert(trunnel_resp
);
488 if (req
->socks_version
!= SOCKS_VER_5
) {
489 res
= SOCKS_RESULT_INVALID
;
493 if (req
->auth_type
!= SOCKS_USER_PASS
&&
494 req
->auth_type
!= SOCKS_NO_AUTH
) {
495 res
= SOCKS_RESULT_INVALID
;
499 socks5_server_userpass_auth_set_version(trunnel_resp
, SOCKS_AUTH
);
500 socks5_server_userpass_auth_set_status(trunnel_resp
, 0); // auth OK
502 const char *errmsg
= socks5_server_userpass_auth_check(trunnel_resp
);
504 log_warn(LD_APP
, "socks5: server userpass auth validation failed: %s",
506 res
= SOCKS_RESULT_INVALID
;
510 ssize_t encoded
= socks5_server_userpass_auth_encode(req
->reply
,
515 log_warn(LD_APP
, "socks5: server userpass auth encoding failed");
516 res
= SOCKS_RESULT_INVALID
;
520 req
->replylen
= (size_t)encoded
;
523 socks5_server_userpass_auth_free(trunnel_resp
);
528 * Parse a single SOCKS5 client request (RFC 1928 section 4) from buffer
529 * <b>raw_data</b> of length <b>datalen</b> and update relevant field of
530 * <b>req</b>. Set <b>*drain_out</b> to number of bytes we parsed so far.
532 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
533 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
534 * failed due to incomplete (truncated) input.
536 static socks_result_t
537 parse_socks5_client_request(const uint8_t *raw_data
, socks_request_t
*req
,
538 size_t datalen
, size_t *drain_out
)
540 socks_result_t res
= SOCKS_RESULT_DONE
;
542 socks5_client_request_t
*trunnel_req
= NULL
;
544 socks5_client_request_parse(&trunnel_req
, raw_data
, datalen
);
546 log_warn(LD_APP
, "socks5: parsing failed - invalid client request");
547 res
= SOCKS_RESULT_INVALID
;
548 socks_request_set_socks5_error(req
, SOCKS5_GENERAL_ERROR
);
550 } else if (parsed
== -2) {
551 res
= SOCKS_RESULT_TRUNCATED
;
555 tor_assert(parsed
>= 0);
556 *drain_out
= (size_t)parsed
;
558 if (socks5_client_request_get_version(trunnel_req
) != 5) {
559 res
= SOCKS_RESULT_INVALID
;
560 socks_request_set_socks5_error(req
, SOCKS5_GENERAL_ERROR
);
564 req
->command
= socks5_client_request_get_command(trunnel_req
);
566 req
->port
= socks5_client_request_get_dest_port(trunnel_req
);
568 uint8_t atype
= socks5_client_request_get_atype(trunnel_req
);
569 req
->socks5_atyp
= atype
;
573 uint32_t ipv4
= socks5_client_request_get_dest_addr_ipv4(trunnel_req
);
574 tor_addr_from_ipv4h(&destaddr
, ipv4
);
576 tor_addr_to_str(req
->address
, &destaddr
, sizeof(req
->address
), 1);
579 const struct domainname_st
*dns_name
=
580 socks5_client_request_getconst_dest_addr_domainname(trunnel_req
);
582 const char *hostname
= domainname_getconstarray_name(dns_name
);
584 strlcpy(req
->address
, hostname
, sizeof(req
->address
));
588 (const char *)socks5_client_request_getarray_dest_addr_ipv6(
590 tor_addr_from_ipv6_bytes(&destaddr
, ipv6
);
592 tor_addr_to_str(req
->address
, &destaddr
, sizeof(req
->address
), 1);
595 socks_request_set_socks5_error(req
, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED
);
601 socks5_client_request_free(trunnel_req
);
606 * Validate and respond to SOCKS5 request we parsed in
607 * parse_socks5_client_request (corresponding to <b>req</b>.
608 * Write appropriate response to <b>req->reply</b> (in
609 * SOCKS5 wire format). If <b>log_sockstype</b> is true, log a
610 * notice about possible DNS leaks on local system. If
611 * <b>safe_socks</b> is true, disallow insecure usage of SOCKS
612 * protocol. Return SOCKS_RESULT_DONE on success or
613 * SOCKS_RESULT_INVALID on failure.
615 static socks_result_t
616 process_socks5_client_request(socks_request_t
*req
,
620 socks_result_t res
= SOCKS_RESULT_DONE
;
622 if (req
->command
!= SOCKS_COMMAND_CONNECT
&&
623 req
->command
!= SOCKS_COMMAND_RESOLVE
&&
624 req
->command
!= SOCKS_COMMAND_RESOLVE_PTR
) {
625 socks_request_set_socks5_error(req
,SOCKS5_COMMAND_NOT_SUPPORTED
);
626 res
= SOCKS_RESULT_INVALID
;
630 if (req
->command
== SOCKS_COMMAND_RESOLVE_PTR
&&
631 !string_is_valid_ipv4_address(req
->address
) &&
632 !string_is_valid_ipv6_address(req
->address
)) {
633 socks_request_set_socks5_error(req
, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED
);
634 log_warn(LD_APP
, "socks5 received RESOLVE_PTR command with "
635 "hostname type. Rejecting.");
637 res
= SOCKS_RESULT_INVALID
;
641 if (!string_is_valid_dest(req
->address
)) {
642 socks_request_set_socks5_error(req
, SOCKS5_GENERAL_ERROR
);
644 log_warn(LD_PROTOCOL
,
645 "Your application (using socks5 to port %d) gave Tor "
646 "a malformed hostname: %s. Rejecting the connection.",
647 req
->port
, escaped_safe_str_client(req
->address
));
649 res
= SOCKS_RESULT_INVALID
;
653 if (req
->socks5_atyp
== 1 || req
->socks5_atyp
== 4) {
654 if (req
->command
!= SOCKS_COMMAND_RESOLVE_PTR
&&
655 !addressmap_have_mapping(req
->address
,0)) {
656 log_unsafe_socks_warning(5, req
->address
, req
->port
, safe_socks
);
658 socks_request_set_socks5_error(req
, SOCKS5_NOT_ALLOWED
);
659 res
= SOCKS_RESULT_INVALID
;
667 "Your application (using socks5 to port %d) instructed "
668 "Tor to take care of the DNS resolution itself if "
669 "necessary. This is good.", req
->port
);
676 * Handle (parse, validate, process, respond) a single SOCKS
677 * message in buffer <b>raw_data</b> of length <b>datalen</b>.
678 * Update relevant fields of <b>req</b>. If <b>log_sockstype</b>
679 * is true, log a warning about possible DNS leaks on local
680 * system. If <b>safe_socks</b> is true, disallow insecure
681 * usage of SOCKS protocol. Set <b>*drain_out</b> to number
682 * of bytes in <b>raw_data</b> that we processed so far and
683 * that can be safely drained from buffer.
686 * - SOCKS_RESULT_DONE if succeeded and not expecting further
687 * messages from client.
688 * - SOCKS_RESULT_INVALID if any of the steps failed due to
689 * request being invalid or unexpected given current state.
690 * - SOCKS_RESULT_TRUNCATED if we do not found an expected
691 * SOCKS message in its entirety (more stuff has to arrive
693 * - SOCKS_RESULT_MORE_EXPECTED if we handled current message
694 * successfully, but we expect more messages from the
697 static socks_result_t
698 handle_socks_message(const uint8_t *raw_data
, size_t datalen
,
699 socks_request_t
*req
, int log_sockstype
,
700 int safe_socks
, size_t *drain_out
)
702 socks_result_t res
= SOCKS_RESULT_DONE
;
704 uint8_t socks_version
= raw_data
[0];
706 if (socks_version
== SOCKS_AUTH
)
707 socks_version
= SOCKS_VER_5
; // SOCKS5 username/pass subnegotiation
709 if (socks_version
== SOCKS_VER_4
) {
710 if (datalen
< SOCKS4_NETWORK_LEN
) {
716 res
= parse_socks4_request((const uint8_t *)raw_data
, req
, datalen
,
717 &is_socks4a
, drain_out
);
719 if (res
!= SOCKS_RESULT_DONE
) {
723 res
= process_socks4_request(req
, is_socks4a
,log_sockstype
,
726 if (res
!= SOCKS_RESULT_DONE
) {
731 } else if (socks_version
== SOCKS_VER_5
) {
732 if (datalen
< 2) { /* version and another byte */
736 /* RFC1929 SOCKS5 username/password subnegotiation. */
737 if (!req
->got_auth
&& (raw_data
[0] == 1 ||
738 req
->auth_type
== SOCKS_USER_PASS
)) {
739 res
= parse_socks5_userpass_auth(raw_data
, req
, datalen
,
742 if (res
!= SOCKS_RESULT_DONE
) {
746 res
= process_socks5_userpass_auth(req
);
747 if (res
!= SOCKS_RESULT_DONE
) {
751 res
= SOCKS_RESULT_MORE_EXPECTED
;
753 } else if (req
->socks_version
!= SOCKS_VER_5
) {
754 int have_user_pass
=0, have_no_auth
=0;
755 res
= parse_socks5_methods_request(raw_data
, req
, datalen
,
760 if (res
!= SOCKS_RESULT_DONE
) {
764 res
= process_socks5_methods_request(req
, have_user_pass
,
767 if (res
!= SOCKS_RESULT_DONE
) {
771 res
= SOCKS_RESULT_MORE_EXPECTED
;
774 res
= parse_socks5_client_request(raw_data
, req
,
776 if (BUG(res
== SOCKS_RESULT_INVALID
&& req
->replylen
== 0)) {
777 socks_request_set_socks5_error(req
, SOCKS5_GENERAL_ERROR
);
779 if (res
!= SOCKS_RESULT_DONE
) {
783 res
= process_socks5_client_request(req
, log_sockstype
,
786 if (res
!= SOCKS_RESULT_DONE
) {
791 *drain_out
= datalen
;
792 res
= SOCKS_RESULT_INVALID
;
799 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
801 * - socks4: "socksheader username\\0"
802 * - socks4a: "socksheader username\\0 destaddr\\0"
803 * - socks5 phase one: "version #methods methods"
804 * - socks5 phase two: "version command 0 addresstype..."
805 * If it's a complete and valid handshake, and destaddr fits in
806 * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
807 * assign to <b>req</b>, and return 1.
809 * If it's invalid or too big, return -1.
811 * Else it's not all there yet, leave buf alone and return 0.
813 * If you want to specify the socks reply, write it into <b>req->reply</b>
814 * and set <b>req->replylen</b>, else leave <b>req->replylen</b> alone.
816 * If <b>log_sockstype</b> is non-zero, then do a notice-level log of whether
817 * the connection is possibly leaking DNS requests locally or not.
819 * If <b>safe_socks</b> is true, then reject unsafe socks protocols.
821 * If returning 0 or -1, <b>req->address</b> and <b>req->port</b> are
825 fetch_from_buf_socks(buf_t
*buf
, socks_request_t
*req
,
826 int log_sockstype
, int safe_socks
)
829 size_t datalen
= buf_datalen(buf
);
831 const char *head
= NULL
;
832 socks_result_t socks_res
;
835 if (buf_datalen(buf
) < 2) { /* version and another byte */
842 n_pullup
= MIN(MAX_SOCKS_MESSAGE_LEN
, buf_datalen(buf
));
843 buf_pullup(buf
, n_pullup
, &head
, &datalen
);
844 tor_assert(head
&& datalen
>= 2);
846 socks_res
= parse_socks(head
, datalen
, req
, log_sockstype
,
847 safe_socks
, &n_drain
);
849 if (socks_res
== SOCKS_RESULT_INVALID
)
851 else if (socks_res
!= SOCKS_RESULT_TRUNCATED
&& n_drain
> 0)
852 buf_drain(buf
, n_drain
);
855 case SOCKS_RESULT_INVALID
:
858 case SOCKS_RESULT_DONE
:
861 case SOCKS_RESULT_TRUNCATED
:
862 if (datalen
== n_pullup
)
865 case SOCKS_RESULT_MORE_EXPECTED
:
869 } while (res
== 0 && head
&& buf_datalen(buf
) >= 2);
875 /** Create a SOCKS5 reply message with <b>reason</b> in its REP field and
876 * have Tor send it as error response to <b>req</b>.
879 socks_request_set_socks5_error(socks_request_t
*req
,
880 socks5_reply_status_t reason
)
882 socks5_server_reply_t
*trunnel_resp
= socks5_server_reply_new();
883 tor_assert(trunnel_resp
);
885 socks5_server_reply_set_version(trunnel_resp
, SOCKS_VER_5
);
886 socks5_server_reply_set_reply(trunnel_resp
, reason
);
887 socks5_server_reply_set_atype(trunnel_resp
, 0x01);
889 const char *errmsg
= socks5_server_reply_check(trunnel_resp
);
891 log_warn(LD_APP
, "socks5: reply validation failed: %s",
896 ssize_t encoded
= socks5_server_reply_encode(req
->reply
,
900 log_warn(LD_APP
, "socks5: reply encoding failed: %d",
903 req
->replylen
= (size_t)encoded
;
907 socks5_server_reply_free(trunnel_resp
);
910 static const char SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG
[] =
911 "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
912 "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
915 "<title>This is a SOCKS Proxy, Not An HTTP Proxy</title>\n"
918 "<h1>This is a SOCKs proxy, not an HTTP proxy.</h1>\n"
920 "It appears you have configured your web browser to use this Tor port as\n"
923 "This is not correct: This port is configured as a SOCKS proxy, not\n"
924 "an HTTP proxy. If you need an HTTP proxy tunnel, use the HTTPTunnelPort\n"
925 "configuration option in place of, or in addition to, SOCKSPort.\n"
926 "Please configure your client accordingly.\n"
929 "See <a href=\"https://www.torproject.org/documentation.html\">"
930 "https://www.torproject.org/documentation.html</a> for more "
936 /** Implementation helper to implement fetch_from_*_socks. Instead of looking
937 * at a buffer's contents, we look at the <b>datalen</b> bytes of data in
938 * <b>data</b>. Instead of removing data from the buffer, we set
939 * <b>drain_out</b> to the amount of data that should be removed (or -1 if the
940 * buffer should be cleared). Instead of pulling more data into the first
941 * chunk of the buffer, we set *<b>want_length_out</b> to the number of bytes
942 * we'd like to see in the input buffer, if they're available. */
944 parse_socks(const char *data
, size_t datalen
, socks_request_t
*req
,
945 int log_sockstype
, int safe_socks
, size_t *drain_out
)
950 /* We always need at least 2 bytes. */
954 first_octet
= get_uint8(data
);
956 if (first_octet
== SOCKS_VER_5
|| first_octet
== SOCKS_VER_4
||
957 first_octet
== SOCKS_AUTH
) { // XXX: RFC 1929
958 return handle_socks_message((const uint8_t *)data
, datalen
, req
,
959 log_sockstype
, safe_socks
, drain_out
);
962 switch (first_octet
) { /* which version of socks? */
965 case 'P': /* put/post */
966 case 'C': /* connect */
967 strlcpy((char*)req
->reply
, SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG
,
968 MAX_SOCKS_REPLY_LEN
);
969 req
->replylen
= strlen((char*)req
->reply
)+1;
971 default: /* version is not socks4 or socks5 */
973 "Socks version %d not recognized. (This port is not an "
974 "HTTP proxy; did you want to use HTTPTunnelPort?)",
977 /* Tell the controller the first 8 bytes. */
978 char *tmp
= tor_strndup(data
, datalen
< 8 ? datalen
: 8);
979 control_event_client_status(LOG_WARN
,
980 "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
987 tor_assert_unreached();
991 /** Inspect a reply from SOCKS server stored in <b>buf</b> according
992 * to <b>state</b>, removing the protocol data upon success. Return 0 on
993 * incomplete response, 1 on success and -1 on error, in which case
994 * <b>reason</b> is set to a descriptive message (free() when finished
997 * As a special case, 2 is returned when user/pass is required
998 * during SOCKS5 handshake and user/pass is configured.
1001 fetch_from_buf_socks_client(buf_t
*buf
, int state
, char **reason
)
1005 const char *head
= NULL
;
1008 if (buf_datalen(buf
) < 2)
1011 buf_pullup(buf
, MAX_SOCKS_MESSAGE_LEN
, &head
, &datalen
);
1012 tor_assert(head
&& datalen
>= 2);
1014 r
= parse_socks_client((uint8_t*)head
, datalen
,
1015 state
, reason
, &drain
);
1017 buf_drain(buf
, drain
);
1024 /** Implementation logic for fetch_from_*_socks_client. */
1026 parse_socks_client(const uint8_t *data
, size_t datalen
,
1027 int state
, char **reason
,
1030 unsigned int addrlen
;
1036 case PROXY_SOCKS4_WANT_CONNECT_OK
:
1037 /* Wait for the complete response */
1041 if (data
[1] != 0x5a) {
1042 *reason
= tor_strdup(socks4_response_code_to_string(data
[1]));
1050 case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE
:
1051 /* we don't have any credentials */
1052 if (data
[1] != 0x00) {
1053 *reason
= tor_strdup("server doesn't support any of our "
1054 "available authentication methods");
1058 log_info(LD_NET
, "SOCKS 5 client: continuing without authentication");
1062 case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929
:
1063 /* we have a username and password. return 1 if we can proceed without
1064 * providing authentication, or 2 otherwise. */
1067 log_info(LD_NET
, "SOCKS 5 client: we have auth details but server "
1068 "doesn't require authentication.");
1072 log_info(LD_NET
, "SOCKS 5 client: need authentication.");
1076 /* This wasn't supposed to be exhaustive; there are other
1077 * authentication methods too. */
1081 *reason
= tor_strdup("server doesn't support any of our available "
1082 "authentication methods");
1085 case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK
:
1086 /* handle server reply to rfc1929 authentication */
1087 if (data
[1] != 0x00) {
1088 *reason
= tor_strdup("authentication failed");
1092 log_info(LD_NET
, "SOCKS 5 client: authentication successful.");
1096 case PROXY_SOCKS5_WANT_CONNECT_OK
:
1097 /* response is variable length. BND.ADDR, etc, isn't needed
1098 * (don't bother with buf_pullup()), but make sure to eat all
1101 /* wait for address type field to arrive */
1106 case 0x01: /* ip4 */
1109 case 0x04: /* ip6 */
1112 case 0x03: /* fqdn (can this happen here?) */
1115 addrlen
= 1 + data
[4];
1118 *reason
= tor_strdup("invalid response to connect request");
1122 /* wait for address and port */
1123 if (datalen
< 6 + addrlen
)
1126 if (data
[1] != 0x00) {
1127 *reason
= tor_strdup(socks5_response_code_to_string(data
[1]));
1131 *drain_out
= 6 + addrlen
;
1135 /* LCOV_EXCL_START */
1136 /* shouldn't get here if the input state is one we know about... */
1140 /* LCOV_EXCL_STOP */