mirror of
https://github.com/neocturne/fastd.git
synced 2025-05-14 12:25:07 +02:00
Add status socket to get the current status as JSON
This commit is contained in:
parent
5f898aa52f
commit
2561266c15
16 changed files with 373 additions and 28 deletions
|
@ -1946,6 +1946,7 @@ PREDEFINED = __attribute__(x)= \
|
|||
VECTOR(x):=VECTOR<x> \
|
||||
WITH_CAPABILITIES \
|
||||
WITH_DYNAMIC_PEERS \
|
||||
WITH_STATUS_SOCKET \
|
||||
WITH_CMDLINE_USER \
|
||||
WITH_CMDLINE_LOGGING \
|
||||
WITH_CMDLINE_OPERATION \
|
||||
|
|
|
@ -44,6 +44,7 @@ set(WITH_CMDLINE_OPERATION TRUE CACHE BOOL "Include support for setting options
|
|||
set(WITH_CMDLINE_COMMANDS TRUE CACHE BOOL "Include support for setting handler scripts (e.g. --on-up) on the command line")
|
||||
|
||||
set(WITH_DYNAMIC_PEERS TRUE CACHE BOOL "Include support for dynamic peers (using on-verify handlers)")
|
||||
set(WITH_STATUS_SOCKET TRUE CACHE BOOL "Include support for the status socket")
|
||||
|
||||
set(MAX_CONFIG_DEPTH 10 CACHE STRING "Maximum config include depth")
|
||||
|
||||
|
|
|
@ -59,3 +59,13 @@ else(WITH_CAPABILITIES)
|
|||
set(CAP_INCLUDE_DIR "")
|
||||
set(CAP_LIBRARY "")
|
||||
endif(WITH_CAPABILITIES)
|
||||
|
||||
if(WITH_STATUS_SOCKET)
|
||||
pkg_check_modules(JSONC json-c)
|
||||
else(WITH_STATUS_SOCKET)
|
||||
set(JSONC_INCLUDE_DIRS "")
|
||||
set(JSONC_CFLAGS_OTHER "")
|
||||
set(JSONC_LIBRARY_DIRS "")
|
||||
set(JSONC_LIBRARIES "")
|
||||
set(JSONC_LDFLAGS_OTHER "")
|
||||
endif(WITH_STATUS_SOCKET)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE __APPLE_USE_RFC_3542)
|
||||
set(FASTD_CFLAGS "${PTHREAD_CFLAGS} -std=c99 ${UECC_CFLAGS_OTHER} ${NACL_CFLAGS_OTHER} ${OPENSSL_CRYPTO_CFLAGS_OTHER} ${CFLAGS_LTO} -Wall")
|
||||
set(FASTD_CFLAGS "${PTHREAD_CFLAGS} -std=c99 ${UECC_CFLAGS_OTHER} ${NACL_CFLAGS_OTHER} ${OPENSSL_CRYPTO_CFLAGS_OTHER} ${JSONC_CFLAGS_OTHER} ${CFLAGS_LTO} -Wall")
|
||||
|
||||
include_directories(${FASTD_SOURCE_DIR} ${FASTD_BINARY_DIR}/src)
|
||||
link_directories(${UECC_LIBRARY_DIRS} ${NACL_LIBRARY_DIRS} ${OPENSSL_CRYPTO_LIBRARY_DIRS})
|
||||
link_directories(${UECC_LIBRARY_DIRS} ${NACL_LIBRARY_DIRS} ${OPENSSL_CRYPTO_LIBRARY_DIRS} ${JSONC_LIBRARY_DIRS})
|
||||
|
||||
|
||||
include(generate_version)
|
||||
|
@ -37,15 +37,16 @@ add_executable(fastd
|
|||
sha256.c
|
||||
shell.c
|
||||
socket.c
|
||||
status.c
|
||||
tuntap.c
|
||||
vector.c
|
||||
verify.c
|
||||
${BISON_fastd_config_parse_OUTPUTS}
|
||||
)
|
||||
set_property(TARGET fastd PROPERTY COMPILE_FLAGS "${FASTD_CFLAGS}")
|
||||
set_property(TARGET fastd PROPERTY LINK_FLAGS "${PTHREAD_LDFLAGS} ${UECC_LDFLAGS_OTHER} ${NACL_LDFLAGS_OTHER} ${OPENSSL_CRYPTO_LDFLAGS_OTHER} ${LDFLAGS_LTO}")
|
||||
set_property(TARGET fastd APPEND PROPERTY INCLUDE_DIRECTORIES ${CAP_INCLUDE_DIR} ${NACL_INCLUDE_DIRS})
|
||||
target_link_libraries(fastd protocols methods ciphers macs ${RT_LIBRARY} ${CAP_LIBRARY} ${UECC_LIBRARIES} ${NACL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES})
|
||||
set_property(TARGET fastd PROPERTY LINK_FLAGS "${PTHREAD_LDFLAGS} ${UECC_LDFLAGS_OTHER} ${NACL_LDFLAGS_OTHER} ${OPENSSL_CRYPTO_LDFLAGS_OTHER} ${JSONC_LDFLAGS_OTHER} ${LDFLAGS_LTO}")
|
||||
set_property(TARGET fastd APPEND PROPERTY INCLUDE_DIRECTORIES ${CAP_INCLUDE_DIR} ${NACL_INCLUDE_DIRS} ${JSONC_INCLUDE_DIRS})
|
||||
target_link_libraries(fastd protocols methods ciphers macs ${RT_LIBRARY} ${CAP_LIBRARY} ${UECC_LIBRARIES} ${NACL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES} ${JSONC_LIBRARIES})
|
||||
|
||||
add_dependencies(fastd version)
|
||||
|
||||
|
|
|
@ -650,6 +650,10 @@ void fastd_config_release(void) {
|
|||
fastd_shell_command_unset(&conf.on_verify);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
free(conf.status_socket);
|
||||
#endif
|
||||
|
||||
free(conf.user);
|
||||
free(conf.group);
|
||||
free(conf.groups);
|
||||
|
|
13
src/config.y
13
src/config.y
|
@ -116,6 +116,8 @@
|
|||
%token TOK_REMOTE
|
||||
%token TOK_SECRET
|
||||
%token TOK_SECURE
|
||||
%token TOK_SOCKET
|
||||
%token TOK_STATUS
|
||||
%token TOK_STDERR
|
||||
%token TOK_SYNC
|
||||
%token TOK_SYSLOG
|
||||
|
@ -199,6 +201,7 @@ statement: peer_group_statement
|
|||
| TOK_ON TOK_ESTABLISH on_establish ';'
|
||||
| TOK_ON TOK_DISESTABLISH on_disestablish ';'
|
||||
| TOK_ON TOK_VERIFY on_verify ';'
|
||||
| TOK_STATUS TOK_SOCKET status_socket ';'
|
||||
| TOK_FORWARD forward ';'
|
||||
;
|
||||
|
||||
|
@ -421,6 +424,16 @@ on_verify: sync_def_async TOK_STRING {
|
|||
}
|
||||
;
|
||||
|
||||
status_socket: TOK_STRING {
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
free(conf.status_socket); conf.status_socket = fastd_strdup($1->str);
|
||||
#else
|
||||
fastd_config_error(&@$, state, "status sockets aren't supported by this version of fastd");
|
||||
YYERROR;
|
||||
#endif
|
||||
}
|
||||
;
|
||||
|
||||
peer: TOK_STRING {
|
||||
state->peer = fastd_new0(fastd_peer_t);
|
||||
state->peer->name = fastd_strdup($1->str);
|
||||
|
|
|
@ -481,6 +481,7 @@ static inline void init(int argc, char *argv[]) {
|
|||
fastd_cap_init();
|
||||
|
||||
init_sockets();
|
||||
fastd_status_init();
|
||||
fastd_async_init();
|
||||
fastd_poll_init();
|
||||
|
||||
|
@ -601,6 +602,7 @@ static inline void cleanup(void) {
|
|||
delete_peers();
|
||||
|
||||
fastd_tuntap_close();
|
||||
fastd_status_close();
|
||||
close_sockets();
|
||||
fastd_poll_free();
|
||||
|
||||
|
|
25
src/fastd.h
25
src/fastd.h
|
@ -217,6 +217,10 @@ struct fastd_config {
|
|||
fastd_shell_command_t on_verify; /**< The command to execute to check if a connection from an unknown peer should be allowed */
|
||||
#endif
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
char *status_socket; /**< The path of the status socket */
|
||||
#endif
|
||||
|
||||
bool daemon; /**< Set to make fastd fork to the background after initialization */
|
||||
char *pid_file; /**< A filename to write fastd's PID to */
|
||||
|
||||
|
@ -250,6 +254,10 @@ struct fastd_context {
|
|||
VECTOR(struct pollfd) pollfds; /**< The vector of pollfds for all file descriptors */
|
||||
#endif
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
int status_fd; /**< The file descriptor of the status socket */
|
||||
#endif
|
||||
|
||||
bool has_floating; /**< Specifies if any of the configured peers have floating remotes */
|
||||
|
||||
uint32_t peer_addr_ht_seed; /**< The hash seed used for peer_addr_ht */
|
||||
|
@ -325,6 +333,23 @@ void fastd_cap_drop(void);
|
|||
|
||||
void fastd_random_bytes(void *buffer, size_t len, bool secure);
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
|
||||
void fastd_status_init(void);
|
||||
void fastd_status_close(void);
|
||||
void fastd_status_handle(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline void fastd_status_init(void) {
|
||||
}
|
||||
|
||||
static inline void fastd_status_close(void) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Returns a random number between \a min (inclusively) and \a max (exclusively) */
|
||||
static inline int fastd_rand(int min, int max) {
|
||||
unsigned int r = (unsigned int)random();
|
||||
|
|
|
@ -93,6 +93,9 @@
|
|||
/** Defined if on-verify support is enabled */
|
||||
#cmakedefine WITH_DYNAMIC_PEERS
|
||||
|
||||
/** Defined if status socket support is enabled */
|
||||
#cmakedefine WITH_STATUS_SOCKET
|
||||
|
||||
/** Defined if systemd support is enabled */
|
||||
#cmakedefine ENABLE_SYSTEMD
|
||||
|
||||
|
|
|
@ -113,6 +113,8 @@ static const keyword_t keywords[] = {
|
|||
{ "remote", TOK_REMOTE },
|
||||
{ "secret", TOK_SECRET },
|
||||
{ "secure", TOK_SECURE },
|
||||
{ "socket", TOK_SOCKET },
|
||||
{ "status", TOK_STATUS },
|
||||
{ "stderr", TOK_STDERR },
|
||||
{ "sync", TOK_SYNC },
|
||||
{ "syslog", TOK_SYSLOG },
|
||||
|
|
|
@ -52,7 +52,7 @@ static inline size_t snprintf_safe(char *buffer, size_t size, const char *format
|
|||
}
|
||||
|
||||
/** Creates a string representation of a peer address */
|
||||
static size_t snprint_peer_address(char *buffer, size_t size, const fastd_peer_address_t *address, const char *iface, bool bind_address) {
|
||||
size_t fastd_snprint_peer_address(char *buffer, size_t size, const fastd_peer_address_t *address, const char *iface, bool bind_address, bool hide) {
|
||||
char addr_buf[INET6_ADDRSTRLEN] = "";
|
||||
|
||||
switch (address->sa.sa_family) {
|
||||
|
@ -63,7 +63,7 @@ static size_t snprint_peer_address(char *buffer, size_t size, const fastd_peer_a
|
|||
return snprintf(buffer, size, "any");
|
||||
|
||||
case AF_INET:
|
||||
if (!bind_address && conf.hide_ip_addresses)
|
||||
if (!bind_address && hide)
|
||||
return snprintf_safe(buffer, size, "[hidden]:%u", ntohs(address->in.sin_port));
|
||||
else if (inet_ntop(AF_INET, &address->in.sin_addr, addr_buf, sizeof(addr_buf)))
|
||||
return snprintf_safe(buffer, size, "%s:%u", addr_buf, ntohs(address->in.sin_port));
|
||||
|
@ -71,7 +71,7 @@ static size_t snprint_peer_address(char *buffer, size_t size, const fastd_peer_a
|
|||
return 0;
|
||||
|
||||
case AF_INET6:
|
||||
if (!bind_address && conf.hide_ip_addresses)
|
||||
if (!bind_address && hide)
|
||||
return snprintf_safe(buffer, size, "[hidden]:%u", ntohs(address->in6.sin6_port));
|
||||
if (inet_ntop(AF_INET6, &address->in6.sin6_addr, addr_buf, sizeof(addr_buf))) {
|
||||
char ifname_buf[IF_NAMESIZE];
|
||||
|
@ -179,7 +179,7 @@ static int fastd_vsnprintf(char *buffer, size_t size, const char *format, va_lis
|
|||
iface = (*format == 'L') ? va_arg(ap, const char *) : NULL;
|
||||
|
||||
if (p)
|
||||
buffer += snprint_peer_address(buffer, buffer_end-buffer, (const fastd_peer_address_t *)p, iface, *format != 'I');
|
||||
buffer += fastd_snprint_peer_address(buffer, buffer_end-buffer, (const fastd_peer_address_t *)p, iface, *format != 'I', conf.hide_ip_addresses);
|
||||
else
|
||||
buffer += snprintf_safe(buffer, buffer_end-buffer, "(null)");
|
||||
break;
|
||||
|
|
|
@ -53,7 +53,9 @@ typedef enum fastd_loglevel {
|
|||
} fastd_loglevel_t;
|
||||
|
||||
|
||||
/** Logs a formatted string with the specified log level */
|
||||
size_t fastd_snprint_peer_address(char *buffer, size_t size, const fastd_peer_address_t *address, const char *iface, bool bind_address, bool hide);
|
||||
|
||||
|
||||
void fastd_logf(const fastd_loglevel_t level, const char *format, ...);
|
||||
|
||||
/** Logs a formatted fatal error message */
|
||||
|
|
|
@ -106,6 +106,16 @@ static void option_pid_file(const char *arg) {
|
|||
}
|
||||
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
|
||||
/** Handles the --status-socket option */
|
||||
static void option_status_socket(const char *arg) {
|
||||
free(conf.status_socket);
|
||||
conf.status_socket = fastd_strdup(arg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** Handles the --config option */
|
||||
static void option_config(const char *arg) {
|
||||
if (!strcmp(arg, "-"))
|
||||
|
|
|
@ -2,6 +2,9 @@ OPTION(usage, "--help" OR "-h", "Shows this help text");
|
|||
OPTION(version, "--version" OR "-v", "Shows the fastd version");
|
||||
OPTION(option_daemon, "--daemon" OR "-d", "Runs fastd in the background");
|
||||
OPTION_ARG(option_pid_file, "--pid-file", "<filename>", "Writes fastd's PID to the specified file");
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
OPTION_ARG(option_status_socket, "--status-socket", "<socket>", "Configure a socket to get fastd's status");
|
||||
#endif
|
||||
SEPARATOR;
|
||||
|
||||
OPTION_ARG(option_config, "--config" OR "-c", "<filename>", "Loads a config file");
|
||||
|
|
61
src/poll.c
61
src/poll.c
|
@ -76,12 +76,22 @@ void fastd_poll_init(void) {
|
|||
if (ctx.epoll_fd < 0)
|
||||
exit_errno("epoll_create1");
|
||||
|
||||
struct epoll_event event = {
|
||||
struct epoll_event event_async = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = &ctx.async_rfd,
|
||||
};
|
||||
if (epoll_ctl(ctx.epoll_fd, EPOLL_CTL_ADD, ctx.async_rfd, &event) < 0)
|
||||
if (epoll_ctl(ctx.epoll_fd, EPOLL_CTL_ADD, ctx.async_rfd, &event_async) < 0)
|
||||
exit_errno("epoll_ctl");
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
struct epoll_event event_status = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = &ctx.status_fd,
|
||||
};
|
||||
|
||||
if (epoll_ctl(ctx.epoll_fd, EPOLL_CTL_ADD, ctx.status_fd, &event_status) < 0)
|
||||
exit_errno("epoll_ctl");
|
||||
#endif
|
||||
}
|
||||
|
||||
void fastd_poll_free(void) {
|
||||
|
@ -161,6 +171,12 @@ void fastd_poll_handle(void) {
|
|||
if (events[i].events & EPOLLIN)
|
||||
fastd_async_handle();
|
||||
}
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
else if (events[i].data.ptr == &ctx.status_fd) {
|
||||
if (events[i].events & EPOLLIN)
|
||||
fastd_status_handle();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
fastd_socket_t *sock = events[i].data.ptr;
|
||||
|
||||
|
@ -180,7 +196,7 @@ void fastd_poll_handle(void) {
|
|||
#else
|
||||
|
||||
void fastd_poll_init(void) {
|
||||
VECTOR_RESIZE(ctx.pollfds, 2 + ctx.n_socks);
|
||||
VECTOR_RESIZE(ctx.pollfds, 3 + ctx.n_socks);
|
||||
|
||||
VECTOR_INDEX(ctx.pollfds, 0) = (struct pollfd) {
|
||||
.fd = -1,
|
||||
|
@ -194,9 +210,19 @@ void fastd_poll_init(void) {
|
|||
.revents = 0,
|
||||
};
|
||||
|
||||
VECTOR_INDEX(ctx.pollfds, 2) = (struct pollfd) {
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
.fd = ctx.status_fd,
|
||||
#else
|
||||
.fd = -1,
|
||||
#endif
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
};
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < ctx.n_socks; i++) {
|
||||
VECTOR_INDEX(ctx.pollfds, 2+i) = (struct pollfd) {
|
||||
VECTOR_INDEX(ctx.pollfds, 3+i) = (struct pollfd) {
|
||||
.fd = -1,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
|
@ -214,16 +240,16 @@ void fastd_poll_set_fd_tuntap(void) {
|
|||
}
|
||||
|
||||
void fastd_poll_set_fd_sock(size_t i) {
|
||||
VECTOR_INDEX(ctx.pollfds, 2+i).fd = ctx.socks[i].fd;
|
||||
VECTOR_INDEX(ctx.pollfds, 3+i).fd = ctx.socks[i].fd;
|
||||
}
|
||||
|
||||
void fastd_poll_set_fd_peer(size_t i) {
|
||||
fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i);
|
||||
|
||||
if (!peer->sock || !fastd_peer_is_socket_dynamic(peer))
|
||||
VECTOR_INDEX(ctx.pollfds, 2+ctx.n_socks+i).fd = -1;
|
||||
VECTOR_INDEX(ctx.pollfds, 3+ctx.n_socks+i).fd = -1;
|
||||
else
|
||||
VECTOR_INDEX(ctx.pollfds, 2+ctx.n_socks+i).fd = peer->sock->fd;
|
||||
VECTOR_INDEX(ctx.pollfds, 3+ctx.n_socks+i).fd = peer->sock->fd;
|
||||
}
|
||||
|
||||
void fastd_poll_add_peer(void) {
|
||||
|
@ -237,7 +263,7 @@ void fastd_poll_add_peer(void) {
|
|||
}
|
||||
|
||||
void fastd_poll_delete_peer(size_t i) {
|
||||
VECTOR_DELETE(ctx.pollfds, 2+ctx.n_socks+i);
|
||||
VECTOR_DELETE(ctx.pollfds, 3+ctx.n_socks+i);
|
||||
}
|
||||
|
||||
|
||||
|
@ -253,7 +279,7 @@ void fastd_poll_handle(void) {
|
|||
if (timeout < 0 || timeout > maintenance_timeout)
|
||||
timeout = maintenance_timeout;
|
||||
|
||||
if (VECTOR_LEN(ctx.pollfds) != 2 + ctx.n_socks + VECTOR_LEN(ctx.peers))
|
||||
if (VECTOR_LEN(ctx.pollfds) != 3 + ctx.n_socks + VECTOR_LEN(ctx.peers))
|
||||
exit_bug("fd count mismatch");
|
||||
|
||||
sigset_t set, oldset;
|
||||
|
@ -324,12 +350,17 @@ void fastd_poll_handle(void) {
|
|||
if (VECTOR_INDEX(ctx.pollfds, 1).revents & POLLIN)
|
||||
fastd_async_handle();
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
if (VECTOR_INDEX(ctx.pollfds, 2).revents & POLLIN)
|
||||
fastd_status_handle();
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ctx.n_socks; i++) {
|
||||
if (VECTOR_INDEX(ctx.pollfds, 2+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
if (VECTOR_INDEX(ctx.pollfds, 3+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
fastd_socket_error(&ctx.socks[i]);
|
||||
VECTOR_INDEX(ctx.pollfds, 2+i).fd = -1;
|
||||
VECTOR_INDEX(ctx.pollfds, 3+i).fd = -1;
|
||||
}
|
||||
else if (VECTOR_INDEX(ctx.pollfds, 2+i).revents & POLLIN) {
|
||||
else if (VECTOR_INDEX(ctx.pollfds, 3+i).revents & POLLIN) {
|
||||
fastd_receive(&ctx.socks[i]);
|
||||
}
|
||||
}
|
||||
|
@ -337,15 +368,15 @@ void fastd_poll_handle(void) {
|
|||
for (i = 0; i < VECTOR_LEN(ctx.peers); i++) {
|
||||
fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i);
|
||||
|
||||
if (VECTOR_INDEX(ctx.pollfds, 2+ctx.n_socks+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
if (VECTOR_INDEX(ctx.pollfds, 3+ctx.n_socks+i).revents & (POLLERR|POLLHUP|POLLNVAL)) {
|
||||
fastd_peer_reset_socket(peer);
|
||||
}
|
||||
else if (VECTOR_INDEX(ctx.pollfds, 2+ctx.n_socks+i).revents & POLLIN) {
|
||||
else if (VECTOR_INDEX(ctx.pollfds, 3+ctx.n_socks+i).revents & POLLIN) {
|
||||
fastd_receive(peer->sock);
|
||||
}
|
||||
}
|
||||
|
||||
if (VECTOR_LEN(ctx.pollfds) != 2 + ctx.n_socks + VECTOR_LEN(ctx.peers))
|
||||
if (VECTOR_LEN(ctx.pollfds) != 3 + ctx.n_socks + VECTOR_LEN(ctx.peers))
|
||||
exit_bug("fd count mismatch");
|
||||
}
|
||||
|
||||
|
|
237
src/status.c
Normal file
237
src/status.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
Copyright (c) 2012-2014, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
\file
|
||||
|
||||
Status socket support
|
||||
*/
|
||||
|
||||
|
||||
#include "peer.h"
|
||||
|
||||
|
||||
#ifdef WITH_STATUS_SOCKET
|
||||
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <json.h>
|
||||
|
||||
|
||||
/** Argument for dump_thread */
|
||||
typedef struct dump_thread_arg {
|
||||
int fd; /**< The file descriptor of an accepted socket connection */
|
||||
struct json_object *json; /**< The JSON object to write to the status socket */
|
||||
} dump_thread_arg_t;
|
||||
|
||||
|
||||
/** Thread to write the status JSON to the status socket */
|
||||
static void * dump_thread(void *p) {
|
||||
dump_thread_arg_t *arg = p;
|
||||
|
||||
const char *str = json_object_to_json_string(arg->json);
|
||||
size_t left = strlen(str);
|
||||
|
||||
while (left > 0) {
|
||||
ssize_t written = write(arg->fd, str, left);
|
||||
if (written < 0) {
|
||||
pr_error_errno("can't dump status: write");
|
||||
break;
|
||||
}
|
||||
|
||||
left -= written;
|
||||
str += written;
|
||||
}
|
||||
|
||||
close(arg->fd);
|
||||
json_object_put(arg->json);
|
||||
free(arg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/** Dumps a fastd_stats_t as a JSON object */
|
||||
static json_object * dump_stats(const fastd_stats_t *stats) {
|
||||
struct json_object *ret = json_object_new_object();
|
||||
|
||||
json_object_object_add(ret, "packets", json_object_new_int64(stats->packets));
|
||||
json_object_object_add(ret, "bytes", json_object_new_int64(stats->bytes));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Dumps a peer's status as a JSON object */
|
||||
static json_object * dump_peer(const fastd_peer_t *peer) {
|
||||
struct json_object *ret = json_object_new_object();
|
||||
|
||||
/* '[' + IPv6 addresss + '%' + interface + ']:' + port + NUL */
|
||||
char addr_buf[1 + INET6_ADDRSTRLEN + 2 + IFNAMSIZ + 1 + 5 + 1];
|
||||
fastd_snprint_peer_address(addr_buf, sizeof(addr_buf), &peer->address, NULL, false, false);
|
||||
|
||||
json_object_object_add(ret, "address", json_object_new_string(addr_buf));
|
||||
|
||||
struct json_object *connection = NULL;
|
||||
|
||||
if (fastd_peer_is_established(peer)) {
|
||||
connection = json_object_new_object();
|
||||
|
||||
if (conf.mode == MODE_TAP) {
|
||||
struct json_object *mac_addresses = json_object_new_array();
|
||||
json_object_object_add(connection, "mac_addresses", mac_addresses);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < VECTOR_LEN(ctx.eth_addrs); i++) {
|
||||
fastd_peer_eth_addr_t *addr = &VECTOR_INDEX(ctx.eth_addrs, i);
|
||||
|
||||
if (addr->peer != peer)
|
||||
continue;
|
||||
|
||||
const uint8_t *d = addr->addr.data;
|
||||
|
||||
char eth_addr_buf[18];
|
||||
snprintf(eth_addr_buf, sizeof(eth_addr_buf),
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5]);
|
||||
|
||||
json_object_array_add(mac_addresses, json_object_new_string(eth_addr_buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json_object_object_add(ret, "connection", connection);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Dumps fastd's status to a connected socket */
|
||||
static void dump_status(int fd) {
|
||||
struct json_object *json = json_object_new_object();
|
||||
|
||||
struct json_object *statistics = json_object_new_object();
|
||||
json_object_object_add(json, "statistics", statistics);
|
||||
|
||||
json_object_object_add(statistics, "rx", dump_stats(&ctx.rx));
|
||||
json_object_object_add(statistics, "tx", dump_stats(&ctx.tx));
|
||||
json_object_object_add(statistics, "tx_dropped", dump_stats(&ctx.tx_dropped));
|
||||
json_object_object_add(statistics, "tx_error", dump_stats(&ctx.tx_error));
|
||||
|
||||
struct json_object *peers = json_object_new_object();
|
||||
json_object_object_add(json, "peers", peers);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < VECTOR_LEN(ctx.peers); i++) {
|
||||
fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i);
|
||||
|
||||
if (!fastd_peer_is_enabled(peer))
|
||||
continue;
|
||||
|
||||
json_object_object_add(peers, peer->name, dump_peer(peer));
|
||||
}
|
||||
|
||||
|
||||
dump_thread_arg_t *arg = fastd_new(dump_thread_arg_t);
|
||||
|
||||
arg->json = json;
|
||||
arg->fd = fd;
|
||||
|
||||
pthread_t thread;
|
||||
if ((errno = pthread_create(&thread, &ctx.detached_thread, dump_thread, arg)) != 0) {
|
||||
pr_error_errno("unable to create status dump thread");
|
||||
|
||||
close(arg->fd);
|
||||
json_object_put(arg->json);
|
||||
free(arg);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialized the status socket */
|
||||
void fastd_status_init(void) {
|
||||
if (!conf.status_socket)
|
||||
return;
|
||||
|
||||
uid_t uid = geteuid();
|
||||
gid_t gid = getegid();
|
||||
|
||||
if (conf.user || conf.group) {
|
||||
if (setegid(conf.gid) < 0)
|
||||
pr_debug_errno("setegid");
|
||||
if (seteuid(conf.uid) < 0)
|
||||
pr_debug_errno("seteuid");
|
||||
}
|
||||
|
||||
|
||||
ctx.status_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (ctx.status_fd < 0)
|
||||
exit_errno("fastd_status_init: socket");
|
||||
|
||||
|
||||
size_t len = offsetof(struct sockaddr_un, sun_path) + strlen(conf.status_socket) + 1;
|
||||
uint8_t buf[len];
|
||||
memset(buf, 0, len);
|
||||
|
||||
struct sockaddr_un *sa = (void*)buf;
|
||||
|
||||
sa->sun_family = AF_UNIX;
|
||||
strcpy(sa->sun_path, conf.status_socket);
|
||||
|
||||
if (bind(ctx.status_fd, (struct sockaddr*)sa, len))
|
||||
exit_errno("fastd_status_init: bind");
|
||||
|
||||
if (listen(ctx.status_fd, 4))
|
||||
exit_errno("fastd_status_init: listen");
|
||||
|
||||
|
||||
if (seteuid(uid) < 0)
|
||||
pr_debug_errno("seteuid");
|
||||
if (setegid(gid) < 0)
|
||||
pr_debug_errno("setegid");
|
||||
}
|
||||
|
||||
/** Closes the status socket */
|
||||
void fastd_status_close(void) {
|
||||
if (!conf.status_socket)
|
||||
return;
|
||||
|
||||
if (close(ctx.status_fd))
|
||||
pr_warn_errno("fastd_status_cleanup: close");
|
||||
|
||||
if (unlink(conf.status_socket))
|
||||
pr_warn_errno("fastd_status_cleanup: unlink");
|
||||
}
|
||||
|
||||
/** Handles a single connection on the status socket */
|
||||
void fastd_status_handle(void) {
|
||||
int fd = accept(ctx.status_fd, NULL, NULL);
|
||||
|
||||
if (fd < 0) {
|
||||
pr_warn_errno("fastd_status_handle: accept");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_status(fd);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue