From 51a1da3272c58e631fc5cecb181327bcceb5f311 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 14 Jan 2015 00:59:49 +0100 Subject: Allow to configure methods per peer group --- src/config.c | 31 +++++++++++++++---- src/config.h | 2 +- src/config.y | 12 ++++---- src/fastd.h | 12 ++++++++ src/handshake.c | 52 ++++++++++++++++++-------------- src/handshake.h | 2 +- src/options.c | 2 +- src/peer.h | 15 +++++++++ src/protocols/ec25519_fhmqvc/handshake.c | 4 +-- 9 files changed, 92 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/config.c b/src/config.c index 7b87dcf..7a0cb4e 100644 --- a/src/config.c +++ b/src/config.c @@ -80,10 +80,10 @@ void fastd_config_protocol(const char *name) { } /** Handles the configuration of a crypto method */ -void fastd_config_method(const char *name) { +void fastd_config_method(fastd_peer_group_t *group, const char *name) { fastd_string_stack_t **method; - for (method = &conf.method_list; *method; method = &(*method)->next) { + for (method = &group->methods; *method; method = &(*method)->next) { if (!strcmp((*method)->str, name)) { pr_debug("duplicate method name `%s', ignoring", name); return; @@ -168,6 +168,7 @@ static void free_peer_group(fastd_peer_group_t *group) { } fastd_string_stack_free(group->peer_dirs); + fastd_string_stack_free(group->methods); free(group->name); free(group); } @@ -467,12 +468,30 @@ static void configure_method_parameters(void) { conf.min_decrypt_head_space = alignto(conf.min_decrypt_head_space, 16) + 8; } + +/** Collects a list of the configured methods of all peer groups */ +static void collect_methods(const fastd_peer_group_t *group, size_t *count) { + const fastd_string_stack_t *method; + + for (method = group->methods; method; method = method->next) { + if (!fastd_string_stack_contains(conf.method_list, method->str)) { + conf.method_list = fastd_string_stack_push(conf.method_list, method->str); + (*count)++; + } + } + + const fastd_peer_group_t *sub; + for (sub = group->children; sub; sub = sub->next) + collect_methods(sub, count); +} + + /** Handles the initialization of the configured methods */ static void configure_methods(void) { size_t n_methods = 0, i; fastd_string_stack_t *method_name; - for (method_name = conf.method_list; method_name; method_name = method_name->next) - n_methods++; + + collect_methods(conf.peer_group, &n_methods); conf.methods = fastd_new0_array(n_methods+1, fastd_method_info_t); @@ -546,9 +565,9 @@ void fastd_config_check(void) { 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) { + if (!conf.peer_group->methods) { pr_warn("no encryption method configured, falling back to method `null' (unencrypted)"); - fastd_config_method("null"); + fastd_config_method(conf.peer_group, "null"); } configure_user(); diff --git a/src/config.h b/src/config.h index b076266..b8ef95d 100644 --- a/src/config.h +++ b/src/config.h @@ -46,7 +46,7 @@ struct fastd_parser_state { void fastd_config_protocol(const char *name); -void fastd_config_method(const char *name); +void fastd_config_method(fastd_peer_group_t *group, const char *name); void fastd_config_cipher(const char *name, const char *impl); void fastd_config_mac(const char *name, const char *impl); void fastd_config_bind_address(const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6); diff --git a/src/config.y b/src/config.y index bd106e7..c4d7eaa 100644 --- a/src/config.y +++ b/src/config.y @@ -191,7 +191,6 @@ statement: peer_group_statement | TOK_PMTU pmtu ';' | TOK_MODE mode ';' | TOK_PROTOCOL protocol ';' - | TOK_METHOD method ';' | TOK_SECRET secret ';' | TOK_ON TOK_PRE_UP on_pre_up ';' | TOK_ON TOK_UP on_up ';' @@ -209,6 +208,7 @@ peer_group_statement: 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_METHOD method ';' | TOK_INCLUDE include ';' ; @@ -371,11 +371,6 @@ protocol: TOK_STRING { } ; -method: TOK_STRING { - fastd_config_method($1->str); - } - ; - secret: TOK_STRING { free(conf.secret); conf.secret = fastd_strdup($1->str); } ; @@ -546,6 +541,11 @@ peer_limit: TOK_UINT { } ; +method: TOK_STRING { + fastd_config_method(state->peer_group, $1->str); + } + ; + forward: boolean { conf.forward = $1; } ; diff --git a/src/fastd.h b/src/fastd.h index 8af0556..6e4cda6 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -450,6 +450,18 @@ static inline const char * fastd_string_stack_get(const fastd_string_stack_t *st return stack ? stack->str : NULL; } +/** */ +static inline bool fastd_string_stack_contains(const fastd_string_stack_t *stack, const char *str) { + while (stack) { + if (strcmp(stack->str, str) == 0) + return true; + + stack = stack->next; + } + + return false; +} + /** Frees a whole string stack */ static inline void fastd_string_stack_free(fastd_string_stack_t *str) { while (str) { diff --git a/src/handshake.c b/src/handshake.c index 2c22655..1bb18a1 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -105,16 +105,17 @@ static inline uint32_t as_uint(const fastd_handshake_record_t *record) { /** Generates a zero-separated list of supported methods */ -static uint8_t * create_method_list(size_t *len) { - size_t n, i; - for (n = 0; conf.methods[n].name; n++) { - } +static uint8_t * create_method_list(const fastd_string_stack_t *methods, size_t *len) { + size_t n = 0, i; + const fastd_string_stack_t *method; + for (method = methods; method; method = method->next) + n++; *len = 0; size_t lens[n]; - for (i = 0; i < n; i++) { - lens[i] = strlen(conf.methods[i].name) + 1; + for (method = methods, i = 0; method; method = method->next, i++) { + lens[i] = strlen(method->str) + 1; *len += lens[i]; } @@ -123,8 +124,8 @@ static uint8_t * create_method_list(size_t *len) { uint8_t *ptr = ret; - for (i = 0; i < n; i++) { - memcpy(ptr, conf.methods[i].name, lens[i]); + for (method = methods, i = 0; method; method = method->next, i++) { + memcpy(ptr, method->str, lens[i]); ptr += lens[i]; } @@ -160,7 +161,7 @@ static fastd_string_stack_t * parse_string_list(const uint8_t *data, size_t len) } /** Allocates and initializes a new handshake packet */ -static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) { +static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, const fastd_method_info_t *method, const fastd_string_stack_t *methods, size_t tail_space) { size_t version_len = strlen(FASTD_VERSION); size_t protocol_len = strlen(conf.protocol->name); size_t method_len = method ? strlen(method->name) : 0; @@ -168,8 +169,8 @@ static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, size_t method_list_len = 0; uint8_t *method_list = NULL; - if (with_method_list) - method_list = create_method_list(&method_list_len); + if (methods) + method_list = create_method_list(methods, &method_list_len); fastd_handshake_buffer_t buffer = { .buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 1, @@ -193,10 +194,10 @@ static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, fastd_handshake_add(&buffer, RECORD_VERSION_NAME, version_len, FASTD_VERSION); fastd_handshake_add(&buffer, RECORD_PROTOCOL_NAME, protocol_len, conf.protocol->name); - if (method && (!with_method_list || !conf.secure_handshakes)) + if (method && (!methods || !conf.secure_handshakes)) fastd_handshake_add(&buffer, RECORD_METHOD_NAME, method_len, method->name); - if (with_method_list) { + if (methods) { fastd_handshake_add(&buffer, RECORD_METHOD_LIST, method_list_len, method_list); free(method_list); } @@ -206,12 +207,12 @@ static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, /** Allocates and initializes a new initial handshake packet */ fastd_handshake_buffer_t fastd_handshake_new_init(size_t tail_space) { - return new_handshake(1, true, NULL, !conf.secure_handshakes, tail_space); + return new_handshake(1, true, NULL, conf.secure_handshakes ? NULL : conf.peer_group->methods, tail_space); } /** Allocates and initializes a new reply handshake packet */ -fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) { - fastd_handshake_buffer_t buffer = new_handshake(type, little_endian, method, with_method_list, tail_space); +fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, const fastd_string_stack_t *methods, size_t tail_space) { + fastd_handshake_buffer_t buffer = new_handshake(type, little_endian, method, methods, tail_space); fastd_handshake_add_uint8(&buffer, RECORD_REPLY_CODE, 0); return buffer; } @@ -390,16 +391,19 @@ static inline bool check_records(fastd_socket_t *sock, const fastd_peer_address_ } /** Returns the method info with a specified name and length */ -static inline const fastd_method_info_t * get_method_by_name(const char *name, size_t n) { +static inline const fastd_method_info_t * get_method_by_name(const fastd_string_stack_t *methods, const char *name, size_t n) { char name0[n+1]; memcpy(name0, name, n); name0[n] = 0; + if (!fastd_string_stack_contains(methods, name0)) + return NULL; + return fastd_method_get_by_name(name0); } /** Returns the most appropriate method to negotiate with a peer a handshake was received from */ -static inline const fastd_method_info_t * get_method(const fastd_handshake_t *handshake) { +static inline const fastd_method_info_t * get_method(const fastd_string_stack_t *methods, const fastd_handshake_t *handshake) { if (handshake->records[RECORD_METHOD_LIST].data && handshake->records[RECORD_METHOD_LIST].length) { fastd_string_stack_t *method_list = parse_string_list(handshake->records[RECORD_METHOD_LIST].data, handshake->records[RECORD_METHOD_LIST].length); @@ -407,10 +411,12 @@ static inline const fastd_method_info_t * get_method(const fastd_handshake_t *ha fastd_string_stack_t *method_name; for (method_name = method_list; method_name; method_name = method_name->next) { - const fastd_method_info_t *cur_method = fastd_method_get_by_name(method_name->str); + if (!fastd_string_stack_contains(methods, method_name->str)) + continue; - if (cur_method) - method = cur_method; + method = fastd_method_get_by_name(method_name->str); + if (!method) + exit_bug("get_method: can't find configured method"); } fastd_string_stack_free(method_list); @@ -421,7 +427,7 @@ static inline const fastd_method_info_t * get_method(const fastd_handshake_t *ha if (!handshake->records[RECORD_METHOD_NAME].data) return NULL; - return get_method_by_name((const char *)handshake->records[RECORD_METHOD_NAME].data, handshake->records[RECORD_METHOD_NAME].length); + return get_method_by_name(methods, (const char *)handshake->records[RECORD_METHOD_NAME].data, handshake->records[RECORD_METHOD_NAME].length); } /** Handles a handshake packet */ @@ -447,7 +453,7 @@ void fastd_handshake_handle(fastd_socket_t *sock, const fastd_peer_address_t *lo goto end_free; if (!conf.secure_handshakes || handshake.type > 1) { - method = get_method(&handshake); + method = get_method(fastd_peer_get_methods(peer), &handshake); if (handshake.records[RECORD_VERSION_NAME].data) handshake.peer_version = peer_version = fastd_strndup((const char *)handshake.records[RECORD_VERSION_NAME].data, handshake.records[RECORD_VERSION_NAME].length); diff --git a/src/handshake.h b/src/handshake.h index f432f64..70d7a16 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -100,7 +100,7 @@ struct fastd_handshake_buffer { fastd_handshake_buffer_t fastd_handshake_new_init(size_t tail_space); -fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space); +fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, const fastd_string_stack_t *methods, size_t tail_space); void fastd_handshake_handle(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); diff --git a/src/options.c b/src/options.c index 2a67f13..b54c086 100644 --- a/src/options.c +++ b/src/options.c @@ -315,7 +315,7 @@ static void option_protocol(const char *arg) { /** Handles the --method option */ static void option_method(const char *arg) { - fastd_config_method(arg); + fastd_config_method(conf.peer_group, arg); } /** Handles the --forward option */ diff --git a/src/peer.h b/src/peer.h index ca03e2f..3181544 100644 --- a/src/peer.h +++ b/src/peer.h @@ -121,6 +121,7 @@ struct fastd_peer_group { /* constraints */ int max_connections; /**< The maximum number of connections to allow in this group; -1 for no limit */ + fastd_string_stack_t *methods; /**< The list of configured method names */ }; /** An entry for a MAC address seen at another peer */ @@ -265,6 +266,20 @@ static inline bool fastd_peer_is_socket_dynamic(const fastd_peer_t *peer) { return (!peer->sock || !peer->sock->addr); } +/** Returns the configured methods for a peer's group */ +static inline const fastd_string_stack_t * fastd_peer_get_methods(const fastd_peer_t *peer) { + if (!peer) + return conf.peer_group->methods; + + const fastd_peer_group_t *group; + for (group = peer->group; group; group = group->parent) { + if (group->methods) + return group->methods; + } + + return NULL; +} + /** Checks if a MAC address is a normal unicast address */ static inline bool fastd_eth_addr_is_unicast(fastd_eth_addr_t addr) { return ((addr.data[0] & 1) == 0); diff --git a/src/protocols/ec25519_fhmqvc/handshake.c b/src/protocols/ec25519_fhmqvc/handshake.c index 2daa709..a6dfc67 100644 --- a/src/protocols/ec25519_fhmqvc/handshake.c +++ b/src/protocols/ec25519_fhmqvc/handshake.c @@ -306,7 +306,7 @@ static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_addre if (!update_shared_handshake_key(peer, handshake_key, peer_handshake_key)) return; - fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(2, little_endian, method, true, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES)); + fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(2, little_endian, method, fastd_peer_get_methods(peer), 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->key->key); @@ -365,7 +365,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l &peer->key->key, &sigma, compat ? NULL : shared_handshake_key.w, handshake_key->serial)) return; - fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(3, handshake->little_endian, method, false, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES)); + fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(3, handshake->little_endian, method, NULL, 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->key->key); -- cgit v1.2.3