Browse Source

Update REGISTER_SUPER_ACK handling on edge (#478)

pull/479/head
Francesco Carli 4 years ago
committed by GitHub
parent
commit
dcbc39c0fb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      include/n2n.h
  2. 23
      include/n2n_define.h
  3. 2
      include/n2n_wire.h
  4. 20
      src/edge.c
  5. 290
      src/edge_utils.c
  6. 42
      src/n2n.c
  7. 52
      src/sn.c
  8. 256
      src/sn_utils.c
  9. 4
      src/wire.c

10
include/n2n.h

@ -199,11 +199,13 @@ struct peer_info {
n2n_ip_subnet_t dev_addr;
n2n_desc_t dev_desc;
n2n_sock_t sock;
n2n_cookie_t last_cookie;
int timeout;
uint8_t purgeable;
time_t last_seen;
time_t last_p2p;
time_t last_sent_query;
time_t ping_time;
uint64_t last_valid_time_stamp;
char *ip_addr;
@ -271,7 +273,7 @@ typedef struct n2n_tuntap_priv_config {
typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
struct peer_info *supernodes; /**< List of supernodes */
n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */
n2n_desc_t dev_desc; /**< The device description (hint) */
@ -309,12 +311,11 @@ struct n2n_edge {
n2n_edge_conf_t conf;
/* Status */
uint8_t sn_idx; /**< Currently active supernode. */
struct peer_info *curr_sn; /**< Currently active supernode. */
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */
n2n_edge_callbacks_t cb; /**< API callbacks */
void *user_data; /**< Can hold user data */
@ -339,6 +340,7 @@ struct n2n_edge {
time_t last_register_req; /**< Check if time to re-register with super*/
time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */
time_t last_sweep; /**< Last time a sweep was performed. */
time_t start_time; /**< For calculating uptime */
@ -503,7 +505,7 @@ int comm_init(struct sn_community *comm, char *cmn);
int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss);
int supernode2sock(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
struct peer_info* add_sn_to_federation_by_mac_or_sock(n2n_sn_t *sss, n2n_sock_t *sock, n2n_mac_t *mac);
struct peer_info* add_sn_to_list_by_mac_or_sock(struct peer_info **sn_list, n2n_sock_t *sock, n2n_mac_t *mac, int *skip_add);
int run_sn_loop(n2n_sn_t *sss, int *keep_running);
int assign_one_ip_subnet(n2n_sn_t *sss, struct sn_community *comm);
const char* compression_str(uint8_t cmpr);

23
include/n2n_define.h

@ -30,25 +30,29 @@
#define MSG_TYPE_MAX_TYPE 10
/* Max available space to add supernodes' informations (sockets and MACs) in REGISTER_SUPER_ACK
* Field sizes of REGISTER_SUPER_ACK as used in encode/decode fucntions in src/wire.c */
* Field sizes of REGISTER_SUPER_ACK as used in encode/decode fucntions in src/wire.c
* REVISIT: replace 255 by DEFAULT_MTU as soon as header encryption allows for longer packets to be encrypted. */
#define MAX_AVAILABLE_SPACE_FOR_ENTRIES \
DEFAULT_MTU-(1+1+2+sizeof(n2n_common_t)+sizeof(n2n_cookie_t)+sizeof(n2n_mac_t)+1+2+4+1+sizeof(n2n_sock_t)+1) \
(255-(1+1+2+sizeof(n2n_common_t)+sizeof(n2n_cookie_t)+sizeof(n2n_mac_t)+1+2+4+1+sizeof(n2n_sock_t)+1)) \
/* Space needed to store socket and MAC address of a supernode */
#define ENTRY_SIZE sizeof(n2n_sock_t)+sizeof(n2n_mac_t)
#define ENTRY_SIZE (sizeof(n2n_sock_t)+sizeof(n2n_mac_t))
#define PURGE_REGISTRATION_FREQUENCY 30
#define RE_REG_AND_PURGE_FREQUENCY 10
#define REGISTRATION_TIMEOUT 60
#define PURGE_FEDERATION_NODE_INTERVAL 90
#define SOCKET_TIMEOUT_INTERVAL_SECS 10
#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */
#define ALLOWED_TIME 20 /* sec, indicates supernodes that are proven to be alive */
#define TEST_TIME (PURGE_FEDERATION_NODE_INTERVAL - ALLOWED_TIME)/2 /* sec, indicates supernodes with unsure status, must be tested to check if they are alive */
#define MAX_PING_TIME 3000 /* millisec, indicates default value for ping_time field in peer_info structure */
#define SWEEP_TIME 30 /* sec, indicates the value after which we have to sort the hash list of supernodes in edges */
#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */
#define TRANSOP_TICK_INTERVAL (10) /* sec */
#define PURGE_REGISTRATION_FREQUENCY 30
#define REGISTRATION_TIMEOUT 60
#define PURGE_FEDERATION_NODE_INTERVAL 90
#define SORT_COMMUNITIES_INTERVAL 90 /* sec. until supernode sorts communities' hash list again */
#define ETH_FRAMESIZE 14
@ -83,7 +87,7 @@ enum federation{IS_NO_FEDERATION = 0,IS_FEDERATION = 1};
#define COMMUNITY_PURGEABLE 1
/* (un)purgeable supernode indicator */
enum sn_purge{SN_UNPURGEABLE = 0, SN_PURGEABLE = 1};
enum sn_purge{SN_PURGEABLE = 0, SN_UNPURGEABLE = 1};
/* Header encryption indicators */
#define HEADER_ENCRYPTION_UNKNOWN 0
@ -103,6 +107,9 @@ enum sn_purge{SN_UNPURGEABLE = 0, SN_PURGEABLE = 1};
#define N2N_EDGE_MGMT_PORT 5644
#define N2N_SN_MGMT_PORT 5645
/* flag used in add_sn_to_list_by_mac_or_sock */
enum skip_add{NO_SKIP = 0, SKIP = 1, ADDED = 2};
#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */
#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/
#define N2N_IF_MODE_SIZE 16 /* static | dhcp */

2
include/n2n_wire.h

@ -186,6 +186,7 @@ typedef struct n2n_REGISTER_SUPER_NAK
typedef struct n2n_PEER_INFO {
uint16_t aflags;
n2n_mac_t srcMac;
n2n_mac_t mac;
n2n_sock_t sock;
} n2n_PEER_INFO_t;
@ -195,6 +196,7 @@ typedef struct n2n_QUERY_PEER
{
n2n_mac_t srcMac;
n2n_mac_t targetMac;
uint8_t req_data; /* data we want the supernode to send back in the answer's payload (e.g. 0 = no payload, 1 = number of connected nodes ...) */
} n2n_QUERY_PEER_t;
typedef struct n2n_buf n2n_buf_t;

20
src/edge.c

@ -172,9 +172,11 @@ static void help() {
" | causes connections stall when not properly supported.\n");
#endif
printf("-r | Enable packet forwarding through n2n community.\n");
printf("-A1 | Disable payload encryption. Do not use with key (defaulting to AES then).\n");
printf("-A2 ... -A5 or -A | Choose a cipher for payload encryption, requires a key: -A2 = Twofish,\n");
printf(" | -A3 or -A (deprecated) = AES (default), -A4 = ChaCha20, -A5 = Speck-CTR.\n");
printf("-A1 | Disable payload encryption. Do not use with key (defaulting to Twofish then).\n");
printf("-A2 ... -A5 or -A | Choose a cipher for payload encryption, requires a key: -A2 = Twofish (default),\n");
printf(" | -A3 or -A (deprecated) = AES, "
"-A4 = ChaCha20, "
"-A5 = Speck-CTR.\n");
printf("-H | Enable full header encryption. Requires supernode with fixed community.\n");
printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x"
#ifdef N2N_HAVE_ZSTD
@ -434,6 +436,12 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec
case 'p':
{
conf->local_port = atoi(optargument);
if(conf->local_port == 0){
traceEvent(TRACE_WARNING, "Bad local port format");
break;
}
break;
}
@ -835,9 +843,9 @@ int main(int argc, char* argv[]) {
if(conf.transop_id == N2N_TRANSFORM_ID_NULL) {
if(conf.encrypt_key) {
/* make sure that AES is default cipher if key only (and no cipher) is specified */
traceEvent(TRACE_WARNING, "Switching to AES as key was provided.");
conf.transop_id = N2N_TRANSFORM_ID_AES;
/* make sure that Twofish is default cipher if key only (and no cipher) is specified */
traceEvent(TRACE_WARNING, "Switching to Twofish as key was provided.");
conf.transop_id = N2N_TRANSFORM_ID_TWOFISH;
}
}

290
src/edge_utils.c

@ -63,8 +63,8 @@ int edge_verify_conf(const n2n_edge_conf_t *conf) {
((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL)))
return(-4);
if (conf->dev_desc[0] == 0)
return (-5);
if(HASH_COUNT(conf->supernodes) == 0)
return(-5);
return(0);
}
@ -176,7 +176,8 @@ static int is_ip6_discovery(const void * buf, size_t bufsize) {
n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
n2n_transform_t transop_id = conf->transop_id;
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
int rc = -1, i;
int rc = -1, i = 0;
struct peer_info *scan, *tmp;
if((rc = edge_verify_conf(conf)) != 0) {
traceEvent(TRACE_ERROR, "Invalid configuration");
@ -193,6 +194,8 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
#endif
memcpy(&eee->conf, conf, sizeof(*conf));
eee->curr_sn = eee->conf.supernodes;
//memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
eee->start_time = time(NULL);
eee->known_peers = NULL;
@ -211,11 +214,11 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
// zstd does not require initialization. if it were required, this would be a good place
#endif
for(i=0; i<eee->conf.sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee->conf.sn_ip_array[i]));
/* Set the active supernode */
supernode2sock(&(eee->supernode), eee->conf.sn_ip_array[eee->sn_idx]);
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++;
}
/* Set active transop */
switch(transop_id) {
@ -687,8 +690,73 @@ static void check_join_multicast_group(n2n_edge_t *eee) {
/* ************************************** */
/** 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];
cmn.ttl=N2N_DEFAULT_TTL;
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 );
query.req_data = 0;
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,
eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
}
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
} else {
traceEvent( TRACE_DEBUG, "send PING to supernodes" );
memcpy(tmp_pkt, pktbuf, idx);
HASH_ITER(hh, eee->conf.supernodes, peer, tmp){
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED){
/* Re-encrypt the orginal message again for non-repeating IV. */
memcpy(pktbuf, tmp_pkt, idx);
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
}
sendto_sock( eee->udp_sock, pktbuf, idx, &(peer->sock));
}
}
}
/* ******************************************************** */
static int ping_time_sort(struct peer_info *a, struct peer_info *b){
// comparison function for sorting supernodes in ascending order of their
// ping_time-fields
return (a->ping_time - b->ping_time);
}
/** Send a REGISTER_SUPER packet to the current supernode. */
static void send_register_super(n2n_edge_t *eee, const n2n_sock_t *supernode, int sn_idx) {
static void send_register_super(n2n_edge_t *eee) {
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
size_t idx;
/* ssize_t sent; */
@ -704,10 +772,10 @@ static void send_register_super(n2n_edge_t *eee, const n2n_sock_t *supernode, in
cmn.flags = 0;
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
for (idx = 0; (sn_idx==0) && (idx < N2N_COOKIE_SIZE); ++idx)
eee->last_cookie[idx] = n2n_rand() % 0xff;
for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx)
eee->curr_sn->last_cookie[idx] = n2n_rand() % 0xff;
memcpy(reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE);
memcpy(reg.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE);
reg.dev_addr.net_addr = ntohl(eee->device.ip_addr);
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask));
memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE);
@ -720,47 +788,47 @@ static void send_register_super(n2n_edge_t *eee, const n2n_sock_t *supernode, in
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, supernode));
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, supernode);
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock));
}
/* ************************************** */
/** 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}};
static int sort_supernodes(n2n_edge_t *eee, time_t now){
struct peer_info *scan, *tmp;
cmn.ttl=N2N_DEFAULT_TTL;
cmn.pc = n2n_query_peer;
cmn.flags = 0;
memcpy( cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE );
if(eee->curr_sn != eee->conf.supernodes){
eee->curr_sn = eee->conf.supernodes;
memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
idx=0;
encode_mac( query.srcMac, &idx, eee->device.mac_addr );
idx=0;
encode_mac( query.targetMac, &idx, dstMac );
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);
idx=0;
encode_QUERY_PEER( pktbuf, &idx, &cmn, &query );
send_register_super(eee);
eee->sn_wait = 1;
}
traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" );
if(now - eee->last_sweep > SWEEP_TIME){
if(eee->sn_wait == 0){
// this routine gets periodically called
// it sorts supernodes in ascending order of their ping_time-fields
HASH_SORT(eee->conf.supernodes, ping_time_sort);
eee->last_sweep = now;
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));
HASH_ITER(hh, eee->conf.supernodes, scan, tmp){
scan->ping_time = MAX_PING_TIME;
}
}
send_query_peer(eee, null_mac);
}
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
return 0; /* OK */
}
/** Send a REGISTER packet to another edge. */
@ -866,7 +934,7 @@ static void send_register_ack(n2n_edge_t * eee,
* This is frequently called by the main loop.
*/
void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
u_int sn_idx;
struct peer_info *scan, *tmp;
if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) {
/* fall through */
@ -878,12 +946,10 @@ void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
if(0 == eee->sup_attempts) {
/* Give up on that supernode and try the next one. */
++(eee->sn_idx);
if(eee->sn_idx >= eee->conf.sn_num) {
/* Got to end of list, go back to the start. Also works for list of one entry. */
eee->sn_idx=0;
}
eee->curr_sn->ping_time = MAX_PING_TIME;
HASH_SORT(eee->conf.supernodes, ping_time_sort);
eee->curr_sn = eee->conf.supernodes;
memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee));
@ -904,16 +970,14 @@ void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
else
--(eee->sup_attempts);
for(sn_idx=0; sn_idx<eee->conf.sn_num; sn_idx++) {
if(supernode2sock(&(eee->supernode), eee->conf.sn_ip_array[sn_idx]) == 0) {
traceEvent(TRACE_INFO, "Registering with supernode [id: %u/%u][%s][attempts left %u]",
sn_idx+1, eee->conf.sn_num,
supernode_ip(eee), (unsigned int)eee->sup_attempts);
if(supernode2sock(&(eee->supernode), eee->curr_sn->ip_addr) == 0) {
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);
send_register_super(eee, &(eee->supernode), sn_idx);
}
send_register_super(eee);
}
register_with_local_peers(eee);
eee->sn_wait=1;
@ -940,7 +1004,7 @@ static void send_deregister(n2n_edge_t * eee,
/** Return the IP address of the current supernode in the ring. */
static const char * supernode_ip(const n2n_edge_t * eee) {
return (eee->conf.sn_ip_array)[eee->sn_idx];
return (eee->curr_sn->ip_addr);
}
/* ************************************** */
@ -1632,9 +1696,6 @@ void edge_read_from_tap(n2n_edge_t * eee) {
}
}
/* ************************************** */
/* ************************************** */
/** Read a datagram from the main UDP socket to the internet. */
@ -1645,7 +1706,6 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
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;
@ -1680,6 +1740,10 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
/* 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. */
/* REVISIT: do not endprse use with several supernodes
memset(&sender, 0, sizeof(n2n_sock_t)); */
sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */
sender.port = ntohs(sender_sock.sin_port);
memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE);
@ -1850,6 +1914,11 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
char * ip_str = NULL;
n2n_REGISTER_SUPER_ACK_t ra;
uint8_t tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES];
n2n_sock_t *tmp_sock;
n2n_mac_t *tmp_mac;
int i;
int skip_add;
struct peer_info *sn;
memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
@ -1887,12 +1956,23 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
return;
}
if(0 == memcmp(ra.cookie, eee->last_cookie, N2N_COOKIE_SIZE))
if(0 == memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE))
{
if(ra.num_sn > 0)
{
traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK payload contains sockets and MACs of supernodes in the federation.");
}
tmp_sock = (void*)&tmpbuf;
tmp_mac = (void*)&tmpbuf[sizeof(n2n_sock_t)];
for(i=0; i<ra.num_sn; i++){
skip_add = NO_SKIP;
sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), tmp_sock, tmp_mac, &skip_add);
if(skip_add == ADDED){
traceEvent(TRACE_NORMAL, "Supernode added to the list of supernodes.");
}
/* REVISIT: find a more elegant expression to increase following pointers. */
tmp_sock = (void*)tmp_sock + ENTRY_SIZE;
tmp_mac = (void*)tmp_sock + sizeof(n2n_sock_t);
}
eee->last_sup = now;
eee->sn_wait=0;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */
@ -1917,6 +1997,8 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
/* NOTE: the register_interval should be chosen by the edge node
* based on its NAT configuration. */
//eee->conf.register_interval = ra.lifetime;
eee->curr_sn->ping_time = (now - eee->last_register_req)*1000;
}
else
{
@ -1932,6 +2014,8 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
case MSG_TYPE_PEER_INFO: {
n2n_PEER_INFO_t pi;
struct peer_info * scan;
int skip_add;
decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx );
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
@ -1942,24 +2026,35 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
}
if(!is_valid_peer_sock(&pi.sock)) {
traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]",
sock_to_cstr(sockbuf1, &pi.sock),
macaddr_str(mac_buf1, pi.mac) );
break;
traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]",
sock_to_cstr(sockbuf1, &pi.sock),
macaddr_str(mac_buf1, pi.mac) );
break;
}
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
if(scan) {
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));
send_register(eee, &scan->sock, scan->mac_addr);
if(memcmp(pi.mac, null_mac, sizeof(n2n_mac_t)) == 0){
skip_add = SKIP;
scan = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, &pi.srcMac, &skip_add);
if(scan != NULL){
scan->ping_time = (now - eee->last_sweep)*1000;
break;
}
} else {
traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s",
macaddr_str(mac_buf1, pi.mac) );
}
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
if(scan) {
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));
send_register(eee, &scan->sock, scan->mac_addr);
} else {
traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s",
macaddr_str(mac_buf1, pi.mac) );
}
}
break;
}
default:
@ -2111,6 +2206,8 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
if (eee->cb.main_loop_period)
eee->cb.main_loop_period(eee, nowTime);
sort_supernodes(eee, nowTime);
} /* while */
#ifdef WIN32
@ -2494,7 +2591,7 @@ static int edge_init_routes_linux(n2n_edge_t *eee, n2n_route_t *routes, uint16_t
return(-1);
}
if (supernode2sock(&sn, eee->conf.sn_ip_array[0]) < 0)
if (supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0)
return(-1);
if (sn.family != AF_INET) {
@ -2635,7 +2732,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
if (getenv("N2N_KEY")) {
conf->encrypt_key = strdup(getenv("N2N_KEY"));
conf->transop_id = N2N_TRANSFORM_ID_AES;
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
}
}
@ -2655,11 +2752,38 @@ const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
/* ************************************** */
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
if(conf->sn_num >= N2N_EDGE_NUM_SUPERNODES)
return(-1);
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);
}
skip_add = NO_SKIP;
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);
strncpy((conf->sn_ip_array[conf->sn_num]), ip_and_port, N2N_EDGE_SN_HOST_SIZE);
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)conf->sn_num, (conf->sn_ip_array[conf->sn_num]));
traceEvent(TRACE_NORMAL, "Adding supernode = %s", sn->ip_addr);
conf->sn_num++;
return(0);
@ -2680,7 +2804,7 @@ int quick_edge_init(char *device_name, char *community_name,
/* Setup the configuration */
edge_init_conf_defaults(&conf);
conf.encrypt_key = encrypt_key;
conf.transop_id = N2N_TRANSFORM_ID_AES;
conf.transop_id = N2N_TRANSFORM_ID_TWOFISH;
conf.compression = N2N_COMPRESSION_ID_NONE;
snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name);
edge_conf_add_supernode(&conf, supernode_ip_address_port);

42
src/n2n.c

@ -26,6 +26,7 @@
static const uint8_t broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const uint8_t multicast_addr[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */
static const uint8_t ipv6_multicast_addr[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */
static const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0};
/* ************************************** */
@ -242,8 +243,9 @@ int supernode2sock(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
struct addrinfo * ainfo = NULL;
int nameerr;
if(supernode_port)
if(supernode_port){
sn->port = atoi(supernode_port);
}
else
traceEvent(TRACE_WARNING, "Bad supernode parameter (-l <host:port>) %s %s:%s",
addr, supernode_host, supernode_port);
@ -287,6 +289,42 @@ int supernode2sock(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
/* ************************************** */
struct peer_info* add_sn_to_list_by_mac_or_sock(struct peer_info **sn_list, n2n_sock_t *sock, n2n_mac_t *mac, int *skip_add){
struct peer_info *scan, *tmp, *peer = NULL;
if(memcmp(mac,null_mac,sizeof(n2n_mac_t)) != 0) { /* not zero MAC */
HASH_FIND_PEER(*sn_list, mac, peer);
//REVISIT: make this dependent from last_seen and update socket
}
if(peer == NULL) { /* zero MAC, search by socket */
HASH_ITER(hh,*sn_list,scan,tmp) {
if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) {
HASH_DEL(*sn_list, scan);
memcpy(&(scan->mac_addr), mac, sizeof(n2n_mac_t));
HASH_ADD_PEER(*sn_list, scan);
peer = scan;
break;
}
}
if((peer == NULL) && (*skip_add == NO_SKIP)) {
peer = (struct peer_info*)calloc(1,sizeof(struct peer_info));
if(peer) {
memcpy(&(peer->sock),sock,sizeof(n2n_sock_t));
memcpy(&(peer->mac_addr),mac, sizeof(n2n_mac_t));
HASH_ADD_PEER(*sn_list, peer);
*skip_add = ADDED;
}
}
}
return peer;
}
/* ************************************************ */
uint8_t is_multi_broadcast(const uint8_t * dest_mac) {
int is_broadcast =(memcmp(broadcast_addr, dest_mac, 6) == 0);
@ -370,7 +408,7 @@ size_t purge_peer_list(struct peer_info ** peer_list,
size_t retval=0;
HASH_ITER(hh, *peer_list, scan, tmp) {
if(scan->last_seen < purge_before) {
if(scan->purgeable == SN_PURGEABLE && scan->last_seen < purge_before) {
HASH_DEL(*peer_list, scan);
retval++;
free(scan);

52
src/sn.c

@ -195,7 +195,7 @@ static void help() {
printf("-p <port> | Set UDP main listen port to <port>\n");
printf("-c <path> | File containing the allowed communities.\n");
printf("-l <sn:port> | Supernode IP:port.\n");
printf("-l <sn host:port> | Name/IP of a known supernode:port.\n");
#if defined(N2N_HAVE_DAEMON)
printf("-f | Run in foreground.\n");
#endif /* #if defined(N2N_HAVE_DAEMON) */
@ -224,10 +224,22 @@ static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) {
switch (optkey) {
case 'p': /* local-port */
sss->lport = atoi(_optarg);
if(sss->lport == 0){
traceEvent(TRACE_WARNING, "Bad local port format");
break;
}
break;
case 't': /* mgmt-port */
sss->mport = atoi(_optarg);
if(sss->mport == 0){
traceEvent(TRACE_WARNING, "Bad management port format");
break;
}
break;
case 'l': { /* supernode:port */
@ -235,44 +247,48 @@ static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) {
struct peer_info *anchor_sn;
size_t length;
int rv = -1;
int skip_add;
char *double_column = strchr(_optarg, ':');
length = strlen(_optarg);
if(length >= N2N_EDGE_SN_HOST_SIZE) {
traceEvent(TRACE_WARNING, "Size of -l argument too long: %zu. Maximum size is %d",length,N2N_EDGE_SN_HOST_SIZE);
traceEvent(TRACE_WARNING, "Size of -l argument too long: %zu. Maximum size is %d", length, N2N_EDGE_SN_HOST_SIZE);
break;
}
/* Need to check the format IP:port */
if(!double_column) {
if(!double_column){
traceEvent(TRACE_WARNING, "Invalid -l format: ignored");
return(-1);
return (-1);
}
socket = (n2n_sock_t *)calloc(1,sizeof(n2n_sock_t));
rv = supernode2sock(socket, _optarg);
if(rv != 0){
traceEvent(TRACE_WARNING, "Invalid socket");
free(socket);
break;
}
if(sss->federation != NULL) {
socket = (n2n_sock_t *)calloc(1,sizeof(n2n_sock_t));
anchor_sn = add_sn_to_federation_by_mac_or_sock(sss,socket, (n2n_mac_t*) null_mac);
skip_add = NO_SKIP;
anchor_sn = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), socket, (n2n_mac_t*) null_mac, &skip_add);
if(anchor_sn != NULL){
anchor_sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE);
if(anchor_sn->ip_addr){
strncpy(anchor_sn->ip_addr,_optarg,N2N_EDGE_SN_HOST_SIZE-1);
rv = supernode2sock(socket,_optarg);
if(rv != 0){
traceEvent(TRACE_WARNING, "Invalid socket");
break;
}
memcpy(&(anchor_sn->sock), socket, sizeof(n2n_sock_t));
memcpy(&(anchor_sn->sock), socket, sizeof(n2n_sock_t));
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();
}
}
}
free(socket);
break;
}
@ -329,8 +345,10 @@ static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) {
#endif
case 'F': { /* federation name */
snprintf(sss->federation->community, N2N_COMMUNITY_SIZE-1, "*%s" ,_optarg);
sss->federation->community[N2N_COMMUNITY_SIZE-1] = '\0';
snprintf(sss->federation->community,N2N_COMMUNITY_SIZE-1,"*%s",_optarg);
sss->federation->community[N2N_COMMUNITY_SIZE-1] = '\0';
break;
}

256
src/sn_utils.c

@ -251,6 +251,7 @@ int sn_init(n2n_sn_t *sss) {
sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED;
/*setup the encryption key */
packet_header_setup_key(sss->federation->community, &(sss->federation->header_encryption_ctx), &(sss->federation->header_iv_ctx));
sss->federation->edges = NULL;
}
n2n_srand (n2n_seed());
@ -511,17 +512,19 @@ static int find_edge_time_stamp_and_verify (struct peer_info * edges,
return ( time_stamp_verify_and_update (stamp, previous_stamp, allow_jitter) );
}
static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community *comm, time_t now) {
static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community *comm, time_t *p_last_re_reg_and_purge, time_t now) {
time_t time;
struct peer_info *peer, *tmp;
if((now - (*p_last_re_reg_and_purge)) < RE_REG_AND_PURGE_FREQUENCY ) return 0;
if(comm != NULL) {
HASH_ITER(hh,comm->edges,peer,tmp) {
time = now - peer->last_seen;
if(time <= ALLOWED_TIME) continue;
if((time < PURGE_FEDERATION_NODE_INTERVAL)
|| (peer->purgeable == SN_UNPURGEABLE) /* FIX fcarli3 */
|| (peer->purgeable == SN_UNPURGEABLE)
) {
/* re-regitser (send REGISTER_SUPER) */
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
@ -537,10 +540,10 @@ static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community *
cmn.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super;
cmn.flags = 0;
cmn.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE);
for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx) /* aggiungi sn_idx */
for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx)
cookie[idx] = n2n_rand() % 0xff;
memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE);
@ -549,7 +552,7 @@ static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community *
reg.auth.scheme = 0; /* No auth yet */
idx = 0;
encode_mac(reg.edgeMac, &idx, peer->mac_addr);
encode_mac(reg.edgeMac, &idx, sss->mac_addr);
idx = 0;
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
@ -561,12 +564,14 @@ static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community *
comm->header_iv_ctx,
time_stamp(), pearson_hash_16(pktbuf, idx));
/* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, N2N_PKT_BUF_SIZE);
/* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, idx);
}
if(time >= PURGE_FEDERATION_NODE_INTERVAL) purge_expired_registrations(&(comm->edges),&time,PURGE_FEDERATION_NODE_INTERVAL);/* purge not-seen-long-time supernodes*/
}
}
(*p_last_re_reg_and_purge) = now;
return 0; /* OK */
}
@ -735,46 +740,6 @@ static int sendto_mgmt(n2n_sn_t *sss,
return 0;
}
/** Search for a node in the federation list. If it has to add a new node, it creates a new peer_info and initializes it
* Evaluate first the MAC parameter and if it's zero-MAC, then it can skip HASH_FIND_PEER by MAC and search by socket
*/
struct peer_info* add_sn_to_federation_by_mac_or_sock(n2n_sn_t *sss,n2n_sock_t *sock, n2n_mac_t *mac) {
struct peer_info *scan, *tmp, *peer = NULL;
int found = 0;
if(sss->federation != NULL) {
if(memcmp(mac,null_mac,sizeof(n2n_mac_t)) != 0) { /* not zero MAC */
HASH_FIND_PEER(sss->federation->edges, mac, peer);
//REVISIT: make this dependent from last_seen and update socket
}
if(peer == NULL) { /* zero MAC, search by socket */
HASH_ITER(hh,sss->federation->edges,scan,tmp) {
if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t))) {
memcpy(&(scan->mac_addr), sock, sizeof(n2n_mac_t));
peer = scan;
break;
}
}
if(peer == NULL) {
peer = (struct peer_info*)calloc(1,sizeof(struct peer_info));
if(peer) {
memcpy(&(peer->sock),sock,sizeof(n2n_sock_t));
memcpy(&(peer->mac_addr),mac, sizeof(n2n_mac_t));
HASH_ADD_PEER(sss->federation->edges,peer);
}
}
}
}
return peer;
}
/** Examine a datagram and determine what to do with it.
*
*/
@ -1058,18 +1023,18 @@ static int process_udp(n2n_sn_t * sss,
n2n_REGISTER_SUPER_ACK_t ack;
n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
uint8_t tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES];
uint8_t tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES];
uint8_t *tmp_dst;
size_t encx=0;
struct sn_community *fed;
struct sn_community_regular_expression *re, *tmp_re;
struct peer_info *peer, *tmp_peer, *p;
struct peer_info *peer, *tmp_peer, *p;
int8_t allowed_match = -1;
uint8_t match = 0;
int match_length = 0;
int match_length = 0;
n2n_ip_subnet_t ipaddr;
int num = 0;
n2n_sock_t *tmp_sock;
n2n_mac_t *tmp_mac;
int num = 0;
int skip_add;
memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
@ -1079,13 +1044,13 @@ static int process_udp(n2n_sn_t * sss,
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx);
if (comm) {
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, reg.edgeMac, stamp, TIME_STAMP_NO_JITTER)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER due to time stamp error.");
return -1;
}
}
}
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, reg.edgeMac, stamp, TIME_STAMP_NO_JITTER)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER due to time stamp error.");
return -1;
}
}
}
/*
Before we move any further, we need to check if the requested
@ -1095,8 +1060,8 @@ static int process_udp(n2n_sn_t * sss,
*/
if(!comm && sss->lock_communities) {
HASH_ITER(hh, sss->rules, re, tmp_re) {
allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length);
HASH_ITER(hh, sss->rules, re, tmp_re) {
allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length);
if( (allowed_match != -1)
&& (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted)
@ -1112,7 +1077,7 @@ static int process_udp(n2n_sn_t * sss,
}
}
if(!comm && (!sss->lock_communities || (match == 1))) {
if(!comm && (!sss->lock_communities || (match == 1))) {
comm = (struct sn_community*)calloc(1,sizeof(struct sn_community));
@ -1127,18 +1092,24 @@ static int process_udp(n2n_sn_t * sss,
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
assign_one_ip_subnet(sss, comm);
assign_one_ip_subnet(sss, comm);
}
}
}
if(comm) {
if(comm) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
if(comm->is_federation == IS_FEDERATION){
memcpy(&(ack.edgeMac), &(sss->mac_addr), sizeof(n2n_mac_t));
}else{
memcpy(&(ack.edgeMac), &(reg.edgeMac), sizeof(n2n_mac_t));
}
if ((reg.dev_addr.net_addr == 0) || (reg.dev_addr.net_addr == 0xFFFFFFFF) || (reg.dev_addr.net_bitlen == 0) ||
((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) {
memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t));
@ -1152,37 +1123,36 @@ static int process_udp(n2n_sn_t * sss,
ack.sock.port = ntohs(sender_sock->sin_port);
memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
if(from_supernode != comm->is_federation) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking");
return -1;
}
if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking");
return -1;
}
/* Add sender's data to federation (or update it) */
if(comm->is_federation == IS_FEDERATION) {
p = add_sn_to_federation_by_mac_or_sock(sss,&(ack.sock),&(reg.edgeMac));
if(p) p->last_seen = now;
skip_add = NO_SKIP;
p = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(ack.sock), &(reg.edgeMac), &skip_add);
}
tmp_sock = (void*)tmpbuf;
tmp_mac = (void*)tmpbuf + sizeof(n2n_sock_t);
// REVISIT: consider adding last_seen
/* Assembling supernode list for REGISTER_SUPER_ACK payload */
tmp_dst = tmpbuf;
HASH_ITER(hh, sss->federation->edges, peer, tmp_peer) {
if(memcmp(&(peer->sock), &(ack.sock), sizeof(n2n_sock_t)) == 0) continue; /* a supernode doesn't add itself to the payload */
if((now - peer->last_seen) >= ALLOWED_TIME) continue; /* skip long-time-not-seen supernodes */
if(((++num)*ENTRY_SIZE) > MAX_AVAILABLE_SPACE_FOR_ENTRIES) break; /* no more space available in REGISTER_SUPER_ACK payload */
memcpy((void*)tmpbuf, (void*)&(peer->sock), sizeof(n2n_sock_t));
memcpy((void*)tmpbuf, (void*)&(peer->mac_addr), sizeof(n2n_mac_t));
tmp_sock += ENTRY_SIZE;
tmp_mac += ENTRY_SIZE;
memcpy((void*)tmp_dst, (void*)&(peer->sock), sizeof(n2n_sock_t));
tmp_dst += sizeof(n2n_sock_t);
memcpy((void*)tmp_dst, (void*)&(peer->mac_addr), sizeof(n2n_mac_t));
tmp_dst += sizeof(n2n_mac_t);
}
ack.num_sn = num;
traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
if(memcmp(reg.edgeMac, &null_mac, N2N_MAC_SIZE) != 0) {
update_edge(sss, &reg, comm, &(ack.sock), now);
@ -1192,8 +1162,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (ackbuf, encx));
comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (ackbuf, encx));
sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
@ -1202,9 +1172,9 @@ static int process_udp(n2n_sn_t * sss,
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
} else {
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community);
return -1;
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community);
return -1;
}
break;
}
@ -1222,7 +1192,9 @@ static int process_udp(n2n_sn_t * sss,
n2n_mac_t *tmp_mac;
int i;
uint8_t dec_tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES];
int skip_add;
memset(&sender, 0, sizeof(n2n_sock_t));
sender.family = AF_INET;
sender.port = ntohs(sender_sock->sin_port);
memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
@ -1235,7 +1207,7 @@ static int process_udp(n2n_sn_t * sss,
return -1;
}
if(from_supernode != comm->is_federation) {
if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK: from_supernode value doesn't correspond to the internal federation marking.");
return -1;
}
@ -1246,9 +1218,9 @@ static int process_udp(n2n_sn_t * sss,
if (comm) {
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, ack.edgeMac, stamp, TIME_STAMP_NO_JITTER)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to time stamp error.");
return -1;
}
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to time stamp error.");
return -1;
}
}
}
@ -1258,27 +1230,30 @@ static int process_udp(n2n_sn_t * sss,
sock_to_cstr(sockbuf2, orig_sender));
if(comm->is_federation == IS_FEDERATION) {
HASH_FIND_PEER(sss->federation->edges, ack.edgeMac, scan);
skip_add = SKIP;
scan = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &sender, &(ack.edgeMac), &skip_add);
if(scan != NULL) {
scan->last_seen = now;
scan->last_seen = now;
} else {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to an unknown supernode.");
break;
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to an unknown supernode.");
break;
}
}
tmp_sock = (void*)&(ack.num_sn) + sizeof(ack.num_sn);
tmp_mac = (void*)tmp_sock + sizeof(n2n_sock_t);
tmp_sock = (void *)dec_tmpbuf;
tmp_mac = (void*)dec_tmpbuf + sizeof(n2n_sock_t);
for(i=0; i<ack.num_sn; i++) {
tmp = add_sn_to_federation_by_mac_or_sock(sss,tmp_sock,tmp_mac);
skip_add = NO_SKIP;
tmp = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), tmp_sock, tmp_mac, &skip_add);
if(tmp) {
tmp->last_seen = now - TEST_TIME;
if(skip_add == ADDED) {
tmp->last_seen = now - TEST_TIME;
}
tmp_sock += ENTRY_SIZE;
tmp_mac += ENTRY_SIZE;
/* REVISIT: find a more elegant expression to increase following pointers. */
tmp_sock = (void*)tmp_sock + ENTRY_SIZE;
tmp_mac = (void*)tmp_sock + sizeof(n2n_sock_t);
}
break;
@ -1305,39 +1280,69 @@ static int process_udp(n2n_sn_t * sss,
}
}
traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) );
struct peer_info *scan;
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if(memcmp(query.targetMac, null_mac, sizeof(n2n_mac_t)) == 0){
traceEvent( TRACE_DEBUG, "Rx PING from %s. Requested data: %d",
macaddr_str( mac_buf, query.srcMac ),
query.req_data );
if (scan) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
pi.aflags = 0;
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
pi.sock = scan->sock;
memcpy( pi.srcMac, sss->mac_addr, sizeof(n2n_mac_t) );
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (encbuf, encx));
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (encbuf, encx));
sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str( mac_buf, query.srcMac ) );
} else {
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) );
}
traceEvent( TRACE_DEBUG, "Tx PING to %s",
macaddr_str( mac_buf, query.srcMac ) );
} else {
traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) );
struct peer_info *scan;
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if (scan) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
pi.aflags = 0;
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
pi.sock = scan->sock;
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (encbuf, encx));
sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str( mac_buf, query.srcMac ) );
} else {
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) );
}
}
break;
}
@ -1356,6 +1361,7 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
time_t last_purge_edges = 0;
time_t last_sort_communities = 0;
time_t last_re_reg_and_purge = 0;
sss->start_time = time(NULL);
@ -1440,7 +1446,7 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
traceEvent(TRACE_DEBUG, "timeout");
}
re_register_and_purge_supernodes(sss, sss->federation, now);
re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now);
purge_expired_communities(sss, &last_purge_edges, now);
sort_communities (sss, &last_sort_communities, now);
} /* while */

4
src/wire.c

@ -514,6 +514,7 @@ int encode_PEER_INFO(uint8_t *base,
int retval = 0;
retval += encode_common(base, idx, common);
retval += encode_uint16(base, idx, pkt->aflags);
retval += encode_mac(base, idx, pkt->srcMac);
retval += encode_mac(base, idx, pkt->mac);
retval += encode_sock(base, idx, &pkt->sock);
@ -529,6 +530,7 @@ int decode_PEER_INFO(n2n_PEER_INFO_t *pkt,
size_t retval = 0;
memset(pkt, 0, sizeof(n2n_PEER_INFO_t));
retval += decode_uint16(&(pkt->aflags), base, rem, idx);
retval += decode_mac(pkt->srcMac, base, rem, idx);
retval += decode_mac(pkt->mac, base, rem, idx);
retval += decode_sock(&pkt->sock, base, rem, idx);
@ -545,6 +547,7 @@ int encode_QUERY_PEER( uint8_t * base,
retval += encode_common( base, idx, common );
retval += encode_mac( base, idx, pkt->srcMac );
retval += encode_mac( base, idx, pkt->targetMac );
retval += encode_uint8( base, idx, pkt->req_data);
return retval;
}
@ -559,6 +562,7 @@ int decode_QUERY_PEER( n2n_QUERY_PEER_t * pkt,
memset( pkt, 0, sizeof(n2n_QUERY_PEER_t) );
retval += decode_mac( pkt->srcMac, base, rem, idx );
retval += decode_mac( pkt->targetMac, base, rem, idx );
retval += decode_uint8( &pkt->req_data, base, rem, idx);
return retval;
}

Loading…
Cancel
Save