#=========================================================== #======= ... Do NOT change anything below ... ==== #=========================================================== # Function library for all dynloaders, modules & programs #=========================================================== # # Common procedures # shared by all programs, dynloaders & modules # # log simple log() { printf "%-18s %-s[%d]: %s\n" "`date +%Y-%m-%dT%T.%3N`" "$ME" "$$" "$*" >> $LOG } # # Columized log # 4 columns: 10,10,15,rest # clog() { printf "%-18s %-s[%d]: %-10s %-10s %-15s %s\n" "`date +%Y-%m-%dT%T.%3N`" "$ME" "$$" "$1" "$2" "$3" "$4" >> $LOG } do_geotrack() { if [ -p $FIFO_BASE/GeoTrack ] then echo $BANDIT $ME >> $FIFO_BASE/GeoTrack fi } trace() { if [ ! -z "$TRACE" ] then echo "`date +%Y-%m-%dT%T.%3N` $ME[$$]: $*" >> $ME.trace fi } # Check whether forward and reverse DNS resolution resolves to # the same IP address get_class() { # $1 .. an IP address local thisIP local thisHOST thisHOST=`dig +short -x $1` if [ -z "$thisHOST" ]; then echo NXDOMAIN; return; fi thisIP=`dig +short $thisHOST` if [[ "`echo $thisIP`" =~ "$1" ]] then echo TRUEHOST else echo FAKEHOST fi } validate_IP() { if [[ "$SYSSTYLE" =~ "rhel" ]] then /bin/ipcalc -sc $1; return $? else # Debian-ish do it the hard way ... $IPSET -q -exist add validate $1; return $? fi } # Pick the bandit's IP from the log line # Probably enquoted by ticks (single quotes), parens, # brackets or curly braces or even at the beginnig or # end of the line e.g. for PostFix # # Common/universal ... # Enclose the 'REPLY' in spaces helps matching # not to fail with IP adresses at begining or end # of the log line get_bandit() { awk ' BEGIN { rc=1 # Devel. note: See /root/bin/Test/IPmatch IP4PAT="([1-9]{1}[0-9]{0,2}[.]{1}){1}((0{1}[.])|([1-9]{1}[0-9]{0,2}[.])){2}((0{1})|([1-9]{1}[0-9]{0,2})){1}([\\] ]|[\\} ]|[\\) ]|[\\047 ]|[\\042 ]|[ ])+" } #match($0,/([0-9]{1,3}[.]{1}){3}[0-9]{1,3}/) { # Too simple and old, do not use! match($0,IP4PAT) { trail=substr($0,RSTART,RLENGTH) gsub(/[\[\]\{\}\(\)\047\042 ]/,"",trail) #print substr($0,RSTART,RLENGTH) print trail rc=0 } END { exit rc } ' <<< " $REPLY " } # Postfix ... IP addr in brackets [...] get_bandit_postfix() { echo "$REPLY" | awk ' /([0-9]{1,3}\.){3}[0-9]{1,3}/ { match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}/) ip=substr($0,RSTART,RLENGTH) print ip }' } # # sshd reports IP addresses like 'from aaa.bbb.xxx.yyy' # get_bandit_ssh() { local funtag="[${FUNCNAME[0]}]" local this_ip echo "$REPLY" | awk ' # IP in "from IPADDR" style # Some badfingers supply an IP addr as "user name" to mock scanners # ------------------------------------------------------------------ /(from )([0-9]{1,3}\.){3}[0-9]{1,3}/ { # Cut off the "from " token ... just the address x=match($0,/(from )([0-9]{1,3}\.){3}[0-9]{1,3}/) trail=substr($0,RSTART,RLENGTH) # match(trail,/([0-9]{1,3}\.){3}[0-9]{1,3}/) ip=substr(trail,RSTART,RLENGTH) print ip next } # IP in ssh-special style ... eeek! /(: Address )([0-9]{1,3}\.){3}[0-9]{1,3}/ { # Cut off the ": Address " token ... just the address x=match($0,/(: Address )([0-9]{1,3}\.){3}[0-9]{1,3}/) trail=substr($0,RSTART,RLENGTH) # match(trail,/([0-9]{1,3}\.){3}[0-9]{1,3}/) ip=substr(trail,RSTART,RLENGTH) print ip next } # IP in any delimiters (spaces, brackets, parens, ...) /\[([0-9]{1,3}\.){3}[0-9]{1,3}\]/ { x=match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}/) ip=substr($0, RSTART, RLENGTH) print ip }' } # # Whitelist check # whitelist() { : } # # Remove IP addr from database and ipset # freehost() { local funtag="[${FUNCNAME[0]}]" local haveit haveit=`$SQL "select IP from $TABLE where IP='$1';"` if [ ! -z "$haveit" ] then $SQL "delete from $TABLE where IP='$1';" # Cleanup in firewall $IPSET -exist del $ME-DB $1 $IPSET -exist del custody $1 $IPSET -exist del tarpit $1 log "$funtag Removing $1 from $ME database $DB" trace "$funtag Removing $1 from $ME database $DB" fi } # # Create an ipset with DROP target mk-ipset() { # $1 .. the ipset to be created local funtag="[${FUNCNAME[0]}]" local setname=$1 local settype=$2 case $FIREWALL in iptables) $IPSET -exist create $* if $IPTABLES -t filter -C INPUT -m set --match-set $setname src -j DROP >/dev/null 2>&1 then : echo "$setname already linked with xtables" else $IPTABLES -t filter -I INPUT -m set --match-set $setname src -j DROP >/dev/null 2>&1 fi if $IPTABLES -t filter -C FORWARD -m set --match-set $setname src -j DROP >/dev/null 2>&1 then : echo "$setname already linked with xtables" else $IPTABLES -t filter -I FORWARD -m set --match-set $setname src -j DROP >/dev/null 2>&1 fi ;; firewalld) # DON'T USE !!!! firewall-cmd --permanent --new-ipset=$setname --type="$settype" firewall-cmd --permanent --zone=public --add-source=ipset:$setname firewall-cmd --reload ;; *) logger "[$ME:$$] Error - firewall unknown ..." trace "Error - firewall unknown ..." ;; esac } # Make a grep -E 'string|string|..." list from superfluous_map file mk_superfluous() { local funtag="[${FUNCNAME[0]}]" awk ' BEGIN { str="" } /^[ \t]*($|#)/ { next } { str=str $0 "|" } END { gsub(/[|]$/,"",str) print str } ' < rules/superfluous_map trace "$funtag (Re)building superfluous_map" } compress_filter() { local funtag="[${FUNCNAME[0]}]" if [ -f filter ] then awk ' /^[ \t]*($|#)/ { next } { print } ' filter > filter.compress fi } dump_loadrate() { local funtag="[${FUNCNAME[0]}]" local loop_rate loop_secs loop_mils loop_days loop_rest local hum_rate # Need one loop ahead to calculate a difference if [ ! -z "$FILT_END" ] then # Loop rate in ms ... loop_rate=$(( `date +%s%3N` - FILT_END )) loop_secs=$(( loop_rate/1000 )) loop_mils=`printf "%03d" $((loop_rate%1000))` loop_days=$(( loop_secs/86400 )) loop_rest=$(( loop_secs%86400 )) hum_rate="`date -u -d @$loop_rest +%T`.$loop_mils" trace "« Loop rate: $loop_days d, $hum_rate »" fi } dump_runtime() { local funtag="[${FUNCNAME[0]}]" local rtfile=RUNTIME local oformat="%-15s: %-s\n" local rdstat rdstat=`mount | grep '^Watcher' | awk '{ print $1,"on",$3}'` > $rtfile printf "$oformat" "Object:" $ME >> $rtfile printf "$oformat" "MasterPath:" $MASTER_PATH >> $rtfile printf "$oformat" "Pool:" $POOL >> $rtfile printf "$oformat" "RAMdisk:" "$rdstat" >> $rtfile printf "$oformat" "Path:" $PATH >> $rtfile printf "$oformat" "AWKpath:" $AWKPATH >> $rtfile printf "$oformat" "BASHlib:" $BASHLIB >> $rtfile printf "$oformat" "\$IPSET:" $IPSET >> $rtfile printf "$oformat" "ipset:" `which ipset` >> $rtfile printf "$oformat" "AWK:" `which awk` >> $rtfile printf "$oformat" "date:" `which date` >> $rtfile printf "$oformat" "grep:" `which grep` >> $rtfile printf "$oformat" "sqlite:" `which sqlite3` >> $rtfile } # Create a table with the module's configuration data # $1 The database name from module config_table() { local table=`cut -f1 -d"." <<< "$1"` $SQL "drop table if exists config;" # $SQL "Create table config ( # my_path text, -- some identification # my_db text, # max_affairs integer # );" # $SQL "update $table # set my_path = '$WHERE', # my_db = '$DB', # max_affairs = $MAX_AFFAIRS # ;" $SQL "CREATE TABLE config ( key TEXT PRIMARY KEY, value TEXT );" # Insert configuration data into config table $SQL "INSERT INTO config (key, value) VALUES ('my_path', '$WHERE'), ('my_db', '$DB'), ('max_affairs', '$MAX_AFFAIRS');" # Define the triggers to drop entries exceeding max_affairs # # Define the trigger for INSERT $SQL "CREATE TRIGGER drop_on_insert AFTER INSERT ON $table FOR EACH ROW WHEN NEW.affairs >= CAST((SELECT value FROM config WHERE key = 'max_affairs') AS INTEGER) BEGIN UPDATE $table SET state = 'DROP', severity = 'Dropped', date_event = datetime(current_timestamp, 'localtime') WHERE IP = NEW.IP; END;" # Define the trigger for UPDATE $SQL "CREATE TRIGGER drop_on_update AFTER UPDATE ON $table FOR EACH ROW WHEN NEW.affairs >= CAST((SELECT value FROM config WHERE key = 'max_affairs') AS INTEGER) BEGIN UPDATE $table SET state = 'DROP', severity = 'Dropped', date_event = datetime(current_timestamp, 'localtime') WHERE IP = NEW.IP; END;" }