Browse Source

add orig_src_ip to ICMP proxy protocol, fix deliver_reply dst_ip (was wrong tun_ip_addr)

congestion
Evgeny 5 months ago
parent
commit
13d469d866
  1. 47
      src/icmp_proxy.c
  2. 9
      src/icmp_proxy.h
  3. 5
      src/tcp_proxy.c
  4. 6
      tests/test_icmp_proxy.c

47
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 // Build and send a raw ICMP echo request
static int exit_send_echo(struct UTUN_INSTANCE* inst, uint64_t client_node_id, 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) { const uint8_t* payload, size_t payload_len) {
if (!g_icmp_ctx || g_icmp_ctx->raw_sock == SOCKET_INVALID) return -1; if (!g_icmp_ctx || g_icmp_ctx->raw_sock == SOCKET_INVALID) return -1;
size_t icmp_len = ICMP_MINLEN + payload_len; 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)); struct icmp_request* r = u_calloc(1, sizeof(struct icmp_request));
if (!r) return 0; 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->echo_id = echo_id; r->echo_seq = echo_seq;
r->payload_len = payload_len > sizeof(r->payload) ? sizeof(r->payload) : payload_len; r->payload_len = payload_len > sizeof(r->payload) ? sizeof(r->payload) : payload_len;
if (payload_len > 0) memcpy(r->payload, payload, r->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; e->dgram[1] = ICMP_PROXY_SUBCMD_REPLY;
memcpy(e->dgram + 2, &r->client_node_id, 8); memcpy(e->dgram + 2, &r->client_node_id, 8);
memcpy(e->dgram + 10, &r->dst_ip, 4); memcpy(e->dgram + 10, &r->dst_ip, 4);
memcpy(e->dgram + 14, &icmp_hdr->icmp_id, 2); memcpy(e->dgram + 14, &r->orig_src_ip, 4);
memcpy(e->dgram + 16, &icmp_hdr->icmp_seq, 2); 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); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
e->len = ICMP_PROXY_HDR_SIZE + payload_len; e->len = ICMP_PROXY_HDR_SIZE + payload_len;
int ret = etcp_route_send(g_icmp_ctx->inst, r->client_node_id, e); 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; 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); uint64_t client_node_id; memcpy(&client_node_id, entry->dgram + 2, 8);
uint32_t dst_ip; memcpy(&dst_ip, entry->dgram + 10, 4); uint32_t dst_ip; memcpy(&dst_ip, entry->dgram + 10, 4);
uint16_t echo_id; memcpy(&echo_id, entry->dgram + 14, 2); uint32_t orig_src_ip; memcpy(&orig_src_ip, entry->dgram + 14, 4);
uint16_t echo_seq; memcpy(&echo_seq, entry->dgram + 16, 2); 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; uint8_t* payload = entry->dgram + ICMP_PROXY_HDR_SIZE;
size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE; size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE;
if (g_icmp_ctx->raw_sock != SOCKET_INVALID) { 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) { } else if (g_icmp_ctx->test_loopback) {
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: test loopback reply to 0x%08x", dst_ip); DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: test loopback reply to 0x%08x", dst_ip);
struct ll_entry* e = queue_entry_new(0); 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; e->dgram[1] = ICMP_PROXY_SUBCMD_REPLY;
memcpy(e->dgram + 2, &client_node_id, 8); memcpy(e->dgram + 2, &client_node_id, 8);
memcpy(e->dgram + 10, &dst_ip, 4); memcpy(e->dgram + 10, &dst_ip, 4);
memcpy(e->dgram + 14, &echo_id, 2); memcpy(e->dgram + 14, &orig_src_ip, 4);
memcpy(e->dgram + 16, &echo_seq, 2); 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); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
e->len = ICMP_PROXY_HDR_SIZE + payload_len; e->len = ICMP_PROXY_HDR_SIZE + payload_len;
etcp_route_send(inst, client_node_id, e); 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) { 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; } if (entry->len < ICMP_PROXY_HDR_SIZE + 1) { queue_entry_free(entry); queue_dgram_free(entry); return; }
uint32_t src_ip; uint32_t src_ip;
uint32_t orig_src_ip;
uint16_t echo_id, echo_seq; uint16_t echo_id, echo_seq;
memcpy(&src_ip, entry->dgram + 10, 4); memcpy(&src_ip, entry->dgram + 10, 4);
memcpy(&echo_id, entry->dgram + 14, 2); memcpy(&orig_src_ip, entry->dgram + 14, 4);
memcpy(&echo_seq, entry->dgram + 16, 2); memcpy(&echo_id, entry->dgram + 18, 2);
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: client got reply id=0x%04x seq=%u from=0x%08x", memcpy(&echo_seq, entry->dgram + 20, 2);
echo_id, echo_seq, src_ip); 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); 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); entry->dgram + ICMP_PROXY_HDR_SIZE, entry->len - ICMP_PROXY_HDR_SIZE);
queue_entry_free(entry); queue_dgram_free(entry); 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 // Client side: send ICMP echo request to exit node
// ==================================================================== // ====================================================================
int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, 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) { const uint8_t* payload, size_t payload_len) {
if (!inst) return -1; if (!inst) return -1;
struct ll_entry* e = queue_entry_new(0); 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; e->dgram[1] = ICMP_PROXY_SUBCMD_REQUEST;
memcpy(e->dgram + 2, &inst->node_id, 8); memcpy(e->dgram + 2, &inst->node_id, 8);
memcpy(e->dgram + 10, &dst_ip, 4); memcpy(e->dgram + 10, &dst_ip, 4);
memcpy(e->dgram + 14, &echo_id, 2); memcpy(e->dgram + 14, &orig_src_ip, 4);
memcpy(e->dgram + 16, &echo_seq, 2); 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); if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
e->len = ICMP_PROXY_HDR_SIZE + payload_len; e->len = ICMP_PROXY_HDR_SIZE + payload_len;
return etcp_route_send(inst, exit_node_id, e); 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 // Client side: deliver ICMP echo reply to TUN
// ==================================================================== // ====================================================================
int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst, 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) { const uint8_t* payload, size_t payload_len) {
if (!inst || !inst->tcp_proxy || !inst->tcp_proxy->tun) { if (!inst || !inst->tcp_proxy || !inst->tcp_proxy->tun) {
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "icmp_proxy: deliver_reply failed — no %s", 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; return -1;
} }
struct tun_if* tun = inst->tcp_proxy->tun; 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 icmp_len = ICMP_MINLEN + payload_len;
size_t pkt_len = 20 + icmp_len; size_t pkt_len = 20 + icmp_len;

9
src/icmp_proxy.h

@ -15,14 +15,15 @@ struct ETCP_CONN;
#define ICMP_PROXY_SUBCMD_REPLY 0x02 // exit→client: echo reply #define ICMP_PROXY_SUBCMD_REPLY 0x02 // exit→client: echo reply
// Message header (excluding svc_id byte) // 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 // 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 18 #define ICMP_PROXY_HDR_SIZE 22
// In-flight ICMP echo request (exit node side) // In-flight ICMP echo request (exit node side)
struct icmp_request { struct icmp_request {
struct icmp_request* next; struct icmp_request* next;
uint64_t client_node_id; uint64_t client_node_id;
uint32_t dst_ip; uint32_t dst_ip;
uint32_t orig_src_ip; // IP исходного отправителя (чтобы вернуть reply правильному адресату)
uint16_t echo_id; uint16_t echo_id;
uint16_t echo_seq; uint16_t echo_seq;
uint8_t payload[1500]; 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 // Client side: принять IP/ICMP echo request с TUN, отправить через etcp
int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id, 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); const uint8_t* payload, size_t payload_len);
int icmp_proxy_deliver_reply(struct UTUN_INSTANCE* inst, 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); const uint8_t* payload, size_t payload_len);
void icmp_proxy_set_test_loopback(struct UTUN_INSTANCE* inst, int enabled); void icmp_proxy_set_test_loopback(struct UTUN_INSTANCE* inst, int enabled);

5
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; if (len < 28) return 0;
uint8_t icmp_type = buf[20]; uint8_t icmp_type = buf[20];
if (icmp_type != 8) return 0; 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; uint16_t icmp_id, icmp_seq;
memcpy(&icmp_id, buf + 24, 2); memcpy(&icmp_seq, buf + 26, 2); 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 1;
} }
return 0; return 0;

6
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) { if (entry->dgram[1] == ICMP_PROXY_SUBCMD_REPLY) {
uint16_t rid, rseq; uint16_t rid, rseq;
memcpy(&rid, entry->dgram + 14, 2); memcpy(&rid, entry->dgram + 18, 2);
memcpy(&rseq, entry->dgram + 16, 2); memcpy(&rseq, entry->dgram + 20, 2);
if (rid == test_echo_id && rseq == test_echo_seq) { if (rid == test_echo_id && rseq == test_echo_seq) {
size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE; size_t payload_len = entry->len - ICMP_PROXY_HDR_SIZE;
uint8_t* payload = entry->dgram + 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); 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); 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, 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"); if (!g_done) g_to_id = uasync_set_timeout(ua, 100, NULL, monitor, "mon");

Loading…
Cancel
Save