mirror of
https://github.com/neocturne/fastd.git
synced 2025-05-14 20:25:08 +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> \
|
VECTOR(x):=VECTOR<x> \
|
||||||
WITH_CAPABILITIES \
|
WITH_CAPABILITIES \
|
||||||
WITH_DYNAMIC_PEERS \
|
WITH_DYNAMIC_PEERS \
|
||||||
|
WITH_STATUS_SOCKET \
|
||||||
WITH_CMDLINE_USER \
|
WITH_CMDLINE_USER \
|
||||||
WITH_CMDLINE_LOGGING \
|
WITH_CMDLINE_LOGGING \
|
||||||
WITH_CMDLINE_OPERATION \
|
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_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_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")
|
set(MAX_CONFIG_DEPTH 10 CACHE STRING "Maximum config include depth")
|
||||||
|
|
||||||
|
|
|
@ -59,3 +59,13 @@ else(WITH_CAPABILITIES)
|
||||||
set(CAP_INCLUDE_DIR "")
|
set(CAP_INCLUDE_DIR "")
|
||||||
set(CAP_LIBRARY "")
|
set(CAP_LIBRARY "")
|
||||||
endif(WITH_CAPABILITIES)
|
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_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)
|
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)
|
include(generate_version)
|
||||||
|
@ -37,15 +37,16 @@ add_executable(fastd
|
||||||
sha256.c
|
sha256.c
|
||||||
shell.c
|
shell.c
|
||||||
socket.c
|
socket.c
|
||||||
|
status.c
|
||||||
tuntap.c
|
tuntap.c
|
||||||
vector.c
|
vector.c
|
||||||
verify.c
|
verify.c
|
||||||
${BISON_fastd_config_parse_OUTPUTS}
|
${BISON_fastd_config_parse_OUTPUTS}
|
||||||
)
|
)
|
||||||
set_property(TARGET fastd PROPERTY COMPILE_FLAGS "${FASTD_CFLAGS}")
|
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 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})
|
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})
|
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)
|
add_dependencies(fastd version)
|
||||||
|
|
||||||
|
|
|
@ -650,6 +650,10 @@ void fastd_config_release(void) {
|
||||||
fastd_shell_command_unset(&conf.on_verify);
|
fastd_shell_command_unset(&conf.on_verify);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_STATUS_SOCKET
|
||||||
|
free(conf.status_socket);
|
||||||
|
#endif
|
||||||
|
|
||||||
free(conf.user);
|
free(conf.user);
|
||||||
free(conf.group);
|
free(conf.group);
|
||||||
free(conf.groups);
|
free(conf.groups);
|
||||||
|
|
17
src/config.y
17
src/config.y
|
@ -116,6 +116,8 @@
|
||||||
%token TOK_REMOTE
|
%token TOK_REMOTE
|
||||||
%token TOK_SECRET
|
%token TOK_SECRET
|
||||||
%token TOK_SECURE
|
%token TOK_SECURE
|
||||||
|
%token TOK_SOCKET
|
||||||
|
%token TOK_STATUS
|
||||||
%token TOK_STDERR
|
%token TOK_STDERR
|
||||||
%token TOK_SYNC
|
%token TOK_SYNC
|
||||||
%token TOK_SYSLOG
|
%token TOK_SYSLOG
|
||||||
|
@ -199,6 +201,7 @@ statement: peer_group_statement
|
||||||
| TOK_ON TOK_ESTABLISH on_establish ';'
|
| TOK_ON TOK_ESTABLISH on_establish ';'
|
||||||
| TOK_ON TOK_DISESTABLISH on_disestablish ';'
|
| TOK_ON TOK_DISESTABLISH on_disestablish ';'
|
||||||
| TOK_ON TOK_VERIFY on_verify ';'
|
| TOK_ON TOK_VERIFY on_verify ';'
|
||||||
|
| TOK_STATUS TOK_SOCKET status_socket ';'
|
||||||
| TOK_FORWARD forward ';'
|
| TOK_FORWARD forward ';'
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -415,8 +418,18 @@ on_verify: sync_def_async TOK_STRING {
|
||||||
#ifdef WITH_DYNAMIC_PEERS
|
#ifdef WITH_DYNAMIC_PEERS
|
||||||
fastd_shell_command_set(&conf.on_verify, $2->str, $1);
|
fastd_shell_command_set(&conf.on_verify, $2->str, $1);
|
||||||
#else
|
#else
|
||||||
fastd_config_error(&@$, state, "`on verify' is not supported by this version of fastd");
|
fastd_config_error(&@$, state, "`on verify' is not supported by this version of fastd");
|
||||||
YYERROR;
|
YYERROR;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -481,6 +481,7 @@ static inline void init(int argc, char *argv[]) {
|
||||||
fastd_cap_init();
|
fastd_cap_init();
|
||||||
|
|
||||||
init_sockets();
|
init_sockets();
|
||||||
|
fastd_status_init();
|
||||||
fastd_async_init();
|
fastd_async_init();
|
||||||
fastd_poll_init();
|
fastd_poll_init();
|
||||||
|
|
||||||
|
@ -601,6 +602,7 @@ static inline void cleanup(void) {
|
||||||
delete_peers();
|
delete_peers();
|
||||||
|
|
||||||
fastd_tuntap_close();
|
fastd_tuntap_close();
|
||||||
|
fastd_status_close();
|
||||||
close_sockets();
|
close_sockets();
|
||||||
fastd_poll_free();
|
fastd_poll_free();
|
||||||
|
|
||||||
|
|
27
src/fastd.h
27
src/fastd.h
|
@ -27,7 +27,7 @@
|
||||||
\file
|
\file
|
||||||
|
|
||||||
\em fastd main header file defining most data structures
|
\em fastd main header file defining most data structures
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -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 */
|
fastd_shell_command_t on_verify; /**< The command to execute to check if a connection from an unknown peer should be allowed */
|
||||||
#endif
|
#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 */
|
bool daemon; /**< Set to make fastd fork to the background after initialization */
|
||||||
char *pid_file; /**< A filename to write fastd's PID to */
|
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 */
|
VECTOR(struct pollfd) pollfds; /**< The vector of pollfds for all file descriptors */
|
||||||
#endif
|
#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 */
|
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 */
|
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);
|
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) */
|
/** Returns a random number between \a min (inclusively) and \a max (exclusively) */
|
||||||
static inline int fastd_rand(int min, int max) {
|
static inline int fastd_rand(int min, int max) {
|
||||||
unsigned int r = (unsigned int)random();
|
unsigned int r = (unsigned int)random();
|
||||||
|
|
|
@ -93,6 +93,9 @@
|
||||||
/** Defined if on-verify support is enabled */
|
/** Defined if on-verify support is enabled */
|
||||||
#cmakedefine WITH_DYNAMIC_PEERS
|
#cmakedefine WITH_DYNAMIC_PEERS
|
||||||
|
|
||||||
|
/** Defined if status socket support is enabled */
|
||||||
|
#cmakedefine WITH_STATUS_SOCKET
|
||||||
|
|
||||||
/** Defined if systemd support is enabled */
|
/** Defined if systemd support is enabled */
|
||||||
#cmakedefine ENABLE_SYSTEMD
|
#cmakedefine ENABLE_SYSTEMD
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,8 @@ static const keyword_t keywords[] = {
|
||||||
{ "remote", TOK_REMOTE },
|
{ "remote", TOK_REMOTE },
|
||||||
{ "secret", TOK_SECRET },
|
{ "secret", TOK_SECRET },
|
||||||
{ "secure", TOK_SECURE },
|
{ "secure", TOK_SECURE },
|
||||||
|
{ "socket", TOK_SOCKET },
|
||||||
|
{ "status", TOK_STATUS },
|
||||||
{ "stderr", TOK_STDERR },
|
{ "stderr", TOK_STDERR },
|
||||||
{ "sync", TOK_SYNC },
|
{ "sync", TOK_SYNC },
|
||||||
{ "syslog", TOK_SYSLOG },
|
{ "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 */
|
/** 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] = "";
|
char addr_buf[INET6_ADDRSTRLEN] = "";
|
||||||
|
|
||||||
switch (address->sa.sa_family) {
|
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");
|
return snprintf(buffer, size, "any");
|
||||||
|
|
||||||
case AF_INET:
|
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));
|
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)))
|
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));
|
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;
|
return 0;
|
||||||
|
|
||||||
case AF_INET6:
|
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));
|
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))) {
|
if (inet_ntop(AF_INET6, &address->in6.sin6_addr, addr_buf, sizeof(addr_buf))) {
|
||||||
char ifname_buf[IF_NAMESIZE];
|
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;
|
iface = (*format == 'L') ? va_arg(ap, const char *) : NULL;
|
||||||
|
|
||||||
if (p)
|
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
|
else
|
||||||
buffer += snprintf_safe(buffer, buffer_end-buffer, "(null)");
|
buffer += snprintf_safe(buffer, buffer_end-buffer, "(null)");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -53,7 +53,9 @@ typedef enum fastd_loglevel {
|
||||||
} fastd_loglevel_t;
|
} 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, ...);
|
void fastd_logf(const fastd_loglevel_t level, const char *format, ...);
|
||||||
|
|
||||||
/** Logs a formatted fatal error message */
|
/** 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 */
|
/** Handles the --config option */
|
||||||
static void option_config(const char *arg) {
|
static void option_config(const char *arg) {
|
||||||
if (!strcmp(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(version, "--version" OR "-v", "Shows the fastd version");
|
||||||
OPTION(option_daemon, "--daemon" OR "-d", "Runs fastd in the background");
|
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");
|
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;
|
SEPARATOR;
|
||||||
|
|
||||||
OPTION_ARG(option_config, "--config" OR "-c", "<filename>", "Loads a config file");
|
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)
|
if (ctx.epoll_fd < 0)
|
||||||
exit_errno("epoll_create1");
|
exit_errno("epoll_create1");
|
||||||
|
|
||||||
struct epoll_event event = {
|
struct epoll_event event_async = {
|
||||||
.events = EPOLLIN,
|
.events = EPOLLIN,
|
||||||
.data.ptr = &ctx.async_rfd,
|
.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");
|
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) {
|
void fastd_poll_free(void) {
|
||||||
|
@ -161,6 +171,12 @@ void fastd_poll_handle(void) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (events[i].events & EPOLLIN)
|
||||||
fastd_async_handle();
|
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 {
|
else {
|
||||||
fastd_socket_t *sock = events[i].data.ptr;
|
fastd_socket_t *sock = events[i].data.ptr;
|
||||||
|
|
||||||
|
@ -180,7 +196,7 @@ void fastd_poll_handle(void) {
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void fastd_poll_init(void) {
|
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) {
|
VECTOR_INDEX(ctx.pollfds, 0) = (struct pollfd) {
|
||||||
.fd = -1,
|
.fd = -1,
|
||||||
|
@ -194,9 +210,19 @@ void fastd_poll_init(void) {
|
||||||
.revents = 0,
|
.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;
|
size_t i;
|
||||||
for (i = 0; i < ctx.n_socks; 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,
|
.fd = -1,
|
||||||
.events = POLLIN,
|
.events = POLLIN,
|
||||||
.revents = 0,
|
.revents = 0,
|
||||||
|
@ -214,16 +240,16 @@ void fastd_poll_set_fd_tuntap(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void fastd_poll_set_fd_sock(size_t i) {
|
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) {
|
void fastd_poll_set_fd_peer(size_t i) {
|
||||||
fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i);
|
fastd_peer_t *peer = VECTOR_INDEX(ctx.peers, i);
|
||||||
|
|
||||||
if (!peer->sock || !fastd_peer_is_socket_dynamic(peer))
|
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
|
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) {
|
void fastd_poll_add_peer(void) {
|
||||||
|
@ -237,7 +263,7 @@ void fastd_poll_add_peer(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void fastd_poll_delete_peer(size_t i) {
|
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)
|
if (timeout < 0 || timeout > maintenance_timeout)
|
||||||
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");
|
exit_bug("fd count mismatch");
|
||||||
|
|
||||||
sigset_t set, oldset;
|
sigset_t set, oldset;
|
||||||
|
@ -324,12 +350,17 @@ void fastd_poll_handle(void) {
|
||||||
if (VECTOR_INDEX(ctx.pollfds, 1).revents & POLLIN)
|
if (VECTOR_INDEX(ctx.pollfds, 1).revents & POLLIN)
|
||||||
fastd_async_handle();
|
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++) {
|
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]);
|
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]);
|
fastd_receive(&ctx.socks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,15 +368,15 @@ void fastd_poll_handle(void) {
|
||||||
for (i = 0; i < VECTOR_LEN(ctx.peers); i++) {
|
for (i = 0; i < VECTOR_LEN(ctx.peers); i++) {
|
||||||
fastd_peer_t *peer = VECTOR_INDEX(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);
|
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);
|
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");
|
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