1
1
mirror of https://github.com/jrbrtsn/ban2fail synced 2024-06-16 03:48:03 +00:00

Implemented event driven behavior script and service file

This commit is contained in:
john 2019-11-27 14:17:34 -05:00
parent 5fa8cd0f99
commit dd8c9cbfa8
8 changed files with 160 additions and 59 deletions

@ -95,7 +95,7 @@ struct Global G= {
.version= { .version= {
.major= 0, .major= 0,
.minor= 11, .minor= 11,
.patch= 0 .patch= 2
}, },
.bitTuples.flags= GlobalFlagBitTuples .bitTuples.flags= GlobalFlagBitTuples
@ -144,7 +144,8 @@ static struct {
/* Enums for long options */ /* Enums for long options */
enum { enum {
VERSION_OPT_ENUM=128, /* Larger than any printable character */ VERSION_OPT_ENUM=128, /* Larger than any printable character */
HELP_OPT_ENUM HELP_OPT_ENUM,
PRINT_LOGFILE_NAMES_ENUM
}; };
int int
@ -177,6 +178,7 @@ main(int argc, char **argv)
static const struct option long_options[]= { static const struct option long_options[]= {
{"help", no_argument, 0, HELP_OPT_ENUM}, {"help", no_argument, 0, HELP_OPT_ENUM},
{"print-lfn", no_argument, 0, PRINT_LOGFILE_NAMES_ENUM},
{"version", no_argument, 0, VERSION_OPT_ENUM}, {"version", no_argument, 0, VERSION_OPT_ENUM},
{} {}
}; };
@ -217,6 +219,10 @@ main(int argc, char **argv)
G.flags |= GLB_VERBOSE_FLG; G.flags |= GLB_VERBOSE_FLG;
break; break;
case PRINT_LOGFILE_NAMES_ENUM:
G.flags |= GLB_PRINT_LOGFILE_NAMES_FLG;
break;
case VERSION_OPT_ENUM: case VERSION_OPT_ENUM:
ez_fprintf(stdout, "ban2fail v%d.%d.%d\n", G.version.major, G.version.minor, G.version.patch); ez_fprintf(stdout, "ban2fail v%d.%d.%d\n", G.version.major, G.version.minor, G.version.patch);
return 0; return 0;
@ -230,8 +236,7 @@ main(int argc, char **argv)
if(errflg) { if(errflg) {
ez_fprintf(stderr, ez_fprintf(stderr,
"ban2fail v%d.%d.%d\n" "ban2fail v%d.%d.%d Usage:\n"
"Usage:\n"
"%s [options] [-t confFile]\n" "%s [options] [-t confFile]\n"
" --help\tprint this usage message.\n" " --help\tprint this usage message.\n"
" -a\t\tList results by Address\n" " -a\t\tList results by Address\n"
@ -239,6 +244,7 @@ main(int argc, char **argv)
" -s\t\tlist Summary results only\n" " -s\t\tlist Summary results only\n"
" -t confFile\tTest confFile, do not apply iptables rules\n" " -t confFile\tTest confFile, do not apply iptables rules\n"
" -v\t\tVerbose information about unrecognized configuration info\n" " -v\t\tVerbose information about unrecognized configuration info\n"
" --print-lfn\tprint the names of primary logfiles to scan\n"
" --version\tprint the version number and exit.\n" " --version\tprint the version number and exit.\n"
, G.version.major, G.version.minor, G.version.patch , G.version.major, G.version.minor, G.version.patch
, argv[0] , argv[0]
@ -333,6 +339,12 @@ main(int argc, char **argv)
} }
if(G.flags & GLB_PRINT_LOGFILE_NAMES_FLG) {
/* Shortcut any further processing or reporting */
rtn= 0;
goto abort;
}
{ /* Check cache for logType directories not in our current map */ { /* Check cache for logType directories not in our current map */
DIR *dir= ez_opendir(G.cacheDir); DIR *dir= ez_opendir(G.cacheDir);
struct dirent *entry; struct dirent *entry;
@ -363,12 +375,29 @@ main(int argc, char **argv)
ez_close(lock_fd); ez_close(lock_fd);
lock_fd= -1; lock_fd= -1;
unsigned nFound= 0;
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_offenseCount, &nFound);
if(G.flags & GLB_LONG_LISTING_FLG) { if(G.flags & GLB_LONG_LISTING_FLG) {
ez_fprintf(G.listing_fh, "===== Found %u total offenses =====\n", nFound); MAP map;
MAP_constructor(&map, 1000, 100);
unsigned nOffFound= 0,
nAddrFound;
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_offenseCount, &nOffFound);
/* Collect unique addresses into a map */
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_map_addr, &map);
/* Number of items in map is number of unique addresses */
nAddrFound= MAP_numItems(&map);
ez_fprintf(G.listing_fh,
"===== Found %u total offenses (%u addresses) =====\n"
, nOffFound
, nAddrFound
);
fflush(G.listing_fh); fflush(G.listing_fh);
/* Clean up map used for counting */
MAP_clearAndDestroy(&map, (void*(*)(void*))LOGENTRY_destructor);
MAP_destructor(&map);
} }
} }

@ -53,6 +53,7 @@ extern struct Global {
GLB_LIST_CNTRY_FLG =1<<2, GLB_LIST_CNTRY_FLG =1<<2,
GLB_DONT_IPTABLE_FLG =1<<3, GLB_DONT_IPTABLE_FLG =1<<3,
GLB_LIST_SUMMARY_FLG =1<<4, GLB_LIST_SUMMARY_FLG =1<<4,
GLB_PRINT_LOGFILE_NAMES_FLG =1<<5,
GLB_LONG_LISTING_FLG = GLB_LIST_CNTRY_FLG|GLB_LIST_ADDR_FLG GLB_LONG_LISTING_FLG = GLB_LIST_CNTRY_FLG|GLB_LIST_ADDR_FLG
} flags; } flags;

12
ban2fail.service Normal file

@ -0,0 +1,12 @@
[Unit]
Description=Log file scanning and iptables filtering
ConditionPathExists=/usr/local/bin/ban2fail.sh
[Service]
WorkingDirectory=/tmp
Type=simple
ExecStart=/usr/local/bin/ban2fail.sh
TimeoutSec=0
[Install]
WantedBy=multi-user.target

@ -1,44 +1,52 @@
#!/bin/bash #!/bin/bash -e
# #
# JDR Wed 20 Nov 2019 10:48:14 PM EST # JDR Wed 27 Nov 2019 01:30:29 PM EST
# The purpose of this script is to be run from a minutely cron job, # The purpose of this script is to be run from a systemd service
# running the job several times a minute, # file, or sysvinit script.
# making reasonably sure there is no overlap.
# #
BAN2FAIL=/usr/local/bin/ban2fail BAN2FAIL=/usr/local/bin/ban2fail
BAN2FAIL_CFG=/etc/ban2fail/ban2fail.cfg
LOGFILE=/var/log/ban2fail.log LOGFILE=/var/log/ban2fail.log
#LOGFILE=/dev/pts/2 #LOGFILE=/dev/pts/2
PERIOD_SEC=5
WHEN=$(date) # Uncomment this if you wish to see output from the time command
#TIME=time
echo -n "$WHEN" >>$LOGFILE # Always do initial check
echo "Initial run for $BAN2FAIL"
$TIME $BAN2FAIL
BEGIN_SEC=$(date +%s)
count=0
while true; do while true; do
echo "Starting main loop"
LOG_NAMES=$($BAN2FAIL --print-lfn | tr $'\n' ' ')
LOG_NAMES="$LOG_NAMES $BAN2FAIL_CFG"
(( ++count )) echo "Monitoring: $LOG_NAMES"
NOW_SEC=$(date +%s) while read; do
# if a file gets renamed, logrotate is doing it's thing.
[[ "$REPLY" =~ MOVE_SELF ]] && break
[[ "$REPLY" == $BAN2FAIL_CFG\ MODIFY ]] && break
(( MAX_SEC= 60 - PERIOD_SEC - 1 )) [[ "$REPLY" =~ MODIFY ]] || continue
(( NOW_SEC - BEGIN_SEC > MAX_SEC )) && break # Uncomment this to see the inotifywait output which triggered this cycle
#echo "REPLY= '$REPLY'"
$BAN2FAIL echo "Running $BAN2FAIL"
# Check for offenses
# If ban2fail failed, then pause to avoid DOS on CPU
$TIME $BAN2FAIL || sleep 1
echo -n " $count" >>$LOGFILE done < <(/usr/bin/inotifywait -m $LOG_NAMES)
FINISHED_SEC=$(date +%s)
(( SLEEP = 5 - FINISHED_SEC + NOW_SEC ))
(( SLEEP < 1 )) && continue date | tr -d $'\n'
sleep $SLEEP echo ' Exiting main loop'
sleep 1
done done
echo >>$LOGFILE
exit 0 exit 0

@ -32,7 +32,9 @@
#include "ez_gzfile.h" #include "ez_gzfile.h"
#include "util.h" #include "util.h"
#define NOFFENSES_CACHED_FLG (1<<0) enum {
NOFFENSES_CACHED_FLG =1<<0
};
/*==================================================================*/ /*==================================================================*/
/*=================== LOGFILE ======================================*/ /*=================== LOGFILE ======================================*/
@ -45,7 +47,7 @@ common_constructor(LOGFILE *self)
*/ */
{ {
memset(self, 0, sizeof(*self)); memset(self, 0, sizeof(*self));
MAP_constructor(&self->addr_map, 1000, 200); MAP_constructor(&self->addr2logEntry_map, 1000, 200);
} }
LOGFILE* LOGFILE*
@ -65,7 +67,7 @@ LOGFILE_cache_constructor(LOGFILE *self, const char *fname)
LOGENTRY *e; LOGENTRY *e;
LOGENTRY_cache_create(e, buf); LOGENTRY_cache_create(e, buf);
if(!e) goto abort; if(!e) goto abort;
MAP_addStrKey(&self->addr_map, e->addr, e); MAP_addStrKey(&self->addr2logEntry_map, e->addr, e);
} }
rtn= self; rtn= self;
@ -111,13 +113,13 @@ LOGFILE_log_constructor(LOGFILE *self, const struct logProtoType *h_protoType, c
strncpy(addr, lbuf+matchArr[1].rm_so, sizeof(addr)-1); strncpy(addr, lbuf+matchArr[1].rm_so, sizeof(addr)-1);
addr[MIN(len, sizeof(addr)-1)]= '\0'; addr[MIN(len, sizeof(addr)-1)]= '\0';
LOGENTRY *e= MAP_findStrItem(&self->addr_map, addr); LOGENTRY *e= MAP_findStrItem(&self->addr2logEntry_map, addr);
if(!e) { if(!e) {
LOGENTRY_addr_create(e, addr); LOGENTRY_addr_create(e, addr);
if(!e) goto abort; if(!e) goto abort;
/* Add to the addr_map */ /* Add to the addr2logEntry_map */
MAP_addStrKey(&self->addr_map, e->addr, e); MAP_addStrKey(&self->addr2logEntry_map, e->addr, e);
} }
LOGENTRY_register(e); LOGENTRY_register(e);
} }
@ -139,8 +141,8 @@ LOGFILE_destructor(LOGFILE *self)
if(self->logFilePath) if(self->logFilePath)
free(self->logFilePath); free(self->logFilePath);
MAP_clearAndDestroy(&self->addr_map, (void*(*)(void*))LOGENTRY_destructor); MAP_clearAndDestroy(&self->addr2logEntry_map, (void*(*)(void*))LOGENTRY_destructor);
MAP_destructor(&self->addr_map); MAP_destructor(&self->addr2logEntry_map);
return self; return self;
} }
@ -166,7 +168,7 @@ LOGFILE_writeCache(LOGFILE *self, const char *fname)
int rc, rtn= -1; int rc, rtn= -1;
FILE *fh= ez_fopen(fname, "w"); FILE *fh= ez_fopen(fname, "w");
rc= MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_cacheWrite, fh); rc= MAP_visitAllEntries(&self->addr2logEntry_map, (int(*)(void*,void*))LOGENTRY_cacheWrite, fh);
if(rc) goto abort; if(rc) goto abort;
rtn= 0; rtn= 0;
@ -182,7 +184,7 @@ LOGFILE_print(LOGFILE *self, FILE *fh)
*/ */
{ {
ez_fprintf(fh, "LOGFILE %p \"%s\" {\n", self, self->logFilePath); ez_fprintf(fh, "LOGFILE %p \"%s\" {\n", self, self->logFilePath);
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_print, fh); MAP_visitAllEntries(&self->addr2logEntry_map, (int(*)(void*,void*))LOGENTRY_print, fh);
ez_fprintf(fh, "}\n"); ez_fprintf(fh, "}\n");
return 0; return 0;
@ -191,11 +193,11 @@ LOGFILE_print(LOGFILE *self, FILE *fh)
int int
LOGFILE_map_addr(LOGFILE *self, MAP *h_rtnMap) LOGFILE_map_addr(LOGFILE *self, MAP *h_rtnMap)
/******************************************************** /********************************************************
* Create a addr_map of LOGENTRY objects with composite * Create a addr2logEntry_map of LOGENTRY objects with composite
* counts by address. * counts by address.
*/ */
{ {
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_map_addr, h_rtnMap); MAP_visitAllEntries(&self->addr2logEntry_map, (int(*)(void*,void*))LOGENTRY_map_addr, h_rtnMap);
return 0; return 0;
} }
@ -206,7 +208,7 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum)
*/ */
{ {
if(!(self->flags & NOFFENSES_CACHED_FLG)) { if(!(self->flags & NOFFENSES_CACHED_FLG)) {
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_offenseCount, &self->nOffenses); MAP_visitAllEntries(&self->addr2logEntry_map, (int(*)(void*,void*))LOGENTRY_offenseCount, &self->nOffenses);
self->flags |= NOFFENSES_CACHED_FLG; self->flags |= NOFFENSES_CACHED_FLG;
} }
@ -214,3 +216,14 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum)
return 0; return 0;
} }
int
LOGFILE_addressCount(LOGFILE *self, unsigned *h_sum)
/********************************************************
* Get a count of all unique addresses for this file.
*/
{
*h_sum += MAP_numItems(&self->addr2logEntry_map);
return 0;
}

@ -28,7 +28,7 @@
typedef struct _LOGFILE { typedef struct _LOGFILE {
int flags; int flags;
char *logFilePath; char *logFilePath;
MAP addr_map; MAP addr2logEntry_map;
unsigned nOffenses; unsigned nOffenses;
} LOGFILE; } LOGFILE;
@ -93,6 +93,12 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum);
* Get a count of all offenses for this file. * Get a count of all offenses for this file.
*/ */
int
LOGFILE_addressCount(LOGFILE *self, unsigned *h_sum);
/********************************************************
* Get a count of all unique addresses for this file.
*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -27,6 +27,7 @@
#include <unistd.h> #include <unistd.h>
#include "ban2fail.h" #include "ban2fail.h"
#include "logEntry.h"
#include "logFile.h" #include "logFile.h"
#include "logType.h" #include "logType.h"
#include "ez_dirent.h" #include "ez_dirent.h"
@ -35,7 +36,6 @@
#include "str.h" #include "str.h"
#include "util.h" #include "util.h"
#define NOFFENSES_CACHED_FLG (1<<0)
static int static int
cmp_pvsort(const void *const* pp1, const void *const* pp2) cmp_pvsort(const void *const* pp1, const void *const* pp2)
@ -104,6 +104,9 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
self->dir= strdup(proto->dir); self->dir= strdup(proto->dir);
self->pfix= strdup(proto->pfix); self->pfix= strdup(proto->pfix);
if(G.flags & GLB_PRINT_LOGFILE_NAMES_FLG)
ez_fprintf(G.listing_fh, "%s/%s\n", proto->dir, proto->pfix);
size_t pfix_len= strlen(self->pfix); size_t pfix_len= strlen(self->pfix);
{ /* Compute md5sum of all patterns put together */ { /* Compute md5sum of all patterns put together */
@ -212,11 +215,14 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
} }
assert(f); assert(f);
unsigned nFound= 0; unsigned nOffFound= 0,
LOGFILE_offenseCount(f, &nFound); nAddrFound= 0;
LOGFILE_offenseCount(f, &nOffFound);
LOGFILE_addressCount(f, &nAddrFound);
if(G.flags & GLB_LONG_LISTING_FLG) { if(G.flags & GLB_LONG_LISTING_FLG) {
ez_fprintf(G.listing_fh, " found %u offenses\n", nFound); ez_fprintf(G.listing_fh, " found %u offenses (%u addresses)\n", nOffFound, nAddrFound);
fflush(G.listing_fh); fflush(G.listing_fh);
} }
@ -248,12 +254,15 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
ez_closedir(dir); ez_closedir(dir);
} }
unsigned nFound= 0; unsigned nOffFound= 0,
LOGTYPE_offenseCount(self, &nFound); nAddrFound;
LOGTYPE_offenseCount(self, &nOffFound);
nAddrFound= LOGTYPE_addressCount(self);
if(G.flags & GLB_LONG_LISTING_FLG) { if(G.flags & GLB_LONG_LISTING_FLG) {
ez_fprintf(G.listing_fh, ">>>> Found %u offenses for %s/%s*\n" ez_fprintf(G.listing_fh, ">>>> Found %u offenses (%u addresses) for %s/%s*\n"
, nFound , nOffFound
, nAddrFound
, self->dir , self->dir
, self->pfix , self->pfix
); );
@ -433,10 +442,29 @@ LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum)
* Get a count of all offenses for this log type. * Get a count of all offenses for this log type.
*/ */
{ {
if(!(self->flags & NOFFENSES_CACHED_FLG)) { unsigned nFound= 0;
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_offenseCount, &self->nOffenses); MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_offenseCount, &nFound);
self->flags |= NOFFENSES_CACHED_FLG; *h_sum += nFound;
}
*h_sum += self->nOffenses;
return 0; return 0;
} }
int
LOGTYPE_addressCount(LOGTYPE *self)
/********************************************************
* Get a count of all addresses for this log type.
* NOT REENTRANT!
*/
{
/* We'll need a map in which to collect unique addresses */
static MAP smap;
MAP_sinit(&smap, 1000, 100);
/* Collect results for all LOGILE objects we own */
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_map_addr, &smap);
/* For clarity */
unsigned nFound= MAP_numItems(&smap);
/* Cleanup for next time */
MAP_clearAndDestroy(&smap, (void*(*)(void*))LOGENTRY_destructor);
return nFound;
}

@ -48,12 +48,10 @@ struct logProtoType {
/* One of these for each log file type to be scanned */ /* One of these for each log file type to be scanned */
typedef struct _LOGTYPE { typedef struct _LOGTYPE {
int flags;
char *dir, char *dir,
*pfix, *pfix,
patterns_md5sum[33]; patterns_md5sum[33];
MAP file_map; MAP file_map;
unsigned nOffenses;
} LOGTYPE; } LOGTYPE;
#ifdef __cplusplus #ifdef __cplusplus
@ -107,6 +105,12 @@ LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum);
* Get a count of all offenses for this log type. * Get a count of all offenses for this log type.
*/ */
int
LOGTYPE_addressCount(LOGTYPE *self);
/********************************************************
* Get a count of all addresses for this log type.
*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif