Sven Schwedas wrote in
 <1d9d281d-de64-8299-2bed-35fc9889f...@tao.at>:
 |
 |> What is the recommended way to combat this behavior?
 |
 |I'd personally lean towards fail2ban or comparable solutions to 
 |aggregate Rejects with other suspicious behaviour on other ports and 
 |react with system-wide IP bans.
 |
 |Fail2ban e.g. has examples for catching REJECTs in its wiki: 
 |http://www.fail2ban.org/wiki/index.php/Postfix
 |Plus built-in modules to handle Postfix SASL login failures and others. 
 |I expect the competition is doing the same.

I use firewall rules to assign traffic control dependent on the
hit count

   if fwcore_has_i smtp || fwcore_has_i smtps || fwcore_has_i submission; then
      change_chain i__smtp

      if [ -n "${FWCORE_SMTPX_NOLIMIT_PEERS}" ]; then
         for i in ${FWCORE_SMTPX_NOLIMIT_PEERS}; do

Whitelisting some which contribute most to my traffic.
Whitelisted also in graylist.  (I hate i need two different
lists.)

            if ipaddr_split a "${i}"; then
               if fwcore_has_i smtp; then
                  [ -z "${port}" -o "${port}" = smtp ] &&
                     add_rule -p tcp --src ${addr}${mask} \
                        --dport ${p_smtp} -m limit --limit 60/m -j f_m0_2
               fi
               if fwcore_has_i smtps; then
                  [ -z "${port}" -o "${port}" = smtps ] &&
                     add_rule -p tcp --src ${addr}${mask} \
                        --dport ${p_smtps} -m limit --limit 60/m -j f_m0_2
               fi
               #if fwcore_has_i submission; then
               #   [ -z "${port}" -o "${port}" = submission ] &&
               #      add_rule -p tcp --src ${addr}${mask} \
               #         --dport ${p_smtps} -m limit --limit 60/m -j f_m0_2
               #fi
            fi
         done
      fi

      #-m recent --name alien --set
      # Alienization now handled by cron-parse-mail.awk
      #   -m recent --name alien --set
      add_rule -m recent --name smtp --set \
         -m recent --name smtp ! --rcheck --seconds 600 --reap --hitcount 20 \
         -j f_m2
      add_rule -m recent --name smtp --rcheck --seconds 120 --hitcount 16 \
         -j f_m5
      add_rule -m recent --name smtp ! --rcheck --hitcount 32 -j f_m3
      add_rule -j f_m5
   fi

f_m2 is second best (VPN and ssh are best), f_m5 is the slowest
that is possible (1 percent of "max").  Ie conn/marks are set,
traffic control is applied. 
(This is a private server with only a high 3-digit number of
messages a day, the remains is noise.)

There are "alien"s which seem strange, and after appearing like
this multiple times they become "super_alien"s which are blocked
for quite some hours.  I found it impossible, really, to do this
automatically from within the firewall for SMTP (and HTTP),
because the firewall just does not know enough to make a decision.
Therefore i had to bite the bullet and finally wrote a primitive
log parser:

  #!/usr/bin/awk -f
  #@ Parse postfix log output, as via
  #@    exec /root/bin/cron-parse-mail.awk < /var/log/mail

  # DEBUG: 1=logger(1), >1=SANDBOX
  BEGIN{ DEBUG = 0; sl = ""; xl = "" }

  function doit(line){
     if((i = match(line, "\\[[^]]+\\]$")) != 0){
        j = substr(line, i + 1)
        j = substr(j, 1, length(j) - 1)

        if(!drops[j]){
           i = maydrops[j]
           if(!i)
              i = 0
           else if(i >= 2){
              drops[j] = 1
              if((i = match(line, " [^ ]+$")) != 0)
                 j = substr(line, i + 1)
              if(sl)
                 sl = sl " "
              sl = sl j
              return
           }
           maydrops[j] = ++i
        }
     }
  }

  # To avoid that "unknown" that tries evil is not blocked because we think
  # it is only a local DNS error, treat logins special
  /too many errors after AUTH from.+\[/ {doit($0); next;} # ]
  /SSL_accept error from.+\[/ { # ]
     line = $0
     if((i = match(line, ": -?[[:alnum:]]+$")) != 0)
        line = substr(line, 1, i - 1)
     doit(line)
     next
  }

  /too many errors.+from unknown\[/{
     if((i = match($0, "\\[[^]]+\\]$")) != 0){
        j = substr($0, i + 1)
        j = substr(j, 1, length(j) - 1)

        if(unign[j])
           next

        if(!drops[j]){
           i = maydrops[j]
           if(!i)
              i = 0
           else if(i >= 2){
              # Could be local resolver error, try this first

This only because my ISP gives me bind and powerdns via two
different IPs after bind alone started producing errors after
i have finally turned on dnssec in my dnsmasq cache.
Ie bind failed a lot for FreeBSD (maybe truncation i have no
idea), and the other fails for other things (i am no longer
looking), anyhow if all else fails we check Google DNS.

              if(DEBUG > 1)
                 es = 1
              else
                 es = system("{ command -v host && \
                       host " j " 8.8.8.8 || \
                       nslookup " j " 8.8.8.8; } >/dev/null 2>&1")
              if(es == 0){
                 unign[j] = 1
                 if(xl)
                    xl = xl " "
                 xl = xl j
              }else
                 drops[j] = 1
              next
           }
           maydrops[j] = ++i
        }
     }
     next
  } # vim ]

  # nawk cannot escape newlines
  /too many errors after (EHLO|END-OF-MESSAGE|HELO|STARTTLS|UNKNOWN) from.+\[/{

Note i removed RCPT| because of gray listing, and RCPT just does
not occur here for any other reason.
(I have super low error counts.)

     doit($0)
  } # vim ]

  END{
     dropno = 0
     ipl = ""
     for(ip in drops){
        if(!drops[ip])
           continue
        ++dropno
        ipl = ipl " " ip
     }

     if(dropno > 0){
        if(DEBUG > 1)
           print "/root/bin/net-qos.sh add alien_super " ipl
        else
           system("/root/bin/net-qos.sh add alien_super " ipl)

        if(DEBUG > 0){
           if(sl)
              sl = "; Named: " sl
           if(xl)
              xl = "; local DNS error: " xl
           if(DEBUG > 1)
              print "logger -t /root/bin/cron-parse-mail.awk '" dropno \
                 " aliens" sl xl "'"
           else
              system("logger -t /root/bin/cron-parse-mail.awk '" dropno \
                 " aliens" sl xl "'")
        }
     }
  }

  # s-sh-mode

It is primitive as it does not sit on the thing with inotify or
similar mechanism, and then only parses new stuff, but always
reads the entire file.  But the logs get rotated when the file
reaches 200 KiB so awk processes these small files fast (real 0m
0.03s even on that vserver), and no bad effect there is.  It runs
several times an hour.  Works for me.

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)

Reply via email to