2018-06-08 00:17:42 +02:00
|
|
|
/**
|
2020-06-17 06:54:02 +02:00
|
|
|
* (C) 2007-20 - ntop.org and contributors
|
2018-06-08 00:17:42 +02:00
|
|
|
*
|
|
|
|
* 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"
|
2020-11-16 21:27:42 +01:00
|
|
|
#include "network_traffic_filter.h"
|
2020-07-06 07:17:01 +02:00
|
|
|
#include "edge_utils_win32.h"
|
2018-10-31 13:08:39 +01:00
|
|
|
|
2020-05-03 18:48:59 +02:00
|
|
|
/* 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);
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2019-04-14 18:08:51 +02:00
|
|
|
static const char * supernode_ip(const n2n_edge_t * eee);
|
2019-05-22 23:04:27 +02:00
|
|
|
static void send_register(n2n_edge_t *eee, const n2n_sock_t *remote_peer, const n2n_mac_t peer_mac);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
|
|
|
static void check_peer_registration_needed(n2n_edge_t *eee,
|
|
|
|
uint8_t from_supernode,
|
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_ip_subnet_t *dev_addr,
|
2020-10-26 21:13:56 +01:00
|
|
|
const n2n_desc_t *dev_desc,
|
2020-08-16 16:34:41 +02:00
|
|
|
const n2n_sock_t *peer);
|
|
|
|
|
2019-07-16 00:37:52 +02:00
|
|
|
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos);
|
2020-05-23 14:33:10 +02:00
|
|
|
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);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
|
|
|
static void check_known_peer_sock_change(n2n_edge_t *eee,
|
|
|
|
uint8_t from_supernode,
|
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_ip_subnet_t *dev_addr,
|
2020-10-26 21:13:56 +01:00
|
|
|
const n2n_desc_t *dev_desc,
|
2020-08-16 16:34:41 +02:00
|
|
|
const n2n_sock_t *peer,
|
|
|
|
time_t when);
|
2019-04-27 01:56:57 +02:00
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
int edge_verify_conf(const n2n_edge_conf_t *conf) {
|
|
|
|
if(conf->community_name[0] == 0)
|
|
|
|
return(-1);
|
|
|
|
|
|
|
|
if(conf->sn_num == 0)
|
|
|
|
return(-2);
|
|
|
|
|
2019-05-05 21:22:23 +02:00
|
|
|
if(conf->register_interval < 1)
|
|
|
|
return(-3);
|
|
|
|
|
2019-05-22 23:30:05 +02:00
|
|
|
if(((conf->encrypt_key == NULL) && (conf->transop_id != N2N_TRANSFORM_ID_NULL)) ||
|
|
|
|
((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL)))
|
|
|
|
return(-4);
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
if(HASH_COUNT(conf->supernodes) == 0)
|
|
|
|
return(-5);
|
2020-10-26 21:13:56 +01:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2019-04-14 18:08:51 +02:00
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-06-30 13:01:37 +02:00
|
|
|
void edge_set_callbacks(n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks) {
|
|
|
|
memcpy(&eee->cb, callbacks, sizeof(n2n_edge_callbacks_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
void edge_set_userdata(n2n_edge_t *eee, void *user_data) {
|
|
|
|
eee->user_data = user_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
void* edge_get_userdata(n2n_edge_t *eee) {
|
|
|
|
return(eee->user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-07-01 16:27:08 +02:00
|
|
|
int edge_get_n2n_socket(n2n_edge_t *eee) {
|
|
|
|
return(eee->udp_sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
int edge_get_management_socket(n2n_edge_t *eee) {
|
|
|
|
return(eee->udp_mgmt_sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-05-12 13:04:07 +02:00
|
|
|
const char* transop_str(enum n2n_transform tr) {
|
2019-05-21 22:53:55 +02:00
|
|
|
switch(tr) {
|
|
|
|
case N2N_TRANSFORM_ID_NULL: return("null");
|
2020-08-30 22:39:23 +02:00
|
|
|
case N2N_TRANSFORM_ID_TWOFISH: return("Twofish");
|
|
|
|
case N2N_TRANSFORM_ID_AES: return("AES");
|
2020-04-26 15:46:41 +02:00
|
|
|
case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20");
|
2020-05-27 23:32:21 +02:00
|
|
|
case N2N_TRANSFORM_ID_SPECK :return("Speck");
|
2019-05-21 22:53:55 +02:00
|
|
|
default: return("invalid");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-05-19 21:27:22 +02:00
|
|
|
const char* compression_str(uint8_t cmpr) {
|
|
|
|
switch(cmpr) {
|
|
|
|
case N2N_COMPRESSION_ID_NONE: return("none");
|
|
|
|
case N2N_COMPRESSION_ID_LZO: return("lzo1x");
|
|
|
|
case N2N_COMPRESSION_ID_ZSTD: return("zstd");
|
|
|
|
default: return("invalid");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-12-26 22:13:49 +01:00
|
|
|
/** Destination 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF is multicast ethernet.
|
|
|
|
*/
|
|
|
|
static int is_ethMulticast(const void * buf, size_t bufsize) {
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
/* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */
|
|
|
|
if(bufsize >= sizeof(ether_hdr_t)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
/* copy to aligned memory */
|
|
|
|
ether_hdr_t eh;
|
|
|
|
memcpy(&eh, buf, sizeof(ether_hdr_t));
|
|
|
|
|
|
|
|
if((0x01 == eh.dhost[0]) &&
|
|
|
|
(0x00 == eh.dhost[1]) &&
|
|
|
|
(0x5E == eh.dhost[2]) &&
|
|
|
|
(0 == (0x80 & eh.dhost[3])))
|
|
|
|
retval = 1; /* This is an ethernet multicast packet [RFC1112]. */
|
|
|
|
}
|
2019-12-26 22:13:49 +01:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6
|
|
|
|
* neighbour discovery.
|
|
|
|
*/
|
|
|
|
static int is_ip6_discovery(const void * buf, size_t bufsize) {
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
if(bufsize >= sizeof(ether_hdr_t)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
/* copy to aligned memory */
|
|
|
|
ether_hdr_t eh;
|
2019-12-26 22:13:49 +01:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
memcpy(&eh, buf, sizeof(ether_hdr_t));
|
2019-12-26 22:13:49 +01:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1]))
|
|
|
|
retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */
|
|
|
|
}
|
2019-12-26 22:13:49 +01:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Initialise an edge to defaults.
|
|
|
|
*
|
|
|
|
* This also initialises the NULL transform operation opstruct.
|
|
|
|
*/
|
2020-08-08 16:40:45 +02:00
|
|
|
n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
|
2019-04-27 15:55:07 +02:00
|
|
|
n2n_transform_t transop_id = conf->transop_id;
|
2019-04-27 01:56:57 +02:00
|
|
|
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
|
2020-10-27 17:02:35 +01:00
|
|
|
int rc = -1, i = 0;
|
|
|
|
struct peer_info *scan, *tmp;
|
2020-11-19 09:31:24 +01:00
|
|
|
size_t idx = 0;
|
2019-04-27 01:56:57 +02:00
|
|
|
|
|
|
|
if((rc = edge_verify_conf(conf)) != 0) {
|
|
|
|
traceEvent(TRACE_ERROR, "Invalid configuration");
|
|
|
|
goto edge_init_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!eee) {
|
|
|
|
traceEvent(TRACE_ERROR, "Cannot allocate memory");
|
|
|
|
goto edge_init_error;
|
|
|
|
}
|
|
|
|
|
2019-05-05 10:08:21 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
memcpy(&eee->conf, conf, sizeof(*conf));
|
2020-10-27 17:02:35 +01:00
|
|
|
eee->curr_sn = eee->conf.supernodes;
|
|
|
|
//memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
|
2018-06-08 00:17:42 +02:00
|
|
|
eee->start_time = time(NULL);
|
|
|
|
|
|
|
|
eee->known_peers = NULL;
|
|
|
|
eee->pending_peers = NULL;
|
|
|
|
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
2020-07-25 14:28:20 +02:00
|
|
|
eee->sn_last_valid_time_stamp = initial_time_stamp ();
|
2020-11-11 09:27:39 +01:00
|
|
|
sn_selection_criterion_common_data_default(eee);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-02 09:04:25 +02:00
|
|
|
pearson_hash_init();
|
|
|
|
|
2020-06-30 22:36:54 +02:00
|
|
|
if(eee->conf.compression == N2N_COMPRESSION_ID_LZO)
|
|
|
|
if(lzo_init() != LZO_E_OK) {
|
|
|
|
traceEvent(TRACE_ERROR, "LZO compression error");
|
|
|
|
goto edge_init_error;
|
|
|
|
}
|
2020-05-19 21:27:22 +02:00
|
|
|
#ifdef N2N_HAVE_ZSTD
|
|
|
|
// zstd does not require initialization. if it were required, this would be a good place
|
|
|
|
#endif
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
traceEvent(TRACE_NORMAL, "Number of supernodes in the list: %d\n", HASH_COUNT(eee->conf.supernodes));
|
|
|
|
HASH_ITER(hh, eee->conf.supernodes, scan, tmp){
|
|
|
|
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (scan->ip_addr));
|
|
|
|
i++;
|
|
|
|
}
|
2019-04-27 01:56:57 +02:00
|
|
|
|
|
|
|
/* Set active transop */
|
|
|
|
switch(transop_id) {
|
|
|
|
case N2N_TRANSFORM_ID_TWOFISH:
|
2020-08-26 14:22:05 +02:00
|
|
|
rc = n2n_transop_tf_init(&eee->conf, &eee->transop);
|
2019-04-27 01:56:57 +02:00
|
|
|
break;
|
2020-08-30 22:39:23 +02:00
|
|
|
case N2N_TRANSFORM_ID_AES:
|
|
|
|
rc = n2n_transop_aes_init(&eee->conf, &eee->transop);
|
2019-04-27 01:56:57 +02:00
|
|
|
break;
|
2020-04-26 15:46:41 +02:00
|
|
|
case N2N_TRANSFORM_ID_CHACHA20:
|
|
|
|
rc = n2n_transop_cc20_init(&eee->conf, &eee->transop);
|
|
|
|
break;
|
2020-05-27 23:32:21 +02:00
|
|
|
case N2N_TRANSFORM_ID_SPECK:
|
|
|
|
rc = n2n_transop_speck_init(&eee->conf, &eee->transop);
|
|
|
|
break;
|
2019-04-27 01:56:57 +02:00
|
|
|
default:
|
2019-04-27 15:55:07 +02:00
|
|
|
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
|
2019-04-27 01:56:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) {
|
|
|
|
traceEvent(TRACE_ERROR, "Transop init failed");
|
|
|
|
goto edge_init_error;
|
|
|
|
}
|
|
|
|
|
2020-06-22 20:49:19 +02:00
|
|
|
/* Set the key schedule (context) for header encryption if enabled */
|
2020-06-24 09:49:36 +02:00
|
|
|
if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
2020-06-22 20:49:19 +02:00
|
|
|
traceEvent(TRACE_NORMAL, "Header encryption is enabled.");
|
2020-08-08 16:40:45 +02:00
|
|
|
packet_header_setup_key ((char *)(eee->conf.community_name), &(eee->conf.header_encryption_ctx),&(eee->conf.header_iv_ctx));
|
2020-06-22 20:49:19 +02:00
|
|
|
}
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
if(eee->transop.no_encryption)
|
|
|
|
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
|
|
|
|
|
2020-08-20 21:08:27 +02:00
|
|
|
// first time calling edge_init_sockets needs -1 in the sockets for it does throw an error
|
|
|
|
// on trying to close them (open_sockets does so for also being able to RE-open the sockets
|
|
|
|
// if called in-between, see "Supernode not responding" in update_supernode_reg(...)
|
|
|
|
eee->udp_sock = -1;
|
|
|
|
eee->udp_mgmt_sock = -1;
|
2020-11-19 09:31:24 +01:00
|
|
|
|
|
|
|
eee->conf.auth.scheme = n2n_auth_simple_id;
|
|
|
|
|
|
|
|
for (idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx)
|
|
|
|
eee->conf.auth.token[idx] = n2n_rand() % 0xff;
|
|
|
|
|
|
|
|
eee->conf.auth.toksize = sizeof(eee->conf.auth.token);
|
|
|
|
|
2020-08-20 21:08:27 +02:00
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
|
|
|
eee->udp_multicast_sock = -1;
|
|
|
|
#endif
|
2020-08-08 16:40:45 +02:00
|
|
|
if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "socket setup failed");
|
|
|
|
goto edge_init_error;
|
|
|
|
}
|
|
|
|
|
2020-08-08 16:40:45 +02:00
|
|
|
if(edge_init_routes(eee, eee->conf.routes, eee->conf.num_routes) < 0) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "routes setup failed");
|
2019-04-27 01:56:57 +02:00
|
|
|
goto edge_init_error;
|
|
|
|
}
|
|
|
|
|
2020-11-16 21:27:42 +01:00
|
|
|
eee->network_traffic_filter = create_network_traffic_filter();
|
2020-11-10 16:35:05 +01:00
|
|
|
network_traffic_filter_add_rule(eee->network_traffic_filter, eee->conf.network_traffic_filter_rules);
|
2020-11-16 21:27:42 +01:00
|
|
|
|
2020-06-21 22:26:27 +02:00
|
|
|
//edge_init_success:
|
2019-04-27 01:56:57 +02:00
|
|
|
*rv = 0;
|
|
|
|
return(eee);
|
|
|
|
|
2020-06-21 22:26:27 +02:00
|
|
|
edge_init_error:
|
2019-04-27 01:56:57 +02:00
|
|
|
if(eee)
|
|
|
|
free(eee);
|
|
|
|
*rv = rc;
|
|
|
|
return(NULL);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 00:40:26 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2019-05-23 00:46:29 +02:00
|
|
|
static int find_and_remove_peer(struct peer_info **head, const n2n_mac_t mac) {
|
2019-06-09 23:41:47 +02:00
|
|
|
struct peer_info *peer;
|
2019-05-23 00:46:29 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_FIND_PEER(*head, mac, peer);
|
|
|
|
if(peer) {
|
|
|
|
HASH_DEL(*head, peer);
|
|
|
|
free(peer);
|
2019-05-23 00:46:29 +02:00
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-05-06 00:40:26 +02:00
|
|
|
static uint32_t localhost_v4 = 0x7f000001;
|
|
|
|
static uint8_t localhost_v6[IPV6_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
|
|
|
|
|
|
|
|
/* Exclude localhost as it may be received when an edge node runs
|
|
|
|
* in the same supernode host.
|
|
|
|
*/
|
|
|
|
static int is_valid_peer_sock(const n2n_sock_t *sock) {
|
2020-06-07 13:51:48 +02:00
|
|
|
switch(sock->family) {
|
|
|
|
case AF_INET:
|
|
|
|
{
|
|
|
|
uint32_t *a = (uint32_t*)sock->addr.v4;
|
2020-06-28 21:30:40 +02:00
|
|
|
|
2020-06-07 13:51:48 +02:00
|
|
|
if(*a != htonl(localhost_v4))
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
break;
|
2020-06-28 21:30:40 +02:00
|
|
|
|
2020-06-07 13:51:48 +02:00
|
|
|
case AF_INET6:
|
|
|
|
if(memcmp(sock->addr.v6, localhost_v6, IPV6_SIZE))
|
|
|
|
return(1);
|
|
|
|
break;
|
|
|
|
}
|
2019-05-06 00:40:26 +02:00
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2019-05-05 19:09:51 +02:00
|
|
|
/* ***************************************************** */
|
|
|
|
|
2020-07-25 14:28:20 +02:00
|
|
|
static const int definitely_from_supernode = 1;
|
|
|
|
|
|
|
|
/***
|
|
|
|
*
|
|
|
|
* For a given packet, find the apporopriate internal last valid time stamp for lookup
|
|
|
|
* and verify it (and also update, if applicable).
|
|
|
|
*/
|
|
|
|
static int find_peer_time_stamp_and_verify (n2n_edge_t * eee,
|
2020-10-11 11:57:48 +02:00
|
|
|
int from_supernode, const n2n_mac_t mac,
|
|
|
|
uint64_t stamp, int allow_jitter) {
|
2020-07-25 14:28:20 +02:00
|
|
|
|
|
|
|
uint64_t * previous_stamp = NULL;
|
|
|
|
|
|
|
|
if(from_supernode) {
|
|
|
|
// from supernode
|
|
|
|
previous_stamp = &(eee->sn_last_valid_time_stamp);
|
|
|
|
} else {
|
|
|
|
// from (peer) edge
|
|
|
|
struct peer_info *peer;
|
|
|
|
HASH_FIND_PEER(eee->pending_peers, mac, peer);
|
|
|
|
if(!peer) {
|
|
|
|
HASH_FIND_PEER(eee->known_peers, mac, peer);
|
|
|
|
}
|
|
|
|
if(peer) {
|
|
|
|
// time_stamp_verify_and_update allows the pointer a previous stamp to be NULL
|
|
|
|
// if it is a (so far) unknown peer
|
|
|
|
previous_stamp = &(peer->last_valid_time_stamp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// failure --> 0; success --> 1
|
2020-09-19 12:02:16 +02:00
|
|
|
return ( time_stamp_verify_and_update (stamp, previous_stamp, allow_jitter) );
|
2020-07-25 14:28:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2018-09-29 12:03:28 +02:00
|
|
|
/***
|
|
|
|
*
|
|
|
|
* Register over multicast in case there is a peer on the same network listening
|
|
|
|
*/
|
|
|
|
static void register_with_local_peers(n2n_edge_t * eee) {
|
2019-06-22 16:50:11 +02:00
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
2019-07-15 23:33:11 +02:00
|
|
|
if(eee->multicast_joined && eee->conf.allow_p2p) {
|
2019-07-06 11:19:27 +02:00
|
|
|
/* send registration to the local multicast group */
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Registering with multicast group %s:%u",
|
2020-07-22 16:01:54 +02:00
|
|
|
N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT);
|
2019-07-06 11:19:27 +02:00
|
|
|
send_register(eee, &(eee->multicast_peer), NULL);
|
|
|
|
}
|
2019-06-22 16:50:11 +02:00
|
|
|
#else
|
|
|
|
traceEvent(TRACE_DEBUG, "Multicast peers discovery is disabled, skipping");
|
|
|
|
#endif
|
2018-09-29 12:03:28 +02:00
|
|
|
}
|
|
|
|
|
2020-12-02 08:33:10 +01:00
|
|
|
/* ************************************** */
|
|
|
|
static struct peer_info* find_peer_by_sock(const n2n_sock_t *sock, struct peer_info *peer_list){
|
|
|
|
struct peer_info *scan, *tmp, *ret = NULL;
|
|
|
|
|
|
|
|
HASH_ITER(hh, peer_list, scan, tmp){
|
|
|
|
if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0){
|
|
|
|
ret = scan;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-09-29 12:03:28 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 08:19:06 +02:00
|
|
|
/** Start the registration process.
|
|
|
|
*
|
|
|
|
* If the peer is already in pending_peers, ignore the request.
|
|
|
|
* If not in pending_peers, add it and send a REGISTER.
|
|
|
|
*
|
|
|
|
* If hdr is for a direct peer-to-peer packet, try to register back to sender
|
|
|
|
* even if the MAC is in pending_peers. This is because an incident direct
|
|
|
|
* packet indicates that peer-to-peer exchange should work so more aggressive
|
|
|
|
* registration can be permitted (once per incoming packet) as this should only
|
|
|
|
* last for a small number of packets..
|
|
|
|
*
|
|
|
|
* Called from the main loop when Rx a packet for our device mac.
|
|
|
|
*/
|
2020-08-16 16:34:41 +02:00
|
|
|
static void register_with_new_peer(n2n_edge_t *eee,
|
|
|
|
uint8_t from_supernode,
|
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_ip_subnet_t *dev_addr,
|
2020-10-26 21:13:56 +01:00
|
|
|
const n2n_desc_t *dev_desc,
|
2020-08-16 16:34:41 +02:00
|
|
|
const n2n_sock_t *peer) {
|
2020-10-11 11:57:48 +02:00
|
|
|
/* REVISIT: purge of pending_peers not yet done. */
|
|
|
|
struct peer_info *scan;
|
|
|
|
macstr_t mac_buf;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
|
|
|
|
HASH_FIND_PEER(eee->pending_peers, mac, scan);
|
|
|
|
|
|
|
|
/* NOTE: pending_peers are purged periodically with purge_expired_registrations */
|
|
|
|
if (scan == NULL) {
|
|
|
|
scan = calloc(1, sizeof(struct peer_info));
|
|
|
|
|
|
|
|
memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
|
|
|
|
scan->sock = *peer;
|
|
|
|
scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */
|
|
|
|
scan->last_valid_time_stamp = initial_time_stamp();
|
|
|
|
|
|
|
|
HASH_ADD_PEER(eee->pending_peers, scan);
|
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "=== new pending %s -> %s",
|
|
|
|
macaddr_str(mac_buf, scan->mac_addr),
|
|
|
|
sock_to_cstr(sockbuf, &(scan->sock)));
|
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "Pending peers list size=%u",
|
|
|
|
HASH_COUNT(eee->pending_peers));
|
|
|
|
|
|
|
|
/* trace Sending REGISTER */
|
|
|
|
if (from_supernode) {
|
|
|
|
/* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole)
|
|
|
|
* and then ask supernode to forward. Supernode then ask peer to ack. Some nat device
|
|
|
|
* drop and block ports with incoming UDP packet if out-come traffic does not exist.
|
|
|
|
* So we can alternatively set TTL so that the packet sent to peer never really reaches
|
|
|
|
* The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ.
|
|
|
|
*/
|
|
|
|
if (eee->conf.register_ttl == 1) {
|
|
|
|
/* We are DMZ host or port is directly accessible. Just let peer to send back the ack */
|
2019-05-26 03:49:42 +02:00
|
|
|
#ifndef WIN32
|
2020-10-11 11:57:48 +02:00
|
|
|
} else if (eee->conf.register_ttl > 1) {
|
|
|
|
/* Setting register_ttl usually implies that the edge knows the internal net topology
|
|
|
|
* clearly, we can apply aggressive port prediction to support incoming Symmetric NAT
|
|
|
|
*/
|
|
|
|
int curTTL = 0;
|
|
|
|
socklen_t lenTTL = sizeof(int);
|
|
|
|
n2n_sock_t sock = scan->sock;
|
|
|
|
int alter = 16; /* TODO: set by command line or more reliable prediction method */
|
|
|
|
|
|
|
|
getsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, &lenTTL);
|
|
|
|
setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL,
|
|
|
|
(void *) (char *) &eee->conf.register_ttl,
|
|
|
|
sizeof(eee->conf.register_ttl));
|
|
|
|
for (; alter > 0; alter--, sock.port++) {
|
|
|
|
send_register(eee, &sock, mac);
|
|
|
|
}
|
|
|
|
setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, sizeof(curTTL));
|
2019-05-26 03:49:42 +02:00
|
|
|
#endif
|
2020-10-11 11:57:48 +02:00
|
|
|
} else { /* eee->conf.register_ttl <= 0 */
|
|
|
|
/* Normal STUN */
|
|
|
|
send_register(eee, &(scan->sock), mac);
|
|
|
|
}
|
|
|
|
send_register(eee, &(eee->supernode), mac);
|
|
|
|
} else {
|
|
|
|
/* P2P register, send directly */
|
|
|
|
send_register(eee, &(scan->sock), mac);
|
|
|
|
}
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
register_with_local_peers(eee);
|
|
|
|
} else{
|
|
|
|
scan->sock = *peer;
|
|
|
|
}
|
|
|
|
scan->last_seen = time(NULL);
|
|
|
|
if(dev_addr != NULL){
|
|
|
|
memcpy(&(scan->dev_addr), dev_addr, sizeof(n2n_ip_subnet_t));
|
|
|
|
}
|
2020-10-26 21:13:56 +01:00
|
|
|
if (dev_desc) memcpy(scan->dev_desc, dev_desc, N2N_DESC_SIZE);
|
2018-06-08 08:19:06 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2018-06-08 08:19:06 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Update the last_seen time for this peer, or get registered. */
|
2020-08-16 16:34:41 +02:00
|
|
|
static void check_peer_registration_needed(n2n_edge_t *eee,
|
|
|
|
uint8_t from_supernode,
|
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_ip_subnet_t *dev_addr,
|
2020-10-26 21:13:56 +01:00
|
|
|
const n2n_desc_t *dev_desc,
|
2020-08-16 16:34:41 +02:00
|
|
|
const n2n_sock_t *peer) {
|
2020-10-11 11:57:48 +02:00
|
|
|
struct peer_info *scan;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
HASH_FIND_PEER(eee->known_peers, mac, scan);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-12-02 08:33:10 +01:00
|
|
|
/* If we were not able to find it by MAC, we try to find it by socket. */
|
|
|
|
if(scan == NULL ){
|
|
|
|
scan = find_peer_by_sock(peer, eee->known_peers);
|
|
|
|
|
|
|
|
if(scan){
|
|
|
|
HASH_DEL(eee->known_peers, scan);
|
|
|
|
memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t));
|
|
|
|
HASH_ADD_PEER(eee->known_peers, scan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (scan == NULL) {
|
|
|
|
/* Not in known_peers - start the REGISTER process. */
|
2020-10-26 21:13:56 +01:00
|
|
|
register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer);
|
2020-10-11 11:57:48 +02:00
|
|
|
} else {
|
|
|
|
/* Already in known_peers. */
|
|
|
|
time_t now = time(NULL);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (!from_supernode)
|
|
|
|
scan->last_p2p = now;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if ((now - scan->last_seen) > 0 /* >= 1 sec */) {
|
|
|
|
/* Don't register too often */
|
2020-10-26 21:13:56 +01:00
|
|
|
check_known_peer_sock_change(eee, from_supernode, mac, dev_addr, dev_desc, peer, now);
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
|
2019-05-05 19:09:51 +02:00
|
|
|
/* Confirm that a pending peer is reachable directly via P2P.
|
2018-06-08 00:17:42 +02:00
|
|
|
*
|
|
|
|
* peer must be a pointer to an element of the pending_peers list.
|
|
|
|
*/
|
2019-05-05 19:09:51 +02:00
|
|
|
static void peer_set_p2p_confirmed(n2n_edge_t * eee,
|
2020-07-22 16:01:54 +02:00
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_sock_t * peer,
|
|
|
|
time_t now) {
|
2020-12-02 08:33:10 +01:00
|
|
|
struct peer_info *scan, *scan_tmp;
|
2018-06-08 00:17:42 +02:00
|
|
|
macstr_t mac_buf;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_FIND_PEER(eee->pending_peers, mac, scan);
|
2020-12-02 08:33:10 +01:00
|
|
|
if(scan == NULL){
|
|
|
|
scan = find_peer_by_sock(peer, eee->pending_peers);
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
if(scan) {
|
|
|
|
HASH_DEL(eee->pending_peers, scan);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-12-02 08:33:10 +01:00
|
|
|
scan_tmp = find_peer_by_sock(peer, eee->known_peers);
|
|
|
|
if(scan_tmp != NULL){
|
|
|
|
HASH_DEL(eee->known_peers, scan_tmp);
|
|
|
|
scan = scan_tmp;
|
|
|
|
memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t));
|
|
|
|
} else {
|
|
|
|
scan->sock = *peer;
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-12-02 08:33:10 +01:00
|
|
|
HASH_ADD_PEER(eee->known_peers, scan);
|
2019-06-09 23:41:47 +02:00
|
|
|
scan->last_p2p = now;
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2020-07-29 07:50:00 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "P2P connection established: %s [%s]",
|
2020-07-22 16:01:54 +02:00
|
|
|
macaddr_str(mac_buf, mac),
|
|
|
|
sock_to_cstr(sockbuf, peer));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "=== new peer %s -> %s",
|
|
|
|
macaddr_str(mac_buf, scan->mac_addr),
|
|
|
|
sock_to_cstr(sockbuf, &(scan->sock)));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Pending peers list size=%u",
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_COUNT(eee->pending_peers));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Known peers list size=%u",
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_COUNT(eee->known_peers));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
scan->last_seen = now;
|
|
|
|
} else
|
|
|
|
traceEvent(TRACE_DEBUG, "Failed to find sender in pending_peers.");
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
int is_empty_ip_address(const n2n_sock_t * sock) {
|
|
|
|
const uint8_t * ptr=NULL;
|
|
|
|
size_t len=0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if(AF_INET6 == sock->family)
|
|
|
|
{
|
|
|
|
ptr = sock->addr.v6;
|
|
|
|
len = 16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = sock->addr.v4;
|
|
|
|
len = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<len; ++i)
|
|
|
|
{
|
|
|
|
if(0 != ptr[i])
|
|
|
|
{
|
|
|
|
/* found a non-zero byte in address */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-08-08 16:40:45 +02:00
|
|
|
static const n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
|
|
static const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0};
|
2019-05-06 00:40:26 +02:00
|
|
|
|
2019-05-05 19:09:51 +02:00
|
|
|
/** Check if a known peer socket has changed and possibly register again.
|
2018-06-08 00:17:42 +02:00
|
|
|
*/
|
2020-08-16 16:34:41 +02:00
|
|
|
static void check_known_peer_sock_change(n2n_edge_t *eee,
|
|
|
|
uint8_t from_supernode,
|
|
|
|
const n2n_mac_t mac,
|
|
|
|
const n2n_ip_subnet_t *dev_addr,
|
2020-10-26 21:13:56 +01:00
|
|
|
const n2n_desc_t *dev_desc,
|
2020-08-16 16:34:41 +02:00
|
|
|
const n2n_sock_t *peer,
|
|
|
|
time_t when) {
|
2020-10-11 11:57:48 +02:00
|
|
|
struct peer_info *scan;
|
|
|
|
n2n_sock_str_t sockbuf1;
|
|
|
|
n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
|
|
|
|
macstr_t mac_buf;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (is_empty_ip_address(peer))
|
|
|
|
return;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (!memcmp(mac, broadcast_mac, N2N_MAC_SIZE))
|
|
|
|
return;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
/* Search the peer in known_peers */
|
|
|
|
HASH_FIND_PEER(eee->known_peers, mac, scan);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (!scan)
|
|
|
|
/* Not in known_peers */
|
|
|
|
return;
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (!sock_equal(&(scan->sock), peer)) {
|
|
|
|
if (!from_supernode) {
|
|
|
|
/* This is a P2P packet */
|
|
|
|
traceEvent(TRACE_NORMAL, "Peer changed %s: %s -> %s",
|
|
|
|
macaddr_str(mac_buf, scan->mac_addr),
|
|
|
|
sock_to_cstr(sockbuf1, &(scan->sock)),
|
|
|
|
sock_to_cstr(sockbuf2, peer));
|
|
|
|
/* The peer has changed public socket. It can no longer be assumed to be reachable. */
|
|
|
|
HASH_DEL(eee->known_peers, scan);
|
|
|
|
free(scan);
|
|
|
|
|
2020-10-26 21:13:56 +01:00
|
|
|
register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer);
|
2020-10-11 11:57:48 +02:00
|
|
|
} else {
|
|
|
|
/* Don't worry about what the supernode reports, it could be seeing a different socket. */
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
scan->last_seen = when;
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Send a datagram to a socket defined by a n2n_sock_t */
|
|
|
|
static ssize_t sendto_sock(int fd, const void * buf,
|
|
|
|
size_t len, const n2n_sock_t * dest) {
|
|
|
|
struct sockaddr_in peer_addr;
|
|
|
|
ssize_t sent;
|
|
|
|
|
2020-07-01 11:16:34 +02:00
|
|
|
if(!dest->family)
|
|
|
|
// Invalid socket
|
|
|
|
return 0;
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
fill_sockaddr((struct sockaddr *) &peer_addr,
|
|
|
|
sizeof(peer_addr),
|
|
|
|
dest);
|
|
|
|
|
|
|
|
sent = sendto(fd, buf, len, 0/*flags*/,
|
|
|
|
(struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in));
|
|
|
|
if(sent < 0)
|
|
|
|
{
|
|
|
|
char * c = strerror(errno);
|
|
|
|
traceEvent(TRACE_ERROR, "sendto failed (%d) %s", errno, c);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
traceEvent(TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-07-06 11:19:27 +02:00
|
|
|
/* Bind eee->udp_multicast_sock to multicast group */
|
|
|
|
static void check_join_multicast_group(n2n_edge_t *eee) {
|
2019-07-08 14:13:26 +02:00
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
2019-07-06 11:19:27 +02:00
|
|
|
if(!eee->multicast_joined) {
|
|
|
|
struct ip_mreq mreq;
|
|
|
|
mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP);
|
|
|
|
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
|
|
|
|
|
|
if(setsockopt(eee->udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) {
|
|
|
|
traceEvent(TRACE_WARNING, "Failed to bind to local multicast group %s:%u [errno %u]",
|
2020-07-22 16:01:54 +02:00
|
|
|
N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno);
|
2019-07-06 11:19:27 +02:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
traceEvent(TRACE_NORMAL, "Successfully joined multicast group %s:%u",
|
2020-07-22 16:01:54 +02:00
|
|
|
N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT);
|
2019-07-06 11:19:27 +02:00
|
|
|
eee->multicast_joined = 1;
|
|
|
|
}
|
|
|
|
}
|
2019-07-08 14:13:26 +02:00
|
|
|
#endif
|
2019-07-06 11:19:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
/** Send a QUERY_PEER packet to the current supernode. */
|
|
|
|
static void send_query_peer( n2n_edge_t * eee,
|
|
|
|
const n2n_mac_t dstMac) {
|
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
|
|
|
size_t idx;
|
|
|
|
n2n_common_t cmn = {0};
|
|
|
|
n2n_QUERY_PEER_t query = {{0}};
|
|
|
|
struct peer_info *peer, *tmp;
|
|
|
|
uint8_t tmp_pkt[N2N_PKT_BUF_SIZE];
|
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
cmn.ttl = N2N_DEFAULT_TTL;
|
2020-10-27 17:02:35 +01:00
|
|
|
cmn.pc = n2n_query_peer;
|
|
|
|
cmn.flags = 0;
|
|
|
|
memcpy( cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE );
|
|
|
|
|
|
|
|
idx=0;
|
|
|
|
encode_mac( query.srcMac, &idx, eee->device.mac_addr );
|
|
|
|
|
|
|
|
idx=0;
|
|
|
|
encode_mac( query.targetMac, &idx, dstMac );
|
|
|
|
|
|
|
|
idx=0;
|
|
|
|
|
|
|
|
encode_QUERY_PEER( pktbuf, &idx, &cmn, &query );
|
|
|
|
|
|
|
|
if(memcmp(dstMac, null_mac, sizeof(n2n_mac_t)) != 0){
|
|
|
|
|
|
|
|
traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" );
|
|
|
|
|
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED){
|
|
|
|
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
|
2020-11-10 17:58:35 +01:00
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp (), pearson_hash_16 (pktbuf, idx));
|
2020-10-27 17:02:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
|
|
|
|
|
|
|
|
} else {
|
|
|
|
traceEvent( TRACE_DEBUG, "send PING to supernodes" );
|
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED){
|
|
|
|
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
|
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp (), pearson_hash_16 (pktbuf, idx));
|
|
|
|
}
|
2020-10-27 17:02:35 +01:00
|
|
|
|
|
|
|
HASH_ITER(hh, eee->conf.supernodes, peer, tmp){
|
|
|
|
sendto_sock( eee->udp_sock, pktbuf, idx, &(peer->sock));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Send a REGISTER_SUPER packet to the current supernode. */
|
2020-10-27 17:02:35 +01:00
|
|
|
static void send_register_super(n2n_edge_t *eee) {
|
2020-10-11 11:57:48 +02:00
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
|
|
|
|
size_t idx;
|
|
|
|
/* ssize_t sent; */
|
|
|
|
n2n_common_t cmn;
|
|
|
|
n2n_REGISTER_SUPER_t reg;
|
|
|
|
n2n_sock_str_t sockbuf;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
memset(&cmn, 0, sizeof(cmn));
|
|
|
|
memset(®, 0, sizeof(reg));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
cmn.ttl = N2N_DEFAULT_TTL;
|
|
|
|
cmn.pc = n2n_register_super;
|
|
|
|
cmn.flags = 0;
|
|
|
|
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx)
|
|
|
|
eee->curr_sn->last_cookie[idx] = n2n_rand() % 0xff;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
memcpy(reg.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE);
|
2020-10-11 11:57:48 +02:00
|
|
|
reg.dev_addr.net_addr = ntohl(eee->device.ip_addr);
|
|
|
|
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask));
|
2020-10-26 21:13:56 +01:00
|
|
|
memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE);
|
2020-11-19 09:31:24 +01:00
|
|
|
memcpy(&(reg.auth), &(eee->conf.auth), sizeof(n2n_auth_t));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
idx = 0;
|
|
|
|
encode_mac(reg.edgeMac, &idx, eee->device.mac_addr);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
idx = 0;
|
|
|
|
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
|
2020-10-27 17:02:35 +01:00
|
|
|
sock_to_cstr(sockbuf, &(eee->curr_sn->sock)));
|
2020-06-22 20:49:19 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
|
|
|
packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx,
|
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp(), pearson_hash_16(pktbuf, idx));
|
2020-08-08 16:40:45 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock));
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-19 09:31:24 +01:00
|
|
|
static void send_unregister_super(n2n_edge_t *eee){
|
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
|
|
|
|
size_t idx;
|
|
|
|
/* ssize_t sent; */
|
|
|
|
n2n_common_t cmn;
|
|
|
|
n2n_UNREGISTER_SUPER_t unreg;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
|
|
|
|
memset(&cmn, 0, sizeof(cmn));
|
|
|
|
memset(&unreg, 0, sizeof(unreg));
|
|
|
|
|
|
|
|
cmn.ttl = N2N_DEFAULT_TTL;
|
|
|
|
cmn.pc = n2n_unregister_super;
|
|
|
|
cmn.flags = 0;
|
|
|
|
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
|
|
|
|
|
|
|
memcpy(&(unreg.auth), &(eee->conf.auth), sizeof(n2n_auth_t));
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
encode_mac(unreg.srcMac, &idx, eee->device.mac_addr);
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
encode_UNREGISTER_SUPER(pktbuf, &idx, &cmn, &unreg);
|
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "send UNREGISTER_SUPER to %s",
|
|
|
|
sock_to_cstr(sockbuf, &(eee->curr_sn->sock)));
|
|
|
|
|
|
|
|
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
|
|
|
packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx,
|
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp(), pearson_hash_16(pktbuf, idx));
|
|
|
|
|
|
|
|
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
static int sort_supernodes(n2n_edge_t *eee, time_t now){
|
|
|
|
struct peer_info *scan, *tmp;
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-11-10 17:58:35 +01:00
|
|
|
if(eee->curr_sn != eee->conf.supernodes){
|
2020-11-19 09:31:24 +01:00
|
|
|
send_unregister_super(eee);
|
|
|
|
|
2020-11-10 17:58:35 +01:00
|
|
|
eee->curr_sn = eee->conf.supernodes;
|
|
|
|
memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
|
|
|
|
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-11-10 17:58:35 +01:00
|
|
|
traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]",
|
|
|
|
supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts);
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-11-10 17:58:35 +01:00
|
|
|
send_register_super(eee);
|
|
|
|
eee->sn_wait = 1;
|
|
|
|
}
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-11-10 17:58:35 +01:00
|
|
|
if(now - eee->last_sweep > SWEEP_TIME){
|
2020-10-27 17:02:35 +01:00
|
|
|
if(eee->sn_wait == 0){
|
|
|
|
// this routine gets periodically called
|
2020-11-11 09:27:39 +01:00
|
|
|
// it sorts supernodes in ascending order of their selection_criterion fields
|
|
|
|
sn_selection_sort(&(eee->conf.supernodes));
|
|
|
|
|
2020-11-09 16:06:00 +01:00
|
|
|
}
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-11-09 16:06:00 +01:00
|
|
|
HASH_ITER(hh, eee->conf.supernodes, scan, tmp){
|
2020-11-11 09:27:39 +01:00
|
|
|
sn_selection_criterion_default(&(scan->selection_criterion));
|
2020-10-27 17:02:35 +01:00
|
|
|
}
|
2020-11-11 09:27:39 +01:00
|
|
|
sn_selection_criterion_common_data_default(eee);
|
2020-11-09 16:06:00 +01:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
send_query_peer(eee, null_mac);
|
2020-11-09 16:06:00 +01:00
|
|
|
eee->last_sweep = now;
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
2020-10-27 17:02:35 +01:00
|
|
|
|
|
|
|
return 0; /* OK */
|
2019-06-08 19:54:46 +02:00
|
|
|
}
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Send a REGISTER packet to another edge. */
|
2019-04-14 18:08:51 +02:00
|
|
|
static void send_register(n2n_edge_t * eee,
|
2020-07-22 16:01:54 +02:00
|
|
|
const n2n_sock_t * remote_peer,
|
|
|
|
const n2n_mac_t peer_mac) {
|
2018-06-08 00:17:42 +02:00
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
|
|
|
size_t idx;
|
|
|
|
/* ssize_t sent; */
|
|
|
|
n2n_common_t cmn;
|
|
|
|
n2n_REGISTER_t reg;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
|
2019-07-15 23:33:11 +02:00
|
|
|
if(!eee->conf.allow_p2p) {
|
|
|
|
traceEvent(TRACE_DEBUG, "Skipping register as P2P is disabled");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
memset(&cmn, 0, sizeof(cmn));
|
|
|
|
memset(®, 0, sizeof(reg));
|
|
|
|
cmn.ttl=N2N_DEFAULT_TTL;
|
|
|
|
cmn.pc = n2n_register;
|
|
|
|
cmn.flags = 0;
|
2019-04-27 01:56:57 +02:00
|
|
|
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
idx=0;
|
|
|
|
encode_uint32(reg.cookie, &idx, 123456789);
|
|
|
|
idx=0;
|
|
|
|
encode_mac(reg.srcMac, &idx, eee->device.mac_addr);
|
|
|
|
|
2019-05-22 23:04:27 +02:00
|
|
|
if(peer_mac) {
|
|
|
|
/* Can be NULL for multicast registrations */
|
|
|
|
idx=0;
|
|
|
|
encode_mac(reg.dstMac, &idx, peer_mac);
|
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
reg.dev_addr.net_addr = ntohl(eee->device.ip_addr);
|
|
|
|
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask));
|
2020-10-26 21:13:56 +01:00
|
|
|
memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE);
|
2019-05-22 23:04:27 +02:00
|
|
|
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
idx=0;
|
2018-06-08 00:17:42 +02:00
|
|
|
encode_REGISTER(pktbuf, &idx, &cmn, ®);
|
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_INFO, "Send REGISTER to %s",
|
2018-06-08 00:17:42 +02:00
|
|
|
sock_to_cstr(sockbuf, remote_peer));
|
|
|
|
|
2020-06-24 09:49:36 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
2020-06-29 12:46:44 +02:00
|
|
|
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
|
2020-10-11 11:57:48 +02:00
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp (), pearson_hash_16 (pktbuf, idx));
|
2020-06-22 20:49:19 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Send a REGISTER_ACK packet to a peer edge. */
|
|
|
|
static void send_register_ack(n2n_edge_t * eee,
|
|
|
|
const n2n_sock_t * remote_peer,
|
|
|
|
const n2n_REGISTER_t * reg) {
|
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
|
|
|
size_t idx;
|
|
|
|
/* ssize_t sent; */
|
|
|
|
n2n_common_t cmn;
|
|
|
|
n2n_REGISTER_ACK_t ack;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
|
2019-07-15 23:33:11 +02:00
|
|
|
if(!eee->conf.allow_p2p) {
|
|
|
|
traceEvent(TRACE_DEBUG, "Skipping register ACK as P2P is disabled");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
memset(&cmn, 0, sizeof(cmn));
|
|
|
|
memset(&ack, 0, sizeof(reg));
|
|
|
|
cmn.ttl=N2N_DEFAULT_TTL;
|
|
|
|
cmn.pc = n2n_register_ack;
|
|
|
|
cmn.flags = 0;
|
2019-04-27 01:56:57 +02:00
|
|
|
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
memset(&ack, 0, sizeof(ack));
|
|
|
|
memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE);
|
|
|
|
memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE);
|
|
|
|
memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE);
|
|
|
|
|
|
|
|
idx=0;
|
|
|
|
encode_REGISTER_ACK(pktbuf, &idx, &cmn, &ack);
|
|
|
|
|
|
|
|
traceEvent(TRACE_INFO, "send REGISTER_ACK %s",
|
|
|
|
sock_to_cstr(sockbuf, remote_peer));
|
|
|
|
|
2020-06-24 09:49:36 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
2020-06-29 12:46:44 +02:00
|
|
|
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
|
2020-10-11 11:57:48 +02:00
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp (), pearson_hash_16 (pktbuf, idx));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-11-09 16:04:41 +01:00
|
|
|
static char gratuitous_arp[] = {
|
|
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* dest MAC */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */
|
|
|
|
0x08, 0x06, /* ARP */
|
|
|
|
0x00, 0x01, /* ethernet */
|
|
|
|
0x08, 0x00, /* IP */
|
|
|
|
0x06, /* hw Size */
|
|
|
|
0x04, /* protocol Size */
|
|
|
|
0x00, 0x02, /* ARP reply */
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */
|
|
|
|
0x00, 0x00, 0x00, 0x00, /* src IP */
|
|
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* target MAC */
|
|
|
|
0x00, 0x00, 0x00, 0x00 /* target IP */
|
|
|
|
};
|
|
|
|
|
|
|
|
// build a gratuitous ARP packet */
|
|
|
|
static int build_gratuitous_arp(n2n_edge_t * eee, char *buffer, uint16_t buffer_len) {
|
|
|
|
if(buffer_len < sizeof(gratuitous_arp)) return(-1);
|
|
|
|
|
|
|
|
memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp));
|
|
|
|
memcpy(&buffer[6], eee->device.mac_addr, 6);
|
|
|
|
memcpy(&buffer[22], eee->device.mac_addr, 6);
|
|
|
|
memcpy(&buffer[28], &(eee->device.ip_addr), 4);
|
|
|
|
|
|
|
|
memcpy(&buffer[38], &(eee->device.ip_addr), 4);
|
|
|
|
return(sizeof(gratuitous_arp));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Called from update_supernode_reg to periodically send gratuitous ARP
|
|
|
|
* broadcasts. */
|
|
|
|
static void send_grat_arps(n2n_edge_t * eee) {
|
2020-11-10 16:40:33 +01:00
|
|
|
uint8_t buffer[48];
|
2020-11-09 16:04:41 +01:00
|
|
|
size_t len;
|
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "Sending gratuitous ARP...");
|
2020-11-10 16:40:33 +01:00
|
|
|
len = build_gratuitous_arp(eee, (char*)buffer, sizeof(buffer));
|
2020-11-09 16:04:41 +01:00
|
|
|
|
|
|
|
edge_send_packet2net(eee, buffer, len);
|
|
|
|
edge_send_packet2net(eee, buffer, len); /* Two is better than one :-) */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** @brief Check to see if we should re-register with the supernode.
|
|
|
|
*
|
|
|
|
* This is frequently called by the main loop.
|
|
|
|
*/
|
2020-08-08 16:40:45 +02:00
|
|
|
void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
|
2020-10-27 17:02:35 +01:00
|
|
|
struct peer_info *scan, *tmp;
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2019-05-05 21:22:23 +02:00
|
|
|
if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) {
|
2018-09-29 00:32:36 +02:00
|
|
|
/* fall through */
|
|
|
|
traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry.");
|
2019-05-05 21:22:23 +02:00
|
|
|
} else if(nowTime < (eee->last_register_req + eee->conf.register_interval))
|
2018-09-29 00:32:36 +02:00
|
|
|
return; /* Too early */
|
|
|
|
|
2019-07-06 11:19:27 +02:00
|
|
|
check_join_multicast_group(eee);
|
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
if(0 == eee->sup_attempts) {
|
|
|
|
/* Give up on that supernode and try the next one. */
|
2020-11-11 09:27:39 +01:00
|
|
|
sn_selection_criterion_default(&(eee->curr_sn->selection_criterion));
|
|
|
|
sn_selection_sort(&(eee->conf.supernodes));
|
2020-10-27 17:02:35 +01:00
|
|
|
eee->curr_sn = eee->conf.supernodes;
|
|
|
|
memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
2020-08-20 21:08:27 +02:00
|
|
|
|
|
|
|
// in some multi-NATed scenarios communication gets stuck on losing connection to supernode
|
|
|
|
// closing and re-opening the socket(s) allows for re-establishing communication
|
2020-08-20 22:08:44 +02:00
|
|
|
// this can only be done, if working on som eunprivileged port and/or having sufficent
|
|
|
|
// privileges. as we are not able to check for sufficent privileges here, we only do it
|
|
|
|
// if port is sufficently high or unset. uncovered: privileged port and sufficent privileges
|
|
|
|
if( (eee->conf.local_port == 0) || (eee->conf.local_port > 1024) ) {
|
|
|
|
if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) {
|
|
|
|
traceEvent(TRACE_ERROR, "socket re-initiliaization failed");
|
|
|
|
}
|
2020-08-20 21:08:27 +02:00
|
|
|
}
|
2020-08-20 22:08:44 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
else
|
2018-09-29 00:32:36 +02:00
|
|
|
--(eee->sup_attempts);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
if(supernode2sock(&(eee->supernode), eee->curr_sn->ip_addr) == 0) {
|
|
|
|
traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]",
|
2020-11-10 17:58:35 +01:00
|
|
|
supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts);
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
send_register_super(eee);
|
2018-09-29 13:08:01 +02:00
|
|
|
}
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
|
2018-09-29 12:03:28 +02:00
|
|
|
register_with_local_peers(eee);
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
eee->sn_wait=1;
|
|
|
|
|
|
|
|
eee->last_register_req = nowTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Return the IP address of the current supernode in the ring. */
|
2019-04-14 18:08:51 +02:00
|
|
|
static const char * supernode_ip(const n2n_edge_t * eee) {
|
2020-10-27 17:02:35 +01:00
|
|
|
return (eee->curr_sn->ip_addr);
|
2019-01-28 00:27:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** A PACKET has arrived containing an encapsulated ethernet datagram - usually
|
|
|
|
* encrypted. */
|
|
|
|
static int handle_PACKET(n2n_edge_t * eee,
|
2020-08-16 16:34:41 +02:00
|
|
|
const uint8_t from_supernode,
|
2018-06-08 00:17:42 +02:00
|
|
|
const n2n_PACKET_t * pkt,
|
|
|
|
const n2n_sock_t * orig_sender,
|
|
|
|
uint8_t * payload,
|
|
|
|
size_t psize) {
|
|
|
|
ssize_t data_sent_len;
|
|
|
|
uint8_t * eth_payload=NULL;
|
|
|
|
int retval = -1;
|
|
|
|
time_t now;
|
2018-10-31 13:08:39 +01:00
|
|
|
ether_hdr_t * eh;
|
|
|
|
ipstr_t ip_buf;
|
2020-08-16 12:10:15 +02:00
|
|
|
macstr_t mac_buf;
|
|
|
|
n2n_sock_str_t sockbuf;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
now = time(NULL);
|
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "handle_PACKET size %u transform %u",
|
|
|
|
(unsigned int)psize, (unsigned int)pkt->transform);
|
|
|
|
/* hexdump(payload, psize); */
|
|
|
|
|
|
|
|
if(from_supernode)
|
|
|
|
{
|
2020-07-29 13:56:22 +02:00
|
|
|
if(!memcmp(pkt->dstMac, broadcast_mac, N2N_MAC_SIZE))
|
2019-06-08 18:41:18 +02:00
|
|
|
++(eee->stats.rx_sup_broadcast);
|
|
|
|
|
2019-05-05 21:47:50 +02:00
|
|
|
++(eee->stats.rx_sup);
|
2018-06-08 00:17:42 +02:00
|
|
|
eee->last_sup=now;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-05 21:47:50 +02:00
|
|
|
++(eee->stats.rx_p2p);
|
2018-06-08 00:17:42 +02:00
|
|
|
eee->last_p2p=now;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle transform. */
|
|
|
|
{
|
|
|
|
uint8_t decodebuf[N2N_PKT_BUF_SIZE];
|
|
|
|
size_t eth_size;
|
2019-04-27 15:55:07 +02:00
|
|
|
n2n_transform_t rx_transop_id;
|
2020-08-15 19:03:57 +02:00
|
|
|
uint8_t rx_compression_id;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-04-27 15:55:07 +02:00
|
|
|
rx_transop_id = (n2n_transform_t)pkt->transform;
|
2020-08-15 19:03:57 +02:00
|
|
|
rx_compression_id = pkt->compression;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
if(rx_transop_id == eee->conf.transop_id) {
|
2020-07-22 16:01:54 +02:00
|
|
|
uint8_t is_multicast;
|
|
|
|
eth_payload = decodebuf;
|
|
|
|
eh = (ether_hdr_t*)eth_payload;
|
|
|
|
eth_size = eee->transop.rev(&eee->transop,
|
|
|
|
eth_payload, N2N_PKT_BUF_SIZE,
|
|
|
|
payload, psize, pkt->srcMac);
|
|
|
|
++(eee->transop.rx_cnt); /* stats */
|
|
|
|
|
|
|
|
/* decompress if necessary */
|
|
|
|
uint8_t * deflation_buffer = 0;
|
2020-10-03 17:15:51 +02:00
|
|
|
lzo_uint deflated_len;
|
2020-07-22 16:01:54 +02:00
|
|
|
switch (rx_compression_id) {
|
|
|
|
case N2N_COMPRESSION_ID_NONE:
|
|
|
|
break; // continue afterwards
|
|
|
|
|
|
|
|
case N2N_COMPRESSION_ID_LZO:
|
|
|
|
deflation_buffer = malloc (N2N_PKT_BUF_SIZE);
|
2020-10-03 17:15:51 +02:00
|
|
|
lzo1x_decompress (eth_payload, eth_size, deflation_buffer, &deflated_len, NULL);
|
2020-07-22 16:01:54 +02:00
|
|
|
break;
|
2020-05-19 21:27:22 +02:00
|
|
|
#ifdef N2N_HAVE_ZSTD
|
2020-07-22 16:01:54 +02:00
|
|
|
case N2N_COMPRESSION_ID_ZSTD:
|
|
|
|
deflated_len = N2N_PKT_BUF_SIZE;
|
|
|
|
deflation_buffer = malloc (deflated_len);
|
2020-10-03 17:15:51 +02:00
|
|
|
deflated_len = ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size);
|
2020-06-24 09:49:36 +02:00
|
|
|
if(ZSTD_isError(deflated_len)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.",
|
|
|
|
ZSTD_getErrorName(deflated_len));
|
|
|
|
free (deflation_buffer);
|
|
|
|
return (-1); // cannot help it
|
|
|
|
}
|
|
|
|
break;
|
2020-05-19 21:27:22 +02:00
|
|
|
#endif
|
2020-07-22 16:01:54 +02:00
|
|
|
default:
|
|
|
|
traceEvent (TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.",
|
|
|
|
compression_str(rx_compression_id));
|
|
|
|
return (-1); // cannot handle it
|
|
|
|
}
|
2020-05-03 18:48:59 +02:00
|
|
|
|
2020-08-15 19:03:57 +02:00
|
|
|
if(rx_compression_id != N2N_COMPRESSION_ID_NONE) {
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes",
|
|
|
|
compression_str(rx_compression_id), eth_size, (int)deflated_len);
|
|
|
|
memcpy(eth_payload ,deflation_buffer, deflated_len );
|
|
|
|
eth_size = deflated_len;
|
|
|
|
free (deflation_buffer);
|
|
|
|
}
|
2020-05-03 18:48:59 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size));
|
|
|
|
|
|
|
|
if(eee->conf.drop_multicast && is_multicast) {
|
|
|
|
traceEvent(TRACE_INFO, "Dropping RX multicast");
|
|
|
|
return(-1);
|
|
|
|
} else if((!eee->conf.allow_routing) && (!is_multicast)) {
|
|
|
|
/* Check if it is a routed packet */
|
2020-11-10 17:58:35 +01:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) {
|
|
|
|
uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET];
|
|
|
|
uint8_t *dst_mac = (uint8_t*)eth_payload;
|
|
|
|
|
|
|
|
/* Note: all elements of the_ip are in network order */
|
2020-07-29 13:56:22 +02:00
|
|
|
if(!memcmp(dst_mac, broadcast_mac, N2N_MAC_SIZE))
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Broadcast packet [%s]",
|
|
|
|
intoa(ntohl(*dst), ip_buf, sizeof(ip_buf)));
|
|
|
|
else if((*dst != eee->device.ip_addr)) {
|
|
|
|
/* This is a packet that needs to be routed */
|
|
|
|
traceEvent(TRACE_INFO, "Discarding routed packet [%s]",
|
|
|
|
intoa(ntohl(*dst), ip_buf, sizeof(ip_buf)));
|
|
|
|
return(-1);
|
|
|
|
} else {
|
|
|
|
/* This packet is directed to us */
|
|
|
|
/* traceEvent(TRACE_INFO, "Sending non-routed packet"); */
|
2018-10-31 13:08:39 +01:00
|
|
|
}
|
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
}
|
2018-10-31 13:08:39 +01:00
|
|
|
|
2020-11-10 23:47:55 +01:00
|
|
|
if(eee->network_traffic_filter->filter_packet_from_peer( eee->network_traffic_filter, eee, orig_sender,
|
2020-11-10 17:58:35 +01:00
|
|
|
eth_payload, eth_size ) == N2N_DROP){
|
2020-11-10 16:35:05 +01:00
|
|
|
traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)eth_size);
|
|
|
|
return(0);
|
|
|
|
}
|
2020-11-16 21:27:42 +01:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if(eee->cb.packet_from_peer) {
|
|
|
|
uint16_t tmp_eth_size = eth_size;
|
|
|
|
if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, &tmp_eth_size) == N2N_DROP) {
|
|
|
|
traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size);
|
|
|
|
return(0);
|
2020-06-30 13:01:37 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
eth_size = tmp_eth_size;
|
|
|
|
}
|
2020-06-10 00:30:11 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
/* Write ethernet packet to tap device. */
|
|
|
|
traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size);
|
|
|
|
data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-06-24 09:49:36 +02:00
|
|
|
if(data_sent_len == eth_size)
|
2020-07-22 16:01:54 +02:00
|
|
|
{
|
|
|
|
retval = 0;
|
|
|
|
}
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
else
|
|
|
|
{
|
2020-08-16 12:10:15 +02:00
|
|
|
traceEvent(TRACE_ERROR, "invalid transop ID: expected %s(%u), got %s(%u) from %s [%s]",
|
2019-05-21 22:53:55 +02:00
|
|
|
transop_str(eee->conf.transop_id), eee->conf.transop_id,
|
2020-08-16 12:10:15 +02:00
|
|
|
transop_str(rx_transop_id), rx_transop_id,
|
|
|
|
sock_to_cstr(sockbuf, orig_sender),
|
|
|
|
macaddr_str(mac_buf, pkt->srcMac));
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-08-16 16:34:41 +02:00
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
|
|
|
|
static char *get_ip_from_arp(dec_ip_str_t buf, const n2n_mac_t req_mac) {
|
2020-10-11 11:57:48 +02:00
|
|
|
FILE *fd;
|
|
|
|
dec_ip_str_t ip_str = {'\0'};
|
|
|
|
char dev_str[N2N_IFNAMSIZ] = {'\0'};
|
|
|
|
macstr_t mac_str = {'\0'};
|
|
|
|
n2n_mac_t mac = {'\0'};
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
strncpy(buf, "0.0.0.0", N2N_NETMASK_STR_SIZE - 1);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (0 == memcmp(null_mac, req_mac, sizeof(n2n_mac_t))){
|
|
|
|
traceEvent(TRACE_DEBUG, "MAC address is null.");
|
|
|
|
return buf;
|
|
|
|
}
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (!(fd = fopen("/proc/net/arp", "r"))) {
|
|
|
|
traceEvent(TRACE_ERROR, "Could not open arp table. [%d]: %s", errno, strerror(errno));
|
|
|
|
return buf;
|
|
|
|
}
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
while (!feof(fd) && fgetc(fd) != '\n');
|
|
|
|
while (!feof(fd) && (fscanf(fd, " %15[0-9.] %*s %*s %17[A-Fa-f0-9:] %*s %15s", ip_str, mac_str, dev_str) == 3)) {
|
|
|
|
str2mac(mac, mac_str);
|
|
|
|
if (0 == memcmp(mac, req_mac, sizeof(n2n_mac_t))) {
|
|
|
|
strncpy(buf, ip_str, N2N_NETMASK_STR_SIZE - 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
return buf;
|
2020-08-16 16:34:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Read a datagram from the management UDP socket and take appropriate
|
|
|
|
* action. */
|
2020-08-16 16:34:41 +02:00
|
|
|
static void readFromMgmtSocket(n2n_edge_t *eee, int *keep_running) {
|
2020-10-11 11:57:48 +02:00
|
|
|
char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
|
|
|
|
ssize_t recvlen;
|
|
|
|
/* ssize_t sendlen; */
|
|
|
|
struct sockaddr_in sender_sock;
|
|
|
|
socklen_t i;
|
|
|
|
size_t msg_len;
|
|
|
|
time_t now;
|
|
|
|
struct peer_info *peer, *tmpPeer;
|
|
|
|
macstr_t mac_buf;
|
|
|
|
/* dec_ip_bit_str_t ip_bit_str = {'\0'}; */
|
|
|
|
/* dec_ip_str_t ip_str = {'\0'}; */
|
|
|
|
in_addr_t net;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
uint32_t num_pending_peers = 0;
|
|
|
|
uint32_t num_known_peers = 0;
|
|
|
|
uint32_t num = 0;
|
2020-11-11 09:27:39 +01:00
|
|
|
selection_criterion_str_t sel_buf;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
now = time(NULL);
|
|
|
|
i = sizeof(sender_sock);
|
|
|
|
recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, (socklen_t *) &i);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (recvlen < 0) {
|
|
|
|
traceEvent(TRACE_ERROR, "mgmt recvfrom failed with %s", strerror(errno));
|
|
|
|
return; /* failed to receive data from UDP */
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if ((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) {
|
|
|
|
msg_len = 0;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"Help for edge management console:\n"
|
|
|
|
"\tstop | Gracefully exit edge\n"
|
|
|
|
"\thelp | This help message\n"
|
|
|
|
"\t+verb | Increase verbosity of logging\n"
|
|
|
|
"\t-verb | Decrease verbosity of logging\n"
|
|
|
|
"\t<enter> | Display statistics\n\n");
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (0 == memcmp(udp_buf, "stop", 4)) {
|
|
|
|
traceEvent(TRACE_ERROR, "stop command received.");
|
|
|
|
*keep_running = 0;
|
|
|
|
return;
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (0 == memcmp(udp_buf, "+verb", 5)) {
|
|
|
|
msg_len = 0;
|
|
|
|
setTraceLevel(getTraceLevel() + 1);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_ERROR, "+verb traceLevel=%u", (unsigned int) getTraceLevel());
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"> +OK traceLevel=%u\n", (unsigned int) getTraceLevel());
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (0 == memcmp(udp_buf, "-verb", 5)) {
|
|
|
|
msg_len = 0;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (getTraceLevel() > 0) {
|
|
|
|
setTraceLevel(getTraceLevel() - 1);
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"> -OK traceLevel=%u\n", getTraceLevel());
|
|
|
|
} else {
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"> -NOK traceLevel=%u\n", getTraceLevel());
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_ERROR, "-verb traceLevel=%u", (unsigned int) getTraceLevel());
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
|
|
return;
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "mgmt status rq");
|
|
|
|
|
|
|
|
msg_len = 0;
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"community: %s\n",
|
|
|
|
eee->conf.community_name);
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
2020-11-10 17:58:35 +01:00
|
|
|
" id tun_tap MAC edge hint last_seen\n");
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
2020-11-10 17:58:35 +01:00
|
|
|
"-----------------------------------------------------------------------------------------------\n");
|
2020-10-11 11:57:48 +02:00
|
|
|
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"supernode_forward:\n");
|
|
|
|
num = 0;
|
|
|
|
HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) {
|
|
|
|
++num_pending_peers;
|
|
|
|
if(peer->dev_addr.net_addr == 0) continue;
|
|
|
|
net = htonl(peer->dev_addr.net_addr);
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
2020-11-09 16:06:00 +01:00
|
|
|
" %-4u %-15s %-17s %-21s %-15s %lu\n",
|
2020-10-11 11:57:48 +02:00
|
|
|
++num, inet_ntoa(*(struct in_addr *) &net),
|
|
|
|
macaddr_str(mac_buf, peer->mac_addr),
|
2020-11-10 17:58:35 +01:00
|
|
|
sock_to_cstr(sockbuf, &(peer->sock)),
|
|
|
|
peer->dev_desc,
|
|
|
|
now - peer->last_seen);
|
2020-10-11 11:57:48 +02:00
|
|
|
|
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
|
|
msg_len = 0;
|
|
|
|
}
|
2020-08-16 10:17:25 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"peer_to_peer:\n");
|
|
|
|
num = 0;
|
|
|
|
HASH_ITER(hh, eee->known_peers, peer, tmpPeer) {
|
|
|
|
++num_known_peers;
|
|
|
|
if(peer->dev_addr.net_addr == 0) continue;
|
|
|
|
net = htonl(peer->dev_addr.net_addr);
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
2020-11-09 16:06:00 +01:00
|
|
|
" %-4u %-15s %-17s %-21s %-15s %lu\n",
|
2020-10-11 11:57:48 +02:00
|
|
|
++num, inet_ntoa(*(struct in_addr *) &net),
|
|
|
|
macaddr_str(mac_buf, peer->mac_addr),
|
2020-11-10 17:58:35 +01:00
|
|
|
sock_to_cstr(sockbuf, &(peer->sock)),
|
|
|
|
peer->dev_desc,
|
|
|
|
now - peer->last_seen);
|
2020-10-11 11:57:48 +02:00
|
|
|
|
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
|
|
msg_len = 0;
|
|
|
|
}
|
2020-08-16 10:17:25 +02:00
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
// dump supernodes
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
2020-11-11 09:27:39 +01:00
|
|
|
"-----------------------------------------------------------------------------------------------\n");
|
|
|
|
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"supernodes:\n");
|
|
|
|
|
|
|
|
HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) {
|
|
|
|
net = htonl(peer->dev_addr.net_addr);
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
" %-4u %-15s %-17s %-21s %-14s %lu\n",
|
|
|
|
++num,
|
|
|
|
(peer->purgeable == SN_UNPURGEABLE)?"-l ":" ",
|
|
|
|
macaddr_str(mac_buf, peer->mac_addr),
|
|
|
|
sock_to_cstr(sockbuf, &(peer->sock)),
|
|
|
|
sn_selection_criterion_str(sel_buf, peer),
|
|
|
|
now - peer->last_seen);
|
|
|
|
|
|
|
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
|
|
msg_len = 0;
|
|
|
|
}
|
|
|
|
// end dump supernodes
|
|
|
|
|
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"-----------------------------------------------------------------------------------------------\n");
|
2020-08-16 10:17:25 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"uptime %lu | ",
|
|
|
|
time(NULL) - eee->start_time);
|
2020-08-16 10:17:25 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"pend_peers %u | ",
|
|
|
|
num_pending_peers);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"known_peers %u | ",
|
|
|
|
num_known_peers);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"transop %u,%u\n",
|
|
|
|
(unsigned int) eee->transop.tx_cnt,
|
|
|
|
(unsigned int) eee->transop.rx_cnt);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"super %u,%u | ",
|
|
|
|
(unsigned int) eee->stats.tx_sup,
|
|
|
|
(unsigned int) eee->stats.rx_sup);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"p2p %u,%u\n",
|
|
|
|
(unsigned int) eee->stats.tx_p2p,
|
|
|
|
(unsigned int) eee->stats.rx_p2p);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"last_super %ld sec ago | ",
|
|
|
|
(now - eee->last_sup));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"last_p2p %ld sec ago\n",
|
|
|
|
(now - eee->last_p2p));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
|
|
|
"\nType \"help\" to see more commands.\n\n");
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
/* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
|
|
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2019-06-08 19:54:46 +02:00
|
|
|
static int check_query_peer_info(n2n_edge_t *eee, time_t now, n2n_mac_t mac) {
|
2019-06-09 23:41:47 +02:00
|
|
|
struct peer_info *scan;
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_FIND_PEER(eee->pending_peers, mac, scan);
|
2019-06-08 19:54:46 +02:00
|
|
|
|
|
|
|
if(!scan) {
|
|
|
|
scan = calloc(1, sizeof(struct peer_info));
|
|
|
|
|
|
|
|
memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
|
2020-08-16 16:34:41 +02:00
|
|
|
scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */
|
2019-06-09 23:41:47 +02:00
|
|
|
scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */
|
2020-07-25 14:28:20 +02:00
|
|
|
scan->last_valid_time_stamp = initial_time_stamp ();
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_ADD_PEER(eee->pending_peers, scan);
|
2019-06-08 19:54:46 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 16:34:41 +02:00
|
|
|
if(now - scan->last_sent_query > eee->conf.register_interval) {
|
|
|
|
send_register(eee, &(eee->supernode), mac);
|
2019-06-08 19:54:46 +02:00
|
|
|
send_query_peer(eee, scan->mac_addr);
|
|
|
|
scan->last_sent_query = now;
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/* @return 1 if destination is a peer, 0 if destination is supernode */
|
|
|
|
static int find_peer_destination(n2n_edge_t * eee,
|
|
|
|
n2n_mac_t mac_address,
|
|
|
|
n2n_sock_t * destination) {
|
2019-06-09 23:41:47 +02:00
|
|
|
struct peer_info *scan;
|
2018-06-08 00:17:42 +02:00
|
|
|
macstr_t mac_buf;
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
int retval=0;
|
2019-05-05 23:48:48 +02:00
|
|
|
time_t now = time(NULL);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-29 13:56:22 +02:00
|
|
|
if(!memcmp(mac_address, broadcast_mac, N2N_MAC_SIZE)) {
|
2019-06-08 16:10:00 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Broadcast destination peer, using supernode");
|
|
|
|
memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in));
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X",
|
|
|
|
mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF,
|
|
|
|
mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF);
|
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_FIND_PEER(eee->known_peers, mac_address, scan);
|
|
|
|
|
|
|
|
if(scan && (scan->last_seen > 0)) {
|
|
|
|
if((now - scan->last_p2p) >= (scan->timeout / 2)) {
|
|
|
|
/* Too much time passed since we saw the peer, need to register again
|
|
|
|
* since the peer address may have changed. */
|
|
|
|
traceEvent(TRACE_DEBUG, "Refreshing idle known peer");
|
|
|
|
HASH_DEL(eee->known_peers, scan);
|
|
|
|
free(scan);
|
|
|
|
/* NOTE: registration will be performed upon the receival of the next response packet */
|
|
|
|
} else {
|
|
|
|
/* Valid known peer found */
|
|
|
|
memcpy(destination, &scan->sock, sizeof(n2n_sock_t));
|
|
|
|
retval=1;
|
2019-05-05 23:48:48 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 00:46:29 +02:00
|
|
|
if(retval == 0) {
|
2019-05-05 23:48:48 +02:00
|
|
|
memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in));
|
2019-06-08 16:10:00 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "P2P Peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X] not found, using supernode",
|
2020-07-22 16:01:54 +02:00
|
|
|
mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF,
|
|
|
|
mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF);
|
2019-06-08 19:54:46 +02:00
|
|
|
|
|
|
|
check_query_peer_info(eee, now, mac_address);
|
2019-05-23 00:46:29 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "find_peer_address (%s) -> [%s]",
|
|
|
|
macaddr_str(mac_buf, mac_address),
|
|
|
|
sock_to_cstr(sockbuf, destination));
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ***************************************************** */
|
|
|
|
|
|
|
|
/** Send an ecapsulated ethernet PACKET to a destination edge or broadcast MAC
|
|
|
|
* address. */
|
|
|
|
static int send_packet(n2n_edge_t * eee,
|
|
|
|
n2n_mac_t dstMac,
|
|
|
|
const uint8_t * pktbuf,
|
|
|
|
size_t pktlen) {
|
2019-05-05 21:47:50 +02:00
|
|
|
int is_p2p;
|
2018-06-08 00:17:42 +02:00
|
|
|
/*ssize_t s; */
|
|
|
|
n2n_sock_str_t sockbuf;
|
|
|
|
n2n_sock_t destination;
|
2019-07-15 23:21:38 +02:00
|
|
|
macstr_t mac_buf;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* hexdump(pktbuf, pktlen); */
|
|
|
|
|
2019-05-05 21:47:50 +02:00
|
|
|
is_p2p = find_peer_destination(eee, dstMac, &destination);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-05-05 21:47:50 +02:00
|
|
|
if(is_p2p)
|
|
|
|
++(eee->stats.tx_p2p);
|
2019-06-08 18:41:18 +02:00
|
|
|
else {
|
2019-05-05 21:47:50 +02:00
|
|
|
++(eee->stats.tx_sup);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-29 13:56:22 +02:00
|
|
|
if(!memcmp(dstMac, broadcast_mac, N2N_MAC_SIZE))
|
2019-06-08 18:41:18 +02:00
|
|
|
++(eee->stats.tx_sup_broadcast);
|
|
|
|
}
|
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_INFO, "Tx PACKET to %s (dest=%s) [%u B]",
|
2020-07-22 16:01:54 +02:00
|
|
|
sock_to_cstr(sockbuf, &destination),
|
|
|
|
macaddr_str(mac_buf, dstMac), pktlen);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* s = */ sendto_sock(eee->udp_sock, pktbuf, pktlen, &destination);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */
|
2020-06-30 13:01:37 +02:00
|
|
|
void edge_send_packet2net(n2n_edge_t * eee,
|
2020-07-22 16:01:54 +02:00
|
|
|
uint8_t *tap_pkt, size_t len) {
|
2018-06-08 00:17:42 +02:00
|
|
|
ipstr_t ip_buf;
|
|
|
|
n2n_mac_t destMac;
|
|
|
|
|
|
|
|
n2n_common_t cmn;
|
|
|
|
n2n_PACKET_t pkt;
|
|
|
|
|
|
|
|
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
|
|
|
size_t idx=0;
|
2019-04-27 01:56:57 +02:00
|
|
|
n2n_transform_t tx_transop_idx = eee->transop.transform_id;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
ether_hdr_t eh;
|
|
|
|
|
|
|
|
/* tap_pkt is not aligned so we have to copy to aligned memory */
|
|
|
|
memcpy(&eh, tap_pkt, sizeof(ether_hdr_t));
|
|
|
|
|
|
|
|
/* Discard IP packets that are not originated by this hosts */
|
2019-04-27 01:56:57 +02:00
|
|
|
if(!(eee->conf.allow_routing)) {
|
2018-06-08 00:17:42 +02:00
|
|
|
if(ntohs(eh.type) == 0x0800) {
|
|
|
|
/* This is an IP packet from the local source address - not forwarded. */
|
2018-10-31 13:08:39 +01:00
|
|
|
uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET];
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* Note: all elements of the_ip are in network order */
|
2018-10-31 13:08:39 +01:00
|
|
|
if(*src != eee->device.ip_addr) {
|
2018-06-08 00:17:42 +02:00
|
|
|
/* This is a packet that needs to be routed */
|
|
|
|
traceEvent(TRACE_INFO, "Discarding routed packet [%s]",
|
2018-10-31 13:08:39 +01:00
|
|
|
intoa(ntohl(*src), ip_buf, sizeof(ip_buf)));
|
2018-06-08 00:17:42 +02:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
/* This packet is originated by us */
|
|
|
|
/* traceEvent(TRACE_INFO, "Sending non-routed packet"); */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Optionally compress then apply transforms, eg encryption. */
|
|
|
|
|
|
|
|
/* Once processed, send to destination in PACKET */
|
|
|
|
|
|
|
|
memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */
|
|
|
|
|
|
|
|
memset(&cmn, 0, sizeof(cmn));
|
|
|
|
cmn.ttl = N2N_DEFAULT_TTL;
|
|
|
|
cmn.pc = n2n_packet;
|
|
|
|
cmn.flags=0; /* no options, not from supernode, no socket */
|
2019-04-27 01:56:57 +02:00
|
|
|
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
memset(&pkt, 0, sizeof(pkt));
|
|
|
|
memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE);
|
|
|
|
memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE);
|
|
|
|
|
|
|
|
pkt.sock.family=0; /* do not encode sock */
|
2019-04-27 01:56:57 +02:00
|
|
|
pkt.transform = tx_transop_idx;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-05-03 18:48:59 +02:00
|
|
|
// compression needs to be tried before encode_PACKET is called for compression indication gets encoded there
|
|
|
|
pkt.compression = N2N_COMPRESSION_ID_NONE;
|
2020-05-19 21:27:22 +02:00
|
|
|
|
2020-06-24 09:49:36 +02:00
|
|
|
if(eee->conf.compression) {
|
2020-08-06 19:28:39 +02:00
|
|
|
uint8_t * compression_buffer = NULL;
|
2020-05-19 21:27:22 +02:00
|
|
|
int32_t compression_len;
|
|
|
|
|
2020-05-03 18:48:59 +02:00
|
|
|
switch (eee->conf.compression) {
|
2020-07-22 16:01:54 +02:00
|
|
|
case N2N_COMPRESSION_ID_LZO:
|
|
|
|
compression_buffer = malloc (len + len / 16 + 64 + 3);
|
2020-06-24 09:49:36 +02:00
|
|
|
if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) {
|
|
|
|
if(compression_len < len) {
|
2020-07-22 16:01:54 +02:00
|
|
|
pkt.compression = N2N_COMPRESSION_ID_LZO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-05-19 21:27:22 +02:00
|
|
|
#ifdef N2N_HAVE_ZSTD
|
2020-07-22 16:01:54 +02:00
|
|
|
case N2N_COMPRESSION_ID_ZSTD:
|
|
|
|
compression_len = N2N_PKT_BUF_SIZE + 128;
|
|
|
|
compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower)
|
|
|
|
compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ;
|
2020-06-24 09:49:36 +02:00
|
|
|
if(!ZSTD_isError(compression_len)) {
|
|
|
|
if(compression_len < len) {
|
2020-07-22 16:01:54 +02:00
|
|
|
pkt.compression = N2N_COMPRESSION_ID_ZSTD;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
traceEvent (TRACE_ERROR, "payload compression failed with zstd error '%s'.",
|
|
|
|
ZSTD_getErrorName(compression_len));
|
|
|
|
free (compression_buffer);
|
|
|
|
// continue with unset without pkt.compression --> will send uncompressed
|
|
|
|
}
|
|
|
|
break;
|
2020-05-19 21:27:22 +02:00
|
|
|
#endif
|
2020-07-22 16:01:54 +02:00
|
|
|
default:
|
|
|
|
break;
|
2020-05-03 18:48:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-15 19:03:57 +02:00
|
|
|
if(pkt.compression != N2N_COMPRESSION_ID_NONE) {
|
2020-05-19 21:27:22 +02:00
|
|
|
traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n",
|
2020-07-22 16:01:54 +02:00
|
|
|
compression_str(pkt.compression), len, compression_len);
|
2020-05-03 18:48:59 +02:00
|
|
|
|
|
|
|
memcpy (tap_pkt, compression_buffer, compression_len);
|
|
|
|
len = compression_len;
|
2020-08-26 19:52:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(compression_buffer) {
|
2020-05-03 18:48:59 +02:00
|
|
|
free (compression_buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
idx=0;
|
|
|
|
encode_PACKET(pktbuf, &idx, &cmn, &pkt);
|
|
|
|
|
2020-06-29 12:46:44 +02:00
|
|
|
uint16_t headerIdx = idx;
|
2020-06-22 20:49:19 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
idx += eee->transop.fwd(&eee->transop,
|
2020-07-22 16:01:54 +02:00
|
|
|
pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
|
|
|
|
tap_pkt, len, pkt.dstMac);
|
2019-07-15 19:42:51 +02:00
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "Encode %u B PACKET [%u B data, %u B overhead] transform %u",
|
2020-07-22 16:01:54 +02:00
|
|
|
(u_int)idx, (u_int)len, (u_int)(idx-len), tx_transop_idx);
|
2019-07-15 19:42:51 +02:00
|
|
|
|
2020-06-29 12:46:44 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
|
|
|
packet_header_encrypt (pktbuf, headerIdx, eee->conf.header_encryption_ctx,
|
2020-10-11 11:57:48 +02:00
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
time_stamp (), pearson_hash_16 (pktbuf, idx));
|
2020-06-29 12:46:44 +02:00
|
|
|
|
2019-07-15 20:14:14 +02:00
|
|
|
#ifdef MTU_ASSERT_VALUE
|
|
|
|
{
|
2019-07-15 22:44:12 +02:00
|
|
|
const u_int eth_udp_overhead = ETH_FRAMESIZE + IP4_MIN_SIZE + UDP_SIZE;
|
2019-07-15 20:14:14 +02:00
|
|
|
|
|
|
|
// MTU assertion which avoids fragmentation by N2N
|
|
|
|
assert(idx + eth_udp_overhead <= MTU_ASSERT_VALUE);
|
|
|
|
}
|
2019-07-15 19:42:51 +02:00
|
|
|
#endif
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
eee->transop.tx_cnt++; /* stats */
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Read a single packet from the TAP interface, process it and write out the
|
|
|
|
* corresponding packet to the cooked socket.
|
|
|
|
*/
|
2020-06-30 13:01:37 +02:00
|
|
|
void edge_read_from_tap(n2n_edge_t * eee) {
|
2018-06-08 00:17:42 +02:00
|
|
|
/* tun -> remote */
|
|
|
|
uint8_t eth_pkt[N2N_PKT_BUF_SIZE];
|
|
|
|
macstr_t mac_buf;
|
|
|
|
ssize_t len;
|
|
|
|
|
2020-07-07 04:51:21 +02:00
|
|
|
len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE );
|
2018-06-08 00:17:42 +02:00
|
|
|
if((len <= 0) || (len > N2N_PKT_BUF_SIZE))
|
|
|
|
{
|
|
|
|
traceEvent(TRACE_WARNING, "read()=%d [%d/%s]",
|
2020-07-22 16:01:54 +02:00
|
|
|
(signed int)len, errno, strerror(errno));
|
2020-07-17 08:21:27 +02:00
|
|
|
traceEvent(TRACE_WARNING, "TAP I/O operation aborted, restart later.");
|
|
|
|
sleep(3);
|
2020-07-22 16:01:54 +02:00
|
|
|
tuntap_close(&(eee->device));
|
|
|
|
tuntap_open(&(eee->device), eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, eee->tuntap_priv_conf.ip_addr,
|
|
|
|
eee->tuntap_priv_conf.netmask, eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const uint8_t * mac = eth_pkt;
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "### Rx TAP packet (%4d) for %s",
|
2018-06-08 00:17:42 +02:00
|
|
|
(signed int)len, macaddr_str(mac_buf, mac));
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
if(eee->conf.drop_multicast &&
|
2018-06-08 00:17:42 +02:00
|
|
|
(is_ip6_discovery(eth_pkt, len) ||
|
|
|
|
is_ethMulticast(eth_pkt, len)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
2019-12-26 22:13:49 +01:00
|
|
|
traceEvent(TRACE_INFO, "Dropping TX multicast");
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-10 17:58:35 +01:00
|
|
|
if(eee->network_traffic_filter) {
|
|
|
|
if( eee->network_traffic_filter->filter_packet_from_tap( eee->network_traffic_filter, eee, eth_pkt,
|
|
|
|
len) == N2N_DROP){
|
2020-11-10 16:35:05 +01:00
|
|
|
traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)len);
|
|
|
|
return;
|
2020-11-10 17:58:35 +01:00
|
|
|
}
|
|
|
|
}
|
2020-11-16 21:27:42 +01:00
|
|
|
|
2020-06-30 13:01:37 +02:00
|
|
|
if(eee->cb.packet_from_tap) {
|
2020-07-03 05:50:47 +02:00
|
|
|
uint16_t tmp_len = len;
|
|
|
|
if(eee->cb.packet_from_tap(eee, eth_pkt, &tmp_len) == N2N_DROP) {
|
2020-06-30 13:01:37 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)len);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2020-07-03 05:50:47 +02:00
|
|
|
len = tmp_len;
|
2020-06-30 13:01:37 +02:00
|
|
|
}
|
2020-12-02 08:33:10 +01:00
|
|
|
|
|
|
|
if (!eee->last_sup) {
|
2020-11-16 21:38:37 +01:00
|
|
|
// drop packets before first registration with supernode
|
|
|
|
traceEvent(TRACE_DEBUG, "DROP packet before first registration with supernode");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-30 13:01:37 +02:00
|
|
|
edge_send_packet2net(eee, eth_pkt, len);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 00:30:11 +02:00
|
|
|
/* ************************************** */
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/** Read a datagram from the main UDP socket to the internet. */
|
2020-08-08 16:40:45 +02:00
|
|
|
void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
2018-06-08 00:17:42 +02:00
|
|
|
n2n_common_t cmn; /* common fields in the packet header */
|
|
|
|
|
|
|
|
n2n_sock_str_t sockbuf1;
|
|
|
|
n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
|
|
|
|
macstr_t mac_buf1;
|
|
|
|
macstr_t mac_buf2;
|
|
|
|
uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
|
|
|
|
ssize_t recvlen;
|
|
|
|
size_t rem;
|
|
|
|
size_t idx;
|
|
|
|
size_t msg_type;
|
|
|
|
uint8_t from_supernode;
|
|
|
|
struct sockaddr_in sender_sock;
|
|
|
|
n2n_sock_t sender;
|
|
|
|
n2n_sock_t * orig_sender=NULL;
|
|
|
|
time_t now=0;
|
2020-11-19 09:31:24 +01:00
|
|
|
uint64_t stamp = 0;
|
2020-11-11 09:27:39 +01:00
|
|
|
size_t i;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
i = sizeof(sender_sock);
|
2018-09-29 00:32:36 +02:00
|
|
|
recvlen = recvfrom(in_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/,
|
2020-11-11 09:27:39 +01:00
|
|
|
(struct sockaddr *)&sender_sock, (socklen_t*)&i);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
if(recvlen < 0) {
|
2019-03-27 01:13:58 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
if(WSAGetLastError() != WSAECONNRESET)
|
|
|
|
#endif
|
2020-07-22 16:01:54 +02:00
|
|
|
{
|
|
|
|
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", recvlen, errno, strerror(errno));
|
2019-03-27 01:13:58 +01:00
|
|
|
#ifdef WIN32
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
|
2019-03-27 01:13:58 +01:00
|
|
|
#endif
|
2020-07-22 16:01:54 +02:00
|
|
|
}
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
return; /* failed to receive data from UDP */
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which
|
|
|
|
* IP transport version the packet arrived on. May need to UDP sockets. */
|
2020-10-27 17:02:35 +01:00
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
memset(&sender, 0, sizeof(n2n_sock_t));
|
2020-10-27 17:02:35 +01:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */
|
2018-06-08 00:17:42 +02:00
|
|
|
sender.port = ntohs(sender_sock.sin_port);
|
|
|
|
memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE);
|
|
|
|
|
|
|
|
/* The packet may not have an orig_sender socket spec. So default to last
|
|
|
|
* hop as sender. */
|
|
|
|
orig_sender=&sender;
|
|
|
|
|
2019-07-15 23:21:38 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s",
|
2018-06-08 00:17:42 +02:00
|
|
|
(signed int)recvlen, sock_to_cstr(sockbuf1, &sender));
|
|
|
|
|
2020-06-29 15:35:40 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
uint16_t checksum = 0;
|
|
|
|
if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx,
|
2020-07-23 12:21:54 +02:00
|
|
|
eee->conf.header_iv_ctx,
|
|
|
|
&stamp, &checksum) == 0) {
|
2020-06-22 20:49:19 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header.");
|
|
|
|
return;
|
|
|
|
}
|
2020-07-23 12:21:54 +02:00
|
|
|
|
|
|
|
// time stamp verification follows in the packet specific section as it requires to determine the
|
|
|
|
// sender from the hash list by its MAC, or the packet might be from the supernode, this all depends
|
|
|
|
// on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place)
|
|
|
|
|
2020-06-29 15:35:40 +02:00
|
|
|
if (checksum != pearson_hash_16 (udp_buf, recvlen)) {
|
2020-07-04 11:25:58 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error.");
|
|
|
|
return;
|
2020-06-29 15:35:40 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-22 20:49:19 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */
|
|
|
|
idx = 0; /* marches through packet header as parts are decoded. */
|
|
|
|
if(decode_common(&cmn, udp_buf, &rem, &idx) < 0)
|
|
|
|
{
|
|
|
|
traceEvent(TRACE_ERROR, "Failed to decode common section in N2N_UDP");
|
|
|
|
return; /* failed to decode packet */
|
|
|
|
}
|
|
|
|
|
|
|
|
now = time(NULL);
|
|
|
|
|
|
|
|
msg_type = cmn.pc; /* packet code */
|
|
|
|
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
switch(msg_type) {
|
|
|
|
case MSG_TYPE_PACKET:
|
2019-05-05 19:09:51 +02:00
|
|
|
{
|
2020-10-11 11:57:48 +02:00
|
|
|
/* process PACKET - most frequent so first in list. */
|
|
|
|
n2n_PACKET_t pkt;
|
|
|
|
|
|
|
|
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
|
|
|
|
|
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
if(!find_peer_time_stamp_and_verify (eee, from_supernode, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) {
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET due to time stamp error.");
|
|
|
|
return;
|
2019-05-26 03:49:42 +02:00
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
2020-12-02 08:33:10 +01:00
|
|
|
|
|
|
|
if (!eee->last_sup) {
|
2020-11-16 21:38:37 +01:00
|
|
|
// drop packets received before first registration with supernode
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET recevied before first registration with supernode.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(is_valid_peer_sock(&pkt.sock))
|
|
|
|
orig_sender = &(pkt.sock);
|
2020-08-16 16:34:41 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(!from_supernode) {
|
|
|
|
/* This is a P2P packet from the peer. We purge a pending
|
|
|
|
* registration towards the possibly nat-ted peer address as we now have
|
|
|
|
* a valid channel. We still use check_peer_registration_needed in
|
|
|
|
* handle_PACKET to double check this.
|
|
|
|
*/
|
|
|
|
traceEvent(TRACE_DEBUG, "Got P2P packet");
|
|
|
|
traceEvent(TRACE_DEBUG, "[P2P] Rx data from %s [%u B]", sock_to_cstr(sockbuf1, &sender), recvlen);
|
|
|
|
find_and_remove_peer(&eee->pending_peers, pkt.srcMac);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* [PsP] : edge Peer->Supernode->edge Peer */
|
|
|
|
traceEvent(TRACE_DEBUG, "[PsP] Rx data from %s (Via=%s) [%u B]",
|
|
|
|
sock_to_cstr(sockbuf2, orig_sender), sock_to_cstr(sockbuf1, &sender), recvlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the sender in peer table entry */
|
2020-10-26 21:13:56 +01:00
|
|
|
check_peer_registration_needed(eee, from_supernode, pkt.srcMac, NULL, NULL, orig_sender);
|
2020-10-11 11:57:48 +02:00
|
|
|
|
|
|
|
handle_PACKET(eee, from_supernode, &pkt, orig_sender, udp_buf+idx, recvlen-idx);
|
2020-07-22 16:01:54 +02:00
|
|
|
break;
|
2019-05-05 19:09:51 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
case MSG_TYPE_REGISTER:
|
2019-05-05 19:09:51 +02:00
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
/* Another edge is registering with us */
|
|
|
|
n2n_REGISTER_t reg;
|
|
|
|
int via_multicast;
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
decode_REGISTER(®, &cmn, udp_buf, &rem, &idx);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
if(!find_peer_time_stamp_and_verify (eee, from_supernode, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) {
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER due to time stamp error.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-07-25 14:28:20 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(is_valid_peer_sock(®.sock))
|
|
|
|
orig_sender = &(reg.sock);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-29 13:56:22 +02:00
|
|
|
via_multicast = !memcmp(reg.dstMac, null_mac, N2N_MAC_SIZE);
|
2019-06-08 16:10:00 +02:00
|
|
|
|
2020-07-29 13:56:22 +02:00
|
|
|
if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, N2N_MAC_SIZE)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Skipping REGISTER from self");
|
|
|
|
break;
|
|
|
|
}
|
2019-06-08 16:10:00 +02:00
|
|
|
|
2020-07-29 13:56:22 +02:00
|
|
|
if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, N2N_MAC_SIZE)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "Skipping REGISTER for other peer");
|
|
|
|
break;
|
|
|
|
}
|
2019-06-10 00:32:38 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if(!from_supernode) {
|
|
|
|
/* This is a P2P registration from the peer. We purge a pending
|
|
|
|
* registration towards the possibly nat-ted peer address as we now have
|
|
|
|
* a valid channel. We still use check_peer_registration_needed below
|
|
|
|
* to double check this.
|
|
|
|
*/
|
|
|
|
traceEvent(TRACE_DEBUG, "Got P2P register");
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_INFO, "[P2P] Rx REGISTER from %s", sock_to_cstr(sockbuf1, &sender));
|
|
|
|
find_and_remove_peer(&eee->pending_peers, reg.srcMac);
|
2020-07-22 16:01:54 +02:00
|
|
|
|
|
|
|
/* NOTE: only ACK to peers */
|
|
|
|
send_register_ack(eee, orig_sender, ®);
|
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
else {
|
|
|
|
traceEvent(TRACE_INFO, "[PsP] Rx REGISTER src=%s dst=%s from sn=%s (edge:%s)",
|
|
|
|
macaddr_str(mac_buf1, reg.srcMac), macaddr_str(mac_buf2, reg.dstMac),
|
|
|
|
sock_to_cstr(sockbuf1, &sender), sock_to_cstr(sockbuf2, orig_sender));
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-11-10 18:10:20 +01:00
|
|
|
check_peer_registration_needed(eee, from_supernode, reg.srcMac, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender);
|
2020-07-22 16:01:54 +02:00
|
|
|
break;
|
2019-05-05 19:09:51 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
case MSG_TYPE_REGISTER_ACK:
|
2019-05-05 19:09:51 +02:00
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
/* Peer edge is acknowledging our register request */
|
|
|
|
n2n_REGISTER_ACK_t ra;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
if(!find_peer_time_stamp_and_verify (eee, !definitely_from_supernode, ra.srcMac, stamp, TIME_STAMP_NO_JITTER)) {
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_ACK due to time stamp error.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-07-25 14:28:20 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(is_valid_peer_sock(&ra.sock))
|
|
|
|
orig_sender = &(ra.sock);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)",
|
|
|
|
macaddr_str(mac_buf1, ra.srcMac),
|
|
|
|
macaddr_str(mac_buf2, ra.dstMac),
|
|
|
|
sock_to_cstr(sockbuf1, &sender),
|
|
|
|
sock_to_cstr(sockbuf2, orig_sender));
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now);
|
|
|
|
break;
|
2019-05-05 19:09:51 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
case MSG_TYPE_REGISTER_SUPER_ACK:
|
2019-05-05 19:09:51 +02:00
|
|
|
{
|
2020-10-11 11:57:48 +02:00
|
|
|
in_addr_t net;
|
|
|
|
char * ip_str = NULL;
|
|
|
|
n2n_REGISTER_SUPER_ACK_t ra;
|
2020-11-10 17:58:35 +01:00
|
|
|
uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE];
|
2020-11-13 10:55:00 +01:00
|
|
|
n2n_REGISTER_SUPER_ACK_payload_t *payload;
|
2020-11-10 17:58:35 +01:00
|
|
|
int i;
|
|
|
|
int skip_add;
|
|
|
|
struct peer_info *sn;
|
2020-08-08 16:40:45 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
|
2020-08-08 16:40:45 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
// Indicates successful connection between the edge and SN nodes
|
2020-07-29 07:24:36 +02:00
|
|
|
static int bTrace = 1;
|
|
|
|
if (bTrace)
|
2020-10-11 11:57:48 +02:00
|
|
|
{
|
|
|
|
traceEvent(TRACE_NORMAL, "[OK] Edge Peer <<< ================ >>> Super Node");
|
|
|
|
bTrace = 0;
|
|
|
|
}
|
2020-07-29 07:24:36 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->sn_wait)
|
|
|
|
{
|
2020-10-11 21:54:06 +02:00
|
|
|
decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx, tmpbuf);
|
2020-07-25 14:28:20 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_NO_JITTER)) {
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_SUPER_ACK due to time stamp error.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(is_valid_peer_sock(&ra.sock))
|
|
|
|
orig_sender = &(ra.sock);
|
2019-06-08 19:54:46 +02:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u",
|
|
|
|
macaddr_str(mac_buf1, ra.edgeMac),
|
|
|
|
sock_to_cstr(sockbuf1, &sender),
|
|
|
|
sock_to_cstr(sockbuf2, orig_sender),
|
|
|
|
(unsigned int)eee->sup_attempts);
|
|
|
|
|
|
|
|
if(memcmp(ra.edgeMac, eee->device.mac_addr, N2N_MAC_SIZE)) {
|
|
|
|
traceEvent(TRACE_INFO, "readFromIPSocket dropped REGISTER_SUPER_ACK due to wrong addressing.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
if(0 == memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE))
|
2020-10-11 11:57:48 +02:00
|
|
|
{
|
2020-11-13 10:55:00 +01:00
|
|
|
payload = (n2n_REGISTER_SUPER_ACK_payload_t*)tmpbuf;
|
2020-11-09 16:06:00 +01:00
|
|
|
|
|
|
|
for(i=0; i<ra.num_sn; i++){
|
2020-11-10 16:34:49 +01:00
|
|
|
skip_add = SN_ADD;
|
2020-11-13 10:55:00 +01:00
|
|
|
sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &(payload->sock), &(payload->mac), &skip_add);
|
2020-11-09 16:06:00 +01:00
|
|
|
|
2020-11-10 16:34:49 +01:00
|
|
|
if(skip_add == SN_ADD_ADDED){
|
2020-11-09 16:06:00 +01:00
|
|
|
sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE);
|
|
|
|
if(sn->ip_addr != NULL){
|
2020-11-13 10:55:00 +01:00
|
|
|
inet_ntop(payload->sock.family,
|
|
|
|
(payload->sock.family == AF_INET)?(void*)&(payload->sock.addr.v4):(void*)&(payload->sock.addr.v6),
|
2020-11-09 16:06:00 +01:00
|
|
|
sn->ip_addr, N2N_EDGE_SN_HOST_SIZE-1);
|
2020-11-13 10:55:00 +01:00
|
|
|
sprintf (sn->ip_addr, "%s:%u", sn->ip_addr, (uint16_t)(payload->sock.port));
|
|
|
|
//sock_to_cstr(sn->ip_addr, payload->sock);
|
2020-11-09 16:06:00 +01:00
|
|
|
}
|
2020-11-11 09:27:39 +01:00
|
|
|
sn_selection_criterion_default(&(sn->selection_criterion));
|
|
|
|
sn->last_seen = now - LAST_SEEN_SN_NEW;
|
2020-11-09 16:06:00 +01:00
|
|
|
sn->last_valid_time_stamp = initial_time_stamp();
|
|
|
|
traceEvent(TRACE_NORMAL, "Supernode '%s' added to the list of supernodes.", sn->ip_addr);
|
|
|
|
}
|
2020-11-13 10:55:00 +01:00
|
|
|
// shfiting to the next payload entry
|
|
|
|
payload++;
|
2020-11-10 17:58:35 +01:00
|
|
|
}
|
2020-12-02 08:33:10 +01:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if (eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) {
|
|
|
|
if ((ra.dev_addr.net_addr != 0) && (ra.dev_addr.net_bitlen != 0)) {
|
|
|
|
net = htonl(ra.dev_addr.net_addr);
|
|
|
|
if ((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) {
|
|
|
|
strncpy(eee->tuntap_priv_conf.ip_addr, ip_str,
|
|
|
|
N2N_NETMASK_STR_SIZE);
|
|
|
|
}
|
|
|
|
net = htonl(bitlen2mask(ra.dev_addr.net_bitlen));
|
|
|
|
if ((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) {
|
|
|
|
strncpy(eee->tuntap_priv_conf.netmask, ip_str,
|
|
|
|
N2N_NETMASK_STR_SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-02 08:33:10 +01:00
|
|
|
|
|
|
|
if (!eee->last_sup) // send gratuitous ARP only upon first registration with supernode
|
2020-11-16 21:38:37 +01:00
|
|
|
send_grat_arps(eee);
|
|
|
|
|
|
|
|
eee->last_sup = now;
|
|
|
|
eee->sn_wait=0;
|
|
|
|
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */
|
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->cb.sn_registration_updated)
|
|
|
|
eee->cb.sn_registration_updated(eee, now, &sender);
|
|
|
|
|
|
|
|
/* NOTE: the register_interval should be chosen by the edge node
|
|
|
|
* based on its NAT configuration. */
|
|
|
|
//eee->conf.register_interval = ra.lifetime;
|
2020-10-27 17:02:35 +01:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER.");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-11-19 09:31:24 +01:00
|
|
|
case MSG_TYPE_REGISTER_SUPER_NAK: {
|
|
|
|
n2n_REGISTER_SUPER_NAK_t nak;
|
|
|
|
struct peer_info *peer, *scan;
|
|
|
|
|
|
|
|
memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t));
|
|
|
|
|
|
|
|
decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx);
|
|
|
|
|
|
|
|
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK");
|
|
|
|
|
|
|
|
if((memcmp(&(nak.srcMac), &(eee->device.mac_addr), sizeof(n2n_mac_t))) == 0){
|
|
|
|
traceEvent(TRACE_ERROR, "%s is already used. Stopping the program.", macaddr_str(mac_buf1, nak.srcMac));
|
|
|
|
exit(1);
|
|
|
|
} else {
|
|
|
|
HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer);
|
|
|
|
if(peer != NULL){
|
|
|
|
HASH_DEL(eee->known_peers, peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan);
|
|
|
|
if(scan != NULL){
|
|
|
|
HASH_DEL(eee->pending_peers, scan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
case MSG_TYPE_PEER_INFO: {
|
|
|
|
n2n_PEER_INFO_t pi;
|
|
|
|
struct peer_info * scan;
|
2020-10-27 17:02:35 +01:00
|
|
|
int skip_add;
|
2020-11-11 09:27:39 +01:00
|
|
|
SN_SELECTION_CRITERION_DATA_TYPE data;
|
2020-10-27 17:02:35 +01:00
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx );
|
|
|
|
|
|
|
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
|
|
|
if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_ALLOW_JITTER)) {
|
|
|
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PEER_INFO due to time stamp error.");
|
|
|
|
return;
|
2020-07-22 16:01:54 +02:00
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!is_valid_peer_sock(&pi.sock)) {
|
2020-11-09 16:06:00 +01:00
|
|
|
traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]",
|
|
|
|
sock_to_cstr(sockbuf1, &pi.sock),
|
|
|
|
macaddr_str(mac_buf1, pi.mac) );
|
|
|
|
break;
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
if(memcmp(pi.mac, null_mac, sizeof(n2n_mac_t)) == 0){
|
2020-11-10 16:34:49 +01:00
|
|
|
skip_add = SN_ADD_SKIP;
|
2020-10-27 17:02:35 +01:00
|
|
|
scan = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, &pi.srcMac, &skip_add);
|
|
|
|
if(scan != NULL){
|
2020-11-11 09:27:39 +01:00
|
|
|
scan->last_seen = now;
|
|
|
|
/* The data type depends on the actual selection strategy that has been chosen. */
|
|
|
|
sn_selection_criterion_calculate(eee, scan, &pi.data);
|
2020-10-27 17:02:35 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
} else {
|
2020-10-27 17:02:35 +01:00
|
|
|
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
|
|
|
|
|
|
|
|
if(scan) {
|
2020-11-09 16:06:00 +01:00
|
|
|
scan->sock = pi.sock;
|
|
|
|
traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s",
|
|
|
|
macaddr_str(mac_buf1, pi.mac),
|
|
|
|
sock_to_cstr(sockbuf1, &pi.sock));
|
2020-10-11 11:57:48 +02:00
|
|
|
|
2020-11-09 16:06:00 +01:00
|
|
|
send_register(eee, &scan->sock, scan->mac_addr);
|
2020-10-27 17:02:35 +01:00
|
|
|
|
|
|
|
} else {
|
2020-11-09 16:06:00 +01:00
|
|
|
traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s",
|
|
|
|
macaddr_str(mac_buf1, pi.mac) );
|
2020-10-27 17:02:35 +01:00
|
|
|
}
|
|
|
|
}
|
2020-10-11 11:57:48 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
default:
|
|
|
|
/* Not a known message type */
|
|
|
|
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
|
|
|
|
return;
|
|
|
|
} /* switch(msg_type) */
|
2020-06-24 09:49:36 +02:00
|
|
|
} else if(from_supernode) /* if(community match) */
|
2019-05-22 22:40:42 +02:00
|
|
|
traceEvent(TRACE_WARNING, "Received packet with unknown community");
|
|
|
|
else
|
|
|
|
traceEvent(TRACE_INFO, "Ignoring packet with unknown community");
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
2019-05-05 21:47:50 +02:00
|
|
|
|
|
|
|
void print_edge_stats(const n2n_edge_t *eee) {
|
|
|
|
const struct n2n_edge_stats *s = &eee->stats;
|
|
|
|
|
|
|
|
traceEvent(TRACE_NORMAL, "**********************************");
|
|
|
|
traceEvent(TRACE_NORMAL, "Packet stats:");
|
|
|
|
traceEvent(TRACE_NORMAL, " TX P2P: %u pkts", s->tx_p2p);
|
|
|
|
traceEvent(TRACE_NORMAL, " RX P2P: %u pkts", s->rx_p2p);
|
2019-06-08 18:41:18 +02:00
|
|
|
traceEvent(TRACE_NORMAL, " TX Supernode: %u pkts (%u broadcast)", s->tx_sup, s->tx_sup_broadcast);
|
|
|
|
traceEvent(TRACE_NORMAL, " RX Supernode: %u pkts (%u broadcast)", s->rx_sup, s->rx_sup_broadcast);
|
2019-05-05 21:47:50 +02:00
|
|
|
traceEvent(TRACE_NORMAL, "**********************************");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2018-06-08 12:01:03 +02:00
|
|
|
int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
2018-06-08 00:17:42 +02:00
|
|
|
size_t numPurged;
|
|
|
|
time_t lastIfaceCheck=0;
|
|
|
|
time_t lastTransop=0;
|
2019-05-17 20:06:14 +02:00
|
|
|
time_t last_purge_known = 0;
|
|
|
|
time_t last_purge_pending = 0;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2019-07-01 00:25:41 +02:00
|
|
|
struct tunread_arg arg;
|
|
|
|
arg.eee = eee;
|
|
|
|
arg.keep_running = keep_running;
|
|
|
|
HANDLE tun_read_thread = startTunReadThread(&arg);
|
2018-06-08 00:17:42 +02:00
|
|
|
#endif
|
|
|
|
|
2018-06-08 12:01:03 +02:00
|
|
|
*keep_running = 1;
|
2019-04-14 18:08:51 +02:00
|
|
|
update_supernode_reg(eee, time(NULL));
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
/* Main loop
|
|
|
|
*
|
|
|
|
* select() is used to wait for input on either the TAP fd or the UDP/TCP
|
|
|
|
* socket. When input is present the data is read and processed by either
|
2020-06-30 13:01:37 +02:00
|
|
|
* readFromIPSocket() or edge_read_from_tap()
|
2018-06-08 00:17:42 +02:00
|
|
|
*/
|
|
|
|
|
2018-06-11 20:59:13 +02:00
|
|
|
while(*keep_running) {
|
2018-06-08 00:17:42 +02:00
|
|
|
int rc, max_sock = 0;
|
|
|
|
fd_set socket_mask;
|
|
|
|
struct timeval wait_time;
|
|
|
|
time_t nowTime;
|
|
|
|
|
|
|
|
FD_ZERO(&socket_mask);
|
|
|
|
FD_SET(eee->udp_sock, &socket_mask);
|
|
|
|
FD_SET(eee->udp_mgmt_sock, &socket_mask);
|
|
|
|
max_sock = max(eee->udp_sock, eee->udp_mgmt_sock);
|
2019-06-22 16:50:11 +02:00
|
|
|
|
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
2018-09-29 00:32:36 +02:00
|
|
|
FD_SET(eee->udp_multicast_sock, &socket_mask);
|
|
|
|
max_sock = max(eee->udp_sock, eee->udp_multicast_sock);
|
2019-06-22 16:50:11 +02:00
|
|
|
#endif
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
#ifndef WIN32
|
|
|
|
FD_SET(eee->device.fd, &socket_mask);
|
|
|
|
max_sock = max(max_sock, eee->device.fd);
|
|
|
|
#endif
|
|
|
|
|
2020-11-11 09:27:39 +01:00
|
|
|
wait_time.tv_sec = (eee->sn_wait)?(SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1):(SOCKET_TIMEOUT_INTERVAL_SECS);
|
|
|
|
wait_time.tv_usec = 0;
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time);
|
2020-11-11 09:27:39 +01:00
|
|
|
nowTime = time(NULL);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* Make sure ciphers are updated before the packet is treated. */
|
2018-09-29 00:32:36 +02:00
|
|
|
if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) {
|
|
|
|
lastTransop = nowTime;
|
2019-04-27 12:42:06 +02:00
|
|
|
|
|
|
|
eee->transop.tick(&eee->transop, nowTime);
|
2018-09-29 00:32:36 +02:00
|
|
|
}
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
if(rc > 0) {
|
|
|
|
/* Any or all of the FDs could have input; check them all. */
|
|
|
|
|
|
|
|
if(FD_ISSET(eee->udp_sock, &socket_mask)) {
|
|
|
|
/* Read a cooked socket from the internet socket (unicast). Writes on the TAP
|
|
|
|
* socket. */
|
|
|
|
readFromIPSocket(eee, eee->udp_sock);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
2019-06-22 16:50:11 +02:00
|
|
|
|
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
2018-09-29 00:32:36 +02:00
|
|
|
if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) {
|
2020-07-22 16:01:54 +02:00
|
|
|
/* Read a cooked socket from the internet socket (multicast). Writes on the TAP
|
|
|
|
* socket. */
|
|
|
|
traceEvent(TRACE_DEBUG, "Received packet from multicast socket");
|
|
|
|
readFromIPSocket(eee, eee->udp_multicast_sock);
|
2018-09-29 00:32:36 +02:00
|
|
|
}
|
2019-06-22 16:50:11 +02:00
|
|
|
#endif
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2018-09-29 00:32:36 +02:00
|
|
|
if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) {
|
|
|
|
/* Read a cooked socket from the internet socket. Writes on the TAP
|
|
|
|
* socket. */
|
|
|
|
readFromMgmtSocket(eee, keep_running);
|
2020-07-01 12:05:19 +02:00
|
|
|
|
|
|
|
if(!(*keep_running))
|
|
|
|
break;
|
2018-09-29 00:32:36 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
#ifndef WIN32
|
2018-09-29 00:32:36 +02:00
|
|
|
if(FD_ISSET(eee->device.fd, &socket_mask)) {
|
|
|
|
/* Read an ethernet frame from the TAP socket. Write on the IP
|
|
|
|
* socket. */
|
2020-06-30 13:01:37 +02:00
|
|
|
edge_read_from_tap(eee);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
2018-09-29 00:32:36 +02:00
|
|
|
#endif
|
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
/* Finished processing select data. */
|
|
|
|
update_supernode_reg(eee, nowTime);
|
|
|
|
|
2020-10-01 16:23:10 +02:00
|
|
|
numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known, PURGE_REGISTRATION_FREQUENCY);
|
|
|
|
numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending, PURGE_REGISTRATION_FREQUENCY);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
if(numPurged > 0) {
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u",
|
2019-06-08 15:32:47 +02:00
|
|
|
numPurged,
|
2019-06-09 23:41:47 +02:00
|
|
|
HASH_COUNT(eee->pending_peers),
|
|
|
|
HASH_COUNT(eee->known_peers));
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
|
|
|
|
2020-08-08 16:40:45 +02:00
|
|
|
if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) &&
|
2018-06-08 00:17:42 +02:00
|
|
|
((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
|
2020-06-30 13:01:37 +02:00
|
|
|
uint32_t old_ip = eee->device.ip_addr;
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address.");
|
|
|
|
tuntap_get_address(&(eee->device));
|
|
|
|
lastIfaceCheck = nowTime;
|
2020-06-30 13:01:37 +02:00
|
|
|
|
|
|
|
if((old_ip != eee->device.ip_addr) && eee->cb.ip_address_changed)
|
|
|
|
eee->cb.ip_address_changed(eee, old_ip, eee->device.ip_addr);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
2018-06-11 20:59:13 +02:00
|
|
|
|
2020-07-21 09:04:16 +02:00
|
|
|
if (eee->cb.main_loop_period)
|
|
|
|
eee->cb.main_loop_period(eee, nowTime);
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
sort_supernodes(eee, nowTime);
|
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
} /* while */
|
|
|
|
|
2019-07-01 07:15:13 +02:00
|
|
|
#ifdef WIN32
|
2019-07-01 00:25:41 +02:00
|
|
|
WaitForSingleObject(tun_read_thread, INFINITE);
|
|
|
|
#endif
|
|
|
|
|
2020-11-19 09:31:24 +01:00
|
|
|
send_unregister_super(eee);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
|
|
|
closesocket(eee->udp_sock);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/** Deinitialise the edge and deallocate any owned memory. */
|
|
|
|
void edge_term(n2n_edge_t * eee) {
|
2020-11-19 09:31:24 +01:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
if(eee->udp_sock >= 0)
|
|
|
|
closesocket(eee->udp_sock);
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-06-08 00:17:42 +02:00
|
|
|
if(eee->udp_mgmt_sock >= 0)
|
2019-06-08 15:32:47 +02:00
|
|
|
closesocket(eee->udp_mgmt_sock);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-06-22 16:50:11 +02:00
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
2018-09-29 00:32:36 +02:00
|
|
|
if(eee->udp_multicast_sock >= 0)
|
2019-06-08 15:32:47 +02:00
|
|
|
closesocket(eee->udp_multicast_sock);
|
2019-06-22 16:50:11 +02:00
|
|
|
#endif
|
2018-09-29 00:32:36 +02:00
|
|
|
|
2019-06-09 23:41:47 +02:00
|
|
|
clear_peer_list(&eee->pending_peers);
|
|
|
|
clear_peer_list(&eee->known_peers);
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
eee->transop.deinit(&eee->transop);
|
2020-05-23 14:33:10 +02:00
|
|
|
|
|
|
|
edge_cleanup_routes(eee);
|
|
|
|
|
2020-11-10 16:35:05 +01:00
|
|
|
destroy_network_traffic_filter(eee->network_traffic_filter);
|
2020-11-16 21:27:42 +01:00
|
|
|
|
2020-07-20 06:08:13 +02:00
|
|
|
closeTraceFile();
|
|
|
|
|
2019-05-21 22:53:55 +02:00
|
|
|
free(eee);
|
2018-06-11 20:59:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-07-16 00:37:52 +02:00
|
|
|
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos) {
|
2019-09-21 19:25:56 +02:00
|
|
|
int sockopt;
|
|
|
|
|
2020-10-11 11:57:48 +02:00
|
|
|
if(eee->udp_sock >= 0)
|
2020-08-20 21:08:27 +02:00
|
|
|
closesocket(eee->udp_sock);
|
|
|
|
|
|
|
|
if(eee->udp_mgmt_sock >= 0)
|
|
|
|
closesocket(eee->udp_mgmt_sock);
|
|
|
|
|
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
|
|
|
if(eee->udp_multicast_sock >= 0)
|
|
|
|
closesocket(eee->udp_multicast_sock);
|
|
|
|
#endif
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
if(udp_local_port > 0)
|
|
|
|
traceEvent(TRACE_NORMAL, "Binding to local port %d", udp_local_port);
|
|
|
|
|
2019-04-14 17:21:47 +02:00
|
|
|
eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */);
|
|
|
|
if(eee->udp_sock < 0) {
|
|
|
|
traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port);
|
2018-06-08 00:17:42 +02:00
|
|
|
return(-1);
|
2019-04-14 17:21:47 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-07-16 00:37:52 +02:00
|
|
|
if(tos) {
|
|
|
|
/* https://www.tucny.com/Home/dscp-tos */
|
2019-09-21 19:25:56 +02:00
|
|
|
sockopt = tos;
|
2019-07-16 00:37:52 +02:00
|
|
|
|
2020-07-01 12:35:22 +02:00
|
|
|
if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_TOS, (char *)&sockopt, sizeof(sockopt)) == 0)
|
2019-07-16 00:37:52 +02:00
|
|
|
traceEvent(TRACE_NORMAL, "TOS set to 0x%x", tos);
|
|
|
|
else
|
|
|
|
traceEvent(TRACE_ERROR, "Could not set TOS 0x%x[%d]: %s", tos, errno, strerror(errno));
|
|
|
|
}
|
2019-08-16 16:55:40 +02:00
|
|
|
|
2019-11-03 15:54:34 +01:00
|
|
|
#ifdef IP_PMTUDISC_DO
|
2019-09-21 19:25:56 +02:00
|
|
|
sockopt = (eee->conf.disable_pmtu_discovery) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO;
|
2019-08-16 16:55:40 +02:00
|
|
|
|
2019-09-21 19:25:56 +02:00
|
|
|
if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt, sizeof(sockopt)) < 0)
|
|
|
|
traceEvent(TRACE_WARNING, "Could not %s PMTU discovery[%d]: %s",
|
2020-07-22 16:01:54 +02:00
|
|
|
(eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno));
|
2019-09-21 19:25:56 +02:00
|
|
|
else
|
|
|
|
traceEvent(TRACE_DEBUG, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled");
|
2019-09-24 09:50:29 +02:00
|
|
|
#endif
|
2019-07-16 00:37:52 +02:00
|
|
|
|
2019-04-14 17:21:47 +02:00
|
|
|
eee->udp_mgmt_sock = open_socket(mgmt_port, 0 /* bind LOOPBACK */);
|
|
|
|
if(eee->udp_mgmt_sock < 0) {
|
|
|
|
traceEvent(TRACE_ERROR, "Failed to bind management UDP port %u", mgmt_port);
|
2019-01-28 00:27:54 +01:00
|
|
|
return(-2);
|
2019-04-14 17:21:47 +02:00
|
|
|
}
|
2018-06-08 00:17:42 +02:00
|
|
|
|
2019-06-22 16:50:11 +02:00
|
|
|
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
|
|
|
/* Populate the multicast group for local edge */
|
|
|
|
eee->multicast_peer.family = AF_INET;
|
|
|
|
eee->multicast_peer.port = N2N_MULTICAST_PORT;
|
|
|
|
eee->multicast_peer.addr.v4[0] = 224; /* N2N_MULTICAST_GROUP */
|
|
|
|
eee->multicast_peer.addr.v4[1] = 0;
|
|
|
|
eee->multicast_peer.addr.v4[2] = 0;
|
|
|
|
eee->multicast_peer.addr.v4[3] = 68;
|
|
|
|
|
2019-04-14 17:21:47 +02:00
|
|
|
eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */);
|
|
|
|
if(eee->udp_multicast_sock < 0)
|
|
|
|
return(-3);
|
2018-09-29 00:32:36 +02:00
|
|
|
else {
|
2018-09-29 11:19:36 +02:00
|
|
|
u_int enable_reuse = 1;
|
2019-06-08 15:32:47 +02:00
|
|
|
|
2018-09-29 11:19:36 +02:00
|
|
|
/* allow multiple sockets to use the same PORT number */
|
2019-06-03 18:09:15 +02:00
|
|
|
setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable_reuse, sizeof(enable_reuse));
|
2019-03-01 20:34:44 +01:00
|
|
|
#ifdef SO_REUSEPORT /* no SO_REUSEPORT in Windows / old linux versions */
|
2019-04-14 17:21:47 +02:00
|
|
|
setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEPORT, &enable_reuse, sizeof(enable_reuse));
|
2019-02-11 22:49:37 +01:00
|
|
|
#endif
|
2018-09-29 00:32:36 +02:00
|
|
|
}
|
2019-06-22 16:50:11 +02:00
|
|
|
#endif
|
2019-04-14 17:21:47 +02:00
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-05-23 14:33:10 +02:00
|
|
|
#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) {
|
2020-07-22 16:01:54 +02:00
|
|
|
case RTM_NEWROUTE:
|
|
|
|
cmd_str = "Add";
|
|
|
|
break;
|
|
|
|
case RTM_DELROUTE:
|
|
|
|
cmd_str = "Delete";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cmd_str = "?";
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2020-05-23 17:17:32 +02:00
|
|
|
snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf);
|
2020-05-23 14:33:10 +02:00
|
|
|
|
|
|
|
return(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adapted from https://olegkutkov.me/2019/08/29/modifying-linux-network-routes-using-netlink/ */
|
2020-07-22 16:01:54 +02:00
|
|
|
#define NLMSG_TAIL(nmsg) \
|
|
|
|
((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
2020-05-23 14:33:10 +02:00
|
|
|
|
|
|
|
/* Add new data to rtattr */
|
|
|
|
static int rtattr_add(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen)
|
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
int len = RTA_LENGTH(alen);
|
|
|
|
struct rtattr *rta;
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
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;
|
|
|
|
}
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
rta = NLMSG_TAIL(n);
|
|
|
|
rta->rta_type = type;
|
|
|
|
rta->rta_len = len;
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if(alen)
|
|
|
|
memcpy(RTA_DATA(rta), data, alen);
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
return 0;
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 17:17:32 +02:00
|
|
|
static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) {
|
2020-05-23 14:33:10 +02:00
|
|
|
int rv = -1;
|
|
|
|
int rv2;
|
|
|
|
char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */
|
2020-05-23 17:17:32 +02:00
|
|
|
char route_buf[256];
|
2020-05-23 14:33:10 +02:00
|
|
|
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. */
|
2020-05-23 16:44:47 +02:00
|
|
|
traceEvent(TRACE_DEBUG, "waiting for netlink response...");
|
|
|
|
|
2020-05-23 14:33:10 +02:00
|
|
|
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 */
|
2020-05-23 17:17:32 +02:00
|
|
|
if(errcode != EEXIST) {
|
|
|
|
traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
|
2020-05-23 14:33:10 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nh->nlmsg_type == NLMSG_DONE)
|
|
|
|
break;
|
|
|
|
|
2020-05-23 17:17:32 +02:00
|
|
|
if(nh->nlmsg_type == cmd) {
|
|
|
|
traceEvent(TRACE_DEBUG, "Found netlink reply");
|
2020-05-23 14:33:10 +02:00
|
|
|
break;
|
2020-05-23 17:17:32 +02:00
|
|
|
}
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-23 17:17:32 +02:00
|
|
|
traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf)));
|
2020-05-23 14:33:10 +02:00
|
|
|
rv = 0;
|
|
|
|
|
2020-06-21 22:26:27 +02:00
|
|
|
out:
|
2020-05-23 14:33:10 +02:00
|
|
|
close(nl_sock);
|
|
|
|
|
|
|
|
return(rv);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
/* ************************************** */
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-21 05:38:22 +02:00
|
|
|
static int edge_init_routes_linux(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) {
|
2020-05-23 14:33:10 +02:00
|
|
|
#ifdef __linux__
|
|
|
|
int i;
|
2020-07-22 16:01:54 +02:00
|
|
|
for (i = 0; i<num_routes; i++) {
|
2020-05-23 14:33:10 +02:00
|
|
|
n2n_route_t *route = &routes[i];
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if ((route->net_addr == 0) && (route->net_bitlen == 0)) {
|
2020-05-23 14:33:10 +02:00
|
|
|
/* 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
|
2020-06-09 11:15:58 +02:00
|
|
|
* of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus
|
|
|
|
* covering the whole IPv4 range. Such routes in linux take precedence
|
|
|
|
* over the default gateway (0.0.0.0/0) since are more specific.
|
|
|
|
* This leaves the default gateway unchanged so that after n2n is
|
|
|
|
* stopped the cleanup is easier.
|
|
|
|
* See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227
|
2020-05-23 14:33:10 +02:00
|
|
|
*/
|
|
|
|
n2n_sock_t sn;
|
|
|
|
n2n_route_t custom_route;
|
2020-06-07 13:51:48 +02:00
|
|
|
uint32_t *a;
|
2020-06-28 21:30:40 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (eee->sn_route_to_clean) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "Only one default gateway route allowed");
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (eee->conf.sn_num != 1) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "Only one supernode supported with routes");
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
if (supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0)
|
2020-05-23 14:33:10 +02:00
|
|
|
return(-1);
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (sn.family != AF_INET) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "Only IPv4 routes supported");
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2020-06-07 13:51:48 +02:00
|
|
|
a = (u_int32_t*)sn.addr.v4;
|
|
|
|
custom_route.net_addr = *a;
|
2020-05-23 14:33:10 +02:00
|
|
|
custom_route.net_bitlen = 32;
|
|
|
|
custom_route.gateway = get_gateway_ip();
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (!custom_route.gateway) {
|
2020-05-23 14:33:10 +02:00
|
|
|
traceEvent(TRACE_ERROR, "could not determine the gateway IP address");
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ip route add supernode via internet_gateway */
|
2020-07-22 16:01:54 +02:00
|
|
|
if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0)
|
2020-05-23 14:33:10 +02:00
|
|
|
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 */
|
2020-07-22 16:01:54 +02:00
|
|
|
if (eee->sn_route_to_clean)
|
2020-05-23 14:33:10 +02:00
|
|
|
*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;
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0)
|
2020-06-09 11:15:58 +02:00
|
|
|
return(-1);
|
|
|
|
|
|
|
|
/* ip route add 128.0.0.0/1 via n2n_gateway */
|
|
|
|
custom_route.net_addr = 128;
|
|
|
|
custom_route.net_bitlen = 1;
|
|
|
|
custom_route.gateway = route->gateway;
|
2020-05-23 14:33:10 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0)
|
2020-05-23 14:33:10 +02:00
|
|
|
return(-1);
|
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
else {
|
2020-05-23 14:33:10 +02:00
|
|
|
/* ip route add net via n2n_gateway */
|
2020-07-22 16:01:54 +02:00
|
|
|
if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0)
|
2020-05-23 14:33:10 +02:00
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-07-21 05:38:22 +02:00
|
|
|
static int edge_init_routes_win(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
2020-07-22 16:01:54 +02:00
|
|
|
int i;
|
|
|
|
struct in_addr net_addr, gateway;
|
|
|
|
char c_net_addr[32];
|
|
|
|
char c_gateway[32];
|
|
|
|
char cmd[256];
|
2020-07-21 05:38:22 +02:00
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
for (i = 0; i < num_routes; i++)
|
2020-07-21 05:38:22 +02:00
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
n2n_route_t *route = &routes[i];
|
|
|
|
if ((route->net_addr == 0) && (route->net_bitlen == 0))
|
2020-07-21 05:38:22 +02:00
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
traceEvent(TRACE_NORMAL, "Warning: The 0.0.0.0/0 route settings are not supported on Windows");
|
|
|
|
return (-1);
|
2020-07-21 05:38:22 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
else
|
2020-07-21 05:38:22 +02:00
|
|
|
{
|
2020-07-22 16:01:54 +02:00
|
|
|
/* ip route add net via n2n_gateway */
|
|
|
|
memcpy(&net_addr, &(route->net_addr), sizeof(net_addr));
|
|
|
|
memcpy(&gateway, &(route->gateway), sizeof(gateway));
|
|
|
|
_snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(net_addr));
|
|
|
|
_snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(gateway));
|
|
|
|
_snprintf(cmd, sizeof(cmd), "route add %s/%d %s > nul", c_net_addr, route->net_bitlen, c_gateway);
|
|
|
|
traceEvent(TRACE_NORMAL, "ROUTE CMD = '%s'\n", cmd);
|
|
|
|
system(cmd);
|
2020-07-21 05:38:22 +02:00
|
|
|
}
|
2020-07-22 16:01:54 +02:00
|
|
|
}
|
2020-07-21 05:38:22 +02:00
|
|
|
|
|
|
|
#endif // WIN32
|
|
|
|
|
2020-07-22 16:01:54 +02:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
/* 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__
|
|
|
|
return edge_init_routes_linux(eee, routes, num_routes);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
return edge_init_routes_win(eee, routes, num_routes);
|
|
|
|
#endif
|
2020-07-23 04:05:29 +02:00
|
|
|
return 0;
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
static void edge_cleanup_routes(n2n_edge_t *eee) {
|
2020-05-23 16:44:47 +02:00
|
|
|
#ifdef __linux__
|
2020-05-23 14:33:10 +02:00
|
|
|
if(eee->sn_route_to_clean) {
|
|
|
|
/* ip route del supernode via internet_gateway */
|
2020-05-23 17:17:32 +02:00
|
|
|
routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1);
|
2020-05-23 14:33:10 +02:00
|
|
|
free(eee->sn_route_to_clean);
|
|
|
|
}
|
2020-05-23 16:44:47 +02:00
|
|
|
#endif
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-04-27 15:55:07 +02:00
|
|
|
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
2020-10-11 11:57:48 +02:00
|
|
|
memset(conf, 0, sizeof(*conf));
|
|
|
|
|
|
|
|
conf->local_port = 0 /* any port */;
|
|
|
|
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
|
|
|
conf->transop_id = N2N_TRANSFORM_ID_NULL;
|
|
|
|
conf->header_encryption = HEADER_ENCRYPTION_NONE;
|
|
|
|
conf->compression = N2N_COMPRESSION_ID_NONE;
|
|
|
|
conf->drop_multicast = 1;
|
|
|
|
conf->allow_p2p = 1;
|
|
|
|
conf->disable_pmtu_discovery = 1;
|
|
|
|
conf->register_interval = REGISTER_SUPER_INTERVAL_DFL;
|
|
|
|
conf->tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN;
|
2020-10-26 21:13:56 +01:00
|
|
|
/* reserve possible last char as null terminator. */
|
2020-11-09 16:06:00 +01:00
|
|
|
gethostname((char*)conf->dev_desc, N2N_DESC_SIZE-1);
|
2020-10-11 11:57:48 +02:00
|
|
|
|
|
|
|
if (getenv("N2N_KEY")) {
|
|
|
|
conf->encrypt_key = strdup(getenv("N2N_KEY"));
|
2020-10-27 17:02:35 +01:00
|
|
|
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
|
2020-10-11 11:57:48 +02:00
|
|
|
}
|
2019-04-27 15:55:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2020-05-23 14:33:10 +02:00
|
|
|
void edge_term_conf(n2n_edge_conf_t *conf) {
|
2020-10-11 11:57:48 +02:00
|
|
|
if (conf->routes) free(conf->routes);
|
|
|
|
if (conf->encrypt_key) free(conf->encrypt_key);
|
2020-11-10 16:35:05 +01:00
|
|
|
|
|
|
|
if(conf->network_traffic_filter_rules)
|
|
|
|
{
|
2020-11-10 17:58:35 +01:00
|
|
|
filter_rule_t *el = 0, *tmp = 0;
|
|
|
|
HASH_ITER(hh, conf->network_traffic_filter_rules, el, tmp)
|
|
|
|
{
|
|
|
|
HASH_DEL(conf->network_traffic_filter_rules, el);
|
|
|
|
free(el);
|
|
|
|
}
|
2020-11-10 16:35:05 +01:00
|
|
|
}
|
2020-05-23 14:33:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-04-27 15:55:07 +02:00
|
|
|
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
|
|
|
|
return(&eee->conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
|
2020-10-27 17:02:35 +01:00
|
|
|
struct peer_info *sn;
|
|
|
|
n2n_sock_t *sock;
|
|
|
|
int skip_add;
|
|
|
|
int rv = -1;
|
|
|
|
|
|
|
|
sock = (n2n_sock_t*)calloc(1,sizeof(n2n_sock_t));
|
|
|
|
rv = supernode2sock(sock, ip_and_port);
|
|
|
|
|
|
|
|
if(rv != 0){
|
|
|
|
traceEvent(TRACE_WARNING, "Invalid socket");
|
|
|
|
free(sock);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
2020-11-10 16:34:49 +01:00
|
|
|
skip_add = SN_ADD;
|
2020-10-27 17:02:35 +01:00
|
|
|
sn = add_sn_to_list_by_mac_or_sock(&(conf->supernodes), sock, (n2n_mac_t *)null_mac, &skip_add);
|
|
|
|
|
|
|
|
if(sn != NULL){
|
|
|
|
sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE);
|
|
|
|
|
|
|
|
if(sn->ip_addr != NULL){
|
|
|
|
strncpy(sn->ip_addr, ip_and_port, N2N_EDGE_SN_HOST_SIZE-1);
|
|
|
|
memcpy(&(sn->sock), sock, sizeof(n2n_sock_t));
|
|
|
|
memcpy(&(sn->mac_addr), null_mac, sizeof(n2n_mac_t));
|
|
|
|
sn->purgeable = SN_UNPURGEABLE;
|
|
|
|
sn->last_valid_time_stamp = initial_time_stamp();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(sock);
|
2019-04-27 01:56:57 +02:00
|
|
|
|
2020-10-27 17:02:35 +01:00
|
|
|
traceEvent(TRACE_NORMAL, "Adding supernode = %s", sn->ip_addr);
|
2019-04-27 01:56:57 +02:00
|
|
|
conf->sn_num++;
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
2019-04-14 17:21:47 +02:00
|
|
|
int quick_edge_init(char *device_name, char *community_name,
|
|
|
|
char *encrypt_key, char *device_mac,
|
|
|
|
char *local_ip_address,
|
|
|
|
char *supernode_ip_address_port,
|
|
|
|
int *keep_on_running) {
|
2019-04-27 01:56:57 +02:00
|
|
|
tuntap_dev tuntap;
|
|
|
|
n2n_edge_t *eee;
|
|
|
|
n2n_edge_conf_t conf;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
/* Setup the configuration */
|
2019-04-27 12:42:06 +02:00
|
|
|
edge_init_conf_defaults(&conf);
|
2019-04-27 01:56:57 +02:00
|
|
|
conf.encrypt_key = encrypt_key;
|
2020-10-27 17:02:35 +01:00
|
|
|
conf.transop_id = N2N_TRANSFORM_ID_TWOFISH;
|
2020-08-15 19:03:57 +02:00
|
|
|
conf.compression = N2N_COMPRESSION_ID_NONE;
|
2019-04-27 01:56:57 +02:00
|
|
|
snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name);
|
|
|
|
edge_conf_add_supernode(&conf, supernode_ip_address_port);
|
|
|
|
|
|
|
|
/* Validate configuration */
|
|
|
|
if(edge_verify_conf(&conf) != 0)
|
|
|
|
return(-1);
|
2019-04-14 17:21:47 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
/* Open the tuntap device */
|
|
|
|
if(tuntap_open(&tuntap, device_name, "static",
|
2019-04-14 17:21:47 +02:00
|
|
|
local_ip_address, "255.255.255.0",
|
|
|
|
device_mac, DEFAULT_MTU) < 0)
|
|
|
|
return(-2);
|
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
/* Init edge */
|
2020-08-08 16:40:45 +02:00
|
|
|
if((eee = edge_init(&conf, &rv)) == NULL)
|
2019-04-27 01:56:57 +02:00
|
|
|
goto quick_edge_init_end;
|
2019-04-14 17:21:47 +02:00
|
|
|
|
2019-04-27 01:56:57 +02:00
|
|
|
rv = run_edge_loop(eee, keep_on_running);
|
|
|
|
edge_term(eee);
|
2020-05-23 14:33:10 +02:00
|
|
|
edge_term_conf(&conf);
|
2019-04-14 17:21:47 +02:00
|
|
|
|
2020-06-21 22:26:27 +02:00
|
|
|
quick_edge_init_end:
|
2019-04-27 01:56:57 +02:00
|
|
|
tuntap_close(&tuntap);
|
|
|
|
return(rv);
|
2018-06-08 00:17:42 +02:00
|
|
|
}
|
2020-06-10 00:30:11 +02:00
|
|
|
|
|
|
|
/* ************************************** */
|