mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-10-26 22:20:59 +01:00
A ClientHello may be splitted accross several different CRYPTO frames, then mixed in a single QUIC packet. This is used notably by clients such as chrome to render the first Initial packet opaque to middleboxes. Each packet frame is handled sequentially. Out-of-order CRYPTO frames are buffered in a ncbuf, until gaps are filled and data is transferred to the SSL stack. If CRYPTO frames are heavily splitted with small fragments, buffering may fail as ncbuf does not support small gaps. This causes the whole packet to be rejected and unacknowledged. It could be solved if the client reemits its ClientHello after remixing its CRYPTO frames. This patch is written to improve CRYPTO frame parsing. Each CRYPTO frames which cannot be buffered due to ncbuf limitation are now stored in a temporary list. Packet parsing is completed until all frames have been handled. If temporary list is not empty, reparsing is done on the stored frames. With the newly buffered CRYPTO frames, ncbuf insert operation may this time succeeds if the frame now covers a whole gap. Reparsing will loop until either no progress can be made or it has been done at least 3 times, to prevent CPU utilization. This patch should fix github issue #2776. This should be backported up to 2.6, after a period of observation. Note that it relies on the following refactor patches : MINOR: quic: extend return value of CRYPTO parsing MINOR: quic: use dynamically allocated frame on parsing MINOR: quic: simplify qc_parse_pkt_frms() return path
69 lines
2.0 KiB
C
69 lines
2.0 KiB
C
#ifndef _HAPROXY_RX_T_H
|
|
#define _HAPROXY_RX_T_H
|
|
|
|
extern struct pool_head *pool_head_quic_conn_rxbuf;
|
|
extern struct pool_head *pool_head_quic_dgram;
|
|
extern struct pool_head *pool_head_quic_rx_packet;
|
|
|
|
#include <import/eb64tree.h>
|
|
#include <haproxy/api-t.h>
|
|
#include <haproxy/quic_cid-t.h>
|
|
#include <inttypes.h>
|
|
#include <sys/socket.h>
|
|
|
|
struct quic_version;
|
|
/* Maximum number of ack-eliciting received packets since the last
|
|
* ACK frame was sent
|
|
*/
|
|
#define QUIC_MAX_RX_AEPKTS_SINCE_LAST_ACK 2
|
|
#define QUIC_ACK_DELAY (QUIC_TP_DFLT_MAX_ACK_DELAY - 5)
|
|
/* Flag a received packet as being an ack-eliciting packet. */
|
|
#define QUIC_FL_RX_PACKET_ACK_ELICITING (1UL << 0)
|
|
/* Packet is the first one in the containing datagram. */
|
|
#define QUIC_FL_RX_PACKET_DGRAM_FIRST (1UL << 1)
|
|
/* Spin bit set */
|
|
#define QUIC_FL_RX_PACKET_SPIN_BIT (1UL << 2)
|
|
|
|
struct quic_rx_packet {
|
|
struct list list;
|
|
struct list qc_rx_pkt_list;
|
|
|
|
/* QUIC version used in packet. */
|
|
const struct quic_version *version;
|
|
|
|
unsigned char type;
|
|
/* Initial desctination connection ID. */
|
|
struct quic_cid dcid;
|
|
struct quic_cid scid;
|
|
/* Packet number offset : only valid for Initial/Handshake/0-RTT/1-RTT. */
|
|
size_t pn_offset;
|
|
/* Packet number */
|
|
int64_t pn;
|
|
/* Packet number length */
|
|
uint32_t pnl;
|
|
uint64_t token_len;
|
|
unsigned char *token;
|
|
/* Packet length */
|
|
uint64_t len;
|
|
/* Packet length before decryption */
|
|
uint64_t raw_len;
|
|
/* Additional authenticated data length */
|
|
size_t aad_len;
|
|
unsigned char *data;
|
|
struct eb64_node pn_node;
|
|
volatile unsigned int refcnt;
|
|
/* Source address of this packet. */
|
|
struct sockaddr_storage saddr;
|
|
unsigned int flags;
|
|
unsigned int time_received;
|
|
};
|
|
|
|
enum quic_rx_ret_frm {
|
|
QUIC_RX_RET_FRM_DONE = 0, /* frame handled correctly */
|
|
QUIC_RX_RET_FRM_DUP, /* frame ignored as already handled previously */
|
|
QUIC_RX_RET_FRM_AGAIN, /* frame cannot be handled temporarily, caller may retry during another parsing round */
|
|
QUIC_RX_RET_FRM_FATAL, /* error during frame handling, packet must not be acknowledged */
|
|
};
|
|
|
|
#endif /* _HAPROXY_RX_T_H */
|