etcp: exchange observed IPs on established TCP links

This commit is contained in:
evgeny committed 2026-10-17 19:46:02 +02:00
1 parent 95f209d098
commit 5eb3526186
2 files changed
+52

No files matched your search

+51
View File
@@ -1262,6 +1262,29 @@ void etcp_link_close(struct ETCP_LINK* link) {
// ====== TCP link helpers ======
/* По готовому STCP сообщает пиру его фактический IP; исходящий порт не является портом listener. */
static void tcp_send_observed_ip(struct ETCP_LINK *link) {
struct UTUN_INSTANCE *inst = link->etcp->instance;
if (!link->tcp_link || (!link->is_server && inst->config && inst->config->global.socks_enabled)) return;
const struct sockaddr_storage *peer = stcp_link_get_peer_addr(link->tcp_link);
if (!peer) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP IP report cannot read peer socket=%s", link->etcp->log_name); return; }
struct ETCP_DGRAM *pkt = memory_pool_alloc(inst->pkt_pool);
if (!pkt) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "TCP IP report allocation failed peer=%s", link->etcp->log_name); return; }
pkt->link = link; pkt->data_len = 18; pkt->noencrypt_len = 0;
memset(pkt->data, 0, pkt->data_len); pkt->data[0] = ETCP_TCP_ADDRESS;
if (peer->ss_family == AF_INET) {
pkt->data[1] = 4; memcpy(pkt->data + 2, &((const struct sockaddr_in *)peer)->sin_addr, 4);
} else if (peer->ss_family == AF_INET6) {
pkt->data[1] = 6; memcpy(pkt->data + 2, &((const struct sockaddr_in6 *)peer)->sin6_addr, 16);
} else {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP IP report unsupported family=%d", peer->ss_family);
memory_pool_free(inst->pkt_pool, pkt); return;
}
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "TCP IP report peer=%s observed=%s", link->etcp->log_name, sockaddr_storage_to_str(peer).str);
if (etcp_encrypt_send(pkt) < 0) DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP IP report send failed");
memory_pool_free(inst->pkt_pool, pkt);
}
// Поднять TCP-линк в ready: синхронизация reset-эпохи (gop/rid), keepalive, ed25519,
// mark initialized + link_status=1, уведомить коннект и loadbalancer.
void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
@@ -1297,6 +1320,7 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP link %d UP (mtu=%d init=%d up=%d tcp_links=%d)",
etcp->log_name, link->local_link_id, link->mtu,
etcp->initialized, etcp->links_up, etcp->tcp_link_count);
tcp_send_observed_ip(link);
}
// Повторная попытка STCP-подключения с экспоненциальным backoff (до 30 с).
@@ -2636,6 +2660,33 @@ int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
uint8_t pkt_code = pkt->data[0];
if (pkt_code == ETCP_TCP_ADDRESS) {
struct UTUN_INSTANCE *inst = link->etcp->instance;
static const uint8_t zero[12];
if (!link->is_tcp || pkt->data_len != 18 ||
(pkt->data[1] != 4 && pkt->data[1] != 6) ||
(pkt->data[1] == 4 && memcmp(pkt->data + 6, zero, sizeof(zero)))) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP IP report invalid transport/format peer=%s size=%u",
link->etcp->log_name, pkt->data_len);
memory_pool_free(inst->pkt_pool, pkt); return 0;
}
if (!link->is_server && inst->config && inst->config->global.socks_enabled) {
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "TCP IP report ignored through SOCKS peer=%s", link->etcp->log_name);
memory_pool_free(inst->pkt_pool, pkt); return 0;
}
struct sockaddr_storage observed = {0};
if (pkt->data[1] == 4) {
observed.ss_family = AF_INET; memcpy(&((struct sockaddr_in *)&observed)->sin_addr, pkt->data + 2, 4);
} else {
observed.ss_family = AF_INET6; memcpy(&((struct sockaddr_in6 *)&observed)->sin6_addr, pkt->data + 2, 16);
}
link->local_as_seen_by_peer = observed;
const struct sockaddr_storage *local = stcp_link_get_local_addr(link->tcp_link);
if (local && inst->nat_det && link->conn) nat_detection_tcp_observed(inst->nat_det, link, local, &observed);
else if (!local) DEBUG_WARN(DEBUG_CATEGORY_NAT, "TCP IP report cannot read local socket peer=%s", link->etcp->log_name);
memory_pool_free(inst->pkt_pool, pkt); return 0;
}
#ifdef UTUN_HAVE_STANDBY
{
char who[256];
+1
View File
@@ -44,6 +44,7 @@ extern "C" {
#define ETCP_PING 0x06
#define ETCP_PONG 0x07
#define ETCP_KEEPALIVE 0x08
#define ETCP_TCP_ADDRESS 0x0d // STCP control: code + family(4/6) + observed IP(16), без порта
#define ETCP_PING_FLAG_WANT_RTT 0x01 // в PONG: хочу получить RTT от пингера
#define ETCP_PING_FLAG_SEND_RTT 0x02 // в PING: несу RTT для получателя