liudf0716 / xfrpc

The xfrpc project is a lightweight implementation of the FRP client written in C language for OpenWRT and IoT systems. It is designed to provide an efficient solution for resource-constrained devices such as OpenWRT routers and IoT devices, which often have limited ROM and RAM space.
GNU General Public License v3.0
724 stars 92 forks source link

The socks5 function cannot be used properly #65

Open mumianbaba opened 1 month ago

mumianbaba commented 1 month ago

I configured a socks5 section, but it is not working properly. I used the socks5 agent function test using xshell.

[socks5]
type = socks5
remote_port = 30002

log for sock5 at client:

$ ./xfrpc  -c xfrpc.ini -f -d 7
[7][Thu Oct 24 19:21:36 2024][983951](config.c:522) Reading configuration file 'xfrpc.ini'
[7][Thu Oct 24 19:21:36 2024][983951](config.c:111) Section[common]: {server_addr:aa.bb.cc.dd, server_port:7000, auth_token:(null), interval:30, timeout:90}
[7][Thu Oct 24 19:21:36 2024][983951](config.c:134) Proxy service 0: {name:tcp_test, local_port:22, type:tcp, use_encryption:0, use_compression:0, custom_domains:(null), subdomain:(null), locations:(null), host_header_rewrite:(null), http_user:(null), http_pwd:(null)}
[7][Thu Oct 24 19:21:36 2024][983951](config.c:134) Proxy service 1: {name:socks5_test, local_port:0, type:socks5, use_encryption:0, use_compression:0, custom_domains:(null), subdomain:(null), locations:(null), host_header_rewrite:(null), http_user:(null), http_pwd:(null)}
[6][Thu Oct 24 19:21:36 2024][983951](control.c:700) connect server [aa.bb.cc.dd:7000]...
[7][Thu Oct 24 19:21:36 2024][983951](control.c:662) xfrp server connected
[7][Thu Oct 24 19:21:36 2024][983951](control.c:737) send plain msg ----> [o: { "version": "0.58.0", "hostname": "", "os": "Linux", "arch": "x86_64", "privilege_key": "c296030b3e909041db75ee0bd046fb60", "timestamp": 1729768896, "run_id": "A69FDB6ADE4A", "pool_count": 1 }]
[7][Thu Oct 24 19:21:36 2024][983951](control.c:674) start keep_control_alive
[7][Thu Oct 24 19:21:36 2024][983951](login.c:128) xfrp login response: run_id: [A69FDB6ADE4A], version: [0.60.0]
[3][Thu Oct 24 19:21:36 2024][983951](control.c:492) login success! login_len 44 len 53 ilen 0
[7][Thu Oct 24 19:21:36 2024][983951](control.c:348) recv eas1238 iv data
[6][Thu Oct 24 19:21:36 2024][983951](control.c:159) Start xfrp proxy services ...
[7][Thu Oct 24 19:21:36 2024][983951](control.c:837) control proxy client: [Type 112 : proxy_name tcp_test : msg_len 266]
[7][Thu Oct 24 19:21:36 2024][983951](control.c:837) control proxy client: [Type 112 : proxy_name socks5_test : msg_len 261]
[7][Thu Oct 24 19:21:36 2024][983951](control.c:128) new client through tcp mux: 5
[7][Thu Oct 24 19:21:36 2024][983951](control.c:737) send plain msg ----> [w: { "run_id": "A69FDB6ADE4A" }]
[7][Thu Oct 24 19:21:39 2024][983951](control.c:424) proxy service [socks5_test] [(null):0] start work connection. remain data length 0
[3][Thu Oct 24 19:21:39 2024][983951](client.c:162) service tunnel started failed, proxy service resource unvalid.
[7][Thu Oct 24 19:21:39 2024][983951](control.c:128) new client through tcp mux: 7
[7][Thu Oct 24 19:21:39 2024][983951](control.c:737) send plain msg ----> [w: { "run_id": "A69FDB6ADE4A" }]
[6][Thu Oct 24 19:21:39 2024][983951](tcpmux.c:367) send data to local proxy not equal, nret 0, length 3

I learned about the socks5 protocol and captured the tcp packet, and found that the initial stage of socks5 may only be 3 bytes. but the handle_ss5 function takes at least 7 bytes, i replace it with handle_socks5 and A few other tweaks were made before it was finally tested with xshell.

diff --git a/client.c b/client.c
index 6900fa1..d2ba154 100644
--- a/client.c
+++ b/client.c
@@ -95,6 +95,7 @@ xfrp_proxy_event_cb(struct bufferevent *bev, short what, void *ctx)
                tx_ring_buffer_write(client->local_proxy_bev, rb, rb->sz);

            client->state = SOCKS5_ESTABLISHED;
+           debug(LOG_DEBUG, "what [%d] client [%d] set socks5 established", what, client->stream_id);
        }
    }
 }
diff --git a/client.h b/client.h
index bcd6953..997465b 100644
--- a/client.h
+++ b/client.h
@@ -50,7 +50,6 @@ struct socks5_addr {
 enum socks5_state {
    SOCKS5_INIT,
    SOCKS5_HANDSHAKE,
-   SOCKS5_CONNECT,
    SOCKS5_ESTABLISHED,
 };

diff --git a/proxy_tcp.c b/proxy_tcp.c
index 60458f4..dd079ed 100644
--- a/proxy_tcp.c
+++ b/proxy_tcp.c
@@ -215,7 +215,7 @@ handle_socks5(struct proxy_client *client, struct ring_buffer *rb, int len)
 {
    uint32_t nret = 0;
    // if client's local_bev is not NULL, then we should forward rb's data to local_bev
-   if (client->state == SOCKS5_CONNECT) {
+   if (client->state == SOCKS5_ESTABLISHED) {
        assert(client->local_proxy_bev);
        tx_ring_buffer_write(client->local_proxy_bev, rb, len);
        return len;
@@ -231,7 +231,13 @@ handle_socks5(struct proxy_client *client, struct ring_buffer *rb, int len)
        buf[0] = 0x5;
        buf[1] = 0x0;
        buf[2] = 0x0;
-       tmux_stream_write(client->ctl_bev, buf, 3, &client->stream);
+       /* 
+           send 3 bytes : cant work normal,
+           xshell print log: Received an invalid response from the specified proxy server: Connection aborted.
+           and xshell close socke tstraightway.
+           send 2 bytes : can work normal.
+       */
+       tmux_stream_write(client->ctl_bev, buf, 2, &client->stream); 
        client->state = SOCKS5_HANDSHAKE;
        return 3;
    } else if (client->state == SOCKS5_HANDSHAKE && len >= 10) {
@@ -253,6 +259,16 @@ handle_socks5(struct proxy_client *client, struct ring_buffer *rb, int len)
            return 0;
        }
        assert(len == offset+3);
+
+       /*
+           Make a simple reply for test.
+       */
+       uint8_t rsp[10] = {0};
+       rsp[0] = 0x05;
+       rsp[1] = 0x00;
+       rsp[2] = 0x00;
+       rsp[3] = 0x01;
+       tmux_stream_write(client->ctl_bev, rsp, 10, &client->stream);
        //tx_ring_buffer_write(client->local_bev, rb, len - offset);
        return len;
    } else {
diff --git a/tcpmux.c b/tcpmux.c
index 491ad61..851c45c 100644
--- a/tcpmux.c
+++ b/tcpmux.c
@@ -357,7 +357,8 @@ process_data(struct tmux_stream *stream, uint32_t length, uint16_t flags,
        free(data);
    } else if (is_socks5_proxy(pc->ps)) {
        // if pc's type is socks5, we should send data to socks5 client
-       nret = handle_ss5(pc, &stream->rx_ring, length);
+       // nret = handle_ss5(pc, &stream->rx_ring, length);
+       nret = handle_socks5(pc, &stream->rx_ring, length);
    } else {
        nret = tx_ring_buffer_write(pc->local_proxy_bev, &stream->rx_ring, length);

I'm sure you can do better, you just don't have the time and energy to invest in it.

liudf0716 commented 1 month ago

@mumianbaba I recall testing xfrpc's SOCKS5 with Shadowsocks, but it might differ from the standard SOCKS5 protocol. I'll double-check and confirm that as soon as possible. Thank you for identifying the issue and providing a solution.