/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ #include #include #include #include #include #include "lsquic.h" #include "lsquic_mm.h" #include "lsquic_types.h" #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 { int ppit_lineno; /* Input */ unsigned char ppit_buf[0x100]; unsigned ppit_bufsz; int ppit_is_server; enum lsquic_version ppit_version; /* Output */ int ppit_retval; int ppit_pi_flags; uint64_t ppit_conn_id; lsquic_packno_t ppit_packno; unsigned short ppit_header_sz; unsigned short ppit_data_sz; unsigned char ppit_quic_ver; unsigned char ppit_nonce; }; static const struct parse_packet_in_test tests[] = { /* * BIG-ENDIAN TESTS: */ { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x73, .ppit_header_sz = 1 + 8 + 4 + 1, .ppit_data_sz = 1 + 8 + 4 + 1 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| 0x10 /* 2-byte packet number */| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, 0x64, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 2 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x7364, .ppit_header_sz = 1 + 8 + 4 + 2, .ppit_data_sz = 1 + 8 + 4 + 2 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| 0x20 /* 4-byte packet number */| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, 0x64, 0x55, 0x46, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x73645546, .ppit_header_sz = 1 + 8 + 4 + 4, .ppit_data_sz = 1 + 8 + 4 + 4 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| 0x30 /* 6-byte packet number */| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, 0x64, 0x55, 0x46, 0x37, 0x28, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x736455463728, .ppit_header_sz = 1 + 8 + 4 + 6, .ppit_data_sz = 1 + 8 + 4 + 6 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, /* Same as above minus connection ID */ .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 0 + 4 + 1 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, .ppit_packno = 0x73, .ppit_header_sz = 1 + 0 + 4 + 1, .ppit_data_sz = 1 + 0 + 4 + 1 + 7, .ppit_quic_ver = 1 + 0, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, /* Same as above minus version */ .ppit_buf = { /* Flags: */ 0, /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 0 + 0 + 1 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = 0, .ppit_conn_id = 0, .ppit_packno = 0x73, .ppit_header_sz = 1 + 0 + 0 + 1, .ppit_data_sz = 1 + 0 + 0 + 1 + 7, .ppit_quic_ver = 0, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = -1, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_NONCE| 0x10 /* 2-byte packet number */| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Nonce: */ 000, 001, 002, 003, 004, 005, 006, 007, 010, 011, 012, 013, 014, 015, 016, 017, 020, 021, 022, 023, 024, 025, 026, 027, 030, 031, 032, 033, 034, 035, 036, 037, /* Packet #: */ 0x73, 0x64, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 32+ 2 + 7, .ppit_is_server = 0, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x7364, .ppit_header_sz = 1 + 8 + 32+ 2, .ppit_data_sz = 1 + 8 + 32+ 2 + 7, .ppit_quic_ver = 0, .ppit_nonce = 1 + 8, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_NONCE| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Nonce: */ 000, 001, 002, 003, 004, 005, 006, 007, 010, 011, 012, 013, 014, 015, 016, 017, 020, 021, 022, 023, 024, 025, 026, 027, 030, 031, 032, 033, 034, 035, 036, 037, /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 32+ 1 + 7, .ppit_is_server = 0, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x73, .ppit_header_sz = 1 + 8 + 32+ 1, .ppit_data_sz = 1 + 8 + 32+ 1 + 7, .ppit_quic_ver = 0, .ppit_nonce = 1 + 8, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| 0x20 /* 4-byte packet number */| PACKET_PUBLIC_FLAGS_NONCE| /* Nonce flag is ignored by server */ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, 0x64, 0x55, 0x46, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 4 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x73645546, .ppit_header_sz = 1 + 8 + 4 + 4, .ppit_data_sz = 1 + 8 + 4 + 4 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| PACKET_PUBLIC_FLAGS_NONCE| /* Nonce flag is ignored by server */ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 1 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x73, .ppit_header_sz = 1 + 8 + 4 + 1, .ppit_data_sz = 1 + 8 + 4 + 1 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| 0x30 /* 6-byte packet number */| PACKET_PUBLIC_FLAGS_NONCE| /* Nonce flag is ignored by server */ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Version: */ 'Q', '0', '4', '3', /* Packet #: */ 0x73, 0x64, 0x55, 0x46, 0x37, 0x28, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_bufsz = 1 + 8 + 4 + 6 + 7, .ppit_is_server = 1, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0x736455463728, .ppit_header_sz = 1 + 8 + 4 + 6, .ppit_data_sz = 1 + 8 + 4 + 6 + 7, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ PACKET_PUBLIC_FLAGS_VERSION| PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID, /* CID: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* Versions: */ 'Q', '0', '4', '0', 'Q', '0', '4', '3', }, .ppit_bufsz = 1 + 8 + 8, .ppit_is_server = 0, .ppit_version = LSQVER_043, .ppit_retval = 0, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x5500000000000000, .ppit_packno = 0, .ppit_header_sz = 1 + 8 + 8, .ppit_data_sz = 1 + 8 + 8, .ppit_quic_ver = 1 + 8, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ 0x40, /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, /* Packet number: */0x9B, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_version = LSQVER_046, .ppit_retval = 0, .ppit_is_server = 1, .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_bufsz = 1 + 8 + 1 + 7, .ppit_quic_ver = 0, .ppit_nonce = 0, }, { .ppit_lineno = __LINE__, .ppit_buf = { /* Flags: */ 0x43, /* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, /* Packet number: */0x9B, 0x03, 0x02, 0x01, /* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D', }, .ppit_version = LSQVER_046, .ppit_retval = 0, .ppit_packno = 0x9B030201, .ppit_is_server = 1, .ppit_header_sz = 1 + 8 + 4, .ppit_bufsz = 1 + 8 + 4 + 7, .ppit_data_sz = 1 + 8 + 4 + 7, .ppit_pi_flags = PI_CONN_ID, .ppit_conn_id = 0x8070605004030201, .ppit_quic_ver = 0, .ppit_nonce = 0, }, /* TODO: check invalid type in finish() -- convert the latter to return * status instead of being void function. */ #if 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, }, #endif { .ppit_lineno = __LINE__, .ppit_buf = { /* Type: */ 0x83 /* Initial */, /* Version: */ 'Q', '0', '4', '6', /* 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_046, .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, }, }; static void run_ppi_test (struct lsquic_mm *mm, const struct parse_packet_in_test *ppit) { int s; lsquic_packet_in_t *packet_in; struct packin_parse_state ppstate; packet_in = lsquic_mm_get_packet_in(mm); packet_in->pi_data = lsquic_mm_get_packet_in_buf(mm, 1370); packet_in->pi_flags |= PI_OWN_DATA; memcpy(packet_in->pi_data, ppit->ppit_buf, ppit->ppit_bufsz); /* 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_046)) s = lsquic_parse_packet_in_server_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, 8, &ppstate); else if (ppit->ppit_version < LSQVER_046) s = lsquic_gquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, -1 /* GQUIC does not use it */, &ppstate); else if (ppit->ppit_version == LSQVER_046) s = lsquic_Q046_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, 8, &ppstate); else s = lsquic_ietf_v1_parse_packet_in_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, 8, &ppstate); assert(s == ppit->ppit_retval); if (0 == s) { 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) { if (ppit->ppit_conn_id) { lsquic_cid_t cid; memset(&cid, 0, sizeof(cid)); cid.len = sizeof(ppit->ppit_conn_id);; memcpy(cid.idbuf, &ppit->ppit_conn_id, sizeof(ppit->ppit_conn_id)); assert(LSQUIC_CIDS_EQ(&packet_in->pi_conn_id, &cid)); } assert((packet_in->pi_flags & PI_CONN_ID) == (ppit->ppit_pi_flags & PI_CONN_ID)); assert(packet_in->pi_packno == ppit->ppit_packno); assert(packet_in->pi_header_sz == ppit->ppit_header_sz); assert(packet_in->pi_data_sz == ppit->ppit_data_sz); assert(packet_in->pi_quic_ver == ppit->ppit_quic_ver); assert(packet_in->pi_nonce == ppit->ppit_nonce); if (ppit->ppit_nonce) assert(lsquic_packet_in_nonce(packet_in)); else assert(!lsquic_packet_in_nonce(packet_in)); } lsquic_mm_put_packet_in(mm, packet_in); } int main (void) { struct lsquic_mm mm; unsigned i; lsquic_mm_init(&mm); for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) run_ppi_test(&mm, &tests[i]); lsquic_mm_cleanup(&mm); return 0; }