Merge tag 'upstream/1.20'

Upstream version 1.20
This commit is contained in:
Jan Wagner 2013-11-05 17:33:35 +01:00
commit 19ceeb5e37
11 changed files with 8688 additions and 73 deletions

View file

@ -7,6 +7,7 @@
PATH=/bin:/usr/bin:/usr/local/bin PATH=/bin:/usr/bin:/usr/local/bin
# path to program # path to program
#PFWCMD=/usr/local/postfwd/sbin/postfwd2
PFWCMD=/usr/local/postfwd/sbin/postfwd PFWCMD=/usr/local/postfwd/sbin/postfwd
# rulesetconfig file # rulesetconfig file
PFWCFG=/etc/postfix/postfwd.cf PFWCFG=/etc/postfix/postfwd.cf

View file

@ -1,3 +1,18 @@
1.20
=====
- code: changed the default umask for the server socket to 0111
to support out-of-the-box postfix setup. Use the
--umask setting to change this
- bugfix: rbl check could fail on multiple dnsbl answers
- bugfix: rbl checks disabled for ipv6 addresses, cidr compare
will switch to default (regex/string)
1.19
=====
- code: Rate limit code rewritten
- code: new --umask setting allows to set filepermissions for pidfiles
and unix domain sockets. Default is 0117 (owner and group rw).
1.18 1.18
===== =====
- bugfix: Fixed bug when comparing sender and recipient addresses, like - bugfix: Fixed bug when comparing sender and recipient addresses, like

173
doc/CHANGELOG2 Normal file
View file

@ -0,0 +1,173 @@
postfwd2 1.00
=============
- code: changed the default umask for the server socket to 0111
to support out-of-the-box postfix setup. Use the
--server_umask setting to change this
- code: --dumpcache command does not require debug mode anymore
- code: rate hits included to cache stats
- bugfix: rbl checks disabled for ipv6 addresses, cidr compare
will switch to default (regex/string)
postfwd2 0.22
=============
- feature: Rate limits are completely supported by postfwd2 now.
Please note that the cache daemon is required for reliable operation.
- bugfix: --syslog_facility could not be changed
- code: rate limit code rewritten
- code: new --umask, --cache_umask and --server_umask settings allow to set
filepermissions for pidfiles and unix domain sockets. New defaults are:
* master (pidfile): 0177 (owner rw)
* cache (socket): 0177 (owner rw)
* server (socket): 0117 (owner and group rw)
postfwd2 0.21
=============
- bugfix: Fixed bug when comparing sender and recipient addresses, like
"sender=$$recipient". This affects only postfwd2 version 0.20.
postfwd2 0.20
=============
- bugfix: Invalid characters in variable substitutions were not correctly catched when
the '=' operator was used, like "client_name=$$helo_name". If you can not
upgrade for some reason change your rule to "client_name=~$$helo_name"
- code: Net::DNS errors will now be handled gracefully
- code: default for options --dns_max_ns_a_lookups and --dns_max_mx_a_lookups of 100
postfwd2 0.19
=============
- bugfix: this is a bugfix release for 0.18. anyone affected is encouraged to upgrade.
detail: the default behavior for the '=' operator with numeric items
(size, recipient_count, ...) changed with version 0.18 to '==' (equals to).
now these items are compared '>=' (greater than) again.
note: if you are using 0.18 and you are not able upgrade for some reason,
please change '=' to '>=' in your ruleset where you mean 'greater than'.
postfwd2 0.18
=============
- feature: items may now be retrieved from files using "item=file:/some/where"
more information in the postfwd manual (FILES section)
- feature: helo_address, and sender_(ns|mx)_addrs can now be csv items
- feature: new rcpt() command counts recipients for rate limits (thanks to Sahil Tandon)
- code: redirect syslog to stdout for --kill, --reload, --showconfig and --dump(cache|stats)
- code: option --reload (HUP signal) now reloads config, if the file is unchanged
- code: new --debug classes 'config' and 'request'
- code: configuration parser improvements:
* rules without defined action will be skipped at configuration stage
* undefined ACLs will now be detected and skipped at configuration stage
* parser timeout skips loading a rule after 4s, to prevent problems with
large files or loops. use --config_timeout to override
- bugfix: documentation fixed (missing "action=" in ask() examples)
- bugfix: fixed logging of an uninitialized value in cache cleanups
postfwd2 0.17
=============
- feature: new compare operators *
====================================================================
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$/i
*ITEM != VALUE false if ITEM equals VALUE
*ITEM !> VALUE false if ITEM >= VALUE
*ITEM !< VALUE false if ITEM <= VALUE
*ITEM !~ VALUE false if ITEM ~= /^VALUE$/i
ITEM = VALUE default behaviour (see ITEMS section)
====================================================================
- feature: added --nodaemon and --stdout options
- code: non dns items first: if a rule contains dns and non dns items, the
lookups will only be done if all non dns items matched
- bugfix: empty pcre with empty sender_(ns|mx)_names was parsed incorrectly.
this bug affects postfwd2 versions 0.15 - 0.16
- bugfix: negated pcre items with '~=' operator were parsed incorrectly.
this bug affects postfwd2 version 0.16
postfwd2 0.16
=============
- feature: enabled dns cache for sender(ns|mx) and helo address
- feature: new options --dns_max_ns_lookups and --dns_max_mx_lookups
- code: parent_dns_cache is now disabled by default. use
--parent_dns_cache if you have a slow nameserver
- bugfix: workaround: Net::Server died if a unix domain socket
filename without a dot ('.') was used (B. Frauendienst)
postfwd2 0.15
=============
- feature: new items sender_ns_names and sender_ns_addrs
- feature: new items sender_mx_names and sender_mx_addrs
- feature: new item helo_address, please see docs for more
- feature: new parent cache statistics. the command line option --dumpstats
uses the --daemons setting now (default: cache,server)
- feature: dnsbl txt lookups only for dnsbls with at least one a record.
use --dns_async_txt for the old behaviour (see docs for more).
- code: summary function went to postfwd::master (and will stay there ;)
- code: small performance improvement (5-10%) for pcre (~= or =~) items
- bugfix: network 0.0.0.0/0 did not work as expected on all platforms
postfwd2 0.14
=============
- code: summary function was moved from postfwd::cache to postfwd::policy.
the reduced policy <-> cache communication increases throughput
considerably and improves cpu balancing on multiprocessor systems
- bugfix: fixed potential division by zero in summary function
postfwd2 0.13
=============
- feature: new options --noidlestats and --norulestats
- feature: more informative --version
- feature: documentation updates
- bugfix: disabled parent_cache counters when --summary=0
postfwd2 0.12
=============
- feature: the ask() action allows to delegate the policy decision to another
policy service (like postgrey). a new parameter allows to specify
answer patterns which should be ignored by postfwd. please look
at the 'ACTIONS' section in the manual (postfwd2 -m) for details.
- feature: parent-request cache will now only be updated, if a rule matches.
if postfwd should cache all requests, you must place a last rule:
id=DEFAULT; action=dunno
- bugfix: reorganised some parent-cache loggings for -vv and *cache debug classes
postfwd2 0.11
=============
- bugfix: all postfwd settings are now detainted
- bugfix: cache-update used an uninitialized value when no rule had hit
postfwd2 0.10
=============
- bugfix: command line arguments --pidfile
postfwd2 0.09
=============
- bugfix: command line arguments --user and --group were not correctly de-tainted
postfwd2 0.08
=============
- bugfix: command line argument --pid_file was ignored
- bugfix: command line argument --manual (-m) did not work
postfwd2 0.07
=============
- first semi-public release of postfwd2
- full ruleset compatibility, no changes required when migrating from postfwd v1
- new architecture:
* Net::Server::PreFork
ruleset processor (server) forks new child for any request
* Net::Server::Multiplex for parent cache
offers a shared request, dns and rate cache for postfwd2 children
* Net::Server::Daemonize for master process
controls server and cache (watchdog function) and allows direct
access to statistics, cache-contents, ... from the command-line
- many new commandline options (see postfwd2 -h) for more information

View file

@ -64,6 +64,7 @@
--proto &lt;proto&gt; socket type (tcp or unix) --proto &lt;proto&gt; socket type (tcp or unix)
-u, --user &lt;name&gt; set uid to user &lt;name&gt; -u, --user &lt;name&gt; set uid to user &lt;name&gt;
-g, --group &lt;name&gt; set gid to group &lt;name&gt; -g, --group &lt;name&gt; set gid to group &lt;name&gt;
--umask &lt;mask&gt; set umask for file permissions
-R, --chroot &lt;path&gt; chroot the daemon to &lt;path&gt; -R, --chroot &lt;path&gt; chroot the daemon to &lt;path&gt;
--pidfile &lt;path&gt; create pidfile under &lt;path&gt; --pidfile &lt;path&gt; create pidfile under &lt;path&gt;
-l, --logname &lt;label&gt; label for syslog messages -l, --logname &lt;label&gt; label for syslog messages
@ -443,10 +444,11 @@ 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 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. 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. 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)!
# no more than 3 requests per 5 minutes # no more than 3 requests per 5 minutes
# from the same &quot;unknown&quot; client # from the same &quot;unknown&quot; client
id=RATE01 ; client_name==unknown ; \ id=RATE01 ; client_name==unknown ; \
action==rate($$client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)</pre> action==rate(client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)</pre>
<pre> <pre>
size (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;) size (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -454,7 +456,7 @@ rule containing only an action statement:</p>
smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset: smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset:
# size limit 1.5mb per hour per client # size limit 1.5mb per hour per client
id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==size($$client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour)</pre> action==size(client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour)</pre>
<pre> <pre>
rcpt (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;) rcpt (&lt;item&gt;/&lt;max&gt;/&lt;time&gt;/&lt;action&gt;)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -463,7 +465,7 @@ rule containing only an action statement:</p>
check it within the ruleset: check it within the ruleset:
# recipient count limit 3 per hour per client # recipient count limit 3 per hour per client
id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==rcpt($$client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)</pre> action==rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)</pre>
<pre> <pre>
ask (&lt;addr&gt;:&lt;port&gt;[:&lt;ignore&gt;]) 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 allows to delegate the policy decision to another policy service (e.g. postgrey). the first
@ -609,6 +611,11 @@ The following arguments will control it's behaviour in this case.</p>
<pre> <pre>
-g, --group &lt;name&gt; -g, --group &lt;name&gt;
Changes real and effective group to &lt;name&gt;.</pre> Changes real and effective group to &lt;name&gt;.</pre>
<pre>
--umask &lt;mask&gt;
Changes the umask for filepermissions (unix domain sockets, pidfiles).
Attention: This is umask, not chmod - you have to specify the bits that
should NOT apply. E.g.: umask 077 equals to chmod 700.</pre>
<pre> <pre>
-R, --chroot &lt;path&gt; -R, --chroot &lt;path&gt;
Chroot the process to the specified path. Chroot the process to the specified path.
@ -805,9 +812,10 @@ the '-I' switch to have your configuration refreshed for every request postfwd r
# 1. 30MB for systems in *.customer1.tld # 1. 30MB for systems in *.customer1.tld
# 2. 20MB for SASL user joejob # 2. 20MB for SASL user joejob
# 3. 10MB default # 3. 10MB default
id=SZ001; state==END-OF-MESSAGE; action=REJECT message too large; size=30000000 ; client_name=\.customer1.tld$ id=SZ001; state==END-OF-MESSAGE; action=DUNNO; size&lt;=30000000 ; client_name=\.customer1.tld$
id=SZ002; state==END-OF-MESSAGE; action=REJECT message too large; size=20000000 ; sasl_username==joejob id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size&lt;=20000000 ; sasl_username==joejob
id=SZ003; state==END-OF-MESSAGE; action=REJECT message too large; size=10000000</pre> id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size&lt;=10000000
id=SZ100; state==END-OF-MESSAGE; action=REJECT message too large</pre>
<pre> <pre>
## Selective Greylisting ## Selective Greylisting
# 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s # 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s
@ -856,9 +864,9 @@ the '-I' switch to have your configuration refreshed for every request postfwd r
# 1. exceeded 30 requests per hour or # 1. exceeded 30 requests per hour or
# 2. tried to send more than 1.5mb within 10 minutes # 2. tried to send more than 1.5mb within 10 minutes
id=RATE01 ; client_name==unknown ; state==RCPT ; \ id=RATE01 ; client_name==unknown ; state==RCPT ; \
action==rate($$client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour) action==rate(client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour)
id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \ id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \
action==size($$client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)</pre> action==size(client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)</pre>
<pre> <pre>
## Macros ## Macros
# definition # definition

View file

@ -18,6 +18,7 @@ SYNOPSIS
--proto <proto> socket type (tcp or unix) --proto <proto> socket type (tcp or unix)
-u, --user <name> set uid to user <name> -u, --user <name> set uid to user <name>
-g, --group <name> set gid to group <name> -g, --group <name> set gid to group <name>
--umask <mask> set umask for file permissions
-R, --chroot <path> chroot the daemon to <path> -R, --chroot <path> chroot the daemon to <path>
--pidfile <path> create pidfile under <path> --pidfile <path> create pidfile under <path>
-l, --logname <label> label for syslog messages -l, --logname <label> label for syslog messages
@ -464,10 +465,11 @@ DESCRIPTION
this command creates a counter for the given <item>, which will be increased any time a request 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. 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. 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)!
# no more than 3 requests per 5 minutes # no more than 3 requests per 5 minutes
# from the same "unknown" client # from the same "unknown" client
id=RATE01 ; client_name==unknown ; \ id=RATE01 ; client_name==unknown ; \
action==rate($$client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes) action==rate(client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)
size (<item>/<max>/<time>/<action>) size (<item>/<max>/<time>/<action>)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -475,7 +477,7 @@ DESCRIPTION
smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset: smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset:
# size limit 1.5mb per hour per client # size limit 1.5mb per hour per client
id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==size($$client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour) action==size(client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour)
rcpt (<item>/<max>/<time>/<action>) rcpt (<item>/<max>/<time>/<action>)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -484,7 +486,7 @@ DESCRIPTION
check it within the ruleset: check it within the ruleset:
# recipient count limit 3 per hour per client # recipient count limit 3 per hour per client
id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==rcpt($$client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour) action==rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
ask (<addr>:<port>[:<ignore>]) ask (<addr>:<port>[:<ignore>])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first allows to delegate the policy decision to another policy service (e.g. postgrey). the first
@ -648,6 +650,11 @@ DESCRIPTION
-g, --group <name> -g, --group <name>
Changes real and effective group to <name>. Changes real and effective group to <name>.
--umask <mask>
Changes the umask for filepermissions (unix domain sockets, pidfiles).
Attention: This is umask, not chmod - you have to specify the bits that
should NOT apply. E.g.: umask 077 equals to chmod 700.
-R, --chroot <path> -R, --chroot <path>
Chroot the process to the specified path. Chroot the process to the specified path.
Test this before using - you might need some libs there. Test this before using - you might need some libs there.
@ -847,9 +854,10 @@ DESCRIPTION
# 1. 30MB for systems in *.customer1.tld # 1. 30MB for systems in *.customer1.tld
# 2. 20MB for SASL user joejob # 2. 20MB for SASL user joejob
# 3. 10MB default # 3. 10MB default
id=SZ001; state==END-OF-MESSAGE; action=REJECT message too large; size=30000000 ; client_name=\.customer1.tld$ id=SZ001; state==END-OF-MESSAGE; action=DUNNO; size<=30000000 ; client_name=\.customer1.tld$
id=SZ002; state==END-OF-MESSAGE; action=REJECT message too large; size=20000000 ; sasl_username==joejob id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=20000000 ; sasl_username==joejob
id=SZ003; state==END-OF-MESSAGE; action=REJECT message too large; size=10000000 id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=10000000
id=SZ100; state==END-OF-MESSAGE; action=REJECT message too large
## Selective Greylisting ## Selective Greylisting
# 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s # 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s
@ -898,9 +906,9 @@ DESCRIPTION
# 1. exceeded 30 requests per hour or # 1. exceeded 30 requests per hour or
# 2. tried to send more than 1.5mb within 10 minutes # 2. tried to send more than 1.5mb within 10 minutes
id=RATE01 ; client_name==unknown ; state==RCPT ; \ id=RATE01 ; client_name==unknown ; state==RCPT ; \
action==rate($$client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour) action==rate(client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour)
id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \ id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \
action==size($$client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes) action==size(client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)
## Macros ## Macros
# definition # definition

1182
doc/postfwd2.html Normal file

File diff suppressed because it is too large Load diff

1270
doc/postfwd2.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -129,7 +129,7 @@
.\" ======================================================================== .\" ========================================================================
.\" .\"
.IX Title "POSTFWD 1" .IX Title "POSTFWD 1"
.TH POSTFWD 1 "2009-09-03" "perl v5.8.5" "User Contributed Perl Documentation" .TH POSTFWD 1 "2010-11-14" "perl v5.8.5" "User Contributed Perl Documentation"
.SH "NAME" .SH "NAME"
postfwd \- postfix firewall daemon postfwd \- postfix firewall daemon
.SH "SYNOPSIS" .SH "SYNOPSIS"
@ -147,7 +147,7 @@ postfwd [\s-1OPTIONS\s0] [\s-1SOURCE1\s0, \s-1SOURCE2\s0, ...]
\& -s, --scores <v>=<r> returns <r> when score exceeds <v> \& -s, --scores <v>=<r> returns <r> when score exceeds <v>
.Ve .Ve
.PP .PP
.Vb 11 .Vb 12
\& Networking: \& Networking:
\& -d, --daemon run postfwd as daemon \& -d, --daemon run postfwd as daemon
\& -i, --interface <dev> listen on interface <dev> \& -i, --interface <dev> listen on interface <dev>
@ -155,6 +155,7 @@ postfwd [\s-1OPTIONS\s0] [\s-1SOURCE1\s0, \s-1SOURCE2\s0, ...]
\& --proto <proto> socket type (tcp or unix) \& --proto <proto> socket type (tcp or unix)
\& -u, --user <name> set uid to user <name> \& -u, --user <name> set uid to user <name>
\& -g, --group <name> set gid to group <name> \& -g, --group <name> set gid to group <name>
\& --umask <mask> set umask for file permissions
\& -R, --chroot <path> chroot the daemon to <path> \& -R, --chroot <path> chroot the daemon to <path>
\& --pidfile <path> create pidfile under <path> \& --pidfile <path> create pidfile under <path>
\& -l, --logname <label> label for syslog messages \& -l, --logname <label> label for syslog messages
@ -674,15 +675,16 @@ postfwd actions control the behaviour of the program. Currently you can specify
\& by "," characters. \& by "," characters.
.Ve .Ve
.PP .PP
.Vb 8 .Vb 9
\& rate (<item>/<max>/<time>/<action>) \& rate (<item>/<max>/<time>/<action>)
\& this command creates a counter for the given <item>, which will be increased any time a request \& 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. \& 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. \& 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)!
\& # no more than 3 requests per 5 minutes \& # no more than 3 requests per 5 minutes
\& # from the same "unknown" client \& # from the same "unknown" client
\& id=RATE01 ; client_name==unknown ; \e \& id=RATE01 ; client_name==unknown ; \e
\& action==rate($$client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes) \& action==rate(client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)
.Ve .Ve
.PP .PP
.Vb 7 .Vb 7
@ -692,7 +694,7 @@ postfwd actions control the behaviour of the program. Currently you can specify
\& smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset: \& smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset:
\& # size limit 1.5mb per hour per client \& # size limit 1.5mb per hour per client
\& id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \e \& id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \e
\& action==size($$client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour) \& action==size(client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour)
.Ve .Ve
.PP .PP
.Vb 8 .Vb 8
@ -703,7 +705,7 @@ postfwd actions control the behaviour of the program. Currently you can specify
\& check it within the ruleset: \& check it within the ruleset:
\& # recipient count limit 3 per hour per client \& # recipient count limit 3 per hour per client
\& id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \e \& id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \e
\& action==rcpt($$client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour) \& action==rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
.Ve .Ve
.PP .PP
.Vb 9 .Vb 9
@ -911,6 +913,13 @@ The following arguments will control it's behaviour in this case.
\& Changes real and effective group to <name>. \& Changes real and effective group to <name>.
.Ve .Ve
.PP .PP
.Vb 4
\& --umask <mask>
\& Changes the umask for filepermissions (unix domain sockets, pidfiles).
\& Attention: This is umask, not chmod - you have to specify the bits that
\& should NOT apply. E.g.: umask 077 equals to chmod 700.
.Ve
.PP
.Vb 3 .Vb 3
\& -R, --chroot <path> \& -R, --chroot <path>
\& Chroot the process to the specified path. \& Chroot the process to the specified path.
@ -1179,14 +1188,15 @@ the '\-I' switch to have your configuration refreshed for every request postfwd
\& id=RBL04 ; action=REJECT combined RBL+RHSBL check ; rbl=bl.spamcop.net ; rhsbl=rhsbl.ahbl.org, rhsbl.sorbs.net \& id=RBL04 ; action=REJECT combined RBL+RHSBL check ; rbl=bl.spamcop.net ; rhsbl=rhsbl.ahbl.org, rhsbl.sorbs.net
.Ve .Ve
.PP .PP
.Vb 7 .Vb 8
\& ## Message size (requires message_size_limit to be set to 30000000) \& ## Message size (requires message_size_limit to be set to 30000000)
\& # 1. 30MB for systems in *.customer1.tld \& # 1. 30MB for systems in *.customer1.tld
\& # 2. 20MB for SASL user joejob \& # 2. 20MB for SASL user joejob
\& # 3. 10MB default \& # 3. 10MB default
\& id=SZ001; state==END-OF-MESSAGE; action=REJECT message too large; size=30000000 ; client_name=\e.customer1.tld$ \& id=SZ001; state==END-OF-MESSAGE; action=DUNNO; size<=30000000 ; client_name=\e.customer1.tld$
\& id=SZ002; state==END-OF-MESSAGE; action=REJECT message too large; size=20000000 ; sasl_username==joejob \& id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=20000000 ; sasl_username==joejob
\& id=SZ003; state==END-OF-MESSAGE; action=REJECT message too large; size=10000000 \& id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=10000000
\& id=SZ100; state==END-OF-MESSAGE; action=REJECT message too large
.Ve .Ve
.PP .PP
.Vb 7 .Vb 7
@ -1245,9 +1255,9 @@ the '\-I' switch to have your configuration refreshed for every request postfwd
\& # 1. exceeded 30 requests per hour or \& # 1. exceeded 30 requests per hour or
\& # 2. tried to send more than 1.5mb within 10 minutes \& # 2. tried to send more than 1.5mb within 10 minutes
\& id=RATE01 ; client_name==unknown ; state==RCPT ; \e \& id=RATE01 ; client_name==unknown ; state==RCPT ; \e
\& action==rate($$client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour) \& action==rate(client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour)
\& id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \e \& id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \e
\& action==size($$client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes) \& action==size(client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)
.Ve .Ve
.PP .PP
.Vb 8 .Vb 8

1671
man/man8/postfwd2.8 Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@ use vars qw(@ISA);
# Program constants # Program constants
our($NAME) = 'postfwd'; our($NAME) = 'postfwd';
our($VERSION) = '1.18'; our($VERSION) = '1.20';
# Networking options (use -i, -p and -R to change) # Networking options (use -i, -p and -R to change)
our($def_net_pid) = "/var/run/".$NAME.".pid"; our($def_net_pid) = "/var/run/".$NAME.".pid";
@ -33,6 +33,7 @@ our($def_net_chroot) = "";
our($def_net_interface) = "127.0.0.1"; our($def_net_interface) = "127.0.0.1";
our($def_net_port) = "10040"; our($def_net_port) = "10040";
our($def_net_proto) = "tcp"; our($def_net_proto) = "tcp";
our($def_net_umask) = "0111";
our($def_net_user) = "nobody"; our($def_net_user) = "nobody";
our($def_net_group) = "nobody"; our($def_net_group) = "nobody";
our($def_dns_queuesize) = "300"; our($def_dns_queuesize) = "300";
@ -201,7 +202,7 @@ our($SepReq) = '///';
our($SepLst) = ':::'; our($SepLst) = ':::';
our($KeyVal) = qr/^([^=]+)=(.*)$/; our($KeyVal) = qr/^([^=]+)=(.*)$/;
use vars qw( use vars qw(
@Configs @Rules @CacheID @DNSBL_Text @Plugins @Configs @Rules @CacheID @DNSBL_Text @Plugins @Rate_Items
%Config_Cache %DNS_Cache %Request_Cache %Rule_by_ID %Config_Cache %DNS_Cache %Request_Cache %Rule_by_ID
%Matches %opt_scores %ACLs %Rates %Timeouts %Matches %opt_scores %ACLs %Rates %Timeouts
%postfwd_items %postfwd_items_plugin %postfwd_items %postfwd_items_plugin
@ -212,7 +213,7 @@ use vars qw(
$Starttime $Startdate $Cleanup_Requests $Starttime $Startdate $Cleanup_Requests
$Cleanup_RBLs $Cleanup_Rates $Cleanup_Timeouts $Cleanup_RBLs $Cleanup_Rates $Cleanup_Timeouts
$opt_daemon $opt_instantconfig $opt_nodns $opt_nodnslog $opt_daemon $opt_instantconfig $opt_nodns $opt_nodnslog
$opt_norulelog $opt_summary $net_interface $net_port $opt_norulelog $opt_summary $net_interface $net_port $net_umask
$net_user $net_group $net_chroot $net_pid $net_proto $net_user $net_group $net_chroot $net_pid $net_proto
$opt_perfmon $opt_test $opt_verbose $opt_noidlestats $opt_perfmon $opt_test $opt_verbose $opt_noidlestats
$opt_cache_rdomain_only $opt_cache_no_size $config_timeout $opt_cache_rdomain_only $opt_cache_no_size $config_timeout
@ -576,6 +577,27 @@ sub prepare_item {
}; };
}; };
# #
# compatibility for old "rate"-syntax
#
sub check_for_old_syntax {
my($myindex,$myfile,$mynum,$mykey,$myvalue) = @_;
if ($mykey =~ /^action$/) {
if ($myvalue =~ /^(\w[\-\w]+)\s*\(\s*(.*?)\s*\)$/) {
my($mycmd,$myarg) = ($1, $2);
if ($mycmd =~ /^(rate|size|rcpt)$/i) {
if ($myarg =~ /^\$\$(.*)$/) {
$myarg = $1;
$myvalue = "$mycmd($myarg)";
mylogs "notice", "notice: Rule $myindex ($myfile line $mynum): "
."removing obsolete '\$\$' for $mycmd limit index. See man page for new syntax." if $opt_verbose;
};
push @Rate_Items, (split '/', $myarg)[0];
};
};
};
return $myvalue;
};
#
# parses configuration line # parses configuration line
# #
sub parse_config_line { sub parse_config_line {
@ -601,6 +623,7 @@ sub parse_config_line {
." overriding $mykey=\"".$myrule{$mykey}."\"" ." overriding $mykey=\"".$myrule{$mykey}."\""
." with $mykey=\"$myvalue\"" ." with $mykey=\"$myvalue\""
if (defined $myrule{$mykey}); if (defined $myrule{$mykey});
$myvalue = check_for_old_syntax($myindex,$myfile,$mynum,$mykey,$myvalue);
$myrule{$mykey} = $myvalue; $myrule{$mykey} = $myvalue;
} elsif ($mykey =~ /^$COMP_CSV$/) { } elsif ($mykey =~ /^$COMP_CSV$/) {
$myvalue =~ s/\s*,\s*/,/g; $myvalue =~ s/\s*,\s*/,/g;
@ -663,7 +686,7 @@ sub read_config {
my($mytype,$myitem,$config); my($mytype,$myitem,$config);
# init, cleanup cache and config vars # init, cleanup cache and config vars
@Rules = %Rule_by_ID = %Request_Cache = %Rates = (); @Rules = %Rule_by_ID = %Request_Cache = %Rates = @Rate_Items = ();
# parse configurations # parse configurations
for $config (@Configs) { for $config (@Configs) {
@ -693,6 +716,8 @@ sub read_config {
} else { } else {
# update Rule by ID hash # update Rule by ID hash
map { $Rule_by_ID{$Rules[$_]{$COMP_ID}} = $_ } (0 .. $#Rules); map { $Rule_by_ID{$Rules[$_]{$COMP_ID}} = $_ } (0 .. $#Rules);
@Rate_Items = uniq(@Rate_Items) if @Rate_Items;
mylogs $syslog_priority, "rate items: ".(join ', ', @Rate_Items) if $opt_verbose;
}; };
} }
# #
@ -874,6 +899,7 @@ sub rbl_check {
if $opt_verbose; if $opt_verbose;
push @DNSBL_Text, $DNS_Cache{$myquery}{type}.':'.$DNS_Cache{$myquery}{name}.':<'.($DNS_Cache{$myquery}{TXT} || '').'>' push @DNSBL_Text, $DNS_Cache{$myquery}{type}.':'.$DNS_Cache{$myquery}{name}.':<'.($DNS_Cache{$myquery}{TXT} || '').'>'
if (defined $DNS_Cache{$myquery}{type} and defined $DNS_Cache{$myquery}{name}); if (defined $DNS_Cache{$myquery}{type} and defined $DNS_Cache{$myquery}{name});
last ANSWER;
}; };
}; };
}; };
@ -885,7 +911,7 @@ sub rbl_check {
sub dns_query { sub dns_query {
my (@queries) = @_; undef my @result; my (@queries) = @_; undef my @result;
eval { eval {
local $SIG{__DIE__} = sub { mylogs 'notice', "dns err: \"$!\", detail: \"@_\""; }; local $SIG{__DIE__} = sub { mylogs 'notice', "dns err: \"$!\", detail: \"@_\""; return if $^S; };
@result = dns_query_net_dns(@queries); @result = dns_query_net_dns(@queries);
}; };
return @result; return @result;
@ -1008,9 +1034,19 @@ sub postfwd_items {
my($myresult) = ($val and $myitem); my($myresult) = ($val and $myitem);
mylogs $syslog_priority, "type cidr : \"$myitem\" \"$cmp\" \"$val\"" if ($opt_verbose > 1); mylogs $syslog_priority, "type cidr : \"$myitem\" \"$cmp\" \"$val\"" if ($opt_verbose > 1);
if ($myresult) { if ($myresult) {
return $myresult if ( ($val eq '0.0.0.0/0') and ($myitem =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) ); # always true
$val .= '/32' unless ($val =~ /\/\d{1,2}$/); $myresult = ($val eq '0.0.0.0/0');
$myresult = cidr_match((cidr_parse($val)),$myitem); unless ($myresult) {
# v4 addresses only
$myresult = ($myitem =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
if ($myresult) {
$val .= '/32' unless ($val =~ /\/\d{1,2}$/);
$myresult = cidr_match((cidr_parse($val)),$myitem);
} else {
mylogs $syslog_priority, "Non IPv4 address. Using type default" if ($opt_verbose > 1);
return &{$postfwd_compare{default}}($cmp,$val,$myitem,%request);
};
};
}; };
$myresult = not($myresult) if ($cmp eq '!='); $myresult = not($myresult) if ($cmp eq '!=');
return $myresult; return $myresult;
@ -1313,6 +1349,8 @@ sub postfwd_items {
my($myaction) = $default_action; my($stop) = 0; my($myaction) = $default_action; my($stop) = 0;
my($ratetype,$ratecount,$ratetime,$ratecmd) = split "/", $myarg, 4; my($ratetype,$ratecount,$ratetime,$ratecmd) = split "/", $myarg, 4;
if ($ratetype and $ratecount and $ratetime and $ratecmd) { if ($ratetype and $ratecount and $ratetime and $ratecmd) {
if ( defined $request{$ratetype} ) {
$ratetype .= "=".$request{$ratetype};
unless ( defined $Rates{$ratetype} ) { unless ( defined $Rates{$ratetype} ) {
$Rates{$ratetype} = { $Rates{$ratetype} = {
type => $mycmd, type => $mycmd,
@ -1328,6 +1366,9 @@ sub postfwd_items {
." [type: ".$mycmd.", max: ".$ratecount.", time: ".$ratetime."s]" ." [type: ".$mycmd.", max: ".$ratecount.", time: ".$ratetime."s]"
if ($opt_verbose > 1); if ($opt_verbose > 1);
}; };
} else {
mylogs $syslog_priority, "[RULES] ".$myline.", ignoring empty index for ".$mycmd." limit '".$ratetype."'" if ($opt_verbose > 1);
};
} else { } else {
mylogs "notice", "[RULES] ".$myline.", ignoring unknown ".$mycmd."() attribute \'".$myarg."\'"; mylogs "notice", "[RULES] ".$myline.", ignoring unknown ".$mycmd."() attribute \'".$myarg."\'";
}; };
@ -1558,7 +1599,7 @@ sub compare_rule {
mylogs "notice", "[DNSQUERY] skipping rbls: $timed - too much timeouts" if $timed; mylogs "notice", "[DNSQUERY] skipping rbls: $timed - too much timeouts" if $timed;
push @queries, rbl_prepare_lookups ( $COMP_RBL_KEY, $request{reverse_address}, @{$Rules[$index]{$COMP_RBL_KEY}} ) push @queries, rbl_prepare_lookups ( $COMP_RBL_KEY, $request{reverse_address}, @{$Rules[$index]{$COMP_RBL_KEY}} )
if ( exists($Rules[$index]{$COMP_RBL_KEY}) ); if ( exists($Rules[$index]{$COMP_RBL_KEY}) and not($request{client_address} =~ /:/) );
push @queries, rbl_prepare_lookups ( $COMP_RHSBL_KEY, $request{client_name}, @{$Rules[$index]{$COMP_RHSBL_KEY}} ) push @queries, rbl_prepare_lookups ( $COMP_RHSBL_KEY, $request{client_name}, @{$Rules[$index]{$COMP_RHSBL_KEY}} )
if ( exists($Rules[$index]{$COMP_RHSBL_KEY}) and not($request{client_name} eq "unknown") ); if ( exists($Rules[$index]{$COMP_RHSBL_KEY}) and not($request{client_name} eq "unknown") );
push @queries, rbl_prepare_lookups ( $COMP_RHSBL_KEY_CLIENT, $request{client_name}, @{$Rules[$index]{$COMP_RHSBL_KEY_CLIENT}} ) push @queries, rbl_prepare_lookups ( $COMP_RHSBL_KEY_CLIENT, $request{client_name}, @{$Rules[$index]{$COMP_RHSBL_KEY_CLIENT}} )
@ -1818,31 +1859,35 @@ sub smtpd_access_policy {
}; };
# increase rate limits # increase rate limits
RATES: foreach $checkreq (keys %request) { if (@Rate_Items) {
next RATES unless ( $request{$checkreq} and (defined $Rates{$request{$checkreq}}) ); RATES: foreach $checkreq (@Rate_Items) {
if ( ($now - $Rates{$request{$checkreq}}{"time"}) > $Rates{$request{$checkreq}}{ttl} ) { next RATES unless $request{$checkreq};
my $checkval = $checkreq."=".$request{$checkreq};
next RATES unless ( defined $Rates{$checkval});
if ( ($now - $Rates{$checkval}{"time"}) > $Rates{$checkval}{ttl} ) {
# renew rate # renew rate
$Rates{$request{$checkreq}}{count} = ( ($Rates{$request{$checkreq}}{type} eq 'size') ? $request{size} : $Rates{$checkval}{count} = ( ($Rates{$checkval}{type} eq 'size') ? $request{size} :
(($Rates{$request{$checkreq}}{type} eq 'rcpt') ? $request{recipient_count} : 1 ) ); (($Rates{$checkval}{type} eq 'rcpt') ? $request{recipient_count} : 1 ) );
$Rates{$request{$checkreq}}{"time"} = $now; $Rates{$checkval}{"time"} = $now;
mylogs $syslog_priority, "[RATE] renewing rate object ".$request{$checkreq} mylogs $syslog_priority, "[RATE] renewing rate object '".$checkval."'"
." [type: ".$Rates{$request{$checkreq}}{type} ." [type: ".$Rates{$checkval}{type}
.", max: ".$Rates{$request{$checkreq}}{maxcount} .", max: ".$Rates{$checkval}{maxcount}
.", time: ".$Rates{$request{$checkreq}}{ttl}."s]" .", time: ".$Rates{$checkval}{ttl}."s]"
if ($opt_verbose > 1); if ($opt_verbose > 1);
} else { } else {
# increase rate # increase rate
$Rates{$request{$checkreq}}{count} += ( ($Rates{$request{$checkreq}}{type} eq 'size') ? $request{size} : $Rates{$checkval}{count} += ( ($Rates{$checkval}{type} eq 'size') ? $request{size} :
(($Rates{$request{$checkreq}}{type} eq 'rcpt') ? $request{recipient_count} : 1 ) ); (($Rates{$checkval}{type} eq 'rcpt') ? $request{recipient_count} : 1 ) );
mylogs $syslog_priority, "[RATE] increasing rate object ".$request{$checkreq} mylogs $syslog_priority, "[RATE] increasing rate object '".$checkval."'"
." to ".$Rates{$request{$checkreq}}{count} ." to ".$Rates{$checkval}{count}
." [type: ".$Rates{$request{$checkreq}}{type} ." [type: ".$Rates{$checkval}{type}
.", max: ".$Rates{$request{$checkreq}}{maxcount} .", max: ".$Rates{$checkval}{maxcount}
.", time: ".$Rates{$request{$checkreq}}{ttl}."s]" .", time: ".$Rates{$checkval}{ttl}."s]"
if ($opt_verbose > 1); if ($opt_verbose > 1);
$ratehit = $checkreq if ($Rates{$request{$checkreq}}{count} > $Rates{$request{$checkreq}}{maxcount});
last RATES if $ratehit;
}; };
$ratehit = ($Rates{$checkval}{count} > $Rates{$checkval}{maxcount}) ? $checkval : undef;
last RATES if $ratehit;
};
}; };
# Request cache enabled? # Request cache enabled?
@ -1885,10 +1930,10 @@ sub smtpd_access_policy {
if ( $ratehit ) { if ( $ratehit ) {
$Counter_Rates++; $Counter_Rates++;
$Matches{$Rates{$request{$ratehit}}{rule}}++; $Matches{$Rates{$ratehit}{rule}}++;
$myaction = $Rates{$request{$ratehit}}{action}; $myaction = $Rates{$ratehit}{action};
mylogs $syslog_priority, "[RATE] rule=".$Rule_by_ID{$Rates{$request{$ratehit}}{rule}} mylogs $syslog_priority, "[RATE] rule=".$Rule_by_ID{$Rates{$ratehit}{rule}}
. ", id=".$Rates{$request{$ratehit}}{rule} . ", id=".$Rates{$ratehit}{rule}
. ", client=".$request{client_name}."[".$request{client_address}."]" . ", client=".$request{client_name}."[".$request{client_address}."]"
. ", sender=<".(($request{sender} eq '<>') ? "" : $request{sender}).">" . ", sender=<".(($request{sender} eq '<>') ? "" : $request{sender}).">"
. ", recipient=<".$request{recipient}.">" . ", recipient=<".$request{recipient}.">"
@ -1896,10 +1941,10 @@ sub smtpd_access_policy {
. ", proto=".$request{protocol_name} . ", proto=".$request{protocol_name}
. ", state=".$request{protocol_state} . ", state=".$request{protocol_state}
. ", delay=".(time - $now)."s" . ", delay=".(time - $now)."s"
. ", action=".$myaction." (item: ".$request{$ratehit} . ", action=".$myaction." (item: '".$ratehit."'"
. ", type: ".$Rates{$request{$ratehit}}{type} . ", type: ".$Rates{$ratehit}{type}
. ", count: ".$Rates{$request{$ratehit}}{count}."/".$Rates{$request{$ratehit}}{maxcount} . ", count: ".$Rates{$ratehit}{count}."/".$Rates{$ratehit}{maxcount}
. ", time: ".($now - $Rates{$request{$ratehit}}{"time"})."/".$Rates{$request{$ratehit}}{ttl}."s)" . ", time: ".($now - $Rates{$ratehit}{"time"})."/".$Rates{$ratehit}{ttl}."s)"
unless $opt_norulelog; unless $opt_norulelog;
# check cache # check cache
@ -2071,6 +2116,7 @@ GetOptions ( "term|kill|stop|k" => \$opt_kill,
'proto=s' => \$net_proto, 'proto=s' => \$net_proto,
'R|chroot=s' => \$net_chroot, 'R|chroot=s' => \$net_chroot,
'pid|pidfile=s' => \$net_pid, 'pid|pidfile=s' => \$net_pid,
'umask=s' => \$net_umask,
'u|user=s' => \$net_user, 'u|user=s' => \$net_user,
'g|group=s' => \$net_group, 'g|group=s' => \$net_group,
'dns_queuesize=s' => \$dns_queuesize, 'dns_queuesize=s' => \$dns_queuesize,
@ -2102,6 +2148,7 @@ GetOptions ( "term|kill|stop|k" => \$opt_kill,
'r|rule=s' => sub{ my($opt,$value) = @_; push (@Configs, $opt.'::'.$value) }, 'r|rule=s' => sub{ my($opt,$value) = @_; push (@Configs, $opt.'::'.$value) },
'plugins=s' => \@Plugins, 'plugins=s' => \@Plugins,
'V|version' => sub{ print "$NAME $VERSION (Net::DNS ".(Net::DNS->VERSION || '<undef>').", Net::Server ".(Net::Server->VERSION || '<undef>').", Sys::Syslog ".($Sys::Syslog::VERSION || '<undef>').", Perl ".$]." on ".$^O.")\n"; exit 1; }, 'V|version' => sub{ print "$NAME $VERSION (Net::DNS ".(Net::DNS->VERSION || '<undef>').", Net::Server ".(Net::Server->VERSION || '<undef>').", Sys::Syslog ".($Sys::Syslog::VERSION || '<undef>').", Perl ".$]." on ".$^O.")\n"; exit 1; },
'versionshort|shortversion' => sub{ print "$VERSION\n"; exit 1; },
'C|showconfig' => \$opt_showconfig, 'C|showconfig' => \$opt_showconfig,
'h|H|?|help|Help|HELP' => sub{ pod2usage (-msg => "\nPlease see \"".$NAME." -m\" for detailed instructions.\n", -verbose => 1); }, 'h|H|?|help|Help|HELP' => sub{ pod2usage (-msg => "\nPlease see \"".$NAME." -m\" for detailed instructions.\n", -verbose => 1); },
'm|M|manual' => sub{ # contructing command string (de-tainting $0) 'm|M|manual' => sub{ # contructing command string (de-tainting $0)
@ -2168,6 +2215,7 @@ get_plugins (@Plugins) if @Plugins;
$net_interface ||= $def_net_interface; $net_interface ||= $def_net_interface;
$net_port ||= $def_net_port; $net_port ||= $def_net_port;
$net_proto ||= $def_net_proto; $net_proto ||= $def_net_proto;
$net_umask ||= $def_net_umask;
$net_user ||= $def_net_user; $net_user ||= $def_net_user;
$net_group ||= $def_net_group; $net_group ||= $def_net_group;
$net_chroot ||= $def_net_chroot; $net_chroot ||= $def_net_chroot;
@ -2180,6 +2228,7 @@ $syslog_name ||= $NAME;
$net_interface = ( $net_interface =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/ ) ? $1 : $def_net_interface; $net_interface = ( $net_interface =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/ ) ? $1 : $def_net_interface;
$net_port = ( $net_port =~ /^(\d+|[-\|\@\/\w. ]+)$/ ) ? $1 : $def_net_port; $net_port = ( $net_port =~ /^(\d+|[-\|\@\/\w. ]+)$/ ) ? $1 : $def_net_port;
$net_proto = ( $net_proto =~ /^(tcp|unix)$/i ) ? $1 : $def_net_proto; $net_proto = ( $net_proto =~ /^(tcp|unix)$/i ) ? $1 : $def_net_proto;
$net_umask = ( $net_umask =~ /^([0-7]+)$/ ) ? $1 : $def_net_umask;
$net_user = ( $net_user =~ /^([\w]+)$/ ) ? $1 : $def_net_user; $net_user = ( $net_user =~ /^([\w]+)$/ ) ? $1 : $def_net_user;
$net_group = ( $net_group =~ /^([\w]+)$/ ) ? $1 : $def_net_group; $net_group = ( $net_group =~ /^([\w]+)$/ ) ? $1 : $def_net_group;
$net_chroot = ( $net_chroot =~ /^(.+)$/ ) ? $1 : $def_net_chroot; $net_chroot = ( $net_chroot =~ /^(.+)$/ ) ? $1 : $def_net_chroot;
@ -2224,6 +2273,7 @@ if ($opt_daemon) {
}, 'postfwd'; }, 'postfwd';
## run the servers main loop ## run the servers main loop
umask oct($net_umask);
$server->run; $server->run;
# ignore syslog failures # ignore syslog failures
@ -2253,7 +2303,7 @@ if ($opt_daemon) {
mylogs $syslog_priority, "successfully installed signal handlers" if $opt_verbose; mylogs $syslog_priority, "successfully installed signal handlers" if $opt_verbose;
# process init # process init
umask 0077; umask oct($net_umask);
setlocale(LC_ALL, 'C'); setlocale(LC_ALL, 'C');
$0 = $0." ".join(" ",@CommandArgs); $0 = $0." ".join(" ",@CommandArgs);
chdir "/" or fatal_exit "Could not chdir to /"; chdir "/" or fatal_exit "Could not chdir to /";
@ -2329,6 +2379,7 @@ postfwd [OPTIONS] [SOURCE1, SOURCE2, ...]
--proto <proto> socket type (tcp or unix) --proto <proto> socket type (tcp or unix)
-u, --user <name> set uid to user <name> -u, --user <name> set uid to user <name>
-g, --group <name> set gid to group <name> -g, --group <name> set gid to group <name>
--umask <mask> set umask for file permissions
-R, --chroot <path> chroot the daemon to <path> -R, --chroot <path> chroot the daemon to <path>
--pidfile <path> create pidfile under <path> --pidfile <path> create pidfile under <path>
-l, --logname <label> label for syslog messages -l, --logname <label> label for syslog messages
@ -2758,10 +2809,11 @@ postfwd 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 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. 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. 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)!
# no more than 3 requests per 5 minutes # no more than 3 requests per 5 minutes
# from the same "unknown" client # from the same "unknown" client
id=RATE01 ; client_name==unknown ; \ id=RATE01 ; client_name==unknown ; \
action==rate($$client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes) action==rate(client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)
size (<item>/<max>/<time>/<action>) size (<item>/<max>/<time>/<action>)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -2769,7 +2821,7 @@ postfwd actions control the behaviour of the program. Currently you can specify
smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset: smtpd_end_of_data_restrictions. if you want to be sure, you could check it within the ruleset:
# size limit 1.5mb per hour per client # size limit 1.5mb per hour per client
id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=SIZE01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==size($$client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour) action==size(client_address/1572864/3600/450 4.7.1 sorry, max 1.5mb per hour)
rcpt (<item>/<max>/<time>/<action>) rcpt (<item>/<max>/<time>/<action>)
this command works similar to the rate() command with the difference, that the rate counter is this command works similar to the rate() command with the difference, that the rate counter is
@ -2778,7 +2830,7 @@ postfwd actions control the behaviour of the program. Currently you can specify
check it within the ruleset: check it within the ruleset:
# recipient count limit 3 per hour per client # recipient count limit 3 per hour per client
id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \ id=RCPT01 ; state==END_OF_DATA ; client_address==!!(10.1.1.1); \
action==rcpt($$client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour) action==rcpt(client_address/3/3600/450 4.7.1 sorry, max 3 recipients per hour)
ask (<addr>:<port>[:<ignore>]) ask (<addr>:<port>[:<ignore>])
allows to delegate the policy decision to another policy service (e.g. postgrey). the first allows to delegate the policy decision to another policy service (e.g. postgrey). the first
@ -2943,6 +2995,11 @@ The following arguments will control it's behaviour in this case.
-g, --group <name> -g, --group <name>
Changes real and effective group to <name>. Changes real and effective group to <name>.
--umask <mask>
Changes the umask for filepermissions (unix domain sockets, pidfiles).
Attention: This is umask, not chmod - you have to specify the bits that
should NOT apply. E.g.: umask 077 equals to chmod 700.
-R, --chroot <path> -R, --chroot <path>
Chroot the process to the specified path. Chroot the process to the specified path.
Test this before using - you might need some libs there. Test this before using - you might need some libs there.
@ -3144,9 +3201,10 @@ the '-I' switch to have your configuration refreshed for every request postfwd r
# 1. 30MB for systems in *.customer1.tld # 1. 30MB for systems in *.customer1.tld
# 2. 20MB for SASL user joejob # 2. 20MB for SASL user joejob
# 3. 10MB default # 3. 10MB default
id=SZ001; state==END-OF-MESSAGE; action=REJECT message too large; size=30000000 ; client_name=\.customer1.tld$ id=SZ001; state==END-OF-MESSAGE; action=DUNNO; size<=30000000 ; client_name=\.customer1.tld$
id=SZ002; state==END-OF-MESSAGE; action=REJECT message too large; size=20000000 ; sasl_username==joejob id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=20000000 ; sasl_username==joejob
id=SZ003; state==END-OF-MESSAGE; action=REJECT message too large; size=10000000 id=SZ002; state==END-OF-MESSAGE; action=DUNNO; size<=10000000
id=SZ100; state==END-OF-MESSAGE; action=REJECT message too large
## Selective Greylisting ## Selective Greylisting
# 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s # 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s
@ -3195,9 +3253,9 @@ the '-I' switch to have your configuration refreshed for every request postfwd r
# 1. exceeded 30 requests per hour or # 1. exceeded 30 requests per hour or
# 2. tried to send more than 1.5mb within 10 minutes # 2. tried to send more than 1.5mb within 10 minutes
id=RATE01 ; client_name==unknown ; state==RCPT ; \ id=RATE01 ; client_name==unknown ; state==RCPT ; \
action==rate($$client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour) action==rate(client_address/30/3600/450 4.7.1 sorry, max 30 requests per hour)
id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \ id=SIZE01 ; client_name==unknown ; state==END_OF_DATA ; \
action==size($$client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes) action==size(client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)
## Macros ## Macros
# definition # definition

4219
sbin/postfwd2 Executable file

File diff suppressed because it is too large Load diff