From 33ac346ba8862c15a92eea0f4a087c964c1e8de5 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 18 Jan 2022 16:44:34 +0100 Subject: [PATCH] MINOR: quic: initialize ssl_sock_ctx alongside the quic_conn Extract the allocation of ssl_sock_ctx from qc_conn_init to a dedicated function qc_conn_alloc_ssl_ctx. This function is called just after allocating a new quic_conn, without waiting for the initialization of the connection. It allocates the ssl_sock_ctx and the quic_conn tasklet. This change is now possible because the SSL callbacks are dealing with a quic_conn instance. This change is required to be able to delay the connection allocation and handle handshake packets without it. --- src/xprt_quic.c | 265 ++++++++++++++++++++---------------------------- 1 file changed, 111 insertions(+), 154 deletions(-) diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 71d3b47ef0..4ece434a75 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -4250,6 +4250,110 @@ static int parse_retry_token(const unsigned char *token, uint64_t token_len, return 0; } +/* Try to allocate the <*ssl> SSL session object for QUIC connection + * with as SSL context inherited settings. Also set the transport + * parameters of this session. + * This is the responsibility of the caller to check the validity of all the + * pointers passed as parameter to this function. + * Return 0 if succeeded, -1 if not. If failed, sets the ->err_code member of conn> to + * CO_ER_SSL_NO_MEM. + */ +static int qc_ssl_sess_init(struct quic_conn *qc, SSL_CTX *ssl_ctx, SSL **ssl, + unsigned char *params, size_t params_len) +{ + int retry; + + retry = 1; + retry: + *ssl = SSL_new(ssl_ctx); + if (!*ssl) { + if (!retry--) + goto err; + + pool_gc(NULL); + goto retry; + } + + if (!SSL_set_quic_method(*ssl, &ha_quic_method) || + !SSL_set_ex_data(*ssl, ssl_qc_app_data_index, qc) || + !SSL_set_quic_transport_params(*ssl, qc->enc_params, qc->enc_params_len)) { + goto err; + + SSL_free(*ssl); + *ssl = NULL; + if (!retry--) + goto err; + + pool_gc(NULL); + goto retry; + } + + return 0; + + err: + qc->conn->err_code = CO_ER_SSL_NO_MEM; + return -1; +} + +/* Allocate the ssl_sock_ctx from connection . This creates the tasklet + * used to process received packets. The allocated context is stored in + * . + * + * Returns 0 on success else non-zero. + */ +int qc_conn_alloc_ssl_ctx(struct quic_conn *qc) +{ + struct bind_conf *bc = qc->li->bind_conf; + struct ssl_sock_ctx *ctx = NULL; + + ctx = pool_zalloc(pool_head_quic_conn_ctx); + if (!ctx) + goto err; + + ctx->wait_event.tasklet = tasklet_new(); + if (!ctx->wait_event.tasklet) + goto err; + + ctx->wait_event.tasklet->process = quic_conn_io_cb; + ctx->wait_event.tasklet->context = ctx; + ctx->wait_event.events = 0; + ctx->subs = NULL; + ctx->xprt_ctx = NULL; + ctx->qc = qc; + + /* Set tasklet tid based on the SCID selected by us for this + * connection. The upper layer will also be binded on the same thread. + */ + qc->tid = ctx->wait_event.tasklet->tid = quic_get_cid_tid(&qc->scid); + + if (qc_is_listener(qc)) { + if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl, + qc->enc_params, qc->enc_params_len) == -1) { + goto err; + } + + /* Enabling 0-RTT */ + if (bc->ssl_conf.early_data) + SSL_set_quic_early_data_enabled(ctx->ssl, 1); + + SSL_set_accept_state(ctx->ssl); + } + + ctx->xprt = xprt_get(XPRT_QUIC); + + /* Store the allocated context in . */ + HA_ATOMIC_STORE(&qc->xprt_ctx, ctx); + + return 0; + + err: + if (ctx && ctx->wait_event.tasklet) + tasklet_free(ctx->wait_event.tasklet); + pool_free(pool_head_quic_conn_ctx, ctx); + + return 1; +} + static ssize_t qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, struct quic_rx_packet *pkt, struct quic_dgram_ctx *dgram_ctx, @@ -4414,6 +4518,9 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (!qc->enc_params_len) goto err; + if (qc_conn_alloc_ssl_ctx(qc)) + goto err; + /* NOTE: the socket address has been concatenated to the destination ID * chosen by the client for Initial packets. */ @@ -5356,178 +5463,28 @@ static int quic_conn_unsubscribe(struct connection *conn, void *xprt_ctx, int ev return conn_unsubscribe(conn, xprt_ctx, event_type, es); } -/* Try to allocate the <*ssl> SSL session object for QUIC connection - * with as SSL context inherited settings. Also set the transport - * parameters of this session. - * This is the responsibility of the caller to check the validity of all the - * pointers passed as parameter to this function. - * Return 0 if succeeded, -1 if not. If failed, sets the ->err_code member of conn> to - * CO_ER_SSL_NO_MEM. - */ -static int qc_ssl_sess_init(struct quic_conn *qc, SSL_CTX *ssl_ctx, SSL **ssl, - unsigned char *params, size_t params_len) -{ - int retry; - - retry = 1; - retry: - *ssl = SSL_new(ssl_ctx); - if (!*ssl) { - if (!retry--) - goto err; - - pool_gc(NULL); - goto retry; - } - - if (!SSL_set_quic_method(*ssl, &ha_quic_method) || - !SSL_set_ex_data(*ssl, ssl_qc_app_data_index, qc) || - !SSL_set_quic_transport_params(*ssl, qc->enc_params, qc->enc_params_len)) { - goto err; - - SSL_free(*ssl); - *ssl = NULL; - if (!retry--) - goto err; - - pool_gc(NULL); - goto retry; - } - - return 0; - - err: - qc->conn->err_code = CO_ER_SSL_NO_MEM; - return -1; -} - -/* Initialize a QUIC connection (quic_conn struct) to be attached to - * connection with as address of the xprt context. - * Returns 1 if succeeded, 0 if not. +/* Store in the context attached to . + * Returns always 0. */ static int qc_conn_init(struct connection *conn, void **xprt_ctx) { - struct ssl_sock_ctx *ctx = NULL; struct quic_conn *qc = NULL; TRACE_ENTER(QUIC_EV_CONN_NEW, conn); + /* do not store the context if already set */ if (*xprt_ctx) goto out; - ctx = pool_zalloc(pool_head_quic_conn_ctx); - if (!ctx) { - conn->err_code = CO_ER_SYS_MEMLIM; - goto err; - } - - ctx->wait_event.tasklet = tasklet_new(); - if (!ctx->wait_event.tasklet) { - conn->err_code = CO_ER_SYS_MEMLIM; - goto err; - } - - ctx->wait_event.tasklet->process = quic_conn_io_cb; - ctx->wait_event.tasklet->context = ctx; - ctx->wait_event.events = 0; - HA_ATOMIC_STORE(&ctx->conn, conn); - ctx->subs = NULL; - ctx->xprt_ctx = NULL; - - ctx->xprt = xprt_get(XPRT_QUIC); - if (objt_server(conn->target)) { - /* Server */ - struct server *srv = __objt_server(conn->target); - unsigned char dcid[QUIC_HAP_CID_LEN]; - int ssl_err, ipv4; - - ssl_err = SSL_ERROR_NONE; - if (RAND_bytes(dcid, sizeof dcid) != 1) - goto err; - - ipv4 = conn->dst->ss_family == AF_INET; - qc = qc_new_conn(QUIC_PROTOCOL_VERSION_DRAFT_28, ipv4, - dcid, sizeof dcid, 0, NULL, 0, 0, srv); - if (qc == NULL) - goto err; - - ctx->qc = qc; - - /* Insert our SCID, the connection ID for the QUIC client. */ - ebmb_insert(&srv->cids, &qc->scid_node, qc->scid.len); - - conn->qc = qc; - qc->conn = conn; - if (!qc_new_isecs(qc, initial_salt_v1, sizeof initial_salt_v1, - dcid, sizeof dcid, 0)) - goto err; - - qc->rx.params = srv->quic_params; - /* Copy the initial source connection ID. */ - quic_cid_cpy(&qc->rx.params.initial_source_connection_id, &qc->scid); - qc->enc_params_len = - quic_transport_params_encode(qc->enc_params, qc->enc_params + sizeof qc->enc_params, - &qc->rx.params, 0); - if (!qc->enc_params_len) - goto err; - - if (qc_ssl_sess_init(qc, srv->ssl_ctx.ctx, &ctx->ssl, - qc->enc_params, qc->enc_params_len) == -1) - goto err; - - SSL_set_quic_transport_params(ctx->ssl, qc->enc_params, qc->enc_params_len); - SSL_set_connect_state(ctx->ssl); - ssl_err = SSL_do_handshake(ctx->ssl); - if (ssl_err != 1) { - int st; - - st = HA_ATOMIC_LOAD(&qc->state); - ssl_err = SSL_get_error(ctx->ssl, ssl_err); - if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { - TRACE_PROTO("SSL handshake", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err); - } - else { - TRACE_DEVEL("SSL handshake error", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err); - goto err; - } - } - } - else if (objt_listener(conn->target)) { - /* Listener */ - struct bind_conf *bc = __objt_listener(conn->target)->bind_conf; - - qc = ctx->conn->qc; - ctx->qc = qc; - - qc->tid = ctx->wait_event.tasklet->tid = quic_get_cid_tid(&qc->scid); - if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl, - qc->enc_params, qc->enc_params_len) == -1) - goto err; - - /* Enabling 0-RTT */ - if (bc->ssl_conf.early_data) - SSL_set_quic_early_data_enabled(ctx->ssl, 1); - - SSL_set_accept_state(ctx->ssl); - } - - HA_ATOMIC_STORE(xprt_ctx, ctx); + HA_ATOMIC_STORE(xprt_ctx, conn->qc->xprt_ctx); /* Leave init state and start handshake */ conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN; out: - HA_ATOMIC_STORE(&qc->xprt_ctx, ctx); TRACE_LEAVE(QUIC_EV_CONN_NEW, qc); return 0; - - err: - if (ctx && ctx->wait_event.tasklet) - tasklet_free(ctx->wait_event.tasklet); - pool_free(pool_head_quic_conn_ctx, ctx); - TRACE_DEVEL("leaving in error", QUIC_EV_CONN_NEW, conn); - return -1; } /* Start the QUIC transport layer */ -- 2.47.3