From cb98cbc593309d4781dfb873b018a5d4e12ad118 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 1 Nov 2012 15:11:40 +0100 Subject: Dynamically create and destroy sockets without fixed binds --- src/config.c | 3 -- src/fastd.c | 99 +++++++++++++++++++++++++++---------------- src/fastd.h | 15 ++++++- src/handshake.c | 2 +- src/handshake.h | 2 +- src/peer.c | 60 ++++++++++++++++++-------- src/peer.h | 9 +++- src/protocol_ec25519_fhmqvc.c | 8 ++-- 8 files changed, 131 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/config.c b/src/config.c index b0f4754..228951e 100644 --- a/src/config.c +++ b/src/config.c @@ -434,7 +434,6 @@ bool fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filen } static void count_peers(fastd_context *ctx, fastd_config *conf) { - conf->n_peers = 0; conf->n_floating = 0; conf->n_v4 = 0; conf->n_v6 = 0; @@ -444,8 +443,6 @@ static void count_peers(fastd_context *ctx, fastd_config *conf) { fastd_peer_config *peer; for (peer = conf->peers; peer; peer = peer->next) { - conf->n_peers++; - switch (peer->address.sa.sa_family) { case AF_UNSPEC: if (peer->hostname) diff --git a/src/fastd.c b/src/fastd.c index a673ea9..ec33356 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -256,6 +256,21 @@ static void bind_sockets(fastd_context *ctx) { } } +fastd_socket* fastd_socket_open(fastd_context *ctx, int af) { + const fastd_bind_address any_address = { .addr.sa.sa_family = af }; + + int fd = bind_socket(ctx, &any_address, true); + if (fd < 0) + return NULL; + + fastd_socket *sock = malloc(sizeof(fastd_socket)); + + sock->fd = fd; + sock->addr = NULL; + + return sock; +} + static void init_tuntap(fastd_context *ctx) { struct ifreq ifr; @@ -309,19 +324,10 @@ static void close_tuntap(fastd_context *ctx) { free(ctx->ifname); } -static void close_socket(fastd_context *ctx, fastd_socket *sock) { - if (sock->fd >= 0) { - if(close(sock->fd)) - pr_error_errno(ctx, "closing socket: close"); - - sock->fd = -2; - } -} - static void close_sockets(fastd_context *ctx) { unsigned i; for (i = 0; i < ctx->n_socks; i++) - close_socket(ctx, &ctx->socks[i]); + fastd_socket_close(ctx, &ctx->socks[i]); free(ctx->socks); } @@ -555,8 +561,10 @@ static void init_peers(fastd_context *ctx) { for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) { ctx->conf->protocol->peer_configure(ctx, peer_conf); - if (peer_conf->enabled) + if (peer_conf->enabled) { fastd_peer_add(ctx, peer_conf); + ctx->n_peers++; + } } } @@ -574,7 +582,10 @@ static inline void update_time(fastd_context *ctx) { } static inline void send_handshake(fastd_context *ctx, fastd_peer *peer) { - if (peer->address.sa.sa_family && peer->sock) { + if (!fastd_peer_is_established(peer)) + fastd_peer_reset_socket(ctx, peer); + + if (peer->sock) { if (timespec_diff(&ctx->now, &peer->last_handshake) < ctx->conf->min_handshake_interval*1000 && fastd_peer_address_equal(&peer->address, &peer->last_handshake_address)) { pr_debug(ctx, "not sending a handshake to %P as we sent one a short time ago", peer); @@ -663,7 +674,7 @@ static void handle_tun(fastd_context *ctx) { } } -static void handle_socket(fastd_context *ctx, const fastd_socket *sock) { +static void handle_socket(fastd_context *ctx, fastd_socket *sock) { size_t max_len = PACKET_TYPE_LEN + methods_max_packet_size(ctx); fastd_buffer buffer = fastd_buffer_alloc(max_len, methods_min_decrypt_head_space(ctx), methods_min_decrypt_tail_space(ctx)); uint8_t *packet_type; @@ -752,17 +763,6 @@ static void handle_resolv_returns(fastd_context *ctx) { peer->last_resolve_return = ctx->now; if (fastd_peer_claim_address(ctx, peer, NULL, &resolve_return.addr)) { - if (!peer->sock) { - switch(resolve_return.addr.sa.sa_family) { - case AF_INET: - peer->sock = ctx->sock_default_v4; - break; - - case AF_INET6: - peer->sock = ctx->sock_default_v6; - } - } - send_handshake(ctx, peer); } else { @@ -781,28 +781,44 @@ static inline void handle_socket_error(fastd_context *ctx, fastd_socket *sock) { else pr_warn(ctx, "socket bind %I lost", &sock->addr->addr); - close_socket(ctx, sock); + fastd_socket_close(ctx, sock); } static void handle_input(fastd_context *ctx) { - struct pollfd fds[ctx->n_socks + 2]; + const size_t n_fds = 2 + ctx->n_socks + ctx->n_peers; + struct pollfd fds[n_fds]; fds[0].fd = ctx->tunfd; fds[0].events = POLLIN; fds[1].fd = ctx->resolverfd; fds[1].events = POLLIN; unsigned i; - for (i = 0; i < ctx->n_socks; i++) { - fds[i+2].fd = ctx->socks[i].fd; - fds[i+2].events = POLLIN; + for (i = 2; i < ctx->n_socks+2; i++) { + fds[i].fd = ctx->socks[i-2].fd; + fds[i].events = POLLIN; + } + + fastd_peer *peer; + for (peer = ctx->peers; peer; peer = peer->next) { + if (peer->sock && fastd_peer_is_socket_dynamic(peer)) + fds[i].fd = peer->sock->fd; + else + fds[i].fd = -1; + + fds[i].events = POLLIN; + + i++; } + if (i != n_fds) + exit_bug(ctx, "fd count mismatch"); + int timeout = fastd_task_timeout(ctx); if (timeout < 0 || timeout > 60000) timeout = 60000; /* call maintenance at least once a minute */ - int ret = poll(fds, ctx->n_socks + 2, timeout); + int ret = poll(fds, n_fds, timeout); if (ret < 0) { if (errno == EINTR) return; @@ -817,15 +833,24 @@ static void handle_input(fastd_context *ctx) { if (fds[1].revents & POLLIN) handle_resolv_returns(ctx); - for (i = 0; i < ctx->n_socks; i++) { - if (fds[i+2].revents & (POLLERR|POLLHUP|POLLNVAL)) { - handle_socket_error(ctx, &ctx->socks[i]); - continue; - } + for (i = 2; i < ctx->n_socks+2; i++) { + if (fds[i].revents & (POLLERR|POLLHUP|POLLNVAL)) + handle_socket_error(ctx, &ctx->socks[i-2]); + else if (fds[i].revents & POLLIN) + handle_socket(ctx, &ctx->socks[i-2]); + } + + for (peer = ctx->peers; peer; peer = peer->next) { + if (fds[i].revents & (POLLERR|POLLHUP|POLLNVAL)) + fastd_peer_reset_socket(ctx, peer); + else if (fds[i].revents & POLLIN) + handle_socket(ctx, peer->sock); - if (fds[i+2].revents & POLLIN) - handle_socket(ctx, &ctx->socks[i]); + i++; } + + if (i != n_fds) + exit_bug(ctx, "fd count mismatch"); } static void cleanup_peers(fastd_context *ctx) { diff --git a/src/fastd.h b/src/fastd.h index e4f7924..ecc3eee 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -73,7 +73,7 @@ struct _fastd_protocol { void (*peer_configure)(fastd_context *ctx, fastd_peer_config *peer_conf); void (*handshake_init)(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf); - void (*handshake_handle)(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method); + void (*handshake_handle)(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method); void (*handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); void (*send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); @@ -189,7 +189,6 @@ struct _fastd_config { fastd_string_stack *peer_dirs; fastd_peer_config *peers; - unsigned n_peers; unsigned n_floating; unsigned n_v4; unsigned n_v6; @@ -228,6 +227,7 @@ struct _fastd_context { struct timespec now; + unsigned n_peers; fastd_peer *peers; fastd_queue task_queue; @@ -268,6 +268,8 @@ void fastd_send(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_a void fastd_send_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_buffer buffer); void fastd_handle_receive(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); +fastd_socket* fastd_socket_open(fastd_context *ctx, int af); + void fastd_resolve_peer(fastd_context *ctx, fastd_peer *peer); int fastd_vsnprintf(const fastd_context *ctx, char *buffer, size_t size, const char *format, va_list ap); @@ -394,6 +396,15 @@ static inline void fastd_string_stack_free(fastd_string_stack *str) { } } +static inline void fastd_socket_close(fastd_context *ctx, fastd_socket *sock) { + if (sock->fd >= 0) { + if(close(sock->fd)) + pr_error_errno(ctx, "closing socket: close"); + + sock->fd = -2; + } +} + static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) { return (tp1->tv_sec > tp2->tv_sec || (tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec)); diff --git a/src/handshake.c b/src/handshake.c index e823a0e..7bd627f 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -180,7 +180,7 @@ static fastd_string_stack* parse_string_list(uint8_t *data, size_t len) { return ret; } -void fastd_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) { +void fastd_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer) { if (buffer.len < sizeof(fastd_packet)) { pr_warn(ctx, "received a short handshake from %I", address); goto end_free; diff --git a/src/handshake.h b/src/handshake.h index 7744665..91bf751 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -71,7 +71,7 @@ struct _fastd_handshake { fastd_buffer fastd_handshake_new_init(fastd_context *ctx, size_t tail_space); fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, const fastd_handshake *handshake, const fastd_method *method, size_t tail_space); -void fastd_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer); +void fastd_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, fastd_buffer buffer); static inline void fastd_handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) { diff --git a/src/peer.c b/src/peer.c index c54259a..9513703 100644 --- a/src/peer.c +++ b/src/peer.c @@ -146,10 +146,46 @@ static void on_disestablish(fastd_context *ctx, fastd_peer *peer) { free(cwd); } -static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) { +static inline void free_socket(fastd_context *ctx, fastd_peer *peer) { + if (peer->sock) { + if (fastd_peer_is_socket_dynamic(peer)) { + fastd_socket_close(ctx, peer->sock); + free(peer->sock); + } + peer->sock = NULL; + } +} + +void fastd_peer_reset_socket(fastd_context *ctx, fastd_peer *peer) { + if (!fastd_peer_is_socket_dynamic(peer)) + return; + + pr_debug(ctx, "resetting socket for peer %P", peer); + + free_socket(ctx, peer); + + switch (peer->address.sa.sa_family) { + case AF_INET: + if (ctx->sock_default_v4) + peer->sock = ctx->sock_default_v4; + else + peer->sock = fastd_socket_open(ctx, AF_INET); + break; + + case AF_INET6: + if (ctx->sock_default_v6) + peer->sock = ctx->sock_default_v6; + else + peer->sock = fastd_socket_open(ctx, AF_INET6); + } +} + +static void reset_peer(fastd_context *ctx, fastd_peer *peer) { if (peer->established) on_disestablish(ctx, peer); + free_socket(ctx, peer); + ctx->conf->protocol->reset_peer_state(ctx, peer); int i, deleted = 0; @@ -167,7 +203,7 @@ static inline void reset_peer(fastd_context *ctx, fastd_peer *peer) { fastd_task_delete_peer(ctx, peer); } -static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) { +static void setup_peer(fastd_context *ctx, fastd_peer *peer) { if (peer->config->hostname) peer->address.sa.sa_family = AF_UNSPEC; else @@ -175,19 +211,6 @@ static inline void setup_peer(fastd_context *ctx, fastd_peer *peer) { peer->established = false; - switch (peer->address.sa.sa_family) { - case AF_INET: - peer->sock = ctx->sock_default_v4; - break; - - case AF_INET6: - peer->sock = ctx->sock_default_v6; - break; - - default: - peer->sock = NULL; - } - peer->last_resolve = (struct timespec){0, 0}; peer->last_resolve_return = (struct timespec){0, 0}; peer->seen = (struct timespec){0, 0}; @@ -292,7 +315,7 @@ bool fastd_peer_address_equal(const fastd_peer_address *addr1, const fastd_peer_ return true; } -bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fastd_socket *sock, const fastd_peer_address *addr) { +bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, fastd_socket *sock, const fastd_peer_address *addr) { if (addr->sa.sa_family != AF_UNSPEC) { fastd_peer *peer; for (peer = ctx->peers; peer; peer = peer->next) { @@ -316,8 +339,10 @@ bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *new_peer, const fa } new_peer->address = *addr; - if (sock) + if (sock && sock->addr && sock != new_peer->sock) { + free_socket(ctx, new_peer); new_peer->sock = sock; + } return true; } @@ -358,6 +383,7 @@ fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) { peer->config = peer_conf; peer->protocol_state = NULL; + peer->sock = NULL; setup_peer(ctx, peer); pr_verbose(ctx, "adding peer %P", peer); diff --git a/src/peer.h b/src/peer.h index 37b5ba2..3e37230 100644 --- a/src/peer.h +++ b/src/peer.h @@ -35,7 +35,7 @@ struct _fastd_peer { const fastd_peer_config *config; - const fastd_socket *sock; + fastd_socket *sock; fastd_peer_address address; bool established; @@ -88,7 +88,8 @@ void fastd_peer_reset(fastd_context *ctx, fastd_peer *peer); void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer); fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf); void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer); -bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, const fastd_socket *sock, const fastd_peer_address *addr); +bool fastd_peer_claim_address(fastd_context *ctx, fastd_peer *peer, fastd_socket *sock, const fastd_peer_address *addr); +void fastd_peer_reset_socket(fastd_context *ctx, fastd_peer *peer); const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer); const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer); @@ -119,6 +120,10 @@ static inline void fastd_peer_seen(fastd_context *ctx, fastd_peer *peer) { peer->seen = ctx->now; } +static inline bool fastd_peer_is_socket_dynamic(const fastd_peer *peer) { + return (!peer->sock || !peer->sock->addr); +} + static inline bool fastd_eth_addr_is_unicast(const fastd_eth_addr *addr) { return ((addr->data[0] & 1) == 0); } diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c index 8c96c01..7d2c4b5 100644 --- a/src/protocol_ec25519_fhmqvc.c +++ b/src/protocol_ec25519_fhmqvc.c @@ -305,7 +305,7 @@ static void respond_handshake(fastd_context *ctx, const fastd_socket *sock, cons fastd_send_handshake(ctx, sock, address, buffer); } -static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, const fastd_socket *sock, const fastd_peer_address *address, bool initiator, +static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method *method, fastd_socket *sock, const fastd_peer_address *address, bool initiator, const ecc_public_key_256 *A, const ecc_public_key_256 *B, const ecc_public_key_256 *X, const ecc_public_key_256 *Y, const ecc_public_key_256 *sigma, uint64_t serial) { uint8_t hashinput[5*PUBLICKEYBYTES]; @@ -362,7 +362,7 @@ static bool establish(fastd_context *ctx, fastd_peer *peer, const fastd_method * return true; } -static void finish_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, +static void finish_handshake(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, const fastd_handshake *handshake, const fastd_method *method) { pr_debug(ctx, "finishing handshake with %P[%I]...", peer, address); @@ -433,7 +433,7 @@ static void finish_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_send_handshake(ctx, sock, address, buffer); } -static void handle_finish_handshake(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, +static void handle_finish_handshake(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, fastd_peer *peer, const handshake_key *handshake_key, const ecc_public_key_256 *peer_handshake_key, const fastd_handshake *handshake, const fastd_method *method) { pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, address); @@ -522,7 +522,7 @@ static inline bool has_field(const fastd_handshake *handshake, uint8_t type, siz return (handshake->records[type].length == length); } -static void protocol_handshake_handle(fastd_context *ctx, const fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method) { +static void protocol_handshake_handle(fastd_context *ctx, fastd_socket *sock, const fastd_peer_address *address, const fastd_peer_config *peer_conf, const fastd_handshake *handshake, const fastd_method *method) { handshake_key *handshake_key; char *peer_version_name = NULL; -- cgit v1.2.3