Files
utun2/tests/test_stcp.c
T
evgeny 1340ab123b reality/stcp: fix OOB read in key_share parse, padding clamp, shbuf leak
- reality_parse_client_hello: bound shares_len by extension data length
  (len-2) to prevent stack-buffer-overflow from malformed ClientHello
- stcp handshake: reject padding_size > STCP_HS_PADDING_MAX (512)
- reality_ch_body_cb: free shbuf on stcp_try_send error (leak)
- tests: fuzz key_share parse; raw-socket handshake control/clamp/garbage

Signed-off-by: uTun <dev@utun>
2026-09-18 17:20:19 +03:00

574 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// test_stcp.c — comprehensive STCP integration tests
#include "stcp.h"
#include "stcp_server.h"
#include "stcp_client.h"
#include "secure_channel.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include "../lib/socket_compat.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int tests_passed = 0, tests_total = 0;
static struct SC_MYKEYS s_keys, c_keys;
#define BASE_PORT 23456
#define TASSERT(cond) do { \
if (!(cond)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, " FAIL: %s", #cond); return 1; } \
} while(0)
#define TRUN(name) do { \
tests_total++; \
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "--- %s ---", name); \
int _r = name(); \
if (_r == 0) { tests_passed++; DEBUG_INFO(DEBUG_CATEGORY_GENERAL, " PASS"); } \
} while(0)
// ======================= peer helper =======================
struct test_peer {
struct stcp_conn *conn;
struct ll_queue *rx, *tx;
int ready, closed, close_err, msg_count;
uint8_t *accum;
size_t accum_len, accum_cap;
};
static void peer_rx_cb(struct ll_queue *q, void *arg) {
struct test_peer *p = (struct test_peer *)arg;
struct ll_entry *e = queue_data_get(q);
if (!e) { queue_resume_callback(q); return; }
p->msg_count++;
size_t need = p->accum_len + e->len;
if (need > p->accum_cap) { p->accum_cap = need + 4096; p->accum = u_realloc(p->accum, p->accum_cap); }
memcpy(p->accum + p->accum_len, e->dgram, e->len);
p->accum_len += e->len;
queue_entry_free(e);
queue_resume_callback(q);
if (p->conn) stcp_rx_resume_if_needed(p->conn);
}
static void peer_close_cb(struct stcp_conn *conn, int err, void *arg) {
(void)conn;
struct test_peer *p = (struct test_peer *)arg;
p->closed = 1; p->close_err = err;
}
static void setup_peer(struct test_peer *p, struct stcp_conn *conn) {
p->conn = conn;
p->rx = queue_new(conn->ua, 0, 0, 0, "rx");
p->tx = queue_new(conn->ua, 0, 0, 0, "tx");
queue_set_threshold(p->rx, STCP_RX_QUEUE_MAX_PACKETS, STCP_RX_QUEUE_MAX_BYTES);
queue_set_callback(p->rx, peer_rx_cb, p);
stcp_conn_set_rx_queue(conn, p->rx);
stcp_conn_set_tx_queue(conn, p->tx);
p->ready = 1;
}
static void server_connect_cb(struct stcp_conn *conn, void *arg) {
struct test_peer *p = (struct test_peer *)arg;
setup_peer(p, conn);
}
static void client_ready_cb(struct stcp_conn *conn, void *arg) {
struct test_peer *p = (struct test_peer *)arg;
setup_peer(p, conn);
}
static void peer_cleanup(struct test_peer *p) {
if (p->rx) { queue_free(p->rx); p->rx = NULL; }
if (p->tx) { queue_free(p->tx); p->tx = NULL; }
if (p->accum) { u_free(p->accum); p->accum = NULL; }
}
static int peer_send(struct test_peer *p, const uint8_t *data, size_t len) {
struct ll_entry *e = queue_entry_new(0);
if (!e) return -1;
e->dgram = u_malloc(len ? len : 1);
if (!e->dgram) { queue_entry_free(e); return -1; }
if (len) memcpy(e->dgram, data, len);
e->len = (uint16_t)len;
queue_data_put(p->tx, e);
return 0;
}
// ======================= test 1: handshake + all message sizes =======================
static int test1_sizes(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
size_t sizes[] = {0, 1, 16, 17, 255, 256, 1000, 65535};
int n_sizes = 8;
size_t total = 0; for (int i = 0; i < n_sizes; i++) total += sizes[i];
uint8_t *payload = u_malloc(65536);
for (int i = 0; i < 65536; i++) payload[i] = (uint8_t)(i * 7 + 13);
int sent = 0, ticks = 0;
while (srv.msg_count < n_sizes && ticks < 200) {
uasync_poll(ua, 10);
if (srv.ready && cli.ready && !sent) {
for (int i = 0; i < n_sizes; i++) TASSERT(peer_send(&cli, payload, sizes[i]) == 0);
sent = 1;
}
ticks++;
}
TASSERT(srv.msg_count == n_sizes);
TASSERT(srv.accum_len == total);
size_t off = 0;
for (int i = 0; i < n_sizes; i++) {
TASSERT(memcmp(srv.accum + off, payload, sizes[i]) == 0);
off += sizes[i];
}
u_free(payload);
peer_cleanup(&srv); peer_cleanup(&cli);
if (srv.conn) stcp_conn_free(srv.conn);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 2: many sequential messages =======================
static int test2_many(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
int sent = 0, ticks = 0;
while (srv.msg_count < 200 && ticks < 200) {
uasync_poll(ua, 10);
if (srv.ready && cli.ready && !sent) {
for (int i = 0; i < 200; i++) {
uint8_t buf[8];
buf[0] = (uint8_t)(i >> 0); buf[1] = (uint8_t)(i >> 8);
buf[2] = (uint8_t)(i >> 16); buf[3] = (uint8_t)(i >> 24);
buf[4] = (uint8_t)(i * 3);
TASSERT(peer_send(&cli, buf, 5) == 0);
}
sent = 1;
}
ticks++;
}
TASSERT(srv.msg_count == 200);
TASSERT(srv.accum_len == 200 * 5);
for (int i = 0; i < 200; i++) {
uint32_t v; memcpy(&v, srv.accum + i * 5, 4); TASSERT(v == (uint32_t)i);
TASSERT(srv.accum[i * 5 + 4] == (uint8_t)(i * 3));
}
peer_cleanup(&srv); peer_cleanup(&cli);
if (srv.conn) stcp_conn_free(srv.conn);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 3: wrong peer pubkey =======================
static int test3_wrong_key(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
uint16_t port = BASE_PORT + 3;
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 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, NULL); TASSERT(sc);
int ticks = 0;
while (ticks < 200) {
uasync_poll(ua, 10);
if (cli.closed || srv.closed) break;
ticks++;
}
TASSERT(!cli.ready);
TASSERT(!srv.ready);
peer_cleanup(&srv); peer_cleanup(&cli);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 4: close detection =======================
static int test4_close(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
int closed = 0, ticks = 0;
while (!srv.closed && ticks < 200) {
uasync_poll(ua, 10);
if (srv.ready && cli.ready && !closed) {
uint8_t m = 0xAB; peer_send(&cli, &m, 1);
closed = 1;
}
if (closed && srv.msg_count >= 1 && cli.conn) {
stcp_conn_free(cli.conn); cli.conn = NULL;
cli.closed = 1;
}
ticks++;
}
TASSERT(srv.closed);
peer_cleanup(&srv); peer_cleanup(&cli);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 5: multiple concurrent clients =======================
static struct test_peer *g_multi_peers;
static int g_multi_idx, g_multi_max;
static void multi_connect_cb(struct stcp_conn *conn, void *arg) {
(void)arg;
int i = g_multi_idx++;
if (i >= g_multi_max) return;
struct test_peer *p = &g_multi_peers[i];
setup_peer(p, conn);
}
static int test5_multi(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
uint16_t port = BASE_PORT + 5;
#define NCLI 3
struct test_peer srvp[NCLI];
struct test_peer clip[NCLI];
memset(srvp, 0, sizeof(srvp)); memset(clip, 0, sizeof(clip));
g_multi_peers = srvp; g_multi_idx = 0; g_multi_max = NCLI;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, multi_connect_cb, NULL, NULL, NULL, AF_INET); TASSERT(ss);
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, NULL);
TASSERT(clients[i]);
}
int sent = 0, ticks = 0;
while (ticks < 200) {
uasync_poll(ua, 10);
if (!sent) {
int all_ready = 1;
for (int i = 0; i < NCLI; i++) if (!clip[i].ready || !srvp[i].ready) all_ready = 0;
if (all_ready) {
for (int i = 0; i < NCLI; i++) {
uint8_t buf[4]; buf[0] = (uint8_t)i; buf[1] = (uint8_t)(i * 17 + 42);
TASSERT(peer_send(&clip[i], buf, 2) == 0);
}
sent = 1;
}
}
if (sent) {
int all_got = 1;
for (int i = 0; i < NCLI; i++) if (srvp[i].msg_count < 1) all_got = 0;
if (all_got) break;
}
ticks++;
}
for (int i = 0; i < NCLI; i++) {
TASSERT(srvp[i].msg_count >= 1);
TASSERT(srvp[i].accum_len == 2);
TASSERT(srvp[i].accum[0] == (uint8_t)i);
TASSERT(srvp[i].accum[1] == (uint8_t)(i * 17 + 42));
}
for (int i = 0; i < NCLI; i++) {
peer_cleanup(&srvp[i]); peer_cleanup(&clip[i]);
if (srvp[i].conn) stcp_conn_free(srvp[i].conn);
stcp_client_destroy(clients[i]);
}
stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 6: interleaved send/recv =======================
static int test6_interleaved(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
int round = 0, ticks = 0;
while (srv.msg_count < 50 || cli.msg_count < 50) {
uasync_poll(ua, 10);
if (srv.ready && cli.ready && round < 50) {
uint8_t cb = (uint8_t)(round + 100);
uint8_t sb = (uint8_t)(round + 200);
if (peer_send(&cli, &cb, 1) == 0 && peer_send(&srv, &sb, 1) == 0) round++;
}
if (++ticks > 200) break;
}
TASSERT(srv.msg_count >= 50);
TASSERT(cli.msg_count >= 50);
for (int i = 0; i < 50; i++) {
TASSERT(srv.accum[i] == (uint8_t)(i + 100));
TASSERT(cli.accum[i] == (uint8_t)(i + 200));
}
peer_cleanup(&srv); peer_cleanup(&cli);
if (srv.conn) stcp_conn_free(srv.conn);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 7: 4MB bulk transfer (pending queue stress) =======================
static int test7_bulk_4mb(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
#define N_BULK 64
#define SZ_BULK 65535
size_t total = N_BULK * SZ_BULK; // 4,194,240 bytes
uint8_t *payload = u_malloc(total); TASSERT(payload);
for (size_t i = 0; i < total; i++) payload[i] = (uint8_t)(i * 7 + 13);
int sent = 0, ticks = 0;
while (srv.msg_count < N_BULK && ticks < 10000) {
uasync_poll(ua, 10);
if (srv.ready && cli.ready && !sent) {
for (int i = 0; i < N_BULK; i++)
TASSERT(peer_send(&cli, payload + i * SZ_BULK, SZ_BULK) == 0);
sent = 1;
}
ticks++;
}
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "bulk: server received %d msgs, %zu bytes in %d ticks", srv.msg_count, srv.accum_len, ticks);
TASSERT(srv.msg_count == N_BULK);
TASSERT(srv.accum_len == total);
TASSERT(memcmp(srv.accum, payload, total) == 0);
u_free(payload);
peer_cleanup(&srv); peer_cleanup(&cli);
if (srv.conn) stcp_conn_free(srv.conn);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 8: server recv error → close chain (allocated=1 + on_close + deferred free) =======================
static int test8_srv_recv_close(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0}, cli = {0};
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, NULL); TASSERT(sc);
int ticks = 0;
while ((!srv.ready || !cli.ready) && ticks < 200) { uasync_poll(ua, 10); ticks++; }
TASSERT(srv.ready && cli.ready);
socket_close_wrapper(cli.conn->sock); cli.conn->sock = SOCKET_INVALID;
ticks = 0;
while (!srv.closed && ticks < 200) { uasync_poll(ua, 10); ticks++; }
TASSERT(srv.closed);
// server conn freed via deferred free (allocated=1 + on_close=peer_close_cb)
srv.conn = NULL; // prevent explicit stcp_conn_free double-free
srv.ready = 0;
peer_cleanup(&srv); peer_cleanup(&cli);
stcp_client_destroy(sc); stcp_server_destroy(ss);
uasync_destroy(ua, 1); // flush deferred → stcp_conn_free(srv_conn)
return 0;
}
// ======================= raw TCP client helpers =======================
// Подключается к 127.0.0.1:port, отправляет len байт, оставляет сокет открытым.
// Возвращает открытый socket (SOCKET_INVALID при ошибке).
static socket_t raw_connect_send(uint16_t port, const uint8_t *data, size_t len) {
socket_t s = socket(AF_INET, SOCK_STREAM, 0);
if (s == SOCKET_INVALID) return SOCKET_INVALID;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) { socket_close_wrapper(s); return SOCKET_INVALID; }
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { socket_close_wrapper(s); return SOCKET_INVALID; }
size_t off = 0;
while (off < len) {
int n = (int)send(s, data + off, len - off, 0);
if (n <= 0) { socket_close_wrapper(s); return SOCKET_INVALID; }
off += (size_t)n;
}
return s;
}
// Собирает криптографически валидный client handshake (91 байт):
// salt(8) + obfuscated_client_pubkey(32) + зашифрованный hs(51) с заданным padding_size.
// Клиентская сторона: X25519(c_keys.priv, s_keys.pub), stream STCP_STREAM_CLIENT_SEND.
static int build_malicious_handshake(uint16_t padding_size, uint8_t *out) {
uint8_t salt[SC_PUBKEY_ENC_SALT_SIZE];
memset(salt, 0x5A, sizeof(salt));
memcpy(out, salt, SC_PUBKEY_ENC_SALT_SIZE);
if (sc_obfuscate_pubkey(salt, s_keys.public_key, c_keys.public_key,
out + SC_PUBKEY_ENC_SALT_SIZE) != SC_OK) return -1;
uint8_t plain[STCP_HS_PLAIN_SIZE];
memset(plain, 0, sizeof(plain));
plain[41] = (uint8_t)(padding_size & 0xff);
plain[42] = (uint8_t)(padding_size >> 8);
uint8_t enc[STCP_HS_ENC_CLIENT];
memcpy(enc, plain, STCP_HS_PLAIN_SIZE);
uint32_t crc = crc32_calc(plain, STCP_HS_PLAIN_SIZE);
enc[47] = (uint8_t)(crc >> 0); enc[48] = (uint8_t)(crc >> 8);
enc[49] = (uint8_t)(crc >> 16); enc[50] = (uint8_t)(crc >> 24);
struct secure_channel sc;
sc_init_ctx(&sc, &c_keys);
if (sc_set_peer_public_key(&sc, s_keys.public_key, SC_PEER_PUBKEY_BIN) != SC_OK) return -1;
struct sc_stream_state ss;
if (sc_stream_init(&sc, &ss, STCP_STREAM_CLIENT_SEND) != SC_OK) return -1;
int rc = sc_stream_xor(&ss, enc, STCP_HS_ENC_CLIENT);
sc_stream_cleanup(&ss);
if (rc != SC_OK) return -1;
memcpy(out + SC_PUBKEY_ENC_SIZE, enc, STCP_HS_ENC_CLIENT);
return 0;
}
// ======================= test 9: контроль — raw handshake с padding=8 принимается =======================
static int test9_raw_handshake_ok(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0};
uint16_t port = BASE_PORT + 9;
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);
uint8_t buf[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT + 8];
TASSERT(build_malicious_handshake(8, buf) == 0);
memset(buf + SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT, 0, 8); // 8 байт паддинга (как легитимный клиент)
socket_t s = raw_connect_send(port, buf, sizeof(buf));
TASSERT(s != SOCKET_INVALID);
int ticks = 0;
while (!srv.ready && !srv.closed && ticks < 200) { uasync_poll(ua, 10); ticks++; }
TASSERT(srv.ready);
TASSERT(!srv.closed);
socket_close_wrapper(s);
peer_cleanup(&srv);
if (srv.conn) stcp_conn_free(srv.conn);
stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 10: oversized padding отклоняется (clamp) =======================
static int test10_oversized_padding(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0};
uint16_t port = BASE_PORT + 10;
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);
uint8_t buf[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT];
TASSERT(build_malicious_handshake(0xFFFF, buf) == 0);
socket_t s = raw_connect_send(port, buf, sizeof(buf));
TASSERT(s != SOCKET_INVALID);
int ticks = 0;
while (!srv.closed && ticks < 200) { uasync_poll(ua, 10); ticks++; }
TASSERT(srv.closed);
TASSERT(!srv.ready);
socket_close_wrapper(s);
peer_cleanup(&srv);
srv.conn = NULL; // уже освобождён deferred-close (allocated=1)
stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= test 11: мусор в handshake не валит сервер =======================
static int test11_garbage_handshake(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct test_peer srv = {0};
uint16_t port = BASE_PORT + 11;
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);
uint8_t buf[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT];
for (int i = 0; i < (int)sizeof(buf); i++) buf[i] = (uint8_t)(i * 31 + 7);
socket_t s = raw_connect_send(port, buf, sizeof(buf));
TASSERT(s != SOCKET_INVALID);
int ticks = 0;
while (!srv.closed && ticks < 200) { uasync_poll(ua, 10); ticks++; }
TASSERT(srv.closed);
TASSERT(!srv.ready);
socket_close_wrapper(s);
peer_cleanup(&srv);
srv.conn = NULL;
stcp_server_destroy(ss);
uasync_destroy(ua, 1);
return 0;
}
// ======================= main =======================
int main(void) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_INFO);
debug_set_categories(DEBUG_CATEGORY_GENERAL | DEBUG_CATEGORY_SOCKET | DEBUG_CATEGORY_CRYPTO);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "============================================");
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "=== STCP Integration Tests ===");
TASSERT(sc_generate_keypair(&s_keys) == SC_OK);
TASSERT(sc_generate_keypair(&c_keys) == SC_OK);
TRUN(test1_sizes);
TRUN(test2_many);
TRUN(test3_wrong_key);
TRUN(test4_close);
TRUN(test5_multi);
TRUN(test6_interleaved);
TRUN(test7_bulk_4mb);
TRUN(test8_srv_recv_close);
TRUN(test9_raw_handshake_ok);
TRUN(test10_oversized_padding);
TRUN(test11_garbage_handshake);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "============================================");
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Results: %d/%d passed", tests_passed, tests_total);
return tests_passed == tests_total ? 0 : 1;
}