Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions other/apidsl/tox.in.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ const FILE_ID_LENGTH = 32;
*/
const MAX_FILENAME_LENGTH = 255;

/**
* Maximum username/password length for proxy authentication.
*/
const MAX_PROXY_USER_PASS_LENGTH = 255;

/**
* Minimum username/password length for proxy authentication.
*/
const MIN_PROXY_USER_PASS_LENGTH = 1;

/*******************************************************************************
*
Expand Down Expand Up @@ -417,6 +426,30 @@ static class options {
* proxy_type is TOX_PROXY_TYPE_NONE.
*/
uint16_t port;

/**
* The username to be used to authenticate.
*
* If used, this must be non-NULL. The username must be at least MIN_PROXY_USER_PASS_LENGTH characters
* long but it must not exceed MAX_PROXY_USER_PASS_LENGTH characters. It must also be in
* a NUL-terminated C string format (MAX_PROXY_USER_PASS_LENGTH chars + 1 NUL byte).
*
* This member and password must be non-NULL in order to use username/password authentication.
* If either of these members are NULL, they are ignored and connecting to the proxy will be attempted without authentication.
*/
string username;

/**
* The password to be used to authenticate.
*
* If used, this must be non-NULL. The password must be at least MIN_PROXY_USER_PASS_LENGTH characters
* long but it must not exceed MAX_PROXY_USER_PASS_LENGTH characters. It must also be in
* a NUL-terminated C string format (MAX_PROXY_USER_PASS_LENGTH chars + 1 NUL byte).
*
* This member and username must be non-NULL in order to use username/password authentication.
* If either of these members are NULL, they are ignored and connecting to the proxy will be attempted without authentication.
*/
string password;
}

/**
Expand Down Expand Up @@ -563,6 +596,14 @@ static this new(const options_t *options) {
* proxy_type was valid, but the proxy_port was invalid.
*/
BAD_PORT,
/**
* The username had an invalid length.
*/
BAD_USERNAME,
/**
* The password had an invalid length.
*/
BAD_PASSWORD,
/**
* The proxy address passed could not be resolved.
*/
Expand Down
78 changes: 73 additions & 5 deletions toxcore/TCP_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,22 @@ static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn)

return -1;
}

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 the client specified a username and password, we should only try to auth with that

this can be important because tor (for example) makes sure circuits aren't shared
between streams for which different credentials were provided
*/
if (TCP_conn->proxy_info.enable_auth) {
TCP_conn->last_packet[2] = 2; /* Username/password authentication */
} else {
TCP_conn->last_packet[2] = 0; /* No authentication */
}

TCP_conn->last_packet_length = 3;
TCP_conn->last_packet_sent = 0;
Expand All @@ -151,7 +161,7 @@ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn)
if (ret == -1)
return 0;

if (data[0] == 5 && data[1] == 0) // FIXME magic numbers
if (data[0] == 5 && (data[1] == 0 || data[1] == 2)) // FIXME magic numbers
return 1;

return -1;
Expand Down Expand Up @@ -183,6 +193,25 @@ static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_
TCP_conn->last_packet_sent = 0;
}

static void proxy_socks5_generate_auth_request(TCP_Client_Connection *TCP_conn)
{
TCP_conn->last_packet[0] = 1; //version of the subnegotiation
TCP_conn->last_packet[1] = TCP_conn->proxy_info.username_len;
uint16_t length = 2;

memcpy(TCP_conn->last_packet + length, TCP_conn->proxy_info.username, TCP_conn->proxy_info.username_len);
length += TCP_conn->proxy_info.username_len;

TCP_conn->last_packet[length] = TCP_conn->proxy_info.password_len;
length++;

memcpy(TCP_conn->last_packet + length, TCP_conn->proxy_info.password, TCP_conn->proxy_info.password_len);
length += TCP_conn->proxy_info.password_len;

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).
Expand Down Expand Up @@ -213,6 +242,24 @@ static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn
return -1;
}

/* return 1 on success.
* return 0 if no data received.
* return -1 on failure (connection refused).
*/
static int proxy_socks5_read_auth_response(TCP_Client_Connection *TCP_conn)
{
uint8_t data[2];
int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));

if (ret == -1)
return 0;

if (data[0] == 1 && data[1] == 0)
return 1;

return -1;
}

/* return 0 on success.
* return -1 on failure.
*/
Expand Down Expand Up @@ -901,8 +948,13 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
}

if (ret == 1) {
proxy_socks5_generate_connection_request(TCP_connection);
TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
if (TCP_connection->proxy_info.enable_auth) {
proxy_socks5_generate_auth_request(TCP_connection);
TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_AUTH;
} else {
proxy_socks5_generate_connection_request(TCP_connection);
TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
}
}
}
}
Expand All @@ -923,6 +975,22 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
}
}

if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_AUTH) {
if (send_pending_data(TCP_connection) ==0) {
int ret = proxy_socks5_read_auth_response(TCP_connection);

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

if (ret == 1) {
proxy_socks5_generate_connection_request(TCP_connection);
TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
}
}
}

if (TCP_connection->status == TCP_CLIENT_CONNECTING) {
if (send_pending_data(TCP_connection) == 0) {
TCP_connection->status = TCP_CLIENT_UNCONFIRMED;
Expand Down
9 changes: 9 additions & 0 deletions toxcore/TCP_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

#define TCP_CONNECTION_TIMEOUT 10

#define MAX_PROXY_USER_PASS_LENGTH 255
#define MIN_PROXY_USER_PASS_LENGTH 1

typedef enum {
TCP_PROXY_NONE,
TCP_PROXY_HTTP,
Expand All @@ -38,13 +41,19 @@ typedef enum {
typedef struct {
IP_Port ip_port;
uint8_t proxy_type; // a value from TCP_PROXY_TYPE
_Bool enable_auth;
char username[MAX_PROXY_USER_PASS_LENGTH];
uint8_t username_len;
char password[MAX_PROXY_USER_PASS_LENGTH];
uint8_t password_len;
} TCP_Proxy_Info;

enum {
TCP_CLIENT_NO_STATUS,
TCP_CLIENT_PROXY_HTTP_CONNECTING,
TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
TCP_CLIENT_PROXY_SOCKS5_AUTH,
TCP_CLIENT_CONNECTING,
TCP_CLIENT_UNCONFIRMED,
TCP_CLIENT_CONFIRMED,
Expand Down
30 changes: 30 additions & 0 deletions toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ typedef struct Messenger Tox;
#error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH
#endif

#if TOX_MAX_PROXY_USER_PASS_LENGTH != MAX_PROXY_USER_PASS_LENGTH
#error TOX_MAX_PROXY_USER_PASS_LENGTH is assumed to be equal to MAX_PROXY_USER_PASS_LENGTH
#endif

#if TOX_MIN_PROXY_USER_PASS_LENGTH != MIN_PROXY_USER_PASS_LENGTH
#error TOX_MIN_PROXY_USER_PASS_LENGTH is assumed to be equal to MIN_PROXY_USERPASS_LENGTH
#endif

uint32_t tox_version_major(void)
{
return TOX_VERSION_MAJOR;
Expand Down Expand Up @@ -194,6 +202,28 @@ Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error)
return NULL;
}

if (options->proxy_username != NULL && options->proxy_password != NULL) {
size_t username_len = strlen(options->proxy_username);

if (username_len > TOX_MAX_PROXY_USER_PASS_LENGTH || username_len < TOX_MIN_PROXY_USER_PASS_LENGTH) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_USERNAME);
return NULL;
}

size_t password_len = strlen(options->proxy_password);

if (password_len > TOX_MAX_PROXY_USER_PASS_LENGTH || password_len < TOX_MIN_PROXY_USER_PASS_LENGTH) {
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PASSWORD);
return NULL;
}

memcpy(m_options.proxy_info.username, options->proxy_username, username_len);
memcpy(m_options.proxy_info.password, options->proxy_password, password_len);
m_options.proxy_info.username_len = username_len;
m_options.proxy_info.password_len = password_len;
m_options.proxy_info.enable_auth = true;
}

ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled);

if (m_options.ipv6enabled)
Expand Down
46 changes: 46 additions & 0 deletions toxcore/tox.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,16 @@ bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);
*/
#define TOX_MAX_FILENAME_LENGTH 255

/**
* Maximum username/password length for proxy authentication.
*/
#define TOX_MAX_PROXY_USER_PASS_LENGTH 255

/**
* Minimum username/password length for proxy authentication.
*/
#define TOX_MIN_PROXY_USER_PASS_LENGTH 1


/*******************************************************************************
*
Expand Down Expand Up @@ -438,6 +448,32 @@ struct Tox_Options {
uint16_t proxy_port;


/**
* The username to be used to authenticate.
*
* If used, this must be non-NULL. The username must be at least MIN_PROXY_USER_PASS_LENGTH characters
* long but it must not exceed MAX_PROXY_USER_PASS_LENGTH characters. It must also be in
* a NUL-terminated C string format (MAX_PROXY_USER_PASS_LENGTH chars + 1 NUL byte).
*
* This member and password must be non-NULL in order to use username/password authentication.
* If either of these members are NULL, they are ignored and connecting to the proxy will be attempted without authentication.
*/
const char *proxy_username;


/**
* The password to be used to authenticate.
*
* If used, this must be non-NULL. The password must be at least MIN_PROXY_USER_PASS_LENGTH characters
* long but it must not exceed MAX_PROXY_USER_PASS_LENGTH characters. It must also be in
* a NUL-terminated C string format (MAX_PROXY_USER_PASS_LENGTH chars + 1 NUL byte).
*
* This member and username must be non-NULL in order to use username/password authentication.
* If either of these members are NULL, they are ignored and connecting to the proxy will be attempted without authentication.
*/
const char *proxy_password;


/**
* The start port of the inclusive port range to attempt to use.
*
Expand Down Expand Up @@ -591,6 +627,16 @@ typedef enum TOX_ERR_NEW {
*/
TOX_ERR_NEW_PROXY_BAD_PORT,

/**
* The username had an invalid length.
*/
TOX_ERR_NEW_PROXY_BAD_USERNAME,

/**
* The password had an invalid length.
*/
TOX_ERR_NEW_PROXY_BAD_PASSWORD,

/**
* The proxy address passed could not be resolved.
*/
Expand Down