2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 05:07:58 +00:00

postfix-2.8-20100830

This commit is contained in:
Wietse Venema 2010-08-29 00:00:00 -05:00 committed by Viktor Dukhovni
parent 4d9829bd37
commit c78b3ad466
19 changed files with 1072 additions and 416 deletions

4
postfix/.indent.pro vendored
View File

@ -191,8 +191,8 @@
-TPOSTMAP_KEY_STATE
-TPOST_MAIL_STATE
-TPRIVATE_STR_TABLE
-TPS_DNSBL_ENTRY
-TPS_DNS_STREAM
-TPS_DNSBL_SITE
-TPS_DNSBL_SCORE
-TPS_STATE
-TQMGR_ENTRY
-TQMGR_FEEDBACK

View File

@ -15908,3 +15908,30 @@ Apologies for any names omitted.
"smtp_dns_resolver_options = res_defnames" to get the old
behavior, which can produce unexpected results. Files:
smtp/smtp.c, smtp/smtp_params.c, smtp/smtp_addr.c.
20100828
Refactoring: postscreen source code broken up into multiple
files, and identifiers updated to match changes in their
purpose. This will be the baseline for adding support for
DNSBL weighting, then a dummy engine to collect forensic
evidence with the option of future protocol checks. Files:
postscreen/*.[hc], Makefile.in.
20100829
Postscreen DNSBL support for optional fixed-string filters
and optional integral weight factors (use negative weights
for whitelisting). See RELEASE_NOTES and postconf(5) for
details. Files: postscreen/postscreen_dnsbl.c,
proto/postconf.proto, mantools.postlink, global/mail_params.h.
Incompatibility: the postscreen-to-dnsblog protocol was
changed to support DNSBL query result filters. Use "postfix
reload" after installing the new version otherwise the
dnsblog(8) server may complain.
20100830
Polished the postscreen documentation and comments to clarify
the user interface and implementation. No code changes.

View File

@ -14,6 +14,46 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.6 or earlier, read RELEASE_NOTES-2.7
before proceeding.
Incompatibility with snapshot 20100830
======================================
Use "postfix reload" after installing this code, otherwise the
dnsblog(8) daemon may complain. The postscreen-to-dnsblog protocol
had to be changed to support DNSBL query result filters.
Major changes with snapshot 20100830
====================================
Postscreen DNSBL support is extended with optional fixed-string
filters, with optional integral weight factors, and with an adjustable
threshold to block SMTP clients with DNSBL score >= that threshold.
Support for wild-card patterns will be added later.
The updated postscreen configuration syntax is:
postscreen_dnsbl_sites = domain[=ipaddr][*weight] ...
postscreen_dnsbl_threshold = score
Elements inside [] are optional, ipaddr is an IPv4 address, and
weight and score are integral numbers. The [] are not part of the
postscreen_dnsbl_sites input. By default, weight and score are
equal to 1, and entries without filter will match any non-error
DNSBL reply. Use a negative weight value for whitelisting.
Examples:
To use example.com as a high-confidence blocklist, and to block
mail with example.net and example.org only when both agree, use:
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = example.com*2, example.net, example.org
To filter only DNSBL replies containing 127.0.0.4, use:
postscreen_dnsbl_sites = example.com=127.0.0.4
See also postconf(5) for the fine details.
Incompatibility with snapshot 20100827
======================================

View File

@ -6623,8 +6623,9 @@ parameter. Specify one of the following: </p>
<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
elapsed, and report whether the client triggers a PREGREET or HANGUP
error, or whether the client is listed at the DNSBL sites specified
with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter. Take the corresponding
error, or whether the client's combined DNSBL score is equal to or
greater than a threshold (as specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> parameters). Take the corresponding
action, or forward the connection to a real SMTP server process.
</dd>
@ -6678,7 +6679,7 @@ seconds. </p>
</DD>
<DT><b><a name="postscreen_cache_map">postscreen_cache_map</a>
(default: btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b></DT><DD>
(default: btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_cache)</b></DT><DD>
<p> Persistent storage for the <a href="postscreen.8.html">postscreen(8)</a> server decisions. </p>
@ -6724,9 +6725,10 @@ unit). </p>
<DT><b><a name="postscreen_dnsbl_action">postscreen_dnsbl_action</a>
(default: continue)</b></DT><DD>
<p>The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client is listed
at the DNS blocklist domains specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
parameter. Specify one of the following: </p>
<p>The action that <a href="postscreen.8.html">postscreen(8)</a> takes when an SMTP client's combined
DNSBL score is equal to or greater than a threshold (as defined
with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a>
parameters). Specify one of the following: </p>
<dl>
@ -6748,14 +6750,70 @@ parameter. Specify one of the following: </p>
<DT><b><a name="postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
(default: empty)</b></DT><DD>
<p>Optional list of DNS blocklist domains. When the list is non-enpty,
the <a href="dnsblog.8.html">dnsblog(8)</a> daemon will query these domains with the IP addresses
of non-whitelisted <a href="postscreen.8.html">postscreen(8)</a> clients. Specify a list of domain
names, separated by comma or whitespace. </p>
<p>Optional list of DNS blocklist domains, filters and weight
factors. When the list is non-empty, the <a href="dnsblog.8.html">dnsblog(8)</a> daemon will
query these domains with the IP addresses of non-whitelisted remote
SMTP clients, and <a href="postscreen.8.html">postscreen(8)</a> will update an SMTP client's DNSBL
score with each non-error reply. </p>
<p> When a client's score is equal to or greater than the threshold
specified with <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a>, <a href="postscreen.8.html">postscreen(8)</a> can drop
the connection with the SMTP client. </p>
<p> Specify a list of domain=filter*weight entries, separated by
comma or whitespace. </p>
<ul>
<li> <p> When no "=filter" is specified, <a href="postscreen.8.html">postscreen(8)</a> will use any
non-error DNSBL reply. Otherwise, the filter must be an IPv4
address, and <a href="postscreen.8.html">postscreen(8)</a> uses only DNSBL replies that match the
filter. </p>
<li> <p> When no "*weight" is specified, <a href="postscreen.8.html">postscreen(8)</a> increments
the SMTP client's DNSBL score by 1. Otherwise, the weight must be
an integral number, and <a href="postscreen.8.html">postscreen(8)</a> adds the specified weight to
the SMTP client's DNSBL score. Specify a negative number for
whitelisting. </p>
<li> <p> When one <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> entry produces multiple
DNSBL responses, <a href="postscreen.8.html">postscreen(8)</a> applies the weight at most once.
</p>
</ul>
<p> Examples: </p>
<p> To use example.com as a high-confidence blocklist, and to
block mail with example.net and example.org only when both agree:
</p>
<pre>
<a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> = 2
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> = example.com*2, example.net, example.org
</pre>
<p> To filter only DNSBL replies containing 127.0.0.4: </p>
<pre>
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> = example.com=127.0.0.4
</pre>
<p> This feature is available in Postfix 2.8. </p>
</DD>
<DT><b><a name="postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a>
(default: 1)</b></DT><DD>
<p> The inclusive lower bound for blocking an SMTP client, based on
its combined DNSBL score as defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a>
parameter. </p>
<p> This feature is available in Postfix 2.8. </p>
</DD>
<DT><b><a name="postscreen_greet_action">postscreen_greet_action</a>
@ -6770,10 +6828,11 @@ parameter. Specify one of the following: </p>
<dt> continue </dt>
<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
elapsed. If the client is listed at the DNS blocklist domains
specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter, execute the
action specified with the <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter, otherwise
forward the connection to a real SMTP server process. </dd>
elapsed. If the client's combined DNSBL score is equal to or greater
than a threshold (as specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and
<a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> parameters), execute the action specified
with the <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter, otherwise forward the
connection to a real SMTP server process. </dd>
<dt> drop </dt>
@ -6836,9 +6895,11 @@ without sending data, within the time specified with the
<dt> continue </dt>
<dd> Continue waiting until the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has
elapsed, and report whether the client is listed at the DNSBL sites
specified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter. Do not
forward the broken connection to a real SMTP server process. </dd>
elapsed, and report whether the client's combined DNSBL score is
equal to or greater than a threshold (as defined with the
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> parameters).
Do not forward the broken connection to a real SMTP server process.
</dd>
<dt> drop </dt>
@ -8617,17 +8678,17 @@ discard EHLO keywords selectively. </p>
(default: empty)</b></DT><DD>
<p> DNS Resolver options for the Postfix SMTP client. Specify zero
or more of the following, separated by comma or whitespace. Option
names are case-sensitive. Some options refer to domain names that
are specified in /etc/resolv.conf or equivalent. </p>
or more of the following options, separated by comma or whitespace.
Option names are case-sensitive. Some options refer to domain names
that are specified in the file /etc/resolv.conf or equivalent. </p>
<dl>
<dt><b>res_defnames</b></dt>
<dd> Append the <a href="ADDRESS_CLASS_README.html#default_domain_class">default domain</a> name to single-component names (those
that do not contain a dot). This can produce incorrect results,
and was the behavior prior to Postfix 2.8. </dd>
<dd> Append the current domain name to single-component names (those
that do not contain a "." character). This can produce incorrect
results, and is the hard-coded behavior prior to Postfix 2.8. </dd>
<dt><b>res_dnsrch</b></dt>

View File

@ -182,30 +182,31 @@ POSTSCREEN(8) POSTSCREEN(8)
are made in parallel.
When the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> time has elapsed, and the
SMTP client address is listed with at least one of these
blocklists, this is logged as:
combined DNSBL score is equal to or greater than the
<a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> parameter value, this is logged
as:
<b>DNSBL rank</b> <i>count</i> <b>for</b> <i>address</i>
Translation: the client at <i>address</i> is listed with <i>count</i>
DNSBL servers. The <i>count</i> does not depend on the number of
DNS records that an individual DNSBL server returns.
Translation: the SMTP client at <i>address</i> has a combined
DNSBL score of <i>count</i>.
The <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter specifies the action
that is taken next:
that is taken when the combined DNSBL score is equal to or
greater than the threshold:
<b>continue</b> (default)
Forward the connection to a real SMTP server
process.
<b>drop</b> Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
<b>drop</b> Drop the connection immediately with a 521 SMTP
reply. In a future implementation, the connection
may instead be passed to a dummy SMTP protocol
engine that logs sender and recipient information.
<b>SECURITY</b>
The <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server is moderately security-sensitive.
It talks to untrusted clients on the network. The process
It talks to untrusted clients on the network. The process
can be run chrooted at fixed low privilege.
<b>STANDARDS</b>
@ -216,34 +217,42 @@ POSTSCREEN(8) POSTSCREEN(8)
Problems and transactions are logged to <b>syslogd</b>(8).
<b>CONFIGURATION PARAMETERS</b>
Changes to <a href="postconf.5.html">main.cf</a> are not picked up automatically, as
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> processes may run for several hours. Use
Changes to <a href="postconf.5.html">main.cf</a> are not picked up automatically, as
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> processes may run for several hours. Use
the command "postfix reload" after a configuration change.
The text below provides only a parameter summary. See
The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b>TRIAGE PARAMETERS</b>
<b><a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> (continue)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client is permanently blacklisted with the
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client is permanently blacklisted with the
<a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter.
<b><a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> (empty)</b>
Network addresses that are permanently blacklisted;
see the <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter for
see the <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter for
possible actions.
<b><a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> (continue)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client is listed at the DNS blocklist domains spec-
ified with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client's combined DNSBL score is equal to or
greater than a threshold (as defined with the
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and postscreen_dnsbl_thresh-
old parameters).
<b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
Optional list of DNS blocklist domains.
Optional list of DNS blocklist domains, filters and
weight factors.
<b><a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> (1)</b>
The inclusive lower bound for blocking an SMTP
client, based on its combined DNSBL score as
defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> (continue)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client speaks before its turn within the time spec-
ified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
@ -251,72 +260,72 @@ POSTSCREEN(8) POSTSCREEN(8)
The <i>text</i> in the optional "220-<i>text</i>..." server
response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
Postfix SMTP server's "220 text..." response, in an
attempt to confuse bad SMTP clients so that they
attempt to confuse bad SMTP clients so that they
speak before their turn (pre-greet).
<b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (4s)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for
an SMTP client to send a command before its turn,
an SMTP client to send a command before its turn,
and for DNS blocklist lookup results to arrive.
<b><a href="postconf.5.html#postscreen_hangup_action">postscreen_hangup_action</a> (continue)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when an SMTP
client disconnects without sending data, within the
time specified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>
time specified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>
parameter.
<b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
The number of clients that can be waiting for ser-
The number of clients that can be waiting for ser-
vice from a real SMTP server process.
<b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
The number of non-whitelisted clients that can be
waiting for a decision whether they will receive
The number of non-whitelisted clients that can be
waiting for a decision whether they will receive
service from a real SMTP server process.
<b><a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
Network addresses that are permanently whitelisted,
and that will not be subjected to <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
and that will not be subjected to <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
checks.
<b><a href="postconf.5.html#smtpd_service">smtpd_service</a> (smtpd)</b>
The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> forwards
The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> forwards
allowed connections to.
<b>CACHE CONTROLS</b>
<b><a href="postconf.5.html#postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a> (12h)</b>
The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
cleanup runs.
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_whitelist)</b>
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$<a href="postconf.5.html#data_directory">data_directory</a>/ps_cache)</b>
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
decisions.
<b><a href="postconf.5.html#postscreen_cache_retention_time">postscreen_cache_retention_time</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache an
expired temporary whitelist entry before it is
expired temporary whitelist entry before it is
removed.
<b><a href="postconf.5.html#postscreen_cache_ttl">postscreen_cache_ttl</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache a
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache a
decision for a specific SMTP client IP address.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
How much time a Postfix daemon process may take to
handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
The maximal number of digits after the decimal
The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative com-
The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@ -324,24 +333,24 @@ POSTSCREEN(8) POSTSCREEN(8)
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The process ID of a Postfix command or daemon
The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
The process name of a Postfix command or daemon
The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
@ -350,7 +359,7 @@ POSTSCREEN(8) POSTSCREEN(8)
syslogd(8), system logging
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>

View File

@ -3726,8 +3726,9 @@ parameter. Specify one of the following:
.IP "continue"
Continue waiting until the postscreen_greet_wait time has
elapsed, and report whether the client triggers a PREGREET or HANGUP
error, or whether the client is listed at the DNSBL sites specified
with the postscreen_dnsbl_sites parameter. Take the corresponding
error, or whether the client's combined DNSBL score is equal to or
greater than a threshold (as specified with the postscreen_dnsbl_sites
and postscreen_dnsbl_threshold parameters). Take the corresponding
action, or forward the connection to a real SMTP server process.
.IP "drop"
Drop the connection immediately with a 521 SMTP reply, without
@ -3759,7 +3760,7 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w
(weeks).
.PP
This feature is available in Postfix 2.8.
.SH postscreen_cache_map (default: btree:$data_directory/ps_whitelist)
.SH postscreen_cache_map (default: btree:$data_directory/ps_cache)
Persistent storage for the \fBpostscreen\fR(8) server decisions.
.PP
This feature is available in Postfix 2.8.
@ -3786,9 +3787,10 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w
.PP
This feature is available in Postfix 2.8.
.SH postscreen_dnsbl_action (default: continue)
The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
at the DNS blocklist domains specified with the postscreen_dnsbl_sites
parameter. Specify one of the following:
The action that \fBpostscreen\fR(8) takes when an SMTP client's combined
DNSBL score is equal to or greater than a threshold (as defined
with the postscreen_dnsbl_sites and postscreen_dnsbl_threshold
parameters). Specify one of the following:
.IP "continue"
Forward the connection to a real SMTP server process.
.IP "drop"
@ -3796,10 +3798,62 @@ Drop the connection with a 521 SMTP reply.
.PP
This feature is available in Postfix 2.8.
.SH postscreen_dnsbl_sites (default: empty)
Optional list of DNS blocklist domains. When the list is non-enpty,
the \fBdnsblog\fR(8) daemon will query these domains with the IP addresses
of non-whitelisted \fBpostscreen\fR(8) clients. Specify a list of domain
names, separated by comma or whitespace.
Optional list of DNS blocklist domains, filters and weight
factors. When the list is non-empty, the \fBdnsblog\fR(8) daemon will
query these domains with the IP addresses of non-whitelisted remote
SMTP clients, and \fBpostscreen\fR(8) will update an SMTP client's DNSBL
score with each non-error reply.
.PP
When a client's score is equal to or greater than the threshold
specified with postscreen_dnsbl_threshold, \fBpostscreen\fR(8) can drop
the connection with the SMTP client.
.PP
Specify a list of domain=filter*weight entries, separated by
comma or whitespace.
.IP \(bu
When no "=filter" is specified, \fBpostscreen\fR(8) will use any
non-error DNSBL reply. Otherwise, the filter must be an IPv4
address, and \fBpostscreen\fR(8) uses only DNSBL replies that match the
filter.
.IP \(bu
When no "*weight" is specified, \fBpostscreen\fR(8) increments
the SMTP client's DNSBL score by 1. Otherwise, the weight must be
an integral number, and \fBpostscreen\fR(8) adds the specified weight to
the SMTP client's DNSBL score. Specify a negative number for
whitelisting.
.IP \(bu
When one postscreen_dnsbl_sites entry produces multiple
DNSBL responses, \fBpostscreen\fR(8) applies the weight at most once.
.PP
Examples:
.PP
To use example.com as a high-confidence blocklist, and to
block mail with example.net and example.org only when both agree:
.PP
.nf
.na
.ft C
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = example.com*2, example.net, example.org
.fi
.ad
.ft R
.PP
To filter only DNSBL replies containing 127.0.0.4:
.PP
.nf
.na
.ft C
postscreen_dnsbl_sites = example.com=127.0.0.4
.fi
.ad
.ft R
.PP
This feature is available in Postfix 2.8.
.SH postscreen_dnsbl_threshold (default: 1)
The inclusive lower bound for blocking an SMTP client, based on
its combined DNSBL score as defined with the postscreen_dnsbl_sites
parameter.
.PP
This feature is available in Postfix 2.8.
.SH postscreen_greet_action (default: continue)
@ -3808,10 +3862,11 @@ before its turn within the time specified with the postscreen_greet_wait
parameter. Specify one of the following:
.IP "continue"
Continue waiting until the postscreen_greet_wait time has
elapsed. If the client is listed at the DNS blocklist domains
specified with the postscreen_dnsbl_sites parameter, execute the
action specified with the postscreen_dnsbl_action parameter, otherwise
forward the connection to a real SMTP server process.
elapsed. If the client's combined DNSBL score is equal to or greater
than a threshold (as specified with the postscreen_dnsbl_sites and
postscreen_dnsbl_threshold parameters), execute the action specified
with the postscreen_dnsbl_action parameter, otherwise forward the
connection to a real SMTP server process.
.IP "drop"
Drop the connection immediately with a 521 SMTP reply, without
examining DNSBL lookup results.
@ -3847,9 +3902,10 @@ without sending data, within the time specified with the
postscreen_greet_wait parameter. Specify one of the following:
.IP "continue"
Continue waiting until the postscreen_greet_wait time has
elapsed, and report whether the client is listed at the DNSBL sites
specified with the postscreen_dnsbl_sites parameter. Do not
forward the broken connection to a real SMTP server process.
elapsed, and report whether the client's combined DNSBL score is
equal to or greater than a threshold (as defined with the
postscreen_dnsbl_sites and postscreen_dnsbl_threshold parameters).
Do not forward the broken connection to a real SMTP server process.
.IP "drop"
Drop the connection immediately, without reporting DNSBL lookup
results.
@ -4903,13 +4959,13 @@ Use the smtp_discard_ehlo_keyword_address_maps feature to
discard EHLO keywords selectively.
.SH smtp_dns_resolver_options (default: empty)
DNS Resolver options for the Postfix SMTP client. Specify zero
or more of the following, separated by comma or whitespace. Option
names are case-sensitive. Some options refer to domain names that
are specified in /etc/resolv.conf or equivalent.
or more of the following options, separated by comma or whitespace.
Option names are case-sensitive. Some options refer to domain names
that are specified in the file /etc/resolv.conf or equivalent.
.IP "\fBres_defnames\fR"
Append the default domain name to single-component names (those
that do not contain a dot). This can produce incorrect results,
and was the behavior prior to Postfix 2.8.
Append the current domain name to single-component names (those
that do not contain a "." character). This can produce incorrect
results, and is the hard-coded behavior prior to Postfix 2.8.
.IP "\fBres_dnsrch\fR"
Search for host names in the current domain and in parent
domains. This can produce incorrect results and is therefore not

View File

@ -199,20 +199,20 @@ specifies a list of DNS blocklist servers. These lookups
are made in parallel.
When the postscreen_greet_wait time has elapsed, and the
SMTP client address is listed with at least one of these
blocklists, this is logged as:
combined DNSBL score is equal to or greater than the
postscreen_dnsbl_threshold parameter value, this is logged
as:
.sp
.nf
\fBDNSBL rank \fIcount \fBfor \fIaddress\fR
.fi
.sp
Translation: the client at \fIaddress\fR is listed with
\fIcount\fR DNSBL servers. The \fIcount\fR does not
depend on the number of DNS records that an individual DNSBL
server returns.
Translation: the SMTP client at \fIaddress\fR has a combined
DNSBL score of \fIcount\fR.
The postscreen_dnsbl_action parameter specifies the action
that is taken next:
that is taken when the combined DNSBL score is equal to or
greater than the threshold:
.IP "\fBcontinue\fR (default)"
Forward the connection to a real SMTP server process.
.IP \fBdrop\fR
@ -262,11 +262,17 @@ parameter.
Network addresses that are permanently blacklisted; see the
postscreen_blacklist_action parameter for possible actions.
.IP "\fBpostscreen_dnsbl_action (continue)\fR"
The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
at the DNS blocklist domains specified with the postscreen_dnsbl_sites
parameter.
The action that \fBpostscreen\fR(8) takes when an SMTP client's combined
DNSBL score is equal to or greater than a threshold (as defined
with the postscreen_dnsbl_sites and postscreen_dnsbl_threshold
parameters).
.IP "\fBpostscreen_dnsbl_sites (empty)\fR"
Optional list of DNS blocklist domains.
Optional list of DNS blocklist domains, filters and weight
factors.
.IP "\fBpostscreen_dnsbl_threshold (1)\fR"
The inclusive lower bound for blocking an SMTP client, based on
its combined DNSBL score as defined with the postscreen_dnsbl_sites
parameter.
.IP "\fBpostscreen_greet_action (continue)\fR"
The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
before its turn within the time specified with the postscreen_greet_wait
@ -305,7 +311,7 @@ connections to.
.fi
.IP "\fBpostscreen_cache_cleanup_interval (12h)\fR"
The amount of time between \fBpostscreen\fR(8) cache cleanup runs.
.IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
.IP "\fBpostscreen_cache_map (btree:$data_directory/ps_cache)\fR"
Persistent storage for the \fBpostscreen\fR(8) server decisions.
.IP "\fBpostscreen_cache_retention_time (1d)\fR"
The amount of time that \fBpostscreen\fR(8) will cache an expired

View File

@ -916,6 +916,7 @@ while (<>) {
s;\bpostscreen_greet_wait\b;<a href="postconf.5.html#postscreen_greet_wait">$&</a>;g;
s;\bpostscreen_greet_action\b;<a href="postconf.5.html#postscreen_greet_action">$&</a>;g;
s;\bpostscreen_dnsbl_sites\b;<a href="postconf.5.html#postscreen_dnsbl_sites">$&</a>;g;
s;\bpostscreen_dnsbl_threshold\b;<a href="postconf.5.html#postscreen_dnsbl_threshold">$&</a>;g;
s;\bpostscreen_dnsbl_action\b;<a href="postconf.5.html#postscreen_dnsbl_action">$&</a>;g;
s;\bpostscreen_hangup_action\b;<a href="postconf.5.html#postscreen_hangup_action">$&</a>;g;
s;\bpostscreen_whitelist_networks\b;<a href="postconf.5.html#postscreen_whitelist_networks">$&</a>;g;

View File

@ -12512,7 +12512,7 @@ inspection for DKIM-signed mail from known friendly domains. </p>
<p> This feature is available in Postfix 2.7, and as an optional
patch for Postfix 2.6. </p>
%PARAM postscreen_cache_map btree:$data_directory/ps_whitelist
%PARAM postscreen_cache_map btree:$data_directory/ps_cache
<p> Persistent storage for the postscreen(8) server decisions. </p>
@ -12604,18 +12604,63 @@ an optional one-letter suffix that specifies the time unit). </p>
%PARAM postscreen_dnsbl_sites
<p>Optional list of DNS blocklist domains. When the list is non-enpty,
the dnsblog(8) daemon will query these domains with the IP addresses
of non-whitelisted postscreen(8) clients. Specify a list of domain
names, separated by comma or whitespace. </p>
<p>Optional list of DNS blocklist domains, filters and weight
factors. When the list is non-empty, the dnsblog(8) daemon will
query these domains with the IP addresses of non-whitelisted remote
SMTP clients, and postscreen(8) will update an SMTP client's DNSBL
score with each non-error reply. </p>
<p> When a client's score is equal to or greater than the threshold
specified with postscreen_dnsbl_threshold, postscreen(8) can drop
the connection with the SMTP client. </p>
<p> Specify a list of domain=filter*weight entries, separated by
comma or whitespace. </p>
<ul>
<li> <p> When no "=filter" is specified, postscreen(8) will use any
non-error DNSBL reply. Otherwise, the filter must be an IPv4
address, and postscreen(8) uses only DNSBL replies that match the
filter. </p>
<li> <p> When no "*weight" is specified, postscreen(8) increments
the SMTP client's DNSBL score by 1. Otherwise, the weight must be
an integral number, and postscreen(8) adds the specified weight to
the SMTP client's DNSBL score. Specify a negative number for
whitelisting. </p>
<li> <p> When one postscreen_dnsbl_sites entry produces multiple
DNSBL responses, postscreen(8) applies the weight at most once.
</p>
</ul>
<p> Examples: </p>
<p> To use example.com as a high-confidence blocklist, and to
block mail with example.net and example.org only when both agree:
</p>
<pre>
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = example.com*2, example.net, example.org
</pre>
<p> To filter only DNSBL replies containing 127.0.0.4: </p>
<pre>
postscreen_dnsbl_sites = example.com=127.0.0.4
</pre>
<p> This feature is available in Postfix 2.8. </p>
%PARAM postscreen_dnsbl_action continue
<p>The action that postscreen(8) takes when an SMTP client is listed
at the DNS blocklist domains specified with the postscreen_dnsbl_sites
parameter. Specify one of the following: </p>
<p>The action that postscreen(8) takes when an SMTP client's combined
DNSBL score is equal to or greater than a threshold (as defined
with the postscreen_dnsbl_sites and postscreen_dnsbl_threshold
parameters). Specify one of the following: </p>
<dl>
@ -12642,10 +12687,11 @@ parameter. Specify one of the following: </p>
<dt> continue </dt>
<dd> Continue waiting until the postscreen_greet_wait time has
elapsed. If the client is listed at the DNS blocklist domains
specified with the postscreen_dnsbl_sites parameter, execute the
action specified with the postscreen_dnsbl_action parameter, otherwise
forward the connection to a real SMTP server process. </dd>
elapsed. If the client's combined DNSBL score is equal to or greater
than a threshold (as specified with the postscreen_dnsbl_sites and
postscreen_dnsbl_threshold parameters), execute the action specified
with the postscreen_dnsbl_action parameter, otherwise forward the
connection to a real SMTP server process. </dd>
<dt> drop </dt>
@ -12671,9 +12717,11 @@ postscreen_greet_wait parameter. Specify one of the following:
<dt> continue </dt>
<dd> Continue waiting until the postscreen_greet_wait time has
elapsed, and report whether the client is listed at the DNSBL sites
specified with the postscreen_dnsbl_sites parameter. Do not
forward the broken connection to a real SMTP server process. </dd>
elapsed, and report whether the client's combined DNSBL score is
equal to or greater than a threshold (as defined with the
postscreen_dnsbl_sites and postscreen_dnsbl_threshold parameters).
Do not forward the broken connection to a real SMTP server process.
</dd>
<dt> drop </dt>
@ -12726,8 +12774,9 @@ parameter. Specify one of the following: </p>
<dd> Continue waiting until the postscreen_greet_wait time has
elapsed, and report whether the client triggers a PREGREET or HANGUP
error, or whether the client is listed at the DNSBL sites specified
with the postscreen_dnsbl_sites parameter. Take the corresponding
error, or whether the client's combined DNSBL score is equal to or
greater than a threshold (as specified with the postscreen_dnsbl_sites
and postscreen_dnsbl_threshold parameters). Take the corresponding
action, or forward the connection to a real SMTP server process.
</dd>
@ -12942,17 +12991,17 @@ configuration parameter. See there for details. </p>
%PARAM smtp_dns_resolver_options
<p> DNS Resolver options for the Postfix SMTP client. Specify zero
or more of the following, separated by comma or whitespace. Option
names are case-sensitive. Some options refer to domain names that
are specified in /etc/resolv.conf or equivalent. </p>
or more of the following options, separated by comma or whitespace.
Option names are case-sensitive. Some options refer to domain names
that are specified in the file /etc/resolv.conf or equivalent. </p>
<dl>
<dt><b>res_defnames</b></dt>
<dd> Append the default domain name to single-component names (those
that do not contain a dot). This can produce incorrect results,
and was the behavior prior to Postfix 2.8. </dd>
<dd> Append the current domain name to single-component names (those
that do not contain a "." character). This can produce incorrect
results, and is the hard-coded behavior prior to Postfix 2.8. </dd>
<dt><b>res_dnsrch</b></dt>
@ -12971,3 +13020,10 @@ configuration parameter. See there for details. </p>
<p> This feature is available in Postfix 2.8 and later. </p>
%PARAM postscreen_dnsbl_threshold 1
<p> The inclusive lower bound for blocking an SMTP client, based on
its combined DNSBL score as defined with the postscreen_dnsbl_sites
parameter. </p>
<p> This feature is available in Postfix 2.8. </p>

View File

@ -99,7 +99,7 @@ int main(int argc, char **argv)
argv_free(types_argv);
name = argv[2];
msg_verbose = 1;
switch (dns_lookup_v(name, RES_DEFNAMES | RES_DEBUG, &rr, fqdn, why,
switch (dns_lookup_v(name, RES_DEBUG, &rr, fqdn, why,
DNS_REQ_FLAG_NONE, types)) {
default:
msg_fatal("%s", vstring_str(why));

View File

@ -108,15 +108,18 @@ static VSTRING *rbl_domain;
static VSTRING *addr;
static VSTRING *query;
static VSTRING *why;
static VSTRING *result;
/*
* Silly little macros.
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
/* static void dnsblog_query - query DNSBL for client address */
static int dnsblog_query(const char *dnsbl_domain, const char *addr)
static VSTRING *dnsblog_query(VSTRING *result, const char *dnsbl_domain,
const char *addr)
{
const char *myname = "dnsblog_query";
ARGV *octets;
@ -127,7 +130,6 @@ static int dnsblog_query(const char *dnsbl_domain, const char *addr)
DNS_RR *addr_list;
DNS_RR *rr;
MAI_HOSTADDR_STR hostaddr;
int found = 0;
if (msg_verbose)
msg_info("%s: addr %s dnsbl_domain %s",
@ -168,11 +170,11 @@ static int dnsblog_query(const char *dnsbl_domain, const char *addr)
}
/*
* Tack on the RBL domain name and query the DNS for an A record. Don't
* do this for AAAA records. Yet.
* Tack on the RBL domain name and query the DNS for an A record.
*/
vstring_strcat(query, dnsbl_domain);
dns_status = dns_lookup(STR(query), T_A, 0, &addr_list, (VSTRING *) 0, why);
VSTRING_RESET(result);
if (dns_status == DNS_OK) {
for (rr = addr_list; rr != 0; rr = rr->next) {
if (dns_rr_to_pa(rr, &hostaddr) == 0) {
@ -181,7 +183,9 @@ static int dnsblog_query(const char *dnsbl_domain, const char *addr)
} else {
msg_info("addr %s blocked by domain %s as %s",
addr, dnsbl_domain, hostaddr.buf);
found = 1;
if (LEN(result) > 0)
vstring_strcat(result, " ");
vstring_strcat(result, hostaddr.buf);
}
}
dns_rr_free(addr_list);
@ -193,7 +197,8 @@ static int dnsblog_query(const char *dnsbl_domain, const char *addr)
msg_warn("%s: lookup error for DNS query %s: %s",
myname, STR(query), STR(why));
}
return (found);
VSTRING_TERMINATE(result);
return (result);
}
/* dnsblog_service - perform service for client */
@ -201,7 +206,6 @@ static int dnsblog_query(const char *dnsbl_domain, const char *addr)
static void dnsblog_service(VSTREAM *client_stream, char *unused_service,
char **argv)
{
int found;
/*
* Sanity check. This service takes no command-line arguments.
@ -217,13 +221,13 @@ static void dnsblog_service(VSTREAM *client_stream, char *unused_service,
if (attr_scan(client_stream,
ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, rbl_domain,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, addr,
ATTR_TYPE_END) == 2) {
found = dnsblog_query(STR(rbl_domain), STR(addr));
(void) dnsblog_query(result, STR(rbl_domain), STR(addr));
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, STR(rbl_domain),
ATTR_TYPE_STR, MAIL_ATTR_ADDR, STR(addr),
ATTR_TYPE_INT, MAIL_ATTR_STATUS, found,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, STR(addr),
ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, STR(result),
ATTR_TYPE_END);
vstream_fflush(client_stream);
}
@ -237,6 +241,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
addr = vstring_alloc(100);
query = vstring_alloc(100);
why = vstring_alloc(100);
result = vstring_alloc(100);
}
MAIL_VERSION_STAMP_DECLARE;

View File

@ -3251,6 +3251,10 @@ extern char *var_ps_greet_action;
#define DEF_PS_DNSBL_SITES ""
extern char *var_ps_dnsbl_sites;
#define VAR_PS_DNSBL_THRESH "postscreen_dnsbl_threshold"
#define DEF_PS_DNSBL_THRESH 1
extern int var_ps_dnsbl_thresh;
#define VAR_PS_DNSBL_ACTION "postscreen_dnsbl_action"
#define DEF_PS_DNSBL_ACTION "continue"
extern char *var_ps_dnsbl_action;

View File

@ -160,6 +160,7 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_RBL_TXT "rbl_txt" /* LaMont compatibility */
#define MAIL_ATTR_RBL_CLASS "rbl_class"
#define MAIL_ATTR_RBL_CODE "rbl_code"
#define MAIL_ATTR_RBL_ADDR "rbl_addr"
/*
* The following attribute names are stored in queue files. Changing this

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20100827"
#define MAIL_RELEASE_DATE "20100829"
#define MAIL_VERSION_NUMBER "2.8"
#ifdef SNAPSHOT

View File

@ -1,6 +1,6 @@
SHELL = /bin/sh
SRCS = postscreen.c
OBJS = postscreen.o
SRCS = postscreen.c postscreen_dict.c postscreen_dnsbl.c
OBJS = postscreen.o postscreen_dict.o postscreen_dnsbl.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
@ -87,3 +87,40 @@ postscreen.o: ../../include/vbuf.h
postscreen.o: ../../include/vstream.h
postscreen.o: ../../include/vstring.h
postscreen.o: postscreen.c
postscreen.o: postscreen.h
postscreen_dict.o: ../../include/addr_match_list.h
postscreen_dict.o: ../../include/argv.h
postscreen_dict.o: ../../include/dict.h
postscreen_dict.o: ../../include/dict_cache.h
postscreen_dict.o: ../../include/match_list.h
postscreen_dict.o: ../../include/match_ops.h
postscreen_dict.o: ../../include/msg.h
postscreen_dict.o: ../../include/sys_defs.h
postscreen_dict.o: ../../include/vbuf.h
postscreen_dict.o: ../../include/vstream.h
postscreen_dict.o: ../../include/vstring.h
postscreen_dict.o: postscreen.h
postscreen_dict.o: postscreen_dict.c
postscreen_dnsbl.o: ../../include/addr_match_list.h
postscreen_dnsbl.o: ../../include/argv.h
postscreen_dnsbl.o: ../../include/attr.h
postscreen_dnsbl.o: ../../include/connect.h
postscreen_dnsbl.o: ../../include/dict.h
postscreen_dnsbl.o: ../../include/dict_cache.h
postscreen_dnsbl.o: ../../include/events.h
postscreen_dnsbl.o: ../../include/htable.h
postscreen_dnsbl.o: ../../include/iostuff.h
postscreen_dnsbl.o: ../../include/mail_params.h
postscreen_dnsbl.o: ../../include/mail_proto.h
postscreen_dnsbl.o: ../../include/match_list.h
postscreen_dnsbl.o: ../../include/match_ops.h
postscreen_dnsbl.o: ../../include/msg.h
postscreen_dnsbl.o: ../../include/mymalloc.h
postscreen_dnsbl.o: ../../include/split_at.h
postscreen_dnsbl.o: ../../include/sys_defs.h
postscreen_dnsbl.o: ../../include/valid_hostname.h
postscreen_dnsbl.o: ../../include/vbuf.h
postscreen_dnsbl.o: ../../include/vstream.h
postscreen_dnsbl.o: ../../include/vstring.h
postscreen_dnsbl.o: postscreen.h
postscreen_dnsbl.o: postscreen_dnsbl.c

View File

@ -191,20 +191,20 @@
/* are made in parallel.
/*
/* When the postscreen_greet_wait time has elapsed, and the
/* SMTP client address is listed with at least one of these
/* blocklists, this is logged as:
/* combined DNSBL score is equal to or greater than the
/* postscreen_dnsbl_threshold parameter value, this is logged
/* as:
/* .sp
/* .nf
/* \fBDNSBL rank \fIcount \fBfor \fIaddress\fR
/* .fi
/* .sp
/* Translation: the client at \fIaddress\fR is listed with
/* \fIcount\fR DNSBL servers. The \fIcount\fR does not
/* depend on the number of DNS records that an individual DNSBL
/* server returns.
/* Translation: the SMTP client at \fIaddress\fR has a combined
/* DNSBL score of \fIcount\fR.
/*
/* The postscreen_dnsbl_action parameter specifies the action
/* that is taken next:
/* that is taken when the combined DNSBL score is equal to or
/* greater than the threshold:
/* .IP "\fBcontinue\fR (default)"
/* Forward the connection to a real SMTP server process.
/* .IP \fBdrop\fR
@ -244,11 +244,17 @@
/* Network addresses that are permanently blacklisted; see the
/* postscreen_blacklist_action parameter for possible actions.
/* .IP "\fBpostscreen_dnsbl_action (continue)\fR"
/* The action that \fBpostscreen\fR(8) takes when an SMTP client is listed
/* at the DNS blocklist domains specified with the postscreen_dnsbl_sites
/* parameter.
/* The action that \fBpostscreen\fR(8) takes when an SMTP client's combined
/* DNSBL score is equal to or greater than a threshold (as defined
/* with the postscreen_dnsbl_sites and postscreen_dnsbl_threshold
/* parameters).
/* .IP "\fBpostscreen_dnsbl_sites (empty)\fR"
/* Optional list of DNS blocklist domains.
/* Optional list of DNS blocklist domains, filters and weight
/* factors.
/* .IP "\fBpostscreen_dnsbl_threshold (1)\fR"
/* The inclusive lower bound for blocking an SMTP client, based on
/* its combined DNSBL score as defined with the postscreen_dnsbl_sites
/* parameter.
/* .IP "\fBpostscreen_greet_action (continue)\fR"
/* The action that \fBpostscreen\fR(8) takes when an SMTP client speaks
/* before its turn within the time specified with the postscreen_greet_wait
@ -285,7 +291,7 @@
/* .fi
/* .IP "\fBpostscreen_cache_cleanup_interval (12h)\fR"
/* The amount of time between \fBpostscreen\fR(8) cache cleanup runs.
/* .IP "\fBpostscreen_cache_map (btree:$data_directory/ps_whitelist)\fR"
/* .IP "\fBpostscreen_cache_map (btree:$data_directory/ps_cache)\fR"
/* Persistent storage for the \fBpostscreen\fR(8) server decisions.
/* .IP "\fBpostscreen_cache_retention_time (1d)\fR"
/* The amount of time that \fBpostscreen\fR(8) will cache an expired
@ -381,6 +387,10 @@
#include <mail_server.h>
/* Application-specific. */
#include <postscreen.h>
/*
* Configuration parameters.
*/
@ -402,6 +412,7 @@ char *var_ps_wlist_nets;
char *var_ps_blist_nets;
char *var_ps_greet_banner;
char *var_ps_blist_action;
int var_ps_dnsbl_thresh;
/*
* Per-session state. See also: new_session_state() and free_event_state()
@ -442,10 +453,6 @@ static DICT_CACHE *cache_map; /* cache table handle */
static VSTRING *temp; /* scratchpad */
static char *smtp_service_name; /* path to real SMTPD */
static char *teaser_greeting; /* spamware teaser banner */
static ARGV *dnsbl_sites; /* dns blocklist domains */
static VSTRING *reply_addr; /* address in DNSBL reply */
static VSTRING *reply_domain; /* domain in DNSBL reply */
static HTABLE *dnsbl_cache; /* entries being queried */
static int dnsbl_action; /* PS_ACT_DROP or PS_ACT_CONT */
static int greet_action; /* PS_ACT_DROP or PS_ACT_CONT */
static int hangup_action; /* PS_ACT_DROP or PS_ACT_CONT */
@ -453,239 +460,6 @@ static ADDR_MATCH_LIST *wlist_nets; /* permanently whitelisted networks */
static ADDR_MATCH_LIST *blist_nets; /* permanently blacklisted networks */
static int blist_action; /* PS_ACT_DROP or PS_ACT_CONT */
/*
* See log_adhoc.c for discussion.
*/
typedef struct {
int dt_sec; /* make sure it's signed */
int dt_usec; /* make sure it's signed */
} DELTA_TIME;
#define PS_CALC_DELTA(x, y, z) \
do { \
(x).dt_sec = (y).tv_sec - (z).tv_sec; \
(x).dt_usec = (y).tv_usec - (z).tv_usec; \
while ((x).dt_usec < 0) { \
(x).dt_usec += 1000000; \
(x).dt_sec -= 1; \
} \
while ((x).dt_usec >= 1000000) { \
(x).dt_usec -= 1000000; \
(x).dt_sec += 1; \
} \
if ((x).dt_sec < 0) \
(x).dt_sec = (x).dt_usec = 0; \
} while (0)
#define SIG_DIGS 2
/* READ_EVENT_REQUEST - prepare for transition to next state */
#define READ_EVENT_REQUEST(fd, action, context, timeout) do { \
if (msg_verbose) msg_info("%s: read-request fd=%d", myname, (fd)); \
event_enable_read((fd), (action), (context)); \
event_request_timer((action), (context), (timeout)); \
} while (0)
/* CLEAR_EVENT_REQUEST - complete state transition */
#define CLEAR_EVENT_REQUEST(fd, action, context) do { \
if (msg_verbose) msg_info("%s: clear-request fd=%d", myname, (fd)); \
event_disable_readwrite(fd); \
event_cancel_timer((action), (context)); \
} while (0)
/* SLMs. */
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
/*
* Monitor time-critical operations.
*/
#define PS_GET_TIME_BEFORE_LOOKUP \
struct timeval _before, _after; \
DELTA_TIME _delta; \
GETTIMEOFDAY(&_before);
#define PS_DELTA_MS(d) ((d).dt_sec * 1000 + (d).dt_usec / 1000)
#define PS_CHECK_TIME_AFTER_LOOKUP(table, action) \
GETTIMEOFDAY(&_after); \
PS_CALC_DELTA(_delta, _after, _before); \
if (_delta.dt_sec > 1 || _delta.dt_usec > 100000) \
msg_warn("%s: %s %s took %d ms", \
myname, (table), (action), PS_DELTA_MS(_delta));
/* ps_addr_match_list_match - time-critical address list lookup */
static int ps_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
const char *addr_str)
{
const char *myname = "ps_addr_match_list_match";
int result;
PS_GET_TIME_BEFORE_LOOKUP;
result = addr_match_list_match(addr_list, addr_str);
PS_CHECK_TIME_AFTER_LOOKUP("address list", "lookup");
return (result);
}
/* ps_dict_get - time-critical table lookup */
static const char *ps_dict_get(DICT_CACHE *cache, const char *key)
{
const char *myname = "ps_dict_get";
const char *result;
PS_GET_TIME_BEFORE_LOOKUP;
result = dict_cache_lookup(cache, key);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup");
return (result);
}
/* ps_dict_put - table dictionary update */
static void ps_dict_put(DICT_CACHE *cache, const char *key, const char *value)
{
const char *myname = "ps_dict_put";
PS_GET_TIME_BEFORE_LOOKUP;
dict_cache_update(cache, key, value);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update");
}
/*
* DNSBL lookup status per client IP address.
*/
typedef struct {
int dnsbl_count; /* is this address listed */
int refcount; /* query reference count */
} PS_DNSBL_ENTRY;
/* postscreen_dnsbl_entry_create - create blocklist cache entry */
static PS_DNSBL_ENTRY *postscreen_dnsbl_entry_create(void)
{
PS_DNSBL_ENTRY *entry;
entry = (PS_DNSBL_ENTRY *) mymalloc(sizeof(*entry));
entry->dnsbl_count = 0;
entry->refcount = 0;
return (entry);
}
/* postscreen_dnsbl_done - get blocklist cache entry, decrement refcount */
static int postscreen_dnsbl_done(const char *addr)
{
const char *myname = "postscreen_dnsbl_done";
PS_DNSBL_ENTRY *entry;
int dnsbl_count;
/*
* Sanity check.
*/
if ((entry = (PS_DNSBL_ENTRY *) htable_find(dnsbl_cache, addr)) == 0)
msg_panic("%s: no blocklist cache entry for %s", myname, addr);
/*
* Yes, cache reads are destructive.
*/
dnsbl_count = entry->dnsbl_count;
entry->refcount -= 1;
if (entry->refcount < 1) {
if (msg_verbose)
msg_info("%s: delete cache entry for %s", myname, addr);
htable_delete(dnsbl_cache, addr, myfree);
}
return (dnsbl_count);
}
/* postscreen_dnsbl_reply - receive dnsbl reply, update blocklist cache entry */
static void postscreen_dnsbl_reply(int event, char *context)
{
const char *myname = "postscreen_dnsbl_reply";
VSTREAM *stream = (VSTREAM *) context;
PS_DNSBL_ENTRY *entry;
int dnsbl_count;
CLEAR_EVENT_REQUEST(vstream_fileno(stream), postscreen_dnsbl_reply, context);
/*
* Later, this will become an UDP-based DNS client that is built directly
* into the postscreen daemon.
*
* Don't panic when no blocklist cache entry exists. It may be gone when the
* client triggered a "drop" action after pregreet, DNSBL lookup, or
* hangup.
*/
if (event == EVENT_READ
&& attr_scan(stream,
ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_domain,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, reply_addr,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &dnsbl_count,
ATTR_TYPE_END) == 3) {
if ((entry = (PS_DNSBL_ENTRY *)
htable_find(dnsbl_cache, STR(reply_addr))) != 0)
entry->dnsbl_count += dnsbl_count;
}
vstream_fclose(stream);
}
/* postscreen_dnsbl_query - send dnsbl query */
static void postscreen_dnsbl_query(const char *addr)
{
const char *myname = "postscreen_dnsbl_query";
int fd;
VSTREAM *stream;
char **cpp;
PS_DNSBL_ENTRY *entry;
/*
* Avoid duplicate effort when this lookup is already in progress. Now,
* we destroy the entry when the client replies. Later, we increment
* refcounts with queries sent, and decrement refcounts with replies
* received, so we can maintain state even after a client talks early,
* and update the external cache asynchronously.
*/
if ((entry = (PS_DNSBL_ENTRY *) htable_find(dnsbl_cache, addr)) != 0) {
entry->refcount += 1;
return;
}
if (msg_verbose)
msg_info("%s: create cache entry for %s", myname, addr);
entry = postscreen_dnsbl_entry_create();
(void) htable_enter(dnsbl_cache, addr, (char *) entry);
entry->refcount = 1;
/*
* Later, this will become an UDP-based DNS client that is built directly
* into the postscreen daemon.
*/
for (cpp = dnsbl_sites->argv; *cpp; cpp++) {
if ((fd = LOCAL_CONNECT("private/" DNSBL_SERVICE, NON_BLOCKING, 1)) < 0) {
msg_warn("%s: connect to " DNSBL_SERVICE " service: %m", myname);
return;
}
stream = vstream_fdopen(fd, O_RDWR);
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, *cpp,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
ATTR_TYPE_END);
if (vstream_fflush(stream) != 0) {
msg_warn("%s: error sending to " DNSBL_SERVICE " service: %m", myname);
vstream_fclose(stream);
return;
}
READ_EVENT_REQUEST(vstream_fileno(stream), postscreen_dnsbl_reply,
(char *) stream, DNSBLOG_TIMEOUT);
}
}
/* new_session_state - fill in connection state for event processing */
static PS_STATE *new_session_state(VSTREAM *stream, const char *addr,
@ -842,7 +616,7 @@ static void send_socket(PS_STATE *state)
vstream_fileno(state->smtp_client_stream)) < 0) {
msg_warn("cannot pass connection to service %s: %m", smtp_service_name);
smtp_reply(vstream_fileno(state->smtp_client_stream), state->smtp_client_addr,
state->smtp_client_port, "421 4.3.2 No system resources\r\n");
state->smtp_client_port, "421 4.3.2 No system resources\r\n");
free_session_state(state);
return;
} else {
@ -863,15 +637,15 @@ static void send_socket(PS_STATE *state)
}
}
/* smtp_read_event - handle pre-greet, EOF or timeout. */
/* smtp_early_event - handle pre-greet, EOF or timeout. */
static void smtp_read_event(int event, char *context)
static void smtp_early_event(int event, char *context)
{
const char *myname = "smtp_read_event";
const char *myname = "smtp_early_event";
PS_STATE *state = (PS_STATE *) context;
char read_buf[PS_READ_BUF_SIZE];
int read_count;
int dnsbl_count;
int dnsbl_score;
int elapsed;
int action;
@ -886,7 +660,7 @@ static void smtp_read_event(int event, char *context)
* was closed, or we reached the limit of our patience.
*/
CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
smtp_read_event, context);
smtp_early_event, context);
/*
* If this session ends here, we MUST read the blocklist cache otherwise
@ -905,12 +679,12 @@ static void smtp_read_event(int event, char *context)
*/
case EVENT_TIME:
if (*var_ps_dnsbl_sites)
dnsbl_count = postscreen_dnsbl_done(state->smtp_client_addr);
dnsbl_score = ps_dnsbl_retrieve(state->smtp_client_addr);
else
dnsbl_count = 0;
if (dnsbl_count > 0) {
dnsbl_score = 0;
if (dnsbl_score >= var_ps_dnsbl_thresh) {
msg_info("DNSBL rank %d for %s",
dnsbl_count, state->smtp_client_addr);
dnsbl_score, state->smtp_client_addr);
if (dnsbl_action == PS_ACT_DROP) {
smtp_reply(vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
@ -927,7 +701,7 @@ static void smtp_read_event(int event, char *context)
"OLD" : "NEW", state->smtp_client_addr);
if (cache_map != 0) {
vstring_sprintf(temp, "%ld", (long) event_time());
ps_dict_put(cache_map, state->smtp_client_addr, STR(temp));
ps_cache_update(cache_map, state->smtp_client_addr, STR(temp));
}
}
send_socket(state);
@ -964,14 +738,14 @@ static void smtp_read_event(int event, char *context)
}
if (action == PS_ACT_DROP) {
if (*var_ps_dnsbl_sites)
(void) postscreen_dnsbl_done(state->smtp_client_addr);
(void) ps_dnsbl_retrieve(state->smtp_client_addr);
free_session_state(state);
} else {
state->flags |= PS_FLAG_NOCACHE;
/* not: postscreen_dnsbl_done */
/* not: ps_dnsbl_retrieve */
if (elapsed > var_ps_greet_wait)
elapsed = var_ps_greet_wait;
event_request_timer(smtp_read_event, context,
event_request_timer(smtp_early_event, context,
var_ps_greet_wait - elapsed);
}
break;
@ -1145,7 +919,7 @@ static void postscreen_service(VSTREAM *smtp_client_stream,
* lowest precedence.
*/
else if (cache_map != 0
&& (stamp_str = ps_dict_get(cache_map, smtp_client_addr.buf)) != 0) {
&& (stamp_str = ps_cache_lookup(cache_map, smtp_client_addr.buf)) != 0) {
stamp_time = strtoul(stamp_str, 0, 10);
if (stamp_time > event_time() - var_ps_cache_ttl) {
msg_info("PASS OLD %s", smtp_client_addr.buf);
@ -1202,13 +976,13 @@ static void postscreen_service(VSTREAM *smtp_client_stream,
smtp_client_port.buf);
state->flags |= state_flags;
READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
smtp_read_event, (char *) state, var_ps_greet_wait);
smtp_early_event, (char *) state, var_ps_greet_wait);
/*
* Run a DNS blocklist query while we wait for the client to respond.
*/
if (*var_ps_dnsbl_sites)
postscreen_dnsbl_query(smtp_client_addr.buf);
ps_dnsbl_request(smtp_client_addr.buf);
}
/* postscreen_cache_validator - validate one cache entry */
@ -1315,10 +1089,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
vstring_sprintf(temp, "220-%s\r\n", var_ps_greet_banner);
teaser_greeting = mystrdup(STR(temp));
}
dnsbl_sites = argv_split(var_ps_dnsbl_sites, ", \t\r\n");
dnsbl_cache = htable_create(13);
reply_addr = vstring_alloc(100);
reply_domain = vstring_alloc(100);
ps_dnsbl_init();
if ((blist_action = name_code(actions, NAME_CODE_FLAG_NONE,
var_ps_blist_action)) < 0)
msg_fatal("bad %s value: %s", VAR_PS_BLIST_ACTION, var_ps_blist_action);
@ -1371,6 +1142,7 @@ int main(int argc, char **argv)
};
static const CONFIG_INT_TABLE int_table[] = {
VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
VAR_PS_DNSBL_THRESH, DEF_PS_DNSBL_THRESH, &var_ps_dnsbl_thresh, 0, 0,
0,
};
static const CONFIG_NINT_TABLE nint_table[] = {

View File

@ -0,0 +1,92 @@
/*++
/* NAME
/* postscreen 3h
/* SUMMARY
/* postscreen internal interfaces
/* SYNOPSIS
/* #include <postscreen.h>
/* DESCRIPTION
/* .nf
/*
* Utility library.
*/
#include <dict_cache.h>
/*
* Global library.
*/
#include <addr_match_list.h>
/*
* See log_adhoc.c for discussion.
*/
typedef struct {
int dt_sec; /* make sure it's signed */
int dt_usec; /* make sure it's signed */
} DELTA_TIME;
#define PS_CALC_DELTA(x, y, z) \
do { \
(x).dt_sec = (y).tv_sec - (z).tv_sec; \
(x).dt_usec = (y).tv_usec - (z).tv_usec; \
while ((x).dt_usec < 0) { \
(x).dt_usec += 1000000; \
(x).dt_sec -= 1; \
} \
while ((x).dt_usec >= 1000000) { \
(x).dt_usec -= 1000000; \
(x).dt_sec += 1; \
} \
if ((x).dt_sec < 0) \
(x).dt_sec = (x).dt_usec = 0; \
} while (0)
#define SIG_DIGS 2
/* READ_EVENT_REQUEST - prepare for transition to next state */
#define READ_EVENT_REQUEST(fd, action, context, timeout) do { \
if (msg_verbose) msg_info("%s: read-request fd=%d", myname, (fd)); \
event_enable_read((fd), (action), (context)); \
event_request_timer((action), (context), (timeout)); \
} while (0)
/* CLEAR_EVENT_REQUEST - complete state transition */
#define CLEAR_EVENT_REQUEST(fd, action, context) do { \
if (msg_verbose) msg_info("%s: clear-request fd=%d", myname, (fd)); \
event_disable_readwrite(fd); \
event_cancel_timer((action), (context)); \
} while (0)
/*
* SLMs.
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
/*
* postscreen_dict.c
*/
extern int ps_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
extern const char *ps_cache_lookup(DICT_CACHE *, const char *);
extern void ps_cache_update(DICT_CACHE *, const char *, const char *);
/*
* postscreen_dnsbl.c
*/
extern void ps_dnsbl_init(void);
extern int ps_dnsbl_retrieve(const char *);
extern void ps_dnsbl_request(const char *);
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/

View File

@ -0,0 +1,107 @@
/*++
/* NAME
/* postscreen_dict 3
/* SUMMARY
/* postscreen table access wrappers
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* int ps_addr_match_list_match(match_list, client_addr)
/* ADDR_MATCH_LIST *match_list;
/* const char *client_addr;
/*
/* const char *ps_cache_lookup(DICT_CACHE *cache, const char *key)
/* DICT_CACHE *cache;
/* const char *key;
/*
/* void ps_cache_update(cache, key, value)
/* DICT_CACHE *cache;
/* const char *key;
/* const char *value;
/* DESCRIPTION
/* This module implements wrappers around time-critical table
/* access functions. The functions log a warning when table
/* access takes a non-trivial amount of time.
/*
/* ps_addr_match_list_match() is a wrapper around
/* addr_match_list_match().
/*
/* ps_cache_lookup() and ps_cache_update() are wrappers around
/* the corresponding dict_cache() methods.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <msg.h>
/* Application-specific. */
#include <postscreen.h>
/*
* Monitor time-critical operations.
*/
#define PS_GET_TIME_BEFORE_LOOKUP \
struct timeval _before, _after; \
DELTA_TIME _delta; \
GETTIMEOFDAY(&_before);
#define PS_DELTA_MS(d) ((d).dt_sec * 1000 + (d).dt_usec / 1000)
#define PS_CHECK_TIME_AFTER_LOOKUP(table, action) \
GETTIMEOFDAY(&_after); \
PS_CALC_DELTA(_delta, _after, _before); \
if (_delta.dt_sec > 1 || _delta.dt_usec > 100000) \
msg_warn("%s: %s %s took %d ms", \
myname, (table), (action), PS_DELTA_MS(_delta));
/* ps_addr_match_list_match - time-critical address list lookup */
int ps_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
const char *addr_str)
{
const char *myname = "ps_addr_match_list_match";
int result;
PS_GET_TIME_BEFORE_LOOKUP;
result = addr_match_list_match(addr_list, addr_str);
PS_CHECK_TIME_AFTER_LOOKUP("address list", "lookup");
return (result);
}
/* ps_cache_lookup - time-critical cache lookup */
const char *ps_cache_lookup(DICT_CACHE *cache, const char *key)
{
const char *myname = "ps_cache_lookup";
const char *result;
PS_GET_TIME_BEFORE_LOOKUP;
result = dict_cache_lookup(cache, key);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup");
return (result);
}
/* ps_cache_update - time-critical cache update */
void ps_cache_update(DICT_CACHE *cache, const char *key, const char *value)
{
const char *myname = "ps_cache_update";
PS_GET_TIME_BEFORE_LOOKUP;
dict_cache_update(cache, key, value);
PS_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update");
}

View File

@ -0,0 +1,382 @@
/*++
/* NAME
/* postscreen_dnsbl 3
/* SUMMARY
/* postscreen DNSBL support
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* void ps_dnsbl_init(void)
/*
/* void ps_dnsbl_request(client_addr)
/* char *client_addr;
/*
/* int ps_dnsbl_retrieve(client_addr)
/* char *client_addr;
/* DESCRIPTION
/* This module implements preliminary support for DNSBL lookups
/* that complete in the background. Multiple requests for the
/* same information are handled with reference counts.
/*
/* ps_dnsbl_init() initializes this module, and must be called
/* once before any of the other functions in this module.
/*
/* ps_dnsbl_request() requests a blocklist score for the specified
/* client IP address and increments the reference count. The
/* client IP address must be in inet_ntop(3) output format.
/*
/* ps_dnsbl_retrieve() retrieves the result score requested with
/* ps_dnsbl_request() and decrements the reference count. It
/* is an error to retrieve a score without requesting it first.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <stdio.h> /* sscanf */
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <argv.h>
#include <htable.h>
#include <events.h>
#include <vstream.h>
#include <connect.h>
#include <split_at.h>
#include <valid_hostname.h>
/* Global library. */
#include <mail_params.h>
#include <mail_proto.h>
/* Application-specific. */
#include <postscreen.h>
#define DNSBL_SERVICE "dnsblog"
#define DNSBLOG_TIMEOUT 10
/*
* Per-DNSBL filters and weights.
*
* The postscreen_dnsbl_sites parameter specifies zero or more DNSBL domains.
* We provide multiple access methods, one for quick iteration when sending
* queries to all DNSBL servers, and one for quick location when receiving a
* reply from one DNSBL server.
*
* Each DNSBL domain can be specified more than once, each time with a
* different (filter, weight) pair. We group (filter, weight) pairs in a
* linked list under their DNSBL domain name.
*/
static HTABLE *dnsbl_site_cache; /* indexed by DNSBNL domain */
static HTABLE_INFO **dnsbl_site_list; /* flattened cache */
typedef struct PS_DNSBL_SITE {
char *filter; /* reply filter (default: null) */
int weight; /* reply weight (default: 1) */
struct PS_DNSBL_SITE *next; /* linked list */
} PS_DNSBL_SITE;
/*
* Per-client DNSBL scores.
*
* One remote SMTP client may make parallel connections and thereby trigger
* parallel blocklist score requests. We combine identical requests under
* the client IP address in a single reference-counted entry. The reference
* count goes up with each score request, and it goes down with each score
* retrieval.
*/
static HTABLE *dnsbl_score_cache; /* indexed by client address */
typedef struct {
int total; /* combined blocklist score */
int refcount; /* score reference count */
} PS_DNSBL_SCORE;
/*
* Per-request state.
*
* This implementation stores the client IP address and DNSBL domain in the
* DNSBLOG query/reply stream. This simplifies code, and allows the DNSBLOG
* server to produce more informative logging.
*/
static VSTRING *reply_client; /* client address in DNSBLOG reply */
static VSTRING *reply_dnsbl; /* domain in DNSBLOG reply */
static VSTRING *reply_addr; /* adress list in DNSBLOG reply */
/* ps_dnsbl_add_site - add DNSBL site information */
static void ps_dnsbl_add_site(const char *site)
{
const char *myname = "ps_dnsbl_add_site";
char *saved_site = mystrdup(site);
PS_DNSBL_SITE *old_site;
PS_DNSBL_SITE *new_site;
char junk;
const char *weight_text;
const char *pattern_text;
int weight;
/*
* Parse the required DNSBL domain name, the optional reply filter and
* the optional reply weight factor.
*/
#define DO_GRIPE 1
/* Negative weight means whitelist. */
if ((weight_text = split_at(saved_site, '*')) != 0) {
if (sscanf(weight_text, "%d%c", &weight, &junk) != 1)
msg_fatal("bad DNSBL weight factor \"%s\" in \"%s\"",
weight_text, site);
} else {
weight = 1;
}
/* Preliminary fixed-string filter. */
if ((pattern_text = split_at(saved_site, '=')) != 0) {
if (valid_ipv4_hostaddr(pattern_text, DO_GRIPE) == 0)
msg_fatal("bad DNSBL filter syntax \"%s\" in \"%s\"",
pattern_text, site);
}
if (valid_hostname(saved_site, DO_GRIPE) == 0)
msg_fatal("bad DNSBL domain name \"%s\" in \"%s\"",
saved_site, site);
if (msg_verbose)
msg_info("%s: \"%s\" -> domain=\"%s\" pattern=\"%s\" weight=%d",
myname, site, saved_site, pattern_text ? pattern_text :
"null", weight);
/*
* Add a new node for this DNSBL domain name. One DNSBL domain name can
* be specified multiple times with different filters and weights. These
* are stored as a linked list under the DNSBL domain name.
*/
new_site = (PS_DNSBL_SITE *) mymalloc(sizeof(*new_site));
new_site->filter = (pattern_text ? mystrdup(pattern_text) : 0);
new_site->weight = weight;
if ((old_site = (PS_DNSBL_SITE *)
htable_find(dnsbl_site_cache, saved_site)) != 0) {
new_site->next = old_site->next;
old_site->next = new_site;
} else {
(void) htable_enter(dnsbl_site_cache, saved_site, (char *) new_site);
new_site->next = 0;
}
myfree(saved_site);
}
/* ps_dnsbl_match - match DNSBL reply filter */
static int ps_dnsbl_match(const char *filter, ARGV *reply)
{
char **cpp;
/*
* Preliminary fixed-string implementation.
*/
for (cpp = reply->argv; *cpp != 0; cpp++)
if (strcmp(filter, *cpp) == 0)
return (1);
return (0);
}
/* ps_dnsbl_retrieve - retrieve blocklist score, decrement reference count */
int ps_dnsbl_retrieve(const char *client_addr)
{
const char *myname = "ps_dnsbl_retrieve";
PS_DNSBL_SCORE *score;
int result_score;
/*
* Sanity check.
*/
if ((score = (PS_DNSBL_SCORE *)
htable_find(dnsbl_score_cache, client_addr)) == 0)
msg_panic("%s: no blocklist score for %s", myname, client_addr);
/*
* Reads are destructive.
*/
result_score = score->total;
score->refcount -= 1;
if (score->refcount < 1) {
if (msg_verbose)
msg_info("%s: delete blocklist score for %s", myname, client_addr);
htable_delete(dnsbl_score_cache, client_addr, myfree);
}
return (result_score);
}
/* ps_dnsbl_receive - receive DNSBL reply, update blocklist score */
static void ps_dnsbl_receive(int event, char *context)
{
const char *myname = "ps_dnsbl_receive";
VSTREAM *stream = (VSTREAM *) context;
PS_DNSBL_SCORE *score;
PS_DNSBL_SITE *site;
ARGV *reply_argv;
CLEAR_EVENT_REQUEST(vstream_fileno(stream), ps_dnsbl_receive, context);
/*
* Receive the DNSBL lookup result.
*
* This is preliminary code to explore the field. Later, DNSBL lookup will
* be handled by an UDP-based DNS client that is built directly into some
* Postfix daemon.
*
* Don't bother looking up the blocklist score when the client IP address is
* not listed at the DNSBL.
*
* Don't panic when the blocklist score no longer exists. It may be deleted
* when the client triggers a "drop" action after pregreet, when the
* client does not pregreet and the DNSBL reply arrives late, or when the
* client triggers a "drop" action after hanging up.
*/
if (event == EVENT_READ
&& attr_scan(stream,
ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_dnsbl,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, reply_client,
ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, reply_addr,
ATTR_TYPE_END) == 3
&& *STR(reply_addr) != 0
&& (score = (PS_DNSBL_SCORE *)
htable_find(dnsbl_score_cache, STR(reply_client))) != 0) {
/*
* Run this response past all applicable DNSBL filters and update the
* blocklist score for this client IP address.
*
* Don't panic when the DNSBL domain name is not found. The DNSBLOG
* server may be messed up.
*/
if (msg_verbose)
msg_info("%s: client=\"%s\" score=%d domain=\"%s\" reply=\"%s\"",
myname, STR(reply_client), score->total,
STR(reply_dnsbl), STR(reply_addr));
for (reply_argv = 0, site = (PS_DNSBL_SITE *)
htable_find(dnsbl_site_cache, STR(reply_dnsbl));
site != 0; site = site->next) {
if (site->filter == 0
|| ps_dnsbl_match(site->filter, reply_argv ? reply_argv :
(reply_argv = argv_split(STR(reply_addr), " ")))) {
score->total += site->weight;
if (msg_verbose)
msg_info("%s: filter=\"%s\" weight=%d score=%d",
myname, site->filter ? site->filter : "null",
site->weight, score->total);
}
}
if (reply_argv != 0)
argv_free(reply_argv);
}
vstream_fclose(stream);
}
/* ps_dnsbl_request - send dnsbl query, increment reference count */
void ps_dnsbl_request(const char *client_addr)
{
const char *myname = "ps_dnsbl_request";
int fd;
VSTREAM *stream;
HTABLE_INFO **ht;
PS_DNSBL_SCORE *score;
/*
* Avoid duplicate effort when this lookup is already in progress. We
* store a reference-counted DNSBL score under its client IP address. We
* increment the reference count with each request, and decrement the
* reference count with each retrieval.
*/
if ((score = (PS_DNSBL_SCORE *)
htable_find(dnsbl_score_cache, client_addr)) != 0) {
score->refcount += 1;
return;
}
if (msg_verbose)
msg_info("%s: create blocklist score for %s", myname, client_addr);
score = (PS_DNSBL_SCORE *) mymalloc(sizeof(*score));
score->total = 0;
score->refcount = 1;
(void) htable_enter(dnsbl_score_cache, client_addr, (char *) score);
/*
* Send a query to all DNSBL servers. Later, DNSBL lookup will be done
* with an UDP-based DNS client that is built directly into Postfix code.
* We therefore do not optimize the maximum out of this temporary
* implementation.
*/
for (ht = dnsbl_site_list; *ht; ht++) {
if ((fd = LOCAL_CONNECT("private/" DNSBL_SERVICE, NON_BLOCKING, 1)) < 0) {
msg_warn("%s: connect to " DNSBL_SERVICE " service: %m", myname);
return;
}
stream = vstream_fdopen(fd, O_RDWR);
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, ht[0]->key,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, client_addr,
ATTR_TYPE_END);
if (vstream_fflush(stream) != 0) {
msg_warn("%s: error sending to " DNSBL_SERVICE " service: %m", myname);
vstream_fclose(stream);
return;
}
READ_EVENT_REQUEST(vstream_fileno(stream), ps_dnsbl_receive,
(char *) stream, DNSBLOG_TIMEOUT);
}
}
/* ps_dnsbl_init - initialize */
void ps_dnsbl_init(void)
{
const char *myname = "ps_dnsbl_init";
ARGV *dnsbl_site = argv_split(var_ps_dnsbl_sites, ", \t\r\n");
char **cpp;
/*
* Sanity check.
*/
if (dnsbl_site_cache != 0)
msg_panic("%s: called more than once", myname);
/*
* Prepare for quick iteration when sending out queries to all DNSBL
* servers, and for quick lookup when a reply arrives from a specific
* DNSBL server.
*/
dnsbl_site_cache = htable_create(13);
for (cpp = dnsbl_site->argv; *cpp; cpp++)
ps_dnsbl_add_site(*cpp);
argv_free(dnsbl_site);
dnsbl_site_list = htable_list(dnsbl_site_cache);
/*
* The per-client blocklist score.
*/
dnsbl_score_cache = htable_create(13);
/*
* Space for ad-hoc DNSBLOG server request/reply parameters.
*/
reply_client = vstring_alloc(100);
reply_dnsbl = vstring_alloc(100);
reply_addr = vstring_alloc(100);
}