mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
parent
85894715bd
commit
a482fe112d
|
@ -32,6 +32,7 @@
|
|||
*/
|
||||
|
||||
#define N2N_HAVE_DAEMON /* needs to be defined before it gets undefined */
|
||||
#define N2N_HAVE_TCP /* needs to be defined before it gets undefined */
|
||||
|
||||
/* #define N2N_CAN_NAME_IFACE */
|
||||
|
||||
|
@ -44,6 +45,7 @@
|
|||
#endif
|
||||
#define N2N_CAN_NAME_IFACE 1
|
||||
#undef N2N_HAVE_DAEMON
|
||||
#undef N2N_HAVE_TCP /* as explained on https://github.com/ntop/n2n/pull/627#issuecomment-782093706 */
|
||||
#undef N2N_HAVE_SETUID
|
||||
#else
|
||||
#ifndef CMAKE_BUILD
|
||||
|
@ -106,6 +108,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
@ -132,6 +135,9 @@
|
|||
#include "n2n_typedefs.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h> /* for tcp */
|
||||
#define SHUT_RDWR SD_BOTH /* for tcp */
|
||||
#define SOL_TCP IPPROTO_TCP /* for tcp */
|
||||
#include "win32/wintap.h"
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
|
@ -211,7 +217,7 @@ void print_edge_stats (const n2n_edge_t *eee);
|
|||
char* sock_to_cstr (n2n_sock_str_t out,
|
||||
const n2n_sock_t * sock);
|
||||
char * ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr);
|
||||
SOCKET open_socket (int local_port, int bind_any);
|
||||
SOCKET open_socket (int local_port, int bind_any, int type);
|
||||
int sock_equal (const n2n_sock_t * a,
|
||||
const n2n_sock_t * b);
|
||||
|
||||
|
@ -222,9 +228,17 @@ int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp, int
|
|||
|
||||
/* Operations on peer_info lists. */
|
||||
size_t purge_peer_list (struct peer_info ** peer_list,
|
||||
SOCKET socket_not_to_close,
|
||||
n2n_tcp_connection_t *tcp_connections,
|
||||
time_t purge_before);
|
||||
|
||||
size_t clear_peer_list (struct peer_info ** peer_list);
|
||||
size_t purge_expired_nodes (struct peer_info **peer_list, time_t *p_last_purge, int frequency, int timeout);
|
||||
|
||||
size_t purge_expired_nodes (struct peer_info **peer_list,
|
||||
SOCKET socket_not_to_close,
|
||||
n2n_tcp_connection_t *tcp_connections,
|
||||
time_t *p_last_purge,
|
||||
int frequency, int timeout);
|
||||
|
||||
/* Edge conf */
|
||||
void edge_init_conf_defaults (n2n_edge_conf_t *conf);
|
||||
|
|
|
@ -108,12 +108,14 @@ enum sn_purge{SN_PURGEABLE = 0, SN_UNPURGEABLE = 1};
|
|||
#define HASH_FIND_PEER(head,mac,out) \
|
||||
HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out)
|
||||
#define N2N_EDGE_SN_HOST_SIZE 48
|
||||
#define N2N_EDGE_NUM_SUPERNODES 2
|
||||
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
|
||||
#define N2N_PATHNAME_MAXLEN 256
|
||||
#define N2N_EDGE_MGMT_PORT 5644
|
||||
#define N2N_SN_MGMT_PORT 5645
|
||||
|
||||
#define N2N_TCP_BACKLOG_QUEUE_SIZE 3 /* number of concurrently pending connections to be accepted */
|
||||
/* NOT the number of max. TCP connections */
|
||||
|
||||
/* flag used in add_sn_to_list_by_mac_or_sock */
|
||||
enum skip_add{SN_ADD = 0, SN_ADD_SKIP = 1, SN_ADD_ADDED = 2};
|
||||
|
||||
|
|
|
@ -415,6 +415,7 @@ struct peer_info {
|
|||
n2n_ip_subnet_t dev_addr;
|
||||
n2n_desc_t dev_desc;
|
||||
n2n_sock_t sock;
|
||||
SOCKET socket_fd;
|
||||
n2n_cookie_t last_cookie;
|
||||
n2n_auth_t auth;
|
||||
int timeout;
|
||||
|
@ -598,6 +599,7 @@ typedef struct n2n_edge_conf {
|
|||
int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */
|
||||
int local_port;
|
||||
int mgmt_port;
|
||||
uint8_t connect_tcp; /** connection to supernode 0 = UDP; 1 = TCP */
|
||||
n2n_auth_t auth;
|
||||
filter_rule_t *network_traffic_filter_rules;
|
||||
int metric; /**< Network interface metric (Windows only). */
|
||||
|
@ -631,7 +633,7 @@ struct n2n_edge {
|
|||
|
||||
/* Sockets */
|
||||
/* supernode socket is in eee->curr_sn->sock (of type n2n_sock_t) */
|
||||
int udp_sock;
|
||||
int sock;
|
||||
int udp_mgmt_sock; /**< socket for status info. */
|
||||
|
||||
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
|
||||
|
@ -692,6 +694,18 @@ struct sn_community_regular_expression {
|
|||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
};
|
||||
|
||||
|
||||
typedef struct n2n_tcp_connection {
|
||||
SOCKET socket_fd; /* file descriptor for tcp socket */
|
||||
struct sockaddr sock; /* network order socket */
|
||||
|
||||
uint16_t expected; /* number of bytes expected to be read */
|
||||
uint16_t position; /* current position in the buffer*/
|
||||
uint8_t buffer[N2N_PKT_BUF_SIZE + sizeof(uint16_t)]; /* buffer for data collected from tcp socket incl. prepended length */
|
||||
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} n2n_tcp_connection_t;
|
||||
|
||||
typedef struct n2n_sn {
|
||||
time_t start_time; /* Used to measure uptime. */
|
||||
sn_stats_t stats;
|
||||
|
@ -700,7 +714,9 @@ typedef struct n2n_sn {
|
|||
uint16_t lport; /* Local UDP port to bind to. */
|
||||
uint16_t mport; /* Management UDP port to bind to. */
|
||||
int sock; /* Main socket for UDP traffic with edges. */
|
||||
int mgmt_sock; /* management socket. */
|
||||
int tcp_sock; /* auxiliary socket for optional TCP connections */
|
||||
n2n_tcp_connection_t *tcp_connections;/* list of established TCP connections */
|
||||
int mgmt_sock; /* management socket. */
|
||||
n2n_ip_subnet_t min_auto_ip_net; /* Address range of auto_ip service. */
|
||||
n2n_ip_subnet_t max_auto_ip_net; /* Address range of auto_ip service. */
|
||||
#ifndef WIN32
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef char selection_criterion_str_t[SN_SELECTION_CRITERION_BUF_SIZE];
|
|||
/* selection criterion's functions */
|
||||
int sn_selection_criterion_init (peer_info_t *peer);
|
||||
int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion);
|
||||
int sn_selection_criterion_bad (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion);
|
||||
int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SELECTION_CRITERION_DATA_TYPE *data);
|
||||
|
||||
/* common data's functions */
|
||||
|
|
71
src/edge.c
71
src/edge.c
|
@ -44,9 +44,12 @@ int num_cap = sizeof(cap_values)/sizeof(cap_value_t);
|
|||
|
||||
// forward declaration for use in main()
|
||||
void send_register_super (n2n_edge_t *eee);
|
||||
void send_query_peer (n2n_edge_t * eee, const n2n_mac_t dst_mac);
|
||||
|
||||
|
||||
void send_query_peer (n2n_edge_t *eee, const n2n_mac_t dst_mac);
|
||||
int supernode_connect (n2n_edge_t *eee);
|
||||
int supernode_disconnect (n2n_edge_t *eee);
|
||||
int fetch_and_eventually_process_data (n2n_edge_t *eee, SOCKET sock,
|
||||
uint8_t *pktbuf, uint16_t *expected, uint16_t *position,
|
||||
time_t now);
|
||||
/* ***************************************************** */
|
||||
|
||||
/** Find the address and IP mode for the tuntap device.
|
||||
|
@ -159,7 +162,6 @@ static void help (int level) {
|
|||
#ifndef __APPLE__
|
||||
"[-D] "
|
||||
#endif
|
||||
"[-S] "
|
||||
"\n options for under- "
|
||||
"[-i <registration interval>]"
|
||||
"[-L <registration ttl>]"
|
||||
|
@ -168,6 +170,8 @@ static void help (int level) {
|
|||
"[-A<cipher>] "
|
||||
"[-H] "
|
||||
"[-z<compression>]"
|
||||
"\n "
|
||||
"[-S<level of solitude>]"
|
||||
"\n\n tap device and "
|
||||
"[-a [static:|dhcp:]<tap IP address>[/<cidr suffix>]] "
|
||||
"\n overlay network "
|
||||
|
@ -206,8 +210,7 @@ static void help (int level) {
|
|||
#ifndef __APPLE__
|
||||
"[-D] enable PMTU discovery"
|
||||
#endif
|
||||
"\n flag options [-S] do not connect p2p, always use supernode"
|
||||
"\n [-H] enable header encryption"
|
||||
"\n flag options [-H] enable header encryption"
|
||||
"\n [-r] enable packet forwarding through n2n community"
|
||||
"\n [-E] accept multicast MAC addresses"
|
||||
#ifndef WIN32
|
||||
|
@ -240,7 +243,11 @@ static void help (int level) {
|
|||
printf(" -D | enable PMTU discovery, it can reduce fragmentation but\n"
|
||||
" | causes connections to stall if not properly supported\n");
|
||||
#endif
|
||||
printf(" -S | do not connect p2p, always use the supernode\n");
|
||||
printf(" -S1 ... -S2 or -S | -S1 or -S do not connect p2p, always use the supernode\n"
|
||||
#ifdef N2N_HAVE_TCP
|
||||
" | -S2 connects through TCP and only to the supernode\n"
|
||||
#endif
|
||||
);
|
||||
printf(" -i <reg_interval> | registration interval, for NAT hole punching (default\n"
|
||||
" | 20 seconds)\n");
|
||||
printf(" -L <reg_ttl> | TTL for registration packet for NAT hole punching through\n"
|
||||
|
@ -593,7 +600,15 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e
|
|||
}
|
||||
|
||||
case 'S': {
|
||||
conf->allow_p2p = 0;
|
||||
int solitude_level = 1;
|
||||
if(optargument)
|
||||
solitude_level = atoi(optargument);
|
||||
if(solitude_level >= 1)
|
||||
conf->allow_p2p = 0;
|
||||
#ifdef N2N_HAVE_TCP
|
||||
if(solitude_level == 2)
|
||||
conf->connect_tcp = 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -663,7 +678,7 @@ static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tunta
|
|||
u_char c;
|
||||
|
||||
while ((c = getopt_long(argc, argv,
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:SDL:z::A::Hn:R:"
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:S::DL:z::A::Hn:R:"
|
||||
#ifdef __linux__
|
||||
"T:"
|
||||
#endif
|
||||
|
@ -833,11 +848,17 @@ int main (int argc, char* argv[]) {
|
|||
n2n_tuntap_priv_config_t ec; /* config used for standalone program execution */
|
||||
uint8_t runlevel = 0; /* bootstrap: runlevel */
|
||||
uint8_t seek_answer = 1; /* expecting answer from supernode */
|
||||
time_t now_time, last_action; /* timeout */
|
||||
time_t now, last_action; /* timeout */
|
||||
macstr_t mac_buf; /* output mac address */
|
||||
fd_set socket_mask; /* for supernode answer */
|
||||
struct timeval wait_time; /* timeout for sn answer */
|
||||
|
||||
size_t bread = 0;
|
||||
uint16_t expected = sizeof(uint16_t);
|
||||
uint16_t position = 0;
|
||||
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE + sizeof(uint16_t)]; /* buffer + prepended buffer length in case of tcp */
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
struct passwd *pw = NULL;
|
||||
#endif
|
||||
|
@ -944,7 +965,7 @@ int main (int argc, char* argv[]) {
|
|||
// is found
|
||||
|
||||
// if more than one supernode given, find at least one who is alive to faster establish connection
|
||||
if(HASH_COUNT(eee->conf.supernodes) <= 1) {
|
||||
if((HASH_COUNT(eee->conf.supernodes) <= 1) || (eee->conf.connect_tcp)) {
|
||||
// skip the initial supernode ping
|
||||
traceEvent(TRACE_DEBUG, "Skip PING to supernode.");
|
||||
runlevel = 2;
|
||||
|
@ -952,15 +973,16 @@ int main (int argc, char* argv[]) {
|
|||
|
||||
eee->last_sup = 0; /* if it wasn't zero yet */
|
||||
eee->curr_sn = eee->conf.supernodes;
|
||||
supernode_connect(eee);
|
||||
|
||||
while(runlevel < 5) {
|
||||
|
||||
now_time = time(NULL);
|
||||
now = time(NULL);
|
||||
|
||||
// we do not use switch-case because we also check for 'greater than'
|
||||
|
||||
if(runlevel == 0) { /* PING to all known supernodes */
|
||||
last_action = now_time;
|
||||
last_action = now;
|
||||
eee->sn_pong = 0;
|
||||
// (re-)initialize the number of max concurrent pings (decreases by calling send_query_peer)
|
||||
eee->conf.number_max_sn_pings = NUMBER_SN_PINGS_INITIAL;
|
||||
|
@ -975,9 +997,10 @@ int main (int argc, char* argv[]) {
|
|||
eee->sn_pong = 0;
|
||||
sn_selection_sort(&(eee->conf.supernodes));
|
||||
eee->curr_sn = eee->conf.supernodes;
|
||||
supernode_connect(eee);
|
||||
traceEvent(TRACE_NORMAL, "Received first PONG from supernode [%s].", eee->curr_sn->ip_addr);
|
||||
runlevel++;
|
||||
} else if(last_action <= (now_time - BOOTSTRAP_TIMEOUT)) {
|
||||
} else if(last_action <= (now - BOOTSTRAP_TIMEOUT)) {
|
||||
// timeout
|
||||
runlevel--;
|
||||
// skip waiting for answer to direcly go to send PING again
|
||||
|
@ -1001,7 +1024,7 @@ int main (int argc, char* argv[]) {
|
|||
|
||||
if(runlevel == 2) { /* send REGISTER_SUPER to get auto ip address from a supernode */
|
||||
if(eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) {
|
||||
last_action = now_time;
|
||||
last_action = now;
|
||||
eee->sn_wait = 1;
|
||||
send_register_super(eee);
|
||||
runlevel++;
|
||||
|
@ -1018,12 +1041,13 @@ int main (int argc, char* argv[]) {
|
|||
runlevel++;
|
||||
traceEvent(TRACE_NORMAL, "Received REGISTER_SUPER_ACK from supernode for IP address asignment.");
|
||||
// it should be from curr_sn, but we can't determine definitely here, so no details to output
|
||||
} else if(last_action <= (now_time - BOOTSTRAP_TIMEOUT)) {
|
||||
} else if(last_action <= (now - BOOTSTRAP_TIMEOUT)) {
|
||||
// timeout, so try next supernode
|
||||
if(eee->curr_sn->hh.next)
|
||||
eee->curr_sn = eee->curr_sn->hh.next;
|
||||
else
|
||||
eee->curr_sn = eee->conf.supernodes;
|
||||
supernode_connect(eee);
|
||||
runlevel--;
|
||||
// skip waiting for answer to direcly go to send REGISTER_SUPER again
|
||||
seek_answer = 0;
|
||||
|
@ -1053,23 +1077,27 @@ int main (int argc, char* argv[]) {
|
|||
// we usually wait for some answer, there however are exceptions when going back to a previous runlevel
|
||||
if(seek_answer) {
|
||||
FD_ZERO(&socket_mask);
|
||||
FD_SET(eee->udp_sock, &socket_mask);
|
||||
FD_SET(eee->sock, &socket_mask);
|
||||
wait_time.tv_sec = BOOTSTRAP_TIMEOUT;
|
||||
wait_time.tv_usec = 0;
|
||||
|
||||
if(select(eee->udp_sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) {
|
||||
if(FD_ISSET(eee->udp_sock, &socket_mask)) {
|
||||
readFromIPSocket(eee, eee->udp_sock);
|
||||
if(select(eee->sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) {
|
||||
if(FD_ISSET(eee->sock, &socket_mask)) {
|
||||
|
||||
fetch_and_eventually_process_data (eee, eee->sock,
|
||||
pktbuf, &expected, &position,
|
||||
now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seek_answer = 1;
|
||||
}
|
||||
// allow a higher number of pings for first regular round of ping
|
||||
// to quicker get an inital 'supernode selection criterion overview'
|
||||
eee->conf.number_max_sn_pings = NUMBER_SN_PINGS_INITIAL;
|
||||
// do not immediately ping again, allow some time
|
||||
eee->last_sweep = now_time - SWEEP_TIME + 2 * BOOTSTRAP_TIMEOUT;
|
||||
eee->last_sweep = now - SWEEP_TIME + 2 * BOOTSTRAP_TIMEOUT;
|
||||
eee->sn_wait = 1;
|
||||
eee->last_register_req = 0;
|
||||
|
||||
|
@ -1114,6 +1142,7 @@ int main (int argc, char* argv[]) {
|
|||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGTERM, term_handler);
|
||||
signal(SIGINT, term_handler);
|
||||
#endif
|
||||
|
|
682
src/edge_utils.c
682
src/edge_utils.c
File diff suppressed because it is too large
Load Diff
|
@ -29,12 +29,12 @@ int main () {
|
|||
sss_node.daemon = 0; // Whether to daemonize
|
||||
sss_node.lport = 1234; // Main UDP listen port
|
||||
|
||||
sss_node.sock = open_socket(sss_node.lport, 1);
|
||||
sss_node.sock = open_socket(sss_node.lport, 1, 0);
|
||||
if(-1 == sss_node.sock) {
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
sss_node.mgmt_sock = open_socket(5645, 0); // Main UDP management port
|
||||
sss_node.mgmt_sock = open_socket(5645, 0, 0); // Main UDP management port
|
||||
if(-1 == sss_node.mgmt_sock) {
|
||||
exit(-2);
|
||||
}
|
||||
|
|
29
src/n2n.c
29
src/n2n.c
|
@ -28,13 +28,13 @@
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
SOCKET open_socket (int local_port, int bind_any) {
|
||||
SOCKET open_socket (int local_port, int bind_any, int type /* 0 = UDP, TCP otherwise */) {
|
||||
|
||||
SOCKET sock_fd;
|
||||
struct sockaddr_in local_address;
|
||||
int sockopt;
|
||||
|
||||
if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
if((sock_fd = socket(PF_INET, ((type == 0) ? SOCK_DGRAM : SOCK_STREAM) , 0)) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n",
|
||||
strerror(errno), sock_fd);
|
||||
return(-1);
|
||||
|
@ -60,6 +60,7 @@ SOCKET open_socket (int local_port, int bind_any) {
|
|||
return(sock_fd);
|
||||
}
|
||||
|
||||
|
||||
static int traceLevel = 2 /* NORMAL */;
|
||||
static int useSyslog = 0, syslog_opened = 0;
|
||||
static FILE *traceFile = NULL;
|
||||
|
@ -439,7 +440,10 @@ void print_n2n_version () {
|
|||
|
||||
/* *********************************************** */
|
||||
|
||||
size_t purge_expired_nodes (struct peer_info **peer_list, time_t *p_last_purge,
|
||||
size_t purge_expired_nodes (struct peer_info **peer_list,
|
||||
SOCKET socket_not_to_close,
|
||||
n2n_tcp_connection_t *tcp_connections,
|
||||
time_t *p_last_purge,
|
||||
int frequency, int timeout) {
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
@ -451,7 +455,7 @@ size_t purge_expired_nodes (struct peer_info **peer_list, time_t *p_last_purge,
|
|||
|
||||
traceEvent(TRACE_DEBUG, "Purging old registrations");
|
||||
|
||||
num_reg = purge_peer_list(peer_list, now - timeout);
|
||||
num_reg = purge_peer_list(peer_list, socket_not_to_close, tcp_connections, now - timeout);
|
||||
|
||||
(*p_last_purge) = now;
|
||||
traceEvent(TRACE_DEBUG, "Remove %ld registrations", num_reg);
|
||||
|
@ -459,15 +463,30 @@ size_t purge_expired_nodes (struct peer_info **peer_list, time_t *p_last_purge,
|
|||
return num_reg;
|
||||
}
|
||||
|
||||
/** Purge old items from the peer_list and return the number of items that were removed. */
|
||||
/** Purge old items from the peer_list, eventually close the related socket, and
|
||||
* return the number of items that were removed. */
|
||||
size_t purge_peer_list (struct peer_info ** peer_list,
|
||||
SOCKET socket_not_to_close,
|
||||
n2n_tcp_connection_t *tcp_connections,
|
||||
time_t purge_before) {
|
||||
|
||||
struct peer_info *scan, *tmp;
|
||||
n2n_tcp_connection_t *conn;
|
||||
size_t retval = 0;
|
||||
|
||||
HASH_ITER(hh, *peer_list, scan, tmp) {
|
||||
if((scan->purgeable == SN_PURGEABLE) && (scan->last_seen < purge_before)) {
|
||||
if((scan->socket_fd >=0) && (scan->socket_fd != socket_not_to_close)) {
|
||||
if(tcp_connections) {
|
||||
HASH_FIND_INT(tcp_connections, &scan->socket_fd, conn);
|
||||
if(conn) {
|
||||
HASH_DEL(tcp_connections, conn);
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
shutdown(scan->socket_fd, SHUT_RDWR);
|
||||
closesocket(scan->socket_fd);
|
||||
}
|
||||
HASH_DEL(*peer_list, scan);
|
||||
retval++;
|
||||
free(scan);
|
||||
|
|
29
src/sn.c
29
src/sn.c
|
@ -355,7 +355,6 @@ static int setOption (int optkey, char *_optarg, n2n_sn_t *sss) {
|
|||
memcpy(anchor_sn->mac_addr, null_mac, sizeof(n2n_mac_t));
|
||||
anchor_sn->purgeable = SN_UNPURGEABLE;
|
||||
anchor_sn->last_valid_time_stamp = initial_time_stamp();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -660,10 +659,11 @@ BOOL WINAPI term_handler (DWORD sig)
|
|||
int main (int argc, char * const argv[]) {
|
||||
|
||||
int rc;
|
||||
|
||||
#ifndef WIN32
|
||||
struct passwd *pw = NULL;
|
||||
#endif
|
||||
struct peer_info *scan, *tmp;
|
||||
|
||||
|
||||
sn_init(&sss_node);
|
||||
add_federation_to_communities(&sss_node);
|
||||
|
@ -704,7 +704,7 @@ int main (int argc, char * const argv[]) {
|
|||
|
||||
traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel());
|
||||
|
||||
sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/);
|
||||
sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 0 /* UDP */);
|
||||
if(-1 == sss_node.sock) {
|
||||
traceEvent(TRACE_ERROR, "Failed to open main socket. %s", strerror(errno));
|
||||
exit(-2);
|
||||
|
@ -712,7 +712,24 @@ int main (int argc, char * const argv[]) {
|
|||
traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss_node.lport);
|
||||
}
|
||||
|
||||
sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */);
|
||||
#ifdef N2N_HAVE_TCP
|
||||
sss_node.tcp_sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 1 /* TCP */);
|
||||
if(-1 == sss_node.tcp_sock) {
|
||||
traceEvent(TRACE_ERROR, "Failed to open auxiliary TCP socket. %s", strerror(errno));
|
||||
exit(-2);
|
||||
} else {
|
||||
traceEvent(TRACE_NORMAL, "supernode opened TCP %u (aux)", sss_node.lport);
|
||||
}
|
||||
|
||||
if(-1 == listen(sss_node.tcp_sock, N2N_TCP_BACKLOG_QUEUE_SIZE)) {
|
||||
traceEvent(TRACE_ERROR, "Failed to listen on auxiliary TCP socket. %s", strerror(errno));
|
||||
exit(-2);
|
||||
} else {
|
||||
traceEvent(TRACE_NORMAL, "supernode is listening on TCP %u (aux)", sss_node.lport);
|
||||
}
|
||||
#endif
|
||||
|
||||
sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */, 0 /* UDP */);
|
||||
if(-1 == sss_node.mgmt_sock) {
|
||||
traceEvent(TRACE_ERROR, "Failed to open management socket. %s", strerror(errno));
|
||||
exit(-2);
|
||||
|
@ -720,6 +737,9 @@ int main (int argc, char * const argv[]) {
|
|||
traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (management)", sss_node.mport);
|
||||
}
|
||||
|
||||
HASH_ITER(hh, sss_node.federation->edges, scan, tmp)
|
||||
scan->socket_fd = sss_node.sock;
|
||||
|
||||
#ifndef WIN32
|
||||
if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) {
|
||||
sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0;
|
||||
|
@ -745,6 +765,7 @@ int main (int argc, char * const argv[]) {
|
|||
traceEvent(TRACE_NORMAL, "supernode started");
|
||||
|
||||
#ifdef __linux__
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGTERM, term_handler);
|
||||
signal(SIGINT, term_handler);
|
||||
signal(SIGHUP, dump_registrations);
|
||||
|
|
|
@ -38,6 +38,15 @@ int sn_selection_criterion_init (peer_info_t *peer) {
|
|||
/* Set selection_criterion field to default value according to selected strategy. */
|
||||
int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) {
|
||||
|
||||
*selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE) (UINT32_MAX >> 1) - 1;
|
||||
|
||||
return 0; /* OK */
|
||||
}
|
||||
|
||||
|
||||
/* Set selection_criterion field to 'bad' value (worse than default) according to selected strategy. */
|
||||
int sn_selection_criterion_bad (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) {
|
||||
|
||||
*selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE) UINT32_MAX >> 1;
|
||||
|
||||
return 0; /* OK */
|
||||
|
@ -148,12 +157,12 @@ extern char * sn_selection_criterion_str (selection_criterion_str_t out, peer_in
|
|||
|
||||
#ifndef SN_SELECTION_RTT
|
||||
snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE,
|
||||
(int16_t)(peer->selection_criterion) != -1 ? "load = %8d" :
|
||||
"", peer->selection_criterion);
|
||||
(int16_t)(peer->selection_criterion) >= 0 ? "load = %8d" :
|
||||
"", peer->selection_criterion);
|
||||
#else
|
||||
snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE,
|
||||
(int16_t)(peer->selection_criterion) != -1 ? "rtt = %6d ms" :
|
||||
"", peer->selection_criterion);
|
||||
(int16_t)(peer->selection_criterion) >= 0 ? "rtt = %6d ms" :
|
||||
"", peer->selection_criterion);
|
||||
#endif
|
||||
|
||||
return out;
|
||||
|
|
467
src/sn_utils.c
467
src/sn_utils.c
|
@ -28,8 +28,8 @@ static int try_forward (n2n_sn_t * sss,
|
|||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static ssize_t sendto_sock (n2n_sn_t *sss,
|
||||
const n2n_sock_t *sock,
|
||||
static ssize_t sendto_peer (n2n_sn_t *sss,
|
||||
const struct peer_info *peer,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
|
@ -52,6 +52,7 @@ static int update_edge (n2n_sn_t *sss,
|
|||
const n2n_REGISTER_SUPER_t* reg,
|
||||
struct sn_community *comm,
|
||||
const n2n_sock_t *sender_sock,
|
||||
const SOCKET socket_fd,
|
||||
n2n_auth_t *answer_auth,
|
||||
int skip_add,
|
||||
time_t now);
|
||||
|
@ -72,6 +73,7 @@ static int process_mgmt (n2n_sn_t *sss,
|
|||
|
||||
static int process_udp (n2n_sn_t *sss,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
const SOCKET socket_fd,
|
||||
uint8_t *udp_buf,
|
||||
size_t udp_size,
|
||||
time_t now);
|
||||
|
@ -95,7 +97,7 @@ static int try_forward (n2n_sn_t * sss,
|
|||
|
||||
if(NULL != scan) {
|
||||
int data_sent_len;
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len == pktsize) {
|
||||
++(sss->stats.fwd);
|
||||
|
@ -110,6 +112,7 @@ static int try_forward (n2n_sn_t * sss,
|
|||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!from_supernode) {
|
||||
|
@ -119,37 +122,155 @@ static int try_forward (n2n_sn_t * sss,
|
|||
} else {
|
||||
traceEvent(TRACE_DEBUG, "try_forward unknown MAC. Dropping the packet.");
|
||||
/* Not a known MAC so drop. */
|
||||
return(-2);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Send a datagram to the destination embodied in a n2n_sock_t.
|
||||
|
||||
static void close_tcp_connection(n2n_sn_t *sss, n2n_tcp_connection_t *conn) {
|
||||
|
||||
struct sn_community *comm, *tmp_comm;
|
||||
struct peer_info *edge, *tmp_edge;
|
||||
|
||||
if(!conn)
|
||||
return;
|
||||
|
||||
// find peer by file descriptor
|
||||
HASH_ITER(hh, sss->communities, comm, tmp_comm) {
|
||||
HASH_ITER(hh, comm->edges, edge, tmp_edge) {
|
||||
if(edge->socket_fd == conn->socket_fd) {
|
||||
// remove peer
|
||||
HASH_DEL(comm->edges, edge);
|
||||
free(edge);
|
||||
goto close_conn; /* break - level 2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close_conn:
|
||||
// close the connection
|
||||
shutdown(conn->socket_fd, SHUT_RDWR);
|
||||
closesocket(conn->socket_fd);
|
||||
// forget about the connection
|
||||
HASH_DEL(sss->tcp_connections, conn);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
|
||||
/** Send a datagram to a file descriptor socket.
|
||||
*
|
||||
* @return -1 on error otherwise number of bytes sent
|
||||
*/
|
||||
static ssize_t sendto_sock (n2n_sn_t *sss,
|
||||
const n2n_sock_t *sock,
|
||||
static ssize_t sendto_fd (n2n_sn_t *sss,
|
||||
SOCKET socket_fd,
|
||||
const struct sockaddr *socket,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize) {
|
||||
|
||||
ssize_t sent = 0;
|
||||
struct sn_community *comm, *tmp_comm;
|
||||
struct peer_info *edge, *tmp_edge;
|
||||
n2n_tcp_connection_t *conn;
|
||||
|
||||
sent = sendto(socket_fd, pktbuf, pktsize, 0 /* flags */,
|
||||
socket, sizeof(struct sockaddr_in));
|
||||
|
||||
if(sent <= 0) {
|
||||
char * c = strerror(errno);
|
||||
traceEvent(TRACE_ERROR, "sendto_fd failed (%d) %s", errno, c);
|
||||
#ifdef WIN32
|
||||
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
|
||||
#endif
|
||||
// if the erroneous connection is tcp, i.e. not the regular sock...
|
||||
if((socket_fd >= 0) && (socket_fd != sss->sock)) {
|
||||
// ...forget about the corresponding peer and the connection
|
||||
HASH_FIND_INT(sss->tcp_connections, &socket_fd, conn);
|
||||
close_tcp_connection(sss, conn);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "sendto_fd sent=%d to ", (signed int)sent);
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
||||
/** Send a datagram to a network order socket of type struct sockaddr.
|
||||
*
|
||||
* @return -1 on error otherwise number of bytes sent
|
||||
*/
|
||||
static ssize_t sendto_sock(n2n_sn_t *sss,
|
||||
SOCKET socket_fd,
|
||||
const struct sockaddr *socket,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize) {
|
||||
|
||||
ssize_t sent = 0;
|
||||
int value = 0;
|
||||
|
||||
// if the connection is tcp, i.e. not the regular sock...
|
||||
if((socket_fd >= 0) && (socket_fd != sss->sock)) {
|
||||
|
||||
setsockopt(socket_fd, SOL_TCP, TCP_NODELAY, &value, sizeof(value));
|
||||
value = 1;
|
||||
#ifndef WIN32
|
||||
setsockopt(socket_fd, SOL_TCP, TCP_CORK, &value, sizeof(value));
|
||||
#endif
|
||||
|
||||
// prepend packet length...
|
||||
uint16_t pktsize16 = htobe16(pktsize);
|
||||
sent = sendto_fd(sss, socket_fd, socket, (uint8_t*)&pktsize16, sizeof(pktsize16));
|
||||
|
||||
if(sent <= 0)
|
||||
return -1;
|
||||
// ...before sending the actual data
|
||||
}
|
||||
|
||||
sent = sendto_fd(sss, socket_fd, socket, pktbuf, pktsize);
|
||||
|
||||
// if the connection is tcp, i.e. not the regular sock...
|
||||
if((socket_fd >= 0) && (socket_fd != sss->sock)) {
|
||||
value = 1; /* value should still be set to 1 */
|
||||
setsockopt(socket_fd, SOL_TCP, TCP_NODELAY, &value, sizeof(value));
|
||||
#ifndef WIN32
|
||||
value = 0;
|
||||
setsockopt(socket_fd, SOL_TCP, TCP_CORK, &value, sizeof(value));
|
||||
#endif
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
||||
/** Send a datagram to a peer whose destination socket is embodied in its sock field of type n2n_sock_t.
|
||||
* It calls sendto_sock to do the final send.
|
||||
*
|
||||
* @return -1 on error otherwise number of bytes sent
|
||||
*/
|
||||
static ssize_t sendto_peer (n2n_sn_t *sss,
|
||||
const struct peer_info *peer,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize) {
|
||||
|
||||
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
if(AF_INET == sock->family) {
|
||||
struct sockaddr_in udpsock;
|
||||
if(AF_INET == peer->sock.family) {
|
||||
|
||||
udpsock.sin_family = AF_INET;
|
||||
udpsock.sin_port = htons(sock->port);
|
||||
memcpy(&(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE);
|
||||
// network order socket
|
||||
struct sockaddr_in socket;
|
||||
fill_sockaddr((struct sockaddr *)&socket, sizeof(socket), &(peer->sock));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "sendto_sock %lu to [%s]",
|
||||
traceEvent(TRACE_DEBUG, "sendto_peer %lu to [%s]",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, sock));
|
||||
sock_to_cstr(sockbuf, &(peer->sock)));
|
||||
|
||||
return sendto(sss->sock, pktbuf, pktsize, 0,
|
||||
(const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in));
|
||||
return sendto_sock(sss,
|
||||
(peer->socket_fd >= 0) ? peer->socket_fd : sss->sock,
|
||||
(const struct sockaddr*)&socket, pktbuf, pktsize);
|
||||
} else {
|
||||
/* AF_INET6 not implemented */
|
||||
errno = EAFNOSUPPORT;
|
||||
|
@ -157,6 +278,7 @@ static ssize_t sendto_sock (n2n_sn_t *sss,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/** Try and broadcast a message to all edges in the community.
|
||||
*
|
||||
* This will send the exact same datagram to zero or more edges registered to
|
||||
|
@ -185,7 +307,7 @@ static int try_broadcast (n2n_sn_t * sss,
|
|||
HASH_ITER(hh, sss->federation->edges, scan, tmp) {
|
||||
int data_sent_len;
|
||||
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len != pktsize) {
|
||||
++(sss->stats.errors);
|
||||
|
@ -210,7 +332,7 @@ static int try_broadcast (n2n_sn_t * sss,
|
|||
/* REVISIT: exclude if the destination socket is where the packet came from. */
|
||||
int data_sent_len;
|
||||
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len != pktsize) {
|
||||
++(sss->stats.errors);
|
||||
|
@ -233,6 +355,7 @@ static int try_broadcast (n2n_sn_t * sss,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Initialise some fields of the community structure **/
|
||||
int comm_init (struct sn_community *comm, char *cmn) {
|
||||
|
||||
|
@ -304,18 +427,34 @@ int sn_init(n2n_sn_t *sss) {
|
|||
return 0; /* OK */
|
||||
}
|
||||
|
||||
|
||||
/** Deinitialise the supernode structure and deallocate any memory owned by
|
||||
* it. */
|
||||
void sn_term (n2n_sn_t *sss) {
|
||||
|
||||
struct sn_community *community, *tmp;
|
||||
struct sn_community_regular_expression *re, *tmp_re;
|
||||
n2n_tcp_connection_t *conn, *tmp_conn;
|
||||
|
||||
if(sss->sock >= 0) {
|
||||
closesocket(sss->sock);
|
||||
}
|
||||
sss->sock = -1;
|
||||
|
||||
HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) {
|
||||
shutdown(conn->socket_fd, SHUT_RDWR);
|
||||
closesocket(conn->socket_fd);
|
||||
HASH_DEL(sss->tcp_connections, conn);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
if(sss->tcp_sock >= 0) {
|
||||
shutdown(sss->tcp_sock, SHUT_RDWR);
|
||||
closesocket(sss->tcp_sock);
|
||||
}
|
||||
sss->tcp_sock = -1;
|
||||
|
||||
|
||||
if(sss->mgmt_sock >= 0) {
|
||||
closesocket(sss->mgmt_sock);
|
||||
}
|
||||
|
@ -345,6 +484,7 @@ void sn_term (n2n_sn_t *sss) {
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** Determine the appropriate lifetime for new registrations.
|
||||
*
|
||||
* If the supernode has been put into a pre-shutdown phase then this lifetime
|
||||
|
@ -409,6 +549,7 @@ static int update_edge (n2n_sn_t *sss,
|
|||
const n2n_REGISTER_SUPER_t* reg,
|
||||
struct sn_community *comm,
|
||||
const n2n_sock_t *sender_sock,
|
||||
const SOCKET socket_fd,
|
||||
n2n_auth_t *answer_auth,
|
||||
int skip_add,
|
||||
time_t now) {
|
||||
|
@ -447,6 +588,7 @@ static int update_edge (n2n_sn_t *sss,
|
|||
scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen;
|
||||
memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE);
|
||||
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
|
||||
scan->socket_fd = socket_fd;
|
||||
memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE));
|
||||
handle_remote_auth(sss, scan, &(reg->auth), answer_auth);
|
||||
scan->last_valid_time_stamp = initial_time_stamp();
|
||||
|
@ -463,6 +605,7 @@ static int update_edge (n2n_sn_t *sss,
|
|||
if(!sock_equal(sender_sock, &(scan->sock))) {
|
||||
if((auth = auth_edge(&(scan->auth), &(reg->auth), answer_auth)) == 0) {
|
||||
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
|
||||
scan->socket_fd = socket_fd;
|
||||
memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE));
|
||||
|
||||
traceEvent(TRACE_INFO, "update_edge updated %s ==> %s",
|
||||
|
@ -697,7 +840,7 @@ static int re_register_and_purge_supernodes (n2n_sn_t *sss, struct sn_community
|
|||
}
|
||||
|
||||
// purge long-time-not-seen supernodes
|
||||
purge_expired_nodes(&(comm->edges), p_last_re_reg_and_purge,
|
||||
purge_expired_nodes(&(comm->edges), sss->sock, sss->tcp_connections, p_last_re_reg_and_purge,
|
||||
RE_REG_AND_PURGE_FREQUENCY, LAST_SEEN_SN_INACTIVE);
|
||||
|
||||
if(comm != NULL) {
|
||||
|
@ -748,7 +891,7 @@ static int re_register_and_purge_supernodes (n2n_sn_t *sss, struct sn_community
|
|||
comm->header_encryption_ctx, comm->header_iv_ctx,
|
||||
time_stamp());
|
||||
|
||||
/* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, idx);
|
||||
/* sent = */ sendto_peer(sss, peer, pktbuf, idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,7 +917,7 @@ static int purge_expired_communities (n2n_sn_t *sss,
|
|||
if(comm->is_federation == IS_FEDERATION)
|
||||
continue;
|
||||
|
||||
num_reg += purge_peer_list(&comm->edges, now - REGISTRATION_TIMEOUT);
|
||||
num_reg += purge_peer_list(&comm->edges, sss->sock, sss->tcp_connections, now - REGISTRATION_TIMEOUT);
|
||||
if((comm->edges == NULL) && (comm->purgeable == COMMUNITY_PURGEABLE)) {
|
||||
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
|
||||
if(NULL != comm->header_encryption_ctx) {
|
||||
|
@ -800,6 +943,7 @@ static int number_enc_packets_sort (struct sn_community *a, struct sn_community
|
|||
return (b->number_enc_packets - a->number_enc_packets);
|
||||
}
|
||||
|
||||
|
||||
static int sort_communities (n2n_sn_t *sss,
|
||||
time_t* p_last_sort,
|
||||
time_t now) {
|
||||
|
@ -847,13 +991,13 @@ static int process_mgmt (n2n_sn_t *sss,
|
|||
traceEvent(TRACE_DEBUG, "process_mgmt");
|
||||
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
" ### | TAP | MAC | EDGE | HINT | LAST SEEN\n");
|
||||
" ### | TAP | MAC | EDGE | HINT | LAST SEEN\n");
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
"====================================================================================================\n");
|
||||
"========================================================================================================\n");
|
||||
HASH_ITER(hh, sss->communities, community, tmp) {
|
||||
if(num_comm)
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
"----------------------------------------------------------------------------------------------------\n");
|
||||
"--------------------------------------------------------------------------------------------------------\n");
|
||||
num_comm++;
|
||||
num_edges += HASH_COUNT(community->edges);
|
||||
|
||||
|
@ -869,12 +1013,13 @@ static int process_mgmt (n2n_sn_t *sss,
|
|||
HASH_ITER(hh, community->edges, peer, tmpPeer) {
|
||||
sprintf (time_buf, "%9u", now - peer->last_seen);
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
"%4u | %-19s | %-17s | %-21s | %-15s | %9s\n",
|
||||
"%4u | %-19s | %-17s | %-21s %-3s | %-15s | %9s\n",
|
||||
++num,
|
||||
(peer->dev_addr.net_addr == 0) ? ((peer->purgeable == SN_UNPURGEABLE) ? "-l" : "") :
|
||||
ip_subnet_to_str(ip_bit_str, &peer->dev_addr),
|
||||
macaddr_str(mac_buf, peer->mac_addr),
|
||||
(is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr),
|
||||
sock_to_cstr(sockbuf, &(peer->sock)),
|
||||
((peer->socket_fd >= 0) && (peer->socket_fd != sss->sock)) ? "TCP" : "",
|
||||
peer->dev_desc,
|
||||
(peer->last_seen) ? time_buf : "");
|
||||
|
||||
|
@ -883,7 +1028,7 @@ static int process_mgmt (n2n_sn_t *sss,
|
|||
}
|
||||
}
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
"====================================================================================================\n");
|
||||
"========================================================================================================\n");
|
||||
|
||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||
"uptime %lu | ", (now - sss->start_time));
|
||||
|
@ -933,7 +1078,7 @@ static int sendto_mgmt (n2n_sn_t *sss,
|
|||
const struct sockaddr_in *sender_sock,
|
||||
const uint8_t *mgmt_buf,
|
||||
size_t mgmt_size) {
|
||||
|
||||
|
||||
ssize_t r = sendto(sss->mgmt_sock, mgmt_buf, mgmt_size, 0 /*flags*/,
|
||||
(struct sockaddr *)sender_sock, sizeof (struct sockaddr_in));
|
||||
|
||||
|
@ -950,7 +1095,8 @@ static int sendto_mgmt (n2n_sn_t *sss,
|
|||
*
|
||||
*/
|
||||
static int process_udp (n2n_sn_t * sss,
|
||||
const struct sockaddr_in * sender_sock,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
const SOCKET socket_fd,
|
||||
uint8_t * udp_buf,
|
||||
size_t udp_size,
|
||||
time_t now) {
|
||||
|
@ -1358,6 +1504,8 @@ static int process_udp (n2n_sn_t * sss,
|
|||
if(comm->is_federation == IS_FEDERATION) {
|
||||
skip_add = SN_ADD;
|
||||
p = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(ack.sock), reg.edgeMac, &skip_add);
|
||||
// communication with other supernodes happens via standard udp port
|
||||
p->socket_fd = sss->sock;
|
||||
}
|
||||
|
||||
/* Skip random numbers of supernodes before payload assembling, calculating an appropriate random_number.
|
||||
|
@ -1390,9 +1538,9 @@ static int process_udp (n2n_sn_t * sss,
|
|||
|
||||
if(!is_null_mac(reg.edgeMac)) {
|
||||
if(cmn.flags & N2N_FLAGS_SOCKET) {
|
||||
ret_value = update_edge(sss, ®, comm, &(ack.sock), &(ack.auth), SN_ADD_SKIP, now);
|
||||
ret_value = update_edge(sss, ®, comm, &(ack.sock), socket_fd, &(ack.auth), SN_ADD_SKIP, now);
|
||||
} else {
|
||||
ret_value = update_edge(sss, ®, comm, &(ack.sock), &(ack.auth), SN_ADD, now);
|
||||
ret_value = update_edge(sss, ®, comm, &(ack.sock), socket_fd, &(ack.auth), SN_ADD, now);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1408,12 +1556,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
comm->header_encryption_ctx, comm->header_iv_ctx,
|
||||
time_stamp());
|
||||
}
|
||||
sendto(sss->sock, ackbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
|
||||
if(cmn.flags & N2N_FLAGS_SOCKET) {
|
||||
sendto_sock(sss, ®.sock, ackbuf, encx);
|
||||
}
|
||||
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s",
|
||||
macaddr_str(mac_buf, reg.edgeMac));
|
||||
|
@ -1453,12 +1596,25 @@ static int process_udp (n2n_sn_t * sss,
|
|||
time_stamp());
|
||||
}
|
||||
|
||||
sendto(sss->sock, ackbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
|
||||
macaddr_str(mac_buf, reg.edgeMac),
|
||||
sock_to_cstr(sockbuf, &(ack.sock)));
|
||||
} else {
|
||||
// this is an edge with valid authentication registering with another supernode
|
||||
// so we can delete it here if present (can happen)
|
||||
HASH_FIND_PEER(comm->edges, reg.edgeMac, peer);
|
||||
if(peer != NULL) {
|
||||
if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) {
|
||||
n2n_tcp_connection_t *conn;
|
||||
HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn);
|
||||
close_tcp_connection(sss, conn); /* also deletes the peer */
|
||||
} else {
|
||||
HASH_DEL(comm->edges, peer);
|
||||
free(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1502,7 +1658,14 @@ static int process_udp (n2n_sn_t * sss,
|
|||
HASH_FIND_PEER(comm->edges, unreg.srcMac, peer);
|
||||
if(peer != NULL) {
|
||||
if((auth = auth_edge(&(peer->auth), &unreg.auth, NULL)) == 0) {
|
||||
HASH_DEL(comm->edges, peer);
|
||||
if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) {
|
||||
n2n_tcp_connection_t *conn;
|
||||
HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn);
|
||||
close_tcp_connection(sss, conn); /* also deletes the peer */
|
||||
} else {
|
||||
HASH_DEL(comm->edges, peer);
|
||||
free(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1576,6 +1739,8 @@ static int process_udp (n2n_sn_t * sss,
|
|||
for(i = 0; i < ack.num_sn; i++) {
|
||||
skip_add = SN_ADD;
|
||||
tmp = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(payload->sock), payload->mac, &skip_add);
|
||||
// other supernodes communicate via standard udp socket
|
||||
tmp->socket_fd = sss->sock;
|
||||
|
||||
if(skip_add == SN_ADD_ADDED) {
|
||||
tmp->last_seen = now - LAST_SEEN_SN_NEW;
|
||||
|
@ -1589,7 +1754,9 @@ static int process_udp (n2n_sn_t * sss,
|
|||
}
|
||||
|
||||
case MSG_TYPE_REGISTER_SUPER_NAK: {
|
||||
n2n_common_t cmn2;
|
||||
n2n_REGISTER_SUPER_NAK_t nak;
|
||||
uint8_t nakbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
struct peer_info *peer;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
@ -1626,10 +1793,32 @@ static int process_udp (n2n_sn_t * sss,
|
|||
HASH_FIND_PEER(comm->edges, nak.srcMac, peer);
|
||||
if(comm->is_federation == IS_NO_FEDERATION) {
|
||||
if(peer != NULL) {
|
||||
HASH_DEL(comm->edges, peer);
|
||||
// this is a NAK for one of the edges conencted to this supernode, forward,
|
||||
// i.e. re-assemble (memcpy of udpbuf to nakbuf could be sufficient as well)
|
||||
|
||||
// use incoming cmn (with already decreased TTL)
|
||||
// NAK (cookie and srcMac) remains unchanged
|
||||
|
||||
encode_REGISTER_SUPER_NAK(nakbuf, &encx, &cmn, &nak);
|
||||
|
||||
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
packet_header_encrypt(nakbuf, encx, encx,
|
||||
comm->header_encryption_ctx, comm->header_iv_ctx,
|
||||
time_stamp());
|
||||
}
|
||||
|
||||
sendto_peer(sss, peer, nakbuf, encx);
|
||||
|
||||
if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) {
|
||||
n2n_tcp_connection_t *conn;
|
||||
HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn);
|
||||
close_tcp_connection(sss, conn); /* also deletes the peer */
|
||||
} else {
|
||||
HASH_DEL(comm->edges, peer);
|
||||
free(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1707,8 +1896,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
}
|
||||
}
|
||||
|
||||
sendto(sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, encbuf, encx);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx PONG to %s",
|
||||
macaddr_str(mac_buf, query.srcMac));
|
||||
|
@ -1727,6 +1915,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
|
||||
|
||||
pi.aflags = 0;
|
||||
memcpy(pi.srcMac, query.srcMac, sizeof(n2n_mac_t));
|
||||
memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t));
|
||||
pi.sock = scan->sock;
|
||||
|
||||
|
@ -1737,13 +1926,9 @@ static int process_udp (n2n_sn_t * sss,
|
|||
comm->header_iv_ctx,
|
||||
time_stamp());
|
||||
}
|
||||
// back to sender, be it edge or supernode (which will forward to edge)
|
||||
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, encbuf, encx);
|
||||
|
||||
if(cmn.flags & N2N_FLAGS_SOCKET) {
|
||||
sendto_sock(sss, &query.sock, encbuf, encx);
|
||||
} else {
|
||||
sendto(sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
}
|
||||
traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s",
|
||||
macaddr_str(mac_buf, query.srcMac));
|
||||
|
||||
|
@ -1757,12 +1942,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
macaddr_str(mac_buf, query.srcMac));
|
||||
|
||||
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
|
||||
|
||||
/* We are going to add socket even if it was not there before */
|
||||
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
query.sock.family = AF_INET;
|
||||
query.sock.port = ntohs(sender_sock->sin_port);
|
||||
memcpy(query.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
|
||||
cmn2.flags |= N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
encode_QUERY_PEER(encbuf, &encx, &cmn2, &query);
|
||||
|
||||
|
@ -1776,7 +1956,53 @@ static int process_udp (n2n_sn_t * sss,
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_TYPE_PEER_INFO: {
|
||||
n2n_PEER_INFO_t pi;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
struct peer_info *peer;
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp PEER_INFO with unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
decode_PEER_INFO(&pi, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
if(!find_edge_time_stamp_and_verify(comm->edges, sn, pi.srcMac, stamp, TIME_STAMP_NO_JITTER)) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped PEER_INFO due to time stamp error.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
traceEvent(TRACE_INFO, "Rx PEER_INFO from %s [%s]",
|
||||
macaddr_str(mac_buf, pi.srcMac),
|
||||
sock_to_cstr(sockbuf, &sender));
|
||||
|
||||
HASH_FIND_PEER(comm->edges, pi.srcMac, peer);
|
||||
if(peer != NULL) {
|
||||
if((comm->is_federation == IS_NO_FEDERATION) && (!is_null_mac(pi.srcMac))) {
|
||||
// this is a PEER_INFO for one of the edges conencted to this supernode, forward,
|
||||
// i.e. re-assemble (memcpy of udpbuf to encbuf could be sufficient as well)
|
||||
|
||||
// use incoming cmn (with already decreased TTL)
|
||||
// PEER_INFO remains unchanged
|
||||
|
||||
encode_PEER_INFO(encbuf, &encx, &cmn, &pi);
|
||||
|
||||
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
packet_header_encrypt(encbuf, encx, encx,
|
||||
comm->header_encryption_ctx, comm->header_iv_ctx,
|
||||
time_stamp());
|
||||
}
|
||||
|
||||
sendto_peer(sss, peer, encbuf, encx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1788,6 +2014,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Long lived processing entry point. Split out from main to simply
|
||||
* daemonisation on some platforms. */
|
||||
int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
|
||||
|
@ -1804,22 +2031,47 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
|
|||
ssize_t bread;
|
||||
int max_sock;
|
||||
fd_set socket_mask;
|
||||
n2n_tcp_connection_t *conn, *tmp_conn;
|
||||
struct sn_community *comm, *tmp_comm;
|
||||
struct peer_info *edge, *tmp_edge;
|
||||
|
||||
SOCKET tmp_sock;
|
||||
n2n_sock_str_t sockbuf;
|
||||
struct timeval wait_time;
|
||||
time_t now = 0;
|
||||
time_t before, now = 0;
|
||||
|
||||
FD_ZERO(&socket_mask);
|
||||
max_sock = MAX(sss->sock, sss->mgmt_sock);
|
||||
|
||||
FD_SET(sss->sock, &socket_mask);
|
||||
#ifdef N2N_HAVE_TCP
|
||||
FD_SET(sss->tcp_sock, &socket_mask);
|
||||
#endif
|
||||
FD_SET(sss->mgmt_sock, &socket_mask);
|
||||
|
||||
max_sock = MAX(MAX(sss->sock, sss->mgmt_sock), sss->tcp_sock);
|
||||
|
||||
#ifdef N2N_HAVE_TCP
|
||||
// add the tcp connections' sockets
|
||||
HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) {
|
||||
//socket descriptor
|
||||
FD_SET(conn->socket_fd, &socket_mask);
|
||||
if(conn->socket_fd > max_sock)
|
||||
max_sock = conn->socket_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
wait_time.tv_sec = 10;
|
||||
wait_time.tv_usec = 0;
|
||||
|
||||
before = time(NULL);
|
||||
|
||||
rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time);
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
if(rc > 0) {
|
||||
|
||||
// external udp
|
||||
if(FD_ISSET(sss->sock, &socket_mask)) {
|
||||
struct sockaddr_in sender_sock;
|
||||
socklen_t i;
|
||||
|
@ -1843,13 +2095,90 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
|
|||
break;
|
||||
}
|
||||
|
||||
/* We have a datagram to process */
|
||||
// we have a datagram to process...
|
||||
if(bread > 0) {
|
||||
/* And the datagram has data (not just a header) */
|
||||
process_udp(sss, &sender_sock, pktbuf, bread, now);
|
||||
// ...and the datagram has data (not just a header)
|
||||
process_udp(sss, &sender_sock, sss->sock, pktbuf, bread, now);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef N2N_HAVE_TCP
|
||||
// the so far known tcp connections
|
||||
// do NOT use 'HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) {' to iterate because
|
||||
// deletion of OTHER connections (that can happen if forwarding to another edge node fails)
|
||||
// may rsult in seg faults if using HASH ITER which is only safe to use if deleting current item
|
||||
for(conn = sss->tcp_connections; conn != NULL; conn = conn->hh.next ) {
|
||||
|
||||
if(FD_ISSET(conn->socket_fd, &socket_mask)) {
|
||||
|
||||
struct sockaddr_in sender_sock;
|
||||
socklen_t i;
|
||||
|
||||
i = sizeof(sender_sock);
|
||||
bread = recvfrom(conn->socket_fd,
|
||||
conn->buffer + conn->position, conn->expected - conn->position, 0 /*flags*/,
|
||||
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
|
||||
|
||||
if(bread <= 0) {
|
||||
traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno));
|
||||
#ifdef WIN32
|
||||
traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError());
|
||||
#endif
|
||||
close_tcp_connection(sss, conn);
|
||||
continue;
|
||||
}
|
||||
conn->position += bread;
|
||||
|
||||
if(conn->position == conn->expected) {
|
||||
if(conn->position == sizeof(uint16_t)) {
|
||||
// the prepended length has been read, preparing for the packet
|
||||
conn->expected += be16toh(*(uint16_t*)(conn->buffer));
|
||||
if(conn->expected > N2N_SN_PKTBUF_SIZE) {
|
||||
traceEvent(TRACE_ERROR, "too many bytes in tcp packet expected");
|
||||
close_tcp_connection(sss, conn);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// full packet read, handle it
|
||||
process_udp(sss, (struct sockaddr_in*)&(conn->sock), conn->socket_fd,
|
||||
conn->buffer + sizeof(uint16_t), conn->position - sizeof(uint16_t), now);
|
||||
// reset, await new prepended length
|
||||
conn->expected = sizeof(uint16_t);
|
||||
conn->position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accept new incoming tcp connection
|
||||
if(FD_ISSET(sss->tcp_sock, &socket_mask)) {
|
||||
struct sockaddr_in sender_sock;
|
||||
socklen_t i;
|
||||
|
||||
i = sizeof(sender_sock);
|
||||
if((HASH_COUNT(sss->tcp_connections) + 4) < FD_SETSIZE) {
|
||||
tmp_sock = accept(sss->tcp_sock, (struct sockaddr *)&sender_sock, (socklen_t *)&i);
|
||||
if(tmp_sock >= 0) {
|
||||
conn = (n2n_tcp_connection_t*)malloc(sizeof(n2n_tcp_connection_t));
|
||||
if(conn) {
|
||||
conn->socket_fd = tmp_sock;
|
||||
memcpy(&(conn->sock), &sender_sock, sizeof(struct sockaddr_in));
|
||||
conn->expected = sizeof(uint16_t);
|
||||
conn->position = 0;
|
||||
HASH_ADD_INT(sss->tcp_connections, socket_fd, conn);
|
||||
traceEvent(TRACE_DEBUG, "run_sn_loop accepted incoming TCP connection from %s",
|
||||
sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no space to store the socket for a new connection, close immediately
|
||||
traceEvent(TRACE_DEBUG, "run_sn_loop denied incoming TCP connection from %s due to max connections limit hit",
|
||||
sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock));
|
||||
}
|
||||
}
|
||||
#endif /* N2N_HAVE_TCP */
|
||||
|
||||
// handle management port input
|
||||
if(FD_ISSET(sss->mgmt_sock, &socket_mask)) {
|
||||
struct sockaddr_in sender_sock;
|
||||
size_t i;
|
||||
|
@ -1864,11 +2193,19 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
|
|||
break;
|
||||
}
|
||||
|
||||
/* We have a datagram to process */
|
||||
// we have a datagram to process
|
||||
process_mgmt(sss, &sender_sock, pktbuf, bread, now);
|
||||
}
|
||||
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "timeout");
|
||||
if(((now - before) < wait_time.tv_sec) && (*keep_running)){
|
||||
// this is no real timeout, something went wrong with one of the tcp connections (probably)
|
||||
// close them all, edges will re-open if they detect closure
|
||||
HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn)
|
||||
close_tcp_connection(sss, conn);
|
||||
traceEvent(TRACE_DEBUG, "falsly claimed timeout, assuming issue with tcp connection, closing them all");
|
||||
} else
|
||||
traceEvent(TRACE_DEBUG, "timeout");
|
||||
}
|
||||
|
||||
re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now);
|
||||
|
|
Loading…
Reference in New Issue
Block a user