Socks5: handle truncated client requests correctly
[tor.git] / src / core / proto / proto_socks.c
blob5a7d7ac9bea18a5dab738b27c4a9bb64720f5d96
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 */
26 typedef enum {
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. */
31 } socks_result_t;
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,
37 size_t datalen,
38 socks_request_t *req,
39 int log_sockstype,
40 int safe_socks,
41 size_t *drain_out);
42 static int parse_socks_client(const uint8_t *data, size_t datalen,
43 int state, char **reason,
44 ssize_t *drain_out);
45 /**
46 * Wait this many seconds before warning the user about using SOCKS unsafely
47 * again. */
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. */
53 static void
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);
59 if (safe_socks) {
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",
67 socks_protocol,
68 (int)port,
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. */
81 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>. */
88 void
89 socks_request_free_(socks_request_t *req)
91 if (!req)
92 return;
93 if (req->username) {
94 memwipe(req->username, 0x10, req->usernamelen);
95 tor_free(req->username);
97 if (req->password) {
98 memwipe(req->password, 0x04, req->passwordlen);
99 tor_free(req->password);
101 memwipe(req, 0xCC, sizeof(socks_request_t));
102 tor_free(req);
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;
122 tor_addr_t destaddr;
124 tor_assert(is_socks4a);
125 tor_assert(drain_out);
127 *is_socks4a = 0;
128 *drain_out = 0;
130 req->socks_version = SOCKS_VER_4;
132 socks4_client_request_t *trunnel_req;
134 ssize_t parsed =
135 socks4_client_request_parse(&trunnel_req, raw_data, datalen);
137 if (parsed == -1) {
138 log_warn(LD_APP, "socks4: parsing failed - invalid request.");
139 res = SOCKS_RESULT_INVALID;
140 goto end;
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;
147 goto end;
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) ||
160 dest_ip == 0) {
161 log_warn(LD_APP, "socks4: Port or DestIP is zero. Rejecting.");
162 res = SOCKS_RESULT_INVALID;
163 goto end;
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;
174 goto end;
177 tor_free(req->username);
178 req->got_auth = 1;
179 req->username = tor_strdup(username);
180 req->usernamelen = usernamelen;
183 if (*is_socks4a) {
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 +
187 usernamelen + 1;
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));
196 } else {
197 log_warn(LD_APP, "socks4: Destaddr too long. Rejecting.");
198 res = SOCKS_RESULT_INVALID;
199 goto end;
201 } else {
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;
207 goto end;
211 end:
212 socks4_client_request_free(trunnel_req);
214 return res;
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
222 * protocol.
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);
234 if (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
241 * socks4.) */
242 log_warn(LD_APP, "socks4: command %d not recognized. Rejecting.",
243 req->command);
244 return SOCKS_RESULT_INVALID;
247 if (is_socks4a) {
248 if (log_sockstype)
249 log_notice(LD_APP,
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
271 * we parsed so far.
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,
286 datalen);
288 (void)req;
290 tor_assert(have_no_auth);
291 tor_assert(have_user_pass);
292 tor_assert(drain_out);
294 *drain_out = 0;
296 if (parsed == -1) {
297 log_warn(LD_APP, "socks5: parsing failed - invalid version "
298 "id/method selection message.");
299 res = SOCKS_RESULT_INVALID;
300 goto end;
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;
308 goto end;
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;
317 goto end;
320 *have_no_auth = 0;
321 *have_user_pass = 0;
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) {
328 *have_user_pass = 1;
329 } else if (method == SOCKS_NO_AUTH) {
330 *have_no_auth = 1;
334 end:
335 socks5_client_version_free(trunnel_req);
337 return res;
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,
352 int have_no_auth)
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)");
376 } else {
377 log_warn(LD_APP,
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);
385 if (errmsg) {
386 log_warn(LD_APP, "socks5: method selection validation failed: %s",
387 errmsg);
388 res = SOCKS_RESULT_INVALID;
389 } else {
390 ssize_t encoded =
391 socks5_server_method_encode(req->reply, sizeof(req->reply),
392 trunnel_resp);
394 if (encoded < 0) {
395 log_warn(LD_APP, "socks5: method selection encoding failed");
396 res = SOCKS_RESULT_INVALID;
397 } else {
398 req->replylen = (size_t)encoded;
402 socks5_server_method_free(trunnel_resp);
403 return res;
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
410 * we parsed so far.
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,
423 datalen);
424 tor_assert(drain_out);
425 *drain_out = 0;
427 if (parsed == -1) {
428 log_warn(LD_APP, "socks5: parsing failed - invalid user/pass "
429 "authentication message.");
430 res = SOCKS_RESULT_INVALID;
431 goto end;
432 } else if (parsed == -2) {
433 res = SOCKS_RESULT_TRUNCATED;
434 goto end;
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.
467 req->got_auth = 1;
469 end:
470 socks5_client_userpass_auth_free(trunnel_req);
471 return res;
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;
490 goto end;
493 if (req->auth_type != SOCKS_USER_PASS &&
494 req->auth_type != SOCKS_NO_AUTH) {
495 res = SOCKS_RESULT_INVALID;
496 goto end;
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);
503 if (errmsg) {
504 log_warn(LD_APP, "socks5: server userpass auth validation failed: %s",
505 errmsg);
506 res = SOCKS_RESULT_INVALID;
507 goto end;
510 ssize_t encoded = socks5_server_userpass_auth_encode(req->reply,
511 sizeof(req->reply),
512 trunnel_resp);
514 if (encoded < 0) {
515 log_warn(LD_APP, "socks5: server userpass auth encoding failed");
516 res = SOCKS_RESULT_INVALID;
517 goto end;
520 req->replylen = (size_t)encoded;
522 end:
523 socks5_server_userpass_auth_free(trunnel_resp);
524 return res;
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;
541 tor_addr_t destaddr;
542 socks5_client_request_t *trunnel_req = NULL;
543 ssize_t parsed =
544 socks5_client_request_parse(&trunnel_req, raw_data, datalen);
545 if (parsed == -1) {
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);
549 goto end;
550 } else if (parsed == -2) {
551 res = SOCKS_RESULT_TRUNCATED;
552 goto end;
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);
561 goto end;
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;
571 switch (atype) {
572 case 1: {
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);
577 } break;
578 case 3: {
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));
585 } break;
586 case 4: {
587 const char *ipv6 =
588 (const char *)socks5_client_request_getarray_dest_addr_ipv6(
589 trunnel_req);
590 tor_addr_from_ipv6_bytes(&destaddr, ipv6);
592 tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
593 } break;
594 default: {
595 socks_request_set_socks5_error(req, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
596 res = -1;
597 } break;
600 end:
601 socks5_client_request_free(trunnel_req);
602 return res;
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,
617 int log_sockstype,
618 int safe_socks)
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;
627 goto end;
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;
638 goto end;
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;
650 goto end;
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);
657 if (safe_socks) {
658 socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
659 res = SOCKS_RESULT_INVALID;
660 goto end;
665 if (log_sockstype)
666 log_notice(LD_APP,
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);
671 end:
672 return res;
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.
685 * Return:
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
692 * from client).
693 * - SOCKS_RESULT_MORE_EXPECTED if we handled current message
694 * successfully, but we expect more messages from the
695 * client.
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) {
711 res = 0;
712 goto end;
715 int is_socks4a = 0;
716 res = parse_socks4_request((const uint8_t *)raw_data, req, datalen,
717 &is_socks4a, drain_out);
719 if (res != SOCKS_RESULT_DONE) {
720 goto end;
723 res = process_socks4_request(req, is_socks4a,log_sockstype,
724 safe_socks);
726 if (res != SOCKS_RESULT_DONE) {
727 goto end;
730 goto end;
731 } else if (socks_version == SOCKS_VER_5) {
732 if (datalen < 2) { /* version and another byte */
733 res = 0;
734 goto end;
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,
740 drain_out);
742 if (res != SOCKS_RESULT_DONE) {
743 goto end;
746 res = process_socks5_userpass_auth(req);
747 if (res != SOCKS_RESULT_DONE) {
748 goto end;
751 res = SOCKS_RESULT_MORE_EXPECTED;
752 goto end;
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,
756 &have_user_pass,
757 &have_no_auth,
758 drain_out);
760 if (res != SOCKS_RESULT_DONE) {
761 goto end;
764 res = process_socks5_methods_request(req, have_user_pass,
765 have_no_auth);
767 if (res != SOCKS_RESULT_DONE) {
768 goto end;
771 res = SOCKS_RESULT_MORE_EXPECTED;
772 goto end;
773 } else {
774 res = parse_socks5_client_request(raw_data, req,
775 datalen, drain_out);
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) {
780 goto end;
783 res = process_socks5_client_request(req, log_sockstype,
784 safe_socks);
786 if (res != SOCKS_RESULT_DONE) {
787 goto end;
790 } else {
791 *drain_out = datalen;
792 res = SOCKS_RESULT_INVALID;
795 end:
796 return res;
799 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
800 * of the forms
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
822 * undefined.
825 fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
826 int log_sockstype, int safe_socks)
828 int res = 0;
829 size_t datalen = buf_datalen(buf);
830 size_t n_drain;
831 const char *head = NULL;
832 socks_result_t socks_res;
833 size_t n_pullup;
835 if (buf_datalen(buf) < 2) { /* version and another byte */
836 res = 0;
837 goto end;
840 do {
841 n_drain = 0;
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)
850 buf_clear(buf);
851 else if (socks_res != SOCKS_RESULT_TRUNCATED && n_drain > 0)
852 buf_drain(buf, n_drain);
854 switch (socks_res) {
855 case SOCKS_RESULT_INVALID:
856 res = -1;
857 break;
858 case SOCKS_RESULT_DONE:
859 res = 1;
860 break;
861 case SOCKS_RESULT_TRUNCATED:
862 if (datalen == n_pullup)
863 return 0;
864 FALLTHROUGH;
865 case SOCKS_RESULT_MORE_EXPECTED:
866 res = 0;
867 break;
869 } while (res == 0 && head && buf_datalen(buf) >= 2);
871 end:
872 return res;
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>.
878 static void
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);
890 if (errmsg) {
891 log_warn(LD_APP, "socks5: reply validation failed: %s",
892 errmsg);
893 goto end;
896 ssize_t encoded = socks5_server_reply_encode(req->reply,
897 sizeof(req->reply),
898 trunnel_resp);
899 if (encoded < 0) {
900 log_warn(LD_APP, "socks5: reply encoding failed: %d",
901 (int)encoded);
902 } else {
903 req->replylen = (size_t)encoded;
906 end:
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"
913 "<html>\n"
914 "<head>\n"
915 "<title>This is a SOCKS Proxy, Not An HTTP Proxy</title>\n"
916 "</head>\n"
917 "<body>\n"
918 "<h1>This is a SOCKs proxy, not an HTTP proxy.</h1>\n"
919 "<p>\n"
920 "It appears you have configured your web browser to use this Tor port as\n"
921 "an HTTP proxy.\n"
922 "</p><p>\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"
927 "</p>\n"
928 "<p>\n"
929 "See <a href=\"https://www.torproject.org/documentation.html\">"
930 "https://www.torproject.org/documentation.html</a> for more "
931 "information.\n"
932 "</p>\n"
933 "</body>\n"
934 "</html>\n";
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. */
943 static int
944 parse_socks(const char *data, size_t datalen, socks_request_t *req,
945 int log_sockstype, int safe_socks, size_t *drain_out)
947 uint8_t first_octet;
949 if (datalen < 2) {
950 /* We always need at least 2 bytes. */
951 return 0;
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? */
963 case 'G': /* get */
964 case 'H': /* head */
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;
970 FALLTHROUGH;
971 default: /* version is not socks4 or socks5 */
972 log_warn(LD_APP,
973 "Socks version %d not recognized. (This port is not an "
974 "HTTP proxy; did you want to use HTTPTunnelPort?)",
975 *(data));
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\"",
981 escaped(tmp));
982 tor_free(tmp);
984 return -1;
987 tor_assert_unreached();
988 return -1;
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
995 * with it).
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)
1003 ssize_t drain = 0;
1004 int r;
1005 const char *head = NULL;
1006 size_t datalen = 0;
1008 if (buf_datalen(buf) < 2)
1009 return 0;
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);
1016 if (drain > 0)
1017 buf_drain(buf, drain);
1018 else if (drain < 0)
1019 buf_clear(buf);
1021 return r;
1024 /** Implementation logic for fetch_from_*_socks_client. */
1025 static int
1026 parse_socks_client(const uint8_t *data, size_t datalen,
1027 int state, char **reason,
1028 ssize_t *drain_out)
1030 unsigned int addrlen;
1031 *drain_out = 0;
1032 if (datalen < 2)
1033 return 0;
1035 switch (state) {
1036 case PROXY_SOCKS4_WANT_CONNECT_OK:
1037 /* Wait for the complete response */
1038 if (datalen < 8)
1039 return 0;
1041 if (data[1] != 0x5a) {
1042 *reason = tor_strdup(socks4_response_code_to_string(data[1]));
1043 return -1;
1046 /* Success */
1047 *drain_out = 8;
1048 return 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");
1055 return -1;
1058 log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
1059 *drain_out = -1;
1060 return 1;
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. */
1065 switch (data[1]) {
1066 case 0x00:
1067 log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
1068 "doesn't require authentication.");
1069 *drain_out = -1;
1070 return 1;
1071 case 0x02:
1072 log_info(LD_NET, "SOCKS 5 client: need authentication.");
1073 *drain_out = -1;
1074 return 2;
1075 default:
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");
1083 return -1;
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");
1089 return -1;
1092 log_info(LD_NET, "SOCKS 5 client: authentication successful.");
1093 *drain_out = -1;
1094 return 1;
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
1099 * the data used */
1101 /* wait for address type field to arrive */
1102 if (datalen < 4)
1103 return 0;
1105 switch (data[3]) {
1106 case 0x01: /* ip4 */
1107 addrlen = 4;
1108 break;
1109 case 0x04: /* ip6 */
1110 addrlen = 16;
1111 break;
1112 case 0x03: /* fqdn (can this happen here?) */
1113 if (datalen < 5)
1114 return 0;
1115 addrlen = 1 + data[4];
1116 break;
1117 default:
1118 *reason = tor_strdup("invalid response to connect request");
1119 return -1;
1122 /* wait for address and port */
1123 if (datalen < 6 + addrlen)
1124 return 0;
1126 if (data[1] != 0x00) {
1127 *reason = tor_strdup(socks5_response_code_to_string(data[1]));
1128 return -1;
1131 *drain_out = 6 + addrlen;
1132 return 1;
1135 /* LCOV_EXCL_START */
1136 /* shouldn't get here if the input state is one we know about... */
1137 tor_assert(0);
1139 return -1;
1140 /* LCOV_EXCL_STOP */