diff --git a/src/sources/files.c b/src/sources/files.c index 44d1cba..3e0b3ad 100644 --- a/src/sources/files.c +++ b/src/sources/files.c @@ -9,16 +9,17 @@ #include #include +#include #include "source.h" #define MODNAME "files" typedef struct f2b_file_t { struct f2b_file_t *next; - bool opened; - char path[PATH_MAX]; FILE *fd; + char path[PATH_MAX]; struct stat st; + unsigned int lines; } f2b_file_t; struct _config { @@ -32,6 +33,7 @@ struct _config { static bool file_open(f2b_file_t *file, const char *path) { + FILE *fd; struct stat st; char buf[PATH_MAX] = ""; @@ -48,15 +50,17 @@ file_open(f2b_file_t *file, const char *path) { if (!(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) return false; - if ((file->fd = fopen(buf, "r")) == NULL) + if ((fd = fopen(buf, "r")) == NULL) return false; - if (S_ISREG(st.st_mode) && fseek(file->fd, 0, SEEK_END) < 0) + if (S_ISREG(st.st_mode) && fseek(fd, 0, SEEK_END) < 0) { + fclose(fd); return false; + } memcpy(&file->st, &st, sizeof(st)); strlcpy(file->path, buf, sizeof(file->path)); - file->opened = true; + file->fd = fd; return true; } @@ -65,19 +69,21 @@ static void file_close(f2b_file_t *file) { assert(file != NULL); - if (file->fd) - fclose(file->fd); + if (file->fd == NULL) + return; - file->opened = false; + fclose(file->fd); file->fd = NULL; + file->lines = 0; + memset(&file->st, 0, sizeof(struct stat)); } static bool -file_rotated(const cfg_t *cfg, const f2b_file_t *file) { +file_rotated(const cfg_t *cfg, f2b_file_t *file) { struct stat st; assert(file != NULL); - if (!file->opened) + if (file->fd == NULL) return true; if (stat(file->path, &st) != 0) { @@ -90,21 +96,25 @@ file_rotated(const cfg_t *cfg, const f2b_file_t *file) { file->st.st_size > st.st_size) { log_msg(cfg, info, "file replaced: %s", file->path); return true; + } else if (file->st.st_size < st.st_size) { + memcpy(&file->st, &st, sizeof(struct stat)); } return false; } static bool -file_getline(const f2b_file_t *file, char *buf, size_t bufsize) { +file_getline(f2b_file_t *file, char *buf, size_t bufsize) { assert(file != NULL); assert(buf != NULL); if (feof(file->fd)) clearerr(file->fd); /* fread()+EOF set is implementation defined */ - if (fgets(buf, bufsize, file->fd) != NULL) + if (fgets(buf, bufsize, file->fd) != NULL) { + file->lines++; return true; + } return false; } @@ -199,7 +209,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) { if (file_rotated(cfg, file)) file_close(file); - if (!file->opened && !file_open(file, NULL)) { + if (file->fd == NULL && !file_open(file, NULL)) { log_msg(cfg, error, "can't open file: %s", file->path); continue; } @@ -210,6 +220,40 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { return false; } +bool +stats(cfg_t *cfg, char *buf, size_t bufsize) { + struct tm tm; + char tmp[PATH_MAX + 512]; + char mtime[30]; + const char *fmt = + "- path: %s\n" + " mtime: %s\n" + " fstat: fd=%d inode=%d size=%ld pos=%ld\n" + " read: %lu lines\n"; + int fd, ino; off_t sz; long pos; + assert(cfg != NULL); + assert(buf != NULL); + assert(bufsize > 0); + + if (buf == NULL || bufsize == 0) + return false; + + for (f2b_file_t *f = cfg->files; f != NULL; f = f->next) { + if (f->fd) { + fd = fileno(f->fd), ino = f->st.st_ino, sz = f->st.st_size, pos = ftell(f->fd); + localtime_r(&f->st.st_mtime, &tm); + strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", &tm); + } else { + fd = -1, ino = -1, sz = 0, pos = -1; + strlcpy(mtime, "-", sizeof(mtime)); + } + snprintf(tmp, sizeof(tmp), fmt, f->path, mtime, fd, ino, sz, pos, f->lines); + strlcat(buf, tmp, bufsize); + } + + return true; +} + void destroy(cfg_t *cfg) { assert(cfg != NULL); diff --git a/src/sources/portknock.c b/src/sources/portknock.c index d8faafe..ec39445 100644 --- a/src/sources/portknock.c +++ b/src/sources/portknock.c @@ -20,6 +20,7 @@ typedef struct f2b_port_t { struct f2b_port_t *next; char host[HOST_MAX]; char port[PORT_MAX]; + unsigned int accepts; int sock; } f2b_port_t; @@ -188,7 +189,8 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { log_msg(cfg, error, "accept() error: %s", strerror(errno)); continue; } - close(sock); + port->accepts++; + shutdown(sock, SHUT_RDWR); if (addr.ss_family == AF_INET) { inet_ntop(AF_INET, &(((struct sockaddr_in *) &addr)->sin_addr), buf, bufsize); return true; @@ -203,6 +205,25 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { return false; } +bool +stats(cfg_t *cfg, char *buf, size_t bufsize) { + char tmp[256]; + const char *fmt = + "- listen: %s:%s\n" + " accepts: %u\n"; + assert(cfg != NULL); + + if (buf == NULL || bufsize == 0) + return false; + + for (f2b_port_t *p = cfg->ports; p != NULL; p = p->next) { + snprintf(tmp, sizeof(tmp), fmt, p->host, p->port, p->accepts); + strlcat(buf, tmp, bufsize); + } + + return true; +} + void destroy(cfg_t *cfg) { f2b_port_t *next; diff --git a/src/sources/redis.c b/src/sources/redis.c index fb0ac0b..5ed8cbc 100644 --- a/src/sources/redis.c +++ b/src/sources/redis.c @@ -23,6 +23,7 @@ struct _config { char password[32]; char host[32]; uint16_t port; + uint32_t received; redisContext *conn; }; @@ -196,6 +197,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { redisReply *reply = NULL; if (redisGetReply(cfg->conn, (void **) &reply) == REDIS_OK) { + cfg->received++; if (reply->type == REDIS_REPLY_ARRAY) { if (strcmp(reply->element[0]->str, "message") == 0 || strcmp(reply->element[1]->str, cfg->hash) == 0) { @@ -217,6 +219,28 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { return gotit; } +bool +stats(cfg_t *cfg, char *buf, size_t bufsize) { + const char *fmt = + "connected: %s\n" + "last error: %d (%s)\n" + "messages: %u\n"; + + assert(cfg != NULL); + + if (buf == NULL || bufsize == 0) + return false; + + if (cfg->conn) { + const char *err = cfg->conn->errstr[0] == '\0' ? cfg->conn->errstr : "---"; + snprintf(buf, bufsize, fmt, "yes", cfg->conn->err, err, cfg->received); + } else { + snprintf(buf, bufsize, fmt, "no", "0", "---", cfg->received); + } + + return true; +} + void destroy(cfg_t *cfg) { assert(cfg != NULL); diff --git a/src/sources/source.h b/src/sources/source.h index 5bbecb8..e005dc8 100644 --- a/src/sources/source.h +++ b/src/sources/source.h @@ -120,6 +120,14 @@ extern bool start(cfg_t *cfg); * @returns false if no new data available, or true otherwise with filling @a buf */ extern bool next(cfg_t *cfg, char *buf, size_t bufsize, bool reset); +/** + * @brief Get statistics for source + * @param cfg Module handler + * @param buf Pointer to buffer for stats report + * @param bufsize Size of buffer above (in bytes) + * @returns true on success, false on error + */ +extern bool stats(cfg_t *cfg, char *buf, size_t bufsize); /** * @brief Deallocate resources, prepare for module destroy * @param cfg Module handler