From e05cce39ec6b2dd7dfb6d4896d9dfd04020c0784 Mon Sep 17 00:00:00 2001 From: hnkeyang Date: Thu, 16 Jan 2025 22:11:30 +0800 Subject: [PATCH] socks5 --- src/buffer.h | 7 +++ src/connection.c | 117 +++++++++++++++++++++++++++++++++++------------ src/connection.h | 1 + 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/src/buffer.h b/src/buffer.h index 1b0a4671..249d62ad 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -54,6 +54,13 @@ size_t buffer_peek(const struct Buffer *, void *, size_t); size_t buffer_coalesce(struct Buffer *, const void **); size_t buffer_pop(struct Buffer *, void *, size_t); size_t buffer_push(struct Buffer *, const void *, size_t); + +static void reset_buffer(struct Buffer *buffer) +{ + buffer->head = 0; + buffer->len = 0; +} + static inline size_t buffer_size(const struct Buffer *b) { return b->size_mask + 1; } diff --git a/src/connection.c b/src/connection.c index 4a551f6b..5f33e3d8 100644 --- a/src/connection.c +++ b/src/connection.c @@ -73,9 +73,9 @@ static void connection_cb(struct ev_loop *, struct ev_io *, int); static void resolv_cb(struct Address *, void *); static void reactivate_watchers(struct Connection *, struct ev_loop *); static void insert_proxy_v1_header(struct Connection *); -static void proxy_socks5_connect_request(struct Connection *); -static void proxy_socks5_connect_response(struct Connection *); -static void proxy_socks5_command_request(struct Connection *); +static void proxy_socks5_connect_request(struct Connection *, struct ev_loop *); +static void proxy_socks5_connect_response(struct Connection *, struct ev_loop *); +static void proxy_socks5_command_request(struct Connection *, struct ev_loop *); static void proxy_socks5_command_response(struct Connection *, struct ev_loop *); static void parse_client_request(struct Connection *); static void resolve_server_address(struct Connection *, struct ev_loop *); @@ -220,6 +220,7 @@ client_socket_open(const struct Connection *con) { con->state == RESOLVED || con->state == CONNECTED || con->state == SERVER_CLOSED || + con->state == PROXY_SOCKET_CONNECTED || con->state == PROXY_CONNECT_REQUEST || con->state == PROXY_CONNECT_RESPONSE || con->state == PROXY_COMMAND_REQUEST || @@ -235,6 +236,16 @@ static inline int server_socket_open(const struct Connection *con) { return con->state == CONNECTED || con->state == CLIENT_CLOSED || + con->state == PROXY_SOCKET_CONNECTED || + con->state == PROXY_CONNECT_REQUEST || + con->state == PROXY_CONNECT_RESPONSE || + con->state == PROXY_COMMAND_REQUEST || + con->state == PROXY_COMMAND_RESPONSE; +} + +static inline int +con_in_proxy_state(const struct Connection *con) { + return con->state == PROXY_SOCKET_CONNECTED || con->state == PROXY_CONNECT_REQUEST || con->state == PROXY_CONNECT_RESPONSE || con->state == PROXY_COMMAND_REQUEST || @@ -265,7 +276,7 @@ connection_cb(struct ev_loop *loop, struct ev_io *w, int revents) { /* Receive first in case the socket was closed */ if (revents & EV_READ && buffer_room(input_buffer) && - (is_client || (!is_client && con->state == CONNECTED))) { + (is_client || (!is_client && (con->state == CONNECTED || con_in_proxy_state(con))))) { ssize_t bytes_received = buffer_recv(input_buffer, w->fd, 0, loop); if (bytes_received < 0 && !IS_TEMPORARY_SOCKERR(errno)) { warn("recv(%s): %s, closing connection", @@ -302,6 +313,16 @@ connection_cb(struct ev_loop *loop, struct ev_io *w, int revents) { if (is_client && con->state == RESOLVED) initiate_server_connect(con, loop); + if (!is_client && con->state == PROXY_SOCKET_CONNECTED) + proxy_socks5_connect_request(con, loop); + if (!is_client && con->state == PROXY_CONNECT_REQUEST && buffer_len(input_buffer)) + proxy_socks5_connect_response(con, loop); + if (!is_client && con->state == PROXY_CONNECT_RESPONSE) + proxy_socks5_command_request(con, loop); + if (!is_client && con->state == PROXY_COMMAND_REQUEST && buffer_len(input_buffer)) + proxy_socks5_command_response(con, loop); + + /* Close other socket if we have flushed corresponding buffer */ if (con->state == SERVER_CLOSED && buffer_len(con->server.buffer) == 0) close_client_socket(con, loop); @@ -318,13 +339,6 @@ connection_cb(struct ev_loop *loop, struct ev_io *w, int revents) { return; } - if (!is_client && con->state == PROXY_CONNECT_REQUEST) - proxy_socks5_connect_response(con); - else if (!is_client && con->state == PROXY_CONNECT_RESPONSE) - proxy_socks5_command_request(con); - else if (!is_client && con->state == PROXY_COMMAND_REQUEST) - proxy_socks5_command_response(con, loop); - reactivate_watchers(con, loop); } @@ -752,29 +766,52 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) { if (!con->use_proxy_socks5) con->state = CONNECTED; else - proxy_socks5_connect_request(con); + con->state = PROXY_SOCKET_CONNECTED; ev_io_start(loop, server_watcher); } -static void proxy_socks5_connect_request(struct Connection * con) +static void proxy_socks5_connect_request(struct Connection * con, struct ev_loop *loop) { char buf[] = { 0x05, 0x02, 0x00, 0x01}; - write(con->server.watcher.fd, buf, 4); + + struct Buffer *buffer = new_buffer(64, loop); + buffer_push(buffer, buf, 4); + + ssize_t bytes_transmitted = buffer_send(buffer, con->server.watcher.fd, 0, loop); + if (bytes_transmitted < 0 && !IS_TEMPORARY_SOCKERR(errno)) { + warn("send(%s): %s, closing connection", + "proxy_socks5_connect_request", + strerror(errno)); + + close_server_socket(con, loop); + } + + free_buffer(buffer); + con->state = PROXY_CONNECT_REQUEST; } -static void proxy_socks5_connect_response(struct Connection * con) +static void proxy_socks5_connect_response(struct Connection * con, struct ev_loop *loop) { - int buf_len = 128; - char buf[buf_len]; - int n = read(con->server.watcher.fd, buf, buf_len); - if (n > 0) + const char *payload; + size_t payload_len = buffer_coalesce(con->server.buffer, (const void **)&payload); + + if (payload_len >= 2) { - if (buf[0] == 0x5 && buf[1] == 0x0) + if (payload[0] == 0x05 && (payload[1] == 0x00 || payload[1] == 0x02)) { + reset_buffer(con->server.buffer); + con->state = PROXY_CONNECT_RESPONSE; - proxy_socks5_command_request(con); + proxy_socks5_command_request(con, loop); + } + else + { + char server[INET6_ADDRSTRLEN + 8]; + warn("Socks5 proxy_socks5_connect_response failed: %s", + display_sockaddr(&con->server.addr, server, sizeof(server))); + abort_connection(con); } } } @@ -791,10 +828,8 @@ struct Address { char data[]; }; -static void proxy_socks5_command_request(struct Connection * con) +static void proxy_socks5_command_request(struct Connection * con, struct ev_loop *loop) { - // 110.242.68.4 80 - //char buf[] = { 0x05, 0x01, 0x00, 0x01, 0x6e, 0xf2, 0x44, 0x04, 0x00, 0x50 }; char buf[128] = { 0x05, 0x01, 0x00, ADDRESS_TYPE_DOMAIN}; int buf_len = 4; @@ -808,21 +843,43 @@ static void proxy_socks5_command_request(struct Connection * con) memcpy(buf + buf_len, &hport, 2); buf_len += 2; - write(con->server.watcher.fd, buf, buf_len); + + struct Buffer *buffer = new_buffer(64, loop); + buffer_push(buffer, buf, buf_len); + + ssize_t bytes_transmitted = buffer_send(buffer, con->server.watcher.fd, 0, loop); + if (bytes_transmitted < 0 && !IS_TEMPORARY_SOCKERR(errno)) { + warn("send(%s): %s, closing connection", + "proxy_socks5_connect_request", + strerror(errno)); + + close_server_socket(con, loop); + } + + free_buffer(buffer); + con->state = PROXY_COMMAND_REQUEST; } static void proxy_socks5_command_response(struct Connection * con, struct ev_loop *loop) { - int buf_len = 128; - char buf[buf_len]; - int n = read(con->server.watcher.fd, buf, buf_len); - if (n > 0) + const char *payload; + size_t payload_len = buffer_coalesce(con->server.buffer, (const void **)&payload); + + if (payload_len >= 2) { - if (buf[0] == 0x5 && buf[1] == 0x0) + if (payload[0] == 0x05 && (payload[1] == 0x00 || payload[1] == 0x02)) { + reset_buffer(con->server.buffer); con->state = CONNECTED; } + else + { + char server[INET6_ADDRSTRLEN + 8]; + warn("Socks5 proxy_socks5_command_response failed: %s", + display_sockaddr(&con->server.addr, server, sizeof(server))); + abort_connection(con); + } } } diff --git a/src/connection.h b/src/connection.h index 0baf53aa..bc9fa426 100644 --- a/src/connection.h +++ b/src/connection.h @@ -39,6 +39,7 @@ struct Connection { PARSED, /* Parsed initial request and extracted hostname */ RESOLVING, /* DNS query in progress */ RESOLVED, /* Server socket address resolved */ + PROXY_SOCKET_CONNECTED, /* Socks5 Connect to Server socket */ PROXY_CONNECT_REQUEST, /* Socks5 Connect to Server Request */ PROXY_CONNECT_RESPONSE, /* Socks5 Connect to Server Response */ PROXY_COMMAND_REQUEST, /* Socks5 Command Request */