Skip to content

Commit

Permalink
Optimize Client::socks5_handshake(), fix core tests
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Nov 1, 2024
1 parent e5b1c90 commit 72886f2
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 69 deletions.
161 changes: 98 additions & 63 deletions core-tests/src/network/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,19 @@ TEST(client, shutdown_all) {
}

#ifdef SW_USE_OPENSSL
TEST(client, ssl_1) {
int ret;

static const char *request_baidu = "GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n";

static const char *domain_baidu = "www.baidu.com";

#define SOCKS5_WITH_AUTH 1

TEST(client, ssl_1) {
bool connected = false;
bool closed = false;
swoole::String buf(65536);
Expand All @@ -230,21 +240,14 @@ TEST(client, ssl_1) {
client.enable_ssl_encrypt();
client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
cli->send(cli, request_baidu, strlen(request_baidu), 0);
};

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);

ASSERT_EQ(client.connect(&client, domain_baidu, 443, -1, 0), 0);

swoole_event_wait();

Expand All @@ -253,89 +256,121 @@ TEST(client, ssl_1) {
ASSERT_TRUE(buf.contains("Baidu"));
}


TEST(client, http_proxy) {
static void proxy_async_test(Client &client, bool https) {
int ret;

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);

bool connected = false;
bool closed = false;
swoole::String buf(65536);

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);

Client client(SW_SOCK_TCP, true);
client.enable_ssl_encrypt();
client.http_proxy = new HttpProxy();
client.http_proxy->proxy_host = std::string(TEST_HTTP_PROXY_HOST);
client.http_proxy->proxy_port = TEST_HTTP_PROXY_PORT;
if (https) {
client.enable_ssl_encrypt();
}

client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
cli->send(cli, request_baidu, strlen(request_baidu), 0);
};

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);

ASSERT_EQ(client.connect(&client, domain_baidu, https ? 443 : 80, -1, 0), 0);

swoole_event_wait();

ASSERT_TRUE(connected);
ASSERT_TRUE(closed);
ASSERT_TRUE(buf.contains("Baidu"));
ASSERT_TRUE(buf.contains("www.baidu.com"));
}

TEST(client, socks5_proxy) {
int ret;

bool connected = false;
bool closed = false;
static void proxy_sync_test(Client &client, bool https) {
swoole::String buf(65536);
if (https) {
client.enable_ssl_encrypt();
}

ASSERT_EQ(client.connect(&client, domain_baidu, https ? 443 : 80, -1, 0), 0);
ASSERT_GT(client.send(&client, request_baidu, strlen(request_baidu), 0), 0);

while(true) {
char rbuf[4096];
auto nr = client.recv(&client, rbuf, sizeof(rbuf), 0);
if (nr <= 0) {
break;
}
buf.append(rbuf, nr);
}

ASSERT_TRUE(buf.contains("www.baidu.com"));
}

swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);

Client client(SW_SOCK_TCP, true);
client.enable_ssl_encrypt();

static void proxy_set_socks5_proxy(Client &client) {
client.socks5_proxy = new Socks5Proxy();
client.socks5_proxy->host = std::string("127.0.0.1");
client.socks5_proxy->port = 1080;
client.socks5_proxy->dns_tunnel = 1;
client.socks5_proxy->method = 0x02;
#if SOCKS5_WITH_AUTH
client.socks5_proxy->method = SW_SOCKS5_METHOD_AUTH;
client.socks5_proxy->username = std::string("user");
client.socks5_proxy->password = std::string("password");
#endif
}

client.onConnect = [&connected](Client *cli) {
connected = true;
cli->send(cli,
SW_STRL("GET / HTTP/1.1\r\n"
"Host: www.baidu.com\r\n"
"Connection: close\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/51.0.2704.106 Safari/537.36"
"\r\n\r\n"),
0);
};
static void proxy_set_http_proxy(Client &client) {
client.http_proxy = new HttpProxy();
client.http_proxy->proxy_host = std::string(TEST_HTTP_PROXY_HOST);
client.http_proxy->proxy_port = TEST_HTTP_PROXY_PORT;
}

client.onError = [](Client *cli) {};
client.onClose = [&closed](Client *cli) { closed = true; };
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
ret = client.connect(&client, "www.baidu.com", 443, -1, 0);
ASSERT_EQ(ret, 0);
TEST(client, https_get_async_with_http_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_http_proxy(client);
proxy_async_test(client, true);
}

swoole_event_wait();
TEST(client, https_get_async_with_socks5_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_socks5_proxy(client);
proxy_async_test(client, true);
}

ASSERT_TRUE(connected);
ASSERT_TRUE(closed);
ASSERT_TRUE(buf.contains("Baidu"));
TEST(client, https_get_sync_with_http_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_http_proxy(client);
proxy_sync_test(client, true);
}

TEST(client, https_get_sync_with_socks5_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_socks5_proxy(client);
proxy_sync_test(client, true);
}

TEST(client, http_get_async_with_http_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_http_proxy(client);
proxy_async_test(client, false);
}

TEST(client, http_get_async_with_socks5_proxy) {
Client client(SW_SOCK_TCP, true);
proxy_set_socks5_proxy(client);
proxy_async_test(client, false);
}

TEST(client, http_get_sync_with_http_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_http_proxy(client);
proxy_sync_test(client, false);
}

TEST(client, http_get_sync_with_socks5_proxy) {
Client client(SW_SOCK_TCP, false);
proxy_set_socks5_proxy(client);
proxy_sync_test(client, false);
}
#endif
17 changes: 11 additions & 6 deletions src/network/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ int Client::socks5_handshake(const char *recv_data, size_t length) {

ctx->state = SW_SOCKS5_STATE_AUTH;

return send(this, ctx->buf, ctx->username.length() + ctx->password.length() + 3, 0);
return send(this, ctx->buf, ctx->username.length() + ctx->password.length() + 3, 0) > 0 ? SW_OK : SW_ERR;
}
// send connect request
else {
Expand All @@ -211,14 +211,14 @@ int Client::socks5_handshake(const char *recv_data, size_t length) {
memcpy(buf, ctx->target_host.c_str(), ctx->target_host.length());
buf += ctx->target_host.length();
*(uint16_t *) buf = htons(ctx->target_port);
return send(this, ctx->buf, ctx->target_host.length() + 7, 0);
return send(this, ctx->buf, ctx->target_host.length() + 7, 0) > 0 ? SW_OK : SW_ERR;
} else {
buf[3] = 0x01;
buf += 4;
*(uint32_t *) buf = htons(ctx->target_host.length());
buf += 4;
*(uint16_t *) buf = htons(ctx->target_port);
return send(this, ctx->buf, ctx->target_host.length() + 7, 0);
return send(this, ctx->buf, ctx->target_host.length() + 7, 0) > 0 ? SW_OK : SW_ERR;
}
}
} else if (ctx->state == SW_SOCKS5_STATE_AUTH) {
Expand Down Expand Up @@ -249,13 +249,14 @@ int Client::socks5_handshake(const char *recv_data, size_t length) {
#endif
if (result == 0) {
ctx->state = SW_SOCKS5_STATE_READY;
return SW_OK;
} else {
swoole_error_log(SW_LOG_NOTICE,
SW_ERROR_SOCKS5_SERVER_ERROR,
"Socks5 server error, reason :%s",
Socks5Proxy::strerror(result));
return SW_ERR;
}
return result;
}
return SW_OK;
}
Expand Down Expand Up @@ -940,9 +941,13 @@ static int Client_onStreamRead(Reactor *reactor, Event *event) {
goto _connect_fail;
}
cli->buffer->length += n;
if (cli->socks5_handshake(buf, buf_size) < 0 || cli->socks5_proxy->state != SW_SOCKS5_STATE_READY) {
if (cli->socks5_handshake(buf, buf_size) < 0) {
goto _connect_fail;
}
if (cli->socks5_proxy->state != SW_SOCKS5_STATE_READY) {
return SW_OK;
}
cli->buffer->clear();
if (!do_ssl_handshake) {
execute_onConnect(cli);
return SW_OK;
Expand Down Expand Up @@ -1119,7 +1124,7 @@ static int Client_onWrite(Reactor *reactor, Event *event) {
// socks5 proxy
if (cli->socks5_proxy && cli->socks5_proxy->state == SW_SOCKS5_STATE_WAIT) {
char buf[3];
Socks5Proxy::pack(buf, cli->socks5_proxy->username.empty() ? 0x00 : 0x02);
Socks5Proxy::pack(buf, cli->socks5_proxy->username.empty() ? 0 : SW_SOCKS5_METHOD_AUTH);
cli->socks5_proxy->state = SW_SOCKS5_STATE_HANDSHAKE;
return cli->send(cli, buf, sizeof(buf), 0);
}
Expand Down

0 comments on commit 72886f2

Please sign in to comment.