Skip to content

Commit 1f39d53

Browse files
committed
Release 4.2.0
1 parent 5915733 commit 1f39d53

11 files changed

+452
-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

+59-8
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
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>
1318
#endif
1419

1520
#include "lsquic_hash.h"
16-
#include "lsquic_xxhash.h"
21+
#include "lsquic_rapidhash.h"
1722

1823
TAILQ_HEAD(hels_head, lsquic_hash_elem);
1924

@@ -26,15 +31,47 @@ struct lsquic_hash
2631
qh_all;
2732
struct lsquic_hash_elem *qh_iter_next;
2833
int (*qh_cmp)(const void *, const void *, size_t);
29-
unsigned (*qh_hash)(const void *, size_t, unsigned seed);
34+
uint64_t (*qh_hash)(const void *, size_t, uint64_t seed);
3035
unsigned qh_count;
3136
unsigned qh_nbits;
37+
uint64_t qh_hash_seed;
3238
};
3339

3440

41+
static uint64_t get_seed()
42+
{
43+
static uint64_t seed = 0;
44+
if (seed == 0)
45+
{
46+
#if defined(WIN32)
47+
LARGE_INTEGER counter;
48+
QueryPerformanceCounter(&counter);
49+
seed = counter.QuadPart;
50+
#elif defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
51+
struct timespec ts;
52+
(void) clock_gettime(CLOCK_MONOTONIC, &ts);
53+
seed = ts.tv_sec * 1000000000 + ts.tv_nsec;
54+
#elif defined(__APPLE__)
55+
seed = mach_absolute_time();
56+
#else
57+
struct timeval tv;
58+
gettimeofday(&tv, NULL);
59+
seed = tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
60+
#endif
61+
srand(seed);
62+
for(unsigned i = 0; i < (seed & 0xf) + 1; ++i)
63+
{
64+
seed = (seed << 8) | (seed >> 56);
65+
seed ^= rand();
66+
}
67+
}
68+
return seed;
69+
}
70+
71+
3572
struct lsquic_hash *
3673
lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
37-
unsigned (*hashf)(const void *, size_t, unsigned seed))
74+
uint64_t (*hashf)(const void *, size_t, uint64_t seed))
3875
{
3976
struct hels_head *buckets;
4077
struct lsquic_hash *hash;
@@ -62,14 +99,26 @@ lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
6299
hash->qh_nbits = nbits;
63100
hash->qh_iter_next = NULL;
64101
hash->qh_count = 0;
102+
hash->qh_hash_seed = get_seed() ^ (uint64_t)hash
103+
^ ((uint64_t)buckets << 32) ^ rand();
65104
return hash;
66105
}
67106

68107

69108
struct lsquic_hash *
70109
lsquic_hash_create (void)
71110
{
72-
return lsquic_hash_create_ext(memcmp, XXH32);
111+
return lsquic_hash_create_ext(memcmp, rapidhash_withSeed);
112+
}
113+
114+
115+
int
116+
lsquic_hash_set_seed (struct lsquic_hash * hash, uint64_t seed)
117+
{
118+
if (hash->qh_count > 0)
119+
return -1;
120+
hash->qh_hash_seed = seed;
121+
return 0;
73122
}
74123

75124

@@ -119,7 +168,8 @@ struct lsquic_hash_elem *
119168
lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
120169
unsigned key_sz, void *value, struct lsquic_hash_elem *el)
121170
{
122-
unsigned buckno, hash_val;
171+
uint64_t hash_val;
172+
unsigned buckno;
123173

124174
if (el->qhe_flags & QHE_HASHED)
125175
return NULL;
@@ -128,7 +178,7 @@ lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
128178
0 != lsquic_hash_grow(hash))
129179
return NULL;
130180

131-
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
181+
hash_val = hash->qh_hash(key, key_sz, hash->qh_hash_seed);
132182
buckno = BUCKNO(hash->qh_nbits, hash_val);
133183
TAILQ_INSERT_TAIL(&hash->qh_all, el, qhe_next_all);
134184
TAILQ_INSERT_TAIL(&hash->qh_buckets[buckno], el, qhe_next_bucket);
@@ -145,10 +195,11 @@ lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
145195
struct lsquic_hash_elem *
146196
lsquic_hash_find (struct lsquic_hash *hash, const void *key, unsigned key_sz)
147197
{
148-
unsigned buckno, hash_val;
198+
uint64_t hash_val;
199+
unsigned buckno;
149200
struct lsquic_hash_elem *el;
150201

151-
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
202+
hash_val = hash->qh_hash(key, key_sz, hash->qh_hash_seed);
152203
buckno = BUCKNO(hash->qh_nbits, hash_val);
153204
TAILQ_FOREACH(el, &hash->qh_buckets[buckno], qhe_next_bucket)
154205
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
{

src/liblsquic/lsquic_pr_queue.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#include "lsquic_engine_public.h"
3838
#include "lsquic_sizes.h"
3939
#include "lsquic_handshake.h"
40-
#include "lsquic_xxhash.h"
40+
#include "lsquic_rapidhash.h"
4141
#include "lsquic_crand.h"
4242

4343
#define LSQUIC_LOGGER_MODULE LSQLM_PRQ
@@ -134,13 +134,13 @@ comp_reqs (const void *s1, const void *s2, size_t n)
134134
}
135135

136136

137-
static unsigned
138-
hash_req (const void *p, size_t len, unsigned seed)
137+
static uint64_t
138+
hash_req (const void *p, size_t len, uint64_t seed)
139139
{
140140
const struct packet_req *req;
141141

142142
req = p;
143-
return XXH32(req->pr_dcid.idbuf, req->pr_dcid.len, seed);
143+
return rapidhash_withSeed(req->pr_dcid.idbuf, req->pr_dcid.len, seed);
144144
}
145145

146146

0 commit comments

Comments
 (0)