Browse Source

nat_detection: гасить NAT-чек при закрытии линка через link-status коллбэк (UAF na->link)

v2
evgeny 2 weeks ago
parent
commit
fc3295ce12
  1. 13
      src/routing_layer/nat_detection.c
  2. 24
      src/routing_layer/route_ping.c
  3. 3
      src/routing_layer/route_ping.h

13
src/routing_layer/nat_detection.c

@ -193,6 +193,17 @@ static void nat_detection_on_conn_down(struct ETCP_CONN* conn, int event, void*
}
}
/* Закрытие ОДНОГО линка (без разрыва conn): etcp_fire_link_status_cbk вызывается
* из etcp_link_close до u_free(link) — здесь link ещё валиден. Гасим NAT-чек этого
* линка, иначе na->link останется висячим указателем. */
static void nat_detection_on_link_status(struct ETCP_CONN* conn, struct ETCP_LINK* link,
int old_state, int old_status, void* arg) {
(void)conn; (void)old_state; (void)old_status;
struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg;
if (!nd || !link) return;
if (link->link_status == 0) route_ping_cancel_for_link(nd, link);
}
static void nat_detection_new_conn_cbk(struct ETCP_CONN* conn, void* arg) {
if (!conn || !conn->instance) return;
struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg;
@ -273,6 +284,7 @@ struct NAT_DETECTION* nat_detection_create(struct UTUN_INSTANCE* inst) {
nd->allow_nat_check_local = 0;
etcp_bind(inst, ETCP_ID_NAT_DETECTION, nat_detection_receive_cbk);
etcp_add_new_conn_cbk(inst, nat_detection_new_conn_cbk, nd);
etcp_add_link_status_cbk(inst, nat_detection_on_link_status, nd);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection initialized");
return nd;
}
@ -281,6 +293,7 @@ void nat_detection_destroy(struct NAT_DETECTION* nd) {
if (!nd) return;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection destroy");
etcp_remove_new_conn_cbk(nd->inst, nat_detection_new_conn_cbk, nd);
etcp_remove_link_status_cbk(nd->inst, nat_detection_on_link_status, nd);
etcp_unbind(nd->inst, ETCP_ID_NAT_DETECTION);
route_ping_destroy_pending(nd);
u_free(nd);

24
src/routing_layer/route_ping.c

@ -148,6 +148,30 @@ void route_ping_cancel_for_conn(struct NAT_DETECTION* nd, struct ETCP_CONN* conn
}
}
void route_ping_cancel_for_link(struct NAT_DETECTION* nd, struct ETCP_LINK* link) {
if (!nd || !link) return;
struct route_ping_pending** cur = &nd->ping_pending;
while (*cur) {
struct route_ping_pending* p = *cur;
struct nat_check_arg* na = (struct nat_check_arg*)p->arg;
if (na && na->link == link) {
*cur = p->next;
uint32_t rid = p->request_id;
if (p->timeout_timer) {
uasync_cancel_timeout(nd->inst->ua, p->timeout_timer);
p->timeout_timer = NULL;
}
p->cancelled = 1;
na->link = NULL;
u_free(na);
u_free(p);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "cancel_for_link: cancelled req_id=%08x link=%p", (unsigned)rid, (void*)link);
} else {
cur = &(*cur)->next;
}
}
}
void route_ping_destroy_pending(struct NAT_DETECTION* nd) {
if (!nd) return;
struct route_ping_pending* p = nd->ping_pending;

3
src/routing_layer/route_ping.h

@ -39,6 +39,9 @@ void route_ping_destroy_pending(struct NAT_DETECTION* nd);
/** Отменить pending для conn (при разрыве/реините соединения). */
void route_ping_cancel_for_conn(struct NAT_DETECTION* nd, struct ETCP_CONN* conn);
/** Отменить pending для конкретного линка (при закрытии линка без разрыва conn). */
void route_ping_cancel_for_link(struct NAT_DETECTION* nd, struct ETCP_LINK* link);
/** Входящий PING_REQ — мы посредник: пингуем цель, шлём PING_RESP. */
void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
struct ETCP_CONN* from_conn, const uint8_t* data, size_t len);

Loading…
Cancel
Save