diff options
-rw-r--r-- | src/config.c | 18 | ||||
-rw-r--r-- | src/fastd.c | 80 | ||||
-rw-r--r-- | src/fastd.h | 8 | ||||
-rw-r--r-- | src/peer.c | 25 | ||||
-rw-r--r-- | src/peer.h | 8 | ||||
-rw-r--r-- | src/protocol_ec25519_fhmqvc.c | 29 | ||||
-rw-r--r-- | src/resolve.c | 23 |
7 files changed, 127 insertions, 64 deletions
diff --git a/src/config.c b/src/config.c index e7c8640..d581ccf 100644 --- a/src/config.c +++ b/src/config.c @@ -292,20 +292,32 @@ static void count_peers(fastd_context *ctx, fastd_config *conf) { conf->n_floating = 0; conf->n_v4 = 0; conf->n_v6 = 0; + conf->n_dynamic = 0; + conf->n_dynamic_v4 = 0; + conf->n_dynamic_v6 = 0; fastd_peer_config *peer; for (peer = conf->peers; peer; peer = peer->next) { switch (peer->address.sa.sa_family) { case AF_UNSPEC: - conf->n_floating++; + if (peer->hostname) + conf->n_dynamic++; + else + conf->n_floating++; break; case AF_INET: - conf->n_v4++; + if (peer->hostname) + conf->n_dynamic_v4++; + else + conf->n_v4++; break; case AF_INET6: - conf->n_v6++; + if (peer->hostname) + conf->n_dynamic_v6++; + else + conf->n_v6++; break; default: diff --git a/src/fastd.c b/src/fastd.c index 59e5c54..ee7f03a 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -55,6 +55,9 @@ static void on_terminate(int signo) { } static void on_sigusr1(int signo, siginfo_t *siginfo, void *context) { + if (siginfo->si_code != SI_QUEUE || !siginfo->si_value.sival_ptr) + return; + fastd_resolve_return *ret = siginfo->si_value.sival_ptr; ret->next = ret->ctx->resolve_returns; @@ -133,10 +136,10 @@ static void init_sockets(fastd_context *ctx) { struct sockaddr_in6 addr_in6 = ctx->conf->bind_addr_in6; if (addr_in.sin_family == AF_UNSPEC && addr_in6.sin6_family == AF_UNSPEC) { - if (ctx->conf->n_floating || ctx->conf->peer_dirs || ctx->conf->n_v4) + if (ctx->conf->peer_dirs || ctx->conf->n_floating || ctx->conf->n_v4 || ctx->conf->n_dynamic || ctx->conf->n_dynamic_v4) addr_in.sin_family = AF_INET; - if (ctx->conf->n_floating || ctx->conf->peer_dirs || ctx->conf->n_v6) + if (ctx->conf->peer_dirs || ctx->conf->n_floating || ctx->conf->n_v6 || ctx->conf->n_dynamic || ctx->conf->n_dynamic_v6) addr_in6.sin6_family = AF_INET6; } @@ -362,13 +365,15 @@ static void delete_peers(fastd_context *ctx) { } } -static void update_time(fastd_context *ctx) { +static inline void update_time(fastd_context *ctx) { clock_gettime(CLOCK_MONOTONIC, &ctx->now); } -static void send_handshake(fastd_context *ctx, fastd_peer *peer) { - pr_debug(ctx, "sending handshake to %P...", peer); - ctx->conf->protocol->handshake_init(ctx, peer); +static inline void send_handshake(fastd_context *ctx, fastd_peer *peer) { + if (peer->address.sa.sa_family != AF_UNSPEC) { + pr_debug(ctx, "sending handshake to %P...", peer); + ctx->conf->protocol->handshake_init(ctx, peer); + } fastd_task_schedule_handshake(ctx, peer, fastd_rand(ctx, 17500, 22500)); } @@ -379,7 +384,7 @@ static void handle_tasks(fastd_context *ctx) { switch (task->type) { case TASK_HANDSHAKE: if (task->peer->state == STATE_RESOLVE) - fastd_resolve_peer_handshake(ctx, task->peer); + fastd_resolve_peer(ctx, task->peer->config); else send_handshake(ctx, task->peer); break; @@ -516,7 +521,9 @@ static void handle_socket(fastd_context *ctx, int sockfd) { fastd_buffer_free(buffer); } } - else if(ctx->conf->n_floating) { + else if(ctx->conf->n_floating || ctx->conf->n_dynamic || + (recvaddr.sa.sa_family == AF_INET && ctx->conf->n_dynamic_v4) || + (recvaddr.sa.sa_family == AF_INET6 && ctx->conf->n_dynamic_v6)) { switch (packet_type) { case PACKET_DATA: peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr); @@ -570,25 +577,51 @@ static void handle_input(fastd_context *ctx) { handle_socket(ctx, ctx->sock6fd); } +static void cleanup_peers(fastd_context *ctx) { + fastd_peer *peer, *next; + + for (peer = ctx->peers; peer; peer = next) { + next = peer->next; + + if (fastd_peer_is_temporary(peer)) { + if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time_temp*1000) + fastd_peer_reset(ctx, peer); + } + else if (fastd_peer_is_established(peer)) { + if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time*1000) + fastd_peer_reset(ctx, peer); + } + } +} + +static void cleanup_peer_with_address(fastd_context *ctx, const fastd_peer_address *addr) { + fastd_peer *peer; + for (peer = ctx->peers; peer; peer = peer->next) { + if (fastd_peer_is_temporary(peer) && fastd_peer_addr_equal(&peer->address, addr)) { + fastd_peer_reset(ctx, peer); + return; + } + } +} + static void handle_resolv_returns(fastd_context *ctx) { while (ctx->resolve_returns) { fastd_peer *peer; for (peer = ctx->peers; peer; peer = peer->next) { - if (peer->state != STATE_RESOLVE) + if (!peer->config) continue; if (!strequal(peer->config->hostname, ctx->resolve_returns->hostname)) continue; - if (peer->config->address.sa.sa_family != AF_UNSPEC && - peer->config->address.sa.sa_family != ctx->resolve_returns->addr.sa.sa_family) - continue; - - if (peer->config->address.in.sin_port != htons(ctx->resolve_returns->port)) + if (!fastd_peer_config_matches_dynamic(peer->config, &ctx->resolve_returns->constraints)) continue; + cleanup_peer_with_address(ctx, &ctx->resolve_returns->addr); peer->address = ctx->resolve_returns->addr; - send_handshake(ctx, peer); + + if (peer->state == STATE_RESOLVE) + send_handshake(ctx, peer); break; } @@ -599,23 +632,6 @@ static void handle_resolv_returns(fastd_context *ctx) { } } -static void cleanup_peers(fastd_context *ctx) { - fastd_peer *peer, *next; - - for (peer = ctx->peers; peer; peer = next) { - next = peer->next; - - if (fastd_peer_is_temporary(peer)) { - if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time_temp*1000) - fastd_peer_reset(ctx, peer); - } - else if (fastd_peer_is_established(peer)) { - if (timespec_diff(&ctx->now, &peer->seen) > ctx->conf->peer_stale_time*1000) - fastd_peer_reset(ctx, peer); - } - } -} - static void maintenance(fastd_context *ctx) { cleanup_peers(ctx); diff --git a/src/fastd.h b/src/fastd.h index c778b19..1fa4d17 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -103,8 +103,7 @@ struct _fastd_resolve_return { fastd_context *ctx; char *hostname; - sa_family_t af; - uint16_t port; + fastd_peer_address constraints; fastd_peer_address addr; }; @@ -139,6 +138,9 @@ struct _fastd_config { unsigned n_floating; unsigned n_v4; unsigned n_v6; + unsigned n_dynamic; + unsigned n_dynamic_v4; + unsigned n_dynamic_v6; fastd_protocol_config *protocol_config; @@ -188,7 +190,7 @@ void fastd_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); void fastd_send_handshake(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); -void fastd_resolve_peer_handshake(fastd_context *ctx, fastd_peer *peer); +void fastd_resolve_peer(fastd_context *ctx, const fastd_peer_config *peer); void fastd_printf(const fastd_context *ctx, const char *format, ...); @@ -251,7 +251,7 @@ void fastd_peer_config_purge(fastd_context *ctx, fastd_peer_config *conf) { fastd_peer_config_free(conf); } -static bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2) { +bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2) { if (addr1->sa.sa_family != addr2->sa.sa_family) return false; @@ -330,9 +330,6 @@ fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) { fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address) { fastd_peer *peer = add_peer(ctx); - if (!ctx->conf->n_floating) - exit_bug(ctx, "tried to add a temporary peer with no floating remotes defined"); - peer->config = NULL; peer->address = *address; peer->state = STATE_TEMP; @@ -409,6 +406,26 @@ const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buf } } +bool fastd_peer_config_matches_dynamic(const fastd_peer_config *config, const fastd_peer_address *addr) { + if (!config->hostname) + return false; + + if (config->address.sa.sa_family != AF_UNSPEC && + config->address.sa.sa_family != addr->sa.sa_family) + return false; + + if (addr->sa.sa_family == AF_INET6) { + if (config->address.in.sin_port != addr->in6.sin6_port) + return false; + } + else { + if (config->address.in.sin_port != addr->in.sin_port) + return false; + } + + return true; +} + static inline int fastd_eth_addr_cmp(const fastd_eth_addr *addr1, const fastd_eth_addr *addr2) { return memcmp(addr1->data, addr2->data, ETH_ALEN); } @@ -67,6 +67,8 @@ struct _fastd_peer_eth_addr { }; +bool fastd_peer_addr_equal(const fastd_peer_address *addr1, const fastd_peer_address *addr2); + fastd_peer_config* fastd_peer_config_new(fastd_context *ctx, fastd_config *conf); void fastd_peer_config_free(fastd_peer_config *peer); void fastd_peer_config_delete(fastd_context *ctx, fastd_config *conf); @@ -87,10 +89,16 @@ static inline bool fastd_peer_config_is_floating(const fastd_peer_config *config return (config->hostname == NULL && config->address.sa.sa_family == AF_UNSPEC); } +bool fastd_peer_config_matches_dynamic(const fastd_peer_config *config, const fastd_peer_address *addr); + static inline bool fastd_peer_is_floating(const fastd_peer *peer) { return (peer->config && fastd_peer_config_is_floating(peer->config)); } +static inline bool fastd_peer_is_dynamic(const fastd_peer *peer) { + return (peer->config && peer->config->hostname); +} + static inline bool fastd_peer_is_waiting(const fastd_peer *peer) { return (peer->state == STATE_WAIT); } diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c index b4dab07..93fd9c4 100644 --- a/src/protocol_ec25519_fhmqvc.c +++ b/src/protocol_ec25519_fhmqvc.c @@ -245,10 +245,6 @@ static void protocol_handshake_init(fastd_context *ctx, fastd_peer *peer) { fastd_send_handshake(ctx, peer, buffer); } -static inline bool has_field(const fastd_handshake *handshake, uint8_t type, size_t length) { - return (handshake->records[type].length == length); -} - static void respond_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { pr_debug(ctx, "responding handshake with %P...", peer); @@ -454,20 +450,27 @@ static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, const &peer->protocol_state->accepting_handshake->sigma); } -static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer *peer, const unsigned char key[32]) { +static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, fastd_peer *peer, const unsigned char key[32]) { if (peer->config) { if (memcmp(peer->config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) return peer->config; } - if (fastd_peer_is_temporary(peer) || fastd_peer_is_floating(peer)) { + if (fastd_peer_is_temporary(peer) || fastd_peer_is_floating(peer) || fastd_peer_is_dynamic(peer)) { fastd_peer_config *config; for (config = ctx->conf->peers; config; config = config->next) { - if (!fastd_peer_config_is_floating(config)) + if (!fastd_peer_config_is_floating(config) && !fastd_peer_config_matches_dynamic(config, &peer->address)) continue; - if (memcmp(config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) - return config; + if (memcmp(config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) { + if (fastd_peer_config_is_floating(config)) { + return config; + } + else { /* matches dynamic */ + fastd_resolve_peer(ctx, config); + return NULL; + } + } } } @@ -484,6 +487,10 @@ static void kill_handshakes(fastd_context *ctx, fastd_peer *peer) { peer->protocol_state->accepting_handshake = NULL; } +static inline bool has_field(const fastd_handshake *handshake, uint8_t type, size_t length) { + return (handshake->records[type].length == length); +} + static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { init_peer_state(ctx, peer); @@ -493,6 +500,10 @@ static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, cons } const fastd_peer_config *peer_config = match_sender_key(ctx, peer, handshake->records[RECORD_SENDER_KEY].data); + if (!peer_config) { + pr_debug(ctx, "ignoring handshake from %P (unknown key or unresolved host)", peer); + return; + } if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) { pr_debug(ctx, "received handshake reply without receipient key from %P", peer); diff --git a/src/resolve.c b/src/resolve.c index 1fbb1bf..6afea91 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -38,12 +38,11 @@ typedef struct _resolv_arg { fastd_context *ctx; pthread_t master_thread; char *hostname; - sa_family_t af; - uint16_t port; + fastd_peer_address constraints; } resolv_arg; -static void* fastd_resolve_peer_handshake_do(void *varg) { +static void* resolve_peer(void *varg) { resolv_arg *arg = varg; struct addrinfo hints; @@ -52,10 +51,10 @@ static void* fastd_resolve_peer_handshake_do(void *varg) { bool error = false; char portstr[6]; - snprintf(portstr, 6, "%u", arg->port); + snprintf(portstr, 6, "%u", ntohs(arg->constraints.in.sin_port)); memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = arg->af; + hints.ai_family = arg->constraints.sa.sa_family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG; @@ -79,8 +78,7 @@ static void* fastd_resolve_peer_handshake_do(void *varg) { ret->ctx = arg->ctx; ret->hostname = arg->hostname; - ret->af = arg->af; - ret->port = arg->port; + ret->constraints = arg->constraints; if (!error) { pr_debug(arg->ctx, "Resolved host `%s' successfully", arg->hostname); @@ -101,19 +99,18 @@ static void* fastd_resolve_peer_handshake_do(void *varg) { return NULL; } -void fastd_resolve_peer_handshake(fastd_context *ctx, fastd_peer *peer) { - pr_debug(ctx, "Resolving host `%s' for peer %P...", peer->config->hostname, peer); +void fastd_resolve_peer(fastd_context *ctx, const fastd_peer_config *peer) { + pr_debug(ctx, "Resolving host `%s' for peer `%s'...", peer->hostname, peer->name); resolv_arg *arg = malloc(sizeof(resolv_arg)); arg->ctx = ctx; arg->master_thread = pthread_self(); - arg->hostname = strdup(peer->config->hostname); - arg->af = peer->config->address.sa.sa_family; - arg->port = ntohs(peer->config->address.in.sin_port); + arg->hostname = strdup(peer->hostname); + arg->constraints = peer->address; pthread_t thread; - if (pthread_create(&thread, NULL, fastd_resolve_peer_handshake_do, arg) != 0) { + if (pthread_create(&thread, NULL, resolve_peer, arg) != 0) { pr_error_errno(ctx, "unable to create resolver thread"); free(arg->hostname); free(arg); |