stcp: закрывать принятые коннекты в stcp_server_destroy (UAF server_tlink->conn после tcp_socket_remove)
This commit is contained in:
1 parent
6a674b3422
commit
5633903be0
3 files changed
+28
No files matched your search
@@ -27,6 +27,7 @@ void stcp_conn_set_on_close(struct stcp_conn *c, void (*cb)(struct stcp_conn *co
|
||||
|
||||
void stcp_conn_free(struct stcp_conn *c) {
|
||||
if (!c) return;
|
||||
stcp_server_remove_conn(c);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_conn_free: c=%p sock=%d sock_id=%p recv_buf=%p state=%d allocated=%d",
|
||||
(void*)c, (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (int)c->state, (int)c->allocated);
|
||||
if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; }
|
||||
@@ -292,6 +293,8 @@ void stcp_conn_do_close(struct stcp_conn *c, int err) {
|
||||
int prev = c->state;
|
||||
c->state = STCP_STATE_CLOSED;
|
||||
|
||||
stcp_server_remove_conn(c);
|
||||
|
||||
if (c->hs_timer) { uasync_cancel_timeout(c->ua, c->hs_timer); c->hs_timer = NULL; }
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_conn close is_server=%d prev_state=%d err=%d sock=%d", c->is_server, prev, err, (int)c->sock);
|
||||
|
||||
@@ -18,6 +18,7 @@ extern "C" {
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
struct stcp_server;
|
||||
|
||||
typedef void (*stcp_ping_cb)(int success, uint16_t rtt, void *arg);
|
||||
|
||||
@@ -143,6 +144,9 @@ struct stcp_conn {
|
||||
uint16_t recv_msg_size; // stream: size from decoded header
|
||||
void (*recv_on_chunk)(struct stcp_conn *c, uint8_t *data, size_t len);
|
||||
uint8_t rx_paused; // reading paused due to rx_queue overflow
|
||||
|
||||
struct stcp_server *srv; // владеющий сервер (accept-сторона), NULL для клиентских коннектов
|
||||
struct stcp_conn *srv_next; // звено в списке принятых коннектов сервера
|
||||
};
|
||||
|
||||
void stcp_conn_free(struct stcp_conn *c);
|
||||
@@ -175,6 +179,9 @@ void stcp_recv_try(struct stcp_conn *c);
|
||||
// unified close: closes socket, frees buffers, calls on_close. does NOT clean streams (stcp_conn_free does)
|
||||
void stcp_conn_do_close(struct stcp_conn *c, int err);
|
||||
|
||||
// снимает принятый коннект из списка владеющего сервера (реализация в stcp_server.c)
|
||||
void stcp_server_remove_conn(struct stcp_conn *c);
|
||||
|
||||
// handshake timeout callback (for use with uasync_set_timeout)
|
||||
void hs_timeout_cb(void *arg);
|
||||
|
||||
|
||||
@@ -36,8 +36,18 @@ struct stcp_server {
|
||||
uint8_t reality_enabled;
|
||||
struct reality_server_config reality_srv;
|
||||
char reality_dest[REALITY_DEST_MAX];
|
||||
|
||||
struct stcp_conn *conns; // список принятых (accept) коннектов — закрываются при destroy
|
||||
};
|
||||
|
||||
void stcp_server_remove_conn(struct stcp_conn *c) {
|
||||
if (!c || !c->srv) return;
|
||||
struct stcp_conn **pp = &c->srv->conns;
|
||||
while (*pp && *pp != c) pp = &(*pp)->srv_next;
|
||||
if (*pp) *pp = c->srv_next;
|
||||
c->srv = NULL;
|
||||
}
|
||||
|
||||
static void server_accept_cb(socket_t sock, void *arg);
|
||||
static void server_conn_read_cb(socket_t sock, void *arg);
|
||||
static void server_hs_phase1_cb(struct stcp_conn *c, uint8_t *data, size_t len);
|
||||
@@ -290,6 +300,10 @@ static void server_accept_cb(socket_t listen_sock, void *arg) {
|
||||
stcp_recv_set(c, SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT, 0, server_hs_phase1_cb);
|
||||
}
|
||||
c->hs_timer = uasync_set_timeout(c->ua, STCP_HS_TIMEOUT, c, hs_timeout_cb, "stcp_hs");
|
||||
|
||||
c->srv = srv;
|
||||
c->srv_next = srv->conns;
|
||||
srv->conns = c;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: accepted connection fd=%d", (int)cli_sock);
|
||||
}
|
||||
|
||||
@@ -356,6 +370,10 @@ void stcp_server_destroy(struct stcp_server *srv) {
|
||||
if (!srv) return;
|
||||
if (srv->listen_id) uasync_remove_socket_t(srv->ua, srv->listen_sock);
|
||||
if (srv->listen_sock != SOCKET_INVALID) socket_close_wrapper(srv->listen_sock);
|
||||
while (srv->conns) {
|
||||
struct stcp_conn *c = srv->conns;
|
||||
stcp_conn_do_close(c, 0); // снимает c из списка (c->srv) и каскадно закрывает серверный ETCP_LINK
|
||||
}
|
||||
u_free(srv);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server destroyed");
|
||||
}
|
||||
Reference in new issue
Block a user