Skip to content

Commit 7686d8f

Browse files
committed
Release 4.2.0
1 parent 5915733 commit 7686d8f

11 files changed

+456
-29
lines changed

CHANGELOG

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
2025-02-18
2+
- 4.2.0
3+
- Address hash flood attack for lsquic_hash by switching to rapidhash with stronger random seed.
4+
- Fix packet packing problem for post-quantum support.
5+
- Add configuration to control version negotiation and amplification factor.
6+
17
2024-12-16
28
- 4.1.0
39
- Update to ls-qpack v2.6.1 to fix a infinite loop.
4-
- Fix packet packing problem for post-quantum support
510
- Add lsquic_engine_get_conns_count() API
611
- Updated ea_generate_scid() API
712
- Fix retry packet SCID generation to follow engine API.

docs/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
author = u'LiteSpeed Technologies'
2525

2626
# The short X.Y version
27-
version = u'4.1'
27+
version = u'4.2'
2828
# The full version, including alpha/beta/rc tags
29-
release = u'4.1.0'
29+
release = u'4.2.0'
3030

3131

3232
# -- General configuration ---------------------------------------------------

include/lsquic.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ extern "C" {
2626
#endif
2727

2828
#define LSQUIC_MAJOR_VERSION 4
29-
#define LSQUIC_MINOR_VERSION 1
29+
#define LSQUIC_MINOR_VERSION 2
3030
#define LSQUIC_PATCH_VERSION 0
3131

3232
/**
@@ -335,6 +335,12 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
335335
*/
336336
#define LSQUIC_DF_SEND_PRST 0
337337

338+
/**
339+
* By default, LSQUIC will send Version Negotiation packets in response to
340+
* packets that specify unknown versions.
341+
*/
342+
#define LSQUIC_DF_SEND_VERNEG 1
343+
338344
/** By default, infinite loop checks are turned on */
339345
#define LSQUIC_DF_PROGRESS_CHECK 1000
340346

@@ -398,6 +404,9 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
398404
/** Turn on timestamp extension by default */
399405
#define LSQUIC_DF_TIMESTAMPS 1
400406

407+
/** default anti-amplification factor is 3 */
408+
#define LSQUIC_DF_AMP_FACTOR 3
409+
401410
/* Use Adaptive CC by default */
402411
#define LSQUIC_DF_CC_ALGO 3
403412

@@ -1092,6 +1101,20 @@ struct lsquic_engine_settings {
10921101
* Default value is @ref LSQUIC_DF_CHECK_TP_SANITY
10931102
*/
10941103
int es_check_tp_sanity;
1104+
1105+
/**
1106+
* This is the anti-amplification factor when peer address has not be verified.
1107+
*
1108+
* Default value is @ref LSQUIC_DF_AMP_FACTOR
1109+
*/
1110+
int es_amp_factor;
1111+
1112+
/**
1113+
* If set to true value, the library will send Version Negotiation packets
1114+
* in response to incoming packets with unsupported versions.
1115+
* The default is @ref LSQUIC_DF_SEND_VERNEG.
1116+
*/
1117+
int es_send_verneg;
10951118
};
10961119

10971120
/* Initialize `settings' to default values */

src/liblsquic/lsquic_engine.c

+15-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#endif
4444

4545
#include <openssl/aead.h>
46+
#include <openssl/rand.h>
4647

4748
#include "lsquic.h"
4849
#include "lsquic_types.h"
@@ -398,6 +399,8 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
398399
settings->es_ptpc_err_divisor= LSQUIC_DF_PTPC_ERR_DIVISOR;
399400
settings->es_delay_onclose = LSQUIC_DF_DELAY_ONCLOSE;
400401
settings->es_check_tp_sanity = LSQUIC_DF_CHECK_TP_SANITY;
402+
settings->es_amp_factor = LSQUIC_DF_AMP_FACTOR;
403+
settings->es_send_verneg = LSQUIC_DF_SEND_VERNEG;
401404
}
402405

403406

@@ -545,6 +548,7 @@ lsquic_engine_new (unsigned flags,
545548
size_t alpn_len;
546549
unsigned i;
547550
char err_buf[100];
551+
uint64_t seed;
548552

549553
if (!api->ea_packets_out)
550554
{
@@ -669,6 +673,8 @@ lsquic_engine_new (unsigned flags,
669673
if (hash_conns_by_addr(engine))
670674
engine->flags |= ENG_CONNS_BY_ADDR;
671675
engine->conns_hash = lsquic_hash_create();
676+
RAND_bytes((uint8_t *)&seed, 8);
677+
lsquic_hash_set_seed(engine->conns_hash, seed);
672678
engine->pub.enp_tokgen = lsquic_tg_new(&engine->pub);
673679
if (!engine->pub.enp_tokgen)
674680
return NULL;
@@ -1094,6 +1100,8 @@ insert_conn_into_hash (struct lsquic_engine *engine, struct lsquic_conn *conn,
10941100
{
10951101
cce = &conn->cn_cces[n];
10961102
assert(!(cce->cce_hash_el.qhe_flags & QHE_HASHED));
1103+
LSQ_DEBUGC("Insert into connection hash-table by CID %"CID_FMT,
1104+
CID_BITS(&cce->cce_cid));
10971105
if (lsquic_hash_insert(engine->conns_hash, cce->cce_cid.idbuf,
10981106
cce->cce_cid.len, conn, &cce->cce_hash_el))
10991107
done |= 1 << n;
@@ -1413,6 +1421,8 @@ find_or_create_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
14131421
LSQ_DEBUG("packet header does not have connection ID: discarding");
14141422
return NULL;
14151423
}
1424+
LSQ_DEBUGC("To find connection by CID %"CID_FMT,
1425+
CID_BITS(&packet_in->pi_conn_id));
14161426
el = lsquic_hash_find(engine->conns_hash,
14171427
packet_in->pi_conn_id.idbuf, packet_in->pi_conn_id.len);
14181428

@@ -1492,7 +1502,8 @@ find_or_create_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
14921502
switch (version_matches(engine, packet_in, &version))
14931503
{
14941504
case VER_UNSUPPORTED:
1495-
if (engine->flags & ENG_SERVER)
1505+
if ((engine->flags & ENG_SERVER) &&
1506+
engine->pub.enp_settings.es_send_verneg)
14961507
schedule_req_packet(engine, PACKET_REQ_VERNEG, packet_in,
14971508
sa_local, sa_peer, peer_ctx);
14981509
return NULL;
@@ -3564,8 +3575,10 @@ lsquic_engine_retire_cid (struct lsquic_engine_public *enpub,
35643575
assert(cce_idx < conn->cn_n_cces);
35653576

35663577
if (cce->cce_hash_el.qhe_flags & QHE_HASHED)
3578+
{
3579+
LSQ_DEBUGC("drop from conn hash-table CID %"CID_FMT, CID_BITS(&cce->cce_cid));
35673580
lsquic_hash_erase(engine->conns_hash, &cce->cce_hash_el);
3568-
3581+
}
35693582
if (engine->purga)
35703583
{
35713584
peer_ctx = lsquic_conn_get_peer_ctx(conn, NULL);

src/liblsquic/lsquic_full_conn_ietf.c

-1
Original file line numberDiff line numberDiff line change
@@ -6210,7 +6210,6 @@ process_max_stream_data_frame (struct ietf_full_conn *conn,
62106210
LSQ_DEBUG("Connection closing: ignore frame");
62116211
return parsed_len;
62126212
}
6213-
62146213
const lsquic_stream_id_t max_allowed =
62156214
conn->ifc_max_allowed_stream_id[stream_id & SIT_MASK];
62166215
if (stream_id >= max_allowed)

src/liblsquic/lsquic_hash.c

+63-8
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@
88
#include <stdlib.h>
99
#include <string.h>
1010
#include <sys/queue.h>
11+
#include <time.h>
12+
1113
#ifdef WIN32
1214
#include <vc_compat.h>
15+
#else
16+
#include <sys/time.h>
17+
#include <unistd.h>
18+
#endif
19+
20+
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
21+
#include <mach/mach_time.h>
1322
#endif
1423

1524
#include "lsquic_hash.h"
16-
#include "lsquic_xxhash.h"
25+
#include "lsquic_rapidhash.h"
1726

1827
TAILQ_HEAD(hels_head, lsquic_hash_elem);
1928

@@ -26,15 +35,47 @@ struct lsquic_hash
2635
qh_all;
2736
struct lsquic_hash_elem *qh_iter_next;
2837
int (*qh_cmp)(const void *, const void *, size_t);
29-
unsigned (*qh_hash)(const void *, size_t, unsigned seed);
38+
uint64_t (*qh_hash)(const void *, size_t, uint64_t seed);
3039
unsigned qh_count;
3140
unsigned qh_nbits;
41+
uint64_t qh_hash_seed;
3242
};
3343

3444

45+
static uint64_t get_seed()
46+
{
47+
static uint64_t seed = 0;
48+
if (seed == 0)
49+
{
50+
#if defined(WIN32)
51+
LARGE_INTEGER counter;
52+
QueryPerformanceCounter(&counter);
53+
seed = counter.QuadPart;
54+
#elif defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
55+
struct timespec ts;
56+
(void) clock_gettime(CLOCK_MONOTONIC, &ts);
57+
seed = ts.tv_sec * 1000000000 + ts.tv_nsec;
58+
#elif defined(__APPLE__)
59+
seed = mach_absolute_time();
60+
#else
61+
struct timeval tv;
62+
gettimeofday(&tv, NULL);
63+
seed = tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
64+
#endif
65+
srand(seed);
66+
for(unsigned i = 0; i < (seed & 0xf) + 1; ++i)
67+
{
68+
seed = (seed << 8) | (seed >> 56);
69+
seed ^= rand();
70+
}
71+
}
72+
return seed;
73+
}
74+
75+
3576
struct lsquic_hash *
3677
lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
37-
unsigned (*hashf)(const void *, size_t, unsigned seed))
78+
uint64_t (*hashf)(const void *, size_t, uint64_t seed))
3879
{
3980
struct hels_head *buckets;
4081
struct lsquic_hash *hash;
@@ -62,14 +103,26 @@ lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
62103
hash->qh_nbits = nbits;
63104
hash->qh_iter_next = NULL;
64105
hash->qh_count = 0;
106+
hash->qh_hash_seed = get_seed() ^ (uint64_t)hash
107+
^ ((uint64_t)buckets << 32) ^ rand();
65108
return hash;
66109
}
67110

68111

69112
struct lsquic_hash *
70113
lsquic_hash_create (void)
71114
{
72-
return lsquic_hash_create_ext(memcmp, XXH32);
115+
return lsquic_hash_create_ext(memcmp, rapidhash_withSeed);
116+
}
117+
118+
119+
int
120+
lsquic_hash_set_seed (struct lsquic_hash * hash, uint64_t seed)
121+
{
122+
if (hash->qh_count > 0)
123+
return -1;
124+
hash->qh_hash_seed = seed;
125+
return 0;
73126
}
74127

75128

@@ -119,7 +172,8 @@ struct lsquic_hash_elem *
119172
lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
120173
unsigned key_sz, void *value, struct lsquic_hash_elem *el)
121174
{
122-
unsigned buckno, hash_val;
175+
uint64_t hash_val;
176+
unsigned buckno;
123177

124178
if (el->qhe_flags & QHE_HASHED)
125179
return NULL;
@@ -128,7 +182,7 @@ lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
128182
0 != lsquic_hash_grow(hash))
129183
return NULL;
130184

131-
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
185+
hash_val = hash->qh_hash(key, key_sz, hash->qh_hash_seed);
132186
buckno = BUCKNO(hash->qh_nbits, hash_val);
133187
TAILQ_INSERT_TAIL(&hash->qh_all, el, qhe_next_all);
134188
TAILQ_INSERT_TAIL(&hash->qh_buckets[buckno], el, qhe_next_bucket);
@@ -145,10 +199,11 @@ lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
145199
struct lsquic_hash_elem *
146200
lsquic_hash_find (struct lsquic_hash *hash, const void *key, unsigned key_sz)
147201
{
148-
unsigned buckno, hash_val;
202+
uint64_t hash_val;
203+
unsigned buckno;
149204
struct lsquic_hash_elem *el;
150205

151-
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
206+
hash_val = hash->qh_hash(key, key_sz, hash->qh_hash_seed);
152207
buckno = BUCKNO(hash->qh_nbits, hash_val);
153208
TAILQ_FOREACH(el, &hash->qh_buckets[buckno], qhe_next_bucket)
154209
if (hash_val == el->qhe_hash_val &&

src/liblsquic/lsquic_hash.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#ifndef LSQUIC_HASH_H
77
#define LSQUIC_HASH_H
88

9+
#include <inttypes.h>
10+
911
#ifdef __cplusplus
1012
extern "C" {
1113
#endif
@@ -20,7 +22,7 @@ struct lsquic_hash_elem
2022
const void *qhe_key_data;
2123
void *qhe_value;
2224
unsigned qhe_key_len;
23-
unsigned qhe_hash_val;
25+
uint64_t qhe_hash_val;
2426
enum {
2527
QHE_HASHED = 1 << 0,
2628
} qhe_flags;
@@ -31,7 +33,10 @@ lsquic_hash_create (void);
3133

3234
struct lsquic_hash *
3335
lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
34-
unsigned (*hash)(const void *, size_t, unsigned seed));
36+
uint64_t (*hash)(const void *, size_t, uint64_t seed));
37+
38+
int
39+
lsquic_hash_set_seed (struct lsquic_hash *, uint64_t seed);
3540

3641
void
3742
lsquic_hash_destroy (struct lsquic_hash *);

src/liblsquic/lsquic_mini_conn_ietf.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,11 @@ imico_stream_write (void *stream, const void *bufp, size_t bufsz)
318318
if (!packet_out)
319319
return -1;
320320
// NOTE: reduce the size of first crypto frame to combine packets
321-
int avail = lsquic_packet_out_avail(packet_out);
321+
unsigned avail = lsquic_packet_out_avail(packet_out);
322322
int coalescing = 0;
323323
if (cryst->mcs_enc_level == ENC_LEV_HSK
324324
&& cryst->mcs_write_off == 0
325-
&& avail > (int)conn->imc_hello_pkt_remain - conn->imc_long_header_sz)
325+
&& avail > (unsigned)conn->imc_hello_pkt_remain - conn->imc_long_header_sz)
326326
{
327327
avail = conn->imc_hello_pkt_remain - conn->imc_long_header_sz;
328328
conn->imc_hello_pkt_remain = 0;
@@ -339,7 +339,7 @@ imico_stream_write (void *stream, const void *bufp, size_t bufsz)
339339
packet_out->po_data_sz += len;
340340
packet_out->po_frame_types |= 1 << QUIC_FRAME_CRYPTO;
341341
packet_out->po_flags |= PO_HELLO;
342-
if (coalescing && len < avail)
342+
if (coalescing && len < (int)avail)
343343
{
344344
LSQ_DEBUG("generated PADDING frame: %d bytes for packet %"PRIu64,
345345
avail - len, packet_out->po_packno);
@@ -810,7 +810,8 @@ static int
810810
imico_can_send (const struct ietf_mini_conn *conn, size_t size)
811811
{
812812
return (conn->imc_flags & IMC_ADDR_VALIDATED)
813-
|| conn->imc_bytes_in * 3 >= conn->imc_bytes_out + size
813+
|| conn->imc_bytes_in * conn->imc_enpub->enp_settings.es_amp_factor
814+
>= conn->imc_bytes_out + size
814815
;
815816
}
816817

@@ -2331,6 +2332,8 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
23312332
(IMC_HAVE_TP|IMC_ADDR_VALIDATED|IMC_BAD_TRANS_PARAMS))
23322333
&& conn->imc_enpub->enp_settings.es_support_srej)
23332334
{
2335+
if (conn->imc_flags & IMC_ERROR)
2336+
goto close_on_error;
23342337
LSQ_DEBUG("Peer not validated and do not have transport parameters "
23352338
"on the first tick: retry");
23362339
return TICK_RETRY|TICK_CLOSE;
@@ -2356,7 +2359,7 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
23562359
close_on_error:
23572360
if (!(conn->imc_flags & IMC_CLOSE_RECVD))
23582361
imico_generate_conn_close(conn);
2359-
tick |= TICK_CLOSE;
2362+
tick = TICK_CLOSE;
23602363
}
23612364
else if (conn->imc_flags & IMC_HSK_OK)
23622365
{

0 commit comments

Comments
 (0)