fix(nat): notify GUI and include profiles in Android socket snapshots

This commit is contained in:
evgeny committed 2026-10-17 22:07:58 +02:00
1 parent 60104ea093
commit c69f8d8975
3 files changed
+87 -16

No files matched your search

+2
View File
@@ -2,6 +2,7 @@
* через router, независимо от прямого UDP-ответа. Входящие пробы не получают PONG;
* незнакомость фактического source IP проверяет только получатель. */
#include "nat_detection.h"
#include "chat/chat_event.h"
#include <stdio.h>
#include <string.h>
@@ -311,6 +312,7 @@ static void publish(struct NAT_DETECTION *detector) {
detector->publish_pending = topo_node_update_my_addresses(detector->instance) < 0;
if (detector->publish_pending) detector->publish_after = get_time_tb() + 10000;
if (detector->publish_pending) DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT profile publication failed; retry scheduled");
else chat_event_post(detector->instance, CHAT_EVT_LOCAL_SOCKETS, NULL, 0);
}
static struct nat_socket *socket_state(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, int create) {
+35
View File
@@ -9,6 +9,7 @@
#include "../src/chat/chat_core.h"
#include "../src/chat/chat_event.h"
#include "../src/routing_layer/topo_node_sqlite.h"
#include "../src/transport_layer/etcp_connections.h"
#include "../src/config_parser.h"
#include "../tools/chatgui-android/jni_bridge/android_jni_bridge.h"
#include "test_utils.h"
@@ -87,6 +88,39 @@ static int check_addresses(const char *channel) {
u_free(json); return 0;
}
/* Собственные сокеты передают профиль независимо от адреса интерфейса; тестовые порты скрыты. */
static int check_local_sockets(void) {
struct ETCP_SOCKET* saved = instance->etcp_sockets;
struct ETCP_SOCKET tcp = {.sock_id = 7, .is_tcp = 1, .name = "as_wlan0_v4_tcp",
.address_profile = {ADDRESS_MAP_UNKNOWN, ADDRESS_IN_UNKNOWN, ADDRESS_SOURCE_ETCP}};
struct ETCP_SOCKET udp = {.sock_id = 8, .name = "as_wlan0_v6_udp",
.address_profile = {ADDRESS_MAP_EIM, ADDRESS_IN_OPEN, ADDRESS_SOURCE_ETCP}};
struct ETCP_SOCKET probe = {.sock_id = 9, .probe_only = 1};
struct sockaddr_in* local4 = (struct sockaddr_in*)&tcp.interface_addr;
local4->sin_family = AF_INET; local4->sin_port = htons(9892); inet_pton(AF_INET, "192.168.40.250", &local4->sin_addr);
struct sockaddr_in* external4 = (struct sockaddr_in*)&tcp.nat_addr;
external4->sin_family = AF_INET; inet_pton(AF_INET, "194.63.142.140", &external4->sin_addr);
struct sockaddr_in6* local6 = (struct sockaddr_in6*)&udp.interface_addr;
local6->sin6_family = AF_INET6; local6->sin6_port = htons(9893); inet_pton(AF_INET6, "fd00::1", &local6->sin6_addr);
struct sockaddr_in6* external6 = (struct sockaddr_in6*)&udp.nat_addr;
external6->sin6_family = AF_INET6; external6->sin6_port = htons(4101); inet_pton(AF_INET6, "2a04:5200::f", &external6->sin6_addr);
tcp.next = &udp; udp.next = &probe; instance->etcp_sockets = &tcp;
char* json = utun_bridge_get_local_sockets_json();
instance->etcp_sockets = saved;
char value[128];
REQUIRE(json && !extract(json, "$[0].nmapping", value, sizeof(value)) && !strcmp(value, "0"));
REQUIRE(!extract(json, "$[0].nsource", value, sizeof(value)) && !strcmp(value, "1"));
REQUIRE(!extract(json, "$[0].ad", value, sizeof(value)) && !strcmp(value, "192.168.40.250"));
REQUIRE(!extract(json, "$[0].external", value, sizeof(value)) && !strcmp(value, "194.63.142.140"));
REQUIRE(!extract(json, "$[0].externalPort", value, sizeof(value)) && !strcmp(value, "0"));
REQUIRE(!extract(json, "$[1].nmapping", value, sizeof(value)) && !strcmp(value, "2"));
REQUIRE(!extract(json, "$[1].ninbound", value, sizeof(value)) && !strcmp(value, "1"));
REQUIRE(!extract(json, "$[1].external", value, sizeof(value)) && !strcmp(value, "2a04:5200::f"));
REQUIRE(!extract(json, "$[1].externalPort", value, sizeof(value)) && !strcmp(value, "4101"));
REQUIRE(!extract(json, "$[#-1].si", value, sizeof(value)) && !strcmp(value, "8"));
u_free(json); return 0;
}
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
char directory[512] = "/tmp/utun_android_replies_XXXXXX", config[1024], channel[64], hex[65];
@@ -101,6 +135,7 @@ int main(void) {
char* json = utun_bridge_get_channels_json();
REQUIRE(!extract(json, "$[0].id", channel, sizeof(channel))); u_free(json);
REQUIRE(!check_addresses(channel));
REQUIRE(!check_local_sockets());
uint8_t empty[32] = {0}, original[32], missing[32]; memset(missing, 0xff, sizeof(missing));
REQUIRE(!utun_bridge_send_message(channel, "Привет 😀 \"original\"\nnext line", empty, 1) && wait_result(1) == 1);
json = utun_bridge_get_messages_json(channel, 1, NULL, 0);
@@ -27,6 +27,7 @@
#include "../../../lib/mem.h"
#include "../../../lib/sqlite3.h"
#include "../../../src/chat/chat_core.h"
#include "../../../src/chat/chat_event.h"
#include "../../../src/chat/chat_poll.h"
#include "../../../lib/strbuf.h"
#include "../../../src/chat/chat_member.h"
@@ -1163,7 +1164,7 @@ char* utun_bridge_get_local_sockets_json(void) {
json[0] = '[';
int first = 1;
bridge_log(BLEV_INFO, "getLocalSockets: etcp_sockets=%p", (void*)inst->etcp_sockets);
bridge_log(BLEV_DEBUG, "local sockets snapshot: etcp_sockets=%p", (void*)inst->etcp_sockets);
/* Helper: count per-socket links_up / links_down */
#define SOCK_COUNT_LINKS(_s, _lu, _ld) do { \
@@ -1194,7 +1195,7 @@ char* utun_bridge_get_local_sockets_json(void) {
/* TCP sockets */
{ struct ETCP_SOCKET* s = inst->etcp_sockets;
while (s) {
if (!s->is_tcp) { s = s->next; continue; }
if (!s->is_tcp || s->probe_only) { s = s->next; continue; }
char ip_str[INET6_ADDRSTRLEN] = ""; int port = 0;
const struct sockaddr_storage* addr = s->interface_addr.ss_family ? &s->interface_addr : &s->local_addr;
if (addr->ss_family == AF_INET) {
@@ -1210,14 +1211,26 @@ char* utun_bridge_get_local_sockets_json(void) {
int state = 2; /* bound and listening */
const char* sep = first ? "" : ","; first = 0;
const char* pn = s->reality_enabled ? "TCP+REALITY" : "TCP";
char external[INET6_ADDRSTRLEN] = ""; int external_port = 0;
if (s->nat_addr.ss_family == AF_INET) {
const struct sockaddr_in* nat = (const struct sockaddr_in*)&s->nat_addr;
inet_ntop(AF_INET, &nat->sin_addr, external, sizeof(external)); external_port = ntohs(nat->sin_port);
} else if (s->nat_addr.ss_family == AF_INET6) {
const struct sockaddr_in6* nat = (const struct sockaddr_in6*)&s->nat_addr;
inet_ntop(AF_INET6, &nat->sin6_addr, external, sizeof(external)); external_port = ntohs(nat->sin6_port);
}
size_t needed = snprintf(NULL, 0,
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"%s\",\"st\":%d,\"lu\":%d,\"ld\":%d}",
sep, s->sock_id, s->name, ip_str, port, pn, state, lu, ld);
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"%s\",\"st\":%d,\"lu\":%d,\"ld\":%d,"
"\"nmapping\":%u,\"ninbound\":%u,\"nsource\":%u,\"external\":\"%s\",\"externalPort\":%d}",
sep, s->sock_id, s->name, ip_str, port, pn, state, lu, ld,
s->address_profile.mapping, s->address_profile.inbound, s->address_profile.source, external, external_port);
while (pos + needed + 2 > cap) { char* tmp = u_realloc(json, cap * 2); if (!tmp) break; json = tmp; cap *= 2; }
if (pos + needed + 2 <= cap)
pos += (size_t)snprintf(json + pos, cap - pos,
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"%s\",\"st\":%d,\"lu\":%d,\"ld\":%d}",
sep, s->sock_id, s->name, ip_str, port, pn, state, lu, ld);
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"%s\",\"st\":%d,\"lu\":%d,\"ld\":%d,"
"\"nmapping\":%u,\"ninbound\":%u,\"nsource\":%u,\"external\":\"%s\",\"externalPort\":%d}",
sep, s->sock_id, s->name, ip_str, port, pn, state, lu, ld,
s->address_profile.mapping, s->address_profile.inbound, s->address_profile.source, external, external_port);
s = s->next;
}
}
@@ -1225,7 +1238,7 @@ char* utun_bridge_get_local_sockets_json(void) {
/* UDP sockets */
{ struct ETCP_SOCKET* es = inst->etcp_sockets;
while (es) {
if (es->is_tcp) { es = es->next; continue; }
if (es->is_tcp || es->probe_only) { es = es->next; continue; }
char ip_str[INET6_ADDRSTRLEN] = ""; int port = 0;
const struct sockaddr_storage* addr = es->interface_addr.ss_family ? &es->interface_addr : &es->local_addr;
if (addr->ss_family == AF_INET) {
@@ -1240,14 +1253,26 @@ char* utun_bridge_get_local_sockets_json(void) {
int lu, ld; SOCK_COUNT_LINKS(es, lu, ld);
int state = 2; /* bound and listening */
const char* sep = first ? "" : ","; first = 0;
char external[INET6_ADDRSTRLEN] = ""; int external_port = 0;
if (es->nat_addr.ss_family == AF_INET) {
const struct sockaddr_in* nat = (const struct sockaddr_in*)&es->nat_addr;
inet_ntop(AF_INET, &nat->sin_addr, external, sizeof(external)); external_port = ntohs(nat->sin_port);
} else if (es->nat_addr.ss_family == AF_INET6) {
const struct sockaddr_in6* nat = (const struct sockaddr_in6*)&es->nat_addr;
inet_ntop(AF_INET6, &nat->sin6_addr, external, sizeof(external)); external_port = ntohs(nat->sin6_port);
}
size_t needed = snprintf(NULL, 0,
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lu\":%d,\"ld\":%d}",
sep, es->sock_id, es->name, ip_str, port, state, lu, ld);
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lu\":%d,\"ld\":%d,"
"\"nmapping\":%u,\"ninbound\":%u,\"nsource\":%u,\"external\":\"%s\",\"externalPort\":%d}",
sep, es->sock_id, es->name, ip_str, port, state, lu, ld,
es->address_profile.mapping, es->address_profile.inbound, es->address_profile.source, external, external_port);
while (pos + needed + 2 > cap) { char* tmp = u_realloc(json, cap * 2); if (!tmp) break; json = tmp; cap *= 2; }
if (pos + needed + 2 <= cap)
pos += (size_t)snprintf(json + pos, cap - pos,
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lu\":%d,\"ld\":%d}",
sep, es->sock_id, es->name, ip_str, port, state, lu, ld);
"%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lu\":%d,\"ld\":%d,"
"\"nmapping\":%u,\"ninbound\":%u,\"nsource\":%u,\"external\":\"%s\",\"externalPort\":%d}",
sep, es->sock_id, es->name, ip_str, port, state, lu, ld,
es->address_profile.mapping, es->address_profile.inbound, es->address_profile.source, external, external_port);
es = es->next;
}
}
@@ -2573,13 +2598,22 @@ JNIEXPORT jstring JNICALL Java_com_utun_chat_data_NativeLib_nativeGetMemberLinks
/* ── Local sockets JSON ── */
JNIEXPORT jstring JNICALL Java_com_utun_chat_data_NativeLib_nativeGetLocalSockets(
JNIEnv* env, jobject thiz) {
(void)thiz;
static void local_sockets_trampoline(void* arg) {
(void)arg;
struct UTUN_INSTANCE* inst = instance_lite_get_instance();
if (!inst) { bridge_log(BLEV_WARN, "local sockets snapshot: core stopped"); return; }
char* json = utun_bridge_get_local_sockets_json();
jstring result = (*env)->NewStringUTF(env, json ? json : "[]");
if (!json) { bridge_log(BLEV_ERROR, "local sockets snapshot allocation failed"); return; }
chat_event_post(inst, CHAT_EVT_LOCAL_SOCKETS, (const uint8_t*)json, (int)strlen(json));
u_free(json);
return result;
}
JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeRequestLocalSockets(
JNIEnv* env, jobject thiz) {
(void)env; (void)thiz;
struct UASYNC* ua = instance_lite_get_uasync();
if (!uasync_is_running(ua)) { bridge_log(BLEV_DEBUG, "local sockets request: core stopped"); return; }
uasync_post(ua, local_sockets_trampoline, NULL);
}
/* ── Network change notification ── */