Browse Source

* general cleanup : drop remaining f2b_cmsg_t

master
Alex 'AdUser' Z 4 years ago
parent
commit
179be41f18
  1. 2
      src/CMakeLists.txt
  2. 1
      src/appconfig.c
  3. 1
      src/appconfig.h
  4. 252
      src/csocket.c
  5. 63
      src/csocket.h
  6. 124
      src/daemon.c

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

1
src/appconfig.c

@ -11,7 +11,6 @@
f2b_appconfig_t appconfig = {
.daemon = false,
.csock = -1,
.uid = 0,
.gid = 0,
.logdest = "file",

1
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];

252
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 <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
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 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;
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 (listen(sock, 5) < 0) {
f2b_log_msg(log_error, "listen() on socket failed: %s", strerror(errno));
return NULL;
}
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;
}
free(csock);
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;
}
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;
}

63
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 <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
/**
* @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_ */

124
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);
}
} 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);
len = snprintf(buf, sizeof(buf), "- %s\n", jail->name);
f2b_buf_append(res, buf, len);
}
} 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;

Loading…
Cancel
Save