diff options
-rw-r--r-- | src/fastd.h | 5 | ||||
-rw-r--r-- | src/method.h | 2 | ||||
-rw-r--r-- | src/methods/cipher_test/cipher_test.c | 8 | ||||
-rw-r--r-- | src/methods/common.c | 16 | ||||
-rw-r--r-- | src/methods/common.h | 2 | ||||
-rw-r--r-- | src/methods/composed_gmac/composed_gmac.c | 8 | ||||
-rw-r--r-- | src/methods/composed_umac/composed_umac.c | 8 | ||||
-rw-r--r-- | src/methods/generic_gmac/generic_gmac.c | 8 | ||||
-rw-r--r-- | src/methods/generic_poly1305/generic_poly1305.c | 8 | ||||
-rw-r--r-- | src/methods/generic_umac/generic_umac.c | 8 | ||||
-rw-r--r-- | src/methods/null/null.c | 12 | ||||
-rw-r--r-- | src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c | 8 | ||||
-rw-r--r-- | src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c | 10 | ||||
-rw-r--r-- | src/receive.c | 5 | ||||
-rw-r--r-- | src/status.c | 2 |
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)); |