diff --git a/src/routing_layer/etcp_router.c b/src/routing_layer/etcp_router.c index a5e2e238..593d6059 100644 --- a/src/routing_layer/etcp_router.c +++ b/src/routing_layer/etcp_router.c @@ -33,7 +33,7 @@ static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn); static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn); static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* wire, size_t wire_len); static void router_send_ctrl(struct ETCP_ROUTER_CONN* rconn, uint8_t flag_bits); -static void router_send_rst(struct ETCP_ROUTER_CONN* rconn); +static void router_send_rst(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn); static void router_restart_send(struct ETCP_ROUTER_CONN* rconn); static struct ETCP_CONN* router_send_conn(struct ETCP_ROUTER_CONN* rconn); static void router_send_kick(struct ETCP_ROUTER_CONN* rconn); @@ -50,7 +50,7 @@ static void router_conn_reset(struct ETCP_ROUTER_CONN* rconn); static void free_entry(struct ll_entry* e) { queue_dgram_free(e); queue_entry_free(e); } static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN* rconn, uint32_t seq, uint64_t src_node_id, uint16_t ack_ts); static void router_forward_transit(struct UTUN_INSTANCE* inst, struct ll_entry* entry, struct SVC_ROUTE_HDR* hdr); -static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN** prconn, struct SVC_ROUTE_HDR* hdr, size_t wire_len); +static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN** prconn, struct SVC_ROUTE_HDR* hdr, size_t wire_len, struct ETCP_CONN* conn); static void router_handle_data_packet(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, uint32_t seq, const uint8_t* wire, size_t wire_len); static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_INFLIGHT* inf); static void router_retrans_schedule(struct ETCP_ROUTER_CONN* rconn); @@ -153,6 +153,27 @@ void etcp_router_transit_queues_destroy(struct ETCP_CONN* conn) { conn->transit_queues = NULL; } +// Сбросить recv_conn у всех ROUTER_CONN, ссылающихся на уничтожаемый ETCP_CONN. +// recv_conn — заимствованный указатель; без очистки он висит после u_free(conn) (UAF). +void etcp_router_conn_destroyed(struct ETCP_CONN* conn) { + if (!conn || !conn->instance || !conn->instance->router_conns) return; + struct ll_queue* q = conn->instance->router_conns; + for (uint32_t slot = 0; slot < q->hash_size; slot++) { + struct ll_entry* entry = q->hash_table[slot]; + while (entry) { + struct ll_entry* next = entry->hash_next; + struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)entry; + if (rconn->recv_conn == conn) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, + "router: clear recv_conn remote=%016llx svc_id=%u (conn destroyed)", + (unsigned long long)rconn->remote_node_id, rconn->svc_id); + rconn->recv_conn = NULL; + } + entry = next; + } + } +} + // ==================================================================== // Управление ROUTER_CONN // ==================================================================== @@ -251,10 +272,9 @@ static void router_send_ctrl(struct ETCP_ROUTER_CONN* rconn, uint8_t flag_bits) } // Отправка RST удалённой стороне — сброс чужой «старой» сессии. -// Идёт через recv_conn: в асимметричной топологии route-lookup до remote вернёт NULL. -static void router_send_rst(struct ETCP_ROUTER_CONN* rconn) { +// conn — живой физический conn, доставивший пакет (recv_conn может быть уже устаревшим). +static void router_send_rst(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn) { struct UTUN_INSTANCE* inst = rconn->inst; - struct ETCP_CONN* conn = rconn->recv_conn; if (!conn) conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, rconn->group_id), rconn->remote_node_id); if (!conn) { DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_rst: no route to %016llx svc_id=%u", @@ -1069,7 +1089,7 @@ static void router_forward_transit(struct UTUN_INSTANCE* inst, struct ll_entry* } static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CONN** prconn, - struct SVC_ROUTE_HDR* hdr, size_t wire_len) { + struct SVC_ROUTE_HDR* hdr, size_t wire_len, struct ETCP_CONN* conn) { (void)wire_len; struct ETCP_ROUTER_CONN* rconn = *prconn; if (!(hdr->flags & ROUTER_FLAG_START)) return 0; // не START — не рестарт @@ -1091,7 +1111,7 @@ static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROU "router: peer reset_id=%016llx != mine=%016llx — master keeps epoch, RST to %016llx svc_id=%u", (unsigned long long)peer_rid, (unsigned long long)rconn->reset_id, (unsigned long long)hdr->src_node_id, hdr->svc_id); - router_send_rst(rconn); + router_send_rst(rconn, conn); return 0; } else { // slave принимает эпоху мастера и ресетится. @@ -1207,11 +1227,11 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) rconn = etcp_router_conn_get(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id); if (!rconn) { free_entry(entry); return; } } - if (router_check_peer_restart(inst, &rconn, hdr, entry->len) != 0) { free_entry(entry); return; } + if (router_check_peer_restart(inst, &rconn, hdr, entry->len, conn) != 0) { free_entry(entry); return; } // Сервер после рестарта «ждёт START»: пришёл не-START пакет от старой сессии → RST. if (!rconn->peer_sync_done && !(hdr->flags & ROUTER_FLAG_START)) { - router_send_rst(rconn); + router_send_rst(rconn, conn); free_entry(entry); return; } diff --git a/src/routing_layer/etcp_router.h b/src/routing_layer/etcp_router.h index d0bd71a3..e07dbcc4 100644 --- a/src/routing_layer/etcp_router.h +++ b/src/routing_layer/etcp_router.h @@ -245,6 +245,9 @@ void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t group_id, uin // Удалить все транзитные очереди соединения (вызывается при закрытии ETCP_CONN) void etcp_router_transit_queues_destroy(struct ETCP_CONN* conn); +// Сбросить recv_conn у всех ROUTER_CONN, ссылающихся на уничтожаемый ETCP_CONN. +void etcp_router_conn_destroyed(struct ETCP_CONN* conn); + #ifdef __cplusplus } diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index f91cb253..3fe2f45a 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -407,6 +407,7 @@ void etcp_connection_close(struct ETCP_CONN* etcp) { routing_del_conn(etcp); etcp_router_transit_queues_destroy(etcp); + etcp_router_conn_destroyed(etcp); if (etcp->normalizer) { pn_deinit((struct PKTNORM*)etcp->normalizer); etcp->normalizer = NULL; etcp->send_input_q = NULL; }