Skip to content

Commit abbf3db

Browse files
committed
Add username/password SOCKS5 auth
1 parent a71ddc7 commit abbf3db

File tree

6 files changed

+306
-4
lines changed

6 files changed

+306
-4
lines changed

Diff for: toxcore/TCP_client.c

+77-4
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,69 @@ static void proxy_socks5_generate_handshake(TCP_Client_Connection *tcp_conn)
183183
{
184184
tcp_conn->last_packet[0] = 5; /* SOCKSv5 */
185185
tcp_conn->last_packet[1] = 1; /* number of authentication methods supported */
186-
tcp_conn->last_packet[2] = 0; /* No authentication */
186+
187+
if (tcp_conn->proxy_info.socks5_username == nullptr || tcp_conn->proxy_info.socks5_password == nullptr) {
188+
tcp_conn->last_packet[2] = 0; /* No authentication */
189+
} else {
190+
tcp_conn->last_packet[2] = 2; /* Username/password */
191+
}
187192

188193
tcp_conn->last_packet_length = 3;
189194
tcp_conn->last_packet_sent = 0;
190195
}
191196

197+
/* return 2 on success, username/password auth.
198+
* return 1 on success, no auth.
199+
* return 0 if no data received.
200+
* return -1 on failure (connection refused).
201+
*/
202+
static int proxy_socks5_read_handshake_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
203+
{
204+
uint8_t data[2];
205+
int ret = read_TCP_packet(logger, tcp_conn->sock, data, sizeof(data));
206+
207+
if (ret == -1) {
208+
return 0;
209+
}
210+
211+
if (data[0] == 5) { /* must be SOCKSv5 */
212+
if (tcp_conn->proxy_info.socks5_username == nullptr || tcp_conn->proxy_info.socks5_password == nullptr) {
213+
if (data[1] == 0) { /* No authentication */
214+
return 1;
215+
}
216+
} else {
217+
if (data[1] == 2) { /* Username/password */
218+
return 2;
219+
}
220+
}
221+
}
222+
223+
return -1;
224+
}
225+
226+
static void proxy_socks5_generate_authentication_request(TCP_Client_Connection *tcp_conn)
227+
{
228+
tcp_conn->last_packet[0] = 1; /* rfc1929 auth version */
229+
tcp_conn->last_packet[1] = tcp_conn->proxy_info.socks5_username_length;
230+
uint16_t length = 2;
231+
memcpy(tcp_conn->last_packet + length, tcp_conn->proxy_info.socks5_username,
232+
tcp_conn->proxy_info.socks5_username_length);
233+
length += tcp_conn->proxy_info.socks5_username_length;
234+
tcp_conn->last_packet[length] = tcp_conn->proxy_info.socks5_password_length;
235+
++length;
236+
memcpy(tcp_conn->last_packet + length, tcp_conn->proxy_info.socks5_password,
237+
tcp_conn->proxy_info.socks5_password_length);
238+
length += tcp_conn->proxy_info.socks5_password_length;
239+
240+
tcp_conn->last_packet_length = length;
241+
tcp_conn->last_packet_sent = 0;
242+
}
243+
192244
/* return 1 on success.
193245
* return 0 if no data received.
194246
* return -1 on failure (connection refused).
195247
*/
196-
static int socks5_read_handshake_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
248+
static int proxy_socks5_read_authentication_response(const Logger *logger, TCP_Client_Connection *tcp_conn)
197249
{
198250
uint8_t data[2];
199251
int ret = read_TCP_packet(logger, tcp_conn->sock, data, sizeof(data));
@@ -202,7 +254,7 @@ static int socks5_read_handshake_response(const Logger *logger, TCP_Client_Conne
202254
return 0;
203255
}
204256

205-
if (data[0] == 5 && data[1] == 0) { // TODO(irungentoo): magic numbers
257+
if (data[0] == 1 && data[1] == 0) {
206258
return 1;
207259
}
208260

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

9841036
if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) {
9851037
if (client_send_pending_data(tcp_connection) == 0) {
986-
int ret = socks5_read_handshake_response(logger, tcp_connection);
1038+
int ret = proxy_socks5_read_handshake_response(logger, tcp_connection);
1039+
1040+
if (ret == -1) {
1041+
tcp_connection->kill_at = 0;
1042+
tcp_connection->status = TCP_CLIENT_DISCONNECTED;
1043+
}
1044+
1045+
if (ret == 1) { /* no auth */
1046+
proxy_socks5_generate_connection_request(tcp_connection);
1047+
tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
1048+
}
1049+
1050+
if (ret == 2) { /* username/password */
1051+
proxy_socks5_generate_authentication_request(tcp_connection);
1052+
tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING;
1053+
}
1054+
}
1055+
}
1056+
1057+
if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING) {
1058+
if (client_send_pending_data(tcp_connection) == 0) {
1059+
int ret = proxy_socks5_read_authentication_response(logger, tcp_connection);
9871060

9881061
if (ret == -1) {
9891062
tcp_connection->kill_at = 0;

Diff for: toxcore/TCP_client.h

+5
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,17 @@ typedef enum TCP_Proxy_Type {
2323
typedef struct TCP_Proxy_Info {
2424
IP_Port ip_port;
2525
uint8_t proxy_type; // a value from TCP_PROXY_TYPE
26+
const uint8_t *socks5_username;
27+
size_t socks5_username_length;
28+
const uint8_t *socks5_password;
29+
size_t socks5_password_length;
2630
} TCP_Proxy_Info;
2731

2832
typedef enum TCP_Client_Status {
2933
TCP_CLIENT_NO_STATUS,
3034
TCP_CLIENT_PROXY_HTTP_CONNECTING,
3135
TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
36+
TCP_CLIENT_PROXY_SOCKS5_AUTHENTICATING,
3237
TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
3338
TCP_CLIENT_CONNECTING,
3439
TCP_CLIENT_UNCONFIRMED,

Diff for: toxcore/tox.api.h

+75
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ const MAX_FILENAME_LENGTH = 255;
319319
*/
320320
const MAX_HOSTNAME_LENGTH = 255;
321321

322+
/**
323+
* Maximum length of a SOCKS5 proxy username in bytes.
324+
*
325+
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
326+
*/
327+
const MAX_PROXY_SOCKS5_USERNAME_LENGTH = 255;
328+
329+
/**
330+
* Maximum length of a SOCKS5 proxy password in bytes.
331+
*
332+
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
333+
*/
334+
const MAX_PROXY_SOCKS5_PASSWORD_LENGTH = 255;
335+
322336

323337
/*******************************************************************************
324338
*
@@ -540,6 +554,52 @@ static class options {
540554
* proxy_type is ${PROXY_TYPE.NONE}.
541555
*/
542556
uint16_t port;
557+
558+
namespace socks5 {
559+
/**
560+
* The username to use to connect to a SOCKS5 proxy.
561+
*
562+
* If set to NULL, the username/password authentication is disabled.
563+
*
564+
* This member is ignored (it can be NULL) if proxy_type is not
565+
* ${PROXY_TYPE.SOCKS5}.
566+
*
567+
* The data pointed at by this member is owned by the user, so must
568+
* outlive the options object.
569+
*/
570+
const uint8_t[length] username;
571+
572+
/**
573+
* The length of the username.
574+
*
575+
* Must be at most $MAX_PROXY_SOCKS5_USERNAME_LENGTH.
576+
*
577+
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_username_length() function.
578+
*/
579+
size_t username_length;
580+
581+
/**
582+
* The password to use to connect to a Socks proxy.
583+
*
584+
* If set to NULL, the username/password authentication is disabled.
585+
*
586+
* This member is ignored (it can be NULL) if proxy_type is not
587+
* ${PROXY_TYPE.SOCKS5}.
588+
*
589+
* The data pointed at by this member is owned by the user, so must
590+
* outlive the options object.
591+
*/
592+
const uint8_t[length] password;
593+
594+
/**
595+
* The length of the password.
596+
*
597+
* Must be at most $MAX_PROXY_SOCKS5_PASSWORD_LENGTH.
598+
*
599+
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_password_length() function.
600+
*/
601+
size_t password_length;
602+
}
543603
}
544604

545605
/**
@@ -595,6 +655,7 @@ static class options {
595655

596656
/**
597657
* The length of the savedata.
658+
* TODO(iphydf): this creates a pointless tox_options_set_savedata_length() function.
598659
*/
599660
size_t length;
600661
}
@@ -741,6 +802,20 @@ static this new(const options_t *options) {
741802
*/
742803
BAD_FORMAT,
743804
}
805+
806+
/**
807+
* The proxy_socks5_username_length is zero or too long.
808+
*
809+
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
810+
*/
811+
PROXY_SOCKS5_BAD_USERNAME_LENGTH,
812+
813+
/**
814+
* The proxy_socks5_password_length is zero or too long.
815+
*
816+
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
817+
*/
818+
PROXY_SOCKS5_BAD_PASSWORD_LENGTH,
744819
}
745820

746821

Diff for: toxcore/tox.c

+26
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,32 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
514514
}
515515

516516
m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts));
517+
518+
if (m_options.proxy_info.proxy_type == TCP_PROXY_SOCKS5) {
519+
if (tox_options_get_proxy_socks5_username(opts) != nullptr &&
520+
(tox_options_get_proxy_socks5_username_length(opts) < 1 ||
521+
tox_options_get_proxy_socks5_username_length(opts) > TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH)) {
522+
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_SOCKS5_BAD_USERNAME_LENGTH);
523+
tox_options_free(default_options);
524+
free(tox);
525+
return nullptr;
526+
}
527+
528+
m_options.proxy_info.socks5_username = tox_options_get_proxy_socks5_username(opts);
529+
m_options.proxy_info.socks5_username_length = tox_options_get_proxy_socks5_username_length(opts);
530+
531+
if (tox_options_get_proxy_socks5_password(opts) != nullptr &&
532+
(tox_options_get_proxy_socks5_password_length(opts) < 1 ||
533+
tox_options_get_proxy_socks5_password_length(opts) > TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH)) {
534+
SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_SOCKS5_BAD_PASSWORD_LENGTH);
535+
tox_options_free(default_options);
536+
free(tox);
537+
return nullptr;
538+
}
539+
540+
m_options.proxy_info.socks5_password = tox_options_get_proxy_socks5_password(opts);
541+
m_options.proxy_info.socks5_password_length = tox_options_get_proxy_socks5_password_length(opts);
542+
}
517543
}
518544

519545
tox->mono_time = mono_time_new();

Diff for: toxcore/tox.h

+97
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,24 @@ uint32_t tox_max_filename_length(void);
350350

351351
uint32_t tox_max_hostname_length(void);
352352

353+
/**
354+
* Maximum length of a SOCKS5 proxy username in bytes.
355+
*
356+
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
357+
*/
358+
#define TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH 255
359+
360+
uint32_t tox_max_proxy_socks5_username_length(void);
361+
362+
/**
363+
* Maximum length of a SOCKS5 proxy password in bytes.
364+
*
365+
* @deprecated The macro will be removed in 0.3.0. Use the function instead.
366+
*/
367+
#define TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH 255
368+
369+
uint32_t tox_max_proxy_socks5_password_length(void);
370+
353371

354372
/*******************************************************************************
355373
*
@@ -604,6 +622,54 @@ struct Tox_Options {
604622
uint16_t proxy_port;
605623

606624

625+
/**
626+
* The username to use to connect to a SOCKS5 proxy.
627+
*
628+
* If set to NULL, the username/password authentication is disabled.
629+
*
630+
* This member is ignored (it can be NULL) if proxy_type is not
631+
* TOX_PROXY_TYPE_SOCKS5.
632+
*
633+
* The data pointed at by this member is owned by the user, so must
634+
* outlive the options object.
635+
*/
636+
const uint8_t *proxy_socks5_username;
637+
638+
639+
/**
640+
* The length of the username.
641+
*
642+
* Must be at most TOX_MAX_PROXY_SOCKS5_USERNAME_LENGTH.
643+
*
644+
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_username_length() function.
645+
*/
646+
size_t proxy_socks5_username_length;
647+
648+
649+
/**
650+
* The password to use to connect to a Socks proxy.
651+
*
652+
* If set to NULL, the username/password authentication is disabled.
653+
*
654+
* This member is ignored (it can be NULL) if proxy_type is not
655+
* TOX_PROXY_TYPE_SOCKS5.
656+
*
657+
* The data pointed at by this member is owned by the user, so must
658+
* outlive the options object.
659+
*/
660+
const uint8_t *proxy_socks5_password;
661+
662+
663+
/**
664+
* The length of the password.
665+
*
666+
* Must be at most TOX_MAX_PROXY_SOCKS5_PASSWORD_LENGTH.
667+
*
668+
* TODO(iphydf): this creates a pointless tox_options_set_proxy_socks5_password_length() function.
669+
*/
670+
size_t proxy_socks5_password_length;
671+
672+
607673
/**
608674
* The start port of the inclusive port range to attempt to use.
609675
*
@@ -662,6 +728,7 @@ struct Tox_Options {
662728

663729
/**
664730
* The length of the savedata.
731+
* TODO(iphydf): this creates a pointless tox_options_set_savedata_length() function.
665732
*/
666733
size_t savedata_length;
667734

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

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

788+
const uint8_t *tox_options_get_proxy_socks5_username(const struct Tox_Options *options);
789+
790+
void tox_options_set_proxy_socks5_username(struct Tox_Options *options, const uint8_t *username, size_t length);
791+
792+
size_t tox_options_get_proxy_socks5_username_length(const struct Tox_Options *options);
793+
794+
void tox_options_set_proxy_socks5_username_length(struct Tox_Options *options, size_t username_length);
795+
796+
const uint8_t *tox_options_get_proxy_socks5_password(const struct Tox_Options *options);
797+
798+
void tox_options_set_proxy_socks5_password(struct Tox_Options *options, const uint8_t *password, size_t length);
799+
800+
size_t tox_options_get_proxy_socks5_password_length(const struct Tox_Options *options);
801+
802+
void tox_options_set_proxy_socks5_password_length(struct Tox_Options *options, size_t password_length);
803+
721804
uint16_t tox_options_get_start_port(const struct Tox_Options *options);
722805

723806
void tox_options_set_start_port(struct Tox_Options *options, uint16_t start_port);
@@ -875,6 +958,20 @@ typedef enum TOX_ERR_NEW {
875958
*/
876959
TOX_ERR_NEW_LOAD_BAD_FORMAT,
877960

961+
/**
962+
* The proxy_socks5_username_length is zero or too long.
963+
*
964+
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
965+
*/
966+
TOX_ERR_NEW_PROXY_SOCKS5_BAD_USERNAME_LENGTH,
967+
968+
/**
969+
* The proxy_socks5_password_length is zero or too long.
970+
*
971+
* TODO(iphydf): allow duplicate namespaces (e.g. PROXY).
972+
*/
973+
TOX_ERR_NEW_PROXY_SOCKS5_BAD_PASSWORD_LENGTH,
974+
878975
} TOX_ERR_NEW;
879976

880977

0 commit comments

Comments
 (0)