Browse Source

Merge branch 'dev' into zstdCompression

pull/246/head
Luca Deri 4 years ago
committed by GitHub
parent
commit
40da89521a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      CMakeLists.txt
  2. 5
      Makefile.in
  3. 34
      README.md
  4. 6
      configure.seed
  5. 161
      edge.c
  6. 372
      edge_utils.c
  7. 17
      n2n.h
  8. 1
      n2n_transforms.h
  9. 4
      sn.c
  10. 12
      tools/benchmark.c
  11. 293
      transform_cc20.c
  12. 5
      tuntap_linux.c

10
CMakeLists.txt

@ -92,6 +92,16 @@ target_link_libraries(example_edge_embed n2n)
add_executable(example_sn_embed example_sn_embed.c)
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
RUNTIME DESTINATION sbin
LIBRARY DESTINATION lib

5
Makefile.in

@ -50,7 +50,7 @@ MAN8DIR=$(MANDIR)/man8
N2N_LIB=libn2n.a
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o \
edge_utils.o sn_utils.o \
transform_null.o transform_tf.o transform_aes.o \
transform_null.o transform_tf.o transform_aes.o transform_cc20.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o \
tuntap_osx.o
LIBS_EDGE+=$(LIBS_EDGE_OPT)
@ -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
$(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 : %
gzip -c $< > $@

34
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
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.
Here is how to configure host1:
In order to enable routing, the `server` must be configured as follows:
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`
3. Possibly configure iptables to `ACCEPT` the packets on the `FORWARD` chain.
On host2, run the `edge` program as normal to join the host1 community.
In order to forward all the internet traffic via host2:
3. Enable IP masquerading: `sudo iptables -t nat -A POSTROUTING -j MASQUERADE`
```sh
# Determine the current gateway (e.g. 192.168.1.1)
$ ip route show default
# Add a route to reach the supernode via such gateway
$ sudo ip route add supernode.ntop.org via 192.168.1.1
On the client side, the easiest way to configure routing is via the `-n` option. For example:
# Forward all the internet traffic via host1
$ sudo ip route del default
$ sudo ip route add default via 192.168.100.1
```
- 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`
This process can be greatly simplified by using the [n2n_gateway.sh](doc/n2n_gateway.sh) script.
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.
See [Routing.md](doc/Routing.md) for other use cases and in depth explanation.
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.
## Manual Compilation
@ -119,10 +106,11 @@ n2n edge nodes use twofish encryption by default for compatibility reasons with
of the edge nodes, their IP address and the community are sent in cleartext.
When encryption is enabled, the supernode will not be able to decrypt the traffic exchanged between
two edge nodes, but it will now that edge A is talking with edge B.
two edge nodes, but it will know that edge A is talking with edge B.
Recently AES encryption support has been implemented, which increases both security and performance,
so it is recommended to enable it on all the edge nodes by specifying the `-A` option.
so it is recommended to enable it on all the edge nodes that must have the -Ax value. When possible
(i.e. when n2n is compiled with OpenSSL 1.1) we recommend to use -A4
A benchmark of the encryption methods is available when compiled from source with `tools/n2n-benchmark`.

6
configure.seed

@ -59,6 +59,12 @@ if test x$pcap_immediate_mode != x; then
AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [], [Have pcap_immediate_mode])
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`
SYSTEM=`uname -s`

161
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 {
char tuntap_dev_name[N2N_IFNAMSIZ];
char ip_mode[N2N_IF_MODE_SIZE];
@ -135,6 +150,7 @@ static void help() {
#endif /* #ifndef WIN32 */
#ifdef __linux__
"[-T <tos>]"
"[-n cidr:gateway] "
#endif
"[-m <MAC address>] "
"-l <supernode host:port>\n"
@ -143,7 +159,7 @@ static void help() {
#ifndef __APPLE__
"[-D] "
#endif
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A] [-z[<compression algo>]] [-h]\n\n");
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-z[<compression algo>]] [-h]\n\n");
#if defined(N2N_CAN_NAME_IFACE)
printf("-d <tun device> | tun device name\n");
@ -172,8 +188,13 @@ static void help() {
" | causes connections stall when not properly supported.\n");
#endif
printf("-r | Enable packet forwarding through n2n community.\n");
printf("-A1 | Disable payload encryption. Do not use with -k.\n");
printf("-A2 | Use Twofish for payload encryption (default). Requires a key (-k).\n");
#ifdef N2N_HAVE_AES
printf("-A | Use AES CBC for encryption (default=use twofish).\n");
printf("-A3 or -A (deprecated) | Use AES-CBC for payload encryption. Requires a key (-k).\n");
#endif
#ifdef HAVE_OPENSSL_1_1
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key (-k).\n");
#endif
printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n");
#ifdef N2N_HAVE_ZSTD
@ -184,6 +205,7 @@ static void help() {
printf("-S | Do not connect P2P. Always use the supernode.\n");
#ifdef __linux__
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
printf("-v | Make more verbose. Repeat as required.\n");
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
@ -201,6 +223,46 @@ static void help() {
/* *************************************************** */
static void setPayloadEncryption( n2n_edge_conf_t *conf, int cipher) {
/* even though 'cipher' and 'conf->transop_id' share the same encoding scheme,
* a switch-statement under conditional compilation is used to sort out the
* unsupported ciphers */
switch (cipher) {
case 1:
{
conf->transop_id = N2N_TRANSFORM_ID_NULL;
break;
}
case 2:
{
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
break;
}
#ifdef N2N_HAVE_AES
case 3:
{
conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
break;
}
#endif
#ifdef HAVE_OPENSSL_1_1
case 4:
{
conf->transop_id = N2N_TRANSFORM_ID_CHACHA20;
break;
}
#endif
default:
{
conf->transop_id = N2N_TRANSFORM_ID_INVAL;
traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version.", transop_str(cipher));
exit(1);
}
}
}
/* *************************************************** */
static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_edge_conf_t *conf) {
/* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */
@ -276,7 +338,6 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
if(conf->encrypt_key) free(conf->encrypt_key);
if(conf->transop_id == N2N_TRANSFORM_ID_NULL)
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
conf->encrypt_key = strdup(optargument);
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key);
break;
@ -288,13 +349,21 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
break;
}
#ifdef N2N_HAVE_AES
case 'A':
{
conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
int cipher;
if (optargument) {
cipher = atoi(optargument);
} else {
traceEvent(TRACE_NORMAL, "the use of the solitary -A switch is deprecated and might not be supported in future versions. "
"please use -A3 instead to choose a the AES-CBC cipher for payload encryption.");
cipher = N2N_TRANSFORM_ID_AESCBC; // default, if '-A' only
}
setPayloadEncryption(conf, cipher);
break;
}
#endif
case 'z':
{
@ -376,6 +445,43 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
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
case 's': /* Subnet Mask */
@ -435,12 +541,9 @@ 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::"
#ifdef N2N_HAVE_AES
"A"
#endif
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:zA:z::"
#ifdef __linux__
"T:"
"T:n:"
#endif
,
long_options, NULL)) != '?') {
@ -635,7 +738,7 @@ static void daemonize() {
static int keep_on_running;
#ifdef __linux__
#if defined(__linux__) || defined(WIN32)
#ifdef WIN32
BOOL WINAPI term_handler(DWORD sig)
#else
@ -657,7 +760,7 @@ static void term_handler(int sig)
return(TRUE);
#endif
}
#endif
#endif /* defined(__linux__) || defined(WIN32) */
/* *************************************************** */
@ -671,6 +774,9 @@ int main(int argc, char* argv[]) {
#ifndef WIN32
struct passwd *pw = NULL;
#endif
#ifdef HAVE_LIBCAP
cap_t caps;
#endif
/* Defaults */
edge_init_conf_defaults(&conf);
@ -721,6 +827,7 @@ int main(int argc, char* argv[]) {
#endif
traceEvent(TRACE_NORMAL, "Using compression: %s.", compression_str(conf.compression));
traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id));
/* Random seed */
srand(time(NULL));
@ -766,6 +873,22 @@ int main(int argc, char* argv[]) {
#endif /* #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)) {
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
(signed int)ec.userid, (signed int)ec.groupid);
@ -795,8 +918,20 @@ int main(int argc, char* argv[]) {
rc = run_edge_loop(eee, &keep_on_running);
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 */
edge_term(eee);
edge_term_conf(&conf);
tuntap_close(&tuntap);
if(conf.encrypt_key) free(conf.encrypt_key);

372
edge_utils.c

@ -42,6 +42,11 @@
#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
@ -61,7 +66,9 @@ static void check_peer_registration_needed(n2n_edge_t * eee,
const n2n_mac_t mac,
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 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,
uint8_t from_supernode,
const n2n_mac_t mac,
@ -110,6 +117,7 @@ struct n2n_edge {
tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */
/* Sockets */
n2n_sock_t supernode;
@ -138,11 +146,12 @@ struct n2n_edge {
/* ************************************** */
static const char* transop_str(enum n2n_transform tr) {
const char* transop_str(enum n2n_transform tr) {
switch(tr) {
case N2N_TRANSFORM_ID_NULL: return("null");
case N2N_TRANSFORM_ID_TWOFISH: return("twofish");
case N2N_TRANSFORM_ID_AESCBC: return("AES-CBC");
case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20");
default: return("invalid");
};
}
@ -258,6 +267,11 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
case N2N_TRANSFORM_ID_AESCBC:
rc = n2n_transop_aes_cbc_init(&eee->conf, &eee->transop);
break;
#endif
#ifdef HAVE_OPENSSL_1_1
case N2N_TRANSFORM_ID_CHACHA20:
rc = n2n_transop_cc20_init(&eee->conf, &eee->transop);
break;
#endif
default:
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
@ -272,7 +286,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");
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;
}
@ -325,16 +344,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
* 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;
const char *supernode_host;
int rv = 0;
memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE);
supernode_host = strtok(addr, ":");
if(supernode_host)
{
if(supernode_host) {
in_addr_t sn_addr;
char *supernode_port = strtok(NULL, ":");
const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL};
@ -366,6 +385,7 @@ static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
{
/* Should only return IPv4 addresses due to aihints. */
traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host);
rv = -1;
}
freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */
@ -375,10 +395,15 @@ static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
sn_addr = inet_addr(supernode_host); /* uint32_t */
memcpy(sn->addr.v4, &(sn_addr), IPV4_SIZE);
sn->family=AF_INET;
rv = -2;
}
} else
} else {
traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l <host:port>)");
rv = -3;
}
return(rv);
}
/* ************************************** */
@ -1958,6 +1983,9 @@ void edge_term(n2n_edge_t * eee) {
clear_peer_list(&eee->known_peers);
eee->transop.deinit(&eee->transop);
edge_cleanup_routes(eee);
free(eee);
}
@ -2029,6 +2057,329 @@ 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) {
memset(conf, 0, sizeof(*conf));
@ -2049,6 +2400,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) {
return(&eee->conf);
}
@ -2101,6 +2458,7 @@ int quick_edge_init(char *device_name, char *community_name,
rv = run_edge_loop(eee, keep_on_running);
edge_term(eee);
edge_term_conf(&conf);
quick_edge_init_end:
tuntap_close(&tuntap);

17
n2n.h

@ -73,8 +73,6 @@
#include <pthread.h>
#ifdef __linux__
#include <linux/if.h>
#include <linux/if_tun.h>
#define N2N_CAN_NAME_IFACE 1
#endif /* #ifdef __linux__ */
@ -139,6 +137,7 @@ typedef struct ether_hdr ether_hdr_t;
#ifndef WIN32
typedef struct tuntap_dev {
int fd;
int if_idx;
uint8_t mac_addr[6];
uint32_t ip_addr, device_mask;
uint16_t mtu;
@ -216,11 +215,19 @@ struct peer_info {
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 {
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_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 allow_routing; /**< Accept packet no to interface address. */
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
@ -304,6 +311,9 @@ int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
#ifdef N2N_HAVE_AES
int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
#endif
#ifdef HAVE_OPENSSL_1_1
int n2n_transop_cc20_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
#endif
/* Log */
void setTraceLevel(int level);
@ -349,6 +359,7 @@ void edge_init_conf_defaults(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);
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
void edge_term_conf(n2n_edge_conf_t *conf);
/* Public functions */
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
@ -363,4 +374,6 @@ int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss);
int run_sn_loop(n2n_sn_t *sss, int *keep_running);
const char* compression_str(uint8_t cmpr);
const char* transop_str(enum n2n_transform tr);
#endif /* _N2N_H_ */

1
n2n_transforms.h

@ -30,6 +30,7 @@ typedef enum n2n_transform {
N2N_TRANSFORM_ID_NULL = 1,
N2N_TRANSFORM_ID_TWOFISH = 2,
N2N_TRANSFORM_ID_AESCBC = 3,
N2N_TRANSFORM_ID_CHACHA20 = 4,
} n2n_transform_t;
struct n2n_trans_op;

4
sn.c

@ -930,7 +930,7 @@ static void dump_registrations(int signo) {
static int keep_running;
#ifdef __linux__
#if defined(__linux__) || defined(WIN32)
#ifdef WIN32
BOOL WINAPI term_handler(DWORD sig)
#else
@ -952,7 +952,7 @@ static void term_handler(int sig)
return(TRUE);
#endif
}
#endif
#endif /* defined(__linux__) || defined(WIN32) */
/* *************************************************** */

12
tools/benchmark.c

@ -96,6 +96,9 @@ int main(int argc, char * argv[]) {
n2n_trans_op_t transop_null, transop_twofish;
#ifdef N2N_HAVE_AES
n2n_trans_op_t transop_aes_cbc;
#endif
#ifdef HAVE_OPENSSL_1_1
n2n_trans_op_t transop_cc20;
#endif
n2n_edge_conf_t conf;
@ -112,6 +115,9 @@ int main(int argc, char * argv[]) {
#ifdef N2N_HAVE_AES
n2n_transop_aes_cbc_init(&conf, &transop_aes_cbc);
#endif
#ifdef HAVE_OPENSSL_1_1
n2n_transop_cc20_init(&conf, &transop_cc20);
#endif
/* Run the tests */
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
@ -119,6 +125,9 @@ int main(int argc, char * argv[]) {
#ifdef N2N_HAVE_AES
run_transop_benchmark("transop_aes", &transop_aes_cbc, &conf, pktbuf);
#endif
#ifdef N2N_HAVE_AES
run_transop_benchmark("transop_cc20", &transop_cc20, &conf, pktbuf);
#endif
/* Cleanup */
transop_null.deinit(&transop_null);
@ -126,6 +135,9 @@ int main(int argc, char * argv[]) {
#ifdef N2N_HAVE_AES
transop_aes_cbc.deinit(&transop_aes_cbc);
#endif
#ifdef HAVE_OPENSSL_1_1
transop_cc20.deinit(&transop_cc20);
#endif
return 0;
}

293
transform_cc20.c

@ -0,0 +1,293 @@
/**
* (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"
#include "n2n_transforms.h"
#ifdef HAVE_OPENSSL_1_1
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define N2N_CC20_TRANSFORM_VERSION 1 /* version of the transform encoding */
#define N2N_CC20_IVEC_SIZE 16
#define CC20_KEY_BYTES (256/8)
/* ChaCha20 plaintext preamble */
#define TRANSOP_CC20_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_CC20_PREAMBLE_SIZE (TRANSOP_CC20_VER_SIZE + N2N_CC20_IVEC_SIZE)
typedef unsigned char n2n_cc20_ivec_t[N2N_CC20_IVEC_SIZE];
typedef struct transop_cc20 {
EVP_CIPHER_CTX *enc_ctx; /* openssl's reusable evp_* encryption context */
EVP_CIPHER_CTX *dec_ctx; /* openssl's reusable evp_* decryption context */
const EVP_CIPHER *cipher; /* cipher to use: EVP_chacha20() */
uint8_t key[32]; /* the pure key data for payload encryption & decryption */
} transop_cc20_t;
/* ****************************************************** */
static int transop_deinit_cc20(n2n_trans_op_t *arg) {
transop_cc20_t *priv = (transop_cc20_t *)arg->priv;
EVP_CIPHER_CTX_free(priv->enc_ctx);
EVP_CIPHER_CTX_free(priv->dec_ctx);
if(priv)
free(priv);
return 0;
}
/* ****************************************************** */
/* get any erorr message out of openssl
taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling */
static char *openssl_err_as_string (void) {
BIO *bio = BIO_new (BIO_s_mem ());
ERR_print_errors (bio);
char *buf = NULL;
size_t len = BIO_get_mem_data (bio, &buf);
char *ret = (char *) calloc (1, 1 + len);
if(ret)
memcpy (ret, buf, len);
BIO_free (bio);
return ret;
}
/* ****************************************************** */
static void set_cc20_iv(transop_cc20_t *priv, n2n_cc20_ivec_t ivec) {
// keep in mind the following condition: N2N_CC20_IVEC_SIZE % sizeof(rand_value) == 0 !
uint32_t rand_value;
for (uint8_t i = 0; i < N2N_CC20_IVEC_SIZE; i += sizeof(rand_value)) {
rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later
memcpy(ivec + i, &rand_value, sizeof(rand_value));
}
}
/* ****************************************************** */
/** The ChaCha20 packet format consists of:
*
* - a 8-bit cc20 encoding version in clear text
* - a 128-bit random IV
* - encrypted payload.
*
* [V|IIII|DDDDDDDDDDDDDDDDDDDDD]
* |<---- encrypted ---->|
*/
static int transop_encode_cc20(n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len,
const uint8_t * peer_mac) {
int len=-1;
transop_cc20_t * priv = (transop_cc20_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE] = {0};
if(in_len <= N2N_PKT_BUF_SIZE) {
if((in_len + TRANSOP_CC20_PREAMBLE_SIZE) <= out_len) {
size_t idx=0;
n2n_cc20_ivec_t enc_ivec = {0};
traceEvent(TRACE_DEBUG, "encode_cc20 %lu bytes", in_len);
/* Encode the ChaCha20 format version. */
encode_uint8(outbuf, &idx, N2N_CC20_TRANSFORM_VERSION);
/* Generate and encode the IV. */
set_cc20_iv(priv, enc_ivec);
encode_buf(outbuf, &idx, &enc_ivec, N2N_CC20_IVEC_SIZE);
/* Encrypt the assembly contents and write the ciphertext after the iv. */
/* len is set to the length of the cipher plain text to be encrpyted
which is (in this case) identical to original packet lentgh */
len = in_len;
/* The assembly buffer is a source for encrypting data.
* The whole contents of assembly are encrypted. */
memcpy(assembly, inbuf, in_len);
EVP_CIPHER_CTX *ctx = priv->enc_ctx;
int evp_len;
int evp_ciphertext_len;
if(1 == EVP_EncryptInit_ex(ctx, priv->cipher, NULL, priv->key, enc_ivec)) {
if(1 == EVP_CIPHER_CTX_set_padding(ctx, 0)) {
if(1 == EVP_EncryptUpdate(ctx, outbuf + TRANSOP_CC20_PREAMBLE_SIZE, &evp_len, assembly, len)) {
evp_ciphertext_len = evp_len;
if(1 == EVP_EncryptFinal_ex(ctx, outbuf + TRANSOP_CC20_PREAMBLE_SIZE + evp_len, &evp_len)) {
evp_ciphertext_len += evp_len;
if(evp_ciphertext_len != len)
traceEvent(TRACE_ERROR, "encode_cc20 openssl encryption: encrypted %u bytes where %u were expected.\n",
evp_ciphertext_len, len);
} else
traceEvent(TRACE_ERROR, "encode_cc20 openssl final encryption: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "encode_cc20 openssl encrpytion: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "encode_cc20 openssl padding setup: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "encode_cc20 openssl init: %s\n", openssl_err_as_string());
EVP_CIPHER_CTX_reset(ctx);
len += TRANSOP_CC20_PREAMBLE_SIZE; /* size of data carried in UDP. */
} else
traceEvent(TRACE_ERROR, "encode_cc20 outbuf too small.");
} else
traceEvent(TRACE_ERROR, "encode_cc20 inbuf too big to encrypt.");
return len;
}
/* ****************************************************** */
/* See transop_encode_cc20 for packet format */
static int transop_decode_cc20(n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len,
const uint8_t * peer_mac) {
int len=0;
transop_cc20_t * priv = (transop_cc20_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
if(((in_len - TRANSOP_CC20_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* Cipher text fits in assembly */
&& (in_len >= TRANSOP_CC20_PREAMBLE_SIZE) /* Has at least version, iv */
)
{
size_t rem=in_len;
size_t idx=0;
uint8_t cc20_enc_ver=0;
n2n_cc20_ivec_t dec_ivec = {0};
/* Get the encoding version to make sure it is supported */
decode_uint8(&cc20_enc_ver, inbuf, &rem, &idx );
if(N2N_CC20_TRANSFORM_VERSION == cc20_enc_ver) {
traceEvent(TRACE_DEBUG, "decode_cc20 %lu bytes", in_len);
len = (in_len - TRANSOP_CC20_PREAMBLE_SIZE);
/* Get the IV */
decode_buf((uint8_t *)&dec_ivec, N2N_CC20_IVEC_SIZE, inbuf, &rem, &idx);
EVP_CIPHER_CTX *ctx = priv->dec_ctx;
int evp_len;
int evp_plaintext_len;
if(1 == EVP_DecryptInit_ex(ctx, priv->cipher, NULL, priv->key, dec_ivec)) {
if(1 == EVP_CIPHER_CTX_set_padding(ctx, 0)) {
if(1 == EVP_DecryptUpdate(ctx, assembly, &evp_len, inbuf + TRANSOP_CC20_PREAMBLE_SIZE, len)) {
evp_plaintext_len = evp_len;
if(1 == EVP_DecryptFinal_ex(ctx, assembly + evp_len, &evp_len)) {
evp_plaintext_len += evp_len;
if(evp_plaintext_len != len)
traceEvent(TRACE_ERROR, "decode_cc20 openssl decryption: decrypted %u bytes where %u were expected.\n",
evp_plaintext_len, len);
} else
traceEvent(TRACE_ERROR, "decode_cc20 openssl final decryption: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "decode_cc20 openssl decrpytion: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "decode_cc20 openssl padding setup: %s\n", openssl_err_as_string());
} else
traceEvent(TRACE_ERROR, "decode_cc20 openssl init: %s\n", openssl_err_as_string());
EVP_CIPHER_CTX_reset(ctx);
memcpy(outbuf, assembly, len);
} else
traceEvent(TRACE_ERROR, "decode_cc20 unsupported ChaCha20 version %u.", cc20_enc_ver);
} else
traceEvent(TRACE_ERROR, "decode_cc20 inbuf wrong size (%ul) to decrypt.", in_len);
return len;
}
/* ****************************************************** */
static int setup_cc20_key(transop_cc20_t *priv, const uint8_t *key, ssize_t key_size) {
uint8_t key_mat_buf[SHA256_DIGEST_LENGTH];
priv->cipher = EVP_chacha20();
/* Clear out any old possibly longer key matter. */
memset(&(priv->key), 0, sizeof(priv->key) );
/* The input key always gets hashed to make a more unpredictable and more complete use of the key space */
SHA256(key, key_size, key_mat_buf);
memcpy (priv->key, key_mat_buf, SHA256_DIGEST_LENGTH);
traceEvent(TRACE_DEBUG, "ChaCha20 key setup completed\n");
return(0);
}
/* ****************************************************** */
static void transop_tick_cc20(n2n_trans_op_t * arg, time_t now) { ; }
/* ****************************************************** */
/* ChaCha20 initialization function */
int n2n_transop_cc20_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
transop_cc20_t *priv;
const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
size_t encrypt_key_len = strlen(conf->encrypt_key);
memset(ttt, 0, sizeof(*ttt));
ttt->transform_id = N2N_TRANSFORM_ID_CHACHA20;
ttt->tick = transop_tick_cc20;
ttt->deinit = transop_deinit_cc20;
ttt->fwd = transop_encode_cc20;
ttt->rev = transop_decode_cc20;
priv = (transop_cc20_t*) calloc(1, sizeof(transop_cc20_t));
if(!priv) {
traceEvent(TRACE_ERROR, "cannot allocate transop_cc20_t memory");
return(-1);
}
ttt->priv = priv;
/* Setup openssl's reusable evp_* contexts for encryption and decryption*/
if(!(priv->enc_ctx = EVP_CIPHER_CTX_new())) {
traceEvent(TRACE_ERROR, "openssl's evp_* encryption context creation: %s\n", openssl_err_as_string());
return(-1);
}
if(!(priv->dec_ctx = EVP_CIPHER_CTX_new())) {
traceEvent(TRACE_ERROR, "openssl's evp_* decryption context creation: %s\n", openssl_err_as_string());
return(-1);
}
/* Setup the cipher and key */
return(setup_cc20_key(priv, encrypt_key, encrypt_key_len));
}
#endif /* HAVE_OPENSSL_1_1 */

5
tuntap_linux.c

@ -21,6 +21,8 @@
#ifdef __linux__
#include <net/if_arp.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
@ -170,6 +172,7 @@ int tuntap_open(tuntap_dev *device,
sa.nl_groups = RTMGRP_LINK;
sa.nl_pid = getpid();
memset(&msg, 0, sizeof(msg));
msg.msg_name = &sa;
msg.msg_namelen = sizeof(sa);
msg.msg_iov = &iov;
@ -229,6 +232,8 @@ int tuntap_open(tuntap_dev *device,
device->ip_addr = inet_addr(device_ip);
device->device_mask = inet_addr(device_mask);
device->if_idx = if_nametoindex(dev);
return(device->fd);
}

Loading…
Cancel
Save