From 3bd4635f04399f9dc2f8e6cd86a226522935ddd7 Mon Sep 17 00:00:00 2001 From: Francesco Carli <62562180+fcarli3@users.noreply.github.com> Date: Thu, 19 Nov 2020 09:31:24 +0100 Subject: [PATCH] Protection mechanism against duplicated MACs (#509) * Prevent duplicated MACs * Prevent duplicated MACs * Fix compile errors * Fix compile errors * Implement auth scheme * Fix compile errors * Add auth_edge * Add auth_edge * Implement REGISTER_SUPER forwarding * Add argument to update_edge * Add auth field to supernode struct * Add REGISTER_SUPER_NAK handling * Fix issues * Code clean-up * Move auth token initialization --- include/n2n_define.h | 13 +- include/n2n_typedefs.h | 38 +++++- include/n2n_wire.h | 22 ++++ src/edge_utils.c | 95 +++++++++++--- src/sn_utils.c | 277 +++++++++++++++++++++++++++++++++-------- src/wire.c | 69 +++++++++- 6 files changed, 433 insertions(+), 81 deletions(-) diff --git a/include/n2n_define.h b/include/n2n_define.h index a921eab..930c0ab 100644 --- a/include/n2n_define.h +++ b/include/n2n_define.h @@ -22,12 +22,13 @@ #define MSG_TYPE_PACKET 3 #define MSG_TYPE_REGISTER_ACK 4 #define MSG_TYPE_REGISTER_SUPER 5 -#define MSG_TYPE_REGISTER_SUPER_ACK 6 -#define MSG_TYPE_REGISTER_SUPER_NAK 7 -#define MSG_TYPE_FEDERATION 8 -#define MSG_TYPE_PEER_INFO 9 -#define MSG_TYPE_QUERY_PEER 10 -#define MSG_TYPE_MAX_TYPE 10 +#define MSG_TYPE_UNREGISTER_SUPER 6 +#define MSG_TYPE_REGISTER_SUPER_ACK 7 +#define MSG_TYPE_REGISTER_SUPER_NAK 8 +#define MSG_TYPE_FEDERATION 9 +#define MSG_TYPE_PEER_INFO 10 +#define MSG_TYPE_QUERY_PEER 11 +#define MSG_TYPE_MAX_TYPE 11 /* 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 diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index b02a044..cf1dba5 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -245,11 +245,12 @@ typedef enum n2n_pc n2n_packet=3, /* PACKET data content */ n2n_register_ack=4, /* ACK of a registration from edge to edge */ n2n_register_super=5, /* Register edge to supernode */ - n2n_register_super_ack=6, /* ACK from supernode to edge */ - n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */ - n2n_federation=8, /* Not used by edge */ - n2n_peer_info=9, /* Send info on a peer from sn to edge */ - n2n_query_peer=10 /* ask supernode for info on a peer */ + n2n_unregister_super=6, /* Deregister edge from supernode */ + n2n_register_super_ack=7, /* ACK from supernode to edge */ + n2n_register_super_nak=8, /* NAK from supernode to edge - registration refused */ + n2n_federation=9, /* Not used by edge */ + n2n_peer_info=10, /* Send info on a peer from sn to edge */ + n2n_query_peer=11 /* ask supernode for info on a peer */ } n2n_pc_t; #define N2N_FLAGS_OPTIONS 0x0080 @@ -289,6 +290,20 @@ typedef struct n2n_sock } addr; } n2n_sock_t; +typedef enum +{ + n2n_auth_none = 0, + n2n_auth_simple_id = 1 +} n2n_auth_scheme_t; + +typedef enum +{ + update_edge_no_change = 0, + update_edge_sock_change = 1, + update_edge_new_sn = 2, + update_edge_auth_fail = -1 +} update_edge_ret_value_t; + typedef struct n2n_auth { uint16_t scheme; /* What kind of auth */ @@ -338,6 +353,7 @@ typedef struct n2n_PACKET typedef struct n2n_REGISTER_SUPER { n2n_cookie_t cookie; /**< Link REGISTER_SUPER and REGISTER_SUPER_ACK */ n2n_mac_t edgeMac; /**< MAC to register with edge sending socket */ + n2n_sock_t sock; /**< Sending socket associated with srcMac */ n2n_ip_subnet_t dev_addr; /**< IP address of the tuntap adapter. */ n2n_desc_t dev_desc; /**< Hint description correlated with the edge */ n2n_auth_t auth; /**< Authentication scheme and tokens */ @@ -366,6 +382,7 @@ typedef struct n2n_REGISTER_SUPER_ACK { typedef struct n2n_REGISTER_SUPER_NAK { n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */ + n2n_mac_t srcMac; } n2n_REGISTER_SUPER_NAK_t; @@ -377,6 +394,14 @@ typedef struct n2n_REGISTER_SUPER_ACK_payload { } n2n_REGISTER_SUPER_ACK_payload_t; +/* Linked with n2n_unregister_super in n2n_pc_t. */ +typedef struct n2n_UNREGISTER_SUPER +{ + n2n_auth_t auth; + n2n_mac_t srcMac; +} n2n_UNREGISTER_SUPER_t; + + typedef struct n2n_PEER_INFO { uint16_t aflags; n2n_mac_t srcMac; @@ -401,6 +426,7 @@ struct peer_info { n2n_desc_t dev_desc; n2n_sock_t sock; n2n_cookie_t last_cookie; + n2n_auth_t auth; int timeout; uint8_t purgeable; time_t last_seen; @@ -546,6 +572,7 @@ typedef struct n2n_edge_conf { int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */ int local_port; int mgmt_port; + n2n_auth_t auth; filter_rule_t *network_traffic_filter_rules; } n2n_edge_conf_t; @@ -660,6 +687,7 @@ typedef struct n2n_sn struct sn_community *communities; struct sn_community_regular_expression *rules; struct sn_community *federation; + n2n_auth_t auth; } n2n_sn_t; diff --git a/include/n2n_wire.h b/include/n2n_wire.h index 89cffd3..fb970ef 100644 --- a/include/n2n_wire.h +++ b/include/n2n_wire.h @@ -131,6 +131,17 @@ int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * pkt, size_t * rem, size_t * idx ); +int encode_UNREGISTER_SUPER(uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_UNREGISTER_SUPER_t *unreg); + +int decode_UNREGISTER_SUPER(n2n_UNREGISTER_SUPER_t *unreg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx); + int encode_REGISTER_ACK( uint8_t * base, size_t * idx, const n2n_common_t * common, @@ -154,6 +165,17 @@ int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg, size_t * rem, size_t * idx, uint8_t * tmpbuf); + +int encode_REGISTER_SUPER_NAK( uint8_t * base, + size_t * idx, + const n2n_common_t * cmn, + const n2n_REGISTER_SUPER_NAK_t * nak); + +int decode_REGISTER_SUPER_NAK( n2n_REGISTER_SUPER_NAK_t * nak, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); int fill_sockaddr( struct sockaddr * addr, size_t addrlen, diff --git a/src/edge_utils.c b/src/edge_utils.c index 88f7d76..6db5c4b 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -179,6 +179,7 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) { n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t)); int rc = -1, i = 0; struct peer_info *scan, *tmp; + size_t idx = 0; if((rc = edge_verify_conf(conf)) != 0) { traceEvent(TRACE_ERROR, "Invalid configuration"); @@ -259,6 +260,14 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) { // if called in-between, see "Supernode not responding" in update_supernode_reg(...) eee->udp_sock = -1; eee->udp_mgmt_sock = -1; + + eee->conf.auth.scheme = n2n_auth_simple_id; + + for (idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) + eee->conf.auth.token[idx] = n2n_rand() % 0xff; + + eee->conf.auth.toksize = sizeof(eee->conf.auth.token); + #ifndef SKIP_MULTICAST_PEERS_DISCOVERY eee->udp_multicast_sock = -1; #endif @@ -773,7 +782,7 @@ static void send_register_super(n2n_edge_t *eee) { 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); - reg.auth.scheme = 0; /* No auth yet */ + memcpy(&(reg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); idx = 0; encode_mac(reg.edgeMac, &idx, eee->device.mac_addr); @@ -793,10 +802,49 @@ static void send_register_super(n2n_edge_t *eee) { } +static void send_unregister_super(n2n_edge_t *eee){ + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_UNREGISTER_SUPER_t unreg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn)); + memset(&unreg, 0, sizeof(unreg)); + + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_unregister_super; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + memcpy(&(unreg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); + + idx = 0; + encode_mac(unreg.srcMac, &idx, eee->device.mac_addr); + + idx = 0; + encode_UNREGISTER_SUPER(pktbuf, &idx, &cmn, &unreg); + + traceEvent(TRACE_DEBUG, "send UNREGISTER_SUPER to %s", + 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, &(eee->curr_sn->sock)); + +} + + static int sort_supernodes(n2n_edge_t *eee, time_t now){ struct peer_info *scan, *tmp; if(eee->curr_sn != eee->conf.supernodes){ + send_unregister_super(eee); + eee->curr_sn = eee->conf.supernodes; memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t)); eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; @@ -1027,18 +1075,6 @@ void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) { /* ************************************** */ -/** NOT IMPLEMENTED - * - * This would send a DEREGISTER packet to a peer edge or supernode to indicate - * the edge is going away. - */ -static void send_deregister(n2n_edge_t * eee, - n2n_sock_t * remote_peer) { - /* Marshall and send message */ -} - -/* ************************************** */ - /** Return the IP address of the current supernode in the ring. */ static const char * supernode_ip(const n2n_edge_t * eee) { return (eee->curr_sn->ip_addr); @@ -1798,8 +1834,7 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) { n2n_sock_t sender; n2n_sock_t * orig_sender=NULL; time_t now=0; - uint64_t stamp = 0; - + uint64_t stamp = 0; size_t i; i = sizeof(sender_sock); @@ -2107,6 +2142,33 @@ void readFromIPSocket(n2n_edge_t * eee, int in_sock) { } break; } + case MSG_TYPE_REGISTER_SUPER_NAK: { + n2n_REGISTER_SUPER_NAK_t nak; + struct peer_info *peer, *scan; + + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK"); + + if((memcmp(&(nak.srcMac), &(eee->device.mac_addr), sizeof(n2n_mac_t))) == 0){ + traceEvent(TRACE_ERROR, "%s is already used. Stopping the program.", macaddr_str(mac_buf1, nak.srcMac)); + exit(1); + } else { + HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer); + if(peer != NULL){ + HASH_DEL(eee->known_peers, peer); + } + + HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan); + if(scan != NULL){ + HASH_DEL(eee->pending_peers, scan); + } + } + + break; + } case MSG_TYPE_PEER_INFO: { n2n_PEER_INFO_t pi; struct peer_info * scan; @@ -2314,7 +2376,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { WaitForSingleObject(tun_read_thread, INFINITE); #endif - send_deregister(eee, &(eee->supernode)); + send_unregister_super(eee); closesocket(eee->udp_sock); @@ -2325,6 +2387,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { /** Deinitialise the edge and deallocate any owned memory. */ void edge_term(n2n_edge_t * eee) { + if(eee->udp_sock >= 0) closesocket(eee->udp_sock); diff --git a/src/sn_utils.c b/src/sn_utils.c index ba9dbaa..28666a3 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -52,6 +52,7 @@ static int update_edge(n2n_sn_t *sss, const n2n_REGISTER_SUPER_t* reg, struct sn_community *comm, const n2n_sock_t *sender_sock, + int skip_add, time_t now); static int purge_expired_communities(n2n_sn_t *sss, @@ -258,6 +259,7 @@ int comm_init(struct sn_community *comm, char *cmn) { /** Initialise the supernode structure */ int sn_init(n2n_sn_t *sss) { int i; + size_t idx; #ifdef WIN32 initWin32(); @@ -295,6 +297,14 @@ int sn_init(n2n_sn_t *sss) { } n2n_srand (n2n_seed()); + + /* Random auth token */ + sss->auth.scheme = n2n_auth_simple_id; + + for (idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) + sss->auth.token[idx] = n2n_rand() % 0xff; + + sss->auth.toksize = sizeof(sss->auth.token); /* Random MAC address */ for(i=0; i<6; i++) { @@ -354,23 +364,35 @@ static uint16_t reg_lifetime(n2n_sn_t *sss) return 15; } +/** Compare two authentication tokens. It is called by update_edge + * and in UNREGISTER_SUPER handling to compare the stored auth token + * with the one received from the packet. + */ +static int auth_edge(const n2n_auth_t *auth1, const n2n_auth_t *auth2){ + /* 0 = success (tokens are equal). */ + return (memcmp(auth1, auth2, sizeof(n2n_auth_t))); +} + /** Update the edge table with the details of the edge which contacted the * supernode. */ static int update_edge(n2n_sn_t *sss, const n2n_REGISTER_SUPER_t* reg, struct sn_community *comm, const n2n_sock_t *sender_sock, + int skip_add, time_t now) { macstr_t mac_buf; n2n_sock_str_t sockbuf; struct peer_info *scan, *iter, *tmp; + int auth; + int ret; traceEvent(TRACE_DEBUG, "update_edge for %s [%s]", macaddr_str(mac_buf, reg->edgeMac), sock_to_cstr(sockbuf, sender_sock)); HASH_FIND_PEER(comm->edges, reg->edgeMac, scan); - + // if unknown, make sure it is also not known by IP address if (NULL == scan) { HASH_ITER(hh,comm->edges,iter,tmp) { @@ -383,42 +405,63 @@ static int update_edge(n2n_sn_t *sss, } } } - - if (NULL == scan) { - /* Not known */ - scan = (struct peer_info *) calloc(1, + if (NULL == scan) { + /* Not known */ + if(skip_add == SN_ADD){ + scan = (struct peer_info *) calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */ - memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); - scan->dev_addr.net_addr = reg->dev_addr.net_addr; - scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen; - memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); - memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); - scan->last_valid_time_stamp = initial_time_stamp(); + memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); + scan->dev_addr.net_addr = reg->dev_addr.net_addr; + scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen; + memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + memcpy(&(scan->auth), &(reg->auth), sizeof(n2n_auth_t)); + scan->last_valid_time_stamp = initial_time_stamp(); - HASH_ADD_PEER(comm->edges, scan); + HASH_ADD_PEER(comm->edges, scan); - traceEvent(TRACE_INFO, "update_edge created %s ==> %s", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); + traceEvent(TRACE_INFO, "update_edge created %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + } + + ret = update_edge_new_sn; } else { /* Known */ if (!sock_equal(sender_sock, &(scan->sock))) { - memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + if((auth = auth_edge(&(scan->auth), &(reg->auth))) == 0){ + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + + traceEvent(TRACE_INFO, "update_edge updated %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + ret = update_edge_sock_change; + } else { + traceEvent(TRACE_INFO, "authentication failed"); - traceEvent(TRACE_INFO, "update_edge updated %s ==> %s", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); + ret = update_edge_auth_fail; + } + } else { + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s", macaddr_str(mac_buf, reg->edgeMac), sock_to_cstr(sockbuf, sender_sock)); + + ret = update_edge_no_change; } } - - scan->last_seen = now; - return 0; + + if(scan != NULL){ + scan->last_seen = now; + } + + return ret; } @@ -602,7 +645,7 @@ static int re_register_and_purge_supernodes(n2n_sn_t *sss, struct sn_community * memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE); reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr); reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen)); - reg.auth.scheme = 0; /* No auth yet */ + memcpy(&(reg.auth), &(sss->auth), sizeof(n2n_auth_t)); idx = 0; encode_mac(reg.edgeMac, &idx, sss->mac_addr); @@ -812,7 +855,7 @@ static int process_udp(n2n_sn_t * sss, n2n_sock_str_t sockbuf; char buf[32]; struct sn_community *comm, *tmp; - uint64_t stamp; + uint64_t stamp; const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; /* 00:00:00:00:00:00 */ traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", @@ -1073,8 +1116,11 @@ static int process_udp(n2n_sn_t * sss, { n2n_REGISTER_SUPER_t reg; n2n_REGISTER_SUPER_ACK_t ack; + n2n_REGISTER_SUPER_NAK_t nak; n2n_common_t cmn2; uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; + uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + uint8_t *tmp_dst; uint8_t payload_buf[REG_SUPER_ACK_PAYLOAD_SPACE]; n2n_REGISTER_SUPER_ACK_payload_t *payload; size_t encx=0; @@ -1088,8 +1134,10 @@ static int process_udp(n2n_sn_t * sss, int num = 0; int skip_add; int skip; + int ret_value; memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); /* Edge/supernode requesting registration with us. */ sss->stats.last_reg_super=now; @@ -1118,7 +1166,7 @@ static int process_udp(n2n_sn_t * sss, if( (allowed_match != -1) && (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted) - && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) + && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) match = 1; break; } @@ -1175,11 +1223,6 @@ static int process_udp(n2n_sn_t * sss, ack.sock.port = ntohs(sender_sock->sin_port); memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - if((from_supernode == 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) { skip_add = SN_ADD; @@ -1191,7 +1234,7 @@ static int process_udp(n2n_sn_t * sss, /* Skip random numbers of supernodes before payload assembling, calculating an appropriate random_number. * That way, all supernodes have a chance to be propagated with REGISTER_SUPER_ACK. */ skip = HASH_COUNT(sss->federation->edges) - (int)(REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE / REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE); - skip = (skip < 0) ? 0 : n2n_rand_sqr(skip); + skip = (skip < 0) ? 0 : n2n_rand_sqr(skip); /* Assembling supernode list for REGISTER_SUPER_ACK payload */ payload = (n2n_REGISTER_SUPER_ACK_payload_t*)payload_buf; @@ -1220,46 +1263,132 @@ static int process_udp(n2n_sn_t * sss, sock_to_cstr(sockbuf, &(ack.sock))); if(memcmp(reg.edgeMac, &null_mac, N2N_MAC_SIZE) != 0) { - update_edge(sss, ®, comm, &(ack.sock), now); + if(cmn.flags & N2N_FLAGS_SOCKET){ + ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD_SKIP, now); + } else { + ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD, now); + } } - encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack, payload_buf); - - 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)); + if(ret_value == update_edge_auth_fail){ + cmn2.pc = n2n_register_super_nak; - sendto(sss->sock, ackbuf, encx, 0, - (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + memcpy(&(nak.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + memcpy(&(nak.srcMac), &(reg.edgeMac), sizeof(n2n_mac_t)); + + encode_REGISTER_SUPER_NAK(ackbuf, &encx, &cmn2, &nak); + + 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)); + + sendto(sss->sock, ackbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + + if(cmn.flags & N2N_FLAGS_SOCKET){ + sendto_sock(sss, ®.sock, ackbuf, encx); + } - traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", - macaddr_str(mac_buf, reg.edgeMac), - sock_to_cstr(sockbuf, &(ack.sock))); + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s", + macaddr_str(mac_buf, reg.edgeMac)); + } else { + if(!(cmn.flags & N2N_FLAGS_SOCKET)){ + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + cmn2.pc = n2n_register_super; + encode_REGISTER_SUPER(ackbuf, &encx, &cmn2, ®); + + 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)); + + try_broadcast(sss, NULL, &cmn, reg.edgeMac, from_supernode, ackbuf, encx); + + encx = 0; + cmn2.pc = n2n_register_super_ack; + + encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack, tmpbuf); + + 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)); + + sendto(sss->sock, ackbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", + 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; } break; + } + case MSG_TYPE_UNREGISTER_SUPER: { + n2n_UNREGISTER_SUPER_t unreg; + struct peer_info *peer; + int auth; + + + memset(&unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp UNREGISTER_SUPER with unknown community %s", cmn.community); + return -1; + } + + if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) { + traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking."); + return -1; } + + decode_UNREGISTER_SUPER(&unreg, &cmn, udp_buf, &rem, &idx); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, unreg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER due to time stamp error."); + return -1; + } + } + + traceEvent(TRACE_DEBUG, "Rx UNREGISTER_SUPER from %s", + macaddr_str(mac_buf, unreg.srcMac)); + + HASH_FIND_PEER(comm->edges, unreg.srcMac, peer); + if(peer != NULL){ + if((auth = auth_edge(&(peer->auth), &unreg.auth)) == 0){ + HASH_DEL(comm->edges, peer); + } + } + + break; + } case MSG_TYPE_REGISTER_SUPER_ACK: { - n2n_REGISTER_SUPER_ACK_t ack; - size_t encx=0; - struct sn_community *fed; + n2n_REGISTER_SUPER_ACK_t ack; + size_t encx=0; + struct sn_community *fed; struct peer_info *scan, *tmp; n2n_sock_str_t sockbuf1; n2n_sock_str_t sockbuf2; - macstr_t mac_buf1; + macstr_t mac_buf1; n2n_sock_t sender; n2n_sock_t *orig_sender; n2n_sock_t *tmp_sock; n2n_mac_t *tmp_mac; - int i; + int i; uint8_t dec_tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; - int skip_add; + int skip_add; n2n_REGISTER_SUPER_ACK_payload_t *payload; - + memset(&sender, 0, sizeof(n2n_sock_t)); sender.family = AF_INET; sender.port = ntohs(sender_sock->sin_port); @@ -1322,6 +1451,50 @@ static int process_udp(n2n_sn_t * sss, break; } + case MSG_TYPE_REGISTER_SUPER_NAK: { + n2n_REGISTER_SUPER_NAK_t nak; + size_t encx=0; + struct peer_info *peer; + n2n_sock_str_t sockbuf; + macstr_t mac_buf; + n2n_sock_t sender; + + 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); + + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp REGISTER_SUPER_NAK with unknown community %s", cmn.community); + return -1; + } + + decode_REGISTER_SUPER_NAK(&nak, &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, nak.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_NAK due to time stamp error."); + return -1; + } + } + } + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK from %s [%s]", + macaddr_str(mac_buf, nak.srcMac), + sock_to_cstr(sockbuf, &sender)); + + HASH_FIND_PEER(comm->edges, nak.srcMac, peer); + if(comm->is_federation == IS_NO_FEDERATION){ + if(peer != NULL){ + HASH_DEL(comm->edges, peer); + } + } + + break; + } case MSG_TYPE_QUERY_PEER: { n2n_QUERY_PEER_t query; uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; @@ -1329,10 +1502,10 @@ static int process_udp(n2n_sn_t * sss, n2n_common_t cmn2; n2n_PEER_INFO_t pi; 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; uint8_t *rec_buf; /* either udp_buf or encbuf */ if(!comm && sss->lock_communities) { diff --git a/src/wire.c b/src/wire.c index 5416ecd..5043322 100644 --- a/src/wire.c +++ b/src/wire.c @@ -324,11 +324,15 @@ int encode_REGISTER_SUPER(uint8_t *base, retval += encode_common(base, idx, common); retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); retval += encode_mac(base, idx, reg->edgeMac); + if (0 != reg->sock.family) { + retval += encode_sock(base, idx, &(reg->sock)); + } retval += encode_uint32(base, idx, reg->dev_addr.net_addr); retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); - retval += encode_uint16(base, idx, 0); /* NULL auth scheme */ - retval += encode_uint16(base, idx, 0); /* No auth data */ + retval += encode_uint16(base, idx, reg->auth.scheme); + retval += encode_uint16(base, idx, reg->auth.toksize); + retval += encode_buf(base, idx, reg->auth.token, reg->auth.toksize); return retval; } @@ -343,6 +347,9 @@ int decode_REGISTER_SUPER(n2n_REGISTER_SUPER_t *reg, memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t)); retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); retval += decode_mac(reg->edgeMac, base, rem, idx); + if (cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); @@ -353,6 +360,37 @@ int decode_REGISTER_SUPER(n2n_REGISTER_SUPER_t *reg, } +int encode_UNREGISTER_SUPER(uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_UNREGISTER_SUPER_t *unreg){ + int retval = 0; + retval += encode_common(base, idx, common); + retval += encode_uint16(base, idx, unreg->auth.scheme); + retval += encode_uint16(base, idx, unreg->auth.toksize); + retval += encode_buf(base, idx, unreg->auth.token, unreg->auth.toksize); + retval += encode_mac(base, idx, unreg->srcMac); + + return retval; +} + + +int decode_UNREGISTER_SUPER(n2n_UNREGISTER_SUPER_t *unreg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx){ + size_t retval = 0; + memset(unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); + retval += decode_uint16(&(unreg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(unreg->auth.toksize), base, rem, idx); + retval += decode_buf(unreg->auth.token, unreg->auth.toksize, base, rem, idx); + retval += decode_mac(unreg->srcMac, base, rem, idx); + + return retval; +} + + int encode_REGISTER_ACK(uint8_t *base, size_t *idx, const n2n_common_t *common, @@ -442,6 +480,33 @@ int decode_REGISTER_SUPER_ACK(n2n_REGISTER_SUPER_ACK_t *reg, } +int encode_REGISTER_SUPER_NAK(uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_SUPER_NAK_t *nak) { + int retval = 0; + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, nak->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, nak->srcMac); + + return retval; +} + + +int decode_REGISTER_SUPER_NAK(n2n_REGISTER_SUPER_NAK_t *nak, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + size_t retval = 0; + memset(nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + retval += decode_buf(nak->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(nak->srcMac, base, rem, idx); + + return retval; +} + + int fill_sockaddr( struct sockaddr * addr, size_t addrlen, const n2n_sock_t * sock )