mirror of
https://github.com/openssl/openssl.git
synced 2025-02-23 14:42:15 +08:00
quic conformance: 10.2.1 rate limiting
Implement the two requirements about limiting closing transmission size to no more than thrice the received size. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Hugo Landau <hlandau@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21429)
This commit is contained in:
parent
afe4a7978d
commit
50e76846bf
@ -56,7 +56,8 @@ typedef struct ossl_quic_tx_packetiser_args_st {
|
||||
* crypto[QUIC_PN_SPACE_APP] is the 1-RTT crypto stream.
|
||||
*/
|
||||
QUIC_SSTREAM *crypto[QUIC_PN_SPACE_NUM];
|
||||
} OSSL_QUIC_TX_PACKETISER_ARGS;
|
||||
|
||||
} OSSL_QUIC_TX_PACKETISER_ARGS;
|
||||
|
||||
typedef struct ossl_quic_tx_packetiser_st OSSL_QUIC_TX_PACKETISER;
|
||||
|
||||
@ -67,6 +68,14 @@ typedef void (ossl_quic_initial_token_free_fn)(const unsigned char *buf,
|
||||
|
||||
void ossl_quic_tx_packetiser_free(OSSL_QUIC_TX_PACKETISER *txp);
|
||||
|
||||
/*
|
||||
* When in the closing state we need to maintain a count of received bytes
|
||||
* so that we can limit the number of close connection frames we send.
|
||||
* Refer RFC 9000 s. 10.2.1 Closing Connection State.
|
||||
*/
|
||||
void ossl_quic_tx_packetiser_record_received_closing_bytes(
|
||||
OSSL_QUIC_TX_PACKETISER *txp, size_t n);
|
||||
|
||||
/*
|
||||
* Generates a datagram by polling the various ELs to determine if they want to
|
||||
* generate any frames, and generating a datagram which coalesces packets for
|
||||
|
@ -1783,6 +1783,7 @@ static void ch_rx_check_forged_pkt_limit(QUIC_CHANNEL *ch)
|
||||
static int ch_rx(QUIC_CHANNEL *ch)
|
||||
{
|
||||
int handled_any = 0;
|
||||
const int closing = ossl_quic_channel_is_closing(ch);
|
||||
|
||||
if (!ch->is_server && !ch->have_sent_any_pkt)
|
||||
/*
|
||||
@ -1797,6 +1798,11 @@ static int ch_rx(QUIC_CHANNEL *ch)
|
||||
if (!ossl_qrx_read_pkt(ch->qrx, &ch->qrx_pkt))
|
||||
break;
|
||||
|
||||
/* Track the amount of data received while in the closing state */
|
||||
if (closing)
|
||||
ossl_quic_tx_packetiser_record_received_closing_bytes(
|
||||
ch->txp, ch->qrx_pkt->hdr->len);
|
||||
|
||||
if (!handled_any)
|
||||
ch_update_idle(ch);
|
||||
|
||||
@ -1820,7 +1826,7 @@ static int ch_rx(QUIC_CHANNEL *ch)
|
||||
* When in TERMINATING - CLOSING, generate a CONN_CLOSE frame whenever we
|
||||
* process one or more incoming packets.
|
||||
*/
|
||||
if (handled_any && ossl_quic_channel_is_closing(ch))
|
||||
if (handled_any && closing)
|
||||
ch->conn_close_queued = 1;
|
||||
|
||||
return 1;
|
||||
@ -1858,8 +1864,12 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch)
|
||||
|
||||
assert(ch->qrx_pkt != NULL);
|
||||
|
||||
/*
|
||||
* RFC 9000 s. 10.2.1 Closing Connection State:
|
||||
* An endpoint that is closing is not required to process any
|
||||
* received frame.
|
||||
*/
|
||||
if (!ossl_quic_channel_is_active(ch))
|
||||
/* Do not process packets once we are terminating. */
|
||||
return;
|
||||
|
||||
if (ossl_quic_pkt_type_is_encrypted(ch->qrx_pkt->hdr->type)) {
|
||||
|
@ -202,7 +202,7 @@ struct quic_channel_st {
|
||||
*/
|
||||
uint64_t txku_threshold_override;
|
||||
|
||||
/* Valid if we are in the TERMINATING or TERMINATED states. */
|
||||
/* Valid if we are in the TERMINATING or TERMINATED states. */
|
||||
QUIC_TERMINATE_CAUSE terminate_cause;
|
||||
|
||||
/*
|
||||
|
@ -89,6 +89,13 @@ struct ossl_quic_tx_packetiser_st {
|
||||
|
||||
OSSL_QUIC_FRAME_CONN_CLOSE conn_close_frame;
|
||||
|
||||
/*
|
||||
* Counts of the number of bytes received and sent while in the closing
|
||||
* state.
|
||||
*/
|
||||
uint64_t closing_bytes_recv;
|
||||
uint64_t closing_bytes_xmit;
|
||||
|
||||
/* Internal state - packet assembly. */
|
||||
struct txp_el {
|
||||
unsigned char *scratch; /* scratch buffer for packet assembly */
|
||||
@ -1640,6 +1647,47 @@ static void on_sstream_updated(uint64_t stream_id, void *arg)
|
||||
ossl_quic_stream_map_update_state(txp->args.qsm, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if we can send that many bytes in closing state, 0 otherwise.
|
||||
* Also maintains the bytes sent state if it returns a success.
|
||||
*/
|
||||
static int try_commit_conn_close(OSSL_QUIC_TX_PACKETISER *txp, size_t n)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* We can always send the first connection close frame */
|
||||
if (txp->closing_bytes_recv == 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* RFC 9000 s. 10.2.1 Closing Connection State:
|
||||
* To avoid being used for an amplification attack, such
|
||||
* endpoints MUST limit the cumulative size of packets it sends
|
||||
* to three times the cumulative size of the packets that are
|
||||
* received and attributed to the connection.
|
||||
* and:
|
||||
* An endpoint in the closing state MUST either discard packets
|
||||
* received from an unvalidated address or limit the cumulative
|
||||
* size of packets it sends to an unvalidated address to three
|
||||
* times the size of packets it receives from that address.
|
||||
*/
|
||||
res = txp->closing_bytes_xmit + n <= txp->closing_bytes_recv * 3;
|
||||
|
||||
/*
|
||||
* Attribute the bytes to the connection, if we are allowed to send them
|
||||
* and this isn't the first closing frame.
|
||||
*/
|
||||
if (res && txp->closing_bytes_recv != 0)
|
||||
txp->closing_bytes_xmit += n;
|
||||
return res;
|
||||
}
|
||||
|
||||
void ossl_quic_tx_packetiser_record_received_closing_bytes(
|
||||
OSSL_QUIC_TX_PACKETISER *txp, size_t n)
|
||||
{
|
||||
txp->closing_bytes_recv += n;
|
||||
}
|
||||
|
||||
static int txp_generate_pre_token(OSSL_QUIC_TX_PACKETISER *txp,
|
||||
struct txp_pkt *pkt,
|
||||
int chosen_for_conn_close,
|
||||
@ -1692,6 +1740,7 @@ static int txp_generate_pre_token(OSSL_QUIC_TX_PACKETISER *txp,
|
||||
if (a->allow_conn_close && txp->want_conn_close && chosen_for_conn_close) {
|
||||
WPACKET *wpkt = tx_helper_begin(h);
|
||||
OSSL_QUIC_FRAME_CONN_CLOSE f, *pf = &txp->conn_close_frame;
|
||||
size_t l;
|
||||
|
||||
if (wpkt == NULL)
|
||||
return 0;
|
||||
@ -1721,7 +1770,9 @@ static int txp_generate_pre_token(OSSL_QUIC_TX_PACKETISER *txp,
|
||||
pf->reason_len = 0;
|
||||
}
|
||||
|
||||
if (ossl_quic_wire_encode_frame_conn_close(wpkt, pf)) {
|
||||
if (ossl_quic_wire_encode_frame_conn_close(wpkt, pf)
|
||||
&& WPACKET_get_total_written(wpkt, &l)
|
||||
&& try_commit_conn_close(txp, l)) {
|
||||
if (!tx_helper_commit(h))
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user