Browse Source

* refactor source modules for new library interface

master
Alex 'AdUser' Z 4 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "source.h"
#include <limits.h> #include <limits.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <glob.h> #include <glob.h>
#include "source.h"
#define MODNAME "files"
typedef struct f2b_file_t { typedef struct f2b_file_t {
struct f2b_file_t *next; struct f2b_file_t *next;
bool opened; bool opened;
@ -22,17 +23,12 @@ typedef struct f2b_file_t {
struct _config { struct _config {
char path[256]; char path[256];
char error[256]; void (*logcb)(enum loglevel lvl, const char *msg);
void (*errcb)(const char *errstr);
f2b_file_t *files; f2b_file_t *files;
f2b_file_t *current; f2b_file_t *current;
}; };
static void #include "source.c"
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
static bool static bool
file_open(f2b_file_t *file, const char *path) { file_open(f2b_file_t *file, const char *path) {
@ -77,21 +73,24 @@ file_close(f2b_file_t *file) {
} }
static bool static bool
file_rotated(const f2b_file_t *file) { file_rotated(const cfg_t *cfg, const f2b_file_t *file) {
struct stat st; struct stat st;
assert(file != NULL); assert(file != NULL);
if (!file->opened) if (!file->opened)
return true; 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; return true;
}
if (file->st.st_dev != st.st_dev || if (file->st.st_dev != st.st_dev ||
file->st.st_ino != st.st_ino || 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 true;
}
return false; return false;
} }
@ -117,7 +116,7 @@ create(const char *init) {
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL; return NULL;
strlcpy(cfg->path, init, sizeof(cfg->path)); strlcpy(cfg->path, init, sizeof(cfg->path));
cfg->errcb = &errcb_stub; cfg->logcb = &logcb_stub;
return cfg; return cfg;
} }
@ -143,21 +142,6 @@ ready(cfg_t *cfg) {
return true; 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 bool
start(cfg_t *cfg) { start(cfg_t *cfg) {
f2b_file_t *file = NULL; f2b_file_t *file = NULL;
@ -172,11 +156,7 @@ start(cfg_t *cfg) {
if ((file = calloc(1, sizeof(f2b_file_t))) == NULL) if ((file = calloc(1, sizeof(f2b_file_t))) == NULL)
continue; continue;
if (file_open(file, globbuf.gl_pathv[i]) == false) { if (file_open(file, globbuf.gl_pathv[i]) == false) {
if (cfg->errcb) { log_msg(cfg, error, "can't open file: %s -- %s", globbuf.gl_pathv[i], strerror(errno));
snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s -- %s",
globbuf.gl_pathv[i], strerror(errno));
cfg->errcb(cfg->error);
}
free(file); free(file);
continue; continue;
} }
@ -217,13 +197,10 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
cfg->current = cfg->files; cfg->current = cfg->files;
for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) { for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) {
if (file_rotated(file)) if (file_rotated(cfg, file))
file_close(file); file_close(file);
if (!file->opened && !file_open(file, NULL)) { if (!file->opened && !file_open(file, NULL)) {
if (cfg->errcb) { log_msg(cfg, error, "can't open file: %s", file->path);
snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s", file->path);
cfg->errcb(cfg->error);
}
continue; continue;
} }
if (file_getline(file, buf, bufsize)) 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "source.h"
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -13,6 +11,8 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include "source.h"
#define MODNAME "portknock"
#define HOST_MAX 48 #define HOST_MAX 48
#define PORT_MAX 6 #define PORT_MAX 6
@ -25,17 +25,12 @@ typedef struct f2b_port_t {
struct _config { struct _config {
char name[32]; char name[32];
char error[256]; void (*logcb)(enum loglevel lvl, const char *msg);
void (*errcb)(const char *errstr);
f2b_port_t *ports; f2b_port_t *ports;
f2b_port_t *current; f2b_port_t *current;
}; };
static void #include "source.c"
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
static bool static bool
try_parse_listen_opt(f2b_port_t *port, const char *value) { 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) if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL; return NULL;
strlcpy(cfg->name, init, sizeof(cfg->name)); strlcpy(cfg->name, init, sizeof(cfg->name));
cfg->errcb = &errcb_stub; cfg->logcb = &logcb_stub;
return cfg; return cfg;
} }
@ -92,11 +87,11 @@ config(cfg_t *cfg, const char *key, const char *value) {
if (strcmp(key, "listen") == 0) { if (strcmp(key, "listen") == 0) {
f2b_port_t *port = NULL; f2b_port_t *port = NULL;
if ((port = calloc(1, sizeof(f2b_port_t))) == 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; return false;
} }
if (try_parse_listen_opt(port, value) == 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); free(port);
return false; return false;
} }
@ -116,21 +111,6 @@ ready(cfg_t *cfg) {
return false; 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 bool
start(cfg_t *cfg) { start(cfg_t *cfg) {
struct addrinfo hints; struct addrinfo hints;
@ -148,8 +128,7 @@ start(cfg_t *cfg) {
port->sock = -1; port->sock = -1;
int ret = getaddrinfo(port->host, port->port, &hints, &result); int ret = getaddrinfo(port->host, port->port, &hints, &result);
if (ret != 0) { if (ret != 0) {
snprintf(cfg->error, sizeof(cfg->error), "getaddrinfo: %s", gai_strerror(ret)); log_msg(cfg, error, "getaddrinfo: %s", gai_strerror(ret));
cfg->errcb(cfg->error);
continue; continue;
} }
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) { for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
@ -169,10 +148,8 @@ start(cfg_t *cfg) {
} }
} }
freeaddrinfo(result); freeaddrinfo(result);
if (port->sock < 0) { if (port->sock < 0)
snprintf(cfg->error, sizeof(cfg->error), "can't bind/listen on %s:%s", port->host, port->port); log_msg(cfg, error, "can't bind/listen on %s:%s", port->host, port->port);
cfg->errcb(cfg->error);
}
} }
return true; return true;
@ -208,8 +185,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
if (sock < 0 && errno == EAGAIN) if (sock < 0 && errno == EAGAIN)
continue; continue;
if (sock < 0) { if (sock < 0) {
snprintf(cfg->error, sizeof(cfg->error), "accept error: %s", strerror(errno)); log_msg(cfg, error, "accept() error: %s", strerror(errno));
cfg->errcb(cfg->error);
continue; continue;
} }
close(sock); 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); inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &addr)->sin6_addr), buf, bufsize);
return true; 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; return false;

51
src/sources/redis.c

@ -4,20 +4,20 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "source.h"
#include <stdint.h> #include <stdint.h>
#include <hiredis/hiredis.h> #include <hiredis/hiredis.h>
#include "../strlcpy.h" #include "../strlcpy.h"
#include "source.h"
#define MODNAME "redis"
#define ID_MAX 32 #define ID_MAX 32
struct _config { struct _config {
char name[ID_MAX + 1]; char name[ID_MAX + 1];
char hash[ID_MAX * 2]; char hash[ID_MAX * 2];
char error[256]; void (*logcb)(enum loglevel lvl, const char *msg);
void (*errcb)(const char *errstr);
time_t timeout; time_t timeout;
uint8_t database; uint8_t database;
char password[32]; char password[32];
@ -26,11 +26,7 @@ struct _config {
redisContext *conn; redisContext *conn;
}; };
static void #include "source.c"
errcb_stub(const char *str) {
assert(str != NULL);
(void)(str);
}
static bool static bool
redis_connect(cfg_t *cfg) { redis_connect(cfg_t *cfg) {
@ -47,14 +43,14 @@ redis_connect(cfg_t *cfg) {
if (!conn) if (!conn)
break; break;
if (conn->err) { if (conn->err) {
snprintf(cfg->error, sizeof(cfg->error), "Connection error: %s", conn->errstr); log_msg(cfg, error, "connection error: %s", conn->errstr);
break; break;
} }
if (cfg->password[0]) { if (cfg->password[0]) {
if ((reply = redisCommand(conn, "AUTH %s", cfg->password)) == NULL) if ((reply = redisCommand(conn, "AUTH %s", cfg->password)) == NULL)
break; break;
if (reply->type == REDIS_REPLY_ERROR) { 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; break;
} }
freeReplyObject(reply); freeReplyObject(reply);
@ -63,7 +59,7 @@ redis_connect(cfg_t *cfg) {
if ((reply = redisCommand(conn, "SELECT %d", cfg->database)) == NULL) if ((reply = redisCommand(conn, "SELECT %d", cfg->database)) == NULL)
break; break;
if (reply->type == REDIS_REPLY_ERROR) { 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; break;
} }
freeReplyObject(reply); freeReplyObject(reply);
@ -71,13 +67,13 @@ redis_connect(cfg_t *cfg) {
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 10000; /* 0.01s */ timeout.tv_usec = 10000; /* 0.01s */
if (redisSetTimeout(conn, timeout) != REDIS_OK) { 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; break;
} }
if ((reply = redisCommand(conn, "SUBSCRIBE %s", cfg->hash)) == NULL) if ((reply = redisCommand(conn, "SUBSCRIBE %s", cfg->hash)) == NULL)
break; break;
if (reply->type == REDIS_REPLY_ERROR) { 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; break;
} }
freeReplyObject(reply); freeReplyObject(reply);
@ -118,7 +114,7 @@ create(const char *init) {
strlcpy(cfg->name, init, sizeof(cfg->name)); strlcpy(cfg->name, init, sizeof(cfg->name));
strlcpy(cfg->hash, "f2b-banned-", sizeof(cfg->hash)); strlcpy(cfg->hash, "f2b-banned-", sizeof(cfg->hash));
strlcat(cfg->hash, init, sizeof(cfg->hash)); strlcat(cfg->hash, init, sizeof(cfg->hash));
cfg->errcb = &errcb_stub; cfg->logcb = &logcb_stub;
return cfg; return cfg;
} }
@ -163,21 +159,6 @@ ready(cfg_t *cfg) {
return true; 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 bool
start(cfg_t *cfg) { start(cfg_t *cfg) {
assert(cfg != NULL); assert(cfg != NULL);
@ -209,7 +190,7 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
return false; /* reconnect failure */ return false; /* reconnect failure */
if (cfg->conn->err) { 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; return false;
} }
@ -221,18 +202,16 @@ next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) {
strlcpy(buf, reply->element[2]->str, bufsize); strlcpy(buf, reply->element[2]->str, bufsize);
gotit = true; gotit = true;
} else { } else {
cfg->errcb(cfg->error); log_msg(cfg, error, "wrong redis message type: %s", reply->element[0]->str);
} }
} else { } else {
strlcpy(cfg->error, "reply is not a array type", sizeof(cfg->error)); log_msg(cfg, error, "reply is not a array type");
cfg->errcb(cfg->error);
} }
freeReplyObject(reply); freeReplyObject(reply);
} else if (cfg->conn->err == REDIS_ERR_IO && errno == EAGAIN) { } else if (cfg->conn->err == REDIS_ERR_IO && errno == EAGAIN) {
cfg->conn->err = 0; /* reset error to prevent reconnecting */ cfg->conn->err = 0; /* reset error to prevent reconnecting */
} else { } else {
snprintf(cfg->error, sizeof(cfg->error), "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr); log_msg(cfg, error, "can't get reply from server %s: %s", cfg->host, cfg->conn->errstr);
cfg->errcb(cfg->error);
} }
return gotit; 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 <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "../strlcpy.h" #include "../strlcpy.h"
enum loglevel {
debug = 0,
info = 1,
notice = 2,
warn = 3,
error = 4,
fatal = 5,
}; /* see log.h */
/** /**
* @file * @file
* This header describes module API of type 'source' * This header describes module API of type 'source'
@ -24,17 +34,15 @@
* f2b, source; * f2b, source;
* f2b => source [label="create(init)"]; * f2b => source [label="create(init)"];
* f2b << source [label="module handler, cfg_t *cfg"]; * f2b << source [label="module handler, cfg_t *cfg"];
* f2b => source [label="logcb(cfg, cb)"];
* |||; * |||;
* f2b => source [label="config(cfg, param, value)"]; * f2b => source [label="config(cfg, param, value)"];
* f2b << source [label="true"]; * f2b << source [label="true"];
* f2b => source [label="config(cfg, param, value)"]; * f2b => source [label="config(cfg, param, value)"];
* f2b << source [label="true"]; * f2b << source [label="true"];
* f2b => source [label="config(cfg, param, value)"]; * f2b => source [label="config(cfg, param, value)"];
* f2b <<= source [label="logcb(level, char *msg)"];
* f2b << source [label="false"]; * 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="ready(cfg)"];
* f2b << source [label="true"]; * f2b << source [label="true"];
@ -48,7 +56,7 @@
* f2b => source [label="next(cfg, buf, sizeof(buf), true)"]; * f2b => source [label="next(cfg, buf, sizeof(buf), true)"];
* f2b << source [label="true"]; * f2b << source [label="true"];
* f2b => source [label="next(cfg, buf, sizeof(buf), false)"]; * 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="true"];
* f2b => source [label="next(cfg, buf, sizeof(buf), false)"]; * f2b => source [label="next(cfg, buf, sizeof(buf), false)"];
* f2b << source [label="false"]; * f2b << source [label="false"];
@ -81,7 +89,7 @@ extern cfg_t *create(const char *init);
* @param cfg Module handler * @param cfg Module handler
* @param key Parameter name * @param key Parameter name
* @param value Parameter value * @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); 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); extern bool ready(cfg_t *cfg);
/** /**
* @brief Returns last error description * @brief Sets the log callback
* @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
* @param cfg Module handler * @param cfg Module handler
* @param cb Error callback * @param cb Logging callback
* @note Optional, if this function is not called, processing errors will be suppressed * @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 * @brief Allocate resources and start processing
* @param cfg Module handler * @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); extern bool start(cfg_t *cfg);
/** /**

Loading…
Cancel
Save