mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Merge remote-tracking branch 'origin/dev' into hin2n_android
This commit is contained in:
commit
0b4d36f7bd
|
@ -61,7 +61,12 @@ add_library(n2n n2n.c
|
|||
transform_null.c
|
||||
transform_tf.c
|
||||
transform_aes.c
|
||||
transform_cc20.c
|
||||
transform_speck.c
|
||||
speck.c
|
||||
random_numbers.c
|
||||
pearson.c
|
||||
header_encryption.c
|
||||
tuntap_freebsd.c
|
||||
tuntap_netbsd.c
|
||||
tuntap_linux.c
|
||||
|
|
25
Makefile.in
25
Makefile.in
|
@ -5,10 +5,7 @@ GIT_COMMITS=@GIT_COMMITS@
|
|||
|
||||
########
|
||||
|
||||
CC?=gcc
|
||||
DEBUG?=-g3
|
||||
OPTIMIZATION?=-O3 #-march=native
|
||||
WARN?=-Wall
|
||||
CC=@CC@
|
||||
|
||||
#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
|
||||
#(thanks to Robert Gibbon)
|
||||
|
@ -16,7 +13,7 @@ PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finlin
|
|||
|
||||
N2N_OBJS_OPT=
|
||||
LIBS_EDGE_OPT=@N2N_LIBS@
|
||||
CFLAGS=@CFLAGS@
|
||||
CFLAGS=@CFLAGS@ -I ./include
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
OPENSSL_CFLAGS=$(shell pkg-config openssl; echo $$?)
|
||||
|
@ -48,11 +45,9 @@ MAN7DIR=$(MANDIR)/man7
|
|||
MAN8DIR=$(MANDIR)/man8
|
||||
|
||||
N2N_LIB=libn2n.a
|
||||
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o speck.o \
|
||||
edge_utils.o sn_utils.o \
|
||||
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
|
||||
N2N_OBJS=$(patsubst src/%.c, src/%.o, $(wildcard src/*.c))
|
||||
N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile $(N2N_LIB)
|
||||
|
||||
LIBS_EDGE+=$(LIBS_EDGE_OPT)
|
||||
LIBS_SN=
|
||||
|
||||
|
@ -76,19 +71,19 @@ all: $(APPS) $(DOCS) tools
|
|||
tools: $(N2N_LIB)
|
||||
$(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 $@
|
||||
|
||||
supernode: sn.c $(N2N_LIB) n2n.h Makefile
|
||||
supernode: src/sn.c $(N2N_LIB) $(N2N_DEPS)
|
||||
$(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 $@
|
||||
|
||||
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 $@
|
||||
|
||||
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 $@
|
||||
|
||||
%.gz : %
|
||||
|
|
19
README.md
19
README.md
|
@ -77,6 +77,10 @@ make
|
|||
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 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.
|
||||
|
||||
**IMPORTANT** Encryption is only applied to the packet payload. Some metadata like the virtual MAC address
|
||||
of the edge nodes, their IP address and the community are sent in cleartext.
|
||||
Different encryption schemes are applied to the packet payload and to the header which
|
||||
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
|
||||
two edge nodes, but it will know that edge A is talking with edge B.
|
||||
|
||||
Recently AES encryption support has been implemented, which increases both security and performance,
|
||||
so it is recommended to enable it on all the edge nodes 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`.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
@ -15,6 +15,7 @@ fi
|
|||
|
||||
N2N_LIBS=
|
||||
|
||||
AC_PROG_CC
|
||||
AC_CHECK_LIB([zstd], [ZSTD_compress])
|
||||
|
||||
if test "x$ac_cv_lib_zstd_ZSTD_compress" != xyes; then
|
||||
|
@ -92,6 +93,7 @@ fi
|
|||
|
||||
DATE=`date +"%Y-%m-%d"`
|
||||
|
||||
AC_SUBST(CC)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(N2N_MAJOR)
|
||||
|
@ -104,7 +106,7 @@ AC_SUBST(GIT_RELEASE)
|
|||
AC_SUBST(N2N_DEFINES)
|
||||
AC_SUBST(N2N_LIBS)
|
||||
AC_SUBST(ADDITIONAL_TOOLS)
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_HEADERS(include/config.h)
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
AC_CONFIG_FILES(tools/Makefile)
|
||||
|
||||
|
|
34
include/edge_utils_win32.h
Normal file
34
include/edge_utils_win32.h
Normal 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
|
||||
|
27
include/header_encryption.h
Normal file
27
include/header_encryption.h
Normal 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);
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -64,6 +64,8 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
|
@ -74,6 +76,16 @@
|
|||
|
||||
#ifdef __linux__
|
||||
#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__ */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
@ -83,7 +95,12 @@
|
|||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if defined (__RDRND__) || defined (__RDSEED__)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#define ETH_ADDR_LEN 6
|
||||
|
||||
struct ether_hdr
|
||||
{
|
||||
uint8_t dhost[ETH_ADDR_LEN];
|
||||
|
@ -93,10 +110,17 @@ struct ether_hdr
|
|||
|
||||
typedef struct ether_hdr ether_hdr_t;
|
||||
|
||||
#ifdef HAVE_LIBZSTD
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
#undef N2N_HAVE_DAEMON
|
||||
#undef N2N_HAVE_SETUID
|
||||
#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__ */
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
@ -105,32 +129,41 @@ typedef struct ether_hdr ether_hdr_t;
|
|||
#include <signal.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef N2N_HAVE_AES
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
#endif
|
||||
|
||||
#include "minilzo.h"
|
||||
#include "n2n_define.h"
|
||||
|
||||
#define closesocket(a) close(a)
|
||||
#endif /* #ifndef WIN32 */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "uthash.h"
|
||||
#include "lzoconf.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32/wintap.h"
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#endif /* #ifdef WIN32 */
|
||||
|
||||
#include "n2n_wire.h"
|
||||
#include "n2n_transforms.h"
|
||||
#include "random_numbers.h"
|
||||
#include "pearson.h"
|
||||
#include "portable_endian.h"
|
||||
#include "speck.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define N2N_IFNAMSIZ 64
|
||||
|
@ -151,39 +184,6 @@ typedef struct tuntap_dev {
|
|||
#define SOCKET int
|
||||
#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. */
|
||||
/** NOTE: see doc/MTU.md for an explanation on the 1400 value */
|
||||
//#define MTU_ASSERT_VALUE 1400
|
||||
|
@ -206,17 +206,7 @@ struct peer_info {
|
|||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
|
||||
typedef struct speck_context_t he_context_t;
|
||||
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
|
||||
|
||||
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_route_t *routes; /**< Networks to route through n2n */
|
||||
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. */
|
||||
uint16_t compression; /**< Compress outgoing data packets before encryption */
|
||||
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. */
|
||||
} 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. */
|
||||
sn_stats_t stats;
|
||||
|
@ -271,16 +273,11 @@ typedef struct sn_stats
|
|||
struct sn_community *communities;
|
||||
} 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__
|
||||
#include <android/log.h>
|
||||
#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 */
|
||||
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);
|
94
include/n2n_define.h
Normal file
94
include/n2n_define.h
Normal 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
|
||||
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
21
include/pearson.h
Normal file
21
include/pearson.h
Normal 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
226
include/portable_endian.h
Normal 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
38
include/random_numbers.h
Normal 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 ();
|
|
@ -2,11 +2,11 @@
|
|||
// 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/
|
||||
|
||||
#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 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_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
|
|
@ -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 ();
|
784
sn_utils.c
784
sn_utils.c
|
@ -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(®, &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, ®);
|
||||
|
||||
/* 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(®, &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;
|
||||
}
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,12 +17,6 @@
|
|||
*/
|
||||
|
||||
#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_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/
|
||||
|
@ -160,7 +154,7 @@ static void help() {
|
|||
#ifndef __APPLE__
|
||||
"[-D] "
|
||||
#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)
|
||||
printf("-d <tun device> | tun device name\n");
|
||||
|
@ -190,20 +184,21 @@ static void help() {
|
|||
#endif
|
||||
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("-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
|
||||
printf("-A3 or -A (deprecated) | Use AES-CBC for payload encryption. Requires a key.\n");
|
||||
"-A3 or -A (deprecated) = AES-CBC, "
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_1_1
|
||||
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
|
||||
"-A4 = ChaCha20, "
|
||||
#endif
|
||||
// COMING SOON, not yet implemented in setPayloadEncryption(...)
|
||||
// printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
|
||||
printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n");
|
||||
"-A5 = Speck-CTR.\n");
|
||||
printf("-H | Enable full header encryption. Requires supernode with fixed community.\n");
|
||||
printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x"
|
||||
#ifdef N2N_HAVE_ZSTD
|
||||
printf("-z2 | Enable zstd compression for outgoing data packets\n");
|
||||
", -z2 = zstd"
|
||||
#endif
|
||||
printf(" | (default=compression disabled)\n");
|
||||
" (default=disabled).\n");
|
||||
printf("-E | Accept multicast MAC addresses (default=drop).\n");
|
||||
printf("-S | Do not connect P2P. Always use the supernode.\n");
|
||||
#ifdef __linux__
|
||||
|
@ -283,6 +278,11 @@ static void setPayloadEncryption( n2n_edge_conf_t *conf, int cipher) {
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
case 5:
|
||||
{
|
||||
conf->transop_id = N2N_TRANSFORM_ID_SPECK;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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':
|
||||
{
|
||||
int compression;
|
||||
|
@ -553,7 +561,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c
|
|||
u_char c;
|
||||
|
||||
while((c = getopt_long(argc, argv,
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::"
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::H"
|
||||
#ifdef __linux__
|
||||
"T:n:"
|
||||
#endif
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,45 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "lzoconf.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
|
||||
#include "header_encryption.h"
|
||||
|
||||
/* 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) ]
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
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;
|
||||
}
|
||||
|
||||
//edge_init_success:
|
||||
//edge_init_success:
|
||||
*rv = 0;
|
||||
return(eee);
|
||||
|
||||
edge_init_error:
|
||||
edge_init_error:
|
||||
if(eee)
|
||||
free(eee);
|
||||
*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
|
||||
* 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 */
|
||||
#ifndef WIN32
|
||||
} 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",
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -810,6 +781,9 @@ static void send_query_peer( n2n_edge_t * eee,
|
|||
|
||||
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) );
|
||||
}
|
||||
|
||||
|
@ -853,6 +827,9 @@ static void send_register(n2n_edge_t * eee,
|
|||
traceEvent(TRACE_INFO, "Send REGISTER to %s",
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -892,6 +869,8 @@ static void send_register_ack(n2n_edge_t * eee,
|
|||
traceEvent(TRACE_INFO, "send REGISTER_ACK %s",
|
||||
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);
|
||||
}
|
||||
|
@ -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. */
|
||||
++(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. */
|
||||
eee->sn_idx=0;
|
||||
}
|
||||
|
@ -1064,7 +1043,7 @@ static int handle_PACKET(n2n_edge_t * eee,
|
|||
deflated_len = N2N_PKT_BUF_SIZE;
|
||||
deflation_buffer = malloc (deflated_len);
|
||||
deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size);
|
||||
if (ZSTD_isError(deflated_len)) {
|
||||
if(ZSTD_isError(deflated_len)) {
|
||||
traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.",
|
||||
ZSTD_getErrorName(deflated_len));
|
||||
free (deflation_buffer);
|
||||
|
@ -1078,7 +1057,7 @@ static int handle_PACKET(n2n_edge_t * eee,
|
|||
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",
|
||||
compression_str(rx_compression_id), eth_size, (int)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);
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
pkt.compression = N2N_COMPRESSION_ID_NONE;
|
||||
|
||||
if (eee->conf.compression) {
|
||||
if(eee->conf.compression) {
|
||||
uint8_t * compression_buffer;
|
||||
int32_t compression_len;
|
||||
|
||||
switch (eee->conf.compression) {
|
||||
case N2N_COMPRESSION_ID_LZO:
|
||||
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 (compression_len < len) {
|
||||
if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) {
|
||||
if(compression_len < len) {
|
||||
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_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower)
|
||||
compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ;
|
||||
if (!ZSTD_isError(compression_len)) {
|
||||
if (compression_len < len) {
|
||||
if(!ZSTD_isError(compression_len)) {
|
||||
if(compression_len < len) {
|
||||
pkt.compression = N2N_COMPRESSION_ID_ZSTD;
|
||||
}
|
||||
} else {
|
||||
|
@ -1500,7 +1479,7 @@ static void send_packet2net(n2n_edge_t * eee,
|
|||
break;
|
||||
}
|
||||
|
||||
if (pkt.compression) {
|
||||
if(pkt.compression) {
|
||||
traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n",
|
||||
compression_str(pkt.compression), len, compression_len);
|
||||
|
||||
|
@ -1519,6 +1498,9 @@ static void send_packet2net(n2n_edge_t * eee,
|
|||
idx=0;
|
||||
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,
|
||||
pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
|
||||
tap_pkt, len, pkt.dstMac);
|
||||
|
@ -1552,13 +1534,11 @@ static void readFromTAPSocket(n2n_edge_t * eee) {
|
|||
ssize_t len;
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
if (uip_arp_len != 0) {
|
||||
if(uip_arp_len != 0) {
|
||||
len = uip_arp_len;
|
||||
memcpy(eth_pkt, uip_arp_buf, MIN(uip_arp_len, N2N_PKT_BUF_SIZE));
|
||||
traceEvent(TRACE_DEBUG, "ARP reply packet to send");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#endif /* #ifdef __ANDROID_NDK__ */
|
||||
len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE );
|
||||
#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. */
|
||||
static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
||||
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",
|
||||
(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); */
|
||||
|
||||
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);
|
||||
if (scan) {
|
||||
if(scan) {
|
||||
scan->sock = pi.sock;
|
||||
traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s",
|
||||
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);
|
||||
return;
|
||||
} /* 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");
|
||||
else
|
||||
traceEvent(TRACE_INFO, "Ignoring packet with unknown community");
|
||||
|
@ -2030,7 +1982,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
|||
#endif
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
if (uip_arp_len != 0) {
|
||||
if(uip_arp_len != 0) {
|
||||
readFromTAPSocket(eee);
|
||||
uip_arp_len = 0;
|
||||
}
|
||||
|
@ -2072,7 +2024,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
|||
}
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
if ((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) {
|
||||
if((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) {
|
||||
uip_arp_timer();
|
||||
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)));
|
||||
rv = 0;
|
||||
|
||||
out:
|
||||
out:
|
||||
close(nl_sock);
|
||||
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* over the default gateway (0.0.0.0/0). This leaves the default
|
||||
* gateway unchanged so that after n2n is stopped the cleanup is
|
||||
* easier.
|
||||
* of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus
|
||||
* covering the whole IPv4 range. Such routes in linux take precedence
|
||||
* over the default gateway (0.0.0.0/0) since are more specific.
|
||||
* 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_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.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)
|
||||
return(-1);
|
||||
} else {
|
||||
|
@ -2514,6 +2476,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
|||
conf->local_port = 0 /* any port */;
|
||||
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
||||
conf->transop_id = N2N_TRANSFORM_ID_NULL;
|
||||
conf->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
conf->compression = N2N_COMPRESSION_ID_NONE;
|
||||
conf->drop_multicast = 1;
|
||||
conf->allow_p2p = 1;
|
||||
|
@ -2588,7 +2551,7 @@ int quick_edge_init(char *device_name, char *community_name,
|
|||
edge_term(eee);
|
||||
edge_term_conf(&conf);
|
||||
|
||||
quick_edge_init_end:
|
||||
quick_edge_init_end:
|
||||
tuntap_close(&tuntap);
|
||||
return(rv);
|
||||
}
|
49
src/edge_utils_win32.c
Normal file
49
src/edge_utils_win32.c
Normal 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
|
||||
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "random_numbers.h"
|
||||
|
||||
/*
|
||||
This tool demonstrates how to easily embed
|
93
src/header_encryption.c
Normal file
93
src/header_encryption.c
Normal 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);
|
||||
}
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
221
src/pearson.c
Normal file
221
src/pearson.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
namely XORSHIFT128+ to use instead of C's rand(). Its performance is
|
||||
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
|
||||
arbitrary defaults (in this case: taken from splitmix64) */
|
||||
static struct rn_generator_state_t rn_current_state = {
|
232
sn.c → src/sn.c
232
sn.c → src/sn.c
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,6 +19,7 @@
|
|||
/* Supernode for n2n-2.x */
|
||||
|
||||
#include "n2n.h"
|
||||
#include "header_encryption.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <signal.h>
|
||||
|
@ -32,12 +33,14 @@
|
|||
#define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out)
|
||||
|
||||
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 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,
|
||||
|
@ -80,6 +83,8 @@ static void deinit_sn(n2n_sn_t * sss)
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -185,24 +190,17 @@ static ssize_t sendto_sock(n2n_sn_t * sss,
|
|||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
HASH_FIND_PEER(comm->edges, dstMac, scan);
|
||||
|
||||
if(NULL != scan)
|
||||
{
|
||||
|
@ -245,51 +243,44 @@ static int try_forward(n2n_sn_t * sss,
|
|||
* 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;
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -389,6 +380,8 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
|
|||
|
||||
HASH_ITER(hh, sss->communities, s, tmp) {
|
||||
HASH_DEL(sss->communities, s);
|
||||
if (NULL != s->header_encryption_ctx)
|
||||
free (s->header_encryption_ctx);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
@ -412,7 +405,12 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
|
|||
if(s != NULL) {
|
||||
strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1);
|
||||
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);
|
||||
|
||||
num_communities++;
|
||||
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
|
||||
(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,
|
||||
const struct sockaddr_in * sender_sock,
|
||||
const uint8_t * udp_buf,
|
||||
uint8_t * udp_buf,
|
||||
size_t udp_size,
|
||||
time_t now)
|
||||
{
|
||||
|
@ -448,11 +446,70 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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
|
||||
|
@ -491,8 +548,12 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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 */
|
||||
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);
|
||||
|
@ -520,6 +581,9 @@ static int process_udp(n2n_sn_t * sss,
|
|||
/* 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 {
|
||||
|
@ -530,13 +594,16 @@ static int process_udp(n2n_sn_t * sss,
|
|||
|
||||
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, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
else
|
||||
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
break;
|
||||
}
|
||||
case MSG_TYPE_REGISTER:
|
||||
|
@ -548,7 +615,12 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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 */
|
||||
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(®, &cmn, udp_buf, &rem, &idx);
|
||||
|
@ -586,7 +658,10 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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
|
||||
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
|
||||
break;
|
||||
|
@ -601,15 +676,12 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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(®, &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
|
||||
|
@ -622,6 +694,10 @@ static int process_udp(n2n_sn_t * sss,
|
|||
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);
|
||||
|
@ -653,6 +729,9 @@ static int process_udp(n2n_sn_t * sss,
|
|||
|
||||
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));
|
||||
|
||||
|
@ -663,13 +742,18 @@ static int process_udp(n2n_sn_t * sss,
|
|||
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
|
||||
(char*)cmn.community);
|
||||
break;
|
||||
} case MSG_TYPE_QUERY_PEER: {
|
||||
}
|
||||
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;
|
||||
|
||||
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 );
|
||||
|
||||
|
@ -677,36 +761,35 @@ static int process_udp(n2n_sn_t * sss,
|
|||
macaddr_str( mac_buf, query.srcMac ),
|
||||
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) {
|
||||
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) );
|
||||
|
||||
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;
|
||||
|
||||
pi.aflags = 0;
|
||||
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
|
||||
pi.sock = scan->sock;
|
||||
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
|
||||
|
||||
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) );
|
||||
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 ) );
|
||||
}
|
||||
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;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Not a known message type */
|
||||
|
@ -1113,6 +1196,9 @@ static int run_loop(n2n_sn_t * sss) {
|
|||
|
||||
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);
|
||||
}
|
839
src/sn_utils.c
Normal file
839
src/sn_utils.c
Normal 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(®, &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, ®);
|
||||
|
||||
/* 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(®, &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;
|
||||
}
|
|
@ -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)
|
||||
// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "portable_endian.h"
|
||||
|
||||
#ifndef __ANDROID_NDK__
|
||||
|
||||
#include "speck.h"
|
||||
|
||||
|
||||
#if defined (__AVX2__) // AVX support ----------------------------------------------------
|
||||
|
||||
|
||||
|
@ -568,9 +566,9 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
|
|||
#else // plain C ----------------------------------------------------------------
|
||||
|
||||
|
||||
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
|
||||
#define ROL64(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 ROR(x,r) (((x)>>(r))|((x)<<(64-(r))))
|
||||
#define ROL(x,r) (((x)<<(r))|((x)>>(64-(r))))
|
||||
#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) {
|
||||
|
@ -645,6 +643,85 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
|
|||
#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 () {
|
||||
|
||||
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,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
|
||||
|
||||
|
||||
uint8_t iv[16] = { 0x70, 0x6f, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x20,
|
||||
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 };
|
||||
|
||||
// expected outcome (according to pp. 35 & 36 of Implementation Guide)
|
||||
uint8_t ct[16] = { 0x43, 0x8f, 0x18, 0x9c, 0x8d, 0xb4, 0xee, 0x4e,
|
||||
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_expand_key (key, &ctx);
|
||||
|
@ -670,24 +754,37 @@ int speck_test () {
|
|||
#else
|
||||
speck_ctr (pt, pt, 16, iv, &ctx);
|
||||
#endif
|
||||
|
||||
u64 i;
|
||||
// fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
|
||||
// fprintf (stderr, "rk33: %016llx\n", ctx.key[33]);
|
||||
// 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, "rk00: %016llx\n", ctx.key[0]);
|
||||
fprintf (stderr, "rk33: %016llx\n", ctx.key[33]);
|
||||
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");
|
||||
|
||||
int ret = 1;
|
||||
for (i=0; i < 16; i++)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -17,8 +17,6 @@
|
|||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
#include "random_numbers.h"
|
||||
|
||||
#ifdef N2N_HAVE_AES
|
||||
|
|
@ -17,8 +17,6 @@
|
|||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
#include "random_numbers.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_1_1
|
||||
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -17,9 +17,6 @@
|
|||
*/
|
||||
|
||||
#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_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. */
|
||||
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 */
|
||||
// REVISIT: Hash the key to keymat (formerly used: SHA)
|
||||
// SHA256(key, key_size, key_mat_buf)
|
||||
// memcpy (priv->key, key_mat_buf, SHA256_DIGEST_LENGTH);
|
||||
// ADD: Pearson Hashing
|
||||
// FOR NOW: USE KEY ITSELF
|
||||
memcpy (key_mat_buf, key, ((key_size>32)?32:key_size) );
|
||||
/* the input key always gets hashed to make a more unpredictable and more complete use of the key space */
|
||||
pearson_hash_256 (key_mat_buf, key, key_size);
|
||||
|
||||
/* expand the key material to the context (= round keys) */
|
||||
speck_expand_key (key_mat_buf, &(priv->ctx));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Speck key setup completed\n");
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,13 +17,6 @@
|
|||
*/
|
||||
|
||||
#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 */
|
||||
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,16 +16,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "random_numbers.h"
|
||||
#include "n2n.h"
|
||||
|
||||
/* ********************************** */
|
||||
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -35,13 +35,7 @@
|
|||
#ifndef __TWOFISH_LIBRARY_SOURCE__
|
||||
#define __TWOFISH_LIBRARY_SOURCE__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include "twofish.h"
|
||||
#include "random_numbers.h"
|
||||
#include "n2n.h"
|
||||
|
||||
/* Fixed 8x8 permutation S-boxes */
|
||||
static const uint8_t TwoFish_P[2][256] =
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
|
@ -16,8 +16,8 @@ endif
|
|||
|
||||
LIBS_EDGE_OPT=@N2N_LIBS@
|
||||
LIBS_EDGE+=$(LIBS_EDGE_OPT)
|
||||
HEADERS=../n2n_wire.h ../n2n.h ../twofish.h ../n2n_transforms.h
|
||||
CFLAGS+=-I.. @CFLAGS@
|
||||
HEADERS=$(wildcard include/*.h)
|
||||
CFLAGS+=-I../include @CFLAGS@
|
||||
LDFLAGS+=-L..
|
||||
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN)
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
@ -40,7 +40,7 @@ n2n-decode: n2n_decode.c $(N2N_LIB) $(HEADERS)
|
|||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(TOOLS) $(N2N_LIB) *.o *.dSYM *~
|
||||
rm -rf $(TOOLS) *.o *.dSYM *~
|
||||
|
||||
install: $(TOOLS)
|
||||
$(INSTALL_PROG) $(TOOLS) $(SBINDIR)/
|
||||
|
|
|
@ -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
|
||||
* 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"
|
||||
#ifdef __GNUC__
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#if defined(WIN32) && !defined(__GNUC__)
|
||||
#include <windows.h>
|
||||
|
||||
static int gettimeofday(struct timeval *tp, void *tzp)
|
||||
{
|
||||
time_t clock;
|
||||
struct tm tm;
|
||||
SYSTEMTIME wtm;
|
||||
GetLocalTime(&wtm);
|
||||
tm.tm_year = wtm.wYear - 1900;
|
||||
tm.tm_mon = wtm.wMonth - 1;
|
||||
tm.tm_mday = wtm.wDay;
|
||||
tm.tm_hour = wtm.wHour;
|
||||
tm.tm_min = wtm.wMinute;
|
||||
tm.tm_sec = wtm.wSecond;
|
||||
tm.tm_isdst = -1;
|
||||
clock = mktime(&tm);
|
||||
tp->tv_sec = clock;
|
||||
tp->tv_usec = wtm.wMilliseconds * 1000;
|
||||
return (0);
|
||||
time_t clock;
|
||||
struct tm tm;
|
||||
SYSTEMTIME wtm;
|
||||
GetLocalTime(&wtm);
|
||||
tm.tm_year = wtm.wYear - 1900;
|
||||
tm.tm_mon = wtm.wMonth - 1;
|
||||
tm.tm_mday = wtm.wDay;
|
||||
tm.tm_hour = wtm.wHour;
|
||||
tm.tm_min = wtm.wMinute;
|
||||
tm.tm_sec = wtm.wSecond;
|
||||
tm.tm_isdst = -1;
|
||||
clock = mktime(&tm);
|
||||
tp->tv_sec = clock;
|
||||
tp->tv_usec = wtm.wMilliseconds * 1000;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -75,7 +64,7 @@ static int perform_decryption = 0;
|
|||
|
||||
static void usage() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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);
|
||||
|
||||
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 += op_fn->fwd(op_fn,
|
||||
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
|
||||
PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf);
|
||||
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
|
||||
PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf);
|
||||
|
||||
idx=0;
|
||||
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;
|
||||
|
||||
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 )
|
||||
|
|
Loading…
Reference in New Issue
Block a user