summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/fastd.h5
-rw-r--r--src/method.h2
-rw-r--r--src/methods/cipher_test/cipher_test.c8
-rw-r--r--src/methods/common.c16
-rw-r--r--src/methods/common.h2
-rw-r--r--src/methods/composed_gmac/composed_gmac.c8
-rw-r--r--src/methods/composed_umac/composed_umac.c8
-rw-r--r--src/methods/generic_gmac/generic_gmac.c8
-rw-r--r--src/methods/generic_poly1305/generic_poly1305.c8
-rw-r--r--src/methods/generic_umac/generic_umac.c8
-rw-r--r--src/methods/null/null.c12
-rw-r--r--src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c8
-rw-r--r--src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c10
-rw-r--r--src/receive.c5
-rw-r--r--src/status.c2
15 files changed, 79 insertions, 31 deletions
diff --git a/src/fastd.h b/src/fastd.h
index a5737ba..5aff8e2 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -284,7 +284,8 @@ struct fastd_context {
fastd_socket_t *sock_default_v4; /**< Points to the socket that is used for new outgoing IPv4 connections */
fastd_socket_t *sock_default_v6; /**< Points to the socket that is used for new outgoing IPv6 connections */
- fastd_stats_t rx; /**< Reception statistics */
+ fastd_stats_t rx; /**< Reception statistics (total) */
+ fastd_stats_t rx_reordered; /**< Reception statistics (reordered packets) */
fastd_stats_t tx; /**< Transmission statistics (OK) */
fastd_stats_t tx_dropped; /**< Transmission statistics (dropped because of full queues) */
@@ -314,7 +315,7 @@ void fastd_send_handshake(const fastd_socket_t *sock, const fastd_peer_address_t
void fastd_send_data(fastd_buffer_t buffer, fastd_peer_t *source);
void fastd_receive(fastd_socket_t *sock);
-void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer);
+void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer, bool reordered);
void fastd_close_all_fds(void);
diff --git a/src/method.h b/src/method.h
index fec81f9..de1fb58 100644
--- a/src/method.h
+++ b/src/method.h
@@ -77,7 +77,7 @@ struct fastd_method_provider {
/** Encrypts a packet for a given session, adding method-specific headers */
bool (*encrypt)(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in);
/** Decrypts a packet for a given session, stripping method-specific headers */
- bool (*decrypt)(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in);
+ bool (*decrypt)(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered);
};
diff --git a/src/methods/cipher_test/cipher_test.c b/src/methods/cipher_test/cipher_test.c
index 056aaea..34f0f13 100644
--- a/src/methods/cipher_test/cipher_test.c
+++ b/src/methods/cipher_test/cipher_test.c
@@ -163,7 +163,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES)
return false;
@@ -197,7 +197,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
return false;
}
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/common.c b/src/methods/common.c
index 51cd6e8..f4f1f9c 100644
--- a/src/methods/common.c
+++ b/src/methods/common.c
@@ -75,8 +75,14 @@ bool fastd_method_is_nonce_valid(const fastd_method_common_t *session, const uin
return true;
}
-/** Checks if a possibly reordered packet should be accepted */
-bool fastd_method_reorder_check(fastd_peer_t *peer, fastd_method_common_t *session, const uint8_t nonce[COMMON_NONCEBYTES], int64_t age) {
+/**
+ Checks if a possibly reordered packet should be accepted
+
+ Returns a tristate: undef if it should not be accepted (duplicate or too old),
+ false if the packet is okay and not reordered and true
+ if it is reordered.
+*/
+fastd_tristate_t fastd_method_reorder_check(fastd_peer_t *peer, fastd_method_common_t *session, const uint8_t nonce[COMMON_NONCEBYTES], int64_t age) {
if (age < 0) {
size_t shift = age < (-64) ? 64 : ((size_t)-age);
@@ -90,15 +96,15 @@ bool fastd_method_reorder_check(fastd_peer_t *peer, fastd_method_common_t *sessi
memcpy(session->receive_nonce, nonce, COMMON_NONCEBYTES);
session->reorder_timeout = ctx.now + REORDER_TIME;
- return true;
+ return fastd_tristate_false;
}
else if (age == 0 || session->receive_reorder_seen & (1 << (age-1))) {
pr_debug("dropping duplicate packet from %P (age %u)", peer, (unsigned)age);
- return false;
+ return fastd_tristate_undef;
}
else {
pr_debug2("accepting reordered packet from %P (age %u)", peer, (unsigned)age);
session->receive_reorder_seen |= (1 << (age-1));
- return true;
+ return fastd_tristate_true;
}
}
diff --git a/src/methods/common.h b/src/methods/common.h
index d200931..3f6223f 100644
--- a/src/methods/common.h
+++ b/src/methods/common.h
@@ -59,7 +59,7 @@ typedef struct fastd_method_common {
void fastd_method_common_init(fastd_method_common_t *session, bool initiator);
bool fastd_method_is_nonce_valid(const fastd_method_common_t *session, const uint8_t nonce[COMMON_NONCEBYTES], int64_t *age);
-bool fastd_method_reorder_check(fastd_peer_t *peer, fastd_method_common_t *session, const uint8_t nonce[COMMON_NONCEBYTES], int64_t age);
+fastd_tristate_t fastd_method_reorder_check(fastd_peer_t *peer, fastd_method_common_t *session, const uint8_t nonce[COMMON_NONCEBYTES], int64_t age);
/**
diff --git a/src/methods/composed_gmac/composed_gmac.c b/src/methods/composed_gmac/composed_gmac.c
index cac24d6..b6506dd 100644
--- a/src/methods/composed_gmac/composed_gmac.c
+++ b/src/methods/composed_gmac/composed_gmac.c
@@ -256,7 +256,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Verifies and decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t))
return false;
@@ -308,7 +308,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_push_head(out, sizeof(fastd_block128_t));
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/composed_umac/composed_umac.c b/src/methods/composed_umac/composed_umac.c
index ed8225f..bca52fb 100644
--- a/src/methods/composed_umac/composed_umac.c
+++ b/src/methods/composed_umac/composed_umac.c
@@ -221,7 +221,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Verifies and decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t))
return false;
@@ -272,7 +272,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_push_head(out, sizeof(fastd_block128_t));
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/generic_gmac/generic_gmac.c b/src/methods/generic_gmac/generic_gmac.c
index 0e68f7e..c780e94 100644
--- a/src/methods/generic_gmac/generic_gmac.c
+++ b/src/methods/generic_gmac/generic_gmac.c
@@ -222,7 +222,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Verifies and decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t))
return false;
@@ -270,7 +270,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_push_head(out, sizeof(fastd_block128_t));
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/generic_poly1305/generic_poly1305.c b/src/methods/generic_poly1305/generic_poly1305.c
index 881ec7f..a12881b 100644
--- a/src/methods/generic_poly1305/generic_poly1305.c
+++ b/src/methods/generic_poly1305/generic_poly1305.c
@@ -181,7 +181,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Verifies and decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES+TAGBYTES)
return false;
@@ -235,7 +235,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_push_head(out, KEYBYTES);
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/generic_umac/generic_umac.c b/src/methods/generic_umac/generic_umac.c
index 3355fdb..fe7aade 100644
--- a/src/methods/generic_umac/generic_umac.c
+++ b/src/methods/generic_umac/generic_umac.c
@@ -187,7 +187,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Verifies and decrypts a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t))
return false;
@@ -233,7 +233,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_push_head(out, sizeof(fastd_block128_t));
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(0, 0, 0);
}
diff --git a/src/methods/null/null.c b/src/methods/null/null.c
index f84cf6c..4897ec2 100644
--- a/src/methods/null/null.c
+++ b/src/methods/null/null.c
@@ -99,7 +99,13 @@ static void method_session_free(fastd_method_session_state_t *session) {
}
/** Just returns the input buffer as the output */
-static bool method_passthrough(UNUSED fastd_peer_t *peer, UNUSED fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_encrypt(UNUSED fastd_peer_t *peer, UNUSED fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+ *out = in;
+ return true;
+}
+
+/** Just returns the input buffer as the output */
+static bool method_decrypt(UNUSED fastd_peer_t *peer, UNUSED fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, UNUSED bool *reordered) {
*out = in;
return true;
}
@@ -126,6 +132,6 @@ const fastd_method_provider_t fastd_method_null = {
.session_superseded = method_session_superseded,
.session_free = method_session_free,
- .encrypt = method_passthrough,
- .decrypt = method_passthrough,
+ .encrypt = method_encrypt,
+ .decrypt = method_decrypt,
};
diff --git a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c
index ee44200..670d09f 100644
--- a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c
+++ b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c
@@ -167,7 +167,7 @@ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state
}
/** Performs validation and decryption of a packet */
-static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) {
+static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) {
if (in.len < COMMON_HEADBYTES)
return false;
@@ -201,7 +201,11 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses
fastd_buffer_free(in);
- if (!fastd_method_reorder_check(peer, &session->common, in_nonce, age)) {
+ fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age);
+ if (reorder_check.set) {
+ *reordered = reorder_check.state;
+ }
+ else {
fastd_buffer_free(*out);
*out = fastd_buffer_alloc(crypto_secretbox_xsalsa20poly1305_ZEROBYTES, 0, 0);
}
diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
index 6920b5e..8533c2b 100644
--- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
+++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
@@ -112,15 +112,17 @@ static void protocol_handle_recv(fastd_peer_t *peer, fastd_buffer_t buffer) {
goto fail;
fastd_buffer_t recv_buffer;
- bool ok = false;
+ bool ok = false, reordered;
if (is_session_valid(&peer->protocol_state->old_session)) {
- if (peer->protocol_state->old_session.method->provider->decrypt(peer, peer->protocol_state->old_session.method_state, &recv_buffer, buffer))
+ reordered = false;
+ if (peer->protocol_state->old_session.method->provider->decrypt(peer, peer->protocol_state->old_session.method_state, &recv_buffer, buffer, &reordered))
ok = true;
}
if (!ok) {
- if (peer->protocol_state->session.method->provider->decrypt(peer, peer->protocol_state->session.method_state, &recv_buffer, buffer)) {
+ reordered = false;
+ if (peer->protocol_state->session.method->provider->decrypt(peer, peer->protocol_state->session.method_state, &recv_buffer, buffer, &reordered)) {
ok = true;
if (peer->protocol_state->old_session.method) {
@@ -150,7 +152,7 @@ static void protocol_handle_recv(fastd_peer_t *peer, fastd_buffer_t buffer) {
fastd_peer_seen(peer);
if (recv_buffer.len)
- fastd_handle_receive(peer, recv_buffer);
+ fastd_handle_receive(peer, recv_buffer, reordered);
else
fastd_buffer_free(recv_buffer);
diff --git a/src/receive.c b/src/receive.c
index 134564c..451e39d 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -253,7 +253,7 @@ static inline fastd_eth_addr_t get_source_address(const fastd_buffer_t buffer) {
}
/** Handles a received and decrypted payload packet */
-void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer) {
+void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer, bool reordered) {
if (conf.mode == MODE_TAP) {
if (buffer.len < ETH_HLEN) {
pr_debug("received truncated packet");
@@ -269,6 +269,9 @@ void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer) {
fastd_stats_add(&ctx.rx, buffer.len);
+ if (reordered)
+ fastd_stats_add(&ctx.rx_reordered, buffer.len);
+
fastd_tuntap_write(buffer);
if (conf.mode == MODE_TAP && conf.forward) {
diff --git a/src/status.c b/src/status.c
index a7f8441..4b4131d 100644
--- a/src/status.c
+++ b/src/status.c
@@ -134,6 +134,8 @@ static void dump_status(int fd) {
json_object_object_add(json, "statistics", statistics);
json_object_object_add(statistics, "rx", dump_stats(&ctx.rx));
+ json_object_object_add(statistics, "rx_reordered", dump_stats(&ctx.rx_reordered));
+
json_object_object_add(statistics, "tx", dump_stats(&ctx.tx));
json_object_object_add(statistics, "tx_dropped", dump_stats(&ctx.tx_dropped));
json_object_object_add(statistics, "tx_error", dump_stats(&ctx.tx_error));