Release 2.15.0

- [FEATURE] QUIC and HTTP/3 Internet Draft 28 support.
- [BUGFIX] Ignore Retry packets after other packets are decrypted
  successfully.
- [BUGFIX] Transport parameter decoding: CID no longer has 4-byte
  length minimum.
- http_client: fix and optimize lsxpack_header allocator.
- Drop support for Internet Draft 25.
This commit is contained in:
Dmitri Tikhonov 2020-05-27 10:26:32 -04:00
parent 4d221313f7
commit fb73393fef
33 changed files with 1124 additions and 631 deletions

View file

@ -33,6 +33,8 @@ enum alarm_id {
AL_PATH_CHAL,
AL_PATH_CHAL_0 = AL_PATH_CHAL,
AL_PATH_CHAL_1,
AL_PATH_CHAL_2,
AL_PATH_CHAL_3,
AL_SESS_TICKET,
AL_BLOCKED_KA, /* Blocked Keep-Alive */
MAX_LSQUIC_ALARMS
@ -51,6 +53,8 @@ enum alarm_id_bit {
ALBIT_CID_THROT = 1 << AL_CID_THROT,
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1,
ALBIT_PATH_CHAL_2 = 1 << AL_PATH_CHAL_2,
ALBIT_PATH_CHAL_3 = 1 << AL_PATH_CHAL_3,
ALBIT_SESS_TICKET = 1 << AL_SESS_TICKET,
ALBIT_BLOCKED_KA = 1 << AL_BLOCKED_KA,
};

View file

@ -243,6 +243,10 @@ struct conn_iface
/* Optional method. Only used by the IETF client code. */
void
(*ci_drop_crypto_streams) (struct lsquic_conn *);
/* Optional method. Only used by IETF connections */
void
(*ci_count_garbage) (struct lsquic_conn *, size_t);
};
#define LSCONN_CCE_BITS 3

View file

@ -276,6 +276,9 @@ struct enc_session_funcs_iquic
(*esfi_reset_dcid) (enc_session_t *, const struct lsquic_cid *,
const struct lsquic_cid *);
void
(*esfi_set_iscid) (enc_session_t *, const struct lsquic_packet_in *);
int
(*esfi_init_server) (enc_session_t *);
@ -288,7 +291,8 @@ struct enc_session_funcs_iquic
const struct lsquic_cid *,
void *(crypto_streams)[4],
const struct crypto_stream_if *,
const struct lsquic_cid *odcid);
const struct lsquic_cid *odcid,
const struct lsquic_cid *iscid );
void
(*esfi_shake_stream)(enc_session_t *, struct lsquic_stream *,
@ -328,8 +332,8 @@ struct enc_session_funcs_gquic lsquic_enc_session_gquic_gquic_1;
extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
#define select_esf_common_by_ver(ver) ( \
ver == LSQVER_ID25 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID28 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
&lsquic_enc_session_common_gquic_1 )

View file

@ -71,9 +71,9 @@ static const struct alpn_map {
enum lsquic_version version;
const unsigned char *alpn;
} s_h3_alpns[] = {
{ LSQVER_ID25, (unsigned char *) "\x05h3-25", },
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-27", },
{ LSQVER_ID28, (unsigned char *) "\x05h3-28", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-28", },
};
struct enc_sess_iquic;
@ -221,6 +221,8 @@ struct enc_sess_iquic
struct header_prot *esi_hsk_hps;
lsquic_packno_t esi_max_packno[N_PNS];
lsquic_cid_t esi_odcid;
lsquic_cid_t esi_rscid; /* Retry SCID */
lsquic_cid_t esi_iscid; /* Initial SCID */
unsigned esi_key_phase;
enum {
ESI_INITIALIZED = 1 << 0,
@ -237,6 +239,9 @@ struct enc_sess_iquic
ESI_WANT_TICKET = 1 << 11,
ESI_RECV_QL_BITS = 1 << 12,
ESI_SEND_QL_BITS = 1 << 13,
ESI_RSCID = 1 << 14,
ESI_ISCID = 1 << 15,
ESI_RETRY = 1 << 16, /* Connection was retried */
} esi_flags;
enum evp_aead_direction_t
esi_dir[2]; /* client, server */
@ -429,9 +434,15 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
const struct lsquic_engine_settings *const settings =
&enc_sess->esi_enpub->enp_settings;
struct transport_params params;
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
int len;
memset(&params, 0, sizeof(params));
if (version > LSQVER_ID27)
{
params.tp_initial_source_cid = *CN_SCID(enc_sess->esi_conn);
params.tp_set |= 1 << TPI_INITIAL_SOURCE_CID;
}
if (enc_sess->esi_flags & ESI_SERVER)
{
const struct lsquic_conn *const lconn = enc_sess->esi_conn;
@ -442,8 +453,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
if (enc_sess->esi_flags & ESI_ODCID)
{
params.tp_original_cid = enc_sess->esi_odcid;
params.tp_set |= 1 << TPI_ORIGINAL_CONNECTION_ID;
params.tp_original_dest_cid = enc_sess->esi_odcid;
params.tp_set |= 1 << TPI_ORIGINAL_DEST_CID;
}
#if LSQUIC_PREFERRED_ADDR
char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1];
@ -544,10 +555,10 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
| (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
;
if (settings->es_max_packet_size_rx)
if (settings->es_max_udp_payload_size_rx)
{
params.tp_max_packet_size = settings->es_max_packet_size_rx;
params.tp_set |= 1 << TPI_MAX_PACKET_SIZE;
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;
@ -564,10 +575,15 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
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);
len = (version == LSQVER_ID27 ? lsquic_tp_encode_27 : lsquic_tp_encode)(
&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
if (len >= 0)
{
char str[MAX_TP_STR_SZ];
LSQ_DEBUG("generated transport parameters buffer of %d bytes", len);
LSQ_DEBUG("%s", ((version == LSQVER_ID27 ? lsquic_tp_to_str_27
: lsquic_tp_to_str)(&params, str, sizeof(str)), str));
}
else
LSQ_WARN("cannot generate transport parameters: %d", errno);
return len;
@ -726,6 +742,9 @@ iquic_esfi_create_client (const char *hostname,
enc_sess->esi_dir[0] = evp_aead_seal;
enc_sess->esi_dir[1] = evp_aead_open;
enc_sess->esi_odcid = *dcid;
enc_sess->esi_flags |= ESI_ODCID;
LSQ_DEBUGC("created client, DCID: %"CID_FMT, CID_BITS(dcid));
{
const char *log;
@ -793,7 +812,8 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
struct lsquic_conn *lconn, const lsquic_cid_t *first_dcid,
void *(crypto_streams)[4],
const struct crypto_stream_if *cryst_if,
const struct lsquic_cid *odcid)
const struct lsquic_cid *odcid,
const struct lsquic_cid *iscid )
{
struct enc_sess_iquic *enc_sess;
@ -819,6 +839,8 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
enc_sess->esi_odcid = *odcid;
enc_sess->esi_flags |= ESI_ODCID;
}
enc_sess->esi_iscid = *iscid;
enc_sess->esi_flags |= ESI_ISCID;
init_frals(enc_sess);
@ -1470,6 +1492,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
const uint8_t *params_buf;
size_t bufsz;
char *params_str;
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, &params_buf, &bufsz);
if (!params_buf)
@ -1479,8 +1502,8 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
}
LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
if (0 > (enc_sess->esi_conn->cn_version == LSQVER_ID25
? lsquic_tp_decode_id25 : lsquic_tp_decode)(params_buf, bufsz,
if (0 > (version == LSQVER_ID27 ? lsquic_tp_decode_27
: lsquic_tp_decode)(params_buf, bufsz,
!(enc_sess->esi_flags & ESI_SERVER),
trans_params))
{
@ -1501,30 +1524,70 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
return -1;
}
if ((enc_sess->esi_flags & (ESI_ODCID|ESI_SERVER)) == ESI_ODCID)
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_RETRY_SOURCE_CID)] = enc_sess->esi_flags & ESI_RSCID ? &enc_sess->esi_rscid : NULL,
[TP_CID_IDX(TPI_INITIAL_SOURCE_CID)] = enc_sess->esi_flags & ESI_ISCID ? &enc_sess->esi_iscid : NULL,
};
unsigned must_have, must_not_have = 0;
if (version > LSQVER_ID27)
{
if (!(trans_params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID)))
must_have = 1 << TPI_INITIAL_SOURCE_CID;
if (enc_sess->esi_flags & ESI_SERVER)
must_not_have |= 1 << TPI_ORIGINAL_DEST_CID;
else
must_have |= 1 << TPI_ORIGINAL_DEST_CID;
if ((enc_sess->esi_flags & (ESI_RETRY|ESI_SERVER)) == ESI_RETRY)
must_have |= 1 << TPI_RETRY_SOURCE_CID;
else
must_not_have |= 1 << TPI_RETRY_SOURCE_CID;
}
else if ((enc_sess->esi_flags & (ESI_RETRY|ESI_SERVER)) == ESI_RETRY)
must_have = 1 << TPI_ORIGINAL_DEST_CID;
enum transport_param_id tpi;
for (tpi = FIRST_TP_CID; tpi <= LAST_TP_CID; ++tpi)
{
if (!(must_have & (1 << tpi)))
continue;
if (!(trans_params->tp_set & (1 << tpi)))
{
LSQ_DEBUG("server did not produce original DCID (ODCID)");
LSQ_DEBUG("server did not produce %s", lsquic_tpi2str[tpi]);
return -1;
}
if (LSQUIC_CIDS_EQ(&enc_sess->esi_odcid,
&trans_params->tp_original_cid))
LSQ_DEBUG("ODCID values match");
if (!cids[TP_CID_IDX(tpi)])
{
LSQ_WARN("do not have CID %s for checking",
lsquic_tpi2str[tpi]);
return -1;
}
if (LSQUIC_CIDS_EQ(cids[TP_CID_IDX(tpi)],
&trans_params->tp_cids[TP_CID_IDX(tpi)]))
LSQ_DEBUG("%s values match", lsquic_tpi2str[tpi]);
else
{
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
{
char cidbuf[2][MAX_CID_LEN * 2 + 1];
lsquic_cid2str(&enc_sess->esi_odcid, cidbuf[0]);
lsquic_cid2str(&trans_params->tp_original_cid, cidbuf[1]);
LSQ_DEBUG("server provided ODCID %s that does not match "
"our ODCID %s", cidbuf[1], cidbuf[0]);
LSQ_DEBUG("server provided %s %"CID_FMT" that does not "
"match ours %"CID_FMT, lsquic_tpi2str[tpi],
CID_BITS_B(&trans_params->tp_cids[TP_CID_IDX(tpi)],
cidbuf[0]),
CID_BITS_B(cids[TP_CID_IDX(tpi)], cidbuf[1]));
}
return -1;
}
}
for (tpi = FIRST_TP_CID; tpi <= LAST_TP_CID; ++tpi)
if (must_not_have & (1 << tpi) & trans_params->tp_set)
{
LSQ_DEBUG("server transport parameters unexpectedly contain %s",
lsquic_tpi2str[tpi]);
return -1;
}
if ((trans_params->tp_set & (1 << TPI_LOSS_BITS))
&& enc_sess->esi_enpub->enp_settings.es_ql_bits)
{
@ -2239,6 +2302,21 @@ iquic_esf_zero_rtt_enabled (enc_session_t *enc_session_p)
}
static void
iquic_esfi_set_iscid (enc_session_t *enc_session_p,
const struct lsquic_packet_in *packet_in)
{
struct enc_sess_iquic *const enc_sess = enc_session_p;
if (!(enc_sess->esi_flags & ESI_ISCID))
{
lsquic_scid_from_packet_in(packet_in, &enc_sess->esi_iscid);
enc_sess->esi_flags |= ESI_ISCID;
LSQ_DEBUGC("set ISCID to %"CID_FMT, CID_BITS(&enc_sess->esi_iscid));
}
}
static int
iquic_esfi_reset_dcid (enc_session_t *enc_session_p,
const lsquic_cid_t *old_dcid, const lsquic_cid_t *new_dcid)
@ -2247,7 +2325,8 @@ iquic_esfi_reset_dcid (enc_session_t *enc_session_p,
struct crypto_ctx_pair *pair;
enc_sess->esi_odcid = *old_dcid;
enc_sess->esi_flags |= ESI_ODCID;
enc_sess->esi_rscid = *new_dcid;
enc_sess->esi_flags |= ESI_ODCID|ESI_RSCID|ESI_RETRY;
/* Free previous handshake keys */
assert(enc_sess->esi_hsk_pairs);
@ -2340,6 +2419,7 @@ const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1 =
= iquic_esfi_get_peer_transport_params,
.esfi_reset_dcid = iquic_esfi_reset_dcid,
.esfi_init_server = iquic_esfi_init_server,
.esfi_set_iscid = iquic_esfi_set_iscid,
.esfi_set_streams = iquic_esfi_set_streams,
.esfi_create_server = iquic_esfi_create_server,
.esfi_shake_stream = iquic_esfi_shake_stream,

View file

@ -223,6 +223,7 @@ struct lsquic_engine
struct min_heap conns_out;
struct eng_hist history;
unsigned batch_size;
struct lsquic_conn *curr_conn;
struct pr_queue *pr_queue;
struct attq *attq;
/* Track time last time a packet was sent to give new connections
@ -1320,8 +1321,12 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
}
if (engine->flags & ENG_SERVER)
{
conn = find_or_create_conn(engine, packet_in, ppstate, sa_local,
sa_peer, peer_ctx, packet_in_size);
if (!engine->curr_conn)
engine->curr_conn = conn;
}
else
conn = find_conn(engine, packet_in, ppstate, sa_local);
@ -2641,6 +2646,20 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
}
static void
maybe_count_garbage (struct lsquic_engine *engine, size_t garbage_sz)
{
/* This is not very pretty (action at a distance via engine->curr_conn),
* but it's the cheapest I can come up with to handle the "count garbage
* toward amplification limit" requirement in
* [draft-ietf-quic-transport-28] Section 8.1.
*/
if (engine->curr_conn && engine->curr_conn->cn_if->ci_count_garbage)
engine->curr_conn->cn_if->ci_count_garbage(engine->curr_conn,
garbage_sz);
}
/* Return 0 if packet is being processed by a real connection, 1 if the
* packet was processed, but not by a connection, and -1 on error.
*/
@ -2692,6 +2711,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
else
parse_packet_in_begin = lsquic_parse_packet_in_begin;
engine->curr_conn = NULL;
n_zeroes = 0;
is_ietf = 0;
do
@ -2709,6 +2729,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
engine->pub.enp_settings.es_scid_len, &ppstate))
{
LSQ_DEBUG("Cannot parse incoming packet's header");
maybe_count_garbage(engine, packet_end - packet_in_data);
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
s = 1;
break;
@ -2724,6 +2745,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
&& LSQUIC_CIDS_EQ(&packet_in->pi_dcid, &cid)))
{
packet_in_data += packet_in->pi_data_sz;
maybe_count_garbage(engine, packet_in->pi_data_sz);
continue;
}
}

View file

@ -144,7 +144,7 @@ enum more_flags
};
#define N_PATHS 2
#define N_PATHS 4
enum send
{
@ -154,9 +154,13 @@ enum send
SEND_PATH_CHAL,
SEND_PATH_CHAL_PATH_0 = SEND_PATH_CHAL + 0,
SEND_PATH_CHAL_PATH_1 = SEND_PATH_CHAL + 1,
SEND_PATH_CHAL_PATH_2 = SEND_PATH_CHAL + 2,
SEND_PATH_CHAL_PATH_3 = SEND_PATH_CHAL + 3,
SEND_PATH_RESP,
SEND_PATH_RESP_PATH_0 = SEND_PATH_RESP + 0,
SEND_PATH_RESP_PATH_1 = SEND_PATH_RESP + 1,
SEND_PATH_RESP_PATH_2 = SEND_PATH_RESP + 2,
SEND_PATH_RESP_PATH_3 = SEND_PATH_RESP + 3,
SEND_MAX_DATA,
SEND_PING,
SEND_NEW_CID,
@ -181,9 +185,13 @@ enum send_flags
SF_SEND_PATH_CHAL = 1 << SEND_PATH_CHAL,
SF_SEND_PATH_CHAL_PATH_0 = 1 << SEND_PATH_CHAL_PATH_0,
SF_SEND_PATH_CHAL_PATH_1 = 1 << SEND_PATH_CHAL_PATH_1,
SF_SEND_PATH_CHAL_PATH_2 = 1 << SEND_PATH_CHAL_PATH_2,
SF_SEND_PATH_CHAL_PATH_3 = 1 << SEND_PATH_CHAL_PATH_3,
SF_SEND_PATH_RESP = 1 << SEND_PATH_RESP,
SF_SEND_PATH_RESP_PATH_0 = 1 << SEND_PATH_RESP_PATH_0,
SF_SEND_PATH_RESP_PATH_1 = 1 << SEND_PATH_RESP_PATH_1,
SF_SEND_PATH_RESP_PATH_2 = 1 << SEND_PATH_RESP_PATH_2,
SF_SEND_PATH_RESP_PATH_3 = 1 << SEND_PATH_RESP_PATH_3,
SF_SEND_NEW_CID = 1 << SEND_NEW_CID,
SF_SEND_RETIRE_CID = 1 << SEND_RETIRE_CID,
SF_SEND_CONN_CLOSE = 1 << SEND_CONN_CLOSE,
@ -464,6 +472,10 @@ ietf_full_conn_ci_get_log_cid (const struct lsquic_conn *);
static void
ietf_full_conn_ci_destroy (struct lsquic_conn *);
static int
insert_new_dcid (struct ietf_full_conn *, uint64_t seqno,
const lsquic_cid_t *, const unsigned char *token, int update_cur_dcid);
static unsigned
highest_bit_set (unsigned sz)
{
@ -652,11 +664,11 @@ migra_begin (struct ietf_full_conn *conn, struct conn_path *copath,
copath->cop_path.np_pack_size = IQUIC_MAX_IPv6_PACKET_SZ;
else
copath->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
if ((params->tp_set & (1 << TPI_MAX_PACKET_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE]
if ((params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< copath->cop_path.np_pack_size)
copath->cop_path.np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE];
= params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
memcpy(&copath->cop_path.np_local_addr, NP_LOCAL_SA(CUR_NPATH(conn)),
sizeof(copath->cop_path.np_local_addr));
memcpy(&copath->cop_path.np_peer_addr, dest_sa,
@ -1113,6 +1125,8 @@ ietf_full_conn_init (struct ietf_full_conn *conn,
conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO;
conn->ifc_paths[0].cop_path.np_path_id = 0;
conn->ifc_paths[1].cop_path.np_path_id = 1;
conn->ifc_paths[2].cop_path.np_path_id = 2;
conn->ifc_paths[3].cop_path.np_path_id = 3;
#define valid_stream_id(v) ((v) <= VINT_MAX_VALUE)
conn->ifc_max_req_id = VINT_MAX_VALUE + 1;
conn->ifc_ping_unretx_thresh = 20;
@ -2740,7 +2754,7 @@ ietf_full_conn_ci_going_away (struct lsquic_conn *lconn)
{
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
if ((conn->ifc_flags & (IFC_SERVER|IFC_HTTP)) == (IFC_SERVER|IFC_HTTP))
if (conn->ifc_flags & IFC_HTTP)
{
if (!(conn->ifc_flags & (IFC_CLOSING|IFC_GOING_AWAY)))
{
@ -2760,7 +2774,7 @@ ietf_full_conn_ci_going_away (struct lsquic_conn *lconn)
}
}
else
LSQ_NOTICE("going away has no effect in IETF QUIC");
LSQ_NOTICE("going away has no effect in non-HTTP mode");
}
@ -2834,8 +2848,8 @@ retire_cid_from_tp (struct ietf_full_conn *conn,
}
static int
begin_migra_or_retire_cid (struct ietf_full_conn *conn,
static enum { BM_MIGRATING, BM_NOT_MIGRATING, BM_ERROR, }
try_to_begin_migration (struct ietf_full_conn *conn,
const struct transport_params *params)
{
struct conn_path *copath;
@ -2853,8 +2867,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
retire_cid_from_tp(conn, params);
return 0;
return BM_NOT_MIGRATING;
}
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
@ -2867,8 +2880,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
*/
LSQ_DEBUG("Cannot migrate from IPv%u to IPv%u", is_ipv6 ? 6 : 4,
is_ipv6 ? 4 : 6);
retire_cid_from_tp(conn, params);
return 0;
return BM_NOT_MIGRATING;
}
if (0 == params->tp_preferred_address.cid.len)
@ -2877,15 +2889,14 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
* DCID becomes available.
*/
LSQ_DEBUG("Cannot migrate using zero-length DCID");
retire_cid_from_tp(conn, params);
return 0;
return BM_NOT_MIGRATING;
}
dce = get_new_dce(conn);
if (!dce)
{
ABORT_WARN("cannot allocate DCE");
return -1;
return BM_ERROR;
}
memset(dce, 0, sizeof(*dce));
@ -2902,7 +2913,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
{
lsquic_malo_put(dce);
ABORT_WARN("cannot insert DCE");
return -1;
return BM_ERROR;
}
}
@ -2925,7 +2936,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
assert(!(conn->ifc_used_paths & (1 << (copath - conn->ifc_paths))));
migra_begin(conn, copath, dce, (struct sockaddr *) &sockaddr, params);
return 0;
return BM_MIGRATING;
}
@ -2938,10 +2949,33 @@ maybe_start_migration (struct ietf_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session);
if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{
if (0 != begin_migra_or_retire_cid(conn, params))
switch (try_to_begin_migration(conn, params))
{
case BM_MIGRATING:
break;
case BM_NOT_MIGRATING:
if (lconn->cn_version == LSQVER_ID27)
retire_cid_from_tp(conn, params);
else
{
/*
* [draft-ietf-quic-transport-28] Section 5.1.1:
" Connection IDs that are issued and not
" retired are considered active; any active connection ID is valid for
" use with the current connection at any time, in any packet type.
" This includes the connection ID issued by the server via the
" preferred_address transport parameter.
*/
LSQ_DEBUG("not migrating: save DCID from transport params");
(void) insert_new_dcid(conn, 1,
&params->tp_preferred_address.cid,
params->tp_preferred_address.srst, 0);
}
break;
case BM_ERROR:
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
}
break;
}
}
@ -2955,7 +2989,7 @@ handshake_ok (struct lsquic_conn *lconn)
const struct transport_params *params;
enum stream_id_type sit;
uint64_t limit;
char buf[0x200];
char buf[MAX_TP_STR_SZ];
fiu_return_on("full_conn_ietf/handshake_ok", -1);
@ -2973,7 +3007,8 @@ handshake_ok (struct lsquic_conn *lconn)
}
LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
((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))
&& conn->ifc_settings->es_ql_bits == 2)
@ -3088,12 +3123,12 @@ handshake_ok (struct lsquic_conn *lconn)
conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000;
if ((params->tp_set & (1 << TPI_MAX_PACKET_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE]
if ((params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< CUR_NPATH(conn)->np_pack_size)
{
CUR_NPATH(conn)->np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE];
= params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
LSQ_DEBUG("decrease packet size to %hu bytes",
CUR_NPATH(conn)->np_pack_size);
}
@ -3937,6 +3972,20 @@ generate_path_chal_1 (struct ietf_full_conn *conn, lsquic_time_t now)
}
static void
generate_path_chal_2 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_chal_frame(conn, now, 2);
}
static void
generate_path_chal_3 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_chal_frame(conn, now, 3);
}
static void
generate_path_resp_frame (struct ietf_full_conn *conn, lsquic_time_t now,
unsigned path_id)
@ -3986,6 +4035,20 @@ generate_path_resp_1 (struct ietf_full_conn *conn, lsquic_time_t now)
}
static void
generate_path_resp_2 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_resp_frame(conn, now, 2);
}
static void
generate_path_resp_3 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_resp_frame(conn, now, 3);
}
static struct lsquic_packet_out *
ietf_full_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
{
@ -5140,17 +5203,91 @@ retire_dcids_prior_to (struct ietf_full_conn *conn, unsigned retire_prior_to)
}
static int
insert_new_dcid (struct ietf_full_conn *conn, uint64_t seqno,
const lsquic_cid_t *cid, const unsigned char *token, int update_cur_dcid)
{
struct dcid_elem **dce, **el;
char tokstr[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
dce = NULL;
for (el = conn->ifc_dces; el < conn->ifc_dces + sizeof(conn->ifc_dces)
/ sizeof(conn->ifc_dces[0]); ++el)
if (*el)
{
if ((*el)->de_seqno == seqno)
{
if (!LSQUIC_CIDS_EQ(&(*el)->de_cid, cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: already have CID seqno %"PRIu64
" but with a different CID", seqno);
return -1;
}
else
{
LSQ_DEBUG("Ignore duplicate CID seqno %"PRIu64, seqno);
return 0;
}
}
else if (LSQUIC_CIDS_EQ(&(*el)->de_cid, cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received the same CID with sequence "
"numbers %u and %"PRIu64, (*el)->de_seqno, seqno);
return -1;
}
else if (((*el)->de_flags & DE_SRST)
&& 0 == memcmp((*el)->de_srst, token,
IQUIC_SRESET_TOKEN_SZ))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received second instance of reset "
"token %s in seqno %"PRIu64", same as in seqno %u",
(lsquic_hexstr(token, IQUIC_SRESET_TOKEN_SZ, tokstr,
sizeof(tokstr)), tokstr),
seqno, (*el)->de_seqno);
return -1;
}
}
else if (!dce)
dce = el;
if (!dce)
{
ABORT_QUIETLY(0, TEC_CONNECTION_ID_LIMIT_ERROR,
"NEW_CONNECTION_ID: received connection ID that is going over the "
"limit of %u CIDs", MAX_IETF_CONN_DCIDS);
return -1;
}
*dce = lsquic_malo_get(conn->ifc_pub.mm->malo.dcid_elem);
if (*dce)
{
memset(*dce, 0, sizeof(**dce));
(*dce)->de_seqno = seqno;
(*dce)->de_cid = *cid;
memcpy((*dce)->de_srst, token, sizeof((*dce)->de_srst));
(*dce)->de_flags |= DE_SRST;
if (update_cur_dcid)
*CUR_DCID(conn) = *cid;
}
else
LSQ_WARN("cannot allocate dce to insert DCID seqno %"PRIu64, seqno);
return 0;
}
static unsigned
process_new_connection_id_frame (struct ietf_full_conn *conn,
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
{
struct dcid_elem **dce, **el;
const unsigned char *token;
const char *action_str;
lsquic_cid_t cid;
uint64_t seqno, retire_prior_to;
int parsed_len, update_cur_dcid;
char tokstr[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_conn_id(p, len,
&seqno, &retire_prior_to, &cid, &token);
@ -5194,71 +5331,9 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,
else
update_cur_dcid = 0;
dce = NULL;
for (el = conn->ifc_dces; el < conn->ifc_dces + sizeof(conn->ifc_dces)
/ sizeof(conn->ifc_dces[0]); ++el)
if (*el)
{
if ((*el)->de_seqno == seqno)
{
if (!LSQUIC_CIDS_EQ(&(*el)->de_cid, &cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: already have CID seqno %"PRIu64
" but with a different CID", seqno);
return 0;
}
else
{
LSQ_DEBUG("Ignore duplicate CID seqno %"PRIu64, seqno);
return parsed_len;
}
}
else if (LSQUIC_CIDS_EQ(&(*el)->de_cid, &cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received the same CID with sequence "
"numbers %u and %"PRIu64, (*el)->de_seqno, seqno);
return 0;
}
else if (((*el)->de_flags & DE_SRST)
&& 0 == memcmp((*el)->de_srst, token,
IQUIC_SRESET_TOKEN_SZ))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received second instance of reset "
"token %s in seqno %"PRIu64", same as in seqno %u",
(lsquic_hexstr(token, IQUIC_SRESET_TOKEN_SZ, tokstr,
sizeof(tokstr)), tokstr),
seqno, (*el)->de_seqno);
return 0;
}
}
else if (!dce)
dce = el;
if (!dce)
{
ABORT_QUIETLY(0, TEC_CONNECTION_ID_LIMIT_ERROR,
"NEW_CONNECTION_ID: received connection ID that is going over the "
"limit of %u CIDs", MAX_IETF_CONN_DCIDS);
if (0 != insert_new_dcid(conn, seqno, &cid, token, update_cur_dcid))
return 0;
}
*dce = lsquic_malo_get(conn->ifc_pub.mm->malo.dcid_elem);
if (*dce)
{
memset(*dce, 0, sizeof(**dce));
(*dce)->de_seqno = seqno;
(*dce)->de_cid = cid;
memcpy((*dce)->de_srst, token, sizeof((*dce)->de_srst));
(*dce)->de_flags |= DE_SRST;
action_str = "Saved";
if (update_cur_dcid)
*CUR_DCID(conn) = cid;
}
else
action_str = "Ignored (alloc failure)";
action_str = "Saved";
end:
LSQ_DEBUGC("Got new connection ID from peer: seq=%"PRIu64"; "
@ -5642,7 +5717,8 @@ process_packet_frame (struct ietf_full_conn *conn,
enc_level = lsquic_packet_in_enc_level(packet_in);
type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p, len);
if (lsquic_legal_frames_by_level[enc_level] & (1 << type))
if (lsquic_legal_frames_by_level[conn->ifc_conn.cn_version][enc_level]
& (1 << type))
{
LSQ_DEBUG("about to process %s frame", frame_type_2_str[type]);
packet_in->pi_frame_types |= 1 << type;
@ -5724,11 +5800,11 @@ init_new_path (struct ietf_full_conn *conn, struct conn_path *path,
path->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session);
if (params && (params->tp_set & (1 << TPI_MAX_PACKET_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE]
if (params && (params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< path->cop_path.np_pack_size)
path->cop_path.np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE];
= params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
LSQ_DEBUG("initialized path %u", (unsigned) (path - conn->ifc_paths));
@ -6158,6 +6234,9 @@ process_regular_packet (struct ietf_full_conn *conn,
return process_retry_packet(conn, packet_in);
pns = lsquic_hety2pns[ packet_in->pi_header_type ];
if (pns == PNS_INIT)
conn->ifc_conn.cn_esf.i->esfi_set_iscid(conn->ifc_conn.cn_enc_session,
packet_in);
if ((pns == PNS_INIT && (conn->ifc_flags & IFC_IGNORE_INIT))
|| (pns == PNS_HSK && (conn->ifc_flags & IFC_IGNORE_HSK)))
{
@ -6241,6 +6320,10 @@ process_regular_packet (struct ietf_full_conn *conn,
"decrypter reports protocol violation");
return -1;
case DECPI_OK:
/* Receiving any other type of packet precludes subsequent retries.
* We only set it if decryption is successful.
*/
conn->ifc_flags |= IFC_RETRIED;
break;
}
}
@ -6344,13 +6427,6 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn,
if (lsquic_packet_in_is_verneg(packet_in))
{
if (!verneg_ok(conn))
{
ABORT_ERROR("version negotiation not permitted in this version "
"of QUIC");
return -1;
}
LSQ_DEBUG("Processing version-negotiation packet");
if (conn->ifc_u.cli.ifcli_ver_neg.vn_state != VN_START)
@ -6383,10 +6459,26 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn,
}
}
/* [draft-ietf-quic-transport-28] Section 6.2:
" A client MUST discard a Version Negotiation packet that lists the
" QUIC version selected by the client.
*/
if (versions & (1 << conn->ifc_u.cli.ifcli_ver_neg.vn_ver))
{
ABORT_ERROR("server replied with version we support: %s",
LSQ_DEBUG("server replied with version we sent, %s, ignore",
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
return 0;
}
/* [draft-ietf-quic-transport-28] Section 6.2:
" A client that supports only this version of QUIC MUST abandon the
" current connection attempt if it receives a Version Negotiation
" packet [...]
*/
if (!verneg_ok(conn))
{
ABORT_ERROR("version negotiation not permitted in this version "
"of QUIC");
return -1;
}
@ -6530,8 +6622,12 @@ static void (*const send_funcs[N_SEND])(
[SEND_STOP_SENDING] = generate_stop_sending_frames,
[SEND_PATH_CHAL_PATH_0] = generate_path_chal_0,
[SEND_PATH_CHAL_PATH_1] = generate_path_chal_1,
[SEND_PATH_CHAL_PATH_2] = generate_path_chal_2,
[SEND_PATH_CHAL_PATH_3] = generate_path_chal_3,
[SEND_PATH_RESP_PATH_0] = generate_path_resp_0,
[SEND_PATH_RESP_PATH_1] = generate_path_resp_1,
[SEND_PATH_RESP_PATH_2] = generate_path_resp_2,
[SEND_PATH_RESP_PATH_3] = generate_path_resp_3,
[SEND_PING] = generate_ping_frame,
[SEND_HANDSHAKE_DONE] = generate_handshake_done_frame,
[SEND_ACK_FREQUENCY] = generate_ack_frequency_frame,
@ -6543,7 +6639,9 @@ static void (*const send_funcs[N_SEND])(
|SF_SEND_STREAMS_BLOCKED_UNI|SF_SEND_STREAMS_BLOCKED_BIDI\
|SF_SEND_MAX_STREAMS_UNI|SF_SEND_MAX_STREAMS_BIDI\
|SF_SEND_PATH_CHAL_PATH_0|SF_SEND_PATH_CHAL_PATH_1\
|SF_SEND_PATH_CHAL_PATH_2|SF_SEND_PATH_CHAL_PATH_3\
|SF_SEND_PATH_RESP_PATH_0|SF_SEND_PATH_RESP_PATH_1\
|SF_SEND_PATH_RESP_PATH_2|SF_SEND_PATH_RESP_PATH_3\
|SF_SEND_PING|SF_SEND_HANDSHAKE_DONE\
|SF_SEND_ACK_FREQUENCY\
|SF_SEND_STOP_SENDING)
@ -7119,6 +7217,17 @@ ietf_full_conn_ci_drop_crypto_streams (struct lsquic_conn *lconn)
}
void
ietf_full_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
{
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
conn->ifc_pub.bytes_in = garbage_sz;
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
conn->ifc_pub.bytes_in);
}
#define IETF_FULL_CONN_FUNCS \
.ci_abort = ietf_full_conn_ci_abort, \
.ci_abort_error = ietf_full_conn_ci_abort_error, \
@ -7127,6 +7236,7 @@ ietf_full_conn_ci_drop_crypto_streams (struct lsquic_conn *lconn)
.ci_cancel_pending_streams = ietf_full_conn_ci_cancel_pending_streams, \
.ci_client_call_on_new = ietf_full_conn_ci_client_call_on_new, \
.ci_close = ietf_full_conn_ci_close, \
.ci_count_garbage = ietf_full_conn_ci_count_garbage, \
.ci_destroy = ietf_full_conn_ci_destroy, \
.ci_drain_time = ietf_full_conn_ci_drain_time, \
.ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams, \

View file

@ -4,7 +4,7 @@
/* Things specific to the IETF version of QUIC that do not fit anywhere else */
/* [draft-ietf-quic-transport-25] Section 22.4 */
/* [draft-ietf-quic-transport-28] Section 20 */
enum trans_error_code
{
TEC_NO_ERROR = 0x0,
@ -19,6 +19,7 @@ enum trans_error_code
TEC_CONNECTION_ID_LIMIT_ERROR = 0x9,
TEC_PROTOCOL_VIOLATION = 0xA,
TEC_INVALID_TOKEN = 0xB,
TEC_APPLICATION_ERROR = 0xC,
TEC_CRYPTO_BUFFER_EXCEEDED = 0xD,
};

View file

@ -248,8 +248,10 @@ lsquic_logger_lopt (const char *optarg);
#define CID_FMT ".*s"
#define CID_BITS(cid) 2 * (int) (cid)->len, \
(lsquic_cid2str(cid, cidbuf_), cidbuf_)
#define CID_BITS_B(cid, b) 2 * (int) (cid)->len, \
(lsquic_cid2str(cid, b), b)
#define CID_BITS(cid) CID_BITS_B(cid, cidbuf_)
void
lsquic_cid2str (const struct lsquic_cid *, char *out);

View file

@ -188,12 +188,12 @@ imico_maybe_process_params (struct ietf_mini_conn *conn)
{
conn->imc_flags |= IMC_HAVE_TP;
conn->imc_ack_exp = params->tp_ack_delay_exponent;
if (params->tp_set & (1 << TPI_MAX_PACKET_SIZE))
if (params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
{
if (params->tp_numerics[TPI_MAX_PACKET_SIZE]
if (params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< conn->imc_path.np_pack_size)
conn->imc_path.np_pack_size =
params->tp_numerics[TPI_MAX_PACKET_SIZE];
params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
}
LSQ_DEBUG("read transport params, packet size is set to %hu bytes",
conn->imc_path.np_pack_size);
@ -493,6 +493,7 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
conn->imc_conn.cn_cur_cce_idx = 1;
conn->imc_conn.cn_flags = LSCONN_MINI|LSCONN_IETF|LSCONN_SERVER;
conn->imc_conn.cn_version = version;
for (i = 0; i < N_ENC_LEVS; ++i)
{
@ -503,7 +504,7 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
esfi = select_esf_iquic_by_ver(version);
enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
&packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
odcid);
&conn->imc_cces[0].cce_cid, &conn->imc_path.np_dcid);
if (!enc_sess)
{
lsquic_malo_put(conn);
@ -518,7 +519,6 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
if (getenv("LSQUIC_CN_PACK_SIZE"))
conn->imc_path.np_pack_size = atoi(getenv("LSQUIC_CN_PACK_SIZE"));
#endif
conn->imc_conn.cn_version = version;
conn->imc_conn.cn_pf = select_pf_by_ver(version);
conn->imc_conn.cn_esf.i = esfi;
conn->imc_conn.cn_enc_session = enc_sess;
@ -1099,7 +1099,8 @@ imico_process_packet_frame (struct ietf_mini_conn *conn,
enc_level = lsquic_packet_in_enc_level(packet_in);
type = conn->imc_conn.cn_pf->pf_parse_frame_type(p, len);
if (lsquic_legal_frames_by_level[enc_level] & (1 << type))
if (lsquic_legal_frames_by_level[conn->imc_conn.cn_version][enc_level]
& (1 << type))
{
packet_in->pi_frame_types |= 1 << type;
return imico_process_frames[type](conn, packet_in, p, len);
@ -1193,6 +1194,17 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
enum dec_packin dec_packin;
enum packnum_space pns;
/* Update "bytes in" count as early as possible. From
* [draft-ietf-quic-transport-28] Section 8.1:
" For the purposes of
" avoiding amplification prior to address validation, servers MUST
" count all of the payload bytes received in datagrams that are
" uniquely attributed to a single connection. This includes datagrams
" that contain packets that are successfully processed and datagrams
" that contain packets that are all discarded.
*/
conn->imc_bytes_in += packet_in->pi_data_sz;
if (conn->imc_flags & IMC_ERROR)
{
LSQ_DEBUG("ignore incoming packet: connection is in error state");
@ -1216,7 +1228,6 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
}
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
conn->imc_bytes_in += packet_in->pi_data_sz + IQUIC_TAG_LEN;
if (pns == PNS_APP)
{
@ -1580,7 +1591,7 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
else if (conn->imc_flags & IMC_BAD_TRANS_PARAMS)
{
is_app = 0;
error_code = TEC_NO_ERROR;
error_code = TEC_PROTOCOL_VIOLATION;
reason = "bad transport parameters";
rlen = 24;
}
@ -1607,7 +1618,7 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
}
/* [draft-ietf-quic-transport-23] Section 12.2:
/* [draft-ietf-quic-transport-28] Section 10.3.1:
*
" A client will always know whether the server has Handshake keys (see
" Section 17.2.2.1), but it is possible that a server does not know
@ -1615,7 +1626,25 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
" server SHOULD send a CONNECTION_CLOSE frame in both Handshake and
" Initial packets to ensure that at least one of them is processable by
" the client.
--- 8< ---
" Sending a CONNECTION_CLOSE of type 0x1d in an Initial or Handshake
" packet could expose application state or be used to alter application
" state. A CONNECTION_CLOSE of type 0x1d MUST be replaced by a
" CONNECTION_CLOSE of type 0x1c when sending the frame in Initial or
" Handshake packets. Otherwise, information about the application
" state might be revealed. Endpoints MUST clear the value of the
" Reason Phrase field and SHOULD use the APPLICATION_ERROR code when
" converting to a CONNECTION_CLOSE of type 0x1c.
*/
LSQ_DEBUG("sending CONNECTION_CLOSE, is_app: %d, error code: %u, "
"reason: %.*s", is_app, error_code, rlen, reason);
if (is_app && conn->imc_conn.cn_version > LSQVER_ID27)
{
LSQ_DEBUG("convert to 0x1C, replace code and reason");
is_app = 0;
error_code = TEC_APPLICATION_ERROR;
rlen = 0;
}
pns = (conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3;
switch ((!!(conn->imc_flags & IMC_HSK_PACKET_SENT) << 1)
@ -1844,9 +1873,21 @@ ietf_mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
}
void
ietf_mini_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
{
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
conn->imc_bytes_in += garbage_sz;
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
conn->imc_bytes_in);
}
static const struct conn_iface mini_conn_ietf_iface = {
.ci_abort_error = ietf_mini_conn_ci_abort_error,
.ci_client_call_on_new = ietf_mini_conn_ci_client_call_on_new,
.ci_count_garbage = ietf_mini_conn_ci_count_garbage,
.ci_destroy = ietf_mini_conn_ci_destroy,
.ci_get_engine = ietf_mini_conn_ci_get_engine,
.ci_get_log_cid = ietf_mini_conn_ci_get_log_cid,

View file

@ -238,6 +238,6 @@ extern const char *const lsquic_pns2str[];
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP))
extern const enum quic_ft_bit lsquic_legal_frames_by_level[];
extern const enum quic_ft_bit lsquic_legal_frames_by_level[][4];
#endif

View file

@ -217,9 +217,38 @@ lsquic_cid_from_packet (const unsigned char *buf, size_t bufsz,
}
/* See [draft-ietf-quic-transport-25], Section 12.4 (Table 3) */
const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] =
/* See [draft-ietf-quic-transport-28], Section 12.4 (Table 3) */
const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
{
[LSQVER_ID28] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| 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_TIMESTAMP
,
},
[LSQVER_ID27] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
@ -246,4 +275,5 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] =
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
| QUIC_FTBIT_TIMESTAMP
,
},
};

View file

@ -355,7 +355,7 @@ lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
version = lsquic_tag2ver(ver_tag);
}
else /* Got to set it to something sensible... */
version = LSQVER_ID25;
version = LSQVER_ID27;
lsquic_scid_from_packet_in(packet_in, &scid);
return lsquic_prq_new_req_ext(prq, type, flags, version,

View file

@ -31,7 +31,7 @@
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define TOKGEN_VERSION 1
#define TOKGEN_VERSION 2
#define CRYPTER_KEY_SIZE 16
#define SRST_MAX_PRK_SIZE EVP_MAX_MD_SIZE
@ -65,6 +65,8 @@ struct crypter
};
struct token_generator
{
/* We encrypt different token types using different keys. */

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ enum transport_param_id
* Numeric transport parameters that have default values:
*/
TPI_MAX_IDLE_TIMEOUT,
TPI_MAX_PACKET_SIZE,
TPI_MAX_UDP_PAYLOAD_SIZE,
TPI_INIT_MAX_DATA,
TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
@ -45,7 +45,12 @@ enum transport_param_id
* Custom handlers:
*/
TPI_PREFERRED_ADDRESS,
TPI_ORIGINAL_CONNECTION_ID,
/* CIDs must be in a contiguous range for tp_cids array to work */
#define FIRST_TP_CID TPI_ORIGINAL_DEST_CID
TPI_ORIGINAL_DEST_CID,
TPI_INITIAL_SOURCE_CID,
#define LAST_TP_CID TPI_RETRY_SOURCE_CID
TPI_RETRY_SOURCE_CID,
#if LSQUIC_TEST_QUANTUM_READINESS
/* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */
#define QUANTUM_READY_SZ 1200
@ -54,6 +59,8 @@ enum transport_param_id
TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN
};
#define TP_CID_IDX(tpi_) ((tpi_) - FIRST_TP_CID)
struct transport_params
{
@ -72,7 +79,7 @@ struct transport_params
#define tp_max_idle_timeout tp_numerics[TPI_MAX_IDLE_TIMEOUT]
#define tp_init_max_streams_bidi tp_numerics[TPI_INIT_MAX_STREAMS_BIDI]
#define tp_init_max_streams_uni tp_numerics[TPI_INIT_MAX_STREAMS_UNI]
#define tp_max_packet_size tp_numerics[TPI_MAX_PACKET_SIZE]
#define tp_max_udp_payload_size tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
#define tp_ack_delay_exponent tp_numerics[TPI_ACK_DELAY_EXPONENT]
#define tp_max_ack_delay tp_numerics[TPI_MAX_ACK_DELAY]
#define tp_active_connection_id_limit tp_numerics[TPI_ACTIVE_CONNECTION_ID_LIMIT]
@ -87,10 +94,20 @@ struct transport_params
lsquic_cid_t cid;
uint8_t srst[IQUIC_SRESET_TOKEN_SZ];
} tp_preferred_address;
lsquic_cid_t tp_original_cid;
lsquic_cid_t tp_cids[3];
#define tp_original_dest_cid tp_cids[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)]
#define tp_initial_source_cid tp_cids[TP_CID_IDX(TPI_INITIAL_SOURCE_CID)]
#define tp_retry_source_cid tp_cids[TP_CID_IDX(TPI_RETRY_SOURCE_CID)]
};
#define TP_DEF_MAX_PACKET_SIZE 65527
#define MAX_TP_STR_SZ ((LAST_TPI + 1) * \
(34 /* longest entry in tt2str */ + 2 /* semicolon */ + 2 /* colon */) \
+ INET_ADDRSTRLEN + INET6_ADDRSTRLEN + 5 /* Port */ * 2 \
+ MAX_CID_LEN * 2 * 4 /* there are four CIDs */ \
+ 11 * (MAX_NUMERIC_TPI + 1) \
+ IQUIC_SRESET_TOKEN_SZ * 2 * 2 /* there are two reset tokens */)
#define TP_DEF_MAX_UDP_PAYLOAD_SIZE 65527
#define TP_DEF_ACK_DELAY_EXP 3
#define TP_DEF_INIT_MAX_STREAMS_UNI 0
#define TP_DEF_INIT_MAX_STREAMS_BIDI 0
@ -111,7 +128,7 @@ struct transport_params
.tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \
.tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \
.tp_max_packet_size = TP_DEF_MAX_PACKET_SIZE, \
.tp_max_udp_payload_size = TP_DEF_MAX_UDP_PAYLOAD_SIZE, \
.tp_ack_delay_exponent = TP_DEF_ACK_DELAY_EXP, \
.tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \
.tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \
@ -135,16 +152,20 @@ lsquic_tp_decode (const unsigned char *buf, size_t bufsz,
int is_server,
struct transport_params *);
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);
int
lsquic_tp_encode_id25 (const struct transport_params *, int is_server,
lsquic_tp_encode_27 (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz);
int
lsquic_tp_decode_id25 (const unsigned char *buf, size_t bufsz,
int is_server, struct transport_params *);
lsquic_tp_decode_27 (const unsigned char *buf, size_t bufsz,
int is_server,
struct transport_params *);
void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);
lsquic_tp_to_str_27 (const struct transport_params *params, char *buf, size_t sz);
int
lsquic_tp_has_pref_ipv4 (const struct transport_params *);
@ -152,4 +173,6 @@ lsquic_tp_has_pref_ipv4 (const struct transport_params *);
int
lsquic_tp_has_pref_ipv6 (const struct transport_params *);
extern const char * const lsquic_tpi2str[LAST_TPI + 1];
#endif

View file

@ -14,8 +14,8 @@ static const unsigned char version_tags[N_LSQVER][4] =
#if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', },
#endif
[LSQVER_ID25] = { 0xFF, 0, 0, 25, },
[LSQVER_ID27] = { 0xFF, 0, 0, 27, },
[LSQVER_ID28] = { 0xFF, 0, 0, 28, },
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
};
@ -52,8 +52,8 @@ const char *const lsquic_ver2str[N_LSQVER] = {
#if LSQUIC_USE_Q098
[LSQVER_098] = "Q098",
#endif
[LSQVER_ID25] = "FF000019",
[LSQVER_ID27] = "FF00001B",
[LSQVER_ID28] = "FF00001C",
[LSQVER_VERNEG] = "FAFAFAFA",
};