From daf3d6e8db9ef39b50dce040f864fb409bd7044a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 17 Apr 2013 21:42:22 +0200 Subject: Fix handling of the local address in shell commands Without this fix, using on-establish/disestablish/verify would cause a strange zero port when a bind with a random port was used, and a segmentation fault with dynamic binds. --- src/fastd.c | 40 ++++++++++++++++++++++++++++++++++++---- src/fastd.h | 6 ++++++ src/peer.c | 4 ++-- src/protocol_ec25519_fhmqvc.c | 4 ++-- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/fastd.c b/src/fastd.c index 3c3d130..d82589e 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -261,13 +261,33 @@ static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, b if (warn) { if (addr->bindtodev) pr_warn(ctx, "unable to bind to %B on `%s'", &addr->addr, addr->bindtodev); - else + 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; @@ -278,10 +298,15 @@ static bool bind_sockets(fastd_context_t *ctx) { 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; + } + if (ctx->socks[i].addr->bindtodev) - pr_info(ctx, "successfully bound to %B on `%s'", &ctx->socks[i].addr->addr, ctx->socks[i].addr->bindtodev); + pr_info(ctx, "successfully bound to %B on `%s'", ctx->socks[i].bound_addr, ctx->socks[i].addr->bindtodev); else - pr_info(ctx, "successfully bound to %B", &ctx->socks[i].addr->addr); + pr_info(ctx, "successfully bound to %B", ctx->socks[i].bound_addr); } } @@ -302,8 +327,15 @@ fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int 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; } @@ -799,7 +831,7 @@ static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) { fastd_peer_address_t recvaddr; socklen_t recvaddrlen = sizeof(recvaddr); - + ssize_t len = recvfrom(sock->fd, buffer.data, buffer.len, 0, (struct sockaddr*)&recvaddr, &recvaddrlen); if (len <= 0) { if (len < 0 && errno != EINTR) diff --git a/src/fastd.h b/src/fastd.h index 9b1191a..9736e08 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -142,6 +142,7 @@ struct fastd_bind_address { struct fastd_socket { int fd; const fastd_bind_address_t *addr; + fastd_peer_address_t *bound_addr; fastd_peer_t *peer; }; @@ -458,6 +459,11 @@ static inline void fastd_socket_close(fastd_context_t *ctx, fastd_socket_t *sock 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) { diff --git a/src/peer.c b/src/peer.c index 55f0467..f4d62e3 100644 --- a/src/peer.c +++ b/src/peer.c @@ -36,14 +36,14 @@ static inline void on_establish(fastd_context_t *ctx, const fastd_peer_t *peer) if (!ctx->conf->on_establish) return; - fastd_shell_exec(ctx, ctx->conf->on_establish, ctx->conf->on_establish_dir, peer, &peer->sock->addr->addr, &peer->address, NULL); + fastd_shell_exec(ctx, ctx->conf->on_establish, ctx->conf->on_establish_dir, peer, peer->sock->bound_addr, &peer->address, NULL); } static inline void on_disestablish(fastd_context_t *ctx, const fastd_peer_t *peer) { if (!ctx->conf->on_disestablish) return; - fastd_shell_exec(ctx, ctx->conf->on_disestablish, ctx->conf->on_disestablish_dir, peer, &peer->sock->addr->addr, &peer->address, NULL); + fastd_shell_exec(ctx, ctx->conf->on_disestablish, ctx->conf->on_disestablish_dir, peer, peer->sock->bound_addr, &peer->address, NULL); } static inline void free_socket(fastd_context_t *ctx, fastd_peer_t *peer) { diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c index eea95e4..d0dad5b 100644 --- a/src/protocol_ec25519_fhmqvc.c +++ b/src/protocol_ec25519_fhmqvc.c @@ -627,7 +627,7 @@ static inline fastd_peer_t* add_temporary(fastd_context_t *ctx, fastd_socket_t * /* Ugly hack */ peer->protocol_state->last_serial--; - if (!fastd_peer_verify_temporary(ctx, peer, &sock->addr->addr, address)) { + if (!fastd_peer_verify_temporary(ctx, peer, sock->bound_addr, address)) { pr_debug(ctx, "ignoring handshake from %P[%I] (verification failed)", peer, address); fastd_peer_delete(ctx, peer); return NULL; @@ -674,7 +674,7 @@ static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock } if (fastd_peer_is_temporary(peer) && !temporary_added) { - if (!fastd_peer_verify_temporary(ctx, peer, &sock->addr->addr, address)) { + if (!fastd_peer_verify_temporary(ctx, peer, sock->bound_addr, address)) { pr_debug(ctx, "ignoring handshake from %P[%I] (verification failed)", peer, address); return; } -- cgit v1.2.3