Merge branch 'dev' into speck

This commit is contained in:
Luca Deri 2020-06-07 10:10:20 +02:00 committed by GitHub
commit 3b0903785e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 76 deletions

View File

@ -106,10 +106,11 @@ n2n edge nodes use twofish encryption by default for compatibility reasons with
of the edge nodes, their IP address and the community are sent in cleartext.
When encryption is enabled, the supernode will not be able to decrypt the traffic exchanged between
two edge nodes, but it will now that edge A is talking with edge B.
two edge nodes, but it will know that edge A is talking with edge B.
Recently AES encryption support has been implemented, which increases both security and performance,
so it is recommended to enable it on all the edge nodes by specifying the `-A` option.
so it is recommended to enable it on all the edge nodes that must have the -Ax value. When possible
(i.e. when n2n is compiled with OpenSSL 1.1) we recommend to use -A4
A benchmark of the encryption methods is available when compiled from source with `tools/n2n-benchmark`.

View File

@ -13,14 +13,24 @@ else
GIT_RELEASE=${N2N_VERSION_SHORT}
fi
N2N_LIBS=
AC_CHECK_LIB([zstd], [ZSTD_compress])
if test "x$ac_cv_lib_zstd_ZSTD_compress" != xyes; then
AC_MSG_RESULT(Building n2n without ZSTD support)
else
AC_DEFINE([N2N_HAVE_ZSTD], [], [Have ZSTD support])
N2N_LIBS="-lzstd ${N2N_LIBS}"
fi
AC_CHECK_LIB([crypto], [AES_cbc_encrypt])
N2N_LIBS=
if test "x$ac_cv_lib_crypto_AES_cbc_encrypt" != xyes; then
AC_MSG_RESULT(Building n2n without AES support)
else
AC_DEFINE([N2N_HAVE_AES], [], [Have AES support])
N2N_LIBS=-lcrypto
N2N_LIBS="-lcrypto ${N2N_LIBS}"
fi
OLD_CFLAGS="${CFLAGS}"

138
edge.c
View File

@ -159,7 +159,7 @@ static void help() {
#ifndef __APPLE__
"[-D] "
#endif
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-h]\n\n");
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-z[<compression algo>]] [-h]\n\n");
#if defined(N2N_CAN_NAME_IFACE)
printf("-d <tun device> | tun device name\n");
@ -189,16 +189,22 @@ static void help() {
#endif
printf("-r | Enable packet forwarding through n2n community.\n");
printf("-A1 | Disable payload encryption. Do not use with -k.\n");
printf("-A2 | Use Twofish for payload encryption (default). Requires a key.\n");
printf("-A2 | Use Twofish for payload encryption (default). Requires a key (-k).\n");
#ifdef N2N_HAVE_AES
printf("-A3 or -A (deprecated) | Use AES-CBC for payload encryption. Requires a key.\n");
printf("-A3 or -A (deprecated) | Use AES-CBC for payload encryption. Requires a key (-k).\n");
#endif
#ifdef HAVE_OPENSSL_1_1
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
#endif
printf("-z | Enable lzo1x compression for outgoing data packets\n");
printf(" | (default=disabled).\n");
#ifdef HAVE_OPENSSL_1_1
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key (-k).\n");
#endif
printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n");
#ifdef N2N_HAVE_ZSTD
printf("-z2 | Enable zstd compression for outgoing data packets\n");
#endif
printf(" | (default=compression disabled)\n");
printf("-E | Accept multicast MAC addresses (default=drop).\n");
printf("-S | Do not connect P2P. Always use the supernode.\n");
#ifdef __linux__
@ -221,6 +227,46 @@ static void help() {
/* *************************************************** */
static void setPayloadEncryption( n2n_edge_conf_t *conf, int cipher) {
/* even though 'cipher' and 'conf->transop_id' share the same encoding scheme,
* a switch-statement under conditional compilation is used to sort out the
* unsupported ciphers */
switch (cipher) {
case 1:
{
conf->transop_id = N2N_TRANSFORM_ID_NULL;
break;
}
case 2:
{
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
break;
}
#ifdef N2N_HAVE_AES
case 3:
{
conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
break;
}
#endif
#ifdef HAVE_OPENSSL_1_1
case 4:
{
conf->transop_id = N2N_TRANSFORM_ID_CHACHA20;
break;
}
#endif
default:
{
conf->transop_id = N2N_TRANSFORM_ID_INVAL;
traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version.", transop_str(cipher));
exit(1);
}
}
}
/* *************************************************** */
static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_edge_conf_t *conf) {
/* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */
@ -309,59 +355,50 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
case 'A':
{
int cipher = N2N_TRANSFORM_ID_AESCBC; // default, if '-A' only
int cipher;
if (optargument) {
cipher = atoi(optargument);
} else {
traceEvent(TRACE_NORMAL, "the use of the solitary -A switch is deprecated and might not be supported in future versions. "
"please use -A3 instead to choose a the AES-CBC cipher for payload encryption.");
cipher = N2N_TRANSFORM_ID_AESCBC; // default, if '-A' only
}
/* even though 'cipher' and 'conf->transop_id' share the same encoding scheme,
* a switch-statement under conditional compilation is used to sort out the
* unsupported ciphers */
switch (cipher) {
case 1:
{
conf->transop_id = N2N_TRANSFORM_ID_NULL;
break;
}
case 2:
{
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
break;
}
#ifdef N2N_HAVE_AES
case 3:
{
conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
break;
}
#endif
#ifdef HAVE_OPENSSL_1_1
case 4:
{
conf->transop_id = N2N_TRANSFORM_ID_CHACHA20;
break;
}
#endif
case 5:
{
conf->transop_id = N2N_TRANSFORM_ID_SPECK;
break;
}
default:
{
conf->transop_id = N2N_TRANSFORM_ID_INVAL;
traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version.", transop_str(cipher));
exit(1);
}
}
setPayloadEncryption(conf, cipher);
break;
}
case 'z':
{
conf->compression = N2N_COMPRESSION_ID_LZO;
int compression = N2N_COMPRESSION_ID_LZO; // default, if '-z' only
if (optargument) {
compression = atoi(optargument);
}
/* even though 'compression' and 'conf->compression' share the same encoding scheme,
* a switch-statement under conditional compilation is used to sort out the
* unsupported optarguments */
switch (compression) {
case 1:
{
conf->compression = N2N_COMPRESSION_ID_LZO;
break;
}
#ifdef N2N_HAVE_ZSTD
case 2:
{
conf->compression = N2N_COMPRESSION_ID_ZSTD;
break;
}
#endif
default:
{
conf->compression = N2N_COMPRESSION_ID_NONE;
traceEvent(TRACE_NORMAL, "the %s compression given by -z_ option is not supported in this version.", compression_str(compression));
exit(1); // to make the user aware
}
}
break;
}
@ -509,10 +546,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c
u_char c;
while((c = getopt_long(argc, argv,
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z"
"A::"
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:zA:z::"
#ifdef __linux__
"T:n:"
#endif
@ -796,6 +830,8 @@ int main(int argc, char* argv[]) {
#if defined(HAVE_OPENSSL_1_1)
traceEvent(TRACE_NORMAL, "Using %s", OpenSSL_version(0));
#endif
traceEvent(TRACE_NORMAL, "Using compression: %s.", compression_str(conf.compression));
traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id));
/* Random seed */

View File

@ -18,6 +18,7 @@
#include "n2n.h"
#include "lzoconf.h"
#include <zstd.h>
#ifdef WIN32
#include <process.h>
@ -158,6 +159,17 @@ const char* transop_str(enum n2n_transform tr) {
/* ************************************** */
const char* compression_str(uint8_t cmpr) {
switch(cmpr) {
case N2N_COMPRESSION_ID_NONE: return("none");
case N2N_COMPRESSION_ID_LZO: return("lzo1x");
case N2N_COMPRESSION_ID_ZSTD: return("zstd");
default: return("invalid");
};
}
/* ************************************** */
/** Destination 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF is multicast ethernet.
*/
static int is_ethMulticast(const void * buf, size_t bufsize) {
@ -237,6 +249,10 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
goto edge_init_error;
}
#ifdef N2N_HAVE_ZSTD
// zstd does not require initialization. if it were required, this would be a good place
#endif
for(i=0; i<conf->sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
@ -261,7 +277,6 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
case N2N_TRANSFORM_ID_SPECK:
rc = n2n_transop_speck_init(&eee->conf, &eee->transop);
break;
default:
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
}
@ -997,20 +1012,37 @@ static int handle_PACKET(n2n_edge_t * eee,
/* decompress if necessary */
uint8_t * deflation_buffer = 0;
uint32_t deflated_len;
int32_t deflated_len;
switch (rx_compression_id) {
case N2N_COMPRESSION_ID_NONE:
break; // continue afterwards
case N2N_COMPRESSION_ID_LZO:
deflation_buffer = malloc (N2N_PKT_BUF_SIZE);
deflation_buffer = malloc (N2N_PKT_BUF_SIZE);
lzo1x_decompress (eth_payload, eth_size, deflation_buffer, (lzo_uint*)&deflated_len, NULL);
break;
default:
#ifdef N2N_HAVE_ZSTD
case N2N_COMPRESSION_ID_ZSTD:
deflated_len = N2N_PKT_BUF_SIZE;
deflation_buffer = malloc (deflated_len);
deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size);
if (ZSTD_isError(deflated_len)) {
traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.",
ZSTD_getErrorName(deflated_len));
free (deflation_buffer);
return (-1); // cannot help it
}
break;
#endif
default:
traceEvent (TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.",
compression_str(rx_compression_id));
return (-1); // cannot handle it
}
if (rx_compression_id) {
traceEvent (TRACE_DEBUG, "payload decompression [id: %u]: deflated %u bytes to %u bytes",
rx_compression_id, eth_size, (int)deflated_len);
traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes",
compression_str(rx_compression_id), eth_size, (int)deflated_len);
memcpy(eth_payload ,deflation_buffer, deflated_len );
eth_size = deflated_len;
free (deflation_buffer);
@ -1375,9 +1407,11 @@ static void send_packet2net(n2n_edge_t * eee,
// compression needs to be tried before encode_PACKET is called for compression indication gets encoded there
pkt.compression = N2N_COMPRESSION_ID_NONE;
if (eee->conf.compression) {
uint8_t * compression_buffer;
uint32_t compression_len;
int32_t compression_len;
switch (eee->conf.compression) {
case N2N_COMPRESSION_ID_LZO:
compression_buffer = malloc (len + len / 16 + 64 + 3);
@ -1387,14 +1421,30 @@ static void send_packet2net(n2n_edge_t * eee,
}
}
break;
#ifdef N2N_HAVE_ZSTD
case N2N_COMPRESSION_ID_ZSTD:
compression_len = N2N_PKT_BUF_SIZE + 128;
compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower)
compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ;
if (!ZSTD_isError(compression_len)) {
if (compression_len < len) {
pkt.compression = N2N_COMPRESSION_ID_ZSTD;
}
} else {
traceEvent (TRACE_ERROR, "payload compression failed with zstd error '%s'.",
ZSTD_getErrorName(compression_len));
free (compression_buffer);
// continue with unset without pkt.compression --> will send uncompressed
}
break;
#endif
default:
break;
}
if (pkt.compression) {
traceEvent (TRACE_DEBUG, "payload compression [id: %u]: compressed %u bytes to %u bytes\n",
pkt.compression, len, compression_len);
traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n",
compression_str(pkt.compression), len, compression_len);
memcpy (tap_pkt, compression_buffer, compression_len);
len = compression_len;

12
n2n.h
View File

@ -164,9 +164,15 @@ typedef struct tuntap_dev {
/* N2N compression indicators. */
/* Compression is disabled by default for outgoing packets if no cli
* option is given. All edges are built with decompression support so
* they are able to understand each other. */
* they are able to understand each other (this applies to lzo only). */
#define N2N_COMPRESSION_ID_NONE 0 /* default, see edge_init_conf_defaults(...) in edge_utils.c */
#define N2N_COMPRESSION_ID_LZO 1 /* set if '-z' cli option is present, see setOption(...) in edge.c */
#define N2N_COMPRESSION_ID_LZO 1 /* set if '-z1' or '-z' cli option is present, see setOption(...) in edge.c */
#ifdef N2N_HAVE_ZSTD
#define N2N_COMPRESSION_ID_ZSTD 2 /* set if '-z2' cli option is present, available only if compiled with zstd lib */
#define ZSTD_COMPRESSION_LEVEL 7 /* 1 (faster) ... 22 (more compression) */
#endif
// with the next major packet structure update, make '0' = invalid, and '1' = no compression
// '2' = LZO, '3' = ZSTD, ... REVISIT then (also: change all occurences in source).
#define N2N_COMPRESSION_ID_BITLEN 3 /* number of bits used for encoding compression id in the uppermost
bits of transform_id; will be obsolete as soon as compression gets
@ -200,7 +206,6 @@ struct peer_info {
HASH_ADD(hh,head,mac_addr,sizeof(n2n_mac_t),add)
#define HASH_FIND_PEER(head,mac,out) \
HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out)
#define N2N_EDGE_SN_HOST_SIZE 48
#define N2N_EDGE_NUM_SUPERNODES 2
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
@ -369,6 +374,7 @@ int quick_edge_init(char *device_name, char *community_name,
int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss);
int run_sn_loop(n2n_sn_t *sss, int *keep_running);
const char* compression_str(uint8_t cmpr);
const char* transop_str(enum n2n_transform tr);
#endif /* _N2N_H_ */

View File

@ -100,6 +100,7 @@ int main(int argc, char * argv[]) {
#ifdef HAVE_OPENSSL_1_1
n2n_trans_op_t transop_cc20;
#endif
n2n_trans_op_t transop_speck;
n2n_edge_conf_t conf;
@ -120,7 +121,7 @@ int main(int argc, char * argv[]) {
n2n_transop_cc20_init(&conf, &transop_cc20);
#endif
n2n_transop_speck_init(&conf, &transop_speck);
/* Run the tests */
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
run_transop_benchmark("transop_twofish", &transop_twofish, &conf, pktbuf);

View File

@ -120,9 +120,6 @@ static int transop_encode_cc20(n2n_trans_op_t * arg,
/* Generate and encode the IV. */
set_cc20_iv(priv, enc_ivec);
encode_buf(outbuf, &idx, &enc_ivec, N2N_CC20_IVEC_SIZE);
traceEvent(TRACE_DEBUG, "encode_cc20 iv=%016llx:%016llx",
htobe64(*(uint64_t*)&enc_ivec[0]),
htobe64(*(uint64_t*)&enc_ivec[8]) );
/* Encrypt the assembly contents and write the ciphertext after the iv. */
/* len is set to the length of the cipher plain text to be encrpyted
@ -198,9 +195,6 @@ static int transop_decode_cc20(n2n_trans_op_t * arg,
/* Get the IV */
decode_buf((uint8_t *)&dec_ivec, N2N_CC20_IVEC_SIZE, inbuf, &rem, &idx);
traceEvent(TRACE_DEBUG, "decode_cc20 iv=%016llx:%016llx",
htobe64(*(uint64_t*)&dec_ivec[0]),
htobe64(*(uint64_t*)&dec_ivec[8]) );
EVP_CIPHER_CTX *ctx = priv->dec_ctx;
int evp_len;