diff --git a/postfix/HISTORY b/postfix/HISTORY index f6d0de624..a7454217f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -16123,3 +16123,16 @@ Apologies for any names omitted. notify" as with Postfix automatically-added BCC recipients. Files: cleanup/cleanup_addr.c, cleanup/cleanup.h, cleanup/cleanup_milter.c. + +20101105 + + Feature: DNS whitelist support in the Postfix SMTP server. + permit_dnswl_client whitelists a client by IP address, and + permit_rhswl_client whitelists a client by its hostname. + The syntax is the same as reject_rbl_client etc., but the + result is PERMIT instead of REJECT. For safety reasons, + permit_xxx_client are silently ignored when they would + override reject_unauth_destination. The result is + DEFER_IF_REJECT when DNSWL lookup fails. The implementation + is based on a design documented by Noel Jones (August 2010). + File: smtpd/smtpd_check.c. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 91a2e837c..3f1a2cdb5 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -33,6 +33,26 @@ 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. +Major changes with snapshot 20101105 +==================================== + +The Postfix SMTP server now supports DNS-based whitelisting with +several safety features: permit_dnswl_client whitelists a client +by IP address, and permit_rhswl_client whitelists a client by its +hostname. These features use the same syntax as reject_rbl_client +and reject_rhsbl_client, respectively. The main difference is that +they return PERMIT instead of REJECT. + +Whitelisting is primarily a tool to reduce the false positive rate +of DNS blocklist lookups. Client name whitelisting should not be +used to make exceptions to access rules. The reason is that client +name lookup can fail unpredictably due to some temporary outage. + +For safety reasons, permit_dnswl_client and permit_rhswl_client are +silently ignored when they would override reject_unauth_destination. +Also for safety reasons, the result is DEFER_IF_REJECT when DNS +whitelist lookup fails (this result will be made configurable). + Incompatibility with snapshot 20101103 ====================================== diff --git a/postfix/WISHLIST b/postfix/WISHLIST index cf0c54e57..90490da14 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -4,6 +4,11 @@ Wish list: anvil rate limit for sasl_username. + permit_tempfail_action (default: defer_if_reject) to be + used as the default value for dnswl_tempfail_action and + rhswl_tempfail_action. Steal liberally from the code that + implements unverified_recipient_tempfail_action etc. + Support filtering of messages that are generated by Postfix: This would apply to postmaster notices and bounce messages (DKIM), and address verification (BATV). diff --git a/postfix/conf/access b/postfix/conf/access index e52790472..9df9991a4 100644 --- a/postfix/conf/access +++ b/postfix/conf/access @@ -74,10 +74,13 @@ # The pattern domain.tld also matches subdomains, but # only when the string smtpd_access_maps is listed in # the Postfix parent_domain_matches_subdomains con- -# figuration setting (note that this is the default -# for some versions of Postfix). Otherwise, specify -# .domain.tld (note the initial dot) in order to -# match subdomains. +# figuration setting. +# +# .domain.tld +# Matches subdomains of domain.tld, but only when the +# string smtpd_access_maps is not listed in the Post- +# fix parent_domain_matches_subdomains configuration +# setting. # # user@ Matches all mail addresses with the specified user # part. @@ -105,9 +108,13 @@ # The pattern domain.tld also matches subdomains, but # only when the string smtpd_access_maps is listed in # the Postfix parent_domain_matches_subdomains con- -# figuration setting. Otherwise, specify .domain.tld -# (note the initial dot) in order to match subdo- -# mains. +# figuration setting. +# +# .domain.tld +# Matches subdomains of domain.tld, but only when the +# string smtpd_access_maps is not listed in the Post- +# fix parent_domain_matches_subdomains configuration +# setting. # # net.work.addr.ess # @@ -115,21 +122,21 @@ # # net.work # -# net Matches the specified IPv4 host address or subnet- -# work. An IPv4 host address is a sequence of four +# net Matches the specified IPv4 host address or subnet- +# work. An IPv4 host address is a sequence of four # decimal octets separated by ".". # -# Subnetworks are matched by repeatedly truncating +# Subnetworks are matched by repeatedly truncating # the last ".octet" from the remote IPv4 host address -# string until a match is found in the access table, +# string until a match is found in the access table, # or until further truncation is not possible. # # NOTE 1: The access map lookup key must be in canon- -# ical form: do not specify unnecessary null charac- -# ters, and do not enclose network address informa- +# ical form: do not specify unnecessary null charac- +# ters, and do not enclose network address informa- # tion with "[]" characters. # -# NOTE 2: use the cidr lookup table type to specify +# NOTE 2: use the cidr lookup table type to specify # network/netmask patterns. See cidr_table(5) for # details. # @@ -139,12 +146,12 @@ # # net:work # -# net Matches the specified IPv6 host address or subnet- -# work. An IPv6 host address is a sequence of three -# to eight hexadecimal octet pairs separated by ":". +# net Matches the specified IPv6 host address or subnet- +# work. An IPv6 host address is a sequence of three +# to eight hexadecimal octet pairs separated by ":". # -# Subnetworks are matched by repeatedly truncating -# the last ":octetpair" from the remote IPv6 host +# Subnetworks are matched by repeatedly truncating +# the last ":octetpair" from the remote IPv6 host # address string until a match is found in the access # table, or until further truncation is not possible. # @@ -153,11 +160,11 @@ # Thus, not all the ":" subnetworks will be tried. # # NOTE 2: The access map lookup key must be in canon- -# ical form: do not specify unnecessary null charac- -# ters, and do not enclose network address informa- +# ical form: do not specify unnecessary null charac- +# ters, and do not enclose network address informa- # tion with "[]" characters. # -# NOTE 3: use the cidr lookup table type to specify +# NOTE 3: use the cidr lookup table type to specify # network/netmask patterns. See cidr_table(5) for # details. # @@ -168,62 +175,62 @@ # # all-numerical # An all-numerical result is treated as OK. This for- -# mat is generated by address-based relay authoriza- +# mat is generated by address-based relay authoriza- # tion schemes such as pop-before-smtp. # # REJECT ACTIONS -# Postfix version 2.3 and later support enhanced status -# codes as defined in RFC 3463. When no code is specified -# at the beginning of the text below, Postfix inserts a -# default enhanced status code of "5.7.1" in the case of -# reject actions, and "4.7.1" in the case of defer actions. +# Postfix version 2.3 and later support enhanced status +# codes as defined in RFC 3463. When no code is specified +# at the beginning of the text below, Postfix inserts a +# default enhanced status code of "5.7.1" in the case of +# reject actions, and "4.7.1" in the case of defer actions. # See "ENHANCED STATUS CODES" below. # # 4NN text # # 5NN text -# Reject the address etc. that matches the pattern, +# Reject the address etc. that matches the pattern, # and respond with the numerical three-digit code and -# text. 4NN means "try again later", while 5NN means +# text. 4NN means "try again later", while 5NN means # "do not try again". # -# The following responses have special meaning for +# The following responses have special meaning for # the Postfix SMTP server: # # 421 text (Postfix 2.3 and later) # # 521 text (Postfix 2.6 and later) -# After responding with the numerical three- -# digit code and text, disconnect immediately -# from the SMTP client. This frees up SMTP -# server resources so that they can be made +# After responding with the numerical three- +# digit code and text, disconnect immediately +# from the SMTP client. This frees up SMTP +# server resources so that they can be made # available to another SMTP client. # # Note: The "521" response should be used only -# with botnets and other malware where inter- +# with botnets and other malware where inter- # operability is of no concern. The "send 521 -# and disconnect" behavior is NOT defined in +# and disconnect" behavior is NOT defined in # the SMTP standard. # # REJECT optional text... -# Reject the address etc. that matches the pattern. -# Reply with "$access_map_reject_code optional -# text..." when the optional text is specified, oth- +# Reject the address etc. that matches the pattern. +# Reply with "$access_map_reject_code optional +# text..." when the optional text is specified, oth- # erwise reply with a generic error response message. # # DEFER optional text... -# Reject the address etc. that matches the pattern. -# Reply with "$access_map_defer_code optional -# text..." when the optional text is specified, oth- +# Reject the address etc. that matches the pattern. +# Reply with "$access_map_defer_code optional +# text..." when the optional text is specified, oth- # erwise reply with a generic error response message. # # This feature is available in Postfix 2.6 and later. # # DEFER_IF_REJECT optional text... -# Defer the request if some later restriction would -# result in a REJECT action. Reply with -# "$access_map_defer_code 4.7.1 optional text..." -# when the optional text is specified, otherwise +# Defer the request if some later restriction would +# result in a REJECT action. Reply with +# "$access_map_defer_code 4.7.1 optional text..." +# when the optional text is specified, otherwise # reply with a generic error response message. # # Prior to Postfix 2.6, the SMTP reply code is 450. @@ -231,10 +238,10 @@ # This feature is available in Postfix 2.1 and later. # # DEFER_IF_PERMIT optional text... -# Defer the request if some later restriction would -# result in a an explicit or implicit PERMIT action. -# Reply with "$access_map_defer_code 4.7.1 optional -# text..." when the optional text is specified, oth- +# Defer the request if some later restriction would +# result in a an explicit or implicit PERMIT action. +# Reply with "$access_map_defer_code 4.7.1 optional +# text..." when the optional text is specified, oth- # erwise reply with a generic error response message. # # Prior to Postfix 2.6, the SMTP reply code is 450. @@ -247,187 +254,187 @@ # reject_unauth_destination, and so on). # # BCC user@domain -# Send one copy of the message to the specified +# Send one copy of the message to the specified # recipient. # -# If multiple BCC actions are specified within the -# same SMTP MAIL transaction, only the last action +# If multiple BCC actions are specified within the +# same SMTP MAIL transaction, only the last action # will be used. # -# This feature is not part of the stable Postfix +# This feature is not part of the stable Postfix # release. # # DISCARD optional text... -# Claim successful delivery and silently discard the -# message. Log the optional text if specified, oth- +# Claim successful delivery and silently discard the +# message. Log the optional text if specified, oth- # erwise log a generic message. # -# Note: this action currently affects all recipients -# of the message. To discard only one recipient -# without discarding the entire message, use the +# Note: this action currently affects all recipients +# of the message. To discard only one recipient +# without discarding the entire message, use the # transport(5) table to direct mail to the discard(8) # service. # # This feature is available in Postfix 2.0 and later. # -# DUNNO Pretend that the lookup key was not found. This -# prevents Postfix from trying substrings of the -# lookup key (such as a subdomain name, or a network +# DUNNO Pretend that the lookup key was not found. This +# prevents Postfix from trying substrings of the +# lookup key (such as a subdomain name, or a network # address subnetwork). # # This feature is available in Postfix 2.0 and later. # # FILTER transport:destination -# After the message is queued, send the entire mes- +# After the message is queued, send the entire mes- # sage through the specified external content filter. -# The transport name specifies the first field of a -# mail delivery agent definition in master.cf; the -# syntax of the next-hop destination is described in +# The transport name specifies the first field of a +# mail delivery agent definition in master.cf; the +# syntax of the next-hop destination is described in # the manual page of the corresponding delivery -# agent. More information about external content +# agent. More information about external content # filters is in the Postfix FILTER_README file. # -# Note 1: do not use $number regular expression sub- -# stitutions for transport or destination unless you +# Note 1: do not use $number regular expression sub- +# stitutions for transport or destination unless you # know that the information has a trusted origin. # -# Note 2: this action overrides the main.cf con- -# tent_filter setting, and affects all recipients of -# the message. In the case that multiple FILTER +# Note 2: this action overrides the main.cf con- +# tent_filter setting, and affects all recipients of +# the message. In the case that multiple FILTER # actions fire, only the last one is executed. # -# Note 3: the purpose of the FILTER command is to -# override message routing. To override the recipi- -# ent's transport but not the next-hop destination, -# specify an empty filter destination (Postfix 2.7 +# Note 3: the purpose of the FILTER command is to +# override message routing. To override the recipi- +# ent's transport but not the next-hop destination, +# specify an empty filter destination (Postfix 2.7 # and later), or specify a transport:destination that -# delivers through a different Postfix instance -# (Postfix 2.6 and earlier). Other options are using -# the recipient-dependent transport_maps or the sen- +# delivers through a different Postfix instance +# (Postfix 2.6 and earlier). Other options are using +# the recipient-dependent transport_maps or the sen- # der-dependent sender_dependent_default_transport- # _maps features. # # This feature is available in Postfix 2.0 and later. # # HOLD optional text... -# Place the message on the hold queue, where it will -# sit until someone either deletes it or releases it -# for delivery. Log the optional text if specified, +# Place the message on the hold queue, where it will +# sit until someone either deletes it or releases it +# for delivery. Log the optional text if specified, # otherwise log a generic message. # -# Mail that is placed on hold can be examined with -# the postcat(1) command, and can be destroyed or +# Mail that is placed on hold can be examined with +# the postcat(1) command, and can be destroyed or # released with the postsuper(1) command. # -# Note: use "postsuper -r" to release mail that was -# kept on hold for a significant fraction of $maxi- +# Note: use "postsuper -r" to release mail that was +# kept on hold for a significant fraction of $maxi- # mal_queue_lifetime or $bounce_queue_lifetime, or -# longer. Use "postsuper -H" only for mail that will +# longer. Use "postsuper -H" only for mail that will # not expire within a few delivery attempts. # -# Note: this action currently affects all recipients +# Note: this action currently affects all recipients # of the message. # # This feature is available in Postfix 2.0 and later. # # PREPEND headername: headervalue -# Prepend the specified message header to the mes- -# sage. When more than one PREPEND action executes, -# the first prepended header appears before the sec- +# Prepend the specified message header to the mes- +# sage. When more than one PREPEND action executes, +# the first prepended header appears before the sec- # ond etc. prepended header. # -# Note: this action must execute before the message -# content is received; it cannot execute in the con- +# Note: this action must execute before the message +# content is received; it cannot execute in the con- # text of smtpd_end_of_data_restrictions. # # This feature is available in Postfix 2.1 and later. # # REDIRECT user@domain -# After the message is queued, send the message to +# After the message is queued, send the message to # the specified address instead of the intended # recipient(s). # -# Note: this action overrides the FILTER action, and +# Note: this action overrides the FILTER action, and # currently affects all recipients of the message. # # This feature is available in Postfix 2.1 and later. # # WARN optional text... # Log a warning with the optional text, together with -# client information and if available, with helo, +# client information and if available, with helo, # sender, recipient and protocol information. # # This feature is available in Postfix 2.1 and later. # # ENHANCED STATUS CODES -# Postfix version 2.3 and later support enhanced status -# codes as defined in RFC 3463. When an enhanced status -# code is specified in an access table, it is subject to -# modification. The following transformations are needed -# when the same access table is used for client, helo, -# sender, or recipient access restrictions; they happen +# Postfix version 2.3 and later support enhanced status +# codes as defined in RFC 3463. When an enhanced status +# code is specified in an access table, it is subject to +# modification. The following transformations are needed +# when the same access table is used for client, helo, +# sender, or recipient access restrictions; they happen # regardless of whether Postfix replies to a MAIL FROM, RCPT # TO or other SMTP command. # -# o When a sender address matches a REJECT action, the -# Postfix SMTP server will transform a recipient DSN -# status (e.g., 4.1.1-4.1.6) into the corresponding +# o When a sender address matches a REJECT action, the +# Postfix SMTP server will transform a recipient DSN +# status (e.g., 4.1.1-4.1.6) into the corresponding # sender DSN status, and vice versa. # -# o When non-address information matches a REJECT -# action (such as the HELO command argument or the -# client hostname/address), the Postfix SMTP server -# will transform a sender or recipient DSN status -# into a generic non-address DSN status (e.g., +# o When non-address information matches a REJECT +# action (such as the HELO command argument or the +# client hostname/address), the Postfix SMTP server +# will transform a sender or recipient DSN status +# into a generic non-address DSN status (e.g., # 4.0.0). # # REGULAR EXPRESSION TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # the table is given in the form of regular expressions. For -# a description of regular expression lookup table syntax, +# a description of regular expression lookup table syntax, # see regexp_table(5) or pcre_table(5). # -# Each pattern is a regular expression that is applied to +# Each pattern is a regular expression that is applied to # the entire string being looked up. Depending on the appli- -# cation, that string is an entire client hostname, an +# cation, that string is an entire client hostname, an # entire client IP address, or an entire mail address. Thus, # no parent domain or parent network search is done, -# user@domain mail addresses are not broken up into their +# user@domain mail addresses are not broken up into their # user@ and domain constituent parts, nor is user+foo broken # up into user and foo. # -# Patterns are applied in the order as specified in the ta- -# ble, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the ta- +# ble, until a pattern is found that matches the search # string. # -# Actions are the same as with indexed file lookups, with -# the additional feature that parenthesized substrings from +# Actions are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from # the pattern can be interpolated as $1, $2 and so on. # # TCP-BASED TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # lookups are directed to a TCP-based server. For a descrip- # tion of the TCP client/server lookup protocol, see tcp_ta- # ble(5). This feature is not available up to and including # Postfix version 2.4. # -# Each lookup operation uses the entire query string once. -# Depending on the application, that string is an entire +# Each lookup operation uses the entire query string once. +# Depending on the application, that string is an entire # client hostname, an entire client IP address, or an entire -# mail address. Thus, no parent domain or parent network -# search is done, user@domain mail addresses are not broken -# up into their user@ and domain constituent parts, nor is +# mail address. Thus, no parent domain or parent network +# search is done, user@domain mail addresses are not broken +# up into their user@ and domain constituent parts, nor is # user+foo broken up into user and foo. # # Actions are the same as with indexed file lookups. # # EXAMPLE -# The following example uses an indexed file, so that the -# order of table entries does not matter. The example per- -# mits access by the client at address 1.2.3.4 but rejects -# all other clients in 1.2.3.0/24. Instead of hash lookup -# tables, some systems use dbm. Use the command "postconf -# -m" to find out what lookup tables Postfix supports on +# The following example uses an indexed file, so that the +# order of table entries does not matter. The example per- +# mits access by the client at address 1.2.3.4 but rejects +# all other clients in 1.2.3.0/24. Instead of hash lookup +# tables, some systems use dbm. Use the command "postconf +# -m" to find out what lookup tables Postfix supports on # your system. # # /etc/postfix/main.cf: @@ -438,11 +445,11 @@ # 1.2.3 REJECT # 1.2.3.4 OK # -# Execute the command "postmap /etc/postfix/access" after +# Execute the command "postmap /etc/postfix/access" after # editing the file. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # SEE ALSO # postmap(1), Postfix lookup table manager @@ -451,13 +458,13 @@ # transport(5), transport:nexthop syntax # # README FILES -# Use "postconf readme_directory" or "postconf html_direc- +# Use "postconf readme_directory" or "postconf html_direc- # tory" to locate this information. # SMTPD_ACCESS_README, built-in SMTP server access control # DATABASE_README, Postfix lookup table overview # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) diff --git a/postfix/html/access.5.html b/postfix/html/access.5.html index c284f86a4..0696fcdbf 100644 --- a/postfix/html/access.5.html +++ b/postfix/html/access.5.html @@ -80,10 +80,13 @@ ACCESS(5) ACCESS(5) The pattern domain.tld also matches subdomains, but only when the string smtpd_access_maps is listed in the Postfix parent_domain_matches_subdomains con- - figuration setting (note that this is the default - for some versions of Postfix). Otherwise, specify - .domain.tld (note the initial dot) in order to - match subdomains. + figuration setting. + + .domain.tld + Matches subdomains of domain.tld, but only when the + string smtpd_access_maps is not listed in the Post- + fix parent_domain_matches_subdomains configuration + setting. user@ Matches all mail addresses with the specified user part. @@ -111,9 +114,13 @@ ACCESS(5) ACCESS(5) The pattern domain.tld also matches subdomains, but only when the string smtpd_access_maps is listed in the Postfix parent_domain_matches_subdomains con- - figuration setting. Otherwise, specify .domain.tld - (note the initial dot) in order to match subdo- - mains. + figuration setting. + + .domain.tld + Matches subdomains of domain.tld, but only when the + string smtpd_access_maps is not listed in the Post- + fix parent_domain_matches_subdomains configuration + setting. net.work.addr.ess @@ -121,21 +128,21 @@ ACCESS(5) ACCESS(5) net.work - net Matches the specified IPv4 host address or subnet- - work. An IPv4 host address is a sequence of four + net Matches the specified IPv4 host address or subnet- + work. An IPv4 host address is a sequence of four decimal octets separated by ".". - Subnetworks are matched by repeatedly truncating + Subnetworks are matched by repeatedly truncating the last ".octet" from the remote IPv4 host address - string until a match is found in the access table, + string until a match is found in the access table, or until further truncation is not possible. NOTE 1: The access map lookup key must be in canon- - ical form: do not specify unnecessary null charac- - ters, and do not enclose network address informa- + ical form: do not specify unnecessary null charac- + ters, and do not enclose network address informa- tion with "[]" characters. - NOTE 2: use the cidr lookup table type to specify + NOTE 2: use the cidr lookup table type to specify network/netmask patterns. See cidr_table(5) for details. @@ -145,12 +152,12 @@ ACCESS(5) ACCESS(5) net:work - net Matches the specified IPv6 host address or subnet- - work. An IPv6 host address is a sequence of three - to eight hexadecimal octet pairs separated by ":". + net Matches the specified IPv6 host address or subnet- + work. An IPv6 host address is a sequence of three + to eight hexadecimal octet pairs separated by ":". - Subnetworks are matched by repeatedly truncating - the last ":octetpair" from the remote IPv6 host + Subnetworks are matched by repeatedly truncating + the last ":octetpair" from the remote IPv6 host address string until a match is found in the access table, or until further truncation is not possible. @@ -159,11 +166,11 @@ ACCESS(5) ACCESS(5) Thus, not all the ":" subnetworks will be tried. NOTE 2: The access map lookup key must be in canon- - ical form: do not specify unnecessary null charac- - ters, and do not enclose network address informa- + ical form: do not specify unnecessary null charac- + ters, and do not enclose network address informa- tion with "[]" characters. - NOTE 3: use the cidr lookup table type to specify + NOTE 3: use the cidr lookup table type to specify network/netmask patterns. See cidr_table(5) for details. @@ -174,62 +181,62 @@ ACCESS(5) ACCESS(5) all-numerical An all-numerical result is treated as OK. This for- - mat is generated by address-based relay authoriza- + mat is generated by address-based relay authoriza- tion schemes such as pop-before-smtp. REJECT ACTIONS - Postfix version 2.3 and later support enhanced status - codes as defined in RFC 3463. When no code is specified - at the beginning of the text below, Postfix inserts a - default enhanced status code of "5.7.1" in the case of - reject actions, and "4.7.1" in the case of defer actions. + Postfix version 2.3 and later support enhanced status + codes as defined in RFC 3463. When no code is specified + at the beginning of the text below, Postfix inserts a + default enhanced status code of "5.7.1" in the case of + reject actions, and "4.7.1" in the case of defer actions. See "ENHANCED STATUS CODES" below. 4NN text 5NN text - Reject the address etc. that matches the pattern, + Reject the address etc. that matches the pattern, and respond with the numerical three-digit code and - text. 4NN means "try again later", while 5NN means + text. 4NN means "try again later", while 5NN means "do not try again". - The following responses have special meaning for + The following responses have special meaning for the Postfix SMTP server: 421 text (Postfix 2.3 and later) 521 text (Postfix 2.6 and later) - After responding with the numerical three- - digit code and text, disconnect immediately - from the SMTP client. This frees up SMTP - server resources so that they can be made + After responding with the numerical three- + digit code and text, disconnect immediately + from the SMTP client. This frees up SMTP + server resources so that they can be made available to another SMTP client. Note: The "521" response should be used only - with botnets and other malware where inter- + with botnets and other malware where inter- operability is of no concern. The "send 521 - and disconnect" behavior is NOT defined in + and disconnect" behavior is NOT defined in the SMTP standard. REJECT optional text... - Reject the address etc. that matches the pattern. - Reply with "$access_map_reject_code optional - text..." when the optional text is specified, oth- + Reject the address etc. that matches the pattern. + Reply with "$access_map_reject_code optional + text..." when the optional text is specified, oth- erwise reply with a generic error response message. DEFER optional text... - Reject the address etc. that matches the pattern. - Reply with "$access_map_defer_code optional - text..." when the optional text is specified, oth- + Reject the address etc. that matches the pattern. + Reply with "$access_map_defer_code optional + text..." when the optional text is specified, oth- erwise reply with a generic error response message. This feature is available in Postfix 2.6 and later. DEFER_IF_REJECT optional text... - Defer the request if some later restriction would - result in a REJECT action. Reply with - "$access_map_defer_code 4.7.1 optional text..." - when the optional text is specified, otherwise + Defer the request if some later restriction would + result in a REJECT action. Reply with + "$access_map_defer_code 4.7.1 optional text..." + when the optional text is specified, otherwise reply with a generic error response message. Prior to Postfix 2.6, the SMTP reply code is 450. @@ -237,10 +244,10 @@ ACCESS(5) ACCESS(5) This feature is available in Postfix 2.1 and later. DEFER_IF_PERMIT optional text... - Defer the request if some later restriction would - result in a an explicit or implicit PERMIT action. - Reply with "$access_map_defer_code 4.7.1 optional - text..." when the optional text is specified, oth- + Defer the request if some later restriction would + result in a an explicit or implicit PERMIT action. + Reply with "$access_map_defer_code 4.7.1 optional + text..." when the optional text is specified, oth- erwise reply with a generic error response message. Prior to Postfix 2.6, the SMTP reply code is 450. @@ -253,187 +260,187 @@ ACCESS(5) ACCESS(5) reject_unauth_destination, and so on). BCC user@domain - Send one copy of the message to the specified + Send one copy of the message to the specified recipient. - If multiple BCC actions are specified within the - same SMTP MAIL transaction, only the last action + If multiple BCC actions are specified within the + same SMTP MAIL transaction, only the last action will be used. - This feature is not part of the stable Postfix + This feature is not part of the stable Postfix release. DISCARD optional text... - Claim successful delivery and silently discard the - message. Log the optional text if specified, oth- + Claim successful delivery and silently discard the + message. Log the optional text if specified, oth- erwise log a generic message. - Note: this action currently affects all recipients - of the message. To discard only one recipient - without discarding the entire message, use the + Note: this action currently affects all recipients + of the message. To discard only one recipient + without discarding the entire message, use the transport(5) table to direct mail to the discard(8) service. This feature is available in Postfix 2.0 and later. - DUNNO Pretend that the lookup key was not found. This - prevents Postfix from trying substrings of the - lookup key (such as a subdomain name, or a network + DUNNO Pretend that the lookup key was not found. This + prevents Postfix from trying substrings of the + lookup key (such as a subdomain name, or a network address subnetwork). This feature is available in Postfix 2.0 and later. FILTER transport:destination - After the message is queued, send the entire mes- + After the message is queued, send the entire mes- sage through the specified external content filter. - The transport name specifies the first field of a - mail delivery agent definition in master.cf; the - syntax of the next-hop destination is described in + The transport name specifies the first field of a + mail delivery agent definition in master.cf; the + syntax of the next-hop destination is described in the manual page of the corresponding delivery - agent. More information about external content + agent. More information about external content filters is in the Postfix FILTER_README file. - Note 1: do not use $number regular expression sub- - stitutions for transport or destination unless you + Note 1: do not use $number regular expression sub- + stitutions for transport or destination unless you know that the information has a trusted origin. - Note 2: this action overrides the main.cf con- - tent_filter setting, and affects all recipients of - the message. In the case that multiple FILTER + Note 2: this action overrides the main.cf con- + tent_filter setting, and affects all recipients of + the message. In the case that multiple FILTER actions fire, only the last one is executed. - Note 3: the purpose of the FILTER command is to - override message routing. To override the recipi- - ent's transport but not the next-hop destination, - specify an empty filter destination (Postfix 2.7 + Note 3: the purpose of the FILTER command is to + override message routing. To override the recipi- + ent's transport but not the next-hop destination, + specify an empty filter destination (Postfix 2.7 and later), or specify a transport:destination that - delivers through a different Postfix instance - (Postfix 2.6 and earlier). Other options are using - the recipient-dependent transport_maps or the sen- + delivers through a different Postfix instance + (Postfix 2.6 and earlier). Other options are using + the recipient-dependent transport_maps or the sen- der-dependent sender_dependent_default_transport- _maps features. This feature is available in Postfix 2.0 and later. HOLD optional text... - Place the message on the hold queue, where it will - sit until someone either deletes it or releases it - for delivery. Log the optional text if specified, + Place the message on the hold queue, where it will + sit until someone either deletes it or releases it + for delivery. Log the optional text if specified, otherwise log a generic message. - Mail that is placed on hold can be examined with - the postcat(1) command, and can be destroyed or + Mail that is placed on hold can be examined with + the postcat(1) command, and can be destroyed or released with the postsuper(1) command. - Note: use "postsuper -r" to release mail that was - kept on hold for a significant fraction of $maxi- + Note: use "postsuper -r" to release mail that was + kept on hold for a significant fraction of $maxi- mal_queue_lifetime or $bounce_queue_lifetime, or - longer. Use "postsuper -H" only for mail that will + longer. Use "postsuper -H" only for mail that will not expire within a few delivery attempts. - Note: this action currently affects all recipients + Note: this action currently affects all recipients of the message. This feature is available in Postfix 2.0 and later. PREPEND headername: headervalue - Prepend the specified message header to the mes- - sage. When more than one PREPEND action executes, - the first prepended header appears before the sec- + Prepend the specified message header to the mes- + sage. When more than one PREPEND action executes, + the first prepended header appears before the sec- ond etc. prepended header. - Note: this action must execute before the message - content is received; it cannot execute in the con- + Note: this action must execute before the message + content is received; it cannot execute in the con- text of smtpd_end_of_data_restrictions. This feature is available in Postfix 2.1 and later. REDIRECT user@domain - After the message is queued, send the message to + After the message is queued, send the message to the specified address instead of the intended recipient(s). - Note: this action overrides the FILTER action, and + Note: this action overrides the FILTER action, and currently affects all recipients of the message. This feature is available in Postfix 2.1 and later. WARN optional text... Log a warning with the optional text, together with - client information and if available, with helo, + client information and if available, with helo, sender, recipient and protocol information. This feature is available in Postfix 2.1 and later. ENHANCED STATUS CODES - Postfix version 2.3 and later support enhanced status - codes as defined in RFC 3463. When an enhanced status - code is specified in an access table, it is subject to - modification. The following transformations are needed - when the same access table is used for client, helo, - sender, or recipient access restrictions; they happen + Postfix version 2.3 and later support enhanced status + codes as defined in RFC 3463. When an enhanced status + code is specified in an access table, it is subject to + modification. The following transformations are needed + when the same access table is used for client, helo, + sender, or recipient access restrictions; they happen regardless of whether Postfix replies to a MAIL FROM, RCPT TO or other SMTP command. - o When a sender address matches a REJECT action, the - Postfix SMTP server will transform a recipient DSN - status (e.g., 4.1.1-4.1.6) into the corresponding + o When a sender address matches a REJECT action, the + Postfix SMTP server will transform a recipient DSN + status (e.g., 4.1.1-4.1.6) into the corresponding sender DSN status, and vice versa. - o When non-address information matches a REJECT - action (such as the HELO command argument or the - client hostname/address), the Postfix SMTP server - will transform a sender or recipient DSN status - into a generic non-address DSN status (e.g., + o When non-address information matches a REJECT + action (such as the HELO command argument or the + client hostname/address), the Postfix SMTP server + will transform a sender or recipient DSN status + into a generic non-address DSN status (e.g., 4.0.0). REGULAR EXPRESSION TABLES - This section describes how the table lookups change when + This section describes how the table lookups change when the table is given in the form of regular expressions. For - a description of regular expression lookup table syntax, + a description of regular expression lookup table syntax, see regexp_table(5) or pcre_table(5). - Each pattern is a regular expression that is applied to + Each pattern is a regular expression that is applied to the entire string being looked up. Depending on the appli- - cation, that string is an entire client hostname, an + cation, that string is an entire client hostname, an entire client IP address, or an entire mail address. Thus, no parent domain or parent network search is done, - user@domain mail addresses are not broken up into their + user@domain mail addresses are not broken up into their user@ and domain constituent parts, nor is user+foo broken up into user and foo. - Patterns are applied in the order as specified in the ta- - ble, until a pattern is found that matches the search + Patterns are applied in the order as specified in the ta- + ble, until a pattern is found that matches the search string. - Actions are the same as with indexed file lookups, with - the additional feature that parenthesized substrings from + Actions are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from the pattern can be interpolated as $1, $2 and so on. TCP-BASED TABLES - This section describes how the table lookups change when + This section describes how the table lookups change when lookups are directed to a TCP-based server. For a descrip- tion of the TCP client/server lookup protocol, see tcp_ta- ble(5). This feature is not available up to and including Postfix version 2.4. - Each lookup operation uses the entire query string once. - Depending on the application, that string is an entire + Each lookup operation uses the entire query string once. + Depending on the application, that string is an entire client hostname, an entire client IP address, or an entire - mail address. Thus, no parent domain or parent network - search is done, user@domain mail addresses are not broken - up into their user@ and domain constituent parts, nor is + mail address. Thus, no parent domain or parent network + search is done, user@domain mail addresses are not broken + up into their user@ and domain constituent parts, nor is user+foo broken up into user and foo. Actions are the same as with indexed file lookups. EXAMPLE - The following example uses an indexed file, so that the - order of table entries does not matter. The example per- - mits access by the client at address 1.2.3.4 but rejects - all other clients in 1.2.3.0/24. Instead of hash lookup - tables, some systems use dbm. Use the command "postconf - -m" to find out what lookup tables Postfix supports on + The following example uses an indexed file, so that the + order of table entries does not matter. The example per- + mits access by the client at address 1.2.3.4 but rejects + all other clients in 1.2.3.0/24. Instead of hash lookup + tables, some systems use dbm. Use the command "postconf + -m" to find out what lookup tables Postfix supports on your system. /etc/postfix/main.cf: @@ -444,11 +451,11 @@ ACCESS(5) ACCESS(5) 1.2.3 REJECT 1.2.3.4 OK - Execute the command "postmap /etc/postfix/access" after + Execute the command "postmap /etc/postfix/access" after editing the file. BUGS - The table format does not understand quoting conventions. + The table format does not understand quoting conventions. SEE ALSO postmap(1), Postfix lookup table manager @@ -461,7 +468,7 @@ ACCESS(5) ACCESS(5) DATABASE_README, Postfix lookup table overview LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index a785cbdd3..66afd8452 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -11688,7 +11688,18 @@ specifies the default server reply, and the reject_rhsbl_client rbl_domain=d.d.d.d +
permit_dnswl_client dnswl_domain=d.d.d.d
+ +
Accept the request when the reversed client network address is +listed with the A record "d.d.d.d" under dnswl_domain. +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 +ignored when it would override reject_unauth_destination. The +result is DEFER_IF_REJECT when whitelist lookup fails. This feature +is available in Postfix 2.8 and later.
+ +
reject_rhsbl_client rbl_domain=d.d.d.d
Reject the request when the client hostname is listed with the A record "d.d.d.d" under rbl_domain (Postfix version @@ -11700,6 +11711,21 @@ This feature is available in Postfix 2.0 and later; with Postfix version 2.8 and later, reject_rhsbl_reverse_client will usually produce better results.
+
permit_rhswl_client rhswl_domain=d.d.d.d
+ +
Accept the request when the client hostname is listed with the +A record "d.d.d.d" under rhswl_domain. 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 +name lookup can fail due to temporary outages. Client name +whitelisting should be used only to reduce false positives in e.g. +DNS-based blocklists, and not for making access rule exceptions. +
For safety, permit_rhswl_client is silently ignored when it +would override reject_unauth_destination. The result is DEFER_IF_REJECT +when whitelist lookup fails. This feature is available in Postfix +2.8 and later.
+
reject_rhsbl_reverse_client rbl_domain=d.d.d.d
Reject the request when the unverified reverse client hostname diff --git a/postfix/man/man5/access.5 b/postfix/man/man5/access.5 index f901b1c9e..64d678ad5 100644 --- a/postfix/man/man5/access.5 +++ b/postfix/man/man5/access.5 @@ -77,10 +77,11 @@ Matches \fIdomain.tld\fR as the domain part of an email address. .sp The pattern \fIdomain.tld\fR also matches subdomains, but only when the string \fBsmtpd_access_maps\fR is listed in the Postfix -\fBparent_domain_matches_subdomains\fR configuration setting -(note that this is the default for some versions of Postfix). -Otherwise, specify \fI.domain.tld\fR (note the initial dot) in -order to match subdomains. +\fBparent_domain_matches_subdomains\fR configuration setting. +.IP \fI.domain.tld\fR +Matches subdomains of \fIdomain.tld\fR, but only when the +string \fBsmtpd_access_maps\fR is not listed in the Postfix +\fBparent_domain_matches_subdomains\fR configuration setting. .IP \fIuser\fR@ Matches all mail addresses with the specified user part. .PP @@ -112,8 +113,10 @@ Matches \fIdomain.tld\fR. The pattern \fIdomain.tld\fR also matches subdomains, but only when the string \fBsmtpd_access_maps\fR is listed in the Postfix \fBparent_domain_matches_subdomains\fR configuration setting. -Otherwise, specify \fI.domain.tld\fR (note the initial dot) in -order to match subdomains. +.IP \fI.domain.tld\fR +Matches subdomains of \fIdomain.tld\fR, but only when the +string \fBsmtpd_access_maps\fR is not listed in the Postfix +\fBparent_domain_matches_subdomains\fR configuration setting. .IP \fInet.work.addr.ess\fR .IP \fInet.work.addr\fR .IP \fInet.work\fR diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index d23140222..db80efbe1 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -7175,6 +7175,17 @@ rejected requests (default: 554), the default_rbl_reply parameter specifies the default server reply, and the rbl_reply_maps parameter specifies tables with server replies indexed by \fIrbl_domain\fR. 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. +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. +.br +For safety, permit_dnswl_client is silently +ignored when it would override reject_unauth_destination. The +result is DEFER_IF_REJECT when whitelist lookup fails. This feature +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 @@ -7185,6 +7196,21 @@ description above for additional RBL related configuration parameters. This feature is available in Postfix 2.0 and later; with Postfix version 2.8 and later, reject_rhsbl_reverse_client will usually 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. 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 +Caution: client name whitelisting is fragile, since the client +name lookup can fail due to temporary outages. Client name +whitelisting should be used only to reduce false positives in e.g. +DNS-based blocklists, and not for making access rule exceptions. +.br +For safety, permit_rhswl_client is silently ignored when it +would override reject_unauth_destination. The result is DEFER_IF_REJECT +when whitelist lookup fails. This feature is available in Postfix +2.8 and later. .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. diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index a5a77dfdb..f72c1aaeb 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -835,6 +835,8 @@ while (<>) { s;\breject_rbl_client\b;$&;g; s;\breject_rhsbl_client\b;$&;g; s;\breject_rhsbl_reverse_client\b;$&;g; + s;\bpermit_dnswl_client\b;$&;g; + s;\bpermit_rhswl_client\b;$&;g; # Access restrictions - helo diff --git a/postfix/proto/access b/postfix/proto/access index 6e7007c64..403e080d1 100644 --- a/postfix/proto/access +++ b/postfix/proto/access @@ -65,10 +65,11 @@ # .sp # The pattern \fIdomain.tld\fR also matches subdomains, but only # when the string \fBsmtpd_access_maps\fR is listed in the Postfix -# \fBparent_domain_matches_subdomains\fR configuration setting -# (note that this is the default for some versions of Postfix). -# Otherwise, specify \fI.domain.tld\fR (note the initial dot) in -# order to match subdomains. +# \fBparent_domain_matches_subdomains\fR configuration setting. +# .IP \fI.domain.tld\fR +# Matches subdomains of \fIdomain.tld\fR, but only when the +# string \fBsmtpd_access_maps\fR is not listed in the Postfix +# \fBparent_domain_matches_subdomains\fR configuration setting. # .IP \fIuser\fR@ # Matches all mail addresses with the specified user part. # .PP @@ -96,8 +97,10 @@ # The pattern \fIdomain.tld\fR also matches subdomains, but only # when the string \fBsmtpd_access_maps\fR is listed in the Postfix # \fBparent_domain_matches_subdomains\fR configuration setting. -# Otherwise, specify \fI.domain.tld\fR (note the initial dot) in -# order to match subdomains. +# .IP \fI.domain.tld\fR +# Matches subdomains of \fIdomain.tld\fR, but only when the +# string \fBsmtpd_access_maps\fR is not listed in the Postfix +# \fBparent_domain_matches_subdomains\fR configuration setting. # .IP \fInet.work.addr.ess\fR # .IP \fInet.work.addr\fR # .IP \fInet.work\fR diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index ad997071c..6e3ce4e1e 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -4888,6 +4888,17 @@ specifies the default server reply, and the rbl_reply_maps parameter specifies tables with server replies indexed by rbl_domain. This feature is available in Postfix 2.0 and later.
+
permit_dnswl_client dnswl_domain=d.d.d.d
+ +
Accept the request when the reversed client network address is +listed with the A record "d.d.d.d" under dnswl_domain. +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 +ignored when it would override reject_unauth_destination. The +result is DEFER_IF_REJECT when whitelist lookup fails. This feature +is available in Postfix 2.8 and later.
+
reject_rhsbl_client rbl_domain=d.d.d.d
Reject the request when the client hostname is listed with the @@ -4900,6 +4911,21 @@ This feature is available in Postfix 2.0 and later; with Postfix version 2.8 and later, reject_rhsbl_reverse_client will usually produce better results.
+
permit_rhswl_client rhswl_domain=d.d.d.d
+ +
Accept the request when the client hostname is listed with the +A record "d.d.d.d" under rhswl_domain. 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 +name lookup can fail due to temporary outages. Client name +whitelisting should be used only to reduce false positives in e.g. +DNS-based blocklists, and not for making access rule exceptions. +
For safety, permit_rhswl_client is silently ignored when it +would override reject_unauth_destination. The result is DEFER_IF_REJECT +when whitelist lookup fails. This feature is available in Postfix +2.8 and later.
+
reject_rhsbl_reverse_client rbl_domain=d.d.d.d
Reject the request when the unverified reverse client hostname diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 3c19cd302..7901248cd 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -2151,6 +2151,9 @@ extern int var_map_defer_code; #define REJECT_RHSBL_SENDER "reject_rhsbl_sender" #define REJECT_RHSBL_RECIPIENT "reject_rhsbl_recipient" +#define PERMIT_DNSWL_CLIENT "permit_dnswl_client" +#define PERMIT_RHSWL_CLIENT "permit_rhswl_client" + #define VAR_RBL_REPLY_MAPS "rbl_reply_maps" #define DEF_RBL_REPLY_MAPS "" extern char *var_rbl_reply_maps; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 1f9174338..d7e5eb580 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 "20101103" +#define MAIL_RELEASE_DATE "20101108" #define MAIL_VERSION_NUMBER "2.8" #ifdef SNAPSHOT diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index eac71d225..01bd2ef40 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -66,7 +66,7 @@ tidy: clean tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_exp_test \ smtpd_token_test smtpd_check_test4 smtpd_check_dsn_test \ - smtpd_check_backup_test + smtpd_check_backup_test smtpd_dnswl_test root_tests: @@ -124,6 +124,13 @@ smtpd_token_test: smtpd_token smtpd_token.in smtpd_token.ref diff smtpd_token.ref smtpd_token.tmp rm -f smtpd_token.tmp +# This requires that the DNS server can query porcupine.org and rfc-ignorant.org + +smtpd_dnswl_test: smtpd_check smtpd_dnswl.in smtpd_dnswl.ref + ./smtpd_check smtpd_dnswl.tmp 2>&1 + diff smtpd_dnswl.ref smtpd_dnswl.tmp + rm -f smtpd_dnswl.tmp + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index a013a6d82..7bfc04335 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -2939,6 +2939,15 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode, } } +/* Support for different DNSXL lookup results. */ + +static SMTPD_RBL_STATE dnsxl_stat_soft[1]; + +#define SMTPD_DNSXL_STAT_SOFT(dnsxl_res) ((dnsxl_res) == dnsxl_stat_soft) +#define SMTPD_DNXSL_STAT_HARD(dnsxl_res) ((dnsxl_res) == 0) +#define SMTPD_DNSXL_STAT_OK(dnsxl_res) \ + !(SMTPD_DNXSL_STAT_HARD(dnsxl_res) || SMTPD_DNSXL_STAT_SOFT(dnsxl_res)) + /* rbl_pagein - look up an RBL lookup result */ static void *rbl_pagein(const char *query, void *unused_context) @@ -2947,7 +2956,7 @@ static void *rbl_pagein(const char *query, void *unused_context) DNS_RR *txt_list; VSTRING *why; int dns_status; - SMTPD_RBL_STATE *rbl; + SMTPD_RBL_STATE *rbl = 0; DNS_RR *addr_list; MAI_HOSTADDR_STR hostaddr; DNS_RR *rr; @@ -2964,11 +2973,13 @@ static void *rbl_pagein(const char *query, void *unused_context) */ why = vstring_alloc(10); dns_status = dns_lookup(query, T_A, 0, &addr_list, (VSTRING *) 0, why); - if (dns_status != DNS_OK && dns_status != DNS_NOTFOUND) + if (dns_status != DNS_OK && dns_status != DNS_NOTFOUND) { msg_warn("%s: RBL lookup error: %s", query, STR(why)); + rbl = dnsxl_stat_soft; + } vstring_free(why); if (dns_status != DNS_OK) - return (0); + return ((void *) rbl); /* * Save the result. Yes, we cache negative results as well as positive @@ -3013,7 +3024,7 @@ static void rbl_pageout(void *data, void *unused_context) { SMTPD_RBL_STATE *rbl = (SMTPD_RBL_STATE *) data; - if (rbl != 0) { + if (SMTPD_DNSXL_STAT_OK(rbl)) { if (rbl->txt) myfree(rbl->txt); if (rbl->a) @@ -3059,7 +3070,7 @@ static const char *rbl_expand_lookup(const char *name, int mode, /* rbl_reject_reply - format reply after RBL reject */ -static int rbl_reject_reply(SMTPD_STATE *state, SMTPD_RBL_STATE *rbl, +static int rbl_reject_reply(SMTPD_STATE *state, const SMTPD_RBL_STATE *rbl, const char *rbl_domain, const char *what, const char *reply_class) @@ -3144,12 +3155,13 @@ static int rbl_match_addr(SMTPD_RBL_STATE *rbl, const char *addr) return (0); } -/* reject_rbl_addr - reject if address in real-time blackhole list */ +/* find_dnsxl_addr - look up address in DNSXL */ -static int reject_rbl_addr(SMTPD_STATE *state, const char *rbl_domain, - const char *addr, const char *reply_class) +static const SMTPD_RBL_STATE *find_dnsxl_addr(SMTPD_STATE *state, + const char *rbl_domain, + const char *addr) { - const char *myname = "reject_rbl"; + const char *myname = "find_dnsxl_addr"; ARGV *octets; VSTRING *query; int i; @@ -3158,9 +3170,6 @@ static int reject_rbl_addr(SMTPD_STATE *state, const char *rbl_domain, struct addrinfo *res; unsigned char *ipv6_addr; - if (msg_verbose) - msg_info("%s: %s %s", myname, reply_class, addr); - query = vstring_alloc(100); /* @@ -3203,31 +3212,79 @@ static int reject_rbl_addr(SMTPD_STATE *state, const char *rbl_domain, rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query)); /* - * If the record exists, the address is blacklisted. + * If the record exists, match the result address. */ - if (rbl == 0 || (reply_addr != 0 && !rbl_match_addr(rbl, reply_addr))) { - vstring_free(query); + if (SMTPD_DNSXL_STAT_OK(rbl) && reply_addr != 0 + && !rbl_match_addr(rbl, reply_addr)) + rbl = 0; + vstring_free(query); + return (rbl); +} + +/* reject_rbl_addr - reject address in real-time blackhole list */ + +static int reject_rbl_addr(SMTPD_STATE *state, const char *rbl_domain, + const char *addr, const char *reply_class) +{ + const char *myname = "reject_rbl_addr"; + const SMTPD_RBL_STATE *rbl; + + if (msg_verbose) + msg_info("%s: %s %s", myname, reply_class, addr); + + rbl = find_dnsxl_addr(state, rbl_domain, addr); + if (!SMTPD_DNSXL_STAT_OK(rbl)) { return (SMTPD_CHECK_DUNNO); } else { - vstring_free(query); return (rbl_reject_reply(state, rbl, rbl_domain, addr, reply_class)); } } -/* reject_rbl_domain - reject if domain in real-time blackhole list */ +/* permit_dnswl_addr - permit address in DNSWL */ -static int reject_rbl_domain(SMTPD_STATE *state, const char *rbl_domain, - const char *what, const char *reply_class) +static int permit_dnswl_addr(SMTPD_STATE *state, const char *dnswl_domain, + const char *addr, const char *reply_class) +{ + const char *myname = "permit_dnswl_addr"; + const SMTPD_RBL_STATE *dnswl_result; + + if (msg_verbose) + msg_info("%s: %s", myname, addr); + + /* Safety: don't whitelist unauthorized recipients. */ + if (strcmp(state->where, SMTPD_CMD_RCPT) == 0 && state->recipient != 0 + && permit_auth_destination(state, state->recipient) != SMTPD_CHECK_OK) + return (SMTPD_CHECK_DUNNO); + + dnswl_result = find_dnsxl_addr(state, dnswl_domain, addr); + if (SMTPD_DNXSL_STAT_HARD(dnswl_result)) { + return (SMTPD_CHECK_DUNNO); + } else if (SMTPD_DNSXL_STAT_SOFT(dnswl_result)) { + /* XXX: Make configurable as dnswl_tempfail_action. */ + DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY, + 450, "4.7.1", + "<%s>: %s rejected: %s", + addr, reply_class, + "Service unavailable"); + return (SMTPD_CHECK_DUNNO); + } else if (SMTPD_DNSXL_STAT_OK(dnswl_result)) { + return (SMTPD_CHECK_OK); + } else { + /* Future proofing, in case find_dnsxl_addr() result is changed. */ + msg_panic("%s: find_dnsxl_addr API failure", myname); + } +} + +/* find_dnsxl_domain - reject if domain in real-time blackhole list */ + +static const SMTPD_RBL_STATE *find_dnsxl_domain(SMTPD_STATE *state, + const char *rbl_domain, const char *what) { - const char *myname = "reject_rbl_domain"; VSTRING *query; SMTPD_RBL_STATE *rbl; const char *domain; const char *reply_addr; - if (msg_verbose) - msg_info("%s: %s %s", myname, reply_class, what); - /* * Extract the domain, tack on the RBL domain name and query the DNS for * an A record. @@ -3247,17 +3304,69 @@ static int reject_rbl_domain(SMTPD_STATE *state, const char *rbl_domain, rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query)); /* - * If the record exists, the domain is blacklisted. + * If the record exists, match the result address. */ - if (rbl == 0 || (reply_addr != 0 && !rbl_match_addr(rbl, reply_addr))) { - vstring_free(query); + if (SMTPD_DNSXL_STAT_OK(rbl) && reply_addr != 0 + && !rbl_match_addr(rbl, reply_addr)) + rbl = 0; + vstring_free(query); + return (rbl); +} + +/* reject_rbl_domain - reject if domain in real-time blackhole list */ + +static int reject_rbl_domain(SMTPD_STATE *state, const char *rbl_domain, + const char *what, const char *reply_class) +{ + const char *myname = "reject_rbl_domain"; + const SMTPD_RBL_STATE *rbl; + + if (msg_verbose) + msg_info("%s: %s %s", myname, rbl_domain, what); + + rbl = find_dnsxl_domain(state, rbl_domain, what); + if (!SMTPD_DNSXL_STAT_OK(rbl)) { return (SMTPD_CHECK_DUNNO); } else { - vstring_free(query); return (rbl_reject_reply(state, rbl, rbl_domain, what, reply_class)); } } +/* permit_dnswl_domain - permit domain in DNSWL */ + +static int permit_dnswl_domain(SMTPD_STATE *state, const char *dnswl_domain, + const char *what, const char *reply_class) +{ + const char *myname = "permit_dnswl_domain"; + const SMTPD_RBL_STATE *dnswl_result; + + if (msg_verbose) + msg_info("%s: %s", myname, what); + + /* Safety: don't whitelist unauthorized recipients. */ + if (strcmp(state->where, SMTPD_CMD_RCPT) == 0 && state->recipient != 0 + && permit_auth_destination(state, state->recipient) != SMTPD_CHECK_OK) + return (SMTPD_CHECK_DUNNO); + + dnswl_result = find_dnsxl_domain(state, dnswl_domain, what); + if (SMTPD_DNXSL_STAT_HARD(dnswl_result)) { + return (SMTPD_CHECK_DUNNO); + } else if (SMTPD_DNSXL_STAT_SOFT(dnswl_result)) { + /* XXX: Make configurable as rhswl_tempfail_action. */ + DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY, + 450, "4.7.1", + "<%s>: %s rejected: %s", + what, reply_class, + "Service unavailable"); + return (SMTPD_CHECK_DUNNO); + } else if (SMTPD_DNSXL_STAT_OK(dnswl_result)) { + return (SMTPD_CHECK_OK); + } else { + /* Future proofing, in case find_dnsxl_addr() result is changed. */ + msg_panic("%s: find_dnsxl_addr API failure", myname); + } +} + /* reject_maps_rbl - reject if client address in real-time blackhole list */ static int reject_maps_rbl(SMTPD_STATE *state) @@ -3680,6 +3789,12 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, else status = reject_rbl_addr(state, *(cpp += 1), state->addr, SMTPD_NAME_CLIENT); + } else if (strcasecmp(name, PERMIT_DNSWL_CLIENT) == 0) { + if (cpp[1] == 0) + msg_warn("restriction %s requires domain name argument", name); + else + status = permit_dnswl_addr(state, *(cpp += 1), state->addr, + SMTPD_NAME_CLIENT); } else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) { if (cpp[1] == 0) msg_warn("restriction %s requires domain name argument", @@ -3690,6 +3805,16 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, status = reject_rbl_domain(state, *cpp, state->name, SMTPD_NAME_CLIENT); } + } else if (strcasecmp(name, PERMIT_RHSWL_CLIENT) == 0) { + if (cpp[1] == 0) + msg_warn("restriction %s requires domain name argument", + name); + else { + cpp += 1; + if (strcasecmp(state->name, "unknown") != 0) + status = permit_dnswl_domain(state, *cpp, state->name, + SMTPD_NAME_CLIENT); + } } else if (strcasecmp(name, REJECT_RHSBL_REVERSE_CLIENT) == 0) { if (cpp[1] == 0) msg_warn("restriction %s requires domain name argument", @@ -4979,7 +5104,7 @@ static const INT_TABLE int_table[] = { VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table, - VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, + VAR_VERIFY_POLL_COUNT, 3, &var_verify_poll_count, VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from, VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt, VAR_PLAINTEXT_CODE, DEF_PLAINTEXT_CODE, &var_plaintext_code, @@ -5238,6 +5363,12 @@ int main(int argc, char **argv) resp = "bad command"; switch (args->argc) { + /* + * Emtpy line. + */ + case 0: + continue; + /* * Special case: client identity. */ diff --git a/postfix/src/smtpd/smtpd_dnswl.in b/postfix/src/smtpd/smtpd_dnswl.in new file mode 100644 index 000000000..891e0c75f --- /dev/null +++ b/postfix/src/smtpd/smtpd_dnswl.in @@ -0,0 +1,56 @@ +# +# Initialize. +# +#msg_verbose 1 +smtpd_delay_reject 0 +mynetworks 127.0.0.0/8,168.100.189.0/28 +mydestination porcupine.org +relay_domains porcupine.org +helo foobar + +# +# DNSWL (by IP address) +# + +# Whitelist overrides reject. +client_restrictions permit_dnswl_client,wild.porcupine.org,reject +client spike.porcupine.org 168.100.189.2 + +# Whitelist does not fire - reject. +client_restrictions permit_dnswl_client,porcupine.org,reject +client spike.porcupine.org 168.100.189.2 + +# Whitelist does not override reject_unauth_destination. +client_restrictions permit +recipient_restrictions permit_dnswl_client,wild.porcupine.org,reject_unauth_destination +# Unauthorized destination - reject. +rcpt rname@rdomain +# Authorized destination - accept. +rcpt wietse@porcupine.org + +# +# RHSWL (by domain name) +# + +# Whitelist overrides reject. +client_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject +# Non-whitelisted client name - reject. +client spike.porcupine.org 168.100.189.2 +# Whitelisted client name - accept. +client example.tld 168.100.189.2 + +# Whitelist does not override reject_unauth_destination. +client_restrictions permit +recipient_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject_unauth_destination +# Non-whitelisted client name. +client spike.porcupine.org 168.100.189.2 +# Unauthorized destination - reject. +rcpt rname@rdomain +# Authorized destination - accept. +rcpt wietse@porcupine.org +# Whitelisted client name. +client example.tld 168.100.189.2 +# Unauthorized destination - reject. +rcpt rname@rdomain +# Authorized destination - accept. +rcpt wietse@porcupine.org diff --git a/postfix/src/smtpd/smtpd_dnswl.ref b/postfix/src/smtpd/smtpd_dnswl.ref new file mode 100644 index 000000000..fc8940546 --- /dev/null +++ b/postfix/src/smtpd/smtpd_dnswl.ref @@ -0,0 +1,85 @@ +>>> # +>>> # Initialize. +>>> # +>>> #msg_verbose 1 +>>> smtpd_delay_reject 0 +OK +>>> mynetworks 127.0.0.0/8,168.100.189.0/28 +OK +>>> mydestination porcupine.org +OK +>>> relay_domains porcupine.org +OK +>>> helo foobar +OK +>>> +>>> # +>>> # DNSWL (by IP address) +>>> # +>>> +>>> # Whitelist overrides reject. +>>> client_restrictions permit_dnswl_client,wild.porcupine.org,reject +OK +>>> client spike.porcupine.org 168.100.189.2 +OK +>>> +>>> # Whitelist does not fire - reject. +>>> client_restrictions permit_dnswl_client,porcupine.org,reject +OK +>>> client spike.porcupine.org 168.100.189.2 +./smtpd_check: : reject: CONNECT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 : Client host rejected: Access denied; proto=SMTP helo= +554 5.7.1 : Client host rejected: Access denied +>>> +>>> # Whitelist does not override reject_unauth_destination. +>>> client_restrictions permit +OK +>>> recipient_restrictions permit_dnswl_client,wild.porcupine.org,reject_unauth_destination +OK +>>> # Unauthorized destination - reject. +>>> rcpt rname@rdomain +./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 : Relay access denied; to= proto=SMTP helo= +554 5.7.1 : Relay access denied +>>> # Authorized destination - accept. +>>> rcpt wietse@porcupine.org +OK +>>> +>>> # +>>> # RHSWL (by domain name) +>>> # +>>> +>>> # Whitelist overrides reject. +>>> client_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject +OK +>>> # Non-whitelisted client name - reject. +>>> client spike.porcupine.org 168.100.189.2 +./smtpd_check: : reject: CONNECT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 : Client host rejected: Access denied; proto=SMTP helo= +554 5.7.1 : Client host rejected: Access denied +>>> # Whitelisted client name - accept. +>>> client example.tld 168.100.189.2 +OK +>>> +>>> # Whitelist does not override reject_unauth_destination. +>>> client_restrictions permit +OK +>>> recipient_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject_unauth_destination +OK +>>> # Non-whitelisted client name. +>>> client spike.porcupine.org 168.100.189.2 +OK +>>> # Unauthorized destination - reject. +>>> rcpt rname@rdomain +./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 : Relay access denied; to= proto=SMTP helo= +554 5.7.1 : Relay access denied +>>> # Authorized destination - accept. +>>> rcpt wietse@porcupine.org +OK +>>> # Whitelisted client name. +>>> client example.tld 168.100.189.2 +OK +>>> # Unauthorized destination - reject. +>>> rcpt rname@rdomain +./smtpd_check: : reject: RCPT from example.tld[168.100.189.2]: 554 5.7.1 : Relay access denied; to= proto=SMTP helo= +554 5.7.1 : Relay access denied +>>> # Authorized destination - accept. +>>> rcpt wietse@porcupine.org +OK