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

View File

@ -95,7 +95,7 @@ struct Global G= {
.version= {
.major= 0,
.minor= 11,
.patch= 0
.patch= 2
},
.bitTuples.flags= GlobalFlagBitTuples
@ -144,7 +144,8 @@ static struct {
/* Enums for long options */
enum {
VERSION_OPT_ENUM=128, /* Larger than any printable character */
HELP_OPT_ENUM
HELP_OPT_ENUM,
PRINT_LOGFILE_NAMES_ENUM
};
int
@ -177,6 +178,7 @@ main(int argc, char **argv)
static const struct option long_options[]= {
{"help", no_argument, 0, HELP_OPT_ENUM},
{"print-lfn", no_argument, 0, PRINT_LOGFILE_NAMES_ENUM},
{"version", no_argument, 0, VERSION_OPT_ENUM},
{}
};
@ -217,6 +219,10 @@ main(int argc, char **argv)
G.flags |= GLB_VERBOSE_FLG;
break;
case PRINT_LOGFILE_NAMES_ENUM:
G.flags |= GLB_PRINT_LOGFILE_NAMES_FLG;
break;
case VERSION_OPT_ENUM:
ez_fprintf(stdout, "ban2fail v%d.%d.%d\n", G.version.major, G.version.minor, G.version.patch);
return 0;
@ -230,8 +236,7 @@ main(int argc, char **argv)
if(errflg) {
ez_fprintf(stderr,
"ban2fail v%d.%d.%d\n"
"Usage:\n"
"ban2fail v%d.%d.%d Usage:\n"
"%s [options] [-t confFile]\n"
" --help\tprint this usage message.\n"
" -a\t\tList results by Address\n"
@ -239,6 +244,7 @@ main(int argc, char **argv)
" -s\t\tlist Summary results only\n"
" -t confFile\tTest confFile, do not apply iptables rules\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"
, G.version.major, G.version.minor, G.version.patch
, 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 */
DIR *dir= ez_opendir(G.cacheDir);
struct dirent *entry;
@ -363,12 +375,29 @@ main(int argc, char **argv)
ez_close(lock_fd);
lock_fd= -1;
unsigned nFound= 0;
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_offenseCount, &nFound);
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);
/* Clean up map used for counting */
MAP_clearAndDestroy(&map, (void*(*)(void*))LOGENTRY_destructor);
MAP_destructor(&map);
}
}

View File

@ -53,6 +53,7 @@ extern struct Global {
GLB_LIST_CNTRY_FLG =1<<2,
GLB_DONT_IPTABLE_FLG =1<<3,
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
} flags;

12
ban2fail.service Normal file
View 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

View File

@ -1,44 +1,52 @@
#!/bin/bash
#!/bin/bash -e
#
# JDR Wed 20 Nov 2019 10:48:14 PM EST
# The purpose of this script is to be run from a minutely cron job,
# running the job several times a minute,
# making reasonably sure there is no overlap.
# JDR Wed 27 Nov 2019 01:30:29 PM EST
# The purpose of this script is to be run from a systemd service
# file, or sysvinit script.
#
BAN2FAIL=/usr/local/bin/ban2fail
BAN2FAIL_CFG=/etc/ban2fail/ban2fail.cfg
LOGFILE=/var/log/ban2fail.log
#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
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
FINISHED_SEC=$(date +%s)
(( SLEEP = 5 - FINISHED_SEC + NOW_SEC ))
done < <(/usr/bin/inotifywait -m $LOG_NAMES)
(( SLEEP < 1 )) && continue
sleep $SLEEP
date | tr -d $'\n'
echo ' Exiting main loop'
sleep 1
done
echo >>$LOGFILE
exit 0

View File

@ -32,7 +32,9 @@
#include "ez_gzfile.h"
#include "util.h"
#define NOFFENSES_CACHED_FLG (1<<0)
enum {
NOFFENSES_CACHED_FLG =1<<0
};
/*==================================================================*/
/*=================== LOGFILE ======================================*/
@ -45,7 +47,7 @@ common_constructor(LOGFILE *self)
*/
{
memset(self, 0, sizeof(*self));
MAP_constructor(&self->addr_map, 1000, 200);
MAP_constructor(&self->addr2logEntry_map, 1000, 200);
}
LOGFILE*
@ -65,7 +67,7 @@ LOGFILE_cache_constructor(LOGFILE *self, const char *fname)
LOGENTRY *e;
LOGENTRY_cache_create(e, buf);
if(!e) goto abort;
MAP_addStrKey(&self->addr_map, e->addr, e);
MAP_addStrKey(&self->addr2logEntry_map, e->addr, e);
}
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);
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) {
LOGENTRY_addr_create(e, addr);
if(!e) goto abort;
/* Add to the addr_map */
MAP_addStrKey(&self->addr_map, e->addr, e);
/* Add to the addr2logEntry_map */
MAP_addStrKey(&self->addr2logEntry_map, e->addr, e);
}
LOGENTRY_register(e);
}
@ -139,8 +141,8 @@ LOGFILE_destructor(LOGFILE *self)
if(self->logFilePath)
free(self->logFilePath);
MAP_clearAndDestroy(&self->addr_map, (void*(*)(void*))LOGENTRY_destructor);
MAP_destructor(&self->addr_map);
MAP_clearAndDestroy(&self->addr2logEntry_map, (void*(*)(void*))LOGENTRY_destructor);
MAP_destructor(&self->addr2logEntry_map);
return self;
}
@ -166,7 +168,7 @@ LOGFILE_writeCache(LOGFILE *self, const char *fname)
int rc, rtn= -1;
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;
rtn= 0;
@ -182,7 +184,7 @@ LOGFILE_print(LOGFILE *self, FILE *fh)
*/
{
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");
return 0;
@ -191,11 +193,11 @@ LOGFILE_print(LOGFILE *self, FILE *fh)
int
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.
*/
{
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;
}
@ -206,7 +208,7 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum)
*/
{
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;
}
@ -214,3 +216,14 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum)
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;
}

View File

@ -28,7 +28,7 @@
typedef struct _LOGFILE {
int flags;
char *logFilePath;
MAP addr_map;
MAP addr2logEntry_map;
unsigned nOffenses;
} LOGFILE;
@ -93,6 +93,12 @@ LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum);
* 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
}
#endif

View File

@ -27,6 +27,7 @@
#include <unistd.h>
#include "ban2fail.h"
#include "logEntry.h"
#include "logFile.h"
#include "logType.h"
#include "ez_dirent.h"
@ -35,7 +36,6 @@
#include "str.h"
#include "util.h"
#define NOFFENSES_CACHED_FLG (1<<0)
static int
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->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);
{ /* Compute md5sum of all patterns put together */
@ -212,11 +215,14 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
}
assert(f);
unsigned nFound= 0;
LOGFILE_offenseCount(f, &nFound);
unsigned nOffFound= 0,
nAddrFound= 0;
LOGFILE_offenseCount(f, &nOffFound);
LOGFILE_addressCount(f, &nAddrFound);
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);
}
@ -248,12 +254,15 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
ez_closedir(dir);
}
unsigned nFound= 0;
LOGTYPE_offenseCount(self, &nFound);
unsigned nOffFound= 0,
nAddrFound;
LOGTYPE_offenseCount(self, &nOffFound);
nAddrFound= LOGTYPE_addressCount(self);
if(G.flags & GLB_LONG_LISTING_FLG) {
ez_fprintf(G.listing_fh, ">>>> Found %u offenses for %s/%s*\n"
, nFound
ez_fprintf(G.listing_fh, ">>>> Found %u offenses (%u addresses) for %s/%s*\n"
, nOffFound
, nAddrFound
, self->dir
, self->pfix
);
@ -433,10 +442,29 @@ LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum)
* Get a count of all offenses for this log type.
*/
{
if(!(self->flags & NOFFENSES_CACHED_FLG)) {
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_offenseCount, &self->nOffenses);
self->flags |= NOFFENSES_CACHED_FLG;
}
*h_sum += self->nOffenses;
unsigned nFound= 0;
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_offenseCount, &nFound);
*h_sum += nFound;
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;
}

View File

@ -48,12 +48,10 @@ struct logProtoType {
/* One of these for each log file type to be scanned */
typedef struct _LOGTYPE {
int flags;
char *dir,
*pfix,
patterns_md5sum[33];
MAP file_map;
unsigned nOffenses;
} LOGTYPE;
#ifdef __cplusplus
@ -107,6 +105,12 @@ LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum);
* 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
}
#endif