Merge tag 'upstream/1.10pre7c'
Upstream version 1.10pre7c
This commit is contained in:
		
						commit
						f0257c6790
					
				
					 12 changed files with 6854 additions and 0 deletions
				
			
		
							
								
								
									
										77
									
								
								bin/postfwd-script.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										77
									
								
								bin/postfwd-script.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# Startscript for the postfwd daemon
 | 
			
		||||
#
 | 
			
		||||
# by JPK
 | 
			
		||||
 | 
			
		||||
PATH=/bin:/usr/bin:/usr/local/bin
 | 
			
		||||
 | 
			
		||||
# path to program
 | 
			
		||||
PFWCMD=/usr/local/postfwd/sbin/postfwd
 | 
			
		||||
# rulesetconfig file
 | 
			
		||||
PFWCFG=/etc/postfix/postfwd.cf
 | 
			
		||||
 | 
			
		||||
# daemon settings
 | 
			
		||||
PFWUSER=nobody
 | 
			
		||||
PFWGROUP=nobody
 | 
			
		||||
PFWINET=127.0.0.1
 | 
			
		||||
PFWPORT=10040
 | 
			
		||||
 | 
			
		||||
# recommended extra arguments
 | 
			
		||||
PFWARG="--shortlog --summary=600 --cache=600 --cache-rbl-timeout=3600 --cleanup-requests=1200 --cleanup-rbls=1800 --cleanup-rates=1200"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## should be no need to change below
 | 
			
		||||
 | 
			
		||||
P1="`basename ${PFWCMD}`"; P2="`basename $0`";
 | 
			
		||||
PIDS="`ps -aef | grep "${P1}" | grep -v "${P2}" | grep -v grep | awk '{print $2}' | sort -nr`"
 | 
			
		||||
 | 
			
		||||
case "$1" in
 | 
			
		||||
 | 
			
		||||
	start*)		if [ -n "${PIDS}" ]; then
 | 
			
		||||
                                echo "Process called \"${P1}\" already found at PID ${PIDS}. Please use \"${P2} restart\" instead." ;
 | 
			
		||||
				false;
 | 
			
		||||
                        else
 | 
			
		||||
				echo "Starting ${P1}...";
 | 
			
		||||
				${PFWCMD} ${PFWARG} --daemon --file=${PFWCFG} --interface=${PFWINET} --port=${PFWPORT} --user=${PFWUSER} --group=${PFWGROUP};
 | 
			
		||||
			fi ;
 | 
			
		||||
			;;
 | 
			
		||||
 | 
			
		||||
	debug*)		if [ -n "${PIDS}" ]; then
 | 
			
		||||
                                echo "Process called \"${P1}\" already found at PID ${PIDS}. Please use \"${P2} restart\" instead." ;
 | 
			
		||||
                                false;
 | 
			
		||||
                        else
 | 
			
		||||
                                echo "Starting ${P1} in DEBUG mode...";
 | 
			
		||||
                                ${PFWCMD} ${PFWARG} -vv --daemon --file=${PFWCFG} --interface=${PFWINET} --port=${PFWPORT} --user=${PFWUSER} --group=${PFWGROUP};
 | 
			
		||||
                        fi ;
 | 
			
		||||
                        ;;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	stop*)		if [ -z "${PIDS}" ]; then
 | 
			
		||||
				echo "No process called \"${P1}\" found" ;
 | 
			
		||||
				false;
 | 
			
		||||
			else
 | 
			
		||||
				echo "Stopping ${P1}...";
 | 
			
		||||
				for pid in ${PIDS}; do kill ${pid}; done ;
 | 
			
		||||
			fi ;
 | 
			
		||||
			;;
 | 
			
		||||
 | 
			
		||||
	reload*)	if [ -z "${PIDS}" ]; then
 | 
			
		||||
				echo "No process called \"${P1}\" found" ;
 | 
			
		||||
				false;
 | 
			
		||||
			else
 | 
			
		||||
				echo "Refreshing ${P1}...";
 | 
			
		||||
				for pid in ${PIDS}; do kill -HUP ${pid}; done ;
 | 
			
		||||
			fi ;
 | 
			
		||||
			;;
 | 
			
		||||
 | 
			
		||||
	restart*)	$0 stop;
 | 
			
		||||
			sleep 4;
 | 
			
		||||
			$0 start;
 | 
			
		||||
			;;
 | 
			
		||||
 | 
			
		||||
	*)		echo "Unknown argument \"$1\"" >&2;
 | 
			
		||||
			echo "Usage: ${P2} {start|stop|reload|restart}" >&2;
 | 
			
		||||
			exit 1;;
 | 
			
		||||
esac
 | 
			
		||||
exit $?
 | 
			
		||||
							
								
								
									
										179
									
								
								doc/CHANGELOG
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								doc/CHANGELOG
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,179 @@
 | 
			
		|||
 | 
			
		||||
**************************************************************************************************
 | 
			
		||||
ATTENTION:  requirements changed - as dns queries are now performed asynchronously, postfwd from
 | 
			
		||||
            v1.10pre2 and above needs the perl module Net::DNS::Async! it is available via CPAN
 | 
			
		||||
            and installed for my tests without any problems on different linux and solaris systems
 | 
			
		||||
NOTE:       please see the docs ('postfwd -m' or 'perldoc postfwd') for more information
 | 
			
		||||
**************************************************************************************************
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
1.10pre7c
 | 
			
		||||
==========
 | 
			
		||||
- note:    1.10pre7c does not contain any code-changes to the postfwd daemon.
 | 
			
		||||
           this release only fixes some issues when buidling packages.
 | 
			
		||||
- bugfix:  set permissions of manpage dirs to 755
 | 
			
		||||
- bugfix:  manpage has gone to section 8
 | 
			
		||||
- bugfix:  postfwd-rblcheck.pl has gone to the tools folder
 | 
			
		||||
- bugfix:  documentation now refers to request.sample
 | 
			
		||||
 | 
			
		||||
1.10pre7b
 | 
			
		||||
==========
 | 
			
		||||
- bugfix:  inter-section links in documentation did not work correctly
 | 
			
		||||
           (thanks to Alexander 'Leo' Bergolth)
 | 
			
		||||
 | 
			
		||||
1.10pre7a
 | 
			
		||||
==========
 | 
			
		||||
- bugfix:  implemented workaround for possible crash of Sys::Syslog when syslog
 | 
			
		||||
           daemon is unavailable (thanks to Henrik Krohns)
 | 
			
		||||
- bugfix:  changed syslog socktype on solaris
 | 
			
		||||
 | 
			
		||||
1.10pre7
 | 
			
		||||
=========
 | 
			
		||||
- feature: $$request_score may now be used to access a request's score
 | 
			
		||||
- feature: auto-deactivation of non-responding dnsbls; please see the
 | 
			
		||||
           new --cleanup-timeouts and --dns_timeout_max options
 | 
			
		||||
- feature: the set command allows some basic operations:
 | 
			
		||||
  =========================================================
 | 
			
		||||
   action=set(ITEM+=VALUE)     adds VALUE to ITEM
 | 
			
		||||
   action=set(ITEM-=VALUE)     substracts VALUE from ITEM
 | 
			
		||||
   action=set(ITEM*=VALUE)     multiplies ITEM by VALUE
 | 
			
		||||
   action=set(ITEM/=VALUE)     divides ITEM through VALUE
 | 
			
		||||
   action=set(ITEM.=VALUE)     concatenates ITEM and VALUE
 | 
			
		||||
   action=set(ITEM==VALUE)     sets ITEM to VALUE
 | 
			
		||||
   action=set(ITEM=VALUE)      default: sets ITEM to VALUE
 | 
			
		||||
  =========================================================
 | 
			
		||||
- bugfix:  fixed wrong timestamp for timed out rbls
 | 
			
		||||
- code:    score() command now allows integer values
 | 
			
		||||
- code:    setting an empty score removes it from the table
 | 
			
		||||
- code:    duplicate lookups within the same rule are now recognised
 | 
			
		||||
 | 
			
		||||
1.10pre6
 | 
			
		||||
=========
 | 
			
		||||
- feature: the new rate() and size() commands offer some basic rate limit controls
 | 
			
		||||
- feature: new cleanup options: --cleanup-rates
 | 
			
		||||
- feature: regexps may now be included in // characters
 | 
			
		||||
- feature: an empty sender address is now replaced by <>
 | 
			
		||||
- bugfix:  some csv-separated itemlists did not work correctly since v1.10pre1
 | 
			
		||||
- bugfix:  fixed a possible race condition with request cache when config was reloaded via HUP signal
 | 
			
		||||
 | 
			
		||||
1.10pre5a
 | 
			
		||||
=========
 | 
			
		||||
- bugfix:  fixed a possible race condition in rbl_read_dns() function
 | 
			
		||||
 | 
			
		||||
1.10pre5
 | 
			
		||||
========
 | 
			
		||||
- feature: new dnsbl lookup types: rhsbl_client, rhsbl_sender, rhsbl_reverse_client
 | 
			
		||||
- feature: new caching option --cacheid allows to increase performance and cache efficiency
 | 
			
		||||
- code:    cleanups will only be logged if '-v' was set or if the process took at least 1 second
 | 
			
		||||
 | 
			
		||||
1.10pre4
 | 
			
		||||
========
 | 
			
		||||
- feature: new date items 'days=Sun-Sat' and 'months=Jan-Dec'
 | 
			
		||||
- feature: all date/time items may now be csv-separated lists
 | 
			
		||||
- feature: the set command can now have multiple, csv-separated arguments
 | 
			
		||||
- feature: enhanced use of rblcount and rhsblcount (see doc)
 | 
			
		||||
- feature: new caching options --cache-no-sender,--cache-rbl-timeout and --cache-rbl-default
 | 
			
		||||
- feature: new cleanup options: --cleanup-requests and --cleanup-rbls
 | 
			
		||||
- code:    cache cleanups are now performed on interval basis (not per request)
 | 
			
		||||
           which should decrease load on busy systems.
 | 
			
		||||
- code:    warning on multiple definitions of id, action, rblcount and rhsblcount is issued
 | 
			
		||||
- bugfix:  date items may now contain whitespaces (e.g. days = Fri - Sat)
 | 
			
		||||
 | 
			
		||||
1.10pre3
 | 
			
		||||
========
 | 
			
		||||
- feature: all hits for a rule are now logged in the final message
 | 
			
		||||
- feature: option --shortlog disables logging for some postfwd actions
 | 
			
		||||
- feature: introduced set() command, which enables setting of variables, which then can be
 | 
			
		||||
           compared to the ruleset to gain performance on repeated item lists (see doc).
 | 
			
		||||
- feature: introduced new command-line switches --dns_queuesize, --dns_retries and dns_retries
 | 
			
		||||
           to influence the behaviour of DNS lookups
 | 
			
		||||
- code:    restructured code (~+15% speed compared to v1.03, with nodns ruleset)
 | 
			
		||||
 | 
			
		||||
1.10pre2
 | 
			
		||||
========
 | 
			
		||||
- feature: DNS lookups are now parallelized per rule. this increases the performance of dnsbl
 | 
			
		||||
           items (and any other future dns based check) significantly. implementation (per rule):
 | 
			
		||||
           1.) send dns queries, 2.) process other non-dns items, 3.) evaluate dns results
 | 
			
		||||
           As a downside of this approach the parser does not wait for dns queries anymore, which
 | 
			
		||||
           could result in increased load. you might use the sleep() command to get some delay ;-)
 | 
			
		||||
 | 
			
		||||
1.10pre1
 | 
			
		||||
========
 | 
			
		||||
- feature: the way how request items are compared to the ruleset can now be influenced.
 | 
			
		||||
  ===============================================================
 | 
			
		||||
   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                      old default behaviour
 | 
			
		||||
  ===============================================================
 | 
			
		||||
- feature: the score() command now allows some basic arithmetic operations (+-*/=)
 | 
			
		||||
           e.g. action=score(*2) will double the current score
 | 
			
		||||
- feature: you can now refer to request attributes in actions, which will e.g. allow the following:
 | 
			
		||||
           id=R001; rbl=zen.spamhaus.org; \
 | 
			
		||||
		action=554 5.7.1 see http://www.spamhaus.org/query/bl?ip=$$client_address
 | 
			
		||||
- feature: introduced extra request attributes sender_localpart, sender_domain,
 | 
			
		||||
           recipient_localpart, recipient_domain and version for use like:
 | 
			
		||||
             id=test01; client_name ~= $$(sender_domain)$; action=score(-0.5)
 | 
			
		||||
- bugfix:  the "=" character could not be used in items
 | 
			
		||||
- bugfix:  negation of items (!!) did not work correctly under some circumstances
 | 
			
		||||
- bugfix:  time was logged incorrectly during request cache cleanups in verbose mode
 | 
			
		||||
           (thanks to Henrik Krohns)
 | 
			
		||||
- code:    restructured some parts of the code for future enhancement options. a plugin interface
 | 
			
		||||
           was prepared and will be included in the final version. perl's -w switch is used now.
 | 
			
		||||
- note:    the documentation has not been fully updated yet.
 | 
			
		||||
 | 
			
		||||
1.03
 | 
			
		||||
====
 | 
			
		||||
- feature: request attributes can now be compared (e.g. to compare client_name and helo_name)
 | 
			
		||||
- feature: rule items can now be negated (e.g. to compare if client_name does not match helo_name)
 | 
			
		||||
- feature: extra verbose mode '-vv' now displays much more debug information
 | 
			
		||||
- feature: -L switch to redirect log output to stdout
 | 
			
		||||
- feature: new manual section about the parser, other updates
 | 
			
		||||
- bugfix:  caching did not work at end_of_data level because of different queue ids, corrected
 | 
			
		||||
- bugfix:  all numeric items will now match if the request attribute exceeds the corresponding
 | 
			
		||||
           rule item. the negation operator will lead to the opposite effect:
 | 
			
		||||
  =============================================================================
 | 
			
		||||
   ITEM=VALUE                            TYPE
 | 
			
		||||
  =============================================================================
 | 
			
		||||
   rblcount=2                            matches if rbl hits   >= 2
 | 
			
		||||
   recipient_count=10                    matches if recipients >= 10
 | 
			
		||||
   size=12345                            matches if size       >= 12345
 | 
			
		||||
   encryption_keysize=256                matches if keysize    >= 256
 | 
			
		||||
   encryption_keysize=!!256              matches if keysize    <  256
 | 
			
		||||
  =============================================================================
 | 
			
		||||
 | 
			
		||||
1.02
 | 
			
		||||
====
 | 
			
		||||
- bugfix:  rblcount and rhsblcount did not work correctly since V1.01, corrected
 | 
			
		||||
 | 
			
		||||
1.01
 | 
			
		||||
====
 | 
			
		||||
- feature: multiple rbl, rhsbl and client_address statements in a single rule are now possible
 | 
			
		||||
- feature: note() command will now log (not warn!). an empty argument suppresses logging
 | 
			
		||||
- feature: in verbose mode you must set -vv now to see the whole request attributes
 | 
			
		||||
- feature: cached dnsbl results are now only logged in verbose mode
 | 
			
		||||
- manual:  several minor updates
 | 
			
		||||
 | 
			
		||||
1.00
 | 
			
		||||
====
 | 
			
		||||
- feature: multiple definitions of the same item in a single rule to build groups
 | 
			
		||||
- feature: rules can span multiple lines by specifying a trailing "\" character
 | 
			
		||||
- feature: syslog_name can now be set with -l|--logname <label>
 | 
			
		||||
- bugfix:  fixed bug in acl parser (no "}" character could be used in ACLs)
 | 
			
		||||
 | 
			
		||||
0.99p
 | 
			
		||||
=====
 | 
			
		||||
- bugfix: size and rcpt_count were checked as minimum values
 | 
			
		||||
          now they are correctly interpreted as maximum.
 | 
			
		||||
 | 
			
		||||
0.99o
 | 
			
		||||
=====
 | 
			
		||||
- feature: date and time based rules
 | 
			
		||||
- feature: macros (please see doc)
 | 
			
		||||
- feature: slightly changed statistics output
 | 
			
		||||
 | 
			
		||||
0.99n
 | 
			
		||||
=====
 | 
			
		||||
- first public beta version
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								doc/LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								doc/LICENSE
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
 | 
			
		||||
License
 | 
			
		||||
-------
 | 
			
		||||
postfwd is free software and released under BSD license, which basically means
 | 
			
		||||
that you can do what you want as long as you keep the copyright notice:
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2007, Jan Peter Kessler
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
        * Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
          this list of conditions and the following disclaimer.
 | 
			
		||||
        * Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
          this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
          and/or other materials provided with the distribution.
 | 
			
		||||
        * Neither the name of the authors nor the names of his contributors may be
 | 
			
		||||
          used to endorse or promote products derived from this software without
 | 
			
		||||
          specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY ME ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										976
									
								
								doc/postfwd.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										976
									
								
								doc/postfwd.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,976 @@
 | 
			
		|||
<!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>
 | 
			
		||||
<link rev="made" href="mailto:root@localhost" />
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body style="background-color: white">
 | 
			
		||||
 | 
			
		||||
<p><a name="__index__"></a></p>
 | 
			
		||||
<!-- INDEX BEGIN -->
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
 | 
			
		||||
	<li><a href="#name">NAME</a></li>
 | 
			
		||||
	<li><a href="#synopsis">SYNOPSIS</a></li>
 | 
			
		||||
	<li><a href="#description">DESCRIPTION</a></li>
 | 
			
		||||
	<ul>
 | 
			
		||||
 | 
			
		||||
		<li><a href="#introduction">INTRODUCTION</a></li>
 | 
			
		||||
		<li><a href="#configuration">CONFIGURATION</a></li>
 | 
			
		||||
		<li><a href="#items">ITEMS</a></li>
 | 
			
		||||
		<li><a href="#actions">ACTIONS</a></li>
 | 
			
		||||
		<li><a href="#macros_acls">MACROS/ACLS</a></li>
 | 
			
		||||
		<li><a href="#command_line">COMMAND LINE</a></li>
 | 
			
		||||
		<li><a href="#refresh">REFRESH</a></li>
 | 
			
		||||
		<li><a href="#examples">EXAMPLES</a></li>
 | 
			
		||||
		<li><a href="#parser">PARSER</a></li>
 | 
			
		||||
		<li><a href="#integration">INTEGRATION</a></li>
 | 
			
		||||
		<li><a href="#testing">TESTING</a></li>
 | 
			
		||||
		<li><a href="#performance">PERFORMANCE</a></li>
 | 
			
		||||
		<li><a href="#see_also">SEE ALSO</a></li>
 | 
			
		||||
	</ul>
 | 
			
		||||
 | 
			
		||||
	<li><a href="#license">LICENSE</a></li>
 | 
			
		||||
	<li><a href="#author">AUTHOR</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
<!-- INDEX END -->
 | 
			
		||||
 | 
			
		||||
<hr />
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h1><a name="name">NAME</a></h1>
 | 
			
		||||
<p>postfwd - postfix firewall daemon</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="synopsis">SYNOPSIS</a></h1>
 | 
			
		||||
<p>postfwd [OPTIONS] [SOURCE1, SOURCE2, ...]</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Ruleset: (at least one, multiple use is allowed):
 | 
			
		||||
        -f, --file <file>           reads rules from <file>
 | 
			
		||||
        -r, --rule <rule>           adds <rule> to config</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Scoring:
 | 
			
		||||
        -s, --scores <v>=<r>        returns <r> when score exceeds <v></pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Networking:
 | 
			
		||||
        -d, --daemon                run postfwd as daemon
 | 
			
		||||
        -i, --interface <dev>       listen on interface <dev>
 | 
			
		||||
        -p, --port <port>           listen on port <port>
 | 
			
		||||
        -u, --user <name>           set uid to user <name>
 | 
			
		||||
        -g, --group <name>          set gid to group <name>
 | 
			
		||||
        -R, --chroot <path>         chroot the daemon to <path>
 | 
			
		||||
        -l, --logname <label>       label for syslog messages
 | 
			
		||||
            --pidfile <path>        create pidfile under <path></pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Caching:
 | 
			
		||||
        -c, --cache <int>           sets the request-cache timeout to <int> seconds
 | 
			
		||||
            --cache-no-size         ignores size attribute for caching
 | 
			
		||||
            --cache-no-sender       ignores sender address in cache
 | 
			
		||||
            --cache-rdomain-only    ignores localpart of recipient address in cache
 | 
			
		||||
            --cache-rbl-timeout     default rbl timeout, if not specified in ruleset
 | 
			
		||||
            --cache-rbl-default     default rbl response pattern to match (regexp)
 | 
			
		||||
            --cacheid <item>, ..    list of attributes for request cache identifier
 | 
			
		||||
            --cleanup-requests      cleanup interval in seconds for request cache
 | 
			
		||||
            --cleanup-rbls          cleanup interval in seconds for rbl cache
 | 
			
		||||
            --cleanup-rates         cleanup interval in seconds for rate cache</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Optional:
 | 
			
		||||
        -t, --test                  testing, always returns "dunno"
 | 
			
		||||
        -v, --verbose               verbose logging, use twice (-vv) to increase level
 | 
			
		||||
            --shortlog              disables logging of some postfwd commands
 | 
			
		||||
        -S, --summary <int>         show some usage statistics every <int> seconds
 | 
			
		||||
        -n, --nodns                 disable dns
 | 
			
		||||
            --dns_queuesize         sets the queue size for asynchonous dns queries
 | 
			
		||||
            --dns_retries           how many retries for a single asynchonous dns query
 | 
			
		||||
            --dns_timeout           timeout in seconds for asynchonous dns queries
 | 
			
		||||
            --dns_timeout_max       maximum of dns timeouts until a dnsbl will be deactivated
 | 
			
		||||
            --dns_timeout_interval  interval in seconds for dns timeout maximum counter
 | 
			
		||||
        -I, --instantcfg            re-reads rulefiles for every new request</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Informational (use only at command-line, not with postfix!):
 | 
			
		||||
        -C, --showconfig            shows ruleset summary, -v for verbose
 | 
			
		||||
        -L, --stdoutlog             redirect syslog messages to stdout
 | 
			
		||||
        -P, --perfmon               no syslogging, no stdout
 | 
			
		||||
        -V, --version               shows program version
 | 
			
		||||
        -h, --help                  shows usage
 | 
			
		||||
        -m, --manual                shows program manual</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="description">DESCRIPTION</a></h1>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="introduction">INTRODUCTION</a></h2>
 | 
			
		||||
<p>postfwd is written to combine complex postfix restrictions in a ruleset similar to those of the most firewalls.
 | 
			
		||||
The program uses the postfix policy delegation protocol to control access to the mail system before a message
 | 
			
		||||
has been accepted (please visit <a href="http://www.postfix.org/SMTPD_POLICY_README.html">http://www.postfix.org/SMTPD_POLICY_README.html</a> for more information).</p>
 | 
			
		||||
<p>postfwd allows you to choose an action (e.g. reject, dunno) for a combination of several smtp parameters
 | 
			
		||||
(like sender and recipient address, size or the client's TLS fingerprint). Also it offers simple macros/acls
 | 
			
		||||
which should allow straightforward and easy-to-read configurations.</p>
 | 
			
		||||
<p><em>Features:</em></p>
 | 
			
		||||
<p>* Complex combinations of smtp parameters</p>
 | 
			
		||||
<p>* Combined RBL/RHSBL lookups with arbitrary actions depending on results</p>
 | 
			
		||||
<p>* Scoring system</p>
 | 
			
		||||
<p>* Date/time based rules</p>
 | 
			
		||||
<p>* Macros/ACLs, Groups, Negation</p>
 | 
			
		||||
<p>* Compare request attributes (e.g. client_name and helo_name)</p>
 | 
			
		||||
<p>* Internal caching for requests and dns lookups</p>
 | 
			
		||||
<p>* Built in statistics for rule efficiency analysis</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="configuration">CONFIGURATION</a></h2>
 | 
			
		||||
<p>A configuration line consists of optional item=value pairs, separated by semicolons
 | 
			
		||||
(`;`) and the appropriate desired action:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        [ <item1>[=><~]=<value>; <item2>[=><~]=<value>; ... ] action=<result></pre>
 | 
			
		||||
<p><em>Example:</em></p>
 | 
			
		||||
<pre>
 | 
			
		||||
        client_address=192.168.1.1 ; sender==no@bad.local ; action=REJECT</pre>
 | 
			
		||||
<p>This will deny all mail from 192.168.1.1 with envelope sender <a href="mailto:no@bad.local.">no@bad.local.</a> The order of the elements
 | 
			
		||||
is not important. So the following would lead to the same result as the previous example:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        action=REJECT ; client_address=192.168.1.1 ; sender==no@bad.local</pre>
 | 
			
		||||
<p>The way how request items are compared to the ruleset can be influenced in the following way:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        ====================================================================
 | 
			
		||||
         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                   default behaviour (see ITEMS section)
 | 
			
		||||
        ====================================================================</pre>
 | 
			
		||||
<p>To identify single rules in your log files, you may add an unique identifier for each of it:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R_001 ; action=REJECT ; client_address=192.168.1.1 ; sender==no@bad.local</pre>
 | 
			
		||||
<p>You may use these identifiers as target for the `jump()` command (see ACTIONS section below). Leading
 | 
			
		||||
or trailing whitespace characters will be ignored. Use '#' to comment your configuration. Others will
 | 
			
		||||
appreciate.</p>
 | 
			
		||||
<p>A ruleset consists of one or multiple rules, which can be loaded from files or passed as command line
 | 
			
		||||
arguments. Please see the COMMAND LINE section below for more information on this topic.</p>
 | 
			
		||||
<p>Rules can span multiple lines by adding a trailing backslash ``\'' character:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R_001 ;  client_address=192.168.1.0/24; sender==no@bad.local; \
 | 
			
		||||
                    action=REJECT please use your relay from there</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="items">ITEMS</a></h2>
 | 
			
		||||
<pre>
 | 
			
		||||
        id                      - a unique rule id, which can be used for log analysis
 | 
			
		||||
                                  ids also serve as targets for the "jump" command.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        date, time              - a time or date range within the specified rule shall hit</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        days, months            - a range of weekdays (Sun-Sat) or months (Jan-Dec)
 | 
			
		||||
                                  within the specified rule shall hit</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        score                   - when the specified score is hit (see ACTIONS section)
 | 
			
		||||
                                  the specified action will be returned to postfix
 | 
			
		||||
                                  scores are set global until redefined!</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        request_score           - this value allows to access a request's score. it
 | 
			
		||||
                                  may be used as variable ($$request_score).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        rbl, rhsbl,             - query the specified RBLs/RHSBLs, possible values are:
 | 
			
		||||
        rhsbl_client,             <name>[/<reply>/<maxcache>, <name>/<reply>/<maxcache>]
 | 
			
		||||
        rhsbl_sender,             (defaults: reply=^127\.0\.0\.\d+$ maxcache=3600)
 | 
			
		||||
        rhsbl_reverse_client      the results of all rhsbl_* queries will be combined
 | 
			
		||||
                                  in rhsbl_count (see below).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        rblcount, rhsblcount    - minimum RBL/RHSBL hitcounts to match. if not specified
 | 
			
		||||
                                  a single RBL/RHSBL hit will match the rbl/rhsbl items.
 | 
			
		||||
                                  you may specify 'all' to evaluate all items, and use
 | 
			
		||||
                                  it as variable in an action (see ACTIONS section)
 | 
			
		||||
                                  (default: 1)</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        sender_localpart,       - the local-/domainpart of the sender address
 | 
			
		||||
        sender_domain</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        recipient_localpart,    - the local-/domainpart of the recipient address
 | 
			
		||||
        recipient_domain</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        version                 - postfwd version, contains "postfwd n.nn"
 | 
			
		||||
                                  this enables version based checks in your rulesets
 | 
			
		||||
                                  (e.g. for migration). works with old versions too,
 | 
			
		||||
                                  because a non-existing item always returns false:
 | 
			
		||||
                                  id=R01; version~=1.10; sender_domain==some.org \
 | 
			
		||||
                                        ; action=REJECT sorry no access</pre>
 | 
			
		||||
<p>Besides these you can specify any attribute of the postfix policy delegation protocol.  
 | 
			
		||||
Feel free to combine them the way you need it (have a look at the EXAMPLES section below).</p>
 | 
			
		||||
<p>Most values can be specified as regular expressions (PCRE). Please see the table below
 | 
			
		||||
for details:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # ==========================================================
 | 
			
		||||
        # ITEM=VALUE                            TYPE
 | 
			
		||||
        # ==========================================================
 | 
			
		||||
        id=something                            mask = string
 | 
			
		||||
        date=01.04.2007-22.04.2007              mask = date (DD.MM.YYYY-DD.MM.YYYY)
 | 
			
		||||
        time=08:30:00-17:00:00                  mask = time (HH:MM:SS-HH:MM:SS)
 | 
			
		||||
        days=Mon-Wed                            mask = weekdays (Mon-Wed) or numeric (1-3)
 | 
			
		||||
        months=Feb-Apr                          mask = months (Feb-Apr) or numeric (1-3)
 | 
			
		||||
        score=5.0                               mask = maximum floating point value
 | 
			
		||||
        rbl=zen.spamhaus.org                    mask = <name>/<reply>/<maxcache>[,...]
 | 
			
		||||
        rblcount=2                              mask = numeric, will match if rbl hits >= 2
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        # Postfix version 2.1 and later:
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        client_address=<a.b.c.d/nn>             mask = CIDR[,CIDR,...]
 | 
			
		||||
        client_name=another.domain.tld          mask = PCRE
 | 
			
		||||
        reverse_client_name=another.domain.tld  mask = PCRE
 | 
			
		||||
        helo_name=some.domain.tld               mask = PCRE
 | 
			
		||||
        sender=foo@bar.tld                      mask = PCRE
 | 
			
		||||
        recipient=bar@foo.tld                   mask = PCRE
 | 
			
		||||
        recipient_count=5                       mask = numeric, will match if recipients >= 5
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        # Postfix version 2.2 and later:
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        sasl_method=plain                       mask = PCRE
 | 
			
		||||
        sasl_username=you                       mask = PCRE
 | 
			
		||||
        sasl_sender=                            mask = PCRE
 | 
			
		||||
        size=12345                              mask = numeric, will match if size >= 12345
 | 
			
		||||
        ccert_subject=blackhole.nowhere.local   mask = PCRE (only if tls verified)
 | 
			
		||||
        ccert_issuer=John+20Doe                 mask = PCRE (only if tls verified)
 | 
			
		||||
        ccert_fingerprint=AA:BB:CC:DD:EE:...    mask = PCRE (do NOT use "..." here)
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        # Postfix version 2.3 and later:
 | 
			
		||||
        # ------------------------------
 | 
			
		||||
        encryption_protocol=TLSv1/SSLv3         mask = PCRE
 | 
			
		||||
        encryption_cipher=DHE-RSA-AES256-SHA    mask = PCRE
 | 
			
		||||
        encryption_keysize=256                  mask = numeric, will match if keysize >= 256
 | 
			
		||||
        ...</pre>
 | 
			
		||||
<p>the current list can be found at <a href="http://www.postfix.org/SMTPD_POLICY_README.html">http://www.postfix.org/SMTPD_POLICY_README.html</a>. Please read carefully about which
 | 
			
		||||
attribute can be used at which level of the smtp transaction (e.g. size will only work reliably at END_OF_DATA level).
 | 
			
		||||
Pattern matching is performed case insensitive.</p>
 | 
			
		||||
<p>Multiple use of the same item is allowed and will compared as logical OR, which means that this will work as expected:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=TRUST001; action=OK; encryption_keysize=64;          \
 | 
			
		||||
                ccert_fingerprint=11:22:33:44:55:66:77:88:99;   \
 | 
			
		||||
                ccert_fingerprint=22:33:44:55:66:77:88:99:00;   \
 | 
			
		||||
                ccert_fingerprint=33:44:55:66:77:88:99:00:11;   \
 | 
			
		||||
                sender=@domain\.local$</pre>
 | 
			
		||||
<p>client_address, rbl and rhsbl items may also be specified as whitespace-or-comma-separated values:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=SKIP01; action=dunno; \
 | 
			
		||||
                client_address=192.168.1.0/24, 172.16.254.23
 | 
			
		||||
        id=SKIP02; action=dunno; \
 | 
			
		||||
                client_address= 10.10.3.32       \
 | 
			
		||||
                                10.216.222.0/27</pre>
 | 
			
		||||
<p>The following items currently have to be unique:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id, minimum and maximum values, rblcount and rhsblcount</pre>
 | 
			
		||||
<p>Any item can be negated by preceeding '!!' to it, e.g.:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=TLS001 ;  hostname=!!^secure\.trust\.local$ ;  action=REJECT only secure.trust.local please</pre>
 | 
			
		||||
<p>To avoid confusion with regexps or simply for better visibility you can use '!!(...)':</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=USER01 ;  sasl_username=!!( (bob|alice) )  ;  action=REJECT who is that?</pre>
 | 
			
		||||
<p>Request attributes can be compared by preceeding '$$' characters, e.g.:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R-003 ;  client_name = !! $$helo_name      ;  action=WARN helo does not match DNS
 | 
			
		||||
        # or
 | 
			
		||||
        id=R-003 ;  client_name = !!($$(helo_name))   ;  action=WARN helo does not match DNS</pre>
 | 
			
		||||
<p>This is only valid for PCRE values (see list above). The comparison will be performed as case insensitive exact match.
 | 
			
		||||
Use the '-vv' option to debug.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="actions">ACTIONS</a></h2>
 | 
			
		||||
<p><em>General</em></p>
 | 
			
		||||
<p>Actions will be executed, when all rule items have matched a request (or at least one of any item list). You can refer to
 | 
			
		||||
request attributes by preceeding $$ characters, like:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R-003; client_name = !!$$helo_name; action=WARN helo '$$helo_name' does not match DNS '$$client_name'
 | 
			
		||||
        # or
 | 
			
		||||
        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
 | 
			
		||||
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>
 | 
			
		||||
<pre>
 | 
			
		||||
        ...
 | 
			
		||||
        action=dunno ; sender=@domain.local     # sender is ok
 | 
			
		||||
        action=reject                           # default deny</pre>
 | 
			
		||||
<p><em>postfwd actions</em></p>
 | 
			
		||||
<p>postfwd actions control the behaviour of the program. Currently you can specify the following:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        jump (<id>)
 | 
			
		||||
        jumps to rule with id <id>, use this to skip certain rules.
 | 
			
		||||
        you can jump backwards - but remember that there is no loop
 | 
			
		||||
        detection at the moment! jumps to non-existing ids will be skipped.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        score (<score>)
 | 
			
		||||
        the request's score will be modified by the specified <score>,
 | 
			
		||||
        which must be a floating point value. the modificator can be either
 | 
			
		||||
                +n.nn   adds n.nn to current score
 | 
			
		||||
                -n.nn   sustracts n.nn from the current score
 | 
			
		||||
                *n.nn   multiplies the current score by n.nn
 | 
			
		||||
                /n.nn   divides the current score through n.nn
 | 
			
		||||
                =n.nn   sets the current score to n.nn
 | 
			
		||||
        if the score exceeds the maximum set by `--scores` option (see
 | 
			
		||||
        COMMAND LINE) or the score item (see ITEMS section), the action
 | 
			
		||||
        defined for this case will be returned (default: 5.0=>"REJECT postfwd score exceeded").</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        set (<item>=<value>,<item>=<value>,...)
 | 
			
		||||
        this command allows you to insert or override request attributes, which then may be
 | 
			
		||||
        compared to your further ruleset. use this to speed up repeated comparisons to large item lists.
 | 
			
		||||
        please see the EXAMPLES section for more information. you may separate multiple key=value pairs
 | 
			
		||||
        by "," characters.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        rate (<item>/<max>/<time>/<action>)
 | 
			
		||||
        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.
 | 
			
		||||
            # no more than 3 requests per 5 minutes
 | 
			
		||||
            # from the same "unknown" client
 | 
			
		||||
            id=RATE01 ;  client_name==unknown ; \
 | 
			
		||||
               action==rate($$client_address/3/300/450 4.7.1 sorry, max 3 requests per 5 minutes)</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        size (<item>/<max>/<time>/<action>)
 | 
			
		||||
        this command works similar to the rate() command with the difference, that the rate counter is
 | 
			
		||||
        increased by the request's size attribute. to do this reliably you should call postfwd from
 | 
			
		||||
        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
 | 
			
		||||
           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>
 | 
			
		||||
<pre>
 | 
			
		||||
        wait (<delay>)
 | 
			
		||||
        pauses the program execution for <delay> seconds. use this for
 | 
			
		||||
        delaying or throtteling connections.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        note (<string>)
 | 
			
		||||
        just logs the given string and continues parsing the ruleset.
 | 
			
		||||
        if the string is empty, nothing will be logged.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        quit (<code>)
 | 
			
		||||
        terminates the program with the given exit-code. postfix doesn`t
 | 
			
		||||
        like that too much, so use it with care.</pre>
 | 
			
		||||
<p>You can reference to request attributes, like</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R-HELO ;  helo_name=^[^\.]+$ ;  action=REJECT invalid helo '$$helo_name'</pre>
 | 
			
		||||
<p>These special attributes will be reset for any new rule:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        rblcount        - contains the number of RBL answers
 | 
			
		||||
        rhsblcount      - contains the number of RHSBL answers
 | 
			
		||||
        matches         - contains the number of matched items</pre>
 | 
			
		||||
<p>This means that you must save them, if you plan to use these values in later rules:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # set vals
 | 
			
		||||
        id=RBL01 ; rhsblcount=all ; rblcount=all ; \
 | 
			
		||||
                rbl=list.dsbl.org, bl.spamcop.net, dnsbl.sorbs.net, zen.spamhaus.org ; \
 | 
			
		||||
                rhsbl_client=rddn.dnsbl.net.au, rhsbl.ahbl.org, rhsbl.sorbs.net ; \
 | 
			
		||||
                rhsbl_sender=rddn.dnsbl.net.au, rhsbl.ahbl.org, rhsbl.sorbs.net ; \
 | 
			
		||||
                action=set(HIT_rhls=$$rhsblcount,HIT_rbls=$$rblcount)</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        # compare
 | 
			
		||||
        id=RBL02 ; HIT_rhls>=1 ; HIT_rbls>=1 ; action=554 5.7.1 blocked using $$HIT_rhls RHSBLs and $$HIT_rbls RBLs
 | 
			
		||||
        id=RBL03 ; HIT_rhls>=2               ; action=554 5.7.1 blocked using $$HIT_rhls RHSBLs
 | 
			
		||||
        id=RBL04 ; HIT_rbls>=2               ; action=554 5.7.1 blocked using $$HIT_rbls RBLs</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="macros_acls">MACROS/ACLS</a></h2>
 | 
			
		||||
<p>Multiple use of long items or combinations of them may be abbreviated by macros. Those must be prefixed by '&&' (two '&' characters).
 | 
			
		||||
First the macros have to be defined as follows:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        &&RBLS { rbl=zen.spamhaus.org,list.dsbl.org,bl.spamcop.net,dnsbl.sorbs.net,ix.dnsbl.manitu.net; };</pre>
 | 
			
		||||
<p>Then these may be used in your rules, like:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        &&RBLS ;  client_name=^unknown$                         ; action=REJECT
 | 
			
		||||
        &&RBLS ;  client_name=(\d+[\.-_]){4}                    ; action=REJECT
 | 
			
		||||
        &&RBLS ;  client_name=[\.-_](adsl|dynamic|ppp|)[\.-_]   ; action=REJECT</pre>
 | 
			
		||||
<p>Macros can contain actions, too:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # definition
 | 
			
		||||
        &&GONOW { action=REJECT your request caused our spam detection policy to reject this message. More info at <a href="http://www.domain.local">http://www.domain.local</a>; };
 | 
			
		||||
        # rules
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=^unknown$
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=(\d+[\.-_]){4}
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=[\.-_](adsl|dynamic|ppp|)[\.-_]</pre>
 | 
			
		||||
<p>Macros can contain macros, too:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # definition (note the trailing "\" characters)
 | 
			
		||||
        &&RBLS {                                                \
 | 
			
		||||
                rbl=zen.spamhaus.org ;                          \
 | 
			
		||||
                rbl=list.dsbl.org ;                             \
 | 
			
		||||
                rbl=bl.spamcop.net ;                            \
 | 
			
		||||
                rbl=dnsbl.sorbs.net ;                           \
 | 
			
		||||
                rbl=ix.dnsbl.manitu.net ;                       \
 | 
			
		||||
        };
 | 
			
		||||
        &&DYNAMIC {                                             \
 | 
			
		||||
                client_name=^unknown$ ;                         \
 | 
			
		||||
                client_name=(\d+[\.-_]){4} ;                    \
 | 
			
		||||
                client_name=[\.-_](adsl|dynamic|ppp|)[\.-_] ;   \
 | 
			
		||||
        };
 | 
			
		||||
        &&GOAWAY { &&RBLS; &&DYNAMIC; };
 | 
			
		||||
        # rules
 | 
			
		||||
        &&GOAWAY ; action=REJECT dynamic client and listed on RBL</pre>
 | 
			
		||||
<p>Basically macros are simple text substitutions - see the <a href="#parser">PARSER</a> section for more information.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="command_line">COMMAND LINE</a></h2>
 | 
			
		||||
<p><em>Ruleset</em></p>
 | 
			
		||||
<p>The following arguments are used to specify the source of the postfwd ruleset. This means
 | 
			
		||||
that at least one of the following is required for postfwd to work.</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        -f, --file <file>
 | 
			
		||||
        Reads rules from <file>. Please see the CONFIGURATION section
 | 
			
		||||
        below for more information.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -r, --rule <rule>
 | 
			
		||||
        Adds <rule> to ruleset. Remember that you might have to quote
 | 
			
		||||
        strings that contain whitespaces or shell characters.</pre>
 | 
			
		||||
<p><em>Scoring</em></p>
 | 
			
		||||
<pre>
 | 
			
		||||
        -s, --scores <val>=<action>
 | 
			
		||||
        Returns <action> to postfix, when the request's score exceeds <val></pre>
 | 
			
		||||
<p>Multiple usage is allowed. Just chain your arguments, like:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd -r "<item>=<value>;action=<result>" -f <file> -f <file> ...
 | 
			
		||||
          or
 | 
			
		||||
        postfwd --scores 4.5="WARN high score" --scores 5.0="REJECT postfwd score too high" ...</pre>
 | 
			
		||||
<p>In case of multiple scores, the highest match will count. The order of the arguments will be
 | 
			
		||||
reflected in the postfwd ruleset.</p>
 | 
			
		||||
<p><em>Networking</em></p>
 | 
			
		||||
<p>postfwd can be run as daemon so that it listens on the network for incoming requests.
 | 
			
		||||
The following arguments will control it's behaviour in this case.</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        -d, --daemon
 | 
			
		||||
        postfwd will run as daemon and listen on the network for incoming
 | 
			
		||||
        queries (default 127.0.0.1:10040).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -i, --interface <dev>
 | 
			
		||||
        Bind postfwd to the specified interface (default 127.0.0.1).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -p, --port <port>
 | 
			
		||||
        postfwd listens on the specified port (default tcp/10040).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -u, --user <name>
 | 
			
		||||
        Changes real and effective user to <name>.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -g, --group <name>
 | 
			
		||||
        Changes real and effective group to <name>.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -R, --chroot <path>
 | 
			
		||||
        Chroot the process to the specified path.
 | 
			
		||||
        Test this before using - you might need some libs there.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -l, --logname <label>
 | 
			
		||||
        Labels the syslog messages. Useful when running multiple
 | 
			
		||||
        instances of postfwd.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --pidfile <path>
 | 
			
		||||
        The process id will be saved in the specified file.</pre>
 | 
			
		||||
<p><em>Optional arguments</em></p>
 | 
			
		||||
<p>These parameters influence the way postfwd is working. Any of them can be combined.</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        -v, --verbose
 | 
			
		||||
        Verbose logging displays a lot of useful information but can cause
 | 
			
		||||
        your logfiles to grow noticeably. So use it with caution. Set the option
 | 
			
		||||
        twice (-vv) to get more information (logs all request attributes).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -c, --cache <int>    (default=600)
 | 
			
		||||
        Timeout for request cache, results for identical requests will be
 | 
			
		||||
        cached until config is reloaded or this time (in seconds) expired.
 | 
			
		||||
        A setting of 0 disables this feature.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cache-no-size
 | 
			
		||||
        Ignores size attribute for cache comparisons which will lead to better
 | 
			
		||||
        cache-hit rates. You should set this option, if you don't use the size
 | 
			
		||||
        item in your ruleset.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cache-no-sender
 | 
			
		||||
        Ignores sender address for cache comparisons which will lead to better
 | 
			
		||||
        cache-hit rates. You should set this option, if you don't use the sender
 | 
			
		||||
        item in your ruleset.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cache-rdomain-only 
 | 
			
		||||
        This will strip the localpart of the recipient's address before filling the
 | 
			
		||||
        cache. This may considerably increase cache-hit rates.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cache-rbl-timeout <timeout>     (default=3600)
 | 
			
		||||
        This default value will be used as timeout in seconds for rbl cache items,
 | 
			
		||||
        if not specified in the ruleset.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cache-rbl-default <pattern>    (default=^127\.0\.0\.\d+$)
 | 
			
		||||
        Matches <pattern> to rbl/rhsbl answers (regexp) if not specified in the ruleset.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cacheid <item>, <item>, ...
 | 
			
		||||
        This csv-separated list of request attributes will be used to construct
 | 
			
		||||
        the request cache identifier. Use this only, if you know exactly what you
 | 
			
		||||
        are doing. If you, for example, use postfwd only for RBL/RHSBL control,
 | 
			
		||||
        you may set this to
 | 
			
		||||
                postfwd --cache=3600 --cacheid=client_name,client_address
 | 
			
		||||
        This increases efficiency of caching and improves postfwd's performance.
 | 
			
		||||
        Warning: You should list all items here, which are used in your ruleset!</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cleanup-requests <interval>    (default=600)
 | 
			
		||||
        The request cache will be searched for timed out items after this <interval> in
 | 
			
		||||
        seconds. It is a minimum value. The cleanup process will only take place, when
 | 
			
		||||
        a new request arrives.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cleanup-rbls <interval>    (default=600)
 | 
			
		||||
        The rbl cache will be searched for timed out items after this <interval> in
 | 
			
		||||
        seconds. It is a minimum value. The cleanup process will only take place, when
 | 
			
		||||
        a new request arrives.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --cleanup-rates <interval>    (default=600)
 | 
			
		||||
        The rate cache will be searched for timed out items after this <interval> in
 | 
			
		||||
        seconds. It is a minimum value. The cleanup process will only take place, when
 | 
			
		||||
        a new request arrives.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -S, --summary <int>    (default=600)
 | 
			
		||||
        Shows some usage statistics (program uptime, request counter, matching rules)
 | 
			
		||||
        every <int> seconds. This option is included by the -v switch.
 | 
			
		||||
        This feature uses the alarm signal, so you can force postfwd to dump the stats
 | 
			
		||||
        using `kill -ALRM <pid>` (where <pid> is the process id of postfwd).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Example:
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Counters: 213000 seconds uptime, 39 rules
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Requests: 71643 overall, 49 last interval, 62.88% cache hits
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Averages: 20.18 overall, 4.90 last interval, 557.30 top
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Contents: 44 cached requests, 239 cached dnsbl results
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Rule ID: R-001   matched: 2704 times
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Rule ID: R-002   matched: 9351 times
 | 
			
		||||
        Aug 19 12:39:45 mail1 postfwd[666]: [STATS] Rule ID: R-003   matched: 3116 times
 | 
			
		||||
        ...</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -L, --stdoutlog
 | 
			
		||||
        Redirects all syslog messages to stdout for debugging. Never use this with postfix!</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --shortlog
 | 
			
		||||
        As postfwd now logs all hits for a request, you might find it unecessary to log the
 | 
			
		||||
        postfwd actions jump(), set() and score(). You may disable it with this option.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -t, --test
 | 
			
		||||
        In test mode postfwd always returns "dunno", but logs according
 | 
			
		||||
        to it`s ruleset. -v will be set automatically with this option.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -n, --nodns
 | 
			
		||||
        Disables all DNS based checks like RBL checks. Rules containing
 | 
			
		||||
        such elements will be ignored.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --dns_queuesize   (default: 100)
 | 
			
		||||
        Sets the queue size for asynchonous dns queries. If the query exceeds this value,
 | 
			
		||||
        postfwd waits for answers of timeouts for previous queries.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --dns_retries     (default: 3)
 | 
			
		||||
        Sets the retry counter for asynchonous dns queries. This value will apply to
 | 
			
		||||
        every single query.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --dns_timeout     (default: 7)
 | 
			
		||||
        Sets the timeout for asynchonous dns queries in seconds. This value will apply to
 | 
			
		||||
        all dns items in a rule.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --dns_timeout_max    (default: 10)
 | 
			
		||||
        Sets the maximum timeout counter for dnsbl lookups. If the timeouts exceed this value
 | 
			
		||||
        the corresponding dnsbl will be deactivated for a while (see --dns_timeout_interval).</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        --dns_timeout_interval    (default=1200)
 | 
			
		||||
        The dnsbl timeout counter will be cleaned after this interval in seconds. Use this
 | 
			
		||||
        in conjunction with the --dns_timeout_max parameter.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -I, --instantcfg
 | 
			
		||||
        The config files, specified by -f will be re-read for every request
 | 
			
		||||
        postfwd receives. This enables on-the-fly configuration changes
 | 
			
		||||
        without restarting. Though files will be read only if necessary
 | 
			
		||||
        (which means their access times changed since last read) this might
 | 
			
		||||
        significantly increase system load.</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>
 | 
			
		||||
        -C, --showconfig
 | 
			
		||||
        Displays the current ruleset. Use -v for verbose output.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -P, --perfmon
 | 
			
		||||
        This option turns of any syslogging and output. It is included
 | 
			
		||||
        for performance testing.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -V, --version
 | 
			
		||||
        Displays the program version.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -h, --help
 | 
			
		||||
        Shows program usage.</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        -m, --manual
 | 
			
		||||
        Displays the program manual.</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="refresh">REFRESH</a></h2>
 | 
			
		||||
<p>In daemon mode postfwd reloads it's ruleset after receiving a HUP signal. Please see the description of
 | 
			
		||||
the '-I' switch to have your configuration refreshed for every request postfwd receives.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="examples">EXAMPLES</a></h2>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## whitelisting
 | 
			
		||||
        # 1. networks 192.168.1.0/24, 192.168.2.4
 | 
			
		||||
        # 2. client_names *.gmx.net and *.gmx.de
 | 
			
		||||
        # 3. sender *@someshop.tld from 11.22.33.44
 | 
			
		||||
        id=WL001; action=dunno ; client_address=192.168.1.0/24, 192.168.2.4
 | 
			
		||||
        id=WL002; action=dunno ; client_name=\.gmx\.(net|de)$
 | 
			
		||||
        id=WL003; action=dunno ; sender=@someshop\.tld$ ; client_address=11.22.33.44</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## TLS control
 | 
			
		||||
        # 1. *@authority.tld only with correct TLS fingerprint
 | 
			
		||||
        # 2. *@secret.tld only with keysizes >=64
 | 
			
		||||
        id=TL001; action=dunno                          ; sender=@authority\.tld$ ; ccert_fingerprint=AA:BB:CC..
 | 
			
		||||
        id=TL002; action=REJECT wrong TLS fingerprint   ; sender=@authority\.tld$
 | 
			
		||||
        id=TL003; action=REJECT tls keylength < 64      ; sender=@secret\.tld$ ; encryption_keysize=64</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Combined RBL checks
 | 
			
		||||
        # This will reject mail if
 | 
			
		||||
        # 1. listed on ix.dnsbl.manitu.net
 | 
			
		||||
        # 2. listed on zen.spamhaus.org (sbl and xbl, dns cache timeout 1200s instead of 3600s)
 | 
			
		||||
        # 3. listed on min 2 of bl.spamcop.net, list.dsbl.org, dnsbl.sorbs.net
 | 
			
		||||
        # 4. listed on bl.spamcop.net and one of rhsbl.ahbl.org, rhsbl.sorbs.net
 | 
			
		||||
        id=RBL01 ; action=REJECT listed on ix.dnsbl.manitu.net  ; rbl=ix.dnsbl.manitu.net
 | 
			
		||||
        id=RBL02 ; action=REJECT listed on zen.spamhaus.org     ; rbl=zen.spamhaus.org/127.0.0.[2-8]/1200
 | 
			
		||||
        id=RBL03 ; action=REJECT listed on too many RBLs        ; rblcount=2 ; rbl=bl.spamcop.net, list.dsbl.org, dnsbl.sorbs.net
 | 
			
		||||
        id=RBL04 ; action=REJECT combined RBL+RHSBL check       ; rbl=bl.spamcop.net ; rhsbl=rhsbl.ahbl.org, rhsbl.sorbs.net</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Message size (requires message_size_limit to be set to 30000000)
 | 
			
		||||
        # 1. 30MB for systems in *.customer1.tld
 | 
			
		||||
        # 2. 20MB for SASL user joejob
 | 
			
		||||
        # 3. 10MB default
 | 
			
		||||
        id=SZ001; state==END-OF-MESSAGE; action=REJECT message too large; size=30000000 ; client_name=\.customer1.tld$
 | 
			
		||||
        id=SZ002; state==END-OF-MESSAGE; action=REJECT message too large; size=20000000 ; sasl_username==joejob
 | 
			
		||||
        id=SZ003; state==END-OF-MESSAGE; action=REJECT message too large; size=10000000</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Selective Greylisting
 | 
			
		||||
        # 1. if listed on zen.spamhaus.org with results 127.0.0.10 or .11, dns cache timeout 1200s
 | 
			
		||||
        # 2. Client has no rDNS
 | 
			
		||||
        # 3. Client comes from several dialin domains
 | 
			
		||||
        id=GR001; action=greylisting ; rbl=dul.dnsbl.sorbs.net, zen.spamhaus.org/127.0.0.1[01]/1200
 | 
			
		||||
        id=GR002; action=greylisting ; client_name=^unknown$
 | 
			
		||||
        id=GR003; action=greylisting ; client_name=\.(t-ipconnect|alicedsl|ish)\.de$</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Date Time
 | 
			
		||||
        date=24.12.2007-26.12.2007          ;  action=450 4.7.1 office closed during christmas
 | 
			
		||||
        time=04:00:00-05:00:00              ;  action=450 4.7.1 maintenance ongoing, try again later
 | 
			
		||||
        time=-07:00:00 ;  sasl_username=jim ;  action=450 4.7.1 to early for you, jim
 | 
			
		||||
        time=22:00:00- ;  sasl_username=jim ;  action=450 4.7.1 to late now, jim
 | 
			
		||||
        months=-Apr                         ;  action=450 4.7.1 see you in may
 | 
			
		||||
        days=!!Mon-Fri                      ;  action=greylist</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Usage of jump
 | 
			
		||||
        # The following allows a message size of 30MB for different
 | 
			
		||||
        # users/clients while others will only have 10MB.
 | 
			
		||||
        id=R001 ; action=jump(R100) ; sasl_username=^(Alice|Bob|Jane)$
 | 
			
		||||
        id=R002 ; action=jump(R100) ; client_address=192.168.1.0/24
 | 
			
		||||
        id=R003 ; action=jump(R100) ; ccert_fingerprint=AA:BB:CC:DD:...
 | 
			
		||||
        id=R004 ; action=jump(R100) ; ccert_fingerprint=AF:BE:CD:DC:...
 | 
			
		||||
        id=R005 ; action=jump(R100) ; ccert_fingerprint=DD:CC:BB:DD:...
 | 
			
		||||
        id=R099 ; state==END-OF-MESSAGE; action=REJECT message too big (max. 10MB); size=10000000
 | 
			
		||||
        id=R100 ; state==END-OF-MESSAGE; action=REJECT message too big (max. 30MB); size=30000000</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Usage of score
 | 
			
		||||
        # The following rejects a mail, if the client
 | 
			
		||||
        # - is listed on 1 RBL and 1 RHSBL
 | 
			
		||||
        # - is listed in 1 RBL or 1 RHSBL and has no correct rDNS
 | 
			
		||||
        # - other clients without correct rDNS will be greylist-checked
 | 
			
		||||
        # - some whitelists are used to lower the score
 | 
			
		||||
        id=S01 ; score=2.6              ; action=greylisting
 | 
			
		||||
        id=S02 ; score=5.0              ; action=REJECT postfwd score too high
 | 
			
		||||
        id=R00 ; action=score(-1.0)     ; rbl=exemptions.ahbl.org,list.dnswl.org,query.bondedsender.org,spf.trusted-forwarder.org
 | 
			
		||||
        id=R01 ; action=score(2.5)      ; rbl=bl.spamcop.net, list.dsbl.org, dnsbl.sorbs.net
 | 
			
		||||
        id=R02 ; action=score(2.5)      ; rhsbl=rhsbl.ahbl.org, rhsbl.sorbs.net
 | 
			
		||||
        id=N01 ; action=score(-0.2)     ; client_name==$$helo_name
 | 
			
		||||
        id=N02 ; action=score(2.7)      ; client_name=^unknown$
 | 
			
		||||
        ...</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Usage of rate and size
 | 
			
		||||
        # The following temporary rejects requests from "unknown" clients, if they
 | 
			
		||||
        # 1. exceeded 30 requests per hour or
 | 
			
		||||
        # 2. tried to send more than 1.5mb within 10 minutes
 | 
			
		||||
        id=RATE01 ;  client_name==unknown ;  state==RCPT ; \
 | 
			
		||||
                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 ; \
 | 
			
		||||
                action==size($$client_address/1572864/600/450 4.7.1 sorry, max 1.5mb per 10 minutes)</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Macros
 | 
			
		||||
        # definition
 | 
			
		||||
        &&RBLS { rbl=zen.spamhaus.org,list.dsbl.org,bl.spamcop.net,dnsbl.sorbs.net,ix.dnsbl.manitu.net; };
 | 
			
		||||
        &&GONOW { action=REJECT your request caused our spam detection policy to reject this message. More info at <a href="http://www.domain.local">http://www.domain.local</a>; };
 | 
			
		||||
        # rules
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=^unknown$
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=(\d+[\.-_]){4}
 | 
			
		||||
        &&GONOW ;  &&RBLS ;  client_name=[\.-_](adsl|dynamic|ppp|)[\.-_]</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        ## Groups
 | 
			
		||||
        # definition
 | 
			
		||||
        &&RBLS { \
 | 
			
		||||
                rbl=zen.spamhaus.org ;          \
 | 
			
		||||
                rbl=list.dsbl.org ;             \
 | 
			
		||||
                rbl=bl.spamcop.net ;            \
 | 
			
		||||
                rbl=dnsbl.sorbs.net ;           \
 | 
			
		||||
                rbl=ix.dnsbl.manitu.net ;       \
 | 
			
		||||
        };
 | 
			
		||||
        &&RHSBLS { \
 | 
			
		||||
                ...
 | 
			
		||||
        };
 | 
			
		||||
        &&DYNAMIC { \
 | 
			
		||||
                client_name==unknown ;                          \
 | 
			
		||||
                client_name~=(\d+[\.-_]){4} ;                   \
 | 
			
		||||
                client_name~=[\.-_](adsl|dynamic|ppp|)[\.-_] ;  \
 | 
			
		||||
                ...
 | 
			
		||||
        };
 | 
			
		||||
        &&BAD_HELO { \
 | 
			
		||||
                helo_name==my.name.tld;         \
 | 
			
		||||
                helo_name~=^([^\.]+)$;          \
 | 
			
		||||
                helo_name~=\.(local|lan)$;      \
 | 
			
		||||
                ...
 | 
			
		||||
        };
 | 
			
		||||
        &&MAINTENANCE { \
 | 
			
		||||
                date=15.01.2007  ; \
 | 
			
		||||
                date=15.04.2007  ; \
 | 
			
		||||
                date=15.07.2007  ; \
 | 
			
		||||
                date=15.10.2007  ; \
 | 
			
		||||
                time=03:00:00-04:00:00 ; \
 | 
			
		||||
        };
 | 
			
		||||
        # rules
 | 
			
		||||
        id=COMBINED    ;  &&RBLS ;  &&DYNAMIC ;  action=REJECT dynamic client and listed on RBL
 | 
			
		||||
        id=MAINTENANCE ;  &&MAINTENANCE       ;  action=DEFER maintenance time - please try again later
 | 
			
		||||
        
 | 
			
		||||
        # now with the set() command, note that long item
 | 
			
		||||
        # lists don't have to be compared twice
 | 
			
		||||
        id=RBL01    ;  &&RBLS      ;  action=set(HIT_rbls=1)
 | 
			
		||||
        id=HELO01   ;  &&BAD_HELO  ;  action=set(HIT_helo=1)
 | 
			
		||||
        id=DYNA01   ;  &&DYNAMIC   ;  action=set(HIT_dyna=1)
 | 
			
		||||
        id=REJECT01 ;  HIT_rbls==1 ;  HIT_helo==1  ; action=REJECT please see <a href="http://some.org/info?reject=01">http://some.org/info?reject=01</a> for more info
 | 
			
		||||
        id=REJECT02 ;  HIT_rbls==1 ;  HIT_dyna==1  ; action=REJECT please see <a href="http://some.org/info?reject=02">http://some.org/info?reject=02</a> for more info
 | 
			
		||||
        id=REJECT03 ;  HIT_helo==1 ;  HIT_dyna==1  ; action=REJECT please see <a href="http://some.org/info?reject=03">http://some.org/info?reject=03</a> for more info</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        # combined with enhanced rbl features
 | 
			
		||||
        # set vals
 | 
			
		||||
        id=RBL01 ; rhsblcount=all ; rblcount=all ; &&RBLS ; &&RHSBLS ; \
 | 
			
		||||
          action=set(HIT_rhls=$$rhsblcount,HIT_rbls=$$rblcount)
 | 
			
		||||
        # compare
 | 
			
		||||
        id=RBL02 ; HIT_rhls>=1 ; HIT_rbls>=1 ; action=554 5.7.1 blocked using $$HIT_rhls RHSBLs and $$HIT_rbls RBLs
 | 
			
		||||
        id=RBL03 ; HIT_rhls>=2               ; action=554 5.7.1 blocked using $$HIT_rhls RHSBLs
 | 
			
		||||
        id=RBL04 ; HIT_rbls>=2               ; action=554 5.7.1 blocked using $$HIT_rbls RBLs</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="parser">PARSER</a></h2>
 | 
			
		||||
<p><em>Configuration</em></p>
 | 
			
		||||
<p>The postfwd ruleset can be specified at the commandline (-r option) or be read from files (-f). The order of your arguments will be kept. You should
 | 
			
		||||
check the parser with the -C | --showconfig switch at the command line before applying a new config. The following call:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd --showconfig \
 | 
			
		||||
                -r "id=TEST; recipient_count=100; action=WARN mail with 100+ recipients" \
 | 
			
		||||
                -f /etc/postfwd.cf \
 | 
			
		||||
                -r "id=DEFAULT; action=dunno";</pre>
 | 
			
		||||
<p>will produce the following output:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Rule   0: id->"TEST" action->"WARN mail with 100+ recipients"; recipient_count->"100"
 | 
			
		||||
        ...
 | 
			
		||||
        ... <content of /etc/postfwd.cf> ...
 | 
			
		||||
        ...
 | 
			
		||||
        Rule <n>: id->"DEFAULT" action->"dunno"</pre>
 | 
			
		||||
<p>Multiple items of the same type will be added to lists (see the <a href="#items">ITEMS</a> section for more info):</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd --showconfig \
 | 
			
		||||
                -r "client_address=192.168.1.0/24; client_address=172.16.26.32; action=dunno"</pre>
 | 
			
		||||
<p>will result in:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Rule   0: id->"R-0"; action->"dunno"; client_address->"192.168.1.0/24, 172.16.26.32"</pre>
 | 
			
		||||
<p>Macros are evaluated at configuration stage, which means that</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd --showconfig \
 | 
			
		||||
                -r "&&RBLS { rbl=bl.spamcop.net; client_name=^unknown$; };" \
 | 
			
		||||
                -r "id=RBL001; &&RBLS; action=REJECT listed on spamcop and bad rdns";</pre>
 | 
			
		||||
<p>will result in:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Rule   0: id->"RBL001"; action->"REJECT listed on spamcop and bad rdns"; rbl->"bl.spamcop.net"; client_name->"^unknown$"</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>
 | 
			
		||||
<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>
 | 
			
		||||
<p>equals to</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        id=R001; sender=bob@alice.local; client_address=192.168.1.1; action=dunno</pre>
 | 
			
		||||
<p>Lists will be evaluated in the specified order. This allows to place faster expressions at first:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd -vv -L -r "id=RBL001; rbl=localrbl.local zen.spamhaus.org; action=REJECT" /root/request.sample</pre>
 | 
			
		||||
<p>produces the following</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        [LOGS info]: compare rbl: "remotehost.remote.net[68.10.1.7]"  ->  "localrbl.local"
 | 
			
		||||
        [LOGS info]: count1 rbl:  "2"  ->  "0"
 | 
			
		||||
        [LOGS info]: query rbl:   localrbl.local 7.1.10.68 (7.1.10.68.localrbl.local)
 | 
			
		||||
        [LOGS info]: count2 rbl:  "2"  ->  "0"
 | 
			
		||||
        [LOGS info]: match rbl:   FALSE
 | 
			
		||||
        [LOGS info]: compare rbl: "remotehost.remote.net[68.10.1.7]"  ->  "zen.spamhaus.org"
 | 
			
		||||
        [LOGS info]: count1 rbl:  "2"  ->  "0"
 | 
			
		||||
        [LOGS info]: query rbl:   zen.spamhaus.org 7.1.10.68 (7.1.10.68.zen.spamhaus.org)
 | 
			
		||||
        [LOGS info]: count2 rbl:  "2"  ->  "0"
 | 
			
		||||
        [LOGS info]: match rbl:   FALSE
 | 
			
		||||
        [LOGS info]: Action: dunno</pre>
 | 
			
		||||
<p>The negation operator !!(<value>) has the highest priority and therefore will be evaluated first. Then variable substitutions are performed:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd -vv -L -r "id=TEST; action=REJECT; client_name=!!($$heloname)" /root/request.sample</pre>
 | 
			
		||||
<p>will give</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        [LOGS info]: compare client_name:     "unknown"  ->  "!!($$helo_name)"
 | 
			
		||||
        [LOGS info]: negate client_name:      "unknown"  ->  "$$helo_name"
 | 
			
		||||
        [LOGS info]: substitute client_name:  "unknown"  ->  "english-breakfast.cloud8.net"
 | 
			
		||||
        [LOGS info]: match client_name:  TRUE
 | 
			
		||||
        [LOGS info]: Action: REJECT</pre>
 | 
			
		||||
<p><em>Ruleset evaluation</em></p>
 | 
			
		||||
<p>A rule hits when all items (or at least one element of a list for each item) have matched. As soon as one item (or all elements of a list) fails
 | 
			
		||||
to compare against the request attribute the parser will jump to the next rule in the postfwd ruleset.</p>
 | 
			
		||||
<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(), ...)
 | 
			
		||||
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
 | 
			
		||||
simply place a last `catch-all´ rule to change that behaviour:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        ... <your rules> ...
 | 
			
		||||
        id=DEFAULT ;  action=dunno</pre>
 | 
			
		||||
<p>will log any request that passes the ruleset without having hit a prior rule.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="integration">INTEGRATION</a></h2>
 | 
			
		||||
<p><em>Integration via daemon mode</em></p>
 | 
			
		||||
<p>The common way to use postfwd is to start it as daemon, listening at a specified tcp port.
 | 
			
		||||
As postfwd will run in a single instance (multiplexing mode), it will take most benefit of
 | 
			
		||||
it`s internal caching in that case. Start postfwd with the following parameters:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        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>
 | 
			
		||||
<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>
 | 
			
		||||
<pre>
 | 
			
		||||
        tcp  0  0  127.0.0.1:10040  0.0.0.0:*  LISTEN</pre>
 | 
			
		||||
<p>If everything works, open your postfix main.cf and insert the following</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        127.0.0.1:10040_time_limit      = 3600                                          <--- integration
 | 
			
		||||
        smtpd_recipient_restrictions    = permit_mynetworks                             <--- recommended
 | 
			
		||||
                                          reject_unauth_destination                     <--- recommended
 | 
			
		||||
                                          check_policy_service inet:127.0.0.1:10040     <--- integration</pre>
 | 
			
		||||
<p>Reload your configuration with `postfix reload` and watch your logs. In it works you should see
 | 
			
		||||
lines like the following in your mail log:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Aug  9 23:01:24 mail postfwd[5158]: rule=22, id=ML_POSTFIX, client=english-breakfast.cloud9.net[168.100.1.7], sender=owner-postfix-users@postfix.tld, recipient=someone@domain.local, helo=english-breakfast.cloud9.net, proto=ESMTP, state=RCPT, action=dunno</pre>
 | 
			
		||||
<p>If you want to check for size or rcpt_count items you must integrate postfwd in smtp_data_restrictions or
 | 
			
		||||
smtpd_end_of_data_restrictions. Of course you can also specify a restriction class and use it in your access
 | 
			
		||||
tables. First create a file /etc/postfix/policy containing:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        domain1.local           postfwdcheck
 | 
			
		||||
        domain2.local           postfwdcheck
 | 
			
		||||
        ...</pre>
 | 
			
		||||
<p>Then postmap that file (`postmap hash:/etc/postfix/policy`), open your main.cf and enter</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # Restriction Classes
 | 
			
		||||
        smtpd_restriction_classes       = postfwdcheck, <some more>...                          <--- integration
 | 
			
		||||
        postfwdcheck                    = check_policy_service inet:127.0.0.1:10040             <--- integration</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        127.0.0.1:10040_time_limit      = 3600                                                  <--- integration
 | 
			
		||||
        smtpd_recipient_restrictions    = permit_mynetworks,                                    <--- recommended
 | 
			
		||||
                                          reject_unauth_destination,                            <--- recommended
 | 
			
		||||
                                          ...                                                   <--- optional
 | 
			
		||||
                                          check_recipient_access hash:/etc/postfix/policy,      <--- integration
 | 
			
		||||
                                          ...                                                   <--- optional</pre>
 | 
			
		||||
<p>Reload postfix and watch your logs.</p>
 | 
			
		||||
<p><em>Integration via xinetd</em></p>
 | 
			
		||||
<p>There might be several reasons for you to use postfwd via a tcp wrapper package like xinetd (see <a href="http://www.xinetd.org/">http://www.xinetd.org/</a>).
 | 
			
		||||
I won`t discuss that here. If you plan to do so, just add the following line to your /etc/services file:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # postfwd port
 | 
			
		||||
        postfwd     10040/tcp</pre>
 | 
			
		||||
<p>Then create a file '/etc/xinetd.d/postfwd':</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        {
 | 
			
		||||
                interface       = 127.0.0.1
 | 
			
		||||
                socket_type     = stream
 | 
			
		||||
                protocol        = tcp
 | 
			
		||||
                wait            = no
 | 
			
		||||
                user            = nobody
 | 
			
		||||
                server          = /usr/local/bin/postfwd
 | 
			
		||||
                server_args     = -f /etc/postfwd.cf
 | 
			
		||||
                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>
 | 
			
		||||
<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>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="testing">TESTING</a></h2>
 | 
			
		||||
<p>First you have to create a ruleset (see Configuration section). Check it with</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd -f /etc/postfwd.cf -C</pre>
 | 
			
		||||
<p>There is an example policy request distributed with postfwd, called 'request.sample'.
 | 
			
		||||
Simply change it to meet your requirements and use</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        postfwd -f /etc/postfwd.cf <request.sample</pre>
 | 
			
		||||
<p>You should get an answer like</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        action=<whateveryouconfigured></pre>
 | 
			
		||||
<p>For network tests I use netcat:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        nc 127.0.0.1 10040 <request.sample</pre>
 | 
			
		||||
<p>to send a request to postfwd. If you receive nothing, make sure that postfwd is running and
 | 
			
		||||
listening on the specified network settings.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="performance">PERFORMANCE</a></h2>
 | 
			
		||||
<p>Some of these proposals might not match your environment. Please check your requirements and test new options carefully!</p>
 | 
			
		||||
<p>- use caching options
 | 
			
		||||
- use the correct match operator ==, <=, >=
 | 
			
		||||
- use ^ and $ in regular expressions
 | 
			
		||||
- use item lists (faster than single rules)
 | 
			
		||||
- use <code>set()</code> action on repeated item lists
 | 
			
		||||
- use jump action
 | 
			
		||||
- use pre-lookup rule for rbl/rhsbls with empty <code>note()</code> action</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="see_also">SEE ALSO</a></h2>
 | 
			
		||||
<p>See <a href="http://www.postfix.org/SMTPD_POLICY_README.html">http://www.postfix.org/SMTPD_POLICY_README.html</a> for a description
 | 
			
		||||
of how Postfix policy servers work.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="license">LICENSE</a></h1>
 | 
			
		||||
<p>postfwd is free software and released under BSD license, which basically means
 | 
			
		||||
that you can do what you want as long as you keep the copyright notice:</p>
 | 
			
		||||
<p>Copyright (c) 2007, Jan Peter Kessler
 | 
			
		||||
All rights reserved.</p>
 | 
			
		||||
<p>Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
 * Redistributions of source code must retain the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer in
 | 
			
		||||
   the documentation and/or other materials provided with the
 | 
			
		||||
   distribution.
 | 
			
		||||
 * Neither the name of the authors nor the names of his contributors
 | 
			
		||||
   may be used to endorse or promote products derived from this
 | 
			
		||||
   software without specific prior written permission.</pre>
 | 
			
		||||
<p>THIS SOFTWARE IS PROVIDED BY ME ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="author">AUTHOR</a></h1>
 | 
			
		||||
<p>Jan Peter Kessler <info (AT) postfwd (DOT) org>. Let me know, if you have any suggestions.</p>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										1053
									
								
								doc/postfwd.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1053
									
								
								doc/postfwd.txt
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										120
									
								
								etc/postfwd.cf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								etc/postfwd.cf
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,120 @@
 | 
			
		|||
#################################################################################################
 | 
			
		||||
##
 | 
			
		||||
##   ATTENTION: This example configuration uses features which require postfwd 1.10pre6!
 | 
			
		||||
##              Please see the manual ('postfwd -m') for example syntax for prior versions.
 | 
			
		||||
##
 | 
			
		||||
#################################################################################################
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
## Definitions
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
# Maintenance times
 | 
			
		||||
&&MAINTENANCE { \
 | 
			
		||||
        date=15.01.2007  ; \
 | 
			
		||||
        date=15.04.2007  ; \
 | 
			
		||||
        date=15.07.2007  ; \
 | 
			
		||||
        date=15.10.2007  ; \
 | 
			
		||||
        time=03:00:00-04:00:00 ; \
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# Whitelists
 | 
			
		||||
&&TRUSTED_NETS { \
 | 
			
		||||
        client_address=192.168.1.0/22 ;   \
 | 
			
		||||
        client_address=172.16.128.32/27 ; \
 | 
			
		||||
};
 | 
			
		||||
&&TRUSTED_HOSTS { \
 | 
			
		||||
        client_name~=\.domain1\.net$ ; \
 | 
			
		||||
        client_name~=\.domain2\.de$ ;  \
 | 
			
		||||
};
 | 
			
		||||
&&TRUSTED_USERS { \
 | 
			
		||||
        sasl_username==bob ; \
 | 
			
		||||
        sasl_username==alice ; \
 | 
			
		||||
};
 | 
			
		||||
&&TRUSTED_TLS { \
 | 
			
		||||
        ccert_fingerprint==11:22:33:44:55:66:AA:BB:CC:DD:EE:FF ; \
 | 
			
		||||
        ccert_fingerprint==AA:BB:CC:DD:EE:FF:11:22:33:44:55:66 ; \
 | 
			
		||||
        encryption_keysize>=64 ; \
 | 
			
		||||
};
 | 
			
		||||
&&FREEMAIL { \
 | 
			
		||||
        client_name~=\.gmx\.net$ ; \
 | 
			
		||||
        client_name~=\.web\.de$ ;  \
 | 
			
		||||
        client_name~=\.(aol|yahoo|h(ush|ot)mail)\.com$ ; \
 | 
			
		||||
};
 | 
			
		||||
&&STATIC { \
 | 
			
		||||
        # contains freemailers
 | 
			
		||||
        &&FREEMAIL ; \
 | 
			
		||||
        client_name~=[\.\-]static[[\.\-] ;               \
 | 
			
		||||
        client_name~=^(mail|smtp|mout|mx)[\-]*[0-9]*\. ; \
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# Spamchecks
 | 
			
		||||
&&BADHELO { \
 | 
			
		||||
	client_name==!!($$(helo_name)) ; \
 | 
			
		||||
};
 | 
			
		||||
&&DYNAMIC { \
 | 
			
		||||
        client_name==unknown ; \
 | 
			
		||||
        client_name~=(\-.+){4} ; \
 | 
			
		||||
        client_name~=\d{5} ;     \
 | 
			
		||||
        client_name~=[_\.\-]([axt]{0,1}dsl|br(e|oa)dband|ppp|pppoe|dynamic|dynip|ADSL|dial(up|in)|pool|dhcp|leased)[_\.\-] ; \
 | 
			
		||||
};
 | 
			
		||||
&&RBLS { \
 | 
			
		||||
        rbl=zen.spamhaus.org ;     \
 | 
			
		||||
        rbl=list.dsbl.org ;        \
 | 
			
		||||
        rbl=bl.spamcop.net ;       \
 | 
			
		||||
        rbl=dnsbl.sorbs.net ;      \
 | 
			
		||||
        rbl=ix.dnsbl.manitu.net ;  \
 | 
			
		||||
};
 | 
			
		||||
&&RHSBLS { \
 | 
			
		||||
        rhsbl=rddn.dnsbl.net.au ; \
 | 
			
		||||
        rhsbl=rhsbl.ahbl.org ; \
 | 
			
		||||
        rhsbl=rhsbl.sorbs.net ; \
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
## Ruleset
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
# temporary reject and drop connection during maintenance window
 | 
			
		||||
id=M_001    ;  &&MAINTENANCE      ;  action=421 maintenance - please try again later
 | 
			
		||||
 | 
			
		||||
# stress-friendly behaviour (will not match on postfix version pre 2.5)
 | 
			
		||||
id=STRESS   ;  stress==yes        ;  action=dunno
 | 
			
		||||
 | 
			
		||||
# Whitelists
 | 
			
		||||
id=WL_001   ;  &&TRUSTED_NETS     ;  action=dunno
 | 
			
		||||
id=WL_002   ;  &&TRUSTED_HOSTS    ;  action=dunno
 | 
			
		||||
id=WL_003   ;  &&TRUSTED_USERS    ;  action=dunno
 | 
			
		||||
id=WL_004   ;  &&TRUSTED_TLS      ;  action=dunno
 | 
			
		||||
 | 
			
		||||
# DNSBL checks
 | 
			
		||||
id=RBL_001  ;  &&RHSBLS ; &&RBLS ; \
 | 
			
		||||
               rhsblcount=all ; rblcount=all ; \
 | 
			
		||||
               action=set(HIT_rhls=$$rhsblcount,HIT_rbls=$$rblcount)
 | 
			
		||||
id=RBL_002  ;  HIT_rhls>=1 ; HIT_rbls>=1 ;  action=554 5.7.1 blocked using $$HIT_rhls RHSBLs and $$HIT_rbls RBLs
 | 
			
		||||
id=RBL_003  ;  HIT_rhls>=2               ;  action=554 5.7.1 blocked using $$HIT_rhls RHSBLs
 | 
			
		||||
id=RBL_004  ;  HIT_rbls>=2               ;  action=554 5.7.1 blocked using $$HIT_rbls RBLs
 | 
			
		||||
id=RBL_005  ;  HIT_rbls>=1 ; &&DYNAMIC   ;  action=REJECT listed on RBL and $$client_name looks like dynip
 | 
			
		||||
id=RBL_006  ;  HIT_rhls>=1 ; &&DYNAMIC   ;  action=REJECT listed on RHSBL and $$client_name looks like dynip
 | 
			
		||||
id=RBL_007  ;  HIT_rbls>=1 ; &&BADHELO   ;  action=REJECT listed on RBL and $$helo_name does not match $$client_name
 | 
			
		||||
id=RBL_008  ;  HIT_rhls>=1 ; &&BADHELO   ;  action=REJECT listed on RHSBL and $$helo_name does not match $$client_name
 | 
			
		||||
 | 
			
		||||
# Rate limits
 | 
			
		||||
id=RATE_001 ;  &&DYNAMIC                 ;  action=rate($$client_address/1/300/450 4.7.1 please do not send more than once per 5 minutes)
 | 
			
		||||
id=RATE_002 ;  HIT_rhls>=1               ;  action=rate($$client_address/1/300/450 4.7.1 please do not send more than once per 5 minutes)
 | 
			
		||||
id=RATE_003 ;  HIT_rbls>=1               ;  action=rate($$client_address/1/300/450 4.7.1 please do not send more than once per 5 minutes)
 | 
			
		||||
id=RATE_004 ; sasl_username==boss        ;  action=size($$sasl_username/30000000/300/450 4.7.1 please do not send more than 30mb within 5 minutes)
 | 
			
		||||
id=RATE_005 ; sasl_username~=\w          ;  action=size($$sasl_username/10000000/300/450 4.7.1 please do not send more than 10mb within 5 minutes)
 | 
			
		||||
 | 
			
		||||
# Selective greylisting
 | 
			
		||||
id=GREY_001 ;  action=dunno              ;  &&STATIC
 | 
			
		||||
id=GREY_002 ;  action=dunno              ;  $$client_name~=$$(sender_domain)$
 | 
			
		||||
id=GREY_003 ;  action=greylisting        ;  &&DYNAMIC
 | 
			
		||||
id=GREY_004 ;  action=greylisting        ;  HIT_rhls>=1
 | 
			
		||||
id=GREY_005 ;  action=greylisting        ;  HIT_rbls>=1
 | 
			
		||||
# greylisting should be safe during out-of-office times
 | 
			
		||||
id=GREY_006 ;  action=greylisting        ;  days=Sat-Sun
 | 
			
		||||
id=GREY_007 ;  action=greylisting        ;  days=Mon-Fri ; time=!!06:00:00-20:00:00
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1388
									
								
								man/man8/postfwd.8
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1388
									
								
								man/man8/postfwd.8
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										2732
									
								
								sbin/postfwd
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										2732
									
								
								sbin/postfwd
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										13
									
								
								tools/README.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tools/README.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
Directory contents:
 | 
			
		||||
 | 
			
		||||
-	lograte.sh [OPTIONS] <logfile>
 | 
			
		||||
	generates per minute stats for generic syslog files
 | 
			
		||||
 | 
			
		||||
-	postfwd-rblcheck.pl <hostname or ip> [<hostname or ip> ...]
 | 
			
		||||
	queries a bunch of dnsbls for the given host(s)
 | 
			
		||||
 | 
			
		||||
-	request.sample
 | 
			
		||||
	a sample policy delegation request. you may test your postfwd config with
 | 
			
		||||
 	  postfwd -f <configfile> request.sample
 | 
			
		||||
 | 
			
		||||
by JPK
 | 
			
		||||
							
								
								
									
										90
									
								
								tools/lograte.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										90
									
								
								tools/lograte.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# generates per minute stats for generic syslog files
 | 
			
		||||
# call it:
 | 
			
		||||
#
 | 
			
		||||
#	lograte.sh [OPTIONS] <logfile>
 | 
			
		||||
#
 | 
			
		||||
# or for online monitoring
 | 
			
		||||
#
 | 
			
		||||
#	tail -f <logfile> | lograte.sh [OPTIONS]
 | 
			
		||||
#
 | 
			
		||||
# by JPK
 | 
			
		||||
 | 
			
		||||
PATH=/usr/local/bin:/bin:/usr/bin
 | 
			
		||||
 | 
			
		||||
# default values
 | 
			
		||||
PATTERN=".*"
 | 
			
		||||
MINIMUM=1
 | 
			
		||||
TOPLIST=10
 | 
			
		||||
 | 
			
		||||
# show usage
 | 
			
		||||
Usage () {
 | 
			
		||||
	{
 | 
			
		||||
		echo "Usage:   `basename $0` -m <mincount> -t <topcount> -s <filter> <file> <file> ...";
 | 
			
		||||
		echo "	-m 	minimum events to display"
 | 
			
		||||
		echo "	-t 	how many rankings?"
 | 
			
		||||
		echo "	-T 	print rankings only"
 | 
			
		||||
		echo "	-s 	filter input through this regexp"
 | 
			
		||||
		echo "Example: `basename $0` -m 10 -t 5 -s \"(panic|error)\" /var/log/messages"
 | 
			
		||||
	} >&2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# parse arguments
 | 
			
		||||
while getopts Tt:m:s: o
 | 
			
		||||
do	case "$o" in
 | 
			
		||||
	s)	PATTERN="$OPTARG";;
 | 
			
		||||
	m)	MINIMUM="$OPTARG";;
 | 
			
		||||
	t)	TOPLIST="$OPTARG";;
 | 
			
		||||
	T)	TOPONLY=1;;
 | 
			
		||||
	*)	Usage;
 | 
			
		||||
		exit 1;;
 | 
			
		||||
	esac
 | 
			
		||||
done
 | 
			
		||||
shift `expr $OPTIND - 1`
 | 
			
		||||
 | 
			
		||||
# a single awk
 | 
			
		||||
awk '	($0 ~ PATTERN) {
 | 
			
		||||
		split($3,TIME,":");
 | 
			
		||||
		CURRTIME=$1 " " $2 " " TIME[1] ":" TIME[2];
 | 
			
		||||
		if (LASTTIME != CURRTIME) {
 | 
			
		||||
			if (COUNT >= MINIMUM) {
 | 
			
		||||
				if (!(TOPONLY == 1)) {
 | 
			
		||||
					printf ( "%s %7d events, %8.2f per sec\n", LASTTIME, COUNT, ( COUNT / 60 ) );
 | 
			
		||||
				};
 | 
			
		||||
				for (i=1;i<=TOPLIST;i++) {
 | 
			
		||||
					if (COUNT > MAXCOUNT[i]) {
 | 
			
		||||
						MAXCOUNT[i+1]=MAXCOUNT[i];
 | 
			
		||||
						MAXCOUNT[i]=COUNT;
 | 
			
		||||
						MAXTIME[i+1]=MAXTIME[i];
 | 
			
		||||
						MAXTIME[i]=LASTTIME;
 | 
			
		||||
						break;
 | 
			
		||||
					};
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
			COUNT=1;
 | 
			
		||||
		} else {
 | 
			
		||||
			COUNT++;
 | 
			
		||||
		};
 | 
			
		||||
		LASTTIME=CURRTIME;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	END {
 | 
			
		||||
		if (CURRTIME != "") {
 | 
			
		||||
			if ( (COUNT >= MINIMUM) && (!(TOPONLY == 1)) ) {
 | 
			
		||||
				printf ( "%s %7d events, %8.2f per sec\n\n", LASTTIME, COUNT, ( COUNT / 60 ) );
 | 
			
		||||
			};
 | 
			
		||||
			print "###########";
 | 
			
		||||
			printf ("# TOP %3d #\n",TOPLIST);
 | 
			
		||||
			print "###########";
 | 
			
		||||
			for (i=1;i<=TOPLIST;i++) {
 | 
			
		||||
				printf ( "# TOP %3d:\t%s %7d events, %8.2f per sec\n", i, MAXTIME[i], MAXCOUNT[i], ( MAXCOUNT[i] / 60 ) );;
 | 
			
		||||
			};
 | 
			
		||||
			exit 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			exit 1;
 | 
			
		||||
		};
 | 
			
		||||
	}' PATTERN="${PATTERN}" MINIMUM="${MINIMUM}" TOPLIST="${TOPLIST}" TOPONLY="${TOPONLY}" $*
 | 
			
		||||
 | 
			
		||||
# set exitcode=1 if no matching lines found
 | 
			
		||||
exit $?
 | 
			
		||||
							
								
								
									
										174
									
								
								tools/postfwd-rblcheck.pl
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										174
									
								
								tools/postfwd-rblcheck.pl
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,174 @@
 | 
			
		|||
#!/usr/bin/perl -T -w
 | 
			
		||||
#
 | 
			
		||||
# Tool to query a bunch of dnsbls. Usage:
 | 
			
		||||
#
 | 
			
		||||
#	postfwd-rblcheck.pl <hostname or ip> [<hostname or ip> ...]
 | 
			
		||||
#
 | 
			
		||||
# by JPK
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use Net::DNS::Async;
 | 
			
		||||
use strict;
 | 
			
		||||
 | 
			
		||||
# length of screen
 | 
			
		||||
my $mylen = 79;
 | 
			
		||||
 | 
			
		||||
# RBLs (ip based)
 | 
			
		||||
my @rbls = qw(
 | 
			
		||||
        query.bondedsender.org
 | 
			
		||||
        exemptions.ahbl.org
 | 
			
		||||
        spf.trusted-forwarder.org
 | 
			
		||||
        list.dnswl.org
 | 
			
		||||
        zz.countries.nerd.dk
 | 
			
		||||
        zen.spamhaus.org
 | 
			
		||||
        bl.spamcop.net
 | 
			
		||||
        list.dsbl.org
 | 
			
		||||
        multihop.dsbl.org
 | 
			
		||||
        unconfirmed.dsbl.org
 | 
			
		||||
        combined.njabl.org
 | 
			
		||||
        dnsbl.sorbs.net
 | 
			
		||||
        dnsbl.ahbl.org
 | 
			
		||||
        ix.dnsbl.manitu.net
 | 
			
		||||
        dnsbl-1.uceprotect.net
 | 
			
		||||
        dnsbl-2.uceprotect.net
 | 
			
		||||
        dnsbl-3.uceprotect.net
 | 
			
		||||
        ips.backscatterer.org
 | 
			
		||||
        sorbs.dnsbl.net.au
 | 
			
		||||
        korea.services.net
 | 
			
		||||
        blackholes.five-ten-sg.com
 | 
			
		||||
        cbl.anti-spam.org.cn
 | 
			
		||||
        cblplus.anti-spam.org.cn
 | 
			
		||||
        cblless.anti-spam.org.cn
 | 
			
		||||
        bogons.cymru.com
 | 
			
		||||
        dynamic.tqmrbl.com
 | 
			
		||||
        relays.tqmrbl.com
 | 
			
		||||
        clients.tqmrbl.com
 | 
			
		||||
	hostkarma.junkemailfilter.com
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
# RHSBLs (domain based)
 | 
			
		||||
my @rhsbls = qw(
 | 
			
		||||
	rhsbl.sorbs.net
 | 
			
		||||
	rhsbl.ahbl.org
 | 
			
		||||
	multi.surbl.org
 | 
			
		||||
	dsn.rfc-ignorant.org
 | 
			
		||||
	abuse.rfc-ignorant.org
 | 
			
		||||
	whois.rfc-ignorant.org
 | 
			
		||||
	bogusmx.rfc-ignorant.org
 | 
			
		||||
	blackhole.securitysage.com
 | 
			
		||||
	ex.dnsbl.org
 | 
			
		||||
	rddn.dnsbl.net.au
 | 
			
		||||
	block.rhs.mailpolice.com
 | 
			
		||||
	dynamic.rhs.mailpolice.com
 | 
			
		||||
	dnsbl.cyberlogic.net
 | 
			
		||||
	hostkarma.junkemailfilter.com
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
# async dns object
 | 
			
		||||
my $DNS = new Net::DNS::Async ( QueueSize => 100, Retries => 3, Timeout => 20 );
 | 
			
		||||
our %RBLres = ();
 | 
			
		||||
 | 
			
		||||
# async dns callback method
 | 
			
		||||
sub callback {
 | 
			
		||||
    my $myresponse = shift;
 | 
			
		||||
    my $query = ''; my $result = '';
 | 
			
		||||
 | 
			
		||||
	# get query
 | 
			
		||||
	if ( defined $myresponse ) {
 | 
			
		||||
		foreach ($myresponse->question) {
 | 
			
		||||
       		 	next unless (($_->qtype eq 'A') or ($_->qtype eq 'TXT'));
 | 
			
		||||
			$query = $_->qname;
 | 
			
		||||
		};
 | 
			
		||||
	
 | 
			
		||||
		# get answer and fill result hash
 | 
			
		||||
		if ( defined $query ) {
 | 
			
		||||
			foreach ($myresponse->answer) {
 | 
			
		||||
				if ($_->type eq 'A') {
 | 
			
		||||
					$result = $_->address;
 | 
			
		||||
			        	$query ||= ''; $result ||= '';
 | 
			
		||||
					$RBLres{$query}{result} = $result;
 | 
			
		||||
					$RBLres{$query}{end} = time;
 | 
			
		||||
				} elsif ($_->type eq 'TXT') {
 | 
			
		||||
					$RBLres{$query}{text} = join(" ", $_->char_str_list());
 | 
			
		||||
					$RBLres{$query}{end} = time;
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# main, parse argument list
 | 
			
		||||
foreach (@ARGV) {
 | 
			
		||||
    my $query = $_;
 | 
			
		||||
    my $now = time;
 | 
			
		||||
    my @lookups = ();
 | 
			
		||||
    my $name  = my $addr = my $res = 'unknown';
 | 
			
		||||
    my $rblcount = my $rhlcount = 0;
 | 
			
		||||
 | 
			
		||||
	# clear result hash
 | 
			
		||||
	%RBLres = ();
 | 
			
		||||
 | 
			
		||||
	# lookup hostname or ip address, remove localpart if email address
 | 
			
		||||
	if ($query =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
 | 
			
		||||
		$addr = $query;
 | 
			
		||||
		$name = $res
 | 
			
		||||
			if ( defined($res = gethostbyaddr (pack ('C4', (split /\./, $addr)), 2)) );
 | 
			
		||||
	} else {
 | 
			
		||||
		$name = ($query =~ /@([^@]+)$/) ? $1 : $query;
 | 
			
		||||
		$addr = ( join ".", (unpack ('C4', $res)) )
 | 
			
		||||
			if ( defined ($res = gethostbyname ($name.".")) );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	# header
 | 
			
		||||
	print "\n", "=" x $mylen, "\n";
 | 
			
		||||
	print "QUERY: ", $query, "  NAME: ", $name, "  ADDR: ", $addr, "\n";
 | 
			
		||||
 | 
			
		||||
	# prepare rbl lookups
 | 
			
		||||
	unless ($addr eq 'unknown') {
 | 
			
		||||
		$addr = join ".", reverse split /\./, $addr;
 | 
			
		||||
		foreach my $rbl (@rbls) {
 | 
			
		||||
			$RBLres{$addr.".".$rbl}{query} = $rbl;
 | 
			
		||||
			$RBLres{$addr.".".$rbl}{type}  = 'RBL';
 | 
			
		||||
			$RBLres{$addr.".".$rbl}{start} = time;
 | 
			
		||||
			push @lookups, $addr.".".$rbl;
 | 
			
		||||
			#print "query ", $RBLres{$addr.".".$rbl}{query}, " for ", $addr.".".$rbl, "\n";
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	# prepare rhsbl lookups
 | 
			
		||||
	unless ($name eq 'unknown') {
 | 
			
		||||
		foreach my $rhsbl (@rhsbls) {
 | 
			
		||||
			$RBLres{$name.".".$rhsbl}{query} = $rhsbl;
 | 
			
		||||
			$RBLres{$name.".".$rhsbl}{type}  = 'RHSBL';
 | 
			
		||||
			$RBLres{$name.".".$rhsbl}{start} = time;
 | 
			
		||||
			push @lookups, $name.".".$rhsbl;
 | 
			
		||||
			#print "name ", $RBLres{$name.".".$rhsbl}{query}, " for ", $name.".".$rhsbl, "\n";
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	# perform lookups
 | 
			
		||||
	map { $DNS->add (\&callback, $_) } @lookups; 
 | 
			
		||||
	map { $DNS->add (\&callback, $_, 'TXT') } @lookups; 
 | 
			
		||||
	$DNS->await();
 | 
			
		||||
 | 
			
		||||
	# evaluate results
 | 
			
		||||
	foreach $query (sort keys %RBLres) {
 | 
			
		||||
		if ($query and (defined $RBLres{$query}{result})) {
 | 
			
		||||
			print "  ", "-" x ($mylen - 4), "\n";
 | 
			
		||||
			printf "  listed on %s:%s, result: %s, time: %ds\n  %s\n",
 | 
			
		||||
				$RBLres{$query}{type},
 | 
			
		||||
				$RBLres{$query}{query}, $RBLres{$query}{result},
 | 
			
		||||
				($RBLres{$query}{end} - $RBLres{$query}{start}),
 | 
			
		||||
				((defined $RBLres{$query}{text}) ? "\"".$RBLres{$query}{text}."\"" : '<undef>');
 | 
			
		||||
			$rblcount++ if $RBLres{$query}{type} eq 'RBL';
 | 
			
		||||
			$rhlcount++ if $RBLres{$query}{type} eq 'RHSBL';
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	# footer
 | 
			
		||||
	print "  ", "-" x ($mylen - 4), "\n";
 | 
			
		||||
	printf "%d of %d RBLs, ", $rblcount, $#rbls if ($rblcount > 0);
 | 
			
		||||
	printf "%d of %d RHSBLs, ", $rhlcount, $#rhsbls if ($rhlcount > 0);
 | 
			
		||||
	printf "Finished after %d seconds\n", (time - $now);
 | 
			
		||||
	print "=" x $mylen, "\n\n";
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										21
									
								
								tools/request.sample
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tools/request.sample
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
ccert_fingerprint=
 | 
			
		||||
size=64063
 | 
			
		||||
helo_name=english-breakfast.cloud9.net
 | 
			
		||||
reverse_client_name=english-breakfast.cloud9.net
 | 
			
		||||
queue_id=
 | 
			
		||||
encryption_cipher=
 | 
			
		||||
encryption_protocol=
 | 
			
		||||
etrn_domain=
 | 
			
		||||
ccert_subject=
 | 
			
		||||
request=smtpd_access_policy
 | 
			
		||||
protocol_state=RCPT
 | 
			
		||||
recipient=someone@domain.local
 | 
			
		||||
instance=6748.46adf3f8.62156.0
 | 
			
		||||
protocol_name=ESMTP
 | 
			
		||||
encryption_keysize=0
 | 
			
		||||
recipient_count=0
 | 
			
		||||
ccert_issuer=
 | 
			
		||||
sender=owner-postfix-users@postfix.org
 | 
			
		||||
client_name=english-breakfast.cloud9.net
 | 
			
		||||
client_address=168.100.1.7
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue