/* sock_match.c — классификация сокетов и сопоставление адресов при подключении */ #include "sock_match.h" #include #include "../lib/platform_compat.h" #include "../lib/debug_config.h" #include "utun_instance.h" #include "etcp_connections.h" #include "config_parser.h" #include "topo_node.h" /* Нормализация NAT-типа: сырые (NAT_TYPE_*) или проверенные (NAT_VERIFIED_*) значения. */ static int nat_is_eim(uint8_t n) { return n == NAT_TYPE_EIM || n == NAT_VERIFIED_EIM; } static int nat_is_direct(uint8_t n) { return n == NAT_TYPE_DIRECT || n == NAT_VERIFIED_DIRECT; } uint8_t sock_target_class(uint8_t a_type, uint8_t tcfg, uint8_t tnat) { if (tcfg == CFG_SERVER_TYPE_PUBLIC || tcfg == CFG_SERVER_TYPE_UNKNOWN) return SOCK_TC_PUB; if (tcfg == CFG_SERVER_TYPE_PRIVATE || tcfg == CFG_SERVER_TYPE_LOCAL) return SOCK_TC_PRIV; /* CFG_SERVER_TYPE_NAT */ if (nat_is_eim(tnat) || nat_is_direct(tnat)) return (a_type == TOPO_ADDR_INTERFACE) ? SOCK_TC_PRIV : SOCK_TC_PUB; /* EIM=direct: NAT-адрес публичный, INTERFACE — приватный */ return (a_type == TOPO_ADDR_INTERFACE) ? SOCK_TC_PRIV : SOCK_TC_UNREACH; /* strict/unknown: публичный адрес не пробиваем */ } int sock_match(const struct sock_view* v, uint8_t a_type, uint8_t tcfg, uint8_t tnat, uint32_t target_ip4) { uint8_t tc = sock_target_class(a_type, tcfg, tnat); if (tc == SOCK_TC_UNREACH) return 0; /* strict/unknown NAT-адрес — напрямую не пробьём */ if (tc == SOCK_TC_PUB) { if (!v->has_inet) return 0; /* у нашего сокета нет интернета */ if (a_type == TOPO_ADDR_NAT && v->is_eim && nat_is_eim(tnat) && v->public_ip4 && v->public_ip4 == target_ip4) return 0; /* оба EIM за одним NAT — hairpin */ return 1; } return v->has_priv; /* приватный адрес — только с нашего приватного интерфейса */ } int sock_collect_views(struct UTUN_INSTANCE* inst, struct sock_view* out, int max) { if (!inst || !out || max <= 0) return 0; int n = 0; struct ETCP_SOCKET* s = inst->etcp_sockets; while (s && n < max) { if (s->local_addr.ss_family != AF_INET) { s = s->next; continue; } struct sock_view* v = &out[n++]; v->sock = s; v->family = AF_INET; v->is_tcp = s->is_tcp; v->local_ip4 = 0; v->public_ip4 = 0; /* Локальный адрес (interface, иначе local). */ { const struct sockaddr_storage* ia = s->interface_addr.ss_family ? &s->interface_addr : &s->local_addr; if (ia && ia->ss_family == AF_INET) v->local_ip4 = ((const struct sockaddr_in*)ia)->sin_addr.s_addr; } /* Публичный адрес (NAT): nat_addr, иначе локальный если он публичный. */ { const struct sockaddr_in* na = (const struct sockaddr_in*)&s->nat_addr; if (s->nat_addr.ss_family == AF_INET && na->sin_addr.s_addr != 0) v->public_ip4 = na->sin_addr.s_addr; } /* Классификация по адресу, а не по type из конфига: * приватный локальный адрес → можем ходить в LAN (has_priv); * исходящие считаем доступными (интернет + локалка). */ int local_public = v->local_ip4 && ip_is_public(v->local_ip4); v->has_priv = (uint8_t)!local_public; v->has_inet = 1; /* NAT-результат (главный критерий если есть) — для hairpin-фильтра. */ v->is_eim = (uint8_t)nat_is_eim(s->nat_type); if (!v->public_ip4 && local_public) v->public_ip4 = v->local_ip4; v->role = local_public ? SOCK_ROLE_DIRECT : (v->is_eim ? SOCK_ROLE_DIRECT : SOCK_ROLE_NAT); DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "sock_view[%d] sock=%s type=%d nat=%d role=%d inet=%d priv=%d eim=%d tcp=%d local=%08x public=%08x", n - 1, s->name, s->type, s->nat_type, v->role, v->has_inet, v->has_priv, v->is_eim, v->is_tcp, v->local_ip4, v->public_ip4); s = s->next; } return n; }