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