Fix sockless TCP keepalive and require complete UTUN initialization
Receive keepalive through the owning ETCP link, preserve RX deadlines, and report routing metrics without TUN. Use independent netlink requests and track installed routes for rollback. Reject incomplete resource initialization and release partially constructed cores while preserving caller config ownership. Validated startup failure and rollback, padded keepalive, standby, STCP traffic, transport lifecycle, dynamic sockets, and daemon startup. Real TUN/netlink checks passed in an isolated Linux network namespace; modified modules passed FreeBSD compilation checks.
This commit is contained in:
1 parent
bb256dccdc
commit
72e2c89e3b
19 files changed
+541
-375
No files matched your search
+38
-34
@@ -60,6 +60,7 @@
|
||||
// Forward declarations
|
||||
static uint32_t get_dest_ip(const uint8_t *packet, size_t len);
|
||||
static int mkdir_recursive(const char* path);
|
||||
static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config);
|
||||
|
||||
// Global instance for signal handlers
|
||||
static struct UTUN_INSTANCE *g_instance = NULL;
|
||||
@@ -173,8 +174,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
struct ll_entry *entry = queue_entry_new(sizeof(struct NETWORK_ENTRY));
|
||||
if (!entry) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate network entry for %s", net->name);
|
||||
net = net->next;
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
struct NETWORK_ENTRY *ne = (struct NETWORK_ENTRY*)entry->data;
|
||||
ne->id = net->id & 0x00FFFFFFFFFFFFFFULL;
|
||||
@@ -195,6 +195,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
instance->ack_pool = memory_pool_init(sizeof(struct ACK_PACKET), "ack_pool");
|
||||
instance->data_pool = memory_pool_init(PACKET_DATA_SIZE, "data_pool");
|
||||
instance->pkt_pool = memory_pool_init(sizeof(struct ETCP_DGRAM) + PACKET_DATA_SIZE, "pkt_pool");
|
||||
if (!instance->ack_pool || !instance->data_pool || !instance->pkt_pool) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Core memory pool initialization failed"); return -1;
|
||||
}
|
||||
|
||||
// Create routing module
|
||||
if (routing_create(instance) != 0) {
|
||||
@@ -209,13 +212,14 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
return -1;
|
||||
}
|
||||
instance->nat_det = nat_detection_create(instance);
|
||||
if (!instance->nat_det) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT detection creation failed"); }
|
||||
if (!instance->nat_det) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT detection creation failed"); return -1; }
|
||||
|
||||
if (config->global.db_path[0]) mkdir_recursive(config->global.db_path);
|
||||
if (g_topo_group_enabled) {
|
||||
instance->topo_groups = topo_groups_init(instance);
|
||||
if (!instance->topo_groups) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to initialize BGP module");
|
||||
return -1;
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized");
|
||||
|
||||
@@ -225,8 +229,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
instance->topo_groups = NULL;
|
||||
}
|
||||
|
||||
socket_monitor_init(instance);
|
||||
auto_socket_init(instance);
|
||||
if (socket_monitor_init(instance) < 0 || auto_socket_init(instance) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "Socket monitoring/automatic socket initialization failed"); return -1;
|
||||
}
|
||||
if (g_topo_group_enabled && instance->topo_groups)
|
||||
topo_node_update_my_addresses(instance);
|
||||
|
||||
@@ -235,7 +240,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
// Initialize firewall
|
||||
fw_init(&instance->fw);
|
||||
if (fw_load_rules(&instance->fw, &config->global) != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Failed to load firewall rules");
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to load firewall rules"); return -1;
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Firewall initialized: %d rules, bypass_all=%d",
|
||||
instance->fw.count, instance->fw.bypass_all);
|
||||
@@ -331,10 +336,8 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
|
||||
|
||||
// Initialize using common function
|
||||
if (instance_init_common(instance, ua, config) != 0) {
|
||||
// Cleanup on error
|
||||
etcp_padding_stop(&instance->padding);
|
||||
if (instance->config) free_config(instance->config);
|
||||
u_free(instance);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Core creation failed; releasing all initialized resources");
|
||||
instance_destroy(instance, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -372,9 +375,8 @@ struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct
|
||||
|
||||
// Initialize using common function (config ownership transferred to instance)
|
||||
if (instance_init_common(instance, ua, config) != 0) {
|
||||
// Cleanup on error - caller still owns config since we failed
|
||||
etcp_padding_stop(&instance->padding);
|
||||
u_free(instance);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Core creation failed; releasing resources and preserving caller config");
|
||||
instance_destroy(instance, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -396,7 +398,7 @@ struct UTUN_INSTANCE* utun_instance_create_from_str(struct UASYNC* ua, const cha
|
||||
}
|
||||
|
||||
// Destroy instance and cleanup resources
|
||||
void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config) {
|
||||
if (!instance) return;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Starting cleanup for instance %p node=0x%016llx ua=%p",
|
||||
@@ -494,7 +496,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
|
||||
/* Phase K: ETCP connections */
|
||||
{
|
||||
struct ll_entry* entry = instance->connections->head;
|
||||
struct ll_entry* entry = instance->connections ? instance->connections->head : NULL;
|
||||
int cc = 0;
|
||||
while (entry) {
|
||||
struct ll_entry* next = entry->next;
|
||||
@@ -526,8 +528,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
|
||||
/* Phase M: TUN + proxy + routing */
|
||||
if (instance->tun) {
|
||||
if (instance->tun->ifindex && instance->route_subnets)
|
||||
tun_route_del_all(instance->tun->ifindex, instance->tun->ifname, instance->route_subnets);
|
||||
if (instance->tun_routes) tun_route_del_all(instance->tun->ifindex, instance->tun->ifname, &instance->tun_routes);
|
||||
tun_close(instance->tun);
|
||||
instance->tun = NULL;
|
||||
}
|
||||
@@ -558,7 +559,8 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[DESTROY] O done — networks");
|
||||
|
||||
/* Phase P: config + pools */
|
||||
if (instance->config) { free_config(instance->config); instance->config = NULL; }
|
||||
if (instance->config && owns_config) free_config(instance->config);
|
||||
instance->config = NULL;
|
||||
|
||||
// Cleanup packet pool (ensure no leak if stop wasn't called)
|
||||
if (instance->pkt_pool) {
|
||||
@@ -625,6 +627,10 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Instance destroyed completely");
|
||||
}
|
||||
|
||||
void utun_instance_destroy(struct UTUN_INSTANCE* instance) {
|
||||
instance_destroy(instance, 1);
|
||||
}
|
||||
|
||||
// Stop instance
|
||||
void utun_instance_stop(struct UTUN_INSTANCE *instance) {
|
||||
if (!instance) return;
|
||||
@@ -669,7 +675,7 @@ int utun_core_start(struct UTUN_INSTANCE *instance) {
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "init_connections() returned: %d", conn_result);
|
||||
|
||||
if (conn_result < 0) {
|
||||
if (conn_result != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections, error=%d", conn_result);
|
||||
return -1;
|
||||
}
|
||||
@@ -679,16 +685,17 @@ int utun_core_start(struct UTUN_INSTANCE *instance) {
|
||||
// Initialize control server if configured
|
||||
if (instance->config->global.control_sock.ss_family != 0) {
|
||||
instance->control_srv = (struct control_server*)u_calloc(1, sizeof(struct control_server));
|
||||
if (instance->control_srv) {
|
||||
if (control_server_init(instance->control_srv, instance->ua, instance,
|
||||
&instance->config->global.control_sock, 8) != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONTROL, "Failed to initialize control server, continuing without monitoring");
|
||||
u_free(instance->control_srv);
|
||||
instance->control_srv = NULL;
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Control server initialized successfully");
|
||||
}
|
||||
if (!instance->control_srv) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Control server allocation failed"); return -1;
|
||||
}
|
||||
if (control_server_init(instance->control_srv, instance->ua, instance,
|
||||
&instance->config->global.control_sock, 8) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Configured control socket initialization failed");
|
||||
control_server_shutdown(instance->control_srv);
|
||||
u_free(instance->control_srv); instance->control_srv = NULL;
|
||||
return -1;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Control server initialized successfully");
|
||||
}
|
||||
|
||||
// Start the main loop
|
||||
@@ -732,9 +739,8 @@ int utun_service_start(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s", instance->tun->ifname);
|
||||
if (config->route_subnets) {
|
||||
int added = tun_route_add_all(instance->tun->ifindex, instance->tun->ifname, config->route_subnets);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Added %d system routes for TUN interface", added);
|
||||
instance->route_subnets = config->route_subnets;
|
||||
if (tun_route_add_all(instance->tun->ifindex, instance->tun->ifname, config->route_subnets, &instance->tun_routes) < 0)
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization disabled - skipping TUN device setup");
|
||||
@@ -758,11 +764,9 @@ void utun_service_stop(struct UTUN_INSTANCE* instance) {
|
||||
if (instance->nat_tr.initialized) nat_transport_destroy(instance);
|
||||
if (instance->router_bindings.callbacks[ETCP_RT_ID_DATA]) etcp_router_unbind(instance, ETCP_RT_ID_DATA);
|
||||
if (instance->tun) {
|
||||
if (instance->tun->ifindex && instance->route_subnets)
|
||||
tun_route_del_all(instance->tun->ifindex, instance->tun->ifname, instance->route_subnets);
|
||||
if (instance->tun_routes) tun_route_del_all(instance->tun->ifindex, instance->tun->ifname, &instance->tun_routes);
|
||||
tun_close(instance->tun); instance->tun = NULL;
|
||||
}
|
||||
instance->route_subnets = NULL;
|
||||
while (instance->config_conn_handles) {
|
||||
struct CONFIG_CONN_HANDLE* owner = instance->config_conn_handles;
|
||||
instance->config_conn_handles = owner->next;
|
||||
|
||||
Reference in new issue
Block a user