Browse Source

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.
pull/1284/head
Max Lv 7 years ago
committed by GitHub
parent
commit
b655fb2b8f
19 changed files with 217 additions and 77 deletions
  1. 4
      .gitmodules
  2. 5
      Makefile.am
  3. 3
      configure.ac
  4. 1
      libbloom
  5. 5
      src/Makefile.am
  6. 38
      src/aead.c
  7. 12
      src/crypto.c
  8. 2
      src/crypto.h
  9. 4
      src/jconf.c
  10. 1
      src/jconf.h
  11. 9
      src/local.c
  12. 19
      src/manager.c
  13. 1
      src/manager.h
  14. 98
      src/ppbloom.c
  15. 31
      src/ppbloom.h
  16. 5
      src/redir.c
  17. 5
      src/server.c
  18. 44
      src/stream.c
  19. 7
      src/tunnel.c

4
.gitmodules

@ -6,3 +6,7 @@
path = libipset path = libipset
url = https://github.com/shadowsocks/ipset.git url = https://github.com/shadowsocks/ipset.git
ignore = dirty ignore = dirty
[submodule "libbloom"]
path = libbloom
url = https://github.com/shadowsocks/libbloom.git
ignore = dirty

5
Makefile.am

@ -1,7 +1,7 @@
if USE_SYSTEM_SHARED_LIB if USE_SYSTEM_SHARED_LIB
SUBDIRS = src
SUBDIRS = src libbloom
else else
SUBDIRS = libcork libipset src
SUBDIRS = libcork libipset libbloom src
endif endif
if ENABLE_DOCUMENTATION if ENABLE_DOCUMENTATION
@ -14,6 +14,7 @@ pkgconfiglibdir = $(libdir)/pkgconfig
pkgconfiglib_DATA = shadowsocks-libev.pc pkgconfiglib_DATA = shadowsocks-libev.pc
EXTRA_DIST = acl Changes completions debian docker rpm README.md EXTRA_DIST = acl Changes completions debian docker rpm README.md
EXTRA_DIST += libbloom
EXTRA_DIST += libcork/include libipset/include EXTRA_DIST += libcork/include libipset/include
EXTRA_DIST += libipset/src/libipset/map/inspection-template.c.in EXTRA_DIST += libipset/src/libipset/map/inspection-template.c.in
EXTRA_DIST += libipset/src/libipset/set/inspection-template.c.in EXTRA_DIST += libipset/src/libipset/set/inspection-template.c.in

3
configure.ac

@ -230,7 +230,8 @@ AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn
AC_CONFIG_FILES([shadowsocks-libev.pc AC_CONFIG_FILES([shadowsocks-libev.pc
Makefile Makefile
src/Makefile])
src/Makefile
libbloom/Makefile])
AM_COND_IF([USE_SYSTEM_SHARED_LIB], AM_COND_IF([USE_SYSTEM_SHARED_LIB],
[AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])], [AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])],

1
libbloom

@ -0,0 +1 @@
Subproject commit f6e53fe6486c40b751b58e6e8e516aeb6247e493

5
src/Makefile.am

@ -2,6 +2,7 @@ VERSION_INFO = 2:0:0
AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE
AM_CFLAGS += $(PTHREAD_CFLAGS) AM_CFLAGS += $(PTHREAD_CFLAGS)
AM_CFLAGS += -I$(top_srcdir)/libbloom
if !USE_SYSTEM_SHARED_LIB if !USE_SYSTEM_SHARED_LIB
AM_CFLAGS += -I$(top_srcdir)/libipset/include AM_CFLAGS += -I$(top_srcdir)/libipset/include
AM_CFLAGS += -I$(top_srcdir)/libcork/include AM_CFLAGS += -I$(top_srcdir)/libcork/include
@ -9,6 +10,7 @@ endif
AM_CFLAGS += $(LIBPCRE_CFLAGS) AM_CFLAGS += $(LIBPCRE_CFLAGS)
SS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS) SS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS)
SS_COMMON_LIBS += $(top_builddir)/libbloom/libbloom.la
if !USE_SYSTEM_SHARED_LIB if !USE_SYSTEM_SHARED_LIB
SS_COMMON_LIBS += $(top_builddir)/libipset/libipset.la \ SS_COMMON_LIBS += $(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la $(top_builddir)/libcork/libcork.la
@ -26,6 +28,7 @@ sni_src = http.c \
crypto_src = crypto.c \ crypto_src = crypto.c \
aead.c \ aead.c \
stream.c \ stream.c \
ppbloom.c \
base64.c base64.c
plugin_src = plugin.c plugin_src = plugin.c
@ -112,6 +115,6 @@ libshadowsocks_libev_la_LIBADD = $(ss_local_LDADD)
include_HEADERS = shadowsocks.h include_HEADERS = shadowsocks.h
noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h tls.h uthash.h \ noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h tls.h uthash.h \
cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h base64.h \
cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h base64.h ppbloom.h \
common.h jconf.h manager.h protocol.h rule.h socks5.h udprelay.h common.h jconf.h manager.h protocol.h rule.h socks5.h udprelay.h
EXTRA_DIST = ss-nat EXTRA_DIST = ss-nat

38
src/aead.c

@ -33,7 +33,7 @@
#include <sodium.h> #include <sodium.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "cache.h"
#include "ppbloom.h"
#include "aead.h" #include "aead.h"
#include "utils.h" #include "utils.h"
@ -405,13 +405,11 @@ aead_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity)
(uint8_t *)plaintext->data, plaintext->len, (uint8_t *)plaintext->data, plaintext->len,
NULL, 0, cipher_ctx.nonce, cipher_ctx.skey); NULL, 0, cipher_ctx.nonce, cipher_ctx.skey);
if (err) {
bfree(plaintext);
aead_ctx_release(&cipher_ctx);
aead_ctx_release(&cipher_ctx);
if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
}
aead_ctx_release(&cipher_ctx);
assert(ciphertext->len == clen); assert(ciphertext->len == clen);
brealloc(plaintext, salt_len + ciphertext->len, capacity); brealloc(plaintext, salt_len + ciphertext->len, capacity);
@ -444,6 +442,11 @@ aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
uint8_t *salt = cipher_ctx.salt; uint8_t *salt = cipher_ctx.salt;
memcpy(salt, ciphertext->data, salt_len); memcpy(salt, ciphertext->data, salt_len);
if (ppbloom_check((void *)salt, salt_len) == 1) {
LOGE("crypto: AEAD: repeat salt detected");
return CRYPTO_ERROR;
}
aead_cipher_ctx_set_key(&cipher_ctx, 0); aead_cipher_ctx_set_key(&cipher_ctx, 0);
size_t plen = plaintext->len; size_t plen = plaintext->len;
@ -453,13 +456,12 @@ aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
ciphertext->len - salt_len, NULL, 0, ciphertext->len - salt_len, NULL, 0,
cipher_ctx.nonce, cipher_ctx.skey); cipher_ctx.nonce, cipher_ctx.skey);
if (err) {
bfree(ciphertext);
aead_ctx_release(&cipher_ctx);
aead_ctx_release(&cipher_ctx);
if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
}
aead_ctx_release(&cipher_ctx);
ppbloom_add((void *)salt, salt_len);
brealloc(ciphertext, plaintext->len, capacity); brealloc(ciphertext, plaintext->len, capacity);
memcpy(ciphertext->data, plaintext->data, plaintext->len); memcpy(ciphertext->data, plaintext->data, plaintext->len);
@ -488,6 +490,7 @@ aead_chunk_encrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c,
NULL, 0, n, ctx->skey); NULL, 0, n, ctx->skey);
if (err) if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
assert(clen == CHUNK_SIZE_LEN + tlen); assert(clen == CHUNK_SIZE_LEN + tlen);
sodium_increment(n, nlen); sodium_increment(n, nlen);
@ -497,6 +500,7 @@ aead_chunk_encrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c,
NULL, 0, n, ctx->skey); NULL, 0, n, ctx->skey);
if (err) if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
assert(clen == plen + tlen); assert(clen == plen + tlen);
sodium_increment(n, nlen); sodium_increment(n, nlen);
@ -634,12 +638,9 @@ aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
aead_cipher_ctx_set_key(cipher_ctx, 0); aead_cipher_ctx_set_key(cipher_ctx, 0);
if (cache_key_exist(nonce_cache, (char *)cipher_ctx->salt, salt_len)) {
if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) {
LOGE("crypto: AEAD: repeat salt detected"); LOGE("crypto: AEAD: repeat salt detected");
bfree(ciphertext);
return CRYPTO_ERROR; return CRYPTO_ERROR;
} else {
cache_insert(nonce_cache, (char *)cipher_ctx->salt, salt_len, NULL);
} }
memmove(cipher_ctx->chunk->data, cipher_ctx->chunk->data + salt_len, memmove(cipher_ctx->chunk->data, cipher_ctx->chunk->data + salt_len,
@ -647,6 +648,10 @@ aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
cipher_ctx->chunk->len -= salt_len; cipher_ctx->chunk->len -= salt_len;
cipher_ctx->init = 1; cipher_ctx->init = 1;
} else if (cipher_ctx->init == 1) {
ppbloom_add((void *)cipher_ctx->salt, salt_len);
cipher_ctx->init = 2;
} }
size_t plen = 0; size_t plen = 0;
@ -685,9 +690,6 @@ aead_key_init(int method, const char *pass, const char *key)
return NULL; return NULL;
} }
// Initialize cache
cache_create(&nonce_cache, 1024, NULL);
cipher_t *cipher = (cipher_t *)ss_malloc(sizeof(cipher_t)); cipher_t *cipher = (cipher_t *)ss_malloc(sizeof(cipher_t));
memset(cipher, 0, sizeof(cipher_t)); memset(cipher, 0, sizeof(cipher_t));

12
src/crypto.c

@ -29,13 +29,11 @@
#include <mbedtls/md5.h> #include <mbedtls/md5.h>
#include "base64.h" #include "base64.h"
#include "cache.h"
#include "crypto.h" #include "crypto.h"
#include "stream.h" #include "stream.h"
#include "aead.h" #include "aead.h"
#include "utils.h" #include "utils.h"
struct cache *nonce_cache;
#include "ppbloom.h"
int int
balloc(buffer_t *ptr, size_t capacity) balloc(buffer_t *ptr, size_t capacity)
@ -111,8 +109,12 @@ crypto_init(const char *password, const char *key, const char *method)
FATAL("Failed to initialize sodium"); FATAL("Failed to initialize sodium");
} }
// Initialize NONCE cache
cache_create(&nonce_cache, 1024, NULL);
// Initialize NONCE bloom filter
#ifdef MODULE_REMOTE
ppbloom_init(1000000, 0.00001);
#else
ppbloom_init(100000, 0.0000001);
#endif
if (method != NULL) { if (method != NULL) {
for (i = 0; i < STREAM_CIPHER_NUM; i++) for (i = 0; i < STREAM_CIPHER_NUM; i++)

2
src/crypto.h

@ -84,7 +84,7 @@ typedef struct {
} cipher_t; } cipher_t;
typedef struct { typedef struct {
uint8_t init;
uint32_t init;
uint64_t counter; uint64_t counter;
cipher_evp_t *evp; cipher_evp_t *evp;
cipher_t *cipher; cipher_t *cipher;

4
src/jconf.c

@ -223,9 +223,7 @@ read_jconf(const char *file)
"invalid config file: option 'reuse_port' must be a boolean"); "invalid config file: option 'reuse_port' must be a boolean");
conf.reuse_port = value->u.boolean; conf.reuse_port = value->u.boolean;
} else if (strcmp(name, "auth") == 0) { } else if (strcmp(name, "auth") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'auth' must be a boolean");
conf.auth = value->u.boolean;
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
} else if (strcmp(name, "nofile") == 0) { } else if (strcmp(name, "nofile") == 0) {
check_json_value_type(value, json_integer, check_json_value_type(value, json_integer,
"invalid config file: option 'nofile' must be an integer"); "invalid config file: option 'nofile' must be an integer");

1
src/jconf.h

@ -59,7 +59,6 @@ typedef struct {
char *user; char *user;
char *plugin; char *plugin;
char *plugin_opts; char *plugin_opts;
int auth;
int fast_open; int fast_open;
int reuse_port; int reuse_port;
int nofile; int nofile;

9
src/local.c

@ -676,7 +676,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
struct sockaddr_storage storage; struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage)); memset(&storage, 0, sizeof(struct sockaddr_storage));
#ifndef ANDROID #ifndef ANDROID
if (sni_detected || atyp == 3)
if (atyp == 3)
err = get_sockaddr(host, port, &storage, 0, ipv6first); err = get_sockaddr(host, port, &storage, 0, ipv6first);
else else
#endif #endif
@ -1211,10 +1211,10 @@ main(int argc, char **argv)
USE_TTY(); USE_TTY();
#ifdef ANDROID #ifdef ANDROID
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUvV6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUvV6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
#else #else
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUv6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUv6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
#endif #endif
switch (c) { switch (c) {
@ -1309,6 +1309,9 @@ main(int argc, char **argv)
vpn = 1; vpn = 1;
break; break;
#endif #endif
case 'A':
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
break;
case '?': case '?':
// The option character is not recognized. // The option character is not recognized.
LOGE("Unrecognized option: %s", optarg); LOGE("Unrecognized option: %s", optarg);

19
src/manager.c

@ -151,10 +151,6 @@ construct_command_line(struct manager_ctx *manager, struct server *server)
int len = strlen(cmd); int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " -u"); snprintf(cmd + len, BUF_SIZE - len, " -u");
} }
if (manager->auth) {
int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " -A");
}
if (manager->fast_open) { if (manager->fast_open) {
int len = strlen(cmd); int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " --fast-open"); snprintf(cmd + len, BUF_SIZE - len, " --fast-open");
@ -884,7 +880,6 @@ main(int argc, char **argv)
char *plugin = NULL; char *plugin = NULL;
char *plugin_opts = NULL; char *plugin_opts = NULL;
int auth = 0;
int fast_open = 0; int fast_open = 0;
int reuse_port = 0; int reuse_port = 0;
int mode = TCP_ONLY; int mode = TCP_ONLY;
@ -999,14 +994,14 @@ main(int argc, char **argv)
case 'h': case 'h':
usage(); usage();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'A':
auth = 1;
break;
#ifdef HAVE_SETRLIMIT #ifdef HAVE_SETRLIMIT
case 'n': case 'n':
nofile = atoi(optarg); nofile = atoi(optarg);
break; break;
#endif #endif
case 'A':
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
break;
case '?': case '?':
// The option character is not recognized. // The option character is not recognized.
LOGE("Unrecognized option: %s", optarg); LOGE("Unrecognized option: %s", optarg);
@ -1047,9 +1042,6 @@ main(int argc, char **argv)
if (conf->nameserver != NULL) { if (conf->nameserver != NULL) {
nameservers[nameserver_num++] = conf->nameserver; nameservers[nameserver_num++] = conf->nameserver;
} }
if (auth == 0) {
auth = conf->auth;
}
if (mode == TCP_ONLY) { if (mode == TCP_ONLY) {
mode = conf->mode; mode = conf->mode;
} }
@ -1107,10 +1099,6 @@ main(int argc, char **argv)
#endif #endif
} }
if (auth) {
LOGI("onetime authentication enabled");
}
// ignore SIGPIPE // ignore SIGPIPE
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
@ -1130,7 +1118,6 @@ main(int argc, char **argv)
manager.fast_open = fast_open; manager.fast_open = fast_open;
manager.verbose = verbose; manager.verbose = verbose;
manager.mode = mode; manager.mode = mode;
manager.auth = auth;
manager.password = password; manager.password = password;
manager.timeout = timeout; manager.timeout = timeout;
manager.method = method; manager.method = method;

1
src/manager.h

@ -38,7 +38,6 @@ struct manager_ctx {
int reuse_port; int reuse_port;
int verbose; int verbose;
int mode; int mode;
int auth;
char *password; char *password;
char *key; char *key;
char *timeout; char *timeout;

98
src/ppbloom.c

@ -0,0 +1,98 @@
/*
* ppbloom.c - Ping-Pong Bloom Filter for nonce reuse detection
*
* Copyright (C) 2013 - 2017, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdlib.h>
#include "bloom.h"
#include "ppbloom.h"
#include "utils.h"
#define PING 0
#define PONG 1
static struct bloom ppbloom[2];
static int bloom_count[2];
static int current;
static int entries;
static double error;
int
ppbloom_init(int n, double e)
{
int err;
entries = n / 2;
error = e;
err = bloom_init(ppbloom + PING, entries, error);
if (err) return err;
err = bloom_init(ppbloom + PONG, entries, error);
if (err) return err;
bloom_count[PING] = 0;
bloom_count[PONG] = 0;
current = PING;
return 0;
}
int
ppbloom_check(const void *buffer, int len)
{
int ret;
ret = bloom_check(ppbloom + PING, buffer, len);
if (ret) return ret;
ret = bloom_check(ppbloom + PONG, buffer, len);
if (ret) return ret;
return 0;
}
int
ppbloom_add(const void *buffer, int len)
{
int err;
err = bloom_add(ppbloom + current, buffer, len);
if (err == -1) return err;
bloom_count[current]++;
if (bloom_count[current] >= entries) {
bloom_count[current] = 0;
current = current == PING ? PONG : PING;
bloom_free(ppbloom + current);
bloom_init(ppbloom + current, entries, error);
}
return 0;
}
void
ppbloom_free()
{
bloom_free(ppbloom + PING);
bloom_free(ppbloom + PONG);
}

31
src/ppbloom.h

@ -0,0 +1,31 @@
/*
* ppbloom.h - Define the Ping-Pong Bloom Filter interface
*
* Copyright (C) 2013 - 2017, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _PPBLOOM_
#define _PPBLOOM_
int ppbloom_init(int entries, double error);
int ppbloom_check(const void * buffer, int len);
int ppbloom_add(const void * buffer, int len);
void ppbloom_free(void);
#endif

5
src/redir.c

@ -818,7 +818,7 @@ main(int argc, char **argv)
USE_TTY(); USE_TTY();
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUv6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUv6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case GETOPT_VAL_MTU: case GETOPT_VAL_MTU:
@ -897,6 +897,9 @@ main(int argc, char **argv)
case '6': case '6':
ipv6first = 1; ipv6first = 1;
break; break;
case 'A':
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
break;
case '?': case '?':
// The option character is not recognized. // The option character is not recognized.
LOGE("Unrecognized option: %s", optarg); LOGE("Unrecognized option: %s", optarg);

5
src/server.c

@ -1384,7 +1384,7 @@ main(int argc, char **argv)
USE_TTY(); USE_TTY();
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:b:c:i:d:a:n:huUv6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:b:c:i:d:a:n:huUv6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case GETOPT_VAL_FAST_OPEN: case GETOPT_VAL_FAST_OPEN:
@ -1477,6 +1477,9 @@ main(int argc, char **argv)
case '6': case '6':
ipv6first = 1; ipv6first = 1;
break; break;
case 'A':
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
break;
case '?': case '?':
// The option character is not recognized. // The option character is not recognized.
LOGE("Unrecognized option: %s", optarg); LOGE("Unrecognized option: %s", optarg);

44
src/stream.c

@ -31,7 +31,7 @@
#include <sodium.h> #include <sodium.h>
#include "cache.h"
#include "ppbloom.h"
#include "stream.h" #include "stream.h"
#include "utils.h" #include "utils.h"
@ -321,11 +321,10 @@ stream_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity)
plaintext->len); plaintext->len);
} }
if (err) {
bfree(plaintext);
stream_ctx_release(&cipher_ctx);
stream_ctx_release(&cipher_ctx);
if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
}
#ifdef SS_DEBUG #ifdef SS_DEBUG
dump("PLAIN", plaintext->data, plaintext->len); dump("PLAIN", plaintext->data, plaintext->len);
@ -333,8 +332,6 @@ stream_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity)
dump("NONCE", ciphertext->data, nonce_len); dump("NONCE", ciphertext->data, nonce_len);
#endif #endif
stream_ctx_release(&cipher_ctx);
brealloc(plaintext, nonce_len + ciphertext->len, capacity); brealloc(plaintext, nonce_len + ciphertext->len, capacity);
memcpy(plaintext->data, ciphertext->data, nonce_len + ciphertext->len); memcpy(plaintext->data, ciphertext->data, nonce_len + ciphertext->len);
plaintext->len = nonce_len + ciphertext->len; plaintext->len = nonce_len + ciphertext->len;
@ -430,6 +427,12 @@ stream_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
uint8_t *nonce = cipher_ctx.nonce; uint8_t *nonce = cipher_ctx.nonce;
memcpy(nonce, ciphertext->data, nonce_len); memcpy(nonce, ciphertext->data, nonce_len);
if (ppbloom_check((void *)nonce, nonce_len) == 1) {
LOGE("crypto: stream: repeat IV detected");
return CRYPTO_ERROR;
}
cipher_ctx_set_nonce(&cipher_ctx, nonce, nonce_len, 0); cipher_ctx_set_nonce(&cipher_ctx, nonce, nonce_len, 0);
if (cipher->method >= SALSA20) { if (cipher->method >= SALSA20) {
@ -443,11 +446,10 @@ stream_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
ciphertext->len - nonce_len); ciphertext->len - nonce_len);
} }
if (err) {
bfree(ciphertext);
stream_ctx_release(&cipher_ctx);
stream_ctx_release(&cipher_ctx);
if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
}
#ifdef SS_DEBUG #ifdef SS_DEBUG
dump("PLAIN", plaintext->data, plaintext->len); dump("PLAIN", plaintext->data, plaintext->len);
@ -455,7 +457,7 @@ stream_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity)
dump("NONCE", ciphertext->data, nonce_len); dump("NONCE", ciphertext->data, nonce_len);
#endif #endif
stream_ctx_release(&cipher_ctx);
ppbloom_add((void *)nonce, nonce_len);
brealloc(ciphertext, plaintext->len, capacity); brealloc(ciphertext, plaintext->len, capacity);
memcpy(ciphertext->data, plaintext->data, plaintext->len); memcpy(ciphertext->data, plaintext->data, plaintext->len);
@ -468,7 +470,7 @@ int
stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
{ {
if (cipher_ctx == NULL) if (cipher_ctx == NULL)
return -1;
return CRYPTO_ERROR;
cipher_t *cipher = cipher_ctx->cipher; cipher_t *cipher = cipher_ctx->cipher;
@ -511,14 +513,16 @@ stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
cipher_ctx->init = 1; cipher_ctx->init = 1;
if (cipher->method >= RC4_MD5) { if (cipher->method >= RC4_MD5) {
if (cache_key_exist(nonce_cache, (char *)nonce, nonce_len)) {
if (ppbloom_check((void *)nonce, nonce_len) == 1) {
LOGE("crypto: stream: repeat IV detected"); LOGE("crypto: stream: repeat IV detected");
bfree(ciphertext);
return -1;
} else {
cache_insert(nonce_cache, (char *)nonce, nonce_len, NULL);
return CRYPTO_ERROR;
} }
} }
} else if (cipher_ctx->init == 1) {
if (cipher->method >= RC4_MD5) {
ppbloom_add((void *)cipher_ctx->nonce, cipher->nonce_len);
cipher_ctx->init = 2;
}
} }
if (ciphertext->len <= 0) if (ciphertext->len <= 0)
@ -550,10 +554,8 @@ stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity)
ciphertext->len); ciphertext->len);
} }
if (err) {
bfree(ciphertext);
if (err)
return CRYPTO_ERROR; return CRYPTO_ERROR;
}
#ifdef SS_DEBUG #ifdef SS_DEBUG
dump("PLAIN", plaintext->data, plaintext->len); dump("PLAIN", plaintext->data, plaintext->len);

7
src/tunnel.c

@ -766,10 +766,10 @@ main(int argc, char **argv)
USE_TTY(); USE_TTY();
#ifdef ANDROID #ifdef ANDROID
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUvV6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUvV6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
#else #else
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUv6",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUv6A",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
#endif #endif
switch (c) { switch (c) {
@ -860,6 +860,9 @@ main(int argc, char **argv)
vpn = 1; vpn = 1;
break; break;
#endif #endif
case 'A':
FATAL("One time auth has been deprecated. Try AEAD ciphers instead.");
break;
case '?': case '?':
// The option character is not recognized. // The option character is not recognized.
LOGE("Unrecognized option: %s", optarg); LOGE("Unrecognized option: %s", optarg);

Loading…
Cancel
Save