Postfix / Postscreen – add IP to the firewall


Robert Schetterer´s post (Botnet-Angriffe mit rsyslog und iptables recent module abwehren) to immediately add a IP by rsyslog to the firewall when they were rejected by postscreen has led me to present my solution here for syslog-ng.
I do not use a pipe, but contribute about syslog-ng the appropriate IP directly into the firewall.

The requirements are the same: Postfix/Postscreen and the recent-modul for iptables are mandatory. Because Robert documented this very well, I leave it out here. I have the principles already explained in my posts limit traffic on clamav-mirror and Block outdated clients regarding recent and in use postscreen to figth spam for postscreen.

After post screen and iptables have been setup accordingly, it is important to just make sure that syslog-ng reacts on matching log entries.

A typical log entry looks like this:

Feb 2 12:35:49 idefix.schaal-24.de postfix/postscreen[20189]: NOQUEUE: reject: RCPT from [1.2.3.4]:37669: 550 5.7.1 Service unavailable; client [1.2.3.4] blocked using bl.blocklist.de; from=, to=, proto=ESMTP, helo=

First we need a filter to parse for postfix/postscreen and ‘NOQUEUE reject’.

filter f_reject_mail {
  program('postfix/postscreen')
  and match('NOQUEUE: reject: RCPT from', value('MESSAGE'));
};

To get the IP from the logstring you can use the pattern-db (see below) or use two CSV-parser.
It´s not possible to use only one CSV-parser since you can´t split a logstring more than one time. Although you can use as a delimiter ‘:’, but that would prevent the blocking of IPv6 addresses. In the first step the (internal) logstring is changed to

[1.2.3.4]:37669:


parser p_reject_mail {
  csv-parser(columns(
    ".col1",
    ".col2",
    ".col3",
    ".col4",
    ".reject_ip_block")
  flags(escape-double-char,strip-whitespace)
  delimiters(" ")
  );
};

The second parser gets the IP-address:

parser p_reject_mail_get_ip {
  csv-parser(columns(
    ".reject_ip")
  quote-pairs('[]')
  delimiters(":")
  template("${.reject_ip_block}")
  );
};

Finally we use the destination to add the IP-Address to the firewall (postfix-reject is the jail):

destination d_reject_mail {
  file("/proc/net/xt_recent/postfix-reject"
  template("+${.mail.rejected.ip}\n"));
};

And that´s the log-statement for syslog-ng:

log {
  source(src);
  filter(f_reject_mail);
  parser(p_reject_mail);
  parser(p_reject_mail_get_ip);
  destination(d_reject_mail);
};

The blocks described above could also be excuted by postfix/smtpd:

Feb 3 10:56:03 idefix.schaal-24.de postfix/smtpd[3612]: NOQUEUE: reject: RCPT from xx-xxx-xx-xx.xx-xx.xx.net[1.2.3.4]: 554 5.7.1 : Recipient address rejected: Access denied; from= to= proto=SMTP helo=

As you can see, there is no significant difference. Through the first parser we get

xx-xxx-xx-xx.xx-xx.xx.net[1.2.3.4]:

And with the second parser the IP-address. To add such connects to the firewall too just expand the filter:

filter f_reject_mail {
  (program('postfix/postscreen') or
  program('postfix/smtpd'))
  and match('NOQUEUE: reject: RCPT from', value('MESSAGE'));
};

And here is the whole using the pattern-DB.
I think this is the better way – easier to setup respectively add to an existing pattern-DB und faster than CSV-Parser:

filter f_reject_mail {
  match("rejected" value(".classifier.class"))
  and match("12" value(".classifier.rule_id"))
  and tags("rejected");
};

destination d_reject_mail {
  file("/proc/net/xt_recent/postfix-reject"
  template("+${.mail.rejected.ip}\n"));
};

log {
  source(src);
  parser(pattern_db);
  filter(f_reject_mail);
  destination(d_reject_mail);
};

pattern-DB:


<?xml version='1.0' encoding='UTF-8'?>
<patterndb version="3" pub_date="2011-04-01">
<ruleset id='12' name='mail'>
  <pattern>postfix/postscreen</pattern>
  <pattern>postfix/smtpd</pattern>
  <rules>
    <rule class='rejected' id='12' provider='fs'>
      <patterns>
        <pattern>NOQUEUE: reject: RCPT from

[@IPv4:.mail.rejected.ip@]:@NUMBER@: 550</pattern>
        <pattern>NOQUEUE: reject: RCPT from

[@IPv6:.mail.rejected.ip@]:@NUMBER@: 550</pattern>
      </patterns>
      <tags>
        <tag>rejected</tag>
      </tags>
    </rule>
  </rules>
</ruleset>
</patterndb>

Leave a comment

Your email address will not be published. Required fields are marked *