summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-06-05 00:44:05 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-06-05 00:44:05 +0200
commit450bbeb8a00cc695cc2c62f48c821388d6191e00 (patch)
tree8341bee2e730850ab0c8e8fb37f5d7c2e083e4db
parentb6b6e059d7343165633eda7b3b4605220751d2dd (diff)
downloadfastd-450bbeb8a00cc695cc2c62f48c821388d6191e00.tar
fastd-450bbeb8a00cc695cc2c62f48c821388d6191e00.zip
Add support for receiving reordered packets
-rw-r--r--src/config.c3
-rw-r--r--src/fastd.h7
-rw-r--r--src/method_null.c2
-rw-r--r--src/method_xsalsa20_poly1305.c49
-rw-r--r--src/protocol_ec25519_fhmqvc.c6
5 files changed, 50 insertions, 17 deletions
diff --git a/src/config.c b/src/config.c
index f826c18..015ff8f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -60,6 +60,9 @@ static void default_config(fastd_config *conf) {
conf->peer_stale_time = 90;
conf->eth_addr_stale_time = 300;
+ conf->reorder_count = 32;
+ conf->reorder_time = 10;
+
conf->ifname = NULL;
memset(&conf->bind_addr_in, 0, sizeof(struct sockaddr_in));
diff --git a/src/fastd.h b/src/fastd.h
index abf8c07..8d7ce59 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -92,8 +92,8 @@ struct _fastd_method {
bool (*session_want_refresh)(fastd_context *ctx, fastd_method_session_state *session);
void (*session_free)(fastd_context *ctx, fastd_method_session_state *session);
- bool (*encrypt)(fastd_context *ctx, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in);
- bool (*decrypt)(fastd_context *ctx, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in);
+ bool (*encrypt)(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in);
+ bool (*decrypt)(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in);
};
union _fastd_peer_address {
@@ -133,6 +133,9 @@ struct _fastd_config {
unsigned peer_stale_time;
unsigned eth_addr_stale_time;
+ unsigned reorder_count;
+ unsigned reorder_time;
+
char *ifname;
struct sockaddr_in bind_addr_in;
diff --git a/src/method_null.c b/src/method_null.c
index fbdf1f5..e8b3fca 100644
--- a/src/method_null.c
+++ b/src/method_null.c
@@ -57,7 +57,7 @@ static bool method_session_want_refresh(fastd_context *ctx, fastd_method_session
static void method_session_free(fastd_context *ctx, fastd_method_session_state *session) {
}
-static bool method_passthrough(fastd_context *ctx, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
+static bool method_passthrough(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
*out = in;
return true;
}
diff --git a/src/method_xsalsa20_poly1305.c b/src/method_xsalsa20_poly1305.c
index 9331265..95fbfa2 100644
--- a/src/method_xsalsa20_poly1305.c
+++ b/src/method_xsalsa20_poly1305.c
@@ -39,6 +39,9 @@ struct _fastd_method_session_state {
uint8_t send_nonce[NONCEBYTES];
uint8_t receive_nonce[NONCEBYTES];
+
+ struct timespec receive_last;
+ uint64_t receive_reorder_seen;
};
@@ -55,19 +58,20 @@ static inline void increment_nonce(uint8_t nonce[NONCEBYTES]) {
}
}
-static inline bool is_nonce_valid(const uint8_t nonce[NONCEBYTES], const uint8_t old_nonce[NONCEBYTES]) {
+static inline bool is_nonce_valid(const uint8_t nonce[NONCEBYTES], const uint8_t old_nonce[NONCEBYTES], int64_t *age) {
if ((nonce[0] & 1) != (old_nonce[0] & 1))
return false;
int i;
+ *age = 0;
+
for (i = NONCEBYTES-1; i >= 0; i--) {
- if (nonce[i] > old_nonce[i])
- return true;
- if (nonce[i] < old_nonce[i])
- return false;
+ *age *= 256;
+ *age += old_nonce[i]-nonce[i];
}
- return false;
+ *age /= 2;
+ return true;
}
static size_t method_max_packet_size(fastd_context *ctx) {
@@ -128,7 +132,7 @@ static void method_session_free(fastd_context *ctx, fastd_method_session_state *
}
}
-static bool method_encrypt(fastd_context *ctx, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
+static bool method_encrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
fastd_buffer_pull_head(&in, crypto_secretbox_xsalsa20poly1305_ZEROBYTES);
memset(in.data, 0, crypto_secretbox_xsalsa20poly1305_ZEROBYTES);
@@ -150,7 +154,7 @@ static bool method_encrypt(fastd_context *ctx, fastd_method_session_state *sessi
return true;
}
-static bool method_decrypt(fastd_context *ctx, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
+static bool method_decrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
if (in.len < NONCEBYTES)
return false;
@@ -161,8 +165,17 @@ static bool method_decrypt(fastd_context *ctx, fastd_method_session_state *sessi
memcpy(nonce, in.data, NONCEBYTES);
memset(nonce+NONCEBYTES, 0, crypto_secretbox_xsalsa20poly1305_NONCEBYTES-NONCEBYTES);
- if (!is_nonce_valid(nonce, session->receive_nonce))
+ int64_t age;
+ if (!is_nonce_valid(nonce, session->receive_nonce, &age))
return false;
+
+ if (age >= 0) {
+ if (timespec_diff(&ctx->now, &session->receive_last) > ctx->conf->reorder_time*1000)
+ return false;
+
+ if (age > ctx->conf->reorder_count)
+ return false;
+ }
fastd_buffer_pull_head(&in, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES-NONCEBYTES);
memset(in.data, 0, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES);
@@ -180,9 +193,23 @@ static bool method_decrypt(fastd_context *ctx, fastd_method_session_state *sessi
fastd_buffer_free(in);
- fastd_buffer_push_head(out, crypto_secretbox_xsalsa20poly1305_ZEROBYTES);
+ if (age < 0) {
+ session->receive_reorder_seen >>= age;
+ session->receive_reorder_seen |= (1 >> (age+1));
+ memcpy(session->receive_nonce, nonce, NONCEBYTES);
+ session->receive_last = ctx->now;
+ }
+ else if (age == 0 || session->receive_reorder_seen & (1 << (age-1))) {
+ pr_debug(ctx, "dropping duplicate packet from %P (age %u)", peer, (unsigned)age);
+ fastd_buffer_free(*out);
+ *out = fastd_buffer_alloc(crypto_secretbox_xsalsa20poly1305_ZEROBYTES, 0, 0);
+ }
+ else {
+ pr_debug(ctx, "accepting reordered packet from %P (age %u)", peer, (unsigned)age);
+ session->receive_reorder_seen |= (1 << (age-1));
+ }
- memcpy(session->receive_nonce, nonce, NONCEBYTES);
+ fastd_buffer_push_head(out, crypto_secretbox_xsalsa20poly1305_ZEROBYTES);
return true;
}
diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c
index 31cf2b6..64d941c 100644
--- a/src/protocol_ec25519_fhmqvc.c
+++ b/src/protocol_ec25519_fhmqvc.c
@@ -637,12 +637,12 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf
bool ok = false;
if (is_session_valid(ctx, &peer->protocol_state->old_session)) {
- if (ctx->conf->method->decrypt(ctx, peer->protocol_state->old_session.method_state, &recv_buffer, buffer))
+ if (ctx->conf->method->decrypt(ctx, peer, peer->protocol_state->old_session.method_state, &recv_buffer, buffer))
ok = true;
}
if (!ok) {
- if (ctx->conf->method->decrypt(ctx, peer->protocol_state->session.method_state, &recv_buffer, buffer)) {
+ if (ctx->conf->method->decrypt(ctx, peer, peer->protocol_state->session.method_state, &recv_buffer, buffer)) {
ok = true;
if (peer->protocol_state->old_session.method_state) {
@@ -698,7 +698,7 @@ static void protocol_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf
}
fastd_buffer send_buffer;
- if (!ctx->conf->method->encrypt(ctx, session->method_state, &send_buffer, buffer))
+ if (!ctx->conf->method->encrypt(ctx, peer, session->method_state, &send_buffer, buffer))
goto fail;
fastd_send(ctx, &peer->address, send_buffer);