Merge pull request #327 from Logan007/rp

added replay protection
This commit is contained in:
Luca Deri 2020-07-27 06:57:45 +02:00 committed by GitHub
commit 8542ba0db6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 345 additions and 107 deletions

View File

@ -19,10 +19,12 @@
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
char * community_name, he_context_t * ctx, char * community_name, he_context_t * ctx,
he_context_t * ctx_iv, uint16_t * checksum); he_context_t * ctx_iv,
uint64_t * stamp, uint16_t * checksum);
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx, int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx,
he_context_t * ctx_iv, uint16_t checksum); he_context_t * ctx_iv,
uint64_t stamp, uint16_t checksum);
void packet_header_setup_key (const char * community_name, he_context_t ** ctx, void packet_header_setup_key (const char * community_name, he_context_t ** ctx,

View File

@ -193,6 +193,7 @@ struct peer_info {
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;
uint64_t last_valid_time_stamp;
UT_hash_handle hh; /* makes this structure hashable */ UT_hash_handle hh; /* makes this structure hashable */
}; };
@ -305,6 +306,7 @@ struct n2n_edge {
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 */
uint64_t sn_last_valid_time_stamp;/*< last valid time stamp from supernode */
/* Sockets */ /* Sockets */
n2n_sock_t supernode; n2n_sock_t supernode;
@ -428,6 +430,11 @@ SOCKET open_socket(int local_port, int bind_any);
int sock_equal( const n2n_sock_t * a, int sock_equal( const n2n_sock_t * a,
const n2n_sock_t * b ); const n2n_sock_t * b );
/* Header encryption */
uint64_t time_stamp(void);
uint64_t initial_time_stamp (void);
int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp);
/* Operations on peer_info lists. */ /* Operations on peer_info lists. */
size_t purge_peer_list( struct peer_info ** peer_list, size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before ); time_t purge_before );

View File

@ -17,7 +17,6 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "header_encryption.h"
#include "edge_utils_win32.h" #include "edge_utils_win32.h"
/* heap allocation for compression as per lzo example doc */ /* heap allocation for compression as per lzo example doc */
@ -194,6 +193,7 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
eee->known_peers = NULL; eee->known_peers = NULL;
eee->pending_peers = NULL; eee->pending_peers = NULL;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
eee->sn_last_valid_time_stamp = initial_time_stamp ();
pearson_hash_init(); pearson_hash_init();
@ -381,6 +381,42 @@ static int supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
/* ************************************** */ /* ************************************** */
static const int definitely_from_supernode = 1;
/***
*
* For a given packet, find the apporopriate internal last valid time stamp for lookup
* and verify it (and also update, if applicable).
*/
static int find_peer_time_stamp_and_verify (n2n_edge_t * eee,
int from_supernode, n2n_mac_t mac,
uint64_t stamp) {
uint64_t * previous_stamp = NULL;
if(from_supernode) {
// from supernode
previous_stamp = &(eee->sn_last_valid_time_stamp);
} else {
// from (peer) edge
struct peer_info *peer;
HASH_FIND_PEER(eee->pending_peers, mac, peer);
if(!peer) {
HASH_FIND_PEER(eee->known_peers, mac, peer);
}
if(peer) {
// time_stamp_verify_and_update allows the pointer a previous stamp to be NULL
// if it is a (so far) unknown peer
previous_stamp = &(peer->last_valid_time_stamp);
}
}
// failure --> 0; success --> 1
return ( time_stamp_verify_and_update (stamp, previous_stamp) );
}
/* ************************************** */
/*** /***
* *
* Register over multicast in case there is a peer on the same network listening * Register over multicast in case there is a peer on the same network listening
@ -432,6 +468,7 @@ static void register_with_new_peer(n2n_edge_t * eee,
scan->sock = *peer; scan->sock = *peer;
scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */ scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */
scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */ scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */
scan->last_valid_time_stamp = initial_time_stamp ();
HASH_ADD_PEER(eee->pending_peers, scan); HASH_ADD_PEER(eee->pending_peers, scan);
@ -731,7 +768,8 @@ static void send_register_super(n2n_edge_t * eee,
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, pearson_hash_16 (pktbuf, idx)); 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, supernode);
} }
@ -763,7 +801,8 @@ static void send_query_peer( n2n_edge_t * eee,
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, pearson_hash_16 (pktbuf, idx)); eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
} }
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
} }
@ -810,7 +849,8 @@ static void send_register(n2n_edge_t * eee,
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, pearson_hash_16 (pktbuf, idx)); eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
} }
@ -853,7 +893,8 @@ static void send_register_ack(n2n_edge_t * eee,
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, pearson_hash_16 (pktbuf, idx)); eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
} }
@ -1242,6 +1283,7 @@ static int check_query_peer_info(n2n_edge_t *eee, time_t now, n2n_mac_t mac) {
memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */ scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */
scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */ scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */
scan->last_valid_time_stamp = initial_time_stamp ();
HASH_ADD_PEER(eee->pending_peers, scan); HASH_ADD_PEER(eee->pending_peers, scan);
} }
@ -1471,7 +1513,8 @@ void edge_send_packet2net(n2n_edge_t * eee,
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, headerIdx, eee->conf.header_encryption_ctx, packet_header_encrypt (pktbuf, headerIdx, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
#ifdef MTU_ASSERT_VALUE #ifdef MTU_ASSERT_VALUE
{ {
@ -1564,6 +1607,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
n2n_sock_t sender; n2n_sock_t sender;
n2n_sock_t * orig_sender=NULL; n2n_sock_t * orig_sender=NULL;
time_t now=0; time_t now=0;
uint64_t stamp = 0;
size_t i; size_t i;
@ -1601,10 +1645,16 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
uint16_t checksum = 0; uint16_t checksum = 0;
if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx, if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx, &checksum) == 0) { eee->conf.header_iv_ctx,
&stamp, &checksum) == 0) {
traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header."); traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header.");
return; return;
} }
// time stamp verification follows in the packet specific section as it requires to determine the
// sender from the hash list by its MAC, or the packet might be from the supernode, this all depends
// on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place)
if (checksum != pearson_hash_16 (udp_buf, recvlen)) { if (checksum != pearson_hash_16 (udp_buf, recvlen)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error."); traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error.");
return; return;
@ -1635,6 +1685,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_peer_time_stamp_and_verify (eee, from_supernode, pkt.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET due to time stamp error.");
return;
}
}
if(is_valid_peer_sock(&pkt.sock)) if(is_valid_peer_sock(&pkt.sock))
orig_sender = &(pkt.sock); orig_sender = &(pkt.sock);
@ -1664,6 +1721,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_peer_time_stamp_and_verify (eee, from_supernode, reg.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER due to time stamp error.");
return;
}
}
if(is_valid_peer_sock(&reg.sock)) if(is_valid_peer_sock(&reg.sock))
orig_sender = &(reg.sock); orig_sender = &(reg.sock);
@ -1708,6 +1772,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_peer_time_stamp_and_verify (eee, !definitely_from_supernode, ra.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_ACK due to time stamp error.");
return;
}
}
if(is_valid_peer_sock(&ra.sock)) if(is_valid_peer_sock(&ra.sock))
orig_sender = &(ra.sock); orig_sender = &(ra.sock);
@ -1728,6 +1799,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
{ {
decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx); decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_SUPER_ACK due to time stamp error.");
return;
}
}
if(is_valid_peer_sock(&ra.sock)) if(is_valid_peer_sock(&ra.sock))
orig_sender = &(ra.sock); orig_sender = &(ra.sock);
@ -1771,6 +1849,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
struct peer_info * scan; struct peer_info * scan;
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(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp)) {
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PEER_INFO due to time stamp error.");
return;
}
}
if(!is_valid_peer_sock(&pi.sock)) { if(!is_valid_peer_sock(&pi.sock)) {
traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]", traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]",
sock_to_cstr(sockbuf1, &pi.sock), sock_to_cstr(sockbuf1, &pi.sock),

View File

@ -25,7 +25,7 @@
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
char * community_name, he_context_t * ctx, char * community_name, he_context_t * ctx,
he_context_t * ctx_iv, uint16_t * checksum) { he_context_t * ctx_iv, uint64_t * stamp, uint16_t * checksum) {
// assemble IV // assemble IV
// the last four are ASCII "n2n!" and do not get overwritten // the last four are ASCII "n2n!" and do not get overwritten
@ -35,9 +35,10 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
// to full 128 bit IV // to full 128 bit IV
memcpy (iv, packet, 12); memcpy (iv, packet, 12);
// extract checksum (last 16 bit) blended in IV // extract time stamp (first 64 bit) and checksum (last 16 bit) blended in IV
speck_he_iv_decrypt (iv, (speck_context_t*)ctx_iv); speck_he_iv_decrypt (iv, (speck_context_t*)ctx_iv);
*checksum = be16toh (((uint16_t*)iv)[5]); *checksum = be16toh (((uint16_t*)iv)[5]);
*stamp = be64toh (((uint64_t*)iv)[0]);
memcpy (iv, packet, 12); memcpy (iv, packet, 12);
@ -64,7 +65,7 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
/* ********************************************************************** */ /* ********************************************************************** */
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx, int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx,
he_context_t * ctx_iv, uint16_t checksum) { he_context_t * ctx_iv, uint64_t stamp, uint16_t checksum) {
uint8_t iv[16]; uint8_t iv[16];
uint16_t *iv16 = (uint16_t*)&iv; uint16_t *iv16 = (uint16_t*)&iv;
@ -79,7 +80,7 @@ int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_
memcpy (&packet[16], &packet[00], 4); memcpy (&packet[16], &packet[00], 4);
iv64[0] = n2n_rand (); iv64[0] = htobe64 (stamp);
iv16[4] = n2n_rand (); iv16[4] = n2n_rand ();
iv16[5] = htobe16 (checksum); iv16[5] = htobe16 (checksum);
iv32[3] = htobe32 (magic); iv32[3] = htobe32 (magic);

View File

@ -22,6 +22,13 @@
#include <assert.h> #include <assert.h>
#define PURGE_REGISTRATION_FREQUENCY 30
#define REGISTRATION_TIMEOUT 60
#define TIME_STAMP_FRAME 0x0000001000000000LL /* clocks of different computers are allowed +/- 16 seconds to be off */
#define TIME_STAMP_JITTER 0x0000000027100000LL /* we allow a packet to arrive 160 ms (== 0x27100 us) before another
* set to 0x0000000000000000LL if increasing (or equal) time stamps allowed only */
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 */
@ -380,3 +387,88 @@ int sock_equal(const n2n_sock_t * a,
return(1); return(1);
} }
/* *********************************************** */
#if defined(WIN32) && !defined(__GNUC__)
int gettimeofday(struct timeval *tp, void *tzp) {
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1;
clock = mktime(&tm);
tp->tv_sec = clock;
tp->tv_usec = wtm.wMilliseconds * 1000;
return (0);
}
#endif
// returns a time stamp for use with replay protection
uint64_t time_stamp (void) {
struct timeval tod;
uint64_t micro_seconds;
gettimeofday (&tod, NULL);
/* We will (roughly) calculate the microseconds since 1970 leftbound into the return value.
The leading 32 bits are used for tv_sec. The following 20 bits (sufficent as microseconds
fraction never exceeds 1,000,000,) encode the value tv_usec. The remaining lowest 12 bits
are kept random for use in IV */
micro_seconds = n2n_rand();
micro_seconds = ( (((uint64_t)(tod.tv_sec) << 32) + (tod.tv_usec << 12))
| (micro_seconds >> 52) );
// more exact but more costly due to the multiplication:
// micro_seconds = (tod.tv_sec * 1000000 + tod.tv_usec) << 12) | ...
return (micro_seconds);
}
// returns an initial time stamp for use with replay protection
uint64_t initial_time_stamp (void) {
return ( time_stamp() - TIME_STAMP_FRAME );
}
// checks if a provided time stamp is consistent with current time and previously valid time stamps
// and, in case of validity, updates the "last valid time stamp"
int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp) {
int64_t diff; // do not change to unsigned
// is it around current time (+/- allowed deviation TIME_STAMP_FRAME)?
diff = stamp - time_stamp();
// abs()
diff = (diff < 0 ? -diff : diff);
if(diff >= TIME_STAMP_FRAME) {
traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp out of allowed frame.");
return (0); // failure
}
// if applicable: is it higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)?
if(NULL != previous_stamp) {
// if no jitter allowed, reset lowest three (random) nybbles; the codnition shoudl already be evaluated by the compiler
if(TIME_STAMP_JITTER == 0) {
stamp = (stamp >> 12) << 12;
*previous_stamp = (*previous_stamp >> 12) << 12;
}
diff = stamp - *previous_stamp + TIME_STAMP_JITTER;
if(diff <= 0) {
traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp too old compared to previous.");
return (0); // failure
}
// for not allowing to exploit the allowed TIME_STAMP_JITTER to "turn the clock backwards",
// set the higher of the values
*previous_stamp = (stamp > *previous_stamp ? stamp : *previous_stamp);
}
return (1); // success
}

View File

@ -1,5 +1,4 @@
#include "n2n.h" #include "n2n.h"
#include "header_encryption.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) #define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
@ -51,6 +50,8 @@ static int process_udp(n2n_sn_t *sss,
size_t udp_size, size_t udp_size,
time_t now); time_t now);
/* ************************************** */
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm, const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
@ -266,6 +267,7 @@ static int update_edge(n2n_sn_t *sss,
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t)); memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
scan->last_valid_time_stamp = initial_time_stamp ();
HASH_ADD_PEER(comm->edges, scan); HASH_ADD_PEER(comm->edges, scan);
@ -296,6 +298,31 @@ static int update_edge(n2n_sn_t *sss,
return 0; return 0;
} }
/***
*
* For a given packet, find the apporopriate internal last valid time stamp for lookup
* and verify it (and also update, if applicable).
*/
static int find_edge_time_stamp_and_verify (struct peer_info * edges,
int from_supernode, n2n_mac_t mac,
uint64_t stamp) {
uint64_t * previous_stamp = NULL;
if(!from_supernode) {
struct peer_info *edge;
HASH_FIND_PEER(edges, mac, edge);
if(edge) {
// time_stamp_verify_and_update allows the pointer a previous stamp to be NULL
// if it is a (so far) unknown edge
previous_stamp = &(edge->last_valid_time_stamp);
}
}
// failure --> 0; success --> 1
return ( time_stamp_verify_and_update (stamp, previous_stamp) );
}
static int purge_expired_communities(n2n_sn_t *sss, static int purge_expired_communities(n2n_sn_t *sss,
time_t* p_last_purge, time_t* p_last_purge,
time_t now) time_t now)
@ -325,6 +352,7 @@ static int purge_expired_communities(n2n_sn_t *sss,
return 0; return 0;
} }
static int process_mgmt(n2n_sn_t *sss, static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock, const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf, const uint8_t *mgmt_buf,
@ -447,6 +475,7 @@ static int process_udp(n2n_sn_t * sss,
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
char buf[32]; char buf[32];
struct sn_community *comm, *tmp; struct sn_community *comm, *tmp;
uint64_t stamp;
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]",
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
@ -493,7 +522,11 @@ static int process_udp(n2n_sn_t * sss,
continue; continue;
uint16_t checksum = 0; uint16_t checksum = 0;
if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx, if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx,
comm->header_iv_ctx, &checksum)) ) { comm->header_iv_ctx,
&stamp, &checksum)) ) {
// time stamp verification follows in the packet specific section as it requires to determine the
// sender from the hash list by its MAC, this all depends on packet type and packet structure
// (MAC is not always in the same place)
if (checksum != pearson_hash_16 (udp_buf, udp_size)) { if (checksum != pearson_hash_16 (udp_buf, udp_size)) {
traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error.");
return -1; return -1;
@ -564,6 +597,14 @@ static int process_udp(n2n_sn_t * sss,
sss->stats.last_fwd=now; sss->stats.last_fwd=now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
// already checked for valid comm
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, pkt.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "process_udp dropped PACKET due to time stamp error.");
return -1;
}
}
unicast = (0 == is_multi_broadcast(pkt.dstMac)); unicast = (0 == is_multi_broadcast(pkt.dstMac));
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s", traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
@ -593,7 +634,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, oldEncx, comm->header_encryption_ctx, packet_header_encrypt (rec_buf, oldEncx, comm->header_encryption_ctx,
comm->header_iv_ctx, pearson_hash_16 (rec_buf, encx)); comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (rec_buf, encx));
} else { } else {
/* Already from a supernode. Nothing to modify, just pass to /* Already from a supernode. Nothing to modify, just pass to
@ -606,7 +648,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx, packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx,
comm->header_iv_ctx, pearson_hash_16 (rec_buf, udp_size)); comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (rec_buf, udp_size));
} }
/* Common section to forward the final product. */ /* Common section to forward the final product. */
@ -635,6 +678,14 @@ static int process_udp(n2n_sn_t * sss,
sss->stats.last_fwd=now; sss->stats.last_fwd=now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
// already checked for valid comm
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, reg.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER due to time stamp error.");
return -1;
}
}
unicast = (0 == is_multi_broadcast(reg.dstMac)); unicast = (0 == is_multi_broadcast(reg.dstMac));
if(unicast) { if(unicast) {
@ -667,7 +718,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx, packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx, pearson_hash_16 (rec_buf, encx)); comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (rec_buf, encx));
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */ try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
} else } else
@ -690,6 +742,15 @@ static int process_udp(n2n_sn_t * sss,
++(sss->stats.reg_super); ++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx);
if (comm) {
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, reg.edgeMac, stamp)) {
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 Before we move any further, we need to check if the requested
community is allowed by the supernode. In case it is not we do community is allowed by the supernode. In case it is not we do
@ -739,7 +800,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx, packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx, pearson_hash_16 (ackbuf, encx)); comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (ackbuf, encx));
sendto(sss->sock, ackbuf, encx, 0, sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
@ -766,6 +828,14 @@ static int process_udp(n2n_sn_t * sss,
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
// already checked for valid comm
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, query.srcMac, stamp)) {
traceEvent(TRACE_DEBUG, "process_udp dropped QUERY_PEER due to time stamp error.");
return -1;
}
}
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 ) );
@ -787,7 +857,8 @@ static int process_udp(n2n_sn_t * sss,
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx, packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx,
comm->header_iv_ctx, pearson_hash_16 (encbuf, encx)); comm->header_iv_ctx,
time_stamp (), pearson_hash_16 (encbuf, encx));
sendto( sss->sock, encbuf, encx, 0, sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );

View File

@ -18,26 +18,6 @@
#include "n2n.h" #include "n2n.h"
#if defined(WIN32) && !defined(__GNUC__)
static int gettimeofday(struct timeval *tp, void *tzp)
{
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1;
clock = mktime(&tm);
tp->tv_sec = clock;
tp->tv_usec = wtm.wMilliseconds * 1000;
return (0);
}
#endif
uint8_t PKT_CONTENT[]={ uint8_t PKT_CONTENT[]={
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,