transport: SOCKS5-прокси для ETCP-линков (CONNECT + UDP ASSOCIATE + пинги)
This commit is contained in:
1 parent
7c8d65db78
commit
d0dfa97a47
14 files changed
+1360
-54
No files matched your search
@@ -47,6 +47,7 @@ check_PROGRAMS = \
|
||||
test_icmp_proxy \
|
||||
test_tcp_proxy_client \
|
||||
test_socks_http_proxy \
|
||||
test_socks_client \
|
||||
test_bgp_route_exchange \
|
||||
test_bgp_triangle \
|
||||
test_broadcast \
|
||||
@@ -151,6 +152,10 @@ test_stcp_SOURCES = test_stcp.c
|
||||
test_stcp_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
test_stcp_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_socks_client_SOURCES = test_socks_client.c
|
||||
test_socks_client_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/transport_layer -I$(top_srcdir)/lib
|
||||
test_socks_client_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_etcp_two_instances_SOURCES = test_etcp_two_instances.c
|
||||
test_etcp_two_instances_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
test_etcp_two_instances_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
@@ -0,0 +1,527 @@
|
||||
// test_socks_client.c — SOCKS5-клиент: dial через mock-прокси (no-auth, auth, reject)
|
||||
#include "socks_client.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
#include "../lib/socket_compat.h"
|
||||
#include "../lib/platform_compat.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int test_failed = 0;
|
||||
#define TASSERT(cond) do { \
|
||||
if (!(cond)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, " FAIL: %s", #cond); test_failed = 1; return test_failed; } \
|
||||
} while(0)
|
||||
|
||||
#define MOCK_PORT 24771
|
||||
|
||||
enum { MOCK_NOAUTH = 0, MOCK_AUTH = 1, MOCK_REJECT = 2 };
|
||||
|
||||
struct mock {
|
||||
struct UASYNC *ua;
|
||||
socket_t listen_sock;
|
||||
void *listen_id;
|
||||
socket_t conn_sock;
|
||||
void *conn_id;
|
||||
uint8_t mode;
|
||||
uint8_t state; // 0=greeting, 1=auth, 2=request, 3=relay
|
||||
uint8_t buf[512];
|
||||
size_t buf_len;
|
||||
int got_connect;
|
||||
};
|
||||
|
||||
static void mock_send(struct mock *m, const uint8_t *d, size_t n) {
|
||||
ssize_t s = send(m->conn_sock, d, n, 0);
|
||||
(void)s;
|
||||
}
|
||||
|
||||
static void mock_process(struct mock *m) {
|
||||
for (;;) {
|
||||
if (m->state == 0) { // greeting
|
||||
if (m->buf_len < 3) return;
|
||||
uint8_t nm = m->buf[1];
|
||||
if (m->buf_len < (size_t)(2 + nm)) return;
|
||||
if (m->mode == MOCK_AUTH) { uint8_t r[] = {0x05, 0x02}; mock_send(m, r, 2); m->state = 1; }
|
||||
else { uint8_t r[] = {0x05, 0x00}; mock_send(m, r, 2); m->state = 2; }
|
||||
size_t c = 2 + nm; memmove(m->buf, m->buf + c, m->buf_len - c); m->buf_len -= c;
|
||||
continue;
|
||||
}
|
||||
if (m->state == 1) { // auth (RFC1929)
|
||||
if (m->buf_len < 2) return;
|
||||
size_t ulen = m->buf[1];
|
||||
if (m->buf_len < 2 + ulen + 1) return;
|
||||
size_t plen = m->buf[2 + ulen];
|
||||
size_t total = 2 + ulen + 1 + plen;
|
||||
if (m->buf_len < total) return;
|
||||
uint8_t r[] = {0x01, 0x00}; mock_send(m, r, 2); m->state = 2;
|
||||
memmove(m->buf, m->buf + total, m->buf_len - total); m->buf_len -= total;
|
||||
continue;
|
||||
}
|
||||
if (m->state == 2) { // CONNECT request
|
||||
if (m->buf_len < 4) return;
|
||||
uint8_t atyp = m->buf[3];
|
||||
size_t need = 4;
|
||||
if (atyp == 0x01) need += 6;
|
||||
else if (atyp == 0x03) { if (m->buf_len < 5) return; need += 1 + (size_t)m->buf[4] + 2; }
|
||||
else if (atyp == 0x04) need += 18;
|
||||
else return;
|
||||
if (m->buf_len < need) return;
|
||||
if (m->mode == MOCK_REJECT) { uint8_t r[] = {0x05, 0x05, 0x00, 0x01, 0,0,0,0, 0,0}; mock_send(m, r, 10); }
|
||||
else { uint8_t r[] = {0x05, 0x00, 0x00, 0x01, 0,0,0,0, 0,0}; mock_send(m, r, 10); m->got_connect = 1; }
|
||||
m->state = 3;
|
||||
memmove(m->buf, m->buf + need, m->buf_len - need); m->buf_len -= need;
|
||||
continue;
|
||||
}
|
||||
while (m->buf_len > 0) { // relay: echo
|
||||
mock_send(m, m->buf, 1);
|
||||
memmove(m->buf, m->buf + 1, m->buf_len - 1); m->buf_len -= 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mock_read_cb(socket_t sock, void *arg) {
|
||||
struct mock *m = (struct mock *)arg;
|
||||
(void)sock;
|
||||
uint8_t tmp[512];
|
||||
ssize_t n = recv(m->conn_sock, tmp, sizeof(tmp), 0);
|
||||
if (n <= 0) return;
|
||||
memcpy(m->buf + m->buf_len, tmp, (size_t)n);
|
||||
m->buf_len += (size_t)n;
|
||||
mock_process(m);
|
||||
}
|
||||
|
||||
static void mock_accept_cb(socket_t sock, void *arg) {
|
||||
struct mock *m = (struct mock *)arg;
|
||||
struct sockaddr_storage sa; socklen_t sl = sizeof(sa);
|
||||
m->conn_sock = accept(sock, (struct sockaddr *)&sa, &sl);
|
||||
if (m->conn_sock == SOCKET_INVALID) return;
|
||||
socket_set_nonblocking(m->conn_sock);
|
||||
m->conn_id = uasync_add_socket_t(m->ua, m->conn_sock, mock_read_cb, NULL, NULL, m);
|
||||
}
|
||||
|
||||
static int mock_start(struct mock *m, struct UASYNC *ua, int port, uint8_t mode) {
|
||||
memset(m, 0, sizeof(*m));
|
||||
m->ua = ua; m->mode = mode; m->conn_sock = SOCKET_INVALID;
|
||||
m->listen_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (m->listen_sock == SOCKET_INVALID) return -1;
|
||||
socket_set_reuseaddr(m->listen_sock, 1);
|
||||
socket_set_nonblocking(m->listen_sock);
|
||||
struct sockaddr_in a; memset(&a, 0, sizeof(a));
|
||||
a.sin_family = AF_INET; a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.sin_port = htons((uint16_t)port);
|
||||
if (bind(m->listen_sock, (struct sockaddr *)&a, sizeof(a)) < 0) return -1;
|
||||
if (listen(m->listen_sock, 8) < 0) return -1;
|
||||
m->listen_id = uasync_add_socket_t(ua, m->listen_sock, mock_accept_cb, NULL, NULL, m);
|
||||
return m->listen_id ? 0 : -1;
|
||||
}
|
||||
|
||||
static void mock_stop(struct mock *m) {
|
||||
if (m->conn_id) uasync_remove_socket_t(m->ua, m->conn_sock);
|
||||
if (m->conn_sock != SOCKET_INVALID) socket_close_wrapper(m->conn_sock);
|
||||
if (m->listen_id) uasync_remove_socket_t(m->ua, m->listen_sock);
|
||||
socket_close_wrapper(m->listen_sock);
|
||||
}
|
||||
|
||||
// ── Mock SOCKS5 UDP ASSOCIATE: TCP-control (greeting+associate) + UDP-релей с эхом ──
|
||||
|
||||
struct udp_mock {
|
||||
struct UASYNC *ua;
|
||||
socket_t listen_sock; // TCP-control listener
|
||||
void *listen_id;
|
||||
socket_t ctrl_sock; // принятый control-коннект
|
||||
void *ctrl_id;
|
||||
uint8_t cbuf[512];
|
||||
size_t cblen;
|
||||
uint8_t cstate; // 0=greeting, 1=associate
|
||||
socket_t udp_sock; // UDP-релей
|
||||
void *udp_id;
|
||||
uint16_t udp_port;
|
||||
int got_associate;
|
||||
int echo_count;
|
||||
uint8_t last_payload[256];
|
||||
size_t last_payload_len;
|
||||
struct sockaddr_storage last_peer;
|
||||
};
|
||||
|
||||
static void umock_ctrl_process(struct udp_mock *m) {
|
||||
for (;;) {
|
||||
if (m->cstate == 0) { // greeting
|
||||
if (m->cblen < 3) return;
|
||||
uint8_t nm = m->cbuf[1];
|
||||
if (m->cblen < (size_t)(2 + nm)) return;
|
||||
uint8_t r[] = {0x05, 0x00}; // no-auth
|
||||
send(m->ctrl_sock, r, 2, 0);
|
||||
m->cstate = 1;
|
||||
size_t c = 2 + nm; memmove(m->cbuf, m->cbuf + c, m->cblen - c); m->cblen -= c;
|
||||
continue;
|
||||
}
|
||||
if (m->cstate == 1) { // UDP ASSOCIATE request
|
||||
if (m->cblen < 4) return;
|
||||
uint8_t atyp = m->cbuf[3];
|
||||
size_t need = 4;
|
||||
if (atyp == 0x01) need += 6;
|
||||
else if (atyp == 0x04) need += 18;
|
||||
else return;
|
||||
if (m->cblen < need) return;
|
||||
uint8_t r[10];
|
||||
r[0] = 0x05; r[1] = 0x00; r[2] = 0x00; r[3] = 0x01;
|
||||
uint32_t ip = htonl(INADDR_LOOPBACK);
|
||||
memcpy(r + 4, &ip, 4);
|
||||
uint16_t port = htons(m->udp_port);
|
||||
memcpy(r + 8, &port, 2);
|
||||
send(m->ctrl_sock, r, 10, 0);
|
||||
m->got_associate++;
|
||||
m->cstate = 2;
|
||||
memmove(m->cbuf, m->cbuf + need, m->cblen - need); m->cblen -= need;
|
||||
continue;
|
||||
}
|
||||
m->cblen = 0; // idle
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void umock_ctrl_read_cb(socket_t sock, void *arg) {
|
||||
struct udp_mock *m = (struct udp_mock *)arg;
|
||||
(void)sock;
|
||||
uint8_t tmp[512];
|
||||
ssize_t n = recv(m->ctrl_sock, tmp, sizeof(tmp), 0);
|
||||
if (n <= 0) return;
|
||||
memcpy(m->cbuf + m->cblen, tmp, (size_t)n); m->cblen += (size_t)n;
|
||||
umock_ctrl_process(m);
|
||||
}
|
||||
|
||||
static void umock_accept_cb(socket_t sock, void *arg) {
|
||||
struct udp_mock *m = (struct udp_mock *)arg;
|
||||
struct sockaddr_storage sa; socklen_t sl = sizeof(sa);
|
||||
socket_t cs = accept(sock, (struct sockaddr *)&sa, &sl);
|
||||
if (cs == SOCKET_INVALID) return;
|
||||
socket_set_nonblocking(cs);
|
||||
m->ctrl_sock = cs;
|
||||
m->cstate = 0;
|
||||
m->cblen = 0;
|
||||
m->ctrl_id = uasync_add_socket_t(m->ua, cs, umock_ctrl_read_cb, NULL, NULL, m);
|
||||
}
|
||||
|
||||
// Релей: принять обёрнутую датаграмму, сохранить dst (peer) + payload, отправить эхо с SRC=peer.
|
||||
static void umock_udp_read_cb(socket_t sock, void *arg) {
|
||||
struct udp_mock *m = (struct udp_mock *)arg;
|
||||
(void)sock;
|
||||
uint8_t raw[2048];
|
||||
struct sockaddr_storage from; socklen_t fl = sizeof(from);
|
||||
ssize_t n = recvfrom(m->udp_sock, raw, sizeof(raw), 0, (struct sockaddr *)&from, &fl);
|
||||
if (n < 10 || raw[0] || raw[1] || raw[2]) return;
|
||||
uint8_t atyp = raw[3];
|
||||
size_t hlen;
|
||||
if (atyp == 0x01) hlen = 10;
|
||||
else if (atyp == 0x04) hlen = 22;
|
||||
else return;
|
||||
if ((size_t)n < hlen) return;
|
||||
|
||||
memset(&m->last_peer, 0, sizeof(m->last_peer));
|
||||
if (atyp == 0x01) {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)&m->last_peer;
|
||||
sa->sin_family = AF_INET;
|
||||
memcpy(&sa->sin_addr.s_addr, raw + 4, 4);
|
||||
memcpy(&sa->sin_port, raw + 8, 2);
|
||||
} else {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&m->last_peer;
|
||||
sa6->sin6_family = AF_INET6;
|
||||
memcpy(&sa6->sin6_addr, raw + 4, 16);
|
||||
memcpy(&sa6->sin6_port, raw + 20, 2);
|
||||
}
|
||||
size_t plen = (size_t)n - hlen;
|
||||
memcpy(m->last_payload, raw + hlen, plen);
|
||||
m->last_payload_len = plen;
|
||||
m->echo_count++;
|
||||
|
||||
uint8_t out[2048];
|
||||
size_t o = 0;
|
||||
out[o++] = 0; out[o++] = 0; out[o++] = 0;
|
||||
if (m->last_peer.ss_family == AF_INET) {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)&m->last_peer;
|
||||
out[o++] = 0x01;
|
||||
memcpy(out + o, &sa->sin_addr.s_addr, 4); o += 4;
|
||||
memcpy(out + o, &sa->sin_port, 2); o += 2;
|
||||
} else {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&m->last_peer;
|
||||
out[o++] = 0x04;
|
||||
memcpy(out + o, &sa6->sin6_addr, 16); o += 16;
|
||||
memcpy(out + o, &sa6->sin6_port, 2); o += 2;
|
||||
}
|
||||
memcpy(out + o, m->last_payload, plen); o += plen;
|
||||
sendto(m->udp_sock, out, o, 0, (struct sockaddr *)&from, fl);
|
||||
}
|
||||
|
||||
static int umock_start(struct udp_mock *m, struct UASYNC *ua, int listen_port) {
|
||||
memset(m, 0, sizeof(*m));
|
||||
m->ua = ua;
|
||||
m->ctrl_sock = SOCKET_INVALID;
|
||||
m->listen_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (m->listen_sock == SOCKET_INVALID) return -1;
|
||||
socket_set_reuseaddr(m->listen_sock, 1);
|
||||
socket_set_nonblocking(m->listen_sock);
|
||||
struct sockaddr_in a; memset(&a, 0, sizeof(a));
|
||||
a.sin_family = AF_INET; a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.sin_port = htons((uint16_t)listen_port);
|
||||
if (bind(m->listen_sock, (struct sockaddr *)&a, sizeof(a)) < 0) return -1;
|
||||
if (listen(m->listen_sock, 8) < 0) return -1;
|
||||
m->listen_id = uasync_add_socket_t(ua, m->listen_sock, umock_accept_cb, NULL, NULL, m);
|
||||
|
||||
m->udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (m->udp_sock == SOCKET_INVALID) return -1;
|
||||
socket_set_nonblocking(m->udp_sock);
|
||||
struct sockaddr_in ua_addr; memset(&ua_addr, 0, sizeof(ua_addr));
|
||||
ua_addr.sin_family = AF_INET; ua_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
if (bind(m->udp_sock, (struct sockaddr *)&ua_addr, sizeof(ua_addr)) < 0) return -1;
|
||||
struct sockaddr_in got; socklen_t gl = sizeof(got);
|
||||
getsockname(m->udp_sock, (struct sockaddr *)&got, &gl);
|
||||
m->udp_port = ntohs(got.sin_port);
|
||||
m->udp_id = uasync_add_socket_t(ua, m->udp_sock, umock_udp_read_cb, NULL, NULL, m);
|
||||
return (m->listen_id && m->udp_id) ? 0 : -1;
|
||||
}
|
||||
|
||||
static void umock_stop(struct udp_mock *m) {
|
||||
if (m->ctrl_id) uasync_remove_socket_t(m->ua, m->ctrl_sock);
|
||||
if (m->ctrl_sock != SOCKET_INVALID) socket_close_wrapper(m->ctrl_sock);
|
||||
if (m->listen_id) uasync_remove_socket_t(m->ua, m->listen_sock);
|
||||
socket_close_wrapper(m->listen_sock);
|
||||
if (m->udp_id) uasync_remove_socket_t(m->ua, m->udp_sock);
|
||||
socket_close_wrapper(m->udp_sock);
|
||||
}
|
||||
|
||||
static int g_su_ready = 0, g_su_err = 0;
|
||||
static void su_ready_cb(struct socks_udp *s, int err, void *arg) {
|
||||
(void)s; (void)arg;
|
||||
g_su_ready++;
|
||||
g_su_err = err;
|
||||
}
|
||||
|
||||
static socket_t g_sock = SOCKET_INVALID;
|
||||
static int g_err = 0;
|
||||
static int g_done = 0;
|
||||
static void dial_cb(socket_t sock, int err, void *arg) {
|
||||
(void)arg;
|
||||
g_sock = sock; g_err = err; g_done = 1;
|
||||
}
|
||||
static void read_echo_cb(socket_t sock, void *arg) {
|
||||
int *got = (int *)arg;
|
||||
uint8_t b;
|
||||
if (recv(sock, &b, 1, 0) == 1) *got = b;
|
||||
}
|
||||
|
||||
// Запустить dial, дождаться результата, вернуть 0 (успех) или err.
|
||||
static int run_dial(struct UASYNC *ua, struct socks_cfg *cfg, const char *target, uint16_t tport) {
|
||||
g_done = 0; g_sock = SOCKET_INVALID; g_err = 0;
|
||||
void *h = socks_dial(ua, cfg, target, tport, dial_cb, NULL, 0);
|
||||
if (!h) return -1;
|
||||
int ticks = 0;
|
||||
while (!g_done && ticks < 20000) { uasync_poll(ua, 10); ticks++; }
|
||||
if (!g_done) return -1;
|
||||
return g_err;
|
||||
}
|
||||
|
||||
static int test1_noauth_v4(void) {
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
struct mock m;
|
||||
TASSERT(mock_start(&m, ua, MOCK_PORT, MOCK_NOAUTH) == 0);
|
||||
struct socks_cfg cfg; memset(&cfg, 0, sizeof(cfg));
|
||||
strcpy(cfg.host, "127.0.0.1"); cfg.port = MOCK_PORT;
|
||||
|
||||
TASSERT(run_dial(ua, &cfg, "127.0.0.1", 12345) == 0);
|
||||
TASSERT(g_sock != SOCKET_INVALID);
|
||||
TASSERT(m.got_connect == 1);
|
||||
|
||||
int got = 0;
|
||||
void *sid = uasync_add_socket_t(ua, g_sock, read_echo_cb, NULL, NULL, &got);
|
||||
TASSERT(sid != NULL);
|
||||
uint8_t x = 'A';
|
||||
send(g_sock, &x, 1, 0);
|
||||
int ticks = 0;
|
||||
while (got == 0 && ticks < 5000) { uasync_poll(ua, 10); ticks++; }
|
||||
TASSERT(got == 'A');
|
||||
|
||||
uasync_remove_socket_t(ua, g_sock);
|
||||
socket_close_wrapper(g_sock);
|
||||
mock_stop(&m);
|
||||
uasync_destroy(ua, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test2_auth_domain(void) {
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
struct mock m;
|
||||
TASSERT(mock_start(&m, ua, MOCK_PORT, MOCK_AUTH) == 0);
|
||||
struct socks_cfg cfg; memset(&cfg, 0, sizeof(cfg));
|
||||
strcpy(cfg.host, "127.0.0.1"); cfg.port = MOCK_PORT;
|
||||
strcpy(cfg.user, "alice"); strcpy(cfg.pass, "secret");
|
||||
|
||||
TASSERT(run_dial(ua, &cfg, "example.com", 443) == 0);
|
||||
TASSERT(g_sock != SOCKET_INVALID);
|
||||
TASSERT(m.got_connect == 1);
|
||||
|
||||
socket_close_wrapper(g_sock);
|
||||
mock_stop(&m);
|
||||
uasync_destroy(ua, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test3_reject(void) {
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
struct mock m;
|
||||
TASSERT(mock_start(&m, ua, MOCK_PORT, MOCK_REJECT) == 0);
|
||||
struct socks_cfg cfg; memset(&cfg, 0, sizeof(cfg));
|
||||
strcpy(cfg.host, "127.0.0.1"); cfg.port = MOCK_PORT;
|
||||
|
||||
int err = run_dial(ua, &cfg, "127.0.0.1", 12345);
|
||||
TASSERT(err != 0);
|
||||
TASSERT(g_sock == SOCKET_INVALID);
|
||||
|
||||
mock_stop(&m);
|
||||
uasync_destroy(ua, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test4_udp_associate(void) {
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
struct udp_mock m;
|
||||
TASSERT(umock_start(&m, ua, MOCK_PORT) == 0);
|
||||
|
||||
socket_t lfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
TASSERT(lfd != SOCKET_INVALID);
|
||||
socket_set_nonblocking(lfd);
|
||||
struct sockaddr_in lb; memset(&lb, 0, sizeof(lb));
|
||||
lb.sin_family = AF_INET; lb.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
TASSERT(bind(lfd, (struct sockaddr *)&lb, sizeof(lb)) == 0);
|
||||
|
||||
struct socks_cfg cfg; memset(&cfg, 0, sizeof(cfg));
|
||||
strcpy(cfg.host, "127.0.0.1"); cfg.port = MOCK_PORT;
|
||||
|
||||
g_su_ready = 0; g_su_err = 0;
|
||||
struct socks_udp *su = socks_udp_associate(ua, &cfg, lfd, su_ready_cb, NULL);
|
||||
TASSERT(su != NULL);
|
||||
|
||||
int ticks = 0;
|
||||
while (g_su_ready == 0 && ticks < 20000) { uasync_poll(ua, 10); ticks++; }
|
||||
TASSERT(g_su_ready == 1);
|
||||
TASSERT(g_su_err == 0);
|
||||
TASSERT(m.got_associate == 1);
|
||||
|
||||
struct sockaddr_storage peer; memset(&peer, 0, sizeof(peer));
|
||||
struct sockaddr_in *p = (struct sockaddr_in *)&peer;
|
||||
p->sin_family = AF_INET; p->sin_addr.s_addr = htonl(INADDR_LOOPBACK); p->sin_port = htons(9999);
|
||||
|
||||
ssize_t snd = socks_udp_sendto(su, (const uint8_t *)"hello", 5, &peer);
|
||||
TASSERT(snd > 0);
|
||||
|
||||
uint8_t raw[2048];
|
||||
struct sockaddr_storage from; socklen_t fl = sizeof(from);
|
||||
ssize_t got = -1;
|
||||
ticks = 0;
|
||||
while (ticks < 5000) {
|
||||
got = recvfrom(lfd, raw, sizeof(raw), 0, (struct sockaddr *)&from, &fl);
|
||||
if (got > 0) break;
|
||||
uasync_poll(ua, 10); ticks++;
|
||||
}
|
||||
TASSERT(got > 0);
|
||||
|
||||
uint8_t payload[256];
|
||||
struct sockaddr_storage src;
|
||||
ssize_t plen = socks_udp_unwrap(su, raw, (size_t)got, payload, sizeof(payload), &src);
|
||||
TASSERT(plen == 5);
|
||||
TASSERT(memcmp(payload, "hello", 5) == 0);
|
||||
TASSERT(src.ss_family == AF_INET);
|
||||
TASSERT(((struct sockaddr_in *)&src)->sin_port == p->sin_port);
|
||||
|
||||
socks_udp_destroy(su);
|
||||
socket_close_wrapper(lfd);
|
||||
umock_stop(&m);
|
||||
uasync_destroy(ua, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test5_udp_reassociate(void) {
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
struct udp_mock m;
|
||||
TASSERT(umock_start(&m, ua, MOCK_PORT) == 0);
|
||||
|
||||
socket_t lfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
TASSERT(lfd != SOCKET_INVALID);
|
||||
socket_set_nonblocking(lfd);
|
||||
struct sockaddr_in lb; memset(&lb, 0, sizeof(lb));
|
||||
lb.sin_family = AF_INET; lb.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
TASSERT(bind(lfd, (struct sockaddr *)&lb, sizeof(lb)) == 0);
|
||||
|
||||
struct socks_cfg cfg; memset(&cfg, 0, sizeof(cfg));
|
||||
strcpy(cfg.host, "127.0.0.1"); cfg.port = MOCK_PORT;
|
||||
|
||||
g_su_ready = 0; g_su_err = 0;
|
||||
struct socks_udp *su = socks_udp_associate(ua, &cfg, lfd, su_ready_cb, NULL);
|
||||
TASSERT(su != NULL);
|
||||
|
||||
int ticks = 0;
|
||||
while (g_su_ready == 0 && ticks < 20000) { uasync_poll(ua, 10); ticks++; }
|
||||
TASSERT(g_su_ready == 1);
|
||||
TASSERT(m.got_associate == 1);
|
||||
|
||||
// Обрыв control-канала: закрываем серверную сторону → клиент должен пересоздать ассоциацию.
|
||||
if (m.ctrl_id) { uasync_remove_socket_t(m.ua, m.ctrl_sock); m.ctrl_id = NULL; }
|
||||
if (m.ctrl_sock != SOCKET_INVALID) { socket_close_wrapper(m.ctrl_sock); m.ctrl_sock = SOCKET_INVALID; }
|
||||
|
||||
int ready_before = g_su_ready;
|
||||
ticks = 0;
|
||||
while (g_su_ready == ready_before && ticks < 50000) { uasync_poll(ua, 10); ticks++; } // backoff ~1с
|
||||
TASSERT(g_su_ready > ready_before);
|
||||
TASSERT(m.got_associate >= 2);
|
||||
|
||||
// После re-associate канал снова работает.
|
||||
struct sockaddr_storage peer; memset(&peer, 0, sizeof(peer));
|
||||
struct sockaddr_in *p = (struct sockaddr_in *)&peer;
|
||||
p->sin_family = AF_INET; p->sin_addr.s_addr = htonl(INADDR_LOOPBACK); p->sin_port = htons(7777);
|
||||
|
||||
TASSERT(socks_udp_sendto(su, (const uint8_t *)"ping", 4, &peer) > 0);
|
||||
uint8_t raw[2048];
|
||||
struct sockaddr_storage from; socklen_t fl = sizeof(from);
|
||||
ssize_t got = -1;
|
||||
ticks = 0;
|
||||
while (ticks < 5000) {
|
||||
got = recvfrom(lfd, raw, sizeof(raw), 0, (struct sockaddr *)&from, &fl);
|
||||
if (got > 0) break;
|
||||
uasync_poll(ua, 10); ticks++;
|
||||
}
|
||||
TASSERT(got > 0);
|
||||
uint8_t payload[256];
|
||||
struct sockaddr_storage src;
|
||||
ssize_t plen = socks_udp_unwrap(su, raw, (size_t)got, payload, sizeof(payload), &src);
|
||||
TASSERT(plen == 4);
|
||||
TASSERT(memcmp(payload, "ping", 4) == 0);
|
||||
|
||||
socks_udp_destroy(su);
|
||||
socket_close_wrapper(lfd);
|
||||
umock_stop(&m);
|
||||
uasync_destroy(ua, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
socket_platform_init();
|
||||
|
||||
struct { const char *name; int (*fn)(void); } tests[] = {
|
||||
{"test1_noauth_v4", test1_noauth_v4},
|
||||
{"test2_auth_domain", test2_auth_domain},
|
||||
{"test3_reject", test3_reject},
|
||||
{"test4_udp_associate", test4_udp_associate},
|
||||
{"test5_udp_reassociate", test5_udp_reassociate},
|
||||
};
|
||||
int n = (int)(sizeof(tests) / sizeof(tests[0]));
|
||||
int passed = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
test_failed = 0;
|
||||
int r = tests[i].fn();
|
||||
if (r == 0) { passed++; DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "PASS: %s", tests[i].name); }
|
||||
else { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "FAIL: %s", tests[i].name); }
|
||||
}
|
||||
socket_platform_cleanup();
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Results: %d/%d passed", passed, n);
|
||||
return passed == n ? 0 : 1;
|
||||
}
|
||||
+8
-8
@@ -104,7 +104,7 @@ static int test1_sizes(void) {
|
||||
uint16_t port = BASE_PORT + 1;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
size_t sizes[] = {0, 1, 16, 17, 255, 256, 1000, 65535};
|
||||
int n_sizes = 8;
|
||||
@@ -144,7 +144,7 @@ static int test2_many(void) {
|
||||
uint16_t port = BASE_PORT + 2;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
int sent = 0, ticks = 0;
|
||||
while (srv.msg_count < 200 && ticks < 200) {
|
||||
@@ -185,7 +185,7 @@ static int test3_wrong_key(void) {
|
||||
|
||||
struct SC_MYKEYS rogue;
|
||||
TASSERT(sc_generate_keypair(&rogue) == SC_OK);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, rogue.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, rogue.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
int ticks = 0;
|
||||
while (ticks < 200) {
|
||||
@@ -210,7 +210,7 @@ static int test4_close(void) {
|
||||
uint16_t port = BASE_PORT + 4;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
int closed = 0, ticks = 0;
|
||||
while (!srv.closed && ticks < 200) {
|
||||
@@ -260,7 +260,7 @@ static int test5_multi(void) {
|
||||
|
||||
struct stcp_client *clients[NCLI] = {0};
|
||||
for (int i = 0; i < NCLI; i++) {
|
||||
clients[i] = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &clip[i], NULL, NULL, peer_close_cb, &clip[i], NULL, 0, NULL);
|
||||
clients[i] = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &clip[i], NULL, NULL, peer_close_cb, &clip[i], NULL, 0, NULL, NULL);
|
||||
TASSERT(clients[i]);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ static int test6_interleaved(void) {
|
||||
uint16_t port = BASE_PORT + 6;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
int round = 0, ticks = 0;
|
||||
while (srv.msg_count < 50 || cli.msg_count < 50) {
|
||||
@@ -343,7 +343,7 @@ static int test7_bulk_4mb(void) {
|
||||
uint16_t port = BASE_PORT + 7;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
#define N_BULK 64
|
||||
#define SZ_BULK 65535
|
||||
@@ -382,7 +382,7 @@ static int test8_srv_recv_close(void) {
|
||||
uint16_t port = BASE_PORT + 8;
|
||||
|
||||
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL, NULL); TASSERT(sc);
|
||||
|
||||
int ticks = 0;
|
||||
while ((!srv.ready || !cli.ready) && ticks < 200) { uasync_poll(ua, 10); ticks++; }
|
||||
|
||||
@@ -52,7 +52,7 @@ static int test1_basic(void) {
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", BASE_PORT + 1, &c_keys,
|
||||
s_keys.public_key, NULL,
|
||||
0, NULL,
|
||||
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
|
||||
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL);
|
||||
TASSERT(sc);
|
||||
|
||||
int ticks = 0;
|
||||
@@ -81,7 +81,7 @@ static int test2_wrong_key(void) {
|
||||
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", BASE_PORT + 2, &c_keys,
|
||||
rogue.public_key, NULL,
|
||||
0, NULL,
|
||||
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
|
||||
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL);
|
||||
TASSERT(sc);
|
||||
|
||||
int ticks = 0;
|
||||
|
||||
Reference in new issue
Block a user