From a2244a0dd09744cd57da13c47b3f5db7aba9bf71 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Tue, 30 Nov 2010 00:00:00 -0500 Subject: [PATCH] postfix-2.8-20101130 --- postfix/HISTORY | 18 + postfix/README_FILES/POSTSCREEN_README | 98 ++--- postfix/RELEASE_NOTES | 10 +- postfix/WISHLIST | 5 - postfix/html/POSTSCREEN_README.html | 71 ++-- postfix/html/postconf.5.html | 84 ++-- postfix/html/postscreen.8.html | 45 ++- postfix/man/man5/postconf.5 | 77 ++-- postfix/man/man8/postscreen.8 | 3 + postfix/mantools/postlink | 1 + postfix/proto/POSTSCREEN_README.html | 71 ++-- postfix/proto/postconf.proto | 80 ++-- postfix/src/global/mail_params.h | 4 + postfix/src/global/mail_version.h | 2 +- postfix/src/postscreen/Makefile.in | 9 + postfix/src/postscreen/postscreen.c | 38 +- postfix/src/postscreen/postscreen.h | 17 +- postfix/src/postscreen/postscreen_dnsbl.c | 12 +- postfix/src/postscreen/postscreen_early.c | 12 +- postfix/src/postscreen/postscreen_misc.c | 10 +- postfix/src/postscreen/postscreen_send.c | 8 +- postfix/src/postscreen/postscreen_smtpd.c | 30 +- postfix/src/postscreen/postscreen_state.c | 23 ++ postfix/src/postscreen/postscreen_tests.c | 1 - postfix/src/util/Makefile.in | 27 +- postfix/src/util/ip_lmatch.c | 450 ---------------------- postfix/src/util/ip_lmatch.h | 35 -- postfix/src/util/ip_lmatch.in | 21 - postfix/src/util/ip_lmatch.ref | 51 --- postfix/src/util/ip_match.c | 21 +- postfix/src/util/ip_match.in | 1 + postfix/src/util/ip_match.ref | 2 + 32 files changed, 483 insertions(+), 854 deletions(-) delete mode 100644 postfix/src/util/ip_lmatch.c delete mode 100644 postfix/src/util/ip_lmatch.h delete mode 100644 postfix/src/util/ip_lmatch.in delete mode 100644 postfix/src/util/ip_lmatch.ref diff --git a/postfix/HISTORY b/postfix/HISTORY index 960ad72bd..793c2aab9 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -16176,3 +16176,21 @@ Apologies for any names omitted. 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. diff --git a/postfix/README_FILES/POSTSCREEN_README b/postfix/README_FILES/POSTSCREEN_README index d06b7237c..a03ebe34a 100644 --- a/postfix/README_FILES/POSTSCREEN_README +++ b/postfix/README_FILES/POSTSCREEN_README @@ -93,9 +93,10 @@ PPeerrmmaanneenntt wwhhiitteelliisstt tteesstt 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: - WWHHIITTEELLIISSTTEEDD address + WWHHIITTEELLIISSTTEEDD [address]:port The action is not configurable: immediately hand off the connection to a Postfix SMTP server process. @@ -105,9 +106,9 @@ PPeerrmmaanneenntt bbllaacckklliisstt tteesstt 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: - BBLLAACCKKLLIISSTTEEDD address + BBLLAACCKKLLIISSTTEEDD [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. @@ -121,9 +122,9 @@ whitelist. The temporary whitelist is not used for SMTP client addresses that 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: - PPAASSSS OOLLDD address + PPAASSSS OOLLDD [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 @@ -174,12 +175,12 @@ postscreen_whitelist_networks feature or else specify an empty teaser banner: When an SMTP client sends a command before the postscreen_greet_wait time has elapsed, postscreen(8) logs this as: - PPRREEGGRREEEETT count aafftteerr time ffrroomm address text... + PPRREEGGRREEEETT count aafftteerr time ffrroomm [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. @@ -199,9 +200,10 @@ When the postscreen_greet_wait time has elapsed, and the combined DNSBL score is equal to or greater than the postscreen_dnsbl_threshold parameter value, postscreen(8) logs this as: - DDNNSSBBLL rraannkk count ffoorr address + DDNNSSBBLL rraannkk count ffoorr [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 @@ -278,11 +280,11 @@ in SMTP engine anyway. This is to make postscreen(8) logging more informative. When a client sends multiple commands, postscreen(8) logs this as: - CCOOMMMMAANNDD PPIIPPEELLIINNIINNGG aafftteerr time ffrroomm address + CCOOMMMMAANNDD PPIIPPEELLIINNIINNGG aafftteerr time ffrroomm [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. @@ -306,9 +308,9 @@ in SMTP engine anyway. This is to make postscreen(8) logging more informative. When a client sends non-SMTP commands, postscreen(8) logs this as: - NNOONN--SSMMTTPP CCOOMMMMAANNDD ffrroomm address command + NNOONN--SSMMTTPP CCOOMMMMAANNDD ffrroomm [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. @@ -330,10 +332,10 @@ in SMTP engine anyway. This is to make postscreen(8) logging more informative. When a client sends bare newline characters, postscreen(8) logs this as: - BBAARREE NNEEWWLLIINNEE ffrroomm address + BBAARREE NNEEWWLLIINNEE ffrroomm [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. @@ -364,44 +366,54 @@ OOtthheerr eerrrroorrss When an SMTP client hangs up unexpectedly during any tests, postscreen(8) logs this as: - HHAANNGGUUPP aafftteerr time ffrroomm address iinn test name + HHAANNGGUUPP aafftteerr time ffrroomm [address]:port iinn 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. - CCOOMMMMAANNDD TTIIMMEE LLIIMMIITT ffrroomm address + CCOOMMMMAANNDD TTIIMMEE LLIIMMIITT ffrroomm [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. - - CCOOMMMMAANNDD CCOOUUNNTT LLIIMMIITT ffrroomm address - -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-command time +limit as specified with the postscreen_command_time_limit parameter. The session is terminated immediately. - CCOOMMMMAANNDD LLEENNGGTTHH LLIIMMIITT ffrroomm address + CCOOMMMMAANNDD CCOOUUNNTT LLIIMMIITT ffrroomm [address]:port -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. +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. + + CCOOMMMMAANNDD LLEENNGGTTHH LLIIMMIITT ffrroomm [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: + + NNOOQQUUEEUUEE:: rreejjeecctt:: CCOONNNNEECCTT ffrroomm [address]:port:: ttoooo mmaannyy ccoonnnneeccttiioonnss + NNOOQQUUEEUUEE:: rreejjeecctt:: CCOONNNNEECCTT ffrroomm [address]:port:: aallll sseerrvveerr ppoorrttss bbuussyy + +The postscreen_client_connection_count_limit and postscreen_pre_queue_limit +parameters control these limits. WWhheenn aallll tteessttss ssuucccceeeedd When a new SMTP client passes all tests (i.e. it is not whitelisted via some mechanism), postscreen(8) logs this as: - PPAASSSS NNEEWW address + PPAASSSS NNEEWW [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 diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index c22627260..501e4baac 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -33,12 +33,20 @@ This is supported only when the default value is stress-dependent 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. diff --git a/postfix/WISHLIST b/postfix/WISHLIST index a57d28a59..e9dd7ac95 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -4,13 +4,8 @@ Wish list: 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. diff --git a/postfix/html/POSTSCREEN_README.html b/postfix/html/POSTSCREEN_README.html index 4f2a1fd18..b59eecd13 100644 --- a/postfix/html/POSTSCREEN_README.html +++ b/postfix/html/POSTSCREEN_README.html @@ -131,11 +131,11 @@ handling of known clients.

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:

+the SMTP client address matches the permanent whitelist, postscreen(8) +logs this with the client address and port number as:

-    WHITELISTED address
+    WHITELISTED [address]:port
 

The action is not configurable: immediately hand off the @@ -146,10 +146,11 @@ 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:

+matches the permanent blacklist, postscreen(8) logs this with the +client address and port number as:

-    BLACKLISTED address
+    BLACKLISTED [address]:port
 

The postscreen_blacklist_action parameter specifies the action @@ -166,10 +167,11 @@ temporary whitelist is not used for SMTP client addresses that appear on the permanent blacklist or whitelist.

When the SMTP client address appears on the temporary -whitelist, postscreen(8) logs this as:

+whitelist, postscreen(8) logs this with the client address and port +number as:

-    PASS OLD address
+    PASS OLD [address]:port
 

The action is not configurable: immediately hand off the @@ -238,10 +240,10 @@ an empty teaser banner:

-    PREGREET count after time from address text...
+    PREGREET count after time from [address]:port text...
 
-

Translation: the client at address sent count +

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 @@ -271,10 +273,10 @@ DNSBL score is equal to or greater than the postscreen(8) logs this as:

-    DNSBL rank count for address
+    DNSBL rank count for [address]:port
 
-

Translation: the SMTP client at address has a combined +

Translation: the SMTP client at [address]:port has a combined DNSBL score of count.

The postscreen_dnsbl_action parameter specifies the action that @@ -380,10 +382,10 @@ logging more informative.

as:

-    COMMAND PIPELINING after time from address
+    COMMAND PIPELINING after time from [address]:port
 
-

Translation: the SMTP client at address sent multiple +

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.

@@ -416,10 +418,10 @@ logging more informative.

as:

-    NON-SMTP COMMAND from address command
+    NON-SMTP COMMAND from [address]:port command
 
-

Translation: the SMTP client at address sent a +

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.

@@ -448,10 +450,10 @@ this as:

-    BARE NEWLINE from address
+    BARE NEWLINE from [address]:port
 
-

Translation: the SMTP client at address sent a bare +

Translation: the SMTP client at [address]:port sent a bare newline character, that is newline not preceded by carriage return.

@@ -499,10 +501,10 @@ feature. postscreen(8) logs this as:

-    HANGUP after time from address in test name
+    HANGUP after time from [address]:port in test name
 
-

Translation: the SMTP client at address disconnected +

Translation: the SMTP client at [address]:port disconnected unexpectedly, time seconds after the start of the test named test name.

@@ -513,7 +515,7 @@ allowed to pass any tests, and postscreen(8) lo with the remaining amount of penalty time as:

-    PENALTY time for address
+    PENALTY time for [address]:port
 

During this time, all attempts by the client to deliver mail @@ -526,40 +528,53 @@ This engine never accepts mail, therefore it has per-session limits on the number of commands and on the session length.

-    COMMAND TIME LIMIT from address
+    COMMAND TIME LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached the +

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.

-    COMMAND COUNT LIMIT from address
+    COMMAND COUNT LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached 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.

-    COMMAND LENGTH LIMIT from address
+    COMMAND LENGTH LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached the +

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:

+ +
+    NOQUEUE: reject: CONNECT from [address]:port: too many connections
+    NOQUEUE: reject: CONNECT from [address]:port: all server ports busy
+
+ +

The postscreen_client_connection_count_limit and +postscreen_pre_queue_limit parameters control these limits.

+

When all tests succeed

When a new SMTP client passes all tests (i.e. it is not whitelisted via some mechanism), postscreen(8) logs this as:

-    PASS NEW address
+    PASS NEW [address]:port
 
-

Where address is the client IP address. Then, postscreen(8) +

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.

diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index c9d86854b..37525409a 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -6782,6 +6782,21 @@ that passed some deep protocol test once and never came back.

This feature is available in Postfix 2.8.

+ + +
postscreen_client_connection_count_limit +(default: $smtpd_client_connection_count_limit)
+ +

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.

+ +

This feature is available in Postfix 2.8.

+ +
postscreen_command_count_limit @@ -11680,8 +11695,8 @@ Postfix version 2.5). This feature is available with Postfix version
Reject the request when the reversed client network address is listed with the A record "d.d.d.d" under rbl_domain -(Postfix version 2.1 and later only). Each "d" can be a -pattern inside "[]" that contains one or more comma-separated decimal +(Postfix version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the reversed client network address is listed with any A record under @@ -11696,8 +11711,8 @@ This feature is available in Postfix 2.0 and later.
Accept the request when the reversed client network address is listed with the A record "d.d.d.d" under dnswl_domain. -Each "d" can be a pattern inside "[]" that contains one or -more comma-separated decimal numbers or number..number ranges. +Each "d" is a number, or a pattern inside "[]" that contains +one or more comma-separated numbers or number..number ranges. If no "=d.d.d.d" is specified, accept the request when the reversed client network address is listed with any A record under dnswl_domain.
For safety, permit_dnswl_client is silently @@ -11709,8 +11724,8 @@ is available in Postfix 2.8 and later.
Reject the request when the client hostname is listed with the A record "d.d.d.d" under rbl_domain (Postfix version -2.1 and later only). Each "d" can be a pattern inside "[]" -that contains one or more comma-separated decimal numbers or +2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the client hostname is listed with @@ -11724,8 +11739,8 @@ produce better results.
Accept the request when the client hostname is listed with the A record "d.d.d.d" under rhswl_domain. Each "d" -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 "=d.d.d.d" is specified, accept the request when the client hostname is listed with any A record under rhswl_domain.
Caution: client name whitelisting is fragile, since the client @@ -11741,8 +11756,8 @@ when whitelist lookup fails. This feature is available in Postfix
Reject the request when the unverified reverse client hostname is listed with the A record "d.d.d.d" under rbl_domain. -Each "d" can be a pattern inside "[]" that contains one or -more comma-separated decimal numbers or number..number ranges. +Each "d" is a number, or a pattern inside "[]" that contains +one or more comma-separated numbers or number..number ranges. If no "=d.d.d.d" is specified, reject the request when the unverified reverse client hostname is listed with any A record under rbl_domain. See the reject_rbl_client description above for @@ -12346,50 +12361,58 @@ received with the HELO or EHLO command.
Search the specified access(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.
check_helo_mx_access type:table
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.
+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. +
check_helo_ns_access type:table
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.
+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. +
reject_invalid_helo_hostname (with Postfix < 2.3: reject_invalid_hostname)
Reject the request when the HELO or EHLO hostname syntax is -invalid.
The invalid_hostname_reject_code specifies the response -code for rejected requests (default: 501).
+invalid. Note: specify "smtpd_helo_required = yes" to fully enforce +this restriction.
The invalid_hostname_reject_code specifies +the response code for rejected requests (default: 501).
reject_non_fqdn_helo_hostname (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.
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.
+The non_fqdn_reject_code parameter specifies the response code for rejected requests (default: 504).
reject_rhsbl_helo rbl_domain=d.d.d.d
Reject the request when the HELO or EHLO hostname hostname is listed with the A record "d.d.d.d" under rbl_domain -(Postfix version 2.1 and later only). Each "d" can be a -pattern inside "[]" that contains one or more comma-separated decimal +(Postfix version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the HELO or EHLO hostname is listed with any A record under rbl_domain. 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.
reject_unknown_helo_hostname (with Postfix < 2.3: reject_unknown_hostname)
@@ -12398,7 +12421,8 @@ or MX record.
The un specifies the numerical response code for rejected requests (default: 450).
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. @@ -12800,8 +12824,8 @@ rejected requests (default: 504).
Reject the request when the RCPT TO domain is listed with the A record "d.d.d.d" under rbl_domain (Postfix version -2.1 and later only). Each "d" can be a pattern inside "[]" -that contains one or more comma-separated decimal numbers or +2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the RCPT TO domain is listed with @@ -13347,8 +13371,8 @@ rejected requests (default: 504).
Reject the request when the MAIL FROM domain is listed with the A record "d.d.d.d" under rbl_domain (Postfix -version 2.1 and later only). Each "d" can be a pattern -inside "[]" that contains one or more comma-separated decimal numbers +version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the MAIL FROM domain is diff --git a/postfix/html/postscreen.8.html b/postfix/html/postscreen.8.html index 45a4c6f67..b3c71a8bf 100644 --- a/postfix/html/postscreen.8.html +++ b/postfix/html/postscreen.8.html @@ -233,41 +233,46 @@ POSTSCREEN(8) POSTSCREEN(8) of at most this length; upon delivery, long lines are reconstructed. + postscreen_client_connection_count_limit + ($smtpd_client_connection_count_limit) + How many simultaneous connections any client is + allowed to have with the postscreen(8) daemon. + postscreen_command_count_limit (20) - The limit on the total number of commands per SMTP - session for postscreen(8)'s built-in SMTP protocol + The limit on the total number of commands per SMTP + session for postscreen(8)'s built-in SMTP protocol engine. postscreen_command_time_limit (${stress?10}${stress:300}s) - The command "read" time limit for postscreen(8)'s + The command "read" time limit for postscreen(8)'s built-in SMTP protocol engine. postscreen_post_queue_limit ($default_process_limit) - 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. postscreen_pre_queue_limit ($default_process_limit) - 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. postscreen_watchdog_timeout (10s) - How much time a postscreen(8) process may take to - respond to an SMTP client command or to perform a + How much time a postscreen(8) 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. MISCELLANEOUS CONTROLS config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal + The maximal number of digits after the decimal point when logging sub-second delay values. command_directory (see 'postconf -d' output) - The location of all postfix administrative com- + The location of all postfix administrative com- mands. ipc_timeout (3600s) @@ -275,24 +280,24 @@ POSTSCREEN(8) POSTSCREEN(8) over an internal communication channel. max_idle (100s) - 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. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - 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". SEE ALSO @@ -304,12 +309,12 @@ POSTSCREEN(8) POSTSCREEN(8) POSTSCREEN_README, Postfix Postscreen Howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. HISTORY - Many ideas in postscreen(8) were explored in earlier work - by Michael Tokarev, in OpenBSD spamd, and in MailChannels + Many ideas in postscreen(8) were explored in earlier work + by Michael Tokarev, in OpenBSD spamd, and in MailChannels Traffic Control. AUTHOR(S) diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 3a98c78b8..3df9798a7 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -3818,6 +3818,15 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w (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 @@ -7166,8 +7175,8 @@ Postfix version 2.5). This feature is available with Postfix version .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 @@ -7181,8 +7190,8 @@ This feature is available in Postfix 2.0 and later. .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. @@ -7194,8 +7203,8 @@ is available in Postfix 2.8 and later. .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 @@ -7207,8 +7216,8 @@ produce better results. .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 @@ -7224,8 +7233,8 @@ when whitelist lookup fails. This feature is available in Postfix .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 @@ -7666,42 +7675,49 @@ received with the HELO or EHLO command. .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. @@ -7712,7 +7728,8 @@ specifies the numerical response code for rejected requests (default: .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 @@ -7939,8 +7956,8 @@ rejected requests (default: 504). .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 @@ -8312,8 +8329,8 @@ rejected requests (default: 504). .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 diff --git a/postfix/man/man8/postscreen.8 b/postfix/man/man8/postscreen.8 index c75c11feb..09ed7de90 100644 --- a/postfix/man/man8/postscreen.8 +++ b/postfix/man/man8/postscreen.8 @@ -210,6 +210,9 @@ a successful "pipelining" SMTP protocol test. .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. diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index f72c1aaeb..a20e3c207 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -944,6 +944,7 @@ while (<>) { s;\bpostscreen_whitelist_networks\b;$&;g; s;\bpostscreen_black[-]*\n*[ ]*list_networks\b;$&;g; s;\bpostscreen_black[-]*\n*[ ]*list_action\b;$&;g; + s;\bpostscreen_client_connection_count_limit\b;$&;g; # Hyperlink URLs and RFC documents diff --git a/postfix/proto/POSTSCREEN_README.html b/postfix/proto/POSTSCREEN_README.html index 2a7492f32..6d0c7e166 100644 --- a/postfix/proto/POSTSCREEN_README.html +++ b/postfix/proto/POSTSCREEN_README.html @@ -131,11 +131,11 @@ handling of known clients.

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:

+the SMTP client address matches the permanent whitelist, postscreen(8) +logs this with the client address and port number as:

-    WHITELISTED address
+    WHITELISTED [address]:port
 

The action is not configurable: immediately hand off the @@ -146,10 +146,11 @@ 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:

+matches the permanent blacklist, postscreen(8) logs this with the +client address and port number as:

-    BLACKLISTED address
+    BLACKLISTED [address]:port
 

The postscreen_blacklist_action parameter specifies the action @@ -166,10 +167,11 @@ temporary whitelist is not used for SMTP client addresses that appear on the permanent blacklist or whitelist.

When the SMTP client address appears on the temporary -whitelist, postscreen(8) logs this as:

+whitelist, postscreen(8) logs this with the client address and port +number as:

-    PASS OLD address
+    PASS OLD [address]:port
 

The action is not configurable: immediately hand off the @@ -238,10 +240,10 @@ postscreen_greet_wait time has elapsed, postscreen(8) logs this as:

-    PREGREET count after time from address text...
+    PREGREET count after time from [address]:port text...
 
-

Translation: the client at address sent count +

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 @@ -271,10 +273,10 @@ DNSBL score is equal to or greater than the postscreen_dnsbl_threshold parameter value, postscreen(8) logs this as:

-    DNSBL rank count for address
+    DNSBL rank count for [address]:port
 
-

Translation: the SMTP client at address has a combined +

Translation: the SMTP client at [address]:port has a combined DNSBL score of count.

The postscreen_dnsbl_action parameter specifies the action that @@ -380,10 +382,10 @@ logging more informative.

as:

-    COMMAND PIPELINING after time from address
+    COMMAND PIPELINING after time from [address]:port
 
-

Translation: the SMTP client at address sent multiple +

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.

@@ -416,10 +418,10 @@ logging more informative.

as:

-    NON-SMTP COMMAND from address command
+    NON-SMTP COMMAND from [address]:port command
 
-

Translation: the SMTP client at address sent a +

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.

@@ -448,10 +450,10 @@ this as:

-    BARE NEWLINE from address
+    BARE NEWLINE from [address]:port
 
-

Translation: the SMTP client at address sent a bare +

Translation: the SMTP client at [address]:port sent a bare newline character, that is newline not preceded by carriage return.

@@ -499,10 +501,10 @@ feature.
postscreen(8) logs this as:

-    HANGUP after time from address in test name
+    HANGUP after time from [address]:port in test name
 
-

Translation: the SMTP client at address disconnected +

Translation: the SMTP client at [address]:port disconnected unexpectedly, time seconds after the start of the test named test name.

@@ -513,7 +515,7 @@ allowed to pass any tests, and postscreen(8) logs each connection with the remaining amount of penalty time as:

-    PENALTY time for address
+    PENALTY time for [address]:port
 

During this time, all attempts by the client to deliver mail @@ -526,40 +528,53 @@ This engine never accepts mail, therefore it has per-session limits on the number of commands and on the session length.

-    COMMAND TIME LIMIT from address
+    COMMAND TIME LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached the +

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.

-    COMMAND COUNT LIMIT from address
+    COMMAND COUNT LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached 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.

-    COMMAND LENGTH LIMIT from address
+    COMMAND LENGTH LIMIT from [address]:port
 
-

Translation: the SMTP client at address reached the +

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:

+ +
+    NOQUEUE: reject: CONNECT from [address]:port: too many connections
+    NOQUEUE: reject: CONNECT from [address]:port: all server ports busy
+
+ +

The postscreen_client_connection_count_limit and +postscreen_pre_queue_limit parameters control these limits.

+

When all tests succeed

When a new SMTP client passes all tests (i.e. it is not whitelisted via some mechanism), postscreen(8) logs this as:

-    PASS NEW address
+    PASS NEW [address]:port
 
-

Where address is the client IP address. Then, postscreen(8) +

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.

diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 16d9d3942..7334ea079 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -4879,8 +4879,8 @@ Postfix version 2.5). This feature is available with Postfix version
Reject the request when the reversed client network address is listed with the A record "d.d.d.d" under rbl_domain -(Postfix version 2.1 and later only). Each "d" can be a -pattern inside "[]" that contains one or more comma-separated decimal +(Postfix version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the reversed client network address is listed with any A record under @@ -4895,8 +4895,8 @@ This feature is available in Postfix 2.0 and later.
Accept the request when the reversed client network address is listed with the A record "d.d.d.d" under dnswl_domain. -Each "d" can be a pattern inside "[]" that contains one or -more comma-separated decimal numbers or number..number ranges. +Each "d" is a number, or a pattern inside "[]" that contains +one or more comma-separated numbers or number..number ranges. If no "=d.d.d.d" is specified, accept the request when the reversed client network address is listed with any A record under dnswl_domain.
For safety, permit_dnswl_client is silently @@ -4908,8 +4908,8 @@ is available in Postfix 2.8 and later.
Reject the request when the client hostname is listed with the A record "d.d.d.d" under rbl_domain (Postfix version -2.1 and later only). Each "d" can be a pattern inside "[]" -that contains one or more comma-separated decimal numbers or +2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the client hostname is listed with @@ -4923,8 +4923,8 @@ produce better results.
Accept the request when the client hostname is listed with the A record "d.d.d.d" under rhswl_domain. Each "d" -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 "=d.d.d.d" is specified, accept the request when the client hostname is listed with any A record under rhswl_domain.
Caution: client name whitelisting is fragile, since the client @@ -4940,8 +4940,8 @@ when whitelist lookup fails. This feature is available in Postfix
Reject the request when the unverified reverse client hostname is listed with the A record "d.d.d.d" under rbl_domain. -Each "d" can be a pattern inside "[]" that contains one or -more comma-separated decimal numbers or number..number ranges. +Each "d" is a number, or a pattern inside "[]" that contains +one or more comma-separated numbers or number..number ranges. If no "=d.d.d.d" is specified, reject the request when the unverified reverse client hostname is listed with any A record under rbl_domain. See the reject_rbl_client description above for @@ -5346,50 +5346,58 @@ received with the HELO or EHLO command.
Search the specified access(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.
check_helo_mx_access type:table
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.
+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. +
check_helo_ns_access type:table
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.
+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. +
reject_invalid_helo_hostname (with Postfix < 2.3: reject_invalid_hostname)
Reject the request when the HELO or EHLO hostname syntax is -invalid.
The invalid_hostname_reject_code specifies the response -code for rejected requests (default: 501).
+invalid. Note: specify "smtpd_helo_required = yes" to fully enforce +this restriction.
The invalid_hostname_reject_code specifies +the response code for rejected requests (default: 501).
reject_non_fqdn_helo_hostname (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.
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.
+The non_fqdn_reject_code parameter specifies the response code for rejected requests (default: 504).
reject_rhsbl_helo rbl_domain=d.d.d.d
Reject the request when the HELO or EHLO hostname hostname is listed with the A record "d.d.d.d" under rbl_domain -(Postfix version 2.1 and later only). Each "d" can be a -pattern inside "[]" that contains one or more comma-separated decimal +(Postfix version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the HELO or EHLO hostname is listed with any A record under rbl_domain. 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.
reject_unknown_helo_hostname (with Postfix < 2.3: reject_unknown_hostname)
@@ -5398,7 +5406,8 @@ or MX record.
The unknown_hostname_reject_code parameter specifies the numerical response code for rejected requests (default: 450).
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. @@ -5674,8 +5683,8 @@ rejected requests (default: 504).
Reject the request when the RCPT TO domain is listed with the A record "d.d.d.d" under rbl_domain (Postfix version -2.1 and later only). Each "d" can be a pattern inside "[]" -that contains one or more comma-separated decimal numbers or +2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the RCPT TO domain is listed with @@ -6052,8 +6061,8 @@ rejected requests (default: 504).
Reject the request when the MAIL FROM domain is listed with the A record "d.d.d.d" under rbl_domain (Postfix -version 2.1 and later only). Each "d" can be a pattern -inside "[]" that contains one or more comma-separated decimal numbers +version 2.1 and later only). Each "d" 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 "=d.d.d.d" is specified, reject the request when the MAIL FROM domain is @@ -13331,6 +13340,17 @@ it passes the test, before it can talk to a real Postfix SMTP server.

This feature is available in Postfix 2.8.

+%PARAM postscreen_client_connection_count_limit $smtpd_client_connection_count_limit + +

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.

+ +

This feature is available in Postfix 2.8.

+ %PARAM dnsblog_reply_delay 0s

A debugging aid to artifically delay DNS responses.

diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 7901248cd..09b4a7d58 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -3366,6 +3366,10 @@ extern bool var_ps_helo_required; #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; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index a5e6a34bb..6758078fd 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20101126" +#define MAIL_RELEASE_DATE "20101130" #define MAIL_VERSION_NUMBER "2.8" #ifdef SNAPSHOT diff --git a/postfix/src/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in index 6957030b2..227e211a5 100644 --- a/postfix/src/postscreen/Makefile.in +++ b/postfix/src/postscreen/Makefile.in @@ -68,6 +68,7 @@ postscreen.o: ../../include/data_redirect.h 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 @@ -93,6 +94,7 @@ postscreen_dict.o: ../../include/argv.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 @@ -118,6 +120,7 @@ postscreen_dnsbl.o: ../../include/mail_proto.h postscreen_dnsbl.o: ../../include/match_list.h postscreen_dnsbl.o: ../../include/match_ops.h postscreen_dnsbl.o: ../../include/msg.h +postscreen_dnsbl.o: ../../include/myaddrinfo.h postscreen_dnsbl.o: ../../include/mymalloc.h postscreen_dnsbl.o: ../../include/split_at.h postscreen_dnsbl.o: ../../include/string_list.h @@ -133,6 +136,7 @@ postscreen_early.o: ../../include/argv.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 @@ -152,6 +156,7 @@ postscreen_misc.o: ../../include/dict.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 @@ -170,6 +175,7 @@ postscreen_send.o: ../../include/connect.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 @@ -187,6 +193,7 @@ postscreen_smtpd.o: ../../include/attr.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 @@ -209,6 +216,7 @@ postscreen_state.o: ../../include/attr.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 @@ -229,6 +237,7 @@ postscreen_tests.o: ../../include/argv.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 diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index 74a32f4e4..37fca2746 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -188,6 +188,9 @@ /* .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. @@ -348,6 +351,8 @@ int var_ps_barlf_ttl; int var_ps_cmd_count; char *var_ps_cmd_time; +int var_ps_cconn_limit; + /* * Global variables. */ @@ -372,6 +377,7 @@ int ps_stress; /* stress level */ 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. @@ -501,11 +507,11 @@ static void ps_service(VSTREAM *smtp_client_stream, 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 @@ -514,12 +520,24 @@ static void ps_service(VSTREAM *smtp_client_stream, 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"); @@ -532,7 +550,7 @@ static void ps_service(VSTREAM *smtp_client_stream, */ 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; } @@ -544,7 +562,7 @@ static void ps_service(VSTREAM *smtp_client_stream, */ 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: @@ -581,7 +599,7 @@ static void ps_service(VSTREAM *smtp_client_stream, 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; } @@ -599,7 +617,7 @@ static void ps_service(VSTREAM *smtp_client_stream, */ 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"); @@ -807,6 +825,11 @@ static void post_jail_init(char *unused_name, char **unused_argv) 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; @@ -848,6 +871,7 @@ int main(int argc, char **argv) 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[] = { diff --git a/postfix/src/postscreen/postscreen.h b/postfix/src/postscreen/postscreen.h index 4470756b3..a93a036bb 100644 --- a/postfix/src/postscreen/postscreen.h +++ b/postfix/src/postscreen/postscreen.h @@ -19,6 +19,7 @@ #include #include #include +#include /* * Global library. @@ -41,6 +42,7 @@ typedef struct { 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 */ @@ -288,6 +290,7 @@ extern int ps_stress; /* stress level */ 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) @@ -323,40 +326,40 @@ extern DICT *ps_dnsbl_reply; /* DNSBL name mapper */ #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 { \ diff --git a/postfix/src/postscreen/postscreen_dnsbl.c b/postfix/src/postscreen/postscreen_dnsbl.c index d28c90e42..2b68b0097 100644 --- a/postfix/src/postscreen/postscreen_dnsbl.c +++ b/postfix/src/postscreen/postscreen_dnsbl.c @@ -107,7 +107,8 @@ typedef struct { } 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; @@ -209,7 +210,7 @@ static void ps_dnsbl_add_site(const char *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; @@ -263,7 +264,8 @@ static void ps_dnsbl_add_site(const char *site) * 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; @@ -382,8 +384,8 @@ static void ps_dnsbl_receive(int event, char *context) 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; diff --git a/postfix/src/postscreen/postscreen_early.c b/postfix/src/postscreen/postscreen_early.c index 27e22e284..54e27bc71 100644 --- a/postfix/src/postscreen/postscreen_early.c +++ b/postfix/src/postscreen/postscreen_early.c @@ -62,7 +62,7 @@ static void ps_early_event(int event, char *context) 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, @@ -117,8 +117,8 @@ static void ps_early_event(int event, char *context) 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: @@ -174,9 +174,9 @@ static void ps_early_event(int event, char *context) 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: @@ -228,7 +228,7 @@ static void ps_early_dnsbl_event(int unused_event, char *context) 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 diff --git a/postfix/src/postscreen/postscreen_misc.c b/postfix/src/postscreen/postscreen_misc.c index 263a85020..f077a57e6 100644 --- a/postfix/src/postscreen/postscreen_misc.c +++ b/postfix/src/postscreen/postscreen_misc.c @@ -104,8 +104,8 @@ void ps_conclude(PS_STATE *state) 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 @@ -128,7 +128,7 @@ void ps_conclude(PS_STATE *state) (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); } } @@ -148,9 +148,9 @@ void ps_hangup_event(PS_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); } diff --git a/postfix/src/postscreen/postscreen_send.c b/postfix/src/postscreen/postscreen_send.c index 5b8fc1f22..9a47e4fe8 100644 --- a/postfix/src/postscreen/postscreen_send.c +++ b/postfix/src/postscreen/postscreen_send.c @@ -78,7 +78,7 @@ int ps_send_reply(int smtp_client_fd, const char *smtp_client_addr, 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); /* @@ -88,7 +88,7 @@ int ps_send_reply(int smtp_client_fd, const char *smtp_client_addr, 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); } @@ -100,7 +100,7 @@ static void ps_send_socket_close_event(int event, char *context) 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); @@ -128,7 +128,7 @@ void ps_send_socket(PS_STATE *state) 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); diff --git a/postfix/src/postscreen/postscreen_smtpd.c b/postfix/src/postscreen/postscreen_smtpd.c index f3d6c4267..c05d1fe5c 100644 --- a/postfix/src/postscreen/postscreen_smtpd.c +++ b/postfix/src/postscreen/postscreen_smtpd.c @@ -321,9 +321,9 @@ static int ps_rcpt_cmd(PS_STATE *state, char *args) 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 : ""); @@ -428,13 +428,13 @@ static void ps_smtpd_time_event(int event, char *context) 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); } @@ -499,7 +499,7 @@ static void ps_smtpd_read_event(int event, char *context) 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, @@ -543,8 +543,8 @@ static void ps_smtpd_read_event(int event, char *context) */ 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; @@ -580,7 +580,8 @@ static void ps_smtpd_read_event(int event, char *context) 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 */ @@ -644,7 +645,7 @@ static void ps_smtpd_read_event(int event, char *context) */ 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. */ @@ -668,8 +669,8 @@ static void ps_smtpd_read_event(int event, char *context) || (*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 */ @@ -703,8 +704,8 @@ static void ps_smtpd_read_event(int event, char *context) 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 */ @@ -766,7 +767,8 @@ static void ps_smtpd_read_event(int event, char *context) /* 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; diff --git a/postfix/src/postscreen/postscreen_state.c b/postfix/src/postscreen/postscreen_state.c index 740c02454..729800494 100644 --- a/postfix/src/postscreen/postscreen_state.c +++ b/postfix/src/postscreen/postscreen_state.c @@ -123,6 +123,7 @@ #include #include #include +#include /* Global library. */ @@ -143,6 +144,7 @@ PS_STATE *ps_new_session_state(VSTREAM *stream, const char *port) { PS_STATE *state; + HTABLE_INFO *ht; state = (PS_STATE *) mymalloc(sizeof(*state)); PS_INIT_TESTS(state); @@ -171,6 +173,15 @@ PS_STATE *ps_new_session_state(VSTREAM *stream, 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); } @@ -178,6 +189,18 @@ PS_STATE *ps_new_session_state(VSTREAM *stream, 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--; diff --git a/postfix/src/postscreen/postscreen_tests.c b/postfix/src/postscreen/postscreen_tests.c index a281d4a50..3ba7adc76 100644 --- a/postfix/src/postscreen/postscreen_tests.c +++ b/postfix/src/postscreen/postscreen_tests.c @@ -156,7 +156,6 @@ void ps_parse_tests(PS_STATE *state, 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; diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index b07f74fdb..69c669812 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -33,7 +33,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ 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 \ @@ -68,7 +68,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.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 \ @@ -89,7 +89,7 @@ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.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) @@ -107,7 +107,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ 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 @@ -427,16 +427,11 @@ ip_match: $(LIB) $(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: @@ -563,11 +558,6 @@ ip_match_test: ip_match ip_match.in ip_match.ref 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.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 \ @@ -1214,13 +1204,6 @@ ip_match.o: mymalloc.h 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 diff --git a/postfix/src/util/ip_lmatch.c b/postfix/src/util/ip_lmatch.c deleted file mode 100644 index 70dc1ecbb..000000000 --- a/postfix/src/util/ip_lmatch.c +++ /dev/null @@ -1,450 +0,0 @@ -/*++ -/* NAME -/* ip_lmatch 3 -/* SUMMARY -/* lazy IP address pattern matching -/* SYNOPSIS -/* #include -/* -/* 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 -#include -#include -#include -#include -#include - -/* Utility library. */ - -#include -#include -#include -#include -#include - - /* - * 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 -#include -#include -#include -#include -#include - -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 diff --git a/postfix/src/util/ip_lmatch.h b/postfix/src/util/ip_lmatch.h deleted file mode 100644 index 788956f88..000000000 --- a/postfix/src/util/ip_lmatch.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _IP_LMATCH_H_INCLUDED_ -#define _IP_LMATCH_H_INCLUDED_ - -/*++ -/* NAME -/* ip_lmatch 3h -/* SUMMARY -/* lazy IP address pattern matching -/* SYNOPSIS -/* #include -/* DESCRIPTION -/* .nf - - /* - * Utility library. - */ -#include - - /* - * 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 diff --git a/postfix/src/util/ip_lmatch.in b/postfix/src/util/ip_lmatch.in deleted file mode 100644 index 9b7aba33a..000000000 --- a/postfix/src/util/ip_lmatch.in +++ /dev/null @@ -1,21 +0,0 @@ -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 diff --git a/postfix/src/util/ip_lmatch.ref b/postfix/src/util/ip_lmatch.ref deleted file mode 100644 index d8431bd91..000000000 --- a/postfix/src/util/ip_lmatch.ref +++ /dev/null @@ -1,51 +0,0 @@ -> 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 diff --git a/postfix/src/util/ip_match.c b/postfix/src/util/ip_match.c index 17d1db29c..eb9333481 100644 --- a/postfix/src/util/ip_match.c +++ b/postfix/src/util/ip_match.c @@ -24,8 +24,8 @@ /* 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 @@ -357,8 +357,8 @@ int ip_match_execute(const char *byte_codes, const char *addr_bytes) 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 @@ -370,8 +370,8 @@ static int ip_match_next_token(char **pstart, char **psaved_start, int *poval) /* * 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) /* @@ -382,13 +382,14 @@ static int ip_match_next_token(char **pstart, char **psaved_start, int *poval) 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); } diff --git a/postfix/src/util/ip_match.in b/postfix/src/util/ip_match.in index 97964fbfb..0aae84b58 100644 --- a/postfix/src/util/ip_match.in +++ b/postfix/src/util/ip_match.in @@ -1,5 +1,6 @@ 1.2.3.4 1.2.300.4 +1.2.3000.4 1.2.3. 1.2.3 a diff --git a/postfix/src/util/ip_match.ref b/postfix/src/util/ip_match.ref index ba75840c5..3293b10ec 100644 --- a/postfix/src/util/ip_match.ref +++ b/postfix/src/util/ip_match.ref @@ -2,6 +2,8 @@ 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