|
|
|
@ -20,6 +20,9 @@ |
|
|
|
#include <time.h> |
|
|
|
#include <time.h> |
|
|
|
#include "../lib/platform_compat.h" |
|
|
|
#include "../lib/platform_compat.h" |
|
|
|
#include "test_utils.h" |
|
|
|
#include "test_utils.h" |
|
|
|
|
|
|
|
#include "test_net.h" |
|
|
|
|
|
|
|
#include "../src/proxy/socks_proxy.h" |
|
|
|
|
|
|
|
#include "../src/proxy/tcp_proxy_client.h" |
|
|
|
#include "../lib/u_async.h" |
|
|
|
#include "../lib/u_async.h" |
|
|
|
#include "../lib/debug_config.h" |
|
|
|
#include "../lib/debug_config.h" |
|
|
|
#include "../lib/ll_queue.h" |
|
|
|
#include "../lib/ll_queue.h" |
|
|
|
@ -58,18 +61,6 @@ static char g_cert[512], g_key[512]; |
|
|
|
static void* g_mon_id = NULL; |
|
|
|
static void* g_mon_id = NULL; |
|
|
|
static int g_file_seed = 0; |
|
|
|
static int g_file_seed = 0; |
|
|
|
|
|
|
|
|
|
|
|
static int alloc_port(void) { |
|
|
|
|
|
|
|
int s = socket(AF_INET, SOCK_STREAM, 0); |
|
|
|
|
|
|
|
if (s < 0) return -1; |
|
|
|
|
|
|
|
struct sockaddr_in a; memset(&a, 0, sizeof(a)); |
|
|
|
|
|
|
|
a.sin_family = AF_INET; a.sin_addr.s_addr = inet_addr("127.0.0.1"); |
|
|
|
|
|
|
|
for (int i = 0; i < 200; i++) { |
|
|
|
|
|
|
|
a.sin_port = htons((uint16_t)(20000 + (rand() % 40000))); |
|
|
|
|
|
|
|
if (bind(s, (struct sockaddr*)&a, sizeof(a)) == 0) { close(s); return ntohs(a.sin_port); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
close(s); return -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gen_file(const char* path, int size, int seed) { |
|
|
|
static void gen_file(const char* path, int size, int seed) { |
|
|
|
FILE* f = fopen(path, "wb"); |
|
|
|
FILE* f = fopen(path, "wb"); |
|
|
|
if (!f) { fprintf(stderr, "gen_file: fopen(%s) failed\n", path); return; } |
|
|
|
if (!f) { fprintf(stderr, "gen_file: fopen(%s) failed\n", path); return; } |
|
|
|
@ -83,7 +74,7 @@ static void gen_file(const char* path, int size, int seed) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Сервер сообщает готовность после listen и настройки TLS; EOF обнаруживает ошибку запуска без паузы.
|
|
|
|
// Сервер сообщает готовность после listen и настройки TLS; EOF обнаруживает ошибку запуска без паузы.
|
|
|
|
static int wait_server_ready(int fd, int port, const char* name) { |
|
|
|
static int wait_server_ready(int fd, int* port, const char* name) { |
|
|
|
uint64_t start = get_time_us(), deadline = start + 5000000; |
|
|
|
uint64_t start = get_time_us(), deadline = start + 5000000; |
|
|
|
struct pollfd pfd = {.fd = fd, .events = POLLIN}; |
|
|
|
struct pollfd pfd = {.fd = fd, .events = POLLIN}; |
|
|
|
int result; |
|
|
|
int result; |
|
|
|
@ -91,21 +82,23 @@ static int wait_server_ready(int fd, int port, const char* name) { |
|
|
|
uint64_t now = get_time_us(); |
|
|
|
uint64_t now = get_time_us(); |
|
|
|
result = poll(&pfd, 1, now < deadline ? (int)((deadline - now + 999) / 1000) : 0); |
|
|
|
result = poll(&pfd, 1, now < deadline ? (int)((deadline - now + 999) / 1000) : 0); |
|
|
|
} while (result < 0 && errno == EINTR); |
|
|
|
} while (result < 0 && errno == EINTR); |
|
|
|
char marker = 0; |
|
|
|
uint8_t assigned[2] = {0}; |
|
|
|
ssize_t bytes = result > 0 ? read(fd, &marker, 1) : -1; |
|
|
|
ssize_t bytes = result > 0 ? read(fd, assigned, sizeof(assigned)) : -1; |
|
|
|
int error = result < 0 || (result > 0 && bytes < 0) ? errno : 0; |
|
|
|
int error = result < 0 || (result > 0 && bytes < 0) ? errno : 0; |
|
|
|
close(fd); |
|
|
|
close(fd); |
|
|
|
if (result <= 0 || bytes != 1 || marker != 'R') { |
|
|
|
int actual = ((int)assigned[0] << 8) | assigned[1]; |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test %s server startup failed: port=%d poll=%d events=%x bytes=%ld marker=%d errno=%d", |
|
|
|
if (result <= 0 || bytes != sizeof(assigned) || !actual) { |
|
|
|
name, port, result, pfd.revents, (long)bytes, marker, error); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test %s server startup failed: poll=%d events=%x bytes=%ld port=%d errno=%d", |
|
|
|
|
|
|
|
name, result, pfd.revents, (long)bytes, actual, error); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test %s server ready: port=%d elapsed=%lluus", name, port, |
|
|
|
*port = actual; |
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test %s server ready: port=%d elapsed=%lluus", name, *port, |
|
|
|
(unsigned long long)(get_time_us() - start)); |
|
|
|
(unsigned long long)(get_time_us() - start)); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int start_http_server(int port, const char* dir) { |
|
|
|
static int start_http_server(int* port, const char* dir) { |
|
|
|
char script[512]; snprintf(script, sizeof(script), "%s/_srv.py", dir); |
|
|
|
char script[512]; snprintf(script, sizeof(script), "%s/_srv.py", dir); |
|
|
|
FILE* sf = fopen(script, "w"); |
|
|
|
FILE* sf = fopen(script, "w"); |
|
|
|
if (!sf) return -1; |
|
|
|
if (!sf) return -1; |
|
|
|
@ -130,7 +123,7 @@ static int start_http_server(int port, const char* dir) { |
|
|
|
"port=int(sys.argv[1])\n" |
|
|
|
"port=int(sys.argv[1])\n" |
|
|
|
"os.chdir(sys.argv[2])\n" |
|
|
|
"os.chdir(sys.argv[2])\n" |
|
|
|
"httpd=HTTPServer(('127.0.0.1',port),H)\n" |
|
|
|
"httpd=HTTPServer(('127.0.0.1',port),H)\n" |
|
|
|
"ready=int(sys.argv[3]);os.write(ready,b'R');os.close(ready)\n" |
|
|
|
"ready=int(sys.argv[3]);os.write(ready,httpd.server_port.to_bytes(2,'big'));os.close(ready)\n" |
|
|
|
"httpd.serve_forever()\n" |
|
|
|
"httpd.serve_forever()\n" |
|
|
|
); |
|
|
|
); |
|
|
|
fclose(sf); |
|
|
|
fclose(sf); |
|
|
|
@ -144,9 +137,8 @@ static int start_http_server(int port, const char* dir) { |
|
|
|
} |
|
|
|
} |
|
|
|
if (pid == 0) { |
|
|
|
if (pid == 0) { |
|
|
|
close(ready[0]); |
|
|
|
close(ready[0]); |
|
|
|
char port_str[16], ready_str[16]; |
|
|
|
char ready_str[16]; snprintf(ready_str, sizeof(ready_str), "%d", ready[1]); |
|
|
|
snprintf(port_str, sizeof(port_str), "%d", port); snprintf(ready_str, sizeof(ready_str), "%d", ready[1]); |
|
|
|
execlp("python3", "python3", script, "0", dir, ready_str, (char*)NULL); |
|
|
|
execlp("python3", "python3", script, port_str, dir, ready_str, (char*)NULL); |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP python exec: %s", strerror(errno)); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTP python exec: %s", strerror(errno)); |
|
|
|
_exit(1); |
|
|
|
_exit(1); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -155,7 +147,7 @@ static int start_http_server(int port, const char* dir) { |
|
|
|
return wait_server_ready(ready[0], port, "HTTP"); |
|
|
|
return wait_server_ready(ready[0], port, "HTTP"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int start_https_server(int port, const char* dir, const char* cert, const char* key) { |
|
|
|
static int start_https_server(int* port, const char* dir, const char* cert, const char* key) { |
|
|
|
char script[512]; snprintf(script, sizeof(script), "%s/_srv_https.py", dir); |
|
|
|
char script[512]; snprintf(script, sizeof(script), "%s/_srv_https.py", dir); |
|
|
|
FILE* sf = fopen(script, "w"); |
|
|
|
FILE* sf = fopen(script, "w"); |
|
|
|
if (!sf) return -1; |
|
|
|
if (!sf) return -1; |
|
|
|
@ -187,7 +179,7 @@ static int start_https_server(int port, const char* dir, const char* cert, const |
|
|
|
"httpd=HTTPServer(('127.0.0.1',int(sys.argv[4])),H)\n" |
|
|
|
"httpd=HTTPServer(('127.0.0.1',int(sys.argv[4])),H)\n" |
|
|
|
"httpd.socket=ctx.wrap_socket(httpd.socket,server_side=True)\n" |
|
|
|
"httpd.socket=ctx.wrap_socket(httpd.socket,server_side=True)\n" |
|
|
|
"httpd.timeout=None\n" |
|
|
|
"httpd.timeout=None\n" |
|
|
|
"ready=int(sys.argv[5]);os.write(ready,b'R');os.close(ready)\n" |
|
|
|
"ready=int(sys.argv[5]);os.write(ready,httpd.server_port.to_bytes(2,'big'));os.close(ready)\n" |
|
|
|
"httpd.serve_forever()\n" |
|
|
|
"httpd.serve_forever()\n" |
|
|
|
); |
|
|
|
); |
|
|
|
fclose(sf); |
|
|
|
fclose(sf); |
|
|
|
@ -201,9 +193,8 @@ static int start_https_server(int port, const char* dir, const char* cert, const |
|
|
|
} |
|
|
|
} |
|
|
|
if (pid == 0) { |
|
|
|
if (pid == 0) { |
|
|
|
close(ready[0]); |
|
|
|
close(ready[0]); |
|
|
|
char port_str[16], ready_str[16]; |
|
|
|
char ready_str[16]; snprintf(ready_str, sizeof(ready_str), "%d", ready[1]); |
|
|
|
snprintf(port_str, sizeof(port_str), "%d", port); snprintf(ready_str, sizeof(ready_str), "%d", ready[1]); |
|
|
|
execlp("python3", "python3", script, cert, key, dir, "0", ready_str, (char*)NULL); |
|
|
|
execlp("python3", "python3", script, cert, key, dir, port_str, ready_str, (char*)NULL); |
|
|
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS python exec: %s", strerror(errno)); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test HTTPS python exec: %s", strerror(errno)); |
|
|
|
_exit(1); |
|
|
|
_exit(1); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -487,14 +478,6 @@ int main(void) { |
|
|
|
utun_instance_set_tun_init_enabled(0); |
|
|
|
utun_instance_set_tun_init_enabled(0); |
|
|
|
srand((unsigned)time(NULL)); |
|
|
|
srand((unsigned)time(NULL)); |
|
|
|
|
|
|
|
|
|
|
|
g_http_port = alloc_port(); g_https_port = alloc_port(); |
|
|
|
|
|
|
|
g_cli_port = alloc_port(); g_srv_port = alloc_port(); |
|
|
|
|
|
|
|
g_socks_port = alloc_port(); g_http_proxy_port = alloc_port(); |
|
|
|
|
|
|
|
if (g_http_port < 0 || g_https_port < 0 || g_cli_port < 0 || g_srv_port < 0 || g_socks_port < 0 || g_http_proxy_port < 0) { |
|
|
|
|
|
|
|
printf("[FAIL] port allocation\n"); return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
printf(" ports: http=%d https=%d socks=%d http_proxy=%d\n", g_http_port, g_https_port, g_socks_port, g_http_proxy_port); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
strcpy(g_tmpdir, "/tmp/utun_test_XXXXXX"); |
|
|
|
strcpy(g_tmpdir, "/tmp/utun_test_XXXXXX"); |
|
|
|
if (test_mkdtemp(g_tmpdir) < 0) { printf("[FAIL] mkdtemp: %s\n", strerror(errno)); return 1; } |
|
|
|
if (test_mkdtemp(g_tmpdir) < 0) { printf("[FAIL] mkdtemp: %s\n", strerror(errno)); return 1; } |
|
|
|
|
|
|
|
|
|
|
|
@ -509,8 +492,8 @@ int main(void) { |
|
|
|
} |
|
|
|
} |
|
|
|
printf(" test files: 1KB, 100KB, 1MB, 10MB (total %.1fMB)\n", total_mb / (1024.0*1024.0)); fflush(stdout); |
|
|
|
printf(" test files: 1KB, 100KB, 1MB, 10MB (total %.1fMB)\n", total_mb / (1024.0*1024.0)); fflush(stdout); |
|
|
|
|
|
|
|
|
|
|
|
if (start_http_server(g_http_port, g_tmpdir) < 0) { printf("[FAIL] start http server\n"); goto cleanup; } |
|
|
|
if (start_http_server(&g_http_port, g_tmpdir) < 0) { printf("[FAIL] start http server\n"); goto cleanup; } |
|
|
|
if (start_https_server(g_https_port, g_tmpdir, g_cert, g_key) < 0) { printf("[FAIL] start https server\n"); goto cleanup; } |
|
|
|
if (start_https_server(&g_https_port, g_tmpdir, g_cert, g_key) < 0) { printf("[FAIL] start https server\n"); goto cleanup; } |
|
|
|
printf(" HTTP/HTTPS servers started\n"); |
|
|
|
printf(" HTTP/HTTPS servers started\n"); |
|
|
|
|
|
|
|
|
|
|
|
g_ua = uasync_create(); |
|
|
|
g_ua = uasync_create(); |
|
|
|
@ -519,6 +502,16 @@ int main(void) { |
|
|
|
g_srv = utun_instance_create_from_str(g_ua, make_cfg_server()); |
|
|
|
g_srv = utun_instance_create_from_str(g_ua, make_cfg_server()); |
|
|
|
g_cli = utun_instance_create_from_str(g_ua, make_cfg_client()); |
|
|
|
g_cli = utun_instance_create_from_str(g_ua, make_cfg_client()); |
|
|
|
if (!g_srv || !g_cli) { printf("[FAIL] instance create\n"); goto cleanup; } |
|
|
|
if (!g_srv || !g_cli) { printf("[FAIL] instance create\n"); goto cleanup; } |
|
|
|
|
|
|
|
test_etcp_set_peer(g_cli, "c1", g_srv, "s1"); |
|
|
|
|
|
|
|
g_srv_port = ss_get_port(&test_etcp_bound_socket(g_srv, "s1")->local_addr); |
|
|
|
|
|
|
|
g_cli_port = ss_get_port(&test_etcp_bound_socket(g_cli, "s1")->local_addr); |
|
|
|
|
|
|
|
struct tcp_proxy_client* proxy = g_cli->tcp_proxy_client; |
|
|
|
|
|
|
|
if (!proxy) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test: proxy client missing"); goto cleanup; } |
|
|
|
|
|
|
|
g_socks_port = socks_proxy_get_port(proxy->socks_listen); |
|
|
|
|
|
|
|
g_http_proxy_port = socks_proxy_get_port(proxy->http_listen); |
|
|
|
|
|
|
|
if (!g_socks_port || !g_http_proxy_port) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "test: proxy listeners missing"); goto cleanup; } |
|
|
|
|
|
|
|
printf(" ports: http=%d https=%d socks=%d http_proxy=%d udp_client=%d udp_server=%d\n", |
|
|
|
|
|
|
|
g_http_port, g_https_port, g_socks_port, g_http_proxy_port, g_cli_port, g_srv_port); |
|
|
|
|
|
|
|
|
|
|
|
if (utun_instance_init(g_srv) < 0 || utun_instance_init(g_cli) < 0) { printf("[FAIL] instance init\n"); goto cleanup; } |
|
|
|
if (utun_instance_init(g_srv) < 0 || utun_instance_init(g_cli) < 0) { printf("[FAIL] instance init\n"); goto cleanup; } |
|
|
|
printf(" waiting for ETCP...\n"); fflush(stdout); |
|
|
|
printf(" waiting for ETCP...\n"); fflush(stdout); |
|
|
|
|