Browse Source

* refactor source modules for new library interface

master
Alex 'AdUser' Z 3 years ago
parent
commit
bc2455852e
  1. 55
      src/sources/files.c
  2. 48
      src/sources/portknock.c
  3. 51
      src/sources/redis.c
  4. 38
      src/sources/source.c
  5. 38
      src/sources/source.h

55
src/sources/files.c

@ -4,14 +4,15 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "source.h"
#include <limits.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <glob.h>
#include "source.h"
#define MODNAME "files"
typedef struct f2b_file_t {
struct f2b_file_t *next;
bool opened;
@ -22,17 +23,12 @@ typedef struct f2b_file_t {
struct _config {
char path[256];
char error[256];
void (*errcb)(const char *errstr);
void (*logcb)(enum loglevel lvl, const char *msg);
f2b_file_t *files;
f2b_file_t *current;
};
static void
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
#include "source.c"
static bool
file_open(f2b_file_t *file, const char *path) {
@ -77,21 +73,24 @@ file_close(f2b_file_t *file) {
}
static bool
file_rotated(const f2b_file_t *file) {
file_rotated(const cfg_t *cfg, const f2b_file_t *file) {
struct stat st;
assert(file != NULL);
if (!file->opened)
return true;
if (stat(file->path, &st) != 0)
if (stat(file->path, &st) != 0) {
log_msg(cfg, error, "file stat error: %s", strerror(errno));
return true;
}
if (file->st.st_dev != st.st_dev ||
file->st.st_ino != st.st_ino ||
file->st.st_size > st.st_size)
file->st.st_size > st.st_size) {
log_msg(cfg, info, "file replaced: %s", file->path);
return true;
}
return false;
}
@ -117,7 +116,7 @@ create(const char *init) {
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL;
strlcpy(cfg->path, init, sizeof(cfg->path));
cfg->errcb = &errcb_stub;
cfg->logcb = &logcb_stub;
return cfg;
}
@ -143,21 +142,6 @@ ready(cfg_t *cfg) {
return true;
}
char *
error(cfg_t *cfg) {
assert(cfg != NULL);
return cfg->error;
}
void
errcb(cfg_t *cfg, void (*cb)(const char *errstr)) {
assert(cfg != NULL);
assert(cb != NULL);
cfg->errcb = cb;
}
bool
start(cfg_t *cfg) {
f2b_file_t *file = NULL;
@ -172,11 +156,7 @@ start(cfg_t *cfg) {
if ((file = calloc(1, sizeof(f2b_file_t))) == NULL)
continue;
if (file_open(file, globbuf.gl_pathv[i]) == false) {
if (cfg->errcb) {
snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s -- %s",
globbuf.gl_pathv[i], strerror(errno));
cfg->errcb(cfg->error);
}
log_msg(cfg, error, "can't open file: %s -- %s", globbuf.gl_pathv[i], strerror(errno));
free(file);
continue;
}
@ -217,13 +197,10 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
cfg->current = cfg->files;
for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) {
if (file_rotated(file))
if (file_rotated(cfg, file))
file_close(file);
if (!file->opened && !file_open(file, NULL)) {
if (cfg->errcb) {
snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s", file->path);
cfg->errcb(cfg->error);
}
log_msg(cfg, error, "can't open file: %s", file->path);
continue;
}
if (file_getline(file, buf, bufsize))

48
src/sources/portknock.c

@ -4,8 +4,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "source.h"
#include <ctype.h>
#include <fcntl.h>
#include <sys/socket.h>
@ -13,6 +11,8 @@
#include <arpa/inet.h>
#include <netdb.h>
#include "source.h"
#define MODNAME "portknock"
#define HOST_MAX 48
#define PORT_MAX 6
@ -25,17 +25,12 @@ typedef struct f2b_port_t {
struct _config {
char name[32];
char error[256];
void (*errcb)(const char *errstr);
void (*logcb)(enum loglevel lvl, const char *msg);
f2b_port_t *ports;
f2b_port_t *current;
};
static void
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
#include "source.c"
static bool
try_parse_listen_opt(f2b_port_t *port, const char *value) {
@ -79,7 +74,7 @@ create(const char *init) {
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL;
strlcpy(cfg->name, init, sizeof(cfg->name));
cfg->errcb = &errcb_stub;
cfg->logcb = &logcb_stub;
return cfg;
}
@ -92,11 +87,11 @@ config(cfg_t *cfg, const char *key, const char *value) {
if (strcmp(key, "listen") == 0) {
f2b_port_t *port = NULL;
if ((port = calloc(1, sizeof(f2b_port_t))) == NULL) {
strlcpy(cfg->error, "out of memory", sizeof(cfg->error));
log_msg(cfg, error, "out of memory");
return false;
}
if (try_parse_listen_opt(port, value) == false) {
snprintf(cfg->error, sizeof(cfg->error), "can't parse: %s", value);
log_msg(cfg, error, "can't parse: %s", value);
free(port);
return false;
}
@ -116,21 +111,6 @@ ready(cfg_t *cfg) {
return false;
}
char *
error(cfg_t *cfg) {
assert(cfg != NULL);
return cfg->error;
}
void
errcb(cfg_t *cfg, void (*cb)(const char *errstr)) {
assert(cfg != NULL);
assert(cb != NULL);
cfg->errcb = cb;
}
bool
start(cfg_t *cfg) {
struct addrinfo hints;
@ -148,8 +128,7 @@ start(cfg_t *cfg) {
port->sock = -1;
int ret = getaddrinfo(port->host, port->port, &hints, &result);
if (ret != 0) {
snprintf(cfg->error, sizeof(cfg->error), "getaddrinfo: %s", gai_strerror(ret));
cfg->errcb(cfg->error);
log_msg(cfg, error, "getaddrinfo: %s", gai_strerror(ret));
continue;
}
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
@ -169,10 +148,8 @@ start(cfg_t *cfg) {
}
}
freeaddrinfo(result);
if (port->sock < 0) {
snprintf(cfg->error, sizeof(cfg->error), "can't bind/listen on %s:%s", port->host, port->port);
cfg->errcb(cfg->error);
}
if (port->sock < 0)
log_msg(cfg, error, "can't bind/listen on %s:%s", port->host, port->port);
}
return true;
@ -208,8 +185,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
if (sock < 0 && errno == EAGAIN)
continue;
if (sock < 0) {
snprintf(cfg->error, sizeof(cfg->error), "accept error: %s", strerror(errno));
cfg->errcb(cfg->error);
log_msg(cfg, error, "accept() error: %s", strerror(errno));
continue;
}
close(sock);
@ -221,7 +197,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &addr)->sin6_addr), buf, bufsize);
return true;
}
cfg->errcb("can't convert sockaddr to string: unknown AF");
cfg->logcb(error, "can't convert sockaddr to string: unknown AF");
}
return false;

51
src/sources/redis.c

@ -4,20 +4,20 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "source.h"
#include <stdint.h>
#include <hiredis/hiredis.h>
#include "../strlcpy.h"
#include "source.h"
#define MODNAME "redis"
#define ID_MAX 32
struct _config {
char name[ID_MAX + 1];
char hash[ID_MAX * 2];
char error[256];
void (*errcb)(const char *errstr);
void (*logcb)(enum loglevel lvl, const char *msg);
time_t timeout;
uint8_t database;
char password[32];
@ -26,11 +26,7 @@ struct _config {
redisContext *conn;
};
static void
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
#include "source.c"
static bool
redis_connect(cfg_t *cfg) {
@ -47,14 +43,14 @@ redis_connect(cfg_t *cfg) {
if (!conn)
break;
if (conn->err) {
snprintf(cfg->error, sizeof(cfg->error), "Connection error: %s", conn->errstr);
log_msg(cfg, error, "connection error: %s", conn->errstr);
break;
}
if (cfg->password[0]) {
if ((reply = redisCommand(conn, "AUTH %s", cfg->password)) == NULL)
break;
if (reply->type == REDIS_REPLY_ERROR) {
snprintf(cfg->error, sizeof(cfg->error), "auth error: %s", reply->str);
log_msg(cfg, error, "auth error: %s", reply->str);
break;
}
freeReplyObject(reply);
@ -63,7 +59,7 @@ redis_connect(cfg_t *cfg) {
if ((reply = redisCommand(conn, "SELECT %d", cfg->database)) == NULL)
break;
if (reply->type == REDIS_REPLY_ERROR) {
snprintf(cfg->error, sizeof(cfg->error), "auth error: %s", reply->str);
log_msg(cfg, error, "reply error: %s", reply->str);
break;
}
freeReplyObject(reply);
@ -71,13 +67,13 @@ redis_connect(cfg_t *cfg) {
timeout.tv_sec = 0;
timeout.tv_usec = 10000; /* 0.01s */
if (redisSetTimeout(conn, timeout) != REDIS_OK) {
strlcpy(cfg->error, "can't enable nonblocking mode", sizeof(cfg->error));
log_msg(cfg, error, "can't enable nonblocking mode");
break;
}
if ((reply = redisCommand(conn, "SUBSCRIBE %s", cfg->hash)) == NULL)
break;
if (reply->type == REDIS_REPLY_ERROR) {
snprintf(cfg->error, sizeof(cfg->error), "can't subscribe: %s", reply->str);
log_msg(cfg, error, "can't subscribe: %s", reply->str);
break;
}
freeReplyObject(reply);
@ -118,7 +114,7 @@ create(const char *init) {
strlcpy(cfg->name, init, sizeof(cfg->name));
strlcpy(cfg->hash, "f2b-banned-", sizeof(cfg->hash));
strlcat(cfg->hash, init, sizeof(cfg->hash));
cfg->errcb = &errcb_stub;
cfg->logcb = &logcb_stub;
return cfg;
}
@ -163,21 +159,6 @@ ready(cfg_t *cfg) {
return true;
}
char *
error(cfg_t *cfg) {
assert(cfg != NULL);
return cfg->error;
}
void
errcb(cfg_t *cfg, void (*cb)(const char *errstr)) {
assert(cfg != NULL);
assert(cb != NULL);
cfg->errcb = cb;
}
bool
start(cfg_t *cfg) {
assert(cfg != NULL);
@ -209,7 +190,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
return false; /* reconnect failure */
if (cfg->conn->err) {
snprintf(cfg->error, sizeof(cfg->error), "connection error: %s", cfg->conn->errstr);
log_msg(cfg, error, "connection error: %s", cfg->conn->errstr);
return false;
}
@ -221,18 +202,16 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
strlcpy(buf, reply->element[2]->str, bufsize);
gotit = true;
} else {
cfg->errcb(cfg->error);
log_msg(cfg, error, "wrong redis message type: %s", reply->element[0]->str);
}
} else {
strlcpy(cfg->error, "reply is not a array type", sizeof(cfg->error));
cfg->errcb(cfg->error);
log_msg(cfg, error, "reply is not a array type");
}
freeReplyObject(reply);
} else if (cfg->conn->err == REDIS_ERR_IO && errno == EAGAIN) {
cfg->conn->err = 0; /* reset error to prevent reconnecting */
} else {
snprintf(cfg->error, sizeof(cfg->error), "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr);
cfg->errcb(cfg->error);
log_msg(cfg, error, "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr);
}
return gotit;

38
src/sources/source.c

@ -0,0 +1,38 @@
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* function shared between modules */
static void
logcb_stub(enum loglevel lvl, const char *str) {
assert(str != NULL);
(void)(lvl);
(void)(str);
}
__attribute__ ((format (printf, 3, 4)))
static void
log_msg(const cfg_t *cfg, enum loglevel lvl, const char *format, ...) {
char buf[4096] = "";
va_list args;
size_t len;
len = snprintf(buf, sizeof(buf), "source/%s ", MODNAME);
va_start(args, format);
vsnprintf(buf + len, sizeof(buf) - len, format, args);
va_end(args);
cfg->logcb(lvl, buf);
}
void
logcb(cfg_t *cfg, void (*cb)(enum loglevel lvl, const char *msg)) {
assert(cfg != NULL);
assert(cb != NULL);
cfg->logcb = cb;
}

38
src/sources/source.h

@ -9,11 +9,21 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include "../strlcpy.h"
enum loglevel {
debug = 0,
info = 1,
notice = 2,
warn = 3,
error = 4,
fatal = 5,
}; /* see log.h */
/**
* @file
* This header describes module API of type 'source'
@ -24,17 +34,15 @@
* f2b, source;
* f2b => source [label="create(init)"];
* f2b << source [label="module handler, cfg_t *cfg"];
* f2b => source [label="logcb(cfg, cb)"];
* |||;
* f2b => source [label="config(cfg, param, value)"];
* f2b << source [label="true"];
* f2b => source [label="config(cfg, param, value)"];
* f2b << source [label="true"];
* f2b => source [label="config(cfg, param, value)"];
* f2b <<= source [label="logcb(level, char *msg)"];
* f2b << source [label="false"];
* f2b => source [label="error(cfg)"];
* f2b << source [label="const char *error"];
* |||;
* f2b => source [label="errcb(cfg, cb), optional"];
* |||;
* f2b => source [label="ready(cfg)"];
* f2b << source [label="true"];
@ -48,7 +56,7 @@
* f2b => source [label="next(cfg, buf, sizeof(buf), true)"];
* f2b << source [label="true"];
* f2b => source [label="next(cfg, buf, sizeof(buf), false)"];
* f2b <<= source [label="errcb(char *error)"];
* f2b <<= source [label="logcb(level, char *msg)"];
* f2b << source [label="true"];
* f2b => source [label="next(cfg, buf, sizeof(buf), false)"];
* f2b << source [label="false"];
@ -81,7 +89,7 @@ extern cfg_t *create(const char *init);
* @param cfg Module handler
* @param key Parameter name
* @param value Parameter value
* @returns true on success, false on error with setting intenal error buffer
* @returns true on success, false on error
*/
extern bool config(cfg_t *cfg, const char *key, const char *value);
/**
@ -91,24 +99,16 @@ extern bool config(cfg_t *cfg, const char *key, const char *value);
*/
extern bool ready(cfg_t *cfg);
/**
* @brief Returns last error description
* @param cfg Module handler
* @returns Pointer to string with description of last error
* @note Returned pointer not marked with const, because libdl complains,
* but contents on pointer should not be modified or written in any way
*/
extern char *error(cfg_t *cfg);
/**
* @brief Sets the error callback for use in processing
* @brief Sets the log callback
* @param cfg Module handler
* @param cb Error callback
* @note Optional, if this function is not called, processing errors will be suppressed
* @param cb Logging callback
* @note Optional, if this function is not called, warnings/errors of module will be suppressed
*/
extern void errcb(cfg_t *cfg, void (*cb)(const char *errstr));
extern void logcb(cfg_t *cfg, void (*cb)(enum loglevel l, const char *msg));
/**
* @brief Allocate resources and start processing
* @param cfg Module handler
* @returns true on success, false on error with setting intenal error buffer
* @returns true on success, false on error
*/
extern bool start(cfg_t *cfg);
/**

Loading…
Cancel
Save