]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.12-20141130
authorWietse Venema <wietse@porcupine.org>
Sun, 30 Nov 2014 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 1 Dec 2014 16:18:16 +0000 (11:18 -0500)
49 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/lmtp.8.html
postfix/html/postconf.5.html
postfix/html/postscreen.8.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/man/man5/postconf.5
postfix/man/man8/postscreen.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/src/dns/Makefile.in
postfix/src/dns/dns.h
postfix/src/dns/dns_lookup.c
postfix/src/dns/dns_rr_filter.c [new file with mode: 0644]
postfix/src/dns/dns_strrecord.c [new file with mode: 0644]
postfix/src/dns/error.ref [new file with mode: 0644]
postfix/src/dns/error.reg [new file with mode: 0644]
postfix/src/dns/mxonly_test.ref
postfix/src/dns/no-a.ref [new file with mode: 0644]
postfix/src/dns/no-a.reg [new file with mode: 0644]
postfix/src/dns/no-aaaa.ref [new file with mode: 0644]
postfix/src/dns/no-aaaa.reg [new file with mode: 0644]
postfix/src/dns/no-mx.ref [new file with mode: 0644]
postfix/src/dns/no-mx.reg [new file with mode: 0644]
postfix/src/dns/no-txt.reg [new file with mode: 0644]
postfix/src/dns/nullmx_test.ref
postfix/src/dns/test_dns_lookup.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_params.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_check_access
postfix/src/smtpd/smtpd_dns_filter.in [new file with mode: 0644]
postfix/src/smtpd/smtpd_dns_filter.ref [new file with mode: 0644]
postfix/src/smtpd/smtpd_dnswl.in
postfix/src/smtpd/smtpd_dnswl.ref
postfix/src/smtpd/smtpd_exp.in
postfix/src/smtpd/smtpd_exp.ref
postfix/src/smtpd/smtpd_resolve.c
postfix/src/smtpd/smtpd_server.in
postfix/src/smtpd/smtpd_server.ref

index 97c7109f37dc37ab84feaae11b155453abd79859..0c816b905eb018ddfcc340ce76eefa7228b14240 100644 (file)
@@ -20834,7 +20834,7 @@ Apologies for any names omitted.
        reject_unknown_sender/recipient_domain. This introduces a
        new SMTP server configuration parameter nullmx_reject_code
        (default: 556).  Files: src/dns/dns_lookup.[hc], dns/Makefile,in,
-       dns/nullmx_test.ref, src/smtp/smtp_addr.c, src/smtpd/smtpd_check.c,
+       dns/nullmx_test.ref, src/smtp/smtp_addr.c, smtpd/smtpd_check.c,
        smtpd/smtpd_check_nullmx.in, smtpd/smtpd_check_nullmx.ref,
        mantools/postlink, proto/postconf.proto, smtpd/smtpd.c.
 
@@ -20843,3 +20843,28 @@ Apologies for any names omitted.
 
        Cleanup: libglobal "make test" had suffered from bitrot.
        Files: global/mime_state.c, global/header_body_checks.c.
+
+20141127
+
+       Feature: DNS reply filter, configured with smtp_dns_reply_filter,
+       smtpd_dns_reply_filter, and lmtp_dns_reply_filter. Files:
+       mantools/postlink, proto/postconf.proto, dns/dns.h,
+       dns/dns_lookup.c, dns/dns_rr_filter.c, dns/dns_strrecord.c,
+       dns/error.ref, dns/error.reg, dns/mxonly_test.ref, dns/no-a.ref,
+       dns/no-a.reg, dns/no-aaaa.ref, dns/no-aaaa.reg, dns/no-mx.ref,
+       dns/no-mx.reg, dns/nullmx_test.ref, dns/test_dns_lookup.c,
+       global/mail_params.h, smtp/lmtp_params.c, smtp/smtp.c,
+       smtp/smtp_addr.c, smtp/smtp_params.c, smtpd/smtpd.c,
+       smtpd/smtpd_check.c, smtpd/smtpd_dns_filter.{in,ref}.
+
+20141130
+
+       Cleanup: when searching multiple DNS record types for a
+       specific name, and the result status is not DNS_OK, return
+       the rcode and diagnostic text for that status instead of
+       the last rcode and last diagnostic text.
+
+       Cleanup: un-broke several smtpd regression tests (work in
+       progress, with three more to go).  Files: smtpd/smtpd_check.c,
+       smtpd/smtpd_server.{in,ref}, smtpd/smtpd_exp.{in,ref}.
+       smtpd/smtpd_dnswl.{in,ref}.
index 585c45dfd72dee888f75aa06ac2ea3f0581a13ed..0f097a22806c858bc61be3621f89ed69a829ade9 100644 (file)
@@ -59,6 +59,40 @@ Maintainers may also benefit from the makedefs documentation
 (mantools/srctoman - makedefs | nroff -man | less) with information
 about build options that are not described in the INSTALL instructions.
 
+Major changes with snapshot 20141128
+====================================
+
+Support for DNS server reply filters in the Postfix SMTP client
+and server. This renders the result in standard zone file format:
+
+    name ttl class type preference value
+
+The class field is always "IN", the preference field exists only
+for MX records, the names of hosts, domains, etc. end in ".", and
+those names are in ASCII form (xn--mumble form in the case of UTF8
+names).
+
+When a match is found, the table lookup result specifies an action.
+By default, the table query and the action name are case-insensitive.
+Currently, only the IGNORE action is implemented.
+
+For safety reasons, Postfix logs a warning or defers mail delivery
+when a filter removes all lookup results from a successful query.
+
+The smtp_dns_reply_filter and lmtp_dns_reply_filter features are
+used only for Postfix SMTP client lookups of MX, A, and AAAAA records
+to locate a remote SMTP or LMTP server, including lookups that are
+made to implement the features reject_unverified_sender and
+reject_unverified_recipient.
+
+The smtpd_dns_reply_filter feature is used only for Postfix SMTP
+server lookups of MX, A, AAAAA, and TXT records to implement the
+features reject_unknown_helo_hostname, reject_unknown_sender_domain,
+reject_unknown_recipient_domain, reject_rbl_*, and reject_rhsbl_*.
+
+Implicit DNS lookups through nsswitch.conf or equivalent mechanisms
+are not filtered.
+
 Major changes with snapshot 20141126
 ====================================
 
index f07bc31f16c112485da0aca4733ae6e4f798cb45..12e631e4cec872d57e38e412352ab53c00d0dcea 100644 (file)
@@ -299,6 +299,9 @@ SMTP(8)                                                                SMTP(8)
               delivery status code or explanatory text of successful or unsuc-
               cessful deliveries.
 
+       <b><a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> ($<a href="postconf.5.html#default_dns_reply_filter">default_dns_reply_filter</a>)</b>
+              Optional filter for Postfix SMTP client DNS lookup results.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
index 6a7ecf623e759e33cc2392556fd5c9ec1160d40d..b8e3b0188a98444db4c343f2f79ca613b83f9b7c 100644 (file)
@@ -4344,6 +4344,17 @@ discard LHLO keywords selectively. </p>
 </ul>
 
 
+</DD>
+
+<DT><b><a name="lmtp_dns_reply_filter">lmtp_dns_reply_filter</a>
+(default: empty)</b></DT><DD>
+
+<p> Optional filter for Postfix LMTP client DNS lookup results.
+See <a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> for details including an example.  </p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_dns_resolver_options">lmtp_dns_resolver_options</a>
@@ -7169,8 +7180,8 @@ Examples:
 <p> The numerical reply code when the Postfix SMTP server rejects
 a sender or recipient address because its domain has a nullmx DNS
 record (an MX record with an empty hostname). This is one of the
-possible replies from <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> and
-<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>. </p>
+possible replies from the restrictions <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>
+and <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>. </p>
 
 <p> This feature is available in Postfix 2.12 and later. </p>
 
@@ -10294,6 +10305,77 @@ discard EHLO keywords selectively. </p>
 </ul>
 
 
+</DD>
+
+<DT><b><a name="smtp_dns_reply_filter">smtp_dns_reply_filter</a>
+(default: empty)</b></DT><DD>
+
+<p> Optional filter for Postfix SMTP client DNS lookup results.
+Specify zero or more lookup tables.  The lookup tables are searched
+in the given order for a match with the DNS lookup result, converted
+to the following form: </p>
+
+<pre>
+    <i>name ttl class type preference value</i>
+</pre>
+
+<p> The <i>class</i> field is always "IN", the <i>preference</i>
+field exists only for MX records, the names of hosts, domains, etc.
+end in ".", and those names are in ASCII form (xn--mumble form in
+the case of UTF8 names).  </p>
+
+<p> When a match is found, the table lookup result specifies an
+action.  By default, the table query and the action name are
+case-insensitive.  Currently, only the <b>IGNORE</b> action is
+implemented.  </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> The <a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> and <a href="postconf.5.html#lmtp_dns_reply_filter">lmtp_dns_reply_filter</a> features
+are used only for Postfix SMTP or LMTP client DNS lookups of MX,
+A, and AAAAA records to locate a remote SMTP or LMTP server, including
+lookups that are made to implement the features <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a>
+and <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>. </p>
+
+<li> <p> The Postfix SMTP or LMTP client defers mail delivery when
+a filter removes all lookup results from a successful query.  </p>
+
+<li> <p> The <a href="postconf.5.html#smtpd_dns_reply_filter">smtpd_dns_reply_filter</a> feature is used only for Postfix
+SMTP server DNS lookups of MX, A, AAAAA, and TXT records to implement
+the features <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a>, <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>,
+<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>, reject_rbl_*, and reject_rhsbl_*.
+</p>
+
+<li> <p> The Postfix SMTP server logs a warning or defers mail
+delivery when a filter removes all lookup results from a successful
+query.  </p>
+
+<li> <p> Implicit DNS lookups through nsswitch.conf or equivalent
+mechanisms are not filtered.  </p>
+
+</ul>
+
+<p> Example: ignore Google AAAA records in Postfix SMTP client DNS
+lookups, because Google sometimes hard-rejects mail from IPv6 clients
+with valid PTR etc. records. </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> = <a href="pcre_table.5.html">pcre</a>:/etc/postfix/smtp_dns_reply_filter
+</pre>
+
+<pre>
+/etc/postfix/smtp_dns_reply_filter:
+    # /domain ttl IN AAAA address/ action, all case-insensitive.
+    # Note: the domain name ends in ".".
+    /^\S+\.google.com\.\s+\S+\s+\S+\s+AAAA\s+/ IGNORE
+</pre>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_dns_resolver_options">smtp_dns_resolver_options</a>
@@ -10515,7 +10597,7 @@ that change the delivery time or destination are not available.
 (default: $<a href="postconf.5.html#myhostname">myhostname</a>)</b></DT><DD>
 
 <p>
-The hostname to send in the SMTP EHLO or HELO command.
+The hostname to send in the SMTP HELO or EHLO command.
 </p>
 
 <p>
@@ -13508,7 +13590,7 @@ that improperly uses ESMTP command pipelining in order to speed up
 deliveries.
 <br> With Postfix 2.6 and later, the SMTP server sets a per-session
 flag whenever it detects illegal pipelining, including pipelined
-EHLO or HELO commands. The <a href="postconf.5.html#reject_unauth_pipelining">reject_unauth_pipelining</a> feature simply
+HELO or EHLO commands. The <a href="postconf.5.html#reject_unauth_pipelining">reject_unauth_pipelining</a> feature simply
 tests whether the flag was set at any point in time during the
 session.
 <br> With older Postfix versions, <a href="postconf.5.html#reject_unauth_pipelining">reject_unauth_pipelining</a> checks
@@ -13796,6 +13878,18 @@ to discard EHLO keywords selectively.  </p>
 </ul>
 
 
+</DD>
+
+<DT><b><a name="smtpd_dns_reply_filter">smtpd_dns_reply_filter</a>
+(default: empty)</b></DT><DD>
+
+<p> Optional filter for Postfix SMTP server DNS lookup results.
+See <a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> for details including an example.
+</p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a>
@@ -14103,11 +14197,11 @@ and later.  </dd>
 <dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix &lt; 2.3: reject_unknown_hostname)</dt>
 
 <dd>Reject the request when the HELO or EHLO hostname has no DNS A
-or MX record. <br> The <a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> parameter
-specifies the numerical response code for rejected requests (default:
-450). <br> The <a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a> parameter
-specifies the action after a temporary DNS error (default:
-<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>). Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully
+or MX record. <br> The reply is specified with the
+<a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> parameter (default: 450) or
+<a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a> (default: <a href="postconf.5.html#defer_if_permit">defer_if_permit</a>).
+See the respective parameter descriptions for details. <br>
+Note: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully
 enforce this restriction (without "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes", a
 client can simply skip <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> by not sending
 HELO or EHLO). </dd>
@@ -14691,13 +14785,11 @@ the recipient domain, and the RCPT TO domain has 1) no DNS MX and
 no DNS A
 record or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later). <br> The
-<a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies the numerical
-response code for rejected requests (default: 450). The <a href="postconf.5.html#nullmx_reject_code">nullmx_reject_code</a>
-parameter specifies the response code for domains with a nullmx
-DNS record (default: 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error. <br> The
-<a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> parameter specifies the action
-after a temporary DNS error (default: <a href="postconf.5.html#defer_if_permit">defer_if_permit</a>).  </dd>
+reply is specified with the <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter
+(default: 450), <a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> (default:
+<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>), or <a href="postconf.5.html#nullmx_reject_code">nullmx_reject_code</a> (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
+</dd>
 
 <dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix version 2.0: check_recipient_maps)</dt>
 
@@ -15437,13 +15529,11 @@ the sender address, and the MAIL FROM domain has 1) no DNS MX and
 no DNS A
 record, or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later). <br> The
-<a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter specifies the numerical
-response code for rejected requests (default: 450). The <a href="postconf.5.html#nullmx_reject_code">nullmx_reject_code</a>
-parameter specifies the response code for domains with a nullmx
-DNS record (default 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error. <br> The
-<a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> parameter specifies the action
-after a temporary DNS error (default: <a href="postconf.5.html#defer_if_permit">defer_if_permit</a>). </dd>
+reply is specified with the <a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> parameter
+(default: 450), <a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> (default:
+<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>), or <a href="postconf.5.html#nullmx_reject_code">nullmx_reject_code</a> (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
+</dd>
 
 <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>
 
@@ -18389,12 +18479,10 @@ specify an empty value to disable this feature.  </p>
 (default: 450)</b></DT><DD>
 
 <p>
-The numerical Postfix SMTP server response code when a sender or
-recipient address is rejected by the <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>
-or <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction. The <a href="postconf.5.html#nullmx_reject_code">nullmx_reject_code</a>
-is used for domains with a nullmx DNS record (Postfix 2.12 and
-later).  The response is always 450 in case of a temporary DNS
-error.
+The numerical response code when the Postfix SMTP server rejects a
+sender or recipient address because its domain is unknown.  This
+is one of the possible replies from the restrictions
+<a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> and <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>.
 </p>
 
 <p>
index 13460cb49b7eb38ec1c978de062757fd90a76bd1..560191ecd7033be1857f5fd2bee7df0e781c81e1 100644 (file)
@@ -391,6 +391,11 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               syslog records, so that "smtpd"  becomes,  for  example,  "post-
               fix/smtpd".
 
+       Available in Postfix version 2.12 and later:
+
+       <b><a href="postconf.5.html#postscreen_dns_reply_filter">postscreen_dns_reply_filter</a> ($<a href="postconf.5.html#default_dns_reply_filter">default_dns_reply_filter</a>)</b>
+              Optional filter for <a href="postscreen.8.html"><b>postscreen</b>(8)</a> DNS lookup results.
+
 <b>SEE ALSO</b>
        <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
        <a href="tlsproxy.8.html">tlsproxy(8)</a>, Postfix TLS proxy server
index f07bc31f16c112485da0aca4733ae6e4f798cb45..12e631e4cec872d57e38e412352ab53c00d0dcea 100644 (file)
@@ -299,6 +299,9 @@ SMTP(8)                                                                SMTP(8)
               delivery status code or explanatory text of successful or unsuc-
               cessful deliveries.
 
+       <b><a href="postconf.5.html#smtp_dns_reply_filter">smtp_dns_reply_filter</a> ($<a href="postconf.5.html#default_dns_reply_filter">default_dns_reply_filter</a>)</b>
+              Optional filter for Postfix SMTP client DNS lookup results.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
index 0968fd182686066733539f38f03e6267eedcc082..eb8b00da59467c798b5c1fdffee1c8478379d39d 100644 (file)
@@ -152,6 +152,11 @@ SMTPD(8)                                                              SMTPD(8)
               record  (an  SMTP command line, SMTP response line, SMTP message
               content line, or TLS protocol message).
 
+       Available in Postfix version 2.12 and later:
+
+       <b><a href="postconf.5.html#smtpd_dns_reply_filter">smtpd_dns_reply_filter</a> (empty)</b>
+              Optional filter for Postfix SMTP server DNS lookup results.
+
 <b>ADDRESS REWRITING CONTROLS</b>
        See the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> document for a detailed discussion  of
        Postfix address rewriting.
@@ -1097,10 +1102,8 @@ SMTPD(8)                                                              SMTPD(8)
               restriction.
 
        <b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
-              The numerical Postfix SMTP server response code when a sender or
-              recipient      address      is       rejected       by       the
-              <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>  or <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>
-              restriction.
+              The  numerical  response  code  when  the Postfix SMTP rejects a
+              sender or recipient address because its domain is unknown.
 
        <b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
               The numerical Postfix SMTP server response code  when  a  client
index dc7b02b0a19ea42ae2fe306620eb39bd7cd67333..d39d6925166691dfce72b6a1445401c2a8e31fd2 100644 (file)
@@ -2646,6 +2646,11 @@ this action from being logged.
 Use the lmtp_discard_lhlo_keyword_address_maps feature to
 discard LHLO keywords selectively.
 .br
+.SH lmtp_dns_reply_filter (default: empty)
+Optional filter for Postfix LMTP client DNS lookup results.
+See smtp_dns_reply_filter for details including an example.
+.PP
+This feature is available in Postfix 2.12 and later.
 .SH lmtp_dns_resolver_options (default: empty)
 The LMTP-specific version of the smtp_dns_resolver_options
 configuration parameter.  See there for details.
@@ -4349,8 +4354,8 @@ notify_classes = 2bounce, resource, software
 The numerical reply code when the Postfix SMTP server rejects
 a sender or recipient address because its domain has a nullmx DNS
 record (an MX record with an empty hostname). This is one of the
-possible replies from reject_unknown_sender_domain and
-reject_unknown_recipient_domain.
+possible replies from the restrictions reject_unknown_sender_domain
+and reject_unknown_recipient_domain.
 .PP
 This feature is available in Postfix 2.12 and later.
 .SH owner_request_special (default: yes)
@@ -6363,6 +6368,79 @@ this action from being logged.
 Use the smtp_discard_ehlo_keyword_address_maps feature to
 discard EHLO keywords selectively.
 .br
+.SH smtp_dns_reply_filter (default: empty)
+Optional filter for Postfix SMTP client DNS lookup results.
+Specify zero or more lookup tables.  The lookup tables are searched
+in the given order for a match with the DNS lookup result, converted
+to the following form:
+.PP
+.nf
+.na
+.ft C
+    \fIname ttl class type preference value\fR
+.fi
+.ad
+.ft R
+.PP
+The \fIclass\fR field is always "IN", the \fIpreference\fR
+field exists only for MX records, the names of hosts, domains, etc.
+end in ".", and those names are in ASCII form (xn--mumble form in
+the case of UTF8 names).
+.PP
+When a match is found, the table lookup result specifies an
+action.  By default, the table query and the action name are
+case-insensitive.  Currently, only the \fBIGNORE\fR action is
+implemented.
+.PP
+Notes:
+.IP \(bu
+The smtp_dns_reply_filter and lmtp_dns_reply_filter features
+are used only for Postfix SMTP or LMTP client DNS lookups of MX,
+A, and AAAAA records to locate a remote SMTP or LMTP server, including
+lookups that are made to implement the features reject_unverified_sender
+and reject_unverified_recipient.
+.IP \(bu
+The Postfix SMTP or LMTP client defers mail delivery when
+a filter removes all lookup results from a successful query.
+.IP \(bu
+The smtpd_dns_reply_filter feature is used only for Postfix
+SMTP server DNS lookups of MX, A, AAAAA, and TXT records to implement
+the features reject_unknown_helo_hostname, reject_unknown_sender_domain,
+reject_unknown_recipient_domain, reject_rbl_*, and reject_rhsbl_*.
+.IP \(bu
+The Postfix SMTP server logs a warning or defers mail
+delivery when a filter removes all lookup results from a successful
+query.
+.IP \(bu
+Implicit DNS lookups through nsswitch.conf or equivalent
+mechanisms are not filtered.
+.br
+.PP
+Example: ignore Google AAAA records in Postfix SMTP client DNS
+lookups, because Google sometimes hard-rejects mail from IPv6 clients
+with valid PTR etc. records.
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    smtp_dns_reply_filter = pcre:/etc/postfix/smtp_dns_reply_filter
+.fi
+.ad
+.ft R
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/smtp_dns_reply_filter:
+    # /domain ttl IN AAAA address/ action, all case-insensitive.
+    # Note: the domain name ends in ".".
+    /^\eS+\e.google.com\e.\es+\eS+\es+\eS+\es+AAAA\es+/ IGNORE
+.fi
+.ad
+.ft R
+.PP
+This feature is available in Postfix 2.12 and later.
 .SH smtp_dns_resolver_options (default: empty)
 DNS Resolver options for the Postfix SMTP client.  Specify zero
 or more of the following options, separated by comma or whitespace.
@@ -6528,7 +6606,7 @@ that change the delivery time or destination are not available.
 .PP
 This feature is available in Postfix 2.5 and later.
 .SH smtp_helo_name (default: $myhostname)
-The hostname to send in the SMTP EHLO or HELO command.
+The hostname to send in the SMTP HELO or EHLO command.
 .PP
 The default value is the machine hostname.  Specify a hostname or
 [ip.add.re.ss].
@@ -8954,7 +9032,7 @@ deliveries.
 .br
 With Postfix 2.6 and later, the SMTP server sets a per-session
 flag whenever it detects illegal pipelining, including pipelined
-EHLO or HELO commands. The reject_unauth_pipelining feature simply
+HELO or EHLO commands. The reject_unauth_pipelining feature simply
 tests whether the flag was set at any point in time during the
 session.
 .br
@@ -9201,6 +9279,11 @@ this action from being logged.
 Use the smtpd_discard_ehlo_keyword_address_maps feature
 to discard EHLO keywords selectively.
 .br
+.SH smtpd_dns_reply_filter (default: empty)
+Optional filter for Postfix SMTP server DNS lookup results.
+See smtp_dns_reply_filter for details including an example.
+.PP
+This feature is available in Postfix 2.12 and later.
 .SH smtpd_end_of_data_restrictions (default: empty)
 Optional access restrictions that the Postfix SMTP server
 applies in the context of the SMTP END-OF-DATA command.
@@ -9406,13 +9489,12 @@ and later.
 Reject the request when the HELO or EHLO hostname has no DNS A
 or MX record.
 .br
-The unknown_hostname_reject_code parameter
-specifies the numerical response code for rejected requests (default:
-450).
+The reply is specified with the
+unknown_hostname_reject_code parameter (default: 450) or
+unknown_helo_hostname_tempfail_action (default: defer_if_permit).
+See the respective parameter descriptions for details.
 .br
-The unknown_helo_hostname_tempfail_action parameter
-specifies the action after a temporary DNS error (default:
-defer_if_permit). Note: specify "smtpd_helo_required = yes" to fully
+Note: specify "smtpd_helo_required = yes" to fully
 enforce this restriction (without "smtpd_helo_required = yes", a
 client can simply skip reject_unknown_helo_hostname by not sending
 HELO or EHLO).
@@ -9807,15 +9889,10 @@ record or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later).
 .br
 The
-unknown_address_reject_code parameter specifies the numerical
-response code for rejected requests (default: 450). The nullmx_reject_code
-parameter specifies the response code for domains with a nullmx
-DNS record (default: 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error.
-.br
-The
-unknown_address_tempfail_action parameter specifies the action
-after a temporary DNS error (default: defer_if_permit).
+reply is specified with the unknown_address_reject_code parameter
+(default: 450), unknown_address_tempfail_action (default:
+defer_if_permit), or nullmx_reject_code (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
 .br
 .IP "\fBreject_unlisted_recipient\fR (with Postfix version 2.0: check_recipient_maps)"
 Reject the request when the RCPT TO address is not listed in
@@ -10392,15 +10469,10 @@ record, or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later).
 .br
 The
-unknown_address_reject_code parameter specifies the numerical
-response code for rejected requests (default: 450). The nullmx_reject_code
-parameter specifies the response code for domains with a nullmx
-DNS record (default 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error.
-.br
-The
-unknown_address_tempfail_action parameter specifies the action
-after a temporary DNS error (default: defer_if_permit).
+reply is specified with the unknown_address_reject_code parameter
+(default: 450), unknown_address_tempfail_action (default:
+defer_if_permit), or nullmx_reject_code (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
 .br
 .IP "\fBreject_unlisted_sender\fR"
 Reject the request when the MAIL FROM address is not listed in
@@ -12581,12 +12653,10 @@ undisclosed_recipients_header = To: undisclosed-recipients:;
 .ad
 .ft R
 .SH unknown_address_reject_code (default: 450)
-The numerical Postfix SMTP server response code when a sender or
-recipient address is rejected by the reject_unknown_sender_domain
-or reject_unknown_recipient_domain restriction. The nullmx_reject_code
-is used for domains with a nullmx DNS record (Postfix 2.12 and
-later).  The response is always 450 in case of a temporary DNS
-error.
+The numerical response code when the Postfix SMTP server rejects a
+sender or recipient address because its domain is unknown.  This
+is one of the possible replies from the restrictions
+reject_unknown_sender_domain and reject_unknown_recipient_domain.
 .PP
 Do not change this unless you have a complete understanding of RFC 5321.
 .SH unknown_address_tempfail_action (default: $reject_tempfail_action)
index fd06da2add845cf7f44b2bd22a2e5ebf767463df..e4beb535911b738bef044f3d1eba54a134ad2799 100644 (file)
@@ -398,6 +398,10 @@ The syslog facility of Postfix logging.
 .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
 The mail system name that is prepended to the process name in syslog
 records, so that "smtpd" becomes, for example, "postfix/smtpd".
+.PP
+Available in Postfix version 2.12 and later:
+.IP "\fBpostscreen_dns_reply_filter ($default_dns_reply_filter)\fR"
+Optional filter for \fBpostscreen\fR(8) DNS lookup results.
 .SH "SEE ALSO"
 .na
 .nf
index c0c3ed2bc72fd809f6b7597950828afdb85057d5..ffcac6c9cd9635b1cb366179277c1ae12006f4b0 100644 (file)
@@ -282,6 +282,8 @@ Available in Postfix version 2.12 and later:
 Optional filter for the \fBsmtp\fR(8) delivery agent to change the
 delivery status code or explanatory text of successful or unsuccessful
 deliveries.
+.IP "\fBsmtp_dns_reply_filter ($default_dns_reply_filter)\fR"
+Optional filter for Postfix SMTP client DNS lookup results.
 .SH "MIME PROCESSING CONTROLS"
 .na
 .nf
index cbaa577c704e8d39ffa17e3d43f69911e8f9fbc9..d0082f3133b9ee33c9f01044324766bc5a85fdf9 100644 (file)
@@ -153,6 +153,10 @@ time limits, from a
 time limit per read or write system call, to a time limit to send
 or receive a complete record (an SMTP command line, SMTP response
 line, SMTP message content line, or TLS protocol message).
+.PP
+Available in Postfix version 2.12 and later:
+.IP "\fBsmtpd_dns_reply_filter (empty)\fR"
+Optional filter for Postfix SMTP server DNS lookup results.
 .SH "ADDRESS REWRITING CONTROLS"
 .na
 .nf
@@ -963,9 +967,8 @@ The numerical Postfix SMTP server response code when a client
 request is rejected by the reject_unauth_destination recipient
 restriction.
 .IP "\fBunknown_address_reject_code (450)\fR"
-The numerical Postfix SMTP server response code when a sender or
-recipient address is rejected by the reject_unknown_sender_domain
-or reject_unknown_recipient_domain restriction.
+The numerical response code when the Postfix SMTP rejects a sender
+or recipient address because its domain is unknown.
 .IP "\fBunknown_client_reject_code (450)\fR"
 The numerical Postfix SMTP server response code when a client
 without valid address <=> name mapping is rejected by the
index 9ad06ed01612eee4d7c4858e573dea58d9052014..c1e47293e8a8525aede6de8918630d4832821eb7 100755 (executable)
@@ -480,6 +480,9 @@ while (<>) {
     s;\bsmtp_discard_ehlo_keywords\b;<a href="postconf.5.html#smtp_discard_ehlo_keywords">$&</a>;g;
     s;\bsmtp_dns_resolver_options\b;<a href="postconf.5.html#smtp_dns_resolver_options">$&</a>;g;
     s;\bsmtp_dns_support_level\b;<a href="postconf.5.html#smtp_dns_support_level">$&</a>;g;
+    s;\blmtp_dns_reply_filter\b;<a href="postconf.5.html#lmtp_dns_reply_filter">$&</a>;g;
+    s;\bsmtp_dns_reply_filter\b;<a href="postconf.5.html#smtp_dns_reply_filter">$&</a>;g;
+    s;\bsmtpd_dns_reply_filter\b;<a href="postconf.5.html#smtpd_dns_reply_filter">$&</a>;g;
     s;\bsmtp_helo_name\b;<a href="postconf.5.html#smtp_helo_name">$&</a>;g;
     s;\bsmtp_helo_timeout\b;<a href="postconf.5.html#smtp_helo_timeout">$&</a>;g;
     s;\bsmtp_host_lookup\b;<a href="postconf.5.html#smtp_host_lookup">$&</a>;g;
index 6476d1444d8c2ba837040bc6ae307db5dbcd3c25..8816efc870173ab01f4c7c82ad896df5cba3257c 100644 (file)
@@ -4272,7 +4272,7 @@ into concurrency per recipient.  </p>
 %PARAM smtp_helo_name $myhostname
 
 <p>
-The hostname to send in the SMTP EHLO or HELO command.
+The hostname to send in the SMTP HELO or EHLO command.
 </p>
 
 <p>
@@ -5343,7 +5343,7 @@ that improperly uses ESMTP command pipelining in order to speed up
 deliveries. 
 <br> With Postfix 2.6 and later, the SMTP server sets a per-session
 flag whenever it detects illegal pipelining, including pipelined
-EHLO or HELO commands. The reject_unauth_pipelining feature simply
+HELO or EHLO commands. The reject_unauth_pipelining feature simply
 tests whether the flag was set at any point in time during the
 session.
 <br> With older Postfix versions, reject_unauth_pipelining checks
@@ -5712,11 +5712,11 @@ and later.  </dd>
 <dt><b><a name="reject_unknown_helo_hostname">reject_unknown_helo_hostname</a></b> (with Postfix &lt; 2.3: reject_unknown_hostname)</dt>
 
 <dd>Reject the request when the HELO or EHLO hostname has no DNS A
-or MX record. <br> The unknown_hostname_reject_code parameter
-specifies the numerical response code for rejected requests (default:
-450). <br> The unknown_helo_hostname_tempfail_action parameter
-specifies the action after a temporary DNS error (default:
-defer_if_permit). Note: specify "smtpd_helo_required = yes" to fully
+or MX record. <br> The reply is specified with the
+unknown_hostname_reject_code parameter (default: 450) or
+unknown_helo_hostname_tempfail_action (default: defer_if_permit).
+See the respective parameter descriptions for details. <br>
+Note: specify "smtpd_helo_required = yes" to fully
 enforce this restriction (without "smtpd_helo_required = yes", a
 client can simply skip reject_unknown_helo_hostname by not sending
 HELO or EHLO). </dd>
@@ -6047,13 +6047,11 @@ the recipient domain, and the RCPT TO domain has 1) no DNS MX and
 no DNS A
 record or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later). <br> The
-unknown_address_reject_code parameter specifies the numerical
-response code for rejected requests (default: 450). The nullmx_reject_code
-parameter specifies the response code for domains with a nullmx
-DNS record (default: 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error. <br> The
-unknown_address_tempfail_action parameter specifies the action
-after a temporary DNS error (default: defer_if_permit).  </dd>
+reply is specified with the unknown_address_reject_code parameter
+(default: 450), unknown_address_tempfail_action (default:
+defer_if_permit), or nullmx_reject_code (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
+</dd>
 
 <dt><b><a name="reject_unlisted_recipient">reject_unlisted_recipient</a></b> (with Postfix version 2.0: check_recipient_maps)</dt>
 
@@ -6518,13 +6516,11 @@ the sender address, and the MAIL FROM domain has 1) no DNS MX and
 no DNS A
 record, or 2) a malformed MX record such as a record with
 a zero-length MX hostname (Postfix version 2.3 and later). <br> The
-unknown_address_reject_code parameter specifies the numerical
-response code for rejected requests (default: 450). The nullmx_reject_code
-parameter specifies the response code for domains with a nullmx
-DNS record (default 556, Postfix 2.12 and later).  The response
-is always 450 in case of a temporary DNS error. <br> The
-unknown_address_tempfail_action parameter specifies the action
-after a temporary DNS error (default: defer_if_permit). </dd>
+reply is specified with the unknown_address_reject_code parameter
+(default: 450), unknown_address_tempfail_action (default:
+defer_if_permit), or nullmx_reject_code (default 556, Postfix 2.12 and
+later). See the respective parameter descriptions for details.
+</dd>
 
 <dt><b><a name="reject_unlisted_sender">reject_unlisted_sender</a></b></dt>
 
@@ -6777,12 +6773,10 @@ The default time unit is s (seconds).
 %PARAM unknown_address_reject_code 450
 
 <p>
-The numerical Postfix SMTP server response code when a sender or
-recipient address is rejected by the reject_unknown_sender_domain
-or reject_unknown_recipient_domain restriction. The nullmx_reject_code
-is used for domains with a nullmx DNS record (Postfix 2.12 and
-later).  The response is always 450 in case of a temporary DNS
-error.
+The numerical response code when the Postfix SMTP server rejects a
+sender or recipient address because its domain is unknown.  This
+is one of the possible replies from the restrictions
+reject_unknown_sender_domain and reject_unknown_recipient_domain.
 </p>
 
 <p>
@@ -16284,7 +16278,97 @@ header names is limited only by available memory.  </p>
 <p> The numerical reply code when the Postfix SMTP server rejects
 a sender or recipient address because its domain has a nullmx DNS
 record (an MX record with an empty hostname). This is one of the
-possible replies from reject_unknown_sender_domain and
-reject_unknown_recipient_domain. </p>
+possible replies from the restrictions reject_unknown_sender_domain
+and reject_unknown_recipient_domain. </p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+%PARAM smtpd_dns_reply_filter
+
+<p> Optional filter for Postfix SMTP server DNS lookup results.
+See smtp_dns_reply_filter for details including an example.
+</p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+%PARAM lmtp_dns_reply_filter
+
+<p> Optional filter for Postfix LMTP client DNS lookup results.
+See smtp_dns_reply_filter for details including an example.  </p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+#%PARAM postscreen_dns_reply_filter
+#
+#<p> Optional filter for postscreen(8) DNS lookup results.
+#See smtp_dns_reply_filter for details including an example.
+#</p>
+#
+#<p> This feature is available in Postfix 2.12 and later. </p>
+
+%PARAM smtp_dns_reply_filter
+
+<p> Optional filter for Postfix SMTP client DNS lookup results.
+Specify zero or more lookup tables.  The lookup tables are searched
+in the given order for a match with the DNS lookup result, converted
+to the following form: </p>
+
+<pre>
+    <i>name ttl class type preference value</i>
+</pre>
+
+<p> The <i>class</i> field is always "IN", the <i>preference</i>
+field exists only for MX records, the names of hosts, domains, etc.
+end in ".", and those names are in ASCII form (xn--mumble form in
+the case of UTF8 names).  </p>
+
+<p> When a match is found, the table lookup result specifies an
+action.  By default, the table query and the action name are
+case-insensitive.  Currently, only the <b>IGNORE</b> action is
+implemented.  </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> The smtp_dns_reply_filter and lmtp_dns_reply_filter features
+are used only for Postfix SMTP or LMTP client DNS lookups of MX,
+A, and AAAAA records to locate a remote SMTP or LMTP server, including
+lookups that are made to implement the features reject_unverified_sender
+and reject_unverified_recipient. </p>
+
+<li> <p> The Postfix SMTP or LMTP client defers mail delivery when
+a filter removes all lookup results from a successful query.  </p>
+
+<li> <p> The smtpd_dns_reply_filter feature is used only for Postfix
+SMTP server DNS lookups of MX, A, AAAAA, and TXT records to implement
+the features reject_unknown_helo_hostname, reject_unknown_sender_domain,
+reject_unknown_recipient_domain, reject_rbl_*, and reject_rhsbl_*.
+</p>
+
+<li> <p> The Postfix SMTP server logs a warning or defers mail
+delivery when a filter removes all lookup results from a successful
+query.  </p>
+
+<li> <p> Implicit DNS lookups through nsswitch.conf or equivalent
+mechanisms are not filtered.  </p>
+
+</ul>
+
+<p> Example: ignore Google AAAA records in Postfix SMTP client DNS
+lookups, because Google sometimes hard-rejects mail from IPv6 clients
+with valid PTR etc. records. </p>
+
+<pre>
+/etc/postfix/main.cf:
+    smtp_dns_reply_filter = pcre:/etc/postfix/smtp_dns_reply_filter
+</pre>
+
+<pre>
+/etc/postfix/smtp_dns_reply_filter:
+    # /domain ttl IN AAAA address/ action, all case-insensitive.
+    # Note: the domain name ends in ".".
+    /^\S+\.google.com\.\s+\S+\s+\S+\s+AAAA\s+/ IGNORE
+</pre>
 
 <p> This feature is available in Postfix 2.12 and later. </p>
index 70ff71c09ee340fd5083db11143ff10758be84b7..4635cb1904694a4c092106a2a3d06916a089e797 100644 (file)
@@ -1,8 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = dns_lookup.c dns_rr.c dns_strerror.c dns_strtype.c dns_rr_to_pa.c \
-       dns_sa_to_rr.c dns_rr_eq_sa.c dns_rr_to_sa.c
+       dns_sa_to_rr.c dns_rr_eq_sa.c dns_rr_to_sa.c dns_strrecord.c \
+       dns_rr_filter.c
 OBJS   = dns_lookup.o dns_rr.o dns_strerror.o dns_strtype.o dns_rr_to_pa.o \
-       dns_sa_to_rr.o dns_rr_eq_sa.o dns_rr_to_sa.o
+       dns_sa_to_rr.o dns_rr_eq_sa.o dns_rr_to_sa.o dns_strrecord.o \
+       dns_rr_filter.o
 HDRS   = dns.h
 TESTSRC        = test_dns_lookup.c test_alias_token.c
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -10,7 +12,8 @@ CFLAGS        = $(DEBUG) $(OPT) $(DEFS)
 INCL   =
 LIB    = lib$(LIB_PREFIX)dns$(LIB_SUFFIX)
 TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa
-LIBS   = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
+LIBS   = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
+       ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
 LIB_DIR        = ../../lib
 INC_DIR        = ../../include
 
@@ -26,7 +29,8 @@ Makefile: Makefile.in
 test:  $(TESTPROG)
 
 tests: test dns_rr_to_pa_test dns_rr_to_sa_test dns_sa_to_rr_test \
-       dns_rr_eq_sa_test nullmx_test nxdomain_test mxonly_test
+       dns_rr_eq_sa_test no-a-test no-aaaa-test no-mx-test \
+       error-filter-test nullmx_test nxdomain_test mxonly_test
 
 root_tests:
 
@@ -89,6 +93,26 @@ dns_rr_eq_sa_test: dns_rr_eq_sa dns_rr_eq_sa.in dns_rr_eq_sa.ref
        diff dns_rr_eq_sa.ref dns_rr_eq_sa.tmp
        rm -f dns_rr_eq_sa.tmp
 
+no-a-test: no-a.reg test_dns_lookup no-a.ref
+       $(SHLIB_ENV) ./test_dns_lookup -f regexp:no-a.reg a,aaaa spike.porcupine.org >test_dns_lookup.tmp 2>&1
+       diff no-a.ref test_dns_lookup.tmp
+       rm -f test_dns_lookup.tmp
+
+no-aaaa-test: no-aaaa.reg test_dns_lookup no-aaaa.ref
+       $(SHLIB_ENV) ./test_dns_lookup -f regexp:no-aaaa.reg a,aaaa spike.porcupine.org >test_dns_lookup.tmp 2>&1
+       diff no-aaaa.ref test_dns_lookup.tmp
+       rm -f test_dns_lookup.tmp
+
+no-mx-test: no-mx.reg test_dns_lookup no-mx.ref
+       set -e; $(SHLIB_ENV) ./test_dns_lookup -f regexp:no-mx.reg mx porcupine.org 2>&1 | sort >test_dns_lookup.tmp || true
+       diff no-mx.ref test_dns_lookup.tmp
+       rm -f test_dns_lookup.tmp
+
+error-filter-test: error.reg test_dns_lookup error.ref
+       set -e; $(SHLIB_ENV) ./test_dns_lookup -f regexp:error.reg a,aaaa spike.porcupine.org >test_dns_lookup.tmp 2>&1 || true
+       diff error.ref test_dns_lookup.tmp
+       rm -f test_dns_lookup.tmp
+
 nullmx_test: test_dns_lookup nullmx_test.ref
        (set -e; \
        $(SHLIB_ENV) ./test_dns_lookup mx,a nullmx.porcupine.org; \
@@ -137,14 +161,19 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+dns_lookup.o: ../../include/argv.h
+dns_lookup.o: ../../include/dict.h
+dns_lookup.o: ../../include/maps.h
 dns_lookup.o: ../../include/msg.h
 dns_lookup.o: ../../include/myaddrinfo.h
+dns_lookup.o: ../../include/myflock.h
 dns_lookup.o: ../../include/mymalloc.h
 dns_lookup.o: ../../include/sock_addr.h
 dns_lookup.o: ../../include/stringops.h
 dns_lookup.o: ../../include/sys_defs.h
 dns_lookup.o: ../../include/valid_hostname.h
 dns_lookup.o: ../../include/vbuf.h
+dns_lookup.o: ../../include/vstream.h
 dns_lookup.o: ../../include/vstring.h
 dns_lookup.o: dns.h
 dns_lookup.o: dns_lookup.c
@@ -166,6 +195,19 @@ dns_rr_eq_sa.o: ../../include/vbuf.h
 dns_rr_eq_sa.o: ../../include/vstring.h
 dns_rr_eq_sa.o: dns.h
 dns_rr_eq_sa.o: dns_rr_eq_sa.c
+dns_rr_filter.o: ../../include/argv.h
+dns_rr_filter.o: ../../include/dict.h
+dns_rr_filter.o: ../../include/maps.h
+dns_rr_filter.o: ../../include/msg.h
+dns_rr_filter.o: ../../include/myaddrinfo.h
+dns_rr_filter.o: ../../include/myflock.h
+dns_rr_filter.o: ../../include/sock_addr.h
+dns_rr_filter.o: ../../include/sys_defs.h
+dns_rr_filter.o: ../../include/vbuf.h
+dns_rr_filter.o: ../../include/vstream.h
+dns_rr_filter.o: ../../include/vstring.h
+dns_rr_filter.o: dns.h
+dns_rr_filter.o: dns_rr_filter.c
 dns_rr_to_pa.o: ../../include/msg.h
 dns_rr_to_pa.o: ../../include/myaddrinfo.h
 dns_rr_to_pa.o: ../../include/sock_addr.h
@@ -197,6 +239,14 @@ dns_strerror.o: ../../include/vbuf.h
 dns_strerror.o: ../../include/vstring.h
 dns_strerror.o: dns.h
 dns_strerror.o: dns_strerror.c
+dns_strrecord.o: ../../include/msg.h
+dns_strrecord.o: ../../include/myaddrinfo.h
+dns_strrecord.o: ../../include/sock_addr.h
+dns_strrecord.o: ../../include/sys_defs.h
+dns_strrecord.o: ../../include/vbuf.h
+dns_strrecord.o: ../../include/vstring.h
+dns_strrecord.o: dns.h
+dns_strrecord.o: dns_strrecord.c
 dns_strtype.o: ../../include/myaddrinfo.h
 dns_strtype.o: ../../include/sock_addr.h
 dns_strtype.o: ../../include/sys_defs.h
index e3335eb219019c3bbd5740f84cd81b92c820545c..769c8dbe6254d793c01928fca6fdff82b68ab585 100644 (file)
@@ -153,6 +153,11 @@ extern const char *dns_strerror(unsigned);
 extern const char *dns_strtype(unsigned);
 extern unsigned dns_type(const char *);
 
+ /*
+  * dns_strrecord.c
+  */
+extern char *dns_strrecord(VSTRING *, DNS_RR *);
+
  /*
   * dns_rr.c
   */
@@ -229,18 +234,41 @@ extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *,
 #define DNS_REQ_FLAG_STOP_OK   (1<<0)
 #define DNS_REQ_FLAG_STOP_INVAL        (1<<1)
 #define DNS_REQ_FLAG_STOP_UNAVAIL (1<<2)
+#define DNS_REQ_FLAG_STOP_MX_POLICY (1<<3)
 #define DNS_REQ_FLAG_NONE      (0)
 
  /*
   * Status codes. Failures must have negative codes so they will not collide
   * with valid counts of answer records etc.
+  * 
+  * When a function queries multiple record types for one name, it issues one
+  * query for each query record type. Each query returns a (status, rcode,
+  * text). Only one of these (status, rcode, text) will be returned to the
+  * caller. The selection is based on the status code precedence.
+  * 
+  * - Return DNS_OK (and the corresponding rcode) as long as any query returned
+  * DNS_OK. If this is changed, then code needs to be added to prevent memory
+  * leaks.
+  * 
+  * - Return DNS_RETRY (and the corresponding rcode and text) instead of any
+  * hard negative result.
+  * 
+  * - Return DNS_NOTFOUND (and the corresponding rcode and text) only when all
+  * queries returned DNS_NOTFOUND.
+  * 
+  * DNS_POLICY ranks higher than DNS_RETRY because there was a DNS_OK result,
+  * but the reply filter dropped it. This is a very soft error.
+  * 
+  * Below is the precedence order. The order between DNS_RETRY and DNS_NOTFOUND
+  * is arbitrary.
   */
-#define DNS_UNAVAIL    (-6)            /* query ok, service unavailable */
-#define DNS_INVAL      (-5)            /* query ok, malformed reply */
+#define DNS_RECURSE    (-7)            /* internal only: recursion needed */
+#define DNS_NOTFOUND   (-6)            /* query ok, data not found */
+#define DNS_UNAVAIL    (-5)            /* query ok, service unavailable */
 #define DNS_FAIL       (-4)            /* query failed, don't retry */
-#define DNS_NOTFOUND   (-3)            /* query ok, data not found */
+#define DNS_INVAL      (-3)            /* query ok, malformed reply */
 #define DNS_RETRY      (-2)            /* query failed, try again */
-#define DNS_RECURSE    (-1)            /* recursion needed */
+#define DNS_POLICY     (-1)            /* query ok, all records dropped */
 #define DNS_OK         0               /* query succeeded */
 
  /*
@@ -248,6 +276,18 @@ extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *,
   */
 #define DNS_NAME_LEN   1024
 
+ /*
+  * dns_rr_filter.c.
+  */
+extern void dns_rr_filter_compile(const char *, const char *);
+
+#ifdef LIBDNS_INTERNAL
+#include <maps.h>
+extern MAPS *dns_rr_filter_maps;
+extern int dns_rr_filter_execute(DNS_RR **);
+
+#endif
+
 /* LICENSE
 /* .ad
 /* .fi
index 9b85fc143aa732a7e61eabf756358e9ca6d504b4..3618550cef9f26b936a99390ee9edc5006b7b1b3 100644 (file)
 /* .IP DNS_REQ_FLAG_STOP_UNAVAIL
 /*     Invoke dns_lookup() for the resource types in the order as
 /*     specified, and return when dns_lookup() returns DNS_UNAVAIL.
+/* .IP DNS_REQ_FLAG_STOP_MX_POLICY
+/*     Invoke dns_lookup() for the resource types in the order as
+/*     specified, and return when dns_lookup() returns DNS_POLICY
+/*     for an MX query.
 /* .IP DNS_REQ_FLAG_STOP_OK
 /*     Invoke dns_lookup() for the resource types in the order as
 /*     specified, and return when dns_lookup() returns DNS_OK.
 /*     \fIwhy\fR argument accordingly:
 /* .IP DNS_OK
 /*     The DNS query succeeded.
+/* .IP DNS_POLICY
+/*     The DNS query succeeded, but the answer did not pass the
+/*     policy filter.
 /* .IP DNS_NOTFOUND
 /*     The DNS query succeeded; the requested information was not found.
 /* .IP DNS_UNAVAIL
 
 /* DNS library. */
 
+#define LIBDNS_INTERNAL
 #include "dns.h"
 
 /* Local stuff. */
@@ -466,7 +474,7 @@ static int dns_get_rr(DNS_RR **list, const char *orig_name, DNS_REPLY *reply,
            return (DNS_RETRY);
        /* Don't even think of returning an invalid hostname to the caller. */
        if (*temp == 0)
-           return (DNS_UNAVAIL);       /* XXX TODO: return descriptive text here */
+           return (DNS_UNAVAIL);               /* TODO: descriptive text */
        if (!valid_rr_name(temp, "resource data", fixed->type, reply))
            return (DNS_INVAL);
        data_len = strlen(temp) + 1;
@@ -627,7 +635,7 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type,
                    rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
                    *rrlist = dns_rr_append(*rrlist, rr);
                } else if (status == DNS_UNAVAIL) {
-                   CORRUPT(status);            /* XXX TODO: use better name here */
+                   CORRUPT(status);            /* TODO: use better name */
                } else if (not_found_status != DNS_RETRY)
                    not_found_status = status;
            } else
@@ -723,13 +731,32 @@ int     dns_lookup_r(const char *name, unsigned type, unsigned flags,
            return (status);
        case DNS_UNAVAIL:
            if (why)
-               vstring_sprintf(why, type == T_MX ?     /* XXX TODO: move this */
-                               "Domain %s does not accept mail (null %s)" : 
+               vstring_sprintf(why, type == T_MX ?     /* TODO: move this */
+                               "Domain %s does not accept mail (null %s)" :
                                "Domain %s does not provide %s service",
                                name, dns_strtype(type));
            h_errno = NO_DATA;
            return (status);
        case DNS_OK:
+           if (dns_rr_filter_maps) {
+               if (dns_rr_filter_execute(rrlist) < 0) {
+                   if (why)
+                       vstring_sprintf(why,
+                                       "Error looking up name=%s type=%s: "
+                                       "Invalid DNS reply filter syntax",
+                                       name, dns_strtype(type));
+                   dns_rr_free(*rrlist);
+                   *rrlist = 0;
+                   status = DNS_RETRY;
+               } else if (*rrlist == 0) {
+                   if (why)
+                       vstring_sprintf(why,
+                                       "Error looking up name=%s type=%s: "
+                                       "DNS reply filter drops all results",
+                                       name, dns_strtype(type));
+                   status = DNS_POLICY;
+               }
+           }
            return (status);
        case DNS_RECURSE:
            if (msg_verbose)
@@ -760,23 +787,44 @@ int     dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
                              int lflags,...)
 {
     va_list ap;
-    unsigned type;
+    unsigned type, next;
     int     status = DNS_NOTFOUND;
+    int     hpref_status = INT_MIN;
+    VSTRING *hpref_rtext = 0;
+    int     hpref_rcode;
     DNS_RR *rr;
-    int     non_err = 0;
-    int     soft_err = 0;
+
+    /* Save intermediate highest-priority result. */
+#define SAVE_HPREF_STATUS() do { \
+       hpref_status = status; \
+       if (rcode) \
+           hpref_rcode = *rcode; \
+       if (why && status != DNS_OK) \
+           vstring_strcpy(hpref_rtext ? hpref_rtext : \
+                          vstring_alloc(VSTRING_LEN(why)), \
+                          vstring_str(why)); \
+    } while (0)
+
+    /* Restore intermediate highest-priority result. */
+#define RESTORE_HPREF_STATUS() do { \
+       status = hpref_status; \
+       if (rcode) \
+           *rcode = hpref_rcode; \
+       if (why && status != DNS_OK) \
+           vstring_strcpy(why, vstring_str(hpref_rtext)); \
+    } while (0)
 
     if (rrlist)
        *rrlist = 0;
     va_start(ap, lflags);
-    while ((type = va_arg(ap, unsigned)) != 0) {
+    for (type = va_arg(ap, unsigned); type != 0; type = next) {
+       next = va_arg(ap, unsigned);
        if (msg_verbose)
            msg_info("lookup %s type %s flags %d",
                     name, dns_strtype(type), flags);
        status = dns_lookup_r(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
                              fqdn, why, rcode);
        if (status == DNS_OK) {
-           non_err = 1;
            if (rrlist)
                *rrlist = dns_rr_append(*rrlist, rr);
            if (lflags & DNS_REQ_FLAG_STOP_OK)
@@ -784,16 +832,25 @@ int     dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
        } else if (status == DNS_INVAL) {
            if (lflags & DNS_REQ_FLAG_STOP_INVAL)
                break;
+       } else if (status == DNS_POLICY) {
+           if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
+               break;
        } else if (status == DNS_UNAVAIL) {
            if (lflags & DNS_REQ_FLAG_STOP_UNAVAIL)
                break;
-       } else if (status == DNS_RETRY) {
-           soft_err = 1;
        }
        /* XXX Stop after NXDOMAIN error. */
+       if (next == 0)
+           break;
+       if (status >= hpref_status)
+           SAVE_HPREF_STATUS();                        /* save last info */
     }
     va_end(ap);
-    return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
+    if (status < hpref_status)
+       RESTORE_HPREF_STATUS();                 /* else report last info */
+    if (hpref_rtext)
+       vstring_free(hpref_rtext);
+    return (status);
 }
 
 /* dns_lookup_rv - DNS lookup interface with types vector */
@@ -802,22 +859,23 @@ int     dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
                              VSTRING *fqdn, VSTRING *why, int *rcode,
                              int lflags, unsigned *types)
 {
-    unsigned type;
+    unsigned type, next;
     int     status = DNS_NOTFOUND;
+    int     hpref_status = INT_MIN;
+    VSTRING *hpref_rtext = 0;
+    int     hpref_rcode;
     DNS_RR *rr;
-    int     non_err = 0;
-    int     soft_err = 0;
 
     if (rrlist)
        *rrlist = 0;
-    while ((type = *types++) != 0) {
+    for (type = *types++; type != 0; type = next) {
+       next = *types++;
        if (msg_verbose)
            msg_info("lookup %s type %s flags %d",
                     name, dns_strtype(type), flags);
        status = dns_lookup_r(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
                              fqdn, why, rcode);
        if (status == DNS_OK) {
-           non_err = 1;
            if (rrlist)
                *rrlist = dns_rr_append(*rrlist, rr);
            if (lflags & DNS_REQ_FLAG_STOP_OK)
@@ -825,13 +883,22 @@ int     dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
        } else if (status == DNS_INVAL) {
            if (lflags & DNS_REQ_FLAG_STOP_INVAL)
                break;
+       } else if (status == DNS_POLICY) {
+           if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
+               break;
        } else if (status == DNS_UNAVAIL) {
            if (lflags & DNS_REQ_FLAG_STOP_UNAVAIL)
                break;
-       } else if (status == DNS_RETRY) {
-           soft_err = 1;
        }
        /* XXX Stop after NXDOMAIN error. */
+       if (next == 0)
+           break;
+       if (status >= hpref_status)
+           SAVE_HPREF_STATUS();                        /* save last info */
     }
-    return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
+    if (status < hpref_status)
+       RESTORE_HPREF_STATUS();                 /* else report last info */
+    if (hpref_rtext)
+       vstring_free(hpref_rtext);
+    return (status);
 }
diff --git a/postfix/src/dns/dns_rr_filter.c b/postfix/src/dns/dns_rr_filter.c
new file mode 100644 (file)
index 0000000..105533e
--- /dev/null
@@ -0,0 +1,146 @@
+/*++
+/* NAME
+/*     dns_rr_filter 3
+/* SUMMARY
+/*     DNS resource record filter
+/* SYNOPSIS
+/*     #include <dns.h>
+/*
+/*     void    dns_rr_filter_compile(title, map_names)
+/*     const char *title;
+/*     const char *map_names;
+/* INTERNAL INTERFACES
+/*     int     dns_rr_filter_execute(rrlist)
+/*     DNS_RR  **rrlist;
+/*
+/*     MAPS    *dns_rr_filter_maps;
+/* DESCRIPTION
+/*     This module implements a simple filter for dns_lookup*()
+/*     results.
+/*
+/*     dns_rr_filter_compile() initializes a result filter.  The
+/*     title and map_names arguments are as with maps_create().
+/*     This function may be invoked more than once; only the last
+/*     filter takes effect.
+/*
+/*     dns_rr_filter_execute() converts each resource record in the
+/*     specified list with dns_strrecord to ASCII form and matches
+/*     that against the specified maps. If a match is found it
+/*     executes the corresponding action.  Currently, only the
+/*     "ignore" action is implemented. This removes the matched
+/*     record from the list. The result is 0 in case of success,
+/*     -1 in case of error.
+/*
+/*     dns_rr_filter_maps is updated by dns_rr_filter_compile().
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <ctype.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <vstring.h>
+#include <myaddrinfo.h>
+
+ /*
+  * Global library.
+  */
+#include <maps.h>
+
+ /*
+  * DNS library.
+  */
+#define LIBDNS_INTERNAL
+#include <dns.h>
+
+ /*
+  * Application-specific.
+  */
+MAPS   *dns_rr_filter_maps;
+
+static DNS_RR dns_rr_filter_error[1];
+
+#define STR vstring_str
+
+/* dns_rr_filter_compile - compile dns result filter */
+
+void    dns_rr_filter_compile(const char *title, const char *map_names)
+{
+    if (dns_rr_filter_maps != 0)
+       maps_free(dns_rr_filter_maps);
+    dns_rr_filter_maps = maps_create(title, map_names,
+                                    DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+}
+
+/* dns_rr_action - execute action from filter map */
+
+static DNS_RR *dns_rr_action(const char *cmd, DNS_RR *rr, const char *rr_text)
+{
+    const char *cmd_args = cmd + strcspn(cmd, " \t");
+    int     cmd_len = cmd_args - cmd;
+
+    while (*cmd_args && ISSPACE(*cmd_args))
+       cmd_args++;
+
+#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
+
+    if (STREQUAL(cmd, "IGNORE", cmd_len)) {
+       msg_info("ignoring DNS RR: %s", rr_text);
+       return (0);
+    } else {
+       msg_warn("%s: unknown DNS filter action: \"%s\"", 
+                dns_rr_filter_maps->title, cmd);
+       return (dns_rr_filter_error);
+    }
+    return (rr);
+}
+
+/* dns_rr_filter_execute - filter DNS lookup result */
+
+int     dns_rr_filter_execute(DNS_RR **rrlist)
+{
+    static VSTRING *buf = 0;
+    DNS_RR **rrp;
+    DNS_RR *rr;
+    const char *map_res;
+    DNS_RR *act_res;
+
+    /*
+     * Convert the resource record to string form, then search the maps for a
+     * matching action.
+     */
+    if (buf == 0)
+       buf = vstring_alloc(100);
+    for (rrp = rrlist; (rr = *rrp) != 0; /* see below */ ) {
+       map_res = maps_find(dns_rr_filter_maps, dns_strrecord(buf, rr),
+                           DICT_FLAG_NONE);
+       if (map_res != 0) {
+           if ((act_res = dns_rr_action(map_res, rr, STR(buf))) == 0) {
+               *rrp = rr->next;                /* do not advance in the list */
+               rr->next = 0;
+               dns_rr_free(rr);
+               continue;
+           } else if (act_res == dns_rr_filter_error) {
+               return (-1);
+           }
+       } else if (dns_rr_filter_maps->error) {
+           return (-1);
+       }
+       rrp = &(rr->next);                      /* do advance in the list */
+    }
+    return (0);
+}
diff --git a/postfix/src/dns/dns_strrecord.c b/postfix/src/dns/dns_strrecord.c
new file mode 100644 (file)
index 0000000..9653d50
--- /dev/null
@@ -0,0 +1,94 @@
+/*++
+/* NAME
+/*     dns_strtype 3
+/* SUMMARY
+/*     name service resource record printable forms
+/* SYNOPSIS
+/*     #include <dns.h>
+/*
+/*     char    *dns_strrecord(buf, record)
+/*     VSTRING *buf;
+/*     DNS_RR  *record;
+/* DESCRIPTION
+/*     dns_strrecord() formats a DNS resource record as "name ttl
+/*     class type preference value", where the class field is
+/*     always "IN", the preference field exists only for MX records,
+/*     and all names end in ".". The result value is the payload
+/*     of the buffer argument.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+#include <msg.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_strrecord - format resource record as generic string */
+
+char   *dns_strrecord(VSTRING *buf, DNS_RR *rr)
+{
+    const char myname[] = "dns_strrecord";
+    MAI_HOSTADDR_STR host;
+
+    vstring_sprintf(buf, "%s. %u IN %s ",
+                   rr->rname, rr->ttl, dns_strtype(rr->type));
+    switch (rr->type) {
+    case T_A:
+#ifdef T_AAAA
+    case T_AAAA:
+#endif
+       if (dns_rr_to_pa(rr, &host) == 0)
+           msg_fatal("%s: conversion error for resource record type %s: %m",
+                     myname, dns_strtype(rr->type));
+       vstring_sprintf_append(buf, "%s", host.buf);
+       break;
+    case T_CNAME:
+    case T_DNAME:
+    case T_MB:
+    case T_MG:
+    case T_MR:
+    case T_NS:
+    case T_PTR:
+    case T_TXT:
+       vstring_sprintf_append(buf, "%s.", rr->data);
+       break;
+    case T_MX:
+       vstring_sprintf_append(buf, "%u %s.", rr->pref, rr->data);
+       break;
+    case T_TLSA:
+       if (rr->data_len >= 3) {
+           uint8_t *ip = (uint8_t *) rr->data;
+           uint8_t usage = *ip++;
+           uint8_t selector = *ip++;
+           uint8_t mtype = *ip++;
+           unsigned i;
+
+           vstring_sprintf_append(buf, "%d %d %d", usage, selector, mtype);
+           for (i = 3; i < rr->data_len; ++i)
+               vstring_sprintf_append(buf, "%02x", *ip++);
+       } else {
+           vstring_sprintf_append(buf, "[truncated record]");
+       }
+       break;
+    default:
+       msg_fatal("%s: don't know how to print type %s",
+                 myname, dns_strtype(rr->type));
+    }
+    return (vstring_str(buf));
+}
diff --git a/postfix/src/dns/error.ref b/postfix/src/dns/error.ref
new file mode 100644 (file)
index 0000000..2e0f9e6
--- /dev/null
@@ -0,0 +1,13 @@
+./test_dns_lookup: lookup spike.porcupine.org type A flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (A): OK
+./test_dns_lookup: dns_get_answer: type A for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: error.reg: spike.porcupine.org. 3600 IN A 168.100.189.2
+./test_dns_lookup: maps_find: DNS reply filter: regexp:error.reg(0,lock|fold_fix): spike.porcupine.org. 3600 IN A 168.100.189.2 = oops
+./test_dns_lookup: warning: DNS reply filter: unknown DNS filter action: "oops"
+./test_dns_lookup: lookup spike.porcupine.org type AAAA flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (AAAA): OK
+./test_dns_lookup: dns_get_answer: type AAAA for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: error.reg: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2
+./test_dns_lookup: maps_find: DNS reply filter: regexp:error.reg(0,lock|fold_fix): spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2 = oops
+./test_dns_lookup: warning: DNS reply filter: unknown DNS filter action: "oops"
+./test_dns_lookup: fatal: Error looking up name=spike.porcupine.org type=AAAA: Invalid DNS reply filter syntax (rcode=0)
diff --git a/postfix/src/dns/error.reg b/postfix/src/dns/error.reg
new file mode 100644 (file)
index 0000000..4e553e8
--- /dev/null
@@ -0,0 +1 @@
+/./ oops
index c7c309ce317e8af4d5fec64fe89b6343f6dce348..ec8eda54cfacddee4242d2a55f7b0061e57112cb 100644 (file)
@@ -5,7 +5,7 @@
 ./test_dns_lookup: dns_get_answer: type MX for porcupine.org
 ./test_dns_lookup: lookup porcupine.org type A flags 2097152
 ./test_dns_lookup: dns_query: porcupine.org (A): Host found but no data record of requested type
-porcupine.org: ad: 0, ttl:      3600 pref: 10 MX: spike.porcupine.org
-porcupine.org: ad: 0, ttl:      3600 pref: 20 MX: fist.porcupine.org
-porcupine.org: ad: 0, ttl:      3600 pref: 30 MX: m1.porcupine.org
+ad: 0, rr: porcupine.org. 3600 IN MX 10 spike.porcupine.org.
+ad: 0, rr: porcupine.org. 3600 IN MX 20 fist.porcupine.org.
+ad: 0, rr: porcupine.org. 3600 IN MX 30 m1.porcupine.org.
 porcupine.org: fqdn: porcupine.org
diff --git a/postfix/src/dns/no-a.ref b/postfix/src/dns/no-a.ref
new file mode 100644 (file)
index 0000000..72b6444
--- /dev/null
@@ -0,0 +1,13 @@
+./test_dns_lookup: lookup spike.porcupine.org type A flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (A): OK
+./test_dns_lookup: dns_get_answer: type A for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: no-a.reg: spike.porcupine.org. 3600 IN A 168.100.189.2
+./test_dns_lookup: maps_find: DNS reply filter: regexp:no-a.reg(0,lock|fold_fix): spike.porcupine.org. 3600 IN A 168.100.189.2 = ignore
+./test_dns_lookup: ignoring DNS RR: spike.porcupine.org. 3600 IN A 168.100.189.2
+./test_dns_lookup: lookup spike.porcupine.org type AAAA flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (AAAA): OK
+./test_dns_lookup: dns_get_answer: type AAAA for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: no-a.reg: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2
+./test_dns_lookup: maps_find: DNS reply filter: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2: not found
+spike.porcupine.org: fqdn: spike.porcupine.org
+ad: 0, rr: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2
diff --git a/postfix/src/dns/no-a.reg b/postfix/src/dns/no-a.reg
new file mode 100644 (file)
index 0000000..69e05e5
--- /dev/null
@@ -0,0 +1 @@
+/ +a +/ ignore
diff --git a/postfix/src/dns/no-aaaa.ref b/postfix/src/dns/no-aaaa.ref
new file mode 100644 (file)
index 0000000..eabe052
--- /dev/null
@@ -0,0 +1,13 @@
+./test_dns_lookup: lookup spike.porcupine.org type A flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (A): OK
+./test_dns_lookup: dns_get_answer: type A for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: no-aaaa.reg: spike.porcupine.org. 3600 IN A 168.100.189.2
+./test_dns_lookup: maps_find: DNS reply filter: spike.porcupine.org. 3600 IN A 168.100.189.2: not found
+./test_dns_lookup: lookup spike.porcupine.org type AAAA flags 2097152
+./test_dns_lookup: dns_query: spike.porcupine.org (AAAA): OK
+./test_dns_lookup: dns_get_answer: type AAAA for spike.porcupine.org
+./test_dns_lookup: dict_regexp_lookup: no-aaaa.reg: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2
+./test_dns_lookup: maps_find: DNS reply filter: regexp:no-aaaa.reg(0,lock|fold_fix): spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2 = ignore
+./test_dns_lookup: ignoring DNS RR: spike.porcupine.org. 3600 IN AAAA 2604:8d00:189::2
+spike.porcupine.org: fqdn: spike.porcupine.org
+ad: 0, rr: spike.porcupine.org. 3600 IN A 168.100.189.2
diff --git a/postfix/src/dns/no-aaaa.reg b/postfix/src/dns/no-aaaa.reg
new file mode 100644 (file)
index 0000000..962adda
--- /dev/null
@@ -0,0 +1 @@
+/ +aaaa +/ ignore
diff --git a/postfix/src/dns/no-mx.ref b/postfix/src/dns/no-mx.ref
new file mode 100644 (file)
index 0000000..6b0085d
--- /dev/null
@@ -0,0 +1,15 @@
+./test_dns_lookup: dict_regexp_lookup: no-mx.reg: porcupine.org. 3600 IN MX 10 spike.porcupine.org.
+./test_dns_lookup: dict_regexp_lookup: no-mx.reg: porcupine.org. 3600 IN MX 20 fist.porcupine.org.
+./test_dns_lookup: dict_regexp_lookup: no-mx.reg: porcupine.org. 3600 IN MX 30 m1.porcupine.org.
+./test_dns_lookup: dns_get_answer: type MX for porcupine.org
+./test_dns_lookup: dns_get_answer: type MX for porcupine.org
+./test_dns_lookup: dns_get_answer: type MX for porcupine.org
+./test_dns_lookup: dns_query: porcupine.org (MX): OK
+./test_dns_lookup: fatal: Error looking up name=porcupine.org type=MX: DNS reply filter drops all results (rcode=0)
+./test_dns_lookup: ignoring DNS RR: porcupine.org. 3600 IN MX 10 spike.porcupine.org.
+./test_dns_lookup: ignoring DNS RR: porcupine.org. 3600 IN MX 20 fist.porcupine.org.
+./test_dns_lookup: ignoring DNS RR: porcupine.org. 3600 IN MX 30 m1.porcupine.org.
+./test_dns_lookup: lookup porcupine.org type MX flags 2097152
+./test_dns_lookup: maps_find: DNS reply filter: regexp:no-mx.reg(0,lock|fold_fix): porcupine.org. 3600 IN MX 10 spike.porcupine.org. = ignore
+./test_dns_lookup: maps_find: DNS reply filter: regexp:no-mx.reg(0,lock|fold_fix): porcupine.org. 3600 IN MX 20 fist.porcupine.org. = ignore
+./test_dns_lookup: maps_find: DNS reply filter: regexp:no-mx.reg(0,lock|fold_fix): porcupine.org. 3600 IN MX 30 m1.porcupine.org. = ignore
diff --git a/postfix/src/dns/no-mx.reg b/postfix/src/dns/no-mx.reg
new file mode 100644 (file)
index 0000000..69cf05d
--- /dev/null
@@ -0,0 +1 @@
+/ +mx +/ ignore
diff --git a/postfix/src/dns/no-txt.reg b/postfix/src/dns/no-txt.reg
new file mode 100644 (file)
index 0000000..175600b
--- /dev/null
@@ -0,0 +1 @@
+/ +txt +/ ignore
index 6451d78ee40bc87cfc0414814d2ca2187ac66cfb..176023889d469dd16e5c366411fc9e2804d9db05 100644 (file)
@@ -5,4 +5,4 @@
 ./test_dns_lookup: dns_query: nullmx.porcupine.org (A): OK
 ./test_dns_lookup: dns_get_answer: type A for nullmx.porcupine.org
 nullmx.porcupine.org: fqdn: nullmx.porcupine.org
-nullmx.porcupine.org: ad: 0, ttl:      3600 A: 168.100.189.13
+ad: 0, rr: nullmx.porcupine.org. 3600 IN A 168.100.189.13
index 3226f133797a82afda52feff2cc67ece712c9402..b0d55cecc71f04614d32fe62e00e9be9285c82c5 100644 (file)
 
 #include "dns.h"
 
-static void print_rr(DNS_RR *rr)
+static void print_rr(VSTRING *buf, DNS_RR *rr)
 {
-    MAI_HOSTADDR_STR host;
-    size_t  i;
-
     while (rr) {
-       printf("%s: ad: %u, ttl: %9u ", rr->rname, rr->dnssec_valid, rr->ttl);
-       switch (rr->type) {
-       case T_A:
-#ifdef T_AAAA
-       case T_AAAA:
-#endif
-           if (dns_rr_to_pa(rr, &host) == 0)
-               msg_fatal("conversion error for resource record type %s: %m",
-                         dns_strtype(rr->type));
-           printf("%s: %s\n", dns_strtype(rr->type), host.buf);
-           break;
-       case T_CNAME:
-       case T_DNAME:
-       case T_MB:
-       case T_MG:
-       case T_MR:
-       case T_NS:
-       case T_PTR:
-       case T_TXT:
-           printf("%s: %s\n", dns_strtype(rr->type), rr->data);
-           break;
-       case T_MX:
-           printf("pref: %d %s: %s\n",
-                  rr->pref, dns_strtype(rr->type), rr->data);
-           break;
-       case T_TLSA:
-           if (rr->data_len >= 3) {
-               uint8_t *ip = (uint8_t *) rr->data;
-               uint8_t usage = *ip++;
-               uint8_t selector = *ip++;
-               uint8_t mtype = *ip++;
-
-               printf("%s: %d %d %d ", dns_strtype(rr->type),
-                      usage, selector, mtype);
-               for (i = 3; i < rr->data_len; ++i)
-                   printf("%02x", *ip++);
-               putchar('\n');
-           } else {
-               printf("%s: truncated record\n", dns_strtype(rr->type));
-           }
-           break;
-       default:
-           msg_fatal("print_rr: don't know how to print type %s",
-                     dns_strtype(rr->type));
-       }
+       vstream_printf("ad: %u, rr: %s\n",
+                      rr->dnssec_valid, dns_strrecord(buf, rr));
        rr = rr->next;
     }
 }
 
+static NORETURN usage(char **argv)
+{
+    msg_fatal("usage: %s [-v] [-f filter] types name", argv[0]);
+}
+
 int     main(int argc, char **argv)
 {
     ARGV   *types_argv;
@@ -102,30 +61,46 @@ int     main(int argc, char **argv)
     char   *name;
     VSTRING *fqdn = vstring_alloc(100);
     VSTRING *why = vstring_alloc(100);
+    VSTRING *buf;
     int     rcode;
     DNS_RR *rr;
     int     i;
+    int     ch;
 
     msg_vstream_init(argv[0], VSTREAM_ERR);
-    if (argc != 3)
-       msg_fatal("usage: %s types name", argv[0]);
-    types_argv = argv_split(argv[1], CHARS_COMMA_SP);
+    while ((ch = GETOPT(argc, argv, "vf:")) > 0) {
+       switch (ch) {
+           msg_verbose++;
+           break;
+       case 'f':
+           dns_rr_filter_compile("DNS reply filter", optarg);
+           break;
+       default:
+           usage(argv);
+       }
+    }
+    if (argc != optind + 2)
+       usage(argv);
+    types_argv = argv_split(argv[optind], CHARS_COMMA_SP);
     types = (unsigned *) mymalloc(sizeof(*types) * (types_argv->argc + 1));
     for (i = 0; i < types_argv->argc; i++)
        if ((types[i] = dns_type(types_argv->argv[i])) == 0)
            msg_fatal("invalid query type: %s", types_argv->argv[i]);
     types[i] = 0;
     argv_free(types_argv);
-    name = argv[2];
+    name = argv[optind + 1];
     msg_verbose = 1;
     switch (dns_lookup_rv(name, RES_USE_DNSSEC, &rr, fqdn, why,
                          &rcode, DNS_REQ_FLAG_NONE, types)) {
     default:
        msg_fatal("%s (rcode=%d)", vstring_str(why), rcode);
     case DNS_OK:
-       printf("%s: fqdn: %s\n", name, vstring_str(fqdn));
-       print_rr(rr);
+       vstream_printf("%s: fqdn: %s\n", name, vstring_str(fqdn));
+       buf = vstring_alloc(100);
+       print_rr(buf, rr);
        dns_rr_free(rr);
+       vstring_free(buf);
+       vstream_fflush(VSTREAM_OUT);
     }
     myfree((char *) types);
     exit(0);
index 276a3d3c53230457a6e9783fe4901fd6a3e3efc6..83f2b36313fa22f80957c9c1f4a3291f52186941 100644 (file)
@@ -3842,6 +3842,19 @@ extern char *var_virt_dsn_filter;
 #define DEF_LOCAL_DSN_FILTER           "$" VAR_DSN_FILTER
 extern char *var_local_dsn_filter;
 
+ /*
+  * Optional DNS reply filter.
+  */
+#define VAR_SMTP_DNS_RE_FILTER         "smtp_dns_reply_filter"
+#define DEF_SMTP_DNS_RE_FILTER         ""
+#define VAR_LMTP_DNS_RE_FILTER         "lmtp_dns_reply_filter"
+#define DEF_LMTP_DNS_RE_FILTER         ""
+extern char *var_smtp_dns_re_filter;
+
+#define VAR_SMTPD_DNS_RE_FILTER                "smtpd_dns_reply_filter"
+#define DEF_SMTPD_DNS_RE_FILTER                ""
+extern char *var_smtpd_dns_re_filter;
+
  /*
   * Location of shared-library files.
   * 
index 68fc4c7363876a5a05ef6636368a731f732d7a05..17c960c6b3c53e3a3b663ab435f8cc6163d57bcf 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20141126"
+#define MAIL_RELEASE_DATE      "20141130"
 #define MAIL_VERSION_NUMBER    "2.12"
 
 #ifdef SNAPSHOT
index 1861e5ba5ee3af14be1f05240478ee854d5cd1b8..24274676f8dfe7f6fdb9d1a2b0e1ff3695e1900f 100644 (file)
@@ -58,6 +58,7 @@
        VAR_LMTP_ADDR_PREF, DEF_LMTP_ADDR_PREF, &var_smtp_addr_pref, 1, 0,
        VAR_LMTP_DNS_RES_OPT, DEF_LMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
        VAR_LMTP_DSN_FILTER, DEF_LMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0,
+       VAR_LMTP_DNS_RE_FILTER, DEF_LMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE lmtp_time_table[] = {
index e7ea7aa9638bc348d1af60ee29a3101f6e69aea3..d66aec33b02c642b5b5f65ac226be1046507e328 100644 (file)
 /*     Optional filter for the \fBsmtp\fR(8) delivery agent to change the
 /*     delivery status code or explanatory text of successful or unsuccessful
 /*     deliveries.
+/* .IP "\fBsmtp_dns_reply_filter ($default_dns_reply_filter)\fR"
+/*     Optional filter for Postfix SMTP client DNS lookup results.
 /* MIME PROCESSING CONTROLS
 /* .ad
 /* .fi
@@ -895,6 +897,7 @@ char   *var_smtp_dns_support;
 bool    var_smtp_rec_deadline;
 bool    var_smtp_dummy_mail_auth;
 char   *var_smtp_dsn_filter;
+char   *var_smtp_dns_re_filter;
 
  /* Special handling of 535 AUTH errors. */
 char   *var_smtp_sasl_auth_cache_name;
@@ -1231,6 +1234,13 @@ static void pre_init(char *unused_name, char **unused_argv)
            msg_fatal("bad %s value: %s", VAR_LMTP_SMTP(ADDR_PREF),
                      var_smtp_addr_pref);
     }
+
+    /*
+     * DNS reply filter.
+     */
+    if (*var_smtp_dns_re_filter)
+       dns_rr_filter_compile(VAR_LMTP_SMTP(DNS_RE_FILTER),
+                             var_smtp_dns_re_filter);
 }
 
 /* pre_accept - see if tables have changed */
index 42fb5068ef45256c8470958cc15a053127446a0f..213473199587342b3d637c1cbb1fc1dab26de02f 100644 (file)
@@ -179,6 +179,9 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
        case DNS_INVAL:
            dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
            return (addr_list);
+       case DNS_POLICY:
+           dsb_status(why, "4.7.0");
+           return (addr_list);
        case DNS_NOTFOUND:
            dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
            /* maybe native naming service will succeed */
@@ -438,6 +441,9 @@ DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags,
     case DNS_UNAVAIL:
        dsb_status(why, "5.1.0");
        break;
+    case DNS_POLICY:
+       dsb_status(why, "4.7.0");
+       break;
     case DNS_FAIL:
        dsb_status(why, "5.4.3");
        if (var_ign_mx_lookup_err)
index 807215dba90d35d07489af0e4c83d1404cfd2034..2b2e860a461c4ddf9194dafe630dd794ee539316 100644 (file)
@@ -59,6 +59,7 @@
        VAR_SMTP_ADDR_PREF, DEF_SMTP_ADDR_PREF, &var_smtp_addr_pref, 1, 0,
        VAR_SMTP_DNS_RES_OPT, DEF_SMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
        VAR_SMTP_DSN_FILTER, DEF_SMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0,
+       VAR_SMTP_DNS_RE_FILTER, DEF_SMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE smtp_time_table[] = {
index bc9e728509e8f9db91086773c11e8061ee7159a3..60112c37bd568d6fa51a875ad23dcf7708faae6c 100644 (file)
@@ -72,10 +72,12 @@ clean:
 
 tidy:  clean
 
-tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_exp_test \
+broken-tests: smtpd_check_test smtpd_check_test2 
+
+tests: smtpd_acl_test smtpd_exp_test \
        smtpd_token_test smtpd_check_test4 smtpd_check_dsn_test \
        smtpd_check_backup_test smtpd_dnswl_test smtpd_error_test \
-       smtpd_server_test smtpd_nullmx_test
+       smtpd_server_test smtpd_nullmx_test smtpd_dns_filter_test
 
 root_tests:
 
@@ -116,7 +118,6 @@ smtpd_exp_test: smtpd_check smtpd_exp.in smtpd_exp.ref
        rm -f smtpd_exp.tmp smtpd_check_access.*
 
 smtpd_server_test: smtpd_check smtpd_server.in smtpd_server.ref
-       $(SHLIB_ENV) ../postmap/postmap hash:smtpd_check_access
        $(SHLIB_ENV) ./smtpd_check <smtpd_server.in >smtpd_server.tmp 2>&1
        diff smtpd_server.ref smtpd_server.tmp
        rm -f smtpd_server.tmp smtpd_check_access.*
@@ -127,6 +128,13 @@ smtpd_nullmx_test: smtpd_check smtpd_nullmx.in smtpd_nullmx.ref
        diff smtpd_nullmx.ref smtpd_nullmx.tmp
        rm -f smtpd_nullmx.tmp smtpd_check_access.*
 
+smtpd_dns_filter_test: smtpd_check smtpd_dns_filter.in smtpd_dns_filter.ref \
+       ../dns/no-mx.reg ../dns/no-a.reg ../dns/error.reg
+       $(SHLIB_ENV) ./smtpd_check <smtpd_dns_filter.in 2>&1 | \
+           sed 's/\. [0-9]* IN/. TTL IN/' >smtpd_dns_filter.tmp
+       diff smtpd_dns_filter.ref smtpd_dns_filter.tmp
+       rm -f smtpd_dns_filter.tmp
+
 smtpd_check_dsn_test: smtpd_check smtpd_check_dsn.in smtpd_check_dsn.ref smtpd_check_access
        $(SHLIB_ENV) ../postmap/postmap hash:smtpd_check_access
        $(SHLIB_ENV) ./smtpd_check <smtpd_check_dsn.in >smtpd_check.tmp 2>&1
index 968656a620eae40faca4f442b5979b2c7fda6ad1..81ec424c998bfbae95a29682758e8e63f7bdbd69 100644 (file)
 /*     time limit per read or write system call, to a time limit to send
 /*     or receive a complete record (an SMTP command line, SMTP response
 /*     line, SMTP message content line, or TLS protocol message).
+/* .PP
+/*     Available in Postfix version 2.12 and later:
+/* .IP "\fBsmtpd_dns_reply_filter (empty)\fR"
+/*     Optional filter for Postfix SMTP server DNS lookup results.
 /* ADDRESS REWRITING CONTROLS
 /* .ad
 /* .fi
 /*     request is rejected by the reject_unauth_destination recipient
 /*     restriction.
 /* .IP "\fBunknown_address_reject_code (450)\fR"
-/*     The numerical Postfix SMTP server response code when a sender or
-/*     recipient address is rejected by the reject_unknown_sender_domain
-/*     or reject_unknown_recipient_domain restriction.
+/*     The numerical response code when the Postfix SMTP rejects a sender
+/*     or recipient address because its domain is unknown.
 /* .IP "\fBunknown_client_reject_code (450)\fR"
 /*     The numerical Postfix SMTP server response code when a client
 /*     without valid address <=> name mapping is rejected by the
@@ -1290,6 +1293,7 @@ bool    var_smtpd_tls_auth_only;
 char   *var_smtpd_cmd_filter;
 char   *var_smtpd_rej_footer;
 char   *var_smtpd_acl_perm_log;
+char   *var_smtpd_dns_re_filter;
 
 #ifdef USE_TLS
 char   *var_smtpd_relay_ccerts;
@@ -5415,6 +5419,13 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
        ehlo_discard_maps = maps_create(VAR_SMTPD_EHLO_DIS_MAPS,
                                        var_smtpd_ehlo_dis_maps,
                                        DICT_FLAG_LOCK);
+
+    /*
+     * DNS reply filter.
+     */
+    if (*var_smtpd_dns_re_filter)
+       dns_rr_filter_compile(VAR_SMTPD_DNS_RE_FILTER,
+                             var_smtpd_dns_re_filter);
 }
 
 /* post_jail_init - post-jail initialization */
@@ -5689,6 +5700,7 @@ int     main(int argc, char **argv)
        VAR_SMTPD_ACL_PERM_LOG, DEF_SMTPD_ACL_PERM_LOG, &var_smtpd_acl_perm_log, 0, 0,
        VAR_SMTPD_UPROXY_PROTO, DEF_SMTPD_UPROXY_PROTO, &var_smtpd_uproxy_proto, 0, 0,
        VAR_SMTPD_POLICY_DEF_ACTION, DEF_SMTPD_POLICY_DEF_ACTION, &var_smtpd_policy_def_action, 1, 0,
+       VAR_SMTPD_DNS_RE_FILTER, DEF_SMTPD_DNS_RE_FILTER, &var_smtpd_dns_re_filter, 0, 0,
        0,
     };
     static const CONFIG_RAW_TABLE raw_table[] = {
index 66e8c1dee820a3a76c9aa846aba4a1709131e9d0..3237ca0f7e4237479190b1e759c597016eba67f1 100644 (file)
@@ -1376,8 +1376,13 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
                              RR_ADDR_TYPES, T_MX, 0);
     if (dummy)
        dns_rr_free(dummy);
-    if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
-       /* We don't care about DNS_UNAVAIL. */
+    /* Allow MTA names to have nullMX records. */
+    if (dns_status != DNS_OK && dns_status != DNS_UNAVAIL) {
+       if (dns_status == DNS_POLICY) {
+           msg_warn("%s: address or MX lookup error: %s",
+                    name, "DNS reply filter drops all results");
+           return (SMTPD_CHECK_DUNNO);
+       }
        if (dns_status != DNS_RETRY)
            return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
                                       var_unk_name_code, "4.7.1",
@@ -1420,7 +1425,8 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
 #endif
 
 #define MAILHOST_LOOKUP_FLAGS \
-    (DNS_REQ_FLAG_STOP_OK | DNS_REQ_FLAG_STOP_INVAL | DNS_REQ_FLAG_STOP_UNAVAIL)
+    (DNS_REQ_FLAG_STOP_OK | DNS_REQ_FLAG_STOP_INVAL | \
+       DNS_REQ_FLAG_STOP_UNAVAIL | DNS_REQ_FLAG_STOP_MX_POLICY)
 
     dns_status = dns_lookup_l(name, 0, &dummy, (VSTRING *) 0,
                              (VSTRING *) 0, MAILHOST_LOOKUP_FLAGS,
@@ -1428,6 +1434,11 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
     if (dummy)
        dns_rr_free(dummy);
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
+       if (dns_status == DNS_POLICY) {
+           msg_warn("%s: MX or address lookup error: %s",
+                    name, "DNS reply filter drops all results");
+           return (SMTPD_CHECK_DUNNO);
+       }
        if (dns_status == DNS_UNAVAIL)
            return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
                                       var_nullmx_rcode,
@@ -1681,10 +1692,13 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
                      DNS_REQ_FLAG_NONE, inet_proto_info()->dns_atype_list);
     /* DNS_UNAVAIL is not applicable here. */
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
-       DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+       DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY,
                         450, "4.4.4",
-          "<%s>: %s rejected: Unable to look up host %s as mail exchanger",
-                        reply_name, reply_class, host);
+                        "<%s>: %s rejected: Unable to look up host "
+                        "%s as mail exchanger: %s",
+                        reply_name, reply_class, host,
+                        dns_status == DNS_POLICY ?
+                        "DNS reply filter policy" : dns_strerror(h_errno));
        return (NOPE);
     }
     for (rr = addr_list; rr != 0; rr = rr->next) {
@@ -1923,11 +1937,13 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
 #endif
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
        /* We don't care about DNS_UNAVAIL. */
-       if (dns_status == DNS_RETRY)
-           DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+       if (dns_status == DNS_RETRY || dns_status == DNS_POLICY)
+           DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
                             450, "4.4.4",
-                            "<%s>: %s rejected: Unable to look up mail exchanger information",
-                            reply_name, reply_class);
+                            "<%s>: %s rejected: Unable to look up mail "
+                            "exchanger information: %s",
+                        reply_name, reply_class, dns_status == DNS_POLICY ?
+                        "DNS reply filter policy" : dns_strerror(h_errno));
        return (SMTPD_CHECK_DUNNO);
     }
 
@@ -2945,7 +2961,8 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
        }
        if (dns_status != DNS_OK) {
            msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type),
-               domain && domain[1] ? domain : name, dns_strerror(h_errno));
+            domain && domain[1] ? domain : name, dns_status == DNS_POLICY ?
+                    "DNS reply filter policy" : dns_strerror(h_errno));
            return (SMTPD_CHECK_DUNNO);
        }
     }
@@ -3253,8 +3270,9 @@ static void *rbl_pagein(const char *query, void *unused_context)
 #define RBL_TXT_LIMIT  500
 
     rbl = (SMTPD_RBL_STATE *) mymalloc(sizeof(*rbl));
-    if (dns_lookup(query, T_TXT, 0, &txt_list,
-                  (VSTRING *) 0, (VSTRING *) 0) == DNS_OK) {
+    dns_status = dns_lookup(query, T_TXT, 0, &txt_list,
+                           (VSTRING *) 0, (VSTRING *) 0);
+    if (dns_status == DNS_OK) {
        buf = vstring_alloc(1);
        space_left = RBL_TXT_LIMIT;
        for (rr = txt_list; rr != 0 && space_left > 0; rr = next) {
@@ -3269,8 +3287,12 @@ static void *rbl_pagein(const char *query, void *unused_context)
        }
        rbl->txt = vstring_export(buf);
        dns_rr_free(txt_list);
-    } else
+    } else {
+       if (dns_status == DNS_POLICY)
+           msg_warn("%s: TXT lookup error: %s",
+                    query, "DNS reply filter drops all results");
        rbl->txt = 0;
+    }
     rbl->a = addr_list;
     return ((void *) rbl);
 }
@@ -5367,6 +5389,7 @@ char   *smtpd_check_eod(SMTPD_STATE *state)
 
 #include <mail_conf.h>
 #include <rewrite_clnt.h>
+#include <dns.h>
 
 #include <smtpd_chat.h>
 
@@ -5487,6 +5510,7 @@ static const STRING_TABLE string_table[] = {
     VAR_UNV_FROM_TF_ACT, DEF_REJECT_TMPF_ACT, &var_unv_from_tf_act,
     /* XXX Can't use ``$name'' type default values above. */
     VAR_SMTPD_ACL_PERM_LOG, DEF_SMTPD_ACL_PERM_LOG, &var_smtpd_acl_perm_log,
+    VAR_SMTPD_DNS_RE_FILTER, DEF_SMTPD_DNS_RE_FILTER, &var_smtpd_dns_re_filter,
     0,
 };
 
@@ -5563,6 +5587,7 @@ int     var_plaintext_code;
 bool    var_smtpd_peername_lookup;
 bool    var_smtpd_client_port_log;
 int     var_nullmx_rcode;
+char   *var_smtpd_dns_re_filter;
 
 #define int_table test_int_table
 
@@ -5882,9 +5907,26 @@ int     main(int argc, char **argv)
             * Special case: rewrite context.
             */
        case 1:
-           if (strcasecmp(args->argv[0], "rewrite") == 0)
+           if (strcasecmp(args->argv[0], "rewrite") == 0) {
                resp = smtpd_check_rewrite(&state);
-           break;
+               break;
+           }
+
+           /*
+            * Other parameter-less commands.
+            */
+           if (strcasecmp(args->argv[0], "flush_dnsxl_cache") == 0) {
+               if (smtpd_rbl_cache) {
+                   ctable_free(smtpd_rbl_cache);
+                   ctable_free(smtpd_rbl_byte_cache);
+               }
+               smtpd_rbl_cache = ctable_create(100, rbl_pagein,
+                                               rbl_pageout, (void *) 0);
+               smtpd_rbl_byte_cache = ctable_create(1000, rbl_byte_pagein,
+                                             rbl_byte_pageout, (void *) 0);
+               resp = 0;
+               break;
+           }
 
            /*
             * Special case: client identity.
@@ -6027,6 +6069,12 @@ int     main(int argc, char **argv)
                resp = 0;
                break;
            }
+           if (strcasecmp(args->argv[0], VAR_SMTPD_DNS_RE_FILTER) == 0) {
+               /* NOT: UPDATE_STRING */
+               dns_rr_filter_compile(VAR_SMTPD_DNS_RE_FILTER, args->argv[1]);
+               resp = 0;
+               break;
+           }
 #ifdef USE_TLS
            if (strcasecmp(args->argv[0], VAR_RELAY_CCERTS) == 0) {
                UPDATE_STRING(var_smtpd_relay_ccerts, args->argv[1]);
@@ -6121,6 +6169,7 @@ int     main(int argc, char **argv)
                sender_restrictions <restrictions>\n\
                recipient_restrictions <restrictions>\n\
                restriction_class name,<restrictions>\n\
+               flush_dnsxl_cache\n\
                \n\
                Note: no address rewriting \n";
            break;
index 88554d27f3a1759ae7c629f107cecef99e10a8ec..788276adfe61763964e9f41c3f487548566f0898 100644 (file)
@@ -41,7 +41,15 @@ blackholes.mail-abuse.org    $rbl_code client=$client
  rbl_code=$rbl_code rbl_domain=$rbl_domain rbl_txt=$rbl_txt rbl_what=$rbl_what
  rbl_class=$rbl_class
 
-dsn.rfc-ignorant.org   $rbl_code client=$client
+rhsbl.porcupine.org    $rbl_code client=$client
+ client_address=$client_address
+ client_name=$client_name helo_name=$helo_name 
+ sender=$sender sender_name=$sender_name  sender_domain=$sender_domain
+ recipient=$recipient recipient_name=$recipient_name recipient_domain=$recipient_domain
+ rbl_code=$rbl_code rbl_domain=$rbl_domain rbl_txt=$rbl_txt rbl_what=$rbl_what
+ rbl_class=$rbl_class
+
+dnswl.porcupine.org    $rbl_code client=$client
  client_address=$client_address
  client_name=$client_name helo_name=$helo_name 
  sender=$sender sender_name=$sender_name  sender_domain=$sender_domain
diff --git a/postfix/src/smtpd/smtpd_dns_filter.in b/postfix/src/smtpd/smtpd_dns_filter.in
new file mode 100644 (file)
index 0000000..e2048c5
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# Initialize
+#
+client localhost 127.0.0.1
+smtpd_delay_reject 0
+#
+# Test reject_unknown_helo_hostname
+#
+smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+helo_restrictions reject_unknown_helo_hostname,permit
+# EXPECT OK + "all MX records dropped" warning.
+helo xn--1xa.porcupine.org
+# EXPECT OK (nullmx has A record)
+helo nullmx.porcupine.org
+# EXPECT reject (nxdomain is not filtered).
+helo nxdomain.porcupine.org
+smtpd_dns_reply_filter regexp:../dns/no-a.reg
+# EXPECT OK (host has AAAA record).
+mail user@spike.porcupine.org
+helo spike.porcupine.org
+# EXPECT OK + "all A records dropped" warning + no delayed reject.
+helo umbilical.porcupine.org
+mail user@spike.porcupine.org
+rcpt user@spike.porcupine.org
+smtpd_dns_reply_filter regexp:../dns/error.reg
+# EXPECT OK + "filter config error" warning + delayed reject.
+helo spike.porcupine.org
+mail user@spike.porcupine.org
+rcpt user@spike.porcupine.org
+# EXPECT OK + "filter config error" warning (nullmx has A record) + delayed reject.
+helo nullmx.porcupine.org
+mail user@spike.porcupine.org
+rcpt user@spike.porcupine.org
+# EXPECT reject (nxdomain is not filtered).
+helo nxdomain.porcupine.org
+#
+# Test reject_unknown_sender_domain (same code as
+# reject_unknown_recipient_domain).
+#
+smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+helo localhost
+sender_restrictions reject_unknown_sender_domain
+# EXPECT OK + "all MX records dropped" warning.
+mail user@xn--1xa.porcupine.org
+# EXPECT reject (nullmx is not filtered).
+mail user@nullmx.porcupine.org
+# EXPECT reject (nxdomain is not filtered).
+mail user@nxdomain.porcupine.org
+# EXPECT OK
+mail user@localhost
+smtpd_dns_reply_filter regexp:../dns/no-a.reg
+# EXPECT OK (host has AAAA record).
+mail user@spike.porcupine.org
+# EXPECT OK + "all A records dropped" warning.
+mail user@umbilical.porcupine.org
+smtpd_dns_reply_filter regexp:../dns/error.reg
+# EXPECT OK + "filter config error" warning + delayed reject.
+mail user@xn--1xa.porcupine.org
+rcpt user
+# EXPECT reject (nullmx is not filtered).
+mail user@nullmx.porcupine.org
+# EXPECT reject (nxdomain is not filtered).
+mail user@nxdomain.porcupine.org
+#
+# Test reject_rbl_client
+#
+client_restrictions reject_rbl_client,dnsbltest.porcupine.org
+smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+flush_dnsxl_cache
+# EXPECT reject + A and TXT record.
+client localhost 127.0.0.2
+smtpd_dns_reply_filter regexp:../dns/no-a.reg
+flush_dnsxl_cache
+# EXPECT OK + "all A results dropped" warning.
+client localhost 127.0.0.2
+smtpd_dns_reply_filter regexp:../dns/no-txt.reg
+flush_dnsxl_cache
+# EXPECT reject + A record, "all TXT results dropped" warning.
+client localhost 127.0.0.2
+smtpd_dns_reply_filter regexp:../dns/error.reg
+flush_dnsxl_cache
+# EXPECT OK + "filter configuration error"
+client localhost 127.0.0.2
diff --git a/postfix/src/smtpd/smtpd_dns_filter.ref b/postfix/src/smtpd/smtpd_dns_filter.ref
new file mode 100644 (file)
index 0000000..5eacfe3
--- /dev/null
@@ -0,0 +1,163 @@
+>>> #
+>>> # Initialize
+>>> #
+>>> client localhost 127.0.0.1
+OK
+>>> smtpd_delay_reject 0
+OK
+>>> #
+>>> # Test reject_unknown_helo_hostname
+>>> #
+>>> smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+OK
+>>> helo_restrictions reject_unknown_helo_hostname,permit
+OK
+>>> # EXPECT OK + "all MX records dropped" warning.
+>>> helo xn--1xa.porcupine.org
+./smtpd_check: ignoring DNS RR: xn--1xa.porcupine.org. TTL IN MX 10 spike.porcupine.org.
+./smtpd_check: warning: xn--1xa.porcupine.org: address or MX lookup error: DNS reply filter drops all results
+OK
+>>> # EXPECT OK (nullmx has A record)
+>>> helo nullmx.porcupine.org
+OK
+>>> # EXPECT reject (nxdomain is not filtered).
+>>> helo nxdomain.porcupine.org
+./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 450 4.7.1 <nxdomain.porcupine.org>: Helo command rejected: Host not found; proto=SMTP helo=<nxdomain.porcupine.org>
+450 4.7.1 <nxdomain.porcupine.org>: Helo command rejected: Host not found
+>>> smtpd_dns_reply_filter regexp:../dns/no-a.reg
+OK
+>>> # EXPECT OK (host has AAAA record).
+>>> mail user@spike.porcupine.org
+OK
+>>> helo spike.porcupine.org
+./smtpd_check: ignoring DNS RR: spike.porcupine.org. TTL IN A 168.100.189.2
+OK
+>>> # EXPECT OK + "all A records dropped" warning + no delayed reject.
+>>> helo umbilical.porcupine.org
+./smtpd_check: ignoring DNS RR: umbilical.porcupine.org. TTL IN A 168.100.189.1
+./smtpd_check: warning: umbilical.porcupine.org: address or MX lookup error: DNS reply filter drops all results
+OK
+>>> mail user@spike.porcupine.org
+OK
+>>> rcpt user@spike.porcupine.org
+OK
+>>> smtpd_dns_reply_filter regexp:../dns/error.reg
+OK
+>>> # EXPECT OK + "filter config error" warning + delayed reject.
+>>> helo spike.porcupine.org
+./smtpd_check: warning: smtpd_dns_reply_filter: unknown DNS filter action: "oops"
+./smtpd_check: warning: smtpd_dns_reply_filter: unknown DNS filter action: "oops"
+OK
+>>> mail user@spike.porcupine.org
+OK
+>>> rcpt user@spike.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from localhost[127.0.0.1]: 450 4.7.1 <spike.porcupine.org>: Helo command rejected: Host not found; from=<user@spike.porcupine.org> to=<user@spike.porcupine.org> proto=SMTP helo=<spike.porcupine.org>
+450 4.7.1 <spike.porcupine.org>: Helo command rejected: Host not found
+>>> # EXPECT OK + "filter config error" warning (nullmx has A record) + delayed reject.
+>>> helo nullmx.porcupine.org
+./smtpd_check: warning: smtpd_dns_reply_filter: unknown DNS filter action: "oops"
+OK
+>>> mail user@spike.porcupine.org
+OK
+>>> rcpt user@spike.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from localhost[127.0.0.1]: 450 4.7.1 <nullmx.porcupine.org>: Helo command rejected: Host not found; from=<user@spike.porcupine.org> to=<user@spike.porcupine.org> proto=SMTP helo=<nullmx.porcupine.org>
+450 4.7.1 <nullmx.porcupine.org>: Helo command rejected: Host not found
+>>> # EXPECT reject (nxdomain is not filtered).
+>>> helo nxdomain.porcupine.org
+./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 450 4.7.1 <nxdomain.porcupine.org>: Helo command rejected: Host not found; from=<user@spike.porcupine.org> proto=SMTP helo=<nxdomain.porcupine.org>
+450 4.7.1 <nxdomain.porcupine.org>: Helo command rejected: Host not found
+>>> #
+>>> # Test reject_unknown_sender_domain (same code as
+>>> # reject_unknown_recipient_domain).
+>>> #
+>>> smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+OK
+>>> helo localhost
+OK
+>>> sender_restrictions reject_unknown_sender_domain
+OK
+>>> # EXPECT OK + "all MX records dropped" warning.
+>>> mail user@xn--1xa.porcupine.org
+./smtpd_check: ignoring DNS RR: xn--1xa.porcupine.org. TTL IN MX 10 spike.porcupine.org.
+./smtpd_check: warning: xn--1xa.porcupine.org: MX or address lookup error: DNS reply filter drops all results
+OK
+>>> # EXPECT reject (nullmx is not filtered).
+>>> mail user@nullmx.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from localhost[127.0.0.1]: 556 5.7.0 <user@nullmx.porcupine.org>: Sender address rejected: Domain nullmx.porcupine.org does not accept mail; from=<user@nullmx.porcupine.org> proto=SMTP helo=<localhost>
+556 5.7.0 <user@nullmx.porcupine.org>: Sender address rejected: Domain nullmx.porcupine.org does not accept mail
+>>> # EXPECT reject (nxdomain is not filtered).
+>>> mail user@nxdomain.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from localhost[127.0.0.1]: 450 4.1.8 <user@nxdomain.porcupine.org>: Sender address rejected: Domain not found; from=<user@nxdomain.porcupine.org> proto=SMTP helo=<localhost>
+450 4.1.8 <user@nxdomain.porcupine.org>: Sender address rejected: Domain not found
+>>> # EXPECT OK
+>>> mail user@localhost
+OK
+>>> smtpd_dns_reply_filter regexp:../dns/no-a.reg
+OK
+>>> # EXPECT OK (host has AAAA record).
+>>> mail user@spike.porcupine.org
+./smtpd_check: ignoring DNS RR: spike.porcupine.org. TTL IN A 168.100.189.2
+OK
+>>> # EXPECT OK + "all A records dropped" warning.
+>>> mail user@umbilical.porcupine.org
+./smtpd_check: ignoring DNS RR: umbilical.porcupine.org. TTL IN A 168.100.189.1
+./smtpd_check: warning: umbilical.porcupine.org: MX or address lookup error: DNS reply filter drops all results
+OK
+>>> smtpd_dns_reply_filter regexp:../dns/error.reg
+OK
+>>> # EXPECT OK + "filter config error" warning + delayed reject.
+>>> mail user@xn--1xa.porcupine.org
+./smtpd_check: warning: smtpd_dns_reply_filter: unknown DNS filter action: "oops"
+OK
+>>> rcpt user
+./smtpd_check: <queue id>: reject: RCPT from localhost[127.0.0.1]: 450 4.1.8 <user@xn--1xa.porcupine.org>: Sender address rejected: Domain not found; from=<user@xn--1xa.porcupine.org> to=<user> proto=SMTP helo=<localhost>
+450 4.1.8 <user@xn--1xa.porcupine.org>: Sender address rejected: Domain not found
+>>> # EXPECT reject (nullmx is not filtered).
+>>> mail user@nullmx.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from localhost[127.0.0.1]: 556 5.7.0 <user@nullmx.porcupine.org>: Sender address rejected: Domain nullmx.porcupine.org does not accept mail; from=<user@nullmx.porcupine.org> proto=SMTP helo=<localhost>
+556 5.7.0 <user@nullmx.porcupine.org>: Sender address rejected: Domain nullmx.porcupine.org does not accept mail
+>>> # EXPECT reject (nxdomain is not filtered).
+>>> mail user@nxdomain.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from localhost[127.0.0.1]: 450 4.1.8 <user@nxdomain.porcupine.org>: Sender address rejected: Domain not found; from=<user@nxdomain.porcupine.org> proto=SMTP helo=<localhost>
+450 4.1.8 <user@nxdomain.porcupine.org>: Sender address rejected: Domain not found
+>>> #
+>>> # Test reject_rbl_client
+>>> #
+>>> client_restrictions reject_rbl_client,dnsbltest.porcupine.org
+OK
+>>> smtpd_dns_reply_filter regexp:../dns/no-mx.reg
+OK
+>>> flush_dnsxl_cache
+OK
+>>> # EXPECT reject + A and TXT record.
+>>> client localhost 127.0.0.2
+./smtpd_check: <queue id>: reject: CONNECT from localhost[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test; from=<user@nxdomain.porcupine.org> proto=SMTP helo=<localhost>
+554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test
+>>> smtpd_dns_reply_filter regexp:../dns/no-a.reg
+OK
+>>> flush_dnsxl_cache
+OK
+>>> # EXPECT OK + "all A results dropped" warning.
+>>> client localhost 127.0.0.2
+./smtpd_check: ignoring DNS RR: 2.0.0.127.dnsbltest.porcupine.org. TTL IN A 127.0.0.2
+./smtpd_check: warning: 2.0.0.127.dnsbltest.porcupine.org: RBL lookup error: Error looking up name=2.0.0.127.dnsbltest.porcupine.org type=A: DNS reply filter drops all results
+OK
+>>> smtpd_dns_reply_filter regexp:../dns/no-txt.reg
+OK
+>>> flush_dnsxl_cache
+OK
+>>> # EXPECT reject + A record, "all TXT results dropped" warning.
+>>> client localhost 127.0.0.2
+./smtpd_check: ignoring DNS RR: 2.0.0.127.dnsbltest.porcupine.org. TTL IN TXT DNS blocklist test.
+./smtpd_check: warning: 2.0.0.127.dnsbltest.porcupine.org: TXT lookup error: DNS reply filter drops all results
+./smtpd_check: <queue id>: reject: CONNECT from localhost[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; from=<user@nxdomain.porcupine.org> proto=SMTP helo=<localhost>
+554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org
+>>> smtpd_dns_reply_filter regexp:../dns/error.reg
+OK
+>>> flush_dnsxl_cache
+OK
+>>> # EXPECT OK + "filter configuration error"
+>>> client localhost 127.0.0.2
+./smtpd_check: warning: smtpd_dns_reply_filter: unknown DNS filter action: "oops"
+./smtpd_check: warning: 2.0.0.127.dnsbltest.porcupine.org: RBL lookup error: Error looking up name=2.0.0.127.dnsbltest.porcupine.org type=A: Invalid DNS reply filter syntax
+OK
index 147dbcaca6f0067ee5a1efedbfb91573726d09ae..6546e023ecb37de8230e96e1c75a5154ce1552f8 100644 (file)
@@ -33,7 +33,7 @@ rcpt wietse@porcupine.org
 #
 
 # Whitelist overrides reject.
-client_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject
+client_restrictions permit_rhswl_client,dnswl.porcupine.org,reject
 # Non-whitelisted client name - reject.
 client spike.porcupine.org 168.100.189.2
 # Whitelisted client name - accept.
@@ -41,7 +41,7 @@ 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
+recipient_restrictions permit_rhswl_client,dnswl.porcupine.org,reject_unauth_destination
 # Non-whitelisted client name.
 client spike.porcupine.org 168.100.189.2
 # Unauthorized destination - reject.
index 14d989874b9a6e87b69723db5baa90bbdd8b68b8..7c23459c49b1883c690cbe878ed60e69a6a8ad51 100644 (file)
@@ -48,7 +48,7 @@ OK
 >>> #
 >>> 
 >>> # Whitelist overrides reject.
->>> client_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject
+>>> client_restrictions permit_rhswl_client,dnswl.porcupine.org,reject
 OK
 >>> # Non-whitelisted client name - reject.
 >>> client spike.porcupine.org 168.100.189.2
@@ -61,7 +61,7 @@ OK
 >>> # Whitelist does not override reject_unauth_destination.
 >>> client_restrictions permit
 OK
->>> recipient_restrictions permit_rhswl_client,dsn.rfc-ignorant.org,reject_unauth_destination
+>>> recipient_restrictions permit_rhswl_client,dnswl.porcupine.org,reject_unauth_destination
 OK
 >>> # Non-whitelisted client name.
 >>> client spike.porcupine.org 168.100.189.2
index a8baf76563e2e3b4115805f2742ae6a6a7d1fcc8..584acf397f31a4114284115da62953db004940f5 100644 (file)
@@ -32,7 +32,7 @@ rcpt rname@rdomain
 #
 # RHSBL sender domain name
 #
-recipient_restrictions reject_rhsbl_sender,dsn.rfc-ignorant.org
+recipient_restrictions reject_rhsbl_sender,rhsbl.porcupine.org
 client spike.porcupine.org 168.100.189.2
 mail sname@example.tld
 rcpt rname@rdomain
@@ -41,14 +41,14 @@ rcpt rname@rdomain
 #
 # RHSBL client domain name
 #
-recipient_restrictions reject_rhsbl_client,dsn.rfc-ignorant.org
+recipient_restrictions reject_rhsbl_client,rhsbl.porcupine.org
 client example.tld 1.2.3.4
 mail sname@sdomain
 rcpt rname@rdomain
 #
 # RHSBL recipient domain name
 #
-recipient_restrictions reject_rhsbl_recipient,dsn.rfc-ignorant.org
+recipient_restrictions reject_rhsbl_recipient,rhsbl.porcupine.org
 client spike.porcupine.org 168.100.189.2
 mail sname@sdomain
 rcpt rname@rdomain
@@ -56,7 +56,7 @@ rcpt rname@example.tld
 #
 # RHSBL helo domain name
 #
-recipient_restrictions reject_rhsbl_helo,abuse.rfc-ignorant.org
+recipient_restrictions reject_rhsbl_helo,rhsbl.porcupine.org
 helo example.tld
 mail sname@sdomain
 rcpt rname@rdomain
index 5e4264d62321ab9d4337b9ea0c17a213ff326e48..6d7e9fc8d84c0660314012fa324da07f72a3f20d 100644 (file)
@@ -30,8 +30,8 @@ OK
 >>> client foo 127.0.0.2
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
-554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
+554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test
 >>> #
 >>> recipient_restrictions reject_rbl_client,dnsbltest.porcupine.org
 OK
@@ -42,15 +42,15 @@ OK
 >>> client foo 127.0.0.2
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
-554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
+554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test
 >>> recipient_restrictions reject_rbl_client,dnsbltest.porcupine.org=127.0.0.2
 OK
 >>> client foo 127.0.0.2
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
-554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
+554 5.7.1 Service unavailable; Client host [127.0.0.2] blocked using dnsbltest.porcupine.org; DNS blocklist test
 >>> client foo 127.0.0.1
 OK
 >>> rcpt rname@rdomain
@@ -58,15 +58,15 @@ OK
 >>> #
 >>> # RHSBL sender domain name
 >>> #
->>> recipient_restrictions reject_rhsbl_sender,dsn.rfc-ignorant.org
+>>> recipient_restrictions reject_rhsbl_sender,rhsbl.porcupine.org
 OK
 >>> client spike.porcupine.org 168.100.189.2
 OK
 >>> mail sname@example.tld
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@example.tld sender_name=sname  sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=sname@example.tld rbl_class=Sender address; from=<sname@example.tld> to=<rname@rdomain> proto=SMTP helo=<foobar>
-554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@example.tld sender_name=sname  sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=sname@example.tld rbl_class=Sender address
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@example.tld sender_name=sname  sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=sname@example.tld rbl_class=Sender address; from=<sname@example.tld> to=<rname@rdomain> proto=SMTP helo=<foobar>
+554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@example.tld sender_name=sname  sender_domain=example.tld recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=sname@example.tld rbl_class=Sender address
 >>> mail sname@sdomain
 OK
 >>> rcpt rname@rdomain
@@ -74,19 +74,19 @@ OK
 >>> #
 >>> # RHSBL client domain name
 >>> #
->>> recipient_restrictions reject_rhsbl_client,dsn.rfc-ignorant.org
+>>> recipient_restrictions reject_rhsbl_client,rhsbl.porcupine.org
 OK
 >>> client example.tld 1.2.3.4
 OK
 >>> mail sname@sdomain
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from example.tld[1.2.3.4]: 554 5.7.1 client=example.tld[1.2.3.4] client_address=1.2.3.4 client_name=example.tld helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=example.tld rbl_class=Client host; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
-554 5.7.1 client=example.tld[1.2.3.4] client_address=1.2.3.4 client_name=example.tld helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=example.tld rbl_class=Client host
+./smtpd_check: <queue id>: reject: RCPT from example.tld[1.2.3.4]: 554 5.7.1 client=example.tld[1.2.3.4] client_address=1.2.3.4 client_name=example.tld helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=example.tld rbl_class=Client host; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<foobar>
+554 5.7.1 client=example.tld[1.2.3.4] client_address=1.2.3.4 client_name=example.tld helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=example.tld rbl_class=Client host
 >>> #
 >>> # RHSBL recipient domain name
 >>> #
->>> recipient_restrictions reject_rhsbl_recipient,dsn.rfc-ignorant.org
+>>> recipient_restrictions reject_rhsbl_recipient,rhsbl.porcupine.org
 OK
 >>> client spike.porcupine.org 168.100.189.2
 OK
@@ -95,17 +95,17 @@ OK
 >>> rcpt rname@rdomain
 OK
 >>> rcpt rname@example.tld
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@example.tld recipient_name=rname recipient_domain=example.tld rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=rname@example.tld rbl_class=Recipient address; from=<sname@sdomain> to=<rname@example.tld> proto=SMTP helo=<foobar>
-554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@example.tld recipient_name=rname recipient_domain=example.tld rbl_code=554 rbl_domain=dsn.rfc-ignorant.org rbl_txt=Not supporting null originator (DSN) rbl_what=rname@example.tld rbl_class=Recipient address
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@example.tld recipient_name=rname recipient_domain=example.tld rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=rname@example.tld rbl_class=Recipient address; from=<sname@sdomain> to=<rname@example.tld> proto=SMTP helo=<foobar>
+554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=foobar  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@example.tld recipient_name=rname recipient_domain=example.tld rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=rname@example.tld rbl_class=Recipient address
 >>> #
 >>> # RHSBL helo domain name
 >>> #
->>> recipient_restrictions reject_rhsbl_helo,abuse.rfc-ignorant.org
+>>> recipient_restrictions reject_rhsbl_helo,rhsbl.porcupine.org
 OK
 >>> helo example.tld
 OK
 >>> mail sname@sdomain
 OK
 >>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<example.tld>
-554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=example.tld  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=example.tld rbl_class=Helo command; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<example.tld>
+554 5.7.1 client=spike.porcupine.org[168.100.189.2] client_address=168.100.189.2 client_name=spike.porcupine.org helo_name=example.tld  sender=sname@sdomain sender_name=sname  sender_domain=sdomain recipient=rname@rdomain recipient_name=rname recipient_domain=rdomain rbl_code=554 rbl_domain=rhsbl.porcupine.org rbl_txt=RHSBL test rbl_what=example.tld rbl_class=Helo command
index fc0758bd14279a5cf5f15c1b477c9827bb039542..3fd269482961cf6288a60e9501ee22187061992b 100644 (file)
@@ -16,7 +16,7 @@
 /*     across SMTP sessions (not process life times). Addresses
 /*     are always resolved in local rewriting context.
 /*
-/*     smtpd_resolve_init() initializes the cache and must
+/*     smtpd_resolve_init() initializes the cache and must be
 /*     called before the cache can be used. This function may also
 /*     be called to flush the cache after an address class update.
 /*
@@ -119,7 +119,8 @@ void    smtpd_resolve_init(int cache_size)
 {
 
     /*
-     * Sanity check.
+     * Flush a pre-existing cache. The smtpd_check test program requires this
+     * after an address class change.
      */
     if (smtpd_resolve_cache)
        ctable_free(smtpd_resolve_cache);
index 8bd78bceba1056b3ea0978bcba002b713ea1934f..2646ac48fdde5a16e96984aa28287e8bc1d8b164 100644 (file)
@@ -4,56 +4,53 @@
 #! ../bin/postmap smtpd_check_access
 #msg_verbose 1
 smtpd_delay_reject 0
-mynetworks 127.0.0.0/8,168.100.189.0/28
 relay_domains porcupine.org
-maps_rbl_domains dnsbltest.porcupine.org
-rbl_reply_maps hash:smtpd_check_access
 client spike.porcupine.org 168.100.189.2
 #
 # Check MX access
 #
-helo_restrictions check_helo_mx_access,hash:smtpd_check_access
-#helo verisign-wildcard.com
-helo verisign.com
+helo_restrictions check_helo_mx_access,inline:{168.100.189.2=reject}
+helo www.porcupine.org
 helo example.tld
-sender_restrictions check_sender_mx_access,hash:smtpd_check_access
-mail foo@pls.net.au
-#mail foo@verisign-wildcard.com
-mail foo@verisign.com
-recipient_restrictions check_recipient_mx_access,hash:smtpd_check_access
-#rcpt foo@verisign-wildcard.com
-rcpt foo@verisign.com
-rcpt foo@1.2.3.porcupine.org
+helo foo@postfix.org
+sender_restrictions check_sender_mx_access,inline:{168.100.189.2=reject}
+mail foo@www.porcupine.org
+mail example.tld
+mail foo@postfix.org
+recipient_restrictions check_recipient_mx_access,inline:{168.100.189.2=reject}
+rcpt foo@www.porcupine.org
+rcpt foo@example.tld
+rcpt foo@postfix.org
 #
 # Check NS access
 #
-helo_restrictions check_helo_ns_access,hash:smtpd_check_access
-helo email-publisher.com
-helo ns1.topica.com
-#helo verisign-wildcard.com
+helo_restrictions check_helo_ns_access,inline:{168.100.189.2=reject}
+helo www.porcupine.org
 helo example.tld
-sender_restrictions check_sender_ns_access,hash:smtpd_check_access
-mail foo@email-publisher.com
-mail foo@ns1.topica.com
-#mail foo@verisign-wildcard.com
-recipient_restrictions check_recipient_ns_access,hash:smtpd_check_access
-rcpt foo@email-publisher.com
-rcpt foo@ns1.topica.com
-#rcpt foo@verisign-wildcard.com
-rcpt foo@1.2.3.porcupine.org
+helo foo@postfix.org
+sender_restrictions check_sender_ns_access,inline:{168.100.189.2=reject}
+mail foo@www.porcupine.org
+mail example.tld
+mail foo@postfix.org
+recipient_restrictions check_recipient_ns_access,inline:{168.100.189.2=reject}
+rcpt foo@www.porcupine.org
+rcpt foo@example.tld
+rcpt foo@postfix.org
 #
 # Check A access
 #
-helo_restrictions check_helo_a_access,hash:smtpd_check_access
-helo help.gypsysoul.org
-helo gypsysoul.org
-client_restrictions check_client_a_access,hash:smtpd_check_access
-client help.gypsysoul.org 1.2.3.4
-client gypsysoul.org 1.2.3.4
-#reverse_client_restrictions check_reverse_client_a_access,hash:smtpd_check_access
-#client help.gypsysoul.org 1.2.3.4
-#client gypsysoul.org 1.2.3.4
-sender_restrictions check_sender_a_access,hash:smtpd_check_access
-mail foo@gypsysoul.org
-recipient_restrictions check_recipient_a_access,hash:smtpd_check_access
-mail foo@gypsysoul.org
+helo_restrictions check_helo_a_access,inline:{168.100.189.2=reject}
+helo spike.porcupine.org
+helo www.porcupine.org
+client_restrictions check_client_a_access,inline:{168.100.189.2=reject}
+client spike.porcupine.org 1.2.3.4
+client www.porcupine.org 1.2.3.4
+reverse_client_restrictions check_reverse_client_a_access,inline:{168.100.189.2=reject}
+client spike.porcupine.org 1.2.3.4
+client www.porcupine.org 1.2.3.4
+sender_restrictions check_sender_a_access,inline:{168.100.189.2=reject}
+mail foo@spike.porcupine.org
+mail foo@www.porcupine.org
+recipient_restrictions check_recipient_a_access,inline:{168.100.189.2=reject}
+rcpt foo@spike.porcupine.org
+rcpt foo@www.porcupine.org
index 6d8a511f9d33e31bfba6d927c424f26c1c758c5c..a35a15f8f6560a718711c85aba398aa761d8aa1d 100644 (file)
 >>> #msg_verbose 1
 >>> smtpd_delay_reject 0
 OK
->>> mynetworks 127.0.0.0/8,168.100.189.0/28
-OK
 >>> relay_domains porcupine.org
 OK
->>> maps_rbl_domains dnsbltest.porcupine.org
-OK
->>> rbl_reply_maps hash:smtpd_check_access
-OK
 >>> client spike.porcupine.org 168.100.189.2
 OK
 >>> #
 >>> # Check MX access
 >>> #
->>> helo_restrictions check_helo_mx_access,hash:smtpd_check_access
-OK
->>> #helo verisign-wildcard.com
->>> helo verisign.com
+>>> helo_restrictions check_helo_mx_access,inline:{168.100.189.2=reject}
 OK
+>>> helo www.porcupine.org
+./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <www.porcupine.org>: Helo command rejected: Access denied; proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <www.porcupine.org>: Helo command rejected: Access denied
 >>> helo example.tld
 ./smtpd_check: warning: Unable to look up MX host example.tld for Helo command example.tld: hostname nor servname provided, or not known
 OK
->>> sender_restrictions check_sender_mx_access,hash:smtpd_check_access
+>>> helo foo@postfix.org
+OK
+>>> sender_restrictions check_sender_mx_access,inline:{168.100.189.2=reject}
 OK
->>> mail foo@pls.net.au
+>>> mail foo@www.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@www.porcupine.org>: Sender address rejected: Access denied; from=<foo@www.porcupine.org> proto=SMTP helo=<foo@postfix.org>
+554 5.7.1 <foo@www.porcupine.org>: Sender address rejected: Access denied
+>>> mail example.tld
+./smtpd_check: warning: Unable to look up MX host example.tld for Sender address example.tld: hostname nor servname provided, or not known
 OK
->>> #mail foo@verisign-wildcard.com
->>> mail foo@verisign.com
+>>> mail foo@postfix.org
 OK
->>> recipient_restrictions check_recipient_mx_access,hash:smtpd_check_access
+>>> recipient_restrictions check_recipient_mx_access,inline:{168.100.189.2=reject}
 OK
->>> #rcpt foo@verisign-wildcard.com
->>> rcpt foo@verisign.com
+>>> rcpt foo@www.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@www.porcupine.org>: Recipient address rejected: Access denied; from=<foo@postfix.org> to=<foo@www.porcupine.org> proto=SMTP helo=<foo@postfix.org>
+554 5.7.1 <foo@www.porcupine.org>: Recipient address rejected: Access denied
+>>> rcpt foo@example.tld
+./smtpd_check: warning: Unable to look up MX host example.tld for Recipient address foo@example.tld: hostname nor servname provided, or not known
+OK
+>>> rcpt foo@postfix.org
 OK
->>> rcpt foo@1.2.3.porcupine.org
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@1.2.3.porcupine.org>: Recipient address rejected: mail server 10.10.10.10; from=<foo@verisign.com> to=<foo@1.2.3.porcupine.org> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@1.2.3.porcupine.org>: Recipient address rejected: mail server 10.10.10.10
 >>> #
 >>> # Check NS access
 >>> #
->>> helo_restrictions check_helo_ns_access,hash:smtpd_check_access
-OK
->>> helo email-publisher.com
-./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <email-publisher.com>: Helo command rejected: Access denied; from=<foo@verisign.com> proto=SMTP helo=<email-publisher.com>
-554 5.7.1 <email-publisher.com>: Helo command rejected: Access denied
->>> helo ns1.topica.com
-./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <ns1.topica.com>: Helo command rejected: Access denied; from=<foo@verisign.com> proto=SMTP helo=<ns1.topica.com>
-554 5.7.1 <ns1.topica.com>: Helo command rejected: Access denied
->>> #helo verisign-wildcard.com
+>>> helo_restrictions check_helo_ns_access,inline:{168.100.189.2=reject}
+OK
+>>> helo www.porcupine.org
+./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <www.porcupine.org>: Helo command rejected: Access denied; from=<foo@postfix.org> proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <www.porcupine.org>: Helo command rejected: Access denied
 >>> helo example.tld
 ./smtpd_check: warning: Unable to look up NS host for example.tld: Host not found
 OK
->>> sender_restrictions check_sender_ns_access,hash:smtpd_check_access
-OK
->>> mail foo@email-publisher.com
-./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@email-publisher.com>: Sender address rejected: Access denied; from=<foo@email-publisher.com> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@email-publisher.com>: Sender address rejected: Access denied
->>> mail foo@ns1.topica.com
-./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@ns1.topica.com>: Sender address rejected: Access denied; from=<foo@ns1.topica.com> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@ns1.topica.com>: Sender address rejected: Access denied
->>> #mail foo@verisign-wildcard.com
->>> recipient_restrictions check_recipient_ns_access,hash:smtpd_check_access
-OK
->>> rcpt foo@email-publisher.com
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@email-publisher.com>: Recipient address rejected: Access denied; from=<foo@ns1.topica.com> to=<foo@email-publisher.com> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@email-publisher.com>: Recipient address rejected: Access denied
->>> rcpt foo@ns1.topica.com
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@ns1.topica.com>: Recipient address rejected: Access denied; from=<foo@ns1.topica.com> to=<foo@ns1.topica.com> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@ns1.topica.com>: Recipient address rejected: Access denied
->>> #rcpt foo@verisign-wildcard.com
->>> rcpt foo@1.2.3.porcupine.org
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@1.2.3.porcupine.org>: Recipient address rejected: ns or mx server spike.porcupine.org; from=<foo@ns1.topica.com> to=<foo@1.2.3.porcupine.org> proto=SMTP helo=<example.tld>
-554 5.7.1 <foo@1.2.3.porcupine.org>: Recipient address rejected: ns or mx server spike.porcupine.org
+>>> helo foo@postfix.org
+OK
+>>> sender_restrictions check_sender_ns_access,inline:{168.100.189.2=reject}
+OK
+>>> mail foo@www.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@www.porcupine.org>: Sender address rejected: Access denied; from=<foo@www.porcupine.org> proto=SMTP helo=<foo@postfix.org>
+554 5.7.1 <foo@www.porcupine.org>: Sender address rejected: Access denied
+>>> mail example.tld
+./smtpd_check: warning: Unable to look up NS host for example.tld: Host not found
+OK
+>>> mail foo@postfix.org
+OK
+>>> recipient_restrictions check_recipient_ns_access,inline:{168.100.189.2=reject}
+OK
+>>> rcpt foo@www.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <foo@www.porcupine.org>: Recipient address rejected: Access denied; from=<foo@postfix.org> to=<foo@www.porcupine.org> proto=SMTP helo=<foo@postfix.org>
+554 5.7.1 <foo@www.porcupine.org>: Recipient address rejected: Access denied
+>>> rcpt foo@example.tld
+./smtpd_check: warning: Unable to look up NS host for example.tld: Host not found
+OK
+>>> rcpt foo@postfix.org
+OK
 >>> #
 >>> # Check A access
 >>> #
->>> helo_restrictions check_helo_a_access,hash:smtpd_check_access
+>>> helo_restrictions check_helo_a_access,inline:{168.100.189.2=reject}
+OK
+>>> helo spike.porcupine.org
+./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <spike.porcupine.org>: Helo command rejected: Access denied; from=<foo@postfix.org> proto=SMTP helo=<spike.porcupine.org>
+554 5.7.1 <spike.porcupine.org>: Helo command rejected: Access denied
+>>> helo www.porcupine.org
+OK
+>>> client_restrictions check_client_a_access,inline:{168.100.189.2=reject}
+OK
+>>> client spike.porcupine.org 1.2.3.4
+./smtpd_check: <queue id>: reject: CONNECT from spike.porcupine.org[1.2.3.4]: 554 5.7.1 <spike.porcupine.org[1.2.3.4]>: Client host rejected: Access denied; from=<foo@postfix.org> proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <spike.porcupine.org[1.2.3.4]>: Client host rejected: Access denied
+>>> client www.porcupine.org 1.2.3.4
 OK
->>> helo help.gypsysoul.org
+>>> reverse_client_restrictions check_reverse_client_a_access,inline:{168.100.189.2=reject}
+bad command
+>>> client spike.porcupine.org 1.2.3.4
+./smtpd_check: <queue id>: reject: CONNECT from spike.porcupine.org[1.2.3.4]: 554 5.7.1 <spike.porcupine.org[1.2.3.4]>: Client host rejected: Access denied; from=<foo@postfix.org> proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <spike.porcupine.org[1.2.3.4]>: Client host rejected: Access denied
+>>> client www.porcupine.org 1.2.3.4
 OK
->>> helo gypsysoul.org
-./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 5.7.1 <gypsysoul.org>: Helo command rejected: bizsat.net, gypsysoul.org spam; from=<foo@ns1.topica.com> proto=SMTP helo=<gypsysoul.org>
-554 5.7.1 <gypsysoul.org>: Helo command rejected: bizsat.net, gypsysoul.org spam
->>> client_restrictions check_client_a_access,hash:smtpd_check_access
+>>> sender_restrictions check_sender_a_access,inline:{168.100.189.2=reject}
 OK
->>> client help.gypsysoul.org 1.2.3.4
+>>> mail foo@spike.porcupine.org
+./smtpd_check: <queue id>: reject: MAIL from www.porcupine.org[1.2.3.4]: 554 5.7.1 <foo@spike.porcupine.org>: Sender address rejected: Access denied; from=<foo@spike.porcupine.org> proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <foo@spike.porcupine.org>: Sender address rejected: Access denied
+>>> mail foo@www.porcupine.org
 OK
->>> client gypsysoul.org 1.2.3.4
-./smtpd_check: <queue id>: reject: CONNECT from gypsysoul.org[1.2.3.4]: 554 5.7.1 <gypsysoul.org[1.2.3.4]>: Client host rejected: bizsat.net, gypsysoul.org spam; from=<foo@ns1.topica.com> proto=SMTP helo=<gypsysoul.org>
-554 5.7.1 <gypsysoul.org[1.2.3.4]>: Client host rejected: bizsat.net, gypsysoul.org spam
->>> #reverse_client_restrictions check_reverse_client_a_access,hash:smtpd_check_access
->>> #client help.gypsysoul.org 1.2.3.4
->>> #client gypsysoul.org 1.2.3.4
->>> sender_restrictions check_sender_a_access,hash:smtpd_check_access
+>>> recipient_restrictions check_recipient_a_access,inline:{168.100.189.2=reject}
 OK
->>> mail foo@gypsysoul.org
-./smtpd_check: <queue id>: reject: MAIL from gypsysoul.org[1.2.3.4]: 554 5.7.1 <foo@gypsysoul.org>: Sender address rejected: bizsat.net, gypsysoul.org spam; from=<foo@gypsysoul.org> proto=SMTP helo=<gypsysoul.org>
-554 5.7.1 <foo@gypsysoul.org>: Sender address rejected: bizsat.net, gypsysoul.org spam
->>> recipient_restrictions check_recipient_a_access,hash:smtpd_check_access
+>>> rcpt foo@spike.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from www.porcupine.org[1.2.3.4]: 554 5.7.1 <foo@spike.porcupine.org>: Recipient address rejected: Access denied; from=<foo@www.porcupine.org> to=<foo@spike.porcupine.org> proto=SMTP helo=<www.porcupine.org>
+554 5.7.1 <foo@spike.porcupine.org>: Recipient address rejected: Access denied
+>>> rcpt foo@www.porcupine.org
 OK
->>> mail foo@gypsysoul.org
-./smtpd_check: <queue id>: reject: MAIL from gypsysoul.org[1.2.3.4]: 554 5.7.1 <foo@gypsysoul.org>: Sender address rejected: bizsat.net, gypsysoul.org spam; from=<foo@gypsysoul.org> proto=SMTP helo=<gypsysoul.org>
-554 5.7.1 <foo@gypsysoul.org>: Sender address rejected: bizsat.net, gypsysoul.org spam