Tor 0.4.9.8
Loading...
Searching...
No Matches
proto_socks.c
Go to the documentation of this file.
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-2021, The Tor Project, Inc. */
5/* See LICENSE for licensing information */
6
7/**
8 * @file proto_socks.c
9 * @brief Implementations for SOCKS4 and SOCKS5 protocols.
10 **/
11
12#include "core/or/or.h"
14#include "lib/buf/buffers.h"
17#include "app/config/config.h"
21#include "core/or/reasons.h"
22
24
25#include "trunnel/socks5.h"
26
27#define SOCKS_VER_5 0x05 /* First octet of non-auth SOCKS5 messages */
28#define SOCKS_VER_4 0x04 /* SOCKS4 messages */
29#define SOCKS_AUTH 0x01 /* SOCKS5 auth messages */
30
31typedef enum {
32 SOCKS_RESULT_INVALID = -1, /* Message invalid. */
33 SOCKS_RESULT_TRUNCATED = 0, /* Message incomplete/truncated. */
34 SOCKS_RESULT_DONE = 1, /* OK, we're done. */
35 SOCKS_RESULT_MORE_EXPECTED = 2, /* OK, more messages expected. */
36} socks_result_t;
37
40
41static socks_result_t parse_socks(const char *data,
42 size_t datalen,
43 socks_request_t *req,
44 int log_sockstype,
45 int safe_socks,
46 size_t *drain_out);
47static int parse_socks_client(const uint8_t *data, size_t datalen,
48 int state, char **reason,
49 ssize_t *drain_out);
50/**
51 * Wait this many seconds before warning the user about using SOCKS unsafely
52 * again. */
53#define SOCKS_WARN_INTERVAL 5
54
55/** Warn that the user application has made an unsafe socks request using
56 * protocol <b>socks_protocol</b> on port <b>port</b>. Don't warn more than
57 * once per SOCKS_WARN_INTERVAL, unless <b>safe_socks</b> is set. */
58static void
59log_unsafe_socks_warning(int socks_protocol, const char *address,
60 uint16_t port, int safe_socks)
61{
62 static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL);
63
64 if (safe_socks) {
65 log_fn_ratelim(&socks_ratelim, LOG_WARN, LD_APP,
66 "Your application (using socks%d to port %d) is giving "
67 "Tor only an IP address. Applications that do DNS resolves "
68 "themselves may leak information. Consider using Socks4A "
69 "(e.g. via privoxy or socat) instead. For more information, "
70 "please see https://2019.www.torproject.org/docs/faq.html.en"
71 "#WarningsAboutSOCKSandDNSInformationLeaks.%s",
72 socks_protocol,
73 (int)port,
74 safe_socks ? " Rejecting." : "");
75 }
77 "DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d",
78 socks_protocol, address, (int)port);
79}
80
81/** Do not attempt to parse socks messages longer than this. This value is
82 * actually significantly higher than the longest possible socks message. */
83#define MAX_SOCKS_MESSAGE_LEN 512
84
85/** Return a new socks_request_t. */
88{
89 return tor_malloc_zero(sizeof(socks_request_t));
90}
91
92/** Free all storage held in the socks_request_t <b>req</b>. */
93void
95{
96 if (!req)
97 return;
98 if (req->username) {
99 memwipe(req->username, 0x10, req->usernamelen);
100 tor_free(req->username);
101 }
102 if (req->password) {
103 memwipe(req->password, 0x04, req->passwordlen);
104 tor_free(req->password);
105 }
106 memwipe(req, 0xCC, sizeof(socks_request_t));
107 tor_free(req);
108}
109
110/**
111 * Parse a single SOCKS4 request from buffer <b>raw_data</b> of length
112 * <b>datalen</b> and update relevant fields of <b>req</b>. If SOCKS4a
113 * request is detected, set <b>*is_socks4a</b> to true. Set <b>*drain_out</b>
114 * to number of bytes we parsed so far.
115 *
116 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
117 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
118 * failed due to incomplete (truncated) input.
119 */
120static socks_result_t
121parse_socks4_request(const uint8_t *raw_data, socks_request_t *req,
122 size_t datalen, int *is_socks4a, size_t *drain_out)
123{
124 // http://ss5.sourceforge.net/socks4.protocol.txt
125 // http://ss5.sourceforge.net/socks4A.protocol.txt
126 socks_result_t res = SOCKS_RESULT_DONE;
127 tor_addr_t destaddr;
128
129 tor_assert(is_socks4a);
130 tor_assert(drain_out);
131
132 *is_socks4a = 0;
133 *drain_out = 0;
134
135 req->socks_version = SOCKS_VER_4;
136
137 socks4_client_request_t *trunnel_req;
138
139 ssize_t parsed =
140 socks4_client_request_parse(&trunnel_req, raw_data, datalen);
141
142 if (parsed == -1) {
143 log_warn(LD_APP, "socks4: parsing failed - invalid request.");
144 res = SOCKS_RESULT_INVALID;
145 goto end;
146 } else if (parsed == -2) {
147 res = SOCKS_RESULT_TRUNCATED;
148 if (datalen >= MAX_SOCKS_MESSAGE_LEN) {
149 log_warn(LD_APP, "socks4: parsing failed - invalid request.");
150 res = SOCKS_RESULT_INVALID;
151 }
152 goto end;
153 }
154
155 tor_assert(parsed >= 0);
156 *drain_out = (size_t)parsed;
157
158 uint8_t command = socks4_client_request_get_command(trunnel_req);
159 req->command = command;
160
161 req->port = socks4_client_request_get_port(trunnel_req);
162 uint32_t dest_ip = socks4_client_request_get_addr(trunnel_req);
163
164 if ((!req->port && req->command != SOCKS_COMMAND_RESOLVE) ||
165 dest_ip == 0) {
166 log_warn(LD_APP, "socks4: Port or DestIP is zero. Rejecting.");
167 res = SOCKS_RESULT_INVALID;
168 goto end;
169 }
170
171 *is_socks4a = (dest_ip >> 8) == 0;
172
173 const char *username = socks4_client_request_get_username(trunnel_req);
174 const size_t usernamelen = username ? strlen(username) : 0;
175 if (username && usernamelen) {
176 if (usernamelen > MAX_SOCKS_MESSAGE_LEN) {
177 log_warn(LD_APP, "Socks4 user name too long; rejecting.");
178 res = SOCKS_RESULT_INVALID;
179 goto end;
180 }
181
182 tor_free(req->username);
183 req->got_auth = 1;
184 req->username = tor_strdup(username);
185 req->usernamelen = usernamelen;
186 }
187
188 if (*is_socks4a) {
189 const char *trunnel_hostname =
190 socks4_client_request_get_socks4a_addr_hostname(trunnel_req);
191 if (BUG(!trunnel_hostname)) {
192 res = SOCKS_RESULT_INVALID;
193 goto end;
194 }
195 size_t hostname_len = strlen(trunnel_hostname);
196 if (hostname_len < sizeof(req->address)) {
197 strlcpy(req->address, trunnel_hostname, sizeof(req->address));
198 } else {
199 log_warn(LD_APP, "socks4: Destaddr too long. Rejecting.");
200 res = SOCKS_RESULT_INVALID;
201 goto end;
202 }
203 } else {
204 tor_addr_from_ipv4h(&destaddr, dest_ip);
205
206 if (!tor_addr_to_str(req->address, &destaddr,
207 MAX_SOCKS_ADDR_LEN, 0)) {
208 res = SOCKS_RESULT_INVALID;
209 goto end;
210 }
211 }
212
213 end:
214 socks4_client_request_free(trunnel_req);
215
216 return res;
217}
218
219/**
220 * Validate SOCKS4/4a related fields in <b>req</b>. Expect SOCKS4a
221 * if <b>is_socks4a</b> is true. If <b>log_sockstype</b> is true,
222 * log a notice about possible DNS leaks on local system. If
223 * <b>safe_socks</b> is true, reject insecure usage of SOCKS
224 * protocol.
225 *
226 * Return SOCKS_RESULT_DONE if validation passed or
227 * SOCKS_RESULT_INVALID if it failed.
228 */
229static socks_result_t
230process_socks4_request(const socks_request_t *req, int is_socks4a,
231 int log_sockstype, int safe_socks)
232{
233 if (!is_socks4a && !addressmap_have_mapping(req->address, 0)) {
234 log_unsafe_socks_warning(4, req->address, req->port, safe_socks);
235
236 if (safe_socks)
237 return SOCKS_RESULT_INVALID;
238 }
239
240 if (req->command != SOCKS_COMMAND_CONNECT &&
242 /* not a connect or resolve? we don't support it. (No resolve_ptr with
243 * socks4.) */
244 log_warn(LD_APP, "socks4: command %d not recognized. Rejecting.",
245 req->command);
246 return SOCKS_RESULT_INVALID;
247 }
248
249 if (is_socks4a) {
250 if (log_sockstype)
251 log_notice(LD_APP,
252 "Your application (using socks4a to port %d) instructed "
253 "Tor to take care of the DNS resolution itself if "
254 "necessary. This is good.", req->port);
255 }
256
257 if (!string_is_valid_dest(req->address)) {
258 log_warn(LD_PROTOCOL,
259 "Your application (using socks4 to port %d) gave Tor "
260 "a malformed hostname: %s. Rejecting the connection.",
262 return SOCKS_RESULT_INVALID;
263 }
264
265 return SOCKS_RESULT_DONE;
266}
267
268/** Parse a single SOCKS5 version identifier/method selection message
269 * from buffer <b>raw_data</b> (of length <b>datalen</b>). Update
270 * relevant fields of <b>req</b> (if any). Set <b>*have_user_pass</b> to
271 * true if username/password method is found. Set <b>*have_no_auth</b>
272 * if no-auth method is found. Set <b>*drain_out</b> to number of bytes
273 * we parsed so far.
274 *
275 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
276 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
277 * failed due to incomplete (truncated) input.
278 */
279static socks_result_t
280parse_socks5_methods_request(const uint8_t *raw_data, socks_request_t *req,
281 size_t datalen, int *have_user_pass,
282 int *have_no_auth, size_t *drain_out)
283{
284 socks_result_t res = SOCKS_RESULT_DONE;
285 socks5_client_version_t *trunnel_req;
286
287 ssize_t parsed = socks5_client_version_parse(&trunnel_req, raw_data,
288 datalen);
289
290 (void)req;
291
292 tor_assert(have_no_auth);
293 tor_assert(have_user_pass);
294 tor_assert(drain_out);
295
296 *drain_out = 0;
297
298 if (parsed == -1) {
299 log_warn(LD_APP, "socks5: parsing failed - invalid version "
300 "id/method selection message.");
301 res = SOCKS_RESULT_INVALID;
302 goto end;
303 } else if (parsed == -2) {
304 res = SOCKS_RESULT_TRUNCATED;
305 if (datalen > MAX_SOCKS_MESSAGE_LEN) {
306 log_warn(LD_APP, "socks5: parsing failed - invalid version "
307 "id/method selection message.");
308 res = SOCKS_RESULT_INVALID;
309 }
310 goto end;
311 }
312
313 tor_assert(parsed >= 0);
314 *drain_out = (size_t)parsed;
315
316 size_t n_methods = (size_t)socks5_client_version_get_n_methods(trunnel_req);
317 if (n_methods == 0) {
318 res = SOCKS_RESULT_INVALID;
319 goto end;
320 }
321
322 *have_no_auth = 0;
323 *have_user_pass = 0;
324
325 for (size_t i = 0; i < n_methods; i++) {
326 uint8_t method = socks5_client_version_get_methods(trunnel_req,
327 i);
328
329 if (method == SOCKS_USER_PASS) {
330 *have_user_pass = 1;
331 } else if (method == SOCKS_NO_AUTH) {
332 *have_no_auth = 1;
333 }
334 }
335
336 end:
337 socks5_client_version_free(trunnel_req);
338
339 return res;
340}
341
342/**
343 * Validate and respond to version identifier/method selection message
344 * we parsed in parse_socks5_methods_request (corresponding to <b>req</b>
345 * and having user/pass method if <b>have_user_pass</b> is true, no-auth
346 * method if <b>have_no_auth</b> is true). Set <b>req->reply</b> to
347 * an appropriate response (in SOCKS5 wire format).
348 *
349 * On success, return SOCKS_RESULT_DONE. On failure, return
350 * SOCKS_RESULT_INVALID.
351 */
352static socks_result_t
354 int have_no_auth)
355{
356 socks_result_t res = SOCKS_RESULT_DONE;
357 socks5_server_method_t *trunnel_resp = socks5_server_method_new();
358 tor_assert(trunnel_resp);
359
360 socks5_server_method_set_version(trunnel_resp, SOCKS_VER_5);
361
362 if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) {
363 req->auth_type = SOCKS_USER_PASS;
364 socks5_server_method_set_method(trunnel_resp, SOCKS_USER_PASS);
365
366 req->socks_version = SOCKS_VER_5;
367 // FIXME: come up with better way to remember
368 // that we negotiated auth
369
370 log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
371 } else if (have_no_auth) {
372 req->auth_type = SOCKS_NO_AUTH;
373 socks5_server_method_set_method(trunnel_resp, SOCKS_NO_AUTH);
374
375 req->socks_version = SOCKS_VER_5;
376
377 log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
378 } else {
379 log_warn(LD_APP,
380 "socks5: offered methods don't include 'no auth' or "
381 "username/password. Rejecting.");
382 socks5_server_method_set_method(trunnel_resp, 0xFF); // reject all
383 res = SOCKS_RESULT_INVALID;
384 }
385
386 const char *errmsg = socks5_server_method_check(trunnel_resp);
387 if (errmsg) {
388 log_warn(LD_APP, "socks5: method selection validation failed: %s",
389 errmsg);
390 res = SOCKS_RESULT_INVALID;
391 } else {
392 ssize_t encoded =
393 socks5_server_method_encode(req->reply, sizeof(req->reply),
394 trunnel_resp);
395
396 if (encoded < 0) {
397 log_warn(LD_APP, "socks5: method selection encoding failed");
398 res = SOCKS_RESULT_INVALID;
399 } else {
400 req->replylen = (size_t)encoded;
401 }
402 }
403
404 socks5_server_method_free(trunnel_resp);
405 return res;
406}
407
408/**
409 * Parse SOCKS5/RFC1929 username/password request from buffer
410 * <b>raw_data</b> of length <b>datalen</b> and update relevant
411 * fields of <b>req</b>. Set <b>*drain_out</b> to number of bytes
412 * we parsed so far.
413 *
414 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
415 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
416 * failed due to incomplete (truncated) input.
417 */
418static socks_result_t
419parse_socks5_userpass_auth(const uint8_t *raw_data, socks_request_t *req,
420 size_t datalen, size_t *drain_out)
421{
422 socks_result_t res = SOCKS_RESULT_DONE;
423 socks5_client_userpass_auth_t *trunnel_req = NULL;
424 ssize_t parsed = socks5_client_userpass_auth_parse(&trunnel_req, raw_data,
425 datalen);
426 tor_assert(drain_out);
427 *drain_out = 0;
428
429 if (parsed == -1) {
430 log_warn(LD_APP, "socks5: parsing failed - invalid user/pass "
431 "authentication message.");
432 res = SOCKS_RESULT_INVALID;
433 goto end;
434 } else if (parsed == -2) {
435 res = SOCKS_RESULT_TRUNCATED;
436 goto end;
437 }
438
439 tor_assert(parsed >= 0);
440 *drain_out = (size_t)parsed;
441
442 uint8_t usernamelen =
443 socks5_client_userpass_auth_get_username_len(trunnel_req);
444 uint8_t passwordlen =
445 socks5_client_userpass_auth_get_passwd_len(trunnel_req);
446 const char *username =
447 socks5_client_userpass_auth_getconstarray_username(trunnel_req);
448 const char *password =
449 socks5_client_userpass_auth_getconstarray_passwd(trunnel_req);
450
451 /* Detect invalid SOCKS5 extended-parameter requests. */
452 if (usernamelen >= 8 &&
453 tor_memeq(username, "<torS0X>", 8)) {
454 /* This is indeed an extended-parameter request. */
455 if (usernamelen != 9 ||
456 tor_memneq(username, "<torS0X>0", 9)) {
457 /* This request is an unrecognized version, or it includes an Arti RPC
458 * object ID (which we do not recognize). */
459 res = SOCKS_RESULT_INVALID;
460 goto end;
461 }
462 }
463
464 if (usernamelen && username) {
465 tor_free(req->username);
466 req->username = tor_memdup_nulterm(username, usernamelen);
467 req->usernamelen = usernamelen;
468 }
469
470 if (passwordlen && password) {
471 tor_free(req->password);
472 req->password = tor_memdup_nulterm(password, passwordlen);
473 req->passwordlen = passwordlen;
474 }
475
476 /**
477 * Yes, we allow username and/or password to be empty. Yes, that does
478 * violate RFC 1929. However, some client software can send a username/
479 * password message with these fields being empty and we want to allow them
480 * to be used with Tor.
481 */
482 req->got_auth = 1;
483
484 end:
485 socks5_client_userpass_auth_free(trunnel_req);
486 return res;
487}
488
489/**
490 * Validate and respond to SOCKS5 username/password request we
491 * parsed in parse_socks5_userpass_auth (corresponding to <b>req</b>.
492 * Set <b>req->reply</b> to appropriate response. Return
493 * SOCKS_RESULT_DONE on success or SOCKS_RESULT_INVALID on failure.
494 */
495static socks_result_t
497{
498 socks_result_t res = SOCKS_RESULT_DONE;
499 socks5_server_userpass_auth_t *trunnel_resp =
500 socks5_server_userpass_auth_new();
501 tor_assert(trunnel_resp);
502
503 if (req->socks_version != SOCKS_VER_5) {
504 res = SOCKS_RESULT_INVALID;
505 goto end;
506 }
507
508 if (req->auth_type != SOCKS_USER_PASS &&
509 req->auth_type != SOCKS_NO_AUTH) {
510 res = SOCKS_RESULT_INVALID;
511 goto end;
512 }
513
514 socks5_server_userpass_auth_set_version(trunnel_resp, SOCKS_AUTH);
515 socks5_server_userpass_auth_set_status(trunnel_resp, 0); // auth OK
516
517 const char *errmsg = socks5_server_userpass_auth_check(trunnel_resp);
518 if (errmsg) {
519 log_warn(LD_APP, "socks5: server userpass auth validation failed: %s",
520 errmsg);
521 res = SOCKS_RESULT_INVALID;
522 goto end;
523 }
524
525 ssize_t encoded = socks5_server_userpass_auth_encode(req->reply,
526 sizeof(req->reply),
527 trunnel_resp);
528
529 if (encoded < 0) {
530 log_warn(LD_APP, "socks5: server userpass auth encoding failed");
531 res = SOCKS_RESULT_INVALID;
532 goto end;
533 }
534
535 req->replylen = (size_t)encoded;
536
537 end:
538 socks5_server_userpass_auth_free(trunnel_resp);
539 return res;
540}
541
542/**
543 * Parse a single SOCKS5 client request (RFC 1928 section 4) from buffer
544 * <b>raw_data</b> of length <b>datalen</b> and update relevant field of
545 * <b>req</b>. Set <b>*drain_out</b> to number of bytes we parsed so far.
546 *
547 * Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if
548 * parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it
549 * failed due to incomplete (truncated) input.
550 */
551static socks_result_t
552parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req,
553 size_t datalen, size_t *drain_out)
554{
555 socks_result_t res = SOCKS_RESULT_DONE;
556 tor_addr_t destaddr;
557 socks5_client_request_t *trunnel_req = NULL;
558 ssize_t parsed =
559 socks5_client_request_parse(&trunnel_req, raw_data, datalen);
560 if (parsed == -1) {
561 log_warn(LD_APP, "socks5: parsing failed - invalid client request");
562 res = SOCKS_RESULT_INVALID;
563 socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
564 goto end;
565 } else if (parsed == -2) {
566 res = SOCKS_RESULT_TRUNCATED;
567 goto end;
568 }
569
570 tor_assert(parsed >= 0);
571 *drain_out = (size_t)parsed;
572
573 if (socks5_client_request_get_version(trunnel_req) != 5) {
574 res = SOCKS_RESULT_INVALID;
575 socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
576 goto end;
577 }
578
579 req->command = socks5_client_request_get_command(trunnel_req);
580
581 req->port = socks5_client_request_get_dest_port(trunnel_req);
582
583 uint8_t atype = socks5_client_request_get_atype(trunnel_req);
584 req->socks5_atyp = atype;
585
586 switch (atype) {
587 case 1: {
588 uint32_t ipv4 = socks5_client_request_get_dest_addr_ipv4(trunnel_req);
589 tor_addr_from_ipv4h(&destaddr, ipv4);
590
591 tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
592 } break;
593 case 3: {
594 const struct domainname_st *dns_name =
595 socks5_client_request_getconst_dest_addr_domainname(trunnel_req);
596
597 const char *hostname = domainname_getconstarray_name(dns_name);
598
599 strlcpy(req->address, hostname, sizeof(req->address));
600 } break;
601 case 4: {
602 const uint8_t *ipv6 =
603 socks5_client_request_getarray_dest_addr_ipv6(trunnel_req);
604 tor_addr_from_ipv6_bytes(&destaddr, ipv6);
605
606 tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
607 } break;
608 default: {
609 socks_request_set_socks5_error(req, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
610 res = -1;
611 } break;
612 }
613
614 end:
615 socks5_client_request_free(trunnel_req);
616 return res;
617}
618
619/**
620 * Validate and respond to SOCKS5 request we parsed in
621 * parse_socks5_client_request (corresponding to <b>req</b>.
622 * Write appropriate response to <b>req->reply</b> (in
623 * SOCKS5 wire format). If <b>log_sockstype</b> is true, log a
624 * notice about possible DNS leaks on local system. If
625 * <b>safe_socks</b> is true, disallow insecure usage of SOCKS
626 * protocol. Return SOCKS_RESULT_DONE on success or
627 * SOCKS_RESULT_INVALID on failure.
628 */
629static socks_result_t
631 int log_sockstype,
632 int safe_socks)
633{
634 socks_result_t res = SOCKS_RESULT_DONE;
635 tor_addr_t tmpaddr;
636
637 if (req->command != SOCKS_COMMAND_CONNECT &&
640 socks_request_set_socks5_error(req,SOCKS5_COMMAND_NOT_SUPPORTED);
641 res = SOCKS_RESULT_INVALID;
642 goto end;
643 }
644
646 tor_addr_parse(&tmpaddr, req->address) < 0) {
647 socks_request_set_socks5_error(req, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
648 log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
649 "a malformed address. Rejecting.");
650
651 res = SOCKS_RESULT_INVALID;
652 goto end;
653 }
654
655 if (!string_is_valid_dest(req->address)) {
656 socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
657
658 log_warn(LD_PROTOCOL,
659 "Your application (using socks5 to port %d) gave Tor "
660 "a malformed hostname: %s. Rejecting the connection.",
662
663 res = SOCKS_RESULT_INVALID;
664 goto end;
665 }
666
667 if (req->socks5_atyp == 1 || req->socks5_atyp == 4) {
670 log_unsafe_socks_warning(5, req->address, req->port, safe_socks);
671 if (safe_socks) {
672 socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
673 res = SOCKS_RESULT_INVALID;
674 goto end;
675 }
676 }
677 }
678
679 if (log_sockstype)
680 log_notice(LD_APP,
681 "Your application (using socks5 to port %d) instructed "
682 "Tor to take care of the DNS resolution itself if "
683 "necessary. This is good.", req->port);
684
685 end:
686 return res;
687}
688
689/**
690 * Handle (parse, validate, process, respond) a single SOCKS
691 * message in buffer <b>raw_data</b> of length <b>datalen</b>.
692 * Update relevant fields of <b>req</b>. If <b>log_sockstype</b>
693 * is true, log a warning about possible DNS leaks on local
694 * system. If <b>safe_socks</b> is true, disallow insecure
695 * usage of SOCKS protocol. Set <b>*drain_out</b> to number
696 * of bytes in <b>raw_data</b> that we processed so far and
697 * that can be safely drained from buffer.
698 *
699 * Return:
700 * - SOCKS_RESULT_DONE if succeeded and not expecting further
701 * messages from client.
702 * - SOCKS_RESULT_INVALID if any of the steps failed due to
703 * request being invalid or unexpected given current state.
704 * - SOCKS_RESULT_TRUNCATED if we do not found an expected
705 * SOCKS message in its entirety (more stuff has to arrive
706 * from client).
707 * - SOCKS_RESULT_MORE_EXPECTED if we handled current message
708 * successfully, but we expect more messages from the
709 * client.
710 */
711static socks_result_t
712handle_socks_message(const uint8_t *raw_data, size_t datalen,
713 socks_request_t *req, int log_sockstype,
714 int safe_socks, size_t *drain_out)
715{
716 socks_result_t res = SOCKS_RESULT_DONE;
717
718 uint8_t socks_version = raw_data[0];
719
720 if (socks_version == SOCKS_AUTH)
721 socks_version = SOCKS_VER_5; // SOCKS5 username/pass subnegotiation
722
723 if (socks_version == SOCKS_VER_4) {
724 if (datalen < SOCKS4_NETWORK_LEN) {
725 res = 0;
726 goto end;
727 }
728
729 int is_socks4a = 0;
730 res = parse_socks4_request((const uint8_t *)raw_data, req, datalen,
731 &is_socks4a, drain_out);
732
733 if (res != SOCKS_RESULT_DONE) {
734 goto end;
735 }
736
737 res = process_socks4_request(req, is_socks4a,log_sockstype,
738 safe_socks);
739
740 if (res != SOCKS_RESULT_DONE) {
741 goto end;
742 }
743
744 goto end;
745 } else if (socks_version == SOCKS_VER_5) {
746 if (datalen < 2) { /* version and another byte */
747 res = 0;
748 goto end;
749 }
750 /* RFC1929 SOCKS5 username/password subnegotiation. */
751 if (!req->got_auth && (raw_data[0] == 1 ||
752 req->auth_type == SOCKS_USER_PASS)) {
753 res = parse_socks5_userpass_auth(raw_data, req, datalen,
754 drain_out);
755
756 if (res != SOCKS_RESULT_DONE) {
757 goto end;
758 }
759
761 if (res != SOCKS_RESULT_DONE) {
762 goto end;
763 }
764
765 res = SOCKS_RESULT_MORE_EXPECTED;
766 goto end;
767 } else if (req->socks_version != SOCKS_VER_5) {
768 int have_user_pass=0, have_no_auth=0;
769 res = parse_socks5_methods_request(raw_data, req, datalen,
770 &have_user_pass,
771 &have_no_auth,
772 drain_out);
773
774 if (res != SOCKS_RESULT_DONE) {
775 goto end;
776 }
777
778 res = process_socks5_methods_request(req, have_user_pass,
779 have_no_auth);
780
781 if (res != SOCKS_RESULT_DONE) {
782 goto end;
783 }
784
785 res = SOCKS_RESULT_MORE_EXPECTED;
786 goto end;
787 } else {
788 res = parse_socks5_client_request(raw_data, req,
789 datalen, drain_out);
790 if (BUG(res == SOCKS_RESULT_INVALID && req->replylen == 0)) {
791 socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
792 }
793 if (res != SOCKS_RESULT_DONE) {
794 goto end;
795 }
796
797 res = process_socks5_client_request(req, log_sockstype,
798 safe_socks);
799
800 if (res != SOCKS_RESULT_DONE) {
801 goto end;
802 }
803 }
804 } else {
805 *drain_out = datalen;
806 res = SOCKS_RESULT_INVALID;
807 }
808
809 end:
810 return res;
811}
812
813/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
814 * of the forms
815 * - socks4: "socksheader username\\0"
816 * - socks4a: "socksheader username\\0 destaddr\\0"
817 * - socks5 phase one: "version #methods methods"
818 * - socks5 phase two: "version command 0 addresstype..."
819 * If it's a complete and valid handshake, and destaddr fits in
820 * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
821 * assign to <b>req</b>, and return 1.
822 *
823 * If it's invalid or too big, return -1.
824 *
825 * Else it's not all there yet, leave buf alone and return 0.
826 *
827 * If you want to specify the socks reply, write it into <b>req->reply</b>
828 * and set <b>req->replylen</b>, else leave <b>req->replylen</b> alone.
829 *
830 * If <b>log_sockstype</b> is non-zero, then do a notice-level log of whether
831 * the connection is possibly leaking DNS requests locally or not.
832 *
833 * If <b>safe_socks</b> is true, then reject unsafe socks protocols.
834 *
835 * If returning 0 or -1, <b>req->address</b> and <b>req->port</b> are
836 * undefined.
837 */
838int
840 int log_sockstype, int safe_socks)
841{
842 int res = 0;
843 size_t datalen = buf_datalen(buf);
844 size_t n_drain;
845 const char *head = NULL;
846 socks_result_t socks_res;
847 size_t n_pullup;
848
849 if (buf_datalen(buf) < 2) { /* version and another byte */
850 res = 0;
851 goto end;
852 }
853
854 do {
855 n_drain = 0;
856 n_pullup = MIN(MAX_SOCKS_MESSAGE_LEN, buf_datalen(buf));
857 buf_pullup(buf, n_pullup, &head, &datalen);
858 tor_assert(head && datalen >= 2);
859
860 socks_res = parse_socks(head, datalen, req, log_sockstype,
861 safe_socks, &n_drain);
862
863 if (socks_res == SOCKS_RESULT_INVALID)
864 buf_clear(buf);
865 else if (socks_res != SOCKS_RESULT_TRUNCATED && n_drain > 0)
866 buf_drain(buf, n_drain);
867
868 switch (socks_res) {
869 case SOCKS_RESULT_INVALID:
870 res = -1;
871 break;
872 case SOCKS_RESULT_DONE:
873 res = 1;
874 break;
875 case SOCKS_RESULT_TRUNCATED:
876 if (datalen == n_pullup)
877 return 0;
878 FALLTHROUGH;
879 case SOCKS_RESULT_MORE_EXPECTED:
880 res = 0;
881 break;
882 }
883 } while (res == 0 && head && buf_datalen(buf) >= 2);
884
885 end:
886 return res;
887}
888
889/** Create a SOCKS5 reply message with <b>reason</b> in its REP field and
890 * have Tor send it as error response to <b>req</b>.
891 */
892static void
895{
896 socks5_server_reply_t *trunnel_resp = socks5_server_reply_new();
897 tor_assert(trunnel_resp);
898
899 socks5_server_reply_set_version(trunnel_resp, SOCKS_VER_5);
900 socks5_server_reply_set_reply(trunnel_resp, reason);
901 socks5_server_reply_set_atype(trunnel_resp, 0x01);
902
903 const char *errmsg = socks5_server_reply_check(trunnel_resp);
904 if (errmsg) {
905 log_warn(LD_APP, "socks5: reply validation failed: %s",
906 errmsg);
907 goto end;
908 }
909
910 ssize_t encoded = socks5_server_reply_encode(req->reply,
911 sizeof(req->reply),
912 trunnel_resp);
913 if (encoded < 0) {
914 log_warn(LD_APP, "socks5: reply encoding failed: %d",
915 (int)encoded);
916 } else {
917 req->replylen = (size_t)encoded;
918 }
919
920 end:
921 socks5_server_reply_free(trunnel_resp);
922}
923
924static const char SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG[] =
925 "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
926 "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
927 "<html>\n"
928 "<head>\n"
929 "<title>This is a SOCKS Proxy, Not An HTTP Proxy</title>\n"
930 "</head>\n"
931 "<body>\n"
932 "<h1>This is a SOCKS proxy, not an HTTP proxy.</h1>\n"
933 "<p>\n"
934 "It appears you have configured your web browser to use this Tor port as\n"
935 "an HTTP proxy.\n"
936 "</p>\n"
937 "<p>\n"
938 "This is not correct: This port is configured as a SOCKS proxy, not\n"
939 "an HTTP proxy. If you need an HTTP proxy tunnel, use the HTTPTunnelPort\n"
940 "configuration option in place of, or in addition to, SOCKSPort.\n"
941 "Please configure your client accordingly.\n"
942 "</p>\n"
943 "<p>\n"
944 "See <a href=\"https://www.torproject.org/documentation.html\">"
945 "https://www.torproject.org/documentation.html</a> for more "
946 "information.\n"
947 "</p>\n"
948 "</body>\n"
949 "</html>\n";
950
951/** Implementation helper to implement fetch_from_*_socks. Instead of looking
952 * at a buffer's contents, we look at the <b>datalen</b> bytes of data in
953 * <b>data</b>. Instead of removing data from the buffer, we set
954 * <b>drain_out</b> to the amount of data that should be removed (or -1 if the
955 * buffer should be cleared). Instead of pulling more data into the first
956 * chunk of the buffer, we set *<b>want_length_out</b> to the number of bytes
957 * we'd like to see in the input buffer, if they're available. */
958static socks_result_t
959parse_socks(const char *data, size_t datalen, socks_request_t *req,
960 int log_sockstype, int safe_socks, size_t *drain_out)
961{
962 uint8_t first_octet;
963
964 if (datalen < 2) {
965 /* We always need at least 2 bytes. */
966 return SOCKS_RESULT_TRUNCATED;
967 }
968
969 first_octet = get_uint8(data);
970
971 if (first_octet == SOCKS_VER_5 || first_octet == SOCKS_VER_4 ||
972 first_octet == SOCKS_AUTH) { // XXX: RFC 1929
973 return handle_socks_message((const uint8_t *)data, datalen, req,
974 log_sockstype, safe_socks, drain_out);
975 }
976
977 switch (first_octet) { /* which version of socks? */
978 case 'G': /* get */
979 case 'H': /* head */
980 case 'P': /* put/post */
981 case 'C': /* connect */
982 strlcpy((char*)req->reply, SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG,
983 MAX_SOCKS_REPLY_LEN);
984 req->replylen = strlen((char*)req->reply)+1;
985 FALLTHROUGH;
986 default: /* version is not socks4 or socks5 */
987 log_warn(LD_APP,
988 "Socks version %d not recognized. (This port is not an "
989 "HTTP proxy; did you want to use HTTPTunnelPort?)",
990 *(data));
991 {
992 /* Tell the controller the first 8 bytes. */
993 char *tmp = tor_strndup(data, datalen < 8 ? datalen : 8);
995 "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
996 escaped(tmp));
997 tor_free(tmp);
998 }
999 return SOCKS_RESULT_INVALID;
1000 }
1001
1002 tor_assert_unreached();
1003 return SOCKS_RESULT_INVALID;
1004}
1005
1006/** Inspect a reply from SOCKS server stored in <b>buf</b> according
1007 * to <b>state</b>, removing the protocol data upon success. Return 0 on
1008 * incomplete response, 1 on success and -1 on error, in which case
1009 * <b>reason</b> is set to a descriptive message (free() when finished
1010 * with it).
1011 *
1012 * As a special case, 2 is returned when user/pass is required
1013 * during SOCKS5 handshake and user/pass is configured.
1014 */
1015int
1016fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
1017{
1018 ssize_t drain = 0;
1019 int r;
1020 const char *head = NULL;
1021 size_t datalen = 0;
1022
1023 if (buf_datalen(buf) < 2)
1024 return 0;
1025
1026 buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, &head, &datalen);
1027 tor_assert(head && datalen >= 2);
1028
1029 r = parse_socks_client((uint8_t*)head, datalen,
1030 state, reason, &drain);
1031 if (drain > 0)
1032 buf_drain(buf, drain);
1033 else if (drain < 0)
1034 buf_clear(buf);
1035
1036 return r;
1037}
1038
1039/** Implementation logic for fetch_from_*_socks_client. */
1040static int
1041parse_socks_client(const uint8_t *data, size_t datalen,
1042 int state, char **reason,
1043 ssize_t *drain_out)
1044{
1045 unsigned int addrlen;
1046 *drain_out = 0;
1047 if (datalen < 2)
1048 return 0;
1049
1050 switch (state) {
1051 case PROXY_SOCKS4_WANT_CONNECT_OK:
1052 /* Wait for the complete response */
1053 if (datalen < 8)
1054 return 0;
1055
1056 if (data[1] != 0x5a) {
1057 *reason = tor_strdup(socks4_response_code_to_string(data[1]));
1058 return -1;
1059 }
1060
1061 /* Success */
1062 *drain_out = 8;
1063 return 1;
1064
1065 case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
1066 /* we don't have any credentials */
1067 if (data[1] != 0x00) {
1068 *reason = tor_strdup("server doesn't support any of our "
1069 "available authentication methods");
1070 return -1;
1071 }
1072
1073 log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
1074 *drain_out = -1;
1075 return 1;
1076
1077 case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
1078 /* we have a username and password. return 1 if we can proceed without
1079 * providing authentication, or 2 otherwise. */
1080 switch (data[1]) {
1081 case 0x00:
1082 log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
1083 "doesn't require authentication.");
1084 *drain_out = -1;
1085 return 1;
1086 case 0x02:
1087 log_info(LD_NET, "SOCKS 5 client: need authentication.");
1088 *drain_out = -1;
1089 return 2;
1090 default:
1091 /* This wasn't supposed to be exhaustive; there are other
1092 * authentication methods too. */
1093 ;
1094 }
1095
1096 *reason = tor_strdup("server doesn't support any of our available "
1097 "authentication methods");
1098 return -1;
1099
1100 case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
1101 /* handle server reply to rfc1929 authentication */
1102 if (data[1] != 0x00) {
1103 *reason = tor_strdup("authentication failed");
1104 return -1;
1105 }
1106
1107 log_info(LD_NET, "SOCKS 5 client: authentication successful.");
1108 *drain_out = -1;
1109 return 1;
1110
1111 case PROXY_SOCKS5_WANT_CONNECT_OK:
1112 /* response is variable length. BND.ADDR, etc, isn't needed
1113 * (don't bother with buf_pullup()), but make sure to eat all
1114 * the data used */
1115
1116 /* wait for address type field to arrive */
1117 if (datalen < 4)
1118 return 0;
1119
1120 switch (data[3]) {
1121 case 0x01: /* ip4 */
1122 addrlen = 4;
1123 break;
1124 case 0x04: /* ip6 */
1125 addrlen = 16;
1126 break;
1127 case 0x03: /* fqdn (can this happen here?) */
1128 if (datalen < 5)
1129 return 0;
1130 addrlen = 1 + data[4];
1131 break;
1132 default:
1133 *reason = tor_strdup("invalid response to connect request");
1134 return -1;
1135 }
1136
1137 /* wait for address and port */
1138 if (datalen < 6 + addrlen)
1139 return 0;
1140
1141 if (data[1] != 0x00) {
1142 *reason = tor_strdup(socks5_response_code_to_string(data[1]));
1143 return -1;
1144 }
1145
1146 *drain_out = 6 + addrlen;
1147 return 1;
1148 }
1149
1150 /* LCOV_EXCL_START */
1151 /* shouldn't get here if the input state is one we know about... */
1152 tor_assert(0);
1153
1154 return -1;
1155 /* LCOV_EXCL_STOP */
1156}
int tor_addr_parse(tor_addr_t *addr, const char *src)
Definition address.c:1349
int string_is_valid_dest(const char *string)
Definition address.c:2155
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
Definition address.c:328
void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes)
Definition address.c:900
#define tor_addr_from_ipv4h(dest, v4addr)
Definition address.h:327
int addressmap_have_mapping(const char *address, int update_expiry)
Definition addressmap.c:544
Header for addressmap.c.
void buf_clear(buf_t *buf)
Definition buffers.c:381
void buf_drain(buf_t *buf, size_t n)
Definition buffers.c:330
size_t buf_datalen(const buf_t *buf)
Definition buffers.c:394
void buf_pullup(buf_t *buf, size_t bytes, const char **head_out, size_t *len_out)
Definition buffers.c:211
Header file for buffers.c.
static uint8_t get_uint8(const void *cp)
Definition bytes.h:23
const char * escaped_safe_str_client(const char *address)
Definition config.c:1146
tor_cmdline_mode_t command
Definition config.c:2478
Header file for config.c.
Header file for connection.c.
int control_event_client_status(int severity, const char *format,...)
Header file for control_events.c.
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition crypto_util.c:55
Common functions for cryptographic routines.
int tor_memeq(const void *a, const void *b, size_t sz)
Definition di_ops.c:107
#define tor_memneq(a, b, sz)
Definition di_ops.h:21
const char * escaped(const char *s)
Definition escape.c:126
Header for ext_orport.c.
#define log_fn_ratelim(ratelim, severity, domain, args,...)
Definition log.h:288
#define LD_APP
Definition log.h:78
#define LD_PROTOCOL
Definition log.h:72
#define LD_NET
Definition log.h:66
#define LOG_WARN
Definition log.h:53
#define tor_free(p)
Definition malloc.h:56
Master header file for Tor-specific functionality.
#define SOCKS4_NETWORK_LEN
Definition or.h:509
static socks_result_t process_socks5_methods_request(socks_request_t *req, int have_user_pass, int have_no_auth)
static socks_result_t parse_socks5_methods_request(const uint8_t *raw_data, socks_request_t *req, size_t datalen, int *have_user_pass, int *have_no_auth, size_t *drain_out)
static socks_result_t process_socks5_client_request(socks_request_t *req, int log_sockstype, int safe_socks)
static socks_result_t parse_socks5_userpass_auth(const uint8_t *raw_data, socks_request_t *req, size_t datalen, size_t *drain_out)
#define MAX_SOCKS_MESSAGE_LEN
Definition proto_socks.c:83
static socks_result_t process_socks5_userpass_auth(socks_request_t *req)
static socks_result_t process_socks4_request(const socks_request_t *req, int is_socks4a, int log_sockstype, int safe_socks)
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype, int safe_socks)
void socks_request_free_(socks_request_t *req)
Definition proto_socks.c:94
socks_request_t * socks_request_new(void)
Definition proto_socks.c:87
static socks_result_t parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req, size_t datalen, size_t *drain_out)
static socks_result_t handle_socks_message(const uint8_t *raw_data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, size_t *drain_out)
static socks_result_t parse_socks4_request(const uint8_t *raw_data, socks_request_t *req, size_t datalen, int *is_socks4a, size_t *drain_out)
int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
#define SOCKS_WARN_INTERVAL
Definition proto_socks.c:53
static socks_result_t parse_socks(const char *data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, size_t *drain_out)
static void socks_request_set_socks5_error(socks_request_t *req, socks5_reply_status_t reason)
static void log_unsafe_socks_warning(int socks_protocol, const char *address, uint16_t port, int safe_socks)
Definition proto_socks.c:59
static int parse_socks_client(const uint8_t *data, size_t datalen, int state, char **reason, ssize_t *drain_out)
Header for proto_socks.c.
const char * socks5_response_code_to_string(uint8_t code)
Definition reasons.c:415
const char * socks4_response_code_to_string(uint8_t code)
Definition reasons.c:397
Header file for reasons.c.
socks5_reply_status_t
Client request structure.
#define SOCKS_COMMAND_RESOLVE_PTR
#define SOCKS_COMMAND_CONNECT
#define SOCKS_COMMAND_RESOLVE
unsigned int socks_prefer_no_auth
unsigned int got_auth
uint8_t reply[MAX_SOCKS_REPLY_LEN]
char address[MAX_SOCKS_ADDR_LEN]
#define tor_assert(expr)
Definition util_bug.h:103