nat: use same-interface STUN mapping as tentative EIM
This commit is contained in:
1 parent
aede36388f
commit
88ac08333e
3 files changed
+26
-12
No files matched your search
@@ -16,6 +16,7 @@
|
||||
#include "etcp_router.h"
|
||||
#include "route_crypto.h"
|
||||
#include "stcp_client.h"
|
||||
#include "stun_nat.h"
|
||||
#include "sock_match.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
@@ -574,7 +575,7 @@ static void clear_profile(struct nat_socket *state, uint8_t reason) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Публикуется только измерение рабочего endpoint; отдельный STUN-порт остаётся диагностикой. */
|
||||
/* Измерение рабочего endpoint приоритетно; STUN того же пути даёт только предварительный EIM?. */
|
||||
static void select_profile(struct nat_socket *state) {
|
||||
const struct address_profile *current = &state->socket->address_profile;
|
||||
struct address_profile selected = state->measured_profile;
|
||||
@@ -586,6 +587,15 @@ static void select_profile(struct nat_socket *state) {
|
||||
if (!selected.mapping && state->observed_address.ss_family) {
|
||||
selected.source = ADDRESS_SOURCE_ETCP; selected_address = state->observed_address;
|
||||
}
|
||||
struct stun_nat_result stun;
|
||||
uint64_t now = get_time_tb();
|
||||
if (!selected.mapping && !stun_nat_get_socket_result(state->detector->instance, state->socket, &stun) &&
|
||||
(stun.status == STUN_NAT_COMPLETE || stun.status == STUN_NAT_PARTIAL) &&
|
||||
stun.measured_at_tb && now >= stun.measured_at_tb && now - stun.measured_at_tb < STUN_NAT_TTL_TB &&
|
||||
stun.server_count == 2 && stun.translated == 1 && (stun.mapping == STUN_MAP_MATCH || stun.mapping == STUN_MAP_EIM) &&
|
||||
(!selected_address.ss_family || route_ping_addr_equal(&selected_address, &stun.mapped[0], 0))) {
|
||||
selected.mapping = ADDRESS_MAP_EIM; selected.inbound = ADDRESS_IN_UNKNOWN; selected.source = ADDRESS_SOURCE_STUN;
|
||||
}
|
||||
int address_changed = selected_address.ss_family != state->socket->nat_addr.ss_family ||
|
||||
(selected_address.ss_family && !route_ping_addr_equal(&selected_address, &state->socket->nat_addr, 1));
|
||||
if (selected.mapping == current->mapping && selected.inbound == current->inbound &&
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define STUN_OTHER 0x802c
|
||||
#define STUN_REQUESTS 7
|
||||
#define STUN_SCAN_TB 30000
|
||||
#define STUN_TTL_TB UINT64_C(3000000)
|
||||
#define STUN_REFRESH_TB UINT64_C(1800000)
|
||||
#define STUN_RETRY_TB UINT64_C(300000)
|
||||
|
||||
@@ -850,7 +849,7 @@ int stun_nat_get_socket_result(const struct UTUN_INSTANCE* inst, const struct ET
|
||||
for (const struct stun_probe* p = inst->stun_nat->probes; p; p = p->next) {
|
||||
if (!key_equal(&p->source.key, &source.key) || (!p->conflict && !policy_equal(&p->source, &source))) continue;
|
||||
uint64_t now = get_time_tb();
|
||||
int fresh = p->cached.measured_at_tb && now >= p->cached.measured_at_tb && now - p->cached.measured_at_tb < STUN_TTL_TB;
|
||||
int fresh = p->cached.measured_at_tb && now >= p->cached.measured_at_tb && now - p->cached.measured_at_tb < STUN_NAT_TTL_TB;
|
||||
*result = fresh ? p->cached : p->result;
|
||||
result->refreshing = fresh && p->result.status == STUN_NAT_PENDING;
|
||||
result->members = p->members;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
/* Независимая STUN-диагностика интерфейсов существующих IPv4 UDP-сокетов.
|
||||
* [stun] enabled=yes, повторяющийся server=host[:port]; нужны два разных IP.
|
||||
* Обычный STUN сравнивает mapping; RFC 5780 дополнительно проверяет mapping/filtering.
|
||||
* MATCH означает совпадение для двух серверов, а не доказанный EIM.
|
||||
* Результат локальный: nat_detection, ETCP и NODEINFO не изменяются.
|
||||
* Модуль создаёт собственный UDP-сокет на том же адресе/интерфейсе, с теми же mark/FIB,
|
||||
* самостоятельно принимает STUN и закрывает fd. Результат относится к тестовому порту.
|
||||
* Периодическая сверка замечает добавление/удаление/изменение исходных сокетов.
|
||||
* Все вызовы выполняются в uasync-потоке; destroy отменяет DNS и таймеры до освобождения config. */
|
||||
/* Определяет поведение NAT через внешние STUN-серверы: совпадает ли внешний IP:порт
|
||||
* при обращении к разным IP и доступны ли входящие без предварительного контакта.
|
||||
* mapping: MATCH — два сервера видят одинаковый адрес; DEPENDENT — разные;
|
||||
* RFC 5780 уточняет EIM/ADM/APDM и filtering (EIF/ADF/APDF). UNKNOWN — данных недостаточно.
|
||||
* Для работы: [stun] enabled=yes и минимум две строки server=host[:port] с разными IP.
|
||||
* Ядро вызывает init(instance)/destroy(instance), модуль сам измеряет и обновляет результат.
|
||||
* get_socket_result(instance, socket, &result) возвращает снимок; recheck(instance) повторяет проверку.
|
||||
* nat_detection использует совпавший mapping как предварительный EIM? для рабочих UDP-сокетов
|
||||
* с теми же IP, интерфейсом и routing options; измерение рабочего сокета имеет приоритет.
|
||||
* Проверка идёт с отдельного тестового порта: его внешний IP:порт не публикуется как адрес рабочего сокета,
|
||||
* а filtering не переносится на рабочий сокет. Без RFC 5780 входящие остаются UNKNOWN.
|
||||
* Все вызовы — в uasync-потоке ядра; destroy отменяет DNS/таймеры до освобождения config. */
|
||||
#ifndef STUN_NAT_H
|
||||
#define STUN_NAT_H
|
||||
|
||||
@@ -22,6 +25,8 @@ struct UTUN_INSTANCE;
|
||||
struct STUN_NAT;
|
||||
struct ETCP_SOCKET;
|
||||
|
||||
#define STUN_NAT_TTL_TB UINT64_C(3000000) /* Результат действителен 300 секунд; единица — 100 мкс. */
|
||||
|
||||
/* Ключ пути не содержит порт/имя рабочего сокета. family — 4 или 6. */
|
||||
struct stun_nat_key { uint8_t family, address[16]; uint32_t netif_index; };
|
||||
|
||||
|
||||
Reference in new issue
Block a user