FINAL: Encryption fully implemented with tests. Add etcp_connections_get_crypto_stats signature fix and tests in Makefile.am

This commit is contained in:
Evgeny committed 2026-01-18 21:20:56 +03:00
1 parent fbd9119cd3
commit f6c337bd1c
12 files changed
+393 -798

No files matched your search

+1
View File
@@ -4,6 +4,7 @@ utun_SOURCES = \
utun.c \
utun_instance.c \
config_parser.c \
config_updater.c \
routing.c \
tun_if.c \
etcp.c \
+1
View File
@@ -65,6 +65,7 @@ void etcp_conn_input(struct ETCP_CONN* etcp, struct packet_buffer* pkt) {
if (!etcp || !pkt) return;
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: packet len=%u", pkt->metadata.data_len);
// пока отправляй сразу в очередь. и из очереди сразу принимай через callback
// TODO: process packet through ETCP protocol
// This will be implemented later for data transfer
+31 -33
View File
@@ -214,6 +214,22 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
uint8_t decrypted_buf[1500];
bool was_decrypted = false;
// Извлекаем pubkey из конца только для INIT_REQUEST
if (cmd == ETCP_INIT_REQUEST && data_len >= SC_PUBKEY_SIZE) {
// Сохраняем pubkey перед изменением data_len
uint8_t pubkey[SC_PUBKEY_SIZE];
memcpy(pubkey, data + data_len - SC_PUBKEY_SIZE, SC_PUBKEY_SIZE);
data_len -= SC_PUBKEY_SIZE;
// Устанавливаем pubkey в secure channel
if (sc && sc->initialized) {
sc_set_peer_public_key(sc, pubkey);
}
// Обновляем cmd, так как data_len изменился
cmd = data[0];
}
if (sc && sc->session_ready && data_len > SC_TAG_SIZE) {
size_t decrypted_len = sizeof(decrypted_buf);
@@ -237,22 +253,6 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
}
}
// Извлекаем pubkey из конца только для INIT_REQUEST
if (cmd == ETCP_INIT_REQUEST && data_len >= SC_PUBKEY_SIZE) {
// Сохраняем pubkey перед изменением data_len
uint8_t pubkey[SC_PUBKEY_SIZE];
memcpy(pubkey, data + data_len - SC_PUBKEY_SIZE, SC_PUBKEY_SIZE);
data_len -= SC_PUBKEY_SIZE;
// Устанавливаем pubkey в secure channel
if (sc && sc->initialized) {
sc_set_peer_public_key(sc, pubkey);
}
// Обновляем cmd, так как data_len изменился
cmd = data[0];
}
// Обработка INIT REQUEST
if (cmd == ETCP_INIT_REQUEST) {
if (pkt->metadata.data_len < 1 + 8 + SC_PUBKEY_SIZE + 2 + 2) {
@@ -604,23 +604,6 @@ int etcp_socket_send(struct ETCP_SOCKET* sock, const uint8_t* data, size_t len,
return sendto(sock->fd, data, len, 0, to_addr, addr_len);
}
int etcp_socket_get_fd(const struct ETCP_SOCKET* sock) {
if (!sock) return -1;
return sock->fd;
}
void etcp_socket_get_local_addr(const struct ETCP_SOCKET* sock, struct sockaddr_storage* addr, socklen_t* addr_len) {
if (!sock || !addr || !addr_len) return;
memcpy(addr, &sock->local_addr, sock->local_addr_len);
*addr_len = sock->local_addr_len;
}
int etcp_socket_set_option(struct ETCP_SOCKET* sock, int level, int optname, const void* optval, socklen_t optlen) {
if (!sock || sock->fd < 0) return -1;
return setsockopt(sock->fd, level, optname, optval, optlen);
}
// Callback для приема пакетов через uasync
static void etcp_socket_read_callback(int fd, void* user_arg) {
struct ETCP_CONNECTIONS* conns = (struct ETCP_CONNECTIONS*)user_arg;
@@ -880,3 +863,18 @@ size_t etcp_connections_get_channel_count(const struct ETCP_CONNECTIONS* conns)
}
void etcp_connections_get_crypto_stats(const struct ETCP_CONNECTIONS* conns,
size_t* encrypt_errors,
size_t* decrypt_errors,
size_t* send_errors,
size_t* recv_errors,
size_t* total_encrypted,
size_t* total_decrypted){
if (!conns) return;
if (encrypt_errors) *encrypt_errors = conns->encrypt_errors;
if (decrypt_errors) *decrypt_errors = conns->decrypt_errors;
if (send_errors) *send_errors = conns->send_errors;
if (recv_errors) *recv_errors = conns->recv_errors;
if (total_encrypted) *total_encrypted = conns->total_encrypted;
if (total_decrypted) *total_decrypted = conns->total_decrypted;
}
-751
View File
@@ -1,751 +0,0 @@
#include "etcp_connections.h"
#include <arpa/inet.h>
#include "routing.h"
#include "utun_instance.h"
#include "crc32.h"
#include "etcp.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Forward declaration
struct utun_instance;
// Бинарный поиск линка по ip_port_hash
static int find_link_index(struct ETCP_CONNECTIONS* conns, uint32_t hash) {
if (!conns || conns->num_channels == 0) return -1;
int left = 0;
int right = conns->num_channels - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (conns->links[mid]->ip_port_hash == hash) {
return mid;
} else if (conns->links[mid]->ip_port_hash < hash) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -(left + 1);
}
// Реалокация массива линков с увеличением в 2 раза
static int realloc_links(struct ETCP_CONNECTIONS* conns) {
size_t new_max = conns->max_channels == 0 ? 8 : conns->max_channels * 2;
struct ETCP_LINK** new_links = realloc(conns->links, new_max * sizeof(struct ETCP_LINK*));
if (!new_links) return -1;
conns->links = new_links;
conns->max_channels = new_max;
return 0;
}
// Вставка линка в отсортированный массив
static int insert_link(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) {
if (!conns || !link) return -1;
if (conns->num_channels >= conns->max_channels) {
if (realloc_links(conns) < 0) return -1;
}
int idx = find_link_index(conns, link->ip_port_hash);
if (idx >= 0) return -1;
idx = -(idx + 1);
if (idx < (int)conns->num_channels) {
memmove(&conns->links[idx + 1], &conns->links[idx],
(conns->num_channels - idx) * sizeof(struct ETCP_LINK*));
}
conns->links[idx] = link;
conns->num_channels++;
return 0;
}
// Удаление линка из массива
static void remove_link(struct ETCP_CONNECTIONS* conns, uint32_t hash) {
if (!conns || conns->num_channels == 0) return;
int idx = find_link_index(conns, hash);
if (idx < 0) return;
if (idx < (int)conns->num_channels - 1) {
memmove(&conns->links[idx], &conns->links[idx + 1],
(conns->num_channels - idx - 1) * sizeof(struct ETCP_LINK*));
}
conns->num_channels--;
}
struct ETCP_CONNECTIONS* etcp_connections_init(etcp_socket_t* socket) {
if (!socket) return NULL;
struct ETCP_CONNECTIONS* conns = calloc(1, sizeof(struct ETCP_CONNECTIONS));
if (!conns) return NULL;
memcpy(&conns->socket, socket, sizeof(struct ETCP_SOCKET));
return conns;
}
void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns) {
if (!conns) return;
for (size_t i = 0; i < conns->num_channels; i++) {
etcp_link_close(conns->links[i]);
}
free(conns->links);
free(conns);
}
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, etcp_socket_t* socket,
const struct sockaddr* remote_addr, socklen_t addr_len) {
if (!etcp || !socket || !remote_addr || addr_len == 0) return NULL;
struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK));
if (!link) return NULL;
link->socket = (struct ETCP_SOCKET*)socket;
link->etcp = etcp;
memcpy(&link->remote_addr, remote_addr, addr_len);
link->remote_addr_len = addr_len;
link->last_activity = time(NULL);
uint8_t* addr_bytes = (uint8_t*)remote_addr;
link->ip_port_hash = crc32(0, addr_bytes, addr_len);
return link;
}
void etcp_link_close(struct ETCP_LINK* link) {
if (!link) return;
free(link);
}
int etcp_input(packet_buffer_t* pkt, etcp_socket_t* socket, struct ETCP_CONNECTIONS* conns) {
if (!pkt || !socket || !conns) return -1;
if (pkt->metadata.data_len < 1) return -1;
uint8_t* data = pkt->data;
uint8_t cmd = data[0];
struct sockaddr* src_addr = packet_remote_addr(pkt);
socklen_t addr_len = sizeof(struct sockaddr_storage);
if (cmd == ETCP_INIT_REQUEST) {
if (pkt->metadata.data_len < 1 + 8 + SC_PUBKEY_SIZE + 2 + 2) {
return -1;
}
struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len);
if (link) {
if (link->initialized) {
etcp_conn_reset(link->etcp);
}
etcp_link_remove_from_connections(conns, link);
etcp_link_close(link);
}
link = etcp_link_new(NULL, socket, src_addr, addr_len);
if (!link) return -1;
uint8_t* p = &data[1];
link->peer_node_id = 0;
memcpy(&link->peer_node_id, p, 8);
p += 8;
memcpy(link->peer_public_key, p, SC_PUBKEY_SIZE);
link->has_peer_key = 1;
p += SC_PUBKEY_SIZE;
uint16_t peer_mtu = ntohs(*(uint16_t*)p);
p += 2;
uint16_t peer_keepalive = ntohs(*(uint16_t*)p);
link->mtu = peer_mtu;
link->keepalive_interval = peer_keepalive;
etcp_link_add_to_connections(conns, link);
return etcp_link_send_init_response(link, 1500, 30);
}
struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len);
if (!link) {
struct ETCP_LINK* temp_link = etcp_link_new(NULL, socket, src_addr, addr_len);
if (temp_link) {
etcp_link_send_reset(temp_link);
etcp_link_close(temp_link);
}
return -1;
}
if (!link->initialized) {
switch (cmd) {
case ETCP_INIT_RESPONSE:
if (pkt->metadata.data_len < 1 + 8 + 2 + 2) return -1;
link->peer_node_id = 0;
memcpy(&link->peer_node_id, &data[1], 8);
link->mtu = ntohs(*(uint16_t*)&data[1 + 8]);
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8 + 2]);
link->initialized = 1;
break;
case ETCP_CHANNEL_INIT:
if (pkt->metadata.data_len < 1 + 8 + 2) return -1;
link->peer_node_id = 0;
memcpy(&link->peer_node_id, &data[1], 8);
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8]);
return etcp_link_send_channel_response(link);
case ETCP_CHANNEL_RESPONSE:
if (pkt->metadata.data_len < 1 + 8) return -1;
link->peer_node_id = 0;
memcpy(&link->peer_node_id, &data[1], 8);
link->initialized = 1;
break;
case ETCP_RESET:
etcp_link_remove_from_connections(conns, link);
etcp_link_close(link);
break;
default:
etcp_link_send_reset(link);
return -1;
}
} else {
if (cmd >= 0x02 && cmd <= 0x06) {
etcp_link_send_reset(link);
return -1;
}
}
link->last_activity = time(NULL);
return 0;
}
int etcp_link_init(struct ETCP_CONN* etcp, struct ETCP_LINK* link) {
return 0;
}
int etcp_link_send(struct ETCP_CONN* etcp, struct ETCP_LINK* link,
const uint8_t* data, size_t len) {
if (!etcp || !link || !data || len == 0) return -1;
link->last_activity = time(NULL);
return etcp_socket_send((etcp_socket_t*)link->socket, data, len,
(struct sockaddr*)&link->remote_addr);
}
int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) {
if (!link || mtu <= 0 || mtu > 65535) return -1;
uint8_t packet[1 + 8 + SC_PUBKEY_SIZE + 2 + 2];
uint8_t* p = packet;
*p++ = ETCP_INIT_REQUEST;
uint64_t node_id = link->etcp->node_id;
memcpy(p, &node_id, 8);
p += 8;
sc_context_t* sc = link->etcp->crypto_ctx;
if (!sc || !sc->initialized) return -1;
memcpy(p, sc->public_key, SC_PUBKEY_SIZE);
p += SC_PUBKEY_SIZE;
uint16_t mtu_be = htons(mtu);
memcpy(p, &mtu_be, 2);
p += 2;
uint16_t keepalive_be = htons(keepalive_interval);
memcpy(p, &keepalive_be, 2);
p += 2;
link->mtu = mtu;
link->keepalive_interval = keepalive_interval;
return etcp_socket_send((etcp_socket_t*)link->socket, packet, sizeof(packet),
(struct sockaddr*)&link->remote_addr);
}
int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) {
if (!link || mtu <= 0 || mtu > 65535) return -1;
uint8_t packet[1 + 8 + 2 + 2];
uint8_t* p = packet;
*p++ = ETCP_INIT_RESPONSE;
uint64_t node_id = link->etcp->node_id;
memcpy(p, &node_id, 8);
p += 8;
uint16_t mtu_be = htons(mtu);
memcpy(p, &mtu_be, 2);
p += 2;
uint16_t keepalive_be = htons(keepalive_interval);
memcpy(p, &keepalive_be, 2);
p += 2;
link->mtu = mtu;
link->keepalive_interval = keepalive_interval;
link->initialized = 1;
return etcp_socket_send((etcp_socket_t*)link->socket, packet, sizeof(packet),
(struct sockaddr*)&link->remote_addr);
}
int etcp_link_send_channel_init(struct ETCP_LINK* link, uint16_t keepalive_interval) {
if (!link) return -1;
uint8_t packet[1 + 8 + 2];
uint8_t* p = packet;
*p++ = ETCP_CHANNEL_INIT;
uint64_t node_id = link->etcp->node_id;
memcpy(p, &node_id, 8);
p += 8;
uint16_t keepalive_be = htons(keepalive_interval);
memcpy(p, &keepalive_be, 2);
p += 2;
link->keepalive_interval = keepalive_interval;
return etcp_socket_send((etcp_socket_t*)link->socket, packet, sizeof(packet),
(struct sockaddr*)&link->remote_addr);
}
int etcp_link_send_channel_response(struct ETCP_LINK* link) {
if (!link) return -1;
uint8_t packet[1 + 8];
uint8_t* p = packet;
*p++ = ETCP_CHANNEL_RESPONSE;
uint64_t node_id = link->etcp->node_id;
memcpy(p, &node_id, 8);
p += 8;
link->initialized = 1;
return etcp_socket_send((etcp_socket_t*)link->socket, packet, sizeof(packet),
(struct sockaddr*)&link->remote_addr);
}
int etcp_link_send_reset(struct ETCP_LINK* link) {
if (!link) return -1;
uint8_t packet[1] = {ETCP_RESET};
return etcp_socket_send((etcp_socket_t*)link->socket, packet, sizeof(packet),
(struct sockaddr*)&link->remote_addr);
}
struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_CONNECTIONS* conns,
const struct sockaddr* addr, socklen_t addr_len) {
if (!conns || !addr || addr_len == 0) return NULL;
uint32_t hash = crc32(0, (uint8_t*)addr, addr_len);
int idx = find_link_index(conns, hash);
if (idx >= 0) {
return conns->links[idx];
}
return NULL;
}
int etcp_link_add_to_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) {
if (!conns || !link) return -1;
return insert_link(conns, link);
}
void etcp_link_remove_from_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) {
if (!conns || !link) return;
remove_link(conns, link->ip_port_hash);
}
// SOCKET FUNCTIONS (moved from etcp_sockets.c)
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
etcp_socket_t* etcp_socket_create(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) {
if (!etcp) return NULL;
etcp_socket_t* sock = calloc(1, sizeof(etcp_socket_t));
if (!sock) return NULL;
sock->etcp = etcp;
sock->socket_id = (uint32_t)(uintptr_t)sock;
sock->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock->fd < 0) {
free(sock);
return NULL;
}
int flags = fcntl(sock->fd, F_GETFL, 0);
fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK);
struct sockaddr_in* addr = (struct sockaddr_in*)&sock->local_addr;
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
sock->local_addr_len = sizeof(struct sockaddr_in);
if (bind_addr) {
inet_pton(AF_INET, bind_addr, &addr->sin_addr);
} else {
addr->sin_addr.s_addr = INADDR_ANY;
}
if (bind(sock->fd, (struct sockaddr*)addr, sock->local_addr_len) < 0) {
close(sock->fd);
free(sock);
return NULL;
}
if (getsockname(sock->fd, (struct sockaddr*)addr, &sock->local_addr_len) < 0) {
close(sock->fd);
free(sock);
return NULL;
}
return sock;
}
void etcp_socket_destroy(etcp_socket_t* sock) {
if (!sock) return;
if (sock->fd >= 0) {
close(sock->fd);
}
free(sock);
}
int etcp_socket_send(etcp_socket_t* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr) {
if (!sock || sock->fd < 0 || !data || !to_addr) {
return -1;
}
socklen_t addr_len = (to_addr->sa_family == AF_INET) ?
sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6);
return sendto(sock->fd, data, len, 0, to_addr, addr_len);
}
int etcp_socket_get_fd(const etcp_socket_t* sock) {
if (!sock) return -1;
return sock->fd;
}
void etcp_socket_get_local_addr(const etcp_socket_t* sock, struct sockaddr_storage* addr, socklen_t* addr_len) {
if (!sock || !addr || !addr_len) return;
memcpy(addr, &sock->local_addr, sock->local_addr_len);
*addr_len = sock->local_addr_len;
}
int etcp_socket_set_option(etcp_socket_t* sock, int level, int optname, const void* optval, socklen_t optlen) {
if (!sock || sock->fd < 0) return -1;
return setsockopt(sock->fd, level, optname, optval, optlen);
}
// Connection management functions
void conn_destroy(conn_handle_t* handle) {
if (!handle) return;
if (handle->conns) {
etcp_socket_destroy((etcp_socket_t*)&handle->conns->socket);
etcp_connections_destroy(handle->conns);
}
if (handle->etcp) {
etcp_destroy(handle->etcp);
}
free(handle);
}
int conn_send(conn_handle_t* handle, const uint8_t* data, size_t len) {
if (!handle || !handle->conns || handle->conns->num_channels == 0 || !data || len == 0) {
return -1;
}
struct ETCP_LINK* link = handle->conns->links[0];
if (!link || !link->etcp) return -1;
return etcp_link_send(link->etcp, link, data, len);
}
// Parse address in format "IP:port" or "[IPv6]:port" and fill sockaddr
static int parse_addr_port(const char* addr_str, struct sockaddr_storage* addr, socklen_t* addr_len) {
if (!addr_str || !addr || !addr_len) return -1;
char addr_copy[MAX_ADDR_LEN];
strncpy(addr_copy, addr_str, MAX_ADDR_LEN - 1);
addr_copy[MAX_ADDR_LEN - 1] = '\0';
// Check for IPv6 format: [address]:port
if (addr_copy[0] == '[') {
char* closing_bracket = strchr(addr_copy, ']');
if (!closing_bracket) return -1;
// Find port after ']:'
char* colon = strchr(closing_bracket + 1, ':');
if (!colon) return -1;
*closing_bracket = '\0';
uint16_t port = (uint16_t)atoi(colon + 1);
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
memset(sin6, 0, sizeof(struct sockaddr_in6));
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
// Extract IP string and port from sockaddr_storage
static int sockaddr_to_ip_port(const struct sockaddr_storage* addr, char* ip_out, size_t ip_out_len, uint16_t* port_out) {
if (!addr || !ip_out || !port_out) return -1;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)addr;
*port_out = ntohs(sin->sin_port);
if (inet_ntop(AF_INET, &sin->sin_addr, ip_out, ip_out_len) == NULL) return -1;
} else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
*port_out = ntohs(sin6->sin6_port);
if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip_out, ip_out_len) == NULL) return -1;
} else {
return -1;
}
return 0;
}
for (int i = 0; i < config->server_count; i++) {
server_config_t* server = &config->servers[i];
char bind_addr[INET_ADDRSTRLEN];
struct sockaddr_storage server_addr;
socklen_t server_addr_len;
if (parse_addr_port(server->addr, &server_addr, &server_addr_len) < 0) {
fprintf(stderr, "Invalid server address '%s'\n", server->addr);
goto cleanup;
}
char bind_addr_str[INET6_ADDRSTRLEN];
uint16_t bind_port;
if (sockaddr_to_ip_port(&server_addr, bind_addr_str, sizeof(bind_addr_str), &bind_port) < 0) {
etcp_destroy(etcp);
goto cleanup;
}
}
etcp_socket_t* sock = etcp_socket_create(etcp, bind_addr, bind_port);
if (!sock) {
fprintf(stderr, "Failed to create socket for %s\n", server->name);
etcp_destroy(etcp);
goto cleanup;
}
if (i == 0) {
instance->first_listen_socket = (struct ETCP_SOCKET*)sock;
}
struct ETCP_CONNECTIONS* conns = etcp_connections_init(sock);
if (!conns) {
etcp_socket_destroy(sock);
etcp_destroy(etcp);
goto cleanup;
}
conn_handle_t* handle = calloc(1, sizeof(conn_handle_t));
if (!handle) {
etcp_connections_destroy(conns);
etcp_socket_destroy(sock);
etcp_destroy(etcp);
goto cleanup;
}
handle->etcp = etcp;
handle->conns = conns;
for (int j = 0; j < config->client_count; j++) {
client_config_t* client = &config->clients[j];
if (strcmp(client->from, server->name) != 0) continue;
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
if (parse_addr_port(client->to_addr, &client_addr, &client_addr_len) < 0) {
fprintf(stderr, "Invalid client address '%s'\n", client->to_addr);
continue;
}
memcpy(&addr, &client_addr, client_addr_len);
addr_len = client_addr_len;
struct sockaddr_in* sin = (struct sockaddr_in*)&addr;
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(client_port);
if (inet_pton(AF_INET, client_addr, &sin->sin_addr) != 1) continue;
addr_len = sizeof(struct sockaddr_in);
struct ETCP_LINK* link = etcp_link_new(etcp, sock, (struct sockaddr*)&addr, addr_len);
if (link) {
etcp_link_add_to_connections(conns, link);
}
}
instance->connections[i] = handle;
}
instance->connection_count = config->server_count;
return 0;
cleanup:
if (instance->connections) {
for (int j = 0; j < 0; j++) {
if (instance->connections[j]) {
conn_destroy(instance->connections[j]);
}
}
free(instance->connections);
instance->connections = NULL;
}
instance->first_listen_socket = NULL;
instance->connection_count = 0;
return -1;
}
#include "etcp_connections.h"
#include "etcp.h"
#include "config_parser.h"
#include "utun_instance.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Parse address in format "IP:port" or "[IPv6]:port" and fill sockaddr
if (!addr || !ip_out || !port_out) return -1;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)addr;
*port_out = ntohs(sin->sin_port);
if (inet_ntop(AF_INET, &sin->sin_addr, ip_out, ip_out_len) == NULL) return -1;
} else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
*port_out = ntohs(sin6->sin6_port);
if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip_out, ip_out_len) == NULL) return -1;
} else {
return -1;
}
return 0;
int init_connections(utun_instance_t* instance) {
if (!instance || !instance->config) {
fprintf(stderr, "Invalid instance or config\n");
return -1;
}
utun_config_t* config = instance->config;
int total_connections = config->server_count, i = 0;
if (total_connections == 0) {
fprintf(stderr, "No servers found in configuration\n");
return -1;
}
instance->connections = calloc(total_connections, sizeof(conn_handle_t*));
if (!instance->connections) {
fprintf(stderr, "Failed to allocate connections array\n");
return -1;
}
for (i = 0; i < config->server_count; i++) {
server_config_t* server = &config->servers[i];
struct sockaddr_storage server_addr;
socklen_t server_addr_len;
if (parse_addr_port(server->addr, &server_addr, &server_addr_len) < 0) {
fprintf(stderr, "Invalid server address '%s'\n", server->addr);
goto cleanup;
}
struct ETCP_CONN* etcp = etcp_create(instance);
if (!etcp) {
fprintf(stderr, "Failed to create ETCP for server %s\n", server->name);
goto cleanup;
}
char bind_addr_str[INET6_ADDRSTRLEN];
}
conn_handle_t* handle = calloc(1, sizeof(conn_handle_t));
if (!handle) {
etcp_connections_destroy(conns);
etcp_socket_destroy(sock);
etcp_destroy(etcp);
goto cleanup;
}
handle->etcp = etcp;
handle->conns = conns;
for (int j = 0; j < config->client_count; j++) {
client_config_t* client = &config->clients[j];
if (strcmp(client->from, server->name) != 0) continue;
struct sockaddr_storage client_addr;
socklen_t client_addr_len;
if (parse_addr_port(client->to_addr, &client_addr, &client_addr_len) < 0) {
fprintf(stderr, "Invalid client address '%s'\n", client->to_addr);
continue;
}
struct sockaddr_storage addr;
socklen_t addr_len = client_addr_len;
struct ETCP_LINK* link = etcp_link_new(etcp, sock, (struct sockaddr*)&addr, addr_len);
if (link) {
etcp_link_add_to_connections(conns, link);
}
}
instance->connections[i] = handle;
}
instance->connection_count = config->server_count;
return 0;
cleanup:
if (instance->connections) {
for (int j = 0; j < i; j++) {
if (instance->connections[j]) {
conn_destroy(instance->connections[j]);
}
}
free(instance->connections);
instance->connections = NULL;
}
instance->first_listen_socket = NULL;
instance->connection_count = 0;
return -1;
+1
View File
@@ -96,6 +96,7 @@ void etcp_connections_get_crypto_stats(const struct ETCP_CONNECTIONS* conns,
size_t* encrypt_errors,
size_t* decrypt_errors,
size_t* send_errors,
size_t* recv_errors,
size_t* total_encrypted,
size_t* total_decrypted);
+46 -7
View File
@@ -14,8 +14,23 @@
#include <sys/time.h>
#include "crc32.h"
#include <fcntl.h>
#include "sha256.h"
static const struct uECC_Curve_t *curve = NULL;
static uint8_t sc_urandom_seed[8] = {0};
static int sc_urandom_initialized = 0;
static void sc_init_random_seed(void)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
ssize_t ret = read(fd, sc_urandom_seed, 8);
close(fd);
if (ret == 8) {
sc_urandom_initialized = 1;
}
}
}
static int sc_rng(uint8_t *dest, unsigned size)
@@ -148,14 +163,38 @@ sc_status_t sc_set_peer_public_key(sc_context_t *ctx,
return SC_OK;
}
static void sc_build_nonce(uint32_t counter, uint8_t *nonce_out)
static void sc_build_nonce(uint64_t counter, uint8_t *nonce_out)
{
/* Simple nonce construction: counter in little-endian + zeros */
memset(nonce_out, 0, SC_NONCE_SIZE);
nonce_out[0] = (counter >> 0) & 0xFF;
nonce_out[1] = (counter >> 8) & 0xFF;
nonce_out[2] = (counter >> 16) & 0xFF;
nonce_out[3] = (counter >> 24) & 0xFF;
SHA256_CTX sha_ctx;
uint8_t hash[32];
struct timeval tv;
uint8_t data[8 + 8 + 4];
if (!sc_urandom_initialized) {
sc_init_random_seed();
}
gettimeofday(&tv, NULL);
memcpy(data, sc_urandom_seed, 8);
data[8] = (counter >> 0) & 0xFF;
data[9] = (counter >> 8) & 0xFF;
data[10] = (counter >> 16) & 0xFF;
data[11] = (counter >> 24) & 0xFF;
data[12] = (counter >> 32) & 0xFF;
data[13] = (counter >> 40) & 0xFF;
data[14] = (counter >> 48) & 0xFF;
data[15] = (counter >> 56) & 0xFF;
data[16] = (tv.tv_sec >> 0) & 0xFF;
data[17] = (tv.tv_sec >> 8) & 0xFF;
data[18] = (tv.tv_sec >> 16) & 0xFF;
data[19] = (tv.tv_sec >> 24) & 0xFF;
sha256_init(&sha_ctx);
sha256_update(&sha_ctx, data, 20);
sha256_final(&sha_ctx, hash);
memcpy(nonce_out, hash, SC_NONCE_SIZE);
}
sc_status_t sc_encrypt(sc_context_t *ctx,
+4 -4
View File
@@ -7,9 +7,9 @@
// Размеры ключей
#define SC_PRIVKEY_SIZE 32
#define SC_PUBKEY_SIZE 32
#define SC_PUBKEY_SIZE 64
#define SC_HASH_SIZE 32
#define SC_NONCE_SIZE 24
#define SC_NONCE_SIZE 8
#define SC_SHARED_SECRET_SIZE SC_HASH_SIZE
#define SC_SESSION_KEY_SIZE 16
#define SC_TAG_SIZE 8
@@ -44,8 +44,8 @@ struct secure_channel {
uint8_t initialized;
uint8_t peer_key_set;
uint8_t session_ready;
uint32_t tx_counter;
uint32_t rx_counter;
uint64_t tx_counter;
uint64_t rx_counter;
};
// Функции инициализации