mirror of https://github.com/jrbrtsn/ban2fail
Implemented event driven behavior script and service file
This commit is contained in:
parent
5fa8cd0f99
commit
dd8c9cbfa8
45
ban2fail.c
45
ban2fail.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
52
ban2fail.sh
52
ban2fail.sh
|
@ -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
|
||||
|
|
39
logFile.c
39
logFile.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
54
logType.c
54
logType.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue