You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
5.8 KiB
88 lines
5.8 KiB
/** |
|
* @file test_sock_match.c |
|
* @brief Unit-тесты классификации сокетов и сопоставления адресов (sock_match). |
|
* |
|
* Тестирует только чистую логику sock_role_of / sock_target_class / sock_match |
|
* без сети и без UTUN_INSTANCE — с синтетическими struct sock_view и адресами. |
|
*/ |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include "../src/routing_layer/sock_match.h" |
|
#include "../src/config_parser.h" |
|
#include "../src/transport_layer/etcp_connections.h" |
|
#include "../src/routing_layer/topo_node.h" |
|
#include "../lib/platform_compat.h" |
|
|
|
static int fails = 0; |
|
static int checks = 0; |
|
|
|
#define CHECK(cond, msg) do { checks++; if (!(cond)) { fails++; printf("FAIL: %s\n", msg); } } while (0) |
|
|
|
static struct sock_view mk_view(uint8_t role, uint8_t has_inet, uint8_t has_priv, uint8_t is_eim, uint32_t pub4) { |
|
struct sock_view v; memset(&v, 0, sizeof(v)); |
|
v.role = role; v.has_inet = has_inet; v.has_priv = has_priv; v.is_eim = is_eim; v.public_ip4 = pub4; |
|
return v; |
|
} |
|
|
|
/* Классификация IPv4-адреса (network byte order): публичный/маршрутизируемый или нет. |
|
* Адрес задаём «логически» (старший байт = первый октет) и переводим в s_addr через htonl. */ |
|
static void test_ip_is_public(void) { |
|
CHECK(ip_is_public(htonl(0x08080808u)) == 1, "8.8.8.8 public"); |
|
CHECK(ip_is_public(htonl(0x01020304u)) == 1, "1.2.3.4 public"); |
|
CHECK(ip_is_public(htonl(0xC0A80101u)) == 0, "192.168.1.1 private"); |
|
CHECK(ip_is_public(htonl(0x0A000001u)) == 0, "10.0.0.1 private"); |
|
CHECK(ip_is_public(htonl(0xAC100001u)) == 0, "172.16.0.1 private"); |
|
CHECK(ip_is_public(htonl(0xAC1F0001u)) == 0, "172.31.0.1 private"); |
|
CHECK(ip_is_public(htonl(0x64400001u)) == 0, "100.64.0.1 CGNAT"); |
|
CHECK(ip_is_public(htonl(0x7F000001u)) == 0, "127.0.0.1 loopback"); |
|
CHECK(ip_is_public(htonl(0xA9FE0101u)) == 0, "169.254.1.1 link-local"); |
|
CHECK(ip_is_public(htonl(0x00000000u)) == 0, "0.0.0.0"); |
|
CHECK(ip_is_public(htonl(0xE0000001u)) == 0, "224.0.0.1 multicast"); |
|
CHECK(ip_is_public(htonl(0xFFFFFFFFu)) == 0, "255.255.255.255 reserved"); |
|
} |
|
|
|
static void test_target_class(void) { |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_PUBLIC, NAT_TYPE_UNKNOWN) == SOCK_TC_PUB, "public INTERFACE -> PUB"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_UNKNOWN, NAT_TYPE_UNKNOWN) == SOCK_TC_PUB, "unknown -> PUB"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_LOCAL, NAT_TYPE_UNKNOWN) == SOCK_TC_PRIV, "local -> PRIV"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_PRIVATE, NAT_TYPE_UNKNOWN) == SOCK_TC_PRIV, "private -> PRIV"); |
|
CHECK(sock_target_class(TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_EIM) == SOCK_TC_PUB, "nat+EIM NAT-addr -> PUB"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_EIM) == SOCK_TC_PRIV, "nat+EIM INTERFACE -> PRIV"); |
|
CHECK(sock_target_class(TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_DIRECT) == SOCK_TC_PUB, "nat+DIRECT NAT-addr -> PUB"); |
|
CHECK(sock_target_class(TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_STRICT) == SOCK_TC_UNREACH, "nat+STRICT NAT-addr -> UNREACH"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_STRICT) == SOCK_TC_PRIV, "nat+STRICT INTERFACE -> PRIV"); |
|
CHECK(sock_target_class(TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_TYPE_UNKNOWN) == SOCK_TC_UNREACH, "nat+unknown NAT-addr -> UNREACH"); |
|
CHECK(sock_target_class(TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_NAT, NAT_TYPE_UNKNOWN) == SOCK_TC_PRIV, "nat+unknown INTERFACE -> PRIV"); |
|
} |
|
|
|
static void test_match(void) { |
|
uint32_t pub = 0x01020304u; /* произвольный "публичный" IP */ |
|
struct sock_view direct = mk_view(SOCK_ROLE_DIRECT, 1, 0, 0, pub); |
|
struct sock_view natout = mk_view(SOCK_ROLE_NAT, 1, 1, 0, 0); |
|
struct sock_view local = mk_view(SOCK_ROLE_LOCAL, 0, 1, 0, 0); |
|
|
|
/* наш DIRECT (публичный) */ |
|
CHECK(sock_match(&direct, TOPO_ADDR_NAT, CFG_SERVER_TYPE_PUBLIC, NAT_TYPE_UNKNOWN, pub) == 1, "DIRECT->PUB ok"); |
|
CHECK(sock_match(&direct, TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_LOCAL, NAT_TYPE_UNKNOWN, 0) == 0, "DIRECT->PRIV нет приватного интерфейса"); |
|
/* наш NAT (outbound-only) */ |
|
CHECK(sock_match(&natout, TOPO_ADDR_NAT, CFG_SERVER_TYPE_PUBLIC, NAT_TYPE_UNKNOWN, pub) == 1, "NAT->PUB ok"); |
|
CHECK(sock_match(&natout, TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_STRICT, 0) == 1, "NAT->PRIV (есть приватный)"); |
|
/* наш LOCAL (без интернета) */ |
|
CHECK(sock_match(&local, TOPO_ADDR_NAT, CFG_SERVER_TYPE_PUBLIC, NAT_TYPE_UNKNOWN, pub) == 0, "LOCAL->PUB нет интернета"); |
|
CHECK(sock_match(&local, TOPO_ADDR_INTERFACE, CFG_SERVER_TYPE_LOCAL, NAT_TYPE_UNKNOWN, 0) == 1, "LOCAL->PRIV ок (LAN)"); |
|
/* UNREACH цель */ |
|
CHECK(sock_match(&direct, TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_STRICT, pub) == 0, "строгий NAT-адрес недостижим"); |
|
/* hairpin: оба EIM, одинаковый публичный IP */ |
|
struct sock_view eim = mk_view(SOCK_ROLE_DIRECT, 1, 1, 1, pub); |
|
CHECK(sock_match(&eim, TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_EIM, pub) == 0, "hairpin (одинаковый публичный IP)"); |
|
CHECK(sock_match(&eim, TOPO_ADDR_NAT, CFG_SERVER_TYPE_NAT, NAT_VERIFIED_EIM, 0x05060708u) == 1, "EIM разные публичные IP -> ok"); |
|
} |
|
|
|
int main(void) { |
|
test_ip_is_public(); |
|
test_target_class(); |
|
test_match(); |
|
if (fails) { printf("RESULT: %d/%d failed\n", fails, checks); return 1; } |
|
printf("RESULT: all %d checks passed\n", checks); |
|
return 0; |
|
}
|
|
|