From f57f6b32fce9c36d8a76711f415f953e909fbce0 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Tue, 11 Aug 2020 17:30:11 +0200 Subject: [PATCH 1/4] Implement support for HTTP proxies Implement support for HTTP/1.1 proxies using the HTTP CONNECT method. This commit also implements basic authentication using the Proxy-Authorization header. It adds a BHttpProxyClient structure which is based on the BSocksClient implementation. --- blog_channels.txt | 1 + generated/blog_channels_defines.h | 3 +- generated/blog_channels_list.h | 1 + system/BAddr.h | 5 +- tun2socks/BHttpProxyClient.c | 519 ++++++++++++++++++++++++++++++ tun2socks/BHttpProxyClient.h | 152 +++++++++ tun2socks/CMakeLists.txt | 1 + tun2socks/tun2socks.c | 125 +++++-- 8 files changed, 783 insertions(+), 24 deletions(-) create mode 100644 tun2socks/BHttpProxyClient.c create mode 100644 tun2socks/BHttpProxyClient.h diff --git a/blog_channels.txt b/blog_channels.txt index 18657d5eb..cd4037f12 100644 --- a/blog_channels.txt +++ b/blog_channels.txt @@ -146,3 +146,4 @@ BLockReactor 4 ncd_load_module 4 ncd_basic_functions 4 ncd_objref 4 +BHttpProxyClient 4 diff --git a/generated/blog_channels_defines.h b/generated/blog_channels_defines.h index 804c91487..16c0bbaed 100644 --- a/generated/blog_channels_defines.h +++ b/generated/blog_channels_defines.h @@ -146,4 +146,5 @@ #define BLOG_CHANNEL_ncd_load_module 145 #define BLOG_CHANNEL_ncd_basic_functions 146 #define BLOG_CHANNEL_ncd_objref 147 -#define BLOG_NUM_CHANNELS 148 +#define BLOG_CHANNEL_BHttpProxyClient 148 +#define BLOG_NUM_CHANNELS 149 diff --git a/generated/blog_channels_list.h b/generated/blog_channels_list.h index 930bd8b28..5024fa134 100644 --- a/generated/blog_channels_list.h +++ b/generated/blog_channels_list.h @@ -146,3 +146,4 @@ {"ncd_load_module", 4}, {"ncd_basic_functions", 4}, {"ncd_objref", 4}, +{"BHttpProxyClient", 4}, diff --git a/system/BAddr.h b/system/BAddr.h index 70d4fa1a1..b4278911c 100644 --- a/system/BAddr.h +++ b/system/BAddr.h @@ -607,8 +607,9 @@ void BAddr_Print (BAddr *addr, char *out) break; case BADDR_TYPE_IPV6: BIPAddr_InitIPv6(&ipaddr, addr->ipv6.ip); - BIPAddr_Print(&ipaddr, out); - sprintf(out + strlen(out), ":%"PRIu16, ntoh16(addr->ipv6.port)); + out[0] = '['; + BIPAddr_Print(&ipaddr, out + 1); + sprintf(out + strlen(out), "]:%"PRIu16, ntoh16(addr->ipv6.port)); break; #ifdef BADVPN_LINUX case BADDR_TYPE_PACKET: diff --git a/tun2socks/BHttpProxyClient.c b/tun2socks/BHttpProxyClient.c new file mode 100644 index 000000000..5bd743bbb --- /dev/null +++ b/tun2socks/BHttpProxyClient.c @@ -0,0 +1,519 @@ +/** + * + * @file BHttpProxyClient.c + * @author B. Blechschmidt, based on the SocksClient implementation by Ambroz Bizjak + * + * @section LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "BHttpProxyClient.h" + +#include + +#define STATE_CONNECTING 1 +#define STATE_CONNECTED_HANDLER 2 +#define STATE_SENDING_REQUEST 3 +#define STATE_SENT_REQUEST 4 +#define STATE_RECEIVED_REPLY_HEADER 5 +#define STATE_UP 6 + +#define IPV4_STR_LEN 15 +#define IPV6_STR_LEN 39 + +static void report_error (BHttpProxyClient *o, int error); +static void init_control_io (BHttpProxyClient *o); +static void free_control_io (BHttpProxyClient *o); +static void init_up_io (BHttpProxyClient *o); +static void free_up_io (BHttpProxyClient *o); +static int reserve_buffer (BHttpProxyClient *o, bsize_t size); +static void start_receive (BHttpProxyClient *o, uint8_t *dest, int total); +static void do_receive (BHttpProxyClient *o); +static void connector_handler (BHttpProxyClient* o, int is_error); +static void connection_handler (BHttpProxyClient* o, int event); +static void continue_job_handler (BHttpProxyClient *o); +static void recv_handler_done (BHttpProxyClient *o, int data_len); +static void send_handler_done (BHttpProxyClient *o); +static void send_connect (BHttpProxyClient *o); +static void base64_encode(const unsigned char *raw, char *encoded); +static int init_auth(BHttpProxyClient *o, const char *username, const char *password); + +void base64_encode(const unsigned char *raw, char *encoded) +{ + const char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t char_count = 0; + unsigned char chars[3]; + size_t i; + + while(1) { + if (*raw != 0) { + chars[char_count++] = *raw++; + } + if (char_count == 3 || *raw == 0) { + if (char_count == 0) { + break; + } + + for (i = 2; i >= char_count; i--) { + chars[i] = 0; + } + + *encoded++ = alphabet[chars[0] >> 2u]; + *encoded++ = alphabet[(unsigned char)((chars[0] & 0x03u) << 4u) | (unsigned char)(chars[1] >> 4u)]; + *encoded++ = alphabet[(unsigned char)((chars[1] & 0x0Fu) << 2u) | (unsigned char)(chars[2] >> 6u)]; + *encoded++ = alphabet[chars[2] & 0x3Fu]; + + for (i = 0; i < 3 - char_count; i++) { + *(encoded - i - 1) = '='; + } + + if (*raw == 0) { + break; + } + char_count = 0; + } + } + *encoded = '\0'; +} + + +void report_error (BHttpProxyClient *o, int error) +{ + DEBUGERROR(&o->d_err, o->handler(o->user, error)) +} + +void init_control_io (BHttpProxyClient *o) +{ + // init receiving + BConnection_RecvAsync_Init(&o->con); + o->control.recv_if = BConnection_RecvAsync_GetIf(&o->con); + StreamRecvInterface_Receiver_Init(o->control.recv_if, (StreamRecvInterface_handler_done)recv_handler_done, o); + + // init sending + BConnection_SendAsync_Init(&o->con); + PacketStreamSender_Init(&o->control.send_sender, BConnection_SendAsync_GetIf(&o->con), INT_MAX, BReactor_PendingGroup(o->reactor)); + o->control.send_if = PacketStreamSender_GetInput(&o->control.send_sender); + PacketPassInterface_Sender_Init(o->control.send_if, (PacketPassInterface_handler_done)send_handler_done, o); +} + +void free_control_io (BHttpProxyClient *o) +{ + // free sending + PacketStreamSender_Free(&o->control.send_sender); + BConnection_SendAsync_Free(&o->con); + + // free receiving + BConnection_RecvAsync_Free(&o->con); +} + +void init_up_io (BHttpProxyClient *o) +{ + // init receiving + BConnection_RecvAsync_Init(&o->con); + + // init sending + BConnection_SendAsync_Init(&o->con); +} + +void free_up_io (BHttpProxyClient *o) +{ + // free sending + BConnection_SendAsync_Free(&o->con); + + // free receiving + BConnection_RecvAsync_Free(&o->con); +} + +int reserve_buffer (BHttpProxyClient *o, bsize_t size) +{ + if (size.is_overflow) { + BLog(BLOG_ERROR, "size overflow"); + return 0; + } + + char *buffer = (char *)BRealloc(o->buffer, size.value); + if (!buffer) { + BLog(BLOG_ERROR, "BRealloc failed"); + return 0; + } + + o->buffer = buffer; + + return 1; +} + +void start_receive (BHttpProxyClient *o, uint8_t *dest, int total) +{ + ASSERT(total > 0) + + o->control.recv_dest = dest; + o->control.recv_len = 0; + o->control.recv_total = total; + + do_receive(o); +} + +void do_receive (BHttpProxyClient *o) +{ + ASSERT(o->control.recv_len < o->control.recv_total) + + StreamRecvInterface_Receiver_Recv(o->control.recv_if, o->control.recv_dest + o->control.recv_len, o->control.recv_total - o->control.recv_len); +} + +void connector_handler (BHttpProxyClient* o, int is_error) +{ + DebugObject_Access(&o->d_obj); + ASSERT(o->state == STATE_CONNECTING) + + // check connection result + if (is_error) { + BLog(BLOG_ERROR, "connection failed"); + goto fail0; + } + + // init connection + if (!BConnection_Init(&o->con, BConnection_source_connector(&o->connector), o->reactor, o, (BConnection_handler)connection_handler)) { + BLog(BLOG_ERROR, "BConnection_Init failed"); + goto fail0; + } + + BLog(BLOG_DEBUG, "connected"); + + // init control I/O + init_control_io(o); + + // go to STATE_CONNECTED_HANDLER and set the continue job in order to continue + // in continue_job_handler + o->state = STATE_CONNECTED_HANDLER; + BPending_Set(&o->continue_job); + + // call the handler with the connected event + o->handler(o->user, BHTTPPROXYCLIENT_EVENT_CONNECTED); + return; + +fail0: + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR); +} + +void connection_handler (BHttpProxyClient* o, int event) +{ + DebugObject_Access(&o->d_obj); + ASSERT(o->state != STATE_CONNECTING) + + if (o->state == STATE_UP && event == BCONNECTION_EVENT_RECVCLOSED) { + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR_CLOSED); + return; + } + + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR); +} + +void continue_job_handler (BHttpProxyClient *o) +{ + DebugObject_Access(&o->d_obj); + ASSERT(o->state == STATE_CONNECTED_HANDLER) + + send_connect(o); +} + +void recv_handler_done (BHttpProxyClient *o, int data_len) +{ + ASSERT(data_len >= 0) + ASSERT(data_len <= o->control.recv_total - o->control.recv_len) + DebugObject_Access(&o->d_obj); + + o->control.recv_len += data_len; + + if (o->control.recv_len < o->control.recv_total) { + do_receive(o); + return; + } + + switch (o->state) { + case STATE_SENT_REQUEST: { + BLog(BLOG_DEBUG, "received reply header"); + + if (memcmp(o->buffer, "HTTP/1.1 2", sizeof("HTTP/1.1 2") - 1) != 0 || o->buffer[12] != ' ') { + BLog(BLOG_NOTICE, "invalid HTTP response"); + goto fail; + } + + // receive the rest of the reply + start_receive(o, (uint8_t *)o->buffer, 1); + + // set state + o->state = STATE_RECEIVED_REPLY_HEADER; + o->crlf_state = 0; + } break; + + case STATE_RECEIVED_REPLY_HEADER: { + if (o->buffer[0] == '\n') { + o->crlf_state++; + } else if (o->buffer[0] != '\r') { + o->crlf_state = 0; + } + + if (o->crlf_state < 2) { + start_receive(o, (uint8_t *)o->buffer, 1); + return; + } + // free buffer + BFree(o->buffer); + o->buffer = NULL; + + // free control I/O + free_control_io(o); + + // init up I/O + // We anyway don't allow the user to use these interfaces in that case. + init_up_io(o); + + // set state + o->state = STATE_UP; + + // call handler + o->handler(o->user, BHTTPPROXYCLIENT_EVENT_UP); + return; + } + default: + ASSERT(0); + } + + return; + +fail: + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR); +} + +void send_handler_done (BHttpProxyClient *o) +{ + DebugObject_Access(&o->d_obj); + ASSERT(o->buffer) + + switch (o->state) { + case STATE_SENDING_REQUEST: { + BLog(BLOG_DEBUG, "sent request"); + + // allocate buffer for receiving reply + bsize_t size; + size.value = 1024; + size.is_overflow = 0; + if (!reserve_buffer(o, size)) { + goto fail; + } + + // receive reply header + start_receive(o, (uint8_t *)o->buffer, sizeof("HTTP/1.1 200 ") - 1); + + // set state + o->state = STATE_SENT_REQUEST; + } break; + + default: + ASSERT(0); + } + + return; + +fail: + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR); +} + +void send_connect (BHttpProxyClient *o) +{ + ASSERT(o->dest_addr.type = BADDR_TYPE_IPV4 || o->dest_addr.type == BADDR_TYPE_IPV6) + + // allocate request buffer + bsize_t size = bsize_fromsize(sizeof("CONNECT HTTP/1.1\r\nHost: \r\n\r\n")); + size = bsize_add(size, bsize_fromsize(BADDR_MAX_PRINT_LEN)); + size = bsize_add(size, bsize_fromsize(BADDR_MAX_PRINT_LEN)); + if (o->headers) { + size = bsize_add(size, bsize_fromsize(strlen(o->headers))); + } + + if (!reserve_buffer(o, size)) { + report_error(o, BHTTPPROXYCLIENT_EVENT_ERROR); + return; + } + + memcpy(o->buffer, "CONNECT ", sizeof("CONNECT ")); + BAddr_Print(&o->dest_addr, o->buffer + strlen(o->buffer)); + sprintf(o->buffer + strlen(o->buffer), " HTTP/1.1\r\nHost: "); + BAddr_Print(&o->dest_addr, o->buffer + strlen(o->buffer)); + sprintf(o->buffer + strlen(o->buffer), "\r\n%s\r\n", o->headers ? o->headers : ""); + + size = bsize_fromsize(strlen(o->buffer)); + + PacketPassInterface_Sender_Send(o->control.send_if, (uint8_t *)o->buffer, size.value); + + // set state + o->state = STATE_SENDING_REQUEST; +} + +int BHttpProxyClient_Init (BHttpProxyClient *o, BAddr server_addr, + const char *username, const char *password, BAddr dest_addr, + BHttpProxyClient_handler handler, void *user, BReactor *reactor) +{ + ASSERT(!BAddr_IsInvalid(&server_addr)) + + // init arguments + if (!init_auth(o, username, password)) { + BLog(BLOG_ERROR, "Failed to allocate authentication buffer"); + return 0; + } + o->dest_addr = dest_addr; + o->handler = handler; + o->user = user; + o->reactor = reactor; + + // set no buffer + o->buffer = NULL; + + // init continue_job + BPending_Init(&o->continue_job, BReactor_PendingGroup(o->reactor), + (BPending_handler)continue_job_handler, o); + + // init connector + if (!BConnector_Init(&o->connector, server_addr, o->reactor, o, (BConnector_handler)connector_handler)) { + BLog(BLOG_ERROR, "BConnector_Init failed"); + goto fail0; + } + + // set state + o->state = STATE_CONNECTING; + + DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor)); + DebugObject_Init(&o->d_obj); + return 1; + +fail0: + BPending_Free(&o->continue_job); + return 0; +} + +int init_auth(BHttpProxyClient *o, const char *username, const char *password) +{ + o->headers = NULL; + if (username == NULL || password == NULL) { + return 1; + } + + // Allocate buffer holding username:password (plus terminator) + bsize_t auth_buf_size = bsize_fromsize(strlen(username)); + auth_buf_size = bsize_add(auth_buf_size, bsize_fromsize(strlen(password))); + auth_buf_size = bsize_add(auth_buf_size, bsize_fromsize(2)); + if (auth_buf_size.is_overflow) { + return 0; + } + char *auth_buf = BAlloc(auth_buf_size.value); + if (!auth_buf) { + return 0; + } + snprintf(auth_buf, auth_buf_size.value, "%s:%s", username, password); + + bsize_t header_buf_size = auth_buf_size; + // Add one only due to terminator, dividing by 3 afterwards is then equivalent to dividing and ceiling + header_buf_size = bsize_add(header_buf_size, bsize_fromsize(1)); + header_buf_size.value /= 3; + header_buf_size = bsize_mul(header_buf_size, bsize_fromsize(4)); + bsize_t base64_size = header_buf_size; // Space needed for base64: ceil(len('username:password') / 3) * 4 + header_buf_size = bsize_add(header_buf_size, bsize_fromsize(sizeof("Proxy-Authorization: Basic \r\n"))); + printf("%zu", header_buf_size.value); + + if (header_buf_size.is_overflow) { + goto fail_init_auth; + } + + o->headers = BAlloc(header_buf_size.value); + + if (!o->headers) { + goto fail_init_auth; + } + memcpy(o->headers, "Proxy-Authorization: Basic ", sizeof("Proxy-Authorization: Basic ")); + base64_encode((unsigned char*)auth_buf, o->headers + sizeof("Proxy-Authorization: Basic ") - 1); + memcpy(o->headers + sizeof("Proxy-Authorization: Basic ") - 1 + base64_size.value, "\r\n\0", 3); + + BFree(auth_buf); + return 1; + +fail_init_auth: + BFree(auth_buf); + return 0; +} + +void BHttpProxyClient_Free (BHttpProxyClient *o) +{ + DebugObject_Free(&o->d_obj); + DebugError_Free(&o->d_err); + + if (o->state != STATE_CONNECTING) { + if (o->state == STATE_UP) { + // free up I/O + free_up_io(o); + } else { + // free control I/O + free_control_io(o); + } + + // free connection + BConnection_Free(&o->con); + } + + // free connector + BConnector_Free(&o->connector); + + // free continue job + BPending_Free(&o->continue_job); + + // free buffer + if (o->buffer) { + BFree(o->buffer); + } + + if (o->headers) { + BFree(o->headers); + } +} + +StreamPassInterface * BHttpProxyClient_GetSendInterface (BHttpProxyClient *o) +{ + ASSERT(o->state == STATE_UP) + DebugObject_Access(&o->d_obj); + + return BConnection_SendAsync_GetIf(&o->con); +} + +StreamRecvInterface * BHttpProxyClient_GetRecvInterface (BHttpProxyClient *o) +{ + ASSERT(o->state == STATE_UP) + DebugObject_Access(&o->d_obj); + + return BConnection_RecvAsync_GetIf(&o->con); +} diff --git a/tun2socks/BHttpProxyClient.h b/tun2socks/BHttpProxyClient.h new file mode 100644 index 000000000..4fe0305d5 --- /dev/null +++ b/tun2socks/BHttpProxyClient.h @@ -0,0 +1,152 @@ +/** + * @file BHttpProxyClient.h + * @author B. Blechschmidt, based on the SocksClient implementation by Ambroz Bizjak + * + * @section LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + * + * HTTP client. HTTP/1.1 only. Support for basic authorization. + */ + +#ifndef BADVPN_HTTP_BHTTPPROXYCLIENT_H +#define BADVPN_HTTP_BHTTPPROXYCLIENT_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define BHTTPPROXYCLIENT_EVENT_ERROR 1 +#define BHTTPPROXYCLIENT_EVENT_UP 2 +#define BHTTPPROXYCLIENT_EVENT_ERROR_CLOSED 3 +#define BHTTPPROXYCLIENT_EVENT_CONNECTED 4 + +/** + * Handler for events generated by the HTTP client. + * + * The event is one of the following: + * - BHttpProxyClient_EVENT_ERROR: An error has occured. The object must be freed from the + * job closure of the handler and no further I/O must be attempted. + * - BHttpProxyClient_EVENT_ERROR_CLOSED: The server has closed the connection. This event + * can only be reported after BHttpProxyClient_EVENT_UP. The object must be freed from + * the job closure of the handler and no further I/O must be attempted. + * - BHttpProxyClient_EVENT_UP: The CONNECT operation was successful. In + * the case of CONNECT, application I/O may now begin. + * - BHttpProxyClient_EVENT_CONNECTED: The TCP connection to the server has been established + * and the HTTP protocol is about to begin. + * + * @param user as in {@link BHttpProxyClient_Init} + * @param event See above. + */ +typedef void (*BHttpProxyClient_handler) (void *user, int event); + +typedef struct { + BAddr dest_addr; + BAddr bind_addr; + BHttpProxyClient_handler handler; + void *user; + BReactor *reactor; + int state; + int crlf_state; + char *headers; + char *buffer; + BConnector connector; + BConnection con; + BPending continue_job; + union { + struct { + PacketPassInterface *send_if; + PacketStreamSender send_sender; + StreamRecvInterface *recv_if; + uint8_t *recv_dest; + int recv_len; + int recv_total; + } control; + }; + DebugError d_err; + DebugObject d_obj; +} BHttpProxyClient; + +/** + * Initializes the object. + * + * This object connects to a HTTP server and performs a CONNECT + * operation. In any case, the object reports the BHttpProxyClient_EVENT_UP event via the + * handler when the operation was completed successfully. In the case of CONNECT, the + * user may then use the send and receive interfaces to exchange data through the + * connection (@ref BHttpProxyClient_GetSendInterface and @ref BHttpProxyClient_GetRecvInterface). + * + * @param o the object + * @param server_addr HTTP server address + * @param username Username for basic auth through the Proxy-Authorization header. + * @param password Password for basic auth. + * @param dest_addr Address to send as DST.ADDR in the CONNECT or UDP ASSOCIATE request. + * It is also possible to specify it later from the BHttpProxyClient_EVENT_CONNECTED + * event callback using @ref BHttpProxyClient_SetDestAddr; this is necessary for UDP + * if the local TCP connection address must be known to bind the UDP socket. + * @param udp false to perform a CONNECT, true to perform a UDP ASSOCIATE + * @param handler handler for up and error events + * @param user value passed to handler + * @param reactor reactor we live in + * @return 1 on success, 0 on failure + */ +int BHttpProxyClient_Init (BHttpProxyClient *o, BAddr server_addr, + const char *username, const char *password, BAddr dest_addr, + BHttpProxyClient_handler handler, void *user, BReactor *reactor) WARN_UNUSED; + +/** + * Frees the object. + * + * @param o the object + */ +void BHttpProxyClient_Free (BHttpProxyClient *o); + +/** + * Returns the send interface. + * The object must be in up state. + * + * @param o the object + * @return send interface + */ +StreamPassInterface * BHttpProxyClient_GetSendInterface (BHttpProxyClient *o); + +/** + * Returns the receive interface. + * The object must be in up state. + * + * @param o the object + * @return receive interface + */ +StreamRecvInterface * BHttpProxyClient_GetRecvInterface (BHttpProxyClient *o); + +#endif diff --git a/tun2socks/CMakeLists.txt b/tun2socks/CMakeLists.txt index 3d5ec329a..32c42f3eb 100644 --- a/tun2socks/CMakeLists.txt +++ b/tun2socks/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable(badvpn-tun2socks tun2socks.c SocksUdpGwClient.c + BHttpProxyClient.c ) target_link_libraries(badvpn-tun2socks system flow tuntap lwip socksclient udpgw_client socks_udp_client) diff --git a/tun2socks/tun2socks.c b/tun2socks/tun2socks.c index 2f5b2d16b..da00a8647 100644 --- a/tun2socks/tun2socks.c +++ b/tun2socks/tun2socks.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #ifndef BADVPN_USE_WINAPI @@ -92,6 +93,9 @@ BReactor_Synchronize(&ss, &sync_mark.base); \ BPending_Free(&sync_mark); +#define PROTOCOL_SOCKS 1 +#define PROTOCOL_HTTP 2 + // command-line options struct { int help; @@ -107,7 +111,7 @@ struct { char *netif_ipaddr; char *netif_netmask; char *netif_ip6addr; - char *socks_server_addr; + char *server_addr; char *username; char *password; char *password_file; @@ -117,6 +121,7 @@ struct { int udpgw_connection_buffer_size; int udpgw_transparent_dns; int socks5_udp; + int protocol; } options; // TCP client @@ -132,6 +137,7 @@ struct tcp_client { int buf_used; char *socks_username; BSocksClient socks_client; + BHttpProxyClient http_client; int socks_up; int socks_closed; StreamPassInterface *socks_send_if; @@ -153,7 +159,7 @@ BIPAddr netif_netmask; struct ipv6_addr netif_ip6addr; // SOCKS server address -BAddr socks_server_addr; +BAddr server_addr; // allocated password file contents uint8_t *password_file_contents; @@ -245,6 +251,7 @@ static void client_dealloc (struct tcp_client *client); static void client_err_func (void *arg, err_t err); static err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); static void client_socks_handler (struct tcp_client *client, int event); +static void client_http_handler (struct tcp_client *client, int event); static void client_send_to_socks (struct tcp_client *client); static void client_socks_send_handler_done (struct tcp_client *client, int data_len); static void client_socks_recv_initiate (struct tcp_client *client); @@ -385,7 +392,7 @@ int main (int argc, char **argv) // init udpgw client if (!SocksUdpGwClient_Init(&udpgw_client, udp_mtu, DEFAULT_UDPGW_MAX_CONNECTIONS, - options.udpgw_connection_buffer_size, UDPGW_KEEPALIVE_TIME, socks_server_addr, + options.udpgw_connection_buffer_size, UDPGW_KEEPALIVE_TIME, server_addr, socks_auth_info, socks_num_auth_info, udpgw_remote_server_addr, UDPGW_RECONNECT_TIME, &ss, NULL, udp_send_packet_to_device)) { @@ -397,7 +404,7 @@ int main (int argc, char **argv) // init SOCKS UDP client SocksUdpClient_Init(&socks_udp_client, udp_mtu, DEFAULT_UDPGW_MAX_CONNECTIONS, - SOCKS_UDP_SEND_BUFFER_PACKETS, UDPGW_KEEPALIVE_TIME, socks_server_addr, + SOCKS_UDP_SEND_BUFFER_PACKETS, UDPGW_KEEPALIVE_TIME, server_addr, socks_auth_info, socks_num_auth_info, &ss, NULL, udp_send_packet_to_device); } else { udp_mode = UdpModeNone; @@ -527,6 +534,7 @@ void print_help (const char *name) " [--udpgw-connection-buffer-size ]\n" " [--udpgw-transparent-dns]\n" " [--socks5-udp]\n" + " [--http-server-addr ]\n" "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n", name ); @@ -558,7 +566,7 @@ int parse_arguments (int argc, char *argv[]) options.netif_ipaddr = NULL; options.netif_netmask = NULL; options.netif_ip6addr = NULL; - options.socks_server_addr = NULL; + options.server_addr = NULL; options.username = NULL; options.password = NULL; options.password_file = NULL; @@ -568,6 +576,7 @@ int parse_arguments (int argc, char *argv[]) options.udpgw_connection_buffer_size = DEFAULT_UDPGW_CONNECTION_BUFFER_SIZE; options.udpgw_transparent_dns = 0; options.socks5_udp = 0; + options.protocol = PROTOCOL_SOCKS; int i; for (i = 1; i < argc; i++) { @@ -677,12 +686,15 @@ int parse_arguments (int argc, char *argv[]) options.netif_ip6addr = argv[i + 1]; i++; } - else if (!strcmp(arg, "--socks-server-addr")) { + else if (!strcmp(arg, "--socks-server-addr") || !strcmp(arg, "--http-server-addr")) { if (1 >= argc - i) { fprintf(stderr, "%s: requires an argument\n", arg); return 0; } - options.socks_server_addr = argv[i + 1]; + if(!strcmp(arg, "--http-server-addr")) { + options.protocol = PROTOCOL_HTTP; + } + options.server_addr = argv[i + 1]; i++; } else if (!strcmp(arg, "--username")) { @@ -768,8 +780,8 @@ int parse_arguments (int argc, char *argv[]) return 0; } - if (!options.socks_server_addr) { - fprintf(stderr, "--socks-server-addr is required\n"); + if (!options.server_addr) { + fprintf(stderr, "--socks-server-addr or --http-server-addr is required\n"); return 0; } @@ -821,7 +833,7 @@ int process_arguments (void) } // resolve SOCKS server address - if (!BAddr_Parse2(&socks_server_addr, options.socks_server_addr, NULL, 0, 0)) { + if (!BAddr_Parse2(&server_addr, options.server_addr, NULL, 0, 0)) { BLog(BLOG_ERROR, "socks server addr: BAddr_Parse2 failed"); return 0; } @@ -1338,12 +1350,22 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) } // init SOCKS - if (!BSocksClient_Init(&client->socks_client, - socks_server_addr, socks_auth_info, socks_num_auth_info, addr, /*udp=*/false, - (BSocksClient_handler)client_socks_handler, client, &ss)) - { - BLog(BLOG_ERROR, "listener accept: BSocksClient_Init failed"); - goto fail1; + if(options.protocol == PROTOCOL_SOCKS) { + if (!BSocksClient_Init(&client->socks_client, + server_addr, socks_auth_info, socks_num_auth_info, addr, /*udp=*/false, + (BSocksClient_handler)client_socks_handler, client, &ss)) + { + BLog(BLOG_ERROR, "listener accept: BSocksClient_Init failed"); + goto fail1; + } + } else { + if (!BHttpProxyClient_Init(&client->http_client, + server_addr, options.username, options.password, addr, + (BHttpProxyClient_handler)client_http_handler, client, &ss)) + { + BLog(BLOG_ERROR, "listener accept: BHttpProxyClient_Init failed"); + goto fail1; + } } // init aborted and dead_aborted @@ -1476,9 +1498,13 @@ void client_free_socks (struct tcp_client *client) tcp_recv(client->pcb, NULL); } } - - // free SOCKS - BSocksClient_Free(&client->socks_client); + + if(options.protocol == PROTOCOL_SOCKS) { + // free SOCKS + BSocksClient_Free(&client->socks_client); + } else { + BHttpProxyClient_Free(&client->http_client); + } // set SOCKS closed client->socks_closed = 1; @@ -1513,8 +1539,12 @@ void client_murder (struct tcp_client *client) // free SOCKS if (!client->socks_closed) { - // free SOCKS - BSocksClient_Free(&client->socks_client); + if(options.protocol == PROTOCOL_SOCKS) { + // free SOCKS + BSocksClient_Free(&client->socks_client); + } else { + BHttpProxyClient_Free(&client->http_client); + } // set SOCKS closed client->socks_closed = 1; @@ -1657,6 +1687,59 @@ void client_socks_handler (struct tcp_client *client, int event) } } +void client_http_handler (struct tcp_client *client, int event) +{ + ASSERT(!client->socks_closed) + + switch (event) { + case BHTTPPROXYCLIENT_EVENT_ERROR: { + client_log(client, BLOG_INFO, "HTTP error"); + + client_free_socks(client); + } break; + + case BHTTPPROXYCLIENT_EVENT_UP: { + ASSERT(!client->socks_up) + + client_log(client, BLOG_INFO, "HTTP up"); + + // init sending + client->socks_send_if = BHttpProxyClient_GetSendInterface(&client->http_client); + StreamPassInterface_Sender_Init(client->socks_send_if, (StreamPassInterface_handler_done)client_socks_send_handler_done, client); + + // init receiving + client->socks_recv_if = BHttpProxyClient_GetRecvInterface(&client->http_client); + StreamRecvInterface_Receiver_Init(client->socks_recv_if, (StreamRecvInterface_handler_done)client_socks_recv_handler_done, client); + client->socks_recv_buf_used = -1; + client->socks_recv_tcp_pending = 0; + if (!client->client_closed) { + tcp_sent(client->pcb, client_sent_func); + } + + // set up + client->socks_up = 1; + + // start sending data if there is any + if (client->buf_used > 0) { + client_send_to_socks(client); + } + + // start receiving data if client is still up + if (!client->client_closed) { + client_socks_recv_initiate(client); + } + } break; + + case BHTTPPROXYCLIENT_EVENT_ERROR_CLOSED: { + ASSERT(client->socks_up) + + client_log(client, BLOG_INFO, "HTTP closed"); + + client_free_socks(client); + } break; + } +} + void client_send_to_socks (struct tcp_client *client) { ASSERT(!client->socks_closed) From 12975708bf091e5e1626eda132a227682141bb21 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Tue, 11 Aug 2020 18:09:04 +0200 Subject: [PATCH 2/4] Adapt naming which is no longer specific to SOCKS --- tun2socks/tun2socks.c | 266 ++++++++++++++++++++++-------------------- tun2socks/tun2socks.h | 2 +- 2 files changed, 139 insertions(+), 129 deletions(-) diff --git a/tun2socks/tun2socks.c b/tun2socks/tun2socks.c index da00a8647..19b8ec4ae 100644 --- a/tun2socks/tun2socks.c +++ b/tun2socks/tun2socks.c @@ -138,15 +138,15 @@ struct tcp_client { char *socks_username; BSocksClient socks_client; BHttpProxyClient http_client; - int socks_up; - int socks_closed; - StreamPassInterface *socks_send_if; - StreamRecvInterface *socks_recv_if; - uint8_t socks_recv_buf[CLIENT_SOCKS_RECV_BUF_SIZE]; - int socks_recv_buf_used; - int socks_recv_buf_sent; - int socks_recv_waiting; - int socks_recv_tcp_pending; + int proxy_up; + int proxy_closed; + StreamPassInterface *proxy_send_if; + StreamRecvInterface *proxy_recv_if; + uint8_t proxy_recv_buf[CLIENT_PROXY_RECV_BUF_SIZE]; + int proxy_recv_buf_used; + int proxy_recv_buf_sent; + int proxy_recv_waiting; + int proxy_recv_tcp_pending; }; // IP address of netif @@ -158,7 +158,7 @@ BIPAddr netif_netmask; // IP6 address of netif struct ipv6_addr netif_ip6addr; -// SOCKS server address +// SOCKS or HTTP server address BAddr server_addr; // allocated password file contents @@ -168,6 +168,9 @@ uint8_t *password_file_contents; struct BSocksClient_auth_info socks_auth_info[2]; size_t socks_num_auth_info; +// Password +char *password; + // remote udpgw server addr, if provided BAddr udpgw_remote_server_addr; @@ -245,18 +248,18 @@ static void client_handle_freed_client (struct tcp_client *client); static void client_free_client (struct tcp_client *client); static void client_abort_client (struct tcp_client *client); static void client_abort_pcb (struct tcp_client *client); -static void client_free_socks (struct tcp_client *client); +static void client_free_proxy (struct tcp_client *client); static void client_murder (struct tcp_client *client); static void client_dealloc (struct tcp_client *client); static void client_err_func (void *arg, err_t err); static err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); static void client_socks_handler (struct tcp_client *client, int event); static void client_http_handler (struct tcp_client *client, int event); -static void client_send_to_socks (struct tcp_client *client); -static void client_socks_send_handler_done (struct tcp_client *client, int data_len); -static void client_socks_recv_initiate (struct tcp_client *client); -static void client_socks_recv_handler_done (struct tcp_client *client, int data_len); -static int client_socks_recv_send_out (struct tcp_client *client); +static void client_send_to_proxy (struct tcp_client *client); +static void client_proxy_send_handler_done (struct tcp_client *client, int data_len); +static void client_proxy_recv_initiate (struct tcp_client *client); +static void client_proxy_recv_handler_done (struct tcp_client *client, int data_len); +static int client_proxy_recv_send_out (struct tcp_client *client); static err_t client_sent_func (void *arg, struct tcp_pcb *tpcb, u16_t len); static void udp_send_packet_to_device (void *unused, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len); @@ -318,6 +321,9 @@ int main (int argc, char **argv) // clear password contents pointer password_file_contents = NULL; + + // clear password pointer + password = NULL; // initialize network if (!BNetwork_GlobalInit()) { @@ -803,6 +809,7 @@ int parse_arguments (int argc, char *argv[]) int process_arguments (void) { ASSERT(!password_file_contents) + ASSERT(!password) // resolve netif ipaddr if (!BIPAddr_Resolve(&netif_ipaddr, options.netif_ipaddr, 0)) { @@ -832,9 +839,9 @@ int process_arguments (void) } } - // resolve SOCKS server address + // resolve proxy server address if (!BAddr_Parse2(&server_addr, options.server_addr, NULL, 0, 0)) { - BLog(BLOG_ERROR, "socks server addr: BAddr_Parse2 failed"); + BLog(BLOG_ERROR, "proxy server addr: BAddr_Parse2 failed"); return 0; } @@ -844,7 +851,6 @@ int process_arguments (void) // add password socks authentication method if (options.username) { - const char *password; size_t password_len; if (options.password) { password = options.password; @@ -1360,7 +1366,7 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) } } else { if (!BHttpProxyClient_Init(&client->http_client, - server_addr, options.username, options.password, addr, + server_addr, options.username, password, addr, (BHttpProxyClient_handler)client_http_handler, client, &ss)) { BLog(BLOG_ERROR, "listener accept: BHttpProxyClient_Init failed"); @@ -1395,9 +1401,9 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) // setup buffer client->buf_used = 0; - // set SOCKS not up, not closed - client->socks_up = 0; - client->socks_closed = 0; + // set proxy not up, not closed + client->proxy_up = 0; + client->proxy_closed = 0; client_log(client, BLOG_INFO, "accepted"); @@ -1425,12 +1431,12 @@ void client_handle_freed_client (struct tcp_client *client) // set client closed client->client_closed = 1; - // if we have data to be sent to SOCKS and can send it, keep sending - if (client->buf_used > 0 && !client->socks_closed) { - client_log(client, BLOG_INFO, "waiting untill buffered data is sent to SOCKS"); + // if we have data to be sent to proxy and can send it, keep sending + if (client->buf_used > 0 && !client->proxy_closed) { + client_log(client, BLOG_INFO, "waiting untill buffered data is sent to proxy"); } else { - if (!client->socks_closed) { - client_free_socks(client); + if (!client->proxy_closed) { + client_free_proxy(client); } else { client_dealloc(client); } @@ -1487,12 +1493,12 @@ void client_abort_pcb (struct tcp_client *client) DEAD_KILL_WITH(client->dead_aborted, 1); } -void client_free_socks (struct tcp_client *client) +void client_free_proxy (struct tcp_client *client) { - ASSERT(!client->socks_closed) + ASSERT(!client->proxy_closed) - // stop sending to SOCKS - if (client->socks_up) { + // stop sending to proxy + if (client->proxy_up) { // stop receiving from client if (!client->client_closed) { tcp_recv(client->pcb, NULL); @@ -1506,11 +1512,11 @@ void client_free_socks (struct tcp_client *client) BHttpProxyClient_Free(&client->http_client); } - // set SOCKS closed - client->socks_closed = 1; + // set proxy closed + client->proxy_closed = 1; // if we have data to be sent to the client and we can send it, keep sending - if (client->socks_up && (client->socks_recv_buf_used >= 0 || client->socks_recv_tcp_pending > 0) && !client->client_closed) { + if (client->proxy_up && (client->proxy_recv_buf_used >= 0 || client->proxy_recv_tcp_pending > 0) && !client->client_closed) { client_log(client, BLOG_INFO, "waiting until buffered data is sent to client"); } else { if (!client->client_closed) { @@ -1537,8 +1543,8 @@ void client_murder (struct tcp_client *client) client->client_closed = 1; } - // free SOCKS - if (!client->socks_closed) { + // free proxy + if (!client->proxy_closed) { if(options.protocol == PROTOCOL_SOCKS) { // free SOCKS BSocksClient_Free(&client->socks_client); @@ -1546,8 +1552,8 @@ void client_murder (struct tcp_client *client) BHttpProxyClient_Free(&client->http_client); } - // set SOCKS closed - client->socks_closed = 1; + // set proxy closed + client->proxy_closed = 1; } // dealloc entry @@ -1557,7 +1563,7 @@ void client_murder (struct tcp_client *client) void client_dealloc (struct tcp_client *client) { ASSERT(client->client_closed) - ASSERT(client->socks_closed) + ASSERT(client->proxy_closed) // decrement counter ASSERT(num_clients > 0) @@ -1617,13 +1623,13 @@ err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t e int p_tot_len = p->tot_len; pbuf_free(p); - // if there was nothing in the buffer before, and SOCKS is up, start send data - if (client->buf_used == p_tot_len && client->socks_up) { - ASSERT(!client->socks_closed) // this callback is removed when SOCKS is closed + // if there was nothing in the buffer before, and proxy is up, start send data + if (client->buf_used == p_tot_len && client->proxy_up) { + ASSERT(!client->proxy_closed) // this callback is removed when proxy is closed SYNC_DECL SYNC_FROMHERE - client_send_to_socks(client); + client_send_to_proxy(client); SYNC_COMMIT } } @@ -1636,124 +1642,128 @@ err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t e void client_socks_handler (struct tcp_client *client, int event) { - ASSERT(!client->socks_closed) + ASSERT(!client->proxy_closed) switch (event) { case BSOCKSCLIENT_EVENT_ERROR: { client_log(client, BLOG_INFO, "SOCKS error"); - - client_free_socks(client); + + client_free_proxy(client); } break; case BSOCKSCLIENT_EVENT_UP: { - ASSERT(!client->socks_up) + ASSERT(!client->proxy_up) client_log(client, BLOG_INFO, "SOCKS up"); // init sending - client->socks_send_if = BSocksClient_GetSendInterface(&client->socks_client); - StreamPassInterface_Sender_Init(client->socks_send_if, (StreamPassInterface_handler_done)client_socks_send_handler_done, client); + client->proxy_send_if = BSocksClient_GetSendInterface(&client->socks_client); + StreamPassInterface_Sender_Init(client->proxy_send_if, + (StreamPassInterface_handler_done) client_proxy_send_handler_done, client); // init receiving - client->socks_recv_if = BSocksClient_GetRecvInterface(&client->socks_client); - StreamRecvInterface_Receiver_Init(client->socks_recv_if, (StreamRecvInterface_handler_done)client_socks_recv_handler_done, client); - client->socks_recv_buf_used = -1; - client->socks_recv_tcp_pending = 0; + client->proxy_recv_if = BSocksClient_GetRecvInterface(&client->socks_client); + StreamRecvInterface_Receiver_Init(client->proxy_recv_if, + (StreamRecvInterface_handler_done) client_proxy_recv_handler_done, client); + client->proxy_recv_buf_used = -1; + client->proxy_recv_tcp_pending = 0; if (!client->client_closed) { tcp_sent(client->pcb, client_sent_func); } // set up - client->socks_up = 1; + client->proxy_up = 1; // start sending data if there is any if (client->buf_used > 0) { - client_send_to_socks(client); + client_send_to_proxy(client); } // start receiving data if client is still up if (!client->client_closed) { - client_socks_recv_initiate(client); + client_proxy_recv_initiate(client); } } break; case BSOCKSCLIENT_EVENT_ERROR_CLOSED: { - ASSERT(client->socks_up) + ASSERT(client->proxy_up) client_log(client, BLOG_INFO, "SOCKS closed"); - - client_free_socks(client); + + client_free_proxy(client); } break; } } void client_http_handler (struct tcp_client *client, int event) { - ASSERT(!client->socks_closed) + ASSERT(!client->proxy_closed) switch (event) { case BHTTPPROXYCLIENT_EVENT_ERROR: { client_log(client, BLOG_INFO, "HTTP error"); - client_free_socks(client); + client_free_proxy(client); } break; case BHTTPPROXYCLIENT_EVENT_UP: { - ASSERT(!client->socks_up) + ASSERT(!client->proxy_up) client_log(client, BLOG_INFO, "HTTP up"); // init sending - client->socks_send_if = BHttpProxyClient_GetSendInterface(&client->http_client); - StreamPassInterface_Sender_Init(client->socks_send_if, (StreamPassInterface_handler_done)client_socks_send_handler_done, client); + client->proxy_send_if = BHttpProxyClient_GetSendInterface(&client->http_client); + StreamPassInterface_Sender_Init(client->proxy_send_if, + (StreamPassInterface_handler_done) client_proxy_send_handler_done, client); // init receiving - client->socks_recv_if = BHttpProxyClient_GetRecvInterface(&client->http_client); - StreamRecvInterface_Receiver_Init(client->socks_recv_if, (StreamRecvInterface_handler_done)client_socks_recv_handler_done, client); - client->socks_recv_buf_used = -1; - client->socks_recv_tcp_pending = 0; + client->proxy_recv_if = BHttpProxyClient_GetRecvInterface(&client->http_client); + StreamRecvInterface_Receiver_Init(client->proxy_recv_if, + (StreamRecvInterface_handler_done) client_proxy_recv_handler_done, client); + client->proxy_recv_buf_used = -1; + client->proxy_recv_tcp_pending = 0; if (!client->client_closed) { tcp_sent(client->pcb, client_sent_func); } // set up - client->socks_up = 1; + client->proxy_up = 1; // start sending data if there is any if (client->buf_used > 0) { - client_send_to_socks(client); + client_send_to_proxy(client); } // start receiving data if client is still up if (!client->client_closed) { - client_socks_recv_initiate(client); + client_proxy_recv_initiate(client); } } break; case BHTTPPROXYCLIENT_EVENT_ERROR_CLOSED: { - ASSERT(client->socks_up) + ASSERT(client->proxy_up) client_log(client, BLOG_INFO, "HTTP closed"); - client_free_socks(client); + client_free_proxy(client); } break; } } -void client_send_to_socks (struct tcp_client *client) +void client_send_to_proxy (struct tcp_client *client) { - ASSERT(!client->socks_closed) - ASSERT(client->socks_up) + ASSERT(!client->proxy_closed) + ASSERT(client->proxy_up) ASSERT(client->buf_used > 0) // schedule sending - StreamPassInterface_Sender_Send(client->socks_send_if, client->buf, client->buf_used); + StreamPassInterface_Sender_Send(client->proxy_send_if, client->buf, client->buf_used); } -void client_socks_send_handler_done (struct tcp_client *client, int data_len) +void client_proxy_send_handler_done (struct tcp_client *client, int data_len) { - ASSERT(!client->socks_closed) - ASSERT(client->socks_up) + ASSERT(!client->proxy_closed) + ASSERT(client->proxy_up) ASSERT(client->buf_used > 0) ASSERT(data_len > 0) ASSERT(data_len <= client->buf_used) @@ -1769,33 +1779,33 @@ void client_socks_send_handler_done (struct tcp_client *client, int data_len) if (client->buf_used > 0) { // send any further data - StreamPassInterface_Sender_Send(client->socks_send_if, client->buf, client->buf_used); + StreamPassInterface_Sender_Send(client->proxy_send_if, client->buf, client->buf_used); } else if (client->client_closed) { // client was closed we've sent everything we had buffered; we're done with it client_log(client, BLOG_INFO, "removing after client went down"); - - client_free_socks(client); + + client_free_proxy(client); } } -void client_socks_recv_initiate (struct tcp_client *client) +void client_proxy_recv_initiate (struct tcp_client *client) { ASSERT(!client->client_closed) - ASSERT(!client->socks_closed) - ASSERT(client->socks_up) - ASSERT(client->socks_recv_buf_used == -1) + ASSERT(!client->proxy_closed) + ASSERT(client->proxy_up) + ASSERT(client->proxy_recv_buf_used == -1) - StreamRecvInterface_Receiver_Recv(client->socks_recv_if, client->socks_recv_buf, sizeof(client->socks_recv_buf)); + StreamRecvInterface_Receiver_Recv(client->proxy_recv_if, client->proxy_recv_buf, sizeof(client->proxy_recv_buf)); } -void client_socks_recv_handler_done (struct tcp_client *client, int data_len) +void client_proxy_recv_handler_done (struct tcp_client *client, int data_len) { ASSERT(data_len > 0) - ASSERT(data_len <= sizeof(client->socks_recv_buf)) - ASSERT(!client->socks_closed) - ASSERT(client->socks_up) - ASSERT(client->socks_recv_buf_used == -1) + ASSERT(data_len <= sizeof(client->proxy_recv_buf)) + ASSERT(!client->proxy_closed) + ASSERT(client->proxy_up) + ASSERT(client->proxy_recv_buf_used == -1) // if client was closed, stop receiving if (client->client_closed) { @@ -1803,39 +1813,39 @@ void client_socks_recv_handler_done (struct tcp_client *client, int data_len) } // set amount of data in buffer - client->socks_recv_buf_used = data_len; - client->socks_recv_buf_sent = 0; - client->socks_recv_waiting = 0; + client->proxy_recv_buf_used = data_len; + client->proxy_recv_buf_sent = 0; + client->proxy_recv_waiting = 0; // send to client - if (client_socks_recv_send_out(client) < 0) { + if (client_proxy_recv_send_out(client) < 0) { return; } // continue receiving if needed - if (client->socks_recv_buf_used == -1) { - client_socks_recv_initiate(client); + if (client->proxy_recv_buf_used == -1) { + client_proxy_recv_initiate(client); } } -int client_socks_recv_send_out (struct tcp_client *client) +int client_proxy_recv_send_out (struct tcp_client *client) { ASSERT(!client->client_closed) - ASSERT(client->socks_up) - ASSERT(client->socks_recv_buf_used > 0) - ASSERT(client->socks_recv_buf_sent < client->socks_recv_buf_used) - ASSERT(!client->socks_recv_waiting) + ASSERT(client->proxy_up) + ASSERT(client->proxy_recv_buf_used > 0) + ASSERT(client->proxy_recv_buf_sent < client->proxy_recv_buf_used) + ASSERT(!client->proxy_recv_waiting) // return value -1 means tcp_abort() was done, // 0 means it wasn't and the client (pcb) is still up do { - int to_write = bmin_int(client->socks_recv_buf_used - client->socks_recv_buf_sent, tcp_sndbuf(client->pcb)); + int to_write = bmin_int(client->proxy_recv_buf_used - client->proxy_recv_buf_sent, tcp_sndbuf(client->pcb)); if (to_write == 0) { break; } - err_t err = tcp_write(client->pcb, client->socks_recv_buf + client->socks_recv_buf_sent, to_write, TCP_WRITE_FLAG_COPY); + err_t err = tcp_write(client->pcb, client->proxy_recv_buf + client->proxy_recv_buf_sent, to_write, TCP_WRITE_FLAG_COPY); if (err != ERR_OK) { if (err == ERR_MEM) { break; @@ -1847,9 +1857,9 @@ int client_socks_recv_send_out (struct tcp_client *client) return -1; } - client->socks_recv_buf_sent += to_write; - client->socks_recv_tcp_pending += to_write; - } while (client->socks_recv_buf_sent < client->socks_recv_buf_used); + client->proxy_recv_buf_sent += to_write; + client->proxy_recv_tcp_pending += to_write; + } while (client->proxy_recv_buf_sent < client->proxy_recv_buf_used); // start sending now err_t err = tcp_output(client->pcb); @@ -1861,8 +1871,8 @@ int client_socks_recv_send_out (struct tcp_client *client) } // more data to queue? - if (client->socks_recv_buf_sent < client->socks_recv_buf_used) { - if (client->socks_recv_tcp_pending == 0) { + if (client->proxy_recv_buf_sent < client->proxy_recv_buf_used) { + if (client->proxy_recv_tcp_pending == 0) { client_log(client, BLOG_ERROR, "can't queue data, but all data was confirmed !?!"); client_abort_client(client); @@ -1870,12 +1880,12 @@ int client_socks_recv_send_out (struct tcp_client *client) } // set waiting, continue in client_sent_func - client->socks_recv_waiting = 1; + client->proxy_recv_waiting = 1; return 0; } // everything was queued - client->socks_recv_buf_used = -1; + client->proxy_recv_buf_used = -1; return 0; } @@ -1885,42 +1895,42 @@ err_t client_sent_func (void *arg, struct tcp_pcb *tpcb, u16_t len) struct tcp_client *client = (struct tcp_client *)arg; ASSERT(!client->client_closed) - ASSERT(client->socks_up) + ASSERT(client->proxy_up) ASSERT(len > 0) - ASSERT(len <= client->socks_recv_tcp_pending) + ASSERT(len <= client->proxy_recv_tcp_pending) DEAD_ENTER(client->dead_aborted) // decrement pending - client->socks_recv_tcp_pending -= len; + client->proxy_recv_tcp_pending -= len; // continue queuing - if (client->socks_recv_buf_used > 0) { - ASSERT(client->socks_recv_waiting) - ASSERT(client->socks_recv_buf_sent < client->socks_recv_buf_used) + if (client->proxy_recv_buf_used > 0) { + ASSERT(client->proxy_recv_waiting) + ASSERT(client->proxy_recv_buf_sent < client->proxy_recv_buf_used) // set not waiting - client->socks_recv_waiting = 0; + client->proxy_recv_waiting = 0; // possibly send more data - if (client_socks_recv_send_out(client) < 0) { + if (client_proxy_recv_send_out(client) < 0) { goto out; } // we just queued some data, so it can't have been confirmed yet - ASSERT(client->socks_recv_tcp_pending > 0) + ASSERT(client->proxy_recv_tcp_pending > 0) // continue receiving if needed - if (client->socks_recv_buf_used == -1 && !client->socks_closed) { + if (client->proxy_recv_buf_used == -1 && !client->proxy_closed) { SYNC_DECL SYNC_FROMHERE - client_socks_recv_initiate(client); + client_proxy_recv_initiate(client); SYNC_COMMIT } } else { - // have we sent everything after SOCKS was closed? - if (client->socks_closed && client->socks_recv_tcp_pending == 0) { - client_log(client, BLOG_INFO, "removing after SOCKS went down"); + // have we sent everything after proxy was closed? + if (client->proxy_closed && client->proxy_recv_tcp_pending == 0) { + client_log(client, BLOG_INFO, "removing after proxy went down"); client_free_client(client); } } diff --git a/tun2socks/tun2socks.h b/tun2socks/tun2socks.h index 27d412949..146b6c7d4 100644 --- a/tun2socks/tun2socks.h +++ b/tun2socks/tun2socks.h @@ -28,7 +28,7 @@ #define PROGRAM_NAME "tun2socks" // size of temporary buffer for passing data from the SOCKS server to TCP for sending -#define CLIENT_SOCKS_RECV_BUF_SIZE 8192 +#define CLIENT_PROXY_RECV_BUF_SIZE 8192 // maximum number of udpgw connections #define DEFAULT_UDPGW_MAX_CONNECTIONS 256 From 4448e82b645a16d88824cc6d458fb8524c4b83c2 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Tue, 11 Aug 2020 18:27:38 +0200 Subject: [PATCH 3/4] Notify user that --append-source-to-username is only supported for SOCKS --- tun2socks/tun2socks.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tun2socks/tun2socks.c b/tun2socks/tun2socks.c index 19b8ec4ae..e4149b6d1 100644 --- a/tun2socks/tun2socks.c +++ b/tun2socks/tun2socks.c @@ -802,6 +802,11 @@ int parse_arguments (int argc, char *argv[]) return 0; } } + + if (options.append_source_to_username && options.protocol != PROTOCOL_SOCKS) { + fprintf(stderr, "--append-source-to-username is only supported for SOCKS\n"); + return 0; + } return 1; } From 5cd80be850b828046ecfd0e1a13eda2eb6cb55d2 Mon Sep 17 00:00:00 2001 From: "B. Blechschmidt" Date: Tue, 11 Aug 2020 20:44:37 +0200 Subject: [PATCH 4/4] Add generated BLog channel file for BHttpProxyClient --- generated/blog_channel_BHttpProxyClient.h | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 generated/blog_channel_BHttpProxyClient.h diff --git a/generated/blog_channel_BHttpProxyClient.h b/generated/blog_channel_BHttpProxyClient.h new file mode 100644 index 000000000..8d6f15974 --- /dev/null +++ b/generated/blog_channel_BHttpProxyClient.h @@ -0,0 +1,4 @@ +#ifdef BLOG_CURRENT_CHANNEL +#undef BLOG_CURRENT_CHANNEL +#endif +#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_BHttpProxyClient