Browse Source
- route_crypto_encode/decode: автономный пред/пост-обработчик пакета (encrypt-then-sign, стандартный Ed25519 вместо sc_stream_sign) - одна функция отправки etcp_route_send/etcp_router_conn_send с bitmask mode - формат доставки: [svc_id][src][dst][rx_flags][payload] (статус подписи/шифрования) - ROUTER_INFLIGHT хранит финальный wire-пакет (чинит потерю подписи при ретрансмите) - дедуп инициализации: router_conn_reset/free_queues - учёт inflight через inflight_q count (seq присваивается на enqueue)v2
25 changed files with 537 additions and 580 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,160 @@
|
||||
// route_crypto.c — пред/пост-обработка SVC_ROUTE пакетов (шифрование + подпись)
|
||||
#include "route_crypto.h" |
||||
#include "utun_instance.h" |
||||
#include "topo_node.h" |
||||
#include "../transport_layer/secure_channel.h" |
||||
#include "../lib/debug_config.h" |
||||
#include "../lib/mem.h" |
||||
#include <string.h> |
||||
|
||||
// ECDH-контекст для пира (кэш в inst->e2e_ctx_cache). NULL = нет NODEINFO / ECDH не удался.
|
||||
static struct secure_channel* route_crypto_e2e_ctx(struct UTUN_INSTANCE* inst, uint64_t peer_node_id) { |
||||
for (int i = 0; i < E2E_CTX_CACHE_SIZE; i++) { |
||||
if (inst->e2e_ctx_cache[i].valid && inst->e2e_ctx_cache[i].peer_node_id == peer_node_id) |
||||
return &inst->e2e_ctx_cache[i].ctx; |
||||
} |
||||
struct TOPO_NODE* tn = topo_node_registry_find(inst->topo_groups, peer_node_id); |
||||
if (!tn) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto: no NODEINFO for peer=%016llx", (unsigned long long)peer_node_id); |
||||
return NULL; |
||||
} |
||||
int slot = -1; |
||||
for (int i = 0; i < E2E_CTX_CACHE_SIZE; i++) { |
||||
if (!inst->e2e_ctx_cache[i].valid) { slot = i; break; } |
||||
} |
||||
if (slot < 0) slot = 0; |
||||
sc_init_ctx(&inst->e2e_ctx_cache[slot].ctx, &inst->my_keys); |
||||
if (sc_set_peer_public_key(&inst->e2e_ctx_cache[slot].ctx, tn->public_key, SC_PEER_PUBKEY_BIN) != SC_OK) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto: ECDH failed peer=%016llx", (unsigned long long)peer_node_id); |
||||
inst->e2e_ctx_cache[slot].valid = 0; |
||||
return NULL; |
||||
} |
||||
inst->e2e_ctx_cache[slot].peer_node_id = peer_node_id; |
||||
inst->e2e_ctx_cache[slot].valid = 1; |
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "route_crypto: new context for peer=%016llx slot=%d", |
||||
(unsigned long long)peer_node_id, slot); |
||||
return &inst->e2e_ctx_cache[slot].ctx; |
||||
} |
||||
|
||||
int route_crypto_encode(struct UTUN_INSTANCE* inst, uint64_t peer_node_id, |
||||
const uint8_t* base, size_t base_len, int mode, |
||||
uint8_t** out, size_t* out_len) { |
||||
if (!inst || !base || base_len < SVC_ROUTE_HDR_SIZE || !out || !out_len) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_encode: invalid args inst=%p base=%p len=%zu mode=%d", |
||||
(void*)inst, (const void*)base, base_len, mode); |
||||
return -1; |
||||
} |
||||
const uint8_t* pl = base + SVC_ROUTE_HDR_SIZE; |
||||
size_t pl_len = base_len - SVC_ROUTE_HDR_SIZE; |
||||
|
||||
const uint8_t* body = pl; |
||||
size_t body_len = pl_len; |
||||
uint8_t* enc_buf = NULL; |
||||
|
||||
if (mode & ROUTE_CRYPTO_ENCRYPT) { |
||||
struct secure_channel* e2e = route_crypto_e2e_ctx(inst, peer_node_id); |
||||
if (!e2e) return -1; |
||||
size_t enc_cap = pl_len + SC_NONCE_SIZE + SC_CRC32_SIZE + SC_TAG_SIZE; |
||||
enc_buf = u_malloc(enc_cap); |
||||
if (!enc_buf) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_encode: enc_buf alloc fail"); return -1; } |
||||
size_t enc_len = 0; |
||||
if (sc_encrypt(e2e, pl, pl_len, enc_buf, &enc_len) != SC_OK) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_encode: sc_encrypt FAIL peer=%016llx len=%zu", |
||||
(unsigned long long)peer_node_id, pl_len); |
||||
u_free(enc_buf); return -1; |
||||
} |
||||
body = enc_buf; body_len = enc_len; |
||||
} |
||||
|
||||
size_t sig_len = (mode & ROUTE_CRYPTO_SIGN) ? SC_SIGN_SIZE : 0; |
||||
size_t total = SVC_ROUTE_HDR_SIZE + body_len + sig_len; |
||||
uint8_t* dgram = u_malloc(total); |
||||
if (!dgram) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_encode: out alloc fail"); if (enc_buf) u_free(enc_buf); return -1; } |
||||
memcpy(dgram, base, SVC_ROUTE_HDR_SIZE); |
||||
memcpy(dgram + SVC_ROUTE_HDR_SIZE, body, body_len); |
||||
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram; |
||||
if (mode & ROUTE_CRYPTO_ENCRYPT) hdr->flags |= ROUTER_FLAG_ENCRYPTED; |
||||
if (mode & ROUTE_CRYPTO_SIGN) { |
||||
hdr->flags |= ROUTER_FLAG_SIGNED; |
||||
if (sc_ed25519_sign(inst->my_ed25519_privkey, dgram, SVC_ROUTE_HDR_SIZE + body_len, |
||||
dgram + SVC_ROUTE_HDR_SIZE + body_len) != SC_OK) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_encode: sign FAIL peer=%016llx", (unsigned long long)peer_node_id); |
||||
u_free(dgram); if (enc_buf) u_free(enc_buf); return -1; |
||||
} |
||||
} |
||||
|
||||
if (enc_buf) u_free(enc_buf); |
||||
*out = dgram; *out_len = total; |
||||
return 0; |
||||
} |
||||
|
||||
int route_crypto_decode(struct UTUN_INSTANCE* inst, |
||||
const uint8_t* wire, size_t wire_len, |
||||
uint8_t** out, size_t* out_len, uint8_t* rx_flags) { |
||||
if (!inst || !wire || wire_len < SVC_ROUTE_HDR_SIZE || !out || !out_len || !rx_flags) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: invalid args inst=%p wire=%p len=%zu", |
||||
(void*)inst, (const void*)wire, wire_len); |
||||
return -1; |
||||
} |
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)wire; |
||||
uint8_t fl = hdr->flags & (ROUTER_FLAG_ENCRYPTED | ROUTER_FLAG_SIGNED); |
||||
*rx_flags = fl; |
||||
|
||||
const uint8_t* body = wire + SVC_ROUTE_HDR_SIZE; |
||||
size_t body_len = wire_len - SVC_ROUTE_HDR_SIZE; |
||||
|
||||
if (fl & ROUTER_FLAG_SIGNED) { |
||||
if (body_len < SC_SIGN_SIZE) { |
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: SIGNED packet too short len=%zu from %016llx", |
||||
wire_len, (unsigned long long)hdr->src_node_id); |
||||
return -1; |
||||
} |
||||
size_t signed_len = SVC_ROUTE_HDR_SIZE + body_len - SC_SIGN_SIZE; |
||||
const uint8_t* sig = wire + signed_len; |
||||
struct TOPO_NODE* sni = topo_node_registry_find(inst->topo_groups, hdr->src_node_id); |
||||
if (!sni) { |
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: SIGNED from unknown node %016llx — dropping", |
||||
(unsigned long long)hdr->src_node_id); |
||||
return -1; |
||||
} |
||||
uint8_t zero[SC_PUBKEY_SIZE] = {0}; |
||||
if (memcmp(sni->ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) { |
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: no Ed25519 pubkey for node %016llx — dropping", |
||||
(unsigned long long)hdr->src_node_id); |
||||
return -1; |
||||
} |
||||
if (sc_ed25519_verify(sni->ed25519_public_key, wire, signed_len, sig) != SC_OK) { |
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: signature FAILED for node %016llx svc_id=%u — dropping", |
||||
(unsigned long long)hdr->src_node_id, hdr->svc_id); |
||||
return -1; |
||||
} |
||||
body_len -= SC_SIGN_SIZE; |
||||
} |
||||
|
||||
uint8_t* pt_buf = NULL; |
||||
if (fl & ROUTER_FLAG_ENCRYPTED) { |
||||
struct secure_channel* e2e = route_crypto_e2e_ctx(inst, hdr->src_node_id); |
||||
if (!e2e) return -1; |
||||
pt_buf = u_malloc(body_len); |
||||
size_t pt_len = 0; |
||||
if (!pt_buf || sc_decrypt(e2e, body, body_len, pt_buf, &pt_len) != SC_OK) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: decrypt FAIL src=%016llx svc=%u len=%zu", |
||||
(unsigned long long)hdr->src_node_id, hdr->svc_id, body_len); |
||||
if (pt_buf) u_free(pt_buf); |
||||
return -1; |
||||
} |
||||
body = pt_buf; body_len = pt_len; |
||||
} |
||||
|
||||
size_t total = SVC_ROUTE_HDR_SIZE + body_len; |
||||
uint8_t* dgram = u_malloc(total); |
||||
if (!dgram) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "route_crypto_decode: out alloc fail"); if (pt_buf) u_free(pt_buf); return -1; } |
||||
memcpy(dgram, wire, SVC_ROUTE_HDR_SIZE); |
||||
memcpy(dgram + SVC_ROUTE_HDR_SIZE, body, body_len); |
||||
((struct SVC_ROUTE_HDR*)dgram)->flags &= ~(ROUTER_FLAG_ENCRYPTED | ROUTER_FLAG_SIGNED); |
||||
|
||||
if (pt_buf) u_free(pt_buf); |
||||
*out = dgram; *out_len = total; |
||||
return 0; |
||||
} |
||||
@ -0,0 +1,46 @@
|
||||
// route_crypto.h — пред/пост-обработка SVC_ROUTE пакетов (шифрование + подпись)
|
||||
// Автономный модуль: из одного пакета формирует другой, пригодный для отправки/обработки.
|
||||
//
|
||||
// encode(): вызывается в начале функции отправки.
|
||||
// [SVC_ROUTE_HDR][plaintext] + mode → [SVC_ROUTE_HDR][payload][sig?]
|
||||
// decode(): вызывается перед вызовом сервисного коллбэка.
|
||||
// [SVC_ROUTE_HDR][payload][sig?] → [SVC_ROUTE_HDR][plaintext]
|
||||
//
|
||||
// Порядок кодирования: encrypt-then-sign (подпись поверх всего протокола, включая шифртекст).
|
||||
// При ошибке декодирования (плохая подпись / не удалось расшифровать) пакет дропается.
|
||||
#ifndef ROUTE_CRYPTO_H |
||||
#define ROUTE_CRYPTO_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include "etcp_router.h" |
||||
|
||||
struct UTUN_INSTANCE; |
||||
|
||||
// Флаги трансформации (bitmask), совпадают с битами SVC_ROUTE_HDR.flags
|
||||
#define ROUTE_CRYPTO_ENCRYPT ROUTER_FLAG_ENCRYPTED // 0x04
|
||||
#define ROUTE_CRYPTO_SIGN ROUTER_FLAG_SIGNED // 0x08
|
||||
|
||||
// Кодировать пакет: base = [SVC_ROUTE_HDR][plaintext payload].
|
||||
// mode — битовая маска ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT.
|
||||
// Возвращает новый буфер (u_malloc) с финальным пакетом. 0 = успех, <0 = ошибка.
|
||||
int route_crypto_encode(struct UTUN_INSTANCE* inst, uint64_t peer_node_id, |
||||
const uint8_t* base, size_t base_len, int mode, |
||||
uint8_t** out, size_t* out_len); |
||||
|
||||
// Декодировать пакет: wire = [SVC_ROUTE_HDR][payload][sig?].
|
||||
// Проверяет подпись и/или расшифровывает. Через *rx_flags сообщает, что было на wire
|
||||
// (ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT). Возвращает [SVC_ROUTE_HDR][plaintext] с очищенными флагами.
|
||||
// 0 = успех, <0 = ошибка (пакет дропается).
|
||||
int route_crypto_decode(struct UTUN_INSTANCE* inst, |
||||
const uint8_t* wire, size_t wire_len, |
||||
uint8_t** out, size_t* out_len, uint8_t* rx_flags); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
#endif // ROUTE_CRYPTO_H
|
||||
Loading…
Reference in new issue