Browse Source

ETCP: Add NAT IP:port tracking to handshake protocol

- Add peer_ipv4 (4 bytes) and peer_port (2 bytes) to INIT_RESPONSE packet
- Server now returns client's external IP:port in handshake response
- Client parses and stores NAT address in ETCP_LINK structure
- Track NAT address changes with nat_changes_count counter
- Track NAT address matches with nat_hits_count counter
- Legacy protocol support: detect old format without NAT info
- Add DEBUG logging for NAT address initialization/changes/hits

This allows clients behind NAT to discover their external address
during the ETCP handshake process.

All 21 tests pass successfully.
nodeinfo-routing-update
Evgeny 8 months ago
parent
commit
d08b14a8c1
  1. 62
      src/etcp_connections.c
  2. 6
      src/etcp_connections.h

62
src/etcp_connections.c

@ -655,6 +655,8 @@ static void etcp_connections_read_callback(int fd, void* arg) {
uint8_t id[8];
uint8_t mtu[2];
uint8_t link_id;
uint8_t peer_ipv4[4];
uint8_t peer_port[2];
} *ack_repl_hdr=(void*)&pkt->data[0];
ack_repl_hdr->code+=1;
memcpy(ack_repl_hdr->id, &e_sock->instance->node_id, 8);
@ -662,6 +664,18 @@ static void etcp_connections_read_callback(int fd, void* arg) {
ack_repl_hdr->mtu[0]=mtu>>8;
ack_repl_hdr->mtu[1]=mtu;
ack_repl_hdr->link_id = link->local_link_id;
// Add client's IP:port (so client behind NAT can know its external address)
if (addr.ss_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)&addr;
memcpy(ack_repl_hdr->peer_ipv4, &sin->sin_addr.s_addr, 4);
uint16_t port = ntohs(sin->sin_port);
ack_repl_hdr->peer_port[0] = port >> 8;
ack_repl_hdr->peer_port[1] = port & 0xFF;
} else {
// For IPv6, set to 0 (not supported for NAT traversal)
memset(ack_repl_hdr->peer_ipv4, 0, 4);
memset(ack_repl_hdr->peer_port, 0, 2);
}
pkt->data_len=sizeof(*ack_repl_hdr);
pkt->noencrypt_len=0;
pkt->link=link;
@ -707,6 +721,54 @@ static void etcp_connections_read_callback(int fd, void* arg) {
}
link->mtu = (pkt->data[offset++] << 8) | pkt->data[offset++];
link->remote_link_id = pkt->data[offset++];
// Parse NAT IP:port from response (new format includes 4+2 bytes)
if (pkt_len >= 18) {
uint32_t new_nat_ip = (pkt->data[offset] << 24) | (pkt->data[offset+1] << 16) |
(pkt->data[offset+2] << 8) | pkt->data[offset+3];
offset += 4;
uint16_t new_nat_port = (pkt->data[offset] << 8) | pkt->data[offset+1];
offset += 2;
// Check if NAT address changed
if (link->nat_ip == 0 && link->nat_port == 0) {
// First time receiving NAT info
link->nat_ip = new_nat_ip;
link->nat_port = new_nat_port;
char ip_str[INET_ADDRSTRLEN];
struct in_addr addr;
addr.s_addr = htonl(new_nat_ip);
inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str));
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] NAT address initialized: %s:%u",
link->etcp->log_name, ip_str, new_nat_port);
} else if (link->nat_ip != new_nat_ip || link->nat_port != new_nat_port) {
// NAT address changed
char old_ip_str[INET_ADDRSTRLEN], new_ip_str[INET_ADDRSTRLEN];
struct in_addr old_addr, new_addr;
old_addr.s_addr = htonl(link->nat_ip);
new_addr.s_addr = htonl(new_nat_ip);
inet_ntop(AF_INET, &old_addr, old_ip_str, sizeof(old_ip_str));
inet_ntop(AF_INET, &new_addr, new_ip_str, sizeof(new_ip_str));
link->nat_ip = new_nat_ip;
link->nat_port = new_nat_port;
link->nat_changes_count++;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] NAT address changed: %s:%u -> %s:%u (change #%u)",
link->etcp->log_name, old_ip_str, link->nat_port, new_ip_str, new_nat_port,
link->nat_changes_count);
} else {
// NAT address unchanged
link->nat_hits_count++;
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] NAT address unchanged (%u matches)",
link->etcp->log_name, link->nat_hits_count);
}
} else {
// Legacy format without NAT info
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] Received legacy INIT_RESPONSE without NAT info",
link->etcp->log_name);
}
if (offset > pkt_len) { errorcode=13; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: packet parsing overflow, offset=%zu, pkt_len=%zu", offset, pkt_len); goto ec_fr; }
// DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Received INIT_RESPONSE from server_node_id=%llu, mtu=%d", (unsigned long long)server_node_id, link->mtu);

6
src/etcp_connections.h

@ -84,6 +84,12 @@ struct ETCP_LINK {
size_t total_decrypted;
uint32_t bandwidth; // Link bandwidth in Kbits/sec
// NAT address tracking (from INIT_RESPONSE)
uint32_t nat_ip; // NAT IPv4 address (network byte order), 0 = not set
uint16_t nat_port; // NAT port (network byte order)
uint32_t nat_changes_count; // Counter of NAT address changes
uint32_t nat_hits_count; // Counter of NAT address matches (new init response with same IP:port)
};
// INITIALIZATION (создаёт listen-сокеты и подключения из конфига)

Loading…
Cancel
Save