diff options
50 files changed, 931 insertions, 114 deletions
diff --git a/Doxyfile.in b/Doxyfile.in index 7b9f2ba..8acbb52 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -805,8 +805,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = "*/.*" \ - "*/.*/*" +EXCLUDE_PATTERNS = "*/.*" "*/.*/*" # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -1943,7 +1942,17 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = __attribute__(x)= VECTOR(x):=VECTOR<x> WITH_CAPABILITIES WITH_VERIFY USE_FREEBIND __linux__ +PREDEFINED = __attribute__(x)= \ + VECTOR(x):=VECTOR<x> \ + WITH_CAPABILITIES \ + WITH_VERIFY \ + WITH_CMDLINE_USER \ + WITH_CMDLINE_LOGGING \ + WITH_CMDLINE_OPERATION \ + WITH_CMDLINE_COMMANDS \ + ENABLE_SYSTEMD \ + USE_FREEBIND \ + __linux__ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/src/async.c b/src/async.c index fa93cd0..a443cfe 100644 --- a/src/async.c +++ b/src/async.c @@ -36,8 +36,8 @@ /** The packet header used on the async notification sockets */ typedef struct fastd_async_hdr { - fastd_async_type_t type; - size_t len; + fastd_async_type_t type; /**< The type of the notification */ + size_t len; /**< The length of the notification payload */ } fastd_async_hdr_t; diff --git a/src/config.c b/src/config.c index 8be44bb..6119669 100644 --- a/src/config.c +++ b/src/config.c @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Configuration management +*/ + #include "fastd.h" #include "config.h" @@ -43,12 +49,14 @@ #include <sys/types.h> +/** The global configuration */ fastd_config_t conf = {}; extern const fastd_protocol_t fastd_protocol_ec25519_fhmqvc; +/** Initializes the global configuration with default values */ static void default_config(void) { memset(&conf, 0, sizeof(fastd_config_t)); @@ -67,6 +75,7 @@ static void default_config(void) { conf.peer_group->max_connections = -1; } +/** Handles the configuration of a handshake protocol */ void fastd_config_protocol(const char *name) { if (!strcmp(name, "ec25519-fhmqvc")) conf.protocol = &fastd_protocol_ec25519_fhmqvc; @@ -74,6 +83,7 @@ void fastd_config_protocol(const char *name) { exit_error("config error: protocol `%s' not supported", name); } +/** Handles the configuration of a crypto method */ void fastd_config_method(const char *name) { fastd_string_stack_t **method; @@ -87,16 +97,19 @@ void fastd_config_method(const char *name) { *method = fastd_string_stack_dup(name); } +/** Handles the configuration of a cipher implementation */ void fastd_config_cipher(const char *name, const char *impl) { if (!fastd_cipher_config(name, impl)) exit_error("config error: implementation `%s' is not supported for cipher `%s' (or cipher `%s' is not supported)", impl, name, name); } +/** Handles the configuration of a MAC implementation */ void fastd_config_mac(const char *name, const char *impl) { if (!fastd_mac_config(name, impl)) exit_error("config error: implementation `%s' is not supported for MAC `%s' (or MAC `%s' is not supported)", impl, name, name); } +/** Handles the configuration of a bind address */ void fastd_config_bind_address(const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6) { #ifndef USE_BINDTODEVICE if (bindtodev && !fastd_peer_address_is_v6_ll(address)) @@ -131,6 +144,7 @@ void fastd_config_bind_address(const fastd_peer_address_t *address, const char * conf.bind_addr_default_v6 = addr; } +/** Handles the start of a peer group configuration */ void fastd_config_peer_group_push(const char *name) { fastd_peer_group_t *group = calloc(1, sizeof(fastd_peer_group_t)); group->name = strdup(name); @@ -144,10 +158,12 @@ void fastd_config_peer_group_push(const char *name) { conf.peer_group = group; } +/** Handles the end of a peer group configuration */ void fastd_config_peer_group_pop(void) { conf.peer_group = conf.peer_group->parent; } +/** Frees a peer group and its children */ static void free_peer_group(fastd_peer_group_t *group) { while (group->children) { fastd_peer_group_t *next = group->children->next; @@ -160,6 +176,7 @@ static void free_peer_group(fastd_peer_group_t *group) { free(group); } +/** Checks if a peer group has configured any peer dirs */ static bool has_peer_group_peer_dirs(const fastd_peer_group_t *group) { if (group->peer_dirs) return true; @@ -173,6 +190,7 @@ static bool has_peer_group_peer_dirs(const fastd_peer_group_t *group) { return false; } +/** Reads and processes all peer definitions in the current directory (which must also be supplied as the argument) */ static void read_peer_dir(const char *dir) { DIR *dirh = opendir("."); @@ -224,6 +242,7 @@ static void read_peer_dir(const char *dir) { } } +/** Reads all peer configured directories */ static void read_peer_dirs(void) { char *oldcwd = get_current_dir_name(); @@ -241,6 +260,7 @@ static void read_peer_dirs(void) { free(oldcwd); } +/** Adds a peer directory to the configuration */ void fastd_add_peer_dir(const char *dir) { char *oldcwd = get_current_dir_name(); @@ -259,6 +279,7 @@ void fastd_add_peer_dir(const char *dir) { free(oldcwd); } +/** Reads and processes a configuration file */ bool fastd_read_config(const char *filename, bool peer_config, int depth) { if (depth >= MAX_CONFIG_DEPTH) exit_error("maximum config include depth exceeded"); @@ -348,6 +369,7 @@ bool fastd_read_config(const char *filename, bool peer_config, int depth) { return ret; } +/** Gathers some information about the configured peers */ static void assess_peers(void) { conf.has_floating = false; @@ -358,7 +380,7 @@ static void assess_peers(void) { } } - +/** Loads information about the configured user and group */ static void configure_user(void) { conf.uid = getuid(); conf.gid = getgid(); @@ -418,6 +440,7 @@ static void configure_user(void) { } } +/** Initializes global configuration that depends on the configured methods */ static void configure_method_parameters(void) { conf.max_overhead = 0; conf.min_encrypt_head_space = 0; @@ -442,6 +465,7 @@ static void configure_method_parameters(void) { conf.min_decrypt_head_space = alignto(conf.min_decrypt_head_space, 16) + 8; } +/** Handles the initialization of the configured methods */ static void configure_methods(void) { size_t n_methods = 0, i; fastd_string_stack_t *method_name; @@ -459,6 +483,7 @@ static void configure_methods(void) { configure_method_parameters(); } +/** Frees the resources used by the configured methods */ static void destroy_methods(void) { size_t i; for (i = 0; conf.methods[i].name; i++) { @@ -468,6 +493,7 @@ static void destroy_methods(void) { free(conf.methods); } +/** Loads the configuration */ void fastd_configure(int argc, char *const argv[]) { default_config(); @@ -477,6 +503,7 @@ void fastd_configure(int argc, char *const argv[]) { conf.log_stderr_level = LL_DEFAULT; } +/** Performs some basic checks on the configuration */ static void config_check_base(void) { if (conf.ifname) { if (strchr(conf.ifname, '/')) @@ -503,6 +530,7 @@ static void config_check_base(void) { #endif } +/** Performs more checks on the configuration */ void fastd_config_check(void) { config_check_base(); @@ -523,6 +551,7 @@ void fastd_config_check(void) { configure_methods(); } +/** Performs the verify-config checks */ void fastd_config_verify(void) { config_check_base(); configure_methods(); @@ -532,6 +561,7 @@ void fastd_config_verify(void) { conf.protocol->peer_verify(peer); } +/** Reads the peer dirs of the current peer group and its children */ static void peer_dirs_read_peer_group(void) { read_peer_dirs(); @@ -544,6 +574,7 @@ static void peer_dirs_read_peer_group(void) { conf.peer_group = base; } +/** Deletes peer configs that have disappeared from a peer dir on reconfiguration */ static void peer_dirs_handle_old_peers(fastd_peer_config_t **old_peers, fastd_peer_config_t **new_peers) { fastd_peer_config_t **peer, **next, **new_peer, **new_next; for (peer = old_peers; *peer; peer = next) { @@ -588,6 +619,7 @@ static void peer_dirs_handle_old_peers(fastd_peer_config_t **old_peers, fastd_pe } } +/** Adds new peer configs on reconfiguration */ static void peer_dirs_handle_new_peers(fastd_peer_config_t **peers, fastd_peer_config_t *new_peers) { fastd_peer_config_t *peer; for (peer = new_peers; peer; peer = peer->next) { @@ -600,6 +632,7 @@ static void peer_dirs_handle_new_peers(fastd_peer_config_t **peers, fastd_peer_c } } +/** Refreshes the peer configurations from the configured peer dirs */ void fastd_config_load_peer_dirs(void) { fastd_peer_config_t *old_peers = conf.peers; conf.peers = NULL; @@ -615,6 +648,7 @@ void fastd_config_load_peer_dirs(void) { assess_peers(); } +/** Frees all resources used by the global configuration */ void fastd_config_release(void) { while (conf.peers) fastd_peer_config_delete(); diff --git a/src/config.h b/src/config.h index d4cbf93..3231f6d 100644 --- a/src/config.h +++ b/src/config.h @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Configuration management +*/ + #pragma once diff --git a/src/cpuid.h b/src/cpuid.h index 546c258..9382156 100644 --- a/src/cpuid.h +++ b/src/cpuid.h @@ -23,17 +23,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + CPUID function for x86-based platforms +*/ #pragma once #include <stdint.h> +/** The FXSR bit in the CPUID return value */ #define CPUID_FXSR ((uint64_t)1 << 24) + +/** The SSE2 bit in the CPUID return value */ #define CPUID_SSE2 ((uint64_t)1 << 26) + +/** The PCLMULQDQ bit in the CPUID return value */ #define CPUID_PCLMULQDQ ((uint64_t)1 << 33) + +/** The SSSE3 bit in the CPUID return value */ #define CPUID_SSSE3 ((uint64_t)1 << 41) +/** Returns the ECX and EDX return values of CPUID function 1 as a single uint64 */ static inline uint64_t fastd_cpuid(void) { unsigned eax, ebx, ecx, edx; diff --git a/src/crypto/cipher/aes128_ctr/aes128_ctr.c b/src/crypto/cipher/aes128_ctr/aes128_ctr.c index 52122d9..4448dd0 100644 --- a/src/crypto/cipher/aes128_ctr/aes128_ctr.c +++ b/src/crypto/cipher/aes128_ctr/aes128_ctr.c @@ -23,10 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The aes128-ctr stream cipher +*/ + #include "../../../crypto.h" +/** cipher info about aes128-ctr */ const fastd_cipher_info_t fastd_cipher_info_aes128_ctr = { .key_length = 16, .iv_length = 16, diff --git a/src/crypto/cipher/aes128_ctr/nacl/cipher_aes128_ctr_nacl.c b/src/crypto/cipher/aes128_ctr/nacl/cipher_aes128_ctr_nacl.c index 793b724..797572c 100644 --- a/src/crypto/cipher/aes128_ctr/nacl/cipher_aes128_ctr_nacl.c +++ b/src/crypto/cipher/aes128_ctr/nacl/cipher_aes128_ctr_nacl.c @@ -23,17 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The aes128-ctr implementation from NaCl +*/ + #include "../../../../crypto.h" #include <crypto_stream_aes128ctr.h> +/** The cipher state */ struct __attribute__((aligned(16))) fastd_cipher_state { - uint8_t d[crypto_stream_aes128ctr_BEFORENMBYTES] __attribute__((aligned(16))); + uint8_t d[crypto_stream_aes128ctr_BEFORENMBYTES] __attribute__((aligned(16))); /**< The unpacked AES key */ }; +/** Initializes the cipher state */ static fastd_cipher_state_t* aes128_ctr_init(const uint8_t *key) { fastd_block128_t k; memcpy(k.b, key, sizeof(fastd_block128_t)); @@ -47,11 +55,13 @@ static fastd_cipher_state_t* aes128_ctr_init(const uint8_t *key) { return state; } +/** XORs data with the aes128-ctr cipher stream */ static bool aes128_ctr_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { crypto_stream_aes128ctr_xor_afternm(out->b, in->b, len, iv, state->d); return true; } +/** Frees the cipher state */ static void aes128_ctr_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -59,6 +69,8 @@ static void aes128_ctr_free(fastd_cipher_state_t *state) { } } + +/** The nacl aes128-ctr implementation */ const fastd_cipher_t fastd_cipher_aes128_ctr_nacl = { .init = aes128_ctr_init, .crypt = aes128_ctr_crypt, diff --git a/src/crypto/cipher/aes128_ctr/openssl/aes128_ctr_openssl.c b/src/crypto/cipher/aes128_ctr/openssl/aes128_ctr_openssl.c index b47be57..2e06763 100644 --- a/src/crypto/cipher/aes128_ctr/openssl/aes128_ctr_openssl.c +++ b/src/crypto/cipher/aes128_ctr/openssl/aes128_ctr_openssl.c @@ -23,17 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The aes128-ctr implementation from OpenSSL +*/ + #include "../../../../crypto.h" #include <openssl/evp.h> +/** The cipher state containing the OpenSSL cipher context */ struct fastd_cipher_state { - EVP_CIPHER_CTX *aes; + EVP_CIPHER_CTX *aes; /**< The OpenSSL cipher context */ }; +/** Initializes the cipher state */ static fastd_cipher_state_t* aes128_ctr_init(const uint8_t *key) { fastd_cipher_state_t *state = malloc(sizeof(fastd_cipher_state_t)); @@ -43,6 +51,7 @@ static fastd_cipher_state_t* aes128_ctr_init(const uint8_t *key) { return state; } +/** XORs data with the aes128-ctr cipher stream */ static bool aes128_ctr_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { int clen, clen2; @@ -61,6 +70,7 @@ static bool aes128_ctr_crypt(const fastd_cipher_state_t *state, fastd_block128_t return true; } +/** Frees the cipher state */ static void aes128_ctr_free(fastd_cipher_state_t *state) { if (state) { EVP_CIPHER_CTX_free(state->aes); @@ -68,6 +78,8 @@ static void aes128_ctr_free(fastd_cipher_state_t *state) { } } + +/** The openssl aes128-ctr implementation */ const fastd_cipher_t fastd_cipher_aes128_ctr_openssl = { .available = fastd_true, diff --git a/src/crypto/cipher/ciphers.c.in b/src/crypto/cipher/ciphers.c.in index 01b5a35..7816bca 100644 --- a/src/crypto/cipher/ciphers.c.in +++ b/src/crypto/cipher/ciphers.c.in @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Generated lists of ciphers and their implementations +*/ + #include <src/crypto.h> #include <src/fastd.h> @@ -30,30 +36,35 @@ @CIPHER_DEFINITIONS@ +/** A cipher implementation */ typedef struct fastd_cipher_impl { - const char *name; - const fastd_cipher_t *impl; + const char *name; /**< The name of the cipher implementation */ + const fastd_cipher_t *impl; /**< The cipher implementation */ } fastd_cipher_impl_t; +/** A cipher */ typedef struct cipher_entry { - const char *name; - const fastd_cipher_info_t *info; - const fastd_cipher_impl_t *impls; + const char *name; /**< The name of the cipher */ + const fastd_cipher_info_t *info; /**< The associated cipher information */ + const fastd_cipher_impl_t *impls; /**< NULL-terminated array of cipher implementations */ } cipher_entry_t; @CIPHER_IMPLS@ +/** The list of supported ciphers */ static const cipher_entry_t ciphers[] = { @CIPHER_LIST@ }; +/** The list of chosen cipher implementations */ static const fastd_cipher_t *cipher_conf[array_size(ciphers)] = {}; +/** Checks if a cipher implementation is available on the runtime platform */ static inline bool cipher_available(const fastd_cipher_t *cipher) { return (!cipher->available) || cipher->available(); } -/** Initializes the list of ciphers */ +/** Initializes the list of cipher implementations */ void fastd_cipher_init(void) { size_t i, j; for (i = 0; i < array_size(ciphers); i++) { @@ -89,6 +100,7 @@ bool fastd_cipher_config(const char *name, const char *impl) { return false; } +/** Returns information about the cipher with the specified name if there is an implementation available */ const fastd_cipher_info_t* fastd_cipher_info_get_by_name(const char *name) { size_t i; for (i = 0; i < array_size(ciphers); i++) { @@ -104,6 +116,7 @@ const fastd_cipher_info_t* fastd_cipher_info_get_by_name(const char *name) { return NULL; } +/** Returns the chosen cipher implementation for a given cipher */ const fastd_cipher_t* fastd_cipher_get(const fastd_cipher_info_t *info) { size_t i; for (i = 0; i < array_size(ciphers); i++) { diff --git a/src/crypto/cipher/null/memcpy/null_memcpy.c b/src/crypto/cipher/null/memcpy/null_memcpy.c index a2c0df9..089817f 100644 --- a/src/crypto/cipher/null/memcpy/null_memcpy.c +++ b/src/crypto/cipher/null/memcpy/null_memcpy.c @@ -23,22 +23,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The memcpy null implementation +*/ + #include "../../../../crypto.h" +/** Doesn't do anything as the null cipher doesn't use any state */ static fastd_cipher_state_t* null_init(const uint8_t *key UNUSED) { return NULL; } +/** Just copies the input data to the output */ static bool null_memcpy(const fastd_cipher_state_t *state UNUSED, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv UNUSED) { memcpy(out, in, len); return true; } +/** Doesn't do anything as the null cipher doesn't use any state */ static void null_free(fastd_cipher_state_t *state UNUSED) { } +/** The memcpy null implementation */ const fastd_cipher_t fastd_cipher_null_memcpy = { .init = null_init, .crypt = null_memcpy, diff --git a/src/crypto/cipher/null/null.c b/src/crypto/cipher/null/null.c index d6e4cab..353090a 100644 --- a/src/crypto/cipher/null/null.c +++ b/src/crypto/cipher/null/null.c @@ -23,10 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The null cipher not performing any encryption +*/ + #include "../../../crypto.h" +/** cipher info about the null cipher */ const fastd_cipher_info_t fastd_cipher_info_null = { .key_length = 0, .iv_length = 0, diff --git a/src/crypto/cipher/salsa20/nacl/salsa20_nacl.c b/src/crypto/cipher/salsa20/nacl/salsa20_nacl.c index 03ab1d9..6179bc2 100644 --- a/src/crypto/cipher/salsa20/nacl/salsa20_nacl.c +++ b/src/crypto/cipher/salsa20/nacl/salsa20_nacl.c @@ -23,17 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The Salsa20 implementation from NaCl +*/ + #include "../../../../crypto.h" #include <crypto_stream_salsa20.h> +/** The cipher state */ struct fastd_cipher_state { - uint8_t key[crypto_stream_salsa20_KEYBYTES]; + uint8_t key[crypto_stream_salsa20_KEYBYTES]; /**< The encryption key */ }; +/** Initializes the cipher state */ static fastd_cipher_state_t* salsa20_init(const uint8_t *key) { fastd_cipher_state_t *state = malloc(sizeof(fastd_cipher_state_t)); memcpy(state->key, key, crypto_stream_salsa20_KEYBYTES); @@ -41,11 +49,13 @@ static fastd_cipher_state_t* salsa20_init(const uint8_t *key) { return state; } +/** XORs data with the Salsa20 cipher stream */ static bool salsa20_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { crypto_stream_salsa20_xor(out->b, in->b, len, iv, state->key); return true; } +/** Frees the cipher state */ static void salsa20_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -53,6 +63,8 @@ static void salsa20_free(fastd_cipher_state_t *state) { } } + +/** The nacl salsa20 implementation */ const fastd_cipher_t fastd_cipher_salsa20_nacl = { .init = salsa20_init, .crypt = salsa20_crypt, diff --git a/src/crypto/cipher/salsa20/salsa20.c b/src/crypto/cipher/salsa20/salsa20.c index f4f713f..dad6a6c 100644 --- a/src/crypto/cipher/salsa20/salsa20.c +++ b/src/crypto/cipher/salsa20/salsa20.c @@ -23,10 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The Salsa20 stream cipher +*/ + #include "../../../crypto.h" +/** Cipher info about Salsa20 */ const fastd_cipher_info_t fastd_cipher_info_salsa20 = { .key_length = 32, .iv_length = 8, diff --git a/src/crypto/cipher/salsa20/xmm/salsa20_xmm.c b/src/crypto/cipher/salsa20/xmm/salsa20_xmm.c index 52c4b6d..a85ed72 100644 --- a/src/crypto/cipher/salsa20/xmm/salsa20_xmm.c +++ b/src/crypto/cipher/salsa20/xmm/salsa20_xmm.c @@ -23,15 +23,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - The assembly implementations were written by D. J. Bernstein and are - Public Domain. For more information see http://cr.yp.to/snuffle.html +/** + \file + + The XMM Salsa20 implementation for SSE2-capable x86 systems + + The assembly implementations were written by D. J. Bernstein and are + Public Domain. For more information see http://cr.yp.to/snuffle.html */ + #include "../../../../crypto.h" #include "../../../../cpuid.h" +/** The length of the key used by Salsa20 */ #define KEYBYTES 32 @@ -44,18 +50,22 @@ #endif +/** The actual Salsa20 assembly implementation */ int crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k); +/** The cipher state */ struct fastd_cipher_state { - uint8_t key[KEYBYTES]; + uint8_t key[KEYBYTES]; /**< The encryption key */ }; +/** Checks if the runtime platform supports SSE2 */ static bool salsa20_available(void) { return fastd_cpuid() & CPUID_SSE2; } +/** Initializes the cipher state */ static fastd_cipher_state_t* salsa20_init(const uint8_t *key) { fastd_cipher_state_t *state = malloc(sizeof(fastd_cipher_state_t)); memcpy(state->key, key, KEYBYTES); @@ -63,11 +73,13 @@ static fastd_cipher_state_t* salsa20_init(const uint8_t *key) { return state; } +/** XORs data with the Salsa20 cipher stream */ static bool salsa20_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { crypto_stream_salsa20_xor(out->b, in->b, len, iv, state->key); return true; } +/** Frees the cipher state */ static void salsa20_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -75,6 +87,8 @@ static void salsa20_free(fastd_cipher_state_t *state) { } } + +/** The xmm salsa20 implementation */ const fastd_cipher_t fastd_cipher_salsa20_xmm = { .available = salsa20_available, diff --git a/src/crypto/cipher/salsa2012/nacl/salsa2012_nacl.c b/src/crypto/cipher/salsa2012/nacl/salsa2012_nacl.c index efe7089..18ec502 100644 --- a/src/crypto/cipher/salsa2012/nacl/salsa2012_nacl.c +++ b/src/crypto/cipher/salsa2012/nacl/salsa2012_nacl.c @@ -23,17 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The Salsa20/12 implementation from NaCl +*/ + #include "../../../../crypto.h" #include <crypto_stream_salsa2012.h> +/** The cipher state */ struct fastd_cipher_state { - uint8_t key[crypto_stream_salsa2012_KEYBYTES]; + uint8_t key[crypto_stream_salsa2012_KEYBYTES]; /**< The encryption key */ }; +/** Initializes the cipher state */ static fastd_cipher_state_t* salsa2012_init(const uint8_t *key) { fastd_cipher_state_t *state = malloc(sizeof(fastd_cipher_state_t)); memcpy(state->key, key, crypto_stream_salsa2012_KEYBYTES); @@ -41,11 +49,13 @@ static fastd_cipher_state_t* salsa2012_init(const uint8_t *key) { return state; } +/** XORs data with the Salsa20/12 cipher stream */ static bool salsa2012_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { crypto_stream_salsa2012_xor(out->b, in->b, len, iv, state->key); return true; } +/** Frees the cipher state */ static void salsa2012_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -53,6 +63,8 @@ static void salsa2012_free(fastd_cipher_state_t *state) { } } + +/** The nacl salsa2012 implementation */ const fastd_cipher_t fastd_cipher_salsa2012_nacl = { .init = salsa2012_init, .crypt = salsa2012_crypt, diff --git a/src/crypto/cipher/salsa2012/salsa2012.c b/src/crypto/cipher/salsa2012/salsa2012.c index 8dcfc33..d10c4fb 100644 --- a/src/crypto/cipher/salsa2012/salsa2012.c +++ b/src/crypto/cipher/salsa2012/salsa2012.c @@ -23,10 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The Salsa20/12 stream cipher, a reduced-round version of Salsa20 +*/ + #include "../../../crypto.h" +/** Cipher info about Salsa20/12 */ const fastd_cipher_info_t fastd_cipher_info_salsa2012 = { .key_length = 32, .iv_length = 8, diff --git a/src/crypto/cipher/salsa2012/xmm/salsa2012_xmm.c b/src/crypto/cipher/salsa2012/xmm/salsa2012_xmm.c index 5e5862f..7e6fe80 100644 --- a/src/crypto/cipher/salsa2012/xmm/salsa2012_xmm.c +++ b/src/crypto/cipher/salsa2012/xmm/salsa2012_xmm.c @@ -23,15 +23,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - The assembly implementations were written by D. J. Bernstein and are - Public Domain. For more information see http://cr.yp.to/snuffle.html +/** + \file + + The XMM Salsa20/12 implementation for SSE2-capable x86 systems + + The assembly implementations were written by D. J. Bernstein and are + Public Domain. For more information see http://cr.yp.to/snuffle.html */ + #include "../../../../crypto.h" #include "../../../../cpuid.h" +/** The length of the key used by Salsa20/12 */ #define KEYBYTES 32 @@ -44,18 +50,22 @@ #endif +/** The actual Salsa20/12 assembly implementation */ int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k); +/** The cipher state */ struct fastd_cipher_state { - uint8_t key[KEYBYTES]; + uint8_t key[KEYBYTES]; /**< The encryption key */ }; +/** Checks if the runtime platform supports SSE2 */ static bool salsa2012_available(void) { return fastd_cpuid() & CPUID_SSE2; } +/** Initializes the cipher state */ static fastd_cipher_state_t* salsa2012_init(const uint8_t *key) { fastd_cipher_state_t *state = malloc(sizeof(fastd_cipher_state_t)); memcpy(state->key, key, KEYBYTES); @@ -63,11 +73,13 @@ static fastd_cipher_state_t* salsa2012_init(const uint8_t *key) { return state; } +/** XORs data with the Salsa20/12 cipher stream */ static bool salsa2012_crypt(const fastd_cipher_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t len, const uint8_t *iv) { crypto_stream_salsa2012_xor(out->b, in->b, len, iv, state->key); return true; } +/** Frees the cipher state */ static void salsa2012_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -75,6 +87,8 @@ static void salsa2012_free(fastd_cipher_state_t *state) { } } + +/** The xmm salsa2012 implementation */ const fastd_cipher_t fastd_cipher_salsa2012_xmm = { .available = salsa2012_available, diff --git a/src/crypto/mac/ghash/builtin/ghash_builtin.c b/src/crypto/mac/ghash/builtin/ghash_builtin.c index 28e9292..0b957a4 100644 --- a/src/crypto/mac/ghash/builtin/ghash_builtin.c +++ b/src/crypto/mac/ghash/builtin/ghash_builtin.c @@ -23,18 +23,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Portable, table-based GHASH implementation +*/ + #include "../../../../crypto.h" +/** MAC state used by this GHASH implmentation */ struct fastd_mac_state { - fastd_block128_t H[32][16]; + fastd_block128_t H[32][16]; /**< Lookup table unpacked from the hash key */ }; +/** Lower 128 bit of the modulus \f$ x^{128} + x^7 + x^2 + x + 1 \f$ */ static const fastd_block128_t r = { .b = {0xe1} }; +/** Right shift of a 128bit integer by up to 8 bytes */ static inline uint8_t shr(fastd_block128_t *out, const fastd_block128_t *in, int n) { size_t i; uint8_t c = 0; @@ -48,6 +57,7 @@ static inline uint8_t shr(fastd_block128_t *out, const fastd_block128_t *in, int return (c >> (8-n)); } +/** Galois field multiplication of a 128bit integer with H */ static inline void mulH_a(fastd_block128_t *x, const fastd_mac_state_t *cstate) { fastd_block128_t out = {}; @@ -61,6 +71,7 @@ static inline void mulH_a(fastd_block128_t *x, const fastd_mac_state_t *cstate) } +/** Initializes the MAC state with the unpacked key data */ static fastd_mac_state_t* ghash_init(const uint8_t *key) { fastd_mac_state_t *state; if (posix_memalign((void**)&state, 16, sizeof(fastd_mac_state_t))) @@ -107,6 +118,7 @@ static fastd_mac_state_t* ghash_init(const uint8_t *key) { return state; } +/** Calculates the GHASH of the supplied blocks */ static bool ghash_hash(const fastd_mac_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t n_blocks) { memset(out, 0, sizeof(fastd_block128_t)); @@ -119,6 +131,7 @@ static bool ghash_hash(const fastd_mac_state_t *state, fastd_block128_t *out, co return true; } +/** Frees the MAC state */ static void ghash_free(fastd_mac_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -126,6 +139,7 @@ static void ghash_free(fastd_mac_state_t *state) { } } +/** The builtin GHASH implementation */ const fastd_mac_t fastd_mac_ghash_builtin = { .init = ghash_init, .hash = ghash_hash, diff --git a/src/crypto/mac/ghash/ghash.c b/src/crypto/mac/ghash/ghash.c index 5976131..0ba6440 100644 --- a/src/crypto/mac/ghash/ghash.c +++ b/src/crypto/mac/ghash/ghash.c @@ -23,10 +23,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + General information about the GHASH algorithm + + \sa http://en.wikipedia.org/wiki/Galois/Counter_Mode +*/ #include "../../../crypto.h" +/** MAC info about the GHASH algorithm */ const fastd_mac_info_t fastd_mac_info_ghash = { .key_length = 16, }; diff --git a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.c b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.c index e335a82..5d5977a 100644 --- a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.c +++ b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.c @@ -23,17 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + PCLMULQDQ-based GHASH implementation for newer x86 systems +*/ + #include "ghash_pclmulqdq.h" #include "../../../../cpuid.h" +/** Checks if the runtime platform can support the PCLMULQDQ implementation */ static bool ghash_available(void) { static const uint64_t REQ = CPUID_FXSR|CPUID_SSSE3|CPUID_PCLMULQDQ; return ((fastd_cpuid()&REQ) == REQ); } +/** The pclmulqdq ghash implementation */ const fastd_mac_t fastd_mac_ghash_pclmulqdq = { .available = ghash_available, diff --git a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.h b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.h index c2cf4e3..51ef5da 100644 --- a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.h +++ b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq.h @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + PCLMULQDQ-based GHASH implementation for newer x86 systems +*/ + #pragma once diff --git a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq_impl.c b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq_impl.c index 9dc0a32..49c036a 100644 --- a/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq_impl.c +++ b/src/crypto/mac/ghash/pclmulqdq/ghash_pclmulqdq_impl.c @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + PCLMULQDQ-based GHASH implementation for newer x86 systems: implementation +*/ + #include "ghash_pclmulqdq.h" #include <wmmintrin.h> @@ -30,16 +36,19 @@ #include <tmmintrin.h> +/** An union allowing easy access to a block as a SIMD vector and a fastd_block128_t */ typedef union vecblock { - __m128i v; - fastd_block128_t b; + __m128i v; /**< __m128i access */ + fastd_block128_t b; /**< fastd_block128_t access */ } vecblock_t; +/** The MAC state used by this GHASH implementation */ struct fastd_mac_state { - vecblock_t H; + vecblock_t H; /**< The hash key used by GHASH */ }; +/** Left shift on a 128bit integer */ static inline __m128i shl(__m128i v, int a) { __m128i tmpl = _mm_slli_epi64(v, a); __m128i tmpr = _mm_srli_epi64(v, 64-a); @@ -48,6 +57,7 @@ static inline __m128i shl(__m128i v, int a) { return _mm_xor_si128(tmpl, tmpr); } +/** Right shift on a 128bit integer */ static inline __m128i shr(__m128i v, int a) { __m128i tmpr = _mm_srli_epi64(v, a); __m128i tmpl = _mm_slli_epi64(v, 64-a); @@ -56,13 +66,16 @@ static inline __m128i shr(__m128i v, int a) { return _mm_xor_si128(tmpr, tmpl); } +/** _mm_shuffle_epi8 parameter to reverse the bytes of a __m128i */ static const __v16qi BYTESWAP_SHUFFLE = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; +/** Reverses the order of the bytes of a __m128i */ static inline __m128i byteswap(__m128i v) { return _mm_shuffle_epi8(v, (__m128i)BYTESWAP_SHUFFLE); } +/** Initializes the state used by this GHASH implementation */ fastd_mac_state_t* fastd_ghash_pclmulqdq_init(const uint8_t *key) { fastd_mac_state_t *state; if (posix_memalign((void**)&state, 16, sizeof(fastd_mac_state_t))) @@ -74,6 +87,7 @@ fastd_mac_state_t* fastd_ghash_pclmulqdq_init(const uint8_t *key) { return state; } +/** Frees the state used by this GHASH implementation */ void fastd_ghash_pclmulqdq_free(fastd_mac_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); @@ -81,6 +95,7 @@ void fastd_ghash_pclmulqdq_free(fastd_mac_state_t *state) { } } +/** Performs a carryless multiplication of two 128bit integers modulo \f$ x^{128} + x^7 + x^2 + x + 1 \f$ */ static __m128i gmul(__m128i v, __m128i h) { /* multiply */ __m128i z0, z1, z2, tmp; @@ -134,6 +149,7 @@ static __m128i gmul(__m128i v, __m128i h) { } +/** Calculates the GHASH of the supplied input blocks */ bool fastd_ghash_pclmulqdq_hash(const fastd_mac_state_t *state, fastd_block128_t *out, const fastd_block128_t *in, size_t n_blocks) { vecblock_t v = {.v = _mm_setzero_si128()}; diff --git a/src/crypto/mac/macs.c.in b/src/crypto/mac/macs.c.in index 0db26d9..5f9a353 100644 --- a/src/crypto/mac/macs.c.in +++ b/src/crypto/mac/macs.c.in @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Generated lists of MACs and their implementations +*/ + #include <src/crypto.h> #include <src/fastd.h> @@ -30,29 +36,35 @@ @MAC_DEFINITIONS@ +/** A MAC implementation */ typedef struct fastd_mac_impl { - const char *name; - const fastd_mac_t *impl; + const char *name; /**< The name of the MAC implementation */ + const fastd_mac_t *impl; /**< The MAC implementation */ } fastd_mac_impl_t; +/** A MAC */ typedef struct mac_entry { - const char *name; - const fastd_mac_info_t *info; - const fastd_mac_impl_t *impls; + const char *name; /**< The name of the MAC */ + const fastd_mac_info_t *info; /**< The associated MAC information */ + const fastd_mac_impl_t *impls; /**< NULL-terminated array of MAC implementations */ } mac_entry_t; @MAC_IMPLS@ +/** The list of supported MACs */ static const mac_entry_t macs[] = { @MAC_LIST@ }; +/** The list of chosen MAC implementations */ static const fastd_mac_t *mac_conf[array_size(macs)] = {}; +/** Checks if a MAC implementation is available on the runtime platform */ static inline bool mac_available(const fastd_mac_t *mac) { return (!mac->available) || mac->available(); } +/** Initializes the list of MAC implementations */ void fastd_mac_init(void) { size_t i, j; for (i = 0; i < array_size(macs); i++) { @@ -65,6 +77,7 @@ void fastd_mac_init(void) { } } +/** Configures a MAC to use a specific implementation */ bool fastd_mac_config(const char *name, const char *impl) { size_t i; for (i = 0; i < array_size(macs); i++) { @@ -87,6 +100,7 @@ bool fastd_mac_config(const char *name, const char *impl) { return false; } +/** Returns information about the MAC with the specified name if there is an implementation available */ const fastd_mac_info_t* fastd_mac_info_get_by_name(const char *name) { size_t i, j; for (i = 0; i < array_size(macs); i++) { @@ -102,6 +116,7 @@ const fastd_mac_info_t* fastd_mac_info_get_by_name(const char *name) { return NULL; } +/** Returns the chosen MAC implementation for a given cipher */ const fastd_mac_t* fastd_mac_get(const fastd_mac_info_t *info) { size_t i; for (i = 0; i < array_size(macs); i++) { diff --git a/src/fastd.c b/src/fastd.c index a33ba66..3bc3929 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -23,6 +23,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Initialization, main loop and cleanup +*/ + + #include "fastd.h" #include "async.h" @@ -55,26 +62,35 @@ #endif +/** The global context */ fastd_context_t ctx; -static volatile bool sighup = false; -static volatile bool terminate = false; -static volatile bool dump = false; +static volatile bool sighup = false; /**< Is set to true when a SIGHUP is received */ +static volatile bool terminate = false; /**< Is set to true when a SIGTERM, SIGQUIT or SIGINT is received */ +static volatile bool dump = false; /**< Is set to true when a SIGUSR1 is received */ +/** SIGHUP handler */ static void on_sighup(int signo UNUSED) { sighup = true; } +/** SIGTERM, SIGQUIT and SIGINT handler */ static void on_terminate(int signo UNUSED) { terminate = true; } +/** SIGUSR1 handler */ static void on_sigusr1(int signo UNUSED) { dump = true; } +/** + SIGCHLD handler + + Reaps zombies of asynchronous shell commands. +*/ static void on_sigchld(int signo UNUSED) { size_t i; for (i = 0; i < VECTOR_LEN(ctx.async_pids);) { @@ -96,6 +112,7 @@ static void on_sigchld(int signo UNUSED) { } } +/** Installs signal handlers */ static void init_signals(void) { struct sigaction action; @@ -135,6 +152,7 @@ static void init_signals(void) { } +/** Initializes log destinations */ static inline void init_log(void) { if (conf.log_syslog_level > LL_UNSPEC) openlog(conf.log_syslog_ident, LOG_PID, LOG_DAEMON); @@ -142,11 +160,13 @@ static inline void init_log(void) { ctx.log_initialized = true; } +/** Cleans up log destinations */ static inline void close_log(void) { closelog(); } +/** Initializes the configured sockets */ static void init_sockets(void) { ctx.socks = malloc(conf.n_bind_addrs * sizeof(fastd_socket_t)); @@ -167,6 +187,7 @@ static void init_sockets(void) { ctx.n_socks = conf.n_bind_addrs; } +/** Closes fastd's sockets */ static void close_sockets(void) { size_t i; for (i = 0; i < ctx.n_socks; i++) @@ -175,22 +196,31 @@ static void close_sockets(void) { free(ctx.socks); } +/** Calls the on-pre-up command */ static inline void on_pre_up(void) { fastd_shell_command_exec(&conf.on_pre_up, NULL); } +/** Calls the on-up command */ static inline void on_up(void) { fastd_shell_command_exec(&conf.on_up, NULL); } +/** Calls the on-down command */ static inline void on_down(void) { fastd_shell_command_exec(&conf.on_down, NULL); } +/** Calls the on-post-down command */ static inline void on_post_down(void) { fastd_shell_command_exec(&conf.on_post_down, NULL); } +/** + Initializes the peers + + Is called after each reconfiguration to remove old peers and add new ones. +*/ static void init_peers(void) { fastd_peer_config_t *peer_conf; for (peer_conf = conf.peers; peer_conf; peer_conf = peer_conf->next) @@ -227,11 +257,13 @@ static void init_peers(void) { } } +/** Removes all peers */ static void delete_peers(void) { while (VECTOR_LEN(ctx.peers)) fastd_peer_delete(VECTOR_INDEX(ctx.peers, VECTOR_LEN(ctx.peers)-1)); } +/** Dumps statistics and the list of known peers to the logs */ static void dump_state(void) { pr_info("TX stats: %U packet(s), %U byte(s); dropped: %U packet(s), %U byte(s); error: %U packet(s), %U byte(s)", ctx.tx.packets, ctx.tx.bytes, ctx.tx_dropped.packets, ctx.tx_dropped.bytes, ctx.tx_error.packets, ctx.tx_error.bytes); @@ -265,6 +297,7 @@ static void dump_state(void) { pr_info("dump finished."); } +/** Performs periodic maintenance tasks */ static inline void maintenance(void) { if (!fastd_timed_out(&ctx.next_maintenance)) return; @@ -299,6 +332,7 @@ void fastd_close_all_fds(void) { } } +/** Writes the PID file */ static void write_pid(pid_t pid) { if (!conf.pid_file) return; @@ -332,6 +366,7 @@ static void write_pid(pid_t pid) { pr_debug_errno("setegid"); } +/** Switches to the configured user */ static void set_user(void) { if (conf.user || conf.group) { if (setgid(conf.gid) < 0) @@ -344,6 +379,7 @@ static void set_user(void) { } } +/** Sets the configured user's supplementary groups */ static void set_groups(void) { if (conf.groups) { if (setgroups(conf.n_groups, conf.groups) < 0) { @@ -359,12 +395,13 @@ static void set_groups(void) { } } +/** Switches the user and drops all capabilities */ static void drop_caps(void) { set_user(); fastd_cap_drop(); } -/* will double fork and wait for a status notification from the child */ +/** Will double fork and wait for a status notification from the child before exiting in the original parent */ static int daemonize(void) { uint8_t status = 1; int pipefd[2]; @@ -415,6 +452,7 @@ static int daemonize(void) { } #ifdef ENABLE_SYSTEMD +/** Sends a readiness notification on a notify socket */ static void notify_systemd(const char *notify_socket) { int fd; struct sockaddr_un sa = {}; @@ -445,6 +483,7 @@ static void notify_systemd(const char *notify_socket) { } #endif +/** Main function */ int main(int argc, char *argv[]) { memset(&ctx, 0, sizeof(ctx)); int status_fd = -1; diff --git a/src/fastd.h b/src/fastd.h index 0b326b0..f69f2f8 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -124,9 +124,9 @@ struct fastd_protocol { /** An union storing an IPv4 or IPv6 address */ union fastd_peer_address { - struct sockaddr sa; /**< A generic sockaddr union field of the address (for access to sa_family) */ - struct sockaddr_in in; /**< An IPv4 address */ - struct sockaddr_in6 in6; /**< An IPv6 address */ + struct sockaddr sa; /**< A sockaddr field (for access to sa_family) */ + struct sockaddr_in in; /**< An IPv4 address */ + struct sockaddr_in6 in6; /**< An IPv6 address */ }; /** A linked list of addresses to bind to */ @@ -201,7 +201,7 @@ struct fastd_config { char *secret; /**< The configured secret key */ - fastd_peer_group_t *peer_group; /**< The root peer group configuration */ + fastd_peer_group_t *peer_group; /**< The root peer group configuration */ fastd_peer_config_t *peers; /**< The configured peers */ bool has_floating; /**< Specifies if any of the configured peers have floating remotes */ @@ -289,8 +289,8 @@ struct fastd_string_stack { }; -extern fastd_context_t ctx; /**< The global context */ -extern fastd_config_t conf; /**< The global configuration */ +extern fastd_context_t ctx; +extern fastd_config_t conf; void fastd_send(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer, size_t stat_size); diff --git a/src/fastd_config.h.in b/src/fastd_config.h.in index 196ed34..429e42e 100644 --- a/src/fastd_config.h.in +++ b/src/fastd_config.h.in @@ -23,52 +23,118 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Generated configuration +*/ + #pragma once +/** Defined if the platform supports the AI_ADDRCONFIG flag to getaddrinfo() */ #cmakedefine HAVE_AI_ADDRCONFIG + +/** Defined if the platform defines the \e ethhdr struct */ #cmakedefine HAVE_ETHHDR + +/** Defined if the platform defines get_current_dir_name() */ #cmakedefine HAVE_GET_CURRENT_DIR_NAME +/** Defined if the platform supports SO_BINDTODEVICE */ #cmakedefine USE_BINDTODEVICE + +/** Defined if the platform supports epoll */ #cmakedefine USE_EPOLL + +/** Defined if the platform supports SO_FREEBIND */ #cmakedefine USE_FREEBIND + +/** Defined if the platform supports IP_MTU_DISCOVER */ #cmakedefine USE_PMTU + +/** Defined if the platform supports IP_PKTINFO */ #cmakedefine USE_PKTINFO + +/** Defined if the platform supports SO_MARK */ #cmakedefine USE_PACKET_MARK + +/** Defined if the platform supports binding on IPv4 and IPv6 with a single socket */ #cmakedefine USE_MULTIAF_BIND +/** Defined if POSIX capability support is enabled */ #cmakedefine WITH_CAPABILITIES + +/** Defined if support for setting user/group related options on the command line is enabled */ #cmakedefine WITH_CMDLINE_USER + +/** Defined if support for setting logging related options on the command line is enabled */ #cmakedefine WITH_CMDLINE_LOGGING + +/** Defined if support for setting related to the VPN operation (like mode, interface, encryption method) on the command line is enabled */ #cmakedefine WITH_CMDLINE_OPERATION + +/** Defined if support for setting handler scripts (e.g. --on-up) on the command line is enabled */ #cmakedefine WITH_CMDLINE_COMMANDS +/** Defined if on-verify support is enabled */ #cmakedefine WITH_VERIFY +/** Defined if systemd support is enabled */ +#cmakedefine ENABLE_SYSTEMD + + +/** Defined if libsodium is used */ #cmakedefine HAVE_LIBSODIUM + +/** Defined if OpenSSL is used */ #cmakedefine ENABLE_OPENSSL -#cmakedefine ENABLE_SYSTEMD + +/** The maximum depth of nested includes in config files */ #define MAX_CONFIG_DEPTH @MAX_CONFIG_DEPTH_NUM@ +/** The interval of periodic maintenance tasks */ #define MAINTENANCE_INTERVAL 10 + +/** The time after which a keepalive should be sent */ #define KEEPALIVE_TIMEOUT 15 + +/** The time after with a peer is reset if no traffic is received from it */ #define PEER_STALE_TIME 90 + +/** The time after which a peer's ethernet address is forgotten if it is not seen */ #define ETH_ADDR_STALE_TIME 300 + +/** The time after a packet is received and no packets with lower sequence numbers are accepted anymore */ #define REORDER_TIME 10 + +/** The minimum time that must pass between two on-verify calls on the same peer */ #define MIN_VERIFY_INTERVAL 10 + +/** How long a peer stays valid after a successful on-verify run */ #define VERIFY_VALID_TIME 60 /* 1 minute */ +/** The minimum interval between two handshakes with a peer */ #define MIN_HANDSHAKE_INTERVAL 15 + +/** The minimum interval between two resolves of the same remote */ #define MIN_RESOLVE_INTERVAL 15 + +/** How long a session stays valid after a key is negotiated */ #define KEY_VALID 3600 /* 60 minutes */ + +/** How long an old session stays valid after a new session has been established */ #define KEY_VALID_OLD 60 /* 1 minute */ + +/** How many seconds after the establishment of a session we want to refresh the session */ #define KEY_REFRESH 3300 /* 55 minutes */ + +/** A random time up to KEY_REFRESH_SPLAY is subtracted from KEY_REFRESH */ #define KEY_REFRESH_SPLAY 300 /* 5 minutes */ @@ -23,6 +23,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + An implementation of the Jenkins hash function + + \sa https://en.wikipedia.org/wiki/Jenkins_hash_function +*/ + #pragma once @@ -31,6 +39,7 @@ #include <stdint.h> +/** Adds data bytes to the 32bit hash value */ static inline void fastd_hash(uint32_t *hash, const void *data, size_t len) { size_t i; for (i = 0; i < len; ++i) { @@ -40,6 +49,7 @@ static inline void fastd_hash(uint32_t *hash, const void *data, size_t len) { } } +/** Finalizes a hash value */ static inline void fastd_hash_final(uint32_t *hash) { *hash += (*hash << 3); *hash ^= (*hash >> 11); diff --git a/src/hkdf_sha256.c b/src/hkdf_sha256.c index 7cf3af8..f521f41 100644 --- a/src/hkdf_sha256.c +++ b/src/hkdf_sha256.c @@ -23,12 +23,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + An implementation of the HMAC-based Key Derivation Function (RFC 5869) using HMAC-SHA256 +*/ + #include "hkdf_sha256.h" #include <string.h> +/** The HKDF-SHA256 expansion function */ void fastd_hkdf_sha256_expand(fastd_sha256_t *out, size_t blocks, const fastd_sha256_t *prk, const uint8_t *info, size_t infolen) { if (!blocks) return; diff --git a/src/hkdf_sha256.h b/src/hkdf_sha256.h index 94b726e..5de543c 100644 --- a/src/hkdf_sha256.h +++ b/src/hkdf_sha256.h @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + An implementation of the HMAC-based Key Derivation Function (RFC 5869) using HMAC-SHA256 +*/ + #pragma once @@ -30,6 +36,7 @@ #include "types.h" +/** The HKDF-SHA256 extraction function (which is just HMAC-SHA256) */ static inline void fastd_hkdf_sha256_extract(fastd_sha256_t *out, const uint32_t salt[FASTD_HMACSHA256_KEY_WORDS], const uint32_t *in, size_t len) { fastd_hmacsha256(out, salt, in, len); } @@ -23,30 +23,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Config scanner for the fastd configuration file format +*/ + #include "lex.h" #include <stdlib.h> +/** The scanner context */ struct fastd_lex { - FILE *file; + FILE *file; /**< The input file */ - bool needspace; + bool needspace; /**< Specifies if some kind of whitespace (or similar separator like a semicolon) is needed before the next token is parsed */ - size_t start; - size_t end; - size_t tok_len; - char buffer[1024]; + size_t start; /**< The start of the current token in the input buffer */ + size_t end; /**< The end of the input read into the input buffer so far */ + size_t tok_len; /**< The number of characters in the current token */ + char buffer[1024]; /**< The input buffer */ }; - +/** A keyword with the corresponding token ID */ typedef struct keyword { - const char *keyword; - int token; + const char *keyword; /**< The keyword */ + int token; /**< The numerical token ID as generated by the parser */ } keyword_t; -/* the keyword list must be sorted */ + +/** + The list of known keywords + + The keyword list must be sorted so binary search can work. +*/ static const keyword_t keywords[] = { { "addresses", TOK_ADDRESSES }, { "any", TOK_ANY }, @@ -116,12 +128,14 @@ static const keyword_t keywords[] = { { "yes", TOK_YES }, }; +/** Compares two keyword_t instances by their keyword */ static int compare_keywords(const void *v1, const void *v2) { const keyword_t *k1 = v1, *k2 = v2; return strcmp(k1->keyword, k2->keyword); } +/** Reads the next part of the input file into the input buffer */ static bool advance(fastd_lex_t *lex) { if (lex->start > 0) { memmove(lex->buffer, lex->buffer+lex->start, lex->end - lex->start); @@ -138,14 +152,17 @@ static bool advance(fastd_lex_t *lex) { return l; } +/** Returns the current character (not yet added to the current token) */ static inline char current(fastd_lex_t *lex) { return lex->buffer[lex->start + lex->tok_len]; } +/** Returns the current token as a newly allocated string */ static char* get_token(fastd_lex_t *lex) { return strndup(lex->buffer+lex->start, lex->tok_len); } +/** Tries to add the next character to the current token */ static bool next(YYLTYPE *yylloc, fastd_lex_t *lex, bool move) { if (lex->start + lex->tok_len >= lex->end) return false; @@ -170,6 +187,7 @@ static bool next(YYLTYPE *yylloc, fastd_lex_t *lex, bool move) { return true; } +/** Removes the current token from the input buffer */ static void consume(fastd_lex_t *lex, bool needspace) { lex->start += lex->tok_len; lex->tok_len = 0; @@ -177,11 +195,13 @@ static void consume(fastd_lex_t *lex, bool needspace) { lex->needspace = needspace; } +/** Signals an error caused by an I/O error */ static int io_error(YYSTYPE *yylval, fastd_lex_t *lex UNUSED) { yylval->error = "I/O error"; return -1; } +/** Signals an error caused by a syntax error */ static int syntax_error(YYSTYPE *yylval, fastd_lex_t *lex) { if (ferror(lex->file)) return io_error(yylval, lex); @@ -190,6 +210,7 @@ static int syntax_error(YYSTYPE *yylval, fastd_lex_t *lex) { return -1; } +/** Skips a block comment */ static int consume_comment(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { char prev = 0; @@ -210,6 +231,7 @@ static int consume_comment(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { return -1; } +/** Signals an error caused by an unterminated string */ static int unterminated_string(YYSTYPE *yylval, fastd_lex_t *lex) { if (ferror(lex->file)) return io_error(yylval, lex); @@ -218,6 +240,7 @@ static int unterminated_string(YYSTYPE *yylval, fastd_lex_t *lex) { return -1; } +/** Tries to process the current input as a string */ static int parse_string(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { char *buf = NULL; size_t len = 1024; @@ -268,6 +291,7 @@ static int parse_string(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { return TOK_STRING; } +/** Tries to process the current input as an IPv6 address */ static int parse_ipv6_address(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { if (lex->needspace) return syntax_error(yylval, lex); @@ -332,6 +356,7 @@ static int parse_ipv6_address(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex return ifname ? TOK_ADDR6_SCOPED : TOK_ADDR6; } +/** Tries to process the current input as an IPv4 address */ static int parse_ipv4_address(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { if (lex->needspace) return syntax_error(yylval, lex); @@ -356,6 +381,7 @@ static int parse_ipv4_address(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex return TOK_ADDR4; } +/** Tries to process the current input as a number */ static int parse_number(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { bool digitonly = true; @@ -390,6 +416,7 @@ static int parse_number(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { return TOK_UINT; } +/** Tries to process the current input as a keyword */ static int parse_keyword(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { if (lex->needspace) return syntax_error(yylval, lex); @@ -414,6 +441,8 @@ static int parse_keyword(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { return ret->token; } + +/** Initializes a new scanner for the given file */ fastd_lex_t* fastd_lex_init(FILE *file) { fastd_lex_t *lex = calloc(1, sizeof(fastd_lex_t)); lex->file = file; @@ -423,10 +452,12 @@ fastd_lex_t* fastd_lex_init(FILE *file) { return lex; } +/** Destroys the scanner */ void fastd_lex_destroy(fastd_lex_t *lex) { free(lex); } +/** Returns a single lexeme of the scanned file */ int fastd_lex(YYSTYPE *yylval, YYLTYPE *yylloc, fastd_lex_t *lex) { int token; @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Config scanner for the fastd configuration file format +*/ + #pragma once @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Logging function implementations +*/ + #include "fastd.h" #include "peer.h" @@ -32,6 +38,7 @@ #include <net/if.h> +/** snprintf wrapper always returning the number of bytes written */ static inline size_t snprintf_safe(char *buffer, size_t size, const char *format, ...) { va_list ap; va_start(ap, format); @@ -44,6 +51,7 @@ static inline size_t snprintf_safe(char *buffer, size_t size, const char *format return min_size_t(ret, size); } +/** Creates a string representation of a peer address */ static size_t snprint_peer_address(char *buffer, size_t size, const fastd_peer_address_t *address, const char *iface, bool bind_address) { char addr_buf[INET6_ADDRSTRLEN] = ""; @@ -83,6 +91,7 @@ static size_t snprint_peer_address(char *buffer, size_t size, const fastd_peer_a } } +/** Creates a string representation of a peer */ static size_t snprint_peer_str(char *buffer, size_t size, const fastd_peer_t *peer) { if (peer->config && peer->config->name) { return snprintf_safe(buffer, size, "<%s>", peer->config->name); @@ -96,6 +105,7 @@ static size_t snprint_peer_str(char *buffer, size_t size, const fastd_peer_t *pe } } +/** vsnprintf-like function using different conversion specifiers */ static int fastd_vsnprintf(char *buffer, size_t size, const char *format, va_list ap) { char *buffer_start = buffer; char *buffer_end = buffer+size; @@ -190,6 +200,7 @@ static int fastd_vsnprintf(char *buffer, size_t size, const char *format, va_lis return buffer-buffer_start; } +/** Returns a prefix string to use for log messages of a specified level */ static inline const char* get_log_prefix(fastd_loglevel_t log_level) { switch(log_level) { case LL_FATAL: @@ -211,6 +222,7 @@ static inline const char* get_log_prefix(fastd_loglevel_t log_level) { } } +/** Converts fastd log levels to syslog levels */ static inline int get_syslog_level(fastd_loglevel_t log_level) { switch(log_level) { case LL_FATAL: @@ -228,6 +240,7 @@ static inline int get_syslog_level(fastd_loglevel_t log_level) { } } +/** printf-like function handling different conversion specifiers and using the configured log destinations */ void fastd_logf(fastd_loglevel_t level, const char *format, ...) { char buffer[1024]; char timestr[100] = ""; diff --git a/src/methods/cipher_test/cipher_test.c b/src/methods/cipher_test/cipher_test.c index 52bca0f..7e064ba 100644 --- a/src/methods/cipher_test/cipher_test.c +++ b/src/methods/cipher_test/cipher_test.c @@ -23,25 +23,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + cipher-test method provider (testing and benchmarking only) + + The cipher-test method provider performs encryption only and can be used to test + and benchmark cipher implementations. +*/ + #include "../../crypto.h" #include "../../method.h" #include "../common.h" +/** A specific method provided by this provider */ struct fastd_method { - const fastd_cipher_info_t *cipher_info; + const fastd_cipher_info_t *cipher_info; /**< The cipher used */ }; +/** The method-specific session state */ struct fastd_method_session_state { - fastd_method_common_t common; + fastd_method_common_t common; /**< The common method state */ - const fastd_method_t *method; - const fastd_cipher_t *cipher; - fastd_cipher_state_t *cipher_state; + const fastd_method_t *method; /**< The specific method used */ + const fastd_cipher_t *cipher; /**< The cipher implementation used */ + fastd_cipher_state_t *cipher_state; /**< The cipher state */ }; +/** Instanciates a method using a name of the pattern "<cipher>+cipher-test" */ static bool method_create_by_name(const char *name, fastd_method_t **method) { fastd_method_t m; @@ -66,14 +78,17 @@ static bool method_create_by_name(const char *name, fastd_method_t **method) { return true; } +/** Frees a method */ static void method_destroy(fastd_method_t *method) { free(method); } +/** Returns the key length used by a method */ static size_t method_key_length(const fastd_method_t *method) { return method->cipher_info->key_length; } +/** Initializes a session */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -87,22 +102,27 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Checks if the session is currently valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(&session->common)); } +/** Checks if this side is the initator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return fastd_method_session_common_is_initiator(&session->common); } +/** Checks if the session should be refreshed */ static bool method_session_want_refresh(fastd_method_session_state_t *session) { return fastd_method_session_common_want_refresh(&session->common); } +/** Marks the session as superseded */ static void method_session_superseded(fastd_method_session_state_t *session) { fastd_method_session_common_superseded(&session->common); } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { if (session) { session->cipher->free(session->cipher_state); @@ -110,6 +130,8 @@ static void method_session_free(fastd_method_session_state_t *session) { } } + +/** Encrypts a packet and adds the common method header */ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { size_t tail_len = alignto(in.len, sizeof(fastd_block128_t))-in.len; *out = fastd_buffer_alloc(in.len, alignto(COMMON_HEADBYTES, 16), sizeof(fastd_block128_t)+tail_len); @@ -140,6 +162,7 @@ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state return true; } +/** 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) { if (in.len < COMMON_HEADBYTES) return false; @@ -184,6 +207,8 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses return true; } + +/** The cipher-test method provider */ const fastd_method_provider_t fastd_method_cipher_test = { .max_overhead = COMMON_HEADBYTES, .min_encrypt_head_space = 0, diff --git a/src/methods/composed_gmac/composed_gmac.c b/src/methods/composed_gmac/composed_gmac.c index 887fb5c..6636e49 100644 --- a/src/methods/composed_gmac/composed_gmac.c +++ b/src/methods/composed_gmac/composed_gmac.c @@ -23,37 +23,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + composed-gmac method provider + + composed-gmac combines any cipher (or null) with GMAC, while another cipher is + used to generate the GHASH keys. Combining the null cipher with GMAC allows creating + unencrypted, authenticated-only methods. +*/ + #include "../../crypto.h" #include "../../method.h" #include "../common.h" +/** A block of zeros */ static const fastd_block128_t ZERO_BLOCK = {}; +/** A specific method provided by this provider */ struct fastd_method { - const fastd_cipher_info_t *cipher_info; - const fastd_cipher_info_t *gmac_cipher_info; - const fastd_mac_info_t *ghash_info; + const fastd_cipher_info_t *cipher_info; /**< The cipher used for encryption */ + const fastd_cipher_info_t *gmac_cipher_info; /**< The cipher used for authenticaton */ + const fastd_mac_info_t *ghash_info; /**< GHASH */ }; +/** The method-specific session state */ struct fastd_method_session_state { - fastd_method_common_t common; + fastd_method_common_t common; /**< The common method state */ - const fastd_method_t *method; + const fastd_method_t *method; /**< The specific method used */ - const fastd_cipher_t *cipher; - fastd_cipher_state_t *cipher_state; + const fastd_cipher_t *cipher; /**< The cipher implementation used for encryption */ + fastd_cipher_state_t *cipher_state; /**< The cipher state for encryption */ - const fastd_cipher_t *gmac_cipher; - fastd_cipher_state_t *gmac_cipher_state; + const fastd_cipher_t *gmac_cipher; /**< The cipher implementation used for authentication */ + fastd_cipher_state_t *gmac_cipher_state; /**< The cipher state for authentication */ - const fastd_mac_t *ghash; - fastd_mac_state_t *ghash_state; + const fastd_mac_t *ghash; /**< The GHASH implementation */ + fastd_mac_state_t *ghash_state; /**< The GHASH state */ }; +/** Instanciates a method using a name of the pattern "<cipher>+<cipher>+gmac" (or "<cipher>+<cipher>-gmac" for block ciphers in counter mode, e.g. null+aes128-gmac instead of null+aes128-ctr+gmac) */ static bool method_create_by_name(const char *name, fastd_method_t **method) { fastd_method_t m; @@ -107,15 +121,17 @@ static bool method_create_by_name(const char *name, fastd_method_t **method) { return true; } +/** Frees a method */ static void method_destroy(fastd_method_t *method) { free(method); } - +/** Returns the key length used by a method */ static size_t method_key_length(const fastd_method_t *method) { return method->cipher_info->key_length + method->gmac_cipher_info->key_length; } +/** Initializes a session */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -148,22 +164,27 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Checks if the session is currently valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(&session->common)); } +/** Checks if this side is the initator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return fastd_method_session_common_is_initiator(&session->common); } +/** Checks if the session should be refreshed */ static bool method_session_want_refresh(fastd_method_session_state_t *session) { return fastd_method_session_common_want_refresh(&session->common); } +/** Marks the session as superseded */ static void method_session_superseded(fastd_method_session_state_t *session) { fastd_method_session_common_superseded(&session->common); } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { if (session) { session->cipher->free(session->cipher_state); @@ -174,6 +195,7 @@ static void method_session_free(fastd_method_session_state_t *session) { } } +/** Writes the size of the input in bits to a block (in a way different from the generic-gmac methods) */ static inline void put_size(fastd_block128_t *out, size_t len) { memset(out, 0, sizeof(fastd_block128_t)); out->b[3] = len >> 29; @@ -183,6 +205,7 @@ static inline void put_size(fastd_block128_t *out, size_t len) { out->b[7] = len << 3; } +/** Encrypts and authenticates a packet */ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { size_t tail_len = alignto(in.len, sizeof(fastd_block128_t))-in.len; *out = fastd_buffer_alloc(sizeof(fastd_block128_t)+in.len, alignto(COMMON_HEADBYTES, 16), sizeof(fastd_block128_t)+tail_len); @@ -232,6 +255,7 @@ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state return true; } +/** 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) { if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t)) return false; @@ -294,6 +318,8 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses return true; } + +/** The composed-gmac method provider */ const fastd_method_provider_t fastd_method_composed_gmac = { .max_overhead = COMMON_HEADBYTES + sizeof(fastd_block128_t), .min_encrypt_head_space = 0, diff --git a/src/methods/generic_gmac/generic_gmac.c b/src/methods/generic_gmac/generic_gmac.c index 6b84a95..546cd50 100644 --- a/src/methods/generic_gmac/generic_gmac.c +++ b/src/methods/generic_gmac/generic_gmac.c @@ -23,30 +23,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + generic-gmac method provider + + generic-gmac can combine any stream cipher with the GMAC authentication. +*/ + #include "../../crypto.h" #include "../../method.h" #include "../common.h" +/** A specific method provided by this provider */ struct fastd_method { - const fastd_cipher_info_t *cipher_info; - const fastd_mac_info_t *ghash_info; + const fastd_cipher_info_t *cipher_info; /**< The cipher used */ + const fastd_mac_info_t *ghash_info; /**< GHASH */ }; +/** The method-specific session state */ struct fastd_method_session_state { - fastd_method_common_t common; + fastd_method_common_t common; /**< The common method state */ - const fastd_method_t *method; + const fastd_method_t *method; /**< The specific method used */ - const fastd_cipher_t *cipher; - fastd_cipher_state_t *cipher_state; + const fastd_cipher_t *cipher; /**< The cipher implementation used */ + fastd_cipher_state_t *cipher_state; /**< The cipher state */ - const fastd_mac_t *ghash; - fastd_mac_state_t *ghash_state; + const fastd_mac_t *ghash; /**< The GHASH implementation */ + fastd_mac_state_t *ghash_state; /**< The GHASH state */ }; +/** Instanciates a method using a name of the pattern "<cipher>+gmac" (or "<cipher>-gcm" for block ciphers in counter mode, e.g. aes128-gcm instead of aes128-ctr+gmac) */ static bool method_create_by_name(const char *name, fastd_method_t **method) { fastd_method_t m; @@ -85,14 +96,17 @@ static bool method_create_by_name(const char *name, fastd_method_t **method) { return true; } +/** Frees a method */ static void method_destroy(fastd_method_t *method) { free(method); } +/** Returns the key length used by a method */ static size_t method_key_length(const fastd_method_t *method) { return method->cipher_info->key_length; } +/** Initializes a session */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -121,22 +135,27 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Checks if the session is currently valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(&session->common)); } +/** Checks if this side is the initator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return fastd_method_session_common_is_initiator(&session->common); } +/** Checks if the session should be refreshed */ static bool method_session_want_refresh(fastd_method_session_state_t *session) { return fastd_method_session_common_want_refresh(&session->common); } +/** Marks the session as superseded */ static void method_session_superseded(fastd_method_session_state_t *session) { fastd_method_session_common_superseded(&session->common); } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { if (session) { session->cipher->free(session->cipher_state); @@ -146,6 +165,7 @@ static void method_session_free(fastd_method_session_state_t *session) { } } +/** Writes the size of the input in bits to a block */ static inline void put_size(fastd_block128_t *out, size_t len) { memset(out, 0, sizeof(fastd_block128_t)); out->b[11] = len >> 29; @@ -155,6 +175,8 @@ static inline void put_size(fastd_block128_t *out, size_t len) { out->b[15] = len << 3; } + +/** Encrypts and authenticates a packet */ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { fastd_buffer_pull_head_zero(&in, sizeof(fastd_block128_t)); @@ -199,6 +221,7 @@ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state return true; } +/** 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) { if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t)) return false; @@ -255,6 +278,8 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses return true; } + +/** The generic-gmac method provider */ const fastd_method_provider_t fastd_method_generic_gmac = { .max_overhead = COMMON_HEADBYTES + sizeof(fastd_block128_t), .min_encrypt_head_space = sizeof(fastd_block128_t), diff --git a/src/methods/generic_poly1305/generic_poly1305.c b/src/methods/generic_poly1305/generic_poly1305.c index 0e2641c..142b50e 100644 --- a/src/methods/generic_poly1305/generic_poly1305.c +++ b/src/methods/generic_poly1305/generic_poly1305.c @@ -23,6 +23,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + generic-poly1305 method provider + + The Poly1305 authenticator is very secure, but for performance reasons + not really recommendable on embedded systems. +*/ + #include "../../crypto.h" #include "../../method.h" @@ -31,23 +40,29 @@ #include <crypto_onetimeauth_poly1305.h> +/** The length of the key used by Poly1305 */ #define KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES + +/** The length of the authentication tag */ #define TAGBYTES crypto_onetimeauth_poly1305_BYTES +/** A specific method provided by this provider */ struct fastd_method { - const fastd_cipher_info_t *cipher_info; + const fastd_cipher_info_t *cipher_info; /**< The cipher used */ }; +/** The method-specific session state */ struct fastd_method_session_state { - fastd_method_common_t common; + fastd_method_common_t common; /**< The common method state */ - const fastd_method_t *method; - const fastd_cipher_t *cipher; - fastd_cipher_state_t *cipher_state; + const fastd_method_t *method; /**< The specific method used */ + const fastd_cipher_t *cipher; /**< The cipher implementation used */ + fastd_cipher_state_t *cipher_state; /**< The cipher state */ }; +/** Instanciates a method using a name of the pattern "<cipher>+poly1305" */ static bool method_create_by_name(const char *name, fastd_method_t **method) { fastd_method_t m; @@ -75,14 +90,17 @@ static bool method_create_by_name(const char *name, fastd_method_t **method) { return true; } +/** Frees a method */ static void method_destroy(fastd_method_t *method) { free(method); } +/** Returns the key length used by a method */ static size_t method_key_length(const fastd_method_t *method) { return method->cipher_info->key_length; } +/** Initializes a session */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -94,22 +112,27 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Checks if the session is currently valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(&session->common)); } +/** Checks if this side is the initator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return fastd_method_session_common_is_initiator(&session->common); } +/** Checks if the session should be refreshed */ static bool method_session_want_refresh(fastd_method_session_state_t *session) { return fastd_method_session_common_want_refresh(&session->common); } +/** Marks the session as superseded */ static void method_session_superseded(fastd_method_session_state_t *session) { fastd_method_session_common_superseded(&session->common); } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { if (session) { session->cipher->free(session->cipher_state); @@ -117,6 +140,8 @@ static void method_session_free(fastd_method_session_state_t *session) { } } + +/** Encrypts and authenticates a packet */ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { fastd_buffer_pull_head_zero(&in, KEYBYTES); @@ -155,6 +180,7 @@ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state return true; } +/** 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) { if (in.len < COMMON_HEADBYTES+TAGBYTES) return false; @@ -217,6 +243,8 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses return true; } + +/** The generic-poly1305 method provider */ const fastd_method_provider_t fastd_method_generic_poly1305 = { .max_overhead = COMMON_HEADBYTES + TAGBYTES, .min_encrypt_head_space = KEYBYTES, diff --git a/src/methods/methods.c.in b/src/methods/methods.c.in index 914d929..672ef70 100644 --- a/src/methods/methods.c.in +++ b/src/methods/methods.c.in @@ -23,16 +23,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Generated list of supported method providers +*/ + #include <src/method.h> @METHOD_DEFINITIONS@ +/** The list of method providers */ static const fastd_method_provider_t *const providers[] = { @METHOD_LIST@ }; +/** Searches for a provider providing a method and instanciates it */ bool fastd_method_create_by_name(const char *name, const fastd_method_provider_t **provider, fastd_method_t **method) { size_t i; for (i = 0; i < array_size(providers); i++) { diff --git a/src/methods/null/null.c b/src/methods/null/null.c index 76fd961..3062fcf 100644 --- a/src/methods/null/null.c +++ b/src/methods/null/null.c @@ -23,27 +23,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The null method not providing any encryption or authenticaton +*/ #include "../../method.h" +/** The session state */ struct fastd_method_session_state { - bool valid; - bool initiator; + bool valid; /**< true if the session has not been invalidated */ + bool initiator; /**< true if this side is the initiator of the session */ }; +/** Returns true if the name is "null" */ static bool method_create_by_name(const char *name, fastd_method_t **method UNUSED) { return !strcmp(name, "null"); } +/** Does nothing as the null provider provides only a single method */ static void method_destroy(fastd_method_t *method UNUSED) { } +/** Returns 0 */ static size_t method_key_length(const fastd_method_t *method UNUSED) { return 0; } +/** Initiates a new null session */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method UNUSED, const uint8_t *secret UNUSED, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -53,35 +63,49 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Initiates a new null session (pre-v11 compat handshake) */ static fastd_method_session_state_t* method_session_init_compat(const fastd_method_t *method, const uint8_t *secret, size_t length UNUSED, bool initiator) { return method_session_init(method, secret, initiator); } +/** Checks if the session is valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && session->valid); } +/** Checks if this side is the initiator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return (session->initiator); } +/** Returns false */ static bool method_session_want_refresh(fastd_method_session_state_t *session UNUSED) { return false; } +/** + Marks the session as invalid + + The session in invalidated without any delay to prevent packets of the new session being + mistaken to be valid for the old session +*/ static void method_session_superseded(fastd_method_session_state_t *session) { session->valid = false; } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { free(session); } +/** Just returns the input buffer as the output */ static bool method_passthrough(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session UNUSED, fastd_buffer_t *out, fastd_buffer_t in) { *out = in; return true; } + +/** The null method provider */ const fastd_method_provider_t fastd_method_null = { .max_overhead = 0, .min_encrypt_head_space = 0, diff --git a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c index f06e0f8..9f2d61c 100644 --- a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c +++ b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c @@ -23,6 +23,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + The xsalsa20-poly1305 method provider (deprecated) + + This provider is included for compatiblity reasons as pre-v11 + xsalsa20-poly1305 was the recommended method. In new setups salsa20+poly1305 + provided by the generic-poly1305 provider should be used as a replacement. +*/ + #include "../../crypto.h" #include "../../method.h" @@ -31,24 +41,29 @@ #include <crypto_secretbox_xsalsa20poly1305.h> +/** The session state */ struct fastd_method_session_state { - fastd_method_common_t common; + fastd_method_common_t common; /**< The common method state */ - uint8_t key[crypto_secretbox_xsalsa20poly1305_KEYBYTES] __attribute__((aligned(8))); + uint8_t key[crypto_secretbox_xsalsa20poly1305_KEYBYTES] __attribute__((aligned(8))); /**< The encryption key */ }; +/** Matches the method name "xsalsa20-poly1305" */ static bool method_create_by_name(const char *name, fastd_method_t **method UNUSED) { return !strcmp(name, "xsalsa20-poly1305"); } +/** Does nothing as this provider has only a single method */ static void method_destroy(fastd_method_t *method UNUSED) { } +/** Returns the key length used by xsalsa20-poly1305 */ static size_t method_key_length(const fastd_method_t *method UNUSED) { return crypto_secretbox_xsalsa20poly1305_KEYBYTES; } +/** Initializes the session state */ static fastd_method_session_state_t* method_session_init(const fastd_method_t *method UNUSED, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); @@ -59,6 +74,7 @@ static fastd_method_session_state_t* method_session_init(const fastd_method_t *m return session; } +/** Initializes the session state (pre-v11 compat handshake) */ static fastd_method_session_state_t* method_session_init_compat(const fastd_method_t *method, const uint8_t *secret, size_t length, bool initiator) { if (length < crypto_secretbox_xsalsa20poly1305_KEYBYTES) exit_bug("xsalsa20-poly1305: tried to init with short secret"); @@ -66,22 +82,27 @@ static fastd_method_session_state_t* method_session_init_compat(const fastd_meth return method_session_init(method, secret, initiator); } +/** Checks if a session is currently valid */ static bool method_session_is_valid(fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(&session->common)); } +/** Checks if this side is the initiator of the session */ static bool method_session_is_initiator(fastd_method_session_state_t *session) { return fastd_method_session_common_is_initiator(&session->common); } +/** Checks if the session should be refreshed */ static bool method_session_want_refresh(fastd_method_session_state_t *session) { return fastd_method_session_common_want_refresh(&session->common); } +/** Marks the session as superseded */ static void method_session_superseded(fastd_method_session_state_t *session) { fastd_method_session_common_superseded(&session->common); } +/** Frees the session state */ static void method_session_free(fastd_method_session_state_t *session) { if(session) { secure_memzero(session, sizeof(fastd_method_session_state_t)); @@ -90,12 +111,19 @@ static void method_session_free(fastd_method_session_state_t *session) { } +/** + Copies a nonce of length COMMON_NONCEBYTES to a buffer, reversing its byte order + + To maintain compability with pre-v11 versions, which used a little-endian nonce, + the xsalsa20-poly1305 keeps using the old nonce format. +*/ static inline void memcpy_nonce(uint8_t *dst, const uint8_t *src) { size_t i; for (i = 0; i < COMMON_NONCEBYTES; i++) dst[i] = src[COMMON_NONCEBYTES-i-1]; } +/** Adds the xsalsa20-poly1305 header to the head of a packet */ static inline void put_header(fastd_buffer_t *buffer, const uint8_t nonce[COMMON_NONCEBYTES], uint8_t flags) { fastd_buffer_pull_head_from(buffer, &flags, 1); @@ -103,19 +131,22 @@ static inline void put_header(fastd_buffer_t *buffer, const uint8_t nonce[COMMON memcpy_nonce(buffer->data, nonce); } +/** Removes the xsalsa20-poly1305 header from the head of a packet */ static inline void take_header(fastd_buffer_t *buffer, uint8_t nonce[COMMON_NONCEBYTES], uint8_t *flags) { - memcpy_nonce(nonce, buffer->data ); + memcpy_nonce(nonce, buffer->data); fastd_buffer_push_head(buffer, COMMON_NONCEBYTES); fastd_buffer_push_head_to(buffer, flags, 1); } +/** Removes and handles the xsalsa20-poly1305 header from the head of a packet */ static inline bool handle_header(const fastd_method_common_t *session, fastd_buffer_t *buffer, uint8_t nonce[COMMON_NONCEBYTES], uint8_t *flags, int64_t *age) { take_header(buffer, nonce, flags); return fastd_method_is_nonce_valid(session, nonce, age); } +/** Performs encryption and authentication of a packet */ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { fastd_buffer_pull_head_zero(&in, crypto_secretbox_xsalsa20poly1305_ZEROBYTES); @@ -135,6 +166,7 @@ static bool method_encrypt(fastd_peer_t *peer UNUSED, fastd_method_session_state return true; } +/** 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) { if (in.len < COMMON_HEADBYTES) return false; @@ -180,6 +212,7 @@ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *ses } +/** The xsalsa20-poly1305 method provider */ const fastd_method_provider_t fastd_method_xsalsa20_poly1305 = { .max_overhead = COMMON_HEADBYTES + crypto_secretbox_xsalsa20poly1305_ZEROBYTES - crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES, diff --git a/src/options.c b/src/options.c index 2a84a06..7ac026e 100644 --- a/src/options.c +++ b/src/options.c @@ -23,6 +23,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Handling of command line options + + + \def OPTION + Defines a command line option without argument + + \def OPTION_ARG + Defines a command line option with an argument + + \def OR + Separates multiple alternative options with the same meaning + + \def SEPARATOR + Separates groups of related options +*/ + #include "fastd.h" #include "config.h" @@ -32,6 +51,7 @@ #include <arpa/inet.h> +/** Prints the usage message for a single command line option */ static void print_usage(const char *options, const char *message) { /* 28 spaces */ static const char spaces[] = {[0 ... 27] = ' ', [28] = 0}; @@ -48,6 +68,8 @@ static void print_usage(const char *options, const char *message) { puts(message); } + +/** Prints the usage message and exits */ static void usage(void) { puts("fastd (Fast and Secure Tunnelling Daemon) " FASTD_VERSION " usage:\n"); @@ -64,21 +86,27 @@ static void usage(void) { exit(0); } + + +/** Prints fastd's version and exits */ static void version(void) { puts("fastd " FASTD_VERSION); exit(0); } +/** Handles the --daemon option */ static void option_daemon(void) { conf.daemon = true; } +/** Handles the --pid-file option */ static void option_pid_file(const char *arg) { free(conf.pid_file); conf.pid_file = strdup(arg); } +/** Handles the --config option */ static void option_config(const char *arg) { if (!strcmp(arg, "-")) arg = NULL; @@ -87,6 +115,7 @@ static void option_config(const char *arg) { exit(1); } +/** Handles the --config-peer option */ static void option_config_peer(const char *arg) { fastd_peer_config_new(); @@ -94,6 +123,7 @@ static void option_config_peer(const char *arg) { exit(1); } +/** Handles the --config-peer-dir option */ static void option_config_peer_dir(const char *arg) { fastd_add_peer_dir(arg); } @@ -101,11 +131,13 @@ static void option_config_peer_dir(const char *arg) { #ifdef WITH_CMDLINE_USER +/** Handles the --config-user option */ static void option_user(const char *arg) { free(conf.user); conf.user = strdup(arg); } +/** Handles the --config-group option */ static void option_group(const char *arg) { free(conf.group); conf.group = strdup(arg); @@ -115,6 +147,7 @@ static void option_group(const char *arg) { #ifdef WITH_CMDLINE_LOGGING +/** Parses a log level argument */ static int parse_log_level(const char *arg) { if (!strcmp(arg, "fatal")) return LL_FATAL; @@ -134,23 +167,28 @@ static int parse_log_level(const char *arg) { exit_error("invalid log level `%s'", arg); } +/** Handles the --log-level option */ static void option_log_level(const char *arg) { conf.log_stderr_level = parse_log_level(arg); } +/** Handles the --syslog-level option */ static void option_syslog_level(const char *arg) { conf.log_syslog_level = parse_log_level(arg); } +/** Handles the --syslog-ident option */ static void option_syslog_ident(const char *arg) { free(conf.log_syslog_ident); conf.log_syslog_ident = strdup(arg); } +/** Handles the --hide-ip-addresses option */ static void option_hide_ip_addresses(void) { conf.hide_ip_addresses = true; } +/** Handles the --hide-mac-addresses option */ static void option_hide_mac_addresses(void) { conf.hide_mac_addresses = true; } @@ -159,6 +197,7 @@ static void option_hide_mac_addresses(void) { #ifdef WITH_CMDLINE_OPERATION +/** Handles the --mode option */ static void option_mode(const char *arg) { if (!strcmp(arg, "tap")) conf.mode = MODE_TAP; @@ -168,11 +207,13 @@ static void option_mode(const char *arg) { exit_error("invalid mode `%s'", arg); } +/** Handles the --interface option */ static void option_interface(const char *arg) { free(conf.ifname); conf.ifname = strdup(arg); } +/** Handles the --mtu option */ static void option_mtu(const char *arg) { char *endptr; long mtu = strtol(arg, &endptr, 10); @@ -183,6 +224,7 @@ static void option_mtu(const char *arg) { conf.mtu = mtu; } +/** Handles the --bind option */ static void option_bind(const char *arg) { long l; char *charptr; @@ -253,14 +295,17 @@ static void option_bind(const char *arg) { fastd_config_bind_address(&addr, ifname, false, false); } +/** Handles the --protocol option */ static void option_protocol(const char *arg) { fastd_config_protocol(arg); } +/** Handles the --method option */ static void option_method(const char *arg) { fastd_config_method(arg); } +/** Handles the --forward option */ static void option_forward(void) { conf.forward = true; } @@ -269,36 +314,44 @@ static void option_forward(void) { #ifdef WITH_CMDLINE_COMMANDS +/** Handles the --on-pre-up option */ static void option_on_pre_up(const char *arg) { fastd_shell_command_set(&conf.on_pre_up, arg, true); } +/** Handles the --on-up option */ static void option_on_up(const char *arg) { fastd_shell_command_set(&conf.on_up, arg, true); } +/** Handles the --on-down option */ static void option_on_down(const char *arg) { fastd_shell_command_set(&conf.on_down, arg, true); } +/** Handles the --on-post-down option */ static void option_on_post_down(const char *arg) { fastd_shell_command_set(&conf.on_post_down, arg, true); } +/** Handles the --on-connect option */ static void option_on_connect(const char *arg) { fastd_shell_command_set(&conf.on_connect, arg, false); } +/** Handles the --on-establish option */ static void option_on_establish(const char *arg) { fastd_shell_command_set(&conf.on_establish, arg, false); } +/** Handles the --on-disestablish option */ static void option_on_disestablish(const char *arg) { fastd_shell_command_set(&conf.on_disestablish, arg, false); } #ifdef WITH_VERIFY +/** Handles the --on-verify option */ static void option_on_verify(const char *arg) { fastd_shell_command_set(&conf.on_verify, arg, false); } @@ -307,25 +360,30 @@ static void option_on_verify(const char *arg) { #endif +/** Handles the --verify-config option */ static void option_verify_config(void) { conf.verify_config = true; } +/** Handles the --generate-key option */ static void option_generate_key(void) { conf.generate_key = true; conf.show_key = false; } +/** Handles the --show-key option */ static void option_show_key(void) { conf.generate_key = false; conf.show_key = true; } +/** Handles the --machine-readable option */ static void option_machine_readable(void) { conf.machine_readable = true; } +/** Matches a command line options agains a NULL-terminated list of arguments */ static bool config_match(const char *opt, ...) { va_list ap; bool match = false; @@ -345,6 +403,7 @@ static bool config_match(const char *opt, ...) { return match; } +/** Parses and handles the supplied command line options */ void fastd_config_handle_options(int argc, char *const argv[]) { int i = 1; diff --git a/src/peer_hashtable.c b/src/peer_hashtable.c index 003a16c..475d7f9 100644 --- a/src/peer_hashtable.c +++ b/src/peer_hashtable.c @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + A hashtable allowing fast lookup from an IP address to a peer +*/ + #include "peer_hashtable.h" #include "fastd.h" @@ -30,9 +36,11 @@ #include "peer.h" +/** The number of hash buckets used */ #define PEER_ADDR_HT_SIZE 64 +/** Initializes the hashtable */ void fastd_peer_hashtable_init(void) { fastd_random_bytes(&ctx.peer_addr_ht_seed, sizeof(ctx.peer_addr_ht_seed), false); @@ -43,6 +51,7 @@ void fastd_peer_hashtable_init(void) { VECTOR_ALLOC(ctx.peer_addr_ht[i], 0); } +/** Frees the resources used by the hashtable */ void fastd_peer_hashtable_free(void) { size_t i; for (i = 0; i < PEER_ADDR_HT_SIZE; i++) @@ -51,6 +60,7 @@ void fastd_peer_hashtable_free(void) { free(ctx.peer_addr_ht); } +/** Gets the hash bucket used for an address */ static size_t peer_address_bucket(const fastd_peer_address_t *addr) { uint32_t hash = ctx.peer_addr_ht_seed; @@ -72,11 +82,21 @@ static size_t peer_address_bucket(const fastd_peer_address_t *addr) { return hash % PEER_ADDR_HT_SIZE; } +/** + Inserts a peer into the hash table + + The peer address must not change while the peer is part of the table. +*/ void fastd_peer_hashtable_insert(fastd_peer_t *peer) { size_t b = peer_address_bucket(&peer->address); VECTOR_ADD(ctx.peer_addr_ht[b], peer); } +/** + Removes a peer from the hash table + + A peer must be removed from the table before it is deleted or its address is changed. +*/ void fastd_peer_hashtable_remove(fastd_peer_t *peer) { if (!peer->address.sa.sa_family) return; @@ -92,6 +112,7 @@ void fastd_peer_hashtable_remove(fastd_peer_t *peer) { } } +/** Looks up a peer in the hashtable */ fastd_peer_t *fastd_peer_hashtable_lookup(const fastd_peer_address_t *addr) { size_t b = peer_address_bucket(addr); diff --git a/src/peer_hashtable.h b/src/peer_hashtable.h index 6c026bc..fae2075 100644 --- a/src/peer_hashtable.h +++ b/src/peer_hashtable.h @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + A hashtable allowing fast lookup from an IP address to a peer +*/ + #pragma once diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c index b97bf4d..86acbec 100644 --- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c +++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + ec25519-fhmqvc protocol: basic functions +*/ + #include "ec25519_fhmqvc.h" diff --git a/src/protocols/ec25519_fhmqvc/handshake.c b/src/protocols/ec25519_fhmqvc/handshake.c index c29b7b1..7374061 100644 --- a/src/protocols/ec25519_fhmqvc/handshake.c +++ b/src/protocols/ec25519_fhmqvc/handshake.c @@ -23,6 +23,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + ec25519-fhmqvc protocol: handshake handling +*/ #include "handshake.h" #include "../../handshake.h" @@ -30,6 +35,7 @@ #include "../../verify.h" +/** The size of the hash outputs used in the handshake */ #define HASHBYTES FASTD_SHA256_HASH_BYTES @@ -42,13 +48,33 @@ #endif +/** TLV field: sender public key */ #define RECORD_SENDER_KEY RECORD_PROTOCOL1 -#define RECORD_RECEIPIENT_KEY RECORD_PROTOCOL2 + +/** TLV field: recipient public key */ +#define RECORD_RECIPIENT_KEY RECORD_PROTOCOL2 + +/** TLV field: sender ephemeral public key */ #define RECORD_SENDER_HANDSHAKE_KEY RECORD_PROTOCOL3 -#define RECORD_RECEIPIENT_HANDSHAKE_KEY RECORD_PROTOCOL4 + +/** TLV field: recipient ephemeral public key */ +#define RECORD_RECIPIENT_HANDSHAKE_KEY RECORD_PROTOCOL4 + +/** + TLV field: pre-v11 compat handshake MAC + + The pre-v11 handshake protocol only secured the four key fields + of the handshake with a MAC, which allowed manipulation of other fields like + the method list; it was replaced by the RECORD_TLV_MAC field in the new + handshake protocol. + + In pre-v11 compat mode fastd ("secure handshakes no") will include both the old and the new + record in the handshake. +*/ #define RECORD_T RECORD_PROTOCOL5 +/** Derives a key of arbitraty length from the shared key material after a handshake using the HKDF algorithm */ static void derive_key(fastd_sha256_t *out, size_t blocks, const uint32_t *salt, const char *method_name, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, const aligned_int256_t *sigma) { @@ -67,6 +93,7 @@ static void derive_key(fastd_sha256_t *out, size_t blocks, const uint32_t *salt, fastd_hkdf_sha256_expand(out, blocks, &prk, info, sizeof(info)); } +/** Marks the active session as superseded and moves it to the \e old_session field of the protocol peer state */ static inline void supersede_session(fastd_peer_t *peer, const fastd_method_info_t *method) { if (is_session_valid(&peer->protocol_state->session) && !is_session_valid(&peer->protocol_state->old_session)) { if (peer->protocol_state->old_session.method) @@ -90,6 +117,7 @@ static inline void supersede_session(fastd_peer_t *peer, const fastd_method_info } } +/** Initalizes a new session with a peer using a specified method */ static inline bool new_session(fastd_peer_t *peer, const fastd_method_info_t *method, bool initiator, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, const aligned_int256_t *sigma, const uint32_t *salt, uint64_t serial) { @@ -120,6 +148,7 @@ static inline bool new_session(fastd_peer_t *peer, const fastd_method_info_t *me return true; } +/** Establishes a connection with a peer after a successful handshake */ static bool establish(fastd_peer_t *peer, const fastd_method_info_t *method, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, bool initiator, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, @@ -143,7 +172,7 @@ static bool establish(fastd_peer_t *peer, const fastd_method_info_t *method, fas } if (!new_session(peer, method, initiator, A, B, X, Y, sigma, salt, serial)) { - pr_error("failed to initialize method session for %P (method `%s'%s)", peer, method->name, salt ? "" : " (compat mode)"); + pr_error("failed to initialize method session for %P (method `%s'%s)", peer, method->name, salt ? "" : ", compat mode"); fastd_peer_reset(peer); return false; } @@ -163,15 +192,18 @@ static bool establish(fastd_peer_t *peer, const fastd_method_info_t *method, fas } +/** Checks if a handshake has a field of a given type and length */ static inline bool has_field(const fastd_handshake_t *handshake, uint8_t type, size_t length) { return (handshake->records[type].length == length); } +/** Checks the handshake has a TLV MAC field, meaning the handshake was sent by fastd v11 or newer */ static inline bool secure_handshake(const fastd_handshake_t *handshake) { return has_field(handshake, RECORD_TLV_MAC, HASHBYTES); } +/** Derives the shares handshake key for computing the MACs used in the handshake */ static bool make_shared_handshake_key(const ecc_int256_t *handshake_key, bool initiator, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, @@ -235,6 +267,7 @@ static bool make_shared_handshake_key(const ecc_int256_t *handshake_key, bool in return true; } +/** Checks if the currently cached shared handshake key is valid and generates a new one otherwise */ static bool update_shared_handshake_key(const fastd_peer_t *peer, const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key) { if (peer->protocol_state->last_handshake_serial == handshake_key->serial) { if (memcmp(&peer->protocol_state->peer_handshake_key, peer_handshake_key, PUBLICKEYBYTES) == 0) @@ -259,6 +292,7 @@ static bool update_shared_handshake_key(const fastd_peer_t *peer, const handshak return true; } +/** Resets the handshake cache for a peer */ static void clear_shared_handshake_key(const fastd_peer_t *peer) { memset(&peer->protocol_state->sigma, 0, sizeof(peer->protocol_state->sigma)); memset(&peer->protocol_state->shared_handshake_key, 0, sizeof(peer->protocol_state->shared_handshake_key)); @@ -268,6 +302,7 @@ static void clear_shared_handshake_key(const fastd_peer_t *peer) { memset(&peer->protocol_state->peer_handshake_key, 0, sizeof(peer->protocol_state->peer_handshake_key)); } +/** Sends a reply to an initial handshake (type 1) */ static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const aligned_int256_t *peer_handshake_key, const fastd_method_info_t *method) { pr_debug("responding handshake with %P[%I]...", peer, remote_addr); @@ -280,9 +315,9 @@ static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_addre fastd_buffer_t buffer = fastd_handshake_new_reply(2, method, true, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES)); fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public); - fastd_handshake_add(&buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); fastd_handshake_add(&buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, &handshake_key->key.public); - fastd_handshake_add(&buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); fastd_sha256_t hmacbuf; @@ -298,6 +333,7 @@ static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_addre fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer); } +/** Sends a reply to a handshake response (type 2) */ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, const fastd_handshake_t *handshake, const fastd_method_info_t *method) { pr_debug("finishing handshake with %P[%I]...", peer, remote_addr); @@ -340,9 +376,9 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l fastd_buffer_t buffer = fastd_handshake_new_reply(3, method, false, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES)); fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public); - fastd_handshake_add(&buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); fastd_handshake_add(&buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, &handshake_key->key.public); - fastd_handshake_add(&buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); if (!compat) { fastd_sha256_t hmacbuf; @@ -359,6 +395,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer); } +/** Handles a reply to a handshake response (type 3) */ static void handle_finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, const fastd_handshake_t *handshake, const fastd_method_info_t *method) { @@ -392,6 +429,7 @@ static void handle_finish_handshake(fastd_socket_t *sock, const fastd_peer_addre clear_shared_handshake_key(peer); } +/** Searches the peer a public key belongs to */ static fastd_peer_t* find_sender_key(const fastd_peer_address_t *address, const unsigned char key[PUBLICKEYBYTES]) { errno = 0; @@ -423,6 +461,7 @@ static fastd_peer_t* find_sender_key(const fastd_peer_address_t *address, const return ret; } +/** Checks if a key matches a peer and searches the correct peer if it doesn't */ static fastd_peer_t* match_sender_key(const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const unsigned char key[PUBLICKEYBYTES]) { errno = 0; @@ -442,6 +481,7 @@ static fastd_peer_t* match_sender_key(const fastd_socket_t *sock, const fastd_pe return find_sender_key(address, key); } +/** Counts how many peers with a key are configured */ static size_t key_count(const unsigned char key[PUBLICKEYBYTES]) { size_t ret = 0; @@ -457,6 +497,7 @@ static size_t key_count(const unsigned char key[PUBLICKEYBYTES]) { return ret; } +/** Validates a peer config */ bool fastd_protocol_ec25519_fhmqvc_peer_check(fastd_peer_config_t *peer_conf) { if (!peer_conf->protocol_config) return false; @@ -474,15 +515,16 @@ bool fastd_protocol_ec25519_fhmqvc_peer_check(fastd_peer_config_t *peer_conf) { return true; } +/** Sends an initial handshake (type 1) to a peer */ void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer) { fastd_protocol_ec25519_fhmqvc_maintenance(); - fastd_buffer_t buffer = fastd_handshake_new_init(3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */); + fastd_buffer_t buffer = fastd_handshake_new_init(3*(4+PUBLICKEYBYTES) /* sender key, recipient key, handshake key */); fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public); if (peer) - fastd_handshake_add(&buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->protocol_config->public_key); else pr_debug("sending handshake to unknown peer %I", remote_addr); @@ -494,6 +536,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fa fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer); } +/** Checks if a temporary peer (added after an on-verify command) can stay after new peers have been configured */ bool fastd_protocol_ec25519_fhmqvc_peer_check_temporary(fastd_peer_t *peer) { if (key_count(peer->protocol_config->public_key.u8)) { char buf[65]; @@ -508,10 +551,12 @@ bool fastd_protocol_ec25519_fhmqvc_peer_check_temporary(fastd_peer_t *peer) { #ifdef WITH_VERIFY +/** Data attached to an asynchronous on-verify run */ typedef struct verify_data { - aligned_int256_t peer_handshake_key; + aligned_int256_t peer_handshake_key; /**< The public key of the peer being verified */ } verify_data_t; +/** Adds a temporary peer for an unknown key */ static fastd_peer_t * add_temporary(fastd_socket_t *sock, const fastd_peer_address_t *addr, const unsigned char key[PUBLICKEYBYTES]) { if (!fastd_allow_verify()) { pr_debug("ignoring handshake from %I (unknown key)", addr); @@ -540,6 +585,7 @@ static fastd_peer_t * add_temporary(fastd_socket_t *sock, const fastd_peer_addre return peer; } +/** Is called when a handshake from a temporary peer is received */ static bool handle_temporary(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method) { if (handshake->type != 1 || !fastd_timed_out(&peer->verify_timeout)) @@ -564,6 +610,7 @@ static bool handle_temporary(fastd_socket_t *sock, const fastd_peer_address_t *l return true; } +/** Handles a reply from an asynchronous on-verify command */ void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *protocol_data, bool ok) { if (!ok) @@ -578,6 +625,7 @@ void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fast #else +/** Dummy add temporary function for fastd versions without on-verify support */ static inline fastd_peer_t * add_temporary(fastd_socket_t *sock UNUSED, const fastd_peer_address_t *addr, const unsigned char key[PUBLICKEYBYTES] UNUSED) { pr_debug("ignoring handshake from %I (unknown key)", addr); return NULL; @@ -586,6 +634,7 @@ static inline fastd_peer_t * add_temporary(fastd_socket_t *sock UNUSED, const fa #endif /* WITH_VERIFY */ +/** Handles a received handshake packet */ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method) { fastd_protocol_ec25519_fhmqvc_maintenance(); @@ -629,9 +678,9 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const return; } - if (has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) { - if (memcmp(&conf.protocol_config->key.public, handshake->records[RECORD_RECEIPIENT_KEY].data, PUBLICKEYBYTES) != 0) { - pr_debug("received protocol handshake with wrong receipient key from %P[%I]", peer, remote_addr); + if (has_field(handshake, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES)) { + if (memcmp(&conf.protocol_config->key.public, handshake->records[RECORD_RECIPIENT_KEY].data, PUBLICKEYBYTES) != 0) { + pr_debug("received protocol handshake with wrong recipient key from %P[%I]", peer, remote_addr); return; } } @@ -661,12 +710,12 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const return; } - if (!has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) { - pr_debug("received handshake reply without receipient key from %P[%I]", peer, remote_addr); + if (!has_field(handshake, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES)) { + pr_debug("recived handshake reply without recipient key from %P[%I]", peer, remote_addr); return; } - if (!has_field(handshake, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES)) { + if (!has_field(handshake, RECORD_RECIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES)) { pr_debug("received handshake reply without receipient handshake key from %P[%I]", peer, remote_addr); return; } @@ -680,15 +729,15 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const handshake_key_t *handshake_key; if (is_handshake_key_valid(&ctx.protocol_state->handshake_key) && - memcmp(&ctx.protocol_state->handshake_key.key.public, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) { + memcmp(&ctx.protocol_state->handshake_key.key.public, handshake->records[RECORD_RECIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) { handshake_key = &ctx.protocol_state->handshake_key; } else if (is_handshake_key_valid(&ctx.protocol_state->prev_handshake_key) && - memcmp(&ctx.protocol_state->prev_handshake_key.key.public, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) { + memcmp(&ctx.protocol_state->prev_handshake_key.key.public, handshake->records[RECORD_RECIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) == 0) { handshake_key = &ctx.protocol_state->prev_handshake_key; } else { - pr_debug("received handshake reply with unexpected receipient handshake key from %P[%I]", peer, remote_addr); + pr_debug("received handshake reply with unexpected recipient handshake key from %P[%I]", peer, remote_addr); return; } diff --git a/src/protocols/ec25519_fhmqvc/state.c b/src/protocols/ec25519_fhmqvc/state.c index f20b381..451e31d 100644 --- a/src/protocols/ec25519_fhmqvc/state.c +++ b/src/protocols/ec25519_fhmqvc/state.c @@ -23,11 +23,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + ec25519-fhmqvc protocol: state handling +*/ + #include "handshake.h" #include "../../crypto.h" +/** Allocates the protocol-specific state */ static void init_protocol_state(void) { if (!ctx.protocol_state) { ctx.protocol_state = calloc(1, sizeof(fastd_protocol_state_t)); @@ -37,6 +44,7 @@ static void init_protocol_state(void) { } } +/** Generates a new ephemeral keypair */ static void new_handshake_key(keypair_t *key) { fastd_random_bytes(key->secret.p, SECRETKEYBYTES, false); ecc_25519_gf_sanitize_secret(&key->secret, &key->secret); @@ -46,6 +54,12 @@ static void new_handshake_key(keypair_t *key) { ecc_25519_store_packed(&key->public.int256, &work); } +/** + Performs maintenance tasks on the protocol state + + If there is currently no preferred ephemeral keypair, a new one + will be generated. +*/ void fastd_protocol_ec25519_fhmqvc_maintenance(void) { init_protocol_state(); @@ -63,6 +77,7 @@ void fastd_protocol_ec25519_fhmqvc_maintenance(void) { } } +/** Allocated protocol-specific peer state */ void fastd_protocol_ec25519_fhmqvc_init_peer_state(fastd_peer_t *peer) { init_protocol_state(); @@ -73,12 +88,14 @@ void fastd_protocol_ec25519_fhmqvc_init_peer_state(fastd_peer_t *peer) { peer->protocol_state->last_serial = ctx.protocol_state->handshake_key.serial; } +/** Resets a the state of a session, freeing method-specific state */ static void reset_session(protocol_session_t *session) { if (session->method) session->method->provider->session_free(session->method_state); secure_memzero(session, sizeof(protocol_session_t)); } +/** Resets all protocol-specific state of a peer */ void fastd_protocol_ec25519_fhmqvc_reset_peer_state(fastd_peer_t *peer) { if (!peer->protocol_state) return; @@ -87,6 +104,7 @@ void fastd_protocol_ec25519_fhmqvc_reset_peer_state(fastd_peer_t *peer) { reset_session(&peer->protocol_state->session); } +/** Frees the protocol-specific state */ void fastd_protocol_ec25519_fhmqvc_free_peer_state(fastd_peer_t *peer) { if (peer->protocol_state) { reset_session(&peer->protocol_state->old_session); diff --git a/src/protocols/ec25519_fhmqvc/util.c b/src/protocols/ec25519_fhmqvc/util.c index a53513f..e4a0c08 100644 --- a/src/protocols/ec25519_fhmqvc/util.c +++ b/src/protocols/ec25519_fhmqvc/util.c @@ -23,10 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + ec25519-fhmqvc protocol: utilify functions +*/ + #include "ec25519_fhmqvc.h" +/** Prints a private or public key on stdout with an optional descriptive text */ static inline void print_hexdump(const char *desc, unsigned char d[32]) { char buf[65]; hexdump(buf, d); @@ -34,6 +41,7 @@ static inline void print_hexdump(const char *desc, unsigned char d[32]) { printf("%s%s\n", desc, buf); } +/** Generates a new keypair */ void fastd_protocol_ec25519_fhmqvc_generate_key(void) { ecc_int256_t secret_key; ecc_int256_t public_key; @@ -57,6 +65,7 @@ void fastd_protocol_ec25519_fhmqvc_generate_key(void) { } } +/** Prints the public key corresponding to the configured private key */ void fastd_protocol_ec25519_fhmqvc_show_key(void) { if (conf.machine_readable) print_hexdump("", conf.protocol_config->key.public.u8); @@ -64,6 +73,7 @@ void fastd_protocol_ec25519_fhmqvc_show_key(void) { print_hexdump("Public: ", conf.protocol_config->key.public.u8); } +/** Adds protocol- and peer-specific environment variables to an environment */ void fastd_protocol_ec25519_fhmqvc_set_shell_env(fastd_shell_env_t *env, const fastd_peer_t *peer) { char buf[65]; @@ -79,6 +89,13 @@ void fastd_protocol_ec25519_fhmqvc_set_shell_env(fastd_shell_env_t *env, const f } } +/** + Generates a protocol-specific string representation of a peer + + This will only be used for peers without names (e.g. temporary peers) and + creates a string containing the first 16 hexadecimal digits of the peer's + public key. +*/ bool fastd_protocol_ec25519_fhmqvc_describe_peer(const fastd_peer_t *peer, char *buf, size_t len) { if (peer && peer->protocol_config) { char dumpbuf[65]; diff --git a/src/shell.c b/src/shell.c index c573a85..c161a9e 100644 --- a/src/shell.c +++ b/src/shell.c @@ -40,14 +40,14 @@ /** An environment variable */ typedef struct shell_env_entry { - const char *key; - char *value; + const char *key; /**< The name of the enviroment variable */ + char *value; /**< The value of the environment variable */ } shell_env_entry_t; /** A shell environment */ struct fastd_shell_env { - VECTOR(shell_env_entry_t) entries; + VECTOR(shell_env_entry_t) entries; /**< Vector of the entries of the environment */ }; diff --git a/src/socket.c b/src/socket.c index 49752fc..5ab9fc1 100644 --- a/src/socket.c +++ b/src/socket.c @@ -23,11 +23,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Socket handling +*/ #include "fastd.h" #include "poll.h" +/** + Creates a new socket bound to a specific address + + \return The new socket's file descriptor +*/ static int bind_socket(const fastd_bind_address_t *addr, bool warn) { int fd = -1; int af = AF_UNSPEC; @@ -160,6 +170,7 @@ static int bind_socket(const fastd_bind_address_t *addr, bool warn) { return -1; } +/** Gets the address a socket is bound to and sets it in the socket structure */ static bool set_bound_address(fastd_socket_t *sock) { fastd_peer_address_t addr = {}; socklen_t len = sizeof(addr); diff --git a/src/verify.c b/src/verify.c index 694206f..4cf0c67 100644 --- a/src/verify.c +++ b/src/verify.c @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Handling of on-verify commands to add peers not configured statically ("temporary peers") +*/ + #include "verify.h" @@ -35,6 +41,12 @@ #include <pthread.h> +/** + Calls the on-verify command and returns the result + + do_verify() may be called from secondary threads as all information about the peer + to verify is encoded in the supplied environment +*/ static bool do_verify(const fastd_shell_env_t *env) { int ret; if (!fastd_shell_command_exec_sync(&conf.on_verify, env, &ret)) @@ -52,12 +64,14 @@ static bool do_verify(const fastd_shell_env_t *env) { return true; } +/** The argument given to asynchronous verifier threads */ typedef struct verify_arg { - fastd_shell_env_t *env; - size_t ret_len; - fastd_async_verify_return_t ret; + fastd_shell_env_t *env; /**< Enviroment containing information about the peer to verify */ + size_t ret_len; /**< Length of the \e ret field (as it contains a flexible member) */ + fastd_async_verify_return_t ret; /**< Information to return to the main thread after the verification */ } verify_arg_t; +/** Verifier thread main function */ static void * do_verify_thread(void *p) { verify_arg_t *arg = p; @@ -71,6 +85,12 @@ static void * do_verify_thread(void *p) { return NULL; } +/** + Verifies a peer + + \return A tristate. If on-verify is a synchronous command, it will be \e true or \e false, but if the command is asynchronous (which is the default), + \e undef will be returned and the result is sent via the asyncronous notification mechanism. +*/ fastd_tristate_t fastd_verify_peer(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *data, size_t data_len) { if (!fastd_shell_command_isset(&conf.on_verify)) exit_bug("tried to verify peer without on-verify command"); diff --git a/src/verify.h b/src/verify.h index 7f0d5c0..5203339 100644 --- a/src/verify.h +++ b/src/verify.h @@ -23,6 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + \file + + Handling of on-verify commands to add peers not configured statically ("temporary peers") +*/ + #pragma once |