pf blacklisting IPs of spammers

rspamd is great, but it works the system. When a spammer sends a lot of email, rspamd has to scan every one of them. Better to block the spammer outright.

#!    /usr/local/bin/fish

#    spam_block.sh
#    reads mail messages in Junk folders of selected accounts, scans for originating IP
#    addresses, then adds those IPs to afctl blacklist
#    Robb Allan, July 2018

source /root/spam_library.sh

set LOGFILE /var/log/spam_block.log
set BLACKLIST_FILE /usr/local/etc/pf/blacklist
set TMP_FILE /tmp/11111
set TMP_FILE2 /tmp/22222
set TARGET_USERS <some users>

function pf_echo ()
    /bin/echo (/bin/date "+%b %e %T") $argv >> $LOGFILE
end

function replace_blacklist ()
    pf_echo "replacing blacklist..."
    /sbin/pfctl -t blacklist -T replace -f /usr/local/etc/pf/blacklist >> $LOGFILE
end

function add_IPs_to_pf_blacklist ()
    if test -e $BLACKLIST_FILE
        /bin/cp $BLACKLIST_FILE {$BLACKLIST_FILE}.(date -j "+%Y%m%d.%H%M")
        /bin/cat $BLACKLIST_FILE >> $TMP_FILE
    end

    /usr/bin/sort -n $TMP_FILE | /usr/bin/uniq > {$TMP_FILE}.2
    /usr/bin/grep -v -e "255.255.255.255" -e "0.0.0.*" -e "127.0.0.1" -e "1.800*" -e "1.81*" {$TMP_FILE}.2 > $TMP_FILE
    /usr/bin/sed -e "s/\.0\([^\.]\)/\.\1/g" {$TMP_FILE} > $BLACKLIST_FILE
    /bin/chmod a+w $BLACKLIST_FILE
end

if test (count $argv) -eq 1 
    switch $argv
    case "--refresh"
        pf_echo "running spam_block in refresh mode..." && replace_blacklist

    case "--update"
        pf_echo "running spam_block in update mode..."
        
        /bin/rm $TMP_FILE $TMP_FILE2 2>>/dev/null
        
        for aUser in $TARGET_USERS
            pf_echo "collecting IPs from user $aUser."
            goto_user_junkmail_directory $aUser > /dev/null
            set TARGET_DIR (/bin/pwd)

            for aFile in (/usr/bin/find {$TARGET_DIR} -type f -a -mmin -700)
                cat $aFile | /usr/bin/sed -nEe 's/.*[^0-9]([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p' >> $TMP_FILE
            end
        end

        add_IPs_to_pf_blacklist && replace_blacklist
        /bin/rm $TMP_FILE $TMP_FILE2 2>>/dev/null

        pf_echo "done"

    case "--fullupdate"
        pf_echo "running spam_block in update mode..."
        
        /bin/rm $TMP_FILE $TMP_FILE2 2>>/dev/null
        
        for aUser in $TARGET_USERS
            pf_echo "collecting IPs from user $aUser."
            goto_user_junkmail_directory $aUser > /dev/null
            set TARGET_DIR (/bin/pwd)

            for aFile in (ls)
                cat $aFile | /usr/bin/sed -nEe 's/.*[^0-9]([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p' >> $TMP_FILE
            end
        end

        add_IPs_to_pf_blacklist && replace_blacklist
        /bin/rm $TMP_FILE $TMP_FILE2 2>>/dev/null

        pf_echo "done"

    case "*"
        /bin/echo "unknown argument(s): \"" $argv "\""
    end

else 
      /bin/echo "spam_block requires an argument."
      /bin/echo "Usage: spam_block [--refresh | --update | --fullupdate ]"
end

Run this script with one of the following arguments:

  • "--update": reloads the pf blacklist.
  • "--refresh": scans the junkmail directory of Maildir, collects the source IP of each email, sort's and uniq's them, adds them to the pf blacklist file, and reloads pf.
  • "--fullupdate": does the same thing as --update.