Skip to content

Commit

Permalink
[FEATURE, API CHANGE] Support zero-sized CIDs in received packets
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitri Tikhonov committed May 30, 2018
1 parent e98f5de commit 96f77e2
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 69 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 3 additions & 3 deletions include/lsquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down
17 changes: 0 additions & 17 deletions src/liblsquic/lsquic_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 0 additions & 3 deletions src/liblsquic/lsquic_conn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
96 changes: 91 additions & 5 deletions src/liblsquic/lsquic_conn_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand All @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -98,16 +179,21 @@ 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 &&
0 != double_conn_hash_buckets(conn_hash))
{
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;
Expand Down
10 changes: 8 additions & 2 deletions src/liblsquic/lsquic_conn_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define CONN_HASH_MAX_PER_BUCKET 2

struct lsquic_conn;
struct sockaddr;

TAILQ_HEAD(lsquic_conn_head, lsquic_conn);

Expand All @@ -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
Expand Down
69 changes: 35 additions & 34 deletions src/liblsquic/lsquic_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions src/liblsquic/lsquic_handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions test/prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Loading

0 comments on commit 96f77e2

Please sign in to comment.