diff options
Diffstat (limited to 'toxcore')
-rw-r--r-- | toxcore/TCP_client.c | 101 | ||||
-rw-r--r-- | toxcore/TCP_client.h | 6 | ||||
-rw-r--r-- | toxcore/network.c | 35 | ||||
-rw-r--r-- | toxcore/network.h | 20 | ||||
-rw-r--r-- | toxcore/tox.c | 1 | ||||
-rw-r--r-- | toxcore/tox.h | 1 |
6 files changed, 151 insertions, 13 deletions
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 23ab28c0..dfb4005c 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c | |||
@@ -66,8 +66,67 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_i | |||
66 | return 1; | 66 | return 1; |
67 | } | 67 | } |
68 | 68 | ||
69 | /* return 1 on success. | ||
70 | * return 0 on failure. | ||
71 | */ | ||
72 | static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) | ||
73 | { | ||
74 | char one[] = "CONNECT "; | ||
75 | char two[] = " HTTP/1.1\nHost: "; | ||
76 | char three[] = "\r\n\r\n"; | ||
77 | |||
78 | char ip[INET6_ADDRSTRLEN]; | ||
79 | if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { | ||
80 | return 0; | ||
81 | } | ||
82 | const uint16_t port = ntohs(TCP_conn->ip_port.port); | ||
83 | const int written = sprintf(TCP_conn->last_packet, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, ip, port, three); | ||
84 | if (written < 0) { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | TCP_conn->last_packet_length = written; | ||
89 | TCP_conn->last_packet_sent = 0; | ||
90 | |||
91 | return 1; | ||
92 | } | ||
69 | 93 | ||
70 | static void socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | 94 | /* return 1 on success. |
95 | * return 0 if no data received. | ||
96 | * return -1 on failure (connection refused). | ||
97 | */ | ||
98 | static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) | ||
99 | { | ||
100 | char success[] = "200"; | ||
101 | uint8_t data[16]; // draining works the best if the length is a power of 2 | ||
102 | |||
103 | int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); | ||
104 | |||
105 | if (ret == -1) { | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | data[sizeof(data) - 1] = '\0'; | ||
110 | |||
111 | if (strstr(data, success)) { | ||
112 | // drain all data | ||
113 | // instead of drainining it byte by byte do it in bigger chunks | ||
114 | // decrementing to 1 | ||
115 | size_t step = sizeof(data); | ||
116 | do { | ||
117 | if (ret <= 0) { | ||
118 | step = step % 2 == 0 ? step/2 : 1; | ||
119 | } | ||
120 | ret = read_TCP_packet(TCP_conn->sock, data, step); | ||
121 | } while (ret > 0 || step != 1); | ||
122 | |||
123 | return 1; | ||
124 | } | ||
125 | |||
126 | return -1; | ||
127 | } | ||
128 | |||
129 | static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn) | ||
71 | { | 130 | { |
72 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 131 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
73 | TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ | 132 | TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ |
@@ -95,7 +154,7 @@ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) | |||
95 | return -1; | 154 | return -1; |
96 | } | 155 | } |
97 | 156 | ||
98 | static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) | 157 | static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) |
99 | { | 158 | { |
100 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ | 159 | TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ |
101 | TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ | 160 | TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ |
@@ -125,7 +184,7 @@ static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) | |||
125 | * return 0 if no data received. | 184 | * return 0 if no data received. |
126 | * return -1 on failure (connection refused). | 185 | * return -1 on failure (connection refused). |
127 | */ | 186 | */ |
128 | static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) | 187 | static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn) |
129 | { | 188 | { |
130 | if (TCP_conn->ip_port.ip.family == AF_INET) { | 189 | if (TCP_conn->ip_port.ip.family == AF_INET) { |
131 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; | 190 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; |
@@ -578,10 +637,14 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public | |||
578 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); | 637 | encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); |
579 | temp->ip_port = ip_port; | 638 | temp->ip_port = ip_port; |
580 | 639 | ||
581 | if (proxy_info) { | 640 | if (proxy_info && proxy_info->is_http) { |
582 | temp->status = TCP_CLIENT_PROXY_CONNECTING; | 641 | temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; |
642 | temp->proxy_info = *proxy_info; | ||
643 | proxy_http_generate_connection_request(temp); | ||
644 | } else if (proxy_info && !proxy_info->is_http) { | ||
645 | temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; | ||
583 | temp->proxy_info = *proxy_info; | 646 | temp->proxy_info = *proxy_info; |
584 | socks5_generate_handshake(temp); | 647 | proxy_socks5_generate_handshake(temp); |
585 | } else { | 648 | } else { |
586 | temp->status = TCP_CLIENT_CONNECTING; | 649 | temp->status = TCP_CLIENT_CONNECTING; |
587 | 650 | ||
@@ -783,7 +846,23 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
783 | return; | 846 | return; |
784 | } | 847 | } |
785 | 848 | ||
786 | if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) { | 849 | if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { |
850 | if (send_pending_data(TCP_connection) == 0) { | ||
851 | int ret = proxy_http_read_connection_response(TCP_connection); | ||
852 | |||
853 | if (ret == -1) { | ||
854 | TCP_connection->kill_at = 0; | ||
855 | TCP_connection->status = TCP_CLIENT_DISCONNECTED; | ||
856 | } | ||
857 | |||
858 | if (ret == 1) { | ||
859 | generate_handshake(TCP_connection); | ||
860 | TCP_connection->status = TCP_CLIENT_CONNECTING; | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | |||
865 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { | ||
787 | if (send_pending_data(TCP_connection) == 0) { | 866 | if (send_pending_data(TCP_connection) == 0) { |
788 | int ret = socks5_read_handshake_response(TCP_connection); | 867 | int ret = socks5_read_handshake_response(TCP_connection); |
789 | 868 | ||
@@ -793,15 +872,15 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) | |||
793 | } | 872 | } |
794 | 873 | ||
795 | if (ret == 1) { | 874 | if (ret == 1) { |
796 | socks5_generate_connection_request(TCP_connection); | 875 | proxy_socks5_generate_connection_request(TCP_connection); |
797 | TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED; | 876 | TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; |
798 | } | 877 | } |
799 | } | 878 | } |
800 | } | 879 | } |
801 | 880 | ||
802 | if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) { | 881 | if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { |
803 | if (send_pending_data(TCP_connection) == 0) { | 882 | if (send_pending_data(TCP_connection) == 0) { |
804 | int ret = socks5_read_connection_response(TCP_connection); | 883 | int ret = proxy_socks5_read_connection_response(TCP_connection); |
805 | 884 | ||
806 | if (ret == -1) { | 885 | if (ret == -1) { |
807 | TCP_connection->kill_at = 0; | 886 | TCP_connection->kill_at = 0; |
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index 83cb48ba..8a1aeec1 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h | |||
@@ -31,12 +31,14 @@ | |||
31 | 31 | ||
32 | typedef struct { | 32 | typedef struct { |
33 | IP_Port ip_port; | 33 | IP_Port ip_port; |
34 | int is_http; /* HTTP proxy on true, SOCKS5 on false */ | ||
34 | } TCP_Proxy_Info; | 35 | } TCP_Proxy_Info; |
35 | 36 | ||
36 | enum { | 37 | enum { |
37 | TCP_CLIENT_NO_STATUS, | 38 | TCP_CLIENT_NO_STATUS, |
38 | TCP_CLIENT_PROXY_CONNECTING, | 39 | TCP_CLIENT_PROXY_HTTP_CONNECTING, |
39 | TCP_CLIENT_PROXY_UNCONFIRMED, | 40 | TCP_CLIENT_PROXY_SOCKS5_CONNECTING, |
41 | TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED, | ||
40 | TCP_CLIENT_CONNECTING, | 42 | TCP_CLIENT_CONNECTING, |
41 | TCP_CLIENT_UNCONFIRMED, | 43 | TCP_CLIENT_UNCONFIRMED, |
42 | TCP_CLIENT_CONFIRMED, | 44 | TCP_CLIENT_CONFIRMED, |
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) | |||
784 | /* ip_ntoa | 784 | /* ip_ntoa |
785 | * converts ip into a string | 785 | * converts ip into a string |
786 | * uses a static buffer, so mustn't used multiple times in the same output | 786 | * uses a static buffer, so mustn't used multiple times in the same output |
787 | * | ||
788 | * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" | ||
789 | * writes error message into the buffer on error | ||
787 | */ | 790 | */ |
788 | /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ | 791 | /* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ |
789 | static char addresstext[96]; | 792 | static char addresstext[96]; |
@@ -816,6 +819,38 @@ const char *ip_ntoa(const IP *ip) | |||
816 | } | 819 | } |
817 | 820 | ||
818 | /* | 821 | /* |
822 | * ip_parse_addr | ||
823 | * parses IP structure into an address string | ||
824 | * | ||
825 | * input | ||
826 | * ip: ip of AF_INET or AF_INET6 families | ||
827 | * length: length of the address buffer | ||
828 | * Must be at least INET_ADDRSTRLEN for AF_INET | ||
829 | * and INET6_ADDRSTRLEN for AF_INET6 | ||
830 | * | ||
831 | * output | ||
832 | * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) | ||
833 | * | ||
834 | * returns 1 on success, 0 on failure | ||
835 | */ | ||
836 | int ip_parse_addr(const IP *ip, char *address, size_t length) | ||
837 | { | ||
838 | if (!address || !ip) { | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | if (ip->family == AF_INET) { | ||
843 | struct in_addr *addr = (struct in_addr *)&ip->ip4; | ||
844 | return inet_ntop(ip->family, addr, address, length) != NULL; | ||
845 | } else if (ip->family == AF_INET6) { | ||
846 | struct in6_addr *addr = (struct in6_addr *)&ip->ip6; | ||
847 | return inet_ntop(ip->family, addr, address, length) != NULL; | ||
848 | } | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | /* | ||
819 | * addr_parse_ip | 854 | * addr_parse_ip |
820 | * directly parses the input into an IP structure | 855 | * directly parses the input into an IP structure |
821 | * tries IPv4 first, then IPv6 | 856 | * tries IPv4 first, then IPv6 |
diff --git a/toxcore/network.h b/toxcore/network.h index ccda7ae9..5f9af490 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -180,10 +180,30 @@ IP_Port; | |||
180 | /* ip_ntoa | 180 | /* ip_ntoa |
181 | * converts ip into a string | 181 | * converts ip into a string |
182 | * uses a static buffer, so mustn't used multiple times in the same output | 182 | * uses a static buffer, so mustn't used multiple times in the same output |
183 | * | ||
184 | * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" | ||
185 | * writes error message into the buffer on error | ||
183 | */ | 186 | */ |
184 | const char *ip_ntoa(const IP *ip); | 187 | const char *ip_ntoa(const IP *ip); |
185 | 188 | ||
186 | /* | 189 | /* |
190 | * ip_parse_addr | ||
191 | * parses IP structure into an address string | ||
192 | * | ||
193 | * input | ||
194 | * ip: ip of AF_INET or AF_INET6 families | ||
195 | * length: length of the address buffer | ||
196 | * Must be at least INET_ADDRSTRLEN for AF_INET | ||
197 | * and INET6_ADDRSTRLEN for AF_INET6 | ||
198 | * | ||
199 | * output | ||
200 | * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) | ||
201 | * | ||
202 | * returns 1 on success, 0 on failure | ||
203 | */ | ||
204 | int ip_parse_addr(const IP *ip, char *address, size_t length); | ||
205 | |||
206 | /* | ||
187 | * addr_parse_ip | 207 | * addr_parse_ip |
188 | * directly parses the input into an IP structure | 208 | * directly parses the input into an IP structure |
189 | * tries IPv4 first, then IPv6 | 209 | * tries IPv4 first, then IPv6 |
diff --git a/toxcore/tox.c b/toxcore/tox.c index 66587011..3f3a05b0 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -1021,6 +1021,7 @@ Tox *tox_new(Tox_Options *options) | |||
1021 | m_options.ipv6enabled = options->ipv6enabled; | 1021 | m_options.ipv6enabled = options->ipv6enabled; |
1022 | m_options.udp_disabled = options->udp_disabled; | 1022 | m_options.udp_disabled = options->udp_disabled; |
1023 | m_options.proxy_enabled = options->proxy_enabled; | 1023 | m_options.proxy_enabled = options->proxy_enabled; |
1024 | m_options.proxy_info.is_http = options->proxy_is_http; | ||
1024 | 1025 | ||
1025 | if (m_options.proxy_enabled) { | 1026 | if (m_options.proxy_enabled) { |
1026 | ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); | 1027 | ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); |
diff --git a/toxcore/tox.h b/toxcore/tox.h index 3b72eede..f2c102ab 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -892,6 +892,7 @@ typedef struct { | |||
892 | uint8_t proxy_enabled; | 892 | uint8_t proxy_enabled; |
893 | char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */ | 893 | char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */ |
894 | uint16_t proxy_port; /* Proxy port: in host byte order. */ | 894 | uint16_t proxy_port; /* Proxy port: in host byte order. */ |
895 | uint8_t proxy_is_http; /*1: HTTP proxy, 0: SOCKS5 proxy*/ | ||
895 | } Tox_Options; | 896 | } Tox_Options; |
896 | 897 | ||
897 | /* | 898 | /* |