mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Added basic socks5 proxy support to TCP client.
This commit is contained in:
parent
f4b10c99ff
commit
78dd2234e0
|
@ -381,7 +381,7 @@ START_TEST(test_client)
|
|||
ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);
|
||||
ip_port_tcp_s.ip.family = AF_INET6;
|
||||
ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;
|
||||
TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key);
|
||||
TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, 0);
|
||||
c_sleep(50);
|
||||
do_TCP_connection(conn);
|
||||
ck_assert_msg(conn->status == TCP_CLIENT_UNCONFIRMED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_UNCONFIRMED,
|
||||
|
@ -408,7 +408,7 @@ START_TEST(test_client)
|
|||
uint8_t f2_public_key[crypto_box_PUBLICKEYBYTES];
|
||||
uint8_t f2_secret_key[crypto_box_SECRETKEYBYTES];
|
||||
crypto_box_keypair(f2_public_key, f2_secret_key);
|
||||
TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key);
|
||||
TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key, 0);
|
||||
routing_response_handler(conn, response_callback, ((void *)conn) + 2);
|
||||
routing_status_handler(conn, status_callback, (void *)2);
|
||||
routing_data_handler(conn, data_callback, (void *)3);
|
||||
|
@ -475,7 +475,7 @@ START_TEST(test_client_invalid)
|
|||
ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);
|
||||
ip_port_tcp_s.ip.family = AF_INET6;
|
||||
ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;
|
||||
TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key);
|
||||
TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, 0);
|
||||
c_sleep(50);
|
||||
do_TCP_connection(conn);
|
||||
ck_assert_msg(conn->status == TCP_CLIENT_CONNECTING, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_CONNECTING,
|
||||
|
|
|
@ -242,7 +242,7 @@ Onions *new_onions(uint16_t port)
|
|||
DHT *dht = new_DHT(new_networking(ip, port));
|
||||
on->onion = new_onion(dht);
|
||||
on->onion_a = new_onion_announce(dht);
|
||||
on->onion_c = new_onion_client(new_net_crypto(dht));
|
||||
on->onion_c = new_onion_client(new_net_crypto(dht, 0));
|
||||
|
||||
if (on->onion && on->onion_a && on->onion_c)
|
||||
return on;
|
||||
|
|
|
@ -1850,8 +1850,7 @@ Messenger *new_messenger(uint8_t ipv6enabled)
|
|||
free(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->net_crypto = new_net_crypto(m->dht);
|
||||
m->net_crypto = new_net_crypto(m->dht, 0);
|
||||
|
||||
if (m->net_crypto == NULL) {
|
||||
kill_networking(m->net);
|
||||
|
|
|
@ -35,8 +35,11 @@
|
|||
/* return 1 on success
|
||||
* return 0 on failure
|
||||
*/
|
||||
static int connect_sock_to(sock_t sock, IP_Port ip_port)
|
||||
static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info)
|
||||
{
|
||||
if (proxy_info)
|
||||
ip_port = proxy_info->ip_port;
|
||||
|
||||
struct sockaddr_storage addr = {0};
|
||||
size_t addrsize;
|
||||
|
||||
|
@ -62,18 +65,102 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port)
|
|||
connect(sock, (struct sockaddr *)&addr, addrsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void 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 */
|
||||
|
||||
TCP_conn->last_packet_length = 3;
|
||||
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(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] == 5 && data[1] == 0)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn)
|
||||
{
|
||||
TCP_conn->last_packet[0] = 5; /* SOCKSv5 */
|
||||
TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */
|
||||
TCP_conn->last_packet[2] = 0; /* reserved, must be 0 */
|
||||
uint16_t length = 3;
|
||||
|
||||
if (TCP_conn->ip_port.ip.family == AF_INET) {
|
||||
TCP_conn->last_packet[3] = 1; /* IPv4 address */
|
||||
++length;
|
||||
memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip4.uint8, sizeof(IP4));
|
||||
length += sizeof(IP4);
|
||||
} else {
|
||||
TCP_conn->last_packet[3] = 4; /* IPv6 address */
|
||||
++length;
|
||||
memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip6.uint8, sizeof(IP6));
|
||||
length += sizeof(IP6);
|
||||
}
|
||||
|
||||
memcpy(TCP_conn->last_packet + length, &TCP_conn->ip_port.port, sizeof(uint16_t));
|
||||
length += sizeof(uint16_t);
|
||||
|
||||
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_connection_response(TCP_Client_Connection *TCP_conn)
|
||||
{
|
||||
if (TCP_conn->ip_port.ip.family == AF_INET) {
|
||||
uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)];
|
||||
int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));
|
||||
|
||||
if (ret == -1)
|
||||
return 0;
|
||||
|
||||
if (data[0] == 5 && data[1] == 0)
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
uint8_t data[4 + sizeof(IP6) + sizeof(uint16_t)];
|
||||
int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));
|
||||
|
||||
if (ret == -1)
|
||||
return 0;
|
||||
|
||||
if (data[0] == 5 && data[1] == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
static int generate_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *self_public_key,
|
||||
const uint8_t *self_secret_key)
|
||||
static int generate_handshake(TCP_Client_Connection *TCP_conn)
|
||||
{
|
||||
uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES];
|
||||
crypto_box_keypair(plain, TCP_conn->temp_secret_key);
|
||||
encrypt_precompute(TCP_conn->public_key, self_secret_key, TCP_conn->shared_key);
|
||||
random_nonce(TCP_conn->sent_nonce);
|
||||
memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(TCP_conn->last_packet, TCP_conn->self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES);
|
||||
int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain,
|
||||
sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
|
@ -448,7 +535,7 @@ void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(vo
|
|||
/* Create new TCP connection to ip_port/public_key
|
||||
*/
|
||||
TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key,
|
||||
const uint8_t *self_secret_key)
|
||||
const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info)
|
||||
{
|
||||
if (networking_at_startup() != 0) {
|
||||
return NULL;
|
||||
|
@ -468,7 +555,7 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port))) {
|
||||
if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) {
|
||||
kill_sock(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -480,15 +567,24 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public
|
|||
return NULL;
|
||||
}
|
||||
|
||||
temp->status = TCP_CLIENT_CONNECTING;
|
||||
temp->sock = sock;
|
||||
memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key);
|
||||
temp->ip_port = ip_port;
|
||||
|
||||
if (generate_handshake(temp, self_public_key, self_secret_key) == -1) {
|
||||
kill_sock(sock);
|
||||
free(temp);
|
||||
return NULL;
|
||||
if (proxy_info) {
|
||||
temp->status = TCP_CLIENT_PROXY_CONNECTING;
|
||||
temp->proxy_info = *proxy_info;
|
||||
socks5_generate_handshake(temp);
|
||||
} else {
|
||||
temp->status = TCP_CLIENT_CONNECTING;
|
||||
|
||||
if (generate_handshake(temp) == -1) {
|
||||
kill_sock(sock);
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT;
|
||||
|
@ -682,6 +778,38 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
|
|||
return;
|
||||
}
|
||||
|
||||
if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) {
|
||||
if (send_pending_data(TCP_connection) == 0) {
|
||||
int ret = socks5_read_handshake_response(TCP_connection);
|
||||
|
||||
if (ret == -1) {
|
||||
TCP_connection->kill_at = 0;
|
||||
TCP_connection->status = TCP_CLIENT_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
socks5_generate_connection_request(TCP_connection);
|
||||
TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) {
|
||||
if (send_pending_data(TCP_connection) == 0) {
|
||||
int ret = socks5_read_connection_response(TCP_connection);
|
||||
|
||||
if (ret == -1) {
|
||||
TCP_connection->kill_at = 0;
|
||||
TCP_connection->status = TCP_CLIENT_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
generate_handshake(TCP_connection);
|
||||
TCP_connection->status = TCP_CLIENT_CONNECTING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TCP_connection->status == TCP_CLIENT_CONNECTING) {
|
||||
if (send_pending_data(TCP_connection) == 0) {
|
||||
TCP_connection->status = TCP_CLIENT_UNCONFIRMED;
|
||||
|
|
|
@ -29,8 +29,14 @@
|
|||
|
||||
#define TCP_CONNECTION_TIMEOUT 10
|
||||
|
||||
typedef struct {
|
||||
IP_Port ip_port;
|
||||
} TCP_Proxy_Info;
|
||||
|
||||
enum {
|
||||
TCP_CLIENT_NO_STATUS,
|
||||
TCP_CLIENT_PROXY_CONNECTING,
|
||||
TCP_CLIENT_PROXY_UNCONFIRMED,
|
||||
TCP_CLIENT_CONNECTING,
|
||||
TCP_CLIENT_UNCONFIRMED,
|
||||
TCP_CLIENT_CONFIRMED,
|
||||
|
@ -39,8 +45,10 @@ enum {
|
|||
typedef struct {
|
||||
uint8_t status;
|
||||
sock_t sock;
|
||||
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; /* our public key */
|
||||
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */
|
||||
IP_Port ip_port; /* The ip and port of the server */
|
||||
TCP_Proxy_Info proxy_info;
|
||||
uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */
|
||||
uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */
|
||||
uint8_t shared_key[crypto_box_BEFORENMBYTES];
|
||||
|
@ -85,7 +93,7 @@ typedef struct {
|
|||
/* Create new TCP connection to ip_port/public_key
|
||||
*/
|
||||
TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key,
|
||||
const uint8_t *self_secret_key);
|
||||
const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info);
|
||||
|
||||
/* Run the TCP connection
|
||||
*/
|
||||
|
|
|
@ -1916,7 +1916,14 @@ int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key)
|
|||
|
||||
for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
|
||||
if (c->tcp_connections_new[i] == NULL) {
|
||||
c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key);
|
||||
if (c->proxy_set) {
|
||||
c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key,
|
||||
&c->proxy_info);
|
||||
} else {
|
||||
c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key,
|
||||
0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2607,7 +2614,7 @@ void load_keys(Net_Crypto *c, const uint8_t *keys)
|
|||
/* Run this to (re)initialize net_crypto.
|
||||
* Sets all the global connection variables to their default values.
|
||||
*/
|
||||
Net_Crypto *new_net_crypto(DHT *dht)
|
||||
Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info)
|
||||
{
|
||||
unix_time_update();
|
||||
|
||||
|
@ -2634,6 +2641,12 @@ Net_Crypto *new_net_crypto(DHT *dht)
|
|||
bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8);
|
||||
|
||||
pthread_mutex_init(&temp->connections_mutex, NULL);
|
||||
|
||||
if (proxy_info) {
|
||||
temp->proxy_info = *proxy_info;
|
||||
temp->proxy_set = 1;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,6 +201,9 @@ typedef struct {
|
|||
|
||||
int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length);
|
||||
void *tcp_onion_callback_object;
|
||||
|
||||
uint8_t proxy_set;
|
||||
TCP_Proxy_Info proxy_info;
|
||||
} Net_Crypto;
|
||||
|
||||
|
||||
|
@ -377,7 +380,7 @@ void load_keys(Net_Crypto *c, const uint8_t *keys);
|
|||
/* Create new instance of Net_Crypto.
|
||||
* Sets all the global connection variables to their default values.
|
||||
*/
|
||||
Net_Crypto *new_net_crypto(DHT *dht);
|
||||
Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info);
|
||||
|
||||
/* return the optimal interval in ms for running do_net_crypto.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user