977 lines
54 KiB
HTML
977 lines
54 KiB
HTML
|
<!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<6C> 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>
|