From 179be41f1835cf3b58cfc1cb6fb7e66d75fb73ad Mon Sep 17 00:00:00 2001 From: Alex 'AdUser' Z Date: Mon, 18 Jan 2021 12:38:43 +1000 Subject: [PATCH] * general cleanup : drop remaining f2b_cmsg_t --- src/CMakeLists.txt | 2 +- src/appconfig.c | 1 - src/appconfig.h | 1 - src/csocket.c | 252 ++++++++++----------------------------------- src/csocket.h | 63 ++---------- src/daemon.c | 122 ++++++++++++---------- 6 files changed, 130 insertions(+), 311 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4252e69..4d80b81 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(SOURCES "daemon.c" "strlcpy.c" "config.c" "log.c" "matches.c" "ipaddr.c" +set(SOURCES "daemon.c" "strlcpy.c" "config.c" "buf.c" "log.c" "matches.c" "ipaddr.c" "appconfig.c" "statefile.c" "source.c" "filter.c" "backend.c" "jail.c") if (WITH_CSOCKET) diff --git a/src/appconfig.c b/src/appconfig.c index 7969dfe..d20d721 100644 --- a/src/appconfig.c +++ b/src/appconfig.c @@ -11,7 +11,6 @@ f2b_appconfig_t appconfig = { .daemon = false, - .csock = -1, .uid = 0, .gid = 0, .logdest = "file", diff --git a/src/appconfig.h b/src/appconfig.h index 54cd89b..9967bb1 100644 --- a/src/appconfig.h +++ b/src/appconfig.h @@ -14,7 +14,6 @@ typedef struct f2b_appconfig_t { bool daemon; uid_t uid; gid_t gid; - int csock; char logdest[CONFIG_KEY_MAX]; char config_path[PATH_MAX]; char logfile_path[PATH_MAX]; diff --git a/src/csocket.c b/src/csocket.c index fffc1a4..c484b5f 100644 --- a/src/csocket.c +++ b/src/csocket.c @@ -5,236 +5,98 @@ * published by the Free Software Foundation. */ #include "common.h" +#include "buf.h" +#include "log.h" #include "commands.h" #include "csocket.h" -#include "log.h" -int +#include +#include +#include + +typedef struct f2b_conn_t { + int sock; + const char *path; + f2b_buf_t recv; + f2b_buf_t send; +} f2b_conn_t; + +struct f2b_csock_t { + f2b_conn_t *clients[MAXCONNS]; + const char *path; + int sock; + bool shutdown; +}; + +f2b_csock_t * f2b_csocket_create(const char *path) { + f2b_csock_t *csock; struct sockaddr_un addr; - int csock = -1; - int flags = -1; + int sock = -1; assert(path != NULL); - if ((csock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) { f2b_log_msg(log_error, "can't create control socket: %s", strerror(errno)); - return -1; + return NULL; } memset(&addr, 0x0, sizeof(addr)); addr.sun_family = AF_UNIX; strlcpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - if ((flags = fcntl(csock, F_GETFL, 0)) < 0) - return -1; - if (fcntl(csock, F_SETFL, flags | O_NONBLOCK) < 0) { - f2b_log_msg(log_error, "can't set non-blocking mode on socket: %s", strerror(errno)); - return -1; - } - unlink(path); - if (bind(csock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) != 0) { + if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) != 0) { f2b_log_msg(log_error, "bind() on socket failed: %s", strerror(errno)); - return -1; + return NULL; } - return csock; -} - -void -f2b_csocket_destroy(int sock, const char *path) { - assert(path != NULL); - - if (sock >= 0) - close(sock); - unlink(path); - - return; -} - -int -f2b_csocket_connect(const char *spath, const char *cpath) { - struct sockaddr_un caddr, saddr; - int csock = -1; - - assert(spath != NULL); - assert(cpath != NULL); - - memset(&saddr, 0x0, sizeof(caddr)); - memset(&caddr, 0x0, sizeof(saddr)); - - caddr.sun_family = AF_LOCAL; - strlcpy(caddr.sun_path, cpath, sizeof(caddr.sun_path)); - saddr.sun_family = AF_LOCAL; - strlcpy(saddr.sun_path, spath, sizeof(saddr.sun_path)); - - if ((csock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { - f2b_log_msg(log_error, "can't create control socket"); - return -1; + if (listen(sock, 5) < 0) { + f2b_log_msg(log_error, "listen() on socket failed: %s", strerror(errno)); + return NULL; } - if (bind(csock, (struct sockaddr *) &caddr, sizeof(struct sockaddr_un)) != 0) { - f2b_log_msg(log_error, "bind() to local side of socket failed: %s", strerror(errno)); - return -1; - } - - if (connect(csock, (struct sockaddr *) &saddr, sizeof(struct sockaddr_un)) != 0) { - f2b_log_msg(log_error, "connect() to socket failed: %s", strerror(errno)); - return -1; + if ((csock = calloc(1, sizeof(f2b_csock_t))) == NULL) { + f2b_log_msg(log_error, "can't allocate memory for csocket struct"); + shutdown(sock, SHUT_RDWR); + unlink(path); + return NULL; } + csock->sock = sock; + csock->path = path; return csock; } void -f2b_csocket_disconnect(int sock, const char *cpath) { - unlink(cpath); - if (sock >= 0) - close(sock); - return; -} - -void -f2b_csocket_rtimeout(int sock, float timeout) { - int ret = 0; - struct timeval tv; - tv.tv_sec = (int) timeout; - tv.tv_usec = (int) ((timeout - tv.tv_sec) * 1000000); - ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(struct timeval)); - if (ret == 0) - return; - f2b_log_msg(log_warn, "can't set recv timeout for csocket: %s", strerror(errno)); -} - -const char * -f2b_csocket_error(int retcode) { - const char *err = "no error"; - switch (retcode) { - case -1 : err = strerror(errno); break; - case -2 : err = "damaged cmsg on socket: truncated"; break; - case -3 : err = "damaged cmsg on socket: no magic"; break; - case -4 : err = "damaged cmsg on socket: version mismatch"; break; - case -5 : err = "damaged cmsg on socket: unknown command type"; break; - case -6 : err = "damaged cmsg on socket: size mismatch"; break; - default : err = "unknown cmsg error"; break; +f2b_csocket_destroy(f2b_csock_t *csock) { + f2b_conn_t *conn = NULL; + assert(csock != NULL); + + if (csock->sock >= 0) + shutdown(csock->sock, SHUT_RDWR); + if (csock->path != NULL) + unlink(csock->path); + for (int i = 0; i < MAXCONNS; i++) { + if ((conn = csock->clients[i]) == NULL) + continue; + shutdown(conn->sock, SHUT_RDWR); + f2b_buf_free(&conn->recv); + f2b_buf_free(&conn->send); + free(conn); } - return err; -} - -int -f2b_csocket_recv(int csock, f2b_cmsg_t *cmsg, struct sockaddr_storage *addr, socklen_t *addrlen) { - struct msghdr msg; - uint16_t size; - int ret; - - assert(csock >= 0); - assert(cmsg != NULL); - - struct iovec iov[] = { - { .iov_len = sizeof(cmsg->magic), .iov_base = &cmsg->magic[0] }, - { .iov_len = sizeof(cmsg->version), .iov_base = &cmsg->version }, - { .iov_len = sizeof(cmsg->type), .iov_base = &cmsg->type }, - { .iov_len = sizeof(cmsg->flags), .iov_base = &cmsg->flags }, - { .iov_len = sizeof(cmsg->size), .iov_base = &size /* need ntohs */ }, - { .iov_len = sizeof(cmsg->pass), .iov_base = &cmsg->pass[0] }, - { .iov_len = sizeof(cmsg->data), .iov_base = &cmsg->data[0] }, - }; - - memset(&msg, 0x0, sizeof(msg)); - msg.msg_name = addr; - msg.msg_namelen = *addrlen; - msg.msg_iov = iov; - msg.msg_iovlen = 7; - - ret = recvmsg(csock, &msg, 0); - if (ret < 0 && errno == EAGAIN) - return 0; /* non-blocking mode & no messages */ - if (ret < 0) - return -1; /* recvmsg() error, see errno */ - if (msg.msg_flags & MSG_TRUNC) - return -2; /* truncated */ - if (memcmp(cmsg->magic, "F2B", 3) != 0) - return -3; /* no magic */ - if (cmsg->version != F2B_PROTO_VER) - return -4; /* version mismatch */ - if (cmsg->type >= CMD_MAX_NUMBER) - return -5; /* unknown command */ - cmsg->size = ntohs(size); - if (ret != (cmsg->size + 16)) - return -6; /* size mismatch */ - *addrlen = msg.msg_namelen; - - return ret; -} + free(csock); -int -f2b_csocket_send(int csock, f2b_cmsg_t *cmsg, struct sockaddr_storage *addr, socklen_t *addrlen) { - struct msghdr msg; - uint16_t size; - int ret; - - assert(csock >= 0); - assert(cmsg != NULL); - - struct iovec iov[] = { - { .iov_len = sizeof(cmsg->magic), .iov_base = &cmsg->magic[0] }, - { .iov_len = sizeof(cmsg->version), .iov_base = &cmsg->version }, - { .iov_len = sizeof(cmsg->type), .iov_base = &cmsg->type }, - { .iov_len = sizeof(cmsg->flags), .iov_base = &cmsg->flags }, - { .iov_len = sizeof(cmsg->size), .iov_base = &size /* need htons */ }, - { .iov_len = sizeof(cmsg->pass), .iov_base = &cmsg->pass[0] }, - { .iov_len = cmsg->size, .iov_base = &cmsg->data[0] }, - }; - size = htons(cmsg->size); - - memset(&msg, 0x0, sizeof(msg)); - msg.msg_name = addr; - msg.msg_namelen = *addrlen; - msg.msg_iov = iov; - msg.msg_iovlen = 7; - - if ((ret = sendmsg(csock, &msg, 0)) <= 0) - return -1; /* see errno */ - - return ret; + return; } int -f2b_csocket_poll(int csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)) { - char res[DATA_LEN_MAX + 1]; - f2b_cmsg_t cmsg; - struct sockaddr_storage addr; - socklen_t addrlen; +f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)) { + f2b_cmd_t *cmd = NULL; int ret, processed = 0; - assert(csock >= 0); + assert(csock != NULL); assert(cb != NULL); - while (1) { - memset(&cmsg, 0x0, sizeof(cmsg)); - memset(&addr, 0x0, sizeof(addr)); - addrlen = sizeof(addr); - ret = f2b_csocket_recv(csock, &cmsg, &addr, &addrlen); - if (ret == 0) - break; /* no messages */ - if (ret < 0) { - f2b_log_msg(log_error, "%s", f2b_csocket_error(ret)); - } - /* TODO: check auth */ - cb(&cmsg, res, sizeof(res)); - if (cmsg.flags & CMSG_FLAG_NEED_REPLY) { - memset(&cmsg, 0x0, sizeof(cmsg)); - strncpy(cmsg.magic, "F2B", sizeof(cmsg.magic)); - strlcpy(cmsg.data, res, sizeof(cmsg.data)); - cmsg.version = F2B_PROTO_VER; - cmsg.type = CMD_RESP; - cmsg.size = strlen(res); - cmsg.data[cmsg.size] = '\0'; - ret = f2b_csocket_send(csock, &cmsg, &addr, &addrlen); - } - processed++; - } - return processed; } diff --git a/src/csocket.h b/src/csocket.h index 725b594..f2559c9 100644 --- a/src/csocket.h +++ b/src/csocket.h @@ -7,56 +7,27 @@ #ifndef F2B_CSOCKET_H_ #define F2B_CSOCKET_H_ +#define MAXCONNS 5 + +typedef struct f2b_csock_t f2b_csock_t; + /** * @file * This file contains control socket manage routines */ -#include -#include -#include - /** * @brief Create UNIX socket with given path * @param path Path to socket endpoint * @returns Socket fd */ -int f2b_csocket_create (const char *path); +f2b_csock_t * f2b_csocket_create (const char *path); /** * @brief Close UNIX socket and unlink endpoint * @param csock Socket fd * @param path Path to socket endpoint */ -void f2b_csocket_destroy(int csock, const char *path); - -/** - * @brief Connect to given socket - * @param spath path to control socket endpoint - * @param cpath Path to client socket's endpoint - * @returns Connected fd or -1 on error - */ -int f2b_csocket_connect(const char *spath, const char *cpath); -/** - * @brief Close client connection and unlink client's endpoint - * @param csock Socket fd - * @param cpath Path to client socket's endpoint - */ -void f2b_csocket_disconnect(int csock, const char *cpath); - -/** - * @brief Set recieve rimeout on socket - * @param csock Socket fd - * @param timeout Timeout in seconds - */ -void f2b_csocket_rtimeout(int csock, float timeout); - -/** - * @brief Get error description for f2b_csocket_recv() - * @param retcode Return code fromf2b_csocket_recv() - * @returns Pointer to errro description - */ -const char * -f2b_csocket_error(int retcode); +void f2b_csocket_destroy(f2b_csock_t *csock); /** * @brief Poll control socket for new messages @@ -64,26 +35,6 @@ f2b_csocket_error(int retcode); * @param cb Callback for handling message * @returns -1 on error, 0 on no messages, and > 0 on some messages processed */ -int f2b_csocket_poll(int csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)); - -/** - * @brief Pack and send control message - * @param csock Opened socket fd - * @param cmsg Control message pointer - * @param addr Pointer for destination address store - * @param addrlen Size of address storage - * @returns >0 on success - */ -int f2b_csocket_send(int csock, f2b_cmsg_t *cmsg, struct sockaddr_storage *addr, socklen_t *addrlen); - -/** - * @brief Recieve and unpack control message - * @param csock Opened socket fd - * @param cmsg Control message pointer - * @param addr Pointer for sender address store - * @param addrlen Size of address storage - * @returns >0 on success, 0 on no avalilable messages, <0 on error - */ -int f2b_csocket_recv(int csock, f2b_cmsg_t *cmsg, struct sockaddr_storage *addr, socklen_t *addrlen); +int f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)); #endif /* F2B_CSOCKET_H_ */ diff --git a/src/daemon.c b/src/daemon.c index e8c2bbc..e11fce0 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -10,6 +10,7 @@ #include "jail.h" #include "backend.h" #include "appconfig.h" +#include "buf.h" #include "commands.h" #include "csocket.h" @@ -55,89 +56,95 @@ void usage(int exitcode) { exit(exitcode); } +static f2b_csock_t *csock = NULL; #ifndef WITH_CSOCKET /* add stubs to reduce #ifdef count */ -int f2b_csocket_create (const char *path) { +f2b_csock_t * +f2b_csocket_create (const char *path) { UNUSED(path); f2b_log_msg(log_warn, "control socket support was disabled at compile-time"); - return -1; + return NULL; } -void f2b_csocket_destroy(int csock, const char *path) { - UNUSED(csock); UNUSED(path); return; +void +f2b_csocket_destroy(f2b_csock_t *csock) { + UNUSED(csock); return; } -int f2b_csocket_poll(int csock, void (*cb)(const f2b_cmsg_t *msg, char *res, size_t ressize)) { +int f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)) { UNUSED(csock); UNUSED(cb); return 0; } void -f2b_cmsg_process(const f2b_cmsg_t *msg, char *res, size_t ressize) { - UNUSED(msg); UNUSED(res); UNUSED(ressize); return; +f2b_csocket_cmd_process(const f2b_cmd_t *cmd, f2b_buf_t *res) { + UNUSED(cmd); UNUSED(res); return; } #else /* WITH_CSOCKET */ void -f2b_cmsg_process(const f2b_cmsg_t *msg, char *res, size_t ressize) { - const char *args[DATA_ARGS_MAX]; +f2b_csocket_cmd_process(const f2b_cmd_t *cmd, f2b_buf_t *res) { f2b_jail_t *jail = NULL; - char line[LINE_MAX]; + char buf[4096] = ""; + size_t len; - assert(msg != NULL); + assert(cmd != NULL); assert(res != NULL); - assert(msg->type < CMD_MAX_NUMBER); - if (msg->type == CMD_NONE) + if (cmd->type == CMD_UNKNOWN) return; - memset(args, 0x0, sizeof(args)); - int argc = f2b_cmsg_extract_args(msg, args); - - if (f2b_cmd_check_argc(msg->type, argc) == false) { - strlcpy(res, "cmd args number mismatch", ressize); - return; - } - - if (msg->type >= CMD_JAIL_STATUS && msg->type <= CMD_MAX_NUMBER) { - if ((jail = f2b_jail_find(jails, args[0])) == NULL) { - snprintf(res, ressize, "can't find jail '%s'", args[0]); + if (cmd->type >= CMD_JAIL_STATUS && cmd->type <= CMD_JAIL_FILTER_RELOAD) { + if ((jail = f2b_jail_find(jails, cmd->args[1])) == NULL) { + len = snprintf(buf, sizeof(buf), "can't find jail '%s'\n", cmd->args[1]); + f2b_buf_append(res, buf, len); return; } } - strlcpy(res, "ok", ressize); /* default reply */ - if (msg->type == CMD_PING) { - /* nothing to do */ - } else if (msg->type == CMD_RELOAD) { + if (cmd->type == CMD_RELOAD) { state = reconfig; - } else if (msg->type == CMD_LOG_ROTATE) { + } else if (cmd->type == CMD_LOG_ROTATE) { state = logrotate; - } else if (msg->type == CMD_LOG_LEVEL) { - f2b_log_set_level(args[0]); - } else if (msg->type == CMD_SHUTDOWN) { + } else if (cmd->type == CMD_LOG_LEVEL) { + f2b_log_set_level(cmd->args[2]); + } else if (cmd->type == CMD_SHUTDOWN) { state = stop; - } else if (msg->type == CMD_STATUS) { - snprintf(line, sizeof(line), "pid: %u\npidfile: %s\ncsocket: %s\nstatedir: %s\njails:\n", - getpid(), appconfig.pidfile_path, appconfig.csocket_path, appconfig.statedir_path); - strlcpy(res, line, ressize); + } else if (cmd->type == CMD_STATUS) { + len = snprintf(buf, sizeof(buf), "pid: %u\npidfile: %s\n", getpid(), appconfig.pidfile_path); + f2b_buf_append(res, buf, len); + len = snprintf(buf, sizeof(buf), "csocket: %s\n", appconfig.csocket_path); + f2b_buf_append(res, buf, len); + len = snprintf(buf, sizeof(buf), "statedir: %s\n", appconfig.statedir_path); + f2b_buf_append(res, buf, len); + f2b_buf_append(res, "jails:\n", 0); for (jail = jails; jail != NULL; jail = jail->next) { - snprintf(line, sizeof(line), "- %s\n", jail->name); - strlcat(res, line, ressize); + len = snprintf(buf, sizeof(buf), "- %s\n", jail->name); + f2b_buf_append(res, buf, len); } - } else if (msg->type == CMD_JAIL_STATUS) { - f2b_jail_cmd_status(res, ressize, jail); - } else if (msg->type == CMD_JAIL_SET) { - f2b_jail_cmd_set(res, ressize, jail, args[1], args[2]); - } else if (msg->type == CMD_JAIL_IP_STATUS) { - f2b_jail_cmd_ip_xxx(res, ressize, jail, 0, args[1]); - } else if (msg->type == CMD_JAIL_IP_BAN) { - f2b_jail_cmd_ip_xxx(res, ressize, jail, 1, args[1]); - } else if (msg->type == CMD_JAIL_IP_RELEASE) { - f2b_jail_cmd_ip_xxx(res, ressize, jail, -1, args[1]); - } else if (msg->type == CMD_JAIL_FILTER_STATS) { - f2b_filter_cmd_stats(res, ressize, jail->filter); - } else if (msg->type == CMD_JAIL_FILTER_RELOAD) { - f2b_filter_cmd_reload(res, ressize, jail->filter); + } else if (cmd->type == CMD_JAIL_STATUS) { + f2b_jail_cmd_status(buf, sizeof(buf), jail); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_SET) { + f2b_jail_cmd_set(buf, sizeof(buf), jail, cmd->args[3], cmd->args[4]); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_IP_STATUS) { + f2b_jail_cmd_ip_xxx(buf, sizeof(buf), jail, 0, cmd->args[4]); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_IP_BAN) { + f2b_jail_cmd_ip_xxx(buf, sizeof(buf), jail, 1, cmd->args[4]); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_IP_RELEASE) { + f2b_jail_cmd_ip_xxx(buf, sizeof(buf), jail, -1, cmd->args[4]); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_FILTER_STATS) { + f2b_filter_cmd_stats(buf, sizeof(buf), jail->filter); + f2b_buf_append(res, buf, 0); + } else if (cmd->type == CMD_JAIL_FILTER_RELOAD) { + f2b_filter_cmd_reload(buf, sizeof(buf), jail->filter); + f2b_buf_append(res, buf, 0); } else { - strlcpy(res, "error: unsupported command type", ressize); + f2b_buf_append(res, "error: unknown command\n", 0); } + if (res->used == 0) + f2b_buf_append(res, "ok\n", 3); /* default reply if not set above */ + return; } #endif /* WITH_CSOCKET */ @@ -288,8 +295,9 @@ int main(int argc, char *argv[]) { } } - if (appconfig.csocket_path[0] != '\0') - appconfig.csock = f2b_csocket_create(appconfig.csocket_path); + if (appconfig.csocket_path[0] != '\0') { + csock = f2b_csocket_create(appconfig.csocket_path); + } if (config.defaults) f2b_jail_set_defaults(config.defaults); @@ -306,7 +314,7 @@ int main(int argc, char *argv[]) { for (f2b_jail_t *jail = jails; jail != NULL; jail = jail->next) { f2b_jail_process(jail); } - f2b_csocket_poll(appconfig.csock, f2b_cmsg_process); + f2b_csocket_poll(csock, f2b_csocket_cmd_process); sleep(1); if (state == logrotate && strcmp(appconfig.logdest, "file") == 0) { state = run; @@ -328,7 +336,7 @@ int main(int argc, char *argv[]) { } } - f2b_csocket_destroy(appconfig.csock, appconfig.csocket_path); + f2b_csocket_destroy(csock); jails_stop(jails); jails = NULL;