Browse Source

Merge branch 'dev' into speck

pull/249/head
Luca Deri 5 years ago
committed by GitHub
parent
commit
3b0903785e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      README.md
  2. 14
      configure.seed
  3. 118
      edge.c
  4. 70
      edge_utils.c
  5. 12
      n2n.h
  6. 1
      tools/benchmark.c
  7. 6
      transform_cc20.c

5
README.md

@ -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. 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 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, 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`. A benchmark of the encryption methods is available when compiled from source with `tools/n2n-benchmark`.

14
configure.seed

@ -13,14 +13,24 @@ else
GIT_RELEASE=${N2N_VERSION_SHORT} GIT_RELEASE=${N2N_VERSION_SHORT}
fi 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]) AC_CHECK_LIB([crypto], [AES_cbc_encrypt])
N2N_LIBS=
if test "x$ac_cv_lib_crypto_AES_cbc_encrypt" != xyes; then if test "x$ac_cv_lib_crypto_AES_cbc_encrypt" != xyes; then
AC_MSG_RESULT(Building n2n without AES support) AC_MSG_RESULT(Building n2n without AES support)
else else
AC_DEFINE([N2N_HAVE_AES], [], [Have AES support]) AC_DEFINE([N2N_HAVE_AES], [], [Have AES support])
N2N_LIBS=-lcrypto N2N_LIBS="-lcrypto ${N2N_LIBS}"
fi fi
OLD_CFLAGS="${CFLAGS}" OLD_CFLAGS="${CFLAGS}"

118
edge.c

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

70
edge_utils.c

@ -18,6 +18,7 @@
#include "n2n.h" #include "n2n.h"
#include "lzoconf.h" #include "lzoconf.h"
#include <zstd.h>
#ifdef WIN32 #ifdef WIN32
#include <process.h> #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. /** 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) { 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; 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) for(i=0; i<conf->sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[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: case N2N_TRANSFORM_ID_SPECK:
rc = n2n_transop_speck_init(&eee->conf, &eee->transop); rc = n2n_transop_speck_init(&eee->conf, &eee->transop);
break; break;
default: default:
rc = n2n_transop_null_init(&eee->conf, &eee->transop); rc = n2n_transop_null_init(&eee->conf, &eee->transop);
} }
@ -997,20 +1012,37 @@ static int handle_PACKET(n2n_edge_t * eee,
/* decompress if necessary */ /* decompress if necessary */
uint8_t * deflation_buffer = 0; uint8_t * deflation_buffer = 0;
uint32_t deflated_len; int32_t deflated_len;
switch (rx_compression_id) { switch (rx_compression_id) {
case N2N_COMPRESSION_ID_NONE:
break; // continue afterwards
case N2N_COMPRESSION_ID_LZO: 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); lzo1x_decompress (eth_payload, eth_size, deflation_buffer, (lzo_uint*)&deflated_len, NULL);
break; break;
#ifdef N2N_HAVE_ZSTD
default: 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; 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) { if (rx_compression_id) {
traceEvent (TRACE_DEBUG, "payload decompression [id: %u]: deflated %u bytes to %u bytes", traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes",
rx_compression_id, eth_size, (int)deflated_len); compression_str(rx_compression_id), eth_size, (int)deflated_len);
memcpy(eth_payload ,deflation_buffer, deflated_len ); memcpy(eth_payload ,deflation_buffer, deflated_len );
eth_size = deflated_len; eth_size = deflated_len;
free (deflation_buffer); 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 // compression needs to be tried before encode_PACKET is called for compression indication gets encoded there
pkt.compression = N2N_COMPRESSION_ID_NONE; pkt.compression = N2N_COMPRESSION_ID_NONE;
if (eee->conf.compression) { if (eee->conf.compression) {
uint8_t * compression_buffer; uint8_t * compression_buffer;
uint32_t compression_len; int32_t compression_len;
switch (eee->conf.compression) { switch (eee->conf.compression) {
case N2N_COMPRESSION_ID_LZO: case N2N_COMPRESSION_ID_LZO:
compression_buffer = malloc (len + len / 16 + 64 + 3); compression_buffer = malloc (len + len / 16 + 64 + 3);
@ -1387,14 +1421,30 @@ static void send_packet2net(n2n_edge_t * eee,
} }
} }
break; 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: default:
break; break;
} }
if (pkt.compression) { if (pkt.compression) {
traceEvent (TRACE_DEBUG, "payload compression [id: %u]: compressed %u bytes to %u bytes\n", traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n",
pkt.compression, len, compression_len); compression_str(pkt.compression), len, compression_len);
memcpy (tap_pkt, compression_buffer, compression_len); memcpy (tap_pkt, compression_buffer, compression_len);
len = compression_len; len = compression_len;

12
n2n.h

@ -164,9 +164,15 @@ typedef struct tuntap_dev {
/* N2N compression indicators. */ /* N2N compression indicators. */
/* Compression is disabled by default for outgoing packets if no cli /* Compression is disabled by default for outgoing packets if no cli
* option is given. All edges are built with decompression support so * 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_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 #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 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) HASH_ADD(hh,head,mac_addr,sizeof(n2n_mac_t),add)
#define HASH_FIND_PEER(head,mac,out) \ #define HASH_FIND_PEER(head,mac,out) \
HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out) HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out)
#define N2N_EDGE_SN_HOST_SIZE 48 #define N2N_EDGE_SN_HOST_SIZE 48
#define N2N_EDGE_NUM_SUPERNODES 2 #define N2N_EDGE_NUM_SUPERNODES 2
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */ #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); int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss); void sn_term(n2n_sn_t *sss);
int run_sn_loop(n2n_sn_t *sss, int *keep_running); 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); const char* transop_str(enum n2n_transform tr);
#endif /* _N2N_H_ */ #endif /* _N2N_H_ */

1
tools/benchmark.c

@ -100,6 +100,7 @@ int main(int argc, char * argv[]) {
#ifdef HAVE_OPENSSL_1_1 #ifdef HAVE_OPENSSL_1_1
n2n_trans_op_t transop_cc20; n2n_trans_op_t transop_cc20;
#endif #endif
n2n_trans_op_t transop_speck; n2n_trans_op_t transop_speck;
n2n_edge_conf_t conf; n2n_edge_conf_t conf;

6
transform_cc20.c

@ -120,9 +120,6 @@ static int transop_encode_cc20(n2n_trans_op_t * arg,
/* Generate and encode the IV. */ /* Generate and encode the IV. */
set_cc20_iv(priv, enc_ivec); set_cc20_iv(priv, enc_ivec);
encode_buf(outbuf, &idx, &enc_ivec, N2N_CC20_IVEC_SIZE); 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. */ /* 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 /* 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 */ /* Get the IV */
decode_buf((uint8_t *)&dec_ivec, N2N_CC20_IVEC_SIZE, inbuf, &rem, &idx); 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; EVP_CIPHER_CTX *ctx = priv->dec_ctx;
int evp_len; int evp_len;

Loading…
Cancel
Save