|
|
|
|
@ -20,6 +20,8 @@
|
|
|
|
|
#include "../routing_layer/topo_node.h" |
|
|
|
|
#include "../utun_instance.h" |
|
|
|
|
#include "../transport_layer/etcp.h" |
|
|
|
|
#include "../transport_layer/etcp_api.h" |
|
|
|
|
#include "../routing_layer/etcp_router.h" |
|
|
|
|
#include "../transport_layer/secure_channel.h" |
|
|
|
|
#include "../ntp_time.h" |
|
|
|
|
#include "../lib/u_async.h" |
|
|
|
|
@ -250,8 +252,29 @@ static size_t test_body(struct UTUN_INSTANCE* author, uint64_t seq, const char*
|
|
|
|
|
return 39 + enc_len + 64; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Вход сервиса после аутентификации router; отдельно от реального UDP-сценария ниже. */ |
|
|
|
|
static int mailbox_packet(struct UTUN_INSTANCE* dst, uint64_t source, uint8_t cmd, const uint8_t* body, size_t len) { |
|
|
|
|
struct ETCP_CONN* conn = instance_find_conn(dst, dst->node_id == g_sh.nid[IDX_C] ? g_sh.nid[IDX_A] : g_sh.nid[IDX_C]); |
|
|
|
|
if (!conn || !dst->router_bindings.callbacks[ETCP_RT_ID_DM_MAILBOX]) return -1; |
|
|
|
|
struct ll_entry* e = queue_entry_new(0); |
|
|
|
|
if (!e) return -1; |
|
|
|
|
e->len = (uint16_t)(ROUTER_SVC_PAYLOAD_OFF + 1 + len); |
|
|
|
|
e->dgram = u_calloc(1, e->len); |
|
|
|
|
if (!e->dgram) { queue_entry_free(e); return -1; } |
|
|
|
|
uint64_t gid = strtoull(CH_ID, NULL, 10); |
|
|
|
|
e->dgram[0] = ETCP_RT_ID_DM_MAILBOX; |
|
|
|
|
memcpy(e->dgram + ROUTER_SVC_SRC_OFF, &source, 8); |
|
|
|
|
memcpy(e->dgram + ROUTER_SVC_DST_OFF, &dst->node_id, 8); |
|
|
|
|
memcpy(e->dgram + ROUTER_SVC_GROUP_OFF, &gid, 8); |
|
|
|
|
e->dgram[ROUTER_SVC_FLAGS_OFF] = ROUTER_FLAG_SIGNED; |
|
|
|
|
e->dgram[ROUTER_SVC_PAYLOAD_OFF] = cmd; |
|
|
|
|
memcpy(e->dgram + ROUTER_SVC_PAYLOAD_OFF + 1, body, len); |
|
|
|
|
dst->router_bindings.callbacks[ETCP_RT_ID_DM_MAILBOX](conn, e); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Ошибочный commit, tamper, точные повторы и ACK чужого тела не теряют pending. */ |
|
|
|
|
static int protocol_checks(struct UTUN_INSTANCE* A, struct UTUN_INSTANCE* B) { |
|
|
|
|
static int protocol_checks(struct UTUN_INSTANCE* A, struct UTUN_INSTANCE* B, struct UTUN_INSTANCE* C) { |
|
|
|
|
uint8_t body[512], receipt[DM_RECEIPT_SIZE], again[DM_RECEIPT_SIZE]; |
|
|
|
|
size_t len = test_body(A, 100, "higher", body); |
|
|
|
|
if (!len || dm_accept_message(B, body, len, receipt) != 0 || |
|
|
|
|
@ -291,6 +314,25 @@ static int protocol_checks(struct UTUN_INSTANCE* A, struct UTUN_INSTANCE* B) {
|
|
|
|
|
int seq_unchanged = sqlite3_step(st) == SQLITE_ROW && sqlite3_column_int64(st, 0) == 1; |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
if (!seq_unchanged) return -1; |
|
|
|
|
/* Суперузел хранит только проверенные тела и удаляет только точный подтверждённый экземпляр. */ |
|
|
|
|
len = test_body(A, 97, "mailbox-exact-receipt", body); |
|
|
|
|
if (!len) return -1; |
|
|
|
|
uint8_t put[8 + 512]; |
|
|
|
|
memcpy(put, &B->node_id, 8); |
|
|
|
|
memcpy(put + 8, body, len); |
|
|
|
|
if (mailbox_packet(A, A->node_id, 1, put, len + 8) != 0 || dm_mail_count(A) != 0) return -1; /* A без роли. */ |
|
|
|
|
put[8 + len - 1] ^= 1; |
|
|
|
|
if (mailbox_packet(C, A->node_id, 1, put, len + 8) != 0 || dm_mail_count(C) != 0) return -1; |
|
|
|
|
put[8 + len - 1] ^= 1; |
|
|
|
|
if (mailbox_packet(C, A->node_id, 1, put, len + 8) != 0 || dm_mail_count(C) != 1) return -1; |
|
|
|
|
if (dm_accept_message(B, body, len, receipt) != 0) return -1; |
|
|
|
|
memcpy(again, receipt, sizeof(again)); |
|
|
|
|
again[40] ^= 1; |
|
|
|
|
if (sc_ed25519_sign(B->my_ed25519_privkey, again, 72, again + 72) != SC_OK) return -1; |
|
|
|
|
if (mailbox_packet(C, B->node_id, 3, again, sizeof(again)) != 0 || dm_mail_count(C) != 1) return -1; |
|
|
|
|
if (mailbox_packet(C, C->node_id, 3, receipt, sizeof(receipt)) != 0 || dm_mail_count(C) != 1) return -1; |
|
|
|
|
if (mailbox_packet(C, B->node_id, 3, receipt, sizeof(receipt)) != 0 || dm_mail_count(C) != 0) return -1; |
|
|
|
|
if (mailbox_packet(C, A->node_id, 1, put, len + 8) != 0 || dm_mail_count(C) != 0) return -1; /* Поздний PUT. */ |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DM, "protocol checks passed: reorder, dedup, tamper, DB rollback, exact receipt"); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
@ -394,7 +436,7 @@ static void dm_tick(void* arg) {
|
|
|
|
|
break; |
|
|
|
|
case P_SEND1: |
|
|
|
|
if (dm_start(A, nb, g_sh.x_pub[IDX_B], g_sh.ed_pub[IDX_B], "B", CH_ID) != 0 |
|
|
|
|
|| dm_send(A, g_sh.conv_id, "text", (const uint8_t*)"hello1", 6) != 0 || protocol_checks(A, B) != 0) { |
|
|
|
|
|| dm_send(A, g_sh.conv_id, "text", (const uint8_t*)"hello1", 6) != 0 || protocol_checks(A, B, C) != 0) { |
|
|
|
|
fprintf(stderr, "A: dm_start/send hello1 failed\n"); |
|
|
|
|
t->result = 2; |
|
|
|
|
} else { |
|
|
|
|
|