Implement purge-and-re-registration process for supernodes (#445)

This commit is contained in:
Francesco Carli 2020-10-01 16:23:10 +02:00 committed by GitHub
parent 3f8d32fa77
commit 8dfffd9fbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 154 additions and 6 deletions

View File

@ -467,7 +467,7 @@ int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp, int
size_t purge_peer_list( struct peer_info ** peer_list, size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before ); time_t purge_before );
size_t clear_peer_list( struct peer_info ** peer_list ); size_t clear_peer_list( struct peer_info ** peer_list );
size_t purge_expired_registrations( struct peer_info ** peer_list, time_t* p_last_purge ); size_t purge_expired_registrations( struct peer_info ** peer_list, time_t* p_last_purge, int timeout );
/* Edge conf */ /* Edge conf */
void edge_init_conf_defaults(n2n_edge_conf_t *conf); void edge_init_conf_defaults(n2n_edge_conf_t *conf);

View File

@ -40,13 +40,14 @@
#define SOCKET_TIMEOUT_INTERVAL_SECS 10 #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 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 ALLOWED_TIME 20 /* sec, indicates supernodes that are proven to be alive */
#define TEST_TIME (SORT_COMMUNITIES_INTERVAL - ALLOWED_TIME)/2 /* sec, indicates supernodes with unsure status, must be tested to check if they are 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 IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */ #define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */
#define TRANSOP_TICK_INTERVAL (10) /* sec */ #define TRANSOP_TICK_INTERVAL (10) /* sec */
#define PURGE_REGISTRATION_FREQUENCY 30 #define PURGE_REGISTRATION_FREQUENCY 30
#define REGISTRATION_TIMEOUT 60 #define REGISTRATION_TIMEOUT 60
#define PURGE_FEDERATION_NODE_INTERVAL 90
#define SORT_COMMUNITIES_INTERVAL 90 /* sec. until supernode sorts communities' hash list again */ #define SORT_COMMUNITIES_INTERVAL 90 /* sec. until supernode sorts communities' hash list again */

View File

@ -2139,8 +2139,8 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
/* Finished processing select data. */ /* Finished processing select data. */
update_supernode_reg(eee, nowTime); update_supernode_reg(eee, nowTime);
numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known); numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known, PURGE_REGISTRATION_FREQUENCY);
numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending); numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending, PURGE_REGISTRATION_FREQUENCY);
if(numPurged > 0) { if(numPurged > 0) {
traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u",

View File

@ -280,11 +280,11 @@ void print_n2n_version() {
/* *********************************************** */ /* *********************************************** */
size_t purge_expired_registrations(struct peer_info ** peer_list, time_t* p_last_purge) { size_t purge_expired_registrations(struct peer_info ** peer_list, time_t* p_last_purge, int timeout) {
time_t now = time(NULL); time_t now = time(NULL);
size_t num_reg = 0; size_t num_reg = 0;
if((now - (*p_last_purge)) < PURGE_REGISTRATION_FREQUENCY) return 0; if((now - (*p_last_purge)) < timeout) return 0;
traceEvent(TRACE_DEBUG, "Purging old registrations"); traceEvent(TRACE_DEBUG, "Purging old registrations");

View File

@ -496,6 +496,62 @@ static int find_edge_time_stamp_and_verify (struct peer_info * edges,
return ( time_stamp_verify_and_update (stamp, previous_stamp, allow_jitter) ); 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){
time_t time;
struct peer_info *peer, *tmp;
if(comm != NULL){
HASH_ITER(hh,comm->edges,peer,tmp){
time = now - peer->last_seen;
if(time <= ALLOWED_TIME) continue;
if((time > ALLOWED_TIME) && (time < PURGE_FEDERATION_NODE_INTERVAL)){ /* re-regitser (send REGISTER_SUPER) */
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
size_t idx;
/* ssize_t sent; */
n2n_common_t cmn;
n2n_cookie_t cookie;
n2n_REGISTER_SUPER_t reg;
n2n_sock_str_t sockbuf;
memset(&cmn, 0, sizeof(cmn));
memset(&reg, 0, sizeof(reg));
cmn.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super;
cmn.flags = 0;
memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE);
for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx) /* aggiungi sn_idx */
cookie[idx] = n2n_rand() % 0xff;
memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE);
reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr);
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen));
reg.auth.scheme = 0; /* No auth yet */
idx = 0;
encode_mac(reg.edgeMac, &idx, peer->mac_addr);
idx = 0;
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, &(peer->sock)));
packet_header_encrypt(pktbuf, idx, comm->header_encryption_ctx,
comm->header_iv_ctx,
time_stamp(), pearson_hash_16(pktbuf, idx));
/* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, N2N_PKT_BUF_SIZE);
}
if(time >= PURGE_FEDERATION_NODE_INTERVAL) purge_expired_registrations(&(comm->edges),&time,PURGE_FEDERATION_NODE_INTERVAL);/* purge not-seen-long-time supernodes*/
}
}
return 0; /* OK */
}
static int purge_expired_communities(n2n_sn_t *sss, static int purge_expired_communities(n2n_sn_t *sss,
time_t* p_last_purge, time_t* p_last_purge,
time_t now) time_t now)
@ -659,6 +715,44 @@ static int sendto_mgmt(n2n_sn_t *sss,
return 0; return 0;
} }
/** Iterate through REGISTER_SUPER_ACK payload and add new supernodes with a legal timestamp
* (half of the difference between the adjustable 20 seconds and 90 seconds limit) to the federation list
*/
static int add_sn_to_federation_from_register_super_ack(n2n_sn_t *sss, n2n_REGISTER_SUPER_ACK_t ack){
struct sn_community *fed;
struct peer_info *peer;
n2n_sock_t *tmp_sock;
n2n_mac_t *tmp_mac;
int i;
HASH_FIND_COMMUNITY(sss->communities, sss->federation, fed);
if(fed != NULL){
tmp_sock = &(ack.sn_bak);
tmp_mac = &(ack.mac_addr);
for(i=0; i<ack.num_sn; i++){
HASH_FIND_PEER(fed->edges, &tmp_mac, peer);
if(peer == NULL){
peer = (struct peer_info *)calloc(1,sizeof(struct peer_info));
memcpy(&(peer->sock),tmp_sock,sizeof(n2n_sock_t));
memcpy(&(peer->mac_addr), &tmp_mac, sizeof(n2n_mac_t));
peer->dev_addr.net_addr = ntohs(ack.dev_addr.net_addr);
peer->dev_addr.net_bitlen = mask2bitlen(ntohl(ack.dev_addr.net_bitlen));
peer->last_seen = TEST_TIME;
HASH_ADD_PEER(fed->edges, peer);
}
tmp_sock += sizeof(n2n_mac_t);
tmp_mac += sizeof(n2n_sock_t);
}
}
return 0; /* OK */
}
/** Examine a datagram and determine what to do with it. /** Examine a datagram and determine what to do with it.
* *
*/ */
@ -1086,6 +1180,59 @@ static int process_udp(n2n_sn_t * sss,
} }
break; break;
} }
case MSG_TYPE_REGISTER_SUPER_ACK: {
n2n_REGISTER_SUPER_ACK_t ack;
size_t encx=0;
struct sn_community *fed;
struct peer_info *scan;
n2n_sock_str_t sockbuf1;
n2n_sock_str_t sockbuf2;
macstr_t mac_buf1;
n2n_sock_t sender;
n2n_sock_t *orig_sender;
sender.family = AF_INET;
sender.port = ntohs(sender_sock->sin_port);
memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
orig_sender = &sender;
memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
if(from_supernode != comm->is_federation){
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK: from_supernode value doesn't correspond to the internal federation marking.");
return -1;
}
decode_REGISTER_SUPER_ACK(&ack,&cmn,udp_buf,&rem,&idx);
orig_sender = &(ack.sock);
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_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s)",
macaddr_str(mac_buf1, ack.mac_addr),
sock_to_cstr(sockbuf1, &sender),
sock_to_cstr(sockbuf2, orig_sender));
HASH_FIND_COMMUNITY(sss->communities, sss->federation, fed);
if(fed != NULL) {
HASH_FIND_PEER(fed->edges, ack.edgeMac, scan);
if(scan != NULL){
scan->last_seen = now;
}
}
if(ack.num_sn > 0) add_sn_to_federation_from_register_super_ack(sss,ack);
break;
}
case MSG_TYPE_QUERY_PEER: { case MSG_TYPE_QUERY_PEER: {
n2n_QUERY_PEER_t query; n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];