diff options
Diffstat (limited to 'toxcore/TCP_client.c')
-rw-r--r-- | toxcore/TCP_client.c | 128 |
1 files changed, 106 insertions, 22 deletions
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 @@ | |||
37 | */ | 37 | */ |
38 | static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) | 38 | static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) |
39 | { | 39 | { |
40 | if (proxy_info) | 40 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
41 | ip_port = proxy_info->ip_port; | 41 | ip_port =proxy_info->ip_port; |
42 | } | ||
42 | 43 | ||
43 | struct sockaddr_storage addr = {0}; | 44 | struct sockaddr_storage addr = {0}; |
44 | size_t addrsize; | 45 | size_t addrsize; |
@@ -66,8 +67,67 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_i | |||
66 | return 1; | 67 | return 1; |
67 | } | 68 | } |
68 | 69 | ||
70 | /* return 1 on success. | ||
71 | * return 0 on failure. | ||
72 | */ | ||
73 | static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) | ||
74 | { | ||
75 | char one[] = "CONNECT "; | ||
76 | char two[] = " HTTP/1.1\nHost: "; | ||
77 | char three[] = "\r\n\r\n"; | ||
78 | |||
79 | char ip[INET6_ADDRSTRLEN]; | ||
80 | if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { | ||
81 | return 0; | ||
82 | } | ||
83 | const uint16_t port = ntohs(TCP_conn->ip_port.port); | ||
84 | 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); | ||
85 | if (written < 0) { | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | TCP_conn->last_packet_length = written; | ||
90 | TCP_conn->last_packet_sent = 0; | ||
91 | |||
92 | return 1; | ||
93 | } | ||
94 | |||
95 | /* return 1 on success. | ||
96 | * return 0 if no data received. | ||
97 | * return -1 on failure (connection refused). | ||
98 | */ | ||
99 | static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) | ||
100 | { | ||
101 | char success[] = "200"; | ||
102 | uint8_t data[16]; // draining works the best if the length is a power of 2 | ||
103 | |||
104 | int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); | ||
105 | |||
106 | if (ret == -1) { | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | data[sizeof(data) - 1] = '\0'; | ||
111 | |||
112 | if (strstr(data, success)) { | ||
113 | // drain all data | ||
114 | // instead of drainining it byte by byte do it in bigger chunks | ||
115 | // decrementing to 1 | ||
116 | size_t step = sizeof(data); | ||
117 | do { | ||
118 | if (ret <= 0) { | ||
119 | step = step % 2 == 0 ? step/2 : 1; | ||
120 | } | ||
121 | ret = read_TCP_packet(TCP_conn->sock, data, step); | ||
122 | } while (ret > 0 || step != 1); | ||
123 | |||
124 | return 1; | ||
125 | } | ||
69 | 126 | ||
70 | static void socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | 127 | return -1; |
128 | } | ||
129 | |||
130 | static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | ||
71 | { | 131 | { |
72 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 132 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
73 | TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ | 133 | 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) | |||
95 | return -1; | 155 | return -1; |
96 | } | 156 | } |
97 | 157 | ||
98 | static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) | 158 | static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) |
99 | { | 159 | { |
100 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 160 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
101 | TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ | 161 | 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) | |||
125 | * return 0 if no data received. | 185 | * return 0 if no data received. |
126 | * return -1 on failure (connection refused). | 186 | * return -1 on failure (connection refused). |
127 | */ | 187 | */ |
128 | static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) | 188 | static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn) |
129 | { | 189 | { |
130 | if (TCP_conn->ip_port.ip.family == AF_INET) { | 190 | if (TCP_conn->ip_port.ip.family == AF_INET) { |
131 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; | 191 | 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 | |||
546 | 606 | ||
547 | uint8_t family = ip_port.ip.family; | 607 | uint8_t family = ip_port.ip.family; |
548 | 608 | ||
549 | if (proxy_info) | 609 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
550 | family = proxy_info->ip_port.ip.family; | 610 | family = proxy_info->ip_port.ip.family; |
611 | } | ||
551 | 612 | ||
552 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); | 613 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); |
553 | 614 | ||
@@ -577,19 +638,26 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public | |||
577 | memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES); | 638 | memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES); |
578 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); | 639 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); |
579 | temp->ip_port = ip_port; | 640 | temp->ip_port = ip_port; |
641 | temp->proxy_info = *proxy_info; | ||
580 | 642 | ||
581 | if (proxy_info) { | 643 | switch (proxy_info->proxy_type) { |
582 | temp->status = TCP_CLIENT_PROXY_CONNECTING; | 644 | case TCP_PROXY_HTTP: |
583 | temp->proxy_info = *proxy_info; | 645 | temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; |
584 | socks5_generate_handshake(temp); | 646 | proxy_http_generate_connection_request(temp); |
585 | } else { | 647 | break; |
586 | temp->status = TCP_CLIENT_CONNECTING; | 648 | case TCP_PROXY_SOCKS5: |
649 | temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; | ||
650 | proxy_socks5_generate_handshake(temp); | ||
651 | break; | ||
652 | case TCP_PROXY_NONE: | ||
653 | temp->status = TCP_CLIENT_CONNECTING; | ||
587 | 654 | ||
588 | if (generate_handshake(temp) == -1) { | 655 | if (generate_handshake(temp) == -1) { |
589 | kill_sock(sock); | 656 | kill_sock(sock); |
590 | free(temp); | 657 | free(temp); |
591 | return NULL; | 658 | return NULL; |
592 | } | 659 | } |
660 | break; | ||
593 | } | 661 | } |
594 | 662 | ||
595 | temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; | 663 | temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; |
@@ -783,7 +851,23 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
783 | return; | 851 | return; |
784 | } | 852 | } |
785 | 853 | ||
786 | if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) { | 854 | if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { |
855 | if (send_pending_data(TCP_connection) == 0) { | ||
856 | int ret = proxy_http_read_connection_response(TCP_connection); | ||
857 | |||
858 | if (ret == -1) { | ||
859 | TCP_connection->kill_at = 0; | ||
860 | TCP_connection->status = TCP_CLIENT_DISCONNECTED; | ||
861 | } | ||
862 | |||
863 | if (ret == 1) { | ||
864 | generate_handshake(TCP_connection); | ||
865 | TCP_connection->status = TCP_CLIENT_CONNECTING; | ||
866 | } | ||
867 | } | ||
868 | } | ||
869 | |||
870 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { | ||
787 | if (send_pending_data(TCP_connection) == 0) { | 871 | if (send_pending_data(TCP_connection) == 0) { |
788 | int ret = socks5_read_handshake_response(TCP_connection); | 872 | int ret = socks5_read_handshake_response(TCP_connection); |
789 | 873 | ||
@@ -793,15 +877,15 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
793 | } | 877 | } |
794 | 878 | ||
795 | if (ret == 1) { | 879 | if (ret == 1) { |
796 | socks5_generate_connection_request(TCP_connection); | 880 | proxy_socks5_generate_connection_request(TCP_connection); |
797 | TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED; | 881 | TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; |
798 | } | 882 | } |
799 | } | 883 | } |
800 | } | 884 | } |
801 | 885 | ||
802 | if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) { | 886 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { |
803 | if (send_pending_data(TCP_connection) == 0) { | 887 | if (send_pending_data(TCP_connection) == 0) { |
804 | int ret = socks5_read_connection_response(TCP_connection); | 888 | int ret = proxy_socks5_read_connection_response(TCP_connection); |
805 | 889 | ||
806 | if (ret == -1) { | 890 | if (ret == -1) { |
807 | TCP_connection->kill_at = 0; | 891 | TCP_connection->kill_at = 0; |