diff options
author | Maxim Biro <nurupo.contributions@gmail.com> | 2014-12-13 23:44:51 -0500 |
---|---|---|
committer | Maxim Biro <nurupo.contributions@gmail.com> | 2014-12-13 23:59:50 -0500 |
commit | 377da127a1e19f96f75da8b4c59eee6a947cab3b (patch) | |
tree | a09251ab4f14dddc2f31e35f832aed2392a36db4 /toxcore/TCP_client.c | |
parent | 7d4489b8724edd929189c7b7f2a9a32b28429c48 (diff) |
Added HTTP proxy support
Diffstat (limited to 'toxcore/TCP_client.c')
-rw-r--r-- | toxcore/TCP_client.c | 101 |
1 files changed, 90 insertions, 11 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; |