From 13d469d8666bee5fd31e9d335f974ddd372b73af Mon Sep 17 00:00:00 2001 From: Evgeny Date: Tue, 12 May 2026 23:03:49 +0300 Subject: [PATCH] add orig_src_ip to ICMP proxy protocol, fix deliver_reply dst_ip (was wrong tun_ip_addr) --- src/icmp_proxy.c | 47 +++++++++++++++++++++++------------------ src/icmp_proxy.h | 9 ++++---- src/tcp_proxy.c | 5 +++-- tests/test_icmp_proxy.c | 6 +++--- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/icmp_proxy.c b/src/icmp_proxy.c index e9d65cf5..9b700180 100644 --- a/src/icmp_proxy.c +++ b/src/icmp_proxy.c @@ -34,7 +34,7 @@ static struct icmp_request* req_find_by_id(struct icmp_request* head, uint16_t e // Build and send a raw ICMP echo request static int exit_send_echo(struct UTUN_INSTANCE* inst, uint64_t client_node_id, - uint32_t dst_ip, uint16_t echo_id, uint16_t echo_seq, + uint32_t dst_ip, uint32_t orig_src_ip, uint16_t echo_id, uint16_t echo_seq, const uint8_t* payload, size_t payload_len) { if (!g_icmp_ctx || g_icmp_ctx->raw_sock == SOCKET_INVALID) return -1; size_t icmp_len = ICMP_MINLEN + payload_len; @@ -64,7 +64,7 @@ static int exit_send_echo(struct UTUN_INSTANCE* inst, uint64_t client_node_id, struct icmp_request* r = u_calloc(1, sizeof(struct icmp_request)); if (!r) return 0; - r->client_node_id = client_node_id; r->dst_ip = dst_ip; + r->client_node_id = client_node_id; r->dst_ip = dst_ip; r->orig_src_ip = orig_src_ip; r->echo_id = echo_id; r->echo_seq = echo_seq; r->payload_len = payload_len > sizeof(r->payload) ? sizeof(r->payload) : payload_len; if (payload_len > 0) memcpy(r->payload, payload, r->payload_len); @@ -108,8 +108,9 @@ static void raw_read_cb(socket_t sock, void* arg) { e->dgram[1] = ICMP_PROXY_SUBCMD_REPLY; memcpy(e->dgram + 2, &r->client_node_id, 8); memcpy(e->dgram + 10, &r->dst_ip, 4); - memcpy(e->dgram + 14, &icmp_hdr->icmp_id, 2); - memcpy(e->dgram + 16, &icmp_hdr->icmp_seq, 2); + memcpy(e->dgram + 14, &r->orig_src_ip, 4); + memcpy(e->dgram + 18, &icmp_hdr->icmp_id, 2); + memcpy(e->dgram + 20, &icmp_hdr->icmp_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; int ret = etcp_route_send(g_icmp_ctx->inst, r->client_node_id, e); @@ -125,14 +126,15 @@ static void exit_handle_request(struct ETCP_CONN* conn, struct ll_entry* entry) if (!inst || !g_icmp_ctx || entry->len < ICMP_PROXY_HDR_SIZE + 1) goto drop; uint64_t client_node_id; memcpy(&client_node_id, entry->dgram + 2, 8); - uint32_t dst_ip; memcpy(&dst_ip, entry->dgram + 10, 4); - uint16_t echo_id; memcpy(&echo_id, entry->dgram + 14, 2); - uint16_t echo_seq; memcpy(&echo_seq, entry->dgram + 16, 2); + uint32_t dst_ip; memcpy(&dst_ip, entry->dgram + 10, 4); + uint32_t orig_src_ip; memcpy(&orig_src_ip, entry->dgram + 14, 4); + uint16_t echo_id; memcpy(&echo_id, entry->dgram + 18, 2); + uint16_t echo_seq; memcpy(&echo_seq, entry->dgram + 20, 2); uint8_t* payload = entry->dgram + ICMP_PROXY_HDR_SIZE; size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE; if (g_icmp_ctx->raw_sock != SOCKET_INVALID) { - exit_send_echo(inst, client_node_id, dst_ip, echo_id, echo_seq, payload, payload_len); + exit_send_echo(inst, client_node_id, dst_ip, orig_src_ip, echo_id, echo_seq, payload, payload_len); } else if (g_icmp_ctx->test_loopback) { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: test loopback reply to 0x%08x", dst_ip); struct ll_entry* e = queue_entry_new(0); @@ -143,8 +145,9 @@ static void exit_handle_request(struct ETCP_CONN* conn, struct ll_entry* entry) e->dgram[1] = ICMP_PROXY_SUBCMD_REPLY; memcpy(e->dgram + 2, &client_node_id, 8); memcpy(e->dgram + 10, &dst_ip, 4); - memcpy(e->dgram + 14, &echo_id, 2); - memcpy(e->dgram + 16, &echo_seq, 2); + memcpy(e->dgram + 14, &orig_src_ip, 4); + memcpy(e->dgram + 18, &echo_id, 2); + memcpy(e->dgram + 20, &echo_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; etcp_route_send(inst, client_node_id, e); @@ -164,14 +167,16 @@ drop: static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) { if (entry->len < ICMP_PROXY_HDR_SIZE + 1) { queue_entry_free(entry); queue_dgram_free(entry); return; } uint32_t src_ip; + uint32_t orig_src_ip; uint16_t echo_id, echo_seq; - memcpy(&src_ip, entry->dgram + 10, 4); - memcpy(&echo_id, entry->dgram + 14, 2); - memcpy(&echo_seq, entry->dgram + 16, 2); - DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: client got reply id=0x%04x seq=%u from=0x%08x", - echo_id, echo_seq, src_ip); + memcpy(&src_ip, entry->dgram + 10, 4); + memcpy(&orig_src_ip, entry->dgram + 14, 4); + memcpy(&echo_id, entry->dgram + 18, 2); + memcpy(&echo_seq, entry->dgram + 20, 2); + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: client got reply id=0x%04x seq=%u from=0x%08x dst=0x%08x", + echo_id, echo_seq, src_ip, orig_src_ip); struct UTUN_INSTANCE* inst = conn ? conn->instance : (g_icmp_ctx ? g_icmp_ctx->inst : NULL); - icmp_proxy_deliver_reply(inst, src_ip, echo_id, echo_seq, + icmp_proxy_deliver_reply(inst, orig_src_ip, src_ip, echo_id, echo_seq, entry->dgram + ICMP_PROXY_HDR_SIZE, entry->len - ICMP_PROXY_HDR_SIZE); queue_entry_free(entry); queue_dgram_free(entry); } @@ -194,7 +199,7 @@ void icmp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { // Client side: send ICMP echo request to exit node // ==================================================================== int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, - uint32_t dst_ip, uint16_t echo_id, uint16_t echo_seq, + uint32_t dst_ip, uint32_t orig_src_ip, uint16_t echo_id, uint16_t echo_seq, const uint8_t* payload, size_t payload_len) { if (!inst) return -1; struct ll_entry* e = queue_entry_new(0); @@ -205,8 +210,9 @@ int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, e->dgram[1] = ICMP_PROXY_SUBCMD_REQUEST; memcpy(e->dgram + 2, &inst->node_id, 8); memcpy(e->dgram + 10, &dst_ip, 4); - memcpy(e->dgram + 14, &echo_id, 2); - memcpy(e->dgram + 16, &echo_seq, 2); + memcpy(e->dgram + 14, &orig_src_ip, 4); + memcpy(e->dgram + 18, &echo_id, 2); + memcpy(e->dgram + 20, &echo_seq, 2); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len); e->len = ICMP_PROXY_HDR_SIZE + payload_len; return etcp_route_send(inst, exit_node_id, e); @@ -216,7 +222,7 @@ int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, // Client side: deliver ICMP echo reply to TUN // ==================================================================== int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst, - uint32_t src_ip, uint16_t echo_id, uint16_t echo_seq, + uint32_t dst_ip, uint32_t src_ip, uint16_t echo_id, uint16_t echo_seq, const uint8_t* payload, size_t payload_len) { if (!inst || !inst->tcp_proxy || !inst->tcp_proxy->tun) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "icmp_proxy: deliver_reply failed — no %s", @@ -224,7 +230,6 @@ int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst, return -1; } struct tun_if* tun = inst->tcp_proxy->tun; - uint32_t dst_ip = inst->tcp_proxy->tun_ip_addr; size_t icmp_len = ICMP_MINLEN + payload_len; size_t pkt_len = 20 + icmp_len; diff --git a/src/icmp_proxy.h b/src/icmp_proxy.h index 3886f4d6..e23d0478 100644 --- a/src/icmp_proxy.h +++ b/src/icmp_proxy.h @@ -15,14 +15,15 @@ struct ETCP_CONN; #define ICMP_PROXY_SUBCMD_REPLY 0x02 // exit→client: echo reply // Message header (excluding svc_id byte) -// svc_id(1) + subcmd(1) + sender_node_id(8) + dst_ip(4) + icmp_id(2) + icmp_seq(2) + payload -#define ICMP_PROXY_HDR_SIZE 18 +// svc_id(1) + subcmd(1) + sender_node_id(8) + dst_ip(4) + orig_src_ip(4) + icmp_id(2) + icmp_seq(2) + payload +#define ICMP_PROXY_HDR_SIZE 22 // In-flight ICMP echo request (exit node side) struct icmp_request { struct icmp_request* next; uint64_t client_node_id; uint32_t dst_ip; + uint32_t orig_src_ip; // IP исходного отправителя (чтобы вернуть reply правильному адресату) uint16_t echo_id; uint16_t echo_seq; uint8_t payload[1500]; @@ -51,11 +52,11 @@ void icmp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry); // Client side: принять IP/ICMP echo request с TUN, отправить через etcp int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, - uint32_t dst_ip, uint16_t echo_id, uint16_t echo_seq, + uint32_t dst_ip, uint32_t orig_src_ip, uint16_t echo_id, uint16_t echo_seq, const uint8_t* payload, size_t payload_len); int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst, - uint32_t src_ip, uint16_t echo_id, uint16_t echo_seq, + uint32_t dst_ip, uint32_t src_ip, uint16_t echo_id, uint16_t echo_seq, const uint8_t* payload, size_t payload_len); void icmp_proxy_set_test_loopback(struct UTUN_INSTANCE* inst, int enabled); diff --git a/src/tcp_proxy.c b/src/tcp_proxy.c index a4815d7c..2d0340b6 100644 --- a/src/tcp_proxy.c +++ b/src/tcp_proxy.c @@ -162,10 +162,11 @@ static int tcp_proxy_handle_non_tcp(struct tcp_proxy* p, uint8_t* buf, size_t le if (len < 28) return 0; uint8_t icmp_type = buf[20]; if (icmp_type != 8) return 0; - uint32_t dst_ip; memcpy(&dst_ip, buf + 16, 4); + uint32_t src_ip, dst_ip; + memcpy(&src_ip, buf + 12, 4); memcpy(&dst_ip, buf + 16, 4); uint16_t icmp_id, icmp_seq; memcpy(&icmp_id, buf + 24, 2); memcpy(&icmp_seq, buf + 26, 2); - icmp_proxy_send_to_exit(p->inst, p->via_node_id, dst_ip, icmp_id, icmp_seq, buf + 28, len - 28); + icmp_proxy_send_to_exit(p->inst, p->via_node_id, dst_ip, src_ip, icmp_id, icmp_seq, buf + 28, len - 28); return 1; } return 0; diff --git a/tests/test_icmp_proxy.c b/tests/test_icmp_proxy.c index 8c1ac937..f5dc5504 100644 --- a/tests/test_icmp_proxy.c +++ b/tests/test_icmp_proxy.c @@ -89,8 +89,8 @@ static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { } if (entry->dgram[1] == ICMP_PROXY_SUBCMD_REPLY) { uint16_t rid, rseq; - memcpy(&rid, entry->dgram + 14, 2); - memcpy(&rseq, entry->dgram + 16, 2); + memcpy(&rid, entry->dgram + 18, 2); + memcpy(&rseq, entry->dgram + 20, 2); if (rid == test_echo_id && rseq == test_echo_seq) { size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE; uint8_t* payload = entry->dgram + ICMP_PROXY_HDR_SIZE; @@ -126,7 +126,7 @@ static void monitor(void* arg) { etcp_router_bind(cli, ETCP_ID_ICMP_PROXY, cli_recv_cb); for (int i = 0; i < ICMP_PAYLOAD_SIZE; i++) send_buf[i] = (uint8_t)(rand() & 0xFF); icmp_proxy_send_to_exit(cli, exit_node_id, - inet_addr("127.0.0.1"), test_echo_id, test_echo_seq, send_buf, ICMP_PAYLOAD_SIZE); + inet_addr("127.0.0.1"), inet_addr("127.0.0.100"), test_echo_id, test_echo_seq, send_buf, ICMP_PAYLOAD_SIZE); } } if (!g_done) g_to_id = uasync_set_timeout(ua, 100, NULL, monitor, "mon");