Skip to content

Commit

Permalink
Add username/password SOCKS5 auth
Browse files Browse the repository at this point in the history
  • Loading branch information
nurupo committed Sep 20, 2021
1 parent a71ddc7 commit abbf3db
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 4 deletions.
81 changes: 77 additions & 4 deletions toxcore/TCP_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,69 @@ static void proxy_socks5_generate_handshake(TCP_Client_Connection *tcp_conn)
{
tcp_conn->last_packet[0] = 5; /* SOCKSv5 */
tcp_conn->last_packet[1] = 1; /* number of authentication methods supported */
tcp_conn->last_packet[2] = 0; /* No authentication */

if (tcp_conn->proxy_info.socks5_username == nullptr || tcp_conn->proxy_info.socks5_password == nullptr) {
tcp_conn->last_packet[2] = 0; /* No authentication */
} else {
tcp_conn->last_packet[2] = 2; /* Username/password */
}

tcp_conn->last_packet_length = 3;
tcp_conn->last_packet_sent = 0;
}

/* return 2 on success, username/password auth.
* return 1 on success, no auth.
* return 0 if no data received.
* return -1 on failure (connection refused).
*/
static int proxy_socks5_read_handshake_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
{
uint8_t data[2];
int ret = read_TCP_packet(logger, tcp_conn->sock, data, sizeof(data));

if (ret == -1) {
return 0;
}

if (data[0] == 5) { /* must be SOCKSv5 */
if (tcp_conn->proxy_info.socks5_username == nullptr || tcp_conn->proxy_info.socks5_password == nullptr) {
if (data[1] == 0) { /* No authentication */
return 1;
}
} else {
if (data[1] == 2) { /* Username/password */
return 2;
}
}
}

return -1;
}

static void proxy_socks5_generate_authentication_request(TCP_Client_Connection *tcp_conn)
{
tcp_conn->last_packet[0] = 1; /* rfc1929 auth version */
tcp_conn->last_packet[1] = tcp_conn->proxy_info.socks5_username_length;
uint16_t length = 2;
memcpy(tcp_conn->last_packet + length, tcp_conn->proxy_info.socks5_username,
tcp_conn->proxy_info.socks5_username_length);
length += tcp_conn->proxy_info.socks5_username_length;
tcp_conn->last_packet[length] = tcp_conn->proxy_info.socks5_password_length;
++length;
memcpy(tcp_conn->last_packet + length, tcp_conn->proxy_info.socks5_password,
tcp_conn->proxy_info.socks5_password_length);
length += tcp_conn->proxy_info.socks5_password_length;

tcp_conn->last_packet_length = length;
tcp_conn->last_packet_sent = 0;
}

/* return 1 on success.
* return 0 if no data received.
* return -1 on failure (connection refused).
*/
static int socks5_read_handshake_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
static int proxy_socks5_read_authentication_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
{
uint8_t data[2];
int ret = read_TCP_packet(logger, tcp_conn->sock, data, sizeof(data));
Expand All @@ -202,7 +254,7 @@ static int socks5_read_handshake_response(const Logger *logger, TCP_Client_Conne
return 0;
}

if (data[0] == 5 && data[1] == 0) { // TODO(irungentoo): magic numbers
if (data[0] == 1 && data[1] == 0) {
return 1;
}

Expand Down Expand Up @@ -983,7 +1035,28 @@ void do_TCP_connection(const Logger *logger, Mono_Time *mono_time, TCP_Client_Co

if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) {
if (client_send_pending_data(tcp_connection) == 0) {
int ret = socks5_read_handshake_response(logger, tcp_connection);
int ret = proxy_socks5_read_handshake_response(logger, tcp_connection);

if (ret == -1) {
tcp_connection->kill_at = 0;
tcp_connection->status = TCP_CLIENT_DISCONNECTED;
}

if (ret == 1) { /* no auth */
proxy_socks5_generate_connection_request(tcp_connection);
tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
}

if (ret == 2) { /* username/password */
proxy_socks5_generate_authentication_request(tcp_connection);
tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING;
}
}
}

if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING) {
if (client_send_pending_data(tcp_connection) == 0) {
int ret = proxy_socks5_read_authentication_response(logger, tcp_connection);

if (ret == -1) {
tcp_connection->kill_at = 0;
Expand Down
5 changes: 5 additions & 0 deletions toxcore/TCP_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ typedef enum TCP_Proxy_Type {
typedef struct TCP_Proxy_Info {
IP_Port ip_port;
uint8_t proxy_type; // a value from TCP_PROXY_TYPE
const uint8_t *socks5_username;
size_t socks5_username_length;
const uint8_t *socks5_password;
size_t socks5_password_length;
} TCP_Proxy_Info;

typedef enum TCP_Client_Status {
TCP_CLIENT_NO_STATUS,
TCP_CLIENT_PROXY_HTTP_CONNECTING,
TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING,
TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
TCP_CLIENT_CONNECTING,
TCP_CLIENT_UNCONFIRMED,
Expand Down
75 changes: 75 additions & 0 deletions toxcore/tox.api.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,20 @@ const MAX_FILENAME_LENGTH = 255;
*/
const MAX_HOSTNAME_LENGTH = 255;

/**
* Maximum length of a SOCKS5 proxy username in bytes.
*
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
*/
const MAX_PROXY_SOCKS5_USERNAME_LENGTH = 255;

/**
* Maximum length of a SOCKS5 proxy password in bytes.
*
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
*/
const MAX_PROXY_SOCKS5_PASSWORD_LENGTH = 255;


/*******************************************************************************
*
Expand Down Expand Up @@ -540,6 +554,52 @@ static class options {
* proxy_type is ${PROXY_TYPE.NONE}.
*/
uint16_t port;

namespace socks5 {
/**
* The username to use to connect to a SOCKS5 proxy.
*
* If set to NULL, the username/password authentication is disabled.
*
* This member is ignored (it can be NULL) if proxy_type is not
* ${PROXY_TYPE.SOCKS5}.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object.
*/
const uint8_t[length] username;

/**
* The length of the username.
*
* Must be at most $MAX_PROXY_SOCKS5_USERNAME_LENGTH.
*
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_username_length() function.
*/
size_t username_length;

/**
* The password to use to connect to a Socks proxy.
*
* If set to NULL, the username/password authentication is disabled.
*
* This member is ignored (it can be NULL) if proxy_type is not
* ${PROXY_TYPE.SOCKS5}.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object.
*/
const uint8_t[length] password;

/**
* The length of the password.
*
* Must be at most $MAX_PROXY_SOCKS5_PASSWORD_LENGTH.
*
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_password_length() function.
*/
size_t password_length;
}
}

/**
Expand Down Expand Up @@ -595,6 +655,7 @@ static class options {

/**
* The length of the savedata.
* TODO(iphydf): this creates a pointless tox_options_set_savedata_length() function.
*/
size_t length;
}
Expand Down Expand Up @@ -741,6 +802,20 @@ static this new(const options_t *options) {
*/
BAD_FORMAT,
}

/**
* The proxy_socks5_username_length is zero or too long.
*
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
*/
PROXY_SOCKS5_BAD_USERNAME_LENGTH,

/**
* The proxy_socks5_password_length is zero or too long.
*
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
*/
PROXY_SOCKS5_BAD_PASSWORD_LENGTH,
}


Expand Down
26 changes: 26 additions & 0 deletions toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,32 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
}

m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts));

if (m_options.proxy_info.proxy_type == TCP_PROXY_SOCKS5) {
if (tox_options_get_proxy_socks5_username(opts) != nullptr &&
(tox_options_get_proxy_socks5_username_length(opts) < 1 ||
tox_options_get_proxy_socks5_username_length(opts) > TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH)) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_SOCKS5_BAD_USERNAME_LENGTH);
tox_options_free(default_options);
free(tox);
return nullptr;
}

m_options.proxy_info.socks5_username = tox_options_get_proxy_socks5_username(opts);
m_options.proxy_info.socks5_username_length = tox_options_get_proxy_socks5_username_length(opts);

if (tox_options_get_proxy_socks5_password(opts) != nullptr &&
(tox_options_get_proxy_socks5_password_length(opts) < 1 ||
tox_options_get_proxy_socks5_password_length(opts) > TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH)) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_SOCKS5_BAD_PASSWORD_LENGTH);
tox_options_free(default_options);
free(tox);
return nullptr;
}

m_options.proxy_info.socks5_password = tox_options_get_proxy_socks5_password(opts);
m_options.proxy_info.socks5_password_length = tox_options_get_proxy_socks5_password_length(opts);
}
}

tox->mono_time = mono_time_new();
Expand Down
97 changes: 97 additions & 0 deletions toxcore/tox.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,24 @@ uint32_t tox_max_filename_length(void);

uint32_t tox_max_hostname_length(void);

/**
* Maximum length of a SOCKS5 proxy username in bytes.
*
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
*/
#define TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH 255

uint32_t tox_max_proxy_socks5_username_length(void);

/**
* Maximum length of a SOCKS5 proxy password in bytes.
*
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
*/
#define TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH 255

uint32_t tox_max_proxy_socks5_password_length(void);


/*******************************************************************************
*
Expand Down Expand Up @@ -604,6 +622,54 @@ struct Tox_Options {
uint16_t proxy_port;


/**
* The username to use to connect to a SOCKS5 proxy.
*
* If set to NULL, the username/password authentication is disabled.
*
* This member is ignored (it can be NULL) if proxy_type is not
* TOX_PROXY_TYPE_SOCKS5.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object.
*/
const uint8_t *proxy_socks5_username;


/**
* The length of the username.
*
* Must be at most TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH.
*
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_username_length() function.
*/
size_t proxy_socks5_username_length;


/**
* The password to use to connect to a Socks proxy.
*
* If set to NULL, the username/password authentication is disabled.
*
* This member is ignored (it can be NULL) if proxy_type is not
* TOX_PROXY_TYPE_SOCKS5.
*
* The data pointed at by this member is owned by the user, so must
* outlive the options object.
*/
const uint8_t *proxy_socks5_password;


/**
* The length of the password.
*
* Must be at most TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH.
*
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_password_length() function.
*/
size_t proxy_socks5_password_length;


/**
* The start port of the inclusive port range to attempt to use.
*
Expand Down Expand Up @@ -662,6 +728,7 @@ struct Tox_Options {

/**
* The length of the savedata.
* TODO(iphydf): this creates a pointless tox_options_set_savedata_length() function.
*/
size_t savedata_length;

Expand Down Expand Up @@ -718,6 +785,22 @@ uint16_t tox_options_get_proxy_port(const struct Tox_Options *options);

void tox_options_set_proxy_port(struct Tox_Options *options, uint16_t port);

const uint8_t *tox_options_get_proxy_socks5_username(const struct Tox_Options *options);

void tox_options_set_proxy_socks5_username(struct Tox_Options *options, const uint8_t *username, size_t length);

size_t tox_options_get_proxy_socks5_username_length(const struct Tox_Options *options);

void tox_options_set_proxy_socks5_username_length(struct Tox_Options *options, size_t username_length);

const uint8_t *tox_options_get_proxy_socks5_password(const struct Tox_Options *options);

void tox_options_set_proxy_socks5_password(struct Tox_Options *options, const uint8_t *password, size_t length);

size_t tox_options_get_proxy_socks5_password_length(const struct Tox_Options *options);

void tox_options_set_proxy_socks5_password_length(struct Tox_Options *options, size_t password_length);

uint16_t tox_options_get_start_port(const struct Tox_Options *options);

void tox_options_set_start_port(struct Tox_Options *options, uint16_t start_port);
Expand Down Expand Up @@ -875,6 +958,20 @@ typedef enum TOX_ERR_NEW {
*/
TOX_ERR_NEW_LOAD_BAD_FORMAT,

/**
* The proxy_socks5_username_length is zero or too long.
*
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
*/
TOX_ERR_NEW_PROXY_SOCKS5_BAD_USERNAME_LENGTH,

/**
* The proxy_socks5_password_length is zero or too long.
*
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
*/
TOX_ERR_NEW_PROXY_SOCKS5_BAD_PASSWORD_LENGTH,

} TOX_ERR_NEW;


Expand Down
Loading

0 comments on commit abbf3db

Please sign in to comment.