diff --git a/src/routing.c b/src/routing.c index a3fdfa6b..eceac2be 100644 --- a/src/routing.c +++ b/src/routing.c @@ -3,6 +3,7 @@ #include "route_lib.h" #include "tun_if.h" #include "etcp.h" +#include "etcp_api.h" #include "pkt_normalizer.h" #include "utun_instance.h" #include "../lib/ll_queue.h" @@ -17,6 +18,9 @@ #define IP_HDR_DST_ADDR_OFFSET 16 #define IP_HDR_MIN_SIZE 20 +// ETCP packet ID for routing data +#define ETCP_ID_DATA 0x00 + // Extract destination IP from IPv4 packet // Returns 0 if not IPv4 or packet too small static uint32_t extract_dst_ip(uint8_t* data, size_t len) { @@ -45,78 +49,100 @@ static uint32_t extract_dst_ip(uint8_t* data, size_t len) { return dst_ip; // Keep in network byte order } -// Callback for packets from ETCP normalizer output queue -static void routing_pkt_from_etcp_cb(struct ll_queue* q, void* arg) { - struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; - if (!etcp || !etcp->instance) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: invalid etcp or instance"); +// Callback for packets from ETCP (via etcp_bind id=0) +// Format: +static void routing_pkt_from_etcp_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { + if (!conn || !entry) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: invalid arguments"); + if (entry) { + queue_entry_free(entry); + queue_dgram_free(entry); + } + return; + } + + struct UTUN_INSTANCE* instance = conn->instance; + if (!instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: connection has no instance"); + queue_entry_free(entry); + queue_dgram_free(entry); return; } - struct UTUN_INSTANCE* instance = etcp->instance; if (!instance->tun) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: no TUN interface"); + queue_entry_free(entry); + queue_dgram_free(entry); return; } - struct ll_entry* entry = queue_data_get(q); - while (entry) { - if (entry->dgram && entry->len > 0) { - // Check MTU - if (entry->len > TUN_MAX_PACKET_SIZE) { - DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Packet too large: %zu bytes (max %d)", - entry->len, TUN_MAX_PACKET_SIZE); - } else { - // Extract destination IP for future routing (currently ignored) - uint32_t dst_ip = extract_dst_ip(entry->dgram, entry->len); - if (dst_ip != 0) { - char ip_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); - DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Packet from ETCP to %s", ip_str); - } - - // Allocate ETCP_FRAGMENT for TUN input_queue - struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(instance->tun->pool); - if (!pkt) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate ETCP_FRAGMENT for TUN"); - } else { - // Allocate packet data (TUN will free it) - uint8_t* packet_data = malloc(entry->len); - if (!packet_data) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate packet data"); - memory_pool_free(instance->tun->pool, pkt); - } else { - memcpy(packet_data, entry->dgram, entry->len); - - pkt->seq = 0; - pkt->timestamp = 0; - pkt->ll.dgram = packet_data; - pkt->ll.len = entry->len; - - // Put to TUN input_queue - if (queue_data_put(instance->tun->input_queue, (struct ll_entry*)pkt, 0) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to put packet to TUN input_queue"); - free(packet_data); - memory_pool_free(instance->tun->pool, pkt); - } else { - DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Forwarded %zu bytes from ETCP to TUN", entry->len); - } - } - } - } - - // Free original entry data - free(entry->dgram); - } - - // Free entry structure + // Check packet data + if (!entry->dgram || entry->len < 2) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_etcp_cb: packet too small or no data"); queue_entry_free(entry); - - // Get next packet - entry = queue_data_get(q); + queue_dgram_free(entry); + return; + } + + // Skip ID byte, extract IP packet (offset 1) + uint8_t* ip_data = entry->dgram + 1; + size_t ip_len = entry->len - 1; + + // Check MTU + if (ip_len > TUN_MAX_PACKET_SIZE) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Packet too large: %zu bytes (max %d)", + ip_len, TUN_MAX_PACKET_SIZE); + queue_entry_free(entry); + queue_dgram_free(entry); + return; + } + + // Log destination IP + uint32_t dst_ip = extract_dst_ip(ip_data, ip_len); + if (dst_ip != 0) { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Packet from ETCP to %s", ip_str); + } + + // Allocate ETCP_FRAGMENT for TUN input_queue + struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(instance->tun->pool); + if (!pkt) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate ETCP_FRAGMENT for TUN"); + queue_entry_free(entry); + queue_dgram_free(entry); + return; + } + + // Allocate packet data (TUN will free it) + uint8_t* packet_data = malloc(ip_len); + if (!packet_data) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate packet data"); + memory_pool_free(instance->tun->pool, pkt); + queue_entry_free(entry); + queue_dgram_free(entry); + return; + } + + memcpy(packet_data, ip_data, ip_len); + + pkt->seq = 0; + pkt->timestamp = 0; + pkt->ll.dgram = packet_data; + pkt->ll.len = ip_len; + + // Put to TUN input_queue + if (queue_data_put(instance->tun->input_queue, (struct ll_entry*)pkt, 0) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to put packet to TUN input_queue"); + free(packet_data); + memory_pool_free(instance->tun->pool, pkt); + } else { + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Forwarded %zu bytes from ETCP to TUN", ip_len); } - queue_resume_callback(q); + // Free original entry from ETCP + queue_entry_free(entry); + queue_dgram_free(entry); } // Callback for packets from TUN output queue @@ -128,25 +154,94 @@ static void routing_pkt_from_tun_cb(struct ll_queue* q, void* arg) { return; } - // For now, just drain the queue (routing to ETCP will be implemented later) + if (!instance->rt) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_pkt_from_tun_cb: no route table"); + return; + } + struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); while (pkt) { if (pkt->ll.dgram && pkt->ll.len > 0) { - // Extract destination IP for future routing + // Extract destination IP for routing uint32_t dst_ip = extract_dst_ip(pkt->ll.dgram, pkt->ll.len); - if (dst_ip != 0) { - char ip_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); - DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Packet from TUN to %s (dropped, routing not implemented yet)", ip_str); + if (dst_ip == 0) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Failed to extract destination IP, dropping packet"); + free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + continue; + } + + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &dst_ip, ip_str, sizeof(ip_str)); + + // Lookup route in routing table + struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip); + if (!routes || routes->routes == 0) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "No route to %s, dropping packet", ip_str); + free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + continue; + } + + // Use first (best) route + struct ETCP_CONN* conn = routes->entries[0]->next_hop; + if (!conn) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Route to %s has no next_hop, dropping packet", ip_str); + free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + continue; + } + + // Check connection has normalizer + if (!conn->normalizer) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Connection for %s has no normalizer, dropping packet", ip_str); + free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + continue; + } + + // Create ll_entry with ID prefix for ETCP + // Format: + size_t etcp_data_len = 1 + pkt->ll.len; + struct ll_entry* entry = ll_alloc_lldgram(etcp_data_len); + if (!entry) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to allocate entry for ETCP send"); + free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); + continue; } - // Free packet data + // Set ID byte and copy IP packet + entry->dgram[0] = ETCP_ID_DATA; + memcpy(entry->dgram + 1, pkt->ll.dgram, pkt->ll.len); + entry->len = etcp_data_len; + + // Send via etcp_send + if (etcp_send(conn, entry) != 0) { + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "etcp_send failed for %s", ip_str); + queue_entry_free(entry); + queue_dgram_free(entry); + } else { + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Forwarded packet to %s via ETCP conn [%s]", + ip_str, conn->log_name); + } + + // Free original TUN packet free(pkt->ll.dgram); + memory_pool_free(instance->tun->pool, pkt); + } else { + // Empty packet - just free structure + if (pkt->ll.dgram) { + free(pkt->ll.dgram); + } + memory_pool_free(instance->tun->pool, pkt); } - // Free fragment structure - memory_pool_free(instance->tun->pool, pkt); - // Get next packet pkt = (struct ETCP_FRAGMENT*)queue_data_get(instance->tun->output_queue); } @@ -166,6 +261,14 @@ int routing_create(struct UTUN_INSTANCE* instance) { return -1; } + // Bind ID=0 for receiving data packets from ETCP + if (etcp_bind(instance, ETCP_ID_DATA, routing_pkt_from_etcp_cb) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to bind ETCP ID=0"); + route_table_destroy(instance->rt); + instance->rt = NULL; + return -1; + } + DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing module initialized for instance"); return 0; @@ -177,6 +280,9 @@ void routing_destroy(struct UTUN_INSTANCE* instance) { DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Destroying routing module"); + // Unbind ETCP ID=0 + etcp_unbind(instance, ETCP_ID_DATA); + // Clean up route table if exists if (instance->rt) { route_table_destroy(instance->rt); @@ -184,46 +290,18 @@ void routing_destroy(struct UTUN_INSTANCE* instance) { } } -// Register ETCP connection with routing +// Register ETCP connection with routing (deprecated, kept for compatibility) void routing_add_conn(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: etcp is NULL"); - return; - } - - if (!etcp->instance) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: etcp has no instance"); - return; - } - - if (!etcp->normalizer) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_add_conn: ETCP has no normalizer"); - return; - } - - struct PKTNORM* pn = (struct PKTNORM*)etcp->normalizer; - - // Set callback on normalizer output queue - pass etcp as arg -// queue_set_callback(pn->output, routing_pkt_from_etcp_cb, etcp); - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added ETCP connection to routing"); + (void)etcp; + // No-op: connections are now handled via routing table entries + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "routing_add_conn: deprecated, no action taken"); } -// Unregister ETCP connection from routing +// Unregister ETCP connection from routing (deprecated, kept for compatibility) void routing_del_conn(struct ETCP_CONN* etcp) { - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "routing_del_conn: etcp is NULL"); - return; - } - - if (!etcp->normalizer) { - return; // Nothing to do - } - - // Note: ll_queue doesn't have a direct way to clear callback - // The callback will be ignored when etcp is freed - - DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Removed ETCP connection from routing"); + (void)etcp; + // No-op: connections are now handled via routing table entries + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "routing_del_conn: deprecated, no action taken"); } // Set TUN interface for routing