From 900ac61351cabc78b5126adbe9c9936d1c3b5ca6 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 25 Jul 2013 15:17:54 +0200 Subject: Move send functions out of fastd.c --- src/CMakeLists.txt | 1 + src/config.c | 27 ++++++++ src/fastd.c | 196 ++--------------------------------------------------- src/fastd.h | 12 ++++ src/send.c | 132 ++++++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 190 deletions(-) create mode 100644 src/send.c (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c2a0128..92ad954 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(fastd queue.c random.c resolve.c + send.c shell.c socket.c task.c diff --git a/src/config.c b/src/config.c index ec04726..6296209 100644 --- a/src/config.c +++ b/src/config.c @@ -845,7 +845,31 @@ static void configure_user(fastd_context_t *ctx, fastd_config_t *conf) { conf->n_groups = ngroups; } } +} + +static void configure_method_parameters(fastd_context_t *ctx, fastd_config_t *conf) { + conf->max_packet_size = 0; + conf->min_encrypt_head_space = 0; + conf->min_decrypt_head_space = 0; + conf->min_encrypt_tail_space = 0; + conf->min_decrypt_tail_space = 0; + + int i; + for (i = 0; i < MAX_METHODS; i++) { + if (!conf->methods[i]) + break; + + conf->max_packet_size = max_size_t(conf->max_packet_size, conf->methods[i]->max_packet_size(ctx)); + conf->min_encrypt_head_space = max_size_t(conf->min_encrypt_head_space, conf->methods[i]->min_encrypt_head_space(ctx)); + conf->min_decrypt_head_space = max_size_t(conf->min_decrypt_head_space, conf->methods[i]->min_decrypt_head_space(ctx)); + conf->min_encrypt_tail_space = max_size_t(conf->min_encrypt_tail_space, conf->methods[i]->min_encrypt_tail_space(ctx)); + conf->min_decrypt_tail_space = max_size_t(conf->min_decrypt_tail_space, conf->methods[i]->min_decrypt_tail_space(ctx)); + } + conf->min_encrypt_head_space = alignto(conf->min_encrypt_head_space, 16); + + /* ugly hack to get alignment right for aes128-gcm, which needs data aligned to 16 and has a 24 byte header */ + conf->min_decrypt_head_space = alignto(conf->min_decrypt_head_space, 16) + 8; } void fastd_configure(fastd_context_t *ctx, fastd_config_t *conf, int argc, char *const argv[]) { @@ -902,6 +926,9 @@ void fastd_configure(fastd_context_t *ctx, fastd_config_t *conf, int argc, char exit_error(ctx, "config error: neither fixed peers nor peer dirs have been configured"); configure_user(ctx, conf); + + ctx->conf = conf; + configure_method_parameters(ctx, conf); } static void peer_dirs_read_peer_group(fastd_context_t *ctx, fastd_config_t *new_conf) { diff --git a/src/fastd.c b/src/fastd.c index 10dbeec..9bd534d 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -276,189 +276,6 @@ static void close_sockets(fastd_context_t *ctx) { free(ctx->socks); } -static size_t methods_max_packet_size(fastd_context_t *ctx) { - size_t ret = ctx->conf->methods[0]->max_packet_size(ctx); - - int i; - for (i = 0; i < MAX_METHODS; i++) { - if (!ctx->conf->methods[i]) - break; - - size_t s = ctx->conf->methods[i]->max_packet_size(ctx); - if (s > ret) - ret = s; - } - - return ret; -} - -static size_t methods_min_encrypt_head_space(fastd_context_t *ctx) { - size_t ret = 0; - - int i; - for (i = 0; i < MAX_METHODS; i++) { - if (!ctx->conf->methods[i]) - break; - - size_t s = ctx->conf->methods[i]->min_encrypt_head_space(ctx); - if (s > ret) - ret = s; - } - - return alignto(ret, 16); -} - -static size_t methods_min_decrypt_head_space(fastd_context_t *ctx) { - size_t ret = 0; - - int i; - for (i = 0; i < MAX_METHODS; i++) { - if (!ctx->conf->methods[i]) - break; - - size_t s = ctx->conf->methods[i]->min_decrypt_head_space(ctx); - if (s > ret) - ret = s; - } - - /* ugly hack to get alignment right for aes128-gcm, which needs data aligned to 16 and has a 24 byte header */ - return alignto(ret, 16) + 8; -} - -static size_t methods_min_encrypt_tail_space(fastd_context_t *ctx) { - size_t ret = 0; - - int i; - for (i = 0; i < MAX_METHODS; i++) { - if (!ctx->conf->methods[i]) - break; - - size_t s = ctx->conf->methods[i]->min_encrypt_tail_space(ctx); - if (s > ret) - ret = s; - } - - return ret; -} - -static size_t methods_min_decrypt_tail_space(fastd_context_t *ctx) { - size_t ret = 0; - - int i; - for (i = 0; i < MAX_METHODS; i++) { - if (!ctx->conf->methods[i]) - break; - - size_t s = ctx->conf->methods[i]->min_decrypt_tail_space(ctx); - if (s > ret) - ret = s; - } - - return ret; -} - -static inline void add_pktinfo(struct msghdr *msg, const fastd_peer_address_t *local_addr) { - if (!local_addr) - return; - - struct cmsghdr *cmsg = (struct cmsghdr*)((char*)msg->msg_control + msg->msg_controllen); - - if (local_addr->sa.sa_family == AF_INET) { - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - msg->msg_controllen += cmsg->cmsg_len; - - struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); - pktinfo->ipi_addr = local_addr->in.sin_addr; - } - else if (local_addr->sa.sa_family == AF_INET6) { - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - msg->msg_controllen += cmsg->cmsg_len; - - struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); - pktinfo->ipi6_addr = local_addr->in6.sin6_addr; - - if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr)) - pktinfo->ipi6_ifindex = local_addr->in6.sin6_scope_id; - } -} - -static void fastd_send_type(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, uint8_t packet_type, fastd_buffer_t buffer) { - if (!sock) - exit_bug(ctx, "send: sock == NULL"); - - struct msghdr msg = {}; - char cbuf[1024] = {}; - - switch (remote_addr->sa.sa_family) { - case AF_INET: - msg.msg_name = (void*)&remote_addr->in; - msg.msg_namelen = sizeof(struct sockaddr_in); - break; - - case AF_INET6: - msg.msg_name = (void*)&remote_addr->in6; - msg.msg_namelen = sizeof(struct sockaddr_in6); - break; - - default: - exit_bug(ctx, "unsupported address family"); - } - - struct iovec iov[2] = { - { .iov_base = &packet_type, .iov_len = 1 }, - { .iov_base = buffer.data, .iov_len = buffer.len } - }; - - msg.msg_iov = iov; - msg.msg_iovlen = buffer.len ? 2 : 1; - msg.msg_control = cbuf; - msg.msg_controllen = 0; - - add_pktinfo(&msg, local_addr); - - int ret; - do { - ret = sendmsg(sock->fd, &msg, 0); - } while (ret < 0 && errno == EINTR); - - if (ret < 0) - pr_warn_errno(ctx, "sendmsg"); - - fastd_buffer_free(buffer); -} - -void fastd_send(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) { - fastd_send_type(ctx, sock, local_addr, remote_addr, PACKET_DATA, buffer); -} - -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) { - fastd_send_type(ctx, sock, local_addr, remote_addr, PACKET_HANDSHAKE, buffer); -} - -static inline void send_all(fastd_context_t *ctx, fastd_peer_t *source_peer, fastd_buffer_t buffer) { - fastd_peer_t *dest_peer; - for (dest_peer = ctx->peers; dest_peer; dest_peer = dest_peer->next) { - if (dest_peer == source_peer || !fastd_peer_is_established(dest_peer)) - continue; - - /* optimization, primarily for TUN mode: don't duplicate the buffer for the last (or only) peer */ - if (!dest_peer->next) { - ctx->conf->protocol->send(ctx, dest_peer, buffer); - return; - } - - ctx->conf->protocol->send(ctx, dest_peer, fastd_buffer_dup(ctx, buffer, methods_min_encrypt_head_space(ctx), methods_min_encrypt_tail_space(ctx))); - } - - fastd_buffer_free(buffer); -} - static inline void handle_forward(fastd_context_t *ctx, fastd_peer_t *source_peer, fastd_buffer_t buffer) { const fastd_eth_addr_t *dest_addr = fastd_get_dest_address(ctx, buffer); @@ -473,7 +290,7 @@ static inline void handle_forward(fastd_context_t *ctx, fastd_peer_t *source_pee ctx->conf->protocol->send(ctx, dest_peer, buffer); } else { - send_all(ctx, source_peer, buffer); + fastd_send_all(ctx, source_peer, buffer); } } @@ -685,7 +502,7 @@ static void handle_tasks(fastd_context_t *ctx) { case TASK_KEEPALIVE: pr_debug(ctx, "sending keepalive to %P", task->peer); - ctx->conf->protocol->send(ctx, task->peer, fastd_buffer_alloc(ctx, 0, methods_min_encrypt_head_space(ctx), methods_min_encrypt_tail_space(ctx))); + ctx->conf->protocol->send(ctx, task->peer, fastd_buffer_alloc(ctx, 0, ctx->conf->min_encrypt_head_space, ctx->conf->min_encrypt_tail_space)); break; default: @@ -723,7 +540,7 @@ static inline bool handle_tun_tap(fastd_context_t *ctx, fastd_buffer_t buffer) { static void handle_tun(fastd_context_t *ctx) { size_t max_len = fastd_max_packet_size(ctx); - fastd_buffer_t buffer = fastd_buffer_alloc(ctx, max_len, methods_min_encrypt_head_space(ctx), methods_min_encrypt_tail_space(ctx)); + fastd_buffer_t buffer = fastd_buffer_alloc(ctx, max_len, ctx->conf->min_encrypt_head_space, ctx->conf->min_encrypt_tail_space); ssize_t len = read(ctx->tunfd, buffer.data, max_len); if (len < 0) { @@ -741,7 +558,7 @@ static void handle_tun(fastd_context_t *ctx) { return; /* TUN mode or multicast packet */ - send_all(ctx, NULL, buffer); + fastd_send_all(ctx, NULL, buffer); } static inline void handle_socket_control(fastd_context_t *ctx, struct msghdr *message, const fastd_socket_t *sock, fastd_peer_address_t *local_addr) { @@ -858,8 +675,8 @@ static inline void handle_socket_receive(fastd_context_t *ctx, fastd_socket_t *s } static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) { - size_t max_len = PACKET_TYPE_LEN + methods_max_packet_size(ctx); - fastd_buffer_t buffer = fastd_buffer_alloc(ctx, max_len, methods_min_decrypt_head_space(ctx), methods_min_decrypt_tail_space(ctx)); + size_t max_len = PACKET_TYPE_LEN + ctx->conf->max_packet_size; + fastd_buffer_t buffer = fastd_buffer_alloc(ctx, max_len, ctx->conf->min_decrypt_head_space, ctx->conf->min_decrypt_tail_space); fastd_peer_address_t local_addr; fastd_peer_address_t recvaddr; struct iovec buffer_vec = { .iov_base = buffer.data, .iov_len = buffer.len }; @@ -1140,7 +957,6 @@ int main(int argc, char *argv[]) { fastd_config_t conf; fastd_configure(&ctx, &conf, argc, argv); - ctx.conf = &conf; init_log(&ctx); diff --git a/src/fastd.h b/src/fastd.h index 8668db6..1bbda28 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -208,6 +208,13 @@ struct fastd_config { const fastd_protocol_t *protocol; const fastd_method_t *methods[MAX_METHODS]; const fastd_method_t *method_default; + + size_t max_packet_size; + size_t min_encrypt_head_space; + size_t min_decrypt_head_space; + size_t min_encrypt_tail_space; + size_t min_decrypt_tail_space; + char *secret; unsigned key_valid; unsigned key_refresh; @@ -302,6 +309,7 @@ struct fastd_string_stack { void fastd_send(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_send_all(fastd_context_t *ctx, fastd_peer_t *source_peer, fastd_buffer_t buffer); 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); @@ -483,4 +491,8 @@ static inline bool strequal(const char *str1, const char *str2) { return (str1 == str2); } +static inline size_t max_size_t(size_t a, size_t b) { + return (a > b) ? a : b; +} + #endif /* _FASTD_FASTD_H_ */ diff --git a/src/send.c b/src/send.c new file mode 100644 index 0000000..4e0d77a --- /dev/null +++ b/src/send.c @@ -0,0 +1,132 @@ +/* + 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 "packet.h" +#include "peer.h" + + +static inline void add_pktinfo(struct msghdr *msg, const fastd_peer_address_t *local_addr) { + if (!local_addr) + return; + + struct cmsghdr *cmsg = (struct cmsghdr*)((char*)msg->msg_control + msg->msg_controllen); + + if (local_addr->sa.sa_family == AF_INET) { + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + + msg->msg_controllen += cmsg->cmsg_len; + + struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); + pktinfo->ipi_addr = local_addr->in.sin_addr; + } + else if (local_addr->sa.sa_family == AF_INET6) { + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + msg->msg_controllen += cmsg->cmsg_len; + + struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); + pktinfo->ipi6_addr = local_addr->in6.sin6_addr; + + if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr)) + pktinfo->ipi6_ifindex = local_addr->in6.sin6_scope_id; + } +} + +static void send_type(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, uint8_t packet_type, fastd_buffer_t buffer) { + if (!sock) + exit_bug(ctx, "send: sock == NULL"); + + struct msghdr msg = {}; + char cbuf[1024] = {}; + + switch (remote_addr->sa.sa_family) { + case AF_INET: + msg.msg_name = (void*)&remote_addr->in; + msg.msg_namelen = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + msg.msg_name = (void*)&remote_addr->in6; + msg.msg_namelen = sizeof(struct sockaddr_in6); + break; + + default: + exit_bug(ctx, "unsupported address family"); + } + + struct iovec iov[2] = { + { .iov_base = &packet_type, .iov_len = 1 }, + { .iov_base = buffer.data, .iov_len = buffer.len } + }; + + msg.msg_iov = iov; + msg.msg_iovlen = buffer.len ? 2 : 1; + msg.msg_control = cbuf; + msg.msg_controllen = 0; + + add_pktinfo(&msg, local_addr); + + int ret; + do { + ret = sendmsg(sock->fd, &msg, 0); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + pr_warn_errno(ctx, "sendmsg"); + + fastd_buffer_free(buffer); +} + +void fastd_send(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) { + send_type(ctx, sock, local_addr, remote_addr, PACKET_DATA, buffer); +} + +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) { + send_type(ctx, sock, local_addr, remote_addr, PACKET_HANDSHAKE, buffer); +} + +void fastd_send_all(fastd_context_t *ctx, fastd_peer_t *source_peer, fastd_buffer_t buffer) { + fastd_peer_t *dest_peer; + for (dest_peer = ctx->peers; dest_peer; dest_peer = dest_peer->next) { + if (dest_peer == source_peer || !fastd_peer_is_established(dest_peer)) + continue; + + /* optimization, primarily for TUN mode: don't duplicate the buffer for the last (or only) peer */ + if (!dest_peer->next) { + ctx->conf->protocol->send(ctx, dest_peer, buffer); + return; + } + + ctx->conf->protocol->send(ctx, dest_peer, fastd_buffer_dup(ctx, buffer, ctx->conf->min_encrypt_head_space, ctx->conf->min_encrypt_tail_space)); + } + + fastd_buffer_free(buffer); +} -- cgit v1.2.3