You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

112 lines
6.9 KiB

/* Реальный relay: нормализация replay, сохранение хвоста, независимое владение instance. */
#include "stcp_server.h"
#include "utun_instance.h"
#include "../lib/mem.h"
#include "../lib/debug_config.h"
#include <string.h>
#include <time.h>
#include <errno.h>
#define CHECK(x) do { if (!(x)) { DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "FAIL line=%d: %s", __LINE__, #x); return 1; } } while (0)
static uint32_t fake_now;
time_t __wrap_ntp_time_get_seconds(struct UTUN_INSTANCE *inst) { (void)inst; return fake_now; }
struct destination_peer { socket_t sock; struct UASYNC *ua; uint8_t data[4096]; size_t len; };
struct destination { socket_t sock; struct UASYNC *ua; unsigned count; struct destination_peer peers[4]; };
static void destination_read(socket_t sock, void *arg) {
struct destination_peer *p = arg;
ssize_t n = recv(sock, p->data + p->len, sizeof(p->data) - p->len, 0);
if (n > 0) p->len += (size_t)n;
else if (!n) { uasync_remove_socket_t(p->ua, sock); socket_close_wrapper(sock); p->sock = SOCKET_INVALID; }
}
static void destination_accept(socket_t sock, void *arg) {
struct destination *d = arg;
socket_t peer = accept(sock, NULL, NULL);
if (peer == SOCKET_INVALID || d->count >= 4) return;
struct destination_peer *p = &d->peers[d->count++];
p->sock = peer; p->ua = d->ua;
socket_set_nonblocking(peer);
uasync_add_socket_t(d->ua, peer, destination_read, NULL, NULL, "reality_test_dest", p);
}
static void unexpected_stcp(struct stcp_conn *c, void *arg) {
(void)c; (void)arg;
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "unexpected STCP before Client Finished");
}
static socket_t connect_to(uint16_t port) {
socket_t s = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address = {0};
address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (struct sockaddr *)&address, sizeof(address))) { socket_close_wrapper(s); return SOCKET_INVALID; }
socket_set_nonblocking(s);
return s;
}
static void poll_some(struct UASYNC *ua) { for (unsigned i = 0; i < 100; i++) uasync_poll(ua, 0); }
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG); debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_WARN);
size_t allocated = u_get_allocated_count();
struct UASYNC *ua = uasync_create(); CHECK(ua);
struct UTUN_INSTANCE a = {0}, b = {0}; a.ua = b.ua = ua;
struct SC_MYKEYS keys; CHECK(sc_generate_keypair(&keys) == SC_OK);
struct reality_config cfg; reality_config_set_defaults(&cfg);
struct reality_client_config cc; reality_client_config_set_defaults(&cc);
cfg.enabled = 1; cfg.short_id_count = 1;
CHECK(!reality_generate_keypair(cfg.private_key, cc.server_static_pubkey));
strcpy(cc.server_name, "www.microsoft.com");
struct destination dest = {0}; dest.ua = ua;
dest.sock = socket(AF_INET, SOCK_STREAM, 0); CHECK(dest.sock != SOCKET_INVALID);
struct sockaddr_in address = {0}; address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
CHECK(!bind(dest.sock, (struct sockaddr *)&address, sizeof(address)) && !listen(dest.sock, 4));
socklen_t size = sizeof(address); CHECK(!getsockname(dest.sock, (struct sockaddr *)&address, &size));
socket_set_nonblocking(dest.sock);
CHECK(uasync_add_socket_t(ua, dest.sock, destination_accept, NULL, NULL, "reality_test_listener", &dest));
snprintf(cfg.dest, sizeof(cfg.dest), "127.0.0.1:%u", ntohs(address.sin_port));
uint16_t port = 32000 + (uint16_t)(time(NULL) % 1000);
struct stcp_server *sa = stcp_server_create(ua, port, &keys, NULL, &a, unexpected_stcp, NULL, NULL, NULL, AF_INET);
struct stcp_server *sb = stcp_server_create(ua, port + 1, &keys, NULL, &b, unexpected_stcp, NULL, NULL, NULL, AF_INET);
CHECK(sa && sb); stcp_server_set_reality(sa, &cfg); stcp_server_set_reality(sb, &cfg);
uint8_t ch[REALITY_MAX_CH_SIZE], answer[4096]; size_t cn;
fake_now = (uint32_t)time(NULL);
CHECK(!reality_client_hello_build_at(&cc, fake_now + 30, ch, sizeof(ch), &cn));
socket_t first = connect_to(port); CHECK(first != SOCKET_INVALID && send(first, ch, cn, 0) == (ssize_t)cn);
poll_some(ua);
CHECK(recv(first, answer, sizeof(answer), 0) >= 127 && answer[0] == 22);
/* Через 31 секунду тот же future timestamp ещё допустим: replay обязан оставаться в кеше. */
fake_now += 31;
uint8_t split[4096]; size_t first_part = 11, rest = cn - 5 - first_part;
memcpy(split, ch, 5); split[3] = 0; split[4] = first_part;
memcpy(split + 5, ch + 5, first_part);
size_t pos = 5 + first_part;
memcpy(split + pos, ch, 5); split[pos + 2] = 3; split[pos + 3] = (uint8_t)(rest >> 8); split[pos + 4] = (uint8_t)rest;
memcpy(split + pos + 5, ch + 5 + first_part, rest);
pos += 5 + rest;
const uint8_t tail[] = {20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 4, 1, 2, 3, 4};
memcpy(split + pos, tail, sizeof(tail)); pos += sizeof(tail);
socket_t replay = connect_to(port); CHECK(replay != SOCKET_INVALID);
CHECK(send(replay, split, 7, 0) == 7); poll_some(ua);
CHECK(send(replay, split + 7, pos - 7, 0) == (ssize_t)(pos - 7)); poll_some(ua);
CHECK(dest.count == 1 && dest.peers[0].len == pos && !memcmp(dest.peers[0].data, split, pos));
CHECK(a.reality_owner.relay_count == 1);
socket_t other = connect_to(port + 1); CHECK(other != SOCKET_INVALID && send(other, ch, cn, 0) == (ssize_t)cn);
poll_some(ua);
CHECK(recv(other, answer, sizeof(answer), 0) >= 127 && answer[0] == 22 && dest.count == 1);
cc.short_id[0] = 1;
CHECK(!reality_client_hello_build_at(&cc, fake_now, ch, sizeof(ch), &cn));
socket_t unauthorized = connect_to(port + 1);
CHECK(unauthorized != SOCKET_INVALID && send(unauthorized, ch, cn, 0) == (ssize_t)cn);
poll_some(ua); CHECK(dest.count == 2 && b.reality_owner.relay_count == 1);
stcp_server_destroy(sb); reality_owner_cleanup(&b.reality_owner); poll_some(ua);
CHECK(a.reality_owner.relay_count == 1 && dest.peers[1].sock == SOCKET_INVALID);
CHECK(send(replay, tail, sizeof(tail), 0) == sizeof(tail)); poll_some(ua);
CHECK(dest.peers[0].len == pos + sizeof(tail) && !memcmp(dest.peers[0].data + pos, tail, sizeof(tail)));
stcp_server_destroy(sa); reality_owner_cleanup(&a.reality_owner); poll_some(ua);
socket_close_wrapper(first); socket_close_wrapper(replay); socket_close_wrapper(other); socket_close_wrapper(unauthorized);
for (unsigned i = 0; i < dest.count; i++) if (dest.peers[i].sock != SOCKET_INVALID) {
uasync_remove_socket_t(ua, dest.peers[i].sock); socket_close_wrapper(dest.peers[i].sock);
}
uasync_remove_socket_t(ua, dest.sock); socket_close_wrapper(dest.sock); uasync_destroy(ua, 1);
CHECK(u_get_allocated_count() == allocated);
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "fragmented replay, future expiry, exact fallback bytes, instance isolation and teardown passed");
return 0;
}