Browse Source

Fix UDP and ICMP packet construction at the TUN boundary

proxy
evgeny 3 days ago
parent
commit
518df33b0e
  1. 20
      src/proxy/icmp_proxy.c
  2. 5
      src/proxy/udp_proxy.c
  3. 4
      tests/Makefile.am
  4. 58
      tests/test_proxy_packets.c

20
src/proxy/icmp_proxy.c

@ -53,6 +53,14 @@ struct icmp_proxy_ctx* g_icmp_ctx = NULL;
static void req_expire_timer_cb(void* arg);
static void req_expire(struct icmp_proxy_ctx* ctx);
static uint16_t icmp_checksum(const uint8_t* data, size_t len) {
uint32_t sum = 0;
while (len >= 2) { sum += ((uint16_t)data[0] << 8) | data[1]; data += 2; len -= 2; }
if (len) sum += (uint16_t)data[0] << 8;
while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
return htons((uint16_t)~sum);
}
static struct icmp_request* req_find_by_id(struct icmp_request* head, uint16_t echo_id, uint16_t echo_seq) {
struct icmp_request* r;
for (r = head; r; r = r->next) if (r->echo_id == echo_id && r->echo_seq == echo_seq) return r;
@ -76,10 +84,7 @@ static int exit_send_echo(struct UTUN_INSTANCE* inst, uint64_t client_node_id,
icmp_hdr->icmp_seq = echo_seq;
if (payload_len > 0) memcpy(icmp_hdr->icmp_data, payload, payload_len);
icmp_hdr->icmp_cksum = 0;
uint32_t sum = 0; uint16_t* w = (uint16_t*)icmp_hdr;
for (size_t i = 0; i < (icmp_len + 1) / 2; i++) sum += w[i];
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
icmp_hdr->icmp_cksum = ~(uint16_t)sum;
icmp_hdr->icmp_cksum = icmp_checksum((const uint8_t*)icmp_hdr, icmp_len);
DEBUG_INFO(DEBUG_CATEGORY_PROXY, "icmp_proxy: sendto dst=0x%08x id=0x%04x seq=%u len=%zu",
dst_ip, echo_id, echo_seq, icmp_len);
@ -260,6 +265,7 @@ int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst,
}
struct tun_if* tun = inst->tcp_proxy_client->tun;
if (payload_len > 65506) { DEBUG_WARN(DEBUG_CATEGORY_PROXY, "icmp_proxy: payload too large len=%zu", payload_len); return -1; }
size_t icmp_len = ICMP_MINLEN + payload_len;
size_t pkt_len = 20 + icmp_len;
uint8_t* pkt = u_malloc(pkt_len);
@ -281,14 +287,12 @@ int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst,
icmp_hdr->icmp_id = echo_id; icmp_hdr->icmp_seq = echo_seq;
if (payload_len > 0) memcpy(icmp_hdr->icmp_data, payload, payload_len);
icmp_hdr->icmp_cksum = 0;
uint32_t sum = 0; uint16_t* w = (uint16_t*)icmp_hdr;
for (size_t i = 0; i < (icmp_len + 1) / 2; i++) sum += w[i];
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
icmp_hdr->icmp_cksum = ~(uint16_t)sum;
icmp_hdr->icmp_cksum = icmp_checksum((const uint8_t*)icmp_hdr, icmp_len);
struct ll_entry* e = queue_entry_new(0);
if (!e) { u_free(pkt); return -1; }
e->dgram = u_malloc(1 + pkt_len);
if (!e->dgram) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "icmp_proxy: reply allocation failed"); u_free(pkt); queue_entry_free(e); return -1; }
e->dgram[0] = 4; memcpy(e->dgram + 1, pkt, pkt_len); e->len = 1 + pkt_len;
u_free(pkt);
DEBUG_INFO(DEBUG_CATEGORY_PROXY, "icmp_proxy: reply delivered to TUN id=0x%04x seq=%u", echo_id, echo_seq);

5
src/proxy/udp_proxy.c

@ -178,14 +178,14 @@ int udp_proxy_deliver_reply(struct UTUN_INSTANCE* inst,
uint32_t src_ip, uint16_t src_port,
uint32_t dst_ip, uint16_t dst_port,
const uint8_t* payload, size_t payload_len) {
if (!inst || !inst->tcp_proxy_client || !inst->tcp_proxy_client->tun) return -1;
if (!inst || !inst->tcp_proxy_client || !inst->tcp_proxy_client->tun || payload_len > 65506) return -1;
// Собрать IP/UDP ответный пакет
size_t ip_len = 20 + 8 + payload_len;
uint8_t* pkt = u_malloc(ip_len);
if (!pkt) return -1;
memset(pkt, 0, 20);
memset(pkt, 0, 28); // IPv4 UDP checksum=0: проверка отключена явно
pkt[0] = 0x45; pkt[8] = 64; pkt[9] = IPPROTO_UDP;
memcpy(pkt + 12, &src_ip, 4); memcpy(pkt + 16, &dst_ip, 4);
@ -205,6 +205,7 @@ int udp_proxy_deliver_reply(struct UTUN_INSTANCE* inst,
struct ll_entry* e = queue_entry_new(0);
if (!e) { u_free(pkt); return -1; }
e->dgram = u_malloc(1 + ip_len);
if (!e->dgram) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "udp_proxy: reply allocation failed"); u_free(pkt); queue_entry_free(e); return -1; }
e->dgram[0] = 4; memcpy(e->dgram + 1, pkt, ip_len); e->len = 1 + ip_len;
u_free(pkt);
queue_data_put(inst->tcp_proxy_client->tun->input_queue, e);

4
tests/Makefile.am

@ -632,3 +632,7 @@ test_etcp_router_tcp_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_services_SOURCES = test_services.c
test_services_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/routing_layer -I$(top_srcdir)/src/transport_layer -I$(top_srcdir)/lib
test_services_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
check_PROGRAMS += test_proxy_packets
test_proxy_packets_SOURCES = test_proxy_packets.c
test_proxy_packets_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)

58
tests/test_proxy_packets.c

@ -0,0 +1,58 @@
// Проверяем пакеты на границе proxy → TUN: длины, адреса, payload и checksum.
#include <stdio.h>
#include <string.h>
#include "utun_instance.h"
#include "tun_if.h"
#include "proxy/udp_proxy.h"
#include "proxy/icmp_proxy.h"
#include "debug_config.h"
#include "mem.h"
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "FAIL line %d: %s\n", __LINE__, #x); return 1; } } while (0)
static unsigned checksum_sum(const uint8_t* p, size_t n) {
unsigned sum = 0;
while (n >= 2) { sum += ((unsigned)p[0] << 8) | p[1]; p += 2; n -= 2; }
if (n) sum += (unsigned)p[0] << 8;
while (sum >> 16) sum = (sum & 65535) + (sum >> 16);
return sum;
}
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
struct UASYNC* ua = uasync_create();
struct UTUN_INSTANCE* inst = u_calloc(1, sizeof(*inst));
struct tcp_proxy_client client = {0};
struct tun_if tun = {0};
CHECK(ua && inst);
inst->tcp_proxy_client = &client; client.tun = &tun;
tun.input_queue = queue_new(ua, 0, 0, 0, "packet_test");
CHECK(tun.input_queue);
uint8_t payload[1501];
for (size_t i = 0; i < sizeof(payload); i++) payload[i] = (uint8_t)(i * 17 + 3);
const uint8_t src[4] = {192, 0, 2, 1}, dst[4] = {10, 0, 0, 2};
uint32_t src_ip, dst_ip; memcpy(&src_ip, src, 4); memcpy(&dst_ip, dst, 4);
for (size_t len = 0; len <= sizeof(payload); len++) {
CHECK(udp_proxy_deliver_reply(inst, src_ip, htons(53), dst_ip, htons(23456), payload, len) == 0);
struct ll_entry* e = queue_data_get(tun.input_queue);
CHECK(e && e->len == 29 + len);
const uint8_t* ip = e->dgram + 1;
CHECK(e->dgram[0] == 4 && ip[9] == 17 && checksum_sum(ip, 20) == 65535);
CHECK(memcmp(ip + 12, src, 4) == 0 && memcmp(ip + 16, dst, 4) == 0);
CHECK(ip[26] == 0 && ip[27] == 0);
CHECK(memcmp(ip + 28, payload, len) == 0);
queue_dgram_free(e); queue_entry_free(e);
CHECK(icmp_proxy_deliver_reply(inst, dst_ip, src_ip, htons(123), htons(5), payload, len) == 0);
e = queue_data_get(tun.input_queue);
CHECK(e && e->len == 29 + len);
ip = e->dgram + 1;
CHECK(ip[9] == 1 && checksum_sum(ip, 20) == 65535 && checksum_sum(ip + 20, 8 + len) == 65535);
CHECK(ip[20] == 0 && ip[24] == 0 && ip[25] == 123 && ip[27] == 5);
CHECK(memcmp(ip + 28, payload, len) == 0);
queue_dgram_free(e); queue_entry_free(e);
}
queue_free(tun.input_queue); u_free(inst); uasync_destroy(ua, 0);
CHECK(u_get_allocated_count() == 0);
puts("[PASS] proxy UDP/ICMP packets: payload lengths 0..1501");
return 0;
}
Loading…
Cancel
Save