nat: determine TCP translation from one public IP observation
This commit is contained in:
1 parent
d7ad58b380
commit
95f209d098
2 files changed
+47
-6
No files matched your search
@@ -580,6 +580,10 @@ static void select_profile(struct nat_socket *state) {
|
||||
const struct address_profile *current = &state->socket->address_profile;
|
||||
struct address_profile selected = state->measured_profile;
|
||||
struct sockaddr_storage selected_address = {0};
|
||||
if (state->socket->is_tcp) {
|
||||
selected_address = state->observed_address;
|
||||
if (!selected.source && !public_address(state->detector, &state->local)) selected.source = ADDRESS_SOURCE_ETCP;
|
||||
}
|
||||
if (state->measured_profile.source == ADDRESS_SOURCE_ETCP) {
|
||||
selected = state->measured_profile;
|
||||
if (selected.mapping == ADDRESS_MAP_EIM) selected_address = state->measured_address;
|
||||
@@ -1286,6 +1290,11 @@ static void receive_control(struct ETCP_CONN *from, struct ll_entry *entry) {
|
||||
|
||||
static void owner_start(struct nat_socket *state) {
|
||||
struct NAT_DETECTION *detector = state->detector;
|
||||
if (state->socket->is_tcp) {
|
||||
select_profile(state); state->due = UINT64_MAX;
|
||||
state->reason = state->socket->address_profile.source ? NAT_REASON_NONE : NAT_REASON_NO_OBSERVER;
|
||||
return;
|
||||
}
|
||||
if (state->socket->socks_udp) {
|
||||
state->reason = NAT_REASON_PROXY; state->due = UINT64_MAX;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT native endpoint not measured through SOCKS5 socket=%s", state->socket->name); return;
|
||||
@@ -1293,11 +1302,6 @@ static void owner_start(struct nat_socket *state) {
|
||||
if (state->socket->type == CFG_SERVER_TYPE_LOCAL || state->socket->type == CFG_SERVER_TYPE_PRIVATE) {
|
||||
state->due = UINT64_MAX; return;
|
||||
}
|
||||
if (state->socket->is_tcp && !public_address(detector, &state->local)) {
|
||||
state->reason = NAT_REASON_NO_LISTENER; state->due = UINT64_MAX;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "TCP inbound profile remains UNKNOWN: no public listener candidate socket=%s local=%s",
|
||||
state->socket->name, sockaddr_storage_to_str(&state->local).str); return;
|
||||
}
|
||||
if (!state->cycling) {
|
||||
state->cycling = 1; state->cursor = (struct nat_pair){0};
|
||||
state->cycle_deadline = get_time_tb() + NAT_ROUND_TB;
|
||||
@@ -1604,6 +1608,35 @@ void nat_detection_link_ready(struct NAT_DETECTION *detector, struct ETCP_LINK *
|
||||
if (state && !state->phase && !state->completed_tb) state->due = get_time_tb() + 2500;
|
||||
}
|
||||
|
||||
/* Одно TCP-наблюдение сравнивает только IP; нулевой порт не обещает доступный listener. */
|
||||
void nat_detection_tcp_observed(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
|
||||
const struct sockaddr_storage *local, const struct sockaddr_storage *observed) {
|
||||
if (!detector || detector->stopping || !link || !link->is_tcp || !link->conn || !local || !observed) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP NAT observation has invalid socket/addresses"); return;
|
||||
}
|
||||
if (local->ss_family != observed->ss_family || !public_address(detector, observed) ||
|
||||
!public_address(detector, &link->remote_addr)) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "TCP NAT observation ignored socket=%s local=%s observed=%s peer=%s reason=non_public_or_family",
|
||||
link->conn->name, sockaddr_storage_to_str(local).str, sockaddr_storage_to_str(observed).str,
|
||||
sockaddr_storage_to_str(&link->remote_addr).str); return;
|
||||
}
|
||||
struct nat_socket *state = socket_state(detector, link->conn, 1);
|
||||
if (!state) return;
|
||||
uint8_t mapping = public_address(detector, local) && route_ping_addr_equal(local, observed, 0) ?
|
||||
ADDRESS_MAP_UNCHANGED : ADDRESS_MAP_UNKNOWN;
|
||||
struct sockaddr_storage address = *observed;
|
||||
if (address.ss_family == AF_INET) ((struct sockaddr_in *)&address)->sin_port = 0;
|
||||
else ((struct sockaddr_in6 *)&address)->sin6_port = 0;
|
||||
if (state->measured_profile.source == ADDRESS_SOURCE_ETCP && state->measured_profile.mapping == mapping &&
|
||||
route_ping_addr_equal(&state->observed_address, &address, 1)) return;
|
||||
state->measured_profile = (struct address_profile){.mapping = mapping, .source = ADDRESS_SOURCE_ETCP};
|
||||
state->observed_address = address; state->completed_tb = get_time_tb(); state->due = UINT64_MAX; state->reason = NAT_REASON_NONE;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "TCP NAT presence socket=%s local=%s observed=%s NAT=%s type=UNKNOWN inbound=UNKNOWN",
|
||||
link->conn->name, sockaddr_storage_to_str(local).str, sockaddr_storage_to_str(&address).str,
|
||||
mapping == ADDRESS_MAP_UNCHANGED ? "no" : "yes");
|
||||
select_profile(state);
|
||||
}
|
||||
|
||||
void nat_detection_observed_by_peer(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
|
||||
const struct sockaddr_storage *observed) {
|
||||
if (!detector || !link || !link->conn || link->is_tcp || link->conn->socks_udp || !observed->ss_family) return;
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
* UNKNOWN в любом свойстве означает, что данных для его определения пока недостаточно.
|
||||
* Одно соединение может подтвердить NAT-адрес: он сохраняется в socket->nat_addr с типом UNKNOWN
|
||||
* и публикуется как NAT-кандидат. Это не адрес интерфейса и не подтверждение открытого входа.
|
||||
* Для UDP сочетания EIM+OPEN и EIM+CONTACT означают eim open и eim filtered. TCP-вход проверяется отдельно.
|
||||
* Для UDP сочетания EIM+OPEN и EIM+CONTACT означают eim open и eim filtered.
|
||||
* Для TCP непубличный локальный IP сразу означает NAT; публичный IP сравнивается с наблюдением одного пира.
|
||||
* TCP не определяет тип NAT/входящие: сохраняет внешний IP с портом 0, непригодным для подключения.
|
||||
* EIM+UNKNOWN отображается как EIM?: внешний адрес совпал, незнакомый вход не удалось проверить.
|
||||
* Если своего измерения mapping нет, совпадение у двух STUN-серверов на том же IP/интерфейсе даёт предварительный EIM?.
|
||||
* Его source=STUN, inbound=UNKNOWN; внешний порт берётся только из наблюдения рабочего сокета, а не из STUN.
|
||||
@@ -115,6 +117,12 @@ void nat_detection_note_send(struct NAT_DETECTION *detector, struct ETCP_SOCKET
|
||||
void nat_detection_observed_by_peer(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
|
||||
const struct sockaddr_storage *observed);
|
||||
|
||||
/* Учесть IP, сообщённый по защищённому TCP link: local — фактический локальный адрес соединения,
|
||||
* observed — адрес, увиденный пиром. Публичные IP сравниваются без портов; сохраняемый внешний порт всегда 0.
|
||||
* Непубличный источник/наблюдение и другая семья адресов не меняют результат; вызов — в потоке ядра. */
|
||||
void nat_detection_tcp_observed(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
|
||||
const struct sockaddr_storage *local, const struct sockaddr_storage *observed);
|
||||
|
||||
/* Обработать запрос наблюдения, полученный на socket: source — реальный IP:порт отправителя,
|
||||
* peer_key — его проверенный ключ (32 байта), tag/length — тег попытки/его размер в байтах.
|
||||
* Непубличный source отклоняется; результат возвращается через защищённый управляющий канал. */
|
||||
|
||||
Reference in new issue
Block a user