Cleanup: don't log "blocked using example.com=127.0.0.1",
just log the domain name. File: smtpd/smtpd_check.c.
+
+20101129
+
+ Cleanup: postscreen_client_connection_count_limit (default:
+ $smtpd_client_connection_count_limit) to limit the number
+ of connections from the same IP address to the postscreen(8)
+ daemon. Files: postscreen/postscreen.c, postscreen/postscreen.h,
+ postscreen/postscreen_state.c.
+
+20101130
+
+ Cleanup: all postscreen(8) logging now reports the client
+ as [address]:port. This requires an update of tools that
+ process postscreen logging. Files: postscreen/*.c,
+ proto/POSTSCREEN_README.html.
+
+ Cleanup: polishing recent documentation and code. Files:
+ postscreen/postscreen_dnsbl.c, util/ip_match.c.
The postscreen_whitelist_networks parameter (default: $mynetworks) specifies a
permanent whitelist for SMTP client IP addresses. When the SMTP client address
-matches the permanent whitelist, this is logged as:
+matches the permanent whitelist, postscreen(8) logs this with the client
+address and port number as:
- W\bWH\bHI\bIT\bTE\bEL\bLI\bIS\bST\bTE\bED\bD address
+ W\bWH\bHI\bIT\bTE\bEL\bLI\bIS\bST\bTE\bED\bD [address]:port
The action is not configurable: immediately hand off the connection to a
Postfix SMTP server process.
The postscreen_blacklist_networks parameter (default: empty) specifies a
permanent blacklist for SMTP client IP addresses. The address syntax is as with
mynetworks. When the SMTP client address matches the permanent blacklist,
-postscreen(8) logs this as:
+postscreen(8) logs this with the client address and port number as:
- B\bBL\bLA\bAC\bCK\bKL\bLI\bIS\bST\bTE\bED\bD address
+ B\bBL\bLA\bAC\bCK\bKL\bLI\bIS\bST\bTE\bED\bD [address]:port
The postscreen_blacklist_action parameter specifies the action that is taken
next. See "When tests fail before the 220 SMTP server greeting" below.
appear on the permanent blacklist or whitelist.
When the SMTP client address appears on the temporary whitelist, postscreen(8)
-logs this as:
+logs this with the client address and port number as:
- P\bPA\bAS\bSS\bS O\bOL\bLD\bD address
+ P\bPA\bAS\bSS\bS O\bOL\bLD\bD [address]:port
The action is not configurable: immediately hand off the connection to a
Postfix SMTP server process. The client is excluded from further tests until
When an SMTP client sends a command before the postscreen_greet_wait time has
elapsed, postscreen(8) logs this as:
- P\bPR\bRE\bEG\bGR\bRE\bEE\bET\bT count a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm address text...
+ P\bPR\bRE\bEG\bGR\bRE\bEE\bET\bT count a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm [address]:port text...
-Translation: the client at address sent count bytes before its turn to speak.
-This happened time seconds after the postscreen_greet_wait timer was started.
-The text is what the client sent (truncated to 100 bytes, and with non-
-printable characters replaced with "?").
+Translation: the client at [address]:port sent count bytes before its turn to
+speak. This happened time seconds after the postscreen_greet_wait timer was
+started. The text is what the client sent (truncated to 100 bytes, and with
+non-printable characters replaced with "?").
The postscreen_greet_action parameter specifies the action that is taken next.
See "When tests fail before the 220 SMTP server greeting" below.
is equal to or greater than the postscreen_dnsbl_threshold parameter value,
postscreen(8) logs this as:
- D\bDN\bNS\bSB\bBL\bL r\bra\ban\bnk\bk count f\bfo\bor\br address
+ D\bDN\bNS\bSB\bBL\bL r\bra\ban\bnk\bk count f\bfo\bor\br [address]:port
-Translation: the SMTP client at address has a combined DNSBL score of count.
+Translation: the SMTP client at [address]:port has a combined DNSBL score of
+count.
The postscreen_dnsbl_action parameter specifies the action that is taken when
the combined DNSBL score is equal to or greater than the threshold. See "When
When a client sends multiple commands, postscreen(8) logs this as:
- C\bCO\bOM\bMM\bMA\bAN\bND\bD P\bPI\bIP\bPE\bEL\bLI\bIN\bNI\bIN\bNG\bG a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm address
+ C\bCO\bOM\bMM\bMA\bAN\bND\bD P\bPI\bIP\bPE\bEL\bLI\bIN\bNI\bIN\bNG\bG a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm [address]:port
-Translation: the SMTP client at address sent multiple SMTP commands, instead of
-sending one command and then waiting for the server to reply. This happened
-time seconds after the "220 " server greeting was sent.
+Translation: the SMTP client at [address]:port sent multiple SMTP commands,
+instead of sending one command and then waiting for the server to reply. This
+happened time seconds after the "220 " server greeting was sent.
The postscreen_pipelining_action parameter specifies the action that is taken
next. See "When tests fail after the 220 SMTP server greeting" below.
When a client sends non-SMTP commands, postscreen(8) logs this as:
- N\bNO\bON\bN-\b-S\bSM\bMT\bTP\bP C\bCO\bOM\bMM\bMA\bAN\bND\bD f\bfr\bro\bom\bm address command
+ N\bNO\bON\bN-\b-S\bSM\bMT\bTP\bP C\bCO\bOM\bMM\bMA\bAN\bND\bD f\bfr\bro\bom\bm [address]:port command
-Translation: the SMTP client at address sent a command that matches the
+Translation: the SMTP client at [address]:port sent a command that matches the
postscreen_forbidden_commands parameter, or that has the syntax of a message
header label.
When a client sends bare newline characters, postscreen(8) logs this as:
- B\bBA\bAR\bRE\bE N\bNE\bEW\bWL\bLI\bIN\bNE\bE f\bfr\bro\bom\bm address
+ B\bBA\bAR\bRE\bE N\bNE\bEW\bWL\bLI\bIN\bNE\bE f\bfr\bro\bom\bm [address]:port
-Translation: the SMTP client at address sent a bare newline character, that is
-newline not preceded by carriage return.
+Translation: the SMTP client at [address]:port sent a bare newline character,
+that is newline not preceded by carriage return.
The postscreen_bare_newline_action parameter specifies the action that is taken
next. See "When tests fail after the 220 SMTP server greeting" below.
When an SMTP client hangs up unexpectedly during any tests, postscreen(8) logs
this as:
- H\bHA\bAN\bNG\bGU\bUP\bP a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm address i\bin\bn test name
+ H\bHA\bAN\bNG\bGU\bUP\bP a\baf\bft\bte\ber\br time f\bfr\bro\bom\bm [address]:port i\bin\bn test name
-Translation: the SMTP client at address disconnected unexpectedly, time seconds
-after the start of the test named test name.
+Translation: the SMTP client at [address]:port disconnected unexpectedly, time
+seconds after the start of the test named test name.
The following errors are reported by the built-in SMTP engine. This engine
never accepts mail, therefore it has per-session limits on the number of
commands and on the session length.
- C\bCO\bOM\bMM\bMA\bAN\bND\bD T\bTI\bIM\bME\bE L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm address
+ C\bCO\bOM\bMM\bMA\bAN\bND\bD T\bTI\bIM\bME\bE L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm [address]:port
-Translation: the SMTP client at address reached the per-command time limit as
-specified with the postscreen_command_time_limit parameter. The session is
-terminated immediately.
+Translation: the SMTP client at [address]:port reached the per-command time
+limit as specified with the postscreen_command_time_limit parameter. The
+session is terminated immediately.
- C\bCO\bOM\bMM\bMA\bAN\bND\bD C\bCO\bOU\bUN\bNT\bT L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm address
+ C\bCO\bOM\bMM\bMA\bAN\bND\bD C\bCO\bOU\bUN\bNT\bT L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm [address]:port
-Translation: the SMTP client at address reached the per-session command count
-limit as specified with the postscreen_command_count_limit parameter. The
+Translation: the SMTP client at [address]:port reached the per-session command
+count limit as specified with the postscreen_command_count_limit parameter. The
session is terminated immediately.
- C\bCO\bOM\bMM\bMA\bAN\bND\bD L\bLE\bEN\bNG\bGT\bTH\bH L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm address
+ C\bCO\bOM\bMM\bMA\bAN\bND\bD L\bLE\bEN\bNG\bGT\bTH\bH L\bLI\bIM\bMI\bIT\bT f\bfr\bro\bom\bm [address]:port
+
+Translation: the SMTP client at [address]:port reached the per-command length
+limit, as specified with the line_length_limit parameter. The session is
+terminated immediately.
+
+When an SMTP client makes too many connections at the same time, or when all
+postscreen(8) ports are busy, postscreen(8) rejects the connection with a 421
+status code and logs:
+
+ N\bNO\bOQ\bQU\bUE\bEU\bUE\bE:\b: r\bre\bej\bje\bec\bct\bt:\b: C\bCO\bON\bNN\bNE\bEC\bCT\bT f\bfr\bro\bom\bm [address]:port:\b: t\bto\boo\bo m\bma\ban\bny\by c\bco\bon\bnn\bne\bec\bct\bti\bio\bon\bns\bs
+ N\bNO\bOQ\bQU\bUE\bEU\bUE\bE:\b: r\bre\bej\bje\bec\bct\bt:\b: C\bCO\bON\bNN\bNE\bEC\bCT\bT f\bfr\bro\bom\bm [address]:port:\b: a\bal\bll\bl s\bse\ber\brv\bve\ber\br p\bpo\bor\brt\bts\bs b\bbu\bus\bsy\by
-Translation: the SMTP client at address reached the per-command length limit,
-as specified with the line_length_limit parameter. The session is terminated
-immediately.
+The postscreen_client_connection_count_limit and postscreen_pre_queue_limit
+parameters control these limits.
W\bWh\bhe\ben\bn a\bal\bll\bl t\bte\bes\bst\bts\bs s\bsu\buc\bcc\bce\bee\bed\bd
When a new SMTP client passes all tests (i.e. it is not whitelisted via some
mechanism), postscreen(8) logs this as:
- P\bPA\bAS\bSS\bS N\bNE\bEW\bW address
+ P\bPA\bAS\bSS\bS N\bNE\bEW\bW [address]:port
-Where address is the client IP address. Then, postscreen(8) creates a temporary
-whitelist entry that excludes the client IP address from further tests until
-the temporary whitelist entry expires, as controlled with the postscreen_*_ttl
-parameters.
+Where [address]:port are the client IP address and port. Then, postscreen(8)
+creates a temporary whitelist entry that excludes the client IP address from
+further tests until the temporary whitelist entry expires, as controlled with
+the postscreen_*_ttl parameters.
When no "deep protocol tests" are configured, postscreen(8) hands off the
"live" connection to a Postfix SMTP server process. The client can then
postscreen parameters always evaluate as if the stress value is
equal to the empty string.
+Incompatibility with snapshot 20101130
+======================================
+
+The postscreen(8) daemon now logs the client as [address]:port.
+The port helps to distinguish between simultaneous sessions from
+the same address, and the [] allow the same tool to be used with
+old and new format logfiles, without producing errors for IPv6.
+
Major changes with snapshot 20101126
====================================
Support for address patterns in DNSBL and DNSWL lookup results.
-For example, "reject_rbl_client example.com = 127.0.0.[2,4,6..8]"
+For example, "reject_rbl_client example.com=127.0.0.[2,4,6..8]"
will reject clients when the lookup result is 127.0.0.2, 127.0.0.4,
127.0.0.6, 127.0.0.7, or 127.0.0.8.
anvil rate limit for sasl_username.
- postscreen per-client connection count limit.
-
smtpd xclient option for sasl_username.
- Documentation: add a note that smtpd_helo_required=yes is
- needed to really enforce HELO restrictions.
-
Use different ipc_timeout settings for email message
transactions (smtpd, pickup)->cleanup and for quick query/reply
transactions such as address rewriting/resolution.
<p> The <a href="postconf.5.html#postscreen_whitelist_networks">postscreen_whitelist_networks</a> parameter (default: $<a href="postconf.5.html#mynetworks">mynetworks</a>)
specifies a permanent whitelist for SMTP client IP addresses. When
-the SMTP client address matches the permanent whitelist, this is
-logged as: </p>
+the SMTP client address matches the permanent whitelist, <a href="postscreen.8.html">postscreen(8)</a>
+logs this with the client address and port number as: </p>
<pre>
- <b>WHITELISTED</b> <i>address</i>
+ <b>WHITELISTED</b> <i>[address]:port</i>
</pre>
<p> The action is not configurable: immediately hand off the
<p> The <a href="postconf.5.html#postscreen_blacklist_networks">postscreen_blacklist_networks</a> parameter (default: empty)
specifies a permanent blacklist for SMTP client IP addresses. The
address syntax is as with <a href="postconf.5.html#mynetworks">mynetworks</a>. When the SMTP client address
-matches the permanent blacklist, <a href="postscreen.8.html">postscreen(8)</a> logs this as: </p>
+matches the permanent blacklist, <a href="postscreen.8.html">postscreen(8)</a> logs this with the
+client address and port number as: </p>
<pre>
- <b>BLACKLISTED</b> <i>address</i>
+ <b>BLACKLISTED</b> <i>[address]:port</i>
</pre>
<p> The <a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> parameter specifies the action
that appear on the <i>permanent</i> blacklist or whitelist. </p>
<p> When the SMTP client address appears on the temporary
-whitelist, <a href="postscreen.8.html">postscreen(8)</a> logs this as: </p>
+whitelist, <a href="postscreen.8.html">postscreen(8)</a> logs this with the client address and port
+number as: </p>
<pre>
- <b>PASS OLD</b> <i>address</i>
+ <b>PASS OLD</b> <i>[address]:port</i>
</pre>
<p> The action is not configurable: immediately hand off the
</p>
<pre>
- <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>address text...</i>
+ <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>[address]:port text...</i>
</pre>
-<p> Translation: the client at <i>address</i> sent <i>count</i>
+<p> Translation: the client at <i>[address]:port</i> sent <i>count</i>
bytes before its turn to speak. This happened <i>time</i> seconds
after the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> timer was started. The <i>text</i>
is what the client sent (truncated to 100 bytes, and with non-printable
parameter value, <a href="postscreen.8.html">postscreen(8)</a> logs this as: </p>
<pre>
- <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>address</i>
+ <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> has a combined
+<p> Translation: the SMTP client at <i>[address]:port</i> has a combined
DNSBL score of <i>count</i>. </p>
<p> The <a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> parameter specifies the action that
as: </p>
<pre>
- <b>COMMAND PIPELINING after</b> <i>time</i> <b>from</b> <i>address</i>
+ <b>COMMAND PIPELINING after</b> <i>time</i> <b>from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent multiple
+<p> Translation: the SMTP client at <i>[address]:port</i> sent multiple
SMTP commands, instead of sending one command and then waiting for
the server to reply. This happened <i>time</i> seconds after the
"220 " server greeting was sent. </p>
as: </p>
<pre>
- <b>NON-SMTP COMMAND from</b> <i>address command</i>
+ <b>NON-SMTP COMMAND from</b> <i>[address]:port command</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent a
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a
<i>command</i> that matches the <a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a>
parameter, or that has the syntax of a message header label. </p>
</p>
<pre>
- <b>BARE NEWLINE from</b> <i>address</i>
+ <b>BARE NEWLINE from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent a bare
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a bare
newline character, that is newline not preceded by carriage
return. </p>
<a href="postscreen.8.html">postscreen(8)</a> logs this as: </p>
<pre>
- <b>HANGUP after</b> <i>time</i> <b>from</b> <i>address</i> <b>in</b> <i>test name</i>
+ <b>HANGUP after</b> <i>time</i> <b>from</b> <i>[address]:port</i> <b>in</b> <i>test name</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> disconnected
+<p> Translation: the SMTP client at <i>[address]:port</i> disconnected
unexpectedly, <i>time</i> seconds after the start of the
test named <i>test name</i>. </p>
with the remaining amount of penalty time as: </p>
<pre>
- <b>PENALTY</b> <i>time</i> <b>for</b> <i>address</i>
+ <b>PENALTY</b> <i>time</i> <b>for</b> <i>[address]:port</i>
</pre>
<p> During this time, all attempts by the client to deliver mail
on the number of commands and on the session length. </p>
<pre>
- <b>COMMAND TIME LIMIT</b> <b>from</b> <i>address</i>
+ <b>COMMAND TIME LIMIT</b> <b>from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-command time limit as specified with the <a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a>
parameter. The session is terminated immediately. </p>
<pre>
- <b>COMMAND COUNT LIMIT from</b> <i>address</i>
+ <b>COMMAND COUNT LIMIT from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-session command count limit as specified with the
<a href="postconf.5.html#postscreen_command_count_limit">postscreen_command_count_limit</a> parameter. The session is terminated
immediately. </p>
<pre>
- <b>COMMAND LENGTH LIMIT from</b> <i>address</i>
+ <b>COMMAND LENGTH LIMIT from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-command length limit, as specified with the <a href="postconf.5.html#line_length_limit">line_length_limit</a>
parameter. The session is terminated immediately. </p>
+<p> When an SMTP client makes too many connections at the same time,
+or when all <a href="postscreen.8.html">postscreen(8)</a> ports are busy, <a href="postscreen.8.html">postscreen(8)</a> rejects the
+connection with a 421 status code and logs: </p>
+
+<pre>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: too many connections</b>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: all server ports busy</b>
+</pre>
+
+<p> The <a href="postconf.5.html#postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a> and
+<a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> parameters control these limits. </p>
+
<h2> <a name="victory">When all tests succeed</a> </h2>
<p> When a new SMTP client passes all tests (i.e. it is not whitelisted
via some mechanism), <a href="postscreen.8.html">postscreen(8)</a> logs this as: </p>
<pre>
- <b>PASS NEW</b> <i>address</i>
+ <b>PASS NEW</b> <i>[address]:port</i>
</pre>
-<p> Where <i>address</i> is the client IP address. Then, <a href="postscreen.8.html">postscreen(8)</a>
+<p> Where <i>[address]:port</i> are the client IP address and port.
+Then, <a href="postscreen.8.html">postscreen(8)</a>
creates a temporary whitelist entry that excludes the client IP
address from further tests until the temporary whitelist entry
expires, as controlled with the postscreen_*_ttl parameters. </p>
<p> This feature is available in Postfix 2.8. </p>
+</DD>
+
+<DT><b><a name="postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a>
+(default: $<a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a>)</b></DT><DD>
+
+<p> How many simultaneous connections any client is allowed to have
+with the <a href="postscreen.8.html">postscreen(8)</a> daemon. By default, this limit is the same
+as with the Postfix SMTP server. Note that the triage process can
+take several seconds, with the time spent in <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a>
+delay, and with the time spent talking to the <a href="postscreen.8.html">postscreen(8)</a> built-in
+dummy SMTP protocol engine. </p>
+
+<p> This feature is available in Postfix 2.8. </p>
+
+
</DD>
<DT><b><a name="postscreen_command_count_limit">postscreen_command_count_limit</a>
<dd>Reject the request when the reversed client network address is
listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
-(Postfix version 2.1 and later only). Each "<i>d</i>" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "<i>d</i>" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "<i>=d.d.d.d</i>" is specified, reject the request when the
reversed client network address is listed with any A record under
<dd>Accept the request when the reversed client network address is
listed with the A record "<i>d.d.d.d</i>" under <i>dnswl_domain</i>.
-Each "<i>d</i>" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "<i>d</i>" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "<i>=d.d.d.d</i>" is specified, accept the request when the
reversed client network address is listed with any A record under
<i>dnswl_domain</i>. <br> For safety, <a href="postconf.5.html#permit_dnswl_client">permit_dnswl_client</a> is silently
<dd>Reject the request when the client hostname is listed with the
A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix version
-2.1 and later only). Each "<i>d</i>" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "<i>d</i>" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified, reject the request when the client
hostname is listed with
<dd>Accept the request when the client hostname is listed with the
A record "<i>d.d.d.d</i>" under <i>rhswl_domain</i>. Each "<i>d</i>"
-can be a pattern inside "[]" that contains one or more comma-separated
-decimal numbers or number..number ranges. If no
+is a number, or a pattern inside "[]" that contains one or more
+comma-separated numbers or number..number ranges. If no
"<i>=d.d.d.d</i>" is specified, accept the request when the client
hostname is listed with any A record under <i>rhswl_domain</i>.
<br> Caution: client name whitelisting is fragile, since the client
<dd>Reject the request when the unverified reverse client hostname
is listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>.
-Each "<i>d</i>" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "<i>d</i>" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "<i>=d.d.d.d</i>" is specified, reject the request when the
unverified reverse client hostname is listed with any A record under
<i>rbl_domain</i>. See the <a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a> description above for
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the HELO or EHLO
hostname or parent domains, and execute the corresponding action.
-</dd>
+Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce this
+restriction. </dd>
<dt><b><a name="check_helo_mx_access">check_helo_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later. </dd>
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
+</dd>
<dt><b><a name="check_helo_ns_access">check_helo_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the DNS servers
for the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later. </dd>
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
+</dd>
<dt><b><a name="reject_invalid_helo_hostname">reject_invalid_helo_hostname</a></b> (with Postfix < 2.3: reject_invalid_hostname)</dt>
<dd>Reject the request when the HELO or EHLO hostname syntax is
-invalid. <br> The <a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> specifies the response
-code for rejected requests (default: 501).</dd>
+invalid. Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce
+this restriction. <br> The <a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> specifies
+the response code for rejected requests (default: 501).</dd>
<dt><b><a name="reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a></b> (with Postfix < 2.3: reject_non_fqdn_hostname)</dt>
<dd>Reject the request when the HELO or EHLO hostname is not in
-fully-qualified domain form, as required by the RFC. <br> The
-<a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> parameter specifies the response code for
+fully-qualified domain form, as required by the RFC. Note: specify
+"<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce this restriction. <br>
+The <a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> parameter specifies the response code for
rejected requests (default: 504).</dd>
<dt><b><a name="reject_rhsbl_helo">reject_rhsbl_helo <i>rbl_domain=d.d.d.d</i></a></b></dt>
<dd>Reject the request when the HELO or EHLO hostname hostname is
listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
-(Postfix version 2.1 and later only). Each "<i>d</i>" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "<i>d</i>" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "<i>=d.d.d.d</i>" is
specified, reject the request when the HELO or EHLO hostname is
listed with any A record under <i>rbl_domain</i>. See the
<a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a> description for additional RBL related configuration
-parameters. This feature is available in Postfix 2.0 and later.
-</dd>
+parameters. Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully
+enforce this restriction. This feature is available in Postfix 2.0
+and later. </dd>
<dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix < 2.3: reject_unknown_hostname)</dt>
specifies the numerical response code for rejected requests (default:
450). <br> The <a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a> parameter
specifies the action after a temporary DNS error (default:
-<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>). </dd>
+<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>). Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully
+enforce this restriction. </dd>
</dl>
<dd>Reject the request when the RCPT TO domain is listed with the
A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix version
-2.1 and later only). Each "<i>d</i>" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "<i>d</i>" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified, reject
the request when the RCPT TO domain is listed with
<dd>Reject the request when the MAIL FROM domain is listed with
the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix
-version 2.1 and later only). Each "<i>d</i>" can be a pattern
-inside "[]" that contains one or more comma-separated decimal numbers
+version 2.1 and later only). Each "<i>d</i>" is a number, or a
+pattern inside "[]" that contains one or more comma-separated numbers
or number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified,
reject the request when the MAIL FROM domain is
of at most this length; upon delivery, long lines
are reconstructed.
+ <b><a href="postconf.5.html#postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a></b>
+ <b>($<a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a>)</b>
+ How many simultaneous connections any client is
+ allowed to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> daemon.
+
<b><a href="postconf.5.html#postscreen_command_count_limit">postscreen_command_count_limit</a> (20)</b>
- The limit on the total number of commands per SMTP
- session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
+ The limit on the total number of commands per SMTP
+ session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
engine.
<b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (${stress?10}${stress:300}s)</b>
- The command "read" time limit for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s
+ The command "read" time limit for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s
built-in SMTP protocol engine.
<b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
- The number of clients that can be waiting for ser-
+ The number of clients that can be waiting for ser-
vice from a real SMTP server process.
<b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
- The number of non-whitelisted clients that can be
- waiting for a decision whether they will receive
+ The number of non-whitelisted clients that can be
+ waiting for a decision whether they will receive
service from a real SMTP server process.
<b><a href="postconf.5.html#postscreen_watchdog_timeout">postscreen_watchdog_timeout</a> (10s)</b>
- How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
- respond to an SMTP client command or to perform a
+ How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
+ respond to an SMTP client command or to perform a
cache operation before it is terminated by a built-
in watchdog timer.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for an incoming connection
+ The maximum amount of time that an idle Postfix
+ daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
<a href="POSTSCREEN_README.html">POSTSCREEN_README</a>, Postfix Postscreen Howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
- Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
- by Michael Tokarev, in OpenBSD spamd, and in MailChannels
+ Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
+ by Michael Tokarev, in OpenBSD spamd, and in MailChannels
Traffic Control.
<b>AUTHOR(S)</b>
(weeks).
.PP
This feature is available in Postfix 2.8.
+.SH postscreen_client_connection_count_limit (default: $smtpd_client_connection_count_limit)
+How many simultaneous connections any client is allowed to have
+with the \fBpostscreen\fR(8) daemon. By default, this limit is the same
+as with the Postfix SMTP server. Note that the triage process can
+take several seconds, with the time spent in postscreen_greet_wait
+delay, and with the time spent talking to the \fBpostscreen\fR(8) built-in
+dummy SMTP protocol engine.
+.PP
+This feature is available in Postfix 2.8.
.SH postscreen_command_count_limit (default: 20)
The limit on the total number of commands per SMTP session for
\fBpostscreen\fR(8)'s built-in SMTP protocol engine. This SMTP engine
.IP "\fBreject_rbl_client \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the reversed client network address is
listed with the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR
-(Postfix version 2.1 and later only). Each "\fId\fR" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "\fId\fR" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "\fI=d.d.d.d\fR" is specified, reject the request when the
reversed client network address is listed with any A record under
.IP "\fBpermit_dnswl_client \fIdnswl_domain=d.d.d.d\fR\fR"
Accept the request when the reversed client network address is
listed with the A record "\fId.d.d.d\fR" under \fIdnswl_domain\fR.
-Each "\fId\fR" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "\fId\fR" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "\fI=d.d.d.d\fR" is specified, accept the request when the
reversed client network address is listed with any A record under
\fIdnswl_domain\fR.
.IP "\fBreject_rhsbl_client \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the client hostname is listed with the
A record "\fId.d.d.d\fR" under \fIrbl_domain\fR (Postfix version
-2.1 and later only). Each "\fId\fR" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "\fId\fR" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"\fI=d.d.d.d\fR" is specified, reject the request when the client
hostname is listed with
.IP "\fBpermit_rhswl_client \fIrhswl_domain=d.d.d.d\fR\fR"
Accept the request when the client hostname is listed with the
A record "\fId.d.d.d\fR" under \fIrhswl_domain\fR. Each "\fId\fR"
-can be a pattern inside "[]" that contains one or more comma-separated
-decimal numbers or number..number ranges. If no
+is a number, or a pattern inside "[]" that contains one or more
+comma-separated numbers or number..number ranges. If no
"\fI=d.d.d.d\fR" is specified, accept the request when the client
hostname is listed with any A record under \fIrhswl_domain\fR.
.br
.IP "\fBreject_rhsbl_reverse_client \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the unverified reverse client hostname
is listed with the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR.
-Each "\fId\fR" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "\fId\fR" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "\fI=d.d.d.d\fR" is specified, reject the request when the
unverified reverse client hostname is listed with any A record under
\fIrbl_domain\fR. See the reject_rbl_client description above for
.IP "\fBcheck_helo_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the HELO or EHLO
hostname or parent domains, and execute the corresponding action.
+Note: specify "smtpd_helo_required = yes" to fully enforce this
+restriction.
.IP "\fBcheck_helo_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later.
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "smtpd_helo_required = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
.IP "\fBcheck_helo_ns_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the DNS servers
for the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later.
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "smtpd_helo_required = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
.IP "\fBreject_invalid_helo_hostname\fR (with Postfix < 2.3: reject_invalid_hostname)"
Reject the request when the HELO or EHLO hostname syntax is
-invalid.
+invalid. Note: specify "smtpd_helo_required = yes" to fully enforce
+this restriction.
.br
-The invalid_hostname_reject_code specifies the response
-code for rejected requests (default: 501).
+The invalid_hostname_reject_code specifies
+the response code for rejected requests (default: 501).
.IP "\fBreject_non_fqdn_helo_hostname\fR (with Postfix < 2.3: reject_non_fqdn_hostname)"
Reject the request when the HELO or EHLO hostname is not in
-fully-qualified domain form, as required by the RFC.
+fully-qualified domain form, as required by the RFC. Note: specify
+"smtpd_helo_required = yes" to fully enforce this restriction.
.br
-The
-non_fqdn_reject_code parameter specifies the response code for
+The non_fqdn_reject_code parameter specifies the response code for
rejected requests (default: 504).
.IP "\fBreject_rhsbl_helo \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the HELO or EHLO hostname hostname is
listed with the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR
-(Postfix version 2.1 and later only). Each "\fId\fR" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "\fId\fR" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "\fI=d.d.d.d\fR" is
specified, reject the request when the HELO or EHLO hostname is
listed with any A record under \fIrbl_domain\fR. See the
reject_rbl_client description for additional RBL related configuration
-parameters. This feature is available in Postfix 2.0 and later.
+parameters. Note: specify "smtpd_helo_required = yes" to fully
+enforce this restriction. This feature is available in Postfix 2.0
+and later.
.IP "\fBreject_unknown_helo_hostname\fR (with Postfix < 2.3: reject_unknown_hostname)"
Reject the request when the HELO or EHLO hostname has no DNS A
or MX record.
.br
The unknown_helo_hostname_tempfail_action parameter
specifies the action after a temporary DNS error (default:
-defer_if_permit).
+defer_if_permit). Note: specify "smtpd_helo_required = yes" to fully
+enforce this restriction.
.PP
Other restrictions that are valid in this context:
.IP \(bu
.IP "\fBreject_rhsbl_recipient \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the RCPT TO domain is listed with the
A record "\fId.d.d.d\fR" under \fIrbl_domain\fR (Postfix version
-2.1 and later only). Each "\fId\fR" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "\fId\fR" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"\fI=d.d.d.d\fR" is specified, reject
the request when the RCPT TO domain is listed with
.IP "\fBreject_rhsbl_sender \fIrbl_domain=d.d.d.d\fR\fR"
Reject the request when the MAIL FROM domain is listed with
the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR (Postfix
-version 2.1 and later only). Each "\fId\fR" can be a pattern
-inside "[]" that contains one or more comma-separated decimal numbers
+version 2.1 and later only). Each "\fId\fR" is a number, or a
+pattern inside "[]" that contains one or more comma-separated numbers
or number..number ranges (Postfix version 2.8 and later). If no
"\fI=d.d.d.d\fR" is specified,
reject the request when the MAIL FROM domain is
.IP "\fBline_length_limit (2048)\fR"
Upon input, long lines are chopped up into pieces of at most
this length; upon delivery, long lines are reconstructed.
+.IP "\fBpostscreen_client_connection_count_limit ($smtpd_client_connection_count_limit)\fR"
+How many simultaneous connections any client is allowed to have
+with the \fBpostscreen\fR(8) daemon.
.IP "\fBpostscreen_command_count_limit (20)\fR"
The limit on the total number of commands per SMTP session for
\fBpostscreen\fR(8)'s built-in SMTP protocol engine.
s;\bpostscreen_whitelist_networks\b;<a href="postconf.5.html#postscreen_whitelist_networks">$&</a>;g;
s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_networks\b;<a href="postconf.5.html#postscreen_blacklist_networks">$&</a>;g;
s;\bpostscreen_black[-</bB>]*\n*[ <bB>]*list_action\b;<a href="postconf.5.html#postscreen_blacklist_action">$&</a>;g;
+ s;\bpostscreen_client_connection_count_limit\b;<a href="postconf.5.html#postscreen_client_connection_count_limit">$&</a>;g;
# Hyperlink URLs and RFC documents
<p> The postscreen_whitelist_networks parameter (default: $mynetworks)
specifies a permanent whitelist for SMTP client IP addresses. When
-the SMTP client address matches the permanent whitelist, this is
-logged as: </p>
+the SMTP client address matches the permanent whitelist, postscreen(8)
+logs this with the client address and port number as: </p>
<pre>
- <b>WHITELISTED</b> <i>address</i>
+ <b>WHITELISTED</b> <i>[address]:port</i>
</pre>
<p> The action is not configurable: immediately hand off the
<p> The postscreen_blacklist_networks parameter (default: empty)
specifies a permanent blacklist for SMTP client IP addresses. The
address syntax is as with mynetworks. When the SMTP client address
-matches the permanent blacklist, postscreen(8) logs this as: </p>
+matches the permanent blacklist, postscreen(8) logs this with the
+client address and port number as: </p>
<pre>
- <b>BLACKLISTED</b> <i>address</i>
+ <b>BLACKLISTED</b> <i>[address]:port</i>
</pre>
<p> The postscreen_blacklist_action parameter specifies the action
that appear on the <i>permanent</i> blacklist or whitelist. </p>
<p> When the SMTP client address appears on the temporary
-whitelist, postscreen(8) logs this as: </p>
+whitelist, postscreen(8) logs this with the client address and port
+number as: </p>
<pre>
- <b>PASS OLD</b> <i>address</i>
+ <b>PASS OLD</b> <i>[address]:port</i>
</pre>
<p> The action is not configurable: immediately hand off the
</p>
<pre>
- <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>address text...</i>
+ <b>PREGREET</b> <i>count</i> <b>after</b> <i>time</i> <b>from</b> <i>[address]:port text...</i>
</pre>
-<p> Translation: the client at <i>address</i> sent <i>count</i>
+<p> Translation: the client at <i>[address]:port</i> sent <i>count</i>
bytes before its turn to speak. This happened <i>time</i> seconds
after the postscreen_greet_wait timer was started. The <i>text</i>
is what the client sent (truncated to 100 bytes, and with non-printable
parameter value, postscreen(8) logs this as: </p>
<pre>
- <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>address</i>
+ <b>DNSBL rank</b> <i>count</i> <b>for</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> has a combined
+<p> Translation: the SMTP client at <i>[address]:port</i> has a combined
DNSBL score of <i>count</i>. </p>
<p> The postscreen_dnsbl_action parameter specifies the action that
as: </p>
<pre>
- <b>COMMAND PIPELINING after</b> <i>time</i> <b>from</b> <i>address</i>
+ <b>COMMAND PIPELINING after</b> <i>time</i> <b>from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent multiple
+<p> Translation: the SMTP client at <i>[address]:port</i> sent multiple
SMTP commands, instead of sending one command and then waiting for
the server to reply. This happened <i>time</i> seconds after the
"220 " server greeting was sent. </p>
as: </p>
<pre>
- <b>NON-SMTP COMMAND from</b> <i>address command</i>
+ <b>NON-SMTP COMMAND from</b> <i>[address]:port command</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent a
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a
<i>command</i> that matches the postscreen_forbidden_commands
parameter, or that has the syntax of a message header label. </p>
</p>
<pre>
- <b>BARE NEWLINE from</b> <i>address</i>
+ <b>BARE NEWLINE from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> sent a bare
+<p> Translation: the SMTP client at <i>[address]:port</i> sent a bare
newline character, that is newline not preceded by carriage
return. </p>
postscreen(8) logs this as: </p>
<pre>
- <b>HANGUP after</b> <i>time</i> <b>from</b> <i>address</i> <b>in</b> <i>test name</i>
+ <b>HANGUP after</b> <i>time</i> <b>from</b> <i>[address]:port</i> <b>in</b> <i>test name</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> disconnected
+<p> Translation: the SMTP client at <i>[address]:port</i> disconnected
unexpectedly, <i>time</i> seconds after the start of the
test named <i>test name</i>. </p>
with the remaining amount of penalty time as: </p>
<pre>
- <b>PENALTY</b> <i>time</i> <b>for</b> <i>address</i>
+ <b>PENALTY</b> <i>time</i> <b>for</b> <i>[address]:port</i>
</pre>
<p> During this time, all attempts by the client to deliver mail
on the number of commands and on the session length. </p>
<pre>
- <b>COMMAND TIME LIMIT</b> <b>from</b> <i>address</i>
+ <b>COMMAND TIME LIMIT</b> <b>from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-command time limit as specified with the postscreen_command_time_limit
parameter. The session is terminated immediately. </p>
<pre>
- <b>COMMAND COUNT LIMIT from</b> <i>address</i>
+ <b>COMMAND COUNT LIMIT from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-session command count limit as specified with the
postscreen_command_count_limit parameter. The session is terminated
immediately. </p>
<pre>
- <b>COMMAND LENGTH LIMIT from</b> <i>address</i>
+ <b>COMMAND LENGTH LIMIT from</b> <i>[address]:port</i>
</pre>
-<p> Translation: the SMTP client at <i>address</i> reached the
+<p> Translation: the SMTP client at <i>[address]:port</i> reached the
per-command length limit, as specified with the line_length_limit
parameter. The session is terminated immediately. </p>
+<p> When an SMTP client makes too many connections at the same time,
+or when all postscreen(8) ports are busy, postscreen(8) rejects the
+connection with a 421 status code and logs: </p>
+
+<pre>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: too many connections</b>
+ <b>NOQUEUE: reject: CONNECT from</b> <i>[address]:port</i><b>: all server ports busy</b>
+</pre>
+
+<p> The postscreen_client_connection_count_limit and
+postscreen_pre_queue_limit parameters control these limits. </p>
+
<h2> <a name="victory">When all tests succeed</a> </h2>
<p> When a new SMTP client passes all tests (i.e. it is not whitelisted
via some mechanism), postscreen(8) logs this as: </p>
<pre>
- <b>PASS NEW</b> <i>address</i>
+ <b>PASS NEW</b> <i>[address]:port</i>
</pre>
-<p> Where <i>address</i> is the client IP address. Then, postscreen(8)
+<p> Where <i>[address]:port</i> are the client IP address and port.
+Then, postscreen(8)
creates a temporary whitelist entry that excludes the client IP
address from further tests until the temporary whitelist entry
expires, as controlled with the postscreen_*_ttl parameters. </p>
<dd>Reject the request when the reversed client network address is
listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
-(Postfix version 2.1 and later only). Each "<i>d</i>" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "<i>d</i>" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "<i>=d.d.d.d</i>" is specified, reject the request when the
reversed client network address is listed with any A record under
<dd>Accept the request when the reversed client network address is
listed with the A record "<i>d.d.d.d</i>" under <i>dnswl_domain</i>.
-Each "<i>d</i>" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "<i>d</i>" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "<i>=d.d.d.d</i>" is specified, accept the request when the
reversed client network address is listed with any A record under
<i>dnswl_domain</i>. <br> For safety, permit_dnswl_client is silently
<dd>Reject the request when the client hostname is listed with the
A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix version
-2.1 and later only). Each "<i>d</i>" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "<i>d</i>" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified, reject the request when the client
hostname is listed with
<dd>Accept the request when the client hostname is listed with the
A record "<i>d.d.d.d</i>" under <i>rhswl_domain</i>. Each "<i>d</i>"
-can be a pattern inside "[]" that contains one or more comma-separated
-decimal numbers or number..number ranges. If no
+is a number, or a pattern inside "[]" that contains one or more
+comma-separated numbers or number..number ranges. If no
"<i>=d.d.d.d</i>" is specified, accept the request when the client
hostname is listed with any A record under <i>rhswl_domain</i>.
<br> Caution: client name whitelisting is fragile, since the client
<dd>Reject the request when the unverified reverse client hostname
is listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>.
-Each "<i>d</i>" can be a pattern inside "[]" that contains one or
-more comma-separated decimal numbers or number..number ranges.
+Each "<i>d</i>" is a number, or a pattern inside "[]" that contains
+one or more comma-separated numbers or number..number ranges.
If no "<i>=d.d.d.d</i>" is specified, reject the request when the
unverified reverse client hostname is listed with any A record under
<i>rbl_domain</i>. See the reject_rbl_client description above for
<dd>Search the specified access(5) database for the HELO or EHLO
hostname or parent domains, and execute the corresponding action.
-</dd>
+Note: specify "smtpd_helo_required = yes" to fully enforce this
+restriction. </dd>
<dt><b><a name="check_helo_mx_access">check_helo_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified access(5) database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later. </dd>
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "smtpd_helo_required = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
+</dd>
<dt><b><a name="check_helo_ns_access">check_helo_ns_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified access(5) database for the DNS servers
for the HELO or EHLO hostname, and execute the corresponding action.
-Note: a result of "OK" is not allowed for safety reasons. Instead,
-use DUNNO in order to exclude specific hosts from blacklists. This
-feature is available in Postfix 2.1 and later. </dd>
+Note 1: a result of "OK" is not allowed for safety reasons. Instead,
+use DUNNO in order to exclude specific hosts from blacklists. Note
+2: specify "smtpd_helo_required = yes" to fully enforce this
+restriction. This feature is available in Postfix 2.1 and later.
+</dd>
<dt><b><a name="reject_invalid_helo_hostname">reject_invalid_helo_hostname</a></b> (with Postfix < 2.3: reject_invalid_hostname)</dt>
<dd>Reject the request when the HELO or EHLO hostname syntax is
-invalid. <br> The invalid_hostname_reject_code specifies the response
-code for rejected requests (default: 501).</dd>
+invalid. Note: specify "smtpd_helo_required = yes" to fully enforce
+this restriction. <br> The invalid_hostname_reject_code specifies
+the response code for rejected requests (default: 501).</dd>
<dt><b><a name="reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a></b> (with Postfix < 2.3: reject_non_fqdn_hostname)</dt>
<dd>Reject the request when the HELO or EHLO hostname is not in
-fully-qualified domain form, as required by the RFC. <br> The
-non_fqdn_reject_code parameter specifies the response code for
+fully-qualified domain form, as required by the RFC. Note: specify
+"smtpd_helo_required = yes" to fully enforce this restriction. <br>
+The non_fqdn_reject_code parameter specifies the response code for
rejected requests (default: 504).</dd>
<dt><b><a name="reject_rhsbl_helo">reject_rhsbl_helo <i>rbl_domain=d.d.d.d</i></a></b></dt>
<dd>Reject the request when the HELO or EHLO hostname hostname is
listed with the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i>
-(Postfix version 2.1 and later only). Each "<i>d</i>" can be a
-pattern inside "[]" that contains one or more comma-separated decimal
+(Postfix version 2.1 and later only). Each "<i>d</i>" is a number,
+or a pattern inside "[]" that contains one or more comma-separated
numbers or number..number ranges (Postfix version 2.8 and later).
If no "<i>=d.d.d.d</i>" is
specified, reject the request when the HELO or EHLO hostname is
listed with any A record under <i>rbl_domain</i>. See the
reject_rbl_client description for additional RBL related configuration
-parameters. This feature is available in Postfix 2.0 and later.
-</dd>
+parameters. Note: specify "smtpd_helo_required = yes" to fully
+enforce this restriction. This feature is available in Postfix 2.0
+and later. </dd>
<dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix < 2.3: reject_unknown_hostname)</dt>
specifies the numerical response code for rejected requests (default:
450). <br> The unknown_helo_hostname_tempfail_action parameter
specifies the action after a temporary DNS error (default:
-defer_if_permit). </dd>
+defer_if_permit). Note: specify "smtpd_helo_required = yes" to fully
+enforce this restriction. </dd>
</dl>
<dd>Reject the request when the RCPT TO domain is listed with the
A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix version
-2.1 and later only). Each "<i>d</i>" can be a pattern inside "[]"
-that contains one or more comma-separated decimal numbers or
+2.1 and later only). Each "<i>d</i>" is a number, or a pattern
+inside "[]" that contains one or more comma-separated numbers or
number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified, reject
the request when the RCPT TO domain is listed with
<dd>Reject the request when the MAIL FROM domain is listed with
the A record "<i>d.d.d.d</i>" under <i>rbl_domain</i> (Postfix
-version 2.1 and later only). Each "<i>d</i>" can be a pattern
-inside "[]" that contains one or more comma-separated decimal numbers
+version 2.1 and later only). Each "<i>d</i>" is a number, or a
+pattern inside "[]" that contains one or more comma-separated numbers
or number..number ranges (Postfix version 2.8 and later). If no
"<i>=d.d.d.d</i>" is specified,
reject the request when the MAIL FROM domain is
<p> This feature is available in Postfix 2.8. </p>
+%PARAM postscreen_client_connection_count_limit $smtpd_client_connection_count_limit
+
+<p> How many simultaneous connections any client is allowed to have
+with the postscreen(8) daemon. By default, this limit is the same
+as with the Postfix SMTP server. Note that the triage process can
+take several seconds, with the time spent in postscreen_greet_wait
+delay, and with the time spent talking to the postscreen(8) built-in
+dummy SMTP protocol engine. </p>
+
+<p> This feature is available in Postfix 2.8. </p>
+
%PARAM dnsblog_reply_delay 0s
<p> A debugging aid to artifically delay DNS responses. </p>
#define DEF_PS_DISABLE_VRFY "$" VAR_DISABLE_VRFY_CMD
extern bool var_ps_disable_vrfy;
+#define VAR_PS_CCONN_LIMIT "postscreen_client_connection_count_limit"
+#define DEF_PS_CCONN_LIMIT "$" VAR_SMTPD_CCONN_LIMIT
+extern int var_ps_cconn_limit;
+
#define VAR_DNSBLOG_DELAY "dnsblog_reply_delay"
#define DEF_DNSBLOG_DELAY "0s"
extern int var_dnsblog_delay;
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20101126"
+#define MAIL_RELEASE_DATE "20101130"
#define MAIL_VERSION_NUMBER "2.8"
#ifdef SNAPSHOT
postscreen.o: ../../include/dict.h
postscreen.o: ../../include/dict_cache.h
postscreen.o: ../../include/events.h
+postscreen.o: ../../include/htable.h
postscreen.o: ../../include/iostuff.h
postscreen.o: ../../include/mail_conf.h
postscreen.o: ../../include/mail_params.h
postscreen_dict.o: ../../include/dict.h
postscreen_dict.o: ../../include/dict_cache.h
postscreen_dict.o: ../../include/events.h
+postscreen_dict.o: ../../include/htable.h
postscreen_dict.o: ../../include/match_list.h
postscreen_dict.o: ../../include/match_ops.h
postscreen_dict.o: ../../include/msg.h
postscreen_dnsbl.o: ../../include/match_list.h
postscreen_dnsbl.o: ../../include/match_ops.h
postscreen_dnsbl.o: ../../include/msg.h
+postscreen_dnsbl.o: ../../include/myaddrinfo.h
postscreen_dnsbl.o: ../../include/mymalloc.h
postscreen_dnsbl.o: ../../include/split_at.h
postscreen_dnsbl.o: ../../include/string_list.h
postscreen_early.o: ../../include/dict.h
postscreen_early.o: ../../include/dict_cache.h
postscreen_early.o: ../../include/events.h
+postscreen_early.o: ../../include/htable.h
postscreen_early.o: ../../include/mail_params.h
postscreen_early.o: ../../include/match_list.h
postscreen_early.o: ../../include/match_ops.h
postscreen_misc.o: ../../include/dict_cache.h
postscreen_misc.o: ../../include/events.h
postscreen_misc.o: ../../include/format_tv.h
+postscreen_misc.o: ../../include/htable.h
postscreen_misc.o: ../../include/iostuff.h
postscreen_misc.o: ../../include/mail_params.h
postscreen_misc.o: ../../include/match_list.h
postscreen_send.o: ../../include/dict.h
postscreen_send.o: ../../include/dict_cache.h
postscreen_send.o: ../../include/events.h
+postscreen_send.o: ../../include/htable.h
postscreen_send.o: ../../include/iostuff.h
postscreen_send.o: ../../include/match_list.h
postscreen_send.o: ../../include/match_ops.h
postscreen_smtpd.o: ../../include/dict.h
postscreen_smtpd.o: ../../include/dict_cache.h
postscreen_smtpd.o: ../../include/events.h
+postscreen_smtpd.o: ../../include/htable.h
postscreen_smtpd.o: ../../include/iostuff.h
postscreen_smtpd.o: ../../include/is_header.h
postscreen_smtpd.o: ../../include/mail_params.h
postscreen_state.o: ../../include/dict.h
postscreen_state.o: ../../include/dict_cache.h
postscreen_state.o: ../../include/events.h
+postscreen_state.o: ../../include/htable.h
postscreen_state.o: ../../include/iostuff.h
postscreen_state.o: ../../include/mail_proto.h
postscreen_state.o: ../../include/mail_server.h
postscreen_tests.o: ../../include/dict.h
postscreen_tests.o: ../../include/dict_cache.h
postscreen_tests.o: ../../include/events.h
+postscreen_tests.o: ../../include/htable.h
postscreen_tests.o: ../../include/mail_params.h
postscreen_tests.o: ../../include/match_list.h
postscreen_tests.o: ../../include/match_ops.h
/* .IP "\fBline_length_limit (2048)\fR"
/* Upon input, long lines are chopped up into pieces of at most
/* this length; upon delivery, long lines are reconstructed.
+/* .IP "\fBpostscreen_client_connection_count_limit ($smtpd_client_connection_count_limit)\fR"
+/* How many simultaneous connections any client is allowed to have
+/* with the \fBpostscreen\fR(8) daemon.
/* .IP "\fBpostscreen_command_count_limit (20)\fR"
/* The limit on the total number of commands per SMTP session for
/* \fBpostscreen\fR(8)'s built-in SMTP protocol engine.
int var_ps_cmd_count;
char *var_ps_cmd_time;
+int var_ps_cconn_limit;
+
/*
* Global variables.
*/
int ps_check_queue_length_lowat; /* stress low-water mark */
int ps_check_queue_length_hiwat; /* stress high-water mark */
DICT *ps_dnsbl_reply; /* DNSBL name mapper */
+HTABLE *ps_client_concurrency; /* per-client concurrency */
/*
* Local variables.
memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
sizeof(smtp_client_addr.buf) - 7);
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d connect from %s:%s",
+ msg_info("%s: sq=%d cq=%d connect from [%s]:%s",
myname, ps_post_queue_length, ps_check_queue_length,
smtp_client_addr.buf, smtp_client_port.buf);
- msg_info("CONNECT from %s", smtp_client_addr.buf);
+ msg_info("CONNECT from [%s]:%s", smtp_client_addr.buf, smtp_client_port.buf);
/*
* Bundle up all the loose session pieces. This zeroes all flags and time
state = ps_new_session_state(smtp_client_stream, smtp_client_addr.buf,
smtp_client_port.buf);
+ /*
+ * Reply with 421 when the client has too many open connections.
+ */
+ if (var_ps_cconn_limit > 0
+ && state->client_concurrency > var_ps_cconn_limit) {
+ msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: too many connections",
+ state->smtp_client_addr, state->smtp_client_port);
+ PS_DROP_SESSION_STATE(state,
+ "421 4.7.0 Error: too many connections\r\n");
+ return;
+ }
+
/*
* Reply with 421 when we can't forward more connections.
*/
if (var_ps_post_queue_limit > 0
&& ps_post_queue_length >= var_ps_post_queue_limit) {
- msg_info("reject: connect from %s:%s: all server ports busy",
+ msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: all server ports busy",
state->smtp_client_addr, state->smtp_client_port);
PS_DROP_SESSION_STATE(state,
"421 4.3.2 All server ports are busy\r\n");
*/
if (ps_wlist_nets != 0
&& ps_addr_match_list_match(ps_wlist_nets, state->smtp_client_addr)) {
- msg_info("WHITELISTED %s", state->smtp_client_addr);
+ msg_info("WHITELISTED [%s]:%s", PS_CLIENT_ADDR_PORT(state));
ps_conclude(state);
return;
}
*/
if (ps_blist_nets != 0
&& ps_addr_match_list_match(ps_blist_nets, state->smtp_client_addr)) {
- msg_info("BLACKLISTED %s", state->smtp_client_addr);
+ msg_info("BLACKLISTED [%s]:%s", PS_CLIENT_ADDR_PORT(state));
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_BLIST_FAIL);
switch (ps_blist_action) {
case PS_ACT_DROP:
msg_info("%s: cached + recent flags: %s",
myname, ps_print_state_flags(state->flags, myname));
if ((state->flags & PS_STATE_MASK_ANY_TODO_FAIL) == 0) {
- msg_info("PASS OLD %s", state->smtp_client_addr);
+ msg_info("PASS OLD [%s]:%s", PS_CLIENT_ADDR_PORT(state));
ps_conclude(state);
return;
}
*/
if (var_ps_pre_queue_limit > 0
&& ps_check_queue_length - ps_post_queue_length >= var_ps_pre_queue_limit) {
- msg_info("reject: connect from %s:%s: all screening ports busy",
+ msg_info("reject: connect from [%s]:%s: all screening ports busy",
state->smtp_client_addr, state->smtp_client_port);
PS_DROP_SESSION_STATE(state,
"421 4.3.2 All screening ports are busy\r\n");
msg_info(VAR_PS_CMD_TIME ": stress=%d normal=%d lowat=%d hiwat=%d",
ps_stress_cmd_time_limit, ps_normal_cmd_time_limit,
ps_check_queue_length_lowat, ps_check_queue_length_hiwat);
+
+ /*
+ * Per-client concurrency.
+ */
+ ps_client_concurrency = htable_create(var_ps_pre_queue_limit);
}
MAIL_VERSION_STAMP_DECLARE;
static const CONFIG_NINT_TABLE nint_table[] = {
VAR_PS_POST_QLIMIT, DEF_PS_POST_QLIMIT, &var_ps_post_queue_limit, 5, 0,
VAR_PS_PRE_QLIMIT, DEF_PS_PRE_QLIMIT, &var_ps_pre_queue_limit, 10, 0,
+ VAR_PS_CCONN_LIMIT, DEF_PS_CCONN_LIMIT, &var_ps_cconn_limit, 0, 0,
0,
};
static const CONFIG_TIME_TABLE time_table[] = {
#include <vstream.h>
#include <vstring.h>
#include <events.h>
+#include <htable.h>
/*
* Global library.
int smtp_server_fd; /* real SMTP server */
char *smtp_client_addr; /* client address */
char *smtp_client_port; /* client port */
+ int client_concurrency; /* per-client */
const char *final_reply; /* cause for hanging up */
/* Test context. */
struct timeval start_time; /* start of current test */
extern int ps_check_queue_length_lowat; /* stress low-water mark */
extern int ps_check_queue_length_hiwat; /* stress high-water mark */
extern DICT *ps_dnsbl_reply; /* DNSBL name mapper */
+extern HTABLE *ps_client_concurrency; /* per-client concurrency */
#define PS_EFF_GREET_WAIT \
(ps_stress ? ps_stress_greet_wait : ps_normal_greet_wait)
#define PS_PASS_SESSION_STATE(state, what, bits) do { \
if (msg_verbose) \
- msg_info("PASS %s %s:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("PASS %s [%s]:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
(state)->flags |= (bits); \
} while (0)
#define PS_FAIL_SESSION_STATE(state, bits) do { \
if (msg_verbose) \
- msg_info("FAIL %s:%s", PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("FAIL [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
(state)->flags |= (bits); \
} while (0)
#define PS_SKIP_SESSION_STATE(state, what, bits) do { \
if (msg_verbose) \
- msg_info("SKIP %s %s:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("SKIP %s [%s]:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
(state)->flags |= (bits); \
} while (0)
#define PS_DROP_SESSION_STATE(state, reply) do { \
if (msg_verbose) \
- msg_info("DROP %s:%s", PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("DROP [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
(state)->flags |= PS_STATE_FLAG_NOFORWARD; \
(state)->final_reply = (reply); \
ps_conclude(state); \
} while (0)
#define PS_ENFORCE_SESSION_STATE(state, reply) do { \
if (msg_verbose) \
- msg_info("ENFORCE %s:%s", PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("ENFORCE [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
(state)->rcpt_reply = (reply); \
(state)->flags |= PS_STATE_FLAG_NOFORWARD; \
} while (0)
#define PS_UNPASS_SESSION_STATE(state, bits) do { \
if (msg_verbose) \
- msg_info("UNPASS %s:%s", PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("UNPASS [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
(state)->flags &= ~(bits); \
} while (0)
#define PS_UNFAIL_SESSION_STATE(state, bits) do { \
if (msg_verbose) \
- msg_info("UNFAIL %s:%s", PS_CLIENT_ADDR_PORT(state)); \
+ msg_info("UNFAIL [%s]:%s", PS_CLIENT_ADDR_PORT(state)); \
(state)->flags &= ~(bits); \
} while (0)
#define PS_ADD_SERVER_STATE(state, fd) do { \
} PS_DNSBL_HEAD;
typedef struct PS_DNSBL_SITE {
- char *filter; /* reply filter (default: null) */
+ char *filter; /* printable filter (default: null) */
+ char *byte_codes; /* encoded filter (default: null) */
int weight; /* reply weight (default: 1) */
struct PS_DNSBL_SITE *next; /* linked list */
} PS_DNSBL_SITE;
PS_DNSBL_SITE *new_site;
char junk;
const char *weight_text;
- char *pattern_text;
+ char *pattern_text;
int weight;
HTABLE_INFO *ht;
char *parse_err;
* name.
*/
new_site = (PS_DNSBL_SITE *) mymalloc(sizeof(*new_site));
- new_site->filter = (pattern_text ? ip_match_save(byte_codes) : 0);
+ new_site->filter = (pattern_text ? mystrdup(pattern_text) : 0);
+ new_site->byte_codes = (byte_codes ? ip_match_save(byte_codes) : 0);
new_site->weight = weight;
new_site->next = head->first;
head->first = new_site;
htable_find(dnsbl_site_cache, STR(reply_dnsbl));
site = (head ? head->first : (PS_DNSBL_SITE *) 0);
for (reply_argv = 0; site != 0; site = site->next) {
- if (site->filter == 0
- || ps_dnsbl_match(site->filter, reply_argv ? reply_argv :
+ if (site->byte_codes == 0
+ || ps_dnsbl_match(site->byte_codes, reply_argv ? reply_argv :
(reply_argv = argv_split(STR(reply_addr), " ")))) {
if (score->dnsbl == 0)
score->dnsbl = head->safe_dnsbl;
const char *dnsbl_name;
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from %s:%s flags=%s",
+ msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
myname, ps_post_queue_length, ps_check_queue_length,
event, vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
PS_PASS_SESSION_STATE(state, "dnsbl test",
PS_STATE_FLAG_DNSBL_PASS);
} else {
- msg_info("DNSBL rank %d for %s",
- dnsbl_score, state->smtp_client_addr);
+ msg_info("DNSBL rank %d for [%s]:%s",
+ dnsbl_score, PS_CLIENT_ADDR_PORT(state));
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_DNSBL_FAIL);
switch (ps_dnsbl_action) {
case PS_ACT_DROP:
return;
}
read_buf[read_count] = 0;
- msg_info("PREGREET %d after %s from %s: %.100s", read_count,
+ msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count,
ps_format_delta_time(ps_temp, state->start_time, &elapsed),
- state->smtp_client_addr, printable(read_buf, '?'));
+ PS_CLIENT_ADDR_PORT(state), printable(read_buf, '?'));
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_PREGR_FAIL);
switch (ps_pregr_action) {
case PS_ACT_DROP:
PS_STATE *state = (PS_STATE *) context;
if (msg_verbose)
- msg_info("%s: notify %s:%s", myname, PS_CLIENT_ADDR_PORT(state));
+ msg_info("%s: notify [%s]:%s", myname, PS_CLIENT_ADDR_PORT(state));
/*
* Terminate the greet delay if we're just waiting for DNSBL lookup to
if ((state->flags & PS_STATE_MASK_ANY_PASS) != 0
&& (state->flags & PS_STATE_MASK_ANY_PASS) ==
PS_STATE_FLAGS_TODO_TO_PASS(state->flags & PS_STATE_MASK_ANY_TODO))
- msg_info("PASS %s %s", (state->flags & PS_STATE_FLAG_NEW) == 0 ?
- "OLD" : "NEW", state->smtp_client_addr);
+ msg_info("PASS %s [%s]:%s", (state->flags & PS_STATE_FLAG_NEW) == 0 ?
+ "OLD" : "NEW", PS_CLIENT_ADDR_PORT(state));
/*
* Update the postscreen cache. This still supports a scenario where a
(void) ps_send_reply(vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
state->final_reply);
- msg_info("DISCONNECT %s", state->smtp_client_addr);
+ msg_info("DISCONNECT [%s]:%s", PS_CLIENT_ADDR_PORT(state));
ps_free_session_state(state);
}
}
* phase.
*/
state->flags |= PS_STATE_FLAG_HANGUP;
- msg_info("HANGUP after %s from %s in %s",
+ msg_info("HANGUP after %s from [%s]:%s in %s",
ps_format_delta_time(ps_temp, state->start_time, &elapsed),
- state->smtp_client_addr, state->test_name);
+ PS_CLIENT_ADDR_PORT(state), state->test_name);
state->flags |= PS_STATE_FLAG_NOFORWARD;
ps_conclude(state);
}
int ret;
if (msg_verbose)
- msg_info("> %s:%s: %.*s", smtp_client_addr, smtp_client_port,
+ msg_info("> [%s]:%s: %.*s", smtp_client_addr, smtp_client_port,
(int) strlen(text) - 2, text);
/*
ret = (write_buf(smtp_client_fd, text, strlen(text),
PS_SEND_TEXT_TIMEOUT) < 0);
if (ret != 0 && errno != EPIPE)
- msg_warn("write %s:%s: %m", smtp_client_addr, smtp_client_port);
+ msg_warn("write [%s]:%s: %m", smtp_client_addr, smtp_client_port);
return (ret);
}
PS_STATE *state = (PS_STATE *) context;
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d event %d on send socket %d from %s:%s",
+ msg_info("%s: sq=%d cq=%d event %d on send socket %d from [%s]:%s",
myname, ps_post_queue_length, ps_check_queue_length,
event, state->smtp_server_fd, state->smtp_client_addr,
state->smtp_client_port);
int window_size;
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d send socket %d from %s:%s",
+ msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
myname, ps_post_queue_length, ps_check_queue_length,
vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port);
if ((addr = ps_extract_addr(ps_temp, colon + 1)) == 0)
return (PS_SEND_REPLY(state,
"501 5.1.3 Bad recipient address syntax\r\n"));
- msg_info("NOQUEUE: reject: RCPT from [%s]: %.*s; "
+ msg_info("NOQUEUE: reject: RCPT from [%s]:%s: %.*s; "
"from=<%s>, to=<%s>, proto=%s, helo=<%s>",
- state->smtp_client_addr,
+ PS_CLIENT_ADDR_PORT(state),
(int) strlen(state->rcpt_reply) - 2, state->rcpt_reply,
state->sender, addr, state->protocol,
state->helo_name ? state->helo_name : "");
PS_STATE *state = (PS_STATE *) context;
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from %s:%s flags=%s",
+ msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
myname, ps_post_queue_length, ps_check_queue_length,
event, vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
ps_print_state_flags(state->flags, myname));
- msg_info("COMMAND TIME LIMIT from %s", state->smtp_client_addr);
+ msg_info("COMMAND TIME LIMIT from [%s]:%s", PS_CLIENT_ADDR_PORT(state));
PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
ps_smtpd_timeout_reply);
}
int write_stat;
if (msg_verbose > 1)
- msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from %s:%s flags=%s",
+ msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
myname, ps_post_queue_length, ps_check_queue_length,
event, vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
*/
if (state->read_state == PS_SMTPD_CMD_ST_ANY
&& VSTRING_LEN(state->cmd_buffer) >= var_line_limit) {
- msg_info("COMMAND LENGTH LIMIT from %s",
- state->smtp_client_addr);
+ msg_info("COMMAND LENGTH LIMIT from [%s]:%s",
+ PS_CLIENT_ADDR_PORT(state));
PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
ps_smtpd_421_reply);
return;
if (ch == '\n') {
if ((state->flags & PS_STATE_MASK_BARLF_TODO_SKIP)
== PS_STATE_FLAG_BARLF_TODO) {
- msg_info("BARE NEWLINE from %s", state->smtp_client_addr);
+ msg_info("BARE NEWLINE from [%s]:%s",
+ PS_CLIENT_ADDR_PORT(state));
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_BARLF_FAIL);
PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_BARLF_PASS);
state->barlf_stamp = PS_TIME_STAMP_DISABLED; /* XXX */
*/
cmd_buffer_ptr = vstring_str(state->cmd_buffer);
if (msg_verbose)
- msg_info("< %s:%s: %s", state->smtp_client_addr,
+ msg_info("< [%s]:%s: %s", state->smtp_client_addr,
state->smtp_client_port, cmd_buffer_ptr);
/* Parse the command name. */
|| (*var_ps_forbid_cmds
&& string_list_match(ps_forbid_cmds, command)))) {
printable(command, '?');
- msg_info("NON-SMTP COMMAND from %s %.100s",
- state->smtp_client_addr, command);
+ msg_info("NON-SMTP COMMAND from [%s]:%s %.100s",
+ PS_CLIENT_ADDR_PORT(state), command);
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_NSMTP_FAIL);
PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_NSMTP_PASS);
state->nsmtp_stamp = PS_TIME_STAMP_DISABLED; /* XXX */
if ((state->flags & PS_STATE_MASK_PIPEL_TODO_SKIP)
== PS_STATE_FLAG_PIPEL_TODO && !PS_SMTPD_BUFFER_EMPTY(state)) {
printable(command, '?');
- msg_info("COMMAND PIPELINING from %s after %.100s",
- state->smtp_client_addr, command);
+ msg_info("COMMAND PIPELINING from [%s]:%s after %.100s",
+ PS_CLIENT_ADDR_PORT(state), command);
PS_FAIL_SESSION_STATE(state, PS_STATE_FLAG_PIPEL_FAIL);
PS_UNPASS_SESSION_STATE(state, PS_STATE_FLAG_PIPEL_PASS);
state->pipel_stamp = PS_TIME_STAMP_DISABLED; /* XXX */
/* Command COUNT limit test. */
if (++state->command_count > var_ps_cmd_count
&& cmdp->action != ps_quit_cmd) {
- msg_info("COMMAND COUNT LIMIT from %s", state->smtp_client_addr);
+ msg_info("COMMAND COUNT LIMIT from [%s]:%s",
+ PS_CLIENT_ADDR_PORT(state));
PS_CLEAR_EVENT_DROP_SESSION_STATE(state, ps_smtpd_time_event,
ps_smtpd_421_reply);
return;
#include <msg.h>
#include <mymalloc.h>
#include <name_mask.h>
+#include <htable.h>
/* Global library. */
const char *port)
{
PS_STATE *state;
+ HTABLE_INFO *ht;
state = (PS_STATE *) mymalloc(sizeof(*state));
PS_INIT_TESTS(state);
msg_info("entering STRESS mode with %d connections",
ps_check_queue_length);
}
+
+ /*
+ * Update the per-client session count.
+ */
+ if ((ht = htable_locate(ps_client_concurrency, addr)) == 0)
+ ht = htable_enter(ps_client_concurrency, addr, (char *) 0);
+ ht->value += 1;
+ state->client_concurrency = (int) ht->value;
+
return (state);
}
void ps_free_session_state(PS_STATE *state)
{
+ const char *myname = "ps_free_session_state";
+ HTABLE_INFO *ht;
+
+ /*
+ * Update the per-client session count.
+ */
+ if ((ht = htable_locate(ps_client_concurrency, state->smtp_client_addr)) == 0)
+ msg_panic("%s: unknown client address: %s",
+ myname, state->smtp_client_addr);
+ if (--(ht->value) == 0)
+ htable_delete(ps_client_concurrency, state->smtp_client_addr, (void (*) (char *)) 0);
+
if (state->smtp_client_stream != 0) {
event_server_disconnect(state->smtp_client_stream);
ps_check_queue_length--;
const char *stamp_str,
time_t time_value)
{
- const char *myname = "ps_parse_tests";
unsigned long pregr_stamp;
unsigned long dnsbl_stamp;
unsigned long pipel_stamp;
allascii.c load_file.c killme_after.c vstream_tweak.c upass_connect.c \
upass_listen.c upass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
- ip_match.c ip_lmatch.c
+ ip_match.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
allascii.o load_file.o killme_after.o vstream_tweak.o upass_connect.o \
upass_listen.o upass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
- ip_match.o ip_lmatch.o
+ ip_match.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \
vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \
edit_file.h dict_cache.h dict_thash.h \
- ip_match.h ip_lmatch.h
+ ip_match.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c test_send_fd test_recv_fd
DEFS = -I. -D$(SYSTYPE)
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
- test_send_fd test_recv_fd valid_utf_8 ip_match ip_lmatch
+ test_send_fd test_recv_fd valid_utf_8 ip_match
LIB_DIR = ../../lib
INC_DIR = ../../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-ip_lmatch: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
-
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
dict_cidr_test attr_scan_plain_test htable_test hex_code_test \
- myaddrinfo_test format_tv_test ip_match_test ip_lmatch_test
+ myaddrinfo_test format_tv_test ip_match_test
root_tests:
diff ip_match.ref ip_match.tmp
rm -f ip_match.tmp
-ip_lmatch_test: ip_lmatch ip_lmatch.in ip_lmatch.ref
- ./ip_lmatch <ip_lmatch.in >ip_lmatch.tmp
- diff ip_lmatch.ref ip_lmatch.tmp
- rm -f ip_lmatch.tmp
-
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
ip_match.o: sys_defs.h
ip_match.o: vbuf.h
ip_match.o: vstring.h
-ip_lmatch.o: ip_lmatch.c
-ip_lmatch.o: ip_lmatch.h
-ip_lmatch.o: msg.h
-ip_lmatch.o: mymalloc.h
-ip_lmatch.o: sys_defs.h
-ip_lmatch.o: vbuf.h
-ip_lmatch.o: vstring.h
killme_after.o: killme_after.c
killme_after.o: killme_after.h
killme_after.o: sys_defs.h
+++ /dev/null
-/*++
-/* NAME
-/* ip_lmatch 3
-/* SUMMARY
-/* lazy IP address pattern matching
-/* SYNOPSIS
-/* #include <ip_lmatch.h>
-/*
-/* int ip_lmatch(pattern, addr, why)
-/* char *pattern;
-/* const char *addr;
-/* VSTRING **why;
-/* DESCRIPTION
-/* This module supports IP address pattern matching. See below
-/* for a description of the supported address pattern syntax.
-/*
-/* This version optimizes for implementation convenience. The
-/* lazy parser stops as soon as the address does not match the
-/* pattern. This results in a poor user interface: a pattern
-/* syntax error at the end will be reported ONLY when an address
-/* matches the entire pattern before the syntax error.
-/*
-/* Use the ip_match() module for an implementation that has
-/* separate parsing and matching stages. That implementation
-/* reports a syntax error immediately, and provides faster
-/* matching at the cost of a more complex programming interface.
-/*
-/* ip_lmatch_parse() matches the address bytes while parsing
-/* the pattern, and terminates as soon as a non-match or syntax
-/* error is found. The result is -1 in case of syntax error,
-/* 0 in case of no match, 1 in case of a match.
-/*
-/* Arguments
-/* .IP addr
-/* Network address in printable form.
-/* .IP pattern
-/* Address pattern. This argument may be modified.
-/* .IP why
-/* Pointer to storage for error reports (result value -1). If
-/* the target is a null pointer, ip_lmatch() will allocate a
-/* buffer that should be freed by the application.
-/* IPV4 PATTERN SYNTAX
-/* .ad
-/* .fi
-/* An IPv4 address pattern has four fields separated by ".".
-/* Each field is either a decimal number, or a sequence inside
-/* "[]" that contains one or more comma-separated decimal
-/* numbers or number..number ranges.
-/*
-/* Examples of patterns are 1.2.3.4 (matches itself, as one
-/* would expect) and 1.2.3.[2,4,6..8] (matches 1.2.3.2, 1.2.3.4,
-/* 1.2.3.6, 1.2.3.7, 1.2.3.8).
-/*
-/* Thus, any pattern field can be a sequence inside "[]", but
-/* a "[]" sequence cannot span multiple address fields, and
-/* a pattern field cannot contain both a number and a "[]"
-/* sequence at the same time.
-/*
-/* This means that the pattern 1.2.[3.4] is not valid (the
-/* sequence [3.4] cannot span two address fields) and the
-/* pattern 1.2.3.3[6..9] is also not valid (the last field
-/* cannot be both number 3 and sequence [6..9] at the same
-/* time).
-/*
-/* The syntax for IPv4 patterns is as follows:
-/*
-/* .in +5
-/* v4pattern = v4field "." v4field "." v4field "." v4field
-/* .br
-/* v4field = v4octet | "[" v4sequence "]
-/* .br
-/* v4octet = any decimal number in the range 0 through 255
-/* .br
-/* v4sequence = v4seq_member | v4sequence "," v4seq_member
-/* .br
-/* v4seq_member = v4octet | v4octet ".." v4octet
-/* .in
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this
-/* software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <vstring.h>
-#include <myaddrinfo.h>
-#include <ip_lmatch.h>
-
- /*
- * Token values.
- */
-#define IP_LMATCH_CODE_OPEN '[' /* start of set */
-#define IP_LMATCH_CODE_CLOSE ']' /* end of set */
-#define IP_LMATCH_CODE_OVAL 'N' /* octet value */
-#define IP_LMATCH_CODE_EOF '\0' /* oops */
-#define IP_LMATCH_CODE_ERR 256 /* oops */
-
- /*
- * Address length is protocol dependent. Find out how large our address byte
- * strings should be.
- */
-#ifdef HAS_IPV6
-#define IP_LMATCH_ABYTES MAI_V6ADDR_BYTES
-#else
-#define IP_LMATCH_ABYTES MAI_V4ADDR_BYTES
-#endif
-
- /*
- * SLMs.
- */
-#define STR vstring_str
-#define LEN VSTRING_LEN
-
-/* ip_lmatch_next_token - carve out the next token from user input */
-
-static int ip_lmatch_next_token(char **pstart, char **psaved_start, int *poval)
-{
- unsigned char *cp;
- unsigned char *next;
- int oval;
-
- /*
- * Return a value-less token (i.e. a literal, error, or EOF.
- */
-#define IP_LMATCH_RETURN_TOK(next, type) \
- do { *pstart = (char *) (next); return (type); } while (0)
-
- /*
- * Return a token that contains an IPv4 address octet value.
- */
-#define IP_LMATCH_RETURN_TOK_OVAL(next, oval) do { \
- *poval = (oval); IP_LMATCH_RETURN_TOK((next), IP_LMATCH_CODE_OVAL); \
- } while (0)
-
- /*
- * Light-weight tokenizer. Each result is an IPv4 address octet value, a
- * literal character value, error, or EOF.
- */
- *psaved_start = *pstart;
- cp = (unsigned char *) *pstart;
- if (ISDIGIT(*cp)) {
- oval = *cp - '0';
- for (next = cp + 1; ISDIGIT(*next); next++) {
- oval *= 10;
- oval += *next - '0';
- if (oval > 255)
- IP_LMATCH_RETURN_TOK(next + 1, IP_LMATCH_CODE_ERR);
- }
- IP_LMATCH_RETURN_TOK_OVAL(next, oval);
- } else {
- IP_LMATCH_RETURN_TOK(*cp ? cp + 1 : cp, *cp);
- }
-}
-
-/* ip_lmatch_print_parse_error - report parsing error in context */
-
-static void PRINTFLIKE(5, 6) ip_lmatch_print_parse_error(VSTRING **why,
- char *start,
- char *here,
- char *next,
- const char *fmt,...)
-{
- va_list ap;
- int start_width;
- int here_width;
-
- /*
- * On-the-fly allocation.
- */
- if (*why == 0)
- *why = vstring_alloc(20);
-
- /*
- * Format the error type.
- */
- va_start(ap, fmt);
- vstring_vsprintf(*why, fmt, ap);
- va_end(ap);
-
- /*
- * Format the error context. The syntax is complex enough that it is
- * worth the effort to precisely indicate what input is in error.
- *
- * XXX Workaround for %.*s to avoid output when a zero width is specified.
- */
-#define IP_LMATCH_NO_ERROR_CONTEXT (char *) 0, (char *) 0, (char *) 0
-
- if (start != 0) {
- start_width = here - start;
- here_width = next - here;
- vstring_sprintf_append(*why, " at \"%.*s>%.*s<%s\"",
- start_width, start_width == 0 ? "" : start,
- here_width, here_width == 0 ? "" : here, next);
- }
-}
-
-/* ip_lmatch - match an address pattern */
-
-int ip_lmatch(char *pattern, const char *addr, VSTRING **why)
-{
- const char *myname = "ip_lmatch";
- char addr_bytes[IP_LMATCH_ABYTES];
- const unsigned char *ap;
- int octet_count;
- char *saved_cp;
- char *cp;
- int token_type;
- int look_ahead;
- int oval;
- int saved_oval;
- int matched;
-
- /*
- * For now, IPv4 support only. Use different parser loops for IPv4 and
- * IPv6.
- */
- switch (inet_pton(AF_INET, addr, addr_bytes)) {
- case -1:
- msg_fatal("%s: address conversion error: %m", myname);
- case 0:
- msg_warn("%s: unexpected address form: %s", myname, addr);
- return (0);
- }
-
- /*
- * Simplify this if we change to {} for "octet set" notation.
- */
-#define FIND_TERMINATOR(start, cp) do { \
- int _level = 1; \
- for (cp = (start) ; *cp; cp++) { \
- if (*cp == '[') _level++; \
- if (*cp != ']') continue; \
- if (--_level == 0) break; \
- } \
- } while (0)
-
- /*
- * Strip [] around the entire pattern.
- */
- if (*pattern == '[') {
- FIND_TERMINATOR(pattern, cp);
- if (cp[0] == 0) {
- ip_lmatch_print_parse_error(why, IP_LMATCH_NO_ERROR_CONTEXT,
- "missing \"]\" character");
- return (-1);
- }
- if (cp[1] == 0) {
- *cp = 0;
- pattern += 1;
- }
- }
-
- /*
- * Sanity check. In this case we can't show any error context.
- */
- if (*pattern == 0) {
- ip_lmatch_print_parse_error(why, IP_LMATCH_NO_ERROR_CONTEXT,
- "empty address pattern");
- return (-1);
- }
-
- /*
- * Simple on-the-fly pattern matching.
- */
- octet_count = 0;
- cp = pattern;
-
- /*
- * Require four address fields separated by ".", each field containing a
- * numeric octet value or a sequence inside []. The loop head has no test
- * and does not step the loop variable. The tokenizer advances the loop
- * variable, and the loop termination logic is inside the loop.
- */
- for (ap = (const unsigned char *) addr_bytes; /* void */ ; ap++) {
- switch (token_type = ip_lmatch_next_token(&cp, &saved_cp, &oval)) {
-
- /*
- * Numeric address field.
- */
- case IP_LMATCH_CODE_OVAL:
- if (*ap == oval)
- break;
- return (0);
-
- /*
- * Wild-card address field.
- */
- case IP_LMATCH_CODE_OPEN:
- matched = 0;
- /* Require comma-separated numbers or numeric ranges. */
- for (;;) {
- token_type = ip_lmatch_next_token(&cp, &saved_cp, &oval);
- if (token_type == IP_LMATCH_CODE_OVAL) {
- saved_oval = oval;
- look_ahead = ip_lmatch_next_token(&cp, &saved_cp, &oval);
- /* Numeric range. */
- if (look_ahead == '.') {
- /* Brute-force parsing. */
- if (ip_lmatch_next_token(&cp, &saved_cp, &oval) == '.'
- && ip_lmatch_next_token(&cp, &saved_cp, &oval)
- == IP_LMATCH_CODE_OVAL
- && saved_oval <= oval) {
- if (!matched)
- matched = (*ap >= saved_oval && *ap <= oval);
- look_ahead =
- ip_lmatch_next_token(&cp, &saved_cp, &oval);
- } else {
- ip_lmatch_print_parse_error(why, pattern,
- saved_cp, cp,
- "numeric range error");
- return (-1);
- }
- }
- /* Single number. */
- else {
- if (!matched)
- matched = (*ap == oval);
- }
- /* Require "," or end-of-wildcard. */
- token_type = look_ahead;
- if (token_type == ',') {
- continue;
- } else if (token_type == IP_LMATCH_CODE_CLOSE) {
- break;
- } else {
- ip_lmatch_print_parse_error(why, pattern, saved_cp, cp,
- "need \",\" or \"%c\"",
- IP_LMATCH_CODE_CLOSE);
- return (-1);
- }
- } else {
- ip_lmatch_print_parse_error(why, pattern, saved_cp, cp,
- "need decimal number 0..255");
- return (-1);
- }
- }
- if (matched == 0)
- return (0);
- break;
-
- /*
- * Invalid field.
- */
- default:
- ip_lmatch_print_parse_error(why, pattern, saved_cp, cp,
- "need decimal number 0..255 or \"%c\"",
- IP_LMATCH_CODE_OPEN);
- return (-1);
- }
- octet_count += 1;
-
- /*
- * Require four address fields. Not one more, not one less.
- */
- if (octet_count == 4) {
- if (*cp != 0) {
- (void) ip_lmatch_next_token(&cp, &saved_cp, &oval);
- ip_lmatch_print_parse_error(why, pattern, saved_cp, cp,
- "garbage after pattern");
- return (-1);
- }
- return (1);
- }
-
- /*
- * Require "." before the next address field.
- */
- if (ip_lmatch_next_token(&cp, &saved_cp, &oval) != '.') {
- ip_lmatch_print_parse_error(why, pattern, saved_cp, cp,
- "need \".\"");
- return (-1);
- }
- }
-}
-
-#ifdef TEST
-
- /*
- * Dummy main program for regression tests.
- */
-#include <sys/socket.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <stringops.h>
-
-int main(int argc, char **argv)
-{
- VSTRING *why = vstring_alloc(100);
- VSTRING *line_buf = vstring_alloc(100);
- char *bufp;
- char *user_pattern;
- char *user_address;
- int echo_input = !isatty(0);
- int match_status;
-
- /*
- * Iterate over the input stream. The input format is a pattern, followed
- * by addresses to match against.
- */
- while (vstring_fgets_nonl(line_buf, VSTREAM_IN)) {
- bufp = STR(line_buf);
- if (echo_input) {
- vstream_printf("> %s\n", bufp);
- vstream_fflush(VSTREAM_OUT);
- }
- if (*bufp == '#')
- continue;
- if ((user_pattern = mystrtok(&bufp, " \t")) == 0)
- continue;
-
- /*
- * Match the patterns.
- */
- while ((user_address = mystrtok(&bufp, " \t")) != 0) {
- match_status = ip_lmatch(user_pattern, user_address, &why);
- if (match_status < 0) {
- vstream_printf("Error: %s\n", STR(why));
- } else {
- vstream_printf("Match %s: %s\n", user_address,
- match_status ? "yes" : "no");
- }
- vstream_fflush(VSTREAM_OUT);
- }
- }
- vstring_free(line_buf);
- vstring_free(why);
- exit(0);
-}
-
-#endif
+++ /dev/null
-#ifndef _IP_LMATCH_H_INCLUDED_
-#define _IP_LMATCH_H_INCLUDED_
-
-/*++
-/* NAME
-/* ip_lmatch 3h
-/* SUMMARY
-/* lazy IP address pattern matching
-/* SYNOPSIS
-/* #include <ip_lmatch.h>
-/* DESCRIPTION
-/* .nf
-
- /*
- * Utility library.
- */
-#include <vstring.h>
-
- /*
- * External interface.
- */
-extern int ip_lmatch(char *, const char *, VSTRING **);
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-#endif
+++ /dev/null
-1.2.3.4 1.2.3.4
-1.2.300.4 1.2.3.4
-1.2.3. 1.2.3.4
-1.2.3 1.2.3.4
-a 1.2.3.4
-1.2.3,4 1.2.3.4
-1.2.[3].4 1.2.3.4
-1.2.[].4 1.2.3.4
-1.2.[.4 1.2.3.4
-1.2.].4 1.2.3.4
-1.2.[1..127,128..255].5 1.2.3.4
-1.2.[1-255].5 1.2.3.4
-1.2.[1..127.128..255].5 1.2.3.4
-1.2.3.[4] 1.2.3.4
-1.2.3.[4..1] 1.2.3.4
-1.2.3.[4.1] 1.2.3.4
-1.2.3.[4.x] 1.2.3.4
-1.2.3.[x] 1.2.3.4
-1.2.3.4x 1.2.3.4
-1.2.[3..11].5 1.2.3.5 1.2.2.5 1.2.11.5 1.2.12.5 1.2.11.6
-1.2.[3,5,7,9,11].5 1.2.3.5 1.2.2.5 1.2.4.5 1.2.11.5 1.2.12.5 1.2.11.6
+++ /dev/null
-> 1.2.3.4 1.2.3.4
-Match 1.2.3.4: yes
-> 1.2.300.4 1.2.3.4
-Error: need decimal number 0..255 or "[" at "1.2.>300<.4"
-> 1.2.3. 1.2.3.4
-Error: need decimal number 0..255 or "[" at "1.2.3.><"
-> 1.2.3 1.2.3.4
-Error: need "." at "1.2.3><"
-> a 1.2.3.4
-Error: need decimal number 0..255 or "[" at ">a<"
-> 1.2.3,4 1.2.3.4
-Error: need "." at "1.2.3>,<4"
-> 1.2.[3].4 1.2.3.4
-Match 1.2.3.4: yes
-> 1.2.[].4 1.2.3.4
-Error: need decimal number 0..255 at "1.2.[>]<.4"
-> 1.2.[.4 1.2.3.4
-Error: need decimal number 0..255 at "1.2.[>.<4"
-> 1.2.].4 1.2.3.4
-Error: need decimal number 0..255 or "[" at "1.2.>]<.4"
-> 1.2.[1..127,128..255].5 1.2.3.4
-Match 1.2.3.4: no
-> 1.2.[1-255].5 1.2.3.4
-Error: need "," or "]" at "1.2.[1>-<255].5"
-> 1.2.[1..127.128..255].5 1.2.3.4
-Error: need "," or "]" at "1.2.[1..127>.<128..255].5"
-> 1.2.3.[4] 1.2.3.4
-Match 1.2.3.4: yes
-> 1.2.3.[4..1] 1.2.3.4
-Error: numeric range error at "1.2.3.[4..>1<]"
-> 1.2.3.[4.1] 1.2.3.4
-Error: numeric range error at "1.2.3.[4.>1<]"
-> 1.2.3.[4.x] 1.2.3.4
-Error: numeric range error at "1.2.3.[4.>x<]"
-> 1.2.3.[x] 1.2.3.4
-Error: need decimal number 0..255 at "1.2.3.[>x<]"
-> 1.2.3.4x 1.2.3.4
-Error: garbage after pattern at "1.2.3.4>x<"
-> 1.2.[3..11].5 1.2.3.5 1.2.2.5 1.2.11.5 1.2.12.5 1.2.11.6
-Match 1.2.3.5: yes
-Match 1.2.2.5: no
-Match 1.2.11.5: yes
-Match 1.2.12.5: no
-Match 1.2.11.6: no
-> 1.2.[3,5,7,9,11].5 1.2.3.5 1.2.2.5 1.2.4.5 1.2.11.5 1.2.12.5 1.2.11.6
-Match 1.2.3.5: yes
-Match 1.2.2.5: no
-Match 1.2.4.5: no
-Match 1.2.11.5: yes
-Match 1.2.12.5: no
-Match 1.2.11.6: no
/* This module supports IP address pattern matching. See below
/* for a description of the supported address pattern syntax.
/*
-/* This implementation aims to minimize the cost of translating
-/* the pattern to internal form, while still providing good
+/* This implementation aims to minimize the cost of encoding
+/* the pattern in internal form, while still providing good
/* matching performance in the typical case. The first byte
/* of an encoded pattern specifies the expected address family
/* (for example, AF_INET); other details of the encoding are
static int ip_match_next_token(char **pstart, char **psaved_start, int *poval)
{
unsigned char *cp;
- unsigned char *next;
- int oval;
+ int oval; /* octet value */
+ int type; /* token value */
/*
* Return a literal, error, or EOF token. Update the read pointer to the
/*
* Return a token that contains an IPv4 address octet value.
*/
-#define IP_MATCH_RETURN_TOK_OVAL(next, oval) do { \
- *poval = (oval); IP_MATCH_RETURN_TOK((next), IP_MATCH_CODE_OVAL); \
+#define IP_MATCH_RETURN_TOK_VAL(next, type, oval) do { \
+ *poval = (oval); IP_MATCH_RETURN_TOK((next), type); \
} while (0)
/*
cp = (unsigned char *) *pstart;
if (ISDIGIT(*cp)) {
oval = *cp - '0';
- for (next = cp + 1; ISDIGIT(*next); next++) {
+ type = IP_MATCH_CODE_OVAL;
+ for (cp += 1; ISDIGIT(*cp); cp++) {
oval *= 10;
- oval += *next - '0';
+ oval += *cp - '0';
if (oval > 255)
- IP_MATCH_RETURN_TOK(next + 1, IP_MATCH_CODE_ERR);
+ type = IP_MATCH_CODE_ERR;
}
- IP_MATCH_RETURN_TOK_OVAL(next, oval);
+ IP_MATCH_RETURN_TOK_VAL(cp, type, oval);
} else {
IP_MATCH_RETURN_TOK(*cp ? cp + 1 : cp, *cp);
}
1.2.3.4
1.2.300.4
+1.2.3000.4
1.2.3.
1.2.3
a
Code: 1.2.3.4
> 1.2.300.4
Error: need decimal number 0..255 or "[" at "1.2.>300<.4"
+> 1.2.3000.4
+Error: need decimal number 0..255 or "[" at "1.2.>3000<.4"
> 1.2.3.
Error: need decimal number 0..255 or "[" at "1.2.3.><"
> 1.2.3