You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
491 lines
18 KiB
491 lines
18 KiB
// test_etcp_simple_traffic.c - Simplified ETCP traffic flow debugging without sockets |
|
// This test focuses purely on ETCP protocol traffic analysis using direct packet injection |
|
|
|
#include "../src/etcp.h" |
|
#include "../src/etcp_connections.h" |
|
#include "../src/etcp_loadbalancer.h" |
|
#include "../lib/u_async.h" |
|
#include "../lib/debug_config.h" |
|
#include "../lib/memory_pool.h" |
|
#include "../lib/ll_queue.h" |
|
#include "../src/secure_channel.h" |
|
#include "../src/crc32.h" |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
#include <pthread.h> |
|
#include <time.h> |
|
#include <errno.h> |
|
|
|
// Simplified traffic analysis - focus on ETCP protocol packets only |
|
typedef struct { |
|
uint64_t timestamp; |
|
uint16_t packet_id; |
|
uint8_t packet_type; |
|
uint16_t data_len; |
|
uint8_t data[1500]; // Copy of packet data for analysis |
|
} packet_capture_t; |
|
|
|
typedef struct { |
|
packet_capture_t captures[1000]; |
|
size_t capture_count; |
|
pthread_mutex_t lock; |
|
} traffic_analyzer_t; |
|
|
|
// Test instance - simplified version without actual sockets |
|
typedef struct { |
|
struct UTUN_INSTANCE* instance; |
|
struct ETCP_CONN* etcp_conn; |
|
traffic_analyzer_t* analyzer; |
|
uint64_t node_id; |
|
int is_server; |
|
int running; |
|
} test_instance_t; |
|
|
|
// Global test state |
|
static test_instance_t* server_instance = NULL; |
|
static test_instance_t* client_instance = NULL; |
|
|
|
// Enhanced packet analysis function |
|
static void analyze_etcp_packet(struct ETCP_CONN* etcp, uint8_t* data, uint16_t len, const char* direction) { |
|
if (!etcp || !data || len == 0) { |
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "analyze_etcp_packet: invalid parameters (etcp=%p, data=%p, len=%u)", |
|
etcp, data, len); |
|
return; |
|
} |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "PACKET %s: etcp=%p, len=%u, first_byte=0x%02x", |
|
direction, etcp, len, data[0]); |
|
|
|
// Parse ETCP sections |
|
uint16_t pos = 0; |
|
int section_count = 0; |
|
|
|
while (pos < len) { |
|
if (pos + 3 > len) { |
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Invalid section header at pos %u (need 3 bytes, have %u)", |
|
pos, len - pos); |
|
break; |
|
} |
|
|
|
uint8_t section_type = data[pos]; |
|
uint16_t section_len = (data[pos+1] << 8) | data[pos+2]; |
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Section %d: type=0x%02x, len=%u at pos=%u", |
|
section_count, section_type, section_len, pos); |
|
|
|
if (pos + 3 + section_len > len || section_len > 1500) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Section length %u exceeds packet boundary (pos=%u, total=%u) or max size", |
|
section_len, pos, len); |
|
break; |
|
} |
|
|
|
// Analyze specific section types |
|
uint8_t* section_data = data + pos + 3; |
|
|
|
switch (section_type) { |
|
case ETCP_SECTION_PAYLOAD: { |
|
if (section_len >= 2) { |
|
uint16_t packet_id = (section_data[0] << 8) | section_data[1]; |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " PAYLOAD: packet_id=%u, payload_len=%u", |
|
packet_id, section_len - 2); |
|
} |
|
break; |
|
} |
|
case ETCP_SECTION_ACK: { |
|
if (section_len >= 1) { |
|
uint8_t ack_count = section_data[0]; |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " ACK: count=%u", ack_count); |
|
for (int i = 0; i < ack_count && i*4+5 <= section_len; i++) { |
|
uint16_t ack_id = (section_data[1+i*4] << 8) | section_data[2+i*4]; |
|
uint16_t ack_ts = (section_data[3+i*4] << 8) | section_data[4+i*4]; |
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, " ACK[%d]: id=%u, ts=%u", i, ack_id, ack_ts); |
|
} |
|
} |
|
break; |
|
} |
|
case ETCP_SECTION_TIMESTAMP: { |
|
if (section_len == 2) { |
|
uint16_t ts = (section_data[0] << 8) | section_data[1]; |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " TIMESTAMP: ts=%u", ts); |
|
} |
|
break; |
|
} |
|
case ETCP_INIT_REQUEST: { |
|
if (section_len >= 76) { // node_id(8) + mtu(2) + keepalive(2) + pubkey(64) |
|
uint64_t node_id = 0; |
|
for (int i = 0; i < 8; i++) { |
|
node_id = (node_id << 8) | section_data[i]; |
|
} |
|
uint16_t mtu = (section_data[8] << 8) | section_data[9]; |
|
uint16_t keepalive = (section_data[10] << 8) | section_data[11]; |
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, " INIT_REQUEST: node_id=%llu, mtu=%u, keepalive=%u", |
|
(unsigned long long)node_id, mtu, keepalive); |
|
} |
|
break; |
|
} |
|
case ETCP_INIT_RESPONSE: { |
|
if (section_len >= 10) { // node_id(8) + mtu(2) |
|
uint64_t node_id = 0; |
|
for (int i = 0; i < 8; i++) { |
|
node_id = (node_id << 8) | section_data[i]; |
|
} |
|
uint16_t mtu = (section_data[8] << 8) | section_data[9]; |
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, " INIT_RESPONSE: node_id=%llu, mtu=%u", |
|
(unsigned long long)node_id, mtu); |
|
} |
|
break; |
|
} |
|
default: { |
|
if (section_type >= ETCP_SECTION_RETRANS && section_type <= ETCP_SECTION_RETRANS + 0x1F) { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " RETRANS: base_id=%u", section_type - ETCP_SECTION_RETRANS); |
|
// Parse retransmission requests |
|
for (int i = 0; i < section_len; i += 2) { |
|
if (i+1 < section_len) { |
|
uint16_t req_id = (section_data[i] << 8) | section_data[i+1]; |
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, " RETRANS_REQ: id=%u", req_id); |
|
} |
|
} |
|
} else { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, " UNKNOWN: type=0x%02x, len=%u", section_type, section_len); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
pos += 3 + section_len; |
|
section_count++; |
|
} |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Packet analysis complete: %d sections processed", section_count); |
|
} |
|
|
|
// Simulate packet reception for analysis |
|
static void simulate_packet_rx(test_instance_t* inst, uint8_t* data, uint16_t len) { |
|
if (!inst || !inst->etcp_conn || !data) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "SIMULATE RX: inst=%s, len=%u", |
|
inst->is_server ? "server" : "client", len); |
|
|
|
// Analyze the packet first |
|
analyze_etcp_packet(inst->etcp_conn, data, len, "SIM_RX"); |
|
|
|
// Create a mock ETCP_DGRAM for processing |
|
struct ETCP_DGRAM mock_dgram; |
|
memset(&mock_dgram, 0, sizeof(mock_dgram)); |
|
mock_dgram.link = NULL; // Will be set by connection processing |
|
mock_dgram.data_len = len > 1500 ? 1500 : len; |
|
mock_dgram.timestamp = get_current_timestamp(); |
|
if (mock_dgram.data_len > 0) { |
|
memcpy(mock_dgram.data, data, mock_dgram.data_len); |
|
} |
|
|
|
// Process through ETCP input |
|
etcp_conn_input(&mock_dgram); |
|
} |
|
|
|
// Simulate packet transmission for analysis |
|
static void simulate_packet_tx(test_instance_t* inst) { |
|
if (!inst || !inst->etcp_conn) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "SIMULATE TX: inst=%s", |
|
inst->is_server ? "server" : "client"); |
|
|
|
struct ETCP_DGRAM* dgram = etcp_request_pkt(inst->etcp_conn); |
|
if (dgram) { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Generated packet: len=%u", dgram->data_len); |
|
analyze_etcp_packet(inst->etcp_conn, dgram->data, dgram->data_len, "SIM_TX"); |
|
|
|
// In a real scenario, this would be sent over the network |
|
// For now, we just analyze it and free it |
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Would send %u bytes to peer", dgram->data_len); |
|
} else { |
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "No packets available to send"); |
|
} |
|
} |
|
|
|
// Create simplified test instance |
|
static test_instance_t* create_simple_instance(uint64_t node_id, int is_server) { |
|
test_instance_t* inst = calloc(1, sizeof(test_instance_t)); |
|
if (!inst) return NULL; |
|
|
|
inst->node_id = node_id; |
|
inst->is_server = is_server; |
|
inst->running = 1; |
|
|
|
// Create traffic analyzer |
|
inst->analyzer = calloc(1, sizeof(traffic_analyzer_t)); |
|
if (inst->analyzer) { |
|
pthread_mutex_init(&inst->analyzer->lock, NULL); |
|
} |
|
|
|
// Create UTUN instance directly without TUN device |
|
inst->instance = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
if (!inst->instance) { |
|
free(inst->analyzer); |
|
free(inst); |
|
return NULL; |
|
} |
|
|
|
// Initialize the instance manually |
|
inst->instance->node_id = node_id; |
|
inst->instance->running = 1; |
|
inst->instance->log_fp = stderr; |
|
|
|
// Initialize crypto keys (hardcoded for test) |
|
const char* priv_key_hex = "67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb"; |
|
const char* pub_key_hex = "1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9"; |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Parsing crypto keys: priv_len=%zu, pub_len=%zu", |
|
strlen(priv_key_hex), strlen(pub_key_hex)); |
|
|
|
// Parse keys |
|
for (int i = 0; i < 32; i++) { |
|
if (sscanf(&priv_key_hex[i*2], "%2hhx", &inst->instance->my_keys.private_key[i]) != 1) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to parse private key byte %d", i); |
|
} |
|
} |
|
for (int i = 0; i < 64; i++) { |
|
if (sscanf(&pub_key_hex[i*2], "%2hhx", &inst->instance->my_keys.public_key[i]) != 1) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to parse public key byte %d", i); |
|
} |
|
} |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Keys parsed successfully"); |
|
|
|
// Create uasync context |
|
inst->instance->ua = uasync_create(); |
|
if (!inst->instance->ua) { |
|
free(inst->instance); |
|
free(inst->analyzer); |
|
free(inst); |
|
return NULL; |
|
} |
|
uasync_init_instance(inst->instance->ua); |
|
|
|
// Create packet pool |
|
inst->instance->pkt_pool = memory_pool_init(1600); // 1600 byte packets |
|
if (!inst->instance->pkt_pool) { |
|
uasync_destroy(inst->instance->ua); |
|
free(inst->instance); |
|
free(inst->analyzer); |
|
free(inst); |
|
return NULL; |
|
} |
|
|
|
// Create ETCP connection |
|
inst->etcp_conn = etcp_connection_create(inst->instance); |
|
if (!inst->etcp_conn) { |
|
memory_pool_destroy(inst->instance->pkt_pool); |
|
uasync_destroy(inst->instance->ua); |
|
free(inst->instance); |
|
free(inst->analyzer); |
|
free(inst); |
|
return NULL; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Created %s instance (node_id=%llu)", |
|
is_server ? "server" : "client", (unsigned long long)node_id); |
|
|
|
return inst; |
|
} |
|
|
|
// Cleanup simplified test instance |
|
static void destroy_simple_instance(test_instance_t* inst) { |
|
if (!inst) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Destroying %s instance", inst->is_server ? "server" : "client"); |
|
|
|
if (inst->etcp_conn) { |
|
etcp_connection_close(inst->etcp_conn); |
|
} |
|
|
|
if (inst->instance) { |
|
if (inst->instance->pkt_pool) { |
|
memory_pool_destroy(inst->instance->pkt_pool); |
|
} |
|
if (inst->instance->ua) { |
|
uasync_destroy(inst->instance->ua); |
|
} |
|
free(inst->instance); |
|
} |
|
|
|
if (inst->analyzer) { |
|
pthread_mutex_destroy(&inst->analyzer->lock); |
|
free(inst->analyzer); |
|
} |
|
|
|
free(inst); |
|
} |
|
|
|
// Generate test packets manually |
|
static void generate_test_packets(test_instance_t* inst, int count) { |
|
if (!inst || !inst->etcp_conn) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Generating %d test packets for %s instance", |
|
count, inst->is_server ? "server" : "client"); |
|
|
|
for (int i = 0; i < count; i++) { |
|
struct ll_entry* entry = queue_entry_new(100); // 100 byte packets |
|
if (entry) { |
|
// Fill with test data |
|
uint8_t* data = (uint8_t*)ll_entry_data(entry); |
|
for (int j = 0; j < 100; j++) { |
|
data[j] = (uint8_t)((i+1) * 10 + j); // Pattern data |
|
} |
|
queue_entry_put(inst->etcp_conn->input_queue, entry); |
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "Queued test packet %d for %s", |
|
i+1, inst->is_server ? "server" : "client"); |
|
} |
|
} |
|
} |
|
|
|
// Main test function |
|
int main(int argc, char* argv[]) { |
|
printf("=== ETCP Traffic Flow Debugging Test (Simplified) ===\n"); |
|
|
|
// Initialize debug system |
|
debug_config_init(); |
|
debug_set_level(DEBUG_LEVEL_DEBUG); |
|
debug_enable_category(DEBUG_CATEGORY_ETCP); |
|
debug_enable_timestamp(1); |
|
debug_enable_function_name(1); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Starting simplified ETCP traffic flow debugging test"); |
|
|
|
// Create server instance |
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating server instance..."); |
|
server_instance = create_simple_instance(0x1111111111111111ULL, 1); |
|
if (!server_instance) { |
|
fprintf(stderr, "Failed to create server instance\n"); |
|
return 1; |
|
} |
|
|
|
// Create client instance |
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Creating client instance..."); |
|
client_instance = create_simple_instance(0x2222222222222222ULL, 0); |
|
if (!client_instance) { |
|
fprintf(stderr, "Failed to create client instance\n"); |
|
destroy_simple_instance(server_instance); |
|
return 1; |
|
} |
|
|
|
// Phase 1: Test basic packet generation and analysis |
|
printf("\n=== Phase 1: Basic Packet Generation ===\n"); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Generating test packets..."); |
|
generate_test_packets(server_instance, 5); |
|
generate_test_packets(client_instance, 5); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating packet transmission..."); |
|
|
|
// Let server generate some packets |
|
for (int i = 0; i < 3; i++) { |
|
simulate_packet_tx(server_instance); |
|
usleep(10000); // 1ms delay |
|
} |
|
|
|
// Let client generate some packets |
|
for (int i = 0; i < 3; i++) { |
|
simulate_packet_tx(client_instance); |
|
usleep(10000); // 1ms delay |
|
} |
|
|
|
// Phase 2: Test connection establishment simulation |
|
printf("\n=== Phase 2: Connection Establishment Simulation ===\n"); |
|
|
|
// Simulate INIT_REQUEST from client - smaller version for testing |
|
uint8_t init_request[] = { |
|
ETCP_INIT_REQUEST, // Section type |
|
0x00, 0x14, // Section length (20 bytes) - smaller for test |
|
// Node ID (8 bytes) |
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, |
|
// MTU (2 bytes) |
|
0x05, 0xDC, // 1500 |
|
// Keepalive (2 bytes) |
|
0x00, 0x64, // 100 |
|
// Fake public key (8 bytes) - just for testing |
|
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22 |
|
}; |
|
// Total: 3 + 20 = 23 bytes |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating INIT_REQUEST from client..."); |
|
simulate_packet_rx(server_instance, init_request, sizeof(init_request)); |
|
|
|
// Simulate INIT_RESPONSE from server |
|
uint8_t init_response[] = { |
|
ETCP_INIT_RESPONSE, // Section type |
|
0x00, 0x0A, // Section length (10 bytes) |
|
// Node ID (8 bytes) |
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, |
|
// MTU (2 bytes) |
|
0x05, 0xDC // 1500 |
|
}; |
|
// Total: 3 + 10 = 13 bytes |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating INIT_RESPONSE from server..."); |
|
simulate_packet_rx(client_instance, init_response, sizeof(init_response)); |
|
|
|
// Phase 3: Test mixed traffic with ACKs and timestamps |
|
printf("\n=== Phase 3: Mixed Traffic Simulation ===\n"); |
|
|
|
// Generate more traffic |
|
generate_test_packets(server_instance, 3); |
|
generate_test_packets(client_instance, 3); |
|
|
|
// Simulate some packets with multiple sections |
|
uint8_t complex_packet[] = { |
|
// TIMESTAMP section: 3 bytes header + 2 bytes data = 5 bytes |
|
ETCP_SECTION_TIMESTAMP, 0x00, 0x02, 0x12, 0x34, |
|
// ACK section with 2 ACKs: 3 bytes header + 1 byte count + 2*4 bytes = 12 bytes total |
|
ETCP_SECTION_ACK, 0x00, 0x09, 0x02, 0x00, 0x01, 0x12, 0x34, 0x00, 0x02, 0x12, 0x35, |
|
// PAYLOAD section: 3 bytes header + 2 bytes ID + 5 bytes data = 10 bytes total |
|
ETCP_SECTION_PAYLOAD, 0x00, 0x08, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F // "Hello" |
|
}; |
|
// Total: 5 + 12 + 10 = 27 bytes |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating complex packet with multiple sections..."); |
|
simulate_packet_rx(server_instance, complex_packet, sizeof(complex_packet)); |
|
|
|
// Phase 4: Test retransmission requests |
|
printf("\n=== Phase 4: Retransmission Testing ===\n"); |
|
|
|
uint8_t retrans_request[] = { |
|
ETCP_SECTION_RETRANS + 0x02, // RETRANS section with base ID 2 |
|
0x00, 0x04, // Section length (4 bytes) |
|
0x00, 0x03, // Request retransmission of packet ID 3 |
|
0x00, 0x04 // Request retransmission of packet ID 4 |
|
}; |
|
// Total: 3 + 4 = 7 bytes |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Simulating retransmission request..."); |
|
simulate_packet_rx(client_instance, retrans_request, sizeof(retrans_request)); |
|
|
|
// Final packet generation |
|
printf("\n=== Final Phase: Additional Traffic ===\n"); |
|
|
|
// Generate final packets |
|
for (int i = 0; i < 5; i++) { |
|
simulate_packet_tx(server_instance); |
|
simulate_packet_tx(client_instance); |
|
usleep(5000); // 0.5ms delay |
|
} |
|
|
|
// Print summary |
|
printf("\n=== Traffic Analysis Summary ===\n"); |
|
printf("Server instance: processed packets with detailed section analysis\n"); |
|
printf("Client instance: processed packets with detailed section analysis\n"); |
|
printf("Connection establishment: INIT handshake simulated\n"); |
|
printf("Mixed traffic: ACK, TIMESTAMP, PAYLOAD sections processed\n"); |
|
printf("Retransmission: RETRANS requests processed\n"); |
|
|
|
// Cleanup |
|
destroy_simple_instance(server_instance); |
|
destroy_simple_instance(client_instance); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Test completed"); |
|
printf("\n=== Test completed successfully ===\n"); |
|
|
|
return 0; |
|
} |