refactor tcp_proxy: remove local socket mode, simplify architecture
- remove sock_transport, transport abstraction, active connections API - simplify proxy_conn to 13 fields (was 15), remove tcp_proxy_mapping linked list - new protocol: stream_id 4B, seq 2B cyclic, HDR_SIZE 8B - add ERROR subcmd for immediate abort, CLOSE for graceful half-close - proper half-close: shutdown SHUT_WR, keep reading, no timer - exhaustive DEBUG_ERROR/WARN on all error/unusual branches - config parser: report unknown options with filename:line and valid keys
This commit is contained in:
1 parent
c3eccd7b35
commit
e5d11ef9c1
10 files changed
+496
-961
No files matched your search
+38
-29
@@ -342,7 +342,7 @@ static struct CFG_SERVER* find_server_by_name(struct CFG_SERVER *servers, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parse_global(const char *key, const char *value, struct global_config *global) {
|
||||
static int parse_global(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "my_node_name") == 0) {
|
||||
return assign_string(global->name, sizeof(global->name), value);
|
||||
}
|
||||
@@ -411,10 +411,11 @@ static int parse_global(const char *key, const char *value, struct global_config
|
||||
global->tun_test_mode = atoi(value);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown global option '%s'. Valid: my_node_name, my_private_key, my_public_key, my_node_id, tun_ifname, tun_ip, mtu, keepalive_timeout, keepalive_interval, inflight_min_bytes, inflight_max_bytes, debug_level, log_file, enable_timestamp, enable_function_names, enable_file_lines, enable_colors, tun_test_mode", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_control(const char *key, const char *value, struct global_config *global) {
|
||||
static int parse_control(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "ip") == 0 || strcmp(key, "control_ip") == 0) {
|
||||
strncpy(global->control_ip, value, sizeof(global->control_ip) - 1);
|
||||
global->control_ip[sizeof(global->control_ip) - 1] = '\0';
|
||||
@@ -435,10 +436,11 @@ static int parse_control(const char *key, const char *value, struct global_confi
|
||||
if (strcmp(key, "allow") == 0 || strcmp(key, "control_allow") == 0) {
|
||||
return parse_control_allow(value, global);
|
||||
}
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown control option '%s'. Valid: ip/control_ip, port/control_port, allow/control_allow", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_tcp_proxy(const char *key, const char *value, struct global_config *global) {
|
||||
static int parse_tcp_proxy(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "enabled") == 0) {
|
||||
global->tcp_proxy_enabled = strcasecmp(value, "yes") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "true") == 0;
|
||||
return 0;
|
||||
@@ -455,10 +457,6 @@ static int parse_tcp_proxy(const char *key, const char *value, struct global_con
|
||||
global->tcp_proxy_mtu = atoi(value);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "eim_timeout") == 0) {
|
||||
global->tcp_proxy_eim_timeout = atoi(value);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "via_node") == 0) {
|
||||
global->tcp_proxy_via_node_id = strtoull(value, NULL, 16);
|
||||
return 0;
|
||||
@@ -499,10 +497,11 @@ static int parse_tcp_proxy(const char *key, const char *value, struct global_con
|
||||
global->tcp_proxy_mapping_count++;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown tcp_proxy option '%s'. Valid: enabled, tun_name, tun_ip, mtu, via_node, forward", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_nat(const char *key, const char *value, struct global_config *global) {
|
||||
static int parse_nat(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "tun_ifname") == 0) {
|
||||
strncpy(global->nat_tun_ifname, value, sizeof(global->nat_tun_ifname) - 1);
|
||||
return 0;
|
||||
@@ -565,15 +564,15 @@ static int parse_nat(const char *key, const char *value, struct global_config *g
|
||||
global->nat_forwards[idx].internal_port_net = htons((uint16_t)atoi(int_port));
|
||||
global->nat_forwards[idx].external_port = (uint16_t)atoi(ext_port);
|
||||
global->nat_forward_count++;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "NAT forward: %s %s:%s -> :%s",
|
||||
proto_str, ip_str, int_port, ext_port);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown NAT option '%s'. Valid: tun_ifname, tun_ip, nat_via, port_start, port_end, forward", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_server(const char *key, const char *value, struct CFG_SERVER *srv) {
|
||||
static int parse_server(const char *key, const char *value, struct CFG_SERVER *srv, const char *filename, int line_num) {
|
||||
if (strcmp(key, "addr") == 0) {
|
||||
if (strncmp(value, "temporary_ipv6:", 15) == 0) {
|
||||
srv->ipv6_mode = CFG_IPV6_MODE_TEMPORARY;
|
||||
@@ -629,10 +628,11 @@ static int parse_server(const char *key, const char *value, struct CFG_SERVER *s
|
||||
srv->only_local = atoi(value) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown server option '%s'. Valid: addr, so_mark, fib, netif, type, mtu, only_local", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_client(const char *key, const char *value, struct CFG_CLIENT *cli, struct CFG_SERVER *servers) {
|
||||
static int parse_client(const char *key, const char *value, struct CFG_CLIENT *cli, struct CFG_SERVER *servers, const char *filename, int line_num) {
|
||||
if (strcmp(key, "link") == 0) {
|
||||
char link_copy[MAX_CONN_NAME_LEN + MAX_ADDR_LEN];
|
||||
if (strlen(value) >= sizeof(link_copy)) return -1;
|
||||
@@ -670,7 +670,8 @@ static int parse_client(const char *key, const char *value, struct CFG_CLIENT *c
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown client option '%s'. Valid: link, peer_public_key, keepalive", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static section_type_t parse_section_header(const char *line, char *name, size_t name_len) {
|
||||
@@ -788,18 +789,18 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
|
||||
switch (cur_section) {
|
||||
case SECTION_GLOBAL:
|
||||
if (parse_global(key, value, &cfg->global) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid global key '%s'", filename, line_num, key);
|
||||
if (parse_global(key, value, &cfg->global, filename, line_num) < 0) {
|
||||
// parse_global already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_SERVER:
|
||||
if (cur_server && parse_server(key, value, cur_server) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid server key '%s'", filename, line_num, key);
|
||||
if (cur_server && parse_server(key, value, cur_server, filename, line_num) < 0) {
|
||||
// parse_server already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_CLIENT:
|
||||
if (cur_client && parse_client(key, value, cur_client, cfg->servers) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid client key '%s'", filename, line_num, key);
|
||||
if (cur_client && parse_client(key, value, cur_client, cfg->servers, filename, line_num) < 0) {
|
||||
// parse_client already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_ROUTING:
|
||||
@@ -807,6 +808,8 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
add_route_entry(&cfg->route_subnets, value);
|
||||
} else if (strcmp(key, "my_subnet") == 0) {
|
||||
add_route_entry(&cfg->my_subnets, value);
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown routing option '%s'. Valid: route_subnet, my_subnet", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_DEBUG:
|
||||
@@ -826,11 +829,13 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
if (parse_firewall_rule(value, &cfg->global) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid firewall rule: %s", filename, line_num, value);
|
||||
}
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown firewall option '%s'. Valid: allow", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_CONTROL:
|
||||
if (parse_control(key, value, &cfg->global) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid control key '%s'", filename, line_num, key);
|
||||
if (parse_control(key, value, &cfg->global, filename, line_num) < 0) {
|
||||
// parse_control already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_ALLOWED_KEYS:
|
||||
@@ -851,22 +856,26 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
cfg->global.allowed_keys = new_key;
|
||||
cfg->global.allowed_keys_count++;
|
||||
}
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown allowed_keys option '%s'. Valid: allow_all, key", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_NAT:
|
||||
cfg->global.nat_enabled = 1;
|
||||
if (parse_nat(key, value, &cfg->global) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT key '%s'", filename, line_num, key);
|
||||
if (parse_nat(key, value, &cfg->global, filename, line_num) < 0) {
|
||||
// parse_nat already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_TCP_PROXY:
|
||||
cfg->global.tcp_proxy_enabled = 1;
|
||||
if (parse_tcp_proxy(key, value, &cfg->global) < 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid tcp_proxy key '%s'", filename, line_num, key);
|
||||
if (parse_tcp_proxy(key, value, &cfg->global, filename, line_num) < 0) {
|
||||
// parse_tcp_proxy already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_REMOTE_PROXY:
|
||||
cfg->global.remote_proxy_enabled = 1;
|
||||
// remote_proxy section has no options — its presence alone enables it
|
||||
(void)key; (void)value;
|
||||
break;
|
||||
default:
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Key outside section: %s", filename, line_num, key);
|
||||
|
||||
+1
-2
@@ -156,8 +156,7 @@ struct global_config {
|
||||
char tcp_proxy_tun_name[16];
|
||||
char tcp_proxy_tun_ip[64];
|
||||
int tcp_proxy_mtu;
|
||||
int tcp_proxy_eim_timeout;
|
||||
uint64_t tcp_proxy_via_node_id; // через этот узел проксируются все forward-правила (0=локально)
|
||||
uint64_t tcp_proxy_via_node_id; // через этот узел проксируются все forward-правила
|
||||
struct tcp_proxy_mapping_config tcp_proxy_mappings[MAX_TCP_PROXY_MAPPINGS];
|
||||
int tcp_proxy_mapping_count;
|
||||
|
||||
|
||||
+102
-114
@@ -7,6 +7,7 @@
|
||||
#include "etcp_api.h"
|
||||
#include "etcp_router.h"
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -27,36 +28,33 @@
|
||||
|
||||
static struct remote_proxy_ctx* g_rp_ctx = NULL;
|
||||
|
||||
static void rp_sock_read_cb (socket_t sock, void* arg);
|
||||
static void rp_sock_read_cb(socket_t sock, void* arg);
|
||||
static void rp_sock_write_cb(socket_t sock, void* arg);
|
||||
static void rp_sock_error_cb(socket_t sock, void* arg);
|
||||
static void rp_conn_free(struct remote_proxy_conn* rc);
|
||||
void rp_conn_free(struct remote_proxy_conn* rc);
|
||||
|
||||
static int rp_send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd,
|
||||
uint64_t sid, uint16_t seq, const uint8_t* data, size_t len) {
|
||||
uint32_t sid, uint16_t seq, const uint8_t* data, size_t len) {
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) return -1;
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "rp_send_msg: queue_entry_new failed subcmd=%02x sid=%08x", subcmd, sid); return -1; }
|
||||
e->dgram = u_malloc(TCP_PROXY_HDR_SIZE + len);
|
||||
if (!e->dgram) { queue_entry_free(e); return -1; }
|
||||
if (!e->dgram) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "rp_send_msg: malloc(%zu) failed subcmd=%02x sid=%08x", TCP_PROXY_HDR_SIZE + len, subcmd, sid); queue_entry_free(e); return -1; }
|
||||
e->dgram[0] = ETCP_ID_TCP_PROXY;
|
||||
e->dgram[1] = subcmd;
|
||||
memcpy(e->dgram + 2, &sid, 8);
|
||||
memcpy(e->dgram + 10, &seq, 2);
|
||||
memcpy(e->dgram + 2, &sid, 4);
|
||||
memcpy(e->dgram + 6, &seq, 2);
|
||||
if (len > 0) memcpy(e->dgram + TCP_PROXY_HDR_SIZE, data, len);
|
||||
e->len = TCP_PROXY_HDR_SIZE + len;
|
||||
return etcp_route_send(inst, dst, e);
|
||||
}
|
||||
|
||||
static int rp_send_connected(struct UTUN_INSTANCE* inst, uint64_t dst, uint64_t sid,
|
||||
static int rp_send_connected(struct UTUN_INSTANCE* inst, uint64_t dst, uint32_t sid,
|
||||
uint16_t local_port, uint8_t status) {
|
||||
uint8_t buf[3];
|
||||
memcpy(buf, &local_port, 2); buf[2] = status;
|
||||
return rp_send_msg(inst, dst, TCP_PROXY_SUBCMD_CONNECTED, sid, 0, buf, 3);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Socket event logging helper
|
||||
// ====================================================================
|
||||
static int rp_conn_total(struct remote_proxy_conn* rc) {
|
||||
if (!rc || !rc->ctx) return 0;
|
||||
int n = 0; struct remote_proxy_conn* c;
|
||||
@@ -69,64 +67,76 @@ static int rp_conn_total(struct remote_proxy_conn* rc) {
|
||||
// ====================================================================
|
||||
static void rp_sock_read_cb(socket_t sock, void* arg) {
|
||||
(void)sock; struct remote_proxy_conn* rc = (struct remote_proxy_conn*)arg;
|
||||
if (!rc || rc->sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "RP rp_sock_read_cb: rc=%p sock=%d", (void*)rc, rc ? (int)rc->sock : -1); return; }
|
||||
if (!rc || rc->sock == SOCKET_INVALID) return;
|
||||
uint8_t buf[8192]; ssize_t n = recv(rc->sock, buf, sizeof(buf), 0);
|
||||
if (n > 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:RECV fd=%d stream=%016llx len=%zd total=%d", (int)rc->sock, (unsigned long long)rc->stream_id, n, rp_conn_total(rc));
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) {
|
||||
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:RECV fd=%d sid=%08x — inst is NULL, drop", (int)rc->sock, rc->stream_id); return; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:RECV fd=%d sid=%08x len=%zd total=%d", (int)rc->sock, rc->stream_id, n, rp_conn_total(rc));
|
||||
if (!rc->error) {
|
||||
rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, rc->send_seq, buf, (size_t)n);
|
||||
rc->send_seq++;
|
||||
}
|
||||
} else {
|
||||
if (n == 0) DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "remote_proxy: EOF stream=%016llx", (unsigned long long)rc->stream_id);
|
||||
else DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: recv error %s", strerror(errno));
|
||||
} else if (n == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:EOF fd=%d sid=%08x total=%d cli_closed=%d sock_closed=%d",
|
||||
(int)rc->sock, rc->stream_id, rp_conn_total(rc), rc->cli_closed, rc->sock_closed);
|
||||
rc->sock_closed = 1;
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, 0, NULL, 0);
|
||||
rc->connected = -1;
|
||||
if (inst) rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, 0, NULL, 0);
|
||||
else DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:EOF fd=%d sid=%08x — inst is NULL, can't send CLOSE", (int)rc->sock, rc->stream_id);
|
||||
if (rc->read_id) { uasync_remove_socket_t(rc->ua, rc->sock); rc->read_id = NULL; }
|
||||
if (rc->cli_closed) rp_conn_free(rc);
|
||||
} else if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:ERROR fd=%d sid=%08x errno=%d %s total=%d",
|
||||
(int)rc->sock, rc->stream_id, errno, strerror(errno), rp_conn_total(rc));
|
||||
rc->error = 1;
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_ERROR, rc->stream_id, 0, NULL, 0);
|
||||
else DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:ERROR fd=%d sid=%08x — inst is NULL, can't send ERROR", (int)rc->sock, rc->stream_id);
|
||||
rp_conn_free(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void rp_sock_write_cb(socket_t sock, void* arg) {
|
||||
(void)sock; struct remote_proxy_conn* rc = (struct remote_proxy_conn*)arg;
|
||||
if (!rc || rc->sock == SOCKET_INVALID) return;
|
||||
if (!rc->connected) {
|
||||
if (!rc->connect_called) return;
|
||||
int err = 0; socklen_t len = sizeof(err);
|
||||
if (getsockopt(rc->sock, SOL_SOCKET, SO_ERROR, &err, &len) == 0 && err == 0) {
|
||||
rc->connected = 1;
|
||||
struct sockaddr_in local; socklen_t llen = sizeof(local);
|
||||
uint16_t local_port = 0;
|
||||
if (getsockname(rc->sock, (struct sockaddr*)&local, &llen) == 0) local_port = local.sin_port;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:CONN fd=%d stream=%016llx local=%d dest=%d.%d.%d.%d:%d total=%d",
|
||||
(int)rc->sock, (unsigned long long)rc->stream_id, ntohs(local_port),
|
||||
rc->dest_ip[0], rc->dest_ip[1], rc->dest_ip[2], rc->dest_ip[3], ntohs(rc->dest_port),
|
||||
rp_conn_total(rc));
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_connected(inst, rc->peer_node_id, rc->stream_id, local_port, TCP_PROXY_CONNECTED_OK);
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: connect failed %s", err ? strerror(err) : "unknown");
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_connected(inst, rc->peer_node_id, rc->stream_id, 0, TCP_PROXY_CONNECTED_REFUSED);
|
||||
rc->connected = -1;
|
||||
rp_conn_free(rc);
|
||||
}
|
||||
if (!rc || rc->sock == SOCKET_INVALID || rc->connected) return;
|
||||
int err = 0; socklen_t len = sizeof(err);
|
||||
if (getsockopt(rc->sock, SOL_SOCKET, SO_ERROR, &err, &len) == 0 && err == 0) {
|
||||
rc->connected = 1;
|
||||
struct sockaddr_in local; socklen_t llen = sizeof(local);
|
||||
uint16_t local_port = 0;
|
||||
if (getsockname(rc->sock, (struct sockaddr*)&local, &llen) == 0) local_port = local.sin_port;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:CONN fd=%d sid=%08x local=%d dest=%d.%d.%d.%d:%d total=%d",
|
||||
(int)rc->sock, rc->stream_id, ntohs(local_port),
|
||||
rc->dest_ip[0], rc->dest_ip[1], rc->dest_ip[2], rc->dest_ip[3], ntohs(rc->dest_port),
|
||||
rp_conn_total(rc));
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_connected(inst, rc->peer_node_id, rc->stream_id, local_port, TCP_PROXY_CONNECTED_OK);
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:FAIL fd=%d sid=%08x err=%d %s",
|
||||
(int)rc->sock, rc->stream_id, err, err ? strerror(err) : "unknown");
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_connected(inst, rc->peer_node_id, rc->stream_id, 0, TCP_PROXY_CONNECTED_REFUSED);
|
||||
rp_conn_free(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void rp_sock_error_cb(socket_t sock, void* arg) {
|
||||
(void)sock; struct remote_proxy_conn* rc = (struct remote_proxy_conn*)arg;
|
||||
if (!rc || rc->sock == SOCKET_INVALID) return;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: socket error stream=%016llx", (unsigned long long)(rc ? rc->stream_id : 0));
|
||||
rc->connected = -1;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:ERR fd=%d sid=%08x", (int)rc->sock, rc->stream_id);
|
||||
rc->error = 1;
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (inst) rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, 0, NULL, 0);
|
||||
if (inst) rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_ERROR, rc->stream_id, 0, NULL, 0);
|
||||
else DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "SOCK:ERR fd=%d sid=%08x — inst is NULL", (int)rc->sock, rc->stream_id);
|
||||
rp_conn_free(rc);
|
||||
}
|
||||
|
||||
static void rp_conn_free(struct remote_proxy_conn* rc) {
|
||||
void rp_conn_free(struct remote_proxy_conn* rc) {
|
||||
if (!rc) return;
|
||||
int total = rp_conn_total(rc);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:FREE fd=%d sid=%08x total=%d cli_closed=%d sock_closed=%d error=%d",
|
||||
(int)rc->sock, rc->stream_id, total, rc->cli_closed, rc->sock_closed, rc->error);
|
||||
if (rc->ctx) {
|
||||
struct remote_proxy_conn** prev = &rc->ctx->conns;
|
||||
while (*prev) { if (*prev == rc) { *prev = rc->next; rc->ctx->conn_count--; break; } prev = &(*prev)->next; }
|
||||
@@ -138,65 +148,47 @@ static void rp_conn_free(struct remote_proxy_conn* rc) {
|
||||
u_free(rc);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Standalone handler (registered when tcp_proxy doesn't have remote mappings)
|
||||
// ====================================================================
|
||||
static void rp_standalone_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
struct UTUN_INSTANCE* i = conn ? conn->instance : (g_rp_ctx ? g_rp_ctx->inst : NULL);
|
||||
if (!i || !entry || entry->dgram == NULL || entry->len < TCP_PROXY_HDR_SIZE) {
|
||||
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); }
|
||||
return;
|
||||
}
|
||||
uint8_t subcmd = entry->dgram[1];
|
||||
uint64_t sid = 0; memcpy(&sid, entry->dgram + 2, 8);
|
||||
uint64_t src = conn ? conn->peer_node_id : i->node_id;
|
||||
if (subcmd == TCP_PROXY_SUBCMD_CONNECT) { remote_proxy_handle_connect(i, entry, sid, src); return; }
|
||||
if (subcmd == TCP_PROXY_SUBCMD_DATA) { remote_proxy_handle_data(i, entry, sid); return; }
|
||||
if (subcmd == TCP_PROXY_SUBCMD_CLOSE) { remote_proxy_handle_close(i, sid); queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Public API
|
||||
// ====================================================================
|
||||
struct remote_proxy_conn* remote_proxy_find_conn(struct remote_proxy_ctx* ctx, uint64_t stream_id) {
|
||||
struct remote_proxy_conn* remote_proxy_find_conn(struct remote_proxy_ctx* ctx, uint32_t stream_id) {
|
||||
struct remote_proxy_conn* c;
|
||||
for (c = ctx->conns; c; c = c->next) if (c->stream_id == stream_id) return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int remote_proxy_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry* entry,
|
||||
uint64_t stream_id, uint64_t src_node_id) {
|
||||
if (!inst || !inst->remote_proxy.enabled) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
uint32_t stream_id, uint64_t src_node_id) {
|
||||
if (!inst || !inst->remote_proxy.enabled) { if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1; }
|
||||
struct remote_proxy_ctx* ctx = &inst->remote_proxy;
|
||||
if (entry->len < TCP_PROXY_CONNECT_HDR_SIZE) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
if (entry->len < TCP_PROXY_CONNECT_HDR_SIZE) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: CONNECT too short len=%u", entry->len); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
uint8_t* dest_ip = entry->dgram + TCP_PROXY_HDR_SIZE;
|
||||
uint16_t dest_port = 0; memcpy(&dest_port, dest_ip + 4, 2);
|
||||
|
||||
struct remote_proxy_conn* rc = u_calloc(1, sizeof(struct remote_proxy_conn));
|
||||
if (!rc) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
if (!rc) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: u_calloc failed for sid=%08x", stream_id); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
rc->ctx = ctx; rc->stream_id = stream_id; rc->peer_node_id = src_node_id;
|
||||
memcpy(rc->dest_ip, dest_ip, 4); rc->dest_port = dest_port;
|
||||
rc->ua = inst->ua; rc->sock = SOCKET_INVALID;
|
||||
rc->send_seq = 0; rc->recv_seq_init = 0;
|
||||
|
||||
rc->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (rc->sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: socket() failed"); rp_conn_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
if (rc->sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: socket() failed"); u_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
ctx->conn_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:NEW fd=%d stream=%016llx dest=%d.%d.%d.%d:%d total=%d", (int)rc->sock, (unsigned long long)stream_id,
|
||||
dest_ip[0],dest_ip[1],dest_ip[2],dest_ip[3],ntohs(dest_port), ctx->conn_count);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:NEW fd=%d sid=%08x dest=%d.%d.%d.%d:%d total=%d",
|
||||
(int)rc->sock, stream_id, dest_ip[0],dest_ip[1],dest_ip[2],dest_ip[3],ntohs(dest_port), ctx->conn_count);
|
||||
socket_set_nonblocking(rc->sock);
|
||||
rc->read_id = uasync_add_socket_t(rc->ua, rc->sock, rp_sock_read_cb, rp_sock_write_cb, rp_sock_error_cb, rc);
|
||||
if (!rc->read_id) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: uasync_add_socket_t failed"); rp_conn_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
if (!rc->read_id) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: uasync_add_socket_t failed"); u_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
|
||||
struct sockaddr_in addr; memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET; memcpy(&addr.sin_addr.s_addr, dest_ip, 4); addr.sin_port = dest_port;
|
||||
rc->connect_called = 1;
|
||||
int ret = connect(rc->sock, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (ret < 0 && errno != EINPROGRESS) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: connect() failed: %s", strerror(errno));
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: connect() to %d.%d.%d.%d:%d failed: %s",
|
||||
dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], ntohs(dest_port), strerror(errno));
|
||||
rp_send_connected(inst, src_node_id, stream_id, 0, TCP_PROXY_CONNECTED_REFUSED);
|
||||
rp_conn_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
||||
uasync_remove_socket_t(rc->ua, rc->sock); socket_close_wrapper(rc->sock); u_free(rc);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
||||
}
|
||||
|
||||
rc->next = ctx->conns; ctx->conns = rc;
|
||||
@@ -204,90 +196,86 @@ int remote_proxy_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry* ent
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remote_proxy_handle_data(struct UTUN_INSTANCE* inst, struct ll_entry* entry, uint64_t stream_id) {
|
||||
int remote_proxy_handle_data(struct UTUN_INSTANCE* inst, struct ll_entry* entry, uint32_t stream_id) {
|
||||
if (!inst) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
struct remote_proxy_ctx* ctx = &inst->remote_proxy;
|
||||
struct remote_proxy_conn* rc = remote_proxy_find_conn(ctx, stream_id);
|
||||
if (!rc || rc->sock == SOCKET_INVALID || rc->connected != 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "RP handle_data drop: rc=%p stream=%016llx sock=%d connected=%d",
|
||||
(void*)rc, (unsigned long long)stream_id, rc ? (int)rc->sock : -1, rc ? rc->connected : -1);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
||||
}
|
||||
uint16_t seq; memcpy(&seq, entry->dgram + 10, 2);
|
||||
if (!rc->recv_seq_init) {
|
||||
rc->recv_last_seq = seq; rc->recv_seq_init = 1;
|
||||
if (!rc || rc->sock == SOCKET_INVALID || rc->connected != 1) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "RP handle_data drop: no active conn for sid=%08x", stream_id); queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
if (rc->error) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
|
||||
uint16_t seq; memcpy(&seq, entry->dgram + 6, 2);
|
||||
if (!rc->recv_init) {
|
||||
rc->recv_last_seq = seq; rc->recv_init = 1;
|
||||
} else {
|
||||
int16_t delta = (int16_t)(seq - rc->recv_last_seq);
|
||||
if (delta <= 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "remote_proxy: duplicate DATA seq=%u stream=%016llx, discard", seq, (unsigned long long)stream_id);
|
||||
uint16_t delta = seq - rc->recv_last_seq;
|
||||
if (delta == 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "remote_proxy: duplicate DATA seq=%u sid=%08x", seq, stream_id);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return 0;
|
||||
}
|
||||
if (delta > 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: seq gap seq=%u last=%u stream=%016llx, tearing down", seq, rc->recv_last_seq, (unsigned long long)stream_id);
|
||||
rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, 0, NULL, 0);
|
||||
if (delta != 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: seq gap seq=%u last=%u sid=%08x", seq, rc->recv_last_seq, stream_id);
|
||||
rc->error = 1;
|
||||
rp_send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_ERROR, rc->stream_id, 0, NULL, 0);
|
||||
rp_conn_free(rc);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
||||
}
|
||||
rc->recv_last_seq = seq;
|
||||
}
|
||||
size_t data_len = entry->len - TCP_PROXY_HDR_SIZE;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:SEND fd=%d stream=%016llx len=%zu total=%d", (int)rc->sock, (unsigned long long)stream_id, data_len, rp_conn_total(rc));
|
||||
uint8_t* data = entry->dgram + TCP_PROXY_HDR_SIZE;
|
||||
ssize_t n = send(rc->sock, data, data_len, MSG_NOSIGNAL);
|
||||
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: send error %s", strerror(errno));
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:SEND fd=%d sid=%08x len=%zu total=%d",
|
||||
(int)rc->sock, stream_id, data_len, rp_conn_total(rc));
|
||||
if (data_len > 0) {
|
||||
uint8_t* data = entry->dgram + TCP_PROXY_HDR_SIZE;
|
||||
ssize_t n = send(rc->sock, data, data_len, MSG_NOSIGNAL);
|
||||
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "remote_proxy: send error %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp_close_timer_cb(void* arg) {
|
||||
struct remote_proxy_conn* rc = (struct remote_proxy_conn*)arg;
|
||||
if (!rc || rc->connected == -1) return;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:TIMER stream=%016llx total=%d", (unsigned long long)rc->stream_id, rp_conn_total(rc));
|
||||
rp_conn_free(rc);
|
||||
}
|
||||
|
||||
void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint64_t stream_id) {
|
||||
void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint32_t stream_id) {
|
||||
if (!inst) return;
|
||||
struct remote_proxy_ctx* ctx = &inst->remote_proxy;
|
||||
struct remote_proxy_conn** prev = &ctx->conns;
|
||||
while (*prev) {
|
||||
struct remote_proxy_conn* rc = *prev;
|
||||
if (rc->stream_id == stream_id) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:CLOSE fd=%d stream=%016llx total=%d", (int)rc->sock, (unsigned long long)stream_id, rp_conn_total(rc));
|
||||
*prev = rc->next;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCK:CLOSE_RECV fd=%d sid=%08x total=%d sock_closed=%d connected=%d",
|
||||
(int)rc->sock, stream_id, rp_conn_total(rc), rc->sock_closed, rc->connected);
|
||||
rc->cli_closed = 1;
|
||||
if (rc->sock != SOCKET_INVALID && rc->connected == 1) shutdown(rc->sock, SHUT_WR);
|
||||
if (rc->read_id) { uasync_remove_socket_t(rc->ua, rc->sock); rc->read_id = NULL; }
|
||||
uasync_set_timeout(rc->ua, 20000, rc, rp_close_timer_cb, "rp_close");
|
||||
if (rc->sock_closed) rp_conn_free(rc);
|
||||
return;
|
||||
}
|
||||
prev = &rc->next;
|
||||
}
|
||||
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "remote_proxy: CLOSE sid=%08x — no conn", stream_id);
|
||||
}
|
||||
|
||||
int remote_proxy_init(struct UTUN_INSTANCE* inst) {
|
||||
if (!inst) return -1;
|
||||
struct remote_proxy_ctx* ctx = &inst->remote_proxy;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->enabled = inst->config && inst->config->global.remote_proxy_enabled;
|
||||
if (!inst->config) return 0;
|
||||
ctx->enabled = inst->config->global.remote_proxy_enabled;
|
||||
ctx->inst = inst;
|
||||
if (!ctx->enabled) return 0;
|
||||
g_rp_ctx = ctx;
|
||||
// Register standalone handler for when tcp_proxy is not using remote mappings
|
||||
// (tcp_proxy_create will overwrite this handler if it has remote mappings)
|
||||
etcp_router_bind(inst, ETCP_ID_TCP_PROXY, rp_standalone_recv_cb);
|
||||
if (!inst->config || !inst->config->global.tcp_proxy_enabled) {
|
||||
etcp_router_bind(inst, ETCP_ID_TCP_PROXY, tcp_proxy_etcp_recv_cb);
|
||||
if (!inst->config->global.tcp_proxy_enabled) {
|
||||
udp_proxy_init(inst, inst->ua);
|
||||
icmp_proxy_init(inst, inst->ua);
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "remote_proxy initialized on node %016llx", (unsigned long long)inst->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "remote_proxy initialized node=%016llx", (unsigned long long)inst->node_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void remote_proxy_destroy(struct UTUN_INSTANCE* inst) {
|
||||
if (!inst) return;
|
||||
struct remote_proxy_ctx* ctx = &inst->remote_proxy;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "remote_proxy destroying: conn_count=%d", ctx->conn_count);
|
||||
struct remote_proxy_conn* rc = ctx->conns;
|
||||
while (rc) { struct remote_proxy_conn* next = rc->next; rp_conn_free(rc); rc = next; }
|
||||
ctx->conns = NULL; ctx->enabled = 0;
|
||||
|
||||
+19
-15
@@ -1,5 +1,4 @@
|
||||
// remote_proxy.h — Удаленный TCP прокси (exit node)
|
||||
// Создаёт OS сокеты к адресатам по запросам от других нод через etcp_router
|
||||
#ifndef REMOTE_PROXY_H
|
||||
#define REMOTE_PROXY_H
|
||||
|
||||
@@ -12,34 +11,38 @@ struct ll_entry;
|
||||
struct ETCP_CONN;
|
||||
struct remote_proxy_ctx;
|
||||
|
||||
// Sub-commands for ETCP_ID_TCP_PROXY protocol
|
||||
#define TCP_PROXY_SUBCMD_CONNECT 0x01
|
||||
#define TCP_PROXY_SUBCMD_CONNECTED 0x02
|
||||
#define TCP_PROXY_SUBCMD_DATA 0x03
|
||||
#define TCP_PROXY_SUBCMD_CLOSE 0x04
|
||||
#define TCP_PROXY_SUBCMD_ERROR 0x05
|
||||
|
||||
#define TCP_PROXY_CONNECTED_OK 0
|
||||
#define TCP_PROXY_CONNECTED_REFUSED 1
|
||||
|
||||
#define TCP_PROXY_HDR_SIZE 12 // svc_id(1)+subcmd(1)+stream_id(8)+seq(2)
|
||||
#define TCP_PROXY_CONNECT_HDR_SIZE 18 // HDR_SIZE + dest_ip(4)+dest_port(2)
|
||||
#define TCP_PROXY_CONNECTED_HDR_SIZE 15 // HDR_SIZE + local_port(2)+status(1)
|
||||
#define TCP_PROXY_HDR_SIZE 8 // svc_id(1)+subcmd(1)+stream_id(4)+seq(2)
|
||||
#define TCP_PROXY_CONNECT_HDR_SIZE 14 // HDR_SIZE + dest_ip(4)+dest_port(2)
|
||||
#define TCP_PROXY_CONNECTED_HDR_SIZE 11 // HDR_SIZE + local_port(2)+status(1)
|
||||
|
||||
struct remote_proxy_conn {
|
||||
struct remote_proxy_conn* next;
|
||||
struct remote_proxy_ctx* ctx;
|
||||
uint64_t stream_id;
|
||||
struct remote_proxy_ctx* ctx;
|
||||
uint32_t stream_id;
|
||||
uint64_t peer_node_id;
|
||||
socket_t sock;
|
||||
void* read_id;
|
||||
struct UASYNC* ua;
|
||||
int connected;
|
||||
int connect_called;
|
||||
uint8_t dest_ip[4];
|
||||
uint16_t dest_port;
|
||||
uint16_t send_seq;
|
||||
|
||||
uint16_t send_seq; // 16-bit circular
|
||||
uint16_t recv_last_seq;
|
||||
uint8_t recv_seq_init;
|
||||
uint8_t recv_init;
|
||||
|
||||
uint8_t cli_closed; // client sent CLOSE
|
||||
uint8_t sock_closed; // socket EOF received
|
||||
uint8_t error;
|
||||
uint8_t connected; // connect() completed successfully
|
||||
};
|
||||
|
||||
struct remote_proxy_ctx {
|
||||
@@ -52,11 +55,12 @@ struct remote_proxy_ctx {
|
||||
int remote_proxy_init(struct UTUN_INSTANCE* inst);
|
||||
void remote_proxy_destroy(struct UTUN_INSTANCE* inst);
|
||||
|
||||
struct remote_proxy_conn* remote_proxy_find_conn(struct remote_proxy_ctx* ctx, uint64_t stream_id);
|
||||
struct remote_proxy_conn* remote_proxy_find_conn(struct remote_proxy_ctx* ctx, uint32_t stream_id);
|
||||
void rp_conn_free(struct remote_proxy_conn* rc);
|
||||
|
||||
int remote_proxy_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry* entry,
|
||||
uint64_t stream_id, uint64_t src_node_id);
|
||||
int remote_proxy_handle_data(struct UTUN_INSTANCE* inst, struct ll_entry* entry, uint64_t stream_id);
|
||||
void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint64_t stream_id);
|
||||
uint32_t stream_id, uint64_t src_node_id);
|
||||
int remote_proxy_handle_data(struct UTUN_INSTANCE* inst, struct ll_entry* entry, uint32_t stream_id);
|
||||
void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint32_t stream_id);
|
||||
|
||||
#endif
|
||||
+257
-608
File diff suppressed because it is too large.
Load diff
+36
-76
@@ -1,6 +1,4 @@
|
||||
// tcp_proxy.h — TCP proxy: lwIP TCP stack ↔ ll_queue ↔ transport → destination
|
||||
// Modes: TUN (use_tun=1) or raw-fd (use_tun=0, socketpair etc.)
|
||||
// Supports port forwarding + EIM NAT + half-close + active connections + remote proxy
|
||||
// tcp_proxy.h — TCP proxy: lwIP TCP stack → ETCP → remote exit node
|
||||
#ifndef TCP_PROXY_H
|
||||
#define TCP_PROXY_H
|
||||
|
||||
@@ -19,97 +17,59 @@ struct tcp_proxy_mapping_config;
|
||||
struct remote_proxy_ctx;
|
||||
struct lwip_tcp_ctx;
|
||||
|
||||
// Transport abstraction (local OS socket or remote via ETCP)
|
||||
struct tcp_proxy_transport;
|
||||
struct tcp_proxy_transport_ops {
|
||||
int (*send)(struct tcp_proxy_transport* t, const uint8_t* data, size_t len);
|
||||
void (*close)(struct tcp_proxy_transport* t);
|
||||
void (*destroy)(struct tcp_proxy_transport* t);
|
||||
};
|
||||
struct tcp_proxy_transport {
|
||||
struct tcp_proxy_transport_ops* ops;
|
||||
};
|
||||
|
||||
// Port mapping (static from config or dynamic from EIM NAT)
|
||||
struct tcp_proxy_mapping {
|
||||
struct tcp_proxy_mapping* next;
|
||||
uint16_t local_port;
|
||||
uint8_t remote_ip[4];
|
||||
uint16_t remote_port;
|
||||
int dynamic;
|
||||
uint64_t created_tb;
|
||||
uint64_t delete_at_tb;
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
struct tcp_pcb;
|
||||
struct tcp_pcb_listen;
|
||||
|
||||
// One proxy connection: TCP PCB ↔ ll_queues ↔ transport ↔ destination
|
||||
struct proxy_conn {
|
||||
struct proxy_conn* next;
|
||||
struct tcp_proxy* proxy;
|
||||
struct tcp_pcb* pcb;
|
||||
struct tcp_pcb_listen* listen_pcb; // for listening connection tracking
|
||||
struct tcp_proxy_transport* transport;
|
||||
struct ll_queue* uip_to_transport; // data: TCP → transport or remote→test (active)
|
||||
struct ll_queue* transport_to_uip; // data: transport → TCP or test→remote (active)
|
||||
uint8_t dest_ip[4]; // proxy target IP (where to forward OS socket)
|
||||
uint32_t tun_ip; // TUN IP (what client connected to, for uip_hostaddr)
|
||||
uint16_t dest_port;
|
||||
int closing_tun; // 1 = TUN/lwIP side sent FIN (waiting for remote)
|
||||
int closing_rem; // 1 = remote/transport closed (waiting for TUN)
|
||||
int closing_sent; // 1 = CLOSE sent to exit via transport->close()
|
||||
int active; // 1 = outgoing connection
|
||||
struct tcp_proxy_mapping* eim_mapping;
|
||||
uint64_t remote_stream_id; // stream ID for remote proxy (0=local)
|
||||
void* uip_retry_timer; // timer for backpressure retry
|
||||
struct tcp_proxy* proxy;
|
||||
struct tcp_pcb* pcb;
|
||||
|
||||
uint32_t stream_id;
|
||||
uint16_t send_seq; // 16-bit circular, only for DATA
|
||||
uint16_t recv_last_seq; // last received seq for gap detection
|
||||
uint8_t recv_init; // first DATA received
|
||||
|
||||
struct ll_queue* to_lwip; // DATA from exit → lwIP (flow control)
|
||||
uint8_t* send_buf; // lwIP→exit data until CONNECTED
|
||||
uint16_t send_len;
|
||||
|
||||
uint8_t tun_closed; // lwIP side sent FIN
|
||||
uint8_t rem_closed; // exit sent CLOSE
|
||||
uint8_t error; // error condition, cleanup immediately
|
||||
uint8_t close_sent; // we sent CLOSE/ERROR to exit
|
||||
uint8_t connected; // CONNECTED(OK) received from exit
|
||||
|
||||
uint8_t dest_ip[4];
|
||||
uint16_t dest_port;
|
||||
};
|
||||
|
||||
// Main TCP proxy module
|
||||
struct tcp_proxy {
|
||||
struct UTUN_INSTANCE* inst;
|
||||
struct UASYNC* ua;
|
||||
struct tun_if* tun; // TUN interface (NULL in raw-fd mode)
|
||||
int ip_fd; // raw IP fd (only when tun==NULL)
|
||||
void* ip_fd_id; // uasync socket id for ip_fd
|
||||
struct tun_if* tun;
|
||||
int ip_fd;
|
||||
void* ip_fd_id;
|
||||
struct proxy_conn* conns;
|
||||
int conn_count;
|
||||
struct memory_pool* entry_pool;
|
||||
struct tcp_proxy_mapping* mappings;
|
||||
int eim_timeout_tb;
|
||||
uint64_t next_stream_id; // counter for remote proxy stream IDs
|
||||
uint64_t via_node_id; // узел через который проксируются все forward (0=локально)
|
||||
int has_remote_mappings; // 1=via_node_id задан и не равен local node_id
|
||||
struct lwip_tcp_ctx* lwip; // lwIP TCP stack context
|
||||
uint32_t tun_ip_addr; // TUN IP (network byte order) for reply packets
|
||||
int ip_fd_mode; // 1=raw fd input, 0=TUN input
|
||||
// Framed read: для raw-fd mode, где поток байт не сохраняет границы пакетов
|
||||
uint8_t raw_buf[2002]; // 2-byte len + max IP packet (MTU=1500 + 2B prefix)
|
||||
size_t raw_pos; // сколько байт уже получено в текущем кадре
|
||||
uint16_t raw_need; // сколько ещё байт ждать (0=ждём 2-байтный заголовок)
|
||||
uint32_t next_stream_id;
|
||||
uint64_t via_node_id;
|
||||
struct lwip_tcp_ctx* lwip;
|
||||
int ip_fd_mode;
|
||||
|
||||
struct tcp_proxy_mapping_config* mappings; // pointer to config
|
||||
int mapping_count;
|
||||
|
||||
uint8_t raw_buf[2002];
|
||||
size_t raw_pos;
|
||||
uint16_t raw_need;
|
||||
};
|
||||
|
||||
// ========== API ==========
|
||||
|
||||
// Create TCP proxy
|
||||
// use_tun=1: TUN mode (needs root), uses tun_name/tun_ip/mtu/test_mode, ip_fd ignored
|
||||
// use_tun=0: raw-fd mode, uses ip_fd for IP packet I/O, TUN params ignored
|
||||
struct tcp_proxy* tcp_proxy_create(struct UTUN_INSTANCE* inst, struct UASYNC* ua,
|
||||
const char* tun_name, const char* tun_ip, int mtu, int test_mode,
|
||||
struct tcp_proxy_mapping_config* mappings, int mapping_count,
|
||||
int eim_timeout_sec, int use_tun, int ip_fd, uint64_t via_node_id);
|
||||
|
||||
int use_tun, int ip_fd, uint64_t via_node_id);
|
||||
void tcp_proxy_destroy(struct tcp_proxy* p);
|
||||
|
||||
// Active (outgoing) connections — for test client or EIM NAT
|
||||
struct proxy_conn* tcp_proxy_active_open (struct tcp_proxy* p, const char* dest_ip, uint16_t dest_port);
|
||||
int tcp_proxy_active_send (struct tcp_proxy* p, struct proxy_conn* pc, const uint8_t* data, size_t len);
|
||||
ssize_t tcp_proxy_active_recv (struct tcp_proxy* p, struct proxy_conn* pc, uint8_t* buf, size_t len);
|
||||
int tcp_proxy_active_close(struct tcp_proxy* p, struct proxy_conn* pc);
|
||||
int tcp_proxy_active_send_done(struct tcp_proxy* p, struct proxy_conn* pc); // 1=all queued data sent
|
||||
|
||||
// etcp_router handler for incoming proxy messages (called from etcp_router dispatch)
|
||||
void tcp_proxy_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
#endif // TCP_PROXY_H
|
||||
+1
-1
@@ -158,7 +158,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
int mtu = config->global.tcp_proxy_mtu > 0 ? config->global.tcp_proxy_mtu : 1500;
|
||||
instance->tcp_proxy = tcp_proxy_create(instance, ua, tun_name, tun_ip, mtu, g_tun_init_enabled ? 0 : 1,
|
||||
config->global.tcp_proxy_mappings, config->global.tcp_proxy_mapping_count,
|
||||
config->global.tcp_proxy_eim_timeout, 1, -1, config->global.tcp_proxy_via_node_id);
|
||||
1, -1, config->global.tcp_proxy_via_node_id);
|
||||
if (instance->tcp_proxy) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TCP proxy enabled: TUN=%s IP=%s MTU=%d mappings=%d",
|
||||
tun_name, tun_ip, mtu, config->global.tcp_proxy_mapping_count);
|
||||
|
||||
Reference in new issue
Block a user