mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-30 15:21:04 +01:00
BUG/MEDIUM: quic: do not prevent sending if no BE token
For QUIC client support, a token may be emitted along with INITIAL packets during the handshake. The token is encoded during emission via qc_enc_token() called by qc_build_pkt(). The token may be provided from different sources. First, it can be retrieved via <retry_token> quic_conn member when a Retry packet was received. If not present, a token may be reused from the server cache, populated from NEW_TOKEN received from previous a connection. Prior to this patch, the last method may cause an issue. If the upper connection instance is released prior to the handshake completion, this prevents access to a possible server token. This is considered an error by qc_enc_token(). The error is reported up to calling functions, preventing any emission to be performed. In the end, this prevented the either the full quic_conn release or subsizing into quic_conn_closed until the idle timeout completion (30s by default). With abortonclose set now by default on HTTP frontends, early client shutdowns can easily cause excessive memory consumption. To fix this, change qc_enc_token() so that if connection is closed, no token is encoded but also no error is reported. This allows to continue emission and permit early connection release. No need to backport.
This commit is contained in:
parent
e27216b799
commit
cbfe574d8a
@ -1779,44 +1779,43 @@ static inline int quic_do_enc_token(unsigned char **pos, const unsigned char *en
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode a token depending on <qc> connection type (listener or not).
|
/* Encode an INITIAL token at <pos> buffer position, without exceeding <end>
|
||||||
* For listeners, ony a null byte is encoded (no token).
|
* pointer.
|
||||||
* For clients, if a RETRY token has been received, it is encoded, if not, if a
|
*
|
||||||
* new token has been received (from NEW_TOKEN frame) and could be retrieved
|
* On client side, token is either retrieved from a previously received RETRY
|
||||||
* from cache, it is encoded, if not a null byte is encoded (no token).
|
* paquet, or from the server cache populated by a NEW_TOKEN frame received by
|
||||||
|
* a previous connection. An empty field is encoded if no token is available.
|
||||||
|
*
|
||||||
|
* On server side, INITIAL token is not used so an empty field is encoded.
|
||||||
|
*
|
||||||
|
* Returns 1 on success or 0 on error.
|
||||||
*/
|
*/
|
||||||
static inline int quic_enc_token(struct quic_conn *qc,
|
static inline int quic_enc_token(struct quic_conn *qc,
|
||||||
unsigned char **pos, const unsigned char *end)
|
unsigned char **pos, const unsigned char *end)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
struct server *s;
|
||||||
const unsigned char *tok;
|
unsigned char *tok;
|
||||||
size_t toklen;
|
size_t toklen;
|
||||||
|
|
||||||
if (!qc_is_back(qc)) {
|
if (qc->retry_token) {
|
||||||
ret = quic_do_enc_token(pos, end, NULL, 0);
|
/* Only clients may received token from a RETRY packet. */
|
||||||
}
|
BUG_ON(!qc_is_back(qc));
|
||||||
else if (qc->retry_token) {
|
|
||||||
tok = qc->retry_token;
|
tok = qc->retry_token;
|
||||||
toklen = qc->retry_token_len;
|
toklen = qc->retry_token_len;
|
||||||
ret = quic_do_enc_token(pos, end, tok, toklen);
|
|
||||||
}
|
}
|
||||||
else if (!qc->conn) {
|
else if (qc_is_back(qc) && qc->conn) {
|
||||||
TRACE_ERROR("connection closed", QUIC_EV_CONN_TXPKT, qc);
|
/* Retrieve token from the server cache. */
|
||||||
goto out;
|
s = __objt_server(qc->conn->target);
|
||||||
|
tok = (unsigned char *)istptr(s->per_thr[tid].quic_retry_token);
|
||||||
|
toklen = istlen(s->per_thr[tid].quic_retry_token);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct server *s = __objt_server(qc->conn->target);
|
/* Prepare to encode an empty field. */
|
||||||
struct ist *stok;
|
tok = NULL;
|
||||||
|
toklen = 0;
|
||||||
stok = &s->per_thr[tid].quic_retry_token;
|
|
||||||
if (isttest(*stok))
|
|
||||||
ret = quic_do_enc_token(pos, end, (unsigned char *)istptr(*stok), istlen(*stok));
|
|
||||||
else
|
|
||||||
ret = quic_do_enc_token(pos, end, NULL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
return quic_do_enc_token(pos, end, tok, toklen);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function builds a clear packet from <pkt> information (its type)
|
/* This function builds a clear packet from <pkt> information (its type)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user