diff --git a/INSTALL b/INSTALL index 007e9396..20998407 100644 --- a/INSTALL +++ b/INSTALL @@ -12,8 +12,8 @@ without warranty of any kind. Basic Installation ================== - Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index f9bd68c2..9869f738 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1595,11 +1595,7 @@ Messenger *new_messenger(Messenger_Options *options) return NULL; } - if (options->proxy_enabled) { - m->net_crypto = new_net_crypto(m->dht, &options->proxy_info); - } else { - m->net_crypto = new_net_crypto(m->dht, 0); - } + m->net_crypto = new_net_crypto(m->dht, &options->proxy_info); if (m->net_crypto == NULL) { kill_networking(m->net); diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index ae6f54c6..3851edf7 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -75,7 +75,6 @@ typedef struct { uint8_t ipv6enabled; uint8_t udp_disabled; - uint8_t proxy_enabled; TCP_Proxy_Info proxy_info; } Messenger_Options; diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 23ab28c0..aee309ae 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -37,8 +37,9 @@ */ 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; + if (proxy_info->proxy_type != TCP_PROXY_NONE) { + ip_port =proxy_info->ip_port; + } struct sockaddr_storage addr = {0}; size_t addrsize; @@ -66,8 +67,67 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_i return 1; } +/* return 1 on success. + * return 0 on failure. + */ +static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) +{ + char one[] = "CONNECT "; + char two[] = " HTTP/1.1\nHost: "; + char three[] = "\r\n\r\n"; -static void socks5_generate_handshake(TCP_Client_Connection *TCP_conn) + char ip[INET6_ADDRSTRLEN]; + if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { + return 0; + } + const uint16_t port = ntohs(TCP_conn->ip_port.port); + const int written = snprintf(TCP_conn->last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, ip, port, three); + if (written < 0) { + return 0; + } + + TCP_conn->last_packet_length = written; + TCP_conn->last_packet_sent = 0; + + return 1; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) +{ + char success[] = "200"; + uint8_t data[16]; // draining works the best if the length is a power of 2 + + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); + + if (ret == -1) { + return 0; + } + + data[sizeof(data) - 1] = '\0'; + + if (strstr(data, success)) { + // drain all data + // instead of drainining it byte by byte do it in bigger chunks + // decrementing to 1 + size_t step = sizeof(data); + do { + if (ret <= 0) { + step = step % 2 == 0 ? step/2 : 1; + } + ret = read_TCP_packet(TCP_conn->sock, data, step); + } while (ret > 0 || step != 1); + + return 1; + } + + 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 */ @@ -95,7 +155,7 @@ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) return -1; } -static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) +static void proxy_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 */ @@ -125,7 +185,7 @@ static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) * return 0 if no data received. * return -1 on failure (connection refused). */ -static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) +static int proxy_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)]; @@ -546,8 +606,9 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public uint8_t family = ip_port.ip.family; - if (proxy_info) + if (proxy_info->proxy_type != TCP_PROXY_NONE) { family = proxy_info->ip_port.ip.family; + } sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); @@ -577,19 +638,26 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public 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; + temp->proxy_info = *proxy_info; - if (proxy_info) { - temp->status = TCP_CLIENT_PROXY_CONNECTING; - temp->proxy_info = *proxy_info; - socks5_generate_handshake(temp); - } else { - temp->status = TCP_CLIENT_CONNECTING; + switch (proxy_info->proxy_type) { + case TCP_PROXY_HTTP: + temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; + proxy_http_generate_connection_request(temp); + break; + case TCP_PROXY_SOCKS5: + temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; + proxy_socks5_generate_handshake(temp); + break; + case TCP_PROXY_NONE: + temp->status = TCP_CLIENT_CONNECTING; - if (generate_handshake(temp) == -1) { - kill_sock(sock); - free(temp); - return NULL; - } + if (generate_handshake(temp) == -1) { + kill_sock(sock); + free(temp); + return NULL; + } + break; } temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; @@ -783,7 +851,23 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) return; } - if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) { + if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { + if (send_pending_data(TCP_connection) == 0) { + int ret = proxy_http_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_PROXY_SOCKS5_CONNECTING) { if (send_pending_data(TCP_connection) == 0) { int ret = socks5_read_handshake_response(TCP_connection); @@ -793,15 +877,15 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) } if (ret == 1) { - socks5_generate_connection_request(TCP_connection); - TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED; + proxy_socks5_generate_connection_request(TCP_connection); + TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; } } } - if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) { + if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { if (send_pending_data(TCP_connection) == 0) { - int ret = socks5_read_connection_response(TCP_connection); + int ret = proxy_socks5_read_connection_response(TCP_connection); if (ret == -1) { TCP_connection->kill_at = 0; diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index 83cb48ba..e37a4ee0 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -29,14 +29,22 @@ #define TCP_CONNECTION_TIMEOUT 10 -typedef struct { +typedef enum { + TCP_PROXY_NONE, + TCP_PROXY_HTTP, + TCP_PROXY_SOCKS5 +} TCP_PROXY_TYPE; + +typedef struct { IP_Port ip_port; + uint8_t proxy_type; // a value from TCP_PROXY_TYPE } TCP_Proxy_Info; enum { TCP_CLIENT_NO_STATUS, - TCP_CLIENT_PROXY_CONNECTING, - TCP_CLIENT_PROXY_UNCONFIRMED, + TCP_CLIENT_PROXY_HTTP_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED, TCP_CLIENT_CONNECTING, TCP_CLIENT_UNCONFIRMED, TCP_CLIENT_CONFIRMED, diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index a1286c5d..c5872068 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -2029,13 +2029,8 @@ 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) { - 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->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; } @@ -2768,10 +2763,7 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info) bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); - if (proxy_info) { - temp->proxy_info = *proxy_info; - temp->proxy_set = 1; - } + temp->proxy_info = *proxy_info; return temp; } diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 7fa05f08..78dea54e 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -215,7 +215,6 @@ 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; diff --git a/toxcore/network.c b/toxcore/network.c index 35ef5221..5539de6b 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -784,6 +784,9 @@ void ipport_unpack(IP_Port *target, const uint8_t *data) /* ip_ntoa * converts ip into a string * uses a static buffer, so mustn't used multiple times in the same output + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error */ /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ static char addresstext[96]; @@ -815,6 +818,38 @@ const char *ip_ntoa(const IP *ip) return addresstext; } +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of AF_INET or AF_INET6 families + * length: length of the address buffer + * Must be at least INET_ADDRSTRLEN for AF_INET + * and INET6_ADDRSTRLEN for AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length) +{ + if (!address || !ip) { + return 0; + } + + if (ip->family == AF_INET) { + struct in_addr *addr = (struct in_addr *)&ip->ip4; + return inet_ntop(ip->family, addr, address, length) != NULL; + } else if (ip->family == AF_INET6) { + struct in6_addr *addr = (struct in6_addr *)&ip->ip6; + return inet_ntop(ip->family, addr, address, length) != NULL; + } + + return 0; +} + /* * addr_parse_ip * directly parses the input into an IP structure diff --git a/toxcore/network.h b/toxcore/network.h index ccda7ae9..5f9af490 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -180,9 +180,29 @@ IP_Port; /* ip_ntoa * converts ip into a string * uses a static buffer, so mustn't used multiple times in the same output + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error */ const char *ip_ntoa(const IP *ip); +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of AF_INET or AF_INET6 families + * length: length of the address buffer + * Must be at least INET_ADDRSTRLEN for AF_INET + * and INET6_ADDRSTRLEN for AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length); + /* * addr_parse_ip * directly parses the input into an IP structure diff --git a/toxcore/tox.c b/toxcore/tox.c index 3f458ac2..d7f231b5 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -1020,9 +1020,20 @@ Tox *tox_new(Tox_Options *options) } else { m_options.ipv6enabled = options->ipv6enabled; m_options.udp_disabled = options->udp_disabled; - m_options.proxy_enabled = options->proxy_enabled; - if (m_options.proxy_enabled) { + switch (options->proxy_type) { + case TOX_PROXY_HTTP: + m_options.proxy_info.proxy_type = TCP_PROXY_HTTP; + break; + case TOX_PROXY_SOCKS5: + m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5; + break; + case TOX_PROXY_NONE: + m_options.proxy_info.proxy_type = TCP_PROXY_NONE; + break; + } + + if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) { ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); if (m_options.ipv6enabled) diff --git a/toxcore/tox.h b/toxcore/tox.h index 3b72eede..c5a5d952 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -873,6 +873,12 @@ int tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_ */ int tox_isconnected(const Tox *tox); +typedef enum { + TOX_PROXY_NONE, + TOX_PROXY_HTTP, + TOX_PROXY_SOCKS5 +} TOX_PROXY_TYPE; + typedef struct { /* * The type of UDP socket created depends on ipv6enabled: @@ -885,13 +891,11 @@ typedef struct { /* Set to 1 to disable udp support. (default: 0) This will force Tox to use TCP only which may slow things down. - Disabling udp support is necessary when using anonymous proxies or Tor.*/ + Disabling udp support is necessary when using proxies or Tor.*/ uint8_t udp_disabled; - - /* Enable proxy support. (only basic TCP socks5 proxy currently supported.) (default: 0 (disabled))*/ - uint8_t proxy_enabled; + uint8_t proxy_type; /* a value from TOX_PROXY_TYPE */ char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */ - uint16_t proxy_port; /* Proxy port: in host byte order. */ + uint16_t proxy_port; /* Proxy port in host byte order. */ } Tox_Options; /*