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. 262
      src/edge_utils.c
  6. 42
      src/n2n.c
  7. 48
      src/sn.c
  8. 146
      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_ip_subnet_t dev_addr;
n2n_desc_t dev_desc; n2n_desc_t dev_desc;
n2n_sock_t sock; n2n_sock_t sock;
n2n_cookie_t last_cookie;
int timeout; int timeout;
uint8_t purgeable; uint8_t purgeable;
time_t last_seen; time_t last_seen;
time_t last_p2p; time_t last_p2p;
time_t last_sent_query; time_t last_sent_query;
time_t ping_time;
uint64_t last_valid_time_stamp; uint64_t last_valid_time_stamp;
char *ip_addr; char *ip_addr;
@ -271,7 +273,7 @@ typedef struct n2n_tuntap_priv_config {
typedef struct n2n_edge_conf { 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_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */ n2n_community_t community_name; /**< The community. 16 full octets. */
n2n_desc_t dev_desc; /**< The device description (hint) */ n2n_desc_t dev_desc; /**< The device description (hint) */
@ -309,12 +311,11 @@ struct n2n_edge {
n2n_edge_conf_t conf; n2n_edge_conf_t conf;
/* Status */ /* 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. */ uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */ size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
tuntap_dev device; /**< All about the TUNTAP device */ tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */ 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_route_t *sn_route_to_clean; /**< Supernode route to clean */
n2n_edge_callbacks_t cb; /**< API callbacks */ n2n_edge_callbacks_t cb; /**< API callbacks */
void *user_data; /**< Can hold user data */ 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_register_req; /**< Check if time to re-register with super*/
time_t last_p2p; /**< Last time p2p traffic was received. */ time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */ 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 */ 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); int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss); void sn_term(n2n_sn_t *sss);
int supernode2sock(n2n_sock_t * sn, const n2n_sn_name_t addrIn); 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 run_sn_loop(n2n_sn_t *sss, int *keep_running);
int assign_one_ip_subnet(n2n_sn_t *sss, struct sn_community *comm); int assign_one_ip_subnet(n2n_sn_t *sss, struct sn_community *comm);
const char* compression_str(uint8_t cmpr); const char* compression_str(uint8_t cmpr);

23
include/n2n_define.h

@ -30,25 +30,29 @@
#define MSG_TYPE_MAX_TYPE 10 #define MSG_TYPE_MAX_TYPE 10
/* Max available space to add supernodes' informations (sockets and MACs) in REGISTER_SUPER_ACK /* 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 \ #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 */ /* 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 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 (PURGE_FEDERATION_NODE_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 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 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 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 */
#define ETH_FRAMESIZE 14 #define ETH_FRAMESIZE 14
@ -83,7 +87,7 @@ enum federation{IS_NO_FEDERATION = 0,IS_FEDERATION = 1};
#define COMMUNITY_PURGEABLE 1 #define COMMUNITY_PURGEABLE 1
/* (un)purgeable supernode indicator */ /* (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 */ /* Header encryption indicators */
#define HEADER_ENCRYPTION_UNKNOWN 0 #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_EDGE_MGMT_PORT 5644
#define N2N_SN_MGMT_PORT 5645 #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_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */
#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/ #define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/
#define N2N_IF_MODE_SIZE 16 /* static | dhcp */ #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 { typedef struct n2n_PEER_INFO {
uint16_t aflags; uint16_t aflags;
n2n_mac_t srcMac;
n2n_mac_t mac; n2n_mac_t mac;
n2n_sock_t sock; n2n_sock_t sock;
} n2n_PEER_INFO_t; } n2n_PEER_INFO_t;
@ -195,6 +196,7 @@ typedef struct n2n_QUERY_PEER
{ {
n2n_mac_t srcMac; n2n_mac_t srcMac;
n2n_mac_t targetMac; 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; } n2n_QUERY_PEER_t;
typedef struct n2n_buf n2n_buf_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"); " | causes connections stall when not properly supported.\n");
#endif #endif
printf("-r | Enable packet forwarding through n2n community.\n"); 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("-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,\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 (default), -A4 = ChaCha20, -A5 = Speck-CTR.\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("-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" printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x"
#ifdef N2N_HAVE_ZSTD #ifdef N2N_HAVE_ZSTD
@ -434,6 +436,12 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec
case 'p': case 'p':
{ {
conf->local_port = atoi(optargument); conf->local_port = atoi(optargument);
if(conf->local_port == 0){
traceEvent(TRACE_WARNING, "Bad local port format");
break;
}
break; break;
} }
@ -835,9 +843,9 @@ int main(int argc, char* argv[]) {
if(conf.transop_id == N2N_TRANSFORM_ID_NULL) { if(conf.transop_id == N2N_TRANSFORM_ID_NULL) {
if(conf.encrypt_key) { if(conf.encrypt_key) {
/* make sure that AES is default cipher if key only (and no cipher) is specified */ /* make sure that Twofish is default cipher if key only (and no cipher) is specified */
traceEvent(TRACE_WARNING, "Switching to AES as key was provided."); traceEvent(TRACE_WARNING, "Switching to Twofish as key was provided.");
conf.transop_id = N2N_TRANSFORM_ID_AES; conf.transop_id = N2N_TRANSFORM_ID_TWOFISH;
} }
} }

262
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))) ((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL)))
return(-4); return(-4);
if (conf->dev_desc[0] == 0) if(HASH_COUNT(conf->supernodes) == 0)
return (-5); return(-5);
return(0); 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_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
n2n_transform_t transop_id = conf->transop_id; n2n_transform_t transop_id = conf->transop_id;
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t)); 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) { if((rc = edge_verify_conf(conf)) != 0) {
traceEvent(TRACE_ERROR, "Invalid configuration"); traceEvent(TRACE_ERROR, "Invalid configuration");
@ -193,6 +194,8 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
#endif #endif
memcpy(&eee->conf, conf, sizeof(*conf)); 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->start_time = time(NULL);
eee->known_peers = 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 // zstd does not require initialization. if it were required, this would be a good place
#endif #endif
for(i=0; i<eee->conf.sn_num; ++i) traceEvent(TRACE_NORMAL, "Number of supernodes in the list: %d\n", HASH_COUNT(eee->conf.supernodes));
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee->conf.sn_ip_array[i])); HASH_ITER(hh, eee->conf.supernodes, scan, tmp){
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (scan->ip_addr));
/* Set the active supernode */ i++;
supernode2sock(&(eee->supernode), eee->conf.sn_ip_array[eee->sn_idx]); }
/* Set active transop */ /* Set active transop */
switch(transop_id) { 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. */ /** 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}; uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
size_t idx; size_t idx;
/* ssize_t sent; */ /* 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; cmn.flags = 0;
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
for (idx = 0; (sn_idx==0) && (idx < N2N_COOKIE_SIZE); ++idx) for (idx = 0; idx < N2N_COOKIE_SIZE; ++idx)
eee->last_cookie[idx] = n2n_rand() % 0xff; 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_addr = ntohl(eee->device.ip_addr);
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask));
memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); 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); encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", 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) if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx, eee->conf.header_iv_ctx,
time_stamp(), pearson_hash_16(pktbuf, idx)); 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 int sort_supernodes(n2n_edge_t *eee, time_t now){
static void send_query_peer( n2n_edge_t * eee, struct peer_info *scan, *tmp;
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}};
cmn.ttl=N2N_DEFAULT_TTL; if(eee->curr_sn != eee->conf.supernodes){
cmn.pc = n2n_query_peer; eee->curr_sn = eee->conf.supernodes;
cmn.flags = 0; memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
memcpy( cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE ); eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
idx=0; traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]",
encode_mac( query.srcMac, &idx, eee->device.mac_addr ); supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts);
idx=0;
encode_mac( query.targetMac, &idx, dstMac );
idx=0; send_register_super(eee);
encode_QUERY_PEER( pktbuf, &idx, &cmn, &query ); 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){ HASH_ITER(hh, eee->conf.supernodes, scan, tmp){
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, scan->ping_time = MAX_PING_TIME;
eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
} }
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); }
send_query_peer(eee, null_mac);
}
return 0; /* OK */
} }
/** Send a REGISTER packet to another edge. */ /** 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. * This is frequently called by the main loop.
*/ */
void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) { 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)))) { if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) {
/* fall through */ /* fall through */
@ -878,12 +946,10 @@ void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
if(0 == eee->sup_attempts) { if(0 == eee->sup_attempts) {
/* Give up on that supernode and try the next one. */ /* Give up on that supernode and try the next one. */
++(eee->sn_idx); eee->curr_sn->ping_time = MAX_PING_TIME;
HASH_SORT(eee->conf.supernodes, ping_time_sort);
if(eee->sn_idx >= eee->conf.sn_num) { eee->curr_sn = eee->conf.supernodes;
/* Got to end of list, go back to the start. Also works for list of one entry. */ memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t));
eee->sn_idx=0;
}
traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee)); 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 else
--(eee->sup_attempts); --(eee->sup_attempts);
for(sn_idx=0; sn_idx<eee->conf.sn_num; sn_idx++) { if(supernode2sock(&(eee->supernode), eee->curr_sn->ip_addr) == 0) {
if(supernode2sock(&(eee->supernode), eee->conf.sn_ip_array[sn_idx]) == 0) { traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]",
traceEvent(TRACE_INFO, "Registering with supernode [id: %u/%u][%s][attempts left %u]", supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts);
sn_idx+1, eee->conf.sn_num,
supernode_ip(eee), (unsigned int)eee->sup_attempts);
send_register_super(eee, &(eee->supernode), sn_idx); send_register_super(eee);
}
} }
register_with_local_peers(eee); register_with_local_peers(eee);
eee->sn_wait=1; 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. */ /** Return the IP address of the current supernode in the ring. */
static const char * supernode_ip(const n2n_edge_t * eee) { 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. */ /** 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 */ n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
macstr_t mac_buf1; macstr_t mac_buf1;
macstr_t mac_buf2; macstr_t mac_buf2;
uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
ssize_t recvlen; ssize_t recvlen;
size_t rem; 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 /* 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. */ * 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.family = AF_INET; /* UDP socket was opened PF_INET v4 */
sender.port = ntohs(sender_sock.sin_port); sender.port = ntohs(sender_sock.sin_port);
memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE); 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; char * ip_str = NULL;
n2n_REGISTER_SUPER_ACK_t ra; n2n_REGISTER_SUPER_ACK_t ra;
uint8_t tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES]; 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)); memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
@ -1887,12 +1956,23 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
return; 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) tmp_sock = (void*)&tmpbuf;
{ tmp_mac = (void*)&tmpbuf[sizeof(n2n_sock_t)];
traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK payload contains sockets and MACs of supernodes in the federation.");
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->last_sup = now;
eee->sn_wait=0; eee->sn_wait=0;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ 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 /* NOTE: the register_interval should be chosen by the edge node
* based on its NAT configuration. */ * based on its NAT configuration. */
//eee->conf.register_interval = ra.lifetime; //eee->conf.register_interval = ra.lifetime;
eee->curr_sn->ping_time = (now - eee->last_register_req)*1000;
} }
else else
{ {
@ -1932,6 +2014,8 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
case MSG_TYPE_PEER_INFO: { case MSG_TYPE_PEER_INFO: {
n2n_PEER_INFO_t pi; n2n_PEER_INFO_t pi;
struct peer_info * scan; struct peer_info * scan;
int skip_add;
decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx ); decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx );
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
@ -1948,18 +2032,29 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
break; break;
} }
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 {
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
if(scan) { if(scan) {
scan->sock = pi.sock; scan->sock = pi.sock;
traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s", traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s",
macaddr_str(mac_buf1, pi.mac), macaddr_str(mac_buf1, pi.mac),
sock_to_cstr(sockbuf1, &pi.sock)); sock_to_cstr(sockbuf1, &pi.sock));
send_register(eee, &scan->sock, scan->mac_addr); send_register(eee, &scan->sock, scan->mac_addr);
} else { } else {
traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s",
macaddr_str(mac_buf1, pi.mac) ); macaddr_str(mac_buf1, pi.mac) );
} }
}
break; break;
} }
default: default:
@ -2111,6 +2206,8 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
if (eee->cb.main_loop_period) if (eee->cb.main_loop_period)
eee->cb.main_loop_period(eee, nowTime); eee->cb.main_loop_period(eee, nowTime);
sort_supernodes(eee, nowTime);
} /* while */ } /* while */
#ifdef WIN32 #ifdef WIN32
@ -2494,7 +2591,7 @@ static int edge_init_routes_linux(n2n_edge_t *eee, n2n_route_t *routes, uint16_t
return(-1); return(-1);
} }
if (supernode2sock(&sn, eee->conf.sn_ip_array[0]) < 0) if (supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0)
return(-1); return(-1);
if (sn.family != AF_INET) { if (sn.family != AF_INET) {
@ -2635,7 +2732,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
if (getenv("N2N_KEY")) { if (getenv("N2N_KEY")) {
conf->encrypt_key = strdup(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) { int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
if(conf->sn_num >= N2N_EDGE_NUM_SUPERNODES) struct peer_info *sn;
return(-1); 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 = %s", sn->ip_addr);
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)conf->sn_num, (conf->sn_ip_array[conf->sn_num]));
conf->sn_num++; conf->sn_num++;
return(0); return(0);
@ -2680,7 +2804,7 @@ int quick_edge_init(char *device_name, char *community_name,
/* Setup the configuration */ /* Setup the configuration */
edge_init_conf_defaults(&conf); edge_init_conf_defaults(&conf);
conf.encrypt_key = encrypt_key; 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; conf.compression = N2N_COMPRESSION_ID_NONE;
snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name); snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name);
edge_conf_add_supernode(&conf, supernode_ip_address_port); 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 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 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 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; struct addrinfo * ainfo = NULL;
int nameerr; int nameerr;
if(supernode_port) if(supernode_port){
sn->port = atoi(supernode_port); sn->port = atoi(supernode_port);
}
else else
traceEvent(TRACE_WARNING, "Bad supernode parameter (-l <host:port>) %s %s:%s", traceEvent(TRACE_WARNING, "Bad supernode parameter (-l <host:port>) %s %s:%s",
addr, supernode_host, supernode_port); 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) { uint8_t is_multi_broadcast(const uint8_t * dest_mac) {
int is_broadcast =(memcmp(broadcast_addr, dest_mac, 6) == 0); 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; size_t retval=0;
HASH_ITER(hh, *peer_list, scan, tmp) { 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); HASH_DEL(*peer_list, scan);
retval++; retval++;
free(scan); free(scan);

48
src/sn.c

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

146
src/sn_utils.c

@ -251,6 +251,7 @@ int sn_init(n2n_sn_t *sss) {
sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED; sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED;
/*setup the encryption key */ /*setup the encryption key */
packet_header_setup_key(sss->federation->community, &(sss->federation->header_encryption_ctx), &(sss->federation->header_iv_ctx)); 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()); 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) ); 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; time_t time;
struct peer_info *peer, *tmp; struct peer_info *peer, *tmp;
if((now - (*p_last_re_reg_and_purge)) < RE_REG_AND_PURGE_FREQUENCY ) return 0;
if(comm != NULL) { if(comm != NULL) {
HASH_ITER(hh,comm->edges,peer,tmp) { HASH_ITER(hh,comm->edges,peer,tmp) {
time = now - peer->last_seen; time = now - peer->last_seen;
if(time <= ALLOWED_TIME) continue; if(time <= ALLOWED_TIME) continue;
if((time < PURGE_FEDERATION_NODE_INTERVAL) if((time < PURGE_FEDERATION_NODE_INTERVAL)
|| (peer->purgeable == SN_UNPURGEABLE) /* FIX fcarli3 */ || (peer->purgeable == SN_UNPURGEABLE)
) { ) {
/* re-regitser (send REGISTER_SUPER) */ /* re-regitser (send REGISTER_SUPER) */
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; 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.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super; cmn.pc = n2n_register_super;
cmn.flags = 0; cmn.flags = N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); 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; cookie[idx] = n2n_rand() % 0xff;
memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE); 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 */ reg.auth.scheme = 0; /* No auth yet */
idx = 0; idx = 0;
encode_mac(reg.edgeMac, &idx, peer->mac_addr); encode_mac(reg.edgeMac, &idx, sss->mac_addr);
idx = 0; idx = 0;
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg); 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, comm->header_iv_ctx,
time_stamp(), pearson_hash_16(pktbuf, idx)); 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*/ 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 */ return 0; /* OK */
} }
@ -735,46 +740,6 @@ static int sendto_mgmt(n2n_sn_t *sss,
return 0; 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. /** Examine a datagram and determine what to do with it.
* *
*/ */
@ -1059,6 +1024,7 @@ static int process_udp(n2n_sn_t * sss,
n2n_common_t cmn2; n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; 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; size_t encx=0;
struct sn_community *fed; struct sn_community *fed;
struct sn_community_regular_expression *re, *tmp_re; struct sn_community_regular_expression *re, *tmp_re;
@ -1068,8 +1034,7 @@ static int process_udp(n2n_sn_t * sss,
int match_length = 0; int match_length = 0;
n2n_ip_subnet_t ipaddr; n2n_ip_subnet_t ipaddr;
int num = 0; int num = 0;
n2n_sock_t *tmp_sock; int skip_add;
n2n_mac_t *tmp_mac;
memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
@ -1129,16 +1094,22 @@ static int process_udp(n2n_sn_t * sss,
traceEvent(TRACE_INFO, "New community: %s", comm->community); 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.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack; cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_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) || 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 */)) { ((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) {
memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t)); memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t));
@ -1152,30 +1123,29 @@ static int process_udp(n2n_sn_t * sss,
ack.sock.port = ntohs(sender_sock->sin_port); ack.sock.port = ntohs(sender_sock->sin_port);
memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
if(from_supernode != comm->is_federation) { 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"); traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking");
return -1; return -1;
} }
/* Add sender's data to federation (or update it) */ /* Add sender's data to federation (or update it) */
if(comm->is_federation == IS_FEDERATION) { if(comm->is_federation == IS_FEDERATION) {
p = add_sn_to_federation_by_mac_or_sock(sss,&(ack.sock),&(reg.edgeMac)); skip_add = NO_SKIP;
if(p) p->last_seen = now; 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 // REVISIT: consider adding last_seen
/* Assembling supernode list for REGISTER_SUPER_ACK payload */ /* Assembling supernode list for REGISTER_SUPER_ACK payload */
tmp_dst = tmpbuf;
HASH_ITER(hh, sss->federation->edges, peer, tmp_peer) { 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((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 */ 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*)tmp_dst, (void*)&(peer->sock), sizeof(n2n_sock_t));
memcpy((void*)tmpbuf, (void*)&(peer->mac_addr), sizeof(n2n_mac_t)); tmp_dst += sizeof(n2n_sock_t);
tmp_sock += ENTRY_SIZE; memcpy((void*)tmp_dst, (void*)&(peer->mac_addr), sizeof(n2n_mac_t));
tmp_mac += ENTRY_SIZE; tmp_dst += sizeof(n2n_mac_t);
} }
ack.num_sn = num; ack.num_sn = num;
@ -1222,7 +1192,9 @@ static int process_udp(n2n_sn_t * sss,
n2n_mac_t *tmp_mac; n2n_mac_t *tmp_mac;
int i; int i;
uint8_t dec_tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES]; uint8_t dec_tmpbuf[MAX_AVAILABLE_SPACE_FOR_ENTRIES];
int skip_add;
memset(&sender, 0, sizeof(n2n_sock_t));
sender.family = AF_INET; sender.family = AF_INET;
sender.port = ntohs(sender_sock->sin_port); sender.port = ntohs(sender_sock->sin_port);
memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); 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; 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."); traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK: from_supernode value doesn't correspond to the internal federation marking.");
return -1; return -1;
} }
@ -1258,7 +1230,8 @@ static int process_udp(n2n_sn_t * sss,
sock_to_cstr(sockbuf2, orig_sender)); sock_to_cstr(sockbuf2, orig_sender));
if(comm->is_federation == IS_FEDERATION) { 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) { if(scan != NULL) {
scan->last_seen = now; scan->last_seen = now;
} else { } else {
@ -1267,18 +1240,20 @@ static int process_udp(n2n_sn_t * sss,
} }
} }
tmp_sock = (void*)&(ack.num_sn) + sizeof(ack.num_sn); tmp_sock = (void *)dec_tmpbuf;
tmp_mac = (void*)tmp_sock + sizeof(n2n_sock_t); tmp_mac = (void*)dec_tmpbuf + sizeof(n2n_sock_t);
for(i=0; i<ack.num_sn; i++) { 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) { if(skip_add == ADDED) {
tmp->last_seen = now - TEST_TIME; tmp->last_seen = now - TEST_TIME;
} }
tmp_sock += ENTRY_SIZE; /* REVISIT: find a more elegant expression to increase following pointers. */
tmp_mac += ENTRY_SIZE; tmp_sock = (void*)tmp_sock + ENTRY_SIZE;
tmp_mac = (void*)tmp_sock + sizeof(n2n_sock_t);
} }
break; break;
@ -1305,6 +1280,34 @@ static int process_udp(n2n_sn_t * sss,
} }
} }
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 );
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) );
memcpy( pi.srcMac, sss->mac_addr, sizeof(n2n_mac_t) );
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 PING to %s",
macaddr_str( mac_buf, query.srcMac ) );
} else {
traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s", traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
macaddr_str( mac_buf, query.srcMac ), macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) ); macaddr_str( mac_buf2, query.targetMac ) );
@ -1339,6 +1342,8 @@ static int process_udp(n2n_sn_t * sss,
macaddr_str( mac_buf, query.targetMac ) ); macaddr_str( mac_buf, query.targetMac ) );
} }
}
break; break;
} }
default: default:
@ -1356,6 +1361,7 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
time_t last_purge_edges = 0; time_t last_purge_edges = 0;
time_t last_sort_communities = 0; time_t last_sort_communities = 0;
time_t last_re_reg_and_purge = 0;
sss->start_time = time(NULL); sss->start_time = time(NULL);
@ -1440,7 +1446,7 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
traceEvent(TRACE_DEBUG, "timeout"); 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); purge_expired_communities(sss, &last_purge_edges, now);
sort_communities (sss, &last_sort_communities, now); sort_communities (sss, &last_sort_communities, now);
} /* while */ } /* while */

4
src/wire.c

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

Loading…
Cancel
Save