Tor  0.4.7.0-alpha-dev
Macros | Enumerations | Functions | Variables
proto_socks.c File Reference

Implementations for SOCKS4 and SOCKS5 protocols. More...

#include "core/or/or.h"
#include "feature/client/addressmap.h"
#include "lib/buf/buffers.h"
#include "core/mainloop/connection.h"
#include "feature/control/control_events.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/relay/ext_orport.h"
#include "core/proto/proto_socks.h"
#include "core/or/reasons.h"
#include "core/or/socks_request_st.h"
#include "trunnel/socks5.h"

Go to the source code of this file.

Macros

#define SOCKS_VER_5   0x05 /* First octet of non-auth SOCKS5 messages */
 
#define SOCKS_VER_4   0x04 /* SOCKS4 messages */
 
#define SOCKS_AUTH   0x01 /* SOCKS5 auth messages */
 
#define SOCKS_WARN_INTERVAL   5
 
#define MAX_SOCKS_MESSAGE_LEN   512
 

Enumerations

enum  socks_result_t { SOCKS_RESULT_INVALID = -1 , SOCKS_RESULT_TRUNCATED = 0 , SOCKS_RESULT_DONE = 1 , SOCKS_RESULT_MORE_EXPECTED = 2 }
 

Functions

static void socks_request_set_socks5_error (socks_request_t *req, socks5_reply_status_t reason)
 
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 int parse_socks_client (const uint8_t *data, size_t datalen, int state, char **reason, ssize_t *drain_out)
 
static void log_unsafe_socks_warning (int socks_protocol, const char *address, uint16_t port, int safe_socks)
 
socks_request_tsocks_request_new (void)
 
void socks_request_free_ (socks_request_t *req)
 
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)
 
static socks_result_t process_socks4_request (const socks_request_t *req, int is_socks4a, int log_sockstype, int safe_socks)
 
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_methods_request (socks_request_t *req, int have_user_pass, int have_no_auth)
 
static socks_result_t parse_socks5_userpass_auth (const uint8_t *raw_data, socks_request_t *req, size_t datalen, size_t *drain_out)
 
static socks_result_t process_socks5_userpass_auth (socks_request_t *req)
 
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 process_socks5_client_request (socks_request_t *req, int log_sockstype, int safe_socks)
 
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)
 
int fetch_from_buf_socks (buf_t *buf, socks_request_t *req, int log_sockstype, int safe_socks)
 
int fetch_from_buf_socks_client (buf_t *buf, int state, char **reason)
 

Variables

static const char SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG []
 

Detailed Description

Implementations for SOCKS4 and SOCKS5 protocols.

Definition in file proto_socks.c.

Macro Definition Documentation

◆ MAX_SOCKS_MESSAGE_LEN

#define MAX_SOCKS_MESSAGE_LEN   512

Do not attempt to parse socks messages longer than this. This value is actually significantly higher than the longest possible socks message.

Definition at line 83 of file proto_socks.c.

◆ SOCKS_WARN_INTERVAL

#define SOCKS_WARN_INTERVAL   5

Wait this many seconds before warning the user about using SOCKS unsafely again.

Definition at line 53 of file proto_socks.c.

Function Documentation

◆ fetch_from_buf_socks()

int fetch_from_buf_socks ( buf_t *  buf,
socks_request_t req,
int  log_sockstype,
int  safe_socks 
)

There is a (possibly incomplete) socks handshake on buf, of one of the forms

  • socks4: "socksheader username\\0"
  • socks4a: "socksheader username\\0 destaddr\\0"
  • socks5 phase one: "version #methods methods"
  • socks5 phase two: "version command 0 addresstype..." If it's a complete and valid handshake, and destaddr fits in MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf, assign to req, and return 1.

If it's invalid or too big, return -1.

Else it's not all there yet, leave buf alone and return 0.

If you want to specify the socks reply, write it into req->reply and set req->replylen, else leave req->replylen alone.

If log_sockstype is non-zero, then do a notice-level log of whether the connection is possibly leaking DNS requests locally or not.

If safe_socks is true, then reject unsafe socks protocols.

If returning 0 or -1, req->address and req->port are undefined.

Definition at line 829 of file proto_socks.c.

◆ fetch_from_buf_socks_client()

int fetch_from_buf_socks_client ( buf_t *  buf,
int  state,
char **  reason 
)

Inspect a reply from SOCKS server stored in buf according to state, removing the protocol data upon success. Return 0 on incomplete response, 1 on success and -1 on error, in which case reason is set to a descriptive message (free() when finished with it).

As a special case, 2 is returned when user/pass is required during SOCKS5 handshake and user/pass is configured.

Definition at line 1005 of file proto_socks.c.

Referenced by connection_fetch_from_buf_socks_client().

◆ handle_socks_message()

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

Handle (parse, validate, process, respond) a single SOCKS message in buffer raw_data of length datalen. Update relevant fields of req. If log_sockstype is true, log a warning about possible DNS leaks on local system. If safe_socks is true, disallow insecure usage of SOCKS protocol. Set *drain_out to number of bytes in raw_data that we processed so far and that can be safely drained from buffer.

Return:

  • SOCKS_RESULT_DONE if succeeded and not expecting further messages from client.
  • SOCKS_RESULT_INVALID if any of the steps failed due to request being invalid or unexpected given current state.
  • SOCKS_RESULT_TRUNCATED if we do not found an expected SOCKS message in its entirety (more stuff has to arrive from client).
  • SOCKS_RESULT_MORE_EXPECTED if we handled current message successfully, but we expect more messages from the client.

Definition at line 702 of file proto_socks.c.

◆ log_unsafe_socks_warning()

static void log_unsafe_socks_warning ( int  socks_protocol,
const char *  address,
uint16_t  port,
int  safe_socks 
)
static

Warn that the user application has made an unsafe socks request using protocol socks_protocol on port port. Don't warn more than once per SOCKS_WARN_INTERVAL, unless safe_socks is set.

Definition at line 59 of file proto_socks.c.

Referenced by process_socks4_request().

◆ parse_socks()

static int parse_socks ( const char *  data,
size_t  datalen,
socks_request_t req,
int  log_sockstype,
int  safe_socks,
size_t *  drain_out 
)
static

Implementation helper to implement fetch_from_*_socks. Instead of looking at a buffer's contents, we look at the datalen bytes of data in data. Instead of removing data from the buffer, we set drain_out to the amount of data that should be removed (or -1 if the buffer should be cleared). Instead of pulling more data into the first chunk of the buffer, we set *want_length_out to the number of bytes we'd like to see in the input buffer, if they're available.

Definition at line 948 of file proto_socks.c.

◆ parse_socks4_request()

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 
)
static

Parse a single SOCKS4 request from buffer raw_data of length datalen and update relevant fields of req. If SOCKS4a request is detected, set *is_socks4a to true. Set *drain_out to number of bytes we parsed so far.

Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it failed due to incomplete (truncated) input.

Definition at line 121 of file proto_socks.c.

◆ parse_socks5_client_request()

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

Parse a single SOCKS5 client request (RFC 1928 section 4) from buffer raw_data of length datalen and update relevant field of req. Set *drain_out to number of bytes we parsed so far.

Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it failed due to incomplete (truncated) input.

Definition at line 542 of file proto_socks.c.

◆ parse_socks5_methods_request()

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

Parse a single SOCKS5 version identifier/method selection message from buffer raw_data (of length datalen). Update relevant fields of req (if any). Set *have_user_pass to true if username/password method is found. Set *have_no_auth if no-auth method is found. Set *drain_out to number of bytes we parsed so far.

Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it failed due to incomplete (truncated) input.

Definition at line 283 of file proto_socks.c.

◆ parse_socks5_userpass_auth()

static socks_result_t parse_socks5_userpass_auth ( const uint8_t *  raw_data,
socks_request_t req,
size_t  datalen,
size_t *  drain_out 
)
static

Parse SOCKS5/RFC1929 username/password request from buffer raw_data of length datalen and update relevant fields of req. Set *drain_out to number of bytes we parsed so far.

Return SOCKS_RESULT_DONE if parsing succeeded, SOCKS_RESULT_INVALID if parsing failed because of invalid input or SOCKS_RESULT_TRUNCATED if it failed due to incomplete (truncated) input.

Yes, we allow username and/or password to be empty. Yes, that does violate RFC 1929. However, some client software can send a username/ password message with these fields being empty and we want to allow them to be used with Tor.

Definition at line 422 of file proto_socks.c.

◆ parse_socks_client()

static int parse_socks_client ( const uint8_t *  data,
size_t  datalen,
int  state,
char **  reason,
ssize_t *  drain_out 
)
static

Implementation logic for fetch_from_*_socks_client.

Definition at line 1030 of file proto_socks.c.

Referenced by fetch_from_buf_socks_client().

◆ process_socks4_request()

static socks_result_t process_socks4_request ( const socks_request_t req,
int  is_socks4a,
int  log_sockstype,
int  safe_socks 
)
static

Validate SOCKS4/4a related fields in req. Expect SOCKS4a if is_socks4a is true. If log_sockstype is true, log a notice about possible DNS leaks on local system. If safe_socks is true, reject insecure usage of SOCKS protocol.

Return SOCKS_RESULT_DONE if validation passed or SOCKS_RESULT_INVALID if it failed.

Definition at line 233 of file proto_socks.c.

◆ process_socks5_client_request()

static socks_result_t process_socks5_client_request ( socks_request_t req,
int  log_sockstype,
int  safe_socks 
)
static

Validate and respond to SOCKS5 request we parsed in parse_socks5_client_request (corresponding to req. Write appropriate response to req->reply (in SOCKS5 wire format). If log_sockstype is true, log a notice about possible DNS leaks on local system. If safe_socks is true, disallow insecure usage of SOCKS protocol. Return SOCKS_RESULT_DONE on success or SOCKS_RESULT_INVALID on failure.

Definition at line 620 of file proto_socks.c.

◆ process_socks5_methods_request()

static socks_result_t process_socks5_methods_request ( socks_request_t req,
int  have_user_pass,
int  have_no_auth 
)
static

Validate and respond to version identifier/method selection message we parsed in parse_socks5_methods_request (corresponding to req and having user/pass method if have_user_pass is true, no-auth method if have_no_auth is true). Set req->reply to an appropriate response (in SOCKS5 wire format).

On success, return SOCKS_RESULT_DONE. On failure, return SOCKS_RESULT_INVALID.

Definition at line 356 of file proto_socks.c.

◆ process_socks5_userpass_auth()

static socks_result_t process_socks5_userpass_auth ( socks_request_t req)
static

Validate and respond to SOCKS5 username/password request we parsed in parse_socks5_userpass_auth (corresponding to req. Set req->reply to appropriate response. Return SOCKS_RESULT_DONE on success or SOCKS_RESULT_INVALID on failure.

Definition at line 486 of file proto_socks.c.

◆ socks_request_free_()

void socks_request_free_ ( socks_request_t req)

Free all storage held in the socks_request_t req.

Definition at line 94 of file proto_socks.c.

◆ socks_request_new()

socks_request_t* socks_request_new ( void  )

Return a new socks_request_t.

Definition at line 87 of file proto_socks.c.

◆ socks_request_set_socks5_error()

static void socks_request_set_socks5_error ( socks_request_t req,
socks5_reply_status_t  reason 
)
static

Create a SOCKS5 reply message with reason in its REP field and have Tor send it as error response to req.

Definition at line 883 of file proto_socks.c.

Variable Documentation

◆ SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG

const char SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG[]
static
Initial value:
=
"HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
"<html>\n"
"<head>\n"
"<title>This is a SOCKS Proxy, Not An HTTP Proxy</title>\n"
"</head>\n"
"<body>\n"
"<h1>This is a SOCKs proxy, not an HTTP proxy.</h1>\n"
"<p>\n"
"It appears you have configured your web browser to use this Tor port as\n"
"an HTTP proxy.\n"
"</p><p>\n"
"This is not correct: This port is configured as a SOCKS proxy, not\n"
"an HTTP proxy. If you need an HTTP proxy tunnel, use the HTTPTunnelPort\n"
"configuration option in place of, or in addition to, SOCKSPort.\n"
"Please configure your client accordingly.\n"
"</p>\n"
"<p>\n"
"See <a href=\"https://www.torproject.org/documentation.html\">"
"https://www.torproject.org/documentation.html</a> for more "
"information.\n"
"</p>\n"
"</body>\n"
"</html>\n"

Definition at line 914 of file proto_socks.c.