Skip to content

Commit b655fb2

Browse files
authored
Replace nonce cache with a ping-pong bloom filter (#1282)
* Add Ping-Pong bloom filter * Refine bloom filter insertion * Reduce the error rate to 0.00001 * Avoid alignment issue in murmurhash2 * Fix a memory leak * Fix build on non-GPU targets * Detect get_current_dir_name in configure * Update README.md * Remove redudant bfree() * Reduce the memory usage for local client * Fix #1275 * Refine #1275 * Use IP when bypassing SNI domains * Also apply replay detector on UDP traffic * Update deb build script Now build script is able to auto detect system and choose libraries necessary to build. Also update the README accordingly. * Update build script to enable jessie/stretch etc Also include a few cleanup that simplified pkg installation from backports repository.
1 parent 9185afb commit b655fb2

19 files changed

+217
-77
lines changed

Diff for: .gitmodules

+4
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@
66
path = libipset
77
url = https://github.com/shadowsocks/ipset.git
88
ignore = dirty
9+
[submodule "libbloom"]
10+
path = libbloom
11+
url = https://github.com/shadowsocks/libbloom.git
12+
ignore = dirty

Diff for: Makefile.am

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
if USE_SYSTEM_SHARED_LIB
2-
SUBDIRS = src
2+
SUBDIRS = src libbloom
33
else
4-
SUBDIRS = libcork libipset src
4+
SUBDIRS = libcork libipset libbloom src
55
endif
66

77
if ENABLE_DOCUMENTATION
@@ -14,6 +14,7 @@ pkgconfiglibdir = $(libdir)/pkgconfig
1414
pkgconfiglib_DATA = shadowsocks-libev.pc
1515

1616
EXTRA_DIST = acl Changes completions debian docker rpm README.md
17+
EXTRA_DIST += libbloom
1718
EXTRA_DIST += libcork/include libipset/include
1819
EXTRA_DIST += libipset/src/libipset/map/inspection-template.c.in
1920
EXTRA_DIST += libipset/src/libipset/set/inspection-template.c.in

Diff for: configure.ac

+2-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn
230230

231231
AC_CONFIG_FILES([shadowsocks-libev.pc
232232
Makefile
233-
src/Makefile])
233+
src/Makefile
234+
libbloom/Makefile])
234235

235236
AM_COND_IF([USE_SYSTEM_SHARED_LIB],
236237
[AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])],

Diff for: libbloom

Submodule libbloom added at f6e53fe

Diff for: src/Makefile.am

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ VERSION_INFO = 2:0:0
22

33
AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE
44
AM_CFLAGS += $(PTHREAD_CFLAGS)
5+
AM_CFLAGS += -I$(top_srcdir)/libbloom
56
if !USE_SYSTEM_SHARED_LIB
67
AM_CFLAGS += -I$(top_srcdir)/libipset/include
78
AM_CFLAGS += -I$(top_srcdir)/libcork/include
89
endif
910
AM_CFLAGS += $(LIBPCRE_CFLAGS)
1011

1112
SS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS)
13+
SS_COMMON_LIBS += $(top_builddir)/libbloom/libbloom.la
1214
if !USE_SYSTEM_SHARED_LIB
1315
SS_COMMON_LIBS += $(top_builddir)/libipset/libipset.la \
1416
$(top_builddir)/libcork/libcork.la
@@ -26,6 +28,7 @@ sni_src = http.c \
2628
crypto_src = crypto.c \
2729
aead.c \
2830
stream.c \
31+
ppbloom.c \
2932
base64.c
3033

3134
plugin_src = plugin.c
@@ -112,6 +115,6 @@ libshadowsocks_libev_la_LIBADD = $(ss_local_LDADD)
112115
include_HEADERS = shadowsocks.h
113116

114117
noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h tls.h uthash.h \
115-
cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h base64.h \
118+
cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h base64.h ppbloom.h \
116119
common.h jconf.h manager.h protocol.h rule.h socks5.h udprelay.h
117120
EXTRA_DIST = ss-nat

Diff for: src/aead.c

+20-18
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#include <sodium.h>
3434
#include <arpa/inet.h>
3535

36-
#include "cache.h"
36+
#include "ppbloom.h"
3737
#include "aead.h"
3838
#include "utils.h"
3939

@@ -405,13 +405,11 @@ aead_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity)
405405
(uint8_t *)plaintext->data, plaintext->len,
406406
NULL, 0, cipher_ctx.nonce, cipher_ctx.skey);
407407

408-
if (err) {
409-
bfree(plaintext);
410-
aead_ctx_release(&cipher_ctx);
408+
aead_ctx_release(&cipher_ctx);
409+
410+
if (err)
411411
return CRYPTO_ERROR;
412-
}
413412

414-
aead_ctx_release(&cipher_ctx);
415413
assert(ciphertext->len == clen);
416414

417415
brealloc(plaintext, salt_len + ciphertext->len, capacity);
@@ -444,6 +442,11 @@ aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
444442
uint8_t *salt = cipher_ctx.salt;
445443
memcpy(salt, ciphertext->data, salt_len);
446444

445+
if (ppbloom_check((void *)salt, salt_len) == 1) {
446+
LOGE("crypto: AEAD: repeat salt detected");
447+
return CRYPTO_ERROR;
448+
}
449+
447450
aead_cipher_ctx_set_key(&cipher_ctx, 0);
448451

449452
size_t plen = plaintext->len;
@@ -453,13 +456,12 @@ aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
453456
ciphertext->len - salt_len, NULL, 0,
454457
cipher_ctx.nonce, cipher_ctx.skey);
455458

456-
if (err) {
457-
bfree(ciphertext);
458-
aead_ctx_release(&cipher_ctx);
459+
aead_ctx_release(&cipher_ctx);
460+
461+
if (err)
459462
return CRYPTO_ERROR;
460-
}
461463

462-
aead_ctx_release(&cipher_ctx);
464+
ppbloom_add((void *)salt, salt_len);
463465

464466
brealloc(ciphertext, plaintext->len, capacity);
465467
memcpy(ciphertext->data, plaintext->data, plaintext->len);
@@ -488,6 +490,7 @@ aead_chunk_encrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c,
488490
NULL, 0, n, ctx->skey);
489491
if (err)
490492
return CRYPTO_ERROR;
493+
491494
assert(clen == CHUNK_SIZE_LEN + tlen);
492495

493496
sodium_increment(n, nlen);
@@ -497,6 +500,7 @@ aead_chunk_encrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c,
497500
NULL, 0, n, ctx->skey);
498501
if (err)
499502
return CRYPTO_ERROR;
503+
500504
assert(clen == plen + tlen);
501505

502506
sodium_increment(n, nlen);
@@ -634,19 +638,20 @@ aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
634638

635639
aead_cipher_ctx_set_key(cipher_ctx, 0);
636640

637-
if (cache_key_exist(nonce_cache, (char *)cipher_ctx->salt, salt_len)) {
641+
if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) {
638642
LOGE("crypto: AEAD: repeat salt detected");
639-
bfree(ciphertext);
640643
return CRYPTO_ERROR;
641-
} else {
642-
cache_insert(nonce_cache, (char *)cipher_ctx->salt, salt_len, NULL);
643644
}
644645

645646
memmove(cipher_ctx->chunk->data, cipher_ctx->chunk->data + salt_len,
646647
cipher_ctx->chunk->len - salt_len);
647648
cipher_ctx->chunk->len -= salt_len;
648649

649650
cipher_ctx->init = 1;
651+
652+
} else if (cipher_ctx->init == 1) {
653+
ppbloom_add((void *)cipher_ctx->salt, salt_len);
654+
cipher_ctx->init = 2;
650655
}
651656

652657
size_t plen = 0;
@@ -685,9 +690,6 @@ aead_key_init(int method, const char *pass, const char *key)
685690
return NULL;
686691
}
687692

688-
// Initialize cache
689-
cache_create(&nonce_cache, 1024, NULL);
690-
691693
cipher_t *cipher = (cipher_t *)ss_malloc(sizeof(cipher_t));
692694
memset(cipher, 0, sizeof(cipher_t));
693695

Diff for: src/crypto.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@
2929
#include <mbedtls/md5.h>
3030

3131
#include "base64.h"
32-
#include "cache.h"
3332
#include "crypto.h"
3433
#include "stream.h"
3534
#include "aead.h"
3635
#include "utils.h"
37-
38-
struct cache *nonce_cache;
36+
#include "ppbloom.h"
3937

4038
int
4139
balloc(buffer_t *ptr, size_t capacity)
@@ -111,8 +109,12 @@ crypto_init(const char *password, const char *key, const char *method)
111109
FATAL("Failed to initialize sodium");
112110
}
113111

114-
// Initialize NONCE cache
115-
cache_create(&nonce_cache, 1024, NULL);
112+
// Initialize NONCE bloom filter
113+
#ifdef MODULE_REMOTE
114+
ppbloom_init(1000000, 0.00001);
115+
#else
116+
ppbloom_init(100000, 0.0000001);
117+
#endif
116118

117119
if (method != NULL) {
118120
for (i = 0; i < STREAM_CIPHER_NUM; i++)

Diff for: src/crypto.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ typedef struct {
8484
} cipher_t;
8585

8686
typedef struct {
87-
uint8_t init;
87+
uint32_t init;
8888
uint64_t counter;
8989
cipher_evp_t *evp;
9090
cipher_t *cipher;

Diff for: src/jconf.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,7 @@ read_jconf(const char *file)
223223
"invalid config file: option 'reuse_port' must be a boolean");
224224
conf.reuse_port = value->u.boolean;
225225
} else if (strcmp(name, "auth") == 0) {
226-
check_json_value_type(value, json_boolean,
227-
"invalid config file: option 'auth' must be a boolean");
228-
conf.auth = value->u.boolean;
226+
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
229227
} else if (strcmp(name, "nofile") == 0) {
230228
check_json_value_type(value, json_integer,
231229
"invalid config file: option 'nofile' must be an integer");

Diff for: src/jconf.h

-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ typedef struct {
5959
char *user;
6060
char *plugin;
6161
char *plugin_opts;
62-
int auth;
6362
int fast_open;
6463
int reuse_port;
6564
int nofile;

Diff for: src/local.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
676676
struct sockaddr_storage storage;
677677
memset(&storage, 0, sizeof(struct sockaddr_storage));
678678
#ifndef ANDROID
679-
if (sni_detected || atyp == 3)
679+
if (atyp == 3)
680680
err = get_sockaddr(host, port, &storage, 0, ipv6first);
681681
else
682682
#endif
@@ -1211,10 +1211,10 @@ main(int argc, char **argv)
12111211
USE_TTY();
12121212

12131213
#ifdef ANDROID
1214-
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUvV6",
1214+
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUvV6A",
12151215
long_options, NULL)) != -1) {
12161216
#else
1217-
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUv6",
1217+
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUv6A",
12181218
long_options, NULL)) != -1) {
12191219
#endif
12201220
switch (c) {
@@ -1309,6 +1309,9 @@ main(int argc, char **argv)
13091309
vpn = 1;
13101310
break;
13111311
#endif
1312+
case 'A':
1313+
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
1314+
break;
13121315
case '?':
13131316
// The option character is not recognized.
13141317
LOGE("Unrecognized option: %s", optarg);

Diff for: src/manager.c

+3-16
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,6 @@ construct_command_line(struct manager_ctx *manager, struct server *server)
151151
int len = strlen(cmd);
152152
snprintf(cmd + len, BUF_SIZE - len, " -u");
153153
}
154-
if (manager->auth) {
155-
int len = strlen(cmd);
156-
snprintf(cmd + len, BUF_SIZE - len, " -A");
157-
}
158154
if (manager->fast_open) {
159155
int len = strlen(cmd);
160156
snprintf(cmd + len, BUF_SIZE - len, " --fast-open");
@@ -884,7 +880,6 @@ main(int argc, char **argv)
884880
char *plugin = NULL;
885881
char *plugin_opts = NULL;
886882

887-
int auth = 0;
888883
int fast_open = 0;
889884
int reuse_port = 0;
890885
int mode = TCP_ONLY;
@@ -999,14 +994,14 @@ main(int argc, char **argv)
999994
case 'h':
1000995
usage();
1001996
exit(EXIT_SUCCESS);
1002-
case 'A':
1003-
auth = 1;
1004-
break;
1005997
#ifdef HAVE_SETRLIMIT
1006998
case 'n':
1007999
nofile = atoi(optarg);
10081000
break;
10091001
#endif
1002+
case 'A':
1003+
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
1004+
break;
10101005
case '?':
10111006
// The option character is not recognized.
10121007
LOGE("Unrecognized option: %s", optarg);
@@ -1047,9 +1042,6 @@ main(int argc, char **argv)
10471042
if (conf->nameserver != NULL) {
10481043
nameservers[nameserver_num++] = conf->nameserver;
10491044
}
1050-
if (auth == 0) {
1051-
auth = conf->auth;
1052-
}
10531045
if (mode == TCP_ONLY) {
10541046
mode = conf->mode;
10551047
}
@@ -1107,10 +1099,6 @@ main(int argc, char **argv)
11071099
#endif
11081100
}
11091101

1110-
if (auth) {
1111-
LOGI("onetime authentication enabled");
1112-
}
1113-
11141102
// ignore SIGPIPE
11151103
signal(SIGPIPE, SIG_IGN);
11161104
signal(SIGCHLD, SIG_IGN);
@@ -1130,7 +1118,6 @@ main(int argc, char **argv)
11301118
manager.fast_open = fast_open;
11311119
manager.verbose = verbose;
11321120
manager.mode = mode;
1133-
manager.auth = auth;
11341121
manager.password = password;
11351122
manager.timeout = timeout;
11361123
manager.method = method;

Diff for: src/manager.h

-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ struct manager_ctx {
3838
int reuse_port;
3939
int verbose;
4040
int mode;
41-
int auth;
4241
char *password;
4342
char *key;
4443
char *timeout;

0 commit comments

Comments
 (0)