summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/fastd.c169
-rw-r--r--src/fastd.h18
-rw-r--r--src/receive.c185
-rw-r--r--src/socket.c23
5 files changed, 216 insertions, 180 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 92ad954..d527006 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -25,6 +25,7 @@ add_executable(fastd
printf.c
queue.c
random.c
+ receive.c
resolve.c
send.c
shell.c
diff --git a/src/fastd.c b/src/fastd.c
index 9bd534d..37e841f 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -561,160 +561,6 @@ static void handle_tun(fastd_context_t *ctx) {
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) {
- memset(local_addr, 0, sizeof(fastd_peer_address_t));
-
- const char *end = (char*)message->msg_control + message->msg_controllen;
-
- struct cmsghdr *cmsg;
- for (cmsg = CMSG_FIRSTHDR(message); cmsg; cmsg = CMSG_NXTHDR(message, cmsg)) {
- if ((char*)cmsg + sizeof(*cmsg) > end)
- return;
-
- if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
- struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
- if ((char*)pktinfo + sizeof(*pktinfo) > end)
- return;
-
- local_addr->in.sin_family = AF_INET;
- local_addr->in.sin_addr = pktinfo->ipi_addr;
- local_addr->in.sin_port = fastd_peer_address_get_port(sock->bound_addr);
-
- return;
- }
-
- if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
- struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
- if ((char*)pktinfo + sizeof(*pktinfo) > end)
- return;
-
- local_addr->in6.sin6_family = AF_INET6;
- local_addr->in6.sin6_addr = pktinfo->ipi6_addr;
- local_addr->in6.sin6_port = fastd_peer_address_get_port(sock->bound_addr);
-
- if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr))
- local_addr->in6.sin6_scope_id = pktinfo->ipi6_ifindex;
-
- return;
- }
- }
-}
-
-static inline void handle_socket_receive_known(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer) {
- if (!fastd_peer_may_connect(ctx, peer)) {
- fastd_buffer_free(buffer);
- return;
- }
-
- const uint8_t *packet_type = buffer.data;
- fastd_buffer_push_head(ctx, &buffer, 1);
-
- switch (*packet_type) {
- case PACKET_DATA:
- if (!fastd_peer_is_established(peer) || !fastd_peer_address_equal(&peer->local_address, local_addr)) {
- fastd_buffer_free(buffer);
- ctx->conf->protocol->handshake_init(ctx, sock, local_addr, remote_addr, NULL);
- return;
- }
-
- ctx->conf->protocol->handle_recv(ctx, peer, buffer);
- break;
-
- case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, sock, local_addr, remote_addr, peer, buffer);
- }
-}
-
-static inline bool is_unknown_peer_valid(fastd_context_t *ctx, const fastd_peer_address_t *remote_addr) {
- return ctx->conf->has_floating || ctx->conf->on_verify;
-}
-
-static inline void handle_socket_receive_unknown(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
- const uint8_t *packet_type = buffer.data;
- fastd_buffer_push_head(ctx, &buffer, 1);
-
- switch (*packet_type) {
- case PACKET_DATA:
- fastd_buffer_free(buffer);
- ctx->conf->protocol->handshake_init(ctx, sock, local_addr, remote_addr, NULL);
- break;
-
- case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, sock, local_addr, remote_addr, NULL, buffer);
- }
-}
-
-static inline void handle_socket_receive(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
- fastd_peer_t *peer = NULL;
-
- if (sock->peer) {
- if (!fastd_peer_address_equal(&sock->peer->address, remote_addr)) {
- fastd_buffer_free(buffer);
- return;
- }
-
- peer = sock->peer;
- }
- else {
- for (peer = ctx->peers; peer; peer = peer->next) {
- if (fastd_peer_address_equal(&peer->address, remote_addr))
- break;
- }
- }
-
- if (peer) {
- handle_socket_receive_known(ctx, sock, local_addr, remote_addr, peer, buffer);
- }
- else if(is_unknown_peer_valid(ctx, remote_addr)) {
- handle_socket_receive_unknown(ctx, sock, local_addr, remote_addr, buffer);
- }
- else {
- pr_debug(ctx, "received packet from unknown peer %I", remote_addr);
- fastd_buffer_free(buffer);
- }
-}
-
-static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) {
- 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 };
- char cbuf[1024];
-
- struct msghdr message = {
- .msg_name = &recvaddr,
- .msg_namelen = sizeof(recvaddr),
- .msg_iov = &buffer_vec,
- .msg_iovlen = 1,
- .msg_control = cbuf,
- .msg_controllen = sizeof(cbuf),
- };
-
- ssize_t len = recvmsg(sock->fd, &message, 0);
- if (len <= 0) {
- if (len < 0 && errno != EINTR)
- pr_warn_errno(ctx, "recvmsg");
-
- fastd_buffer_free(buffer);
- return;
- }
-
- buffer.len = len;
-
- handle_socket_control(ctx, &message, sock, &local_addr);
-
- if (!local_addr.sa.sa_family) {
- pr_error(ctx, "received packet without packet info");
- fastd_buffer_free(buffer);
- return;
- }
-
- fastd_peer_address_simplify(&recvaddr);
-
- handle_socket_receive(ctx, sock, &local_addr, &recvaddr, buffer);
-}
-
static void handle_resolve_returns(fastd_context_t *ctx) {
fastd_resolve_return_t resolve_return;
@@ -745,15 +591,6 @@ static void handle_resolve_returns(fastd_context_t *ctx) {
fastd_remote_unref(resolve_return.remote);
}
-static inline void handle_socket_error(fastd_context_t *ctx, fastd_socket_t *sock) {
- if (sock->addr->bindtodev)
- pr_warn(ctx, "socket bind %I on `%s' lost", &sock->addr->addr, sock->addr->bindtodev);
- else
- pr_warn(ctx, "socket bind %I lost", &sock->addr->addr);
-
- fastd_socket_close(ctx, sock);
-}
-
static void handle_input(fastd_context_t *ctx) {
const size_t n_fds = 2 + ctx->n_socks + ctx->n_peers;
struct pollfd fds[n_fds];
@@ -805,16 +642,16 @@ static void handle_input(fastd_context_t *ctx) {
for (i = 2; i < ctx->n_socks+2; i++) {
if (fds[i].revents & (POLLERR|POLLHUP|POLLNVAL))
- handle_socket_error(ctx, &ctx->socks[i-2]);
+ fastd_socket_error(ctx, &ctx->socks[i-2]);
else if (fds[i].revents & POLLIN)
- handle_socket(ctx, &ctx->socks[i-2]);
+ fastd_receive(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);
+ fastd_receive(ctx, peer->sock);
i++;
}
diff --git a/src/fastd.h b/src/fastd.h
index 1bbda28..ba74330 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -311,10 +311,14 @@ 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_receive(fastd_context_t *ctx, fastd_socket_t *sock);
+
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_socket_close(fastd_context_t *ctx, fastd_socket_t *sock);
+void fastd_socket_error(fastd_context_t *ctx, fastd_socket_t *sock);
void fastd_setfd(const fastd_context_t *ctx, int fd, int set, int unset);
void fastd_setfl(const fastd_context_t *ctx, int fd, int set, int unset);
@@ -460,20 +464,6 @@ static inline void fastd_string_stack_free(fastd_string_stack_t *str) {
}
}
-static inline void fastd_socket_close(fastd_context_t *ctx, fastd_socket_t *sock) {
- if (sock->fd >= 0) {
- if(close(sock->fd))
- pr_error_errno(ctx, "closing socket: close");
-
- sock->fd = -2;
- }
-
- if (sock->bound_addr) {
- free(sock->bound_addr);
- sock->bound_addr = NULL;
- }
-}
-
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/receive.c b/src/receive.c
new file mode 100644
index 0000000..fc835eb
--- /dev/null
+++ b/src/receive.c
@@ -0,0 +1,185 @@
+/*
+ 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 "handshake.h"
+#include "packet.h"
+#include "peer.h"
+
+
+static inline void handle_socket_control(fastd_context_t *ctx, struct msghdr *message, const fastd_socket_t *sock, fastd_peer_address_t *local_addr) {
+ memset(local_addr, 0, sizeof(fastd_peer_address_t));
+
+ const char *end = (char*)message->msg_control + message->msg_controllen;
+
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(message); cmsg; cmsg = CMSG_NXTHDR(message, cmsg)) {
+ if ((char*)cmsg + sizeof(*cmsg) > end)
+ return;
+
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+ struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ if ((char*)pktinfo + sizeof(*pktinfo) > end)
+ return;
+
+ local_addr->in.sin_family = AF_INET;
+ local_addr->in.sin_addr = pktinfo->ipi_addr;
+ local_addr->in.sin_port = fastd_peer_address_get_port(sock->bound_addr);
+
+ return;
+ }
+
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ if ((char*)pktinfo + sizeof(*pktinfo) > end)
+ return;
+
+ local_addr->in6.sin6_family = AF_INET6;
+ local_addr->in6.sin6_addr = pktinfo->ipi6_addr;
+ local_addr->in6.sin6_port = fastd_peer_address_get_port(sock->bound_addr);
+
+ if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr))
+ local_addr->in6.sin6_scope_id = pktinfo->ipi6_ifindex;
+
+ return;
+ }
+ }
+}
+
+static inline void handle_socket_receive_known(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer) {
+ if (!fastd_peer_may_connect(ctx, peer)) {
+ fastd_buffer_free(buffer);
+ return;
+ }
+
+ const uint8_t *packet_type = buffer.data;
+ fastd_buffer_push_head(ctx, &buffer, 1);
+
+ switch (*packet_type) {
+ case PACKET_DATA:
+ if (!fastd_peer_is_established(peer) || !fastd_peer_address_equal(&peer->local_address, local_addr)) {
+ fastd_buffer_free(buffer);
+ ctx->conf->protocol->handshake_init(ctx, sock, local_addr, remote_addr, NULL);
+ return;
+ }
+
+ ctx->conf->protocol->handle_recv(ctx, peer, buffer);
+ break;
+
+ case PACKET_HANDSHAKE:
+ fastd_handshake_handle(ctx, sock, local_addr, remote_addr, peer, buffer);
+ }
+}
+
+static inline bool is_unknown_peer_valid(fastd_context_t *ctx, const fastd_peer_address_t *remote_addr) {
+ return ctx->conf->has_floating || ctx->conf->on_verify;
+}
+
+static inline void handle_socket_receive_unknown(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
+ const uint8_t *packet_type = buffer.data;
+ fastd_buffer_push_head(ctx, &buffer, 1);
+
+ switch (*packet_type) {
+ case PACKET_DATA:
+ fastd_buffer_free(buffer);
+ ctx->conf->protocol->handshake_init(ctx, sock, local_addr, remote_addr, NULL);
+ break;
+
+ case PACKET_HANDSHAKE:
+ fastd_handshake_handle(ctx, sock, local_addr, remote_addr, NULL, buffer);
+ }
+}
+
+static inline void handle_socket_receive(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
+ fastd_peer_t *peer = NULL;
+
+ if (sock->peer) {
+ if (!fastd_peer_address_equal(&sock->peer->address, remote_addr)) {
+ fastd_buffer_free(buffer);
+ return;
+ }
+
+ peer = sock->peer;
+ }
+ else {
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (fastd_peer_address_equal(&peer->address, remote_addr))
+ break;
+ }
+ }
+
+ if (peer) {
+ handle_socket_receive_known(ctx, sock, local_addr, remote_addr, peer, buffer);
+ }
+ else if(is_unknown_peer_valid(ctx, remote_addr)) {
+ handle_socket_receive_unknown(ctx, sock, local_addr, remote_addr, buffer);
+ }
+ else {
+ pr_debug(ctx, "received packet from unknown peer %I", remote_addr);
+ fastd_buffer_free(buffer);
+ }
+}
+
+void fastd_receive(fastd_context_t *ctx, fastd_socket_t *sock) {
+ 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 };
+ char cbuf[1024];
+
+ struct msghdr message = {
+ .msg_name = &recvaddr,
+ .msg_namelen = sizeof(recvaddr),
+ .msg_iov = &buffer_vec,
+ .msg_iovlen = 1,
+ .msg_control = cbuf,
+ .msg_controllen = sizeof(cbuf),
+ };
+
+ ssize_t len = recvmsg(sock->fd, &message, 0);
+ if (len <= 0) {
+ if (len < 0 && errno != EINTR)
+ pr_warn_errno(ctx, "recvmsg");
+
+ fastd_buffer_free(buffer);
+ return;
+ }
+
+ buffer.len = len;
+
+ handle_socket_control(ctx, &message, sock, &local_addr);
+
+ if (!local_addr.sa.sa_family) {
+ pr_error(ctx, "received packet without packet info");
+ fastd_buffer_free(buffer);
+ return;
+ }
+
+ fastd_peer_address_simplify(&recvaddr);
+
+ handle_socket_receive(ctx, sock, &local_addr, &recvaddr, buffer);
+}
diff --git a/src/socket.c b/src/socket.c
index ca6f588..c53695b 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -199,3 +199,26 @@ fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int
return sock;
}
+
+void fastd_socket_close(fastd_context_t *ctx, fastd_socket_t *sock) {
+ if (sock->fd >= 0) {
+ if(close(sock->fd))
+ pr_error_errno(ctx, "closing socket: close");
+
+ sock->fd = -2;
+ }
+
+ if (sock->bound_addr) {
+ free(sock->bound_addr);
+ sock->bound_addr = NULL;
+ }
+}
+
+void fastd_socket_error(fastd_context_t *ctx, fastd_socket_t *sock) {
+ if (sock->addr->bindtodev)
+ pr_warn(ctx, "socket bind %I on `%s' lost", &sock->addr->addr, sock->addr->bindtodev);
+ else
+ pr_warn(ctx, "socket bind %I lost", &sock->addr->addr);
+
+ fastd_socket_close(ctx, sock);
+}