Skip to content

Commit

Permalink
socks5
Browse files Browse the repository at this point in the history
  • Loading branch information
hnkeyang committed Jan 16, 2025
1 parent 5f0c522 commit e05cce3
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 30 deletions.
7 changes: 7 additions & 0 deletions src/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
117 changes: 87 additions & 30 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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 ||
Expand All @@ -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 ||
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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;

Expand All @@ -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);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit e05cce3

Please sign in to comment.