# ##################### # Private WatchMX stuff # ##################### # # Settings & functions private to this module # # # Bump a culprit into database & firewall #---------------------------------------------------- # 'inject' is directly triggered from a rule that has # the global variable $RULE set when calling us. # So there is no need to pass $RULE to this function # # The global variable $REPLY holds the complete log line. # # All the dirty work is done here -- triggered by the rule. # inject() { local funtag="[${FUNCNAME[0]}]" local penalty=${1:-1} local retcode=0 #local affairs local isdropped local haveit this_ip this_state this_affairs this_severity trace "$funtag Triggered by rule [$RULE] '$Pattern'" # If BANDIT is determined by the preprocessor don't repeat here # BANDIT=`get_bandit` if ipset -q test whitelist "$BANDIT" then return 3 # Flag whitelisted IP address and bailout fi # # Check if we have a valid IP4 address # validate_IP "$BANDIT" if [ $? -ne 0 ] then trace "$funtag Got junk for $BANDIT ... bailing out ..." return 255 fi CLASS=`get_class $BANDIT` trace "$funtag $CLASS $BANDIT" # haveit=`$SQL "select IP from $TABLE where IP='$BANDIT';"` haveit=`$SQL "select IP,state,affairs,severity from $TABLE where IP='$BANDIT';"` if [ -n "$haveit" ] then IFS='|' read -r this_ip this_state this_affairs this_severity <<< "$haveit" fi # # Introduce bandit on first attempt ... Phase #1 # if [ -z "$haveit" ] then # Preset AFFAIRS for NXDOMAINS and FAKEHOSTS ... # NX domains have no business to do on MTAs and FAKEHOSTs are suspicious anyway. # These get their affairs set up at MAX_AFFAIRS-1; i.e. they die on 2nd attempt. # The first attempt is needed to identify and classify them. # They never reach a 'COUNT' state ... if [[ "NXDOMAIN FAKEHOST" =~ "$CLASS" ]] # then penalty=$(( $MAX_AFFAIRS - 1 )) then penalty=$(( $MAX_AFFAIRS )) fi AFFAIRS=$penalty if [ ! -z "$GEOTRACK" ] then do_geotrack $BANDIT $ME fi # First drop into the IPset ... $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "tarpit,$THIS_TYPE,$AFFAIRS" STATE='INTRO' ACTION="Initial $AFFAIRS/$MAX_AFFAIRS, Penalty: $penalty" $SQL "insert into $TABLE (IP,origin,rule,class,state,severity,affairs,type,date_intro,date_event) values ('$BANDIT','$ME','$RULE','$CLASS','$STATE','Initial',$AFFAIRS,'$THIS_TYPE', datetime(current_timestamp,'localtime'), datetime(current_timestamp,'localtime') );" retcode=1 else # IP address already known ... Phase #2 # isdropped=`$SQL "select IP from $TABLE where IP='$BANDIT' and state='DROP';"` isdropped="$this_state" if [ ! -z "$isdropped" ] then $IPSET -exist add custody $BANDIT comment "custody,$THIS_TYPE,$CLASS" trace "$funtag DROPed culprit $BANDIT re-occured ... taken into custody ..." return 1 # short way out fi # # Bandit returned repeatedly ... count-up affairs ... # # AFFAIRS=`$SQL "select affairs from $TABLE where IP='$BANDIT';"` AFFAIRS=$this_affairs if [ $AFFAIRS -lt $MAX_AFFAIRS ] then ((AFFAIRS++)) # IPset first ... before DB action $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "tarpit,$THIS_TYPE,$AFFAIRS" STATE='COUNT' ACTION="Count $AFFAIRS/$MAX_AFFAIRS" $SQL "update $TABLE set affairs=$AFFAIRS, origin='$ME', state='$STATE',severity='Counted', rule='$RULE', date_event=datetime(current_timestamp,'localtime') where IP='$BANDIT';" retcode=1 else # Drop the beast ... Phase #3, state transition to DROP # IPset first ... before DB update $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "tarpit,$THIS_TYPE,$AFFAIRS" STATE='DROP' ACTION="Dropped @ $AFFAIRS" $SQL "update $TABLE set affairs=$MAX_AFFAIRS, origin='$ME', state='$STATE', severity='Dropped', rule='$RULE', date_event=datetime(current_timestamp,'localtime') where IP='$BANDIT';" retcode=1 fi fi write_affairs $BANDIT $AFFAIRS $RULE $ME #log "$funtag $CLASS $BANDIT - Rule: $RULE, Action: $ACTION" clog "$funtag" "$CLASS" "$BANDIT" "'$ACTION'" "'$RULE'" trace "$funtag $CLASS $BANDIT '$ACTION'" return $retcode } write_affairs() { local useconds=`date +%s%6N` $SQL "insert into affairs_by_ip (ip_addr, affair_num, rule, event_date, time_useconds, origin) VALUES ('$1',$2,'$3', datetime(current_timestamp,'localtime'), $useconds, '$4');" } # Forward a log line to the WatchMB scanner passon() { local funtag="[${FUNCNAME[0]}]" echo "$REPLY" >> $FIFO_BASE/WatchMB trace "$funtag Passed to WatchMB ..." } # # Kick off a bandit w/o further discussion # for known nasty badfingers # kickoff() { local funtag="[${FUNCNAME[0]}]" local penalty=$MAX_AFFAIRS local affairs=$penalty local haveit trace "$funtag, $BANDIT, $RULE, '$Pattern'" # Put into custody first .. ipset -exist add custody $BANDIT comment "$funtag,$THIS_TYPE,$CLASS" # ... then nail it into the database haveit=`$SQL "select IP from $TABLE where IP='$BANDIT';"` if [ -z "$haveit" ] then STATE=DROP ACTION="$funtag $AFFAIRS/$MAX_AFFAIRS, Penalty: $penalty" $SQL "insert into $TABLE (IP,origin,rule,class,state,severity,affairs,type,date_intro,date_event) values ('$BANDIT','$ME','$RULE','$CLASS','$STATE',$funtag,$affairs,'$THIS_TYPE', datetime(current_timestamp,'localtime'), datetime(current_timestamp,'localtime') );" else STATE=DROP ACTION="Kicked off $AFFAIRS/$MAX_AFFAIRS" $SQL "update $TABLE set affairs=$affairs, origin='$ME', state='$STATE',severity='$funtag', rule='$RULE', date_event=datetime(current_timestamp,'localtime') where IP='$BANDIT';" fi return 1 # Let post processor know }