Skip to content

feat: Add username/password SOCKS5 auth #1683

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion auto_tests/invalid_udp_proxy_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int main(void)

bootstrap_tox_live_network(tox, true);

printf("Waiting for connection...");
printf("Waiting for connection...\n");

for (uint16_t i = 0; i < NUM_ITERATIONS; i++) {
tox_iterate(tox, nullptr);
Expand Down
51 changes: 40 additions & 11 deletions auto_tests/proxy_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "auto_test_support.h"

Expand All @@ -16,32 +17,36 @@ static void *proxy_routine(void *arg)
return nullptr;
}

static bool try_bootstrap(Tox *tox1, Tox *tox2, Tox *tox3, Tox *tox4)
static bool try_bootstrap(Tox *tox1, Tox *tox2, Tox *tox3, Tox *tox4, Tox *tox5)
{
for (uint32_t i = 0; i < 400; ++i) {
if (tox_self_get_connection_status(tox1) != TOX_CONNECTION_NONE &&
tox_self_get_connection_status(tox2) != TOX_CONNECTION_NONE &&
tox_self_get_connection_status(tox3) != TOX_CONNECTION_NONE &&
tox_self_get_connection_status(tox4) != TOX_CONNECTION_NONE) {
printf("%d %d %d %d\n",
tox_self_get_connection_status(tox4) != TOX_CONNECTION_NONE &&
tox_self_get_connection_status(tox5) != TOX_CONNECTION_NONE) {
printf("%d %d %d %d %d\n",
tox_self_get_connection_status(tox1),
tox_self_get_connection_status(tox2),
tox_self_get_connection_status(tox3),
tox_self_get_connection_status(tox4));
tox_self_get_connection_status(tox4),
tox_self_get_connection_status(tox5));
return true;
}

tox_iterate(tox1, nullptr);
tox_iterate(tox2, nullptr);
tox_iterate(tox3, nullptr);
tox_iterate(tox4, nullptr);
tox_iterate(tox5, nullptr);

if (i % 10 == 0) {
printf("%d %d %d %d\n",
printf("%d %d %d %d %d\n",
tox_self_get_connection_status(tox1),
tox_self_get_connection_status(tox2),
tox_self_get_connection_status(tox3),
tox_self_get_connection_status(tox4));
tox_self_get_connection_status(tox4),
tox_self_get_connection_status(tox5));
}

c_sleep(tox_iteration_interval(tox1));
Expand All @@ -60,15 +65,16 @@ int main(int argc, char **argv)
c_sleep(100);
}

const uint16_t tcp_port = 7082;
uint32_t index[] = { 1, 2, 3, 4 };
const uint16_t tcp_port = 7083;
uint32_t index[] = { 1, 2, 3, 4, 5 };

struct Tox_Options *tox_options = tox_options_new(nullptr);
ck_assert(tox_options != nullptr);

// tox1 is a TCP server and has UDP enabled.
tox_options_set_udp_enabled(tox_options, true);
tox_options_set_tcp_port(tox_options, tcp_port);
tox_options_set_local_discovery_enabled(tox_options, false);

Tox *tox1 = tox_new_log(tox_options, nullptr, &index[0]);
ck_assert(tox1 != nullptr);
Expand All @@ -80,8 +86,10 @@ int main(int argc, char **argv)
ck_assert(dht_port != 0);

// tox2 is a regular DHT node bootstrapping against tox1.
tox_options_default(tox_options);
tox_options_set_udp_enabled(tox_options, true);
tox_options_set_tcp_port(tox_options, 0);
tox_options_set_local_discovery_enabled(tox_options, false);

Tox *tox2 = tox_new_log(tox_options, nullptr, &index[1]);
ck_assert(tox2 != nullptr);
Expand All @@ -90,36 +98,57 @@ int main(int argc, char **argv)
ck_assert(tox_bootstrap(tox2, "127.0.0.1", dht_port, dht_pk, nullptr));

// tox3 has UDP disabled and connects to tox1 via an HTTP proxy
tox_options_default(tox_options);
tox_options_set_udp_enabled(tox_options, false);
tox_options_set_proxy_host(tox_options, "127.0.0.1");
tox_options_set_proxy_port(tox_options, 7080);
tox_options_set_proxy_type(tox_options, TOX_PROXY_TYPE_HTTP);
tox_options_set_local_discovery_enabled(tox_options, false);

Tox *tox3 = tox_new_log(tox_options, nullptr, &index[2]);
ck_assert(tox3 != nullptr);

// tox4 has UDP disabled and connects to tox1 via a SOCKS5 proxy
// tox4 has UDP disabled and connects to tox1 via a SOCKS5 proxy with no auth
tox_options_default(tox_options);
tox_options_set_udp_enabled(tox_options, false);
tox_options_set_proxy_host(tox_options, "127.0.0.1");
tox_options_set_proxy_port(tox_options, 7081);
tox_options_set_proxy_type(tox_options, TOX_PROXY_TYPE_SOCKS5);
tox_options_set_local_discovery_enabled(tox_options, false);

Tox *tox4 = tox_new_log(tox_options, nullptr, &index[3]);
ck_assert(tox4 != nullptr);

// tox3 and tox4 bootstrap against tox1 and add it as a TCP relay
// tox5 has UDP disabled and connects to tox1 via a SOCKS5 proxy with username/password auth
tox_options_default(tox_options);
tox_options_set_udp_enabled(tox_options, false);
tox_options_set_proxy_host(tox_options, "127.0.0.1");
tox_options_set_proxy_port(tox_options, 7082);
tox_options_set_proxy_type(tox_options, TOX_PROXY_TYPE_SOCKS5);
tox_options_set_proxy_socks5_username(tox_options, (const uint8_t *) "nurupo", strlen("nurupo"));
tox_options_set_proxy_socks5_password(tox_options, (const uint8_t *) "hunter2", strlen("hunter2"));
tox_options_set_local_discovery_enabled(tox_options, false);

Tox *tox5 = tox_new_log(tox_options, nullptr, &index[4]);
ck_assert(tox5 != nullptr);

// tox3, tox4 and tox5 bootstrap against tox1 and add it as a TCP relay
ck_assert(tox_bootstrap(tox3, "127.0.0.1", dht_port, dht_pk, nullptr));
ck_assert(tox_add_tcp_relay(tox3, "127.0.0.1", tcp_port, dht_pk, nullptr));

ck_assert(tox_bootstrap(tox4, "127.0.0.1", dht_port, dht_pk, nullptr));
ck_assert(tox_add_tcp_relay(tox4, "127.0.0.1", tcp_port, dht_pk, nullptr));

ck_assert(tox_bootstrap(tox5, "127.0.0.1", dht_port, dht_pk, nullptr));
ck_assert(tox_add_tcp_relay(tox5, "127.0.0.1", tcp_port, dht_pk, nullptr));

int ret = 1;
if (try_bootstrap(tox1, tox2, tox3, tox4)) {
if (try_bootstrap(tox1, tox2, tox3, tox4, tox5)) {
ret = 0;
}

tox_options_free(tox_options);
tox_kill(tox5);
tox_kill(tox4);
tox_kill(tox3);
tox_kill(tox2);
Expand Down
23 changes: 16 additions & 7 deletions other/proxy/proxy_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import (
)

const (
debug = false
httpAddr = ":7080"
socks5Addr = ":7081"
debug = false
httpAddr = "127.0.0.1:7080"
socks5NoAuthAddr = "127.0.0.1:7081"
socks5UsernamePasswordAuthAddr = "127.0.0.1:7082"
)

func handleTunneling(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -75,11 +76,19 @@ func main() {
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}

log.Printf("starting SOCKS5 proxy server on %s", socks5Addr)
socks5Server := socks5.NewServer(
socks5.WithLogger(socks5.NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
log.Printf("starting SOCKS5 no-auth proxy server on %s", socks5NoAuthAddr)
socks5NoAuthServer := socks5.NewServer(
socks5.WithLogger(socks5.NewLogger(log.New(os.Stdout, "socks5 no-auth: ", log.LstdFlags))),
)

go socks5Server.ListenAndServe("tcp", socks5Addr)
log.Printf("starting SOCKS5 username/password auth proxy server on %s", socks5UsernamePasswordAuthAddr)
authenticator := socks5.UserPassAuthenticator{socks5.StaticCredentials{"nurupo": "hunter2"}}
socks5UsernamePasswordAuthServer := socks5.NewServer(
socks5.WithAuthMethods([]socks5.Authenticator{authenticator}),
socks5.WithLogger(socks5.NewLogger(log.New(os.Stdout, "socks5 username/password auth: ", log.LstdFlags))),
)

go socks5NoAuthServer.ListenAndServe("tcp", socks5NoAuthAddr)
go socks5UsernamePasswordAuthServer.ListenAndServe("tcp", socks5UsernamePasswordAuthAddr)
log.Fatal(httpServer.ListenAndServe())
}
63 changes: 48 additions & 15 deletions toxcore/Messenger.c
Original file line number Diff line number Diff line change
Expand Up @@ -3474,10 +3474,26 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->mem = mem;
m->rng = rng;
m->ns = ns;
// copy options by value
m->options = *options;
// deep copy of arrays/strings
// Messenger_Options is owned by the caller and the caller will free these, so we need to make our own copy
m->options.proxy_info.socks5_username = memdup(m->mem, options->proxy_info.socks5_username, options->proxy_info.socks5_username_length);
m->options.proxy_info.socks5_password = memdup(m->mem, options->proxy_info.socks5_password, options->proxy_info.socks5_password_length);
if ((options->proxy_info.socks5_username != nullptr && m->options.proxy_info.socks5_username == nullptr)
|| (options->proxy_info.socks5_password != nullptr && m->options.proxy_info.socks5_password == nullptr)) {
LOGGER_WARNING(m->log, "failed to copy SOCKS5 proxy username or password");
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

m->fr = friendreq_new(mem);

if (m->fr == nullptr) {
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}
Expand All @@ -3486,26 +3502,28 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *

if (m->log == nullptr) {
friendreq_kill(m->fr);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

logger_callback_log(m->log, options->log_callback, options->log_context, options->log_user_data);
logger_callback_log(m->log, m->options.log_callback, m->options.log_context, m->options.log_user_data);

unsigned int net_err = 0;

if (!options->udp_disabled && options->proxy_info.proxy_type != TCP_PROXY_NONE) {
if (!m->options.udp_disabled && m->options.proxy_info.proxy_type != TCP_PROXY_NONE) {
// We don't currently support UDP over proxy.
LOGGER_INFO(m->log, "UDP enabled and proxy set: disabling UDP");
options->udp_disabled = true;
m->options.udp_disabled = true;
}

if (options->udp_disabled) {
if (m->options.udp_disabled) {
m->net = new_networking_no_udp(m->log, m->mem, m->ns);
} else {
IP ip;
ip_init(&ip, options->ipv6enabled);
m->net = new_networking_ex(m->log, m->mem, m->ns, &ip, options->port_range[0], options->port_range[1], &net_err);
ip_init(&ip, m->options.ipv6enabled);
m->net = new_networking_ex(m->log, m->mem, m->ns, &ip, m->options.port_range[0], m->options.port_range[1], &net_err);
}

if (m->net == nullptr) {
Expand All @@ -3517,21 +3535,25 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
}

logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

m->dht = new_dht(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, options->hole_punching_enabled, options->local_discovery_enabled);
m->dht = new_dht(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, m->options.hole_punching_enabled, m->options.local_discovery_enabled);

if (m->dht == nullptr) {
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

m->net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->dht, &options->proxy_info);
m->net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->dht, &m->options.proxy_info);

if (m->net_crypto == nullptr) {
LOGGER_WARNING(m->log, "net_crypto initialisation failed");
Expand All @@ -3540,6 +3562,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}
Expand All @@ -3554,11 +3578,13 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

if (options->dht_announcements_enabled) {
if (m->options.dht_announcements_enabled) {
m->forwarding = new_forwarding(m->log, m->mem, m->rng, m->mono_time, m->dht);
if (m->forwarding != nullptr) {
m->announce = new_announcements(m->log, m->mem, m->rng, m->mono_time, m->forwarding);
Expand All @@ -3574,10 +3600,10 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
m->onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht);
m->onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto);
if (m->onion_c != nullptr) {
m->fr_c = new_friend_connections(m->log, m->mem, m->mono_time, m->ns, m->onion_c, options->local_discovery_enabled);
m->fr_c = new_friend_connections(m->log, m->mem, m->mono_time, m->ns, m->onion_c, m->options.local_discovery_enabled);
}

if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
if ((m->options.dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {
LOGGER_WARNING(m->log, "onion initialisation failed");

Expand All @@ -3593,6 +3619,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}
Expand All @@ -3616,13 +3644,15 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);
return nullptr;
}

if (options->tcp_server_port != 0) {
m->tcp_server = new_tcp_server(m->log, m->mem, m->rng, m->ns, options->ipv6enabled, 1,
&options->tcp_server_port, dht_get_self_secret_key(m->dht),
if (m->options.tcp_server_port != 0) {
m->tcp_server = new_tcp_server(m->log, m->mem, m->rng, m->ns, m->options.ipv6enabled, 1,
&m->options.tcp_server_port, dht_get_self_secret_key(m->dht),
m->onion, m->forwarding);

if (m->tcp_server == nullptr) {
Expand All @@ -3641,6 +3671,8 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
kill_networking(m->net);
friendreq_kill(m->fr);
logger_kill(m->log);
mem_delete(mem, m->options.proxy_info.socks5_username);
mem_delete(mem, m->options.proxy_info.socks5_password);
mem_delete(mem, m);

if (error != nullptr) {
Expand All @@ -3651,7 +3683,6 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
}
}

m->options = *options;
friendreq_init(m->fr, m->fr_c);
set_nospam(m->fr, random_u32(m->rng));
set_filter_function(m->fr, &friend_already_added, m);
Expand Down Expand Up @@ -3704,6 +3735,8 @@ void kill_messenger(Messenger *m)

mem_delete(m->mem, m->options.state_plugins);
logger_kill(m->log);
mem_delete(m->mem, m->options.proxy_info.socks5_username);
mem_delete(m->mem, m->options.proxy_info.socks5_password);
mem_delete(m->mem, m);
}

Expand Down
Loading
Loading