From c3dee51736841587b2f81adc54c1949276ab5de0 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 25 Jul 2013 14:22:19 +0200 Subject: Move socket handling out of fastd.c --- src/CMakeLists.txt | 1 + src/fastd.c | 174 +--------------------------------------------- src/fastd.h | 1 + src/socket.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 172 deletions(-) create mode 100644 src/socket.c (limited to 'src') 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 + 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 + + +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; +} -- cgit v1.2.3