Merge tag 'upstream/1.35'

Upstream version 1.35
This commit is contained in:
Jan Wagner 2013-11-05 17:33:54 +01:00
commit cf9402a5ac
11 changed files with 1565 additions and 1684 deletions

View file

@ -1,3 +1,41 @@
1.35
====
- code: rate(), size() and rcpt() function index is now case insensitive by default
(same limit counters for from@example.org and fRom@eXample.org)
if you need to treat the localpart case-sensitive according to rfc5321
you may use rate5321(), size5321() and rcpt5321()
1.34
====
- bugfix: fixed taint mode logging error for verbose --showconfig and --stdoutlog
options and newer perl versions.
- bugfix: check_* functions use print/getline instead of send/recv for large
--dumpcache output (thanks to Alexandre Simon)
- code: log_* routines added to allow the same plugins for postfwd1 and postfwd2
- code: added more information when using --debug=cleanup
- docs: documentation updates
- feature: new sendmail(sendmail-path::from::to::subject::body) action.
Please take a look at the manual, especially about
it's limitations, before using it!
------------------------------------------------------------
# alert
action=sendmail(/usr/sbin/sendmail::from@example.org::to@example.org::Subject::Text)
------------------------------------------------------------
1.33
====
- feature: new compare operators *
====================================================================
*ITEM > VALUE true if ITEM > VALUE
*ITEM < VALUE true if ITEM < VALUE
====================================================================
- bugfix: fixed bug when computing scores with more than 1 digit after the "." (n.nn)
- bugfix: fixed bug when computing negative values with the set action
- bugfix: ITEMS plugins returning zero values were handled incorrectly
- bugfix: max command recursion was not reset for each rule
1.32
====
- feature: new option --save_rates=<file> allows to load and save

View file

@ -1,14 +1,18 @@
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>postfwd - postfix firewall daemon</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:root@localhost" />
</head>
<body style="background-color: white">
<p><a name="__index__"></a></p>
<!-- INDEX BEGIN -->
<div name="index">
<p><a name="__index__"></a></p>
<ul>
@ -37,9 +41,11 @@
<li><a href="#license">LICENSE</a></li>
<li><a href="#author">AUTHOR</a></li>
</ul>
<hr name="index" />
</div>
<!-- INDEX END -->
<hr />
<p>
</p>
<h1><a name="name">NAME</a></h1>
@ -111,7 +117,8 @@
--config_timeout &lt;i&gt; parser timeout in seconds
--keep_rates do not clear rate limit counters on reload
--save_rates &lt;file&gt; save and load rate limits on disk
--fast_limit_evaluation evaluate rate limits before ruleset is parsed</pre>
--fast_limit_evaluation evaluate rate limits before ruleset is parsed
(please note the limitations)</pre>
<pre>
Plugins:
--plugins &lt;file&gt; loads postfwd plugins from file</pre>
@ -165,6 +172,8 @@ is not important. So the following would lead to the same result as the previous
ITEM == VALUE true if ITEM equals VALUE
ITEM =&gt; VALUE true if ITEM &gt;= VALUE
ITEM =&lt; VALUE true if ITEM &lt;= VALUE
ITEM &gt; VALUE true if ITEM &gt; VALUE
ITEM &lt; VALUE true if ITEM &lt; VALUE
ITEM =~ VALUE true if ITEM ~= /^VALUE$/i
ITEM != VALUE false if ITEM equals VALUE
ITEM !&gt; VALUE false if ITEM &gt;= VALUE
@ -442,7 +451,7 @@ necessary. Of course this might increase the system load, so please use it with
<pre>
-- FILE /etc/postfwd/clients_west.cf --
192.168.3.0/24</pre>
<p>Remind that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
<p>Note that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
with postfwd1 v1.15 and postfwd2 v0.18 and higher.</p>
<p>
</p>
@ -456,7 +465,7 @@ request attributes by preceeding $$ characters, like:</p>
id=R-003; client_name = !!$$helo_name; action=WARN helo '$$(helo_name)' does not match DNS '$$(client_name)'</pre>
<p><em>postfix actions</em></p>
<p>Actions will be replied to postfix as result to policy delegation requests. Any action that postfix understands is allowed - see
``man 5 access'' or <a href="http://www.postfix.org/access.5.html">http://www.postfix.org/access.5.html</a> for a description. If no action is specified, the postfix WARN action
&quot;man 5 access&quot; or <a href="http://www.postfix.org/access.5.html">http://www.postfix.org/access.5.html</a> for a description. If no action is specified, the postfix WARN action
which simply logs the event will be used for the corresponding rule.</p>
<p>postfwd will return dunno if it has reached the end of the ruleset and no rule has matched. This can be changed by placing a last
rule containing only an action statement:</p>
@ -494,7 +503,7 @@ rule containing only an action statement:</p>
this command creates a counter for the given &lt;item&gt;, which will be increased any time a request
containing it arrives. if it exceeds &lt;max&gt; within &lt;time&gt; seconds it will return &lt;action&gt; to postfix.
rate counters are very fast as they are executed before the ruleset is parsed.
please note that &lt;action&gt; is currently limited to postfix actions (no postfwd actions)!
please note that &lt;action&gt; was limited to postfix actions (no postfwd actions) for postfwd versions &lt;1.33!
# no more than 3 requests per 5 minutes
# from the same &quot;unknown&quot; client
id=RATE01 ; client_name==unknown
@ -525,6 +534,11 @@ rule containing only an action statement:</p>
# recipient count limit 3 per hour per client
id=RCPT01 ; protocol_state==END-OF-MESSAGE ; client_address!=10.1.1.1
action=rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)</pre>
<pre>
rate5321,size5321,rcpt5321 (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;)
same as the corresponding non-5321 functions, with the difference that the localpart of
sender oder recipient addresses are evaluated case-sensitive according to rfc5321. That
means that requests from bob@example.local and BoB@example.local will be treated differently</pre>
<pre>
ask (&lt;addr&gt;:&lt;port&gt;[:&lt;ignore&gt;])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first
@ -537,9 +551,15 @@ rule containing only an action statement:</p>
id=GREY; client_address==10.1.1.1; action=ask(127.0.0.1:10031:^dunno$)</pre>
<pre>
mail(server/helo/from/to/subject/body)
This command is deprecated. You should try to use the sendmail() action instead.
Very basic mail command, that sends a message with the given arguments. LIMITATIONS:
This basically performs a telnet. No authentication or TLS are available. Additionally it does
not track notification state and will notify you any time, the corresponding rule hits.</pre>
<pre>
sendmail(sendmail-path::from::to::subject::body)
Mail command, that uses an existing sendmail binary and sends a message with the given arguments.
LIMITATIONS: The command does not track notification state and will notify you any time, the
corresponding rule hits (which could mean 100 mails for a mail with 100 recipients at RCPT stage).</pre>
<pre>
wait (&lt;delay&gt;)
pauses the program execution for &lt;delay&gt; seconds. use this for
@ -680,6 +700,10 @@ will be used.</p>
$myresult = ($myitem &lt;= $val);
} elsif ($cmp eq '=&gt;') {
$myresult = ($myitem &gt;= $val);
} elsif ($cmp eq '&lt;') {
$myresult = ($myitem &lt; $val);
} elsif ($cmp eq '&gt;') {
$myresult = ($myitem &gt; $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!&lt;') {
@ -709,15 +733,15 @@ continue or to stop parsing the ruleset.</p>
# note(&lt;logstring&gt;) command
&quot;note&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
mylogs 'info', &quot;[RULES] &quot;.$myline.&quot; - note: &quot;.$myarg if $myarg;
my($myaction) = 'dunno'; my($stop) = 0;
log_info &quot;[RULES] &quot;.$myline.&quot; - note: &quot;.$myarg if $myarg;
return ($stop,$index,$myaction,$myline,%request);
},
# skips next &lt;myarg&gt; rules
&quot;skip&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
my($myaction) = 'dunno'; my($stop) = 0;
$index += $myarg if ( $myarg and not(($index + $myarg) &gt; $#Rules) );
return ($stop,$index,$myaction,$myline,%request);
},
@ -725,8 +749,8 @@ continue or to stop parsing the ruleset.</p>
# dumps current request contents to syslog
&quot;dumprequest&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
map { mylogs 'info', &quot;[DUMP] rule=$index, Attribute: $_=$request{$_}&quot; } (keys %request);
my($myaction) = 'dunno'; my($stop) = 0;
map { log_info &quot;[DUMP] rule=$index, Attribute: $_=$request{$_}&quot; } (keys %request);
return ($stop,$index,$myaction,$myline,%request);
},</pre>
<pre>
@ -979,7 +1003,10 @@ The following arguments will control it's behaviour in this case.</p>
Once a ratelimit was set by the ruleset, future requests will be evaluated against it
before consulting the ruleset. This mode was the default behaviour until v1.30.
With this mode rate limits will be faster, but also eventually set up
whitelisting-rules within the ruleset might not work as expected.</pre>
whitelisting-rules within the ruleset might not work as expected.
LIMITATIONS: This option does not allow nested postfwd commands like
action=rate(sender/3/60/wait(3))
This option doe not work with the strict-rfc5321 rate() functions.</pre>
<p><em>Informational arguments</em></p>
<p>These arguments are for command line usage only. Never ever use them with postfix spawn!</p>
<pre>
@ -1193,7 +1220,7 @@ check the parser with the -C | --showconfig switch at the command line before ap
Rule 0: id-&gt;&quot;RBL001&quot;; action-&gt;&quot;REJECT listed on spamcop and bad rdns&quot;; rbl-&gt;&quot;bl.spamcop.net&quot;; client_name-&gt;&quot;^unknown$&quot;</pre>
<p><em>Request processing</em></p>
<p>When a policy delegation request arrives it will be compared against postfwd`s ruleset. To inspect the processing in detail you should increase
verbority using use the ``-v'' or ``-vv'' switch. ``-L'' redirects log messages to stdout.</p>
verbority using use the &quot;-v&quot; or &quot;-vv&quot; switch. &quot;-L&quot; redirects log messages to stdout.</p>
<p>Keeping the order of the ruleset in general, items will be compared in random order, which basically means that</p>
<pre>
id=R001; action=dunno; client_address=192.168.1.1; sender=bob@alice.local</pre>
@ -1232,7 +1259,7 @@ to compare against the request attribute the parser will jump to the next rule i
<p>If a rule matches, there are two options:</p>
<p>* Rule returns postfix action (dunno, reject, ...)
The parser stops rule processing and returns the action to postfix. Other rules will not be evaluated.</p>
<p>* Rule returns postfwd action (jump(), note(), ...)
<p>* Rule returns postfwd action (jump(), <code>note()</code>, ...)
The parser evaluates the given action and continues with the next rule (except for the <code>jump()</code> or <code>quit()</code> actions - please see the <a href="#actions">ACTIONS</a> section
for more information). Nothing will be sent to postfix.</p>
<p>If no rule has matched and the end of the ruleset is reached postfwd will return dunno without logging anything unless in verbose mode. You may
@ -1252,7 +1279,7 @@ it`s internal caching in that case. Start postfwd with the following parameters:
postfwd -d -f /etc/postfwd.cf -i 127.0.0.1 -p 10040 -u nobody -g nobody -S</pre>
<p>For efficient caching you should check if you can use the options --cache-rdomain-only, --cache-no-sender
and --cache-no-size.</p>
<p>Now check your syslogs (default facility ``mail'') for a line like:</p>
<p>Now check your syslogs (default facility &quot;mail&quot;) for a line like:</p>
<pre>
Aug 9 23:00:24 mail postfwd[5158]: postfwd n.nn ready for input</pre>
<p>and use `netstat -an|grep 10040` to check for something like</p>
@ -1307,7 +1334,7 @@ I won`t discuss that here. If you plan to do so, just add the following line to
disable = no
}</pre>
<p>and restart the xinetd daemon (usually a SIGHUP should be fine). If you experience problems
you might want to check your system's log for xinetd errors like ``socket already in use''.</p>
you might want to check your system's log for xinetd errors like &quot;socket already in use&quot;.</p>
<p>The integration with postfix is similar to the <em>Integration via daemon mode</em> section above.
Reload postfix and watch your logs to see if everything works.</p>
<p>

View file

@ -66,6 +66,7 @@ SYNOPSIS
--keep_rates do not clear rate limit counters on reload
--save_rates <file> save and load rate limits on disk
--fast_limit_evaluation evaluate rate limits before ruleset is parsed
(please note the limitations)
Plugins:
--plugins <file> loads postfwd plugins from file
@ -133,6 +134,8 @@ DESCRIPTION
ITEM == VALUE true if ITEM equals VALUE
ITEM => VALUE true if ITEM >= VALUE
ITEM =< VALUE true if ITEM <= VALUE
ITEM > VALUE true if ITEM > VALUE
ITEM < VALUE true if ITEM < VALUE
ITEM =~ VALUE true if ITEM ~= /^VALUE$/i
ITEM != VALUE false if ITEM equals VALUE
ITEM !> VALUE false if ITEM >= VALUE
@ -457,7 +460,7 @@ DESCRIPTION
-- FILE /etc/postfwd/clients_west.cf --
192.168.3.0/24
Remind that there is currently no loop detection (/a/file calls /a/file)
Note that there is currently no loop detection (/a/file calls /a/file)
and that this feature is only available with postfwd1 v1.15 and postfwd2
v0.18 and higher.
@ -520,7 +523,7 @@ DESCRIPTION
this command creates a counter for the given <item>, which will be increased any time a request
containing it arrives. if it exceeds <max> within <time> seconds it will return <action> to postfix.
rate counters are very fast as they are executed before the ruleset is parsed.
please note that <action> is currently limited to postfix actions (no postfwd actions)!
please note that <action> was limited to postfix actions (no postfwd actions) for postfwd versions <1.33!
# no more than 3 requests per 5 minutes
# from the same "unknown" client
id=RATE01 ; client_name==unknown
@ -552,6 +555,11 @@ DESCRIPTION
id=RCPT01 ; protocol_state==END-OF-MESSAGE ; client_address!=10.1.1.1
action=rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
rate5321,size5321,rcpt5321 (<item>/<max>/<time>/<action>)
same as the corresponding non-5321 functions, with the difference that the localpart of
sender oder recipient addresses are evaluated case-sensitive according to rfc5321. That
means that requests from bob@example.local and BoB@example.local will be treated differently
ask (<addr>:<port>[:<ignore>])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first
and the second argument (address and port) are mandatory. a third optional argument may be
@ -563,10 +571,16 @@ DESCRIPTION
id=GREY; client_address==10.1.1.1; action=ask(127.0.0.1:10031:^dunno$)
mail(server/helo/from/to/subject/body)
This command is deprecated. You should try to use the sendmail() action instead.
Very basic mail command, that sends a message with the given arguments. LIMITATIONS:
This basically performs a telnet. No authentication or TLS are available. Additionally it does
not track notification state and will notify you any time, the corresponding rule hits.
sendmail(sendmail-path::from::to::subject::body)
Mail command, that uses an existing sendmail binary and sends a message with the given arguments.
LIMITATIONS: The command does not track notification state and will notify you any time, the
corresponding rule hits (which could mean 100 mails for a mail with 100 recipients at RCPT stage).
wait (<delay>)
pauses the program execution for <delay> seconds. use this for
delaying or throtteling connections.
@ -724,6 +738,10 @@ DESCRIPTION
$myresult = ($myitem <= $val);
} elsif ($cmp eq '=>') {
$myresult = ($myitem >= $val);
} elsif ($cmp eq '<') {
$myresult = ($myitem < $val);
} elsif ($cmp eq '>') {
$myresult = ($myitem > $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!<') {
@ -755,15 +773,15 @@ DESCRIPTION
# note(<logstring>) command
"note" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
mylogs 'info', "[RULES] ".$myline." - note: ".$myarg if $myarg;
my($myaction) = 'dunno'; my($stop) = 0;
log_info "[RULES] ".$myline." - note: ".$myarg if $myarg;
return ($stop,$index,$myaction,$myline,%request);
},
# skips next <myarg> rules
"skip" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
my($myaction) = 'dunno'; my($stop) = 0;
$index += $myarg if ( $myarg and not(($index + $myarg) > $#Rules) );
return ($stop,$index,$myaction,$myline,%request);
},
@ -771,8 +789,8 @@ DESCRIPTION
# dumps current request contents to syslog
"dumprequest" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
map { mylogs 'info', "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
my($myaction) = 'dunno'; my($stop) = 0;
map { log_info "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
return ($stop,$index,$myaction,$myline,%request);
},
@ -1038,6 +1056,9 @@ DESCRIPTION
before consulting the ruleset. This mode was the default behaviour until v1.30.
With this mode rate limits will be faster, but also eventually set up
whitelisting-rules within the ruleset might not work as expected.
LIMITATIONS: This option does not allow nested postfwd commands like
action=rate(sender/3/60/wait(3))
This option doe not work with the strict-rfc5321 rate() functions.
*Informational arguments*

View file

@ -1,3 +1,41 @@
postfwd2 1.35
=============
- code: rate(), size() and rcpt() function index is now case insensitive by default
(same limit counters for from@example.org and fRom@eXample.org)
if you need to treat the localpart case-sensitive according to rfc5321
you may use rate5321(), size5321() and rcpt5321().
- bugfix: fixed segfault when using new perl versions (prevented to work with upstart)
postfwd2 1.34
=============
- bugfix: fixed taint mode logging error for verbose --showconfig and --stdoutlog
options and newer perl versions.
- bugfix: check_* functions use print/getline instead of send/recv for large
--dumpcache output (thanks to Alexandre Simon)
- code: added more information when using --debug=cleanup
- docs: documentation updates
- feature: new sendmail(sendmail-path::from::to::subject::body) action.
Please take a look at the manual, especially about
it's limitations, before using it!
------------------------------------------------------------
# alert
action=sendmail(/usr/sbin/sendmail::from@example.org::to@example.org::Subject::Text)
------------------------------------------------------------
postfwd2 1.33
=============
- feature: new compare operators *
====================================================================
ITEM > VALUE true if ITEM > VALUE
ITEM < VALUE true if ITEM < VALUE
====================================================================
- bugfix: fixed bug when computing scores with more than 1 digit after the "." (n.nn)
- bugfix: fixed bug when computing negative values with the set action
- bugfix: ITEMS plugins returning zero values were handled incorrectly
- bugfix: max command recursion was not reset for each rule
- bugfix: fixed warning about use of (uninitialized value) when STORABLE is available
but no cache file was defined
postfwd2 1.32
=============
- feature: new option --save_rates=<file> allows to load and save

View file

@ -1,14 +1,18 @@
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>postfwd2 - postfix firewall daemon</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:root@localhost" />
</head>
<body style="background-color: white">
<p><a name="__index__"></a></p>
<!-- INDEX BEGIN -->
<div name="index">
<p><a name="__index__"></a></p>
<ul>
@ -38,9 +42,11 @@
<li><a href="#license">LICENSE</a></li>
<li><a href="#author">AUTHOR</a></li>
</ul>
<hr name="index" />
</div>
<!-- INDEX END -->
<hr />
<p>
</p>
<h1><a name="name">NAME</a></h1>
@ -125,7 +131,8 @@
--config_timeout &lt;i&gt; parser timeout in seconds
--keep_rates do not clear rate limit counters on reload
--save_rates &lt;file&gt; save and load rate limits on disk
--fast_limit_evaluation evaluate rate limits before ruleset is parsed</pre>
--fast_limit_evaluation evaluate rate limits before ruleset is parsed
(please note the limitations)</pre>
<pre>
Plugins:
--plugins &lt;file&gt; loads postfwd plugins from file</pre>
@ -194,6 +201,8 @@ is not important. So the following would lead to the same result as the previous
ITEM == VALUE true if ITEM equals VALUE
ITEM =&gt; VALUE true if ITEM &gt;= VALUE
ITEM =&lt; VALUE true if ITEM &lt;= VALUE
ITEM &gt; VALUE true if ITEM &gt; VALUE
ITEM &lt; VALUE true if ITEM &lt; VALUE
ITEM =~ VALUE true if ITEM ~= /^VALUE$/i
ITEM != VALUE false if ITEM equals VALUE
ITEM !&gt; VALUE false if ITEM &gt;= VALUE
@ -471,7 +480,7 @@ necessary. Of course this might increase the system load, so please use it with
<pre>
-- FILE /etc/postfwd/clients_west.cf --
192.168.3.0/24</pre>
<p>Remind that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
<p>Note that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
with postfwd1 v1.15 and postfwd2 v0.18 and higher.</p>
<p>
</p>
@ -485,7 +494,7 @@ request attributes by preceeding $$ characters, like:</p>
id=R-003; client_name = !!$$helo_name; action=WARN helo '$$(helo_name)' does not match DNS '$$(client_name)'</pre>
<p><em>postfix actions</em></p>
<p>Actions will be replied to postfix as result to policy delegation requests. Any action that postfix understands is allowed - see
``man 5 access'' or <a href="http://www.postfix.org/access.5.html">http://www.postfix.org/access.5.html</a> for a description. If no action is specified, the postfix WARN action
&quot;man 5 access&quot; or <a href="http://www.postfix.org/access.5.html">http://www.postfix.org/access.5.html</a> for a description. If no action is specified, the postfix WARN action
which simply logs the event will be used for the corresponding rule.</p>
<p>postfwd2 will return dunno if it has reached the end of the ruleset and no rule has matched. This can be changed by placing a last
rule containing only an action statement:</p>
@ -523,7 +532,7 @@ rule containing only an action statement:</p>
this command creates a counter for the given &lt;item&gt;, which will be increased any time a request
containing it arrives. if it exceeds &lt;max&gt; within &lt;time&gt; seconds it will return &lt;action&gt; to postfix.
rate counters are very fast as they are executed before the ruleset is parsed.
please note that &lt;action&gt; is currently limited to postfix actions (no postfwd actions)!
please note that &lt;action&gt; was limited to postfix actions (no postfwd actions) for postfwd versions &lt;1.33!
# no more than 3 requests per 5 minutes
# from the same &quot;unknown&quot; client
id=RATE01 ; client_name==unknown
@ -545,6 +554,11 @@ rule containing only an action statement:</p>
# recipient count limit 3 per hour per client
id=RCPT01 ; protocol_state==END-OF-MESSAGE ; client_address==!!(10.1.1.1)
action=rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)</pre>
<pre>
rate5321,size5321,rcpt5321 (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;)
same as the corresponding non-5321 functions, with the difference that the localpart of
sender oder recipient addresses are evaluated case-sensitive according to rfc5321. That
means that requests from bob@example.local and BoB@example.local will be treated differently</pre>
<pre>
ask (&lt;addr&gt;:&lt;port&gt;[:&lt;ignore&gt;])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first
@ -557,9 +571,15 @@ rule containing only an action statement:</p>
id=GREY; client_address==10.1.1.1; action=ask(127.0.0.1:10031:^dunno$)</pre>
<pre>
mail(server/helo/from/to/subject/body)
This command is deprecated. You should try to use the sendmail() action instead.
Very basic mail command, that sends a message with the given arguments. LIMITATIONS:
This basically performs a telnet. No authentication or TLS are available. Additionally it does
not track notification state and will notify you any time, the corresponding rule hits.</pre>
<pre>
sendmail(sendmail-path::from::to::subject::body)
Mail command, that uses an existing sendmail binary and sends a message with the given arguments.
LIMITATIONS: The command does not track notification state and will notify you any time, the
corresponding rule hits (which could mean 100 mails for a mail with 100 recipients at RCPT stage).</pre>
<pre>
wait (&lt;delay&gt;)
pauses the program execution for &lt;delay&gt; seconds. use this for
@ -700,6 +720,10 @@ will be used.</p>
$myresult = ($myitem &lt;= $val);
} elsif ($cmp eq '=&gt;') {
$myresult = ($myitem &gt;= $val);
} elsif ($cmp eq '&lt;') {
$myresult = ($myitem &lt; $val);
} elsif ($cmp eq '&gt;') {
$myresult = ($myitem &gt; $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!&lt;') {
@ -729,15 +753,15 @@ continue or to stop parsing the ruleset.</p>
# note(&lt;logstring&gt;) command
&quot;note&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
mylogs 'info', &quot;[RULES] &quot;.$myline.&quot; - note: &quot;.$myarg if $myarg;
my($myaction) = 'dunno'; my($stop) = 0;
log_info &quot;[RULES] &quot;.$myline.&quot; - note: &quot;.$myarg if $myarg;
return ($stop,$index,$myaction,$myline,%request);
},
# skips next &lt;myarg&gt; rules
&quot;skip&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
my($myaction) = 'dunno'; my($stop) = 0;
$index += $myarg if ( $myarg and not(($index + $myarg) &gt; $#Rules) );
return ($stop,$index,$myaction,$myline,%request);
},
@ -745,8 +769,8 @@ continue or to stop parsing the ruleset.</p>
# dumps current request contents to syslog
&quot;dumprequest&quot; =&gt; sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
map { mylogs 'info', &quot;[DUMP] rule=$index, Attribute: $_=$request{$_}&quot; } (keys %request);
my($myaction) = 'dunno'; my($stop) = 0;
map { log_info &quot;[DUMP] rule=$index, Attribute: $_=$request{$_}&quot; } (keys %request);
return ($stop,$index,$myaction,$myline,%request);
},</pre>
<pre>
@ -978,7 +1002,10 @@ The following arguments will control it's behaviour in this case.</p>
Once a ratelimit was set by the ruleset, future requests will be evaluated against it
before consulting the ruleset. This mode was the default behaviour until v1.30.
With this mode rate limits will be faster, but also eventually set up
whitelisting-rules within the ruleset might not work as expected.</pre>
whitelisting-rules within the ruleset might not work as expected.
LIMITATIONS: This option does not allow nested postfwd commands like
action=rate(sender/3/60/wait(3))
This option doe not work with the strict-rfc5321 rate() functions.</pre>
<p><em>Informational arguments</em></p>
<p>These arguments are for command line usage only. Never ever use them with postfix!</p>
<pre>
@ -1215,7 +1242,7 @@ check the parser with the -C | --showconfig switch at the command line before ap
Rule 0: id-&gt;&quot;RBL001&quot;; action-&gt;&quot;REJECT listed on spamcop and bad rdns&quot;; rbl-&gt;&quot;bl.spamcop.net&quot;; client_name-&gt;&quot;^unknown$&quot;</pre>
<p><em>Request processing</em></p>
<p>When a policy delegation request arrives it will be compared against postfwd`s ruleset. To inspect the processing in detail you should increase
verbority using use the ``-v'' or ``-vv'' switch. ``-L'' redirects log messages to stdout.</p>
verbority using use the &quot;-v&quot; or &quot;-vv&quot; switch. &quot;-L&quot; redirects log messages to stdout.</p>
<p>Keeping the order of the ruleset in general, items will be compared in random order, which basically means that</p>
<pre>
id=R001; action=dunno; client_address=192.168.1.1; sender=bob@alice.local</pre>
@ -1254,7 +1281,7 @@ to compare against the request attribute the parser will jump to the next rule i
<p>If a rule matches, there are two options:</p>
<p>* Rule returns postfix action (dunno, reject, ...)
The parser stops rule processing and returns the action to postfix. Other rules will not be evaluated.</p>
<p>* Rule returns postfwd2 action (jump(), note(), ...)
<p>* Rule returns postfwd2 action (jump(), <code>note()</code>, ...)
The parser evaluates the given action and continues with the next rule (except for the <code>jump()</code> or <code>quit()</code> actions - please see the <a href="#actions">ACTIONS</a> section
for more information). Nothing will be sent to postfix.</p>
<p>If no rule has matched and the end of the ruleset is reached postfwd2 will return dunno without logging anything unless in verbose mode. You may
@ -1283,7 +1310,7 @@ the prefered way to use postfwd2 in high volume environments. Start postfwd2 wit
postfwd2 -d -f /etc/postfwd.cf -i 127.0.0.1 -p 10045 -u nobody -g nobody -S</pre>
<p>For efficient caching you should check if you can use the options --cacheid, --cache-rdomain-only,
--cache-no-sender and --cache-no-size.</p>
<p>Now check your syslogs (default facility ``mail'') for a line like:</p>
<p>Now check your syslogs (default facility &quot;mail&quot;) for a line like:</p>
<pre>
Aug 9 23:00:24 mail postfwd[5158]: postfwd2 n.nn ready for input</pre>
<p>and use `netstat -an|grep 10045` to check for something like</p>

View file

@ -79,6 +79,8 @@ SYNOPSIS
--keep_rates do not clear rate limit counters on reload
--save_rates <file> save and load rate limits on disk
--fast_limit_evaluation evaluate rate limits before ruleset is parsed
(please note the limitations)
Plugins:
--plugins <file> loads postfwd plugins from file
@ -161,6 +163,8 @@ DESCRIPTION
ITEM == VALUE true if ITEM equals VALUE
ITEM => VALUE true if ITEM >= VALUE
ITEM =< VALUE true if ITEM <= VALUE
ITEM > VALUE true if ITEM > VALUE
ITEM < VALUE true if ITEM < VALUE
ITEM =~ VALUE true if ITEM ~= /^VALUE$/i
ITEM != VALUE false if ITEM equals VALUE
ITEM !> VALUE false if ITEM >= VALUE
@ -485,7 +489,7 @@ DESCRIPTION
-- FILE /etc/postfwd/clients_west.cf --
192.168.3.0/24
Remind that there is currently no loop detection (/a/file calls /a/file)
Note that there is currently no loop detection (/a/file calls /a/file)
and that this feature is only available with postfwd1 v1.15 and postfwd2
v0.18 and higher.
@ -548,7 +552,7 @@ DESCRIPTION
this command creates a counter for the given <item>, which will be increased any time a request
containing it arrives. if it exceeds <max> within <time> seconds it will return <action> to postfix.
rate counters are very fast as they are executed before the ruleset is parsed.
please note that <action> is currently limited to postfix actions (no postfwd actions)!
please note that <action> was limited to postfix actions (no postfwd actions) for postfwd versions <1.33!
# no more than 3 requests per 5 minutes
# from the same "unknown" client
id=RATE01 ; client_name==unknown
@ -571,6 +575,11 @@ DESCRIPTION
id=RCPT01 ; protocol_state==END-OF-MESSAGE ; client_address==!!(10.1.1.1)
action=rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
rate5321,size5321,rcpt5321 (<item>/<max>/<time>/<action>)
same as the corresponding non-5321 functions, with the difference that the localpart of
sender oder recipient addresses are evaluated case-sensitive according to rfc5321. That
means that requests from bob@example.local and BoB@example.local will be treated differently
ask (<addr>:<port>[:<ignore>])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first
and the second argument (address and port) are mandatory. a third optional argument may be
@ -582,10 +591,16 @@ DESCRIPTION
id=GREY; client_address==10.1.1.1; action=ask(127.0.0.1:10031:^dunno$)
mail(server/helo/from/to/subject/body)
This command is deprecated. You should try to use the sendmail() action instead.
Very basic mail command, that sends a message with the given arguments. LIMITATIONS:
This basically performs a telnet. No authentication or TLS are available. Additionally it does
not track notification state and will notify you any time, the corresponding rule hits.
sendmail(sendmail-path::from::to::subject::body)
Mail command, that uses an existing sendmail binary and sends a message with the given arguments.
LIMITATIONS: The command does not track notification state and will notify you any time, the
corresponding rule hits (which could mean 100 mails for a mail with 100 recipients at RCPT stage).
wait (<delay>)
pauses the program execution for <delay> seconds. use this for
delaying or throtteling connections.
@ -743,6 +758,10 @@ DESCRIPTION
$myresult = ($myitem <= $val);
} elsif ($cmp eq '=>') {
$myresult = ($myitem >= $val);
} elsif ($cmp eq '<') {
$myresult = ($myitem < $val);
} elsif ($cmp eq '>') {
$myresult = ($myitem > $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!<') {
@ -774,15 +793,15 @@ DESCRIPTION
# note(<logstring>) command
"note" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
mylogs 'info', "[RULES] ".$myline." - note: ".$myarg if $myarg;
my($myaction) = 'dunno'; my($stop) = 0;
log_info "[RULES] ".$myline." - note: ".$myarg if $myarg;
return ($stop,$index,$myaction,$myline,%request);
},
# skips next <myarg> rules
"skip" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
my($myaction) = 'dunno'; my($stop) = 0;
$index += $myarg if ( $myarg and not(($index + $myarg) > $#Rules) );
return ($stop,$index,$myaction,$myline,%request);
},
@ -790,8 +809,8 @@ DESCRIPTION
# dumps current request contents to syslog
"dumprequest" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
map { mylogs 'info', "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
my($myaction) = 'dunno'; my($stop) = 0;
map { log_info "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
return ($stop,$index,$myaction,$myline,%request);
},
@ -1035,6 +1054,9 @@ DESCRIPTION
before consulting the ruleset. This mode was the default behaviour until v1.30.
With this mode rate limits will be faster, but also eventually set up
whitelisting-rules within the ruleset might not work as expected.
LIMITATIONS: This option does not allow nested postfwd commands like
action=rate(sender/3/60/wait(3))
This option doe not work with the strict-rfc5321 rate() functions.
*Informational arguments*

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -137,15 +137,15 @@
# # note(<logstring>) command
# "note" => sub {
# my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
# my($myaction) = $default_action; my($stop) = 0;
# mylogs 'info', "[RULES] ".$myline." - note: ".$myarg if $myarg;
# my($myaction) = 'dunno'; my($stop) = 0;
# log_info ("[RULES] ".$myline." - note: ".$myarg) if $myarg;
# return ($stop,$index,$myaction,$myline,%request);
# },
#
# # skips next <myarg> rules
# "skip" => sub {
# my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
# my($myaction) = $default_action; my($stop) = 0;
# my($myaction) = 'dunno'; my($stop) = 0;
# $index += $myarg if ( $myarg and not(($index + $myarg) > $#Rules) );
# return ($stop,$index,$myaction,$myline,%request);
# },
@ -153,8 +153,8 @@
# # dumps current request contents to syslog
# "dumprequest" => sub {
# my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
# my($myaction) = $default_action; my($stop) = 0;
# map { mylogs 'info', "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
# my($myaction) = 'dunno'; my($stop) = 0;
# map { log_info ("[DUMP] rule=$index, Attribute: $_=$request{$_}") } (keys %request);
# return ($stop,$index,$myaction,$myline,%request);
# },

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ BEGIN {
# basics
our $NAME = "postfwd2";
our $VERSION = "1.32";
our $VERSION = "1.35";
our $DEFAULT = 'DUNNO';
# change this, to match your POD requirements
@ -75,7 +75,6 @@ our %postfwd_settings = (
proto => (($nounixsock) ? "tcp" : "unix"),
check => (($nounixsock) ? \&check_inet : \&check_unix),
umask => "0177",
recvbuffer => 65535,
},
server => {
commandline => " ".$NAME."::policy",
@ -85,7 +84,6 @@ our %postfwd_settings = (
proto => "tcp",
check => \&check_inet,
umask => "0111",
recvbuffer => 65535,
# child control
#check_for_dead => 30,
#check_for_waiting => 10,
@ -299,8 +297,8 @@ sub mylogs_new {
# Syslog to stdout
sub mylogs_stdout {
my($prio,$msg) = @_;
printf STDOUT "[LOG $prio]: $msg\n", @_;
my($prio,$msg) = @_; $msg =~ /^(.*)$/;
printf STDOUT "[LOG $prio]: $1\n", @_;
};
# send log message
@ -345,8 +343,8 @@ sub check_inet {
Proto => 'tcp',
Timeout => $postfwd_settings{timeout}{$type},
Type => SOCK_STREAM ) ) {
$socket->send("$send\n");
$socket->recv($send, $postfwd_settings{$type}{recvbuffer});
$socket->print("$send\n");
$send = $socket->getline();
$socket->close();
chomp($send);
} else {
@ -363,8 +361,8 @@ sub check_unix {
Peer => $postfwd_settings{$type}{port},
Timeout => $postfwd_settings{timeout}{$type},
Type => SOCK_STREAM ) ) {
$socket->send("$send\n");
$socket->recv($send, $postfwd_settings{$type}{recvbuffer});
$socket->print("$send\n");
$send = $socket->getline();
$socket->close();
chomp($send);
} else {
@ -638,6 +636,7 @@ sub cleanup_cache {
# saves rate limits to disk
sub save_rates {
return unless ($STORABLE and $postfwd_settings{rate}{store} and defined $Cache{rate});
cleanup_cache ('rate', time());
eval {
local $SIG{__DIE__} = sub { log_note ("ERROR: Could not store rate limits to ".$postfwd_settings{rate}{store}.": $! @_") };
store ($Cache{rate}, $postfwd_settings{rate}{store});
@ -651,7 +650,7 @@ sub save_rates {
# loads rate limits from disk
sub load_rates {
my $loadrate = undef;
return unless ($STORABLE and (-f $postfwd_settings{rate}{store}));
return unless ($STORABLE and $postfwd_settings{rate}{store} and (-f $postfwd_settings{rate}{store}));
eval {
local $SIG{__DIE__} = sub { log_note ("Could not load rate limits from ".$postfwd_settings{rate}{store}.": $! @_") };
$loadrate = retrieve($postfwd_settings{rate}{store});
@ -660,6 +659,7 @@ sub load_rates {
$Cache{rate} = $loadrate;
log_info ("Fetched ".(scalar %{$Cache{rate}})." rates from ".$postfwd_settings{rate}{store})
if wantsdebug(qw[ all verbose rates loadrates saverates ]);
cleanup_cache ('rate', time());
};
};
@ -880,7 +880,7 @@ my $COMP_HITS = "request_hits";
# item match counter
my $COMP_MATCHES = "matches";
# separator
my $COMP_SEPARATOR = "[=\~\<\>]=|[=\!][=\~\<\>]|=";
my $COMP_SEPARATOR = "[=\~\<\>]=|[\<\>]|[=\!][=\~\<\>]|=";
# macros
my $COMP_ACL = "[\&][\&]";
# negation
@ -1141,7 +1141,7 @@ sub check_for_old_syntax {
if ($mykey =~ /^action$/) {
if ($myvalue =~ /^(\w[\-\w]+)\s*\(\s*(.*?)\s*\)$/) {
my($mycmd,$myarg) = ($1, $2);
if ($mycmd =~ /^(rate|size|rcpt)$/i) {
if ($mycmd =~ /^(rate|size|rcpt)(5321)?$/i) {
if ($myarg =~ /^\$\$(.*)$/) {
$myarg = $1;
$myvalue = "$mycmd($myarg)";
@ -1630,7 +1630,7 @@ sub postfwd_items {
%result = (%result, &{$postfwd_items{$_}}((%request,%result)))
if (defined $postfwd_items{$_});
};
map { $result{$_} = '' unless $result{$_}; log_info ("[PLUGIN] Added key: $_=$result{$_}") if wantsdebug (qw[ all thisrequest ]) } (keys %result);
map { $result{$_} = '' unless (defined $result{$_}); log_info ("[PLUGIN] Added key: $_=$result{$_}") if wantsdebug (qw[ all thisrequest ]) } (keys %result);
return %result;
};
#
@ -1671,6 +1671,10 @@ sub postfwd_items {
$myresult = ($myitem <= $val);
} elsif ($cmp eq '=>') {
$myresult = ($myitem >= $val);
} elsif ($cmp eq '<') {
$myresult = ($myitem < $val);
} elsif ($cmp eq '>') {
$myresult = ($myitem > $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!<') {
@ -1835,6 +1839,10 @@ sub postfwd_items {
$myresult = (($myitem || 0) >= $val);
} elsif ($cmp eq '!>') {
$myresult = not(($myitem || 0) >= $val);
} elsif ($cmp eq '<') {
$myresult = (($myitem || 0) < $val);
} elsif ($cmp eq '>') {
$myresult = (($myitem || 0) > $val);
} elsif ($cmp eq '=~') {
$myresult = ($myitem =~ /$val/i);
} elsif ($cmp eq '!~') {
@ -1895,13 +1903,13 @@ sub postfwd_items {
$m_val = $r_val;
} elsif ( ($mod eq '.=') or ($mod eq '=.') ) {
$m_val .= $r_val;
} elsif ( (($mod eq '+=') or ($mod eq '=+')) and (($m_val=~/^\d+(\.\d+)?$/) and ($r_val=~/^\d+(\.\d+)?$/)) ) {
} elsif ( (($mod eq '+=') or ($mod eq '=+')) and (($m_val=~/^\-?\d+(\.\d+)?$/) and ($r_val=~/^\-?\d+(\.\d+)?$/)) ) {
$m_val += $r_val;
} elsif ( (($mod eq '-=') or ($mod eq '=-')) and (($m_val=~/^\d+(\.\d+)?$/) and ($r_val=~/^\d+(\.\d+)?$/)) ) {
} elsif ( (($mod eq '-=') or ($mod eq '=-')) and (($m_val=~/^\-?\d+(\.\d+)?$/) and ($r_val=~/^\-?\d+(\.\d+)?$/)) ) {
$m_val -= $r_val;
} elsif ( (($mod eq '*=') or ($mod eq '=*')) and (($m_val=~/^\d+(\.\d+)?$/) and ($r_val=~/^\d+(\.\d+)?$/)) ) {
} elsif ( (($mod eq '*=') or ($mod eq '=*')) and (($m_val=~/^\-?\d+(\.\d+)?$/) and ($r_val=~/^\-?\d+(\.\d+)?$/)) ) {
$m_val *= $r_val;
} elsif ( (($mod eq '/=') or ($mod eq '=/')) and (($m_val=~/^\d+(\.\d+)?$/) and ($r_val=~/^\d+(\.\d+)?$/)) ) {
} elsif ( (($mod eq '/=') or ($mod eq '=/')) and (($m_val=~/^\-?\d+(\.\d+)?$/) and ($r_val=~/^\-?\d+(\.\d+)?$/)) ) {
$m_val /= (($r_val == 0) ? 1 : $r_val);
} else {
$m_val = $r_val;
@ -1924,7 +1932,7 @@ sub postfwd_items {
my($myaction) = $postfwd_settings{default}; my($stop) = 0;
my($score) = (defined $request{request_score}) ? $request{request_score} : 0;
if ($myarg =~/^([\+\-\*\/\=]?)(\d+)([\.,](\d+))?$/) {
my($mod, $val) = ($1, $2 + ((defined $4) ? ($4 / 10) : 0));
my($mod, $val) = ($1, $2 + ((defined $4) ? "0.$4" : 0));
if ($mod eq '-') {
$score -= $val;
} elsif ($mod eq '*') {
@ -1968,7 +1976,7 @@ sub postfwd_items {
);
if ( my $socket = IO::Socket::INET->new(
PeerAddr => $mserver,
PeerPort => ($mport || 25),
PeerPort => ($mport ||= 25),
Proto => 'tcp',
Timeout => 30,
Type => SOCK_STREAM,
@ -1984,16 +1992,40 @@ sub postfwd_items {
};
return ($stop,$index,$myaction,$myline,%request);
},
# sendmail()
"sendmail" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $postfwd_settings{default}; my($stop) = 0;
my($mcmd,$mfrom,$mto,$msubject,$mbody) = split '::', $myarg, 5;
my($msg) = "From: $mfrom\nTo: $mto\nSubject: $msubject\n\n$mbody\n";
if ( (-x $mcmd) and open (SM, "| $mcmd -i -f $mfrom $mto") ) {
if ( print SM "$msg" ) {
log_info ("[SENDMAIL] ".$myline.", $mcmd from=<$mfrom>, to=<$mto>, subject=<$msubject>");
} else {
log_note ("[SENDMAIL] ".$myline.", could not print to $mcmd pipe: '$!'");
};
close(SM);
} else {
log_note ("[SENDMAIL] ".$myline.", could not open pipe to $mcmd: '$!'");
};
return ($stop,$index,$myaction,$myline,%request);
},
# rate() command
"rate" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $postfwd_settings{default}; my($stop) = 0; my $prate = '';
my($ratetype,$ratecount,$ratetime,$ratecmd) = split "/", $myarg, 4;
my($rcount) = ( ($mycmd eq 'size') ? $request{size} : (($mycmd eq 'rcpt') ? $request{recipient_count} : 1 ) );
my($rcount) = ( ($mycmd =~ /^size/) ? $request{size} : (($mycmd =~ /^rcpt/) ? $request{recipient_count} : 1 ) );
if ($ratetype and $ratecount and $ratetime and $ratecmd and $rcount) {
my $crate = $Rules[$index]{$COMP_ID}.'+'.$ratecount.'_'.$ratetime;
if ( defined $request{$ratetype} ) {
$ratetype .= "=".$request{$ratetype};
my $r = $request{$ratetype};
unless ($mycmd =~ /5321$/) {
$r = lc($r);
} else {
$r = ($r =~ /^([^@]+)@(\S+)$/) ? $1.'@'.lc($2) : lc($r);
};
$ratetype .= "=".$r;
if ( $postfwd_settings{rate}{fast_eval} ) {
# Check if rate already exists in cache
@ -2077,6 +2109,12 @@ sub postfwd_items {
"size" => sub { return &{$postfwd_actions{rate}}(@_); },
# rcpt() command
"rcpt" => sub { return &{$postfwd_actions{rate}}(@_); },
# rate() command, according to rfc5321 case-sensivity
"rate5321" => sub { return &{$postfwd_actions{rate}}(@_); },
# rcpt() command, according to rfc5321 case-sensivity
"rcpt5321" => sub { return &{$postfwd_actions{rate}}(@_); },
# size() command, according to rfc5321 case-sensivity
"size5321" => sub { return &{$postfwd_actions{rate}}(@_); },
# wait() command
"wait" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
@ -2206,7 +2244,7 @@ sub compare_item {
# now compare request to every single item
ITEM: foreach (@items) {
($cmp, $val) = split ";";
next ITEM unless ($cmp and $val and $mykey);
next ITEM unless ($cmp and (defined $val) and $mykey);
# prepare_file
if ($val =~ /$COMP_LIVE_FILE_TABLE/) {
push @items, prepare_file (0, $1, $cmp, $2);
@ -2215,7 +2253,7 @@ sub compare_item {
log_info ("compare $mykey: \"$myitem\" \"$cmp\" \"$val\"") if wantsdebug (qw[ all thisrequest ]);
$val = $neg if ($neg = deneg_item($val));
log_info ("deneg $mykey: \"$myitem\" \"$cmp\" \"$val\"") if ($neg and wantsdebug (qw[ all thisrequest ]));
next ITEM unless $val;
next ITEM unless (defined $val);
# substitute check for $$vars in rule item
if ( $var = devar_item ($cmp,$val,$myitem,%request) ) {
$val = $var; $val =~ s/([^-_@\.\w\s])/\\$1/g unless ($cmp eq '==');
@ -2288,7 +2326,7 @@ sub compare_rule {
? $date
# default: compare against request attribute
: $request{$mykey};
$myresult[0] = ($res = compare_item($mykey, $Rules[$index]{$mykey}, $num, ($val || ''), %request)) ? ($myresult[0] + $res) : 0;
$myresult[0] = ($res = compare_item($mykey, $Rules[$index]{$mykey}, $num, ((defined $val) ? $val : ''), %request)) ? ($myresult[0] + $res) : 0;
};
last ITEM unless ($myresult[0] > 0);
};
@ -2493,7 +2531,7 @@ sub compare_rule {
$myline = "[RULES] RULE: ".$index." MATCHES: ".((($myresult[0] - 2) > 0) ? ($myresult[0] - 2) : 0);
$myline .= " RBLCOUNT: ".$myresult[1] if $myresult[1];
$myline .= " RHSBLCOUNT: ".$myresult[2] if $myresult[2];
$myline .= " DNSBLTEXT: ".(join ("; ", @DNSBL_Text)) if ( (defined @DNSBL_Text) and (($myresult[1] > 0) or ($myresult[2] > 0)) );
$myline .= " DNSBLTEXT: ".(join ("; ", @DNSBL_Text)) if ( (@DNSBL_Text) and (($myresult[1] > 0) or ($myresult[2] > 0)) );
log_info ($myline);
};
return @myresult;
@ -2549,7 +2587,7 @@ sub smtpd_access_policy {
# increase rate limits
if (@Rate_Items and $postfwd_settings{rate}{fast_eval}) {
map { $checkval .= $_."=".$request{$_}.$postfwd_settings{seplst} if $request{$_} } (@Rate_Items);
map { $checkval .= $_."=".lc($request{$_}).$postfwd_settings{seplst} if $request{$_} } (@Rate_Items);
if ($checkval) {
$checkval = "CMD=".$postfwd_commands{checkrate}.";TYPE=rate;ITEM=$checkval;SIZE=".($request{'size'} || 0).";RCPT=".($request{'recipient_count'} || 0);
log_info ("[RATES] parent rate limit query: ".$checkval) if wantsdebug (qw[ all thisrequest verbose rates ]);
@ -2746,6 +2784,7 @@ sub smtpd_access_policy {
. ", state=".$request{protocol_state};
# check for postfwd action
$ai = 0; # (re)set max_command_recursion counter
while ($ai++ < $postfwd_settings{max_command_recursion} and $myaction =~ /^(\w[\-\w]+)\s*\(\s*(.*?)\s*\)$/) {
my($mycmd,$myarg) = ($1, $2); $stop = 0;
if (defined $postfwd_actions{$mycmd}) {
@ -3199,6 +3238,7 @@ log_note ("NODNS: set - will skip all dns based checks") if $postfwd_settings{dn
# check for --nodaemon option
unless ($postfwd_settings{daemon}) {
log_note ("NODAEMON: Please note that rate() commands do not work with postfwd2 and --nodaemon option due to the missing cache daemon");
my(%attr) = ();
get_plugins (@{$postfwd_settings{Plugins}}) if $postfwd_settings{Plugins};
read_config(1);
@ -3280,7 +3320,8 @@ die "master-daemon: should never see me!\n";
# cleanup children and files and terminate
sub end_program {
local $SIG{TERM} = 'IGNORE';
# ignore further TERM signals
$SIG{TERM} = 'IGNORE';
if ($postfwd_settings{summary}) {
undef $postfwd_settings{syslog}{noidlestats};
log_stats();
@ -3445,6 +3486,8 @@ B<postfwd2> [OPTIONS] [SOURCE1, SOURCE2, ...]
--keep_rates do not clear rate limit counters on reload
--save_rates <file> save and load rate limits on disk
--fast_limit_evaluation evaluate rate limits before ruleset is parsed
(please note the limitations)
Plugins:
--plugins <file> loads postfwd plugins from file
@ -3527,6 +3570,8 @@ The way how request items are compared to the ruleset can be influenced in the f
ITEM == VALUE true if ITEM equals VALUE
ITEM => VALUE true if ITEM >= VALUE
ITEM =< VALUE true if ITEM <= VALUE
ITEM > VALUE true if ITEM > VALUE
ITEM < VALUE true if ITEM < VALUE
ITEM =~ VALUE true if ITEM ~= /^VALUE$/i
ITEM != VALUE false if ITEM equals VALUE
ITEM !> VALUE false if ITEM >= VALUE
@ -3837,7 +3882,7 @@ Files can refer to other files. The following is valid.
-- FILE /etc/postfwd/clients_west.cf --
192.168.3.0/24
Remind that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
Note that there is currently no loop detection (/a/file calls /a/file) and that this feature is only available
with postfwd1 v1.15 and postfwd2 v0.18 and higher.
@ -3896,7 +3941,7 @@ postfwd2 actions control the behaviour of the program. Currently you can specify
this command creates a counter for the given <item>, which will be increased any time a request
containing it arrives. if it exceeds <max> within <time> seconds it will return <action> to postfix.
rate counters are very fast as they are executed before the ruleset is parsed.
please note that <action> is currently limited to postfix actions (no postfwd actions)!
please note that <action> was limited to postfix actions (no postfwd actions) for postfwd versions <1.33!
# no more than 3 requests per 5 minutes
# from the same "unknown" client
id=RATE01 ; client_name==unknown
@ -3919,6 +3964,11 @@ postfwd2 actions control the behaviour of the program. Currently you can specify
id=RCPT01 ; protocol_state==END-OF-MESSAGE ; client_address==!!(10.1.1.1)
action=rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
rate5321,size5321,rcpt5321 (<item>/<max>/<time>/<action>)
same as the corresponding non-5321 functions, with the difference that the localpart of
sender oder recipient addresses are evaluated case-sensitive according to rfc5321. That
means that requests from bob@example.local and BoB@example.local will be treated differently
ask (<addr>:<port>[:<ignore>])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first
and the second argument (address and port) are mandatory. a third optional argument may be
@ -3930,10 +3980,16 @@ postfwd2 actions control the behaviour of the program. Currently you can specify
id=GREY; client_address==10.1.1.1; action=ask(127.0.0.1:10031:^dunno$)
mail(server/helo/from/to/subject/body)
This command is deprecated. You should try to use the sendmail() action instead.
Very basic mail command, that sends a message with the given arguments. LIMITATIONS:
This basically performs a telnet. No authentication or TLS are available. Additionally it does
not track notification state and will notify you any time, the corresponding rule hits.
sendmail(sendmail-path::from::to::subject::body)
Mail command, that uses an existing sendmail binary and sends a message with the given arguments.
LIMITATIONS: The command does not track notification state and will notify you any time, the
corresponding rule hits (which could mean 100 mails for a mail with 100 recipients at RCPT stage).
wait (<delay>)
pauses the program execution for <delay> seconds. use this for
delaying or throtteling connections.
@ -4091,6 +4147,10 @@ will be used.
$myresult = ($myitem <= $val);
} elsif ($cmp eq '=>') {
$myresult = ($myitem >= $val);
} elsif ($cmp eq '<') {
$myresult = ($myitem < $val);
} elsif ($cmp eq '>') {
$myresult = ($myitem > $val);
} elsif ($cmp eq '!=') {
$myresult = not($myitem == $val);
} elsif ($cmp eq '!<') {
@ -4122,15 +4182,15 @@ continue or to stop parsing the ruleset.
# note(<logstring>) command
"note" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
mylogs 'info', "[RULES] ".$myline." - note: ".$myarg if $myarg;
my($myaction) = 'dunno'; my($stop) = 0;
log_info "[RULES] ".$myline." - note: ".$myarg if $myarg;
return ($stop,$index,$myaction,$myline,%request);
},
# skips next <myarg> rules
"skip" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
my($myaction) = 'dunno'; my($stop) = 0;
$index += $myarg if ( $myarg and not(($index + $myarg) > $#Rules) );
return ($stop,$index,$myaction,$myline,%request);
},
@ -4138,8 +4198,8 @@ continue or to stop parsing the ruleset.
# dumps current request contents to syslog
"dumprequest" => sub {
my($index,$now,$mycmd,$myarg,$myline,%request) = @_;
my($myaction) = $default_action; my($stop) = 0;
map { mylogs 'info', "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
my($myaction) = 'dunno'; my($stop) = 0;
map { log_info "[DUMP] rule=$index, Attribute: $_=$request{$_}" } (keys %request);
return ($stop,$index,$myaction,$myline,%request);
},
@ -4382,6 +4442,9 @@ These parameters influence the way postfwd2 is working. Any of them can be combi
before consulting the ruleset. This mode was the default behaviour until v1.30.
With this mode rate limits will be faster, but also eventually set up
whitelisting-rules within the ruleset might not work as expected.
LIMITATIONS: This option does not allow nested postfwd commands like
action=rate(sender/3/60/wait(3))
This option doe not work with the strict-rfc5321 rate() functions.
I<Informational arguments>