Merge remote-tracking branch 'origin/dev' into hin2n_android

This commit is contained in:
emanuele-f 2020-06-28 17:52:21 +02:00
commit 0b4d36f7bd
48 changed files with 2164 additions and 1206 deletions

View File

@ -61,7 +61,12 @@ add_library(n2n n2n.c
transform_null.c transform_null.c
transform_tf.c transform_tf.c
transform_aes.c transform_aes.c
transform_cc20.c
transform_speck.c
speck.c
random_numbers.c random_numbers.c
pearson.c
header_encryption.c
tuntap_freebsd.c tuntap_freebsd.c
tuntap_netbsd.c tuntap_netbsd.c
tuntap_linux.c tuntap_linux.c

View File

@ -5,10 +5,7 @@ GIT_COMMITS=@GIT_COMMITS@
######## ########
CC?=gcc CC=@CC@
DEBUG?=-g3
OPTIMIZATION?=-O3 #-march=native
WARN?=-Wall
#Ultrasparc64 users experiencing SIGBUS should try the following gcc options #Ultrasparc64 users experiencing SIGBUS should try the following gcc options
#(thanks to Robert Gibbon) #(thanks to Robert Gibbon)
@ -16,7 +13,7 @@ PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finlin
N2N_OBJS_OPT= N2N_OBJS_OPT=
LIBS_EDGE_OPT=@N2N_LIBS@ LIBS_EDGE_OPT=@N2N_LIBS@
CFLAGS=@CFLAGS@ CFLAGS=@CFLAGS@ -I ./include
LDFLAGS=@LDFLAGS@ LDFLAGS=@LDFLAGS@
OPENSSL_CFLAGS=$(shell pkg-config openssl; echo $$?) OPENSSL_CFLAGS=$(shell pkg-config openssl; echo $$?)
@ -48,11 +45,9 @@ MAN7DIR=$(MANDIR)/man7
MAN8DIR=$(MANDIR)/man8 MAN8DIR=$(MANDIR)/man8
N2N_LIB=libn2n.a N2N_LIB=libn2n.a
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o speck.o \ N2N_OBJS=$(patsubst src/%.c, src/%.o, $(wildcard src/*.c))
edge_utils.o sn_utils.o \ N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile $(N2N_LIB)
transform_null.o transform_tf.o transform_aes.o transform_cc20.o transform_speck.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o random_numbers.o \
tuntap_osx.o
LIBS_EDGE+=$(LIBS_EDGE_OPT) LIBS_EDGE+=$(LIBS_EDGE_OPT)
LIBS_SN= LIBS_SN=
@ -76,19 +71,19 @@ all: $(APPS) $(DOCS) tools
tools: $(N2N_LIB) tools: $(N2N_LIB)
$(MAKE) -C $@ $(MAKE) -C $@
edge: edge.c $(N2N_LIB) n2n_wire.h n2n.h Makefile edge: src/edge.c $(N2N_LIB) $(N2N_DEPS)
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@ $(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
supernode: sn.c $(N2N_LIB) n2n.h Makefile supernode: src/sn.c $(N2N_LIB) $(N2N_DEPS)
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_SN) -o $@ $(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_SN) -o $@
example_edge_embed_quick_edge_init: example_edge_embed_quick_edge_init.c $(N2N_LIB) n2n.h example_edge_embed_quick_edge_init: src/example_edge_embed_quick_edge_init.c $(N2N_DEPS)
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@ $(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
example_sn_embed: example_sn_embed.c $(N2N_LIB) n2n.h example_sn_embed: src/example_sn_embed.c $(N2N_DEPS)
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@ $(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
example_edge_embed: example_edge_embed.c $(N2N_LIB) n2n.h example_edge_embed: src/example_edge_embed.c $(N2N_DEPS)
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@ $(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
%.gz : % %.gz : %

View File

@ -77,6 +77,10 @@ make
make install make install
``` ```
Parts of the code especially Speck cipher and the header encryption speedwise benefit
from compiler optimizations and platform features such as NEON, SSE and AVX. To enable,
use `./configure CFLAGS="-O3 -march=native"` for configuration instead.
For Windows, check out [Windows.md](doc/Windows.md) for compilation and run instuctions. For Windows, check out [Windows.md](doc/Windows.md) for compilation and run instuctions.
For MacOS, check out [macOS.md](doc/macOS.md). For MacOS, check out [macOS.md](doc/macOS.md).
@ -102,18 +106,25 @@ Check out [IPv6.md](https://github.com/ntop/n2n/blob/dev/doc/IPv6.md) for more i
n2n edge nodes use twofish encryption by default for compatibility reasons with existing versions. n2n edge nodes use twofish encryption by default for compatibility reasons with existing versions.
**IMPORTANT** Encryption is only applied to the packet payload. Some metadata like the virtual MAC address Different encryption schemes are applied to the packet payload and to the header which
of the edge nodes, their IP address and the community are sent in cleartext. contains some metadata like the virtual MAC address of the edge nodes, their IP address and the community
name.
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 know 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 that must have the -Ax value. When possible 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 (i.e. when n2n is compiled with OpenSSL 1.1) we recommend to use `-A3`.
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`.
Use `-H` on the edges to enable header encryption. Note, that header encryption is a per-community
decision, i.e. _all_ edges of one community need to have it either enabled or disabled. The supernode
can handle encrypted and unencrypted headers. As the key for header encryption is derived from the
community names, it requires the supernode to be used with fixed communities `-c <path>`
parameter. Also, reuse of once-publically-used community names for header encryption is not recomended.
## Contribution ## Contribution
You can contribute to n2n in various ways: You can contribute to n2n in various ways:
@ -136,4 +147,4 @@ Here is a list of third-party projects connected to this repository.
--- ---
(C) 2007-2019 - ntop.org and contributors (C) 2007-2020 - ntop.org and contributors

View File

@ -15,6 +15,7 @@ fi
N2N_LIBS= N2N_LIBS=
AC_PROG_CC
AC_CHECK_LIB([zstd], [ZSTD_compress]) AC_CHECK_LIB([zstd], [ZSTD_compress])
if test "x$ac_cv_lib_zstd_ZSTD_compress" != xyes; then if test "x$ac_cv_lib_zstd_ZSTD_compress" != xyes; then
@ -92,6 +93,7 @@ fi
DATE=`date +"%Y-%m-%d"` DATE=`date +"%Y-%m-%d"`
AC_SUBST(CC)
AC_SUBST(CFLAGS) AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS) AC_SUBST(LDFLAGS)
AC_SUBST(N2N_MAJOR) AC_SUBST(N2N_MAJOR)
@ -104,7 +106,7 @@ AC_SUBST(GIT_RELEASE)
AC_SUBST(N2N_DEFINES) AC_SUBST(N2N_DEFINES)
AC_SUBST(N2N_LIBS) AC_SUBST(N2N_LIBS)
AC_SUBST(ADDITIONAL_TOOLS) AC_SUBST(ADDITIONAL_TOOLS)
AC_CONFIG_HEADERS(config.h) AC_CONFIG_HEADERS(include/config.h)
AC_CONFIG_FILES(Makefile) AC_CONFIG_FILES(Makefile)
AC_CONFIG_FILES(tools/Makefile) AC_CONFIG_FILES(tools/Makefile)

View File

@ -0,0 +1,34 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
#ifdef WIN32
#include <process.h>
/* Multicast peers discovery disabled due to https://github.com/ntop/n2n/issues/65 */
#define SKIP_MULTICAST_PEERS_DISCOVERY
struct tunread_arg {
n2n_edge_t *eee;
int *keep_running;
};
extern HANDLE startTunReadThread(struct tunread_arg *arg);
#endif

View File

@ -0,0 +1,27 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
char * community_name, he_context_t * ctx);
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx);
void packet_header_setup_key (const char * community_name, he_context_t ** ctx);

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -64,6 +64,8 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdint.h>
#include <time.h>
#ifndef WIN32 #ifndef WIN32
#include <unistd.h> #include <unistd.h>
@ -74,6 +76,16 @@
#ifdef __linux__ #ifdef __linux__
#define N2N_CAN_NAME_IFACE 1 #define N2N_CAN_NAME_IFACE 1
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define GRND_NONBLOCK 1
#endif /* #ifdef __linux__ */ #endif /* #ifdef __linux__ */
#ifdef __FreeBSD__ #ifdef __FreeBSD__
@ -83,7 +95,12 @@
#include <syslog.h> #include <syslog.h>
#include <sys/wait.h> #include <sys/wait.h>
#if defined (__RDRND__) || defined (__RDSEED__)
#include <immintrin.h>
#endif
#define ETH_ADDR_LEN 6 #define ETH_ADDR_LEN 6
struct ether_hdr struct ether_hdr
{ {
uint8_t dhost[ETH_ADDR_LEN]; uint8_t dhost[ETH_ADDR_LEN];
@ -93,10 +110,17 @@ struct ether_hdr
typedef struct ether_hdr ether_hdr_t; typedef struct ether_hdr ether_hdr_t;
#ifdef HAVE_LIBZSTD
#include <zstd.h>
#endif
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
#undef N2N_HAVE_DAEMON #undef N2N_HAVE_DAEMON
#undef N2N_HAVE_SETUID #undef N2N_HAVE_SETUID
#undef N2N_CAN_NAME_IFACE #undef N2N_CAN_NAME_IFACE
#include <tun2tap/tun2tap.h>
#include <edge_jni/edge_jni.h>
#define ARP_PERIOD_INTERVAL (10) /* sec */
#endif /* #ifdef __ANDROID_NDK__ */ #endif /* #ifdef __ANDROID_NDK__ */
#include <netinet/in.h> #include <netinet/in.h>
@ -105,32 +129,41 @@ typedef struct ether_hdr ether_hdr_t;
#include <signal.h> #include <signal.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdint.h>
#ifdef N2N_HAVE_AES #ifdef N2N_HAVE_AES
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#endif #endif
#include "minilzo.h" #include "minilzo.h"
#include "n2n_define.h"
#define closesocket(a) close(a) #define closesocket(a) close(a)
#endif /* #ifndef WIN32 */ #endif /* #ifndef WIN32 */
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include "uthash.h" #include "uthash.h"
#include "lzoconf.h"
#ifdef WIN32 #ifdef WIN32
#include "win32/wintap.h" #include "win32/wintap.h"
#include <sys/stat.h>
#else
#include <pwd.h>
#endif /* #ifdef WIN32 */ #endif /* #ifdef WIN32 */
#include "n2n_wire.h" #include "n2n_wire.h"
#include "n2n_transforms.h" #include "n2n_transforms.h"
#include "random_numbers.h"
#include "pearson.h"
#include "portable_endian.h"
#include "speck.h"
#ifdef WIN32 #ifdef WIN32
#define N2N_IFNAMSIZ 64 #define N2N_IFNAMSIZ 64
@ -151,39 +184,6 @@ typedef struct tuntap_dev {
#define SOCKET int #define SOCKET int
#endif /* #ifndef WIN32 */ #endif /* #ifndef WIN32 */
#define QUICKLZ 1
/* N2N packet header indicators. */
#define MSG_TYPE_REGISTER 1
#define MSG_TYPE_DEREGISTER 2
#define MSG_TYPE_PACKET 3
#define MSG_TYPE_REGISTER_ACK 4
#define MSG_TYPE_REGISTER_SUPER 5
#define MSG_TYPE_REGISTER_SUPER_ACK 6
#define MSG_TYPE_REGISTER_SUPER_NAK 7
#define MSG_TYPE_FEDERATION 8
#define MSG_TYPE_PEER_INFO 9
#define MSG_TYPE_QUERY_PEER 10
/* 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 (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 '-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
its own field in the packet. REVISIT then. */
#define DEFAULT_MTU 1290
/** Uncomment this to enable the MTU check, then try to ssh to generate a fragmented packet. */ /** Uncomment this to enable the MTU check, then try to ssh to generate a fragmented packet. */
/** NOTE: see doc/MTU.md for an explanation on the 1400 value */ /** NOTE: see doc/MTU.md for an explanation on the 1400 value */
//#define MTU_ASSERT_VALUE 1400 //#define MTU_ASSERT_VALUE 1400
@ -206,17 +206,7 @@ struct peer_info {
UT_hash_handle hh; /* makes this structure hashable */ UT_hash_handle hh; /* makes this structure hashable */
}; };
#define HASH_ADD_PEER(head,add) \ typedef struct speck_context_t he_context_t;
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. */
#define N2N_PATHNAME_MAXLEN 256
#define N2N_EDGE_MGMT_PORT 5644
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE]; typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
typedef struct n2n_route { typedef struct n2n_route {
@ -229,6 +219,8 @@ typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */ n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */ n2n_community_t community_name; /**< The community. 16 full octets. */
uint8_t header_encryption; /**< Header encryption indicator. */
he_context_t *header_encryption_ctx; /**< Header encryption cipher context. */
n2n_transform_t transop_id; /**< The transop to use. */ n2n_transform_t transop_id; /**< The transop to use. */
uint16_t compression; /**< Compress outgoing data packets before encryption */ uint16_t compression; /**< Compress outgoing data packets before encryption */
uint16_t num_routes; /**< Number of routes in routes */ uint16_t num_routes; /**< Number of routes in routes */
@ -259,7 +251,17 @@ typedef struct sn_stats
time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */
} sn_stats_t; } sn_stats_t;
typedef struct n2n_sn struct sn_community
{
char community[N2N_COMMUNITY_SIZE];
uint8_t header_encryption; /* Header encryption indicator. */
he_context_t *header_encryption_ctx; /* Header encryption cipher context. */
struct peer_info *edges; /* Link list of registered edges. */
UT_hash_handle hh; /* makes this structure hashable */
};
typedef struct n2n_sn
{ {
time_t start_time; /* Used to measure uptime. */ time_t start_time; /* Used to measure uptime. */
sn_stats_t stats; sn_stats_t stats;
@ -271,16 +273,11 @@ typedef struct sn_stats
struct sn_community *communities; struct sn_community *communities;
} n2n_sn_t; } n2n_sn_t;
struct sn_community
{
char community[N2N_COMMUNITY_SIZE];
struct peer_info *edges; /* Link list of registered edges. */
UT_hash_handle hh; /* makes this structure hashable */
};
/* ************************************** */ /* ************************************** */
#include "header_encryption.h"
#include "twofish.h"
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
#include <android/log.h> #include <android/log.h>
#endif /* #ifdef __ANDROID_NDK__ */ #endif /* #ifdef __ANDROID_NDK__ */
@ -294,21 +291,6 @@ typedef struct sn_stats
/* ************************************** */ /* ************************************** */
#define SUPERNODE_IP "127.0.0.1"
#define SUPERNODE_PORT 1234
/* ************************************** */
#ifndef max
#define max(a, b) ((a < b) ? b : a)
#endif
#ifndef min
#define min(a, b) ((a > b) ? b : a)
#endif
/* ************************************** */
/* Transop Init Functions */ /* Transop Init Functions */
int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);

94
include/n2n_define.h Normal file
View File

@ -0,0 +1,94 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
#define QUICKLZ 1
/* N2N packet header indicators. */
#define MSG_TYPE_REGISTER 1
#define MSG_TYPE_DEREGISTER 2
#define MSG_TYPE_PACKET 3
#define MSG_TYPE_REGISTER_ACK 4
#define MSG_TYPE_REGISTER_SUPER 5
#define MSG_TYPE_REGISTER_SUPER_ACK 6
#define MSG_TYPE_REGISTER_SUPER_NAK 7
#define MSG_TYPE_FEDERATION 8
#define MSG_TYPE_PEER_INFO 9
#define MSG_TYPE_QUERY_PEER 10
#define MSG_TYPE_MAX_TYPE 10
#define SOCKET_TIMEOUT_INTERVAL_SECS 10
#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */
#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */
#define TRANSOP_TICK_INTERVAL (10) /* sec */
#define ETH_FRAMESIZE 14
#define IP4_SRCOFFSET 12
#define IP4_DSTOFFSET 16
#define IP4_MIN_SIZE 20
#define UDP_SIZE 8
/* 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 (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 '-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
its own field in the packet. REVISIT then. */
/* Header encryption indicators */
#define HEADER_ENCRYPTION_UNKNOWN 0
#define HEADER_ENCRYPTION_NONE 1
#define HEADER_ENCRYPTION_ENABLED 2
#define DEFAULT_MTU 1290
#define HASH_ADD_PEER(head,add) \
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. */
#define N2N_PATHNAME_MAXLEN 256
#define N2N_EDGE_MGMT_PORT 5644
/* ************************************** */
#define SUPERNODE_IP "127.0.0.1"
#define SUPERNODE_PORT 1234
/* ************************************** */
#ifndef max
#define max(a, b) ((a < b) ? b : a)
#endif
#ifndef min
#define min(a, b) ((a > b) ? b : a)
#endif

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

21
include/pearson.h Normal file
View File

@ -0,0 +1,21 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len);
void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len);

226
include/portable_endian.h Normal file
View File

@ -0,0 +1,226 @@
// taken from
// https://raw.githubusercontent.com/pyca/bcrypt/master/src/_csrc/portable_endian.h
// as of June 11, 2020
// "License": Public Domain
// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like.
// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to
// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it
// an example on how to get the endian conversion functions on different platforms.
#ifndef PORTABLE_ENDIAN_H__
#define PORTABLE_ENDIAN_H__
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
# define __WINDOWS__
#endif
#if defined(__linux__) || defined(__CYGWIN__)
/* Define necessary macros for the header to expose all fields. */
# if !defined(_BSD_SOURCE)
# define _BSD_SOURCE
# endif
# if !defined(__USE_BSD)
# define __USE_BSD
# endif
# if !defined(_DEFAULT_SOURCE)
# define _DEFAULT_SOURCE
# endif
# include <endian.h>
# include <features.h>
/* See http://linux.die.net/man/3/endian */
# if defined(htobe16) && defined(htole16) && defined(be16toh) && defined(le16toh) && defined(htobe32) && defined(htole32) && defined(be32toh) && defined(htole32) && defined(htobe64) && defined(htole64) && defined(be64) && defined(le64)
/* Do nothing. The macros we need already exist. */
# elif !defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 9)))
# include <arpa/inet.h>
# if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
# define htobe16(x) htons(x)
# define htole16(x) (x)
# define be16toh(x) ntohs(x)
# define le16toh(x) (x)
# define htobe32(x) htonl(x)
# define htole32(x) (x)
# define be32toh(x) ntohl(x)
# define le32toh(x) (x)
# define htobe64(x) (((uint64_t)htonl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htonl(((uint32_t)(x)))) << 32))
# define htole64(x) (x)
# define be64toh(x) (((uint64_t)ntohl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)ntohl(((uint32_t)(x)))) << 32))
# define le64toh(x) (x)
# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
# define htobe16(x) (x)
# define htole16(x) (((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8)))
# define be16toh(x) (x)
# define le16toh(x) (((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8)))
# define htobe32(x) (x)
# define htole32(x) (((uint32_t)htole16(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)htole16(((uint16_t)(x)))) << 16))
# define be32toh(x) (x)
# define le32toh(x) (((uint32_t)le16toh(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)le16toh(((uint16_t)(x)))) << 16))
# define htobe64(x) (x)
# define htole64(x) (((uint64_t)htole32(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htole32(((uint32_t)(x)))) << 32))
# define be64toh(x) (x)
# define le64toh(x) (((uint64_t)le32toh(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)le32toh(((uint32_t)(x)))) << 32))
# else
# error Byte Order not supported or not defined.
# endif
# endif
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__OpenBSD__)
# include <sys/endian.h>
#elif defined(__HAIKU__)
# include <endian.h>
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
# if !defined(be16toh)
# define be16toh(x) betoh16(x)
# define le16toh(x) letoh16(x)
# endif
# if !defined(be32toh)
# define be32toh(x) betoh32(x)
# define le32toh(x) letoh32(x)
# endif
# if !defined(be64toh)
# define be64toh(x) betoh64(x)
# define le64toh(x) letoh64(x)
# endif
#elif defined(__WINDOWS__)
# if BYTE_ORDER == LITTLE_ENDIAN
# define htobe16(x) _byteswap_ushort(x)
# define htole16(x) (x)
# define be16toh(x) _byteswap_ushort(x)
# define le16toh(x) (x)
# define htobe32(x) _byteswap_ulong(x)
# define htole32(x) (x)
# define be32toh(x) _byteswap_ulong(x)
# define le32toh(x) (x)
# define htobe64(x) _byteswap_uint64(x)
# define be64toh(x) _byteswap_uint64(x)
# define htole64(x) (x)
# define le64toh(x) (x)
# elif BYTE_ORDER == BIG_ENDIAN
/* that would be xbox 360 */
# define htobe16(x) (x)
# define htole16(x) __builtin_bswap16(x)
# define be16toh(x) (x)
# define le16toh(x) __builtin_bswap16(x)
# define htobe32(x) (x)
# define htole32(x) __builtin_bswap32(x)
# define be32toh(x) (x)
# define le32toh(x) __builtin_bswap32(x)
# define htobe64(x) (x)
# define htole64(x) __builtin_bswap64(x)
# define be64toh(x) (x)
# define le64toh(x) __builtin_bswap64(x)
# else
# error byte order not supported
# endif
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__sun)
# include <sys/byteorder.h>
# define htobe16(x) BE_16(x)
# define htole16(x) LE_16(x)
# define be16toh(x) BE_16(x)
# define le16toh(x) LE_16(x)
# define htobe32(x) BE_32(x)
# define htole32(x) LE_32(x)
# define be32toh(x) BE_32(x)
# define le32toh(x) LE_32(x)
# define htobe64(x) BE_64(x)
# define htole64(x) LE_64(x)
# define be64toh(x) BE_64(x)
# define le64toh(x) LE_64(x)
#elif defined _AIX /* AIX is always big endian */
# define be64toh(x) (x)
# define be32toh(x) (x)
# define be16toh(x) (x)
# define le32toh(x) \
((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000) >> 8) | \
(((x) & 0xff000000) >> 24))
# define le64toh(x) \
((((x) & 0x00000000000000ffL) << 56) | \
(((x) & 0x000000000000ff00L) << 40) | \
(((x) & 0x0000000000ff0000L) << 24) | \
(((x) & 0x00000000ff000000L) << 8) | \
(((x) & 0x000000ff00000000L) >> 8) | \
(((x) & 0x0000ff0000000000L) >> 24) | \
(((x) & 0x00ff000000000000L) >> 40) | \
(((x) & 0xff00000000000000L) >> 56))
# ifndef htobe64
# define htobe64(x) be64toh(x)
# endif
# ifndef htobe32
# define htobe32(x) be32toh(x)
# endif
# ifndef htobe16
# define htobe16(x) be16toh(x)
# endif
#else
# error platform not supported
#endif
#endif

38
include/random_numbers.h Normal file
View File

@ -0,0 +1,38 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
/* The WIN32 code is still untested and thus commented
#if defined (WIN32)
#include <Wincrypt.h>
#endif
*/
struct rn_generator_state_t {
uint64_t a, b;
};
struct splitmix64_state_t {
uint64_t s;
};
int n2n_srand (uint64_t seed);
uint64_t n2n_rand ();
uint64_t n2n_seed ();

View File

@ -2,11 +2,11 @@
// taken from (and modified: removed pure crypto-stream generation and seperated key expansion) // taken from (and modified: removed pure crypto-stream generation and seperated key expansion)
// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/ // https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
#define htole64(x) OSSwapHostToLittleInt64(x)
#endif
#ifndef SPECK_H
#define SPECK_H
#include <stdint.h>
#define u32 uint32_t #define u32 uint32_t
#define u64 uint64_t #define u64 uint64_t
@ -59,3 +59,13 @@ speck_context_t *ctx);
int speck_expand_key (const unsigned char *k, speck_context_t *ctx); int speck_expand_key (const unsigned char *k, speck_context_t *ctx);
int speck_he (unsigned char *out, const unsigned char *in, unsigned long long inlen,
const unsigned char *n, speck_context_t *ctx);
int speck_expand_key_he (const unsigned char *k, speck_context_t *ctx);
#endif

View File

@ -1,34 +0,0 @@
#include <stdint.h>
#include <time.h>
#if defined (__linux__)
#include <sys/syscall.h>
#include <unistd.h>
#define GRND_NONBLOCK 1
#endif
#if defined (__RDRND__) || defined (__RDSEED__)
#include <immintrin.h>
#endif
/* The WIN32 code is still untested and thus commented
#if defined (WIN32)
#include <Wincrypt.h>
#endif */
struct rn_generator_state_t {
uint64_t a, b;
};
struct splitmix64_state_t {
uint64_t s;
};
int n2n_srand (uint64_t seed);
uint64_t n2n_rand ();
uint64_t n2n_seed ();

View File

@ -1,784 +0,0 @@
#include "n2n.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
#define N2N_SN_LPORT_DEFAULT 7654
#define N2N_SN_PKTBUF_SIZE 2048
static int try_forward(n2n_sn_t *sss,
const n2n_common_t *cmn,
const n2n_mac_t dstMac,
const uint8_t *pktbuf,
size_t pktsize);
static ssize_t sendto_sock(n2n_sn_t *sss,
const n2n_sock_t *sock,
const uint8_t *pktbuf,
size_t pktsize);
static int try_broadcast(n2n_sn_t *sss,
const n2n_common_t *cmn,
const n2n_mac_t srcMac,
const uint8_t *pktbuf,
size_t pktsize);
static uint16_t reg_lifetime(n2n_sn_t *sss);
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now);
static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
size_t mgmt_size,
time_t now);
static int process_udp(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *udp_buf,
size_t udp_size,
time_t now);
static int try_forward(n2n_sn_t *sss,
const n2n_common_t *cmn,
const n2n_mac_t dstMac,
const uint8_t *pktbuf,
size_t pktsize)
{
struct peer_info *scan;
struct sn_community *community;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn->community, community);
if (!community)
{
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community);
return (-1);
}
HASH_FIND_PEER(community->edges, dstMac, scan);
if (NULL != scan)
{
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
if (data_sent_len == pktsize)
{
++(sss->stats.fwd);
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr));
}
else
{
++(sss->stats.errors);
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr),
errno, strerror(errno));
}
}
else
{
traceEvent(TRACE_DEBUG, "try_forward unknown MAC");
/* Not a known MAC so drop. */
return (-2);
}
return (0);
}
/** Send a datagram to the destination embodied in a n2n_sock_t.
*
* @return -1 on error otherwise number of bytes sent
*/
static ssize_t sendto_sock(n2n_sn_t *sss,
const n2n_sock_t *sock,
const uint8_t *pktbuf,
size_t pktsize)
{
n2n_sock_str_t sockbuf;
if (AF_INET == sock->family)
{
struct sockaddr_in udpsock;
udpsock.sin_family = AF_INET;
udpsock.sin_port = htons(sock->port);
memcpy(&(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE);
traceEvent(TRACE_DEBUG, "sendto_sock %lu to [%s]",
pktsize,
sock_to_cstr(sockbuf, sock));
return sendto(sss->sock, pktbuf, pktsize, 0,
(const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in));
}
else
{
/* AF_INET6 not implemented */
errno = EAFNOSUPPORT;
return -1;
}
}
/** Try and broadcast a message to all edges in the community.
*
* This will send the exact same datagram to zero or more edges registered to
* the supernode.
*/
static int try_broadcast(n2n_sn_t *sss,
const n2n_common_t *cmn,
const n2n_mac_t srcMac,
const uint8_t *pktbuf,
size_t pktsize)
{
struct peer_info *scan, *tmp;
struct sn_community *community;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
traceEvent(TRACE_DEBUG, "try_broadcast");
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn->community, community);
if (community)
{
HASH_ITER(hh, community->edges, scan, tmp)
{
if (memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0)
{
/* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
if (data_sent_len != pktsize)
{
++(sss->stats.errors);
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr),
strerror(errno));
}
else
{
++(sss->stats.broadcast);
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr));
}
}
}
}
else
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
cmn->community);
return 0;
}
/** Initialise the supernode structure */
int sn_init(n2n_sn_t *sss)
{
#ifdef WIN32
initWin32();
#endif
memset(sss, 0, sizeof(n2n_sn_t));
sss->daemon = 1; /* By defult run as a daemon. */
sss->lport = N2N_SN_LPORT_DEFAULT;
sss->sock = -1;
sss->mgmt_sock = -1;
return 0; /* OK */
}
/** Deinitialise the supernode structure and deallocate any memory owned by
* it. */
void sn_term(n2n_sn_t *sss)
{
struct sn_community *community, *tmp;
if (sss->sock >= 0)
{
closesocket(sss->sock);
}
sss->sock = -1;
if (sss->mgmt_sock >= 0)
{
closesocket(sss->mgmt_sock);
}
sss->mgmt_sock = -1;
HASH_ITER(hh, sss->communities, community, tmp)
{
clear_peer_list(&community->edges);
HASH_DEL(sss->communities, community);
free(community);
}
}
/** Determine the appropriate lifetime for new registrations.
*
* If the supernode has been put into a pre-shutdown phase then this lifetime
* should not allow registrations to continue beyond the shutdown point.
*/
static uint16_t reg_lifetime(n2n_sn_t *sss)
{
/* NOTE: UDP firewalls usually have a 30 seconds timeout */
return 15;
}
/** Update the edge table with the details of the edge which contacted the
* supernode. */
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now)
{
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
struct peer_info *scan;
traceEvent(TRACE_DEBUG, "update_edge for %s [%s]",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
HASH_FIND_PEER(comm->edges, edgeMac, scan);
if (NULL == scan)
{
/* Not known */
scan = (struct peer_info *)calloc(1,
sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
HASH_ADD_PEER(comm->edges, scan);
traceEvent(TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
/* Known */
if (!sock_equal(sender_sock, &(scan->sock)))
{
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
traceEvent(TRACE_INFO, "update_edge updated %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
}
scan->last_seen = now;
return 0;
}
static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
size_t mgmt_size,
time_t now)
{
char resbuf[N2N_SN_PKTBUF_SIZE];
size_t ressize = 0;
uint32_t num_edges = 0;
ssize_t r;
struct sn_community *community, *tmp;
traceEvent(TRACE_DEBUG, "process_mgmt");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"----------------\n");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"uptime %lu\n", (now - sss->start_time));
HASH_ITER(hh, sss->communities, community, tmp)
{
num_edges += HASH_COUNT(community->edges);
}
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"edges %u\n",
num_edges);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"errors %u\n",
(unsigned int)sss->stats.errors);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_sup %u\n",
(unsigned int)sss->stats.reg_super);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_nak %u\n",
(unsigned int)sss->stats.reg_super_nak);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"fwd %u\n",
(unsigned int)sss->stats.fwd);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"broadcast %u\n",
(unsigned int)sss->stats.broadcast);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last fwd %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_fwd));
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last reg %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_reg_super));
r = sendto(sss->mgmt_sock, resbuf, ressize, 0 /*flags*/,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
if (r <= 0)
{
++(sss->stats.errors);
traceEvent(TRACE_ERROR, "process_mgmt : sendto failed. %s", strerror(errno));
}
return 0;
}
/** Examine a datagram and determine what to do with it.
*
*/
static int process_udp(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *udp_buf,
size_t udp_size,
time_t now)
{
n2n_common_t cmn; /* common fields in the packet header */
size_t rem;
size_t idx;
size_t msg_type;
uint8_t from_supernode;
macstr_t mac_buf;
macstr_t mac_buf2;
n2n_sock_str_t sockbuf;
char buf[32];
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]",
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port));
/* Use decode_common() to determine the kind of packet then process it:
*
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
*
* REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
* destination edge. If the destination is not known then PACKETs are
* broadcast.
*/
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
idx = 0; /* marches through packet header as parts are decoded. */
if (decode_common(&cmn, udp_buf, &rem, &idx) < 0)
{
traceEvent(TRACE_ERROR, "Failed to decode common section");
return -1; /* failed to decode packet */
}
msg_type = cmn.pc; /* packet code */
from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
if (cmn.ttl < 1)
{
traceEvent(TRACE_WARNING, "Expired TTL");
return 0; /* Don't process further */
}
--(cmn.ttl); /* The value copied into all forwarded packets. */
switch (msg_type)
{
case MSG_TYPE_PACKET:
{
/* PACKET from one edge to another edge via supernode. */
/* pkt will be modified in place and recoded to an output of potentially
* different size due to addition of the socket.*/
n2n_PACKET_t pkt;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx = 0;
int unicast; /* non-zero if unicast */
const uint8_t *rec_buf; /* either udp_buf or encbuf */
sss->stats.last_fwd = now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
unicast = (0 == is_multi_broadcast(pkt.dstMac));
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
(unicast ? "unicast" : "multicast"),
macaddr_str(mac_buf, pkt.srcMac),
macaddr_str(mac_buf2, pkt.dstMac),
(from_supernode ? "from sn" : "local"));
if (!from_supernode)
{
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
pkt.sock.family = AF_INET;
pkt.sock.port = ntohs(sender_sock->sin_port);
memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
rec_buf = encbuf;
/* Re-encode the header. */
encode_PACKET(encbuf, &encx, &cmn2, &pkt);
/* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
}
else
{
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified");
rec_buf = udp_buf;
encx = udp_size;
}
/* Common section to forward the final product. */
if (unicast)
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx);
else
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx);
break;
}
case MSG_TYPE_REGISTER:
{
/* Forwarding a REGISTER from one edge to the next */
n2n_REGISTER_t reg;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx = 0;
int unicast; /* non-zero if unicast */
const uint8_t *rec_buf; /* either udp_buf or encbuf */
sss->stats.last_fwd = now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
unicast = (0 == is_multi_broadcast(reg.dstMac));
if (unicast)
{
traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
macaddr_str(mac_buf, reg.srcMac),
macaddr_str(mac_buf2, reg.dstMac),
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ? "from sn" : "local"));
if (0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE))
{
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
reg.sock.family = AF_INET;
reg.sock.port = ntohs(sender_sock->sin_port);
memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
rec_buf = encbuf;
/* Re-encode the header. */
encode_REGISTER(encbuf, &encx, &cmn2, &reg);
/* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
}
else
{
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
rec_buf = udp_buf;
encx = udp_size;
}
try_forward(sss, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
}
else
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
break;
}
case MSG_TYPE_REGISTER_ACK:
traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode");
break;
case MSG_TYPE_REGISTER_SUPER:
{
n2n_REGISTER_SUPER_t reg;
n2n_REGISTER_SUPER_ACK_t ack;
n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx = 0;
struct sn_community *comm;
/* Edge requesting registration with us. */
sss->stats.last_reg_super = now;
++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx);
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn.community, comm);
/*
Before we move any further, we need to check if the requested
community is allowed by the supernode. In case it is not we do
not report any message back to the edge to hide the supernode
existance (better from the security standpoint)
*/
if (!comm && !sss->lock_communities)
{
comm = calloc(1, sizeof(struct sn_community));
if (comm)
{
strncpy(comm->community, (char *)cmn.community, N2N_COMMUNITY_SIZE - 1);
comm->community[N2N_COMMUNITY_SIZE - 1] = '\0';
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
}
}
if (comm)
{
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
ack.lifetime = reg_lifetime(sss);
ack.sock.family = AF_INET;
ack.sock.port = ntohs(sender_sock->sin_port);
memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
ack.num_sn = 0; /* No backup */
memset(&(ack.sn_bak), 0, sizeof(n2n_sock_t));
traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
update_edge(sss, reg.edgeMac, comm, &(ack.sock), now);
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
}
else
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char *)cmn.community);
break;
}
case MSG_TYPE_QUERY_PEER:
{
n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx = 0;
n2n_common_t cmn2;
n2n_PEER_INFO_t pi;
struct sn_community *community;
decode_QUERY_PEER(&query, &cmn, udp_buf, &rem, &idx);
traceEvent(TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
macaddr_str(mac_buf, query.srcMac),
macaddr_str(mac_buf2, query.targetMac));
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn.community, community);
if (community)
{
struct peer_info *scan;
HASH_FIND_PEER(community->edges, query.targetMac, scan);
if (scan)
{
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
pi.aflags = 0;
memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t));
pi.sock = scan->sock;
encode_PEER_INFO(encbuf, &encx, &cmn2, &pi);
sendto(sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str(mac_buf, query.srcMac));
}
else
{
traceEvent(TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str(mac_buf, query.targetMac));
}
}
break;
}
default:
/* Not a known message type */
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
} /* switch(msg_type) */
return 0;
}
/** Long lived processing entry point. Split out from main to simply
* daemonisation on some platforms. */
int run_sn_loop(n2n_sn_t *sss, int *keep_running)
{
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
time_t last_purge_edges = 0;
struct sn_community *comm, *tmp;
sss->start_time = time(NULL);
while (*keep_running)
{
int rc;
ssize_t bread;
int max_sock;
fd_set socket_mask;
struct timeval wait_time;
time_t now = 0;
FD_ZERO(&socket_mask);
max_sock = MAX(sss->sock, sss->mgmt_sock);
FD_SET(sss->sock, &socket_mask);
FD_SET(sss->mgmt_sock, &socket_mask);
wait_time.tv_sec = 10;
wait_time.tv_usec = 0;
rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time);
now = time(NULL);
if (rc > 0)
{
if (FD_ISSET(sss->sock, &socket_mask))
{
struct sockaddr_in sender_sock;
socklen_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if ((bread < 0)
#ifdef WIN32
&& (WSAGetLastError() != WSAECONNRESET)
#endif
)
{
/* For UDP bread of zero just means no data (unlike TCP). */
/* The fd is no good now. Maybe we lost our interface. */
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno));
#ifdef WIN32
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
#endif
keep_running = 0;
break;
}
/* We have a datagram to process */
if (bread > 0)
{
/* And the datagram has data (not just a header) */
process_udp(sss, &sender_sock, pktbuf, bread, now);
}
}
if (FD_ISSET(sss->mgmt_sock, &socket_mask))
{
struct sockaddr_in sender_sock;
size_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if (bread <= 0)
{
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno));
keep_running = 0;
break;
}
/* We have a datagram to process */
process_mgmt(sss, &sender_sock, pktbuf, bread, now);
}
}
else
{
traceEvent(TRACE_DEBUG, "timeout");
}
HASH_ITER(hh, sss->communities, comm, tmp)
{
purge_expired_registrations(&comm->edges, &last_purge_edges);
if ((comm->edges == NULL) && (!sss->lock_communities))
{
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
HASH_DEL(sss->communities, comm);
free(comm);
}
}
} /* while */
sn_term(sss);
return 0;
}

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,12 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "random_numbers.h"
#ifdef WIN32
#include <sys/stat.h>
#else
#include <pwd.h>
#endif
#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */ #define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */
#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/ #define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/
@ -160,7 +154,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>]] [-z[<compression algo>]] [-h]\n\n"); "[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-H] [-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");
@ -190,20 +184,21 @@ 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 key (defaulting to Twofish then).\n"); printf("-A1 | Disable payload encryption. Do not use with key (defaulting to Twofish then).\n");
printf("-A2 | Use Twofish for payload encryption (default). Requires a key.\n"); printf("-A2 ... -A5 or -A | Choose a cipher for payload encryption, requires a key: -A2 = Twofish (default),\n");
printf(" | "
#ifdef N2N_HAVE_AES #ifdef N2N_HAVE_AES
printf("-A3 or -A (deprecated) | Use AES-CBC for payload encryption. Requires a key.\n"); "-A3 or -A (deprecated) = AES-CBC, "
#endif #endif
#ifdef HAVE_OPENSSL_1_1 #ifdef HAVE_OPENSSL_1_1
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n"); "-A4 = ChaCha20, "
#endif #endif
// COMING SOON, not yet implemented in setPayloadEncryption(...) "-A5 = Speck-CTR.\n");
// printf("-A5 | Use Speck for payload encryption. Requires a key.\n"); printf("-H | Enable full header encryption. Requires supernode with fixed community.\n");
printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n"); printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x"
#ifdef N2N_HAVE_ZSTD #ifdef N2N_HAVE_ZSTD
printf("-z2 | Enable zstd compression for outgoing data packets\n"); ", -z2 = zstd"
#endif #endif
printf(" | (default=compression disabled)\n"); " (default=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__
@ -283,6 +278,11 @@ static void setPayloadEncryption( n2n_edge_conf_t *conf, int cipher) {
break; break;
} }
#endif #endif
case 5:
{
conf->transop_id = N2N_TRANSFORM_ID_SPECK;
break;
}
default: default:
{ {
conf->transop_id = N2N_TRANSFORM_ID_INVAL; conf->transop_id = N2N_TRANSFORM_ID_INVAL;
@ -395,6 +395,14 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
break; break;
} }
case 'H': /* indicate header encryption */
{
/* we cannot be sure if this gets parsed before the community name is set.
* so, only an indicator is set, action is taken later*/
conf->header_encryption = HEADER_ENCRYPTION_ENABLED;
break;
}
case 'z': case 'z':
{ {
int compression; int compression;
@ -553,7 +561,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::A::" "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::H"
#ifdef __linux__ #ifdef __linux__
"T:n:" "T:n:"
#endif #endif

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,45 +17,7 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "lzoconf.h" #include "header_encryption.h"
#include "random_numbers.h"
#ifdef HAVE_LIBZSTD
#include <zstd.h>
#endif
#ifdef WIN32
#include <process.h>
/* Multicast peers discovery disabled due to https://github.com/ntop/n2n/issues/65 */
#define SKIP_MULTICAST_PEERS_DISCOVERY
#endif
#ifdef __ANDROID_NDK__
#include <tun2tap/tun2tap.h>
#include <edge_jni/edge_jni.h>
#endif /* __ANDROID_NDK__ */
#define SOCKET_TIMEOUT_INTERVAL_SECS 10
#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */
#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */
#define TRANSOP_TICK_INTERVAL (10) /* sec */
#ifdef __ANDROID_NDK__
#define ARP_PERIOD_INTERVAL (10) /* sec */
#endif
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#endif
#define ETH_FRAMESIZE 14
#define IP4_SRCOFFSET 12
#define IP4_DSTOFFSET 16
#define IP4_MIN_SIZE 20
#define UDP_SIZE 8
/* heap allocation for compression as per lzo example doc */ /* heap allocation for compression as per lzo example doc */
#define HEAP_ALLOC(var,size) lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] #define HEAP_ALLOC(var,size) lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
@ -300,6 +262,12 @@ 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;
} }
/* Set the key schedule (context) for header encryption if enabled */
if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) {
traceEvent(TRACE_NORMAL, "Header encryption is enabled.");
packet_header_setup_key ((char *)(conf->community_name), &(eee->conf.header_encryption_ctx));
}
if(eee->transop.no_encryption) if(eee->transop.no_encryption)
traceEvent(TRACE_WARNING, "Encryption is disabled in edge"); traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
@ -313,11 +281,11 @@ 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;
} }
//edge_init_success: //edge_init_success:
*rv = 0; *rv = 0;
return(eee); return(eee);
edge_init_error: edge_init_error:
if(eee) if(eee)
free(eee); free(eee);
*rv = rc; *rv = rc;
@ -507,7 +475,7 @@ static void register_with_new_peer(n2n_edge_t * eee,
* So we can alternatively set TTL so that the packet sent to peer never really reaches * So we can alternatively set TTL so that the packet sent to peer never really reaches
* The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ. * The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ.
*/ */
if (eee->conf.register_ttl == 1) { if(eee->conf.register_ttl == 1) {
/* We are DMZ host or port is directly accessible. Just let peer to send back the ack */ /* We are DMZ host or port is directly accessible. Just let peer to send back the ack */
#ifndef WIN32 #ifndef WIN32
} else if(eee->conf.register_ttl > 1) { } else if(eee->conf.register_ttl > 1) {
@ -782,6 +750,9 @@ static void send_register_super(n2n_edge_t * eee,
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, supernode)); sock_to_cstr(sockbuf, supernode));
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode);
} }
@ -810,6 +781,9 @@ static void send_query_peer( n2n_edge_t * eee,
traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" ); traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" );
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
} }
@ -853,6 +827,9 @@ static void send_register(n2n_edge_t * eee,
traceEvent(TRACE_INFO, "Send REGISTER to %s", traceEvent(TRACE_INFO, "Send REGISTER to %s",
sock_to_cstr(sockbuf, remote_peer)); sock_to_cstr(sockbuf, remote_peer));
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
} }
@ -892,6 +869,8 @@ static void send_register_ack(n2n_edge_t * eee,
traceEvent(TRACE_INFO, "send REGISTER_ACK %s", traceEvent(TRACE_INFO, "send REGISTER_ACK %s",
sock_to_cstr(sockbuf, remote_peer)); sock_to_cstr(sockbuf, remote_peer));
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
} }
@ -917,7 +896,7 @@ static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
/* Give up on that supernode and try the next one. */ /* Give up on that supernode and try the next one. */
++(eee->sn_idx); ++(eee->sn_idx);
if (eee->sn_idx >= eee->conf.sn_num) { if(eee->sn_idx >= eee->conf.sn_num) {
/* Got to end of list, go back to the start. Also works for list of one entry. */ /* Got to end of list, go back to the start. Also works for list of one entry. */
eee->sn_idx=0; eee->sn_idx=0;
} }
@ -1064,7 +1043,7 @@ static int handle_PACKET(n2n_edge_t * eee,
deflated_len = N2N_PKT_BUF_SIZE; deflated_len = N2N_PKT_BUF_SIZE;
deflation_buffer = malloc (deflated_len); deflation_buffer = malloc (deflated_len);
deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size); deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size);
if (ZSTD_isError(deflated_len)) { if(ZSTD_isError(deflated_len)) {
traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.", traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.",
ZSTD_getErrorName(deflated_len)); ZSTD_getErrorName(deflated_len));
free (deflation_buffer); free (deflation_buffer);
@ -1078,7 +1057,7 @@ static int handle_PACKET(n2n_edge_t * eee,
return (-1); // cannot handle it return (-1); // cannot handle it
} }
if (rx_compression_id) { if(rx_compression_id) {
traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes", traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes",
compression_str(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 );
@ -1130,7 +1109,7 @@ static int handle_PACKET(n2n_edge_t * eee,
traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size);
data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size);
if (data_sent_len == eth_size) if(data_sent_len == eth_size)
{ {
retval = 0; retval = 0;
} }
@ -1466,15 +1445,15 @@ 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;
int32_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);
if (lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) { if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) {
if (compression_len < len) { if(compression_len < len) {
pkt.compression = N2N_COMPRESSION_ID_LZO; pkt.compression = N2N_COMPRESSION_ID_LZO;
} }
} }
@ -1484,8 +1463,8 @@ static void send_packet2net(n2n_edge_t * eee,
compression_len = N2N_PKT_BUF_SIZE + 128; 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_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) ; compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ;
if (!ZSTD_isError(compression_len)) { if(!ZSTD_isError(compression_len)) {
if (compression_len < len) { if(compression_len < len) {
pkt.compression = N2N_COMPRESSION_ID_ZSTD; pkt.compression = N2N_COMPRESSION_ID_ZSTD;
} }
} else { } else {
@ -1500,7 +1479,7 @@ static void send_packet2net(n2n_edge_t * eee,
break; break;
} }
if (pkt.compression) { if(pkt.compression) {
traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n", traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n",
compression_str(pkt.compression), len, compression_len); compression_str(pkt.compression), len, compression_len);
@ -1519,6 +1498,9 @@ static void send_packet2net(n2n_edge_t * eee,
idx=0; idx=0;
encode_PACKET(pktbuf, &idx, &cmn, &pkt); encode_PACKET(pktbuf, &idx, &cmn, &pkt);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
idx += eee->transop.fwd(&eee->transop, idx += eee->transop.fwd(&eee->transop,
pktbuf+idx, N2N_PKT_BUF_SIZE-idx, pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
tap_pkt, len, pkt.dstMac); tap_pkt, len, pkt.dstMac);
@ -1552,13 +1534,11 @@ static void readFromTAPSocket(n2n_edge_t * eee) {
ssize_t len; ssize_t len;
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
if (uip_arp_len != 0) { if(uip_arp_len != 0) {
len = uip_arp_len; len = uip_arp_len;
memcpy(eth_pkt, uip_arp_buf, MIN(uip_arp_len, N2N_PKT_BUF_SIZE)); memcpy(eth_pkt, uip_arp_buf, MIN(uip_arp_len, N2N_PKT_BUF_SIZE));
traceEvent(TRACE_DEBUG, "ARP reply packet to send"); traceEvent(TRACE_DEBUG, "ARP reply packet to send");
} } else {
else
{
#endif /* #ifdef __ANDROID_NDK__ */ #endif /* #ifdef __ANDROID_NDK__ */
len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE );
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
@ -1644,40 +1624,6 @@ static void update_gateway_mac(n2n_edge_t *eee) {
/* ************************************** */ /* ************************************** */
#ifdef WIN32
struct tunread_arg {
n2n_edge_t *eee;
int *keep_running;
};
static DWORD* tunReadThread(LPVOID lpArg) {
struct tunread_arg *arg = (struct tunread_arg*)lpArg;
while(*arg->keep_running)
readFromTAPSocket(arg->eee);
return((DWORD*)NULL);
}
/* ************************************** */
/** Start a second thread in Windows because TUNTAP interfaces do not expose
* file descriptors. */
static HANDLE startTunReadThread(struct tunread_arg *arg) {
DWORD dwThreadId;
return(CreateThread(NULL, /* security attributes */
0, /* use default stack size */
(LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */
(void*)arg, /* argument to thread function */
0, /* thread creation flags */
&dwThreadId)); /* thread id out */
}
#endif
/* ************************************** */
/** Read a datagram from the main UDP socket to the internet. */ /** Read a datagram from the main UDP socket to the internet. */
static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
n2n_common_t cmn; /* common fields in the packet header */ n2n_common_t cmn; /* common fields in the packet header */
@ -1731,6 +1677,12 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s", traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s",
(signed int)recvlen, sock_to_cstr(sockbuf1, &sender)); (signed int)recvlen, sock_to_cstr(sockbuf1, &sender));
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx) == 0) {
traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header.");
return;
}
/* hexdump(udp_buf, recvlen); */ /* hexdump(udp_buf, recvlen); */
rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */ rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */
@ -1910,7 +1862,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
} }
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
if (scan) { if(scan) {
scan->sock = pi.sock; scan->sock = pi.sock;
traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s", traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s",
macaddr_str(mac_buf1, pi.mac), macaddr_str(mac_buf1, pi.mac),
@ -1928,7 +1880,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
return; return;
} /* switch(msg_type) */ } /* switch(msg_type) */
} else if(from_supernode) /* if (community match) */ } else if(from_supernode) /* if(community match) */
traceEvent(TRACE_WARNING, "Received packet with unknown community"); traceEvent(TRACE_WARNING, "Received packet with unknown community");
else else
traceEvent(TRACE_INFO, "Ignoring packet with unknown community"); traceEvent(TRACE_INFO, "Ignoring packet with unknown community");
@ -2030,7 +1982,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
#endif #endif
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
if (uip_arp_len != 0) { if(uip_arp_len != 0) {
readFromTAPSocket(eee); readFromTAPSocket(eee);
uip_arp_len = 0; uip_arp_len = 0;
} }
@ -2072,7 +2024,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
} }
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
if ((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) { if((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) {
uip_arp_timer(); uip_arp_timer();
lastArpPeriod = nowTime; lastArpPeriod = nowTime;
} }
@ -2404,7 +2356,7 @@ static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) {
traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
rv = 0; rv = 0;
out: out:
close(nl_sock); close(nl_sock);
return(rv); return(rv);
@ -2428,10 +2380,12 @@ static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_r
* 2. Add the new default gateway route * 2. Add the new default gateway route
* *
* Instead of modifying the system default gateway, we use the trick * Instead of modifying the system default gateway, we use the trick
* of adding a route to the 0.0.0.0/1 network, which takes precedence * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus
* over the default gateway (0.0.0.0/0). This leaves the default * covering the whole IPv4 range. Such routes in linux take precedence
* gateway unchanged so that after n2n is stopped the cleanup is * over the default gateway (0.0.0.0/0) since are more specific.
* easier. * This leaves the default gateway unchanged so that after n2n is
* stopped the cleanup is easier.
* See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227
*/ */
n2n_sock_t sn; n2n_sock_t sn;
n2n_route_t custom_route; n2n_route_t custom_route;
@ -2481,6 +2435,14 @@ static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_r
custom_route.net_bitlen = 1; custom_route.net_bitlen = 1;
custom_route.gateway = route->gateway; custom_route.gateway = route->gateway;
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0)
return(-1);
/* ip route add 128.0.0.0/1 via n2n_gateway */
custom_route.net_addr = 128;
custom_route.net_bitlen = 1;
custom_route.gateway = route->gateway;
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0)
return(-1); return(-1);
} else { } else {
@ -2514,6 +2476,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
conf->local_port = 0 /* any port */; conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_NULL; conf->transop_id = N2N_TRANSFORM_ID_NULL;
conf->header_encryption = HEADER_ENCRYPTION_NONE;
conf->compression = N2N_COMPRESSION_ID_NONE; conf->compression = N2N_COMPRESSION_ID_NONE;
conf->drop_multicast = 1; conf->drop_multicast = 1;
conf->allow_p2p = 1; conf->allow_p2p = 1;
@ -2588,7 +2551,7 @@ int quick_edge_init(char *device_name, char *community_name,
edge_term(eee); edge_term(eee);
edge_term_conf(&conf); edge_term_conf(&conf);
quick_edge_init_end: quick_edge_init_end:
tuntap_close(&tuntap); tuntap_close(&tuntap);
return(rv); return(rv);
} }

49
src/edge_utils_win32.c Normal file
View File

@ -0,0 +1,49 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
#ifdef WIN32
#include "edge_utils_win32.h"
/* ************************************** */
static DWORD* tunReadThread(LPVOID lpArg) {
struct tunread_arg *arg = (struct tunread_arg*)lpArg;
while(*arg->keep_running)
readFromTAPSocket(arg->eee);
return((DWORD*)NULL);
}
/* ************************************** */
/** Start a second thread in Windows because TUNTAP interfaces do not expose
* file descriptors. */
HANDLE startTunReadThread(struct tunread_arg *arg) {
DWORD dwThreadId;
return(CreateThread(NULL, /* security attributes */
0, /* use default stack size */
(LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */
(void*)arg, /* argument to thread function */
0, /* thread creation flags */
&dwThreadId)); /* thread id out */
}
#endif

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,7 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "random_numbers.h"
/* /*
This tool demonstrates how to easily embed This tool demonstrates how to easily embed

93
src/header_encryption.c Normal file
View File

@ -0,0 +1,93 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
#include "n2n.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
/* ********************************************************************** */
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
char * community_name, he_context_t * ctx) {
// assemble IV
// the last four are ASCII "n2n!" and do not get overwritten
uint8_t iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6E, 0x32, 0x6E, 0x21 };
// the first 96 bits of the packet get padded with ASCII "n2n!"
// to full 128 bit IV
memcpy (iv, packet, 12);
// try community name as possible key and check for magic bytes
uint32_t magic = 0x6E326E00; // ="n2n_"
uint32_t test_magic;
// check for magic bytes and reasonable value in header len field
// so, as a first step, decrypt 4 bytes only starting at byte 12
speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, (speck_context_t*)ctx);
test_magic = be32toh (test_magic);
if( (((test_magic >> 8) << 8) == magic) // check the thre uppermost bytes
&& (((uint8_t)test_magic) <= packet_len) // lowest 8 bit of test_magic are header_len
) {
// decrypt the complete header
speck_he (&packet[12], &packet[12], (uint8_t)(test_magic) - 12, iv, (speck_context_t*)ctx);
// restore original packet order
memcpy (&packet[0], &packet[16], 4);
memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE);
return (1); // successful
} else
return (0); // unsuccessful
}
/* ********************************************************************** */
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx) {
uint8_t iv[16];
uint32_t *iv32 = (uint32_t*)&iv;
uint64_t *iv64 = (uint64_t*)&iv;
const uint32_t magic = 0x6E326E21; // = ASCII "n2n!"
if(header_len < 20) {
traceEvent(TRACE_DEBUG, "packet_header_encrypt dropped a packet too short to be valid.");
return (-1);
}
memcpy (&packet[16], &packet[00], 4);
iv64[0] = n2n_rand ();
iv32[2] = n2n_rand ();
iv32[3] = htobe32 (magic);
memcpy (packet, iv, 16);
packet[15] = header_len;
speck_he (&packet[12], &packet[12], header_len - 12, iv, (speck_context_t*)ctx);
return (0);
}
/* ********************************************************************** */
void packet_header_setup_key (const char * community_name, he_context_t ** ctx) {
uint8_t key[16];
pearson_hash_128 (key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE);
*ctx = (he_context_t*)calloc(1, sizeof (speck_context_t));
speck_expand_key_he (key, (speck_context_t*)*ctx);
}

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

221
src/pearson.c Normal file
View File

@ -0,0 +1,221 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
// taken from https://github.com/Logan007/pearson
// This is free and unencumbered software released into the public domain.
#include <stddef.h>
#include <stdint.h>
#include "pearson.h"
// table as in original paper "Fast Hashing of Variable-Length Text Strings" by Peter K. Pearson
// as published in The Communications of the ACM Vol.33, No. 6 (June 1990), pp. 677-680.
static const uint8_t t[256] ={
0x01, 0x57, 0x31, 0x0c, 0xb0, 0xb2, 0x66, 0xa6, 0x79, 0xc1, 0x06, 0x54, 0xf9, 0xe6, 0x2c, 0xa3,
0x0e, 0xc5, 0xd5, 0xb5, 0xa1, 0x55, 0xda, 0x50, 0x40, 0xef, 0x18, 0xe2, 0xec, 0x8e, 0x26, 0xc8,
0x6e, 0xb1, 0x68, 0x67, 0x8d, 0xfd, 0xff, 0x32, 0x4d, 0x65, 0x51, 0x12, 0x2d, 0x60, 0x1f, 0xde,
0x19, 0x6b, 0xbe, 0x46, 0x56, 0xed, 0xf0, 0x22, 0x48, 0xf2, 0x14, 0xd6, 0xf4, 0xe3, 0x95, 0xeb,
0x61, 0xea, 0x39, 0x16, 0x3c, 0xfa, 0x52, 0xaf, 0xd0, 0x05, 0x7f, 0xc7, 0x6f, 0x3e, 0x87, 0xf8,
0xae, 0xa9, 0xd3, 0x3a, 0x42, 0x9a, 0x6a, 0xc3, 0xf5, 0xab, 0x11, 0xbb, 0xb6, 0xb3, 0x00, 0xf3,
0x84, 0x38, 0x94, 0x4b, 0x80, 0x85, 0x9e, 0x64, 0x82, 0x7e, 0x5b, 0x0d, 0x99, 0xf6, 0xd8, 0xdb,
0x77, 0x44, 0xdf, 0x4e, 0x53, 0x58, 0xc9, 0x63, 0x7a, 0x0b, 0x5c, 0x20, 0x88, 0x72, 0x34, 0x0a,
0x8a, 0x1e, 0x30, 0xb7, 0x9c, 0x23, 0x3d, 0x1a, 0x8f, 0x4a, 0xfb, 0x5e, 0x81, 0xa2, 0x3f, 0x98,
0xaa, 0x07, 0x73, 0xa7, 0xf1, 0xce, 0x03, 0x96, 0x37, 0x3b, 0x97, 0xdc, 0x5a, 0x35, 0x17, 0x83,
0x7d, 0xad, 0x0f, 0xee, 0x4f, 0x5f, 0x59, 0x10, 0x69, 0x89, 0xe1, 0xe0, 0xd9, 0xa0, 0x25, 0x7b,
0x76, 0x49, 0x02, 0x9d, 0x2e, 0x74, 0x09, 0x91, 0x86, 0xe4, 0xcf, 0xd4, 0xca, 0xd7, 0x45, 0xe5,
0x1b, 0xbc, 0x43, 0x7c, 0xa8, 0xfc, 0x2a, 0x04, 0x1d, 0x6c, 0x15, 0xf7, 0x13, 0xcd, 0x27, 0xcb,
0xe9, 0x28, 0xba, 0x93, 0xc6, 0xc0, 0x9b, 0x21, 0xa4, 0xbf, 0x62, 0xcc, 0xa5, 0xb4, 0x75, 0x4c,
0x8c, 0x24, 0xd2, 0xac, 0x29, 0x36, 0x9f, 0x08, 0xb9, 0xe8, 0x71, 0xc4, 0xe7, 0x2f, 0x92, 0x78,
0x33, 0x41, 0x1c, 0x90, 0xfe, 0xdd, 0x5d, 0xbd, 0xc2, 0x8b, 0x70, 0x2b, 0x47, 0x6d, 0xb8, 0xd1 };
/*
// alternative table as used in RFC 3074 and NOT as in original paper
static const uint8_t t[256] ={
0xfb, 0xaf, 0x77, 0xd7, 0x51, 0x0e, 0x4f, 0xbf, 0x67, 0x31, 0xb5, 0x8f, 0xba, 0x9d, 0x00, 0xe8,
0x1f, 0x20, 0x37, 0x3c, 0x98, 0x3a, 0x11, 0xed, 0xae, 0x46, 0xa0, 0x90, 0xdc, 0x5a, 0x39, 0xdf,
0x3b, 0x03, 0x12, 0x8c, 0x6f, 0xa6, 0xcb, 0xc4, 0x86, 0xf3, 0x7c, 0x5f, 0xde, 0xb3, 0xc5, 0x41,
0xb4, 0x30, 0x24, 0x0f, 0x6b, 0x2e, 0xe9, 0x82, 0xa5, 0x1e, 0x7b, 0xa1, 0xd1, 0x17, 0x61, 0x10,
0x28, 0x5b, 0xdb, 0x3d, 0x64, 0x0a, 0xd2, 0x6d, 0xfa, 0x7f, 0x16, 0x8a, 0x1d, 0x6c, 0xf4, 0x43,
0xcf, 0x09, 0xb2, 0xcc, 0x4a, 0x62, 0x7e, 0xf9, 0xa7, 0x74, 0x22, 0x4d, 0xc1, 0xc8, 0x79, 0x05,
0x14, 0x71, 0x47, 0x23, 0x80, 0x0d, 0xb6, 0x5e, 0x19, 0xe2, 0xe3, 0xc7, 0x4b, 0x1b, 0x29, 0xf5,
0xe6, 0xe0, 0x2b, 0xe1, 0xb1, 0x1a, 0x9b, 0x96, 0xd4, 0x8e, 0xda, 0x73, 0xf1, 0x49, 0x58, 0x69,
0x27, 0x72, 0x3e, 0xff, 0xc0, 0xc9, 0x91, 0xd6, 0xa8, 0x9e, 0xdd, 0x94, 0x9a, 0x7a, 0x0c, 0x54,
0x52, 0xa3, 0x2c, 0x8b, 0xe4, 0xec, 0xcd, 0xf2, 0xd9, 0x0b, 0xbb, 0x92, 0x9f, 0x40, 0x56, 0xef,
0xc3, 0x2a, 0x6a, 0xc6, 0x76, 0x70, 0xb8, 0xac, 0x57, 0x02, 0xad, 0x75, 0xb0, 0xe5, 0xf7, 0xfd,
0x89, 0xb9, 0x63, 0xa4, 0x66, 0x93, 0x2d, 0x42, 0xe7, 0x34, 0x8d, 0xd3, 0xc2, 0xce, 0xf6, 0xee,
0x38, 0x6e, 0x4e, 0xf8, 0x3f, 0xf0, 0xbd, 0x5d, 0x5c, 0x33, 0x35, 0xb7, 0x13, 0xab, 0x48, 0x32,
0x21, 0x68, 0x65, 0x45, 0x08, 0xfc, 0x53, 0x78, 0x4c, 0x87, 0x55, 0x36, 0xca, 0x7d, 0xbc, 0xd5,
0x60, 0xeb, 0x88, 0xd0, 0xa2, 0x81, 0xbe, 0x84, 0x9c, 0x26, 0x2f, 0x01, 0x07, 0xfe, 0x18, 0x04,
0xd8, 0x83, 0x59, 0x15, 0x1c, 0x85, 0x25, 0x99, 0x95, 0x50, 0xaa, 0x44, 0x06, 0xa9, 0xea, 0x97 }; */
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len) {
/* initial values - astonishingly, assembling using SHIFTs and ORs (in register)
* works faster on well pipelined CPUs than loading the 64-bit value from memory.
* however, there is one advantage to loading from memory: as we also store back to
* memory at the end, we do not need to care about endianess! */
uint8_t upper[8] = { 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };
uint8_t lower[8] = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
uint64_t *upper_hash_mask_ptr = (uint64_t*)&upper;
uint64_t *lower_hash_mask_ptr = (uint64_t*)&lower;
uint64_t upper_hash_mask = *upper_hash_mask_ptr;
uint64_t lower_hash_mask = *lower_hash_mask_ptr;
uint64_t high_upper_hash_mask = upper_hash_mask + 0x1010101010101010;
uint64_t high_lower_hash_mask = lower_hash_mask + 0x1010101010101010;
uint64_t upper_hash = 0;
uint64_t lower_hash = 0;
uint64_t high_upper_hash = 0;
uint64_t high_lower_hash = 0;
size_t i;
for (i = 0; i < len; i++) {
// broadcast the character, xor into hash, make them different permutations
uint64_t c = (uint8_t)in[i];
c |= c << 8;
c |= c << 16;
c |= c << 32;
upper_hash ^= c ^ upper_hash_mask;
lower_hash ^= c ^ lower_hash_mask;
high_upper_hash ^= c ^ high_upper_hash_mask;
high_lower_hash ^= c ^ high_lower_hash_mask;
// table lookup
uint8_t x;
uint64_t h = 0;
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
upper_hash = h;
h = 0;
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
lower_hash = h;
h = 0;
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_upper_hash; x = t[x]; high_upper_hash >>= 8; h |= x; h=ROR64(h,8);
high_upper_hash = h;
h = 0;
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = high_lower_hash; x = t[x]; high_lower_hash >>= 8; h |= x; h=ROR64(h,8);
high_lower_hash = h;
}
// store output
uint64_t *o;
o = (uint64_t*)&out[0];
*o = high_upper_hash;
o = (uint64_t*)&out[8];
*o = high_lower_hash;
o = (uint64_t*)&out[16];
*o = upper_hash;
o = (uint64_t*)&out[24];
*o = lower_hash;
}
void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len) {
/* initial values - astonishingly, assembling using SHIFTs and ORs (in register)
* works faster on well pipelined CPUs than loading the 64-bit value from memory.
* however, there is one advantage to loading from memory: as we also store back to
* memory at the end, we do not need to care about endianess! */
uint8_t upper[8] = { 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };
uint8_t lower[8] = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
uint64_t *upper_hash_mask_ptr = (uint64_t*)&upper;
uint64_t *lower_hash_mask_ptr = (uint64_t*)&lower;
uint64_t upper_hash_mask = *upper_hash_mask_ptr;
uint64_t lower_hash_mask = *lower_hash_mask_ptr;
uint64_t upper_hash = 0;
uint64_t lower_hash = 0;
size_t i;
for (i = 0; i < len; i++) {
// broadcast the character, xor into hash, make them different permutations
uint64_t c = (uint8_t)in[i];
c |= c << 8;
c |= c << 16;
c |= c << 32;
upper_hash ^= c ^ upper_hash_mask;
lower_hash ^= c ^ lower_hash_mask;
// table lookup
uint8_t x;
uint64_t h = 0;
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
upper_hash = h;
h = 0;
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
lower_hash = h;
}
// store output
uint64_t *o;
o = (uint64_t*)&out[0];
*o = upper_hash;
o = (uint64_t*)&out[8];
*o = lower_hash;
}

View File

@ -1,12 +1,29 @@
/**
* (C) 2007-20 - ntop.org and contributors
*
* This program 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.
*
* This program 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 this program; if not see see <http://www.gnu.org/licenses/>
*
*/
#include "n2n.h"
/* The following code offers an alterate pseudo random number generator /* The following code offers an alterate pseudo random number generator
namely XORSHIFT128+ to use instead of C's rand(). Its performance is namely XORSHIFT128+ to use instead of C's rand(). Its performance is
on par with C's rand(). on par with C's rand().
*/ */
#include "random_numbers.h"
/* The state must be seeded in a way that it is not all zero, choose some /* The state must be seeded in a way that it is not all zero, choose some
arbitrary defaults (in this case: taken from splitmix64) */ arbitrary defaults (in this case: taken from splitmix64) */
static struct rn_generator_state_t rn_current_state = { static struct rn_generator_state_t rn_current_state = {

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +19,7 @@
/* Supernode for n2n-2.x */ /* Supernode for n2n-2.x */
#include "n2n.h" #include "n2n.h"
#include "header_encryption.h"
#ifdef WIN32 #ifdef WIN32
#include <signal.h> #include <signal.h>
@ -32,12 +33,14 @@
#define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out) #define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out)
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize); size_t pktsize);
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
@ -80,6 +83,8 @@ static void deinit_sn(n2n_sn_t * sss)
HASH_ITER(hh, sss->communities, community, tmp) { HASH_ITER(hh, sss->communities, community, tmp) {
clear_peer_list(&community->edges); clear_peer_list(&community->edges);
if (NULL != community->header_encryption_ctx)
free (community->header_encryption_ctx);
HASH_DEL(sss->communities, community); HASH_DEL(sss->communities, community);
free(community); free(community);
} }
@ -185,24 +190,17 @@ static ssize_t sendto_sock(n2n_sn_t * sss,
} }
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info * scan; struct peer_info * scan;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community); HASH_FIND_PEER(comm->edges, dstMac, scan);
if(!community) {
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community);
return(-1);
}
HASH_FIND_PEER(community->edges, dstMac, scan);
if(NULL != scan) if(NULL != scan)
{ {
@ -245,51 +243,44 @@ static int try_forward(n2n_sn_t * sss,
* the supernode. * the supernode.
*/ */
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info *scan, *tmp; struct peer_info *scan, *tmp;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
traceEvent(TRACE_DEBUG, "try_broadcast"); traceEvent(TRACE_DEBUG, "try_broadcast");
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community); HASH_ITER(hh, comm->edges, scan, tmp) {
if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) {
/* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len;
if(community) { data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
HASH_ITER(hh, community->edges, scan, tmp) {
if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) {
/* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); if(data_sent_len != pktsize)
{
if(data_sent_len != pktsize) ++(sss->stats.errors);
{ traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
++(sss->stats.errors); pktsize,
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s", sock_to_cstr(sockbuf, &(scan->sock)),
pktsize, macaddr_str(mac_buf, scan->mac_addr),
sock_to_cstr(sockbuf, &(scan->sock)), strerror(errno));
macaddr_str(mac_buf, scan->mac_addr), }
strerror(errno)); else
} {
else ++(sss->stats.broadcast);
{ traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
++(sss->stats.broadcast); pktsize,
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s", sock_to_cstr(sockbuf, &(scan->sock)),
pktsize, macaddr_str(mac_buf, scan->mac_addr));
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr));
}
} }
} }
} else }
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
cmn->community);
return 0; return 0;
} }
@ -389,6 +380,8 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
HASH_ITER(hh, sss->communities, s, tmp) { HASH_ITER(hh, sss->communities, s, tmp) {
HASH_DEL(sss->communities, s); HASH_DEL(sss->communities, s);
if (NULL != s->header_encryption_ctx)
free (s->header_encryption_ctx);
free(s); free(s);
} }
@ -412,7 +405,12 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
if(s != NULL) { if(s != NULL) {
strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1); strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1);
s->community[N2N_COMMUNITY_SIZE-1] = '\0'; s->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* we do not know if header encryption is used in this community,
* first packet will show. just in case, setup the key. */
s->header_encryption = HEADER_ENCRYPTION_UNKNOWN;
packet_header_setup_key (s->community, &(s->header_encryption_ctx));
HASH_ADD_STR(sss->communities, community, s); HASH_ADD_STR(sss->communities, community, s);
num_communities++; num_communities++;
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]", traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
(char*)s->community, num_communities); (char*)s->community, num_communities);
@ -435,7 +433,7 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
*/ */
static int process_udp(n2n_sn_t * sss, static int process_udp(n2n_sn_t * sss,
const struct sockaddr_in * sender_sock, const struct sockaddr_in * sender_sock,
const uint8_t * udp_buf, uint8_t * udp_buf,
size_t udp_size, size_t udp_size,
time_t now) time_t now)
{ {
@ -448,11 +446,70 @@ static int process_udp(n2n_sn_t * sss,
macstr_t mac_buf2; macstr_t mac_buf2;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
char buf[32]; char buf[32];
struct sn_community *comm, *tmp;
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]",
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port)); ntohs(sender_sock->sin_port));
/* check if header is unenrypted. the following check is around 99.99962 percent reliable.
* it heavily relies on the structure of packet's common part
* changes to wire.c:encode/decode_common need to go together with this code */
if (udp_size < 20) {
traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid.");
return -1;
}
if ( (udp_buf[19] == (uint8_t)0x00) // null terminated community name
&& (udp_buf[00] == N2N_PKT_VERSION) // correct packet version
&& ((be16toh (*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
&& ( be16toh (*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags
) {
/* most probably unencrypted */
/* make sure, no downgrading happens here and no unencrypted packets can be
* injected in a community which definitely deals with encrypted headers */
HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm);
if (comm) {
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header "
"addressed to community '%s' which uses encrypted headers.",
comm->community);
return -1;
}
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
"unencrypted headers.", comm->community);
/* set 'no encryption' in case it is not set yet */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
}
}
} else {
/* most probably encrypted */
/* cycle through the known communities (as keys) to eventually decrypt */
uint32_t ret = 0;
HASH_ITER (hh, sss->communities, comm, tmp) {
/* skip the definitely unencrypted communities */
if (comm->header_encryption == HEADER_ENCRYPTION_NONE)
continue;
if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) {
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
"encrypted headers.", comm->community);
/* set 'encrypted' in case it is not set yet */
comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
}
// no need to test further communities
break;
}
}
if (!ret) {
// no matching key/community
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header "
"for which no matching community which uses encrypted headers was found.");
return -1;
}
}
/* Use decode_common() to determine the kind of packet then process it: /* Use decode_common() to determine the kind of packet then process it:
* *
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
@ -491,8 +548,12 @@ static int process_udp(n2n_sn_t * sss,
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ int unicast; /* non-zero if unicast */
const uint8_t * rec_buf; /* either udp_buf or encbuf */ uint8_t * rec_buf; /* either udp_buf or encbuf */
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community);
return -1;
}
sss->stats.last_fwd=now; sss->stats.last_fwd=now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
@ -520,6 +581,9 @@ static int process_udp(n2n_sn_t * sss,
/* Re-encode the header. */ /* Re-encode the header. */
encode_PACKET(encbuf, &encx, &cmn2, &pkt); encode_PACKET(encbuf, &encx, &cmn2, &pkt);
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx);
/* Copy the original payload unchanged */ /* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} else { } else {
@ -530,13 +594,16 @@ static int process_udp(n2n_sn_t * sss,
rec_buf = udp_buf; rec_buf = udp_buf;
encx = udp_size; encx = udp_size;
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
} }
/* Common section to forward the final product. */ /* Common section to forward the final product. */
if(unicast) if(unicast)
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx); try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
else else
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx); try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
break; break;
} }
case MSG_TYPE_REGISTER: case MSG_TYPE_REGISTER:
@ -548,7 +615,12 @@ static int process_udp(n2n_sn_t * sss,
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ int unicast; /* non-zero if unicast */
const uint8_t * rec_buf; /* either udp_buf or encbuf */ uint8_t * rec_buf; /* either udp_buf or encbuf */
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community);
return -1;
}
sss->stats.last_fwd=now; sss->stats.last_fwd=now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
@ -586,7 +658,10 @@ static int process_udp(n2n_sn_t * sss,
encx = udp_size; encx = udp_size;
} }
try_forward(sss, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */ if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
} else } else
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
break; break;
@ -601,15 +676,12 @@ static int process_udp(n2n_sn_t * sss,
n2n_common_t cmn2; n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
struct sn_community *comm;
/* Edge requesting registration with us. */ /* Edge requesting registration with us. */
sss->stats.last_reg_super=now; sss->stats.last_reg_super=now;
++(sss->stats.reg_super); ++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx);
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, comm);
/* /*
Before we move any further, we need to check if the requested Before we move any further, we need to check if the requested
community is allowed by the supernode. In case it is not we do community is allowed by the supernode. In case it is not we do
@ -622,6 +694,10 @@ static int process_udp(n2n_sn_t * sss,
if(comm) { if(comm) {
strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1); strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1);
comm->community[N2N_COMMUNITY_SIZE-1] = '\0'; comm->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* new communities introduced by REGISTERs could not have had encrypted header */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
HASH_ADD_STR(sss->communities, community, comm); HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community); traceEvent(TRACE_INFO, "New community: %s", comm->community);
@ -653,6 +729,9 @@ static int process_udp(n2n_sn_t * sss,
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack); encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx);
sendto(sss->sock, ackbuf, encx, 0, sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
@ -663,13 +742,18 @@ static int process_udp(n2n_sn_t * sss,
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community); (char*)cmn.community);
break; break;
} case MSG_TYPE_QUERY_PEER: { }
case MSG_TYPE_QUERY_PEER: {
n2n_QUERY_PEER_t query; n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
n2n_common_t cmn2; n2n_common_t cmn2;
n2n_PEER_INFO_t pi; n2n_PEER_INFO_t pi;
struct sn_community *community;
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community);
return -1;
}
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
@ -677,36 +761,35 @@ static int process_udp(n2n_sn_t * sss,
macaddr_str( mac_buf, query.srcMac ), macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) ); macaddr_str( mac_buf2, query.targetMac ) );
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, community); struct peer_info *scan;
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if(community) { if (scan) {
struct peer_info *scan; cmn2.ttl = N2N_DEFAULT_TTL;
HASH_FIND_PEER(community->edges, query.targetMac, scan); cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
if (scan) { pi.aflags = 0;
cmn2.ttl = N2N_DEFAULT_TTL; memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
cmn2.pc = n2n_peer_info; pi.sock = scan->sock;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
pi.aflags = 0; encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
pi.sock = scan->sock;
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi ); if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx);
sendto( sss->sock, encbuf, encx, 0, sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s", traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str( mac_buf, query.srcMac ) ); macaddr_str( mac_buf, query.srcMac ) );
} else { } else {
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s", traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) ); macaddr_str( mac_buf, query.targetMac ) );
}
} }
break; break;
} }
default: default:
/* Not a known message type */ /* Not a known message type */
@ -1113,6 +1196,9 @@ static int run_loop(n2n_sn_t * sss) {
if((comm->edges == NULL) && (!sss->lock_communities)) { if((comm->edges == NULL) && (!sss->lock_communities)) {
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community); traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
if (NULL != comm->header_encryption_ctx)
/* this should not happen as no 'locked' and thus only communities w/o encrypted header here */
free (comm->header_encryption_ctx);
HASH_DEL(sss->communities, comm); HASH_DEL(sss->communities, comm);
free(comm); free(comm);
} }

839
src/sn_utils.c Normal file
View File

@ -0,0 +1,839 @@
#include "n2n.h"
#include "header_encryption.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
#define N2N_SN_LPORT_DEFAULT 7654
#define N2N_SN_PKTBUF_SIZE 2048
static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn,
const n2n_mac_t dstMac,
const uint8_t * pktbuf,
size_t pktsize);
static ssize_t sendto_sock(n2n_sn_t *sss,
const n2n_sock_t *sock,
const uint8_t *pktbuf,
size_t pktsize);
static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn,
const n2n_mac_t srcMac,
const uint8_t * pktbuf,
size_t pktsize);
static uint16_t reg_lifetime(n2n_sn_t *sss);
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now);
static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
size_t mgmt_size,
time_t now);
static int process_udp(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
uint8_t *udp_buf,
size_t udp_size,
time_t now);
static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn,
const n2n_mac_t dstMac,
const uint8_t * pktbuf,
size_t pktsize)
{
struct peer_info * scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
HASH_FIND_PEER(comm->edges, dstMac, scan);
if(NULL != scan)
{
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
if(data_sent_len == pktsize)
{
++(sss->stats.fwd);
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr));
}
else
{
++(sss->stats.errors);
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr),
errno, strerror(errno));
}
}
else
{
traceEvent(TRACE_DEBUG, "try_forward unknown MAC");
/* Not a known MAC so drop. */
return(-2);
}
return(0);
}
/** Send a datagram to the destination embodied in a n2n_sock_t.
*
* @return -1 on error otherwise number of bytes sent
*/
static ssize_t sendto_sock(n2n_sn_t *sss,
const n2n_sock_t *sock,
const uint8_t *pktbuf,
size_t pktsize)
{
n2n_sock_str_t sockbuf;
if (AF_INET == sock->family)
{
struct sockaddr_in udpsock;
udpsock.sin_family = AF_INET;
udpsock.sin_port = htons(sock->port);
memcpy(&(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE);
traceEvent(TRACE_DEBUG, "sendto_sock %lu to [%s]",
pktsize,
sock_to_cstr(sockbuf, sock));
return sendto(sss->sock, pktbuf, pktsize, 0,
(const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in));
}
else
{
/* AF_INET6 not implemented */
errno = EAFNOSUPPORT;
return -1;
}
}
/** Try and broadcast a message to all edges in the community.
*
* This will send the exact same datagram to zero or more edges registered to
* the supernode.
*/
static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn,
const n2n_mac_t srcMac,
const uint8_t * pktbuf,
size_t pktsize)
{
struct peer_info *scan, *tmp;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
traceEvent(TRACE_DEBUG, "try_broadcast");
HASH_ITER(hh, comm->edges, scan, tmp) {
if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) {
/* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
if(data_sent_len != pktsize)
{
++(sss->stats.errors);
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr),
strerror(errno));
}
else
{
++(sss->stats.broadcast);
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
pktsize,
sock_to_cstr(sockbuf, &(scan->sock)),
macaddr_str(mac_buf, scan->mac_addr));
}
}
}
return 0;
}
/** Initialise the supernode structure */
int sn_init(n2n_sn_t *sss)
{
#ifdef WIN32
initWin32();
#endif
memset(sss, 0, sizeof(n2n_sn_t));
sss->daemon = 1; /* By defult run as a daemon. */
sss->lport = N2N_SN_LPORT_DEFAULT;
sss->sock = -1;
sss->mgmt_sock = -1;
return 0; /* OK */
}
/** Deinitialise the supernode structure and deallocate any memory owned by
* it. */
void sn_term(n2n_sn_t *sss)
{
struct sn_community *community, *tmp;
if (sss->sock >= 0)
{
closesocket(sss->sock);
}
sss->sock = -1;
if (sss->mgmt_sock >= 0)
{
closesocket(sss->mgmt_sock);
}
sss->mgmt_sock = -1;
HASH_ITER(hh, sss->communities, community, tmp)
{
clear_peer_list(&community->edges);
if (NULL != community->header_encryption_ctx)
free (community->header_encryption_ctx);
HASH_DEL(sss->communities, community);
free(community);
}
}
/** Determine the appropriate lifetime for new registrations.
*
* If the supernode has been put into a pre-shutdown phase then this lifetime
* should not allow registrations to continue beyond the shutdown point.
*/
static uint16_t reg_lifetime(n2n_sn_t *sss)
{
/* NOTE: UDP firewalls usually have a 30 seconds timeout */
return 15;
}
/** Update the edge table with the details of the edge which contacted the
* supernode. */
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now)
{
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
struct peer_info *scan;
traceEvent(TRACE_DEBUG, "update_edge for %s [%s]",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
HASH_FIND_PEER(comm->edges, edgeMac, scan);
if (NULL == scan)
{
/* Not known */
scan = (struct peer_info *)calloc(1,
sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
HASH_ADD_PEER(comm->edges, scan);
traceEvent(TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
/* Known */
if (!sock_equal(sender_sock, &(scan->sock)))
{
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
traceEvent(TRACE_INFO, "update_edge updated %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
}
scan->last_seen = now;
return 0;
}
static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
size_t mgmt_size,
time_t now)
{
char resbuf[N2N_SN_PKTBUF_SIZE];
size_t ressize = 0;
uint32_t num_edges = 0;
ssize_t r;
struct sn_community *community, *tmp;
traceEvent(TRACE_DEBUG, "process_mgmt");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"----------------\n");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"uptime %lu\n", (now - sss->start_time));
HASH_ITER(hh, sss->communities, community, tmp)
{
num_edges += HASH_COUNT(community->edges);
}
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"edges %u\n",
num_edges);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"errors %u\n",
(unsigned int)sss->stats.errors);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_sup %u\n",
(unsigned int)sss->stats.reg_super);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_nak %u\n",
(unsigned int)sss->stats.reg_super_nak);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"fwd %u\n",
(unsigned int)sss->stats.fwd);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"broadcast %u\n",
(unsigned int)sss->stats.broadcast);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last fwd %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_fwd));
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last reg %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_reg_super));
r = sendto(sss->mgmt_sock, resbuf, ressize, 0 /*flags*/,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
if (r <= 0)
{
++(sss->stats.errors);
traceEvent(TRACE_ERROR, "process_mgmt : sendto failed. %s", strerror(errno));
}
return 0;
}
/** Examine a datagram and determine what to do with it.
*
*/
static int process_udp(n2n_sn_t * sss,
const struct sockaddr_in * sender_sock,
uint8_t * udp_buf,
size_t udp_size,
time_t now)
{
n2n_common_t cmn; /* common fields in the packet header */
size_t rem;
size_t idx;
size_t msg_type;
uint8_t from_supernode;
macstr_t mac_buf;
macstr_t mac_buf2;
n2n_sock_str_t sockbuf;
char buf[32];
struct sn_community *comm, *tmp;
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]",
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port));
/* check if header is unenrypted. the following check is around 99.99962 percent reliable.
* it heavily relies on the structure of packet's common part
* changes to wire.c:encode/decode_common need to go together with this code */
if (udp_size < 20) {
traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid.");
return -1;
}
if ( (udp_buf[19] == (uint8_t)0x00) // null terminated community name
&& (udp_buf[00] == N2N_PKT_VERSION) // correct packet version
&& ((be16toh (*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
&& ( be16toh (*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags
) {
/* most probably unencrypted */
/* make sure, no downgrading happens here and no unencrypted packets can be
* injected in a community which definitely deals with encrypted headers */
HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm);
if (comm) {
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header "
"addressed to community '%s' which uses encrypted headers.",
comm->community);
return -1;
}
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
"unencrypted headers.", comm->community);
/* set 'no encryption' in case it is not set yet */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
}
}
} else {
/* most probably encrypted */
/* cycle through the known communities (as keys) to eventually decrypt */
uint32_t ret = 0;
HASH_ITER (hh, sss->communities, comm, tmp) {
/* skip the definitely unencrypted communities */
if (comm->header_encryption == HEADER_ENCRYPTION_NONE)
continue;
if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) {
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
"encrypted headers.", comm->community);
/* set 'encrypted' in case it is not set yet */
comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
}
// no need to test further communities
break;
}
}
if (!ret) {
// no matching key/community
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header "
"for which no matching community which uses encrypted headers was found.");
return -1;
}
}
/* Use decode_common() to determine the kind of packet then process it:
*
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
*
* REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
* destination edge. If the destination is not known then PACKETs are
* broadcast.
*/
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
idx = 0; /* marches through packet header as parts are decoded. */
if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) {
traceEvent(TRACE_ERROR, "Failed to decode common section");
return -1; /* failed to decode packet */
}
msg_type = cmn.pc; /* packet code */
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
if(cmn.ttl < 1) {
traceEvent(TRACE_WARNING, "Expired TTL");
return 0; /* Don't process further */
}
--(cmn.ttl); /* The value copied into all forwarded packets. */
switch(msg_type) {
case MSG_TYPE_PACKET:
{
/* PACKET from one edge to another edge via supernode. */
/* pkt will be modified in place and recoded to an output of potentially
* different size due to addition of the socket.*/
n2n_PACKET_t pkt;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
int unicast; /* non-zero if unicast */
uint8_t * rec_buf; /* either udp_buf or encbuf */
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community);
return -1;
}
sss->stats.last_fwd=now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
unicast = (0 == is_multi_broadcast(pkt.dstMac));
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
(unicast?"unicast":"multicast"),
macaddr_str(mac_buf, pkt.srcMac),
macaddr_str(mac_buf2, pkt.dstMac),
(from_supernode?"from sn":"local"));
if(!from_supernode) {
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
pkt.sock.family = AF_INET;
pkt.sock.port = ntohs(sender_sock->sin_port);
memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
rec_buf = encbuf;
/* Re-encode the header. */
encode_PACKET(encbuf, &encx, &cmn2, &pkt);
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx);
/* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} else {
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified");
rec_buf = udp_buf;
encx = udp_size;
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
}
/* Common section to forward the final product. */
if(unicast)
try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
else
try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
break;
}
case MSG_TYPE_REGISTER:
{
/* Forwarding a REGISTER from one edge to the next */
n2n_REGISTER_t reg;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
int unicast; /* non-zero if unicast */
uint8_t * rec_buf; /* either udp_buf or encbuf */
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community);
return -1;
}
sss->stats.last_fwd=now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
unicast = (0 == is_multi_broadcast(reg.dstMac));
if(unicast) {
traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
macaddr_str(mac_buf, reg.srcMac),
macaddr_str(mac_buf2, reg.dstMac),
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local"));
if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) {
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
reg.sock.family = AF_INET;
reg.sock.port = ntohs(sender_sock->sin_port);
memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
rec_buf = encbuf;
/* Re-encode the header. */
encode_REGISTER(encbuf, &encx, &cmn2, &reg);
/* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} else {
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
rec_buf = udp_buf;
encx = udp_size;
}
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
} else
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
break;
}
case MSG_TYPE_REGISTER_ACK:
traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode");
break;
case MSG_TYPE_REGISTER_SUPER:
{
n2n_REGISTER_SUPER_t reg;
n2n_REGISTER_SUPER_ACK_t ack;
n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
/* Edge requesting registration with us. */
sss->stats.last_reg_super=now;
++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx);
/*
Before we move any further, we need to check if the requested
community is allowed by the supernode. In case it is not we do
not report any message back to the edge to hide the supernode
existance (better from the security standpoint)
*/
if(!comm && !sss->lock_communities) {
comm = calloc(1, sizeof(struct sn_community));
if(comm) {
strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1);
comm->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* new communities introduced by REGISTERs could not have had encrypted header */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
}
}
if(comm) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
ack.lifetime = reg_lifetime(sss);
ack.sock.family = AF_INET;
ack.sock.port = ntohs(sender_sock->sin_port);
memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
ack.num_sn=0; /* No backup */
memset(&(ack.sn_bak), 0, sizeof(n2n_sock_t));
traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
update_edge(sss, reg.edgeMac, comm, &(ack.sock), now);
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx);
sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
} else
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community);
break;
}
case MSG_TYPE_QUERY_PEER: {
n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
n2n_common_t cmn2;
n2n_PEER_INFO_t pi;
if(!comm) {
traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community);
return -1;
}
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) );
struct peer_info *scan;
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if (scan) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
pi.aflags = 0;
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
pi.sock = scan->sock;
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx);
sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str( mac_buf, query.srcMac ) );
} else {
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) );
}
break;
}
default:
/* Not a known message type */
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
} /* switch(msg_type) */
return 0;
}
/** Long lived processing entry point. Split out from main to simply
* daemonisation on some platforms. */
int run_sn_loop(n2n_sn_t *sss, int *keep_running)
{
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
time_t last_purge_edges = 0;
struct sn_community *comm, *tmp;
sss->start_time = time(NULL);
while (*keep_running)
{
int rc;
ssize_t bread;
int max_sock;
fd_set socket_mask;
struct timeval wait_time;
time_t now = 0;
FD_ZERO(&socket_mask);
max_sock = MAX(sss->sock, sss->mgmt_sock);
FD_SET(sss->sock, &socket_mask);
FD_SET(sss->mgmt_sock, &socket_mask);
wait_time.tv_sec = 10;
wait_time.tv_usec = 0;
rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time);
now = time(NULL);
if (rc > 0)
{
if (FD_ISSET(sss->sock, &socket_mask))
{
struct sockaddr_in sender_sock;
socklen_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if ((bread < 0)
#ifdef WIN32
&& (WSAGetLastError() != WSAECONNRESET)
#endif
)
{
/* For UDP bread of zero just means no data (unlike TCP). */
/* The fd is no good now. Maybe we lost our interface. */
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno));
#ifdef WIN32
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
#endif
keep_running = 0;
break;
}
/* We have a datagram to process */
if (bread > 0)
{
/* And the datagram has data (not just a header) */
process_udp(sss, &sender_sock, pktbuf, bread, now);
}
}
if (FD_ISSET(sss->mgmt_sock, &socket_mask))
{
struct sockaddr_in sender_sock;
size_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if (bread <= 0)
{
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno));
keep_running = 0;
break;
}
/* We have a datagram to process */
process_mgmt(sss, &sender_sock, pktbuf, bread, now);
}
}
else
{
traceEvent(TRACE_DEBUG, "timeout");
}
HASH_ITER(hh, sss->communities, comm, tmp)
{
purge_expired_registrations(&comm->edges, &last_purge_edges);
if ((comm->edges == NULL) && (!sss->lock_communities))
{
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
if (NULL != comm->header_encryption_ctx)
/* this should not happen as no 'locked' and thus only communities w/o encrypted header here */
free (comm->header_encryption_ctx);
HASH_DEL(sss->communities, comm);
free(comm);
}
}
} /* while */
sn_term(sss);
return 0;
}

View File

@ -1,16 +1,14 @@
// cipher SPECK -- 128 bit block size -- 256 bit key size // cipher SPECK -- 128 bit block size -- 256 bit key size -- CTR mode
// taken from (and modified: removed pure crypto-stream generation and seperated key expansion) // taken from (and modified: removed pure crypto-stream generation and seperated key expansion)
// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/ // https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include "portable_endian.h"
#ifndef __ANDROID_NDK__ #ifndef __ANDROID_NDK__
#include "speck.h" #include "speck.h"
#if defined (__AVX2__) // AVX support ---------------------------------------------------- #if defined (__AVX2__) // AVX support ----------------------------------------------------
@ -568,9 +566,9 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
#else // plain C ---------------------------------------------------------------- #else // plain C ----------------------------------------------------------------
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r)))) #define ROR(x,r) (((x)>>(r))|((x)<<(64-(r))))
#define ROL64(x,r) (((x)<<(r))|((x)>>(64-(r)))) #define ROL(x,r) (((x)<<(r))|((x)>>(64-(r))))
#define R(x,y,k) (x=ROR64(x,8), x+=y, x^=k, y=ROL64(y,3), y^=x) #define R(x,y,k) (x=ROR(x,8), x+=y, x^=k, y=ROL(y,3), y^=x)
static int speck_encrypt (u64 *u, u64 *v, speck_context_t *ctx) { static int speck_encrypt (u64 *u, u64 *v, speck_context_t *ctx) {
@ -645,6 +643,85 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
#endif // AVX, SSE, NEON, plain C ------------------------------------------------ #endif // AVX, SSE, NEON, plain C ------------------------------------------------
// cipher SPECK -- 128 bit block size -- 128 bit key size -- CTR mode
// used for header encryption, thus the prefix 'he_'
// for now: just plain C -- AVX, SSE, NEON might follow
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
#define ROL64(x,r) (((x)<<(r))|((x)>>(64-(r))))
#define R64(x,y,k) (x=ROR64(x,8), x+=y, x^=k, y=ROL64(y,3), y^=x)
static int speck_encrypt_he (u64 *u, u64 *v, speck_context_t *ctx) {
u64 i, x=*u, y=*v;
for (i = 0; i < 32; i++)
R64 (x, y, ctx->key[i]);
*u = x; *v = y;
return 0;
}
int speck_he (unsigned char *out, const unsigned char *in, unsigned long long inlen,
const unsigned char *n, speck_context_t *ctx) {
u64 i, nonce[2], x, y, t;
unsigned char *block = malloc(16);
if (!inlen) {
free (block);
return 0;
}
nonce[0] = htole64 ( ((u64*)n)[0] );
nonce[1] = htole64 ( ((u64*)n)[1] );
t = 0;
while (inlen >= 16) {
x = nonce[1]; y = nonce[0]; nonce[0]++;
speck_encrypt_he (&x, &y, ctx);
((u64 *)out)[1+t] = htole64 (x ^ ((u64 *)in)[1+t]);
((u64 *)out)[0+t] = htole64 (y ^ ((u64 *)in)[0+t]);
t += 2;
inlen -= 16;
}
if (inlen > 0) {
x = nonce[1]; y = nonce[0];
speck_encrypt_he (&x, &y, ctx);
((u64 *)block)[1] = htole64 (x); ((u64 *)block)[0] = htole64 (y);
for (i = 0; i < inlen; i++)
out[i+8*t] = block[i] ^ in[i+8*t];
}
free(block);
return 0;
}
int speck_expand_key_he (const unsigned char *k, speck_context_t *ctx) {
u64 A, B;
u64 i;
A = htole64 ( ((u64 *)k)[0] );
B = htole64 ( ((u64 *)k)[1] );
for (i = 0; i < 32; i ++) {
ctx->key[i] = A;
R64 ( B, A, i);
}
return 1;
}
// code for testing -- to be removed when finished
/*
#include <stdio.h> // for testing
#include <string.h>
int speck_test () { int speck_test () {
uint8_t key[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, uint8_t key[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@ -652,16 +729,23 @@ int speck_test () {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
uint8_t iv[16] = { 0x70, 0x6f, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x20, uint8_t iv[16] = { 0x70, 0x6f, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x20,
0x49, 0x6e, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65 }; 0x49, 0x6e, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65 };
uint8_t xv[16] = { 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x69, 0x74,
0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c };
uint8_t pt[16] = { 0x00 }; uint8_t pt[16] = { 0x00 };
// expected outcome (according to pp. 35 & 36 of Implementation Guide) // expected outcome (according to pp. 35 & 36 of Implementation Guide)
uint8_t ct[16] = { 0x43, 0x8f, 0x18, 0x9c, 0x8d, 0xb4, 0xee, 0x4e, uint8_t ct[16] = { 0x43, 0x8f, 0x18, 0x9c, 0x8d, 0xb4, 0xee, 0x4e,
0x3e, 0xf5, 0xc0, 0x05, 0x04, 0x01, 0x09, 0x41 }; 0x3e, 0xf5, 0xc0, 0x05, 0x04, 0x01, 0x09, 0x41 };
uint8_t xt[16] = { 0x18, 0x0d, 0x57, 0x5c, 0xdf, 0xfe, 0x60, 0x78,
0x65, 0x32, 0x78, 0x79, 0x51, 0x98, 0x5d, 0xa6 };
speck_context_t ctx; speck_context_t ctx;
speck_expand_key (key, &ctx); speck_expand_key (key, &ctx);
@ -670,24 +754,37 @@ int speck_test () {
#else #else
speck_ctr (pt, pt, 16, iv, &ctx); speck_ctr (pt, pt, 16, iv, &ctx);
#endif #endif
u64 i; u64 i;
// fprintf (stderr, "rk00: %016llx\n", ctx.key[0]); fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
// fprintf (stderr, "rk33: %016llx\n", ctx.key[33]); fprintf (stderr, "rk33: %016llx\n", ctx.key[33]);
// fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt); fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt);
// fprintf (stderr, "mem : " ); for (i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n"); fprintf (stderr, "mem : " ); for (i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n");
int ret = 1; int ret = 1;
for (i=0; i < 16; i++) for (i=0; i < 16; i++)
if (pt[i] != ct[i]) ret = 0; if (pt[i] != ct[i]) ret = 0;
memset (pt, 0, 16);
speck_expand_key_he (key, &ctx);
speck_he (pt, pt, 16, xv, &ctx);
fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
fprintf (stderr, "rk31: %016llx\n", ctx.key[31]);
fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt);
fprintf (stderr, "mem : " ); for (i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n");
for (i=0; i < 16; i++)
if (pt[i] != xt[i]) ret = 0;
return (ret); return (ret);
} }
/*
int main (int argc, char* argv[]) { int main (int argc, char* argv[]) {
fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL)); fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL));
} }
*/ */
#endif #endif

View File

@ -17,8 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "n2n_transforms.h"
#include "random_numbers.h"
#ifdef N2N_HAVE_AES #ifdef N2N_HAVE_AES

View File

@ -17,8 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "n2n_transforms.h"
#include "random_numbers.h"
#ifdef HAVE_OPENSSL_1_1 #ifdef HAVE_OPENSSL_1_1

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -17,9 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "n2n_transforms.h"
#include "speck.h"
#include "random_numbers.h"
#define N2N_SPECK_TRANSFORM_VERSION 1 /* version of the transform encoding */ #define N2N_SPECK_TRANSFORM_VERSION 1 /* version of the transform encoding */
#define N2N_SPECK_IVEC_SIZE 16 #define N2N_SPECK_IVEC_SIZE 16
@ -175,13 +172,10 @@ static int setup_speck_key(transop_speck_t *priv, const uint8_t *key, ssize_t ke
/* Clear out any old possibly longer key matter. */ /* Clear out any old possibly longer key matter. */
memset(&(priv->ctx), 0, sizeof(speck_context_t) ); memset(&(priv->ctx), 0, sizeof(speck_context_t) );
/* TODO: The input key always gets hashed to make a more unpredictable and more complete use of the key space */ /* the input key always gets hashed to make a more unpredictable and more complete use of the key space */
// REVISIT: Hash the key to keymat (formerly used: SHA) pearson_hash_256 (key_mat_buf, key, key_size);
// SHA256(key, key_size, key_mat_buf)
// memcpy (priv->key, key_mat_buf, SHA256_DIGEST_LENGTH); /* expand the key material to the context (= round keys) */
// ADD: Pearson Hashing
// FOR NOW: USE KEY ITSELF
memcpy (key_mat_buf, key, ((key_size>32)?32:key_size) );
speck_expand_key (key_mat_buf, &(priv->ctx)); speck_expand_key (key_mat_buf, &(priv->ctx));
traceEvent(TRACE_DEBUG, "Speck key setup completed\n"); traceEvent(TRACE_DEBUG, "Speck key setup completed\n");

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,13 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "n2n_transforms.h"
#include "twofish.h"
#include "random_numbers.h"
#ifndef _MSC_VER
/* Not included in Visual Studio 2008 */
#include <strings.h> /* index() */
#endif
#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */ #define N2N_TWOFISH_NUM_SA 32 /* space for SAa */

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,16 +16,9 @@
* *
*/ */
#include "n2n.h"
#ifdef __linux__ #ifdef __linux__
#include <net/if_arp.h> #include "n2n.h"
#include <net/if.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "random_numbers.h"
/* ********************************** */ /* ********************************** */

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -35,13 +35,7 @@
#ifndef __TWOFISH_LIBRARY_SOURCE__ #ifndef __TWOFISH_LIBRARY_SOURCE__
#define __TWOFISH_LIBRARY_SOURCE__ #define __TWOFISH_LIBRARY_SOURCE__
#include <string.h> #include "n2n.h"
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>
#include "twofish.h"
#include "random_numbers.h"
/* Fixed 8x8 permutation S-boxes */ /* Fixed 8x8 permutation S-boxes */
static const uint8_t TwoFish_P[2][256] = static const uint8_t TwoFish_P[2][256] =

View File

@ -1,5 +1,5 @@
/** /**
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -16,8 +16,8 @@ endif
LIBS_EDGE_OPT=@N2N_LIBS@ LIBS_EDGE_OPT=@N2N_LIBS@
LIBS_EDGE+=$(LIBS_EDGE_OPT) LIBS_EDGE+=$(LIBS_EDGE_OPT)
HEADERS=../n2n_wire.h ../n2n.h ../twofish.h ../n2n_transforms.h HEADERS=$(wildcard include/*.h)
CFLAGS+=-I.. @CFLAGS@ CFLAGS+=-I../include @CFLAGS@
LDFLAGS+=-L.. LDFLAGS+=-L..
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN)
LDFLAGS=@LDFLAGS@ LDFLAGS=@LDFLAGS@
@ -40,7 +40,7 @@ n2n-decode: n2n_decode.c $(N2N_LIB) $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
clean: clean:
rm -rf $(TOOLS) $(N2N_LIB) *.o *.dSYM *~ rm -rf $(TOOLS) *.o *.dSYM *~
install: $(TOOLS) install: $(TOOLS)
$(INSTALL_PROG) $(TOOLS) $(SBINDIR)/ $(INSTALL_PROG) $(TOOLS) $(SBINDIR)/

View File

@ -1,5 +1,5 @@
/* /*
* (C) 2007-18 - ntop.org and contributors * (C) 2007-20 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,37 +16,26 @@
* *
*/ */
#include "n2n_wire.h"
#include "n2n_transforms.h"
#include "n2n.h" #include "n2n.h"
#ifdef __GNUC__
#include <sys/time.h>
#endif
#include <time.h>
#include <string.h>
#include <stdio.h>
#if defined(WIN32) && !defined(__GNUC__) #if defined(WIN32) && !defined(__GNUC__)
#include <windows.h>
static int gettimeofday(struct timeval *tp, void *tzp) static int gettimeofday(struct timeval *tp, void *tzp)
{ {
time_t clock; time_t clock;
struct tm tm; struct tm tm;
SYSTEMTIME wtm; SYSTEMTIME wtm;
GetLocalTime(&wtm); GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900; tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1; tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay; tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour; tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute; tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond; tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1; tm.tm_isdst = -1;
clock = mktime(&tm); clock = mktime(&tm);
tp->tv_sec = clock; tp->tv_sec = clock;
tp->tv_usec = wtm.wMilliseconds * 1000; tp->tv_usec = wtm.wMilliseconds * 1000;
return (0); return (0);
} }
#endif #endif
@ -75,7 +64,7 @@ static int perform_decryption = 0;
static void usage() { static void usage() {
fprintf(stderr, "Usage: benchmark [-d]\n" fprintf(stderr, "Usage: benchmark [-d]\n"
" -d\t\tEnable decryption. Default: only encryption is performed\n"); " -d\t\tEnable decryption. Default: only encryption is performed\n");
exit(1); exit(1);
} }
@ -162,7 +151,7 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2
size_t num_packets = 0; size_t num_packets = 0;
printf("Run %s[%s] for %us (%u bytes): ", perform_decryption ? "enc/dec" : "enc", printf("Run %s[%s] for %us (%u bytes): ", perform_decryption ? "enc/dec" : "enc",
op_name, target_sec, (unsigned int)sizeof(PKT_CONTENT)); op_name, target_sec, (unsigned int)sizeof(PKT_CONTENT));
fflush(stdout); fflush(stdout);
memset(mac_buf, 0, sizeof(mac_buf)); memset(mac_buf, 0, sizeof(mac_buf));
@ -172,8 +161,8 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name); nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name);
nw += op_fn->fwd(op_fn, nw += op_fn->fwd(op_fn,
pktbuf+nw, N2N_PKT_BUF_SIZE-nw, pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf); PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf);
idx=0; idx=0;
rem=nw; rem=nw;
@ -198,7 +187,7 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2
float mpps = num_packets / (tdiff / 1e6) / 1e6; float mpps = num_packets / (tdiff / 1e6) / 1e6;
printf("\t%12u packets\t%8.1f Kpps\t%8.1f MB/s\n", printf("\t%12u packets\t%8.1f Kpps\t%8.1f MB/s\n",
(unsigned int)num_packets, mpps * 1e3, mpps * sizeof(PKT_CONTENT)); (unsigned int)num_packets, mpps * 1e3, mpps * sizeof(PKT_CONTENT));
} }
static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ) static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c )