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 *safe_conns; /* Safe idle connections */
|
||||
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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/* 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>
|
||||
* as encryption level.
|
||||
* 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;
|
||||
}
|
||||
else {
|
||||
/* TODO NEW_TOKEN not implemented on client side.
|
||||
* Note that for now token is not copied into <data> field
|
||||
* of qf_new_token frame. See quic_parse_new_token_frame()
|
||||
* for further explanations.
|
||||
*/
|
||||
struct qf_new_token *new_tok_frm = &frm->new_token;
|
||||
|
||||
if (!qc->conn) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
* 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,
|
||||
@ -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. */
|
||||
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
||||
if (!quic_enc_int(&pos, end, qc->retry_token_len) ||
|
||||
end - pos <= qc->retry_token_len)
|
||||
if (!quic_enc_token(qc, &pos, end))
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user