Add status socket to get the current status as JSON

This commit is contained in:
Matthias Schiffer 2014-09-05 22:43:11 +02:00
parent 5f898aa52f
commit 2561266c15
16 changed files with 373 additions and 28 deletions

View file

@ -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 \

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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

View file

@ -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 },

View file

@ -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;

View file

@ -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 */

View file

@ -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, "-"))

View file

@ -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");

View file

@ -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
View 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