Browse Source

reality: использовать NTP-время вместо time(NULL) в анти-реплей проверке timestamp

Часы colo2 отстают на ~52с (ntpd выключен), что ломало reality auth
(diff < -30с = time_window). Теперь клиент и сервер передают
ntp_time_get_seconds() в reality_client_hello_build_at /
reality_server_hello_build_at вместо сырого системного времени.
v2
evgeny 2 weeks ago
parent
commit
27b591daee
  1. 14
      src/transport_layer/reality.c
  2. 7
      src/transport_layer/reality.h
  3. 5
      src/transport_layer/stcp_client.c
  4. 4
      src/transport_layer/stcp_server.c

14
src/transport_layer/reality.c

@ -488,9 +488,9 @@ static int reality_parse_client_hello(const uint8_t *ch, size_t ch_len,
return REALITY_OK;
}
int reality_server_hello_build(const struct reality_server_config *cfg,
const uint8_t *ch, size_t ch_len,
uint8_t *out, size_t out_cap, size_t *out_len) {
int reality_server_hello_build_at(const struct reality_server_config *cfg, uint32_t now_sec,
const uint8_t *ch, size_t ch_len,
uint8_t *out, size_t out_cap, size_t *out_len) {
if (!cfg || !ch || !out || !out_len || out_cap < REALITY_MAX_SH_SIZE) {
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "reality_server_hello_build: invalid args");
return REALITY_ERR_ARG;
@ -546,7 +546,7 @@ int reality_server_hello_build(const struct reality_server_config *cfg,
// сверка timestamp
uint32_t ts = ((uint32_t)plain[4] << 24) | ((uint32_t)plain[5] << 16) |
((uint32_t)plain[6] << 8) | plain[7];
int64_t now = (int64_t)time(NULL);
int64_t now = (int64_t)now_sec;
int64_t diff = now - (int64_t)ts;
if (diff < -(int64_t)cfg->time_window_sec || diff > (int64_t)cfg->time_window_sec) {
DEBUG_WARN(DEBUG_CATEGORY_REALITY, "reality_server_hello_build: timestamp out of window ts=%u now=%lld diff=%lld",
@ -623,3 +623,9 @@ int reality_server_hello_build(const struct reality_server_config *cfg,
DEBUG_INFO(DEBUG_CATEGORY_REALITY, "server hello built: total=%zu", *out_len);
return REALITY_OK;
}
int reality_server_hello_build(const struct reality_server_config *cfg,
const uint8_t *ch, size_t ch_len,
uint8_t *out, size_t out_cap, size_t *out_len) {
return reality_server_hello_build_at(cfg, (uint32_t)time(NULL), ch, ch_len, out, out_cap, out_len);
}

7
src/transport_layer/reality.h

@ -105,6 +105,13 @@ int reality_server_hello_build(const struct reality_server_config *cfg,
const uint8_t *ch, size_t ch_len,
uint8_t *out, size_t out_cap, size_t *out_len);
// То же, но с явным now (unix-секунды) для анти-реплей проверки timestamp.
// Вызывающий код передаёт синхронизированное время (ntp_time_get_seconds),
// чтобы не зависеть от сырого time(NULL) при рассинхроне системных часов.
int reality_server_hello_build_at(const struct reality_server_config *cfg, uint32_t now_sec,
const uint8_t *ch, size_t ch_len,
uint8_t *out, size_t out_cap, size_t *out_len);
// Сгенерировать X25519 пару ключей (для конфигурации: сервер хранит privkey,
// клиент — pubkey сервера). Возвращает REALITY_OK / REALITY_ERR_CRYPTO.
int reality_generate_keypair(uint8_t priv[REALITY_AUTH_KEY_SIZE],

5
src/transport_layer/stcp_client.c

@ -3,6 +3,7 @@
#include "secure_channel.h"
#include "crc32.h"
#include "etcp.h"
#include "../ntp_time.h"
#include "../lib/u_async.h"
#include "../lib/socket_compat.h"
#include "../lib/ll_queue.h"
@ -173,7 +174,9 @@ static void client_after_connect(struct stcp_conn *c) {
int opt = 1; setsockopt(c->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&opt, sizeof(opt));
if (cli->reality_enabled) {
uint8_t ch[REALITY_MAX_CH_SIZE]; size_t ch_len = 0;
if (reality_client_hello_build(&cli->reality_cfg, ch, sizeof(ch), &ch_len) != REALITY_OK) {
uint32_t now_sec = (c->etcp_conn && c->etcp_conn->instance)
? (uint32_t)ntp_time_get_seconds(c->etcp_conn->instance) : (uint32_t)time(NULL);
if (reality_client_hello_build_at(&cli->reality_cfg, now_sec, ch, sizeof(ch), &ch_len) != REALITY_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_REALITY, "stcp_client: ClientHello build failed");
stcp_conn_do_close(c, 1); return;
}

4
src/transport_layer/stcp_server.c

@ -11,6 +11,7 @@
#include "../lib/debug_config.h"
#include "../lib/platform_compat.h"
#include "../utun_instance.h"
#include "../ntp_time.h"
#include "etcp.h"
#include <stdlib.h>
#include <string.h>
@ -232,7 +233,8 @@ static void reality_ch_body_cb(struct stcp_conn *c, uint8_t *data, size_t len) {
uint8_t sh[REALITY_MAX_SH_SIZE];
size_t sh_len = 0;
int rc = reality_server_hello_build(&c->reality_srv, full, 5 + len, sh, sizeof(sh), &sh_len);
uint32_t now_sec = c->inst ? (uint32_t)ntp_time_get_seconds(c->inst) : (uint32_t)time(NULL);
int rc = reality_server_hello_build_at(&c->reality_srv, now_sec, full, 5 + len, sh, sizeof(sh), &sh_len);
if (rc == REALITY_OK) {
uint8_t *shbuf = u_malloc(sh_len);
if (!shbuf) { stcp_conn_do_close(c, ENOMEM); return; }

Loading…
Cancel
Save