mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-12-02 16:21:27 +01:00
MEDIUM: quic-be: Parse, store and reuse tokens provided by NEW_TOKEN
Add a per thread ist struct to srv_per_thread struct to store the QUIC token to be reused for subsequent sessions. Parse at packet level (from qc_parse_ptk_frms()) these tokens and store them calling qc_try_store_new_token() newly implemented function. This is this new function which does its best (may fail) to update the tokens. Modify qc_do_build_pkt() to resend these tokens calling quic_enc_token() implemented by this patch.
This commit is contained in:
parent
8f23d4d287
commit
80070fe51c
@ -276,6 +276,9 @@ struct srv_per_thread {
|
|||||||
struct ceb_root *idle_conns; /* Shareable idle connections */
|
struct ceb_root *idle_conns; /* Shareable idle connections */
|
||||||
struct ceb_root *safe_conns; /* Safe idle connections */
|
struct ceb_root *safe_conns; /* Safe idle connections */
|
||||||
struct ceb_root *avail_conns; /* Connections in use, but with still new streams available */
|
struct ceb_root *avail_conns; /* Connections in use, but with still new streams available */
|
||||||
|
#ifdef USE_QUIC
|
||||||
|
struct ist quic_retry_token;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Each server will have one occurrence of this structure per thread group */
|
/* Each server will have one occurrence of this structure per thread group */
|
||||||
|
|||||||
@ -802,6 +802,35 @@ static inline unsigned int quic_ack_delay_ms(struct qf_ack *ack_frm,
|
|||||||
return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000;
|
return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Client only.
|
||||||
|
* Do its best to store <tok> token received from a NEW_TOKEN frame into <s>
|
||||||
|
* server cache for tokens to reuse.
|
||||||
|
*/
|
||||||
|
static inline void qc_try_store_new_token(struct server *s,
|
||||||
|
const unsigned char *tok,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct ist *stok;
|
||||||
|
char *stok_ptr;
|
||||||
|
|
||||||
|
stok = &s->per_thr[tid].quic_retry_token;
|
||||||
|
stok_ptr = istptr(*stok);
|
||||||
|
if (len > istlen(*stok)) {
|
||||||
|
stok_ptr = realloc(stok_ptr, len);
|
||||||
|
if (stok_ptr)
|
||||||
|
s->per_thr[tid].quic_retry_token.ptr = stok_ptr;
|
||||||
|
else {
|
||||||
|
memset(istptr(*stok), 0, istlen(*stok));
|
||||||
|
istfree(stok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stok_ptr) {
|
||||||
|
memcpy(stok_ptr, tok, len);
|
||||||
|
stok->len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse all the frames of <pkt> QUIC packet for QUIC connection <qc> and <qel>
|
/* Parse all the frames of <pkt> QUIC packet for QUIC connection <qc> and <qel>
|
||||||
* as encryption level.
|
* as encryption level.
|
||||||
* Returns 1 if succeeded, 0 if failed.
|
* Returns 1 if succeeded, 0 if failed.
|
||||||
@ -906,11 +935,16 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* TODO NEW_TOKEN not implemented on client side.
|
struct qf_new_token *new_tok_frm = &frm->new_token;
|
||||||
* Note that for now token is not copied into <data> field
|
|
||||||
* of qf_new_token frame. See quic_parse_new_token_frame()
|
if (!qc->conn) {
|
||||||
* for further explanations.
|
TRACE_ERROR("reject NEW_TOKEN frame (connection closed",
|
||||||
*/
|
QUIC_EV_CONN_PRSHPKT, qc);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc_try_store_new_token(__objt_server(qc->conn->target),
|
||||||
|
new_tok_frm->r_data, new_tok_frm->len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F:
|
case QUIC_FT_STREAM_8 ... QUIC_FT_STREAM_F:
|
||||||
|
|||||||
@ -1745,6 +1745,66 @@ static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received,
|
|||||||
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
|
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Encode the <tok> token data field made of <toklen> bytes at <pos> buffer
|
||||||
|
* address. <end> points to the byte following the end of <*pos> buffer.
|
||||||
|
* Note that the type of the frame which embed this token is not encoded.
|
||||||
|
* Return 1 if succeeded, 0 if not.
|
||||||
|
*/
|
||||||
|
static inline int quic_do_enc_token(unsigned char **pos, const unsigned char *end,
|
||||||
|
const unsigned char *tok, size_t toklen)
|
||||||
|
{
|
||||||
|
if (!quic_enc_int(pos, end, toklen) || end - *pos <= toklen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (toklen) {
|
||||||
|
memcpy(*pos, tok, toklen);
|
||||||
|
*pos += toklen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode a token depending on <qc> connection type (listener or not).
|
||||||
|
* For listeners, ony a null byte is encoded (no token).
|
||||||
|
* 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
|
||||||
|
* from cache, it is encoded, if not a null byte is encoded (no token).
|
||||||
|
*/
|
||||||
|
static inline int quic_enc_token(struct quic_conn *qc,
|
||||||
|
unsigned char **pos, const unsigned char *end)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
const unsigned char *tok;
|
||||||
|
size_t toklen;
|
||||||
|
|
||||||
|
if (!qc_is_back(qc)) {
|
||||||
|
ret = quic_do_enc_token(pos, end, NULL, 0);
|
||||||
|
}
|
||||||
|
else if (qc->retry_token) {
|
||||||
|
tok = qc->retry_token;
|
||||||
|
toklen = qc->retry_token_len;
|
||||||
|
ret = quic_do_enc_token(pos, end, tok, toklen);
|
||||||
|
}
|
||||||
|
else if (!qc->conn) {
|
||||||
|
TRACE_ERROR("connection closed", QUIC_EV_CONN_TXPKT, qc);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct server *s = __objt_server(qc->conn->target);
|
||||||
|
struct ist *stok;
|
||||||
|
|
||||||
|
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 ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function builds a clear packet from <pkt> information (its type)
|
/* This function builds a clear packet from <pkt> information (its type)
|
||||||
* into a buffer with <pos> as position pointer and <qel> as QUIC TLS encryption
|
* into a buffer with <pos> as position pointer and <qel> as QUIC TLS encryption
|
||||||
* level for <conn> QUIC connection and <qel> as QUIC TLS encryption level,
|
* level for <conn> QUIC connection and <qel> as QUIC TLS encryption level,
|
||||||
@ -1828,14 +1888,8 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end,
|
|||||||
|
|
||||||
/* Encode the token length (0) for an Initial packet. */
|
/* Encode the token length (0) for an Initial packet. */
|
||||||
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
||||||
if (!quic_enc_int(&pos, end, qc->retry_token_len) ||
|
if (!quic_enc_token(qc, &pos, end))
|
||||||
end - pos <= qc->retry_token_len)
|
|
||||||
goto no_room;
|
goto no_room;
|
||||||
|
|
||||||
if (qc->retry_token_len) {
|
|
||||||
memcpy(pos, qc->retry_token, qc->retry_token_len);
|
|
||||||
pos += qc->retry_token_len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
head_len = pos - beg;
|
head_len = pos - beg;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user