mirror of https://github.com/jrbrtsn/ban2fail
Lots of new reporting features
This commit is contained in:
parent
bd5a01f5a2
commit
5549c4d188
|
@ -32,6 +32,8 @@ src := \
|
|||
pdns.c \
|
||||
ptrvec.c \
|
||||
str.c \
|
||||
target.c \
|
||||
timestamp.c \
|
||||
util.c \
|
||||
|
||||
libs := z crypto GeoIP pthread db
|
||||
|
|
128
ban2fail.c
128
ban2fail.c
|
@ -21,6 +21,7 @@
|
|||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "addrRpt.h"
|
||||
|
@ -38,13 +39,6 @@
|
|||
#include "str.h"
|
||||
#include "util.h"
|
||||
|
||||
enum {
|
||||
BLOCKED_FLG =1<<0,
|
||||
WOULD_BLOCK_FLG =1<<1,
|
||||
UNJUST_BLOCK_FLG =1<<2,
|
||||
WHITELIST_FLG =1<<3
|
||||
};
|
||||
|
||||
/*==================================================================*/
|
||||
/*=================== Support structs ==============================*/
|
||||
/*==================================================================*/
|
||||
|
@ -67,6 +61,7 @@ static int addrRpt_serial_qsort(const void *p1, const void *p2);
|
|||
static int cntryStat_count_qsort(const void *p1, const void *p2);
|
||||
static int configure(CFGMAP *h_cfgmap, const char *pfix);
|
||||
static int logentry_count_qsort(const void *p1, const void *p2);
|
||||
static int logentry_latest_qsort(const void *p1, const void *p2);
|
||||
static int map_byCountries(OFFENTRY *e, MAP *h_map);
|
||||
static int stub_init(CFGMAP *map, char *symStr);
|
||||
|
||||
|
@ -83,13 +78,21 @@ static const struct bitTuple GlobalFlagBitTuples[]= {
|
|||
};
|
||||
|
||||
struct Global G= {
|
||||
.cacheDir= CACHEDIR,
|
||||
.lockDir= LOCKDIR,
|
||||
.cache= {
|
||||
.dir= CACHEDIR,
|
||||
.dir_mode=0770,
|
||||
.file_mode=0660
|
||||
},
|
||||
.lock= {
|
||||
.dir= LOCKDIR,
|
||||
.dir_mode= 0770,
|
||||
.file_mode=0660
|
||||
},
|
||||
|
||||
.version= {
|
||||
.major= 0,
|
||||
.minor= 13,
|
||||
.patch= 3
|
||||
.patch= 4
|
||||
},
|
||||
|
||||
.bitTuples.flags= GlobalFlagBitTuples
|
||||
|
@ -101,14 +104,6 @@ const static struct initInfo S_initInfo_arr[] = {
|
|||
{/* Terminating member */}
|
||||
};
|
||||
|
||||
static const struct bitTuple BlockBitTuples[]= {
|
||||
{.name= "BLK", .bit= BLOCKED_FLG},
|
||||
{.name= "+blk+", .bit= WOULD_BLOCK_FLG},
|
||||
{.name= "-blk-", .bit= UNJUST_BLOCK_FLG},
|
||||
{.name= "WL", .bit= WHITELIST_FLG},
|
||||
{/* Terminating member */}
|
||||
};
|
||||
|
||||
|
||||
/*================ Local only static struct ======================*/
|
||||
static struct {
|
||||
|
@ -169,6 +164,11 @@ main(int argc, char **argv)
|
|||
|
||||
/* Prepare static data */
|
||||
// global
|
||||
struct group *gr= ez_getgrnam(GROUP_NAME);
|
||||
G.gid= gr->gr_gid;
|
||||
|
||||
/* Default sending listing to stdout */
|
||||
G.rpt.fh= stdout;
|
||||
MAP_constructor(&G.logType_map, 10, 10);
|
||||
MAP_constructor(&G.rpt.AddrRPT_map, 10, 10);
|
||||
|
||||
|
@ -232,8 +232,8 @@ main(int argc, char **argv)
|
|||
|
||||
case 't':
|
||||
G.flags |= GLB_DONT_IPTABLE_FLG;
|
||||
G.cacheDir= CACHEDIR "-test";
|
||||
G.lockDir= LOCKDIR "-test";
|
||||
G.cache.dir= CACHEDIR "-test";
|
||||
G.lock.dir= LOCKDIR "-test";
|
||||
confFile= optarg;
|
||||
break;
|
||||
|
||||
|
@ -300,11 +300,13 @@ main(int argc, char **argv)
|
|||
|
||||
} /* Done with command line arguments */
|
||||
|
||||
/* Make sure we will be able to run iptables */
|
||||
if(getuid()) {
|
||||
eprintf("ERROR: You must be root to run iptables!");
|
||||
goto abort;
|
||||
}
|
||||
/* So we can run iptables */
|
||||
ez_setuid(0);
|
||||
ez_setgid(G.gid);
|
||||
|
||||
/* Get a time when the scan began */
|
||||
G.begin.time_t= time(NULL);
|
||||
G.begin.tm= *localtime(&G.begin.time_t);
|
||||
|
||||
/* Read the configuration file */
|
||||
{ /*=========================================================*/
|
||||
|
@ -313,6 +315,9 @@ main(int argc, char **argv)
|
|||
goto abort;
|
||||
}
|
||||
|
||||
/* For debugging this can be useful */
|
||||
// CFGMAP_print(&S.cfgmap, G.rpt.fh);
|
||||
|
||||
/* Just leave the S.cfgmap in place, so all the value strings
|
||||
* don't need to be copied.
|
||||
*/
|
||||
|
@ -321,21 +326,21 @@ main(int argc, char **argv)
|
|||
/* Obtain a file lock to protect cache files */
|
||||
/*===========================================================*/
|
||||
{
|
||||
if(-1 == ez_access(G.lockDir, F_OK))
|
||||
ez_mkdir(G.lockDir, 0750);
|
||||
if(-1 == ez_access(G.lock.dir, F_OK)) {
|
||||
ez_mkdir(G.lock.dir, G.lock.dir_mode);
|
||||
ez_chown(G.lock.dir, getuid(), G.gid);
|
||||
}
|
||||
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/cache", G.lockDir);
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/cache", G.lock.dir);
|
||||
/* Make sure the file exists by open()'ing */
|
||||
S.cacheLock_fd= ez_open(S.fnameBuf, O_CREAT|O_WRONLY|O_CLOEXEC, 0640);
|
||||
assert(-1 != S.cacheLock_fd);
|
||||
S.cacheLock_fd= ez_open(S.fnameBuf, O_CREAT|O_RDONLY|O_CLOEXEC, G.lock.file_mode);
|
||||
ez_fchown(S.cacheLock_fd, getuid(), G.gid);
|
||||
|
||||
/* Let's get a exclusive lock */
|
||||
// TODO: set SIGALRM to knock us out of blocked wait?
|
||||
int rc= ez_flock(S.cacheLock_fd, LOCK_EX);
|
||||
}
|
||||
|
||||
/* Default sending listing to stdout */
|
||||
G.rpt.fh= stdout;
|
||||
#ifndef DEBUG
|
||||
/* if stdout is a tty, and listing is likely
|
||||
* to be long, then use $PAGER.
|
||||
|
@ -349,16 +354,19 @@ main(int argc, char **argv)
|
|||
|
||||
/* Open our cache, instance file-specific LOGTYPE objects */
|
||||
{ /*=============================================================*/
|
||||
if(G.flags & GLB_FLUSH_CACHE_FLG && !access(G.cacheDir, F_OK)) {
|
||||
ez_rmdir_recursive(G.cacheDir);
|
||||
if(G.flags & GLB_FLUSH_CACHE_FLG &&
|
||||
!ez_access(G.cache.dir, F_OK))
|
||||
{
|
||||
ez_rmdir_recursive(G.cache.dir);
|
||||
}
|
||||
|
||||
/* Make the directory if needed */
|
||||
if(access(G.cacheDir, F_OK)) {
|
||||
if(ez_access(G.cache.dir, F_OK)) {
|
||||
/* errno will be set if access() fails */
|
||||
errno= 0;
|
||||
|
||||
ez_mkdir(G.cacheDir, 0750);
|
||||
ez_mkdir(G.cache.dir, G.cache.dir_mode);
|
||||
ez_chown(G.cache.dir, getuid(), G.gid);
|
||||
}
|
||||
|
||||
if(G.flags & GLB_LONG_LISTING_MASK) {
|
||||
|
@ -398,7 +406,7 @@ main(int argc, char **argv)
|
|||
|
||||
/* Check cache for logType directories not in our current map, and remove them */
|
||||
{ /*---------------------------------------------------------------------*/
|
||||
DIR *dir= ez_opendir(G.cacheDir);
|
||||
DIR *dir= ez_opendir(G.cache.dir);
|
||||
struct dirent *entry;
|
||||
|
||||
while((entry= ez_readdir(dir))) {
|
||||
|
@ -412,7 +420,7 @@ main(int argc, char **argv)
|
|||
continue;
|
||||
|
||||
/* Make the path with filename */
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/%s", G.cacheDir, entry->d_name);
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/%s", G.cache.dir, entry->d_name);
|
||||
|
||||
/* Remove unused directory & contents. */
|
||||
ez_rmdir_recursive(S.fnameBuf);
|
||||
|
@ -475,7 +483,7 @@ main(int argc, char **argv)
|
|||
assert(S.lePtrArr);
|
||||
|
||||
MAP_fetchAllItems(&S.addr2logEntry_map, (void**)S.lePtrArr);
|
||||
qsort(S.lePtrArr, nItems, sizeof(OFFENTRY*), logentry_count_qsort);
|
||||
qsort(S.lePtrArr, nItems, sizeof(OFFENTRY*), logentry_latest_qsort);
|
||||
|
||||
/* Special processing for DNS lookups */
|
||||
if(G.flags & GLB_DNS_LOOKUP_FLG) {
|
||||
|
@ -525,27 +533,7 @@ main(int argc, char **argv)
|
|||
if(G.flags & GLB_LIST_ADDR_FLG &&
|
||||
!(G.flags & GLB_DNS_FILTER_BAD_FLG && e->dns.flags & PDNS_BAD_MASK))
|
||||
{
|
||||
|
||||
const static struct bitTuple dns_flagsArr[]= {
|
||||
{.name= "~", .bit= PDNS_FWD_FAIL_FLG},
|
||||
{.name= "!!", .bit= PDNS_FWD_NONE_FLG},
|
||||
{.name= "NXDOMAIN", .bit= PDNS_NXDOMAIN_FLG},
|
||||
{.name= "SERVFAIL", .bit= PDNS_SERVFAIL_FLG},
|
||||
{}
|
||||
};
|
||||
|
||||
const static char *dns_fmt= "%-15s\t%5u/%-4d offenses %s [%s] %s %s\n",
|
||||
*fmt= "%-15s\t%5u/%-4d offenses %s [%s]\n";
|
||||
|
||||
ez_fprintf(G.rpt.fh, e->dns.flags ? dns_fmt : fmt
|
||||
, e->addr
|
||||
, e->count
|
||||
, nAllowed
|
||||
, e->cntry[0] ? e->cntry : "--"
|
||||
, bits2str(flags, BlockBitTuples)
|
||||
, e->dns.name ? e->dns.name : ""
|
||||
, bits2str(e->dns.flags, dns_flagsArr)
|
||||
);
|
||||
OFFENTRY_list(e, G.rpt.fh, flags, nAllowed);
|
||||
}
|
||||
|
||||
} /*--- End of OFFENTRY processing ---*/
|
||||
|
@ -599,10 +587,10 @@ main(int argc, char **argv)
|
|||
if(!(G.flags & GLB_DONT_IPTABLE_FLG)) {
|
||||
|
||||
if(n2Block || n2Unblock) {
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/iptables", G.lockDir);
|
||||
snprintf(S.fnameBuf, sizeof(S.fnameBuf), "%s/iptables", G.lock.dir);
|
||||
/* Make sure the file exists by open()'ing */
|
||||
S.iptablesLock_fd= ez_open(S.fnameBuf, O_CREAT|O_WRONLY|O_CLOEXEC, 0640);
|
||||
assert(-1 != S.iptablesLock_fd);
|
||||
S.iptablesLock_fd= ez_open(S.fnameBuf, O_CREAT|O_WRONLY|O_CLOEXEC, G.lock.file_mode);
|
||||
ez_fchown(S.iptablesLock_fd, getuid(), G.gid);
|
||||
/* Get an exclusive lock on the lockfile */
|
||||
ez_flock(S.iptablesLock_fd, LOCK_EX);
|
||||
}
|
||||
|
@ -684,6 +672,20 @@ abort:
|
|||
/*==================================================================*/
|
||||
/*============== Supporting functions ==============================*/
|
||||
/*==================================================================*/
|
||||
static int
|
||||
logentry_latest_qsort(const void *p1, const void *p2)
|
||||
/***************************************************************
|
||||
* qsort functor puts large counts on top.
|
||||
*/
|
||||
{
|
||||
const OFFENTRY *le1= *(const OFFENTRY *const*)p1,
|
||||
*le2= *(const OFFENTRY *const*)p2;
|
||||
|
||||
if(le1->latest > le2->latest) return -1;
|
||||
if(le1->latest < le2->latest) return 1;
|
||||
return logentry_count_qsort(p1, p2);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
logentry_count_qsort(const void *p1, const void *p2)
|
||||
|
|
32
ban2fail.h
32
ban2fail.h
|
@ -26,6 +26,8 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <regex.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "cfgmap.h"
|
||||
|
||||
|
@ -59,6 +61,7 @@
|
|||
#define IP6TABLES "/usr/sbin/ip6tables"
|
||||
#define GEOIP_DB "/usr/share/GeoIP/GeoIP.dat"
|
||||
#define GEOIP6_DB "/usr/share/GeoIP/GeoIPv6.dat"
|
||||
#define GROUP_NAME "adm"
|
||||
|
||||
enum GlobalFlg_enum {
|
||||
GLB_VERBOSE_FLG =1<<0,
|
||||
|
@ -74,6 +77,13 @@ enum GlobalFlg_enum {
|
|||
GLB_LONG_LISTING_MASK = GLB_LIST_CNTRY_FLG|GLB_LIST_ADDR_FLG
|
||||
};
|
||||
|
||||
enum BlockedFlg_enum {
|
||||
BLOCKED_FLG =1<<0,
|
||||
WOULD_BLOCK_FLG =1<<1,
|
||||
UNJUST_BLOCK_FLG =1<<2,
|
||||
WHITELIST_FLG =1<<3
|
||||
};
|
||||
|
||||
/* Singleton static object with global visibility */
|
||||
extern struct Global {
|
||||
|
||||
|
@ -81,8 +91,21 @@ extern struct Global {
|
|||
|
||||
MAP logType_map;
|
||||
|
||||
char *cacheDir,
|
||||
*lockDir;
|
||||
struct {
|
||||
char *dir;
|
||||
mode_t dir_mode,
|
||||
file_mode;
|
||||
} cache;
|
||||
|
||||
struct {
|
||||
char *dir;
|
||||
mode_t dir_mode,
|
||||
file_mode;
|
||||
} lock;
|
||||
|
||||
/* This should be set to adm */
|
||||
gid_t gid;
|
||||
|
||||
|
||||
struct {
|
||||
FILE *fh;
|
||||
|
@ -99,6 +122,11 @@ extern struct Global {
|
|||
const struct bitTuple *flags;
|
||||
} bitTuples;
|
||||
|
||||
struct {
|
||||
time_t time_t;
|
||||
struct tm tm;
|
||||
} begin;
|
||||
|
||||
} G;
|
||||
|
||||
|
||||
|
|
160
ez_libc.c
160
ez_libc.c
|
@ -92,8 +92,9 @@ FILE* _ez_popen (
|
|||
const char *type
|
||||
)
|
||||
{
|
||||
errno= 0;
|
||||
FILE *rtn= popen (command, type);
|
||||
if (!rtn) {
|
||||
if (!rtn || errno) {
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "popen(\"%s\", \"%s\") failed", command, type);
|
||||
abort();
|
||||
}
|
||||
|
@ -524,6 +525,7 @@ int _ez_open(
|
|||
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_access(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
|
@ -547,3 +549,159 @@ int _ez_access(
|
|||
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
char *_ez_strptime(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *s,
|
||||
const char *format,
|
||||
struct tm *tm
|
||||
)
|
||||
{
|
||||
char *rtn= strptime (s, format, tm);
|
||||
if(rtn) return rtn;
|
||||
|
||||
_eprintf(fileName, lineNo, funcName, "strptime(\"%s\",\"%s\") failed", s, format);
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_seteuid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
uid_t euid
|
||||
)
|
||||
{
|
||||
int rtn= seteuid (euid);
|
||||
if(0 == rtn) return 0;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "seteuid(%d) failed", (int)euid);
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_setegid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
gid_t egid
|
||||
)
|
||||
{
|
||||
int rtn= setegid (egid);
|
||||
if(0 == rtn) return 0;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "setegid(%d) failed", (int)egid);
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
struct group* _ez_getgrnam(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *name
|
||||
)
|
||||
{
|
||||
errno= 0;
|
||||
struct group *rtn= getgrnam (name);
|
||||
|
||||
if(rtn) return rtn;
|
||||
|
||||
switch(errno) {
|
||||
case EINTR:
|
||||
case EIO:
|
||||
case EMFILE:
|
||||
case ENFILE:
|
||||
case ENOMEM:
|
||||
case ERANGE:
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "getgrnam(\"%s\") failed", name);
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_chown(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *pathname,
|
||||
uid_t owner,
|
||||
gid_t group
|
||||
)
|
||||
{
|
||||
int rtn= chown (pathname, owner, group);
|
||||
if(0 == rtn) return rtn;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "chown(\"%s\", %d, %d) failed", pathname, (int)owner, (int)group);
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_fchown(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
int fd,
|
||||
uid_t owner,
|
||||
gid_t group
|
||||
)
|
||||
{
|
||||
int rtn= fchown (fd, owner, group);
|
||||
if(0 == rtn) return rtn;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fchown() failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_fchmod(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
int fd,
|
||||
mode_t mode
|
||||
)
|
||||
{
|
||||
int rtn= fchmod (fd, mode);
|
||||
if(0 == rtn) return rtn;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fchmod() failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_setuid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
uid_t uid
|
||||
)
|
||||
{
|
||||
int rtn= setuid (uid);
|
||||
if(0 == rtn) return 0;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "setuid(%d) failed", (int)uid);
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_setgid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
gid_t gid
|
||||
)
|
||||
{
|
||||
int rtn= setgid (gid);
|
||||
if(0 == rtn) return 0;
|
||||
|
||||
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "setgid(%d) failed", (int)gid);
|
||||
abort();
|
||||
}
|
||||
|
|
90
ez_libc.h
90
ez_libc.h
|
@ -30,17 +30,30 @@ glibc calls with boilerplate error handling.
|
|||
|
||||
#define _GNU_SOURCE
|
||||
#include <dirent.h>
|
||||
#include <grp.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ez_strptime(s, format, tm) \
|
||||
_ez_strptime(__FILE__, __LINE__, __FUNCTION__, s, format, tm)
|
||||
char *_ez_strptime(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *s,
|
||||
const char *format,
|
||||
struct tm *tm
|
||||
);
|
||||
|
||||
#define ez_access(pathname, mode) \
|
||||
_ez_access(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
||||
int _ez_access(
|
||||
|
@ -341,6 +354,83 @@ int _ez_flock (
|
|||
int operation
|
||||
);
|
||||
|
||||
#define ez_setuid(uid) \
|
||||
_ez_setuid(__FILE__, __LINE__, __FUNCTION__, uid)
|
||||
int _ez_setuid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
uid_t uid
|
||||
);
|
||||
|
||||
#define ez_setgid(gid) \
|
||||
_ez_setgid(__FILE__, __LINE__, __FUNCTION__, gid)
|
||||
int _ez_setgid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
gid_t gid
|
||||
);
|
||||
|
||||
|
||||
#define ez_seteuid(euid) \
|
||||
_ez_seteuid(__FILE__, __LINE__, __FUNCTION__, euid)
|
||||
int _ez_seteuid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
uid_t euid
|
||||
);
|
||||
|
||||
#define ez_setegid(egid) \
|
||||
_ez_setegid(__FILE__, __LINE__, __FUNCTION__, egid)
|
||||
int _ez_setegid(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
gid_t egid
|
||||
);
|
||||
|
||||
#define ez_getgrnam(name) \
|
||||
_ez_getgrnam(__FILE__, __LINE__, __FUNCTION__, name)
|
||||
struct group* _ez_getgrnam(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *name
|
||||
);
|
||||
|
||||
#define ez_chown(pathname, owner, group) \
|
||||
_ez_chown(__FILE__, __LINE__, __FUNCTION__, pathname, owner, group)
|
||||
int _ez_chown(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
const char *pathname,
|
||||
uid_t owner,
|
||||
gid_t group
|
||||
);
|
||||
|
||||
#define ez_fchown(fd, owner, group) \
|
||||
_ez_fchown(__FILE__, __LINE__, __FUNCTION__, fd, owner, group)
|
||||
int _ez_fchown(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
int fd,
|
||||
uid_t owner,
|
||||
gid_t group
|
||||
);
|
||||
|
||||
#define ez_fchmod(fd, mode) \
|
||||
_ez_fchmod(__FILE__, __LINE__, __FUNCTION__, fd, mode)
|
||||
int _ez_fchmod(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
int fd,
|
||||
mode_t mode
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
20
ez_libdb.c
20
ez_libdb.c
|
@ -145,7 +145,6 @@ int _ez_db_close(
|
|||
u_int32_t flags
|
||||
)
|
||||
{
|
||||
//eprintf("Closing database (%p)", db);
|
||||
int rtn= db->close(db, flags);
|
||||
|
||||
if(!rtn) return 0;
|
||||
|
@ -155,3 +154,22 @@ int _ez_db_close(
|
|||
_sys_eprintf((const char*(*)(int))db_strerror, fileName, lineNo, funcName, "DB->close() failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
int _ez_db_fd(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
DB *db,
|
||||
int *fdp
|
||||
)
|
||||
{
|
||||
int rtn= db->fd(db, fdp);
|
||||
|
||||
if(!rtn) return 0;
|
||||
|
||||
/* _sys_eprintf() will pass errno to db_sterror */
|
||||
errno= rtn;
|
||||
_sys_eprintf((const char*(*)(int))db_strerror, fileName, lineNo, funcName, "DB->fd() failed");
|
||||
abort();
|
||||
}
|
||||
|
|
10
ez_libdb.h
10
ez_libdb.h
|
@ -101,6 +101,16 @@ int _ez_db_close(
|
|||
u_int32_t flags
|
||||
);
|
||||
|
||||
#define ez_db_fd(db, fdp) \
|
||||
_ez_db_fd(__FILE__, __LINE__, __FUNCTION__, db, fdp)
|
||||
int _ez_db_fd(
|
||||
const char *fileName,
|
||||
int lineNo,
|
||||
const char *funcName,
|
||||
DB *db,
|
||||
int *fdp
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
10
iptables.c
10
iptables.c
|
@ -76,7 +76,9 @@ initialize (void)
|
|||
}
|
||||
|
||||
fh= ez_popen(ipv->cmd, "r");
|
||||
|
||||
#ifdef qqDEBUG
|
||||
unsigned count= 0;
|
||||
#endif
|
||||
while(ez_fgets(lbuf, sizeof(lbuf)-1, fh)) {
|
||||
|
||||
/* Filter all that looks uninteresting */
|
||||
|
@ -93,9 +95,15 @@ initialize (void)
|
|||
eprintf("WARNING: duplicate iptable entry for %s", addr);
|
||||
else
|
||||
MAP_addStrKey(&S.addr_map, addr, strdup(addr));
|
||||
#ifdef qqDEBUG
|
||||
++count;
|
||||
#endif
|
||||
}
|
||||
ez_pclose(fh);
|
||||
regfree(&re);
|
||||
#ifdef qqDEBUG
|
||||
eprintf("%s got %u entries", ipv->cmd, count);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
32
logFile.c
32
logFile.c
|
@ -81,7 +81,7 @@ LOGFILE_cache_constructor(
|
|||
|
||||
static char dbFname[PATH_MAX];
|
||||
snprintf(dbFname, sizeof(dbFname), "%s.db", cacheFname);
|
||||
if(0 == access(dbFname, F_OK)) {
|
||||
if(0 == ez_access(dbFname, F_OK)) {
|
||||
ez_db_create(&db, NULL, 0);
|
||||
ez_db_open(db, NULL, dbFname, NULL, DB_BTREE, DB_RDONLY, 0664);
|
||||
}
|
||||
|
@ -157,18 +157,10 @@ LOGFILE_log_constructor(
|
|||
lbuf[--line_len]= '\0';
|
||||
|
||||
/* Search for a match in the targets */
|
||||
for(struct target *tg= h_protoType->targetArr; tg->pattern; ++tg) {
|
||||
|
||||
/* If there is no match, continue looking */
|
||||
regmatch_t matchArr[2];
|
||||
if(0 != regexec(&tg->re, lbuf, 2, matchArr, 0) || -1 == matchArr[1].rm_so)
|
||||
continue;
|
||||
for(Target *tg= h_protoType->targetArr; Target_is_init(tg); ++tg) {
|
||||
|
||||
static char addr[128];
|
||||
unsigned len;
|
||||
len= matchArr[1].rm_eo - matchArr[1].rm_so;
|
||||
strncpy(addr, lbuf+matchArr[1].rm_so, sizeof(addr)-1);
|
||||
addr[MIN(len, sizeof(addr)-1)]= '\0';
|
||||
if(Target_scan(tg, addr, sizeof(addr), lbuf)) continue;
|
||||
|
||||
OFFENTRY *e= MAP_findStrItem(&self->addr.offEntry_map, addr);
|
||||
if(!e) {
|
||||
|
@ -179,7 +171,15 @@ LOGFILE_log_constructor(
|
|||
MAP_addStrKey(&self->addr.offEntry_map, e->addr, e);
|
||||
}
|
||||
|
||||
OFFENTRY_register(e);
|
||||
/* See if we can extract the date */
|
||||
time_t when= 0;
|
||||
if(TS_is_prepared(&h_protoType->ts)) {
|
||||
if(TS_scan(&h_protoType->ts, &when, lbuf, &G.begin.tm)) {
|
||||
eprintf("WARNING: TS_scan() failed.");
|
||||
}
|
||||
}
|
||||
|
||||
OFFENTRY_register(e, Target_severity(tg), when);
|
||||
|
||||
{ /* Keep ObsvTpl record of offense line in log file */
|
||||
ObsvTpl *ot= MAP_findStrItem(&self->addr.obsvTpl_map, e->addr);
|
||||
|
@ -190,9 +190,8 @@ LOGFILE_log_constructor(
|
|||
}
|
||||
|
||||
ObsvTpl_addObsv(ot, pos, line_len);
|
||||
|
||||
}
|
||||
}
|
||||
} /* End of Target loop */
|
||||
} /* End of line reading loop */
|
||||
|
||||
/* Take car of possible address reporting */
|
||||
|
@ -244,6 +243,8 @@ LOGFILE_writeCache(LOGFILE *self, const char *fname)
|
|||
DB *dbh= NULL;
|
||||
|
||||
FILE *fh= ez_fopen(fname, "w");
|
||||
ez_fchown(fileno(fh), getuid(), G.gid);
|
||||
ez_fchmod(fileno(fh), G.cache.file_mode);
|
||||
|
||||
/* Writes all OFFENTRY object to fh */
|
||||
rc= MAP_visitAllEntries(&self->addr.offEntry_map, (int(*)(void*,void*))OFFENTRY_cacheWrite, fh);
|
||||
|
@ -258,7 +259,8 @@ LOGFILE_writeCache(LOGFILE *self, const char *fname)
|
|||
|
||||
ez_db_create(&dbh, NULL, 0);
|
||||
assert(dbh);
|
||||
ez_db_open(dbh, NULL, dbFname, NULL, DB_BTREE, DB_CREATE, 0664);
|
||||
ez_db_open(dbh, NULL, dbFname, NULL, DB_BTREE, DB_CREATE, G.cache.file_mode);
|
||||
ez_chown(dbFname, getuid(), G.gid);
|
||||
|
||||
/* This will write all entries in the map do the database */
|
||||
MAP_visitAllEntries(&self->addr.obsvTpl_map, (int(*)(void*,void*))ObsvTpl_db_put, dbh);
|
||||
|
|
60
logType.c
60
logType.c
|
@ -118,9 +118,9 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||
{ /* Compute md5sum of all patterns put together */
|
||||
MD5_CTX md5ctx;
|
||||
MD5_Init(&md5ctx);
|
||||
const struct target *t;
|
||||
for(t= proto->targetArr; t->pattern; ++t) {
|
||||
MD5_Update(&md5ctx, t->pattern, strlen(t->pattern));
|
||||
const Target *t;
|
||||
for(t= proto->targetArr; t->rxArr; ++t) {
|
||||
Target_MD5_update(t, &md5ctx);
|
||||
}
|
||||
static unsigned char sum[16];
|
||||
MD5_Final(sum, &md5ctx);
|
||||
|
@ -131,7 +131,7 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||
/* At this point we can call LOGTYPE_cacheName() */
|
||||
|
||||
/* Keep the name of this logType's cache directory */
|
||||
rc= snprintf(CacheDname, sizeof(CacheDname), "%s/%s", G.cacheDir, LOGTYPE_cacheName(self));
|
||||
rc= snprintf(CacheDname, sizeof(CacheDname), "%s/%s", G.cache.dir, LOGTYPE_cacheName(self));
|
||||
|
||||
{ /*** Compute md5sum for each log file, then scan of read from cache ***/
|
||||
|
||||
|
@ -206,7 +206,7 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||
LOGFILE *f;
|
||||
|
||||
/* Use the cache, if available */
|
||||
if(!access(CacheFname, F_OK))
|
||||
if(!ez_access(CacheFname, F_OK))
|
||||
{
|
||||
|
||||
/* Construct object from cache file */
|
||||
|
@ -215,8 +215,9 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||
|
||||
} else { /* Scan the log file, write to new cache */
|
||||
|
||||
if(access(CacheDname, F_OK)) {
|
||||
ez_mkdir(CacheDname, 0770);
|
||||
if(ez_access(CacheDname, F_OK)) {
|
||||
ez_mkdir(CacheDname, G.cache.dir_mode);
|
||||
ez_chown(CacheDname, getuid(), G.gid);
|
||||
}
|
||||
|
||||
/* Construct object from log file */
|
||||
|
@ -328,26 +329,43 @@ LOGTYPE_init(CFGMAP *h_map, char *pfix)
|
|||
}
|
||||
}
|
||||
|
||||
{ /*--- Get all regex entries ---*/
|
||||
snprintf(symBuf, len, "%s\\REGEX", pfix);
|
||||
{ /*--- Get the TIMESTAMP entry ---*/
|
||||
snprintf(symBuf, len, "%s\\TIMESTAMP", pfix);
|
||||
const char *val= CFGMAP_find_last_value(h_map, symBuf);
|
||||
|
||||
if(val) {
|
||||
|
||||
snprintf(symBuf, len, "%s\\%s", pfix, val);
|
||||
|
||||
if(TS_init(&proto.ts, h_map, symBuf)) {
|
||||
eprintf("ERROR: TS_init() failed.");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ /*--- Get all TARGET entries ---*/
|
||||
|
||||
snprintf(symBuf, len, "%s\\TARGET", pfix);
|
||||
|
||||
unsigned nFound= CFGMAP_find_tuples(h_map, rtn_arr, symBuf);
|
||||
|
||||
/* Get enough object to include a terminating entry */
|
||||
struct target targetArr[nFound+1];
|
||||
Target targetArr[nFound+1];
|
||||
/* Clear all bits in array */
|
||||
memset(targetArr, 0, sizeof(struct target)*(nFound+1));
|
||||
memset(targetArr, 0, sizeof(Target)*(nFound+1));
|
||||
|
||||
proto.targetArr= targetArr;
|
||||
|
||||
for(unsigned i= 0; i < nFound; ++i) {
|
||||
const struct CFGMAP_tuple *tpl= rtn_arr + i;
|
||||
struct target *tg= targetArr + i;
|
||||
tg->pattern= tpl->value;
|
||||
if(regex_compile(&tg->re, tg->pattern, REG_EXTENDED)) {
|
||||
eprintf("ERROR: regex_compile(\"%s\") failed.", tg->pattern);
|
||||
Target *tg= targetArr + i;
|
||||
snprintf(symBuf, len, "%s\\%s", pfix, tpl->value);
|
||||
if(Target_init(tg, h_map, symBuf)) {
|
||||
eprintf("ERROR: Target_init() failed.");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the LOGTYPE object, place in global map */
|
||||
|
@ -362,13 +380,17 @@ LOGTYPE_init(CFGMAP *h_map, char *pfix)
|
|||
/* Place int the global map */
|
||||
MAP_addStrKey(&G.logType_map, LOGTYPE_cacheName(obj), obj);
|
||||
|
||||
/* Free regex pattern data */
|
||||
/* Free regex stuff */
|
||||
for(unsigned i= 0; i < nFound; ++i) {
|
||||
struct target *tg= targetArr + i;
|
||||
regfree(&tg->re);
|
||||
Target *tg= targetArr + i;
|
||||
Target_destructor(tg);
|
||||
}
|
||||
}
|
||||
|
||||
if(TS_is_prepared(&proto.ts)) {
|
||||
TS_destructor(&proto.ts);
|
||||
}
|
||||
|
||||
rtn= 0;
|
||||
abort:
|
||||
return rtn;
|
||||
|
|
13
logType.h
13
logType.h
|
@ -24,14 +24,8 @@
|
|||
#include "ban2fail.h"
|
||||
#include "cfgmap.h"
|
||||
#include "map.h"
|
||||
|
||||
/*==================================================================*/
|
||||
/*===================== target =====================================*/
|
||||
/*==================================================================*/
|
||||
struct target {
|
||||
const char *pattern;
|
||||
regex_t re;
|
||||
};
|
||||
#include "target.h"
|
||||
#include "timestamp.h"
|
||||
|
||||
/*==================================================================*/
|
||||
/*===================== log file prototype =========================*/
|
||||
|
@ -39,7 +33,8 @@ struct target {
|
|||
struct logProtoType {
|
||||
const char *dir,
|
||||
*pfix;
|
||||
struct target *targetArr;
|
||||
TS ts; /* For log entry timestamps */
|
||||
Target *targetArr;
|
||||
};
|
||||
|
||||
/*==================================================================*/
|
||||
|
|
94
offEntry.c
94
offEntry.c
|
@ -74,16 +74,29 @@ OFFENTRY_cache_constructor(OFFENTRY *self, const char *cacheFileEntry)
|
|||
|
||||
common_constructor(self);
|
||||
|
||||
int rc= sscanf(cacheFileEntry, "%u %45s %2s"
|
||||
,&self->count
|
||||
,self->addr
|
||||
,self->cntry);
|
||||
long long ll;
|
||||
|
||||
if(2 > rc) {
|
||||
int rc= sscanf(cacheFileEntry, "%u %u %lld %45s %2s"
|
||||
, &self->count
|
||||
, &self->severity
|
||||
, &ll
|
||||
, self->addr
|
||||
, self->cntry
|
||||
);
|
||||
|
||||
if(4 > rc) {
|
||||
eprintf("ERROR: failed to interpret \"%s\"", cacheFileEntry);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
self->latest= ll;
|
||||
|
||||
#ifdef qqDEBUG
|
||||
if(self->severity) {
|
||||
eprintf("%s : %u", self->addr, self->severity);
|
||||
}
|
||||
#endif
|
||||
|
||||
rtn= self;
|
||||
abort:
|
||||
return rtn;
|
||||
|
@ -102,13 +115,28 @@ OFFENTRY_destructor(OFFENTRY *self)
|
|||
}
|
||||
|
||||
void
|
||||
OFFENTRY_register(OFFENTRY *self)
|
||||
OFFENTRY_register(OFFENTRY *self, unsigned severity, time_t when)
|
||||
/********************************************************
|
||||
* Register the current failure try.
|
||||
*/
|
||||
{
|
||||
/* Keep track of count */
|
||||
++self->count;
|
||||
|
||||
#ifdef qqDEBUG
|
||||
if(severity) {
|
||||
eprintf("Severity= %u", severity);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Keep track of most severe match */
|
||||
if(self->severity < severity)
|
||||
self->severity= severity;
|
||||
|
||||
/* Keep track of the most recent offense time */
|
||||
if(self->latest < when)
|
||||
self->latest= when;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,8 +146,10 @@ OFFENTRY_cacheWrite(OFFENTRY *self, FILE *fh)
|
|||
* Write to the cache file in a form we can read later.
|
||||
*/
|
||||
{
|
||||
ez_fprintf(fh, "%u %s %s\n"
|
||||
ez_fprintf(fh, "%u %u %lld %s %s\n"
|
||||
, self->count
|
||||
, self->severity
|
||||
, (long long)self->latest
|
||||
, self->addr
|
||||
, self->cntry
|
||||
);
|
||||
|
@ -133,11 +163,12 @@ OFFENTRY_print(OFFENTRY *self, FILE *fh)
|
|||
*/
|
||||
{
|
||||
ez_fprintf(fh,
|
||||
"\tLOGENTRY %p { addr= \"%s\", cntry= \"%2s\" count= %u }\n"
|
||||
"\tLOGENTRY %p { addr= \"%s\", cntry= \"%2s\" count= %u, severity= %u }\n"
|
||||
, self
|
||||
, self->addr
|
||||
, self->cntry
|
||||
, self->count
|
||||
, self->severity
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,6 +189,12 @@ OFFENTRY_map_addr(OFFENTRY *self, MAP *h_rtnMap)
|
|||
}
|
||||
|
||||
e->count += self->count;
|
||||
|
||||
if(e->severity < self->severity)
|
||||
e->severity= self->severity;
|
||||
|
||||
if(e->latest < self->latest)
|
||||
e->latest= self->latest;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -171,3 +208,44 @@ OFFENTRY_offenseCount(OFFENTRY *self, unsigned *h_sum)
|
|||
//eprintf("%s numItems= %u", self->addr, PTRVEC_numItems(&self->rptObj_vec));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
OFFENTRY_list(OFFENTRY *self, FILE *fh, int flags, unsigned nAllowed)
|
||||
/********************************************************
|
||||
* Print in listing form
|
||||
*/
|
||||
{
|
||||
static const struct bitTuple BlockBitTuples[]= {
|
||||
{.name= "BLK", .bit= BLOCKED_FLG},
|
||||
{.name= "+blk+", .bit= WOULD_BLOCK_FLG},
|
||||
{.name= "-blk-", .bit= UNJUST_BLOCK_FLG},
|
||||
{.name= "WL", .bit= WHITELIST_FLG},
|
||||
{/* Terminating member */}
|
||||
};
|
||||
|
||||
const static struct bitTuple dns_flagsArr[]= {
|
||||
{.name= "~", .bit= PDNS_FWD_FAIL_FLG},
|
||||
{.name= "!!", .bit= PDNS_FWD_NONE_FLG},
|
||||
{.name= "NXDOMAIN", .bit= PDNS_NXDOMAIN_FLG},
|
||||
{.name= "SERVFAIL", .bit= PDNS_SERVFAIL_FLG},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
const static char *dns_fmt= "%u %-13s %-15s\t%5u/%-4d offenses %s [%s] %s %s\n",
|
||||
*fmt= "%u %-13s %-15s\t%5u/%-4d offenses %s [%s]\n";
|
||||
|
||||
ez_fprintf(fh, self->dns.flags ? dns_fmt : fmt
|
||||
, self->severity
|
||||
, self->latest ? local_strftime(&self->latest, "%b %d %H:%M") : ""
|
||||
, self->addr
|
||||
, self->count
|
||||
, nAllowed
|
||||
, self->cntry[0] ? self->cntry : "--"
|
||||
, bits2str(flags, BlockBitTuples)
|
||||
, self->dns.name ? self->dns.name : ""
|
||||
, bits2str(self->dns.flags, dns_flagsArr)
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
24
offEntry.h
24
offEntry.h
|
@ -29,10 +29,14 @@
|
|||
|
||||
/* One of these for each offense found in a log file */
|
||||
typedef struct _OFFENTRY {
|
||||
unsigned logfile_ndx;
|
||||
|
||||
unsigned count,
|
||||
severity;
|
||||
|
||||
time_t latest;
|
||||
|
||||
char addr[46],
|
||||
cntry[3];
|
||||
unsigned count;
|
||||
|
||||
/* This data populated by PDNS_lookup() */
|
||||
struct {
|
||||
|
@ -78,19 +82,11 @@ OFFENTRY_destructor(OFFENTRY *self);
|
|||
*/
|
||||
|
||||
void
|
||||
OFFENTRY_register(OFFENTRY *self);
|
||||
OFFENTRY_register(OFFENTRY *self, unsigned severity, time_t when);
|
||||
/********************************************************
|
||||
* Register the current failure try.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
int
|
||||
OFFENTRY_is_blocked_country(const OFFENTRY *self);
|
||||
/********************************************************
|
||||
* Return 1 if the country is blocked, or 0.
|
||||
*/
|
||||
#endif
|
||||
|
||||
int
|
||||
OFFENTRY_cacheWrite(OFFENTRY *self, FILE *fh);
|
||||
/********************************************************
|
||||
|
@ -103,6 +99,12 @@ OFFENTRY_print(OFFENTRY *self, FILE *fh);
|
|||
* Print a human readable representation of *self.
|
||||
*/
|
||||
|
||||
int
|
||||
OFFENTRY_list(OFFENTRY *self, FILE *fh, int flags, unsigned nAllowed);
|
||||
/********************************************************
|
||||
* Print in listing form
|
||||
*/
|
||||
|
||||
int
|
||||
OFFENTRY_map_addr(OFFENTRY *self, MAP *h_rtnMap);
|
||||
/********************************************************
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2019 by John D. Robertson *
|
||||
* john@rrci.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <regex.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "target.h"
|
||||
#include "util.h"
|
||||
|
||||
int
|
||||
Target_init(Target *self, CFGMAP *h_map, const char *pfix)
|
||||
/********************************************************
|
||||
* Prepare for use from config map
|
||||
*/
|
||||
{
|
||||
int rtn= -1;
|
||||
memset(self, 0, sizeof(*self));
|
||||
|
||||
self->flags |= TARGET_INIT_FLG;
|
||||
|
||||
unsigned arr_sz= CFGMAP_numTuples(h_map);
|
||||
struct CFGMAP_tuple rtn_arr[arr_sz];
|
||||
|
||||
size_t len= strlen(pfix)+1024;
|
||||
char symBuf[len];
|
||||
|
||||
{ /*--- Check for "SEVERITY" symbol ---*/
|
||||
snprintf(symBuf, len, "%s\\SEVERITY", pfix);
|
||||
|
||||
if(CFGMAP_query_last_uint(h_map, &self->severity, 0, symBuf)) {
|
||||
eprintf("ERROR: cannot interpret \"SEVERITY\" entry for REGEX %s", pfix);
|
||||
goto abort;
|
||||
}
|
||||
#ifdef qqDEBUG
|
||||
eprintf("%s = %u", symBuf, self->severity);
|
||||
#endif
|
||||
}
|
||||
|
||||
{ /*--- Get all REGEX entries ---*/
|
||||
snprintf(symBuf, len, "%s\\REGEX", pfix);
|
||||
self->nRx= CFGMAP_find_tuples(h_map, rtn_arr, symBuf);
|
||||
|
||||
self->rxArr= calloc(self->nRx, sizeof(struct TargetRx));
|
||||
assert(self->rxArr);
|
||||
|
||||
for(unsigned i= 0; i < self->nRx; ++i) {
|
||||
|
||||
const struct CFGMAP_tuple *tpl= rtn_arr + i;
|
||||
struct TargetRx *rx= self->rxArr + i;
|
||||
|
||||
/* Compile regular expression */
|
||||
rx->pattern= tpl->value;
|
||||
if(regex_compile(&rx->re, rx->pattern, REG_EXTENDED)) {
|
||||
eprintf("ERROR: regex_compile(\"%s\") failed.", rx->pattern);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtn= 0;
|
||||
abort:
|
||||
return rtn;
|
||||
}
|
||||
|
||||
void*
|
||||
Target_destructor(Target *self)
|
||||
/********************************************************
|
||||
* Free resources.
|
||||
*/
|
||||
{
|
||||
if(self->nRx && self->rxArr) {
|
||||
for(unsigned i= 0; i < self->nRx; ++i) {
|
||||
struct TargetRx *rx= self->rxArr + i;
|
||||
regfree(&rx->re);
|
||||
}
|
||||
free(self->rxArr);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
int
|
||||
Target_scan(const Target *self, char *rsltBuf, unsigned buf_sz, const char *str)
|
||||
/********************************************************
|
||||
* Scan a string to obtain the address.
|
||||
*/
|
||||
{
|
||||
int rtn= EOF;
|
||||
|
||||
/* Exit on first match */
|
||||
for(unsigned i= 0; i < self->nRx; ++i) {
|
||||
|
||||
const struct TargetRx *rx= self->rxArr+i;
|
||||
|
||||
regmatch_t matchArr[2];
|
||||
if(0 != regexec(&rx->re, str, 2, matchArr, 0) || -1 == matchArr[1].rm_so)
|
||||
continue;
|
||||
|
||||
unsigned len= matchArr[1].rm_eo - matchArr[1].rm_so;
|
||||
|
||||
strncpy(rsltBuf, str+matchArr[1].rm_so, buf_sz-1);
|
||||
rsltBuf[MIN(len, buf_sz-1)]= '\0';
|
||||
rtn= 0;
|
||||
break;
|
||||
}
|
||||
|
||||
abort:
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int
|
||||
Target_MD5_update(const Target *self, MD5_CTX *ctx)
|
||||
/********************************************************
|
||||
* For computing MD5 checksum of cumulative patterns.
|
||||
*/
|
||||
{
|
||||
for(unsigned i= 0; i < self->nRx; ++i) {
|
||||
const struct TargetRx *rx= self->rxArr+i;
|
||||
MD5_Update(ctx, rx->pattern, strlen(rx->pattern));
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2019 by John D. Robertson *
|
||||
* john@rrci.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef TARGET_H
|
||||
#define TARGET_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <openssl/md5.h>
|
||||
#include "cfgmap.h"
|
||||
|
||||
struct TargetRx {
|
||||
const char *pattern;
|
||||
regex_t re;
|
||||
};
|
||||
|
||||
typedef struct _Target {
|
||||
enum {
|
||||
TARGET_INIT_FLG=1<<0
|
||||
} flags;
|
||||
unsigned severity,
|
||||
nRx;
|
||||
struct TargetRx *rxArr;
|
||||
} Target;
|
||||
|
||||
#define Target_severity(s) \
|
||||
((const unsigned)(s)->severity)
|
||||
|
||||
#define Target_is_init(s) \
|
||||
((const int)(s)->flags)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int
|
||||
Target_init(Target *self, CFGMAP *h_map, const char *pfix);
|
||||
/********************************************************
|
||||
* Prepare for use from config map
|
||||
*/
|
||||
|
||||
void*
|
||||
Target_destructor(Target *self);
|
||||
/********************************************************
|
||||
* Free resources.
|
||||
*/
|
||||
|
||||
int
|
||||
Target_scan(const Target *self, char *rsltBuf, unsigned buf_sz, const char *str);
|
||||
/********************************************************
|
||||
* Scan a string to obtain the address.
|
||||
*/
|
||||
|
||||
int
|
||||
Target_MD5_update(const Target *self, MD5_CTX *ctx);
|
||||
/********************************************************
|
||||
* For computing MD5 checksum of cumulative patterns.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2019 by John D. Robertson *
|
||||
* john@rrci.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "ez_libc.h"
|
||||
#include "timestamp.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
enum Flags {
|
||||
GUESS_YR_FLG= 1<<0
|
||||
};
|
||||
|
||||
const static struct bitTuple FlagsBitTupleArr[]= {
|
||||
{.name= "GUESS_YEAR", .bit= GUESS_YR_FLG},
|
||||
{/* Terminating member */}
|
||||
};
|
||||
|
||||
int
|
||||
TS_init(TS *self, CFGMAP *h_map, const char *pfix)
|
||||
/********************************************************
|
||||
* Initialize timestamp from config map.
|
||||
*/
|
||||
{
|
||||
int rtn= -1;
|
||||
memset(self, 0, sizeof(*self));
|
||||
|
||||
size_t len= strlen(pfix)+1024;
|
||||
char symBuf[len];
|
||||
|
||||
{ /*--- Check for "REGEX" symbol ---*/
|
||||
snprintf(symBuf, len, "%s\\REGEX", pfix);
|
||||
/* CFGMAP is left in place, so we don't need to strdup() */
|
||||
self->pattern= CFGMAP_find_last_value(h_map, symBuf);
|
||||
|
||||
if(!self->pattern) {
|
||||
eprintf("ERROR: cannot find \"REGEX\" entry for ENTRY_TIMESTAMP %s", pfix);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if(regex_compile(&self->re, self->pattern, REG_EXTENDED)) {
|
||||
eprintf("ERROR: regex_compile(\"%s\") failed.", self->pattern);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
{ /*--- Check for "STRPTIME" symbol ---*/
|
||||
snprintf(symBuf, len, "%s\\STRPTIME", pfix);
|
||||
/* CFGMAP is left in place, so we don't need to strdup() */
|
||||
self->strptime_fmt= CFGMAP_find_last_value(h_map, symBuf);
|
||||
|
||||
if(!self->strptime_fmt) {
|
||||
eprintf("ERROR: cannot find \"STRPTIME\" entry for ENTRY_TIMESTAMP %s", pfix);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
{ /*--- Check for "FLAGS" symbol ---*/
|
||||
const char *flagStr;
|
||||
snprintf(symBuf, len, "%s\\FLAGS", pfix);
|
||||
|
||||
flagStr= CFGMAP_find_last_value(h_map, symBuf);
|
||||
/* This is optional */
|
||||
if(flagStr) {
|
||||
int rc= str2bits(&self->flags, flagStr, FlagsBitTupleArr);
|
||||
if(rc) {
|
||||
eprintf("ERROR: cannot interpret \"FLAGS\" entry for ENTRY_TIMESTAMP %s", pfix);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtn= 0;
|
||||
abort:
|
||||
return rtn;
|
||||
}
|
||||
|
||||
void*
|
||||
TS_destructor(TS *self)
|
||||
/********************************************************
|
||||
* Free resources.
|
||||
*/
|
||||
{
|
||||
if(self->pattern)
|
||||
regfree(&self->re);
|
||||
return self;
|
||||
}
|
||||
|
||||
int
|
||||
TS_scan(const TS *self, time_t *rslt, const char *str, const struct tm *pTmRef)
|
||||
/********************************************************
|
||||
* Scan a string to obtain the timestamp.
|
||||
*/
|
||||
{
|
||||
int rtn= -1;
|
||||
|
||||
/* If there is no match, continue looking */
|
||||
regmatch_t matchArr[2];
|
||||
if(0 != regexec(&self->re, str, 2, matchArr, 0) || -1 == matchArr[1].rm_so) {
|
||||
eprintf("ERROR: failed to identify date in \"%s\"", str);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
unsigned len= matchArr[1].rm_eo - matchArr[1].rm_so;
|
||||
static char date[128];
|
||||
strncpy(date, str+matchArr[1].rm_so, sizeof(date)-1);
|
||||
date[MIN(len, sizeof(date)-1)]= '\0';
|
||||
static struct tm tm;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_isdst= -1;
|
||||
|
||||
const char *lc= ez_strptime(date, self->strptime_fmt, &tm);
|
||||
|
||||
/* We may have to guess the year */
|
||||
if(self->flags & GUESS_YR_FLG) {
|
||||
|
||||
tm.tm_year= pTmRef->tm_year;
|
||||
|
||||
if(tm.tm_mon > pTmRef->tm_mon)
|
||||
--tm.tm_year;
|
||||
}
|
||||
|
||||
*rslt= mktime(&tm);
|
||||
//eprintf("Date string= \"%s\", lc= \"%s\", =? \"%s\"", date, lc, ctime(rslt));
|
||||
|
||||
rtn= 0;
|
||||
abort:
|
||||
return rtn;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2019 by John D. Robertson *
|
||||
* john@rrci.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef TIMESTAMP_H
|
||||
#define TIMESTAMP_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <regex.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cfgmap.h"
|
||||
|
||||
typedef struct _TS {
|
||||
const char *pattern;
|
||||
regex_t re;
|
||||
const char *strptime_fmt;
|
||||
int64_t flags;
|
||||
} TS;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TS_is_prepared(s) \
|
||||
((s)->pattern ? 1 : 0)
|
||||
|
||||
int
|
||||
TS_init(TS *self, CFGMAP *h_map, const char *pfix);
|
||||
/********************************************************
|
||||
* Initialize timestamp from config map.
|
||||
*/
|
||||
|
||||
void*
|
||||
TS_destructor(TS *self);
|
||||
/********************************************************
|
||||
* Free resources.
|
||||
*/
|
||||
|
||||
int
|
||||
TS_scan(const TS *self, time_t *rslt, const char *str, const struct tm *pTmRef);
|
||||
/********************************************************
|
||||
* Scan a string to obtain the timestamp.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue