Allow to configure methods per peer group

This commit is contained in:
Matthias Schiffer 2015-01-14 00:59:49 +01:00
parent 7815904f11
commit 51a1da3272
9 changed files with 92 additions and 40 deletions

View file

@ -80,10 +80,10 @@ void fastd_config_protocol(const char *name) {
} }
/** Handles the configuration of a crypto method */ /** 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; 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)) { if (!strcmp((*method)->str, name)) {
pr_debug("duplicate method name `%s', ignoring", name); pr_debug("duplicate method name `%s', ignoring", name);
return; 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->peer_dirs);
fastd_string_stack_free(group->methods);
free(group->name); free(group->name);
free(group); 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; 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 */ /** Handles the initialization of the configured methods */
static void configure_methods(void) { static void configure_methods(void) {
size_t n_methods = 0, i; size_t n_methods = 0, i;
fastd_string_stack_t *method_name; 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); 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)) 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"); 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)"); 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(); configure_user();

View file

@ -46,7 +46,7 @@ struct fastd_parser_state {
void fastd_config_protocol(const char *name); 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_cipher(const char *name, const char *impl);
void fastd_config_mac(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); void fastd_config_bind_address(const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6);

View file

@ -191,7 +191,6 @@ statement: peer_group_statement
| TOK_PMTU pmtu ';' | TOK_PMTU pmtu ';'
| TOK_MODE mode ';' | TOK_MODE mode ';'
| TOK_PROTOCOL protocol ';' | TOK_PROTOCOL protocol ';'
| TOK_METHOD method ';'
| TOK_SECRET secret ';' | TOK_SECRET secret ';'
| TOK_ON TOK_PRE_UP on_pre_up ';' | TOK_ON TOK_PRE_UP on_pre_up ';'
| TOK_ON TOK_UP on_up ';' | TOK_ON TOK_UP on_up ';'
@ -209,6 +208,7 @@ peer_group_statement:
TOK_PEER peer '{' peer_conf '}' peer_after TOK_PEER peer '{' peer_conf '}' peer_after
| TOK_PEER TOK_GROUP peer_group '{' peer_group_config '}' peer_group_after | TOK_PEER TOK_GROUP peer_group '{' peer_group_config '}' peer_group_after
| TOK_PEER TOK_LIMIT peer_limit ';' | TOK_PEER TOK_LIMIT peer_limit ';'
| TOK_METHOD method ';'
| TOK_INCLUDE include ';' | 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); } 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; } forward: boolean { conf.forward = $1; }
; ;

View file

@ -450,6 +450,18 @@ static inline const char * fastd_string_stack_get(const fastd_string_stack_t *st
return stack ? stack->str : NULL; 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 */ /** Frees a whole string stack */
static inline void fastd_string_stack_free(fastd_string_stack_t *str) { static inline void fastd_string_stack_free(fastd_string_stack_t *str) {
while (str) { while (str) {

View file

@ -105,16 +105,17 @@ static inline uint32_t as_uint(const fastd_handshake_record_t *record) {
/** Generates a zero-separated list of supported methods */ /** Generates a zero-separated list of supported methods */
static uint8_t * create_method_list(size_t *len) { static uint8_t * create_method_list(const fastd_string_stack_t *methods, size_t *len) {
size_t n, i; size_t n = 0, i;
for (n = 0; conf.methods[n].name; n++) { const fastd_string_stack_t *method;
} for (method = methods; method; method = method->next)
n++;
*len = 0; *len = 0;
size_t lens[n]; size_t lens[n];
for (i = 0; i < n; i++) { for (method = methods, i = 0; method; method = method->next, i++) {
lens[i] = strlen(conf.methods[i].name) + 1; lens[i] = strlen(method->str) + 1;
*len += lens[i]; *len += lens[i];
} }
@ -123,8 +124,8 @@ static uint8_t * create_method_list(size_t *len) {
uint8_t *ptr = ret; uint8_t *ptr = ret;
for (i = 0; i < n; i++) { for (method = methods, i = 0; method; method = method->next, i++) {
memcpy(ptr, conf.methods[i].name, lens[i]); memcpy(ptr, method->str, lens[i]);
ptr += 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 */ /** 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 version_len = strlen(FASTD_VERSION);
size_t protocol_len = strlen(conf.protocol->name); size_t protocol_len = strlen(conf.protocol->name);
size_t method_len = method ? strlen(method->name) : 0; 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; size_t method_list_len = 0;
uint8_t *method_list = NULL; uint8_t *method_list = NULL;
if (with_method_list) if (methods)
method_list = create_method_list(&method_list_len); method_list = create_method_list(methods, &method_list_len);
fastd_handshake_buffer_t buffer = { fastd_handshake_buffer_t buffer = {
.buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 1, .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_VERSION_NAME, version_len, FASTD_VERSION);
fastd_handshake_add(&buffer, RECORD_PROTOCOL_NAME, protocol_len, conf.protocol->name); 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); 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); fastd_handshake_add(&buffer, RECORD_METHOD_LIST, method_list_len, method_list);
free(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 */ /** Allocates and initializes a new initial handshake packet */
fastd_handshake_buffer_t fastd_handshake_new_init(size_t tail_space) { 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 */ /** 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 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, with_method_list, 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); fastd_handshake_add_uint8(&buffer, RECORD_REPLY_CODE, 0);
return buffer; 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 */ /** 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]; char name0[n+1];
memcpy(name0, name, n); memcpy(name0, name, n);
name0[n] = 0; name0[n] = 0;
if (!fastd_string_stack_contains(methods, name0))
return NULL;
return fastd_method_get_by_name(name0); return fastd_method_get_by_name(name0);
} }
/** Returns the most appropriate method to negotiate with a peer a handshake was received from */ /** 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) { 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); 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; fastd_string_stack_t *method_name;
for (method_name = method_list; method_name; method_name = method_name->next) { 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 = fastd_method_get_by_name(method_name->str);
method = cur_method; if (!method)
exit_bug("get_method: can't find configured method");
} }
fastd_string_stack_free(method_list); 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) if (!handshake->records[RECORD_METHOD_NAME].data)
return NULL; 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 */ /** 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; goto end_free;
if (!conf.secure_handshakes || handshake.type > 1) { 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) 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); handshake.peer_version = peer_version = fastd_strndup((const char *)handshake.records[RECORD_VERSION_NAME].data, handshake.records[RECORD_VERSION_NAME].length);

View file

@ -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_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); 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);

View file

@ -315,7 +315,7 @@ static void option_protocol(const char *arg) {
/** Handles the --method option */ /** Handles the --method option */
static void option_method(const char *arg) { static void option_method(const char *arg) {
fastd_config_method(arg); fastd_config_method(conf.peer_group, arg);
} }
/** Handles the --forward option */ /** Handles the --forward option */

View file

@ -121,6 +121,7 @@ struct fastd_peer_group {
/* constraints */ /* constraints */
int max_connections; /**< The maximum number of connections to allow in this group; -1 for no limit */ 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 */ /** 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); 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 */ /** Checks if a MAC address is a normal unicast address */
static inline bool fastd_eth_addr_is_unicast(fastd_eth_addr_t addr) { static inline bool fastd_eth_addr_is_unicast(fastd_eth_addr_t addr) {
return ((addr.data[0] & 1) == 0); return ((addr.data[0] & 1) == 0);

View file

@ -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)) if (!update_shared_handshake_key(peer, handshake_key, peer_handshake_key))
return; 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_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public);
fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key); 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)) &peer->key->key, &sigma, compat ? NULL : shared_handshake_key.w, handshake_key->serial))
return; 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_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public);
fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key); fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key);