2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

postfix-2.3-20051010

This commit is contained in:
Wietse Venema 2005-10-10 00:00:00 -05:00 committed by Viktor Dukhovni
parent 14313fe35c
commit 88a2e39fc7
37 changed files with 932 additions and 543 deletions

2
postfix/.indent.pro vendored
View File

@ -3,7 +3,9 @@
-TALIAS_TOKEN -TALIAS_TOKEN
-TANVIL_CLNT -TANVIL_CLNT
-TANVIL_LOCAL -TANVIL_LOCAL
-TANVIL_MAX
-TANVIL_REMOTE -TANVIL_REMOTE
-TANVIL_REQ_TABLE
-TARGV -TARGV
-TATTR_CLNT -TATTR_CLNT
-TATTR_TABLE -TATTR_TABLE

View File

@ -11148,19 +11148,47 @@ Apologies for any names omitted.
others. Files: local/local.c, local/aliases.c, local/dotforward.c, others. Files: local/local.c, local/aliases.c, local/dotforward.c,
local/mailbox.c, local/maildir.c. local/mailbox.c, local/maildir.c.
Cleanup: while expanding a local(8) alias that has an owner
alias, don't reset the owner-alias information when recursing
into an alias that has no owner alias. This produces better
error reports when delivering mail to nested aliases that
have an owner alias only at the top level. To get the old
behavior, specify "sticky_owner_alias = no". Problem
reported by Victor Duchovni. File: local/alias.c.
Logging: additional SASL debug logging by Andreas Winkelmann. Logging: additional SASL debug logging by Andreas Winkelmann.
Files: */*sasl_glue.c. Files: */*sasl_glue.c.
20050929
Paranoia: don't ignore garbage in SMTP or LMTP server replies
when ESMTP command pipelining is turned on. For example,
after sending ".<CR><LF>QUIT<CR><LF>", Postfix could recognize
the server's 2XX QUIT reply as a 2XX END-OF-DATA reply after
garbage, causing mail to be lost. The SMTP and LMTP clients
now report a remote protocol error and defer delivery.
Files: smtp/smtp_chat.c, smtp/smtp_trouble.c, lmtp/lmtp_chat.c,
lmtp/lmtp_trouble.c.
Performance: specify "smtpd_peername_lookup = no" to disable
client hostname lookups in the SMTP server. All clients are
treated as "unknown". This should be used only under extreme
conditions where DNS lookup latencies are critical. File:
smtpd/smtpd_peer.c.
20051010
Feature: smtpd_client_new_tls_session_rate_limit parameter
to limit the number of new (i.e. uncached) TLS sessions
that a remote SMTP client may negotiate per unit time. This
feature, which is off by default, can limit the CPU load
due to expensive crypto operations. Files: global/anvil_clnt.c,
anvil/anvil.c, smtpd/smtpd.c.
Cleanup: eliminated code duplicatiom in the anvil server
that resulted from adding similar features one at a time.
File: anvil/anvil.c.
Open problems: Open problems:
Try to recognize that Resent- headers appear in blocks,
newest block first. But don't break on incorrect header
block organization.
Hard limits on cache sizes (anvil, specifically).
Look for systems with XPG basename() declared in <libgen.h>, Look for systems with XPG basename() declared in <libgen.h>,
and prepare for phasing out the Postfix-supplied one. and prepare for phasing out the Postfix-supplied one.
Beware, however, that XPG basename() takes (char *), and Beware, however, that XPG basename() takes (char *), and

View File

@ -17,7 +17,8 @@ Postfix source code, in the directory examples/smtpd-policy.
Policy delegation is now the preferred method for adding policies to Postfix. Policy delegation is now the preferred method for adding policies to Postfix.
It's much easier to develop a new feature in few lines of Perl, than trying to It's much easier to develop a new feature in few lines of Perl, than trying to
do the same in C code. The difference in performance will be unnoticeable do the same in C code. The difference in performance will be unnoticeable
except in the most demanding environments. except in the most demanding environments. On active systems a policy daemon
process is used multiple times, for up to 100 incoming SMTP connections.
This document covers the following topics: This document covers the following topics:

View File

@ -26,12 +26,9 @@ files. With deeply nested aliases or .forward files, this can greatly
reduce the number of queue files and cleanup process instances. To reduce the number of queue files and cleanup process instances. To
get the earlier behavior, specify "frozen_delivered_to = no". get the earlier behavior, specify "frozen_delivered_to = no".
While expanding an alias that has an owner alias, the Postfix The frozen_delivered_to feature also fixes an old problem with
local(8) delivery agent no longer resets the owner information when duplicate deliveries to recipients that are listed in multiple
it expands a subordinate alias that has no owner alias. This nested aliases.
produces better error reporting with nested aliases that have an
owner alias only at the top level. To get the earlier behavior,
specify "sticky_owner_alias = no".
Incompatibility with snapshot 20050828 Incompatibility with snapshot 20050828
====================================== ======================================

View File

@ -36,7 +36,8 @@ the Postfix source code, in the directory examples/smtpd-policy.
to Postfix. It's much easier to develop a new feature in few lines to Postfix. It's much easier to develop a new feature in few lines
of Perl, than trying to do the same in C code. The difference in of Perl, than trying to do the same in C code. The difference in
performance will be unnoticeable except in the most demanding performance will be unnoticeable except in the most demanding
environments. </p> environments. On active systems a policy daemon process is used
multiple times, for up to 100 incoming SMTP connections. </p>
<p> This document covers the following topics: </p> <p> This document covers the following topics: </p>

View File

@ -13,151 +13,167 @@ ANVIL(8) ANVIL(8)
<b>anvil</b> [generic Postfix daemon options] <b>anvil</b> [generic Postfix daemon options]
<b>DESCRIPTION</b> <b>DESCRIPTION</b>
The Postfix <a href="anvil.8.html"><b>anvil</b>(8)</a> server maintains short-term statis- The Postfix <a href="anvil.8.html"><b>anvil</b>(8)</a> server maintains statistics about
tics to defend against clients that hammer a server with client connection counts or client request rates. This
either too many simultaneous sessions, or with too many information can be used to defend against clients that
successive requests within a configurable time interval. hammer a server with either too many simultaneous ses-
This server is designed to run under control by the Post- sions, or with too many successive requests within a con-
fix <a href="master.8.html"><b>master</b>(8)</a> server. figurable time interval. This server is designed to run
under control by the Postfix <a href="master.8.html"><b>master</b>(8)</a> server.
The <a href="anvil.8.html"><b>anvil</b>(8)</a> server maintains no persistent database. In the following text, <b>ident</b> specifies a (service, client)
Standard library utilities do not meet Postfix performance combination. The exact syntax of that information is
and robustness requirements. application-dependent; the <a href="anvil.8.html"><b>anvil</b>(8)</a> server does not care.
<b>CONNECTION COUNT/RATE LIMITING</b> <b>CONNECTION COUNT/RATE CONTROL</b>
When a remote client connects, a connection count (or To register a new connection send the following request to
rate) limited server should send the following request to
the <a href="anvil.8.html"><b>anvil</b>(8)</a> server: the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
<b>request=connect</b> <b>request=connect</b>
<b>ident=</b><i>string</i> <b>ident=</b><i>string</i>
This registers a new connection for the (service, client) The <a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of simultane-
combination specified with <b>ident</b>. The <a href="anvil.8.html"><b>anvil</b>(8)</a> server ous connections and the number of connections per unit
answers with the number of simultaneous connections and time for the (service, client) combination specified with
the number of connections per unit time for that (service, <b>ident</b>:
client) combination:
<b>status=0</b> <b>status=0</b>
<b>count=</b><i>number</i> <b>count=</b><i>number</i>
<b>rate=</b><i>number</i> <b>rate=</b><i>number</i>
The <b>rate</b> is computed as the number of connections that To register a disconnect event send the following request
were registered in the current "time unit" interval. It to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
is left up to the server to decide if the remote client
exceeds the connection count (or rate) limit.
When a remote client disconnects, a connection count (or
rate) limited server should send the following request to
the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
<b>request=disconnect</b> <b>request=disconnect</b>
<b>ident=</b><i>string</i> <b>ident=</b><i>string</i>
This registers a disconnect event for the (service, The <a href="anvil.8.html"><b>anvil</b>(8)</a> server replies with:
client) combination specified with <b>ident</b>. The <a href="anvil.8.html"><b>anvil</b>(8)</a>
server replies with:
<b>status=0</b> <b>status=0</b>
<b>MESSAGE RATE LIMITING</b> <b>MESSAGE RATE CONTROL</b>
When a remote client sends a message delivery request, a To register a message delivery request send the following
message rate limited server should send the following
request to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server: request to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
<b>request=message</b> <b>request=message</b>
<b>ident=</b><i>string</i> <b>ident=</b><i>string</i>
This registers a message delivery request for the (ser- The <a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of message
vice, client) combination specified with <b>ident</b>. The delivery requests per unit time for the (service, client)
<a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of message deliv- combination specified with <b>ident</b>:
ery requests per unit time for that (service, client) com-
bination:
<b>status=0</b> <b>status=0</b>
<b>rate=</b><i>number</i> <b>rate=</b><i>number</i>
In order to prevent the <a href="anvil.8.html"><b>anvil</b>(8)</a> server from discarding <b>RECIPIENT RATE CONTROL</b>
client request rates too early or too late, a message rate To register a recipient request send the following request
limited service should also register connect/disconnect
events.
<b>RECIPIENT RATE LIMITING</b>
When a remote client sends a recipient address, a recipi-
ent rate limited server should send the following request
to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server: to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
<b>request=recipient</b> <b>request=recipient</b>
<b>ident=</b><i>string</i> <b>ident=</b><i>string</i>
This registers a recipient request for the (service, The <a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of recipient
client) combination specified with <b>ident</b>. The <a href="anvil.8.html"><b>anvil</b>(8)</a> addresses per unit time for the (service, client) combina-
server answers with the number of recipient addresses per tion specified with <b>ident</b>:
unit time for that (service, client) combination:
<b>status=0</b> <b>status=0</b>
<b>rate=</b><i>number</i> <b>rate=</b><i>number</i>
In order to prevent the <a href="anvil.8.html"><b>anvil</b>(8)</a> server from discarding <b>TLS SESSION NEGOTIATION RATE CONTROL</b>
client request rates too early or too late, a recipient The features described in this section are available with
rate limited service should also register connect/discon- Postfix 2.3 and later.
nect events.
To register a request for a new (i.e. not cached) TLS ses-
sion send the following request to the <a href="anvil.8.html"><b>anvil</b>(8)</a> server:
<b>request=newtls</b>
<b>ident=</b><i>string</i>
The <a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of new TLS
session requests per unit time for the (service, client)
combination specified with <b>ident</b>:
<b>status=0</b>
<b>rate=</b><i>number</i>
To retrieve new TLS session request rate information with-
out updating the counter information, use:
<b>request=newtls_report</b>
<b>ident=</b><i>string</i>
The <a href="anvil.8.html"><b>anvil</b>(8)</a> server answers with the number of new TLS
session requests per unit time for the (service, client)
combination specified with <b>ident</b>.
<b>status=0</b>
<b>rate=</b><i>number</i>
<b>SECURITY</b> <b>SECURITY</b>
The <a href="anvil.8.html"><b>anvil</b>(8)</a> server does not talk to the network or to The <a href="anvil.8.html"><b>anvil</b>(8)</a> server does not talk to the network or to
local users, and can run chrooted at fixed low privilege. local users, and can run chrooted at fixed low privilege.
The <a href="anvil.8.html"><b>anvil</b>(8)</a> server maintains an in-memory table with The <a href="anvil.8.html"><b>anvil</b>(8)</a> server maintains an in-memory table with
information about recent clients of a connection count (or information about recent clients requests. No persistent
rate) limited service. Although state is kept only tempo- state is kept because standard system library routines are
rarily, this may require a lot of memory on systems that not sufficiently robust for update-intensive applications.
handle connections from many remote clients. To reduce
memory usage, reduce the time unit over which state is Although the in-memory state is kept only temporarily,
kept. this may require a lot of memory on systems that handle
connections from many remote clients. To reduce memory
usage, reduce the time unit over which state is kept.
<b>DIAGNOSTICS</b> <b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8). Problems and transactions are logged to <b>syslogd</b>(8).
Upon exit, and every <b><a href="postconf.5.html#anvil_status_update_time">anvil_status_update_time</a></b> seconds, the Upon exit, and every <b><a href="postconf.5.html#anvil_status_update_time">anvil_status_update_time</a></b> seconds, the
server logs the maximal count and rate values measured, server logs the maximal count and rate values measured,
together with (service, client) information and the time together with (service, client) information and the time
of day associated with those events. In order to avoid of day associated with those events. In order to avoid
unnecessary overhead, no measurements are done for activ- unnecessary overhead, no measurements are done for activ-
ity that isn't concurrency limited or rate limited. ity that isn't concurrency limited or rate limited.
<b>BUGS</b> <b>BUGS</b>
Systems behind network address translating routers or Systems behind network address translating routers or
proxies appear to have the same client address and can run proxies appear to have the same client address and can run
into connection count and/or rate limits falsely. into connection count and/or rate limits falsely.
In this preliminary implementation, a count (or rate) lim- In this preliminary implementation, a count (or rate) lim-
ited server can have only one remote client at a time. If ited server can have only one remote client at a time. If
a server reports multiple simultaneous clients, all but a server reports multiple simultaneous clients, all but
the last reported client are ignored. the last reported client are ignored.
<b>CONFIGURATION PARAMETERS</b> The <a href="anvil.8.html"><b>anvil</b>(8)</a> server automatically discards client request
Changes to <b>main.cf</b> are picked up automatically as <a href="anvil.8.html"><b>anvil</b>(8)</a> information after it expires. To prevent the <a href="anvil.8.html"><b>anvil</b>(8)</a>
processes run for only a limited amount of time. Use the server from discarding client request rate information too
command "<b>postfix reload</b>" to speed up a change. early or too late, a rate limited service should always
register connect/disconnect events even when it does not
explicitly limit them.
The text below provides only a parameter summary. See <b>CONFIGURATION PARAMETERS</b>
On low-traffic mail systems, changes to <b>main.cf</b> are picked
up automatically as <a href="anvil.8.html"><b>anvil</b>(8)</a> processes run for only a lim-
ited amount of time. On other mail systems, use the com-
mand "<b>postfix reload</b>" to speed up a change.
The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples. <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a> (60s)</b> <b><a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a> (60s)</b>
The time unit over which client connection rates The time unit over which client connection rates
and other rates are calculated. and other rates are calculated.
<b><a href="postconf.5.html#anvil_status_update_time">anvil_status_update_time</a> (600s)</b> <b><a href="postconf.5.html#anvil_status_update_time">anvil_status_update_time</a> (600s)</b>
How frequently the <a href="anvil.8.html"><b>anvil</b>(8)</a> connection and rate How frequently the <a href="anvil.8.html"><b>anvil</b>(8)</a> connection and rate
limiting server logs peak usage information. limiting server logs peak usage information.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b> <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix main.cf and The default location of the Postfix main.cf and
master.cf configuration files. master.cf configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b> <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to How much time a Postfix daemon process may take to
handle a request before it is terminated by a handle a request before it is terminated by a
built-in watchdog timer. built-in watchdog timer.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b> <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@ -165,28 +181,28 @@ ANVIL(8) ANVIL(8)
over an internal communication channel. over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b> <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix The maximum amount of time that an idle Postfix
daemon process waits for the next service request daemon process waits for the next service request
before exiting. before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b> <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
The maximal number of connection requests before a The maximal number of connection requests before a
Postfix daemon process terminates. Postfix daemon process terminates.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b> <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. process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b> <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. process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b> <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging. The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b> <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
The mail system name that is prepended to the The mail system name that is prepended to the
process name in syslog records, so that "smtpd" process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd". becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b> <b>SEE ALSO</b>
@ -198,7 +214,7 @@ ANVIL(8) ANVIL(8)
<a href="TUNING_README.html">TUNING_README</a>, performance tuning <a href="TUNING_README.html">TUNING_README</a>, performance tuning
<b>LICENSE</b> <b>LICENSE</b>
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>HISTORY</b> <b>HISTORY</b>

View File

@ -386,13 +386,6 @@ LOCAL(8) LOCAL(8)
attempt; do not update the Delivered-To: address attempt; do not update the Delivered-To: address
while expanding aliases or .forward files. while expanding aliases or .forward files.
<b><a href="postconf.5.html#sticky_owner_alias">sticky_owner_alias</a> (yes)</b>
When expanding a <a href="local.8.html"><b>local</b>(8)</a> alias that has an owner
alias (see owner-<i>name</i> discussion in <a href="aliases.5.html"><b>aliases</b>(5)</a>),
use the owner information even when the expansion
invokes a subordinate alias that has no owner
alias.
<b>DELIVERY METHOD CONTROLS</b> <b>DELIVERY METHOD CONTROLS</b>
The precedence of <a href="local.8.html"><b>local</b>(8)</a> delivery methods from high to The precedence of <a href="local.8.html"><b>local</b>(8)</a> delivery methods from high to
low is: aliases, .forward files, <a href="postconf.5.html#mailbox_transport">mailbox_transport</a>, <a href="postconf.5.html#mailbox_command_maps">mail</a>- low is: aliases, .forward files, <a href="postconf.5.html#mailbox_transport">mailbox_transport</a>, <a href="postconf.5.html#mailbox_command_maps">mail</a>-

View File

@ -7205,6 +7205,47 @@ Example:
</pre> </pre>
</DD>
<DT><b><a name="smtpd_client_new_tls_session_rate_limit">smtpd_client_new_tls_session_rate_limit</a>
(default: 0)</b></DT><DD>
<p>
The maximal number of new (i.e., uncached) TLS sessions that a
remote SMTP client is allowed to negotiate with this service per
time unit. The time unit is specified with the <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_time_unit</a>
configuration parameter.
</p>
<p>
By default, a remote SMTP client can negotiate as many new TLS
sessions per time unit as Postfix can accept.
</p>
<p>
To disable this feature, specify a limit of 0. Otherwise, specify
a limit that is at least the per-client concurrent session limit,
or else legitimate client sessions may be rejected.
</p>
<p>
WARNING: The purpose of this feature is to limit abuse. It must
not be used to regulate legitimate mail traffic.
</p>
<p>
This feature is available in Postfix 2.3 and later.
</p>
<p>
Example:
</p>
<pre>
<a href="postconf.5.html#smtpd_client_new_tls_session_rate_limit">smtpd_client_new_tls_session_rate_limit</a> = 100
</pre>
</DD> </DD>
<DT><b><a name="smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a> <DT><b><a name="smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a>
@ -7924,6 +7965,18 @@ null sender address.
</p> </p>
</DD>
<DT><b><a name="smtpd_peername_lookup">smtpd_peername_lookup</a>
(default: yes)</b></DT><DD>
<p> Attempt to look up the SMTP client hostname, and verify that
the name matches the client IP address. A client name is set to
"unknown" when it cannot be looked up or verified, or when name
lookup is disabled. Turning off name lookup reduces delays due to
DNS lookup and increases the maximal inbound delivery rate. </p>
</DD> </DD>
<DT><b><a name="smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a> <DT><b><a name="smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a>
@ -9149,22 +9202,6 @@ The default time unit is s (seconds).
</p> </p>
</DD>
<DT><b><a name="sticky_owner_alias">sticky_owner_alias</a>
(default: yes)</b></DT><DD>
<p> When expanding a <a href="local.8.html">local(8)</a> alias that has an owner alias (see
owner-<i>name</i> discussion in <a href="aliases.5.html">aliases(5)</a>), use the owner information
even when the expansion invokes a subordinate alias that has no
owner alias. </p>
<p> This feature is available in Postfix 2.3 and later. With older
Postfix releases, the behavior is as if this parameter is set to
"no". The old setting provides poorer error reporting with nested
aliases that only have an owner alias at the top level. </p>
</DD> </DD>
<DT><b><a name="strict_7bit_headers">strict_7bit_headers</a> <DT><b><a name="strict_7bit_headers">strict_7bit_headers</a>

View File

@ -548,6 +548,12 @@ SMTPD(8) SMTPD(8)
server command history before it is flushed upon server command history before it is flushed upon
receipt of EHLO, RSET, or end of DATA. receipt of EHLO, RSET, or end of DATA.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#smtpd_peername_lookup">smtpd_peername_lookup</a> (yes)</b>
Attempt to look up the SMTP client hostname, and
verify that the name matches the client IP address.
The per SMTP client connection count and request rate lim- The per SMTP client connection count and request rate lim-
its are implemented in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> ser- its are implemented in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> ser-
vice, and are available in Postfix version 2.2 and later. vice, and are available in Postfix version 2.2 and later.
@ -577,6 +583,13 @@ SMTPD(8) SMTPD(8)
Clients that are excluded from connection count, Clients that are excluded from connection count,
connection rate, or SMTP request rate restrictions. connection rate, or SMTP request rate restrictions.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#smtpd_client_new_tls_session_rate_limit">smtpd_client_new_tls_session_rate_limit</a> (0)</b>
The maximal number of new (i.e., uncached) TLS ses-
sions that any client is allowed to negotiate with
this service per time unit.
<b>TARPIT CONTROLS</b> <b>TARPIT CONTROLS</b>
When a remote SMTP client makes errors, the Postfix SMTP When a remote SMTP client makes errors, the Postfix SMTP
server can insert delays before responding. This can help server can insert delays before responding. This can help

View File

@ -4070,6 +4070,33 @@ smtpd_client_message_rate_limit = 1000
.fi .fi
.ad .ad
.ft R .ft R
.SH smtpd_client_new_tls_session_rate_limit (default: 0)
The maximal number of new (i.e., uncached) TLS sessions that a
remote SMTP client is allowed to negotiate with this service per
time unit. The time unit is specified with the anvil_rate_time_unit
configuration parameter.
.PP
By default, a remote SMTP client can negotiate as many new TLS
sessions per time unit as Postfix can accept.
.PP
To disable this feature, specify a limit of 0. Otherwise, specify
a limit that is at least the per-client concurrent session limit,
or else legitimate client sessions may be rejected.
.PP
WARNING: The purpose of this feature is to limit abuse. It must
not be used to regulate legitimate mail traffic.
.PP
This feature is available in Postfix 2.3 and later.
.PP
Example:
.PP
.nf
.na
.ft C
smtpd_client_new_tls_session_rate_limit = 100
.fi
.ad
.ft R
.SH smtpd_client_recipient_rate_limit (default: 0) .SH smtpd_client_recipient_rate_limit (default: 0)
The maximal number of recipient addresses that any client is allowed The maximal number of recipient addresses that any client is allowed
to send to this service per time unit, regardless of whether or not to send to this service per time unit, regardless of whether or not
@ -4540,6 +4567,12 @@ This list overrides any commands built into the Postfix SMTP server.
.SH smtpd_null_access_lookup_key (default: <>) .SH smtpd_null_access_lookup_key (default: <>)
The lookup key to be used in SMTP \fBaccess\fR(5) tables instead of the The lookup key to be used in SMTP \fBaccess\fR(5) tables instead of the
null sender address. null sender address.
.SH smtpd_peername_lookup (default: yes)
Attempt to look up the SMTP client hostname, and verify that
the name matches the client IP address. A client name is set to
"unknown" when it cannot be looked up or verified, or when name
lookup is disabled. Turning off name lookup reduces delays due to
DNS lookup and increases the maximal inbound delivery rate.
.SH smtpd_policy_service_max_idle (default: 300s) .SH smtpd_policy_service_max_idle (default: 300s)
The time after which an idle SMTPD policy service connection is The time after which an idle SMTPD policy service connection is
closed. closed.
@ -5349,16 +5382,6 @@ This is used for delivery to file or mailbox.
.PP .PP
Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
The default time unit is s (seconds). The default time unit is s (seconds).
.SH sticky_owner_alias (default: yes)
When expanding a \fBlocal\fR(8) alias that has an owner alias (see
owner-\fIname\fR discussion in \fBaliases\fR(5)), use the owner information
even when the expansion invokes a subordinate alias that has no
owner alias.
.PP
This feature is available in Postfix 2.3 and later. With older
Postfix releases, the behavior is as if this parameter is set to
"no". The old setting provides poorer error reporting with nested
aliases that only have an owner alias at the top level.
.SH strict_7bit_headers (default: no) .SH strict_7bit_headers (default: no)
Reject mail with 8-bit text in message headers. This blocks mail Reject mail with 8-bit text in message headers. This blocks mail
from poorly written applications. from poorly written applications.

View File

@ -12,23 +12,25 @@ Postfix session count and request rate control
.SH DESCRIPTION .SH DESCRIPTION
.ad .ad
.fi .fi
The Postfix \fBanvil\fR(8) server maintains short-term statistics The Postfix \fBanvil\fR(8) server maintains statistics about
to defend against clients that hammer a server with either too client connection counts or client request rates. This
many simultaneous sessions, or with too many successive requests information can be used to defend against clients that
within a configurable time interval. hammer a server with either too many simultaneous sessions,
This server is designed to run under control by the Postfix or with too many successive requests within a configurable
\fBmaster\fR(8) server. time interval. This server is designed to run under control
by the Postfix \fBmaster\fR(8) server.
The \fBanvil\fR(8) server maintains no persistent database. Standard In the following text, \fBident\fR specifies a (service,
library utilities do not meet Postfix performance and robustness client) combination. The exact syntax of that information
requirements. is application-dependent; the \fBanvil\fR(8) server does
.SH "CONNECTION COUNT/RATE LIMITING" not care.
.SH "CONNECTION COUNT/RATE CONTROL"
.na .na
.nf .nf
.ad .ad
.fi .fi
When a remote client connects, a connection count (or rate) limited To register a new connection send the following request to
server should send the following request to the \fBanvil\fR(8) server: the \fBanvil\fR(8) server:
.PP .PP
.in +4 .in +4
\fBrequest=connect\fR \fBrequest=connect\fR
@ -36,11 +38,10 @@ server should send the following request to the \fBanvil\fR(8) server:
\fBident=\fIstring\fR \fBident=\fIstring\fR
.in .in
.PP .PP
This registers a new connection for the (service, client) The \fBanvil\fR(8) server answers with the number of
combination specified with \fBident\fR. The \fBanvil\fR(8) server simultaneous connections and the number of connections per
answers with the number of simultaneous connections and the unit time for the (service, client) combination specified
number of connections per unit time for that (service, client) with \fBident\fR:
combination:
.PP .PP
.in +4 .in +4
\fBstatus=0\fR \fBstatus=0\fR
@ -50,13 +51,8 @@ combination:
\fBrate=\fInumber\fR \fBrate=\fInumber\fR
.in .in
.PP .PP
The \fBrate\fR is computed as the number of connections To register a disconnect event send the following request
that were registered in the current "time unit" interval. to the \fBanvil\fR(8) server:
It is left up to the server to decide if the remote client
exceeds the connection count (or rate) limit.
.PP
When a remote client disconnects, a connection count (or rate) limited
server should send the following request to the \fBanvil\fR(8) server:
.PP .PP
.in +4 .in +4
\fBrequest=disconnect\fR \fBrequest=disconnect\fR
@ -64,19 +60,16 @@ server should send the following request to the \fBanvil\fR(8) server:
\fBident=\fIstring\fR \fBident=\fIstring\fR
.in .in
.PP .PP
This registers a disconnect event for the (service, client) The \fBanvil\fR(8) server replies with:
combination specified with \fBident\fR. The \fBanvil\fR(8)
server replies with:
.PP .PP
.ti +4 .ti +4
\fBstatus=0\fR \fBstatus=0\fR
.SH "MESSAGE RATE LIMITING" .SH "MESSAGE RATE CONTROL"
.na .na
.nf .nf
.ad .ad
.fi .fi
When a remote client sends a message delivery request, a To register a message delivery request send the following
message rate limited server should send the following
request to the \fBanvil\fR(8) server: request to the \fBanvil\fR(8) server:
.PP .PP
.in +4 .in +4
@ -85,28 +78,22 @@ request to the \fBanvil\fR(8) server:
\fBident=\fIstring\fR \fBident=\fIstring\fR
.in .in
.PP .PP
This registers a message delivery request for the (service, client) The \fBanvil\fR(8) server answers with the number of message
combination specified with \fBident\fR. The \fBanvil\fR(8) server delivery requests per unit time for the (service, client)
answers with the number of message delivery requests per unit time combination specified with \fBident\fR:
for that (service, client) combination:
.PP .PP
.in +4 .in +4
\fBstatus=0\fR \fBstatus=0\fR
.br .br
\fBrate=\fInumber\fR \fBrate=\fInumber\fR
.in .in
.PP .SH "RECIPIENT RATE CONTROL"
In order to prevent the \fBanvil\fR(8) server from discarding client
request rates too early or too late, a message rate limited
service should also register connect/disconnect events.
.SH "RECIPIENT RATE LIMITING"
.na .na
.nf .nf
.ad .ad
.fi .fi
When a remote client sends a recipient address, a recipient To register a recipient request send the following request
rate limited server should send the following request to to the \fBanvil\fR(8) server:
the \fBanvil\fR(8) server:
.PP .PP
.in +4 .in +4
\fBrequest=recipient\fR \fBrequest=recipient\fR
@ -114,10 +101,35 @@ the \fBanvil\fR(8) server:
\fBident=\fIstring\fR \fBident=\fIstring\fR
.in .in
.PP .PP
This registers a recipient request for the (service, client) The \fBanvil\fR(8) server answers with the number of recipient
combination specified with \fBident\fR. The \fBanvil\fR(8) server addresses per unit time for the (service, client) combination
answers with the number of recipient addresses per unit time specified with \fBident\fR:
for that (service, client) combination: .PP
.in +4
\fBstatus=0\fR
.br
\fBrate=\fInumber\fR
.in
.SH "TLS SESSION NEGOTIATION RATE CONTROL"
.na
.nf
.ad
.fi
The features described in this section are available with
Postfix 2.3 and later.
To register a request for a new (i.e. not cached) TLS session
send the following request to the \fBanvil\fR(8) server:
.PP
.in +4
\fBrequest=newtls\fR
.br
\fBident=\fIstring\fR
.in
.PP
The \fBanvil\fR(8) server answers with the number of new
TLS session requests per unit time for the (service, client)
combination specified with \fBident\fR:
.PP .PP
.in +4 .in +4
\fBstatus=0\fR \fBstatus=0\fR
@ -125,9 +137,24 @@ for that (service, client) combination:
\fBrate=\fInumber\fR \fBrate=\fInumber\fR
.in .in
.PP .PP
In order to prevent the \fBanvil\fR(8) server from discarding client To retrieve new TLS session request rate information without
request rates too early or too late, a recipient rate limited updating the counter information, use:
service should also register connect/disconnect events. .PP
.in +4
\fBrequest=newtls_report\fR
.br
\fBident=\fIstring\fR
.in
.PP
The \fBanvil\fR(8) server answers with the number of new
TLS session requests per unit time for the (service, client)
combination specified with \fBident\fR.
.PP
.in +4
\fBstatus=0\fR
.br
\fBrate=\fInumber\fR
.in
.SH "SECURITY" .SH "SECURITY"
.na .na
.nf .nf
@ -136,12 +163,15 @@ service should also register connect/disconnect events.
The \fBanvil\fR(8) server does not talk to the network or to local The \fBanvil\fR(8) server does not talk to the network or to local
users, and can run chrooted at fixed low privilege. users, and can run chrooted at fixed low privilege.
The \fBanvil\fR(8) server maintains an in-memory table with information The \fBanvil\fR(8) server maintains an in-memory table with
about recent clients of a connection count (or rate) limited service. information about recent clients requests. No persistent
Although state is kept only temporarily, this may require a lot of state is kept because standard system library routines are
memory on systems that handle connections from many remote clients. not sufficiently robust for update-intensive applications.
To reduce memory usage, reduce the time unit over which state
is kept. Although the in-memory state is kept only temporarily, this
may require a lot of memory on systems that handle connections
from many remote clients. To reduce memory usage, reduce
the time unit over which state is kept.
.SH DIAGNOSTICS .SH DIAGNOSTICS
.ad .ad
.fi .fi
@ -165,14 +195,22 @@ In this preliminary implementation, a count (or rate) limited server
can have only one remote client at a time. If a server reports can have only one remote client at a time. If a server reports
multiple simultaneous clients, all but the last reported client multiple simultaneous clients, all but the last reported client
are ignored. are ignored.
The \fBanvil\fR(8) server automatically discards client
request information after it expires. To prevent the
\fBanvil\fR(8) server from discarding client request rate
information too early or too late, a rate limited service
should always register connect/disconnect events even when
it does not explicitly limit them.
.SH "CONFIGURATION PARAMETERS" .SH "CONFIGURATION PARAMETERS"
.na .na
.nf .nf
.ad .ad
.fi .fi
Changes to \fBmain.cf\fR are picked up automatically as \fBanvil\fR(8) On low-traffic mail systems, changes to \fBmain.cf\fR are
processes run for only a limited amount of time. Use the command picked up automatically as \fBanvil\fR(8) processes run for
"\fBpostfix reload\fR" to speed up a change. only a limited amount of time. On other mail systems, use
the command "\fBpostfix reload\fR" to speed up a change.
The text below provides only a parameter summary. See The text below provides only a parameter summary. See
\fBpostconf\fR(5) for more details including examples. \fBpostconf\fR(5) for more details including examples.

View File

@ -399,11 +399,6 @@ Update the \fBlocal\fR(8) delivery agent's idea of the Delivered-To:
address (see prepend_delivered_header) only once, at the start of address (see prepend_delivered_header) only once, at the start of
a delivery attempt; do not update the Delivered-To: address while a delivery attempt; do not update the Delivered-To: address while
expanding aliases or .forward files. expanding aliases or .forward files.
.IP "\fBsticky_owner_alias (yes)\fR"
When expanding a \fBlocal\fR(8) alias that has an owner alias (see
owner-\fIname\fR discussion in \fBaliases\fR(5)), use the owner information
even when the expansion invokes a subordinate alias that has no
owner alias.
.SH "DELIVERY METHOD CONTROLS" .SH "DELIVERY METHOD CONTROLS"
.na .na
.nf .nf

View File

@ -453,6 +453,11 @@ receiving a remote SMTP client request.
The maximal number of lines in the Postfix SMTP server command history The maximal number of lines in the Postfix SMTP server command history
before it is flushed upon receipt of EHLO, RSET, or end of DATA. before it is flushed upon receipt of EHLO, RSET, or end of DATA.
.PP .PP
Available in Postfix version 2.3 and later:
.IP "\fBsmtpd_peername_lookup (yes)\fR"
Attempt to look up the SMTP client hostname, and verify that
the name matches the client IP address.
.PP
The per SMTP client connection count and request rate limits are The per SMTP client connection count and request rate limits are
implemented in co-operation with the \fBanvil\fR(8) service, and implemented in co-operation with the \fBanvil\fR(8) service, and
are available in Postfix version 2.2 and later. are available in Postfix version 2.2 and later.
@ -473,6 +478,11 @@ Postfix actually accepts those recipients.
.IP "\fBsmtpd_client_event_limit_exceptions ($mynetworks)\fR" .IP "\fBsmtpd_client_event_limit_exceptions ($mynetworks)\fR"
Clients that are excluded from connection count, connection rate, Clients that are excluded from connection count, connection rate,
or SMTP request rate restrictions. or SMTP request rate restrictions.
.PP
Available in Postfix version 2.3 and later:
.IP "\fBsmtpd_client_new_tls_session_rate_limit (0)\fR"
The maximal number of new (i.e., uncached) TLS sessions that any
client is allowed to negotiate with this service per time unit.
.SH "TARPIT CONTROLS" .SH "TARPIT CONTROLS"
.na .na
.nf .nf

View File

@ -372,6 +372,7 @@ while (<>) {
s;\bsmtpd_client_connection_rate_limit\b;<a href="postconf.5.html#smtpd_client_connection_rate_limit">$&</a>;g; s;\bsmtpd_client_connection_rate_limit\b;<a href="postconf.5.html#smtpd_client_connection_rate_limit">$&</a>;g;
s;\bsmtpd_client_message_rate_limit\b;<a href="postconf.5.html#smtpd_client_message_rate_limit">$&</a>;g; s;\bsmtpd_client_message_rate_limit\b;<a href="postconf.5.html#smtpd_client_message_rate_limit">$&</a>;g;
s;\bsmtpd_client_recipient_rate_limit\b;<a href="postconf.5.html#smtpd_client_recipient_rate_limit">$&</a>;g; s;\bsmtpd_client_recipient_rate_limit\b;<a href="postconf.5.html#smtpd_client_recipient_rate_limit">$&</a>;g;
s;\bsmtpd_client_new_tls_session_rate_limit\b;<a href="postconf.5.html#smtpd_client_new_tls_session_rate_limit">$&</a>;g;
s;\bsmtpd_client_restrictions\b;<a href="postconf.5.html#smtpd_client_restrictions">$&</a>;g; s;\bsmtpd_client_restrictions\b;<a href="postconf.5.html#smtpd_client_restrictions">$&</a>;g;
s;\bsmtpd_data_restrictions\b;<a href="postconf.5.html#smtpd_data_restrictions">$&</a>;g; s;\bsmtpd_data_restrictions\b;<a href="postconf.5.html#smtpd_data_restrictions">$&</a>;g;
s;\bsmtpd_delay_reject\b;<a href="postconf.5.html#smtpd_delay_reject">$&</a>;g; s;\bsmtpd_delay_reject\b;<a href="postconf.5.html#smtpd_delay_reject">$&</a>;g;
@ -390,6 +391,7 @@ while (<>) {
s;\bsmtpd_noop_commands\b;<a href="postconf.5.html#smtpd_noop_commands">$&</a>;g; s;\bsmtpd_noop_commands\b;<a href="postconf.5.html#smtpd_noop_commands">$&</a>;g;
s;\bsmtpd_null_access_lookup_key\b;<a href="postconf.5.html#smtpd_null_access_lookup_key">$&</a>;g; s;\bsmtpd_null_access_lookup_key\b;<a href="postconf.5.html#smtpd_null_access_lookup_key">$&</a>;g;
s;\bsmtpd_recipient_overshoot_limit\b;<a href="postconf.5.html#smtpd_recipient_overshoot_limit">$&</a>;g; s;\bsmtpd_recipient_overshoot_limit\b;<a href="postconf.5.html#smtpd_recipient_overshoot_limit">$&</a>;g;
s;\bsmtpd_peername_lookup\b;<a href="postconf.5.html#smtpd_peername_lookup">$&</a>;g;
s;\bsmtpd_policy_service_max_idle\b;<a href="postconf.5.html#smtpd_policy_service_max_idle">$&</a>;g; s;\bsmtpd_policy_service_max_idle\b;<a href="postconf.5.html#smtpd_policy_service_max_idle">$&</a>;g;
s;\bsmtpd_policy_service_max_ttl\b;<a href="postconf.5.html#smtpd_policy_service_max_ttl">$&</a>;g; s;\bsmtpd_policy_service_max_ttl\b;<a href="postconf.5.html#smtpd_policy_service_max_ttl">$&</a>;g;
s;\bsmtpd_policy_service_timeout\b;<a href="postconf.5.html#smtpd_policy_service_timeout">$&</a>;g; s;\bsmtpd_policy_service_timeout\b;<a href="postconf.5.html#smtpd_policy_service_timeout">$&</a>;g;
@ -502,7 +504,6 @@ while (<>) {
s;\btls_ran[-</Bb>]*\n* *[<Bb>]*dom_source\b;<a href="postconf.5.html#tls_random_source">$&</a>;g; s;\btls_ran[-</Bb>]*\n* *[<Bb>]*dom_source\b;<a href="postconf.5.html#tls_random_source">$&</a>;g;
s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g; s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
s;\bsticky_owner_alias\b;<a href="postconf.5.html#sticky_owner_alias">$&</a>;g;
# Undo hyperlinks of manual pages with the same name as parameters. # Undo hyperlinks of manual pages with the same name as parameters.

View File

@ -36,7 +36,8 @@ the Postfix source code, in the directory examples/smtpd-policy.
to Postfix. It's much easier to develop a new feature in few lines to Postfix. It's much easier to develop a new feature in few lines
of Perl, than trying to do the same in C code. The difference in of Perl, than trying to do the same in C code. The difference in
performance will be unnoticeable except in the most demanding performance will be unnoticeable except in the most demanding
environments. </p> environments. On active systems a policy daemon process is used
multiple times, for up to 100 incoming SMTP connections. </p>
<p> This document covers the following topics: </p> <p> This document covers the following topics: </p>

View File

@ -4399,6 +4399,43 @@ Example:
smtpd_client_recipient_rate_limit = 1000 smtpd_client_recipient_rate_limit = 1000
</pre> </pre>
%PARAM smtpd_client_new_tls_session_rate_limit 0
<p>
The maximal number of new (i.e., uncached) TLS sessions that a
remote SMTP client is allowed to negotiate with this service per
time unit. The time unit is specified with the anvil_rate_time_unit
configuration parameter.
</p>
<p>
By default, a remote SMTP client can negotiate as many new TLS
sessions per time unit as Postfix can accept.
</p>
<p>
To disable this feature, specify a limit of 0. Otherwise, specify
a limit that is at least the per-client concurrent session limit,
or else legitimate client sessions may be rejected.
</p>
<p>
WARNING: The purpose of this feature is to limit abuse. It must
not be used to regulate legitimate mail traffic.
</p>
<p>
This feature is available in Postfix 2.3 and later.
</p>
<p>
Example:
</p>
<pre>
smtpd_client_new_tls_session_rate_limit = 100
</pre>
%PARAM smtpd_client_restrictions %PARAM smtpd_client_restrictions
<p> <p>
@ -8542,18 +8579,6 @@ message_strip_characters = \0
<p> This feature is available in Postfix 2.3 and later. </p> <p> This feature is available in Postfix 2.3 and later. </p>
%PARAM sticky_owner_alias yes
<p> When expanding a local(8) alias that has an owner alias (see
owner-<i>name</i> discussion in aliases(5)), use the owner information
even when the expansion invokes a subordinate alias that has no
owner alias. </p>
<p> This feature is available in Postfix 2.3 and later. With older
Postfix releases, the behavior is as if this parameter is set to
"no". The old setting provides poorer error reporting with nested
aliases that only have an owner alias at the top level. </p>
%PARAM frozen_delivered_to yes %PARAM frozen_delivered_to yes
<p> Update the local(8) delivery agent's idea of the Delivered-To: <p> Update the local(8) delivery agent's idea of the Delivered-To:
@ -8567,3 +8592,11 @@ Postfix releases, the behavior is as if this parameter is set to
or .forward files. When an alias or .forward file changes the or .forward files. When an alias or .forward file changes the
Delivered-To: address, it ties up one queue file and one cleanup Delivered-To: address, it ties up one queue file and one cleanup
process instance while mail is being forwarded. </p> process instance while mail is being forwarded. </p>
%PARAM smtpd_peername_lookup yes
<p> Attempt to look up the SMTP client hostname, and verify that
the name matches the client IP address. A client name is set to
"unknown" when it cannot be looked up or verified, or when name
lookup is disabled. Turning off name lookup reduces delays due to
DNS lookup and increases the maximal inbound delivery rate. </p>

View File

@ -6,21 +6,23 @@
/* SYNOPSIS /* SYNOPSIS
/* \fBanvil\fR [generic Postfix daemon options] /* \fBanvil\fR [generic Postfix daemon options]
/* DESCRIPTION /* DESCRIPTION
/* The Postfix \fBanvil\fR(8) server maintains short-term statistics /* The Postfix \fBanvil\fR(8) server maintains statistics about
/* to defend against clients that hammer a server with either too /* client connection counts or client request rates. This
/* many simultaneous sessions, or with too many successive requests /* information can be used to defend against clients that
/* within a configurable time interval. /* hammer a server with either too many simultaneous sessions,
/* This server is designed to run under control by the Postfix /* or with too many successive requests within a configurable
/* \fBmaster\fR(8) server. /* time interval. This server is designed to run under control
/* by the Postfix \fBmaster\fR(8) server.
/* /*
/* The \fBanvil\fR(8) server maintains no persistent database. Standard /* In the following text, \fBident\fR specifies a (service,
/* library utilities do not meet Postfix performance and robustness /* client) combination. The exact syntax of that information
/* requirements. /* is application-dependent; the \fBanvil\fR(8) server does
/* CONNECTION COUNT/RATE LIMITING /* not care.
/* CONNECTION COUNT/RATE CONTROL
/* .ad /* .ad
/* .fi /* .fi
/* When a remote client connects, a connection count (or rate) limited /* To register a new connection send the following request to
/* server should send the following request to the \fBanvil\fR(8) server: /* the \fBanvil\fR(8) server:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBrequest=connect\fR /* \fBrequest=connect\fR
@ -28,11 +30,10 @@
/* \fBident=\fIstring\fR /* \fBident=\fIstring\fR
/* .in /* .in
/* .PP /* .PP
/* This registers a new connection for the (service, client) /* The \fBanvil\fR(8) server answers with the number of
/* combination specified with \fBident\fR. The \fBanvil\fR(8) server /* simultaneous connections and the number of connections per
/* answers with the number of simultaneous connections and the /* unit time for the (service, client) combination specified
/* number of connections per unit time for that (service, client) /* with \fBident\fR:
/* combination:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBstatus=0\fR /* \fBstatus=0\fR
@ -42,13 +43,8 @@
/* \fBrate=\fInumber\fR /* \fBrate=\fInumber\fR
/* .in /* .in
/* .PP /* .PP
/* The \fBrate\fR is computed as the number of connections /* To register a disconnect event send the following request
/* that were registered in the current "time unit" interval. /* to the \fBanvil\fR(8) server:
/* It is left up to the server to decide if the remote client
/* exceeds the connection count (or rate) limit.
/* .PP
/* When a remote client disconnects, a connection count (or rate) limited
/* server should send the following request to the \fBanvil\fR(8) server:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBrequest=disconnect\fR /* \fBrequest=disconnect\fR
@ -56,17 +52,14 @@
/* \fBident=\fIstring\fR /* \fBident=\fIstring\fR
/* .in /* .in
/* .PP /* .PP
/* This registers a disconnect event for the (service, client) /* The \fBanvil\fR(8) server replies with:
/* combination specified with \fBident\fR. The \fBanvil\fR(8)
/* server replies with:
/* .PP /* .PP
/* .ti +4 /* .ti +4
/* \fBstatus=0\fR /* \fBstatus=0\fR
/* MESSAGE RATE LIMITING /* MESSAGE RATE CONTROL
/* .ad /* .ad
/* .fi /* .fi
/* When a remote client sends a message delivery request, a /* To register a message delivery request send the following
/* message rate limited server should send the following
/* request to the \fBanvil\fR(8) server: /* request to the \fBanvil\fR(8) server:
/* .PP /* .PP
/* .in +4 /* .in +4
@ -75,26 +68,20 @@
/* \fBident=\fIstring\fR /* \fBident=\fIstring\fR
/* .in /* .in
/* .PP /* .PP
/* This registers a message delivery request for the (service, client) /* The \fBanvil\fR(8) server answers with the number of message
/* combination specified with \fBident\fR. The \fBanvil\fR(8) server /* delivery requests per unit time for the (service, client)
/* answers with the number of message delivery requests per unit time /* combination specified with \fBident\fR:
/* for that (service, client) combination:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBstatus=0\fR /* \fBstatus=0\fR
/* .br /* .br
/* \fBrate=\fInumber\fR /* \fBrate=\fInumber\fR
/* .in /* .in
/* .PP /* RECIPIENT RATE CONTROL
/* In order to prevent the \fBanvil\fR(8) server from discarding client
/* request rates too early or too late, a message rate limited
/* service should also register connect/disconnect events.
/* RECIPIENT RATE LIMITING
/* .ad /* .ad
/* .fi /* .fi
/* When a remote client sends a recipient address, a recipient /* To register a recipient request send the following request
/* rate limited server should send the following request to /* to the \fBanvil\fR(8) server:
/* the \fBanvil\fR(8) server:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBrequest=recipient\fR /* \fBrequest=recipient\fR
@ -102,10 +89,33 @@
/* \fBident=\fIstring\fR /* \fBident=\fIstring\fR
/* .in /* .in
/* .PP /* .PP
/* This registers a recipient request for the (service, client) /* The \fBanvil\fR(8) server answers with the number of recipient
/* combination specified with \fBident\fR. The \fBanvil\fR(8) server /* addresses per unit time for the (service, client) combination
/* answers with the number of recipient addresses per unit time /* specified with \fBident\fR:
/* for that (service, client) combination: /* .PP
/* .in +4
/* \fBstatus=0\fR
/* .br
/* \fBrate=\fInumber\fR
/* .in
/* TLS SESSION NEGOTIATION RATE CONTROL
/* .ad
/* .fi
/* The features described in this section are available with
/* Postfix 2.3 and later.
/*
/* To register a request for a new (i.e. not cached) TLS session
/* send the following request to the \fBanvil\fR(8) server:
/* .PP
/* .in +4
/* \fBrequest=newtls\fR
/* .br
/* \fBident=\fIstring\fR
/* .in
/* .PP
/* The \fBanvil\fR(8) server answers with the number of new
/* TLS session requests per unit time for the (service, client)
/* combination specified with \fBident\fR:
/* .PP /* .PP
/* .in +4 /* .in +4
/* \fBstatus=0\fR /* \fBstatus=0\fR
@ -113,21 +123,39 @@
/* \fBrate=\fInumber\fR /* \fBrate=\fInumber\fR
/* .in /* .in
/* .PP /* .PP
/* In order to prevent the \fBanvil\fR(8) server from discarding client /* To retrieve new TLS session request rate information without
/* request rates too early or too late, a recipient rate limited /* updating the counter information, use:
/* service should also register connect/disconnect events. /* .PP
/* .in +4
/* \fBrequest=newtls_report\fR
/* .br
/* \fBident=\fIstring\fR
/* .in
/* .PP
/* The \fBanvil\fR(8) server answers with the number of new
/* TLS session requests per unit time for the (service, client)
/* combination specified with \fBident\fR.
/* .PP
/* .in +4
/* \fBstatus=0\fR
/* .br
/* \fBrate=\fInumber\fR
/* .in
/* SECURITY /* SECURITY
/* .ad /* .ad
/* .fi /* .fi
/* The \fBanvil\fR(8) server does not talk to the network or to local /* The \fBanvil\fR(8) server does not talk to the network or to local
/* users, and can run chrooted at fixed low privilege. /* users, and can run chrooted at fixed low privilege.
/* /*
/* The \fBanvil\fR(8) server maintains an in-memory table with information /* The \fBanvil\fR(8) server maintains an in-memory table with
/* about recent clients of a connection count (or rate) limited service. /* information about recent clients requests. No persistent
/* Although state is kept only temporarily, this may require a lot of /* state is kept because standard system library routines are
/* memory on systems that handle connections from many remote clients. /* not sufficiently robust for update-intensive applications.
/* To reduce memory usage, reduce the time unit over which state /*
/* is kept. /* Although the in-memory state is kept only temporarily, this
/* may require a lot of memory on systems that handle connections
/* from many remote clients. To reduce memory usage, reduce
/* the time unit over which state is kept.
/* DIAGNOSTICS /* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8). /* Problems and transactions are logged to \fBsyslogd\fR(8).
/* /*
@ -147,12 +175,20 @@
/* can have only one remote client at a time. If a server reports /* can have only one remote client at a time. If a server reports
/* multiple simultaneous clients, all but the last reported client /* multiple simultaneous clients, all but the last reported client
/* are ignored. /* are ignored.
/*
/* The \fBanvil\fR(8) server automatically discards client
/* request information after it expires. To prevent the
/* \fBanvil\fR(8) server from discarding client request rate
/* information too early or too late, a rate limited service
/* should always register connect/disconnect events even when
/* it does not explicitly limit them.
/* CONFIGURATION PARAMETERS /* CONFIGURATION PARAMETERS
/* .ad /* .ad
/* .fi /* .fi
/* Changes to \fBmain.cf\fR are picked up automatically as \fBanvil\fR(8) /* On low-traffic mail systems, changes to \fBmain.cf\fR are
/* processes run for only a limited amount of time. Use the command /* picked up automatically as \fBanvil\fR(8) processes run for
/* "\fBpostfix reload\fR" to speed up a change. /* only a limited amount of time. On other mail systems, use
/* the command "\fBpostfix reload\fR" to speed up a change.
/* /*
/* The text below provides only a parameter summary. See /* The text below provides only a parameter summary. See
/* \fBpostconf\fR(5) for more details including examples. /* \fBpostconf\fR(5) for more details including examples.
@ -252,28 +288,53 @@ static HTABLE *anvil_remote_map; /* indexed by service+ remote client */
* Absent a real-time query interface, these are logged at process exit time * Absent a real-time query interface, these are logged at process exit time
* and at regular intervals. * and at regular intervals.
*/ */
static int max_count; typedef struct {
static char *max_count_user; int value; /* peak value */
static time_t max_count_time; char *ident; /* lookup key */
time_t when; /* time of peak value */
} ANVIL_MAX;
static int max_rate; static ANVIL_MAX max_conn_count; /* peak connection count */
static char *max_rate_user; static ANVIL_MAX max_conn_rate; /* peak connection rate */
static time_t max_rate_time; static ANVIL_MAX max_mail_rate; /* peak message rate */
static ANVIL_MAX max_rcpt_rate; /* peak recipient rate */
static ANVIL_MAX max_ntls_rate; /* peak new TLS session rate */
static int max_mail; static int max_cache_size; /* peak cache size */
static char *max_mail_user; static time_t max_cache_time; /* time of peak size */
static time_t max_mail_time;
static int max_rcpt; /* Update/report peak usage. */
static char *max_rcpt_user;
static time_t max_rcpt_time;
static int max_newtls; #define ANVIL_MAX_UPDATE(_max, _value, _ident) \
static char *max_newtls_user; do { \
static time_t max_newtls_time; _max.value = _value; \
if (_max.ident == 0) { \
_max.ident = mystrdup(_ident); \
} else if (!STREQ(_max.ident, _ident)) { \
myfree(_max.ident); \
_max.ident = mystrdup(_ident); \
} \
_max.when = event_time(); \
} while (0)
static int max_cache; #define ANVIL_MAX_RATE_REPORT(_max, _name) \
static time_t max_cache_time; do { \
if (_max.value > 0) { \
msg_info("statistics: max " _name " rate %d/%ds for (%s) at %.15s", \
_max.value, var_anvil_time_unit, \
_max.ident, ctime(&_max.when) + 4); \
_max.value = 0; \
} \
} while (0);
#define ANVIL_MAX_COUNT_REPORT(_max, _name) \
do { \
if (_max.value > 0) { \
msg_info("statistics: max " _name " count %d for (%s) at %.15s", \
_max.value, _max.ident, ctime(&_max.when) + 4); \
_max.value = 0; \
} \
} while (0);
/* /*
* Remote connection state, one instance for each (service, client) pair. * Remote connection state, one instance for each (service, client) pair.
@ -284,7 +345,7 @@ typedef struct {
int rate; /* connection rate */ int rate; /* connection rate */
int mail; /* message rate */ int mail; /* message rate */
int rcpt; /* recipient rate */ int rcpt; /* recipient rate */
int newtls; /* newtls rate */ int ntls; /* new TLS session rate */
time_t start; /* time of first rate sample */ time_t start; /* time of first rate sample */
} ANVIL_REMOTE; } ANVIL_REMOTE;
@ -296,12 +357,6 @@ typedef struct {
ANVIL_REMOTE *anvil_remote; /* XXX should be list */ ANVIL_REMOTE *anvil_remote; /* XXX should be list */
} ANVIL_LOCAL; } ANVIL_LOCAL;
/*
* Silly little macros.
*/
#define STR(x) vstring_str(x)
#define STREQ(x,y) (strcmp((x), (y)) == 0)
/* /*
* The following operations are implemented as macros with recognizable * The following operations are implemented as macros with recognizable
* names so that we don't lose sight of what the code is trying to do. * names so that we don't lose sight of what the code is trying to do.
@ -312,14 +367,14 @@ typedef struct {
/* Create new (service, client) state. */ /* Create new (service, client) state. */
#define ANVIL_REMOTE_FIRST(remote, id) \ #define ANVIL_REMOTE_FIRST_CONN(remote, id) \
do { \ do { \
(remote)->ident = mystrdup(id); \ (remote)->ident = mystrdup(id); \
(remote)->count = 1; \ (remote)->count = 1; \
(remote)->rate = 1; \ (remote)->rate = 1; \
(remote)->mail = 0; \ (remote)->mail = 0; \
(remote)->rcpt = 0; \ (remote)->rcpt = 0; \
(remote)->newtls = 0; \ (remote)->ntls = 0; \
(remote)->start = event_time(); \ (remote)->start = event_time(); \
} while(0) } while(0)
@ -331,66 +386,41 @@ typedef struct {
myfree((char *) (remote)); \ myfree((char *) (remote)); \
} while(0) } while(0)
/* Reset event rate counters and start of data collection interval. */
#define ANVIL_REMOTE_RSET_RATE(remote, _start) \
do { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = _start; \
} while(0)
/* Add connection to (service, client) state. */ /* Add connection to (service, client) state. */
#define ANVIL_REMOTE_NEXT(remote) \ #define ANVIL_REMOTE_INCR_RATE(remote, _what) \
do { \ do { \
time_t _now = event_time(); \ time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) { \ if ((remote)->start + var_anvil_time_unit < _now) \
(remote)->rate = 1; \ ANVIL_REMOTE_RSET_RATE((remote), _now); \
(remote)->mail = 0; \ if ((remote)->_what < INT_MAX) \
(remote)->rcpt = 0; \ (remote)->_what += 1; \
(remote)->newtls = 0; \ } while(0)
(remote)->start = _now; \
} else if ((remote)->rate < INT_MAX) { \ #define ANVIL_REMOTE_NEXT_CONN(remote) \
(remote)->rate += 1; \ do { \
} \ ANVIL_REMOTE_INCR_RATE((remote), rate); \
if ((remote)->count == 0) \ if ((remote)->count == 0) \
event_cancel_timer(anvil_remote_expire, (char *) remote); \ event_cancel_timer(anvil_remote_expire, (char *) remote); \
(remote)->count++; \ (remote)->count++; \
} while(0) } while(0)
#define ANVIL_ADD_MAIL(remote) \ #define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) { \
(remote)->rate = 0; \
(remote)->mail = 1; \
(remote)->rcpt = 0; \
(remote)->newtls = 0; \
(remote)->start = _now; \
} else if ((remote)->mail < INT_MAX) { \
(remote)->mail += 1; \
} \
} while(0)
#define ANVIL_ADD_RCPT(remote) \ #define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 1; \
(remote)->newtls = 0; \
(remote)->start = _now; \
} else if ((remote)->rcpt < INT_MAX) { \
(remote)->rcpt += 1; \
} \
} while(0)
#define ANVIL_ADD_STARTTLS(remote) \ #define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->newtls = 1; \
(remote)->start = _now; \
} else if ((remote)->newtls < INT_MAX) { \
(remote)->newtls += 1; \
} \
} while(0)
/* Drop connection from (service, client) state. */ /* Drop connection from (service, client) state. */
@ -443,6 +473,20 @@ typedef struct {
anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \ anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
} while (0) } while (0)
/*
* Lookup table to map request names to action routines.
*/
typedef struct {
const char *name;
void (*action) (VSTREAM *, const char *);
} ANVIL_REQ_TABLE;
/*
* Silly little macros.
*/
#define STR(x) vstring_str(x)
#define STREQ(x,y) (strcmp((x), (y)) == 0)
/* anvil_remote_expire - purge expired connection state */ /* anvil_remote_expire - purge expired connection state */
static void anvil_remote_expire(int unused_event, char *context) static void anvil_remote_expire(int unused_event, char *context)
@ -472,8 +516,6 @@ static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident)
{ {
ANVIL_REMOTE *anvil_remote; ANVIL_REMOTE *anvil_remote;
char *myname = "anvil_remote_lookup"; char *myname = "anvil_remote_lookup";
HTABLE_INFO **ht_info;
HTABLE_INFO **ht;
if (msg_verbose) if (msg_verbose)
msg_info("%s fd=%d stream=0x%lx ident=%s", msg_info("%s fd=%d stream=0x%lx ident=%s",
@ -483,39 +525,31 @@ static void anvil_remote_lookup(VSTREAM *client_stream, const char *ident)
/* /*
* Look up remote client information. * Look up remote client information.
*/ */
if (STREQ(ident, "*")) { if ((anvil_remote =
attr_print_plain(client_stream, ATTR_FLAG_MORE, (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_END);
ht_info = htable_list(anvil_remote_map);
for (ht = ht_info; *ht; ht++) {
anvil_remote = (ANVIL_REMOTE *) ht[0]->value;
attr_print_plain(client_stream, ATTR_FLAG_MORE,
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ht[0]->key,
ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, anvil_remote->count,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rate,
ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, anvil_remote->mail,
ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, anvil_remote->rcpt,
ATTR_TYPE_END);
}
attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_END);
myfree((char *) ht_info);
} else if ((anvil_remote =
(ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, 0, ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, 0,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, 0, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, 0,
ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, 0, ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, 0,
ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, 0, ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, 0,
ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, 0,
ATTR_TYPE_END); ATTR_TYPE_END);
} else { } else {
/*
* Do not report stale information.
*/
if (anvil_remote->start != 0
&& anvil_remote->start + var_anvil_time_unit < event_time())
ANVIL_REMOTE_RSET_RATE(anvil_remote, 0);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, anvil_remote->count, ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, anvil_remote->count,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rate, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rate,
ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, anvil_remote->mail, ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, anvil_remote->mail,
ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, anvil_remote->rcpt, ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, anvil_remote->rcpt,
ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, anvil_remote->ntls,
ATTR_TYPE_END); ATTR_TYPE_END);
} }
} }
@ -542,14 +576,14 @@ static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char
if ((anvil_remote = if ((anvil_remote =
(ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) { (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
anvil_remote = (ANVIL_REMOTE *) mymalloc(sizeof(*anvil_remote)); anvil_remote = (ANVIL_REMOTE *) mymalloc(sizeof(*anvil_remote));
ANVIL_REMOTE_FIRST(anvil_remote, ident); ANVIL_REMOTE_FIRST_CONN(anvil_remote, ident);
htable_enter(anvil_remote_map, ident, (char *) anvil_remote); htable_enter(anvil_remote_map, ident, (char *) anvil_remote);
if (max_cache < anvil_remote_map->used) { if (max_cache_size < anvil_remote_map->used) {
max_cache = anvil_remote_map->used; max_cache_size = anvil_remote_map->used;
max_cache_time = event_time(); max_cache_time = event_time();
} }
} else { } else {
ANVIL_REMOTE_NEXT(anvil_remote); ANVIL_REMOTE_NEXT_CONN(anvil_remote);
} }
/* /*
@ -592,28 +626,12 @@ static void anvil_remote_connect(VSTREAM *client_stream, const char *ident)
ATTR_TYPE_END); ATTR_TYPE_END);
/* /*
* Update local statistics. * Update peak statistics.
*/ */
if (anvil_remote->rate > max_rate) { if (anvil_remote->rate > max_conn_rate.value)
max_rate = anvil_remote->rate; ANVIL_MAX_UPDATE(max_conn_rate, anvil_remote->rate, anvil_remote->ident);
if (max_rate_user == 0) { if (anvil_remote->count > max_conn_count.value)
max_rate_user = mystrdup(anvil_remote->ident); ANVIL_MAX_UPDATE(max_conn_count, anvil_remote->count, anvil_remote->ident);
} else if (!STREQ(max_rate_user, anvil_remote->ident)) {
myfree(max_rate_user);
max_rate_user = mystrdup(anvil_remote->ident);
}
max_rate_time = event_time();
}
if (anvil_remote->count > max_count) {
max_count = anvil_remote->count;
if (max_count_user == 0) {
max_count_user = mystrdup(anvil_remote->ident);
} else if (!STREQ(max_count_user, anvil_remote->ident)) {
myfree(max_count_user);
max_count_user = mystrdup(anvil_remote->ident);
}
max_count_time = event_time();
}
} }
/* anvil_remote_mail - register message delivery request */ /* anvil_remote_mail - register message delivery request */
@ -632,25 +650,17 @@ static void anvil_remote_mail(VSTREAM *client_stream, const char *ident)
/* /*
* Update message delivery request rate and respond to local client. * Update message delivery request rate and respond to local client.
*/ */
ANVIL_ADD_MAIL(anvil_remote); ANVIL_REMOTE_INCR_MAIL(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->mail, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->mail,
ATTR_TYPE_END); ATTR_TYPE_END);
/* /*
* Update local statistics. * Update peak statistics.
*/ */
if (anvil_remote->mail > max_mail) { if (anvil_remote->mail > max_mail_rate.value)
max_mail = anvil_remote->mail; ANVIL_MAX_UPDATE(max_mail_rate, anvil_remote->mail, anvil_remote->ident);
if (max_mail_user == 0) {
max_mail_user = mystrdup(anvil_remote->ident);
} else if (!STREQ(max_mail_user, anvil_remote->ident)) {
myfree(max_mail_user);
max_mail_user = mystrdup(anvil_remote->ident);
}
max_mail_time = event_time();
}
} }
/* anvil_remote_rcpt - register recipient address event */ /* anvil_remote_rcpt - register recipient address event */
@ -669,25 +679,17 @@ static void anvil_remote_rcpt(VSTREAM *client_stream, const char *ident)
/* /*
* Update recipient address rate and respond to local client. * Update recipient address rate and respond to local client.
*/ */
ANVIL_ADD_RCPT(anvil_remote); ANVIL_REMOTE_INCR_RCPT(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rcpt, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rcpt,
ATTR_TYPE_END); ATTR_TYPE_END);
/* /*
* Update local statistics. * Update peak statistics.
*/ */
if (anvil_remote->rcpt > max_rcpt) { if (anvil_remote->rcpt > max_rcpt_rate.value)
max_rcpt = anvil_remote->rcpt; ANVIL_MAX_UPDATE(max_rcpt_rate, anvil_remote->rcpt, anvil_remote->ident);
if (max_rcpt_user == 0) {
max_rcpt_user = mystrdup(anvil_remote->ident);
} else if (!STREQ(max_rcpt_user, anvil_remote->ident)) {
myfree(max_rcpt_user);
max_rcpt_user = mystrdup(anvil_remote->ident);
}
max_rcpt_time = event_time();
}
} }
/* anvil_remote_newtls - register newtls event */ /* anvil_remote_newtls - register newtls event */
@ -706,25 +708,51 @@ static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident)
/* /*
* Update newtls rate and respond to local client. * Update newtls rate and respond to local client.
*/ */
ANVIL_ADD_STARTTLS(anvil_remote); ANVIL_REMOTE_INCR_NTLS(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->newtls, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->ntls,
ATTR_TYPE_END); ATTR_TYPE_END);
/* /*
* Update local statistics. * Update peak statistics.
*/ */
if (anvil_remote->newtls > max_newtls) { if (anvil_remote->ntls > max_ntls_rate.value)
max_newtls = anvil_remote->newtls; ANVIL_MAX_UPDATE(max_ntls_rate, anvil_remote->ntls, anvil_remote->ident);
if (max_newtls_user == 0) { }
max_newtls_user = mystrdup(anvil_remote->ident);
} else if (!STREQ(max_newtls_user, anvil_remote->ident)) { /* anvil_remote_newtls_stat - report newtls stats */
myfree(max_newtls_user);
max_newtls_user = mystrdup(anvil_remote->ident); static void anvil_remote_newtls_stat(VSTREAM *client_stream, const char *ident)
} {
max_newtls_time = event_time(); ANVIL_REMOTE *anvil_remote;
int rate;
/*
* Be prepared for "postfix reload" after "connect".
*/
if ((anvil_remote =
(ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
rate = 0;
} }
/*
* Do not report stale information.
*/
else {
if (anvil_remote->start != 0
&& anvil_remote->start + var_anvil_time_unit < event_time())
ANVIL_REMOTE_RSET_RATE(anvil_remote, 0);
rate = anvil_remote->ntls;
}
/*
* Respond to local client.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate,
ATTR_TYPE_END);
} }
/* anvil_remote_disconnect - report disconnect event */ /* anvil_remote_disconnect - report disconnect event */
@ -796,8 +824,19 @@ static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv) static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv)
{ {
VSTRING *request = vstring_alloc(10); static VSTRING *request;
VSTRING *ident = vstring_alloc(10); static VSTRING *ident;
static ANVIL_REQ_TABLE request_table[] = {
ANVIL_REQ_CONN, anvil_remote_connect,
ANVIL_REQ_MAIL, anvil_remote_mail,
ANVIL_REQ_RCPT, anvil_remote_rcpt,
ANVIL_REQ_NTLS, anvil_remote_newtls,
ANVIL_REQ_DISC, anvil_remote_disconnect,
ANVIL_REQ_NTLS_STAT, anvil_remote_newtls_stat,
ANVIL_REQ_LOOKUP, anvil_remote_lookup,
0, 0,
};
ANVIL_REQ_TABLE *rp;
/* /*
* Sanity check. This service takes no command-line arguments. * Sanity check. This service takes no command-line arguments.
@ -805,6 +844,14 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
if (argv[0]) if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]); msg_fatal("unexpected command-line argument: %s", argv[0]);
/*
* Initialize.
*/
if (request == 0) {
request = vstring_alloc(10);
ident = vstring_alloc(10);
}
/* /*
* This routine runs whenever a client connects to the socket dedicated * This routine runs whenever a client connects to the socket dedicated
* to the client connection rate management service. All * to the client connection rate management service. All
@ -818,23 +865,18 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
ATTR_TYPE_STR, ANVIL_ATTR_REQ, request, ATTR_TYPE_STR, ANVIL_ATTR_REQ, request,
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END) == 2) { ATTR_TYPE_END) == 2) {
if (STREQ(STR(request), ANVIL_REQ_CONN)) { for (rp = request_table; /* see below */ ; rp++) {
anvil_remote_connect(client_stream, STR(ident)); if (rp->name == 0) {
} else if (STREQ(STR(request), ANVIL_REQ_MAIL)) { msg_warn("unrecognized request: \"%s\", ignored", STR(request));
anvil_remote_mail(client_stream, STR(ident)); attr_print_plain(client_stream, ATTR_FLAG_NONE,
} else if (STREQ(STR(request), ANVIL_REQ_RCPT)) {
anvil_remote_rcpt(client_stream, STR(ident));
} else if (STREQ(STR(request), ANVIL_REQ_NEWTLS)) {
anvil_remote_newtls(client_stream, STR(ident));
} else if (STREQ(STR(request), ANVIL_REQ_DISC)) {
anvil_remote_disconnect(client_stream, STR(ident));
} else if (STREQ(STR(request), ANVIL_REQ_LOOKUP)) {
anvil_remote_lookup(client_stream, STR(ident));
} else {
msg_warn("unrecognized request: \"%s\", ignored", STR(request));
attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL,
ATTR_TYPE_END); ATTR_TYPE_END);
break;
}
if (STREQ(rp->name, STR(request))) {
rp->action(client_stream, STR(ident));
break;
}
} }
vstream_fflush(client_stream); vstream_fflush(client_stream);
} else { } else {
@ -843,8 +885,6 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
} }
if (msg_verbose) if (msg_verbose)
msg_info("--- end request ---"); msg_info("--- end request ---");
vstring_free(ident);
vstring_free(request);
} }
/* post_jail_init - post-jail initialization */ /* post_jail_init - post-jail initialization */
@ -874,39 +914,16 @@ static void post_jail_init(char *unused_name, char **unused_argv)
static void anvil_status_dump(char *unused_name, char **unused_argv) static void anvil_status_dump(char *unused_name, char **unused_argv)
{ {
if (max_rate > 0) { ANVIL_MAX_RATE_REPORT(max_conn_rate, "connection");
msg_info("statistics: max connection rate %d/%ds for (%s) at %.15s", ANVIL_MAX_COUNT_REPORT(max_conn_count, "connection");
max_rate, var_anvil_time_unit, ANVIL_MAX_RATE_REPORT(max_mail_rate, "message");
max_rate_user, ctime(&max_rate_time) + 4); ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
max_rate = 0; ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
}
if (max_count > 0) { if (max_cache_size > 0) {
msg_info("statistics: max connection count %d for (%s) at %.15s",
max_count, max_count_user, ctime(&max_count_time) + 4);
max_count = 0;
}
if (max_mail > 0) {
msg_info("statistics: max message rate %d/%ds for (%s) at %.15s",
max_mail, var_anvil_time_unit,
max_mail_user, ctime(&max_mail_time) + 4);
max_mail = 0;
}
if (max_rcpt > 0) {
msg_info("statistics: max recipient rate %d/%ds for (%s) at %.15s",
max_rcpt, var_anvil_time_unit,
max_rcpt_user, ctime(&max_rcpt_time) + 4);
max_rcpt = 0;
}
if (max_newtls > 0) {
msg_info("statistics: max newtls rate %d/%ds for (%s) at %.15s",
max_newtls, var_anvil_time_unit,
max_newtls_user, ctime(&max_newtls_time) + 4);
max_newtls = 0;
}
if (max_cache > 0) {
msg_info("statistics: max cache size %d at %.15s", msg_info("statistics: max cache size %d at %.15s",
max_cache, ctime(&max_cache_time) + 4); max_cache_size, ctime(&max_cache_time) + 4);
max_cache = 0; max_cache_size = 0;
} }
} }

View File

@ -37,6 +37,12 @@
/* const char *addr; /* const char *addr;
/* int *newtls; /* int *newtls;
/* /*
/* int anvil_clnt_newtls_stat(anvil_clnt, service, addr, newtls)
/* ANVIL_CLNT *anvil_clnt;
/* const char *service;
/* const char *addr;
/* int *newtls;
/*
/* int anvil_clnt_disconnect(anvil_clnt, service, addr) /* int anvil_clnt_disconnect(anvil_clnt, service, addr)
/* ANVIL_CLNT *anvil_clnt; /* ANVIL_CLNT *anvil_clnt;
/* const char *service; /* const char *service;
@ -52,29 +58,36 @@
/* int *msgs; /* int *msgs;
/* int *rcpts; /* int *rcpts;
/* DESCRIPTION /* DESCRIPTION
/* anvil_clnt_create() instantiates an anvil service client endpoint. /* anvil_clnt_create() instantiates a local anvil service
/* client endpoint.
/* /*
/* anvil_clnt_connect() informs the anvil server that a /* anvil_clnt_connect() informs the anvil server that a
/* client has connected, and returns the current connection /* remote client has connected, and returns the current
/* count and connection rate for that client. /* connection count and connection rate for that remote client.
/* /*
/* anvil_clnt_mail() registers a MAIL FROM event and returns /* anvil_clnt_mail() registers a MAIL FROM event and
/* the current MAIL FROM rate for the specified client. /* returns the current MAIL FROM rate for the specified remote
/* client.
/* /*
/* anvil_clnt_rcpt() registers a RCPT TO event and returns /* anvil_clnt_rcpt() registers a RCPT TO event and
/* the current RCPT TO rate for the specified client. /* returns the current RCPT TO rate for the specified remote
/* client.
/* /*
/* anvil_clnt_newtls() registers a request to negotiate a new /* anvil_clnt_newtls() registers a remote client request
/* (uncached) TLS session and returns the current request rate /* to negotiate a new (uncached) TLS session and returns the
/* for the specified client. /* current newtls request rate for the specified remote client.
/* /*
/* anvil_clnt_disconnect() informs the anvil server that a /* anvil_clnt_newtls_stat() returns the current newtls request
/* rate for the specified remote client.
/*
/* anvil_clnt_disconnect() informs the anvil server that a remote
/* client has disconnected. /* client has disconnected.
/* /*
/* anvil_clnt_lookup() looks up the current connection /* anvil_clnt_lookup() returns the current count and rate
/* count and connection rate for that client. /* information for the specified client.
/* /*
/* anvil_clnt_free() destroys an anvil service client endpoint. /* anvil_clnt_free() destroys a local anvil service client
/* endpoint.
/* /*
/* Arguments: /* Arguments:
/* .IP anvil_clnt /* .IP anvil_clnt
@ -99,7 +112,7 @@
/* Pointer to storage for the current "new TLS session" rate /* Pointer to storage for the current "new TLS session" rate
/* for this remote client. /* for this remote client.
/* DIAGNOSTICS /* DIAGNOSTICS
/* anvil_clnt_connect() and anvil_clnt_disconnect() return /* The update and status query routines return
/* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise /* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise
/* (either the communication with the server is broken or the /* (either the communication with the server is broken or the
/* server experienced a problem). /* server experienced a problem).
@ -168,7 +181,7 @@ void anvil_clnt_free(ANVIL_CLNT *anvil_clnt)
int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *count, int *rate, const char *addr, int *count, int *rate,
int *msgs, int *rcpts) int *msgs, int *rcpts, int *newtls)
{ {
char *ident = ANVIL_IDENT(service, addr); char *ident = ANVIL_IDENT(service, addr);
int status; int status;
@ -184,7 +197,8 @@ int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate, ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate,
ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, msgs, ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, msgs,
ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, rcpts, ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, rcpts,
ATTR_TYPE_END) != 5) ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, newtls,
ATTR_TYPE_END) != 6)
status = ANVIL_STAT_FAIL; status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK) else if (status != ANVIL_STAT_OK)
status = ANVIL_STAT_FAIL; status = ANVIL_STAT_FAIL;
@ -192,7 +206,7 @@ int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service,
return (status); return (status);
} }
/* anvil_clnt_connect - heads-up and policy query */ /* anvil_clnt_connect - heads-up and status query */
int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *count, int *rate) const char *addr, int *count, int *rate)
@ -217,7 +231,7 @@ int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service,
return (status); return (status);
} }
/* anvil_clnt_mail - heads-up and policy query */ /* anvil_clnt_mail - heads-up and status query */
int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *msgs) const char *addr, int *msgs)
@ -241,7 +255,7 @@ int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service,
return (status); return (status);
} }
/* anvil_clnt_rcpt - heads-up and policy query */ /* anvil_clnt_rcpt - heads-up and status query */
int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *rcpts) const char *addr, int *rcpts)
@ -265,17 +279,41 @@ int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service,
return (status); return (status);
} }
/* anvil_clnt_newtls - heads-up and policy query */ /* anvil_clnt_newtls - heads-up and status query */
int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *newtls) const char *addr, int *newtls)
{ {
char *ident = ANVIL_IDENT(service, addr); char *ident = ANVIL_IDENT(service, addr);
int status; int status;
if (attr_clnt_request((ATTR_CLNT *)anvil_clnt, if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
ATTR_FLAG_NONE, /* Query attributes. */ ATTR_FLAG_NONE, /* Query attributes. */
ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_NEWTLS, ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_NTLS,
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
ATTR_TYPE_NUM, ANVIL_ATTR_RATE, newtls,
ATTR_TYPE_END) != 2)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
status = ANVIL_STAT_FAIL;
myfree(ident);
return (status);
}
/* anvil_clnt_newtls_stat - status query */
int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr, int *newtls)
{
char *ident = ANVIL_IDENT(service, addr);
int status;
if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
ATTR_FLAG_NONE, /* Query attributes. */
ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_NTLS_STAT,
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END, ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */ ATTR_FLAG_MISSING, /* Reply attributes. */
@ -291,13 +329,13 @@ int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service,
/* anvil_clnt_disconnect - heads-up only */ /* anvil_clnt_disconnect - heads-up only */
int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service, int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service,
const char *addr) const char *addr)
{ {
char *ident = ANVIL_IDENT(service, addr); char *ident = ANVIL_IDENT(service, addr);
int status; int status;
if (attr_clnt_request((ATTR_CLNT *)anvil_clnt, if (attr_clnt_request((ATTR_CLNT *) anvil_clnt,
ATTR_FLAG_NONE, /* Query attributes. */ ATTR_FLAG_NONE, /* Query attributes. */
ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_DISC, ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_DISC,
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
@ -326,13 +364,17 @@ int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service,
static void usage(void) static void usage(void)
{ {
vstream_printf("usage: %s service addr | %s service addr |" vstream_printf("usage: "
" %s service addr | %s service addr\n", ANVIL_REQ_CONN " service addr | "
ANVIL_REQ_CONN, ANVIL_REQ_DISC, ANVIL_REQ_DISC " service addr | "
ANVIL_REQ_MAIL, ANVIL_REQ_RCPT); ANVIL_REQ_MAIL " service addr | "
ANVIL_REQ_RCPT " service addr | "
ANVIL_REQ_NTLS " service addr | "
ANVIL_REQ_NTLS_STAT " service addr | "
ANVIL_REQ_LOOKUP " service addr\n");
} }
int main(int unused_argc, char **argv) int main(int unused_argc, char **argv)
{ {
VSTRING *inbuf = vstring_alloc(1); VSTRING *inbuf = vstring_alloc(1);
char *bufp; char *bufp;
@ -340,10 +382,11 @@ int main(int unused_argc, char **argv)
ssize_t cmd_len; ssize_t cmd_len;
char *service; char *service;
char *addr; char *addr;
int count; int count;
int rate; int rate;
int msgs; int msgs;
int rcpts; int rcpts;
int newtls;
ANVIL_CLNT *anvil; ANVIL_CLNT *anvil;
msg_vstream_init(argv[0], VSTREAM_ERR); msg_vstream_init(argv[0], VSTREAM_ERR);
@ -384,6 +427,16 @@ int main(int unused_argc, char **argv)
msg_warn("error!"); msg_warn("error!");
else else
vstream_printf("rate=%d\n", rcpts); vstream_printf("rate=%d\n", rcpts);
} else if (strncmp(cmd, ANVIL_REQ_NTLS, cmd_len) == 0) {
if (anvil_clnt_newtls(anvil, service, addr, &newtls) != ANVIL_STAT_OK)
msg_warn("error!");
else
vstream_printf("rate=%d\n", newtls);
} else if (strncmp(cmd, ANVIL_REQ_NTLS_STAT, cmd_len) == 0) {
if (anvil_clnt_newtls_stat(anvil, service, addr, &newtls) != ANVIL_STAT_OK)
msg_warn("error!");
else
vstream_printf("rate=%d\n", newtls);
} else if (strncmp(cmd, ANVIL_REQ_DISC, cmd_len) == 0) { } else if (strncmp(cmd, ANVIL_REQ_DISC, cmd_len) == 0) {
if (anvil_clnt_disconnect(anvil, service, addr) != ANVIL_STAT_OK) if (anvil_clnt_disconnect(anvil, service, addr) != ANVIL_STAT_OK)
msg_warn("error!"); msg_warn("error!");
@ -391,11 +444,11 @@ int main(int unused_argc, char **argv)
vstream_printf("OK\n"); vstream_printf("OK\n");
} else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) { } else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) {
if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, if (anvil_clnt_lookup(anvil, service, addr, &count, &rate,
&msgs, &rcpts) != ANVIL_STAT_OK) &msgs, &rcpts, &newtls) != ANVIL_STAT_OK)
msg_warn("error!"); msg_warn("error!");
else else
vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d\n", vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d\n",
count, rate, msgs, rcpts); count, rate, msgs, rcpts, newtls);
} else { } else {
vstream_printf("bad command: \"%s\"\n", cmd); vstream_printf("bad command: \"%s\"\n", cmd);
usage(); usage();

View File

@ -32,13 +32,15 @@
#define ANVIL_REQ_DISC "disconnect" #define ANVIL_REQ_DISC "disconnect"
#define ANVIL_REQ_MAIL "message" #define ANVIL_REQ_MAIL "message"
#define ANVIL_REQ_RCPT "recipient" #define ANVIL_REQ_RCPT "recipient"
#define ANVIL_REQ_NEWTLS "newtls" #define ANVIL_REQ_NTLS "newtls"
#define ANVIL_REQ_NTLS_STAT "newtls_status"
#define ANVIL_REQ_LOOKUP "lookup" #define ANVIL_REQ_LOOKUP "lookup"
#define ANVIL_ATTR_IDENT "ident" #define ANVIL_ATTR_IDENT "ident"
#define ANVIL_ATTR_COUNT "count" #define ANVIL_ATTR_COUNT "count"
#define ANVIL_ATTR_RATE "rate" #define ANVIL_ATTR_RATE "rate"
#define ANVIL_ATTR_MAIL "mail" #define ANVIL_ATTR_MAIL "mail"
#define ANVIL_ATTR_RCPT "rcpt" #define ANVIL_ATTR_RCPT "rcpt"
#define ANVIL_ATTR_NTLS "newtls"
#define ANVIL_ATTR_STATUS "status" #define ANVIL_ATTR_STATUS "status"
#define ANVIL_STAT_OK 0 #define ANVIL_STAT_OK 0
@ -54,7 +56,8 @@ extern int anvil_clnt_connect(ANVIL_CLNT *, const char *, const char *, int *, i
extern int anvil_clnt_mail(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_mail(ANVIL_CLNT *, const char *, const char *, int *);
extern int anvil_clnt_rcpt(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_rcpt(ANVIL_CLNT *, const char *, const char *, int *);
extern int anvil_clnt_newtls(ANVIL_CLNT *, const char *, const char *, int *); extern int anvil_clnt_newtls(ANVIL_CLNT *, const char *, const char *, int *);
extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *); extern int anvil_clnt_newtls_stat(ANVIL_CLNT *, const char *, const char *, int *);
extern int anvil_clnt_lookup(ANVIL_CLNT *, const char *, const char *, int *, int *, int *, int *, int *);
extern int anvil_clnt_disconnect(ANVIL_CLNT *, const char *, const char *); extern int anvil_clnt_disconnect(ANVIL_CLNT *, const char *, const char *);
extern void anvil_clnt_free(ANVIL_CLNT *); extern void anvil_clnt_free(ANVIL_CLNT *);

View File

@ -355,6 +355,7 @@ static DELIVER_REQUEST *deliver_request_alloc(void)
request->sasl_username = 0; request->sasl_username = 0;
request->sasl_sender = 0; request->sasl_sender = 0;
request->rewrite_context = 0; request->rewrite_context = 0;
request->dsn_envid = 0;
return (request); return (request);
} }

View File

@ -1728,6 +1728,10 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`\
abcdefghijklmnopqrstuvwxyz{|}~" abcdefghijklmnopqrstuvwxyz{|}~"
extern char *var_smtpd_exp_filter; extern char *var_smtpd_exp_filter;
#define VAR_SMTPD_PEERNAME_LOOKUP "smtpd_peername_lookup"
#define DEF_SMTPD_PEERNAME_LOOKUP 1
extern bool var_smtpd_peername_lookup;
/* /*
* Heuristic to reject unknown local recipients at the SMTP port. * Heuristic to reject unknown local recipients at the SMTP port.
*/ */
@ -2301,6 +2305,10 @@ extern int var_smtpd_cmail_limit;
#define DEF_SMTPD_CRCPT_LIMIT 0 #define DEF_SMTPD_CRCPT_LIMIT 0
extern int var_smtpd_crcpt_limit; extern int var_smtpd_crcpt_limit;
#define VAR_SMTPD_CNTLS_LIMIT "smtpd_client_new_tls_session_rate_limit"
#define DEF_SMTPD_CNTLS_LIMIT 0
extern int var_smtpd_cntls_limit;
#define VAR_SMTPD_HOGGERS "smtpd_client_event_limit_exceptions" #define VAR_SMTPD_HOGGERS "smtpd_client_event_limit_exceptions"
#define DEF_SMTPD_HOGGERS "${smtpd_client_connection_limit_exceptions:$" VAR_MYNETWORKS "}" #define DEF_SMTPD_HOGGERS "${smtpd_client_connection_limit_exceptions:$" VAR_MYNETWORKS "}"
extern char *var_smtpd_hoggers; extern char *var_smtpd_hoggers;
@ -2380,10 +2388,6 @@ extern char *var_msg_strip_chars;
#define DEF_FROZEN_DELIVERED 1 #define DEF_FROZEN_DELIVERED 1
extern bool var_frozen_delivered; extern bool var_frozen_delivered;
#define VAR_STICKY_OWNER_ALIAS "sticky_owner_alias"
#define DEF_STICKY_OWNER_ALIAS 1
extern bool var_sticky_owner_alias;
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi

View File

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

View File

@ -95,6 +95,9 @@
/* An I/O error happened, or the peer has disconnected unexpectedly. /* An I/O error happened, or the peer has disconnected unexpectedly.
/* .IP SMTP_ERR_TIME /* .IP SMTP_ERR_TIME
/* The time limit specified to smtp_timeout_setup() was exceeded. /* The time limit specified to smtp_timeout_setup() was exceeded.
/* .IP SMTP_ERR_PROTO
/* This error is never generated by the smtp_stream(3) module, but
/* is defined for application-specific use.
/* BUGS /* BUGS
/* The timeout deadline affects all I/O on the named stream, not /* The timeout deadline affects all I/O on the named stream, not
/* just the I/O done on behalf of this module. /* just the I/O done on behalf of this module.

View File

@ -28,6 +28,7 @@
*/ */
#define SMTP_ERR_EOF 1 /* unexpected client disconnect */ #define SMTP_ERR_EOF 1 /* unexpected client disconnect */
#define SMTP_ERR_TIME 2 /* time out */ #define SMTP_ERR_TIME 2 /* time out */
#define SMTP_ERR_PROTO 3 /* protocol (application) */
extern void smtp_timeout_setup(VSTREAM *, int); extern void smtp_timeout_setup(VSTREAM *, int);
extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...); extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);

View File

@ -231,7 +231,21 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
if (*cp == ' ' || *cp == 0) if (*cp == ' ' || *cp == 0)
break; break;
} }
/*
* XXX Do not ignore garbage when ESMTP command pipelining is turned
* on. After sending ".<CR><LF>QUIT<CR><LF>", Postfix might recognize
* the server's 2XX QUIT reply as a 2XX END-OF-DATA reply after
* garbage, causing mail to be lost. Instead, make a long jump so
* that all recipients of multi-recipient mail get consistent
* treatment.
*/
state->error_mask |= MAIL_ERROR_PROTOCOL; state->error_mask |= MAIL_ERROR_PROTOCOL;
if (state->features & LMTP_FEATURE_PIPELINING) {
msg_warn("non-SMTP response from %s: %s",
session->namaddr, STR(state->buffer));
vstream_longjmp(session->stream, SMTP_ERR_PROTO);
}
} }
/* /*

View File

@ -378,6 +378,12 @@ int lmtp_stream_except(LMTP_STATE *state, int code, const char *description)
"conversation with %s timed out while %s", "conversation with %s timed out while %s",
session->namaddr, description); session->namaddr, description);
break; break;
case SMTP_ERR_PROTO:
lmtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA,
"4.5.0", "403 remote protocol error",
"protocol error in reply from %s while %s",
session->namaddr, description);
break;
} }
return (lmtp_bulk_fail(state, &dsn, LMTP_THROTTLE)); return (lmtp_bulk_fail(state, &dsn, LMTP_THROTTLE));
} }

View File

@ -263,8 +263,7 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
} else { } else {
canon_owner = 0; canon_owner = 0;
if (var_sticky_owner_alias == 0) RESET_OWNER_ATTR(state.msg_attr, state.level);
RESET_OWNER_ATTR(state.msg_attr, state.level);
} }
/* /*

View File

@ -367,11 +367,6 @@
/* address (see prepend_delivered_header) only once, at the start of /* address (see prepend_delivered_header) only once, at the start of
/* a delivery attempt; do not update the Delivered-To: address while /* a delivery attempt; do not update the Delivered-To: address while
/* expanding aliases or .forward files. /* expanding aliases or .forward files.
/* .IP "\fBsticky_owner_alias (yes)\fR"
/* When expanding a \fBlocal\fR(8) alias that has an owner alias (see
/* owner-\fIname\fR discussion in \fBaliases\fR(5)), use the owner information
/* even when the expansion invokes a subordinate alias that has no
/* owner alias.
/* DELIVERY METHOD CONTROLS /* DELIVERY METHOD CONTROLS
/* .ad /* .ad
/* .fi /* .fi
@ -620,7 +615,6 @@ int var_mailtool_compat;
char *var_mailbox_lock; char *var_mailbox_lock;
int var_mailbox_limit; int var_mailbox_limit;
bool var_frozen_delivered; bool var_frozen_delivered;
bool var_sticky_owner_alias;
int local_cmd_deliver_mask; int local_cmd_deliver_mask;
int local_file_deliver_mask; int local_file_deliver_mask;
@ -861,7 +855,6 @@ int main(int argc, char **argv)
VAR_STAT_HOME_DIR, DEF_STAT_HOME_DIR, &var_stat_home_dir, VAR_STAT_HOME_DIR, DEF_STAT_HOME_DIR, &var_stat_home_dir,
VAR_MAILTOOL_COMPAT, DEF_MAILTOOL_COMPAT, &var_mailtool_compat, VAR_MAILTOOL_COMPAT, DEF_MAILTOOL_COMPAT, &var_mailtool_compat,
VAR_FROZEN_DELIVERED, DEF_FROZEN_DELIVERED, &var_frozen_delivered, VAR_FROZEN_DELIVERED, DEF_FROZEN_DELIVERED, &var_frozen_delivered,
VAR_STICKY_OWNER_ALIAS, DEF_STICKY_OWNER_ALIAS, &var_sticky_owner_alias,
0, 0,
}; };

View File

@ -251,7 +251,21 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session)
if (*cp == ' ' || *cp == 0) if (*cp == ' ' || *cp == 0)
break; break;
} }
/*
* XXX Do not ignore garbage when ESMTP command pipelining is turned
* on. After sending ".<CR><LF>QUIT<CR><LF>", Postfix might recognize
* the server's 2XX QUIT reply as a 2XX END-OF-DATA reply after
* garbage, causing mail to be lost. Instead, make a long jump so
* that all recipients of multi-recipient mail get consistent
* treatment.
*/
session->error_mask |= MAIL_ERROR_PROTOCOL; session->error_mask |= MAIL_ERROR_PROTOCOL;
if (session->features & SMTP_FEATURE_PIPELINING) {
msg_warn("non-SMTP response from %s: %s",
session->namaddr, STR(session->buffer));
vstream_longjmp(session->stream, SMTP_ERR_PROTO);
}
} }
/* /*

View File

@ -432,6 +432,12 @@ int smtp_stream_except(SMTP_STATE *state, int code, const char *description)
"conversation with %s timed out while %s", "conversation with %s timed out while %s",
session->namaddr, description); session->namaddr, description);
break; break;
case SMTP_ERR_PROTO:
smtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA,
"4.5.0", "403 remote protocol error",
"protocol error in reply from %s while %s",
session->namaddr, description);
break;
} }
return (smtp_bulk_fail(state, &dsn, SMTP_THROTTLE)); return (smtp_bulk_fail(state, &dsn, SMTP_THROTTLE));
} }

View File

@ -275,6 +275,7 @@ smtpd_peer.o: ../../include/argv.h
smtpd_peer.o: ../../include/attr.h smtpd_peer.o: ../../include/attr.h
smtpd_peer.o: ../../include/inet_proto.h smtpd_peer.o: ../../include/inet_proto.h
smtpd_peer.o: ../../include/iostuff.h smtpd_peer.o: ../../include/iostuff.h
smtpd_peer.o: ../../include/mail_params.h
smtpd_peer.o: ../../include/mail_proto.h smtpd_peer.o: ../../include/mail_proto.h
smtpd_peer.o: ../../include/mail_stream.h smtpd_peer.o: ../../include/mail_stream.h
smtpd_peer.o: ../../include/msg.h smtpd_peer.o: ../../include/msg.h

View File

@ -415,6 +415,11 @@
/* The maximal number of lines in the Postfix SMTP server command history /* The maximal number of lines in the Postfix SMTP server command history
/* before it is flushed upon receipt of EHLO, RSET, or end of DATA. /* before it is flushed upon receipt of EHLO, RSET, or end of DATA.
/* .PP /* .PP
/* Available in Postfix version 2.3 and later:
/* .IP "\fBsmtpd_peername_lookup (yes)\fR"
/* Attempt to look up the SMTP client hostname, and verify that
/* the name matches the client IP address.
/* .PP
/* The per SMTP client connection count and request rate limits are /* The per SMTP client connection count and request rate limits are
/* implemented in co-operation with the \fBanvil\fR(8) service, and /* implemented in co-operation with the \fBanvil\fR(8) service, and
/* are available in Postfix version 2.2 and later. /* are available in Postfix version 2.2 and later.
@ -435,6 +440,11 @@
/* .IP "\fBsmtpd_client_event_limit_exceptions ($mynetworks)\fR" /* .IP "\fBsmtpd_client_event_limit_exceptions ($mynetworks)\fR"
/* Clients that are excluded from connection count, connection rate, /* Clients that are excluded from connection count, connection rate,
/* or SMTP request rate restrictions. /* or SMTP request rate restrictions.
/* .PP
/* Available in Postfix version 2.3 and later:
/* .IP "\fBsmtpd_client_new_tls_session_rate_limit (0)\fR"
/* The maximal number of new (i.e., uncached) TLS sessions that any
/* client is allowed to negotiate with this service per time unit.
/* TARPIT CONTROLS /* TARPIT CONTROLS
/* .ad /* .ad
/* .fi /* .fi
@ -912,6 +922,7 @@ int var_smtpd_crate_limit;
int var_smtpd_cconn_limit; int var_smtpd_cconn_limit;
int var_smtpd_cmail_limit; int var_smtpd_cmail_limit;
int var_smtpd_crcpt_limit; int var_smtpd_crcpt_limit;
int var_smtpd_cntls_limit;
char *var_smtpd_hoggers; char *var_smtpd_hoggers;
char *var_local_rwr_clients; char *var_local_rwr_clients;
char *var_smtpd_ehlo_dis_words; char *var_smtpd_ehlo_dis_words;
@ -933,6 +944,8 @@ char *var_smtpd_sasl_tls_opts;
#endif #endif
bool var_smtpd_peername_lookup;
/* /*
* Silly little macros. * Silly little macros.
*/ */
@ -982,6 +995,7 @@ int smtpd_input_transp_mask;
static void helo_reset(SMTPD_STATE *); static void helo_reset(SMTPD_STATE *);
static void mail_reset(SMTPD_STATE *); static void mail_reset(SMTPD_STATE *);
static void rcpt_reset(SMTPD_STATE *); static void rcpt_reset(SMTPD_STATE *);
static void tls_reset(SMTPD_STATE *);
static void chat_reset(SMTPD_STATE *, int); static void chat_reset(SMTPD_STATE *, int);
/* /*
@ -3025,6 +3039,25 @@ static void chat_reset(SMTPD_STATE *state, int threshold)
static void smtpd_start_tls(SMTPD_STATE *state) static void smtpd_start_tls(SMTPD_STATE *state)
{ {
int rate;
/*
* XXX The client event count/rate control must be consistent in its use
* of client address information in connect and disconnect events. For
* now we exclude xclient authorized hosts from event count/rate control.
*/
if (SMTPD_STAND_ALONE(state) == 0
&& !xclient_allowed
&& anvil_clnt
&& var_smtpd_cntls_limit > 0
&& !namadr_list_match(hogger_list, state->name, state->addr)
&& anvil_clnt_newtls_stat(anvil_clnt, state->service, state->addr,
&rate) == ANVIL_STAT_OK
&& rate > var_smtpd_cntls_limit) {
msg_warn("Refusing STARTTLS request from %s for service %s",
state->namaddr, state->service);
vstream_longjmp(state->client, SMTP_ERR_EOF);
}
/* /*
* Wrapper mode uses a dedicated port and always requires TLS. * Wrapper mode uses a dedicated port and always requires TLS.
@ -3037,9 +3070,30 @@ static void smtpd_start_tls(SMTPD_STATE *state)
* verification unless TLS is required. * verification unless TLS is required.
*/ */
state->tls_context = state->tls_context =
tls_server_start(smtpd_tls_ctx, state->client, tls_server_start(smtpd_tls_ctx, state->client,
var_smtpd_starttls_tmout, state->name, state->addr, var_smtpd_starttls_tmout, state->name, state->addr,
(var_smtpd_tls_req_ccert && state->tls_enforce_tls)); (var_smtpd_tls_req_ccert && state->tls_enforce_tls));
/*
* XXX The client event count/rate control must be consistent in its use
* of client address information in connect and disconnect events. For
* now we exclude xclient authorized hosts from event count/rate control.
*/
if (state->tls_context
&& state->tls_context->session_reused == 0
&& SMTPD_STAND_ALONE(state) == 0
&& !xclient_allowed
&& anvil_clnt
&& var_smtpd_cntls_limit > 0
&& !namadr_list_match(hogger_list, state->name, state->addr)
&& anvil_clnt_newtls(anvil_clnt, state->service, state->addr,
&rate) == ANVIL_STAT_OK
&& rate > var_smtpd_cntls_limit) {
msg_warn("Too many uncached TLS sessions: "
"%d from %s for service %s",
rate, state->namaddr, state->service);
tls_reset(state);
}
/* /*
* When the TLS handshake fails, the conversation is in an unknown state. * When the TLS handshake fails, the conversation is in an unknown state.
@ -3587,7 +3641,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
* Connection rate management. * Connection rate management.
*/ */
if (var_smtpd_crate_limit || var_smtpd_cconn_limit if (var_smtpd_crate_limit || var_smtpd_cconn_limit
|| var_smtpd_cmail_limit || var_smtpd_crcpt_limit) || var_smtpd_cmail_limit || var_smtpd_crcpt_limit
|| var_smtpd_cntls_limit)
anvil_clnt = anvil_clnt_create(); anvil_clnt = anvil_clnt_create();
} }
@ -3625,6 +3680,7 @@ int main(int argc, char **argv)
VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0, VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
VAR_SMTPD_CMAIL_LIMIT, DEF_SMTPD_CMAIL_LIMIT, &var_smtpd_cmail_limit, 0, 0, VAR_SMTPD_CMAIL_LIMIT, DEF_SMTPD_CMAIL_LIMIT, &var_smtpd_cmail_limit, 0, 0,
VAR_SMTPD_CRCPT_LIMIT, DEF_SMTPD_CRCPT_LIMIT, &var_smtpd_crcpt_limit, 0, 0, VAR_SMTPD_CRCPT_LIMIT, DEF_SMTPD_CRCPT_LIMIT, &var_smtpd_crcpt_limit, 0, 0,
VAR_SMTPD_CNTLS_LIMIT, DEF_SMTPD_CNTLS_LIMIT, &var_smtpd_cntls_limit, 0, 0,
#ifdef USE_TLS #ifdef USE_TLS
VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0, VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
#endif #endif
@ -3664,6 +3720,7 @@ int main(int argc, char **argv)
VAR_SMTPD_TLS_RCERT, DEF_SMTPD_TLS_RCERT, &var_smtpd_tls_req_ccert, VAR_SMTPD_TLS_RCERT, DEF_SMTPD_TLS_RCERT, &var_smtpd_tls_req_ccert,
VAR_SMTPD_TLS_RECHEAD, DEF_SMTPD_TLS_RECHEAD, &var_smtpd_tls_received_header, VAR_SMTPD_TLS_RECHEAD, DEF_SMTPD_TLS_RECHEAD, &var_smtpd_tls_received_header,
#endif #endif
VAR_SMTPD_PEERNAME_LOOKUP, DEF_SMTPD_PEERNAME_LOOKUP, &var_smtpd_peername_lookup,
0, 0,
}; };
static CONFIG_STR_TABLE str_table[] = { static CONFIG_STR_TABLE str_table[] = {

View File

@ -118,6 +118,7 @@
#include <mail_proto.h> #include <mail_proto.h>
#include <valid_mailhost_addr.h> #include <valid_mailhost_addr.h>
#include <mail_params.h>
/* Application-specific. */ /* Application-specific. */
@ -251,8 +252,19 @@ void smtpd_peer_init(SMTPD_STATE *state)
state->name_status = code; \ state->name_status = code; \
} }
if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name, if (var_smtpd_peername_lookup == 0) {
(MAI_SERVNAME_STR *) 0, 0)) != 0) { state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
#ifdef FORWARD_CLIENT_NAME
state->forward_name = mystrdup(CLIENT_NAME_UNKNOWN);
#endif
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
#ifdef FORWARD_CLIENT_NAME
state->forward_name_status = SMTPD_PEER_CODE_PERM;
#endif
} else if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
#ifdef FORWARD_CLIENT_NAME #ifdef FORWARD_CLIENT_NAME

View File

@ -56,7 +56,8 @@ typedef struct {
const char *cipher_name; const char *cipher_name;
int cipher_usebits; int cipher_usebits;
int cipher_algbits; int cipher_algbits;
int log_level; int log_level; /* TLS library logging level */
int session_reused; /* this session was reused */
} TLScontext_t; } TLScontext_t;
#define TLS_BIO_BUFSIZE 8192 #define TLS_BIO_BUFSIZE 8192

View File

@ -693,6 +693,12 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream,
if (var_smtp_tls_loglevel < 4) if (var_smtp_tls_loglevel < 4)
BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
/*
* The caller may want to know if this session was reused or if a new
* session was negotiated.
*/
TLScontext->session_reused = SSL_session_reused(TLScontext->con);
/* /*
* Do peername verification if requested and extract useful information * Do peername verification if requested and extract useful information
* from the certificate for later use. * from the certificate for later use.

View File

@ -564,6 +564,12 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
if (var_smtpd_tls_loglevel < 4) if (var_smtpd_tls_loglevel < 4)
BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
/*
* The caller may want to know if this session was reused or if a new
* session was negotiated.
*/
TLScontext->session_reused = SSL_session_reused(TLScontext->con);
/* /*
* Let's see whether a peer certificate is available and what is the * Let's see whether a peer certificate is available and what is the
* actual information. We want to save it for later use. * actual information. We want to save it for later use.
@ -618,6 +624,8 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
*/ */
if (requirecert) { if (requirecert) {
if (!TLScontext->peer_verified || !TLScontext->peer_CN) { if (!TLScontext->peer_verified || !TLScontext->peer_CN) {
if (TLScontext->session_reused == 0)
msg_panic("tls_server_start: peer was not verified");
msg_info("Re-used session without peer certificate removed"); msg_info("Re-used session without peer certificate removed");
uncache_session(server_ctx, TLScontext); uncache_session(server_ctx, TLScontext);
tls_free_context(TLScontext); tls_free_context(TLScontext);

View File

@ -15,7 +15,8 @@
/* DICT *ptr; /* DICT *ptr;
/* DESCRIPTION /* DESCRIPTION
/* dict_alloc() allocates memory for a dictionary structure of /* dict_alloc() allocates memory for a dictionary structure of
/* \fIsize\fR bytes, initializes all properties to default settings, /* \fIsize\fR bytes, initializes all generic dictionary
/* properties to default settings,
/* and installs default methods that do not support any operation. /* and installs default methods that do not support any operation.
/* The caller is supposed to override the default methods with /* The caller is supposed to override the default methods with
/* ones that it supports. /* ones that it supports.