250 lines
9.8 KiB
C
250 lines
9.8 KiB
C
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "lsquic.h"
|
|
#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_enc_sess.h"
|
|
#include "lsquic_version.h"
|
|
#include "lsquic_qtags.h"
|
|
|
|
|
|
static int
|
|
parse_ietf_v1_or_Q046plus_long_begin (struct lsquic_packet_in *packet_in,
|
|
size_t length, int is_server, unsigned cid_len,
|
|
struct packin_parse_state *state)
|
|
{
|
|
lsquic_ver_tag_t tag;
|
|
|
|
if (length >= 5)
|
|
{
|
|
memcpy(&tag, packet_in->pi_data + 1, 4);
|
|
switch (tag)
|
|
{
|
|
case TAG('Q', '0', '4', '6'):
|
|
return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
case TAG('Q', '0', '5', '0'):
|
|
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
default:
|
|
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
}
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int (* const parse_begin_funcs[32]) (struct lsquic_packet_in *,
|
|
size_t length, int is_server, unsigned cid_len,
|
|
struct packin_parse_state *) =
|
|
{
|
|
/* Xs vary, Gs are iGnored: */
|
|
#define PBEL(mask) [(mask) >> 3]
|
|
/* 1X11 XGGG: */
|
|
PBEL(0x80|0x40|0x20|0x10|0x08) = lsquic_Q046_parse_packet_in_long_begin,
|
|
PBEL(0x80|0x00|0x20|0x10|0x08) = lsquic_Q046_parse_packet_in_long_begin,
|
|
PBEL(0x80|0x40|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
|
|
PBEL(0x80|0x00|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
|
|
/* 1X00 XGGG: */
|
|
PBEL(0x80|0x40|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x40|0x00|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x00|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
/* 1X01 XGGG: */
|
|
PBEL(0x80|0x40|0x00|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x00|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x40|0x00|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x00|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
/* 1X10 XGGG: */
|
|
PBEL(0x80|0x40|0x20|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x20|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x40|0x20|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
PBEL(0x80|0x00|0x20|0x00|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
|
/* 01XX XGGG */
|
|
PBEL(0x00|0x40|0x00|0x00|0x00) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x00|0x00|0x08) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x00|0x10|0x00) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x00|0x10|0x08) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x20|0x00|0x00) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x20|0x00|0x08) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x20|0x10|0x00) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x40|0x20|0x10|0x08) = lsquic_ietf_v1_parse_packet_in_short_begin,
|
|
/* 00XX 0GGG */
|
|
PBEL(0x00|0x00|0x00|0x00|0x00) = lsquic_Q046_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x00|0x00|0x10|0x00) = lsquic_Q046_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x00|0x20|0x00|0x00) = lsquic_Q046_parse_packet_in_short_begin,
|
|
PBEL(0x00|0x00|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_short_begin,
|
|
/* 00XX 1GGG */
|
|
PBEL(0x00|0x00|0x00|0x00|0x08) = lsquic_gquic_parse_packet_in_begin,
|
|
PBEL(0x00|0x00|0x00|0x10|0x08) = lsquic_gquic_parse_packet_in_begin,
|
|
PBEL(0x00|0x00|0x20|0x00|0x08) = lsquic_gquic_parse_packet_in_begin,
|
|
PBEL(0x00|0x00|0x20|0x10|0x08) = lsquic_gquic_parse_packet_in_begin,
|
|
#undef PBEL
|
|
};
|
|
|
|
|
|
int
|
|
lsquic_parse_packet_in_server_begin (struct lsquic_packet_in *packet_in,
|
|
size_t length, int is_server_UNUSED, unsigned cid_len,
|
|
struct packin_parse_state *state)
|
|
{
|
|
if (length)
|
|
return parse_begin_funcs[ packet_in->pi_data[0] >> 3 ](
|
|
packet_in, length, 1, cid_len, state);
|
|
else
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
|
|
int is_server, unsigned cid_len, struct packin_parse_state *state)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
switch (packet_in->pi_data[0] & 0xC0)
|
|
{
|
|
case 0xC0:
|
|
case 0x80:
|
|
return parse_ietf_v1_or_Q046plus_long_begin(packet_in,
|
|
length, is_server, cid_len, state);
|
|
case 0x00:
|
|
return lsquic_gquic_parse_packet_in_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
default:
|
|
return lsquic_ietf_v1_parse_packet_in_short_begin(packet_in,
|
|
length, is_server, cid_len, state);
|
|
}
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_ietf_v1_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
|
|
size_t length, int is_server, unsigned cid_len,
|
|
struct packin_parse_state *state)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
if (0 == (packet_in->pi_data[0] & 0x80))
|
|
return lsquic_ietf_v1_parse_packet_in_short_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
else
|
|
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_Q046_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
|
|
size_t length, int is_server, unsigned cid_len,
|
|
struct packin_parse_state *state)
|
|
{
|
|
assert(!is_server);
|
|
assert(cid_len == GQUIC_CID_LEN);
|
|
if (length > 0)
|
|
{
|
|
if (0 == (packet_in->pi_data[0] & 0x80))
|
|
return lsquic_ietf_v1_parse_packet_in_short_begin(packet_in, length,
|
|
is_server, is_server ? cid_len : 0, state);
|
|
else
|
|
return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_Q050_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
|
|
size_t length, int is_server, unsigned cid_len,
|
|
struct packin_parse_state *state)
|
|
{
|
|
assert(!is_server);
|
|
assert(cid_len == GQUIC_CID_LEN);
|
|
if (length > 0)
|
|
{
|
|
if (0 == (packet_in->pi_data[0] & 0x80))
|
|
return lsquic_ietf_v1_parse_packet_in_short_begin(packet_in, length,
|
|
is_server, is_server ? cid_len : 0, state);
|
|
else
|
|
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
|
|
is_server, cid_len, state);
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* TODO This function uses the full packet parsing functionality to get at
|
|
* the CID. This is an overkill and could be optimized -- at the cost of
|
|
* some code duplication, of course.
|
|
*/
|
|
int
|
|
lsquic_cid_from_packet (const unsigned char *buf, size_t bufsz,
|
|
lsquic_cid_t *cid)
|
|
{
|
|
struct lsquic_packet_in packet_in;
|
|
struct packin_parse_state pps;
|
|
int s;
|
|
|
|
packet_in.pi_data = (unsigned char *) buf;
|
|
s = lsquic_parse_packet_in_server_begin(&packet_in, bufsz, 1, 8, &pps);
|
|
if (0 == s && (packet_in.pi_flags & PI_CONN_ID))
|
|
{
|
|
*cid = packet_in.pi_dcid;
|
|
return 0;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* See [draft-ietf-quic-transport-25], Section 12.4 (Table 3) */
|
|
const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] =
|
|
{
|
|
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
|
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
|
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
|
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
|
| QUIC_FTBIT_BLOCKED
|
|
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
|
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
|
| QUIC_FTBIT_STREAMS_BLOCKED
|
|
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
|
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
|
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
|
|
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
|
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
|
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
|
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
|
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
|
| QUIC_FTBIT_BLOCKED
|
|
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
|
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
|
| QUIC_FTBIT_STREAMS_BLOCKED
|
|
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
|
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
|
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
|
|
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
|
|
| QUIC_FTBIT_TIMESTAMP
|
|
,
|
|
};
|