|
|
|
@ -36,32 +36,30 @@ static void tun_read_callback(int fd, void* user_arg) |
|
|
|
} |
|
|
|
} |
|
|
|
if (nread == 0) return; |
|
|
|
if (nread == 0) return; |
|
|
|
|
|
|
|
|
|
|
|
// Allocate packet data
|
|
|
|
// Allocate packet data (+1 for prefix byte)
|
|
|
|
uint8_t* packet_data = u_malloc(nread); |
|
|
|
uint8_t* packet_data = u_malloc(nread + 1); |
|
|
|
if (!packet_data) { |
|
|
|
if (!packet_data) { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate packet data (size=%zd)", nread); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate packet data (size=%zd)", nread + 1); |
|
|
|
tun->read_errors++; |
|
|
|
tun->read_errors++; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
memcpy(packet_data, buffer, nread); |
|
|
|
packet_data[0] = 0; // Prefix byte
|
|
|
|
|
|
|
|
memcpy(packet_data + 1, buffer, nread); |
|
|
|
|
|
|
|
|
|
|
|
// Allocate ETCP_FRAGMENT from pool
|
|
|
|
struct ll_entry* pkt = queue_entry_new_from_pool(tun->pool); |
|
|
|
struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(tun->pool); |
|
|
|
|
|
|
|
if (!pkt) { |
|
|
|
if (!pkt) { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate ETCP_FRAGMENT from pool"); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to allocate struct ll_entry from pool"); |
|
|
|
u_free(packet_data); |
|
|
|
u_free(packet_data); |
|
|
|
tun->read_errors++; |
|
|
|
tun->read_errors++; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Initialize fragment
|
|
|
|
// Initialize entry
|
|
|
|
pkt->seq = 0; |
|
|
|
pkt->dgram = packet_data; |
|
|
|
pkt->timestamp = 0; |
|
|
|
pkt->len = nread + 1; |
|
|
|
pkt->ll.dgram = packet_data; |
|
|
|
|
|
|
|
pkt->ll.len = nread; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add to output queue (TUN → routing)
|
|
|
|
// Add to output queue (TUN → routing)
|
|
|
|
if (queue_data_put(tun->output_queue, (struct ll_entry*)pkt, 0) != 0) { |
|
|
|
if (queue_data_put(tun->output_queue, pkt, 0) != 0) { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to add packet to output queue"); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to add packet to output queue"); |
|
|
|
u_free(packet_data); |
|
|
|
u_free(packet_data); |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
@ -70,10 +68,10 @@ static void tun_read_callback(int fd, void* user_arg) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Update statistics
|
|
|
|
// Update statistics
|
|
|
|
tun->bytes_read += nread; |
|
|
|
tun->bytes_read += nread + 1; |
|
|
|
tun->packets_read++; |
|
|
|
tun->packets_read++; |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Read %zd bytes from TUN %s", nread, tun->ifname); |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Read %zd bytes from TUN %s", nread + 1, tun->ifname); |
|
|
|
dump_ip_packet("TUN->", buffer, nread); |
|
|
|
dump_ip_packet("TUN->", packet_data + 1, nread); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
@ -84,26 +82,27 @@ static void tun_input_queue_callback(struct ll_queue* q, void* arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
(void)q; |
|
|
|
(void)q; |
|
|
|
struct tun_if* tun = (struct tun_if*)arg; |
|
|
|
struct tun_if* tun = (struct tun_if*)arg; |
|
|
|
struct ETCP_FRAGMENT* pkt = queue_data_get(tun->input_queue); |
|
|
|
struct ll_entry* pkt = queue_data_get(tun->input_queue); |
|
|
|
if (!pkt) return; |
|
|
|
if (!pkt) return; |
|
|
|
|
|
|
|
|
|
|
|
if (pkt->ll.dgram && pkt->ll.len > 0) { |
|
|
|
if (pkt->dgram && pkt->len > 1) { |
|
|
|
if (pkt->ll.len > TUN_MAX_PACKET_SIZE) { |
|
|
|
if (pkt->len > TUN_MAX_PACKET_SIZE + 1) { |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Packet too large: %zu bytes", pkt->ll.len); |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Packet too large: %zu bytes", pkt->len); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ssize_t n = tun_platform_write(tun, pkt->ll.dgram, pkt->ll.len); |
|
|
|
// Skip prefix byte, write from second byte
|
|
|
|
|
|
|
|
ssize_t n = tun_platform_write(tun, pkt->dgram + 1, pkt->len - 1); |
|
|
|
if (n < 0) { |
|
|
|
if (n < 0) { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_platform_write failed"); |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "tun_platform_write failed"); |
|
|
|
tun->write_errors++; |
|
|
|
tun->write_errors++; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
tun->bytes_written += n; |
|
|
|
tun->bytes_written += n; |
|
|
|
tun->packets_written++; |
|
|
|
tun->packets_written++; |
|
|
|
dump_ip_packet("->TUN", pkt->ll.dgram, pkt->ll.len); |
|
|
|
dump_ip_packet("->TUN", pkt->dgram + 1, pkt->len - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
u_free(pkt->ll.dgram); |
|
|
|
queue_dgram_free(pkt); |
|
|
|
} |
|
|
|
} |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
queue_entry_free(pkt); |
|
|
|
|
|
|
|
|
|
|
|
queue_resume_callback(tun->input_queue); |
|
|
|
queue_resume_callback(tun->input_queue); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -146,7 +145,7 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config) |
|
|
|
strncpy(tun->ifname, "tun_test", sizeof(tun->ifname)-1); |
|
|
|
strncpy(tun->ifname, "tun_test", sizeof(tun->ifname)-1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tun->pool = memory_pool_init(sizeof(struct ETCP_FRAGMENT)); |
|
|
|
tun->pool = memory_pool_init(sizeof(struct ll_entry)); |
|
|
|
if (!tun->pool) goto fail; |
|
|
|
if (!tun->pool) goto fail; |
|
|
|
|
|
|
|
|
|
|
|
tun->output_queue = queue_new(ua, 0); |
|
|
|
tun->output_queue = queue_new(ua, 0); |
|
|
|
@ -222,16 +221,16 @@ void tun_close(struct tun_if* tun) |
|
|
|
uasync_remove_socket(tun->ua, tun->socket_id); |
|
|
|
uasync_remove_socket(tun->ua, tun->socket_id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct ETCP_FRAGMENT* pkt; |
|
|
|
struct ll_entry* pkt; |
|
|
|
while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue)) != NULL) { |
|
|
|
while ((pkt = queue_data_get(tun->input_queue)) != NULL) { |
|
|
|
if (pkt->ll.dgram) u_free(pkt->ll.dgram); |
|
|
|
queue_dgram_free(pkt); |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
queue_entry_free(pkt); |
|
|
|
} |
|
|
|
} |
|
|
|
queue_free(tun->input_queue); |
|
|
|
queue_free(tun->input_queue); |
|
|
|
|
|
|
|
|
|
|
|
while ((pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->output_queue)) != NULL) { |
|
|
|
while ((pkt = queue_data_get(tun->output_queue)) != NULL) { |
|
|
|
if (pkt->ll.dgram) u_free(pkt->ll.dgram); |
|
|
|
queue_dgram_free(pkt); |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
queue_entry_free(pkt); |
|
|
|
} |
|
|
|
} |
|
|
|
queue_free(tun->output_queue); |
|
|
|
queue_free(tun->output_queue); |
|
|
|
|
|
|
|
|
|
|
|
@ -242,17 +241,19 @@ void tun_close(struct tun_if* tun) |
|
|
|
|
|
|
|
|
|
|
|
ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len) |
|
|
|
ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!tun || !buf || len == 0) return -1; |
|
|
|
if (!tun || !buf || len <= 1) return -1; |
|
|
|
|
|
|
|
|
|
|
|
if (tun->test_mode) { |
|
|
|
if (tun->test_mode) { |
|
|
|
return tun_inject_packet(tun, buf, len) == 0 ? (ssize_t)len : -1; |
|
|
|
// Skip prefix byte for test mode injection
|
|
|
|
|
|
|
|
return tun_inject_packet(tun, buf + 1, len - 1) == 0 ? (ssize_t)(len - 1) : -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ssize_t n = tun_platform_write(tun, buf, len); |
|
|
|
// Skip prefix byte, write from second byte
|
|
|
|
|
|
|
|
ssize_t n = tun_platform_write(tun, buf + 1, len - 1); |
|
|
|
if (n > 0) { |
|
|
|
if (n > 0) { |
|
|
|
tun->bytes_written += n; |
|
|
|
tun->bytes_written += n; |
|
|
|
tun->packets_written++; |
|
|
|
tun->packets_written++; |
|
|
|
dump_ip_packet("->TUN", buf, len); |
|
|
|
dump_ip_packet("->TUN", buf + 1, len - 1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
tun->write_errors++; |
|
|
|
tun->write_errors++; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -297,19 +298,19 @@ int tun_inject_packet(struct tun_if* tun, const uint8_t* buf, size_t len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!tun || !buf || len == 0 || len > TUN_MAX_PACKET_SIZE) return -1; |
|
|
|
if (!tun || !buf || len == 0 || len > TUN_MAX_PACKET_SIZE) return -1; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t* data = u_malloc(len); |
|
|
|
// Allocate with +1 for prefix byte
|
|
|
|
|
|
|
|
uint8_t* data = u_malloc(len + 1); |
|
|
|
if (!data) { tun->read_errors++; return -1; } |
|
|
|
if (!data) { tun->read_errors++; return -1; } |
|
|
|
memcpy(data, buf, len); |
|
|
|
data[0] = 0; // Prefix byte
|
|
|
|
|
|
|
|
memcpy(data + 1, buf, len); |
|
|
|
|
|
|
|
|
|
|
|
struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(tun->pool); |
|
|
|
struct ll_entry* pkt = queue_entry_new_from_pool(tun->pool); |
|
|
|
if (!pkt) { u_free(data); tun->read_errors++; return -1; } |
|
|
|
if (!pkt) { u_free(data); tun->read_errors++; return -1; } |
|
|
|
|
|
|
|
|
|
|
|
pkt->seq = 0; |
|
|
|
pkt->dgram = data; |
|
|
|
pkt->timestamp = 0; |
|
|
|
pkt->len = len + 1; |
|
|
|
pkt->ll.dgram = data; |
|
|
|
|
|
|
|
pkt->ll.len = len; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ret = queue_data_put(tun->output_queue, (struct ll_entry*)pkt, 0); |
|
|
|
int ret = queue_data_put(tun->output_queue, pkt, 0); |
|
|
|
|
|
|
|
|
|
|
|
if (ret != 0) { |
|
|
|
if (ret != 0) { |
|
|
|
u_free(data); |
|
|
|
u_free(data); |
|
|
|
@ -318,7 +319,7 @@ int tun_inject_packet(struct tun_if* tun, const uint8_t* buf, size_t len) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tun->bytes_read += len; |
|
|
|
tun->bytes_read += len + 1; |
|
|
|
tun->packets_read++; |
|
|
|
tun->packets_read++; |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -327,22 +328,24 @@ ssize_t tun_read_packet(struct tun_if* tun, uint8_t* buf, size_t len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!tun || !buf || len == 0) return -1; |
|
|
|
if (!tun || !buf || len == 0) return -1; |
|
|
|
|
|
|
|
|
|
|
|
struct ETCP_FRAGMENT* pkt = (struct ETCP_FRAGMENT*)queue_data_get(tun->input_queue); |
|
|
|
struct ll_entry* pkt = queue_data_get(tun->input_queue); |
|
|
|
if (!pkt) return 0; |
|
|
|
if (!pkt) return 0; |
|
|
|
|
|
|
|
|
|
|
|
if (pkt->ll.len > len) { |
|
|
|
if (pkt->len > len) { |
|
|
|
queue_data_put(tun->input_queue, (struct ll_entry*)pkt, 0); |
|
|
|
queue_data_put(tun->input_queue, pkt, 0); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
memcpy(buf, pkt->ll.dgram, pkt->ll.len); |
|
|
|
// Add prefix byte at start
|
|
|
|
ssize_t ret = pkt->ll.len; |
|
|
|
buf[0] = 0; |
|
|
|
|
|
|
|
memcpy(buf + 1, pkt->dgram, pkt->len); |
|
|
|
|
|
|
|
ssize_t ret = pkt->len + 1; |
|
|
|
|
|
|
|
|
|
|
|
u_free(pkt->ll.dgram); |
|
|
|
queue_dgram_free(pkt); |
|
|
|
memory_pool_free(tun->pool, pkt); |
|
|
|
queue_entry_free(pkt); |
|
|
|
|
|
|
|
|
|
|
|
tun->bytes_written += ret; |
|
|
|
tun->bytes_written += ret; |
|
|
|
tun->packets_written++; |
|
|
|
tun->packets_written++; |
|
|
|
dump_ip_packet("TUN->", buf, ret); |
|
|
|
dump_ip_packet("TUN->", buf + 1, pkt->len); |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|