mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.23.0
- [FEATURE] IETF Client 0-RTT support. - [BUGFIX] Do not schedule MTU probe on first tick. - [BUGFIX] Parsing DATAGRAM frame. - [BUGFIX] If push promise fails, do not invoke hset destructor. - [BUGFIX] Client: When connections are IDed by port number, check DCID. Fixes issue #176. - Revert the 2.22.1 lsquic_is_valid_hs_packet change. All that was necessary is a change to the way we call it in lsquic_engine. No change to the function itself is required.
This commit is contained in:
parent
f3d781aa59
commit
04f8f447b2
24 changed files with 808 additions and 309 deletions
12
CHANGELOG
12
CHANGELOG
|
@ -1,3 +1,15 @@
|
||||||
|
2020-10-13
|
||||||
|
- 2.23.0
|
||||||
|
- [FEATURE] IETF Client 0-RTT support.
|
||||||
|
- [BUGFIX] Do not schedule MTU probe on first tick.
|
||||||
|
- [BUGFIX] Parsing DATAGRAM frame.
|
||||||
|
- [BUGFIX] If push promise fails, do not invoke hset destructor.
|
||||||
|
- [BUGFIX] Client: When connections are IDed by port number, check DCID.
|
||||||
|
Fixes issue #176.
|
||||||
|
- Revert the 2.22.1 lsquic_is_valid_hs_packet change. All that was
|
||||||
|
necessary is a change to the way we call it in lsquic_engine. No
|
||||||
|
change to the function itself is required.
|
||||||
|
|
||||||
2020-10-08
|
2020-10-08
|
||||||
- 2.22.1
|
- 2.22.1
|
||||||
- [BUGFIX] Function that checks validity of handshake packets.
|
- [BUGFIX] Function that checks validity of handshake packets.
|
||||||
|
|
|
@ -1506,8 +1506,14 @@ idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
headers.count = sizeof(header_arr) / sizeof(header_arr[0]);
|
headers.count = sizeof(header_arr) / sizeof(header_arr[0]);
|
||||||
req = new_req(GET, push_path->path, st_h->req->authority_str);
|
req = new_req(GET, push_path->path, st_h->req->authority_str);
|
||||||
if (req)
|
if (req)
|
||||||
(void) lsquic_conn_push_stream(lsquic_stream_conn(stream),
|
{
|
||||||
req, stream, &headers);
|
if (0 != lsquic_conn_push_stream(lsquic_stream_conn(stream),
|
||||||
|
req, stream, &headers))
|
||||||
|
{
|
||||||
|
LSQ_WARN("stream push failed");
|
||||||
|
interop_server_hset_destroy(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LSQ_WARN("cannot allocate req for push");
|
LSQ_WARN("cannot allocate req for push");
|
||||||
free(push_path);
|
free(push_path);
|
||||||
|
|
|
@ -93,7 +93,11 @@ load_cert (struct lsquic_hash *certs, const char *optarg)
|
||||||
SSL_CTX_set_max_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION);
|
SSL_CTX_set_max_proto_version(cert->ce_ssl_ctx, TLS1_3_VERSION);
|
||||||
SSL_CTX_set_default_verify_paths(cert->ce_ssl_ctx);
|
SSL_CTX_set_default_verify_paths(cert->ce_ssl_ctx);
|
||||||
SSL_CTX_set_alpn_select_cb(cert->ce_ssl_ctx, select_alpn, NULL);
|
SSL_CTX_set_alpn_select_cb(cert->ce_ssl_ctx, select_alpn, NULL);
|
||||||
SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1); /* XXX */
|
{
|
||||||
|
const char *const s = getenv("LSQUIC_ENABLE_EARLY_DATA");
|
||||||
|
if (!s || atoi(s))
|
||||||
|
SSL_CTX_set_early_data_enabled(cert->ce_ssl_ctx, 1); /* XXX */
|
||||||
|
}
|
||||||
if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file))
|
if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file))
|
||||||
{
|
{
|
||||||
LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file);
|
LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file);
|
||||||
|
|
|
@ -1993,6 +1993,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
|
||||||
settings->es_qpack_dec_max_blocked = atoi(val);
|
settings->es_qpack_dec_max_blocked = atoi(val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (0 == strncmp(name, "init_max_streams_bidi", 21))
|
||||||
|
{
|
||||||
|
settings->es_init_max_streams_bidi = atoi(val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 23:
|
case 23:
|
||||||
if (0 == strncmp(name, "max_udp_payload_size_rx", 23))
|
if (0 == strncmp(name, "max_udp_payload_size_rx", 23))
|
||||||
|
|
|
@ -58,9 +58,9 @@ developed by the IETF. Both types are included in a single enum:
|
||||||
|
|
||||||
IETF QUIC version ID 29
|
IETF QUIC version ID 29
|
||||||
|
|
||||||
.. member:: LSQVER_ID30; this version is deprecated.
|
.. member:: LSQVER_ID30
|
||||||
|
|
||||||
IETF QUIC version ID 30
|
IETF QUIC version ID 30; this version is deprecated.
|
||||||
|
|
||||||
.. member:: LSQVER_ID31
|
.. member:: LSQVER_ID31
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
|
||||||
author = u'LiteSpeed Technologies'
|
author = u'LiteSpeed Technologies'
|
||||||
|
|
||||||
# The short X.Y version
|
# The short X.Y version
|
||||||
version = u'2.22'
|
version = u'2.23'
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = u'2.22.1'
|
release = u'2.23.0'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
|
@ -18,7 +18,7 @@ connections.
|
||||||
|
|
||||||
To aid development, there is a :macro:`LSQUIC_FORCED_TCID0_VERSIONS` that
|
To aid development, there is a :macro:`LSQUIC_FORCED_TCID0_VERSIONS` that
|
||||||
specifies the list of versions with 0-sized connections. (If you, for
|
specifies the list of versions with 0-sized connections. (If you, for
|
||||||
example, want to turn them.)
|
example, want to turn them off.)
|
||||||
|
|
||||||
Once gQUIC becomes deprecated in the future, there will remain no technical
|
Once gQUIC becomes deprecated in the future, there will remain no technical
|
||||||
reason why a single engine instance could not be used both for client and
|
reason why a single engine instance could not be used both for client and
|
||||||
|
|
|
@ -24,8 +24,8 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LSQUIC_MAJOR_VERSION 2
|
#define LSQUIC_MAJOR_VERSION 2
|
||||||
#define LSQUIC_MINOR_VERSION 22
|
#define LSQUIC_MINOR_VERSION 23
|
||||||
#define LSQUIC_PATCH_VERSION 1
|
#define LSQUIC_PATCH_VERSION 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engine flags:
|
* Engine flags:
|
||||||
|
@ -1923,8 +1923,7 @@ lsquic_get_h3_alpns (unsigned versions);
|
||||||
* been established: it will return incorrect result.
|
* been established: it will return incorrect result.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
lsquic_is_valid_hs_packet (lsquic_engine_t *, const unsigned char *,
|
lsquic_is_valid_hs_packet (lsquic_engine_t *, const unsigned char *, size_t);
|
||||||
size_t bufsz, size_t packet_in_sz);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse cid from packet stored in `buf' and store it to `cid'. Returns 0
|
* Parse cid from packet stored in `buf' and store it to `cid'. Returns 0
|
||||||
|
|
|
@ -282,6 +282,10 @@ struct conn_iface
|
||||||
/* Optional method */
|
/* Optional method */
|
||||||
size_t
|
size_t
|
||||||
(*ci_get_min_datagram_size) (struct lsquic_conn *);
|
(*ci_get_min_datagram_size) (struct lsquic_conn *);
|
||||||
|
|
||||||
|
/* Optional method */
|
||||||
|
void
|
||||||
|
(*ci_early_data_failed) (struct lsquic_conn *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LSCONN_CCE_BITS 3
|
#define LSCONN_CCE_BITS 3
|
||||||
|
|
|
@ -15,6 +15,8 @@ struct ssl_stream_method_st;
|
||||||
struct ssl_st;
|
struct ssl_st;
|
||||||
struct sockaddr;
|
struct sockaddr;
|
||||||
struct conn_cid_elem;
|
struct conn_cid_elem;
|
||||||
|
struct lsquic_engine_settings;
|
||||||
|
enum lsquic_version;
|
||||||
|
|
||||||
#define DNONC_LENGTH 32
|
#define DNONC_LENGTH 32
|
||||||
#define SRST_LENGTH 16
|
#define SRST_LENGTH 16
|
||||||
|
@ -242,12 +244,6 @@ struct enc_session_funcs_gquic
|
||||||
void (*esf_reset_cid) (enc_session_t *, const lsquic_cid_t *);
|
void (*esf_reset_cid) (enc_session_t *, const lsquic_cid_t *);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum iquic_handshake_status {
|
|
||||||
IHS_WANT_READ,
|
|
||||||
IHS_WANT_WRITE,
|
|
||||||
IHS_STOP,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct crypto_stream_if
|
struct crypto_stream_if
|
||||||
{
|
{
|
||||||
ssize_t (*csi_write) (void *stream, const void *buf, size_t len);
|
ssize_t (*csi_write) (void *stream, const void *buf, size_t len);
|
||||||
|
@ -371,4 +367,10 @@ lsquic_sess_resume_version (const unsigned char *, size_t);
|
||||||
*/
|
*/
|
||||||
#define IQUIC_TAG_LEN 16
|
#define IQUIC_TAG_LEN 16
|
||||||
|
|
||||||
|
/* Return number of bytes written to `buf' or -1 on error */
|
||||||
|
int
|
||||||
|
lsquic_enc_sess_ietf_gen_quic_ctx (
|
||||||
|
const struct lsquic_engine_settings *settings,
|
||||||
|
enum lsquic_version version, unsigned char *buf, size_t bufsz);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -107,6 +107,20 @@ static void
|
||||||
no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
||||||
lsquic_time_t expiry, lsquic_time_t now);
|
lsquic_time_t expiry, lsquic_time_t now);
|
||||||
|
|
||||||
|
static int
|
||||||
|
iquic_new_session_cb (SSL *, SSL_SESSION *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
keylog_callback (const SSL *, const char *);
|
||||||
|
|
||||||
|
static enum ssl_verify_result_t
|
||||||
|
verify_server_cert_callback (SSL *, uint8_t *out_alert);
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_setup_key_logging (struct enc_sess_iquic *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
iquic_esfi_destroy (enc_session_t *);
|
||||||
|
|
||||||
#define SAMPLE_SZ 16
|
#define SAMPLE_SZ 16
|
||||||
|
|
||||||
|
@ -223,7 +237,7 @@ struct enc_sess_iquic
|
||||||
lsquic_cid_t esi_iscid; /* Initial SCID */
|
lsquic_cid_t esi_iscid; /* Initial SCID */
|
||||||
unsigned esi_key_phase;
|
unsigned esi_key_phase;
|
||||||
enum {
|
enum {
|
||||||
ESI_INITIALIZED = 1 << 0,
|
ESI_UNUSED0 = 1 << 0,
|
||||||
ESI_LOG_SECRETS = 1 << 1,
|
ESI_LOG_SECRETS = 1 << 1,
|
||||||
ESI_HANDSHAKE_OK = 1 << 2,
|
ESI_HANDSHAKE_OK = 1 << 2,
|
||||||
ESI_ODCID = 1 << 3,
|
ESI_ODCID = 1 << 3,
|
||||||
|
@ -243,17 +257,15 @@ struct enc_sess_iquic
|
||||||
ESI_MAX_PACKNO_INIT = 1 << 17,
|
ESI_MAX_PACKNO_INIT = 1 << 17,
|
||||||
ESI_MAX_PACKNO_HSK = ESI_MAX_PACKNO_INIT << PNS_HSK,
|
ESI_MAX_PACKNO_HSK = ESI_MAX_PACKNO_INIT << PNS_HSK,
|
||||||
ESI_MAX_PACKNO_APP = ESI_MAX_PACKNO_INIT << PNS_APP,
|
ESI_MAX_PACKNO_APP = ESI_MAX_PACKNO_INIT << PNS_APP,
|
||||||
|
ESI_HAVE_0RTT_TP = 1 << 20,
|
||||||
} esi_flags;
|
} esi_flags;
|
||||||
enum enc_level esi_last_w;
|
enum enc_level esi_last_w;
|
||||||
unsigned esi_trasec_sz;
|
unsigned esi_trasec_sz;
|
||||||
char *esi_hostname;
|
|
||||||
void *esi_keylog_handle;
|
void *esi_keylog_handle;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
char *esi_sni_bypass;
|
char *esi_sni_bypass;
|
||||||
#endif
|
#endif
|
||||||
const unsigned char *esi_alpn;
|
const unsigned char *esi_alpn;
|
||||||
unsigned char *esi_sess_resume_buf;
|
|
||||||
size_t esi_sess_resume_sz;
|
|
||||||
/* Need MD and AEAD for key rotation */
|
/* Need MD and AEAD for key rotation */
|
||||||
const EVP_MD *esi_md;
|
const EVP_MD *esi_md;
|
||||||
const EVP_AEAD *esi_aead;
|
const EVP_AEAD *esi_aead;
|
||||||
|
@ -279,6 +291,7 @@ struct enc_sess_iquic
|
||||||
esi_hp_batch_packets[HP_BATCH_SIZE];
|
esi_hp_batch_packets[HP_BATCH_SIZE];
|
||||||
unsigned char esi_hp_batch_samples[HP_BATCH_SIZE][SAMPLE_SZ];
|
unsigned char esi_hp_batch_samples[HP_BATCH_SIZE][SAMPLE_SZ];
|
||||||
unsigned char esi_grease;
|
unsigned char esi_grease;
|
||||||
|
signed char esi_have_forw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -696,24 +709,23 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
||||||
|
|
||||||
static SSL_SESSION *
|
static SSL_SESSION *
|
||||||
maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
|
maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
|
||||||
const SSL_CTX *ssl_ctx)
|
const SSL_CTX *ssl_ctx, const unsigned char *sess_resume,
|
||||||
|
size_t sess_resume_sz)
|
||||||
{
|
{
|
||||||
SSL_SESSION *ssl_session;
|
SSL_SESSION *ssl_session;
|
||||||
lsquic_ver_tag_t ver_tag;
|
lsquic_ver_tag_t ver_tag;
|
||||||
enum lsquic_version quic_ver;
|
enum lsquic_version quic_ver;
|
||||||
uint32_t rtt_ver, ticket_sz, trapa_sz;
|
uint32_t rtt_ver, ticket_sz, trapa_sz;
|
||||||
const unsigned char *ticket_buf, *trapa_buf, *p;
|
const unsigned char *ticket_buf, *trapa_buf, *p;
|
||||||
const unsigned char *const end
|
const unsigned char *const end = sess_resume + sess_resume_sz;
|
||||||
= enc_sess->esi_sess_resume_buf + enc_sess->esi_sess_resume_sz;
|
|
||||||
|
|
||||||
if (enc_sess->esi_sess_resume_sz
|
if (sess_resume_sz < sizeof(ver_tag) + sizeof(rtt_ver) + sizeof(ticket_sz))
|
||||||
< sizeof(ver_tag) + sizeof(rtt_ver) + sizeof(ticket_sz))
|
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("rtt buf too short");
|
LSQ_DEBUG("rtt buf too short");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = enc_sess->esi_sess_resume_buf;
|
p = sess_resume;
|
||||||
memcpy(&ver_tag, p, sizeof(ver_tag));
|
memcpy(&ver_tag, p, sizeof(ver_tag));
|
||||||
p += sizeof(ver_tag);
|
p += sizeof(ver_tag);
|
||||||
quic_ver = lsquic_tag2ver(ver_tag);
|
quic_ver = lsquic_tag2ver(ver_tag);
|
||||||
|
@ -760,8 +772,6 @@ maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
|
||||||
p += trapa_sz;
|
p += trapa_sz;
|
||||||
assert(p == end);
|
assert(p == end);
|
||||||
|
|
||||||
(void) /* TODO */ trapa_buf;
|
|
||||||
|
|
||||||
ssl_session = SSL_SESSION_from_bytes(ticket_buf, ticket_sz, ssl_ctx);
|
ssl_session = SSL_SESSION_from_bytes(ticket_buf, ticket_sz, ssl_ctx);
|
||||||
if (!ssl_session)
|
if (!ssl_session)
|
||||||
{
|
{
|
||||||
|
@ -769,6 +779,22 @@ maybe_create_SSL_SESSION (struct enc_sess_iquic *enc_sess,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SSL_SESSION_early_data_capable(ssl_session))
|
||||||
|
{
|
||||||
|
if (0 > (quic_ver == LSQVER_ID27 ? lsquic_tp_decode_27
|
||||||
|
: lsquic_tp_decode)(trapa_buf, trapa_sz, 1,
|
||||||
|
&enc_sess->esi_peer_tp))
|
||||||
|
{
|
||||||
|
SSL_SESSION_free(ssl_session);
|
||||||
|
LSQ_WARN("cannot parse stored transport parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
LSQ_DEBUG("early data capable, will try 0-RTT");
|
||||||
|
enc_sess->esi_flags |= ESI_HAVE_0RTT_TP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LSQ_DEBUG("early data not capable -- not trying 0-RTT");
|
||||||
|
|
||||||
LSQ_INFO("instantiated SSL_SESSION from serialized buffer");
|
LSQ_INFO("instantiated SSL_SESSION from serialized buffer");
|
||||||
return ssl_session;
|
return ssl_session;
|
||||||
}
|
}
|
||||||
|
@ -795,6 +821,16 @@ iquic_esfi_create_client (const char *hostname,
|
||||||
struct lsquic_alarmset *alset, unsigned max_streams_uni)
|
struct lsquic_alarmset *alset, unsigned max_streams_uni)
|
||||||
{
|
{
|
||||||
struct enc_sess_iquic *enc_sess;
|
struct enc_sess_iquic *enc_sess;
|
||||||
|
SSL_CTX *ssl_ctx;
|
||||||
|
SSL_SESSION *ssl_session;
|
||||||
|
const struct alpn_map *am;
|
||||||
|
int transpa_len;
|
||||||
|
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||||
|
unsigned char trans_params[0x80
|
||||||
|
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||||
|
+ 4 + lsquic_tp_get_quantum_sz()
|
||||||
|
#endif
|
||||||
|
];
|
||||||
|
|
||||||
fiu_return_on("enc_sess_ietf/create_client", NULL);
|
fiu_return_on("enc_sess_ietf/create_client", NULL);
|
||||||
|
|
||||||
|
@ -802,18 +838,6 @@ iquic_esfi_create_client (const char *hostname,
|
||||||
if (!enc_sess)
|
if (!enc_sess)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (hostname)
|
|
||||||
{
|
|
||||||
enc_sess->esi_hostname = strdup(hostname);
|
|
||||||
if (!enc_sess->esi_hostname)
|
|
||||||
{
|
|
||||||
free(enc_sess);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
enc_sess->esi_hostname = NULL;
|
|
||||||
|
|
||||||
enc_sess->esi_enpub = enpub;
|
enc_sess->esi_enpub = enpub;
|
||||||
enc_sess->esi_streams = crypto_streams;
|
enc_sess->esi_streams = crypto_streams;
|
||||||
enc_sess->esi_cryst_if = cryst_if;
|
enc_sess->esi_cryst_if = cryst_if;
|
||||||
|
@ -844,35 +868,123 @@ iquic_esfi_create_client (const char *hostname,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Have to wait until the call to init_client() -- this is when the
|
enc_sess->esi_max_streams_uni = max_streams_uni;
|
||||||
* result of version negotiation is known.
|
|
||||||
*/
|
if (enc_sess->esi_enpub->enp_alpn)
|
||||||
|
enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
|
||||||
|
else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
|
||||||
|
{
|
||||||
|
for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
|
||||||
|
/ sizeof(s_h3_alpns[0]); ++am)
|
||||||
|
if (am->version == enc_sess->esi_ver_neg->vn_ver)
|
||||||
|
goto alpn_selected;
|
||||||
|
LSQ_ERROR("version %s has no matching ALPN",
|
||||||
|
lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
|
||||||
|
goto err;
|
||||||
|
alpn_selected:
|
||||||
|
enc_sess->esi_alpn = am->alpn;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSQ_DEBUG("Create new SSL_CTX");
|
||||||
|
ssl_ctx = SSL_CTX_new(TLS_method());
|
||||||
|
if (!ssl_ctx)
|
||||||
|
{
|
||||||
|
LSQ_ERROR("cannot create SSL context: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), errbuf));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
|
||||||
|
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
|
||||||
|
SSL_CTX_set_default_verify_paths(ssl_ctx);
|
||||||
|
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
|
||||||
|
if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
|
||||||
|
SSL_CTX_sess_set_new_cb(ssl_ctx, iquic_new_session_cb);
|
||||||
|
if (enc_sess->esi_enpub->enp_kli)
|
||||||
|
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
|
||||||
|
if (enc_sess->esi_enpub->enp_verify_cert
|
||||||
|
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)
|
||||||
|
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG))
|
||||||
|
SSL_CTX_set_custom_verify(ssl_ctx, SSL_VERIFY_PEER,
|
||||||
|
verify_server_cert_callback);
|
||||||
|
SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
|
||||||
|
|
||||||
|
enc_sess->esi_ssl = SSL_new(ssl_ctx);
|
||||||
|
if (!enc_sess->esi_ssl)
|
||||||
|
{
|
||||||
|
LSQ_ERROR("cannot create SSL object: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), errbuf));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
transpa_len = gen_trans_params(enc_sess, trans_params,
|
||||||
|
sizeof(trans_params));
|
||||||
|
if (transpa_len < 0)
|
||||||
|
{
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, trans_params,
|
||||||
|
transpa_len))
|
||||||
|
{
|
||||||
|
LSQ_ERROR("cannot set QUIC transport params: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), errbuf));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(SSL_set_quic_method(enc_sess->esi_ssl, &cry_quic_method)))
|
||||||
|
{
|
||||||
|
LSQ_INFO("could not set stream method");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_setup_key_logging(enc_sess);
|
||||||
|
|
||||||
|
if (enc_sess->esi_alpn &&
|
||||||
|
0 != SSL_set_alpn_protos(enc_sess->esi_ssl, enc_sess->esi_alpn,
|
||||||
|
enc_sess->esi_alpn[0] + 1))
|
||||||
|
{
|
||||||
|
LSQ_ERROR("cannot set ALPN: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), errbuf));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (1 != SSL_set_tlsext_host_name(enc_sess->esi_ssl, hostname))
|
||||||
|
{
|
||||||
|
LSQ_ERROR("cannot set hostname: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), errbuf));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
if (sess_resume && sess_resume_sz)
|
if (sess_resume && sess_resume_sz)
|
||||||
{
|
{
|
||||||
enc_sess->esi_sess_resume_buf = malloc(sess_resume_sz);
|
ssl_session = maybe_create_SSL_SESSION(enc_sess, ssl_ctx,
|
||||||
if (enc_sess->esi_sess_resume_buf)
|
sess_resume, sess_resume_sz);
|
||||||
|
if (ssl_session)
|
||||||
{
|
{
|
||||||
memcpy(enc_sess->esi_sess_resume_buf, sess_resume, sess_resume_sz);
|
(void) /* This only ever returns 1: */
|
||||||
enc_sess->esi_sess_resume_sz = sess_resume_sz;
|
SSL_set_session(enc_sess->esi_ssl, ssl_session);
|
||||||
|
SSL_SESSION_free(ssl_session);
|
||||||
|
ssl_session = NULL;
|
||||||
|
enc_sess->esi_flags |= ESI_USE_SSL_TICKET;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
enc_sess->esi_sess_resume_sz = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enc_sess->esi_sess_resume_buf = NULL;
|
|
||||||
enc_sess->esi_sess_resume_sz = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
|
||||||
|
SSL_set_connect_state(enc_sess->esi_ssl);
|
||||||
|
|
||||||
if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
|
if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
|
||||||
enc_sess->esi_flags |= ESI_WANT_TICKET;
|
enc_sess->esi_flags |= ESI_WANT_TICKET;
|
||||||
enc_sess->esi_alset = alset;
|
enc_sess->esi_alset = alset;
|
||||||
lsquic_alarmset_init_alarm(enc_sess->esi_alset, AL_SESS_TICKET,
|
lsquic_alarmset_init_alarm(enc_sess->esi_alset, AL_SESS_TICKET,
|
||||||
no_sess_ticket, enc_sess);
|
no_sess_ticket, enc_sess);
|
||||||
|
|
||||||
enc_sess->esi_max_streams_uni = max_streams_uni;
|
SSL_CTX_free(ssl_ctx);
|
||||||
|
|
||||||
return enc_sess;
|
return enc_sess;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (enc_sess)
|
||||||
|
iquic_esfi_destroy(enc_sess);
|
||||||
|
if (ssl_ctx)
|
||||||
|
SSL_CTX_free(ssl_ctx);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1242,6 +1354,7 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
||||||
{
|
{
|
||||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||||
const struct alpn_map *am;
|
const struct alpn_map *am;
|
||||||
|
unsigned quic_ctx_idx;
|
||||||
int transpa_len;
|
int transpa_len;
|
||||||
SSL_CTX *ssl_ctx = NULL;
|
SSL_CTX *ssl_ctx = NULL;
|
||||||
union {
|
union {
|
||||||
|
@ -1287,9 +1400,10 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
||||||
LSQ_INFO("could not set stream method");
|
LSQ_INFO("could not set stream method");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* TODO: set to transport parameter string instead of the constant string */
|
quic_ctx_idx = enc_sess->esi_conn->cn_version == LSQVER_ID27 ? 0 : 1;
|
||||||
if (!SSL_set_quic_early_data_context(enc_sess->esi_ssl,
|
if (!SSL_set_quic_early_data_context(enc_sess->esi_ssl,
|
||||||
(unsigned char *) "lsquic", 6))
|
enc_sess->esi_enpub->enp_quic_ctx_buf[quic_ctx_idx],
|
||||||
|
enc_sess->esi_enpub->enp_quic_ctx_sz[quic_ctx_idx]))
|
||||||
{
|
{
|
||||||
LSQ_INFO("could not set early data context");
|
LSQ_INFO("could not set early data context");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1317,7 +1431,6 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
||||||
SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
|
SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
|
||||||
SSL_set_accept_state(enc_sess->esi_ssl);
|
SSL_set_accept_state(enc_sess->esi_ssl);
|
||||||
LSQ_DEBUG("initialized server enc session");
|
LSQ_DEBUG("initialized server enc session");
|
||||||
enc_sess->esi_flags |= ESI_INITIALIZED;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,129 +1528,6 @@ iquic_new_session_cb (SSL *ssl, SSL_SESSION *session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
init_client (struct enc_sess_iquic *const enc_sess)
|
|
||||||
{
|
|
||||||
SSL_CTX *ssl_ctx;
|
|
||||||
SSL_SESSION *ssl_session;
|
|
||||||
const struct alpn_map *am;
|
|
||||||
int transpa_len;
|
|
||||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
|
||||||
#define hexbuf errbuf /* This is a dual-purpose buffer */
|
|
||||||
unsigned char trans_params[0x80
|
|
||||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
|
||||||
+ 4 + lsquic_tp_get_quantum_sz()
|
|
||||||
#endif
|
|
||||||
];
|
|
||||||
|
|
||||||
if (enc_sess->esi_enpub->enp_alpn)
|
|
||||||
enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
|
|
||||||
else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
|
|
||||||
{
|
|
||||||
for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
|
|
||||||
/ sizeof(s_h3_alpns[0]); ++am)
|
|
||||||
if (am->version == enc_sess->esi_ver_neg->vn_ver)
|
|
||||||
goto ok;
|
|
||||||
LSQ_ERROR("version %s has no matching ALPN",
|
|
||||||
lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
|
|
||||||
return -1;
|
|
||||||
ok: enc_sess->esi_alpn = am->alpn;
|
|
||||||
}
|
|
||||||
|
|
||||||
LSQ_DEBUG("Create new SSL_CTX");
|
|
||||||
ssl_ctx = SSL_CTX_new(TLS_method());
|
|
||||||
if (!ssl_ctx)
|
|
||||||
{
|
|
||||||
LSQ_ERROR("cannot create SSL context: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), errbuf));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
|
|
||||||
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
|
|
||||||
SSL_CTX_set_default_verify_paths(ssl_ctx);
|
|
||||||
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
|
|
||||||
if (enc_sess->esi_enpub->enp_stream_if->on_sess_resume_info)
|
|
||||||
SSL_CTX_sess_set_new_cb(ssl_ctx, iquic_new_session_cb);
|
|
||||||
if (enc_sess->esi_enpub->enp_kli)
|
|
||||||
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
|
|
||||||
if (enc_sess->esi_enpub->enp_verify_cert
|
|
||||||
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)
|
|
||||||
|| LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_QLOG))
|
|
||||||
SSL_CTX_set_custom_verify(ssl_ctx, SSL_VERIFY_PEER,
|
|
||||||
verify_server_cert_callback);
|
|
||||||
SSL_CTX_set_early_data_enabled(ssl_ctx, 1);
|
|
||||||
|
|
||||||
transpa_len = gen_trans_params(enc_sess, trans_params,
|
|
||||||
sizeof(trans_params));
|
|
||||||
if (transpa_len < 0)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
enc_sess->esi_ssl = SSL_new(ssl_ctx);
|
|
||||||
if (!enc_sess->esi_ssl)
|
|
||||||
{
|
|
||||||
LSQ_ERROR("cannot create SSL object: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), errbuf));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (!(SSL_set_quic_method(enc_sess->esi_ssl, &cry_quic_method)))
|
|
||||||
{
|
|
||||||
LSQ_INFO("could not set stream method");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
maybe_setup_key_logging(enc_sess);
|
|
||||||
if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, trans_params,
|
|
||||||
transpa_len))
|
|
||||||
{
|
|
||||||
LSQ_ERROR("cannot set QUIC transport params: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), errbuf));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (enc_sess->esi_alpn &&
|
|
||||||
0 != SSL_set_alpn_protos(enc_sess->esi_ssl, enc_sess->esi_alpn,
|
|
||||||
enc_sess->esi_alpn[0] + 1))
|
|
||||||
{
|
|
||||||
LSQ_ERROR("cannot set ALPN: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), errbuf));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (1 != SSL_set_tlsext_host_name(enc_sess->esi_ssl,
|
|
||||||
enc_sess->esi_hostname))
|
|
||||||
{
|
|
||||||
LSQ_ERROR("cannot set hostname: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), errbuf));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
free(enc_sess->esi_hostname);
|
|
||||||
enc_sess->esi_hostname = NULL;
|
|
||||||
if (enc_sess->esi_sess_resume_buf)
|
|
||||||
{
|
|
||||||
ssl_session = maybe_create_SSL_SESSION(enc_sess, ssl_ctx);
|
|
||||||
if (ssl_session)
|
|
||||||
{
|
|
||||||
if (SSL_set_session(enc_sess->esi_ssl, ssl_session))
|
|
||||||
enc_sess->esi_flags |= ESI_USE_SSL_TICKET;
|
|
||||||
else
|
|
||||||
LSQ_WARN("cannot set session");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SSL_set_ex_data(enc_sess->esi_ssl, s_idx, enc_sess);
|
|
||||||
SSL_set_connect_state(enc_sess->esi_ssl);
|
|
||||||
SSL_CTX_free(ssl_ctx);
|
|
||||||
LSQ_DEBUG("initialized client enc session");
|
|
||||||
enc_sess->esi_flags |= ESI_INITIALIZED;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (ssl_ctx)
|
|
||||||
SSL_CTX_free(ssl_ctx);
|
|
||||||
return -1;
|
|
||||||
#undef hexbuf
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct crypto_params
|
struct crypto_params
|
||||||
{
|
{
|
||||||
const EVP_AEAD *aead;
|
const EVP_AEAD *aead;
|
||||||
|
@ -1607,14 +1597,72 @@ get_crypto_params (const struct enc_sess_iquic *enc_sess,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* [draft-ietf-quic-transport-31] Section 7.4.1:
|
||||||
|
" If 0-RTT data is accepted by the server, the server MUST NOT reduce
|
||||||
|
" any limits or alter any values that might be violated by the client
|
||||||
|
" with its 0-RTT data. In particular, a server that accepts 0-RTT data
|
||||||
|
" MUST NOT set values for the following parameters (Section 18.2) that
|
||||||
|
" are smaller than the remembered value of the parameters.
|
||||||
|
"
|
||||||
|
" * active_connection_id_limit
|
||||||
|
"
|
||||||
|
" * initial_max_data
|
||||||
|
"
|
||||||
|
" * initial_max_stream_data_bidi_local
|
||||||
|
"
|
||||||
|
" * initial_max_stream_data_bidi_remote
|
||||||
|
"
|
||||||
|
" * initial_max_stream_data_uni
|
||||||
|
"
|
||||||
|
" * initial_max_streams_bidi
|
||||||
|
"
|
||||||
|
" * initial_max_streams_uni
|
||||||
|
*/
|
||||||
|
#define REDUCTION_PROHIBITED_TPS (0 \
|
||||||
|
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT) \
|
||||||
|
| (1 << TPI_INIT_MAX_DATA) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_UNI) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_BIDI) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_UNI) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_server_tps_for_violations (const struct enc_sess_iquic *enc_sess,
|
||||||
|
const struct transport_params *params_0rtt,
|
||||||
|
const struct transport_params *new_params)
|
||||||
|
{
|
||||||
|
enum transport_param_id tpi;
|
||||||
|
|
||||||
|
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
|
||||||
|
if ((1 << tpi) & REDUCTION_PROHIBITED_TPS)
|
||||||
|
if (new_params->tp_numerics[tpi] > params_0rtt->tp_numerics[tpi])
|
||||||
|
{
|
||||||
|
LSQ_INFO("server's new TP %s increased in value from %"PRIu64
|
||||||
|
" to %"PRIu64, lsquic_tpi2str[tpi],
|
||||||
|
params_0rtt->tp_numerics[tpi],
|
||||||
|
new_params->tp_numerics[tpi]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSQ_DEBUG("server's new transport parameters do not violate save 0-RTT "
|
||||||
|
"parameters");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
||||||
{
|
{
|
||||||
struct transport_params *const trans_params = &enc_sess->esi_peer_tp;
|
struct transport_params *const trans_params = &enc_sess->esi_peer_tp;
|
||||||
|
struct transport_params params_0rtt;
|
||||||
const uint8_t *params_buf;
|
const uint8_t *params_buf;
|
||||||
size_t bufsz;
|
size_t bufsz;
|
||||||
char *params_str;
|
char *params_str;
|
||||||
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
|
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
|
||||||
|
int have_0rtt_tp;
|
||||||
|
|
||||||
SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, ¶ms_buf, &bufsz);
|
SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, ¶ms_buf, &bufsz);
|
||||||
if (!params_buf)
|
if (!params_buf)
|
||||||
|
@ -1623,6 +1671,13 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_0rtt_tp = !!(enc_sess->esi_flags & ESI_HAVE_0RTT_TP);
|
||||||
|
if (have_0rtt_tp)
|
||||||
|
{
|
||||||
|
params_0rtt = enc_sess->esi_peer_tp;
|
||||||
|
enc_sess->esi_flags &= ~ESI_HAVE_0RTT_TP;
|
||||||
|
}
|
||||||
|
|
||||||
LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
|
LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
|
||||||
if (0 > (version == LSQVER_ID27 ? lsquic_tp_decode_27
|
if (0 > (version == LSQVER_ID27 ? lsquic_tp_decode_27
|
||||||
: lsquic_tp_decode)(params_buf, bufsz,
|
: lsquic_tp_decode)(params_buf, bufsz,
|
||||||
|
@ -1646,6 +1701,10 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (have_0rtt_tp && 0 != check_server_tps_for_violations(enc_sess,
|
||||||
|
¶ms_0rtt, trans_params))
|
||||||
|
return -1;
|
||||||
|
|
||||||
const lsquic_cid_t *const cids[LAST_TPI + 1] = {
|
const lsquic_cid_t *const cids[LAST_TPI + 1] = {
|
||||||
[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)] = enc_sess->esi_flags & ESI_ODCID ? &enc_sess->esi_odcid : NULL,
|
[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)] = enc_sess->esi_flags & ESI_ODCID ? &enc_sess->esi_odcid : NULL,
|
||||||
[TP_CID_IDX(TPI_RETRY_SOURCE_CID)] = enc_sess->esi_flags & ESI_RSCID ? &enc_sess->esi_rscid : NULL,
|
[TP_CID_IDX(TPI_RETRY_SOURCE_CID)] = enc_sess->esi_flags & ESI_RSCID ? &enc_sess->esi_rscid : NULL,
|
||||||
|
@ -1771,6 +1830,14 @@ maybe_get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum iquic_handshake_status {
|
||||||
|
IHS_WANT_READ,
|
||||||
|
IHS_WANT_WRITE,
|
||||||
|
IHS_WANT_RW,
|
||||||
|
IHS_STOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static enum iquic_handshake_status
|
static enum iquic_handshake_status
|
||||||
iquic_esfi_handshake (struct enc_sess_iquic *enc_sess)
|
iquic_esfi_handshake (struct enc_sess_iquic *enc_sess)
|
||||||
{
|
{
|
||||||
|
@ -1791,9 +1858,12 @@ iquic_esfi_handshake (struct enc_sess_iquic *enc_sess)
|
||||||
LSQ_DEBUG("retry write");
|
LSQ_DEBUG("retry write");
|
||||||
return IHS_WANT_WRITE;
|
return IHS_WANT_WRITE;
|
||||||
case SSL_ERROR_EARLY_DATA_REJECTED:
|
case SSL_ERROR_EARLY_DATA_REJECTED:
|
||||||
LSQ_DEBUG("early data rejected");
|
LSQ_DEBUG("early data rejected: reset");
|
||||||
hsk_status = LSQ_HSK_RESUMED_FAIL;
|
SSL_reset_early_data_reject(enc_sess->esi_ssl);
|
||||||
goto err;
|
if (enc_sess->esi_conn->cn_if->ci_early_data_failed)
|
||||||
|
enc_sess->esi_conn->cn_if->ci_early_data_failed(
|
||||||
|
enc_sess->esi_conn);
|
||||||
|
return IHS_WANT_RW;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
LSQ_DEBUG("handshake: %s", ERR_error_string(err, errbuf));
|
LSQ_DEBUG("handshake: %s", ERR_error_string(err, errbuf));
|
||||||
|
@ -1866,7 +1936,9 @@ iquic_esfi_get_peer_transport_params (enc_session_t *enc_session_p)
|
||||||
{
|
{
|
||||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||||
|
|
||||||
if (0 == maybe_get_peer_transport_params(enc_sess))
|
if (enc_sess->esi_flags & ESI_HAVE_0RTT_TP)
|
||||||
|
return &enc_sess->esi_peer_tp;
|
||||||
|
else if (0 == maybe_get_peer_transport_params(enc_sess))
|
||||||
return &enc_sess->esi_peer_tp;
|
return &enc_sess->esi_peer_tp;
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1892,8 +1964,6 @@ iquic_esfi_destroy (enc_session_t *enc_session_p)
|
||||||
free_handshake_keys(enc_sess);
|
free_handshake_keys(enc_sess);
|
||||||
cleanup_hp(&enc_sess->esi_hp);
|
cleanup_hp(&enc_sess->esi_hp);
|
||||||
|
|
||||||
free(enc_sess->esi_sess_resume_buf);
|
|
||||||
free(enc_sess->esi_hostname);
|
|
||||||
free(enc_sess);
|
free(enc_sess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1910,11 +1980,18 @@ static const enum enc_level hety2el[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const enum enc_level pns2enc_level[] =
|
static const enum enc_level pns2enc_level[2][N_PNS] =
|
||||||
{
|
{
|
||||||
[PNS_INIT] = ENC_LEV_CLEAR,
|
[0] = {
|
||||||
[PNS_HSK] = ENC_LEV_INIT,
|
[PNS_INIT] = ENC_LEV_CLEAR,
|
||||||
[PNS_APP] = ENC_LEV_FORW,
|
[PNS_HSK] = ENC_LEV_INIT,
|
||||||
|
[PNS_APP] = ENC_LEV_EARLY,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
[PNS_INIT] = ENC_LEV_CLEAR,
|
||||||
|
[PNS_HSK] = ENC_LEV_INIT,
|
||||||
|
[PNS_APP] = ENC_LEV_FORW,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1941,8 +2018,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
||||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||||
|
|
||||||
pns = lsquic_packet_out_pns(packet_out);
|
pns = lsquic_packet_out_pns(packet_out);
|
||||||
/* TODO Obviously, will need more logic for 0-RTT */
|
enc_level = pns2enc_level[ enc_sess->esi_have_forw ][ pns ];
|
||||||
enc_level = pns2enc_level[ pns ];
|
|
||||||
|
|
||||||
if (enc_level == ENC_LEV_FORW)
|
if (enc_level == ENC_LEV_FORW)
|
||||||
{
|
{
|
||||||
|
@ -2458,7 +2534,7 @@ static int
|
||||||
iquic_esf_sess_resume_enabled (enc_session_t *enc_session_p)
|
iquic_esf_sess_resume_enabled (enc_session_t *enc_session_p)
|
||||||
{
|
{
|
||||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||||
return enc_sess->esi_sess_resume_buf != NULL;
|
return !!(enc_sess->esi_flags & ESI_USE_SSL_TICKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2817,6 +2893,9 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
||||||
key_len, hexbuf));
|
key_len, hexbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rw && enc_level == ENC_LEV_FORW)
|
||||||
|
enc_sess->esi_have_forw = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -2955,25 +3034,11 @@ chsk_ietf_on_new_stream (void *stream_if_ctx, struct lsquic_stream *stream)
|
||||||
enum enc_level enc_level;
|
enum enc_level enc_level;
|
||||||
|
|
||||||
enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
||||||
if (enc_level != ENC_LEV_CLEAR)
|
if (enc_level == ENC_LEV_CLEAR)
|
||||||
{
|
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
||||||
LSQ_DEBUG("skip initialization of stream at level %u", enc_level);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(enc_sess->esi_flags & ESI_SERVER) == 0 &&
|
|
||||||
0 != init_client(enc_sess))
|
|
||||||
{
|
|
||||||
LSQ_WARN("enc session could not be initialized");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
|
||||||
|
|
||||||
LSQ_DEBUG("handshake stream created successfully");
|
LSQ_DEBUG("handshake stream created successfully");
|
||||||
|
|
||||||
end:
|
|
||||||
return stream_if_ctx;
|
return stream_if_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3006,6 +3071,7 @@ chsk_ietf_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||||
static const char *const ihs2str[] = {
|
static const char *const ihs2str[] = {
|
||||||
[IHS_WANT_READ] = "want read",
|
[IHS_WANT_READ] = "want read",
|
||||||
[IHS_WANT_WRITE] = "want write",
|
[IHS_WANT_WRITE] = "want write",
|
||||||
|
[IHS_WANT_RW] = "want rw",
|
||||||
[IHS_STOP] = "stop",
|
[IHS_STOP] = "stop",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3036,6 +3102,10 @@ iquic_esfi_shake_stream (enc_session_t *sess,
|
||||||
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
||||||
enc_sess->esi_cryst_if->csi_wantread(stream, 0);
|
enc_sess->esi_cryst_if->csi_wantread(stream, 0);
|
||||||
break;
|
break;
|
||||||
|
case IHS_WANT_RW:
|
||||||
|
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
||||||
|
enc_sess->esi_cryst_if->csi_wantread(stream, 1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(st == IHS_STOP);
|
assert(st == IHS_STOP);
|
||||||
write = !lsquic_frab_list_empty(&enc_sess->esi_frals[enc_level]);
|
write = !lsquic_frab_list_empty(&enc_sess->esi_frals[enc_level]);
|
||||||
|
@ -3209,3 +3279,96 @@ const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS] =
|
||||||
/* [draft-ietf-quic-tls-29] Section 5.8 */
|
/* [draft-ietf-quic-tls-29] Section 5.8 */
|
||||||
(unsigned char *) "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c",
|
(unsigned char *) "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
lsquic_enc_sess_ietf_gen_quic_ctx (
|
||||||
|
const struct lsquic_engine_settings *settings,
|
||||||
|
enum lsquic_version version, unsigned char *buf, size_t bufsz)
|
||||||
|
{
|
||||||
|
struct transport_params params;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* This code is pretty much copied from gen_trans_params(), with
|
||||||
|
* small (but important) exceptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
params.tp_init_max_data = settings->es_init_max_data;
|
||||||
|
params.tp_init_max_stream_data_bidi_local
|
||||||
|
= settings->es_init_max_stream_data_bidi_local;
|
||||||
|
params.tp_init_max_stream_data_bidi_remote
|
||||||
|
= settings->es_init_max_stream_data_bidi_remote;
|
||||||
|
params.tp_init_max_stream_data_uni
|
||||||
|
= settings->es_init_max_stream_data_uni;
|
||||||
|
params.tp_init_max_streams_uni
|
||||||
|
= settings->es_init_max_streams_uni;
|
||||||
|
params.tp_init_max_streams_bidi
|
||||||
|
= settings->es_init_max_streams_bidi;
|
||||||
|
params.tp_ack_delay_exponent
|
||||||
|
= TP_DEF_ACK_DELAY_EXP;
|
||||||
|
params.tp_max_idle_timeout = settings->es_idle_timeout * 1000;
|
||||||
|
params.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY;
|
||||||
|
params.tp_active_connection_id_limit = MAX_IETF_CONN_DCIDS;
|
||||||
|
params.tp_set |= (1 << TPI_INIT_MAX_DATA)
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_UNI)
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_UNI)
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_BIDI)
|
||||||
|
| (1 << TPI_ACK_DELAY_EXPONENT)
|
||||||
|
| (1 << TPI_MAX_IDLE_TIMEOUT)
|
||||||
|
| (1 << TPI_MAX_ACK_DELAY)
|
||||||
|
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
|
||||||
|
;
|
||||||
|
if (settings->es_max_udp_payload_size_rx)
|
||||||
|
{
|
||||||
|
params.tp_max_udp_payload_size = settings->es_max_udp_payload_size_rx;
|
||||||
|
params.tp_set |= 1 << TPI_MAX_UDP_PAYLOAD_SIZE;
|
||||||
|
}
|
||||||
|
if (!settings->es_allow_migration)
|
||||||
|
params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
|
||||||
|
if (settings->es_ql_bits)
|
||||||
|
{
|
||||||
|
params.tp_loss_bits = settings->es_ql_bits - 1;
|
||||||
|
params.tp_set |= 1 << TPI_LOSS_BITS;
|
||||||
|
}
|
||||||
|
if (settings->es_delayed_acks)
|
||||||
|
{
|
||||||
|
params.tp_numerics[TPI_MIN_ACK_DELAY] = 10000; /* TODO: make into a constant? make configurable? */
|
||||||
|
params.tp_set |= 1 << TPI_MIN_ACK_DELAY;
|
||||||
|
}
|
||||||
|
if (settings->es_timestamps)
|
||||||
|
{
|
||||||
|
params.tp_numerics[TPI_TIMESTAMPS] = TS_GENERATE_THEM;
|
||||||
|
params.tp_set |= 1 << TPI_TIMESTAMPS;
|
||||||
|
}
|
||||||
|
if (settings->es_datagrams)
|
||||||
|
{
|
||||||
|
if (params.tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
|
||||||
|
params.tp_numerics[TPI_MAX_DATAGRAM_FRAME_SIZE]
|
||||||
|
= params.tp_max_udp_payload_size;
|
||||||
|
else
|
||||||
|
params.tp_numerics[TPI_MAX_DATAGRAM_FRAME_SIZE]
|
||||||
|
= TP_DEF_MAX_UDP_PAYLOAD_SIZE;
|
||||||
|
params.tp_set |= 1 << TPI_MAX_DATAGRAM_FRAME_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.tp_set &= SERVER_0RTT_TPS;
|
||||||
|
|
||||||
|
len = (version == LSQVER_ID27 ? lsquic_tp_encode_27 : lsquic_tp_encode)(
|
||||||
|
¶ms, 1, buf, bufsz);
|
||||||
|
if (len >= 0)
|
||||||
|
{
|
||||||
|
char str[MAX_TP_STR_SZ];
|
||||||
|
LSQ_LOG1(LSQ_LOG_DEBUG, "generated QUIC server context of %d bytes "
|
||||||
|
"for version %s", len, lsquic_ver2str[version]);
|
||||||
|
LSQ_LOG1(LSQ_LOG_DEBUG, "%s", ((version == LSQVER_ID27
|
||||||
|
? lsquic_tp_to_str_27 : lsquic_tp_to_str)(¶ms, str,
|
||||||
|
sizeof(str)), str));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LSQ_LOG1(LSQ_LOG_WARN, "cannot generate QUIC server context: %d",
|
||||||
|
errno);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
|
@ -631,6 +631,22 @@ lsquic_engine_new (unsigned flags,
|
||||||
engine->pub.enp_tokgen = lsquic_tg_new(&engine->pub);
|
engine->pub.enp_tokgen = lsquic_tg_new(&engine->pub);
|
||||||
if (!engine->pub.enp_tokgen)
|
if (!engine->pub.enp_tokgen)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (engine->flags & ENG_SERVER)
|
||||||
|
for (i = 0; i < sizeof(engine->pub.enp_quic_ctx_sz)
|
||||||
|
/ sizeof(engine->pub.enp_quic_ctx_sz[0]); ++i)
|
||||||
|
{
|
||||||
|
int sz = lsquic_enc_sess_ietf_gen_quic_ctx(
|
||||||
|
&engine->pub.enp_settings,
|
||||||
|
i == 0 ? LSQVER_ID27 : LSQVER_ID28,
|
||||||
|
engine->pub.enp_quic_ctx_buf[i],
|
||||||
|
sizeof(engine->pub.enp_quic_ctx_buf));
|
||||||
|
if (sz < 0)
|
||||||
|
{
|
||||||
|
free(engine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
engine->pub.enp_quic_ctx_sz[i] = (unsigned) sz;
|
||||||
|
}
|
||||||
engine->pub.enp_crand = &engine->crand;
|
engine->pub.enp_crand = &engine->crand;
|
||||||
if (engine->pub.enp_settings.es_noprogress_timeout)
|
if (engine->pub.enp_settings.es_noprogress_timeout)
|
||||||
engine->pub.enp_noprog_timeout
|
engine->pub.enp_noprog_timeout
|
||||||
|
@ -1106,6 +1122,34 @@ find_conn_by_addr (struct lsquic_hash *hash, const struct sockaddr *sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* When connections are identified by the local address, we need to drop
|
||||||
|
* packets that use DCIDs that do not correspond to any of SCIDs. This
|
||||||
|
* can happen when peer retires a SCID. This mimics the normal behavior,
|
||||||
|
* when connections are looked up in engine->conns_hash by ID: when there
|
||||||
|
* is no match, the packet is dropped.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dcid_checks_out (const struct lsquic_conn *conn, const lsquic_cid_t *dcid)
|
||||||
|
{
|
||||||
|
const struct conn_cid_elem *cce;
|
||||||
|
|
||||||
|
if (LSQUIC_CIDS_EQ(CN_SCID(conn), dcid))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Slow check for those rare cases */
|
||||||
|
for (cce = conn->cn_cces; cce < END_OF_CCES(conn); ++cce)
|
||||||
|
if ((conn->cn_cces_mask & (1 << (cce - conn->cn_cces)))
|
||||||
|
&& !(cce->cce_flags & CCE_PORT)
|
||||||
|
&& LSQUIC_CIDS_EQ(&cce->cce_cid, dcid))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("connection checks out");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static lsquic_conn_t *
|
static lsquic_conn_t *
|
||||||
find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||||
struct packin_parse_state *ppstate, const struct sockaddr *sa_local)
|
struct packin_parse_state *ppstate, const struct sockaddr *sa_local)
|
||||||
|
@ -1114,7 +1158,17 @@ find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
||||||
lsquic_conn_t *conn;
|
lsquic_conn_t *conn;
|
||||||
|
|
||||||
if (engine->flags & ENG_CONNS_BY_ADDR)
|
if (engine->flags & ENG_CONNS_BY_ADDR)
|
||||||
|
{
|
||||||
el = find_conn_by_addr(engine->conns_hash, sa_local);
|
el = find_conn_by_addr(engine->conns_hash, sa_local);
|
||||||
|
if ((packet_in->pi_flags & PI_CONN_ID)
|
||||||
|
&& !dcid_checks_out(lsquic_hashelem_getdata(el),
|
||||||
|
&packet_in->pi_conn_id))
|
||||||
|
{
|
||||||
|
LSQ_DEBUGC("DCID matches no SCID in connection %"CID_FMT": drop it",
|
||||||
|
CID_BITS(&packet_in->pi_conn_id));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (packet_in->pi_flags & PI_CONN_ID)
|
else if (packet_in->pi_flags & PI_CONN_ID)
|
||||||
el = lsquic_hash_find(engine->conns_hash,
|
el = lsquic_hash_find(engine->conns_hash,
|
||||||
packet_in->pi_conn_id.idbuf, packet_in->pi_conn_id.len);
|
packet_in->pi_conn_id.idbuf, packet_in->pi_conn_id.len);
|
||||||
|
|
|
@ -78,6 +78,11 @@ struct lsquic_engine_public {
|
||||||
struct lsquic_hash *enp_server_certs;
|
struct lsquic_hash *enp_server_certs;
|
||||||
/* gQUIC server configuration: */
|
/* gQUIC server configuration: */
|
||||||
struct lsquic_server_config *enp_server_config;
|
struct lsquic_server_config *enp_server_config;
|
||||||
|
/* Serialized subset of server engine transport parameters that is used
|
||||||
|
* as SSL QUIC context. 0 is for version <= LSQVER_ID27, 1 is for others.
|
||||||
|
*/
|
||||||
|
unsigned char enp_quic_ctx_buf[2][200];
|
||||||
|
unsigned enp_quic_ctx_sz[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Put connection onto the Tickable Queue if it is not already on it. If
|
/* Put connection onto the Tickable Queue if it is not already on it. If
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include "lsquic_frab_list.h"
|
#include "lsquic_frab_list.h"
|
||||||
#include "lsquic_ev_log.h"
|
#include "lsquic_ev_log.h"
|
||||||
|
|
||||||
|
#include "fiu-local.h"
|
||||||
|
|
||||||
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER
|
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER
|
||||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\
|
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\
|
||||||
lsquic_stream_conn(fw->fw_stream))
|
lsquic_stream_conn(fw->fw_stream))
|
||||||
|
@ -497,6 +499,8 @@ lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
fiu_return_on("frame_writer/writer_promise", -1);
|
||||||
|
|
||||||
if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers))
|
if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -4156,10 +4156,15 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
||||||
if (0 != lsquic_headers_stream_push_promise(conn->fc_pub.u.gquic.hs, dep_stream->id,
|
if (0 != lsquic_headers_stream_push_promise(conn->fc_pub.u.gquic.hs, dep_stream->id,
|
||||||
pushed_stream->id, headers))
|
pushed_stream->id, headers))
|
||||||
{
|
{
|
||||||
/* Since the failure to write to HEADERS stream results in aborting
|
/* If forget we ever had the hset pointer: */
|
||||||
* the connection, we do not bother rolling back.
|
lsquic_stream_drop_hset_ref(pushed_stream);
|
||||||
*/
|
/* Now roll back stream creation and return stream ID: */
|
||||||
LSQ_ERROR("could not send push promise");
|
if (pushed_stream->sm_hash_el.qhe_flags & QHE_HASHED)
|
||||||
|
lsquic_hash_erase(conn->fc_pub.all_streams,
|
||||||
|
&pushed_stream->sm_hash_el);
|
||||||
|
lsquic_stream_destroy(pushed_stream);
|
||||||
|
conn->fc_last_stream_id -= 2;
|
||||||
|
LSQ_INFO("could not send push promise");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ enum ifull_conn_flags
|
||||||
IFC_IGNORE_HSK = 1 << 25,
|
IFC_IGNORE_HSK = 1 << 25,
|
||||||
IFC_PROC_CRYPTO = 1 << 26,
|
IFC_PROC_CRYPTO = 1 << 26,
|
||||||
IFC_MIGRA = 1 << 27,
|
IFC_MIGRA = 1 << 27,
|
||||||
IFC_UNUSED28 = 1 << 28, /* Unused */
|
IFC_HTTP_INITED = 1 << 28, /* HTTP initialized */
|
||||||
IFC_DELAYED_ACKS = 1 << 29, /* Delayed ACKs are enabled */
|
IFC_DELAYED_ACKS = 1 << 29, /* Delayed ACKs are enabled */
|
||||||
IFC_TIMESTAMPS = 1 << 30, /* Timestamps are enabled */
|
IFC_TIMESTAMPS = 1 << 30, /* Timestamps are enabled */
|
||||||
IFC_DATAGRAMS = 1u<< 31, /* Datagrams are enabled */
|
IFC_DATAGRAMS = 1u<< 31, /* Datagrams are enabled */
|
||||||
|
@ -153,6 +153,7 @@ enum more_flags
|
||||||
MF_CONN_CLOSE_PACK = 1 << 4, /* CONNECTION_CLOSE has been packetized */
|
MF_CONN_CLOSE_PACK = 1 << 4, /* CONNECTION_CLOSE has been packetized */
|
||||||
MF_SEND_WRONG_COUNTS= 1 << 5, /* Send wrong ECN counts to peer */
|
MF_SEND_WRONG_COUNTS= 1 << 5, /* Send wrong ECN counts to peer */
|
||||||
MF_WANT_DATAGRAM_WRITE = 1 << 6,
|
MF_WANT_DATAGRAM_WRITE = 1 << 6,
|
||||||
|
MF_DOING_0RTT = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -568,6 +569,12 @@ find_cce_by_cid (struct ietf_full_conn *, const lsquic_cid_t *);
|
||||||
static void
|
static void
|
||||||
mtu_probe_too_large (struct ietf_full_conn *, const struct lsquic_packet_out *);
|
mtu_probe_too_large (struct ietf_full_conn *, const struct lsquic_packet_out *);
|
||||||
|
|
||||||
|
static int
|
||||||
|
apply_trans_params (struct ietf_full_conn *, const struct transport_params *);
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_http (struct ietf_full_conn *);
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
highest_bit_set (unsigned sz)
|
highest_bit_set (unsigned sz)
|
||||||
{
|
{
|
||||||
|
@ -1252,7 +1259,7 @@ ietf_full_conn_init (struct ietf_full_conn *conn,
|
||||||
conn->ifc_peer_hq_settings.header_table_size = HQ_DF_QPACK_MAX_TABLE_CAPACITY;
|
conn->ifc_peer_hq_settings.header_table_size = HQ_DF_QPACK_MAX_TABLE_CAPACITY;
|
||||||
conn->ifc_peer_hq_settings.qpack_blocked_streams = HQ_DF_QPACK_BLOCKED_STREAMS;
|
conn->ifc_peer_hq_settings.qpack_blocked_streams = HQ_DF_QPACK_BLOCKED_STREAMS;
|
||||||
|
|
||||||
conn->ifc_flags = flags | IFC_CREATED_OK | IFC_FIRST_TICK;
|
conn->ifc_flags = flags | IFC_FIRST_TICK;
|
||||||
conn->ifc_max_ack_packno[PNS_INIT] = IQUIC_INVALID_PACKNO;
|
conn->ifc_max_ack_packno[PNS_INIT] = IQUIC_INVALID_PACKNO;
|
||||||
conn->ifc_max_ack_packno[PNS_HSK] = IQUIC_INVALID_PACKNO;
|
conn->ifc_max_ack_packno[PNS_HSK] = IQUIC_INVALID_PACKNO;
|
||||||
conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO;
|
conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO;
|
||||||
|
@ -1282,6 +1289,7 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
const unsigned char *sess_resume, size_t sess_resume_sz,
|
const unsigned char *sess_resume, size_t sess_resume_sz,
|
||||||
const unsigned char *token, size_t token_sz)
|
const unsigned char *token, size_t token_sz)
|
||||||
{
|
{
|
||||||
|
const struct transport_params *params;
|
||||||
const struct enc_session_funcs_iquic *esfi;
|
const struct enc_session_funcs_iquic *esfi;
|
||||||
struct ietf_full_conn *conn;
|
struct ietf_full_conn *conn;
|
||||||
enum lsquic_version ver, sess_resume_version;
|
enum lsquic_version ver, sess_resume_version;
|
||||||
|
@ -1397,6 +1405,18 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
conn->ifc_created = now;
|
conn->ifc_created = now;
|
||||||
LSQ_DEBUG("logging using %s SCID",
|
LSQ_DEBUG("logging using %s SCID",
|
||||||
LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "client" : "server");
|
LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "client" : "server");
|
||||||
|
if (sess_resume && (params
|
||||||
|
= conn->ifc_conn.cn_esf.i->esfi_get_peer_transport_params(
|
||||||
|
conn->ifc_conn.cn_enc_session), params != NULL))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("initializing transport parameters for 0RTT");
|
||||||
|
if (0 != apply_trans_params(conn, params))
|
||||||
|
goto full_err;
|
||||||
|
if ((conn->ifc_flags & IFC_HTTP) && 0 != init_http(conn))
|
||||||
|
goto full_err;
|
||||||
|
conn->ifc_mflags |= MF_DOING_0RTT;
|
||||||
|
}
|
||||||
|
conn->ifc_flags |= IFC_CREATED_OK;
|
||||||
return &conn->ifc_conn;
|
return &conn->ifc_conn;
|
||||||
|
|
||||||
err4:
|
err4:
|
||||||
|
@ -1411,6 +1431,10 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
free(conn);
|
free(conn);
|
||||||
err0:
|
err0:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
full_err:
|
||||||
|
ietf_full_conn_ci_destroy(&conn->ifc_conn);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1635,6 +1659,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
||||||
|
|
||||||
LSQ_DEBUG("logging using %s SCID",
|
LSQ_DEBUG("logging using %s SCID",
|
||||||
LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "server" : "client");
|
LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "server" : "client");
|
||||||
|
conn->ifc_flags |= IFC_CREATED_OK;
|
||||||
return &conn->ifc_conn;
|
return &conn->ifc_conn;
|
||||||
|
|
||||||
err3:
|
err3:
|
||||||
|
@ -3317,35 +3342,13 @@ maybe_start_migration (struct ietf_full_conn *conn)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
handshake_ok (struct lsquic_conn *lconn)
|
apply_trans_params (struct ietf_full_conn *conn,
|
||||||
|
const struct transport_params *params)
|
||||||
{
|
{
|
||||||
struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
|
|
||||||
struct lsquic_stream *stream;
|
struct lsquic_stream *stream;
|
||||||
struct lsquic_hash_elem *el;
|
struct lsquic_hash_elem *el;
|
||||||
struct dcid_elem *dce;
|
|
||||||
const struct transport_params *params;
|
|
||||||
enum stream_id_type sit;
|
enum stream_id_type sit;
|
||||||
uint64_t limit;
|
uint64_t limit;
|
||||||
char buf[MAX_TP_STR_SZ];
|
|
||||||
|
|
||||||
fiu_return_on("full_conn_ietf/handshake_ok", -1);
|
|
||||||
|
|
||||||
/* Need to set this flag even we hit an error in the rest of this funciton.
|
|
||||||
* This is because this flag is used to calculate packet out header size
|
|
||||||
*/
|
|
||||||
lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
|
|
||||||
|
|
||||||
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
|
|
||||||
lconn->cn_enc_session);
|
|
||||||
if (!params)
|
|
||||||
{
|
|
||||||
ABORT_WARN("could not get transport parameters");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LSQ_DEBUG("peer transport parameters: %s",
|
|
||||||
((lconn->cn_version == LSQVER_ID27 ? lsquic_tp_to_str_27
|
|
||||||
: lsquic_tp_to_str)(params, buf, sizeof(buf)), buf));
|
|
||||||
|
|
||||||
if ((params->tp_set & (1 << TPI_LOSS_BITS))
|
if ((params->tp_set & (1 << TPI_LOSS_BITS))
|
||||||
&& conn->ifc_settings->es_ql_bits == 2)
|
&& conn->ifc_settings->es_ql_bits == 2)
|
||||||
|
@ -3487,6 +3490,104 @@ handshake_ok (struct lsquic_conn *lconn)
|
||||||
CUR_NPATH(conn)->np_pack_size);
|
CUR_NPATH(conn)->np_pack_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->tp_active_connection_id_limit > conn->ifc_conn.cn_n_cces)
|
||||||
|
conn->ifc_active_cids_limit = conn->ifc_conn.cn_n_cces;
|
||||||
|
else
|
||||||
|
conn->ifc_active_cids_limit = params->tp_active_connection_id_limit;
|
||||||
|
conn->ifc_first_active_cid_seqno = conn->ifc_scid_seqno;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_http (struct ietf_full_conn *conn)
|
||||||
|
{
|
||||||
|
fiu_return_on("full_conn_ietf/init_http", -1);
|
||||||
|
lsquic_qeh_init(&conn->ifc_qeh, &conn->ifc_conn);
|
||||||
|
if (0 == avail_streams_count(conn, conn->ifc_flags & IFC_SERVER,
|
||||||
|
SD_UNI))
|
||||||
|
{
|
||||||
|
ABORT_QUIETLY(1, HEC_GENERAL_PROTOCOL_ERROR, "cannot create "
|
||||||
|
"control stream due to peer-imposed limit");
|
||||||
|
conn->ifc_error = CONN_ERR(1, HEC_GENERAL_PROTOCOL_ERROR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (0 != create_ctl_stream_out(conn))
|
||||||
|
{
|
||||||
|
ABORT_WARN("cannot create outgoing control stream");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (0 != lsquic_hcso_write_settings(&conn->ifc_hcso,
|
||||||
|
&conn->ifc_enpub->enp_settings, conn->ifc_flags & IFC_SERVER))
|
||||||
|
{
|
||||||
|
ABORT_WARN("cannot write SETTINGS");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!(conn->ifc_flags & IFC_SERVER)
|
||||||
|
&& (conn->ifc_u.cli.ifcli_flags & IFCLI_PUSH_ENABLED)
|
||||||
|
&& 0 != lsquic_hcso_write_max_push_id(&conn->ifc_hcso,
|
||||||
|
conn->ifc_u.cli.ifcli_max_push_id))
|
||||||
|
{
|
||||||
|
ABORT_WARN("cannot write MAX_PUSH_ID");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (0 != lsquic_qdh_init(&conn->ifc_qdh, &conn->ifc_conn,
|
||||||
|
conn->ifc_flags & IFC_SERVER, conn->ifc_enpub,
|
||||||
|
conn->ifc_settings->es_qpack_dec_max_size,
|
||||||
|
conn->ifc_settings->es_qpack_dec_max_blocked))
|
||||||
|
{
|
||||||
|
ABORT_WARN("cannot initialize QPACK decoder");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (avail_streams_count(conn, conn->ifc_flags & IFC_SERVER, SD_UNI) > 0)
|
||||||
|
{
|
||||||
|
if (0 != create_qdec_stream_out(conn))
|
||||||
|
{
|
||||||
|
ABORT_WARN("cannot create outgoing QPACK decoder stream");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queue_streams_blocked_frame(conn, SD_UNI);
|
||||||
|
LSQ_DEBUG("cannot create outgoing QPACK decoder stream due to "
|
||||||
|
"unidir limits");
|
||||||
|
}
|
||||||
|
conn->ifc_flags |= IFC_HTTP_INITED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
handshake_ok (struct lsquic_conn *lconn)
|
||||||
|
{
|
||||||
|
struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
|
||||||
|
struct dcid_elem *dce;
|
||||||
|
const struct transport_params *params;
|
||||||
|
char buf[MAX_TP_STR_SZ];
|
||||||
|
|
||||||
|
fiu_return_on("full_conn_ietf/handshake_ok", -1);
|
||||||
|
|
||||||
|
/* Need to set this flag even we hit an error in the rest of this funciton.
|
||||||
|
* This is because this flag is used to calculate packet out header size
|
||||||
|
*/
|
||||||
|
lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
|
||||||
|
|
||||||
|
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
|
||||||
|
lconn->cn_enc_session);
|
||||||
|
if (!params)
|
||||||
|
{
|
||||||
|
ABORT_WARN("could not get transport parameters");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSQ_DEBUG("peer transport parameters: %s",
|
||||||
|
((lconn->cn_version == LSQVER_ID27 ? lsquic_tp_to_str_27
|
||||||
|
: lsquic_tp_to_str)(params, buf, sizeof(buf)), buf));
|
||||||
|
if (0 != apply_trans_params(conn, params))
|
||||||
|
return -1;
|
||||||
|
|
||||||
dce = get_new_dce(conn);
|
dce = get_new_dce(conn);
|
||||||
if (!dce)
|
if (!dce)
|
||||||
{
|
{
|
||||||
|
@ -3518,65 +3619,9 @@ handshake_ok (struct lsquic_conn *lconn)
|
||||||
|
|
||||||
LSQ_INFO("applied peer transport parameters");
|
LSQ_INFO("applied peer transport parameters");
|
||||||
|
|
||||||
if (conn->ifc_flags & IFC_HTTP)
|
if ((conn->ifc_flags & (IFC_HTTP|IFC_HTTP_INITED)) == IFC_HTTP)
|
||||||
{
|
if (0 != init_http(conn))
|
||||||
lsquic_qeh_init(&conn->ifc_qeh, &conn->ifc_conn);
|
|
||||||
if (0 == avail_streams_count(conn, conn->ifc_flags & IFC_SERVER,
|
|
||||||
SD_UNI))
|
|
||||||
{
|
|
||||||
ABORT_QUIETLY(1, HEC_GENERAL_PROTOCOL_ERROR, "cannot create "
|
|
||||||
"control stream due to peer-imposed limit");
|
|
||||||
conn->ifc_error = CONN_ERR(1, HEC_GENERAL_PROTOCOL_ERROR);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
if (0 != create_ctl_stream_out(conn))
|
|
||||||
{
|
|
||||||
ABORT_WARN("cannot create outgoing control stream");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (0 != lsquic_hcso_write_settings(&conn->ifc_hcso,
|
|
||||||
&conn->ifc_enpub->enp_settings, conn->ifc_flags & IFC_SERVER))
|
|
||||||
{
|
|
||||||
ABORT_WARN("cannot write SETTINGS");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!(conn->ifc_flags & IFC_SERVER)
|
|
||||||
&& (conn->ifc_u.cli.ifcli_flags & IFCLI_PUSH_ENABLED)
|
|
||||||
&& 0 != lsquic_hcso_write_max_push_id(&conn->ifc_hcso,
|
|
||||||
conn->ifc_u.cli.ifcli_max_push_id))
|
|
||||||
{
|
|
||||||
ABORT_WARN("cannot write MAX_PUSH_ID");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (0 != lsquic_qdh_init(&conn->ifc_qdh, &conn->ifc_conn,
|
|
||||||
conn->ifc_flags & IFC_SERVER, conn->ifc_enpub,
|
|
||||||
conn->ifc_settings->es_qpack_dec_max_size,
|
|
||||||
conn->ifc_settings->es_qpack_dec_max_blocked))
|
|
||||||
{
|
|
||||||
ABORT_WARN("cannot initialize QPACK decoder");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (avail_streams_count(conn, conn->ifc_flags & IFC_SERVER, SD_UNI) > 0)
|
|
||||||
{
|
|
||||||
if (0 != create_qdec_stream_out(conn))
|
|
||||||
{
|
|
||||||
ABORT_WARN("cannot create outgoing QPACK decoder stream");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
queue_streams_blocked_frame(conn, SD_UNI);
|
|
||||||
LSQ_DEBUG("cannot create outgoing QPACK decoder stream due to "
|
|
||||||
"unidir limits");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params->tp_active_connection_id_limit > conn->ifc_conn.cn_n_cces)
|
|
||||||
conn->ifc_active_cids_limit = conn->ifc_conn.cn_n_cces;
|
|
||||||
else
|
|
||||||
conn->ifc_active_cids_limit = params->tp_active_connection_id_limit;
|
|
||||||
conn->ifc_first_active_cid_seqno = conn->ifc_scid_seqno;
|
|
||||||
|
|
||||||
if (conn->ifc_settings->es_dplpmtud)
|
if (conn->ifc_settings->es_dplpmtud)
|
||||||
conn->ifc_mflags |= MF_CHECK_MTU_PROBE;
|
conn->ifc_mflags |= MF_CHECK_MTU_PROBE;
|
||||||
|
@ -3585,6 +3630,9 @@ handshake_ok (struct lsquic_conn *lconn)
|
||||||
conn->ifc_send_flags |= SF_SEND_NEW_CID;
|
conn->ifc_send_flags |= SF_SEND_NEW_CID;
|
||||||
maybe_create_delayed_streams(conn);
|
maybe_create_delayed_streams(conn);
|
||||||
|
|
||||||
|
if (!(conn->ifc_flags & IFC_SERVER))
|
||||||
|
lsquic_send_ctl_0rtt_to_1rtt(&conn->ifc_send_ctl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3615,10 +3663,10 @@ ietf_full_conn_ci_hsk_done (struct lsquic_conn *lconn,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
case LSQ_HSK_RESUMED_FAIL: /* IETF crypto never returns this */
|
||||||
assert(0);
|
assert(0);
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
case LSQ_HSK_FAIL:
|
case LSQ_HSK_FAIL:
|
||||||
case LSQ_HSK_RESUMED_FAIL:
|
|
||||||
handshake_failed(lconn);
|
handshake_failed(lconn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -7406,6 +7454,7 @@ check_or_schedule_mtu_probe (struct ietf_full_conn *conn, lsquic_time_t now)
|
||||||
|
|
||||||
if (!(conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
if (!(conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||||
|| (conn->ifc_flags & IFC_CLOSING)
|
|| (conn->ifc_flags & IFC_CLOSING)
|
||||||
|
|| ~0ull == lsquic_senhist_largest(&conn->ifc_send_ctl.sc_senhist)
|
||||||
|| lsquic_senhist_largest(&conn->ifc_send_ctl.sc_senhist) < 30
|
|| lsquic_senhist_largest(&conn->ifc_send_ctl.sc_senhist) < 30
|
||||||
|| lsquic_send_ctl_in_recovery(&conn->ifc_send_ctl)
|
|| lsquic_send_ctl_in_recovery(&conn->ifc_send_ctl)
|
||||||
|| !lsquic_send_ctl_can_send_probe(&conn->ifc_send_ctl,
|
|| !lsquic_send_ctl_can_send_probe(&conn->ifc_send_ctl,
|
||||||
|
@ -7594,6 +7643,16 @@ ietf_full_conn_ci_retx_timeout (struct lsquic_conn *lconn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ietf_full_conn_ci_early_data_failed (struct lsquic_conn *lconn)
|
||||||
|
{
|
||||||
|
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
|
||||||
|
|
||||||
|
LSQ_DEBUG("early data failed");
|
||||||
|
lsquic_send_ctl_stash_0rtt_packets(&conn->ifc_send_ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
ietf_full_conn_ci_get_min_datagram_size (struct lsquic_conn *lconn)
|
ietf_full_conn_ci_get_min_datagram_size (struct lsquic_conn *lconn)
|
||||||
{
|
{
|
||||||
|
@ -7830,7 +7889,8 @@ ietf_full_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
||||||
conn->ifc_flags |= (s < 0) << IFC_BIT_ERROR;
|
conn->ifc_flags |= (s < 0) << IFC_BIT_ERROR;
|
||||||
if (0 == s)
|
if (0 == s)
|
||||||
process_crypto_stream_write_events(conn);
|
process_crypto_stream_write_events(conn);
|
||||||
goto end_write;
|
if (!(conn->ifc_mflags & MF_DOING_0RTT))
|
||||||
|
goto end_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_conn_flush_special_streams(conn);
|
maybe_conn_flush_special_streams(conn);
|
||||||
|
@ -8279,6 +8339,7 @@ ietf_full_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
|
||||||
.ci_destroy = ietf_full_conn_ci_destroy, \
|
.ci_destroy = ietf_full_conn_ci_destroy, \
|
||||||
.ci_drain_time = ietf_full_conn_ci_drain_time, \
|
.ci_drain_time = ietf_full_conn_ci_drain_time, \
|
||||||
.ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams, \
|
.ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams, \
|
||||||
|
.ci_early_data_failed = ietf_full_conn_ci_early_data_failed, \
|
||||||
.ci_get_engine = ietf_full_conn_ci_get_engine, \
|
.ci_get_engine = ietf_full_conn_ci_get_engine, \
|
||||||
.ci_get_log_cid = ietf_full_conn_ci_get_log_cid, \
|
.ci_get_log_cid = ietf_full_conn_ci_get_log_cid, \
|
||||||
.ci_get_min_datagram_size= ietf_full_conn_ci_get_min_datagram_size, \
|
.ci_get_min_datagram_size= ietf_full_conn_ci_get_min_datagram_size, \
|
||||||
|
|
|
@ -88,7 +88,7 @@ is_valid_gquic_hs_packet (const unsigned char *buf, size_t bufsz,
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
|
lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
|
||||||
const unsigned char *buf, size_t bufsz, size_t packet_in_sz)
|
const unsigned char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
lsquic_ver_tag_t tag;
|
lsquic_ver_tag_t tag;
|
||||||
int is_valid;
|
int is_valid;
|
||||||
|
@ -104,7 +104,7 @@ lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
|
||||||
case 0x80|0x00|0x20|0x10|0x08:
|
case 0x80|0x00|0x20|0x10|0x08:
|
||||||
case 0x80|0x40|0x20|0x10|0x00:
|
case 0x80|0x40|0x20|0x10|0x00:
|
||||||
case 0x80|0x00|0x20|0x10|0x00:
|
case 0x80|0x00|0x20|0x10|0x00:
|
||||||
is_valid = packet_in_sz >= IQUIC_MIN_INIT_PACKET_SZ
|
is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ
|
||||||
&& lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag);
|
&& lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag);
|
||||||
break;
|
break;
|
||||||
/* 1X00 XGGG: ID-22 long header */
|
/* 1X00 XGGG: ID-22 long header */
|
||||||
|
@ -122,7 +122,7 @@ lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
|
||||||
case 0x80|0x00|0x20|0x00|0x08:
|
case 0x80|0x00|0x20|0x00|0x08:
|
||||||
case 0x80|0x40|0x20|0x00|0x00:
|
case 0x80|0x40|0x20|0x00|0x00:
|
||||||
case 0x80|0x00|0x20|0x00|0x00:
|
case 0x80|0x00|0x20|0x00|0x00:
|
||||||
is_valid = packet_in_sz >= IQUIC_MIN_INIT_PACKET_SZ
|
is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ
|
||||||
&& lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz, &tag);
|
&& lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz, &tag);
|
||||||
break;
|
break;
|
||||||
/* 01XX XGGG: ID-22 short header */
|
/* 01XX XGGG: ID-22 short header */
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -560,6 +561,16 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
||||||
TAILQ_INIT(&conn->imc_crypto_frames);
|
TAILQ_INIT(&conn->imc_crypto_frames);
|
||||||
if (odcid)
|
if (odcid)
|
||||||
imico_peer_addr_validated(conn, "odcid");
|
imico_peer_addr_validated(conn, "odcid");
|
||||||
|
#if LSQUIC_DEVEL
|
||||||
|
{
|
||||||
|
const char *const s = getenv("LSQUIC_LOSE_0RTT");
|
||||||
|
if (s && atoi(s))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("will lose 0-RTT packets (via env variable)");
|
||||||
|
conn->imc_delayed_packets_count = UCHAR_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
|
LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
|
||||||
conn, conn->imc_path.np_pack_size);
|
conn, conn->imc_path.np_pack_size);
|
||||||
|
|
|
@ -2163,11 +2163,11 @@ ietf_v1_parse_datagram_frame (const unsigned char *buf, size_t buf_len,
|
||||||
if (buf[0] & 1)
|
if (buf[0] & 1)
|
||||||
{
|
{
|
||||||
s = vint_read(buf + 1, buf + buf_len, &len);
|
s = vint_read(buf + 1, buf + buf_len, &len);
|
||||||
if (s > 0 && 1 + s + len >= buf_len)
|
if (s > 0 && 1 + s + len <= buf_len)
|
||||||
{
|
{
|
||||||
*data = buf + 1 + s;
|
*data = buf + 1 + s;
|
||||||
*data_len = len;
|
*data_len = len;
|
||||||
return 1 + buf_len + len;
|
return 1 + s + len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -338,6 +338,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
|
||||||
TAILQ_INIT(&ctl->sc_unacked_packets[PNS_HSK]);
|
TAILQ_INIT(&ctl->sc_unacked_packets[PNS_HSK]);
|
||||||
TAILQ_INIT(&ctl->sc_unacked_packets[PNS_APP]);
|
TAILQ_INIT(&ctl->sc_unacked_packets[PNS_APP]);
|
||||||
TAILQ_INIT(&ctl->sc_lost_packets);
|
TAILQ_INIT(&ctl->sc_lost_packets);
|
||||||
|
TAILQ_INIT(&ctl->sc_0rtt_stash);
|
||||||
ctl->sc_enpub = enpub;
|
ctl->sc_enpub = enpub;
|
||||||
ctl->sc_alset = alset;
|
ctl->sc_alset = alset;
|
||||||
ctl->sc_ver_neg = ver_neg;
|
ctl->sc_ver_neg = ver_neg;
|
||||||
|
@ -1463,6 +1464,11 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
|
||||||
packet_out->po_flags &= ~PO_LOST;
|
packet_out->po_flags &= ~PO_LOST;
|
||||||
send_ctl_destroy_packet(ctl, packet_out);
|
send_ctl_destroy_packet(ctl, packet_out);
|
||||||
}
|
}
|
||||||
|
while ((packet_out = TAILQ_FIRST(&ctl->sc_0rtt_stash)))
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&ctl->sc_0rtt_stash, packet_out, po_next);
|
||||||
|
send_ctl_destroy_packet(ctl, packet_out);
|
||||||
|
}
|
||||||
for (n = 0; n < sizeof(ctl->sc_buffered_packets) /
|
for (n = 0; n < sizeof(ctl->sc_buffered_packets) /
|
||||||
sizeof(ctl->sc_buffered_packets[0]); ++n)
|
sizeof(ctl->sc_buffered_packets[0]); ++n)
|
||||||
{
|
{
|
||||||
|
@ -3795,3 +3801,72 @@ lsquic_send_ctl_rollback (struct lsquic_send_ctl *ctl,
|
||||||
if (buffered && (lost_types & QUIC_FTBIT_ACK))
|
if (buffered && (lost_types & QUIC_FTBIT_ACK))
|
||||||
lconn->cn_if->ci_ack_rollback(lconn, &ctl_state->ack_state);
|
lconn->cn_if->ci_ack_rollback(lconn, &ctl_state->ack_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Find 0-RTT packets and change them to 1-RTT packets */
|
||||||
|
void
|
||||||
|
lsquic_send_ctl_0rtt_to_1rtt (struct lsquic_send_ctl *ctl)
|
||||||
|
{
|
||||||
|
struct lsquic_packet_out *packet_out;
|
||||||
|
unsigned count;
|
||||||
|
struct lsquic_packets_tailq *const *q;
|
||||||
|
struct lsquic_packets_tailq *const queues[] = {
|
||||||
|
&ctl->sc_scheduled_packets,
|
||||||
|
&ctl->sc_unacked_packets[PNS_APP],
|
||||||
|
&ctl->sc_lost_packets,
|
||||||
|
&ctl->sc_buffered_packets[0].bpq_packets,
|
||||||
|
&ctl->sc_buffered_packets[1].bpq_packets,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(ctl->sc_flags & SC_IETF);
|
||||||
|
|
||||||
|
while (packet_out = TAILQ_FIRST(&ctl->sc_0rtt_stash), packet_out != NULL)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&ctl->sc_0rtt_stash, packet_out, po_next);
|
||||||
|
TAILQ_INSERT_TAIL(&ctl->sc_lost_packets, packet_out, po_next);
|
||||||
|
packet_out->po_flags |= PO_LOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (q = queues; q < queues + sizeof(queues) / sizeof(queues[0]); ++q)
|
||||||
|
TAILQ_FOREACH(packet_out, *q, po_next)
|
||||||
|
if (packet_out->po_header_type == HETY_0RTT)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
packet_out->po_header_type = HETY_NOT_SET;
|
||||||
|
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||||
|
send_ctl_return_enc_data(ctl, packet_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
LSQ_DEBUG("handshake ok: changed %u packet%.*s from 0-RTT to 1-RTT",
|
||||||
|
count, count != 1, "s");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove 0-RTT packets from the unacked queue and wait to retransmit them
|
||||||
|
* after handshake succeeds. This is the most common case. There could
|
||||||
|
* (theoretically) be some corner cases where 0-RTT packets are in the
|
||||||
|
* scheduled queue, but we let those be lost naturally if that occurs.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lsquic_send_ctl_stash_0rtt_packets (struct lsquic_send_ctl *ctl)
|
||||||
|
{
|
||||||
|
struct lsquic_packet_out *packet_out, *next;
|
||||||
|
unsigned count, packet_sz;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets[PNS_APP]);
|
||||||
|
packet_out; packet_out = next)
|
||||||
|
{
|
||||||
|
next = TAILQ_NEXT(packet_out, po_next);
|
||||||
|
if (packet_out->po_header_type == HETY_0RTT)
|
||||||
|
{
|
||||||
|
packet_sz = packet_out_sent_sz(packet_out);
|
||||||
|
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
|
||||||
|
TAILQ_INSERT_TAIL(&ctl->sc_0rtt_stash, packet_out, po_next);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LSQ_DEBUG("stashed %u 0-RTT packet%.*s", count, count != 1, "s");
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ typedef struct lsquic_send_ctl {
|
||||||
|
|
||||||
/* Second section: everything else. */
|
/* Second section: everything else. */
|
||||||
struct lsquic_packets_tailq sc_scheduled_packets,
|
struct lsquic_packets_tailq sc_scheduled_packets,
|
||||||
|
sc_0rtt_stash,
|
||||||
sc_lost_packets;
|
sc_lost_packets;
|
||||||
struct buf_packet_q sc_buffered_packets[BPT_OTHER_PRIO + 1];
|
struct buf_packet_q sc_buffered_packets[BPT_OTHER_PRIO + 1];
|
||||||
const struct ver_neg *sc_ver_neg;
|
const struct ver_neg *sc_ver_neg;
|
||||||
|
@ -431,4 +432,10 @@ void
|
||||||
lsquic_send_ctl_rollback (struct lsquic_send_ctl *, struct send_ctl_state *,
|
lsquic_send_ctl_rollback (struct lsquic_send_ctl *, struct send_ctl_state *,
|
||||||
const struct iovec *, size_t);
|
const struct iovec *, size_t);
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_send_ctl_0rtt_to_1rtt (struct lsquic_send_ctl *);
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_send_ctl_stash_0rtt_packets (struct lsquic_send_ctl *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -373,6 +373,39 @@ stream_is_hsk (const struct lsquic_stream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function's only job is to change the allocated packet's header
|
||||||
|
* type to HETY_0RTT when stream frames are written before handshake
|
||||||
|
* is complete.
|
||||||
|
*/
|
||||||
|
static struct lsquic_packet_out *
|
||||||
|
stream_get_packet_for_stream_0rtt (struct lsquic_send_ctl *ctl,
|
||||||
|
unsigned need_at_least, const struct network_path *path,
|
||||||
|
const struct lsquic_stream *stream)
|
||||||
|
{
|
||||||
|
struct lsquic_packet_out *packet_out;
|
||||||
|
|
||||||
|
if (stream->conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("switch to regular \"get packet for stream\" function");
|
||||||
|
/* Here we drop the "const" because this is a static function.
|
||||||
|
* Otherwise, we would not condone such sorcery.
|
||||||
|
*/
|
||||||
|
((struct lsquic_stream *) stream)->sm_get_packet_for_stream
|
||||||
|
= lsquic_send_ctl_get_packet_for_stream;
|
||||||
|
return lsquic_send_ctl_get_packet_for_stream(ctl, need_at_least,
|
||||||
|
path, stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet_out = lsquic_send_ctl_get_packet_for_stream(ctl, need_at_least,
|
||||||
|
path, stream);
|
||||||
|
if (packet_out)
|
||||||
|
packet_out->po_header_type = HETY_0RTT;
|
||||||
|
return packet_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct lsquic_stream *
|
static struct lsquic_stream *
|
||||||
stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
|
stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
|
||||||
const struct lsquic_stream_if *stream_if, void *stream_if_ctx,
|
const struct lsquic_stream_if *stream_if, void *stream_if_ctx,
|
||||||
|
@ -405,6 +438,7 @@ stream_new_common (lsquic_stream_id_t id, struct lsquic_conn_public *conn_pub,
|
||||||
stream->sm_bflags |= ctor_flags & ((1 << N_SMBF_FLAGS) - 1);
|
stream->sm_bflags |= ctor_flags & ((1 << N_SMBF_FLAGS) - 1);
|
||||||
if (conn_pub->lconn->cn_flags & LSCONN_SERVER)
|
if (conn_pub->lconn->cn_flags & LSCONN_SERVER)
|
||||||
stream->sm_bflags |= SMBF_SERVER;
|
stream->sm_bflags |= SMBF_SERVER;
|
||||||
|
stream->sm_get_packet_for_stream = lsquic_send_ctl_get_packet_for_stream;
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -479,6 +513,13 @@ lsquic_stream_new (lsquic_stream_id_t id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((stream->sm_bflags & (SMBF_SERVER|SMBF_IETF)) == SMBF_IETF
|
||||||
|
&& !(conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE))
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("use wrapper \"get packet for stream\" function");
|
||||||
|
stream->sm_get_packet_for_stream = stream_get_packet_for_stream_0rtt;
|
||||||
|
}
|
||||||
|
|
||||||
lsquic_sfcw_init(&stream->fc, initial_window, cfcw, conn_pub, id);
|
lsquic_sfcw_init(&stream->fc, initial_window, cfcw, conn_pub, id);
|
||||||
stream->max_send_off = initial_send_off;
|
stream->max_send_off = initial_send_off;
|
||||||
LSQ_DEBUG("created stream");
|
LSQ_DEBUG("created stream");
|
||||||
|
@ -584,6 +625,14 @@ drop_buffered_data (struct lsquic_stream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_stream_drop_hset_ref (struct lsquic_stream *stream)
|
||||||
|
{
|
||||||
|
if (stream->uh)
|
||||||
|
stream->uh->uh_hset = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_uh (struct lsquic_stream *stream)
|
destroy_uh (struct lsquic_stream *stream)
|
||||||
{
|
{
|
||||||
|
@ -3087,7 +3136,7 @@ stream_write_to_packet_std (struct frame_gen_ctx *fg_ctx, const size_t size)
|
||||||
else
|
else
|
||||||
need_at_least += size > 0;
|
need_at_least += size > 0;
|
||||||
get_packet:
|
get_packet:
|
||||||
packet_out = lsquic_send_ctl_get_packet_for_stream(send_ctl,
|
packet_out = stream->sm_get_packet_for_stream(send_ctl,
|
||||||
need_at_least, stream->conn_pub->path, stream);
|
need_at_least, stream->conn_pub->path, stream);
|
||||||
if (packet_out)
|
if (packet_out)
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,9 @@ struct data_frame;
|
||||||
enum quic_frame_type;
|
enum quic_frame_type;
|
||||||
struct push_promise;
|
struct push_promise;
|
||||||
union hblock_ctx;
|
union hblock_ctx;
|
||||||
|
struct lsquic_packet_out;
|
||||||
|
struct lsquic_send_ctl;
|
||||||
|
struct network_path;
|
||||||
|
|
||||||
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
|
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
|
||||||
|
|
||||||
|
@ -311,6 +314,11 @@ struct lsquic_stream
|
||||||
size_t (*sm_write_avail)(struct lsquic_stream *);
|
size_t (*sm_write_avail)(struct lsquic_stream *);
|
||||||
int (*sm_readable)(struct lsquic_stream *);
|
int (*sm_readable)(struct lsquic_stream *);
|
||||||
|
|
||||||
|
struct lsquic_packet_out * (*sm_get_packet_for_stream)(
|
||||||
|
struct lsquic_send_ctl *,
|
||||||
|
unsigned, const struct network_path *,
|
||||||
|
const struct lsquic_stream *);
|
||||||
|
|
||||||
/* This element is optional */
|
/* This element is optional */
|
||||||
const struct stream_filter_if *sm_sfi;
|
const struct stream_filter_if *sm_sfi;
|
||||||
|
|
||||||
|
@ -622,4 +630,7 @@ void
|
||||||
lsquic_stream_set_pwritev_params (unsigned iovecs, unsigned frames);
|
lsquic_stream_set_pwritev_params (unsigned iovecs, unsigned frames);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_stream_drop_hset_ref (struct lsquic_stream *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -184,4 +184,26 @@ size_t
|
||||||
lsquic_tp_get_quantum_sz (void);
|
lsquic_tp_get_quantum_sz (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SERVER_0RTT_TPS (0 \
|
||||||
|
/* [draft-ietf-quic-transport-31] Section 7.4.1: */ \
|
||||||
|
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT) \
|
||||||
|
| (1 << TPI_INIT_MAX_DATA) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_UNI) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAMS_BIDI) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE) \
|
||||||
|
| (1 << TPI_INIT_MAX_STREAM_DATA_UNI) \
|
||||||
|
| (1 << TPI_MAX_IDLE_TIMEOUT) \
|
||||||
|
| (1 << TPI_MAX_UDP_PAYLOAD_SIZE) \
|
||||||
|
| (1 << TPI_DISABLE_ACTIVE_MIGRATION) \
|
||||||
|
/* Not including TPI_LOSS_BITS, see */ \
|
||||||
|
/* draft-ferrieuxhamchaoui-quic-lossbits-03, Section 5.1 */ \
|
||||||
|
/* [draft-ietf-quic-datagram-01] Section 3: */ \
|
||||||
|
| (1 << TPI_MAX_DATAGRAM_FRAME_SIZE) \
|
||||||
|
/* [draft-iyengar-quic-delayed-ack-01] does not specfiy, store: */ \
|
||||||
|
| (1 << TPI_MIN_ACK_DELAY) \
|
||||||
|
/* [draft-huitema-quic-ts-03] does not specfiy, store: */ \
|
||||||
|
| (1 << TPI_TIMESTAMPS) \
|
||||||
|
)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue