From 389ef00da6d2d3596af269bc8b05a54d9282916e Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 2 Jul 2026 18:58:34 +0300 Subject: [PATCH] =?UTF-8?q?refactor:=20split=20socket=20meta=20'type'=20in?= =?UTF-8?q?to=20config=5Ftype=20and=20nat=5Ftype=20=E2=80=94=20separate=20?= =?UTF-8?q?config=20(PUBLIC/NAT/PRIVATE)=20from=20detected=20NAT=20(EIM/ST?= =?UTF-8?q?RICT/DIRECT)=20across=20NODEINFO,=20conn=5Fmgr,=20route=5Fbgp,?= =?UTF-8?q?=20route=5Fnode,=20etcpmon;=20win32=20compat=20fixes=20(memmem,?= =?UTF-8?q?=20SHUT=5FWR,=20tun=20test=5Fmode,=20tcp=5Fproxy=20guards)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ lib/platform_compat.h | 12 ++++++++++++ lib/tcp_io.c | 5 ++++- src/conn_mgr.c | 22 ++++++++++------------ src/control_server.c | 1 + src/etcp_connections.c | 2 +- src/route_bgp.c | 4 ++-- src/route_node.c | 14 ++++++++------ src/route_node.h | 6 ++++-- src/tun_if.c | 14 ++++++++++++++ src/utun_instance.c | 6 ++++++ tests/test_ipv6_sockets.c | 6 +++--- tests/test_nat_detection.c | 14 +++++++------- tools/etcpmon/etcpmon_gui.c | 27 +++++++++++++++++++-------- tools/etcpmon/etcpmon_protocol.h | 10 +++++++++- 15 files changed, 102 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 449a5d13..da8b9cb1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Build directory (out-of-tree build) /build/ +build-win/ +cross-build-win.sh tools/chatgui/build/ # Build outputs diff --git a/lib/platform_compat.h b/lib/platform_compat.h index 7342406a..00c7f277 100644 --- a/lib/platform_compat.h +++ b/lib/platform_compat.h @@ -30,6 +30,18 @@ // POSIX functions missing on Windows #define strcasecmp _stricmp #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 // Only define if not already present diff --git a/lib/tcp_io.c b/lib/tcp_io.c index fc0b11eb..2b0a5210 100644 --- a/lib/tcp_io.c +++ b/lib/tcp_io.c @@ -13,6 +13,9 @@ #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif +#ifdef _WIN32 +#define SHUT_WR SD_SEND +#endif static void read_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) { int err = 0; 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; DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "tcp_io: connect ok fd=%d", (int)tc->sock); } else { diff --git a/src/conn_mgr.c b/src/conn_mgr.c index b709af88..9c267822 100644 --- a/src/conn_mgr.c +++ b/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_deliver_result(struct CONN_MGR_ENTRY* entry, int result); 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 int cm_has_direct_ip(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"); } -static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_meta_type) { - uint8_t tt = target_meta_type; - if (tt == NAT_VERIFIED_DIRECT) tt = CFG_SERVER_TYPE_PUBLIC; - else if (tt >= NAT_VERIFIED_UNKNOWN) tt = CFG_SERVER_TYPE_PUBLIC; +static int cm_nat_compatible(struct ETCP_SOCKET* our, uint8_t target_config_type, uint8_t target_nat_type) { + uint8_t tt = target_nat_type >= NAT_VERIFIED_UNKNOWN ? CFG_SERVER_TYPE_PUBLIC : target_config_type; uint8_t ot = our->type; 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_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_PUBLIC) 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; 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) { for (int j = 0; j < meta_count; j++) { 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; } } @@ -395,7 +393,7 @@ static int cm_has_local_addr(struct NODEINFO_Q* nq) { for (int i = 0; i < addr_count; i++) { if (addrs[i].type == ADDR_TYPE_INTERFACE) { 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; } } @@ -426,7 +424,7 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) { for (int i = 0; i < addr_count; i++) { if (addrs[i].type != ADDR_TYPE_INTERFACE) continue; 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; while (s) { 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; struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; 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) { struct sockaddr_in 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; for (int j = 0; j < meta_count; j++) { 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; memcpy(out_addrs[direct_count].ip, addrs[i].addr, 4); out_addrs[direct_count].port = htons(addrs[i].port); diff --git a/src/control_server.c b/src/control_server.c index 4f971282..f3546573 100644 --- a/src/control_server.c +++ b/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].port = 0; } + info[i].config_type = sock->type; info[i].nat_type = sock->nat_type; /* NAT address from socket (set when INIT_RESPONSE received) */ diff --git a/src/etcp_connections.c b/src/etcp_connections.c index 036ed52a..fc397898 100644 --- a/src/etcp_connections.c +++ b/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->type = type; 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->only_local = only_local; DEBUG_INFO(DEBUG_CATEGORY_BGP, "Add Socket type=%d", type); diff --git a/src/route_bgp.c b/src/route_bgp.c index 5e2beaaf..27aef472 100644 --- a/src/route_bgp.c +++ b/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; for (int i = 0; i < bgp->local_node->node.local_v4_sockets; i++) { if (meta[i].id == socket_id) { - if (meta[i].type != verified_type) { - meta[i].type = verified_type; + if (meta[i].nat_type != verified_type) { + meta[i].nat_type = verified_type; data_changed = 1; } break; diff --git a/src/route_node.c b/src/route_node.c index 274d891a..9f35c92e 100644 --- a/src/route_node.c +++ b/src/route_node.c @@ -173,7 +173,7 @@ void route_node_dump_all(struct ROUTE_BGP* bgp) { const struct NODEINFO_IPV4_SOCKET_META* v4sm; int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); 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; @@ -190,7 +190,7 @@ void route_node_dump_all(struct ROUTE_BGP* bgp) { const struct NODEINFO_IPV6_SOCKET_META* v6sm; int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); 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; @@ -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; int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); 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; 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; int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); 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; 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) { if (e_sock->local_addr.ss_family == AF_INET) { 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++; } 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) { if (e_sock->local_addr.ss_family == AF_INET6) { 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++; } e_sock = e_sock->next; diff --git a/src/route_node.h b/src/route_node.h index d5aa157f..b5cc1c9c 100644 --- a/src/route_node.h +++ b/src/route_node.h @@ -91,7 +91,8 @@ struct NODEINFO { // метаданные одного сокета struct NODEINFO_IPV4_SOCKET_META { 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)); // одна типизированная адресная запись (плоский список) @@ -104,7 +105,8 @@ struct NODEINFO_IPV4_ADDR { struct NODEINFO_IPV6_SOCKET_META { 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)); struct NODEINFO_IPV6_ADDR { diff --git a/src/tun_if.c b/src/tun_if.c index e4fb8f13..d9623718 100644 --- a/src/tun_if.c +++ b/src/tun_if.c @@ -11,7 +11,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif #include "../lib/mem.h" #ifdef _WIN32 @@ -151,6 +153,7 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config) } } else { if (tun->ifname[0] == '\0') strncpy(tun->ifname, "tun_test", sizeof(tun->ifname)-1); +#ifndef _WIN32 int fds[2]; 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)); @@ -159,6 +162,11 @@ struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config) } tun->fd = fds[0]; 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"); @@ -244,6 +252,7 @@ struct tun_if* tun_init_nat(struct UASYNC* ua, const char* ifname, const char* i return NULL; } } else { +#ifndef _WIN32 int fds[2]; 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)); @@ -252,6 +261,11 @@ struct tun_if* tun_init_nat(struct UASYNC* ua, const char* ifname, const char* i } tun->fd = fds[0]; 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"); diff --git a/src/utun_instance.c b/src/utun_instance.c index 9797f692..b1dc7685 100644 --- a/src/utun_instance.c +++ b/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_client_create can overwrite the handler if it has remote mappings +#ifndef _WIN32 if (tcp_proxy_server_init(instance) != 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "Failed to initialize tcp_proxy_server (non-fatal)"); } +#endif // 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) { const char* tun_name = config->global.tcp_proxy_client_tun_name; 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 { instance->tcp_proxy_client = NULL; } +#endif /* _WIN32 */ return 0; } @@ -362,6 +366,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) { } // Cleanup TCP proxy client module +#ifndef _WIN32 if (instance->tcp_proxy_client) { DEBUG_INFO(DEBUG_CATEGORY_TUN, "Destroying TCP proxy client module"); tcp_proxy_client_destroy(instance->tcp_proxy_client); @@ -370,6 +375,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) { // Cleanup TCP proxy server tcp_proxy_server_destroy(instance); +#endif // Cleanup routing module (unbinds from etcp_router before etcp_router_destroy) routing_destroy(instance); diff --git a/tests/test_ipv6_sockets.c b/tests/test_ipv6_sockets.c index 30eac267..fcd743b2 100644 --- a/tests/test_ipv6_sockets.c +++ b/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); if (mc != expect_socks || !meta) { printf("FAIL [%s]: v6 sockets meta retrieval failed\n", name); return 0; } for (int i = 0; i < mc; i++) { - if (meta[i].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; + if (meta[i].config_type != CFG_SERVER_TYPE_PUBLIC) { + 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 diff --git a/tests/test_nat_detection.c b/tests/test_nat_detection.c index 5dfe8ba3..a5490caf 100644 --- a/tests/test_nat_detection.c +++ b/tests/test_nat_detection.c @@ -261,9 +261,9 @@ int main(void) { // Verify C1 socket has config type before NAT detection { struct ETCP_SOCKET* s = inst_c1->etcp_sockets; - if (!s || s->nat_type != CFG_SERVER_TYPE_NAT) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C1 socket nat_type=%d, expected CFG_SERVER_TYPE_NAT(%d) before detection", - s ? (int)s->nat_type : -1, CFG_SERVER_TYPE_NAT); + if (!s || s->type != CFG_SERVER_TYPE_NAT) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C1 socket type=%d, expected CFG_SERVER_TYPE_NAT(%d) before detection", + s ? (int)s->type : -1, CFG_SERVER_TYPE_NAT); goto cleanup; } DEBUG_INFO(DEBUG_CATEGORY_BGP, "C1 socket has config NAT type before detection"); @@ -367,9 +367,9 @@ int main(void) { int found = 0; for (int i = 0; i < meta_count; i++) { if (meta[i].id == sock_c1->sock_id) { - if (meta[i].type != NAT_VERIFIED_EIM) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: type=%u expected=%u", - 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: nat_type=%u expected=%u", + meta[i].nat_type, NAT_VERIFIED_EIM); goto cleanup; } found = 1; @@ -413,7 +413,7 @@ int main(void) { const struct NODEINFO_IPV4_SOCKET_META* meta = NULL; int meta_count = get_node_v4_sockets_meta(node_c1_on_c2, &meta); 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; break; } diff --git a/tools/etcpmon/etcpmon_gui.c b/tools/etcpmon/etcpmon_gui.c index 78d3f61f..e52c3a7f 100644 --- a/tools/etcpmon/etcpmon_gui.c +++ b/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) { switch (nat_type) { case NAT_TYPE_EIM: return "EIM"; case NAT_TYPE_STRICT: return "Strict"; + case NAT_TYPE_DIRECT: return "Direct"; case NAT_VERIFIED_EIM: return "Verified-EIM"; case NAT_VERIFIED_STRICT: return "Verified-Strict"; 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; 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); if (list[i].nat_ip[0] != '\0') { if (list[i].is_ipv6) { - snprintf(display, sizeof(display), "[%s]:%d | NAT: %s (%s:%d)", - list[i].ip, list[i].port, nat_str, list[i].nat_ip, list[i].nat_port); + snprintf(display, sizeof(display), "[%s]:%d | Type: %s | NAT: %s (%s:%d)", + list[i].ip, list[i].port, cfg_str, nat_str, list[i].nat_ip, list[i].nat_port); } else { - snprintf(display, sizeof(display), "%s:%d | NAT: %s (%s:%d)", - list[i].ip, list[i].port, nat_str, list[i].nat_ip, list[i].nat_port); + snprintf(display, sizeof(display), "%s:%d | Type: %s | NAT: %s (%s:%d)", + list[i].ip, list[i].port, cfg_str, nat_str, list[i].nat_ip, list[i].nat_port); } } else { if (list[i].is_ipv6) { - snprintf(display, sizeof(display), "[%s]:%d | NAT: %s", - list[i].ip, list[i].port, nat_str); + snprintf(display, sizeof(display), "[%s]:%d | Type: %s | NAT: %s", + list[i].ip, list[i].port, cfg_str, nat_str); } else { - snprintf(display, sizeof(display), "%s:%d | NAT: %s", - list[i].ip, list[i].port, nat_str); + snprintf(display, sizeof(display), "%s:%d | Type: %s | NAT: %s", + list[i].ip, list[i].port, cfg_str, nat_str); } } SendMessageA(app->hListSockets, LB_ADDSTRING, 0, (LPARAM)display); diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index 744edf46..c54c23e7 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -27,10 +27,17 @@ extern "C" { #define NAT_TYPE_UNKNOWN 0 #define NAT_TYPE_EIM 1 /* Endpoint-Independent Mapping */ #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_EIM 5 /* EIM NAT */ #define NAT_VERIFIED_STRICT 6 /* strict NAT */ #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_CONN_NAME 32 #define ETCPMON_MAX_CONNECTIONS 250 @@ -126,7 +133,8 @@ struct etcpmon_socket_info { char ip[46]; /* Null-terminated IP address string */ uint16_t port; /* Port number (host byte order) */ 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 */ uint16_t nat_port; /* NAT port (host byte order) */ };