Scope router access policies to CHAT without changing UTUN

This commit is contained in:
evgeny committed 2026-11-03 19:49:58 +01:00
1 parent 5ac829363e
commit 31c8f35b6b
3 files changed
+38 -3

No files matched your search

+30 -3
View File
@@ -70,8 +70,16 @@ static uint32_t router_effective_max_inflight(struct ETCP_ROUTER_CONN* rconn);
static void router_update_inflight_limit(struct ETCP_ROUTER_CONN* rconn);
static void router_update_minrtt(struct ETCP_ROUTER_CONN* rconn);
/* Общий service ID может ограничивать только CHAT; неизвестная группа не получает обход проверки. */
static int router_policy_applies(struct UTUN_INSTANCE* inst, uint64_t group_id, uint8_t svc) {
if (!inst->router_bindings.chat_policy[svc]) return 1;
struct TOPO_GROUP* group = inst->topo_groups ? topo_groups_find(inst->topo_groups, group_id) : NULL;
return !group || group->group_type != TOPO_GROUP_TYPE_UTUN;
}
/* Политика не изменяет router; отказ не закрывает канал из чужого стека отправки. */
static int router_allowed(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t peer, uint8_t svc) {
if (!router_policy_applies(inst, group, svc)) return 1;
int (*authorize)(struct UTUN_INSTANCE*, uint64_t, uint64_t) = inst->router_bindings.authorize[svc];
if (!authorize || authorize(inst, group, peer) == 1) return 1;
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router access denied: group=%016llx peer=%016llx svc=%u",
@@ -98,7 +106,8 @@ static int router_source_send(struct ETCP_CONN* conn, struct ll_entry* e) {
struct UTUN_INSTANCE* inst = conn->instance;
const struct SVC_ROUTE_HDR* header = (const struct SVC_ROUTE_HDR*)e->dgram;
if (!router_allowed(inst, header->group_id, header->dst_node_id, header->svc_id)) return -1;
if (e->len == SVC_ROUTE_HDR_SIZE && (inst->router_bindings.required_crypto[header->svc_id] & ROUTER_FLAG_SIGNED)) {
if (e->len == SVC_ROUTE_HDR_SIZE && router_policy_applies(inst, header->group_id, header->svc_id)
&& (inst->router_bindings.required_crypto[header->svc_id] & ROUTER_FLAG_SIGNED)) {
uint8_t* signed_wire = NULL; size_t size = 0;
if (route_crypto_encode(inst, header->dst_node_id, e->dgram, e->len, ROUTE_CRYPTO_SIGN, &signed_wire, &size)) return -1;
queue_dgram_free(e); e->dgram = signed_wire; e->len = size;
@@ -913,7 +922,8 @@ static void router_retrans_timer_cb(void* arg) {
// Скопировать plaintext и mode в send_q, выделить seq; кодирование выполняется при отправке после handshake.
static int router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t len, int force, int mode) {
if (!router_allowed(rconn->inst, rconn->group_id, rconn->remote_node_id, rconn->svc_id)) return -1;
uint8_t required = rconn->inst->router_bindings.required_crypto[rconn->svc_id];
uint8_t required = router_policy_applies(rconn->inst, rconn->group_id, rconn->svc_id)
? rconn->inst->router_bindings.required_crypto[rconn->svc_id] : 0;
if ((mode & required) != required) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router send: insufficient crypto svc=%u peer=%016llx flags=%02x required=%02x",
rconn->svc_id, (unsigned long long)rconn->remote_node_id, mode, required);
@@ -1501,7 +1511,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
router_forward_transit(inst, entry, (struct SVC_ROUTE_HDR*)entry->dgram); return;
}
entry->len = body;
uint8_t required = inst->router_bindings.required_crypto[h->svc_id];
uint8_t required = router_policy_applies(inst, h->group_id, h->svc_id) ? inst->router_bindings.required_crypto[h->svc_id] : 0;
if ((h->flags & (required & ROUTER_FLAG_SIGNED)) != (required & ROUTER_FLAG_SIGNED)) {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router receive: insufficient crypto svc=%u peer=%016llx flags=%02x required=%02x",
h->svc_id, (unsigned long long)h->src_node_id, h->flags, required);
@@ -1619,6 +1629,7 @@ int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn ca
inst->router_bindings.authorize[svc_id] = NULL;
inst->router_bindings.receive_ready[svc_id] = NULL;
inst->router_bindings.required_crypto[svc_id] = 0;
inst->router_bindings.chat_policy[svc_id] = 0;
return 0;
}
if (inst->router_bindings.callbacks[svc_id])
@@ -1639,6 +1650,7 @@ int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) {
inst->router_bindings.authorize[svc_id] = NULL;
inst->router_bindings.receive_ready[svc_id] = NULL;
inst->router_bindings.required_crypto[svc_id] = 0;
inst->router_bindings.chat_policy[svc_id] = 0;
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "svc_id=%u", svc_id);
return 0;
}
@@ -1665,6 +1677,21 @@ int etcp_router_set_authorize(struct UTUN_INSTANCE* inst, uint8_t svc_id,
return 0;
}
int etcp_router_set_chat_policy(struct UTUN_INSTANCE* inst, uint8_t svc_id, uint8_t flags,
int (*authorize)(struct UTUN_INSTANCE*, uint64_t, uint64_t)) {
if (!inst || !inst->router_bindings.callbacks[svc_id] || !authorize || !(flags & ROUTER_FLAG_SIGNED)
|| (flags & ~(ROUTER_FLAG_SIGNED | ROUTER_FLAG_ENCRYPTED))
|| inst->router_bindings.authorize[svc_id] || inst->router_bindings.required_crypto[svc_id]) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router CHAT policy invalid or already configured svc=%u flags=%02x", svc_id, flags);
return -1;
}
inst->router_bindings.required_crypto[svc_id] = flags;
inst->router_bindings.authorize[svc_id] = authorize;
inst->router_bindings.chat_policy[svc_id] = 1;
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router CHAT policy svc=%u required=%02x; UTUN unchanged", svc_id, flags);
return 0;
}
void etcp_router_revalidate_group(struct UTUN_INSTANCE* inst, uint64_t group_id) {
if (!inst) return;
for (;;) {
+7
View File
@@ -261,6 +261,7 @@ struct ETCP_ROUTER_BINDINGS {
int (*authorize[SVC_ROUTE_MAX_BINDINGS])(struct UTUN_INSTANCE*, uint64_t, uint64_t); // Допуск group/peer; 1 — разрешено.
int (*receive_ready[SVC_ROUTE_MAX_BINDINGS])(struct UTUN_INSTANCE*, uint64_t, uint64_t, const uint8_t*, size_t);
uint8_t required_crypto[SVC_ROUTE_MAX_BINDINGS]; // Обязательные ENCRYPTED/SIGNED для сервисных данных; 0 — без требования.
uint8_t chat_policy[SVC_ROUTE_MAX_BINDINGS]; // 1 — crypto/authorize не применяются к существующей UTUN-группе.
};
// ====================================================================
@@ -298,6 +299,12 @@ int etcp_router_require_crypto(struct UTUN_INSTANCE* inst, uint8_t svc_id, uint8
* Транзит не проверяется. Unbind очищает callback. 0/-1 с диагностикой. */
int etcp_router_set_authorize(struct UTUN_INSTANCE* inst, uint8_t svc_id,
int (*authorize)(struct UTUN_INSTANCE*, uint64_t, uint64_t));
/* Установить crypto и authorize общему сервису только для CHAT, сохранив обмен существующих UTUN-групп.
* До первого использования сервиса; требует bound callback, SIGNED, authorize и отсутствие прежней политики.
* Неизвестная группа проходит authorize (обычно получает отказ); сам scope не даёт ей разрешения.
* Ограничения чистоты authorize те же. Bind сохраняет scope, unbind очищает. 0/-1 с диагностикой. */
int etcp_router_set_chat_policy(struct UTUN_INSTANCE* inst, uint8_t svc_id, uint8_t flags,
int (*authorize)(struct UTUN_INSTANCE*, uint64_t, uint64_t));
/* После commit изменения допуска: закрыть запрещённые каналы группы, уведомить сервисы, очистить очереди.
* Не затрагивает общий ETCP и сервисы без authorize; callbacks могут менять список каналов. */
void etcp_router_revalidate_group(struct UTUN_INSTANCE* inst, uint64_t group_id);
+1
View File
@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <string.h>
#include "utun_instance.h"
#include "config_updater.h"
#include "broadcast.h"
#include "chat/member_sync.h"
#include "radio/radio.h"