Release 2.12.0

- [FEATURE] QUIC timestamps extension.
- [API] New: ea_alpn that is used when not in HTTP mode.
- [BUGFIX] SNI is mandatory only for HTTP/3 and gQUIC.
- [BUGFIX] Benign double-free -- issue #110.
- [BUGFIX] Printing of transport parameters.
This commit is contained in:
Dmitri Tikhonov 2020-03-02 08:53:41 -05:00
parent fa4561dcea
commit afe3d36359
24 changed files with 279 additions and 34 deletions

View file

@ -558,6 +558,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
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_set |= 1 << TPI_TIMESTAMPS;
len = (enc_sess->esi_conn->cn_version == LSQVER_ID25 ? lsquic_tp_encode_id25 :
lsquic_tp_encode)(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
@ -1035,8 +1037,10 @@ iquic_lookup_cert (SSL *ssl, void *arg)
#endif
if (!server_name)
{
LSQ_DEBUG("cert lookup: server name is not set, skip");
return 1;
LSQ_DEBUG("cert lookup: server name is not set");
/* SNI is required in HTTP/3 */
if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
return 1;
}
path = enc_sess->esi_conn->cn_if->ci_get_path(enc_sess->esi_conn, NULL);
@ -1049,7 +1053,8 @@ iquic_lookup_cert (SSL *ssl, void *arg)
{
if (SSL_set_SSL_CTX(enc_sess->esi_ssl, ssl_ctx))
{
LSQ_DEBUG("looked up cert for %s", server_name);
LSQ_DEBUG("looked up cert for %s", server_name
? server_name : "<no SNI>");
if (enc_sess->esi_enpub->enp_kli)
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
SSL_set_verify(enc_sess->esi_ssl,
@ -1070,7 +1075,8 @@ iquic_lookup_cert (SSL *ssl, void *arg)
}
else
{
LSQ_DEBUG("could not look up cert for %s", server_name);
LSQ_DEBUG("could not look up cert for %s", server_name
? server_name : "<no SNI>");
return 0;
}
}

View file

@ -335,6 +335,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
settings->es_ql_bits = LSQUIC_DF_QL_BITS;
settings->es_spin = LSQUIC_DF_SPIN;
settings->es_delayed_acks = LSQUIC_DF_DELAYED_ACKS;
settings->es_timestamps = LSQUIC_DF_TIMESTAMPS;
}
@ -1636,7 +1637,7 @@ remove_conn_from_hash (lsquic_engine_t *engine, lsquic_conn_t *conn)
static void
refflags2str (enum lsquic_conn_flags flags, char s[6])
refflags2str (enum lsquic_conn_flags flags, char s[7])
{
*s = 'C'; s += !!(flags & LSCONN_CLOSING);
*s = 'H'; s += !!(flags & LSCONN_HASHED);

View file

@ -133,6 +133,7 @@ enum ifull_conn_flags
IFC_MIGRA = 1 << 27,
IFC_SPIN = 1 << 28, /* Spin bits are enabled */
IFC_DELAYED_ACKS = 1 << 29, /* Delayed ACKs are enabled */
IFC_TIMESTAMPS = 1 << 30, /* Timestamps are enabled */
};
@ -334,6 +335,7 @@ struct ietf_full_conn
struct transport_params ifc_peer_param;
STAILQ_HEAD(, stream_id_to_ss)
ifc_stream_ids_to_ss;
lsquic_time_t ifc_created;
lsquic_time_t ifc_saved_ack_received;
lsquic_packno_t ifc_max_ack_packno[N_PNS];
lsquic_packno_t ifc_max_non_probing;
@ -1215,6 +1217,7 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
LSQ_DEBUG("negotiating version %s",
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
conn->ifc_process_incoming_packet = process_incoming_packet_verneg;
conn->ifc_created = now;
LSQ_DEBUG("logging using %s SCID",
LSQUIC_LOG_CONN_ID == CN_SCID(&conn->ifc_conn) ? "client" : "server");
return &conn->ifc_conn;
@ -1431,6 +1434,7 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
if (0 != handshake_ok(&conn->ifc_conn))
goto err3;
conn->ifc_created = imc->imc_created;
if (conn->ifc_idle_to)
lsquic_alarmset_set(&conn->ifc_alset, AL_IDLE,
imc->imc_created + conn->ifc_idle_to);
@ -1506,6 +1510,33 @@ ietf_full_conn_ci_cancel_pending_streams (struct lsquic_conn *lconn, unsigned n)
}
/* Best effort. If timestamp frame does not fit, oh well */
static void
generate_timestamp_frame (struct ietf_full_conn *conn,
struct lsquic_packet_out *packet_out, lsquic_time_t now)
{
uint64_t timestamp;
int w;
timestamp = (now - conn->ifc_created) >> TP_DEF_ACK_DELAY_EXP;
w = conn->ifc_conn.cn_pf->pf_gen_timestamp_frame(
packet_out->po_data + packet_out->po_data_sz,
lsquic_packet_out_avail(packet_out), timestamp);
if (w < 0)
{
LSQ_DEBUG("could not generate TIMESTAMP frame");
return;
}
LSQ_DEBUG("generated TIMESTAMP(%"PRIu64" us) frame",
timestamp << TP_DEF_ACK_DELAY_EXP);
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated TIMESTAMP(%"
PRIu64" us) frame", timestamp << TP_DEF_ACK_DELAY_EXP);
packet_out->po_frame_types |= 1 << QUIC_FRAME_TIMESTAMP;
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w);
packet_out->po_regen_sz += w;
}
static int
generate_ack_frame_for_pns (struct ietf_full_conn *conn,
struct lsquic_packet_out *packet_out, enum packnum_space pns,
@ -1561,6 +1592,9 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
lsquic_send_ctl_sanity_check(&conn->ifc_send_ctl);
LSQ_DEBUG("%s ACK state reset", lsquic_pns2str[pns]);
if (pns == PNS_APP && (conn->ifc_flags & IFC_TIMESTAMPS))
generate_timestamp_frame(conn, packet_out, now);
return 0;
}
@ -3013,6 +3047,12 @@ handshake_ok (struct lsquic_conn *lconn)
LSQ_DEBUG("delayed ACKs enabled");
conn->ifc_flags |= IFC_DELAYED_ACKS;
}
if (conn->ifc_settings->es_timestamps
&& (params->tp_set & (1 << TPI_TIMESTAMPS)))
{
LSQ_DEBUG("timestamps enabled");
conn->ifc_flags |= IFC_TIMESTAMPS;
}
conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000;
@ -5583,6 +5623,36 @@ process_ack_frequency_frame (struct ietf_full_conn *conn,
}
static unsigned
process_timestamp_frame (struct ietf_full_conn *conn,
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
{
uint64_t timestamp;
int parsed_len;
if (!(conn->ifc_flags & IFC_TIMESTAMPS))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"Received unexpected TIMESTAMP frame (not negotiated)");
return 0;
}
parsed_len = conn->ifc_conn.cn_pf->pf_parse_timestamp_frame(p, len,
&timestamp);
if (parsed_len < 0)
return 0;
timestamp <<= conn->ifc_cfg.ack_exp;
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "TIMESTAMP(%"PRIu64" us)", timestamp);
LSQ_DEBUG("TIMESTAMP(%"PRIu64" us) (%"PRIu64" << %"PRIu8")", timestamp,
timestamp >> conn->ifc_cfg.ack_exp, conn->ifc_cfg.ack_exp);
/* We don't do anything with the timestamp */
return parsed_len;
}
typedef unsigned (*process_frame_f)(
struct ietf_full_conn *, struct lsquic_packet_in *,
const unsigned char *p, size_t);
@ -5611,6 +5681,7 @@ static process_frame_f const process_frames[N_QUIC_FRAMES] =
[QUIC_FRAME_CRYPTO] = process_crypto_frame,
[QUIC_FRAME_HANDSHAKE_DONE] = process_handshake_done_frame,
[QUIC_FRAME_ACK_FREQUENCY] = process_ack_frequency_frame,
[QUIC_FRAME_TIMESTAMP] = process_timestamp_frame,
};

View file

@ -1049,6 +1049,8 @@ static unsigned (*const imico_process_frames[N_QUIC_FRAMES])
/* STREAM frame can only come in the App PNS and we delay those packets: */
[QUIC_FRAME_STREAM] = imico_process_invalid_frame,
[QUIC_FRAME_HANDSHAKE_DONE] = imico_process_invalid_frame,
[QUIC_FRAME_ACK_FREQUENCY] = imico_process_invalid_frame,
[QUIC_FRAME_TIMESTAMP] = imico_process_invalid_frame,
};

View file

@ -384,8 +384,6 @@ lsquic_mm_put_packet_out (struct lsquic_mm *mm,
poolst_freed(&mm->packet_out_bstats[idx]);
if (poolst_has_new_sample(&mm->packet_out_bstats[idx]))
maybe_shrink_packet_out_bufs(mm, idx);
if (packet_out->po_bwp_state)
lsquic_malo_put(packet_out->po_bwp_state);
#else
free(packet_out->po_data);
#endif

View file

@ -35,6 +35,7 @@ enum quic_frame_type
QUIC_FRAME_NEW_TOKEN, /* I */
QUIC_FRAME_HANDSHAKE_DONE, /* I */
QUIC_FRAME_ACK_FREQUENCY, /* I */
QUIC_FRAME_TIMESTAMP, /* I */
N_QUIC_FRAMES
};
@ -64,6 +65,7 @@ enum quic_ft_bit {
QUIC_FTBIT_RETIRE_CONNECTION_ID = 1 << QUIC_FRAME_RETIRE_CONNECTION_ID,
QUIC_FTBIT_HANDSHAKE_DONE = 1 << QUIC_FRAME_HANDSHAKE_DONE,
QUIC_FTBIT_ACK_FREQUENCY = 1 << QUIC_FRAME_ACK_FREQUENCY,
QUIC_FTBIT_TIMESTAMP = 1 << QUIC_FRAME_TIMESTAMP,
};
static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
@ -92,6 +94,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
[QUIC_FRAME_RETIRE_CONNECTION_ID] = "QUIC_FRAME_RETIRE_CONNECTION_ID",
[QUIC_FRAME_HANDSHAKE_DONE] = "QUIC_FRAME_HANDSHAKE_DONE",
[QUIC_FRAME_ACK_FREQUENCY] = "QUIC_FRAME_ACK_FREQUENCY",
[QUIC_FRAME_TIMESTAMP] = "QUIC_FRAME_TIMESTAMP",
};
#define QUIC_FRAME_PRELEN (sizeof("QUIC_FRAME_"))
@ -128,6 +131,7 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
QUIC_FRAME_SLEN(QUIC_FRAME_NEW_TOKEN) + 1 + \
QUIC_FRAME_SLEN(QUIC_FRAME_HANDSHAKE_DONE) + 1 + \
QUIC_FRAME_SLEN(QUIC_FRAME_ACK_FREQUENCY) + 1 + \
QUIC_FRAME_SLEN(QUIC_FRAME_TIMESTAMP) + 1 + \
0
@ -217,6 +221,7 @@ extern const char *const lsquic_pns2str[];
| QUIC_FTBIT_NEW_TOKEN \
| QUIC_FTBIT_HANDSHAKE_DONE \
| QUIC_FTBIT_ACK_FREQUENCY \
| QUIC_FTBIT_TIMESTAMP \
| QUIC_FTBIT_CRYPTO )
/* [draft-ietf-quic-transport-24] Section 1.2 */
@ -231,7 +236,7 @@ extern const char *const lsquic_pns2str[];
*/
#define IQUIC_FRAME_RETX_MASK ( \
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK))
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP))
extern const enum quic_ft_bit lsquic_legal_frames_by_level[];

View file

@ -18,7 +18,7 @@ enum PACKET_PUBLIC_FLAGS
#define GQUIC_FRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \
| (1 << QUIC_FRAME_PATH_CHALLENGE) | (1 << QUIC_FRAME_PATH_RESPONSE) \
| (1 << QUIC_FRAME_STOP_WAITING))
| (1 << QUIC_FRAME_STOP_WAITING) | (1 << QUIC_FRAME_TIMESTAMP))
#define GQUIC_FRAME_REGENERATE(frame_type) ((1 << (frame_type)) & GQUIC_FRAME_REGEN_MASK)

View file

@ -310,6 +310,10 @@ struct parse_funcs
unsigned
(*pf_ack_frequency_frame_size) (uint64_t seqno, uint64_t pack_tol,
uint64_t upd_mad);
int
(*pf_gen_timestamp_frame) (unsigned char *buf, size_t buf_len, uint64_t);
int
(*pf_parse_timestamp_frame) (const unsigned char *buf, size_t, uint64_t *);
};

View file

@ -243,5 +243,7 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] =
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN,
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
| QUIC_FTBIT_TIMESTAMP
,
};

View file

@ -46,6 +46,9 @@
#define CHECK_SPACE(need, pstart, pend) \
do { if ((intptr_t) (need) > ((pend) - (pstart))) { return -1; } } while (0)
#define FRAME_TYPE_ACK_FREQUENCY 0xAF
#define FRAME_TYPE_TIMESTAMP 0x2F5
static int
ietf_v1_gen_one_varint (unsigned char *, size_t, unsigned char, uint64_t);
@ -1109,7 +1112,8 @@ ietf_v1_parse_frame_type (const unsigned char *buf, size_t len)
if (s > 0 && (unsigned) s == (1u << vint_val2bits(val)))
switch (val)
{
case 0xAF: return QUIC_FRAME_ACK_FREQUENCY;
case FRAME_TYPE_ACK_FREQUENCY: return QUIC_FRAME_ACK_FREQUENCY;
case FRAME_TYPE_TIMESTAMP: return QUIC_FRAME_TIMESTAMP;
default: break;
}
@ -2059,7 +2063,7 @@ ietf_v1_gen_ack_frequency_frame (unsigned char *buf, size_t buf_len,
uint64_t seqno, uint64_t pack_tol, uint64_t upd_mad)
{
return ietf_v1_gen_frame_with_varints(buf, buf_len, 4,
(uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad });
(uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad });
}
@ -2068,7 +2072,8 @@ ietf_v1_parse_ack_frequency_frame (const unsigned char *buf, size_t buf_len,
uint64_t *seqno, uint64_t *pack_tol, uint64_t *upd_mad)
{
return ietf_v1_parse_frame_with_varints(buf, buf_len,
0xAF, 3, (uint64_t *[]) { seqno, pack_tol, upd_mad });
FRAME_TYPE_ACK_FREQUENCY,
3, (uint64_t *[]) { seqno, pack_tol, upd_mad });
}
@ -2077,7 +2082,7 @@ ietf_v1_ack_frequency_frame_size (uint64_t seqno, uint64_t pack_tol,
uint64_t upd_mad)
{
return ietf_v1_frame_with_varints_size(4,
(uint64_t[]){ 0xAF, seqno, pack_tol, upd_mad });
(uint64_t[]){ FRAME_TYPE_ACK_FREQUENCY, seqno, pack_tol, upd_mad });
}
@ -2088,6 +2093,24 @@ ietf_v1_handshake_done_frame_size (void)
}
static int
ietf_v1_gen_timestamp_frame (unsigned char *buf, size_t buf_len,
uint64_t timestamp)
{
return ietf_v1_gen_frame_with_varints(buf, buf_len, 2,
(uint64_t[]){ FRAME_TYPE_TIMESTAMP, timestamp });
}
static int
ietf_v1_parse_timestamp_frame (const unsigned char *buf, size_t buf_len,
uint64_t *timestamp)
{
return ietf_v1_parse_frame_with_varints(buf, buf_len,
FRAME_TYPE_TIMESTAMP, 1, (uint64_t *[]) { timestamp });
}
const struct parse_funcs lsquic_parse_funcs_ietf_v1 =
{
.pf_gen_reg_pkt_header = ietf_v1_gen_reg_pkt_header,
@ -2156,4 +2179,6 @@ const struct parse_funcs lsquic_parse_funcs_ietf_v1 =
.pf_gen_ack_frequency_frame = ietf_v1_gen_ack_frequency_frame,
.pf_parse_ack_frequency_frame = ietf_v1_parse_ack_frequency_frame,
.pf_ack_frequency_frame_size = ietf_v1_ack_frequency_frame_size,
.pf_gen_timestamp_frame = ietf_v1_gen_timestamp_frame,
.pf_parse_timestamp_frame = ietf_v1_parse_timestamp_frame,
};

View file

@ -52,6 +52,7 @@ tpi_val_2_enum (uint64_t tpi_val)
#endif
case 0x1057: return TPI_LOSS_BITS;
case 0xDE1A: return TPI_MIN_ACK_DELAY;
case 0x7157: return TPI_TIMESTAMPS;
default: return INT_MAX;
}
}
@ -79,6 +80,7 @@ static const unsigned enum_2_tpi_val[LAST_TPI + 1] =
#endif
[TPI_LOSS_BITS] = 0x1057,
[TPI_MIN_ACK_DELAY] = 0xDE1A,
[TPI_TIMESTAMPS] = 0x7157,
};
@ -104,6 +106,7 @@ static const char * const tpi2str[LAST_TPI + 1] =
#endif
[TPI_LOSS_BITS] = "loss_bits",
[TPI_MIN_ACK_DELAY] = "min_ack_delay",
[TPI_TIMESTAMPS] = "timestamps",
};
@ -378,6 +381,7 @@ lsquic_tp_encode (const struct transport_params *params, int is_server,
sizeof(params->tp_preferred_address.srst));
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
case TPI_TIMESTAMPS:
*p++ = 0;
break;
#if LSQUIC_TEST_QUANTUM_READINESS
@ -500,6 +504,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
}
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
case TPI_TIMESTAMPS:
EXPECT_LEN(0);
break;
case TPI_STATELESS_RESET_TOKEN:
@ -615,7 +620,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
return;
}
for (; tpi <= MAX_EMPTY_TPI; ++tpi)
if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
if (params->tp_set & (1 << tpi))
{
nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[tpi]);
@ -825,6 +830,7 @@ lsquic_tp_encode_id25 (const struct transport_params *params, int is_server,
sizeof(params->tp_preferred_address.srst));
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
case TPI_TIMESTAMPS:
WRITE_UINT_TO_P(0, 16);
break;
#if LSQUIC_TEST_QUANTUM_READINESS
@ -948,6 +954,7 @@ lsquic_tp_decode_id25 (const unsigned char *const buf, size_t bufsz,
}
break;
case TPI_DISABLE_ACTIVE_MIGRATION:
case TPI_TIMESTAMPS:
EXPECT_LEN(0);
break;
case TPI_STATELESS_RESET_TOKEN:

View file

@ -38,6 +38,7 @@ enum transport_param_id
/*
* Empty transport parameters:
*/
TPI_TIMESTAMPS,
TPI_DISABLE_ACTIVE_MIGRATION, MAX_EMPTY_TPI = TPI_DISABLE_ACTIVE_MIGRATION,
/*