mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
MINOR: quic: Add definitions for QUIC protocol.
This patch imports all the definitions for QUIC protocol with few modifications from 20200720-quic branch of quic-dev repository found at https://github.com/haproxytech/quic-dev.
This commit is contained in:
parent
10caf65634
commit
0c4e3b09b0
101
include/haproxy/quic_cc-t.h
Normal file
101
include/haproxy/quic_cc-t.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* include/haproxy/quic_cc-t.h
|
||||
* This file contains definitions for QUIC congestion control.
|
||||
*
|
||||
* Copyright 2020 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _HAPROXY_QUIC_CC_H
|
||||
#define _HAPROXY_QUIC_CC_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdint.h>
|
||||
|
||||
#include <haproxy/buf-t.h>
|
||||
|
||||
#define QUIC_CC_INFINITE_SSTHESH ((uint64_t)-1)
|
||||
|
||||
extern struct quic_cc_algo quic_cc_algo_nr;
|
||||
extern struct quic_cc_algo *default_quic_cc_algo;
|
||||
|
||||
enum quic_cc_algo_state_type {
|
||||
/* Slow start. */
|
||||
QUIC_CC_ST_SS,
|
||||
/* Congestion avoidance. */
|
||||
QUIC_CC_ST_CA,
|
||||
};
|
||||
|
||||
enum quic_cc_event_type {
|
||||
/* ACK receipt. */
|
||||
QUIC_CC_EVT_ACK,
|
||||
/* Packet loss. */
|
||||
QUIC_CC_EVT_LOSS,
|
||||
/* ECN-CE. */
|
||||
QUIC_CC_EVT_ECN_CE,
|
||||
};
|
||||
|
||||
struct quic_cc_event {
|
||||
enum quic_cc_event_type type;
|
||||
union {
|
||||
struct ack {
|
||||
uint64_t acked;
|
||||
unsigned int time_sent;
|
||||
} ack;
|
||||
struct loss {
|
||||
unsigned int now_ms;
|
||||
unsigned int max_ack_delay;
|
||||
size_t lost_bytes;
|
||||
unsigned int newest_time_sent;
|
||||
unsigned int period;
|
||||
} loss;
|
||||
};
|
||||
};
|
||||
|
||||
enum quic_cc_algo_type {
|
||||
QUIC_CC_ALGO_TP_NEWRENO,
|
||||
};
|
||||
|
||||
union quic_cc_algo_state {
|
||||
/* NewReno */
|
||||
struct nr {
|
||||
enum quic_cc_algo_state_type state;
|
||||
uint64_t cwnd;
|
||||
uint64_t ssthresh;
|
||||
uint64_t recovery_start_time;
|
||||
} nr;
|
||||
};
|
||||
|
||||
struct quic_cc {
|
||||
/* <conn> is there ony for debugging purpose. */
|
||||
struct quic_conn *qc;
|
||||
struct quic_cc_algo *algo;
|
||||
union quic_cc_algo_state algo_state;
|
||||
};
|
||||
|
||||
struct quic_cc_algo {
|
||||
enum quic_cc_algo_type type;
|
||||
int (*init)(struct quic_cc *cc);
|
||||
void (*event)(struct quic_cc *cc, struct quic_cc_event *ev);
|
||||
void (*state_trace)(struct buffer *buf, const struct quic_cc *cc);
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _HAPROXY_QUIC_CC_H */
|
73
include/haproxy/quic_cc.h
Normal file
73
include/haproxy/quic_cc.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* include/proto/quic_cc.h
|
||||
* This file contains prototypes for QUIC congestion control.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_QUIC_CC_H
|
||||
#define _PROTO_QUIC_CC_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/chunk.h>
|
||||
#include <haproxy/quic_cc-t.h>
|
||||
#include <haproxy/xprt_quic-t.h>
|
||||
|
||||
void quic_cc_init(struct quic_cc *cc, struct quic_cc_algo *algo, struct quic_conn *qc);
|
||||
void quic_cc_event(struct quic_cc *cc, struct quic_cc_event *ev);
|
||||
void quic_cc_state_trace(struct buffer *buf, const struct quic_cc *cc);
|
||||
|
||||
static inline const char *quic_cc_state_str(enum quic_cc_algo_state_type state)
|
||||
{
|
||||
switch (state) {
|
||||
case QUIC_CC_ST_SS:
|
||||
return "ss";
|
||||
case QUIC_CC_ST_CA:
|
||||
return "ca";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a human readable string from <ev> control congestion event type. */
|
||||
static inline void quic_cc_event_trace(struct buffer *buf, const struct quic_cc_event *ev)
|
||||
{
|
||||
chunk_appendf(buf, " event type=");
|
||||
switch (ev->type) {
|
||||
case QUIC_CC_EVT_ACK:
|
||||
chunk_appendf(buf, "ack acked=%llu time_sent:%u",
|
||||
(unsigned long long)ev->ack.acked, ev->ack.time_sent);
|
||||
break;
|
||||
case QUIC_CC_EVT_LOSS:
|
||||
chunk_appendf(buf, "loss now_ms=%u max_ack_delay=%u lost_bytes=%llu"
|
||||
" time_sent=%u period=%u",
|
||||
ev->loss.now_ms, ev->loss.max_ack_delay,
|
||||
(unsigned long long)ev->loss.lost_bytes,
|
||||
ev->loss.newest_time_sent, ev->loss.period);
|
||||
break;
|
||||
case QUIC_CC_EVT_ECN_CE:
|
||||
chunk_appendf(buf, "ecn_ce");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _PROTO_QUIC_CC_H */
|
235
include/haproxy/quic_frame-t.h
Normal file
235
include/haproxy/quic_frame-t.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* include/types/quic_frame.h
|
||||
* This file contains QUIC frame definitions.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_QUIC_FRAME_H
|
||||
#define _TYPES_QUIC_FRAME_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <haproxy/list.h>
|
||||
|
||||
/* QUIC frame types. */
|
||||
enum quic_frame_type {
|
||||
QUIC_FT_PADDING = 0x00,
|
||||
QUIC_FT_PING = 0x01,
|
||||
QUIC_FT_ACK = 0x02,
|
||||
QUIC_FT_ACK_ECN = 0x03,
|
||||
QUIC_FT_RESET_STREAM = 0x04,
|
||||
QUIC_FT_STOP_SENDING = 0x05,
|
||||
QUIC_FT_CRYPTO = 0x06,
|
||||
QUIC_FT_NEW_TOKEN = 0x07,
|
||||
|
||||
QUIC_FT_STREAM_8 = 0x08,
|
||||
QUIC_FT_STREAM_9 = 0x09,
|
||||
QUIC_FT_STREAM_A = 0x0a,
|
||||
QUIC_FT_STREAM_B = 0x0b,
|
||||
QUIC_FT_STREAM_C = 0x0c,
|
||||
QUIC_FT_STREAM_D = 0x0d,
|
||||
QUIC_FT_STREAM_E = 0x0e,
|
||||
QUIC_FT_STREAM_F = 0x0f,
|
||||
|
||||
QUIC_FT_MAX_DATA = 0x10,
|
||||
QUIC_FT_MAX_STREAM_DATA = 0x11,
|
||||
QUIC_FT_MAX_STREAMS_BIDI = 0x12,
|
||||
QUIC_FT_MAX_STREAMS_UNI = 0x13,
|
||||
QUIC_FT_DATA_BLOCKED = 0x14,
|
||||
QUIC_FT_STREAM_DATA_BLOCKED = 0x15,
|
||||
QUIC_FT_STREAMS_BLOCKED_BIDI = 0x16,
|
||||
QUIC_FT_STREAMS_BLOCKED_UNI = 0x17,
|
||||
QUIC_FT_NEW_CONNECTION_ID = 0x18,
|
||||
QUIC_FT_RETIRE_CONNECTION_ID = 0x19,
|
||||
QUIC_FT_PATH_CHALLENGE = 0x1a,
|
||||
QUIC_FT_PATH_RESPONSE = 0x1b,
|
||||
QUIC_FT_CONNECTION_CLOSE = 0x1c,
|
||||
QUIC_FT_CONNECTION_CLOSE_APP = 0x1d,
|
||||
QUIC_FT_HANDSHAKE_DONE = 0x1e,
|
||||
/* Do not insert enums after the following one. */
|
||||
QUIC_FT_MAX
|
||||
};
|
||||
|
||||
#define QUIC_FT_PKT_TYPE_I_BITMASK (1 << QUIC_PACKET_TYPE_INITIAL)
|
||||
#define QUIC_FT_PKT_TYPE_0_BITMASK (1 << QUIC_PACKET_TYPE_0RTT)
|
||||
#define QUIC_FT_PKT_TYPE_H_BITMASK (1 << QUIC_PACKET_TYPE_HANDSHAKE)
|
||||
#define QUIC_FT_PKT_TYPE_1_BITMASK (1 << QUIC_PACKET_TYPE_SHORT)
|
||||
|
||||
#define QUIC_FT_PKT_TYPE_IH01_BITMASK \
|
||||
(QUIC_FT_PKT_TYPE_I_BITMASK | QUIC_FT_PKT_TYPE_H_BITMASK | \
|
||||
QUIC_FT_PKT_TYPE_0_BITMASK | QUIC_FT_PKT_TYPE_1_BITMASK)
|
||||
|
||||
#define QUIC_FT_PKT_TYPE_IH_1_BITMASK \
|
||||
(QUIC_FT_PKT_TYPE_I_BITMASK | QUIC_FT_PKT_TYPE_H_BITMASK | \
|
||||
QUIC_FT_PKT_TYPE_1_BITMASK)
|
||||
|
||||
#define QUIC_FT_PKT_TYPE___01_BITMASK \
|
||||
(QUIC_FT_PKT_TYPE_0_BITMASK | QUIC_FT_PKT_TYPE_1_BITMASK)
|
||||
|
||||
#define QUIC_FT_PKT_TYPE____1_BITMASK QUIC_FT_PKT_TYPE_1_BITMASK
|
||||
|
||||
#define QUIC_STREAM_FRAME_FIN_BIT 0x01
|
||||
#define QUIC_STREAM_FRAME_LEN_BIT 0x02
|
||||
#define QUIC_STREAM_FRAME_OFF_BIT 0x04
|
||||
|
||||
#define QUIC_PATH_CHALLENGE_LEN 8
|
||||
|
||||
struct quic_padding {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct quic_ack {
|
||||
uint64_t largest_ack;
|
||||
uint64_t ack_delay;
|
||||
uint64_t ack_range_num;
|
||||
uint64_t first_ack_range;
|
||||
};
|
||||
|
||||
/* Structure used when emitting ACK frames. */
|
||||
struct quic_tx_ack {
|
||||
uint64_t ack_delay;
|
||||
struct quic_ack_ranges *ack_ranges;
|
||||
};
|
||||
|
||||
struct quic_reset_stream {
|
||||
uint64_t id;
|
||||
uint64_t app_error_code;
|
||||
uint64_t final_size;
|
||||
};
|
||||
|
||||
struct quic_stop_sending_frame {
|
||||
uint64_t id;
|
||||
uint64_t app_error_code;
|
||||
};
|
||||
|
||||
struct quic_crypto {
|
||||
uint64_t offset;
|
||||
uint64_t len;
|
||||
const struct quic_enc_level *qel;
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
struct quic_new_token {
|
||||
uint64_t len;
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
struct quic_stream {
|
||||
uint64_t id;
|
||||
uint64_t offset;
|
||||
uint64_t len;
|
||||
const unsigned char *data;
|
||||
};
|
||||
|
||||
struct quic_max_data {
|
||||
uint64_t max_data;
|
||||
};
|
||||
|
||||
struct quic_max_stream_data {
|
||||
uint64_t id;
|
||||
uint64_t max_stream_data;
|
||||
};
|
||||
|
||||
struct quic_max_streams {
|
||||
uint64_t max_streams;
|
||||
};
|
||||
|
||||
struct quic_data_blocked {
|
||||
uint64_t limit;
|
||||
};
|
||||
|
||||
struct quic_stream_data_blocked {
|
||||
uint64_t id;
|
||||
uint64_t limit;
|
||||
};
|
||||
|
||||
struct quic_streams_blocked {
|
||||
uint64_t limit;
|
||||
};
|
||||
|
||||
struct quic_new_connection_id {
|
||||
uint64_t seq_num;
|
||||
uint64_t retire_prior_to;
|
||||
struct {
|
||||
unsigned char len;
|
||||
const unsigned char *data;
|
||||
} cid;
|
||||
const unsigned char *stateless_reset_token;
|
||||
};
|
||||
|
||||
struct quic_retire_connection_id {
|
||||
uint64_t seq_num;
|
||||
};
|
||||
|
||||
struct quic_path_challenge {
|
||||
unsigned char data[QUIC_PATH_CHALLENGE_LEN];
|
||||
};
|
||||
|
||||
struct quic_path_challenge_response {
|
||||
unsigned char data[QUIC_PATH_CHALLENGE_LEN];
|
||||
};
|
||||
|
||||
struct quic_connection_close {
|
||||
uint64_t error_code;
|
||||
uint64_t frame_type;
|
||||
uint64_t reason_phrase_len;
|
||||
unsigned char *reason_phrase;
|
||||
};
|
||||
|
||||
struct quic_connection_close_app {
|
||||
uint64_t error_code;
|
||||
uint64_t reason_phrase_len;
|
||||
unsigned char *reason_phrase;
|
||||
};
|
||||
|
||||
struct quic_frame {
|
||||
struct list list;
|
||||
unsigned char type;
|
||||
union {
|
||||
struct quic_padding padding;
|
||||
struct quic_ack ack;
|
||||
struct quic_tx_ack tx_ack;
|
||||
struct quic_crypto crypto;
|
||||
struct quic_reset_stream reset_stream;
|
||||
struct quic_stop_sending_frame stop_sending_frame;
|
||||
struct quic_new_token new_token;
|
||||
struct quic_stream stream;
|
||||
struct quic_max_data max_data;
|
||||
struct quic_max_stream_data max_stream_data;
|
||||
struct quic_max_streams max_streams_bidi;
|
||||
struct quic_max_streams max_streams_uni;
|
||||
struct quic_data_blocked data_blocked;
|
||||
struct quic_stream_data_blocked stream_data_blocked;
|
||||
struct quic_streams_blocked streams_blocked_bidi;
|
||||
struct quic_streams_blocked streams_blocked_uni;
|
||||
struct quic_new_connection_id new_connection_id;
|
||||
struct quic_retire_connection_id retire_connection_id;
|
||||
struct quic_path_challenge path_challenge;
|
||||
struct quic_path_challenge_response path_challenge_response;
|
||||
struct quic_connection_close connection_close;
|
||||
struct quic_connection_close_app connection_close_app;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _TYPES_QUIC_FRAME_H */
|
43
include/haproxy/quic_frame.h
Normal file
43
include/haproxy/quic_frame.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* include/haproxy/quic_frame.h
|
||||
* This file contains prototypes for QUIC frames.
|
||||
*
|
||||
* Copyright 2020 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _HAPROXY_QUIC_FRAME_H
|
||||
#define _HAPROXY_QUIC_FRAME_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <haproxy/quic_frame-t.h>
|
||||
#include <haproxy/xprt_quic-t.h>
|
||||
|
||||
const char *quic_frame_type_string(enum quic_frame_type ft);
|
||||
|
||||
int qc_build_frm(unsigned char **buf, const unsigned char *end,
|
||||
struct quic_frame *frm, struct quic_tx_packet *pkt,
|
||||
struct quic_conn *conn);
|
||||
|
||||
int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
|
||||
const unsigned char **buf, const unsigned char *end,
|
||||
struct quic_conn *conn);
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _HAPROXY_QUIC_FRAME_H */
|
54
include/haproxy/quic_loss-t.h
Normal file
54
include/haproxy/quic_loss-t.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* include/types/quic_loss.h
|
||||
* This file contains definitions for QUIC loss detection.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_QUIC_LOSS_H
|
||||
#define _TYPES_QUIC_LOSS_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Maximum reordering in packets. */
|
||||
#define QUIC_LOSS_PACKET_THRESHOLD 3
|
||||
#define QUIC_TIMER_GRANULARITY 1U /* 1ms */
|
||||
#define QUIC_LOSS_INITIAL_RTT 333U /* 333ms */
|
||||
|
||||
/* Note that all the unit of variables for QUIC LOSS dectections
|
||||
* is the tick.
|
||||
*/
|
||||
|
||||
struct quic_loss {
|
||||
/* The most recent RTT measurement. */
|
||||
unsigned int latest_rtt;
|
||||
/* Smoothed RTT << 4*/
|
||||
unsigned int srtt;
|
||||
/* RTT variation << 2 */
|
||||
unsigned int rtt_var;
|
||||
/* Minimum RTT. */
|
||||
unsigned int rtt_min;
|
||||
/* Number of NACKed sent PTO. */
|
||||
unsigned int pto_count;
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _TYPES_QUIC_LOSS_H */
|
190
include/haproxy/quic_loss.h
Normal file
190
include/haproxy/quic_loss.h
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* include/proto/quic_loss.h
|
||||
* This file provides interface definition for QUIC loss detection.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_QUIC_LOSS_H
|
||||
#define _PROTO_QUIC_LOSS_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <haproxy/ticks.h>
|
||||
#include <haproxy/time.h>
|
||||
#include <haproxy/xprt_quic-t.h>
|
||||
|
||||
#include <haproxy/trace.h>
|
||||
|
||||
#define TRACE_SOURCE &trace_quic
|
||||
|
||||
static inline void quic_loss_init(struct quic_loss *ql)
|
||||
{
|
||||
ql->srtt = QUIC_LOSS_INITIAL_RTT << 4;
|
||||
ql->rtt_var = (QUIC_LOSS_INITIAL_RTT >> 1) << 2;
|
||||
ql->rtt_min = 0;
|
||||
ql->pto_count = 0;
|
||||
}
|
||||
|
||||
/* Update <ql> QUIC loss information with new <rtt> measurement and <ack_delay>
|
||||
* on ACK frame receipt which MUST be min(ack->ack_delay, max_ack_delay) for
|
||||
* non handshake packets.
|
||||
*/
|
||||
static inline void quic_loss_srtt_update(struct quic_loss *ql,
|
||||
unsigned int rtt, unsigned int ack_delay,
|
||||
struct quic_conn *conn)
|
||||
{
|
||||
TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, conn->conn, &rtt, &ack_delay, ql);
|
||||
ql->latest_rtt = rtt;
|
||||
if (!ql->rtt_min) {
|
||||
/* No previous measurement. */
|
||||
ql->srtt = rtt << 3;
|
||||
/* rttval <- rtt / 2 or 4*rttval <- 2*rtt. */
|
||||
ql->rtt_var = rtt << 1;
|
||||
ql->rtt_min = rtt;
|
||||
}
|
||||
else {
|
||||
int diff;
|
||||
|
||||
ql->rtt_min = QUIC_MIN(rtt, ql->rtt_min);
|
||||
/* Specific to QUIC (RTT adjustment). */
|
||||
if (ack_delay && rtt > ql->rtt_min + ack_delay)
|
||||
rtt -= ack_delay;
|
||||
diff = ql->srtt - rtt;
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
/* 4*rttvar = 3*rttvar + |diff| */
|
||||
ql->rtt_var += diff - (ql->rtt_var >> 2);
|
||||
/* 8*srtt = 7*srtt + rtt */
|
||||
ql->srtt += rtt - (ql->srtt >> 3);
|
||||
}
|
||||
TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, conn->conn,,, ql);
|
||||
}
|
||||
|
||||
/* Return 1 if a persitent congestion is observed for a list of
|
||||
* lost packets sent during <period> period depending on <ql> loss information,
|
||||
* <now_us> the current time and <max_ack_delay_us> the maximum ACK delay of the connection
|
||||
* experiencing a packet loss. Return 0 on the contrary.
|
||||
*/
|
||||
static inline int quic_loss_persistent_congestion(struct quic_loss *ql,
|
||||
unsigned int period,
|
||||
unsigned int now_us,
|
||||
unsigned int max_ack_delay)
|
||||
{
|
||||
unsigned int congestion_period;
|
||||
|
||||
if (!period)
|
||||
return 0;
|
||||
|
||||
congestion_period = (ql->srtt >> 3) +
|
||||
QUIC_MAX(ql->rtt_var, QUIC_TIMER_GRANULARITY) + max_ack_delay;
|
||||
congestion_period *= QUIC_LOSS_PACKET_THRESHOLD;
|
||||
|
||||
return period >= congestion_period;
|
||||
}
|
||||
|
||||
/* Returns for <qc> QUIC connection the first packet number space which
|
||||
* experienced packet loss, if any or a packet number space with
|
||||
* TICK_ETERNITY as packet loss time if not.
|
||||
*/
|
||||
static inline struct quic_pktns *quic_loss_pktns(struct quic_conn *qc)
|
||||
{
|
||||
enum quic_tls_pktns i;
|
||||
struct quic_pktns *pktns;
|
||||
|
||||
pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL];
|
||||
for (i = QUIC_TLS_PKTNS_01RTT; i < QUIC_TLS_PKTNS_MAX; i++)
|
||||
if (qc->pktns[i].tx.loss_time < pktns->tx.loss_time)
|
||||
pktns = &qc->pktns[i];
|
||||
|
||||
return pktns;
|
||||
}
|
||||
|
||||
/* Returns for <qc> QUIC connection the first packet number space to
|
||||
* arm the PTO for if any or a packet number space with TICK_ETERNITY
|
||||
* as PTO value if not.
|
||||
*/
|
||||
static inline struct quic_pktns *quic_pto_pktns(struct quic_conn *qc,
|
||||
int handshake_completed,
|
||||
unsigned int *pto)
|
||||
{
|
||||
int i;
|
||||
unsigned int duration, lpto, time_of_last_eliciting;
|
||||
struct quic_loss *ql = &qc->path->loss;
|
||||
struct quic_pktns *pktns;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_SPTO, qc->conn);
|
||||
duration =
|
||||
(ql->srtt >> 3) +
|
||||
(QUIC_MAX(ql->rtt_var, QUIC_TIMER_GRANULARITY) << ql->pto_count);
|
||||
|
||||
if (!qc->path->in_flight) {
|
||||
struct quic_enc_level *hel;
|
||||
|
||||
hel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE];
|
||||
if (hel->tls_ctx.tx.flags & QUIC_FL_TLS_SECRETS_SET) {
|
||||
pktns = &qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE];
|
||||
}
|
||||
else {
|
||||
pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL];
|
||||
}
|
||||
lpto = tick_add(now_ms, duration);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpto = TICK_ETERNITY;
|
||||
pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL];
|
||||
|
||||
for (i = QUIC_TLS_PKTNS_INITIAL; i < QUIC_TLS_PKTNS_MAX; i++) {
|
||||
unsigned int tmp_pto;
|
||||
struct quic_pktns *p;
|
||||
|
||||
p = &qc->pktns[i];
|
||||
if (!p->tx.in_flight)
|
||||
continue;
|
||||
|
||||
if (i == QUIC_TLS_PKTNS_01RTT) {
|
||||
if (!handshake_completed) {
|
||||
pktns = p;
|
||||
goto out;
|
||||
}
|
||||
|
||||
duration += qc->max_ack_delay << ql->pto_count;
|
||||
}
|
||||
|
||||
time_of_last_eliciting = p->tx.time_of_last_eliciting;
|
||||
tmp_pto =
|
||||
tick_first(lpto, tick_add(time_of_last_eliciting, duration));
|
||||
if (!tick_isset(lpto) || tmp_pto < lpto) {
|
||||
lpto = tmp_pto;
|
||||
pktns = p;
|
||||
}
|
||||
TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc->conn, p);
|
||||
}
|
||||
|
||||
out:
|
||||
if (pto)
|
||||
*pto = lpto;
|
||||
TRACE_LEAVE(QUIC_EV_CONN_SPTO, qc->conn, pktns, &duration);
|
||||
|
||||
return pktns;
|
||||
}
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _PROTO_QUIC_LOSS_H */
|
@ -21,6 +21,10 @@
|
||||
|
||||
#ifndef _HAPROXY_QUIC_SOCK_H
|
||||
#define _HAPROXY_QUIC_SOCK_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
@ -33,6 +37,7 @@ int quic_sock_accepting_conn(const struct receiver *rx);
|
||||
struct connection *quic_sock_accept_conn(struct listener *l, int *status);
|
||||
void quic_sock_fd_iocb(int fd);
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _HAPROXY_QUIC_SOCK_H */
|
||||
|
||||
/*
|
||||
|
110
include/haproxy/quic_tls-t.h
Normal file
110
include/haproxy/quic_tls-t.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* include/types/quic_tls.h
|
||||
* This file provides definitions for QUIC-TLS.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_QUIC_TLS_H
|
||||
#define _TYPES_QUIC_TLS_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/* It seems TLS 1.3 ciphersuites macros differ between openssl and boringssl */
|
||||
|
||||
#if defined(OPENSSL_IS_BORINGSSL)
|
||||
#if !defined(TLS1_3_CK_AES_128_GCM_SHA256)
|
||||
#define TLS1_3_CK_AES_128_GCM_SHA256 TLS1_CK_AES_128_GCM_SHA256
|
||||
#endif
|
||||
#if !defined(TLS1_3_CK_AES_256_GCM_SHA384)
|
||||
#define TLS1_3_CK_AES_256_GCM_SHA384 TLS1_CK_AES_256_GCM_SHA384
|
||||
#endif
|
||||
#if !defined(TLS1_3_CK_CHACHA20_POLY1305_SHA256)
|
||||
#define TLS1_3_CK_CHACHA20_POLY1305_SHA256 TLS1_CK_CHACHA20_POLY1305_SHA256
|
||||
#endif
|
||||
#if !defined(TLS1_3_CK_AES_128_CCM_SHA256)
|
||||
/* Note that TLS1_CK_AES_128_CCM_SHA256 is not defined in boringssl */
|
||||
#define TLS1_3_CK_AES_128_CCM_SHA256 0x03001304
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The TLS extension (enum) for QUIC transport parameters */
|
||||
#define TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS 0xffa5
|
||||
|
||||
/* QUIC handshake states for both clients and servers. */
|
||||
enum quic_handshake_state {
|
||||
QUIC_HS_ST_CLIENT_INITIAL,
|
||||
QUIC_HS_ST_CLIENT_HANDSHAKE,
|
||||
QUIC_HS_ST_CLIENT_HANDSHAKE_FAILED,
|
||||
|
||||
QUIC_HS_ST_SERVER_INITIAL,
|
||||
QUIC_HS_ST_SERVER_HANDSHAKE,
|
||||
QUIC_HS_ST_SERVER_HANDSHAKE_FAILED,
|
||||
|
||||
/* Common to servers and clients */
|
||||
QUIC_HS_ST_COMPLETE,
|
||||
QUIC_HS_ST_CONFIRMED,
|
||||
};
|
||||
|
||||
/* QUIC TLS level encryption */
|
||||
enum quic_tls_enc_level {
|
||||
QUIC_TLS_ENC_LEVEL_NONE = -1,
|
||||
QUIC_TLS_ENC_LEVEL_INITIAL,
|
||||
QUIC_TLS_ENC_LEVEL_EARLY_DATA,
|
||||
QUIC_TLS_ENC_LEVEL_HANDSHAKE,
|
||||
QUIC_TLS_ENC_LEVEL_APP,
|
||||
/* Please do not insert any value after this following one */
|
||||
QUIC_TLS_ENC_LEVEL_MAX,
|
||||
};
|
||||
|
||||
/* QUIC packet number spaces */
|
||||
enum quic_tls_pktns {
|
||||
QUIC_TLS_PKTNS_INITIAL,
|
||||
QUIC_TLS_PKTNS_01RTT,
|
||||
QUIC_TLS_PKTNS_HANDSHAKE,
|
||||
/* Please do not insert any value after this following one */
|
||||
QUIC_TLS_PKTNS_MAX,
|
||||
};
|
||||
|
||||
/* The ciphersuites for AEAD QUIC-TLS have 16-bytes authentication tag */
|
||||
#define QUIC_TLS_TAG_LEN 16
|
||||
|
||||
extern unsigned char initial_salt[20];
|
||||
|
||||
/* Flag to be used when TLS secrets have been set. */
|
||||
#define QUIC_FL_TLS_SECRETS_SET (1 << 0)
|
||||
/* Flag to be used when TLS secrets have been discarded. */
|
||||
#define QUIC_FL_TLS_SECRETS_DCD (1 << 1)
|
||||
|
||||
struct quic_tls_secrets {
|
||||
const EVP_CIPHER *aead;
|
||||
const EVP_MD *md;
|
||||
const EVP_CIPHER *hp;
|
||||
unsigned char key[32];
|
||||
unsigned char iv[12];
|
||||
/* Header protection key.
|
||||
* Note: the header protection is applied after packet protection.
|
||||
* As the header belong to the data, its protection must be removed before removing
|
||||
* the packet protection.
|
||||
*/
|
||||
unsigned char hp_key[32];
|
||||
char flags;
|
||||
};
|
||||
|
||||
struct quic_tls_ctx {
|
||||
struct quic_tls_secrets rx;
|
||||
struct quic_tls_secrets tx;
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _TYPES_QUIC_TLS_H */
|
||||
|
441
include/haproxy/quic_tls.h
Normal file
441
include/haproxy/quic_tls.h
Normal file
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* include/proto/quic_tls.h
|
||||
* This file provides definitions for QUIC-TLS.
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_QUIC_TLS_H
|
||||
#define _PROTO_QUIC_TLS_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#define TRACE_SOURCE &trace_quic
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <haproxy/dynbuf.h>
|
||||
#include <haproxy/quic_tls-t.h>
|
||||
#include <haproxy/trace.h>
|
||||
#include <haproxy/xprt_quic.h>
|
||||
|
||||
void quic_tls_keys_hexdump(struct buffer *buf, struct quic_tls_secrets *secs);
|
||||
|
||||
void quic_tls_secret_hexdump(struct buffer *buf,
|
||||
const unsigned char *secret, size_t secret_len);
|
||||
|
||||
int quic_derive_initial_secret(const EVP_MD *md,
|
||||
unsigned char *initial_secret, size_t initial_secret_sz,
|
||||
const unsigned char *secret, size_t secret_sz);
|
||||
|
||||
int quic_tls_derive_initial_secrets(const EVP_MD *md,
|
||||
unsigned char *rx, size_t rx_sz,
|
||||
unsigned char *tx, size_t tx_sz,
|
||||
const unsigned char *secret, size_t secret_sz,
|
||||
int server);
|
||||
|
||||
int quic_tls_encrypt(unsigned char *buf, size_t len,
|
||||
const unsigned char *aad, size_t aad_len,
|
||||
const EVP_CIPHER *aead,
|
||||
const unsigned char *key, const unsigned char *iv);
|
||||
|
||||
int quic_tls_decrypt(unsigned char *buf, size_t len,
|
||||
unsigned char *aad, size_t aad_len,
|
||||
const EVP_CIPHER *aead,
|
||||
const unsigned char *key, const unsigned char *iv);
|
||||
|
||||
int quic_tls_derive_keys(const EVP_CIPHER *aead, const EVP_CIPHER *hp,
|
||||
const EVP_MD *md,
|
||||
unsigned char *key, size_t keylen,
|
||||
unsigned char *iv, size_t ivlen,
|
||||
unsigned char *hp_key, size_t hp_keylen,
|
||||
const unsigned char *secret, size_t secretlen);
|
||||
|
||||
int quic_aead_iv_build(unsigned char *iv, size_t ivlen,
|
||||
unsigned char *aead_iv, size_t aead_ivlen, uint64_t pn);
|
||||
|
||||
static inline const EVP_CIPHER *tls_aead(const SSL_CIPHER *cipher)
|
||||
{
|
||||
switch (SSL_CIPHER_get_id(cipher)) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
return EVP_aes_128_gcm();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_aes_256_gcm();
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
/* XXX TO DO XXX */
|
||||
/* Note that for chacha20_poly1305, there exists EVP_AEAD_chacha20_poly135() function
|
||||
* which returns a pointer to const EVP_AEAD.
|
||||
*/
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_chacha20_poly1305();
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return EVP_aes_128_ccm();
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const EVP_MD *tls_md(const SSL_CIPHER *cipher)
|
||||
{
|
||||
switch (SSL_CIPHER_get_id(cipher)) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
/* XXX TO DO XXX */
|
||||
/* Note that for chacha20_poly1305, there exists EVP_AEAD_chacha20_poly135() function
|
||||
* which returns a pointer to const EVP_AEAD.
|
||||
*/
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
#endif
|
||||
return EVP_sha256();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_sha384();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const EVP_CIPHER *tls_hp(const SSL_CIPHER *cipher)
|
||||
{
|
||||
switch (SSL_CIPHER_get_id(cipher)) {
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
/* XXX TO DO XXX */
|
||||
/* Note that for chacha20_poly1305, there exists EVP_AEAD_chacha20_poly135() function
|
||||
* which returns a pointer to const EVP_AEAD.
|
||||
*/
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_chacha20();
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
#endif
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
return EVP_aes_128_ctr();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_aes_256_ctr();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* These following functions map TLS implementation encryption level to ours */
|
||||
static inline enum quic_tls_enc_level ssl_to_quic_enc_level(enum ssl_encryption_level_t level)
|
||||
{
|
||||
switch (level) {
|
||||
case ssl_encryption_initial:
|
||||
return QUIC_TLS_ENC_LEVEL_INITIAL;
|
||||
case ssl_encryption_early_data:
|
||||
return QUIC_TLS_ENC_LEVEL_EARLY_DATA;
|
||||
case ssl_encryption_handshake:
|
||||
return QUIC_TLS_ENC_LEVEL_HANDSHAKE;
|
||||
case ssl_encryption_application:
|
||||
return QUIC_TLS_ENC_LEVEL_APP;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* These two following functions map our encryption level to the TLS implementation ones. */
|
||||
static inline enum quic_tls_enc_level quic_to_ssl_enc_level(enum quic_tls_enc_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case QUIC_TLS_ENC_LEVEL_INITIAL:
|
||||
return ssl_encryption_initial;
|
||||
case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
|
||||
return ssl_encryption_early_data;
|
||||
case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
|
||||
return ssl_encryption_handshake;
|
||||
case QUIC_TLS_ENC_LEVEL_APP:
|
||||
return ssl_encryption_application;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a human readable string from <state> QUIC handshake state of NULL
|
||||
* for unknown state values (for debug purpose).
|
||||
*/
|
||||
static inline char *quic_hdshk_state_str(const enum quic_handshake_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case QUIC_HS_ST_CLIENT_INITIAL:
|
||||
return "CI";
|
||||
case QUIC_HS_ST_CLIENT_HANDSHAKE:
|
||||
return "CH";
|
||||
case QUIC_HS_ST_CLIENT_HANDSHAKE_FAILED:
|
||||
return "CF";
|
||||
case QUIC_HS_ST_SERVER_INITIAL:
|
||||
return "SI";
|
||||
case QUIC_HS_ST_SERVER_HANDSHAKE:
|
||||
return "SH";
|
||||
case QUIC_HS_ST_SERVER_HANDSHAKE_FAILED:
|
||||
return "SF";
|
||||
case QUIC_HS_ST_COMPLETE:
|
||||
return "CP";
|
||||
case QUIC_HS_ST_CONFIRMED:
|
||||
return "CF";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return a human readable string from <err> SSL error (returned from
|
||||
* SSL_get_error())
|
||||
*/
|
||||
static inline const char *ssl_error_str(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case SSL_ERROR_NONE:
|
||||
return "NONE";
|
||||
case SSL_ERROR_SSL:
|
||||
return "SSL";
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return "WANT_READ";
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return "WANT_WRITE";
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return "X509_LOOKUP";
|
||||
case SSL_ERROR_SYSCALL:
|
||||
return "SYSCALL";
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return "ZERO_RETURN";
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
return "WANT_CONNECT";
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
return "WANT_ACCEPT";
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
case SSL_ERROR_WANT_ASYNC:
|
||||
return "WANT_ASYNC";
|
||||
case SSL_ERROR_WANT_ASYNC_JOB:
|
||||
return "WANT_ASYNC_JOB";
|
||||
case SSL_ERROR_WANT_CLIENT_HELLO_CB:
|
||||
return "WANT_CLIENT_HELLO_CB";
|
||||
#endif
|
||||
default:
|
||||
return "UNKNWON";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return a character identifying the encryption level from <level> QUIC TLS
|
||||
* encryption level (for debug purpose).
|
||||
* Initial -> 'I', Early Data -> 'E', Handshake -> 'H', Application -> 'A' and
|
||||
* '-' if undefined.
|
||||
*/
|
||||
static inline char quic_enc_level_char(enum quic_tls_enc_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case QUIC_TLS_ENC_LEVEL_INITIAL:
|
||||
return 'I';
|
||||
case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
|
||||
return 'E';
|
||||
case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
|
||||
return 'H';
|
||||
case QUIC_TLS_ENC_LEVEL_APP:
|
||||
return 'A';
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a character identifying <qel> encryption level from <qc> QUIC connection
|
||||
* (for debug purpose).
|
||||
* Initial -> 'I', Early Data -> 'E', Handshake -> 'H', Application -> 'A' and
|
||||
* '-' if undefined.
|
||||
*/
|
||||
static inline char quic_enc_level_char_from_qel(const struct quic_enc_level *qel,
|
||||
const struct quic_conn *qc)
|
||||
{
|
||||
if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL])
|
||||
return 'I';
|
||||
else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA])
|
||||
return 'E';
|
||||
else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])
|
||||
return 'H';
|
||||
else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_APP])
|
||||
return 'A';
|
||||
return '-';
|
||||
}
|
||||
|
||||
/* Return a character identifying the encryption level of a packet depending on
|
||||
* its <type> type, and its <long_header> header length (for debug purpose).
|
||||
* Initial -> 'I', ORTT -> '0', Handshake -> 'H', Application -> 'A' and
|
||||
* '-' if undefined.
|
||||
*/
|
||||
static inline char quic_packet_type_enc_level_char(int packet_type)
|
||||
{
|
||||
switch (packet_type) {
|
||||
case QUIC_PACKET_TYPE_INITIAL:
|
||||
return 'I';
|
||||
case QUIC_PACKET_TYPE_0RTT:
|
||||
return '0';
|
||||
case QUIC_PACKET_TYPE_HANDSHAKE:
|
||||
return 'H';
|
||||
case QUIC_PACKET_TYPE_SHORT:
|
||||
return 'A';
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the TLS encryption level to be used for <packet_type>
|
||||
* QUIC packet type.
|
||||
* Returns -1 if there is no TLS encryption level for <packet_type>
|
||||
* packet type.
|
||||
*/
|
||||
static inline enum quic_tls_enc_level quic_packet_type_enc_level(enum quic_pkt_type packet_type)
|
||||
{
|
||||
switch (packet_type) {
|
||||
case QUIC_PACKET_TYPE_INITIAL:
|
||||
return QUIC_TLS_ENC_LEVEL_INITIAL;
|
||||
case QUIC_PACKET_TYPE_0RTT:
|
||||
return QUIC_TLS_ENC_LEVEL_EARLY_DATA;
|
||||
case QUIC_PACKET_TYPE_HANDSHAKE:
|
||||
return QUIC_TLS_ENC_LEVEL_HANDSHAKE;
|
||||
case QUIC_PACKET_TYPE_RETRY:
|
||||
return QUIC_TLS_ENC_LEVEL_NONE;
|
||||
case QUIC_PACKET_TYPE_SHORT:
|
||||
return QUIC_TLS_ENC_LEVEL_APP;
|
||||
default:
|
||||
return QUIC_TLS_ENC_LEVEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline enum quic_tls_pktns quic_tls_pktns(enum quic_tls_enc_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case QUIC_TLS_ENC_LEVEL_INITIAL:
|
||||
return QUIC_TLS_PKTNS_INITIAL;
|
||||
case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
|
||||
case QUIC_TLS_ENC_LEVEL_APP:
|
||||
return QUIC_TLS_PKTNS_01RTT;
|
||||
case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
|
||||
return QUIC_TLS_PKTNS_HANDSHAKE;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize a TLS cryptographic context for the Initial encryption level. */
|
||||
static inline void quic_initial_tls_ctx_init(struct quic_tls_ctx *ctx)
|
||||
{
|
||||
ctx->rx.aead = ctx->tx.aead = EVP_aes_128_gcm();
|
||||
ctx->rx.md = ctx->tx.md = EVP_sha256();
|
||||
ctx->rx.hp = ctx->tx.hp = EVP_aes_128_ctr();
|
||||
}
|
||||
|
||||
static inline int quic_tls_level_pkt_type(enum quic_tls_enc_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case QUIC_TLS_ENC_LEVEL_INITIAL:
|
||||
return QUIC_PACKET_TYPE_INITIAL;
|
||||
case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
|
||||
return QUIC_PACKET_TYPE_0RTT;
|
||||
case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
|
||||
return QUIC_PACKET_TYPE_HANDSHAKE;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set <*level> and <*next_level> depending on <state> QUIC handshake state. */
|
||||
static inline int quic_get_tls_enc_levels(enum quic_tls_enc_level *level,
|
||||
enum quic_tls_enc_level *next_level,
|
||||
enum quic_handshake_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case QUIC_HS_ST_SERVER_INITIAL:
|
||||
case QUIC_HS_ST_CLIENT_INITIAL:
|
||||
*level = QUIC_TLS_ENC_LEVEL_INITIAL;
|
||||
*next_level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
|
||||
break;
|
||||
case QUIC_HS_ST_SERVER_HANDSHAKE:
|
||||
case QUIC_HS_ST_CLIENT_HANDSHAKE:
|
||||
case QUIC_HS_ST_COMPLETE:
|
||||
case QUIC_HS_ST_CONFIRMED:
|
||||
*level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
|
||||
*next_level = QUIC_TLS_ENC_LEVEL_APP;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Flag the keys at <qel> encryption level as discarded. */
|
||||
static inline void quic_tls_discard_keys(struct quic_enc_level *qel)
|
||||
{
|
||||
qel->tls_ctx.rx.flags |= QUIC_FL_TLS_SECRETS_DCD;
|
||||
qel->tls_ctx.tx.flags |= QUIC_FL_TLS_SECRETS_DCD;
|
||||
}
|
||||
|
||||
/* Derive the initial secrets with <ctx> as QUIC TLS context which is the
|
||||
* cryptographic context for the first encryption level (Initial) from
|
||||
* <cid> connection ID with <cidlen> as length (in bytes) for a server or not
|
||||
* depending on <server> boolean value.
|
||||
* Return 1 if succeeded or 0 if not.
|
||||
*/
|
||||
static inline int qc_new_isecs(struct connection *conn,
|
||||
const unsigned char *cid, size_t cidlen, int server)
|
||||
{
|
||||
unsigned char initial_secret[32];
|
||||
/* Initial secret to be derived for incoming packets */
|
||||
unsigned char rx_init_sec[32];
|
||||
/* Initial secret to be derived for outgoing packets */
|
||||
unsigned char tx_init_sec[32];
|
||||
struct quic_tls_secrets *rx_ctx, *tx_ctx;
|
||||
struct quic_tls_ctx *ctx;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_ISEC, conn);
|
||||
ctx = &conn->qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx;
|
||||
quic_initial_tls_ctx_init(ctx);
|
||||
if (!quic_derive_initial_secret(ctx->rx.md,
|
||||
initial_secret, sizeof initial_secret,
|
||||
cid, cidlen))
|
||||
goto err;
|
||||
|
||||
if (!quic_tls_derive_initial_secrets(ctx->rx.md,
|
||||
rx_init_sec, sizeof rx_init_sec,
|
||||
tx_init_sec, sizeof tx_init_sec,
|
||||
initial_secret, sizeof initial_secret, server))
|
||||
goto err;
|
||||
|
||||
rx_ctx = &ctx->rx;
|
||||
tx_ctx = &ctx->tx;
|
||||
if (!quic_tls_derive_keys(ctx->rx.aead, ctx->rx.hp, ctx->rx.md,
|
||||
rx_ctx->key, sizeof rx_ctx->key,
|
||||
rx_ctx->iv, sizeof rx_ctx->iv,
|
||||
rx_ctx->hp_key, sizeof rx_ctx->hp_key,
|
||||
rx_init_sec, sizeof rx_init_sec))
|
||||
goto err;
|
||||
|
||||
rx_ctx->flags |= QUIC_FL_TLS_SECRETS_SET;
|
||||
if (!quic_tls_derive_keys(ctx->tx.aead, ctx->tx.hp, ctx->tx.md,
|
||||
tx_ctx->key, sizeof tx_ctx->key,
|
||||
tx_ctx->iv, sizeof tx_ctx->iv,
|
||||
tx_ctx->hp_key, sizeof tx_ctx->hp_key,
|
||||
tx_init_sec, sizeof tx_init_sec))
|
||||
goto err;
|
||||
|
||||
tx_ctx->flags |= QUIC_FL_TLS_SECRETS_SET;
|
||||
TRACE_LEAVE(QUIC_EV_CONN_ISEC, conn, rx_init_sec, tx_init_sec);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
TRACE_DEVEL("leaving in error", QUIC_EV_CONN_EISEC, conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _PROTO_QUIC_TLS_H */
|
||||
|
640
include/haproxy/xprt_quic-t.h
Normal file
640
include/haproxy/xprt_quic-t.h
Normal file
@ -0,0 +1,640 @@
|
||||
/*
|
||||
* include/haproxy/xprt_quic-t.h
|
||||
* This file contains applet function prototypes
|
||||
*
|
||||
* Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _HAPROXY_XPRT_QUIC_T_H
|
||||
#define _HAPROXY_XPRT_QUIC_T_H
|
||||
#ifdef USE_QUIC
|
||||
#ifndef USE_OPENSSL
|
||||
#error "Must define USE_OPENSSL"
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <haproxy/list.h>
|
||||
|
||||
#include <haproxy/quic_cc-t.h>
|
||||
#include <haproxy/quic_frame-t.h>
|
||||
#include <haproxy/quic_tls-t.h>
|
||||
#include <haproxy/quic_loss-t.h>
|
||||
#include <haproxy/task.h>
|
||||
|
||||
#include <import/eb64tree.h>
|
||||
#include <import/ebmbtree.h>
|
||||
|
||||
#define QUIC_PROTOCOL_VERSION_DRAFT_28 0xff00001c /* draft-28 */
|
||||
|
||||
#define QUIC_INITIAL_IPV4_MTU 1252 /* (bytes) */
|
||||
#define QUIC_INITIAL_IPV6_MTU 1232
|
||||
/* XXX TO DO XXX */
|
||||
/* Maximum packet length during handshake */
|
||||
#define QUIC_PACKET_MAXLEN QUIC_INITIAL_IPV4_MTU
|
||||
|
||||
/* The minimum length of Initial packets. */
|
||||
#define QUIC_INITIAL_PACKET_MINLEN 1200
|
||||
|
||||
/*
|
||||
* QUIC CID lengths. This the length of the connection IDs for this QUIC
|
||||
* implementation.
|
||||
*/
|
||||
#define QUIC_CID_LEN 8
|
||||
|
||||
/* Common definitions for short and long QUIC packet headers. */
|
||||
/* QUIC connection ID maximum length for version 1. */
|
||||
#define QUIC_CID_MAXLEN 20 /* bytes */
|
||||
/*
|
||||
* All QUIC packets with long headers are made of at least (in bytes):
|
||||
* flags(1), version(4), DCID length(1), DCID(0..20), SCID length(1), SCID(0..20)
|
||||
*/
|
||||
#define QUIC_LONG_PACKET_MINLEN 7
|
||||
/*
|
||||
* All QUIC packets with short headers are made of at least (in bytes):
|
||||
* flags(1), DCID length(1), DCID(0..20)
|
||||
*/
|
||||
#define QUIC_SHORT_PACKET_MINLEN 2
|
||||
/* Byte 0 of QUIC packets. */
|
||||
#define QUIC_PACKET_LONG_HEADER_BIT 0x80 /* Long header format if set, short if not. */
|
||||
#define QUIC_PACKET_FIXED_BIT 0x40 /* Must always be set for all the headers. */
|
||||
|
||||
/*
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+
|
||||
* |1|1|T|T|X|X|X|X|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Version (32) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | DCID Len (8) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Destination Connection ID (0..160) ...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | SCID Len (8) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Source Connection ID (0..160) ...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* Long Header Packet Format
|
||||
*/
|
||||
|
||||
/* Two bits (T) for QUIC packet types. */
|
||||
#define QUIC_PACKET_TYPE_BITMASK 0x03
|
||||
#define QUIC_PACKET_TYPE_SHIFT 4
|
||||
|
||||
enum quic_pkt_type {
|
||||
QUIC_PACKET_TYPE_INITIAL,
|
||||
QUIC_PACKET_TYPE_0RTT,
|
||||
QUIC_PACKET_TYPE_HANDSHAKE,
|
||||
QUIC_PACKET_TYPE_RETRY,
|
||||
/*
|
||||
* The following one is not defined by the RFC but we define it for our
|
||||
* own convenience.
|
||||
*/
|
||||
QUIC_PACKET_TYPE_SHORT,
|
||||
};
|
||||
|
||||
/* Packet number field length. */
|
||||
#define QUIC_PACKET_PNL_BITMASK 0x03
|
||||
#define QUIC_PACKET_PN_MAXLEN 4
|
||||
|
||||
/*
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+
|
||||
* |0|1|S|R|R|K|P|P|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Destination Connection ID (0..160) ...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Packet Number (8/16/24/32) ...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Protected Payload (*) ...
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* Short Header Packet Format
|
||||
*/
|
||||
|
||||
/* Bit (S) of short header. */
|
||||
#define QUIC_PACKET_SPIN_BIT 0x20
|
||||
|
||||
/* Reserved Bits (R): The next two bits of byte 0 are reserved.
|
||||
* These bits are protected using header protection
|
||||
* (see Section 5.4 of [QUIC-TLS]). The value included
|
||||
* prior to protection MUST be set to 0. An endpoint MUST treat
|
||||
* receipt of a packet that has a non-zero value for these bits,
|
||||
* after removing both packet and header protection, as a connection
|
||||
* error of type PROTOCOL_VIOLATION. Discarding such a packet after
|
||||
* only removing header protection can expose the endpoint to attacks
|
||||
* (see Section 9.3 of [QUIC-TLS]).
|
||||
*/
|
||||
#define QUIC_PACKET_RESERVED_BITS 0x18 /* (protected) */
|
||||
|
||||
#define QUIC_PACKET_KEY_PHASE_BIT 0x04 /* (protected) */
|
||||
|
||||
/*
|
||||
* Tranport level error codes.
|
||||
*/
|
||||
#define NO_ERROR 0x00
|
||||
#define INTERNAL_ERROR 0x01
|
||||
#define CONNECTION_REFUSED_ERROR 0x02
|
||||
#define FLOW_CONTROL_ERROR 0x03
|
||||
#define STREAM_LIMIT_ERROR 0x04
|
||||
#define STREAM_STATE_ERROR 0x05
|
||||
#define FINAL_SIZE_ERROR 0x06
|
||||
#define FRAME_ENCODING_ERROR 0x07
|
||||
#define TRANSPORT_PARAMETER_ERROR 0x08
|
||||
#define CONNECTION_ID_LIMIT_ERROR 0x09
|
||||
#define PROTOCOL_VIOLATION 0x0a
|
||||
#define INVALID_TOKEN 0x0b
|
||||
#define APPLICATION_ERROR 0x0c
|
||||
#define CRYPTO_BUFFER_EXCEEDED 0x0d
|
||||
|
||||
/* XXX TODO: check/complete this remaining part (256 crypto reserved errors). */
|
||||
#define CRYPTO_ERROR 0x100
|
||||
|
||||
/* The maximum number of QUIC packets stored by the fd I/O handler by QUIC
|
||||
* connection. Must be a power of two.
|
||||
*/
|
||||
#define QUIC_CONN_MAX_PACKET 64
|
||||
|
||||
#define QUIC_STATELESS_RESET_TOKEN_LEN 16
|
||||
|
||||
#define QUIC_EV_CONN_NEW (1ULL << 0)
|
||||
#define QUIC_EV_CONN_INIT (1ULL << 1)
|
||||
#define QUIC_EV_CONN_ISEC (1ULL << 2)
|
||||
#define QUIC_EV_CONN_RSEC (1ULL << 3)
|
||||
#define QUIC_EV_CONN_WSEC (1ULL << 4)
|
||||
#define QUIC_EV_CONN_RWSEC (1ULL << 5)
|
||||
#define QUIC_EV_CONN_LPKT (1ULL << 6)
|
||||
#define QUIC_EV_CONN_SPKT (1ULL << 7)
|
||||
#define QUIC_EV_CONN_CHPKT (1ULL << 8)
|
||||
#define QUIC_EV_CONN_HPKT (1ULL << 9)
|
||||
#define QUIC_EV_CONN_PAPKT (1ULL << 10)
|
||||
#define QUIC_EV_CONN_PAPKTS (1ULL << 11)
|
||||
#define QUIC_EV_CONN_HDSHK (1ULL << 12)
|
||||
#define QUIC_EV_CONN_RMHP (1ULL << 13)
|
||||
#define QUIC_EV_CONN_PRSHPKT (1ULL << 14)
|
||||
#define QUIC_EV_CONN_PRSAPKT (1ULL << 15)
|
||||
#define QUIC_EV_CONN_PRSFRM (1ULL << 16)
|
||||
#define QUIC_EV_CONN_PRSAFRM (1ULL << 17)
|
||||
#define QUIC_EV_CONN_BFRM (1ULL << 18)
|
||||
#define QUIC_EV_CONN_PHPKTS (1ULL << 19)
|
||||
#define QUIC_EV_CONN_TRMHP (1ULL << 20)
|
||||
#define QUIC_EV_CONN_ELRMHP (1ULL << 21)
|
||||
#define QUIC_EV_CONN_ELRXPKTS (1ULL << 22)
|
||||
#define QUIC_EV_CONN_SSLDATA (1ULL << 23)
|
||||
#define QUIC_EV_CONN_RXCDATA (1ULL << 24)
|
||||
#define QUIC_EV_CONN_ADDDATA (1ULL << 25)
|
||||
#define QUIC_EV_CONN_FFLIGHT (1ULL << 26)
|
||||
#define QUIC_EV_CONN_SSLALERT (1ULL << 27)
|
||||
#define QUIC_EV_CONN_CPAPKT (1ULL << 28)
|
||||
#define QUIC_EV_CONN_RTTUPDT (1ULL << 29)
|
||||
#define QUIC_EV_CONN_CC (1ULL << 30)
|
||||
#define QUIC_EV_CONN_SPPKTS (1ULL << 31)
|
||||
#define QUIC_EV_CONN_PKTLOSS (1ULL << 32)
|
||||
#define QUIC_EV_CONN_STIMER (1ULL << 33)
|
||||
#define QUIC_EV_CONN_PTIMER (1ULL << 34)
|
||||
#define QUIC_EV_CONN_SPTO (1ULL << 35)
|
||||
|
||||
#define QUIC_EV_CONN_ENEW (1ULL << 32)
|
||||
#define QUIC_EV_CONN_EISEC (1ULL << 33)
|
||||
#define QUIC_EV_CONN_ERSEC (1ULL << 34)
|
||||
#define QUIC_EV_CONN_EWSEC (1ULL << 35)
|
||||
#define QUIC_EV_CONN_ELPKT (1ULL << 36)
|
||||
#define QUIC_EV_CONN_ESPKT (1ULL << 37)
|
||||
#define QUIC_EV_CONN_ECHPKT (1ULL << 38)
|
||||
#define QUIC_EV_CONN_EHPKT (1ULL << 39)
|
||||
#define QUIC_EV_CONN_EPAPKT (1ULL << 40)
|
||||
|
||||
/* Similar to kernel min()/max() definitions. */
|
||||
#define QUIC_MIN(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(void) (&_a == &_b); \
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
#define QUIC_MAX(a, b) ({ \
|
||||
typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(void) (&_a == &_b); \
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
extern struct trace_source trace_quic;
|
||||
extern struct pool_head *pool_head_quic_rx_packet;
|
||||
extern struct pool_head *pool_head_quic_tx_packet;
|
||||
extern struct pool_head *pool_head_quic_tx_frm;
|
||||
|
||||
/*
|
||||
* This struct is used by ebmb_node structs as last member of flexible arrays.
|
||||
* So do not change the order of the member of quic_cid struct.
|
||||
* <data> member must be the first one.
|
||||
*/
|
||||
struct quic_cid {
|
||||
unsigned char data[QUIC_CID_MAXLEN + sizeof(in_port_t) + sizeof(struct in6_addr)];
|
||||
unsigned char len;
|
||||
};
|
||||
|
||||
/* The data structure used to build a set of connection IDs for each connection. */
|
||||
struct quic_connection_id {
|
||||
struct eb64_node seq_num;
|
||||
uint64_t retire_prior_to;
|
||||
struct quic_cid cid;
|
||||
unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
|
||||
};
|
||||
|
||||
struct preferred_address {
|
||||
uint16_t ipv4_port;
|
||||
uint16_t ipv6_port;
|
||||
uint8_t ipv4_addr[4];
|
||||
uint8_t ipv6_addr[16];
|
||||
struct quic_cid cid;
|
||||
uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
|
||||
};
|
||||
|
||||
/* Default values for some of transport parameters */
|
||||
#define QUIC_DFLT_MAX_PACKET_SIZE 65527
|
||||
#define QUIC_DFLT_ACK_DELAY_COMPONENT 3 /* milliseconds */
|
||||
#define QUIC_DFLT_MAX_ACK_DELAY 25 /* milliseconds */
|
||||
|
||||
/* Types of QUIC transport parameters */
|
||||
#define QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID 0
|
||||
#define QUIC_TP_IDLE_TIMEOUT 1
|
||||
#define QUIC_TP_STATELESS_RESET_TOKEN 2
|
||||
#define QUIC_TP_MAX_PACKET_SIZE 3
|
||||
#define QUIC_TP_INITIAL_MAX_DATA 4
|
||||
#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 5
|
||||
#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 6
|
||||
#define QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI 7
|
||||
#define QUIC_TP_INITIAL_MAX_STREAMS_BIDI 8
|
||||
#define QUIC_TP_INITIAL_MAX_STREAMS_UNI 9
|
||||
#define QUIC_TP_ACK_DELAY_EXPONENT 10
|
||||
#define QUIC_TP_MAX_ACK_DELAY 11
|
||||
#define QUIC_TP_DISABLE_ACTIVE_MIGRATION 12
|
||||
#define QUIC_TP_PREFERRED_ADDRESS 13
|
||||
#define QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 14
|
||||
#define QUIC_TP_INITIAL_SOURCE_CONNECTION_ID 15
|
||||
|
||||
/*
|
||||
* These defines are not for transport parameter type, but the maximum accepted value for
|
||||
* transport parameter types.
|
||||
*/
|
||||
#define QUIC_TP_ACK_DELAY_EXPONENT_LIMIT 20
|
||||
#define QUIC_TP_MAX_ACK_DELAY_LIMIT (1UL << 14)
|
||||
|
||||
/* The maximum length of encoded transport parameters for any QUIC peer. */
|
||||
#define QUIC_TP_MAX_ENCLEN 128
|
||||
/*
|
||||
* QUIC transport parameters.
|
||||
* Note that forbidden parameters sent by clients MUST generate TRANSPORT_PARAMETER_ERROR errors.
|
||||
*/
|
||||
struct quic_transport_params {
|
||||
uint64_t idle_timeout;
|
||||
uint64_t max_packet_size; /* Default: 65527 (max of UDP payload for IPv6) */
|
||||
uint64_t initial_max_data;
|
||||
uint64_t initial_max_stream_data_bidi_local;
|
||||
uint64_t initial_max_stream_data_bidi_remote;
|
||||
uint64_t initial_max_stream_data_uni;
|
||||
uint64_t initial_max_streams_bidi;
|
||||
uint64_t initial_max_streams_uni;
|
||||
uint64_t ack_delay_exponent; /* Default: 3, max: 20 */
|
||||
uint64_t max_ack_delay; /* Default: 3ms, max: 2^14ms*/
|
||||
uint64_t active_connection_id_limit;
|
||||
|
||||
/* Booleans */
|
||||
uint8_t disable_active_migration;
|
||||
uint8_t with_stateless_reset_token;
|
||||
uint8_t with_preferred_address;
|
||||
uint8_t original_destination_connection_id_present;
|
||||
uint8_t initial_source_connection_id_present;
|
||||
|
||||
uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN]; /* Forbidden for clients */
|
||||
/*
|
||||
* MUST be sent by servers.
|
||||
* When received by clients, must be set to 1 if present.
|
||||
*/
|
||||
struct quic_cid original_destination_connection_id; /* Forbidden for clients */
|
||||
/* MUST be present both for servers and clients. */
|
||||
struct quic_cid initial_source_connection_id;
|
||||
struct preferred_address preferred_address; /* Forbidden for clients */
|
||||
};
|
||||
|
||||
/* Structure for ACK ranges sent in ACK frames. */
|
||||
struct quic_ack_range {
|
||||
struct list list;
|
||||
int64_t first;
|
||||
int64_t last;
|
||||
};
|
||||
|
||||
struct quic_ack_ranges {
|
||||
/* list of ACK ranges. */
|
||||
struct list list;
|
||||
/* The number of ACK ranges is this lists */
|
||||
size_t sz;
|
||||
/* The number of bytes required to encode this ACK ranges lists. */
|
||||
size_t enc_sz;
|
||||
};
|
||||
|
||||
/* Flag the packet number space as requiring an ACK frame to be sent. */
|
||||
#define QUIC_FL_PKTNS_ACK_REQUIRED (1UL << 0)
|
||||
#define QUIC_FL_PKTNS_ACK_RECEIVED (1UL << 1)
|
||||
|
||||
/* The maximum number of dgrams which may be sent upon PTO expirations. */
|
||||
#define QUIC_MAX_NB_PTO_DGRAMS 2
|
||||
|
||||
/* QUIC packet number space */
|
||||
struct quic_pktns {
|
||||
struct {
|
||||
/* List of frames to send. */
|
||||
struct list frms;
|
||||
/* Next packet number to use for transmissions. */
|
||||
int64_t next_pn;
|
||||
/* Largest acked sent packet. */
|
||||
int64_t largest_acked_pn;
|
||||
/* The packet which has been sent. */
|
||||
struct eb_root pkts;
|
||||
/* The time the most recent ack-eliciting packer was sent. */
|
||||
unsigned int time_of_last_eliciting;
|
||||
/* The time this packet number space has experienced packet loss. */
|
||||
unsigned int loss_time;
|
||||
/* Boolean to denote if we must send probe packet. */
|
||||
unsigned int pto_probe;
|
||||
/* In flight bytes for this packet number space. */
|
||||
size_t in_flight;
|
||||
} tx;
|
||||
struct {
|
||||
/* Largest packet number */
|
||||
int64_t largest_pn;
|
||||
/* Number of ack-eliciting packets. */
|
||||
size_t nb_ack_eliciting;
|
||||
struct quic_ack_ranges ack_ranges;
|
||||
} rx;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* The QUIC packet numbers are 62-bits integers */
|
||||
#define QUIC_MAX_PACKET_NUM ((1ULL << 62) - 1)
|
||||
|
||||
/* Default QUIC connection transport parameters */
|
||||
extern struct quic_transport_params quic_dflt_transport_params;
|
||||
|
||||
/* Flag a received packet as being an ack-eliciting packet. */
|
||||
#define QUIC_FL_RX_PACKET_ACK_ELICITING (1UL << 0)
|
||||
|
||||
struct quic_rx_packet {
|
||||
struct list list;
|
||||
struct list rx_list;
|
||||
struct quic_conn *qc;
|
||||
unsigned char type;
|
||||
uint32_t version;
|
||||
/* Initial desctination connection ID. */
|
||||
struct quic_cid dcid;
|
||||
struct quic_cid scid;
|
||||
size_t odcid_len;
|
||||
size_t pn_offset;
|
||||
/* Packet number */
|
||||
int64_t pn;
|
||||
/* Packet number length */
|
||||
uint32_t pnl;
|
||||
uint64_t token_len;
|
||||
/* Packet length */
|
||||
uint64_t len;
|
||||
/* Additional authenticated data length */
|
||||
size_t aad_len;
|
||||
unsigned char data[QUIC_PACKET_MAXLEN];
|
||||
struct eb64_node pn_node;
|
||||
volatile unsigned int refcnt;
|
||||
/* Source address of this packet. */
|
||||
struct sockaddr_storage saddr;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* UDP datagram context used by the I/O handler receiver callbacks.
|
||||
* Useful to store the connection
|
||||
*/
|
||||
struct quic_dgram_ctx {
|
||||
struct quic_conn *qc;
|
||||
struct ebmb_node *dcid_node;
|
||||
void *owner;
|
||||
};
|
||||
|
||||
/* QUIC packet reader. */
|
||||
typedef ssize_t qpkt_read_func(unsigned char **buf,
|
||||
const unsigned char *end,
|
||||
struct quic_rx_packet *qpkt,
|
||||
struct quic_dgram_ctx *dgram_ctx,
|
||||
struct sockaddr_storage *saddr);
|
||||
|
||||
/* Structure to store enough information about the RX CRYPTO frames. */
|
||||
struct quic_rx_crypto_frm {
|
||||
struct eb64_node offset_node;
|
||||
uint64_t len;
|
||||
const unsigned char *data;
|
||||
struct quic_rx_packet *pkt;
|
||||
};
|
||||
|
||||
/* Flag a sent packet as being an ack-eliciting packet. */
|
||||
#define QUIC_FL_TX_PACKET_ACK_ELICITING (1UL << 0)
|
||||
/* Flag a sent packet as containing a PADDING frame. */
|
||||
#define QUIC_FL_TX_PACKET_PADDING (1UL << 1)
|
||||
/* Flag a sent packet as being in flight. */
|
||||
#define QUIC_FL_TX_PACKET_IN_FLIGHT (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING)
|
||||
|
||||
/* Structure to store enough information about TX QUIC packets. */
|
||||
struct quic_tx_packet {
|
||||
/* List entry point. */
|
||||
struct list list;
|
||||
/* This is not the packet length but the length of outstanding data
|
||||
* for in flight TX packet.
|
||||
*/
|
||||
size_t in_flight_len;
|
||||
struct eb64_node pn_node;
|
||||
/* The number of bytes of CRYPTO data in this packet. */
|
||||
unsigned int cdata_len;
|
||||
/* The list of frames of this packet. */
|
||||
struct list frms;
|
||||
/* The time this packet was sent (usec). */
|
||||
unsigned int time_sent;
|
||||
/* Packet number spakce. */
|
||||
struct quic_pktns *pktns;
|
||||
/* Flags. */
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* Structure to stora enough information about the TX frames. */
|
||||
struct quic_tx_frm {
|
||||
struct list list;
|
||||
unsigned char type;
|
||||
union {
|
||||
struct quic_crypto crypto;
|
||||
struct quic_new_connection_id new_connection_id;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#define QUIC_CRYPTO_BUF_SHIFT 10
|
||||
#define QUIC_CRYPTO_BUF_MASK ((1UL << QUIC_CRYPTO_BUF_SHIFT) - 1)
|
||||
/* The maximum allowed size of CRYPTO data buffer provided by the TLS stack. */
|
||||
#define QUIC_CRYPTO_BUF_SZ (1UL << QUIC_CRYPTO_BUF_SHIFT) /* 1 KB */
|
||||
|
||||
/* The maximum number of bytes of CRYPTO data in flight during handshakes. */
|
||||
#define QUIC_CRYPTO_IN_FLIGHT_MAX 4096
|
||||
|
||||
/*
|
||||
* CRYPTO buffer struct.
|
||||
* Such buffers are used to send CRYPTO data.
|
||||
*/
|
||||
struct quic_crypto_buf {
|
||||
unsigned char data[QUIC_CRYPTO_BUF_SZ];
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
/* QUIC buffer structure used to build outgoing packets. */
|
||||
struct q_buf {
|
||||
/* Points to the data in this buffer. */
|
||||
unsigned char *area;
|
||||
/* Points to the current position to write into this buffer. */
|
||||
unsigned char *pos;
|
||||
/* Point to the end of this buffer past one. */
|
||||
const unsigned char *end;
|
||||
/* The number of data bytes in this buffer. */
|
||||
size_t data;
|
||||
/* The list of packets attached to this buffer which have not been already sent. */
|
||||
struct list pkts;
|
||||
};
|
||||
|
||||
struct quic_enc_level {
|
||||
enum ssl_encryption_level_t level;
|
||||
struct quic_tls_ctx tls_ctx;
|
||||
struct {
|
||||
/* The packets received by the listener I/O handler
|
||||
with header protection removed. */
|
||||
struct eb_root pkts;
|
||||
/* Liste of QUIC packets with protected header. */
|
||||
struct list pqpkts;
|
||||
/* Crypto frames */
|
||||
struct {
|
||||
uint64_t offset;
|
||||
struct eb_root frms; /* XXX TO CHECK XXX */
|
||||
} crypto;
|
||||
} rx;
|
||||
struct {
|
||||
struct {
|
||||
struct quic_crypto_buf **bufs;
|
||||
/* The number of element in use in the previous array. */
|
||||
size_t nb_buf;
|
||||
/* The total size of the CRYPTO data stored in the CRYPTO buffers. */
|
||||
size_t sz;
|
||||
/* The offset of the CRYPT0 data stream. */
|
||||
uint64_t offset;
|
||||
} crypto;
|
||||
} tx;
|
||||
struct quic_pktns *pktns;
|
||||
};
|
||||
|
||||
struct quic_path {
|
||||
/* Control congestion. */
|
||||
struct quic_cc cc;
|
||||
/* Packet loss detection information. */
|
||||
struct quic_loss loss;
|
||||
|
||||
/* MTU. */
|
||||
size_t mtu;
|
||||
/* Congestion window. */
|
||||
uint64_t cwnd;
|
||||
/* Minimum congestion window. */
|
||||
uint64_t min_cwnd;
|
||||
/* Prepared data to be sent (in bytes). */
|
||||
uint64_t prep_in_flight;
|
||||
/* Outstanding data (in bytes). */
|
||||
uint64_t in_flight;
|
||||
/* Number of in flight ack-eliciting packets. */
|
||||
uint64_t in_flight_ae_pkts;
|
||||
};
|
||||
|
||||
/* The number of buffers for outgoing packets (must be a power of two). */
|
||||
#define QUIC_CONN_TX_BUFS_NB 8
|
||||
#define QUIC_CONN_TX_BUF_SZ QUIC_PACKET_MAXLEN
|
||||
|
||||
struct quic_conn {
|
||||
uint32_t version;
|
||||
|
||||
/* Transport parameters. */
|
||||
struct quic_transport_params params;
|
||||
unsigned char enc_params[QUIC_TP_MAX_ENCLEN]; /* encoded QUIC transport parameters */
|
||||
size_t enc_params_len;
|
||||
|
||||
/*
|
||||
* Original Destination Connection ID (comming with first client Initial packets).
|
||||
* Used only by servers.
|
||||
*/
|
||||
struct ebmb_node odcid_node;
|
||||
struct quic_cid odcid;
|
||||
|
||||
struct quic_cid dcid;
|
||||
struct ebmb_node scid_node;
|
||||
struct quic_cid scid;
|
||||
struct eb_root cids;
|
||||
|
||||
struct quic_enc_level els[QUIC_TLS_ENC_LEVEL_MAX];
|
||||
|
||||
struct quic_transport_params rx_tps;
|
||||
|
||||
struct quic_pktns pktns[QUIC_TLS_PKTNS_MAX];
|
||||
|
||||
/* Used only to reach the tasklet for the I/O handler from this quic_conn object. */
|
||||
struct connection *conn;
|
||||
/* Output buffer used during the handshakes. */
|
||||
struct {
|
||||
unsigned char data[QUIC_PACKET_MAXLEN];
|
||||
unsigned char *pos;
|
||||
} obuf;
|
||||
|
||||
struct {
|
||||
/* The remaining frames to send. */
|
||||
struct list frms_to_send;
|
||||
|
||||
/* Array of buffers. */
|
||||
struct q_buf **bufs;
|
||||
/* The size of the previous array. */
|
||||
size_t nb_buf;
|
||||
/* Writer index. */
|
||||
int wbuf;
|
||||
/* Reader index. */
|
||||
int rbuf;
|
||||
/* Number of sent bytes. */
|
||||
uint64_t bytes;
|
||||
/* The number of datagrams which may be sent
|
||||
* when sending probe packets.
|
||||
*/
|
||||
int nb_pto_dgrams;
|
||||
} tx;
|
||||
struct {
|
||||
/* Number of received bytes. */
|
||||
uint64_t bytes;
|
||||
} rx;
|
||||
/* In flight CRYPTO data counter. */
|
||||
size_t ifcdata;
|
||||
unsigned int max_ack_delay;
|
||||
struct quic_path paths[1];
|
||||
struct quic_path *path;
|
||||
|
||||
struct task *timer_task;
|
||||
unsigned int timer;
|
||||
};
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
#endif /* _HAPROXY_XPRT_QUIC_T_H */
|
1209
include/haproxy/xprt_quic.h
Normal file
1209
include/haproxy/xprt_quic.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user