summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/fastd.c128
-rw-r--r--src/fastd.h7
-rw-r--r--src/peer.c23
-rw-r--r--src/poll.c183
-rw-r--r--src/poll.h43
-rw-r--r--src/socket.c3
-rw-r--r--src/tuntap.c7
8 files changed, 273 insertions, 122 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9e757c5..dcd21bc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,6 +28,7 @@ add_executable(fastd
log.c
options.c
peer.c
+ poll.c
random.c
receive.c
resolve.c
diff --git a/src/fastd.c b/src/fastd.c
index 0f8194b..f87f43e 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -30,11 +30,11 @@
#include "crypto.h"
#include "handshake.h"
#include "peer.h"
+#include "poll.h"
#include <fastd_version.h>
#include <fcntl.h>
#include <grp.h>
-#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
@@ -397,10 +397,6 @@ static void dump_state(fastd_context_t *ctx) {
pr_info(ctx, "dump finished.");
}
-static inline void update_time(fastd_context_t *ctx) {
- clock_gettime(CLOCK_MONOTONIC, &ctx->now);
-}
-
static inline void no_valid_address_debug(fastd_context_t *ctx, const fastd_peer_t *peer) {
pr_debug(ctx, "not sending a handshake to %P (no valid address resolved)", peer);
}
@@ -476,120 +472,6 @@ static void handle_handshake_queue(fastd_context_t *ctx) {
fastd_resolve_peer(ctx, peer, peer->next_remote);
}
-static inline bool handle_tun_tap(fastd_context_t *ctx, fastd_buffer_t buffer) {
- if (ctx->conf->mode != MODE_TAP)
- return false;
-
- if (buffer.len < ETH_HLEN) {
- pr_debug(ctx, "truncated packet on tap interface");
- fastd_buffer_free(buffer);
- return true;
- }
-
- fastd_eth_addr_t dest_addr = fastd_get_dest_address(ctx, buffer);
- if (!fastd_eth_addr_is_unicast(dest_addr))
- return false;
-
- fastd_peer_t *peer = fastd_peer_find_by_eth_addr(ctx, dest_addr);
-
- if (!peer)
- return false;
-
- ctx->conf->protocol->send(ctx, peer, buffer);
- return true;
-}
-
-static void handle_tun(fastd_context_t *ctx) {
- fastd_buffer_t buffer = fastd_tuntap_read(ctx);
- if (!buffer.len)
- return;
-
- if (handle_tun_tap(ctx, buffer))
- return;
-
- /* TUN mode or multicast packet */
- fastd_send_all(ctx, NULL, buffer);
-}
-
-static inline int handshake_timeout(fastd_context_t *ctx) {
- if (!ctx->handshake_queue.next)
- return -1;
-
- fastd_peer_t *peer = container_of(ctx->handshake_queue.next, fastd_peer_t, handshake_entry);
-
- int diff_msec = timespec_diff(&peer->next_handshake, &ctx->now);
- if (diff_msec < 0)
- return 0;
- else
- return diff_msec;
-}
-
-static void handle_input(fastd_context_t *ctx) {
- const size_t n_fds = 2 + ctx->n_socks + VECTOR_LEN(ctx->peers);
- struct pollfd fds[n_fds];
- fds[0].fd = ctx->tunfd;
- fds[0].events = POLLIN;
- fds[1].fd = ctx->async_rfd;
- fds[1].events = POLLIN;
-
- size_t i;
- for (i = 0; i < ctx->n_socks; i++) {
- fds[2+i].fd = ctx->socks[i].fd;
- fds[2+i].events = POLLIN;
- }
-
- for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
- fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i);
-
- if (peer->sock && fastd_peer_is_socket_dynamic(peer))
- fds[2+ctx->n_socks+i].fd = peer->sock->fd;
- else
- fds[2+ctx->n_socks+i].fd = -1;
-
- fds[i+2+ctx->n_socks].events = POLLIN;
- }
-
- int maintenance_timeout = timespec_diff(&ctx->next_maintenance, &ctx->now);
-
- if (maintenance_timeout < 0)
- maintenance_timeout = 0;
-
- int timeout = handshake_timeout(ctx);
- if (timeout < 0 || timeout > maintenance_timeout)
- timeout = maintenance_timeout;
-
- int ret = poll(fds, n_fds, timeout);
- if (ret < 0) {
- if (errno == EINTR)
- return;
-
- exit_errno(ctx, "poll");
- }
-
- update_time(ctx);
-
- if (fds[0].revents & POLLIN)
- handle_tun(ctx);
- if (fds[1].revents & POLLIN)
- fastd_async_handle(ctx);
-
- for (i = 0; i < ctx->n_socks; i++) {
- if (fds[2+i].revents & (POLLERR|POLLHUP|POLLNVAL))
- fastd_socket_error(ctx, &ctx->socks[i]);
- else if (fds[2+i].revents & POLLIN)
- fastd_receive(ctx, &ctx->socks[i]);
- }
-
- for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
- fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i);
-
- if (fds[2+ctx->n_socks+i].revents & (POLLERR|POLLHUP|POLLNVAL))
- fastd_peer_reset_socket(ctx, peer);
- else if (fds[2+ctx->n_socks+i].revents & POLLIN)
- fastd_receive(ctx, peer->sock);
- }
-}
-
static void enable_temporaries(fastd_context_t *ctx) {
size_t i;
for (i = 0; i < VECTOR_LEN(ctx->peers_temp); i++)
@@ -913,7 +795,7 @@ int main(int argc, char *argv[]) {
fastd_config_check(&ctx, &conf);
- update_time(&ctx);
+ fastd_update_time(&ctx);
ctx.next_maintenance = fastd_in_seconds(&ctx, conf.maintenance_interval);
@@ -926,8 +808,9 @@ int main(int argc, char *argv[]) {
/* change groups early as the can be relevant for file access (for PID file & log files) */
set_groups(&ctx);
- fastd_async_init(&ctx);
init_sockets(&ctx);
+ fastd_async_init(&ctx);
+ fastd_poll_init(&ctx);
if (!fastd_socket_handle_binds(&ctx))
exit_error(&ctx, "unable to bind default socket");
@@ -976,7 +859,7 @@ int main(int argc, char *argv[]) {
while (!terminate) {
handle_handshake_queue(&ctx);
- handle_input(&ctx);
+ fastd_poll_handle(&ctx);
enable_temporaries(&ctx);
@@ -1014,6 +897,7 @@ int main(int argc, char *argv[]) {
fastd_tuntap_close(&ctx);
close_sockets(&ctx);
+ fastd_poll_free(&ctx);
on_post_down(&ctx);
diff --git a/src/fastd.h b/src/fastd.h
index 9cd6b2a..a116baf 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -34,6 +34,7 @@
#include "vector.h"
#include <errno.h>
+#include <poll.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
@@ -240,6 +241,8 @@ struct fastd_context {
fastd_peer_group_t *peer_group;
VECTOR(fastd_peer_t*) peers;
+ VECTOR(struct pollfd) pollfds;
+
VECTOR(fastd_peer_t*) peers_temp;
fastd_dlist_head_t handshake_queue;
@@ -401,6 +404,10 @@ static inline struct timespec fastd_in_seconds(const fastd_context_t *ctx, int s
return ret;
}
+static inline void fastd_update_time(fastd_context_t *ctx) {
+ clock_gettime(CLOCK_MONOTONIC, &ctx->now);
+}
+
static inline bool strequal(const char *str1, const char *str2) {
if (str1 && str2)
return (!strcmp(str1, str2));
diff --git a/src/peer.c b/src/peer.c
index 67aa622..ecb7e2c 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -25,6 +25,7 @@
#include "peer.h"
+#include "poll.h"
#include <arpa/inet.h>
#include <sys/wait.h>
@@ -46,6 +47,14 @@ static inline void free_socket(fastd_context_t *ctx, fastd_peer_t *peer) {
fastd_socket_close(ctx, peer->sock);
free(peer->sock);
+
+ size_t i;
+ for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
+ if (VECTOR_INDEX(ctx->peers, i) == peer) {
+ fastd_poll_set_fd_peer(ctx, -1, i);
+ break;
+ }
+ }
}
peer->sock = NULL;
}
@@ -87,6 +96,17 @@ void fastd_peer_reset_socket(fastd_context_t *ctx, fastd_peer_t *peer) {
else
peer->sock = fastd_socket_open(ctx, peer, AF_INET6);
}
+
+ if (!peer->sock || !fastd_peer_is_socket_dynamic(peer))
+ return;
+
+ size_t i;
+ for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
+ if (VECTOR_INDEX(ctx->peers, i) == peer) {
+ fastd_poll_set_fd_peer(ctx, peer->sock->fd, i);
+ break;
+ }
+ }
}
void fastd_peer_schedule_handshake(fastd_context_t *ctx, fastd_peer_t *peer, int delay) {
@@ -238,6 +258,7 @@ static void delete_peer(fastd_context_t *ctx, fastd_peer_t *peer) {
for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
if (VECTOR_INDEX(ctx->peers, i) == peer) {
VECTOR_DELETE(ctx->peers, i);
+ fastd_poll_delete_peer(ctx, i);
break;
}
}
@@ -550,6 +571,7 @@ fastd_peer_t* fastd_peer_add(fastd_context_t *ctx, fastd_peer_config_t *peer_con
setup_peer(ctx, peer);
VECTOR_ADD(ctx->peers, peer);
+ fastd_poll_add_peer(ctx);
return peer;
}
@@ -599,6 +621,7 @@ void fastd_peer_enable_temporary(fastd_context_t *ctx, fastd_peer_t *peer) {
exit_bug(ctx, "trying to re-enable non-temporary peer");
VECTOR_ADD(ctx->peers, peer);
+ fastd_poll_add_peer(ctx);
}
void fastd_peer_set_established(fastd_context_t *ctx, fastd_peer_t *peer) {
diff --git a/src/poll.c b/src/poll.c
new file mode 100644
index 0000000..1e87946
--- /dev/null
+++ b/src/poll.c
@@ -0,0 +1,183 @@
+/*
+ Copyright (c) 2012-2014, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "poll.h"
+#include "async.h"
+#include "peer.h"
+
+
+void fastd_poll_init(fastd_context_t *ctx) {
+ VECTOR_ALLOC(ctx->pollfds, 2 + ctx->n_socks);
+
+ VECTOR_INDEX(ctx->pollfds, 0) = (struct pollfd) {
+ .fd = -1,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ VECTOR_INDEX(ctx->pollfds, 1) = (struct pollfd) {
+ .fd = ctx->async_rfd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ size_t i;
+ for (i = 0; i < ctx->n_socks; i++) {
+ VECTOR_INDEX(ctx->pollfds, 2+i) = (struct pollfd) {
+ .fd = -1,
+ .events = POLLIN,
+ .revents = 0,
+ };
+ }
+}
+
+void fastd_poll_free(fastd_context_t *ctx) {
+ VECTOR_FREE(ctx->pollfds);
+}
+
+
+void fastd_poll_set_fd_tuntap(fastd_context_t *ctx, int fd) {
+ VECTOR_INDEX(ctx->pollfds, 0).fd = fd;
+}
+
+void fastd_poll_set_fd_sock(fastd_context_t *ctx, int fd, size_t i) {
+ VECTOR_INDEX(ctx->pollfds, 2+i).fd = fd;
+}
+
+void fastd_poll_set_fd_peer(fastd_context_t *ctx, int fd, size_t i) {
+ VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).fd = fd;
+}
+
+void fastd_poll_add_peer(fastd_context_t *ctx) {
+ struct pollfd pollfd = {
+ .fd = -1,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ VECTOR_ADD(ctx->pollfds, pollfd);
+}
+
+void fastd_poll_delete_peer(fastd_context_t *ctx, size_t i) {
+ VECTOR_DELETE(ctx->pollfds, 2+ctx->n_socks+i);
+}
+
+
+static inline bool handle_tun_tap(fastd_context_t *ctx, fastd_buffer_t buffer) {
+ if (ctx->conf->mode != MODE_TAP)
+ return false;
+
+ if (buffer.len < ETH_HLEN) {
+ pr_debug(ctx, "truncated packet on tap interface");
+ fastd_buffer_free(buffer);
+ return true;
+ }
+
+ fastd_eth_addr_t dest_addr = fastd_get_dest_address(ctx, buffer);
+ if (!fastd_eth_addr_is_unicast(dest_addr))
+ return false;
+
+ fastd_peer_t *peer = fastd_peer_find_by_eth_addr(ctx, dest_addr);
+
+ if (!peer)
+ return false;
+
+ ctx->conf->protocol->send(ctx, peer, buffer);
+ return true;
+}
+
+static void handle_tun(fastd_context_t *ctx) {
+ fastd_buffer_t buffer = fastd_tuntap_read(ctx);
+ if (!buffer.len)
+ return;
+
+ if (handle_tun_tap(ctx, buffer))
+ return;
+
+ /* TUN mode or multicast packet */
+ fastd_send_all(ctx, NULL, buffer);
+}
+
+static inline int handshake_timeout(fastd_context_t *ctx) {
+ if (!ctx->handshake_queue.next)
+ return -1;
+
+ fastd_peer_t *peer = container_of(ctx->handshake_queue.next, fastd_peer_t, handshake_entry);
+
+ int diff_msec = timespec_diff(&peer->next_handshake, &ctx->now);
+ if (diff_msec < 0)
+ return 0;
+ else
+ return diff_msec;
+}
+
+void fastd_poll_handle(fastd_context_t *ctx) {
+ int maintenance_timeout = timespec_diff(&ctx->next_maintenance, &ctx->now);
+
+ if (maintenance_timeout < 0)
+ maintenance_timeout = 0;
+
+ int timeout = handshake_timeout(ctx);
+ if (timeout < 0 || timeout > maintenance_timeout)
+ timeout = maintenance_timeout;
+
+ int ret = poll(VECTOR_DATA(ctx->pollfds), VECTOR_LEN(ctx->pollfds), timeout);
+ if (ret < 0) {
+ if (errno == EINTR)
+ return;
+
+ exit_errno(ctx, "poll");
+ }
+
+ fastd_update_time(ctx);
+
+ if (VECTOR_INDEX(ctx->pollfds, 0).revents & POLLIN)
+ handle_tun(ctx);
+ if (VECTOR_INDEX(ctx->pollfds, 1).revents & POLLIN)
+ fastd_async_handle(ctx);
+
+ size_t i;
+ for (i = 0; i < ctx->n_socks; i++) {
+ if (VECTOR_INDEX(ctx->pollfds, 2+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ fastd_socket_error(ctx, &ctx->socks[i]);
+ VECTOR_INDEX(ctx->pollfds, 2+i).fd = -1;
+ }
+ else if (VECTOR_INDEX(ctx->pollfds, 2+i).revents & POLLIN) {
+ fastd_receive(ctx, &ctx->socks[i]);
+ }
+ }
+
+ for (i = 0; i < VECTOR_LEN(ctx->peers); i++) {
+ fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i);
+
+ if (VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ fastd_peer_reset_socket(ctx, peer);
+ }
+ else if (VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).revents & POLLIN) {
+ fastd_receive(ctx, peer->sock);
+ }
+ }
+}
diff --git a/src/poll.h b/src/poll.h
new file mode 100644
index 0000000..cc472b2
--- /dev/null
+++ b/src/poll.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 2012-2014, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#pragma once
+
+
+#include "types.h"
+
+
+void fastd_poll_init(fastd_context_t *ctx);
+void fastd_poll_free(fastd_context_t *ctx);
+
+void fastd_poll_set_fd_tuntap(fastd_context_t *ctx, int fd);
+void fastd_poll_set_fd_sock(fastd_context_t *ctx, int fd, size_t i);
+void fastd_poll_set_fd_peer(fastd_context_t *ctx, int fd, size_t i);
+
+void fastd_poll_add_peer(fastd_context_t *ctx);
+void fastd_poll_delete_peer(fastd_context_t *ctx, size_t i);
+
+void fastd_poll_handle(fastd_context_t *ctx);
diff --git a/src/socket.c b/src/socket.c
index 4f5ac0f..6db4b9f 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -25,6 +25,7 @@
#include "fastd.h"
+#include "poll.h"
#include <fcntl.h>
@@ -195,6 +196,8 @@ bool fastd_socket_handle_binds(fastd_context_t *ctx) {
continue;
}
+ fastd_poll_set_fd_sock(ctx, ctx->socks[i].fd, i);
+
fastd_peer_address_t bound_addr = *ctx->socks[i].bound_addr;
if (!ctx->socks[i].addr->addr.sa.sa_family)
bound_addr.sa.sa_family = AF_UNSPEC;
diff --git a/src/tuntap.c b/src/tuntap.c
index c75c281..d638611 100644
--- a/src/tuntap.c
+++ b/src/tuntap.c
@@ -25,6 +25,7 @@
#include "fastd.h"
+#include "poll.h"
#include <fcntl.h>
#include <net/if.h>
@@ -101,6 +102,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) {
if (close(ctl_sock))
pr_error_errno(ctx, "close");
+ fastd_poll_set_fd_tuntap(ctx, ctx->tunfd);
+
pr_debug(ctx, "tun/tap device initialized.");
}
@@ -201,6 +204,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) {
exit_bug(ctx, "invalid mode");
}
+ fastd_poll_set_fd_tuntap(ctx, ctx->tunfd);
+
pr_debug(ctx, "tun/tap device initialized.");
}
@@ -268,6 +273,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) {
exit_bug(ctx, "invalid mode");
}
+ fastd_poll_set_fd_tuntap(ctx, ctx->tunfd);
+
pr_debug(ctx, "tun device initialized.");
}