transport: reality-релей idle-timeout (конфиг, дефолт 5с) + warn при >64 релеях; убрать лимит FD_SETSIZE; проверка socket_id в stcp_server
This commit is contained in:
1 parent
cc269e810c
commit
fb4343fca6
7 files changed
+51
-13
No files matched your search
+2
-1
@@ -918,12 +918,13 @@ static int parse_reality(const char *key, const char *value, struct reality_conf
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "time_window") == 0) { rc->time_window_sec = atoi(value); return 0; }
|
||||
if (strcmp(key, "relay_idle_timeout") == 0) { rc->relay_idle_timeout_sec = atoi(value); return 0; }
|
||||
if (strcmp(key, "fingerprint") == 0) {
|
||||
if (strcmp(value, "chrome") == 0) { rc->fingerprint = REALITY_FP_CHROME; return 0; }
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: unknown reality fingerprint '%s' (valid: chrome)", filename, line_num, value);
|
||||
return -1;
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown reality option '%s'. Valid: enabled, server_name, dest, short_id, short_ids, public_key, private_key, version, time_window, fingerprint", filename, line_num, key);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown reality option '%s'. Valid: enabled, server_name, dest, short_id, short_ids, public_key, private_key, version, time_window, relay_idle_timeout, fingerprint", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ void reality_config_set_defaults(struct reality_config *cfg) {
|
||||
cfg->has_private_key = 0;
|
||||
cfg->version[0] = 1; cfg->version[1] = 0; cfg->version[2] = 0;
|
||||
cfg->time_window_sec = 30;
|
||||
cfg->relay_idle_timeout_sec = 5;
|
||||
cfg->fingerprint = REALITY_FP_CHROME;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ struct reality_server_config {
|
||||
int short_id_count;
|
||||
uint8_t version[REALITY_VERSION_SIZE]; // принимаемая версия
|
||||
int64_t time_window_sec; // допуск timestamp (антиреплей)
|
||||
int relay_idle_timeout_sec; // idle-timeout релея неавторизованных (0=выкл)
|
||||
int fingerprint;
|
||||
};
|
||||
|
||||
@@ -75,6 +76,7 @@ struct reality_config {
|
||||
uint8_t has_private_key;
|
||||
uint8_t version[REALITY_VERSION_SIZE]; // версия протокола
|
||||
int time_window_sec;
|
||||
int relay_idle_timeout_sec; // idle-timeout релея неавторизованных (0=выкл)
|
||||
int fingerprint;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#endif
|
||||
|
||||
#define RELAY_IO_BUF 65536
|
||||
#define RELAY_WARN_CONNS 64
|
||||
|
||||
#ifdef _WIN32
|
||||
#define RELAY_SHUT_WR SD_SEND
|
||||
@@ -36,6 +37,9 @@ struct reality_relay {
|
||||
void *dest_sid;
|
||||
int connecting; // 1 = ждём завершения connect() к dest
|
||||
|
||||
void *idle_timer; // handle таймера простоя (NULL если выключен)
|
||||
int idle_timeout_tb; // время простоя в 0.1ms (0 = таймер выключен)
|
||||
|
||||
char host[256]; // dest hostname (для async DNS и логирования)
|
||||
uint16_t port; // dest port
|
||||
struct adns_query *dns_q; // pending async DNS query (NULL если нет)
|
||||
@@ -53,8 +57,11 @@ struct reality_relay {
|
||||
};
|
||||
|
||||
static struct reality_relay *g_relays = NULL; // активные релеи
|
||||
static int g_relay_count = 0; // число активных релеев (для warn)
|
||||
|
||||
static void relay_free(struct reality_relay *r);
|
||||
static void relay_touch(struct reality_relay *r);
|
||||
static void relay_idle_timeout_cb(void *arg);
|
||||
static void relay_flush_c2d(struct reality_relay *r);
|
||||
static void relay_flush_d2c(struct reality_relay *r);
|
||||
static void relay_client_read_cb(socket_t sock, void *arg);
|
||||
@@ -69,12 +76,14 @@ static void relay_free_cb(void *arg) {
|
||||
static void relay_free(struct reality_relay *r) {
|
||||
if (!r || r->closed) return;
|
||||
r->closed = 1;
|
||||
g_relay_count--;
|
||||
{ // вынуть из реестра активных релеев
|
||||
struct reality_relay **pp = &g_relays;
|
||||
while (*pp && *pp != r) pp = &(*pp)->next;
|
||||
if (*pp) *pp = r->next;
|
||||
r->next = NULL;
|
||||
}
|
||||
if (r->idle_timer) { uasync_cancel_timeout(r->ua, r->idle_timer); r->idle_timer = NULL; }
|
||||
if (r->dns_q) { adns_cancel(r->dns_q); r->dns_q = NULL; }
|
||||
if (r->client_sid) { uasync_remove_socket_t(r->ua, r->client_sock); r->client_sid = NULL; }
|
||||
if (r->dest_sid) { uasync_remove_socket_t(r->ua, r->dest_sock); r->dest_sid = NULL; }
|
||||
@@ -86,6 +95,21 @@ static void relay_free(struct reality_relay *r) {
|
||||
uasync_call_soon(r->ua, r, relay_free_cb);
|
||||
}
|
||||
|
||||
// Перезапустить таймер простоя: сброс на любую активность (чтение данных).
|
||||
static void relay_touch(struct reality_relay *r) {
|
||||
if (r->idle_timeout_tb <= 0) return;
|
||||
if (r->idle_timer) { uasync_cancel_timeout(r->ua, r->idle_timer); r->idle_timer = NULL; }
|
||||
r->idle_timer = uasync_set_timeout(r->ua, r->idle_timeout_tb, r, relay_idle_timeout_cb, "relay_idle");
|
||||
}
|
||||
|
||||
static void relay_idle_timeout_cb(void *arg) {
|
||||
struct reality_relay *r = (struct reality_relay *)arg;
|
||||
r->idle_timer = NULL; // handle освобождён process_timeouts сразу после колбэка
|
||||
DEBUG_WARN(DEBUG_CATEGORY_REALITY, "reality_relay: idle timeout %ds c2d=%zu d2c=%zu — closing",
|
||||
r->idle_timeout_tb / 10000, r->bytes_c2d, r->bytes_d2c);
|
||||
relay_free(r);
|
||||
}
|
||||
|
||||
static void relay_flush_c2d(struct reality_relay *r) {
|
||||
if (!r->c2d) return;
|
||||
while (r->c2d_off < r->c2d_len) {
|
||||
@@ -157,6 +181,7 @@ static void relay_client_read_cb(socket_t sock, void *arg) {
|
||||
#endif
|
||||
r->c2d = buf; r->c2d_len = (size_t)n; r->c2d_off = 0;
|
||||
uasync_set_socket_read(r->ua, r->client_sid, 0); // backpressure
|
||||
relay_touch(r);
|
||||
relay_flush_c2d(r);
|
||||
}
|
||||
|
||||
@@ -183,6 +208,7 @@ static void relay_dest_read_cb(socket_t sock, void *arg) {
|
||||
}
|
||||
r->d2c = buf; r->d2c_len = (size_t)n; r->d2c_off = 0;
|
||||
uasync_set_socket_read(r->ua, r->dest_sid, 0); // backpressure
|
||||
relay_touch(r);
|
||||
relay_flush_d2c(r);
|
||||
}
|
||||
|
||||
@@ -263,7 +289,8 @@ static void relay_dns_done_cb(const struct adns_result *res, void *arg) {
|
||||
|
||||
int reality_relay_start(struct UASYNC *ua, socket_t client_sock,
|
||||
const char *dest,
|
||||
const uint8_t *initial_data, size_t initial_len) {
|
||||
const uint8_t *initial_data, size_t initial_len,
|
||||
int idle_timeout_sec) {
|
||||
if (!ua || client_sock == SOCKET_INVALID || !dest || !dest[0]) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "reality_relay_start: invalid args");
|
||||
return -1;
|
||||
@@ -275,7 +302,12 @@ int reality_relay_start(struct UASYNC *ua, socket_t client_sock,
|
||||
r->client_sock = client_sock;
|
||||
r->dest_sock = SOCKET_INVALID;
|
||||
r->connecting = 1;
|
||||
r->idle_timeout_tb = idle_timeout_sec > 0 ? idle_timeout_sec * 10000 : 0;
|
||||
r->next = g_relays; g_relays = r;
|
||||
g_relay_count++;
|
||||
if (g_relay_count > RELAY_WARN_CONNS)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_REALITY, "reality_relay: %d concurrent relays (over %d) — возможен скан-флуд", g_relay_count, RELAY_WARN_CONNS);
|
||||
relay_touch(r); // таймер покрывает DNS + connect (застрявший connect тоже чистится)
|
||||
|
||||
// берём владение client_sock сразу (снимаем старую регистрацию) — до парсинга,
|
||||
// чтобы любая ошибка ниже не оставила сокет зарегистрированным в uasync.
|
||||
|
||||
@@ -21,10 +21,13 @@ struct UASYNC;
|
||||
// в uasync) и проксирует его на dest ("host:port").
|
||||
// initial_data/initial_len — уже прочитанные байты от клиента (ClientHello),
|
||||
// отправляются на dest первыми (буфер КОПИРУЕТСЯ — владение остаётся у вызывающего).
|
||||
// idle_timeout_sec — время простоя (без трафика в обе стороны), после которого
|
||||
// релей принудительно закрывается; 0 = таймер выключен.
|
||||
// Возвращает 0 = ok, -1 = ошибка (client_sock уже закрыт внутри).
|
||||
int reality_relay_start(struct UASYNC *ua, socket_t client_sock,
|
||||
const char *dest,
|
||||
const uint8_t *initial_data, size_t initial_len);
|
||||
const uint8_t *initial_data, size_t initial_len,
|
||||
int idle_timeout_sec);
|
||||
|
||||
// Принудительно завершить все активные релеи (вызывается при shutdown).
|
||||
// Освобождение отложено через uasync_call_soon — после вызова нужно
|
||||
|
||||
@@ -196,6 +196,7 @@ void stcp_server_set_reality(struct stcp_server *srv, const struct reality_confi
|
||||
srv->reality_srv.short_id_count = rc->short_id_count;
|
||||
memcpy(srv->reality_srv.version, rc->version, REALITY_VERSION_SIZE);
|
||||
srv->reality_srv.time_window_sec = rc->time_window_sec;
|
||||
srv->reality_srv.relay_idle_timeout_sec = rc->relay_idle_timeout_sec;
|
||||
srv->reality_srv.fingerprint = rc->fingerprint;
|
||||
snprintf(srv->reality_dest, sizeof(srv->reality_dest), "%s", rc->dest);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "stcp_server_set_reality: enabled, short_ids=%d dest=%s", rc->short_id_count, rc->dest);
|
||||
@@ -216,7 +217,7 @@ static void reality_server_start_relay(struct stcp_conn *c,
|
||||
c->socket_id = NULL;
|
||||
c->sock = SOCKET_INVALID;
|
||||
|
||||
reality_relay_start(c->ua, cli_sock, c->reality_dest, init, init_len);
|
||||
reality_relay_start(c->ua, cli_sock, c->reality_dest, init, init_len, c->reality_srv.relay_idle_timeout_sec);
|
||||
u_free(init); /* reality_relay_start копирует данные в свой буфер — владение остаётся у нас */
|
||||
stcp_conn_do_close(c, 0);
|
||||
}
|
||||
@@ -307,6 +308,12 @@ static void server_accept_cb(socket_t listen_sock, void *arg) {
|
||||
c->on_close = srv->close_cb;
|
||||
c->close_arg = srv->close_arg;
|
||||
c->socket_id = uasync_add_socket_t(srv->ua, cli_sock, server_conn_read_cb, stcp_write_cb, NULL, "stcp_conn", c);
|
||||
if (!c->socket_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server: uasync_add_socket_t failed for accepted fd=%d", (int)cli_sock);
|
||||
socket_close_wrapper(cli_sock);
|
||||
u_free(c);
|
||||
return;
|
||||
}
|
||||
c->inst = srv->inst;
|
||||
c->device_type = srv->inst ? srv->inst->client_type : 0;
|
||||
c->keepalive_interval = srv->inst ? srv->inst->keepalive_interval : 200;
|
||||
|
||||
Reference in new issue
Block a user