From 9626cfc25bfaccaf578c88dda1a81624705990e3 Mon Sep 17 00:00:00 2001 From: Dmitri Tikhonov Date: Wed, 15 Aug 2018 15:06:31 -0400 Subject: [PATCH] 1.11.0: [FEATURE] Add support for Q044 --- CHANGELOG | 5 + README.md | 8 +- include/lsquic.h | 37 +++- src/liblsquic/CMakeLists.txt | 3 + src/liblsquic/lsquic_byteswap.h | 23 +++ src/liblsquic/lsquic_conn.c | 4 +- src/liblsquic/lsquic_engine.c | 68 ++++--- src/liblsquic/lsquic_ev_log.c | 28 ++- src/liblsquic/lsquic_full_conn.c | 40 +++- src/liblsquic/lsquic_handshake.c | 56 +++++- src/liblsquic/lsquic_handshake.h | 11 +- src/liblsquic/lsquic_packet_common.c | 11 ++ src/liblsquic/lsquic_packet_common.h | 32 +++- src/liblsquic/lsquic_packet_in.h | 16 +- src/liblsquic/lsquic_packet_out.c | 25 ++- src/liblsquic/lsquic_packet_out.h | 46 +++-- src/liblsquic/lsquic_parse.h | 54 ++++-- src/liblsquic/lsquic_parse_Q044.c | 213 ++++++++++++++++++++++ src/liblsquic/lsquic_parse_common.c | 56 ++++++ src/liblsquic/lsquic_parse_common.h | 24 +++ src/liblsquic/lsquic_parse_gquic_be.c | 77 ++++---- src/liblsquic/lsquic_parse_gquic_be.h | 23 --- src/liblsquic/lsquic_parse_gquic_common.c | 41 ++++- src/liblsquic/lsquic_parse_gquic_le.c | 68 +++---- src/liblsquic/lsquic_parse_iquic_common.c | 185 +++++++++++++++++++ src/liblsquic/lsquic_qtags.h | 3 + src/liblsquic/lsquic_send_ctl.c | 30 +-- src/liblsquic/lsquic_stream.c | 7 +- src/liblsquic/lsquic_version.c | 10 +- src/liblsquic/lsquic_version.h | 2 +- test/unittests/test_parse_packet_in.c | 175 +++++++++++++++--- test/unittests/test_reg_pkt_headergen.c | 24 ++- test/unittests/test_some_packets.c | 3 + test/unittests/test_ver_nego.c | 28 +-- 34 files changed, 1157 insertions(+), 279 deletions(-) create mode 100644 src/liblsquic/lsquic_byteswap.h create mode 100644 src/liblsquic/lsquic_parse_Q044.c create mode 100644 src/liblsquic/lsquic_parse_common.c create mode 100644 src/liblsquic/lsquic_parse_common.h create mode 100644 src/liblsquic/lsquic_parse_iquic_common.c diff --git a/CHANGELOG b/CHANGELOG index aaddc7509..0f31aba68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2018-08-15 + + - 1.11.0 + - [FEATURE] Add support for Q044. + 2018-08-09 - 1.10.2 diff --git a/README.md b/README.md index bb9937d9d..6ad0474ff 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ our own products: LiteSpeed Web Server and ADC. We think it is free of major problems. Nevertheless, do not hesitate to report bugs back to us. Even better, send us fixes and improvements! -Currently supported QUIC versions are Q035, Q039, and Q043. Support for -newer versions will be added soon after they are released. The version(s) -specified by IETF QUIC WG will be added once the IETF version of the -protocol settles down a little. +Currently supported QUIC versions are Q035, Q039, Q043, and Q044. Support +for newer versions will be added soon after they are released. The +version(s) specified by IETF QUIC WG will be added once the IETF version +of the protocol settles down a little. Documentation ------------- diff --git a/include/lsquic.h b/include/lsquic.h index 26df183f4..c44a39e82 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -24,8 +24,8 @@ extern "C" { #endif #define LSQUIC_MAJOR_VERSION 1 -#define LSQUIC_MINOR_VERSION 10 -#define LSQUIC_PATCH_VERSION 2 +#define LSQUIC_MINOR_VERSION 11 +#define LSQUIC_PATCH_VERSION 0 /** * Engine flags: @@ -97,23 +97,45 @@ enum lsquic_version */ LSQVER_043, + /** + * Q044. IETF-like packet headers are used. Frames are the same as + * in Q043. Server never includes CIDs in short packets. + */ + LSQVER_044, + +#if LSQUIC_USE_Q098 + /** + * Q098. This is a made-up, experimental version used to test version + * negotiation. The choice of 98 is similar to Google's choice of 99 + * as the "IETF" version. + */ + LSQVER_098, +#define LSQUIC_EXPERIMENTAL_Q098 (1 << LSQVER_098) +#else +#define LSQUIC_EXPERIMENTAL_Q098 0 +#endif + N_LSQVER }; /** - * We currently support versions 35, 39, and 43. + * We currently support versions 35, 39, 43, and 44. * @see lsquic_version */ #define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1) -#define LSQUIC_EXPERIMENTAL_VERSIONS 0 +#define LSQUIC_EXPERIMENTAL_VERSIONS (0 \ + | LSQUIC_EXPERIMENTAL_Q098) #define LSQUIC_DEPRECATED_VERSIONS 0 +#define LSQUIC_GQUIC_HEADER_VERSIONS ( \ + (1 << LSQVER_035) | (1 << LSQVER_039) | (1 << LSQVER_043)) + /** - * List of version in which the server does not include CID in short packets. + * List of versions in which the server never includes CID in short packets. */ -#define LSQUIC_FORCED_TCID0_VERSIONS 0 +#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_044) /** * @struct lsquic_stream_if @@ -330,6 +352,9 @@ struct lsquic_engine_settings { * (source-addr, dest-addr) tuple, thereby making it necessary to create * a socket for each connection. * + * This option has no effect in Q044, as the server never includes CIDs + * in the short packets. + * * The default is @ref LSQUIC_DF_SUPPORT_TCID0. */ int es_support_tcid0; diff --git a/src/liblsquic/CMakeLists.txt b/src/liblsquic/CMakeLists.txt index 3860a592f..b5452b45c 100644 --- a/src/liblsquic/CMakeLists.txt +++ b/src/liblsquic/CMakeLists.txt @@ -6,6 +6,8 @@ SET(lsquic_STAT_SRCS lsquic_chsk_stream.c lsquic_engine.c lsquic_parse_gquic_common.c + lsquic_parse_iquic_common.c + lsquic_parse_common.c lsquic_parse_gquic_le.c lsquic_parse_gquic_be.c lsquic_packet_in.c @@ -50,6 +52,7 @@ SET(lsquic_STAT_SRCS lsquic_buf.c lsquic_min_heap.c lshpack.c + lsquic_parse_Q044.c ) diff --git a/src/liblsquic/lsquic_byteswap.h b/src/liblsquic/lsquic_byteswap.h new file mode 100644 index 000000000..06a4f0c71 --- /dev/null +++ b/src/liblsquic/lsquic_byteswap.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ +#ifndef LSQUIC_BYTESWAP_H +#define LSQUIC_BYTESWAP_H 1 + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#include +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#elif defined(__APPLE__) +#include +#define bswap_16 OSSwapInt16 +#define bswap_32 OSSwapInt32 +#define bswap_64 OSSwapInt64 +#elif defined(WIN32) +#define bswap_16 _byteswap_ushort +#define bswap_32 _byteswap_ulong +#define bswap_64 _byteswap_uint64 +#else +#include +#endif + +#endif diff --git a/src/liblsquic/lsquic_conn.c b/src/liblsquic/lsquic_conn.c index 26889ac95..c5093a0d8 100644 --- a/src/liblsquic/lsquic_conn.c +++ b/src/liblsquic/lsquic_conn.c @@ -126,8 +126,8 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn, | (enc_level << PIBIT_ENC_LEV_SHIFT); packet_in->pi_header_sz = header_len; packet_in->pi_data_sz = out_len + header_len; - EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64, - packet_in->pi_packno); + EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64" crypto: %s", + packet_in->pi_packno, lsquic_enclev2str[ enc_level ]); return 0; } diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index 16a96f995..25ae470c7 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -27,6 +27,7 @@ #include "lsquic.h" #include "lsquic_types.h" #include "lsquic_alarmset.h" +#include "lsquic_parse_common.h" #include "lsquic_parse.h" #include "lsquic_packet_in.h" #include "lsquic_packet_out.h" @@ -261,6 +262,18 @@ static const struct lsquic_packout_mem_if stock_pmi = }; +static int +hash_conns_by_addr (const struct lsquic_engine *engine) +{ + if (engine->pub.enp_settings.es_versions & LSQUIC_FORCED_TCID0_VERSIONS) + return 1; + if ((engine->pub.enp_settings.es_versions & LSQUIC_GQUIC_HEADER_VERSIONS) + && engine->pub.enp_settings.es_support_tcid0) + return 1; + return 0; +} + + lsquic_engine_t * lsquic_engine_new (unsigned flags, const struct lsquic_engine_api *api) @@ -295,7 +308,7 @@ lsquic_engine_new (unsigned flags, engine->pub.enp_settings = *api->ea_settings; else lsquic_engine_init_settings(&engine->pub.enp_settings, flags); - tag_buf_len = gen_ver_tags(engine->pub.enp_ver_tags_buf, + tag_buf_len = lsquic_gen_ver_tags(engine->pub.enp_ver_tags_buf, sizeof(engine->pub.enp_ver_tags_buf), engine->pub.enp_settings.es_versions); if (tag_buf_len <= 0) @@ -324,8 +337,7 @@ lsquic_engine_new (unsigned flags, } engine->pub.enp_engine = engine; conn_hash_init(&engine->conns_hash, - !(flags & ENG_SERVER) && engine->pub.enp_settings.es_support_tcid0 ? - CHF_USE_ADDR : 0); + hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0); engine->attq = attq_create(); eng_hist_init(&engine->history); engine->batch_size = INITIAL_OUT_BATCH_SIZE; @@ -498,7 +510,7 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in, { lsquic_conn_t *conn; - if (lsquic_packet_in_is_prst(packet_in) + if (lsquic_packet_in_is_gquic_prst(packet_in) && !engine->pub.enp_settings.es_honor_prst) { lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in); @@ -758,44 +770,34 @@ lsquic_engine_process_conns (lsquic_engine_t *engine) } -static int -generate_header (const lsquic_packet_out_t *packet_out, - const struct parse_funcs *pf, lsquic_cid_t cid, - unsigned char *buf, size_t bufsz) -{ - return pf->pf_gen_reg_pkt_header(buf, bufsz, - packet_out->po_flags & PO_CONN_ID ? &cid : NULL, - packet_out->po_flags & PO_VERSION ? &packet_out->po_ver_tag : NULL, - packet_out->po_flags & PO_NONCE ? packet_out->po_nonce : NULL, - packet_out->po_packno, lsquic_packet_out_packno_bits(packet_out)); -} - - static ssize_t really_encrypt_packet (const lsquic_conn_t *conn, - const lsquic_packet_out_t *packet_out, + struct lsquic_packet_out *packet_out, unsigned char *buf, size_t bufsz) { - int enc, header_sz, is_hello_packet; + int header_sz, is_hello_packet; + enum enc_level enc_level; size_t packet_sz; unsigned char header_buf[QUIC_MAX_PUBHDR_SZ]; - header_sz = generate_header(packet_out, conn->cn_pf, conn->cn_cid, + header_sz = conn->cn_pf->pf_gen_reg_pkt_header(conn, packet_out, header_buf, sizeof(header_buf)); if (header_sz < 0) return -1; is_hello_packet = !!(packet_out->po_flags & PO_HELLO); - enc = conn->cn_esf->esf_encrypt(conn->cn_enc_session, conn->cn_version, 0, + enc_level = conn->cn_esf->esf_encrypt(conn->cn_enc_session, + conn->cn_version, 0, packet_out->po_packno, header_buf, header_sz, packet_out->po_data, packet_out->po_data_sz, buf, bufsz, &packet_sz, is_hello_packet); - if (0 == enc) + if ((int) enc_level >= 0) { - LSQ_DEBUG("encrypted packet %"PRIu64"; plaintext is %u bytes, " + lsquic_packet_out_set_enc_level(packet_out, enc_level); + LSQ_DEBUG("encrypted packet %"PRIu64"; plaintext is %zu bytes, " "ciphertext is %zd bytes", packet_out->po_packno, - lsquic_po_header_length(packet_out->po_flags) + + conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) + packet_out->po_data_sz, packet_sz); return packet_sz; @@ -814,7 +816,7 @@ encrypt_packet (lsquic_engine_t *engine, const lsquic_conn_t *conn, unsigned sent_sz; unsigned char *buf; - bufsz = lsquic_po_header_length(packet_out->po_flags) + + bufsz = conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) + packet_out->po_data_sz + QUIC_PACKET_HASH_SZ; buf = engine->pub.enp_pmi->pmi_allocate(engine->pub.enp_pmi_ctx, bufsz); if (!buf) @@ -1281,6 +1283,8 @@ lsquic_engine_packet_in (lsquic_engine_t *engine, { struct packin_parse_state ppstate; lsquic_packet_in_t *packet_in; + int (*parse_packet_in_begin) (struct lsquic_packet_in *, size_t length, + int is_server, struct packin_parse_state *); if (packet_in_size > QUIC_MAX_PACKET_SZ) { @@ -1290,6 +1294,20 @@ lsquic_engine_packet_in (lsquic_engine_t *engine, return -1; } + if (conn_hash_using_addr(&engine->conns_hash)) + { + const struct lsquic_conn *conn; + conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local); + if (!conn) + return -1; + if ((1 << conn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS) + parse_packet_in_begin = lsquic_gquic_parse_packet_in_begin; + else + parse_packet_in_begin = lsquic_iquic_parse_packet_in_begin; + } + else + parse_packet_in_begin = lsquic_parse_packet_in_begin; + packet_in = lsquic_mm_get_packet_in(&engine->pub.enp_mm); if (!packet_in) return -1; diff --git a/src/liblsquic/lsquic_ev_log.c b/src/liblsquic/lsquic_ev_log.c index 59023d5a0..e06d5877a 100644 --- a/src/liblsquic/lsquic_ev_log.c +++ b/src/liblsquic/lsquic_ev_log.c @@ -19,6 +19,8 @@ #include "lsquic_parse.h" #include "lsquic_frame_common.h" #include "lsquic_frame_reader.h" +#include "lsquic_str.h" +#include "lsquic_handshake.h" #include "lsquic_ev_log.h" #define LSQUIC_LOGGER_MODULE LSQLM_EVENT @@ -39,7 +41,17 @@ void lsquic_ev_log_packet_in (lsquic_cid_t cid, const lsquic_packet_in_t *packet_in) { - LCID("packet in: %"PRIu64, packet_in->pi_packno); + switch (packet_in->pi_flags & ( + PI_GQUIC)) + { + case PI_GQUIC: + LCID("packet in: %"PRIu64, packet_in->pi_packno); + break; + default: + LCID("packet in: %"PRIu64", type: %s", + packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type]); + break; + } } @@ -153,7 +165,7 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid, packet_out->po_data_sz); else if (lsquic_packet_out_pubres(packet_out)) LCID("sent public reset packet, size %hu", packet_out->po_data_sz); - else + else if (packet_out->po_flags & PO_GQUIC) LCID("sent packet %"PRIu64", size %hu, frame types: %s", packet_out->po_packno, packet_out->po_enc_data_sz, /* Frame types is a list of different frames types contained @@ -162,6 +174,18 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid, */ lsquic_frame_types_to_str(frames, sizeof(frames), packet_out->po_frame_types)); + else + LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame " + "types: %s", + packet_out->po_packno, lsquic_hety2str[packet_out->po_header_type], + lsquic_enclev2str[ lsquic_packet_out_enc_level(packet_out) ], + packet_out->po_enc_data_sz, + /* Frame types is a list of different frames types contained + * in the packet, no more. Count and order of frames is not + * printed. + */ + lsquic_frame_types_to_str(frames, sizeof(frames), + packet_out->po_frame_types)); } diff --git a/src/liblsquic/lsquic_full_conn.c b/src/liblsquic/lsquic_full_conn.c index 37f52fca3..aedac8735 100644 --- a/src/liblsquic/lsquic_full_conn.c +++ b/src/liblsquic/lsquic_full_conn.c @@ -383,6 +383,7 @@ set_versions (struct full_conn *conn, unsigned versions) conn->fc_ver_neg.vn_ver = highest_bit_set(versions); conn->fc_ver_neg.vn_buf = lsquic_ver2tag(conn->fc_ver_neg.vn_ver); conn->fc_conn.cn_version = conn->fc_ver_neg.vn_ver; + conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver); LSQ_DEBUG("negotiating version %s", lsquic_ver2str[conn->fc_ver_neg.vn_ver]); } @@ -675,7 +676,6 @@ full_conn_client_new (struct lsquic_engine_public *enpub, .stream_if = &lsquic_client_hsk_stream_if; conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client; init_ver_neg(conn, conn->fc_settings->es_versions); - conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver); if (conn->fc_settings->es_handshake_to) lsquic_alarmset_set(&conn->fc_alset, AL_HANDSHAKE, lsquic_time_now() + conn->fc_settings->es_handshake_to); @@ -1872,6 +1872,18 @@ parse_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) } +static int +conn_is_stateless_reset (const struct full_conn *conn, + const struct lsquic_packet_in *packet_in) +{ + return packet_in->pi_data_sz > SRST_LENGTH + && 0 == conn->fc_conn.cn_esf->esf_verify_reset_token( + conn->fc_conn.cn_enc_session, + packet_in->pi_data + packet_in->pi_data_sz - SRST_LENGTH, + SRST_LENGTH); +} + + static int process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) { @@ -1893,11 +1905,20 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) if (0 == (packet_in->pi_flags & PI_DECRYPTED) && 0 != conn_decrypt_packet(conn, packet_in)) { - LSQ_INFO("could not decrypt packet"); + if (conn_is_stateless_reset(conn, packet_in)) + { + LSQ_INFO("received public reset packet: aborting connection"); + conn->fc_flags |= FC_GOT_PRST; + return -1; + } + else + { + LSQ_INFO("could not decrypt packet"); #if FULL_CONN_STATS - ++conn->fc_stats.n_undec_packets; + ++conn->fc_stats.n_undec_packets; #endif - return 0; + return 0; + } } st = lsquic_rechist_received(&conn->fc_rechist, packet_in->pi_packno, @@ -1937,13 +1958,18 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) static int process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) { + int is_prst, is_verneg; + recent_packet_hist_new(conn, 0, packet_in->pi_received); LSQ_DEBUG("Processing packet %"PRIu64, packet_in->pi_packno); + + is_prst = lsquic_packet_in_is_gquic_prst(packet_in); + is_verneg = lsquic_packet_in_is_verneg(packet_in); + /* See flowchart in Section 4.1 of [draft-ietf-quic-transport-00]. We test * for the common case first. */ - const unsigned flags = lsquic_packet_in_public_flags(packet_in); - if (0 == (flags & (PACKET_PUBLIC_FLAGS_RST|PACKET_PUBLIC_FLAGS_VERSION))) + if (0 == is_prst && 0 == is_verneg) { if (conn->fc_ver_neg.vn_tag) { @@ -1966,7 +1992,7 @@ process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in) } return process_regular_packet(conn, packet_in); } - else if (flags & PACKET_PUBLIC_FLAGS_RST) + else if (is_prst) { LSQ_INFO("received public reset packet: aborting connection"); conn->fc_flags |= FC_GOT_PRST; diff --git a/src/liblsquic/lsquic_handshake.c b/src/liblsquic/lsquic_handshake.c index d8cf4a74e..2cbdc6fa2 100644 --- a/src/liblsquic/lsquic_handshake.c +++ b/src/liblsquic/lsquic_handshake.c @@ -60,6 +60,7 @@ enum enc_sess_history_event ESHE_SET_STK = 'K', ESHE_SET_SCID = 'D', ESHE_SET_PROF = 'P', + ESHE_SET_SRST = 'S', }; #endif @@ -71,6 +72,7 @@ typedef struct hs_ctx_st HSET_SMHL = (1 << 1), /* smhl is set */ HSET_SCID = (1 << 2), HSET_IRTT = (1 << 3), + HSET_SRST = (1 << 4), } set; enum { HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */ @@ -95,6 +97,7 @@ typedef struct hs_ctx_st //unsigned char chlo_hash[32]; //SHA256 HASH of CHLO unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */ unsigned char pubs[32]; + unsigned char srst[SRST_LENGTH]; uint32_t rrej; struct lsquic_str ccs; @@ -684,6 +687,18 @@ static int parse_hs_data (lsquic_enc_session_t *enc_session, uint32_t tag, hs_ctx->sttl = get_tag_value_i64(val, len); break; + case QTAG_SRST: + if (len != sizeof(hs_ctx->srst)) + { + LSQ_INFO("Unexpected size of SRST: %u instead of %zu bytes", + len, sizeof(hs_ctx->srst)); + return -1; + } + memcpy(hs_ctx->srst, val, len); + hs_ctx->set |= HSET_SRST; + ESHIST_APPEND(enc_session, ESHE_SET_SRST); + break; + default: LSQ_DEBUG("Ignored tag '%.*s'", 4, (char *)&tag); break; @@ -848,7 +863,7 @@ struct message_writer memset(data_ptr + 4 + 2, 0, 2); \ (mw)->mw_entry = (void *) (data_ptr + 8); \ (mw)->mw_p = data_ptr + 8 + \ - n_entries * sizeof((mw)->mw_entry[0]); \ + (n_entries) * sizeof((mw)->mw_entry[0]); \ (mw)->mw_first_dummy_entry.tag = 0; \ (mw)->mw_first_dummy_entry.off = 0; \ (mw)->mw_prev_entry = &(mw)->mw_first_dummy_entry; \ @@ -1575,7 +1590,7 @@ lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session, } -static int +static enum enc_level lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session, enum lsquic_version version, uint8_t path_id, uint64_t pack_num, @@ -1587,6 +1602,7 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session, uint8_t md[HS_PKT_HASH_LENGTH]; uint128 hash; int ret; + enum enc_level enc_level; int is_chlo = (is_hello && ((IS_SERVER(enc_session)) == 0)); int is_shlo = (is_hello && (IS_SERVER(enc_session))); @@ -1620,7 +1636,7 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session, memcpy(buf_out, header, header_len); memcpy(buf_out + header_len, md, HS_PKT_HASH_LENGTH); memcpy(buf_out + header_len + HS_PKT_HASH_LENGTH, data, data_len); - return 0; + return ENC_LEV_CLEAR; } else { @@ -1635,12 +1651,14 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session, { enc_session->server_start_use_final_key = 1; } + enc_level = ENC_LEV_INIT; } else { LSQ_DEBUG("lsquic_enc_session_encrypt using 'F' key..."); key = enc_session->enc_ctx_f; memcpy(nonce, enc_session->enc_key_nonce_f, 4); + enc_level = ENC_LEV_FORW; } path_id_packet_number = combine_path_id_pack_num(path_id, pack_num); memcpy(nonce + 4, &path_id_packet_number, @@ -1651,8 +1669,13 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session, ret = aes_aead_enc(key, header, header_len, nonce, 12, data, data_len, buf_out + header_len, out_len); - *out_len += header_len; - return ret; + if (ret == 0) + { + *out_len += header_len; + return enc_level; + } + else + return -1; } } @@ -1801,6 +1824,19 @@ lsquic_enc_session_mem_used (struct lsquic_enc_session *enc_session) } +static int +lsquic_enc_session_verify_reset_token (lsquic_enc_session_t *enc_session, + const unsigned char *buf, size_t bufsz) +{ + if (bufsz == SRST_LENGTH + && (enc_session->hs_ctx.set & HSET_SRST) + && 0 == memcmp(buf, enc_session->hs_ctx.srst, SRST_LENGTH)) + return 0; + else + return -1; +} + + #ifdef NDEBUG const #endif @@ -1822,4 +1858,14 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 = .esf_gen_chlo = lsquic_enc_session_gen_chlo, .esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply, .esf_mem_used = lsquic_enc_session_mem_used, + .esf_verify_reset_token = lsquic_enc_session_verify_reset_token, +}; + + +const char *const lsquic_enclev2str[] = +{ + [ENC_LEV_UNSET] = "unset", + [ENC_LEV_CLEAR] = "clear", + [ENC_LEV_INIT] = "initial", + [ENC_LEV_FORW] = "forw-secure", }; diff --git a/src/liblsquic/lsquic_handshake.h b/src/liblsquic/lsquic_handshake.h index a7620c77f..fb65c4557 100644 --- a/src/liblsquic/lsquic_handshake.h +++ b/src/liblsquic/lsquic_handshake.h @@ -13,6 +13,7 @@ typedef struct lsquic_enc_session lsquic_enc_session_t; #define DNONC_LENGTH 32 #define aes128_key_len 16 #define aes128_iv_len 4 +#define SRST_LENGTH 16 enum handshake_error /* TODO: rename this enum */ { @@ -33,6 +34,8 @@ enum enc_level ENC_LEV_FORW, }; +extern const char *const lsquic_enclev2str[]; + /* client side need to store 0rtt info per STK */ typedef struct lsquic_session_cache_info_st { @@ -86,8 +89,8 @@ struct enc_session_funcs int (*esf_is_hsk_done)(lsquic_enc_session_t *enc_session); /* Encrypt buffer */ - int (*esf_encrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version, - uint8_t path_id, uint64_t pack_num, + enum enc_level (*esf_encrypt)(lsquic_enc_session_t *enc_session, + enum lsquic_version, uint8_t path_id, uint64_t pack_num, const unsigned char *header, size_t header_len, const unsigned char *data, size_t data_len, unsigned char *buf_out, size_t max_out_len, size_t *out_len, @@ -132,6 +135,10 @@ struct enc_session_funcs size_t (*esf_mem_used)(lsquic_enc_session_t *); + + int + (*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *, + size_t); }; extern diff --git a/src/liblsquic/lsquic_packet_common.c b/src/liblsquic/lsquic_packet_common.c index dbaa433ba..415652220 100644 --- a/src/liblsquic/lsquic_packet_common.c +++ b/src/liblsquic/lsquic_packet_common.c @@ -88,3 +88,14 @@ restore_packno (lsquic_packno_t cur_packno, return candidates[min]; } + + +const char *const lsquic_hety2str[] = +{ + [HETY_NOT_SET] = "Short", + [HETY_VERNEG] = "Version Negotiation", + [HETY_INITIAL] = "Initial", + [HETY_RETRY] = "Retry", + [HETY_HANDSHAKE] = "Handshake", + [HETY_0RTT] = "0-RTT", +}; diff --git a/src/liblsquic/lsquic_packet_common.h b/src/liblsquic/lsquic_packet_common.h index dd13c56bc..03512dc9b 100644 --- a/src/liblsquic/lsquic_packet_common.h +++ b/src/liblsquic/lsquic_packet_common.h @@ -116,10 +116,25 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit); #define QFRAME_RETRANSMITTABLE(frame_type) \ ((1 << (frame_type)) & QFRAME_RETRANSMITTABLE_MASK) -#define QUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \ +#define GQUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \ + 32 /* Nonce */ + 6 /* Packet Number */ ) -#define QUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */) +#define GQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */) + +#define GQUIC_IETF_LONG_HEADER_SIZE (1 /* Type */ + 4 /* Version */ \ + + 1 /* DCIL/SCIL */ + 8 /* CID */ + 4 /* Packet number */) + +/* XXX Nonce? */ +#define IQUIC_MAX_PUBHDR_SZ GQUIC_IETF_LONG_HEADER_SIZE + +#define IQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ \ + + 1 /* Packet number */) + +#define QUIC_MAX_PUBHDR_SZ (GQUIC_MAX_PUBHDR_SZ > IQUIC_MAX_PUBHDR_SZ \ + ? GQUIC_MAX_PUBHDR_SZ : IQUIC_MAX_PUBHDR_SZ) + +#define QUIC_MIN_PUBHDR_SZ (GQUIC_MIN_PUBHDR_SZ < IQUIC_MIN_PUBHDR_SZ \ + ? GQUIC_MIN_PUBHDR_SZ : IQUIC_MIN_PUBHDR_SZ) /* 12 bytes of FNV hash or encryption IV */ #define QUIC_PACKET_HASH_SZ 12 @@ -151,6 +166,19 @@ enum lsquic_packno_bits PACKNO_LEN_6 = 3, }; + +enum header_type +{ + HETY_NOT_SET, /* This value must be zero */ + HETY_VERNEG, + HETY_INITIAL, + HETY_RETRY, + HETY_HANDSHAKE, + HETY_0RTT, +}; + +extern const char *const lsquic_hety2str[]; + enum lsquic_packno_bits calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked, uint64_t n_in_flight); diff --git a/src/liblsquic/lsquic_packet_in.h b/src/liblsquic/lsquic_packet_in.h index e451a1c6c..1c5ca74d5 100644 --- a/src/liblsquic/lsquic_packet_in.h +++ b/src/liblsquic/lsquic_packet_in.h @@ -60,7 +60,9 @@ typedef struct lsquic_packet_in #define PIBIT_ENC_LEV_SHIFT 5 PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */ PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */ + PI_GQUIC = (1 << 7), } pi_flags:8; + enum header_type pi_header_type:8; /* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied * packet data, which is NOT TO BE MODIFIED. */ @@ -69,11 +71,19 @@ typedef struct lsquic_packet_in #define lsquic_packet_in_public_flags(p) ((p)->pi_data[0]) -#define lsquic_packet_in_is_prst(p) \ - (lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_RST) +#define lsquic_packet_in_is_gquic_prst(p) \ + (((p)->pi_flags & PI_GQUIC) \ + && (lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_RST)) + +#define lsquic_packet_in_is_verneg(p) \ + (((p)->pi_flags & PI_GQUIC) ? \ + lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_VERSION : \ + (p)->pi_header_type == HETY_VERNEG) #define lsquic_packet_in_packno_bits(p) \ - ((lsquic_packet_in_public_flags(p) >> 4) & 3) + (((p)->pi_flags & PI_GQUIC) ? \ + ((lsquic_packet_in_public_flags(p) >> 4) & 3) : \ + ((p)->pi_data[0] & 3)) #define lsquic_packet_in_upref(p) (++(p)->pi_refcnt) diff --git a/src/liblsquic/lsquic_packet_out.c b/src/liblsquic/lsquic_packet_out.c index e359c53a8..a42275681 100644 --- a/src/liblsquic/lsquic_packet_out.c +++ b/src/liblsquic/lsquic_packet_out.c @@ -22,6 +22,7 @@ #include "lsquic_stream.h" #include "lsquic_logger.h" #include "lsquic_ev_log.h" +#include "lsquic_conn.h" typedef char _stream_rec_arr_is_at_most_64bytes[ (sizeof(struct stream_rec_arr) <= 64)? 1: - 1]; @@ -212,12 +213,12 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out, lsquic_packet_out_t * lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid, - unsigned short max_size, enum lsquic_packno_bits bits, + const struct lsquic_conn *lconn, enum lsquic_packno_bits bits, const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce) { lsquic_packet_out_t *packet_out; enum packet_out_flags flags; - unsigned short header_size; + unsigned short header_size, max_size; flags = bits << POBIT_SHIFT; if (ver_tag) @@ -226,8 +227,22 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid, flags |= PO_NONCE; if (use_cid) flags |= PO_CONN_ID; + if ((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS) + flags |= PO_GQUIC; + if ( + 0 == (lconn->cn_flags & LSCONN_HANDSHAKE_DONE) + ) + { + flags |= PO_LONGHEAD; + if (!((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS)) + { + flags &= ~(3 << POBIT_SHIFT); + flags |= PACKNO_LEN_4 << POBIT_SHIFT; + } + } - header_size = lsquic_po_header_length(flags); + header_size = lsquic_po_header_length(lconn, flags); + max_size = lconn->cn_pack_size; if (header_size + QUIC_PACKET_HASH_SZ >= max_size) { errno = EINVAL; @@ -255,6 +270,8 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid, } memcpy(packet_out->po_nonce, nonce, 32); } + if (flags & PO_LONGHEAD) + packet_out->po_header_type = HETY_HANDSHAKE; return packet_out; } @@ -602,6 +619,8 @@ verify_srecs (lsquic_packet_out_t *packet_out) assert(packet_out->po_data_sz == off); } + + #endif diff --git a/src/liblsquic/lsquic_packet_out.h b/src/liblsquic/lsquic_packet_out.h index 733e425ac..a6e75030f 100644 --- a/src/liblsquic/lsquic_packet_out.h +++ b/src/liblsquic/lsquic_packet_out.h @@ -9,6 +9,7 @@ #include struct malo; +struct lsquic_conn; struct lsquic_engine_public; struct lsquic_mm; struct lsquic_stream; @@ -84,7 +85,12 @@ typedef struct lsquic_packet_out */ PO_SCHED = (1 <<14), /* On scheduled queue */ PO_SENT_SZ = (1 <<15), - } po_flags:16; + PO_LONGHEAD = (1 <<16), + PO_GQUIC = (1 <<17), /* Used for logging */ +#define POLEV_SHIFT 18 + PO_BITS_2 = (1 <<18), /* PO_BITS_2 and PO_BITS_3 encode the */ + PO_BITS_3 = (1 <<19), /* crypto level. Used for logging. */ + } po_flags; enum quic_ft_bit po_frame_types:16; /* Bitmask of QUIC_FRAME_* */ unsigned short po_data_sz; /* Number of usable bytes in data */ unsigned short po_enc_data_sz; /* Number of usable bytes in data */ @@ -95,6 +101,7 @@ typedef struct lsquic_packet_out * frames. */ unsigned short po_n_alloc; /* Total number of bytes allocated in po_data */ + enum header_type po_header_type:8; unsigned char *po_data; lsquic_packno_t po_ack2ed; /* If packet has ACK frame, value of * largest acked in it. @@ -135,33 +142,27 @@ typedef struct lsquic_packet_out (p)->po_flags |= ((b) & 0x3) << POBIT_SHIFT; \ } while (0) -#define lsquic_po_header_length(po_flags) ( \ - 1 /* Type */ \ - + (!!((po_flags) & PO_CONN_ID) << 3) /* Connection ID */ \ - + (!!((po_flags) & PO_VERSION) << 2) /* Version */ \ - + (!!((po_flags) & PO_NONCE) << 5) /* Nonce */ \ - + packno_bits2len(((po_flags) >> POBIT_SHIFT) & 0x3) /* Packet number */ \ -) +#define lsquic_po_header_length(lconn, po_flags) ( \ + lconn->cn_pf->pf_packout_header_size(lconn, po_flags)) -#define lsquic_packet_out_total_sz(p) \ - ((p)->po_data_sz + lsquic_po_header_length((p)->po_flags) \ - + QUIC_PACKET_HASH_SZ) +#define lsquic_packet_out_total_sz(lconn, p) (\ + lconn->cn_pf->pf_packout_size(lconn, p)) #if __GNUC__ #if LSQUIC_EXTRA_CHECKS -#define lsquic_packet_out_sent_sz(p) ( \ +#define lsquic_packet_out_sent_sz(lconn, p) ( \ __builtin_expect(((p)->po_flags & PO_SENT_SZ), 1) ? \ - (assert((p)->po_sent_sz == lsquic_packet_out_total_sz(p)), \ - (p)->po_sent_sz) : lsquic_packet_out_total_sz(p)) + (assert((p)->po_sent_sz == lsquic_packet_out_total_sz(lconn, p)), \ + (p)->po_sent_sz) : lsquic_packet_out_total_sz(lconn, p)) # else -#define lsquic_packet_out_sent_sz(p) ( \ +#define lsquic_packet_out_sent_sz(lconn, p) ( \ __builtin_expect(((p)->po_flags & PO_SENT_SZ), 1) ? \ - (p)->po_sent_sz : lsquic_packet_out_total_sz(p)) + (p)->po_sent_sz : lsquic_packet_out_total_sz(lconn, p)) #endif #else -# define lsquic_packet_out_sent_sz(p) ( \ +# define lsquic_packet_out_sent_sz(lconn, p) ( \ (p)->po_flags & PO_SENT_SZ ? \ - (p)->po_sent_sz : lsquic_packet_out_total_sz(p)) + (p)->po_sent_sz : lsquic_packet_out_total_sz(lconn, p)) #endif #define lsquic_packet_out_verneg(p) \ @@ -170,6 +171,13 @@ typedef struct lsquic_packet_out #define lsquic_packet_out_pubres(p) \ (((p)->po_flags & (PO_NOENCRYPT|PO_VERNEG)) == PO_NOENCRYPT ) +#define lsquic_packet_out_set_enc_level(p, level) do { \ + (p)->po_flags &= ~(3 << POLEV_SHIFT); \ + (p)->po_flags |= level << POLEV_SHIFT; \ +} while (0) + +#define lsquic_packet_out_enc_level(p) (((p)->po_flags >> POLEV_SHIFT) & 3) + struct packet_out_srec_iter { lsquic_packet_out_t *packet_out; struct stream_rec_arr *cur_srec_arr; @@ -185,7 +193,7 @@ posi_next (struct packet_out_srec_iter *posi); lsquic_packet_out_t * lsquic_packet_out_new (struct lsquic_mm *, struct malo *, int use_cid, - unsigned short size, enum lsquic_packno_bits, + const struct lsquic_conn *, enum lsquic_packno_bits, const lsquic_ver_tag_t *, const unsigned char *nonce); void diff --git a/src/liblsquic/lsquic_parse.h b/src/liblsquic/lsquic_parse.h index 66f241a10..54986a819 100644 --- a/src/liblsquic/lsquic_parse.h +++ b/src/liblsquic/lsquic_parse.h @@ -7,7 +7,10 @@ #include "lsquic_packet_common.h" struct lsquic_packet_in; +struct lsquic_packet_out; +struct packin_parse_state; struct stream_frame; +enum packet_out_flags; #define LSQUIC_PARSE_ACK_TIMESTAMPS 0 @@ -54,27 +57,17 @@ typedef lsquic_time_t /* gsf_: generate stream frame */ typedef size_t (*gsf_read_f) (void *stream, void *buf, size_t len, int *fin); -struct packin_parse_state { - const unsigned char *pps_p; /* Pointer to packet number */ - unsigned pps_nbytes; /* Number of bytes in packet number */ -}; - /* This structure contains functions that parse and generate packets and * frames in version-specific manner. To begin with, there is difference * between GQUIC's little-endian (Q038 and lower) and big-endian formats - * (Q039 and higher). + * (Q039 and higher). Q044 uses different format for packet headers. */ struct parse_funcs { - int - (*pf_gen_ver_nego_pkt) (unsigned char *buf, size_t bufsz, uint64_t conn_id, - unsigned version_bitmask); /* Return buf length */ int - (*pf_gen_reg_pkt_header) (unsigned char *buf, size_t bufsz, - const lsquic_cid_t *, const lsquic_ver_tag_t *, - const unsigned char *nonce, lsquic_packno_t, - enum lsquic_packno_bits); + (*pf_gen_reg_pkt_header) (const struct lsquic_conn *, + const struct lsquic_packet_out *, unsigned char *, size_t); void (*pf_parse_packet_in_finish) (struct lsquic_packet_in *packet_in, struct packin_parse_state *); @@ -154,28 +147,57 @@ struct parse_funcs (*pf_calc_stream_frame_header_sz) (uint32_t stream_id, uint64_t offset); void (*pf_turn_on_fin) (unsigned char *); + + size_t + (*pf_packout_size) (const struct lsquic_conn *, + const struct lsquic_packet_out *); + + size_t + (*pf_packout_header_size) (const struct lsquic_conn *, + enum packet_out_flags); }; extern const struct parse_funcs lsquic_parse_funcs_gquic_le; /* Q039 and later are big-endian: */ extern const struct parse_funcs lsquic_parse_funcs_gquic_Q039; +extern const struct parse_funcs lsquic_parse_funcs_gquic_Q044; #define select_pf_by_ver(ver) ( \ ((1 << (ver)) & (1 << LSQVER_035)) \ ? &lsquic_parse_funcs_gquic_le \ - : &lsquic_parse_funcs_gquic_Q039) + : (ver) < LSQVER_044 \ + ? &lsquic_parse_funcs_gquic_Q039 \ + : &lsquic_parse_funcs_gquic_Q044) -/* This function is QUIC-version independent */ int -parse_packet_in_begin (struct lsquic_packet_in *, size_t length, +lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *, size_t length, int is_server, struct packin_parse_state *); +int +lsquic_iquic_parse_packet_in_long_begin (struct lsquic_packet_in *, + size_t length, int is_server, struct packin_parse_state *state); + +int +lsquic_iquic_parse_packet_in_short_begin (struct lsquic_packet_in *, + size_t length, int is_server, struct packin_parse_state *state); + enum QUIC_FRAME_TYPE parse_frame_type_gquic_Q035_thru_Q039 (unsigned char first_byte); size_t calc_stream_frame_header_sz_gquic (uint32_t stream_id, uint64_t offset); +size_t +lsquic_gquic_packout_size (const struct lsquic_conn *, + const struct lsquic_packet_out *); + +size_t +lsquic_gquic_packout_header_size (const struct lsquic_conn *conn, + enum packet_out_flags flags); + +size_t +lsquic_gquic_po_header_sz (enum packet_out_flags flags); + /* This maps two bits as follows: * 00 -> 1 * 01 -> 2 diff --git a/src/liblsquic/lsquic_parse_Q044.c b/src/liblsquic/lsquic_parse_Q044.c new file mode 100644 index 000000000..f30f946bc --- /dev/null +++ b/src/liblsquic/lsquic_parse_Q044.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ +/* + * lsquic_parse_Q044.c -- Parsing functions specific to GQUIC Q044 + */ + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#else +#include +#endif + +#include "lsquic_types.h" +#include "lsquic_packet_common.h" +#include "lsquic_packet_in.h" +#include "lsquic_packet_out.h" +#include "lsquic_parse.h" +#include "lsquic_parse_common.h" +#include "lsquic_version.h" +#include "lsquic.h" +#include "lsquic_parse_gquic_be.h" +#include "lsquic_byteswap.h" +#include "lsquic_conn.h" + +#define LSQUIC_LOGGER_MODULE LSQLM_PARSE +#include "lsquic_logger.h" + + + + +static int +gen_short_pkt_header (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out, unsigned char *buf, + size_t bufsz) +{ + unsigned packno_len, need; + enum lsquic_packno_bits bits; + uint32_t packno; + + bits = (packet_out->po_flags >> POBIT_SHIFT) & 0x3; + packno_len = packno_bits2len(bits); + + need = 1 + 8 /* CID */ + packno_len; + + if (need > bufsz) + return -1; + + *buf++ = 0x30 | bits; + + memcpy(buf, &lconn->cn_cid, 8); + buf += 8; + + packno = packet_out->po_packno; +#if __BYTE_ORDER == __LITTLE_ENDIAN + packno = bswap_32(packno); +#endif + memcpy(buf, (unsigned char *) &packno + 4 - packno_len, packno_len); + + return need; +} + + +static size_t +gquic_Q044_packout_header_size_long (const struct lsquic_conn *lconn, + enum packet_out_flags flags) +{ + return GQUIC_IETF_LONG_HEADER_SIZE; +} + + +static const unsigned char header_type_to_bin[] = { + [HETY_NOT_SET] = 0x00, + [HETY_INITIAL] = 0x7F, + [HETY_RETRY] = 0x7E, + [HETY_HANDSHAKE] = 0x7D, + [HETY_0RTT] = 0x7C, +}; + + +static int +gen_long_pkt_header (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out, unsigned char *buf, + size_t bufsz) +{ + lsquic_ver_tag_t ver_tag; + unsigned char *p; + uint32_t packno; + size_t need; + + need = gquic_Q044_packout_header_size_long(lconn, packet_out->po_flags); + if (need > bufsz) + { + errno = EINVAL; + return -1; + } + + p = buf; + *p++ = 0x80 | header_type_to_bin[ packet_out->po_header_type ]; + ver_tag = lsquic_ver2tag(lconn->cn_version); + memcpy(p, &ver_tag, sizeof(ver_tag)); + p += sizeof(ver_tag); + + *p++ = 0x50; + + memcpy(p, &lconn->cn_cid, 8); + p += 8; + + packno = packet_out->po_packno; +#if __BYTE_ORDER == __LITTLE_ENDIAN + packno = bswap_32(packno); +#endif + memcpy(p, &packno, 4); + p += 4; + + + assert(need = p - buf); + return p - buf; +} + + +static int +gquic_Q044_gen_reg_pkt_header (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out, unsigned char *buf, + size_t bufsz) +{ + if (0 == (packet_out->po_flags & PO_LONGHEAD)) + return gen_short_pkt_header(lconn, packet_out, buf, bufsz); + else + return gen_long_pkt_header(lconn, packet_out, buf, bufsz); +} + + +static size_t +gquic_Q044_packout_header_size_short (const struct lsquic_conn *lconn, + enum packet_out_flags flags) +{ + enum lsquic_packno_bits bits; + size_t sz; + + bits = (flags >> POBIT_SHIFT) & 0x3; + sz = 1; /* Type */ + sz += 8; /* CID */ + sz += packno_bits2len(bits); + + return sz; +} + + +static size_t +gquic_Q044_packout_header_size (const struct lsquic_conn *lconn, + enum packet_out_flags flags) +{ + if (0 == (flags & PO_LONGHEAD)) + return gquic_Q044_packout_header_size_short(lconn, flags); + else + return gquic_Q044_packout_header_size_long(lconn, flags); +} + + +static size_t +gquic_Q044_packout_size (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out) +{ + size_t sz; + + if (0 == (packet_out->po_flags & PO_LONGHEAD)) + sz = gquic_Q044_packout_header_size_short(lconn, packet_out->po_flags); + else + sz = gquic_Q044_packout_header_size_long(lconn, packet_out->po_flags); + + sz += packet_out->po_data_sz; + sz += QUIC_PACKET_HASH_SZ; + + return sz; +} + + +const struct parse_funcs lsquic_parse_funcs_gquic_Q044 = +{ + .pf_gen_reg_pkt_header = gquic_Q044_gen_reg_pkt_header, + .pf_parse_packet_in_finish = gquic_be_parse_packet_in_finish, + .pf_gen_stream_frame = gquic_be_gen_stream_frame, + .pf_calc_stream_frame_header_sz = calc_stream_frame_header_sz_gquic, + .pf_parse_stream_frame = gquic_be_parse_stream_frame, + .pf_parse_ack_frame = gquic_be_parse_ack_frame, + .pf_gen_ack_frame = gquic_be_gen_ack_frame, + .pf_gen_stop_waiting_frame = gquic_be_gen_stop_waiting_frame, + .pf_parse_stop_waiting_frame = gquic_be_parse_stop_waiting_frame, + .pf_skip_stop_waiting_frame = gquic_be_skip_stop_waiting_frame, + .pf_gen_window_update_frame = gquic_be_gen_window_update_frame, + .pf_parse_window_update_frame = gquic_be_parse_window_update_frame, + .pf_gen_blocked_frame = gquic_be_gen_blocked_frame, + .pf_parse_blocked_frame = gquic_be_parse_blocked_frame, + .pf_gen_rst_frame = gquic_be_gen_rst_frame, + .pf_parse_rst_frame = gquic_be_parse_rst_frame, + .pf_gen_connect_close_frame = gquic_be_gen_connect_close_frame, + .pf_parse_connect_close_frame = gquic_be_parse_connect_close_frame, + .pf_gen_goaway_frame = gquic_be_gen_goaway_frame, + .pf_parse_goaway_frame = gquic_be_parse_goaway_frame, + .pf_gen_ping_frame = gquic_be_gen_ping_frame, +#ifndef NDEBUG + .pf_write_float_time16 = gquic_be_write_float_time16, + .pf_read_float_time16 = gquic_be_read_float_time16, +#endif + .pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039, + .pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039, + .pf_packout_size = gquic_Q044_packout_size, + .pf_packout_header_size = gquic_Q044_packout_header_size, +}; diff --git a/src/liblsquic/lsquic_parse_common.c b/src/liblsquic/lsquic_parse_common.c new file mode 100644 index 000000000..1e93bd2fe --- /dev/null +++ b/src/liblsquic/lsquic_parse_common.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ +#include +#include +#include + +#include "lsquic_types.h" +#include "lsquic_int_types.h" +#include "lsquic_packet_common.h" +#include "lsquic_packet_in.h" +#include "lsquic_parse_common.h" +#include "lsquic_parse.h" + + +int +lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length, + int is_server, struct packin_parse_state *state) +{ + if (length > 0) + { + switch (packet_in->pi_data[0] & 0x88) + { + case 0x88: + case 0x80: + return lsquic_iquic_parse_packet_in_long_begin(packet_in, length, + is_server, state); + case 0x08: + return lsquic_gquic_parse_packet_in_begin(packet_in, length, + is_server, state); + default: + return lsquic_iquic_parse_packet_in_short_begin(packet_in, length, + is_server, state); + } + } + else + return -1; +} + + +int +lsquic_iquic_parse_packet_in_begin (struct lsquic_packet_in *packet_in, + size_t length, int is_server, struct packin_parse_state *state) +{ + if (length > 0) + { + if (0 == (packet_in->pi_data[0] & 0x80)) + return lsquic_iquic_parse_packet_in_short_begin(packet_in, length, + is_server, state); + else + return lsquic_iquic_parse_packet_in_long_begin(packet_in, length, + is_server, state); + } + else + return -1; +} + + diff --git a/src/liblsquic/lsquic_parse_common.h b/src/liblsquic/lsquic_parse_common.h new file mode 100644 index 000000000..e02c75287 --- /dev/null +++ b/src/liblsquic/lsquic_parse_common.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ +/* + * lsquic_parse_common.h + */ + +#ifndef LSQUIC_PARSE_COMMON_H +#define LSQUIC_PARSE_COMMON_H 1 + +struct lsquic_packet_in; + +struct packin_parse_state { + const unsigned char *pps_p; /* Pointer to packet number */ + unsigned pps_nbytes; /* Number of bytes in packet number */ +}; + +int +lsquic_parse_packet_in_begin (struct lsquic_packet_in *, + size_t length, int is_server, struct packin_parse_state *); + +int +lsquic_iquic_parse_packet_in_begin (struct lsquic_packet_in *, + size_t length, int is_server, struct packin_parse_state *); + +#endif diff --git a/src/liblsquic/lsquic_parse_gquic_be.c b/src/liblsquic/lsquic_parse_gquic_be.c index be3bb86cf..a19071a48 100644 --- a/src/liblsquic/lsquic_parse_gquic_be.c +++ b/src/liblsquic/lsquic_parse_gquic_be.c @@ -20,7 +20,9 @@ #include "lsquic_alarmset.h" #include "lsquic_packet_common.h" #include "lsquic_packet_in.h" +#include "lsquic_packet_out.h" #include "lsquic_parse.h" +#include "lsquic_parse_common.h" #include "lsquic_rechist.h" #include "lsquic_sfcw.h" #include "lsquic_stream.h" @@ -28,7 +30,9 @@ #include "lsquic_malo.h" #include "lsquic_version.h" #include "lsquic.h" +#include "lsquic_conn.h" #include "lsquic_parse_gquic_be.h" /* Include to catch mismatches */ +#include "lsquic_byteswap.h" #define LSQUIC_LOGGER_MODULE LSQLM_PARSE #include "lsquic_logger.h" @@ -98,41 +102,20 @@ gquic_be_parse_packet_in_finish (lsquic_packet_in_t *packet_in, } -int -gquic_be_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id, - unsigned version_bitmask) -{ - int sz; - unsigned char *p = buf; - unsigned char *const pend = p + bufsz; - - CHECK_SPACE(1, p, pend); - *p = PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID; - ++p; - - CHECK_SPACE(8, p, pend); - memcpy(p, &conn_id, 8); - p += 8; - - sz = gen_ver_tags(p, pend - p, version_bitmask); - if (sz < 0) - return -1; - - return p + sz - buf; -} - - -int -gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id, - const lsquic_ver_tag_t *ver, const unsigned char *nonce, - lsquic_packno_t packno, enum lsquic_packno_bits bits) +static int +gquic_be_gen_reg_pkt_header (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out, unsigned char *buf, + size_t bufsz) { unsigned packnum_len, header_len; + enum lsquic_packno_bits bits; + lsquic_packno_t packno; unsigned char *p; + bits = lsquic_packet_out_packno_bits(packet_out); packnum_len = packno_bits2len(bits); - if (!(conn_id || ver || nonce)) + if (0 == (packet_out->po_flags & (PO_CONN_ID|PO_VERSION|PO_NONCE))) { header_len = 1 + packnum_len; if (header_len > bufsz) @@ -146,8 +129,16 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_ } else { - header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5) - + packnum_len; + const int + have_cid = packet_out->po_flags & PO_CONN_ID, + have_ver = packet_out->po_flags & PO_VERSION, + have_nonce = packet_out->po_flags & PO_NONCE; + header_len = 1 + + (!!have_cid << 3) + + (!!have_ver << 2) + + (!!have_nonce << 5) + + packnum_len + ; if (header_len > bufsz) { errno = ENOBUFS; @@ -156,31 +147,32 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_ p = buf; - *p = (!!conn_id << 3) + *p = (!!have_cid << 3) | (bits << 4) - | ((!!nonce) << 2) - | !!ver; + | ((!!have_nonce) << 2) + | !!have_ver; ++p; - if (conn_id) + if (have_cid) { - memcpy(p, conn_id , sizeof(*conn_id)); - p += sizeof(*conn_id); + memcpy(p, &lconn->cn_cid, sizeof(lconn->cn_cid)); + p += sizeof(lconn->cn_cid); } - if (ver) + if (have_ver) { - memcpy(p, ver, 4); + memcpy(p, &packet_out->po_ver_tag, 4); p += 4; } - if (nonce) + if (have_nonce) { - memcpy(p, nonce , 32); + memcpy(p, packet_out->po_nonce , 32); p += 32; } } + packno = packet_out->po_packno; #if __BYTE_ORDER == __LITTLE_ENDIAN packno = bswap_64(packno); #endif @@ -955,7 +947,6 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz, const struct parse_funcs lsquic_parse_funcs_gquic_Q039 = { - .pf_gen_ver_nego_pkt = gquic_be_gen_ver_nego_pkt, .pf_gen_reg_pkt_header = gquic_be_gen_reg_pkt_header, .pf_parse_packet_in_finish = gquic_be_parse_packet_in_finish, .pf_gen_stream_frame = gquic_be_gen_stream_frame, @@ -983,4 +974,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q039 = #endif .pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039, .pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039, + .pf_packout_size = lsquic_gquic_packout_size, + .pf_packout_header_size = lsquic_gquic_packout_header_size, }; diff --git a/src/liblsquic/lsquic_parse_gquic_be.h b/src/liblsquic/lsquic_parse_gquic_be.h index 446482552..3f2b30203 100644 --- a/src/liblsquic/lsquic_parse_gquic_be.h +++ b/src/liblsquic/lsquic_parse_gquic_be.h @@ -8,24 +8,6 @@ * and that would be a mess. */ -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) -#include -#define bswap_16 bswap16 -#define bswap_32 bswap32 -#define bswap_64 bswap64 -#elif defined(__APPLE__) -#include -#define bswap_16 OSSwapInt16 -#define bswap_32 OSSwapInt32 -#define bswap_64 OSSwapInt64 -#elif defined(WIN32) -#define bswap_16 _byteswap_ushort -#define bswap_32 _byteswap_ulong -#define bswap_64 _byteswap_uint64 -#else -#include -#endif - #define CHECK_SPACE(need, pstart, pend) \ do { if ((intptr_t) (need) > ((pend) - (pstart))) { return -1; } } while (0) @@ -58,11 +40,6 @@ int gquic_be_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id, unsigned version_bitmask); -int -gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id, - const lsquic_ver_tag_t *ver, const unsigned char *nonce, - lsquic_packno_t packno, enum lsquic_packno_bits bits); - int gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id, uint64_t offset, int fin, size_t size, diff --git a/src/liblsquic/lsquic_parse_gquic_common.c b/src/liblsquic/lsquic_parse_gquic_common.c index cf6e09e68..7110a5ce5 100644 --- a/src/liblsquic/lsquic_parse_gquic_common.c +++ b/src/liblsquic/lsquic_parse_gquic_common.c @@ -17,8 +17,11 @@ #include "lsquic_types.h" #include "lsquic_packet_common.h" +#include "lsquic_packet_out.h" #include "lsquic_packet_in.h" #include "lsquic_parse.h" +#include "lsquic_parse_common.h" +#include "lsquic_version.h" #include "lsquic.h" #define LSQUIC_LOGGER_MODULE LSQLM_PARSE @@ -35,8 +38,8 @@ * pf_parse_packet_in_finish() routine. */ int -parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length, - int is_server, struct packin_parse_state *state) +lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *packet_in, + size_t length, int is_server, struct packin_parse_state *state) { int nbytes; enum PACKET_PUBLIC_FLAGS public_flags; @@ -128,6 +131,7 @@ parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length, packet_in->pi_data_sz = length; packet_in->pi_refcnt = 0; packet_in->pi_received = 0; + packet_in->pi_flags |= PI_GQUIC; return 0; } @@ -462,3 +466,36 @@ acki2str (const struct ack_info *acki, size_t *sz) *sz = off; return buf; } + + +size_t +lsquic_gquic_po_header_sz (enum packet_out_flags flags) +{ + return 1 /* Type */ + + (!!(flags & PO_CONN_ID) << 3) /* Connection ID */ + + (!!(flags & PO_VERSION) << 2) /* Version */ + + (!!(flags & PO_NONCE) << 5) /* Nonce */ + + packno_bits2len((flags >> POBIT_SHIFT) & 0x3) /* Packet number */ + ; +} + + +size_t +lsquic_gquic_packout_size (const struct lsquic_conn *conn, + const struct lsquic_packet_out *packet_out) +{ + return lsquic_gquic_po_header_sz(packet_out->po_flags) + + packet_out->po_data_sz + + QUIC_PACKET_HASH_SZ + ; +} + + +size_t +lsquic_gquic_packout_header_size (const struct lsquic_conn *conn, + enum packet_out_flags flags) +{ + return lsquic_gquic_po_header_sz(flags); +} + + diff --git a/src/liblsquic/lsquic_parse_gquic_le.c b/src/liblsquic/lsquic_parse_gquic_le.c index 86fc40906..3ef3681f8 100644 --- a/src/liblsquic/lsquic_parse_gquic_le.c +++ b/src/liblsquic/lsquic_parse_gquic_le.c @@ -20,7 +20,9 @@ #include "lsquic_alarmset.h" #include "lsquic_packet_common.h" #include "lsquic_packet_in.h" +#include "lsquic_packet_out.h" #include "lsquic_parse.h" +#include "lsquic_parse_common.h" #include "lsquic_rechist.h" #include "lsquic_sfcw.h" #include "lsquic_stream.h" @@ -28,6 +30,7 @@ #include "lsquic_malo.h" #include "lsquic_version.h" #include "lsquic.h" +#include "lsquic_conn.h" #define LSQUIC_LOGGER_MODULE LSQLM_PARSE #include "lsquic_logger.h" @@ -118,41 +121,23 @@ gquic_le_parse_packet_in_finish (lsquic_packet_in_t *packet_in, static int -gquic_le_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id, - unsigned version_bitmask) -{ - int sz; - unsigned char *p = buf; - unsigned char *const pend = p + bufsz; - - CHECK_SPACE(1, p, pend); - *p = PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID; - ++p; - - CHECK_SPACE(8, p, pend); - memcpy(p, &conn_id, 8); - p += 8; - - sz = gen_ver_tags(p, pend - p, version_bitmask); - if (sz < 0) - return -1; - - return p + sz - buf; -} - - -static int -gquic_le_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id, - const lsquic_ver_tag_t *ver, const unsigned char *nonce, - lsquic_packno_t packno, enum lsquic_packno_bits bits) +gquic_le_gen_reg_pkt_header (const struct lsquic_conn *lconn, + const struct lsquic_packet_out *packet_out, unsigned char *buf, + size_t bufsz) { unsigned packnum_len, header_len; unsigned char *p; + enum lsquic_packno_bits bits; + bits = lsquic_packet_out_packno_bits(packet_out); packnum_len = packno_bits2len(bits); - header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5) - + packnum_len; + header_len = 1 + + (!!(packet_out->po_flags & PO_CONN_ID) << 3) + + (!!(packet_out->po_flags & PO_VERSION) << 2) + + (!!(packet_out->po_flags & PO_NONCE) << 5) + + packnum_len + ; if (header_len > bufsz) { errno = ENOBUFS; @@ -161,32 +146,32 @@ gquic_le_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_ p = buf; - *p = (!!conn_id << 3) + *p = (!!(packet_out->po_flags & PO_CONN_ID) << 3) | (bits << 4) - | ((!!nonce) << 2) - | !!ver; + | ((!!(packet_out->po_flags & PO_NONCE)) << 2) + | !!(packet_out->po_flags & PO_VERSION); ++p; - if (conn_id) + if (packet_out->po_flags & PO_CONN_ID) { - memcpy(p, conn_id , sizeof(*conn_id)); - p += sizeof(*conn_id); + memcpy(p, &lconn->cn_cid, sizeof(lconn->cn_cid)); + p += sizeof(lconn->cn_cid); } - if (ver) + if (packet_out->po_flags & PO_VERSION) { - memcpy(p, ver, 4); + memcpy(p, &packet_out->po_ver_tag, 4); p += 4; } - if (nonce) + if (packet_out->po_flags & PO_NONCE) { - memcpy(p, nonce , 32); + memcpy(p, packet_out->po_nonce, 32); p += 32; } /* ENDIAN */ - memcpy(p, &packno, packnum_len); + memcpy(p, &packet_out->po_packno, packnum_len); p += packnum_len; assert(p - buf == (intptr_t) header_len); @@ -832,7 +817,6 @@ gquic_le_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz, const struct parse_funcs lsquic_parse_funcs_gquic_le = { - .pf_gen_ver_nego_pkt = gquic_le_gen_ver_nego_pkt, .pf_gen_reg_pkt_header = gquic_le_gen_reg_pkt_header, .pf_parse_packet_in_finish = gquic_le_parse_packet_in_finish, .pf_gen_stream_frame = gquic_le_gen_stream_frame, @@ -860,4 +844,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_le = #endif .pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039, .pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039, + .pf_packout_size = lsquic_gquic_packout_size, + .pf_packout_header_size = lsquic_gquic_packout_header_size, }; diff --git a/src/liblsquic/lsquic_parse_iquic_common.c b/src/liblsquic/lsquic_parse_iquic_common.c new file mode 100644 index 000000000..93b843acc --- /dev/null +++ b/src/liblsquic/lsquic_parse_iquic_common.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ +#include +#include +#include +#include +#include + +#include + +#include "lsquic_types.h" +#include "lsquic_int_types.h" +#include "lsquic_packet_common.h" +#include "lsquic_packet_in.h" +#include "lsquic_parse_common.h" +#include "lsquic_parse.h" +#include "lsquic_version.h" +#include "lsquic.h" +#include "lsquic_logger.h" +#include "lsquic_byteswap.h" +#include "lsquic_str.h" +#include "lsquic_handshake.h" + + +static const enum header_type bin_2_header_type[0x100] = +{ + [0x80 | 0x7F] = HETY_INITIAL, + [0x80 | 0x7E] = HETY_RETRY, + [0x80 | 0x7D] = HETY_HANDSHAKE, + [0x80 | 0x7C] = HETY_0RTT, +}; + + +int +lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in, + size_t length, int is_server, struct packin_parse_state *state) +{ + const unsigned char *p = packet_in->pi_data; + const unsigned char *const end = p + length; + lsquic_ver_tag_t tag; + enum header_type header_type; + unsigned dcil, scil; + int verneg; + unsigned char first_byte; + const unsigned cid_len = 8; + + if (length < 6) + return -1; + first_byte = *p++; + + memcpy(&tag, p, 4); + p += 4; + verneg = 0 == tag; + if (!verneg) + { + header_type = bin_2_header_type[ first_byte ]; + if (!header_type) + return -1; + } + else + header_type = HETY_VERNEG; + + packet_in->pi_header_type = header_type; + + dcil = p[0] >> 4; + if (dcil) + dcil += 3; + scil = p[0] & 0xF; + if (scil) + scil += 3; + ++p; + + /* Chromium comments state that the client sends packets with destination + * CID of 8 bytes and source CID of 0 bytes and the server does it the + * other way around. + * + * XXX When IETF branch is merged, this check for Q044 will have to be + * moved to the pf_parse_packet_in_finish(). + */ + if (is_server) + { + if (!(dcil == cid_len && scil == 0)) + return -1; + } + else + { + if (!(dcil == 0 && scil == cid_len)) + return -1; + } + + const unsigned packet_len = 4; + /* XXX This checks both packet length or the first version of the version + * array in a version negotiation packet. This is because the sizes of + * the packet number field and the version tag are the same. The check + * will probably have to be split in the future. + */ + if (end - p < dcil + scil + packet_len) + return -1; + + memcpy(&packet_in->pi_conn_id, p, cid_len); + p += cid_len; + packet_in->pi_flags |= PI_CONN_ID; + + packet_in->pi_packno = 0; + + if (!verneg) + { + state->pps_p = p; + state->pps_nbytes = packet_len; + p += packet_len; + packet_in->pi_quic_ver = 1; + if (is_server || HETY_0RTT != header_type) + packet_in->pi_nonce = 0; + else + { + packet_in->pi_nonce = p - packet_in->pi_data; + p += 32; + } + } + else + { + if ((end - p) & 3) + return -1; + state->pps_p = NULL; + state->pps_nbytes = 0; + packet_in->pi_quic_ver = p - packet_in->pi_data; + p = packet_in->pi_data + length; + packet_in->pi_nonce = 0; + } + + packet_in->pi_header_sz = p - packet_in->pi_data; + packet_in->pi_frame_types = 0; + packet_in->pi_data_sz = length; + packet_in->pi_refcnt = 0; + packet_in->pi_received = 0; + + return 0; +} + + +int +lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in, + size_t length, int is_server, struct packin_parse_state *state) +{ + const unsigned char *p = packet_in->pi_data; + const unsigned char *const pend = packet_in->pi_data + length; + unsigned cid_len = 8; /* XXX this will need to be passed in */ + unsigned packet_len; + + if ((*p & 0x30) != 0x30 || (*p & 3) == 3) + return -1; + + packet_len = 1 << (*p & 3); + if (pend - p < 1 + cid_len + packet_len) + return -1; + + ++p; + + if (is_server) + { + memcpy(&packet_in->pi_conn_id, p, cid_len); + p += cid_len; + packet_in->pi_flags = PI_CONN_ID; + } + + /* We could read in the packet number here, but we choose to do it in + * the finish() call instead. + */ + packet_in->pi_packno = 0; + state->pps_p = p; + state->pps_nbytes = packet_len; + p += packet_len; + + packet_in->pi_header_type = HETY_NOT_SET; + packet_in->pi_quic_ver = 0; + packet_in->pi_nonce = 0; + packet_in->pi_header_sz = p - packet_in->pi_data; + packet_in->pi_frame_types = 0; + packet_in->pi_data_sz = length; + packet_in->pi_refcnt = 0; + packet_in->pi_received = 0; + + return 0; +} + + diff --git a/src/liblsquic/lsquic_qtags.h b/src/liblsquic/lsquic_qtags.h index d81bc7549..4a4826f14 100644 --- a/src/liblsquic/lsquic_qtags.h +++ b/src/liblsquic/lsquic_qtags.h @@ -56,4 +56,7 @@ */ #define QTAG_NSTP TAG('N', 'S', 'T', 'P') +/* Stateless reset token. Used in Q044 and later. */ +#define QTAG_SRST TAG('S', 'R', 'S', 'T') + #endif diff --git a/src/liblsquic/lsquic_send_ctl.c b/src/liblsquic/lsquic_send_ctl.c index a2b1a8ef0..84a3ab606 100644 --- a/src/liblsquic/lsquic_send_ctl.c +++ b/src/liblsquic/lsquic_send_ctl.c @@ -45,6 +45,10 @@ #define MIN_RTO_DELAY 1000000 /* Microseconds */ #define N_NACKS_BEFORE_RETX 3 +#define packet_out_total_sz(p) \ + lsquic_packet_out_total_sz(ctl->sc_conn_pub->lconn, p) +#define packet_out_sent_sz(p) \ + lsquic_packet_out_sent_sz(ctl->sc_conn_pub->lconn, p) enum retx_mode { RETX_MODE_HANDSHAKE, @@ -402,11 +406,11 @@ send_ctl_unacked_append (struct lsquic_send_ctl *ctl, struct lsquic_packet_out *packet_out) { TAILQ_INSERT_TAIL(&ctl->sc_unacked_packets, packet_out, po_next); - ctl->sc_bytes_unacked_all += lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_unacked_all += packet_out_total_sz(packet_out); ctl->sc_n_in_flight_all += 1; if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK) { - ctl->sc_bytes_unacked_retx += lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_unacked_retx += packet_out_total_sz(packet_out); ++ctl->sc_n_in_flight_retx; } } @@ -434,7 +438,7 @@ send_ctl_sched_Xpend_common (struct lsquic_send_ctl *ctl, { packet_out->po_flags |= PO_SCHED; ++ctl->sc_n_scheduled; - ctl->sc_bytes_scheduled += lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_scheduled += packet_out_total_sz(packet_out); lsquic_send_ctl_sanity_check(ctl); } @@ -465,7 +469,7 @@ send_ctl_sched_remove (struct lsquic_send_ctl *ctl, packet_out->po_flags &= ~PO_SCHED; assert(ctl->sc_n_scheduled); --ctl->sc_n_scheduled; - ctl->sc_bytes_scheduled -= lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_scheduled -= packet_out_total_sz(packet_out); lsquic_send_ctl_sanity_check(ctl); } @@ -479,7 +483,7 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl, packet_out->po_packno, lsquic_frame_types_to_str(frames, sizeof(frames), packet_out->po_frame_types)); if (account) - ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_out -= packet_out_total_sz(packet_out); lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno); send_ctl_unacked_append(ctl, packet_out); if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK) @@ -540,7 +544,7 @@ send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl, unsigned packet_sz; assert(ctl->sc_n_in_flight_all); - packet_sz = lsquic_packet_out_sent_sz(packet_out); + packet_sz = packet_out_sent_sz(packet_out); send_ctl_unacked_remove(ctl, packet_out, packet_sz); if (packet_out->po_flags & PO_ENCRYPTED) send_ctl_release_enc_data(ctl, packet_out); @@ -740,7 +744,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl, if (!now) now = lsquic_time_now(); after_checks: - packet_sz = lsquic_packet_out_sent_sz(packet_out); + packet_sz = packet_out_sent_sz(packet_out); ctl->sc_largest_acked_packno = packet_out->po_packno; ctl->sc_largest_acked_sent_time = packet_out->po_sent; send_ctl_unacked_remove(ctl, packet_out, packet_sz); @@ -856,7 +860,7 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl) while ((packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets))) { TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next); - ctl->sc_bytes_unacked_all -= lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_unacked_all -= packet_out_total_sz(packet_out); lsquic_packet_out_destroy(packet_out, ctl->sc_enpub); --ctl->sc_n_in_flight_all; } @@ -1008,7 +1012,7 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl) count = 0, bytes = 0; TAILQ_FOREACH(packet_out, &ctl->sc_unacked_packets, po_next) { - bytes += lsquic_packet_out_sent_sz(packet_out); + bytes += packet_out_sent_sz(packet_out); ++count; } assert(count == ctl->sc_n_in_flight_all); @@ -1018,7 +1022,7 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl) TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next) { assert(packet_out->po_flags & PO_SCHED); - bytes += lsquic_packet_out_total_sz(packet_out); + bytes += packet_out_total_sz(packet_out); ++count; } assert(count == ctl->sc_n_scheduled); @@ -1090,7 +1094,7 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl) } send_ctl_sched_remove(ctl, packet_out); - ctl->sc_bytes_out += lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_out += packet_out_total_sz(packet_out); return packet_out; } @@ -1100,7 +1104,7 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl, lsquic_packet_out_t *packet_out) { send_ctl_sched_prepend(ctl, packet_out); - ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out); + ctl->sc_bytes_out -= packet_out_total_sz(packet_out); LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno); #if LSQUIC_SEND_STATS ++ctl->sc_stats.n_delayed; @@ -1139,7 +1143,7 @@ send_ctl_allocate_packet (lsquic_send_ctl_t *ctl, enum lsquic_packno_bits bits, packet_out = lsquic_packet_out_new(&ctl->sc_enpub->enp_mm, ctl->sc_conn_pub->packet_out_malo, - !(ctl->sc_flags & SC_TCID0), ctl->sc_pack_size, bits, + !(ctl->sc_flags & SC_TCID0), ctl->sc_conn_pub->lconn, bits, ctl->sc_ver_neg->vn_tag, NULL); if (!packet_out) return NULL; diff --git a/src/liblsquic/lsquic_stream.c b/src/liblsquic/lsquic_stream.c index a1496b3fc..2cfe16ec4 100644 --- a/src/liblsquic/lsquic_stream.c +++ b/src/liblsquic/lsquic_stream.c @@ -1369,8 +1369,10 @@ lsquic_stream_flush_threshold (const struct lsquic_stream *stream) flags = bits << POBIT_SHIFT; if (!(stream->conn_pub->lconn->cn_flags & LSCONN_TCID0)) flags |= PO_CONN_ID; + if (LSQUIC_STREAM_HANDSHAKE == stream->id) + flags |= PO_LONGHEAD; - packet_header_sz = lsquic_po_header_length(flags); + packet_header_sz = lsquic_po_header_length(stream->conn_pub->lconn, flags); stream_header_sz = stream->conn_pub->lconn->cn_pf ->pf_calc_stream_frame_header_sz(stream->id, stream->tosend_off); @@ -1542,6 +1544,9 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx, const size_t size) packet_out = get_packet[hsk](send_ctl, need_at_least, stream); if (!packet_out) return SWTP_STOP; + if (hsk) + packet_out->po_header_type = stream->tosend_off == 0 + ? HETY_INITIAL : HETY_HANDSHAKE; off = packet_out->po_data_sz; len = pf->pf_gen_stream_frame( diff --git a/src/liblsquic/lsquic_version.c b/src/liblsquic/lsquic_version.c index 17f7e5775..26c3fcad6 100644 --- a/src/liblsquic/lsquic_version.c +++ b/src/liblsquic/lsquic_version.c @@ -11,6 +11,10 @@ static const unsigned char version_tags[N_LSQVER][4] = [LSQVER_035] = { 'Q', '0', '3', '5', }, [LSQVER_039] = { 'Q', '0', '3', '9', }, [LSQVER_043] = { 'Q', '0', '4', '3', }, + [LSQVER_044] = { 'Q', '0', '4', '4', }, +#if LSQUIC_USE_Q098 + [LSQVER_098] = { 'Q', '0', '9', '8', }, +#endif }; @@ -58,11 +62,15 @@ const char *const lsquic_ver2str[N_LSQVER] = { [LSQVER_035] = "Q035", [LSQVER_039] = "Q039", [LSQVER_043] = "Q043", + [LSQVER_044] = "Q044", +#if LSQUIC_USE_Q098 + [LSQVER_098] = "Q098", +#endif }; int -gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned version_bitmask) +lsquic_gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned version_bitmask) { unsigned n; lsquic_ver_tag_t tag; diff --git a/src/liblsquic/lsquic_version.h b/src/liblsquic/lsquic_version.h index 82bd0cd9b..5ea7c3856 100644 --- a/src/liblsquic/lsquic_version.h +++ b/src/liblsquic/lsquic_version.h @@ -17,6 +17,6 @@ lsquic_tag2ver (uint32_t ver_tag); extern const char *const lsquic_ver2str[]; int -gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned versions); +lsquic_gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned versions); #endif diff --git a/test/unittests/test_parse_packet_in.c b/test/unittests/test_parse_packet_in.c index 8f3691471..9ce9dcd4a 100644 --- a/test/unittests/test_parse_packet_in.c +++ b/test/unittests/test_parse_packet_in.c @@ -11,8 +11,10 @@ #include "lsquic_int_types.h" #include "lsquic_packet_common.h" #include "lsquic_parse.h" +#include "lsquic_parse_common.h" #include "lsquic_packet_in.h" #include "lsquic_engine_public.h" +#include "lsquic_version.h" struct parse_packet_in_test @@ -22,8 +24,7 @@ struct parse_packet_in_test unsigned char ppit_buf[0x100]; unsigned ppit_bufsz; int ppit_is_server; - const struct parse_funcs * - ppit_pf; + enum lsquic_version ppit_version; /* Output */ int ppit_retval; int ppit_pi_flags; @@ -49,7 +50,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -72,7 +73,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 2 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -95,7 +96,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -118,7 +119,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -138,7 +139,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 0 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, @@ -157,7 +158,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 0 + 0 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, @@ -179,7 +180,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = -1, }, @@ -198,7 +199,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 32+ 2 + 7, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -223,7 +224,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 32+ 1 + 7, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -247,7 +248,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -270,7 +271,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -294,7 +295,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -315,7 +316,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 8, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_035), + .ppit_version = LSQVER_035, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -340,7 +341,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -363,7 +364,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 2 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -386,7 +387,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -409,7 +410,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -429,7 +430,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 0 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, @@ -448,7 +449,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 0 + 0 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, @@ -470,7 +471,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = -1, }, @@ -489,7 +490,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 32+ 2 + 7, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -514,7 +515,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 32+ 1 + 7, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -538,7 +539,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -561,7 +562,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -585,7 +586,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -606,7 +607,7 @@ static const struct parse_packet_in_test tests[] = { }, .ppit_bufsz = 1 + 8 + 8, .ppit_is_server = 0, - .ppit_pf = select_pf_by_ver(LSQVER_039), + .ppit_version = LSQVER_039, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, @@ -616,6 +617,83 @@ static const struct parse_packet_in_test tests[] = { .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, + + { .ppit_lineno = __LINE__, + .ppit_buf = { + /* Flags: */ 0x30, + /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, + /* Packet number: */0x9B, + /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', + }, + .ppit_bufsz = 1 + 8 + 1 + 7, + .ppit_is_server = 1, + .ppit_version = LSQVER_044, + .ppit_retval = 0, + .ppit_pi_flags = PI_CONN_ID, + .ppit_conn_id = 0x8070605004030201, + .ppit_packno = 0x9B, + .ppit_header_sz = 1 + 8 + 1, + .ppit_data_sz = 1 + 8 + 1 + 7, + .ppit_quic_ver = 0, + .ppit_nonce = 0, + }, + + { .ppit_lineno = __LINE__, + .ppit_buf = { + /* Flags: */ 0x32, + /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, + /* Packet number: */0x9B, 0x03, 0x02, 0x01, + /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', + }, + .ppit_bufsz = 1 + 8 + 4 + 7, + .ppit_is_server = 1, + .ppit_version = LSQVER_044, + .ppit_retval = 0, + .ppit_pi_flags = PI_CONN_ID, + .ppit_conn_id = 0x8070605004030201, + .ppit_packno = 0x9B030201, + .ppit_header_sz = 1 + 8 + 4, + .ppit_data_sz = 1 + 8 + 4 + 7, + .ppit_quic_ver = 0, + .ppit_nonce = 0, + }, + + { .ppit_lineno = __LINE__, + .ppit_buf = { + /* Flags: */ 0x30 + | 0x3 /* <--- Invalid type */, + /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, + /* Packet number: */0x9B, + /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', + }, + .ppit_bufsz = 1 + 8 + 1 + 7, + .ppit_is_server = 1, + .ppit_version = LSQVER_044, + .ppit_retval = -1, + }, + + { .ppit_lineno = __LINE__, + .ppit_buf = { + /* Type: */ 0xFF /* Initial */, + /* Version: */ 'Q', '0', '4', '4', + /* DCIL/SCIL: */ 0x5 /* DCIL */ << 4 | 0x0 /* SCIL */, + /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, + /* Packet number: */0x21, 0x22, 0x23, 0x34, + /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', + }, + .ppit_bufsz = 1 + 4 + 1 + 8 + 4 + 7, + .ppit_is_server = 1, + .ppit_version = LSQVER_044, + .ppit_retval = 0, + .ppit_pi_flags = PI_CONN_ID, + .ppit_conn_id = 0x8070605004030201, + .ppit_packno = 0x21222334, + .ppit_header_sz = 1 + 4 + 1 + 8 + 4, + .ppit_data_sz = 1 + 4 + 1 + 8 + 4 + 7, + .ppit_quic_ver = 1, + .ppit_nonce = 0, + }, + }; @@ -630,10 +708,47 @@ run_ppi_test (struct lsquic_mm *mm, const struct parse_packet_in_test *ppit) packet_in->pi_data = lsquic_mm_get_1370(mm); packet_in->pi_flags |= PI_OWN_DATA; memcpy(packet_in->pi_data, ppit->ppit_buf, ppit->ppit_bufsz); - s = parse_packet_in_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, &ppstate); + + /* Server should be able to differentiate different header formats + * because it expect the connection ID to be there, while the client + * needs help. + */ + if (ppit->ppit_is_server && + /* In addition, some tests verify parsing of GQUIC packets in + * server mode where there is no connection ID. This is for + * completeness and does not represent a real-life scenario, + * as the server will always require the client to send the + * connection ID. + */ + !(!(ppit->ppit_pi_flags & PI_CONN_ID) + && ppit->ppit_version < LSQVER_044)) + s = lsquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, + ppit->ppit_is_server, &ppstate); + else if (ppit->ppit_version < LSQVER_044) + s = lsquic_gquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, + ppit->ppit_is_server, &ppstate); + else + s = lsquic_iquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, + ppit->ppit_is_server, &ppstate); + assert(s == ppit->ppit_retval); if (0 == s) - ppit->ppit_pf->pf_parse_packet_in_finish(packet_in, &ppstate); + { + const struct parse_funcs *pf; + if (ppit->ppit_quic_ver && ppit->ppit_is_server /* Server packets + with version are version negotiation packets. */) + { + uint32_t tag; + enum lsquic_version ver; + assert(packet_in->pi_quic_ver); + memcpy(&tag, packet_in->pi_data + packet_in->pi_quic_ver, 4); + ver = lsquic_tag2ver(tag); + assert((enum lsquic_version) -1 != ver); + assert(ver == ppit->ppit_version); + } + pf = select_pf_by_ver(ppit->ppit_version); + pf->pf_parse_packet_in_finish(packet_in, &ppstate); + } if (0 == s) { diff --git a/test/unittests/test_reg_pkt_headergen.c b/test/unittests/test_reg_pkt_headergen.c index 7012a88de..793bd808c 100644 --- a/test/unittests/test_reg_pkt_headergen.c +++ b/test/unittests/test_reg_pkt_headergen.c @@ -8,10 +8,12 @@ #endif #include "lsquic_types.h" +#include "lsquic.h" #include "lsquic_alarmset.h" #include "lsquic_packet_common.h" +#include "lsquic_packet_out.h" +#include "lsquic_conn.h" #include "lsquic_parse.h" -#include "lsquic.h" struct test { /* Inputs. */ @@ -232,11 +234,23 @@ run_test (int i) { const struct test *const test = &tests[i]; + struct lsquic_packet_out packet_out = + { + .po_flags = (test->cid ? PO_CONN_ID : 0) + | (test->ver.val ? PO_VERSION : 0) + | (test->nonce ? PO_NONCE: 0) + , + .po_nonce = (unsigned char *) test->nonce, + .po_ver_tag = test->ver.val, + .po_packno = test->packno, + }; + lsquic_packet_out_set_packno_bits(&packet_out, test->bits); + + struct lsquic_conn lconn = { .cn_cid = test->cid, }; + unsigned char out[QUIC_MAX_PUBHDR_SZ]; - int len = test->pf->pf_gen_reg_pkt_header(out, sizeof(out), - (test->cid ? &test->cid : NULL), - (test->ver.val ? &test->ver.val : NULL), - (unsigned char *) test->nonce, test->packno, test->bits); + int len = test->pf->pf_gen_reg_pkt_header(&lconn, &packet_out, out, + sizeof(out)); assert(("Packet length is correct", len == test->len)); diff --git a/test/unittests/test_some_packets.c b/test/unittests/test_some_packets.c index 0f41bc526..557b53eb7 100644 --- a/test/unittests/test_some_packets.c +++ b/test/unittests/test_some_packets.c @@ -62,6 +62,7 @@ lsquic_stream_tosend_sz (const lsquic_stream_t *stream) static int make_complex_packet(unsigned char *pkt_buf, int max_buf_len) { +#if 0 /* What is this function testing? Seems useless. */ unsigned char *p = pkt_buf; unsigned char *const pend = p + 1500; lsquic_stream_t *stream = lsquic_stream_new(12345, NULL, NULL, NULL, 0, 0); @@ -90,6 +91,8 @@ static int make_complex_packet(unsigned char *pkt_buf, int max_buf_len) free(stream); return p - pkt_buf; +#endif + return 0; } diff --git a/test/unittests/test_ver_nego.c b/test/unittests/test_ver_nego.c index ecdda37c8..68660cef5 100644 --- a/test/unittests/test_ver_nego.c +++ b/test/unittests/test_ver_nego.c @@ -13,12 +13,12 @@ #include "lsquic_alarmset.h" #include "lsquic_packet_common.h" #include "lsquic_parse.h" +#include "lsquic_parse_common.h" #include "lsquic_mm.h" #include "lsquic_packet_in.h" #include "lsquic_engine_public.h" #include "lsquic_version.h" -static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_035); /* The struct is used to test both generation and parsing of version @@ -100,7 +100,7 @@ test_parsing_ver_nego (const struct gen_ver_nego_test *gvnt) packet_in->pi_data = lsquic_mm_get_1370(&mm); packet_in->pi_flags |= PI_OWN_DATA; memcpy(packet_in->pi_data, gvnt->gvnt_buf, gvnt->gvnt_len); - s = parse_packet_in_begin(packet_in, gvnt->gvnt_len, 0, &ppstate); + s = lsquic_parse_packet_in_begin(packet_in, gvnt->gvnt_len, 0, &ppstate); assert(s == 0); for (s = packet_in_ver_first(packet_in, &vi, &ver_tag); s; @@ -119,32 +119,12 @@ test_parsing_ver_nego (const struct gen_ver_nego_test *gvnt) } -static void -run_gvnt (int i) -{ - const struct gen_ver_nego_test *const gvnt = &tests[i]; - - unsigned char out[0x40]; - assert(sizeof(out) <= sizeof(gvnt->gvnt_buf)); /* Internal sanity check */ - int len = pf->pf_gen_ver_nego_pkt(out, gvnt->gvnt_bufsz, gvnt->gvnt_cid, - gvnt->gvnt_versions); - - assert(("Packet length is correct", len == gvnt->gvnt_len)); - - if (gvnt->gvnt_len > 0) - { - assert(("Packet contents are correct", - 0 == memcmp(out, gvnt->gvnt_buf, gvnt->gvnt_len))); - test_parsing_ver_nego(gvnt); - } -} - - int main (void) { unsigned i; for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) - run_gvnt(i); + if (tests[i].gvnt_len > 0) + test_parsing_ver_nego(&tests[i]); return 0; }