nat: distinguish public interface addresses from unknown NAT candidates

This commit is contained in:
evgeny committed 2026-10-17 17:53:20 +02:00
1 parent 37461bb938
commit 78f71ddbb0
3 files changed
+23 -4

No files matched your search

+4 -2
View File
@@ -62,11 +62,13 @@ static int addr_type_from_ip(int family, const uint8_t* addr) {
} }
/* Итоговая классификация: конфиг + автоопределение + IP (всё локально). */ /* Итоговая классификация: конфиг + автоопределение + IP (всё локально). */
static int addr_type_classify(int config_type, int global, const struct address_profile *profile) { static int addr_type_classify(int kind, int config_type, int global, const struct address_profile *profile) {
if (config_type == CFG_SERVER_TYPE_PRIVATE || config_type == CFG_SERVER_TYPE_LOCAL) return ADDR_TYPE_NETIF; if (config_type == CFG_SERVER_TYPE_PRIVATE || config_type == CFG_SERVER_TYPE_LOCAL) return ADDR_TYPE_NETIF;
if (!profile) return ADDR_TYPE_NAT; if (!profile) return ADDR_TYPE_NAT;
if (profile->mapping == ADDRESS_MAP_EIM) return ADDR_TYPE_NAT_EIM; if (profile->mapping == ADDRESS_MAP_EIM) return ADDR_TYPE_NAT_EIM;
if (profile->mapping == ADDRESS_MAP_DEPENDENT) return ADDR_TYPE_NAT_STRICT; if (profile->mapping == ADDRESS_MAP_DEPENDENT) return ADDR_TYPE_NAT_STRICT;
/* Публичный адрес интерфейса известен без определения входящих и не становится NAT из-за UNKNOWN. */
if (global && kind == TOPO_ADDR_INTERFACE && profile->mapping == ADDRESS_MAP_UNKNOWN) return ADDR_TYPE_NETIF;
if (!global) return config_type == CFG_SERVER_TYPE_NAT ? ADDR_TYPE_NAT : ADDR_TYPE_NETIF; if (!global) return config_type == CFG_SERVER_TYPE_NAT ? ADDR_TYPE_NAT : ADDR_TYPE_NETIF;
if (profile->mapping == ADDRESS_MAP_UNCHANGED && profile->inbound == ADDRESS_IN_OPEN) return ADDR_TYPE_DIRECT; if (profile->mapping == ADDRESS_MAP_UNCHANGED && profile->inbound == ADDRESS_IN_OPEN) return ADDR_TYPE_DIRECT;
if (profile->mapping == ADDRESS_MAP_UNCHANGED && profile->inbound == ADDRESS_IN_CONTACT) return ADDR_TYPE_CONTACT; if (profile->mapping == ADDRESS_MAP_UNCHANGED && profile->inbound == ADDRESS_IN_CONTACT) return ADDR_TYPE_CONTACT;
@@ -109,7 +111,7 @@ static int address_row_put(sqlite3_stmt *statement, struct TOPO_NODE *node, uint
uint8_t protocol, uint8_t config, const struct address_profile *profile) { uint8_t protocol, uint8_t config, const struct address_profile *profile) {
static const struct address_profile unknown = {0}; static const struct address_profile unknown = {0};
if (!profile) profile = &unknown; if (!profile) profile = &unknown;
int summary = addr_type_classify(config, addr_type_from_ip(family, address) == ADDR_TYPE_DIRECT, profile); int summary = addr_type_classify(kind, config, addr_type_from_ip(family, address) == ADDR_TYPE_DIRECT, profile);
struct TOPO_ADDR_REALITY_OPTS reality; struct TOPO_ADDR_REALITY_OPTS reality;
int has_reality = (protocol & TOPO_PROTO_REALITY) && reality_opts_build(node, socket_id, &reality); int has_reality = (protocol & TOPO_PROTO_REALITY) && reality_opts_build(node, socket_id, &reality);
sqlite3_bind_int64(statement, 1, (sqlite3_int64)node_id); sqlite3_bind_int64(statement, 1, (sqlite3_int64)node_id);
+10
View File
@@ -83,6 +83,16 @@ static void test_compact_addresses(struct UTUN_INSTANCE *inst) {
assert(sqlite3_column_int(statement, 4) == ADDR_TYPE_CONTACT && sqlite3_column_int(statement, 5) == TOPO_ADDR_REALITY_OPTS_SIZE); assert(sqlite3_column_int(statement, 4) == ADDR_TYPE_CONTACT && sqlite3_column_int(statement, 5) == TOPO_ADDR_REALITY_OPTS_SIZE);
assert(sqlite3_step(statement) == SQLITE_DONE); sqlite3_finalize(statement); assert(sqlite3_step(statement) == SQLITE_DONE); sqlite3_finalize(statement);
/* Публичный IP интерфейса не становится NAT UNKNOWN из-за отсутствия измерения входящих. */
struct address_profile known = node->v4_sock_meta->address_profile;
node->v4_sock_meta->address_profile = (struct address_profile){0};
assert(!topo_node_sqlite_addrs_put(db, inst->node_id, node));
assert(sqlite3_prepare_v2(db, "SELECT addr_type FROM node_addresses WHERE family=4", -1, &statement, NULL) == SQLITE_OK);
assert(sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_int(statement, 0) == ADDR_TYPE_NETIF);
sqlite3_finalize(statement);
node->v4_sock_meta->address_profile = known;
assert(!topo_node_sqlite_addrs_put(db, inst->node_id, node));
/* Две старые колонки отмечают прежний формат. Миграция не теряет IP/port, REALITY и максимум timestamp. */ /* Две старые колонки отмечают прежний формат. Миграция не теряет IP/port, REALITY и максимум timestamp. */
assert(sqlite3_exec(db, "ALTER TABLE node_addresses ADD COLUMN nat_evidence INTEGER DEFAULT 1;" assert(sqlite3_exec(db, "ALTER TABLE node_addresses ADD COLUMN nat_evidence INTEGER DEFAULT 1;"
"ALTER TABLE node_addresses ADD COLUMN nat_checked INTEGER DEFAULT 1", NULL, NULL, NULL) == SQLITE_OK); "ALTER TABLE node_addresses ADD COLUMN nat_checked INTEGER DEFAULT 1", NULL, NULL, NULL) == SQLITE_OK);
+9 -2
View File
@@ -208,7 +208,7 @@ void NodesPage::refreshNodes() {
sqlite3_stmt* na = nullptr; sqlite3_stmt* na = nullptr;
sqlite3_prepare_v2(d, sqlite3_prepare_v2(d,
"SELECT family, protocol, address, port, rtt, addr_type, address_kind" "SELECT family, protocol, address, port, rtt, addr_type, address_kind, nat_mapping, nat_inbound"
" FROM node_addresses WHERE node_id=? ORDER BY family, port", " FROM node_addresses WHERE node_id=? ORDER BY family, port",
-1, &na, nullptr); -1, &na, nullptr);
if (na) { if (na) {
@@ -224,13 +224,20 @@ void NodesPage::refreshNodes() {
int rtt = sqlite3_column_int(na, 4); int rtt = sqlite3_column_int(na, 4);
int addrType = sqlite3_column_int(na, 5); int addrType = sqlite3_column_int(na, 5);
int kind = sqlite3_column_int(na, 6); int kind = sqlite3_column_int(na, 6);
int mapping = sqlite3_column_int(na, 7), inbound = sqlite3_column_int(na, 8);
if (addr && addrSz > 0) { if (addr && addrSz > 0) {
QString label = addrTypeStr(addrType);
if (kind == TOPO_ADDR_INTERFACE) {
label = QStringLiteral("INTERFACE");
if (mapping != ADDRESS_MAP_UNKNOWN || inbound != ADDRESS_IN_UNKNOWN)
label += QString(" mapping=%1 inbound=%2").arg(address_mapping_name(mapping), address_inbound_name(inbound));
}
dump += QString(" %1:%2 %3 %4 rtt=%5ms\n") dump += QString(" %1:%2 %3 %4 rtt=%5ms\n")
.arg(addrStr(addr, family)) .arg(addrStr(addr, family))
.arg(port) .arg(port)
.arg(protoStr(proto)) .arg(protoStr(proto))
.arg(kind == TOPO_ADDR_INTERFACE ? QStringLiteral("INTERFACE") : addrTypeStr(addrType)) .arg(label)
.arg(rtt > 0 ? QString::number(rtt / 10) : "-"); .arg(rtt > 0 ? QString::number(rtt / 10) : "-");
} }
ac++; ac++;