mirror of
https://github.com/ntop/n2n.git
synced 2024-09-20 00:51:10 +02:00
Merge branch 'dev' into speck
This commit is contained in:
commit
78e72a2f9e
|
@ -92,6 +92,16 @@ target_link_libraries(example_edge_embed n2n)
|
||||||
add_executable(example_sn_embed example_sn_embed.c)
|
add_executable(example_sn_embed example_sn_embed.c)
|
||||||
target_link_libraries(example_sn_embed n2n)
|
target_link_libraries(example_sn_embed n2n)
|
||||||
|
|
||||||
|
if(NOT DEFINED WIN32)
|
||||||
|
# Linux Capabilities
|
||||||
|
find_library(CAP_LIB cap)
|
||||||
|
if(CAP_LIB)
|
||||||
|
target_link_libraries(edge cap)
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${CAP_LIB})
|
||||||
|
ADD_DEFINITIONS("-DHAVE_LIBCAP")
|
||||||
|
endif()
|
||||||
|
endif(NOT DEFINED WIN32)
|
||||||
|
|
||||||
install(TARGETS edge supernode
|
install(TARGETS edge supernode
|
||||||
RUNTIME DESTINATION sbin
|
RUNTIME DESTINATION sbin
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
|
|
|
@ -91,9 +91,6 @@ example_sn_embed: example_sn_embed.c $(N2N_LIB) n2n.h
|
||||||
example_edge_embed: example_edge_embed.c $(N2N_LIB) n2n.h
|
example_edge_embed: example_edge_embed.c $(N2N_LIB) n2n.h
|
||||||
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
|
$(CC) $(CFLAGS) $< $(LDFLAGS) $(N2N_LIB) $(LIBS_EDGE) -o $@
|
||||||
|
|
||||||
.c.o: n2n.h n2n_transforms.h n2n_wire.h twofish.h Makefile
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
%.gz : %
|
%.gz : %
|
||||||
gzip -c $< > $@
|
gzip -c $< > $@
|
||||||
|
|
||||||
|
|
29
README.md
29
README.md
|
@ -47,35 +47,22 @@ Now the supernode service should be up and running on port 1234. On your edge no
|
||||||
|
|
||||||
## Routing the traffic
|
## Routing the traffic
|
||||||
|
|
||||||
On linux, n2n provides a standard TAP interface, so routing works gracefully via the standard system utilities as follows.
|
Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. In this context, the `server` is the edge node which provides access to the remote network/internet, whereas the `client` is the connecting edge node.
|
||||||
|
|
||||||
In this example host1 is the edge router (with n2n IP 192.168.100.1), whereas host2 is the client.
|
In order to enable routing, the `server` must be configured as follows:
|
||||||
|
|
||||||
Here is how to configure host1:
|
|
||||||
|
|
||||||
1. Add the `-r` option to the edge options to enable routing
|
1. Add the `-r` option to the edge options to enable routing
|
||||||
2. Enable packet forwarding with `sudo sysctl -w net.ipv4.ip_forward=1`
|
2. Enable packet forwarding with `sudo sysctl -w net.ipv4.ip_forward=1`
|
||||||
3. Possibly configure iptables to `ACCEPT` the packets on the `FORWARD` chain.
|
3. Enable IP masquerading: `sudo iptables -t nat -A POSTROUTING -j MASQUERADE`
|
||||||
|
|
||||||
On host2, run the `edge` program as normal to join the host1 community.
|
On the client side, the easiest way to configure routing is via the `-n` option. For example:
|
||||||
|
|
||||||
In order to forward all the internet traffic via host2:
|
- In order to connect to the remote network `192.168.100.0/24`, use `-n 192.168.100.0/24:10.0.0.1`
|
||||||
|
- In order to tunnel all the internet traffic, use `-n 0.0.0.0/0:10.0.0.1`
|
||||||
|
|
||||||
```sh
|
10.0.0.1 is the IP address of the gateway to use to route the specified network. It should correspond to the IP address of the `server` within n2n. Multiple `-n` options can be specified.
|
||||||
# Determine the current gateway (e.g. 192.168.1.1)
|
|
||||||
$ ip route show default
|
|
||||||
|
|
||||||
# Add a route to reach the supernode via such gateway
|
As an alternative to the `-n` option, the `ip route` linux command can be manually used. See the [n2n_gateway.sh](doc/n2n_gateway.sh) script for an example. See also [Routing.md](doc/Routing.md) for other use cases and in depth explanation.
|
||||||
$ sudo ip route add supernode.ntop.org via 192.168.1.1
|
|
||||||
|
|
||||||
# Forward all the internet traffic via host1
|
|
||||||
$ sudo ip route del default
|
|
||||||
$ sudo ip route add default via 192.168.100.1
|
|
||||||
```
|
|
||||||
|
|
||||||
This process can be greatly simplified by using the [n2n_gateway.sh](doc/n2n_gateway.sh) script.
|
|
||||||
|
|
||||||
See [Routing.md](doc/Routing.md) for other use cases and in depth explanation.
|
|
||||||
|
|
||||||
## Manual Compilation
|
## Manual Compilation
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,12 @@ if test x$pcap_immediate_mode != x; then
|
||||||
AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [], [Have pcap_immediate_mode])
|
AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [], [Have pcap_immediate_mode])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_CHECK_LIB([cap], [cap_get_proc], cap=true)
|
||||||
|
if test x$cap != x; then
|
||||||
|
LDFLAGS="${LDFLAGS} -lcap"
|
||||||
|
AC_DEFINE([HAVE_LIBCAP],[1],[Support for linux capabilities])
|
||||||
|
fi
|
||||||
|
|
||||||
MACHINE=`uname -m`
|
MACHINE=`uname -m`
|
||||||
SYSTEM=`uname -s`
|
SYSTEM=`uname -s`
|
||||||
|
|
||||||
|
|
101
edge.c
101
edge.c
|
@ -37,6 +37,21 @@
|
||||||
|
|
||||||
/* ***************************************************** */
|
/* ***************************************************** */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCAP
|
||||||
|
|
||||||
|
#include <sys/capability.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
|
static cap_value_t cap_values[] = {
|
||||||
|
//CAP_NET_RAW, /* Use RAW and PACKET sockets */
|
||||||
|
CAP_NET_ADMIN /* Needed to performs routes cleanup at exit */
|
||||||
|
};
|
||||||
|
|
||||||
|
int num_cap = sizeof(cap_values)/sizeof(cap_value_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ***************************************************** */
|
||||||
|
|
||||||
typedef struct n2n_priv_config {
|
typedef struct n2n_priv_config {
|
||||||
char tuntap_dev_name[N2N_IFNAMSIZ];
|
char tuntap_dev_name[N2N_IFNAMSIZ];
|
||||||
char ip_mode[N2N_IF_MODE_SIZE];
|
char ip_mode[N2N_IF_MODE_SIZE];
|
||||||
|
@ -135,6 +150,7 @@ static void help() {
|
||||||
#endif /* #ifndef WIN32 */
|
#endif /* #ifndef WIN32 */
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
"[-T <tos>]"
|
"[-T <tos>]"
|
||||||
|
"[-n cidr:gateway] "
|
||||||
#endif
|
#endif
|
||||||
"[-m <MAC address>] "
|
"[-m <MAC address>] "
|
||||||
"-l <supernode host:port>\n"
|
"-l <supernode host:port>\n"
|
||||||
|
@ -181,10 +197,13 @@ static void help() {
|
||||||
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
|
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
|
||||||
printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
|
printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
|
||||||
#endif
|
#endif
|
||||||
|
printf("-z | Enable lzo1x compression for outgoing data packets\n");
|
||||||
|
printf(" | (default=disabled).\n");
|
||||||
printf("-E | Accept multicast MAC addresses (default=drop).\n");
|
printf("-E | Accept multicast MAC addresses (default=drop).\n");
|
||||||
printf("-S | Do not connect P2P. Always use the supernode.\n");
|
printf("-S | Do not connect P2P. Always use the supernode.\n");
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
printf("-T <tos> | TOS for packets (e.g. 0x48 for SSH like priority)\n");
|
printf("-T <tos> | TOS for packets (e.g. 0x48 for SSH like priority)\n");
|
||||||
|
printf("-n <cidr:gateway> | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n");
|
||||||
#endif
|
#endif
|
||||||
printf("-v | Make more verbose. Repeat as required.\n");
|
printf("-v | Make more verbose. Repeat as required.\n");
|
||||||
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
|
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
|
||||||
|
@ -340,6 +359,12 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'z':
|
||||||
|
{
|
||||||
|
conf->compression = N2N_COMPRESSION_ID_LZO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'l': /* supernode-list */
|
case 'l': /* supernode-list */
|
||||||
if(optargument) {
|
if(optargument) {
|
||||||
if(edge_conf_add_supernode(conf, optargument) != 0) {
|
if(edge_conf_add_supernode(conf, optargument) != 0) {
|
||||||
|
@ -388,6 +413,43 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
{
|
||||||
|
char cidr_net[64], gateway[64];
|
||||||
|
n2n_route_t route;
|
||||||
|
|
||||||
|
if(sscanf(optargument, "%63[^/]/%d:%63s", cidr_net, &route.net_bitlen, gateway) != 3) {
|
||||||
|
traceEvent(TRACE_WARNING, "Bad cidr/gateway format '%d'. See -h.", optargument);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
route.net_addr = inet_addr(cidr_net);
|
||||||
|
route.gateway = inet_addr(gateway);
|
||||||
|
|
||||||
|
if((route.net_bitlen < 0) || (route.net_bitlen > 32)) {
|
||||||
|
traceEvent(TRACE_WARNING, "Bad prefix '%d' in '%s'", route.net_bitlen, optargument);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(route.net_addr == INADDR_NONE) {
|
||||||
|
traceEvent(TRACE_WARNING, "Bad network '%s' in '%s'", cidr_net, optargument);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(route.net_addr == INADDR_NONE) {
|
||||||
|
traceEvent(TRACE_WARNING, "Bad gateway '%s' in '%s'", gateway, optargument);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_DEBUG, "Adding %s/%d via %s", cidr_net, route.net_bitlen, gateway);
|
||||||
|
|
||||||
|
conf->routes = realloc(conf->routes, sizeof(struct n2n_route) * (conf->num_routes + 1));
|
||||||
|
conf->routes[conf->num_routes] = route;
|
||||||
|
conf->num_routes++;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 's': /* Subnet Mask */
|
case 's': /* Subnet Mask */
|
||||||
|
@ -448,9 +510,11 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c
|
||||||
|
|
||||||
while((c = getopt_long(argc, argv,
|
while((c = getopt_long(argc, argv,
|
||||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z"
|
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z"
|
||||||
|
|
||||||
"A::"
|
"A::"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
"T:"
|
"T:n:"
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
long_options, NULL)) != '?') {
|
long_options, NULL)) != '?') {
|
||||||
|
@ -645,7 +709,7 @@ static void daemonize() {
|
||||||
|
|
||||||
static int keep_on_running;
|
static int keep_on_running;
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__) || defined(WIN32)
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
BOOL WINAPI term_handler(DWORD sig)
|
BOOL WINAPI term_handler(DWORD sig)
|
||||||
#else
|
#else
|
||||||
|
@ -667,7 +731,7 @@ static void term_handler(int sig)
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* defined(__linux__) || defined(WIN32) */
|
||||||
|
|
||||||
/* *************************************************** */
|
/* *************************************************** */
|
||||||
|
|
||||||
|
@ -681,6 +745,9 @@ int main(int argc, char* argv[]) {
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
struct passwd *pw = NULL;
|
struct passwd *pw = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBCAP
|
||||||
|
cap_t caps;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Defaults */
|
/* Defaults */
|
||||||
edge_init_conf_defaults(&conf);
|
edge_init_conf_defaults(&conf);
|
||||||
|
@ -775,6 +842,22 @@ int main(int argc, char* argv[]) {
|
||||||
#endif /* #ifndef WIN32 */
|
#endif /* #ifndef WIN32 */
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCAP
|
||||||
|
/* Before dropping the privileges, retain capabilities to regain them in future. */
|
||||||
|
caps = cap_get_proc();
|
||||||
|
|
||||||
|
cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET);
|
||||||
|
cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET);
|
||||||
|
|
||||||
|
if((cap_set_proc(caps) != 0) || (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0))
|
||||||
|
traceEvent(TRACE_WARNING, "Unable to retain permitted capabilities [%s]\n", strerror(errno));
|
||||||
|
#else
|
||||||
|
#ifndef __APPLE__
|
||||||
|
traceEvent(TRACE_WARNING, "n2n has not been compiled with libcap-dev. Some commands may fail.");
|
||||||
|
#endif
|
||||||
|
#endif /* HAVE_LIBCAP */
|
||||||
|
|
||||||
if((ec.userid != 0) || (ec.groupid != 0)) {
|
if((ec.userid != 0) || (ec.groupid != 0)) {
|
||||||
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
|
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
|
||||||
(signed int)ec.userid, (signed int)ec.groupid);
|
(signed int)ec.userid, (signed int)ec.groupid);
|
||||||
|
@ -804,8 +887,20 @@ int main(int argc, char* argv[]) {
|
||||||
rc = run_edge_loop(eee, &keep_on_running);
|
rc = run_edge_loop(eee, &keep_on_running);
|
||||||
print_edge_stats(eee);
|
print_edge_stats(eee);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCAP
|
||||||
|
/* Before completing the cleanup, regain the capabilities as some
|
||||||
|
* cleanup tasks require them (e.g. routes cleanup). */
|
||||||
|
cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET);
|
||||||
|
|
||||||
|
if(cap_set_proc(caps) != 0)
|
||||||
|
traceEvent(TRACE_WARNING, "Could not regain the capabilities [%s]\n", strerror(errno));
|
||||||
|
|
||||||
|
cap_free(caps);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
edge_term(eee);
|
edge_term(eee);
|
||||||
|
edge_term_conf(&conf);
|
||||||
tuntap_close(&tuntap);
|
tuntap_close(&tuntap);
|
||||||
|
|
||||||
if(conf.encrypt_key) free(conf.encrypt_key);
|
if(conf.encrypt_key) free(conf.encrypt_key);
|
||||||
|
|
437
edge_utils.c
437
edge_utils.c
|
@ -41,12 +41,21 @@
|
||||||
#define ARP_PERIOD_INTERVAL (10) /* sec */
|
#define ARP_PERIOD_INTERVAL (10) /* sec */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ETH_FRAMESIZE 14
|
#define ETH_FRAMESIZE 14
|
||||||
#define IP4_SRCOFFSET 12
|
#define IP4_SRCOFFSET 12
|
||||||
#define IP4_DSTOFFSET 16
|
#define IP4_DSTOFFSET 16
|
||||||
#define IP4_MIN_SIZE 20
|
#define IP4_MIN_SIZE 20
|
||||||
#define UDP_SIZE 8
|
#define UDP_SIZE 8
|
||||||
|
|
||||||
|
/* 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) ]
|
||||||
|
static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS);
|
||||||
|
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
|
||||||
static const char * supernode_ip(const n2n_edge_t * eee);
|
static const char * supernode_ip(const n2n_edge_t * eee);
|
||||||
|
@ -56,7 +65,9 @@ static void check_peer_registration_needed(n2n_edge_t * eee,
|
||||||
const n2n_mac_t mac,
|
const n2n_mac_t mac,
|
||||||
const n2n_sock_t * peer);
|
const n2n_sock_t * peer);
|
||||||
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos);
|
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos);
|
||||||
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
|
static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes);
|
||||||
|
static void edge_cleanup_routes(n2n_edge_t *eee);
|
||||||
|
static int supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
|
||||||
static void check_known_peer_sock_change(n2n_edge_t * eee,
|
static void check_known_peer_sock_change(n2n_edge_t * eee,
|
||||||
uint8_t from_supernode,
|
uint8_t from_supernode,
|
||||||
const n2n_mac_t mac,
|
const n2n_mac_t mac,
|
||||||
|
@ -105,6 +116,7 @@ struct n2n_edge {
|
||||||
tuntap_dev device; /**< All about the TUNTAP device */
|
tuntap_dev device; /**< All about the TUNTAP device */
|
||||||
n2n_trans_op_t transop; /**< The transop to use when encoding */
|
n2n_trans_op_t transop; /**< The transop to use when encoding */
|
||||||
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
|
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
|
||||||
|
n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */
|
||||||
|
|
||||||
/* Sockets */
|
/* Sockets */
|
||||||
n2n_sock_t supernode;
|
n2n_sock_t supernode;
|
||||||
|
@ -220,12 +232,10 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
|
||||||
eee->pending_peers = NULL;
|
eee->pending_peers = NULL;
|
||||||
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
if(lzo_init() != LZO_E_OK) {
|
if(lzo_init() != LZO_E_OK) {
|
||||||
traceEvent(TRACE_ERROR, "LZO compression error");
|
traceEvent(TRACE_ERROR, "LZO compression error");
|
||||||
goto edge_init_error;
|
goto edge_init_error;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
for(i=0; i<conf->sn_num; ++i)
|
for(i=0; i<conf->sn_num; ++i)
|
||||||
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
|
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
|
||||||
|
@ -265,7 +275,12 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
|
||||||
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
|
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
|
||||||
|
|
||||||
if(edge_init_sockets(eee, conf->local_port, conf->mgmt_port, conf->tos) < 0) {
|
if(edge_init_sockets(eee, conf->local_port, conf->mgmt_port, conf->tos) < 0) {
|
||||||
traceEvent(TRACE_ERROR, "Error: socket setup failed");
|
traceEvent(TRACE_ERROR, "socket setup failed");
|
||||||
|
goto edge_init_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(edge_init_routes(eee, conf->routes, conf->num_routes) < 0) {
|
||||||
|
traceEvent(TRACE_ERROR, "routes setup failed");
|
||||||
goto edge_init_error;
|
goto edge_init_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,16 +333,16 @@ static int is_valid_peer_sock(const n2n_sock_t *sock) {
|
||||||
* REVISIT: This is a really bad idea. The edge will block completely while the
|
* REVISIT: This is a really bad idea. The edge will block completely while the
|
||||||
* hostname resolution is performed. This could take 15 seconds.
|
* hostname resolution is performed. This could take 15 seconds.
|
||||||
*/
|
*/
|
||||||
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
static int supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
||||||
n2n_sn_name_t addr;
|
n2n_sn_name_t addr;
|
||||||
const char *supernode_host;
|
const char *supernode_host;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE);
|
memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE);
|
||||||
|
|
||||||
supernode_host = strtok(addr, ":");
|
supernode_host = strtok(addr, ":");
|
||||||
|
|
||||||
if(supernode_host)
|
if(supernode_host) {
|
||||||
{
|
|
||||||
in_addr_t sn_addr;
|
in_addr_t sn_addr;
|
||||||
char *supernode_port = strtok(NULL, ":");
|
char *supernode_port = strtok(NULL, ":");
|
||||||
const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL};
|
const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL};
|
||||||
|
@ -359,6 +374,7 @@ static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
||||||
{
|
{
|
||||||
/* Should only return IPv4 addresses due to aihints. */
|
/* Should only return IPv4 addresses due to aihints. */
|
||||||
traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host);
|
traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host);
|
||||||
|
rv = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */
|
freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */
|
||||||
|
@ -368,10 +384,15 @@ static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
||||||
sn_addr = inet_addr(supernode_host); /* uint32_t */
|
sn_addr = inet_addr(supernode_host); /* uint32_t */
|
||||||
memcpy(sn->addr.v4, &(sn_addr), IPV4_SIZE);
|
memcpy(sn->addr.v4, &(sn_addr), IPV4_SIZE);
|
||||||
sn->family=AF_INET;
|
sn->family=AF_INET;
|
||||||
|
rv = -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else
|
} else {
|
||||||
traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l <host:port>)");
|
traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l <host:port>)");
|
||||||
|
rv = -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
@ -955,6 +976,15 @@ static int handle_PACKET(n2n_edge_t * eee,
|
||||||
n2n_transform_t rx_transop_id;
|
n2n_transform_t rx_transop_id;
|
||||||
|
|
||||||
rx_transop_id = (n2n_transform_t)pkt->transform;
|
rx_transop_id = (n2n_transform_t)pkt->transform;
|
||||||
|
/* optional compression is encoded in uppermost bit of transform field.
|
||||||
|
* this is an intermediate solution to maintain compatibility until some
|
||||||
|
* upcoming major release (3.0?) brings up changes in packet structure anyway
|
||||||
|
* in the course of which a dedicated compression field could be spent.
|
||||||
|
* REVISIT then. */
|
||||||
|
uint16_t rx_compression_id;
|
||||||
|
|
||||||
|
rx_compression_id = (uint16_t)rx_transop_id >> (8*sizeof((uint16_t)rx_transop_id)-N2N_COMPRESSION_ID_BITLEN);
|
||||||
|
rx_transop_id &= (1 << (8*sizeof((uint16_t)rx_transop_id)-N2N_COMPRESSION_ID_BITLEN)) -1;
|
||||||
|
|
||||||
if(rx_transop_id == eee->conf.transop_id) {
|
if(rx_transop_id == eee->conf.transop_id) {
|
||||||
uint8_t is_multicast;
|
uint8_t is_multicast;
|
||||||
|
@ -964,6 +994,28 @@ static int handle_PACKET(n2n_edge_t * eee,
|
||||||
eth_payload, N2N_PKT_BUF_SIZE,
|
eth_payload, N2N_PKT_BUF_SIZE,
|
||||||
payload, psize, pkt->srcMac);
|
payload, psize, pkt->srcMac);
|
||||||
++(eee->transop.rx_cnt); /* stats */
|
++(eee->transop.rx_cnt); /* stats */
|
||||||
|
|
||||||
|
/* decompress if necessary */
|
||||||
|
uint8_t * deflation_buffer = 0;
|
||||||
|
uint32_t deflated_len;
|
||||||
|
switch (rx_compression_id) {
|
||||||
|
case N2N_COMPRESSION_ID_LZO:
|
||||||
|
deflation_buffer = malloc (N2N_PKT_BUF_SIZE);
|
||||||
|
lzo1x_decompress (eth_payload, eth_size, deflation_buffer, (lzo_uint*)&deflated_len, NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_compression_id) {
|
||||||
|
traceEvent (TRACE_DEBUG, "payload decompression [id: %u]: deflated %u bytes to %u bytes",
|
||||||
|
rx_compression_id, eth_size, (int)deflated_len);
|
||||||
|
memcpy(eth_payload ,deflation_buffer, deflated_len );
|
||||||
|
eth_size = deflated_len;
|
||||||
|
free (deflation_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size));
|
is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size));
|
||||||
|
|
||||||
if(eee->conf.drop_multicast && is_multicast) {
|
if(eee->conf.drop_multicast && is_multicast) {
|
||||||
|
@ -1321,6 +1373,41 @@ static void send_packet2net(n2n_edge_t * eee,
|
||||||
pkt.sock.family=0; /* do not encode sock */
|
pkt.sock.family=0; /* do not encode sock */
|
||||||
pkt.transform = tx_transop_idx;
|
pkt.transform = tx_transop_idx;
|
||||||
|
|
||||||
|
// compression needs to be tried before encode_PACKET is called for compression indication gets encoded there
|
||||||
|
pkt.compression = N2N_COMPRESSION_ID_NONE;
|
||||||
|
if (eee->conf.compression) {
|
||||||
|
uint8_t * compression_buffer;
|
||||||
|
uint32_t compression_len;
|
||||||
|
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) {
|
||||||
|
pkt.compression = N2N_COMPRESSION_ID_LZO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt.compression) {
|
||||||
|
traceEvent (TRACE_DEBUG, "payload compression [id: %u]: compressed %u bytes to %u bytes\n",
|
||||||
|
pkt.compression, len, compression_len);
|
||||||
|
|
||||||
|
memcpy (tap_pkt, compression_buffer, compression_len);
|
||||||
|
len = compression_len;
|
||||||
|
free (compression_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* optional compression is encoded in uppermost bits of transform field.
|
||||||
|
* this is an intermediate solution to maintain compatibility until some
|
||||||
|
* upcoming major release (3.0?) brings up changes in packet structure anyway
|
||||||
|
* in the course of which a dedicated compression field could be spent.
|
||||||
|
* REVISIT then. */
|
||||||
|
pkt.transform = pkt.transform | (pkt.compression << (8*sizeof(pkt.transform)-N2N_COMPRESSION_ID_BITLEN));
|
||||||
|
|
||||||
idx=0;
|
idx=0;
|
||||||
encode_PACKET(pktbuf, &idx, &cmn, &pkt);
|
encode_PACKET(pktbuf, &idx, &cmn, &pkt);
|
||||||
|
|
||||||
|
@ -1850,6 +1937,9 @@ void edge_term(n2n_edge_t * eee) {
|
||||||
clear_peer_list(&eee->known_peers);
|
clear_peer_list(&eee->known_peers);
|
||||||
|
|
||||||
eee->transop.deinit(&eee->transop);
|
eee->transop.deinit(&eee->transop);
|
||||||
|
|
||||||
|
edge_cleanup_routes(eee);
|
||||||
|
|
||||||
free(eee);
|
free(eee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1921,12 +2011,336 @@ static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port,
|
||||||
|
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
static uint32_t get_gateway_ip() {
|
||||||
|
FILE *fd;
|
||||||
|
char *token = NULL;
|
||||||
|
char *gateway_ip_str = NULL;
|
||||||
|
char buf[256];
|
||||||
|
uint32_t gateway = 0;
|
||||||
|
|
||||||
|
if(!(fd = fopen("/proc/net/route", "r")))
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
while(fgets(buf, sizeof(buf), fd)) {
|
||||||
|
if(strtok(buf, "\t") && (token = strtok(NULL, "\t")) && (!strcmp(token, "00000000"))) {
|
||||||
|
token = strtok(NULL, "\t");
|
||||||
|
|
||||||
|
if(token) {
|
||||||
|
struct in_addr addr;
|
||||||
|
|
||||||
|
addr.s_addr = strtoul(token, NULL, 16);
|
||||||
|
gateway_ip_str = inet_ntoa(addr);
|
||||||
|
|
||||||
|
if(gateway_ip_str) {
|
||||||
|
gateway = addr.s_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
return(gateway);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* route_cmd_to_str(int cmd, const n2n_route_t *route, char *buf, size_t bufsize) {
|
||||||
|
const char *cmd_str;
|
||||||
|
struct in_addr addr;
|
||||||
|
char netbuf[64], gwbuf[64];
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
|
case RTM_NEWROUTE:
|
||||||
|
cmd_str = "Add";
|
||||||
|
break;
|
||||||
|
case RTM_DELROUTE:
|
||||||
|
cmd_str = "Delete";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cmd_str = "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.s_addr = route->net_addr;
|
||||||
|
inet_ntop(AF_INET, &addr, netbuf, sizeof(netbuf));
|
||||||
|
addr.s_addr = route->gateway;
|
||||||
|
inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf));
|
||||||
|
|
||||||
|
snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf);
|
||||||
|
|
||||||
|
return(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adapted from https://olegkutkov.me/2019/08/29/modifying-linux-network-routes-using-netlink/ */
|
||||||
|
#define NLMSG_TAIL(nmsg) \
|
||||||
|
((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||||
|
|
||||||
|
/* Add new data to rtattr */
|
||||||
|
static int rtattr_add(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen)
|
||||||
|
{
|
||||||
|
int len = RTA_LENGTH(alen);
|
||||||
|
struct rtattr *rta;
|
||||||
|
|
||||||
|
if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
||||||
|
traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rta = NLMSG_TAIL(n);
|
||||||
|
rta->rta_type = type;
|
||||||
|
rta->rta_len = len;
|
||||||
|
|
||||||
|
if(alen)
|
||||||
|
memcpy(RTA_DATA(rta), data, alen);
|
||||||
|
|
||||||
|
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) {
|
||||||
|
int rv = -1;
|
||||||
|
int rv2;
|
||||||
|
char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */
|
||||||
|
char route_buf[256];
|
||||||
|
struct iovec iov;
|
||||||
|
struct msghdr msg;
|
||||||
|
struct sockaddr_nl sa;
|
||||||
|
uint8_t read_reply = 1;
|
||||||
|
int nl_sock;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr n;
|
||||||
|
struct rtmsg r;
|
||||||
|
char buf[4096];
|
||||||
|
} nl_request;
|
||||||
|
|
||||||
|
if((nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
|
||||||
|
traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno));
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subscribe to route change events */
|
||||||
|
iov.iov_base = nl_buf;
|
||||||
|
iov.iov_len = sizeof(nl_buf);
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.nl_family = PF_NETLINK;
|
||||||
|
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;
|
||||||
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_name = &sa;
|
||||||
|
msg.msg_namelen = sizeof(sa);
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
/* Subscribe to route events */
|
||||||
|
if(bind(nl_sock, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
||||||
|
traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize request structure */
|
||||||
|
memset(&nl_request, 0, sizeof(nl_request));
|
||||||
|
nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags;
|
||||||
|
nl_request.n.nlmsg_type = cmd;
|
||||||
|
nl_request.r.rtm_family = AF_INET;
|
||||||
|
nl_request.r.rtm_table = RT_TABLE_MAIN;
|
||||||
|
nl_request.r.rtm_scope = RT_SCOPE_NOWHERE;
|
||||||
|
|
||||||
|
/* Set additional flags if NOT deleting route */
|
||||||
|
if(cmd != RTM_DELROUTE) {
|
||||||
|
nl_request.r.rtm_protocol = RTPROT_BOOT;
|
||||||
|
nl_request.r.rtm_type = RTN_UNICAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_request.r.rtm_family = AF_INET;
|
||||||
|
nl_request.r.rtm_dst_len = route->net_bitlen;
|
||||||
|
|
||||||
|
/* Select scope, for simplicity we supports here only IPv6 and IPv4 */
|
||||||
|
if(nl_request.r.rtm_family == AF_INET6)
|
||||||
|
nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||||
|
else
|
||||||
|
nl_request.r.rtm_scope = RT_SCOPE_LINK;
|
||||||
|
|
||||||
|
/* Set gateway */
|
||||||
|
if(route->net_bitlen) {
|
||||||
|
if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &route->gateway, 4) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
nl_request.r.rtm_scope = 0;
|
||||||
|
nl_request.r.rtm_family = AF_INET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't set destination and interface in case of default gateways */
|
||||||
|
if(route->net_bitlen) {
|
||||||
|
/* Set destination network */
|
||||||
|
if(rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &route->net_addr, 4) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Set interface */
|
||||||
|
if(if_idx > 0) {
|
||||||
|
if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)) < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send message to the netlink */
|
||||||
|
if((rv2 = send(nl_sock, &nl_request, sizeof(nl_request), 0)) != sizeof(nl_request)) {
|
||||||
|
traceEvent(TRACE_ERROR, "netlink send failed [%d]: %s", errno, strerror(errno));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the route notification. Assume that the first reply we get is the correct one. */
|
||||||
|
traceEvent(TRACE_DEBUG, "waiting for netlink response...");
|
||||||
|
|
||||||
|
while(read_reply) {
|
||||||
|
ssize_t len = recvmsg(nl_sock, &msg, 0);
|
||||||
|
struct nlmsghdr *nh;
|
||||||
|
|
||||||
|
for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||||
|
/* Stop after the first reply */
|
||||||
|
read_reply = 0;
|
||||||
|
|
||||||
|
if(nh->nlmsg_type == NLMSG_ERROR) {
|
||||||
|
struct nlmsgerr *err = NLMSG_DATA(nh);
|
||||||
|
int errcode = err->error;
|
||||||
|
|
||||||
|
if(errcode < 0)
|
||||||
|
errcode = -errcode;
|
||||||
|
|
||||||
|
/* Ignore EEXIST as existing rules are ok */
|
||||||
|
if(errcode != EEXIST) {
|
||||||
|
traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nh->nlmsg_type == NLMSG_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(nh->nlmsg_type == cmd) {
|
||||||
|
traceEvent(TRACE_DEBUG, "Found netlink reply");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
close(nl_sock);
|
||||||
|
|
||||||
|
return(rv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Add the user-provided routes to the linux routing table. Network routes
|
||||||
|
* are bound to the n2n TAP device, so they are automatically removed when
|
||||||
|
* the TAP device is destroyed. */
|
||||||
|
static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) {
|
||||||
|
#ifdef __linux__
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<num_routes; i++) {
|
||||||
|
n2n_route_t *route = &routes[i];
|
||||||
|
|
||||||
|
if((route->net_addr == 0) && (route->net_bitlen == 0)) {
|
||||||
|
/* This is a default gateway rule. We need to:
|
||||||
|
*
|
||||||
|
* 1. Add a route to the supernode via the host internet gateway
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
n2n_sock_t sn;
|
||||||
|
n2n_route_t custom_route;
|
||||||
|
|
||||||
|
if(eee->sn_route_to_clean) {
|
||||||
|
traceEvent(TRACE_ERROR, "Only one default gateway route allowed");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(eee->conf.sn_num != 1) {
|
||||||
|
traceEvent(TRACE_ERROR, "Only one supernode supported with routes");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(supernode2addr(&sn, eee->conf.sn_ip_array[0]) < 0)
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
if(sn.family != AF_INET) {
|
||||||
|
traceEvent(TRACE_ERROR, "Only IPv4 routes supported");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_route.net_addr = *((u_int32_t*)sn.addr.v4);
|
||||||
|
custom_route.net_bitlen = 32;
|
||||||
|
custom_route.gateway = get_gateway_ip();
|
||||||
|
|
||||||
|
if(!custom_route.gateway) {
|
||||||
|
traceEvent(TRACE_ERROR, "could not determine the gateway IP address");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ip route add supernode via internet_gateway */
|
||||||
|
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0)
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
/* Save the route to delete it when n2n is stopped */
|
||||||
|
eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t));
|
||||||
|
|
||||||
|
/* Store a copy of the rules into the runtime to delete it during shutdown */
|
||||||
|
if(eee->sn_route_to_clean)
|
||||||
|
*eee->sn_route_to_clean = custom_route;
|
||||||
|
|
||||||
|
/* ip route add 0.0.0.0/1 via n2n_gateway */
|
||||||
|
custom_route.net_addr = 0;
|
||||||
|
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 {
|
||||||
|
/* ip route add net via n2n_gateway */
|
||||||
|
if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0)
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************** */
|
||||||
|
|
||||||
|
static void edge_cleanup_routes(n2n_edge_t *eee) {
|
||||||
|
#ifdef __linux__
|
||||||
|
if(eee->sn_route_to_clean) {
|
||||||
|
/* ip route del supernode via internet_gateway */
|
||||||
|
routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1);
|
||||||
|
free(eee->sn_route_to_clean);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************** */
|
||||||
|
|
||||||
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
||||||
memset(conf, 0, sizeof(*conf));
|
memset(conf, 0, sizeof(*conf));
|
||||||
|
|
||||||
conf->local_port = 0 /* any port */;
|
conf->local_port = 0 /* any port */;
|
||||||
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
||||||
conf->transop_id = N2N_TRANSFORM_ID_NULL;
|
conf->transop_id = N2N_TRANSFORM_ID_NULL;
|
||||||
|
conf->compression = N2N_COMPRESSION_ID_NONE;
|
||||||
conf->drop_multicast = 1;
|
conf->drop_multicast = 1;
|
||||||
conf->allow_p2p = 1;
|
conf->allow_p2p = 1;
|
||||||
conf->disable_pmtu_discovery = 1;
|
conf->disable_pmtu_discovery = 1;
|
||||||
|
@ -1940,6 +2354,12 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
||||||
|
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
|
||||||
|
void edge_term_conf(n2n_edge_conf_t *conf) {
|
||||||
|
if(conf->routes) free(conf->routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************** */
|
||||||
|
|
||||||
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
|
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
|
||||||
return(&eee->conf);
|
return(&eee->conf);
|
||||||
}
|
}
|
||||||
|
@ -1992,6 +2412,7 @@ int quick_edge_init(char *device_name, char *community_name,
|
||||||
|
|
||||||
rv = run_edge_loop(eee, keep_on_running);
|
rv = run_edge_loop(eee, keep_on_running);
|
||||||
edge_term(eee);
|
edge_term(eee);
|
||||||
|
edge_term_conf(&conf);
|
||||||
|
|
||||||
quick_edge_init_end:
|
quick_edge_init_end:
|
||||||
tuntap_close(&tuntap);
|
tuntap_close(&tuntap);
|
||||||
|
|
28
n2n.h
28
n2n.h
|
@ -73,8 +73,6 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <linux/if.h>
|
|
||||||
#include <linux/if_tun.h>
|
|
||||||
#define N2N_CAN_NAME_IFACE 1
|
#define N2N_CAN_NAME_IFACE 1
|
||||||
#endif /* #ifdef __linux__ */
|
#endif /* #ifdef __linux__ */
|
||||||
|
|
||||||
|
@ -139,6 +137,7 @@ typedef struct ether_hdr ether_hdr_t;
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
typedef struct tuntap_dev {
|
typedef struct tuntap_dev {
|
||||||
int fd;
|
int fd;
|
||||||
|
int if_idx;
|
||||||
uint8_t mac_addr[6];
|
uint8_t mac_addr[6];
|
||||||
uint32_t ip_addr, device_mask;
|
uint32_t ip_addr, device_mask;
|
||||||
uint16_t mtu;
|
uint16_t mtu;
|
||||||
|
@ -162,11 +161,16 @@ typedef struct tuntap_dev {
|
||||||
#define MSG_TYPE_PEER_INFO 9
|
#define MSG_TYPE_PEER_INFO 9
|
||||||
#define MSG_TYPE_QUERY_PEER 10
|
#define MSG_TYPE_QUERY_PEER 10
|
||||||
|
|
||||||
/* Set N2N_COMPRESSION_ENABLED to 0 to disable lzo1x compression of ethernet
|
/* N2N compression indicators. */
|
||||||
* frames. Doing this will break compatibility with the standard n2n packet
|
/* Compression is disabled by default for outgoing packets if no cli
|
||||||
* format so do it only for experimentation. All edges must be built with the
|
* option is given. All edges are built with decompression support so
|
||||||
* same value if they are to understand each other. */
|
* they are able to understand each other. */
|
||||||
#define N2N_COMPRESSION_ENABLED 1
|
#define N2N_COMPRESSION_ID_NONE 0 /* default, see edge_init_conf_defaults(...) in edge_utils.c */
|
||||||
|
#define N2N_COMPRESSION_ID_LZO 1 /* set if '-z' cli option is present, see setOption(...) in edge.c */
|
||||||
|
|
||||||
|
#define N2N_COMPRESSION_ID_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
|
#define DEFAULT_MTU 1290
|
||||||
|
|
||||||
|
@ -206,10 +210,19 @@ struct peer_info {
|
||||||
|
|
||||||
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
|
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
|
||||||
|
|
||||||
|
typedef struct n2n_route {
|
||||||
|
in_addr_t net_addr;
|
||||||
|
int net_bitlen;
|
||||||
|
in_addr_t gateway;
|
||||||
|
} n2n_route_t;
|
||||||
|
|
||||||
typedef struct n2n_edge_conf {
|
typedef struct n2n_edge_conf {
|
||||||
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
|
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
|
||||||
|
n2n_route_t *routes; /**< Networks to route through n2n */
|
||||||
n2n_community_t community_name; /**< The community. 16 full octets. */
|
n2n_community_t community_name; /**< The community. 16 full octets. */
|
||||||
n2n_transform_t transop_id; /**< The transop to use. */
|
n2n_transform_t transop_id; /**< The transop to use. */
|
||||||
|
uint16_t compression; /**< Compress outgoing data packets before encryption */
|
||||||
|
uint16_t num_routes; /**< Number of routes in routes */
|
||||||
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
|
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
|
||||||
uint8_t allow_routing; /**< Accept packet no to interface address. */
|
uint8_t allow_routing; /**< Accept packet no to interface address. */
|
||||||
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
|
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
|
||||||
|
@ -342,6 +355,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf);
|
||||||
int edge_verify_conf(const n2n_edge_conf_t *conf);
|
int edge_verify_conf(const n2n_edge_conf_t *conf);
|
||||||
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port);
|
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port);
|
||||||
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
|
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
|
||||||
|
void edge_term_conf(n2n_edge_conf_t *conf);
|
||||||
|
|
||||||
/* Public functions */
|
/* Public functions */
|
||||||
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
|
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
|
||||||
|
|
|
@ -137,6 +137,7 @@ typedef struct n2n_PACKET
|
||||||
n2n_mac_t dstMac;
|
n2n_mac_t dstMac;
|
||||||
n2n_sock_t sock;
|
n2n_sock_t sock;
|
||||||
uint16_t transform;
|
uint16_t transform;
|
||||||
|
uint16_t compression;
|
||||||
} n2n_PACKET_t;
|
} n2n_PACKET_t;
|
||||||
|
|
||||||
/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */
|
/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */
|
||||||
|
|
4
sn.c
4
sn.c
|
@ -930,7 +930,7 @@ static void dump_registrations(int signo) {
|
||||||
|
|
||||||
static int keep_running;
|
static int keep_running;
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__) || defined(WIN32)
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
BOOL WINAPI term_handler(DWORD sig)
|
BOOL WINAPI term_handler(DWORD sig)
|
||||||
#else
|
#else
|
||||||
|
@ -952,7 +952,7 @@ static void term_handler(int sig)
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* defined(__linux__) || defined(WIN32) */
|
||||||
|
|
||||||
/* *************************************************** */
|
/* *************************************************** */
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
|
|
||||||
/* AES plaintext preamble */
|
/* AES plaintext preamble */
|
||||||
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||||
#define TRANSOP_AES_IV_SEED_SIZE 8 /* size of transmitted random part of IV in bytes; leave it set to 8 for now */
|
#define TRANSOP_AES_IV_SEED_SIZE 8 /* size of transmitted random part of IV in bytes; could range
|
||||||
|
* from 0=lowest security (constant IV) to 16=higest security
|
||||||
|
* (fully random IV); default=8 */
|
||||||
#define TRANSOP_AES_IV_PADDING_SIZE (N2N_AES_IVEC_SIZE - TRANSOP_AES_IV_SEED_SIZE)
|
#define TRANSOP_AES_IV_PADDING_SIZE (N2N_AES_IVEC_SIZE - TRANSOP_AES_IV_SEED_SIZE)
|
||||||
#define TRANSOP_AES_IV_KEY_BYTES (AES128_KEY_BYTES) /* use AES128 for IV encryption */
|
#define TRANSOP_AES_IV_KEY_BYTES (AES128_KEY_BYTES) /* use AES128 for IV encryption */
|
||||||
#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_IV_SEED_SIZE)
|
#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_IV_SEED_SIZE)
|
||||||
|
@ -43,7 +45,7 @@
|
||||||
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
|
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
|
||||||
|
|
||||||
typedef struct transop_aes {
|
typedef struct transop_aes {
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
EVP_CIPHER_CTX *enc_ctx; /* openssl's reusable evp_* encryption context */
|
EVP_CIPHER_CTX *enc_ctx; /* openssl's reusable evp_* encryption context */
|
||||||
EVP_CIPHER_CTX *dec_ctx; /* openssl's reusable evp_* decryption context */
|
EVP_CIPHER_CTX *dec_ctx; /* openssl's reusable evp_* decryption context */
|
||||||
const EVP_CIPHER *cipher; /* cipher to use: e.g. EVP_aes_128_cbc */
|
const EVP_CIPHER *cipher; /* cipher to use: e.g. EVP_aes_128_cbc */
|
||||||
|
@ -61,7 +63,7 @@ typedef struct transop_aes {
|
||||||
static int transop_deinit_aes(n2n_trans_op_t *arg) {
|
static int transop_deinit_aes(n2n_trans_op_t *arg) {
|
||||||
transop_aes_t *priv = (transop_aes_t *)arg->priv;
|
transop_aes_t *priv = (transop_aes_t *)arg->priv;
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
EVP_CIPHER_CTX_free(priv->enc_ctx);
|
EVP_CIPHER_CTX_free(priv->enc_ctx);
|
||||||
EVP_CIPHER_CTX_free(priv->dec_ctx);
|
EVP_CIPHER_CTX_free(priv->dec_ctx);
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,10 +76,10 @@ static int transop_deinit_aes(n2n_trans_op_t *arg) {
|
||||||
|
|
||||||
/* ****************************************************** */
|
/* ****************************************************** */
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
/* get any erorr message out of openssl
|
/* get any erorr message out of openssl
|
||||||
taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling */
|
taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling */
|
||||||
char *openssl_err_as_string (void) {
|
static char *openssl_err_as_string (void) {
|
||||||
BIO *bio = BIO_new (BIO_s_mem ());
|
BIO *bio = BIO_new (BIO_s_mem ());
|
||||||
ERR_print_errors (bio);
|
ERR_print_errors (bio);
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
|
@ -94,12 +96,35 @@ char *openssl_err_as_string (void) {
|
||||||
|
|
||||||
/* ****************************************************** */
|
/* ****************************************************** */
|
||||||
|
|
||||||
static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
|
/* convert a given number of bytes from memory to hex string; taken (and modified) from
|
||||||
|
https://stackoverflow.com/questions/6357031/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-in-c */
|
||||||
|
const char* to_hex(unsigned char * in, size_t insz, char * out, size_t outsz)
|
||||||
|
{
|
||||||
|
unsigned char * pin = in;
|
||||||
|
const char * hex = "0123456789abcdef";
|
||||||
|
char * pout = out;
|
||||||
|
for(; pin < in+insz; pout +=2, pin++){
|
||||||
|
pout[0] = hex[(*pin>>4) & 0xF];
|
||||||
|
pout[1] = hex[ *pin & 0xF];
|
||||||
|
if (pout + 2 - out > outsz){
|
||||||
|
/* Better to truncate output string than overflow buffer */
|
||||||
|
/* it would be still better to either return a status */
|
||||||
|
/* or ensure the target buffer is large enough and it never happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pout[2] = 0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ****************************************************** */
|
||||||
|
|
||||||
|
static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint8_t * iv_seed) {
|
||||||
uint8_t iv_full[N2N_AES_IVEC_SIZE];
|
uint8_t iv_full[N2N_AES_IVEC_SIZE];
|
||||||
|
|
||||||
/* Extend the seed to full block size with padding value */
|
/* Extend the seed to full block size with padding value */
|
||||||
memcpy(iv_full, priv->iv_pad_val, TRANSOP_AES_IV_PADDING_SIZE);
|
memcpy(iv_full, priv->iv_pad_val, TRANSOP_AES_IV_PADDING_SIZE);
|
||||||
memcpy(iv_full + TRANSOP_AES_IV_PADDING_SIZE, &iv_seed, TRANSOP_AES_IV_SEED_SIZE);
|
memcpy(iv_full + TRANSOP_AES_IV_PADDING_SIZE, iv_seed, TRANSOP_AES_IV_SEED_SIZE);
|
||||||
|
|
||||||
/* Encrypt the IV with secret key to make it unpredictable.
|
/* Encrypt the IV with secret key to make it unpredictable.
|
||||||
* As discussed in https://github.com/ntop/n2n/issues/72, it's important to
|
* As discussed in https://github.com/ntop/n2n/issues/72, it's important to
|
||||||
|
@ -115,7 +140,7 @@ static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint64_t iv
|
||||||
/** The aes packet format consists of:
|
/** The aes packet format consists of:
|
||||||
*
|
*
|
||||||
* - a 8-bit aes encoding version in clear text
|
* - a 8-bit aes encoding version in clear text
|
||||||
* - a 64-bit random IV seed
|
* - a TRANSOP_AES_IV_SEED_SIZE-sized [bytes] random IV seed
|
||||||
* - encrypted payload.
|
* - encrypted payload.
|
||||||
*
|
*
|
||||||
* [V|II|DDDDDDDDDDDDDDDDDDDDD]
|
* [V|II|DDDDDDDDDDDDDDDDDDDDD]
|
||||||
|
@ -135,7 +160,7 @@ static int transop_encode_aes(n2n_trans_op_t * arg,
|
||||||
if((in_len + TRANSOP_AES_PREAMBLE_SIZE) <= out_len) {
|
if((in_len + TRANSOP_AES_PREAMBLE_SIZE) <= out_len) {
|
||||||
int len=-1;
|
int len=-1;
|
||||||
size_t idx=0;
|
size_t idx=0;
|
||||||
uint64_t iv_seed = 0;
|
uint8_t iv_seed[TRANSOP_AES_IV_SEED_SIZE];
|
||||||
uint8_t padding = 0;
|
uint8_t padding = 0;
|
||||||
n2n_aes_ivec_t enc_ivec = {0};
|
n2n_aes_ivec_t enc_ivec = {0};
|
||||||
|
|
||||||
|
@ -144,12 +169,20 @@ static int transop_encode_aes(n2n_trans_op_t * arg,
|
||||||
/* Encode the aes format version. */
|
/* Encode the aes format version. */
|
||||||
encode_uint8(outbuf, &idx, N2N_AES_TRANSFORM_VERSION);
|
encode_uint8(outbuf, &idx, N2N_AES_TRANSFORM_VERSION);
|
||||||
|
|
||||||
/* Generate and encode the IV seed.
|
/* Generate and encode the IV seed using as many calls to rand() as neccessary.
|
||||||
* Using two calls to rand() because RAND_MAX is usually < 64bit
|
* Note: ( N2N_AES_IV_SEED_SIZE % sizeof(rand_value) ) not neccessarily equals 0. */
|
||||||
* (e.g. linux) and sometimes < 32bit (e.g. Windows).
|
uint32_t rand_value;
|
||||||
*/
|
int8_t i;
|
||||||
iv_seed = ((((uint64_t)rand() & 0xFFFFFFFF)) << 32) | rand();
|
for (i = TRANSOP_AES_IV_SEED_SIZE; i >= sizeof(rand_value); i -= sizeof(rand_value)) {
|
||||||
encode_buf(outbuf, &idx, &iv_seed, TRANSOP_AES_IV_SEED_SIZE);
|
rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later
|
||||||
|
memcpy(iv_seed + TRANSOP_AES_IV_SEED_SIZE - i, &rand_value, sizeof(rand_value));
|
||||||
|
}
|
||||||
|
/* Are there bytes left to fill? */
|
||||||
|
if (i != 0) {
|
||||||
|
rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later
|
||||||
|
memcpy(iv_seed, &rand_value, i);
|
||||||
|
}
|
||||||
|
encode_buf(outbuf, &idx, iv_seed, TRANSOP_AES_IV_SEED_SIZE);
|
||||||
|
|
||||||
/* Encrypt the assembly contents and write the ciphertext after the iv seed. */
|
/* Encrypt the assembly contents and write the ciphertext after the iv seed. */
|
||||||
/* len is set to the length of the cipher plain text to be encrpyted
|
/* len is set to the length of the cipher plain text to be encrpyted
|
||||||
|
@ -164,11 +197,13 @@ static int transop_encode_aes(n2n_trans_op_t * arg,
|
||||||
len2 = ((len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */
|
len2 = ((len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */
|
||||||
padding = (len2-len);
|
padding = (len2-len);
|
||||||
assembly[len2 - 1] = padding;
|
assembly[len2 - 1] = padding;
|
||||||
traceEvent(TRACE_DEBUG, "padding = %u, seed = %016llx", padding, iv_seed);
|
|
||||||
|
char iv_seed_hex[2 * N2N_AES_IVEC_SIZE + 1];
|
||||||
|
traceEvent(TRACE_DEBUG, "padding = %u, seed = 0x%s", padding, to_hex (iv_seed, TRANSOP_AES_IV_SEED_SIZE, iv_seed_hex, 2 * N2N_AES_IVEC_SIZE + 1) );
|
||||||
|
|
||||||
set_aes_cbc_iv(priv, enc_ivec, iv_seed);
|
set_aes_cbc_iv(priv, enc_ivec, iv_seed);
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
EVP_CIPHER_CTX *ctx = priv->enc_ctx;
|
EVP_CIPHER_CTX *ctx = priv->enc_ctx;
|
||||||
int evp_len;
|
int evp_len;
|
||||||
int evp_ciphertext_len;
|
int evp_ciphertext_len;
|
||||||
|
@ -229,7 +264,7 @@ static int transop_decode_aes(n2n_trans_op_t * arg,
|
||||||
size_t rem=in_len;
|
size_t rem=in_len;
|
||||||
size_t idx=0;
|
size_t idx=0;
|
||||||
uint8_t aes_enc_ver=0;
|
uint8_t aes_enc_ver=0;
|
||||||
uint64_t iv_seed=0;
|
uint8_t iv_seed[TRANSOP_AES_IV_SEED_SIZE];
|
||||||
|
|
||||||
/* Get the encoding version to make sure it is supported */
|
/* Get the encoding version to make sure it is supported */
|
||||||
decode_uint8(&aes_enc_ver, inbuf, &rem, &idx );
|
decode_uint8(&aes_enc_ver, inbuf, &rem, &idx );
|
||||||
|
@ -238,7 +273,8 @@ static int transop_decode_aes(n2n_trans_op_t * arg,
|
||||||
/* Get the IV seed */
|
/* Get the IV seed */
|
||||||
decode_buf((uint8_t *)&iv_seed, TRANSOP_AES_IV_SEED_SIZE, inbuf, &rem, &idx);
|
decode_buf((uint8_t *)&iv_seed, TRANSOP_AES_IV_SEED_SIZE, inbuf, &rem, &idx);
|
||||||
|
|
||||||
traceEvent(TRACE_DEBUG, "decode_aes %lu with seed %016llx", in_len, iv_seed);
|
char iv_seed_hex[2 * N2N_AES_IVEC_SIZE + 1];
|
||||||
|
traceEvent(TRACE_DEBUG, "decode_aes %lu with seed 0x%s", in_len, to_hex (iv_seed, TRANSOP_AES_IV_SEED_SIZE, iv_seed_hex, 2 * N2N_AES_IVEC_SIZE + 1) );
|
||||||
|
|
||||||
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
|
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
|
||||||
|
|
||||||
|
@ -248,7 +284,7 @@ static int transop_decode_aes(n2n_trans_op_t * arg,
|
||||||
|
|
||||||
set_aes_cbc_iv(priv, dec_ivec, iv_seed);
|
set_aes_cbc_iv(priv, dec_ivec, iv_seed);
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
EVP_CIPHER_CTX *ctx = priv->dec_ctx;
|
EVP_CIPHER_CTX *ctx = priv->dec_ctx;
|
||||||
int evp_len;
|
int evp_len;
|
||||||
int evp_plaintext_len;
|
int evp_plaintext_len;
|
||||||
|
@ -319,7 +355,7 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
|
||||||
size_t key_mat_buf_length;
|
size_t key_mat_buf_length;
|
||||||
|
|
||||||
/* Clear out any old possibly longer key matter. */
|
/* Clear out any old possibly longer key matter. */
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
memset(&(priv->key), 0, sizeof(priv->key) );
|
memset(&(priv->key), 0, sizeof(priv->key) );
|
||||||
#else
|
#else
|
||||||
memset(&(priv->enc_key), 0, sizeof(priv->enc_key) );
|
memset(&(priv->enc_key), 0, sizeof(priv->enc_key) );
|
||||||
|
@ -344,14 +380,14 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(key_size >= 65) {
|
if(key_size >= 65) {
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
priv->cipher = EVP_aes_256_cbc();
|
priv->cipher = EVP_aes_256_cbc();
|
||||||
#endif
|
#endif
|
||||||
aes_key_size_bytes = AES256_KEY_BYTES;
|
aes_key_size_bytes = AES256_KEY_BYTES;
|
||||||
SHA512(key, key_size, key_mat_buf);
|
SHA512(key, key_size, key_mat_buf);
|
||||||
key_mat_buf_length = SHA512_DIGEST_LENGTH;
|
key_mat_buf_length = SHA512_DIGEST_LENGTH;
|
||||||
} else if(key_size >= 44) {
|
} else if(key_size >= 44) {
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
priv->cipher = EVP_aes_192_cbc();
|
priv->cipher = EVP_aes_192_cbc();
|
||||||
#endif
|
#endif
|
||||||
aes_key_size_bytes = AES192_KEY_BYTES;
|
aes_key_size_bytes = AES192_KEY_BYTES;
|
||||||
|
@ -360,7 +396,7 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
|
||||||
SHA256(key_mat_buf, SHA384_DIGEST_LENGTH, key_mat_buf + SHA384_DIGEST_LENGTH);
|
SHA256(key_mat_buf, SHA384_DIGEST_LENGTH, key_mat_buf + SHA384_DIGEST_LENGTH);
|
||||||
key_mat_buf_length = SHA384_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
key_mat_buf_length = SHA384_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
||||||
} else {
|
} else {
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
priv->cipher = EVP_aes_128_cbc();
|
priv->cipher = EVP_aes_128_cbc();
|
||||||
#endif
|
#endif
|
||||||
aes_key_size_bytes = AES128_KEY_BYTES;
|
aes_key_size_bytes = AES128_KEY_BYTES;
|
||||||
|
@ -381,7 +417,7 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
|
||||||
/* setup of key, used for the CBC encryption */
|
/* setup of key, used for the CBC encryption */
|
||||||
aes_key_size_bits = 8 * aes_key_size_bytes;
|
aes_key_size_bits = 8 * aes_key_size_bytes;
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
memcpy (priv->key, key_mat_buf, aes_key_size_bytes);
|
memcpy (priv->key, key_mat_buf, aes_key_size_bytes);
|
||||||
#else
|
#else
|
||||||
AES_set_encrypt_key(key_mat_buf, aes_key_size_bits, &(priv->enc_key));
|
AES_set_encrypt_key(key_mat_buf, aes_key_size_bits, &(priv->enc_key));
|
||||||
|
@ -425,7 +461,7 @@ int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
|
||||||
}
|
}
|
||||||
ttt->priv = priv;
|
ttt->priv = priv;
|
||||||
|
|
||||||
#ifdef OPENSSL_1_1
|
#ifdef HAVE_OPENSSL_1_1
|
||||||
/* Setup openssl's reusable evp_* contexts for encryption and decryption*/
|
/* Setup openssl's reusable evp_* contexts for encryption and decryption*/
|
||||||
if(!(priv->enc_ctx = EVP_CIPHER_CTX_new())) {
|
if(!(priv->enc_ctx = EVP_CIPHER_CTX_new())) {
|
||||||
traceEvent(TRACE_ERROR, "openssl's evp_* encryption context creation: %s\n", openssl_err_as_string());
|
traceEvent(TRACE_ERROR, "openssl's evp_* encryption context creation: %s\n", openssl_err_as_string());
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
#include <net/if_arp.h>
|
#include <net/if_arp.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
@ -170,6 +172,7 @@ int tuntap_open(tuntap_dev *device,
|
||||||
sa.nl_groups = RTMGRP_LINK;
|
sa.nl_groups = RTMGRP_LINK;
|
||||||
sa.nl_pid = getpid();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
msg.msg_name = &sa;
|
msg.msg_name = &sa;
|
||||||
msg.msg_namelen = sizeof(sa);
|
msg.msg_namelen = sizeof(sa);
|
||||||
msg.msg_iov = &iov;
|
msg.msg_iov = &iov;
|
||||||
|
@ -229,6 +232,8 @@ int tuntap_open(tuntap_dev *device,
|
||||||
|
|
||||||
device->ip_addr = inet_addr(device_ip);
|
device->ip_addr = inet_addr(device_ip);
|
||||||
device->device_mask = inet_addr(device_mask);
|
device->device_mask = inet_addr(device_mask);
|
||||||
|
device->if_idx = if_nametoindex(dev);
|
||||||
|
|
||||||
return(device->fd);
|
return(device->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user