diff --git a/cross-build-win.sh b/cross-build-win.sh index a0b3e1c1..00175bf9 100755 --- a/cross-build-win.sh +++ b/cross-build-win.sh @@ -203,7 +203,7 @@ SRC_SOURCES=( transport_layer/pkt_normalizer.c transport_layer/packet_dump.c transport_layer/etcp_api.c control_server.c firewall.c eim_nat.c nat_transport.c transport_layer/dummynet.c - etcp_router.c + etcp_router.c route_crypto.c proxy/udp_proxy.c proxy/socks_proxy.c lwip_tcp/lwip_pbuf.c ) diff --git a/src/Makefile.am b/src/Makefile.am index 7ec76031..fc5b4e14 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,6 +61,7 @@ utun_CORE_SOURCES = \ ntp_node_time.c \ proxy/tcp_proxy_client.c \ routing_layer/etcp_router.c \ + routing_layer/route_crypto.c \ proxy/tcp_proxy_server.c \ proxy/udp_proxy.c \ proxy/socks_proxy.c \ @@ -143,6 +144,7 @@ libutun_a_SOURCES = \ ntp_node_time.c \ proxy/tcp_proxy_client.c \ routing_layer/etcp_router.c \ + routing_layer/route_crypto.c \ proxy/tcp_proxy_server.c \ proxy/udp_proxy.c \ proxy/socks_proxy.c \ diff --git a/src/media_delivery/media_delivery.c b/src/media_delivery/media_delivery.c index 1ee2346c..2d03f371 100644 --- a/src/media_delivery/media_delivery.c +++ b/src/media_delivery/media_delivery.c @@ -412,7 +412,7 @@ static int md_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_n if (!e->dgram) { queue_entry_free(e); return -1; } e->dgram[0] = ETCP_RT_ID_MEDIA_DELIVERY; memcpy(e->dgram + 1, data, len); e->len = (uint16_t)(len + 1); - int rc = etcp_route_send(inst, group_id, dst_node_id, e, 1); + int rc = etcp_route_send(inst, group_id, dst_node_id, e, 1, 0); if (rc != 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "%s: md_send FAIL rc=%d dst=0x%016llx group=0x%016llx", MD_ID, rc, (unsigned long long)dst_node_id, (unsigned long long)group_id); diff --git a/src/media_delivery/media_download.c b/src/media_delivery/media_download.c index d14c1202..c046a9d3 100644 --- a/src/media_delivery/media_download.c +++ b/src/media_delivery/media_download.c @@ -72,7 +72,7 @@ static int md_dl_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t ds if (!e->dgram) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: u_malloc(%zu) failed for send to 0x%016llx", MDL_ID, len + 1, (unsigned long long)dst); queue_entry_free(e); return -1; } e->dgram[0] = ETCP_RT_ID_MEDIA_DELIVERY; memcpy(e->dgram + 1, data, len); e->len = (uint16_t)(len + 1); - int rc = etcp_route_send(inst, group_id, dst, e, 1); + int rc = etcp_route_send(inst, group_id, dst, e, 1, 0); if (rc != 0) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: etcp_route_send failed rc=%d to 0x%016llx group=0x%016llx", MDL_ID, rc, (unsigned long long)dst, (unsigned long long)group_id); u_free(e->dgram); queue_entry_free(e); } return rc; } diff --git a/src/nat_transport.c b/src/nat_transport.c index 727db025..4daa99f8 100644 --- a/src/nat_transport.c +++ b/src/nat_transport.c @@ -47,7 +47,7 @@ static void nat_transport_client_tun_out_cb(struct ll_queue* q, void* arg) { queue_dgram_free(pkt); queue_entry_free(pkt); queue_resume_callback(q); - int ret = etcp_route_send(inst, TOPO_GROUP_UTUN, tr->nat_via_node_id, new_entry, 0); + int ret = etcp_route_send(inst, TOPO_GROUP_UTUN, tr->nat_via_node_id, new_entry, 0, 0); if (ret != 0) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT client: etcp_route_send to provider %016llx failed", (unsigned long long)tr->nat_via_node_id); @@ -89,7 +89,7 @@ static void nat_transport_provider_tun_out_cb(struct ll_queue* q, void* arg) { queue_dgram_free(pkt); queue_entry_free(pkt); queue_resume_callback(q); - int send_ret = etcp_route_send(inst, TOPO_GROUP_UTUN, entry->src_node_id, new_entry, 0); + int send_ret = etcp_route_send(inst, TOPO_GROUP_UTUN, entry->src_node_id, new_entry, 0, 0); if (send_ret != 0) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT provider: etcp_route_send back to node %016llx failed", (unsigned long long)entry->src_node_id); diff --git a/src/proxy/icmp_proxy.c b/src/proxy/icmp_proxy.c index bd9eda0f..d5724da5 100644 --- a/src/proxy/icmp_proxy.c +++ b/src/proxy/icmp_proxy.c @@ -143,7 +143,7 @@ static void raw_read_cb(socket_t sock, void* arg) { memcpy(e->dgram + 12, &icmp_hdr->icmp_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; - int ret = etcp_route_send(g_icmp_ctx->inst, TOPO_GROUP_UTUN, r->client_node_id, e, 0); + int ret = etcp_route_send(g_icmp_ctx->inst, TOPO_GROUP_UTUN, r->client_node_id, e, 0, 0); if (ret != 0) DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "icmp_proxy: etcp_route_send reply failed: %d", ret); else DEBUG_INFO(DEBUG_CATEGORY_PROXY, "icmp_proxy: reply forwarded to client %016llx", (unsigned long long)r->client_node_id); u_free(r); @@ -180,7 +180,7 @@ static void exit_handle_request(struct ETCP_CONN* conn, struct ll_entry* entry) memcpy(e->dgram + 12, &echo_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; - etcp_route_send(inst, TOPO_GROUP_UTUN, client_node_id, e, 0); + etcp_route_send(inst, TOPO_GROUP_UTUN, client_node_id, e, 0, 0); } else queue_entry_free(e); } } else { @@ -244,7 +244,7 @@ int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, memcpy(e->dgram + 12, &echo_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; - return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0); + return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0, 0); } // ==================================================================== diff --git a/src/proxy/socks_proxy.c b/src/proxy/socks_proxy.c index 736d6b31..3b20e1b6 100644 --- a/src/proxy/socks_proxy.c +++ b/src/proxy/socks_proxy.c @@ -70,7 +70,7 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, queue_dgram_free(e); queue_entry_free(e); return -1; } e->len = (uint16_t)(TCP_PROXY_HDR_SIZE + len); - int ret = etcp_route_send(inst, group_id, dst, e, force); + int ret = etcp_route_send(inst, group_id, dst, e, force, 0); DEBUG_TRACE(DEBUG_CATEGORY_PROXY, "SOCKS send_msg subcmd=%02x sid=%08x len=%zu force=%d → ret=%d", subcmd, sid, len, force, ret); return ret; diff --git a/src/proxy/tcp_proxy_client.c b/src/proxy/tcp_proxy_client.c index e09dbb56..5930c406 100644 --- a/src/proxy/tcp_proxy_client.c +++ b/src/proxy/tcp_proxy_client.c @@ -79,7 +79,7 @@ static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t group_ memcpy(e->dgram + 2, &sid, 4); if (len > 0) memcpy(e->dgram + TCP_PROXY_HDR_SIZE, data, len); e->len = TCP_PROXY_HDR_SIZE + len; - return etcp_route_send(inst, group_id, dst, e, force); + return etcp_route_send(inst, group_id, dst, e, force, 0); } static int tcp_proxy_client_send_connect(struct tcp_proxy_client_conn* pc) { diff --git a/src/proxy/tcp_proxy_server.c b/src/proxy/tcp_proxy_server.c index dfb6d899..4a3a1b68 100644 --- a/src/proxy/tcp_proxy_server.c +++ b/src/proxy/tcp_proxy_server.c @@ -65,7 +65,7 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, queue_dgram_free(e); queue_entry_free(e); return -1; } e->len = TCP_PROXY_HDR_SIZE + len; - return etcp_route_send(inst, group_id, dst, e, force); + return etcp_route_send(inst, group_id, dst, e, force, 0); } static void close_retry_cb(void* arg) { diff --git a/src/proxy/udp_proxy.c b/src/proxy/udp_proxy.c index 32d9cd5f..f898f710 100644 --- a/src/proxy/udp_proxy.c +++ b/src/proxy/udp_proxy.c @@ -64,7 +64,7 @@ static void flow_read_cb(socket_t sock, void* arg) { memcpy(e->dgram + UDP_PROXY_HDR_SIZE, buf, n); e->len = UDP_PROXY_HDR_SIZE + n; - etcp_route_send(g_udp_ctx->inst, TOPO_GROUP_UTUN, f->client_node_id, e, 0); + etcp_route_send(g_udp_ctx->inst, TOPO_GROUP_UTUN, f->client_node_id, e, 0, 0); } // ==================================================================== @@ -168,7 +168,7 @@ int udp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, memcpy(e->dgram + 12, &dst_port, 2); if (payload_len > 0) memcpy(e->dgram + UDP_PROXY_HDR_SIZE, payload, payload_len); e->len = UDP_PROXY_HDR_SIZE + payload_len; - return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0); + return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0, 0); } // ==================================================================== diff --git a/src/routing_layer/conn_mgr_core.c b/src/routing_layer/conn_mgr_core.c index 8a32e46c..ada7b6a4 100644 --- a/src/routing_layer/conn_mgr_core.c +++ b/src/routing_layer/conn_mgr_core.c @@ -440,7 +440,7 @@ void conn_mgr_close(struct CONN_MGR_HANDLE* h) { pkt.cmd = ETCP_RT_ID_CONN_MGR; pkt.subcmd = CM_SUBCMD_DISCONNECT; pkt.node_id = entry->node_id; struct ll_entry* qe = queue_entry_new(0); if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); - etcp_route_send(entry->mgr->instance, entry->mgr->group->group_id, entry->node_id, qe, 1); } + etcp_route_send(entry->mgr->instance, entry->mgr->group->group_id, entry->node_id, qe, 1, 0); } /* NCD CLOSE — транспортный уровень (отправит CLOSE/KEEP_ALIVE через node_conn_direct) */ } cm_entry_cleanup(entry); u_free(h); @@ -458,7 +458,7 @@ int conn_mgr_send(struct CONN_MGR_HANDLE* h, struct ll_entry* e) { entry->last_traffic_tb = get_time_tb(); struct ETCP_ROUTER_CONN* r = etcp_router_conn_get(entry->mgr->instance, entry->mgr->group->group_id, entry->node_id, ETCP_RT_ID_CONN_MGR); if (!r) { queue_entry_free(e); return -1; } - int ret = etcp_router_conn_send(r, e->dgram, e->len); queue_entry_free(e); return ret; + int ret = etcp_router_conn_send(r, e->dgram, e->len, 0); queue_entry_free(e); return ret; } /* ═══════ локальное сканирование ═══════ */ @@ -676,7 +676,7 @@ void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) { for (uint8_t i=0;idgram=pkt; qe->len=(uint16_t)sz; etcp_route_send(entry->mgr->instance, group->group_id, entry->node_id, qe, 1); + qe->dgram=pkt; qe->len=(uint16_t)sz; etcp_route_send(entry->mgr->instance, group->group_id, entry->node_id, qe, 1, 0); struct cm_reverse_pending* rp = u_calloc(1, sizeof(*rp)); if (rp) { rp->request_id=req_id; rp->entry=entry; rp->next=entry->mgr->reverse_pending; entry->mgr->reverse_pending=rp; } entry->main.timer = uasync_set_timeout(entry->mgr->instance->ua, CONN_MGR_CONNECT_REVERSE_TIMEOUT_MS*10, diff --git a/src/routing_layer/conn_mgr_indirect.c b/src/routing_layer/conn_mgr_indirect.c index 5798fb07..056ed5f6 100644 --- a/src/routing_layer/conn_mgr_indirect.c +++ b/src/routing_layer/conn_mgr_indirect.c @@ -26,7 +26,7 @@ void cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry) { for (uint8_t i=0;ibest_candidates[i]; struct ll_entry* qe = queue_entry_new(0); if (!qe) return; qe->dgram=u_malloc(sizeof(req)); memcpy(qe->dgram,&req,sizeof(req)); qe->len=sizeof(req); - etcp_route_send(mgr->instance, mgr->group->group_id, entry->node_id, qe, 1); + etcp_route_send(mgr->instance, mgr->group->group_id, entry->node_id, qe, 1, 0); entry->main.timer = uasync_set_timeout(mgr->instance->ua, CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS*10, entry, cm_exchange_timeout_cb, "conn_mgr_interm_exch"); struct cm_exchange_pending* ep = u_calloc(1,sizeof(*ep)); if (ep) { ep->request_id=entry->main.request_id; ep->entry=entry; ep->timer=entry->main.timer; ep->next=mgr->exchange_pending; mgr->exchange_pending=ep; } @@ -67,7 +67,7 @@ void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_ for(uint8_t i=0;imgr->group,all[i].nid); if(nq)pkt.selected[i].rtt=topo_get_chain_rtt(nq);} struct ll_entry* qe=queue_entry_new(0); - if(qe){qe->dgram=u_malloc(sizeof(pkt));memcpy(qe->dgram,&pkt,sizeof(pkt));qe->len=sizeof(pkt);etcp_route_send(entry->mgr->instance,entry->mgr->group->group_id,entry->node_id,qe,1);} + if(qe){qe->dgram=u_malloc(sizeof(pkt));memcpy(qe->dgram,&pkt,sizeof(pkt));qe->len=sizeof(pkt);etcp_route_send(entry->mgr->instance,entry->mgr->group->group_id,entry->node_id,qe,1,0);} entry->conn_type=CONN_TYPE_INDIRECT; entry->state=CONN_MGR_STATE_CONNECTED; DEBUG_INFO(DEBUG_CATEGORY_GENERAL,"conn_mgr: indirect OK for 0x%016llx via %u intermediaries",(unsigned long long)entry->node_id,sel); cm_update_nodeinfo(entry); cm_deliver_event(entry,CONN_EVENT_UP); @@ -140,6 +140,6 @@ void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CM_EXCHANGE_RE } size_t sz=offsetof(struct CM_EXCHANGE_RESP,your_candidates)+(size_t)resp.your_count*sizeof(struct CONN_MGR_CANDIDATE); struct ll_entry* qe=queue_entry_new(0); - if(qe){qe->dgram=u_malloc(sz);memcpy(qe->dgram,&resp,sz);qe->len=(uint16_t)sz;etcp_route_send(mgr->instance,mgr->group->group_id,conn->peer_node_id,qe,1);} + if(qe){qe->dgram=u_malloc(sz);memcpy(qe->dgram,&resp,sz);qe->len=(uint16_t)sz;etcp_route_send(mgr->instance,mgr->group->group_id,conn->peer_node_id,qe,1,0);} DEBUG_INFO(DEBUG_CATEGORY_GENERAL,"conn_mgr: sent EXCHANGE_RESP to 0x%016llx my=%u your=%u",(unsigned long long)conn->peer_node_id,resp.my_count,resp.your_count); } diff --git a/src/routing_layer/etcp_router.c b/src/routing_layer/etcp_router.c index 5f0eed70..5fd16d11 100644 --- a/src/routing_layer/etcp_router.c +++ b/src/routing_layer/etcp_router.c @@ -1,7 +1,8 @@ // etcp_router.c — Сервисный слой маршрутизации поверх ETCP -// Упрощённый TCP: восстановление порядка (recv_q), дедупликация, без переповторов +// Упрощённый TCP: восстановление порядка (recv_q), дедупликация, ретрансмиты (inflight_q) // ACK: периодическая отправка rx_seq (не чаще 100ms), idle-таймер для последнего seq // Inflight контроль через send_q: при переполнении — очередь + retry-таймер, без дропов +// Подпись/шифрование — в route_crypto.c (encode в начале отправки, decode перед коллбэком) /* @@ -12,6 +13,7 @@ in ---> {Q} -> [src, etcp] --> ... --> [dst,etcp] -> {asm_q} -> {buf q} ---> out */ #include "etcp_router.h" +#include "route_crypto.h" #include "etcp.h" #include "utun_instance.h" #include "topo_group.h" @@ -19,13 +21,8 @@ in ---> {Q} -> [src, etcp] --> ... --> [dst,etcp] -> {asm_q} -> {buf q} ---> out #include "../lib/mem.h" #include "../lib/ll_queue.h" #include "../lib/u_async.h" -#include "../transport_layer/secure_channel.h" #include -// Флаги метаданных элемента send_q (data[0]): bit0=encrypted, bit1=signed -#define SENDQ_FLAG_ENCRYPTED 0x01 -#define SENDQ_FLAG_SIGNED 0x02 - // ==================================================================== // Внутренние forward declarations // ==================================================================== @@ -34,8 +31,8 @@ static void router_idle_ack_timer_cb(void* arg); static void router_send_ack(struct ETCP_ROUTER_CONN* rconn); static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn); static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn); -static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* payload, size_t payload_len); -static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, uint8_t flag_bits, int is_signed); +static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* wire, size_t wire_len); +static void router_send_ctrl(struct ETCP_ROUTER_CONN* rconn, uint8_t flag_bits); static void router_send_rst(struct ETCP_ROUTER_CONN* rconn); static struct ETCP_CONN* router_send_conn(struct ETCP_ROUTER_CONN* rconn); static void router_send_kick(struct ETCP_ROUTER_CONN* rconn); @@ -47,12 +44,13 @@ static void router_no_route_retry_cb(void* arg); static void router_send_close_to_service(struct ETCP_ROUTER_CONN* rconn); static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn); static void router_close_finalize(void* arg); +static void router_conn_free_queues(struct ETCP_ROUTER_CONN* rconn); +static void router_conn_reset(struct ETCP_ROUTER_CONN* rconn); static void free_entry(struct ll_entry* e) { queue_dgram_free(e); queue_entry_free(e); } -static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry* entry, struct SVC_ROUTE_HDR* hdr, size_t* pl_len); static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN* rconn, uint32_t seq, uint64_t src_node_id, uint16_t ack_ts); static void router_forward_transit(struct UTUN_INSTANCE* inst, struct ll_entry* entry, struct SVC_ROUTE_HDR* hdr); static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN** prconn, struct SVC_ROUTE_HDR* hdr); -static void router_handle_data_packet(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, uint32_t seq, const uint8_t* pl, size_t pl_len); +static void router_handle_data_packet(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, uint32_t seq, const uint8_t* wire, size_t wire_len); static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_INFLIGHT* inf); static void router_retrans_schedule(struct ETCP_ROUTER_CONN* rconn); static void router_retrans_timer_cb(void* arg); @@ -170,38 +168,7 @@ static struct ETCP_ROUTER_CONN* router_conn_find(struct UTUN_INSTANCE* inst, } // ==================================================================== -// E2E encryption — per-peer sc_context_t cache, ECDH key derivation -// ==================================================================== - -static struct secure_channel* e2e_get_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, "E2E: 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, "E2E: 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, "E2E: new context for peer=%016llx slot=%d", (unsigned long long)peer_node_id, slot); - return &inst->e2e_ctx_cache[slot].ctx; -} - -// ==================================================================== -// Отправка: router_send_one_flags + send_q (дренится через waiter на send_input_q) +// Отправка: build+encode в начале send, дренирование через waiter на send_input_q // ==================================================================== // Найти ETCP_CONN для отправки (учитывая indirect-посредников). NULL = нет маршрута. @@ -220,100 +187,62 @@ static struct ETCP_CONN* router_send_conn(struct ETCP_ROUTER_CONN* rconn) { return topo_group_find_conn_for_node(group, rconn->remote_node_id); } -static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, uint8_t flag_bits, int is_signed) { +// Собрать и закодировать (подпись/шифрование) пакет в начале отправки. +// Возвращает финальный wire-пакет [SVC_ROUTE_HDR][payload][sig?] (u_malloc). +static int router_build_packet(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, int mode, + uint8_t** out, size_t* out_len) { struct UTUN_INSTANCE* inst = rconn->inst; - uint8_t ctrl_bits = flag_bits & ~ROUTER_FLAG_ENCRYPTED; - uint32_t seq = ctrl_bits ? 0 : rconn->tx_seq++; - size_t sig_len = is_signed ? SC_SIGN_SIZE : 0; - size_t total_len = SVC_ROUTE_HDR_SIZE + pl_len + sig_len; - uint8_t* dgram = u_malloc(total_len); - if (!dgram) { if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; } - struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram; + uint8_t* base = u_malloc(SVC_ROUTE_HDR_SIZE + pl_len); + if (!base) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_build_packet: alloc fail"); rconn->c_pkts_send_err++; return -1; } + struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)base; hdr->cmd = ETCP_RT_ID_SVC_ROUTE; hdr->group_id = rconn->group_id; hdr->dst_node_id = rconn->remote_node_id; hdr->src_node_id = inst->node_id; - hdr->seq = seq; + hdr->seq = rconn->tx_seq++; hdr->svc_id = rconn->svc_id; { - uint8_t f = (rconn->sess_id << ROUTER_SESS_ID_SHIFT) | flag_bits; - if (!rconn->start_sent && seq == 0 && pl_len > 0 && !ctrl_bits) { - f |= ROUTER_FLAG_START; - } - if (is_signed) f |= ROUTER_FLAG_SIGNED; + uint8_t f = (rconn->sess_id << ROUTER_SESS_ID_SHIFT); + if (!rconn->start_sent && hdr->seq == 0 && pl_len > 0) f |= ROUTER_FLAG_START; hdr->flags = f; } hdr->timestamp = get_current_timestamp(); - if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, payload, pl_len); + if (pl_len > 0) memcpy(base + SVC_ROUTE_HDR_SIZE, payload, pl_len); - struct ETCP_CONN* conn = router_send_conn(rconn); - if (!conn) { - DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "no route to %016llx svc_id=%u", - (unsigned long long)rconn->remote_node_id, rconn->svc_id); - u_free(dgram); if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; + if (route_crypto_encode(inst, rconn->remote_node_id, base, SVC_ROUTE_HDR_SIZE + pl_len, mode, out, out_len) != 0) { + u_free(base); rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; } + u_free(base); + return 0; +} - if (is_signed) { - struct sc_stream_sign_state sign_state; - if (sc_stream_sign_init(&conn->crypto_ctx, &sign_state) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "sign_init failed svc_id=%u", rconn->svc_id); - u_free(dgram); if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; - } - size_t data_len = SVC_ROUTE_HDR_SIZE + pl_len; - if (sc_stream_sign_update(&sign_state, dgram, data_len) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "sign_update failed svc_id=%u", rconn->svc_id); - sc_stream_sign_cleanup(&sign_state); u_free(dgram); if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; - } - size_t actual_sig_len = SC_SIGN_SIZE; - if (sc_stream_sign_final(&sign_state, dgram + data_len, &actual_sig_len) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "sign_final failed svc_id=%u", rconn->svc_id); - u_free(dgram); if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; - } +// Отправить контрольный (header-only) пакет: CLOSE и т.п. Без seq/подписи/шифрования. +static void router_send_ctrl(struct ETCP_ROUTER_CONN* rconn, uint8_t flag_bits) { + struct ETCP_CONN* conn = router_send_conn(rconn); + if (!conn) { + DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_ctrl: no route to %016llx svc_id=%u flag=%02x", + (unsigned long long)rconn->remote_node_id, rconn->svc_id, flag_bits); + return; } - + struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE); + if (!hdr) return; + hdr->cmd = ETCP_RT_ID_SVC_ROUTE; + hdr->group_id = rconn->group_id; + hdr->dst_node_id = rconn->remote_node_id; + hdr->src_node_id = rconn->inst->node_id; + hdr->seq = 0; + hdr->svc_id = rconn->svc_id; + hdr->flags = (rconn->sess_id << ROUTER_SESS_ID_SHIFT) | flag_bits; + hdr->timestamp = get_current_timestamp(); struct ll_entry* entry = queue_entry_new(0); - if (!entry) { u_free(dgram); if (!ctrl_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; } - entry->dgram = dgram; - entry->len = total_len; - - rconn->last_dgram_ts = get_current_timestamp(); - DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ETCP_SEND: svc_id=%u seq=%u len=%zu inflight=%d signed=%d enc=%d → %016llx", - rconn->svc_id, seq, pl_len, - (int32_t)(rconn->tx_seq - rconn->tx_acked), - is_signed, !!(flag_bits & ROUTER_FLAG_ENCRYPTED), - (unsigned long long)rconn->remote_node_id); + if (!entry) { u_free(hdr); return; } + entry->dgram = (uint8_t*)hdr; + entry->len = SVC_ROUTE_HDR_SIZE; int ret = etcp_send(conn, entry); if (ret != 0) { - if (!ctrl_bits) rconn->tx_seq--; queue_dgram_free(entry); queue_entry_free(entry); - rconn->c_pkts_send_err++; - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_send failed ret=%d svc_id=%u seq=%u", ret, rconn->svc_id, seq); - } else { - rconn->c_pkts_sent++; - if (!ctrl_bits && pl_len > 0) { - struct ROUTER_INFLIGHT* inf = u_malloc(sizeof(struct ROUTER_INFLIGHT)); - if (inf) { - memset(&inf->ll, 0, sizeof(inf->ll)); - inf->ll.size = 4; - inf->seq = seq; - *(uint32_t*)inf->ll.data = seq; - inf->last_sent_tb = get_time_tb(); - inf->send_count = 1; - inf->is_encrypted = !!(flag_bits & ROUTER_FLAG_ENCRYPTED); - inf->payload = u_malloc(pl_len); - if (inf->payload) { - memcpy(inf->payload, payload, pl_len); - inf->payload_len = pl_len; - queue_data_put_with_index(rconn->inflight_q, &inf->ll); - } else { - u_free(inf); - } - if (!rconn->retrans_timer) router_retrans_schedule(rconn); - } - } - if (!flag_bits) router_track_inflight_state(rconn); + DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_ctrl: etcp_send failed ret=%d svc_id=%u flag=%02x", ret, rconn->svc_id, flag_bits); } - return ret; } // Отправка RST удалённой стороне — сброс чужой «старой» сессии. @@ -368,6 +297,7 @@ static void router_send_close_to_service(struct ETCP_ROUTER_CONN* rconn) { e->dgram[0] = rconn->svc_id; memcpy(e->dgram + ROUTER_SVC_SRC_OFF, &rconn->remote_node_id, 8); memcpy(e->dgram + ROUTER_SVC_DST_OFF, &inst->node_id, 8); + e->dgram[ROUTER_SVC_FLAGS_OFF] = 0; e->len = ROUTER_SVC_HDR_SIZE; DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_close_svc: svc_id=%u remote=%016llx", rconn->svc_id, (unsigned long long)rconn->remote_node_id); @@ -383,48 +313,86 @@ static void router_close_finalize(void* arg) { if (cb) cb(cb_arg); } -static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn) { - if (!rconn || rconn->closed) return; +// Отменить таймеры/waiter и освободить все очереди rconn (общий код для close/restart). +static void router_conn_free_queues(struct ETCP_ROUTER_CONN* rconn) { struct UTUN_INSTANCE* inst = rconn->inst; - rconn->closed = 1; - router_send_close_to_service(rconn); - // Отправляем CLOSE удалённой стороне + снимаем waiter отправки - struct ETCP_CONN* conn = router_send_conn(rconn); - if (conn) { - if (conn->send_input_q) queue_waiter_cancel(conn->send_input_q, &rconn->send_waiter); - router_send_one_flags(rconn, NULL, 0, ROUTER_FLAG_CLOSE, 0); - } - // Таймеры - if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; } - if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; } - if (rconn->watchdog_timer) { uasync_cancel_timeout(inst->ua, rconn->watchdog_timer); rconn->watchdog_timer = NULL; } - if (rconn->no_route_timer) { uasync_cancel_timeout(inst->ua, rconn->no_route_timer); rconn->no_route_timer = NULL; } - if (rconn->recv_q) { - struct ll_entry* f; - while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } - queue_free(rconn->recv_q); rconn->recv_q = NULL; + if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; } + if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; } + if (rconn->watchdog_timer) { uasync_cancel_timeout(inst->ua, rconn->watchdog_timer); rconn->watchdog_timer = NULL; } + if (rconn->no_route_timer) { uasync_cancel_timeout(inst->ua, rconn->no_route_timer); rconn->no_route_timer = NULL; } + if (rconn->retrans_timer) { uasync_cancel_timeout(inst->ua, rconn->retrans_timer); rconn->retrans_timer = NULL; } + { + struct ETCP_CONN* c = router_send_conn(rconn); + if (c && c->send_input_q) queue_waiter_cancel(c->send_input_q, &rconn->send_waiter); + memset(&rconn->send_waiter, 0, sizeof(rconn->send_waiter)); } + struct ll_entry* f; if (rconn->send_q) { - struct ll_entry* f; while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } queue_free(rconn->send_q); rconn->send_q = NULL; } + if (rconn->recv_q) { + while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } + queue_free(rconn->recv_q); rconn->recv_q = NULL; + } if (rconn->inflight_q) { - struct ll_entry* f; while ((f = queue_data_get(rconn->inflight_q)) != NULL) { struct ROUTER_INFLIGHT* inf = (struct ROUTER_INFLIGHT*)f; - if (inf->payload) u_free(inf->payload); + if (inf->dgram) u_free(inf->dgram); u_free(inf); } queue_free(rconn->inflight_q); rconn->inflight_q = NULL; } - if (rconn->retrans_timer) { uasync_cancel_timeout(inst->ua, rconn->retrans_timer); rconn->retrans_timer = NULL; } if (rconn->incoming_q) { - struct ll_entry* f; while ((f = queue_data_get(rconn->incoming_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } queue_resume_callback(rconn->incoming_q); queue_free(rconn->incoming_q); rconn->incoming_q = NULL; } +} + +// Пересоздать очереди и сбросить всё состояние rconn (кроме identity: group/remote/svc/ll.data/inst/sess_id/close_cb/last_dgram_ts). +static void router_conn_reset(struct ETCP_ROUTER_CONN* rconn) { + router_conn_free_queues(rconn); + + rconn->send_q = queue_new(rconn->inst->ua, 0, 0, 0, "router_send_q"); + rconn->recv_q = queue_new(rconn->inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q"); + rconn->inflight_q = queue_new(rconn->inst->ua, ROUTER_INFLIGHT_HASH_SIZE, 0, 4, "router_inflight_q"); + rconn->incoming_q = queue_new(rconn->inst->ua, 0, 0, 0, "router_incoming_q"); + queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS - 1, 0); + queue_set_callback(rconn->incoming_q, router_incoming_q_cb, rconn); + queue_set_threshold(rconn->incoming_q, 0, 0); + rconn->incoming_data_ready = 0; + rconn->recv_conn = NULL; + + rconn->rtt = 0; rconn->rtt_jitter = 0; + rconn->max_inflight = ROUTER_MAX_INFLIGHT; + rconn->inflight_limit = ROUTER_MAX_INFLIGHT; + rconn->minrtt = MINRTT_DEFAULT_TB; + memset(rconn->minrtt_window, 0, sizeof(rconn->minrtt_window)); + memset(rconn->minrtt_window_tb, 0, sizeof(rconn->minrtt_window_tb)); + rconn->minrtt_window_idx = 0; rconn->minrtt_window_count = 0; rconn->minrtt_probe = 0; + rconn->last_inflight_loaded_tb = 0; rconn->last_inflight_unloaded_tb = 0; rconn->inflight_was_loaded = 0; + rconn->last_recv_pkt_ts = 0; rconn->last_recv_pkt_local_tb = 0; rconn->last_recv_updated = 0; + + rconn->tx_seq = 0; rconn->rx_seq = 0; rconn->tx_acked = 0; + rconn->last_sent_ack_seq = 0; rconn->last_ack_sent_tb = 0; + rconn->peer_sess_id = 0; + rconn->send_blocked = 0; rconn->start_sent = 0; rconn->peer_sync_done = 0; + rconn->no_route = 0; rconn->no_route_timer = NULL; rconn->no_ack_count = 0; rconn->closed = 0; + rconn->c_pkts_sent = 0; rconn->c_pkts_send_err = 0; rconn->c_pkts_rcvd = 0; + rconn->c_ack_sent = 0; rconn->c_ack_recv = 0; rconn->c_retrans_done = 0; + rconn->c_dup_dropped = 0; rconn->c_oob_dropped = 0; rconn->c_stale_ack = 0; rconn->c_sign_fail = 0; + rconn->last_ack_changed_tb = 0; +} + +static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn) { + if (!rconn || rconn->closed) return; + struct UTUN_INSTANCE* inst = rconn->inst; + rconn->closed = 1; + router_send_close_to_service(rconn); + // Отправляем CLOSE удалённой стороне + снимаем waiter отправки + if (router_send_conn(rconn)) router_send_ctrl(rconn, ROUTER_FLAG_CLOSE); + router_conn_free_queues(rconn); if (inst->router_conns) queue_remove_data(inst->router_conns, &rconn->ll); DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: closed group=%016llx remote=%016llx svc_id=%u", @@ -446,7 +414,7 @@ static void router_set_no_route(struct ETCP_ROUTER_CONN* rconn) { static void router_send_kick(struct ETCP_ROUTER_CONN* rconn) { if (rconn->closed || rconn->no_route) return; if (queue_entry_count(rconn->send_q) == 0) return; - if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= (int32_t)router_effective_max_inflight(rconn)) { + if (queue_entry_count(rconn->inflight_q) >= (int)router_effective_max_inflight(rconn)) { rconn->send_blocked = 1; return; } @@ -456,33 +424,62 @@ static void router_send_kick(struct ETCP_ROUTER_CONN* rconn) { queue_waiter_wait(conn->send_input_q, &rconn->send_waiter, router_send_drain_cb, rconn); } -// Waiter-коллбэк: send_input_q опустел → шлём один пакет, при необходимости снова встаём в хвост (round-robin). +// Waiter-коллбэк: send_input_q опустел → шлём один пакет (уже закодированный), при необходимости +// снова встаём в хвост (round-robin). Успешно отправленный пакет кладём в inflight_q для ретрансмита. static void router_send_drain_cb(struct ll_queue* q, void* arg) { (void)q; struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg; if (rconn->closed || rconn->no_route) return; if (queue_entry_count(rconn->send_q) == 0) { rconn->send_blocked = 0; router_send_watchdog_disarm(rconn); return; } - if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= (int32_t)router_effective_max_inflight(rconn)) { + if (queue_entry_count(rconn->inflight_q) >= (int)router_effective_max_inflight(rconn)) { rconn->send_blocked = 1; return; } struct ll_entry* e = queue_data_get(rconn->send_q); if (!e) { rconn->send_blocked = 0; router_send_watchdog_disarm(rconn); return; } - uint8_t m = (e->size > 0) ? e->data[0] : 0; - uint8_t fb = (m & SENDQ_FLAG_ENCRYPTED) ? ROUTER_FLAG_ENCRYPTED : 0; - int is_signed = (m & SENDQ_FLAG_SIGNED) ? 1 : 0; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "SEND_Q_DRAIN: svc_id=%u send_q=%d inflight=%d sq_in=%d", + uint32_t seq = ((struct SVC_ROUTE_HDR*)e->dgram)->seq; + + struct ETCP_CONN* conn = router_send_conn(rconn); + if (!conn) { free_entry(e); router_set_no_route(rconn); return; } + + // копия финального пакета для inflight (e->dgram уйдёт в etcp_send) + struct ROUTER_INFLIGHT* inf = u_malloc(sizeof(struct ROUTER_INFLIGHT)); + if (inf) { + memset(&inf->ll, 0, sizeof(inf->ll)); + inf->ll.size = 4; + inf->seq = seq; + *(uint32_t*)inf->ll.data = seq; + inf->last_sent_tb = get_time_tb(); + inf->send_count = 1; + inf->dgram = u_malloc(e->len); + if (inf->dgram) { memcpy(inf->dgram, e->dgram, e->len); inf->dgram_len = e->len; } + else { u_free(inf); inf = NULL; } + } + + DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "SEND_Q_DRAIN: svc_id=%u send_q=%d inflight=%d sq_in=%d seq=%u", rconn->svc_id, queue_entry_count(rconn->send_q), - (int32_t)(rconn->tx_seq - rconn->tx_acked), rconn->send_q->count); - router_send_one_flags(rconn, e->dgram, e->len, fb, is_signed); - queue_dgram_free(e); queue_entry_free(e); + queue_entry_count(rconn->inflight_q), rconn->send_q->count, seq); + int ret = etcp_send(conn, e); + if (ret != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_send failed ret=%d svc_id=%u seq=%u", ret, rconn->svc_id, seq); + free_entry(e); rconn->c_pkts_send_err++; + if (inf) { if (inf->dgram) u_free(inf->dgram); u_free(inf); } + } else { + rconn->c_pkts_sent++; + rconn->last_dgram_ts = get_current_timestamp(); + if (inf) { + queue_data_put_with_index(rconn->inflight_q, &inf->ll); + if (!rconn->retrans_timer) router_retrans_schedule(rconn); + } + router_track_inflight_state(rconn); + } if (queue_entry_count(rconn->send_q) == 0) { rconn->send_blocked = 0; router_send_watchdog_disarm(rconn); return; } - if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= (int32_t)router_effective_max_inflight(rconn)) { + if (queue_entry_count(rconn->inflight_q) >= (int)router_effective_max_inflight(rconn)) { rconn->send_blocked = 1; return; } - struct ETCP_CONN* conn = router_send_conn(rconn); + conn = router_send_conn(rconn); if (!conn) { router_set_no_route(rconn); return; } queue_waiter_wait(conn->send_input_q, &rconn->send_waiter, router_send_drain_cb, rconn); } @@ -495,11 +492,11 @@ static void router_send_watchdog_cb(void* arg) { if (rconn->closed) return; if (queue_entry_count(rconn->send_q) == 0) return; if (!rconn->no_route - && (int32_t)(rconn->tx_seq - rconn->tx_acked) < (int32_t)router_effective_max_inflight(rconn) + && queue_entry_count(rconn->inflight_q) < (int)router_effective_max_inflight(rconn) && !rconn->send_waiter.internal && !rconn->send_waiter.call_soon_id) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router watchdog: send_q stalled svc_id=%u send_q=%d inflight=%d blocked=%d — force kick", rconn->svc_id, queue_entry_count(rconn->send_q), - (int32_t)(rconn->tx_seq - rconn->tx_acked), rconn->send_blocked); + queue_entry_count(rconn->inflight_q), rconn->send_blocked); router_send_kick(rconn); } if (queue_entry_count(rconn->send_q) > 0) @@ -539,34 +536,19 @@ static void router_no_route_retry_cb(void* arg) { // ==================================================================== static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_INFLIGHT* inf) { - struct UTUN_INSTANCE* inst = rconn->inst; - size_t total_len = SVC_ROUTE_HDR_SIZE + inf->payload_len; - uint8_t* dgram = u_malloc(total_len); - if (!dgram) { rconn->c_pkts_send_err++; return; } - struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram; - hdr->cmd = ETCP_RT_ID_SVC_ROUTE; - hdr->group_id = rconn->group_id; - hdr->dst_node_id = rconn->remote_node_id; - hdr->src_node_id = inst->node_id; - hdr->seq = inf->seq; - hdr->svc_id = rconn->svc_id; - hdr->flags = (rconn->sess_id << ROUTER_SESS_ID_SHIFT); - if (!rconn->start_sent && inf->seq == 0) hdr->flags |= ROUTER_FLAG_START; - if (inf->is_encrypted) hdr->flags |= ROUTER_FLAG_ENCRYPTED; - hdr->timestamp = get_current_timestamp(); - struct ETCP_CONN* conn = router_send_conn(rconn); if (!conn) { DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_retransmit: no route to %016llx svc_id=%u", (unsigned long long)rconn->remote_node_id, rconn->svc_id); - u_free(dgram); rconn->c_pkts_send_err++; return; + rconn->c_pkts_send_err++; return; } - - memcpy(dgram + SVC_ROUTE_HDR_SIZE, inf->payload, inf->payload_len); + // Финальный пакет уже закодирован (подпись/шифрование) — шлём как есть. struct ll_entry* entry = queue_entry_new(0); - if (!entry) { u_free(dgram); rconn->c_pkts_send_err++; return; } - entry->dgram = dgram; - entry->len = total_len; + if (!entry) { rconn->c_pkts_send_err++; return; } + entry->dgram = u_malloc(inf->dgram_len); + if (!entry->dgram) { queue_entry_free(entry); rconn->c_pkts_send_err++; return; } + memcpy(entry->dgram, inf->dgram, inf->dgram_len); + entry->len = inf->dgram_len; rconn->last_dgram_ts = get_current_timestamp(); DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "RETRANS: svc_id=%u seq=%u attempt=%d → %016llx", @@ -626,24 +608,23 @@ static void router_retrans_timer_cb(void* arg) { } } -// Флаги метаданных элемента send_q (data[0]): bit0=encrypted, bit1=signed -static int router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, int force, int is_encrypted, int is_signed) { +// Собрать+закодировать пакет в начале отправки и положить в send_q. +static int router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, int force, int mode) { if (!force && queue_entry_count(rconn->send_q) >= ROUTER_MAX_SEND_Q_PACKETS) { DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_send_q: FULL svc_id=%u count=%d — backpressure", rconn->svc_id, queue_entry_count(rconn->send_q)); return -1; } - struct ll_entry* qe = queue_entry_new(1); - if (!qe) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "queue_entry_new failed"); return -1; } - qe->dgram = u_malloc(pl_len); - if (!qe->dgram) { queue_entry_free(qe); return -1; } - qe->len = pl_len; - qe->data[0] = (is_encrypted ? SENDQ_FLAG_ENCRYPTED : 0) | (is_signed ? SENDQ_FLAG_SIGNED : 0); - if (pl_len > 0) memcpy(qe->dgram, payload, pl_len); - DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_send_q: queued svc_id=%u inflight=%d send_q=%d enc=%d signed=%d", - rconn->svc_id, (int32_t)(rconn->tx_seq - rconn->tx_acked), queue_entry_count(rconn->send_q), is_encrypted, is_signed); + uint8_t* dgram = NULL; size_t dgram_len = 0; + if (router_build_packet(rconn, payload, pl_len, mode, &dgram, &dgram_len) != 0) return -1; + + struct ll_entry* qe = queue_entry_new(0); + if (!qe) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "queue_entry_new failed"); u_free(dgram); rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; } + qe->dgram = dgram; + qe->len = dgram_len; + DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_send_q: queued svc_id=%u inflight=%d send_q=%d mode=%02x", + rconn->svc_id, queue_entry_count(rconn->inflight_q), queue_entry_count(rconn->send_q), mode); queue_data_put(rconn->send_q, qe); - u_check(qe, "enqueue_send:after_put", "router"); router_send_kick(rconn); router_send_watchdog_arm(rconn); return 0; @@ -662,7 +643,7 @@ static void router_update_inflight_limit(struct ETCP_ROUTER_CONN* rconn) { if (new_limit == rconn->inflight_limit) return; uint32_t old = rconn->inflight_limit; rconn->inflight_limit = new_limit; - uint32_t inflight = rconn->tx_seq - rconn->tx_acked; + uint32_t inflight = (uint32_t)queue_entry_count(rconn->inflight_q); if (new_limit < old && inflight >= new_limit) { if (!rconn->send_blocked) rconn->send_blocked = 1; @@ -682,7 +663,7 @@ void router_set_max_inflight(struct ETCP_ROUTER_CONN* rconn, uint16_t new_max) { } static void router_track_inflight_state(struct ETCP_ROUTER_CONN* rconn) { - uint32_t inflight = rconn->tx_seq - rconn->tx_acked; + uint32_t inflight = (uint32_t)queue_entry_count(rconn->inflight_q); uint32_t threshold = rconn->max_inflight / 2; uint8_t is_loaded = (inflight >= threshold); if (is_loaded && !rconn->inflight_was_loaded) { @@ -832,8 +813,8 @@ static void router_idle_ack_timer_cb(void* arg) { // Reorder / assembly (аналог etcp_output_try_assembly) // ==================================================================== -// Доставка сервисной кодограммы в едином формате [svc_id][src][dst][payload]. -// Для loopback (dst == self) src и dst оба = self. +// Доставка сервисной кодограммы в едином формате [svc_id][src][dst][rx_flags][payload]. +// Для loopback (dst == self) src и dst оба = self, rx_flags = 0. static void router_deliver_loopback(struct UTUN_INSTANCE* inst, uint8_t svc_id, struct ll_entry* entry) { etcp_recv_fn cb = inst->router_bindings.callbacks[svc_id]; if (!cb) { queue_dgram_free(entry); queue_entry_free(entry); return; } @@ -845,34 +826,56 @@ static void router_deliver_loopback(struct UTUN_INSTANCE* inst, uint8_t svc_id, e->dgram[0] = svc_id; memcpy(e->dgram + ROUTER_SVC_SRC_OFF, &inst->node_id, 8); memcpy(e->dgram + ROUTER_SVC_DST_OFF, &inst->node_id, 8); + e->dgram[ROUTER_SVC_FLAGS_OFF] = 0; if (payload_len > 0) memcpy(e->dgram + ROUTER_SVC_PAYLOAD_OFF, entry->dgram + 1, payload_len); e->len = ROUTER_SVC_HDR_SIZE + payload_len; queue_dgram_free(entry); queue_entry_free(entry); cb(loopback_conn(inst), e); } +// Доставка: декодирует (подпись/шифрование) перед вызовом сервисного коллбэка. +// wire = [SVC_ROUTE_HDR][payload][sig?] — финальный пакет, лежавший в recv_q. static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, - const uint8_t* payload, size_t payload_len) { + const uint8_t* wire, size_t wire_len) { struct UTUN_INSTANCE* inst = rconn->inst; etcp_recv_fn cb = inst->router_bindings.callbacks[rconn->svc_id]; if (!cb) { DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: no handler for svc_id=%u", rconn->svc_id); return; } + const uint8_t* payload; size_t payload_len; uint8_t rx_flags = 0; uint8_t* decoded = NULL; + struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)wire; + if (hdr->flags & (ROUTER_FLAG_ENCRYPTED | ROUTER_FLAG_SIGNED)) { + size_t decoded_len = 0; + if (route_crypto_decode(inst, wire, wire_len, &decoded, &decoded_len, &rx_flags) != 0) { + DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: decode failed svc_id=%u from %016llx — dropping", + rconn->svc_id, (unsigned long long)rconn->remote_node_id); + rconn->c_sign_fail++; + return; + } + payload = decoded + SVC_ROUTE_HDR_SIZE; + payload_len = decoded_len - SVC_ROUTE_HDR_SIZE; + } else { + payload = wire + SVC_ROUTE_HDR_SIZE; + payload_len = wire_len - SVC_ROUTE_HDR_SIZE; + } + size_t entry_len = ROUTER_SVC_HDR_SIZE + payload_len; struct ll_entry* svc_entry = queue_entry_new(0); - if (!svc_entry) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: queue_entry_new failed"); return; } + if (!svc_entry) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: queue_entry_new failed"); if (decoded) u_free(decoded); return; } svc_entry->len = entry_len; svc_entry->dgram = u_malloc(entry_len); - if (!svc_entry->dgram) { queue_entry_free(svc_entry); return; } + if (!svc_entry->dgram) { queue_entry_free(svc_entry); if (decoded) u_free(decoded); return; } svc_entry->dgram[0] = rconn->svc_id; memcpy(svc_entry->dgram + ROUTER_SVC_SRC_OFF, &rconn->remote_node_id, 8); memcpy(svc_entry->dgram + ROUTER_SVC_DST_OFF, &inst->node_id, 8); + svc_entry->dgram[ROUTER_SVC_FLAGS_OFF] = rx_flags; if (payload_len > 0) memcpy(svc_entry->dgram + ROUTER_SVC_PAYLOAD_OFF, payload, payload_len); + if (decoded) u_free(decoded); - DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: svc_id=%u len=%zu src=%016llx dst=%016llx conn=%p cb=%p", - rconn->svc_id, payload_len, (unsigned long long)rconn->remote_node_id, - (unsigned long long)inst->node_id, (void*)conn, (void*)cb); + DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: svc_id=%u len=%zu flags=%02x src=%016llx dst=%016llx", + rconn->svc_id, payload_len, rx_flags, (unsigned long long)rconn->remote_node_id, + (unsigned long long)inst->node_id); rconn->c_pkts_rcvd++; cb(conn, svc_entry); } @@ -902,8 +905,8 @@ static void router_incoming_q_cb(struct ll_queue* q, void* arg) { if (!e) { queue_resume_callback(q); return; } uint32_t seq = *(uint32_t*)e->data; - const uint8_t* pl = e->dgram; - size_t pl_len = e->len; + const uint8_t* wire = e->dgram; + size_t wire_len = e->len; if (queue_find_data_by_index(rconn->recv_q, &seq)) { DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_incoming_q: dup in recv_q seq=%u, dropping", seq); @@ -924,61 +927,9 @@ static void router_incoming_q_cb(struct ll_queue* q, void* arg) { } // ==================================================================== -// Извлечённые функции для etcp_router_recv_cb +// Функции приёма etcp_router_recv_cb // ==================================================================== -static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry* entry, - struct SVC_ROUTE_HDR* hdr, size_t* pl_len) { - if (!(hdr->flags & ROUTER_FLAG_SIGNED)) return 0; - if (*pl_len < SC_SIGN_SIZE) { - DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet too short len=%zu from %016llx", - *pl_len, (unsigned long long)hdr->src_node_id); - free_entry(entry); return -1; - } - size_t actual_payload = *pl_len - SC_SIGN_SIZE; - uint8_t* sig = (uint8_t*)entry->dgram + SVC_ROUTE_HDR_SIZE + actual_payload; - struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, hdr->group_id); - struct TOPO_GROUP_NODE* nq = group ? topo_node_find_by_id(group, hdr->src_node_id) : NULL; - if (!nq) { - DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet from unknown node %016llx — dropping", - (unsigned long long)hdr->src_node_id); - free_entry(entry); return -1; - } - struct TOPO_NODE* sni = topo_node_registry_find(inst->topo_groups, nq->node_id); - if (!sni) { free_entry(entry); 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, "router: no Ed25519 pubkey for node %016llx — dropping", - (unsigned long long)hdr->src_node_id); - free_entry(entry); return -1; - } - } - struct sc_stream_sign_state vfy_state; - if (sc_stream_sign_verify_init(&vfy_state, sni->ed25519_public_key) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_verify_init failed for node %016llx", - (unsigned long long)hdr->src_node_id); - free_entry(entry); return -1; - } - size_t signed_len = SVC_ROUTE_HDR_SIZE + actual_payload; - if (sc_stream_sign_update(&vfy_state, entry->dgram, signed_len) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_update failed for node %016llx", - (unsigned long long)hdr->src_node_id); - sc_stream_sign_cleanup(&vfy_state); free_entry(entry); return -1; - } - if (sc_stream_sign_verify(&vfy_state, sig, SC_SIGN_SIZE) != SC_OK) { - DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: signature verification FAILED for node %016llx svc_id=%u — dropping", - (unsigned long long)hdr->src_node_id, hdr->svc_id); - struct ETCP_ROUTER_CONN* sr = router_conn_find(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id); - if (sr) sr->c_sign_fail++; - free_entry(entry); return -1; - } - *pl_len = actual_payload; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router: signature verified for node %016llx svc_id=%u", - (unsigned long long)hdr->src_node_id, hdr->svc_id); - return 0; -} - static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN* rconn, uint32_t seq, uint64_t src_node_id, uint16_t ack_ts) { (void)src_node_id; @@ -999,7 +950,7 @@ static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CON struct ROUTER_INFLIGHT* inf = (struct ROUTER_INFLIGHT*)queue_find_data_by_index(rconn->inflight_q, &clean_seq); if (inf) { queue_remove_data(rconn->inflight_q, &inf->ll); - if (inf->payload) u_free(inf->payload); + if (inf->dgram) u_free(inf->dgram); u_free(inf); } clean_seq++; @@ -1013,7 +964,7 @@ static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CON rconn->retrans_timer = NULL; } DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "SEND_Q_ACKED: svc_id=%u ack=%u inflight=%d send_q=%d inflight_q=%d from %016llx", - rconn->svc_id, seq, (int32_t)(rconn->tx_seq - rconn->tx_acked), + rconn->svc_id, seq, queue_entry_count(rconn->inflight_q), queue_entry_count(rconn->send_q), queue_entry_count(rconn->inflight_q), (unsigned long long)src_node_id); rconn->c_ack_recv++; } else { @@ -1094,7 +1045,7 @@ static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROU } static void router_handle_data_packet(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, - uint32_t seq, const uint8_t* pl, size_t pl_len) { + uint32_t seq, const uint8_t* wire, size_t wire_len) { rconn->recv_conn = conn; rconn->last_dgram_ts = get_current_timestamp(); @@ -1124,9 +1075,9 @@ static void router_handle_data_packet(struct ETCP_ROUTER_CONN* rconn, struct ETC struct ll_entry* qe = queue_entry_new(4); if (!qe) return; *(uint32_t*)qe->data = seq; - qe->dgram = u_malloc(pl_len); + qe->dgram = u_malloc(wire_len); if (!qe->dgram) { queue_dgram_free(qe); queue_entry_free(qe); return; } - qe->len = pl_len; memcpy(qe->dgram, pl, pl_len); + qe->len = wire_len; memcpy(qe->dgram, wire, wire_len); DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router: incoming_q seq=%u rx_seq=%u from %016llx svc_id=%u", seq, rconn->rx_seq, @@ -1148,41 +1099,12 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) } struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)entry->dgram; size_t pl_len = entry->len - SVC_ROUTE_HDR_SIZE; - uint8_t* pl = entry->dgram + SVC_ROUTE_HDR_SIZE; DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ETCP_RECV: svc_id=%u seq=%u len=%zu from %016llx", hdr->svc_id, hdr->seq, pl_len, (unsigned long long)hdr->src_node_id); if (hdr->dst_node_id != inst->node_id) { router_forward_transit(inst, entry, hdr); return; } - if (router_verify_signature(inst, entry, hdr, &pl_len) != 0) return; - - if ((hdr->flags & ROUTER_FLAG_ENCRYPTED) && pl_len > 0) { - struct secure_channel* e2e = e2e_get_ctx(inst, hdr->src_node_id); - if (!e2e) { free_entry(entry); return; } - uint8_t* pt_buf = u_malloc(pl_len); - size_t pt_len_val = 0; - if (sc_decrypt(e2e, pl, pl_len, pt_buf, &pt_len_val) != SC_OK) { - u_free(pt_buf); - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "E2E decrypt FAIL src=%016llx svc=%u seq=%u len=%zu", - (unsigned long long)hdr->src_node_id, hdr->svc_id, hdr->seq, pl_len); - free_entry(entry); return; - } - size_t new_total = SVC_ROUTE_HDR_SIZE + pt_len_val; - uint8_t* new_dgram = u_malloc(new_total); - memcpy(new_dgram, entry->dgram, SVC_ROUTE_HDR_SIZE); - memcpy(new_dgram + SVC_ROUTE_HDR_SIZE, pt_buf, pt_len_val); - u_free(pt_buf); - u_free(entry->dgram); - entry->dgram = new_dgram; - entry->len = new_total; - hdr = (struct SVC_ROUTE_HDR*)entry->dgram; - pl = entry->dgram + SVC_ROUTE_HDR_SIZE; - pl_len = pt_len_val; - DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "E2E decrypt OK src=%016llx svc=%u seq=%u pt_len=%zu", - (unsigned long long)hdr->src_node_id, hdr->svc_id, hdr->seq, pt_len_val); - } - struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id); if (pl_len == 0 && (hdr->flags & ROUTER_FLAG_RST)) { @@ -1212,7 +1134,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) rconn->last_recv_pkt_ts = hdr->timestamp; rconn->last_recv_pkt_local_tb = get_time_tb(); rconn->last_recv_updated = 1; - router_handle_data_packet(rconn, conn, hdr->seq, pl, pl_len); + router_handle_data_packet(rconn, conn, hdr->seq, entry->dgram, entry->len); free_entry(entry); } @@ -1280,7 +1202,7 @@ int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) { return 0; } -int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force) { +int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force, int mode) { if (!inst || !entry) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "NULL inst=%p entry=%p", (void*)inst, (void*)entry); if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1; @@ -1301,51 +1223,11 @@ int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_ struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, dst_node_id, svc_id); if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return -1; } - int ret = router_enqueue_send(rconn, entry->dgram + 1, payload_len, force, 0, 0); + int ret = router_enqueue_send(rconn, entry->dgram + 1, payload_len, force, mode); queue_dgram_free(entry); queue_entry_free(entry); return ret; } -int etcp_route_send_encrypted(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force) { - if (!inst || !entry) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "E2E send: NULL inst=%p entry=%p", (void*)inst, (void*)entry); - if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1; - } - if (!entry->dgram || entry->len < 1) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "E2E send: empty entry dgram=%p len=%u", (void*)entry->dgram, entry->len); - queue_dgram_free(entry); queue_entry_free(entry); return -1; - } - uint8_t svc_id = entry->dgram[0]; - size_t pl_len = entry->len - 1; - - if (dst_node_id == inst->node_id) { - DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "E2E send: loopback svc_id=%u len=%zu", svc_id, pl_len); - router_deliver_loopback(inst, svc_id, entry); - return 0; - } - - struct secure_channel* e2e = e2e_get_ctx(inst, dst_node_id); - if (!e2e) { queue_dgram_free(entry); queue_entry_free(entry); return -1; } - - size_t enc_cap = pl_len + SC_NONCE_SIZE + SC_CRC32_SIZE + SC_TAG_SIZE; - uint8_t* enc_buf = u_malloc(enc_cap); - if (!enc_buf) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "E2E send: enc_buf alloc fail"); queue_dgram_free(entry); queue_entry_free(entry); return -1; } - size_t enc_len = 0; - if (sc_encrypt(e2e, entry->dgram + 1, pl_len, enc_buf, &enc_len) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "E2E send: sc_encrypt FAIL dst=%016llx svc=%u len=%zu", - (unsigned long long)dst_node_id, svc_id, pl_len); - u_free(enc_buf); queue_dgram_free(entry); queue_entry_free(entry); return -1; - } - queue_dgram_free(entry); queue_entry_free(entry); - - struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, dst_node_id, svc_id); - if (!rconn) { u_free(enc_buf); return -1; } - - int ret = router_enqueue_send(rconn, enc_buf, enc_len, force, 1, 0); - u_free(enc_buf); - return ret; -} - int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id) { if (!inst || !topo_groups_find(inst->topo_groups, group_id)) return -1; struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), node_id); @@ -1386,94 +1268,14 @@ void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t group_id, uin e->dgram[0] = svc_id; memcpy(e->dgram + ROUTER_SVC_SRC_OFF, &remote_node_id, 8); memcpy(e->dgram + ROUTER_SVC_DST_OFF, &inst->node_id, 8); + e->dgram[ROUTER_SVC_FLAGS_OFF] = 0; e->len = ROUTER_SVC_HDR_SIZE; cb(loopback_conn(inst), e); } else { queue_entry_free(e); } } } - if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; } - if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; } - if (rconn->watchdog_timer) { uasync_cancel_timeout(inst->ua, rconn->watchdog_timer); rconn->watchdog_timer = NULL; } - if (rconn->no_route_timer) { uasync_cancel_timeout(inst->ua, rconn->no_route_timer); rconn->no_route_timer = NULL; } - if (rconn->retrans_timer) { uasync_cancel_timeout(inst->ua, rconn->retrans_timer); rconn->retrans_timer = NULL; } - { - struct ETCP_CONN* c = router_send_conn(rconn); - if (c && c->send_input_q) queue_waiter_cancel(c->send_input_q, &rconn->send_waiter); - memset(&rconn->send_waiter, 0, sizeof(rconn->send_waiter)); - } - - struct ll_entry* f; - if (rconn->send_q) { - while ((f = queue_data_get(rconn->send_q)) != NULL) { u_check(f, "restart:send_q", "router"); queue_dgram_free(f); queue_entry_free(f); } - queue_free(rconn->send_q); - } - if (rconn->recv_q) { - while ((f = queue_data_get(rconn->recv_q)) != NULL) { u_check(f, "restart:recv_q", "router"); queue_dgram_free(f); queue_entry_free(f); } - queue_free(rconn->recv_q); - } - if (rconn->inflight_q) { - while ((f = queue_data_get(rconn->inflight_q)) != NULL) { - struct ROUTER_INFLIGHT* inf = (struct ROUTER_INFLIGHT*)f; - if (inf->payload) u_free(inf->payload); - u_free(inf); - } - queue_free(rconn->inflight_q); - } - if (rconn->incoming_q) { - while ((f = queue_data_get(rconn->incoming_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } - queue_resume_callback(rconn->incoming_q); - queue_free(rconn->incoming_q); - } - rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q"); - rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q"); - rconn->inflight_q = queue_new(inst->ua, ROUTER_INFLIGHT_HASH_SIZE, 0, 4, "router_inflight_q"); - rconn->incoming_q = queue_new(inst->ua, 0, 0, 0, "router_incoming_q"); - queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS - 1, 0); - queue_set_callback(rconn->incoming_q, router_incoming_q_cb, rconn); - queue_set_threshold(rconn->incoming_q, 0, 0); - rconn->incoming_data_ready = 0; - rconn->recv_conn = NULL; - - rconn->tx_seq = 0; - rconn->rx_seq = 0; - rconn->tx_acked = 0; - rconn->last_sent_ack_seq = 0; - rconn->last_ack_sent_tb = 0; - rconn->peer_sess_id = 0; - rconn->send_blocked = 0; - rconn->start_sent = 0; - rconn->peer_sync_done = 0; - rconn->c_pkts_sent = 0; - rconn->c_pkts_send_err = 0; - rconn->c_pkts_rcvd = 0; - rconn->c_ack_sent = 0; - rconn->c_ack_recv = 0; - rconn->c_retrans_done = 0; - rconn->c_dup_dropped = 0; - rconn->c_oob_dropped = 0; - rconn->c_stale_ack = 0; - rconn->c_sign_fail = 0; - rconn->last_ack_changed_tb = 0; - rconn->rtt = 0; - rconn->rtt_jitter = 0; - rconn->max_inflight = ROUTER_MAX_INFLIGHT; - rconn->inflight_limit = ROUTER_MAX_INFLIGHT; - rconn->minrtt = MINRTT_DEFAULT_TB; - memset(rconn->minrtt_window, 0, sizeof(rconn->minrtt_window)); - memset(rconn->minrtt_window_tb, 0, sizeof(rconn->minrtt_window_tb)); - rconn->minrtt_window_idx = 0; - rconn->minrtt_window_count = 0; - rconn->minrtt_probe = 0; - rconn->last_inflight_loaded_tb = 0; - rconn->last_inflight_unloaded_tb = 0; - rconn->inflight_was_loaded = 0; - rconn->last_recv_pkt_ts = 0; - rconn->last_recv_pkt_local_tb = 0; - rconn->last_recv_updated = 0; - rconn->no_route = 0; - rconn->no_ack_count = 0; - rconn->closed = 0; + router_conn_reset(rconn); } void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id, @@ -1518,70 +1320,18 @@ struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst, rconn->group_id = group_id; rconn->remote_node_id = remote_node_id; rconn->svc_id = svc_id; + rconn->inst = inst; memcpy(rconn->ll.data, &group_id, 8); memcpy(rconn->ll.data + 8, &remote_node_id, 8); rconn->ll.data[16] = svc_id; rconn->last_dgram_ts = get_current_timestamp(); - rconn->rtt = 0; - rconn->rtt_jitter = 0; - rconn->max_inflight = ROUTER_MAX_INFLIGHT; - rconn->inflight_limit = ROUTER_MAX_INFLIGHT; - rconn->minrtt = MINRTT_DEFAULT_TB; - memset(rconn->minrtt_window, 0, sizeof(rconn->minrtt_window)); - memset(rconn->minrtt_window_tb, 0, sizeof(rconn->minrtt_window_tb)); - rconn->minrtt_window_idx = 0; - rconn->minrtt_window_count = 0; - rconn->minrtt_probe = 0; - rconn->last_inflight_loaded_tb = 0; - rconn->last_inflight_unloaded_tb = 0; - rconn->inflight_was_loaded = 0; - rconn->last_recv_pkt_ts = 0; - rconn->last_recv_pkt_local_tb = 0; - rconn->last_recv_updated = 0; - rconn->tx_seq = 0; - rconn->rx_seq = 0; - rconn->tx_acked = 0; - rconn->last_sent_ack_seq = 0; - rconn->last_ack_sent_tb = 0; - rconn->inst = inst; - rconn->recv_conn = NULL; - rconn->ack_timer = NULL; - rconn->idle_ack_timer = NULL; - rconn->send_blocked = 0; - rconn->watchdog_timer = NULL; - rconn->sess_id = 0; - rconn->start_sent = 0; - rconn->peer_sync_done = 0; - rconn->c_pkts_sent = 0; - rconn->c_pkts_send_err = 0; - rconn->c_pkts_rcvd = 0; - rconn->c_ack_sent = 0; - rconn->c_ack_recv = 0; - rconn->c_dup_dropped = 0; - rconn->c_oob_dropped = 0; - rconn->c_stale_ack = 0; - rconn->c_sign_fail = 0; - rconn->c_retrans_done = 0; - rconn->retrans_timer = NULL; - rconn->last_ack_changed_tb = 0; - rconn->no_route = 0; - rconn->no_route_timer = NULL; - rconn->no_ack_count = 0; - rconn->closed = 0; - rconn->close_callback = NULL; - rconn->close_callback_arg = NULL; - rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q"); - if (!rconn->recv_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(recv_q) failed"); queue_entry_free(&rconn->ll); return NULL; } - rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q"); - if (!rconn->send_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(send_q) failed"); queue_free(rconn->recv_q); queue_entry_free(&rconn->ll); return NULL; } - rconn->inflight_q = queue_new(inst->ua, ROUTER_INFLIGHT_HASH_SIZE, 0, 4, "router_inflight_q"); - if (!rconn->inflight_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(inflight_q) failed"); queue_free(rconn->send_q); queue_free(rconn->recv_q); queue_entry_free(&rconn->ll); return NULL; } - rconn->incoming_q = queue_new(inst->ua, 0, 0, 0, "router_incoming_q"); - if (!rconn->incoming_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(incoming_q) failed"); queue_free(rconn->inflight_q); queue_free(rconn->send_q); queue_free(rconn->recv_q); queue_entry_free(&rconn->ll); return NULL; } - queue_set_callback(rconn->incoming_q, router_incoming_q_cb, rconn); - queue_set_threshold(rconn->incoming_q, 0, 0); - rconn->incoming_data_ready = 0; - queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS - 1, 0); + router_conn_reset(rconn); + if (!rconn->send_q || !rconn->recv_q || !rconn->inflight_q || !rconn->incoming_q) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new failed"); + router_conn_free_queues(rconn); + queue_entry_free(&rconn->ll); + return NULL; + } DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: new conn group=%016llx remote=%016llx svc_id=%u", (unsigned long long)group_id, (unsigned long long)remote_node_id, svc_id); queue_data_put_with_index(inst->router_conns, &rconn->ll); @@ -1589,23 +1339,13 @@ struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst, } int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn, - const uint8_t* data, size_t len) { + const uint8_t* data, size_t len, int mode) { if (!rconn || !data || len == 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_send: invalid args rconn=%p data=%p len=%zu", (void*)rconn, (const void*)data, len); return -1; } - return router_enqueue_send(rconn, data, len, 0, 0, 0); -} - -int etcp_router_conn_send_signed(struct ETCP_ROUTER_CONN* rconn, - const uint8_t* data, size_t len) { - if (!rconn || !data || len == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_send_signed: invalid args rconn=%p data=%p len=%zu", - (void*)rconn, (const void*)data, len); - return -1; - } - return router_enqueue_send(rconn, data, len, 0, 0, 1); + return router_enqueue_send(rconn, data, len, 0, mode); } void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn) { @@ -1637,7 +1377,7 @@ void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t rem struct ll_entry* f; while ((f = queue_data_get(rconn->inflight_q)) != NULL) { struct ROUTER_INFLIGHT* inf = (struct ROUTER_INFLIGHT*)f; - if (inf->payload) u_free(inf->payload); + if (inf->dgram) u_free(inf->dgram); u_free(inf); } } diff --git a/src/routing_layer/etcp_router.h b/src/routing_layer/etcp_router.h index a90d2b75..cd43c97d 100644 --- a/src/routing_layer/etcp_router.h +++ b/src/routing_layer/etcp_router.h @@ -1,10 +1,11 @@ // etcp_router.h — Сервисный слой маршрутизации поверх ETCP // Маршрутизирует сервисные пакеты до целевой ноды, на промежуточных нодах ретранслирует -// Упрощённый TCP поверх ETCP: восстановление порядка, дедупликация, без переповторов +// Упрощённый TCP поверх ETCP: восстановление порядка, дедупликация, ретрансмиты, inflight-контроль. +// Подпись/шифрование вынесены в автономный модуль route_crypto (encode/decode). // // Формат SVC_ROUTE пакета: // [cmd:1] [group_id:8] [dst_node_id:8] [src_node_id:8] [seq:4] [svc_id:1] [flags:1] [timestamp:2] [payload...] -// flags: bit7=START, bit6=RST, bit5-4=sess_id(0-3), bit2=ENCRYPTED, bit1=CLOSE +// flags: bit7=START, bit6=RST, bit5-4=sess_id(0-3), bit3=SIGNED, bit2=ENCRYPTED, bit1=CLOSE // ACK-пакет: тот же заголовок, seq=rx_seq, payload_len=0 #ifndef ETCP_ROUTER_H #define ETCP_ROUTER_H @@ -35,12 +36,14 @@ struct SVC_ROUTE_HDR { #define SVC_ROUTE_MAX_BINDINGS 256 // Единый формат доставки сервисной кодограммы (router → сервис): -// [svc_id:1][src_node_id:8][dst_node_id:8][payload...] +// [svc_id:1][src_node_id:8][dst_node_id:8][rx_flags:1][payload...] // src/dst — реальные end-to-end узлы из SVC_ROUTE заголовка (не промежуточные). +// rx_flags — биты ROUTER_FLAG_ENCRYPTED/SIGNED, бывшие на wire (статус для сервиса). #define ROUTER_SVC_SRC_OFF 1 #define ROUTER_SVC_DST_OFF 9 -#define ROUTER_SVC_PAYLOAD_OFF 17 -#define ROUTER_SVC_HDR_SIZE 17 // svc_id(1) + src_node_id(8) + dst_node_id(8) +#define ROUTER_SVC_FLAGS_OFF 17 +#define ROUTER_SVC_PAYLOAD_OFF 18 +#define ROUTER_SVC_HDR_SIZE 18 // svc_id(1) + src_node_id(8) + dst_node_id(8) + rx_flags(1) // Биты в flags #define ROUTER_FLAG_START 0x80 @@ -158,15 +161,14 @@ struct ETCP_ROUTER_CONN { #define MINRTT_WINDOW_SIZE 10 #define MINRTT_DEFAULT_TB 100 // default minRTT = 10ms (заменяется первым RTT) -// Inflight запись — копия отправленного пакета для возможного ретрансмита +// Inflight запись — копия финального wire-пакета (уже закодирован encode'ом) для ретрансмита struct ROUTER_INFLIGHT { struct ll_entry ll; // индекс по seq (4 байта, offset 0) uint32_t seq; uint64_t last_sent_tb; // время последней отправки (0.1ms) uint8_t send_count; // число переотправок - uint8_t is_encrypted; // 1 = E2E-шифрованный пакет - uint8_t* payload; // копия данных - size_t payload_len; + uint8_t* dgram; // копия финального пакета [SVC_ROUTE_HDR][payload][sig?] + size_t dgram_len; }; // Bindings для сервисов внутри etcp_router (аналогично ETCP_BINDINGS) @@ -184,24 +186,18 @@ void etcp_router_destroy(struct UTUN_INSTANCE* inst); int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn callback); int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id); -// Отправить сервисный пакет (авто-conn, seq, inflight-контроль через send_q) -int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force); - -// Отправить сервисный пакет с E2E-шифрованием (AES-128-CCM через X25519 ECDH) -int etcp_route_send_encrypted(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force); +// Отправить сервисный пакет (авто-conn, seq, inflight-контроль через send_q). +// mode — битовая маска ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (см. route_crypto.h), 0 = обычный пакет. +int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force, int mode); // Найти/создать состояние seq-подключения по (group_id, remote_node_id, svc_id) struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id); // Отправить данные с авто-seq и контролем inflight -// data: payload без svc_id, flags: битовые флаги (зарезервировано) +// data: payload без svc_id, mode: ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT (0 = обычный) int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn, - const uint8_t* data, size_t len); - -// Отправить данные с Ed25519 подписью (аналог etcp_router_conn_send с флагом ROUTER_FLAG_SIGNED) -int etcp_router_conn_send_signed(struct ETCP_ROUTER_CONN* rconn, - const uint8_t* data, size_t len); + const uint8_t* data, size_t len, int mode); // Закрыть seq-подключение void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn); diff --git a/src/routing_layer/etcp_router_doc.md b/src/routing_layer/etcp_router_doc.md index bc3ffa33..cac1cec8 100644 --- a/src/routing_layer/etcp_router_doc.md +++ b/src/routing_layer/etcp_router_doc.md @@ -22,20 +22,21 @@ e->dgram = u_malloc(1 + payload_len); e->dgram[0] = svc_id; memcpy(e->dgram + 1, payload, payload_len); e->len = 1 + payload_len; -etcp_route_send(inst, dst_node_id, e, force); +etcp_route_send(inst, group_id, dst_node_id, e, force, mode); // mode: 0 / ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT // Или через существующий ROUTER_CONN: -struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, remote_node_id, svc_id); -etcp_router_conn_send(rconn, data, len); +struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, remote_node_id, svc_id); +etcp_router_conn_send(rconn, data, len, mode); ``` ### Приём ```c void my_service_callback(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!entry) { /* соединение закрыто */ return; } - uint8_t svc_id = entry->dgram[0]; - uint64_t from = *(uint64_t*)(entry->dgram + 1); // remote_node_id - // ... данные начиная с entry->dgram[9] ... + uint8_t svc_id = entry->dgram[0]; + uint64_t from = *(uint64_t*)(entry->dgram + ROUTER_SVC_SRC_OFF); // remote_node_id + uint8_t rx_flags = entry->dgram[ROUTER_SVC_FLAGS_OFF]; // был ли SIGNED/ENCRYPTED на wire + // ... данные начиная с entry->dgram[ROUTER_SVC_PAYLOAD_OFF] ... queue_dgram_free(entry); queue_entry_free(entry); } @@ -45,34 +46,40 @@ void my_service_callback(struct ETCP_CONN* conn, struct ll_entry* entry) { ```c // На send_q (inflight переполнен): struct queue_waiter_handle h; -etcp_router_on_send_ready(inst, node_id, svc_id, &h, my_ready_cb, my_arg); +etcp_router_on_send_ready(inst, group_id, node_id, svc_id, &h, my_ready_cb, my_arg); // Когда send_q освободится — вызовется my_ready_cb // На normalizer->input (сетевая очередь): -etcp_router_waiter_register(inst, node_id, &h, my_ready_cb, my_arg); +etcp_router_waiter_register(inst, group_id, node_id, &h, my_ready_cb, my_arg); ``` -### Подписанные сообщения +### Подпись / шифрование (модуль route_crypto) ```c -etcp_router_conn_send_signed(rconn, data, len); // добавляет Ed25519-подпись +// mode — битовая маска, применяется в начале функции отправки (route_crypto_encode), +// при приёме проверяется/расшифровывается перед вызовом коллбэка (route_crypto_decode). +#include "route_crypto.h" +etcp_route_send(inst, group_id, dst, e, force, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT); ``` ## 3. API ### Ключевые структуры -**SVC_ROUTE_HDR** (25 байт) — заголовок пакета: -`cmd(1) + dst_node_id(8) + src_node_id(8) + seq(4) + svc_id(1) + flags(1) + timestamp(2)` +**SVC_ROUTE_HDR** (33 байта) — заголовок пакета: +`cmd(1) + group_id(8) + dst_node_id(8) + src_node_id(8) + seq(4) + svc_id(1) + flags(1) + timestamp(2)` -Флаги: `ROUTER_FLAG_START` (0x80), `ROUTER_FLAG_RST` (0x40), `ROUTER_FLAG_SIGNED` (0x08), `ROUTER_FLAG_CLOSE` (0x02). Sess_id в bits 5-4. +Флаги: `ROUTER_FLAG_START` (0x80), `ROUTER_FLAG_RST` (0x40), `ROUTER_FLAG_SIGNED` (0x08), `ROUTER_FLAG_ENCRYPTED` (0x04), `ROUTER_FLAG_CLOSE` (0x02). Sess_id в bits 5-4. -**ETCP_ROUTER_CONN** — состояние логического подключения (remote_node_id + svc_id): +**Формат доставки сервису** (router → callback): +`[svc_id:1][src_node_id:8][dst_node_id:8][rx_flags:1][payload...]` (ROUTER_SVC_HDR_SIZE = 18). + +**ETCP_ROUTER_CONN** — состояние логического подключения (group_id + remote_node_id + svc_id): - `tx_seq`, `rx_seq`, `tx_acked` — seq-нумерация для порядка и inflight - `recv_q` — reorder-очередь с хеш-индексом по seq (восстановление порядка) - `send_q` — очередь ожидания при полном inflight (backpressure) - `send_waiter` — waiter на send_input_q (по 1 пакету, round-robin между сервисами) - `watchdog_timer` — медленная проверка инварианта drain (страховка от заклинивания) -- `inflight_q` — копии отправленных пакетов для ретрансмита (хеш по seq) +- `inflight_q` — копии финальных отправленных пакетов для ретрансмита (хеш по seq) - `incoming_q` — FIFO между сетевым приёмом и recv_q (защита от гонок) - `rtt`, `rtt_jitter`, `minrtt` — измерения задержки - `inflight_limit` — текущий лимит пакетов в полёте (minrtt_probe снижает до 4) @@ -80,9 +87,9 @@ etcp_router_conn_send_signed(rconn, data, len); // добавляет Ed25519- - `start_sent`, `peer_sync_done` — синхронизация после (пере)подключения - `closed` — флаг закрытия (игнорирование таймеров) -**ROUTER_INFLIGHT** — запись в inflight_q: `seq, last_sent_tb, send_count, payload*` +**ROUTER_INFLIGHT** — запись в inflight_q: `seq, last_sent_tb, send_count, dgram*` (финальный wire-пакет) -**TRANSIT_QUEUE** — per (src,dst) пара на промежуточном узле: +**TRANSIT_QUEUE** — per (group_id, src, dst) пара на промежуточном узле: - `q` — FIFO транзитных пакетов - `waiter` — backpressure на send_input_q next_hop'а - `conn` — ETCP_CONN следующего шага @@ -91,11 +98,11 @@ etcp_router_conn_send_signed(rconn, data, len); // добавляет Ed25519- ``` Приём: сеть → incoming_q (FIFO) → router_incoming_q_cb → recv_q (хеш по seq) ↓ - router_try_assembly → deliver (rx_seq++) + router_try_assembly → deliver → route_crypto_decode → cb -Отправка: router_enqueue_send → send_q (FIFO, backpressure) +Отправка: router_enqueue_send → router_build_packet (seq + route_crypto_encode) → send_q (FIFO, backpressure) router_send_kick → waiter на send_input_q → router_send_drain_cb (по 1 пакету, round-robin) - → router_send_one_flags → etcp_send + inflight_q (копия) + → etcp_send + inflight_q (копия финального пакета) ↓ router_track_inflight_state + retrans_schedule ACK: периодический (10ms) + idle (500ms) → router_send_ack(rx_seq) @@ -119,17 +126,22 @@ ACK: периодический (10ms) + idle (500ms) → router_send_ack(rx_seq | `etcp_router_destroy(inst)` | Деинициализация: unbind + close_all + free | | `etcp_router_bind(inst, svc_id, cb)` | Зарегистрировать обработчик сервиса | | `etcp_router_unbind(inst, svc_id)` | Удалить обработчик сервиса | -| `etcp_route_send(inst, dst, entry, force)` | Отправить пакет (loopback/transit/direct) | -| `etcp_router_conn_get(inst, remote, svc_id)` | Найти или создать ROUTER_CONN | -| `etcp_router_conn_send(rconn, data, len)` | Отправить данные с авто-seq и inflight-контролем | -| `etcp_router_conn_send_signed(rconn, data, len)` | Отправить с Ed25519-подписью | +| `etcp_route_send(inst, group, dst, entry, force, mode)` | Отправить пакет (loopback/transit/direct); mode = ROUTE_CRYPTO_SIGN/ENCRYPT | +| `etcp_router_conn_get(inst, group, remote, svc_id)` | Найти или создать ROUTER_CONN | +| `etcp_router_conn_send(rconn, data, len, mode)` | Отправить данные с авто-seq и inflight-контролем | | `etcp_router_conn_close(rconn)` | Закрыть seq-подключение (CLOSE + уведомление сервиса) | | `etcp_router_conn_close_async(rconn, cb, arg)` | Асинхронное закрытие с коллбэком | -| `etcp_router_conn_close_all_for_node(inst, node_id)` | Закрыть все conn к узлу | -| `etcp_router_conn_restart(inst, remote, svc_id)` | Сброс состояния (перезапуск удалённой стороны) | +| `etcp_router_conn_close_all_for_node(inst, group, node_id)` | Закрыть все conn к узлу | +| `etcp_router_conn_restart(inst, group, remote, svc_id)` | Сброс состояния (перезапуск удалённой стороны) | | `etcp_router_pause_retrans_for_node(inst, node_id)` | Сбросить ретрансмиты без закрытия (для conn reinit) | | `router_set_max_inflight(rconn, new_max)` | Установить рабочий max_inflight | -| `etcp_router_input_q_count(inst, node_id)` | Размер normalizer->input очереди узла | -| `etcp_router_waiter_register/cancel(inst, node_id, h, cb, arg)` | Backpressure на normalizer->input | -| `etcp_router_on_send_ready/cancel_send_ready(inst, node, svc, h, cb, arg)` | Backpressure на send_q | +| `etcp_router_input_q_count(inst, group, node_id)` | Размер normalizer->input очереди узла | +| `etcp_router_waiter_register/cancel(inst, group, node_id, h, cb, arg)` | Backpressure на normalizer->input | +| `etcp_router_on_send_ready/cancel_send_ready(inst, group, node, svc, h, cb, arg)` | Backpressure на send_q | | `etcp_router_transit_queues_destroy(conn)` | Удалить все транзитные очереди ETCP_CONN | + +### Модуль route_crypto (пред/пост-обработка пакета) +| Функция | Описание | +|---|---| +| `route_crypto_encode(inst, peer, base, len, mode, &out, &len)` | Шифрование/подпись в начале отправки → финальный пакет | +| `route_crypto_decode(inst, wire, len, &out, &len, &rx_flags)` | Проверка подписи/расшифровка перед коллбэком; ошибка → дроп | diff --git a/src/routing_layer/route_crypto.c b/src/routing_layer/route_crypto.c new file mode 100644 index 00000000..9d485983 --- /dev/null +++ b/src/routing_layer/route_crypto.c @@ -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 + +// 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; +} diff --git a/src/routing_layer/route_crypto.h b/src/routing_layer/route_crypto.h new file mode 100644 index 00000000..5a44f2f8 --- /dev/null +++ b/src/routing_layer/route_crypto.h @@ -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 +#include +#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 diff --git a/src/routing_layer/routing.c b/src/routing_layer/routing.c index e23248ea..bf143992 100644 --- a/src/routing_layer/routing.c +++ b/src/routing_layer/routing.c @@ -145,7 +145,7 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t } else { DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s", ip_len, (unsigned long long)nq->node_id, ip_to_str(&addr, AF_INET).str); - int send_err = etcp_route_send(instance, TOPO_GROUP_UTUN, nq->node_id, entry, 1); + int send_err = etcp_route_send(instance, TOPO_GROUP_UTUN, nq->node_id, entry, 1, 0); if (send_err != 0) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d", ip_to_str(&addr, AF_INET).str, send_err); diff --git a/tests/test_etcp_router.c b/tests/test_etcp_router.c index 468768c0..7ebb1840 100644 --- a/tests/test_etcp_router.c +++ b/tests/test_etcp_router.c @@ -243,7 +243,7 @@ static int send_one_pkt(uint32_t seq, int data_len) { memcpy(e->dgram, buf, 10 + data_len); e->len = 10 + data_len; - return etcp_route_send(cli, TOPO_GROUP_UTUN, server_node_id, e, 0); + return etcp_route_send(cli, TOPO_GROUP_UTUN, server_node_id, e, 0, 0); } // ======================== Server handler ======================== @@ -338,7 +338,7 @@ static int test_loopback(void) { uint8_t data[6] = { 0xF0, 0xAA, 0xBB, 0xCC, 0x00, 0x00 }; struct ll_entry* e = queue_entry_new(0); e->dgram = u_malloc(6); memcpy(e->dgram, data, 6); e->len = 6; - etcp_route_send(srv, TOPO_GROUP_UTUN, srv->node_id, e, 0); + etcp_route_send(srv, TOPO_GROUP_UTUN, srv->node_id, e, 0, 0); etcp_router_unbind(srv, 0xF0); if (loop_rcvd != 1 || !loop_ok) { printf("[FAIL] loopback: rcvd=%d ok=%d\n", loop_rcvd, loop_ok); diff --git a/tests/test_etcp_router_reconnect.c b/tests/test_etcp_router_reconnect.c index d1e9b184..23381595 100644 --- a/tests/test_etcp_router_reconnect.c +++ b/tests/test_etcp_router_reconnect.c @@ -148,7 +148,7 @@ static int send_one_pkt(void) { gen_payload(g_seq, buf+7, len); struct ll_entry* e=queue_entry_new(0); if(!e){u_free(buf);return -1;} e->dgram=buf; e->len=7+len; - int ret = etcp_route_send(g_a, TOPO_GROUP_UTUN, node_c, e, 0); + int ret = etcp_route_send(g_a, TOPO_GROUP_UTUN, node_c, e, 0, 0); if (ret == 0) g_seq++; return ret; } diff --git a/tests/test_etcp_router_unit.c b/tests/test_etcp_router_unit.c index 1554ac27..b7cc4d8e 100644 --- a/tests/test_etcp_router_unit.c +++ b/tests/test_etcp_router_unit.c @@ -18,6 +18,7 @@ #include "../lib/debug_config.h" #include "../lib/mem.h" #include "../src/transport_layer/secure_channel.h" +#include #define TEST_SVC_ID 0x42 #define TEST_SVC_ID2 0x43 @@ -131,6 +132,7 @@ static int g_sign_ready = 0; static struct SC_MYKEYS g_sign_keys; static sc_context_t g_sign_ctx; static uint8_t g_sign_ed25519_pubkey[SC_PUBKEY_SIZE]; +static uint8_t g_sign_ed25519_privkey[SC_PRIVKEY_SIZE]; static const uint64_t SIGNER_NODE = 0xCCCC000000000001ULL; static int setup_sign_keys(void) { @@ -138,6 +140,7 @@ static int setup_sign_keys(void) { if (sc_generate_keypair(&g_sign_keys) != SC_OK) { printf(" setup_sign_keys: generate_keypair failed\n"); return -1; } sc_init_ctx(&g_sign_ctx, &g_sign_keys); if (sc_derive_ed25519_pubkey(g_sign_keys.private_key, g_sign_ed25519_pubkey) != SC_OK) { printf(" setup_sign_keys: derive_ed25519_pubkey failed\n"); return -1; } + { unsigned char h[SHA512_DIGEST_LENGTH]; SHA512(g_sign_keys.private_key, SC_PRIVKEY_SIZE, h); memcpy(g_sign_ed25519_privkey, h, SC_PRIVKEY_SIZE); } g_sign_ready = 1; return 0; } @@ -208,11 +211,7 @@ static void inject_signed(etcp_recv_fn recv_cb, struct UTUN_INSTANCE* inst, hdr->flags = flags | ROUTER_FLAG_SIGNED; if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, pl, pl_len); - struct sc_stream_sign_state sign_state; - if (sc_stream_sign_init(&g_sign_ctx, &sign_state) != SC_OK) { u_free(dgram); return; } - if (sc_stream_sign_update(&sign_state, dgram, hdr_pl) != SC_OK) { sc_stream_sign_cleanup(&sign_state); u_free(dgram); return; } - size_t sig_len = SC_SIGN_SIZE; - if (sc_stream_sign_final(&sign_state, dgram + hdr_pl, &sig_len) != SC_OK) { u_free(dgram); return; } + if (sc_ed25519_sign(g_sign_ed25519_privkey, dgram, hdr_pl, dgram + hdr_pl) != SC_OK) { u_free(dgram); return; } if (tamper_sig) dgram[hdr_pl] ^= 0x01; @@ -565,19 +564,25 @@ static int test_send_q(void) { struct ETCP_ROUTER_CONN* c = etcp_router_conn_get(&inst, TOPO_GROUP_UTUN, TEST_REMOTE_NODE, TEST_SVC_ID); if (!c) FAIL("conn_get failed"); - // Simulate full inflight: set tx_acked far behind tx_seq - c->tx_seq = ROUTER_MAX_INFLIGHT; - c->tx_acked = 0; + // Заполняем inflight_q до лимита — канал «загружен» + for (int i = 0; i < ROUTER_MAX_INFLIGHT; i++) { + struct ROUTER_INFLIGHT* inf = u_malloc(sizeof(struct ROUTER_INFLIGHT)); + if (!inf) FAIL("inflight alloc"); + memset(&inf->ll, 0, sizeof(inf->ll)); + inf->ll.size = 4; inf->seq = (uint32_t)i; *(uint32_t*)inf->ll.data = (uint32_t)i; + inf->dgram = u_malloc(1); inf->dgram_len = 1; + queue_data_put_with_index(c->inflight_q, &inf->ll); + } if (c->send_q == NULL) FAIL("send_q is NULL"); // Send via conn_send — should queue, not drop uint8_t data[4] = { 1, 2, 3, 4 }; - int ret = etcp_router_conn_send(c, data, sizeof(data)); + int ret = etcp_router_conn_send(c, data, sizeof(data), 0); if (ret != 0) FAIL("conn_send should return 0 (queued in send_q)"); if (c->send_blocked == 0) FAIL("send_blocked not set"); if (c->watchdog_timer == NULL) FAIL("watchdog_timer not set"); if (queue_entry_count(c->send_q) != 1) FAIL("send_q count != 1"); - if (c->tx_seq != ROUTER_MAX_INFLIGHT) FAIL("tx_seq advanced while queued"); + if (c->tx_seq != 1) FAIL("tx_seq should advance to 1 at enqueue"); // Cancel timers manually if (c->watchdog_timer) { uasync_cancel_timeout(ua, c->watchdog_timer); c->watchdog_timer = NULL; } @@ -602,7 +607,7 @@ static int test_loopback(void) { memcpy(e->dgram, buf, 4); e->len = 4; - if (etcp_route_send(&inst, TOPO_GROUP_UTUN, inst.node_id, e, 0) != 0) FAIL("loopback send failed"); + if (etcp_route_send(&inst, TOPO_GROUP_UTUN, inst.node_id, e, 0, 0) != 0) FAIL("loopback send failed"); if (rx.delivered != 1) FAIL("loopback not delivered"); if (rx.errors != 0) FAIL("loopback data mismatch"); @@ -642,7 +647,7 @@ static int test_conn_send_no_bgp(void) { if (!c) FAIL("conn_get failed"); uint8_t data[4] = { 1, 2, 3, 4 }; - int ret = etcp_router_conn_send(c, data, sizeof(data)); + int ret = etcp_router_conn_send(c, data, sizeof(data), 0); if (ret != 0) FAIL("conn_send should buffer (return 0) without BGP"); if (c->no_route == 0) FAIL("no_route not set"); if (queue_entry_count(c->send_q) != 1) FAIL("send_q count != 1"); @@ -1144,11 +1149,7 @@ static int test_e2e_combined_signed(void) { hdr->flags = ROUTER_FLAG_ENCRYPTED | ROUTER_FLAG_SIGNED | ROUTER_FLAG_START; memcpy(dgram + SVC_ROUTE_HDR_SIZE, enc_buf, enc_len); - struct sc_stream_sign_state sign_state; - if (sc_stream_sign_init(&g_sign_ctx, &sign_state) != SC_OK) { u_free(dgram); u_free(enc_buf); FAIL("sign init"); } - if (sc_stream_sign_update(&sign_state, dgram, hdr_pl) != SC_OK) { sc_stream_sign_cleanup(&sign_state); u_free(dgram); u_free(enc_buf); FAIL("sign update"); } - size_t sig_len = SC_SIGN_SIZE; - if (sc_stream_sign_final(&sign_state, dgram + hdr_pl, &sig_len) != SC_OK) { u_free(dgram); u_free(enc_buf); FAIL("sign final"); } + if (sc_ed25519_sign(g_sign_ed25519_privkey, dgram, hdr_pl, dgram + hdr_pl) != SC_OK) { u_free(dgram); u_free(enc_buf); FAIL("sign"); } struct ll_entry* e = queue_entry_new(0); if (!e) { u_free(dgram); u_free(enc_buf); FAIL("entry"); } diff --git a/tests/test_media_delivery_full.c b/tests/test_media_delivery_full.c index 4c57b3dd..cf3f001c 100644 --- a/tests/test_media_delivery_full.c +++ b/tests/test_media_delivery_full.c @@ -104,7 +104,7 @@ static int msend(struct UTUN_INSTANCE* inst, uint64_t dst, const uint8_t* data, e->dgram[0] = ETCP_RT_ID_MEDIA_DELIVERY; memcpy(e->dgram + 1, data, len); e->len = (uint16_t)(len + 1); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[msend] 0x%016llx → 0x%016llx svc=0x%02x subcmd=0x%02x len=%zu", (unsigned long long)inst->node_id, (unsigned long long)dst, e->dgram[0], data[0], len); - int rc = etcp_route_send(inst, TOPO_GROUP_UTUN, dst, e, 1); + int rc = etcp_route_send(inst, TOPO_GROUP_UTUN, dst, e, 1, 0); if (rc != 0) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "[msend] FAILED rc=%d", rc); u_free(e->dgram); queue_entry_free(e); } return rc; } diff --git a/tests/test_media_delivery_integration.c b/tests/test_media_delivery_integration.c index 1b40952c..a6c5004c 100644 --- a/tests/test_media_delivery_integration.c +++ b/tests/test_media_delivery_integration.c @@ -117,7 +117,7 @@ static int msend(struct UTUN_INSTANCE* inst, uint64_t dst, const uint8_t* data, e->dgram = u_malloc(len + 1); if (!e->dgram) { queue_entry_free(e); return -1; } e->dgram[0] = ETCP_RT_ID_MEDIA_DELIVERY; memcpy(e->dgram + 1, data, len); e->len = (uint16_t)(len + 1); - int rc = etcp_route_send(inst, TOPO_GROUP_UTUN, dst, e, 1); + int rc = etcp_route_send(inst, TOPO_GROUP_UTUN, dst, e, 1, 0); if (rc != 0) { u_free(e->dgram); queue_entry_free(e); } return rc; } diff --git a/tests/test_nat_transport.c b/tests/test_nat_transport.c index 938477bf..69a4a363 100644 --- a/tests/test_nat_transport.c +++ b/tests/test_nat_transport.c @@ -306,7 +306,7 @@ static int test_provider_egress(void) { entry->dgram = dgram; entry->len = total; - int ret = etcp_route_send(inst_client, TOPO_GROUP_UTUN, g_provider_node_id, entry, 0); + int ret = etcp_route_send(inst_client, TOPO_GROUP_UTUN, g_provider_node_id, entry, 0, 0); if (ret != 0) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "etcp_route_send failed"); queue_dgram_free(entry); @@ -474,7 +474,7 @@ static int test_full_roundtrip(void) { struct ll_entry* entry = queue_entry_new(0); entry->dgram = dgram; entry->len = total; - int ret = etcp_route_send(inst_client, TOPO_GROUP_UTUN, g_provider_node_id, entry, 0); + int ret = etcp_route_send(inst_client, TOPO_GROUP_UTUN, g_provider_node_id, entry, 0, 0); if (ret != 0) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "etcp_route_send failed"); queue_dgram_free(entry); queue_entry_free(entry); return 0; } // Poll for provider to process egress diff --git a/tools/chatgui/transport/utun_node.cpp b/tools/chatgui/transport/utun_node.cpp index ed4bfe3b..75f91d2e 100644 --- a/tools/chatgui/transport/utun_node.cpp +++ b/tools/chatgui/transport/utun_node.cpp @@ -112,7 +112,7 @@ void UtunNode::send(uint64_t dstNodeId, const QByteArray& data) { struct ll_entry* entry = queue_entry_new(data.size()); if (!entry) return; memcpy(entry->data, data.constData(), data.size()); - etcp_route_send(m_instance, TOPO_GROUP_UTUN, dstNodeId, entry, 0); + etcp_route_send(m_instance, TOPO_GROUP_UTUN, dstNodeId, entry, 0, 0); } QString UtunNode::nodeIdHex() const {