[FEATURE, API CHANGE] Support zero-sized CIDs in received packets

This commit is contained in:
Dmitri Tikhonov 2018-05-30 00:15:35 -04:00
parent e98f5deb04
commit 96f77e2060
12 changed files with 157 additions and 69 deletions

View File

@ -1,3 +1,7 @@
2018-05-30
- [FEATURE, API CHANGE] Support zero-sized CIDs in received packets
2018-05-24
- Close connection properly when packet encryption fails

View File

@ -319,8 +319,7 @@ struct lsquic_engine_settings {
* If set to true value, the server will not include connection ID in
* outgoing packets if client's CHLO specifies TCID=0.
*
* For client, this means including TCID=0 into CHLO message. TODO:
* this does not work yet.
* For client, this means including TCID=0 into CHLO message.
*/
int es_support_tcid0;
@ -492,7 +491,8 @@ lsquic_engine_new (unsigned lsquic_engine_flags,
* 1350 for IPv6 and 1370 for IPv4.
*/
lsquic_conn_t *
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *peer_sa,
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *local_sa,
const struct sockaddr *peer_sa,
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
const char *hostname, unsigned short max_packet_size);

View File

@ -51,23 +51,6 @@ lsquic_conn_record_sockaddr (lsquic_conn_t *lconn,
}
void
lsquic_conn_record_peer_sa (lsquic_conn_t *lconn, const struct sockaddr *peer)
{
switch (peer->sa_family)
{
case AF_INET:
lconn->cn_flags |= LSCONN_HAS_PEER_SA;
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in));
break;
case AF_INET6:
lconn->cn_flags |= LSCONN_HAS_PEER_SA;
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in6));
break;
}
}
int
lsquic_conn_get_sockaddr (const lsquic_conn_t *lconn,
const struct sockaddr **local, const struct sockaddr **peer)

View File

@ -113,9 +113,6 @@ void
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn, const struct sockaddr *local,
const struct sockaddr *peer);
void
lsquic_conn_record_peer_sa (lsquic_conn_t *lconn, const struct sockaddr *peer);
int
lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
struct lsquic_engine_public *, struct lsquic_packet_in *);

View File

@ -18,9 +18,61 @@
#define conn_hash_mask(conn_hash) ((1 << (conn_hash)->ch_nbits) - 1)
#define conn_hash_bucket_no(conn_hash, hash) (hash & conn_hash_mask(conn_hash))
#if FULL_LOCAL_ADDR_SUPPORTED
#define HASHBUF_SZ (2 + sizeof(((struct sockaddr_in6 *) 0)->sin6_addr))
#else
#define HASHBUF_SZ 2
#endif
static const unsigned char *
conn2hash_server (const struct lsquic_conn *lconn, unsigned char *buf,
size_t *sz)
{
*sz = sizeof(lconn->cn_cid);
return (unsigned char *) &lconn->cn_cid;
}
static void
sockaddr2hash (const struct sockaddr *sa, unsigned char *buf, size_t *sz)
{
if (sa->sa_family == AF_INET)
{
const struct sockaddr_in *const sa4 = (void *) sa;
memcpy(buf, &sa4->sin_port, 2);
#if FULL_LOCAL_ADDR_SUPPORTED
memcpy(buf + 2, &sa4->sin_addr, sizeof(sa4->sin_addr));
*sz = 2 + sizeof(sa4->sin_addr);
#else
*sz = 2;
#endif
}
else
{
const struct sockaddr_in6 *const sa6 = (void *) sa;
memcpy(buf, &sa6->sin6_port, 2);
#if FULL_LOCAL_ADDR_SUPPORTED
memcpy(buf + 2, &sa6->sin6_addr, sizeof(sa6->sin6_addr));
*sz = 2 + sizeof(sa6->sin6_addr);
#else
*sz = 2;
#endif
}
}
static const unsigned char *
conn2hash_client (const struct lsquic_conn *lconn, unsigned char *buf,
size_t *sz)
{
sockaddr2hash((struct sockaddr *) &lconn->cn_local_addr, buf, sz);
return buf;
}
int
conn_hash_init (struct conn_hash *conn_hash)
conn_hash_init (struct conn_hash *conn_hash, int server)
{
unsigned n;
@ -32,6 +84,10 @@ conn_hash_init (struct conn_hash *conn_hash)
return -1;
for (n = 0; n < n_buckets(conn_hash->ch_nbits); ++n)
TAILQ_INIT(&conn_hash->ch_buckets[n]);
if (server)
conn_hash->ch_conn2hash = conn2hash_server;
else
conn_hash->ch_conn2hash = conn2hash_client;
LSQ_INFO("initialized");
return 0;
}
@ -45,7 +101,7 @@ conn_hash_cleanup (struct conn_hash *conn_hash)
struct lsquic_conn *
conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t cid)
conn_hash_find_by_cid (struct conn_hash *conn_hash, lsquic_cid_t cid)
{
const unsigned hash = XXH32(&cid, sizeof(cid), (uintptr_t) conn_hash);
const unsigned buckno = conn_hash_bucket_no(conn_hash, hash);
@ -57,6 +113,31 @@ conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t cid)
}
struct lsquic_conn *
conn_hash_find_by_addr (struct conn_hash *conn_hash, const struct sockaddr *sa)
{
unsigned char hash_buf[HASHBUF_SZ][2];
struct lsquic_conn *lconn;
unsigned hash, buckno;
size_t hash_sz[2];
sockaddr2hash(sa, hash_buf[0], &hash_sz[0]);
hash = XXH32(hash_buf, hash_sz[0], (uintptr_t) conn_hash);
buckno = conn_hash_bucket_no(conn_hash, hash);
TAILQ_FOREACH(lconn, &conn_hash->ch_buckets[buckno], cn_next_hash)
if (lconn->cn_hash == hash)
{
sockaddr2hash((struct sockaddr *) lconn->cn_local_addr, hash_buf[1],
&hash_sz[1]);
if (hash_sz[0] == hash_sz[1]
&& 0 == memcmp(hash_buf[0], hash_buf[1], hash_sz[0]))
return lconn;
}
return NULL;
}
static int
double_conn_hash_buckets (struct conn_hash *conn_hash)
{
@ -98,8 +179,13 @@ double_conn_hash_buckets (struct conn_hash *conn_hash)
int
conn_hash_add (struct conn_hash *conn_hash, struct lsquic_conn *lconn)
{
const unsigned hash = XXH32(&lconn->cn_cid, sizeof(lconn->cn_cid),
(uintptr_t) conn_hash);
unsigned char hash_buf[HASHBUF_SZ];
const unsigned char *key;
size_t key_sz;
unsigned hash, buckno;
key = conn_hash->ch_conn2hash(lconn, hash_buf, &key_sz);
hash = XXH32(key, key_sz, (uintptr_t) conn_hash);
if (conn_hash->ch_count >=
n_buckets(conn_hash->ch_nbits) * CONN_HASH_MAX_PER_BUCKET &&
conn_hash->ch_nbits < sizeof(hash) * 8 - 1 &&
@ -107,7 +193,7 @@ conn_hash_add (struct conn_hash *conn_hash, struct lsquic_conn *lconn)
{
return -1;
}
const unsigned buckno = conn_hash_bucket_no(conn_hash, hash);
buckno = conn_hash_bucket_no(conn_hash, hash);
lconn->cn_hash = hash;
TAILQ_INSERT_TAIL(&conn_hash->ch_buckets[buckno], lconn, cn_next_hash);
++conn_hash->ch_count;

View File

@ -16,6 +16,7 @@
#define CONN_HASH_MAX_PER_BUCKET 2
struct lsquic_conn;
struct sockaddr;
TAILQ_HEAD(lsquic_conn_head, lsquic_conn);
@ -28,19 +29,24 @@ struct conn_hash
} ch_iter;
unsigned ch_count;
unsigned ch_nbits;
const unsigned char * (*ch_conn2hash)(const struct lsquic_conn *,
unsigned char *, size_t *);
};
#define conn_hash_count(conn_hash) (+(conn_hash)->ch_count)
/* Returns -1 if malloc fails */
int
conn_hash_init (struct conn_hash *);
conn_hash_init (struct conn_hash *, int server);
void
conn_hash_cleanup (struct conn_hash *);
struct lsquic_conn *
conn_hash_find (struct conn_hash *conn_hash, lsquic_cid_t);
conn_hash_find_by_cid (struct conn_hash *, lsquic_cid_t);
struct lsquic_conn *
conn_hash_find_by_addr (struct conn_hash *, const struct sockaddr *);
/* Returns -1 if limit has been reached or if malloc fails */
int

View File

@ -323,7 +323,7 @@ lsquic_engine_new (unsigned flags,
engine->pub.enp_pmi_ctx = NULL;
}
engine->pub.enp_engine = engine;
conn_hash_init(&engine->conns_hash);
conn_hash_init(&engine->conns_hash, flags & ENG_SERVER);
engine->attq = attq_create();
eng_hist_init(&engine->history);
engine->batch_size = INITIAL_OUT_BATCH_SIZE;
@ -409,50 +409,28 @@ new_full_conn_client (lsquic_engine_t *engine, const char *hostname,
if (!conn)
return NULL;
++engine->n_conns;
if (0 != conn_hash_add(&engine->conns_hash, conn))
{
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
conn->cn_cid);
destroy_conn(engine, conn);
return NULL;
}
assert(!(conn->cn_flags &
(CONN_REF_FLAGS
& ~LSCONN_TICKABLE /* This flag may be set as effect of user
callbacks */
)));
conn->cn_flags |= LSCONN_HASHED;
return conn;
}
static lsquic_conn_t *
find_or_create_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
struct packin_parse_state *ppstate, const struct sockaddr *sa_peer,
void *peer_ctx)
find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
struct packin_parse_state *ppstate, const struct sockaddr *sa_local)
{
lsquic_conn_t *conn;
if (lsquic_packet_in_is_prst(packet_in)
&& !engine->pub.enp_settings.es_honor_prst)
{
LSQ_DEBUG("public reset packet: discarding");
conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local);
if (!conn)
return NULL;
}
if (!(packet_in->pi_flags & PI_CONN_ID))
conn->cn_pf->pf_parse_packet_in_finish(packet_in, ppstate);
if ((packet_in->pi_flags & PI_CONN_ID)
&& conn->cn_cid != packet_in->pi_conn_id)
{
LSQ_DEBUG("packet header does not have connection ID: discarding");
LSQ_DEBUG("connection IDs do not match");
return NULL;
}
conn = conn_hash_find(&engine->conns_hash, packet_in->pi_conn_id);
if (conn)
{
conn->cn_pf->pf_parse_packet_in_finish(packet_in, ppstate);
return conn;
}
return conn;
}
@ -508,7 +486,16 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
{
lsquic_conn_t *conn;
conn = find_or_create_conn(engine, packet_in, ppstate, sa_peer, peer_ctx);
if (lsquic_packet_in_is_prst(packet_in)
&& !engine->pub.enp_settings.es_honor_prst)
{
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
LSQ_DEBUG("public reset packet: discarding");
return 1;
}
conn = find_conn(engine, packet_in, ppstate, sa_local);
if (!conn)
{
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
@ -567,7 +554,8 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
lsquic_conn_t *
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *local_sa,
const struct sockaddr *peer_sa,
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
const char *hostname, unsigned short max_packet_size)
{
@ -596,9 +584,22 @@ lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
conn = new_full_conn_client(engine, hostname, max_packet_size);
if (!conn)
goto err;
lsquic_conn_record_sockaddr(conn, local_sa, peer_sa);
if (0 != conn_hash_add(&engine->conns_hash, conn))
{
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
conn->cn_cid);
destroy_conn(engine, conn);
goto err;
}
assert(!(conn->cn_flags &
(CONN_REF_FLAGS
& ~LSCONN_TICKABLE /* This flag may be set as effect of user
callbacks */
)));
conn->cn_flags |= LSCONN_HASHED;
lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked);
engine_incref_conn(conn, LSCONN_TICKABLE);
lsquic_conn_record_peer_sa(conn, peer_sa);
conn->cn_peer_ctx = peer_ctx;
lsquic_conn_set_ctx(conn, conn_ctx);
full_conn_client_call_on_new(conn);

View File

@ -964,6 +964,10 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
}
else
ua_len = 0;
if (settings->es_support_tcid0)
{
MSG_LEN_ADD(msg_len, 4); ++n_tags; /* TCID */
}
MSG_LEN_ADD(msg_len, lsquic_str_len(&enc_session->hs_ctx.sni));
++n_tags; /* SNI */
MSG_LEN_ADD(msg_len, lsquic_str_len(ccs)); ++n_tags; /* CCS */
@ -1034,6 +1038,8 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
if (lsquic_str_len(&enc_session->info->scfg) > 0)
MW_WRITE_BUFFER(&mw, QTAG_SCID, enc_session->info->sscid,
sizeof(enc_session->info->sscid));
if (settings->es_support_tcid0)
MW_WRITE_UINT32(&mw, QTAG_TCID, 0);
MW_WRITE_UINT32(&mw, QTAG_PDMD, settings->es_pdmd);
MW_WRITE_UINT32(&mw, QTAG_SMHL, 1);
MW_WRITE_UINT32(&mw, QTAG_ICSL, settings->es_idle_conn_to / 1000000);

View File

@ -251,6 +251,7 @@ prog_connect (struct prog *prog)
sport = TAILQ_FIRST(prog->prog_sports);
if (NULL == lsquic_engine_connect(prog->prog_engine,
(struct sockaddr *) &sport->sp_local_addr,
(struct sockaddr *) &sport->sas, sport, NULL,
prog->prog_hostname ? prog->prog_hostname : sport->host,
prog->prog_max_packet_size))

View File

@ -512,7 +512,7 @@ read_one_packet (struct read_iter *iter)
#endif
local_addr = &packs_in->local_addresses[iter->ri_idx];
memcpy(local_addr, &sport->sas, sizeof(*local_addr));
memcpy(local_addr, &sport->sp_local_addr, sizeof(*local_addr));
#if __linux__
n_dropped = 0;
#endif
@ -753,6 +753,9 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
return -1;
}
memcpy((void *) &sport->sp_local_addr, sa_local,
sa_local->sa_family == AF_INET ?
sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
switch (sa_local->sa_family) {
case AF_INET:
LSQ_DEBUG("local address: %s:%d",

View File

@ -47,6 +47,7 @@ struct service_port {
void *conn_ctx;
char host[80];
struct sockaddr_storage sas;
struct sockaddr_storage sp_local_addr;
struct packets_in *packs_in;
enum sport_flags sp_flags;
int sp_sndbuf; /* If SPORT_SET_SNDBUF is set */

View File

@ -48,14 +48,14 @@ main (int argc, char **argv)
lsquic_set_log_level("info");
malo = lsquic_malo_create(sizeof(*lconn));
s = conn_hash_init(&conn_hash);
s = conn_hash_init(&conn_hash, 1);
assert(0 == s);
for (n = 0; n < nelems; ++n)
{
lconn = get_new_lsquic_conn(malo);
lconn->cn_if = (void *) (uintptr_t) n; /* This will be used for verification later the test */
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
assert(!find_lsconn);
s = conn_hash_add(&conn_hash, lconn);
assert(0 == s);
@ -66,10 +66,10 @@ main (int argc, char **argv)
for (lconn = lsquic_malo_first(malo); lconn;
lconn = lsquic_malo_next(malo))
{
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
assert(find_lsconn == lconn);
conn_hash_remove(&conn_hash, lconn);
find_lsconn = conn_hash_find(&conn_hash, lconn->cn_cid);
find_lsconn = conn_hash_find_by_cid(&conn_hash, lconn->cn_cid);
assert(!find_lsconn);
}