From a04bcf247f4be7e3da4fe3895200f0b9709fc0bb Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 24 Aug 2014 01:00:45 +0200 Subject: Merge peer config into peer structure With this refactoring, the structure fastd_peer_config_t is merged into fastd_peer_t, and fastd_remote_config_t into fastd_remote_t. This also means we now create peers directly when reading their configurations, which significantly simplifies the whole reload process, and prepares for some future optimizations like a key hash table. Note: This commit is too big, but I couldn't come up with a nice way to split it into smaller pieces... --- src/config.c | 156 ++++++---------- src/config.h | 4 +- src/config.y | 87 ++++----- src/fastd.c | 53 +----- src/fastd.h | 39 ++-- src/log.c | 27 ++- src/options.c | 6 +- src/peer.c | 257 +++++++++++++------------- src/peer.h | 72 ++------ src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c | 51 ++--- src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h | 12 +- src/protocols/ec25519_fhmqvc/handshake.c | 104 ++++------- src/protocols/ec25519_fhmqvc/util.c | 20 +- src/receive.c | 2 +- src/resolve.c | 6 +- src/types.h | 4 +- 16 files changed, 369 insertions(+), 531 deletions(-) diff --git a/src/config.c b/src/config.c index 842e6cc..98f99a7 100644 --- a/src/config.c +++ b/src/config.c @@ -75,9 +75,7 @@ static void default_config(void) { /** 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; - else + if (strcmp(name, conf.protocol->name)) exit_error("config error: protocol `%s' not supported", name); } @@ -189,7 +187,7 @@ static bool has_peer_group_peer_dirs(const fastd_peer_group_t *group) { } /** Reads and processes all peer definitions in the current directory (which must also be supplied as the argument) */ -static void read_peer_dir(fastd_peer_config_t **peers, fastd_peer_group_t *group, const char *dir) { +static void read_peer_dir(fastd_peer_group_t *group, const char *dir) { DIR *dirh = opendir("."); if (dirh) { @@ -221,18 +219,16 @@ static void read_peer_dir(fastd_peer_config_t **peers, fastd_peer_group_t *group continue; } - fastd_peer_config_t *peer = fastd_peer_config_new(group); + fastd_peer_t *peer = fastd_new0(fastd_peer_t); peer->name = fastd_strdup(result->d_name); peer->config_source_dir = dir; - if (fastd_config_read(result->d_name, group, peer, 0)) { - peer->next = *peers; - *peers = peer; - } - else { - pr_warn("peer config `%s' will be ignored", result->d_name); - fastd_peer_config_free(peer); + if (!fastd_config_read(result->d_name, group, peer, 0)) { + fastd_peer_free(peer); + continue; } + + fastd_peer_add(peer); } if (closedir(dirh) < 0) @@ -245,13 +241,13 @@ static void read_peer_dir(fastd_peer_config_t **peers, fastd_peer_group_t *group } /** Reads all configured peer directories for a peer grup */ -static void read_peer_dirs(fastd_peer_config_t **peers, fastd_peer_group_t *group) { +static void read_peer_dirs(fastd_peer_group_t *group) { char *oldcwd = get_current_dir_name(); fastd_string_stack_t *dir; for (dir = group->peer_dirs; dir; dir = dir->next) { if (!chdir(dir->str)) - read_peer_dir(peers, group, dir->str); + read_peer_dir(group, dir->str); else pr_error("change from directory `%s' to `%s' failed: %s", oldcwd, dir->str, strerror(errno)); } @@ -282,7 +278,7 @@ void fastd_config_add_peer_dir(fastd_peer_group_t *group, const char *dir) { } /** Reads and processes a configuration file */ -bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fastd_peer_config_t *peer_config, int depth) { +bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fastd_peer_t *peer, int depth) { if (depth >= MAX_CONFIG_DEPTH) exit_error("maximum config include depth exceeded"); @@ -327,15 +323,18 @@ bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fas YYLTYPE loc = {1, 0, 1, 0}; fastd_parser_state_t state = { .peer_group = peer_group, - .peer = peer_config, + .peer = peer, .filename = filename, .depth = depth+1, }; - if (peer_config) + if (peer) { token = START_PEER_CONFIG; - else + peer->group = peer_group; + } + else { token = peer_group->parent ? START_PEER_GROUP_CONFIG : START_CONFIG; + } int parse_ret = fastd_config_push_parse(ps, token, &token_val, &loc, &state); @@ -377,17 +376,6 @@ bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fas return ret; } -/** Gathers some information about the configured peers */ -static void assess_peers(void) { - conf.has_floating = false; - - fastd_peer_config_t *peer; - for (peer = ctx.peer_configs; peer; peer = peer->next) { - if (fastd_peer_config_is_floating(peer)) - conf.has_floating = true; - } -} - /** Loads information about the configured user and group */ static void configure_user(void) { conf.uid = getuid(); @@ -531,7 +519,7 @@ static void config_check_base(void) { if (conf.peer_group->children) exit_error("config error: in TUN mode peer groups can't be used"); - if (ctx.peer_configs && ctx.peer_configs->next) + if (VECTOR_LEN(ctx.peers) != 1) exit_error("config error: in TUN mode exactly one peer must be configured"); } @@ -551,11 +539,11 @@ void fastd_config_check(void) { config_check_base(); if (conf.mode == MODE_TUN) { - if (!ctx.peer_configs) + if (!VECTOR_LEN(ctx.peers)) exit_error("config error: in TUN mode exactly one peer must be configured"); } - if (!ctx.peer_configs && !has_peer_group_peer_dirs(conf.peer_group)) + if (!VECTOR_LEN(ctx.peers) && !has_peer_group_peer_dirs(conf.peer_group)) exit_error("config error: neither fixed peers nor peer dirs have been configured"); if (!conf.method_list) { @@ -571,98 +559,74 @@ void fastd_config_check(void) { void fastd_config_verify(void) { config_check_base(); configure_methods(); - - fastd_peer_config_t *peer; - for (peer = ctx.peer_configs; peer; peer = peer->next) - conf.protocol->peer_verify(peer); } /** Reads the peer dirs of a peer group and its children */ -static void peer_dirs_read_peer_group(fastd_peer_config_t **peers, fastd_peer_group_t *group) { - read_peer_dirs(peers, group); +static void peer_dirs_read_peer_group(fastd_peer_group_t *group) { + read_peer_dirs(group); fastd_peer_group_t *child; for (child = group->children; child; child = child->next) - peer_dirs_read_peer_group(peers, child); + peer_dirs_read_peer_group(child); } -/** 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) { - next = &(*peer)->next; - - /* don't touch statically configured peers */ - if (!(*peer)->config_source_dir) - continue; - - /* search for each peer in the list of new peers */ - for (new_peer = new_peers; *new_peer; new_peer = new_next) { - new_next = &(*new_peer)->next; +/** Initializes the configured peers */ +static void configure_peers(void) { + ctx.has_floating = false; - if (((*peer)->config_source_dir == (*new_peer)->config_source_dir) && strequal((*peer)->name, (*new_peer)->name)) { - if (fastd_peer_config_equal(*peer, *new_peer)) { - pr_verbose("peer `%s' unchanged", (*peer)->name); + ssize_t i; + for (i = VECTOR_LEN(ctx.peers)-1; i >= 0; i--) { + fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i); - fastd_peer_config_t *free_peer = *new_peer; - *new_peer = *new_next; - fastd_peer_config_free(free_peer); - peer = NULL; - } - else { - pr_verbose("peer `%s' changed, resetting", (*peer)->name); - new_peer = NULL; - } - - break; - } + if (peer->config_state == CONFIG_STATIC) { + /* The peer hasn't been touched since the last run of init_peers(), so its definition must have disappeared */ + fastd_peer_delete(peer); + continue; } - /* no new peer was found, or the old one has changed */ - if (peer && (!new_peer || !*new_peer)) { - pr_verbose("removing peer `%s'", (*peer)->name); + if (fastd_peer_is_dynamic(peer)) + continue; - fastd_peer_config_t *free_peer = *peer; - *peer = *next; - next = peer; + if (peer->config_state != CONFIG_DISABLED && !conf.protocol->check_peer(peer)) + peer->config_state = CONFIG_DISABLED; - fastd_peer_config_purge(free_peer); + if (peer->config_state == CONFIG_DISABLED) { + fastd_peer_reset(peer); + continue; } - } -} -/** 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) { - if (peer->next) - continue; + if (fastd_peer_is_floating(peer)) + ctx.has_floating = true; - peer->next = *peers; - *peers = new_peers; - return; + peer->config_state = CONFIG_STATIC; + + if (!fastd_peer_is_established(peer)) + fastd_peer_reset(peer); } } /** Refreshes the peer configurations from the configured peer dirs */ void fastd_config_load_peer_dirs(void) { - fastd_peer_config_t *new_peers = NULL; - peer_dirs_read_peer_group(&new_peers, conf.peer_group); + size_t i; + for (i = 0; i < VECTOR_LEN(ctx.peers); i++) { + fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i); - peer_dirs_handle_old_peers(&ctx.peer_configs, &new_peers); - peer_dirs_handle_new_peers(&ctx.peer_configs, new_peers); + if (fastd_peer_is_dynamic(peer)) + continue; - assess_peers(); + /* Reset all peers' config states */ + if (!peer->config_source_dir) + peer->config_state = CONFIG_NEW; + else if (peer->config_state == CONFIG_DISABLED) + peer->config_state = CONFIG_STATIC; + } + + peer_dirs_read_peer_group(conf.peer_group); + configure_peers(); } /** Frees all resources used by the global configuration */ void fastd_config_release(void) { - while (ctx.peer_configs) { - fastd_peer_config_t *peer = ctx.peer_configs, *next = peer->next; - fastd_peer_config_free(peer); - ctx.peer_configs = next; - } - while (conf.bind_addrs) { fastd_bind_address_t *next = conf.bind_addrs->next; free(conf.bind_addrs->bindtodev); diff --git a/src/config.h b/src/config.h index f4e1de5..b076266 100644 --- a/src/config.h +++ b/src/config.h @@ -38,7 +38,7 @@ /** State of the config parser */ struct fastd_parser_state { fastd_peer_group_t *peer_group; /**< The current peer group */ - fastd_peer_config_t *peer; /**< The peer currently being loaded */ + fastd_peer_t *peer; /**< The peer currently being loaded */ const char *const filename; /**< The filename of the currently parsed file */ const int depth; /**< The include depth */ @@ -54,7 +54,7 @@ void fastd_config_release(void); void fastd_config_handle_options(int argc, char *const argv[]); void fastd_config_verify(void); -bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fastd_peer_config_t *peer_config, int depth); +bool fastd_config_read(const char *filename, fastd_peer_group_t *peer_group, fastd_peer_t *peer, int depth); void fastd_config_peer_group_push(fastd_parser_state_t *state, const char *name); void fastd_config_peer_group_pop(fastd_parser_state_t *state); void fastd_config_add_peer_dir(fastd_peer_group_t *group, const char *dir); diff --git a/src/config.y b/src/config.y index 9b5d13d..44fc59f 100644 --- a/src/config.y +++ b/src/config.y @@ -203,7 +203,7 @@ statement: peer_group_statement ; peer_group_statement: - TOK_PEER peer '{' peer_conf '}' + TOK_PEER peer '{' peer_conf '}' peer_after | TOK_PEER TOK_GROUP peer_group '{' peer_group_config '}' peer_group_after | TOK_PEER TOK_LIMIT peer_limit ';' | TOK_INCLUDE include ';' @@ -422,15 +422,17 @@ on_verify: sync_def_async TOK_STRING { ; peer: TOK_STRING { - fastd_peer_config_t *peer = fastd_peer_config_new(state->peer_group); - peer->name = fastd_strdup($1->str); - peer->next = ctx.peer_configs; - - ctx.peer_configs = peer; - state->peer = peer; + state->peer = fastd_new0(fastd_peer_t); + state->peer->name = fastd_strdup($1->str); + state->peer->group = state->peer_group; } ; +peer_after: { + if (!fastd_peer_add(state->peer)) + YYERROR; + } + peer_conf: peer_conf peer_statement | ; @@ -442,59 +444,51 @@ peer_statement: TOK_REMOTE peer_remote ';' ; peer_remote: TOK_ADDR4 port { - fastd_remote_config_t **remote = &state->peer->remotes; - while (*remote) - remote = &(*remote)->next; + fastd_remote_t remote = {}; - *remote = fastd_new0(fastd_remote_config_t); + remote.address.in.sin_family = AF_INET; + remote.address.in.sin_addr = $1; + remote.address.in.sin_port = htons($2); + fastd_peer_address_simplify(&remote.address); - (*remote)->address.in.sin_family = AF_INET; - (*remote)->address.in.sin_addr = $1; - (*remote)->address.in.sin_port = htons($2); - fastd_peer_address_simplify(&(*remote)->address); + VECTOR_ADD(state->peer->remotes, remote); } | TOK_ADDR6 port { - fastd_remote_config_t **remote = &state->peer->remotes; - while (*remote) - remote = &(*remote)->next; + fastd_remote_t remote = {}; - *remote = fastd_new0(fastd_remote_config_t); + remote.address.in6.sin6_family = AF_INET6; + remote.address.in6.sin6_addr = $1; + remote.address.in6.sin6_port = htons($2); + fastd_peer_address_simplify(&remote.address); - (*remote)->address.in6.sin6_family = AF_INET6; - (*remote)->address.in6.sin6_addr = $1; - (*remote)->address.in6.sin6_port = htons($2); - fastd_peer_address_simplify(&(*remote)->address); + VECTOR_ADD(state->peer->remotes, remote); } | TOK_ADDR6_SCOPED port { char addrbuf[INET6_ADDRSTRLEN]; size_t addrlen; - fastd_remote_config_t **remote = &state->peer->remotes; - while (*remote) - remote = &(*remote)->next; inet_ntop(AF_INET6, &$1.addr, addrbuf, sizeof(addrbuf)); addrlen = strlen(addrbuf); - *remote = fastd_new0(fastd_remote_config_t); + fastd_remote_t remote = {}; + remote.hostname = fastd_alloc(addrlen + strlen($1.ifname) + 2); + memcpy(remote.hostname, addrbuf, addrlen); + remote.hostname[addrlen] = '%'; + strcpy(remote.hostname+addrlen+1, $1.ifname); - (*remote)->hostname = fastd_alloc(addrlen + strlen($1.ifname) + 2); - memcpy((*remote)->hostname, addrbuf, addrlen); - (*remote)->hostname[addrlen] = '%'; - strcpy((*remote)->hostname+addrlen+1, $1.ifname); + remote.address.sa.sa_family = AF_INET6; + remote.address.in.sin_port = htons($2); - (*remote)->address.sa.sa_family = AF_INET6; - (*remote)->address.in.sin_port = htons($2); + VECTOR_ADD(state->peer->remotes, remote); } | maybe_af TOK_STRING port { - fastd_remote_config_t **remote = &state->peer->remotes; - while (*remote) - remote = &(*remote)->next; + fastd_remote_t remote = {}; - *remote = fastd_new0(fastd_remote_config_t); + remote.hostname = fastd_strdup($2->str); + remote.address.sa.sa_family = $1; + remote.address.in.sin_port = htons($3); - (*remote)->hostname = fastd_strdup($2->str); - (*remote)->address.sa.sa_family = $1; - (*remote)->address.in.sin_port = htons($3); + VECTOR_ADD(state->peer->remotes, remote); } ; @@ -504,7 +498,8 @@ peer_float: boolean { ; peer_key: TOK_STRING { - free(state->peer->key); state->peer->key = fastd_strdup($1->str); + free(state->peer->key); + state->peer->key = conf.protocol->read_key($1->str); } ; @@ -541,14 +536,14 @@ forward: boolean { conf.forward = $1; } include: TOK_PEER TOK_STRING maybe_as { - fastd_peer_config_t *peer = fastd_peer_config_new(state->peer_group); - if ($3) - peer->name = fastd_strdup($3->str); + fastd_peer_t *peer = fastd_new0(fastd_peer_t); + peer->name = fastd_strdup(fastd_string_stack_get($3)); + if (!fastd_config_read($2->str, state->peer_group, peer, state->depth)) YYERROR; - peer->next = ctx.peer_configs; - ctx.peer_configs = peer; + if (!fastd_peer_add(peer)) + YYERROR; } | TOK_PEERS TOK_FROM TOK_STRING { fastd_config_add_peer_dir(state->peer_group, $3->str); diff --git a/src/fastd.c b/src/fastd.c index 589a293..0f74984 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -199,51 +199,6 @@ 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 = ctx.peer_configs; peer_conf; peer_conf = peer_conf->next) { - conf.protocol->peer_configure(peer_conf); - - if (peer_conf->config_state == CONFIG_NEW) - fastd_peer_add(peer_conf); - } - - size_t i; - for (i = 0; i < VECTOR_LEN(ctx.peers);) { - fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i); - - if (fastd_peer_is_dynamic(peer)) { - if (!conf.protocol->peer_check_dynamic(peer)) { - fastd_peer_delete(peer); - continue; - } - } - else { - fastd_peer_config_state_t state = conf.protocol->peer_check(peer->config) ? CONFIG_STATIC : CONFIG_DISABLED; - if (state != peer->config->config_state) { - if (peer->config->config_state != CONFIG_NEW) - pr_info("peer %P is %s now.", peer, (state == CONFIG_DISABLED) ? "disabled" : "enabled"); - - peer->config->config_state = state; - fastd_peer_reset(peer); - } - } - - i++; - } -} - -/** 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)", @@ -584,7 +539,6 @@ static inline void init(int argc, char *argv[]) { set_user(); fastd_config_load_peer_dirs(); - init_peers(); } @@ -629,7 +583,6 @@ static inline void handle_signals(void) { pr_info("reconfigure triggered"); fastd_config_load_peer_dirs(); - init_peers(); } if (dump) { @@ -653,6 +606,12 @@ static inline void run(void) { handle_signals(); } +/** 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)); +} + /** Performs cleanup of resources used by fastd diff --git a/src/fastd.h b/src/fastd.h index 9b1dc29..ea30045 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -68,20 +68,7 @@ struct fastd_protocol { const char *name; /** Performs one-time initialization tasks for the protocol */ - fastd_protocol_config_t* (*init)(void); - - /** Does some basic checks for the validity of a peer configuration */ - void (*peer_verify)(fastd_peer_config_t *peer_conf); - - /** Initializes protocol-specific parts of a peer configuration */ - void (*peer_configure)(fastd_peer_config_t *peer_conf); - - /** Checks if a peer configuration is valid and a connection may be established */ - bool (*peer_check)(fastd_peer_config_t *peer_conf); - - /** Checks if a dynamic peer is valid and a connection may be established */ - bool (*peer_check_dynamic)(fastd_peer_t *peer); - + fastd_protocol_config_t * (*init)(void); /** Sends a handshake to the given peer */ void (*handshake_init)(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer); @@ -101,16 +88,27 @@ struct fastd_protocol { /** Sends a payload data packet to the given peer */ void (*send)(fastd_peer_t *peer, fastd_buffer_t buffer); + /** Initializes the protocol state for a peer */ void (*init_peer_state)(fastd_peer_t *peer); /** Resets the protocol state for a peer (resets active sessions etc.) */ void (*reset_peer_state)(fastd_peer_t *peer); - /** Frees the protocol state for a peer */ void (*free_peer_state)(fastd_peer_t *peer); + + /** Initializes protocol-specific parts of a peer configuration */ + fastd_protocol_key_t * (*read_key)(const char *key); + + /** Checks a peer after reading its configuration */ + bool (*check_peer)(const fastd_peer_t *peer); + + /** Searches a peer identified by a specific key */ + fastd_peer_t * (*find_peer)(const fastd_protocol_key_t *key); + + /** Generates a new keypair and outputs it */ void (*generate_key)(void); @@ -206,8 +204,6 @@ struct fastd_config { fastd_peer_group_t *peer_group; /**< The root peer group configuration */ - bool has_floating; /**< Specifies if any of the configured peers have floating remotes */ - fastd_protocol_config_t *protocol_config; /**< The protocol-specific configuration */ fastd_shell_command_t on_pre_up; /**< The command to execute before the initialization of the tunnel interface */ @@ -241,8 +237,6 @@ struct fastd_context { struct timespec now; /**< The current monotonous timestamp */ - fastd_peer_config_t *peer_configs; /**< The configured peers */ - uint64_t next_peer_id; /**< An monotonously increasing ID peers are identified with in some components */ VECTOR(fastd_peer_t*) peers; /**< The currectly active peers */ @@ -256,6 +250,8 @@ struct fastd_context { VECTOR(struct pollfd) pollfds; /**< The vector of pollfds for all file descriptors */ #endif + bool has_floating; /**< Specifies if any of the configured peers have floating remotes */ + uint32_t peer_addr_ht_seed; /**< The hash seed used for peer_addr_ht */ VECTOR(fastd_peer_t*) *peer_addr_ht; /**< An array of hash buckets for the peer hash table */ @@ -425,6 +421,11 @@ static inline fastd_string_stack_t* fastd_string_stack_push(fastd_string_stack_t return ret; } +/** Gets the head of string stack (or NULL if the stack is NULL) */ +static inline const char * fastd_string_stack_get(const fastd_string_stack_t *stack) { + return stack ? stack->str : NULL; +} + /** Frees a whole string stack */ static inline void fastd_string_stack_free(fastd_string_stack_t *str) { while (str) { diff --git a/src/log.c b/src/log.c index 122b322..f6b6d2d 100644 --- a/src/log.c +++ b/src/log.c @@ -93,16 +93,18 @@ 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->name) { - return snprintf_safe(buffer, size, "<%s>", peer->config->name); - } - else { - char buf[65]; - if (conf.protocol->describe_peer(peer, buf, sizeof(buf))) - return snprintf_safe(buffer, size, "{%s}", buf); - else - return snprintf_safe(buffer, size, "(null)"); + if (peer) { + if (peer->name) { + return snprintf_safe(buffer, size, "<%s>", peer->name); + } + else { + char buf[65]; + if (conf.protocol->describe_peer(peer, buf, sizeof(buf))) + return snprintf_safe(buffer, size, "{%s}", buf); + } } + + return snprintf_safe(buffer, size, "(null)"); } /** vsnprintf-like function using different conversion specifiers */ @@ -166,12 +168,7 @@ static int fastd_vsnprintf(char *buffer, size_t size, const char *format, va_lis break; case 'P': - p = va_arg(ap, const fastd_peer_t*); - - if (p) - buffer += snprint_peer_str(buffer, buffer_end-buffer, (const fastd_peer_t*)p); - else - buffer += snprintf_safe(buffer, buffer_end-buffer, "(null)"); + buffer += snprint_peer_str(buffer, buffer_end-buffer, va_arg(ap, const fastd_peer_t*)); break; case 'I': diff --git a/src/options.c b/src/options.c index e3cf78a..1e7764d 100644 --- a/src/options.c +++ b/src/options.c @@ -117,14 +117,12 @@ static void option_config(const char *arg) { /** Handles the --config-peer option */ static void option_config_peer(const char *arg) { - fastd_peer_config_t *peer = fastd_peer_config_new(conf.peer_group); + fastd_peer_t *peer = fastd_new0(fastd_peer_t); if(!fastd_config_read(arg, conf.peer_group, peer, 0)) exit(1); - peer->next = ctx.peer_configs; - ctx.peer_configs = peer; - + fastd_peer_add(peer); } /** Handles the --config-peer-dir option */ diff --git a/src/peer.c b/src/peer.c index 1ae7b3c..34f7bf7 100644 --- a/src/peer.c +++ b/src/peer.c @@ -42,7 +42,7 @@ void fastd_peer_set_shell_env(fastd_shell_env_t *env, const fastd_peer_t *peer, /* both INET6_ADDRSTRLEN and IFNAMESIZE already include space for the zero termination, so there is no need to add space for the '%' here. */ char buf[INET6_ADDRSTRLEN+IF_NAMESIZE]; - fastd_shell_env_set(env, "PEER_NAME", peer ? peer->config->name : NULL); + fastd_shell_env_set(env, "PEER_NAME", peer ? peer->name : NULL); switch(local_addr ? local_addr->sa.sa_family : AF_UNSPEC) { case AF_INET: @@ -293,7 +293,7 @@ static inline bool is_group_in(const fastd_peer_group_t *group1, const fastd_pee /** Checks if a peer lies in a peer group */ static bool is_peer_in_group(const fastd_peer_t *peer, const fastd_peer_group_t *group) { - return is_group_in(fastd_peer_get_group(peer), group); + return is_group_in(peer->group, group); } /** @@ -304,11 +304,6 @@ static bool is_peer_in_group(const fastd_peer_t *peer, const fastd_peer_group_t After a call to reset_peer a peer must be deleted by delete_peer or re-initialized by setup_peer. */ static void reset_peer(fastd_peer_t *peer) { - if (peer->state == STATE_INACTIVE) - return; - - pr_debug("resetting peer %P", peer); - if (fastd_peer_is_established(peer)) { on_disestablish(peer); pr_info("connection with %P disestablished.", peer); @@ -348,7 +343,7 @@ static void reset_peer(fastd_peer_t *peer) { */ static void init_handshake(fastd_peer_t *peer) { unsigned delay = 0; - if (has_group_config_constraints(fastd_peer_get_group(peer))) + if (has_group_config_constraints(peer->group)) delay = fastd_rand(0, 3000); peer->state = STATE_HANDSHAKE; @@ -371,7 +366,7 @@ void fastd_peer_handle_resolve(fastd_peer_t *peer, fastd_remote_t *remote, size_ /** Checks if a remote contains a hostname instead of a static IP address */ static inline bool has_remote_hostname(const fastd_remote_t *remote) { - return remote->config->hostname; + return remote->hostname; } /** Initializes a peer */ @@ -395,13 +390,15 @@ static void setup_peer(fastd_peer_t *peer) { peer->establish_handshake_timeout = ctx.now; +#ifdef WITH_DYNAMIC_PEERS + peer->verify_timeout = ctx.now; + peer->verify_valid_timeout = ctx.now; +#endif + if (!fastd_peer_is_enabled(peer)) /* Keep the peer in STATE_INACTIVE */ return; - if (!peer->protocol_state) - conf.protocol->init_peer_state(peer); - fastd_remote_t *next_remote = fastd_peer_get_next_remote(peer); if (next_remote) { next_remote->current_address = 0; @@ -420,68 +417,42 @@ static void setup_peer(fastd_peer_t *peer) { } } -/** Frees a peer */ -static void delete_peer(fastd_peer_t *peer) { - pr_debug("deleting peer %P", peer); - - size_t i = peer_index(peer); - VECTOR_DELETE(ctx.peers, i); - fastd_poll_delete_peer(i); - - fastd_peer_hashtable_remove(peer); +/** + Frees a peer - conf.protocol->free_peer_state(peer); + If the peer has already been added to the peer list, + use fastd_peer_delete() instead. +*/ +void fastd_peer_free(fastd_peer_t *peer) { + free(peer->key); - if (fastd_peer_is_dynamic(peer)) - fastd_peer_config_free(peer->config); + size_t i; + for (i = 0; i < VECTOR_LEN(peer->remotes); i++) { + fastd_remote_t *remote = &VECTOR_INDEX(peer->remotes, i); - for (i = 0; i < VECTOR_LEN(peer->remotes); i++) - free(VECTOR_INDEX(peer->remotes, i).addresses); + free(remote->addresses); + free(remote->hostname); + } VECTOR_FREE(peer->remotes); + free(peer->name); free(peer); } +/** Deletes a peer */ +static void delete_peer(fastd_peer_t *peer) { + pr_verbose("deleting peer %P", peer); -/** Allocates a new peer config */ -fastd_peer_config_t* fastd_peer_config_new(fastd_peer_group_t *group) { - fastd_peer_config_t *peer = fastd_new0(fastd_peer_config_t); - peer->group = group; - - return peer; -} - -/** Frees a peer config (which must not be referenced anywhere) */ -void fastd_peer_config_free(fastd_peer_config_t *peer) { - while (peer->remotes) { - fastd_remote_config_t *remote = peer->remotes; - peer->remotes = remote->next; + size_t i = peer_index(peer); + VECTOR_DELETE(ctx.peers, i); + fastd_poll_delete_peer(i); - free(remote->hostname); - free(remote); - } + conf.protocol->free_peer_state(peer); - free(peer->name); - free(peer->key); - free(peer->protocol_config); - free(peer); + fastd_peer_free(peer); } -/** Deletes a peer config, and removes the peer assiciated with the peer config */ -void fastd_peer_config_purge(fastd_peer_config_t *config) { - size_t i; - for (i = 0; i < VECTOR_LEN(ctx.peers); i++) { - fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i); - - if (peer->config == config) { - fastd_peer_delete(peer); - break; - } - } - - fastd_peer_config_free(config); -} /** Checks if two fastd_peer_address_t are equal */ bool fastd_peer_address_equal(const fastd_peer_address_t *addr1, const fastd_peer_address_t *addr2) { @@ -556,8 +527,10 @@ bool fastd_peer_owns_address(const fastd_peer_t *peer, const fastd_peer_address_ if (fastd_peer_is_floating(peer)) return false; - fastd_remote_config_t *remote; - for (remote = peer->config->remotes; remote; remote = remote->next) { + size_t i; + for (i = 0; i < VECTOR_LEN(peer->remotes); i++) { + fastd_remote_t *remote = &VECTOR_INDEX(peer->remotes, i); + if (remote->hostname) continue; @@ -643,43 +616,13 @@ bool fastd_peer_claim_address(fastd_peer_t *new_peer, fastd_socket_t *sock, cons return true; } -/** Checks if two remote configs are equivalent */ -static bool remote_configs_equal(const fastd_remote_config_t *remote1, const fastd_remote_config_t *remote2) { - if (!remote1 && !remote2) - return true; - - if (!remote1 || !remote2) - return false; - - if (!fastd_peer_address_equal(&remote1->address, &remote2->address)) - return false; - - if (!strequal(remote1->hostname, remote2->hostname)) - return false; - - return remote_configs_equal(remote1->next, remote2->next); -} - -/** Checks if two peer configs are equivalent */ -bool fastd_peer_config_equal(const fastd_peer_config_t *peer1, const fastd_peer_config_t *peer2) { - if (peer1->group != peer2->group) - return false; - - if(peer1->floating != peer2->floating) - return false; - - if (!remote_configs_equal(peer1->remotes, peer2->remotes)) - return false; - - if (!strequal(peer1->key, peer2->key)) - return false; - - return true; -} - /** Resets and re-initializes a peer */ void fastd_peer_reset(fastd_peer_t *peer) { - reset_peer(peer); + if (peer->state != STATE_INACTIVE) { + pr_debug("resetting peer %P", peer); + reset_peer(peer); + } + setup_peer(peer); } @@ -709,7 +652,7 @@ bool fastd_peer_may_connect(fastd_peer_t *peer) { const fastd_peer_group_t *group; - for (group = fastd_peer_get_group(peer); group; group = group->parent) { + for (group = peer->group; group; group = group->parent) { if (group->max_connections < 0) continue; @@ -720,53 +663,111 @@ bool fastd_peer_may_connect(fastd_peer_t *peer) { return true; } -/** Create a new peer */ -fastd_peer_t* fastd_peer_add(fastd_peer_config_t *peer_conf) { - fastd_peer_t *peer = fastd_new0(fastd_peer_t); +/** Checks if two peer configurations are equivalent (exept for the name) */ +static inline bool peer_configs_equal(const fastd_peer_t *peer1, const fastd_peer_t *peer2) { + if (peer1->group != peer2->group) + return false; - peer->id = ctx.next_peer_id++; + if (peer1->floating != peer2->floating) + return false; - if (peer_conf) { - peer->config = peer_conf; + if (VECTOR_LEN(peer1->remotes) != VECTOR_LEN(peer2->remotes)) + return false; - fastd_remote_config_t *remote_config; - for (remote_config = peer_conf->remotes; remote_config; remote_config = remote_config->next) { - fastd_remote_t remote = {.config = remote_config}; + size_t i; + for (i = 0; i < VECTOR_LEN(peer1->remotes); i++) { + const fastd_remote_t *remote1 = &VECTOR_INDEX(peer1->remotes, i), *remote2 = &VECTOR_INDEX(peer2->remotes, i); - if (!remote_config->hostname) { - remote.n_addresses = 1; - remote.addresses = fastd_new(fastd_peer_address_t); - remote.addresses[0] = remote_config->address; - } + if (!fastd_peer_address_equal(&remote1->address, &remote2->address)) + return false; - VECTOR_ADD(peer->remotes, remote); - } + if (!strequal(remote1->hostname, remote2->hostname)) + return false; + } - pr_verbose("adding peer %P (group `%s')", peer, fastd_peer_get_group(peer)->name); + return true; +} + +/** Replaces a peer with a new configuration */ +static void replace_peer(fastd_peer_t *old, fastd_peer_t *new) { + reset_peer(old); + + new->id = old->id; + + new->protocol_state = old->protocol_state; + old->protocol_state = NULL; + + fastd_peer_t tmp = *old; + *old = *new; + *new = tmp; + + fastd_peer_free(new); +} + +/** Adds a new peer */ +bool fastd_peer_add(fastd_peer_t *peer) { + if (!peer->key) { + pr_warn("no valid key configured for peer %P", peer); + goto error; } - else { -#ifdef WITH_DYNAMIC_PEERS - if (!fastd_shell_command_isset(&conf.on_verify)) - exit_bug("tried to add dynamic peer without on-verify command"); - peer->config = fastd_peer_config_new(conf.peer_group); - peer->config->config_state = CONFIG_DYNAMIC; + fastd_peer_t *other = conf.protocol->find_peer(peer->key); + if (other) { + if (peer->config_state != CONFIG_NEW) + exit_bug("tried to replace with active peer"); + + switch (other->config_state) { + case CONFIG_NEW: + case CONFIG_DISABLED: + pr_warn("duplicate key used by peers %P and %P, disabling both", peer, other); + other->config_state = CONFIG_DISABLED; + goto error; + + case CONFIG_STATIC: + if (!strequal(other->name, peer->name)) + pr_verbose("peer %P has been renamed to %P", other, peer); + + if (peer_configs_equal(other, peer)) { + free(other->name); + other->name = peer->name; + peer->name = NULL; - peer->verify_timeout = ctx.now; - peer->verify_valid_timeout = ctx.now; + fastd_peer_free(peer); - pr_debug("adding dynamic peer"); -#else - exit_bug("dynamic peers not supported"); + pr_verbose("peer %P is unchanged", other); + other->config_state = CONFIG_NEW; + + return true; + } + + pr_verbose("peer %P has changed, resetting...", peer); + + replace_peer(other, peer); + return true; + +#ifdef WITH_DYNAMIC_PEERS + case CONFIG_DYNAMIC: + pr_verbose("dynamic peer %P is now configured as %P", other, peer); + replace_peer(other, peer); + return true; #endif + } } - setup_peer(peer); + peer->id = ctx.next_peer_id++; VECTOR_ADD(ctx.peers, peer); fastd_poll_add_peer(); - return peer; + conf.protocol->init_peer_state(peer); + + pr_verbose("adding peer %P", peer); + + return true; + + error: + fastd_peer_free(peer); + return false; } /** Prints a debug message when no handshake could be sent because the current remote didn't resolve successfully */ diff --git a/src/peer.h b/src/peer.h index f1187d8..3ddead4 100644 --- a/src/peer.h +++ b/src/peer.h @@ -46,7 +46,7 @@ typedef enum fastd_peer_state { /** The config state of a peer */ typedef enum fastd_peer_config_state { - CONFIG_NEW = 0, /**< The peer is configured statically, but has been not been enabled yet */ + CONFIG_NEW = 0, /**< The peer is configured statically, but has not been enabled yet */ CONFIG_STATIC, /**< The peer is configured statically */ CONFIG_DISABLED, /**< The peer is configured statically, but has been disabled because of a configuration error */ #ifdef WITH_DYNAMIC_PEERS @@ -54,11 +54,11 @@ typedef enum fastd_peer_config_state { #endif } fastd_peer_config_state_t; -/** Dynamic state of a peer */ +/** A peer's configuration and state */ struct fastd_peer { uint64_t id; /**< A unique ID assigned to each peer */ - fastd_peer_config_t *config; /**< The peer's fastd_peer_config_t */ + char *name; /**< The peer's name */ /** The socket used by the peer. This can either be a common bound socket or a dynamic, unbound socket that is used exclusively by this peer */ @@ -66,12 +66,17 @@ struct fastd_peer { fastd_peer_address_t local_address; /**< The local address used to communicate with this peer */ fastd_peer_address_t address; /**< The peers current address */ + fastd_peer_config_state_t config_state; /**< Specifies the way this peer was configured and if it is enabled */ fastd_peer_state_t state; /**< The peer's state */ + struct timespec timeout; /**< The timeout after which the peer is reset */ struct timespec keepalive_timeout; /**< The timeout after which a keepalive is sent to the peer */ + const fastd_peer_group_t *group; /**< The peer group the peer belongs to */ + VECTOR(fastd_remote_t) remotes; /**< The vector of the peer's remotes */ ssize_t next_remote; /**< An index into the field remotes or -1 */ + bool floating; /**< Specifies if the peer has any floating remotes */ struct timespec next_handshake; /**< The time of the next handshake */ fastd_dlist_head_t handshake_entry; /**< Entry in the handshake queue */ @@ -84,35 +89,17 @@ struct fastd_peer { struct timespec establish_handshake_timeout; /**< A timeout during which all handshakes for this peer will be ignored after a new connection has been established */ + const char *config_source_dir; /**< The directory this peer's configuration was loaded from */ + #ifdef WITH_DYNAMIC_PEERS struct timespec verify_timeout; /**< Specifies the minimum time after which on-verify may be run again */ struct timespec verify_valid_timeout; /**< Specifies how long a peer stays valid after a successful on-verify run */ #endif + fastd_protocol_key_t *key; /**< The peer's public key */ fastd_protocol_peer_state_t *protocol_state; /**< Protocol-specific peer state */ }; -/** - Static configuration of a peer - - Peer configurations are kept in a linked list. -*/ -struct fastd_peer_config { - fastd_peer_config_t *next; /**< The next peer configuration */ - - fastd_peer_config_state_t config_state; /**< Specifies the way this peer was configured and if it is enabled */ - - const char *config_source_dir; /**< The directory this peer's configuration was loaded from */ - - char *name; /**< The peer's name */ - - fastd_remote_config_t *remotes; /**< A linked list of the peer's remote entries */ - char *key; /**< The peer's public key */ - bool floating; /**< Specifies if the peer has any floating remotes */ - const fastd_peer_group_t *group; /**< The peer group the peer belongs to */ - - fastd_protocol_peer_config_t *protocol_config; /**< The protocol-specific configuration of the peer */ -}; /** A group of peers @@ -138,9 +125,10 @@ struct fastd_peer_eth_addr { struct timespec timeout; /**< Timeout after which the address entry will be purged */ }; -/** A resolved remote entry */ +/** A remote entry */ struct fastd_remote { - fastd_remote_config_t *config; /**< The remote's configuration */ + char *hostname; /**< The hostname or NULL */ + fastd_peer_address_t address; /**< The address; if hostname is set only sin.sin_port is used */ size_t n_addresses; /**< The size of the \e addresses array */ size_t current_address; /**< The index of the remote the next handshake will be sent to */ @@ -149,14 +137,6 @@ struct fastd_remote { struct timespec last_resolve_timeout; /**< Timeout before the remote must not be resolved again */ }; -/** An address or hostname entry associated with a peer */ -struct fastd_remote_config { - fastd_remote_config_t *next; /**< The next remote for the peer */ - - char *hostname; /**< The hostname or NULL */ - fastd_peer_address_t address; /**< The address; if hostname is set only sin.sin_port is used */ -}; - bool fastd_peer_address_equal(const fastd_peer_address_t *addr1, const fastd_peer_address_t *addr2); void fastd_peer_address_simplify(fastd_peer_address_t *addr); @@ -176,14 +156,10 @@ static inline uint16_t fastd_peer_address_get_port(const fastd_peer_address_t *a } } -fastd_peer_config_t* fastd_peer_config_new(fastd_peer_group_t *group); -void fastd_peer_config_free(fastd_peer_config_t *peer); -void fastd_peer_config_purge(fastd_peer_config_t *config); -bool fastd_peer_config_equal(const fastd_peer_config_t *peer1, const fastd_peer_config_t *peer2); - +bool fastd_peer_add(fastd_peer_t *peer); void fastd_peer_reset(fastd_peer_t *peer); void fastd_peer_delete(fastd_peer_t *peer); -fastd_peer_t* fastd_peer_add(fastd_peer_config_t *peer_conf); +void fastd_peer_free(fastd_peer_t *peer); void fastd_peer_set_established(fastd_peer_t *peer); bool fastd_peer_may_connect(fastd_peer_t *peer); void fastd_peer_handle_resolve(fastd_peer_t *peer, fastd_remote_t *remote, size_t n_addresses, const fastd_peer_address_t *addresses); @@ -228,20 +204,15 @@ static inline bool fastd_peer_handshake_scheduled(fastd_peer_t *peer) { return fastd_dlist_linked(&peer->handshake_entry); } -/** Checks if a peer config has floating remotes (or no remotes at all) */ -static inline bool fastd_peer_config_is_floating(const fastd_peer_config_t *config) { - return (!config->remotes || config->floating); -} - /** Checks if a peer is floating (is has at least one floating remote or no remotes at all) */ static inline bool fastd_peer_is_floating(const fastd_peer_t *peer) { - return fastd_peer_config_is_floating(peer->config); + return (!VECTOR_LEN(peer->remotes) || peer->floating); } /** Checks if a peer is not statically configured, but added after a on-verify run */ static inline bool fastd_peer_is_dynamic(const fastd_peer_t *peer UNUSED) { #ifdef WITH_DYNAMIC_PEERS - return peer->config->config_state == CONFIG_DYNAMIC; + return peer->config_state == CONFIG_DYNAMIC; #else return false; #endif @@ -249,7 +220,7 @@ static inline bool fastd_peer_is_dynamic(const fastd_peer_t *peer UNUSED) { /** Checks if a peer is enabled */ static inline bool fastd_peer_is_enabled(const fastd_peer_t *peer) { - switch (peer->config->config_state) { + switch (peer->config_state) { case CONFIG_STATIC: #ifdef WITH_DYNAMIC_PEERS case CONFIG_DYNAMIC: @@ -279,11 +250,6 @@ static inline bool fastd_peer_is_established(const fastd_peer_t *peer) { } } -/** Returns the peer's peer group */ -static inline const fastd_peer_group_t * fastd_peer_get_group(const fastd_peer_t *peer) { - return peer->config->group; -} - /** Signals that a valid packet was received from the peer */ static inline void fastd_peer_seen(fastd_peer_t *peer) { peer->timeout = fastd_in_seconds(PEER_STALE_TIME); diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c index d952a5e..080c555 100644 --- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c +++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c @@ -74,37 +74,26 @@ static fastd_protocol_config_t* protocol_init(void) { return protocol_config; } -/** Checks if a peer configuration is valid */ -static void protocol_peer_verify(fastd_peer_config_t *peer_conf) { - if (!peer_conf->key) - exit_error("no key configured for peer `%s'", peer_conf->name); - - aligned_int256_t key; - if (!read_key(key.u8, peer_conf->key)) - exit_error("invalid key configured for peer `%s'", peer_conf->name); -} - -/** Initializes the protocol-specific peer configuration */ -static void protocol_peer_configure(fastd_peer_config_t *peer_conf) { - if (peer_conf->protocol_config) - return; +/** Parses a peer's key */ +static fastd_protocol_key_t * protocol_read_key(const char *key) { + fastd_protocol_key_t *ret = fastd_new(fastd_protocol_key_t); - if (!peer_conf->key) { - pr_warn("no key configured for `%s', disabling peer", peer_conf->name); - return; + if (!read_key(ret->key.u8, key)) { + free(ret); + return NULL; } - aligned_int256_t key; - if (!read_key(key.u8, peer_conf->key)) { - pr_warn("invalid key configured for `%s', disabling peer", peer_conf->name); - return; - } + return ret; +} - peer_conf->protocol_config = fastd_new(fastd_protocol_peer_config_t); - peer_conf->protocol_config->public_key = key; +/** Checks if a peer is configured using our own key */ +static bool protocol_check_peer(const fastd_peer_t *peer) { + if (memcmp(conf.protocol_config->key.public.u8, peer->key->key.u8, PUBLICKEYBYTES) == 0) { + pr_verbose("found own key as %P, ignoring peer", peer); + return false; + } - if (memcmp(&peer_conf->protocol_config->public_key, &conf.protocol_config->key.public, PUBLICKEYBYTES) == 0) - pr_debug("found own key as `%s', ignoring peer", peer_conf->name); + return true; } /** Checks if the current session with a peer is valid and resets the connection if not */ @@ -215,11 +204,6 @@ const fastd_protocol_t fastd_protocol_ec25519_fhmqvc = { .name = "ec25519-fhmqvc", .init = protocol_init, - .peer_verify = protocol_peer_verify, - .peer_configure = protocol_peer_configure, - - .peer_check = fastd_protocol_ec25519_fhmqvc_peer_check, - .peer_check_dynamic = fastd_protocol_ec25519_fhmqvc_peer_check_dynamic, .handshake_init = fastd_protocol_ec25519_fhmqvc_handshake_init, .handshake_handle = fastd_protocol_ec25519_fhmqvc_handshake_handle, @@ -234,8 +218,13 @@ const fastd_protocol_t fastd_protocol_ec25519_fhmqvc = { .reset_peer_state = fastd_protocol_ec25519_fhmqvc_reset_peer_state, .free_peer_state = fastd_protocol_ec25519_fhmqvc_free_peer_state, + .read_key = protocol_read_key, + .check_peer = protocol_check_peer, + .find_peer = fastd_protocol_ec25519_fhmqvc_find_peer, + .generate_key = fastd_protocol_ec25519_fhmqvc_generate_key, .show_key = fastd_protocol_ec25519_fhmqvc_show_key, + .set_shell_env = fastd_protocol_ec25519_fhmqvc_set_shell_env, .describe_peer = fastd_protocol_ec25519_fhmqvc_describe_peer, }; diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h index 529dd15..55696c1 100644 --- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h +++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h @@ -65,9 +65,9 @@ struct fastd_protocol_config { keypair_t key; /**< The own keypair */ }; -/** The protocol-specific peer configuration */ -struct fastd_protocol_peer_config { - aligned_int256_t public_key; /**< The peer's public key */ +/** A peer's public key */ +struct fastd_protocol_key { + aligned_int256_t key; /**< The peer's public key */ }; /** Session state */ @@ -101,9 +101,6 @@ struct fastd_protocol_peer_state { }; -bool fastd_protocol_ec25519_fhmqvc_peer_check(fastd_peer_config_t *peer_conf); -bool fastd_protocol_ec25519_fhmqvc_peer_check_dynamic(fastd_peer_t *peer); - void fastd_protocol_ec25519_fhmqvc_maintenance(void); void fastd_protocol_ec25519_fhmqvc_init_peer_state(fastd_peer_t *peer); void fastd_protocol_ec25519_fhmqvc_reset_peer_state(fastd_peer_t *peer); @@ -118,8 +115,11 @@ void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fast void fastd_protocol_ec25519_fhmqvc_send_empty(fastd_peer_t *peer, protocol_session_t *session); +fastd_peer_t * fastd_protocol_ec25519_fhmqvc_find_peer(const fastd_protocol_key_t *key); + void fastd_protocol_ec25519_fhmqvc_generate_key(void); void fastd_protocol_ec25519_fhmqvc_show_key(void); + void fastd_protocol_ec25519_fhmqvc_set_shell_env(fastd_shell_env_t *env, const fastd_peer_t *peer); bool fastd_protocol_ec25519_fhmqvc_describe_peer(const fastd_peer_t *peer, char *buf, size_t len); diff --git a/src/protocols/ec25519_fhmqvc/handshake.c b/src/protocols/ec25519_fhmqvc/handshake.c index 86f9f9e..8f468cd 100644 --- a/src/protocols/ec25519_fhmqvc/handshake.c +++ b/src/protocols/ec25519_fhmqvc/handshake.c @@ -277,7 +277,7 @@ static bool update_shared_handshake_key(const fastd_peer_t *peer, const handshak bool compat = !conf.secure_handshakes; if (!make_shared_handshake_key(&handshake_key->key.secret, false, - &peer->config->protocol_config->public_key, + &peer->key->key, &conf.protocol_config->key.public, peer_handshake_key, &handshake_key->key.public, @@ -315,7 +315,7 @@ 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_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->config->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key); fastd_handshake_add(&buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, &handshake_key->key.public); fastd_handshake_add(&buffer, RECORD_RECIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); @@ -344,7 +344,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l fastd_sha256_t shared_handshake_key, shared_handshake_key_compat; if (!make_shared_handshake_key(&handshake_key->key.secret, true, &conf.protocol_config->key.public, - &peer->config->protocol_config->public_key, + &peer->key->key, &handshake_key->key.public, peer_handshake_key, &sigma, @@ -361,7 +361,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l valid = fastd_hmacsha256_verify(mac, shared_handshake_key.w, handshake->tlv_data, handshake->tlv_len); } else { - valid = fastd_hmacsha256_blocks_verify(handshake->records[RECORD_T].data, shared_handshake_key_compat.w, peer->config->protocol_config->public_key.u32, peer_handshake_key->u32, NULL); + valid = fastd_hmacsha256_blocks_verify(handshake->records[RECORD_T].data, shared_handshake_key_compat.w, peer->key->key.u32, peer_handshake_key->u32, NULL); } if (!valid) { @@ -370,13 +370,13 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l } if (!establish(peer, method, sock, local_addr, remote_addr, true, &handshake_key->key.public, peer_handshake_key, &conf.protocol_config->key.public, - &peer->config->protocol_config->public_key, &sigma, compat ? NULL : shared_handshake_key.w, handshake_key->serial)) + &peer->key->key, &sigma, compat ? NULL : shared_handshake_key.w, handshake_key->serial)) return; 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_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->config->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key); fastd_handshake_add(&buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, &handshake_key->key.public); fastd_handshake_add(&buffer, RECORD_RECIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key); @@ -415,7 +415,7 @@ static void handle_finish_handshake(fastd_socket_t *sock, const fastd_peer_addre valid = fastd_hmacsha256_verify(mac, peer->protocol_state->shared_handshake_key.w, handshake->tlv_data, handshake->tlv_len); } else { - valid = fastd_hmacsha256_blocks_verify(handshake->records[RECORD_T].data, peer->protocol_state->shared_handshake_key_compat.w, peer->config->protocol_config->public_key.u32, peer_handshake_key->u32, NULL); + valid = fastd_hmacsha256_blocks_verify(handshake->records[RECORD_T].data, peer->protocol_state->shared_handshake_key_compat.w, peer->key->key.u32, peer_handshake_key->u32, NULL); } if (!valid) { @@ -423,14 +423,14 @@ static void handle_finish_handshake(fastd_socket_t *sock, const fastd_peer_addre return; } - establish(peer, method, sock, local_addr, remote_addr, false, peer_handshake_key, &handshake_key->key.public, &peer->config->protocol_config->public_key, + establish(peer, method, sock, local_addr, remote_addr, false, peer_handshake_key, &handshake_key->key.public, &peer->key->key, &conf.protocol_config->key.public, &peer->protocol_state->sigma, compat ? NULL : peer->protocol_state->shared_handshake_key.w, handshake_key->serial); 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]) { +/** Searches the peer a public key belongs to, optionally restricting matches to a specific sender address */ +static fastd_peer_t * find_key(const uint8_t key[PUBLICKEYBYTES], const fastd_peer_address_t *address) { errno = 0; fastd_peer_t *ret = NULL; @@ -439,10 +439,13 @@ static fastd_peer_t* find_sender_key(const fastd_peer_address_t *address, const for (i = 0; i < VECTOR_LEN(ctx.peers); i++) { fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i); - if (!fastd_peer_is_enabled(peer)) + if (address && !fastd_peer_is_enabled(peer)) continue; - if (memcmp(&peer->config->protocol_config->public_key, key, PUBLICKEYBYTES) == 0) { + if (memcmp(&peer->key->key, key, PUBLICKEYBYTES) == 0) { + if (!address) + return peer; + if (!fastd_peer_matches_address(peer, address)) { errno = EPERM; return NULL; @@ -464,15 +467,20 @@ static fastd_peer_t* find_sender_key(const fastd_peer_address_t *address, const return ret; } +/** Searches the peer a public key belongs to (including disabled peers) */ +fastd_peer_t * fastd_protocol_ec25519_fhmqvc_find_peer(const fastd_protocol_key_t *key) { + return find_key(key->key.u8, NULL); +} + /** 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]) { +static fastd_peer_t * match_sender_key(const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const uint8_t key[PUBLICKEYBYTES]) { errno = 0; if (sock->peer && peer != sock->peer) exit_bug("packet without correct peer set on dynamic socket"); if (peer) { - if (memcmp(&peer->config->protocol_config->public_key, key, PUBLICKEYBYTES) == 0) + if (memcmp(&peer->key->key, key, PUBLICKEYBYTES) == 0) return peer; if (fastd_peer_owns_address(peer, address)) { @@ -481,41 +489,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; - - fastd_peer_config_t *p; - for (p = ctx.peer_configs; p; p = p->next) { - if (!p->protocol_config) - continue; - - if (memcmp(&p->protocol_config->public_key, key, PUBLICKEYBYTES) == 0) - ret++; - } - - 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; - - if (memcmp(&peer_conf->protocol_config->public_key, &conf.protocol_config->key.public, PUBLICKEYBYTES) == 0) - return false; - - if (key_count(peer_conf->protocol_config->public_key.u8) > 1) { - char buf[65]; - hexdump(buf, peer_conf->protocol_config->public_key.u8); - pr_warn("more than one peer is configured with key %s, disabling %s", buf, peer_conf->name); - return false; - } - - return true; + return find_key(key, address); } /** Sends an initial handshake (type 1) to a peer */ @@ -527,7 +501,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fa fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public); if (peer) { - fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->config->protocol_config->public_key); + fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key); pr_verbose("sending handshake to %P[%I]...", peer, remote_addr); } @@ -543,18 +517,6 @@ 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 dynamic peer (added after an on-verify command) can stay after new peers have been configured */ -bool fastd_protocol_ec25519_fhmqvc_peer_check_dynamic(fastd_peer_t *peer) { - if (key_count(peer->config->protocol_config->public_key.u8)) { - char buf[65]; - hexdump(buf, peer->config->protocol_config->public_key.u8); - pr_info("key %s is configured now, deleting dynamic peer.", buf); - return false; - } - - return true; -} - #ifdef WITH_DYNAMIC_PEERS @@ -576,15 +538,25 @@ static fastd_peer_t * add_dynamic(fastd_socket_t *sock, const fastd_peer_address return NULL; } - if (key_count(key)) { + if (memcmp(&conf.protocol_config->key.public, key, PUBLICKEYBYTES) == 0) { + pr_debug("ignoring handshake from %I (used our own key)", addr); + return NULL; + } + + if (find_key(key, NULL)) { pr_debug("ignoring handshake from %I (disabled key)", addr); return NULL; } - fastd_peer_t *peer = fastd_peer_add(NULL); + fastd_peer_t *peer = fastd_new0(fastd_peer_t); + peer->group = conf.peer_group; + peer->config_state = CONFIG_DYNAMIC; + + peer->key = fastd_new(fastd_protocol_key_t); + memcpy(&peer->key->key, key, PUBLICKEYBYTES); - peer->config->protocol_config = fastd_new(fastd_protocol_peer_config_t); - memcpy(&peer->config->protocol_config->public_key, key, PUBLICKEYBYTES); + if (!fastd_peer_add(peer)) + exit_bug("failed to add dynamic peer"); /* Ugly hack */ peer->protocol_state->last_serial--; diff --git a/src/protocols/ec25519_fhmqvc/util.c b/src/protocols/ec25519_fhmqvc/util.c index c716916..f34f709 100644 --- a/src/protocols/ec25519_fhmqvc/util.c +++ b/src/protocols/ec25519_fhmqvc/util.c @@ -80,8 +80,8 @@ void fastd_protocol_ec25519_fhmqvc_set_shell_env(fastd_shell_env_t *env, const f hexdump(buf, conf.protocol_config->key.public.u8); fastd_shell_env_set(env, "LOCAL_KEY", buf); - if (peer && peer->config->protocol_config) { - hexdump(buf, peer->config->protocol_config->public_key.u8); + if (peer) { + hexdump(buf, peer->key->key.u8); fastd_shell_env_set(env, "PEER_KEY", buf); } else { @@ -97,14 +97,12 @@ void fastd_protocol_ec25519_fhmqvc_set_shell_env(fastd_shell_env_t *env, const f public key. */ bool fastd_protocol_ec25519_fhmqvc_describe_peer(const fastd_peer_t *peer, char *buf, size_t len) { - if (peer && peer->config->protocol_config) { - char dumpbuf[65]; - - hexdump(dumpbuf, peer->config->protocol_config->public_key.u8); - snprintf(buf, len, "%.16s", dumpbuf); - return true; - } - else { + if (!peer->key) return false; - } + + char dumpbuf[65]; + hexdump(dumpbuf, peer->key->key.u8); + snprintf(buf, len, "%.16s", dumpbuf); + + return true; } diff --git a/src/receive.c b/src/receive.c index 7b00f2c..10f70e7 100644 --- a/src/receive.c +++ b/src/receive.c @@ -150,7 +150,7 @@ static inline void handle_socket_receive_known(fastd_socket_t *sock, const fastd /** Determines if packets from known addresses are accepted */ static inline bool allow_unknown_peers(void) { - return conf.has_floating || fastd_allow_verify(); + return ctx.has_floating || fastd_allow_verify(); } /** Handles a packet received from an unknown address */ diff --git a/src/resolve.c b/src/resolve.c index df48fec..048c1b3 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -121,7 +121,7 @@ void fastd_resolve_peer(fastd_peer_t *peer, fastd_remote_t *remote) { return; } - pr_verbose("resolving host `%s' for peer %P...", remote->config->hostname, peer); + pr_verbose("resolving host `%s' for peer %P...", remote->hostname, peer); remote->last_resolve_timeout = fastd_in_seconds(MIN_RESOLVE_INTERVAL); @@ -129,8 +129,8 @@ void fastd_resolve_peer(fastd_peer_t *peer, fastd_remote_t *remote) { arg->peer_id = peer->id; arg->remote = remote - VECTOR_DATA(peer->remotes); - arg->hostname = fastd_strdup(remote->config->hostname); - arg->constraints = remote->config->address; + arg->hostname = fastd_strdup(remote->hostname); + arg->constraints = remote->address; pthread_t thread; if ((errno = pthread_create(&thread, &ctx.detached_thread, resolve_peer, arg)) != 0) { diff --git a/src/types.h b/src/types.h index 3ab03a6..927d707 100644 --- a/src/types.h +++ b/src/types.h @@ -82,11 +82,9 @@ typedef union fastd_peer_address fastd_peer_address_t; typedef struct fastd_bind_address fastd_bind_address_t; typedef struct fastd_socket fastd_socket_t; typedef struct fastd_peer_group fastd_peer_group_t; -typedef struct fastd_peer_config fastd_peer_config_t; typedef struct fastd_eth_addr fastd_eth_addr_t; typedef struct fastd_peer fastd_peer_t; typedef struct fastd_peer_eth_addr fastd_peer_eth_addr_t; -typedef struct fastd_remote_config fastd_remote_config_t; typedef struct fastd_remote fastd_remote_t; typedef struct fastd_stats fastd_stats_t; typedef struct fastd_handshake_timeout fastd_handshake_timeout_t; @@ -124,7 +122,7 @@ typedef union fastd_block128 { /* May be defined by the protocol/method/crypto implementations however they like */ typedef struct fastd_protocol_config fastd_protocol_config_t; typedef struct fastd_protocol_state fastd_protocol_state_t; -typedef struct fastd_protocol_peer_config fastd_protocol_peer_config_t; +typedef struct fastd_protocol_key fastd_protocol_key_t; typedef struct fastd_protocol_peer_state fastd_protocol_peer_state_t; typedef struct fastd_method fastd_method_t; -- cgit v1.2.3