summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-11-01 15:11:40 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-11-01 15:11:40 +0100
commitcb98cbc593309d4781dfb873b018a5d4e12ad118 (patch)
treec5c0760dbd36cabec9d421f678b5ebd4d59ed25e
parent86df5dbefec807234e9a458da00acbbd2e0e6649 (diff)
downloadfastd-cb98cbc593309d4781dfb873b018a5d4e12ad118.tar
fastd-cb98cbc593309d4781dfb873b018a5d4e12ad118.zip
Dynamically create and destroy sockets without fixed binds
-rw-r--r--src/config.c3
-rw-r--r--src/fastd.c99
-rw-r--r--src/fastd.h15
-rw-r--r--src/handshake.c2
-rw-r--r--src/handshake.h2
-rw-r--r--src/peer.c60
-rw-r--r--src/peer.h9
-rw-r--r--src/protocol_ec25519_fhmqvc.c8
8 files changed, 131 insertions, 67 deletions
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;