From 1bb1ee5f86ec8d4712213937675e4eaf495d4dc7 Mon Sep 17 00:00:00 2001 From: john Date: Thu, 28 Nov 2019 10:10:31 -0500 Subject: [PATCH] Various optimizations --- ban2fail.c | 2 +- ban2fail.sh | 59 +++++++++++++++++++++++++++++++++++++++++++---------- iptables.c | 5 +++-- logType.c | 21 ++++++++++++++++++- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/ban2fail.c b/ban2fail.c index 31be2f1..05e2065 100644 --- a/ban2fail.c +++ b/ban2fail.c @@ -95,7 +95,7 @@ struct Global G= { .version= { .major= 0, .minor= 11, - .patch= 5 + .patch= 6 }, .bitTuples.flags= GlobalFlagBitTuples diff --git a/ban2fail.sh b/ban2fail.sh index c4674db..2d524ff 100755 --- a/ban2fail.sh +++ b/ban2fail.sh @@ -1,11 +1,11 @@ -#!/bin/bash -e +#!/bin/bash # # 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. # # BE CAREFUL not to monitor the log file to which output from this -# script gets written - you will have a feedback loop! +# script is written - you will have a feedback loop! # BAN2FAIL=/usr/local/bin/ban2fail @@ -15,18 +15,27 @@ INOTIFYWAIT=/usr/bin/inotifywait # Uncomment this if you wish to see output from the time command #TIME=time -# Always do initial check -echo "Initial run for $BAN2FAIL" -$TIME $BAN2FAIL +# Do not run again for at least this many deciseconds, to +# avoid monopolizing CPU +MIN_PERIOD_DS=3 + +# Get period in nanoseconds for integer calculations +(( MIN_PERIOD_NS = MIN_PERIOD_DS * 100000000 )) while true; do echo "Starting main loop" LOG_NAMES=$($BAN2FAIL --print-lfn | tr $'\n' ' ') LOG_NAMES="$LOG_NAMES $BAN2FAIL_CFG" + # Always do initial check + echo "Initial run for $BAN2FAIL" + RAN_NS=$(date +%s%N) + $TIME $BAN2FAIL + echo "Monitoring: $LOG_NAMES" while read; do + # if a file gets renamed, logrotate is doing it's thing. [[ "$REPLY" =~ MOVE_SELF ]] && break [[ "$REPLY" == $BAN2FAIL_CFG\ MODIFY ]] && break @@ -36,18 +45,46 @@ while true; do # Uncomment this to see the inotifywait output which triggered this cycle #echo "REPLY= '$REPLY'" - # Avoid running ban2fail multiple times if possible - while read -t 0; do - read - done + NOW_NS=$(date +%s%N) + (( SINCE_NS = NOW_NS - RAN_NS )) +#echo "RAN_NS= $RAN_NS, NOW_NS= $NOW_NS, SINCE_NS= $SINCE_NS, MIN_PERIOD_NS= $MIN_PERIOD_NS" + if (( SINCE_NS < MIN_PERIOD_NS )); then + + (( REMAINING_NS = MIN_PERIOD_NS - SINCE_NS )) + + # break sleep time into seconds and nanosecond remainder components + (( REMAINING_SEC = REMAINING_NS / 1000000000 )) + (( REMAINING_NS_REM = REMAINING_NS % 1000000000 )) + +#echo "REMAINING_NS= $REMAINING_NS, REMAINING_SEC= $REMAINING_SEC, REMAINING_NS_REM= $REMAINING_NS_REM" + + if (( REMAINING_SEC || REMAINING_NS_REM > 1000000 )); then + + # use printf command to format as floating point string + remaining_sec_fp=$(printf '%d.%09d' $REMAINING_SEC $REMAINING_NS_REM) + +#echo "sleeping for $remaining_sec_fp seconds" + + # sleep for floating point period of seconds + sleep $remaining_sec_fp + fi + + fi + + # Consume queued input to avoid running ban2fail more than necessary + while read -t 0; do read; done echo "Running $BAN2FAIL" + # Check for offenses - # If ban2fail failed, then pause to avoid DOS on CPU + # If ban2fail failed, then pause to avoid monopolizing CPU + RAN_NS=$(date +%s%N) while ! $TIME $BAN2FAIL; do - sleep 1 + sleep .5 + RAN_NS=$(date +%s%N) done + done < <(exec $INOTIFYWAIT -m $LOG_NAMES) echo ' Exiting main loop' diff --git a/iptables.c b/iptables.c index bfc4b19..7875075 100644 --- a/iptables.c +++ b/iptables.c @@ -49,7 +49,7 @@ initialize (void) const static struct ipv { const char *cmd, *pattern; - } Ipv[] = { + } ipv_arr[] = { { .cmd= IPTABLES " -nL INPUT 2>/dev/null", .pattern= "DROP[[:space:]]+all[[:space:]]+--[[:space:]]+([0-9.]+)[[:space:]]+0\\.0\\.0\\.0/0" }, @@ -59,7 +59,8 @@ initialize (void) { /* Terminating member */ } }; - for(const struct ipv *ipv= Ipv; ipv->cmd; ++ipv) { + /* Take care of all ip versions ... */ + for(const struct ipv *ipv= ipv_arr; ipv->cmd; ++ipv) { static char lbuf[1024]; static char addr[43]; diff --git a/logType.c b/logType.c index cb9ef7e..d726d81 100644 --- a/logType.c +++ b/logType.c @@ -104,8 +104,15 @@ 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) + if(G.flags & GLB_PRINT_LOGFILE_NAMES_FLG) { + ez_fprintf(G.listing_fh, "%s/%s\n", proto->dir, proto->pfix); + /* We're going to save time here and short circuit the remainder + * of the process; because this object will not get used for + * anything other than listing the file names. + */ + return self; + } size_t pfix_len= strlen(self->pfix); @@ -192,6 +199,10 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto) /* Now we have the checksum of the log file */ /* See if the cached results exist */ rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, sumStr); + if(sizeof(CacheFname) == rc) { + eprintf("FATAL: File path truncated!"); + exit(1); + } LOGFILE *f; if(!access(CacheFname, F_OK)) { @@ -248,6 +259,10 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto) if(f) continue; rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, entry->d_name); + if(sizeof(CacheFname) == rc) { + eprintf("FATAL: File path truncated!"); + exit(1); + } ez_unlink(CacheFname); } @@ -337,6 +352,10 @@ LOGTYPE_init(CFGMAP *h_map, char *pfix) LOGTYPE_proto_create(obj, &proto); assert(obj); + /* Short circuit remainder of process if only printing file names */ + if(G.flags & GLB_PRINT_LOGFILE_NAMES_FLG) + return 0; + /* Place int the global map */ MAP_addStrKey(&G.logType_map, LOGTYPE_cacheName(obj), obj);