Browse Source

refactor: split socket meta 'type' into config_type and nat_type — separate config (PUBLIC/NAT/PRIVATE) from detected NAT (EIM/STRICT/DIRECT) across NODEINFO, conn_mgr, route_bgp, route_node, etcpmon; win32 compat fixes (memmem, SHUT_WR, tun test_mode, tcp_proxy guards)

chatgui
Evgeny 3 months ago
parent
commit
389ef00da6
  1. 2
      .gitignore
  2. 12
      lib/platform_compat.h
  3. 5
      lib/tcp_io.c
  4. 22
      src/conn_mgr.c
  5. 1
      src/control_server.c
  6. 2
      src/etcp_connections.c
  7. 4
      src/route_bgp.c
  8. 14
      src/route_node.c
  9. 6
      src/route_node.h
  10. 14
      src/tun_if.c
  11. 6
      src/utun_instance.c
  12. 6
      tests/test_ipv6_sockets.c
  13. 14
      tests/test_nat_detection.c
  14. 27
      tools/etcpmon/etcpmon_gui.c
  15. 10
      tools/etcpmon/etcpmon_protocol.h

2
.gitignore vendored

@ -1,5 +1,7 @@
# Build directory (out-of-tree build) # Build directory (out-of-tree build)
/build/ /build/
build-win/
cross-build-win.sh
tools/chatgui/build/ tools/chatgui/build/
# Build outputs # Build outputs

12
lib/platform_compat.h

@ -31,6 +31,18 @@
#define strcasecmp _stricmp #define strcasecmp _stricmp
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
// memmem — not available on Windows
#define memmem compat_memmem
static inline void* compat_memmem(const void* h, size_t hl, const void* n, size_t nl) {
if (nl == 0) return (void*)h;
if (hl < nl) return NULL;
const unsigned char* hay = (const unsigned char*)h;
const unsigned char* ndl = (const unsigned char*)n;
for (size_t i = 0; i <= hl - nl; i++)
if (hay[i] == ndl[0] && memcmp(hay + i, ndl, nl) == 0) return (void*)(hay + i);
return NULL;
}
// poll() and pollfd are already defined in winsock2.h on MSYS2 UCRT64 // poll() and pollfd are already defined in winsock2.h on MSYS2 UCRT64
// Only define if not already present // Only define if not already present
#ifndef POLLIN #ifndef POLLIN

5
lib/tcp_io.c

@ -13,6 +13,9 @@
#ifndef MSG_NOSIGNAL #ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0 #define MSG_NOSIGNAL 0
#endif #endif
#ifdef _WIN32
#define SHUT_WR SD_SEND
#endif
static void read_cb(socket_t sock, void* arg); static void read_cb(socket_t sock, void* arg);
static void write_cb(socket_t sock, void* arg); static void write_cb(socket_t sock, void* arg);
@ -382,7 +385,7 @@ static void write_cb(socket_t sock, void* arg) {
if (!tc->connected) { if (!tc->connected) {
int err = 0; int err = 0;
socklen_t len = sizeof(err); socklen_t len = sizeof(err);
if (getsockopt(tc->sock, SOL_SOCKET, SO_ERROR, &err, &len) == 0 && err == 0) { if (getsockopt(tc->sock, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 0 && err == 0) {
tc->connected = 1; tc->connected = 1;
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "tcp_io: connect ok fd=%d", (int)tc->sock); DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "tcp_io: connect ok fd=%d", (int)tc->sock);
} else { } else {

22
src/conn_mgr.c

@ -31,7 +31,7 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry);
static void cm_idle_timer_cb(void* arg); static void cm_idle_timer_cb(void* arg);
static void cm_deliver_result(struct CONN_MGR_ENTRY* entry, int result); static void cm_deliver_result(struct CONN_MGR_ENTRY* entry, int result);
static void cm_bg_ping_timer_cb(void* arg); static void cm_bg_ping_timer_cb(void* arg);
static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_meta_type); static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_config_type, uint8_t target_nat_type);
static uint16_t cm_get_node_min_rtt(struct NODEINFO_Q* nq); static uint16_t cm_get_node_min_rtt(struct NODEINFO_Q* nq);
static int cm_has_direct_ip(struct NODEINFO_Q* nq); static int cm_has_direct_ip(struct NODEINFO_Q* nq);
static int cm_has_local_addr(struct NODEINFO_Q* nq); static int cm_has_local_addr(struct NODEINFO_Q* nq);
@ -333,14 +333,12 @@ static void cm_idle_timer_cb(void* arg) {
entry->idle_timer = uasync_set_timeout(mgr->instance->ua, CONN_MGR_IDLE_CHECK_INTERVAL_TB, entry, cm_idle_timer_cb, "conn_mgr_idle"); entry->idle_timer = uasync_set_timeout(mgr->instance->ua, CONN_MGR_IDLE_CHECK_INTERVAL_TB, entry, cm_idle_timer_cb, "conn_mgr_idle");
} }
static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_meta_type) { static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_config_type, uint8_t target_nat_type) {
uint8_t tt = target_meta_type; uint8_t tt = target_nat_type >= NAT_VERIFIED_UNKNOWN ? CFG_SERVER_TYPE_PUBLIC : target_config_type;
if (tt == NAT_VERIFIED_DIRECT) tt = CFG_SERVER_TYPE_PUBLIC;
else if (tt >= NAT_VERIFIED_UNKNOWN) tt = CFG_SERVER_TYPE_PUBLIC;
uint8_t ot = our->type; uint8_t ot = our->type;
if (ot == CFG_SERVER_TYPE_PUBLIC) return 1; if (ot == CFG_SERVER_TYPE_PUBLIC) return 1;
if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_TYPE_EIM && tt == CFG_SERVER_TYPE_PUBLIC) return 1; if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_VERIFIED_EIM && tt == CFG_SERVER_TYPE_PUBLIC) return 1;
if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_TYPE_EIM && tt == CFG_SERVER_TYPE_NAT) return 1; if (ot == CFG_SERVER_TYPE_NAT && our->nat_type == NAT_VERIFIED_EIM && tt == CFG_SERVER_TYPE_NAT) return 1;
if (ot == CFG_SERVER_TYPE_PRIVATE && tt == CFG_SERVER_TYPE_PRIVATE) return 2; if (ot == CFG_SERVER_TYPE_PRIVATE && tt == CFG_SERVER_TYPE_PRIVATE) return 2;
return 0; return 0;
} }
@ -378,7 +376,7 @@ static int cm_has_direct_ip(struct NODEINFO_Q* nq) {
if (addrs[i].type == ADDR_TYPE_REAL || addrs[i].type == ADDR_TYPE_NAT) { if (addrs[i].type == ADDR_TYPE_REAL || addrs[i].type == ADDR_TYPE_NAT) {
for (int j = 0; j < meta_count; j++) { for (int j = 0; j < meta_count; j++) {
if (metas[j].id == addrs[i].socket_id && if (metas[j].id == addrs[i].socket_id &&
(metas[j].type == CFG_SERVER_TYPE_PUBLIC || metas[j].type == NAT_VERIFIED_EIM || metas[j].type == NAT_VERIFIED_DIRECT)) (metas[j].config_type == CFG_SERVER_TYPE_PUBLIC || metas[j].nat_type == NAT_VERIFIED_EIM || metas[j].nat_type == NAT_VERIFIED_DIRECT))
return 1; return 1;
} }
} }
@ -395,7 +393,7 @@ static int cm_has_local_addr(struct NODEINFO_Q* nq) {
for (int i = 0; i < addr_count; i++) { for (int i = 0; i < addr_count; i++) {
if (addrs[i].type == ADDR_TYPE_INTERFACE) { if (addrs[i].type == ADDR_TYPE_INTERFACE) {
for (int j = 0; j < meta_count; j++) { for (int j = 0; j < meta_count; j++) {
if (metas[j].id == addrs[i].socket_id && metas[j].type == CFG_SERVER_TYPE_PRIVATE) if (metas[j].id == addrs[i].socket_id && metas[j].config_type == CFG_SERVER_TYPE_PRIVATE)
return 1; return 1;
} }
} }
@ -426,7 +424,7 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
for (int i = 0; i < addr_count; i++) { for (int i = 0; i < addr_count; i++) {
if (addrs[i].type != ADDR_TYPE_INTERFACE) continue; if (addrs[i].type != ADDR_TYPE_INTERFACE) continue;
for (int j = 0; j < meta_count; j++) { for (int j = 0; j < meta_count; j++) {
if (metas[j].id != addrs[i].socket_id || metas[j].type != CFG_SERVER_TYPE_PRIVATE) continue; if (metas[j].id != addrs[i].socket_id || metas[j].config_type != CFG_SERVER_TYPE_PRIVATE) continue;
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { while (s) {
if (s->type == CFG_SERVER_TYPE_PRIVATE && s->local_addr.ss_family == AF_INET) { if (s->type == CFG_SERVER_TYPE_PRIVATE && s->local_addr.ss_family == AF_INET) {
@ -475,7 +473,7 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
if (metas[j].id != addrs[i].socket_id) continue; if (metas[j].id != addrs[i].socket_id) continue;
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { while (s) {
int compat = cm_nat_compatible(s, metas[j].type); int compat = cm_nat_compatible(s, metas[j].config_type, metas[j].nat_type);
if (compat && s->local_addr.ss_family == AF_INET) { if (compat && s->local_addr.ss_family == AF_INET) {
struct sockaddr_in sin; struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
@ -591,7 +589,7 @@ static void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) {
if (addrs[i].type != ADDR_TYPE_REAL && addrs[i].type != ADDR_TYPE_NAT) continue; if (addrs[i].type != ADDR_TYPE_REAL && addrs[i].type != ADDR_TYPE_NAT) continue;
for (int j = 0; j < meta_count; j++) { for (int j = 0; j < meta_count; j++) {
if (metas[j].id == addrs[i].socket_id && if (metas[j].id == addrs[i].socket_id &&
(metas[j].type == CFG_SERVER_TYPE_PUBLIC || metas[j].type == NAT_VERIFIED_EIM || metas[j].type == NAT_VERIFIED_DIRECT)) { (metas[j].config_type == CFG_SERVER_TYPE_PUBLIC || metas[j].nat_type == NAT_VERIFIED_EIM || metas[j].nat_type == NAT_VERIFIED_DIRECT)) {
out_addrs[direct_count].type = addrs[i].type; out_addrs[direct_count].type = addrs[i].type;
memcpy(out_addrs[direct_count].ip, addrs[i].addr, 4); memcpy(out_addrs[direct_count].ip, addrs[i].addr, 4);
out_addrs[direct_count].port = htons(addrs[i].port); out_addrs[direct_count].port = htons(addrs[i].port);

1
src/control_server.c

@ -985,6 +985,7 @@ static void send_socket_list(struct control_server* server, struct control_clien
info[i].ip[sizeof(info[i].ip) - 1] = '\0'; info[i].ip[sizeof(info[i].ip) - 1] = '\0';
info[i].port = 0; info[i].port = 0;
} }
info[i].config_type = sock->type;
info[i].nat_type = sock->nat_type; info[i].nat_type = sock->nat_type;
/* NAT address from socket (set when INIT_RESPONSE received) */ /* NAT address from socket (set when INIT_RESPONSE received) */

2
src/etcp_connections.c

@ -699,7 +699,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S
e_sock->pkt_format_errors = 0; e_sock->pkt_format_errors = 0;
e_sock->type = type; e_sock->type = type;
e_sock->sock_id = instance->next_socket_id++; e_sock->sock_id = instance->next_socket_id++;
e_sock->nat_type = type; // initial type from config, updated after NAT detection e_sock->nat_type = NAT_TYPE_UNKNOWN; // только результат детекции NAT, серверные сокеты стартуют с unknown
e_sock->mtu = mtu; e_sock->mtu = mtu;
e_sock->only_local = only_local; e_sock->only_local = only_local;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Add Socket type=%d", type); DEBUG_INFO(DEBUG_CATEGORY_BGP, "Add Socket type=%d", type);

4
src/route_bgp.c

@ -1023,8 +1023,8 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f
int data_changed = 0; int data_changed = 0;
for (int i = 0; i < bgp->local_node->node.local_v4_sockets; i++) { for (int i = 0; i < bgp->local_node->node.local_v4_sockets; i++) {
if (meta[i].id == socket_id) { if (meta[i].id == socket_id) {
if (meta[i].type != verified_type) { if (meta[i].nat_type != verified_type) {
meta[i].type = verified_type; meta[i].nat_type = verified_type;
data_changed = 1; data_changed = 1;
} }
break; break;

14
src/route_node.c

@ -173,7 +173,7 @@ void route_node_dump_all(struct ROUTE_BGP* bgp) {
const struct NODEINFO_IPV4_SOCKET_META* v4sm; const struct NODEINFO_IPV4_SOCKET_META* v4sm;
int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm);
if (v4sm_cnt > 0) for (int i = 0; i < v4sm_cnt; i++) { if (v4sm_cnt > 0) for (int i = 0; i < v4sm_cnt; i++) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sock[%d]: id=%u type=%u", i, v4sm[i].id, v4sm[i].type); DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sock[%d]: id=%u config=%u nat=%u", i, v4sm[i].id, v4sm[i].config_type, v4sm[i].nat_type);
} }
const struct NODEINFO_IPV4_ADDR* v4a; const struct NODEINFO_IPV4_ADDR* v4a;
@ -190,7 +190,7 @@ void route_node_dump_all(struct ROUTE_BGP* bgp) {
const struct NODEINFO_IPV6_SOCKET_META* v6sm; const struct NODEINFO_IPV6_SOCKET_META* v6sm;
int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm);
if (v6sm_cnt > 0) for (int i = 0; i < v6sm_cnt; i++) { if (v6sm_cnt > 0) for (int i = 0; i < v6sm_cnt; i++) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sock[%d]: id=%u type=%u", i, v6sm[i].id, v6sm[i].type); DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sock[%d]: id=%u config=%u nat=%u", i, v6sm[i].id, v6sm[i].config_type, v6sm[i].nat_type);
} }
const struct NODEINFO_IPV6_ADDR* v6a; const struct NODEINFO_IPV6_ADDR* v6a;
@ -321,7 +321,7 @@ int route_node_format_all(struct ROUTE_BGP* bgp, char* buf, size_t buf_size) {
const struct NODEINFO_IPV4_SOCKET_META* v4sm; const struct NODEINFO_IPV4_SOCKET_META* v4sm;
int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm);
for (int i = 0; i < v4sm_cnt; i++) for (int i = 0; i < v4sm_cnt; i++)
FMT_ADD(" v4sock[%d]: id=%u type=%u\n", i, v4sm[i].id, v4sm[i].type); FMT_ADD(" v4sock[%d]: id=%u config=%u nat=%u\n", i, v4sm[i].id, v4sm[i].config_type, v4sm[i].nat_type);
const struct NODEINFO_IPV4_ADDR* v4a; const struct NODEINFO_IPV4_ADDR* v4a;
int v4a_cnt = get_node_v4_addrs(nq, &v4a); int v4a_cnt = get_node_v4_addrs(nq, &v4a);
@ -336,7 +336,7 @@ int route_node_format_all(struct ROUTE_BGP* bgp, char* buf, size_t buf_size) {
const struct NODEINFO_IPV6_SOCKET_META* v6sm; const struct NODEINFO_IPV6_SOCKET_META* v6sm;
int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm);
for (int i = 0; i < v6sm_cnt; i++) for (int i = 0; i < v6sm_cnt; i++)
FMT_ADD(" v6sock[%d]: id=%u type=%u\n", i, v6sm[i].id, v6sm[i].type); FMT_ADD(" v6sock[%d]: id=%u config=%u nat=%u\n", i, v6sm[i].id, v6sm[i].config_type, v6sm[i].nat_type);
const struct NODEINFO_IPV6_ADDR* v6a; const struct NODEINFO_IPV6_ADDR* v6a;
int v6a_cnt = get_node_v6_addrs(nq, &v6a); int v6a_cnt = get_node_v6_addrs(nq, &v6a);
@ -518,7 +518,8 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG
while (e_sock) { while (e_sock) {
if (e_sock->local_addr.ss_family == AF_INET) { if (e_sock->local_addr.ss_family == AF_INET) {
meta[midx].id = e_sock->sock_id; meta[midx].id = e_sock->sock_id;
meta[midx].type = e_sock->nat_type; meta[midx].config_type = e_sock->type;
meta[midx].nat_type = e_sock->nat_type;
midx++; midx++;
} }
e_sock = e_sock->next; e_sock = e_sock->next;
@ -569,7 +570,8 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG
while (e_sock) { while (e_sock) {
if (e_sock->local_addr.ss_family == AF_INET6) { if (e_sock->local_addr.ss_family == AF_INET6) {
meta6[m6idx].id = e_sock->sock_id; meta6[m6idx].id = e_sock->sock_id;
meta6[m6idx].type = e_sock->nat_type; meta6[m6idx].config_type = e_sock->type;
meta6[m6idx].nat_type = e_sock->nat_type;
m6idx++; m6idx++;
} }
e_sock = e_sock->next; e_sock = e_sock->next;

6
src/route_node.h

@ -91,7 +91,8 @@ struct NODEINFO {
// метаданные одного сокета // метаданные одного сокета
struct NODEINFO_IPV4_SOCKET_META { struct NODEINFO_IPV4_SOCKET_META {
uint8_t id; // unique socket id (0-255) uint8_t id; // unique socket id (0-255)
uint8_t type; // CFG_SERVER_TYPE_*/NAT_VERIFIED_* uint8_t config_type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE
uint8_t nat_type; // NAT_TYPE_* / NAT_VERIFIED_*
} __attribute__((packed)); } __attribute__((packed));
// одна типизированная адресная запись (плоский список) // одна типизированная адресная запись (плоский список)
@ -104,7 +105,8 @@ struct NODEINFO_IPV4_ADDR {
struct NODEINFO_IPV6_SOCKET_META { struct NODEINFO_IPV6_SOCKET_META {
uint8_t id; // unique socket id (0-255) uint8_t id; // unique socket id (0-255)
uint8_t type; // CFG_SERVER_TYPE_*/NAT_VERIFIED_* uint8_t config_type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE
uint8_t nat_type; // NAT_TYPE_* / NAT_VERIFIED_*
} __attribute__((packed)); } __attribute__((packed));
struct NODEINFO_IPV6_ADDR { struct NODEINFO_IPV6_ADDR {

14
src/tun_if.c

@ -11,7 +11,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#ifndef _WIN32
#include <sys/socket.h> #include <sys/socket.h>
#endif
#include "../lib/mem.h" #include "../lib/mem.h"
#ifdef _WIN32 #ifdef _WIN32
@ -151,6 +153,7 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config)
} }
} else { } else {
if (tun->ifname[0] == '\0') strncpy(tun->ifname, "tun_test", sizeof(tun->ifname)-1); if (tun->ifname[0] == '\0') strncpy(tun->ifname, "tun_test", sizeof(tun->ifname)-1);
#ifndef _WIN32
int fds[2]; int fds[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "TUN %s test_mode socketpair failed: %s", tun->ifname, strerror(errno)); DEBUG_ERROR(DEBUG_CATEGORY_TUN, "TUN %s test_mode socketpair failed: %s", tun->ifname, strerror(errno));
@ -159,6 +162,11 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config)
} }
tun->fd = fds[0]; tun->fd = fds[0];
tun->test_fd = fds[1]; tun->test_fd = fds[1];
#else
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "TUN test_mode not supported on Windows");
u_free(tun);
return NULL;
#endif
} }
tun->pool = memory_pool_init(sizeof(struct ll_entry), "tun_pool"); tun->pool = memory_pool_init(sizeof(struct ll_entry), "tun_pool");
@ -244,6 +252,7 @@ struct tun_if* tun_init_nat(struct UASYNC* ua, const char* ifname, const char* i
return NULL; return NULL;
} }
} else { } else {
#ifndef _WIN32
int fds[2]; int fds[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "NAT TUN %s test_mode socketpair failed: %s", tun->ifname, strerror(errno)); DEBUG_ERROR(DEBUG_CATEGORY_TUN, "NAT TUN %s test_mode socketpair failed: %s", tun->ifname, strerror(errno));
@ -252,6 +261,11 @@ struct tun_if* tun_init_nat(struct UASYNC* ua, const char* ifname, const char* i
} }
tun->fd = fds[0]; tun->fd = fds[0];
tun->test_fd = fds[1]; tun->test_fd = fds[1];
#else
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "NAT TUN test_mode not supported on Windows");
u_free(tun);
return NULL;
#endif
} }
tun->pool = memory_pool_init(sizeof(struct ll_entry), "tun_pool"); tun->pool = memory_pool_init(sizeof(struct ll_entry), "tun_pool");

6
src/utun_instance.c

@ -156,11 +156,14 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
// TCP proxy server (exit node, optional) — must be before tcp_proxy_client so // TCP proxy server (exit node, optional) — must be before tcp_proxy_client so
// tcp_proxy_client_create can overwrite the handler if it has remote mappings // tcp_proxy_client_create can overwrite the handler if it has remote mappings
#ifndef _WIN32
if (tcp_proxy_server_init(instance) != 0) { if (tcp_proxy_server_init(instance) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "Failed to initialize tcp_proxy_server (non-fatal)"); DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "Failed to initialize tcp_proxy_server (non-fatal)");
} }
#endif
// TCP proxy client (from [tcp_proxy] config section) // TCP proxy client (from [tcp_proxy] config section)
#ifndef _WIN32
if (config->global.tcp_proxy_client_enabled || config->global.tcp_proxy_client_socks_enabled || config->global.tcp_proxy_client_http_proxy_enabled) { if (config->global.tcp_proxy_client_enabled || config->global.tcp_proxy_client_socks_enabled || config->global.tcp_proxy_client_http_proxy_enabled) {
const char* tun_name = config->global.tcp_proxy_client_tun_name; const char* tun_name = config->global.tcp_proxy_client_tun_name;
const char* tun_ip = config->global.tcp_proxy_client_tun_ip; const char* tun_ip = config->global.tcp_proxy_client_tun_ip;
@ -183,6 +186,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
} else { } else {
instance->tcp_proxy_client = NULL; instance->tcp_proxy_client = NULL;
} }
#endif /* _WIN32 */
return 0; return 0;
} }
@ -362,6 +366,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
} }
// Cleanup TCP proxy client module // Cleanup TCP proxy client module
#ifndef _WIN32
if (instance->tcp_proxy_client) { if (instance->tcp_proxy_client) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Destroying TCP proxy client module"); DEBUG_INFO(DEBUG_CATEGORY_TUN, "Destroying TCP proxy client module");
tcp_proxy_client_destroy(instance->tcp_proxy_client); tcp_proxy_client_destroy(instance->tcp_proxy_client);
@ -370,6 +375,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
// Cleanup TCP proxy server // Cleanup TCP proxy server
tcp_proxy_server_destroy(instance); tcp_proxy_server_destroy(instance);
#endif
// Cleanup routing module (unbinds from etcp_router before etcp_router_destroy) // Cleanup routing module (unbinds from etcp_router before etcp_router_destroy)
routing_destroy(instance); routing_destroy(instance);

6
tests/test_ipv6_sockets.c

@ -171,10 +171,10 @@ static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* in
int mc = get_node_v6_sockets_meta(inst->bgp->local_node, &meta); int mc = get_node_v6_sockets_meta(inst->bgp->local_node, &meta);
if (mc != expect_socks || !meta) { printf("FAIL [%s]: v6 sockets meta retrieval failed\n", name); return 0; } if (mc != expect_socks || !meta) { printf("FAIL [%s]: v6 sockets meta retrieval failed\n", name); return 0; }
for (int i = 0; i < mc; i++) { for (int i = 0; i < mc; i++) {
if (meta[i].type != CFG_SERVER_TYPE_PUBLIC) { if (meta[i].config_type != CFG_SERVER_TYPE_PUBLIC) {
printf("FAIL [%s]: v6 socket meta[%d] type=%d expected=%d\n", name, i, meta[i].type, CFG_SERVER_TYPE_PUBLIC); return 0; printf("FAIL [%s]: v6 socket meta[%d] config_type=%d expected=%d\n", name, i, meta[i].config_type, CFG_SERVER_TYPE_PUBLIC); return 0;
} }
printf("PASS [%s]: v6 socket meta[%d] id=%d type=%d\n", name, i, meta[i].id, meta[i].type); printf("PASS [%s]: v6 socket meta[%d] id=%d config=%d nat=%d\n", name, i, meta[i].id, meta[i].config_type, meta[i].nat_type);
} }
// Verify IPv6 addresses // Verify IPv6 addresses

14
tests/test_nat_detection.c

@ -261,9 +261,9 @@ int main(void) {
// Verify C1 socket has config type before NAT detection // Verify C1 socket has config type before NAT detection
{ {
struct ETCP_SOCKET* s = inst_c1->etcp_sockets; struct ETCP_SOCKET* s = inst_c1->etcp_sockets;
if (!s || s->nat_type != CFG_SERVER_TYPE_NAT) { if (!s || s->type != CFG_SERVER_TYPE_NAT) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C1 socket nat_type=%d, expected CFG_SERVER_TYPE_NAT(%d) before detection", DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C1 socket type=%d, expected CFG_SERVER_TYPE_NAT(%d) before detection",
s ? (int)s->nat_type : -1, CFG_SERVER_TYPE_NAT); s ? (int)s->type : -1, CFG_SERVER_TYPE_NAT);
goto cleanup; goto cleanup;
} }
DEBUG_INFO(DEBUG_CATEGORY_BGP, "C1 socket has config NAT type before detection"); DEBUG_INFO(DEBUG_CATEGORY_BGP, "C1 socket has config NAT type before detection");
@ -367,9 +367,9 @@ int main(void) {
int found = 0; int found = 0;
for (int i = 0; i < meta_count; i++) { for (int i = 0; i < meta_count; i++) {
if (meta[i].id == sock_c1->sock_id) { if (meta[i].id == sock_c1->sock_id) {
if (meta[i].type != NAT_VERIFIED_EIM) { if (meta[i].nat_type != NAT_VERIFIED_EIM) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: type=%u expected=%u", DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: nat_type=%u expected=%u",
meta[i].type, NAT_VERIFIED_EIM); meta[i].nat_type, NAT_VERIFIED_EIM);
goto cleanup; goto cleanup;
} }
found = 1; found = 1;
@ -413,7 +413,7 @@ int main(void) {
const struct NODEINFO_IPV4_SOCKET_META* meta = NULL; const struct NODEINFO_IPV4_SOCKET_META* meta = NULL;
int meta_count = get_node_v4_sockets_meta(node_c1_on_c2, &meta); int meta_count = get_node_v4_sockets_meta(node_c1_on_c2, &meta);
for (int i = 0; i < meta_count; i++) { for (int i = 0; i < meta_count; i++) {
if (meta[i].type == NAT_VERIFIED_EIM) { if (meta[i].nat_type == NAT_VERIFIED_EIM) {
c2_verified_nat = 1; c2_verified_nat = 1;
break; break;
} }

27
tools/etcpmon/etcpmon_gui.c

@ -1530,10 +1530,20 @@ void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
} }
} }
static const char* config_type_to_string(uint8_t config_type) {
switch (config_type) {
case CFG_SERVER_TYPE_PUBLIC: return "PUBLIC";
case CFG_SERVER_TYPE_NAT: return "NAT";
case CFG_SERVER_TYPE_PRIVATE: return "Private";
default: return "Unknown";
}
}
static const char* nat_type_to_string(uint8_t nat_type) { static const char* nat_type_to_string(uint8_t nat_type) {
switch (nat_type) { switch (nat_type) {
case NAT_TYPE_EIM: return "EIM"; case NAT_TYPE_EIM: return "EIM";
case NAT_TYPE_STRICT: return "Strict"; case NAT_TYPE_STRICT: return "Strict";
case NAT_TYPE_DIRECT: return "Direct";
case NAT_VERIFIED_EIM: return "Verified-EIM"; case NAT_VERIFIED_EIM: return "Verified-EIM";
case NAT_VERIFIED_STRICT: return "Verified-Strict"; case NAT_VERIFIED_STRICT: return "Verified-Strict";
case NAT_VERIFIED_DIRECT: return "Verified-Direct"; case NAT_VERIFIED_DIRECT: return "Verified-Direct";
@ -1554,22 +1564,23 @@ void etcpmon_gui_update_socket_list(struct etcpmon_app* app,
if (list[i].name[0] == '\0') continue; if (list[i].name[0] == '\0') continue;
char display[256]; char display[256];
const char* cfg_str = config_type_to_string(list[i].config_type);
const char* nat_str = nat_type_to_string(list[i].nat_type); const char* nat_str = nat_type_to_string(list[i].nat_type);
if (list[i].nat_ip[0] != '\0') { if (list[i].nat_ip[0] != '\0') {
if (list[i].is_ipv6) { if (list[i].is_ipv6) {
snprintf(display, sizeof(display), "[%s]:%d | NAT: %s (%s:%d)", snprintf(display, sizeof(display), "[%s]:%d | Type: %s | NAT: %s (%s:%d)",
list[i].ip, list[i].port, nat_str, list[i].nat_ip, list[i].nat_port); list[i].ip, list[i].port, cfg_str, nat_str, list[i].nat_ip, list[i].nat_port);
} else { } else {
snprintf(display, sizeof(display), "%s:%d | NAT: %s (%s:%d)", snprintf(display, sizeof(display), "%s:%d | Type: %s | NAT: %s (%s:%d)",
list[i].ip, list[i].port, nat_str, list[i].nat_ip, list[i].nat_port); list[i].ip, list[i].port, cfg_str, nat_str, list[i].nat_ip, list[i].nat_port);
} }
} else { } else {
if (list[i].is_ipv6) { if (list[i].is_ipv6) {
snprintf(display, sizeof(display), "[%s]:%d | NAT: %s", snprintf(display, sizeof(display), "[%s]:%d | Type: %s | NAT: %s",
list[i].ip, list[i].port, nat_str); list[i].ip, list[i].port, cfg_str, nat_str);
} else { } else {
snprintf(display, sizeof(display), "%s:%d | NAT: %s", snprintf(display, sizeof(display), "%s:%d | Type: %s | NAT: %s",
list[i].ip, list[i].port, nat_str); list[i].ip, list[i].port, cfg_str, nat_str);
} }
} }
SendMessageA(app->hListSockets, LB_ADDSTRING, 0, (LPARAM)display); SendMessageA(app->hListSockets, LB_ADDSTRING, 0, (LPARAM)display);

10
tools/etcpmon/etcpmon_protocol.h

@ -27,10 +27,17 @@ extern "C" {
#define NAT_TYPE_UNKNOWN 0 #define NAT_TYPE_UNKNOWN 0
#define NAT_TYPE_EIM 1 /* Endpoint-Independent Mapping */ #define NAT_TYPE_EIM 1 /* Endpoint-Independent Mapping */
#define NAT_TYPE_STRICT 2 /* Address/Restricted or Symmetric */ #define NAT_TYPE_STRICT 2 /* Address/Restricted or Symmetric */
#define NAT_TYPE_DIRECT 3 /* Real public IP */
#define NAT_VERIFIED_UNKNOWN 4 #define NAT_VERIFIED_UNKNOWN 4
#define NAT_VERIFIED_EIM 5 /* EIM NAT */ #define NAT_VERIFIED_EIM 5 /* EIM NAT */
#define NAT_VERIFIED_STRICT 6 /* strict NAT */ #define NAT_VERIFIED_STRICT 6 /* strict NAT */
#define NAT_VERIFIED_DIRECT 7 #define NAT_VERIFIED_DIRECT 7
/* Server config types (mirrored from config_parser.h) */
#define CFG_SERVER_TYPE_UNKNOWN 0
#define CFG_SERVER_TYPE_PUBLIC 1
#define CFG_SERVER_TYPE_NAT 2
#define CFG_SERVER_TYPE_PRIVATE 3
#define ETCPMON_MAX_MSG_SIZE 32768 #define ETCPMON_MAX_MSG_SIZE 32768
#define ETCPMON_MAX_CONN_NAME 32 #define ETCPMON_MAX_CONN_NAME 32
#define ETCPMON_MAX_CONNECTIONS 250 #define ETCPMON_MAX_CONNECTIONS 250
@ -126,7 +133,8 @@ struct etcpmon_socket_info {
char ip[46]; /* Null-terminated IP address string */ char ip[46]; /* Null-terminated IP address string */
uint16_t port; /* Port number (host byte order) */ uint16_t port; /* Port number (host byte order) */
uint8_t is_ipv6; /* 1 = IPv6, 0 = IPv4 */ uint8_t is_ipv6; /* 1 = IPv6, 0 = IPv4 */
uint8_t nat_type; /* NAT type (NAT_TYPE_*, NAT_VERIFIED_*) */ uint8_t config_type; /* CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE */
uint8_t nat_type; /* NAT_TYPE_* / NAT_VERIFIED_* */
char nat_ip[46]; /* Null-terminated NAT IP address string */ char nat_ip[46]; /* Null-terminated NAT IP address string */
uint16_t nat_port; /* NAT port (host byte order) */ uint16_t nat_port; /* NAT port (host byte order) */
}; };

Loading…
Cancel
Save