Browse Source

nat: distinguish public interface addresses from unknown NAT candidates

stream-multiview
evgeny 1 week ago
parent
commit
78f71ddbb0
  1. 6
      src/routing_layer/topo_node_sqlite.c
  2. 10
      tests/test_node_snapshot.c
  3. 11
      tools/chatgui/src/nodespage.cpp

6
src/routing_layer/topo_node_sqlite.c

@ -62,11 +62,13 @@ static int addr_type_from_ip(int family, const uint8_t* addr) {
}
/* Итоговая классификация: конфиг + автоопределение + 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 (!profile) return ADDR_TYPE_NAT;
if (profile->mapping == ADDRESS_MAP_EIM) return ADDR_TYPE_NAT_EIM;
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 (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;
@ -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) {
static const struct address_profile unknown = {0};
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;
int has_reality = (protocol & TOPO_PROTO_REALITY) && reality_opts_build(node, socket_id, &reality);
sqlite3_bind_int64(statement, 1, (sqlite3_int64)node_id);

10
tests/test_node_snapshot.c

@ -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_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. */
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);

11
tools/chatgui/src/nodespage.cpp

@ -208,7 +208,7 @@ void NodesPage::refreshNodes() {
sqlite3_stmt* na = nullptr;
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",
-1, &na, nullptr);
if (na) {
@ -224,13 +224,20 @@ void NodesPage::refreshNodes() {
int rtt = sqlite3_column_int(na, 4);
int addrType = sqlite3_column_int(na, 5);
int kind = sqlite3_column_int(na, 6);
int mapping = sqlite3_column_int(na, 7), inbound = sqlite3_column_int(na, 8);
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")
.arg(addrStr(addr, family))
.arg(port)
.arg(protoStr(proto))
.arg(kind == TOPO_ADDR_INTERFACE ? QStringLiteral("INTERFACE") : addrTypeStr(addrType))
.arg(label)
.arg(rtt > 0 ? QString::number(rtt / 10) : "-");
}
ac++;

Loading…
Cancel
Save