FINAL: Encryption fully implemented with tests. Add etcp_connections_get_crypto_stats signature fix and tests in Makefile.am
This commit is contained in:
1 parent
fbd9119cd3
commit
f6c337bd1c
12 files changed
+393
-798
No files matched your search
@@ -4,6 +4,7 @@ utun_SOURCES = \
|
||||
utun.c \
|
||||
utun_instance.c \
|
||||
config_parser.c \
|
||||
config_updater.c \
|
||||
routing.c \
|
||||
tun_if.c \
|
||||
etcp.c \
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
// Функции инициализации
|
||||
|
||||
Reference in new issue
Block a user