diff --git a/include/n2n.h b/include/n2n.h index 8342543..ba0d7b7 100644 --- a/include/n2n.h +++ b/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); diff --git a/include/n2n_define.h b/include/n2n_define.h index 4228c2e..7cac1b5 100644 --- a/include/n2n_define.h +++ b/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 */ diff --git a/include/n2n_wire.h b/include/n2n_wire.h index a27a93d..86b75e2 100644 --- a/include/n2n_wire.h +++ b/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; diff --git a/src/edge.c b/src/edge.c index ccea3a8..3022582 100644 --- a/src/edge.c +++ b/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 @@ -387,7 +389,7 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec case 'z': { int compression; - + if (optargument) { compression = atoi(optargument); } else @@ -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; } @@ -616,7 +624,7 @@ static int loadFromFile(const char *path, n2n_edge_conf_t *conf, n2n_tuntap_priv } } else if(line[0] == '-') { /* short opt */ char *equal; - + key = &line[1], line_len--; equal = strchr(line, '='); @@ -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; } } @@ -852,7 +860,7 @@ int main(int argc, char* argv[]) { #if defined(HAVE_OPENSSL_1_1) traceEvent(TRACE_NORMAL, "Using %s", OpenSSL_version(0)); #endif - + traceEvent(TRACE_NORMAL, "Using compression: %s.", compression_str(conf.compression)); traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id)); @@ -862,7 +870,7 @@ int main(int argc, char* argv[]) { #ifndef WIN32 /* If running suid root then we need to setuid before using the force. */ if(setuid(0) != 0) - traceEvent(TRACE_ERROR, "Unable to become root [%u/%s]", errno, strerror(errno)); + traceEvent(TRACE_ERROR, "Unable to become root [%u/%s]", errno, strerror(errno)); /* setgid(0); */ #endif diff --git a/src/edge_utils.c b/src/edge_utils.c index ab9d09c..97030c6 100644 --- a/src/edge_utils.c +++ b/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; iconf.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, ®); 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_idxconf.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; iconf.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); diff --git a/src/n2n.c b/src/n2n.c index 5a1d067..fa605cd 100644 --- a/src/n2n.c +++ b/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 ) %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); diff --git a/src/sn.c b/src/sn.c index 29c75f7..1a15e70 100644 --- a/src/sn.c +++ b/src/sn.c @@ -195,7 +195,7 @@ static void help() { printf("-p | Set UDP main listen port to \n"); printf("-c | File containing the allowed communities.\n"); - printf("-l | Supernode IP:port.\n"); + printf("-l | 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; } diff --git a/src/sn_utils.c b/src/sn_utils.c index 4560308..a24975a 100644 --- a/src/sn_utils.c +++ b/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, ®); @@ -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(®, &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)); @@ -1151,38 +1122,37 @@ static int process_udp(n2n_sn_t * sss, ack.sock.family = AF_INET; 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, ®, 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; ifederation->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 */ diff --git a/src/wire.c b/src/wire.c index 1dc1003..9103129 100644 --- a/src/wire.c +++ b/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; }