mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
added replay protection
This commit is contained in:
parent
b976379125
commit
0776e06912
|
@ -432,7 +432,8 @@ int sock_equal( const n2n_sock_t * a,
|
|||
|
||||
/* Header encryption */
|
||||
uint64_t time_stamp(void);
|
||||
int time_stamp_verify (uint64_t stamp, uint64_t * previous_stamp);
|
||||
uint64_t initial_time_stamp (void);
|
||||
int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp);
|
||||
|
||||
/* Operations on peer_info lists. */
|
||||
size_t purge_peer_list( struct peer_info ** peer_list,
|
||||
|
|
|
@ -193,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->pending_peers = NULL;
|
||||
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
||||
eee->sn_last_valid_time_stamp = initial_time_stamp ();
|
||||
|
||||
pearson_hash_init();
|
||||
|
||||
|
@ -380,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
|
||||
|
@ -431,6 +468,7 @@ static void register_with_new_peer(n2n_edge_t * eee,
|
|||
scan->sock = *peer;
|
||||
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_valid_time_stamp = initial_time_stamp ();
|
||||
|
||||
HASH_ADD_PEER(eee->pending_peers, scan);
|
||||
|
||||
|
@ -1245,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);
|
||||
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_valid_time_stamp = initial_time_stamp ();
|
||||
|
||||
HASH_ADD_PEER(eee->pending_peers, scan);
|
||||
}
|
||||
|
@ -1646,19 +1685,15 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
|
||||
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
if(is_valid_peer_sock(&pkt.sock))
|
||||
orig_sender = &(pkt.sock);
|
||||
|
||||
/* // sketch for time stamp verification -- to be implemented !!!
|
||||
|
||||
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
// find edge and its specific last time stamp or supernode's one !!!
|
||||
if ( !time_stamp_verify (stamp, &found_time_stamp !!!) ) {
|
||||
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to time stamp error.");
|
||||
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))
|
||||
orig_sender = &(pkt.sock);
|
||||
|
||||
if(!from_supernode) {
|
||||
/* This is a P2P packet from the peer. We purge a pending
|
||||
|
@ -1686,6 +1721,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
|
||||
decode_REGISTER(®, &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(®.sock))
|
||||
orig_sender = &(reg.sock);
|
||||
|
||||
|
@ -1730,6 +1772,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
|
||||
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))
|
||||
orig_sender = &(ra.sock);
|
||||
|
||||
|
@ -1750,6 +1799,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
{
|
||||
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))
|
||||
orig_sender = &(ra.sock);
|
||||
|
||||
|
@ -1793,6 +1849,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
struct peer_info * scan;
|
||||
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)) {
|
||||
traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]",
|
||||
sock_to_cstr(sockbuf1, &pi.sock),
|
||||
|
|
51
src/n2n.c
51
src/n2n.c
|
@ -26,7 +26,8 @@
|
|||
#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 */
|
||||
#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 multicast_addr[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */
|
||||
|
@ -383,7 +384,6 @@ int sock_equal(const n2n_sock_t * a,
|
|||
/* *********************************************** */
|
||||
|
||||
#if defined(WIN32) && !defined(__GNUC__)
|
||||
// REVISIT during the years 2035...2038
|
||||
int gettimeofday(struct timeval *tp, void *tzp) {
|
||||
time_t clock;
|
||||
struct tm tm;
|
||||
|
@ -405,7 +405,6 @@ int gettimeofday(struct timeval *tp, void *tzp) {
|
|||
|
||||
|
||||
// returns a time stamp for use with replay protection
|
||||
// REVISIT during the years 2035...2038
|
||||
uint64_t time_stamp (void) {
|
||||
|
||||
struct timeval tod;
|
||||
|
@ -426,36 +425,44 @@ uint64_t time_stamp (void) {
|
|||
}
|
||||
|
||||
|
||||
// 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, replaces the "last valid time stamp"
|
||||
// REVISIT during the years 2035...2038
|
||||
int time_stamp_verify (uint64_t stamp, uint64_t * previous_stamp) {
|
||||
// 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 higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)?
|
||||
diff = stamp - *previous_stamp + TIME_STAMP_JITTER;
|
||||
if(diff > 0) {
|
||||
|
||||
// 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(diff < TIME_STAMP_FRAME) {
|
||||
|
||||
// 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
|
||||
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "time_stamp_verify found a timestamp out of allowed frame.");
|
||||
return (0); // failure
|
||||
}
|
||||
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "time_stamp_verify found a timestamp too old / older than previous.");
|
||||
return (0); // failure
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ static int process_udp(n2n_sn_t *sss,
|
|||
size_t udp_size,
|
||||
time_t now);
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
static int try_forward(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
|
@ -255,6 +257,7 @@ static int update_edge(n2n_sn_t *sss,
|
|||
|
||||
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
|
||||
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
|
||||
scan->last_valid_time_stamp = initial_time_stamp ();
|
||||
|
||||
HASH_ADD_PEER(comm->edges, scan);
|
||||
|
||||
|
@ -285,6 +288,32 @@ static int update_edge(n2n_sn_t *sss,
|
|||
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 process_mgmt(n2n_sn_t *sss,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
const uint8_t *mgmt_buf,
|
||||
|
@ -512,6 +541,14 @@ static int process_udp(n2n_sn_t * sss,
|
|||
sss->stats.last_fwd=now;
|
||||
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));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
|
||||
|
@ -585,6 +622,14 @@ static int process_udp(n2n_sn_t * sss,
|
|||
sss->stats.last_fwd=now;
|
||||
decode_REGISTER(®, &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));
|
||||
|
||||
if(unicast) {
|
||||
|
@ -641,6 +686,15 @@ static int process_udp(n2n_sn_t * sss,
|
|||
++(sss->stats.reg_super);
|
||||
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)) {
|
||||
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
|
||||
community is allowed by the supernode. In case it is not we do
|
||||
|
@ -718,6 +772,14 @@ static int process_udp(n2n_sn_t * sss,
|
|||
|
||||
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",
|
||||
macaddr_str( mac_buf, query.srcMac ),
|
||||
macaddr_str( mac_buf2, query.targetMac ) );
|
||||
|
|
Loading…
Reference in New Issue
Block a user