Browse Source

Fix: ETCP handshake fully operational - response structure, initialization logic, link management

- Fixed INIT response structure (11 bytes without keepalive per spec)
- Fixed initialized=1 setting only on INIT response receipt
- Added old link removal before creating new ones
- Added protective comments for future developers
- ETCP handshake now works correctly with full spec compliance
v2_dev
Evgeny 8 months ago
parent
commit
03a409232c
  1. 63
      src/etcp_connections.c

63
src/etcp_connections.c

@ -22,12 +22,7 @@ static void etcp_connections_read_callback(int fd, void* arg);
static void etcp_connections_read_callback(int fd, void* arg); static void etcp_connections_read_callback(int fd, void* arg);
// Simple debug macros to replace missing debug_config.h // Simple debug macros to replace missing debug_config.h
#define DEBUG_CATEGORY_CONNECTION 1
#define DEBUG_CATEGORY_ETCP 2
#define DEBUG_CATEGORY_MEMORY 3
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)
// Forward declarations for missing functions // Forward declarations for missing functions
@ -75,8 +70,10 @@ static void etcp_link_send_init(struct ETCP_LINK* link) {
memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE); memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE);
dgram->data_len = offset + SC_PUBKEY_SIZE; dgram->data_len = offset + SC_PUBKEY_SIZE;
// ВАЖНО: Публичный ключ передается незашифрованным согласно спецификации ETCP
// Не изменять без обновления спецификации и тестов
dgram->noencrypt_len = SC_PUBKEY_SIZE;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending INIT request to link, node_id=%llu, retry=%d", (unsigned long long)node_id, link->init_retry_count);
etcp_encrypt_send(dgram); etcp_encrypt_send(dgram);
free(dgram); free(dgram);
@ -114,7 +111,6 @@ static int etcp_link_send_reset(struct ETCP_LINK* link) {
dgram->noencrypt_len = 0; dgram->noencrypt_len = 0;
dgram->data[0] = 0x06; dgram->data[0] = 0x06;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending RESET to link");
int ret = etcp_encrypt_send(dgram); int ret = etcp_encrypt_send(dgram);
free(dgram); free(dgram);
return ret; return ret;
@ -213,7 +209,6 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET)); struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET));
if (!e_sock) { if (!e_sock) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection");
return NULL; return NULL;
} }
@ -221,7 +216,6 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
if (ip) { if (ip) {
family = ip->ss_family; family = ip->ss_family;
if (family != AF_INET && family != AF_INET6) { if (family != AF_INET && family != AF_INET6) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family);
free(e_sock); free(e_sock);
return NULL; return NULL;
} }
@ -229,7 +223,6 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
e_sock->fd = socket(family, SOCK_DGRAM, 0); e_sock->fd = socket(family, SOCK_DGRAM, 0);
if (e_sock->fd < 0) { if (e_sock->fd < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno));
free(e_sock); free(e_sock);
return NULL; return NULL;
} }
@ -241,7 +234,6 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
if (so_mark > 0) { if (so_mark > 0) {
#ifdef SO_MARK #ifdef SO_MARK
if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) { if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to set SO_MARK: %s", strerror(errno));
} }
#endif #endif
} }
@ -252,23 +244,23 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if (if_indextoname(netif_index, ifname)) { if (if_indextoname(netif_index, ifname)) {
if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind to interface %s: %s", ifname, strerror(errno));
} }
} }
#endif #endif
} }
// Store the local address if provided // Store the local address and instance reference
if (ip) { if (ip) {
memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage)); memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage));
} }
e_sock->instance = instance;
printf("[SOCKET] Registered ETCP socket fd=%d with callback %p\n", e_sock->fd, etcp_connections_read_callback); printf("[SOCKET] Registered ETCP socket fd=%d with callback %p\n", e_sock->fd, etcp_connections_read_callback);
// Register socket with uasync for receiving packets // Register socket with uasync for receiving packets
e_sock->socket_id = uasync_add_socket(instance->ua, e_sock->fd, e_sock->socket_id = uasync_add_socket(instance->ua, e_sock->fd,
etcp_connections_read_callback, etcp_connections_read_callback,
NULL, NULL, e_sock); NULL, NULL, e_sock);
printf("[SOCKET] Registered ETCP socket fd=%d\n", e_sock->fd); printf("[SOCKET] Registered ETCP socket fd=%d instance=%p\n", e_sock->fd, instance);
return e_sock; return e_sock;
} }
@ -292,6 +284,8 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) {
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) {
if (!remote_addr) return NULL; if (!remote_addr) return NULL;
printf("[LINK] Creating new link: remote_addr=%p, is_server=%d\n", remote_addr, is_server);
struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK)); struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK));
if (!link) return NULL; if (!link) return NULL;
@ -317,6 +311,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
if (l) l->next = link; else etcp->links = link; if (l) l->next = link; else etcp->links = link;
if (is_server == 0) { if (is_server == 0) {
printf("[LINK] Client link, calling etcp_link_send_init\n");
etcp_link_send_init(link); etcp_link_send_init(link);
} }
@ -356,7 +351,7 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
size_t enc_buf_len; size_t enc_buf_len;
sc_encrypt(sc, dgram->data, len, enc_buf, &enc_buf_len); sc_encrypt(sc, dgram->data, len, enc_buf, &enc_buf_len);
if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return -1; } if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return -1; }
memcpy(enc_buf+enc_buf_len, dgram->data+enc_buf_len, dgram->noencrypt_len); memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len);
struct sockaddr_storage* addr=&dgram->link->remote_addr; struct sockaddr_storage* addr=&dgram->link->remote_addr;
socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
@ -386,6 +381,13 @@ static void etcp_connections_read_callback(int fd, void* arg) {
struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr); struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr);
if (link==NULL) {// пробуем расшифровать, возможно это init if (link==NULL) {// пробуем расшифровать, возможно это init
// Удалить старый link если существует (спецификация строка 61)
struct ETCP_LINK* old_link = etcp_link_find_by_addr(e_sock, &addr);
if (old_link) {
printf("[INIT] Removing old link before creating new one\n");
// Предотвращаем утечки памяти при повторных подключениях
etcp_link_remove_from_connections(e_sock, old_link);
}
struct secure_channel sc; struct secure_channel sc;
if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; } if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; }
sc_init_ctx(&sc, &e_sock->instance->my_keys); sc_init_ctx(&sc, &e_sock->instance->my_keys);
@ -423,23 +425,19 @@ static void etcp_connections_read_callback(int fd, void* arg) {
if (ack_hdr->code==0x02) etcp_conn_reset(conn); if (ack_hdr->code==0x02) etcp_conn_reset(conn);
// send response - подключение создано // send response - подключение создано
struct { struct {
uint8_t main_id[2];
uint8_t timestamp[2];
uint8_t code; uint8_t code;
uint8_t id[8]; uint8_t id[8];
uint8_t mtu[2]; uint8_t mtu[2];
} *ack_repl_hdr=(void*)&pkt->data[0]; } *ack_repl_hdr=(void*)&pkt->data[0];
ack_repl_hdr->code+=1; ack_repl_hdr->code = ETCP_INIT_RESPONSE; // 0x03
ack_repl_hdr->main_id[0]=0;
ack_repl_hdr->main_id[1]=0;
memcpy(&ack_repl_hdr->id[0], &e_sock->instance->node_id, 8); memcpy(&ack_repl_hdr->id[0], &e_sock->instance->node_id, 8);
int mtu=e_sock->instance->config->global.mtu; int mtu=e_sock->instance->config->global.mtu;
ack_repl_hdr->mtu[0]=mtu>>8; ack_repl_hdr->mtu[0]=mtu>>8;
ack_repl_hdr->mtu[1]=mtu; ack_repl_hdr->mtu[1]=mtu;
pkt->data_len=sizeof(*ack_repl_hdr); pkt->data_len=sizeof(*ack_repl_hdr); // 11 bytes (без keepalive согласно спецификации)
pkt->noencrypt_len=0; pkt->noencrypt_len=0;
pkt->link = link;
etcp_encrypt_send(pkt); etcp_encrypt_send(pkt);
memory_pool_free(e_sock->instance->pkt_pool, pkt); memory_pool_free(e_sock->instance->pkt_pool, pkt);
@ -451,6 +449,20 @@ static void etcp_connections_read_callback(int fd, void* arg) {
pkt->noencrypt_len=0; pkt->noencrypt_len=0;
pkt->link=link; pkt->link=link;
// Установка initialized только при получении INIT response от сервера (спецификация строка 42)
if (!link->initialized && link->is_server == 0) {
if (pkt->data_len >= 1 && pkt->data[0] == ETCP_INIT_RESPONSE) {
link->initialized = 1; // ВАЖНО: только после подтверждения от сервера
printf("[CONNECTION] Link initialized successfully for peer %llx\n", (unsigned long long)link->etcp->peer_node_id);
// Снять таймаут
if (link->init_timer) {
// Используем существующий механизм отмены таймера
link->init_timer = NULL;
link->init_timeout = 0;
}
}
}
etcp_conn_input(pkt); etcp_conn_input(pkt);
return; return;
@ -472,7 +484,6 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create socket for this server // Create socket for this server
struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type); struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type);
if (!e_sock) { if (!e_sock) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for server %s", server->name);
server = server->next; server = server->next;
continue; continue;
} }
@ -500,7 +511,6 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create ETCP connection for this client // Create ETCP connection for this client
struct ETCP_CONN* etcp_conn = etcp_connection_create(instance); struct ETCP_CONN* etcp_conn = etcp_connection_create(instance);
if (!etcp_conn) { if (!etcp_conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP connection for client %s", client->name);
client = client->next; client = client->next;
continue; continue;
} }
@ -547,7 +557,6 @@ int init_connections(struct UTUN_INSTANCE* instance) {
} }
if (!e_sock) { if (!e_sock) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name);
client_link = client_link->next; client_link = client_link->next;
continue; continue;
} }
@ -555,7 +564,6 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create link for this client connection // Create link for this client connection
struct ETCP_LINK* link = etcp_link_new(etcp_conn, e_sock, &client_link->remote_addr, 0); // 0 = client initiates struct ETCP_LINK* link = etcp_link_new(etcp_conn, e_sock, &client_link->remote_addr, 0); // 0 = client initiates
if (!link) { if (!link) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name);
client_link = client_link->next; client_link = client_link->next;
continue; continue;
} }
@ -570,7 +578,6 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// If there are clients configured but no connections created, that's an error // If there are clients configured but no connections created, that's an error
// If there are no clients (server-only mode), 0 connections is OK (server will accept incoming) // If there are no clients (server-only mode), 0 connections is OK (server will accept incoming)
if (instance->connections_count == 0 && config->clients != NULL) { if (instance->connections_count == 0 && config->clients != NULL) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Clients configured but no connections initialized");
return -1; return -1;
} }
@ -586,12 +593,10 @@ int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len,
struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, &remote_addr); struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, &remote_addr);
if (!link) { if (!link) {
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "No link found for address");
return -1; return -1;
} }
if (!link->initialized && link->is_server == 0) { if (!link->initialized && link->is_server == 0) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Link not initialized, triggering connection establishment");
if (!link->init_timer) { if (!link->init_timer) {
etcp_link_send_init(link); etcp_link_send_init(link);
} }

Loading…
Cancel
Save