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.
 
 
 
 
 
 

76 lines
4.4 KiB

/* sock_match.c — классификация сокетов и сопоставление адресов при подключении */
#include "sock_match.h"
#include <string.h>
#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;
}