diff options
author | Pauli <pauli@openssl.org> | 2023-08-02 09:35:35 +1000 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2023-08-16 12:07:17 +0200 |
commit | cdd916313a89def99493e00b49958ced894ca209 (patch) | |
tree | 5cb1b4690011d15d974d3a820955cbf050468f79 /ssl/quic/quic_demux.c | |
parent | 945fde53a3db5011940a059fd1407b81197c9e14 (diff) |
quic: process stateless resets
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21649)
Diffstat (limited to 'ssl/quic/quic_demux.c')
-rw-r--r-- | ssl/quic/quic_demux.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c index 160bf28168..bc2cde726b 100644 --- a/ssl/quic/quic_demux.c +++ b/ssl/quic/quic_demux.c @@ -80,6 +80,10 @@ struct quic_demux_st { ossl_quic_demux_cb_fn *default_cb; void *default_cb_arg; + /* The stateless reset token checker handler, if any. */ + ossl_quic_stateless_reset_cb_fn *reset_token_cb; + void *reset_token_cb_arg; + /* * List of URXEs which are not currently in use (i.e., not filled with * unconsumed data). These are moved to the pending list as they are filled. @@ -297,6 +301,14 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, demux->default_cb_arg = cb_arg; } +void ossl_quic_demux_set_stateless_reset_handler( + QUIC_DEMUX *demux, + ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg) +{ + demux->reset_token_cb = cb; + demux->reset_token_cb_arg = cb_arg; +} + static QUIC_URXE *demux_alloc_urxe(size_t alloc_len) { QUIC_URXE *e; @@ -483,10 +495,14 @@ static QUIC_DEMUX_CONN *demux_identify_conn(QUIC_DEMUX *demux, QUIC_URXE *e) return demux_get_by_conn_id(demux, &dst_conn_id); } -/* Process a single pending URXE. */ +/* + * Process a single pending URXE. + * Returning 1 on success, 0 on failure and -1 on stateless reset. + */ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) { QUIC_DEMUX_CONN *conn; + int r; /* The next URXE we process should be at the head of the pending list. */ if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending))) @@ -494,6 +510,29 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) assert(e->demux_state == URXE_DEMUX_STATE_PENDING); + /* + * Check if the packet ends with a stateless reset token and if it does + * skip it after dropping the connection. + * + * RFC 9000 s. 10.3.1 Detecting a Stateless Reset + * If the last 16 bytes of the datagram are identical in value to + * a stateless reset token, the endpoint MUST enter the draining + * period and not send any further packets on this connection. + * + * Returning a failure here causes the connection to enter the terminating + * state which achieves the desired outcome. + * + * TODO(QUIC FUTURE): only try to match unparsable packets + */ + if (demux->reset_token_cb != NULL) { + r = demux->reset_token_cb(ossl_quic_urxe_data(e), e->data_len, + demux->reset_token_cb_arg); + if (r > 0) /* Received a stateless reset */ + return -1; + if (r < 0) /* Error during stateless reset detection */ + return 0; + } + conn = demux_identify_conn(demux, e); if (conn == NULL) { /* @@ -528,10 +567,11 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) static int demux_process_pending_urxl(QUIC_DEMUX *demux) { QUIC_URXE *e; + int ret; while ((e = ossl_list_urxe_head(&demux->urx_pending)) != NULL) - if (!demux_process_pending_urxe(demux, e)) - return 0; + if ((ret = demux_process_pending_urxe(demux, e)) <= 0) + return ret; return 1; } @@ -559,8 +599,9 @@ int ossl_quic_demux_pump(QUIC_DEMUX *demux) assert(ossl_list_urxe_head(&demux->urx_pending) != NULL); } - if (!demux_process_pending_urxl(demux)) - return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; + if ((ret = demux_process_pending_urxl(demux)) <= 0) + return ret == 0 ? QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL + : QUIC_DEMUX_PUMP_RES_STATELESS_RESET; return QUIC_DEMUX_PUMP_RES_OK; } @@ -608,7 +649,7 @@ int ossl_quic_demux_inject(QUIC_DEMUX *demux, ossl_list_urxe_insert_tail(&demux->urx_pending, urxe); urxe->demux_state = URXE_DEMUX_STATE_PENDING; - return demux_process_pending_urxl(demux); + return demux_process_pending_urxl(demux) > 0; } /* Called by our user to return a URXE to the free list. */ |