summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/fastd.c174
-rw-r--r--src/fastd.h1
-rw-r--r--src/socket.c201
4 files changed, 205 insertions, 172 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8f6c62e..c2a0128 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,6 +27,7 @@ add_executable(fastd
random.c
resolve.c
shell.c
+ socket.c
task.c
protocol_ec25519_fhmqvc.c
${FLEX_fastd_config_lex_OUTPUTS}
diff --git a/src/fastd.c b/src/fastd.c
index b0901f9..10dbeec 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -191,176 +191,6 @@ static void init_sockets(fastd_context_t *ctx) {
ctx->n_socks = ctx->conf->n_bind_addrs;
}
-static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, bool warn) {
- int fd = -1;
- int af = AF_UNSPEC;
-
- if (addr->addr.sa.sa_family != AF_INET) {
- fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- if (fd >= 0) {
- af = AF_INET6;
-
- int val = (addr->addr.sa.sa_family == AF_INET6);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
- if (warn)
- pr_warn_errno(ctx, "setsockopt");
- goto error;
- }
- }
- }
- if (fd < 0 && addr->addr.sa.sa_family != AF_INET6) {
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0)
- exit_errno(ctx, "unable to create socket");
- else
- af = AF_INET;
- }
-
- if (fd < 0)
- goto error;
-
- fastd_setfd(ctx, fd, FD_CLOEXEC, 0);
- fastd_setfl(ctx, fd, O_NONBLOCK, 0);
-
- int one = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one))) {
- pr_error_errno(ctx, "setsockopt: unable to set IP_PKTINFO");
- goto error;
- }
-
- if (af == AF_INET6) {
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one))) {
- pr_error_errno(ctx, "setsockopt: unable to set IPV6_RECVPKTINFO");
- goto error;
- }
- }
-
- if (addr->bindtodev) {
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) {
- if (warn)
- pr_warn_errno(ctx, "setsockopt: unable to bind to device");
- goto error;
- }
- }
-
- if (ctx->conf->pmtu.set) {
- int pmtu = ctx->conf->pmtu.state ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
- if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu))) {
- pr_error_errno(ctx, "setsockopt: unable to set PMTU discovery");
- goto error;
- }
- }
-
- fastd_peer_address_t bind_address = addr->addr;
-
- if (bind_address.sa.sa_family == AF_UNSPEC) {
- memset(&bind_address, 0, sizeof(bind_address));
- bind_address.sa.sa_family = af;
-
- if (af == AF_INET6)
- bind_address.in6.sin6_port = addr->addr.in.sin_port;
- else
- bind_address.in.sin_port = addr->addr.in.sin_port;
- }
-
- if (bind(fd, (struct sockaddr*)&bind_address, bind_address.sa.sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- if (warn)
- pr_warn_errno(ctx, "bind");
- goto error;
- }
-
- return fd;
-
- error:
- if (fd >= 0) {
- if (close(fd))
- pr_error_errno(ctx, "close");
- }
-
- if (warn) {
- if (addr->bindtodev)
- pr_warn(ctx, "unable to bind to %B on `%s'", &addr->addr, addr->bindtodev);
- else
- pr_warn(ctx, "unable to bind to %B", &addr->addr);
- }
-
- return -1;
-}
-
-static bool set_bound_address(fastd_context_t *ctx, fastd_socket_t *sock) {
- fastd_peer_address_t addr = {};
- socklen_t len = sizeof(addr);
-
- if (getsockname(sock->fd, &addr.sa, &len) < 0) {
- pr_error_errno(ctx, "getsockname");
- return false;
- }
-
- if (len > sizeof(addr)) {
- pr_error(ctx, "getsockname: got strange long address");
- return false;
- }
-
- sock->bound_addr = calloc(1, sizeof(addr));
- *sock->bound_addr = addr;
-
- return true;
-}
-
-static bool bind_sockets(fastd_context_t *ctx) {
- unsigned i;
-
- for (i = 0; i < ctx->n_socks; i++) {
- if (ctx->socks[i].fd >= 0)
- continue;
-
- ctx->socks[i].fd = bind_socket(ctx, ctx->socks[i].addr, ctx->socks[i].fd < -1);
-
- if (ctx->socks[i].fd >= 0) {
- if (!set_bound_address(ctx, &ctx->socks[i])) {
- fastd_socket_close(ctx, &ctx->socks[i]);
- continue;
- }
-
- 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;
-
- if (ctx->socks[i].addr->bindtodev)
- pr_info(ctx, "successfully bound to %B on `%s'", &bound_addr, ctx->socks[i].addr->bindtodev);
- else
- pr_info(ctx, "successfully bound to %B", &bound_addr);
- }
- }
-
- if ((ctx->sock_default_v4 && ctx->sock_default_v4->fd < 0) || (ctx->sock_default_v6 && ctx->sock_default_v6->fd < 0))
- return false;
-
- return true;
-}
-
-fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int af) {
- const fastd_bind_address_t any_address = { .addr.sa.sa_family = af };
-
- int fd = bind_socket(ctx, &any_address, true);
- if (fd < 0)
- return NULL;
-
- fastd_socket_t *sock = malloc(sizeof(fastd_socket_t));
-
- sock->fd = fd;
- sock->addr = NULL;
- sock->bound_addr = NULL;
- sock->peer = peer;
-
- if (!set_bound_address(ctx, sock)) {
- fastd_socket_close(ctx, sock);
- free(sock);
- return NULL;
- }
-
- return sock;
-}
void fastd_setfd(const fastd_context_t *ctx, int fd, int set, int unset) {
int flags = fcntl(fd, F_GETFD);
@@ -1206,7 +1036,7 @@ static void maintenance(fastd_context_t *ctx) {
cleanup_peers(ctx);
fastd_peer_eth_addr_cleanup(ctx);
- bind_sockets(ctx);
+ fastd_socket_handle_binds(ctx);
}
@@ -1339,7 +1169,7 @@ int main(int argc, char *argv[]) {
init_sockets(&ctx);
- if (!bind_sockets(&ctx))
+ if (!fastd_socket_handle_binds(&ctx))
exit_error(&ctx, "unable to bind default socket");
init_tuntap(&ctx);
diff --git a/src/fastd.h b/src/fastd.h
index d61178a..8668db6 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -305,6 +305,7 @@ void fastd_send(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_pe
void fastd_send_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer);
void fastd_handle_receive(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer);
+bool fastd_socket_handle_binds(fastd_context_t *ctx);
fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int af);
void fastd_setfd(const fastd_context_t *ctx, int fd, int set, int unset);
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..ca6f588
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,201 @@
+/*
+ Copyright (c) 2012-2013, 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 "fastd.h"
+
+#include <fcntl.h>
+
+
+static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, bool warn) {
+ int fd = -1;
+ int af = AF_UNSPEC;
+
+ if (addr->addr.sa.sa_family != AF_INET) {
+ fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd >= 0) {
+ af = AF_INET6;
+
+ int val = (addr->addr.sa.sa_family == AF_INET6);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
+ if (warn)
+ pr_warn_errno(ctx, "setsockopt");
+ goto error;
+ }
+ }
+ }
+ if (fd < 0 && addr->addr.sa.sa_family != AF_INET6) {
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd < 0)
+ exit_errno(ctx, "unable to create socket");
+ else
+ af = AF_INET;
+ }
+
+ if (fd < 0)
+ goto error;
+
+ fastd_setfd(ctx, fd, FD_CLOEXEC, 0);
+ fastd_setfl(ctx, fd, O_NONBLOCK, 0);
+
+ int one = 1;
+ if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one))) {
+ pr_error_errno(ctx, "setsockopt: unable to set IP_PKTINFO");
+ goto error;
+ }
+
+ if (af == AF_INET6) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one))) {
+ pr_error_errno(ctx, "setsockopt: unable to set IPV6_RECVPKTINFO");
+ goto error;
+ }
+ }
+
+ if (addr->bindtodev) {
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) {
+ if (warn)
+ pr_warn_errno(ctx, "setsockopt: unable to bind to device");
+ goto error;
+ }
+ }
+
+ if (ctx->conf->pmtu.set) {
+ int pmtu = ctx->conf->pmtu.state ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+ if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu))) {
+ pr_error_errno(ctx, "setsockopt: unable to set PMTU discovery");
+ goto error;
+ }
+ }
+
+ fastd_peer_address_t bind_address = addr->addr;
+
+ if (bind_address.sa.sa_family == AF_UNSPEC) {
+ memset(&bind_address, 0, sizeof(bind_address));
+ bind_address.sa.sa_family = af;
+
+ if (af == AF_INET6)
+ bind_address.in6.sin6_port = addr->addr.in.sin_port;
+ else
+ bind_address.in.sin_port = addr->addr.in.sin_port;
+ }
+
+ if (bind(fd, (struct sockaddr*)&bind_address, bind_address.sa.sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
+ if (warn)
+ pr_warn_errno(ctx, "bind");
+ goto error;
+ }
+
+ return fd;
+
+ error:
+ if (fd >= 0) {
+ if (close(fd))
+ pr_error_errno(ctx, "close");
+ }
+
+ if (warn) {
+ if (addr->bindtodev)
+ pr_warn(ctx, "unable to bind to %B on `%s'", &addr->addr, addr->bindtodev);
+ else
+ pr_warn(ctx, "unable to bind to %B", &addr->addr);
+ }
+
+ return -1;
+}
+
+static bool set_bound_address(fastd_context_t *ctx, fastd_socket_t *sock) {
+ fastd_peer_address_t addr = {};
+ socklen_t len = sizeof(addr);
+
+ if (getsockname(sock->fd, &addr.sa, &len) < 0) {
+ pr_error_errno(ctx, "getsockname");
+ return false;
+ }
+
+ if (len > sizeof(addr)) {
+ pr_error(ctx, "getsockname: got strange long address");
+ return false;
+ }
+
+ sock->bound_addr = calloc(1, sizeof(addr));
+ *sock->bound_addr = addr;
+
+ return true;
+}
+
+bool fastd_socket_handle_binds(fastd_context_t *ctx) {
+ unsigned i;
+
+ for (i = 0; i < ctx->n_socks; i++) {
+ if (ctx->socks[i].fd >= 0)
+ continue;
+
+ ctx->socks[i].fd = bind_socket(ctx, ctx->socks[i].addr, ctx->socks[i].fd < -1);
+
+ if (ctx->socks[i].fd >= 0) {
+ if (!set_bound_address(ctx, &ctx->socks[i])) {
+ fastd_socket_close(ctx, &ctx->socks[i]);
+ continue;
+ }
+
+ 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;
+
+ if (ctx->socks[i].addr->bindtodev)
+ pr_info(ctx, "successfully bound to %B on `%s'", &bound_addr, ctx->socks[i].addr->bindtodev);
+ else
+ pr_info(ctx, "successfully bound to %B", &bound_addr);
+ }
+ }
+
+ if ((ctx->sock_default_v4 && ctx->sock_default_v4->fd < 0) || (ctx->sock_default_v6 && ctx->sock_default_v6->fd < 0))
+ return false;
+
+ return true;
+}
+
+fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int af) {
+ const fastd_bind_address_t any_address = { .addr.sa.sa_family = af };
+
+ int fd = bind_socket(ctx, &any_address, true);
+ if (fd < 0)
+ return NULL;
+
+ fastd_socket_t *sock = malloc(sizeof(fastd_socket_t));
+
+ sock->fd = fd;
+ sock->addr = NULL;
+ sock->bound_addr = NULL;
+ sock->peer = peer;
+
+ if (!set_bound_address(ctx, sock)) {
+ fastd_socket_close(ctx, sock);
+ free(sock);
+ return NULL;
+ }
+
+ return sock;
+}