tests: cover TCP NAT presence and zero-port address publication
This commit is contained in:
1 parent
c42d75c2f5
commit
62aee9f01c
1 file changed
+71
-3
@@ -48,6 +48,75 @@ static void check_snapshot(struct UTUN_INSTANCE *owner, struct ETCP_SOCKET *sock
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
|
||||
/* Один TCP-пир даёт только наличие NAT и IP:0; локальный IP сам по себе достаточен для NAT. */
|
||||
static void test_tcp_presence(void) {
|
||||
struct nat_fixture fixture; nat_fixture_init(&fixture);
|
||||
struct UTUN_INSTANCE *owner = nat_fixture_node(&fixture, "127.0.0.2", NULL,
|
||||
"[server:tcp]\naddr=127.0.0.2:0\ntype=public\ntransport=tcp\n");
|
||||
struct UTUN_INSTANCE *peer = nat_fixture_node(&fixture, "127.0.0.3", NULL,
|
||||
"[server:tcp]\naddr=127.0.0.3:0\ntype=public\ntransport=tcp\n");
|
||||
nat_detection_set_automatic(owner->nat_det, 0); nat_detection_set_automatic(peer->nat_det, 0);
|
||||
struct ETCP_SOCKET *socket = test_etcp_bound_socket(owner, "tcp");
|
||||
struct ETCP_CONN *connection = nat_fixture_connect(&fixture, owner, "tcp", peer);
|
||||
wait_profile(&fixture, socket, ADDRESS_MAP_UNCHANGED, ADDRESS_IN_UNKNOWN);
|
||||
struct ETCP_LINK *link = connection->links;
|
||||
while (link && !link->is_tcp) link = link->next;
|
||||
assert(link && link->conn == socket && link->local_as_seen_by_peer.ss_family == AF_INET);
|
||||
assert(!((struct sockaddr_in *)&link->local_as_seen_by_peer)->sin_port);
|
||||
assert(route_ping_addr_equal(&socket->nat_addr, &socket->local_addr, 0));
|
||||
assert(!((struct sockaddr_in *)&socket->nat_addr)->sin_port);
|
||||
struct nat_check_status status;
|
||||
assert(!nat_detection_get_status(owner->nat_det, socket, &status) && !status.rounds && !status.helper);
|
||||
|
||||
/* В обычном режиме loopback — непубличный IP: NAT известен без второго пира и без пробы listener. */
|
||||
nat_detection_set_allow_local(owner->nat_det, 0);
|
||||
nat_detection_socket_removed(owner->nat_det, socket);
|
||||
wait_profile(&fixture, socket, ADDRESS_MAP_UNKNOWN, ADDRESS_IN_UNKNOWN);
|
||||
assert(!socket->nat_addr.ss_family);
|
||||
struct sockaddr_storage remote = link->remote_addr, local = socket->interface_addr, observed = {0};
|
||||
((struct sockaddr_in *)&link->remote_addr)->sin_addr.s_addr = htonl(UINT32_C(0xc633640b));
|
||||
struct sockaddr_in *external = (struct sockaddr_in *)&observed;
|
||||
external->sin_family = AF_INET; external->sin_addr.s_addr = htonl(UINT32_C(0xcb00712c)); external->sin_port = htons(5555);
|
||||
nat_detection_tcp_observed(owner->nat_det, link, &local, &observed);
|
||||
assert(socket->address_profile.mapping == ADDRESS_MAP_UNKNOWN && socket->address_profile.source == ADDRESS_SOURCE_ETCP);
|
||||
assert(route_ping_addr_equal(&socket->nat_addr, &observed, 0) && !((struct sockaddr_in *)&socket->nat_addr)->sin_port);
|
||||
check_snapshot(owner, socket);
|
||||
struct TOPO_NODE *snapshot = topo_node_registry_find(owner->topo_groups, owner->node_id);
|
||||
int found = 0;
|
||||
for (const struct TOPO_ADDR4 *a = snapshot->v4_addrs; a; a = a->next) {
|
||||
if (a->socket_id != socket->sock_id || a->type != TOPO_ADDR_NAT) continue;
|
||||
assert(!a->port && (a->protocol & TOPO_PROTO_TCP) && !memcmp(a->addr, &external->sin_addr, 4)); found++;
|
||||
}
|
||||
assert(found == 1);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
assert(sqlite3_prepare_v2(owner->topo_sqlite_db,
|
||||
"SELECT port,addr_type FROM node_addresses WHERE node_id=? AND socket_id=? AND address_kind=?",
|
||||
-1, &statement, NULL) == SQLITE_OK);
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)owner->node_id); sqlite3_bind_int(statement, 2, socket->sock_id);
|
||||
sqlite3_bind_int(statement, 3, TOPO_ADDR_NAT);
|
||||
assert(sqlite3_step(statement) == SQLITE_ROW && !sqlite3_column_int(statement, 0));
|
||||
assert(sqlite3_column_int(statement, 1) == ADDR_TYPE_NAT); sqlite3_finalize(statement);
|
||||
|
||||
/* Совпавший публичный IP означает отсутствие NAT даже при разных портах. */
|
||||
local = observed; ((struct sockaddr_in *)&local)->sin_port = htons(12345);
|
||||
nat_detection_tcp_observed(owner->nat_det, link, &local, &observed);
|
||||
assert(socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && socket->address_profile.inbound == ADDRESS_IN_UNKNOWN);
|
||||
external->sin_addr.s_addr = htonl(UINT32_C(0xcb00712d));
|
||||
nat_detection_tcp_observed(owner->nat_det, link, &local, &observed);
|
||||
assert(socket->address_profile.mapping == ADDRESS_MAP_UNKNOWN);
|
||||
struct sockaddr_storage saved = socket->nat_addr;
|
||||
external->sin_addr.s_addr = htonl(UINT32_C(0xc0a80101));
|
||||
nat_detection_tcp_observed(owner->nat_det, link, &local, &observed);
|
||||
assert(route_ping_addr_equal(&socket->nat_addr, &saved, 1));
|
||||
external->sin_addr.s_addr = htonl(UINT32_C(0xcb00712c));
|
||||
link->remote_addr = remote; /* LAN-узел также не годится для наблюдения интернет-адреса. */
|
||||
nat_detection_tcp_observed(owner->nat_det, link, &local, &observed);
|
||||
assert(route_ping_addr_equal(&socket->nat_addr, &saved, 1));
|
||||
assert(!nat_detection_get_status(owner->nat_det, socket, &status) && !status.rounds && !status.helper);
|
||||
nat_fixture_cleanup(&fixture);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS TCP NAT presence: one peer, public/private IP, ignored ports, signed IP:0 and SQLite");
|
||||
}
|
||||
|
||||
/* Недостаточная UTUN-группа и достаточная CHAT-группа; helper доступен только через TCP next hop. */
|
||||
static void test_all_groups_tcp(void) {
|
||||
struct nat_fixture fixture; nat_fixture_init(&fixture);
|
||||
@@ -177,13 +246,11 @@ int main(void) {
|
||||
assert(connection->links && connection->links->remote_socket_id == observer_socket->sock_id);
|
||||
assert(connection->links->local_as_seen_by_peer.ss_family == AF_INET);
|
||||
assert(route_ping_addr_equal(&connection->links->local_as_seen_by_peer, &socket->local_addr, 1));
|
||||
/* Подписанная запись A нужна независимому испытанию настоящего TCP listener. */
|
||||
nat_fixture_connect(&fixture, observer, "udp", owner);
|
||||
owner->ntp.reachable = 0; /* ни измерение, ни публикация не требуют интернет-NTP */
|
||||
nat_detection_request_check_all(owner->nat_det);
|
||||
wait_profile(&fixture, socket, ADDRESS_MAP_UNCHANGED, ADDRESS_IN_OPEN);
|
||||
wait_profile(&fixture, second_socket, ADDRESS_MAP_UNCHANGED, ADDRESS_IN_OPEN);
|
||||
wait_profile(&fixture, tcp, ADDRESS_MAP_UNCHANGED, ADDRESS_IN_OPEN);
|
||||
|
||||
struct nat_check_status status;
|
||||
assert(nat_detection_get_status(owner->nat_det, socket, &status) == 0);
|
||||
@@ -194,7 +261,7 @@ int main(void) {
|
||||
assert(status.round != second_status.round);
|
||||
check_snapshot(owner, socket);
|
||||
check_snapshot(owner, second_socket);
|
||||
check_snapshot(owner, tcp);
|
||||
assert(tcp->address_profile.mapping == ADDRESS_MAP_UNKNOWN && tcp->address_profile.inbound == ADDRESS_IN_UNKNOWN);
|
||||
|
||||
/* Профиль B не заимствует профиль A, даже когда транспорт переиспользуется в обе стороны. */
|
||||
assert(!route_ping_addr_equal(&socket->local_addr, &observer_socket->local_addr, 1));
|
||||
@@ -232,5 +299,6 @@ int main(void) {
|
||||
|
||||
nat_fixture_cleanup(&fixture);
|
||||
test_all_groups_tcp();
|
||||
test_tcp_presence();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user